Merge "msm: qdsp5v2: Update MVS driver for evrc codec" into msm-3.0
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
new file mode 100644
index 0000000..35385d3
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
@@ -0,0 +1,47 @@
+* Low Power Management Levels
+
+The application processor in MSM can do a variety of C-States for low power
+management. These C-States are invoked by the CPUIdle framework when the core
+becomes idle. But based on the time available until the next scheduled wakeup,
+the system can do a combination of low power modes of different resources -
+L2, XO, Vdd Dig and Vdd Mem. The combination is captured in the device tree as
+lpm-level. The units for voltage are dependent on the PMIC used on the target
+and are in uV.
+
+The required nodes for lpm-levels are:
+
+- compatible: "qcom,lpm-levels"
+- reg: The numeric level id
+- qcom,mode: The sleep mode of the processor
+- qcom,xo: The state of XO clock.
+- qcom,l2: The state of L2 cache.
+- qcom,vdd-mem-upper-bound: The upper bound value of mem voltage in uV
+- qcom,vdd-mem-lower-bound: The lower bound value of mem voltage in uV
+- qcom,vdd-dig-upper-bound: The upper bound value of dig voltage in uV
+- qcom,vdd-dig-lower-bound: The lower bound value of dig voltage in uV
+- qcom,latency-us: The latency in handling the interrupt if this level was
+	chosen, in uSec
+- qcom,ss-power: The steady state power expelled when the processor is in this
+	level in mWatts
+- qcom,energy-overhead: The energy used up in entering and exiting this level
+	in mWatts.uSec
+- qcom,time-overhead: The time spent in entering and exiting this level in uS
+
+Example:
+
+qcom,lpm-levels {
+	qcom,lpm-level@0 {
+		reg = <0>;
+		qcom,mode = <0>;        /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
+		qcom,xo = <1>;          /* ON */
+		qcom,l2 = <3>;          /* ACTIVE */
+		qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+		qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+		qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+		qcom,vdd-dig-lower-bound = <950000>;  /* ACTIVE */
+		qcom,latency-us = <100>;
+		qcom,ss-power = <650>;
+		qcom,energy-overhead = <801>;
+		qcom,time-overhead = <200>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/arm/msm/pm-boot.txt b/Documentation/devicetree/bindings/arm/msm/pm-boot.txt
new file mode 100644
index 0000000..cce9d0e
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/pm-boot.txt
@@ -0,0 +1,40 @@
+* Power Management boot configuration (pm-boot)
+
+Low power management drivers need to specify the warmboot entry path for the
+application processors to resume from sleep/suspend. The boot configuration
+can vary if the core does/does not support a secure boot mode. The secure
+boot configuration boots the core sets up the core sub system registers and
+calls into the kernel entry point. In the absence of a secure boot mode, the
+core when powered on from reset will need to be configured with the warmboot
+entry pointer. The physical and the virtual address for the entry pointer
+need to provided to the driver.
+
+
+The device tree parameters for pm-boot are:
+
+Required parameters:
+
+- compatible: Must be "qcom,pm-boot"
+- qcom,mode: The mode that the target will use for booting
+	MSM_PM_BOOT_CONFIG_TZ                = 0,
+	MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS = 1,
+	MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT = 2,
+	MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR   = 3,
+
+Optional parameters (based on the mode chosen):
+
+- qcom,phy-addr: The physical address that will be used for warmboot entry if
+	the processor remap register can be programmed.
+	Needed for modes = { MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS,
+				MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR }
+- qcom,virt-addr: The virtual address at which the processor start booting from
+	Needed for modes = { MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
+				MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR }
+
+
+Example:
+
+	qcom,pm-boot {
+		compatible = "qcom,pm-boot";
+		qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
new file mode 100644
index 0000000..a33d833
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
@@ -0,0 +1,66 @@
+* MSM Subsystem Power Manager (spm-v2)
+
+S4 generation of MSMs have SPM hardware blocks to control the Application
+Processor Sub-System power. These SPM blocks run individual state machine
+to determine what the core (L2 or Krait/Scorpion) would do when the WFI
+instruction is executed by the core. The SAW hardware block handles SPM and
+AVS functionality for the cores.
+
+The devicetree representation of the SPM block should be:
+
+Required properties
+
+- compatible: "qcom,spm-v2"
+- reg: The physical address and the size of the SPM's memory mapped registers
+- qcom, core-id: The core id the SPM block is attached to.
+	{0..n} for cores {0..n}
+	{0xffff} for L2
+- qcom,saw2-ver-reg: The location of the version register
+- qcom,saw2-cfg: SAW2 configuration register
+- qcom,saw2-avs-ctl: The AVS control register
+- qcom,saw2-avs-hysterisis: The AVS hysterisis register to delay the AVS
+	controller requests
+- qcom,saw2-spm-dly: Provides the values for the SPM delay command in the SPM
+	sequence
+- qcom,saw2-spm-ctl: The SPM control register
+- qcom,saw2-vctl-timeout-us: The timeout value to wait for voltage to change
+	after sending the voltage command to the PMIC
+
+Optional properties
+
+- qcom,saw2-avs-limit: The AVS limit register
+- qcom,saw2-avs-dly: The AVS delay register is used to specify the delay values
+	between AVS controller requests
+- qcom,saw2-pmic-dly: The delay values for waiting on PMIC response
+- qcom,saw2-pmic-data0..7: Specify the pmic data value and the associated FTS
+	index to send the PMIC data to
+- qcom,saw2-vctl-port: The FTS port used for changing voltage
+- qcom,saw2-phase-port: The FTS port used for changing the number of phases
+- qcom,saw2-spm-cmd-wfi: The WFI command sequence
+- qcom,saw2-spm-cmd-ret: The Retention command sequence
+- qcom,saw2-spm-cmd-spc: The Standalone PC command sequence
+- qcom,saw2-spm-cmd-pc: The Power Collapse command sequence
+
+Example:
+	qcom,spm@f9089000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9089000 0x1000>;
+		qcom,core-id = <0>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x1b>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x20000400>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,spm-cmd-wfi = [03 0b 0f];
+		qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+				a0 b0 03 68 70 3b 92 a0 b0
+				82 2b 50 10 30 02 22 30 0f];
+		qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+				a0 b0 82 10 30 02 22 30 0f];
+	};
+
diff --git a/Documentation/devicetree/bindings/gpio/qpnp-gpio.txt b/Documentation/devicetree/bindings/gpio/qpnp-gpio.txt
index dff6a3e..7cab09b 100644
--- a/Documentation/devicetree/bindings/gpio/qpnp-gpio.txt
+++ b/Documentation/devicetree/bindings/gpio/qpnp-gpio.txt
@@ -24,27 +24,26 @@
 
 Required properties :
  - reg : Specify the spmi offset and size for this gpio device.
- - qcom,qpnp-gpio-num : Specify the PMIC GPIO number for this gpio device.
+ - qcom,gpio-num : Specify the PMIC GPIO number for this gpio device.
 
-Optional properties :
- - qcom,qpnp-gpio-cfg : Specify the PMIC gpio configuration.
-   The format of this configuration is specified in a tuple of 9 entries.
-   These entries should be specified in the same order as the entries listed
-   in this following discription.
-
-   @direction:		indicates whether the gpio should be input, output, or
+Optional configuration properties :
+ -  qcom,direction:	indicates whether the gpio should be input, output, or
 			both.
+			QPNP_GPIO_DIR_IN   = 0,
 			QPNP_GPIO_DIR_OUT  = 1,
-			QPNP_GPIO_DIR_IN   = 2,
-			QPNP_GPIO_DIR_BOTH = 3
+			QPNP_GPIO_DIR_BOTH = 2
 
-   @output_type:	indicates gpio should be configured as CMOS or open
+ - qcom,output-type:	indicates gpio should be configured as CMOS or open
 			drain.
-			QPNP_GPIO_OUT_BUF_OPEN_DRAIN = 1,
 			QPNP_GPIO_OUT_BUF_CMOS = 0
+			QPNP_GPIO_OUT_BUF_OPEN_DRAIN_NMOS = 1,
+			QPNP_GPIO_OUT_BUF_OPEN_DRAIN_PMOS = 2,
 
-   @output_value:	The gpio output value of the gpio line - 0 or 1
-   @pull:		Indicates whether a pull up or pull down should be
+ - qcom,invert:		Invert the signal of the gpio line -
+			QPNP_GPIO_INVERT_DISABLE = 0
+			QPNP_GPIO_INVERT_ENABLE = 1
+
+ - qcom,pull:		Indicates whether a pull up or pull down should be
 			applied. If a pullup is required the current strength
 			needs to be specified. Current values of 30uA, 1.5uA,
 			31.5uA, 1.5uA with 30uA boost are supported.
@@ -55,7 +54,7 @@
 			QPNP_GPIO_PULL_DN	 = 4,
 			QPNP_GPIO_PULL_NO	 = 5
 
-  @vin_sel:		specifies the voltage level when the output is set to 1.
+  - qcom,vin-sel:	specifies the voltage level when the output is set to 1.
 			For an input gpio specifies the voltage level at which
 			the input is interpreted as a logical 1.
 			QPNP_GPIO_VIN0 = 0,
@@ -67,27 +66,32 @@
 			QPNP_GPIO_VIN6 = 6,
 			QPNP_GPIO_VIN7 = 7
 
-  @out_strength:	the amount of current supplied for an output gpio.
-			QPNP_GPIO_OUT_STRENGTH_HIGH = 1,
+  - qcom,out-strength:	the amount of current supplied for an output gpio.
+			QPNP_GPIO_OUT_STRENGTH_LOW  = 1
 			QPNP_GPIO_OUT_STRENGTH_MED  = 2,
-			QPNP_GPIO_OUT_STRENGTH_LOW  = 3
+			QPNP_GPIO_OUT_STRENGTH_HIGH = 3,
 
-  @source_sel:		choose alternate function for the gpio. Certain gpios
+  - qcom,source-sel:	choose alternate function for the gpio. Certain gpios
 			can be paired (shorted) with each other. Some gpio pin
 			can act as alternate functions.
 			QPNP_GPIO_FUNC_NORMAL   = 0,
 			QPNP_GPIO_FUNC_PAIRED   = 1
 			QPNP_GPIO_FUNC_1	= 2,
-			QPNP_GPIO_FUNC_3	= 3,
+			QPNP_GPIO_FUNC_2	= 3,
 			QPNP_GPIO_DTEST1	= 4,
 			QPNP_GPIO_DTEST2	= 5,
 			QPNP_GPIO_DTEST3	= 6,
 			QPNP_GPIO_DTEST4	= 7
 
-  @master_en:		1 = Enable features within the GPIO block based on
-			configurations.
-			0 = Completely disable the GPIO block and let the pin
-			float with high impedance regardless of other settings.
+ - qcom,master-en:	1 = Enable features within the
+			GPIO block based on configurations.
+			0 = Completely disable the GPIO
+			block and let the pin float with high impedance
+			regardless of other settings.
+
+*Note: If any of the configuration properties are not specified, then the
+       qpnp-gpio driver will not modify that respective configuration in
+       hardware.
 
 [PMIC GPIO clients]
 
@@ -116,15 +120,16 @@
 				#address-cells = <1>;
 				#size-cells = <1>;
 
-				qcom,pm8941_gpio1@0xc000 {
+				gpio@c000 {
 					reg = <0xc000 0x100>;
-					qcom,qpnp-gpio-num = <62>;
+					qcom,gpio-num = <62>;
 				};
 
-				qcom,pm8941_gpio2@0xc100 {
+				gpio@c100 {
 					reg = <0xc100 0x100>;
-					qcom,qpnp-gpio-num = <20>;
-					qcom,qpnp-gpio-cfg = <0x1 0x1 0x1 0x2 0x3 0x2 0x0 0x0 0x1>;
+					qcom,gpio-num = <20>;
+					qcom,source_sel = <2>;
+					qcom,pull = <5>;
 				};
 			};
 
diff --git a/Documentation/devicetree/bindings/pil/pil-pronto.txt b/Documentation/devicetree/bindings/pil/pil-pronto.txt
new file mode 100644
index 0000000..6193b68
--- /dev/null
+++ b/Documentation/devicetree/bindings/pil/pil-pronto.txt
@@ -0,0 +1,25 @@
+* Qualcomm WCNSS Pronto Peripheral Image Loader
+
+pil-pronto is a peripheral image loading (PIL) driver. It is used for loading
+Pronto firmware images for wireless connectivity subsystems into memory and
+preparing the subsystem's processor to execute code. It is also used for
+shutting down the processor when it's not needed.
+
+Required properties:
+- compatible: "pil-pronto"
+- reg: offset and length of the register set for the device. The first pair
+       corresponds to PRONTO_PMU, the second pair corresponds to CLK_CTL_WCNSS
+       the third pair corresponds to WCNSS_HALTREQ.
+- vdd_pronto_pll-supply: regulator to supply pronto pll.
+- qcom,firmware-name: Base name of the firmware image. Ex. "wcnss"
+
+Example:
+	qcom,pronto@fb21b000 {
+		compatible = "qcom,pil-pronto";
+		reg = <0xfb21b000 0x3000>,
+		      <0xfc401700 0x4>,
+		      <0xfd485300 0xc>;
+		vdd_pronto_pll-supply = <&pm8941_l12>;
+
+		qcom,firmware-name = "wcnss";
+	};
diff --git a/Documentation/devicetree/bindings/spi/spi_qsd.txt b/Documentation/devicetree/bindings/spi/spi_qsd.txt
index 5839f63..939f77b 100644
--- a/Documentation/devicetree/bindings/spi/spi_qsd.txt
+++ b/Documentation/devicetree/bindings/spi/spi_qsd.txt
@@ -6,11 +6,41 @@
 - interrupts : should contain the QUP core interrupt.
 - spi-max-frequency : specifies maximum SPI clock frequency, Units - Hz.
 
+Optional properties:
+- gpios : specifies the gpio pins to be used for SPI CLK, MISO, MOSI in
+  that order.
+- cs-gpios : specifies the gpio pins to be used for chipselects.
+
+SPI slave nodes must be children of the SPI master node and contain
+the following properties.
+- reg : (required) chip select address of device.
+- compatible : (required) name of SPI device following generic names
+  recommended practice
+- spi-max-frequency : (required) Maximum SPI clocking speed of device in Hz
+- interrupts : (recommended) should contain the SPI slave interrupt number
+  encoded depending on the type of the interrupt controller.
+- interrupt-parent : (recommended) the phandle for the interrupt controller
+  that services interrupts for this device.
+- spi-cpol : (optional) Empty property indicating device requires inverse
+  clock polarity (CPOL) mode
+- spi-cpha : (optional) Empty property indicating device requires shifted
+  clock phase (CPHA) mode
+- spi-cs-high : (optional) Empty property indicating device requires
+  chip select active high
+
 Example:
 	spi@f9924000 {
 		compatible = "qcom,spi-qup-v2";
 		reg = <0xf9924000 0x1000>;
-		interrupts = <96>;
+		interrupts = <0 96 0>;
 		spi-max-frequency = <24000000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		device@0 {
+			compatible = "spidev";
+			reg = <0>;
+			spi-max-frequency = <5000000>;
+		};
 	};
 
diff --git a/Documentation/genlock.txt b/Documentation/genlock.txt
index 6f24a76..cd82614 100644
--- a/Documentation/genlock.txt
+++ b/Documentation/genlock.txt
@@ -34,6 +34,12 @@
 space and kernel space to allow a kernel driver to unlock or lock a buffer
 on behalf of a user process.
 
+Locks within a process using a single genlock handle follow the same rules for
+exclusive write locks with multiple readers. Genlock cannot provide deadlock
+protection because the same handle can be used simultaneously by a producer and
+consumer. In practice in the event that the client creates a deadlock an error
+will still be generated when the timeout expires.
+
 Kernel API
 
 Access to the genlock API can either be via the in-kernel API or via an
@@ -137,7 +143,12 @@
  * GENLOCK_UNLOCK - unlock an existing lock
 
 Pass flags in genlock_lock.flags:
- * GENLOCK_NOBLOCK - Do not block if the lock is already taken
+ * GENLOCK_NOBLOCK       - Do not block if the lock is already taken
+ * GENLOCK_WRITE_TO_READ - Convert a write lock that the handle owns to a read
+                           lock. For instance graphics may hold a write lock
+                           while rendering the back buffer then when swapping
+                           convert the lock to a read lock to copy the front
+                           buffer in the next frame for preserved buffers.
 
 Pass a timeout value in milliseconds in genlock_lock.timeout.
 genlock_lock.flags and genlock_lock.timeout are not used for UNLOCK.
diff --git a/arch/arm/boot/dts/msm-pm8841.dtsi b/arch/arm/boot/dts/msm-pm8841.dtsi
index 81afa37..523c9b0 100644
--- a/arch/arm/boot/dts/msm-pm8841.dtsi
+++ b/arch/arm/boot/dts/msm-pm8841.dtsi
@@ -17,9 +17,9 @@
 		interrupt-controller;
 		#interrupt-cells = <3>;
 
-		qcom,pm8841@3 {
+		qcom,pm8841@5 {
 			spmi-slave-container;
-			reg = <0x3>;
+			reg = <0x5>;
 			#address-cells = <1>;
 			#size-cells = <1>;
 
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index c8a4ff9..2698ea7 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -17,6 +17,238 @@
 		interrupt-controller;
 		#interrupt-cells = <3>;
 
+		qcom,pm8941@0 {
+			spmi-slave-container;
+			reg = <0x0>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			pm8941_gpios {
+				spmi-dev-container;
+				compatible = "qcom,qpnp-gpio";
+				gpio-controller;
+				#gpio-cells = <2>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+
+				gpio@c000 {
+					reg = <0xc000 0x100>;
+					qcom,gpio-num = <1>;
+					status = "disabled";
+				};
+
+				gpio@c100 {
+					reg = <0xc100 0x100>;
+					qcom,gpio-num = <2>;
+					status = "disabled";
+				};
+
+				gpio@c200 {
+					reg = <0xc200 0x100>;
+					qcom,gpio-num = <3>;
+					status = "disabled";
+				};
+
+				gpio@c300 {
+					reg = <0xc300 0x100>;
+					qcom,gpio-num = <4>;
+					status = "disabled";
+				};
+
+				gpio@c400 {
+					reg = <0xc400 0x100>;
+					qcom,gpio-num = <5>;
+					status = "disabled";
+				};
+
+				gpio@c500 {
+					reg = <0xc500 0x100>;
+					qcom,gpio-num = <6>;
+					status = "disabled";
+				};
+
+				gpio@c600 {
+					reg = <0xc600 0x100>;
+					qcom,gpio-num = <7>;
+					status = "disabled";
+				};
+
+				gpio@c700 {
+					reg = <0xc700 0x100>;
+					qcom,gpio-num = <8>;
+					status = "disabled";
+				};
+
+				gpio@c800 {
+					reg = <0xc800 0x100>;
+					qcom,gpio-num = <9>;
+					status = "disabled";
+				};
+
+				gpio@c900 {
+					reg = <0xc900 0x100>;
+					qcom,gpio-num = <10>;
+					status = "disabled";
+				};
+
+				gpio@ca00 {
+					reg = <0xca00 0x100>;
+					qcom,gpio-num = <11>;
+					status = "disabled";
+				};
+
+				gpio@cb00 {
+					reg = <0xcb00 0x100>;
+					qcom,gpio-num = <12>;
+					status = "disabled";
+				};
+
+				gpio@cc00 {
+					reg = <0xcc00 0x100>;
+					qcom,gpio-num = <13>;
+					status = "disabled";
+				};
+
+				gpio@cd00 {
+					reg = <0xcd00 0x100>;
+					qcom,gpio-num = <14>;
+					status = "disabled";
+				};
+
+				gpio@ce00 {
+					reg = <0xce00 0x100>;
+					qcom,gpio-num = <15>;
+					status = "disabled";
+				};
+
+				gpio@cf00 {
+					reg = <0xcf00 0x100>;
+					qcom,gpio-num = <16>;
+					status = "disabled";
+				};
+
+				gpio@d000 {
+					reg = <0xd000 0x100>;
+					qcom,gpio-num = <17>;
+					status = "disabled";
+				};
+
+				gpio@d100 {
+					reg = <0xd100 0x100>;
+					qcom,gpio-num = <18>;
+					status = "disabled";
+				};
+
+				gpio@d200 {
+					reg = <0xd200 0x100>;
+					qcom,gpio-num = <19>;
+					status = "disabled";
+				};
+
+				gpio@d300 {
+					reg = <0xd300 0x100>;
+					qcom,gpio-num = <20>;
+					status = "disabled";
+				};
+
+				gpio@d400 {
+					reg = <0xd400 0x100>;
+					qcom,gpio-num = <21>;
+					status = "disabled";
+				};
+
+				gpio@d500 {
+					reg = <0xd500 0x100>;
+					qcom,gpio-num = <22>;
+					status = "disabled";
+				};
+
+				gpio@d600 {
+					reg = <0xd600 0x100>;
+					qcom,gpio-num = <23>;
+					status = "disabled";
+				};
+
+				gpio@d700 {
+					reg = <0xd700 0x100>;
+					qcom,gpio-num = <24>;
+					status = "disabled";
+				};
+
+				gpio@d800 {
+					reg = <0xd800 0x100>;
+					qcom,gpio-num = <25>;
+					status = "disabled";
+				};
+
+				gpio@d900 {
+					reg = <0xd900 0x100>;
+					qcom,gpio-num = <26>;
+					status = "disabled";
+				};
+
+				gpio@da00 {
+					reg = <0xda00 0x100>;
+					qcom,gpio-num = <27>;
+					status = "disabled";
+				};
+
+				gpio@db00 {
+					reg = <0xdb00 0x100>;
+					qcom,gpio-num = <28>;
+					status = "disabled";
+				};
+
+				gpio@dc00 {
+					reg = <0xdc00 0x100>;
+					qcom,gpio-num = <29>;
+					status = "disabled";
+				};
+
+				gpio@dd00 {
+					reg = <0xdd00 0x100>;
+					qcom,gpio-num = <30>;
+					status = "disabled";
+				};
+
+				gpio@de00 {
+					reg = <0xde00 0x100>;
+					qcom,gpio-num = <31>;
+					status = "disabled";
+				};
+
+				gpio@df00 {
+					reg = <0xdf00 0x100>;
+					qcom,gpio-num = <32>;
+					status = "disabled";
+				};
+
+				gpio@e000 {
+					reg = <0xe000 0x100>;
+					qcom,gpio-num = <33>;
+					status = "disabled";
+				};
+
+				gpio@e100 {
+					reg = <0xe100 0x100>;
+					qcom,gpio-num = <34>;
+					status = "disabled";
+				};
+
+				gpio@e200 {
+					reg = <0xe200 0x100>;
+					qcom,gpio-num = <35>;
+					status = "disabled";
+				};
+
+				gpio@e300 {
+					reg = <0xe300 0x100>;
+					qcom,gpio-num = <36>;
+					status = "disabled";
+				};
+			};
+		};
+
 		qcom,pm8941@1 {
 			spmi-slave-container;
 			reg = <0x1>;
diff --git a/arch/arm/boot/dts/msmcopper-gpio.dtsi b/arch/arm/boot/dts/msmcopper-gpio.dtsi
new file mode 100644
index 0000000..7c3f5ce
--- /dev/null
+++ b/arch/arm/boot/dts/msmcopper-gpio.dtsi
@@ -0,0 +1,214 @@
+/* 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.
+ */
+
+/ {
+	qcom,spmi@fc4c0000 {
+
+		qcom,pm8941@0 {
+
+			pm8941_gpios: pm8941_gpios {
+
+				gpio@c000 {
+					qcom,gpio-num = <1>;
+					status = "ok";
+				};
+
+				gpio@c100 {
+					qcom,gpio-num = <2>;
+					status = "ok";
+				};
+
+				gpio@c200 {
+					qcom,gpio-num = <3>;
+					status = "ok";
+				};
+
+				gpio@c300 {
+					qcom,gpio-num = <4>;
+					status = "ok";
+				};
+
+				gpio@c400 {
+					qcom,gpio-num = <5>;
+					status = "ok";
+				};
+
+				gpio@c500 {
+					qcom,gpio-num = <6>;
+					status = "ok";
+				};
+
+				gpio@c600 {
+					qcom,gpio-num = <7>;
+					status = "ok";
+				};
+
+				gpio@c700 {
+					qcom,gpio-num = <8>;
+					status = "ok";
+				};
+
+				gpio@c800 {
+					qcom,gpio-num = <9>;
+					status = "ok";
+				};
+
+				gpio@c900 {
+					qcom,gpio-num = <10>;
+					status = "ok";
+				};
+
+				gpio@ca00 {
+					qcom,gpio-num = <11>;
+					status = "ok";
+				};
+
+				gpio@cb00 {
+					qcom,gpio-num = <12>;
+					status = "ok";
+				};
+
+				gpio@cc00 {
+					qcom,gpio-num = <13>;
+					status = "ok";
+				};
+
+				gpio@cd00 {
+					qcom,gpio-num = <14>;
+					status = "ok";
+				};
+
+				gpio@ce00 {
+					qcom,gpio-num = <15>;
+					status = "ok";
+				};
+
+				gpio@cf00 {
+					qcom,gpio-num = <16>;
+					status = "ok";
+				};
+
+				gpio@d000 {
+					qcom,gpio-num = <17>;
+					status = "ok";
+				};
+
+				gpio@d100 {
+					qcom,gpio-num = <18>;
+					status = "ok";
+				};
+
+				gpio@d200 {
+					qcom,gpio-num = <19>;
+					status = "ok";
+				};
+
+				gpio@d300 {
+					qcom,gpio-num = <20>;
+					status = "ok";
+				};
+
+				gpio@d400 {
+					qcom,gpio-num = <21>;
+					status = "ok";
+				};
+
+				gpio@d500 {
+					qcom,gpio-num = <22>;
+					status = "ok";
+				};
+
+				gpio@d600 {
+					qcom,gpio-num = <23>;
+					status = "ok";
+				};
+
+				gpio@d700 {
+					qcom,gpio-num = <24>;
+					status = "ok";
+				};
+
+				gpio@d800 {
+					qcom,gpio-num = <25>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@d900 {
+					qcom,gpio-num = <26>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@da00 {
+					qcom,gpio-num = <27>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@db00 {
+					qcom,gpio-num = <28>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@dc00 {
+					qcom,gpio-num = <29>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@dd00 {
+					qcom,gpio-num = <30>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@de00 {
+					qcom,gpio-num = <31>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@df00 {
+					qcom,gpio-num = <32>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@e000 {
+					qcom,gpio-num = <33>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@e100 {
+					qcom,gpio-num = <34>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@e200 {
+					qcom,gpio-num = <35>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+
+				gpio@e300 {
+					qcom,gpio-num = <36>;
+					qcom,out-strength = <1>;
+					status = "ok";
+				};
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msmcopper-regulator.dtsi b/arch/arm/boot/dts/msmcopper-regulator.dtsi
index b0c48fc..48d5720 100644
--- a/arch/arm/boot/dts/msmcopper-regulator.dtsi
+++ b/arch/arm/boot/dts/msmcopper-regulator.dtsi
@@ -20,6 +20,7 @@
 				regulator-max-microvolt = <1300000>;
 				qcom,enable-time = <500>;
 				qcom,pull-down-enable = <1>;
+				regulator-always-on;
 				status = "okay";
 			};
 
@@ -36,6 +37,7 @@
 				regulator-max-microvolt = <1800000>;
 				qcom,enable-time = <500>;
 				qcom,pull-down-enable = <1>;
+				regulator-always-on;
 				status = "okay";
 			};
 
@@ -52,6 +54,7 @@
 				regulator-max-microvolt = <1225000>;
 				qcom,enable-time = <200>;
 				qcom,pull-down-enable = <1>;
+				regulator-always-on;
 				status = "okay";
 			};
 
@@ -285,13 +288,14 @@
 			};
 		};
 
-		qcom,pm8841@3 {
+		qcom,pm8841@5 {
 
 			pm8841_s1: regulator@1400 {
 				regulator-min-microvolt = <900000>;
 				regulator-max-microvolt = <1150000>;
 				qcom,enable-time = <500>;
 				qcom,pull-down-enable = <1>;
+				regulator-always-on;
 				status = "okay";
 			};
 
@@ -300,6 +304,7 @@
 				regulator-max-microvolt = <1150000>;
 				qcom,enable-time = <500>;
 				qcom,pull-down-enable = <1>;
+				regulator-always-on;
 				status = "okay";
 			};
 
@@ -324,6 +329,7 @@
 				regulator-max-microvolt = <1100000>;
 				qcom,enable-time = <500>;
 				qcom,pull-down-enable = <1>;
+				regulator-always-on;
 				status = "okay";
 			};
 
@@ -352,4 +358,36 @@
 			};
 		};
 	};
+
+	krait0_vreg: regulator@f9088000 {
+		compatible = "qcom,krait-regulator";
+		regulator-name = "krait0";
+		reg = <0xf9088000 0x1000>;
+		regulator-min-microvolt = <500000>;
+		regulator-max-microvolt = <1100000>;
+	};
+
+	krait1_vreg: regulator@f9098000 {
+		compatible = "qcom,krait-regulator";
+		regulator-name = "krait1";
+		reg = <0xf9098000 0x1000>;
+		regulator-min-microvolt = <500000>;
+		regulator-max-microvolt = <1100000>;
+	};
+
+	krait2_vreg: regulator@f90a8000 {
+		compatible = "qcom,krait-regulator";
+		regulator-name = "krait2";
+		reg = <0xf90a8000 0x1000>;
+		regulator-min-microvolt = <500000>;
+		regulator-max-microvolt = <1100000>;
+	};
+
+	krait3_vreg: regulator@f90b8000 {
+		compatible = "qcom,krait-regulator";
+		regulator-name = "krait3";
+		reg = <0xf90b8000 0x1000>;
+		regulator-min-microvolt = <500000>;
+		regulator-max-microvolt = <1100000>;
+	};
 };
diff --git a/arch/arm/boot/dts/msmcopper-rumi.dts b/arch/arm/boot/dts/msmcopper-rumi.dts
index bb53ff8..8c00535 100644
--- a/arch/arm/boot/dts/msmcopper-rumi.dts
+++ b/arch/arm/boot/dts/msmcopper-rumi.dts
@@ -46,6 +46,27 @@
 		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>;
+		};
+	};
+
 	slim@fe12f000 {
 		status = "disable";
 	};
@@ -57,4 +78,16 @@
 	i2c@f9966000 {
 		status = "disable";
 	};
+
+	qcom,ssusb@F9200000 {
+		status = "disable";
+	};
+
+	qcom,lpass@fe200000 {
+		status = "disable";
+	};
+
+	qcom,pronto@fb21b000 {
+		status = "disable";
+	};
 };
diff --git a/arch/arm/boot/dts/msmcopper.dtsi b/arch/arm/boot/dts/msmcopper.dtsi
index 4821290..fc9d50a 100644
--- a/arch/arm/boot/dts/msmcopper.dtsi
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -11,9 +11,11 @@
  */
 
 /include/ "skeleton.dtsi"
+/include/ "msmcopper_pm.dtsi"
 /include/ "msm-pm8841.dtsi"
 /include/ "msm-pm8941.dtsi"
 /include/ "msmcopper-regulator.dtsi"
+/include/ "msmcopper-gpio.dtsi"
 
 / {
 	model = "Qualcomm MSM Copper";
@@ -28,16 +30,17 @@
 		      <0xF9002000 0x1000>;
 	};
 
-	msmgpio: gpio@fd400000 {
+	msmgpio: gpio@fd510000 {
 		compatible = "qcom,msm-gpio";
 		interrupt-controller;
 		#interrupt-cells = <2>;
-		reg = <0xfd400000 0x4000>;
+		reg = <0xfd510000 0x4000>;
+		#gpio-cells = <2>;
 	};
 
 	timer {
 		compatible = "qcom,msm-qtimer", "arm,armv7-timer";
-		interrupts = <1 2 0>;
+		interrupts = <1 2 0 1 3 0>;
 		clock-frequency = <19200000>;
 	};
 
@@ -252,4 +255,18 @@
 
 		qcom,firmware-name = "lpass";
 	};
+
+	qcom,pronto@fb21b000 {
+		compatible = "qcom,pil-pronto";
+		reg = <0xfb21b000 0x3000>,
+		      <0xfc401700 0x4>,
+		      <0xfd485300 0xc>;
+		vdd_pronto_pll-supply = <&pm8941_l12>;
+
+		qcom,firmware-name = "wcnss";
+	};
+
+	qcom,ocmem@fdd00000 {
+		compatible = "qcom,msm_ocmem";
+	};
 };
diff --git a/arch/arm/boot/dts/msmcopper_pm.dtsi b/arch/arm/boot/dts/msmcopper_pm.dtsi
new file mode 100644
index 0000000..0da3200
--- /dev/null
+++ b/arch/arm/boot/dts/msmcopper_pm.dtsi
@@ -0,0 +1,280 @@
+/* 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/ "skeleton.dtsi"
+
+/ {
+	qcom,spm@f9089000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9089000 0x1000>;
+		qcom,core-id = <0>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x1b>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x20000400>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,spm-cmd-wfi = [03 0b 0f];
+		qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+				a0 b0 03 68 70 3b 92 a0 b0
+				82 2b 50 10 30 02 22 30 0f];
+		qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+				a0 b0 82 10 30 02 22 30 0f];
+	};
+
+	qcom,spm@f9099000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9099000 0x1000>;
+		qcom,core-id = <1>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x1b>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x20000400>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,spm-cmd-wfi = [03 0b 0f];
+		qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+				a0 b0 03 68 70 3b 92 a0 b0
+				82 2b 50 10 30 02 22 30 0f];
+		qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+				a0 b0 82 10 30 02 22 30 0f];
+	};
+
+	qcom,spm@f90a9000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf90a9000 0x1000>;
+		qcom,core-id = <2>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x1b>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x20000400>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,spm-cmd-wfi = [03 0b 0f];
+		qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+				a0 b0 03 68 70 3b 92 a0 b0
+				82 2b 50 10 30 02 22 30 0f];
+		qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+				a0 b0 82 10 30 02 22 30 0f];
+	};
+
+	qcom,spm@f90b9000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf90b9000 0x1000>;
+		qcom,core-id = <3>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x1b>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x20000400>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,spm-cmd-wfi = [03 0b 0f];
+		qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+				a0 b0 03 68 70 3b 92 a0 b0
+				82 2b 50 10 30 02 22 30 0f];
+		qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+				a0 b0 82 10 30 02 22 30 0f];
+	};
+
+	qcom,spm@f9012000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9012000 0x1000>;
+		qcom,core-id = <0xffff>; /* L2/APCS SAW */
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x1a>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x20000400>;
+		qcom,saw2-spm-ctl = <0x0>; /* TODO: Enable L2 SPM */
+		qcom,saw2-pmic-dly = <0x02020204>;
+		qcom,saw2-pmic-data0 = <0x0400009c>;
+		qcom,saw2-pmic-data1 = <0x00000060>;
+		qcom,saw2-pmic-data2 = <0x0000001c>;
+		qcom,saw2-pmic-data3 = <0x04000000>;
+		qcom,vctl-timeout-us = <50>;
+		qcom,vctl-port = <0x0>; /* TODO: */
+		qcom,phase-port = <0x1>; /* TODO: */
+		qcom,spm-cmd-ret = [0b 00 20 03 22 00 0f];
+		qcom,spm-cmd-spc = [00 20 32 60 70 80 42 03
+				78 80 44 22 50 3b 60 02 32
+				50 0f];
+		qcom,spm-cmd-pc = [00 10 32 60 70 80 b0 11 42
+				07 01 b0 78 80 12 44 a0 50
+				3b 60 02 32 a0 50 0f];
+	};
+
+	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 = <1150000>; /* MAX */
+			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-dig-lower-bound = <950000>;  /* ACTIVE */
+			qcom,latency-us = <100>;
+			qcom,ss-power = <650>;
+			qcom,energy-overhead = <801>;
+			qcom,time-overhead = <200>;
+		};
+
+		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 = <1150000>; /* MAX */
+			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-dig-lower-bound = <950000>;  /* ACTIVE */
+			qcom,latency-us = <2000>;
+			qcom,ss-power = <200>;
+			qcom,energy-overhead = <576000>;
+			qcom,time-overhead = <2000>;
+		};
+
+		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 = <1150000>; /* MAX */
+			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-dig-lower-bound = <950000>;  /* ACTIVE */
+			qcom,latency-us = <8500>;
+			qcom,ss-power = <51>;
+			qcom,energy-overhead = <1122000>;
+			qcom,time-overhead = <8500>;
+		};
+
+		qcom,lpm-level@3 {
+			reg = <0x3>;
+			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <1>;          /* ON */
+			qcom,l2 = <0>;          /* OFF */
+			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-dig-lower-bound = <950000>;  /* ACTIVE */
+			qcom,latency-us = <9000>;
+			qcom,ss-power = <51>;
+			qcom,energy-overhead = <1130300>;
+			qcom,time-overhead = <9000>;
+		};
+
+		qcom,lpm-level@4 {
+			reg = <0x4>;
+			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <1>;          /* ON */
+			qcom,l2 = <0>;          /* OFF */
+			qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-mem-lower-bound = <750000>;  /* RETENTION HIGH */
+			qcom,vdd-dig-upper-bound = <950000>;  /* ACTIVE */
+			qcom,vdd-dig-lower-bound = <750000>;  /* RETENTION HIGH */
+			qcom,latency-us = <10000>;
+			qcom,ss-power = <51>;
+			qcom,energy-overhead = <1130300>;
+			qcom,time-overhead = <10000>;
+		};
+
+		qcom,lpm-level@5 {
+			reg = <0x5>;
+			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <0>;          /* OFF */
+			qcom,l2 = <1>;          /* GDHS */
+			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-dig-lower-bound = <950000>;  /* ACTIVE */
+			qcom,latency-us = <12000>;
+			qcom,ss-power = <14>;
+			qcom,energy-overhead = <2205900>;
+			qcom,time-overhead = <12000>;
+		};
+
+		qcom,lpm-level@6 {
+			reg = <0x6>;
+			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <0>;          /* OFF */
+			qcom,l2 = <0>;          /* OFF */
+			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+			qcom,vdd-dig-lower-bound = <950000>;  /* ACTIVE */
+			qcom,latency-us = <18000>;
+			qcom,ss-power = <12>;
+			qcom,energy-overhead = <2364250>;
+			qcom,time-overhead = <18000>;
+		};
+
+		qcom,lpm-level@7 {
+			reg = <0x7>;
+			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <0>;          /* OFF */
+			qcom,l2 = <0>;          /* OFF */
+			qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
+			qcom,vdd-mem-lower-bound = <750000>;  /* RETENTION HIGH */
+			qcom,vdd-dig-upper-bound = <950000>;  /* ACTIVE */
+			qcom,vdd-dig-lower-bound = <750000>;  /* RETIONTION HIGH */
+			qcom,latency-us = <23500>;
+			qcom,ss-power = <10>;
+			qcom,energy-overhead = <2667000>;
+			qcom,time-overhead = <23500>;
+		};
+
+		qcom,lpm-level@8 {
+			reg = <0x8>;
+			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+			qcom,xo = <0>;          /* OFF */
+			qcom,l2 = <0>;          /* OFF */
+			qcom,vdd-mem-upper-bound = <750000>; /* RETENTION HIGH */
+			qcom,vdd-mem-lower-bound = <750000>; /* RETENTION LOW */
+			qcom,vdd-dig-upper-bound = <750000>; /* RETENTION HIGH */
+			qcom,vdd-dig-lower-bound = <500000>; /* RETENTION LOW */
+			qcom,latency-us = <29700>;
+			qcom,ss-power = <5>;
+			qcom,energy-overhead = <2867000>;
+			qcom,time-overhead = <30000>;
+		};
+	};
+
+	qcom,pm-boot {
+		compatible = "qcom,pm-boot";
+		qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+	};
+};
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 1107412..875b479 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -1113,3 +1113,113 @@
 	return 0;
 }
 #endif
+#ifdef CONFIG_ARCH_MSM8625
+ /*
+  *  Check for any interrupts which are enabled are pending
+  *  in the pending set or not.
+  *  Return :
+  *       0 : No pending interrupts
+  *       1 : Pending interrupts other than A9_M2A_5
+  */
+unsigned int msm_gic_spi_ppi_pending(void)
+{
+	unsigned int i, bit = 0;
+	unsigned int pending_enb = 0, pending = 0;
+	unsigned long value = 0;
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *base = gic_data_dist_base(gic);
+
+	raw_spin_lock(&irq_controller_lock);
+	/*
+	 * PPI and SGI to be included.
+	 * MSM8625_INT_A9_M2A_5 needs to be ignored, as A9_M2A_5
+	 * requesting sleep triggers it
+	 */
+	for (i = 0; (i * 32) < gic->max_irq; i++) {
+		pending = readl_relaxed(base +
+				GIC_DIST_PENDING_SET + i * 4);
+		pending_enb = readl_relaxed(base +
+				GIC_DIST_ENABLE_SET + i * 4);
+		value = pending & pending_enb;
+
+		if (value) {
+			for (bit = 0; bit < 32; bit++) {
+				bit = find_next_bit(&value, 32, bit);
+				if ((bit + 32 * i) != MSM8625_INT_A9_M2A_5) {
+					raw_spin_unlock(&irq_controller_lock);
+					return 1;
+				}
+			}
+		}
+	}
+	raw_spin_unlock(&irq_controller_lock);
+
+	return 0;
+}
+
+void msm_gic_save(bool modem_wake, int from_idle)
+{
+	unsigned int i;
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *base = gic_data_dist_base(gic);
+
+	gic_cpu_save(0);
+	gic_dist_save(0);
+	 /* Disable all the Interrupts, if we enter from idle pc */
+	if (from_idle) {
+		for (i = 0; (i * 32) < gic->max_irq; i++) {
+			raw_spin_lock(&irq_controller_lock);
+			writel_relaxed(0xffffffff, base
+					+ GIC_DIST_ENABLE_CLEAR + i * 4);
+			raw_spin_unlock(&irq_controller_lock);
+		}
+	}
+}
+
+void msm_gic_restore(void)
+{
+	gic_dist_restore(0);
+	gic_cpu_restore(0);
+}
+
+/*
+ * Configure the GIC after we come out of power collapse.
+ * This function will configure some of the GIC registers so as to prepare the
+ * core1 to receive an SPI(ACSR_MP_CORE_IPC1, (32 + 8)), which will bring
+ * core1 out of GDFS.
+ */
+void core1_gic_configure_and_raise(void)
+{
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *base = gic_data_dist_base(gic);
+	unsigned int value = 0;
+
+	raw_spin_lock(&irq_controller_lock);
+
+	value = __raw_readl(base + GIC_DIST_ACTIVE_BIT + 0x4);
+	value |= BIT(8);
+	__raw_writel(value, base + GIC_DIST_ACTIVE_BIT + 0x4);
+	mb();
+
+	value = __raw_readl(base + GIC_DIST_TARGET + 0x24);
+	value |= BIT(13);
+	__raw_writel(value, base + GIC_DIST_TARGET + 0x24);
+	mb();
+
+	value = __raw_readl(base + GIC_DIST_TARGET + 0x28);
+	value |= BIT(1);
+	__raw_writel(value, base + GIC_DIST_TARGET + 0x28);
+	mb();
+
+	value =  __raw_readl(base + GIC_DIST_ENABLE_SET + 0x4);
+	value |= BIT(8);
+	__raw_writel(value, base + GIC_DIST_ENABLE_SET + 0x4);
+	mb();
+
+	value =  __raw_readl(base + GIC_DIST_PENDING_SET + 0x4);
+	value |= BIT(8);
+	__raw_writel(value, base + GIC_DIST_PENDING_SET + 0x4);
+	mb();
+	raw_spin_unlock(&irq_controller_lock);
+}
+#endif
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 5b77374..f195d68 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -309,6 +309,7 @@
 CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT=y
 CONFIG_LEDS_GPIO=y
 CONFIG_LEDS_MSM_PDM=y
+CONFIG_LEDS_PMIC_MPP=y
 CONFIG_SWITCH=y
 CONFIG_SWITCH_GPIO=y
 CONFIG_RTC_CLASS=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 287e7fb..bc350a7 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -220,7 +220,7 @@
 # CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set
 CONFIG_DIAG_CHAR=y
 # CONFIG_HW_RANDOM is not set
-CONFIG_DCC_TTY=y
+# CONFIG_DCC_TTY is not set
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 # CONFIG_I2C_MSM is not set
@@ -309,6 +309,7 @@
 CONFIG_MMC_MSM_SDC3_SUPPORT=y
 CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT=y
 CONFIG_LEDS_MSM_PDM=y
+CONFIG_LEDS_PMIC_MPP=y
 CONFIG_SWITCH=y
 CONFIG_SWITCH_GPIO=y
 CONFIG_RTC_CLASS=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index b5a17cd..fb5cff7 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -311,6 +311,7 @@
 CONFIG_MFD_PM8921_CORE=y
 CONFIG_MFD_PM8821_CORE=y
 CONFIG_MFD_PM8038_CORE=y
+CONFIG_MFD_PM8XXX_SPK=y
 CONFIG_MFD_PM8XXX_BATT_ALARM=y
 CONFIG_WCD9304_CODEC=y
 CONFIG_WCD9310_CODEC=y
@@ -320,6 +321,7 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_IR_GPIO_CIR=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
 CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
 CONFIG_USB_VIDEO_CLASS=y
@@ -334,6 +336,9 @@
 CONFIG_MSM_GEMINI=y
 CONFIG_S5K3L1YX=y
 CONFIG_IMX091=y
+CONFIG_MSM_EEPROM=y
+CONFIG_IMX074_EEPROM=y
+CONFIG_IMX091_EEPROM=y
 CONFIG_RADIO_IRIS=y
 CONFIG_RADIO_IRIS_TRANSPORT=m
 CONFIG_ION=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index e18f0ea..5c01299 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -244,6 +244,7 @@
 CONFIG_HAPTIC_ISA1200=y
 CONFIG_PMIC8XXX_VIBRATOR=y
 CONFIG_QSEECOM=y
+CONFIG_USB_HSIC_SMSC_HUB=y
 CONFIG_SCSI=y
 CONFIG_SCSI_TGT=y
 CONFIG_BLK_DEV_SD=y
@@ -276,6 +277,7 @@
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=m
 CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_MATRIX=y
 CONFIG_KEYBOARD_PMIC8XXX=y
 CONFIG_INPUT_JOYSTICK=y
 CONFIG_JOYSTICK_XPAD=y
@@ -318,6 +320,7 @@
 CONFIG_MFD_PM8921_CORE=y
 CONFIG_MFD_PM8821_CORE=y
 CONFIG_MFD_PM8038_CORE=y
+CONFIG_MFD_PM8XXX_SPK=y
 CONFIG_MFD_PM8XXX_BATT_ALARM=y
 CONFIG_WCD9304_CODEC=y
 CONFIG_WCD9310_CODEC=y
@@ -327,6 +330,7 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_IR_GPIO_CIR=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
 CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
 CONFIG_USB_VIDEO_CLASS=y
@@ -341,6 +345,9 @@
 CONFIG_MSM_GEMINI=y
 CONFIG_S5K3L1YX=y
 CONFIG_IMX091=y
+CONFIG_MSM_EEPROM=y
+CONFIG_IMX074_EEPROM=y
+CONFIG_IMX091_EEPROM=y
 CONFIG_RADIO_IRIS=y
 CONFIG_RADIO_IRIS_TRANSPORT=m
 CONFIG_ION=y
@@ -435,7 +442,6 @@
 CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y
 CONFIG_ANDROID_TIMED_GPIO=y
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
-CONFIG_USB_HSIC_SMSC_HUB=y
 CONFIG_MSM_SSBI=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_BAMDMA=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index 601f235..ac9f465 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -162,7 +162,7 @@
 CONFIG_SCSI_LOGGING=y
 CONFIG_SCSI_SCAN_ASYNC=y
 CONFIG_NETDEVICES=y
-CONFIG_ATH6K_LEGACY=y
+CONFIG_ATH6K_LEGACY_EXT=y
 # CONFIG_MSM_RMNET is not set
 CONFIG_MSM_RMNET_BAM=y
 # CONFIG_INPUT_MOUSEDEV is not set
@@ -180,10 +180,8 @@
 CONFIG_SERIAL_MSM_HSL=y
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
 CONFIG_DIAG_CHAR=y
-CONFIG_HVC_DCC=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM=y
-CONFIG_DCC_TTY=y
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 # CONFIG_I2C_MSM is not set
@@ -242,6 +240,7 @@
 CONFIG_MMC_EMBEDDED_SDIO=y
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_CLKGATE=y
 # CONFIG_MMC_BLOCK_BOUNCE is not set
 CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
@@ -255,6 +254,9 @@
 # CONFIG_RTC_INTF_ALARM is not set
 # CONFIG_RTC_DRV_MSM is not set
 CONFIG_RTC_DRV_PM8XXX=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_LOGGER=y
 CONFIG_MSM_SSBI=y
 CONFIG_SPS=y
 CONFIG_USB_BAM=y
diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h
index df30306..773b380 100644
--- a/arch/arm/include/asm/hardware/cache-l2x0.h
+++ b/arch/arm/include/asm/hardware/cache-l2x0.h
@@ -109,8 +109,8 @@
 #define L2X0_PREFETCH_CTRL_WRAP8_SHIFT		30
 
 #ifndef __ASSEMBLY__
-extern void l2x0_suspend(void);
-extern void l2x0_resume(int collapsed);
+extern void l2cc_suspend(void);
+extern void l2cc_resume(void);
 extern void l2x0_cache_sync(void);
 extern void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask);
 #if defined(CONFIG_CACHE_L2X0) && defined(CONFIG_OF)
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index 5668e75..7e1989e 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -63,4 +63,10 @@
 
 #endif
 
+#ifdef CONFIG_ARCH_MSM8625
+void msm_gic_save(bool modem_wake, int from_idle);
+void msm_gic_restore(void);
+void core1_gic_configure_and_raise(void);
+#endif
+
 #endif
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 3f8ff74..11155d9 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -999,7 +999,7 @@
 		   cpu_name, read_cpuid_id() & 15, elf_platform);
 
 #if defined(CONFIG_SMP)
-	for_each_online_cpu(i) {
+	for_each_present_cpu(i) {
 		/*
 		 * glibc reads /proc/cpuinfo to determine the number of
 		 * online processors, looking for lines beginning with
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index ca3e459..4ecc3a4 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -35,6 +35,7 @@
 	select CLEANCACHE
 	select QCACHE
 	select MSM_PM2 if PM
+	select MSM_RUN_QUEUE_STATS if MSM_SOC_REV_A
 
 config ARCH_MSM7X30
 	bool "MSM7x30"
@@ -128,6 +129,7 @@
 	select MULTI_IRQ_HANDLER
 	select MSM_MULTIMEDIA_USE_ION
 	select MSM_PM8X60 if PM
+	select MSM_RUN_QUEUE_STATS
 
 config ARCH_MSM8960
 	bool "MSM8960"
@@ -169,6 +171,7 @@
 	select MULTI_IRQ_HANDLER
 	select MSM_PM8X60 if PM
 	select HOLES_IN_ZONE if SPARSEMEM
+	select MSM_RUN_QUEUE_STATS
 
 config ARCH_MSM8930
 	bool "MSM8930"
@@ -228,6 +231,19 @@
 	select MSM_PM8X60 if PM
 	select CPU_HAS_L2_PMU
 	select HOLES_IN_ZONE if SPARSEMEM
+	select ENABLE_DMM
+	select MEMORY_HOTPLUG if ENABLE_DMM
+	select MEMORY_HOTREMOVE if ENABLE_DMM
+	select ARCH_ENABLE_MEMORY_HOTPLUG if ENABLE_DMM
+	select ARCH_ENABLE_MEMORY_HOTREMOVE if ENABLE_DMM
+	select MIGRATION if ENABLE_DMM
+	select ARCH_MEMORY_PROBE if ENABLE_DMM
+	select ARCH_MEMORY_REMOVE if ENABLE_DMM
+	select FIX_MOVABLE_ZONE if ENABLE_DMM
+	select CLEANCACHE
+	select QCACHE
+	select MIGHT_HAVE_PCI
+	select ARCH_SUPPORTS_MSI
 
 config ARCH_MSMCOPPER
 	bool "MSM Copper"
@@ -240,6 +256,10 @@
 	select MULTI_IRQ_HANDLER
 	select MSM_MULTIMEDIA_USE_ION
 	select MSM_PIL
+	select MSM_SPM_V2
+	select MSM_L2_SPM
+	select MSM_RPM
+	select MSM_PM8X60 if PM
 
 config ARCH_FSM9XXX
 	bool "FSM9XXX"
@@ -281,6 +301,19 @@
 	select ARCH_MSM_CORTEXMP
 	select MULTI_IRQ_HANDLER
 	select ARM_TICKET_LOCKS
+	select MSM_RUN_QUEUE_STATS
+
+config ARCH_MSM9625
+	bool "MSM9625"
+	select ARM_GIC
+	select GIC_SECURE
+	select ARCH_MSM_CORTEX_A5
+	select SMP
+	select MSM_SMP
+	select CPU_V7
+	select MULTI_IRQ_HANDLER
+	select MSM_V2_TLMM
+
 endmenu
 
 choice
@@ -500,6 +533,14 @@
 	help
 	  Support for the Qualcomm MSM8625 SURF.
 
+config MACH_MSM8625_FFA
+	depends on ARCH_MSM8625
+	depends on !MSM_STACKED_MEMORY
+	default y
+	bool "MSM8625 FFA"
+	help
+	  Support for the Qualcomm MSM8625 FFA.
+
 config MACH_MSM8625_EVB
 	depends on ARCH_MSM8625
 	depends on !MSM_STACKED_MEMORY
@@ -516,6 +557,14 @@
 	help
 	  Support for the Qualcomm MSM8625 Reference Design.
 
+config MACH_MSM8625_EVT
+	depends on ARCH_MSM8625
+	depends on !MSM_STACKED_MEMORY
+	default y
+	bool "MSM8625 EVT"
+	help
+	  Support for the Qualcomm MSM8625 Reference Design.
+
 config MACH_MSM7X30_SURF
        depends on ARCH_MSM7X30
        depends on !MSM_STACKED_MEMORY
@@ -832,6 +881,7 @@
 	default "0x80200000" if ARCH_MSM8930
 	default "0x20200000" if ARCH_MSMCOPPER
 	default "0x10000000" if ARCH_FSM9XXX
+	default "0x20200000" if ARCH_MSM9625
 	default "0x00200000" if !MSM_STACKED_MEMORY
 	default "0x00000000" if ARCH_QSD8X50 && MSM_SOC_REV_A
 	default "0x20000000" if ARCH_QSD8X50
@@ -1181,6 +1231,13 @@
 	    prompt "Package 4"
 endchoice
 
+config MSM_PCIE
+	bool "MSM PCIe Controller driver"
+	depends on PCI && PCI_MSI
+	help
+	  Enables the PCIe functionality by configures PCIe core on
+	  MSM chipset and by enabling the ARM PCI framework extension.
+
 config MSM_RPC_SDIO_XPRT
 	depends on MSM_SDIO_AL
 	default y
@@ -1818,6 +1875,14 @@
 	  Support for booting and shutting down Cortex A5 processors which run
 	  GPS subsystem firmware.
 
+config MSM_PIL_PRONTO
+	tristate "PRONTO (WCNSS) Boot Support"
+	depends on MSM_PIL
+	help
+	  Support for booting and shutting down the PRONTO processor (WCNSS).
+	  PRONTO is the wireless subsystem processor used in bluetooth, wireless
+	  LAN, and FM software applications.
+
 config MSM_SCM
 	bool "Secure Channel Manager (SCM) support"
 	default n
@@ -2049,7 +2114,11 @@
 
 config MSM_RUN_QUEUE_STATS
 	bool "Enable collection and exporting of MSM Run Queue stats to userspace"
-	default y
+	depends on (MSM_SOC_REV_A || ARCH_MSM8X60 || ARCH_MSM8960)
+	help
+	 This option enalbes statistics collection on Run Queue. A daemon
+         in user mode, called MPDecision will be using this data to decide
+         on when to switch off/on the other cores.
 
 config MSM_STANDALONE_POWER_COLLAPSE
        bool "Enable standalone power collapse"
@@ -2168,6 +2237,12 @@
 	  instead of pmem. Selecting this may also involve userspace
 	  dependencies as well.
 
+config MSM_OCMEM
+	bool "MSM On-Chip memory driver (OCMEM)"
+	help
+	  Enable support for On-Chip Memory available on certain MSM chipsets.
+	  OCMEM is a low latency, high performance pool shared by subsystems.
+
 config MSM_RTB
 	bool "Register tracing"
 	help
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 84af813..d633aa7 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -74,6 +74,7 @@
 obj-$(CONFIG_MSM_PIL_MODEM) += pil-modem.o
 obj-$(CONFIG_MSM_PIL_DSPS) += pil-dsps.o
 obj-$(CONFIG_MSM_PIL_GSS) += pil-gss.o
+obj-$(CONFIG_MSM_PIL_PRONTO) += pil-pronto.o
 obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
 obj-$(CONFIG_ARCH_FSM9XXX) += sirc-fsm9xxx.o
 obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o
@@ -155,6 +156,8 @@
 obj-$(CONFIG_MSM_PM) += pm.o
 obj-$(CONFIG_MSM_NOPM) += no-pm.o
 
+obj-$(CONFIG_MSM_PCIE) += pcie.o pcie_irq.o
+
 obj-$(CONFIG_MSM_SPM_V1) += spm.o
 obj-$(CONFIG_MSM_SPM_V2) += spm-v2.o spm_devices.o
 
@@ -200,6 +203,7 @@
 	obj-$(CONFIG_ARCH_MSM8960) += cpuidle.o
 	obj-$(CONFIG_ARCH_MSM8X60) += cpuidle.o
 	obj-$(CONFIG_ARCH_MSM9615) += cpuidle.o
+	obj-$(CONFIG_ARCH_MSMCOPPER) += cpuidle.o
 endif
 
 ifdef CONFIG_MSM_CAMERA_V4L2
@@ -240,6 +244,8 @@
 obj-$(CONFIG_MACH_MSM8625_SURF) +=  board-msm7x27a.o board-7627a-all.o
 obj-$(CONFIG_MACH_MSM8625_EVB) +=  board-qrd7627a.o board-7627a-all.o
 obj-$(CONFIG_MACH_MSM8625_QRD7) +=  board-qrd7627a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM8625_FFA) += board-msm7x27a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM8625_EVT) += board-msm7x27a.o board-7627a-all.o
 obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o memory_topology.o
 obj-$(CONFIG_ARCH_MSM7X30) += clock-local.o clock-7x30.o acpuclock-7x30.o clock-pll.o
 obj-$(CONFIG_MACH_MSM7X25_SURF) += board-msm7x27.o devices-msm7x25.o
@@ -274,7 +280,7 @@
 obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o clock-pll.o
 obj-$(CONFIG_ARCH_MSMCOPPER) += board-copper.o board-dt.o board-copper-regulator.o board-copper-gpiomux.o
 obj-$(CONFIG_ARCH_MSMCOPPER) += acpuclock-krait.o acpuclock-copper.o
-obj-$(CONFIG_ARCH_MSMCOPPER) += clock-local2.o
+obj-$(CONFIG_ARCH_MSMCOPPER) += clock-local2.o clock-pll.o clock-copper.o
 
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
@@ -291,7 +297,14 @@
 obj-$(CONFIG_HTC_HEADSET) += htc_headset.o
 obj-$(CONFIG_MSM_RMT_STORAGE_CLIENT) += rmt_storage_client.o
 obj-$(CONFIG_MSM_SDIO_SMEM) += sdio_smem.o
-obj-$(CONFIG_MSM_RPM) += rpm.o rpm_resources.o
+obj-$(CONFIG_MSM_RPM) += rpm.o
+ifdef CONFIG_MSM_RPM
+	obj-$(CONFIG_ARCH_APQ8064) += rpm_resources.o
+	obj-$(CONFIG_ARCH_MSM8960) += rpm_resources.o
+	obj-$(CONFIG_ARCH_MSM8X60) += rpm_resources.o
+	obj-$(CONFIG_ARCH_MSM9615) += rpm_resources.o
+	obj-$(CONFIG_ARCH_MSMCOPPER) += lpm_levels.o
+endif
 obj-$(CONFIG_MSM_MPM) += mpm.o
 obj-$(CONFIG_MSM_RPM_STATS_LOG) += rpm_stats.o
 obj-$(CONFIG_MSM_RPM_LOG) += rpm_log.o
@@ -305,6 +318,7 @@
 ifdef CONFIG_VCM
 obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-vcm.o
 endif
+obj-$(CONFIG_MSM_OCMEM) += ocmem.o
 
 obj-$(CONFIG_ARCH_MSM7X27) += gpiomux-7x27.o gpiomux-v1.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-7x30.o gpiomux-v1.o gpiomux.o
diff --git a/arch/arm/mach-msm/acpuclock-7627.c b/arch/arm/mach-msm/acpuclock-7627.c
index b6c0b26..99311d4 100644
--- a/arch/arm/mach-msm/acpuclock-7627.c
+++ b/arch/arm/mach-msm/acpuclock-7627.c
@@ -527,7 +527,7 @@
 
 	if (reason == SETRATE_CPUFREQ) {
 		if (strt_s->pll != tgt_s->pll && tgt_s->pll != ACPU_PLL_TCXO) {
-			rc = clk_prepare_enable(pll_clk[tgt_s->pll].clk);
+			rc = clk_enable(pll_clk[tgt_s->pll].clk);
 			if (rc < 0) {
 				pr_err("PLL%d enable failed (%d)\n",
 					tgt_s->pll, rc);
@@ -602,7 +602,7 @@
 
 		if (cur_s->pll != ACPU_PLL_TCXO
 		    && !(plls_enabled & (1 << cur_s->pll))) {
-			rc = clk_prepare_enable(pll_clk[cur_s->pll].clk);
+			rc = clk_enable(pll_clk[cur_s->pll].clk);
 			if (rc < 0) {
 				pr_err("PLL%d enable failed (%d)\n",
 					cur_s->pll, rc);
@@ -642,7 +642,7 @@
 		plls_enabled &= ~(1 << tgt_s->pll);
 	for (pll = ACPU_PLL_0; pll < ACPU_PLL_END; pll++)
 		if (plls_enabled & (1 << pll))
-			clk_disable_unprepare(pll_clk[pll].clk);
+			clk_disable(pll_clk[pll].clk);
 
 	/* Nothing else to do for power collapse. */
 	if (reason == SETRATE_PC)
@@ -669,6 +669,18 @@
 	int res;
 
 	/*
+	 * Prepare all the PLLs because we enable/disable them
+	 * from atomic context and can't always ensure they're
+	 * all prepared in non-atomic context. Same goes for
+	 * ebi1_acpu_clk.
+	 */
+	BUG_ON(clk_prepare(pll_clk[ACPU_PLL_0].clk));
+	BUG_ON(clk_prepare(pll_clk[ACPU_PLL_1].clk));
+	BUG_ON(clk_prepare(pll_clk[ACPU_PLL_2].clk));
+	BUG_ON(clk_prepare(pll_clk[ACPU_PLL_4].clk));
+	BUG_ON(clk_prepare(drv_state.ebi1_clk));
+
+	/*
 	 * Determine the rate of ACPU clock
 	 */
 
@@ -696,7 +708,7 @@
 
 	drv_state.current_speed = speed;
 	if (speed->pll != ACPU_PLL_TCXO) {
-		if (clk_prepare_enable(pll_clk[speed->pll].clk))
+		if (clk_enable(pll_clk[speed->pll].clk))
 			pr_warning("Failed to vote for boot PLL\n");
 	}
 
@@ -711,7 +723,7 @@
 	res = clk_set_rate(drv_state.ebi1_clk, speed->axiclk_khz * 1000);
 	if (res < 0)
 		pr_warning("Setting AXI min rate failed (%d)\n", res);
-	res = clk_prepare_enable(drv_state.ebi1_clk);
+	res = clk_enable(drv_state.ebi1_clk);
 	if (res < 0)
 		pr_warning("Enabling AXI clock failed (%d)\n", res);
 
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index eba5637..d53e471 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -241,6 +241,8 @@
 static int disconnect_ack;
 static LIST_HEAD(bam_other_notify_funcs);
 static DEFINE_MUTEX(smsm_cb_lock);
+static DEFINE_MUTEX(delayed_ul_vote_lock);
+static int need_delayed_ul_vote;
 
 struct outside_notify_func {
 	void (*notify)(void *, int, unsigned long);
@@ -1593,6 +1595,7 @@
 static void ul_wakeup(void)
 {
 	int ret;
+	int do_vote_dfab = 0;
 
 	mutex_lock(&wakeup_lock);
 	if (bam_is_connected) { /* bam got connected before lock grabbed */
@@ -1601,21 +1604,37 @@
 		return;
 	}
 
+	/*
+	 * if someone is voting for UL before bam is inited (modem up first
+	 * time), set flag for init to kickoff ul wakeup once bam is inited
+	 */
+	mutex_lock(&delayed_ul_vote_lock);
+	if (unlikely(!bam_mux_initialized)) {
+		need_delayed_ul_vote = 1;
+		mutex_unlock(&delayed_ul_vote_lock);
+		mutex_unlock(&wakeup_lock);
+		return;
+	}
+	mutex_unlock(&delayed_ul_vote_lock);
+
 	if (a2_pc_disabled) {
 		/*
 		 * don't grab the wakelock the first time because it is
 		 * already grabbed when a2 powers on
 		 */
-		if (likely(a2_pc_disabled_wakelock_skipped))
+		if (likely(a2_pc_disabled_wakelock_skipped)) {
 			grab_wakelock();
-		else
+			do_vote_dfab = 1; /* vote must occur after wait */
+		} else {
 			a2_pc_disabled_wakelock_skipped = 1;
+		}
 		if (wait_for_dfab) {
 			ret = wait_for_completion_timeout(
 					&dfab_unvote_completion, HZ);
 			BUG_ON(ret == 0);
 		}
-		vote_dfab();
+		if (likely(do_vote_dfab))
+			vote_dfab();
 		schedule_delayed_work(&ul_timeout_work,
 				msecs_to_jiffies(UL_TIMEOUT_DELAY));
 		bam_is_connected = 1;
@@ -2012,7 +2031,13 @@
 		goto rx_event_reg_failed;
 	}
 
+	mutex_lock(&delayed_ul_vote_lock);
 	bam_mux_initialized = 1;
+	if (need_delayed_ul_vote) {
+		need_delayed_ul_vote = 0;
+		msm_bam_dmux_kickoff_ul_wakeup();
+	}
+	mutex_unlock(&delayed_ul_vote_lock);
 	toggle_apps_ack();
 	bam_connection_is_active = 1;
 	complete_all(&bam_connection_completion);
@@ -2079,6 +2104,14 @@
 		goto register_bam_failed;
 	}
 	a2_device_handle = h;
+
+	mutex_lock(&delayed_ul_vote_lock);
+	bam_mux_initialized = 1;
+	if (need_delayed_ul_vote) {
+		need_delayed_ul_vote = 0;
+		msm_bam_dmux_kickoff_ul_wakeup();
+	}
+	mutex_unlock(&delayed_ul_vote_lock);
 	toggle_apps_ack();
 
 	return 0;
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 24f0f41..36953ef 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -468,6 +468,15 @@
 	.csi_lane_params = &imx074_csi_lane_params,
 };
 
+static struct i2c_board_info imx074_eeprom_i2c_info = {
+	I2C_BOARD_INFO("imx074_eeprom", 0x34 << 1),
+};
+
+static struct msm_eeprom_info imx074_eeprom_info = {
+	.board_info     = &imx074_eeprom_i2c_info,
+	.bus_id         = APQ_8064_GSBI4_QUP_I2C_BUS_ID,
+};
+
 static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
 	.sensor_name	= "imx074",
 	.pdata	= &msm_camera_csi_device_data[0],
@@ -477,7 +486,9 @@
 	.camera_type = BACK_CAMERA_2D,
 	.sensor_type = BAYER_SENSOR,
 	.actuator_info = &msm_act_main_cam_0_info,
+	.eeprom_info = &imx074_eeprom_info,
 };
+
 static struct msm_camera_csi_lane_params imx091_csi_lane_params = {
 	.csi_lane_assign = 0xE4,
 	.csi_lane_mask = 0xF,
@@ -503,6 +514,15 @@
 	.csi_lane_params = &imx091_csi_lane_params,
 };
 
+static struct i2c_board_info imx091_eeprom_i2c_info = {
+	I2C_BOARD_INFO("imx091_eeprom", 0x21),
+};
+
+static struct msm_eeprom_info imx091_eeprom_info = {
+	.board_info     = &imx091_eeprom_i2c_info,
+	.bus_id         = APQ_8064_GSBI4_QUP_I2C_BUS_ID,
+};
+
 static struct msm_camera_sensor_info msm_camera_sensor_imx091_data = {
 	.sensor_name	= "imx091",
 	.pdata	= &msm_camera_csi_device_data[0],
@@ -512,6 +532,7 @@
 	.camera_type = BACK_CAMERA_2D,
 	.sensor_type = BAYER_SENSOR,
 	.actuator_info = &msm_act_main_cam_1_info,
+	.eeprom_info = &imx091_eeprom_info,
 };
 
 static struct camera_vreg_t apq_8064_s5k3l1yx_vreg[] = {
diff --git a/arch/arm/mach-msm/board-8064-display.c b/arch/arm/mach-msm/board-8064-display.c
index ee1a2ae..60bc26c 100644
--- a/arch/arm/mach-msm/board-8064-display.c
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -30,32 +30,13 @@
 
 #ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
 /* prim = 1366 x 768 x 3(bpp) x 3(pages) */
-#define MSM_FB_PRIM_BUF_SIZE roundup(1920 * 1080 * 4 * 3, 0x10000)
+#define MSM_FB_PRIM_BUF_SIZE roundup(1920 * 1088 * 4 * 3, 0x10000)
 #else
 /* prim = 1366 x 768 x 3(bpp) x 2(pages) */
-#define MSM_FB_PRIM_BUF_SIZE roundup(1920 * 1080 * 4 * 2, 0x10000)
+#define MSM_FB_PRIM_BUF_SIZE roundup(1920 * 1088 * 4 * 2, 0x10000)
 #endif
 
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
-#define MSM_FB_EXT_BUF_SIZE \
-		(roundup((1920 * 1088 * 2), 4096) * 1) /* 2 bpp x 1 page */
-#elif defined(CONFIG_FB_MSM_TVOUT)
-#define MSM_FB_EXT_BUF_SIZE \
-		(roundup((720 * 576 * 2), 4096) * 2) /* 2 bpp x 2 pages */
-#else
-#define MSM_FB_EXT_BUF_SIZE	0
-#endif
-
-#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
-#define MSM_FB_WFD_BUF_SIZE \
-		(roundup((1280 * 736 * 2), 4096) * 1) /* 2 bpp x 1 page */
-#else
-#define MSM_FB_WFD_BUF_SIZE     0
-#endif
-
-#define MSM_FB_SIZE \
-	roundup(MSM_FB_PRIM_BUF_SIZE + \
-		MSM_FB_EXT_BUF_SIZE + MSM_FB_WFD_BUF_SIZE, 4096)
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE, 4096)
 
 #ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
 #define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((1376 * 768 * 3 * 2), 4096)
@@ -615,7 +596,7 @@
 {
 	if (machine_is_apq8064_cdp() ||
 	    machine_is_apq8064_liquid()) {
-		u32 ver = socinfo_get_platform_version();
+		u32 ver = socinfo_get_version();
 		if ((SOCINFO_VERSION_MAJOR(ver) == 1) &&
 		    (SOCINFO_VERSION_MINOR(ver) == 0))
 			return 1;
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 99a3fa1..3431cd0 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -433,6 +433,19 @@
 	.drv = GPIOMUX_DRV_12MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
+
+static struct gpiomux_setting sx150x_suspended_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sx150x_active_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
 static struct gpiomux_setting cyts_sleep_sus_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_6MA,
@@ -968,6 +981,16 @@
 	},
 };
 
+static struct msm_gpiomux_config sx150x_int_configs[] __initdata = {
+	{
+		.gpio      = 81,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &sx150x_suspended_cfg,
+			[GPIOMUX_ACTIVE] = &sx150x_active_cfg,
+		},
+	},
+};
+
 void __init apq8064_init_gpiomux(void)
 {
 	int rc;
@@ -989,6 +1012,8 @@
 		msm_gpiomux_install(vcap_configs,
 				ARRAY_SIZE(vcap_configs));
 #endif
+		msm_gpiomux_install(sx150x_int_configs,
+				ARRAY_SIZE(sx150x_int_configs));
 	} else {
 		#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
 		msm_gpiomux_install(apq8064_ethernet_configs,
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index 2cab803..41dccac 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -148,26 +148,26 @@
 	},
 };
 
-static const char *kgsl_3d0_iommu0_ctx_names[] = {
-	"gfx3d_user",
-	/* priv_ctx goes here */
+static const struct kgsl_iommu_ctx kgsl_3d0_iommu0_ctxs[] = {
+	{ "gfx3d_user", 0 },
+	{ "gfx3d_priv", 1 },
 };
 
-static const char *kgsl_3d0_iommu1_ctx_names[] = {
-	"gfx3d1_user",
-	/* priv_ctx goes here */
+static const struct kgsl_iommu_ctx kgsl_3d0_iommu1_ctxs[] = {
+	{ "gfx3d1_user", 0 },
+	{ "gfx3d1_priv", 1 },
 };
 
 static struct kgsl_device_iommu_data kgsl_3d0_iommu_data[] = {
 	{
-		.iommu_ctx_names = kgsl_3d0_iommu0_ctx_names,
-		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu0_ctx_names),
+		.iommu_ctxs = kgsl_3d0_iommu0_ctxs,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu0_ctxs),
 		.physstart = 0x07C00000,
 		.physend = 0x07C00000 + SZ_1M - 1,
 	},
 	{
-		.iommu_ctx_names = kgsl_3d0_iommu1_ctx_names,
-		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu1_ctx_names),
+		.iommu_ctxs = kgsl_3d0_iommu1_ctxs,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu1_ctxs),
 		.physstart = 0x07D00000,
 		.physend = 0x07D00000 + SZ_1M - 1,
 	},
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index f915657..91fd400 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -126,6 +126,7 @@
 	PM8921_GPIO_INPUT(38, PM_GPIO_PULL_UP_30),
 	/* TABLA CODEC RESET */
 	PM8921_GPIO_OUTPUT(34, 1, MED),
+	PM8921_GPIO_INPUT(31, PM_GPIO_PULL_NO),
 };
 
 static struct pm8xxx_gpio_init pm8921_mtp_kp_gpios[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 7bb8af9..58e83a0 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -104,6 +104,9 @@
 VREG_CONSUMERS(L18) = {
 	REGULATOR_SUPPLY("8921_l18",		NULL),
 };
+VREG_CONSUMERS(L21) = {
+	REGULATOR_SUPPLY("8921_l21",		NULL),
+};
 VREG_CONSUMERS(L22) = {
 	REGULATOR_SUPPLY("8921_l22",		NULL),
 };
@@ -137,6 +140,9 @@
 	REGULATOR_SUPPLY("8921_l28",		NULL),
 	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.1"),
 };
+VREG_CONSUMERS(L29) = {
+	REGULATOR_SUPPLY("8921_l29",		NULL),
+};
 VREG_CONSUMERS(S1) = {
 	REGULATOR_SUPPLY("8921_s1",		NULL),
 };
@@ -180,6 +186,9 @@
 VREG_CONSUMERS(S7) = {
 	REGULATOR_SUPPLY("8921_s7",		NULL),
 };
+VREG_CONSUMERS(S8) = {
+	REGULATOR_SUPPLY("8921_s8",		NULL),
+};
 VREG_CONSUMERS(LVS1) = {
 	REGULATOR_SUPPLY("8921_lvs1",		NULL),
 	REGULATOR_SUPPLY("iris_vddio",		"wcnss_wlan.0"),
@@ -550,14 +559,15 @@
 	RPM_SMPS(S1, 1, 1, 0, 1225000, 1225000, NULL, 100000, 3p20, NONE, NONE),
 	RPM_SMPS(S2, 0, 1, 0, 1300000, 1300000, NULL,      0, 1p60, NONE, NONE),
 	RPM_SMPS(S3, 0, 1, 1,  500000, 1150000, NULL, 100000, 4p80, NONE, NONE),
-	RPM_SMPS(S4, 1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60, NONE, NONE),
+	RPM_SMPS(S4, 1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60, AUTO, AUTO),
 	RPM_SMPS(S7, 0, 1, 0, 1300000, 1300000, NULL, 100000, 3p20, NONE, NONE),
+	RPM_SMPS(S8, 0, 1, 0, 2200000, 2200000, NULL,      0, 1p60, NONE, NONE),
 
 	/*	ID a_on pd ss min_uV   max_uV   supply    sys_uA init_ip */
-	RPM_LDO(L1,  1, 1, 0, 1100000, 1100000, "8921_s4",     0, 10000),
+	RPM_LDO(L1,  1, 1, 0, 1100000, 1100000, "8921_s4",     0,  1000),
 	RPM_LDO(L2,  0, 1, 0, 1200000, 1200000, "8921_s4",     0,     0),
 	RPM_LDO(L3,  0, 1, 0, 3075000, 3075000, NULL,          0,     0),
-	RPM_LDO(L4,  1, 1, 0, 1800000, 1800000, NULL,      10000, 10000),
+	RPM_LDO(L4,  1, 1, 0, 1800000, 1800000, NULL,          0, 10000),
 	RPM_LDO(L5,  0, 1, 0, 2950000, 2950000, NULL,          0,     0),
 	RPM_LDO(L6,  0, 1, 0, 2950000, 2950000, NULL,          0,     0),
 	RPM_LDO(L7,  0, 1, 0, 1850000, 2950000, NULL,          0,     0),
@@ -571,12 +581,14 @@
 	RPM_LDO(L16, 0, 1, 0, 2800000, 2800000, NULL,          0,     0),
 	RPM_LDO(L17, 0, 1, 0, 2000000, 2000000, NULL,          0,     0),
 	RPM_LDO(L18, 0, 1, 0, 1300000, 1800000, "8921_s4",     0,     0),
+	RPM_LDO(L21, 0, 1, 0, 1050000, 1050000, NULL,          0,     0),
 	RPM_LDO(L22, 0, 1, 0, 2600000, 2600000, NULL,          0,     0),
 	RPM_LDO(L23, 0, 1, 0, 1800000, 1800000, NULL,          0,     0),
 	RPM_LDO(L24, 0, 1, 1,  750000, 1150000, "8921_s1", 10000, 10000),
 	RPM_LDO(L25, 1, 1, 0, 1225000, 1225000, "8921_s1", 10000, 10000),
 	RPM_LDO(L27, 0, 1, 0, 1100000, 1100000, "8921_s7",     0,     0),
 	RPM_LDO(L28, 0, 1, 0, 1050000, 1050000, "8921_s7",     0,     0),
+	RPM_LDO(L29, 0, 1, 0, 2000000, 2000000, NULL,          0,     0),
 
 	/*     ID  a_on pd ss                   supply */
 	RPM_VS(LVS1, 0, 1, 0,                   "8921_s4"),
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index d91408a..b4e7d35 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -280,6 +280,13 @@
 			apq8064_sdc3_pdata->wpswitch_gpio = 0;
 			apq8064_sdc3_pdata->wpswitch_polarity = 0;
 		}
+		if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
+			machine_is_mpq8064_dtv()) {
+			apq8064_sdc3_pdata->status_gpio =
+				PM8921_GPIO_PM_TO_SYS(31);
+			apq8064_sdc3_pdata->status_irq =
+				PM8921_GPIO_IRQ(PM8921_IRQ_BASE, 31);
+		}
 		apq8064_add_sdcc(3, apq8064_sdc3_pdata);
 	}
 }
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 5b0b9c3..62f5d70 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -27,6 +27,7 @@
 #include <linux/platform_data/qcom_crypto_device.h>
 #include <linux/ion.h>
 #include <linux/memory.h>
+#include <linux/memblock.h>
 #include <linux/i2c/atmel_mxt_ts.h>
 #include <linux/cyttsp.h>
 #include <linux/i2c/isa1200.h>
@@ -67,6 +68,7 @@
 #include <mach/msm_rtb.h>
 #include <sound/cs8427.h>
 #include <media/gpio-ir-recv.h>
+#include <linux/fmem.h>
 
 #include "msm_watchdog.h"
 #include "board-8064.h"
@@ -107,6 +109,11 @@
 #define MSM_ION_HEAP_NUM	1
 #endif
 
+#define APQ8064_FIXED_AREA_START 0xa0000000
+#define MAX_FIXED_AREA_SIZE	0x10000000
+#define MSM_MM_FW_SIZE		0x200000
+#define APQ8064_FW_START	(APQ8064_FIXED_AREA_START - MSM_MM_FW_SIZE)
+
 #ifdef CONFIG_KERNEL_PMEM_EBI_REGION
 static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
 static int __init pmem_kernel_ebi1_size_setup(char *p)
@@ -154,7 +161,7 @@
 	.memory_type = MEMTYPE_EBI1,
 };
 
-static struct platform_device android_pmem_device = {
+static struct platform_device apq8064_android_pmem_device = {
 	.name = "android_pmem",
 	.id = 0,
 	.dev = {.platform_data = &android_pmem_pdata},
@@ -166,7 +173,7 @@
 	.cached = 0,
 	.memory_type = MEMTYPE_EBI1,
 };
-static struct platform_device android_pmem_adsp_device = {
+static struct platform_device apq8064_android_pmem_adsp_device = {
 	.name = "android_pmem",
 	.id = 2,
 	.dev = { .platform_data = &android_pmem_adsp_pdata },
@@ -179,7 +186,7 @@
 	.memory_type = MEMTYPE_EBI1,
 };
 
-static struct platform_device android_pmem_audio_device = {
+static struct platform_device apq8064_android_pmem_audio_device = {
 	.name = "android_pmem",
 	.id = 4,
 	.dev = { .platform_data = &android_pmem_audio_pdata },
@@ -187,6 +194,9 @@
 #endif /* CONFIG_MSM_MULTIMEDIA_USE_ION */
 #endif /* CONFIG_ANDROID_PMEM */
 
+struct fmem_platform_data apq8064_fmem_pdata = {
+};
+
 static struct memtype_reserve apq8064_reserve_table[] __initdata = {
 	[MEMTYPE_SMI] = {
 	},
@@ -198,35 +208,10 @@
 	},
 };
 
-#if defined(CONFIG_MSM_RTB)
-static struct msm_rtb_platform_data msm_rtb_pdata = {
-	.size = SZ_1M,
-};
-
-static int __init msm_rtb_set_buffer_size(char *p)
-{
-	int s;
-
-	s = memparse(p, NULL);
-	msm_rtb_pdata.size = ALIGN(s, SZ_4K);
-	return 0;
-}
-early_param("msm_rtb_size", msm_rtb_set_buffer_size);
-
-
-static struct platform_device msm_rtb_device = {
-	.name           = "msm_rtb",
-	.id             = -1,
-	.dev            = {
-		.platform_data = &msm_rtb_pdata,
-	},
-};
-#endif
-
 static void __init reserve_rtb_memory(void)
 {
 #if defined(CONFIG_MSM_RTB)
-	apq8064_reserve_table[MEMTYPE_EBI1].size += msm_rtb_pdata.size;
+	apq8064_reserve_table[MEMTYPE_EBI1].size += apq8064_rtb_pdata.size;
 #endif
 }
 
@@ -268,26 +253,37 @@
 	return MEMTYPE_EBI1;
 }
 
+#define FMEM_ENABLED 1
+
 #ifdef CONFIG_ION_MSM
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-static struct ion_cp_heap_pdata cp_mm_ion_pdata = {
+static struct ion_cp_heap_pdata cp_mm_apq8064_ion_pdata = {
 	.permission_type = IPT_TYPE_MM_CARVEOUT,
 	.align = PAGE_SIZE,
+	.reusable = FMEM_ENABLED,
+	.mem_is_fmem = FMEM_ENABLED,
+	.fixed_position = FIXED_MIDDLE,
 };
 
-static struct ion_cp_heap_pdata cp_mfc_ion_pdata = {
+static struct ion_cp_heap_pdata cp_mfc_apq8064_ion_pdata = {
 	.permission_type = IPT_TYPE_MFC_SHAREDMEM,
 	.align = PAGE_SIZE,
+	.reusable = 0,
+	.mem_is_fmem = FMEM_ENABLED,
+	.fixed_position = FIXED_HIGH,
 };
 
-static struct ion_co_heap_pdata co_ion_pdata = {
+static struct ion_co_heap_pdata co_apq8064_ion_pdata = {
 	.adjacent_mem_id = INVALID_HEAP_ID,
 	.align = PAGE_SIZE,
+	.mem_is_fmem = 0,
 };
 
-static struct ion_co_heap_pdata fw_co_ion_pdata = {
+static struct ion_co_heap_pdata fw_co_apq8064_ion_pdata = {
 	.adjacent_mem_id = ION_CP_MM_HEAP_ID,
 	.align = SZ_128K,
+	.mem_is_fmem = FMEM_ENABLED,
+	.fixed_position = FIXED_LOW,
 };
 #endif
 
@@ -302,7 +298,7 @@
  * to each other.
  * Don't swap the order unless you know what you are doing!
  */
-static struct ion_platform_data ion_pdata = {
+static struct ion_platform_data apq8064_ion_pdata = {
 	.nr = MSM_ION_HEAP_NUM,
 	.heaps = {
 		{
@@ -317,7 +313,7 @@
 			.name	= ION_MM_HEAP_NAME,
 			.size	= MSM_ION_MM_SIZE,
 			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &cp_mm_ion_pdata,
+			.extra_data = (void *) &cp_mm_apq8064_ion_pdata,
 		},
 		{
 			.id	= ION_MM_FIRMWARE_HEAP_ID,
@@ -325,7 +321,7 @@
 			.name	= ION_MM_FIRMWARE_HEAP_NAME,
 			.size	= MSM_ION_MM_FW_SIZE,
 			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &fw_co_ion_pdata,
+			.extra_data = (void *) &fw_co_apq8064_ion_pdata,
 		},
 		{
 			.id	= ION_CP_MFC_HEAP_ID,
@@ -333,7 +329,7 @@
 			.name	= ION_MFC_HEAP_NAME,
 			.size	= MSM_ION_MFC_SIZE,
 			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &cp_mfc_ion_pdata,
+			.extra_data = (void *) &cp_mfc_apq8064_ion_pdata,
 		},
 #ifndef CONFIG_MSM_IOMMU
 		{
@@ -342,7 +338,7 @@
 			.name	= ION_SF_HEAP_NAME,
 			.size	= MSM_ION_SF_SIZE,
 			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &co_ion_pdata,
+			.extra_data = (void *) &co_apq8064_ion_pdata,
 		},
 #endif
 		{
@@ -356,7 +352,7 @@
 			.name	= ION_QSECOM_HEAP_NAME,
 			.size	= MSM_ION_QSECOM_SIZE,
 			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &co_ion_pdata,
+			.extra_data = (void *) &co_apq8064_ion_pdata,
 		},
 		{
 			.id	= ION_AUDIO_HEAP_ID,
@@ -364,28 +360,193 @@
 			.name	= ION_AUDIO_HEAP_NAME,
 			.size	= MSM_ION_AUDIO_SIZE,
 			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &co_ion_pdata,
+			.extra_data = (void *) &co_apq8064_ion_pdata,
 		},
 #endif
 	}
 };
 
-static struct platform_device ion_dev = {
+static struct platform_device apq8064_ion_dev = {
 	.name = "ion-msm",
 	.id = 1,
-	.dev = { .platform_data = &ion_pdata },
+	.dev = { .platform_data = &apq8064_ion_pdata },
 };
 #endif
 
+static struct platform_device apq8064_fmem_device = {
+	.name = "fmem",
+	.id = 1,
+	.dev = { .platform_data = &apq8064_fmem_pdata },
+};
+
+static void __init reserve_mem_for_ion(enum ion_memory_types mem_type,
+				      unsigned long size)
+{
+	apq8064_reserve_table[mem_type].size += size;
+}
+
+static void __init apq8064_reserve_fixed_area(unsigned long fixed_area_size)
+{
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+	int ret;
+
+	if (fixed_area_size > MAX_FIXED_AREA_SIZE)
+		panic("fixed area size is larger than %dM\n",
+			MAX_FIXED_AREA_SIZE >> 20);
+
+	reserve_info->fixed_area_size = fixed_area_size;
+	reserve_info->fixed_area_start = APQ8064_FW_START;
+
+	ret = memblock_remove(reserve_info->fixed_area_start,
+		reserve_info->fixed_area_size);
+	BUG_ON(ret);
+#endif
+}
+
+/**
+ * Reserve memory for ION and calculate amount of reusable memory for fmem.
+ * We only reserve memory for heaps that are not reusable. However, we only
+ * support one reusable heap at the moment so we ignore the reusable flag for
+ * other than the first heap with reusable flag set. Also handle special case
+ * for video heaps (MM,FW, and MFC). Video requires heaps MM and MFC to be
+ * at a higher address than FW in addition to not more than 256MB away from the
+ * base address of the firmware. This means that if MM is reusable the other
+ * two heaps must be allocated in the same region as FW. This is handled by the
+ * mem_is_fmem flag in the platform data. In addition the MM heap must be
+ * adjacent to the FW heap for content protection purposes.
+ */
 static void __init reserve_ion_memory(void)
 {
 #if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
-	apq8064_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MM_SIZE;
-	apq8064_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MM_FW_SIZE;
-	apq8064_reserve_table[MEMTYPE_EBI1].size += MSM_ION_SF_SIZE;
-	apq8064_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MFC_SIZE;
-	apq8064_reserve_table[MEMTYPE_EBI1].size += MSM_ION_QSECOM_SIZE;
-	apq8064_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
+	unsigned int i;
+	unsigned int reusable_count = 0;
+	unsigned int fixed_size = 0;
+	unsigned int fixed_low_size, fixed_middle_size, fixed_high_size;
+	unsigned long fixed_low_start, fixed_middle_start, fixed_high_start;
+
+	apq8064_fmem_pdata.size = 0;
+	apq8064_fmem_pdata.reserved_size_low = 0;
+	apq8064_fmem_pdata.reserved_size_high = 0;
+	fixed_low_size = 0;
+	fixed_middle_size = 0;
+	fixed_high_size = 0;
+
+	/* We only support 1 reusable heap. Check if more than one heap
+	 * is specified as reusable and set as non-reusable if found.
+	 */
+	for (i = 0; i < apq8064_ion_pdata.nr; ++i) {
+		const struct ion_platform_heap *heap =
+			&(apq8064_ion_pdata.heaps[i]);
+
+		if (heap->type == ION_HEAP_TYPE_CP && heap->extra_data) {
+			struct ion_cp_heap_pdata *data = heap->extra_data;
+
+			reusable_count += (data->reusable) ? 1 : 0;
+
+			if (data->reusable && reusable_count > 1) {
+				pr_err("%s: Too many heaps specified as "
+					"reusable. Heap %s was not configured "
+					"as reusable.\n", __func__, heap->name);
+				data->reusable = 0;
+			}
+		}
+	}
+
+	for (i = 0; i < apq8064_ion_pdata.nr; ++i) {
+		const struct ion_platform_heap *heap =
+			&(apq8064_ion_pdata.heaps[i]);
+
+		if (heap->extra_data) {
+			int fixed_position = NOT_FIXED;
+			int mem_is_fmem = 0;
+
+			switch (heap->type) {
+			case ION_HEAP_TYPE_CP:
+				mem_is_fmem = ((struct ion_cp_heap_pdata *)
+					heap->extra_data)->mem_is_fmem;
+				fixed_position = ((struct ion_cp_heap_pdata *)
+					heap->extra_data)->fixed_position;
+				break;
+			case ION_HEAP_TYPE_CARVEOUT:
+				mem_is_fmem = ((struct ion_co_heap_pdata *)
+					heap->extra_data)->mem_is_fmem;
+				fixed_position = ((struct ion_co_heap_pdata *)
+					heap->extra_data)->fixed_position;
+				break;
+			default:
+				break;
+			}
+
+			if (fixed_position != NOT_FIXED)
+				fixed_size += heap->size;
+			else
+				reserve_mem_for_ion(MEMTYPE_EBI1, heap->size);
+
+			if (fixed_position == FIXED_LOW)
+				fixed_low_size += heap->size;
+			else if (fixed_position == FIXED_MIDDLE)
+				fixed_middle_size += heap->size;
+			else if (fixed_position == FIXED_HIGH)
+				fixed_high_size += heap->size;
+
+			if (mem_is_fmem)
+				apq8064_fmem_pdata.size += heap->size;
+		}
+	}
+
+	if (!fixed_size)
+		return;
+
+	if (apq8064_fmem_pdata.size) {
+		apq8064_fmem_pdata.reserved_size_low = fixed_low_size;
+		apq8064_fmem_pdata.reserved_size_high = fixed_high_size;
+	}
+
+	/* Since the fixed area may be carved out of lowmem,
+	 * make sure the length is a multiple of 1M.
+	 */
+	fixed_size = (fixed_size + MSM_MM_FW_SIZE + SECTION_SIZE - 1)
+		& SECTION_MASK;
+	apq8064_reserve_fixed_area(fixed_size);
+
+	fixed_low_start = APQ8064_FIXED_AREA_START;
+	fixed_middle_start = fixed_low_start + fixed_low_size;
+	fixed_high_start = fixed_middle_start + fixed_middle_size;
+
+	for (i = 0; i < apq8064_ion_pdata.nr; ++i) {
+		struct ion_platform_heap *heap = &(apq8064_ion_pdata.heaps[i]);
+
+		if (heap->extra_data) {
+			int fixed_position = NOT_FIXED;
+
+			switch (heap->type) {
+			case ION_HEAP_TYPE_CP:
+				fixed_position = ((struct ion_cp_heap_pdata *)
+					heap->extra_data)->fixed_position;
+				break;
+			case ION_HEAP_TYPE_CARVEOUT:
+				fixed_position = ((struct ion_co_heap_pdata *)
+					heap->extra_data)->fixed_position;
+				break;
+			default:
+				break;
+			}
+
+			switch (fixed_position) {
+			case FIXED_LOW:
+				heap->base = fixed_low_start;
+				break;
+			case FIXED_MIDDLE:
+				heap->base = fixed_middle_start;
+				break;
+			case FIXED_HIGH:
+				heap->base = fixed_high_start;
+				break;
+			default:
+				break;
+			}
+		}
+	}
 #endif
 }
 
@@ -406,6 +567,7 @@
 static struct reserve_info apq8064_reserve_info __initdata = {
 	.memtype_reserve_table = apq8064_reserve_table,
 	.calculate_reserve_sizes = apq8064_calculate_reserve_sizes,
+	.reserve_fixed_area = apq8064_reserve_fixed_area,
 	.paddr_to_memtype = apq8064_paddr_to_memtype,
 };
 
@@ -426,12 +588,14 @@
 
 	/* Check if 32 bit overflow occured */
 	if (high < mb->start)
-		high = ~0UL;
+		high = -PAGE_SIZE;
 
 	low &= ~(bank_size - 1);
 
 	if (high - low <= bank_size)
-		return;
+		goto no_dmm;
+
+#ifdef CONFIG_ENABLE_DMM
 	apq8064_reserve_info.low_unstable_address = mb->start -
 					MIN_MEMORY_BLOCK_SIZE + mb->size;
 	apq8064_reserve_info.max_unstable_size = MIN_MEMORY_BLOCK_SIZE;
@@ -441,6 +605,11 @@
 		apq8064_reserve_info.low_unstable_address,
 		apq8064_reserve_info.max_unstable_size,
 		apq8064_reserve_info.bank_size);
+	return;
+#endif
+no_dmm:
+	apq8064_reserve_info.low_unstable_address = high;
+	apq8064_reserve_info.max_unstable_size = 0;
 }
 
 static int apq8064_change_memory_power(u64 start, u64 size,
@@ -471,14 +640,29 @@
 {
 	apq8064_set_display_params(prim_panel_name, ext_panel_name);
 	msm_reserve();
+	if (apq8064_fmem_pdata.size) {
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+		if (reserve_info->fixed_area_size) {
+			apq8064_fmem_pdata.phys =
+				reserve_info->fixed_area_start + MSM_MM_FW_SIZE;
+			pr_info("mm fw at %lx (fixed) size %x\n",
+				reserve_info->fixed_area_start, MSM_MM_FW_SIZE);
+			pr_info("fmem start %lx (fixed) size %lx\n",
+				apq8064_fmem_pdata.phys,
+				apq8064_fmem_pdata.size);
+		}
+#endif
+	}
 }
 
 static void __init place_movable_zone(void)
 {
+#ifdef CONFIG_ENABLE_DMM
 	movable_reserved_start = apq8064_reserve_info.low_unstable_address;
 	movable_reserved_size = apq8064_reserve_info.max_unstable_size;
 	pr_info("movable zone start %lx size %lx\n",
 		movable_reserved_start, movable_reserved_size);
+#endif
 }
 
 static void __init apq8064_early_reserve(void)
@@ -1076,7 +1260,6 @@
 	0,
 };
 
-#ifndef CONFIG_MSM_VCAP
 #define MXT_TS_GPIO_IRQ			6
 #define MXT_TS_PWR_EN_GPIO		PM8921_GPIO_PM_TO_SYS(23)
 #define MXT_TS_RESET_GPIO		33
@@ -1128,7 +1311,6 @@
 		.irq = MSM_GPIO_TO_INT(MXT_TS_GPIO_IRQ),
 	},
 };
-#endif
 #define CYTTSP_TS_GPIO_IRQ		6
 #define CYTTSP_TS_GPIO_SLEEP		33
 
@@ -1490,6 +1672,11 @@
 			1132, 1132, 1199, 1132, 1199, 1132},
 };
 
+static struct platform_device msm_tsens_device = {
+	.name   = "tsens8960-tm",
+	.id = -1,
+};
+
 #define MSM_SHARED_RAM_PHYS 0x80000000
 static void __init apq8064_map_io(void)
 {
@@ -1866,13 +2053,14 @@
 	},
 };
 
-static struct platform_device *common_devices[] __initdata = {
-	&apq8064_device_dmov,
-#ifndef CONFIG_MSM_VCAP
+static struct platform_device *common_not_mpq_devices[] __initdata = {
 	&apq8064_device_qup_i2c_gsbi1,
 	&apq8064_device_qup_i2c_gsbi3,
 	&apq8064_device_qup_i2c_gsbi4,
-#endif
+};
+
+static struct platform_device *common_devices[] __initdata = {
+	&apq8064_device_dmov,
 	&apq8064_device_qup_spi_gsbi5,
 	&apq8064_device_ext_5v_vreg,
 	&apq8064_device_ext_mpp8_vreg,
@@ -1887,15 +2075,16 @@
 	&android_usb_device,
 	&msm_device_wcnss_wlan,
 	&msm_device_iris_fm,
+	&apq8064_fmem_device,
 #ifdef CONFIG_ANDROID_PMEM
 #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-	&android_pmem_device,
-	&android_pmem_adsp_device,
-	&android_pmem_audio_device,
+	&apq8064_android_pmem_device,
+	&apq8064_android_pmem_adsp_device,
+	&apq8064_android_pmem_audio_device,
 #endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
 #endif /*CONFIG_ANDROID_PMEM*/
 #ifdef CONFIG_ION_MSM
-	&ion_dev,
+	&apq8064_ion_dev,
 #endif
 	&msm8064_device_watchdog,
 	&msm8064_device_saw_regulator_core0,
@@ -1949,6 +2138,7 @@
 	&apq_cpudai_slimbus_1_rx,
 	&apq_cpudai_slimbus_1_tx,
 	&apq_cpudai_slimbus_2_tx,
+	&apq_cpudai_slimbus_3_rx,
 	&apq8064_rpm_device,
 	&apq8064_rpm_log_device,
 	&apq8064_rpm_stat_device,
@@ -1963,9 +2153,7 @@
 	&msm_8960_q6_lpass,
 	&msm_pil_vidc,
 	&msm_gss,
-#ifdef CONFIG_MSM_RTB
-	&msm_rtb_device,
-#endif
+	&apq8064_rtb_device,
 	&apq8064_cpu_idle_device,
 	&apq8064_msm_gov_device,
 	&apq8064_device_cache_erp,
@@ -1979,6 +2167,7 @@
 	&apq_cpudai_slim_4_tx,
 	&msm8960_gemini_device,
 	&apq8064_iommu_domain_device,
+	&msm_tsens_device,
 };
 
 static struct platform_device *sim_devices[] __initdata = {
@@ -2063,6 +2252,11 @@
 	},
 };
 
+static struct platform_device rc_input_loopback_pdev = {
+	.name	= "rc-user-input",
+	.id	= -1,
+};
+
 static struct platform_device *mpq_devices[] __initdata = {
 	&msm_device_sps_apq8064,
 	&mpq8064_device_qup_i2c_gsbi5,
@@ -2079,6 +2273,7 @@
 #ifdef CONFIG_MSM_VCAP
 	&msm8064_device_vcap,
 #endif
+	&rc_input_loopback_pdev,
 };
 
 static struct msm_spi_platform_data apq8064_qup_spi_gsbi5_pdata = {
@@ -2291,6 +2486,92 @@
 	},
 };
 
+static struct gpio_keys_button mpq_keys[] = {
+	{
+		.code           = KEY_VOLUMEDOWN,
+		.gpio           = GPIO_KEY_VOLUME_DOWN,
+		.desc           = "volume_down_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.wakeup		= 1,
+		.debounce_interval = 15,
+	},
+	{
+		.code           = KEY_VOLUMEUP,
+		.gpio           = GPIO_KEY_VOLUME_UP,
+		.desc           = "volume_up_key",
+		.active_low     = 1,
+		.type		= EV_KEY,
+		.wakeup		= 1,
+		.debounce_interval = 15,
+	},
+};
+
+static struct gpio_keys_platform_data mpq_keys_data = {
+	.buttons        = mpq_keys,
+	.nbuttons       = ARRAY_SIZE(mpq_keys),
+};
+
+static struct platform_device mpq_gpio_keys_pdev = {
+	.name           = "gpio-keys",
+	.id             = -1,
+	.dev            = {
+		.platform_data  = &mpq_keys_data,
+	},
+};
+
+#define MPQ_KP_ROW_BASE		SX150X_EXP2_GPIO_BASE
+#define MPQ_KP_COL_BASE		(SX150X_EXP2_GPIO_BASE + 4)
+
+static unsigned int mpq_row_gpios[] = {MPQ_KP_ROW_BASE, MPQ_KP_ROW_BASE + 1,
+				MPQ_KP_ROW_BASE + 2, MPQ_KP_ROW_BASE + 3};
+static unsigned int mpq_col_gpios[] = {MPQ_KP_COL_BASE, MPQ_KP_COL_BASE + 1,
+				MPQ_KP_COL_BASE + 2};
+
+static const unsigned int mpq_keymap[] = {
+	KEY(0, 0, KEY_UP),
+	KEY(0, 1, KEY_ENTER),
+	KEY(0, 2, KEY_3),
+
+	KEY(1, 0, KEY_DOWN),
+	KEY(1, 1, KEY_EXIT),
+	KEY(1, 2, KEY_4),
+
+	KEY(2, 0, KEY_LEFT),
+	KEY(2, 1, KEY_1),
+	KEY(2, 2, KEY_5),
+
+	KEY(3, 0, KEY_RIGHT),
+	KEY(3, 1, KEY_2),
+	KEY(3, 2, KEY_6),
+};
+
+static struct matrix_keymap_data mpq_keymap_data = {
+	.keymap_size	= ARRAY_SIZE(mpq_keymap),
+	.keymap		= mpq_keymap,
+};
+
+static struct matrix_keypad_platform_data mpq_keypad_data = {
+	.keymap_data		= &mpq_keymap_data,
+	.row_gpios		= mpq_row_gpios,
+	.col_gpios		= mpq_col_gpios,
+	.num_row_gpios		= ARRAY_SIZE(mpq_row_gpios),
+	.num_col_gpios		= ARRAY_SIZE(mpq_col_gpios),
+	.col_scan_delay_us	= 32000,
+	.debounce_ms		= 20,
+	.wakeup			= 1,
+	.active_low		= 1,
+	.no_autorepeat		= 1,
+};
+
+static struct platform_device mpq_keypad_device = {
+	.name           = "matrix-keypad",
+	.id             = -1,
+	.dev            = {
+		.platform_data  = &mpq_keypad_data,
+	},
+};
+
 /* Sensors DSPS platform data */
 #define DSPS_PIL_GENERIC_NAME		"dsps"
 static void __init apq8064_init_dsps(void)
@@ -2327,14 +2608,12 @@
 		smb349_charger_i2c_info,
 		ARRAY_SIZE(smb349_charger_i2c_info)
 	},
-#ifndef CONFIG_MSM_VCAP
 	{
 		I2C_SURF | I2C_LIQUID,
 		APQ_8064_GSBI3_QUP_I2C_BUS_ID,
 		mxt_device_info,
 		ARRAY_SIZE(mxt_device_info),
 	},
-#endif
 	{
 		I2C_FFA,
 		APQ_8064_GSBI3_QUP_I2C_BUS_ID,
@@ -2356,6 +2635,7 @@
 };
 
 #define SX150X_EXP1_INT_N	PM8921_MPP_IRQ(PM8921_IRQ_BASE, 9)
+#define SX150X_EXP2_INT_N	MSM_GPIO_TO_INT(81)
 
 struct sx150x_platform_data mpq8064_sx150x_pdata[] = {
 	[SX150X_EXP1] = {
@@ -2371,11 +2651,12 @@
 	[SX150X_EXP2] = {
 		.gpio_base	= SX150X_EXP2_GPIO_BASE,
 		.oscio_is_gpo	= false,
-		.io_pullup_ena	= 0x0,
-		.io_pulldn_ena	= 0x0,
+		.io_pullup_ena	= 0x0f,
+		.io_pulldn_ena	= 0x70,
 		.io_open_drain_ena = 0x0,
 		.io_polarity	= 0,
-		.irq_summary	= -1,
+		.irq_summary	= SX150X_EXP2_INT_N,
+		.irq_base	= SX150X_EXP2_IRQ_BASE,
 	},
 	[SX150X_EXP3] = {
 		.gpio_base	= SX150X_EXP3_GPIO_BASE,
@@ -2528,13 +2809,17 @@
 	if (machine_is_apq8064_liquid())
 		msm_otg_pdata.mhl_enable = true;
 
-	msm_otg_pdata.swfi_latency =
-		msm_rpmrs_levels[0].latency_us + 1;
+	android_usb_pdata.swfi_latency =
+		msm_rpmrs_levels[0].latency_us;
 
 	apq8064_device_otg.dev.platform_data = &msm_otg_pdata;
 	apq8064_ehci_host_init();
 	apq8064_init_buses();
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+	if (!(machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
+			machine_is_mpq8064_dtv()))
+		platform_add_devices(common_not_mpq_devices,
+			ARRAY_SIZE(common_not_mpq_devices));
 	enable_ddr3_regulator();
 	if (machine_is_apq8064_mtp()) {
 		apq8064_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
@@ -2599,7 +2884,7 @@
 	}
 	apq8064_init_fb();
 	apq8064_init_gpu();
-	platform_add_devices(apq8064_fs_devices, apq8064_num_fs_devices);
+	platform_add_devices(apq8064_footswitch, apq8064_num_footswitch);
 	apq8064_init_cam();
 
 	if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
@@ -2609,6 +2894,11 @@
 		platform_device_register(&mtp_kp_pdev);
 
 	change_memory_power = &apq8064_change_memory_power;
+
+	if (machine_is_mpq8064_cdp()) {
+		platform_device_register(&mpq_gpio_keys_pdev);
+		platform_device_register(&mpq_keypad_device);
+	}
 }
 
 MACHINE_START(APQ8064_SIM, "QCT APQ8064 SIMULATOR")
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 3729385..67e0e6f 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -19,6 +19,7 @@
 #include <mach/msm_memtypes.h>
 #include <mach/irqs.h>
 #include <mach/rpm-regulator.h>
+#include <mach/msm_rtb.h>
 
 /* Macros assume PMIC GPIOs and MPPs start at 1 */
 #define PM8921_GPIO_BASE		NR_GPIO_IRQS
@@ -141,4 +142,5 @@
 	SX150X_EXP4,
 };
 
+extern struct msm_rtb_platform_data apq8064_rtb_pdata;
 #endif
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index e7992f9..cc5b13c 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -545,13 +545,21 @@
 };
 
 static struct msm_camera_sensor_platform_info sensor_board_info_s5k3l1yx = {
-	.mount_angle  = 0,
+	.mount_angle  = 90,
 	.cam_vreg = msm_8930_s5k3l1yx_vreg,
 	.num_vreg = ARRAY_SIZE(msm_8930_s5k3l1yx_vreg),
 	.gpio_conf = &msm_8930_back_cam_gpio_conf,
 	.csi_lane_params = &s5k3l1yx_csi_lane_params,
 };
 
+static struct msm_actuator_info msm_act_main_cam_2_info = {
+	.board_info     = &msm_act_main_cam_i2c_info,
+	.cam_name   = MSM_ACTUATOR_MAIN_CAM_2,
+	.bus_id         = MSM_8930_GSBI4_QUP_I2C_BUS_ID,
+	.vcm_pwd        = 0,
+	.vcm_enable     = 0,
+};
+
 static struct msm_camera_sensor_info msm_camera_sensor_s5k3l1yx_data = {
 	.sensor_name          = "s5k3l1yx",
 	.pdata                = &msm_camera_csi_device_data[0],
@@ -560,6 +568,7 @@
 	.csi_if               = 1,
 	.camera_type          = BACK_CAMERA_2D,
 	.sensor_type          = BAYER_SENSOR,
+	.actuator_info    = &msm_act_main_cam_2_info,
 };
 
 static struct platform_device msm_camera_server = {
@@ -572,6 +581,12 @@
 	msm_gpiomux_install(msm8930_cam_common_configs,
 			ARRAY_SIZE(msm8930_cam_common_configs));
 
+	if (machine_is_msm8930_cdp()) {
+		struct msm_camera_sensor_info *s_info;
+		s_info = &msm_camera_sensor_s5k3l1yx_data;
+		s_info->sensor_platform_info->mount_angle = 0;
+	}
+
 	platform_device_register(&msm_camera_server);
 	platform_device_register(&msm8960_device_csiphy0);
 	platform_device_register(&msm8960_device_csiphy1);
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index 42b20b2..6230b65 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -30,29 +30,13 @@
 
 #ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
 #define MSM_FB_PRIM_BUF_SIZE \
-		(roundup((1376 * 768 * 4), 4096) * 3) /* 4 bpp x 3 pages */
+		(roundup((1920 * 1088 * 4), 4096) * 3) /* 4 bpp x 3 pages */
 #else
 #define MSM_FB_PRIM_BUF_SIZE \
-		(roundup((1376 * 768 * 4), 4096) * 2) /* 4 bpp x 2 pages */
+		(roundup((1920 * 1088 * 4), 4096) * 2) /* 4 bpp x 2 pages */
 #endif
-
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
-#define MSM_FB_EXT_BUF_SIZE \
-		(roundup((1920 * 1088 * 2), 4096) * 1) /* 2 bpp x 1 page */
-#elif defined(CONFIG_FB_MSM_TVOUT)
-#define MSM_FB_EXT_BUF_SIZE \
-		(roundup((720 * 576 * 2), 4096) * 2) /* 2 bpp x 2 pages */
-#else
-#define MSM_FB_EXT_BUF_SIZE	0
-#endif
-
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-/* 4 bpp x 2 page HDMI case */
-#define MSM_FB_SIZE roundup((1920 * 1088 * 4 * 2), 4096)
-#else
 /* Note: must be multiple of 4096 */
-#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE, 4096)
-#endif
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE, 4096)
 
 #ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
 #define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((1376 * 768 * 3 * 2), 4096)
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index 854f318..cd4aff8 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -88,6 +88,12 @@
 	},
 };
 
+static struct gpiomux_setting audio_mbhc = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
 #if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
 static struct gpiomux_setting gpio_eth_config = {
 	.pull = GPIOMUX_PULL_NONE,
@@ -374,6 +380,15 @@
 	},
 };
 
+static struct msm_gpiomux_config msm8960_audio_mbhc_configs[] __initdata = {
+	{
+		.gpio = 37,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &audio_mbhc,
+		},
+	},
+};
+
 static struct msm_gpiomux_config msm8960_audio_auxpcm_configs[] __initdata = {
 	{
 		.gpio = 63,
@@ -618,6 +633,9 @@
 	msm_gpiomux_install(msm8960_audio_codec_configs,
 			ARRAY_SIZE(msm8960_audio_codec_configs));
 
+	msm_gpiomux_install(msm8960_audio_mbhc_configs,
+			ARRAY_SIZE(msm8960_audio_mbhc_configs));
+
 	msm_gpiomux_install(msm8960_audio_auxpcm_configs,
 			ARRAY_SIZE(msm8960_audio_auxpcm_configs));
 
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
index 5ee480a..e23b76c 100644
--- a/arch/arm/mach-msm/board-8930-gpu.c
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -98,15 +98,15 @@
 	},
 };
 
-static const char *kgsl_3d0_iommu0_ctx_names[] = {
-	"gfx3d_user",
-	/* priv_ctx goes here */
+static const struct kgsl_iommu_ctx kgsl_3d0_iommu0_ctxs[] = {
+	{ "gfx3d_user", 0 },
+	{ "gfx3d_priv", 1 },
 };
 
 static struct kgsl_device_iommu_data kgsl_3d0_iommu_data[] = {
 	{
-		.iommu_ctx_names = kgsl_3d0_iommu0_ctx_names,
-		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu0_ctx_names),
+		.iommu_ctxs = kgsl_3d0_iommu0_ctxs,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu0_ctxs),
 		.physstart = 0x07C00000,
 		.physend = 0x07C00000 + SZ_1M - 1,
 	},
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 86c0438..cf7a829 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -329,6 +329,10 @@
 	.priority		= 0,
 };
 
+static struct pm8xxx_spk_platform_data pm8xxx_spk_pdata = {
+	.spk_add_enable		= false,
+};
+
 static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
 	.battery_type	= BATT_UNKNOWN,
 	.r_sense		= 10,
@@ -351,6 +355,7 @@
 	.adc_pdata		= &pm8xxx_adc_pdata,
 	.leds_pdata		= &pm8xxx_leds_pdata,
 	.ccadc_pdata		= &pm8xxx_ccadc_pdata,
+	.spk_pdata		= &pm8xxx_spk_pdata,
 };
 
 static struct msm_ssbi_platform_data msm8930_ssbi_pm8038_pdata __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index ecebfa9..9171749 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -284,6 +284,10 @@
 #endif
 #ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
 	/* SDC3: External card slot */
+	if (!machine_is_msm8930_cdp()) {
+		msm8960_sdc3_data.wpswitch_gpio = 0;
+		msm8960_sdc3_data.wpswitch_polarity = 0;
+	}
 	msm_add_sdcc(3, &msm8960_sdc3_data);
 #endif
 }
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 24e6a79..28499dd 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -41,6 +41,7 @@
 #include <linux/i2c/isa1200.h>
 #include <linux/gpio_keys.h>
 #include <linux/memory.h>
+#include <linux/memblock.h>
 
 #include <linux/slimbus/slimbus.h>
 #include <linux/mfd/wcd9xxx/core.h>
@@ -76,6 +77,7 @@
 #include <mach/ion.h>
 #include <mach/mdm2.h>
 #include <mach/msm_rtb.h>
+#include <linux/fmem.h>
 
 #include "timer.h"
 #include "devices.h"
@@ -122,17 +124,33 @@
 #else
 #define MSM_PMEM_SIZE 0x2800000 /* 40 Mbytes */
 #endif
-
+#define MSM_LIQUID_PMEM_SIZE 0x4000000 /* 64 Mbytes */
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 #define MSM_PMEM_KERNEL_EBI1_SIZE  0x65000
+#ifdef CONFIG_MSM_IOMMU
+#define MSM_ION_MM_SIZE            0x3800000 /* Need to be multiple of 64K */
+#define MSM_ION_SF_SIZE            0x0
+#define MSM_ION_HEAP_NUM	7
+#else
 #define MSM_ION_SF_SIZE		MSM_PMEM_SIZE
-#define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
 #define MSM_ION_MM_SIZE		MSM_PMEM_ADSP_SIZE
+#define MSM_ION_HEAP_NUM	8
+#endif
+#define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
 #define MSM_ION_QSECOM_SIZE	0x300000 /* (3MB) */
 #define MSM_ION_MFC_SIZE	SZ_8K
 #define MSM_ION_AUDIO_SIZE	MSM_PMEM_AUDIO_SIZE
-#define MSM_ION_HEAP_NUM	8
+
+#define MSM_LIQUID_ION_MM_SIZE (MSM_ION_MM_SIZE + 0x600000)
+#define MSM_LIQUID_ION_SF_SIZE MSM_LIQUID_PMEM_SIZE
+#define MSM_HDMI_PRIM_ION_SF_SIZE MSM_HDMI_PRIM_PMEM_SIZE
+
+#define MSM8930_FIXED_AREA_START 0xa0000000
+#define MAX_FIXED_AREA_SIZE	0x10000000
+#define MSM_MM_FW_SIZE		0x200000
+#define MSM8930_FW_START	(MSM8930_FIXED_AREA_START - MSM_MM_FW_SIZE)
+
 #else
 #define MSM_PMEM_KERNEL_EBI1_SIZE  0x110C000
 #define MSM_ION_HEAP_NUM	1
@@ -185,7 +203,7 @@
 	.memory_type = MEMTYPE_EBI1,
 };
 
-static struct platform_device android_pmem_device = {
+static struct platform_device msm8930_android_pmem_device = {
 	.name = "android_pmem",
 	.id = 0,
 	.dev = {.platform_data = &android_pmem_pdata},
@@ -197,7 +215,7 @@
 	.cached = 0,
 	.memory_type = MEMTYPE_EBI1,
 };
-static struct platform_device android_pmem_adsp_device = {
+static struct platform_device msm8930_android_pmem_adsp_device = {
 	.name = "android_pmem",
 	.id = 2,
 	.dev = { .platform_data = &android_pmem_adsp_pdata },
@@ -210,7 +228,7 @@
 	.memory_type = MEMTYPE_EBI1,
 };
 
-static struct platform_device android_pmem_audio_device = {
+static struct platform_device msm8930_android_pmem_audio_device = {
 	.name = "android_pmem",
 	.id = 4,
 	.dev = { .platform_data = &android_pmem_audio_pdata },
@@ -218,6 +236,9 @@
 #endif /* CONFIG_MSM_MULTIMEDIA_USE_ION */
 #endif /* CONFIG_ANDROID_PMEM */
 
+struct fmem_platform_data msm8930_fmem_pdata = {
+};
+
 #define DSP_RAM_BASE_8960 0x8da00000
 #define DSP_RAM_SIZE_8960 0x1800000
 static int dspcrashd_pdata_8960 = 0xDEADDEAD;
@@ -249,35 +270,11 @@
 	},
 };
 
-#if defined(CONFIG_MSM_RTB)
-static struct msm_rtb_platform_data msm_rtb_pdata = {
-	.size = SZ_1M,
-};
-
-static int __init msm_rtb_set_buffer_size(char *p)
-{
-	int s;
-
-	s = memparse(p, NULL);
-	msm_rtb_pdata.size = ALIGN(s, SZ_4K);
-	return 0;
-}
-early_param("msm_rtb_size", msm_rtb_set_buffer_size);
-
-
-static struct platform_device msm_rtb_device = {
-	.name           = "msm_rtb",
-	.id             = -1,
-	.dev            = {
-		.platform_data = &msm_rtb_pdata,
-	},
-};
-#endif
 
 static void __init reserve_rtb_memory(void)
 {
 #if defined(CONFIG_MSM_RTB)
-	msm8930_reserve_table[MEMTYPE_EBI1].size += msm_rtb_pdata.size;
+	msm8930_reserve_table[MEMTYPE_EBI1].size += msm8930_rtb_pdata.size;
 #endif
 }
 
@@ -318,24 +315,36 @@
 	return MEMTYPE_EBI1;
 }
 
+#define FMEM_ENABLED 1
 #ifdef CONFIG_ION_MSM
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-static struct ion_cp_heap_pdata cp_mm_ion_pdata = {
+static struct ion_cp_heap_pdata cp_mm_msm8930_ion_pdata = {
 	.permission_type = IPT_TYPE_MM_CARVEOUT,
 	.align = PAGE_SIZE,
+	.reusable = FMEM_ENABLED,
+	.mem_is_fmem = FMEM_ENABLED,
+	.fixed_position = FIXED_MIDDLE,
 };
 
-static struct ion_cp_heap_pdata cp_mfc_ion_pdata = {
+static struct ion_cp_heap_pdata cp_mfc_msm8930_ion_pdata = {
 	.permission_type = IPT_TYPE_MFC_SHAREDMEM,
 	.align = PAGE_SIZE,
+	.reusable = 0,
+	.mem_is_fmem = FMEM_ENABLED,
+	.fixed_position = FIXED_HIGH,
 };
-static struct ion_co_heap_pdata co_ion_pdata = {
+
+static struct ion_co_heap_pdata co_msm8930_ion_pdata = {
 	.adjacent_mem_id = INVALID_HEAP_ID,
 	.align = PAGE_SIZE,
+	.mem_is_fmem = 0,
 };
-static struct ion_co_heap_pdata fw_co_ion_pdata = {
+
+static struct ion_co_heap_pdata fw_co_msm8930_ion_pdata = {
 	.adjacent_mem_id = ION_CP_MM_HEAP_ID,
 	.align = SZ_128K,
+	.mem_is_fmem = FMEM_ENABLED,
+	.fixed_position = FIXED_LOW,
 };
 #endif
 
@@ -350,7 +359,7 @@
  * to each other.
  * Don't swap the order unless you know what you are doing!
  */
-static struct ion_platform_data ion_pdata = {
+static struct ion_platform_data msm8930_ion_pdata = {
 	.nr = MSM_ION_HEAP_NUM,
 	.heaps = {
 		{
@@ -365,7 +374,7 @@
 			.name	= ION_MM_HEAP_NAME,
 			.size	= MSM_ION_MM_SIZE,
 			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &cp_mm_ion_pdata,
+			.extra_data = (void *) &cp_mm_msm8930_ion_pdata,
 		},
 		{
 			.id	= ION_MM_FIRMWARE_HEAP_ID,
@@ -373,7 +382,7 @@
 			.name	= ION_MM_FIRMWARE_HEAP_NAME,
 			.size	= MSM_ION_MM_FW_SIZE,
 			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &fw_co_ion_pdata,
+			.extra_data = (void *) &fw_co_msm8930_ion_pdata,
 		},
 		{
 			.id	= ION_CP_MFC_HEAP_ID,
@@ -381,16 +390,18 @@
 			.name	= ION_MFC_HEAP_NAME,
 			.size	= MSM_ION_MFC_SIZE,
 			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &cp_mfc_ion_pdata,
+			.extra_data = (void *) &cp_mfc_msm8930_ion_pdata,
 		},
+#ifndef CONFIG_MSM_IOMMU
 		{
 			.id	= ION_SF_HEAP_ID,
 			.type	= ION_HEAP_TYPE_CARVEOUT,
 			.name	= ION_SF_HEAP_NAME,
 			.size	= MSM_ION_SF_SIZE,
 			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &co_ion_pdata,
+			.extra_data = (void *) &co_msm8930_ion_pdata,
 		},
+#endif
 		{
 			.id	= ION_IOMMU_HEAP_ID,
 			.type	= ION_HEAP_TYPE_IOMMU,
@@ -402,7 +413,7 @@
 			.name	= ION_QSECOM_HEAP_NAME,
 			.size	= MSM_ION_QSECOM_SIZE,
 			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &co_ion_pdata,
+			.extra_data = (void *) &co_msm8930_ion_pdata,
 		},
 		{
 			.id	= ION_AUDIO_HEAP_ID,
@@ -410,28 +421,193 @@
 			.name	= ION_AUDIO_HEAP_NAME,
 			.size	= MSM_ION_AUDIO_SIZE,
 			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &co_ion_pdata,
+			.extra_data = (void *) &co_msm8930_ion_pdata,
 		},
 #endif
 	}
 };
 
-static struct platform_device ion_dev = {
+static struct platform_device msm8930_ion_dev = {
 	.name = "ion-msm",
 	.id = 1,
-	.dev = { .platform_data = &ion_pdata },
+	.dev = { .platform_data = &msm8930_ion_pdata },
 };
 #endif
 
+struct platform_device msm8930_fmem_device = {
+	.name = "fmem",
+	.id = 1,
+	.dev = { .platform_data = &msm8930_fmem_pdata },
+};
+
+static void __init reserve_mem_for_ion(enum ion_memory_types mem_type,
+				      unsigned long size)
+{
+	msm8930_reserve_table[mem_type].size += size;
+}
+
+static void __init msm8930_reserve_fixed_area(unsigned long fixed_area_size)
+{
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+	int ret;
+
+	if (fixed_area_size > MAX_FIXED_AREA_SIZE)
+		panic("fixed area size is larger than %dM\n",
+			MAX_FIXED_AREA_SIZE >> 20);
+
+	reserve_info->fixed_area_size = fixed_area_size;
+	reserve_info->fixed_area_start = MSM8930_FW_START;
+
+	ret = memblock_remove(reserve_info->fixed_area_start,
+		reserve_info->fixed_area_size);
+	BUG_ON(ret);
+#endif
+}
+
+/**
+ * Reserve memory for ION and calculate amount of reusable memory for fmem.
+ * We only reserve memory for heaps that are not reusable. However, we only
+ * support one reusable heap at the moment so we ignore the reusable flag for
+ * other than the first heap with reusable flag set. Also handle special case
+ * for video heaps (MM,FW, and MFC). Video requires heaps MM and MFC to be
+ * at a higher address than FW in addition to not more than 256MB away from the
+ * base address of the firmware. This means that if MM is reusable the other
+ * two heaps must be allocated in the same region as FW. This is handled by the
+ * mem_is_fmem flag in the platform data. In addition the MM heap must be
+ * adjacent to the FW heap for content protection purposes.
+ */
 static void __init reserve_ion_memory(void)
 {
 #if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
-	msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_SF_SIZE;
-	msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MM_SIZE;
-	msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MM_FW_SIZE;
-	msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MFC_SIZE;
-	msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_QSECOM_SIZE;
-	msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
+	unsigned int i;
+	unsigned int reusable_count = 0;
+	unsigned int fixed_size = 0;
+	unsigned int fixed_low_size, fixed_middle_size, fixed_high_size;
+	unsigned long fixed_low_start, fixed_middle_start, fixed_high_start;
+
+	msm8930_fmem_pdata.size = 0;
+	msm8930_fmem_pdata.reserved_size_low = 0;
+	msm8930_fmem_pdata.reserved_size_high = 0;
+	fixed_low_size = 0;
+	fixed_middle_size = 0;
+	fixed_high_size = 0;
+
+	/* We only support 1 reusable heap. Check if more than one heap
+	 * is specified as reusable and set as non-reusable if found.
+	 */
+	for (i = 0; i < msm8930_ion_pdata.nr; ++i) {
+		const struct ion_platform_heap *heap =
+						&(msm8930_ion_pdata.heaps[i]);
+
+		if (heap->type == ION_HEAP_TYPE_CP && heap->extra_data) {
+			struct ion_cp_heap_pdata *data = heap->extra_data;
+
+			reusable_count += (data->reusable) ? 1 : 0;
+
+			if (data->reusable && reusable_count > 1) {
+				pr_err("%s: Too many heaps specified as "
+					"reusable. Heap %s was not configured "
+					"as reusable.\n", __func__, heap->name);
+				data->reusable = 0;
+			}
+		}
+	}
+
+	for (i = 0; i < msm8930_ion_pdata.nr; ++i) {
+		const struct ion_platform_heap *heap =
+						&(msm8930_ion_pdata.heaps[i]);
+
+		if (heap->extra_data) {
+			int fixed_position = NOT_FIXED;
+			int mem_is_fmem = 0;
+
+			switch (heap->type) {
+			case ION_HEAP_TYPE_CP:
+				mem_is_fmem = ((struct ion_cp_heap_pdata *)
+					heap->extra_data)->mem_is_fmem;
+				fixed_position = ((struct ion_cp_heap_pdata *)
+					heap->extra_data)->fixed_position;
+				break;
+			case ION_HEAP_TYPE_CARVEOUT:
+				mem_is_fmem = ((struct ion_co_heap_pdata *)
+					heap->extra_data)->mem_is_fmem;
+				fixed_position = ((struct ion_co_heap_pdata *)
+					heap->extra_data)->fixed_position;
+				break;
+			default:
+				break;
+			}
+
+			if (fixed_position != NOT_FIXED)
+				fixed_size += heap->size;
+			else
+				reserve_mem_for_ion(MEMTYPE_EBI1, heap->size);
+
+			if (fixed_position == FIXED_LOW)
+				fixed_low_size += heap->size;
+			else if (fixed_position == FIXED_MIDDLE)
+				fixed_middle_size += heap->size;
+			else if (fixed_position == FIXED_HIGH)
+				fixed_high_size += heap->size;
+
+			if (mem_is_fmem)
+				msm8930_fmem_pdata.size += heap->size;
+		}
+	}
+
+	if (!fixed_size)
+		return;
+
+	if (msm8930_fmem_pdata.size) {
+		msm8930_fmem_pdata.reserved_size_low = fixed_low_size;
+		msm8930_fmem_pdata.reserved_size_high = fixed_high_size;
+	}
+
+	/* Since the fixed area may be carved out of lowmem,
+	 * make sure the length is a multiple of 1M.
+	 */
+	fixed_size = (fixed_size + MSM_MM_FW_SIZE + SECTION_SIZE - 1)
+		& SECTION_MASK;
+	msm8930_reserve_fixed_area(fixed_size);
+
+	fixed_low_start = MSM8930_FIXED_AREA_START;
+	fixed_middle_start = fixed_low_start + fixed_low_size;
+	fixed_high_start = fixed_middle_start + fixed_middle_size;
+
+	for (i = 0; i < msm8930_ion_pdata.nr; ++i) {
+		struct ion_platform_heap *heap = &(msm8930_ion_pdata.heaps[i]);
+
+		if (heap->extra_data) {
+			int fixed_position = NOT_FIXED;
+
+			switch (heap->type) {
+			case ION_HEAP_TYPE_CP:
+				fixed_position = ((struct ion_cp_heap_pdata *)
+					heap->extra_data)->fixed_position;
+				break;
+			case ION_HEAP_TYPE_CARVEOUT:
+				fixed_position = ((struct ion_co_heap_pdata *)
+					heap->extra_data)->fixed_position;
+				break;
+			default:
+				break;
+			}
+
+			switch (fixed_position) {
+			case FIXED_LOW:
+				heap->base = fixed_low_start;
+				break;
+			case FIXED_MIDDLE:
+				heap->base = fixed_middle_start;
+				break;
+			case FIXED_HIGH:
+				heap->base = fixed_high_start;
+				break;
+			default:
+				break;
+			}
+		}
+	}
 #endif
 }
 
@@ -452,6 +628,7 @@
 static struct reserve_info msm8930_reserve_info __initdata = {
 	.memtype_reserve_table = msm8930_reserve_table,
 	.calculate_reserve_sizes = msm8930_calculate_reserve_sizes,
+	.reserve_fixed_area = msm8930_reserve_fixed_area,
 	.paddr_to_memtype = msm8930_paddr_to_memtype,
 };
 
@@ -472,12 +649,15 @@
 
 	/* Check if 32 bit overflow occured */
 	if (high < mb->start)
-		high = ~0UL;
+		high -= PAGE_SIZE;
+
+	if (high < MAX_FIXED_AREA_SIZE + MSM8930_FIXED_AREA_START)
+		panic("fixed area extends beyond end of memory\n");
 
 	low &= ~(bank_size - 1);
 
 	if (high - low <= bank_size)
-		return;
+		goto no_dmm;
 
 	msm8930_reserve_info.bank_size = bank_size;
 #ifdef CONFIG_ENABLE_DMM
@@ -488,10 +668,11 @@
 		msm8930_reserve_info.low_unstable_address,
 		msm8930_reserve_info.max_unstable_size,
 		msm8930_reserve_info.bank_size);
-#else
-	msm8930_reserve_info.low_unstable_address = 0;
-	msm8930_reserve_info.max_unstable_size = 0;
+	return;
 #endif
+no_dmm:
+	msm8930_reserve_info.low_unstable_address = high;
+	msm8930_reserve_info.max_unstable_size = 0;
 }
 
 static void __init place_movable_zone(void)
@@ -514,6 +695,18 @@
 static void __init msm8930_reserve(void)
 {
 	msm_reserve();
+	if (msm8930_fmem_pdata.size) {
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+		if (reserve_info->fixed_area_size) {
+			msm8930_fmem_pdata.phys =
+				reserve_info->fixed_area_start + MSM_MM_FW_SIZE;
+		pr_info("mm fw at %lx (fixed) size %x\n",
+			reserve_info->fixed_area_start, MSM_MM_FW_SIZE);
+		pr_info("fmem start %lx (fixed) size %lx\n",
+			msm8930_fmem_pdata.phys, msm8930_fmem_pdata.size);
+		}
+#endif
+	}
 }
 
 static int msm8930_change_memory_power(u64 start, u64 size,
@@ -1286,30 +1479,35 @@
 	},
 };
 
-#/* TODO: Remove this once PM8038 physically becomes
- * available.
- */
 #define ISA1200_HAP_EN_GPIO	77
 #define ISA1200_HAP_LEN_GPIO	78
 #define ISA1200_HAP_CLK		PM8038_GPIO_PM_TO_SYS(7)
 
 static int isa1200_power(int on)
 {
+	int rc = 0;
+
 	gpio_set_value_cansleep(ISA1200_HAP_CLK, !!on);
 
-	return 0;
+	if (on)
+		rc = pm8xxx_aux_clk_control(CLK_MP3_1, XO_DIV_1, true);
+	else
+		rc = pm8xxx_aux_clk_control(CLK_MP3_1, XO_DIV_NONE, true);
+
+	if (rc) {
+		pr_err("%s: unable to write aux clock register(%d)\n",
+			__func__, rc);
+	}
+
+	return rc;
 }
 
 static int isa1200_dev_setup(bool enable)
 {
 	int rc = 0;
 
-	rc = pm8xxx_aux_clk_control(CLK_MP3_1, XO_DIV_1, enable);
-	if (rc) {
-		pr_err("%s: unable to write aux clock register(%d)\n",
-			__func__, rc);
-		return rc;
-	}
+	if (!enable)
+		goto fail_gpio_dir;
 
 	rc = gpio_request(ISA1200_HAP_CLK, "haptics_clk");
 	if (rc) {
@@ -1633,9 +1831,14 @@
 static struct tsens_platform_data msm_tsens_pdata  = {
 	.tsens_factor		= 1000,
 	.hw_type		= APQ_8064,
-	.tsens_num_sensor	= 11,
-	.slope = {1176, 1176, 1154, 1176, 1111,
-			1132, 1132, 1199, 1132, 1199, 1132},
+	.tsens_num_sensor	= 10,
+	.slope = {1132, 1135, 1137, 1135, 1157,
+			1142, 1124, 1153, 1175, 1166},
+};
+
+static struct platform_device msm_tsens_device = {
+	.name   = "tsens8960-tm",
+	.id = -1,
 };
 
 #ifdef CONFIG_MSM_FAKE_BATTERY
@@ -1749,11 +1952,12 @@
 #endif
 #ifdef CONFIG_ANDROID_PMEM
 #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-	&android_pmem_device,
-	&android_pmem_adsp_device,
-	&android_pmem_audio_device,
+	&msm8930_android_pmem_device,
+	&msm8930_android_pmem_adsp_device,
+	&msm8930_android_pmem_audio_device,
 #endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
 #endif /*CONFIG_ANDROID_PMEM*/
+	&msm8930_fmem_device,
 	&msm_device_bam_dmux,
 	&msm_fm_platform_init,
 
@@ -1764,7 +1968,7 @@
 	&msm8930_rpm_log_device,
 	&msm8930_rpm_stat_device,
 #ifdef CONFIG_ION_MSM
-	&ion_dev,
+	&msm8930_ion_dev,
 #endif
 	&msm_device_tz_log,
 
@@ -1780,9 +1984,7 @@
 #ifdef MSM8930_PHASE_2
 	&gpio_keys_8930,
 #endif
-#ifdef CONFIG_MSM_RTB
-	&msm_rtb_device,
-#endif
+	&msm8930_rtb_device,
 	&msm8930_cpu_idle_device,
 	&msm8930_msm_gov_device,
 	&msm_bus_8930_apps_fabric,
@@ -1792,6 +1994,7 @@
 	&msm_bus_8930_cpss_fpb,
 	&msm8960_device_cache_erp,
 	&msm8930_iommu_domain_device,
+	&msm_tsens_device,
 };
 
 static struct platform_device *cdp_devices[] __initdata = {
@@ -2083,8 +2286,7 @@
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
 	msm_spm_l2_init(msm_spm_l2_data);
 	msm8930_init_buses();
-	platform_add_devices(msm_footswitch_devices,
-		msm_num_footswitch_devices);
+	platform_add_devices(msm8930_footswitch, msm8930_num_footswitch);
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
 	msm8930_add_vidc_device();
 	/*
diff --git a/arch/arm/mach-msm/board-8930.h b/arch/arm/mach-msm/board-8930.h
index a8fad72..2bbbf80 100644
--- a/arch/arm/mach-msm/board-8930.h
+++ b/arch/arm/mach-msm/board-8930.h
@@ -22,6 +22,7 @@
 #include <mach/irqs.h>
 #include <mach/rpm-regulator.h>
 #include <mach/msm_memtypes.h>
+#include <mach/msm_rtb.h>
 
 /*
  * TODO: When physical 8930/PM8038 hardware becomes
@@ -137,3 +138,5 @@
 #define MSM_8930_GSBI4_QUP_I2C_BUS_ID 4
 #define MSM_8930_GSBI9_QUP_I2C_BUS_ID 0
 #define MSM_8930_GSBI10_QUP_I2C_BUS_ID 10
+
+extern struct msm_rtb_platform_data msm8930_rtb_pdata;
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 83e3c8d..371bb53 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -524,6 +524,15 @@
 	.csi_lane_params = &imx074_csi_lane_params,
 };
 
+static struct i2c_board_info imx074_eeprom_i2c_info = {
+	I2C_BOARD_INFO("imx074_eeprom", 0x34 << 1),
+};
+
+static struct msm_eeprom_info imx074_eeprom_info = {
+	.board_info     = &imx074_eeprom_i2c_info,
+	.bus_id         = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+};
+
 static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
 	.sensor_name	= "imx074",
 	.pdata	= &msm_camera_csi_device_data[0],
@@ -534,6 +543,7 @@
 	.camera_type = BACK_CAMERA_2D,
 	.sensor_type = BAYER_SENSOR,
 	.actuator_info = &msm_act_main_cam_0_info,
+	.eeprom_info = &imx074_eeprom_info,
 };
 
 static struct camera_vreg_t msm_8960_mt9m114_vreg[] = {
@@ -621,6 +631,14 @@
 	.csi_lane_params = &s5k3l1yx_csi_lane_params,
 };
 
+static struct msm_actuator_info msm_act_main_cam_2_info = {
+	.board_info     = &msm_act_main_cam_i2c_info,
+	.cam_name   = MSM_ACTUATOR_MAIN_CAM_2,
+	.bus_id         = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+	.vcm_pwd        = 0,
+	.vcm_enable     = 0,
+};
+
 static struct msm_camera_sensor_info msm_camera_sensor_s5k3l1yx_data = {
 	.sensor_name          = "s5k3l1yx",
 	.pdata                = &msm_camera_csi_device_data[0],
@@ -629,6 +647,7 @@
 	.csi_if               = 1,
 	.camera_type          = BACK_CAMERA_2D,
 	.sensor_type          = BAYER_SENSOR,
+	.actuator_info    = &msm_act_main_cam_2_info,
 };
 
 static struct msm_camera_csi_lane_params imx091_csi_lane_params = {
@@ -658,6 +677,15 @@
 	.csi_lane_params = &imx091_csi_lane_params,
 };
 
+static struct i2c_board_info imx091_eeprom_i2c_info = {
+	I2C_BOARD_INFO("imx091_eeprom", 0x21),
+};
+
+static struct msm_eeprom_info imx091_eeprom_info = {
+	.board_info     = &imx091_eeprom_i2c_info,
+	.bus_id         = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+};
+
 static struct msm_camera_sensor_info msm_camera_sensor_imx091_data = {
 	.sensor_name	= "imx091",
 	.pdata	= &msm_camera_csi_device_data[0],
@@ -667,6 +695,7 @@
 	.camera_type = BACK_CAMERA_2D,
 	.sensor_type = BAYER_SENSOR,
 	.actuator_info = &msm_act_main_cam_1_info,
+	.eeprom_info = &imx091_eeprom_info,
 };
 
 static struct pm8xxx_mpp_config_data privacy_light_on_config = {
@@ -727,6 +756,11 @@
 			msm_camera_8960_ext_power_ctrl;
 	}
 
+	if (machine_is_msm8960_fluid()) {
+		msm_camera_sensor_imx091_data.sensor_platform_info->
+			mount_angle = 270;
+	}
+
 	platform_device_register(&msm_camera_server);
 	platform_device_register(&msm8960_device_csiphy0);
 	platform_device_register(&msm8960_device_csiphy1);
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index 8c41e8c..b4db968 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -38,20 +38,8 @@
 			/* 4 bpp x 2 pages */
 #endif
 
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
-#define MSM_FB_EXT_BUF_SIZE \
-		(roundup((roundup(1920, 32) * roundup(1080, 32) * 2), 4096) * 1)
-			/* 2 bpp x 1 page */
-#elif defined(CONFIG_FB_MSM_TVOUT)
-#define MSM_FB_EXT_BUF_SIZE \
-		(roundup((roundup(720, 32) * roundup(576, 32) * 2), 4096) * 2)
-			/* 2 bpp x 2 pages */
-#else
-#define MSM_FB_EXT_BUF_SIZE	0
-#endif
-
 /* Note: must be multiple of 4096 */
-#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE, 4096)
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE, 4096)
 
 #ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
 #define MSM_FB_OVERLAY0_WRITEBACK_SIZE \
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
index 8b5c693..978eb09 100644
--- a/arch/arm/mach-msm/board-8960-gpiomux.c
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -597,6 +597,84 @@
 };
 #endif
 
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+static struct gpiomux_setting sdcc4_clk_actv_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sdcc4_cmd_data_0_3_actv_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdcc4_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting sdcc4_data_1_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config msm8960_sdcc4_configs[] __initdata = {
+	{
+		/* SDC4_DATA_3 */
+		.gpio      = 83,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc4_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc4_suspend_cfg,
+		},
+	},
+	{
+		/* SDC4_DATA_2 */
+		.gpio      = 84,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc4_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc4_suspend_cfg,
+		},
+	},
+	{
+		/* SDC4_DATA_1 */
+		.gpio      = 85,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc4_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc4_data_1_suspend_cfg,
+		},
+	},
+	{
+		/* SDC4_DATA_0 */
+		.gpio      = 86,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc4_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc4_suspend_cfg,
+		},
+	},
+	{
+		/* SDC4_CMD */
+		.gpio      = 87,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc4_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc4_suspend_cfg,
+		},
+	},
+	{
+		/* SDC4_CLK */
+		.gpio      = 88,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc4_clk_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc4_suspend_cfg,
+		},
+	},
+};
+#endif
+
+
 static struct msm_gpiomux_config hap_lvl_shft_config[] __initdata = {
 	{
 		.gpio = 47,
@@ -727,6 +805,83 @@
 };
 #endif
 
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static struct gpiomux_setting sdcc2_clk_actv_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sdcc2_cmd_data_0_3_actv_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdcc2_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting sdcc2_data_1_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config msm8960_sdcc2_configs[] __initdata = {
+	{
+		/* DATA_3 */
+		.gpio      = 92,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+	{
+		/* DATA_2 */
+		.gpio      = 91,
+		.settings = {
+		[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+		[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+	{
+		/* DATA_1 */
+		.gpio      = 90,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_data_1_suspend_cfg,
+		},
+	},
+	{
+		/* DATA_0 */
+		.gpio      = 89,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+	{
+		/* CMD */
+		.gpio      = 97,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+	{
+		/* CLK */
+		.gpio      = 98,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_clk_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+};
+#endif
+
 int __init msm8960_init_gpiomux(void)
 {
 	int rc = msm_gpiomux_init(NR_GPIO_IRQS);
@@ -758,6 +913,11 @@
 	msm_gpiomux_install(wcnss_5wire_interface,
 			ARRAY_SIZE(wcnss_5wire_interface));
 
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+	msm_gpiomux_install(msm8960_sdcc4_configs,
+		ARRAY_SIZE(msm8960_sdcc4_configs));
+#endif
+
 	if (machine_is_msm8960_mtp() || machine_is_msm8960_fluid() ||
 		machine_is_msm8960_liquid() || machine_is_msm8960_cdp())
 		msm_gpiomux_install(hap_lvl_shft_config,
@@ -798,5 +958,10 @@
 		msm_gpiomux_install(msm8960_fusion_gsbi_configs,
 			ARRAY_SIZE(msm8960_fusion_gsbi_configs));
 
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+	msm_gpiomux_install(msm8960_sdcc2_configs,
+		ARRAY_SIZE(msm8960_sdcc2_configs));
+#endif
+
 	return 0;
 }
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index c9a5f77..ea1ab58 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -471,7 +471,7 @@
 	{
 		.name		= "led:blue",
 		.flags		= PM8XXX_ID_LED_2,
-		.default_trigger	= "dc-online",
+		.default_trigger	= "notification",
 	},
 };
 
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index ed47ae2..3923ecf 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -163,6 +163,8 @@
 VREG_CONSUMERS(S4) = {
 	REGULATOR_SUPPLY("8921_s4",		NULL),
 	REGULATOR_SUPPLY("sdc_vccq",		"msm_sdcc.1"),
+	REGULATOR_SUPPLY("sdc_vdd",		"msm_sdcc.2"),
+	REGULATOR_SUPPLY("sdc_vddp",            "msm_sdcc.4"),
 	REGULATOR_SUPPLY("riva_vddpx",		"wcnss_wlan.0"),
 	REGULATOR_SUPPLY("hdmi_vcc",		"hdmi_msm.0"),
 	REGULATOR_SUPPLY("VDDIO_CDC",		"tabla-slim"),
@@ -193,7 +195,6 @@
 };
 VREG_CONSUMERS(LVS1) = {
 	REGULATOR_SUPPLY("8921_lvs1",		NULL),
-	REGULATOR_SUPPLY("sdc_vdd",		"msm_sdcc.4"),
 	REGULATOR_SUPPLY("iris_vddio",		"wcnss_wlan.0"),
 };
 VREG_CONSUMERS(LVS2) = {
diff --git a/arch/arm/mach-msm/board-8960-storage.c b/arch/arm/mach-msm/board-8960-storage.c
index f39a691..df1d846 100644
--- a/arch/arm/mach-msm/board-8960-storage.c
+++ b/arch/arm/mach-msm/board-8960-storage.c
@@ -46,6 +46,16 @@
 		.lpm_uA = 9000,
 		.hpm_uA = 200000, /* 200mA */
 	},
+	/* SDCC2 : SDIO slot connected */
+	[SDCC2] = {
+		.name = "sdc_vdd",
+		.high_vol_level = 1800000,
+		.low_vol_level = 1800000,
+		.always_on = 1,
+		.lpm_sup = 1,
+		.lpm_uA = 9000,
+		.hpm_uA = 200000, /* 200mA */
+	},
 	/* SDCC3 : External card slot connected */
 	[SDCC3] = {
 		.name = "sdc_vdd",
@@ -84,7 +94,17 @@
 		 * during sleep.
 		 */
 		.lpm_uA = 2000,
-	}
+	},
+	/* SDCC4 : SDIO slot connected */
+	[SDCC4] = {
+		.name = "sdc_vddp",
+		.high_vol_level = 1800000,
+		.low_vol_level = 1800000,
+		.always_on = 1,
+		.lpm_sup = 1,
+		.hpm_uA = 200000, /* 200mA */
+		.lpm_uA = 2000,
+	},
 };
 
 static struct msm_mmc_slot_reg_data mmc_slot_vreg_data[MAX_SDCC_CONTROLLER] = {
@@ -93,11 +113,19 @@
 		.vdd_data = &mmc_vdd_reg_data[SDCC1],
 		.vccq_data = &mmc_vccq_reg_data[SDCC1],
 	},
+	/* SDCC2 : SDIO card slot connected */
+	[SDCC2] = {
+		.vdd_data = &mmc_vdd_reg_data[SDCC2],
+	},
 	/* SDCC3 : External card slot connected */
 	[SDCC3] = {
 		.vdd_data = &mmc_vdd_reg_data[SDCC3],
 		.vddp_data = &mmc_vddp_reg_data[SDCC3],
-	}
+	},
+	/* SDCC4 : SDIO card slot connected */
+	[SDCC4] = {
+		.vddp_data = &mmc_vddp_reg_data[SDCC4],
+	},
 };
 
 /* SDC1 pad data */
@@ -186,6 +214,35 @@
 	},
 };
 
+struct msm_mmc_gpio sdc2_gpio[] = {
+	{92, "sdc2_dat_3"},
+	{91, "sdc2_dat_2"},
+	{90, "sdc2_dat_1"},
+	{89, "sdc2_dat_0"},
+	{97, "sdc2_cmd"},
+	{98, "sdc2_clk"}
+};
+
+struct msm_mmc_gpio sdc4_gpio[] = {
+	{83, "sdc4_dat_3"},
+	{84, "sdc4_dat_2"},
+	{85, "sdc4_dat_1"},
+	{86, "sdc4_dat_0"},
+	{87, "sdc4_cmd"},
+	{88, "sdc4_clk"}
+};
+
+struct msm_mmc_gpio_data mmc_gpio_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC2] = {
+		.gpio = sdc2_gpio,
+		.size = ARRAY_SIZE(sdc2_gpio),
+	},
+	[SDCC4] = {
+		.gpio = sdc4_gpio,
+		.size = ARRAY_SIZE(sdc4_gpio),
+	},
+};
+
 static struct msm_mmc_pad_data mmc_pad_data[MAX_SDCC_CONTROLLER] = {
 	[SDCC1] = {
 		.pull = &mmc_pad_pull_data[SDCC1],
@@ -201,9 +258,17 @@
 	[SDCC1] = {
 		.pad_data = &mmc_pad_data[SDCC1],
 	},
+	[SDCC2] = {
+		.is_gpio = 1,
+		.gpio_data = &mmc_gpio_data[SDCC2],
+	},
 	[SDCC3] = {
 		.pad_data = &mmc_pad_data[SDCC3],
 	},
+	[SDCC4] = {
+		.is_gpio = 1,
+		.gpio_data = &mmc_gpio_data[SDCC4],
+	},
 };
 
 #define MSM_MPM_PIN_SDC1_DAT1	17
@@ -237,6 +302,23 @@
 };
 #endif
 
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static unsigned int sdc2_sup_clk_rates[] = {
+	400000, 24000000, 48000000
+};
+
+static struct mmc_platform_data msm8960_sdc2_data = {
+	.ocr_mask       = MMC_VDD_165_195,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.sup_clk_table  = sdc2_sup_clk_rates,
+	.sup_clk_cnt    = ARRAY_SIZE(sdc2_sup_clk_rates),
+	.pclk_src_dfab  = 1,
+	.vreg_data      = &mmc_slot_vreg_data[SDCC2],
+	.pin_data       = &mmc_slot_pin_data[SDCC2],
+	.sdiowakeup_irq = MSM_GPIO_TO_INT(90),
+};
+#endif
+
 #ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
 static struct mmc_platform_data msm8960_sdc3_data = {
 	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
@@ -263,14 +345,39 @@
 };
 #endif
 
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+static unsigned int sdc4_sup_clk_rates[] = {
+	400000, 24000000, 48000000
+};
+
+static struct mmc_platform_data msm8960_sdc4_data = {
+	.ocr_mask       = MMC_VDD_165_195,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.sup_clk_table  = sdc4_sup_clk_rates,
+	.sup_clk_cnt    = ARRAY_SIZE(sdc4_sup_clk_rates),
+	.pclk_src_dfab  = 1,
+	.vreg_data      = &mmc_slot_vreg_data[SDCC4],
+	.pin_data       = &mmc_slot_pin_data[SDCC4],
+	.sdiowakeup_irq = MSM_GPIO_TO_INT(85),
+};
+#endif
+
 void __init msm8960_init_mmc(void)
 {
 #ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
 	/* SDC1 : eMMC card connected */
 	msm_add_sdcc(1, &msm8960_sdc1_data);
 #endif
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+	/* SDC2: SDIO slot for WLAN*/
+	msm_add_sdcc(2, &msm8960_sdc2_data);
+#endif
 #ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
 	/* SDC3: External card slot */
 	msm_add_sdcc(3, &msm8960_sdc3_data);
 #endif
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+	/* SDC4: SDIO slot for WLAN */
+	msm_add_sdcc(4, &msm8960_sdc4_data);
+#endif
 }
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 6328ab3..c103fa8 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -84,6 +84,7 @@
 #include <mach/msm_rtb.h>
 #include <mach/msm_cache_dump.h>
 #include <mach/scm.h>
+#include <mach/iommu_domains.h>
 
 #include <linux/fmem.h>
 
@@ -146,7 +147,7 @@
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 #define MSM_PMEM_KERNEL_EBI1_SIZE  0x65000
 #ifdef CONFIG_MSM_IOMMU
-#define MSM_ION_MM_SIZE            0x3800000
+#define MSM_ION_MM_SIZE            0x3800000 /* Need to be multiple of 64K */
 #define MSM_ION_SF_SIZE            0x0
 #define MSM_ION_QSECOM_SIZE        0x780000 /* (7.5MB) */
 #define MSM_ION_HEAP_NUM	7
@@ -224,7 +225,7 @@
 	.memory_type = MEMTYPE_EBI1,
 };
 
-static struct platform_device android_pmem_device = {
+static struct platform_device msm8960_android_pmem_device = {
 	.name = "android_pmem",
 	.id = 0,
 	.dev = {.platform_data = &android_pmem_pdata},
@@ -236,7 +237,7 @@
 	.cached = 0,
 	.memory_type = MEMTYPE_EBI1,
 };
-static struct platform_device android_pmem_adsp_device = {
+static struct platform_device msm8960_android_pmem_adsp_device = {
 	.name = "android_pmem",
 	.id = 2,
 	.dev = { .platform_data = &android_pmem_adsp_pdata },
@@ -249,7 +250,7 @@
 	.memory_type = MEMTYPE_EBI1,
 };
 
-static struct platform_device android_pmem_audio_device = {
+static struct platform_device msm8960_android_pmem_audio_device = {
 	.name = "android_pmem",
 	.id = 4,
 	.dev = { .platform_data = &android_pmem_audio_pdata },
@@ -257,7 +258,7 @@
 #endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
 #endif /*CONFIG_ANDROID_PMEM*/
 
-struct fmem_platform_data fmem_pdata = {
+struct fmem_platform_data msm8960_fmem_pdata = {
 };
 
 #define DSP_RAM_BASE_8960 0x8da00000
@@ -291,35 +292,10 @@
 	},
 };
 
-#if defined(CONFIG_MSM_RTB)
-static struct msm_rtb_platform_data msm_rtb_pdata = {
-	.size = SZ_1M,
-};
-
-static int __init msm_rtb_set_buffer_size(char *p)
-{
-	int s;
-
-	s = memparse(p, NULL);
-	msm_rtb_pdata.size = ALIGN(s, SZ_4K);
-	return 0;
-}
-early_param("msm_rtb_size", msm_rtb_set_buffer_size);
-
-
-static struct platform_device msm_rtb_device = {
-	.name           = "msm_rtb",
-	.id             = -1,
-	.dev            = {
-		.platform_data = &msm_rtb_pdata,
-	},
-};
-#endif
-
 static void __init reserve_rtb_memory(void)
 {
 #if defined(CONFIG_MSM_RTB)
-	msm8960_reserve_table[MEMTYPE_EBI1].size += msm_rtb_pdata.size;
+	msm8960_reserve_table[MEMTYPE_EBI1].size += msm8960_rtb_pdata.size;
 #endif
 }
 
@@ -372,15 +348,17 @@
 
 #ifdef CONFIG_ION_MSM
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-static struct ion_cp_heap_pdata cp_mm_ion_pdata = {
+static struct ion_cp_heap_pdata cp_mm_msm8960_ion_pdata = {
 	.permission_type = IPT_TYPE_MM_CARVEOUT,
-	.align = PAGE_SIZE,
+	.align = SZ_64K,
 	.reusable = FMEM_ENABLED,
 	.mem_is_fmem = FMEM_ENABLED,
 	.fixed_position = FIXED_MIDDLE,
+	.iommu_map_all = 1,
+	.iommu_2x_map_domain = VIDEO_DOMAIN,
 };
 
-static struct ion_cp_heap_pdata cp_mfc_ion_pdata = {
+static struct ion_cp_heap_pdata cp_mfc_msm8960_ion_pdata = {
 	.permission_type = IPT_TYPE_MFC_SHAREDMEM,
 	.align = PAGE_SIZE,
 	.reusable = 0,
@@ -388,13 +366,13 @@
 	.fixed_position = FIXED_HIGH,
 };
 
-static struct ion_co_heap_pdata co_ion_pdata = {
+static struct ion_co_heap_pdata co_msm8960_ion_pdata = {
 	.adjacent_mem_id = INVALID_HEAP_ID,
 	.align = PAGE_SIZE,
 	.mem_is_fmem = 0,
 };
 
-static struct ion_co_heap_pdata fw_co_ion_pdata = {
+static struct ion_co_heap_pdata fw_co_msm8960_ion_pdata = {
 	.adjacent_mem_id = ION_CP_MM_HEAP_ID,
 	.align = SZ_128K,
 	.mem_is_fmem = FMEM_ENABLED,
@@ -413,7 +391,7 @@
  * to each other.
  * Don't swap the order unless you know what you are doing!
  */
-static struct ion_platform_data ion_pdata = {
+static struct ion_platform_data msm8960_ion_pdata = {
 	.nr = MSM_ION_HEAP_NUM,
 	.heaps = {
 		{
@@ -428,7 +406,7 @@
 			.name	= ION_MM_HEAP_NAME,
 			.size	= MSM_ION_MM_SIZE,
 			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &cp_mm_ion_pdata,
+			.extra_data = (void *) &cp_mm_msm8960_ion_pdata,
 		},
 		{
 			.id	= ION_MM_FIRMWARE_HEAP_ID,
@@ -436,7 +414,7 @@
 			.name	= ION_MM_FIRMWARE_HEAP_NAME,
 			.size	= MSM_ION_MM_FW_SIZE,
 			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &fw_co_ion_pdata,
+			.extra_data = (void *) &fw_co_msm8960_ion_pdata,
 		},
 		{
 			.id	= ION_CP_MFC_HEAP_ID,
@@ -444,7 +422,7 @@
 			.name	= ION_MFC_HEAP_NAME,
 			.size	= MSM_ION_MFC_SIZE,
 			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &cp_mfc_ion_pdata,
+			.extra_data = (void *) &cp_mfc_msm8960_ion_pdata,
 		},
 #ifndef CONFIG_MSM_IOMMU
 		{
@@ -453,7 +431,7 @@
 			.name	= ION_SF_HEAP_NAME,
 			.size	= MSM_ION_SF_SIZE,
 			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &co_ion_pdata,
+			.extra_data = (void *) &co_msm8960_ion_pdata,
 		},
 #endif
 		{
@@ -467,7 +445,7 @@
 			.name	= ION_QSECOM_HEAP_NAME,
 			.size	= MSM_ION_QSECOM_SIZE,
 			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &co_ion_pdata,
+			.extra_data = (void *) &co_msm8960_ion_pdata,
 		},
 		{
 			.id	= ION_AUDIO_HEAP_ID,
@@ -475,23 +453,23 @@
 			.name	= ION_AUDIO_HEAP_NAME,
 			.size	= MSM_ION_AUDIO_SIZE,
 			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &co_ion_pdata,
+			.extra_data = (void *) &co_msm8960_ion_pdata,
 		},
 #endif
 	}
 };
 
-static struct platform_device ion_dev = {
+static struct platform_device msm8960_ion_dev = {
 	.name = "ion-msm",
 	.id = 1,
-	.dev = { .platform_data = &ion_pdata },
+	.dev = { .platform_data = &msm8960_ion_pdata },
 };
 #endif
 
-struct platform_device fmem_device = {
+struct platform_device msm8960_fmem_device = {
 	.name = "fmem",
 	.id = 1,
-	.dev = { .platform_data = &fmem_pdata },
+	.dev = { .platform_data = &msm8960_fmem_pdata },
 };
 
 static void __init adjust_mem_for_liquid(void)
@@ -507,9 +485,10 @@
 
 		if (machine_is_msm8960_liquid() ||
 			msm8960_hdmi_as_primary_selected()) {
-			for (i = 0; i < ion_pdata.nr; i++) {
-				if (ion_pdata.heaps[i].id == ION_SF_HEAP_ID) {
-					ion_pdata.heaps[i].size =
+			for (i = 0; i < msm8960_ion_pdata.nr; i++) {
+				if (msm8960_ion_pdata.heaps[i].id ==
+							ION_SF_HEAP_ID) {
+					msm8960_ion_pdata.heaps[i].size =
 						msm_ion_sf_size;
 					pr_debug("msm_ion_sf_size 0x%x\n",
 						msm_ion_sf_size);
@@ -566,9 +545,10 @@
 	unsigned long fixed_low_start, fixed_middle_start, fixed_high_start;
 
 	adjust_mem_for_liquid();
-	fmem_pdata.size = 0;
-	fmem_pdata.reserved_size_low = 0;
-	fmem_pdata.reserved_size_high = 0;
+	msm8960_fmem_pdata.size = 0;
+	msm8960_fmem_pdata.reserved_size_low = 0;
+	msm8960_fmem_pdata.reserved_size_high = 0;
+	msm8960_fmem_pdata.align = PAGE_SIZE;
 	fixed_low_size = 0;
 	fixed_middle_size = 0;
 	fixed_high_size = 0;
@@ -576,8 +556,9 @@
 	/* We only support 1 reusable heap. Check if more than one heap
 	 * is specified as reusable and set as non-reusable if found.
 	 */
-	for (i = 0; i < ion_pdata.nr; ++i) {
-		const struct ion_platform_heap *heap = &(ion_pdata.heaps[i]);
+	for (i = 0; i < msm8960_ion_pdata.nr; ++i) {
+		const struct ion_platform_heap *heap =
+						&(msm8960_ion_pdata.heaps[i]);
 
 		if (heap->type == ION_HEAP_TYPE_CP && heap->extra_data) {
 			struct ion_cp_heap_pdata *data = heap->extra_data;
@@ -593,8 +574,12 @@
 		}
 	}
 
-	for (i = 0; i < ion_pdata.nr; ++i) {
-		const struct ion_platform_heap *heap = &(ion_pdata.heaps[i]);
+	for (i = 0; i < msm8960_ion_pdata.nr; ++i) {
+		struct ion_platform_heap *heap =
+						&(msm8960_ion_pdata.heaps[i]);
+		int align = SZ_4K;
+		int iommu_map_all = 0;
+		int adjacent_mem_id = INVALID_HEAP_ID;
 
 		if (heap->extra_data) {
 			int fixed_position = NOT_FIXED;
@@ -606,17 +591,35 @@
 					heap->extra_data)->mem_is_fmem;
 				fixed_position = ((struct ion_cp_heap_pdata *)
 					heap->extra_data)->fixed_position;
+				align = ((struct ion_cp_heap_pdata *)
+						heap->extra_data)->align;
+				iommu_map_all =
+					((struct ion_cp_heap_pdata *)
+					heap->extra_data)->iommu_map_all;
 				break;
 			case ION_HEAP_TYPE_CARVEOUT:
 				mem_is_fmem = ((struct ion_co_heap_pdata *)
 					heap->extra_data)->mem_is_fmem;
 				fixed_position = ((struct ion_co_heap_pdata *)
 					heap->extra_data)->fixed_position;
+				adjacent_mem_id = ((struct ion_co_heap_pdata *)
+					heap->extra_data)->adjacent_mem_id;
 				break;
 			default:
 				break;
 			}
 
+			if (iommu_map_all) {
+				if (heap->size & (SZ_64K-1)) {
+					heap->size = ALIGN(heap->size, SZ_64K);
+					pr_info("Heap %s not aligned to 64K. Adjusting size to %x\n",
+						heap->name, heap->size);
+				}
+			}
+
+			if (mem_is_fmem && adjacent_mem_id != INVALID_HEAP_ID)
+				msm8960_fmem_pdata.align = align;
+
 			if (fixed_position != NOT_FIXED)
 				fixed_size += heap->size;
 			else
@@ -630,16 +633,16 @@
 				fixed_high_size += heap->size;
 
 			if (mem_is_fmem)
-				fmem_pdata.size += heap->size;
+				msm8960_fmem_pdata.size += heap->size;
 		}
 	}
 
 	if (!fixed_size)
 		return;
 
-	if (fmem_pdata.size) {
-		fmem_pdata.reserved_size_low = fixed_low_size;
-		fmem_pdata.reserved_size_high = fixed_high_size;
+	if (msm8960_fmem_pdata.size) {
+		msm8960_fmem_pdata.reserved_size_low = fixed_low_size;
+		msm8960_fmem_pdata.reserved_size_high = fixed_high_size;
 	}
 
 	/* Since the fixed area may be carved out of lowmem,
@@ -653,8 +656,8 @@
 	fixed_middle_start = fixed_low_start + fixed_low_size;
 	fixed_high_start = fixed_middle_start + fixed_middle_size;
 
-	for (i = 0; i < ion_pdata.nr; ++i) {
-		struct ion_platform_heap *heap = &(ion_pdata.heaps[i]);
+	for (i = 0; i < msm8960_ion_pdata.nr; ++i) {
+		struct ion_platform_heap *heap = &(msm8960_ion_pdata.heaps[i]);
 
 		if (heap->extra_data) {
 			int fixed_position = NOT_FIXED;
@@ -695,21 +698,6 @@
 	msm8960_mdp_writeback(msm8960_reserve_table);
 }
 
-#if defined(CONFIG_MSM_CACHE_DUMP)
-static struct msm_cache_dump_platform_data msm_cache_dump_pdata = {
-	.l2_size = L2_BUFFER_SIZE,
-};
-
-static struct platform_device msm_cache_dump_device = {
-	.name           = "msm_cache_dump",
-	.id             = -1,
-	.dev            = {
-		.platform_data = &msm_cache_dump_pdata,
-	},
-};
-
-#endif
-
 static void __init reserve_cache_dump_memory(void)
 {
 #ifdef CONFIG_MSM_CACHE_DUMP
@@ -736,8 +724,8 @@
 	total = l1_size + l2_size;
 
 	msm8960_reserve_table[MEMTYPE_EBI1].size += total;
-	msm_cache_dump_pdata.l1_size = l1_size;
-	msm_cache_dump_pdata.l2_size = l2_size;
+	msm8960_cache_dump_pdata.l1_size = l1_size;
+	msm8960_cache_dump_pdata.l2_size = l2_size;
 #endif
 }
 
@@ -841,16 +829,17 @@
 {
 	msm8960_set_display_params(prim_panel_name, ext_panel_name);
 	msm_reserve();
-	if (fmem_pdata.size) {
+	if (msm8960_fmem_pdata.size) {
 #if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
-		fmem_pdata.phys = reserve_info->fixed_area_start +
-			MSM_MM_FW_SIZE;
-		pr_info("mm fw at %lx (fixed) size %x\n",
-			reserve_info->fixed_area_start, MSM_MM_FW_SIZE);
-		pr_info("fmem start %lx (fixed) size %lx\n",
-			fmem_pdata.phys, fmem_pdata.size);
-#else
-		fmem_pdata.phys = reserve_memory_for_fmem(fmem_pdata.size);
+		if (reserve_info->fixed_area_size) {
+			msm8960_fmem_pdata.phys =
+				reserve_info->fixed_area_start + MSM_MM_FW_SIZE;
+			pr_info("mm fw at %lx (fixed) size %x\n",
+				reserve_info->fixed_area_start, MSM_MM_FW_SIZE);
+			pr_info("fmem start %lx (fixed) size %lx\n",
+				msm8960_fmem_pdata.phys,
+				msm8960_fmem_pdata.size);
+		}
 #endif
 	}
 }
@@ -2422,6 +2411,11 @@
 		.tsens_num_sensor	= 5,
 };
 
+static struct platform_device msm_tsens_device = {
+	.name   = "tsens8960-tm",
+	.id = -1,
+};
+
 #ifdef CONFIG_MSM_FAKE_BATTERY
 static struct platform_device fish_battery_device = {
 	.name = "fish_battery",
@@ -2539,12 +2533,12 @@
 #ifdef CONFIG_MSM_FAKE_BATTERY
 	&fish_battery_device,
 #endif
-	&fmem_device,
+	&msm8960_fmem_device,
 #ifdef CONFIG_ANDROID_PMEM
 #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-	&android_pmem_device,
-	&android_pmem_adsp_device,
-	&android_pmem_audio_device,
+	&msm8960_android_pmem_device,
+	&msm8960_android_pmem_adsp_device,
+	&msm8960_android_pmem_audio_device,
 #endif
 #endif
 	&msm_device_vidc,
@@ -2563,7 +2557,7 @@
 	&msm_device_rng,
 #endif
 #ifdef CONFIG_ION_MSM
-	&ion_dev,
+	&msm8960_ion_dev,
 #endif
 	&msm8960_rpm_device,
 	&msm8960_rpm_log_device,
@@ -2578,16 +2572,13 @@
 #endif
 	&msm_device_dspcrashd_8960,
 	&msm8960_device_watchdog,
-#ifdef CONFIG_MSM_RTB
-	&msm_rtb_device,
-#endif
+	&msm8960_rtb_device,
 	&msm8960_cpu_idle_device,
 	&msm8960_msm_gov_device,
 	&msm8960_device_cache_erp,
-#ifdef CONFIG_MSM_CACHE_DUMP
-	&msm_cache_dump_device,
-#endif
+	&msm8960_cache_dump_device,
 	&msm8960_iommu_domain_device,
+	&msm_tsens_device,
 };
 
 static struct platform_device *sim_devices[] __initdata = {
@@ -3121,7 +3112,7 @@
 			msm_otg_pdata.phy_init_seq =
 				liquid_v1_phy_init_seq;
 	}
-	msm_otg_pdata.swfi_latency =
+	android_usb_pdata.swfi_latency =
 		msm_rpmrs_levels[0].latency_us;
 	msm_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
 	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2 &&
@@ -3141,8 +3132,7 @@
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
 	msm_spm_l2_init(msm_spm_l2_data);
 	msm8960_init_buses();
-	platform_add_devices(msm_footswitch_devices,
-		msm_num_footswitch_devices);
+	platform_add_devices(msm8960_footswitch, msm8960_num_footswitch);
 	if (machine_is_msm8960_liquid())
 		platform_device_register(&msm8960_device_ext_3p3v_vreg);
 	if (machine_is_msm8960_cdp())
diff --git a/arch/arm/mach-msm/board-8960.h b/arch/arm/mach-msm/board-8960.h
index 3824cfd..925c5b4 100644
--- a/arch/arm/mach-msm/board-8960.h
+++ b/arch/arm/mach-msm/board-8960.h
@@ -20,6 +20,8 @@
 #include <mach/irqs.h>
 #include <mach/rpm-regulator.h>
 #include <mach/msm_memtypes.h>
+#include <mach/msm_rtb.h>
+#include <mach/msm_cache_dump.h>
 
 /* Macros assume PMIC GPIOs and MPPs start at 1 */
 #define PM8921_GPIO_BASE		NR_GPIO_IRQS
@@ -92,3 +94,6 @@
 #define MSM_8960_GSBI4_QUP_I2C_BUS_ID 4
 #define MSM_8960_GSBI3_QUP_I2C_BUS_ID 3
 #define MSM_8960_GSBI10_QUP_I2C_BUS_ID 10
+
+extern struct msm_rtb_platform_data msm8960_rtb_pdata;
+extern struct msm_cache_dump_platform_data msm8960_cache_dump_pdata;
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 3389dea..a8602d3 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -43,10 +43,11 @@
 #include <mach/dma.h>
 #include <mach/ion.h>
 #include <mach/msm_memtypes.h>
+#include <mach/cpuidle.h>
+#include <mach/usb_bam.h>
 #include "timer.h"
 #include "devices.h"
 #include "board-9615.h"
-#include <mach/cpuidle.h>
 #include "pm.h"
 #include "acpuclock.h"
 #include "pm-boot.h"
@@ -568,6 +569,10 @@
 	.disable_reset_on_disconnect	= true,
 };
 
+static struct msm_hsic_peripheral_platform_data msm_hsic_peripheral_pdata = {
+	.keep_core_clk_on_suspend_workaround = true,
+};
+
 #define PID_MAGIC_ID		0x71432909
 #define SERIAL_NUM_MAGIC_ID	0x61945374
 #define SERIAL_NUMBER_LENGTH	127
@@ -620,18 +625,6 @@
 	return 0;
 }
 
-static struct android_usb_platform_data android_usb_pdata = {
-	.update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
-};
-
-static struct platform_device android_usb_device = {
-	.name	= "android_usb",
-	.id	= -1,
-	.dev	= {
-		.platform_data = &android_usb_pdata,
-	},
-};
-
 static struct platform_device msm_wlan_ar6000_pm_device = {
 	.name           = "wlan_ar6000_pm_dev",
 	.id             = -1,
@@ -656,7 +649,12 @@
 	.tsens_factor		= 1000,
 	.hw_type		= MDM_9615,
 	.tsens_num_sensor	= 5,
-	.slope = {1176, 1176, 1154, 1176, 1111},
+	.slope = {1176, 1162, 1162, 1149, 1176},
+};
+
+static struct platform_device msm_tsens_device = {
+	.name   = "tsens8960-tm",
+	.id = -1,
 };
 
 static struct platform_device *common_devices[] = {
@@ -673,7 +671,7 @@
 	&msm_device_hsusb_host,
 	&msm_device_hsic_host,
 	&msm_device_usb_bam,
-	&android_usb_device,
+	&msm_android_usb_device,
 	&msm9615_device_uart_gsbi4,
 	&msm9615_device_ext_2p95v_vreg,
 	&msm9615_device_ssbi_pmic1,
@@ -725,6 +723,7 @@
 	&msm_bus_def_fab,
 	&msm9615_rpm_log_device,
 	&msm9615_rpm_stat_device,
+	&msm_tsens_device,
 };
 
 static void __init msm9615_i2c_init(void)
@@ -743,6 +742,9 @@
 
 static void __init msm9615_common_init(void)
 {
+	struct android_usb_platform_data *android_pdata =
+				msm_android_usb_device.dev.platform_data;
+
 	msm9615_device_init();
 	msm9615_init_gpiomux();
 	msm9615_i2c_init();
@@ -759,6 +761,8 @@
 
 	msm_device_otg.dev.platform_data = &msm_otg_pdata;
 	msm_otg_pdata.phy_init_seq = shelby_phy_init_seq;
+	msm_device_hsic_peripheral.dev.platform_data =
+		&msm_hsic_peripheral_pdata;
 	msm_device_usb_bam.dev.platform_data = &msm_usb_bam_pdata;
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
 
@@ -770,6 +774,8 @@
 	msm9615_init_mmc();
 	slim_register_board_info(msm_slim_devices,
 		ARRAY_SIZE(msm_slim_devices));
+	android_pdata->update_pid_and_serial_num =
+					usb_diag_update_pid_and_serial_num;
 	msm_pm_boot_pdata.p_addr = allocate_contiguous_ebi_nomap(SZ_8, SZ_64K);
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 	msm_tsens_early_init(&msm_tsens_pdata);
diff --git a/arch/arm/mach-msm/board-copper-gpiomux.c b/arch/arm/mach-msm/board-copper-gpiomux.c
index 50b03fc..0ea33c7 100644
--- a/arch/arm/mach-msm/board-copper-gpiomux.c
+++ b/arch/arm/mach-msm/board-copper-gpiomux.c
@@ -17,6 +17,8 @@
 #include <mach/gpio.h>
 #include <mach/gpiomux.h>
 
+#define KS8851_IRQ_GPIO 90
+
 static struct gpiomux_setting gpio_uart_config = {
 	.func = GPIOMUX_FUNC_2,
 	.drv = GPIOMUX_DRV_16MA,
@@ -24,7 +26,62 @@
 	.dir = GPIOMUX_OUT_HIGH,
 };
 
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+static struct gpiomux_setting gpio_eth_config = {
+	.pull = GPIOMUX_PULL_NONE,
+	.drv = GPIOMUX_DRV_8MA,
+	.func = GPIOMUX_FUNC_GPIO,
+};
+
+static struct gpiomux_setting gpio_spi_cs_config = {
+	.func = GPIOMUX_FUNC_4,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gpio_spi_config = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config msm_eth_configs[] = {
+	{
+		.gpio = KS8851_IRQ_GPIO,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_eth_config,
+		}
+	},
+};
+#endif
+
 static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+	{
+		.gpio      = 0,		/* BLSP1 QUP SPI_DATA_MOSI */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 1,		/* BLSP1 QUP SPI_DATA_MISO */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 3,		/* BLSP1 QUP SPI_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 9,		/* BLSP1 QUP SPI_CS_N */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+		},
+	},
+#endif
 	{
 		.gpio      = 45,	       /* BLSP8 UART TX */
 		.settings = {
@@ -49,5 +106,8 @@
 		return;
 	}
 
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+	msm_gpiomux_install(msm_eth_configs, ARRAY_SIZE(msm_eth_configs));
+#endif
 	msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
 }
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index d1b62ae..14efac4 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -27,6 +27,7 @@
 #include <linux/android_pmem.h>
 #endif
 #include <linux/regulator/stub-regulator.h>
+#include <linux/regulator/machine.h>
 #include <asm/mach/map.h>
 #include <asm/hardware/gic.h>
 #include <mach/board.h>
@@ -39,8 +40,10 @@
 #include <mach/msm_memtypes.h>
 #include <mach/msm_smd.h>
 #include <mach/qpnp-int.h>
+#include <mach/socinfo.h>
 #include "clock.h"
 #include "devices.h"
+#include "spm.h"
 
 #define MSM_KERNEL_EBI1_MEM_SIZE	0x280000
 #ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
@@ -406,6 +409,8 @@
  */
 void __init msm_copper_add_drivers(void)
 {
+	msm_smd_init();
+	msm_spm_device_init();
 	regulator_stub_init();
 }
 
@@ -423,6 +428,7 @@
 
 static struct clk_lookup msm_clocks_dummy[] = {
 	CLK_DUMMY("xo",		XO_CLK,		NULL,	OFF),
+	CLK_DUMMY("xo",		XO_CLK,		"pil_pronto",		OFF),
 	CLK_DUMMY("core_clk",	BLSP2_UART_CLK,	"msm_serial_hsl.0",	OFF),
 	CLK_DUMMY("iface_clk",	BLSP2_UART_CLK,	"msm_serial_hsl.0",	OFF),
 	CLK_DUMMY("core_clk",	SDC1_CLK,	NULL,			OFF),
@@ -463,15 +469,23 @@
 			"msm_sdcc.3", NULL),
 	OF_DEV_AUXDATA("qcom,pil-q6v5-lpass",   0xFE200000, \
 			"pil-q6v5-lpass", NULL),
+	OF_DEV_AUXDATA("qcom,pil-pronto", 0xFB21B000, \
+			"pil_pronto", NULL),
 	{}
 };
 
 void __init msm_copper_init(struct of_dev_auxdata **adata)
 {
 	msm_copper_init_gpiomux();
-	msm_clock_init(&msm_dummy_clock_init_data);
+
+	if (machine_is_copper_rumi())
+		msm_clock_init(&msm_dummy_clock_init_data);
+	else
+		msm_clock_init(&msmcopper_clock_init_data);
 
 	*adata = msm_copper_auxdata_lookup;
+
+	regulator_has_full_constraints();
 }
 
 void __init msm_copper_very_early(void)
diff --git a/arch/arm/mach-msm/board-msm7627a-bt.c b/arch/arm/mach-msm/board-msm7627a-bt.c
index 81abbc0..75d5f15 100644
--- a/arch/arm/mach-msm/board-msm7627a-bt.c
+++ b/arch/arm/mach-msm/board-msm7627a-bt.c
@@ -102,7 +102,8 @@
 	u32 socinfo = socinfo_get_platform_version();
 	if (machine_is_msm7627a_qrd1())
 		gpio_bt_sys_rest_en = 114;
-	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
+	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+				|| machine_is_msm8625_evt())
 		gpio_bt_sys_rest_en = 16;
 	if (machine_is_msm8625_qrd7())
 		gpio_bt_sys_rest_en = 88;
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 9d01d90..329dcae 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -29,6 +29,9 @@
 #define GPIO_SKU3_CAM_5MP_SHDN_N   5         /* PWDN */
 #define GPIO_SKU3_CAM_5MP_CAMIF_RESET   6    /* (board_is(EVT))?123:121 RESET */
 #define GPIO_SKU3_CAM_5MP_CAM_DRIVER_PWDN 30
+#define GPIO_SKU7_CAM_VGA_SHDN    91
+#define GPIO_SKU7_CAM_5MP_SHDN_N   93         /* PWDN */
+#define GPIO_SKU7_CAM_5MP_CAMIF_RESET   23   /* (board_is(EVT))?123:121 RESET */
 
 #ifdef CONFIG_MSM_CAMERA_V4L2
 static uint32_t camera_off_gpio_table[] = {
@@ -73,9 +76,25 @@
 };
 
 #ifdef CONFIG_WEBCAM_OV7692_QRD
+static struct gpio ov7692_cam_req_gpio[] = {
+	{GPIO_SKU1_CAM_VGA_SHDN, GPIOF_DIR_OUT, "CAM_VGA_SHDN"},
+	{GPIO_SKU1_CAM_VGA_RESET_N, GPIOF_DIR_OUT, "CAM_VGA_RESET"},
+};
+
+static struct msm_gpio_set_tbl ov7692_cam_gpio_set_tbl[] = {
+	{GPIO_SKU1_CAM_VGA_SHDN, GPIOF_OUT_INIT_HIGH, 5000},
+	{GPIO_SKU1_CAM_VGA_SHDN, GPIOF_OUT_INIT_LOW, 5000},
+	{GPIO_SKU1_CAM_VGA_RESET_N, GPIOF_OUT_INIT_HIGH, 5000},
+	{GPIO_SKU1_CAM_VGA_RESET_N, GPIOF_OUT_INIT_LOW, 5000},
+	{40, GPIOF_OUT_INIT_HIGH, 5000},
+	{35, GPIOF_OUT_INIT_HIGH, 5000},
+};
+
 static struct msm_camera_gpio_conf gpio_conf_ov7692 = {
-	.camera_off_table = camera_off_gpio_table,
-	.camera_on_table = camera_on_gpio_table,
+	.cam_gpio_req_tbl = ov7692_cam_req_gpio,
+	.cam_gpio_req_tbl_size = ARRAY_SIZE(ov7692_cam_req_gpio),
+	.cam_gpio_set_tbl = ov7692_cam_gpio_set_tbl,
+	.cam_gpio_set_tbl_size = ARRAY_SIZE(ov7692_cam_gpio_set_tbl),
 	.gpio_no_mux = 1,
 };
 #endif
@@ -104,14 +123,38 @@
 
 static struct msm_camera_sensor_info msm_camera_sensor_s5k4e1_data;
 
-struct msm_camera_device_platform_data msm_camera_device_data_csi1 = {
-	.csid_core = 1,
-	.is_csic = 1,
+struct msm_camera_device_platform_data msm_camera_device_data_csi1[] = {
+	{
+		.csid_core = 1,
+		.is_csic = 1,
+		.ioclk = {
+			.vfe_clk_rate = 192000000,
+		},
+	},
+	{
+		.csid_core = 1,
+		.is_csic = 1,
+		.ioclk = {
+			.vfe_clk_rate = 266667000,
+		},
+	},
 };
 
-struct msm_camera_device_platform_data msm_camera_device_data_csi0 = {
-	.csid_core = 0,
-	.is_csic = 1,
+struct msm_camera_device_platform_data msm_camera_device_data_csi0[] = {
+	{
+		.csid_core = 0,
+		.is_csic = 1,
+		.ioclk = {
+			.vfe_clk_rate = 192000000,
+		},
+	},
+	{
+		.csid_core = 0,
+		.is_csic = 1,
+		.ioclk = {
+			.vfe_clk_rate = 266667000,
+		},
+	},
 };
 
 static struct i2c_board_info msm_act_main_cam_i2c_info = {
@@ -143,7 +186,7 @@
 	.sensor_name    = "s5k4e1",
 	.sensor_reset_enable = 1,
 	.pmic_gpio_enable    = 0,
-	.pdata                  = &msm_camera_device_data_csi1,
+	.pdata                  = &msm_camera_device_data_csi1[0],
 	.flash_data             = &flash_s5k4e1,
 	.sensor_platform_info   = &sensor_board_info_s5k4e1,
 	.csi_if                 = 1,
@@ -171,7 +214,7 @@
 	.pmic_gpio_enable  = 1,
 	.sensor_reset	   = GPIO_SKU1_CAM_VGA_RESET_N,
 	.sensor_pwd	     = GPIO_SKU1_CAM_VGA_SHDN,
-	.pdata			= &msm_camera_device_data_csi0,
+	.pdata			= &msm_camera_device_data_csi0[0],
 	.flash_data	     = &flash_ov7692,
 	.sensor_platform_info   = &sensor_board_info_ov7692,
 	.csi_if		 = 1,
@@ -214,7 +257,7 @@
 	.pmic_gpio_enable  = 1,
 	.sensor_reset   = GPIO_SKU3_CAM_5MP_CAMIF_RESET,
 	.sensor_pwd     = GPIO_SKU3_CAM_5MP_SHDN_N,
-	.pdata          = &msm_camera_device_data_csi1,
+	.pdata          = &msm_camera_device_data_csi1[0],
 	.flash_data     = &flash_ov5647,
 	.sensor_platform_info   = &sensor_board_info_ov5647,
 	.csi_if                 = 1,
@@ -241,7 +284,7 @@
 	.sensor_name    = "mt9e013",
 	.sensor_reset_enable = 1,
 	.pmic_gpio_enable    = 0,
-	.pdata                  = &msm_camera_device_data_csi1,
+	.pdata                  = &msm_camera_device_data_csi1[1],
 	.flash_data             = &flash_mt9e013,
 	.sensor_platform_info   = &sensor_board_info_mt9e013,
 	.csi_if                 = 1,
@@ -267,7 +310,7 @@
 	.sensor_name    = "ov9726",
 	.sensor_reset_enable = 0,
 	.pmic_gpio_enable  = 0,
-	.pdata                  = &msm_camera_device_data_csi0,
+	.pdata                  = &msm_camera_device_data_csi0[0],
 	.flash_data             = &flash_ov9726,
 	.sensor_platform_info   = &sensor_board_info_ov9726,
 	.csi_if                 = 1,
@@ -284,7 +327,8 @@
 static void __init msm7x27a_init_cam(void)
 {
 	if (!(machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
-				|| machine_is_msm7627a_qrd1())) {
+				|| machine_is_msm7627a_qrd1()
+				|| machine_is_msm8625_ffa())) {
 		sensor_board_info_s5k4e1.cam_vreg = NULL;
 		sensor_board_info_s5k4e1.num_vreg = 0;
 		sensor_board_info_mt9e013.cam_vreg = NULL;
@@ -297,14 +341,18 @@
 		sensor_board_info_ov5647.num_vreg = 0;
 	}
 	platform_device_register(&msm_camera_server);
-	if (machine_is_msm8625_surf() || machine_is_msm8625_evb()) {
+	if (machine_is_msm8625_surf() || machine_is_msm8625_evb()
+			|| machine_is_msm8625_evt()
+			|| machine_is_msm8625_qrd7()) {
 		platform_device_register(&msm8625_device_csic0);
 		platform_device_register(&msm8625_device_csic1);
 	} else {
 		platform_device_register(&msm7x27a_device_csic0);
 		platform_device_register(&msm7x27a_device_csic1);
 	}
-	if (machine_is_msm8625_evb())
+	if (machine_is_msm8625_evb()
+			|| machine_is_msm8625_evt()
+			|| machine_is_msm8625_qrd7())
 		*(int *) msm7x27a_device_clkctl.dev.platform_data = 1;
 	platform_device_register(&msm7x27a_device_clkctl);
 	platform_device_register(&msm7x27a_device_vfe);
@@ -420,71 +468,45 @@
 {
 	int rc = 0;
 
-	rc = gpio_request(GPIO_SKU3_CAM_5MP_SHDN_N, "ov5647");
+	rc = gpio_request(msm_camera_sensor_ov5647_data.sensor_pwd, "ov5647");
 	if (rc < 0)
-		pr_err("%s: gpio_request GPIO_SKU3_CAM_5MP_SHDN_N failed!",
-			 __func__);
+		pr_err("%s: gpio_request OV5647 sensor_pwd: %d failed!",
+			 __func__, msm_camera_sensor_ov5647_data.sensor_pwd);
 
-	pr_debug("gpio_tlmm_config %d\r\n", GPIO_SKU3_CAM_5MP_SHDN_N);
-	rc = gpio_tlmm_config(GPIO_CFG(GPIO_SKU3_CAM_5MP_SHDN_N, 0,
-		GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
-		GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+	rc = gpio_tlmm_config(GPIO_CFG(msm_camera_sensor_ov5647_data.sensor_pwd,
+				0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
+				GPIO_CFG_2MA), GPIO_CFG_ENABLE);
 	if (rc < 0) {
 		pr_err("%s:unable to enable Powr Dwn gpio for main camera!\n",
 			 __func__);
-		gpio_free(GPIO_SKU3_CAM_5MP_SHDN_N);
+		gpio_free(msm_camera_sensor_ov5647_data.sensor_pwd);
 	}
 
-	gpio_direction_output(GPIO_SKU3_CAM_5MP_SHDN_N, 1);
-
-	rc = gpio_request(GPIO_SKU3_CAM_5MP_CAMIF_RESET, "ov5647");
+	rc = gpio_direction_output(msm_camera_sensor_ov5647_data.sensor_pwd, 1);
 	if (rc < 0)
-		pr_err("%s: gpio_request GPIO_SKU3_CAM_5MP_CAMIF_RESET failed!",
-			 __func__);
+		pr_err("%s: unable to set gpio: %d direction for ov5647 camera\n",
+			__func__, msm_camera_sensor_ov5647_data.sensor_pwd);
 
-	pr_debug("gpio_tlmm_config %d\r\n", GPIO_SKU3_CAM_5MP_CAMIF_RESET);
-	rc = gpio_tlmm_config(GPIO_CFG(GPIO_SKU3_CAM_5MP_CAMIF_RESET, 0,
-		GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
-		GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+	rc = gpio_request(msm_camera_sensor_ov5647_data.sensor_reset, "ov5647");
+	if (rc < 0)
+		pr_err("%s: gpio_request OV5647 sensor_reset: %d failed!",
+			 __func__, msm_camera_sensor_ov5647_data.sensor_reset);
+
+	rc = gpio_tlmm_config(GPIO_CFG(
+				msm_camera_sensor_ov5647_data.sensor_reset,
+				0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
+				GPIO_CFG_2MA), GPIO_CFG_ENABLE);
 	if (rc < 0) {
 		pr_err("%s: unable to enable reset gpio for main camera!\n",
 			 __func__);
-		gpio_free(GPIO_SKU3_CAM_5MP_CAMIF_RESET);
+		gpio_free(msm_camera_sensor_ov5647_data.sensor_reset);
 	}
 
-	gpio_direction_output(GPIO_SKU3_CAM_5MP_CAMIF_RESET, 1);
-
-	rc = gpio_request(GPIO_SKU1_CAM_VGA_SHDN, "ov7692");
+	rc = gpio_direction_output(
+			msm_camera_sensor_ov5647_data.sensor_reset, 1);
 	if (rc < 0)
-		pr_err("%s: gpio_request---GPIO_SKU1_CAM_VGA_SHDN failed!",
-			 __func__);
-
-	rc = gpio_tlmm_config(GPIO_CFG(GPIO_SKU1_CAM_VGA_SHDN, 0,
-		GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
-		GPIO_CFG_2MA), GPIO_CFG_ENABLE);
-	if (rc < 0) {
-		pr_err("%s:unable to enable Powr Dwn gpio for frnt camera!\n",
-			 __func__);
-		gpio_free(GPIO_SKU1_CAM_VGA_SHDN);
-	}
-
-	gpio_direction_output(GPIO_SKU1_CAM_VGA_SHDN, 1);
-
-	rc = gpio_request(GPIO_SKU1_CAM_VGA_RESET_N, "ov7692");
-	if (rc < 0)
-		pr_err("%s: gpio_request---GPIO_SKU1_CAM_VGA_RESET_N failed!",
-			 __func__);
-
-	rc = gpio_tlmm_config(GPIO_CFG(GPIO_SKU1_CAM_VGA_RESET_N, 0,
-		GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
-		GPIO_CFG_2MA), GPIO_CFG_ENABLE);
-
-	if (rc < 0) {
-		pr_err("%s: unable to enable reset gpio for front camera!\n",
-			 __func__);
-		gpio_free(GPIO_SKU1_CAM_VGA_RESET_N);
-	}
-	gpio_direction_output(GPIO_SKU1_CAM_VGA_RESET_N, 1);
+		pr_err("%s: unable to set gpio: %d direction for ov5647 camera\n",
+			__func__, msm_camera_sensor_ov5647_data.sensor_reset);
 
 }
 
@@ -523,7 +545,8 @@
 	int rc = 0;
 
 	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
-				|| machine_is_msm7627a_qrd1())
+				|| machine_is_msm7627a_qrd1()
+				|| machine_is_msm8625_ffa())
 		msm_camera_vreg_config(1);
 
 	rc = config_gpio_table(camera_on_gpio_table,
@@ -540,7 +563,8 @@
 static void config_camera_off_gpios_rear(void)
 {
 	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
-				|| machine_is_msm7627a_qrd1())
+				|| machine_is_msm7627a_qrd1()
+				|| machine_is_msm8625_ffa())
 		msm_camera_vreg_config(0);
 
 	config_gpio_table(camera_off_gpio_table,
@@ -552,7 +576,8 @@
 	int rc = 0;
 
 	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
-				|| machine_is_msm7627a_qrd1())
+				|| machine_is_msm7627a_qrd1()
+				|| machine_is_msm8625_ffa())
 		msm_camera_vreg_config(1);
 
 	rc = config_gpio_table(camera_on_gpio_table,
@@ -569,7 +594,8 @@
 static void config_camera_off_gpios_front(void)
 {
 	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
-				|| machine_is_msm7627a_qrd1())
+				|| machine_is_msm7627a_qrd1()
+				|| machine_is_msm8625_ffa())
 		msm_camera_vreg_config(0);
 
 	config_gpio_table(camera_off_gpio_table,
@@ -962,6 +988,7 @@
 
 #define LCD_CAMERA_LDO_2V8 35 /* SKU1&SKU3 2.8V LDO */
 #define SKU3_LCD_CAMERA_LDO_1V8 40 /* SKU3 1.8V LDO */
+#define SKU7_LCD_CAMERA_LDO_1V8 58 /* SKU7 1.8V LDO */
 
 static int lcd_camera_ldo_1v8 = SKU3_LCD_CAMERA_LDO_1V8;
 
@@ -971,7 +998,10 @@
 
 	pr_debug("lcd_camera_power_init\n");
 
-	lcd_camera_ldo_1v8 = SKU3_LCD_CAMERA_LDO_1V8; /* SKU3 PVT */
+	if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())
+		lcd_camera_ldo_1v8 = SKU7_LCD_CAMERA_LDO_1V8;
+	else
+		lcd_camera_ldo_1v8 = SKU3_LCD_CAMERA_LDO_1V8;
 
 	/* LDO_EXT2V8 */
 	if (gpio_request(LCD_CAMERA_LDO_2V8, "lcd_camera_ldo_2v8")) {
@@ -1063,8 +1093,28 @@
 #endif
 
 	pr_debug("msm7627a_camera_init Entered\n");
+
+	if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()) {
+		ov7692_cam_req_gpio[0].gpio =
+			GPIO_SKU7_CAM_VGA_SHDN;
+		ov7692_cam_gpio_set_tbl[0].gpio = GPIO_SKU7_CAM_VGA_SHDN;
+		ov7692_cam_gpio_set_tbl[1].gpio = GPIO_SKU7_CAM_VGA_SHDN;
+		ov7692_cam_gpio_set_tbl[4].gpio = LCD_CAMERA_LDO_2V8 ;
+		ov7692_cam_gpio_set_tbl[5].gpio = SKU7_LCD_CAMERA_LDO_1V8;
+
+		msm_camera_sensor_ov5647_data.sensor_pwd =
+			GPIO_SKU7_CAM_5MP_SHDN_N;
+		msm_camera_sensor_ov5647_data.sensor_reset =
+			GPIO_SKU7_CAM_5MP_CAMIF_RESET;
+
+	}
+
 	/* LCD and camera power (VREG & LDO) init */
-	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
+	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+			|| machine_is_msm8625_evt()
+			|| machine_is_msm7627a_qrd3()
+			|| machine_is_msm8625_qrd7()) {
+
 		lcd_camera_power_init();
 		evb_camera_gpio_cfg();
 	}
@@ -1074,7 +1124,11 @@
 		qrd1_camera_gpio_cfg();
 		platform_add_devices(camera_devices_qrd,
 				ARRAY_SIZE(camera_devices_qrd));
-	} else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
+	} else if (machine_is_msm7627a_evb()
+			|| machine_is_msm8625_evb()
+			|| machine_is_msm8625_evt()
+			|| machine_is_msm7627a_qrd3()
+			|| machine_is_msm8625_qrd7()) {
 		platform_add_devices(camera_devices_evb,
 				ARRAY_SIZE(camera_devices_evb));
 	} else if (machine_is_msm7627a_qrd3())
@@ -1084,7 +1138,10 @@
 				ARRAY_SIZE(camera_devices_msm));
 #endif
 	if (!machine_is_msm7627a_qrd1() || !machine_is_msm7627a_evb()
-					|| !machine_is_msm8625_evb())
+					|| !machine_is_msm8625_evb()
+					|| !machine_is_msm8625_evt()
+					|| !machine_is_msm7627a_qrd3()
+					|| !machine_is_msm8625_qrd7())
 		register_i2c_devices();
 #ifndef CONFIG_MSM_CAMERA_V4L2
 	rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_camera), regs_camera);
@@ -1110,7 +1167,11 @@
 		i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
 				i2c_camera_devices_qrd,
 				ARRAY_SIZE(i2c_camera_devices_qrd));
-	} else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
+	} else if (machine_is_msm7627a_evb()
+			|| machine_is_msm8625_evb()
+			|| machine_is_msm8625_evt()
+			|| machine_is_msm7627a_qrd3()
+			|| machine_is_msm8625_qrd7()) {
 		pr_debug("machine_is_msm7627a_evb i2c_register_board_info\n");
 		i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
 				i2c_camera_devices_evb,
diff --git a/arch/arm/mach-msm/board-msm7627a-display.c b/arch/arm/mach-msm/board-msm7627a-display.c
index 2a703f0..f44cc9e 100644
--- a/arch/arm/mach-msm/board-msm7627a-display.c
+++ b/arch/arm/mach-msm/board-msm7627a-display.c
@@ -487,7 +487,8 @@
 		if (!strncmp(name, "lcdc_toshiba_fwvga_pt", 21) ||
 				!strncmp(name, "mipi_cmd_renesas_fwvga", 22))
 			ret = 0;
-	} else if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()) {
+	} else if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+					|| machine_is_msm8625_ffa()) {
 		if (!strncmp(name, "mipi_cmd_renesas_fwvga", 22))
 			ret = 0;
 	} else if (machine_is_msm7627a_qrd1()) {
@@ -499,6 +500,9 @@
 	} else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
 		if (!strncmp(name, "mipi_cmd_nt35510_wvga", 21))
 			ret = 0;
+	} else if (machine_is_msm8625_evt()) {
+		if (!strncmp(name, "mipi_video_nt35510_wvga", 23))
+			ret = 0;
 	}
 
 #if !defined(CONFIG_FB_MSM_LCDC_AUTO_DETECT) && \
@@ -661,6 +665,14 @@
 	return 0;
 }
 
+static int mipi_NT35510_rotate_panel(void)
+{
+	int rotate = 0;
+	if (machine_is_msm8625_evt())
+		rotate = 1;
+
+	return rotate;
+}
 
 static struct msm_panel_common_pdata mipi_truly_pdata = {
 	.pmic_backlight = mipi_truly_set_bl,
@@ -676,6 +688,7 @@
 
 static struct msm_panel_common_pdata mipi_NT35510_pdata = {
 	.pmic_backlight = evb_backlight_control,
+	.rotate_panel = mipi_NT35510_rotate_panel,
 };
 
 static struct platform_device mipi_dsi_NT35510_panel_device = {
@@ -732,7 +745,8 @@
 
 	if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa())
 		fb_size = MSM7x25A_MSM_FB_SIZE;
-	else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
+	else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+						|| machine_is_msm8625_evt())
 		fb_size = MSM8x25_MSM_FB_SIZE;
 	else
 		fb_size = MSM_FB_SIZE;
@@ -946,7 +960,8 @@
 
 	if (machine_is_msm7627a_qrd1())
 		rc = msm_fb_dsi_client_qrd1_reset();
-	else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
+	else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+						|| machine_is_msm8625_evt())
 		rc = msm_fb_dsi_client_qrd3_reset();
 	else
 		rc = msm_fb_dsi_client_msm_reset();
@@ -1021,8 +1036,8 @@
 			machine_is_msm8625_surf()) {
 		gpio_set_value_cansleep(GPIO_DISPLAY_PWR_EN, on);
 		gpio_set_value_cansleep(GPIO_BACKLIGHT_EN, on);
-	} else if (machine_is_msm7x27a_ffa() ||
-			 machine_is_msm7625a_ffa()) {
+	} else if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+					|| machine_is_msm8625_ffa()) {
 		if (on) {
 			/* This line drives an active low pin on FFA */
 			rc = gpio_direction_output(GPIO_DISPLAY_PWR_EN, !on);
@@ -1132,20 +1147,6 @@
 		if (rc < 0)
 			return rc;
 
-		rc = gpio_tlmm_config(GPIO_CFG(GPIO_QRD3_LCD_BACKLIGHT_EN, 0,
-			GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
-			GPIO_CFG_ENABLE);
-		if (rc < 0) {
-			pr_err("failed QRD3 GPIO_BACKLIGHT_EN tlmm config\n");
-			return rc;
-		}
-		rc = gpio_direction_output(GPIO_QRD3_LCD_BACKLIGHT_EN, 1);
-		if (rc < 0) {
-			pr_err("failed to enable backlight\n");
-			gpio_free(GPIO_QRD3_LCD_BACKLIGHT_EN);
-			return rc;
-		}
-
 		rc = gpio_request(GPIO_QRD3_LCD_EXT_2V85_EN,
 			"qrd3_gpio_ext_2v85_en");
 		if (rc < 0)
@@ -1190,6 +1191,20 @@
 	}
 
 	if (on) {
+		rc = gpio_tlmm_config(GPIO_CFG(GPIO_QRD3_LCD_BACKLIGHT_EN, 0,
+			GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
+			GPIO_CFG_ENABLE);
+		if (rc < 0) {
+			pr_err("failed QRD3 GPIO_BACKLIGHT_EN tlmm config\n");
+			return rc;
+		}
+		rc = gpio_direction_output(GPIO_QRD3_LCD_BACKLIGHT_EN, 1);
+		if (rc < 0) {
+			pr_err("failed to enable backlight\n");
+			gpio_free(GPIO_QRD3_LCD_BACKLIGHT_EN);
+			return rc;
+		}
+
 		gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 1);
 		udelay(190);
 		gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 0);
@@ -1197,8 +1212,11 @@
 		gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 1);
 		/* 1 wire mode starts from this low to high transition */
 		udelay(50);
-	} else
-		gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, !!on);
+	} else {
+		gpio_tlmm_config(GPIO_CFG(GPIO_QRD3_LCD_BACKLIGHT_EN, 0,
+			GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+			GPIO_CFG_DISABLE);
+	}
 
 	gpio_set_value_cansleep(GPIO_QRD3_LCD_EXT_2V85_EN, !!on);
 	gpio_set_value_cansleep(GPIO_QRD3_LCD_EXT_1V8_EN, !!on);
@@ -1239,7 +1257,8 @@
 
 	if (machine_is_msm7627a_qrd1())
 		rc = mipi_dsi_panel_qrd1_power(on);
-	else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
+	else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+						|| machine_is_msm8625_evt())
 		rc = mipi_dsi_panel_qrd3_power(on);
 	else
 		rc = mipi_dsi_panel_msm_power(on);
@@ -1282,7 +1301,8 @@
 	if (machine_is_msm7627a_qrd1())
 		platform_add_devices(qrd_fb_devices,
 				ARRAY_SIZE(qrd_fb_devices));
-	else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
+	else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+						|| machine_is_msm8625_evt()) {
 		mipi_NT35510_pdata.bl_lock = 1;
 		mipi_NT35516_pdata.bl_lock = 1;
 		platform_add_devices(evb_fb_devices,
diff --git a/arch/arm/mach-msm/board-msm7627a-io.c b/arch/arm/mach-msm/board-msm7627a-io.c
index e622dfe..49945d0 100644
--- a/arch/arm/mach-msm/board-msm7627a-io.c
+++ b/arch/arm/mach-msm/board-msm7627a-io.c
@@ -25,6 +25,7 @@
 #include <asm/gpio.h>
 #include <asm/mach-types.h>
 #include <mach/rpc_server_handset.h>
+#include <mach/pmic.h>
 
 #include "devices.h"
 #include "board-msm7627a.h"
@@ -185,6 +186,56 @@
 
 #define MXT_TS_IRQ_GPIO         48
 #define MXT_TS_RESET_GPIO       26
+#define MAX_VKEY_LEN		100
+
+static ssize_t mxt_virtual_keys_register(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	char *virtual_keys = __stringify(EV_KEY) ":" __stringify(KEY_MENU) \
+		":60:840:120:80" ":" __stringify(EV_KEY) \
+		":" __stringify(KEY_HOME)   ":180:840:120:80" \
+		":" __stringify(EV_KEY) ":" \
+		__stringify(KEY_BACK) ":300:840:120:80" \
+		":" __stringify(EV_KEY) ":" \
+		__stringify(KEY_SEARCH)   ":420:840:120:80" "\n";
+
+	return snprintf(buf, strnlen(virtual_keys, MAX_VKEY_LEN) + 1 , "%s",
+			virtual_keys);
+}
+
+static struct kobj_attribute mxt_virtual_keys_attr = {
+	.attr = {
+		.name = "virtualkeys.atmel_mxt_ts",
+		.mode = S_IRUGO,
+	},
+	.show = &mxt_virtual_keys_register,
+};
+
+static struct attribute *mxt_virtual_key_properties_attrs[] = {
+	&mxt_virtual_keys_attr.attr,
+	NULL,
+};
+
+static struct attribute_group mxt_virtual_key_properties_attr_group = {
+	.attrs = mxt_virtual_key_properties_attrs,
+};
+
+struct kobject *mxt_virtual_key_properties_kobj;
+
+static int mxt_vkey_setup(void)
+{
+	int retval;
+
+	mxt_virtual_key_properties_kobj =
+		kobject_create_and_add("board_properties", NULL);
+	if (mxt_virtual_key_properties_kobj)
+		retval = sysfs_create_group(mxt_virtual_key_properties_kobj,
+				&mxt_virtual_key_properties_attr_group);
+	if (!mxt_virtual_key_properties_kobj || retval)
+		pr_err("failed to create mxt board_properties\n");
+
+	return retval;
+}
 
 static const u8 mxt_config_data[] = {
 	/* T6 Object */
@@ -231,6 +282,51 @@
 	80, 100, 15, 3,
 };
 
+static const u8 mxt_config_data_evt[] = {
+	/* T6 Object */
+	0, 0, 0, 0, 0, 0,
+	/* T38 Object */
+	20, 0, 0, 0, 0, 0, 0, 0,
+	/* T7 Object */
+	24, 12, 10,
+	/* T8 Object */
+	30, 0, 20, 20, 0, 0, 9, 45, 10, 192,
+	/* T9 Object */
+	3, 0, 0, 18, 11, 0, 16, 60, 3, 1,
+	0, 1, 1, 0, 10, 10, 10, 10, 107, 3,
+	223, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+	20, 15, 0, 0, 2,
+	/* T15 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0,
+	/* T18 Object */
+	0, 0,
+	/* T19 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0,
+	/* T23 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0,
+	/* T25 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0,
+	/* T40 Object */
+	17, 0, 0, 30, 30,
+	/* T42 Object */
+	3, 20, 45, 40, 128, 0, 0, 0,
+	/* T46 Object */
+	0, 2, 16, 16, 0, 0, 0, 0, 0,
+	/* T47 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	/* T48 Object */
+	1, 128, 96, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 6, 6, 0, 0, 63, 4, 64,
+	10, 0, 32, 5, 0, 38, 0, 8, 0, 0,
+	0, 0, 0, 0, 16, 65, 3, 1, 1, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0,
+};
+
 static struct mxt_config_info mxt_config_array[] = {
 	{
 		.config		= mxt_config_data,
@@ -653,6 +749,24 @@
 	},
 };
 
+static struct led_info ctp_backlight_info = {
+	.name           = "button-backlight",
+	.flags          = PM_MPP__I_SINK__LEVEL_40mA << 16 | PM_MPP_7,
+};
+
+static struct led_platform_data ctp_backlight_pdata = {
+	.leds = &ctp_backlight_info,
+	.num_leds = 1,
+};
+
+static struct platform_device pmic_mpp_leds_pdev = {
+	.name   = "pmic-mpp-leds",
+	.id     = -1,
+	.dev    = {
+		.platform_data  = &ctp_backlight_pdata,
+	},
+};
+
 void __init msm7627a_add_io_devices(void)
 {
 	/* touchscreen */
@@ -682,7 +796,8 @@
 		platform_device_register(&led_pdev);
 
 	/* Vibrator */
-	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa())
+	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+					|| machine_is_msm8625_ffa())
 		msm_init_pmic_vibrator();
 }
 
@@ -695,7 +810,17 @@
 		i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
 					synaptic_i2c_clearpad3k,
 					ARRAY_SIZE(synaptic_i2c_clearpad3k));
-	} else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
+	} else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb() ||
+			machine_is_msm8625_evt()) {
+		/* Use configuration data for EVT */
+		if (machine_is_msm8625_evt()) {
+			mxt_config_array[0].config = mxt_config_data_evt;
+			mxt_config_array[0].config_length =
+					ARRAY_SIZE(mxt_config_data_evt);
+			mxt_platform_data.panel_maxy = 875;
+			mxt_vkey_setup();
+		}
+
 		rc = gpio_tlmm_config(GPIO_CFG(MXT_TS_IRQ_GPIO, 0,
 				GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
 				GPIO_CFG_8MA), GPIO_CFG_ENABLE);
@@ -752,5 +877,6 @@
 		}
 
 		platform_device_register(&gpio_leds_8625);
+		platform_device_register(&pmic_mpp_leds_pdev);
 	}
 }
diff --git a/arch/arm/mach-msm/board-msm7627a-storage.c b/arch/arm/mach-msm/board-msm7627a-storage.c
index 946e109..43937b8 100644
--- a/arch/arm/mach-msm/board-msm7627a-storage.c
+++ b/arch/arm/mach-msm/board-msm7627a-storage.c
@@ -382,7 +382,14 @@
 	gpio_sdc1_config();
 	if (mmc_regulator_init(1, "mmc", 2850000))
 		return;
-	sdc1_plat_data.status_irq = MSM_GPIO_TO_INT(gpio_sdc1_hw_det);
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+	/* 8x25 EVT do not use hw detector */
+	if (!(machine_is_msm8625_evt()))
+		sdc1_plat_data.status_irq = MSM_GPIO_TO_INT(gpio_sdc1_hw_det);
+	if (machine_is_msm8625_evt())
+		sdc1_plat_data.status = NULL;
+#endif
+
 	msm_add_sdcc(1, &sdc1_plat_data);
 #endif
 	/* SDIO WLAN slot */
diff --git a/arch/arm/mach-msm/board-msm7627a-wlan.c b/arch/arm/mach-msm/board-msm7627a-wlan.c
index 5c2f801..07b7ab0 100644
--- a/arch/arm/mach-msm/board-msm7627a-wlan.c
+++ b/arch/arm/mach-msm/board-msm7627a-wlan.c
@@ -50,6 +50,7 @@
 {
 	if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
 					|| machine_is_msm8625_evb()
+					|| machine_is_msm8625_evt()
 					|| machine_is_msm7627a_qrd3()
 					|| machine_is_msm8625_qrd7())
 		gpio_wlan_sys_rest_en = 124;
@@ -234,6 +235,7 @@
 	 */
 	if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
 					|| machine_is_msm8625_evb()
+					|| machine_is_msm8625_evt()
 					|| machine_is_msm7627a_qrd3()
 					|| machine_is_msm8625_qrd7()) {
 		rc = gpio_tlmm_config(GPIO_CFG(gpio_wlan_sys_rest_en, 0,
@@ -312,6 +314,7 @@
 	 */
 	if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
 					|| machine_is_msm8625_evb()
+					|| machine_is_msm8625_evt()
 					|| machine_is_msm7627a_qrd3()
 					|| machine_is_msm8625_qrd7()) {
 		rc = gpio_tlmm_config(GPIO_CFG(gpio_wlan_sys_rest_en, 0,
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 8941b6d..df4ca83 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -48,6 +48,7 @@
 #include <mach/msm_battery.h>
 #include <linux/smsc911x.h>
 #include <linux/atmel_maxtouch.h>
+#include <linux/fmem.h>
 #include <linux/msm_adc.h>
 #include "devices.h"
 #include "timer.h"
@@ -435,6 +436,9 @@
 	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
 	.cached = 1,
 	.memory_type = MEMTYPE_EBI1,
+	.request_region = request_fmem_c_region,
+	.release_region = release_fmem_c_region,
+	.reusable = 1,
 };
 
 static struct platform_device android_pmem_adsp_device = {
@@ -563,9 +567,9 @@
 	(DEC4_FORMAT),
 
 	/* Concurrency 6 */
-	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	0, 0, 0,
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|
+			(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	0, 0, 0, 0,
 
 	/* Concurrency 7 */
 	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
@@ -756,6 +760,14 @@
 static void msm7x27a_cfg_uart2dm_serial(void) { }
 #endif
 
+struct fmem_platform_data fmem_pdata;
+
+struct platform_device fmem_device = {
+	.name = "fmem",
+	.id = 1,
+	.dev = { .platform_data = &fmem_pdata },
+};
+
 static struct platform_device *rumi_sim_devices[] __initdata = {
 	&msm_device_dmov,
 	&msm_device_smd,
@@ -793,6 +805,7 @@
 	&android_pmem_device,
 	&android_pmem_adsp_device,
 	&android_pmem_audio_device,
+	&fmem_device,
 	&msm_device_nand,
 	&msm_device_snd,
 	&msm_device_adspdec,
@@ -843,8 +856,19 @@
 	},
 };
 
+#ifdef CONFIG_ANDROID_PMEM
+static struct android_pmem_platform_data *pmem_pdata_array[] __initdata = {
+		&android_pmem_adsp_pdata,
+		&android_pmem_audio_pdata,
+		&android_pmem_pdata,
+};
+#endif
+
 static void __init size_pmem_devices(void)
 {
+#ifdef CONFIG_ANDROID_PMEM
+	unsigned int i;
+	unsigned int reusable_count = 0;
 
 	if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) {
 		pmem_mdp_size = MSM7x25A_MSM_PMEM_MDP_SIZE;
@@ -854,11 +878,30 @@
 		pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
 	}
 
-#ifdef CONFIG_ANDROID_PMEM
 	android_pmem_adsp_pdata.size = pmem_adsp_size;
 	android_pmem_pdata.size = pmem_mdp_size;
 	android_pmem_audio_pdata.size = pmem_audio_size;
+
+	fmem_pdata.size = 0;
+
+	/* Find pmem devices that should use FMEM (reusable) memory.
+	 */
+	for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) {
+		struct android_pmem_platform_data *pdata = pmem_pdata_array[i];
+
+		if (!reusable_count && pdata->reusable)
+			fmem_pdata.size += pdata->size;
+
+		reusable_count += (pdata->reusable) ? 1 : 0;
+
+		if (pdata->reusable && reusable_count > 1) {
+			pr_err("%s: Too many PMEM devices specified as reusable. PMEM device %s was not configured as reusable.\n",
+				__func__, pdata->name);
+			pdata->reusable = 0;
+		}
+	}
 #endif
+
 }
 
 static void __init reserve_memory_for(struct android_pmem_platform_data *p)
@@ -869,9 +912,10 @@
 static void __init reserve_pmem_memory(void)
 {
 #ifdef CONFIG_ANDROID_PMEM
-	reserve_memory_for(&android_pmem_adsp_pdata);
-	reserve_memory_for(&android_pmem_pdata);
-	reserve_memory_for(&android_pmem_audio_pdata);
+	unsigned int i;
+	for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i)
+		reserve_memory_for(pmem_pdata_array[i]);
+
 	msm7x27a_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
 #endif
 }
@@ -1034,7 +1078,7 @@
 
 static void __init msm7x27a_add_platform_devices(void)
 {
-	if (machine_is_msm8625_surf()) {
+	if (machine_is_msm8625_surf() || machine_is_msm8625_ffa()) {
 		platform_add_devices(msm8625_surf_devices,
 			ARRAY_SIZE(msm8625_surf_devices));
 	} else {
@@ -1059,14 +1103,16 @@
 
 static void __init msm7x27a_otg_gadget(void)
 {
-	msm_otg_pdata.swfi_latency =
-		msm7x27a_pm_data[
-		MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
 	if (cpu_is_msm8625()) {
+		msm_otg_pdata.swfi_latency =
+		msm8625_pm_data[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency;
 		msm8625_device_otg.dev.platform_data = &msm_otg_pdata;
 		msm8625_device_gadget_peripheral.dev.platform_data =
 			&msm_gadget_pdata;
 	} else {
+		msm_otg_pdata.swfi_latency =
+		msm7x27a_pm_data[
+		MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
 		msm_device_otg.dev.platform_data = &msm_otg_pdata;
 		msm_device_gadget_peripheral.dev.platform_data =
 			&msm_gadget_pdata;
@@ -1075,7 +1121,7 @@
 
 static void __init msm7x27a_pm_init(void)
 {
-	if (machine_is_msm8625_surf()) {
+	if (machine_is_msm8625_surf() || machine_is_msm8625_ffa()) {
 		msm_pm_set_platform_data(msm8625_pm_data,
 				ARRAY_SIZE(msm8625_pm_data));
 		BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata));
@@ -1198,3 +1244,13 @@
 	.init_early     = msm7x2x_init_early,
 	.handle_irq	= gic_handle_irq,
 MACHINE_END
+MACHINE_START(MSM8625_FFA, "QCT MSM8625 FFA")
+	.boot_params    = PHYS_OFFSET + 0x100,
+	.map_io         = msm8625_map_io,
+	.reserve        = msm8625_reserve,
+	.init_irq       = msm8625_init_irq,
+	.init_machine   = msm7x2x_init,
+	.timer          = &msm_timer,
+	.init_early     = msm7x2x_init_early,
+	.handle_irq	= gic_handle_irq,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-msm8x60-camera.c b/arch/arm/mach-msm/board-msm8x60-camera.c
index 743ca4d..32d5530 100644
--- a/arch/arm/mach-msm/board-msm8x60-camera.c
+++ b/arch/arm/mach-msm/board-msm8x60-camera.c
@@ -23,6 +23,7 @@
 #include "devices.h"
 
 #define GPIO_EXT_CAMIF_PWR_EN1 (PM8901_MPP_BASE + PM8901_MPPS + 13)
+#define GPIO_WEB_CAMIF_STANDBY1 (PM8901_MPP_BASE + PM8901_MPPS + 60)
 #ifdef CONFIG_MSM_CAMERA_FLASH
 #define VFE_CAMIF_TIMER1_GPIO 29
 #define VFE_CAMIF_TIMER2_GPIO 30
@@ -388,10 +389,10 @@
 	{47, GPIOF_DIR_IN, "CAMIF_I2C_DATA"},
 	{48, GPIOF_DIR_IN, "CAMIF_I2C_CLK"},
 	{105, GPIOF_DIR_IN, "STANDBY"},
-	{GPIO_EXT_CAMIF_PWR_EN1, GPIOF_DIR_OUT, "CAMIF_PWR_EN"},
 };
 
 static struct gpio msm8x60_back_cam_gpio[] = {
+	{GPIO_EXT_CAMIF_PWR_EN1, GPIOF_DIR_OUT, "CAMIF_PWR_EN"},
 	{106, GPIOF_DIR_OUT, "CAM_RESET"},
 };
 
@@ -448,6 +449,63 @@
 	.actuator_info = &imx074_actuator_info
 };
 
+static struct msm_camera_sensor_flash_data flash_mt9e013 = {
+	.flash_type	= MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_mt9e013 = {
+	.mount_angle	= 0,
+	.cam_vreg = msm_8x60_back_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8x60_back_cam_vreg),
+	.gpio_conf = &msm_8x60_back_cam_gpio_conf,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9e013_data = {
+	.sensor_name	= "mt9e013",
+	.pdata	= &msm_camera_csi_device_data[0],
+	.flash_data	= &flash_mt9e013,
+	.sensor_platform_info = &sensor_board_info_mt9e013,
+	.csi_if	= 1,
+	.camera_type = BACK_CAMERA_2D,
+};
+
+static struct gpio ov7692_cam_gpio[] = {
+	{GPIO_WEB_CAMIF_STANDBY1, GPIOF_DIR_OUT, "CAM_EN"},
+};
+
+static struct msm_gpio_set_tbl ov7692_cam_gpio_set_tbl[] = {
+	{GPIO_WEB_CAMIF_STANDBY1, GPIOF_OUT_INIT_LOW, 10000},
+};
+
+static struct msm_camera_gpio_conf ov7692_cam_gpio_conf = {
+	.cam_gpio_common_tbl = msm8x60_common_cam_gpio,
+	.cam_gpio_common_tbl_size = ARRAY_SIZE(msm8x60_common_cam_gpio),
+	.cam_gpio_req_tbl = ov7692_cam_gpio,
+	.cam_gpio_req_tbl_size = ARRAY_SIZE(ov7692_cam_gpio),
+	.cam_gpio_set_tbl = ov7692_cam_gpio_set_tbl,
+	.cam_gpio_set_tbl_size = ARRAY_SIZE(ov7692_cam_gpio_set_tbl),
+};
+
+static struct msm_camera_sensor_flash_data flash_ov7692 = {
+	.flash_type	= MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_ov7692 = {
+	.mount_angle	= 0,
+	.cam_vreg = msm_8x60_back_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_8x60_back_cam_vreg),
+	.gpio_conf = &ov7692_cam_gpio_conf,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov7692_data = {
+	.sensor_name	= "ov7692",
+	.pdata	= &msm_camera_csi_device_data[1],
+	.flash_data	= &flash_ov7692,
+	.sensor_platform_info = &sensor_board_info_ov7692,
+	.csi_if	= 1,
+	.camera_type = FRONT_CAMERA_2D,
+};
+
 static struct platform_device msm_camera_server = {
 	.name = "msm_cam_server",
 	.id = 0,
@@ -468,6 +526,14 @@
 	I2C_BOARD_INFO("imx074", 0x1A),
 	.platform_data = &msm_camera_sensor_imx074_data,
 	},
+	{
+	I2C_BOARD_INFO("mt9e013", 0x6C),
+	.platform_data = &msm_camera_sensor_mt9e013_data,
+	},
+	{
+	I2C_BOARD_INFO("ov7692", 0x78),
+	.platform_data = &msm_camera_sensor_ov7692_data,
+	},
 };
 
 struct msm_camera_board_info msm8x60_camera_board_info = {
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 5fc17df..e5a31f2a 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -85,6 +85,7 @@
 #include <mach/rpm-regulator.h>
 #include <mach/restart.h>
 #include <mach/board-msm8660.h>
+#include <mach/iommu_domains.h>
 
 #include "devices.h"
 #include "devices-msm8x60.h"
@@ -2646,7 +2647,7 @@
 #define MSM_ION_SF_SIZE		0x4000000 /* 64MB */
 #define MSM_ION_CAMERA_SIZE     MSM_PMEM_ADSP_SIZE
 #define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
-#define MSM_ION_MM_SIZE		0x3600000 /* (54MB) */
+#define MSM_ION_MM_SIZE		0x3600000 /* (54MB) Must be a multiple of 64K */
 #define MSM_ION_MFC_SIZE	SZ_8K
 #ifdef CONFIG_FB_MSM_OVERLAY1_WRITEBACK
 #define MSM_ION_WB_SIZE		0xC00000 /* 12MB */
@@ -3812,6 +3813,8 @@
 static struct regulator_consumer_supply vreg_consumers_PM8058_L15[] = {
 	REGULATOR_SUPPLY("8058_l15",		NULL),
 	REGULATOR_SUPPLY("cam_vana",		"1-001a"),
+	REGULATOR_SUPPLY("cam_vana",		"1-006c"),
+	REGULATOR_SUPPLY("cam_vana",		"1-0078"),
 };
 static struct regulator_consumer_supply vreg_consumers_PM8058_L16[] = {
 	REGULATOR_SUPPLY("8058_l16",		NULL),
@@ -3843,6 +3846,8 @@
 static struct regulator_consumer_supply vreg_consumers_PM8058_L25[] = {
 	REGULATOR_SUPPLY("8058_l25",		NULL),
 	REGULATOR_SUPPLY("cam_vdig",		"1-001a"),
+	REGULATOR_SUPPLY("cam_vdig",		"1-006c"),
+	REGULATOR_SUPPLY("cam_vdig",		"1-0078"),
 };
 static struct regulator_consumer_supply vreg_consumers_PM8058_S0[] = {
 	REGULATOR_SUPPLY("8058_s0",		NULL),
@@ -3862,6 +3867,8 @@
 static struct regulator_consumer_supply vreg_consumers_PM8058_LVS0[] = {
 	REGULATOR_SUPPLY("8058_lvs0",		NULL),
 	REGULATOR_SUPPLY("cam_vio",			"1-001a"),
+	REGULATOR_SUPPLY("cam_vio",			"1-006c"),
+	REGULATOR_SUPPLY("cam_vio",			"1-0078"),
 };
 static struct regulator_consumer_supply vreg_consumers_PM8058_LVS1[] = {
 	REGULATOR_SUPPLY("8058_lvs1",		NULL),
@@ -5256,10 +5263,12 @@
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 static struct ion_cp_heap_pdata cp_mm_ion_pdata = {
 	.permission_type = IPT_TYPE_MM_CARVEOUT,
-	.align = PAGE_SIZE,
+	.align = SZ_64K,
 	.request_region = request_smi_region,
 	.release_region = release_smi_region,
 	.setup_region = setup_smi_region,
+	.iommu_map_all = 1,
+	.iommu_2x_map_domain = VIDEO_DOMAIN,
 };
 
 static struct ion_cp_heap_pdata cp_mfc_ion_pdata = {
@@ -5426,6 +5435,23 @@
 		}
 	}
 
+	/* Verify size of heap is a multiple of 64K */
+	for (i = 0; i < ion_pdata.nr; i++) {
+		struct ion_platform_heap *heap = &(ion_pdata.heaps[i]);
+
+		if (heap->extra_data && heap->type == ION_HEAP_TYPE_CP) {
+			int map_all = ((struct ion_cp_heap_pdata *)
+				heap->extra_data)->iommu_map_all;
+
+			if (map_all && (heap->size & (SZ_64K-1))) {
+				heap->size = ALIGN(heap->size, SZ_64K);
+				pr_err("Heap %s size is not a multiple of 64K. Adjusting size to %x\n",
+					heap->name, heap->size);
+
+			}
+		}
+	}
+
 	msm8x60_reserve_table[MEMTYPE_EBI1].size += msm_ion_sf_size;
 	msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MM_FW_SIZE;
 	msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MM_SIZE;
@@ -7491,7 +7517,7 @@
 					"msm_ebi2", "mem_clk");
 		return;
 	}
-	clk_enable(mem_clk);
+	clk_prepare_enable(mem_clk);
 	clk_put(mem_clk);
 
 	ebi2_cfg_ptr = ioremap_nocache(0x1a100000, sizeof(uint32_t));
@@ -10315,8 +10341,8 @@
 	    machine_is_msm8x60_fusn_ffa() || machine_is_msm8x60_dragon()) {
 		msm8x60_cfg_smsc911x();
 		if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 1)
-			platform_add_devices(msm_footswitch_devices,
-					     msm_num_footswitch_devices);
+			platform_add_devices(msm8660_footswitch,
+					     msm8660_num_footswitch);
 		platform_add_devices(surf_devices,
 				     ARRAY_SIZE(surf_devices));
 
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 86bf205..f565075 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -510,9 +510,9 @@
 	(DEC4_FORMAT),
 
 	/* Concurrency 6 */
-	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	(DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
-	0, 0, 0,
+	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|
+			(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+	0, 0, 0, 0,
 
 	/* Concurrency 7 */
 	(DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
@@ -808,7 +808,8 @@
 
 static void __init add_platform_devices(void)
 {
-	if (machine_is_msm8625_evb() || machine_is_msm8625_qrd7()) {
+	if (machine_is_msm8625_evb() || machine_is_msm8625_qrd7()
+				|| machine_is_msm8625_evt()) {
 		platform_add_devices(msm8625_evb_devices,
 				ARRAY_SIZE(msm8625_evb_devices));
 		platform_add_devices(qrd3_devices,
@@ -839,15 +840,16 @@
 
 static void __init qrd7627a_otg_gadget(void)
 {
-	msm_otg_pdata.swfi_latency = msm7627a_pm_data
-		[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
-
 	if (cpu_is_msm8625()) {
+		msm_otg_pdata.swfi_latency = msm8625_pm_data
+		[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency;
 		msm8625_device_otg.dev.platform_data = &msm_otg_pdata;
 		msm8625_device_gadget_peripheral.dev.platform_data =
 					&msm_gadget_pdata;
 
 	} else {
+	msm_otg_pdata.swfi_latency = msm7627a_pm_data
+		[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
 		msm_device_otg.dev.platform_data = &msm_otg_pdata;
 		msm_device_gadget_peripheral.dev.platform_data =
 					&msm_gadget_pdata;
@@ -965,3 +967,13 @@
 	.init_early	= qrd7627a_init_early,
 	.handle_irq	= gic_handle_irq,
 MACHINE_END
+MACHINE_START(MSM8625_EVT, "QRD MSM8625 EVT")
+	.boot_params	= PHYS_OFFSET + 0x100,
+	.map_io		= msm8625_map_io,
+	.reserve	= msm8625_reserve,
+	.init_irq	= msm8625_init_irq,
+	.init_machine	= msm_qrd_init,
+	.timer		= &msm_timer,
+	.init_early	= qrd7627a_init_early,
+	.handle_irq	= gic_handle_irq,
+MACHINE_END
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
index 5ba3577..f51eb5b 100644
--- a/arch/arm/mach-msm/clock-7x30.c
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -2796,8 +2796,8 @@
 	OWN(APPS1,  6, "iface_clk",	grp_2d_p_clk,	"kgsl-2d0.0"),
 	OWN(APPS1,  6, "iface_clk",	grp_2d_p_clk,	"footswitch-pcom.0"),
 	OWN(APPS1, 31, "hdmi_clk",	hdmi_clk,	"dtv.0"),
-	OWN(APPS1,  0, "jpeg_clk",	jpeg_clk,	"msm_gemini.0"),
-	OWN(APPS1,  0, "jpeg_pclk",	jpeg_p_clk,	"msm_gemini.0"),
+	OWN(APPS1,  0, "core_clk",	jpeg_clk,	"msm_gemini.0"),
+	OWN(APPS1,  0, "iface_clk",	jpeg_p_clk,	"msm_gemini.0"),
 	OWN(APPS1, 23, "lpa_codec_clk", lpa_codec_clk,	NULL),
 	OWN(APPS1, 23, "lpa_core_clk",	lpa_core_clk,	NULL),
 	OWN(APPS1, 23, "lpa_pclk",	lpa_p_clk,	NULL),
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 0997e8bd..3a0b87e 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -49,6 +49,7 @@
 #define CE3_CORE_CLK_CTL_REG			REG(0x36CC)
 #define CE3_CLK_SRC_NS_REG			REG(0x36C0)
 #define DMA_BAM_HCLK_CTL			REG(0x25C0)
+#define CLK_HALT_AFAB_SFAB_STATEA_REG		REG(0x2FC0)
 #define CLK_HALT_AFAB_SFAB_STATEB_REG		REG(0x2FC4)
 #define CLK_HALT_CFPB_STATEA_REG		REG(0x2FCC)
 #define CLK_HALT_CFPB_STATEB_REG		REG(0x2FD0)
@@ -142,7 +143,9 @@
 #define USB_HSIC_XCVR_FS_CLK_NS_REG		REG(0x2928)
 #define USB_PHY0_RESET_REG			REG(0x2E20)
 #define PCIE_ALT_REF_CLK_NS_REG			REG(0x3860)
+#define PCIE_ACLK_CTL_REG			REG(0x22C0)
 #define PCIE_HCLK_CTL_REG			REG(0x22CC)
+#define PCIE_PCLK_CTL_REG			REG(0x22D0)
 #define GPLL1_MODE_REG				REG(0x3160)
 #define GPLL1_L_VAL_REG				REG(0x3164)
 #define GPLL1_M_VAL_REG				REG(0x3168)
@@ -1412,7 +1415,12 @@
 		.freq_hz = f, \
 		.src_clk = &s##_clk.c, \
 	}
-static struct clk_freq_tbl clk_tbl_prng[] = {
+static struct clk_freq_tbl clk_tbl_prng_32[] = {
+	F_PRNG(32000000, pll8),
+	F_END
+};
+
+static struct clk_freq_tbl clk_tbl_prng_64[] = {
 	F_PRNG(64000000, pll8),
 	F_END
 };
@@ -1426,12 +1434,12 @@
 		.halt_bit = 10,
 	},
 	.set_rate = set_rate_nop,
-	.freq_tbl = clk_tbl_prng,
+	.freq_tbl = clk_tbl_prng_32,
 	.current_freq = &rcg_dummy_freq,
 	.c = {
 		.dbg_name = "prng_clk",
 		.ops = &clk_ops_rcg,
-		VDD_DIG_FMAX_MAP2(LOW, 32000000, NOMINAL, 65000000),
+		VDD_DIG_FMAX_MAP2(LOW, 32000000, NOMINAL, 64000000),
 		CLK_INIT(prng_clk.c),
 	},
 };
@@ -1947,6 +1955,34 @@
 	},
 };
 
+static struct branch_clk pcie_phy_ref_clk = {
+	.b = {
+		.ctl_reg = PCIE_PCLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+		.halt_bit = 29,
+	},
+	.c = {
+		.dbg_name = "pcie_phy_ref_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(pcie_phy_ref_clk.c),
+	},
+};
+
+static struct branch_clk pcie_a_clk = {
+	.b = {
+		.ctl_reg = PCIE_ACLK_CTL_REG,
+		.en_mask = BIT(4),
+		.halt_reg = CLK_HALT_AFAB_SFAB_STATEA_REG,
+		.halt_bit = 13,
+	},
+	.c = {
+		.dbg_name = "pcie_a_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(pcie_a_clk.c),
+	},
+};
+
 static struct branch_clk dma_bam_p_clk = {
 	.b = {
 		.ctl_reg = DMA_BAM_HCLK_CTL,
@@ -4570,6 +4606,8 @@
 	{ TEST_PER_HS(0x26), &q6sw_clk },
 	{ TEST_PER_HS(0x27), &q6fw_clk },
 	{ TEST_PER_HS(0x2A), &adm0_clk.c },
+	{ TEST_PER_HS(0x2D), &pcie_phy_ref_clk.c },
+	{ TEST_PER_HS(0x32), &pcie_a_clk.c },
 	{ TEST_PER_HS(0x34), &ebi1_clk.c },
 	{ TEST_PER_HS(0x34), &ebi1_a_clk.c },
 	{ TEST_PER_HS(0x50), &usb_hsic_hsic_clk.c },
@@ -4927,8 +4965,6 @@
 	CLK_LOOKUP("src_clk",		usb_fs1_src_clk.c,	""),
 	CLK_LOOKUP("alt_core_clk",	usb_fs1_xcvr_clk.c,	""),
 	CLK_LOOKUP("sys_clk",		usb_fs1_sys_clk.c,	""),
-	CLK_LOOKUP("iface_clk",		ce1_p_clk.c,		""),
-	CLK_LOOKUP("core_clk",		ce1_core_clk.c,		""),
 	CLK_LOOKUP("ref_clk",		sata_phy_ref_clk.c,	""),
 	CLK_LOOKUP("cfg_clk",		sata_phy_cfg_clk.c,	""),
 	CLK_LOOKUP("iface_clk",		ce3_p_clk.c,		"qce.0"),
@@ -4957,6 +4993,8 @@
 	CLK_LOOKUP("iface_clk",		sdc3_p_clk.c,		"msm_sdcc.3"),
 	CLK_LOOKUP("iface_clk",		sdc4_p_clk.c,		"msm_sdcc.4"),
 	CLK_LOOKUP("iface_clk",		pcie_p_clk.c,		""),
+	CLK_LOOKUP("ref_clk",		pcie_phy_ref_clk.c,	""),
+	CLK_LOOKUP("bus_clk",		pcie_a_clk.c,		""),
 	CLK_LOOKUP("core_clk",		adm0_clk.c,		"msm_dmov"),
 	CLK_LOOKUP("iface_clk",		adm0_p_clk.c,		"msm_dmov"),
 	CLK_LOOKUP("iface_clk",		pmic_arb0_p_clk.c,	""),
@@ -5012,8 +5050,8 @@
 	CLK_LOOKUP("vcap_npl_clk",      vcap_npl_clk.c,         ""),
 	CLK_LOOKUP("vcap_npl_clk",      vcap_npl_clk.c,         "msm_vcap.0"),
 	CLK_LOOKUP("bus_clk",		ijpeg_axi_clk.c, "footswitch-8x60.3"),
-	CLK_LOOKUP("imem_clk",		imem_axi_clk.c,		"msm_gemini.0"),
-	CLK_LOOKUP("ijpeg_clk",         ijpeg_clk.c,    "msm_gemini.0"),
+	CLK_LOOKUP("mem_clk",		imem_axi_clk.c,	"msm_gemini.0"),
+	CLK_LOOKUP("core_clk",          ijpeg_clk.c,    "msm_gemini.0"),
 	CLK_LOOKUP("core_clk",		ijpeg_clk.c,	"footswitch-8x60.3"),
 	CLK_LOOKUP("core_clk",		jpegd_clk.c,		""),
 	CLK_LOOKUP("core_clk",		mdp_clk.c,		"mdp.0"),
@@ -5058,7 +5096,7 @@
 	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"footswitch-8x60.2"),
 	CLK_LOOKUP("master_iface_clk",	hdmi_m_p_clk.c,		"hdmi_msm.1"),
 	CLK_LOOKUP("slave_iface_clk",	hdmi_s_p_clk.c,		"hdmi_msm.1"),
-	CLK_LOOKUP("ijpeg_pclk",	ijpeg_p_clk.c,		"msm_gemini.0"),
+	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,		"msm_gemini.0"),
 	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"footswitch-8x60.3"),
 	CLK_LOOKUP("iface_clk",		jpegd_p_clk.c,		""),
 	CLK_LOOKUP("mem_iface_clk",	imem_p_clk.c,	"kgsl-3d0.0"),
@@ -5074,10 +5112,10 @@
 	CLK_LOOKUP("vpe_pclk",		vpe_p_clk.c,		"msm_vpe.0"),
 	CLK_LOOKUP("iface_clk",		vpe_p_clk.c,	"footswitch-8x60.9"),
 
-	CLK_LOOKUP("bit_clk",		mi2s_bit_clk.c,		"msm-dai-q6.6"),
-	CLK_LOOKUP("osr_clk",		mi2s_osr_clk.c,		"msm-dai-q6.6"),
-	CLK_LOOKUP("bit_clk",		mi2s_bit_clk.c,		"msm-dai-q6.7"),
-	CLK_LOOKUP("osr_clk",		mi2s_osr_clk.c,		"msm-dai-q6.7"),
+	CLK_LOOKUP("bit_clk",		mi2s_bit_clk.c,
+			    "msm-dai-q6-mi2s"),
+	CLK_LOOKUP("osr_clk",		mi2s_osr_clk.c,
+			    "msm-dai-q6-mi2s"),
 	CLK_LOOKUP("bit_clk",		codec_i2s_mic_bit_clk.c,
 			   "msm-dai-q6.1"),
 	CLK_LOOKUP("osr_clk",		codec_i2s_mic_osr_clk.c,
@@ -5321,8 +5359,8 @@
 	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"kgsl-3d0.0"),
 	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"footswitch-8x60.2"),
 	CLK_LOOKUP("bus_clk",		ijpeg_axi_clk.c, "footswitch-8x60.3"),
-	CLK_LOOKUP("imem_clk",		imem_axi_clk.c,		"msm_gemini.0"),
-	CLK_LOOKUP("ijpeg_clk",     ijpeg_clk.c,    "msm_gemini.0"),
+	CLK_LOOKUP("mem_clk",		imem_axi_clk.c,	"msm_gemini.0"),
+	CLK_LOOKUP("core_clk",          ijpeg_clk.c,    "msm_gemini.0"),
 	CLK_LOOKUP("core_clk",		ijpeg_clk.c,	"footswitch-8x60.3"),
 	CLK_LOOKUP("core_clk",		jpegd_clk.c,		""),
 	CLK_LOOKUP("core_clk",		mdp_clk.c,		"mdp.0"),
@@ -5374,7 +5412,7 @@
 	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"footswitch-8x60.2"),
 	CLK_LOOKUP("master_iface_clk",	hdmi_m_p_clk.c,	"hdmi_msm.1"),
 	CLK_LOOKUP("slave_iface_clk",	hdmi_s_p_clk.c,	"hdmi_msm.1"),
-	CLK_LOOKUP("ijpeg_pclk",	ijpeg_p_clk.c,		"msm_gemini.0"),
+	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"msm_gemini.0"),
 	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"footswitch-8x60.3"),
 	CLK_LOOKUP("iface_clk",		jpegd_p_clk.c,		""),
 	CLK_LOOKUP("mem_iface_clk",	imem_p_clk.c,	"kgsl-3d0.0"),
@@ -5390,10 +5428,10 @@
 	CLK_LOOKUP("iface_clk",		vfe_p_clk.c,	"footswitch-8x60.8"),
 	CLK_LOOKUP("vpe_pclk",		vpe_p_clk.c,		"msm_vpe.0"),
 	CLK_LOOKUP("iface_clk",		vpe_p_clk.c,	"footswitch-8x60.9"),
-	CLK_LOOKUP("bit_clk",		mi2s_bit_clk.c,		"msm-dai-q6.6"),
-	CLK_LOOKUP("osr_clk",		mi2s_osr_clk.c,		"msm-dai-q6.6"),
-	CLK_LOOKUP("bit_clk",		mi2s_bit_clk.c,		"msm-dai-q6.7"),
-	CLK_LOOKUP("osr_clk",		mi2s_osr_clk.c,		"msm-dai-q6.7"),
+	CLK_LOOKUP("bit_clk",		mi2s_bit_clk.c,
+			    "msm-dai-q6-mi2s"),
+	CLK_LOOKUP("osr_clk",		mi2s_osr_clk.c,
+			    "msm-dai-q6-mi2s"),
 	CLK_LOOKUP("bit_clk",		codec_i2s_mic_bit_clk.c,
 			   "msm-dai-q6.1"),
 	CLK_LOOKUP("osr_clk",		codec_i2s_mic_osr_clk.c,
@@ -5575,7 +5613,7 @@
 	CLK_LOOKUP("mem_clk",		rpm_msg_ram_p_clk.c,	""),
 	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-001a"),
 	CLK_LOOKUP("cam_clk",		cam1_clk.c,	"4-006c"),
-	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-0048"),
+	CLK_LOOKUP("cam_clk",		cam1_clk.c,	"4-0048"),
 	CLK_LOOKUP("cam_clk",		cam2_clk.c,		NULL),
 	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-0020"),
 	CLK_LOOKUP("csi_src_clk",	csi0_src_clk.c,		"msm_csid.0"),
@@ -5612,8 +5650,8 @@
 	CLK_LOOKUP("bus_clk",
 			    gfx3d_axi_clk_8930.c, "footswitch-8x60.2"),
 	CLK_LOOKUP("bus_clk",		ijpeg_axi_clk.c, "footswitch-8x60.3"),
-	CLK_LOOKUP("imem_clk",		imem_axi_clk.c,		"msm_gemini.0"),
-	CLK_LOOKUP("ijpeg_clk",         ijpeg_clk.c,    "msm_gemini.0"),
+	CLK_LOOKUP("mem_clk",		imem_axi_clk.c, "msm_gemini.0"),
+	CLK_LOOKUP("core_clk",          ijpeg_clk.c,    "msm_gemini.0"),
 	CLK_LOOKUP("core_clk",		ijpeg_clk.c,	"footswitch-8x60.3"),
 	CLK_LOOKUP("core_clk",		mdp_clk.c,		"mdp.0"),
 	CLK_LOOKUP("core_clk",		mdp_clk.c,	"footswitch-8x60.4"),
@@ -5656,7 +5694,7 @@
 	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"footswitch-8x60.2"),
 	CLK_LOOKUP("master_iface_clk",	hdmi_m_p_clk.c,	"hdmi_msm.1"),
 	CLK_LOOKUP("slave_iface_clk",	hdmi_s_p_clk.c,	"hdmi_msm.1"),
-	CLK_LOOKUP("ijpeg_pclk",	ijpeg_p_clk.c,		"msm_gemini.0"),
+	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"msm_gemini.0"),
 	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"footswitch-8x60.3"),
 	CLK_LOOKUP("mem_iface_clk",	imem_p_clk.c,	"kgsl-3d0.0"),
 	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,		"mdp.0"),
@@ -5744,32 +5782,82 @@
 	writel_relaxed(regval, reg);
 }
 
-static void __init set_fsm_mode(void __iomem *mode_reg)
-{
-	u32 regval = readl_relaxed(mode_reg);
+static struct pll_config_regs pll4_regs __initdata = {
+	.l_reg = LCC_PLL0_L_VAL_REG,
+	.m_reg = LCC_PLL0_M_VAL_REG,
+	.n_reg = LCC_PLL0_N_VAL_REG,
+	.config_reg = LCC_PLL0_CONFIG_REG,
+	.mode_reg = LCC_PLL0_MODE_REG,
+};
 
-	/*De-assert reset to FSM */
-	regval &= ~BIT(21);
-	writel_relaxed(regval, mode_reg);
+static struct pll_config pll4_config __initdata = {
+	.l = 0xE,
+	.m = 0x27A,
+	.n = 0x465,
+	.vco_val = 0x0,
+	.vco_mask = BM(17, 16),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BIT(19),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(21, 20),
+	.mn_ena_val = BIT(22),
+	.mn_ena_mask = BIT(22),
+	.main_output_val = BIT(23),
+	.main_output_mask = BIT(23),
+};
 
-	/* Program bias count */
-	regval &= ~BM(19, 14);
-	regval |= BVAL(19, 14, 0x1);
-	writel_relaxed(regval, mode_reg);
+static struct pll_config_regs pll15_regs __initdata = {
+	.l_reg = MM_PLL3_L_VAL_REG,
+	.m_reg = MM_PLL3_M_VAL_REG,
+	.n_reg = MM_PLL3_N_VAL_REG,
+	.config_reg = MM_PLL3_CONFIG_REG,
+	.mode_reg = MM_PLL3_MODE_REG,
+};
 
-	/* Program lock count */
-	regval &= ~BM(13, 8);
-	regval |= BVAL(13, 8, 0x8);
-	writel_relaxed(regval, mode_reg);
+static struct pll_config pll15_config __initdata = {
+	.l = (0x24 | BVAL(31, 7, 0x620)),
+	.m = 0x1,
+	.n = 0x9,
+	.vco_val = BVAL(17, 16, 0x2),
+	.vco_mask = BM(17, 16),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BIT(19),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(21, 20),
+	.mn_ena_val = BIT(22),
+	.mn_ena_mask = BIT(22),
+	.main_output_val = BIT(23),
+	.main_output_mask = BIT(23),
+};
 
-	/*Enable PLL FSM voting */
-	regval |= BIT(20);
-	writel_relaxed(regval, mode_reg);
-}
+static struct pll_config_regs pll14_regs __initdata = {
+	.l_reg = BB_PLL14_L_VAL_REG,
+	.m_reg = BB_PLL14_M_VAL_REG,
+	.n_reg = BB_PLL14_N_VAL_REG,
+	.config_reg = BB_PLL14_CONFIG_REG,
+	.mode_reg = BB_PLL14_MODE_REG,
+};
+
+static struct pll_config pll14_config __initdata = {
+	.l = (0x11 | BVAL(31, 7, 0x620)),
+	.m = 0x7,
+	.n = 0x9,
+	.vco_val = 0x0,
+	.vco_mask = BM(17, 16),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BIT(19),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(21, 20),
+	.mn_ena_val = BIT(22),
+	.mn_ena_mask = BIT(22),
+	.main_output_val = BIT(23),
+	.main_output_mask = BIT(23),
+};
 
 static void __init reg_init(void)
 {
 	void __iomem *imem_reg;
+
 	/* Deassert MM SW_RESET_ALL signal. */
 	writel_relaxed(0, SW_RESET_ALL_REG);
 
@@ -5910,40 +5998,18 @@
 
 		/* Check if PLL14 is active */
 		is_pll_enabled = readl_relaxed(BB_PLL14_STATUS_REG) & BIT(16);
-		if (!is_pll_enabled) {
+		if (!is_pll_enabled)
 			/* Ref clk = 27MHz and program pll14 to 480MHz */
-			writel_relaxed(0x00031011, BB_PLL14_L_VAL_REG);
-			writel_relaxed(0x7,  BB_PLL14_M_VAL_REG);
-			writel_relaxed(0x9,  BB_PLL14_N_VAL_REG);
-
-			/*
-			 * Enable the main output and the MN accumulator
-			 * Set pre-divider and post-divider values to 1 and 1
-			 */
-			writel_relaxed(0x00C00000, BB_PLL14_CONFIG_REG);
-
-			set_fsm_mode(BB_PLL14_MODE_REG);
-		}
+			configure_pll(&pll14_config, &pll14_regs, 1);
 
 		/* Program PLL15 to 975MHz with ref clk = 27MHz */
-		writel_relaxed(0x31024, MM_PLL3_L_VAL_REG);
-		writel_relaxed(0x1,	MM_PLL3_M_VAL_REG);
-		writel_relaxed(0x9,	MM_PLL3_N_VAL_REG);
-
-		writel_relaxed(0xC20000, MM_PLL3_CONFIG_REG);
+		configure_pll(&pll15_config, &pll15_regs, 0);
 
 		/* Check if PLL4 is active */
 		is_pll_enabled = readl_relaxed(LCC_PLL0_STATUS_REG) & BIT(16);
-		if (!is_pll_enabled) {
+		if (!is_pll_enabled)
 			/* Ref clk = 27MHz and program pll4 to 393.2160MHz */
-			writel_relaxed(0xE,   LCC_PLL0_L_VAL_REG);
-			writel_relaxed(0x27A, LCC_PLL0_M_VAL_REG);
-			writel_relaxed(0x465, LCC_PLL0_N_VAL_REG);
-
-			writel_relaxed(0xC00000, LCC_PLL0_CONFIG_REG);
-
-			set_fsm_mode(LCC_PLL0_MODE_REG);
-		}
+			configure_pll(&pll4_config, &pll4_regs, 1);
 
 		/* Enable PLL4 source on the LPASS Primary PLL Mux */
 		writel_relaxed(0x1, LCC_PRI_PLL_CLK_CTL_REG);
@@ -5958,12 +6024,12 @@
 	 * only enable PLL main output.
 	 */
 	if (cpu_is_msm8930()) {
-		writel_relaxed(0x30021, MM_PLL3_L_VAL_REG);
-		writel_relaxed(0x1,	MM_PLL3_M_VAL_REG);
-		writel_relaxed(0x3,	MM_PLL3_N_VAL_REG);
-
-		writel_relaxed(0xC20000, MM_PLL3_CONFIG_REG);
-		writel_relaxed(0,	 MM_PLL3_TEST_CTL_REG);
+		pll15_config.l = 0x21 | BVAL(31, 7, 0x600);
+		pll15_config.m = 0x1;
+		pll15_config.n = 0x3;
+		configure_pll(&pll15_config, &pll15_regs, 0);
+		/* Disable AUX and BIST outputs */
+		writel_relaxed(0, MM_PLL3_TEST_CTL_REG);
 	}
 }
 
@@ -6010,6 +6076,8 @@
 		pll15_clk.c.rate = 900000000;
 		gmem_axi_clk.c.depends = &gfx3d_axi_clk_8930.c;
 	}
+	if ((readl_relaxed(PRNG_CLK_NS_REG) & 0x7F) == 0x2B)
+		prng_clk.freq_tbl = clk_tbl_prng_64;
 
 	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
 
@@ -6034,7 +6102,7 @@
 
 	/* Initialize rates for clocks that only support one. */
 	clk_set_rate(&pdm_clk.c, 27000000);
-	clk_set_rate(&prng_clk.c, 64000000);
+	clk_set_rate(&prng_clk.c, prng_clk.freq_tbl->freq_hz);
 	clk_set_rate(&mdp_vsync_clk.c, 27000000);
 	clk_set_rate(&tsif_ref_clk.c, 105000);
 	clk_set_rate(&tssc_clk.c, 27000000);
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 26ccaa3..8d2b37a 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -75,6 +75,7 @@
 #define PLLTEST_PAD_CFG_REG			REG(0x2FA4)
 #define PMEM_ACLK_CTL_REG			REG(0x25A0)
 #define PPSS_HCLK_CTL_REG			REG(0x2580)
+#define PRNG_CLK_NS_REG				REG(0x2E80)
 #define RINGOSC_NS_REG				REG(0x2DC0)
 #define RINGOSC_STATUS_REG			REG(0x2DCC)
 #define RINGOSC_TCXO_CTL_REG			REG(0x2DC4)
@@ -1139,7 +1140,12 @@
 		.freq_hz = f, \
 		.src_clk = &s##_clk.c, \
 	}
-static struct clk_freq_tbl clk_tbl_prng[] = {
+static struct clk_freq_tbl clk_tbl_prng_32[] = {
+	F_PRNG(32000000, pll8),
+	F_END
+};
+
+static struct clk_freq_tbl clk_tbl_prng_64[] = {
 	F_PRNG(64000000, pll8),
 	F_END
 };
@@ -1153,12 +1159,12 @@
 		.halt_bit = 10,
 	},
 	.set_rate = set_rate_nop,
-	.freq_tbl = clk_tbl_prng,
+	.freq_tbl = clk_tbl_prng_32,
 	.current_freq = &rcg_dummy_freq,
 	.c = {
 		.dbg_name = "prng_clk",
 		.ops = &clk_ops_rcg,
-		VDD_DIG_FMAX_MAP2(LOW, 32000000, NOMINAL, 65000000),
+		VDD_DIG_FMAX_MAP2(LOW, 32000000, NOMINAL, 64000000),
 		CLK_INIT(prng_clk.c),
 	},
 };
@@ -3585,7 +3591,7 @@
 	CLK_LOOKUP("core_clk",		gfx2d1_clk.c,	"footswitch-8x60.1"),
 	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"kgsl-3d0.0"),
 	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"footswitch-8x60.2"),
-	CLK_LOOKUP("ijpeg_clk",		ijpeg_clk.c,		"msm_gemini.0"),
+	CLK_LOOKUP("core_clk",		ijpeg_clk.c,	"msm_gemini.0"),
 	CLK_LOOKUP("core_clk",		ijpeg_clk.c,	"footswitch-8x60.3"),
 	CLK_LOOKUP("core_clk",		jpegd_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		mdp_clk.c,		"mdp.0"),
@@ -3638,7 +3644,7 @@
 	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"footswitch-8x60.2"),
 	CLK_LOOKUP("master_iface_clk",	hdmi_m_p_clk.c,	"hdmi_msm.1"),
 	CLK_LOOKUP("slave_iface_clk",	hdmi_s_p_clk.c,	"hdmi_msm.1"),
-	CLK_LOOKUP("ijpeg_pclk",	ijpeg_p_clk.c,		"msm_gemini.0"),
+	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"msm_gemini.0"),
 	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"footswitch-8x60.3"),
 	CLK_LOOKUP("iface_clk",		jpegd_p_clk.c,		NULL),
 	CLK_LOOKUP("mem_iface_clk",	imem_p_clk.c,	"kgsl-3d0.0"),
@@ -3788,6 +3794,9 @@
 	/* Set the dsi_byte_clk src to the DSI PHY PLL,
 	 * dsi_esc_clk to PXO/2, and the hdmi_app_clk src to PXO */
 	rmwreg(0x400001, MISC_CC2_REG, 0x424003);
+
+	if ((readl_relaxed(PRNG_CLK_NS_REG) & 0x7F) == 0x2B)
+		prng_clk.freq_tbl = clk_tbl_prng_64;
 }
 
 static void __init msm8660_clock_post_init(void)
@@ -3805,7 +3814,7 @@
 
 	/* Initialize rates for clocks that only support one. */
 	clk_set_rate(&pdm_clk.c, 27000000);
-	clk_set_rate(&prng_clk.c, 64000000);
+	clk_set_rate(&prng_clk.c, prng_clk.freq_tbl->freq_hz);
 	clk_set_rate(&mdp_vsync_clk.c, 27000000);
 	clk_set_rate(&tsif_ref_clk.c, 105000);
 	clk_set_rate(&tssc_clk.c, 27000000);
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 12d37ae..1fd9b4d 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -1689,28 +1689,51 @@
 	CLK_LOOKUP("q6_func_clk",	q6_func_clk, NULL),
 };
 
-static void set_fsm_mode(void __iomem *mode_reg)
-{
-	u32 regval = readl_relaxed(mode_reg);
+static struct pll_config_regs pll0_regs __initdata = {
+	.l_reg = BB_PLL0_L_VAL_REG,
+	.m_reg = BB_PLL0_M_VAL_REG,
+	.n_reg = BB_PLL0_N_VAL_REG,
+	.config_reg = BB_PLL0_CONFIG_REG,
+	.mode_reg = BB_PLL0_MODE_REG,
+};
 
-	/* De-assert reset to FSM */
-	regval &= ~BIT(21);
-	writel_relaxed(regval, mode_reg);
+static struct pll_config pll0_config __initdata = {
+	.l = 0xE,
+	.m = 0x3,
+	.n = 0x8,
+	.vco_val = 0x0,
+	.vco_mask = BM(17, 16),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BIT(19),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(21, 20),
+	.mn_ena_val = BIT(22),
+	.mn_ena_mask = BIT(22),
+	.main_output_val = BIT(23),
+	.main_output_mask = BIT(23),
+};
 
-	/* Program bias count */
-	regval &= ~BM(19, 14);
-	regval |= BVAL(19, 14, 0x1);
-	writel_relaxed(regval, mode_reg);
+static struct pll_config_regs pll14_regs __initdata = {
+	.l_reg = BB_PLL14_L_VAL_REG,
+	.m_reg = BB_PLL14_M_VAL_REG,
+	.n_reg = BB_PLL14_N_VAL_REG,
+	.config_reg = BB_PLL14_CONFIG_REG,
+	.mode_reg = BB_PLL14_MODE_REG,
+};
 
-	/* Program lock count */
-	regval &= ~BM(13, 8);
-	regval |= BVAL(13, 8, 0x8);
-	writel_relaxed(regval, mode_reg);
-
-	/* Enable PLL FSM voting */
-	regval |= BIT(20);
-	writel_relaxed(regval, mode_reg);
-}
+static struct pll_config pll14_config __initdata = {
+	.l = 0x19,
+	.m = 0x0,
+	.n = 0x1,
+	.vco_val = 0x0,
+	.vco_mask = BM(17, 16),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BIT(19),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(21, 20),
+	.main_output_val = BIT(23),
+	.main_output_mask = BIT(23),
+};
 
 /*
  * Miscellaneous clock register initializations
@@ -1731,57 +1754,20 @@
 	is_pll_enabled = readl_relaxed(BB_PLL0_STATUS_REG) & BIT(16);
 
 	if (!is_pll_enabled) {
-		writel_relaxed(0xE, BB_PLL0_L_VAL_REG);
-		writel_relaxed(0x3, BB_PLL0_M_VAL_REG);
-		writel_relaxed(0x8, BB_PLL0_N_VAL_REG);
-
-		regval = readl_relaxed(BB_PLL0_CONFIG_REG);
-
-		/* Enable the main output and the MN accumulator  */
-		regval |= BIT(23) | BIT(22);
-
-		/* Set pre-divider and post-divider values to 1 and 1 */
-		regval &= ~BIT(19);
-		regval &= ~BM(21, 20);
-
-		/* Set VCO frequency */
-		regval &= ~BM(17, 16);
-
-		writel_relaxed(regval, BB_PLL0_CONFIG_REG);
-
 		/* Enable AUX output */
 		regval = readl_relaxed(BB_PLL0_TEST_CTL_REG);
 		regval |= BIT(12);
 		writel_relaxed(regval, BB_PLL0_TEST_CTL_REG);
 
-		set_fsm_mode(BB_PLL0_MODE_REG);
+		configure_pll(&pll0_config, &pll0_regs, 1);
 	}
 
 	/* Check if PLL14 is enabled in FSM mode */
 	is_pll_enabled  = readl_relaxed(BB_PLL14_STATUS_REG) & BIT(16);
 
-	if (!is_pll_enabled) {
-		writel_relaxed(0x19, BB_PLL14_L_VAL_REG);
-		writel_relaxed(0x0, BB_PLL14_M_VAL_REG);
-		writel_relaxed(0x1, BB_PLL14_N_VAL_REG);
-
-		regval = readl_relaxed(BB_PLL14_CONFIG_REG);
-
-		/* Enable main output and the MN accumulator */
-		regval |= BIT(23) | BIT(22);
-
-		/* Set pre-divider and post-divider values to 1 and 1 */
-		regval &= ~BIT(19);
-		regval &= ~BM(21, 20);
-
-		/* Set VCO frequency */
-		regval &= ~BM(17, 16);
-
-		writel_relaxed(regval, BB_PLL14_CONFIG_REG);
-
-		set_fsm_mode(BB_PLL14_MODE_REG);
-
-	} else if (!(readl_relaxed(BB_PLL14_MODE_REG) & BIT(20)))
+	if (!is_pll_enabled)
+		configure_pll(&pll14_config, &pll14_regs, 1);
+	else if (!(readl_relaxed(BB_PLL14_MODE_REG) & BIT(20)))
 		WARN(1, "PLL14 enabled in non-FSM mode!\n");
 
 	/* Detect PLL9 rate and fixup structure accordingly */
diff --git a/arch/arm/mach-msm/clock-copper.c b/arch/arm/mach-msm/clock-copper.c
new file mode 100644
index 0000000..03667d7
--- /dev/null
+++ b/arch/arm/mach-msm/clock-copper.c
@@ -0,0 +1,5186 @@
+/* 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/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <mach/clk.h>
+
+#include "clock-local2.h"
+#include "clock-pll.h"
+
+enum {
+	GCC_BASE,
+	MMSS_BASE,
+	LPASS_BASE,
+	MSS_BASE,
+	N_BASES,
+};
+
+static void __iomem *virt_bases[N_BASES];
+
+#define GCC_REG_BASE(x) (void __iomem *)(virt_bases[GCC_BASE] + (x))
+#define MMSS_REG_BASE(x) (void __iomem *)(virt_bases[MMSS_BASE] + (x))
+#define LPASS_REG_BASE(x) (void __iomem *)(virt_bases[LPASS_BASE] + (x))
+#define MSS_REG_BASE(x) (void __iomem *)(virt_bases[MSS_BASE] + (x))
+
+#define GPLL0_MODE_REG                 0x0000
+#define GPLL0_L_REG                    0x0004
+#define GPLL0_M_REG                    0x0008
+#define GPLL0_N_REG                    0x000C
+#define GPLL0_USER_CTL_REG             0x0010
+#define GPLL0_CONFIG_CTL_REG           0x0014
+#define GPLL0_TEST_CTL_REG             0x0018
+#define GPLL0_STATUS_REG               0x001C
+
+#define GPLL1_MODE_REG                 0x0040
+#define GPLL1_L_REG                    0x0044
+#define GPLL1_M_REG                    0x0048
+#define GPLL1_N_REG                    0x004C
+#define GPLL1_USER_CTL_REG             0x0050
+#define GPLL1_CONFIG_CTL_REG           0x0054
+#define GPLL1_TEST_CTL_REG             0x0058
+#define GPLL1_STATUS_REG               0x005C
+
+#define MMPLL0_MODE_REG                0x0000
+#define MMPLL0_L_REG                   0x0004
+#define MMPLL0_M_REG                   0x0008
+#define MMPLL0_N_REG                   0x000C
+#define MMPLL0_USER_CTL_REG            0x0010
+#define MMPLL0_CONFIG_CTL_REG          0x0014
+#define MMPLL0_TEST_CTL_REG            0x0018
+#define MMPLL0_STATUS_REG              0x001C
+
+#define MMPLL1_MODE_REG                0x0040
+#define MMPLL1_L_REG                   0x0044
+#define MMPLL1_M_REG                   0x0048
+#define MMPLL1_N_REG                   0x004C
+#define MMPLL1_USER_CTL_REG            0x0050
+#define MMPLL1_CONFIG_CTL_REG          0x0054
+#define MMPLL1_TEST_CTL_REG            0x0058
+#define MMPLL1_STATUS_REG              0x005C
+
+#define MMPLL3_MODE_REG                0x0080
+#define MMPLL3_L_REG                   0x0084
+#define MMPLL3_M_REG                   0x0088
+#define MMPLL3_N_REG                   0x008C
+#define MMPLL3_USER_CTL_REG            0x0090
+#define MMPLL3_CONFIG_CTL_REG          0x0094
+#define MMPLL3_TEST_CTL_REG            0x0098
+#define MMPLL3_STATUS_REG              0x009C
+
+#define LPAPLL_MODE_REG                0x0000
+#define LPAPLL_L_REG                   0x0004
+#define LPAPLL_M_REG                   0x0008
+#define LPAPLL_N_REG                   0x000C
+#define LPAPLL_USER_CTL_REG            0x0010
+#define LPAPLL_CONFIG_CTL_REG          0x0014
+#define LPAPLL_TEST_CTL_REG            0x0018
+#define LPAPLL_STATUS_REG              0x001C
+
+#define GCC_DEBUG_CLK_CTL_REG          0x1880
+#define CLOCK_FRQ_MEASURE_CTL_REG      0x1884
+#define CLOCK_FRQ_MEASURE_STATUS_REG   0x1888
+#define GCC_XO_DIV4_CBCR_REG           0x10C8
+#define APCS_GPLL_ENA_VOTE_REG         0x1480
+#define MMSS_PLL_VOTE_APCS_REG         0x0100
+#define MMSS_DEBUG_CLK_CTL_REG         0x0900
+#define LPASS_DEBUG_CLK_CTL_REG        0x29000
+#define LPASS_LPA_PLL_VOTE_APPS_REG    0x2000
+#define MSS_DEBUG_CLK_CTL_REG          0x0078
+
+#define USB30_MASTER_CMD_RCGR          0x03D4
+#define USB30_MOCK_UTMI_CMD_RCGR       0x03E8
+#define USB_HSIC_SYSTEM_CMD_RCGR       0x041C
+#define USB_HSIC_CMD_RCGR              0x0440
+#define USB_HSIC_IO_CAL_CMD_RCGR       0x0458
+#define USB_HS_SYSTEM_CMD_RCGR         0x0490
+#define SDCC1_APPS_CMD_RCGR            0x04D0
+#define SDCC2_APPS_CMD_RCGR            0x0510
+#define SDCC3_APPS_CMD_RCGR            0x0550
+#define SDCC4_APPS_CMD_RCGR            0x0590
+#define BLSP1_QUP1_SPI_APPS_CMD_RCGR   0x064C
+#define BLSP1_UART1_APPS_CMD_RCGR      0x068C
+#define BLSP1_QUP2_SPI_APPS_CMD_RCGR   0x06CC
+#define BLSP1_UART2_APPS_CMD_RCGR      0x070C
+#define BLSP1_QUP3_SPI_APPS_CMD_RCGR   0x074C
+#define BLSP1_UART3_APPS_CMD_RCGR      0x078C
+#define BLSP1_QUP4_SPI_APPS_CMD_RCGR   0x07CC
+#define BLSP1_UART4_APPS_CMD_RCGR      0x080C
+#define BLSP1_QUP5_SPI_APPS_CMD_RCGR   0x084C
+#define BLSP1_UART5_APPS_CMD_RCGR      0x088C
+#define BLSP1_QUP6_SPI_APPS_CMD_RCGR   0x08CC
+#define BLSP1_UART6_APPS_CMD_RCGR      0x090C
+#define BLSP2_QUP1_SPI_APPS_CMD_RCGR   0x098C
+#define BLSP2_UART1_APPS_CMD_RCGR      0x09CC
+#define BLSP2_QUP2_SPI_APPS_CMD_RCGR   0x0A0C
+#define BLSP2_UART2_APPS_CMD_RCGR      0x0A4C
+#define BLSP2_QUP3_SPI_APPS_CMD_RCGR   0x0A8C
+#define BLSP2_UART3_APPS_CMD_RCGR      0x0ACC
+#define BLSP2_QUP4_SPI_APPS_CMD_RCGR   0x0B0C
+#define BLSP2_UART4_APPS_CMD_RCGR      0x0B4C
+#define BLSP2_QUP5_SPI_APPS_CMD_RCGR   0x0B8C
+#define BLSP2_UART5_APPS_CMD_RCGR      0x0BCC
+#define BLSP2_QUP6_SPI_APPS_CMD_RCGR   0x0C0C
+#define BLSP2_UART6_APPS_CMD_RCGR      0x0C4C
+#define PDM2_CMD_RCGR                  0x0CD0
+#define TSIF_REF_CMD_RCGR              0x0D90
+#define CE1_CMD_RCGR                   0x1050
+#define CE2_CMD_RCGR                   0x1090
+#define GP1_CMD_RCGR                   0x1904
+#define GP2_CMD_RCGR                   0x1944
+#define GP3_CMD_RCGR                   0x1984
+#define LPAIF_SPKR_CMD_RCGR            0xA000
+#define LPAIF_PRI_CMD_RCGR             0xB000
+#define LPAIF_SEC_CMD_RCGR             0xC000
+#define LPAIF_TER_CMD_RCGR             0xD000
+#define LPAIF_QUAD_CMD_RCGR            0xE000
+#define LPAIF_PCM0_CMD_RCGR            0xF000
+#define LPAIF_PCM1_CMD_RCGR            0x10000
+#define RESAMPLER_CMD_RCGR             0x11000
+#define SLIMBUS_CMD_RCGR               0x12000
+#define LPAIF_PCMOE_CMD_RCGR           0x13000
+#define AHBFABRIC_CMD_RCGR             0x18000
+#define VCODEC0_CMD_RCGR               0x1000
+#define PCLK0_CMD_RCGR                 0x2000
+#define PCLK1_CMD_RCGR                 0x2020
+#define MDP_CMD_RCGR                   0x2040
+#define EXTPCLK_CMD_RCGR               0x2060
+#define VSYNC_CMD_RCGR                 0x2080
+#define EDPPIXEL_CMD_RCGR              0x20A0
+#define EDPLINK_CMD_RCGR               0x20C0
+#define EDPAUX_CMD_RCGR                0x20E0
+#define HDMI_CMD_RCGR                  0x2100
+#define BYTE0_CMD_RCGR                 0x2120
+#define BYTE1_CMD_RCGR                 0x2140
+#define ESC0_CMD_RCGR                  0x2160
+#define ESC1_CMD_RCGR                  0x2180
+#define CSI0PHYTIMER_CMD_RCGR          0x3000
+#define CSI1PHYTIMER_CMD_RCGR          0x3030
+#define CSI2PHYTIMER_CMD_RCGR          0x3060
+#define CSI0_CMD_RCGR                  0x3090
+#define CSI1_CMD_RCGR                  0x3100
+#define CSI2_CMD_RCGR                  0x3160
+#define CSI3_CMD_RCGR                  0x31C0
+#define CCI_CMD_RCGR                   0x3300
+#define MCLK0_CMD_RCGR                 0x3360
+#define MCLK1_CMD_RCGR                 0x3390
+#define MCLK2_CMD_RCGR                 0x33C0
+#define MCLK3_CMD_RCGR                 0x33F0
+#define MMSS_GP0_CMD_RCGR              0x3420
+#define MMSS_GP1_CMD_RCGR              0x3450
+#define JPEG0_CMD_RCGR                 0x3500
+#define JPEG1_CMD_RCGR                 0x3520
+#define JPEG2_CMD_RCGR                 0x3540
+#define VFE0_CMD_RCGR                  0x3600
+#define VFE1_CMD_RCGR                  0x3620
+#define CPP_CMD_RCGR                   0x3640
+#define GFX3D_CMD_RCGR                 0x4000
+#define RBCPR_CMD_RCGR                 0x4060
+#define AHB_CMD_RCGR                   0x5000
+#define AXI_CMD_RCGR                   0x5040
+#define OCMEMNOC_CMD_RCGR              0x5090
+
+#define MMSS_BCR                  0x0240
+#define USB_30_BCR                0x03C0
+#define USB3_PHY_BCR              0x03FC
+#define USB_HS_HSIC_BCR           0x0400
+#define USB_HS_BCR                0x0480
+#define SDCC1_BCR                 0x04C0
+#define SDCC2_BCR                 0x0500
+#define SDCC3_BCR                 0x0540
+#define SDCC4_BCR                 0x0580
+#define BLSP1_BCR                 0x05C0
+#define BLSP1_QUP1_BCR            0x0640
+#define BLSP1_UART1_BCR           0x0680
+#define BLSP1_QUP2_BCR            0x06C0
+#define BLSP1_UART2_BCR           0x0700
+#define BLSP1_QUP3_BCR            0x0740
+#define BLSP1_UART3_BCR           0x0780
+#define BLSP1_QUP4_BCR            0x07C0
+#define BLSP1_UART4_BCR           0x0800
+#define BLSP1_QUP5_BCR            0x0840
+#define BLSP1_UART5_BCR           0x0880
+#define BLSP1_QUP6_BCR            0x08C0
+#define BLSP1_UART6_BCR           0x0900
+#define BLSP2_BCR                 0x0940
+#define BLSP2_QUP1_BCR            0x0980
+#define BLSP2_UART1_BCR           0x09C0
+#define BLSP2_QUP2_BCR            0x0A00
+#define BLSP2_UART2_BCR           0x0A40
+#define BLSP2_QUP3_BCR            0x0A80
+#define BLSP2_UART3_BCR           0x0AC0
+#define BLSP2_QUP4_BCR            0x0B00
+#define BLSP2_UART4_BCR           0x0B40
+#define BLSP2_QUP5_BCR            0x0B80
+#define BLSP2_UART5_BCR           0x0BC0
+#define BLSP2_QUP6_BCR            0x0C00
+#define BLSP2_UART6_BCR           0x0C40
+#define BOOT_ROM_BCR              0x0E00
+#define PDM_BCR                   0x0CC0
+#define PRNG_BCR                  0x0D00
+#define BAM_DMA_BCR               0x0D40
+#define TSIF_BCR                  0x0D80
+#define CE1_BCR                   0x1040
+#define CE2_BCR                   0x1080
+#define AUDIO_CORE_BCR            0x4000
+#define VENUS0_BCR                0x1020
+#define MDSS_BCR                  0x2300
+#define CAMSS_PHY0_BCR            0x3020
+#define CAMSS_PHY1_BCR            0x3050
+#define CAMSS_PHY2_BCR            0x3080
+#define CAMSS_CSI0_BCR            0x30B0
+#define CAMSS_CSI0PHY_BCR         0x30C0
+#define CAMSS_CSI0RDI_BCR         0x30D0
+#define CAMSS_CSI0PIX_BCR         0x30E0
+#define CAMSS_CSI1_BCR            0x3120
+#define CAMSS_CSI1PHY_BCR         0x3130
+#define CAMSS_CSI1RDI_BCR         0x3140
+#define CAMSS_CSI1PIX_BCR         0x3150
+#define CAMSS_CSI2_BCR            0x3180
+#define CAMSS_CSI2PHY_BCR         0x3190
+#define CAMSS_CSI2RDI_BCR         0x31A0
+#define CAMSS_CSI2PIX_BCR         0x31B0
+#define CAMSS_CSI3_BCR            0x31E0
+#define CAMSS_CSI3PHY_BCR         0x31F0
+#define CAMSS_CSI3RDI_BCR         0x3200
+#define CAMSS_CSI3PIX_BCR         0x3210
+#define CAMSS_ISPIF_BCR           0x3220
+#define CAMSS_CCI_BCR             0x3340
+#define CAMSS_MCLK0_BCR           0x3380
+#define CAMSS_MCLK1_BCR           0x33B0
+#define CAMSS_MCLK2_BCR           0x33E0
+#define CAMSS_MCLK3_BCR           0x3410
+#define CAMSS_GP0_BCR             0x3440
+#define CAMSS_GP1_BCR             0x3470
+#define CAMSS_TOP_BCR             0x3480
+#define CAMSS_MICRO_BCR           0x3490
+#define CAMSS_JPEG_BCR            0x35A0
+#define CAMSS_VFE_BCR             0x36A0
+#define CAMSS_CSI_VFE0_BCR        0x3700
+#define CAMSS_CSI_VFE1_BCR        0x3710
+#define OCMEMNOC_BCR              0x50B0
+#define MMSSNOCAHB_BCR            0x5020
+#define MMSSNOCAXI_BCR            0x5060
+#define OXILI_GFX3D_CBCR          0x4028
+#define OXILICX_AHB_CBCR          0x403C
+#define OXILICX_AXI_CBCR          0x4038
+#define OXILI_BCR                 0x4020
+#define OXILICX_BCR               0x4030
+#define LPASS_Q6SS_BCR            0x6000
+#define MSS_Q6SS_BCR              0x1068
+
+#define OCMEM_SYS_NOC_AXI_CBCR                   0x0244
+#define OCMEM_NOC_CFG_AHB_CBCR                   0x0248
+#define MMSS_NOC_CFG_AHB_CBCR                    0x024C
+
+#define USB30_MASTER_CBCR                        0x03C8
+#define USB30_MOCK_UTMI_CBCR                     0x03D0
+#define USB_HSIC_AHB_CBCR                        0x0408
+#define USB_HSIC_SYSTEM_CBCR                     0x040C
+#define USB_HSIC_CBCR                            0x0410
+#define USB_HSIC_IO_CAL_CBCR                     0x0414
+#define USB_HS_SYSTEM_CBCR                       0x0484
+#define USB_HS_AHB_CBCR                          0x0488
+#define SDCC1_APPS_CBCR                          0x04C4
+#define SDCC1_AHB_CBCR                           0x04C8
+#define SDCC2_APPS_CBCR                          0x0504
+#define SDCC2_AHB_CBCR                           0x0508
+#define SDCC3_APPS_CBCR                          0x0544
+#define SDCC3_AHB_CBCR                           0x0548
+#define SDCC4_APPS_CBCR                          0x0584
+#define SDCC4_AHB_CBCR                           0x0588
+#define BLSP1_AHB_CBCR                           0x05C4
+#define BLSP1_QUP1_SPI_APPS_CBCR                 0x0644
+#define BLSP1_QUP1_I2C_APPS_CBCR                 0x0648
+#define BLSP1_UART1_APPS_CBCR                    0x0684
+#define BLSP1_UART1_SIM_CBCR                     0x0688
+#define BLSP1_QUP2_SPI_APPS_CBCR                 0x06C4
+#define BLSP1_QUP2_I2C_APPS_CBCR                 0x06C8
+#define BLSP1_UART2_APPS_CBCR                    0x0704
+#define BLSP1_UART2_SIM_CBCR                     0x0708
+#define BLSP1_QUP3_SPI_APPS_CBCR                 0x0744
+#define BLSP1_QUP3_I2C_APPS_CBCR                 0x0748
+#define BLSP1_UART3_APPS_CBCR                    0x0784
+#define BLSP1_UART3_SIM_CBCR                     0x0788
+#define BLSP1_QUP4_SPI_APPS_CBCR                 0x07C4
+#define BLSP1_QUP4_I2C_APPS_CBCR                 0x07C8
+#define BLSP1_UART4_APPS_CBCR                    0x0804
+#define BLSP1_UART4_SIM_CBCR                     0x0808
+#define BLSP1_QUP5_SPI_APPS_CBCR                 0x0844
+#define BLSP1_QUP5_I2C_APPS_CBCR                 0x0848
+#define BLSP1_UART5_APPS_CBCR                    0x0884
+#define BLSP1_UART5_SIM_CBCR                     0x0888
+#define BLSP1_QUP6_SPI_APPS_CBCR                 0x08C4
+#define BLSP1_QUP6_I2C_APPS_CBCR                 0x08C8
+#define BLSP1_UART6_APPS_CBCR                    0x0904
+#define BLSP1_UART6_SIM_CBCR                     0x0908
+#define BLSP2_AHB_CBCR                           0x0944
+#define BOOT_ROM_AHB_CBCR                        0x0E04
+#define BLSP2_QUP1_SPI_APPS_CBCR                 0x0984
+#define BLSP2_QUP1_I2C_APPS_CBCR                 0x0988
+#define BLSP2_UART1_APPS_CBCR                    0x09C4
+#define BLSP2_UART1_SIM_CBCR                     0x09C8
+#define BLSP2_QUP2_SPI_APPS_CBCR                 0x0A04
+#define BLSP2_QUP2_I2C_APPS_CBCR                 0x0A08
+#define BLSP2_UART2_APPS_CBCR                    0x0A44
+#define BLSP2_UART2_SIM_CBCR                     0x0A48
+#define BLSP2_QUP3_SPI_APPS_CBCR                 0x0A84
+#define BLSP2_QUP3_I2C_APPS_CBCR                 0x0A88
+#define BLSP2_UART3_APPS_CBCR                    0x0AC4
+#define BLSP2_UART3_SIM_CBCR                     0x0AC8
+#define BLSP2_QUP4_SPI_APPS_CBCR                 0x0B04
+#define BLSP2_QUP4_I2C_APPS_CBCR                 0x0B08
+#define BLSP2_UART4_APPS_CBCR                    0x0B44
+#define BLSP2_UART4_SIM_CBCR                     0x0B48
+#define BLSP2_QUP5_SPI_APPS_CBCR                 0x0B84
+#define BLSP2_QUP5_I2C_APPS_CBCR                 0x0B88
+#define BLSP2_UART5_APPS_CBCR                    0x0BC4
+#define BLSP2_UART5_SIM_CBCR                     0x0BC8
+#define BLSP2_QUP6_SPI_APPS_CBCR                 0x0C04
+#define BLSP2_QUP6_I2C_APPS_CBCR                 0x0C08
+#define BLSP2_UART6_APPS_CBCR                    0x0C44
+#define BLSP2_UART6_SIM_CBCR                     0x0C48
+#define PDM_AHB_CBCR                             0x0CC4
+#define PDM_XO4_CBCR                             0x0CC8
+#define PDM2_CBCR                                0x0CCC
+#define PRNG_AHB_CBCR                            0x0D04
+#define BAM_DMA_AHB_CBCR                         0x0D44
+#define TSIF_AHB_CBCR                            0x0D84
+#define TSIF_REF_CBCR                            0x0D88
+#define MSG_RAM_AHB_CBCR                         0x0E44
+#define CE1_CBCR                                 0x1044
+#define CE1_AXI_CBCR                             0x1048
+#define CE1_AHB_CBCR                             0x104C
+#define CE2_CBCR                                 0x1084
+#define CE2_AXI_CBCR                             0x1088
+#define CE2_AHB_CBCR                             0x108C
+#define GCC_AHB_CBCR                             0x10C0
+#define GP1_CBCR                                 0x1900
+#define GP2_CBCR                                 0x1940
+#define GP3_CBCR                                 0x1980
+#define AUDIO_CORE_LPAIF_CODEC_SPKR_OSR_CBCR     0xA014
+#define AUDIO_CORE_LPAIF_CODEC_SPKR_IBIT_CBCR    0xA018
+#define AUDIO_CORE_LPAIF_CODEC_SPKR_EBIT_CBCR    0xA01C
+#define AUDIO_CORE_LPAIF_PRI_OSR_CBCR            0xB014
+#define AUDIO_CORE_LPAIF_PRI_IBIT_CBCR           0xB018
+#define AUDIO_CORE_LPAIF_PRI_EBIT_CBCR           0xB01C
+#define AUDIO_CORE_LPAIF_SEC_OSR_CBCR            0xC014
+#define AUDIO_CORE_LPAIF_SEC_IBIT_CBCR           0xC018
+#define AUDIO_CORE_LPAIF_SEC_EBIT_CBCR           0xC01C
+#define AUDIO_CORE_LPAIF_TER_OSR_CBCR            0xD014
+#define AUDIO_CORE_LPAIF_TER_IBIT_CBCR           0xD018
+#define AUDIO_CORE_LPAIF_TER_EBIT_CBCR           0xD01C
+#define AUDIO_CORE_LPAIF_QUAD_OSR_CBCR           0xE014
+#define AUDIO_CORE_LPAIF_QUAD_IBIT_CBCR          0xE018
+#define AUDIO_CORE_LPAIF_QUAD_EBIT_CBCR          0xE01C
+#define AUDIO_CORE_LPAIF_PCM0_IBIT_CBCR          0xF014
+#define AUDIO_CORE_LPAIF_PCM0_EBIT_CBCR          0xF018
+#define AUDIO_CORE_LPAIF_PCM1_IBIT_CBCR          0x10014
+#define AUDIO_CORE_LPAIF_PCM1_EBIT_CBCR          0x10018
+#define AUDIO_CORE_RESAMPLER_CORE_CBCR           0x11014
+#define AUDIO_CORE_RESAMPLER_LFABIF_CBCR         0x11018
+#define AUDIO_CORE_SLIMBUS_CORE_CBCR             0x12014
+#define AUDIO_CORE_SLIMBUS_LFABIF_CBCR           0x12018
+#define AUDIO_CORE_LPAIF_PCM_DATA_OE_CBCR        0x13014
+#define VENUS0_VCODEC0_CBCR                      0x1028
+#define VENUS0_AHB_CBCR                          0x1030
+#define VENUS0_AXI_CBCR                          0x1034
+#define VENUS0_OCMEMNOC_CBCR                     0x1038
+#define MDSS_AHB_CBCR                            0x2308
+#define MDSS_HDMI_AHB_CBCR                       0x230C
+#define MDSS_AXI_CBCR                            0x2310
+#define MDSS_PCLK0_CBCR                          0x2314
+#define MDSS_PCLK1_CBCR                          0x2318
+#define MDSS_MDP_CBCR                            0x231C
+#define MDSS_MDP_LUT_CBCR                        0x2320
+#define MDSS_EXTPCLK_CBCR                        0x2324
+#define MDSS_VSYNC_CBCR                          0x2328
+#define MDSS_EDPPIXEL_CBCR                       0x232C
+#define MDSS_EDPLINK_CBCR                        0x2330
+#define MDSS_EDPAUX_CBCR                         0x2334
+#define MDSS_HDMI_CBCR                           0x2338
+#define MDSS_BYTE0_CBCR                          0x233C
+#define MDSS_BYTE1_CBCR                          0x2340
+#define MDSS_ESC0_CBCR                           0x2344
+#define MDSS_ESC1_CBCR                           0x2348
+#define CAMSS_PHY0_CSI0PHYTIMER_CBCR             0x3024
+#define CAMSS_PHY1_CSI1PHYTIMER_CBCR             0x3054
+#define CAMSS_PHY2_CSI2PHYTIMER_CBCR             0x3084
+#define CAMSS_CSI0_CBCR                          0x30B4
+#define CAMSS_CSI0_AHB_CBCR                      0x30BC
+#define CAMSS_CSI0PHY_CBCR                       0x30C4
+#define CAMSS_CSI0RDI_CBCR                       0x30D4
+#define CAMSS_CSI0PIX_CBCR                       0x30E4
+#define CAMSS_CSI1_CBCR                          0x3124
+#define CAMSS_CSI1_AHB_CBCR                      0x3128
+#define CAMSS_CSI1PHY_CBCR                       0x3134
+#define CAMSS_CSI1RDI_CBCR                       0x3144
+#define CAMSS_CSI1PIX_CBCR                       0x3154
+#define CAMSS_CSI2_CBCR                          0x3184
+#define CAMSS_CSI2_AHB_CBCR                      0x3188
+#define CAMSS_CSI2PHY_CBCR                       0x3194
+#define CAMSS_CSI2RDI_CBCR                       0x31A4
+#define CAMSS_CSI2PIX_CBCR                       0x31B4
+#define CAMSS_CSI3_CBCR                          0x31E4
+#define CAMSS_CSI3_AHB_CBCR                      0x31E8
+#define CAMSS_CSI3PHY_CBCR                       0x31F4
+#define CAMSS_CSI3RDI_CBCR                       0x3204
+#define CAMSS_CSI3PIX_CBCR                       0x3214
+#define CAMSS_ISPIF_AHB_CBCR                     0x3224
+#define CAMSS_CCI_CCI_CBCR                       0x3344
+#define CAMSS_CCI_CCI_AHB_CBCR                   0x3348
+#define CAMSS_MCLK0_CBCR                         0x3384
+#define CAMSS_MCLK1_CBCR                         0x33B4
+#define CAMSS_MCLK2_CBCR                         0x33E4
+#define CAMSS_MCLK3_CBCR                         0x3414
+#define CAMSS_GP0_CBCR                           0x3444
+#define CAMSS_GP1_CBCR                           0x3474
+#define CAMSS_TOP_AHB_CBCR                       0x3484
+#define CAMSS_MICRO_AHB_CBCR                     0x3494
+#define CAMSS_JPEG_JPEG0_CBCR                    0x35A8
+#define CAMSS_JPEG_JPEG1_CBCR                    0x35AC
+#define CAMSS_JPEG_JPEG2_CBCR                    0x35B0
+#define CAMSS_JPEG_JPEG_AHB_CBCR                 0x35B4
+#define CAMSS_JPEG_JPEG_AXI_CBCR                 0x35B8
+#define CAMSS_JPEG_JPEG_OCMEMNOC_CBCR            0x35BC
+#define CAMSS_VFE_VFE0_CBCR                      0x36A8
+#define CAMSS_VFE_VFE1_CBCR                      0x36AC
+#define CAMSS_VFE_CPP_CBCR                       0x36B0
+#define CAMSS_VFE_CPP_AHB_CBCR                   0x36B4
+#define CAMSS_VFE_VFE_AHB_CBCR                   0x36B8
+#define CAMSS_VFE_VFE_AXI_CBCR                   0x36BC
+#define CAMSS_VFE_VFE_OCMEMNOC_CBCR              0x36C0
+#define CAMSS_CSI_VFE0_CBCR                      0x3704
+#define CAMSS_CSI_VFE1_CBCR                      0x3714
+#define MMSS_MMSSNOC_AXI_CBCR                    0x506C
+#define MMSS_MMSSNOC_AHB_CBCR                    0x5024
+#define MMSS_MMSSNOC_BTO_AHB_CBCR                0x5028
+#define MMSS_MISC_AHB_CBCR                       0x502C
+#define MMSS_S0_AXI_CBCR                         0x5064
+#define OCMEMNOC_CBCR                            0x50B4
+#define LPASS_Q6SS_AHB_LFABIF_CBCR               0x22000
+#define LPASS_Q6SS_XO_CBCR                       0x26000
+#define MSS_XO_Q6_CBCR                           0x108C
+#define MSS_BUS_Q6_CBCR                          0x10A4
+#define MSS_CFG_AHB_CBCR                         0x0280
+
+#define APCS_CLOCK_BRANCH_ENA_VOTE 0x1484
+#define APCS_CLOCK_SLEEP_ENA_VOTE  0x1488
+
+/* Mux source select values */
+#define cxo_source_val	0
+#define gpll0_source_val 1
+#define gpll1_source_val 2
+#define gnd_source_val	5
+#define mmpll0_mm_source_val 1
+#define mmpll1_mm_source_val 2
+#define mmpll3_mm_source_val 3
+#define gpll0_mm_source_val 5
+#define cxo_mm_source_val 0
+#define mm_gnd_source_val 6
+#define gpll1_hsic_source_val 4
+#define cxo_lpass_source_val 0
+#define lpapll0_lpass_source_val 1
+#define gpll0_lpass_source_val 5
+#define edppll_270_mm_source_val 4
+#define edppll_350_mm_source_val 4
+#define dsipll_750_mm_source_val 1
+#define dsipll_250_mm_source_val 2
+#define hdmipll_297_mm_source_val 3
+
+#define F(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s##_clk_src.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_source_val), \
+	}
+
+#define F_MM(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s##_clk_src.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_mm_source_val), \
+	}
+
+#define F_MDSS(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_mm_source_val), \
+	}
+
+#define F_HSIC(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s##_clk_src.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_hsic_source_val), \
+	}
+
+#define F_LPASS(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s##_clk_src.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_lpass_source_val), \
+	}
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+	.vdd_class = &vdd_dig, \
+	.fmax[VDD_DIG_##l1] = (f1)
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+	.vdd_class = &vdd_dig, \
+	.fmax[VDD_DIG_##l1] = (f1), \
+	.fmax[VDD_DIG_##l2] = (f2)
+#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+	.vdd_class = &vdd_dig, \
+	.fmax[VDD_DIG_##l1] = (f1), \
+	.fmax[VDD_DIG_##l2] = (f2), \
+	.fmax[VDD_DIG_##l3] = (f3)
+
+enum vdd_dig_levels {
+	VDD_DIG_NONE,
+	VDD_DIG_LOW,
+	VDD_DIG_NOMINAL,
+	VDD_DIG_HIGH
+};
+
+static int set_vdd_dig(struct clk_vdd_class *vdd_class, int level)
+{
+	/* TODO: Actually call into regulator APIs to set VDD_DIG here. */
+	return 0;
+}
+
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
+
+static int cxo_clk_enable(struct clk *clk)
+{
+	/* TODO: Remove from here once the rpm xo clock is ready. */
+	return 0;
+}
+
+static void cxo_clk_disable(struct clk *clk)
+{
+	/* TODO: Remove from here once the rpm xo clock is ready. */
+	return;
+}
+
+static struct clk_ops clk_ops_cxo = {
+	.enable = cxo_clk_enable,
+	.disable = cxo_clk_disable,
+};
+
+static struct fixed_clk cxo_clk_src = {
+	.c = {
+		.rate = 19200000,
+		.dbg_name = "cxo_clk_src",
+		.ops = &clk_ops_cxo,
+		.warned = true,
+		CLK_INIT(cxo_clk_src.c),
+	},
+};
+
+static struct pll_vote_clk gpll0_clk_src = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE_REG,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_STATUS_REG,
+	.status_mask = BIT(17),
+	.parent = &cxo_clk_src.c,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.rate = 600000000,
+		.dbg_name = "gpll0_clk_src",
+		.ops = &clk_ops_pll_vote,
+		.warned = true,
+		CLK_INIT(gpll0_clk_src.c),
+	},
+};
+
+static struct pll_vote_clk gpll1_clk_src = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE_REG,
+	.en_mask = BIT(1),
+	.status_reg = (void __iomem *)GPLL1_STATUS_REG,
+	.status_mask = BIT(17),
+	.parent = &cxo_clk_src.c,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.rate = 480000000,
+		.dbg_name = "gpll1_clk_src",
+		.ops = &clk_ops_pll_vote,
+		.warned = true,
+		CLK_INIT(gpll1_clk_src.c),
+	},
+};
+
+static struct pll_vote_clk lpapll0_clk_src = {
+	.en_reg = (void __iomem *)LPASS_LPA_PLL_VOTE_APPS_REG,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)LPAPLL_STATUS_REG,
+	.status_mask = BIT(17),
+	.parent = &cxo_clk_src.c,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.rate = 491520000,
+		.dbg_name = "lpapll0_clk_src",
+		.ops = &clk_ops_pll_vote,
+		.warned = true,
+		CLK_INIT(lpapll0_clk_src.c),
+	},
+};
+
+static struct pll_vote_clk mmpll0_clk_src = {
+	.en_reg = (void __iomem *)MMSS_PLL_VOTE_APCS_REG,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)MMPLL0_STATUS_REG,
+	.status_mask = BIT(17),
+	.parent = &cxo_clk_src.c,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmpll0_clk_src",
+		.rate = 800000000,
+		.ops = &clk_ops_pll_vote,
+		.warned = true,
+		CLK_INIT(mmpll0_clk_src.c),
+	},
+};
+
+static struct pll_vote_clk mmpll1_clk_src = {
+	.en_reg = (void __iomem *)MMSS_PLL_VOTE_APCS_REG,
+	.en_mask = BIT(1),
+	.status_reg = (void __iomem *)MMPLL1_STATUS_REG,
+	.status_mask = BIT(17),
+	.parent = &cxo_clk_src.c,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmpll1_clk_src",
+		.rate = 1000000000,
+		.ops = &clk_ops_pll_vote,
+		.warned = true,
+		CLK_INIT(mmpll1_clk_src.c),
+	},
+};
+
+static struct pll_clk mmpll3_clk_src = {
+	.mode_reg = (void __iomem *)MMPLL3_MODE_REG,
+	.status_reg = (void __iomem *)MMPLL3_STATUS_REG,
+	.parent = &cxo_clk_src.c,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmpll3_clk_src",
+		.rate = 1000000000,
+		.ops = &clk_ops_local_pll,
+		CLK_INIT(mmpll3_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb30_master_clk[] = {
+	F(125000000,  gpll0,   1,   5,  24),
+	F_END
+};
+
+static struct rcg_clk usb30_master_clk_src = {
+	.cmd_rcgr_reg = USB30_MASTER_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_usb30_master_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb30_master_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 125000000),
+		CLK_INIT(usb30_master_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk[] = {
+	F(  960000,    cxo,  10,   1,   2),
+	F( 4800000,    cxo,   4,   0,   0),
+	F( 9600000,    cxo,   2,   0,   0),
+	F(15000000,  gpll0,  10,   1,   4),
+	F(19200000,    cxo,   1,   0,   0),
+	F(25000000,  gpll0,  12,   1,   2),
+	F(50000000,  gpll0,  12,   0,   0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup1_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP1_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup1_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup1_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup2_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP2_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup2_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup2_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup3_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP3_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup3_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup3_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup4_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP4_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup4_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup4_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup5_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP5_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup5_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup5_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup6_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP6_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup6_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup6_spi_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_2_uart1_6_apps_clk[] = {
+	F( 3686400,  gpll0,    1,  96,  15625),
+	F( 7372800,  gpll0,    1, 192,  15625),
+	F(14745600,  gpll0,    1, 384,  15625),
+	F(16000000,  gpll0,    5,   2,     15),
+	F(19200000,    cxo,    1,   0,      0),
+	F(24000000,  gpll0,    5,   1,      5),
+	F(32000000,  gpll0,    1,   4,     75),
+	F(40000000,  gpll0,   15,   0,      0),
+	F(46400000,  gpll0,    1,  29,    375),
+	F(48000000,  gpll0, 12.5,   0,      0),
+	F(51200000,  gpll0,    1,  32,    375),
+	F(56000000,  gpll0,    1,   7,     75),
+	F(58982400,  gpll0,    1, 1536, 15625),
+	F(60000000,  gpll0,   10,   0,      0),
+	F_END
+};
+
+static struct rcg_clk blsp1_uart1_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart2_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart2_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart3_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART3_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart3_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart3_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart4_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART4_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart4_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart4_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart5_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART5_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart5_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart5_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart6_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART6_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart6_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart6_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup1_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP1_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup1_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup1_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup2_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP2_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup2_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup2_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup3_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP3_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup3_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup3_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup4_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP4_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup4_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup4_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup5_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP5_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup5_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup5_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup6_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP6_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup6_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup6_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart1_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_UART1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp2_uart1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart2_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_UART2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp2_uart2_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart3_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_UART3_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart3_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp2_uart3_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart4_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_UART4_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart4_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp2_uart4_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart5_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_UART5_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart5_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp2_uart5_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart6_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_UART6_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart6_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp2_uart6_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_ce1_clk[] = {
+	F( 50000000,  gpll0,  12,   0,   0),
+	F(100000000,  gpll0,   6,   0,   0),
+	F_END
+};
+
+static struct rcg_clk ce1_clk_src = {
+	.cmd_rcgr_reg = CE1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_ce1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "ce1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 100000000),
+		CLK_INIT(ce1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_ce2_clk[] = {
+	F( 50000000,  gpll0,  12,   0,   0),
+	F(100000000,  gpll0,   6,   0,   0),
+	F_END
+};
+
+static struct rcg_clk ce2_clk_src = {
+	.cmd_rcgr_reg = CE2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_ce2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "ce2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 100000000),
+		CLK_INIT(ce2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_gp_clk[] = {
+	F(19200000,  cxo,  1,   0,   0),
+	F_END
+};
+
+static struct rcg_clk gp1_clk_src = {
+	.cmd_rcgr_reg = GP1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_gp_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(gp1_clk_src.c),
+	},
+};
+
+static struct rcg_clk gp2_clk_src = {
+	.cmd_rcgr_reg = GP2_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_gp_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp2_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(gp2_clk_src.c),
+	},
+};
+
+static struct rcg_clk gp3_clk_src = {
+	.cmd_rcgr_reg = GP3_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_gp_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp3_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(gp3_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_pdm2_clk[] = {
+	F(60000000,  gpll0,  10,   0,   0),
+	F_END
+};
+
+static struct rcg_clk pdm2_clk_src = {
+	.cmd_rcgr_reg = PDM2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_pdm2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "pdm2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 60000000),
+		CLK_INIT(pdm2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_sdcc1_2_apps_clk[] = {
+	F(   144000,    cxo,  16,   3,  25),
+	F(   400000,    cxo,  12,   1,   4),
+	F( 20000000,  gpll0,  15,   1,   2),
+	F( 25000000,  gpll0,  12,   1,   2),
+	F( 50000000,  gpll0,  12,   0,   0),
+	F(100000000,  gpll0,   6,   0,   0),
+	F(200000000,  gpll0,   3,   0,   0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_sdcc3_4_apps_clk[] = {
+	F(   144000,    cxo,  16,   3,  25),
+	F(   400000,    cxo,  12,   1,   4),
+	F( 20000000,  gpll0,  15,   1,   2),
+	F( 25000000,  gpll0,  12,   1,   2),
+	F( 50000000,  gpll0,  12,   0,   0),
+	F(100000000,  gpll0,   6,   0,   0),
+	F_END
+};
+
+static struct rcg_clk sdcc1_apps_clk_src = {
+	.cmd_rcgr_reg = SDCC1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc1_2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(sdcc1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk sdcc2_apps_clk_src = {
+	.cmd_rcgr_reg = SDCC2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc1_2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(sdcc2_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk sdcc3_apps_clk_src = {
+	.cmd_rcgr_reg = SDCC3_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc3_4_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc3_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 100000000),
+		CLK_INIT(sdcc3_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk sdcc4_apps_clk_src = {
+	.cmd_rcgr_reg = SDCC4_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc3_4_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc4_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 100000000),
+		CLK_INIT(sdcc4_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_tsif_ref_clk[] = {
+	F(105000,    cxo,   2,   1,  91),
+	F_END
+};
+
+static struct rcg_clk tsif_ref_clk_src = {
+	.cmd_rcgr_reg = TSIF_REF_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_tsif_ref_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "tsif_ref_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOW, 105500),
+		CLK_INIT(tsif_ref_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb30_mock_utmi_clk[] = {
+	F(60000000,  gpll0,   10,   0,   0),
+	F_END
+};
+
+static struct rcg_clk usb30_mock_utmi_clk_src = {
+	.cmd_rcgr_reg = USB30_MOCK_UTMI_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb30_mock_utmi_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb30_mock_utmi_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(NOMINAL, 60000000),
+		CLK_INIT(usb30_mock_utmi_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hs_system_clk[] = {
+	F(75000000,  gpll0,   8,   0,   0),
+	F_END
+};
+
+static struct rcg_clk usb_hs_system_clk_src = {
+	.cmd_rcgr_reg = USB_HS_SYSTEM_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hs_system_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hs_system_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 37500000, NOMINAL, 75000000),
+		CLK_INIT(usb_hs_system_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hsic_clk[] = {
+	F_HSIC(480000000,  gpll1,   1,   0,   0),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_clk_src = {
+	.cmd_rcgr_reg = USB_HSIC_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hsic_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hsic_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 480000000),
+		CLK_INIT(usb_hsic_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hsic_io_cal_clk[] = {
+	F(9600000,    cxo,   2,   0,   0),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_io_cal_clk_src = {
+	.cmd_rcgr_reg = USB_HSIC_IO_CAL_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hsic_io_cal_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hsic_io_cal_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 9600000),
+		CLK_INIT(usb_hsic_io_cal_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hsic_system_clk[] = {
+	F(75000000,  gpll0,   8,   0,   0),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_system_clk_src = {
+	.cmd_rcgr_reg = USB_HSIC_SYSTEM_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hsic_system_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hsic_system_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 37500000, NOMINAL, 75000000),
+		CLK_INIT(usb_hsic_system_clk_src.c),
+	},
+};
+
+static struct local_vote_clk gcc_bam_dma_ahb_clk = {
+	.cbcr_reg = BAM_DMA_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(12),
+	.bcr_reg = BAM_DMA_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_bam_dma_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_bam_dma_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_blsp1_ahb_clk = {
+	.cbcr_reg = BLSP1_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(17),
+	.bcr_reg = BLSP1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_blsp1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP1_QUP1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_SPI_APPS_CBCR,
+	.parent = &blsp1_qup1_spi_apps_clk_src.c,
+	.bcr_reg = BLSP1_QUP1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP1_QUP2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_SPI_APPS_CBCR,
+	.parent = &blsp1_qup2_spi_apps_clk_src.c,
+	.bcr_reg = BLSP1_QUP2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP1_QUP3_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_SPI_APPS_CBCR,
+	.parent = &blsp1_qup3_spi_apps_clk_src.c,
+	.bcr_reg = BLSP1_QUP3_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP1_QUP4_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_SPI_APPS_CBCR,
+	.parent = &blsp1_qup4_spi_apps_clk_src.c,
+	.bcr_reg = BLSP1_QUP4_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup5_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP5_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP1_QUP5_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup5_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup5_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup5_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP5_SPI_APPS_CBCR,
+	.parent = &blsp1_qup5_spi_apps_clk_src.c,
+	.bcr_reg = BLSP1_QUP5_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup5_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup5_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup6_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP6_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP1_QUP6_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup6_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup6_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup6_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP6_SPI_APPS_CBCR,
+	.parent = &blsp1_qup6_spi_apps_clk_src.c,
+	.bcr_reg = BLSP1_QUP6_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup6_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup6_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart1_apps_clk = {
+	.cbcr_reg = BLSP1_UART1_APPS_CBCR,
+	.parent = &blsp1_uart1_apps_clk_src.c,
+	.bcr_reg = BLSP1_UART1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart1_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart2_apps_clk = {
+	.cbcr_reg = BLSP1_UART2_APPS_CBCR,
+	.parent = &blsp1_uart2_apps_clk_src.c,
+	.bcr_reg = BLSP1_UART2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart2_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart2_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart3_apps_clk = {
+	.cbcr_reg = BLSP1_UART3_APPS_CBCR,
+	.parent = &blsp1_uart3_apps_clk_src.c,
+	.bcr_reg = BLSP1_UART3_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart3_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart3_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart4_apps_clk = {
+	.cbcr_reg = BLSP1_UART4_APPS_CBCR,
+	.parent = &blsp1_uart4_apps_clk_src.c,
+	.bcr_reg = BLSP1_UART4_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart4_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart4_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart5_apps_clk = {
+	.cbcr_reg = BLSP1_UART5_APPS_CBCR,
+	.parent = &blsp1_uart5_apps_clk_src.c,
+	.bcr_reg = BLSP1_UART5_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart5_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart5_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart6_apps_clk = {
+	.cbcr_reg = BLSP1_UART6_APPS_CBCR,
+	.parent = &blsp1_uart6_apps_clk_src.c,
+	.bcr_reg = BLSP1_UART6_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart6_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart6_apps_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_boot_rom_ahb_clk = {
+	.cbcr_reg = BOOT_ROM_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(10),
+	.bcr_reg = BOOT_ROM_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_boot_rom_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_boot_rom_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_blsp2_ahb_clk = {
+	.cbcr_reg = BLSP2_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(15),
+	.bcr_reg = BLSP2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_blsp2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup1_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP1_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP2_QUP1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup1_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup1_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup1_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP1_SPI_APPS_CBCR,
+	.parent = &blsp2_qup1_spi_apps_clk_src.c,
+	.bcr_reg = BLSP2_QUP1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup1_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup1_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup2_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP2_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP2_QUP2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup2_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup2_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup2_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP2_SPI_APPS_CBCR,
+	.parent = &blsp2_qup2_spi_apps_clk_src.c,
+	.bcr_reg = BLSP2_QUP2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup2_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup2_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup3_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP3_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP2_QUP3_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup3_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup3_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup3_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP3_SPI_APPS_CBCR,
+	.parent = &blsp2_qup3_spi_apps_clk_src.c,
+	.bcr_reg = BLSP2_QUP3_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup3_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup3_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup4_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP4_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP2_QUP4_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup4_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup4_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup4_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP4_SPI_APPS_CBCR,
+	.parent = &blsp2_qup4_spi_apps_clk_src.c,
+	.bcr_reg = BLSP2_QUP4_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup4_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup4_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup5_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP5_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP2_QUP5_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup5_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup5_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup5_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP5_SPI_APPS_CBCR,
+	.parent = &blsp2_qup5_spi_apps_clk_src.c,
+	.bcr_reg = BLSP2_QUP5_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup5_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup5_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup6_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP6_I2C_APPS_CBCR,
+	.parent = &cxo_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = BLSP2_QUP6_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup6_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup6_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup6_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP6_SPI_APPS_CBCR,
+	.parent = &blsp2_qup6_spi_apps_clk_src.c,
+	.bcr_reg = BLSP2_QUP6_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup6_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup6_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart1_apps_clk = {
+	.cbcr_reg = BLSP2_UART1_APPS_CBCR,
+	.parent = &blsp2_uart1_apps_clk_src.c,
+	.bcr_reg = BLSP2_UART1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart1_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart2_apps_clk = {
+	.cbcr_reg = BLSP2_UART2_APPS_CBCR,
+	.parent = &blsp2_uart2_apps_clk_src.c,
+	.bcr_reg = BLSP2_UART2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart2_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart2_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart3_apps_clk = {
+	.cbcr_reg = BLSP2_UART3_APPS_CBCR,
+	.parent = &blsp2_uart3_apps_clk_src.c,
+	.bcr_reg = BLSP2_UART3_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart3_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart3_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart4_apps_clk = {
+	.cbcr_reg = BLSP2_UART4_APPS_CBCR,
+	.parent = &blsp2_uart4_apps_clk_src.c,
+	.bcr_reg = BLSP2_UART4_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart4_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart4_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart5_apps_clk = {
+	.cbcr_reg = BLSP2_UART5_APPS_CBCR,
+	.parent = &blsp2_uart5_apps_clk_src.c,
+	.bcr_reg = BLSP2_UART5_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart5_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart5_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart6_apps_clk = {
+	.cbcr_reg = BLSP2_UART6_APPS_CBCR,
+	.parent = &blsp2_uart6_apps_clk_src.c,
+	.bcr_reg = BLSP2_UART6_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart6_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart6_apps_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce1_clk = {
+	.cbcr_reg = CE1_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(5),
+	.bcr_reg = CE1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce1_ahb_clk = {
+	.cbcr_reg = CE1_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(3),
+	.bcr_reg = CE1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce1_axi_clk = {
+	.cbcr_reg = CE1_AXI_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(4),
+	.bcr_reg = CE1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_axi_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_axi_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce2_clk = {
+	.cbcr_reg = CE2_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(2),
+	.bcr_reg = CE2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce2_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce2_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce2_ahb_clk = {
+	.cbcr_reg = CE2_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(0),
+	.bcr_reg = CE2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce2_axi_clk = {
+	.cbcr_reg = CE2_AXI_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(1),
+	.bcr_reg = CE2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_axi_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce2_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp1_clk = {
+	.cbcr_reg = GP1_CBCR,
+	.parent = &gp1_clk_src.c,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gp1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp2_clk = {
+	.cbcr_reg = GP2_CBCR,
+	.parent = &gp2_clk_src.c,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gp2_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp3_clk = {
+	.cbcr_reg = GP3_CBCR,
+	.parent = &gp3_clk_src.c,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_gp3_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp3_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm2_clk = {
+	.cbcr_reg = PDM2_CBCR,
+	.parent = &pdm2_clk_src.c,
+	.bcr_reg = PDM_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pdm2_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm_ahb_clk = {
+	.cbcr_reg = PDM_AHB_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = PDM_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pdm_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_prng_ahb_clk = {
+	.cbcr_reg = PRNG_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(13),
+	.bcr_reg = PRNG_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_prng_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_prng_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_ahb_clk = {
+	.cbcr_reg = SDCC1_AHB_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = SDCC1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc1_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_apps_clk = {
+	.cbcr_reg = SDCC1_APPS_CBCR,
+	.parent = &sdcc1_apps_clk_src.c,
+	.bcr_reg = SDCC1_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc1_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc2_ahb_clk = {
+	.cbcr_reg = SDCC2_AHB_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = SDCC2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc2_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc2_apps_clk = {
+	.cbcr_reg = SDCC2_APPS_CBCR,
+	.parent = &sdcc2_apps_clk_src.c,
+	.bcr_reg = SDCC2_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc2_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc3_ahb_clk = {
+	.cbcr_reg = SDCC3_AHB_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = SDCC3_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc3_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc3_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc3_apps_clk = {
+	.cbcr_reg = SDCC3_APPS_CBCR,
+	.parent = &sdcc3_apps_clk_src.c,
+	.bcr_reg = SDCC3_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc3_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc3_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc4_ahb_clk = {
+	.cbcr_reg = SDCC4_AHB_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = SDCC4_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc4_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc4_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc4_apps_clk = {
+	.cbcr_reg = SDCC4_APPS_CBCR,
+	.parent = &sdcc4_apps_clk_src.c,
+	.bcr_reg = SDCC4_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc4_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc4_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_tsif_ahb_clk = {
+	.cbcr_reg = TSIF_AHB_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = TSIF_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_tsif_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_tsif_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_tsif_ref_clk = {
+	.cbcr_reg = TSIF_REF_CBCR,
+	.parent = &tsif_ref_clk_src.c,
+	.bcr_reg = TSIF_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_tsif_ref_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_tsif_ref_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb30_master_clk = {
+	.cbcr_reg = USB30_MASTER_CBCR,
+	.parent = &usb30_master_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = USB_30_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb30_master_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb30_master_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb30_mock_utmi_clk = {
+	.cbcr_reg = USB30_MOCK_UTMI_CBCR,
+	.parent = &usb30_mock_utmi_clk_src.c,
+	.bcr_reg = USB_30_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb30_mock_utmi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb30_mock_utmi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_ahb_clk = {
+	.cbcr_reg = USB_HS_AHB_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = USB_HS_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_system_clk = {
+	.cbcr_reg = USB_HS_SYSTEM_CBCR,
+	.parent = &usb_hs_system_clk_src.c,
+	.bcr_reg = USB_HS_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_system_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_system_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_ahb_clk = {
+	.cbcr_reg = USB_HSIC_AHB_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = USB_HS_HSIC_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_clk = {
+	.cbcr_reg = USB_HSIC_CBCR,
+	.parent = &usb_hsic_clk_src.c,
+	.bcr_reg = USB_HS_HSIC_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_io_cal_clk = {
+	.cbcr_reg = USB_HSIC_IO_CAL_CBCR,
+	.parent = &usb_hsic_io_cal_clk_src.c,
+	.bcr_reg = USB_HS_HSIC_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_io_cal_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_io_cal_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_system_clk = {
+	.cbcr_reg = USB_HSIC_SYSTEM_CBCR,
+	.parent = &usb_hsic_system_clk_src.c,
+	.bcr_reg = USB_HS_HSIC_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_system_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_system_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_cfg_ahb_clk = {
+	.cbcr_reg = MSS_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mss_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_cfg_ahb_clk.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mmss_ahb_clk[] = {
+	F_MM(19200000,    cxo,   1,   0,   0),
+	F_MM(40000000,  gpll0,  15,   0,   0),
+	F_MM(80000000, mmpll0,  10,   0,   0),
+	F_END,
+};
+
+/* TODO: This may go away (may be controlled by the RPM). */
+static struct rcg_clk ahb_clk_src = {
+	.cmd_rcgr_reg = 0x5000,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mmss_ahb_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "ahb_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 40000000, NOMINAL, 80000000),
+		CLK_INIT(ahb_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mmss_axi_clk[] = {
+	F_MM( 19200000,    cxo,   1,   0,   0),
+	F_MM(150000000,  gpll0,   4,   0,   0),
+	F_MM(333330000, mmpll1,   3,   0,   0),
+	F_MM(400000000, mmpll0,   2,   0,   0),
+	F_END
+};
+
+static struct rcg_clk axi_clk_src = {
+	.cmd_rcgr_reg = 0x5040,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mmss_axi_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "axi_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 150000000, NOMINAL, 333330000,
+				  HIGH, 400000000),
+		CLK_INIT(axi_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_csi0_3_clk[] = {
+	F_MM(100000000,  gpll0,   6,   0,   0),
+	F_MM(200000000, mmpll0,   4,   0,   0),
+	F_END
+};
+
+static struct rcg_clk csi0_clk_src = {
+	.cmd_rcgr_reg = CSI0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_csi0_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi0_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi1_clk_src = {
+	.cmd_rcgr_reg = CSI1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_csi0_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi1_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi2_clk_src = {
+	.cmd_rcgr_reg = CSI2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_csi0_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi2_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi3_clk_src = {
+	.cmd_rcgr_reg = CSI3_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_csi0_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi3_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi3_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_vfe_vfe0_1_clk[] = {
+	F_MM( 37500000,  gpll0,  16,   0,   0),
+	F_MM( 50000000,  gpll0,  12,   0,   0),
+	F_MM( 60000000,  gpll0,  10,   0,   0),
+	F_MM( 80000000,  gpll0, 7.5,   0,   0),
+	F_MM(100000000,  gpll0,   6,   0,   0),
+	F_MM(109090000,  gpll0, 5.5,   0,   0),
+	F_MM(150000000,  gpll0,   4,   0,   0),
+	F_MM(200000000,  gpll0,   3,   0,   0),
+	F_MM(228570000, mmpll0, 3.5,   0,   0),
+	F_MM(266670000, mmpll0,   3,   0,   0),
+	F_MM(320000000, mmpll0, 2.5,   0,   0),
+	F_END
+};
+
+static struct rcg_clk vfe0_clk_src = {
+	.cmd_rcgr_reg = VFE0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_vfe_vfe0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "vfe0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000,
+				  HIGH, 320000000),
+		CLK_INIT(vfe0_clk_src.c),
+	},
+};
+
+static struct rcg_clk vfe1_clk_src = {
+	.cmd_rcgr_reg = VFE1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_vfe_vfe0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "vfe1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000,
+				  HIGH, 320000000),
+		CLK_INIT(vfe1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_mdp_clk[] = {
+	F_MM( 37500000,  gpll0,  16,   0,   0),
+	F_MM( 60000000,  gpll0,  10,   0,   0),
+	F_MM( 75000000,  gpll0,   8,   0,   0),
+	F_MM( 85710000,  gpll0,   7,   0,   0),
+	F_MM(100000000,  gpll0,   6,   0,   0),
+	F_MM(133330000, mmpll0,   6,   0,   0),
+	F_MM(160000000, mmpll0,   5,   0,   0),
+	F_MM(200000000, mmpll0,   4,   0,   0),
+	F_MM(266670000, mmpll0,   3,   0,   0),
+	F_MM(320000000, mmpll0, 2.5,   0,   0),
+	F_END
+};
+
+static struct rcg_clk mdp_clk_src = {
+	.cmd_rcgr_reg = MDP_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_mdp_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdp_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000,
+				  HIGH, 320000000),
+		CLK_INIT(mdp_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_cci_cci_clk[] = {
+	F_MM(19200000,    cxo,   1,   0,   0),
+	F_END
+};
+
+static struct rcg_clk cci_clk_src = {
+	.cmd_rcgr_reg = CCI_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_cci_cci_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "cci_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 20000000, NOMINAL, 40000000),
+		CLK_INIT(cci_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_gp0_1_clk[] = {
+	F_MM(   10000,    cxo,  16,   1, 120),
+	F_MM(   20000,    cxo,  16,   1,  50),
+	F_MM( 6000000,  gpll0,  10,   1,  10),
+	F_MM(12000000,  gpll0,  10,   1,   5),
+	F_MM(13000000,  gpll0,  10,  13,  60),
+	F_MM(24000000,  gpll0,   5,   1,   5),
+	F_END
+};
+
+static struct rcg_clk mmss_gp0_clk_src = {
+	.cmd_rcgr_reg = MMSS_GP0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_camss_gp0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_gp0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(mmss_gp0_clk_src.c),
+	},
+};
+
+static struct rcg_clk mmss_gp1_clk_src = {
+	.cmd_rcgr_reg = MMSS_GP1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_camss_gp0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_gp1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(mmss_gp1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_jpeg_jpeg0_2_clk[] = {
+	F_MM( 75000000,  gpll0,   8,   0,   0),
+	F_MM(150000000,  gpll0,   4,   0,   0),
+	F_MM(200000000,  gpll0,   3,   0,   0),
+	F_MM(228570000, mmpll0, 3.5,   0,   0),
+	F_MM(266670000, mmpll0,   3,   0,   0),
+	F_MM(320000000, mmpll0, 2.5,   0,   0),
+	F_END
+};
+
+static struct rcg_clk jpeg0_clk_src = {
+	.cmd_rcgr_reg = JPEG0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_jpeg_jpeg0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "jpeg0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000,
+				  HIGH, 320000000),
+		CLK_INIT(jpeg0_clk_src.c),
+	},
+};
+
+static struct rcg_clk jpeg1_clk_src = {
+	.cmd_rcgr_reg = JPEG1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_jpeg_jpeg0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "jpeg1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000,
+				  HIGH, 320000000),
+		CLK_INIT(jpeg1_clk_src.c),
+	},
+};
+
+static struct rcg_clk jpeg2_clk_src = {
+	.cmd_rcgr_reg = JPEG2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_jpeg_jpeg0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "jpeg2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000,
+				  HIGH, 320000000),
+		CLK_INIT(jpeg2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_mclk0_3_clk[] = {
+	F_MM(66670000,  gpll0,   9,   0,   0),
+	F_END
+};
+
+static struct rcg_clk mclk0_clk_src = {
+	.cmd_rcgr_reg = MCLK0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_mclk0_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mclk0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 66670000),
+		CLK_INIT(mclk0_clk_src.c),
+	},
+};
+
+static struct rcg_clk mclk1_clk_src = {
+	.cmd_rcgr_reg = MCLK1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_mclk0_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mclk1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 66670000),
+		CLK_INIT(mclk1_clk_src.c),
+	},
+};
+
+static struct rcg_clk mclk2_clk_src = {
+	.cmd_rcgr_reg = MCLK2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_mclk0_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mclk2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 66670000),
+		CLK_INIT(mclk2_clk_src.c),
+	},
+};
+
+static struct rcg_clk mclk3_clk_src = {
+	.cmd_rcgr_reg = MCLK3_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_mclk0_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mclk3_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 66670000),
+		CLK_INIT(mclk3_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_phy0_2_csi0_2phytimer_clk[] = {
+	F_MM(100000000,  gpll0,   6,   0,   0),
+	F_MM(200000000, mmpll0,   4,   0,   0),
+	F_END
+};
+
+static struct rcg_clk csi0phytimer_clk_src = {
+	.cmd_rcgr_reg = CSI0PHYTIMER_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_phy0_2_csi0_2phytimer_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi0phytimer_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi0phytimer_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi1phytimer_clk_src = {
+	.cmd_rcgr_reg = CSI1PHYTIMER_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_phy0_2_csi0_2phytimer_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi1phytimer_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi1phytimer_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi2phytimer_clk_src = {
+	.cmd_rcgr_reg = CSI2PHYTIMER_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_phy0_2_csi0_2phytimer_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi2phytimer_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi2phytimer_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_vfe_cpp_clk[] = {
+	F_MM(150000000,  gpll0,   4,   0,   0),
+	F_MM(266670000, mmpll0,   3,   0,   0),
+	F_MM(320000000, mmpll0, 2.5,   0,   0),
+	F_END
+};
+
+static struct rcg_clk cpp_clk_src = {
+	.cmd_rcgr_reg = CPP_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_vfe_cpp_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "cpp_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000,
+				  HIGH, 320000000),
+		CLK_INIT(cpp_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_byte0_1_clk[] = {
+	F_MDSS( 93750000, dsipll_750,   8,   0,   0),
+	F_MDSS(187500000, dsipll_750,   4,   0,   0),
+	F_END
+};
+
+static struct rcg_clk byte0_clk_src = {
+	.cmd_rcgr_reg = BYTE0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_byte0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "byte0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 93800000, NOMINAL, 187500000,
+				  HIGH, 188000000),
+		CLK_INIT(byte0_clk_src.c),
+	},
+};
+
+static struct rcg_clk byte1_clk_src = {
+	.cmd_rcgr_reg = BYTE1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_byte0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "byte1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 93800000, NOMINAL, 187500000,
+				  HIGH, 188000000),
+		CLK_INIT(byte1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_edpaux_clk[] = {
+	F_MM(19200000,    cxo,   1,   0,   0),
+	F_END
+};
+
+static struct rcg_clk edpaux_clk_src = {
+	.cmd_rcgr_reg = EDPAUX_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_edpaux_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "edpaux_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 20000000, NOMINAL, 40000000),
+		CLK_INIT(edpaux_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_edplink_clk[] = {
+	F_MDSS(135000000, edppll_270,   2,   0,   0),
+	F_MDSS(270000000, edppll_270,  11,   0,   0),
+	F_END
+};
+
+static struct rcg_clk edplink_clk_src = {
+	.cmd_rcgr_reg = EDPLINK_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_edplink_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "edplink_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 135000000, NOMINAL, 270000000),
+		CLK_INIT(edplink_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_edppixel_clk[] = {
+	F_MDSS(175000000, edppll_350,   2,   0,   0),
+	F_MDSS(350000000, edppll_350,  11,   0,   0),
+	F_END
+};
+
+static struct rcg_clk edppixel_clk_src = {
+	.cmd_rcgr_reg = EDPPIXEL_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_mdss_edppixel_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "edppixel_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 175000000, NOMINAL, 350000000),
+		CLK_INIT(edppixel_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_esc0_1_clk[] = {
+	F_MM(19200000,    cxo,   1,   0,   0),
+	F_END
+};
+
+static struct rcg_clk esc0_clk_src = {
+	.cmd_rcgr_reg = ESC0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_esc0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "esc0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 20000000, NOMINAL, 40000000),
+		CLK_INIT(esc0_clk_src.c),
+	},
+};
+
+static struct rcg_clk esc1_clk_src = {
+	.cmd_rcgr_reg = ESC1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_esc0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "esc1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 20000000, NOMINAL, 40000000),
+		CLK_INIT(esc1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_extpclk_clk[] = {
+	F_MDSS(148500000, hdmipll_297,   2,   0,   0),
+	F_END
+};
+
+static struct rcg_clk extpclk_clk_src = {
+	.cmd_rcgr_reg = EXTPCLK_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_extpclk_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "extpclk_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 148500000, NOMINAL, 297000000),
+		CLK_INIT(extpclk_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_hdmi_clk[] = {
+	F_MDSS(19200000,    cxo,   1,   0,   0),
+	F_END
+};
+
+static struct rcg_clk hdmi_clk_src = {
+	.cmd_rcgr_reg = HDMI_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_hdmi_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "hdmi_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 20000000, NOMINAL, 40000000),
+		CLK_INIT(hdmi_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_pclk0_1_clk[] = {
+	F_MDSS(125000000, dsipll_250,   2,   0,   0),
+	F_MDSS(250000000, dsipll_250,   1,   0,   0),
+	F_END
+};
+
+static struct rcg_clk pclk0_clk_src = {
+	.cmd_rcgr_reg = PCLK0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_mdss_pclk0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "pclk0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 125000000, NOMINAL, 250000000),
+		CLK_INIT(pclk0_clk_src.c),
+	},
+};
+
+static struct rcg_clk pclk1_clk_src = {
+	.cmd_rcgr_reg = PCLK1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_mdss_pclk0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "pclk1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 125000000, NOMINAL, 250000000),
+		CLK_INIT(pclk1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_vsync_clk[] = {
+	F_MDSS(19200000,    cxo,   1,   0,   0),
+	F_END
+};
+
+static struct rcg_clk vsync_clk_src = {
+	.cmd_rcgr_reg = VSYNC_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_vsync_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "vsync_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 20000000, NOMINAL, 40000000),
+		CLK_INIT(vsync_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_venus0_vcodec0_clk[] = {
+	F_MM( 50000000,  gpll0,  12,   0,   0),
+	F_MM(100000000,  gpll0,   6,   0,   0),
+	F_MM(133330000, mmpll0,   6,   0,   0),
+	F_MM(200000000, mmpll0,   4,   0,   0),
+	F_MM(266670000, mmpll0,   3,   0,   0),
+	F_MM(410000000, mmpll3,   2,   0,   0),
+	F_END
+};
+
+static struct rcg_clk vcodec0_clk_src = {
+	.cmd_rcgr_reg = VCODEC0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_venus0_vcodec0_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "vcodec0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000,
+				  HIGH, 410000000),
+		CLK_INIT(vcodec0_clk_src.c),
+	},
+};
+
+static struct branch_clk camss_cci_cci_ahb_clk = {
+	.cbcr_reg = CAMSS_CCI_CCI_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CCI_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_cci_cci_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_cci_cci_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_cci_cci_clk = {
+	.cbcr_reg = CAMSS_CCI_CCI_CBCR,
+	.parent = &cci_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_CCI_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_cci_cci_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_cci_cci_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi0_ahb_clk = {
+	.cbcr_reg = CAMSS_CSI0_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi0_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi0_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi0_clk = {
+	.cbcr_reg = CAMSS_CSI0_CBCR,
+	.parent = &csi0_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi0_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi0phy_clk = {
+	.cbcr_reg = CAMSS_CSI0PHY_CBCR,
+	.parent = &csi0_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI0PHY_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi0phy_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi0phy_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi0pix_clk = {
+	.cbcr_reg = CAMSS_CSI0PIX_CBCR,
+	.parent = &csi0_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI0PIX_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi0pix_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi0pix_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi0rdi_clk = {
+	.cbcr_reg = CAMSS_CSI0RDI_CBCR,
+	.parent = &csi0_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI0RDI_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi0rdi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi0rdi_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi1_ahb_clk = {
+	.cbcr_reg = CAMSS_CSI1_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI1_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi1_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi1_clk = {
+	.cbcr_reg = CAMSS_CSI1_CBCR,
+	.parent = &csi1_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI1_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi1_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi1phy_clk = {
+	.cbcr_reg = CAMSS_CSI1PHY_CBCR,
+	.parent = &csi1_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI1PHY_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi1phy_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi1phy_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi1pix_clk = {
+	.cbcr_reg = CAMSS_CSI1PIX_CBCR,
+	.parent = &csi1_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI1PIX_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi1pix_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi1pix_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi1rdi_clk = {
+	.cbcr_reg = CAMSS_CSI1RDI_CBCR,
+	.parent = &csi1_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI1RDI_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi1rdi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi1rdi_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi2_ahb_clk = {
+	.cbcr_reg = CAMSS_CSI2_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI2_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi2_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi2_clk = {
+	.cbcr_reg = CAMSS_CSI2_CBCR,
+	.parent = &csi2_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI2_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi2_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi2_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi2phy_clk = {
+	.cbcr_reg = CAMSS_CSI2PHY_CBCR,
+	.parent = &csi2_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI2PHY_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi2phy_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi2phy_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi2pix_clk = {
+	.cbcr_reg = CAMSS_CSI2PIX_CBCR,
+	.parent = &csi2_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI2PIX_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi2pix_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi2pix_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi2rdi_clk = {
+	.cbcr_reg = CAMSS_CSI2RDI_CBCR,
+	.parent = &csi2_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI2RDI_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi2rdi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi2rdi_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi3_ahb_clk = {
+	.cbcr_reg = CAMSS_CSI3_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI3_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi3_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi3_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi3_clk = {
+	.cbcr_reg = CAMSS_CSI3_CBCR,
+	.parent = &csi3_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI3_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi3_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi3_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi3phy_clk = {
+	.cbcr_reg = CAMSS_CSI3PHY_CBCR,
+	.parent = &csi3_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI3PHY_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi3phy_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi3phy_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi3pix_clk = {
+	.cbcr_reg = CAMSS_CSI3PIX_CBCR,
+	.parent = &csi3_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI3PIX_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi3pix_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi3pix_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi3rdi_clk = {
+	.cbcr_reg = CAMSS_CSI3RDI_CBCR,
+	.parent = &csi3_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI3RDI_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi3rdi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi3rdi_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi_vfe0_clk = {
+	.cbcr_reg = CAMSS_CSI_VFE0_CBCR,
+	.parent = &vfe0_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI_VFE0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi_vfe0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi_vfe0_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi_vfe1_clk = {
+	.cbcr_reg = CAMSS_CSI_VFE1_CBCR,
+	.parent = &vfe1_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_CSI_VFE1_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi_vfe1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi_vfe1_clk.c),
+	},
+};
+
+static struct branch_clk camss_gp0_clk = {
+	.cbcr_reg = CAMSS_GP0_CBCR,
+	.parent = &mmss_gp0_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_GP0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_gp0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_gp0_clk.c),
+	},
+};
+
+static struct branch_clk camss_gp1_clk = {
+	.cbcr_reg = CAMSS_GP1_CBCR,
+	.parent = &mmss_gp1_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_GP1_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_gp1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_gp1_clk.c),
+	},
+};
+
+static struct branch_clk camss_ispif_ahb_clk = {
+	.cbcr_reg = CAMSS_ISPIF_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_ISPIF_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_ispif_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_ispif_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_jpeg_jpeg0_clk = {
+	.cbcr_reg = CAMSS_JPEG_JPEG0_CBCR,
+	.parent = &jpeg0_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_JPEG_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_jpeg_jpeg0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_jpeg_jpeg0_clk.c),
+	},
+};
+
+static struct branch_clk camss_jpeg_jpeg1_clk = {
+	.cbcr_reg = CAMSS_JPEG_JPEG1_CBCR,
+	.parent = &jpeg1_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_JPEG_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_jpeg_jpeg1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_jpeg_jpeg1_clk.c),
+	},
+};
+
+static struct branch_clk camss_jpeg_jpeg2_clk = {
+	.cbcr_reg = CAMSS_JPEG_JPEG2_CBCR,
+	.parent = &jpeg2_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_JPEG_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_jpeg_jpeg2_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_jpeg_jpeg2_clk.c),
+	},
+};
+
+static struct branch_clk camss_jpeg_jpeg_ahb_clk = {
+	.cbcr_reg = CAMSS_JPEG_JPEG_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_JPEG_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_jpeg_jpeg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_jpeg_jpeg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_jpeg_jpeg_axi_clk = {
+	.cbcr_reg = CAMSS_JPEG_JPEG_AXI_CBCR,
+	.parent = &axi_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_JPEG_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_jpeg_jpeg_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_jpeg_jpeg_axi_clk.c),
+	},
+};
+
+static struct branch_clk camss_jpeg_jpeg_ocmemnoc_clk = {
+	.cbcr_reg = CAMSS_JPEG_JPEG_OCMEMNOC_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_JPEG_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_jpeg_jpeg_ocmemnoc_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_jpeg_jpeg_ocmemnoc_clk.c),
+	},
+};
+
+static struct branch_clk camss_mclk0_clk = {
+	.cbcr_reg = CAMSS_MCLK0_CBCR,
+	.parent = &mclk0_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_MCLK0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_mclk0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_mclk0_clk.c),
+	},
+};
+
+static struct branch_clk camss_mclk1_clk = {
+	.cbcr_reg = CAMSS_MCLK1_CBCR,
+	.parent = &mclk1_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_MCLK1_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_mclk1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_mclk1_clk.c),
+	},
+};
+
+static struct branch_clk camss_mclk2_clk = {
+	.cbcr_reg = CAMSS_MCLK2_CBCR,
+	.parent = &mclk2_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_MCLK2_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_mclk2_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_mclk2_clk.c),
+	},
+};
+
+static struct branch_clk camss_mclk3_clk = {
+	.cbcr_reg = CAMSS_MCLK3_CBCR,
+	.parent = &mclk3_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_MCLK3_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_mclk3_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_mclk3_clk.c),
+	},
+};
+
+static struct branch_clk camss_micro_ahb_clk = {
+	.cbcr_reg = CAMSS_MICRO_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_MICRO_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_micro_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_micro_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_phy0_csi0phytimer_clk = {
+	.cbcr_reg = CAMSS_PHY0_CSI0PHYTIMER_CBCR,
+	.parent = &csi0phytimer_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_PHY0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_phy0_csi0phytimer_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_phy0_csi0phytimer_clk.c),
+	},
+};
+
+static struct branch_clk camss_phy1_csi1phytimer_clk = {
+	.cbcr_reg = CAMSS_PHY1_CSI1PHYTIMER_CBCR,
+	.parent = &csi1phytimer_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_PHY1_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_phy1_csi1phytimer_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_phy1_csi1phytimer_clk.c),
+	},
+};
+
+static struct branch_clk camss_phy2_csi2phytimer_clk = {
+	.cbcr_reg = CAMSS_PHY2_CSI2PHYTIMER_CBCR,
+	.parent = &csi2phytimer_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_PHY2_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_phy2_csi2phytimer_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_phy2_csi2phytimer_clk.c),
+	},
+};
+
+static struct branch_clk camss_top_ahb_clk = {
+	.cbcr_reg = CAMSS_TOP_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_TOP_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_top_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_top_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_vfe_cpp_ahb_clk = {
+	.cbcr_reg = CAMSS_VFE_CPP_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_VFE_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_cpp_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_cpp_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_vfe_cpp_clk = {
+	.cbcr_reg = CAMSS_VFE_CPP_CBCR,
+	.parent = &cpp_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = CAMSS_VFE_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_cpp_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_cpp_clk.c),
+	},
+};
+
+static struct branch_clk camss_vfe_vfe0_clk = {
+	.cbcr_reg = CAMSS_VFE_VFE0_CBCR,
+	.parent = &vfe0_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_VFE_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_vfe0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_vfe0_clk.c),
+	},
+};
+
+static struct branch_clk camss_vfe_vfe1_clk = {
+	.cbcr_reg = CAMSS_VFE_VFE1_CBCR,
+	.parent = &vfe1_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_VFE_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_vfe1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_vfe1_clk.c),
+	},
+};
+
+static struct branch_clk camss_vfe_vfe_ahb_clk = {
+	.cbcr_reg = CAMSS_VFE_VFE_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_VFE_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_vfe_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_vfe_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_vfe_vfe_axi_clk = {
+	.cbcr_reg = CAMSS_VFE_VFE_AXI_CBCR,
+	.parent = &axi_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_VFE_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_vfe_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_vfe_axi_clk.c),
+	},
+};
+
+static struct branch_clk camss_vfe_vfe_ocmemnoc_clk = {
+	.cbcr_reg = CAMSS_VFE_VFE_OCMEMNOC_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = CAMSS_VFE_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_vfe_ocmemnoc_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_vfe_ocmemnoc_clk.c),
+	},
+};
+
+static struct branch_clk mdss_ahb_clk = {
+	.cbcr_reg = MDSS_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_ahb_clk.c),
+	},
+};
+
+static struct branch_clk mdss_axi_clk = {
+	.cbcr_reg = MDSS_AXI_CBCR,
+	.parent = &axi_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_axi_clk.c),
+	},
+};
+
+static struct branch_clk mdss_byte0_clk = {
+	.cbcr_reg = MDSS_BYTE0_CBCR,
+	.parent = &byte0_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_byte0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_byte0_clk.c),
+	},
+};
+
+static struct branch_clk mdss_byte1_clk = {
+	.cbcr_reg = MDSS_BYTE1_CBCR,
+	.parent = &byte1_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_byte1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_byte1_clk.c),
+	},
+};
+
+static struct branch_clk mdss_edpaux_clk = {
+	.cbcr_reg = MDSS_EDPAUX_CBCR,
+	.parent = &edpaux_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_edpaux_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_edpaux_clk.c),
+	},
+};
+
+static struct branch_clk mdss_edplink_clk = {
+	.cbcr_reg = MDSS_EDPLINK_CBCR,
+	.parent = &edplink_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_edplink_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_edplink_clk.c),
+	},
+};
+
+static struct branch_clk mdss_edppixel_clk = {
+	.cbcr_reg = MDSS_EDPPIXEL_CBCR,
+	.parent = &edppixel_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_edppixel_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_edppixel_clk.c),
+	},
+};
+
+static struct branch_clk mdss_esc0_clk = {
+	.cbcr_reg = MDSS_ESC0_CBCR,
+	.parent = &esc0_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_esc0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_esc0_clk.c),
+	},
+};
+
+static struct branch_clk mdss_esc1_clk = {
+	.cbcr_reg = MDSS_ESC1_CBCR,
+	.parent = &esc1_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_esc1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_esc1_clk.c),
+	},
+};
+
+static struct branch_clk mdss_extpclk_clk = {
+	.cbcr_reg = MDSS_EXTPCLK_CBCR,
+	.parent = &extpclk_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_extpclk_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_extpclk_clk.c),
+	},
+};
+
+static struct branch_clk mdss_hdmi_ahb_clk = {
+	.cbcr_reg = MDSS_HDMI_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_hdmi_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_hdmi_ahb_clk.c),
+	},
+};
+
+static struct branch_clk mdss_hdmi_clk = {
+	.cbcr_reg = MDSS_HDMI_CBCR,
+	.parent = &hdmi_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_hdmi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_hdmi_clk.c),
+	},
+};
+
+static struct branch_clk mdss_mdp_clk = {
+	.cbcr_reg = MDSS_MDP_CBCR,
+	.parent = &mdp_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_mdp_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_mdp_clk.c),
+	},
+};
+
+static struct branch_clk mdss_mdp_lut_clk = {
+	.cbcr_reg = MDSS_MDP_LUT_CBCR,
+	.parent = &mdp_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_mdp_lut_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_mdp_lut_clk.c),
+	},
+};
+
+static struct branch_clk mdss_pclk0_clk = {
+	.cbcr_reg = MDSS_PCLK0_CBCR,
+	.parent = &pclk0_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_pclk0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_pclk0_clk.c),
+	},
+};
+
+static struct branch_clk mdss_pclk1_clk = {
+	.cbcr_reg = MDSS_PCLK1_CBCR,
+	.parent = &pclk1_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_pclk1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_pclk1_clk.c),
+	},
+};
+
+static struct branch_clk mdss_vsync_clk = {
+	.cbcr_reg = MDSS_VSYNC_CBCR,
+	.parent = &vsync_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = MDSS_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_vsync_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_vsync_clk.c),
+	},
+};
+
+static struct branch_clk mmss_misc_ahb_clk = {
+	.cbcr_reg = MMSS_MISC_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MMSSNOCAHB_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_misc_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mmss_misc_ahb_clk.c),
+	},
+};
+
+static struct branch_clk mmss_mmssnoc_ahb_clk = {
+	.cbcr_reg = MMSS_MMSSNOC_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MMSSNOCAHB_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_mmssnoc_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mmss_mmssnoc_ahb_clk.c),
+	},
+};
+
+static struct branch_clk mmss_mmssnoc_bto_ahb_clk = {
+	.cbcr_reg = MMSS_MMSSNOC_BTO_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MMSSNOCAHB_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_mmssnoc_bto_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mmss_mmssnoc_bto_ahb_clk.c),
+	},
+};
+
+static struct branch_clk mmss_mmssnoc_axi_clk = {
+	.cbcr_reg = MMSS_MMSSNOC_AXI_CBCR,
+	.parent = &axi_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MMSSNOCAXI_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_mmssnoc_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mmss_mmssnoc_axi_clk.c),
+	},
+};
+
+static struct branch_clk mmss_s0_axi_clk = {
+	.cbcr_reg = MMSS_S0_AXI_CBCR,
+	.parent = &axi_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = MMSSNOCAXI_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_s0_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mmss_s0_axi_clk.c),
+	},
+};
+
+static struct branch_clk venus0_ahb_clk = {
+	.cbcr_reg = VENUS0_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = VENUS0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "venus0_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(venus0_ahb_clk.c),
+	},
+};
+
+static struct branch_clk venus0_axi_clk = {
+	.cbcr_reg = VENUS0_AXI_CBCR,
+	.parent = &axi_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = VENUS0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "venus0_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(venus0_axi_clk.c),
+	},
+};
+
+static struct branch_clk venus0_ocmemnoc_clk = {
+	.cbcr_reg = VENUS0_OCMEMNOC_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = VENUS0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "venus0_ocmemnoc_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(venus0_ocmemnoc_clk.c),
+	},
+};
+
+static struct branch_clk venus0_vcodec0_clk = {
+	.cbcr_reg = VENUS0_VCODEC0_CBCR,
+	.parent = &vcodec0_clk_src.c,
+	.has_sibling = 0,
+	.bcr_reg = VENUS0_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "venus0_vcodec0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(venus0_vcodec0_clk.c),
+	},
+};
+
+static struct branch_clk oxili_gfx3d_clk = {
+	.cbcr_reg = OXILI_GFX3D_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = OXILI_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "oxili_gfx3d_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(oxili_gfx3d_clk.c),
+	},
+};
+
+static struct branch_clk oxilicx_ahb_clk = {
+	.cbcr_reg = OXILICX_AHB_CBCR,
+	.parent = &ahb_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = OXILICX_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "oxilicx_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(oxilicx_ahb_clk.c),
+	},
+};
+
+static struct branch_clk oxilicx_axi_clk = {
+	.cbcr_reg = OXILICX_AXI_CBCR,
+	.parent = &axi_clk_src.c,
+	.has_sibling = 1,
+	.bcr_reg = OXILICX_BCR,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "oxilicx_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(oxilicx_axi_clk.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_audio_core_slimbus_core_clock[] = {
+	F_LPASS(28800000, lpapll0, 1, 15, 256),
+	F_END
+};
+
+static struct rcg_clk audio_core_slimbus_core_clk_src = {
+	.cmd_rcgr_reg = SLIMBUS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_slimbus_core_clock,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_slimbus_core_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 70000000, NOMINAL, 140000000),
+		CLK_INIT(audio_core_slimbus_core_clk_src.c),
+	},
+};
+
+static struct branch_clk audio_core_slimbus_core_clk = {
+	.cbcr_reg = AUDIO_CORE_SLIMBUS_CORE_CBCR,
+	.parent = &audio_core_slimbus_core_clk_src.c,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_slimbus_core_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_slimbus_core_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_slimbus_lfabif_clk = {
+	.cbcr_reg = AUDIO_CORE_SLIMBUS_LFABIF_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_slimbus_lfabif_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_slimbus_lfabif_clk.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_audio_core_lpaif_clock[] = {
+	F_LPASS(  512000, lpapll0, 16, 1, 60),
+	F_LPASS(  768000, lpapll0, 16, 1, 40),
+	F_LPASS( 1024000, lpapll0, 16, 1, 30),
+	F_LPASS( 1536000, lpapll0, 16, 1, 10),
+	F_LPASS( 2048000, lpapll0, 16, 1, 15),
+	F_LPASS( 3072000, lpapll0, 16, 1, 10),
+	F_LPASS( 4096000, lpapll0, 15, 1,  8),
+	F_LPASS( 6144000, lpapll0, 10, 1,  8),
+	F_LPASS( 8192000, lpapll0, 15, 1,  4),
+	F_LPASS(12288000, lpapll0, 10, 1,  4),
+	F_END
+};
+
+static struct rcg_clk audio_core_lpaif_codec_spkr_clk_src = {
+	.cmd_rcgr_reg = LPAIF_SPKR_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_clock,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_codec_spkr_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
+		CLK_INIT(audio_core_lpaif_codec_spkr_clk_src.c),
+	},
+};
+
+static struct rcg_clk audio_core_lpaif_pri_clk_src = {
+	.cmd_rcgr_reg = LPAIF_PRI_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_clock,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pri_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
+		CLK_INIT(audio_core_lpaif_pri_clk_src.c),
+	},
+};
+
+static struct rcg_clk audio_core_lpaif_sec_clk_src = {
+	.cmd_rcgr_reg = LPAIF_SEC_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_clock,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_sec_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
+		CLK_INIT(audio_core_lpaif_sec_clk_src.c),
+	},
+};
+
+static struct rcg_clk audio_core_lpaif_ter_clk_src = {
+	.cmd_rcgr_reg = LPAIF_TER_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_clock,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_ter_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
+		CLK_INIT(audio_core_lpaif_ter_clk_src.c),
+	},
+};
+
+static struct rcg_clk audio_core_lpaif_quad_clk_src = {
+	.cmd_rcgr_reg = LPAIF_QUAD_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_clock,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_quad_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
+		CLK_INIT(audio_core_lpaif_quad_clk_src.c),
+	},
+};
+
+static struct rcg_clk audio_core_lpaif_pcm0_clk_src = {
+	.cmd_rcgr_reg = LPAIF_PCM0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_clock,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pcm0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
+		CLK_INIT(audio_core_lpaif_pcm0_clk_src.c),
+	},
+};
+
+static struct rcg_clk audio_core_lpaif_pcm1_clk_src = {
+	.cmd_rcgr_reg = LPAIF_PCM1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_clock,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pcm1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
+		CLK_INIT(audio_core_lpaif_pcm1_clk_src.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_codec_spkr_osr_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_OSR_CBCR,
+	.parent = &audio_core_lpaif_codec_spkr_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_codec_spkr_clk_src",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_codec_spkr_clk_src.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_codec_spkr_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_EBIT_CBCR,
+	.parent = &audio_core_lpaif_codec_spkr_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_codec_spkr_clk_src",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_codec_spkr_clk_src.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_codec_spkr_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_IBIT_CBCR,
+	.parent = &audio_core_lpaif_codec_spkr_clk_src.c,
+	.has_sibling = 1,
+	.max_div = 16,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_codec_spkr_clk_src",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_codec_spkr_clk_src.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pri_osr_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_OSR_CBCR,
+	.parent = &audio_core_lpaif_pri_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pri_osr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pri_osr_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pri_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_EBIT_CBCR,
+	.parent = &audio_core_lpaif_pri_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pri_ebit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pri_ebit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pri_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_IBIT_CBCR,
+	.parent = &audio_core_lpaif_pri_clk_src.c,
+	.has_sibling = 1,
+	.max_div = 16,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pri_ibit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pri_ibit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_sec_osr_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_OSR_CBCR,
+	.parent = &audio_core_lpaif_sec_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_sec_osr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_sec_osr_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_sec_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_EBIT_CBCR,
+	.parent = &audio_core_lpaif_sec_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_sec_ebit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_sec_ebit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_sec_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_IBIT_CBCR,
+	.parent = &audio_core_lpaif_sec_clk_src.c,
+	.has_sibling = 1,
+	.max_div = 16,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_sec_ibit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_sec_ibit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_ter_osr_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_TER_OSR_CBCR,
+	.parent = &audio_core_lpaif_ter_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_ter_osr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_ter_osr_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_ter_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_TER_EBIT_CBCR,
+	.parent = &audio_core_lpaif_ter_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_ter_ebit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_ter_ebit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_ter_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_TER_IBIT_CBCR,
+	.parent = &audio_core_lpaif_ter_clk_src.c,
+	.has_sibling = 1,
+	.max_div = 16,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_ter_ibit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_ter_ibit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_quad_osr_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_OSR_CBCR,
+	.parent = &audio_core_lpaif_quad_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_quad_osr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_quad_osr_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_quad_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_EBIT_CBCR,
+	.parent = &audio_core_lpaif_quad_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_quad_ebit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_quad_ebit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_quad_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_IBIT_CBCR,
+	.parent = &audio_core_lpaif_quad_clk_src.c,
+	.has_sibling = 1,
+	.max_div = 16,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_quad_ibit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_quad_ibit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pcm0_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PCM0_EBIT_CBCR,
+	.parent = &audio_core_lpaif_pcm0_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pcm0_ebit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pcm0_ebit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pcm0_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PCM0_IBIT_CBCR,
+	.parent = &audio_core_lpaif_pcm0_clk_src.c,
+	.has_sibling = 1,
+	.max_div = 16,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pcm0_ibit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pcm0_ibit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pcm1_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PCM1_EBIT_CBCR,
+	.parent = &audio_core_lpaif_pcm1_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pcm1_ebit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pcm1_ebit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pcm1_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PCM1_IBIT_CBCR,
+	.parent = &audio_core_lpaif_pcm1_clk_src.c,
+	.has_sibling = 1,
+	.max_div = 16,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pcm1_ibit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pcm1_ibit_clk.c),
+	},
+};
+
+static struct branch_clk q6ss_ahb_lfabif_clk = {
+	.cbcr_reg = LPASS_Q6SS_AHB_LFABIF_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "q6ss_ahb_lfabif_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(q6ss_ahb_lfabif_clk.c),
+	},
+};
+
+static struct branch_clk q6ss_xo_clk = {
+	.cbcr_reg = LPASS_Q6SS_XO_CBCR,
+	.bcr_reg = LPASS_Q6SS_BCR,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "q6ss_xo_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(q6ss_xo_clk.c),
+	},
+};
+
+static struct branch_clk mss_xo_q6_clk = {
+	.cbcr_reg = MSS_XO_Q6_CBCR,
+	.bcr_reg = MSS_Q6SS_BCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MSS_BASE],
+	.c = {
+		.dbg_name = "mss_xo_q6_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mss_xo_q6_clk.c),
+		.depends = &gcc_mss_cfg_ahb_clk.c,
+	},
+};
+
+static struct branch_clk mss_bus_q6_clk = {
+	.cbcr_reg = MSS_BUS_Q6_CBCR,
+	.bcr_reg = MSS_Q6SS_BCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MSS_BASE],
+	.c = {
+		.dbg_name = "mss_bus_q6_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mss_bus_q6_clk.c),
+		.depends = &gcc_mss_cfg_ahb_clk.c,
+	},
+};
+
+#ifdef CONFIG_DEBUG_FS
+
+struct measure_mux_entry {
+	struct clk *c;
+	int base;
+	u32 debug_mux;
+};
+
+struct measure_mux_entry measure_mux[] = {
+	{&gcc_bam_dma_ahb_clk.c,		GCC_BASE, 0x00e8},
+	{&gcc_blsp1_ahb_clk.c,			GCC_BASE, 0x0090},
+	{&gcc_blsp1_qup1_i2c_apps_clk.c,	GCC_BASE, 0x0093},
+	{&gcc_blsp1_qup1_spi_apps_clk.c,	GCC_BASE, 0x0092},
+	{&gcc_blsp1_qup2_i2c_apps_clk.c,	GCC_BASE, 0x0098},
+	{&gcc_blsp1_qup2_spi_apps_clk.c,	GCC_BASE, 0x0096},
+	{&gcc_blsp1_qup3_i2c_apps_clk.c,	GCC_BASE, 0x009c},
+	{&gcc_blsp1_qup3_spi_apps_clk.c,	GCC_BASE, 0x009b},
+	{&gcc_blsp1_qup4_i2c_apps_clk.c,	GCC_BASE, 0x00a1},
+	{&gcc_blsp1_qup4_spi_apps_clk.c,	GCC_BASE, 0x00a0},
+	{&gcc_blsp1_qup5_i2c_apps_clk.c,	GCC_BASE, 0x00a5},
+	{&gcc_blsp1_qup5_spi_apps_clk.c,	GCC_BASE, 0x00a4},
+	{&gcc_blsp1_qup6_i2c_apps_clk.c,	GCC_BASE, 0x00aa},
+	{&gcc_blsp1_qup6_spi_apps_clk.c,	GCC_BASE, 0x00a9},
+	{&gcc_blsp1_uart1_apps_clk.c,		GCC_BASE, 0x0094},
+	{&gcc_blsp1_uart2_apps_clk.c,		GCC_BASE, 0x0099},
+	{&gcc_blsp1_uart3_apps_clk.c,		GCC_BASE, 0x009d},
+	{&gcc_blsp1_uart4_apps_clk.c,		GCC_BASE, 0x00a2},
+	{&gcc_blsp1_uart5_apps_clk.c,		GCC_BASE, 0x00a6},
+	{&gcc_blsp1_uart6_apps_clk.c,		GCC_BASE, 0x00ab},
+	{&gcc_blsp2_ahb_clk.c,			GCC_BASE, 0x00b0},
+	{&gcc_blsp2_qup1_i2c_apps_clk.c,	GCC_BASE, 0x00b3},
+	{&gcc_blsp2_qup1_spi_apps_clk.c,	GCC_BASE, 0x00b2},
+	{&gcc_blsp2_qup2_i2c_apps_clk.c,	GCC_BASE, 0x00b8},
+	{&gcc_blsp2_qup2_spi_apps_clk.c,	GCC_BASE, 0x00b6},
+	{&gcc_blsp2_qup3_i2c_apps_clk.c,	GCC_BASE, 0x00bc},
+	{&gcc_blsp2_qup3_spi_apps_clk.c,	GCC_BASE, 0x00bb},
+	{&gcc_blsp2_qup4_i2c_apps_clk.c,	GCC_BASE, 0x00c1},
+	{&gcc_blsp2_qup4_spi_apps_clk.c,	GCC_BASE, 0x00c0},
+	{&gcc_blsp2_qup5_i2c_apps_clk.c,	GCC_BASE, 0x00c5},
+	{&gcc_blsp2_qup5_spi_apps_clk.c,	GCC_BASE, 0x00c4},
+	{&gcc_blsp2_qup6_i2c_apps_clk.c,	GCC_BASE, 0x00ca},
+	{&gcc_blsp2_qup6_spi_apps_clk.c,	GCC_BASE, 0x00c9},
+	{&gcc_blsp2_uart1_apps_clk.c,		GCC_BASE, 0x00b4},
+	{&gcc_blsp2_uart2_apps_clk.c,		GCC_BASE, 0x00b9},
+	{&gcc_blsp2_uart3_apps_clk.c,		GCC_BASE, 0x00bd},
+	{&gcc_blsp2_uart4_apps_clk.c,		GCC_BASE, 0x00c2},
+	{&gcc_blsp2_uart5_apps_clk.c,		GCC_BASE, 0x00c6},
+	{&gcc_blsp2_uart6_apps_clk.c,		GCC_BASE, 0x00cb},
+	{&gcc_boot_rom_ahb_clk.c,		GCC_BASE, 0x0100},
+	{&gcc_mss_cfg_ahb_clk.c,		GCC_BASE, 0x0030},
+	{&gcc_ce1_clk.c,			GCC_BASE, 0x0140},
+	{&gcc_ce2_clk.c,			GCC_BASE, 0x0148},
+	{&gcc_pdm2_clk.c,			GCC_BASE, 0x00da},
+	{&gcc_pdm_ahb_clk.c,			GCC_BASE, 0x00d8},
+	{&gcc_prng_ahb_clk.c,			GCC_BASE, 0x00e0},
+	{&gcc_sdcc1_ahb_clk.c,			GCC_BASE, 0x0071},
+	{&gcc_sdcc1_apps_clk.c,			GCC_BASE, 0x0070},
+	{&gcc_sdcc2_ahb_clk.c,			GCC_BASE, 0x0079},
+	{&gcc_sdcc2_apps_clk.c,			GCC_BASE, 0x0078},
+	{&gcc_sdcc3_ahb_clk.c,			GCC_BASE, 0x0081},
+	{&gcc_sdcc3_apps_clk.c,			GCC_BASE, 0x0080},
+	{&gcc_sdcc4_ahb_clk.c,			GCC_BASE, 0x0089},
+	{&gcc_sdcc4_apps_clk.c,			GCC_BASE, 0x0088},
+	{&gcc_tsif_ahb_clk.c,			GCC_BASE, 0x00f0},
+	{&gcc_tsif_ref_clk.c,			GCC_BASE, 0x00f1},
+	{&gcc_usb30_master_clk.c,		GCC_BASE, 0x0050},
+	{&gcc_usb30_mock_utmi_clk.c,		GCC_BASE, 0x0052},
+	{&gcc_usb_hs_ahb_clk.c,			GCC_BASE, 0x0069},
+	{&gcc_usb_hs_system_clk.c,		GCC_BASE, 0x0068},
+	{&gcc_usb_hsic_ahb_clk.c,		GCC_BASE, 0x0060},
+	{&gcc_usb_hsic_clk.c,			GCC_BASE, 0x0062},
+	{&gcc_usb_hsic_io_cal_clk.c,		GCC_BASE, 0x0063},
+	{&gcc_usb_hsic_system_clk.c,		GCC_BASE, 0x0061},
+	{&mmss_mmssnoc_ahb_clk.c,		MMSS_BASE, 0x0001},
+	{&mmss_mmssnoc_axi_clk.c,		MMSS_BASE, 0x0004},
+	{&camss_cci_cci_ahb_clk.c,		MMSS_BASE, 0x002e},
+	{&camss_cci_cci_clk.c,			MMSS_BASE, 0x002d},
+	{&camss_csi0_ahb_clk.c,			MMSS_BASE, 0x0042},
+	{&camss_csi0_clk.c,			MMSS_BASE, 0x0041},
+	{&camss_csi0phy_clk.c,			MMSS_BASE, 0x0043},
+	{&camss_csi0pix_clk.c,			MMSS_BASE, 0x0045},
+	{&camss_csi0rdi_clk.c,			MMSS_BASE, 0x0044},
+	{&camss_csi1_ahb_clk.c,			MMSS_BASE, 0x0047},
+	{&camss_csi1_clk.c,			MMSS_BASE, 0x0046},
+	{&camss_csi1phy_clk.c,			MMSS_BASE, 0x0048},
+	{&camss_csi1pix_clk.c,			MMSS_BASE, 0x004a},
+	{&camss_csi1rdi_clk.c,			MMSS_BASE, 0x0049},
+	{&camss_csi2_ahb_clk.c,			MMSS_BASE, 0x004c},
+	{&camss_csi2_clk.c,			MMSS_BASE, 0x004b},
+	{&camss_csi2phy_clk.c,			MMSS_BASE, 0x004d},
+	{&camss_csi2pix_clk.c,			MMSS_BASE, 0x004f},
+	{&camss_csi2rdi_clk.c,			MMSS_BASE, 0x004e},
+	{&camss_csi3_ahb_clk.c,			MMSS_BASE, 0x0051},
+	{&camss_csi3_clk.c,			MMSS_BASE, 0x0050},
+	{&camss_csi3phy_clk.c,			MMSS_BASE, 0x0052},
+	{&camss_csi3pix_clk.c,			MMSS_BASE, 0x0054},
+	{&camss_csi3rdi_clk.c,			MMSS_BASE, 0x0053},
+	{&camss_csi_vfe0_clk.c,			MMSS_BASE, 0x003f},
+	{&camss_csi_vfe1_clk.c,			MMSS_BASE, 0x0040},
+	{&camss_gp0_clk.c,			MMSS_BASE, 0x0027},
+	{&camss_gp1_clk.c,			MMSS_BASE, 0x0028},
+	{&camss_ispif_ahb_clk.c,		MMSS_BASE, 0x0055},
+	{&camss_jpeg_jpeg0_clk.c,		MMSS_BASE, 0x0032},
+	{&camss_jpeg_jpeg1_clk.c,		MMSS_BASE, 0x0033},
+	{&camss_jpeg_jpeg2_clk.c,		MMSS_BASE, 0x0034},
+	{&camss_jpeg_jpeg_ahb_clk.c,		MMSS_BASE, 0x0035},
+	{&camss_jpeg_jpeg_axi_clk.c,		MMSS_BASE, 0x0036},
+	{&camss_jpeg_jpeg_ocmemnoc_clk.c,	MMSS_BASE, 0x0037},
+	{&camss_mclk0_clk.c,			MMSS_BASE, 0x0029},
+	{&camss_mclk1_clk.c,			MMSS_BASE, 0x002a},
+	{&camss_mclk2_clk.c,			MMSS_BASE, 0x002b},
+	{&camss_mclk3_clk.c,			MMSS_BASE, 0x002c},
+	{&camss_micro_ahb_clk.c,		MMSS_BASE, 0x0026},
+	{&camss_phy0_csi0phytimer_clk.c,	MMSS_BASE, 0x002f},
+	{&camss_phy1_csi1phytimer_clk.c,	MMSS_BASE, 0x0030},
+	{&camss_phy2_csi2phytimer_clk.c,	MMSS_BASE, 0x0031},
+	{&camss_top_ahb_clk.c,			MMSS_BASE, 0x0025},
+	{&camss_vfe_cpp_ahb_clk.c,		MMSS_BASE, 0x003b},
+	{&camss_vfe_cpp_clk.c,			MMSS_BASE, 0x003a},
+	{&camss_vfe_vfe0_clk.c,			MMSS_BASE, 0x0038},
+	{&camss_vfe_vfe1_clk.c,			MMSS_BASE, 0x0039},
+	{&camss_vfe_vfe_ahb_clk.c,		MMSS_BASE, 0x003c},
+	{&camss_vfe_vfe_axi_clk.c,		MMSS_BASE, 0x003d},
+	{&camss_vfe_vfe_ocmemnoc_clk.c,		MMSS_BASE, 0x003e},
+	{&mdss_ahb_clk.c,			MMSS_BASE, 0x0022},
+	{&mdss_hdmi_clk.c,			MMSS_BASE, 0x001d},
+	{&mdss_mdp_clk.c,			MMSS_BASE, 0x0014},
+	{&mdss_mdp_lut_clk.c,			MMSS_BASE, 0x0015},
+	{&mdss_axi_clk.c,			MMSS_BASE, 0x0024},
+	{&mdss_vsync_clk.c,			MMSS_BASE, 0x001c},
+	{&mdss_esc0_clk.c,			MMSS_BASE, 0x0020},
+	{&mdss_esc1_clk.c,			MMSS_BASE, 0x0021},
+	{&mdss_edpaux_clk.c,			MMSS_BASE, 0x001b},
+	{&mdss_byte0_clk.c,			MMSS_BASE, 0x001e},
+	{&mdss_byte1_clk.c,			MMSS_BASE, 0x001f},
+	{&mdss_edplink_clk.c,			MMSS_BASE, 0x001a},
+	{&mdss_edppixel_clk.c,			MMSS_BASE, 0x0019},
+	{&mdss_extpclk_clk.c,			MMSS_BASE, 0x0018},
+	{&mdss_hdmi_ahb_clk.c,			MMSS_BASE, 0x0023},
+	{&mdss_pclk0_clk.c,			MMSS_BASE, 0x0016},
+	{&mdss_pclk1_clk.c,			MMSS_BASE, 0x0017},
+	{&audio_core_lpaif_pri_clk_src.c,	LPASS_BASE, 0x0017},
+	{&audio_core_lpaif_sec_clk_src.c,	LPASS_BASE, 0x0016},
+	{&audio_core_lpaif_ter_clk_src.c,	LPASS_BASE, 0x0015},
+	{&audio_core_lpaif_quad_clk_src.c,	LPASS_BASE, 0x0014},
+	{&audio_core_lpaif_pcm0_clk_src.c,	LPASS_BASE, 0x0013},
+	{&audio_core_lpaif_pcm1_clk_src.c,	LPASS_BASE, 0x0012},
+	{&audio_core_slimbus_core_clk.c,	LPASS_BASE, 0x003d},
+	{&audio_core_slimbus_lfabif_clk.c,	LPASS_BASE, 0x003e},
+	{&q6ss_xo_clk.c,			LPASS_BASE, 0x002b},
+	{&q6ss_ahb_lfabif_clk.c,		LPASS_BASE, 0x001e},
+	{&mss_bus_q6_clk.c,			MSS_BASE, 0x003c},
+	{&mss_xo_q6_clk.c,			MSS_BASE, 0x0007},
+
+	{&dummy_clk,				N_BASES,   0x0000},
+};
+
+static int measure_clk_set_parent(struct clk *c, struct clk *parent)
+{
+	struct measure_clk *clk = to_measure_clk(c);
+	unsigned long flags;
+	u32 regval, clk_sel, i;
+
+	if (!parent)
+		return -EINVAL;
+
+	for (i = 0; i < (ARRAY_SIZE(measure_mux) - 1); i++)
+		if (measure_mux[i].c == parent)
+			break;
+
+	if (measure_mux[i].c == &dummy_clk)
+		return -EINVAL;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	/*
+	 * Program the test vector, measurement period (sample_ticks)
+	 * and scaling multiplier.
+	 */
+	clk->sample_ticks = 0x10000;
+	clk->multiplier = 1;
+
+	writel_relaxed(0, MSS_REG_BASE(MSS_DEBUG_CLK_CTL_REG));
+	writel_relaxed(0, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL_REG));
+	writel_relaxed(0, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL_REG));
+	writel_relaxed(0, GCC_REG_BASE(GCC_DEBUG_CLK_CTL_REG));
+
+	switch (measure_mux[i].base) {
+
+	case GCC_BASE:
+		clk_sel = measure_mux[i].debug_mux;
+		break;
+
+	case MMSS_BASE:
+		clk_sel = 0x02C;
+		regval = BVAL(11, 0, measure_mux[i].debug_mux);
+		writel_relaxed(regval, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL_REG));
+
+		/* Activate debug clock output */
+		regval |= BIT(16);
+		writel_relaxed(regval, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL_REG));
+		break;
+
+	case LPASS_BASE:
+		clk_sel = 0x169;
+		regval = BVAL(11, 0, measure_mux[i].debug_mux);
+		writel_relaxed(regval, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL_REG));
+
+		/* Activate debug clock output */
+		regval |= BIT(16);
+		writel_relaxed(regval, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL_REG));
+		break;
+
+	case MSS_BASE:
+		clk_sel = 0x32;
+		regval = BVAL(5, 0, measure_mux[i].debug_mux);
+		writel_relaxed(regval, MSS_REG_BASE(MSS_DEBUG_CLK_CTL_REG));
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Set debug mux clock index */
+	regval = BVAL(8, 0, clk_sel);
+	writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL_REG));
+
+	/* Activate debug clock output */
+	regval |= BIT(16);
+	writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL_REG));
+
+	/* Make sure test vector is set before starting measurements. */
+	mb();
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	return 0;
+}
+
+/* Sample clock for 'ticks' reference clock ticks. */
+static u32 run_measurement(unsigned ticks)
+{
+	/* Stop counters and set the XO4 counter start value. */
+	writel_relaxed(ticks, GCC_REG_BASE(CLOCK_FRQ_MEASURE_CTL_REG));
+
+	/* Wait for timer to become ready. */
+	while ((readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS_REG)) &
+			BIT(25)) != 0)
+		cpu_relax();
+
+	/* Run measurement and wait for completion. */
+	writel_relaxed(BIT(20)|ticks, GCC_REG_BASE(CLOCK_FRQ_MEASURE_CTL_REG));
+	while ((readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS_REG)) &
+			BIT(25)) == 0)
+		cpu_relax();
+
+	/* Return measured ticks. */
+	return readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS_REG)) &
+				BM(24, 0);
+}
+
+/*
+ * Perform a hardware rate measurement for a given clock.
+ * FOR DEBUG USE ONLY: Measurements take ~15 ms!
+ */
+static unsigned long measure_clk_get_rate(struct clk *c)
+{
+	unsigned long flags;
+	u32 gcc_xo4_reg_backup;
+	u64 raw_count_short, raw_count_full;
+	struct measure_clk *clk = to_measure_clk(c);
+	unsigned ret;
+
+	ret = clk_prepare_enable(&cxo_clk_src.c);
+	if (ret) {
+		pr_warning("CXO clock failed to enable. Can't measure\n");
+		return 0;
+	}
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+
+	/* Enable CXO/4 and RINGOSC branch. */
+	gcc_xo4_reg_backup = readl_relaxed(GCC_REG_BASE(GCC_XO_DIV4_CBCR_REG));
+	writel_relaxed(0x1, GCC_REG_BASE(GCC_XO_DIV4_CBCR_REG));
+
+	/*
+	 * The ring oscillator counter will not reset if the measured clock
+	 * is not running.  To detect this, run a short measurement before
+	 * the full measurement.  If the raw results of the two are the same
+	 * then the clock must be off.
+	 */
+
+	/* Run a short measurement. (~1 ms) */
+	raw_count_short = run_measurement(0x1000);
+	/* Run a full measurement. (~14 ms) */
+	raw_count_full = run_measurement(clk->sample_ticks);
+
+	writel_relaxed(gcc_xo4_reg_backup, GCC_REG_BASE(GCC_XO_DIV4_CBCR_REG));
+
+	/* Return 0 if the clock is off. */
+	if (raw_count_full == raw_count_short) {
+		ret = 0;
+	} else {
+		/* Compute rate in Hz. */
+		raw_count_full = ((raw_count_full * 10) + 15) * 4800000;
+		do_div(raw_count_full, ((clk->sample_ticks * 10) + 35));
+		ret = (raw_count_full * clk->multiplier);
+	}
+
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	clk_disable_unprepare(&cxo_clk_src.c);
+
+	return ret;
+}
+#else /* !CONFIG_DEBUG_FS */
+static int measure_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	return -EINVAL;
+}
+
+static unsigned long measure_clk_get_rate(struct clk *clk)
+{
+	return 0;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static struct clk_ops measure_clk_ops = {
+	.set_parent = measure_clk_set_parent,
+	.get_rate = measure_clk_get_rate,
+};
+
+static struct measure_clk measure_clk = {
+	.c = {
+		.dbg_name = "measure_clk",
+		.ops = &measure_clk_ops,
+		CLK_INIT(measure_clk.c),
+	},
+	.multiplier = 1,
+};
+
+static struct clk_lookup msm_clocks_copper[] = {
+	CLK_LOOKUP("xo",	cxo_clk_src.c,	"msm_otg"),
+	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil-q6v5-lpass"),
+	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
+
+	CLK_LOOKUP("dma_bam_pclk", gcc_bam_dma_ahb_clk.c, "msm_sps"),
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "msm_serial_hsl.0"),
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "spi_qsd.1"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, "spi_qsd.1"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup3_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup4_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup4_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup5_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup5_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup6_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup6_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart1_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart2_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart3_apps_clk.c, "msm_serial_hsl.0"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart4_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart5_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart6_apps_clk.c, ""),
+
+	CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f9966000.i2c"),
+	CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f995e000.serial"),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup1_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup1_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup2_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup2_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup3_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup3_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup4_i2c_apps_clk.c, "f9966000.i2c"),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup4_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup5_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup5_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup6_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup6_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_uart1_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_uart2_apps_clk.c, "f995e000.serial"),
+	CLK_LOOKUP("core_clk", gcc_blsp2_uart3_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_uart4_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_uart5_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp2_uart6_apps_clk.c, ""),
+
+	CLK_LOOKUP("core_clk", gcc_ce1_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_ce2_clk.c, ""),
+	CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, ""),
+	CLK_LOOKUP("iface_clk", gcc_ce2_ahb_clk.c, ""),
+	CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, ""),
+	CLK_LOOKUP("bus_clk", gcc_ce2_axi_clk.c, ""),
+
+	CLK_LOOKUP("core_clk", gcc_gp1_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_gp2_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_gp3_clk.c, ""),
+
+	CLK_LOOKUP("core_clk", gcc_pdm2_clk.c, ""),
+	CLK_LOOKUP("iface_clk", gcc_pdm_ahb_clk.c, ""),
+	CLK_LOOKUP("iface_clk", gcc_prng_ahb_clk.c, ""),
+
+	CLK_LOOKUP("iface_clk", gcc_sdcc1_ahb_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("core_clk", gcc_sdcc1_apps_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("iface_clk", gcc_sdcc2_ahb_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("core_clk", gcc_sdcc2_apps_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("iface_clk", gcc_sdcc3_ahb_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("core_clk", gcc_sdcc3_apps_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("iface_clk", gcc_sdcc4_ahb_clk.c, "msm_sdcc.4"),
+	CLK_LOOKUP("core_clk", gcc_sdcc4_apps_clk.c, "msm_sdcc.4"),
+
+	CLK_LOOKUP("iface_clk", gcc_tsif_ahb_clk.c, ""),
+	CLK_LOOKUP("ref_clk", gcc_tsif_ref_clk.c, ""),
+
+	CLK_LOOKUP("core_clk", gcc_usb30_master_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_usb30_mock_utmi_clk.c, ""),
+	CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c, "msm_otg"),
+	CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c, ""),
+	CLK_LOOKUP("iface_clk", gcc_usb_hsic_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_usb_hsic_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_usb_hsic_io_cal_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_usb_hsic_system_clk.c, ""),
+
+	/* Multimedia clocks */
+	CLK_LOOKUP("bus_clk_src", axi_clk_src.c, ""),
+	CLK_LOOKUP("bus_clk_src", ahb_clk_src.c, ""),
+	CLK_LOOKUP("bus_clk", mmss_mmssnoc_ahb_clk.c, ""),
+	CLK_LOOKUP("bus_clk", mmss_mmssnoc_axi_clk.c, ""),
+	CLK_LOOKUP("core_clk", mdss_edpaux_clk.c, ""),
+	CLK_LOOKUP("core_clk", mdss_edppixel_clk.c, ""),
+	CLK_LOOKUP("core_clk", mdss_esc0_clk.c, ""),
+	CLK_LOOKUP("core_clk", mdss_esc1_clk.c, ""),
+	CLK_LOOKUP("iface_clk", mdss_hdmi_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk", mdss_hdmi_clk.c, ""),
+	CLK_LOOKUP("core_clk", mdss_mdp_clk.c, ""),
+	CLK_LOOKUP("core_clk", mdss_mdp_lut_clk.c, ""),
+	CLK_LOOKUP("core_clk", mdp_clk_src.c, ""),
+	CLK_LOOKUP("core_clk", mdss_vsync_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_cci_cci_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_cci_cci_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_csi0_ahb_clk.c, ""),
+	CLK_LOOKUP("camss_csi0_clk", camss_csi0_clk.c, ""),
+	CLK_LOOKUP("camss_csi0phy_clk", camss_csi0phy_clk.c, ""),
+	CLK_LOOKUP("camss_csi0pix_clk", camss_csi0pix_clk.c, ""),
+	CLK_LOOKUP("camss_csi0rdi_clk", camss_csi0rdi_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_csi1_ahb_clk.c, ""),
+	CLK_LOOKUP("camss_csi1_clk", camss_csi1_clk.c, ""),
+	CLK_LOOKUP("camss_csi1phy_clk", camss_csi1phy_clk.c, ""),
+	CLK_LOOKUP("camss_csi1pix_clk", camss_csi1pix_clk.c, ""),
+	CLK_LOOKUP("camss_csi1rdi_clk", camss_csi1rdi_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_csi2_ahb_clk.c, ""),
+	CLK_LOOKUP("camss_csi2_clk", camss_csi2_clk.c, ""),
+	CLK_LOOKUP("camss_csi2phy_clk", camss_csi2phy_clk.c, ""),
+	CLK_LOOKUP("camss_csi2pix_clk", camss_csi2pix_clk.c, ""),
+	CLK_LOOKUP("camss_csi2rdi_clk", camss_csi2rdi_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_csi3_ahb_clk.c, ""),
+	CLK_LOOKUP("camss_csi3_clk", camss_csi3_clk.c, ""),
+	CLK_LOOKUP("camss_csi3phy_clk", camss_csi3phy_clk.c, ""),
+	CLK_LOOKUP("camss_csi3pix_clk", camss_csi3pix_clk.c, ""),
+	CLK_LOOKUP("camss_csi3rdi_clk", camss_csi3rdi_clk.c, ""),
+	CLK_LOOKUP("camss_csi0_clk_src", csi0_clk_src.c, ""),
+	CLK_LOOKUP("camss_csi1_clk_src", csi1_clk_src.c, ""),
+	CLK_LOOKUP("camss_csi2_clk_src", csi2_clk_src.c, ""),
+	CLK_LOOKUP("camss_csi3_clk_src", csi3_clk_src.c, ""),
+	CLK_LOOKUP("camss_csi_vfe0_clk", camss_csi_vfe0_clk.c, ""),
+	CLK_LOOKUP("camss_csi_vfe1_clk", camss_csi_vfe1_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_gp0_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_gp1_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_ispif_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_jpeg_jpeg0_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_jpeg_jpeg1_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_jpeg_jpeg2_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_jpeg_jpeg_ahb_clk.c, ""),
+	CLK_LOOKUP("bus_clk", camss_jpeg_jpeg_axi_clk.c, ""),
+	CLK_LOOKUP("bus_clk", camss_jpeg_jpeg_ocmemnoc_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_mclk0_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_mclk1_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_mclk2_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_mclk3_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_micro_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_phy0_csi0phytimer_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_phy1_csi1phytimer_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_phy2_csi2phytimer_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_top_ahb_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_vfe_cpp_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk", camss_vfe_cpp_clk.c, ""),
+	CLK_LOOKUP("camss_vfe_vfe0_clk", camss_vfe_vfe0_clk.c, ""),
+	CLK_LOOKUP("camss_vfe_vfe1_clk", camss_vfe_vfe1_clk.c, ""),
+	CLK_LOOKUP("vfe0_clk_src", vfe0_clk_src.c, ""),
+	CLK_LOOKUP("vfe1_clk_src", vfe1_clk_src.c, ""),
+	CLK_LOOKUP("iface_clk", camss_vfe_vfe_ahb_clk.c, ""),
+	CLK_LOOKUP("bus_clk", camss_vfe_vfe_axi_clk.c, ""),
+	CLK_LOOKUP("bus_clk", camss_vfe_vfe_ocmemnoc_clk.c, ""),
+	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, ""),
+	CLK_LOOKUP("bus_clk", mdss_axi_clk.c, ""),
+	CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, ""),
+	CLK_LOOKUP("iface_clk", oxilicx_ahb_clk.c, ""),
+	CLK_LOOKUP("bus_clk", oxilicx_axi_clk.c, ""),
+
+	/* LPASS clocks */
+	CLK_LOOKUP("core_clk", audio_core_slimbus_core_clk.c, "fe12f000.slim"),
+	CLK_LOOKUP("iface_clk", audio_core_slimbus_lfabif_clk.c,
+			"fe12f000.slim"),
+	CLK_LOOKUP("core_clk", audio_core_lpaif_codec_spkr_clk_src.c, ""),
+	CLK_LOOKUP("osr_clk", audio_core_lpaif_codec_spkr_osr_clk.c, ""),
+	CLK_LOOKUP("ebit_clk", audio_core_lpaif_codec_spkr_ebit_clk.c, ""),
+	CLK_LOOKUP("ibit_clk", audio_core_lpaif_codec_spkr_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk", audio_core_lpaif_pri_clk_src.c, ""),
+	CLK_LOOKUP("osr_clk", audio_core_lpaif_pri_osr_clk.c, ""),
+	CLK_LOOKUP("ebit_clk", audio_core_lpaif_pri_ebit_clk.c, ""),
+	CLK_LOOKUP("ibit_clk", audio_core_lpaif_pri_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk", audio_core_lpaif_sec_clk_src.c, ""),
+	CLK_LOOKUP("osr_clk", audio_core_lpaif_sec_osr_clk.c, ""),
+	CLK_LOOKUP("ebit_clk", audio_core_lpaif_sec_ebit_clk.c, ""),
+	CLK_LOOKUP("ibit_clk", audio_core_lpaif_sec_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk", audio_core_lpaif_ter_clk_src.c, ""),
+	CLK_LOOKUP("osr_clk", audio_core_lpaif_ter_osr_clk.c, ""),
+	CLK_LOOKUP("ebit_clk", audio_core_lpaif_ter_ebit_clk.c, ""),
+	CLK_LOOKUP("ibit_clk", audio_core_lpaif_ter_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk", audio_core_lpaif_quad_clk_src.c, ""),
+	CLK_LOOKUP("osr_clk", audio_core_lpaif_quad_osr_clk.c, ""),
+	CLK_LOOKUP("ebit_clk", audio_core_lpaif_quad_ebit_clk.c, ""),
+	CLK_LOOKUP("ibit_clk", audio_core_lpaif_quad_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk", audio_core_lpaif_pcm0_clk_src.c, ""),
+	CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm0_ebit_clk.c, ""),
+	CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm0_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk", audio_core_lpaif_pcm1_clk_src.c, ""),
+	CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm1_ebit_clk.c, ""),
+	CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm1_ibit_clk.c, ""),
+
+	CLK_LOOKUP("core_clk",       mss_xo_q6_clk.c, ""),
+	CLK_LOOKUP("bus_clk",       mss_bus_q6_clk.c, ""),
+	CLK_LOOKUP("core_clk",         q6ss_xo_clk.c, ""),
+	CLK_LOOKUP("bus_clk",  q6ss_ahb_lfabif_clk.c, ""),
+	CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, ""),
+	CLK_LOOKUP("bus_clk",  gcc_mss_cfg_ahb_clk.c, ""),
+
+	/* TODO: Remove dummy clocks as soon as they become unnecessary */
+	CLK_DUMMY("phy_clk",       NULL,    "msm_otg", OFF),
+	CLK_DUMMY("core_clk",      NULL,    "msm_otg", OFF),
+	CLK_DUMMY("dfab_clk",  DFAB_CLK,    "msm_sps", OFF),
+	CLK_DUMMY("mem_clk",       NULL,    "msm_sps", OFF),
+	CLK_DUMMY("bus_clk",       NULL,        "scm", OFF),
+};
+
+static struct pll_config_regs gpll0_regs __initdata = {
+	.l_reg = (void __iomem *)GPLL0_L_REG,
+	.m_reg = (void __iomem *)GPLL0_M_REG,
+	.n_reg = (void __iomem *)GPLL0_N_REG,
+	.config_reg = (void __iomem *)GPLL0_USER_CTL_REG,
+	.mode_reg = (void __iomem *)GPLL0_MODE_REG,
+	.base = &virt_bases[GCC_BASE],
+};
+
+/* GPLL0 at 600 MHz, main output enabled. */
+static struct pll_config gpll0_config __initdata = {
+	.l = 0x1f,
+	.m = 0x1,
+	.n = 0x4,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+static struct pll_config_regs gpll1_regs __initdata = {
+	.l_reg = (void __iomem *)GPLL1_L_REG,
+	.m_reg = (void __iomem *)GPLL1_M_REG,
+	.n_reg = (void __iomem *)GPLL1_N_REG,
+	.config_reg = (void __iomem *)GPLL1_USER_CTL_REG,
+	.mode_reg = (void __iomem *)GPLL1_MODE_REG,
+	.base = &virt_bases[GCC_BASE],
+};
+
+/* GPLL1 at 480 MHz, main output enabled. */
+static struct pll_config gpll1_config __initdata = {
+	.l = 0x19,
+	.m = 0x0,
+	.n = 0x1,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+static struct pll_config_regs mmpll0_regs __initdata = {
+	.l_reg = (void __iomem *)MMPLL0_L_REG,
+	.m_reg = (void __iomem *)MMPLL0_M_REG,
+	.n_reg = (void __iomem *)MMPLL0_N_REG,
+	.config_reg = (void __iomem *)MMPLL0_USER_CTL_REG,
+	.mode_reg = (void __iomem *)MMPLL0_MODE_REG,
+	.base = &virt_bases[MMSS_BASE],
+};
+
+/* MMPLL0 at 800 MHz, main output enabled. */
+static struct pll_config mmpll0_config __initdata = {
+	.l = 0x29,
+	.m = 0x2,
+	.n = 0x3,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+static struct pll_config_regs mmpll1_regs __initdata = {
+	.l_reg = (void __iomem *)MMPLL1_L_REG,
+	.m_reg = (void __iomem *)MMPLL1_M_REG,
+	.n_reg = (void __iomem *)MMPLL1_N_REG,
+	.config_reg = (void __iomem *)MMPLL1_USER_CTL_REG,
+	.mode_reg = (void __iomem *)MMPLL1_MODE_REG,
+	.base = &virt_bases[MMSS_BASE],
+};
+
+/* MMPLL1 at 1000 MHz, main output enabled. */
+static struct pll_config mmpll1_config __initdata = {
+	.l = 0x34,
+	.m = 0x1,
+	.n = 0xC,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+static struct pll_config_regs mmpll3_regs __initdata = {
+	.l_reg = (void __iomem *)MMPLL3_L_REG,
+	.m_reg = (void __iomem *)MMPLL3_M_REG,
+	.n_reg = (void __iomem *)MMPLL3_N_REG,
+	.config_reg = (void __iomem *)MMPLL3_USER_CTL_REG,
+	.mode_reg = (void __iomem *)MMPLL3_MODE_REG,
+	.base = &virt_bases[MMSS_BASE],
+};
+
+/* MMPLL3 at 820 MHz, main output enabled. */
+static struct pll_config mmpll3_config __initdata = {
+	.l = 0x2A,
+	.m = 0x11,
+	.n = 0x18,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+static struct pll_config_regs lpapll0_regs __initdata = {
+	.l_reg = (void __iomem *)LPAPLL_L_REG,
+	.m_reg = (void __iomem *)LPAPLL_M_REG,
+	.n_reg = (void __iomem *)LPAPLL_N_REG,
+	.config_reg = (void __iomem *)LPAPLL_USER_CTL_REG,
+	.mode_reg = (void __iomem *)LPAPLL_MODE_REG,
+	.base = &virt_bases[LPASS_BASE],
+};
+
+/* LPAPLL0 at 491.52 MHz, main output enabled. */
+static struct pll_config lpapll0_config __initdata = {
+	.l = 0x33,
+	.m = 0x1,
+	.n = 0x5,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = BVAL(14, 12, 0x1),
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+#define PLL_AUX_OUTPUT BIT(1)
+
+static void __init reg_init(void)
+{
+	u32 regval;
+
+	if (!(readl_relaxed(GCC_REG_BASE(GPLL0_STATUS_REG))
+			& gpll0_clk_src.status_mask))
+		configure_pll(&gpll0_config, &gpll0_regs, 1);
+
+	if (!(readl_relaxed(GCC_REG_BASE(GPLL1_STATUS_REG))
+			& gpll1_clk_src.status_mask))
+		configure_pll(&gpll1_config, &gpll1_regs, 1);
+
+	configure_pll(&mmpll0_config, &mmpll0_regs, 1);
+	configure_pll(&mmpll1_config, &mmpll1_regs, 1);
+	configure_pll(&mmpll3_config, &mmpll3_regs, 0);
+	configure_pll(&lpapll0_config, &lpapll0_regs, 1);
+
+	/* Active GPLL0's aux output. This is needed by acpuclock. */
+	regval = readl_relaxed(GCC_REG_BASE(GPLL0_USER_CTL_REG));
+	regval |= BIT(PLL_AUX_OUTPUT);
+	writel_relaxed(regval, GCC_REG_BASE(GPLL0_USER_CTL_REG));
+
+	/* Vote for GPLL0 to turn on. Needed by acpuclock. */
+	regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE_REG));
+	regval |= BIT(0);
+	writel_relaxed(regval, GCC_REG_BASE(APCS_GPLL_ENA_VOTE_REG));
+
+	/*
+	 * TODO: Confirm that no clocks need to be voted on in this sleep vote
+	 * register.
+	 */
+	writel_relaxed(0x0, GCC_REG_BASE(APCS_CLOCK_SLEEP_ENA_VOTE));
+}
+
+static void __init msmcopper_clock_post_init(void)
+{
+	clk_set_rate(&ahb_clk_src.c, 80000000);
+	clk_set_rate(&axi_clk_src.c, 333330000);
+
+	/* Set rates for single-rate clocks. */
+	clk_set_rate(&usb30_master_clk_src.c,
+			usb30_master_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&tsif_ref_clk_src.c,
+			tsif_ref_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&usb_hs_system_clk_src.c,
+			usb_hs_system_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&usb_hsic_clk_src.c,
+			usb_hsic_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&usb_hsic_io_cal_clk_src.c,
+			usb_hsic_io_cal_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&usb_hsic_system_clk_src.c,
+			usb_hsic_system_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&usb30_mock_utmi_clk_src.c,
+			usb30_mock_utmi_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&pdm2_clk_src.c, pdm2_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&cci_clk_src.c, cci_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&mclk0_clk_src.c, mclk0_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&mclk1_clk_src.c, mclk1_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&mclk2_clk_src.c, mclk2_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&edpaux_clk_src.c, edpaux_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&esc0_clk_src.c, esc0_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&esc1_clk_src.c, esc1_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&hdmi_clk_src.c, hdmi_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&vsync_clk_src.c, vsync_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&audio_core_slimbus_core_clk_src.c,
+			audio_core_slimbus_core_clk_src.freq_tbl[0].freq_hz);
+}
+
+#define GCC_CC_PHYS	0xFC400000
+#define GCC_CC_SIZE	SZ_16K
+
+#define MMSS_CC_PHYS	0xFD8C0000
+#define MMSS_CC_SIZE	SZ_256K
+
+#define LPASS_CC_PHYS	0xFE000000
+#define LPASS_CC_SIZE	SZ_256K
+
+#define MSS_CC_PHYS	0xFC980000
+#define MSS_CC_SIZE	SZ_16K
+
+static void __init msmcopper_clock_pre_init(void)
+{
+	virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
+	if (!virt_bases[GCC_BASE])
+		panic("clock-copper: Unable to ioremap GCC memory!");
+
+	virt_bases[MMSS_BASE] = ioremap(MMSS_CC_PHYS, MMSS_CC_SIZE);
+	if (!virt_bases[MMSS_BASE])
+		panic("clock-copper: Unable to ioremap MMSS_CC memory!");
+
+	virt_bases[LPASS_BASE] = ioremap(LPASS_CC_PHYS, LPASS_CC_SIZE);
+	if (!virt_bases[LPASS_BASE])
+		panic("clock-copper: Unable to ioremap LPASS_CC memory!");
+
+	virt_bases[MSS_BASE] = ioremap(MSS_CC_PHYS, MSS_CC_SIZE);
+	if (!virt_bases[MSS_BASE])
+		panic("clock-copper: Unable to ioremap MSS_CC memory!");
+
+	clk_ops_local_pll.enable = copper_pll_clk_enable;
+
+	reg_init();
+}
+
+struct clock_init_data msmcopper_clock_init_data __initdata = {
+	.table = msm_clocks_copper,
+	.size = ARRAY_SIZE(msm_clocks_copper),
+	.pre_init = msmcopper_clock_pre_init,
+	.post_init = msmcopper_clock_post_init,
+};
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 55282b6..e8e88d7 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -316,7 +316,7 @@
 				  void __iomem *cbcr_reg,
 				  enum branch_state br_status)
 {
-	char *status_str = (br_status == BRANCH_ON) ? "on" : "off";
+	char *status_str = (br_status == BRANCH_ON) ? "off" : "on";
 
 	/*
 	 * Use a memory barrier since some halt status registers are
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index 5022811..3a232c5 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -42,6 +42,14 @@
 				((x)->status_reg))
 #define PLL_MODE_REG(x) ((x)->base ? (*(x)->base + (u32)((x)->mode_reg)) : \
 				((x)->mode_reg))
+#define PLL_L_REG(x) ((x)->base ? (*(x)->base + (u32)((x)->l_reg)) : \
+				((x)->l_reg))
+#define PLL_M_REG(x) ((x)->base ? (*(x)->base + (u32)((x)->m_reg)) : \
+				((x)->m_reg))
+#define PLL_N_REG(x) ((x)->base ? (*(x)->base + (u32)((x)->n_reg)) : \
+				((x)->n_reg))
+#define PLL_CONFIG_REG(x) ((x)->base ? (*(x)->base + (u32)((x)->config_reg)) : \
+				((x)->config_reg))
 
 static DEFINE_SPINLOCK(pll_reg_lock);
 
@@ -67,7 +75,7 @@
 
 	/* Wait for pll to enable. */
 	for (count = ENABLE_WAIT_MAX_LOOPS; count > 0; count--) {
-		if (readl_relaxed(pll->status_reg) & pll->status_mask)
+		if (readl_relaxed(PLL_STATUS_REG(pll)) & pll->status_mask)
 			return 0;
 		udelay(1);
 	}
@@ -218,6 +226,57 @@
 	return 0;
 }
 
+#define PLL_LOCKED_BIT BIT(16)
+
+int copper_pll_clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	struct pll_clk *pll = to_pll_clk(clk);
+	u32 count, mode;
+	int ret = 0;
+
+	spin_lock_irqsave(&pll_reg_lock, flags);
+	mode = readl_relaxed(PLL_MODE_REG(pll));
+	/* Disable PLL bypass mode. */
+	mode |= PLL_BYPASSNL;
+	writel_relaxed(mode, PLL_MODE_REG(pll));
+
+	/*
+	 * H/W requires a 5us delay between disabling the bypass and
+	 * de-asserting the reset. Delay 10us just to be safe.
+	 */
+	mb();
+	udelay(10);
+
+	/* De-assert active-low PLL reset. */
+	mode |= PLL_RESET_N;
+	writel_relaxed(mode, PLL_MODE_REG(pll));
+
+	/* Wait for pll to enable. */
+	for (count = ENABLE_WAIT_MAX_LOOPS; count > 0; count--) {
+		if (readl_relaxed(PLL_STATUS_REG(pll)) & PLL_LOCKED_BIT)
+			break;
+		udelay(1);
+	}
+
+	if (!(readl_relaxed(PLL_STATUS_REG(pll)) & PLL_LOCKED_BIT)) {
+		WARN("PLL %s didn't lock after enabling it!\n", clk->dbg_name);
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	/* Enable PLL output. */
+	mode |= PLL_OUTCTRL;
+	writel_relaxed(mode, PLL_MODE_REG(pll));
+
+	/* Ensure the write above goes through before returning. */
+	mb();
+
+out:
+	spin_unlock_irqrestore(&pll_reg_lock, flags);
+	return ret;
+}
+
 struct clk_ops clk_ops_local_pll = {
 	.enable = local_pll_clk_enable,
 	.disable = local_pll_clk_disable,
@@ -374,3 +433,65 @@
 	.handoff = pll_clk_handoff,
 	.is_enabled = pll_clk_is_enabled,
 };
+
+static void __init __set_fsm_mode(void __iomem *mode_reg)
+{
+	u32 regval = readl_relaxed(mode_reg);
+
+	/* De-assert reset to FSM */
+	regval &= ~BIT(21);
+	writel_relaxed(regval, mode_reg);
+
+	/* Program bias count */
+	regval &= ~BM(19, 14);
+	regval |= BVAL(19, 14, 0x1);
+	writel_relaxed(regval, mode_reg);
+
+	/* Program lock count */
+	regval &= ~BM(13, 8);
+	regval |= BVAL(13, 8, 0x8);
+	writel_relaxed(regval, mode_reg);
+
+	/* Enable PLL FSM voting */
+	regval |= BIT(20);
+	writel_relaxed(regval, mode_reg);
+}
+
+void __init configure_pll(struct pll_config *config,
+		struct pll_config_regs *regs, u32 ena_fsm_mode)
+{
+	u32 regval;
+
+	writel_relaxed(config->l, PLL_L_REG(regs));
+	writel_relaxed(config->m, PLL_M_REG(regs));
+	writel_relaxed(config->n, PLL_N_REG(regs));
+
+	regval = readl_relaxed(PLL_CONFIG_REG(regs));
+
+	/* Enable the MN accumulator  */
+	if (config->mn_ena_mask) {
+		regval &= ~config->mn_ena_mask;
+		regval |= config->mn_ena_val;
+	}
+
+	/* Enable the main output */
+	if (config->main_output_mask) {
+		regval &= ~config->main_output_mask;
+		regval |= config->main_output_val;
+	}
+
+	/* Set pre-divider and post-divider values */
+	regval &= ~config->pre_div_mask;
+	regval |= config->pre_div_val;
+	regval &= ~config->post_div_mask;
+	regval |= config->post_div_val;
+
+	/* Select VCO setting */
+	regval &= ~config->vco_mask;
+	regval |= config->vco_val;
+	writel_relaxed(regval, PLL_CONFIG_REG(regs));
+
+	/* Configure in FSM mode if necessary */
+	if (ena_fsm_mode)
+		__set_fsm_mode(PLL_MODE_REG(regs));
+}
diff --git a/arch/arm/mach-msm/clock-pll.h b/arch/arm/mach-msm/clock-pll.h
index 26bfc68..231668f 100644
--- a/arch/arm/mach-msm/clock-pll.h
+++ b/arch/arm/mach-msm/clock-pll.h
@@ -89,11 +89,14 @@
 /**
  * struct pll_clk - phase locked loop
  * @mode_reg: enable register
+ * @status_reg: status register, contains the lock detection bit
  * @parent: clock source
  * @c: clk
+ * @base: pointer to base address of ioremapped registers.
  */
 struct pll_clk {
 	void __iomem *const mode_reg;
+	void __iomem *const status_reg;
 
 	struct clk *parent;
 	struct clk c;
@@ -108,6 +111,7 @@
 }
 
 int sr_pll_clk_enable(struct clk *clk);
+int copper_pll_clk_enable(struct clk *clk);
 
 /*
  * PLL vote clock APIs
@@ -117,4 +121,31 @@
 struct clk *pll_vote_clk_get_parent(struct clk *clk);
 int pll_vote_clk_is_enabled(struct clk *clk);
 
+struct pll_config {
+	u32 l;
+	u32 m;
+	u32 n;
+	u32 vco_val;
+	u32 vco_mask;
+	u32 pre_div_val;
+	u32 pre_div_mask;
+	u32 post_div_val;
+	u32 post_div_mask;
+	u32 mn_ena_val;
+	u32 mn_ena_mask;
+	u32 main_output_val;
+	u32 main_output_mask;
+};
+
+struct pll_config_regs {
+	void __iomem *l_reg;
+	void __iomem *m_reg;
+	void __iomem *n_reg;
+	void __iomem *config_reg;
+	void __iomem *mode_reg;
+	void *const __iomem *base;
+};
+
+void __init configure_pll(struct pll_config *, struct pll_config_regs *, u32);
+
 #endif
diff --git a/arch/arm/mach-msm/clock-voter.c b/arch/arm/mach-msm/clock-voter.c
index 177af8c..4cd9b1c 100644
--- a/arch/arm/mach-msm/clock-voter.c
+++ b/arch/arm/mach-msm/clock-voter.c
@@ -147,7 +147,7 @@
 	return true;
 }
 
-enum handoff voter_clk_handoff(struct clk *clk)
+static enum handoff voter_clk_handoff(struct clk *clk)
 {
 	/* Apply default rate vote */
 	if (clk->rate)
@@ -164,4 +164,5 @@
 	.round_rate = voter_clk_round_rate,
 	.get_parent = voter_clk_get_parent,
 	.is_local = voter_clk_is_local,
+	.handoff = voter_clk_handoff,
 };
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 7ea464f..1be05ad 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -172,6 +172,7 @@
 extern struct clock_init_data qds8x50_clock_init_data;
 extern struct clock_init_data msm8625_dummy_clock_init_data;
 extern struct clock_init_data msm8930_clock_init_data;
+extern struct clock_init_data msmcopper_clock_init_data;
 
 void msm_clock_init(struct clock_init_data *data);
 int vote_vdd_level(struct clk_vdd_class *vdd_class, int level);
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index aaa5bfb..f6eee76 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -31,6 +31,7 @@
 #include <mach/mdm2.h>
 #include <mach/msm_smd.h>
 #include <mach/msm_dcvs.h>
+#include <mach/msm_rtb.h>
 #include <mach/qdss.h>
 #include <linux/ion.h>
 #include "clock.h"
@@ -482,14 +483,15 @@
 	},
 };
 
-struct msm_mi2s_data mpq_mi2s_tx_data = {
-	.sd_lines = MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 | MSM_MI2S_SD3,
-	.capability = MSM_MI2S_CAP_TX,
+struct msm_mi2s_pdata mpq_mi2s_tx_data = {
+	.rx_sd_lines = 0,
+	.tx_sd_lines = MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 |
+		       MSM_MI2S_SD3,
 };
 
 struct platform_device mpq_cpudai_mi2s_tx = {
-	.name	= "msm-dai-q6",
-	.id	= 7, /*MI2S_TX */
+	.name	= "msm-dai-q6-mi2s",
+	.id	= -1, /*MI2S_TX */
 	.dev = {
 		.platform_data = &mpq_mi2s_tx_data,
 	},
@@ -580,6 +582,11 @@
 	.id = 0x4005,
 };
 
+struct platform_device apq_cpudai_slimbus_3_rx = {
+	.name = "msm-dai-q6",
+	.id = 0x4006,
+};
+
 static struct resource resources_ssbi_pmic1[] = {
 	{
 		.start  = MSM_PMIC1_SSBI_CMD_PHYS,
@@ -1059,12 +1066,14 @@
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 	.memtype = ION_CP_MM_HEAP_ID,
 	.enable_ion = 1,
+	.cp_enabled = 1,
 #else
 	.memtype = MEMTYPE_EBI1,
 	.enable_ion = 0,
 #endif
 	.disable_dmx = 0,
 	.disable_fullhd = 0,
+	.cont_mode_dpb_count = 18,
 };
 
 struct platform_device apq8064_msm_device_vidc = {
@@ -1546,16 +1555,88 @@
 	.resource       = msm_gss_resources,
 };
 
-struct platform_device *apq8064_fs_devices[] = {
-	FS_8X60(FS_ROT,    "fs_rot"),
-	FS_8X60(FS_IJPEG,  "fs_ijpeg"),
-	FS_8X60(FS_VFE,    "fs_vfe"),
-	FS_8X60(FS_VPE,    "fs_vpe"),
-	FS_8X60(FS_GFX3D,  "fs_gfx3d"),
-	FS_8X60(FS_VED,    "fs_ved"),
-	FS_8X60(FS_VCAP,   "fs_vcap"),
+static struct fs_driver_data gfx3d_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk", .reset_rate = 27000000 },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_GRAPHICS_3D,
+	.bus_port1 = MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
 };
-unsigned apq8064_num_fs_devices = ARRAY_SIZE(apq8064_fs_devices);
+
+static struct fs_driver_data ijpeg_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_JPEG_ENC,
+};
+
+static struct fs_driver_data rot_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_ROTATOR,
+};
+
+static struct fs_driver_data ved_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_VIDEO_ENC,
+	.bus_port1 = MSM_BUS_MASTER_VIDEO_DEC,
+};
+
+static struct fs_driver_data vfe_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_VFE,
+};
+
+static struct fs_driver_data vpe_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_VPE,
+};
+
+static struct fs_driver_data vcap_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 },
+	},
+	.bus_port0 = MSM_BUS_MASTER_VIDEO_CAP,
+};
+
+struct platform_device *apq8064_footswitch[] __initdata = {
+	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,    "fs_vfe",	NULL,	&vfe_fs_data),
+	FS_8X60(FS_VPE,    "fs_vpe",	NULL,	&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_VCAP,   "vdd",	"msm_vcap.0",	&vcap_fs_data),
+};
+unsigned apq8064_num_footswitch __initdata = ARRAY_SIZE(apq8064_footswitch);
 
 struct msm_rpm_platform_data apq8064_rpm_data __initdata = {
 	.reg_base_addrs = {
@@ -2406,5 +2487,27 @@
 	.id = -1,
 	.dev = {
 		.platform_data = &apq8064_iommu_domain_pdata,
+	}
+};
+
+struct msm_rtb_platform_data apq8064_rtb_pdata = {
+	.size = SZ_1M,
+};
+
+static int __init msm_rtb_set_buffer_size(char *p)
+{
+	int s;
+
+	s = memparse(p, NULL);
+	apq8064_rtb_pdata.size = ALIGN(s, SZ_4K);
+	return 0;
+}
+early_param("msm_rtb_size", msm_rtb_set_buffer_size);
+
+struct platform_device apq8064_rtb_device = {
+	.name           = "msm_rtb",
+	.id             = -1,
+	.dev            = {
+		.platform_data = &apq8064_rtb_pdata,
 	},
 };
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index b7048db..4ad73f9 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -23,10 +23,12 @@
 #include <mach/board.h>
 #include <mach/socinfo.h>
 #include <mach/iommu_domains.h>
+#include <mach/msm_rtb.h>
 
 #include "devices.h"
 #include "rpm_log.h"
 #include "rpm_stats.h"
+#include "footswitch.h"
 
 #ifdef CONFIG_MSM_MPM
 #include <mach/mpm.h>
@@ -351,6 +353,93 @@
 	.id    = MSM_BUS_FAB_CPSS_FPB,
 };
 
+static struct fs_driver_data gfx3d_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk", .reset_rate = 27000000 },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_GRAPHICS_3D,
+};
+
+static struct fs_driver_data ijpeg_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_JPEG_ENC,
+};
+
+static struct fs_driver_data mdp_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ .name = "vsync_clk" },
+		{ .name = "lut_clk" },
+		{ .name = "tv_src_clk" },
+		{ .name = "tv_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_MDP_PORT0,
+	.bus_port1 = MSM_BUS_MASTER_MDP_PORT1,
+};
+
+static struct fs_driver_data rot_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_ROTATOR,
+};
+
+static struct fs_driver_data ved_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_HD_CODEC_PORT0,
+	.bus_port1 = MSM_BUS_MASTER_HD_CODEC_PORT1,
+};
+
+static struct fs_driver_data vfe_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_VFE,
+};
+
+static struct fs_driver_data vpe_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_VPE,
+};
+
+struct platform_device *msm8930_footswitch[] __initdata = {
+	FS_8X60(FS_MDP,    "vdd",	"mdp.0",	&mdp_fs_data),
+	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,    "fs_vfe",	NULL,	&vfe_fs_data),
+	FS_8X60(FS_VPE,    "fs_vpe",	NULL,	&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_num_footswitch __initdata = ARRAY_SIZE(msm8930_footswitch);
+
 /* MSM Video core device */
 #ifdef CONFIG_MSM_BUS_SCALING
 static struct msm_bus_vectors vidc_init_vectors[] = {
@@ -597,11 +686,12 @@
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 	.memtype = ION_CP_MM_HEAP_ID,
 	.enable_ion = 1,
+	.cp_enabled = 1,
 #else
 	.memtype = MEMTYPE_EBI1,
 	.enable_ion = 0,
 #endif
-	.disable_dmx = 0,
+	.disable_dmx = 1,
 	.disable_fullhd = 0,
 };
 
@@ -785,5 +875,28 @@
 	.id = -1,
 	.dev = {
 		.platform_data = &msm8930_iommu_domain_pdata,
+	}
+};
+
+struct msm_rtb_platform_data msm8930_rtb_pdata = {
+	.size = SZ_1M,
+};
+
+static int __init msm_rtb_set_buffer_size(char *p)
+{
+	int s;
+
+	s = memparse(p, NULL);
+	msm8930_rtb_pdata.size = ALIGN(s, SZ_4K);
+	return 0;
+}
+early_param("msm_rtb_size", msm_rtb_set_buffer_size);
+
+
+struct platform_device msm8930_rtb_device = {
+	.name           = "msm_rtb",
+	.id             = -1,
+	.dev            = {
+		.platform_data = &msm8930_rtb_pdata,
 	},
 };
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 8df1d7a..f1553b6 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -32,6 +32,8 @@
 #include <mach/msm_memtypes.h>
 #include <mach/msm_smd.h>
 #include <mach/msm_dcvs.h>
+#include <mach/msm_rtb.h>
+#include <mach/msm_cache_dump.h>
 #include <sound/msm-dai-q6.h>
 #include <sound/apr_audio.h>
 #include <mach/msm_tsif.h>
@@ -654,12 +656,14 @@
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 	.memtype = ION_CP_MM_HEAP_ID,
 	.enable_ion = 1,
+	.cp_enabled = 1,
 #else
 	.memtype = MEMTYPE_EBI1,
 	.enable_ion = 0,
 #endif
 	.disable_dmx = 0,
 	.disable_fullhd = 0,
+	.cont_mode_dpb_count = 18,
 };
 
 struct platform_device msm_device_vidc = {
@@ -678,7 +682,6 @@
 #define MSM_SDC2_BASE         0x12140000
 #define MSM_SDC2_DML_BASE     (MSM_SDC2_BASE + 0x800)
 #define MSM_SDC2_BAM_BASE     (MSM_SDC2_BASE + 0x2000)
-#define MSM_SDC2_BASE         0x12140000
 #define MSM_SDC3_BASE         0x12180000
 #define MSM_SDC3_DML_BASE     (MSM_SDC3_BASE + 0x800)
 #define MSM_SDC3_BAM_BASE     (MSM_SDC3_BASE + 0x2000)
@@ -1974,19 +1977,111 @@
 	.id	= -1,
 };
 
-struct platform_device *msm_footswitch_devices[] = {
-	FS_8X60(FS_MDP,    "fs_mdp"),
-	FS_8X60(FS_ROT,    "fs_rot"),
-	FS_8X60(FS_IJPEG,  "fs_ijpeg"),
-	FS_8X60(FS_VFE,    "fs_vfe"),
-	FS_8X60(FS_VPE,    "fs_vpe"),
-	FS_8X60(FS_GFX3D,  "fs_gfx3d"),
-	FS_8X60(FS_GFX2D0, "fs_gfx2d0"),
-	FS_8X60(FS_GFX2D1, "fs_gfx2d1"),
-	FS_8X60(FS_VED,    "fs_ved"),
+static struct fs_driver_data gfx2d0_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
 };
-unsigned msm_num_footswitch_devices = ARRAY_SIZE(msm_footswitch_devices);
 
+static struct fs_driver_data gfx2d1_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
+};
+
+static struct fs_driver_data gfx3d_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk", .reset_rate = 27000000 },
+		{ .name = "iface_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_GRAPHICS_3D,
+};
+
+static struct fs_driver_data ijpeg_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_JPEG_ENC,
+};
+
+static struct fs_driver_data mdp_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ .name = "vsync_clk" },
+		{ .name = "lut_clk" },
+		{ .name = "tv_src_clk" },
+		{ .name = "tv_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_MDP_PORT0,
+	.bus_port1 = MSM_BUS_MASTER_MDP_PORT1,
+};
+
+static struct fs_driver_data rot_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_ROTATOR,
+};
+
+static struct fs_driver_data ved_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_HD_CODEC_PORT0,
+	.bus_port1 = MSM_BUS_MASTER_HD_CODEC_PORT1,
+};
+
+static struct fs_driver_data vfe_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_VFE,
+};
+
+static struct fs_driver_data vpe_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_VPE,
+};
+
+struct platform_device *msm8960_footswitch[] __initdata = {
+	FS_8X60(FS_MDP,    "vdd",	"mdp.0",	&mdp_fs_data),
+	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,    "fs_vfe",	NULL,	&vfe_fs_data),
+	FS_8X60(FS_VPE,    "fs_vpe",	NULL,	&vpe_fs_data),
+	FS_8X60(FS_GFX3D,  "vdd",	"kgsl-3d0.0",	&gfx3d_fs_data),
+	FS_8X60(FS_GFX2D0, "vdd",	"kgsl-2d0.0",	&gfx2d0_fs_data),
+	FS_8X60(FS_GFX2D1, "vdd",	"kgsl-2d1.1",	&gfx2d1_fs_data),
+	FS_8X60(FS_VED,    "vdd",	"msm_vidc.0",	&ved_fs_data),
+};
+unsigned msm8960_num_footswitch __initdata = ARRAY_SIZE(msm8960_footswitch);
 
 #ifdef CONFIG_MSM_ROTATOR
 static struct msm_bus_vectors rotator_init_vectors[] = {
@@ -2100,7 +2195,6 @@
 	.number_of_clocks = ARRAY_SIZE(rotator_clocks),
 	.hardware_version_number = 0x01020309,
 	.rotator_clks = rotator_clocks,
-	.regulator_name = "fs_rot",
 #ifdef CONFIG_MSM_BUS_SCALING
 	.bus_scale_table = &rotator_bus_scale_pdata,
 #endif
@@ -2614,15 +2708,15 @@
 	},
 };
 
-static const char *kgsl_3d0_iommu_ctx_names[] = {
-	"gfx3d_user",
-	/* priv_ctx goes here */
+static const struct kgsl_iommu_ctx kgsl_3d0_iommu_ctxs[] = {
+	{ "gfx3d_user", 0 },
+	{ "gfx3d_priv", 1 },
 };
 
 static struct kgsl_device_iommu_data kgsl_3d0_iommu_data[] = {
 	{
-		.iommu_ctx_names = kgsl_3d0_iommu_ctx_names,
-		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu_ctx_names),
+		.iommu_ctxs = kgsl_3d0_iommu_ctxs,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_3d0_iommu_ctxs),
 		.physstart = 0x07C00000,
 		.physend = 0x07C00000 + SZ_1M - 1,
 	},
@@ -2694,14 +2788,14 @@
 	},
 };
 
-static const char *kgsl_2d0_iommu_ctx_names[] = {
-	"gfx2d0_2d0",
+static const struct kgsl_iommu_ctx kgsl_2d0_iommu_ctxs[] = {
+	{ "gfx2d0_2d0", 0 },
 };
 
 static struct kgsl_device_iommu_data kgsl_2d0_iommu_data[] = {
 	{
-		.iommu_ctx_names = kgsl_2d0_iommu_ctx_names,
-		.iommu_ctx_count = ARRAY_SIZE(kgsl_2d0_iommu_ctx_names),
+		.iommu_ctxs = kgsl_2d0_iommu_ctxs,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_2d0_iommu_ctxs),
 		.physstart = 0x07D00000,
 		.physend = 0x07D00000 + SZ_1M - 1,
 	},
@@ -2746,14 +2840,14 @@
 	},
 };
 
-static const char *kgsl_2d1_iommu_ctx_names[] = {
-	"gfx2d1_2d1",
+static const struct kgsl_iommu_ctx kgsl_2d1_iommu_ctxs[] = {
+	{ "gfx2d1_2d1", 0 },
 };
 
 static struct kgsl_device_iommu_data kgsl_2d1_iommu_data[] = {
 	{
-		.iommu_ctx_names = kgsl_2d1_iommu_ctx_names,
-		.iommu_ctx_count = ARRAY_SIZE(kgsl_2d1_iommu_ctx_names),
+		.iommu_ctxs = kgsl_2d1_iommu_ctxs,
+		.iommu_ctx_count = ARRAY_SIZE(kgsl_2d1_iommu_ctxs),
 		.physstart = 0x07E00000,
 		.physend = 0x07E00000 + SZ_1M - 1,
 	},
@@ -3500,5 +3594,41 @@
 	.id = -1,
 	.dev = {
 		.platform_data = &msm8960_iommu_domain_pdata,
+	}
+};
+
+struct msm_rtb_platform_data msm8960_rtb_pdata = {
+	.size = SZ_1M,
+};
+
+static int __init msm_rtb_set_buffer_size(char *p)
+{
+	int s;
+
+	s = memparse(p, NULL);
+	msm8960_rtb_pdata.size = ALIGN(s, SZ_4K);
+	return 0;
+}
+early_param("msm_rtb_size", msm_rtb_set_buffer_size);
+
+
+struct platform_device msm8960_rtb_device = {
+	.name           = "msm_rtb",
+	.id             = -1,
+	.dev            = {
+		.platform_data = &msm8960_rtb_pdata,
+	},
+};
+
+struct msm_cache_dump_platform_data msm8960_cache_dump_pdata = {
+	.l2_size = L2_BUFFER_SIZE,
+	.l1_size = L1_BUFFER_SIZE,
+};
+
+struct platform_device msm8960_cache_dump_device = {
+	.name           = "msm_cache_dump",
+	.id             = -1,
+	.dev            = {
+		.platform_data = &msm8960_cache_dump_pdata,
 	},
 };
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 34298c5..c084d29 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -19,6 +19,7 @@
 #include <linux/dma-mapping.h>
 #include <sound/msm-dai-q6.h>
 #include <sound/apr_audio.h>
+#include <linux/usb/android.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach/flash.h>
 #include <mach/board.h>
@@ -1247,11 +1248,36 @@
 	},
 };
 
+uint32_t __init msm9615_rpm_get_swfi_latency(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(msm_rpmrs_levels); i++) {
+		if (msm_rpmrs_levels[i].sleep_mode ==
+			MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)
+				return msm_rpmrs_levels[i].latency_us;
+	}
+	return 0;
+}
+
+struct android_usb_platform_data msm_android_usb_pdata;
+
+struct platform_device msm_android_usb_device = {
+	.name	= "android_usb",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &msm_android_usb_pdata,
+	},
+};
+
 void __init msm9615_device_init(void)
 {
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
 	BUG_ON(msm_rpm_init(&msm9615_rpm_data));
 	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
+	msm_android_usb_pdata.swfi_latency =
+		msm_rpmrs_levels[0].latency_us;
+
 }
 
 #define MSM_SHARED_RAM_PHYS 0x40000000
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
index d36b8d9..2382510 100644
--- a/arch/arm/mach-msm/devices-msm7x27.c
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -870,7 +870,7 @@
 };
 
 struct platform_device *msm_footswitch_devices[] = {
-	FS_PCOM(FS_GFX3D,  "fs_gfx3d"),
+	FS_PCOM(FS_GFX3D,  "vdd", "kgsl-3d0.0"),
 };
 unsigned msm_num_footswitch_devices = ARRAY_SIZE(msm_footswitch_devices);
 
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index bd0376e..2d79f62 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -17,6 +17,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <linux/notifier.h>
 #include <mach/irqs.h>
 #include <mach/msm_iomap.h>
 #include <mach/board.h>
@@ -26,6 +27,7 @@
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/mach/mmc.h>
+#include <asm/cacheflush.h>
 #include <mach/rpc_hsusb.h>
 #include <mach/socinfo.h>
 
@@ -830,7 +832,7 @@
 
 void __init msm7x25a_kgsl_3d0_init(void)
 {
-	if (cpu_is_msm7x25a() || cpu_is_msm7x25aa()) {
+	if (cpu_is_msm7x25a() || cpu_is_msm7x25aa() || cpu_is_msm7x25ab()) {
 		kgsl_3d0_pdata.num_levels = 2;
 		kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 133330000;
 		kgsl_3d0_pdata.pwrlevel[0].bus_freq = 160000000;
@@ -927,7 +929,7 @@
 };
 
 struct platform_device *msm_footswitch_devices[] = {
-	FS_PCOM(FS_GFX3D,  "fs_gfx3d"),
+	FS_PCOM(FS_GFX3D,  "vdd", "kgsl-3d0.0"),
 };
 unsigned msm_num_footswitch_devices = ARRAY_SIZE(msm_footswitch_devices);
 
@@ -1618,7 +1620,7 @@
 	}
 
 	msm_clock_init(&msm7x27a_clock_init_data);
-	if (cpu_is_msm7x27aa())
+	if (cpu_is_msm7x27aa() || cpu_is_msm7x25ab())
 		acpuclk_init(&acpuclk_7x27aa_soc_data);
 	else if (cpu_is_msm8625()) {
 		if (msm8625_cpu_id() == MSM8625)
@@ -1704,3 +1706,23 @@
 	return 0;
 }
 postcore_initcall(msm7627a_init_gpio);
+
+static int msm7627a_panic_handler(struct notifier_block *this,
+		unsigned long event, void *ptr)
+{
+	flush_cache_all();
+	outer_flush_all();
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_handler = {
+	.notifier_call = msm7627a_panic_handler,
+};
+
+static int __init panic_register(void)
+{
+	atomic_notifier_chain_register(&panic_notifier_list,
+			&panic_handler);
+	return 0;
+}
+module_init(panic_register);
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index 5f08d77..e055579 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -955,7 +955,8 @@
 struct msm_vidc_platform_data vidc_platform_data = {
 	.memtype = MEMTYPE_EBI0,
 	.enable_ion = 0,
-	.disable_dmx = 0
+	.disable_dmx = 0,
+	.cont_mode_dpb_count = 8
 };
 
 struct platform_device msm_device_vidc_720p = {
@@ -1186,7 +1187,6 @@
 	.number_of_clocks = ARRAY_SIZE(rotator_clocks),
 	.hardware_version_number = 0x1000303,
 	.rotator_clks = rotator_clocks,
-	.regulator_name = "fs_rot",
 };
 
 struct platform_device msm_rotator_device = {
@@ -1344,13 +1344,13 @@
 };
 
 struct platform_device *msm_footswitch_devices[] = {
-	FS_PCOM(FS_GFX2D0, "fs_gfx2d0"),
-	FS_PCOM(FS_GFX3D,  "fs_gfx3d"),
-	FS_PCOM(FS_MDP,    "fs_mdp"),
-	FS_PCOM(FS_MFC,    "fs_mfc"),
-	FS_PCOM(FS_ROT,    "fs_rot"),
-	FS_PCOM(FS_VFE,    "fs_vfe"),
-	FS_PCOM(FS_VPE,    "fs_vpe"),
+	FS_PCOM(FS_GFX2D0, "vdd", "kgsl-2d0.0"),
+	FS_PCOM(FS_GFX3D,  "vdd", "kgsl-3d0.0"),
+	FS_PCOM(FS_MDP,    "vdd", "mdp.0"),
+	FS_PCOM(FS_MFC,    "fs_mfc",    NULL),
+	FS_PCOM(FS_ROT,    "vdd",  "msm_rotator.0"),
+	FS_PCOM(FS_VFE,    "fs_vfe",    NULL),
+	FS_PCOM(FS_VPE,    "fs_vpe",    NULL),
 };
 unsigned msm_num_footswitch_devices = ARRAY_SIZE(msm_footswitch_devices);
 
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 614f6ff..d622af2 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -1547,7 +1547,6 @@
 	.number_of_clocks = ARRAY_SIZE(rotator_clocks),
 	.hardware_version_number = 0x01010307,
 	.rotator_clks = rotator_clocks,
-	.regulator_name = "fs_rot",
 #ifdef CONFIG_MSM_BUS_SCALING
 	.bus_scale_table = &rotator_bus_scale_pdata,
 #endif
@@ -2260,12 +2259,14 @@
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 	.memtype = ION_CP_MM_HEAP_ID,
 	.enable_ion = 1,
+	.cp_enabled = 0,
 #else
 	.memtype = MEMTYPE_SMI_KERNEL,
 	.enable_ion = 0,
 #endif
 	.disable_dmx = 0,
-	.disable_fullhd = 0
+	.disable_fullhd = 0,
+	.cont_mode_dpb_count = 8
 };
 
 struct platform_device msm_device_vidc = {
@@ -2560,18 +2561,112 @@
 };
 #endif
 
-struct platform_device *msm_footswitch_devices[] = {
-	FS_8X60(FS_IJPEG,  "fs_ijpeg"),
-	FS_8X60(FS_MDP,    "fs_mdp"),
-	FS_8X60(FS_ROT,    "fs_rot"),
-	FS_8X60(FS_VED,    "fs_ved"),
-	FS_8X60(FS_VFE,    "fs_vfe"),
-	FS_8X60(FS_VPE,    "fs_vpe"),
-	FS_8X60(FS_GFX3D,  "fs_gfx3d"),
-	FS_8X60(FS_GFX2D0, "fs_gfx2d0"),
-	FS_8X60(FS_GFX2D1, "fs_gfx2d1"),
+static struct fs_driver_data gfx2d0_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
 };
-unsigned msm_num_footswitch_devices = ARRAY_SIZE(msm_footswitch_devices);
+
+static struct fs_driver_data gfx2d1_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
+};
+
+static struct fs_driver_data gfx3d_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk", .reset_rate = 27000000 },
+		{ .name = "iface_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_GRAPHICS_3D,
+};
+
+static struct fs_driver_data ijpeg_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_JPEG_ENC,
+};
+
+static struct fs_driver_data mdp_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ .name = "vsync_clk" },
+		{ .name = "tv_src_clk" },
+		{ .name = "tv_clk" },
+		{ .name = "pixel_mdp_clk" },
+		{ .name = "pixel_lcdc_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_MDP_PORT0,
+	.bus_port1 = MSM_BUS_MASTER_MDP_PORT1,
+};
+
+static struct fs_driver_data rot_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_ROTATOR,
+};
+
+static struct fs_driver_data ved_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_HD_CODEC_PORT0,
+	.bus_port1 = MSM_BUS_MASTER_HD_CODEC_PORT1,
+};
+
+static struct fs_driver_data vfe_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_VFE,
+};
+
+static struct fs_driver_data vpe_fs_data = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_VPE,
+};
+
+struct platform_device *msm8660_footswitch[] __initdata = {
+	FS_8X60(FS_IJPEG,  "vdd",	"msm_gemini.0",	&ijpeg_fs_data),
+	FS_8X60(FS_MDP,    "vdd",	"mdp.0",	&mdp_fs_data),
+	FS_8X60(FS_ROT,    "vdd",	"msm_rotator.0", &rot_fs_data),
+	FS_8X60(FS_VED,    "vdd",	"msm_vidc.0",	&ved_fs_data),
+	FS_8X60(FS_VFE,    "fs_vfe",	NULL,	&vfe_fs_data),
+	FS_8X60(FS_VPE,    "fs_vpe",	NULL,	&vpe_fs_data),
+	FS_8X60(FS_GFX3D,  "vdd",	"kgsl-3d0.0",	&gfx3d_fs_data),
+	FS_8X60(FS_GFX2D0, "vdd",	"kgsl-2d0.0",	&gfx2d0_fs_data),
+	FS_8X60(FS_GFX2D1, "vdd",	"kgsl-2d1.1",	&gfx2d1_fs_data),
+};
+unsigned msm8660_num_footswitch __initdata = ARRAY_SIZE(msm8660_footswitch);
 
 struct msm_rpm_platform_data msm8660_rpm_data __initdata = {
 	.reg_base_addrs = {
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 5718fe0..31142c1 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -109,6 +109,7 @@
 extern struct platform_device msm_device_hsic_host;
 
 extern struct platform_device msm_device_otg;
+extern struct platform_device msm_android_usb_device;
 extern struct platform_device msm_device_hsic_peripheral;
 extern struct platform_device msm8960_device_otg;
 extern struct platform_device msm8960_device_gadget_peripheral;
@@ -263,13 +264,20 @@
 extern struct platform_device apq_cpudai_slimbus_1_rx;
 extern struct platform_device apq_cpudai_slimbus_1_tx;
 extern struct platform_device apq_cpudai_slimbus_2_tx;
+extern struct platform_device apq_cpudai_slimbus_3_rx;
 extern struct platform_device apq_cpudai_slim_4_rx;
 extern struct platform_device apq_cpudai_slim_4_tx;
 
 extern struct platform_device *msm_footswitch_devices[];
 extern unsigned msm_num_footswitch_devices;
-extern struct platform_device *apq8064_fs_devices[];
-extern unsigned apq8064_num_fs_devices;
+extern struct platform_device *msm8660_footswitch[];
+extern unsigned msm8660_num_footswitch;
+extern struct platform_device *msm8960_footswitch[];
+extern unsigned msm8960_num_footswitch;
+extern struct platform_device *apq8064_footswitch[];
+extern unsigned apq8064_num_footswitch;
+extern struct platform_device *msm8930_footswitch[];
+extern unsigned msm8930_num_footswitch;
 
 extern struct platform_device fsm_qfp_fuse_device;
 
@@ -378,3 +386,9 @@
 extern struct platform_device msm8960_iommu_domain_device;
 extern struct platform_device msm8930_iommu_domain_device;
 extern struct platform_device apq8064_iommu_domain_device;
+
+extern struct platform_device msm8960_rtb_device;
+extern struct platform_device msm8930_rtb_device;
+extern struct platform_device apq8064_rtb_device;
+
+extern struct platform_device msm8960_cache_dump_device;
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
index 087227c..d433b9e 100644
--- a/arch/arm/mach-msm/dma.c
+++ b/arch/arm/mach-msm/dma.c
@@ -59,19 +59,20 @@
 	int channel_active;
 	int sd;
 	size_t sd_size;
+	struct list_head staged_commands[MSM_DMOV_CHANNEL_COUNT];
 	struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT];
 	struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT];
-	spinlock_t lock;
+	struct mutex lock;
+	spinlock_t list_lock;
 	unsigned int irq;
 	struct clk *clk;
 	struct clk *pclk;
 	struct clk *ebiclk;
 	unsigned int clk_ctl;
-	struct timer_list timer;
+	struct delayed_work work;
 };
 
-static void msm_dmov_clock_timer(unsigned long);
-static int msm_dmov_clk_toggle(int, int);
+static void msm_dmov_clock_work(struct work_struct *);
 
 #ifdef CONFIG_ARCH_MSM8X60
 
@@ -163,15 +164,19 @@
 	{
 		.crci_conf = adm0_crci_conf,
 		.chan_conf = adm0_chan_conf,
-		.lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
+		.lock = __MUTEX_INITIALIZER(dmov_conf[0].lock),
+		.list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock),
 		.clk_ctl = CLK_DIS,
-		.timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 0),
+		.work = __DELAYED_WORK_INITIALIZER(dmov_conf[0].work,
+				msm_dmov_clock_work),
 	}, {
 		.crci_conf = adm1_crci_conf,
 		.chan_conf = adm1_chan_conf,
-		.lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
+		.lock = __MUTEX_INITIALIZER(dmov_conf[1].lock),
+		.list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock),
 		.clk_ctl = CLK_DIS,
-		.timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 1),
+		.work = __DELAYED_WORK_INITIALIZER(dmov_conf[1].work,
+				msm_dmov_clock_work),
 	}
 };
 #else
@@ -179,9 +184,11 @@
 	{
 		.crci_conf = NULL,
 		.chan_conf = NULL,
-		.lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
+		.lock = __MUTEX_INITIALIZER(dmov_conf[0].lock),
+		.list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock),
 		.clk_ctl = CLK_DIS,
-		.timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 0),
+		.work = __DELAYED_WORK_INITIALIZER(dmov_conf[0].work,
+				msm_dmov_clock_work),
 	}
 };
 #endif
@@ -223,103 +230,153 @@
 #define PRINT_FLOW(format, args...) \
 	MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_FLOW, format, args);
 
-static int msm_dmov_clk_toggle(int adm, int on)
+static int msm_dmov_clk_on(int adm)
 {
-	int ret = 0;
+	int ret;
 
-	if (on) {
-		ret = clk_enable(dmov_conf[adm].clk);
-		if (ret)
-			goto err;
-		if (dmov_conf[adm].pclk) {
-			ret = clk_enable(dmov_conf[adm].pclk);
-			if (ret) {
-				clk_disable(dmov_conf[adm].clk);
-				goto err;
-			}
+	ret = clk_prepare_enable(dmov_conf[adm].clk);
+	if (ret)
+		return ret;
+	if (dmov_conf[adm].pclk) {
+		ret = clk_prepare_enable(dmov_conf[adm].pclk);
+		if (ret) {
+			clk_disable_unprepare(dmov_conf[adm].clk);
+			return ret;
 		}
-		if (dmov_conf[adm].ebiclk) {
-			ret = clk_enable(dmov_conf[adm].ebiclk);
-			if (ret) {
-				if (dmov_conf[adm].pclk)
-					clk_disable(dmov_conf[adm].pclk);
-				clk_disable(dmov_conf[adm].clk);
-			}
-		}
-	} else {
-		clk_disable(dmov_conf[adm].clk);
-		if (dmov_conf[adm].pclk)
-			clk_disable(dmov_conf[adm].pclk);
-		if (dmov_conf[adm].ebiclk)
-			clk_disable(dmov_conf[adm].ebiclk);
 	}
-err:
+	if (dmov_conf[adm].ebiclk) {
+		ret = clk_prepare_enable(dmov_conf[adm].ebiclk);
+		if (ret) {
+			if (dmov_conf[adm].pclk)
+				clk_disable_unprepare(dmov_conf[adm].pclk);
+			clk_disable_unprepare(dmov_conf[adm].clk);
+		}
+	}
 	return ret;
 }
 
-static void msm_dmov_clock_timer(unsigned long adm)
+static void msm_dmov_clk_off(int adm)
 {
-	unsigned long irq_flags;
-	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
-	if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS) {
-		BUG_ON(dmov_conf[adm].channel_active);
-		msm_dmov_clk_toggle(adm, 0);
-		dmov_conf[adm].clk_ctl = CLK_DIS;
+	clk_disable_unprepare(dmov_conf[adm].clk);
+	if (dmov_conf[adm].pclk)
+		clk_disable_unprepare(dmov_conf[adm].pclk);
+	if (dmov_conf[adm].ebiclk)
+		clk_disable_unprepare(dmov_conf[adm].ebiclk);
+}
+
+static void msm_dmov_clock_work(struct work_struct *work)
+{
+	struct msm_dmov_conf *conf =
+		container_of(to_delayed_work(work), struct msm_dmov_conf, work);
+	int adm = DMOV_IRQ_TO_ADM(conf->irq);
+	mutex_lock(&conf->lock);
+	if (conf->clk_ctl == CLK_TO_BE_DIS) {
+		BUG_ON(conf->channel_active);
+		msm_dmov_clk_off(adm);
+		conf->clk_ctl = CLK_DIS;
 	}
-	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
+	mutex_unlock(&conf->lock);
 }
 
-void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful)
-{
-	int adm = DMOV_ID_TO_ADM(id);
-	int ch = DMOV_ID_TO_CHAN(id);
-	writel_relaxed((graceful << 31), DMOV_REG(DMOV_FLUSH0(ch), adm));
-	wmb();
-}
-EXPORT_SYMBOL(msm_dmov_stop_cmd);
+enum {
+	NOFLUSH = 0,
+	GRACEFUL,
+	NONGRACEFUL,
+};
 
-void msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd)
+/* Caller must hold the list lock */
+static struct msm_dmov_cmd *start_ready_cmd(unsigned ch, int adm)
 {
-	unsigned long irq_flags;
-	unsigned int status;
+	struct msm_dmov_cmd *cmd;
+
+	if (list_empty(&dmov_conf[adm].ready_commands[ch]))
+		return NULL;
+
+	cmd = list_entry(dmov_conf[adm].ready_commands[ch].next, typeof(*cmd),
+			 list);
+	list_del(&cmd->list);
+	if (cmd->exec_func)
+		cmd->exec_func(cmd);
+	list_add_tail(&cmd->list, &dmov_conf[adm].active_commands[ch]);
+	if (!dmov_conf[adm].channel_active)
+		enable_irq(dmov_conf[adm].irq);
+	dmov_conf[adm].channel_active |= BIT(ch);
+	PRINT_IO("msm dmov enqueue command, %x, ch %d\n", cmd->cmdptr, ch);
+	writel_relaxed(cmd->cmdptr, DMOV_REG(DMOV_CMD_PTR(ch), adm));
+
+	return cmd;
+}
+
+static void msm_dmov_enqueue_cmd_ext_work(struct work_struct *work)
+{
+	struct msm_dmov_cmd *cmd =
+		container_of(work, struct msm_dmov_cmd, work);
+	unsigned id = cmd->id;
+	unsigned status;
+	unsigned long flags;
 	int adm = DMOV_ID_TO_ADM(id);
 	int ch = DMOV_ID_TO_CHAN(id);
 
-	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+	mutex_lock(&dmov_conf[adm].lock);
 	if (dmov_conf[adm].clk_ctl == CLK_DIS) {
-		status = msm_dmov_clk_toggle(adm, 1);
+		status = msm_dmov_clk_on(adm);
 		if (status != 0)
 			goto error;
 	} else if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS)
-		del_timer(&dmov_conf[adm].timer);
+		cancel_delayed_work_sync(&dmov_conf[adm].work);
 	dmov_conf[adm].clk_ctl = CLK_EN;
 
+	spin_lock_irqsave(&dmov_conf[adm].list_lock, flags);
+
+	cmd = list_entry(dmov_conf[adm].staged_commands[ch].next, typeof(*cmd),
+			 list);
+	list_del(&cmd->list);
+	list_add_tail(&cmd->list, &dmov_conf[adm].ready_commands[ch]);
 	status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch), adm));
 	if (status & DMOV_STATUS_CMD_PTR_RDY) {
 		PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n",
 			id, status);
-		if (cmd->exec_func)
-			cmd->exec_func(cmd);
-		list_add_tail(&cmd->list, &dmov_conf[adm].active_commands[ch]);
-		if (!dmov_conf[adm].channel_active)
-			enable_irq(dmov_conf[adm].irq);
-		dmov_conf[adm].channel_active |= 1U << ch;
-		PRINT_IO("Writing %x exactly to register", cmd->cmdptr);
-		writel_relaxed(cmd->cmdptr, DMOV_REG(DMOV_CMD_PTR(ch), adm));
-	} else {
-		if (!dmov_conf[adm].channel_active) {
-			dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
-			mod_timer(&dmov_conf[adm].timer, jiffies + HZ);
+		cmd = start_ready_cmd(ch, adm);
+		/*
+		 * We added something to the ready list, and still hold the
+		 * list lock. Thus, no need to check for cmd == NULL
+		 */
+		if (cmd->toflush) {
+			int flush = (cmd->toflush == GRACEFUL) ? 1 << 31 : 0;
+			writel_relaxed(flush, DMOV_REG(DMOV_FLUSH0(ch), adm));
 		}
-		if (list_empty(&dmov_conf[adm].active_commands[ch]))
+	} else {
+		cmd->toflush = 0;
+		if (list_empty(&dmov_conf[adm].active_commands[ch]) &&
+		    !list_empty(&dmov_conf[adm].ready_commands[ch]))
 			PRINT_ERROR("msm_dmov_enqueue_cmd_ext(%d), stalled, "
 				"status %x\n", id, status);
 		PRINT_IO("msm_dmov_enqueue_cmd(%d), enqueue command, status "
 		    "%x\n", id, status);
-		list_add_tail(&cmd->list, &dmov_conf[adm].ready_commands[ch]);
 	}
+	if (!dmov_conf[adm].channel_active) {
+		dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
+		schedule_delayed_work(&dmov_conf[adm].work, HZ);
+	}
+	spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags);
 error:
-	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
+	mutex_unlock(&dmov_conf[adm].lock);
+}
+
+void msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd)
+{
+	int adm = DMOV_ID_TO_ADM(id);
+	int ch = DMOV_ID_TO_CHAN(id);
+	unsigned long flags;
+	cmd->id = id;
+	cmd->toflush = 0;
+	INIT_WORK(&cmd->work, msm_dmov_enqueue_cmd_ext_work);
+
+	spin_lock_irqsave(&dmov_conf[adm].list_lock, flags);
+	list_add_tail(&cmd->list, &dmov_conf[adm].staged_commands[ch]);
+	spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags);
+
+	schedule_work(&cmd->work);
 }
 EXPORT_SYMBOL(msm_dmov_enqueue_cmd_ext);
 
@@ -332,19 +389,24 @@
 }
 EXPORT_SYMBOL(msm_dmov_enqueue_cmd);
 
-void msm_dmov_flush(unsigned int id)
+void msm_dmov_flush(unsigned int id, int graceful)
 {
 	unsigned long irq_flags;
 	int ch = DMOV_ID_TO_CHAN(id);
 	int adm = DMOV_ID_TO_ADM(id);
-	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+	int flush = graceful ? DMOV_FLUSH_TYPE : 0;
+	struct msm_dmov_cmd *cmd;
+
+	spin_lock_irqsave(&dmov_conf[adm].list_lock, irq_flags);
 	/* XXX not checking if flush cmd sent already */
 	if (!list_empty(&dmov_conf[adm].active_commands[ch])) {
 		PRINT_IO("msm_dmov_flush(%d), send flush cmd\n", id);
-		writel_relaxed(DMOV_FLUSH_TYPE, DMOV_REG(DMOV_FLUSH0(ch), adm));
+		writel_relaxed(flush, DMOV_REG(DMOV_FLUSH0(ch), adm));
 	}
+	list_for_each_entry(cmd, &dmov_conf[adm].staged_commands[ch], list)
+		cmd->toflush = graceful ? GRACEFUL : NONGRACEFUL;
 	/* spin_unlock_irqrestore has the necessary barrier */
-	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
+	spin_unlock_irqrestore(&dmov_conf[adm].list_lock, irq_flags);
 }
 EXPORT_SYMBOL(msm_dmov_flush);
 
@@ -400,13 +462,13 @@
 {
 	errdata->flush[0] = readl_relaxed(DMOV_REG(DMOV_FLUSH0(ch), adm));
 	errdata->flush[1] = readl_relaxed(DMOV_REG(DMOV_FLUSH1(ch), adm));
-	errdata->flush[2] = readl_relaxed(DMOV_REG(DMOV_FLUSH2(ch), adm));
+	errdata->flush[2] = 0;
 	errdata->flush[3] = readl_relaxed(DMOV_REG(DMOV_FLUSH3(ch), adm));
 	errdata->flush[4] = readl_relaxed(DMOV_REG(DMOV_FLUSH4(ch), adm));
 	errdata->flush[5] = readl_relaxed(DMOV_REG(DMOV_FLUSH5(ch), adm));
 }
 
-static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id)
+static irqreturn_t msm_dmov_isr(int irq, void *dev_id)
 {
 	unsigned int int_status;
 	unsigned int mask;
@@ -419,11 +481,12 @@
 	struct msm_dmov_cmd *cmd;
 	int adm = DMOV_IRQ_TO_ADM(irq);
 
-	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+	mutex_lock(&dmov_conf[adm].lock);
 	/* read and clear isr */
 	int_status = readl_relaxed(DMOV_REG(DMOV_ISR, adm));
 	PRINT_FLOW("msm_datamover_irq_handler: DMOV_ISR %x\n", int_status);
 
+	spin_lock_irqsave(&dmov_conf[adm].list_lock, irq_flags);
 	while (int_status) {
 		mask = int_status & -int_status;
 		ch = fls(mask) - 1;
@@ -491,50 +554,38 @@
 			ch_status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch),
 						  adm));
 			PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
-			if ((ch_status & DMOV_STATUS_CMD_PTR_RDY) &&
-			    !list_empty(&dmov_conf[adm].ready_commands[ch])) {
-				cmd = list_entry(dmov_conf[adm].
-					ready_commands[ch].next, typeof(*cmd),
-					list);
-				list_del(&cmd->list);
-				if (cmd->exec_func)
-					cmd->exec_func(cmd);
-				list_add_tail(&cmd->list,
-					&dmov_conf[adm].active_commands[ch]);
-				PRINT_FLOW("msm_datamover_irq_handler id %d, start command\n", id);
-				writel_relaxed(cmd->cmdptr,
-					       DMOV_REG(DMOV_CMD_PTR(ch), adm));
-			}
+			if (ch_status & DMOV_STATUS_CMD_PTR_RDY)
+				start_ready_cmd(ch, adm);
 		} while (ch_status & DMOV_STATUS_RSLT_VALID);
 		if (list_empty(&dmov_conf[adm].active_commands[ch]) &&
-				list_empty(&dmov_conf[adm].ready_commands[ch]))
+		    list_empty(&dmov_conf[adm].ready_commands[ch]))
 			dmov_conf[adm].channel_active &= ~(1U << ch);
 		PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
 	}
+	spin_unlock_irqrestore(&dmov_conf[adm].list_lock, irq_flags);
 
 	if (!dmov_conf[adm].channel_active && valid) {
 		disable_irq_nosync(dmov_conf[adm].irq);
 		dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
-		mod_timer(&dmov_conf[adm].timer, jiffies + HZ);
+		schedule_delayed_work(&dmov_conf[adm].work, HZ);
 	}
 
-	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
+	mutex_unlock(&dmov_conf[adm].lock);
 	return valid ? IRQ_HANDLED : IRQ_NONE;
 }
 
 static int msm_dmov_suspend_late(struct device *dev)
 {
-	unsigned long irq_flags;
 	struct platform_device *pdev = to_platform_device(dev);
 	int adm = (pdev->id >= 0) ? pdev->id : 0;
-	spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+	mutex_lock(&dmov_conf[adm].lock);
 	if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS) {
 		BUG_ON(dmov_conf[adm].channel_active);
-		del_timer(&dmov_conf[adm].timer);
-		msm_dmov_clk_toggle(adm, 0);
+		cancel_delayed_work_sync(&dmov_conf[adm].work);
+		msm_dmov_clk_off(adm);
 		dmov_conf[adm].clk_ctl = CLK_DIS;
 	}
-	spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
+	mutex_unlock(&dmov_conf[adm].lock);
 	return 0;
 }
 
@@ -649,8 +700,8 @@
 	if (!dmov_conf[adm].base)
 		return -ENOMEM;
 
-	ret = request_irq(dmov_conf[adm].irq, msm_datamover_irq_handler,
-		0, "msmdatamover", NULL);
+	ret = request_threaded_irq(dmov_conf[adm].irq, NULL, msm_dmov_isr,
+				   IRQF_ONESHOT, "msmdatamover", NULL);
 	if (ret) {
 		PRINT_ERROR("Requesting ADM%d irq %d failed\n", adm,
 			dmov_conf[adm].irq);
@@ -662,7 +713,7 @@
 		PRINT_ERROR("Requesting ADM%d clocks failed\n", adm);
 		goto out_irq;
 	}
-	ret = msm_dmov_clk_toggle(adm, 1);
+	ret = msm_dmov_clk_on(adm);
 	if (ret) {
 		PRINT_ERROR("Enabling ADM%d clocks failed\n", adm);
 		goto out_irq;
@@ -670,6 +721,7 @@
 
 	config_datamover(adm);
 	for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) {
+		INIT_LIST_HEAD(&dmov_conf[adm].staged_commands[i]);
 		INIT_LIST_HEAD(&dmov_conf[adm].ready_commands[i]);
 		INIT_LIST_HEAD(&dmov_conf[adm].active_commands[i]);
 
@@ -678,7 +730,7 @@
 		     DMOV_REG(DMOV_RSLT_CONF(i), adm));
 	}
 	wmb();
-	msm_dmov_clk_toggle(adm, 0);
+	msm_dmov_clk_off(adm);
 	return ret;
 out_irq:
 	free_irq(dmov_conf[adm].irq, NULL);
diff --git a/arch/arm/mach-msm/footswitch-8x60.c b/arch/arm/mach-msm/footswitch-8x60.c
index bde7713..72361a6 100644
--- a/arch/arm/mach-msm/footswitch-8x60.c
+++ b/arch/arm/mach-msm/footswitch-8x60.c
@@ -21,10 +21,8 @@
 #include <linux/regulator/machine.h>
 #include <linux/clk.h>
 #include <mach/msm_iomap.h>
-#include <mach/msm_bus_board.h>
 #include <mach/msm_bus.h>
 #include <mach/scm-io.h>
-#include <mach/socinfo.h>
 #include "clock.h"
 #include "footswitch.h"
 
@@ -51,6 +49,8 @@
 #define ENABLE_BIT		BIT(8)
 #define RETENTION_BIT		BIT(9)
 
+#define GFS_DELAY_CNT		31
+
 #define RESET_DELAY_US		1
 /* Clock rate to use if one has not previously been set. */
 #define DEFAULT_RATE		27000000
@@ -62,14 +62,6 @@
  */
 static DEFINE_MUTEX(claim_lock);
 
-struct clk_data {
-	const char *name;
-	struct clk *clk;
-	unsigned long rate;
-	unsigned long reset_rate;
-	bool enabled;
-};
-
 struct footswitch {
 	struct regulator_dev	*rdev;
 	struct regulator_desc	desc;
@@ -77,15 +69,14 @@
 	int			bus_port0, bus_port1;
 	bool			is_enabled;
 	bool			is_claimed;
-	struct clk_data		*clk_data;
+	struct fs_clk_data	*clk_data;
 	struct clk		*core_clk;
-	unsigned int		gfs_delay_cnt:5;
 };
 
 static int setup_clocks(struct footswitch *fs)
 {
 	int rc = 0;
-	struct clk_data *clock;
+	struct fs_clk_data *clock;
 	long rate;
 
 	/*
@@ -124,7 +115,7 @@
 
 static void restore_clocks(struct footswitch *fs)
 {
-	struct clk_data *clock;
+	struct fs_clk_data *clock;
 
 	/* Restore clocks to their orignal states before setup_clocks(). */
 	for (clock = fs->clk_data; clock->clk; clock++) {
@@ -146,7 +137,7 @@
 static int footswitch_enable(struct regulator_dev *rdev)
 {
 	struct footswitch *fs = rdev_get_drvdata(rdev);
-	struct clk_data *clock;
+	struct fs_clk_data *clock;
 	uint32_t regval, rc = 0;
 
 	mutex_lock(&claim_lock);
@@ -232,7 +223,7 @@
 static int footswitch_disable(struct regulator_dev *rdev)
 {
 	struct footswitch *fs = rdev_get_drvdata(rdev);
-	struct clk_data *clock;
+	struct fs_clk_data *clock;
 	uint32_t regval, rc = 0;
 
 	/* Return early if already disabled. */
@@ -308,7 +299,7 @@
 static int gfx2d_footswitch_enable(struct regulator_dev *rdev)
 {
 	struct footswitch *fs = rdev_get_drvdata(rdev);
-	struct clk_data *clock;
+	struct fs_clk_data *clock;
 	uint32_t regval, rc = 0;
 
 	mutex_lock(&claim_lock);
@@ -384,7 +375,7 @@
 static int gfx2d_footswitch_disable(struct regulator_dev *rdev)
 {
 	struct footswitch *fs = rdev_get_drvdata(rdev);
-	struct clk_data *clock;
+	struct fs_clk_data *clock;
 	uint32_t regval, rc = 0;
 
 	/* Return early if already disabled. */
@@ -461,108 +452,7 @@
 	.disable = gfx2d_footswitch_disable,
 };
 
-/*
- * Lists of required clocks for the collapse and restore sequences.
- *
- * Order matters here. Clocks are listed in the same order as their
- * resets will be de-asserted when the core is restored. Also, rate-
- * settable clocks must be listed before any of the branches that
- * are derived from them. Otherwise, the branches may fail to enable
- * if their parent's rate is not yet set.
- */
-
-static struct clk_data gfx2d0_clks[] = {
-	{ .name = "core_clk" },
-	{ .name = "iface_clk" },
-	{ 0 }
-};
-
-static struct clk_data gfx2d1_clks[] = {
-	{ .name = "core_clk" },
-	{ .name = "iface_clk" },
-	{ 0 }
-};
-
-static struct clk_data gfx3d_8660_clks[] = {
-	{ .name = "core_clk", .reset_rate = 27000000 },
-	{ .name = "iface_clk" },
-	{ 0 }
-};
-
-static struct clk_data gfx3d_8064_clks[] = {
-	{ .name = "core_clk", .reset_rate = 27000000 },
-	{ .name = "iface_clk" },
-	{ .name = "bus_clk" },
-	{ 0 }
-};
-
-static struct clk_data ijpeg_clks[] = {
-	{ .name = "core_clk" },
-	{ .name = "iface_clk" },
-	{ .name = "bus_clk" },
-	{ 0 }
-};
-
-static struct clk_data mdp_8960_clks[] = {
-	{ .name = "core_clk" },
-	{ .name = "iface_clk" },
-	{ .name = "bus_clk" },
-	{ .name = "vsync_clk" },
-	{ .name = "lut_clk" },
-	{ .name = "tv_src_clk" },
-	{ .name = "tv_clk" },
-	{ 0 }
-};
-
-static struct clk_data mdp_8660_clks[] = {
-	{ .name = "core_clk" },
-	{ .name = "iface_clk" },
-	{ .name = "bus_clk" },
-	{ .name = "vsync_clk" },
-	{ .name = "tv_src_clk" },
-	{ .name = "tv_clk" },
-	{ .name = "pixel_mdp_clk" },
-	{ .name = "pixel_lcdc_clk" },
-	{ 0 }
-};
-
-static struct clk_data rot_clks[] = {
-	{ .name = "core_clk" },
-	{ .name = "iface_clk" },
-	{ .name = "bus_clk" },
-	{ 0 }
-};
-
-static struct clk_data ved_clks[] = {
-	{ .name = "core_clk" },
-	{ .name = "iface_clk" },
-	{ .name = "bus_clk" },
-	{ 0 }
-};
-
-static struct clk_data vfe_clks[] = {
-	{ .name = "core_clk" },
-	{ .name = "iface_clk" },
-	{ .name = "bus_clk" },
-	{ 0 }
-};
-
-static struct clk_data vpe_clks[] = {
-	{ .name = "core_clk" },
-	{ .name = "iface_clk" },
-	{ .name = "bus_clk" },
-	{ 0 }
-};
-
-static struct clk_data vcap_clks[] = {
-	{ .name = "core_clk" },
-	{ .name = "iface_clk" },
-	{ .name = "bus_clk" },
-	{ 0 }
-};
-
-#define FOOTSWITCH(_id, _name, _ops, _gfs_ctl_reg, _dc, _clk_data, \
-		   _bp1, _bp2) \
+#define FOOTSWITCH(_id, _name, _ops, _gfs_ctl_reg) \
 	[(_id)] = { \
 		.desc = { \
 			.id = (_id), \
@@ -572,51 +462,26 @@
 			.owner = THIS_MODULE, \
 		}, \
 		.gfs_ctl_reg = (_gfs_ctl_reg), \
-		.gfs_delay_cnt = (_dc), \
-		.clk_data = (_clk_data), \
-		.bus_port0 = (_bp1), \
-		.bus_port1 = (_bp2), \
 	}
 static struct footswitch footswitches[] = {
-	FOOTSWITCH(FS_GFX2D0, "fs_gfx2d0", &gfx2d_fs_ops,
-		GFX2D0_GFS_CTL_REG, 31, gfx2d0_clks,
-		MSM_BUS_MASTER_GRAPHICS_2D_CORE0, 0),
-	FOOTSWITCH(FS_GFX2D1, "fs_gfx2d1", &gfx2d_fs_ops,
-		GFX2D1_GFS_CTL_REG, 31, gfx2d1_clks,
-		MSM_BUS_MASTER_GRAPHICS_2D_CORE1, 0),
-	FOOTSWITCH(FS_GFX3D, "fs_gfx3d", &standard_fs_ops,
-		GFX3D_GFS_CTL_REG, 31, gfx3d_8660_clks,
-		MSM_BUS_MASTER_GRAPHICS_3D, 0),
-	FOOTSWITCH(FS_IJPEG, "fs_ijpeg", &standard_fs_ops,
-		GEMINI_GFS_CTL_REG, 31, ijpeg_clks,
-		MSM_BUS_MASTER_JPEG_ENC, 0),
-	FOOTSWITCH(FS_MDP, "fs_mdp", &standard_fs_ops,
-		MDP_GFS_CTL_REG, 31, NULL,
-		MSM_BUS_MASTER_MDP_PORT0,
-		MSM_BUS_MASTER_MDP_PORT1),
-	FOOTSWITCH(FS_ROT, "fs_rot", &standard_fs_ops,
-		ROT_GFS_CTL_REG, 31, rot_clks,
-		MSM_BUS_MASTER_ROTATOR, 0),
-	FOOTSWITCH(FS_VED, "fs_ved", &standard_fs_ops,
-		VED_GFS_CTL_REG, 31, ved_clks,
-		MSM_BUS_MASTER_HD_CODEC_PORT0,
-		MSM_BUS_MASTER_HD_CODEC_PORT1),
-	FOOTSWITCH(FS_VFE, "fs_vfe", &standard_fs_ops,
-		VFE_GFS_CTL_REG, 31, vfe_clks,
-		MSM_BUS_MASTER_VFE, 0),
-	FOOTSWITCH(FS_VPE, "fs_vpe", &standard_fs_ops,
-		VPE_GFS_CTL_REG, 31, vpe_clks,
-		MSM_BUS_MASTER_VPE, 0),
-	FOOTSWITCH(FS_VCAP, "fs_vcap", &standard_fs_ops,
-		VCAP_GFS_CTL_REG, 31, vcap_clks,
-		MSM_BUS_MASTER_VIDEO_CAP, 0),
+	FOOTSWITCH(FS_GFX2D0, "fs_gfx2d0", &gfx2d_fs_ops, GFX2D0_GFS_CTL_REG),
+	FOOTSWITCH(FS_GFX2D1, "fs_gfx2d1", &gfx2d_fs_ops, GFX2D1_GFS_CTL_REG),
+	FOOTSWITCH(FS_GFX3D,  "fs_gfx3d", &standard_fs_ops, GFX3D_GFS_CTL_REG),
+	FOOTSWITCH(FS_IJPEG,  "fs_ijpeg", &standard_fs_ops, GEMINI_GFS_CTL_REG),
+	FOOTSWITCH(FS_MDP,    "fs_mdp",   &standard_fs_ops, MDP_GFS_CTL_REG),
+	FOOTSWITCH(FS_ROT,    "fs_rot",   &standard_fs_ops, ROT_GFS_CTL_REG),
+	FOOTSWITCH(FS_VED,    "fs_ved",   &standard_fs_ops, VED_GFS_CTL_REG),
+	FOOTSWITCH(FS_VFE,    "fs_vfe",   &standard_fs_ops, VFE_GFS_CTL_REG),
+	FOOTSWITCH(FS_VPE,    "fs_vpe",   &standard_fs_ops, VPE_GFS_CTL_REG),
+	FOOTSWITCH(FS_VCAP,   "fs_vcap",  &standard_fs_ops, VCAP_GFS_CTL_REG),
 };
 
 static int footswitch_probe(struct platform_device *pdev)
 {
 	struct footswitch *fs;
 	struct regulator_init_data *init_data;
-	struct clk_data *clock;
+	struct fs_driver_data *driver_data;
+	struct fs_clk_data *clock;
 	uint32_t regval, rc = 0;
 
 	if (pdev == NULL)
@@ -625,25 +490,12 @@
 	if (pdev->id >= MAX_FS)
 		return -ENODEV;
 
-	fs = &footswitches[pdev->id];
 	init_data = pdev->dev.platform_data;
-
-	if (pdev->id == FS_MDP) {
-		if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_apq8064())
-			fs->clk_data = mdp_8960_clks;
-		else
-			fs->clk_data = mdp_8660_clks;
-	} else if (pdev->id == FS_GFX3D) {
-		if (cpu_is_msm8930() || cpu_is_apq8064())
-			fs->clk_data = gfx3d_8064_clks;
-		else
-			fs->clk_data = gfx3d_8660_clks;
-	} else if (pdev->id == FS_VED) {
-		if (cpu_is_apq8064()) {
-			fs->bus_port0 = MSM_BUS_MASTER_VIDEO_ENC;
-			fs->bus_port1 = MSM_BUS_MASTER_VIDEO_DEC;
-		}
-	}
+	driver_data = init_data->driver_data;
+	fs = &footswitches[pdev->id];
+	fs->clk_data = driver_data->clks;
+	fs->bus_port0 = driver_data->bus_port0;
+	fs->bus_port1 = driver_data->bus_port1;
 
 	for (clock = fs->clk_data; clock->name; clock++) {
 		clock->clk = clk_get(&pdev->dev, clock->name);
@@ -663,7 +515,7 @@
 	 * clear so disabling the footswitch will power-collapse the core.
 	 */
 	regval = readl_relaxed(fs->gfs_ctl_reg);
-	regval |= fs->gfs_delay_cnt;
+	regval |= GFS_DELAY_CNT;
 	regval &= ~RETENTION_BIT;
 	writel_relaxed(regval, fs->gfs_ctl_reg);
 
@@ -688,7 +540,7 @@
 static int __devexit footswitch_remove(struct platform_device *pdev)
 {
 	struct footswitch *fs = &footswitches[pdev->id];
-	struct clk_data *clock;
+	struct fs_clk_data *clock;
 
 	for (clock = fs->clk_data; clock->clk; clock++)
 		clk_put(clock->clk);
diff --git a/arch/arm/mach-msm/footswitch.h b/arch/arm/mach-msm/footswitch.h
index 4882ff0..1809b2e 100644
--- a/arch/arm/mach-msm/footswitch.h
+++ b/arch/arm/mach-msm/footswitch.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011 Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -30,7 +30,21 @@
 #define FS_VCAP		10
 #define MAX_FS		11
 
-#define FS_GENERIC(_drv_name, _id, _name) (&(struct platform_device){ \
+struct fs_clk_data {
+	const char *name;
+	struct clk *clk;
+	unsigned long rate;
+	unsigned long reset_rate;
+	bool enabled;
+};
+
+struct fs_driver_data {
+	int bus_port0, bus_port1;
+	struct fs_clk_data *clks;
+};
+
+#define FS_GENERIC(_drv_name, _id, _name, _dev_id, _data) \
+(&(struct platform_device){ \
 	.name	= (_drv_name), \
 	.id	= (_id), \
 	.dev	= { \
@@ -42,11 +56,14 @@
 			.num_consumer_supplies = 1, \
 			.consumer_supplies = \
 				&(struct regulator_consumer_supply) \
-				REGULATOR_SUPPLY((_name), NULL), \
+				REGULATOR_SUPPLY((_name), (_dev_id)), \
+			.driver_data = (_data), \
 		} \
 	}, \
 })
-#define FS_PCOM(_id, _name) FS_GENERIC("footswitch-pcom", (_id), (_name))
-#define FS_8X60(_id, _name) FS_GENERIC("footswitch-8x60", (_id), (_name))
+#define FS_PCOM(_id, _name, _dev_id) \
+		FS_GENERIC("footswitch-pcom", _id, _name, _dev_id, NULL)
+#define FS_8X60(_id, _name, _dev_id, _data) \
+		FS_GENERIC("footswitch-8x60", _id, _name, _dev_id, _data)
 
 #endif
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index 0028286..b73ddc8 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -44,6 +44,15 @@
 skip\@:
 .endm
 
+/* Add NOPs for 8x25 target */
+.macro DELAY_8x25, rept
+#ifdef CONFIG_ARCH_MSM8625
+	.rept	\rept
+	nop
+	.endr
+#endif
+.endm
+
 ENTRY(msm_arch_idle)
 	wfi
 #ifdef CONFIG_ARCH_MSM8X60
@@ -130,6 +139,7 @@
 
 	SET_SMP_COHERENCY OFF
 	wfi
+	DELAY_8x25 300
 
 	mcr     p15, 0, r4, c1, c0, 0    /* restore d/i cache  */
 	isb
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index c46c493..644746e 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -261,6 +261,11 @@
 	int vcm_enable;
 };
 
+struct msm_eeprom_info {
+	struct i2c_board_info const *board_info;
+	int bus_id;
+};
+
 struct msm_camera_sensor_info {
 	const char *sensor_name;
 	int sensor_reset_enable;
@@ -283,6 +288,7 @@
 	enum msm_sensor_type sensor_type;
 	struct msm_actuator_info *actuator_info;
 	int pmic_gpio_enable;
+	struct msm_eeprom_info *eeprom_info;
 };
 
 struct msm_camera_board_info {
@@ -375,6 +381,7 @@
 	spinlock_t bl_spinlock;
 	int (*backlight_level)(int level, int max, int min);
 	int (*pmic_backlight)(int level);
+	int (*rotate_panel)(void);
 	int (*panel_num)(void);
 	void (*panel_config_gpio)(int);
 	int (*vga_switch)(int select_vga);
@@ -505,9 +512,11 @@
 	u32 enable_ion;
 	int disable_dmx;
 	int disable_fullhd;
+	u32 cp_enabled;
 #ifdef CONFIG_MSM_BUS_SCALING
 	struct msm_bus_scale_pdata *vidc_bus_client_pdata;
 #endif
+	int cont_mode_dpb_count;
 };
 
 struct vcap_platform_data {
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 7857e69..90d236b 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -343,13 +343,6 @@
 	enum msm_st_frame_packing s_snap_packing;
 };
 
-struct msm_actuator_ctrl {
-	int (*a_power_up)(void *);
-	int (*a_power_down)(void *);
-	int (*a_create_subdevice)(void *, void *);
-	int (*a_config)(void __user *);
-};
-
 struct msm_strobe_flash_ctrl {
 	int (*strobe_flash_init)
 		(struct msm_camera_sensor_strobe_flash_data *);
@@ -382,6 +375,11 @@
 	const char *name;
 };
 
+struct msm_mctl_stats_t {
+	struct hlist_head pmem_stats_list;
+	spinlock_t pmem_stats_spinlock;
+};
+
 struct msm_sync {
 	/* These two queues are accessed from a process context only
 	 * They contain pmem descriptors for the preview frames and the stats
@@ -416,7 +414,6 @@
 	struct msm_camvpe_fn vpefn;
 	struct msm_sensor_ctrl sctrl;
 	struct msm_strobe_flash_ctrl sfctrl;
-	struct msm_actuator_ctrl actctrl;
 	struct wake_lock wake_lock;
 	struct platform_device *pdev;
 	int16_t ignore_qcmd_type;
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index 339a955..ba621e6 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -35,7 +35,10 @@
 			      unsigned int result,
 			      struct msm_dmov_errdata *err);
 	void (*exec_func)(struct msm_dmov_cmd *cmd);
+	struct work_struct work;
+	unsigned id;    /* For internal use */
 	void *user;	/* Pointer for caller's reference */
+	u8 toflush;
 };
 
 struct msm_dmov_pdata {
@@ -45,8 +48,7 @@
 
 void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd);
 void msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd);
-void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful);
-void msm_dmov_flush(unsigned int id);
+void msm_dmov_flush(unsigned int id, int graceful);
 int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr);
 
 #define DMOV_CRCIS_PER_CONF 10
diff --git a/arch/arm/mach-msm/include/mach/hardware.h b/arch/arm/mach-msm/include/mach/hardware.h
index 2d12609..f1095af 100644
--- a/arch/arm/mach-msm/include/mach/hardware.h
+++ b/arch/arm/mach-msm/include/mach/hardware.h
@@ -1,6 +1,7 @@
 /* arch/arm/mach-msm/include/mach/hardware.h
  *
  * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2012, Code Aurora Forum. 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
@@ -14,5 +15,10 @@
  */
 
 #ifndef __ASM_ARCH_MSM_HARDWARE_H
+#define __ASM_ARCH_MSM_HARDWARE_H
+
+#define PCIBIOS_MIN_IO                  0x10000000
+#define PCIBIOS_MIN_MEM                 0x10000000
+#define pcibios_assign_all_busses()     1
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 994150f..a6f27d7 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-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -73,7 +73,6 @@
  */
 struct msm_iommu_drvdata {
 	void __iomem *base;
-	int irq;
 	int ncb;
 	int ttbr_split;
 	struct clk *clk;
@@ -95,6 +94,8 @@
 	int num;
 	struct platform_device *pdev;
 	struct list_head attached_elm;
+	struct iommu_domain *attached_domain;
+	const char *name;
 };
 
 /*
diff --git a/arch/arm/mach-msm/include/mach/iommu_domains.h b/arch/arm/mach-msm/include/mach/iommu_domains.h
index 52e70ec..dfb100c 100644
--- a/arch/arm/mach-msm/include/mach/iommu_domains.h
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.h
@@ -75,8 +75,28 @@
 extern int msm_iommu_map_extra(struct iommu_domain *domain,
 						unsigned long start_iova,
 						unsigned long size,
+						unsigned long page_size,
 						int cached);
 
+extern void msm_iommu_unmap_extra(struct iommu_domain *domain,
+						unsigned long start_iova,
+						unsigned long size,
+						unsigned long page_size);
+
+extern int msm_iommu_map_contig_buffer(unsigned long phys,
+				unsigned int domain_no,
+				unsigned int partition_no,
+				unsigned long size,
+				unsigned long align,
+				unsigned long cached,
+				unsigned long *iova_val);
+
+
+extern void msm_iommu_unmap_contig_buffer(unsigned long iova,
+					unsigned int domain_no,
+					unsigned int partition_no,
+					unsigned long size);
+
 #else
 static inline struct iommu_domain
 	*msm_get_iommu_domain(int subsys_id) { return NULL; }
@@ -101,10 +121,38 @@
 static inline int msm_iommu_map_extra(struct iommu_domain *domain,
 						unsigned long start_iova,
 						unsigned long size,
+						unsigned long page_size,
 						int cached)
 {
 	return -ENODEV;
 }
+
+static inline void msm_iommu_unmap_extra(struct iommu_domain *domain,
+						unsigned long start_iova,
+						unsigned long size,
+						unsigned long page_size)
+{
+}
+
+static inline int msm_iommu_map_contig_buffer(unsigned long phys,
+				unsigned int domain_no,
+				unsigned int partition_no,
+				unsigned long size,
+				unsigned long align,
+				unsigned long cached,
+				unsigned long *iova_val)
+{
+	*iova_val = phys;
+	return 0;
+}
+
+static inline void msm_iommu_unmap_contig_buffer(unsigned long iova,
+					unsigned int domain_no,
+					unsigned int partition_no,
+					unsigned long size)
+{
+	return;
+}
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-9625.h b/arch/arm/mach-msm/include/mach/irqs-9625.h
new file mode 100644
index 0000000..91b4d07
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-9625.h
@@ -0,0 +1,36 @@
+/* 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.
+ */
+
+#ifndef __ASM_ARCH_MSM_IRQS_9625_H
+#define __ASM_ARCH_MSM_IRQS_9625_H
+
+/* MSM ACPU Interrupt Numbers */
+
+/*
+ * 0-15:  STI/SGI (software triggered/generated interrupts)
+ * 16-31: PPI (private peripheral interrupts)
+ * 32+:   SPI (shared peripheral interrupts)
+ */
+
+
+#define APCC_QGICL2PERFMONIRPTREQ	(GIC_SPI_START + 1)
+#define SC_SICL2PERFMONIRPTREQ		APCC_QGICL2PERFMONIRPTREQ
+#define TLMM_MSM_SUMMARY_IRQ		(GIC_SPI_START + 16)
+#define SPS_BAM_DMA_IRQ			(GIC_SPI_START + 208)
+
+#define NR_MSM_IRQS 288
+#define NR_GPIO_IRQS 88
+#define NR_BOARD_IRQS 0
+#define NR_TLMM_MSM_DIR_CONN_IRQ 8 /*Need to Verify this Count*/
+#define NR_MSM_GPIOS NR_GPIO_IRQS
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-copper.h b/arch/arm/mach-msm/include/mach/irqs-copper.h
index c961804..6d27d69 100644
--- a/arch/arm/mach-msm/include/mach/irqs-copper.h
+++ b/arch/arm/mach-msm/include/mach/irqs-copper.h
@@ -31,7 +31,7 @@
 
 #define APCC_QGICL2PERFMONIRPTREQ	(GIC_SPI_START + 1)
 #define SC_SICL2PERFMONIRPTREQ		APCC_QGICL2PERFMONIRPTREQ
-#define TLMM_MSM_SUMMARY_IRQ		(GIC_SPI_START + 16)
+#define TLMM_MSM_SUMMARY_IRQ		(GIC_SPI_START + 208)
 #define SPS_BAM_DMA_IRQ			(GIC_SPI_START + 105)
 
 #define NR_MSM_IRQS 1020 /* Should be 256 - but higher due to bug in sim */
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index ff011a8..bf766f4 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -45,8 +45,14 @@
 #define NR_WCD9XXX_IRQS 49
 #define NR_TABLA_IRQS NR_WCD9XXX_IRQS
 #define NR_GPIO_EXPANDER_IRQS 64
+#ifdef CONFIG_PCI_MSI
+#define NR_PCIE_MSI_IRQS 256
+#define NR_BOARD_IRQS (NR_PM8921_IRQS + NR_PM8821_IRQS + \
+		NR_WCD9XXX_IRQS + NR_GPIO_EXPANDER_IRQS + NR_PCIE_MSI_IRQS)
+#else
 #define NR_BOARD_IRQS (NR_PM8921_IRQS + NR_PM8821_IRQS + \
 		NR_WCD9XXX_IRQS + NR_GPIO_EXPANDER_IRQS)
+#endif
 #define NR_TLMM_MSM_DIR_CONN_IRQ 8 /*Need to Verify this Count*/
 #define NR_MSM_GPIOS NR_GPIO_IRQS
 
@@ -56,6 +62,8 @@
 #include "irqs-copper.h"
 #elif defined(CONFIG_ARCH_MSM9615)
 #include "irqs-9615.h"
+#elif defined(CONFIG_ARCH_MSM9625)
+#include "irqs-9625.h"
 #elif defined(CONFIG_ARCH_MSM7X30)
 #include "irqs-7x30.h"
 #elif defined(CONFIG_ARCH_QSD8X50)
@@ -85,4 +93,9 @@
 #define FIRST_GPIO_IRQ MSM_GPIO_TO_INT(0)
 #define MSM_INT_TO_REG(base, irq) (base + irq / 32)
 
+#if defined(CONFIG_PCI_MSI) && defined(CONFIG_MSM_PCIE)
+#define MSM_PCIE_MSI_INT(n) (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS +  \
+		NR_PM8821_IRQS + NR_TABLA_IRQS + NR_GPIO_EXPANDER_IRQS + (n))
+#endif
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-9625.h b/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
new file mode 100644
index 0000000..493cf36
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. 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
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __ASM_ARCH_MSM_IOMAP_MSM9625_H
+#define __ASM_ARCH_MSM_IOMAP_MSM9625_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * io desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSM9625_SHARED_RAM_PHYS	0x18D00000
+
+#define MSM9625_APCS_GCC_PHYS	0xF9011000
+#define MSM9625_APCS_GCC_SIZE	SZ_4K
+
+#define MSM9625_TMR_PHYS	0xF9021000
+#define MSM9625_TMR_SIZE	SZ_4K
+
+#define MSM9625_TLMM_PHYS	0xFD510000
+#define MSM9625_TLMM_SIZE	SZ_16K
+
+#ifdef CONFIG_DEBUG_MSM9625_UART
+#define MSM_DEBUG_UART_BASE	IOMEM(0xFA71E000)
+#define MSM_DEBUG_UART_PHYS	0xF991E000
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 34af610..2676297 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -58,7 +58,8 @@
 	defined(CONFIG_ARCH_MSM8930) || defined(CONFIG_ARCH_MSM9615) || \
 	defined(CONFIG_ARCH_MSMCOPPER) || defined(CONFIG_ARCH_MSM7X27) || \
 	defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X01A) || \
-	defined(CONFIG_ARCH_MSM8625) || defined(CONFIG_ARCH_MSM7X30)
+	defined(CONFIG_ARCH_MSM8625) || defined(CONFIG_ARCH_MSM7X30) || \
+	defined(CONFIG_ARCH_MSM9625)
 
 /* Unified iomap */
 
@@ -121,6 +122,7 @@
 #include "msm_iomap-8064.h"
 #include "msm_iomap-9615.h"
 #include "msm_iomap-copper.h"
+#include "msm_iomap-9625.h"
 
 #else
 /* Legacy single-target iomap */
diff --git a/arch/arm/mach-msm/include/mach/msm_memtypes.h b/arch/arm/mach-msm/include/mach/msm_memtypes.h
index 6f9bed1..7afb38d 100644
--- a/arch/arm/mach-msm/include/mach/msm_memtypes.h
+++ b/arch/arm/mach-msm/include/mach/msm_memtypes.h
@@ -66,5 +66,5 @@
 
 extern struct reserve_info *reserve_info;
 
-unsigned long __init reserve_memory_for_fmem(unsigned long);
+unsigned long __init reserve_memory_for_fmem(unsigned long, unsigned long);
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_pcie.h b/arch/arm/mach-msm/include/mach/msm_pcie.h
new file mode 100644
index 0000000..008c984
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_pcie.h
@@ -0,0 +1,37 @@
+/* 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.
+ */
+
+#ifndef __ASM_ARCH_MSM_PCIE_H
+#define __ASM_ARCH_MSM_PCIE_H
+
+#include <linux/types.h>
+
+/* gpios */
+enum msm_pcie_gpio {
+	MSM_PCIE_GPIO_RST_N,
+	MSM_PCIE_GPIO_PWR_EN,
+	MSM_PCIE_MAX_GPIO
+};
+
+/* gpio info structrue */
+struct msm_pcie_gpio_info_t {
+	char      *name;
+	uint32_t   num;
+	uint32_t   on;
+};
+
+/* msm pcie platfrom data */
+struct msm_pcie_platform {
+	struct msm_pcie_gpio_info_t  *gpio;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index 4934c0f..dc633fb 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -282,6 +282,27 @@
  * @returns Pointer to subsystem name or NULL if not found
  */
 const char *smd_pid_to_subsystem(uint32_t pid);
+
+/*
+ * Checks to see if a new packet has arrived on the channel.  Only to be
+ * called with interrupts disabled.
+ *
+ * @ch: channel to check if a packet has arrived
+ *
+ * Returns:
+ *      0 - packet not available
+ *      1 - packet available
+ *      -EINVAL - NULL parameter or non-packet based channel provided
+ */
+int smd_is_pkt_avail(smd_channel_t *ch);
+
+/*
+ * SMD initialization function that registers for a SMD platform driver.
+ *
+ * returns success on successful driver registration.
+ */
+int __init msm_smd_init(void);
+
 #else
 
 static inline int smd_open(const char *name, smd_channel_t **ch, void *priv,
@@ -393,6 +414,16 @@
 {
 	return NULL;
 }
+
+static inline int smd_is_pkt_avail(smd_channel_t *ch)
+{
+	return -ENODEV;
+}
+
+static inline int __init msm_smd_init(void)
+{
+	return 0;
+}
 #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 5c3307e..5b15340 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -94,6 +94,7 @@
 #define SMSM_WLAN_TX_RINGS_EMPTY 0x00000200
 #define SMSM_WLAN_TX_ENABLE	0x00000400
 
+#define SMSM_ERR_SRV_READY         0x00008000
 
 void *smem_alloc(unsigned id, unsigned size);
 void *smem_alloc2(unsigned id, unsigned size_in);
diff --git a/arch/arm/mach-msm/include/mach/ocmem.h b/arch/arm/mach-msm/include/mach/ocmem.h
new file mode 100644
index 0000000..bf7c338
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/ocmem.h
@@ -0,0 +1,109 @@
+/* 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.
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_OCMEM_H
+#define _ARCH_ARM_MACH_MSM_OCMEM_H
+
+#include <asm/page.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+
+#define OCMEM_MIN_ALLOC SZ_64K
+#define OCMEM_MIN_ALIGN SZ_64K
+
+/* Maximum number of slots in DM */
+#define OCMEM_MAX_CHUNKS 32
+#define MIN_CHUNK_SIZE (SZ_1K/8)
+
+struct ocmem_buf {
+	unsigned long addr;
+	unsigned long len;
+};
+
+struct ocmem_buf_attr {
+	unsigned long paddr;
+	unsigned long len;
+};
+
+struct ocmem_chunk {
+	bool ro;
+	unsigned long ddr_paddr;
+	unsigned long size;
+};
+
+struct ocmem_map_list {
+	int num_chunks;
+	struct ocmem_chunk chunks[OCMEM_MAX_CHUNKS];
+};
+
+/* List of clients that allocate/interact with OCMEM */
+/* Must be in sync with client_names */
+enum ocmem_client {
+	/* GMEM clients */
+	OCMEM_GRAPHICS = 0x0,
+	/* TCMEM clients */
+	OCMEM_VIDEO,
+	OCMEM_CAMERA,
+	/* Dummy Clients */
+	OCMEM_HP_AUDIO,
+	OCMEM_VOICE,
+	/* IMEM Clients */
+	OCMEM_LP_AUDIO,
+	OCMEM_SENSORS,
+	OCMEM_BLAST,
+	OCMEM_CLIENT_MAX,
+};
+
+/**
+ * List of OCMEM notification events which will be broadcasted
+ * to clients that optionally register for these notifications
+ * on a per allocation basis.
+ **/
+enum ocmem_notif_type {
+	OCMEM_MAP_DONE = 1,
+	OCMEM_MAP_FAIL,
+	OCMEM_UNMAP_DONE,
+	OCMEM_UNMAP_FAIL,
+	OCMEM_ALLOC_GROW,
+	OCMEM_ALLOC_SHRINK,
+	OCMEM_NOTIF_TYPE_COUNT,
+};
+
+/* APIS */
+/* Notification APIs */
+void *ocmem_notifier_register(int client_id, struct notifier_block *nb);
+
+int ocmem_notifier_unregister(void *notif_hndl, struct notifier_block *nb);
+
+/* Allocation APIs */
+struct ocmem_buf *ocmem_allocate(int client_id, unsigned long size);
+
+struct ocmem_buf *ocmem_allocate_nb(int client_id, unsigned long size);
+
+struct ocmem_buf *ocmem_allocate_range(int client_id, unsigned long min,
+			unsigned long goal, unsigned long step);
+
+/* Free APIs */
+int ocmem_free(int client_id, struct ocmem_buf *buf);
+
+/* Dynamic Resize APIs */
+int ocmem_shrink(int client_id, struct ocmem_buf *buf,
+			unsigned long new_size);
+
+int ocmem_expand(int client_id, struct ocmem_buf *buf,
+			unsigned long new_size);
+
+/* Priority Enforcement APIs */
+int ocmem_evict(int client_id);
+
+int ocmem_restore(int client_id);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
new file mode 100644
index 0000000..32d46b4
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -0,0 +1,77 @@
+/* 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.
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_OCMEM_CORE_H
+#define _ARCH_ARM_MACH_MSM_OCMEM_CORE_H
+
+/** All interfaces in this header should only be used by OCMEM driver
+ *  Client drivers should use wrappers available in ocmem.h
+ **/
+
+#include "ocmem.h"
+#include <mach/msm_iomap.h>
+#include <asm/io.h>
+
+#define OCMEM_PHYS_BASE 0xFEC00000
+#define OCMEM_PHYS_SIZE 0x180000
+
+struct ocmem_zone;
+
+struct ocmem_zone_ops {
+	unsigned long (*allocate) (struct ocmem_zone *, unsigned long);
+	int (*free) (struct ocmem_zone *, unsigned long, unsigned long);
+};
+
+struct ocmem_zone {
+	int owner;
+	int active_regions;
+	int max_regions;
+	struct list_head region_list;
+	unsigned long z_start;
+	unsigned long z_end;
+	unsigned long z_head;
+	unsigned long z_tail;
+	unsigned long z_free;
+	struct gen_pool *z_pool;
+	struct ocmem_zone_ops *z_ops;
+};
+
+struct ocmem_req {
+	struct rw_semaphore rw_sem;
+	/* Chain in sched queue */
+	struct list_head sched_list;
+	/* Chain in zone list */
+	struct list_head zone_list;
+	int owner;
+	int prio;
+	uint32_t req_id;
+	unsigned long req_min;
+	unsigned long req_max;
+	unsigned long req_step;
+	/* reverse pointers */
+	struct ocmem_zone *zone;
+	struct ocmem_buf *buffer;
+	unsigned long state;
+	/* Request assignments */
+	unsigned long req_start;
+	unsigned long req_end;
+	unsigned long req_sz;
+};
+
+struct ocmem_handle {
+	struct ocmem_buf buffer;
+	struct mutex handle_mutex;
+	struct ocmem_req *req;
+};
+
+struct ocmem_zone *get_zone(unsigned);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdss.h b/arch/arm/mach-msm/include/mach/qdss.h
index 3b236b8..05d8577 100644
--- a/arch/arm/mach-msm/include/mach/qdss.h
+++ b/arch/arm/mach-msm/include/mach/qdss.h
@@ -30,6 +30,7 @@
 extern void qdss_put(struct qdss_source *src);
 extern int qdss_enable(struct qdss_source *src);
 extern void qdss_disable(struct qdss_source *src);
+extern void qdss_disable_sink(void);
 extern int qdss_clk_enable(void);
 extern void qdss_clk_disable(void);
 #else
@@ -37,6 +38,7 @@
 static inline void qdss_put(struct qdss_source *src) {}
 static inline int qdss_enable(struct qdss_source *src) { return -ENOSYS; }
 static inline void qdss_disable(struct qdss_source *src) {}
+static inline void qdss_disable_sink(void) {}
 static inline int qdss_clk_enable(void) { return -ENOSYS; }
 static inline void qdss_clk_disable(void) {}
 #endif
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index aee562e..c0ad65b 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -38,10 +38,19 @@
 	of_machine_is_compatible("qcom,msmcopper")
 #define machine_is_copper_sim()		\
 	of_machine_is_compatible("qcom,msmcopper-sim")
+#define machine_is_copper_rumi()	\
+	of_machine_is_compatible("qcom,msmcopper-rumi")
+#define early_machine_is_msm9625()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm9625")
+#define machine_is_msm9625()		\
+	of_machine_is_compatible("qcom,msm9625")
 #else
 #define early_machine_is_copper()	0
 #define machine_is_copper()		0
 #define machine_is_copper_sim()	0
+#define machine_is_copper_rumi()	0
+#define early_machine_is_msm9625()	0
+#define machine_is_msm9625()		0
 #endif
 
 #define PLATFORM_SUBTYPE_SGLTE	6
@@ -61,6 +70,7 @@
 	FSM_CPU_9XXX,
 	MSM_CPU_7X25A,
 	MSM_CPU_7X25AA,
+	MSM_CPU_7X25AB,
 	MSM_CPU_8064,
 	MSM_CPU_8930,
 	MSM_CPU_7X27AA,
@@ -68,6 +78,7 @@
 	MSM_CPU_COPPER,
 	MSM_CPU_8627,
 	MSM_CPU_8625,
+	MSM_CPU_9625
 };
 
 enum msm_cpu socinfo_get_msm_cpu(void);
@@ -167,6 +178,18 @@
 #endif
 }
 
+static inline int cpu_is_msm7x25ab(void)
+{
+#ifdef CONFIG_ARCH_MSM7X27A
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == MSM_CPU_7X25AB;
+#else
+	return 0;
+#endif
+}
+
 static inline int cpu_is_msm7x30(void)
 {
 #ifdef CONFIG_ARCH_MSM7X30
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index 852c8db..319a3ec 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -240,6 +240,12 @@
 /*   SPS_TIMER_MODE_PERIODIC,    Not supported by hardware yet */
 };
 
+/* This enum indicates the cases when callback the user of BAM */
+enum sps_callback_case {
+	SPS_CALLBACK_BAM_ERROR_IRQ = 1,     /* BAM ERROR IRQ */
+	SPS_CALLBACK_BAM_HRESP_ERR_IRQ,	    /* Erroneous HResponse */
+};
+
 /*
  * This enum indicates the command type in a command element
  */
@@ -317,6 +323,9 @@
  * @periph_virt_addr - Peripheral base virtual address.
  * @periph_virt_size - Size for virtual mapping.
  *
+ * @callback - callback function for BAM user.
+ * @user - pointer to user data.
+ *
  * @event_threshold - Pipe event threshold.
  * @desc_size - Size (bytes) of descriptor FIFO.
  * @data_size - Size (bytes) of data FIFO.
@@ -369,6 +378,10 @@
 	u32 desc_mem_id;
 	u32 data_mem_id;
 
+	/* Feedback to BAM user */
+	void (*callback)(enum sps_callback_case, void *);
+	void *user;
+
 	/* Security properties */
 
 	u32 manage;
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index 4caa71b..ec135a3 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,20 @@
 #define _USB_BAM_H_
 
 /**
+ * SPS Pipes direction.
+ *
+ * USB_TO_PEER_PERIPHERAL	USB (as Producer) to other
+ *                          peer peripheral.
+ * PEER_PERIPHERAL_TO_USB	Other Peripheral to
+ *                          USB (as consumer).
+ */
+enum usb_bam_pipe_dir {
+	USB_TO_PEER_PERIPHERAL,
+	PEER_PERIPHERAL_TO_USB,
+};
+
+#ifdef CONFIG_USB_BAM
+/**
  * Connect USB-to-Periperal SPS connection.
  *
  * This function returns the allocated pipes number.
@@ -29,12 +43,31 @@
  * @return 0 on success, negative value on error
  *
  */
-#ifdef CONFIG_USB_BAM
 int usb_bam_connect(u8 idx, u8 *src_pipe_idx, u8 *dst_pipe_idx);
+
+/**
+ * Register a wakeup callback from peer BAM.
+ *
+ * @idx - Connection index.
+ *
+ * @callback - the callback function
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int usb_bam_register_wake_cb(u8 idx,
+	 int (*callback)(void *), void* param);
 #else
-int usb_bam_connect(u8 idx, u8 *src_pipe_idx, u8 *dst_pipe_idx)
+static inline int usb_bam_connect(u8 idx, u8 *src_pipe_idx, u8 *dst_pipe_idx)
+{
+	return -ENODEV;
+}
+
+static inline int usb_bam_register_wake_cb(u8 idx,
+	int (*callback)(void *), void* param)
 {
 	return -ENODEV;
 }
 #endif
 #endif				/* _USB_BAM_H_ */
+
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 7c0de57..59d3a96 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -449,6 +449,29 @@
 void __init msm_map_msm8625_io(void) { return; }
 #endif /* CONFIG_ARCH_MSM8625 */
 
+#ifdef CONFIG_ARCH_MSM9625
+static struct map_desc msm9625_io_desc[] __initdata = {
+	MSM_CHIP_DEVICE(APCS_GCC, MSM9625),
+	MSM_CHIP_DEVICE(TLMM, MSM9625),
+	MSM_CHIP_DEVICE(TMR, MSM9625),
+	{
+		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
+		.length =   MSM_SHARED_RAM_SIZE,
+		.type =     MT_DEVICE,
+	},
+#ifdef CONFIG_DEBUG_MSM9625_UART
+	MSM_DEVICE(DEBUG_UART),
+#endif
+};
+
+void __init msm_map_msm9625_io(void)
+{
+	msm_shared_ram_phys = MSM9625_SHARED_RAM_PHYS;
+	msm_map_io(msm9625_io_desc, ARRAY_SIZE(msm9625_io_desc));
+}
+#endif /* CONFIG_ARCH_MSM9625 */
+
+
 void __iomem *
 __msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
 {
diff --git a/arch/arm/mach-msm/iommu.c b/arch/arm/mach-msm/iommu.c
index 19e1684..49a3e6f 100644
--- a/arch/arm/mach-msm/iommu.c
+++ b/arch/arm/mach-msm/iommu.c
@@ -49,9 +49,11 @@
 #define MSM_IOMMU_ATTR_CACHED_WT	0x3
 
 
-static inline void clean_pte(unsigned long *start, unsigned long *end)
+static inline void clean_pte(unsigned long *start, unsigned long *end,
+			     int redirect)
 {
-	dmac_flush_range(start, end);
+	if (!redirect)
+		dmac_flush_range(start, end);
 }
 
 static int msm_iommu_tex_class[4];
@@ -292,6 +294,9 @@
 
 	memset(priv->pgtable, 0, SZ_16K);
 	domain->priv = priv;
+
+	clean_pte(priv->pgtable, priv->pgtable + NUM_FL_PTE, priv->redirect);
+
 	return 0;
 
 fail_nomem:
@@ -374,6 +379,7 @@
 	__disable_clocks(iommu_drvdata);
 	list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
 
+	ctx_drvdata->attached_domain = domain;
 fail:
 	mutex_unlock(&msm_iommu_lock);
 	return ret;
@@ -411,7 +417,7 @@
 	__reset_context(iommu_drvdata->base, ctx_dev->num);
 	__disable_clocks(iommu_drvdata);
 	list_del_init(&ctx_drvdata->attached_elm);
-
+	ctx_drvdata->attached_domain = NULL;
 fail:
 	mutex_unlock(&msm_iommu_lock);
 }
@@ -517,8 +523,7 @@
 		for (i = 0; i < 16; i++)
 			*(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION
 				  | FL_TYPE_SECT | FL_SHARED | FL_NG | pgprot;
-		if (!priv->redirect)
-			clean_pte(fl_pte, fl_pte + 16);
+		clean_pte(fl_pte, fl_pte + 16, priv->redirect);
 	}
 
 	if (len == SZ_1M) {
@@ -529,8 +534,7 @@
 
 		*fl_pte = (pa & 0xFFF00000) | FL_NG | FL_TYPE_SECT | FL_SHARED
 					    | pgprot;
-		if (!priv->redirect)
-			clean_pte(fl_pte, fl_pte + 1);
+		clean_pte(fl_pte, fl_pte + 1, priv->redirect);
 	}
 
 	/* Need a 2nd level table */
@@ -547,12 +551,12 @@
 				goto fail;
 			}
 			memset(sl, 0, SZ_4K);
+			clean_pte(sl, sl + NUM_SL_PTE, priv->redirect);
 
 			*fl_pte = ((((int)__pa(sl)) & FL_BASE_MASK) | \
 						      FL_TYPE_TABLE);
 
-			if (!priv->redirect)
-				clean_pte(fl_pte, fl_pte + 1);
+			clean_pte(fl_pte, fl_pte + 1, priv->redirect);
 		}
 
 		if (!(*fl_pte & FL_TYPE_TABLE)) {
@@ -573,8 +577,7 @@
 
 		*sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_NG | SL_SHARED
 						    | SL_TYPE_SMALL | pgprot;
-		if (!priv->redirect)
-			clean_pte(sl_pte, sl_pte + 1);
+		clean_pte(sl_pte, sl_pte + 1, priv->redirect);
 	}
 
 	if (len == SZ_64K) {
@@ -590,8 +593,7 @@
 			*(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_NG
 					  | SL_SHARED | SL_TYPE_LARGE | pgprot;
 
-		if (!priv->redirect)
-			clean_pte(sl_pte, sl_pte + 16);
+		clean_pte(sl_pte, sl_pte + 16, priv->redirect);
 	}
 
 	ret = __flush_iotlb_va(domain, va);
@@ -651,15 +653,13 @@
 		for (i = 0; i < 16; i++)
 			*(fl_pte+i) = 0;
 
-		if (!priv->redirect)
-			clean_pte(fl_pte, fl_pte + 16);
+		clean_pte(fl_pte, fl_pte + 16, priv->redirect);
 	}
 
 	if (len == SZ_1M) {
 		*fl_pte = 0;
 
-		if (!priv->redirect)
-			clean_pte(fl_pte, fl_pte + 1);
+		clean_pte(fl_pte, fl_pte + 1, priv->redirect);
 	}
 
 	sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
@@ -670,15 +670,13 @@
 		for (i = 0; i < 16; i++)
 			*(sl_pte+i) = 0;
 
-		if (!priv->redirect)
-			clean_pte(sl_pte, sl_pte + 16);
+		clean_pte(sl_pte, sl_pte + 16, priv->redirect);
 	}
 
 	if (len == SZ_4K) {
 		*sl_pte = 0;
 
-		if (!priv->redirect)
-			clean_pte(sl_pte, sl_pte + 1);
+		clean_pte(sl_pte, sl_pte + 1, priv->redirect);
 	}
 
 	if (len == SZ_4K || len == SZ_64K) {
@@ -691,8 +689,7 @@
 			free_page((unsigned long)sl_table);
 			*fl_pte = 0;
 
-			if (!priv->redirect)
-				clean_pte(fl_pte, fl_pte + 1);
+			clean_pte(fl_pte, fl_pte + 1, priv->redirect);
 		}
 	}
 
@@ -772,10 +769,12 @@
 			}
 
 			memset(sl_table, 0, SZ_4K);
+			clean_pte(sl_table, sl_table + NUM_SL_PTE,
+				  priv->redirect);
+
 			*fl_pte = ((((int)__pa(sl_table)) & FL_BASE_MASK) |
 							    FL_TYPE_TABLE);
-			if (!priv->redirect)
-				clean_pte(fl_pte, fl_pte + 1);
+			clean_pte(fl_pte, fl_pte + 1, priv->redirect);
 		} else
 			sl_table = (unsigned long *)
 					       __va(((*fl_pte) & FL_BASE_MASK));
@@ -808,8 +807,8 @@
 			}
 		}
 
-		if (!priv->redirect)
-			clean_pte(sl_table + sl_start, sl_table + sl_offset);
+		clean_pte(sl_table + sl_start, sl_table + sl_offset,
+			  priv->redirect);
 
 		fl_pte++;
 		sl_offset = 0;
@@ -853,8 +852,8 @@
 			sl_end = NUM_SL_PTE;
 
 		memset(sl_table + sl_start, 0, (sl_end - sl_start) * 4);
-		if (!priv->redirect)
-			clean_pte(sl_table + sl_start, sl_table + sl_end);
+		clean_pte(sl_table + sl_start, sl_table + sl_end,
+			  priv->redirect);
 
 		offset += (sl_end - sl_start) * SZ_4K;
 
@@ -878,8 +877,7 @@
 			free_page((unsigned long)sl_table);
 			*fl_pte = 0;
 
-			if (!priv->redirect)
-				clean_pte(fl_pte, fl_pte + 1);
+			clean_pte(fl_pte, fl_pte + 1, priv->redirect);
 		}
 
 		sl_start = 0;
@@ -974,41 +972,55 @@
 
 irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id)
 {
-	struct msm_iommu_drvdata *drvdata = dev_id;
+	struct msm_iommu_ctx_drvdata *ctx_drvdata = dev_id;
+	struct msm_iommu_drvdata *drvdata;
 	void __iomem *base;
-	unsigned int fsr;
-	int i, ret;
+	unsigned int fsr, num;
+	int ret;
 
 	mutex_lock(&msm_iommu_lock);
+	BUG_ON(!ctx_drvdata);
 
-	if (!drvdata) {
-		pr_err("Invalid device ID in context interrupt handler\n");
-		goto fail;
-	}
+	drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent);
+	BUG_ON(!drvdata);
 
 	base = drvdata->base;
-
-	pr_err("Unexpected IOMMU page fault!\n");
-	pr_err("base = %08x\n", (unsigned int) base);
-	pr_err("name = %s\n", drvdata->name);
+	num = ctx_drvdata->num;
 
 	ret = __enable_clocks(drvdata);
 	if (ret)
 		goto fail;
 
-	for (i = 0; i < drvdata->ncb; i++) {
-		fsr = GET_FSR(base, i);
-		if (fsr) {
-			pr_err("Fault occurred in context %d.\n", i);
+	fsr = GET_FSR(base, num);
+
+	if (fsr) {
+		if (!ctx_drvdata->attached_domain) {
+			pr_err("Bad domain in interrupt handler\n");
+			ret = -ENOSYS;
+		} else
+			ret = report_iommu_fault(ctx_drvdata->attached_domain,
+						&ctx_drvdata->pdev->dev,
+						GET_FAR(base, num), 0);
+
+		if (ret == -ENOSYS) {
+			pr_err("Unexpected IOMMU page fault!\n");
+			pr_err("name    = %s\n", drvdata->name);
+			pr_err("context = %s (%d)\n", ctx_drvdata->name, num);
 			pr_err("Interesting registers:\n");
-			print_ctx_regs(base, i);
-			SET_FSR(base, i, 0x4000000F);
+			print_ctx_regs(base, num);
 		}
-	}
+
+		SET_FSR(base, num, fsr);
+		SET_RESUME(base, num, 1);
+
+		ret = IRQ_HANDLED;
+	} else
+		ret = IRQ_NONE;
+
 	__disable_clocks(drvdata);
 fail:
 	mutex_unlock(&msm_iommu_lock);
-	return 0;
+	return ret;
 }
 
 static phys_addr_t msm_iommu_get_pt_base_addr(struct iommu_domain *domain)
diff --git a/arch/arm/mach-msm/iommu_dev.c b/arch/arm/mach-msm/iommu_dev.c
index 6633cae..b8b5aa3 100644
--- a/arch/arm/mach-msm/iommu_dev.c
+++ b/arch/arm/mach-msm/iommu_dev.c
@@ -131,7 +131,7 @@
 	struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data;
 	void __iomem *regs_base;
 	resource_size_t	len;
-	int ret, irq, par;
+	int ret, par;
 
 	if (pdev->id == -1) {
 		msm_iommu_root_dev = pdev;
@@ -202,12 +202,6 @@
 		goto fail_mem;
 	}
 
-	irq = platform_get_irq_byname(pdev, "nonsecure_irq");
-	if (irq < 0) {
-		ret = -ENODEV;
-		goto fail_io;
-	}
-
 	msm_iommu_reset(regs_base, iommu_dev->ncb);
 
 	SET_M(regs_base, 0, 1);
@@ -226,24 +220,15 @@
 		goto fail_io;
 	}
 
-	ret = request_threaded_irq(irq, NULL, msm_iommu_fault_handler,
-			IRQF_ONESHOT, "msm_iommu_secure_irpt_handler", drvdata);
-	if (ret) {
-		pr_err("Request IRQ %d failed with ret=%d\n", irq, ret);
-		goto fail_io;
-	}
-
-
 	drvdata->pclk = iommu_pclk;
 	drvdata->clk = iommu_clk;
 	drvdata->base = regs_base;
-	drvdata->irq = irq;
 	drvdata->ncb = iommu_dev->ncb;
 	drvdata->ttbr_split = iommu_dev->ttbr_split;
 	drvdata->name = iommu_dev->name;
 
-	pr_info("device %s mapped at %p, irq %d with %d ctx banks\n",
-		iommu_dev->name, regs_base, irq, iommu_dev->ncb);
+	pr_info("device %s mapped at %p, with %d ctx banks\n",
+		iommu_dev->name, regs_base, iommu_dev->ncb);
 
 	platform_set_drvdata(pdev, drvdata);
 
@@ -292,7 +277,7 @@
 	struct msm_iommu_ctx_dev *c = pdev->dev.platform_data;
 	struct msm_iommu_drvdata *drvdata;
 	struct msm_iommu_ctx_drvdata *ctx_drvdata = NULL;
-	int i, ret;
+	int i, ret, irq;
 	if (!c || !pdev->dev.parent) {
 		ret = -EINVAL;
 		goto fail;
@@ -312,6 +297,23 @@
 	}
 	ctx_drvdata->num = c->num;
 	ctx_drvdata->pdev = pdev;
+	ctx_drvdata->name = c->name;
+
+	irq = platform_get_irq_byname(to_platform_device(pdev->dev.parent),
+				      "nonsecure_irq");
+	if (irq < 0) {
+		ret = -ENODEV;
+		goto fail;
+	}
+
+	ret = request_threaded_irq(irq, NULL, msm_iommu_fault_handler,
+				   IRQF_ONESHOT | IRQF_SHARED,
+				   "msm_iommu_nonsecure_irq", ctx_drvdata);
+
+	if (ret) {
+		pr_err("request_threaded_irq %d failed: %d\n", irq, ret);
+		goto fail;
+	}
 
 	INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
 	platform_set_drvdata(pdev, ctx_drvdata);
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 8f4af3b..34c16d1 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -22,8 +22,8 @@
 #include <mach/iommu_domains.h>
 #include <mach/socinfo.h>
 
-/* dummy 4k for overmapping */
-char iommu_dummy[2*PAGE_SIZE-4];
+/* dummy 64K for overmapping */
+char iommu_dummy[2*SZ_64K-4];
 
 struct msm_iommu_domain_state {
 	struct msm_iommu_domain *domains;
@@ -35,36 +35,122 @@
 int msm_iommu_map_extra(struct iommu_domain *domain,
 				unsigned long start_iova,
 				unsigned long size,
+				unsigned long page_size,
 				int cached)
 {
-	int i, ret = 0;
-	struct scatterlist *sglist;
-	unsigned int nrpages = PFN_ALIGN(size) >> PAGE_SHIFT;
-	struct page *dummy_page = phys_to_page(
-					PFN_ALIGN(virt_to_phys(iommu_dummy)));
+	int i, ret_value = 0;
+	unsigned long order = get_order(page_size);
+	unsigned long aligned_size = ALIGN(size, page_size);
+	unsigned long nrpages = aligned_size >> (PAGE_SHIFT + order);
+	unsigned long phy_addr = ALIGN(virt_to_phys(iommu_dummy), page_size);
+	unsigned long temp_iova = start_iova;
 
-	sglist = vmalloc(sizeof(*sglist) * nrpages);
+	for (i = 0; i < nrpages; i++) {
+		int ret = iommu_map(domain, temp_iova, phy_addr, order, cached);
+		if (ret) {
+			pr_err("%s: could not map %lx in domain %p, error: %d\n",
+				__func__, start_iova, domain, ret);
+			ret_value = -EAGAIN;
+			goto out;
+		}
+		temp_iova += page_size;
+	}
+	return ret_value;
+out:
+	for (; i > 0; --i) {
+		temp_iova -= page_size;
+		iommu_unmap(domain, start_iova, order);
+	}
+	return ret_value;
+}
+
+void msm_iommu_unmap_extra(struct iommu_domain *domain,
+				unsigned long start_iova,
+				unsigned long size,
+				unsigned long page_size)
+{
+	int i;
+	unsigned long order = get_order(page_size);
+	unsigned long aligned_size = ALIGN(size, page_size);
+	unsigned long nrpages =  aligned_size >> (PAGE_SHIFT + order);
+	unsigned long temp_iova = start_iova;
+
+	for (i = 0; i < nrpages; ++i) {
+		iommu_unmap(domain, temp_iova, order);
+		temp_iova += page_size;
+	}
+}
+
+static int msm_iommu_map_iova_phys(struct iommu_domain *domain,
+				unsigned long iova,
+				unsigned long phys,
+				unsigned long size,
+				int cached)
+{
+	int ret;
+	struct scatterlist *sglist;
+
+	sglist = vmalloc(sizeof(*sglist));
 	if (!sglist) {
 		ret = -ENOMEM;
 		goto err1;
 	}
 
-	sg_init_table(sglist, nrpages);
+	sg_init_table(sglist, 1);
+	sglist->length = size;
+	sglist->offset = 0;
+	sglist->dma_address = phys;
 
-	for (i = 0; i < nrpages; i++)
-		sg_set_page(&sglist[i], dummy_page, PAGE_SIZE, 0);
-
-	ret = iommu_map_range(domain, start_iova, sglist, size, cached);
+	ret = iommu_map_range(domain, iova, sglist, size, cached);
 	if (ret) {
 		pr_err("%s: could not map extra %lx in domain %p\n",
-			__func__, start_iova, domain);
+			__func__, iova, domain);
 	}
 
 	vfree(sglist);
 err1:
 	return ret;
+
 }
 
+int msm_iommu_map_contig_buffer(unsigned long phys,
+				unsigned int domain_no,
+				unsigned int partition_no,
+				unsigned long size,
+				unsigned long align,
+				unsigned long cached,
+				unsigned long *iova_val)
+{
+	unsigned long iova;
+	int ret;
+
+	if (size & (align - 1))
+		return -EINVAL;
+
+	iova = msm_allocate_iova_address(domain_no, partition_no, size, align);
+
+	if (!iova)
+		return -ENOMEM;
+
+	ret = msm_iommu_map_iova_phys(msm_get_iommu_domain(domain_no), iova,
+					phys, size, cached);
+
+	if (ret)
+		msm_free_iova_address(iova, domain_no, partition_no, size);
+	else
+		*iova_val = iova;
+
+	return ret;
+}
+
+void msm_iommu_unmap_contig_buffer(unsigned long iova,
+					unsigned int domain_no,
+					unsigned int partition_no,
+					unsigned long size)
+{
+	iommu_unmap_range(msm_get_iommu_domain(domain_no), iova, size);
+	msm_free_iova_address(iova, domain_no, partition_no, size);
+}
 
 struct iommu_domain *msm_get_iommu_domain(int domain_num)
 {
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 6e8c99e..085b87a 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -21,6 +21,10 @@
 #include <linux/gfp.h>
 #include <linux/msm_ipc.h>
 
+#ifdef CONFIG_ANDROID_PARANOID_NETWORK
+#include <linux/android_aid.h>
+#endif
+
 #include <asm/string.h>
 #include <asm/atomic.h>
 
@@ -39,6 +43,21 @@
 static struct proto msm_ipc_proto;
 static const struct proto_ops msm_ipc_proto_ops;
 
+#ifdef CONFIG_ANDROID_PARANOID_NETWORK
+static inline int check_permissions(void)
+{
+	int rc = 0;
+	if (!current_euid() || in_egroup_p(AID_NET_RAW))
+		rc = 1;
+	return rc;
+}
+# else
+static inline int check_permissions(void)
+{
+	return 1;
+}
+#endif
+
 static void msm_ipc_router_unload_modem(void *pil)
 {
 	if (pil)
@@ -214,6 +233,11 @@
 	struct msm_ipc_port *port_ptr;
 	void *pil;
 
+	if (!check_permissions()) {
+		pr_err("%s: Do not have permissions\n", __func__);
+		return -EPERM;
+	}
+
 	if (unlikely(protocol != 0)) {
 		pr_err("%s: Protocol not supported\n", __func__);
 		return -EPROTONOSUPPORT;
diff --git a/arch/arm/mach-msm/lpass-8960.c b/arch/arm/mach-msm/lpass-8960.c
index 7775740..c58b0e1 100644
--- a/arch/arm/mach-msm/lpass-8960.c
+++ b/arch/arm/mach-msm/lpass-8960.c
@@ -31,6 +31,7 @@
 
 #define SCM_Q6_NMI_CMD                  0x1
 #define MODULE_NAME			"lpass_8960"
+#define MAX_BUF_SIZE			0x51
 
 /* Subsystem restart: QDSP6 data, functions */
 static void lpass_fatal_fn(struct work_struct *);
@@ -86,10 +87,39 @@
 	.notifier_call = modem_notifier_cb,
 };
 
+static void lpass_log_failure_reason(void)
+{
+	char *reason;
+	char buffer[MAX_BUF_SIZE];
+	unsigned size;
+
+	reason = smem_get_entry(SMEM_SSR_REASON_LPASS0, &size);
+
+	if (!reason) {
+		pr_err("%s: subsystem failure reason: (unknown, smem_get_entry failed).",
+			 MODULE_NAME);
+		return;
+	}
+
+	if (reason[0] == '\0') {
+		pr_err("%s: subsystem failure reason: (unknown, init value found)",
+			 MODULE_NAME);
+		return;
+	}
+
+	size = size < MAX_BUF_SIZE ? size : (MAX_BUF_SIZE-1);
+	memcpy(buffer, reason, size);
+	buffer[size] = '\0';
+	pr_err("%s: subsystem failure reason: %s", MODULE_NAME, buffer);
+	memset((void *)reason, 0x0, size);
+	wmb();
+}
+
 static void lpass_fatal_fn(struct work_struct *work)
 {
 	pr_err("%s %s: Watchdog bite received from Q6!\n", MODULE_NAME,
 		__func__);
+	lpass_log_failure_reason();
 	panic(MODULE_NAME ": Resetting the SoC");
 }
 
@@ -104,6 +134,7 @@
 		pr_err("%s: LPASS SMSM state changed to SMSM_RESET,"
 			" new_state = 0x%x, old_state = 0x%x\n", __func__,
 			new_state, old_state);
+		lpass_log_failure_reason();
 		panic(MODULE_NAME ": Resetting the SoC");
 	}
 }
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
new file mode 100644
index 0000000..48cf3f7
--- /dev/null
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -0,0 +1,232 @@
+/* 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <mach/mpm.h>
+#include "rpm_resources.h"
+
+static struct msm_rpmrs_level *msm_lpm_levels;
+static int msm_lpm_level_count;
+
+int msm_rpmrs_enter_sleep(uint32_t sclk_count, struct msm_rpmrs_limits *limits,
+		bool from_idle, bool notify_rpm)
+{
+	/* TODO */
+	return 0;
+}
+
+void msm_rpmrs_exit_sleep(struct msm_rpmrs_limits *limits, bool from_idle,
+		bool notify_rpm, bool collapsed)
+{
+	/* TODO */
+	return;
+}
+
+static bool msm_rpmrs_irqs_detectable(struct msm_rpmrs_limits *limits,
+		bool irqs_detect, bool gpio_detect)
+{
+	/* TODO */
+	return true;
+}
+
+void msm_rpmrs_show_resources(void)
+{
+	/* TODO */
+	return;
+}
+
+struct msm_rpmrs_limits *msm_rpmrs_lowest_limits(
+	bool from_idle, enum msm_pm_sleep_mode sleep_mode, uint32_t latency_us,
+	uint32_t sleep_us)
+{
+	unsigned int cpu = smp_processor_id();
+	struct msm_rpmrs_level *best_level = NULL;
+	bool irqs_detectable = false;
+	bool gpio_detectable = false;
+	int i;
+
+	if (!msm_lpm_levels)
+		return NULL;
+
+	if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
+		irqs_detectable = msm_mpm_irqs_detectable(from_idle);
+		gpio_detectable = msm_mpm_gpio_irqs_detectable(from_idle);
+	}
+
+	for (i = 0; i < msm_lpm_level_count; i++) {
+		struct msm_rpmrs_level *level = &msm_lpm_levels[i];
+		uint32_t power;
+
+		if (!level->available)
+			continue;
+
+		if (sleep_mode != level->sleep_mode)
+			continue;
+
+		if (latency_us < level->latency_us)
+			continue;
+
+		if (!msm_rpmrs_irqs_detectable(&level->rs_limits,
+					irqs_detectable, gpio_detectable))
+			continue;
+
+		if (sleep_us <= 1) {
+			power = level->energy_overhead;
+		} else if (sleep_us <= level->time_overhead_us) {
+			power = level->energy_overhead / sleep_us;
+		} else if ((sleep_us >> 10) > level->time_overhead_us) {
+			power = level->steady_state_power;
+		} else {
+			power = level->steady_state_power;
+			power -= (level->time_overhead_us *
+					level->steady_state_power)/sleep_us;
+			power += level->energy_overhead / sleep_us;
+		}
+
+		if (!best_level ||
+				best_level->rs_limits.power[cpu] >= power) {
+			level->rs_limits.latency_us[cpu] = level->latency_us;
+			level->rs_limits.power[cpu] = power;
+			best_level = level;
+		}
+	}
+
+	return best_level ? &best_level->rs_limits : NULL;
+}
+
+static int __devinit msm_lpm_levels_probe(struct platform_device *pdev)
+{
+	struct msm_rpmrs_level *levels = NULL;
+	struct msm_rpmrs_level *level = NULL;
+	struct device_node *node = NULL;
+	char *key = NULL;
+	uint32_t val = 0;
+	int ret = 0;
+	uint32_t num_levels = 0;
+	int idx = 0;
+
+	for_each_child_of_node(pdev->dev.of_node, node)
+		num_levels++;
+
+	levels = kzalloc(num_levels * sizeof(struct msm_rpmrs_level),
+			GFP_KERNEL);
+	if (!levels)
+		return -ENOMEM;
+
+	for_each_child_of_node(pdev->dev.of_node, node) {
+		level = &levels[idx++];
+		level->available = false;
+
+		key = "qcom,mode";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->sleep_mode = val;
+
+		key = "qcom,xo";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->rs_limits.pxo = val;
+
+		key = "qcom,l2";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->rs_limits.l2_cache = val;
+
+		key = "qcom,vdd-dig-upper-bound";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->rs_limits.vdd_dig_upper_bound = val;
+
+		key = "qcom,vdd-dig-lower-bound";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->rs_limits.vdd_dig = val;
+
+		key = "qcom,vdd-mem-upper-bound";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->rs_limits.vdd_mem_upper_bound = val;
+
+		key = "qcom,vdd-mem-lower-bound";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->rs_limits.vdd_mem = val;
+
+		key = "qcom,latency-us";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->latency_us = val;
+
+		key = "qcom,ss-power";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->steady_state_power = val;
+
+		key = "qcom,energy-overhead";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->energy_overhead = val;
+
+		key = "qcom,time-overhead";
+		ret = of_property_read_u32(node, key, &val);
+		if (ret)
+			goto fail;
+		level->time_overhead_us = val;
+
+		level->available = true;
+	}
+
+	msm_lpm_levels = levels;
+	msm_lpm_level_count = idx;
+
+	return 0;
+fail:
+	pr_err("%s: Error in name %s key %s\n", __func__, node->full_name, key);
+	kfree(levels);
+	return -EFAULT;
+}
+
+static struct of_device_id msm_lpm_levels_match_table[] = {
+	{.compatible = "qcom,lpm-levels"},
+	{},
+};
+
+static struct platform_driver msm_lpm_levels_driver = {
+	.probe = msm_lpm_levels_probe,
+	.driver = {
+		.name = "lpm-levels",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_lpm_levels_match_table,
+	},
+};
+
+static int __init msm_lpm_levels_module_init(void)
+{
+	return platform_driver_register(&msm_lpm_levels_driver);
+}
+late_initcall(msm_lpm_levels_module_init);
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index 0db160e..ccb18b3 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -332,29 +332,6 @@
 	}
 }
 
-unsigned long __init reserve_memory_for_fmem(unsigned long fmem_size)
-{
-	struct membank *mb;
-	int ret;
-	unsigned long fmem_phys;
-
-	if (!fmem_size)
-		return 0;
-
-	mb = &meminfo.bank[meminfo.nr_banks - 1];
-	/*
-	 * Placing fmem at the top of memory causes multimedia issues.
-	 * Instead, place it 1 page below the top of memory to prevent
-	 * the issues from occurring.
-	 */
-	fmem_phys = mb->start + (mb->size - fmem_size) - PAGE_SIZE;
-	ret = memblock_remove(fmem_phys, fmem_size);
-	BUG_ON(ret);
-
-	pr_info("fmem start %lx size %lx\n", fmem_phys, fmem_size);
-	return fmem_phys;
-}
-
 static void __init initialize_mempools(void)
 {
 	struct mem_pool *mpool;
diff --git a/arch/arm/mach-msm/modem-8960.c b/arch/arm/mach-msm/modem-8960.c
index 7df1c3a..4922007 100644
--- a/arch/arm/mach-msm/modem-8960.c
+++ b/arch/arm/mach-msm/modem-8960.c
@@ -27,6 +27,7 @@
 #include <mach/subsystem_restart.h>
 #include <mach/subsystem_notif.h>
 #include <mach/socinfo.h>
+#include <mach/msm_smsm.h>
 
 #include "smd_private.h"
 #include "modem_notifier.h"
@@ -34,6 +35,55 @@
 
 static int crash_shutdown;
 
+#define MAX_SSR_REASON_LEN 81U
+#define Q6_FW_WDOG_ENABLE		0x08882024
+#define Q6_SW_WDOG_ENABLE		0x08982024
+
+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, init string found).\n");
+		return;
+	}
+
+	size = min(size, MAX_SSR_REASON_LEN-1);
+	memcpy(reason, smem_reason, size);
+	reason[size] = '\0';
+	pr_err("modem subsystem failure reason: %s.\n", reason);
+
+	smem_reason[0] = '\0';
+	wmb();
+}
+
+static void modem_wdog_check(struct work_struct *work)
+{
+	void __iomem *q6_sw_wdog_addr;
+	u32 regval;
+
+	q6_sw_wdog_addr = ioremap_nocache(Q6_SW_WDOG_ENABLE, 4);
+	if (!q6_sw_wdog_addr)
+		panic("Unable to check modem watchdog status.\n");
+
+	regval = readl_relaxed(q6_sw_wdog_addr);
+	if (!regval) {
+		pr_err("modem-8960: Modem watchdog wasn't activated!. Restarting the modem now.\n");
+		log_modem_sfr();
+		subsystem_restart("modem");
+	}
+
+	iounmap(q6_sw_wdog_addr);
+}
+
+static DECLARE_DELAYED_WORK(modem_wdog_check_work, modem_wdog_check);
+
 static void modem_sw_fatal_fn(struct work_struct *work)
 {
 	uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
@@ -50,6 +100,7 @@
 		pr_err("Modem SMSM state changed to SMSM_RESET.\n"
 			"Probable err_fatal on the modem. "
 			"Calling subsystem restart...\n");
+		log_modem_sfr();
 		subsystem_restart("modem");
 
 	} else if (modem_state & reset_smsm_states) {
@@ -59,7 +110,7 @@
 			__func__);
 		kernel_restart(NULL);
 	} else {
-		/* TODO: Bus unlock code/sequence goes _here_ */
+		log_modem_sfr();
 		subsystem_restart("modem");
 	}
 }
@@ -67,6 +118,7 @@
 static void modem_fw_fatal_fn(struct work_struct *work)
 {
 	pr_err("Watchdog bite received from modem FW!\n");
+	log_modem_sfr();
 	subsystem_restart("modem");
 }
 
@@ -80,21 +132,24 @@
 		return;
 
 	if (new_state & SMSM_RESET) {
-		pr_err("Modem SMSM state changed to SMSM_RESET.\n"
-			"Probable err_fatal on the modem. "
-			"Calling subsystem restart...\n");
+		pr_err("Probable fatal error on the modem.\n");
+		log_modem_sfr();
 		subsystem_restart("modem");
 	}
 }
 
-#define Q6_FW_WDOG_ENABLE		0x08882024
-#define Q6_SW_WDOG_ENABLE		0x08982024
 static int modem_shutdown(const struct subsys_data *subsys)
 {
 	void __iomem *q6_fw_wdog_addr;
 	void __iomem *q6_sw_wdog_addr;
 
 	/*
+	 * Cancel any pending wdog_check work items, since we're shutting
+	 * down anyway.
+	 */
+	cancel_delayed_work(&modem_wdog_check_work);
+
+	/*
 	 * Disable the modem watchdog since it keeps running even after the
 	 * modem is shutdown.
 	 */
@@ -122,12 +177,16 @@
 	return 0;
 }
 
+#define MODEM_WDOG_CHECK_TIMEOUT_MS 10000
+
 static int modem_powerup(const struct subsys_data *subsys)
 {
 	pil_force_boot("modem_fw");
 	pil_force_boot("modem");
 	enable_irq(Q6FW_WDOG_EXPIRED_IRQ);
 	enable_irq(Q6SW_WDOG_EXPIRED_IRQ);
+	schedule_delayed_work(&modem_wdog_check_work,
+				msecs_to_jiffies(MODEM_WDOG_CHECK_TIMEOUT_MS));
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/mpm-8625.c b/arch/arm/mach-msm/mpm-8625.c
index 6b88103..fa966d2 100644
--- a/arch/arm/mach-msm/mpm-8625.c
+++ b/arch/arm/mach-msm/mpm-8625.c
@@ -25,20 +25,14 @@
 #include <asm/hardware/gic.h>
 #include <mach/msm_smsm.h>
 
+#include "mpm-8625.h"
+
 #define NUM_REGS_ENABLE		2
 /* (NR_MSM_IRQS/32) 96 max irqs supported */
 #define NUM_REGS_DISABLE	3
 #define GIC_IRQ_MASK(irq)	BIT(irq % 32)
 #define GIC_IRQ_INDEX(irq)	(irq / 32)
 
-#ifdef CONFIG_PM
-u32 saved_spi_enable[DIV_ROUND_UP(256, 32)];
-u32 saved_spi_conf[DIV_ROUND_UP(256, 16)];
-u32 saved_spi_target[DIV_ROUND_UP(256, 4)];
-u32 __percpu *saved_ppi_enable;
-u32 __percpu *saved_ppi_conf;
-#endif
-
 enum {
 	IRQ_DEBUG_SLEEP_INT_TRIGGER	= BIT(0),
 	IRQ_DEBUG_SLEEP_INT		= BIT(1),
@@ -54,10 +48,6 @@
 static uint32_t msm_gic_irq_smsm_wake_enable[NUM_REGS_ENABLE];
 static uint32_t msm_gic_irq_idle_disable[NUM_REGS_DISABLE];
 
-static DEFINE_RAW_SPINLOCK(gic_controller_lock);
-static void __iomem *dist_base, *cpu_base;
-static unsigned int max_irqs;
-
  /*
   * Some of the interrupts which will not be considered as wake capable
   * should be marked as FAKE.
@@ -162,158 +152,17 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static void __init msm_gic_pm_init(void)
-{
-	saved_ppi_enable =  __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
-						sizeof(u32));
-	BUG_ON(!saved_ppi_enable);
-
-	saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4,
-						sizeof(u32));
-	BUG_ON(!saved_ppi_conf);
-}
-#endif
-
 void __init msm_gic_irq_extn_init(void __iomem *db, void __iomem *cb)
 {
-	dist_base = db;
-	cpu_base = cb;
-	max_irqs = readl_relaxed(dist_base + GIC_DIST_CTR) & 0x11f;
-	max_irqs = (max_irqs + 1) * 32;
-
 	gic_arch_extn.irq_mask	= msm_gic_mask_irq;
 	gic_arch_extn.irq_unmask = msm_gic_unmask_irq;
 	gic_arch_extn.irq_disable = msm_gic_mask_irq;
 	gic_arch_extn.irq_set_wake = msm_gic_set_irq_wake;
-
-#ifdef CONFIG_PM
-	msm_gic_pm_init();
-#endif
-}
-
-/* GIC APIs */
-
- /*
-  * Save the GIC cpu and distributor context before PC and
-  * restor it back after coming out of PC.
-  */
-static void msm_gic_save(void)
-{
-	int i;
-	u32 *ptr;
-
-	/* Save the Per CPU PPI's */
-	ptr = __this_cpu_ptr(saved_ppi_enable);
-	/* 0 - 31 the SGI and PPI */
-	ptr[0] = readl_relaxed(dist_base +  GIC_DIST_ENABLE_SET);
-
-	ptr = __this_cpu_ptr(saved_ppi_conf);
-	for (i = 0; i < 2; i++)
-		ptr[i] =  readl_relaxed(dist_base +  GIC_DIST_CONFIG + i * 4);
-
-	/* Save the SPIs */
-	for (i = 0; (i * 16) < max_irqs; i++)
-		saved_spi_conf[i] =
-			readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
-
-	for (i = 0; (i * 4) < max_irqs; i++)
-		saved_spi_target[i] =
-			readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
-
-	for (i = 0; (i * 32) < max_irqs; i++)
-		saved_spi_enable[i] =
-		readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
-}
-
-static void msm_gic_restore(void)
-{
-	int i;
-	u32 *ptr;
-
-	/* restore CPU Interface */
-	/* Per CPU SGIs and PPIs */
-	ptr = __this_cpu_ptr(saved_ppi_enable);
-	writel_relaxed(ptr[0], dist_base + GIC_DIST_ENABLE_SET);
-
-	ptr = __this_cpu_ptr(saved_ppi_conf);
-	for (i = 0; i < 2; i++)
-		writel_relaxed(ptr[i], dist_base +  GIC_DIST_CONFIG + i * 4);
-
-	for (i = 0; (i * 4) < max_irqs; i++)
-		writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
-
-	writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
-	writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
-
-	/* restore Distributor */
-	writel_relaxed(0, dist_base + GIC_DIST_CTRL);
-
-	for (i = 0; (i * 16) < max_irqs; i++)
-		writel_relaxed(saved_spi_conf[i],
-				dist_base + GIC_DIST_CONFIG + i * 4);
-
-	for (i = 0; (i * 4) < max_irqs; i++)
-		writel_relaxed(0xa0a0a0a0,
-				dist_base + GIC_DIST_PRI + i * 4);
-
-	for (i = 0; (i * 4) < max_irqs; i++)
-		writel_relaxed(saved_spi_target[i],
-				dist_base + GIC_DIST_TARGET + i * 4);
-
-	for (i = 0; (i * 32) < max_irqs; i++)
-		writel_relaxed(saved_spi_enable[i],
-				dist_base + GIC_DIST_ENABLE_SET + i * 4);
-
-	writel_relaxed(1, dist_base + GIC_DIST_CTRL);
-
-	mb();
 }
 
 /* Power APIs */
 
  /*
-  *  Check for any interrupts which are enabled are pending
-  *  in the pending set or not.
-  *  Return :
-  *       0 : No pending interrupts
-  *       1 : Pending interrupts other than A9_M2A_5
-  */
-unsigned int msm_gic_spi_ppi_pending(void)
-{
-	unsigned int i, bit = 0;
-	unsigned int pending_enb = 0, pending = 0;
-	unsigned long value = 0;
-
-	raw_spin_lock(&gic_controller_lock);
-	/*
-	 * PPI and SGI to be included.
-	 * MSM8625_INT_A9_M2A_5 needs to be ignored, as A9_M2A_5
-	 * requesting sleep triggers it
-	 */
-	for (i = 0; (i * 32) < max_irqs; i++) {
-		pending = readl_relaxed(dist_base +
-				GIC_DIST_PENDING_SET + i * 4);
-		pending_enb = readl_relaxed(dist_base +
-				GIC_DIST_ENABLE_SET + i * 4);
-		value = pending & pending_enb;
-
-		if (value) {
-			for (bit = 0; bit < 32; bit++) {
-				bit = find_next_bit(&value, 32, bit);
-				if ((bit + 32 * i) != MSM8625_INT_A9_M2A_5) {
-					raw_spin_unlock(&gic_controller_lock);
-					return 1;
-				}
-			}
-		}
-	}
-	raw_spin_unlock(&gic_controller_lock);
-
-	return 0;
-}
-
- /*
   * Iterate over the disable list
   */
 
@@ -352,8 +201,6 @@
   */
 int msm_gic_irq_enter_sleep2(bool modem_wake, int from_idle)
 {
-	int i;
-
 	if (from_idle && !modem_wake)
 		return 0;
 
@@ -371,14 +218,10 @@
 	}
 
 	if (modem_wake) {
-		/* save the contents of GIC CPU interface and Distributor */
-		msm_gic_save();
-		/* Disable all the Interrupts, if we enter from idle pc */
-		if (from_idle) {
-			for (i = 0; (i * 32) < max_irqs; i++)
-				writel_relaxed(0xffffffff, dist_base
-					+ GIC_DIST_ENABLE_CLEAR + i * 4);
-		}
+		/* save the contents of GIC CPU interface and Distributor
+		 * Disable all the Interrupts, if we enter from idle pc
+		 */
+		msm_gic_save(modem_wake, from_idle);
 		irq_set_irq_type(MSM8625_INT_A9_M2A_6, IRQF_TRIGGER_RISING);
 		enable_irq(MSM8625_INT_A9_M2A_6);
 		pr_debug("%s going for sleep now\n", __func__);
diff --git a/arch/arm/mach-msm/msm_cache_dump.c b/arch/arm/mach-msm/msm_cache_dump.c
index 404c8f0..191e950 100644
--- a/arch/arm/mach-msm/msm_cache_dump.c
+++ b/arch/arm/mach-msm/msm_cache_dump.c
@@ -26,7 +26,7 @@
 #include <mach/memory.h>
 #include <mach/msm_iomap.h>
 
-#define L2C_IMEM_ADDR 0x2a03f014
+#define L2_DUMP_OFFSET 0x14
 
 static unsigned long msm_cache_dump_addr;
 
@@ -66,9 +66,6 @@
 		unsigned long buf;
 		unsigned long size;
 	} l1_cache_data;
-#ifndef CONFIG_MSM_CACHE_DUMP_ON_PANIC
-	unsigned int *imem_loc;
-#endif
 	void *temp;
 	unsigned long total_size = d->l1_size + d->l2_size;
 
@@ -105,9 +102,8 @@
 		pr_err("%s: could not register L2 buffer ret = %d.\n",
 			__func__, ret);
 #else
-	imem_loc = ioremap(L2C_IMEM_ADDR, SZ_4K);
-	__raw_writel(msm_cache_dump_addr + d->l1_size, imem_loc);
-	iounmap(imem_loc);
+	__raw_writel(msm_cache_dump_addr + d->l1_size,
+			MSM_IMEM_BASE + L2_DUMP_OFFSET);
 #endif
 
 	atomic_notifier_chain_register(&panic_notifier_list,
diff --git a/arch/arm/mach-msm/msm_watchdog.c b/arch/arm/mach-msm/msm_watchdog.c
index aabb644..9b8bc61 100644
--- a/arch/arm/mach-msm/msm_watchdog.c
+++ b/arch/arm/mach-msm/msm_watchdog.c
@@ -217,6 +217,9 @@
 	unsigned long long slack_ns;
 	unsigned long long bark_time_ns = bark_time * 1000000ULL;
 
+	if (!enable)
+		return;
+
 	slack = __raw_readl(msm_tmr0_base + WDT0_STS) >> 3;
 	slack = ((bark_time*WDT_HZ)/1000) - slack;
 	if (slack < min_slack_ticks)
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
new file mode 100644
index 0000000..af39dc3
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem.c
@@ -0,0 +1,304 @@
+/* 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 <mach/ocmem_priv.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/rbtree.h>
+#include <linux/genalloc.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+struct ocmem_partition {
+	const char *name;
+	int id;
+	unsigned long p_start;
+	unsigned long p_size;
+	unsigned long p_min;
+};
+
+struct ocmem_plat_data {
+	void __iomem *vbase;
+	unsigned long size;
+	unsigned long base;
+	struct ocmem_partition *parts;
+	int nr_parts;
+};
+
+struct ocmem_zone zones[OCMEM_CLIENT_MAX];
+
+struct ocmem_zone *get_zone(unsigned id)
+{
+	if (id < OCMEM_GRAPHICS || id >= OCMEM_CLIENT_MAX)
+		return NULL;
+	else
+		return &zones[id];
+}
+
+static struct ocmem_plat_data *ocmem_pdata;
+
+#define CLIENT_NAME_MAX 10
+/* Must be in sync with enum ocmem_client */
+static const char *client_names[OCMEM_CLIENT_MAX] = {
+	"graphics",
+	"video",
+	"camera",
+	"hp_audio",
+	"voice",
+	"lp_audio",
+	"sensors",
+	"blast",
+};
+
+struct ocmem_quota_table {
+	const char *name;
+	int id;
+	unsigned long start;
+	unsigned long size;
+	unsigned long min;
+};
+
+/* This static table will go away with device tree support */
+static struct ocmem_quota_table qt[OCMEM_CLIENT_MAX] = {
+	/* name,	id,	start,	size,	min */
+	{ "graphics", OCMEM_GRAPHICS, 0x0, 0x100000, 0x80000},
+	{ "video", OCMEM_VIDEO, 0x100000, 0x80000, 0x55000},
+	{ "camera", OCMEM_CAMERA, 0x0, 0x0, 0x0},
+	{ "voice", OCMEM_VOICE,  0x0, 0x0, 0x0 },
+	{ "hp_audio", OCMEM_HP_AUDIO, 0x0, 0x0, 0x0},
+	{ "lp_audio", OCMEM_LP_AUDIO, 0x80000, 0xA0000, 0xA0000},
+	{ "blast", OCMEM_BLAST, 0x120000, 0x20000, 0x20000},
+	{ "sensors", OCMEM_SENSORS, 0x140000, 0x40000, 0x40000},
+};
+
+static inline int get_id(const char *name)
+{
+	int i = 0;
+	for (i = 0 ; i < OCMEM_CLIENT_MAX; i++) {
+		if (strncmp(name, client_names[i], CLIENT_NAME_MAX) == 0)
+			return i;
+	}
+	return -EINVAL;
+}
+
+static struct ocmem_plat_data *parse_static_config(struct platform_device *pdev)
+{
+	struct ocmem_plat_data *pdata = NULL;
+	struct ocmem_partition *parts = NULL;
+	struct device   *dev = &pdev->dev;
+	int nr_parts;
+	int i;
+	int j;
+
+	pdata = devm_kzalloc(dev, sizeof(struct ocmem_plat_data),
+			GFP_KERNEL);
+
+	if (!pdata) {
+		dev_err(dev, "Unable to allocate memory for"
+			" platform data\n");
+		return NULL;
+	}
+
+	for (i = 0 ; i < ARRAY_SIZE(qt); i++)
+		if (qt[i].size != 0x0)
+			nr_parts++;
+
+	if (nr_parts == 0x0) {
+		dev_err(dev, "No valid ocmem partitions\n");
+		return NULL;
+	} else
+		dev_info(dev, "Total partitions = %d\n", nr_parts);
+
+	parts = devm_kzalloc(dev, sizeof(struct ocmem_partition) * nr_parts,
+				 GFP_KERNEL);
+
+	if (!parts) {
+		dev_err(dev, "Unable to allocate memory for"
+			" partition data\n");
+		return NULL;
+	}
+
+	for (i = 0, j = 0; i < ARRAY_SIZE(qt); i++) {
+		if (qt[i].size == 0x0) {
+			dev_dbg(dev, "Skipping creation of pool for %s\n",
+						qt[i].name);
+			continue;
+		}
+		parts[j].id = qt[i].id;
+		parts[j].p_size = qt[i].size;
+		parts[j].p_start = qt[i].start;
+		parts[j].p_min = qt[i].min;
+		j++;
+	}
+	BUG_ON(j != nr_parts);
+	pdata->nr_parts = nr_parts;
+	pdata->parts = parts;
+	pdata->base = OCMEM_PHYS_BASE;
+	pdata->size = OCMEM_PHYS_SIZE;
+	return pdata;
+}
+
+static struct ocmem_plat_data *parse_dt_config(struct platform_device *pdev)
+{
+	return NULL;
+}
+
+static int ocmem_zone_init(struct platform_device *pdev)
+{
+
+	int ret = -1;
+	int i = 0;
+	unsigned active_zones = 0;
+
+	struct ocmem_zone *zone = NULL;
+	struct ocmem_zone_ops *z_ops = NULL;
+	struct device   *dev = &pdev->dev;
+	unsigned long start;
+	struct ocmem_plat_data *pdata = NULL;
+
+	pdata = platform_get_drvdata(pdev);
+
+	for (i = 0; i < pdata->nr_parts; i++) {
+		struct ocmem_partition *part = &pdata->parts[i];
+		zone = get_zone(part->id);
+
+		dev_dbg(dev, "Partition %d, start %lx, size %lx for %s\n",
+				i, part->p_start, part->p_size,
+				client_names[part->id]);
+
+		if (part->p_size > pdata->size) {
+			dev_alert(dev, "Quota > ocmem_size for id:%d\n",
+					part->id);
+			continue;
+		}
+
+		zone->z_pool = gen_pool_create(PAGE_SHIFT, -1);
+
+		if (!zone->z_pool) {
+			dev_alert(dev, "Creating pool failed for id:%d\n",
+					part->id);
+			return -EBUSY;
+		}
+
+		start = pdata->base + part->p_start;
+		ret = gen_pool_add(zone->z_pool, start,
+					part->p_size, -1);
+
+		if (ret < 0) {
+			gen_pool_destroy(zone->z_pool);
+			dev_alert(dev, "Unable to back pool %d with "
+				"buffer:%lx\n", part->id, part->p_size);
+			return -EBUSY;
+		}
+
+		/* Initialize zone allocators */
+		z_ops = devm_kzalloc(dev, sizeof(struct ocmem_zone_ops),
+				GFP_KERNEL);
+		if (!z_ops) {
+			pr_alert("ocmem: Unable to allocate memory for"
+					"zone ops:%d\n", i);
+			return -EBUSY;
+		}
+
+		/* Initialize zone parameters */
+		zone->z_start = start;
+		zone->z_head = zone->z_start;
+		zone->z_end = start + part->p_size;
+		zone->z_tail = zone->z_end;
+		zone->z_free = part->p_size;
+		zone->owner = part->id;
+		zone->active_regions = 0;
+		zone->max_regions = 0;
+		INIT_LIST_HEAD(&zone->region_list);
+		zone->z_ops = z_ops;
+		active_zones++;
+
+		if (active_zones == 1)
+			pr_info("Physical OCMEM zone layout:\n");
+
+		pr_info(" zone %s\t: 0x%08lx - 0x%08lx (%4ld KB)\n",
+				client_names[part->id], zone->z_start,
+				zone->z_end, part->p_size/SZ_1K);
+	}
+
+	dev_info(dev, "Total active zones = %d\n", active_zones);
+	return 0;
+}
+
+static int __devinit msm_ocmem_probe(struct platform_device *pdev)
+{
+	struct device   *dev = &pdev->dev;
+
+	if (!pdev->dev.of_node->child) {
+		dev_info(dev, "Missing Configuration in Device Tree\n");
+		ocmem_pdata = parse_static_config(pdev);
+	} else {
+		ocmem_pdata = parse_dt_config(pdev);
+	}
+
+	/* Check if we have some configuration data to start */
+	if (!ocmem_pdata)
+		return -ENODEV;
+
+	/* Sanity Checks */
+	BUG_ON(!IS_ALIGNED(ocmem_pdata->size, PAGE_SIZE));
+	BUG_ON(!IS_ALIGNED(ocmem_pdata->base, PAGE_SIZE));
+
+	platform_set_drvdata(pdev, ocmem_pdata);
+
+	if (ocmem_zone_init(pdev))
+		return -EBUSY;
+
+	dev_info(dev, "initialized successfully\n");
+	return 0;
+}
+
+static int __devexit msm_ocmem_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct of_device_id msm_ocmem_dt_match[] = {
+	{       .compatible = "qcom,msm_ocmem",
+	},
+	{}
+};
+
+static struct platform_driver msm_ocmem_driver = {
+	.probe = msm_ocmem_probe,
+	.remove = __devexit_p(msm_ocmem_remove),
+	.driver = {
+		.name = "msm_ocmem",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_ocmem_dt_match,
+	},
+};
+
+static int __init ocmem_init(void)
+{
+	return platform_driver_register(&msm_ocmem_driver);
+}
+subsys_initcall(ocmem_init);
+
+static void __exit ocmem_exit(void)
+{
+	platform_driver_unregister(&msm_ocmem_driver);
+}
+module_exit(ocmem_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Support for On-Chip Memory on MSM");
diff --git a/arch/arm/mach-msm/pcie.c b/arch/arm/mach-msm/pcie.c
new file mode 100644
index 0000000..4e2b1083
--- /dev/null
+++ b/arch/arm/mach-msm/pcie.c
@@ -0,0 +1,669 @@
+/* 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.
+ */
+
+/*
+ * MSM PCIe controller driver.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <asm/mach/pci.h>
+#include <mach/gpiomux.h>
+#include <mach/hardware.h>
+#include <mach/msm_iomap.h>
+
+#include "pcie.h"
+
+/* Root Complex Port vendor/device IDs */
+#define PCIE_VENDOR_ID_RCP             0x17cb
+#define PCIE_DEVICE_ID_RCP             0x0101
+
+#define PCIE20_PARF_PCS_DEEMPH         0x34
+#define PCIE20_PARF_PCS_SWING          0x38
+#define PCIE20_PARF_PHY_CTRL           0x40
+#define PCIE20_PARF_PHY_REFCLK         0x4C
+#define PCIE20_PARF_CONFIG_BITS        0x50
+
+#define PCIE20_ELBI_SYS_CTRL           0x04
+
+#define PCIE20_CAP                     0x70
+#define PCIE20_CAP_LINKCTRLSTATUS      (PCIE20_CAP + 0x10)
+
+#define PCIE20_COMMAND_STATUS          0x04
+#define PCIE20_BUSNUMBERS              0x18
+#define PCIE20_MEMORY_BASE_LIMIT       0x20
+
+#define PCIE20_PLR_IATU_VIEWPORT       0x900
+#define PCIE20_PLR_IATU_CTRL1          0x904
+#define PCIE20_PLR_IATU_CTRL2          0x908
+#define PCIE20_PLR_IATU_LBAR           0x90C
+#define PCIE20_PLR_IATU_UBAR           0x910
+#define PCIE20_PLR_IATU_LAR            0x914
+#define PCIE20_PLR_IATU_LTAR           0x918
+#define PCIE20_PLR_IATU_UTAR           0x91c
+
+#define PCIE_RESET                     (MSM_CLK_CTL_BASE + 0x22dc)
+#define PCIE_SFAB_AXI_S5_FCLK_CTL      (MSM_CLK_CTL_BASE + 0x2154)
+
+#define MSM_PCIE_DEV_BAR_ADDR          PCIBIOS_MIN_MEM
+#define MSM_PCIE_DEV_CFG_ADDR          0x01000000
+
+#define RD 0
+#define WR 1
+
+/* debug mask sys interface */
+static int msm_pcie_debug_mask;
+module_param_named(debug_mask, msm_pcie_debug_mask,
+			    int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+/* resources from device file */
+enum msm_pcie_res {
+	MSM_PCIE_RES_PARF,
+	MSM_PCIE_RES_ELBI,
+	MSM_PCIE_RES_PCIE20,
+	MSM_PCIE_RES_AXI_BAR,
+	MSM_PCIE_RES_AXI_CONF,
+	MSM_PCIE_MAX_RES
+};
+
+/* msm pcie device data */
+static struct msm_pcie_dev_t msm_pcie_dev;
+
+/* regulators */
+static struct msm_pcie_vreg_info_t msm_pcie_vreg_info[MSM_PCIE_MAX_VREG] = {
+	{NULL, "vp_pcie",      1050000, 1050000, 40900},
+	{NULL, "vptx_pcie",    1050000, 1050000, 18200},
+	{NULL, "vdd_pcie_vph",       0,       0,     0},
+	{NULL, "pcie_ext_3p3v",      0,       0,     0}
+};
+
+/* clocks */
+static struct msm_pcie_clk_info_t msm_pcie_clk_info[MSM_PCIE_MAX_CLK] = {
+	{NULL, "bus_clk"},
+	{NULL, "iface_clk"},
+	{NULL, "ref_clk"}
+};
+
+/* resources */
+static struct msm_pcie_res_info_t msm_pcie_res_info[MSM_PCIE_MAX_RES] = {
+	{"parf",     0, 0, 0},
+	{"elbi",     0, 0, 0},
+	{"pcie20",   0, 0, 0},
+	{"axi_bar",  0, 0, 0},
+	{"axi_conf", 0, 0, 0},
+};
+
+int msm_pcie_get_debug_mask(void)
+{
+	return msm_pcie_debug_mask;
+}
+
+static void msm_pcie_write_mask(void __iomem *addr,
+				uint32_t clear_mask, uint32_t set_mask)
+{
+	uint32_t val;
+
+	val = (readl_relaxed(addr) & ~clear_mask) | set_mask;
+	writel_relaxed(val, addr);
+	wmb();  /* ensure data is written to hardware register */
+}
+
+static int msm_pcie_is_link_up(void)
+{
+	return readl_relaxed(msm_pcie_dev.pcie20 + PCIE20_CAP_LINKCTRLSTATUS) &
+				BIT(29);
+}
+
+static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper,
+				     int where, int size, u32 *val)
+{
+	uint32_t word_offset, byte_offset, mask;
+	uint32_t rd_val, wr_val;
+	struct msm_pcie_dev_t *dev = &msm_pcie_dev;
+	void __iomem *config_base;
+
+	/*
+	 * Only buses 0 and 1 are supported. RC port on bus 0 and EP in bus 1.
+	 * For downstream bus (1), make sure link is up
+	 */
+	if ((bus->number > 1) || (devfn != 0)) {
+		PCIE_DBG("invalid %s - bus %d devfn %d\n",
+			 (oper == RD) ? "rd" : "wr", bus->number, devfn);
+		*val = ~0;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	} else if ((bus->number != 0) && !msm_pcie_is_link_up()) {
+		PCIE_DBG("%s fail, link down - bus %d devfn %d\n",
+			 (oper == RD) ? "rd" : "wr", bus->number, devfn);
+		*val = ~0;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	word_offset = where & ~0x3;
+	byte_offset = where & 0x3;
+	mask = (~0 >> (8 * (4 - size))) << (8 * byte_offset);
+
+	config_base = (bus->number == 0) ? dev->pcie20 : dev->axi_conf;
+	rd_val = readl_relaxed(config_base + word_offset);
+
+	if (oper == RD) {
+		*val = ((rd_val & mask) >> (8 * byte_offset));
+
+		PCIE_DBG("%d:0x%02x + 0x%04x[%d] -> 0x%08x; rd 0x%08x\n",
+			 bus->number, devfn, where, size, *val, rd_val);
+	} else {
+		wr_val = (rd_val & ~mask) |
+				((*val << (8 * byte_offset)) & mask);
+		writel_relaxed(wr_val, config_base + word_offset);
+		wmb(); /* ensure config data is written to hardware register */
+
+		PCIE_DBG("%d:0x%02x + 0x%04x[%d] <- 0x%08x;"
+			 " rd 0x%08x val 0x%08x\n", bus->number,
+			 devfn, where, size, wr_val, rd_val, *val);
+	}
+
+	return 0;
+}
+
+static int msm_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
+			    int size, u32 *val)
+{
+	return msm_pcie_oper_conf(bus, devfn, RD, where, size, val);
+}
+
+static int msm_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
+			    int where, int size, u32 val)
+{
+	return msm_pcie_oper_conf(bus, devfn, WR, where, size, &val);
+}
+
+static struct pci_ops msm_pcie_ops = {
+	.read = msm_pcie_rd_conf,
+	.write = msm_pcie_wr_conf,
+};
+
+static int __devinit msm_pcie_gpio_init(void)
+{
+	int rc, i;
+	struct msm_pcie_gpio_info_t *info;
+
+	for (i = 0; i < MSM_PCIE_MAX_GPIO; i++) {
+		info = &msm_pcie_dev.gpio[i];
+
+		rc = gpio_request(info->num, info->name);
+		if (rc) {
+			pr_err("can't get gpio %s; %d\n", info->name, rc);
+			break;
+		}
+
+		rc = gpio_direction_output(info->num, 0);
+		if (rc) {
+			pr_err("can't set gpio direction %s; %d\n",
+			       info->name, rc);
+			gpio_free(info->num);
+			break;
+		}
+	}
+
+	if (rc)
+		while (i--)
+			gpio_free(msm_pcie_dev.gpio[i].num);
+
+	return rc;
+}
+
+static void msm_pcie_gpio_deinit(void)
+{
+	int i;
+
+	for (i = 0; i < MSM_PCIE_MAX_GPIO; i++)
+		gpio_free(msm_pcie_dev.gpio[i].num);
+}
+
+static int __devinit msm_pcie_vreg_init(struct device *dev)
+{
+	int i, rc = 0;
+	struct regulator *vreg;
+	struct msm_pcie_vreg_info_t *info;
+
+	for (i = 0; i < MSM_PCIE_MAX_VREG; i++) {
+		info = &msm_pcie_dev.vreg[i];
+
+		vreg = regulator_get(dev, info->name);
+		if (!vreg || IS_ERR(vreg)) {
+			rc = (PTR_ERR(vreg)) ? PTR_ERR(vreg) : -ENODEV;
+			pr_err("can't get %s; %d\n", info->name, rc);
+			break;
+		}
+
+		if (info->max_v) {
+			rc = regulator_set_voltage(vreg,
+						   info->min_v, info->max_v);
+			if (rc) {
+				pr_err("can't set voltage %s; %d\n",
+				       info->name, rc);
+				regulator_put(vreg);
+				break;
+			}
+		}
+
+		if (info->opt_mode) {
+			rc = regulator_set_optimum_mode(vreg, info->opt_mode);
+			if (rc < 0) {
+				pr_err("can't set mode %s; %d\n",
+				       info->name, rc);
+				regulator_put(vreg);
+				break;
+			}
+		}
+
+		rc = regulator_enable(vreg);
+		if (rc) {
+			pr_err("can't enable %s, %d\n", info->name, rc);
+			regulator_put(vreg);
+			break;
+		}
+		info->hdl = vreg;
+	}
+
+	if (rc)
+		while (i--) {
+			regulator_disable(msm_pcie_dev.vreg[i].hdl);
+			regulator_put(msm_pcie_dev.vreg[i].hdl);
+			msm_pcie_dev.vreg[i].hdl = NULL;
+		}
+
+	return rc;
+}
+
+static void msm_pcie_vreg_deinit(void)
+{
+	int i;
+
+	for (i = 0; i < MSM_PCIE_MAX_VREG; i++) {
+		regulator_disable(msm_pcie_dev.vreg[i].hdl);
+		regulator_put(msm_pcie_dev.vreg[i].hdl);
+		msm_pcie_dev.vreg[i].hdl = NULL;
+	}
+}
+
+static int __devinit msm_pcie_clk_init(struct device *dev)
+{
+	int i, rc = 0;
+	struct clk *clk_hdl;
+	struct msm_pcie_clk_info_t *info;
+
+	for (i = 0; i < MSM_PCIE_MAX_CLK; i++) {
+		info = &msm_pcie_dev.clk[i];
+
+		clk_hdl = clk_get(dev, info->name);
+		if (!clk_hdl || IS_ERR(clk_hdl)) {
+			rc = (PTR_ERR(clk_hdl)) ? PTR_ERR(clk_hdl) : -ENODEV;
+			pr_err("can't get clk %s; %d\n", info->name, rc);
+			break;
+		}
+		clk_prepare_enable(clk_hdl);
+		info->hdl = clk_hdl;
+	}
+
+	if (rc)
+		while (i--) {
+			clk_disable_unprepare(msm_pcie_dev.clk[i].hdl);
+			clk_put(msm_pcie_dev.clk[i].hdl);
+			msm_pcie_dev.clk[i].hdl = NULL;
+		}
+
+	return rc;
+}
+
+static void msm_pcie_clk_deinit(void)
+{
+	int i;
+
+	for (i = 0; i < MSM_PCIE_MAX_CLK; i++) {
+		clk_disable_unprepare(msm_pcie_dev.clk[i].hdl);
+		clk_put(msm_pcie_dev.clk[i].hdl);
+		msm_pcie_dev.clk[i].hdl = NULL;
+	}
+}
+
+static void __devinit msm_pcie_config_controller(void)
+{
+	struct msm_pcie_dev_t *dev = &msm_pcie_dev;
+	struct msm_pcie_res_info_t *axi_bar = &dev->res[MSM_PCIE_RES_AXI_BAR];
+	struct msm_pcie_res_info_t *axi_conf = &dev->res[MSM_PCIE_RES_AXI_CONF];
+
+	/*
+	 * program and enable address translation region 0 (device config
+	 * address space); region type config;
+	 * axi config address range to device config address range
+	 */
+	writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_VIEWPORT);
+	/* ensure that hardware locks the region before programming it */
+	wmb();
+
+	writel_relaxed(4, dev->pcie20 + PCIE20_PLR_IATU_CTRL1);
+	writel_relaxed(BIT(31), dev->pcie20 + PCIE20_PLR_IATU_CTRL2);
+	writel_relaxed(axi_conf->start, dev->pcie20 + PCIE20_PLR_IATU_LBAR);
+	writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UBAR);
+	writel_relaxed(axi_conf->end, dev->pcie20 + PCIE20_PLR_IATU_LAR);
+	writel_relaxed(MSM_PCIE_DEV_CFG_ADDR,
+		       dev->pcie20 + PCIE20_PLR_IATU_LTAR);
+	writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UTAR);
+	/* ensure that hardware registers the configuration */
+	wmb();
+
+	/*
+	 * program and enable address translation region 2 (device resource
+	 * address space); region type memory;
+	 * axi device bar address range to device bar address range
+	 */
+	writel_relaxed(2, dev->pcie20 + PCIE20_PLR_IATU_VIEWPORT);
+	/* ensure that hardware locks the region before programming it */
+	wmb();
+
+	writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_CTRL1);
+	writel_relaxed(BIT(31), dev->pcie20 + PCIE20_PLR_IATU_CTRL2);
+	writel_relaxed(axi_bar->start, dev->pcie20 + PCIE20_PLR_IATU_LBAR);
+	writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UBAR);
+	writel_relaxed(axi_bar->end, dev->pcie20 + PCIE20_PLR_IATU_LAR);
+	writel_relaxed(MSM_PCIE_DEV_BAR_ADDR,
+		       dev->pcie20 + PCIE20_PLR_IATU_LTAR);
+	writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UTAR);
+	/* ensure that hardware registers the configuration */
+	wmb();
+}
+
+static int __devinit msm_pcie_get_resources(struct platform_device *pdev)
+{
+	int i, rc = 0;
+	struct resource *res;
+	struct msm_pcie_res_info_t *info;
+	struct msm_pcie_dev_t *dev = &msm_pcie_dev;
+
+	for (i = 0; i < MSM_PCIE_MAX_RES; i++) {
+		info = &dev->res[i];
+
+		res = platform_get_resource_byname(pdev,
+						   IORESOURCE_MEM, info->name);
+		if (!res) {
+			pr_err("can't get %s resource\n", info->name);
+			rc = -ENOMEM;
+			break;
+		}
+
+		info->base = ioremap(res->start, resource_size(res));
+		if (!info->base) {
+			pr_err("can't remap %s\n", info->name);
+			rc = -ENOMEM;
+			break;
+		}
+
+		info->start = res->start;
+		info->end = res->end;
+	}
+
+	if (rc) {
+		while (i--) {
+			iounmap(dev->res[i].base);
+			dev->res[i].base = NULL;
+		}
+	} else {
+		dev->parf = dev->res[MSM_PCIE_RES_PARF].base;
+		dev->elbi = dev->res[MSM_PCIE_RES_ELBI].base;
+		dev->pcie20 = dev->res[MSM_PCIE_RES_PCIE20].base;
+		dev->axi_conf = dev->res[MSM_PCIE_RES_AXI_CONF].base;
+	}
+
+	return rc;
+}
+
+static void __devexit msm_pcie_release_resources(void)
+{
+	int i;
+
+	for (i = 0; i < MSM_PCIE_MAX_RES; i++) {
+		iounmap(msm_pcie_dev.res[i].base);
+		msm_pcie_dev.res[i].base = NULL;
+	}
+
+	msm_pcie_dev.parf = NULL;
+	msm_pcie_dev.elbi = NULL;
+	msm_pcie_dev.pcie20 = NULL;
+	msm_pcie_dev.axi_conf = NULL;
+}
+
+static int __devinit msm_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+	int rc;
+	struct msm_pcie_dev_t *dev = &msm_pcie_dev;
+	uint32_t val;
+
+	PCIE_DBG("bus %d\n", nr);
+	if (nr != 0)
+		return 0;
+
+	/* assert PCIe reset link to keep EP in reset */
+	gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_RST_N].num,
+				dev->gpio[MSM_PCIE_GPIO_RST_N].on);
+
+	/* enable power */
+	rc = msm_pcie_vreg_init(&dev->pdev->dev);
+	if (rc)
+		goto out;
+
+	/* assert PCIe PARF reset while powering the core */
+	msm_pcie_write_mask(PCIE_RESET, 0, BIT(2));
+
+	/* enable clocks */
+	rc = msm_pcie_clk_init(&dev->pdev->dev);
+	if (rc)
+		goto clk_fail;
+
+	/* enable pcie power; wait 3ms for clock to stabilize */
+	gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_PWR_EN].num,
+				dev->gpio[MSM_PCIE_GPIO_PWR_EN].on);
+	usleep(3000);
+
+	/*
+	 * de-assert PCIe PARF reset;
+	 * wait 1us before accessing PARF registers
+	 */
+	msm_pcie_write_mask(PCIE_RESET, BIT(2), 0);
+	udelay(1);
+
+	/* enable PCIe clocks and resets */
+	msm_pcie_write_mask(dev->parf + PCIE20_PARF_PHY_CTRL, BIT(0), 0);
+
+	/* PARF programming */
+	writel_relaxed(0x282828, dev->parf + PCIE20_PARF_PCS_DEEMPH);
+	writel_relaxed(0x7F7F, dev->parf + PCIE20_PARF_PCS_SWING);
+	writel_relaxed((4<<24), dev->parf + PCIE20_PARF_CONFIG_BITS);
+	/* ensure that hardware registers the PARF configuration */
+	wmb();
+
+	/* enable reference clock */
+	msm_pcie_write_mask(dev->parf + PCIE20_PARF_PHY_REFCLK, 0, BIT(16));
+
+	/* enable access to PCIe slave port on system fabric */
+	writel_relaxed(BIT(4), PCIE_SFAB_AXI_S5_FCLK_CTL);
+	/* ensure that access is enabled before proceeding */
+	wmb();
+
+	/* de-assert PICe PHY, Core, POR and AXI clk domain resets */
+	msm_pcie_write_mask(PCIE_RESET, BIT(5), 0);
+	msm_pcie_write_mask(PCIE_RESET, BIT(4), 0);
+	msm_pcie_write_mask(PCIE_RESET, BIT(3), 0);
+	msm_pcie_write_mask(PCIE_RESET, BIT(0), 0);
+
+	/* wait 150ms for clock acquisition */
+	udelay(150);
+
+	/* de-assert PCIe reset link to bring EP out of reset */
+	gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_RST_N].num,
+				!dev->gpio[MSM_PCIE_GPIO_RST_N].on);
+
+	/* enable link training */
+	msm_pcie_write_mask(dev->elbi + PCIE20_ELBI_SYS_CTRL, 0, BIT(0));
+
+	/* poll for link to come up for upto 100ms */
+	rc = readl_poll_timeout(
+			(msm_pcie_dev.pcie20 + PCIE20_CAP_LINKCTRLSTATUS),
+			val, (val & BIT(29)), 10000, 100000);
+	if (rc) {
+		pr_err("link initialization failed\n");
+		goto link_fail;
+	} else
+		pr_info("link initialized\n");
+
+	msm_pcie_config_controller();
+	rc = msm_pcie_irq_init(dev);
+	if (!rc)
+		goto out;
+
+link_fail:
+	msm_pcie_clk_deinit();
+clk_fail:
+	msm_pcie_vreg_deinit();
+out:
+	return (rc) ? 0 : 1;
+}
+
+static struct pci_bus __devinit *msm_pcie_scan_bus(int nr,
+						   struct pci_sys_data *sys)
+{
+	struct pci_bus *bus = NULL;
+
+	PCIE_DBG("bus %d\n", nr);
+	if (nr == 0)
+		bus = pci_scan_bus(sys->busnr, &msm_pcie_ops, sys);
+
+	return bus;
+}
+
+static int __devinit msm_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	PCIE_DBG("slot %d pin %d\n", slot, pin);
+	return (pin <= 4) ? (PCIE20_INTA + pin - 1) : 0;
+}
+
+static struct hw_pci msm_pci __devinitdata = {
+	.nr_controllers = 1,
+	.swizzle = pci_std_swizzle,
+	.setup = msm_pcie_setup,
+	.scan = msm_pcie_scan_bus,
+	.map_irq = msm_pcie_map_irq,
+};
+
+static int __devinit msm_pcie_probe(struct platform_device *pdev)
+{
+	const struct msm_pcie_platform *pdata;
+	int rc;
+
+	PCIE_DBG("\n");
+
+	msm_pcie_dev.pdev = pdev;
+	pdata = pdev->dev.platform_data;
+	msm_pcie_dev.gpio = pdata->gpio;
+	msm_pcie_dev.vreg = msm_pcie_vreg_info;
+	msm_pcie_dev.clk = msm_pcie_clk_info;
+	msm_pcie_dev.res = msm_pcie_res_info;
+
+	rc = msm_pcie_get_resources(msm_pcie_dev.pdev);
+	if (rc)
+		return rc;
+
+	rc = msm_pcie_gpio_init();
+	if (rc) {
+		msm_pcie_release_resources();
+		return rc;
+	}
+
+	/* kick start ARM PCI configuration framework */
+	pci_common_init(&msm_pci);
+	return 0;
+}
+
+static int __devexit msm_pcie_remove(struct platform_device *pdev)
+{
+	PCIE_DBG("\n");
+
+	msm_pcie_irq_deinit(&msm_pcie_dev);
+	msm_pcie_vreg_deinit();
+	msm_pcie_clk_deinit();
+	msm_pcie_gpio_deinit();
+	msm_pcie_release_resources();
+
+	msm_pcie_dev.pdev = NULL;
+	msm_pcie_dev.vreg = NULL;
+	msm_pcie_dev.clk = NULL;
+	msm_pcie_dev.gpio = NULL;
+	return 0;
+}
+
+static struct platform_driver msm_pcie_driver = {
+	.probe = msm_pcie_probe,
+	.remove = __devexit_p(msm_pcie_remove),
+	.driver = {
+		.name = "msm_pcie",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_pcie_init(void)
+{
+	PCIE_DBG("\n");
+	return platform_driver_register(&msm_pcie_driver);
+}
+subsys_initcall(msm_pcie_init);
+
+/* RC do not represent the right class; set it to PCI_CLASS_BRIDGE_PCI */
+static void __devinit msm_pcie_fixup_header(struct pci_dev *dev)
+{
+	PCIE_DBG("hdr_type %d\n", dev->hdr_type);
+	if (dev->hdr_type == 1)
+		dev->class = (dev->class & 0xff) | (PCI_CLASS_BRIDGE_PCI << 8);
+}
+DECLARE_PCI_FIXUP_HEADER(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
+			 msm_pcie_fixup_header);
+
+/*
+ * actual physical (BAR) address of the device resources starts from 0x10xxxxxx;
+ * the system axi address for the device resources starts from 0x08xxxxxx;
+ * correct the device resource structure here; address translation unit handles
+ * the required translations
+ */
+static void __devinit msm_pcie_fixup_final(struct pci_dev *dev)
+{
+	int i;
+
+	PCIE_DBG("vendor 0x%x 0x%x\n", dev->vendor, dev->device);
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		if (dev->resource[i].start & 0xFF000000) {
+			dev->resource[i].start &= 0x00FFFFFF;
+			dev->resource[i].start |= 0x08000000;
+			dev->resource[i].end &= 0x00FFFFFF;
+			dev->resource[i].end |= 0x08000000;
+		}
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, msm_pcie_fixup_final);
diff --git a/arch/arm/mach-msm/pcie.h b/arch/arm/mach-msm/pcie.h
new file mode 100644
index 0000000..4866ec5
--- /dev/null
+++ b/arch/arm/mach-msm/pcie.h
@@ -0,0 +1,73 @@
+/* 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.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_PCIE_H
+#define __ARCH_ARM_MACH_MSM_PCIE_H
+
+#include <linux/clk.h>
+#include <linux/compiler.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <mach/msm_pcie.h>
+
+#define MSM_PCIE_MAX_VREG 4
+#define MSM_PCIE_MAX_CLK  3
+
+#define PCIE_DBG(x...) do {              \
+	if (msm_pcie_get_debug_mask())   \
+		pr_info(x);              \
+	} while (0)
+
+/* voltage regulator info structrue */
+struct msm_pcie_vreg_info_t {
+	struct regulator  *hdl;
+	char              *name;
+	uint32_t           max_v;
+	uint32_t           min_v;
+	uint32_t           opt_mode;
+};
+
+/* clock info structure */
+struct msm_pcie_clk_info_t {
+	struct clk  *hdl;
+	char        *name;
+};
+
+/* resource info structure */
+struct msm_pcie_res_info_t {
+	char          *name;
+	uint32_t       start;
+	uint32_t       end;
+	void __iomem  *base;
+};
+
+/* msm pcie device structure */
+struct msm_pcie_dev_t {
+	struct platform_device       *pdev;
+
+	struct msm_pcie_vreg_info_t  *vreg;
+	struct msm_pcie_gpio_info_t  *gpio;
+	struct msm_pcie_clk_info_t   *clk;
+	struct msm_pcie_res_info_t   *res;
+
+	void __iomem                 *parf;
+	void __iomem                 *elbi;
+	void __iomem                 *pcie20;
+	void __iomem                 *axi_conf;
+};
+
+extern uint32_t msm_pcie_irq_init(struct msm_pcie_dev_t *dev);
+extern void msm_pcie_irq_deinit(struct msm_pcie_dev_t *dev);
+extern int msm_pcie_get_debug_mask(void);
+
+#endif
diff --git a/arch/arm/mach-msm/pcie_irq.c b/arch/arm/mach-msm/pcie_irq.c
new file mode 100644
index 0000000..df100db
--- /dev/null
+++ b/arch/arm/mach-msm/pcie_irq.c
@@ -0,0 +1,170 @@
+/* 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.
+ */
+
+/*
+ * MSM PCIe controller IRQ driver.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/msi.h>
+#include <linux/pci.h>
+#include <mach/irqs.h>
+
+#include "pcie.h"
+
+/* Any address will do here, as it won't be dereferenced */
+#define MSM_PCIE_MSI_PHY 0xa0000000
+
+#define PCIE20_MSI_CTRL_ADDR            (0x820)
+#define PCIE20_MSI_CTRL_UPPER_ADDR      (0x824)
+#define PCIE20_MSI_CTRL_INTR_EN         (0x828)
+#define PCIE20_MSI_CTRL_INTR_MASK       (0x82C)
+#define PCIE20_MSI_CTRL_INTR_STATUS     (0x830)
+
+#define PCIE20_MSI_CTRL_MAX 8
+
+static DECLARE_BITMAP(msi_irq_in_use, NR_PCIE_MSI_IRQS);
+
+irqreturn_t handle_msi_irq(int irq, void *data)
+{
+	int i, j;
+	unsigned long val;
+	struct msm_pcie_dev_t *dev = data;
+	void __iomem *ctrl_status;
+
+	/* check for set bits, clear it by setting that bit
+	   and trigger corresponding irq */
+	for (i = 0; i < PCIE20_MSI_CTRL_MAX; i++) {
+		ctrl_status = dev->pcie20 +
+				PCIE20_MSI_CTRL_INTR_STATUS + (i * 12);
+
+		val = readl_relaxed(ctrl_status);
+		while (val) {
+			j = find_first_bit(&val, 32);
+			writel_relaxed(BIT(j), ctrl_status);
+			/* ensure that interrupt is cleared (acked) */
+			wmb();
+
+			generic_handle_irq(MSM_PCIE_MSI_INT(j + (32 * i)));
+			val = readl_relaxed(ctrl_status);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+uint32_t __devinit msm_pcie_irq_init(struct msm_pcie_dev_t *dev)
+{
+	int i, rc;
+
+	PCIE_DBG("\n");
+
+	/* program MSI controller and enable all interrupts */
+	writel_relaxed(MSM_PCIE_MSI_PHY, dev->pcie20 + PCIE20_MSI_CTRL_ADDR);
+	writel_relaxed(0, dev->pcie20 + PCIE20_MSI_CTRL_UPPER_ADDR);
+
+	for (i = 0; i < PCIE20_MSI_CTRL_MAX; i++)
+		writel_relaxed(~0, dev->pcie20 +
+			       PCIE20_MSI_CTRL_INTR_EN + (i * 12));
+
+	/* ensure that hardware is configured before proceeding */
+	wmb();
+
+	/* register handler for physical MSI interrupt line */
+	rc = request_irq(PCIE20_INT_MSI, handle_msi_irq, IRQF_TRIGGER_RISING,
+			 "msm_pcie_msi", dev);
+	if (rc)
+		pr_err("Unable to allocate msi interrupt\n");
+
+	return rc;
+}
+
+void msm_pcie_irq_deinit(struct msm_pcie_dev_t *dev)
+{
+	free_irq(PCIE20_INT_MSI, dev);
+}
+
+void msm_pcie_destroy_irq(unsigned int irq)
+{
+	int pos = irq - MSM_PCIE_MSI_INT(0);
+
+	dynamic_irq_cleanup(irq);
+	clear_bit(pos, msi_irq_in_use);
+}
+
+/* hookup to linux pci msi framework */
+void arch_teardown_msi_irq(unsigned int irq)
+{
+	PCIE_DBG("irq %d deallocated\n", irq);
+	msm_pcie_destroy_irq(irq);
+}
+
+static void msm_pcie_msi_nop(struct irq_data *d)
+{
+	return;
+}
+
+static struct irq_chip pcie_msi_chip = {
+	.name = "msm-pcie-msi",
+	.irq_ack = msm_pcie_msi_nop,
+	.irq_enable = unmask_msi_irq,
+	.irq_disable = mask_msi_irq,
+	.irq_mask = mask_msi_irq,
+	.irq_unmask = unmask_msi_irq,
+};
+
+static int msm_pcie_create_irq(void)
+{
+	int irq, pos;
+
+again:
+	pos = find_first_zero_bit(msi_irq_in_use, NR_PCIE_MSI_IRQS);
+	irq = MSM_PCIE_MSI_INT(pos);
+	if (irq >= (MSM_PCIE_MSI_INT(0) + NR_PCIE_MSI_IRQS))
+		return -ENOSPC;
+
+	if (test_and_set_bit(pos, msi_irq_in_use))
+		goto again;
+
+	dynamic_irq_init(irq);
+	return irq;
+}
+
+/* hookup to linux pci msi framework */
+int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
+{
+	int irq;
+	struct msi_msg msg;
+
+	irq = msm_pcie_create_irq();
+	if (irq < 0)
+		return irq;
+
+	PCIE_DBG("irq %d allocated\n", irq);
+
+	irq_set_msi_desc(irq, desc);
+
+	/* write msi vector and data */
+	msg.address_hi = 0;
+	msg.address_lo = MSM_PCIE_MSI_PHY;
+	msg.data = irq - MSM_PCIE_MSI_INT(0);
+	write_msi_msg(irq, &msg);
+
+	irq_set_chip_and_handler(irq, &pcie_msi_chip, handle_simple_irq);
+	set_irq_flags(irq, IRQF_VALID);
+	return 0;
+}
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index fa9159e..0ecea85 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -350,13 +350,14 @@
 	}
 
 	mutex_lock(&pil->lock);
-	if (!pil->count++) {
+	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:
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
new file mode 100644
index 0000000..58d5176
--- /dev/null
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -0,0 +1,349 @@
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/err.h>
+#include <linux/io.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+#define PRONTO_PMU_COMMON_GDSCR				0x24
+#define PRONTO_PMU_COMMON_GDSCR_SW_COLLAPSE		BIT(0)
+#define CLK_DIS_WAIT					12
+#define EN_FEW_WAIT					16
+#define EN_REST_WAIT					20
+
+#define PRONTO_PMU_COMMON_CPU_CBCR			0x30
+#define PRONTO_PMU_COMMON_CPU_CBCR_CLK_EN		BIT(0)
+#define PRONTO_PMU_COMMON_CPU_CLK_OFF			BIT(31)
+
+#define PRONTO_PMU_COMMON_AHB_CBCR			0x34
+#define PRONTO_PMU_COMMON_AHB_CBCR_CLK_EN		BIT(0)
+#define PRONTO_PMU_COMMON_AHB_CLK_OFF			BIT(31)
+
+#define PRONTO_PMU_COMMON_CSR				0x1040
+#define PRONTO_PMU_COMMON_CSR_A2XB_CFG_EN		BIT(0)
+
+#define PRONTO_PMU_SOFT_RESET				0x104C
+#define PRONTO_PMU_SOFT_RESET_CRCM_CCPU_SOFT_RESET	BIT(10)
+
+#define PRONTO_PMU_CCPU_CTL				0x2000
+#define PRONTO_PMU_CCPU_CTL_REMAP_EN			BIT(2)
+#define PRONTO_PMU_CCPU_CTL_HIGH_IVT			BIT(0)
+
+#define PRONTO_PMU_CCPU_BOOT_REMAP_ADDR			0x2004
+
+#define CLK_CTL_WCNSS_RESTART_BIT			BIT(0)
+
+#define AXI_HALTREQ					0x0
+#define AXI_HALTACK					0x4
+#define AXI_IDLE					0x8
+
+#define HALT_ACK_TIMEOUT_US				500000
+#define CLK_UPDATE_TIMEOUT_US				500000
+
+struct pronto_data {
+	void __iomem *base;
+	void __iomem *reset_base;
+	void __iomem *axi_halt_base;
+	unsigned long start_addr;
+	struct pil_device *pil;
+	struct clk *cxo;
+	struct regulator *vreg;
+};
+
+static int pil_pronto_make_proxy_vote(struct pil_desc *pil)
+{
+	struct pronto_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
+
+	ret = regulator_enable(drv->vreg);
+	if (ret) {
+		dev_err(pil->dev, "failed to enable pll supply\n");
+		goto err;
+	}
+	ret = clk_prepare_enable(drv->cxo);
+	if (ret) {
+		dev_err(pil->dev, "failed to enable cxo\n");
+		goto err_clk;
+	}
+	return 0;
+err_clk:
+	regulator_disable(drv->vreg);
+err:
+	return ret;
+}
+
+static void pil_pronto_remove_proxy_vote(struct pil_desc *pil)
+{
+	struct pronto_data *drv = dev_get_drvdata(pil->dev);
+	regulator_disable(drv->vreg);
+	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;
+
+	/* Deassert reset to Pronto */
+	reg = readl_relaxed(drv->reset_base);
+	reg &= ~CLK_CTL_WCNSS_RESTART_BIT;
+	writel_relaxed(reg, drv->reset_base);
+	mb();
+
+	/* Configure boot address */
+	writel_relaxed(start_addr >> 16, base +
+			PRONTO_PMU_CCPU_BOOT_REMAP_ADDR);
+
+	/* Use the high vector table */
+	reg = readl_relaxed(base + PRONTO_PMU_CCPU_CTL);
+	reg |= PRONTO_PMU_CCPU_CTL_REMAP_EN | PRONTO_PMU_CCPU_CTL_HIGH_IVT;
+	writel_relaxed(reg, base + PRONTO_PMU_CCPU_CTL);
+
+	/* Turn on AHB clock of common_ss */
+	reg = readl_relaxed(base + PRONTO_PMU_COMMON_AHB_CBCR);
+	reg |= PRONTO_PMU_COMMON_AHB_CBCR_CLK_EN;
+	writel_relaxed(reg, base + PRONTO_PMU_COMMON_AHB_CBCR);
+
+	/* Turn on CPU clock of common_ss */
+	reg = readl_relaxed(base + PRONTO_PMU_COMMON_CPU_CBCR);
+	reg |= PRONTO_PMU_COMMON_CPU_CBCR_CLK_EN;
+	writel_relaxed(reg, base + PRONTO_PMU_COMMON_CPU_CBCR);
+
+	/* Enable A2XB bridge */
+	reg = readl_relaxed(base + PRONTO_PMU_COMMON_CSR);
+	reg |= PRONTO_PMU_COMMON_CSR_A2XB_CFG_EN;
+	writel_relaxed(reg, base + PRONTO_PMU_COMMON_CSR);
+
+	/* Enable common_ss power */
+	reg = readl_relaxed(base + PRONTO_PMU_COMMON_GDSCR);
+	reg &= ~PRONTO_PMU_COMMON_GDSCR_SW_COLLAPSE;
+	writel_relaxed(reg, base + PRONTO_PMU_COMMON_GDSCR);
+
+	/* Wait for AHB clock to be on */
+	rc = readl_tight_poll_timeout(base + PRONTO_PMU_COMMON_AHB_CBCR,
+				      reg,
+				      !(reg & PRONTO_PMU_COMMON_AHB_CLK_OFF),
+				      CLK_UPDATE_TIMEOUT_US);
+	if (rc) {
+		dev_err(pil->dev, "pronto common ahb clk enable timeout\n");
+		return rc;
+	}
+
+	/* Wait for CPU clock to be on */
+	rc = readl_tight_poll_timeout(base + PRONTO_PMU_COMMON_CPU_CBCR,
+				      reg,
+				      !(reg & PRONTO_PMU_COMMON_CPU_CLK_OFF),
+				      CLK_UPDATE_TIMEOUT_US);
+	if (rc) {
+		dev_err(pil->dev, "pronto common cpu clk enable timeout\n");
+		return rc;
+	}
+
+	/* Deassert ARM9 software reset */
+	reg = readl_relaxed(base + PRONTO_PMU_SOFT_RESET);
+	reg &= ~PRONTO_PMU_SOFT_RESET_CRCM_CCPU_SOFT_RESET;
+	writel_relaxed(reg, base + PRONTO_PMU_SOFT_RESET);
+
+	return 0;
+}
+
+static int pil_pronto_shutdown(struct pil_desc *pil)
+{
+	struct pronto_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
+	u32 reg, status;
+
+	/* Halt A2XB */
+	writel_relaxed(1, drv->axi_halt_base + AXI_HALTREQ);
+	ret = readl_poll_timeout(drv->axi_halt_base + AXI_HALTACK,
+				status, status, 50, HALT_ACK_TIMEOUT_US);
+	if (ret)
+		dev_err(pil->dev, "Port halt timeout\n");
+	else if (!readl_relaxed(drv->axi_halt_base + AXI_IDLE))
+		dev_err(pil->dev, "Port halt failed\n");
+
+	writel_relaxed(0, drv->axi_halt_base + AXI_HALTREQ);
+
+	/* Assert reset to Pronto */
+	reg = readl_relaxed(drv->reset_base);
+	reg |= CLK_CTL_WCNSS_RESTART_BIT;
+	writel_relaxed(reg, drv->reset_base);
+
+	/* Wait for reset to complete */
+	mb();
+	usleep_range(1000, 2000);
+
+	/* Deassert reset to Pronto */
+	reg = readl_relaxed(drv->reset_base);
+	reg &= ~CLK_CTL_WCNSS_RESTART_BIT;
+	writel_relaxed(reg, drv->reset_base);
+	mb();
+
+	return 0;
+}
+
+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,
+	.proxy_unvote = pil_pronto_remove_proxy_vote,
+};
+
+static int __devinit pil_pronto_probe(struct platform_device *pdev)
+{
+	struct pronto_data *drv;
+	struct resource *res;
+	struct pil_desc *desc;
+	int ret;
+	uint32_t regval;
+
+	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));
+	if (!drv->base)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res)
+		return -EINVAL;
+
+	drv->reset_base = devm_ioremap(&pdev->dev, res->start,
+					resource_size(res));
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	if (!res)
+		return -EINVAL;
+
+	drv->axi_halt_base = devm_ioremap(&pdev->dev, res->start,
+					  resource_size(res));
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	ret = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
+				      &desc->name);
+	if (ret)
+		return ret;
+
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	desc->proxy_timeout = 10000;
+
+	/* TODO: need to add secure boot when the support is available */
+	desc->ops = &pil_pronto_ops;
+	dev_info(&pdev->dev, "using non-secure boot\n");
+
+	drv->vreg = devm_regulator_get(&pdev->dev, "vdd_pronto_pll");
+	if (IS_ERR(drv->vreg)) {
+		dev_err(&pdev->dev, "failed to get pronto pll supply");
+		return PTR_ERR(drv->vreg);
+	}
+
+	ret = regulator_set_voltage(drv->vreg, 1800000, 1800000);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to set pll supply voltage\n");
+		return ret;
+	}
+
+	ret = regulator_set_optimum_mode(drv->vreg, 18000);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to set pll supply mode\n");
+		return ret;
+	}
+
+	drv->cxo = devm_clk_get(&pdev->dev, "xo");
+	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);
+
+	/* Initialize common_ss GDSCR to wait 4 cycles between states */
+	regval = readl_relaxed(drv->base + PRONTO_PMU_COMMON_GDSCR)
+		& PRONTO_PMU_COMMON_GDSCR_SW_COLLAPSE;
+	regval |= (2 << EN_REST_WAIT) | (2 << EN_FEW_WAIT)
+		  | (2 << CLK_DIS_WAIT);
+	writel_relaxed(regval, drv->base + PRONTO_PMU_COMMON_GDSCR);
+
+	return 0;
+}
+
+static int __devexit pil_pronto_remove(struct platform_device *pdev)
+{
+	struct pronto_data *drv = platform_get_drvdata(pdev);
+	msm_pil_unregister(drv->pil);
+	return 0;
+}
+
+static struct of_device_id msm_pil_pronto_match[] = {
+	{.compatible = "qcom,pil-pronto"},
+	{}
+};
+
+static struct platform_driver pil_pronto_driver = {
+	.probe = pil_pronto_probe,
+	.remove = __devexit_p(pil_pronto_remove),
+	.driver = {
+		.name = "pil_pronto",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_pil_pronto_match,
+	},
+};
+
+static int __init pil_pronto_init(void)
+{
+	return platform_driver_register(&pil_pronto_driver);
+}
+module_init(pil_pronto_init);
+
+static void __exit pil_pronto_exit(void)
+{
+	platform_driver_unregister(&pil_pronto_driver);
+}
+module_exit(pil_pronto_exit);
+
+MODULE_DESCRIPTION("Support for booting PRONTO (WCNSS) processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 60ae4d9..5eac539 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -114,7 +114,12 @@
 	struct resource *res;
 
 	desc = pil_q6v5_init(pdev);
+	if (IS_ERR(desc))
+		return PTR_ERR(desc);
+
 	drv = platform_get_drvdata(pdev);
+	if (drv == NULL)
+		return -ENODEV;
 
 	desc->ops = &pil_lpass_ops;
 	desc->owner = THIS_MODULE;
diff --git a/arch/arm/mach-msm/platsmp-8625.c b/arch/arm/mach-msm/platsmp-8625.c
index 23ca454..393f1bd 100644
--- a/arch/arm/mach-msm/platsmp-8625.c
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -60,7 +60,6 @@
 }
 
 static DEFINE_SPINLOCK(boot_lock);
-static DEFINE_RAW_SPINLOCK(irq_controller_lock);
 
 /*
  * MP_CORE_IPC will be used to generate interrupt and can be used by either
@@ -79,51 +78,14 @@
 	mb();
 }
 
-/*
- * Configure the GIC after we come out of power collapse.
- * This function will configure some of the GIC registers so as to prepare the
- * core1 to receive an SPI(ACSR_MP_CORE_IPC1, (32 + 8)), which will bring
- * core1 out of GDFS.
- */
-static void core1_gic_configure_and_raise(void)
-{
-	unsigned int value = 0;
-
-	raw_spin_lock(&irq_controller_lock);
-
-	value = __raw_readl(MSM_QGIC_DIST_BASE + GIC_DIST_ACTIVE_BIT + 0x4);
-	value |= BIT(8);
-	__raw_writel(value, MSM_QGIC_DIST_BASE + GIC_DIST_ACTIVE_BIT + 0x4);
-	mb();
-
-	value = __raw_readl(MSM_QGIC_DIST_BASE + GIC_DIST_TARGET + 0x24);
-	value |= BIT(13);
-	__raw_writel(value, MSM_QGIC_DIST_BASE + GIC_DIST_TARGET + 0x24);
-	mb();
-
-	value = __raw_readl(MSM_QGIC_DIST_BASE + GIC_DIST_TARGET + 0x28);
-	value |= BIT(1);
-	__raw_writel(value, MSM_QGIC_DIST_BASE + GIC_DIST_TARGET + 0x28);
-	mb();
-
-	value =  __raw_readl(MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET + 0x4);
-	value |= BIT(8);
-	__raw_writel(value, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET + 0x4);
-	mb();
-
-	value =  __raw_readl(MSM_QGIC_DIST_BASE + GIC_DIST_PENDING_SET + 0x4);
-	value |= BIT(8);
-	__raw_writel(value, MSM_QGIC_DIST_BASE + GIC_DIST_PENDING_SET + 0x4);
-	mb();
-
-	raise_clear_spi(1, true);
-	raw_spin_unlock(&irq_controller_lock);
-}
-
 static void clear_pending_spi(unsigned int irq)
 {
-	/* Clear the IRQ from the ENABLE_SET */
+	struct irq_data *d = irq_get_irq_data(irq);
+	struct irq_chip *c = irq_data_get_irq_chip(d);
+
+	c->irq_mask(d);
 	local_irq_disable();
+	/* Clear the IRQ from the ENABLE_SET */
 	gic_clear_spi_pending(irq);
 	local_irq_enable();
 }
@@ -234,10 +196,12 @@
 	 * needs to be brought out by raising an SPI.
 	 */
 
-	if (power_collapsed)
+	if (power_collapsed) {
 		core1_gic_configure_and_raise();
-	else
+		raise_clear_spi(1, true);
+	} else {
 		gic_raise_softirq(cpumask_of(cpu), 1);
+	}
 
 	timeout = jiffies + (1 * HZ);
 	while (time_before(jiffies, timeout)) {
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 668e0c2..b66729b 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -75,8 +75,10 @@
 	if (machine_is_apq8064_sim())
 		writel_relaxed(0xf0000, base_ptr+0x04);
 
-	if (machine_is_copper_sim())
-		writel_relaxed(0x9, base_ptr+0x04);
+	if (machine_is_copper_sim()) {
+		writel_relaxed(0x800, base_ptr+0x04);
+		writel_relaxed(0x3FFF, base_ptr+0x14);
+	}
 
 	mb();
 	iounmap(base_ptr);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index a22b175..cc17ceb 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -29,6 +29,7 @@
 #include <linux/wakelock.h>
 #include <linux/delay.h>
 #include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
 #include <mach/system.h>
 #include <asm/cacheflush.h>
 #include <asm/hardware/gic.h>
@@ -612,6 +613,7 @@
  *****************************************************************************/
 
 static struct msm_rpmrs_limits *msm_pm_idle_rs_limits;
+static bool msm_pm_use_qtimer;
 
 static void msm_pm_swfi(void)
 {
@@ -637,9 +639,9 @@
 {
 	bool collapsed = 0;
 
-	l2x0_suspend();
+	l2cc_suspend();
 	collapsed = msm_pm_collapse();
-	l2x0_resume(collapsed);
+	l2cc_resume();
 
 	return collapsed;
 }
@@ -748,12 +750,28 @@
 
 	collapsed = msm_pm_spm_power_collapse(cpu, from_idle, true);
 
-	if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
-		pr_info("CPU%u: %s: restore clock rate to %lu\n",
-			cpu, __func__, saved_acpuclk_rate);
-	if (acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC) < 0)
-		pr_err("CPU%u: %s: failed to restore clock rate(%lu)\n",
-			cpu, __func__, saved_acpuclk_rate);
+	if (cpu_online(cpu)) {
+		if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
+			pr_info("CPU%u: %s: restore clock rate to %lu\n",
+				cpu, __func__, saved_acpuclk_rate);
+		if (acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC) < 0)
+			pr_err("CPU%u: %s: failed to restore clock rate(%lu)\n",
+				cpu, __func__, saved_acpuclk_rate);
+	} else {
+		unsigned int gic_dist_enabled;
+		unsigned int gic_dist_pending;
+		gic_dist_enabled = readl_relaxed(
+				MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR);
+		gic_dist_pending = readl_relaxed(
+				MSM_QGIC_DIST_BASE + GIC_DIST_PENDING_SET);
+		mb();
+		gic_dist_pending &= gic_dist_enabled;
+
+		if (gic_dist_pending)
+			pr_err("CPU %d interrupted during hotplug.Pending int 0x%x\n",
+					cpu, gic_dist_pending);
+	}
+
 
 	avs_reset_delays(avsdscr_setting);
 	msm_pm_config_hw_after_power_up();
@@ -765,6 +783,28 @@
 	return collapsed;
 }
 
+static void msm_pm_qtimer_available(void)
+{
+	if (machine_is_copper())
+		msm_pm_use_qtimer = true;
+}
+
+static int64_t msm_pm_timer_enter_idle(void)
+{
+	if (msm_pm_use_qtimer)
+		return ktime_to_ns(tick_nohz_get_sleep_length());
+
+	return msm_timer_enter_idle();
+}
+
+static void msm_pm_timer_exit_idle(bool timer_halted)
+{
+	if (msm_pm_use_qtimer)
+		return;
+
+	msm_timer_exit_idle((int) timer_halted);
+}
+
 /******************************************************************************
  * External Idle/Suspend Functions
  *****************************************************************************/
@@ -919,7 +959,7 @@
 		break;
 
 	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE: {
-		int64_t timer_expiration = msm_timer_enter_idle();
+		int64_t timer_expiration = 0;
 		bool timer_halted = false;
 		uint32_t sleep_delay;
 		int ret;
@@ -927,6 +967,8 @@
 			(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(
 			timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
 		if (sleep_delay == 0) /* 0 would mean infinite time */
@@ -944,8 +986,8 @@
 			msm_rpmrs_exit_sleep(msm_pm_idle_rs_limits, true,
 					notify_rpm, collapsed);
 		}
+		msm_pm_timer_exit_idle(timer_halted);
 
-		msm_timer_exit_idle((int) timer_halted);
 #ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
 #endif
@@ -1132,7 +1174,6 @@
 			} else
 				time = 0;
 		}
-
 		msm_pm_add_stat(MSM_PM_STAT_SUSPEND, time);
 #endif /* CONFIG_MSM_IDLE_STATS */
 	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
@@ -1176,11 +1217,10 @@
 	pgd_t *pc_pgd;
 	pmd_t *pmd;
 	unsigned long pmdval;
-	unsigned int cpu;
 #ifdef CONFIG_MSM_IDLE_STATS
+	unsigned int cpu;
 	struct proc_dir_entry *d_entry;
 #endif
-
 	/* Page table for cores to come back up safely. */
 	pc_pgd = pgd_alloc(&init_mm);
 	if (!pc_pgd)
@@ -1258,10 +1298,12 @@
 	}
 #endif  /* CONFIG_MSM_IDLE_STATS */
 
+
 	msm_pm_mode_sysfs_add();
 	msm_spm_allow_x_cpu_set_vdd(false);
 
 	suspend_set_ops(&msm_pm_ops);
+	msm_pm_qtimer_available();
 	msm_cpuidle_init();
 
 	return 0;
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index b5f0fdc..f6105af1 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -15,6 +15,10 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <mach/msm_iomap.h>
 #include <mach/socinfo.h>
 #include <asm/mach-types.h>
@@ -200,3 +204,69 @@
 
 	return ret;
 }
+
+static int __devinit msm_pm_boot_probe(struct platform_device *pdev)
+{
+	struct msm_pm_boot_platform_data pdata;
+	char *key = NULL;
+	uint32_t val = 0;
+	int ret = 0;
+	int flag = 0;
+
+	key = "qcom,mode";
+	ret = of_property_read_u32(pdev->dev.of_node, key, &val);
+	if (ret) {
+		pr_err("Unable to read boot mode Err(%d).\n", ret);
+		return -ENODEV;
+	}
+	pdata.mode = val;
+
+	key = "qcom,phy-addr";
+	ret = of_property_read_u32(pdev->dev.of_node, key, &val);
+	if (ret && pdata.mode == MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS)
+		goto fail;
+	if (!ret) {
+		pdata.p_addr = val;
+		flag++;
+	}
+
+	key = "qcom,virt-addr";
+	ret = of_property_read_u32(pdev->dev.of_node, key, &val);
+	if (ret && pdata.mode == MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT)
+		goto fail;
+	if (!ret) {
+		pdata.v_addr = (void *)val;
+		flag++;
+	}
+
+	if (pdata.mode == MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR && (flag != 2)) {
+		key = "addresses for boot remap";
+		goto fail;
+	}
+
+	return msm_pm_boot_init(&pdata);
+
+fail:
+	pr_err("Error reading %s\n", key);
+	return -EFAULT;
+}
+
+static struct of_device_id msm_pm_match_table[] = {
+	{.compatible = "qcom,pm-boot"},
+	{},
+};
+
+static struct platform_driver msm_pm_boot_driver = {
+	.probe = msm_pm_boot_probe,
+	.driver = {
+		.name = "pm-boot",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_pm_match_table,
+	},
+};
+
+static int __init msm_pm_boot_module_init(void)
+{
+	return platform_driver_register(&msm_pm_boot_driver);
+}
+module_init(msm_pm_boot_module_init);
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 39e321a..f4bfe23 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -465,7 +465,8 @@
 		__raw_writel(1, APPS_PWRDOWN);
 		mb();
 	} else if (cpu_is_msm7x27a() || cpu_is_msm7x27aa() ||
-		   cpu_is_msm7x25a() || cpu_is_msm7x25aa()) {
+		   cpu_is_msm7x25a() || cpu_is_msm7x25aa() ||
+		   cpu_is_msm7x25ab()) {
 		__raw_writel(0x7, APPS_CLK_SLEEP_EN);
 		mb();
 		__raw_writel(1, APPS_PWRDOWN);
@@ -591,7 +592,8 @@
 		__raw_writel(0x0f, APPS_CLK_SLEEP_EN);
 		mb();
 	} else if (cpu_is_msm7x27a() || cpu_is_msm7x27aa() ||
-		   cpu_is_msm7x25a() || cpu_is_msm7x25aa()) {
+		   cpu_is_msm7x25a() || cpu_is_msm7x25aa() ||
+		   cpu_is_msm7x25ab()) {
 		__raw_writel(0x7, APPS_CLK_SLEEP_EN);
 		mb();
 	}
@@ -1192,7 +1194,7 @@
 #endif
 
 #ifdef CONFIG_CACHE_L2X0
-	l2x0_suspend();
+	l2cc_suspend();
 #endif
 
 	collapsed = msm_pm_collapse();
@@ -1203,21 +1205,23 @@
 	 */
 	if (cpu_is_msm8625()) {
 		/*
-		 * on system reset default value of MPA5_GDFS_CNT_VAL
-		 * is = 0xFF, later power driver reprogrammed this
-		 * as: 0x000300FF. Currently based on the value of
-		 * MPA5_GDFS_CNT_VAL register decide whether it is
-		 * a modem early exit are not.
+		 * 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.
 		 */
 		val = __raw_readl(MSM_CFG_CTL_BASE + 0x38);
-		if (val != 0xFF)
-			modem_early_exit = 1;
-		else
+		if (val != 0x00030002)
 			power_collapsed = 1;
+		else
+			modem_early_exit = 1;
 	}
 
 #ifdef CONFIG_CACHE_L2X0
-	l2x0_resume(collapsed);
+	l2cc_resume();
 #endif
 
 	msm_pm_boot_config_after_pc(smp_processor_id());
@@ -1434,14 +1438,14 @@
 
 #ifdef CONFIG_CACHE_L2X0
 	if (!cpu_is_msm8625())
-		l2x0_suspend();
+		l2cc_suspend();
 #endif
 
 	collapsed = msm_pm_collapse();
 
 #ifdef CONFIG_CACHE_L2X0
 	if (!cpu_is_msm8625())
-		l2x0_resume(collapsed);
+		l2cc_resume();
 #endif
 
 	msm_pm_boot_config_after_pc(smp_processor_id());
@@ -1950,11 +1954,14 @@
 		clean_caches((unsigned long)&target_type, sizeof(target_type),
 				virt_to_phys(&target_type));
 
-		/* Override the DBGNOPOWERDN for each cpu in
-		 * MPA5_GDFS_CNT_VAL register
+		/*
+		 * Configure the MPA5_GDFS_CNT_VAL register for
+		 * DBGPWRUPEREQ_OVERRIDE[17:16] = Override the
+		 * DBGNOPOWERDN for each cpu.
+		 * MPA5_GDFS_CNT_VAL[9:0] = Delay counter for
+		 * GDFS control.
 		 */
-		val = __raw_readl((MSM_CFG_CTL_BASE + 0x38));
-		val = val | 0x00030000;
+		val = 0x00030002;
 		__raw_writel(val, (MSM_CFG_CTL_BASE + 0x38));
 	}
 
diff --git a/arch/arm/mach-msm/qdsp5/adsp.c b/arch/arm/mach-msm/qdsp5/adsp.c
index 71e0409..6f5ccbf 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.c
+++ b/arch/arm/mach-msm/qdsp5/adsp.c
@@ -34,6 +34,7 @@
 #include <linux/wait.h>
 #include <linux/wakelock.h>
 #include <linux/slab.h>
+#include <linux/workqueue.h>
 #include <mach/debug_mm.h>
 #include <linux/debugfs.h>
 
@@ -71,6 +72,10 @@
 static uint32_t rpc_adsp_rtos_mtoa_vers_comp;
 static DEFINE_MUTEX(adsp_open_lock);
 
+static struct workqueue_struct *msm_adsp_probe_work_queue;
+static void adsp_probe_work(struct work_struct *work);
+static DECLARE_WORK(msm_adsp_probe_work, adsp_probe_work);
+
 /* protect interactions with the ADSP command/message queue */
 static spinlock_t adsp_cmd_lock;
 static spinlock_t adsp_write_lock;
@@ -1230,8 +1235,8 @@
 		goto fail_rpc_register;
 	}
 
-	/* start the kernel thread to process the callbacks */
-	kthread_run(adsp_rpc_thread, NULL, "kadspd");
+	/* schedule start of kernel thread later using work queue */
+	queue_work(msm_adsp_probe_work_queue, &msm_adsp_probe_work);
 
 	for (i = 0; i < count; i++) {
 		struct msm_adsp_module *mod = adsp_modules + i;
@@ -1271,6 +1276,13 @@
 	kfree(adsp_info.init_info_ptr);
 	return rc;
 }
+
+static void adsp_probe_work(struct work_struct *work)
+{
+	/* start the kernel thread to process the callbacks */
+	kthread_run(adsp_rpc_thread, NULL, "kadspd");
+}
+
 #ifdef CONFIG_DEBUG_FS
 static int get_parameters(char *buf, long int *param1, int num_of_par)
 {
@@ -1433,6 +1445,9 @@
 	rpc_adsp_rtos_mtoa_vers_comp = 0x00030001;
 #endif
 
+	msm_adsp_probe_work_queue = create_workqueue("msm_adsp_probe");
+	if (msm_adsp_probe_work_queue == NULL)
+		return -ENOMEM;
 	msm_adsp_driver.driver.name = msm_adsp_driver_name;
 	rc = platform_driver_register(&msm_adsp_driver);
 	MM_INFO("%s -- %d\n", msm_adsp_driver_name, rc);
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac.c b/arch/arm/mach-msm/qdsp5/audio_aac.c
index de756eb..8cae321 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac.c
@@ -39,7 +39,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5/qdsp5audppcmdi.h>
 #include <mach/qdsp5/qdsp5audppmsg.h>
 #include <mach/qdsp5/qdsp5audplaycmdi.h>
@@ -126,8 +125,8 @@
 	/* ---- End of Host PCM section */
 
 	struct msm_adsp_module *audplay;
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 
 	/* configuration to use on next enable */
 	uint32_t out_sample_rate;
@@ -1509,9 +1508,9 @@
 	audio->event_abort = 1;
 	wake_up(&audio->event_wait);
 	audaac_reset_event_queue(audio);
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
-	msm_subsystem_unmap_buffer(audio->map_v_read);
+	iounmap(audio->map_v_read);
 	free_contiguous_memory_by_paddr(audio->read_phys);
 	mutex_unlock(&audio->lock);
 #ifdef CONFIG_DEBUG_FS
@@ -1701,10 +1700,7 @@
 		MM_DBG("pmemsz = %d\n", pmem_sz);
 		audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
 		if (audio->phys) {
-			audio->map_v_write = msm_subsystem_map_buffer(
-							audio->phys, pmem_sz,
-							MSM_SUBSYSTEM_MAP_KADDR,
-							NULL, 0);
+			audio->map_v_write = ioremap(audio->phys, pmem_sz);
 			if (IS_ERR(audio->map_v_write)) {
 				MM_ERR("could not map write buffers, \
 						freeing instance 0x%08x\n",
@@ -1715,7 +1711,7 @@
 				kfree(audio);
 				goto done;
 			}
-			audio->data = audio->map_v_write->vaddr;
+			audio->data = audio->map_v_write;
 			MM_DBG("write buf: phy addr 0x%08x kernel addr \
 				0x%08x\n", audio->phys, (int)audio->data);
 			break;
@@ -1737,29 +1733,26 @@
 		MM_ERR("could not allocate read buffers, freeing instance \
 				0x%08x\n", (int)audio);
 		rc = -ENOMEM;
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->phys);
 		audpp_adec_free(audio->dec_id);
 		kfree(audio);
 		goto done;
 	}
-	audio->map_v_read = msm_subsystem_map_buffer(
-					audio->read_phys,
-					PCM_BUFSZ_MIN * PCM_BUF_MAX_COUNT,
-					MSM_SUBSYSTEM_MAP_KADDR,
-					NULL, 0);
+	audio->map_v_read = ioremap(audio->read_phys,
+					PCM_BUFSZ_MIN * PCM_BUF_MAX_COUNT);
 	if (IS_ERR(audio->map_v_read)) {
 		MM_ERR("could not map read buffers, freeing instance \
 				0x%08x\n", (int)audio);
 		rc = -ENOMEM;
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->phys);
 		free_contiguous_memory_by_paddr(audio->read_phys);
 		audpp_adec_free(audio->dec_id);
 		kfree(audio);
 		goto done;
 	}
-	audio->read_data = audio->map_v_read->vaddr;
+	audio->read_data = audio->map_v_read;
 	MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
 				audio->read_phys, (int)audio->read_data);
 
@@ -1880,9 +1873,9 @@
 done:
 	return rc;
 err:
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
-	msm_subsystem_unmap_buffer(audio->map_v_read);
+	iounmap(audio->map_v_read);
 	free_contiguous_memory_by_paddr(audio->read_phys);
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac_in.c b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
index 456a8ff..ab9f15c 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
@@ -40,7 +40,6 @@
 #include <mach/msm_rpcrouter.h>
 #include <mach/msm_memtypes.h>
 #include <mach/iommu.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/iommu_domains.h>
 
 #include <mach/msm_adsp.h>
@@ -141,8 +140,8 @@
 	/* data allocated for various buffers */
 	char *data;
 	dma_addr_t phys;
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 
 	int opened;
 	int enabled;
@@ -1249,13 +1248,13 @@
 
 	if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
 	   (audio->out_data)) {
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->out_phys);
 		audio->out_data = NULL;
 	}
 
 	if (audio->data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->phys);
 		audio->data = NULL;
 	}
@@ -1355,16 +1354,15 @@
 
 	audio->phys = allocate_contiguous_ebi_nomap(dma_size, SZ_4K);
 	if (audio->phys) {
-		audio->map_v_read = msm_subsystem_map_buffer(
-					audio->phys, dma_size,
-					MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+		audio->map_v_read = ioremap(
+					audio->phys, dma_size);
 		if (IS_ERR(audio->map_v_read)) {
 			MM_ERR("could not map DMA buffers\n");
 			rc = -ENOMEM;
 			free_contiguous_memory_by_paddr(audio->phys);
 			goto evt_error;
 		}
-		audio->data = audio->map_v_read->vaddr;
+		audio->data = audio->map_v_read;
 	} else {
 		MM_ERR("could not allocate read buffers\n");
 		rc = -ENOMEM;
@@ -1380,23 +1378,22 @@
 		if (!audio->out_phys) {
 			MM_ERR("could not allocate write buffers\n");
 			rc = -ENOMEM;
-			msm_subsystem_unmap_buffer(audio->map_v_read);
+			iounmap(audio->map_v_read);
 			free_contiguous_memory_by_paddr(audio->phys);
 			goto evt_error;
 		} else {
-			audio->map_v_write = msm_subsystem_map_buffer(
-					audio->out_phys, BUFFER_SIZE,
-					MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+			audio->map_v_write = ioremap(
+					audio->out_phys, BUFFER_SIZE);
 			if (IS_ERR(audio->map_v_write)) {
 				MM_ERR("could not map write phys address\n");
 				rc = -ENOMEM;
-				msm_subsystem_unmap_buffer(audio->map_v_read);
+				iounmap(audio->map_v_read);
 				free_contiguous_memory_by_paddr(audio->phys);
 				free_contiguous_memory_by_paddr(\
 						audio->out_phys);
 				goto evt_error;
 			}
-			audio->out_data = audio->map_v_write->vaddr;
+			audio->out_data = audio->map_v_write;
 			MM_DBG("wr buf: phy addr 0x%08x kernel addr 0x%08x\n",
 					audio->out_phys, (int)audio->out_data);
 		}
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb.c b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
index d66a270..1ad941f 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
@@ -47,7 +47,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5/qdsp5audppcmdi.h>
 #include <mach/qdsp5/qdsp5audppmsg.h>
 #include <mach/qdsp5/qdsp5audplaycmdi.h>
@@ -138,8 +137,8 @@
 	/* data allocated for various buffers */
 	char *data;
 	int32_t phys; /* physical address of write buffer */
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 
 
 	int mfield; /* meta field embedded in data */
@@ -979,12 +978,10 @@
 					rc = -ENOMEM;
 					break;
 			}
-			audio->map_v_read = msm_subsystem_map_buffer(
+			audio->map_v_read = ioremap(
 						audio->read_phys,
 						config.buffer_size *
-						config.buffer_count,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+						config.buffer_count);
 			if (IS_ERR(audio->map_v_read)) {
 				MM_ERR("failed to map read buf\n");
 				rc = -ENOMEM;
@@ -994,7 +991,7 @@
 				uint8_t index;
 				uint32_t offset = 0;
 				audio->read_data =
-						audio->map_v_read->vaddr;
+						audio->map_v_read;
 				audio->buf_refresh = 0;
 				audio->pcm_buf_count =
 					config.buffer_count;
@@ -1298,10 +1295,10 @@
 	audio->event_abort = 1;
 	wake_up(&audio->event_wait);
 	audamrnb_reset_event_queue(audio);
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	if (audio->read_data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->read_phys);
 	}
 	mutex_unlock(&audio->lock);
@@ -1494,10 +1491,8 @@
 		kfree(audio);
 		goto done;
 	} else {
-		audio->map_v_write = msm_subsystem_map_buffer(
-					audio->phys, DMASZ,
-					MSM_SUBSYSTEM_MAP_KADDR,
-					NULL, 0);
+		audio->map_v_write = ioremap(
+					audio->phys, DMASZ);
 		if (IS_ERR(audio->map_v_write)) {
 			MM_ERR("could not map write buffers, freeing \
 					instance 0x%08x freeing\n", (int)audio);
@@ -1507,7 +1502,7 @@
 			kfree(audio);
 			goto done;
 		}
-		audio->data = audio->map_v_write->vaddr;
+		audio->data = audio->map_v_write;
 		MM_DBG("write buf: phy addr 0x%08x kernel addr \
 				0x%08x\n", audio->phys, (int)audio->data);
 	}
@@ -1595,7 +1590,7 @@
 done:
 	return rc;
 err:
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
index 2b4ead9..bec1d4c 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
@@ -2,7 +2,7 @@
  *
  * amrnb encoder device
  *
- * Copyright (c) 2009, 2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009, 2011-2012 Code Aurora Forum. All rights reserved.
  *
  * This code is based in part on arch/arm/mach-msm/qdsp5/audio_in.c, which is
  * Copyright (C) 2008 Google, Inc.
@@ -44,7 +44,6 @@
 #include <mach/msm_rpcrouter.h>
 #include <mach/msm_memtypes.h>
 #include <mach/iommu.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/iommu_domains.h>
 
 #include <mach/msm_adsp.h>
@@ -146,7 +145,7 @@
 	/* data allocated for various buffers */
 	char *data;
 	dma_addr_t phys;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_write;
 
 	uint8_t opened;
 	uint8_t enabled;
@@ -822,13 +821,15 @@
 		}
 		/* Allow only single frame */
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
-			if (cfg.buffer_size != (FRAME_SIZE - 8))
+			if (cfg.buffer_size != (FRAME_SIZE - 8)) {
 				rc = -EINVAL;
 				break;
+			}
 		} else {
-			if (cfg.buffer_size != (AMRNB_FRAME_SIZE + 14))
+			if (cfg.buffer_size != (AMRNB_FRAME_SIZE + 14)) {
 				rc = -EINVAL;
 				break;
+			}
 		}
 		audio->buffer_size = cfg.buffer_size;
 		break;
@@ -1206,7 +1207,7 @@
 	audio->opened = 0;
 	if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
 	   (audio->out_data)) {
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->out_phys);
 		audio->out_data = NULL;
 	}
@@ -1330,9 +1331,8 @@
 				dma_size, audio->data, audio->phys);
 			goto evt_error;
 		} else {
-			audio->map_v_write = msm_subsystem_map_buffer(
-					audio->out_phys, BUFFER_SIZE,
-					MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+			audio->map_v_write = ioremap(
+					audio->out_phys, BUFFER_SIZE);
 			if (IS_ERR(audio->map_v_write)) {
 				MM_ERR("could not map write phys address\n");
 				rc = -ENOMEM;
@@ -1342,7 +1342,7 @@
 						audio->out_phys);
 				goto evt_error;
 			}
-			audio->out_data = audio->map_v_write->vaddr;
+			audio->out_data = audio->map_v_write;
 			MM_DBG("wr buf: phy addr 0x%08x kernel addr 0x%08x\n",
 					audio->out_phys,
 					(uint32_t)audio->out_data);
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrwb.c b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
index b566c60..0d3b67a 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
@@ -46,7 +46,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5/qdsp5audppcmdi.h>
 #include <mach/qdsp5/qdsp5audppmsg.h>
 #include <mach/qdsp5/qdsp5audplaycmdi.h>
@@ -139,8 +138,8 @@
 	/* data allocated for various buffers */
 	char *data;
 	int32_t phys; /* physical address of write buffer */
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 	int mfield; /* meta field embedded in data */
 	int rflush; /* Read  flush */
 	int wflush; /* Write flush */
@@ -975,12 +974,10 @@
 					rc = -ENOMEM;
 					break;
 			}
-			audio->map_v_read = msm_subsystem_map_buffer(
+			audio->map_v_read = ioremap(
 						audio->read_phys,
 						config.buffer_size *
-						config.buffer_count,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+						config.buffer_count);
 			if (IS_ERR(audio->map_v_read)) {
 				MM_ERR("failed to map mem for read buf\n");
 				rc = -ENOMEM;
@@ -989,7 +986,7 @@
 			} else {
 				uint8_t index;
 				uint32_t offset = 0;
-				audio->read_data = audio->map_v_read->vaddr;
+				audio->read_data = audio->map_v_read;
 				audio->pcm_feedback = 1;
 				audio->buf_refresh = 0;
 				audio->pcm_buf_count =
@@ -1366,10 +1363,10 @@
 	audio->event_abort = 1;
 	wake_up(&audio->event_wait);
 	audamrwb_reset_event_queue(audio);
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	if (audio->read_data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->read_phys);
 	}
 	mutex_unlock(&audio->lock);
@@ -1557,10 +1554,7 @@
 		kfree(audio);
 		goto done;
 	} else {
-		audio->map_v_write = msm_subsystem_map_buffer(
-						audio->phys, DMASZ,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+		audio->map_v_write = ioremap(audio->phys, DMASZ);
 
 		if (IS_ERR(audio->map_v_write)) {
 			MM_ERR("could not map write buffers, freeing \
@@ -1571,7 +1565,7 @@
 			kfree(audio);
 			goto done;
 		}
-		audio->data = audio->map_v_write->vaddr;
+		audio->data = audio->map_v_write;
 		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
 				audio->phys, (int)audio->data);
 	}
@@ -1664,7 +1658,7 @@
 done:
 	return rc;
 err:
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc.c b/arch/arm/mach-msm/qdsp5/audio_evrc.c
index 86035db..7479e36 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc.c
@@ -41,7 +41,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5/qdsp5audppcmdi.h>
 #include <mach/qdsp5/qdsp5audppmsg.h>
 #include <mach/qdsp5/qdsp5audplaycmdi.h>
@@ -135,8 +134,8 @@
 	/* data allocated for various buffers */
 	char *data;
 	int32_t phys;  /* physical address of write buffer */
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 
 	int mfield; /* meta field embedded in data */
 	int rflush; /* Read  flush */
@@ -965,12 +964,10 @@
 					rc = -ENOMEM;
 					break;
 				}
-				audio->map_v_read = msm_subsystem_map_buffer(
+				audio->map_v_read = ioremap(
 							audio->read_phys,
 							config.buffer_size *
-							config.buffer_count,
-							MSM_SUBSYSTEM_MAP_KADDR,
-							NULL, 0);
+							config.buffer_count);
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("failed to map mem"
 							" for read buf\n");
@@ -981,7 +978,7 @@
 					uint8_t index;
 					uint32_t offset = 0;
 					audio->read_data =
-						audio->map_v_read->vaddr;
+						audio->map_v_read;
 					audio->buf_refresh = 0;
 					audio->pcm_buf_count =
 					    config.buffer_count;
@@ -1290,10 +1287,10 @@
 	audio->event_abort = 1;
 	wake_up(&audio->event_wait);
 	audevrc_reset_event_queue(audio);
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	if (audio->read_data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->read_phys);
 	}
 	mutex_unlock(&audio->lock);
@@ -1485,10 +1482,7 @@
 		kfree(audio);
 		goto done;
 	} else {
-		audio->map_v_write = msm_subsystem_map_buffer(
-						audio->phys, DMASZ,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+		audio->map_v_write = ioremap(audio->phys, DMASZ);
 		if (IS_ERR(audio->map_v_write)) {
 			MM_ERR("could not map write buffers, freeing \
 					instance 0x%08x\n", (int)audio);
@@ -1498,7 +1492,7 @@
 			kfree(audio);
 			goto done;
 		}
-		audio->data = audio->map_v_write->vaddr;
+		audio->data = audio->map_v_write;
 		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
 				audio->phys, (int)audio->data);
 	}
@@ -1588,7 +1582,7 @@
 done:
 	return rc;
 err:
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
index 0bdbf5d..05a16da 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
@@ -41,7 +41,6 @@
 #include <mach/msm_rpcrouter.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 
 #include "audmgr.h"
 
@@ -144,8 +143,8 @@
 	char *data;
 	dma_addr_t phys;
 
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 
 	int opened;
 	int enabled;
@@ -800,13 +799,15 @@
 		}
 		/* Allow only single frame */
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
-			if (cfg.buffer_size != (FRAME_SIZE - 8))
+			if (cfg.buffer_size != (FRAME_SIZE - 8)) {
 				rc = -EINVAL;
 				break;
+			}
 		} else {
-			if (cfg.buffer_size != (EVRC_FRAME_SIZE + 14))
+			if (cfg.buffer_size != (EVRC_FRAME_SIZE + 14)) {
 				rc = -EINVAL;
 				break;
+			}
 		}
 		audio->buffer_size = cfg.buffer_size;
 		break;
@@ -1189,12 +1190,12 @@
 	audio->opened = 0;
 	if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
 	   (audio->out_data)) {
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->out_phys);
 		audio->out_data = NULL;
 	}
 	if (audio->data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->phys);
 		audio->data = NULL;
 	}
@@ -1295,17 +1296,14 @@
 		rc = -ENOMEM;
 		goto evt_error;
 	} else {
-		audio->map_v_read = msm_subsystem_map_buffer(
-						audio->phys, dma_size,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+		audio->map_v_read = ioremap(audio->phys, dma_size);
 		if (IS_ERR(audio->map_v_read)) {
 			MM_ERR("could not map physical address\n");
 			rc = -ENOMEM;
 			free_contiguous_memory_by_paddr(audio->phys);
 			goto evt_error;
 		}
-		audio->data = audio->map_v_read->vaddr;
+		audio->data = audio->map_v_read;
 		MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
 				audio->phys, (int)audio->data);
 	}
@@ -1316,25 +1314,23 @@
 		if (!audio->out_phys) {
 			MM_ERR("could not allocate physical write buffers\n");
 			rc = -ENOMEM;
-			msm_subsystem_unmap_buffer(audio->map_v_read);
+			iounmap(audio->map_v_read);
 			free_contiguous_memory_by_paddr(audio->phys);
 			goto evt_error;
 		} else {
-			audio->map_v_write = msm_subsystem_map_buffer(
-						audio->out_phys, BUFFER_SIZE,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+			audio->map_v_write = ioremap(
+						audio->out_phys, BUFFER_SIZE);
 
 			if (IS_ERR(audio->map_v_write)) {
 				MM_ERR("could not map write phys address\n");
 				rc = -ENOMEM;
-				msm_subsystem_unmap_buffer(audio->map_v_read);
+				iounmap(audio->map_v_read);
 				free_contiguous_memory_by_paddr(audio->phys);
 				free_contiguous_memory_by_paddr(\
 							audio->out_phys);
 				goto evt_error;
 			}
-			audio->out_data = audio->map_v_write->vaddr;
+			audio->out_data = audio->map_v_write;
 			MM_DBG("wr buf: phy addr 0x%08x kernel addr 0x%08x\n",
 					audio->out_phys, (int)audio->out_data);
 		}
diff --git a/arch/arm/mach-msm/qdsp5/audio_lpa.c b/arch/arm/mach-msm/qdsp5/audio_lpa.c
index 8760e443..a7c2543 100644
--- a/arch/arm/mach-msm/qdsp5/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp5/audio_lpa.c
@@ -46,7 +46,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5/qdsp5audppcmdi.h>
 #include <mach/qdsp5/qdsp5audppmsg.h>
 #include <mach/qdsp5/qdsp5audplaycmdi.h>
@@ -73,7 +72,7 @@
 
 /* Size must be power of 2 */
 #define MAX_BUF 2
-#define BUFSZ (1024000)
+#define BUFSZ (524288)
 
 #define AUDDEC_DEC_PCM 0
 
@@ -553,7 +552,9 @@
 	struct audpcm_buffer_node *buf_node;
 	struct list_head *ptr, *next;
 	union msm_audio_event_payload payload;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	MM_DBG("\n"); /* Macro prints the file name and function */
 	list_for_each_safe(ptr, next, &audio->out_queue) {
 		buf_node = list_entry(ptr, struct audpcm_buffer_node, list);
@@ -566,6 +567,7 @@
 	audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
 	audio->out_needed = 0;
 	atomic_set(&audio->out_bytes, 0);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 static void audio_ioport_reset(struct audio *audio)
 {
@@ -1221,7 +1223,7 @@
 	audpcm_reset_event_queue(audio);
 	MM_DBG("pmem area = 0x%8x\n", (unsigned int)audio->data);
 	if (audio->data) {
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->phys);
 	}
 	mutex_unlock(&audio->lock);
diff --git a/arch/arm/mach-msm/qdsp5/audio_mp3.c b/arch/arm/mach-msm/qdsp5/audio_mp3.c
index f6fa62a..7f72e25 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mp3.c
@@ -39,7 +39,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/msm_memtypes.h>
 #include <mach/qdsp5/qdsp5audppcmdi.h>
 #include <mach/qdsp5/qdsp5audppmsg.h>
@@ -202,8 +201,8 @@
 	/* data allocated for various buffers */
 	char *data;
 	int32_t phys; /* physical address of write buffer */
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 
 	uint32_t drv_status;
 	int mfield; /* meta field embedded in data */
@@ -837,7 +836,9 @@
 	struct audmp3_buffer_node *buf_node;
 	struct list_head *ptr, *next;
 	union msm_audio_event_payload payload;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->dsp_lock, flags);
 	MM_DBG("\n"); /* Macro prints the file name and function */
 	list_for_each_safe(ptr, next, &audio->out_queue) {
 		buf_node = list_entry(ptr, struct audmp3_buffer_node, list);
@@ -850,6 +851,7 @@
 	audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
 	audio->out_needed = 0;
 	atomic_set(&audio->out_bytes, 0);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
 static void audio_flush(struct audio *audio)
@@ -1488,12 +1490,10 @@
 					rc = -ENOMEM;
 					break;
 				}
-				audio->map_v_read = msm_subsystem_map_buffer(
+				audio->map_v_read = ioremap(
 							audio->read_phys,
 							config.buffer_size *
-							config.buffer_count,
-							MSM_SUBSYSTEM_MAP_KADDR,
-							NULL, 0);
+							config.buffer_count);
 
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("map of read buf failed\n");
@@ -1504,7 +1504,7 @@
 					uint8_t index;
 					uint32_t offset = 0;
 					audio->read_data =
-						audio->map_v_read->vaddr;
+						audio->map_v_read;
 					audio->buf_refresh = 0;
 					audio->pcm_buf_count =
 					    config.buffer_count;
@@ -1979,11 +1979,11 @@
 	audmp3_reset_event_queue(audio);
 	MM_DBG("pmem area = 0x%8x\n", (unsigned int)audio->data);
 	if (audio->data) {
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->phys);
 	}
 	if (audio->read_data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->read_phys);
 	}
 	mutex_unlock(&audio->lock);
@@ -2178,10 +2178,8 @@
 			audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
 								SZ_4K);
 			if (audio->phys) {
-				audio->map_v_write = msm_subsystem_map_buffer(
-							audio->phys, pmem_sz,
-							MSM_SUBSYSTEM_MAP_KADDR,
-							NULL, 0);
+				audio->map_v_write = ioremap(
+							audio->phys, pmem_sz);
 				if (IS_ERR(audio->map_v_write)) {
 					MM_ERR("could not map write \
 						buffers, freeing instance \
@@ -2193,7 +2191,7 @@
 					kfree(audio);
 					goto done;
 				}
-				audio->data = audio->map_v_write->vaddr;
+				audio->data = audio->map_v_write;
 				MM_DBG("write buf: phy addr 0x%08x kernel addr\
 					0x%08x\n", audio->phys,\
 					(int)audio->data);
@@ -2321,7 +2319,7 @@
 	return rc;
 err:
 	if (audio->data) {
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->phys);
 	}
 	audpp_adec_free(audio->dec_id);
diff --git a/arch/arm/mach-msm/qdsp5/audio_out.c b/arch/arm/mach-msm/qdsp5/audio_out.c
index 8fe8cf66..ef7a70b 100644
--- a/arch/arm/mach-msm/qdsp5/audio_out.c
+++ b/arch/arm/mach-msm/qdsp5/audio_out.c
@@ -593,6 +593,7 @@
 			audio_flush(audio);
 			mutex_unlock(&audio->write_lock);
 		}
+		break;
 	case AUDIO_SET_CONFIG: {
 		struct msm_audio_config config;
 		if (copy_from_user(&config, (void*) arg, sizeof(config))) {
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm.c b/arch/arm/mach-msm/qdsp5/audio_pcm.c
index 6468e93..5cd95f6 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm.c
@@ -46,7 +46,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5/qdsp5audppcmdi.h>
 #include <mach/qdsp5/qdsp5audppmsg.h>
 #include <mach/qdsp5/qdsp5audplaycmdi.h>
@@ -187,7 +186,7 @@
 	/* data allocated for various buffers */
 	char *data;
 	int32_t phys;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_write;
 
 	uint32_t drv_status;
 	int wflush; /* Write flush */
@@ -1379,7 +1378,7 @@
 	audpcm_reset_event_queue(audio);
 	MM_DBG("pmem area = 0x%8x\n", (unsigned int)audio->data);
 	if (audio->data) {
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->phys);
 	}
 	mutex_unlock(&audio->lock);
@@ -1551,10 +1550,8 @@
 			audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
 								SZ_4K);
 			if (audio->phys) {
-				audio->map_v_write = msm_subsystem_map_buffer(
-							audio->phys, pmem_sz,
-							MSM_SUBSYSTEM_MAP_KADDR,
-							NULL, 0);
+				audio->map_v_write = ioremap(
+							audio->phys, pmem_sz);
 				if (IS_ERR(audio->map_v_write)) {
 					MM_ERR("could not map write\
 							buffers\n");
@@ -1567,7 +1564,7 @@
 					kfree(audio);
 					goto done;
 				}
-				audio->data = audio->map_v_write->vaddr;
+				audio->data = audio->map_v_write;
 				MM_DBG("write buf: phy addr 0x%08x kernel addr\
 					0x%08x\n", audio->phys,\
 					(int)audio->data);
@@ -1678,7 +1675,7 @@
 	return rc;
 err:
 	if (audio->data) {
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->phys);
 	}
 	audpp_adec_free(audio->dec_id);
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
index 16c70ce..851980d 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
@@ -585,7 +585,7 @@
 	audio->in_head = 0;
 	audio->in_tail = 0;
 	audio->in_count = 0;
-	for (i = FRAME_NUM-1; i <= 0; i--) {
+	for (i = FRAME_NUM-1; i >= 0; i--) {
 		audio->in[i].size = 0;
 		audio->in[i].read = 0;
 	}
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp.c b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
index 2be5144..667a164 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
@@ -42,7 +42,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5/qdsp5audppcmdi.h>
 #include <mach/qdsp5/qdsp5audppmsg.h>
 #include <mach/qdsp5/qdsp5audplaycmdi.h>
@@ -132,8 +131,8 @@
 	/* data allocated for various buffers */
 	char *data;
 	int32_t phys; /* physical address of write buffer */
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 	int mfield; /* meta field embedded in data */
 	int rflush; /* Read  flush */
 	int wflush; /* Write flush */
@@ -966,12 +965,10 @@
 					rc = -ENOMEM;
 					break;
 				}
-				audio->map_v_read = msm_subsystem_map_buffer(
+				audio->map_v_read = ioremap(
 							audio->read_phys,
 							config.buffer_size *
-							config.buffer_count,
-							MSM_SUBSYSTEM_MAP_KADDR,
-							NULL, 0);
+							config.buffer_count);
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("failed to map read buf\n");
 					rc = -ENOMEM;
@@ -981,7 +978,7 @@
 					uint8_t index;
 					uint32_t offset = 0;
 					audio->read_data =
-						audio->map_v_read->vaddr;
+						audio->map_v_read;
 					audio->buf_refresh = 0;
 					audio->pcm_buf_count =
 						config.buffer_count;
@@ -1290,10 +1287,10 @@
 	audio->event_abort = 1;
 	wake_up(&audio->event_wait);
 	audqcelp_reset_event_queue(audio);
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	if (audio->read_data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->read_phys);
 	}
 	mutex_unlock(&audio->lock);
@@ -1483,10 +1480,7 @@
 		kfree(audio);
 		goto done;
 	} else {
-		audio->map_v_write = msm_subsystem_map_buffer(
-						audio->phys, DMASZ,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+		audio->map_v_write = ioremap(audio->phys, DMASZ);
 		if (IS_ERR(audio->map_v_write)) {
 			MM_ERR("could not map write buffers, freeing \
 					instance 0x%08x\n", (int)audio);
@@ -1496,7 +1490,7 @@
 			kfree(audio);
 			goto done;
 		}
-		audio->data = audio->map_v_write->vaddr;
+		audio->data = audio->map_v_write;
 		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
 				audio->phys, (int)audio->data);
 	}
@@ -1586,7 +1580,7 @@
 done:
 	return rc;
 err:
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
index a79f721..e6906d0 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
@@ -42,7 +42,6 @@
 #include <mach/msm_rpcrouter.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include "audmgr.h"
 
 #include <mach/qdsp5/qdsp5audpreproc.h>
@@ -145,8 +144,8 @@
 	char *data;
 	dma_addr_t phys;
 
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 
 	int opened;
 	int enabled;
@@ -801,13 +800,15 @@
 		}
 		/* Allow only single frame */
 		if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
-			if (cfg.buffer_size != (FRAME_SIZE - 8))
+			if (cfg.buffer_size != (FRAME_SIZE - 8)) {
 				rc = -EINVAL;
 				break;
+			}
 		} else {
-			if (cfg.buffer_size != (QCELP_FRAME_SIZE + 14))
+			if (cfg.buffer_size != (QCELP_FRAME_SIZE + 14)) {
 				rc = -EINVAL;
 				break;
+			}
 		}
 		audio->buffer_size = cfg.buffer_size;
 		break;
@@ -1191,13 +1192,13 @@
 
 	if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
 	   (audio->out_data)) {
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->out_phys);
 		audio->out_data = NULL;
 	}
 
 	if (audio->data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->phys);
 		audio->data = NULL;
 	}
@@ -1298,17 +1299,14 @@
 		rc = -ENOMEM;
 		goto evt_error;
 	} else {
-		audio->map_v_read = msm_subsystem_map_buffer(
-						audio->phys, dma_size,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+		audio->map_v_read = ioremap(audio->phys, dma_size);
 		if (IS_ERR(audio->map_v_read)) {
 			MM_ERR("could not map physical address\n");
 			rc = -ENOMEM;
 			free_contiguous_memory_by_paddr(audio->phys);
 			goto evt_error;
 		}
-		audio->data = audio->map_v_read->vaddr;
+		audio->data = audio->map_v_read;
 		MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
 				audio->phys, (int)audio->data);
 	}
@@ -1320,25 +1318,23 @@
 		if (!audio->out_phys) {
 			MM_ERR("could not allocate physical write buffers\n");
 			rc = -ENOMEM;
-			msm_subsystem_unmap_buffer(audio->map_v_read);
+			iounmap(audio->map_v_read);
 			free_contiguous_memory_by_paddr(audio->phys);
 			goto evt_error;
 		} else {
-			audio->map_v_write = msm_subsystem_map_buffer(
-						audio->out_phys, BUFFER_SIZE,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+			audio->map_v_write = ioremap(
+						audio->out_phys, BUFFER_SIZE);
 
 			if (IS_ERR(audio->map_v_write)) {
 				MM_ERR("could not map write phys address\n");
 				rc = -ENOMEM;
-				msm_subsystem_unmap_buffer(audio->map_v_read);
+				iounmap(audio->map_v_read);
 				free_contiguous_memory_by_paddr(audio->phys);
 				free_contiguous_memory_by_paddr(\
 							audio->out_phys);
 				goto evt_error;
 			}
-			audio->out_data = audio->map_v_write->vaddr;
+			audio->out_data = audio->map_v_write;
 			MM_DBG("wr buf: phy addr 0x%08x kernel addr 0x%08x\n",
 					audio->out_phys, (int)audio->out_data);
 		}
diff --git a/arch/arm/mach-msm/qdsp5/audio_wma.c b/arch/arm/mach-msm/qdsp5/audio_wma.c
index 674ee4f..b17cdda 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wma.c
@@ -46,7 +46,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5/qdsp5audppcmdi.h>
 #include <mach/qdsp5/qdsp5audppmsg.h>
 #include <mach/qdsp5/qdsp5audplaycmdi.h>
@@ -145,8 +144,8 @@
 	/* data allocated for various buffers */
 	char *data;
 	int32_t phys; /* physical address of write buffer */
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 
 	int mfield; /* meta field embedded in data */
 	int rflush; /* Read  flush */
@@ -470,6 +469,7 @@
 		wake_up(&audio->write_wait);
 		if (audio->pcm_feedback)
 			audplay_buffer_refresh(audio);
+		break;
 	case AUDPP_MSG_PCMDMAMISSED:
 		MM_DBG("PCMDMAMISSED\n");
 		audio->teos = 1;
@@ -1043,12 +1043,10 @@
 					rc = -ENOMEM;
 					break;
 				}
-				audio->map_v_read = msm_subsystem_map_buffer(
+				audio->map_v_read = ioremap(
 						audio->read_phys,
 						config.buffer_size *
-						config.buffer_count,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+						config.buffer_count);
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("map of read buf failed\n");
 					rc = -ENOMEM;
@@ -1058,7 +1056,7 @@
 					uint8_t index;
 					uint32_t offset = 0;
 					audio->read_data =
-						audio->map_v_read->vaddr;
+						audio->map_v_read;
 					audio->buf_refresh = 0;
 					audio->pcm_buf_count =
 					    config.buffer_count;
@@ -1435,10 +1433,10 @@
 	audio->event_abort = 1;
 	wake_up(&audio->event_wait);
 	audwma_reset_event_queue(audio);
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	if (audio->read_data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->read_phys);
 	}
 	mutex_unlock(&audio->lock);
@@ -1630,10 +1628,7 @@
 		MM_DBG("pmemsz = %d\n", pmem_sz);
 		audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
 		if (audio->phys) {
-			audio->map_v_write = msm_subsystem_map_buffer(
-							audio->phys, pmem_sz,
-							MSM_SUBSYSTEM_MAP_KADDR,
-							NULL, 0);
+			audio->map_v_write = ioremap(audio->phys, pmem_sz);
 			if (IS_ERR(audio->map_v_write)) {
 				MM_ERR("could not map write buffers, \
 						freeing instance 0x%08x\n",
@@ -1644,7 +1639,7 @@
 				kfree(audio);
 				goto done;
 			}
-			audio->data = audio->map_v_write->vaddr;
+			audio->data = audio->map_v_write;
 			MM_DBG("write buf: phy addr 0x%08x kernel addr \
 				0x%08x\n", audio->phys, (int)audio->data);
 			break;
@@ -1753,7 +1748,7 @@
 done:
 	return rc;
 err:
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_wmapro.c b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
index c2a0b93..5e806e6 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
@@ -52,7 +52,6 @@
 #include <mach/msm_memtypes.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 
 #include "audmgr.h"
 
@@ -144,8 +143,8 @@
 	/* data allocated for various buffers */
 	char *data;
 	int32_t phys; /* physical address of write buffer */
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 
 	int mfield; /* meta field embedded in data */
 	int rflush; /* Read  flush */
@@ -464,6 +463,7 @@
 		wake_up(&audio->write_wait);
 		if (audio->pcm_feedback)
 			audplay_buffer_refresh(audio);
+		break;
 	case AUDPP_MSG_PCMDMAMISSED:
 		MM_DBG("PCMDMAMISSED\n");
 		audio->teos = 1;
@@ -1040,12 +1040,10 @@
 					rc = -ENOMEM;
 					break;
 				}
-				audio->map_v_read = msm_subsystem_map_buffer(
+				audio->map_v_read = ioremap(
 						audio->read_phys,
 						config.buffer_size *
-						config.buffer_count,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+						config.buffer_count);
 
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("map of read buf failed\n");
@@ -1055,8 +1053,7 @@
 				} else {
 					uint8_t index;
 					uint32_t offset = 0;
-					audio->read_data =
-						audio->map_v_read->vaddr;
+					audio->read_data = audio->map_v_read;
 					audio->pcm_feedback = 1;
 					audio->buf_refresh = 0;
 					audio->pcm_buf_count =
@@ -1432,10 +1429,10 @@
 	audio->event_abort = 1;
 	wake_up(&audio->event_wait);
 	audwmapro_reset_event_queue(audio);
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	if (audio->read_data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->read_phys);
 	}
 	mutex_unlock(&audio->lock);
@@ -1627,10 +1624,7 @@
 		MM_DBG("pmemsz = %d\n", pmem_sz);
 		audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
 		if (audio->phys) {
-			audio->map_v_write = msm_subsystem_map_buffer(
-							audio->phys, pmem_sz,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+			audio->map_v_write = ioremap(audio->phys, pmem_sz);
 			if (IS_ERR(audio->map_v_write)) {
 				MM_ERR("could not map write buffers, \
 						freeing instance 0x%08x\n",
@@ -1641,7 +1635,7 @@
 				kfree(audio);
 				goto done;
 			}
-			audio->data = audio->map_v_write->vaddr;
+			audio->data = audio->map_v_write;
 			MM_DBG("write buf: phy addr 0x%08x kernel addr \
 				0x%08x\n", audio->phys, (int)audio->data);
 			break;
@@ -1741,7 +1735,7 @@
 done:
 	return rc;
 err:
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
index 60b5c20..733b7a1 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * sbc/pcm audio input driver
  * Based on the pcm input driver in arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
@@ -41,7 +41,6 @@
 #include <mach/iommu_domains.h>
 #include <mach/msm_adsp.h>
 #include <mach/msm_memtypes.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/socinfo.h>
 #include <mach/qdsp5v2/qdsp5audreccmdi.h>
 #include <mach/qdsp5v2/qdsp5audrecmsg.h>
@@ -108,7 +107,7 @@
 	/* data allocated for various buffers */
 	char *data;
 	dma_addr_t phys;
-	struct msm_mapped_buffer *msm_map;
+	void *msm_map;
 
 	int opened;
 	int enabled;
@@ -849,7 +848,7 @@
 	audio->audrec = NULL;
 	audio->opened = 0;
 	if (audio->data) {
-		msm_subsystem_unmap_buffer(audio->msm_map);
+		iounmap(audio->msm_map);
 		free_contiguous_memory_by_paddr(audio->phys);
 		audio->data = NULL;
 	}
@@ -871,9 +870,7 @@
 
 	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
 	if (audio->phys) {
-		audio->msm_map = msm_subsystem_map_buffer(
-					audio->phys, DMASZ,
-					MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+		audio->msm_map = ioremap(audio->phys, DMASZ);
 		if (IS_ERR(audio->msm_map)) {
 			MM_ERR("could not map the phys address to kernel"
 							"space\n");
@@ -881,7 +878,7 @@
 			free_contiguous_memory_by_paddr(audio->phys);
 			goto done;
 		}
-		audio->data = (u8 *)audio->msm_map->vaddr;
+		audio->data = (u8 *)audio->msm_map;
 	} else {
 		MM_ERR("could not allocate DMA buffers\n");
 		rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_aac.c b/arch/arm/mach-msm/qdsp5v2/audio_aac.c
index 9069426..32053bf 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_aac.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. 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
@@ -38,7 +38,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5v2/qdsp5audppmsg.h>
 #include <mach/qdsp5v2/qdsp5audplaycmdi.h>
 #include <mach/qdsp5v2/qdsp5audplaymsg.h>
@@ -142,8 +141,8 @@
 	/* data allocated for various buffers */
 	char *data;
 	int32_t phys; /* physical address of write buffer */
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 
 	int mfield; /* meta field embedded in data */
 	int rflush; /* Read  flush */
@@ -1629,9 +1628,9 @@
 	audio->event_abort = 1;
 	wake_up(&audio->event_wait);
 	audaac_reset_event_queue(audio);
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
-	msm_subsystem_unmap_buffer(audio->map_v_read);
+	iounmap(audio->map_v_read);
 	free_contiguous_memory_by_paddr(audio->read_phys);
 	mutex_unlock(&audio->lock);
 #ifdef CONFIG_DEBUG_FS
@@ -1821,10 +1820,8 @@
 		audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
 		if (audio->phys) {
 			audio->map_v_write =
-					msm_subsystem_map_buffer(audio->phys,
-						pmem_sz,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+					ioremap(audio->phys,
+						pmem_sz);
 			if (IS_ERR(audio->map_v_write)) {
 				MM_ERR("could not map write phys address, \
 						freeing instance 0x%08x\n",
@@ -1835,7 +1832,7 @@
 				kfree(audio);
 				goto done;
 			}
-			audio->data = (u8 *)audio->map_v_write->vaddr;
+			audio->data = (u8 *)audio->map_v_write;
 			MM_DBG("write buf: phy addr 0x%08x kernel addr \
 				0x%08x\n", audio->phys, (int)audio->data);
 			break;
@@ -1857,28 +1854,26 @@
 		MM_ERR("could not allocate read buffers, freeing instance \
 				0x%08x\n", (int)audio);
 		rc = -ENOMEM;
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->phys);
 		audpp_adec_free(audio->dec_id);
 		kfree(audio);
 		goto done;
 	}
-	audio->map_v_read = msm_subsystem_map_buffer(
-				audio->read_phys,
-				PCM_BUFSZ_MIN * PCM_BUF_MAX_COUNT,
-				MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+	audio->map_v_read = ioremap(audio->read_phys,
+				PCM_BUFSZ_MIN * PCM_BUF_MAX_COUNT);
 	if (IS_ERR(audio->map_v_read)) {
 		MM_ERR("could not map read phys address, freeing instance \
 				0x%08x\n", (int)audio);
 		rc = -ENOMEM;
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->phys);
 		free_contiguous_memory_by_paddr(audio->read_phys);
 		audpp_adec_free(audio->dec_id);
 		kfree(audio);
 		goto done;
 	}
-	audio->read_data = audio->map_v_read->vaddr;
+	audio->read_data = audio->map_v_read;
 	MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
 				audio->read_phys, (int)audio->read_data);
 
@@ -2000,9 +1995,9 @@
 event_err:
 	msm_adsp_put(audio->audplay);
 err:
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
-	msm_subsystem_unmap_buffer(audio->map_v_read);
+	iounmap(audio->map_v_read);
 	free_contiguous_memory_by_paddr(audio->read_phys);
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c b/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c
index 010fd90..d2b4407 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -32,7 +32,6 @@
 
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/iommu_domains.h>
 #include <mach/qdsp5v2/qdsp5audreccmdi.h>
 #include <mach/qdsp5v2/qdsp5audrecmsg.h>
@@ -97,8 +96,8 @@
 	wait_queue_head_t write_wait;
 	int32_t out_phys; /* physical address of write buffer */
 	char *out_data;
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 
 	int mfield; /* meta field embedded in data */
 	int wflush; /*write flush */
@@ -1292,12 +1291,12 @@
 	audio->audrec = NULL;
 	audio->opened = 0;
 	if (audio->data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->phys);
 		audio->data = NULL;
 	}
 	if (audio->out_data) {
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->out_phys);
 		audio->out_data = NULL;
 	}
@@ -1320,16 +1319,14 @@
 	}
 	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
 	if (audio->phys) {
-		audio->map_v_read = msm_subsystem_map_buffer(
-					audio->phys, DMASZ,
-					MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+		audio->map_v_read = ioremap(audio->phys, DMASZ);
 		if (IS_ERR(audio->map_v_read)) {
 			MM_ERR("could not map DMA buffers\n");
 			rc = -ENOMEM;
 			free_contiguous_memory_by_paddr(audio->phys);
 			goto done;
 		}
-		audio->data = audio->map_v_read->vaddr;
+		audio->data = audio->map_v_read;
 	} else {
 		MM_ERR("could not allocate DMA buffers\n");
 		rc = -ENOMEM;
@@ -1398,16 +1395,15 @@
 		rc = -ENOMEM;
 		goto evt_error;
 	} else {
-		audio->map_v_write = msm_subsystem_map_buffer(
-					audio->out_phys, BUFFER_SIZE,
-					MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+		audio->map_v_write = ioremap(
+					audio->out_phys, BUFFER_SIZE);
 		if (IS_ERR(audio->map_v_write)) {
 			MM_ERR("could not map write phys address\n");
 			rc = -ENOMEM;
 			free_contiguous_memory_by_paddr(audio->out_phys);
 			goto evt_error;
 		}
-		audio->out_data = audio->map_v_write->vaddr;
+		audio->out_data = audio->map_v_write;
 		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
 				audio->out_phys, (int)audio->out_data);
 	}
@@ -1434,7 +1430,7 @@
 					aac_in_listener, (void *) audio);
 	if (rc) {
 		MM_ERR("failed to register device event listener\n");
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->out_phys);
 		goto evt_error;
 	}
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_acdb.c b/arch/arm/mach-msm/qdsp5v2/audio_acdb.c
index 90373f9..89957a4 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_acdb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* 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
@@ -28,7 +28,6 @@
 #include <mach/dal.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5v2/audio_dev_ctl.h>
 #include <mach/qdsp5v2/audpp.h>
 #include <mach/socinfo.h>
@@ -111,7 +110,7 @@
 	u16 *pbe_enable_flag;
 	u32 fluence_extbuff;
 	u8 *fluence_extbuff_virt;
-	struct msm_mapped_buffer *map_v_fluence;
+	void *map_v_fluence;
 
 	struct acdb_pbe_block *pbe_blk;
 
@@ -130,7 +129,7 @@
 	/* pmem for get acdb blk */
 	unsigned long	get_blk_paddr;
 	u8		*get_blk_kvaddr;
-	struct msm_mapped_buffer *map_v_get_blk;
+	void *map_v_get_blk;
 	char *build_id;
 };
 
@@ -140,7 +139,7 @@
 	u32 node_status;
 	s32 stream_id;
 	u32 phys_addr_acdb_values;
-	struct msm_mapped_buffer *map_v_addr;
+	void *map_v_addr;
 	u8 *virt_addr_acdb_values;
 	struct auddev_evt_audcal_info device_info;
 };
@@ -237,7 +236,7 @@
 struct rtc_acdb_pmem {
 	u8 *viraddr;
 	int32_t phys;
-	struct msm_mapped_buffer *map_v_rtc;
+	void *map_v_rtc;
 };
 
 struct rtc_acdb_data {
@@ -1087,11 +1086,11 @@
 	rtc_acdb.valid_abid = false;
 
 	if (rtc_read->viraddr != NULL || ((void *)rtc_read->phys) != NULL) {
-		msm_subsystem_unmap_buffer(rtc_read->map_v_rtc);
+		iounmap(rtc_read->map_v_rtc);
 		free_contiguous_memory_by_paddr(rtc_read->phys);
 	}
 	if (rtc_write->viraddr != NULL || ((void *)rtc_write->phys) != NULL) {
-		msm_subsystem_unmap_buffer(rtc_write->map_v_rtc);
+		iounmap(rtc_write->map_v_rtc);
 		free_contiguous_memory_by_paddr(rtc_write->phys);
 	}
 }
@@ -1141,17 +1140,15 @@
 		result = -ENOMEM;
 		goto error;
 	}
-	rtc_read->map_v_rtc = msm_subsystem_map_buffer(
-				rtc_read->phys,
-				PMEM_RTC_ACDB_QUERY_MEM,
-				MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+	rtc_read->map_v_rtc = ioremap(rtc_read->phys,
+				PMEM_RTC_ACDB_QUERY_MEM);
 
 	if (IS_ERR(rtc_read->map_v_rtc)) {
 		MM_ERR("ACDB Could not map physical address\n");
 		result = -ENOMEM;
 		goto error;
 	}
-	rtc_read->viraddr = rtc_read->map_v_rtc->vaddr;
+	rtc_read->viraddr = rtc_read->map_v_rtc;
 	memset(rtc_read->viraddr, 0, PMEM_RTC_ACDB_QUERY_MEM);
 
 	rtc_write->phys = allocate_contiguous_ebi_nomap(PMEM_RTC_ACDB_QUERY_MEM,
@@ -1162,16 +1159,15 @@
 		result = -ENOMEM;
 		goto error;
 	}
-	rtc_write->map_v_rtc = msm_subsystem_map_buffer(
-				rtc_write->phys, PMEM_RTC_ACDB_QUERY_MEM,
-				MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+	rtc_write->map_v_rtc = ioremap(rtc_write->phys,
+				PMEM_RTC_ACDB_QUERY_MEM);
 
 	if (IS_ERR(rtc_write->map_v_rtc)) {
 		MM_ERR("ACDB Could not map physical address\n");
 		result = -ENOMEM;
 		goto error;
 	}
-	rtc_write->viraddr = rtc_write->map_v_rtc->vaddr;
+	rtc_write->viraddr = rtc_write->map_v_rtc;
 	memset(rtc_write->viraddr, 0, PMEM_RTC_ACDB_QUERY_MEM);
 	init_waitqueue_head(&rtc_acdb.wait);
 	return true;
@@ -1187,11 +1183,11 @@
 		debugfs_remove(get_set_abid_data_dentry);
 	}
 	if (rtc_read->viraddr != NULL || ((void *)rtc_read->phys) != NULL) {
-		msm_subsystem_unmap_buffer(rtc_read->map_v_rtc);
+		iounmap(rtc_read->map_v_rtc);
 		free_contiguous_memory_by_paddr(rtc_read->phys);
 	}
 	if (rtc_write->viraddr != NULL || ((void *)rtc_write->phys) != NULL) {
-		msm_subsystem_unmap_buffer(rtc_write->map_v_rtc);
+		iounmap(rtc_write->map_v_rtc);
 		free_contiguous_memory_by_paddr(rtc_write->phys);
 	}
 	return false;
@@ -2544,11 +2540,9 @@
 			result = -ENOMEM;
 			goto error;
 		}
-		acdb_cache_tx[i].map_v_addr =
-					msm_subsystem_map_buffer(
+		acdb_cache_tx[i].map_v_addr = ioremap(
 					acdb_cache_tx[i].phys_addr_acdb_values,
-						ACDB_BUF_SIZE,
-					MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+						ACDB_BUF_SIZE);
 		if (IS_ERR(acdb_cache_tx[i].map_v_addr)) {
 			MM_ERR("ACDB=> Could not map physical address\n");
 			result = -ENOMEM;
@@ -2557,15 +2551,14 @@
 			goto error;
 		}
 		acdb_cache_tx[i].virt_addr_acdb_values =
-					acdb_cache_tx[i].map_v_addr->vaddr;
+					acdb_cache_tx[i].map_v_addr;
 		memset(acdb_cache_tx[i].virt_addr_acdb_values, 0,
 						ACDB_BUF_SIZE);
 	}
 	return result;
 error:
 	for (err = 0; err < i; err++) {
-		msm_subsystem_unmap_buffer(
-				acdb_cache_tx[err].map_v_addr);
+		iounmap(acdb_cache_tx[err].map_v_addr);
 		free_contiguous_memory_by_paddr(
 				acdb_cache_tx[err].phys_addr_acdb_values);
 	}
@@ -2590,11 +2583,8 @@
 			goto error;
 		}
 		acdb_cache_rx[i].map_v_addr =
-				msm_subsystem_map_buffer(
-					acdb_cache_rx[i].phys_addr_acdb_values,
-					ACDB_BUF_SIZE,
-					MSM_SUBSYSTEM_MAP_KADDR,
-					NULL, 0);
+				ioremap(acdb_cache_rx[i].phys_addr_acdb_values,
+					ACDB_BUF_SIZE);
 		if (IS_ERR(acdb_cache_rx[i].map_v_addr)) {
 			MM_ERR("ACDB=> Could not map physical address\n");
 			result = -ENOMEM;
@@ -2603,15 +2593,14 @@
 			goto error;
 		}
 		acdb_cache_rx[i].virt_addr_acdb_values =
-					acdb_cache_rx[i].map_v_addr->vaddr;
+					acdb_cache_rx[i].map_v_addr;
 		memset(acdb_cache_rx[i].virt_addr_acdb_values, 0,
 						ACDB_BUF_SIZE);
 	}
 	return result;
 error:
 	for (err = 0; err < i; err++) {
-		msm_subsystem_unmap_buffer(
-					acdb_cache_rx[err].map_v_addr);
+		iounmap(acdb_cache_rx[err].map_v_addr);
 		free_contiguous_memory_by_paddr(
 				acdb_cache_rx[err].phys_addr_acdb_values);
 	}
@@ -2628,10 +2617,8 @@
 		result = -ENOMEM;
 		goto error;
 	}
-	acdb_data.map_v_get_blk = msm_subsystem_map_buffer(
-					acdb_data.get_blk_paddr,
-					ACDB_BUF_SIZE,
-					MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+	acdb_data.map_v_get_blk = ioremap(acdb_data.get_blk_paddr,
+					ACDB_BUF_SIZE);
 	if (IS_ERR(acdb_data.map_v_get_blk)) {
 		MM_ERR("ACDB=> Could not map physical address\n");
 		result = -ENOMEM;
@@ -2639,7 +2626,7 @@
 					acdb_data.get_blk_paddr);
 		goto error;
 	}
-	acdb_data.get_blk_kvaddr = acdb_data.map_v_get_blk->vaddr;
+	acdb_data.get_blk_kvaddr = acdb_data.map_v_get_blk;
 	memset(acdb_data.get_blk_kvaddr, 0, ACDB_BUF_SIZE);
 error:
 	return result;
@@ -2650,7 +2637,7 @@
 	u32 i = 0;
 
 	for (i = 0; i < MAX_COPP_NODE_SUPPORTED; i++) {
-		msm_subsystem_unmap_buffer(acdb_cache_rx[i].map_v_addr);
+		iounmap(acdb_cache_rx[i].map_v_addr);
 		free_contiguous_memory_by_paddr(
 				acdb_cache_rx[i].phys_addr_acdb_values);
 	}
@@ -2661,7 +2648,7 @@
 	u32 i = 0;
 
 	for (i = 0; i < MAX_AUDREC_SESSIONS; i++) {
-		msm_subsystem_unmap_buffer(acdb_cache_tx[i].map_v_addr);
+		iounmap(acdb_cache_tx[i].map_v_addr);
 		free_contiguous_memory_by_paddr(
 				acdb_cache_tx[i].phys_addr_acdb_values);
 	}
@@ -2669,7 +2656,7 @@
 
 static void free_memory_acdb_get_blk(void)
 {
-	msm_subsystem_unmap_buffer(acdb_data.map_v_get_blk);
+	iounmap(acdb_data.map_v_get_blk);
 	free_contiguous_memory_by_paddr(acdb_data.get_blk_paddr);
 }
 
@@ -2827,11 +2814,9 @@
 		result = -ENOMEM;
 		goto done;
 	}
-	acdb_data.map_v_fluence =
-			msm_subsystem_map_buffer(
+	acdb_data.map_v_fluence = ioremap(
 				acdb_data.fluence_extbuff,
-				FLUENCE_BUF_SIZE,
-				MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+				FLUENCE_BUF_SIZE);
 	if (IS_ERR(acdb_data.map_v_fluence)) {
 		MM_ERR("ACDB=> Could not map physical address\n");
 		free_memory_acdb_get_blk();
@@ -2852,7 +2837,7 @@
 		goto done;
 	} else
 		acdb_data.fluence_extbuff_virt =
-					acdb_data.map_v_fluence->vaddr;
+					acdb_data.map_v_fluence;
 done:
 	return result;
 }
@@ -3431,11 +3416,11 @@
 
 	for (i = 0; i < MAX_COPP_NODE_SUPPORTED; i++) {
 		if (i < MAX_AUDREC_SESSIONS) {
-			msm_subsystem_unmap_buffer(acdb_cache_tx[i].map_v_addr);
+			iounmap(acdb_cache_tx[i].map_v_addr);
 			free_contiguous_memory_by_paddr(
 					acdb_cache_tx[i].phys_addr_acdb_values);
 		}
-		msm_subsystem_unmap_buffer(acdb_cache_rx[i].map_v_addr);
+		iounmap(acdb_cache_rx[i].map_v_addr);
 		free_contiguous_memory_by_paddr(
 					acdb_cache_rx[i].phys_addr_acdb_values);
 	}
@@ -3446,7 +3431,7 @@
 	kfree(acdb_data.preproc_iir);
 	free_contiguous_memory_by_paddr(
 				(int32_t)acdb_data.pbe_extbuff);
-	msm_subsystem_unmap_buffer(acdb_data.map_v_fluence);
+	iounmap(acdb_data.map_v_fluence);
 	free_contiguous_memory_by_paddr(
 			(int32_t)acdb_data.fluence_extbuff);
 	mutex_destroy(&acdb_data.acdb_mutex);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_adpcm.c b/arch/arm/mach-msm/qdsp5v2/audio_adpcm.c
index 4b8b7a6..a53128d 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_adpcm.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_adpcm.c
@@ -43,7 +43,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5v2/qdsp5audppmsg.h>
 #include <mach/qdsp5v2/qdsp5audplaycmdi.h>
 #include <mach/qdsp5v2/qdsp5audplaymsg.h>
@@ -139,8 +138,8 @@
 	/* data allocated for various buffers */
 	char *data;
 	int32_t phys; /* physical address of write buffer */
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 	int mfield; /* meta field embedded in data */
 	int rflush; /* Read  flush */
 	int wflush; /* Write flush */
@@ -1023,12 +1022,10 @@
 					rc = -ENOMEM;
 					break;
 				}
-				audio->map_v_read = msm_subsystem_map_buffer(
+				audio->map_v_read = ioremap(
 							audio->read_phys,
 							config.buffer_size *
-							config.buffer_count,
-							MSM_SUBSYSTEM_MAP_KADDR
-							, NULL, 0);
+							config.buffer_count);
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("read buf map fail\n");
 					rc = -ENOMEM;
@@ -1038,7 +1035,7 @@
 					uint8_t index;
 					uint32_t offset = 0;
 					audio->read_data =
-						audio->map_v_read->vaddr;
+						audio->map_v_read;
 					audio->buf_refresh = 0;
 					audio->pcm_buf_count =
 					    config.buffer_count;
@@ -1420,10 +1417,10 @@
 	audio->event_abort = 1;
 	wake_up(&audio->event_wait);
 	audadpcm_reset_event_queue(audio);
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	if (audio->read_data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->read_phys);
 	}
 	mutex_unlock(&audio->lock);
@@ -1615,10 +1612,7 @@
 		audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
 									SZ_4K);
 		if (audio->phys) {
-			audio->map_v_write = msm_subsystem_map_buffer(
-						audio->phys, pmem_sz,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+			audio->map_v_write = ioremap(audio->phys, pmem_sz);
 			if (IS_ERR(audio->map_v_write)) {
 				MM_ERR("could not map write phys address, \
 						freeing instance 0x%08x\n",
@@ -1629,7 +1623,7 @@
 				kfree(audio);
 				goto done;
 			}
-			audio->data = audio->map_v_write->vaddr;
+			audio->data = audio->map_v_write;
 			MM_DBG("write buf: phy addr 0x%08x kernel addr \
 				0x%08x\n", audio->phys, (int)audio->data);
 			break;
@@ -1729,7 +1723,7 @@
 event_err:
 	msm_adsp_put(audio->audplay);
 err:
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrnb.c b/arch/arm/mach-msm/qdsp5v2/audio_amrnb.c
index a09b71b..5f288dd 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrnb.c
@@ -44,7 +44,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5v2/audio_dev_ctl.h>
 #include <mach/qdsp5v2/qdsp5audppmsg.h>
 #include <mach/qdsp5v2/qdsp5audplaycmdi.h>
@@ -132,8 +131,8 @@
 	/* data allocated for various buffers */
 	char *data;
 	int32_t phys; /* physical address of write buffer */
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 
 	int mfield; /* meta field embedded in data */
 	int rflush; /* Read  flush */
@@ -993,12 +992,10 @@
 					rc = -ENOMEM;
 					break;
 			}
-			audio->map_v_read = msm_subsystem_map_buffer(
+			audio->map_v_read = ioremap(
 						audio->read_phys,
 						config.buffer_size *
-						config.buffer_count,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+						config.buffer_count);
 			if (IS_ERR(audio->map_v_read)) {
 				MM_ERR("failed to map read phys address\n");
 				rc = -ENOMEM;
@@ -1007,7 +1004,7 @@
 			} else {
 				uint8_t index;
 				uint32_t offset = 0;
-				audio->read_data = audio->map_v_read->vaddr;
+				audio->read_data = audio->map_v_read;
 				audio->buf_refresh = 0;
 				audio->pcm_buf_count =
 					config.buffer_count;
@@ -1317,10 +1314,10 @@
 	audio->event_abort = 1;
 	wake_up(&audio->event_wait);
 	audamrnb_reset_event_queue(audio);
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	if (audio->read_data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->read_phys);
 	}
 	mutex_unlock(&audio->lock);
@@ -1512,9 +1509,7 @@
 		kfree(audio);
 		goto done;
 	} else {
-		audio->map_v_write = msm_subsystem_map_buffer(
-					audio->phys, DMASZ,
-					MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+		audio->map_v_write = ioremap(audio->phys, DMASZ);
 		if (IS_ERR(audio->map_v_write)) {
 			MM_ERR("could not map write phys address, freeing \
 					instance 0x%08x\n", (int)audio);
@@ -1525,7 +1520,7 @@
 			kfree(audio);
 			goto done;
 		}
-		audio->data = audio->map_v_write->vaddr;
+		audio->data = audio->map_v_write;
 		MM_DBG("write buf: phy addr 0x%08x kernel addr \
 				0x%08x\n", audio->phys, (int)audio->data);
 	}
@@ -1610,7 +1605,7 @@
 event_err:
 	msm_adsp_put(audio->audplay);
 err:
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
index bdb5bb1..790c510 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -32,7 +32,6 @@
 
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/msm_adsp.h>
 #include <mach/socinfo.h>
 #include <mach/qdsp5v2/qdsp5audreccmdi.h>
@@ -99,7 +98,7 @@
 	/* data allocated for various buffers */
 	char *data;
 	dma_addr_t phys;
-	struct msm_mapped_buffer *map_v_read;
+	void *map_v_read;
 
 	int opened;
 	int enabled;
@@ -767,7 +766,7 @@
 	audio->audrec = NULL;
 	audio->opened = 0;
 	if (audio->data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->phys);
 		audio->data = NULL;
 	}
@@ -788,16 +787,14 @@
 	}
 	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
 	if (audio->phys) {
-		audio->map_v_read = msm_subsystem_map_buffer(
-					audio->phys, DMASZ,
-					MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+		audio->map_v_read = ioremap(audio->phys, DMASZ);
 		if (IS_ERR(audio->map_v_read)) {
 			MM_ERR("could not map DMA buffers\n");
 			rc = -ENOMEM;
 			free_contiguous_memory_by_paddr(audio->phys);
 			goto done;
 		}
-		audio->data = audio->map_v_read->vaddr;
+		audio->data = audio->map_v_read;
 	} else {
 		MM_ERR("could not allocate DMA buffers\n");
 		rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrwb.c b/arch/arm/mach-msm/qdsp5v2/audio_amrwb.c
index 48e9a9f..b74c054 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrwb.c
@@ -45,7 +45,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5v2/qdsp5audppmsg.h>
 #include <mach/qdsp5v2/qdsp5audplaycmdi.h>
 #include <mach/qdsp5v2/qdsp5audplaymsg.h>
@@ -136,8 +135,8 @@
 	char *data;
 	int32_t phys; /* physical address of write buffer */
 
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 
 	int mfield; /* meta field embedded in data */
 	int rflush; /* Read  flush */
@@ -1003,12 +1002,10 @@
 					rc = -ENOMEM;
 					break;
 			}
-			audio->map_v_read = msm_subsystem_map_buffer(
+			audio->map_v_read = ioremap(
 						audio->read_phys,
 						config.buffer_size *
-						config.buffer_count,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+						config.buffer_count);
 			if (IS_ERR(audio->map_v_read)) {
 				MM_ERR("Error could not map read"
 							" phys address\n");
@@ -1018,7 +1015,7 @@
 			} else {
 				uint8_t index;
 				uint32_t offset = 0;
-				audio->read_data = audio->map_v_read->vaddr;
+				audio->read_data = audio->map_v_read;
 				audio->pcm_feedback = 1;
 				audio->buf_refresh = 0;
 				audio->pcm_buf_count =
@@ -1401,10 +1398,10 @@
 	audio->event_abort = 1;
 	wake_up(&audio->event_wait);
 	audamrwb_reset_event_queue(audio);
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	if (audio->read_data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->read_phys);
 	}
 	mutex_unlock(&audio->lock);
@@ -1591,9 +1588,7 @@
 		kfree(audio);
 		goto done;
 	} else {
-		audio->map_v_write = msm_subsystem_map_buffer(
-					audio->phys, DMASZ,
-					MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+		audio->map_v_write = ioremap(audio->phys, DMASZ);
 		if (IS_ERR(audio->map_v_write)) {
 			MM_ERR("could not map write phys buffers, freeing \
 					instance 0x%08x\n", (int)audio);
@@ -1603,7 +1598,7 @@
 			kfree(audio);
 			goto done;
 		}
-		audio->data = audio->map_v_write->vaddr;
+		audio->data = audio->map_v_write;
 		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
 				audio->phys, (int)audio->data);
 	}
@@ -1692,7 +1687,7 @@
 event_err:
 	msm_adsp_put(audio->audplay);
 err:
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_evrc.c b/arch/arm/mach-msm/qdsp5v2/audio_evrc.c
index 9b5694d..8818cbd 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_evrc.c
@@ -40,7 +40,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5v2/audio_dev_ctl.h>
 #include <mach/qdsp5v2/qdsp5audppmsg.h>
 #include <mach/qdsp5v2/qdsp5audplaycmdi.h>
@@ -132,8 +131,8 @@
 	/* data allocated for various buffers */
 	char *data;
 	int32_t phys;  /* physical address of write buffer */
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 
 	int mfield; /* meta field embedded in data */
 	int rflush; /* Read  flush */
@@ -982,12 +981,10 @@
 					rc = -ENOMEM;
 					break;
 				}
-				audio->map_v_read = msm_subsystem_map_buffer(
+				audio->map_v_read = ioremap(
 							audio->read_phys,
 							config.buffer_size *
-							config.buffer_count,
-							MSM_SUBSYSTEM_MAP_KADDR
-							, NULL, 0);
+							config.buffer_count);
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("failed to map read"
 							" phy address\n");
@@ -998,7 +995,7 @@
 					uint8_t index;
 					uint32_t offset = 0;
 					audio->read_data =
-						audio->map_v_read->vaddr;
+						audio->map_v_read;
 					audio->buf_refresh = 0;
 					audio->pcm_buf_count =
 					    config.buffer_count;
@@ -1311,10 +1308,10 @@
 	audio->event_abort = 1;
 	wake_up(&audio->event_wait);
 	audevrc_reset_event_queue(audio);
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	if (audio->read_data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->read_phys);
 	}
 	mutex_unlock(&audio->lock);
@@ -1505,9 +1502,7 @@
 		kfree(audio);
 		goto done;
 	} else {
-		audio->map_v_write = msm_subsystem_map_buffer(
-					audio->phys, DMASZ,
-					MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+		audio->map_v_write = ioremap(audio->phys, DMASZ);
 		if (IS_ERR(audio->map_v_write)) {
 			MM_ERR("failed to map write physical address, freeing \
 					instance 0x%08x\n", (int)audio);
@@ -1517,7 +1512,7 @@
 			kfree(audio);
 			goto done;
 		}
-		audio->data = audio->map_v_write->vaddr;
+		audio->data = audio->map_v_write;
 		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
 				audio->phys, (int)audio->data);
 	}
@@ -1604,7 +1599,7 @@
 event_err:
 	msm_adsp_put(audio->audplay);
 err:
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
index 50621c9..150e476 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -33,7 +33,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/socinfo.h>
 #include <mach/qdsp5v2/qdsp5audreccmdi.h>
 #include <mach/qdsp5v2/qdsp5audrecmsg.h>
@@ -131,8 +130,8 @@
 	/* data allocated for various buffers */
 	char *data;
 	dma_addr_t phys;
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 	int opened;
 	int enabled;
 	int running;
@@ -1319,12 +1318,12 @@
 	audio->audrec = NULL;
 	audio->opened = 0;
 	if (audio->data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->phys);
 		audio->data = NULL;
 	}
 	if (audio->out_data) {
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->out_phys);
 		audio->out_data = NULL;
 	}
@@ -1346,17 +1345,14 @@
 	}
 	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
 	if (audio->phys) {
-		audio->map_v_read = msm_subsystem_map_buffer(
-						audio->phys, DMASZ,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+		audio->map_v_read = ioremap(audio->phys, DMASZ);
 		if (IS_ERR(audio->map_v_read)) {
 			MM_ERR("failed to map read physical address\n");
 			rc = -ENOMEM;
 			free_contiguous_memory_by_paddr(audio->phys);
 			goto done;
 		}
-		audio->data = audio->map_v_read->vaddr;
+		audio->data = audio->map_v_read;
 	} else {
 		MM_ERR("could not allocate DMA buffers\n");
 		rc = -ENOMEM;
@@ -1425,17 +1421,14 @@
 		rc = -ENOMEM;
 		goto evt_error;
 	} else {
-		audio->map_v_write = msm_subsystem_map_buffer(
-						audio->out_phys, BUFFER_SIZE,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+		audio->map_v_write = ioremap(audio->out_phys, BUFFER_SIZE);
 		if (IS_ERR(audio->map_v_write)) {
 			MM_ERR("could map write buffers\n");
 			rc = -ENOMEM;
 			free_contiguous_memory_by_paddr(audio->out_phys);
 			goto evt_error;
 		}
-		audio->out_data = audio->map_v_write->vaddr;
+		audio->out_data = audio->map_v_write;
 		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
 				audio->out_phys, (int)audio->out_data);
 	}
@@ -1461,7 +1454,7 @@
 					evrc_in_listener, (void *) audio);
 	if (rc) {
 		MM_ERR("failed to register device event listener\n");
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->out_phys);
 		goto evt_error;
 	}
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_mp3.c b/arch/arm/mach-msm/qdsp5v2/audio_mp3.c
index c639833..a4fc3e3 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_mp3.c
@@ -37,7 +37,6 @@
 
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5v2/audio_dev_ctl.h>
 #include <mach/qdsp5v2/qdsp5audppmsg.h>
 #include <mach/qdsp5v2/qdsp5audplaycmdi.h>
@@ -198,8 +197,8 @@
 	/* data allocated for various buffers */
 	char *data;
 	int32_t phys; /* physical address of write buffer */
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 
 	uint32_t drv_status;
 	int mfield; /* meta field embedded in data */
@@ -1609,12 +1608,10 @@
 					rc = -ENOMEM;
 					break;
 				}
-				audio->map_v_read = msm_subsystem_map_buffer(
+				audio->map_v_read = ioremap(
 							audio->read_phys,
 							config.buffer_size *
-							config.buffer_count,
-							MSM_SUBSYSTEM_MAP_KADDR
-							, NULL, 0);
+							config.buffer_count);
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("failed to map read buffer"
 							" physical address\n");
@@ -1625,7 +1622,7 @@
 					uint8_t index;
 					uint32_t offset = 0;
 					audio->read_data =
-						audio->map_v_read->vaddr;
+						audio->map_v_read;
 					audio->buf_refresh = 0;
 					audio->pcm_buf_count =
 					    config.buffer_count;
@@ -2145,11 +2142,11 @@
 	wake_up(&audio->event_wait);
 	audmp3_reset_event_queue(audio);
 	if (audio->data) {
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->phys);
 	}
 	if (audio->read_data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->read_phys);
 	}
 	mutex_unlock(&audio->lock);
@@ -2353,10 +2350,8 @@
 			audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
 									SZ_4K);
 			if (audio->phys) {
-				audio->map_v_write = msm_subsystem_map_buffer(
-							audio->phys, pmem_sz,
-							MSM_SUBSYSTEM_MAP_KADDR
-							, NULL, 0);
+				audio->map_v_write = ioremap(
+							audio->phys, pmem_sz);
 				if (IS_ERR(audio->map_v_write)) {
 					MM_ERR("failed to map write physical"
 						" address , freeing instance"
@@ -2368,7 +2363,7 @@
 					kfree(audio);
 					goto done;
 				}
-				audio->data = audio->map_v_write->vaddr;
+				audio->data = audio->map_v_write;
 				MM_DBG("write buf: phy addr 0x%08x kernel addr\
 					0x%08x\n", audio->phys,\
 					(int)audio->data);
@@ -2485,7 +2480,7 @@
 	msm_adsp_put(audio->audplay);
 err:
 	if (audio->data) {
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->phys);
 	}
 	audpp_adec_free(audio->dec_id);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_out.c b/arch/arm/mach-msm/qdsp5v2/audio_out.c
index 9a93185..930de03 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_out.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_out.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -36,7 +36,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5v2/qdsp5audppcmdi.h>
 #include <mach/qdsp5v2/qdsp5audppmsg.h>
 #include <mach/qdsp5v2/audio_dev_ctl.h>
@@ -86,7 +85,7 @@
 	/* data allocated for various buffers */
 	char *data;
 	dma_addr_t phys;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_write;
 	int teos; /* valid only if tunnel mode & no data left for decoder */
 	int opened;
 	int enabled;
@@ -704,16 +703,13 @@
 {
 	the_audio.phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
 	if (the_audio.phys) {
-		the_audio.map_v_write = msm_subsystem_map_buffer(
-						the_audio.phys, DMASZ,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+		the_audio.map_v_write = ioremap(the_audio.phys, DMASZ);
 		if (IS_ERR(the_audio.map_v_write)) {
 			MM_ERR("could not map physical buffers\n");
 			free_contiguous_memory_by_paddr(the_audio.phys);
 			return -ENOMEM;
 		}
-		the_audio.data = the_audio.map_v_write->vaddr;
+		the_audio.data = the_audio.map_v_write;
 	} else {
 			MM_ERR("could not allocate physical buffers\n");
 			return -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_pcm.c b/arch/arm/mach-msm/qdsp5v2/audio_pcm.c
index b22820b..613ee57 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_pcm.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_pcm.c
@@ -40,7 +40,6 @@
 
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5v2/qdsp5audppcmdi.h>
 #include <mach/qdsp5v2/qdsp5audppmsg.h>
 #include <mach/qdsp5v2/qdsp5audplaycmdi.h>
@@ -172,7 +171,7 @@
 	/* data allocated for various buffers */
 	char *data;
 	int32_t phys;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_write;
 	uint32_t drv_status;
 	int wflush; /* Write flush */
 	int opened;
@@ -1382,7 +1381,7 @@
 	wake_up(&audio->event_wait);
 	audpcm_reset_event_queue(audio);
 	if (audio->data) {
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->phys);
 	}
 	mutex_unlock(&audio->lock);
@@ -1560,10 +1559,8 @@
 			audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
 								SZ_4K);
 			if (audio->phys) {
-				audio->map_v_write = msm_subsystem_map_buffer(
-							audio->phys, pmem_sz,
-							MSM_SUBSYSTEM_MAP_KADDR
-							, NULL, 0);
+				audio->map_v_write = ioremap(
+							audio->phys, pmem_sz);
 				if (IS_ERR(audio->map_v_write)) {
 					MM_ERR("could not map write phys\
 						address freeing instance \
@@ -1575,7 +1572,7 @@
 					kfree(audio);
 					goto done;
 				}
-				audio->data = audio->map_v_write->vaddr;
+				audio->data = audio->map_v_write;
 				MM_DBG("write buf: phy addr 0x%08x \
 						kernel addr 0x%08x\n",
 						audio->phys, (int)audio->data);
@@ -1679,7 +1676,7 @@
 	msm_adsp_put(audio->audplay);
 err:
 	if (audio->data) {
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->phys);
 	}
 	audpp_adec_free(audio->dec_id);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
index a5a9bd2..ce67ebb 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -33,7 +33,6 @@
 
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 
 #include <mach/msm_adsp.h>
 #include <mach/socinfo.h>
@@ -113,7 +112,7 @@
 	/* data allocated for various buffers */
 	char *data;
 	dma_addr_t phys;
-	struct msm_mapped_buffer *map_v_read;
+	void *map_v_read;
 
 	int opened;
 	int enabled;
@@ -843,7 +842,7 @@
 	audio->audrec = NULL;
 	audio->opened = 0;
 	if (audio->data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->phys);
 		audio->data = NULL;
 	}
@@ -864,16 +863,14 @@
 	}
 	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
 	if (audio->phys) {
-		audio->map_v_read = msm_subsystem_map_buffer(
-					audio->phys, DMASZ,
-					MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+		audio->map_v_read = ioremap(audio->phys, DMASZ);
 		if (IS_ERR(audio->map_v_read)) {
 			MM_ERR("could not map read phys buffers\n");
 			rc = -ENOMEM;
 			free_contiguous_memory_by_paddr(audio->phys);
 			goto done;
 		}
-		audio->data = audio->map_v_read->vaddr;
+		audio->data = audio->map_v_read;
 	} else {
 		MM_ERR("could not allocate read buffers\n");
 		rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_qcelp.c b/arch/arm/mach-msm/qdsp5v2/audio_qcelp.c
index ce5d421..c4851d9 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_qcelp.c
@@ -41,7 +41,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5v2/qdsp5audppmsg.h>
 #include <mach/qdsp5v2/qdsp5audplaycmdi.h>
 #include <mach/qdsp5v2/qdsp5audplaymsg.h>
@@ -128,8 +127,8 @@
 	/* data allocated for various buffers */
 	char *data;
 	int32_t phys; /* physical address of write buffer */
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 
 	int mfield; /* meta field embedded in data */
 	int rflush; /* Read  flush */
@@ -984,12 +983,10 @@
 					rc = -ENOMEM;
 					break;
 				}
-				audio->map_v_read = msm_subsystem_map_buffer(
+				audio->map_v_read = ioremap(
 							audio->read_phys,
 							config.buffer_size *
-							config.buffer_count,
-							MSM_SUBSYSTEM_MAP_KADDR
-							, NULL, 0);
+							config.buffer_count);
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("failed to map read buf\n");
 					rc = -ENOMEM;
@@ -999,7 +996,7 @@
 					uint8_t index;
 					uint32_t offset = 0;
 					audio->read_data =
-						audio->map_v_read->vaddr;
+						audio->map_v_read;
 					audio->buf_refresh = 0;
 					audio->pcm_buf_count =
 						config.buffer_count;
@@ -1313,10 +1310,10 @@
 	audio->event_abort = 1;
 	wake_up(&audio->event_wait);
 	audqcelp_reset_event_queue(audio);
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	if (audio->read_data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->read_phys);
 	}
 	mutex_unlock(&audio->lock);
@@ -1505,9 +1502,7 @@
 		kfree(audio);
 		goto done;
 	} else {
-		audio->map_v_write = msm_subsystem_map_buffer(
-					audio->phys, DMASZ,
-					MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+		audio->map_v_write = ioremap(audio->phys, DMASZ);
 		if (IS_ERR(audio->map_v_write)) {
 			MM_ERR("could not map write phys address, freeing \
 					instance 0x%08x\n", (int)audio);
@@ -1517,7 +1512,7 @@
 			kfree(audio);
 			goto done;
 		}
-		audio->data = audio->map_v_write->vaddr;
+		audio->data = audio->map_v_write;
 		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
 				audio->phys, (int)audio->data);
 	}
@@ -1604,7 +1599,7 @@
 event_err:
 	msm_adsp_put(audio->audplay);
 err:
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
index d34499d..7041bde 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -33,7 +33,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/socinfo.h>
 #include <mach/qdsp5v2/qdsp5audreccmdi.h>
 #include <mach/qdsp5v2/qdsp5audrecmsg.h>
@@ -133,8 +132,8 @@
 	/* data allocated for various buffers */
 	char *data;
 	dma_addr_t phys;
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 
 	int opened;
 	int enabled;
@@ -1325,12 +1324,12 @@
 	audio->audrec = NULL;
 	audio->opened = 0;
 	if (audio->data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->phys);
 		audio->data = NULL;
 	}
 	if (audio->out_data) {
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->out_phys);
 		audio->out_data = NULL;
 	}
@@ -1352,16 +1351,14 @@
 	}
 	audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
 	if (audio->phys) {
-		audio->map_v_read = msm_subsystem_map_buffer(
-					audio->phys, DMASZ,
-					MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+		audio->map_v_read = ioremap(audio->phys, DMASZ);
 		if (IS_ERR(audio->map_v_read)) {
 			MM_ERR("could not map DMA buffers\n");
 			rc = -ENOMEM;
 			free_contiguous_memory_by_paddr(audio->phys);
 			goto done;
 		}
-		audio->data = audio->map_v_read->vaddr;
+		audio->data = audio->map_v_read;
 	} else {
 		MM_ERR("could not allocate DMA buffers\n");
 		rc = -ENOMEM;
@@ -1431,16 +1428,14 @@
 		rc = -ENOMEM;
 		goto evt_error;
 	} else {
-		audio->map_v_write = msm_subsystem_map_buffer(
-					audio->out_phys, BUFFER_SIZE,
-					MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+		audio->map_v_write = ioremap(audio->out_phys, BUFFER_SIZE);
 		if (IS_ERR(audio->map_v_write)) {
 			MM_ERR("could not map write buffers\n");
 			rc = -ENOMEM;
 			free_contiguous_memory_by_paddr(audio->out_phys);
 			goto evt_error;
 		}
-		audio->out_data = audio->map_v_write->vaddr;
+		audio->out_data = audio->map_v_write;
 		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
 				audio->out_phys, (int)audio->out_data);
 	}
@@ -1466,7 +1461,7 @@
 					qcelp_in_listener, (void *) audio);
 	if (rc) {
 		MM_ERR("failed to register device event listener\n");
-		msm_subsystem_unmap_buffer(audio->map_v_write);
+		iounmap(audio->map_v_write);
 		free_contiguous_memory_by_paddr(audio->out_phys);
 		goto evt_error;
 	}
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_wma.c b/arch/arm/mach-msm/qdsp5v2/audio_wma.c
index f29b078..79439e1 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_wma.c
@@ -45,7 +45,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5v2/qdsp5audppmsg.h>
 #include <mach/qdsp5v2/qdsp5audplaycmdi.h>
 #include <mach/qdsp5v2/qdsp5audplaymsg.h>
@@ -141,8 +140,8 @@
 	/* data allocated for various buffers */
 	char *data;
 	int32_t phys; /* physical address of write buffer */
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 
 	int mfield; /* meta field embedded in data */
 	int rflush; /* Read  flush */
@@ -1062,12 +1061,10 @@
 					rc = -ENOMEM;
 					break;
 				}
-				audio->map_v_read = msm_subsystem_map_buffer(
+				audio->map_v_read = ioremap(
 							audio->read_phys,
 							config.buffer_size *
-							config.buffer_count,
-							MSM_SUBSYSTEM_MAP_KADDR
-							, NULL, 0);
+							config.buffer_count);
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("read buf alloc fail\n");
 					rc = -ENOMEM;
@@ -1077,7 +1074,7 @@
 					uint8_t index;
 					uint32_t offset = 0;
 					audio->read_data =
-						audio->map_v_read->vaddr;
+						audio->map_v_read;
 					audio->buf_refresh = 0;
 					audio->pcm_buf_count =
 					    config.buffer_count;
@@ -1458,10 +1455,10 @@
 	audio->event_abort = 1;
 	wake_up(&audio->event_wait);
 	audwma_reset_event_queue(audio);
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	if (audio->read_data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->read_phys);
 	}
 	mutex_unlock(&audio->lock);
@@ -1652,10 +1649,7 @@
 		MM_DBG("pmemsz = %d\n", pmem_sz);
 		audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
 		if (audio->phys) {
-			audio->map_v_write = msm_subsystem_map_buffer(
-						audio->phys, pmem_sz,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+			audio->map_v_write = ioremap(audio->phys, pmem_sz);
 			if (IS_ERR(audio->map_v_write)) {
 				MM_ERR("could not allocate write buffers, \
 						freeing instance 0x%08x\n",
@@ -1666,7 +1660,7 @@
 				kfree(audio);
 				goto done;
 			}
-			audio->data = audio->map_v_write->vaddr;
+			audio->data = audio->map_v_write;
 			MM_DBG("write buf: phy addr 0x%08x kernel addr \
 				0x%08x\n", audio->phys, (int)audio->data);
 			break;
@@ -1772,7 +1766,7 @@
 event_err:
 	msm_adsp_put(audio->audplay);
 err:
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_wmapro.c b/arch/arm/mach-msm/qdsp5v2/audio_wmapro.c
index cf25359..6672ca0 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_wmapro.c
@@ -44,7 +44,6 @@
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
 #include <mach/qdsp5v2/qdsp5audppmsg.h>
 #include <mach/qdsp5v2/qdsp5audplaycmdi.h>
 #include <mach/qdsp5v2/qdsp5audplaymsg.h>
@@ -141,8 +140,8 @@
 	/* data allocated for various buffers */
 	char *data;
 	int32_t phys; /* physical address of write buffer */
-	struct msm_mapped_buffer *map_v_read;
-	struct msm_mapped_buffer *map_v_write;
+	void *map_v_read;
+	void *map_v_write;
 
 	int mfield; /* meta field embedded in data */
 	int rflush; /* Read  flush */
@@ -1074,12 +1073,10 @@
 					rc = -ENOMEM;
 					break;
 				}
-				audio->map_v_read = msm_subsystem_map_buffer(
+				audio->map_v_read = ioremap(
 							audio->read_phys,
 							config.buffer_size *
-							config.buffer_count,
-							MSM_SUBSYSTEM_MAP_KADDR
-							, NULL, 0);
+							config.buffer_count);
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("read buf map fail\n");
 					rc = -ENOMEM;
@@ -1089,7 +1086,7 @@
 					uint8_t index;
 					uint32_t offset = 0;
 					audio->read_data =
-						audio->map_v_read->vaddr;
+						audio->map_v_read;
 					audio->pcm_feedback = 1;
 					audio->buf_refresh = 0;
 					audio->pcm_buf_count =
@@ -1471,10 +1468,10 @@
 	audio->event_abort = 1;
 	wake_up(&audio->event_wait);
 	audwmapro_reset_event_queue(audio);
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	if (audio->read_data) {
-		msm_subsystem_unmap_buffer(audio->map_v_read);
+		iounmap(audio->map_v_read);
 		free_contiguous_memory_by_paddr(audio->read_phys);
 	}
 	mutex_unlock(&audio->lock);
@@ -1665,10 +1662,7 @@
 		MM_DBG("pmemsz = %d\n", pmem_sz);
 		audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
 		if (audio->phys) {
-			audio->map_v_write = msm_subsystem_map_buffer(
-						audio->phys, pmem_sz,
-						MSM_SUBSYSTEM_MAP_KADDR,
-						NULL, 0);
+			audio->map_v_write = ioremap(audio->phys, pmem_sz);
 			if (IS_ERR(audio->map_v_write)) {
 				MM_ERR("could not map write buffers, \
 						freeing instance 0x%08x\n",
@@ -1679,7 +1673,7 @@
 				kfree(audio);
 				goto done;
 			}
-			audio->data = audio->map_v_write->vaddr;
+			audio->data = audio->map_v_write;
 			MM_DBG("write buf: phy addr 0x%08x kernel addr \
 				0x%08x\n", audio->phys, (int)audio->data);
 			break;
@@ -1790,7 +1784,7 @@
 event_err:
 	msm_adsp_put(audio->audplay);
 err:
-	msm_subsystem_unmap_buffer(audio->map_v_write);
+	iounmap(audio->map_v_write);
 	free_contiguous_memory_by_paddr(audio->phys);
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
index ee32b80..8a0ba3e 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -16,6 +16,7 @@
  */
 
 #include <linux/msm_audio_aac.h>
+#include <mach/socinfo.h>
 #include "audio_utils_aio.h"
 
 #define AUDIO_AAC_DUAL_MONO_INVALID -1
@@ -122,6 +123,14 @@
 			pr_err("cmd media format block failed\n");
 			break;
 		}
+		if (!cpu_is_msm8x60()) {
+			rc = q6asm_set_encdec_chan_map(audio->ac, 2);
+			if (rc < 0) {
+				pr_err("%s: cmd set encdec_chan_map failed\n",
+					__func__);
+				break;
+			}
+		}
 		rc = audio_aio_enable(audio);
 		audio->eos_rsp = 0;
 		audio->eos_flag = 0;
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c b/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c
index eb394a3..f75af16 100644
--- a/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -344,7 +344,7 @@
 	mutex_init(&drv->dev_lock);
 	drv->ref_cnt = 0;
 
-	drv->ecodec_clk = clk_get(NULL, "pcm_clk");
+	drv->ecodec_clk = clk_get_sys(NULL, "pcm_clk");
 	if (IS_ERR(drv->ecodec_clk)) {
 		pr_err("%s: could not get pcm_clk\n", __func__);
 		return PTR_ERR(drv->ecodec_clk);
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
index 216d982..ea935cc 100644
--- a/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -308,7 +308,7 @@
 	}
 	msm_snddev_rx_mclk_request();
 
-	drv->rx_osrclk = clk_get(0, "i2s_spkr_osr_clk");
+	drv->rx_osrclk = clk_get_sys(NULL, "i2s_spkr_osr_clk");
 	if (IS_ERR(drv->rx_osrclk))
 		pr_err("%s master clock Error\n", __func__);
 
@@ -320,7 +320,7 @@
 	}
 
 	clk_enable(drv->rx_osrclk);
-	drv->rx_bitclk = clk_get(0, "i2s_spkr_bit_clk");
+	drv->rx_bitclk = clk_get_sys(NULL, "i2s_spkr_bit_clk");
 	if (IS_ERR(drv->rx_bitclk))
 		pr_err("%s clock Error\n", __func__);
 
@@ -437,7 +437,7 @@
 
 	msm_snddev_tx_mclk_request();
 
-	drv->tx_osrclk = clk_get(0, "i2s_mic_osr_clk");
+	drv->tx_osrclk = clk_get_sys(NULL, "i2s_mic_osr_clk");
 	if (IS_ERR(drv->tx_osrclk))
 		pr_err("%s master clock Error\n", __func__);
 
@@ -449,7 +449,7 @@
 	}
 
 	clk_enable(drv->tx_osrclk);
-	drv->tx_bitclk = clk_get(0, "i2s_mic_bit_clk");
+	drv->tx_bitclk = clk_get_sys(NULL, "i2s_mic_bit_clk");
 	if (IS_ERR(drv->tx_bitclk))
 		pr_err("%s clock Error\n", __func__);
 
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c b/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c
index a99b600..75a7411 100644
--- a/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -184,7 +184,7 @@
 	}
 
 	/* set up osr clk */
-	drv->tx_osrclk = clk_get(0, "mi2s_osr_clk");
+	drv->tx_osrclk = clk_get_sys(NULL, "mi2s_osr_clk");
 	if (IS_ERR(drv->tx_osrclk))
 		pr_err("%s master clock Error\n", __func__);
 
@@ -197,7 +197,7 @@
 	clk_enable(drv->tx_osrclk);
 
 	/* set up bit clk */
-	drv->tx_bitclk = clk_get(0, "mi2s_bit_clk");
+	drv->tx_bitclk = clk_get_sys(NULL, "mi2s_bit_clk");
 	if (IS_ERR(drv->tx_bitclk))
 		pr_err("%s clock Error\n", __func__);
 
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
index 1182a4d..25e10a6 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
@@ -21,7 +21,7 @@
 #include "q6usm.h"
 
 /* The driver version*/
-#define DRV_VERSION "1.1"
+#define DRV_VERSION "1.2"
 
 #define SESSION_MAX 0x02 /* aDSP:USM limit */
 
@@ -38,7 +38,7 @@
 #define WRITEDONE_IDX_STATUS    0
 
 /* Standard timeout in the asynchronous ops */
-#define Q6USM_TIMEOUT_JIFFIES	(3*HZ) /* 3 sec */
+#define Q6USM_TIMEOUT_JIFFIES	(1*HZ) /* 1 sec */
 
 static DEFINE_MUTEX(session_lock);
 
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index b4a0a7f..614339b 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -27,10 +27,10 @@
 #include "usfcdev.h"
 
 /* The driver version*/
-#define DRV_VERSION "1.3"
+#define DRV_VERSION "1.3.1"
 
 /* Standard timeout in the asynchronous ops */
-#define USF_TIMEOUT_JIFFIES (3*HZ) /* 3 sec */
+#define USF_TIMEOUT_JIFFIES (1*HZ) /* 1 sec */
 
 /* Undefined USF device */
 #define USF_UNDEF_DEV_ID 0xffff
@@ -735,24 +735,27 @@
 
 	/* Get US detection result */
 	if (detect_info.detect_timeout == USF_INFINITIVE_TIMEOUT) {
-		wait_event(usf_xx->wait,
-				(usf_xx->us_detect_type !=
-				 USF_US_DETECT_UNDEF));
+		rc = wait_event_interruptible(usf_xx->wait,
+						(usf_xx->us_detect_type !=
+						USF_US_DETECT_UNDEF));
 	} else {
 		if (detect_info.detect_timeout == USF_DEFAULT_TIMEOUT)
 			timeout = USF_TIMEOUT_JIFFIES;
 		else
 			timeout = detect_info.detect_timeout * HZ;
-
-		rc = wait_event_timeout(usf_xx->wait,
+	}
+	rc = wait_event_interruptible_timeout(usf_xx->wait,
 					(usf_xx->us_detect_type !=
 					 USF_US_DETECT_UNDEF),
 					timeout);
-		/* In the case of timeout, "no US" is assumed */
+	/* In the case of timeout, "no US" is assumed */
+	if (rc < 0) {
+		pr_err("%s: Getting US detection failed rc[%d]\n",
+		       __func__, rc);
+		return rc;
 	}
 
 	usf->usf_rx.us_detect_type = usf->usf_tx.us_detect_type;
-
 	detect_info.is_us = (usf_xx->us_detect_type == USF_US_DETECT_YES);
 	rc = copy_to_user((void __user *)arg,
 			  &detect_info,
@@ -913,7 +916,7 @@
 
 	/* Get data ready regions */
 	if (upd_tx_info.timeout == USF_INFINITIVE_TIMEOUT) {
-		wait_event(usf_xx->wait,
+		rc = wait_event_interruptible(usf_xx->wait,
 			   (usf_xx->prev_region !=
 			    usf_xx->new_region) ||
 			   (usf_xx->usf_state !=
@@ -922,18 +925,26 @@
 		if (upd_tx_info.timeout == USF_NO_WAIT_TIMEOUT)
 			rc = (usf_xx->prev_region != usf_xx->new_region);
 		else {
-			if (upd_tx_info.timeout == USF_DEFAULT_TIMEOUT)
-				timeout = USF_TIMEOUT_JIFFIES;
-			else
-				timeout = upd_tx_info.timeout * HZ;
-
 			prev_jiffies = jiffies;
-			rc = wait_event_timeout(usf_xx->wait,
+			if (upd_tx_info.timeout == USF_DEFAULT_TIMEOUT) {
+				timeout = USF_TIMEOUT_JIFFIES;
+				rc = wait_event_timeout(
+						usf_xx->wait,
 						(usf_xx->prev_region !=
 						 usf_xx->new_region) ||
 						(usf_xx->usf_state !=
 						 USF_WORK_STATE),
 						timeout);
+			} else {
+				timeout = upd_tx_info.timeout * HZ;
+				rc = wait_event_interruptible_timeout(
+						usf_xx->wait,
+						(usf_xx->prev_region !=
+						 usf_xx->new_region) ||
+						(usf_xx->usf_state !=
+						 USF_WORK_STATE),
+						timeout);
+			}
 		}
 		if (!rc) {
 			pr_debug("%s: timeout. prev_j=%lu; j=%lu\n",
@@ -952,9 +963,11 @@
 		}
 	}
 
-	if (usf_xx->usf_state != USF_WORK_STATE) {
-		pr_err("%s: TX device is in not work state[%d]\n",
-		       __func__, usf_xx->usf_state);
+	if ((usf_xx->usf_state != USF_WORK_STATE) ||
+	    (rc == -ERESTARTSYS)) {
+		pr_err("%s: Getting ready region failed "
+			"work state[%d]; rc[%d]\n",
+		       __func__, usf_xx->usf_state, rc);
 		return -EINTR;
 	}
 
diff --git a/arch/arm/mach-msm/qdss-etb.c b/arch/arm/mach-msm/qdss-etb.c
index 96eba26..7837af0 100644
--- a/arch/arm/mach-msm/qdss-etb.c
+++ b/arch/arm/mach-msm/qdss-etb.c
@@ -69,7 +69,7 @@
 	void __iomem	*base;
 	bool		enabled;
 	bool		reading;
-	struct mutex	mutex;
+	spinlock_t	spinlock;
 	atomic_t	in_use;
 	struct device	*dev;
 	struct kobject	*kobj;
@@ -100,11 +100,13 @@
 
 void etb_enable(void)
 {
-	mutex_lock(&etb.mutex);
+	unsigned long flags;
+
+	spin_lock_irqsave(&etb.spinlock, flags);
 	__etb_enable();
 	etb.enabled = true;
 	dev_info(etb.dev, "ETB enabled\n");
-	mutex_unlock(&etb.mutex);
+	spin_unlock_irqrestore(&etb.spinlock, flags);
 }
 
 static void __etb_disable(void)
@@ -137,11 +139,13 @@
 
 void etb_disable(void)
 {
-	mutex_lock(&etb.mutex);
+	unsigned long flags;
+
+	spin_lock_irqsave(&etb.spinlock, flags);
 	__etb_disable();
 	etb.enabled = false;
 	dev_info(etb.dev, "ETB disabled\n");
-	mutex_unlock(&etb.mutex);
+	spin_unlock_irqrestore(&etb.spinlock, flags);
 }
 
 static void __etb_dump(void)
@@ -200,7 +204,9 @@
 
 void etb_dump(void)
 {
-	mutex_lock(&etb.mutex);
+	unsigned long flags;
+
+	spin_lock_irqsave(&etb.spinlock, flags);
 	if (etb.enabled) {
 		__etb_disable();
 		__etb_dump();
@@ -208,7 +214,7 @@
 
 		dev_info(etb.dev, "ETB dumped\n");
 	}
-	mutex_unlock(&etb.mutex);
+	spin_unlock_irqrestore(&etb.spinlock, flags);
 }
 
 static int etb_open(struct inode *inode, struct file *file)
@@ -293,7 +299,7 @@
 }
 ETB_ATTR(trigger_cntr);
 
-static int __init etb_sysfs_init(void)
+static int __devinit etb_sysfs_init(void)
 {
 	int ret;
 
@@ -318,7 +324,7 @@
 	return ret;
 }
 
-static void __exit etb_sysfs_exit(void)
+static void __devexit etb_sysfs_exit(void)
 {
 	sysfs_remove_file(etb.kobj, &trigger_cntr_attr.attr);
 	kobject_put(etb.kobj);
@@ -343,7 +349,7 @@
 
 	etb.dev = &pdev->dev;
 
-	mutex_init(&etb.mutex);
+	spin_lock_init(&etb.spinlock);
 
 	ret = misc_register(&etb_misc);
 	if (ret)
@@ -363,7 +369,6 @@
 err_alloc:
 	misc_deregister(&etb_misc);
 err_misc:
-	mutex_destroy(&etb.mutex);
 	iounmap(etb.base);
 err_ioremap:
 err_res:
@@ -378,7 +383,6 @@
 	etb_sysfs_exit();
 	kfree(etb.buf);
 	misc_deregister(&etb_misc);
-	mutex_destroy(&etb.mutex);
 	iounmap(etb.base);
 
 	return 0;
diff --git a/arch/arm/mach-msm/qdss-etm.c b/arch/arm/mach-msm/qdss-etm.c
index 251db45..61f1c1b 100644
--- a/arch/arm/mach-msm/qdss-etm.c
+++ b/arch/arm/mach-msm/qdss-etm.c
@@ -1120,7 +1120,7 @@
 	.attrs = etm_attrs,
 };
 
-static int __init etm_sysfs_init(void)
+static int __devinit etm_sysfs_init(void)
 {
 	int ret;
 
@@ -1148,14 +1148,14 @@
 	return ret;
 }
 
-static void __exit etm_sysfs_exit(void)
+static void __devexit etm_sysfs_exit(void)
 {
 	sysfs_remove_group(etm.kobj, &etm_attr_grp);
 	sysfs_remove_file(etm.kobj, &enabled_attr.attr);
 	kobject_put(etm.kobj);
 }
 
-static bool __init etm_arch_supported(uint8_t arch)
+static bool __devinit etm_arch_supported(uint8_t arch)
 {
 	switch (arch) {
 	case PFT_ARCH_V1_1:
@@ -1166,7 +1166,7 @@
 	return true;
 }
 
-static int __init etm_arch_init(void)
+static int __devinit etm_arch_init(void)
 {
 	int ret, i;
 	/* use cpu 0 for setup */
diff --git a/arch/arm/mach-msm/qdss-funnel.c b/arch/arm/mach-msm/qdss-funnel.c
index 2d80603..52eb2b6 100644
--- a/arch/arm/mach-msm/qdss-funnel.c
+++ b/arch/arm/mach-msm/qdss-funnel.c
@@ -134,7 +134,7 @@
 }
 FUNNEL_ATTR(priority);
 
-static int __init funnel_sysfs_init(void)
+static int __devinit funnel_sysfs_init(void)
 {
 	int ret;
 
@@ -159,7 +159,7 @@
 	return ret;
 }
 
-static void __exit funnel_sysfs_exit(void)
+static void __devexit funnel_sysfs_exit(void)
 {
 	sysfs_remove_file(funnel.kobj, &priority_attr.attr);
 	kobject_put(funnel.kobj);
diff --git a/arch/arm/mach-msm/qdss.c b/arch/arm/mach-msm/qdss.c
index cfe65ad..fd1fc2b 100644
--- a/arch/arm/mach-msm/qdss.c
+++ b/arch/arm/mach-msm/qdss.c
@@ -175,6 +175,26 @@
 EXPORT_SYMBOL(qdss_disable);
 
 /**
+ * qdss_disable_sink - force disable the current qdss sink(s)
+ *
+ * Force disable the current qdss sink(s) to stop the sink from accepting any
+ * trace generated subsequent to this call. This function should only be used
+ * as a way to stop the sink from getting polluted with trace data that is
+ * uninteresting after an event of interest has occured.
+ *
+ * CONTEXT:
+ * Can be called from atomic or non-atomic context.
+ */
+void qdss_disable_sink(void)
+{
+	if ((qdss.pdata)->afamily) {
+		etb_dump();
+		etb_disable();
+	}
+}
+EXPORT_SYMBOL(qdss_disable_sink);
+
+/**
  * qdss_clk_enable - enable qdss clocks
  *
  * Enables qdss clocks via RPM if they aren't already enabled, otherwise
@@ -270,7 +290,7 @@
 }
 QDSS_ATTR(max_clk);
 
-static void __init qdss_add_sources(struct qdss_source *srcs, size_t num)
+static void __devinit qdss_add_sources(struct qdss_source *srcs, size_t num)
 {
 	mutex_lock(&qdss.sources_mutex);
 	while (num--) {
@@ -302,7 +322,7 @@
 	return ret;
 }
 
-static void __exit qdss_sysfs_exit(void)
+static void __devexit qdss_sysfs_exit(void)
 {
 	sysfs_remove_file(qdss.modulekobj, &max_clk_attr.attr);
 }
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index 06e3d37..e45e2c4 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -232,21 +232,10 @@
 	printk(KERN_ERR "Restarting has failed\n");
 }
 
-static int __init msm_restart_init(void)
+static int __init msm_pmic_restart_init(void)
 {
 	int rc;
 
-#ifdef CONFIG_MSM_DLOAD_MODE
-	atomic_notifier_chain_register(&panic_notifier_list, &panic_blk);
-	dload_mode_addr = MSM_IMEM_BASE + DLOAD_MODE_ADDR;
-
-	/* Reset detection is switched on below.*/
-	set_dload_mode(1);
-#endif
-	msm_tmr0_base = msm_timer_get_timer0_base();
-	restart_reason = MSM_IMEM_BASE + RESTART_REASON_ADDR;
-	pm_power_off = msm_power_off;
-
 	if (pmic_reset_irq != 0) {
 		rc = request_any_context_irq(pmic_reset_irq,
 					resout_irq_handler, IRQF_TRIGGER_HIGH,
@@ -260,4 +249,19 @@
 	return 0;
 }
 
-late_initcall(msm_restart_init);
+late_initcall(msm_pmic_restart_init);
+
+static int __init msm_restart_init(void)
+{
+#ifdef CONFIG_MSM_DLOAD_MODE
+	atomic_notifier_chain_register(&panic_notifier_list, &panic_blk);
+	dload_mode_addr = MSM_IMEM_BASE + DLOAD_MODE_ADDR;
+	set_dload_mode(download_mode);
+#endif
+	msm_tmr0_base = msm_timer_get_timer0_base();
+	restart_reason = MSM_IMEM_BASE + RESTART_REASON_ADDR;
+	pm_power_off = msm_power_off;
+
+	return 0;
+}
+early_initcall(msm_restart_init);
diff --git a/arch/arm/mach-msm/rpc_server_handset.c b/arch/arm/mach-msm/rpc_server_handset.c
index b011aeb..6d173fb 100644
--- a/arch/arm/mach-msm/rpc_server_handset.c
+++ b/arch/arm/mach-msm/rpc_server_handset.c
@@ -1,6 +1,6 @@
 /* arch/arm/mach-msm/rpc_server_handset.c
  *
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2010,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
@@ -517,7 +517,7 @@
 	return 0;
 }
 
-static int __init hs_rpc_cb_init(void)
+static int __devinit hs_rpc_cb_init(void)
 {
 	int rc = 0, i, num_vers;
 
diff --git a/arch/arm/mach-msm/scm-boot.h b/arch/arm/mach-msm/scm-boot.h
index b14c968..221ffca 100644
--- a/arch/arm/mach-msm/scm-boot.h
+++ b/arch/arm/mach-msm/scm-boot.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010, 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
@@ -21,6 +21,10 @@
 #define SCM_FLAG_WARMBOOT_CPU2		0x10
 #define SCM_FLAG_WARMBOOT_CPU3		0x40
 
+#ifdef CONFIG_MSM_SCM
 int scm_set_boot_addr(void *addr, int flags);
+#else
+static inline int scm_set_boot_addr(void *addr, int flags) { return 0; }
+#endif
 
 #endif
diff --git a/arch/arm/mach-msm/sdio_al_dloader.c b/arch/arm/mach-msm/sdio_al_dloader.c
index 77a06a3..74b8478 100644
--- a/arch/arm/mach-msm/sdio_al_dloader.c
+++ b/arch/arm/mach-msm/sdio_al_dloader.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -530,7 +530,7 @@
 	curr_index++;
 }
 
-static int __init bootloader_debugfs_init(void)
+static int bootloader_debugfs_init(void)
 {
 	/* /sys/kernel/debug/bootloader there will be dld_arr file */
 	root = debugfs_create_dir("bootloader", NULL);
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 6b42325..ddc3a8d 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -2207,6 +2207,20 @@
 }
 EXPORT_SYMBOL(smd_tiocmset);
 
+int smd_is_pkt_avail(smd_channel_t *ch)
+{
+	if (!ch || !ch->is_pkt_ch)
+		return -EINVAL;
+
+	if (ch->current_packet)
+		return 1;
+
+	update_packet_state(ch);
+
+	return ch->current_packet ? 1 : 0;
+}
+EXPORT_SYMBOL(smd_is_pkt_avail);
+
 
 /* -------------------------------------------------------------------------- */
 
@@ -3469,8 +3483,14 @@
 	},
 };
 
-static int __init msm_smd_init(void)
+int __init msm_smd_init(void)
 {
+	static bool registered;
+
+	if (registered)
+		return 0;
+
+	registered = true;
 	return platform_driver_register(&msm_smd_driver);
 }
 
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 3faeb37..d811f71 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -247,6 +247,14 @@
 	[128] = MSM_CPU_8625,
 	[129] = MSM_CPU_8625,
 
+	/* 9625 IDs */
+	[130] = MSM_CPU_9625,
+
+	/* 7x25AB IDs */
+	[131] = MSM_CPU_7X25AB,
+	[132] = MSM_CPU_7X25AB,
+	[133] = MSM_CPU_7X25AB,
+
 	/* Uninitialized IDs are not known to run Linux.
 	   MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
 	   considered as unknown CPU. */
@@ -616,6 +624,10 @@
 		dummy_socinfo.id = 126;
 		strlcpy(dummy_socinfo.build_id, "copper - ",
 			sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_msm9625()) {
+		dummy_socinfo.id = 130;
+		strlcpy(dummy_socinfo.build_id, "msm9625 - ",
+			sizeof(dummy_socinfo.build_id));
 	} else if (machine_is_msm8625_rumi3())
 		dummy_socinfo.id = 127;
 	strlcat(dummy_socinfo.build_id, "Dummy socinfo",
diff --git a/arch/arm/mach-msm/spm-v2.c b/arch/arm/mach-msm/spm-v2.c
index 2a6294f..b6d5324 100644
--- a/arch/arm/mach-msm/spm-v2.c
+++ b/arch/arm/mach-msm/spm-v2.c
@@ -21,6 +21,14 @@
 
 #include "spm_driver.h"
 
+#define MSM_SPM_PMIC_STATE_IDLE  0
+
+#define SAW2_V1_VER_REG 0x04
+#define SAW2_V2_VER_REG 0xfd0
+
+#define SAW2_MAJOR_2 2
+
+
 enum {
 	MSM_SPM_DEBUG_SHADOW = 1U << 0,
 	MSM_SPM_DEBUG_VCTL = 1U << 1,
@@ -31,35 +39,95 @@
 	debug_mask, msm_spm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
 );
 
-#define MSM_SPM_PMIC_STATE_IDLE  0
 
+static uint32_t msm_spm_reg_offsets_v1[MSM_SPM_REG_NR] = {
+	[MSM_SPM_REG_SAW2_SECURE]		= 0x00,
+	[MSM_SPM_REG_SAW2_ID]			= 0x04,
+	[MSM_SPM_REG_SAW2_CFG]			= 0x08,
+	[MSM_SPM_REG_SAW2_STS0]			= 0x0C,
+	[MSM_SPM_REG_SAW2_STS1]			= 0x10,
+	[MSM_SPM_REG_SAW2_VCTL]			= 0x14,
+	[MSM_SPM_REG_SAW2_AVS_CTL]		= 0x18,
+	[MSM_SPM_REG_SAW2_AVS_HYSTERESIS]	= 0x1C,
+	[MSM_SPM_REG_SAW2_SPM_CTL]		= 0x20,
+	[MSM_SPM_REG_SAW2_PMIC_DLY]		= 0x24,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_0]		= 0x28,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_1]		= 0x2C,
+	[MSM_SPM_REG_SAW2_RST]			= 0x30,
+	[MSM_SPM_REG_SAW2_SEQ_ENTRY]		= 0x80,
+};
 
-static uint32_t msm_spm_reg_offsets[MSM_SPM_REG_NR] = {
-	[MSM_SPM_REG_SAW2_SECURE] = 0x00,
-
-	[MSM_SPM_REG_SAW2_ID] = 0x04,
-	[MSM_SPM_REG_SAW2_CFG] = 0x08,
-	[MSM_SPM_REG_SAW2_STS0] = 0x0C,
-	[MSM_SPM_REG_SAW2_STS1] = 0x10,
-
-	[MSM_SPM_REG_SAW2_VCTL] = 0x14,
-
-	[MSM_SPM_REG_SAW2_AVS_CTL] = 0x18,
-	[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x1C,
-
-	[MSM_SPM_REG_SAW2_SPM_CTL] = 0x20,
-	[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x24,
-	[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x28,
-	[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x2C,
-	[MSM_SPM_REG_SAW2_RST] = 0x30,
-
-	[MSM_SPM_REG_SAW2_SEQ_ENTRY] = 0x80,
+static uint32_t msm_spm_reg_offsets_v2[MSM_SPM_REG_NR] = {
+	[MSM_SPM_REG_SAW2_SECURE]		= 0x00,
+	[MSM_SPM_REG_SAW2_ID]			= 0x04,
+	[MSM_SPM_REG_SAW2_CFG]			= 0x08,
+	[MSM_SPM_REG_SAW2_SPM_STS]		= 0x0C,
+	[MSM_SPM_REG_SAW2_AVS_STS]		= 0x10,
+	[MSM_SPM_REG_SAW2_PMIC_STS]		= 0x14,
+	[MSM_SPM_REG_SAW2_RST]			= 0x18,
+	[MSM_SPM_REG_SAW2_VCTL]			= 0x1C,
+	[MSM_SPM_REG_SAW2_AVS_CTL]		= 0x20,
+	[MSM_SPM_REG_SAW2_AVS_LIMIT]		= 0x24,
+	[MSM_SPM_REG_SAW2_AVS_DLY]		= 0x28,
+	[MSM_SPM_REG_SAW2_AVS_HYSTERESIS]	= 0x2C,
+	[MSM_SPM_REG_SAW2_SPM_CTL]		= 0x30,
+	[MSM_SPM_REG_SAW2_SPM_DLY]		= 0x34,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_0]		= 0x40,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_1]		= 0x44,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_2]		= 0x48,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_3]		= 0x4C,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_4]		= 0x50,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_5]		= 0x54,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_6]		= 0x58,
+	[MSM_SPM_REG_SAW2_PMIC_DATA_7]		= 0x5C,
+	[MSM_SPM_REG_SAW2_SEQ_ENTRY]		= 0x80,
+	[MSM_SPM_REG_SAW2_VERSION]		= 0xFD0,
 };
 
 /******************************************************************************
  * Internal helper functions
  *****************************************************************************/
 
+static inline uint32_t msm_spm_drv_get_num_spm_entry(
+		struct msm_spm_driver_data *dev)
+{
+	return 32;
+}
+
+static void msm_spm_drv_flush_shadow(struct msm_spm_driver_data *dev,
+		unsigned int reg_index)
+{
+	__raw_writel(dev->reg_shadow[reg_index],
+		dev->reg_base_addr + dev->reg_offsets[reg_index]);
+}
+
+static void msm_spm_drv_load_shadow(struct msm_spm_driver_data *dev,
+		unsigned int reg_index)
+{
+	dev->reg_shadow[reg_index] =
+		__raw_readl(dev->reg_base_addr +
+				dev->reg_offsets[reg_index]);
+}
+
+static inline void msm_spm_drv_set_start_addr(
+		struct msm_spm_driver_data *dev, uint32_t addr)
+{
+	addr &= 0x7F;
+	addr <<= 4;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] &= 0xFFFFF80F;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] |= addr;
+}
+
+static inline bool msm_spm_pmic_arb_present(struct msm_spm_driver_data *dev)
+{
+	msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_ID);
+
+	if (dev->major == SAW2_MAJOR_2)
+		return (dev->reg_shadow[MSM_SPM_REG_SAW2_ID] >> 2) & 0x1;
+	else
+		return (dev->reg_shadow[MSM_SPM_REG_SAW2_ID] >> 18) & 0x1;
+}
+
 static inline void msm_spm_drv_set_vctl(struct msm_spm_driver_data *dev,
 		uint32_t vlevel)
 {
@@ -73,58 +141,81 @@
 	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] |= (vlevel & 0x3F);
 }
 
-static void msm_spm_drv_flush_shadow(struct msm_spm_driver_data *dev,
-		unsigned int reg_index)
+static inline void msm_spm_drv_set_vctl2(struct msm_spm_driver_data *dev,
+		uint32_t vlevel)
 {
-	__raw_writel(dev->reg_shadow[reg_index],
-		dev->reg_base_addr + msm_spm_reg_offsets[reg_index]);
+	unsigned int pmic_data = 0;
+
+	pmic_data |= vlevel;
+	pmic_data |= (dev->vctl_port & 0x7) << 16;
+
+	dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] &= ~0x700FF;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] |= pmic_data;
+
+	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] &= ~0x700FF;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] |= pmic_data;
 }
 
-static void msm_spm_drv_load_shadow(struct msm_spm_driver_data *dev,
-		unsigned int reg_index)
+static inline void msm_spm_drv_apcs_set_vctl(struct msm_spm_driver_data *dev,
+		unsigned int vlevel)
 {
-	dev->reg_shadow[reg_index] =
-		__raw_readl(dev->reg_base_addr +
-				msm_spm_reg_offsets[reg_index]);
-}
-
-static inline uint32_t msm_spm_drv_get_awake_vlevel(
-		struct msm_spm_driver_data *dev)
-{
-	return dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] & 0xFF;
+	if (dev->major == SAW2_MAJOR_2)
+		return msm_spm_drv_set_vctl2(dev, vlevel);
+	else
+		return msm_spm_drv_set_vctl(dev, vlevel);
 }
 
 static inline uint32_t msm_spm_drv_get_sts_pmic_state(
 		struct msm_spm_driver_data *dev)
 {
-	return (dev->reg_shadow[MSM_SPM_REG_SAW2_STS0] >> 10) & 0x03;
+	if (dev->major == SAW2_MAJOR_2) {
+		msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_PMIC_STS);
+		return (dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_STS] >> 16) &
+				0x03;
+	} else {
+		msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_STS0);
+		return (dev->reg_shadow[MSM_SPM_REG_SAW2_STS0] >> 10) & 0x03;
+	}
 }
 
 static inline uint32_t msm_spm_drv_get_sts_curr_pmic_data(
 		struct msm_spm_driver_data *dev)
 {
-	return dev->reg_shadow[MSM_SPM_REG_SAW2_STS1] & 0xFF;
+	if (dev->major == SAW2_MAJOR_2) {
+		msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_PMIC_STS);
+		return dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_STS] & 0xFF;
+	} else {
+		msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_STS1);
+		return dev->reg_shadow[MSM_SPM_REG_SAW2_STS1] & 0xFF;
+	}
 }
 
-static inline uint32_t msm_spm_drv_get_num_spm_entry(
-		struct msm_spm_driver_data *dev)
+static inline uint32_t msm_spm_drv_get_saw2_ver(struct msm_spm_driver_data *dev,
+		uint32_t *major, uint32_t *minor)
 {
-	return 32;
-}
+	int ret = -ENODEV;
+	uint32_t val = 0;
 
-static inline void msm_spm_drv_set_start_addr(
-		struct msm_spm_driver_data *dev, uint32_t addr)
-{
-	addr &= 0x7F;
-	addr <<= 4;
-	dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] &= 0xFFFFF80F;
-	dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] |= addr;
-}
+	msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_VERSION);
+	val = dev->reg_shadow[MSM_SPM_REG_SAW2_VERSION];
 
+	if (dev->ver_reg == SAW2_V2_VER_REG) {
+		*major = (val >> 28) & 0xF;
+		*minor = (val >> 16) & 0xFFF;
+		ret = 0;
+	} else if (dev->ver_reg == SAW2_V1_VER_REG) {
+		*major = (val >> 4) & 0xF;
+		*minor = val & 0xF;
+		ret = 0;
+	}
+
+	return ret;
+}
 
 /******************************************************************************
  * Public functions
  *****************************************************************************/
+
 inline int msm_spm_drv_set_spm_enable(
 		struct msm_spm_driver_data *dev, bool enable)
 {
@@ -156,48 +247,42 @@
 	for (i = 0; i < num_spm_entry; i++) {
 		__raw_writel(dev->reg_seq_entry_shadow[i],
 			dev->reg_base_addr
-			+ msm_spm_reg_offsets[MSM_SPM_REG_SAW2_SEQ_ENTRY]
+			+ dev->reg_offsets[MSM_SPM_REG_SAW2_SEQ_ENTRY]
 			+ 4 * i);
 	}
 	mb();
 }
 
 int msm_spm_drv_write_seq_data(struct msm_spm_driver_data *dev,
-		uint8_t *cmd, uint32_t offset)
+		uint8_t *cmd, uint32_t *offset)
 {
-	uint32_t offset_w = offset / 4;
-	int ret = 0;
+	uint32_t cmd_w;
+	uint32_t offset_w = *offset / 4;
+	uint8_t last_cmd;
 
-	if (!cmd || !dev) {
-		__WARN();
-		goto failed_write_seq_data;
-	};
+	if (!cmd)
+		return -EINVAL;
 
 	while (1) {
 		int i;
-		uint32_t cmd_w = 0;
-		uint8_t last_cmd = 0;
+		cmd_w = 0;
+		last_cmd = 0;
+		cmd_w = dev->reg_seq_entry_shadow[offset_w];
 
-		for (i = 0; i < 4; i++) {
-			last_cmd = (last_cmd == 0x0f) ? 0x0f : *(cmd + i);
-			cmd_w |= last_cmd << (i * 8);
-			ret++;
+		for (i = (*offset % 4) ; i < 4; i++) {
+			last_cmd = *(cmd++);
+			cmd_w |=  last_cmd << (i * 8);
+			(*offset)++;
+			if (last_cmd == 0x0f)
+				break;
 		}
 
-		if (offset_w >=  msm_spm_drv_get_num_spm_entry(dev)) {
-			__WARN();
-			goto failed_write_seq_data;
-		}
-
-		cmd += i;
 		dev->reg_seq_entry_shadow[offset_w++] = cmd_w;
 		if (last_cmd == 0x0f)
 			break;
 	}
-	return ret;
 
-failed_write_seq_data:
-	 return -EINVAL;
+	return 0;
 }
 
 int msm_spm_drv_set_low_power_mode(struct msm_spm_driver_data *dev,
@@ -218,7 +303,7 @@
 		int i;
 		for (i = 0; i < MSM_SPM_REG_NR; i++)
 			pr_info("%s: reg %02x = 0x%08x\n", __func__,
-				msm_spm_reg_offsets[i], dev->reg_shadow[i]);
+				dev->reg_offsets[i], dev->reg_shadow[i]);
 	}
 
 	return 0;
@@ -231,11 +316,14 @@
 	if (!dev)
 		return -EINVAL;
 
+	if (!msm_spm_pmic_arb_present(dev))
+		return -ENOSYS;
+
 	if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
 		pr_info("%s: requesting vlevel 0x%x\n",
 			__func__, vlevel);
 
-	msm_spm_drv_set_vctl(dev, vlevel);
+	msm_spm_drv_apcs_set_vctl(dev, vlevel);
 	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_VCTL);
 	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_PMIC_DATA_0);
 	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_PMIC_DATA_1);
@@ -243,7 +331,6 @@
 
 	/* Wait for PMIC state to return to idle or until timeout */
 	timeout_us = dev->vctl_timeout_us;
-	msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_STS0);
 	while (msm_spm_drv_get_sts_pmic_state(dev) != MSM_SPM_PMIC_STATE_IDLE) {
 		if (!timeout_us)
 			goto set_vdd_bail;
@@ -255,11 +342,8 @@
 			udelay(timeout_us);
 			timeout_us = 0;
 		}
-		msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_STS0);
 	}
 
-	msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_STS1);
-
 	if (msm_spm_drv_get_sts_curr_pmic_data(dev) != vlevel)
 		goto set_vdd_bail;
 
@@ -275,6 +359,54 @@
 	return -EIO;
 }
 
+int msm_spm_drv_set_phase(struct msm_spm_driver_data *dev,
+		unsigned int phase_cnt)
+{
+	unsigned int pmic_data = 0;
+	unsigned int timeout_us = 0;
+
+	if (dev->major != SAW2_MAJOR_2)
+		return -ENODEV;
+
+	pmic_data |= phase_cnt & 0xFF;
+	pmic_data |= (dev->phase_port & 0x7) << 16;
+
+	dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] &= ~0x700FF;
+	dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] |= pmic_data;
+	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_VCTL);
+	mb();
+
+	/* Wait for PMIC state to return to idle or until timeout */
+	timeout_us = dev->vctl_timeout_us;
+	while (msm_spm_drv_get_sts_pmic_state(dev) != MSM_SPM_PMIC_STATE_IDLE) {
+		if (!timeout_us)
+			goto set_phase_bail;
+
+		if (timeout_us > 10) {
+			udelay(10);
+			timeout_us -= 10;
+		} else {
+			udelay(timeout_us);
+			timeout_us = 0;
+		}
+	}
+
+	if (msm_spm_drv_get_sts_curr_pmic_data(dev) != phase_cnt)
+		goto set_phase_bail;
+
+	if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
+		pr_info("%s: done, remaining timeout %uus\n",
+			__func__, timeout_us);
+
+	return 0;
+
+set_phase_bail:
+	pr_err("%s: failed, remaining timeout %uus, phase count %d\n",
+	       __func__, timeout_us, msm_spm_drv_get_sts_curr_pmic_data(dev));
+	return -EIO;
+
+}
+
 void msm_spm_drv_reinit(struct msm_spm_driver_data *dev)
 {
 	int i;
@@ -286,15 +418,21 @@
 	mb();
 }
 
-int __init msm_spm_drv_init(struct msm_spm_driver_data *dev,
+int __devinit msm_spm_drv_init(struct msm_spm_driver_data *dev,
 		struct msm_spm_platform_data *data)
 {
-
 	int i;
 	int num_spm_entry;
 
 	BUG_ON(!dev || !data);
 
+	if (dev->ver_reg == SAW2_V2_VER_REG)
+		dev->reg_offsets = msm_spm_reg_offsets_v2;
+	else
+		dev->reg_offsets = msm_spm_reg_offsets_v1;
+
+	dev->vctl_port = data->vctl_port;
+	dev->phase_port = data->phase_port;
 	dev->reg_base_addr = data->reg_base_addr;
 	memcpy(dev->reg_shadow, data->reg_init_values,
 			sizeof(data->reg_init_values));
@@ -314,18 +452,16 @@
 	/* barrier to ensure read completes before we proceed further*/
 	mb();
 
+	msm_spm_drv_get_saw2_ver(dev, &dev->major, &dev->minor);
+
 	num_spm_entry = msm_spm_drv_get_num_spm_entry(dev);
 
 	dev->reg_seq_entry_shadow =
-		kmalloc(sizeof(*dev->reg_seq_entry_shadow) * num_spm_entry,
+		kzalloc(sizeof(*dev->reg_seq_entry_shadow) * num_spm_entry,
 				GFP_KERNEL);
 
 	if (!dev->reg_seq_entry_shadow)
 		return -ENOMEM;
 
-
-	memset(dev->reg_seq_entry_shadow, 0x0f,
-			num_spm_entry * sizeof(*dev->reg_seq_entry_shadow));
-
 	return 0;
 }
diff --git a/arch/arm/mach-msm/spm.h b/arch/arm/mach-msm/spm.h
index 21c7dca..154303b 100644
--- a/arch/arm/mach-msm/spm.h
+++ b/arch/arm/mach-msm/spm.h
@@ -70,19 +70,33 @@
 	MSM_SPM_REG_SAW2_AVS_HYSTERESIS,
 	MSM_SPM_REG_SAW2_SPM_CTL,
 	MSM_SPM_REG_SAW2_PMIC_DLY,
+	MSM_SPM_REG_SAW2_AVS_LIMIT,
+	MSM_SPM_REG_SAW2_AVS_DLY,
+	MSM_SPM_REG_SAW2_SPM_DLY,
 	MSM_SPM_REG_SAW2_PMIC_DATA_0,
 	MSM_SPM_REG_SAW2_PMIC_DATA_1,
+	MSM_SPM_REG_SAW2_PMIC_DATA_2,
+	MSM_SPM_REG_SAW2_PMIC_DATA_3,
+	MSM_SPM_REG_SAW2_PMIC_DATA_4,
+	MSM_SPM_REG_SAW2_PMIC_DATA_5,
+	MSM_SPM_REG_SAW2_PMIC_DATA_6,
+	MSM_SPM_REG_SAW2_PMIC_DATA_7,
 	MSM_SPM_REG_SAW2_RST,
 
 	MSM_SPM_REG_NR_INITIALIZE = MSM_SPM_REG_SAW2_RST,
+
 	MSM_SPM_REG_SAW2_ID,
 	MSM_SPM_REG_SAW2_SECURE,
 	MSM_SPM_REG_SAW2_STS0,
 	MSM_SPM_REG_SAW2_STS1,
 	MSM_SPM_REG_SAW2_VCTL,
-	MSM_SPM_REG_SAW2_SEQ_ENTRY ,
+	MSM_SPM_REG_SAW2_SEQ_ENTRY,
+	MSM_SPM_REG_SAW2_SPM_STS,
+	MSM_SPM_REG_SAW2_AVS_STS,
+	MSM_SPM_REG_SAW2_PMIC_STS,
+	MSM_SPM_REG_SAW2_VERSION,
 
-	MSM_SPM_REG_NR
+	MSM_SPM_REG_NR,
 };
 
 struct msm_spm_seq_entry {
@@ -95,8 +109,13 @@
 	void __iomem *reg_base_addr;
 	uint32_t reg_init_values[MSM_SPM_REG_NR_INITIALIZE];
 
+	uint32_t ver_reg;
+	uint32_t vctl_port;
+	uint32_t phase_port;
+
 	uint8_t awake_vlevel;
 	uint32_t vctl_timeout_us;
+	uint32_t avs_timeout_us;
 
 	uint32_t num_modes;
 	struct msm_spm_seq_entry *modes;
@@ -105,18 +124,93 @@
 
 #if defined(CONFIG_MSM_SPM_V1) || defined(CONFIG_MSM_SPM_V2)
 
+/* 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);
-void msm_spm_reinit(void);
-void msm_spm_allow_x_cpu_set_vdd(bool allowed);
-int msm_spm_init(struct msm_spm_platform_data *data, int nr_devs);
+
+/**
+ * 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_allow_x_cpu_set_vdd(): Turn on/off cross calling to set voltage
+ * @allowed: boolean to indicate on/off.
+ */
+void msm_spm_allow_x_cpu_set_vdd(bool allowed);
+
+/**
+ * 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);
+
+/* 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
+
 static inline int msm_spm_l2_set_low_power_mode(unsigned int mode,
 		bool notify_rpm)
 {
@@ -130,10 +224,18 @@
 {
 	/* empty */
 }
+
+static inline int msm_spm_apcs_set_vdd(unsigned int vlevel)
+{
+	return -ENOSYS;
+}
+
+static inline int msm_spm_apcs_set_phase(unsigned int phase_cnt)
+{
+	return -ENOSYS;
+}
 #endif /* defined(CONFIG_MSM_L2_SPM) */
-
 #else /* defined(CONFIG_MSM_SPM_V1) || defined(CONFIG_MSM_SPM_V2) */
-
 static inline int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm)
 {
 	return -ENOSYS;
@@ -158,6 +260,11 @@
 {
 	return -ENOSYS;
 }
-#endif  /*defined(CONFIG_MSM_SPM_V1) || defined (CONFIG_MSM_SPM_V2) */
 
+static inline int msm_spm_device_init(void)
+{
+	return -ENOSYS;
+}
+
+#endif  /*defined(CONFIG_MSM_SPM_V1) || defined (CONFIG_MSM_SPM_V2) */
 #endif  /* __ARCH_ARM_MACH_MSM_SPM_H */
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 2b17fa3..2980811 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -17,6 +17,9 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
 #include <mach/msm_iomap.h>
 #include <mach/socinfo.h>
 #include "spm.h"
@@ -35,6 +38,7 @@
 	uint32_t num_modes;
 };
 
+static struct msm_spm_device msm_spm_l2_device;
 static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_spm_device, msm_cpu_spm_device);
 static atomic_t msm_spm_set_vdd_x_cpu_allowed = ATOMIC_INIT(1);
 
@@ -42,6 +46,7 @@
 {
 	atomic_set(&msm_spm_set_vdd_x_cpu_allowed, allowed ? 1 : 0);
 }
+EXPORT_SYMBOL(msm_spm_allow_x_cpu_set_vdd);
 
 int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel)
 {
@@ -62,6 +67,7 @@
 	local_irq_restore(flags);
 	return ret;
 }
+EXPORT_SYMBOL(msm_spm_set_vdd);
 
 static int msm_spm_dev_set_low_power_mode(struct msm_spm_device *dev,
 		unsigned int mode, bool notify_rpm)
@@ -86,7 +92,7 @@
 	return ret;
 }
 
-static int __init msm_spm_dev_init(struct msm_spm_device *dev,
+static int __devinit msm_spm_dev_init(struct msm_spm_device *dev,
 		struct msm_spm_platform_data *data)
 {
 	int i, ret = -ENOMEM;
@@ -100,6 +106,7 @@
 	if (!dev->modes)
 		goto spm_failed_malloc;
 
+	dev->reg_data.ver_reg = data->ver_reg;
 	ret = msm_spm_drv_init(&dev->reg_data, data);
 
 	if (ret)
@@ -107,15 +114,17 @@
 
 	for (i = 0; i < dev->num_modes; i++) {
 
+		/* Default offset is 0 and gets updated as we write more
+		 * sequences into SPM
+		 */
+		dev->modes[i].start_addr = offset;
 		ret = msm_spm_drv_write_seq_data(&dev->reg_data,
-						data->modes[i].cmd, offset);
+						data->modes[i].cmd, &offset);
 		if (ret < 0)
 			goto spm_failed_init;
 
 		dev->modes[i].mode = data->modes[i].mode;
 		dev->modes[i].notify_rpm = data->modes[i].notify_rpm;
-		dev->modes[i].start_addr = offset;
-		offset += ret;
 	}
 	msm_spm_drv_flush_seq_entry(&dev->reg_data);
 	return 0;
@@ -126,39 +135,6 @@
 	return ret;
 }
 
-void msm_spm_reinit(void)
-{
-	unsigned int cpu;
-	for_each_possible_cpu(cpu)
-		msm_spm_drv_reinit(&per_cpu(msm_cpu_spm_device.reg_data, cpu));
-}
-
-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);
-	return msm_spm_dev_set_low_power_mode(dev, mode, notify_rpm);
-}
-
-int __init msm_spm_init(struct msm_spm_platform_data *data, int nr_devs)
-{
-	unsigned int cpu;
-	int ret = 0;
-
-	BUG_ON((nr_devs < num_possible_cpus()) || !data);
-
-	for_each_possible_cpu(cpu) {
-		struct msm_spm_device *dev = &per_cpu(msm_cpu_spm_device, cpu);
-		ret = msm_spm_dev_init(dev, &data[cpu]);
-		if (ret < 0) {
-			pr_warn("%s():failed CPU:%u ret:%d\n", __func__,
-					cpu, ret);
-			break;
-		}
-	}
-
-	return ret;
-}
-
 int msm_spm_turn_on_cpu_rail(unsigned int cpu)
 {
 	uint32_t val = 0;
@@ -192,22 +168,227 @@
 }
 EXPORT_SYMBOL(msm_spm_turn_on_cpu_rail);
 
-#if defined(CONFIG_MSM_L2_SPM)
-static struct msm_spm_device msm_spm_l2_device;
+void msm_spm_reinit(void)
+{
+	unsigned int cpu;
+	for_each_possible_cpu(cpu)
+		msm_spm_drv_reinit(&per_cpu(msm_cpu_spm_device.reg_data, cpu));
+}
+EXPORT_SYMBOL(msm_spm_reinit);
+
+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);
+	return msm_spm_dev_set_low_power_mode(dev, mode, notify_rpm);
+}
+EXPORT_SYMBOL(msm_spm_set_low_power_mode);
+
+/* Board file init function */
+int __init msm_spm_init(struct msm_spm_platform_data *data, int nr_devs)
+{
+	unsigned int cpu;
+	int ret = 0;
+
+	BUG_ON((nr_devs < num_possible_cpus()) || !data);
+
+	for_each_possible_cpu(cpu) {
+		struct msm_spm_device *dev = &per_cpu(msm_cpu_spm_device, cpu);
+		ret = msm_spm_dev_init(dev, &data[cpu]);
+		if (ret < 0) {
+			pr_warn("%s():failed CPU:%u ret:%d\n", __func__,
+					cpu, ret);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_MSM_L2_SPM
 
 int msm_spm_l2_set_low_power_mode(unsigned int mode, bool notify_rpm)
 {
 	return msm_spm_dev_set_low_power_mode(
 			&msm_spm_l2_device, mode, notify_rpm);
 }
-
-int __init msm_spm_l2_init(struct msm_spm_platform_data *data)
-{
-	return msm_spm_dev_init(&msm_spm_l2_device, data);
-}
+EXPORT_SYMBOL(msm_spm_l2_set_low_power_mode);
 
 void msm_spm_l2_reinit(void)
 {
 	msm_spm_drv_reinit(&msm_spm_l2_device.reg_data);
 }
+EXPORT_SYMBOL(msm_spm_l2_reinit);
+
+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);
+
+int msm_spm_apcs_set_phase(unsigned int phase_cnt)
+{
+	return msm_spm_drv_set_phase(&msm_spm_l2_device.reg_data, phase_cnt);
+}
+EXPORT_SYMBOL(msm_spm_apcs_set_phase);
+
+/* Board file init function */
+int __init msm_spm_l2_init(struct msm_spm_platform_data *data)
+{
+	return msm_spm_dev_init(&msm_spm_l2_device, data);
+}
 #endif
+
+static int __devinit msm_spm_dev_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	int cpu = 0;
+	int i = 0;
+	struct device_node *node = pdev->dev.of_node;
+	struct msm_spm_platform_data spm_data;
+	char *key = NULL;
+	uint32_t val = 0;
+	struct msm_spm_seq_entry modes[MSM_SPM_MODE_NR];
+	size_t len = 0;
+	struct msm_spm_device *dev = NULL;
+	struct resource *res = NULL;
+	uint32_t mode_count = 0;
+
+	struct spm_of {
+		char *key;
+		uint32_t id;
+	};
+
+	struct spm_of spm_of_data[] = {
+		{"qcom,saw2-cfg", MSM_SPM_REG_SAW2_CFG},
+		{"qcom,saw2-avs-ctl", MSM_SPM_REG_SAW2_AVS_CTL},
+		{"qcom,saw2-avs-hysteresis", MSM_SPM_REG_SAW2_AVS_HYSTERESIS},
+		{"qcom,saw2-spm-ctl", MSM_SPM_REG_SAW2_SPM_CTL},
+		{"qcom,saw2-pmic-dly", MSM_SPM_REG_SAW2_PMIC_DLY},
+		{"qcom,saw2-avs-limit", MSM_SPM_REG_SAW2_AVS_LIMIT},
+		{"qcom,saw2-spm-dly", MSM_SPM_REG_SAW2_SPM_DLY},
+		{"qcom,saw2-pmic-data0", MSM_SPM_REG_SAW2_PMIC_DATA_0},
+		{"qcom,saw2-pmic-data1", MSM_SPM_REG_SAW2_PMIC_DATA_1},
+		{"qcom,saw2-pmic-data2", MSM_SPM_REG_SAW2_PMIC_DATA_2},
+		{"qcom,saw2-pmic-data3", MSM_SPM_REG_SAW2_PMIC_DATA_3},
+		{"qcom,saw2-pmic-data4", MSM_SPM_REG_SAW2_PMIC_DATA_4},
+		{"qcom,saw2-pmic-data5", MSM_SPM_REG_SAW2_PMIC_DATA_5},
+		{"qcom,saw2-pmic-data6", MSM_SPM_REG_SAW2_PMIC_DATA_6},
+		{"qcom,saw2-pmic-data7", MSM_SPM_REG_SAW2_PMIC_DATA_7},
+	};
+
+	struct mode_of {
+		char *key;
+		uint32_t id;
+		uint32_t notify_rpm;
+	};
+
+	struct mode_of mode_of_data[] = {
+		{"qcom,spm-cmd-wfi", MSM_SPM_MODE_CLOCK_GATING, 0},
+		{"qcom,spm-cmd-ret", MSM_SPM_MODE_POWER_RETENTION, 0},
+		{"qcom,spm-cmd-spc", MSM_SPM_MODE_POWER_COLLAPSE, 0},
+		{"qcom,spm-cmd-pc", MSM_SPM_MODE_POWER_COLLAPSE, 1},
+	};
+
+	BUG_ON(ARRAY_SIZE(mode_of_data) > MSM_SPM_MODE_NR);
+	memset(&spm_data, 0, sizeof(struct msm_spm_platform_data));
+	memset(&modes, 0,
+		(MSM_SPM_MODE_NR - 2) * sizeof(struct msm_spm_seq_entry));
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		goto fail;
+
+	spm_data.reg_base_addr = devm_ioremap(&pdev->dev, res->start,
+					resource_size(res));
+	if (!spm_data.reg_base_addr)
+		return -ENOMEM;
+
+	key = "qcom,core-id";
+	ret = of_property_read_u32(node, key, &val);
+	if (ret)
+		goto fail;
+	cpu = val;
+
+	key = "qcom,saw2-ver-reg";
+	ret = of_property_read_u32(node, key, &val);
+	if (ret)
+		goto fail;
+	spm_data.ver_reg = val;
+
+	key = "qcom,vctl-timeout-us";
+	ret = of_property_read_u32(node, key, &val);
+	if (!ret)
+		spm_data.vctl_timeout_us = val;
+
+	/* optional */
+	key = "qcom,vctl-port";
+	ret = of_property_read_u32(node, key, &val);
+	if (!ret)
+		spm_data.vctl_port = val;
+
+	/* optional */
+	key = "qcom,phase-port";
+	ret = of_property_read_u32(node, key, &val);
+	if (!ret)
+		spm_data.phase_port = val;
+
+	for (i = 0; i < ARRAY_SIZE(spm_of_data); i++) {
+		ret = of_property_read_u32(node, spm_of_data[i].key, &val);
+		if (ret)
+			continue;
+		spm_data.reg_init_values[spm_of_data[i].id] = val;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(mode_of_data); i++) {
+		key = mode_of_data[i].key;
+		modes[mode_count].cmd =
+			(uint8_t *)of_get_property(node, key, &len);
+		if (!modes[mode_count].cmd)
+			continue;
+		modes[mode_count].mode = mode_of_data[i].id;
+		modes[mode_count].notify_rpm = mode_of_data[i].notify_rpm;
+		mode_count++;
+	}
+
+	spm_data.modes = modes;
+	spm_data.num_modes = mode_count;
+
+	/*
+	 * Device with id 0..NR_CPUS are SPM for apps cores
+	 * Device with id 0xFFFF is for L2 SPM.
+	 */
+	if (cpu >= 0 && cpu < num_possible_cpus())
+		dev = &per_cpu(msm_cpu_spm_device, cpu);
+	else
+		dev = &msm_spm_l2_device;
+
+	ret = msm_spm_dev_init(dev, &spm_data);
+	if (ret < 0)
+		pr_warn("%s():failed core-id:%u ret:%d\n", __func__, cpu, ret);
+
+	return ret;
+
+fail:
+	pr_err("%s: Failed reading node=%s, key=%s\n",
+			__func__, node->full_name, key);
+	return -EFAULT;
+}
+
+static struct of_device_id msm_spm_match_table[] = {
+	{.compatible = "qcom,spm-v2"},
+	{},
+};
+
+static struct platform_driver msm_spm_device_driver = {
+	.probe = msm_spm_dev_probe,
+	.driver = {
+		.name = "spm-v2",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_spm_match_table,
+	},
+};
+
+int __init msm_spm_device_init(void)
+{
+	return platform_driver_register(&msm_spm_device_driver);
+}
diff --git a/arch/arm/mach-msm/spm_driver.h b/arch/arm/mach-msm/spm_driver.h
index 712f051..f272adb0 100644
--- a/arch/arm/mach-msm/spm_driver.h
+++ b/arch/arm/mach-msm/spm_driver.h
@@ -15,10 +15,17 @@
 #include "spm.h"
 
 struct msm_spm_driver_data {
+	uint32_t major;
+	uint32_t minor;
+	uint32_t ver_reg;
+	uint32_t vctl_port;
+	uint32_t phase_port;
 	void __iomem *reg_base_addr;
 	uint32_t vctl_timeout_us;
+	uint32_t avs_timeout_us;
 	uint32_t reg_shadow[MSM_SPM_REG_NR];
 	uint32_t *reg_seq_entry_shadow;
+	uint32_t *reg_offsets;
 };
 
 int msm_spm_drv_init(struct msm_spm_driver_data *dev,
@@ -29,9 +36,10 @@
 int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev,
 		unsigned int vlevel);
 int msm_spm_drv_write_seq_data(struct msm_spm_driver_data *dev,
-		uint8_t *cmd, uint32_t offset);
+		uint8_t *cmd, uint32_t *offset);
 void msm_spm_drv_flush_seq_entry(struct msm_spm_driver_data *dev);
 int msm_spm_drv_set_spm_enable(struct msm_spm_driver_data *dev,
 		bool enable);
-
+int msm_spm_drv_set_phase(struct msm_spm_driver_data *dev,
+		unsigned int phase_cnt);
 #endif
diff --git a/arch/arm/mach-msm/subsystem_map.c b/arch/arm/mach-msm/subsystem_map.c
index d6a17e6..4a1285b 100644
--- a/arch/arm/mach-msm/subsystem_map.c
+++ b/arch/arm/mach-msm/subsystem_map.c
@@ -392,7 +392,8 @@
 					temp_phys += SZ_4K,
 					temp_va += SZ_4K) {
 				ret = iommu_map(d, temp_va, temp_phys,
-						 get_order(SZ_4K), 0);
+						get_order(SZ_4K),
+						(IOMMU_READ | IOMMU_WRITE));
 				if (ret) {
 					pr_err("%s: could not map iommu for"
 						" domain %p, iova %lx,"
@@ -406,7 +407,8 @@
 
 			if (flags & MSM_SUBSYSTEM_MAP_IOMMU_2X)
 				msm_iommu_map_extra
-					(d, temp_va, length, 0);
+					(d, temp_va, length, SZ_4K,
+					(IOMMU_READ | IOMMU_WRITE));
 		}
 
 	}
diff --git a/arch/arm/mach-msm/sysmon.c b/arch/arm/mach-msm/sysmon.c
index 679393d..1305bd1 100644
--- a/arch/arm/mach-msm/sysmon.c
+++ b/arch/arm/mach-msm/sysmon.c
@@ -27,7 +27,8 @@
 #include "hsic_sysmon.h"
 #include "sysmon.h"
 
-#define MAX_MSG_LENGTH	50
+#define TX_BUF_SIZE	50
+#define RX_BUF_SIZE	500
 #define TIMEOUT_MS	5000
 
 enum transports {
@@ -40,7 +41,7 @@
 	struct smd_channel	*chan;
 	bool			chan_open;
 	struct completion	resp_ready;
-	char			rx_buf[MAX_MSG_LENGTH];
+	char			rx_buf[RX_BUF_SIZE];
 	enum transports		transport;
 };
 
@@ -60,7 +61,8 @@
 	[SUBSYS_AFTER_POWERUP]   = "after_powerup",
 };
 
-static int sysmon_send_smd(struct sysmon_subsys *ss, char *tx_buf, size_t len)
+static int sysmon_send_smd(struct sysmon_subsys *ss, const char *tx_buf,
+			   size_t len)
 {
 	int ret;
 
@@ -78,7 +80,8 @@
 	return 0;
 }
 
-static int sysmon_send_hsic(struct sysmon_subsys *ss, char *tx_buf, size_t len)
+static int sysmon_send_hsic(struct sysmon_subsys *ss, const char *tx_buf,
+			    size_t len)
 {
 	int ret;
 	size_t actual_len;
@@ -93,11 +96,46 @@
 	return ret;
 }
 
+static int sysmon_send_msg(struct sysmon_subsys *ss, const char *tx_buf,
+			   size_t len)
+{
+	int ret;
+
+	switch (ss->transport) {
+	case TRANSPORT_SMD:
+		ret = sysmon_send_smd(ss, tx_buf, len);
+		break;
+	case TRANSPORT_HSIC:
+		ret = sysmon_send_hsic(ss, tx_buf, len);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (!ret)
+		pr_debug("Received response: %s\n", ss->rx_buf);
+
+	return ret;
+}
+
+/**
+ * sysmon_send_event() - Notify a subsystem of another's state change
+ * @dest_ss:	ID of subsystem the notification should be sent to
+ * @event_ss:	String name of the subsystem that generated the notification
+ * @notif:	ID of the notification type (ex. SUBSYS_BEFORE_SHUTDOWN)
+ *
+ * Returns 0 for success, -EINVAL for invalid destination or notification IDs,
+ * -ENODEV if the transport channel is not open, -ETIMEDOUT if the destination
+ * subsystem does not respond, and -ENOSYS if the destination subsystem
+ * responds, but with something other than an acknowledgement.
+ *
+ * If CONFIG_MSM_SYSMON_COMM is not defined, always return success (0).
+ */
 int sysmon_send_event(enum subsys_id dest_ss, const char *event_ss,
 		      enum subsys_notif_type notif)
 {
 	struct sysmon_subsys *ss = &subsys[dest_ss];
-	char tx_buf[MAX_MSG_LENGTH];
+	char tx_buf[TX_BUF_SIZE];
 	int ret;
 
 	if (dest_ss < 0 || dest_ss >= SYSMON_NUM_SS ||
@@ -109,24 +147,52 @@
 		 notif_name[notif]);
 
 	mutex_lock(&ss->lock);
-	switch (ss->transport) {
-	case TRANSPORT_SMD:
-		ret = sysmon_send_smd(ss, tx_buf, strlen(tx_buf));
-		break;
-	case TRANSPORT_HSIC:
-		ret = sysmon_send_hsic(ss, tx_buf, strlen(tx_buf));
-		break;
-	default:
-		ret = -EINVAL;
-	}
+	ret = sysmon_send_msg(ss, tx_buf, strlen(tx_buf));
 	if (ret)
 		goto out;
 
-	pr_debug("Received response: %s\n", ss->rx_buf);
 	if (strncmp(ss->rx_buf, "ssr:ack", ARRAY_SIZE(ss->rx_buf)))
 		ret = -ENOSYS;
-	else
-		ret = 0;
+out:
+	mutex_unlock(&ss->lock);
+	return ret;
+}
+
+/**
+ * sysmon_get_reason() - Retrieve failure reason from a subsystem.
+ * @dest_ss:	ID of subsystem to query
+ * @buf:	Caller-allocated buffer for the returned NUL-terminated reason
+ * @len:	Length of @buf
+ *
+ * Returns 0 for success, -EINVAL for an invalid destination, -ENODEV if
+ * the SMD transport channel is not open, -ETIMEDOUT if the destination
+ * subsystem does not respond, and -ENOSYS if the destination subsystem
+ * responds with something unexpected.
+ *
+ * If CONFIG_MSM_SYSMON_COMM is not defined, always return success (0).
+ */
+int sysmon_get_reason(enum subsys_id dest_ss, char *buf, size_t len)
+{
+	struct sysmon_subsys *ss = &subsys[dest_ss];
+	const char tx_buf[] = "ssr:retrieve:sfr";
+	const char expect[] = "ssr:return:";
+	size_t prefix_len = ARRAY_SIZE(expect) - 1;
+	int ret;
+
+	if (dest_ss < 0 || dest_ss >= SYSMON_NUM_SS ||
+	    buf == NULL || len == 0)
+		return -EINVAL;
+
+	mutex_lock(&ss->lock);
+	ret = sysmon_send_msg(ss, tx_buf, ARRAY_SIZE(tx_buf));
+	if (ret)
+		goto out;
+
+	if (strncmp(ss->rx_buf, expect, prefix_len)) {
+		ret = -ENOSYS;
+		goto out;
+	}
+	strlcpy(buf, ss->rx_buf + prefix_len, len);
 out:
 	mutex_unlock(&ss->lock);
 	return ret;
diff --git a/arch/arm/mach-msm/sysmon.h b/arch/arm/mach-msm/sysmon.h
index d014187..77c3329 100644
--- a/arch/arm/mach-msm/sysmon.h
+++ b/arch/arm/mach-msm/sysmon.h
@@ -34,22 +34,10 @@
 	SYSMON_NUM_SS
 };
 
-/**
- * sysmon_send_event() - Notify a subsystem of another's state change.
- * @dest_ss:	ID of subsystem the notification should be sent to.
- * @event_ss:	String name of the subsystem that generated the notification.
- * @notif:	ID of the notification type (ex. SUBSYS_BEFORE_SHUTDOWN)
- *
- * Returns 0 for success, -EINVAL for invalid destination or notification IDs,
- * -ENODEV if the SMD channel is not open, -ETIMEDOUT if the destination
- * subsystem does not respond, and -ENOSYS if the destination subsystem
- * responds, but with something other than an acknowledgement.
- *
- * If CONFIG_MSM_SYSMON_COMM is not defined, always return success (0).
- */
 #ifdef CONFIG_MSM_SYSMON_COMM
 int sysmon_send_event(enum subsys_id dest_ss, const char *event_ss,
 		      enum subsys_notif_type notif);
+int sysmon_get_reason(enum subsys_id dest_ss, char *buf, size_t len);
 #else
 static inline int sysmon_send_event(enum subsys_id dest_ss,
 				    const char *event_ss,
@@ -57,6 +45,11 @@
 {
 	return 0;
 }
+static inline int sysmon_get_reason(enum subsys_id dest_ss, char *buf,
+				    size_t len)
+{
+	return 0;
+}
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index ea8356c..0eabd1b 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -214,9 +214,9 @@
 		global*global_timer_offset;
 
 	if (!(clock->flags & MSM_CLOCK_FLAGS_UNSTABLE_COUNT))
-		return __raw_readl(addr);
+		return __raw_readl_no_log(addr);
 
-	t1 = __raw_readl(addr);
+	t1 = __raw_readl_no_log(addr);
 	t2 = __raw_readl_no_log(addr);
 	if ((t2-t1) <= 1)
 		return t2;
@@ -981,7 +981,7 @@
 
 	if (cpu_is_msm7x01() || cpu_is_msm7x25() || cpu_is_msm7x27() ||
 	    cpu_is_msm7x25a() || cpu_is_msm7x27a() || cpu_is_msm7x25aa() ||
-	    cpu_is_msm7x27aa() || cpu_is_msm8625()) {
+	    cpu_is_msm7x27aa() || cpu_is_msm8625() || cpu_is_msm7x25ab()) {
 		dgt->shift = MSM_DGT_SHIFT;
 		dgt->freq = 19200000 >> MSM_DGT_SHIFT;
 		dgt->clockevent.shift = 32 + MSM_DGT_SHIFT;
diff --git a/arch/arm/mach-msm/timer.h b/arch/arm/mach-msm/timer.h
index 7da9e6a..368dd7b 100644
--- a/arch/arm/mach-msm/timer.h
+++ b/arch/arm/mach-msm/timer.h
@@ -26,5 +26,6 @@
 #else
 static inline int64_t msm_timer_enter_idle(void) { return 0; }
 static inline void msm_timer_exit_idle(int low_power) { return; }
+static inline int64_t msm_timer_get_sclk_time(int64_t *period) { return 0; }
 #endif
 #endif
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index db2a9b4..e81f881 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -2,7 +2,7 @@
  * arch/arm/mm/cache-l2x0.c - L210/L220 cache controller support
  *
  * Copyright (C) 2007 ARM Limited
- * Copyright (c) 2009, 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009, 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -30,8 +30,6 @@
 #define CACHE_LINE_SIZE		32
 
 static void __iomem *l2x0_base;
-static uint32_t aux_ctrl_save;
-static uint32_t data_latency_ctrl;
 static DEFINE_RAW_SPINLOCK(l2x0_lock);
 
 static uint32_t l2x0_way_mask;	/* Bitmask of active ways */
@@ -39,6 +37,7 @@
 static u32 l2x0_cache_id;
 static unsigned int l2x0_sets;
 static unsigned int l2x0_ways;
+static void pl310_save(void);
 
 static inline bool is_pl310_rev(int rev)
 {
@@ -447,51 +446,9 @@
 	printk(KERN_INFO "%s cache controller enabled\n", type);
 	printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n",
 			ways, cache_id, aux, l2x0_size);
-}
 
-void l2x0_suspend(void)
-{
-	/* Save aux control register value */
-	aux_ctrl_save = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
-	data_latency_ctrl = readl_relaxed(l2x0_base + L2X0_DATA_LATENCY_CTRL);
-	/* Flush all cache */
-	l2x0_flush_all();
-	/* Disable the cache */
-	writel_relaxed(0, l2x0_base + L2X0_CTRL);
-
-	/* Memory barrier */
-	dmb();
-}
-
-void l2x0_resume(int collapsed)
-{
-	if (collapsed) {
-		/* Disable the cache */
-		writel_relaxed(0, l2x0_base + L2X0_CTRL);
-
-		/* Restore aux control register value */
-		writel_relaxed(aux_ctrl_save, l2x0_base + L2X0_AUX_CTRL);
-		writel_relaxed(data_latency_ctrl, l2x0_base +
-				L2X0_DATA_LATENCY_CTRL);
-
-		/* Invalidate the cache */
-		l2x0_inv_all();
-		/*
-		 * TBD: make sure that l2xo_inv_all finished
-		 * before actually enabling the cache. Logically this
-		 * is not required as cache sync is atomic operation.
-		 * but on 8x25, observed the random crashes and they go
-		 * away if we add dmb or disable the L2.
-		 * keeping this as temporary workaround until root
-		 * cause is find out.
-		 */
-		dmb();
-	}
-
-	/* Enable the cache */
-	writel_relaxed(1, l2x0_base + L2X0_CTRL);
-
-	mb();
+	/* Save the L2X0 contents, as they are not modified else where */
+	pl310_save();
 }
 
 #ifdef CONFIG_OF
@@ -562,6 +519,7 @@
 			       l2x0_base + L2X0_ADDR_FILTER_START);
 	}
 }
+#endif
 
 static void pl310_save(void)
 {
@@ -637,6 +595,7 @@
 	l2x0_resume();
 }
 
+#ifdef CONFIG_OF
 static const struct l2x0_of_data pl310_data = {
 	pl310_of_setup,
 	pl310_save,
@@ -692,3 +651,15 @@
 	return 0;
 }
 #endif
+
+void l2cc_suspend(void)
+{
+	l2x0_disable();
+	dmb();
+}
+
+void l2cc_resume(void)
+{
+	pl310_resume();
+	dmb();
+}
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 0ff30c3..ed160f1 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -1143,3 +1143,5 @@
 msm8625_surf		MACH_MSM8625_SURF	MSM8625_SURF		4037
 msm8625_evb		MACH_MSM8625_EVB	MSM8625_EVB		4042
 msm8625_qrd7		MACH_MSM8625_QRD7	MSM8625_QRD7		4095
+msm8625_ffa		MACH_MSM8625_FFA	MSM8625_FFA		4166
+msm8625_evt		MACH_MSM8625_EVT	MSM8625_EVT		4193
diff --git a/drivers/base/genlock.c b/drivers/base/genlock.c
index d9cd600..5e1d7af 100644
--- a/drivers/base/genlock.c
+++ b/drivers/base/genlock.c
@@ -307,12 +307,15 @@
 	if (handle_has_lock(lock, handle)) {
 
 		/*
-		 * If the handle already holds the lock and the type matches,
-		 * then just increment the active pointer. This allows the
-		 * handle to do recursive locks
+		 * If the handle already holds the lock and the lock type is
+		 * a read lock then just increment the active pointer. This
+		 * allows the handle to do recursive read locks. Recursive
+		 * write locks are not allowed in order to support
+		 * synchronization within a process using a single gralloc
+		 * handle.
 		 */
 
-		if (lock->state == op) {
+		if (lock->state == _RDLOCK && op == _RDLOCK) {
 			handle->active++;
 			goto done;
 		}
@@ -321,33 +324,46 @@
 		 * If the handle holds a write lock then the owner can switch
 		 * to a read lock if they want. Do the transition atomically
 		 * then wake up any pending waiters in case they want a read
-		 * lock too.
+		 * lock too. In order to support synchronization within a
+		 * process the caller must explicity request to convert the
+		 * lock type with the GENLOCK_WRITE_TO_READ flag.
 		 */
 
-		if (op == _RDLOCK && handle->active == 1) {
-			lock->state = _RDLOCK;
-			wake_up(&lock->queue);
+		if (flags & GENLOCK_WRITE_TO_READ) {
+			if (lock->state == _WRLOCK && op == _RDLOCK) {
+				lock->state = _RDLOCK;
+				wake_up(&lock->queue);
+				goto done;
+			} else {
+				GENLOCK_LOG_ERR("Invalid state to convert"
+					"write to read\n");
+				ret = -EINVAL;
+				goto done;
+			}
+		}
+	} else {
+
+		/*
+		 * Check to ensure the caller has not attempted to convert a
+		 * write to a read without holding the lock.
+		 */
+
+		if (flags & GENLOCK_WRITE_TO_READ) {
+			GENLOCK_LOG_ERR("Handle must have lock to convert"
+				"write to read\n");
+			ret = -EINVAL;
 			goto done;
 		}
 
 		/*
-		 * Otherwise the user tried to turn a read into a write, and we
-		 * don't allow that.
+		 * If we request a read and the lock is held by a read, then go
+		 * ahead and share the lock
 		 */
-		GENLOCK_LOG_ERR("Trying to upgrade a read lock to a write"
-				"lock\n");
-		ret = -EINVAL;
-		goto done;
+
+		if (op == GENLOCK_RDLOCK && lock->state == _RDLOCK)
+			goto dolock;
 	}
 
-	/*
-	 * If we request a read and the lock is held by a read, then go
-	 * ahead and share the lock
-	 */
-
-	if (op == GENLOCK_RDLOCK && lock->state == _RDLOCK)
-		goto dolock;
-
 	/* Treat timeout 0 just like a NOBLOCK flag and return if the
 	   lock cannot be aquired without blocking */
 
@@ -356,15 +372,26 @@
 		goto done;
 	}
 
-	/* Wait while the lock remains in an incompatible state */
+	/*
+	 * Wait while the lock remains in an incompatible state
+	 * state    op    wait
+	 * -------------------
+	 * unlocked n/a   no
+	 * read     read  no
+	 * read     write yes
+	 * write    n/a   yes
+	 */
 
-	while (lock->state != _UNLOCKED) {
+	while ((lock->state == _RDLOCK && op == _WRLOCK) ||
+			lock->state == _WRLOCK) {
 		signed long elapsed;
 
 		spin_unlock_irqrestore(&lock->lock, irqflags);
 
 		elapsed = wait_event_interruptible_timeout(lock->queue,
-			lock->state == _UNLOCKED, ticks);
+			lock->state == _UNLOCKED ||
+			(lock->state == _RDLOCK && op == _RDLOCK),
+			ticks);
 
 		spin_lock_irqsave(&lock->lock, irqflags);
 
@@ -381,7 +408,7 @@
 
 	list_add_tail(&handle->entry, &lock->active);
 	lock->state = op;
-	handle->active = 1;
+	handle->active++;
 
 done:
 	spin_unlock_irqrestore(&lock->lock, irqflags);
@@ -390,7 +417,7 @@
 }
 
 /**
- * genlock_lock - Acquire or release a lock
+ * genlock_lock - Acquire or release a lock (depreciated)
  * @handle - pointer to the genlock handle that is requesting the lock
  * @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK)
  * @flags - flags to control the operation
@@ -403,6 +430,61 @@
 	uint32_t timeout)
 {
 	struct genlock *lock;
+	unsigned long irqflags;
+
+	int ret = 0;
+
+	if (IS_ERR_OR_NULL(handle)) {
+		GENLOCK_LOG_ERR("Invalid handle\n");
+		return -EINVAL;
+	}
+
+	lock = handle->lock;
+
+	if (lock == NULL) {
+		GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
+		return -EINVAL;
+	}
+
+	switch (op) {
+	case GENLOCK_UNLOCK:
+		ret = _genlock_unlock(lock, handle);
+		break;
+	case GENLOCK_RDLOCK:
+		spin_lock_irqsave(&lock->lock, irqflags);
+		if (handle_has_lock(lock, handle)) {
+			/* request the WRITE_TO_READ flag for compatibility */
+			flags |= GENLOCK_WRITE_TO_READ;
+		}
+		spin_unlock_irqrestore(&lock->lock, irqflags);
+		/* fall through to take lock */
+	case GENLOCK_WRLOCK:
+		ret = _genlock_lock(lock, handle, op, flags, timeout);
+		break;
+	default:
+		GENLOCK_LOG_ERR("Invalid lock operation\n");
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(genlock_lock);
+
+/**
+ * genlock_dreadlock - Acquire or release a lock
+ * @handle - pointer to the genlock handle that is requesting the lock
+ * @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK)
+ * @flags - flags to control the operation
+ * @timeout - optional timeout to wait for the lock to come free
+ *
+ * Returns: 0 on success or error code on failure
+ */
+
+int genlock_dreadlock(struct genlock_handle *handle, int op, int flags,
+	uint32_t timeout)
+{
+	struct genlock *lock;
 
 	int ret = 0;
 
@@ -434,7 +516,7 @@
 
 	return ret;
 }
-EXPORT_SYMBOL(genlock_lock);
+EXPORT_SYMBOL(genlock_dreadlock);
 
 /**
  * genlock_wait - Wait for the lock to be released
@@ -657,6 +739,14 @@
 		return genlock_lock(handle, param.op, param.flags,
 			param.timeout);
 	}
+	case GENLOCK_IOC_DREADLOCK: {
+		if (copy_from_user(&param, (void __user *) arg,
+		sizeof(param)))
+			return -EFAULT;
+
+		return genlock_dreadlock(handle, param.op, param.flags,
+			param.timeout);
+	}
 	case GENLOCK_IOC_WAIT: {
 		if (copy_from_user(&param, (void __user *) arg,
 		sizeof(param)))
diff --git a/drivers/base/iommu.c b/drivers/base/iommu.c
index ea2a1df6..b8333b0 100644
--- a/drivers/base/iommu.c
+++ b/drivers/base/iommu.c
@@ -40,6 +40,26 @@
 }
 EXPORT_SYMBOL_GPL(iommu_found);
 
+/**
+ * iommu_set_fault_handler() - set a fault handler for an iommu domain
+ * @domain: iommu domain
+ * @handler: fault handler
+ *
+ * This function should be used by IOMMU users which want to be notified
+ * whenever an IOMMU fault happens.
+ *
+ * The fault handler itself should return 0 on success, and an appropriate
+ * error code otherwise.
+ */
+void iommu_set_fault_handler(struct iommu_domain *domain,
+					iommu_fault_handler_t handler)
+{
+	BUG_ON(!domain);
+
+	domain->handler = handler;
+}
+EXPORT_SYMBOL_GPL(iommu_set_fault_handler);
+
 struct iommu_domain *iommu_domain_alloc(int flags)
 {
 	struct iommu_domain *domain;
@@ -48,7 +68,7 @@
 	if (!iommu_found())
 		return NULL;
 
-	domain = kmalloc(sizeof(*domain), GFP_KERNEL);
+	domain = kzalloc(sizeof(*domain), GFP_KERNEL);
 	if (!domain)
 		return NULL;
 
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 656223b..49d687d 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -162,6 +162,7 @@
 	int count_write_struct_pool;
 	int used;
 	/* Buffers for masks */
+	struct mutex diag_cntl_mutex;
 	struct diag_ctrl_event_mask *event_mask;
 	struct diag_ctrl_log_mask *log_mask;
 	struct diag_ctrl_msg_mask *msg_mask;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index a63e344..a7a4a2a 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -22,7 +22,7 @@
 #include <linux/delay.h>
 #include <linux/reboot.h>
 #include <linux/of.h>
-#include <linux/spinlock.h>
+#include <linux/kmemleak.h>
 #ifdef CONFIG_DIAG_OVER_USB
 #include <mach/usbdiag.h>
 #endif
@@ -59,7 +59,6 @@
 	int num_items;
 	int index;
 };
-spinlock_t diag_cntl_lock;
 
 #define CREATE_MSG_MASK_TBL_ROW(XX)					\
 do {									\
@@ -774,9 +773,9 @@
 	void *buf = driver->buf_log_mask_update;
 	int header_size = sizeof(struct diag_ctrl_log_mask);
 	struct mask_info *ptr = (struct mask_info *)driver->log_masks;
-	int i, size, wr_size = -ENOMEM, retry_count = 0;
-	unsigned long flags = 0;
+	int i, size, wr_size = -ENOMEM, retry_count = 0, timer;
 
+	mutex_lock(&driver->diag_cntl_mutex);
 	for (i = 0; i < MAX_EQUIP_ID; i++) {
 		size = (ptr->num_items+7)/8;
 		/* reached null entry */
@@ -797,15 +796,13 @@
 									 size);
 			if (ch) {
 				while (retry_count < 3) {
-					spin_lock_irqsave(&diag_cntl_lock,
-									 flags);
 					wr_size = smd_write(ch, buf,
 							 header_size + size);
-					spin_unlock_irqrestore(&diag_cntl_lock,
-									 flags);
 					if (wr_size == -ENOMEM) {
 						retry_count++;
-						usleep(20000);
+						for (timer = 0; timer < 5;
+								 timer++)
+							udelay(2000);
 					} else
 						break;
 				}
@@ -821,17 +818,19 @@
 		}
 		ptr++;
 	}
+	mutex_unlock(&driver->diag_cntl_mutex);
 }
 
 void diag_send_event_mask_update(smd_channel_t *ch, int num_bytes)
 {
 	void *buf = driver->buf_event_mask_update;
 	int header_size = sizeof(struct diag_ctrl_event_mask);
-	int wr_size = -ENOMEM, retry_count = 0;
-	unsigned long flags = 0;
+	int wr_size = -ENOMEM, retry_count = 0, timer;
 
+	mutex_lock(&driver->diag_cntl_mutex);
 	if (num_bytes == 0) {
 		pr_debug("diag: event mask not set yet, so no update\n");
+		mutex_unlock(&driver->diag_cntl_mutex);
 		return;
 	}
 	/* send event mask update */
@@ -845,12 +844,11 @@
 	memcpy(buf+header_size, driver->event_masks, num_bytes);
 	if (ch) {
 		while (retry_count < 3) {
-			spin_lock_irqsave(&diag_cntl_lock, flags);
 			wr_size = smd_write(ch, buf, header_size + num_bytes);
-			spin_unlock_irqrestore(&diag_cntl_lock, flags);
 			if (wr_size == -ENOMEM) {
 				retry_count++;
-				usleep(20000);
+				for (timer = 0; timer < 5; timer++)
+					udelay(2000);
 			} else
 				break;
 		}
@@ -859,17 +857,18 @@
 					 wr_size, header_size + num_bytes);
 	} else
 		pr_err("diag: ch not valid for event update\n");
+	mutex_unlock(&driver->diag_cntl_mutex);
 }
 
 void diag_send_msg_mask_update(smd_channel_t *ch, int updated_ssid_first,
 						int updated_ssid_last, int proc)
 {
 	void *buf = driver->buf_msg_mask_update;
-	int first, last, size = -ENOMEM, retry_count = 0;
+	int first, last, size = -ENOMEM, retry_count = 0, timer;
 	int header_size = sizeof(struct diag_ctrl_msg_mask);
 	uint8_t *ptr = driver->msg_masks;
-	unsigned long flags = 0;
 
+	mutex_lock(&driver->diag_cntl_mutex);
 	while (*(uint32_t *)(ptr + 4)) {
 		first = *(uint32_t *)ptr;
 		ptr += 4;
@@ -892,31 +891,31 @@
 				 4 * (driver->msg_mask->msg_mask_size));
 			if (ch) {
 				while (retry_count < 3) {
-					spin_lock_irqsave(&diag_cntl_lock,
-									 flags);
 					size = smd_write(ch, buf, header_size +
 					 4*(driver->msg_mask->msg_mask_size));
-					spin_unlock_irqrestore(&diag_cntl_lock,
-									 flags);
 					if (size == -ENOMEM) {
 						retry_count++;
-						usleep(20000);
+						for (timer = 0; timer < 5;
+								 timer++)
+							udelay(2000);
 					} else
 						break;
 				}
 				if (size != header_size +
 					 4*(driver->msg_mask->msg_mask_size))
-					pr_err("diag:  msg mask update fail %d,"
-							" tried %d\n", size,
-			 header_size + 4*(driver->msg_mask->msg_mask_size));
+					pr_err("diag: proc %d, msg mask update "
+	 "fail %d, tried %d\n", proc, size,
+	 header_size + 4*(driver->msg_mask->msg_mask_size));
 				else
 					pr_debug("diag: sending mask update for"
-		" ssid first %d, last %d on PROC %d\n", first, last, proc);
+		"ssid first %d, last %d on PROC %d\n", first, last, proc);
 			} else
-				pr_err("diag: ch invalid msg mask update\n");
+				pr_err("diag: proc %d, ch invalid msg mask"
+						 "update\n", proc);
 		}
 		ptr += MAX_SSID_PER_RANGE*4;
 	}
+	mutex_unlock(&driver->diag_cntl_mutex);
 }
 
 static int diag_process_apps_pkt(unsigned char *buf, int len)
@@ -961,7 +960,6 @@
 #endif
 	} /* Disable log masks */
 	else if (*buf == 0x73 && *(int *)(buf+4) == 0) {
-		buf += 8;
 		/* Disable mask for each log code */
 		diag_disable_log_mask();
 		diag_update_userspace_clients(LOG_MASKS_TYPE);
@@ -974,17 +972,16 @@
 			*(int *)(driver->apps_rsp_buf + 4) = 0x0;
 			if (driver->ch_cntl)
 				diag_send_log_mask_update(driver->ch_cntl,
-								 *(int *)buf);
+								 ALL_EQUIP_ID);
 			if (driver->chqdsp_cntl)
 				diag_send_log_mask_update(driver->chqdsp_cntl,
-								 *(int *)buf);
+								 ALL_EQUIP_ID);
 			if (driver->ch_wcnss_cntl)
 				diag_send_log_mask_update(driver->ch_wcnss_cntl,
-								 *(int *)buf);
+								 ALL_EQUIP_ID);
 			ENCODE_RSP_AND_SEND(7);
 			return 0;
-		} else
-			buf = temp;
+		}
 #endif
 	} /* Set runtime message mask  */
 	else if ((*buf == 0x7d) && (*(buf+1) == 0x4)) {
@@ -1791,55 +1788,64 @@
 	diag_debug_buf_idx = 0;
 	driver->read_len_legacy = 0;
 	driver->use_device_tree = has_device_tree();
-	spin_lock_init(&diag_cntl_lock);
+	mutex_init(&driver->diag_cntl_mutex);
 
 	if (driver->event_mask == NULL) {
 		driver->event_mask = kzalloc(sizeof(
 			struct diag_ctrl_event_mask), GFP_KERNEL);
 		if (driver->event_mask == NULL)
 			goto err;
+		kmemleak_not_leak(driver->event_mask);
 	}
 	if (driver->msg_mask == NULL) {
 		driver->msg_mask = kzalloc(sizeof(
 			struct diag_ctrl_msg_mask), GFP_KERNEL);
 		if (driver->msg_mask == NULL)
 			goto err;
+		kmemleak_not_leak(driver->msg_mask);
 	}
 	if (driver->log_mask == NULL) {
 		driver->log_mask = kzalloc(sizeof(
 			struct diag_ctrl_log_mask), GFP_KERNEL);
 		if (driver->log_mask == NULL)
 			goto err;
+		kmemleak_not_leak(driver->log_mask);
 	}
 	if (driver->buf_in_1 == NULL) {
 		driver->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
 		if (driver->buf_in_1 == NULL)
 			goto err;
+		kmemleak_not_leak(driver->buf_in_1);
 	}
 	if (driver->buf_in_2 == NULL) {
 		driver->buf_in_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
 		if (driver->buf_in_2 == NULL)
 			goto err;
+		kmemleak_not_leak(driver->buf_in_2);
 	}
 	if (driver->buf_in_qdsp_1 == NULL) {
 		driver->buf_in_qdsp_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
 		if (driver->buf_in_qdsp_1 == NULL)
 			goto err;
+		kmemleak_not_leak(driver->buf_in_qdsp_1);
 	}
 	if (driver->buf_in_qdsp_2 == NULL) {
 		driver->buf_in_qdsp_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
 		if (driver->buf_in_qdsp_2 == NULL)
 			goto err;
+		kmemleak_not_leak(driver->buf_in_qdsp_2);
 	}
 	if (driver->buf_in_wcnss_1 == NULL) {
 		driver->buf_in_wcnss_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
 		if (driver->buf_in_wcnss_1 == NULL)
 			goto err;
+		kmemleak_not_leak(driver->buf_in_wcnss_1);
 	}
 	if (driver->buf_in_wcnss_2 == NULL) {
 		driver->buf_in_wcnss_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
 		if (driver->buf_in_wcnss_2 == NULL)
 			goto err;
+		kmemleak_not_leak(driver->buf_in_wcnss_2);
 	}
 
 	if (driver->buf_msg_mask_update == NULL) {
@@ -1847,98 +1853,117 @@
 								 GFP_KERNEL);
 		if (driver->buf_msg_mask_update == NULL)
 			goto err;
+		kmemleak_not_leak(driver->buf_msg_mask_update);
 	}
 	if (driver->buf_log_mask_update == NULL) {
 		driver->buf_log_mask_update = kzalloc(APPS_BUF_SIZE,
 								 GFP_KERNEL);
 		if (driver->buf_log_mask_update == NULL)
 			goto err;
+		kmemleak_not_leak(driver->buf_log_mask_update);
 	}
 	if (driver->buf_event_mask_update == NULL) {
 		driver->buf_event_mask_update = kzalloc(APPS_BUF_SIZE,
 								 GFP_KERNEL);
 		if (driver->buf_event_mask_update == NULL)
 			goto err;
+		kmemleak_not_leak(driver->buf_event_mask_update);
 	}
 	if (driver->usb_buf_out  == NULL &&
 	     (driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
 					 GFP_KERNEL)) == NULL)
 		goto err;
+	kmemleak_not_leak(driver->usb_buf_out);
 	if (driver->hdlc_buf == NULL
 	    && (driver->hdlc_buf = kzalloc(HDLC_MAX, GFP_KERNEL)) == NULL)
 		goto err;
+	kmemleak_not_leak(driver->hdlc_buf);
 	if (driver->user_space_data == NULL)
 		driver->user_space_data = kzalloc(USER_SPACE_DATA, GFP_KERNEL);
 		if (driver->user_space_data == NULL)
 			goto err;
+	kmemleak_not_leak(driver->user_space_data);
 	if (driver->msg_masks == NULL
 	    && (driver->msg_masks = kzalloc(MSG_MASK_SIZE,
 					     GFP_KERNEL)) == NULL)
 		goto err;
+	kmemleak_not_leak(driver->msg_masks);
 	diag_create_msg_mask_table();
 	diag_event_num_bytes = 0;
 	if (driver->log_masks == NULL &&
 	    (driver->log_masks = kzalloc(LOG_MASK_SIZE, GFP_KERNEL)) == NULL)
 		goto err;
+	kmemleak_not_leak(driver->log_masks);
 	driver->log_masks_length = (sizeof(struct mask_info))*MAX_EQUIP_ID;
 	if (driver->event_masks == NULL &&
 	    (driver->event_masks = kzalloc(EVENT_MASK_SIZE,
 					    GFP_KERNEL)) == NULL)
 		goto err;
+	kmemleak_not_leak(driver->event_masks);
 	if (driver->client_map == NULL &&
 	    (driver->client_map = kzalloc
 	     ((driver->num_clients) * sizeof(struct diag_client_map),
 		   GFP_KERNEL)) == NULL)
 		goto err;
+	kmemleak_not_leak(driver->client_map);
 	if (driver->buf_tbl == NULL)
 			driver->buf_tbl = kzalloc(buf_tbl_size *
 			  sizeof(struct diag_write_device), GFP_KERNEL);
 	if (driver->buf_tbl == NULL)
 		goto err;
+	kmemleak_not_leak(driver->buf_tbl);
 	if (driver->data_ready == NULL &&
 	     (driver->data_ready = kzalloc(driver->num_clients * sizeof(int)
 							, GFP_KERNEL)) == NULL)
 		goto err;
+	kmemleak_not_leak(driver->data_ready);
 	if (driver->table == NULL &&
 	     (driver->table = kzalloc(diag_max_reg*
 		      sizeof(struct diag_master_table),
 		       GFP_KERNEL)) == NULL)
 		goto err;
+	kmemleak_not_leak(driver->table);
 	if (driver->write_ptr_1 == NULL) {
 		driver->write_ptr_1 = kzalloc(
 			sizeof(struct diag_request), GFP_KERNEL);
 		if (driver->write_ptr_1 == NULL)
 			goto err;
+		kmemleak_not_leak(driver->write_ptr_1);
 	}
 	if (driver->write_ptr_2 == NULL) {
 		driver->write_ptr_2 = kzalloc(
 			sizeof(struct diag_request), GFP_KERNEL);
 		if (driver->write_ptr_2 == NULL)
 			goto err;
+		kmemleak_not_leak(driver->write_ptr_2);
 	}
 	if (driver->write_ptr_qdsp_1 == NULL) {
 		driver->write_ptr_qdsp_1 = kzalloc(
 			sizeof(struct diag_request), GFP_KERNEL);
 		if (driver->write_ptr_qdsp_1 == NULL)
 			goto err;
+		kmemleak_not_leak(driver->write_ptr_qdsp_1);
 	}
 	if (driver->write_ptr_qdsp_2 == NULL) {
 		driver->write_ptr_qdsp_2 = kzalloc(
 			sizeof(struct diag_request), GFP_KERNEL);
 		if (driver->write_ptr_qdsp_2 == NULL)
 			goto err;
+		kmemleak_not_leak(driver->write_ptr_qdsp_2);
 	}
 	if (driver->write_ptr_wcnss_1 == NULL) {
 		driver->write_ptr_wcnss_1 = kzalloc(
 			sizeof(struct diag_request), GFP_KERNEL);
 		if (driver->write_ptr_wcnss_1 == NULL)
 			goto err;
+		kmemleak_not_leak(driver->write_ptr_wcnss_1);
 	}
 	if (driver->write_ptr_wcnss_2 == NULL) {
 		driver->write_ptr_wcnss_2 = kzalloc(
 			sizeof(struct diag_request), GFP_KERNEL);
 		if (driver->write_ptr_wcnss_2 == NULL)
 			goto err;
+		kmemleak_not_leak(driver->write_ptr_wcnss_2);
 	}
 
 	if (driver->usb_read_ptr == NULL) {
@@ -1946,15 +1971,18 @@
 			sizeof(struct diag_request), GFP_KERNEL);
 		if (driver->usb_read_ptr == NULL)
 			goto err;
+		kmemleak_not_leak(driver->usb_read_ptr);
 	}
 	if (driver->pkt_buf == NULL &&
 	     (driver->pkt_buf = kzalloc(PKT_SIZE,
 			 GFP_KERNEL)) == NULL)
 		goto err;
+	kmemleak_not_leak(driver->pkt_buf);
 	if (driver->apps_rsp_buf == NULL) {
 		driver->apps_rsp_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
 		if (driver->apps_rsp_buf == NULL)
 			goto err;
+		kmemleak_not_leak(driver->apps_rsp_buf);
 	}
 	driver->diag_wq = create_singlethread_workqueue("diag_wq");
 #ifdef CONFIG_DIAG_OVER_USB
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 8efe10b..de1a5b5 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/diagchar.h>
 #include <linux/platform_device.h>
+#include <linux/kmemleak.h>
 #include "diagchar.h"
 #include "diagfwd.h"
 #include "diagfwd_cntl.h"
@@ -280,16 +281,19 @@
 		driver->buf_in_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
 		if (driver->buf_in_cntl == NULL)
 			goto err;
+		kmemleak_not_leak(driver->buf_in_cntl);
 	}
 	if (driver->buf_in_qdsp_cntl == NULL) {
 		driver->buf_in_qdsp_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
 		if (driver->buf_in_qdsp_cntl == NULL)
 			goto err;
+		kmemleak_not_leak(driver->buf_in_qdsp_cntl);
 	}
 	if (driver->buf_in_wcnss_cntl == NULL) {
 		driver->buf_in_wcnss_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
 		if (driver->buf_in_wcnss_cntl == NULL)
 			goto err;
+		kmemleak_not_leak(driver->buf_in_wcnss_cntl);
 	}
 	platform_driver_register(&msm_smd_ch1_cntl_driver);
 	platform_driver_register(&diag_smd_lite_cntl_driver);
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index 865fcc2..81a9fa7 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -393,6 +393,8 @@
 	case MDP_RGB_565:
 	case MDP_BGR_565:
 	case MDP_YCRYCB_H2V1:
+	case MDP_YCBCR_H1V1:
+	case MDP_YCRCB_H1V1:
 		p->num_planes = 1;
 		p->plane_size[0] = w * h * get_bpp(format);
 		break;
@@ -1562,7 +1564,8 @@
 		}
 	}
 
-	msm_rotator_dev->regulator = regulator_get(NULL, pdata->regulator_name);
+	msm_rotator_dev->regulator = regulator_get(&msm_rotator_dev->pdev->dev,
+						   "vdd");
 	if (IS_ERR(msm_rotator_dev->regulator))
 		msm_rotator_dev->regulator = NULL;
 
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 8328ee2..cf024cf 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -485,4 +485,12 @@
 	help
 	  Say 'y' here to include support for the Qualcomm QPNP gpio
 	  support. QPNP is a SPMI based PMIC implementation.
+
+config GPIO_QPNP_DEBUG
+	depends on GPIO_QPNP
+	depends on DEBUG_FS
+	bool "Qualcomm QPNP GPIO debug support"
+	help
+	  Say 'y' here to include debug support for the Qualcomm
+	  QPNP gpio support
 endif
diff --git a/drivers/gpio/qpnp-gpio.c b/drivers/gpio/qpnp-gpio.c
index 90cc798..bc0904ec 100644
--- a/drivers/gpio/qpnp-gpio.c
+++ b/drivers/gpio/qpnp-gpio.c
@@ -10,10 +10,13 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
 #include <linux/interrupt.h>
 #include <linux/types.h>
 #include <linux/spmi.h>
 #include <linux/platform_device.h>
+#include <linux/debugfs.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
 #include <linux/of.h>
@@ -27,49 +30,97 @@
 		((q_spec)->offset + reg_index)
 
 #define Q_REG_STATUS1			0x8
-#define Q_NUM_CTL_REGS			5
+#define Q_NUM_CTL_REGS			7
+
+/* type registers base address offsets */
+#define Q_REG_TYPE			0x10
+#define Q_REG_SUBTYPE			0x11
+
+/* gpio peripheral type and subtype values */
+#define Q_GPIO_TYPE			0x10
+#define Q_GPIO_SUBTYPE_GPIO_4CH		0x1
+#define Q_GPIO_SUBTYPE_GPIOC_4CH	0x5
+#define Q_GPIO_SUBTYPE_GPIO_8CH		0x9
+#define Q_GPIO_SUBTYPE_GPIOC_8CH	0xD
 
 /* control register base address offsets */
-#define Q_REG_IO_CTL1			0x42
-#define Q_REG_INPUT_CTL1		0x43
-#define Q_REG_OUTPUT_CTL1		0x44
-#define Q_REG_OUTPUT_CTL2		0x45
-#define Q_REG_EN_CTL1			0x46
+#define Q_REG_MODE_CTL			0x40
+#define Q_REG_DIG_PULL_CTL		0x42
+#define Q_REG_DIG_IN_CTL		0x43
+#define Q_REG_DIG_VIN_CTL		0x44
+#define Q_REG_DIG_OUT_CTL		0x45
+#define Q_REG_EN_CTL			0x46
 
 /* control register regs array indices */
-#define Q_REG_I_IO_CTL1			0
-#define Q_REG_I_INPUT_CTL1		1
-#define Q_REG_I_OUTPUT_CTL1		2
-#define Q_REG_I_OUTPUT_CTL2		3
-#define Q_REG_I_EN_CTL1			4
+#define Q_REG_I_MODE_CTL		0
+#define Q_REG_I_DIG_PULL_CTL		2
+#define Q_REG_I_DIG_IN_CTL		3
+#define Q_REG_I_DIG_VIN_CTL		4
+#define Q_REG_I_DIG_OUT_CTL		5
+#define Q_REG_I_EN_CTL			6
 
-/* control register configuration */
-#define Q_REG_VIN_SHIFT			0
-#define Q_REG_VIN_MASK			0x7
-#define Q_REG_PULL_SHIFT		4
-#define Q_REG_PULL_MASK			0x70
-#define Q_REG_INPUT_EN_SHIFT		7
-#define Q_REG_INPUT_EN_MASK		0x80
-#define Q_REG_OUT_STRENGTH_SHIFT	0
-#define Q_REG_OUT_STRENGTH_MASK		0x3
-#define Q_REG_OUT_TYPE_SHIFT		6
-#define Q_REG_OUT_TYPE_MASK		0x40
+/* control reg: mode */
 #define Q_REG_OUT_INVERT_SHIFT		0
 #define Q_REG_OUT_INVERT_MASK		0x1
 #define Q_REG_SRC_SEL_SHIFT		1
 #define Q_REG_SRC_SEL_MASK		0xE
-#define Q_REG_OUTPUT_EN_SHIFT		7
-#define Q_REG_OUTPUT_EN_MASK		0x80
+#define Q_REG_MODE_SEL_SHIFT		4
+#define Q_REG_MODE_SEL_MASK		0x70
+
+/* control reg: dig_vin */
+#define Q_REG_VIN_SHIFT			0
+#define Q_REG_VIN_MASK			0x7
+
+/* control reg: dig_pull */
+#define Q_REG_PULL_SHIFT		0
+#define Q_REG_PULL_MASK			0x7
+
+/* control reg: dig_out */
+#define Q_REG_OUT_STRENGTH_SHIFT	0
+#define Q_REG_OUT_STRENGTH_MASK		0x3
+#define Q_REG_OUT_TYPE_SHIFT		4
+#define Q_REG_OUT_TYPE_MASK		0x30
+
+/* control reg: en */
 #define Q_REG_MASTER_EN_SHIFT		7
 #define Q_REG_MASTER_EN_MASK		0x80
 
+enum qpnp_gpio_param_type {
+	Q_GPIO_CFG_DIRECTION,
+	Q_GPIO_CFG_OUTPUT_TYPE,
+	Q_GPIO_CFG_INVERT,
+	Q_GPIO_CFG_PULL,
+	Q_GPIO_CFG_VIN_SEL,
+	Q_GPIO_CFG_OUT_STRENGTH,
+	Q_GPIO_CFG_SRC_SELECT,
+	Q_GPIO_CFG_MASTER_EN,
+	Q_GPIO_CFG_INVALID,
+};
+
+#define Q_NUM_PARAMS			Q_GPIO_CFG_INVALID
+
+/* param error checking */
+#define QPNP_GPIO_DIR_INVALID		3
+#define QPNP_GPIO_INVERT_INVALID	2
+#define QPNP_GPIO_OUT_BUF_INVALID	3
+#define QPNP_GPIO_VIN_INVALID		8
+#define QPNP_GPIO_PULL_INVALID		6
+#define QPNP_GPIO_OUT_STRENGTH_INVALID	4
+#define QPNP_GPIO_SRC_INVALID		8
+#define QPNP_GPIO_MASTER_INVALID	2
 
 struct qpnp_gpio_spec {
 	uint8_t slave;			/* 0-15 */
 	uint16_t offset;		/* 0-255 */
 	uint32_t gpio_chip_idx;		/* offset from gpio_chip base */
+	uint32_t pmic_gpio;		/* PMIC gpio number */
 	int irq;			/* logical IRQ number */
 	u8 regs[Q_NUM_CTL_REGS];	/* Control regs */
+	u8 type;			/* peripheral type */
+	u8 subtype;			/* peripheral subtype */
+	struct device_node *node;
+	enum qpnp_gpio_param_type params[Q_NUM_PARAMS];
+	struct qpnp_gpio_chip *q_chip;
 };
 
 struct qpnp_gpio_chip {
@@ -81,6 +132,7 @@
 	uint32_t		pmic_gpio_highest;
 	struct device_node	*int_ctrl;
 	struct list_head	chip_list;
+	struct dentry		*dfs_dir;
 };
 
 static LIST_HEAD(qpnp_gpio_chips);
@@ -121,6 +173,131 @@
 	q_chip->chip_gpios[chip_gpio] = spec;
 }
 
+static int qpnp_gpio_check_config(struct qpnp_gpio_spec *q_spec,
+				  struct qpnp_gpio_cfg *param)
+{
+	int gpio = q_spec->pmic_gpio;
+
+	if (param->direction >= QPNP_GPIO_DIR_INVALID)
+		pr_err("invalid direction for gpio %d\n", gpio);
+	else if (param->invert >= QPNP_GPIO_INVERT_INVALID)
+		pr_err("invalid invert polarity for gpio %d\n", gpio);
+	else if (param->src_select >= QPNP_GPIO_SRC_INVALID)
+		pr_err("invalid source select for gpio %d\n", gpio);
+	else if (param->out_strength >= QPNP_GPIO_OUT_STRENGTH_INVALID ||
+		 param->out_strength == 0)
+		pr_err("invalid out strength for gpio %d\n", gpio);
+	else if (param->output_type >= QPNP_GPIO_OUT_BUF_INVALID)
+		pr_err("invalid out type for gpio %d\n", gpio);
+	else if ((param->output_type == QPNP_GPIO_OUT_BUF_OPEN_DRAIN_NMOS ||
+		 param->output_type == QPNP_GPIO_OUT_BUF_OPEN_DRAIN_PMOS) &&
+		 (q_spec->subtype == Q_GPIO_SUBTYPE_GPIOC_4CH ||
+		 (q_spec->subtype == Q_GPIO_SUBTYPE_GPIOC_8CH)))
+		pr_err("invalid out type for gpio %d\n"
+		       "gpioc does not support open-drain\n", gpio);
+	else if (param->vin_sel >= QPNP_GPIO_VIN_INVALID)
+		pr_err("invalid vin select value for gpio %d\n", gpio);
+	else if (param->pull >= QPNP_GPIO_PULL_INVALID)
+		pr_err("invalid pull value for gpio %d\n", gpio);
+	else if (param->master_en >= QPNP_GPIO_MASTER_INVALID)
+		pr_err("invalid master_en value for gpio %d\n", gpio);
+	else
+		return 0;
+
+	return -EINVAL;
+}
+
+static inline u8 q_reg_get(u8 *reg, int shift, int mask)
+{
+	return (*reg & mask) >> shift;
+}
+
+static inline void q_reg_set(u8 *reg, int shift, int mask, int value)
+{
+	*reg |= (value << shift) & mask;
+}
+
+static inline void q_reg_clr_set(u8 *reg, int shift, int mask, int value)
+{
+	*reg &= ~mask;
+	*reg |= (value << shift) & mask;
+}
+
+static int qpnp_gpio_cache_regs(struct qpnp_gpio_chip *q_chip,
+				struct qpnp_gpio_spec *q_spec)
+{
+	int rc;
+	struct device *dev = &q_chip->spmi->dev;
+
+	rc = spmi_ext_register_readl(q_chip->spmi->ctrl, q_spec->slave,
+				     Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
+				     &q_spec->regs[Q_REG_I_MODE_CTL],
+				     Q_NUM_CTL_REGS);
+	if (rc)
+		dev_err(dev, "%s: unable to read control regs\n", __func__);
+
+	return rc;
+}
+
+static int _qpnp_gpio_config(struct qpnp_gpio_chip *q_chip,
+			     struct qpnp_gpio_spec *q_spec,
+			     struct qpnp_gpio_cfg *param)
+{
+	struct device *dev = &q_chip->spmi->dev;
+	int rc;
+
+	rc = qpnp_gpio_check_config(q_spec, param);
+	if (rc)
+		goto gpio_cfg;
+
+	/* set direction */
+	q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
+			  Q_REG_MODE_SEL_SHIFT, Q_REG_MODE_SEL_MASK,
+			  param->direction);
+
+	/* output specific configuration */
+	q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
+			  Q_REG_OUT_INVERT_SHIFT, Q_REG_OUT_INVERT_MASK,
+			  param->invert);
+	q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
+			  Q_REG_SRC_SEL_SHIFT, Q_REG_SRC_SEL_MASK,
+			  param->src_select);
+	q_reg_clr_set(&q_spec->regs[Q_REG_I_DIG_OUT_CTL],
+			  Q_REG_OUT_STRENGTH_SHIFT, Q_REG_OUT_STRENGTH_MASK,
+			  param->out_strength);
+	q_reg_clr_set(&q_spec->regs[Q_REG_I_DIG_OUT_CTL],
+			  Q_REG_OUT_TYPE_SHIFT, Q_REG_OUT_TYPE_MASK,
+			  param->output_type);
+
+	/* config applicable for both input / output */
+	q_reg_clr_set(&q_spec->regs[Q_REG_I_DIG_VIN_CTL],
+			  Q_REG_VIN_SHIFT, Q_REG_VIN_MASK,
+			  param->vin_sel);
+	q_reg_clr_set(&q_spec->regs[Q_REG_I_DIG_PULL_CTL],
+			  Q_REG_PULL_SHIFT, Q_REG_PULL_MASK,
+			  param->pull);
+	q_reg_clr_set(&q_spec->regs[Q_REG_I_EN_CTL],
+			  Q_REG_MASTER_EN_SHIFT, Q_REG_MASTER_EN_MASK,
+			  param->master_en);
+
+	rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
+			      Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
+			      &q_spec->regs[Q_REG_I_MODE_CTL], Q_NUM_CTL_REGS);
+	if (rc) {
+		dev_err(&q_chip->spmi->dev, "%s: unable to write master"
+						" enable\n", __func__);
+		goto gpio_cfg;
+	}
+
+	return 0;
+
+gpio_cfg:
+	dev_err(dev, "%s: unable to set default config for"
+		     " pmic gpio %d\n", __func__, q_spec->pmic_gpio);
+
+	return rc;
+}
+
 int qpnp_gpio_config(int gpio, struct qpnp_gpio_cfg *param)
 {
 	int rc, chip_offset;
@@ -146,47 +323,8 @@
 		}
 	}
 	mutex_unlock(&qpnp_gpio_chips_lock);
-	if (!q_spec) {
-		pr_err("gpio %d not handled by any pmic\n", gpio);
-		return -EINVAL;
-	}
 
-	q_spec->regs[Q_REG_I_IO_CTL1] = (param->vin_sel <<
-					Q_REG_VIN_SHIFT) & Q_REG_VIN_MASK;
-	q_spec->regs[Q_REG_I_IO_CTL1] |= (param->pull <<
-					Q_REG_PULL_SHIFT) & Q_REG_PULL_MASK;
-	q_spec->regs[Q_REG_I_INPUT_CTL1] = ((param->direction &
-			QPNP_GPIO_DIR_IN) ? ((1 << Q_REG_INPUT_EN_SHIFT)) : 0);
-
-	if (param->direction & QPNP_GPIO_DIR_OUT) {
-		q_spec->regs[Q_REG_I_OUTPUT_CTL1] = (param->out_strength
-			 << Q_REG_OUT_STRENGTH_SHIFT) & Q_REG_OUT_STRENGTH_MASK;
-		q_spec->regs[Q_REG_I_OUTPUT_CTL1] |= (param->output_type
-			 << Q_REG_OUT_TYPE_SHIFT) & Q_REG_OUT_TYPE_MASK;
-	} else {
-		q_spec->regs[Q_REG_I_OUTPUT_CTL1] = 0;
-	}
-
-	if (param->direction & QPNP_GPIO_DIR_OUT) {
-		q_spec->regs[Q_REG_I_OUTPUT_CTL2] = (param->output_value
-			    << Q_REG_OUT_INVERT_SHIFT) & Q_REG_OUT_INVERT_MASK;
-		q_spec->regs[Q_REG_I_OUTPUT_CTL2] |= (param->src_select
-			    << Q_REG_SRC_SEL_SHIFT) & Q_REG_SRC_SEL_MASK;
-		q_spec->regs[Q_REG_I_OUTPUT_CTL2] |= (1 <<
-			      Q_REG_OUTPUT_EN_SHIFT) & Q_REG_OUTPUT_EN_MASK;
-	} else {
-		q_spec->regs[Q_REG_I_OUTPUT_CTL2] = 0;
-	}
-
-	q_spec->regs[Q_REG_I_EN_CTL1] = (param->master_en <<
-				Q_REG_MASTER_EN_SHIFT) & Q_REG_MASTER_EN_MASK;
-
-	rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
-			      Q_REG_ADDR(q_spec, Q_REG_IO_CTL1),
-			      &q_spec->regs[Q_REG_I_IO_CTL1], Q_NUM_CTL_REGS);
-	if (rc)
-		dev_err(&q_chip->spmi->dev, "%s: unable to write master"
-						" enable\n", __func__);
+	rc = _qpnp_gpio_config(q_chip, q_spec, param);
 
 	return rc;
 }
@@ -242,7 +380,8 @@
 		return -ENODEV;
 
 	/* gpio val is from RT status iff input is enabled */
-	if (q_spec->regs[Q_REG_I_INPUT_CTL1] & Q_REG_INPUT_EN_MASK) {
+	if ((q_spec->regs[Q_REG_I_MODE_CTL] & Q_REG_MODE_SEL_MASK)
+						== QPNP_GPIO_DIR_IN) {
 		/* INT_RT_STS */
 		rc = spmi_ext_register_readl(q_chip->spmi->ctrl, q_spec->slave,
 				Q_REG_ADDR(q_spec, Q_REG_STATUS1),
@@ -250,7 +389,7 @@
 		return buf[0];
 
 	} else {
-		ret_val = (q_spec->regs[Q_REG_I_OUTPUT_CTL2] &
+		ret_val = (q_spec->regs[Q_REG_I_MODE_CTL] &
 			       Q_REG_OUT_INVERT_MASK) >> Q_REG_OUT_INVERT_SHIFT;
 		return ret_val;
 	}
@@ -266,15 +405,16 @@
 	if (!q_chip || !q_spec)
 		return -EINVAL;
 
-	q_spec->regs[Q_REG_I_OUTPUT_CTL2] &= ~(1 << Q_REG_OUT_INVERT_SHIFT);
-
 	if (value)
-		q_spec->regs[Q_REG_I_OUTPUT_CTL2] |=
-					    (1 << Q_REG_OUT_INVERT_SHIFT);
+		q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
+			  Q_REG_OUT_INVERT_SHIFT, Q_REG_OUT_INVERT_MASK, 1);
+	else
+		q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
+			  Q_REG_OUT_INVERT_SHIFT, Q_REG_OUT_INVERT_MASK, 0);
 
 	rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
-			      Q_REG_ADDR(q_spec, Q_REG_OUTPUT_CTL2),
-			      &q_spec->regs[Q_REG_I_OUTPUT_CTL2], 1);
+			      Q_REG_ADDR(q_spec, Q_REG_I_MODE_CTL),
+			      &q_spec->regs[Q_REG_I_MODE_CTL], 1);
 	if (rc)
 		dev_err(&q_chip->spmi->dev, "%s: spmi write failed\n",
 								__func__);
@@ -306,21 +446,19 @@
 	if (!q_chip || !q_spec)
 		return -EINVAL;
 
-	if (direction & QPNP_GPIO_DIR_IN) {
-		q_spec->regs[Q_REG_I_INPUT_CTL1] |=
-					(1 << Q_REG_INPUT_EN_SHIFT);
-		q_spec->regs[Q_REG_I_OUTPUT_CTL2] &=
-					~(1 << Q_REG_OUTPUT_EN_SHIFT);
-	} else {
-		q_spec->regs[Q_REG_I_INPUT_CTL1] &=
-					~(1 << Q_REG_INPUT_EN_SHIFT);
-		q_spec->regs[Q_REG_I_OUTPUT_CTL2] |=
-					(1 << Q_REG_OUTPUT_EN_SHIFT);
+	if (direction >= QPNP_GPIO_DIR_INVALID) {
+		pr_err("invalid direction specification %d\n", direction);
+		return -EINVAL;
 	}
 
+	q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
+			Q_REG_MODE_SEL_SHIFT,
+			Q_REG_MODE_SEL_MASK,
+			direction);
+
 	rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
-			      Q_REG_ADDR(q_spec, Q_REG_INPUT_CTL1),
-			      &q_spec->regs[Q_REG_I_INPUT_CTL1], 3);
+			      Q_REG_ADDR(q_spec, Q_REG_I_MODE_CTL),
+			      &q_spec->regs[Q_REG_I_MODE_CTL], 1);
 	return rc;
 }
 
@@ -374,14 +512,13 @@
 	u32 n = be32_to_cpup(gpio);
 
 	if (WARN_ON(gpio_chip->of_gpio_n_cells < 2)) {
-		pr_err("%s: of_gpio_n_cells < 2\n", __func__);
+		pr_err("of_gpio_n_cells < 2\n");
 		return -EINVAL;
 	}
 
 	q_spec = qpnp_pmic_gpio_get_spec(q_chip, n);
 	if (!q_spec) {
-		pr_err("%s: no such PMIC gpio %u in device topology\n",
-							__func__, n);
+		pr_err("no such PMIC gpio %u in device topology\n", n);
 		return -EINVAL;
 	}
 
@@ -391,32 +528,54 @@
 	return q_spec->gpio_chip_idx;
 }
 
-static int qpnp_gpio_config_default(struct spmi_device *spmi,
-					const __be32 *prop, int gpio)
+static int qpnp_gpio_apply_config(struct qpnp_gpio_chip *q_chip,
+				  struct qpnp_gpio_spec *q_spec)
 {
 	struct qpnp_gpio_cfg param;
+	struct device_node *node = q_spec->node;
 	int rc;
 
-	dev_dbg(&spmi->dev, "%s: p[0]: 0x%x p[1]: 0x%x p[2]: 0x%x p[3]:"
-		" 0x%x p[4]: 0x%x p[5]: 0x%x p[6]: 0x%x p[7]: 0x%x\n", __func__,
-		be32_to_cpup(&prop[0]), be32_to_cpup(&prop[1]),
-		be32_to_cpup(&prop[2]), be32_to_cpup(&prop[3]),
-		be32_to_cpup(&prop[4]), be32_to_cpup(&prop[5]),
-		be32_to_cpup(&prop[6]), be32_to_cpup(&prop[7]));
+	param.direction    = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
+				       Q_REG_MODE_SEL_SHIFT,
+				       Q_REG_MODE_SEL_MASK);
+	param.output_type  = q_reg_get(&q_spec->regs[Q_REG_I_DIG_OUT_CTL],
+				       Q_REG_OUT_TYPE_SHIFT,
+				       Q_REG_OUT_TYPE_MASK);
+	param.invert	   = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
+				       Q_REG_OUT_INVERT_MASK,
+				       Q_REG_OUT_INVERT_MASK);
+	param.pull	   = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
+				       Q_REG_PULL_SHIFT, Q_REG_PULL_MASK);
+	param.vin_sel	   = q_reg_get(&q_spec->regs[Q_REG_I_DIG_VIN_CTL],
+				       Q_REG_VIN_SHIFT, Q_REG_VIN_MASK);
+	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.src_select   = 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,
+				       Q_REG_MASTER_EN_MASK);
 
-	param.direction    =	be32_to_cpup(&prop[0]);
-	param.output_type  =	be32_to_cpup(&prop[1]);
-	param.output_value =	be32_to_cpup(&prop[2]);
-	param.pull	   =	be32_to_cpup(&prop[3]);
-	param.vin_sel	   =	be32_to_cpup(&prop[4]);
-	param.out_strength =	be32_to_cpup(&prop[5]);
-	param.src_select   =	be32_to_cpup(&prop[6]);
-	param.master_en    =	be32_to_cpup(&prop[7]);
+	of_property_read_u32(node, "qcom,direction",
+		&param.direction);
+	of_property_read_u32(node, "qcom,output-type",
+		&param.output_type);
+	of_property_read_u32(node, "qcom,invert",
+		&param.invert);
+	of_property_read_u32(node, "qcom,pull",
+		&param.pull);
+	of_property_read_u32(node, "qcom,vin-sel",
+		&param.vin_sel);
+	of_property_read_u32(node, "qcom,out-strength",
+		&param.out_strength);
+	of_property_read_u32(node, "qcom,src-select",
+		&param.src_select);
+	rc = of_property_read_u32(node, "qcom,master-en",
+		&param.master_en);
 
-	rc = qpnp_gpio_config(gpio, &param);
-	if (rc)
-		dev_err(&spmi->dev, "%s: unable to set default config for"
-				" gpio %d\n", __func__, gpio);
+	rc = _qpnp_gpio_config(q_chip, q_spec, &param);
+
 	return rc;
 }
 
@@ -442,15 +601,255 @@
 	return rc;
 }
 
+#ifdef CONFIG_GPIO_QPNP_DEBUG
+struct qpnp_gpio_reg {
+	uint32_t addr;
+	uint32_t idx;
+	uint32_t shift;
+	uint32_t mask;
+};
+
+static struct dentry *driver_dfs_dir;
+
+static int qpnp_gpio_reg_attr(enum qpnp_gpio_param_type type,
+			     struct qpnp_gpio_reg *cfg)
+{
+	switch (type) {
+	case Q_GPIO_CFG_DIRECTION:
+		cfg->addr = Q_REG_MODE_CTL;
+		cfg->idx = Q_REG_I_MODE_CTL;
+		cfg->shift = Q_REG_MODE_SEL_SHIFT;
+		cfg->mask = Q_REG_MODE_SEL_MASK;
+		break;
+	case Q_GPIO_CFG_OUTPUT_TYPE:
+		cfg->addr = Q_REG_DIG_OUT_CTL;
+		cfg->idx = Q_REG_I_DIG_OUT_CTL;
+		cfg->shift = Q_REG_OUT_TYPE_SHIFT;
+		cfg->mask = Q_REG_OUT_TYPE_MASK;
+		break;
+	case Q_GPIO_CFG_INVERT:
+		cfg->addr = Q_REG_MODE_CTL;
+		cfg->idx = Q_REG_I_MODE_CTL;
+		cfg->shift = Q_REG_OUT_INVERT_SHIFT;
+		cfg->mask = Q_REG_OUT_INVERT_MASK;
+		break;
+	case Q_GPIO_CFG_PULL:
+		cfg->addr = Q_REG_DIG_PULL_CTL;
+		cfg->idx = Q_REG_I_DIG_PULL_CTL;
+		cfg->shift = Q_REG_PULL_SHIFT;
+		cfg->mask = Q_REG_PULL_MASK;
+		break;
+	case Q_GPIO_CFG_VIN_SEL:
+		cfg->addr = Q_REG_DIG_VIN_CTL;
+		cfg->idx = Q_REG_I_DIG_VIN_CTL;
+		cfg->shift = Q_REG_VIN_SHIFT;
+		cfg->mask = Q_REG_VIN_MASK;
+		break;
+	case Q_GPIO_CFG_OUT_STRENGTH:
+		cfg->addr = Q_REG_DIG_OUT_CTL;
+		cfg->idx = Q_REG_I_DIG_OUT_CTL;
+		cfg->shift = Q_REG_OUT_STRENGTH_SHIFT;
+		cfg->mask = Q_REG_OUT_STRENGTH_MASK;
+		break;
+	case Q_GPIO_CFG_SRC_SELECT:
+		cfg->addr = Q_REG_MODE_CTL;
+		cfg->idx = Q_REG_I_MODE_CTL;
+		cfg->shift = Q_REG_SRC_SEL_SHIFT;
+		cfg->mask = Q_REG_SRC_SEL_MASK;
+		break;
+	case Q_GPIO_CFG_MASTER_EN:
+		cfg->addr = Q_REG_EN_CTL;
+		cfg->idx = Q_REG_I_EN_CTL;
+		cfg->shift = Q_REG_MASTER_EN_SHIFT;
+		cfg->mask = Q_REG_MASTER_EN_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int qpnp_gpio_debugfs_get(void *data, u64 *val)
+{
+	enum qpnp_gpio_param_type *idx = data;
+	struct qpnp_gpio_spec *q_spec;
+	struct qpnp_gpio_reg cfg = {};
+	int rc;
+
+	rc = qpnp_gpio_reg_attr(*idx, &cfg);
+	if (rc)
+		return rc;
+	q_spec = container_of(idx, struct qpnp_gpio_spec, params[*idx]);
+	*val = q_reg_get(&q_spec->regs[cfg.idx], cfg.shift, cfg.mask);
+	return 0;
+}
+
+static int qpnp_gpio_check_reg_val(enum qpnp_gpio_param_type idx,
+				   struct qpnp_gpio_spec *q_spec,
+				   uint32_t val)
+{
+	switch (idx) {
+	case Q_GPIO_CFG_DIRECTION:
+		if (val >= QPNP_GPIO_DIR_INVALID)
+			return -EINVAL;
+		break;
+	case Q_GPIO_CFG_OUTPUT_TYPE:
+		if ((val >= QPNP_GPIO_OUT_BUF_INVALID) ||
+		   ((val == QPNP_GPIO_OUT_BUF_OPEN_DRAIN_NMOS ||
+		   val == QPNP_GPIO_OUT_BUF_OPEN_DRAIN_PMOS) &&
+		   (q_spec->subtype == Q_GPIO_SUBTYPE_GPIOC_4CH ||
+		   (q_spec->subtype == Q_GPIO_SUBTYPE_GPIOC_8CH))))
+			return -EINVAL;
+		break;
+	case Q_GPIO_CFG_INVERT:
+		if (val >= QPNP_GPIO_INVERT_INVALID)
+			return -EINVAL;
+		break;
+	case Q_GPIO_CFG_PULL:
+		if (val >= QPNP_GPIO_PULL_INVALID)
+			return -EINVAL;
+		break;
+	case Q_GPIO_CFG_VIN_SEL:
+		if (val >= QPNP_GPIO_VIN_INVALID)
+			return -EINVAL;
+		break;
+	case Q_GPIO_CFG_OUT_STRENGTH:
+		if (val >= QPNP_GPIO_OUT_STRENGTH_INVALID ||
+		    val == 0)
+			return -EINVAL;
+		break;
+	case Q_GPIO_CFG_SRC_SELECT:
+		if (val >= QPNP_GPIO_SRC_INVALID)
+			return -EINVAL;
+		break;
+	case Q_GPIO_CFG_MASTER_EN:
+		if (val >= QPNP_GPIO_MASTER_INVALID)
+			return -EINVAL;
+		break;
+	default:
+		pr_err("invalid param type %u specified\n", idx);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int qpnp_gpio_debugfs_set(void *data, u64 val)
+{
+	enum qpnp_gpio_param_type *idx = data;
+	struct qpnp_gpio_spec *q_spec;
+	struct qpnp_gpio_chip *q_chip;
+	struct qpnp_gpio_reg cfg = {};
+	int rc;
+
+	q_spec = container_of(idx, struct qpnp_gpio_spec, params[*idx]);
+	q_chip = q_spec->q_chip;
+
+	rc = qpnp_gpio_check_reg_val(*idx, q_spec, val);
+	if (rc)
+		return rc;
+
+	rc = qpnp_gpio_reg_attr(*idx, &cfg);
+	if (rc)
+		return rc;
+	q_reg_clr_set(&q_spec->regs[cfg.idx], cfg.shift, cfg.mask, val);
+	rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
+				      Q_REG_ADDR(q_spec, cfg.addr),
+				      &q_spec->regs[cfg.idx], 1);
+
+	return rc;
+}
+DEFINE_SIMPLE_ATTRIBUTE(qpnp_gpio_fops, qpnp_gpio_debugfs_get,
+			qpnp_gpio_debugfs_set, "%llu\n");
+
+#define DEBUGFS_BUF_SIZE 11 /* supports 2^32 in decimal */
+
+struct qpnp_gpio_debugfs_args {
+	enum qpnp_gpio_param_type type;
+	const char *filename;
+};
+
+static struct qpnp_gpio_debugfs_args dfs_args[] = {
+	{ Q_GPIO_CFG_DIRECTION, "direction" },
+	{ Q_GPIO_CFG_OUTPUT_TYPE, "output_type" },
+	{ Q_GPIO_CFG_INVERT, "invert" },
+	{ Q_GPIO_CFG_PULL, "pull" },
+	{ Q_GPIO_CFG_VIN_SEL, "vin_sel" },
+	{ Q_GPIO_CFG_OUT_STRENGTH, "out_strength" },
+	{ Q_GPIO_CFG_SRC_SELECT, "src_select" },
+	{ Q_GPIO_CFG_MASTER_EN, "master_en" }
+};
+
+static int qpnp_gpio_debugfs_create(struct qpnp_gpio_chip *q_chip)
+{
+	struct spmi_device *spmi = q_chip->spmi;
+	struct device *dev = &spmi->dev;
+	struct qpnp_gpio_spec *q_spec;
+	enum qpnp_gpio_param_type *params;
+	enum qpnp_gpio_param_type type;
+	char pmic_gpio[DEBUGFS_BUF_SIZE];
+	const char *filename;
+	struct dentry *dfs, *dfs_io_dir;
+	int i, j;
+
+	BUG_ON(Q_NUM_PARAMS != ARRAY_SIZE(dfs_args));
+
+	q_chip->dfs_dir = debugfs_create_dir(dev->of_node->name,
+							driver_dfs_dir);
+	if (q_chip->dfs_dir == NULL) {
+		dev_err(dev, "%s: cannot register chip debugfs directory %s\n",
+						__func__, dev->of_node->name);
+		return -ENODEV;
+	}
+
+	for (i = 0; i < spmi->num_dev_node; i++) {
+		q_spec = qpnp_chip_gpio_get_spec(q_chip, i);
+		params = q_spec->params;
+		snprintf(pmic_gpio, DEBUGFS_BUF_SIZE, "%u", q_spec->pmic_gpio);
+		dfs_io_dir = debugfs_create_dir(pmic_gpio,
+							q_chip->dfs_dir);
+		if (dfs_io_dir == NULL)
+			goto dfs_err;
+
+		for (j = 0; j < Q_NUM_PARAMS; j++) {
+			type = dfs_args[j].type;
+			filename = dfs_args[j].filename;
+
+			params[type] = type;
+			dfs = debugfs_create_file(
+					filename,
+					S_IRUGO | S_IWUSR,
+					dfs_io_dir,
+					&q_spec->params[type],
+					&qpnp_gpio_fops);
+			if (dfs == NULL)
+				goto dfs_err;
+		}
+	}
+	return 0;
+dfs_err:
+	dev_err(dev, "%s: cannot register debugfs for pmic gpio %u on"
+				     " chip %s\n", __func__,
+				     q_spec->pmic_gpio, dev->of_node->name);
+	debugfs_remove_recursive(q_chip->dfs_dir);
+	return -ENFILE;
+}
+#else
+static int qpnp_gpio_debugfs_create(struct qpnp_gpio_chip *q_chip)
+{
+	return 0;
+}
+#endif
+
 static int qpnp_gpio_probe(struct spmi_device *spmi)
 {
 	struct qpnp_gpio_chip *q_chip;
 	struct resource *res;
 	struct qpnp_gpio_spec *q_spec;
-	const __be32 *prop;
-	int i, rc, ret, gpio, len;
-	int lowest_gpio = INT_MAX, highest_gpio = INT_MIN;
-	u32 intspec[3];
+	int i, rc;
+	int lowest_gpio = UINT_MAX, highest_gpio = 0;
+	u32 intspec[3], gpio;
+	char buf[2];
 
 	q_chip = kzalloc(sizeof(*q_chip), GFP_KERNEL);
 	if (!q_chip) {
@@ -467,21 +866,14 @@
 
 	/* first scan through nodes to find the range required for allocation */
 	for (i = 0; i < spmi->num_dev_node; i++) {
-		prop = of_get_property(spmi->dev_node[i].of_node,
-						"qcom,qpnp-gpio-num", &len);
-		if (!prop) {
+		rc = of_property_read_u32(spmi->dev_node[i].of_node,
+							"qcom,gpio-num", &gpio);
+		if (rc) {
 			dev_err(&spmi->dev, "%s: unable to get"
-				" qcom,qpnp-gpio-num property\n", __func__);
-			ret = -EINVAL;
-			goto err_probe;
-		} else if (len != sizeof(__be32)) {
-			dev_err(&spmi->dev, "%s: Invalid qcom,qpnp-gpio-num"
-				" property\n", __func__);
-			ret = -EINVAL;
+				" qcom,gpio-num property\n", __func__);
 			goto err_probe;
 		}
 
-		gpio = be32_to_cpup(prop);
 		if (gpio < lowest_gpio)
 			lowest_gpio = gpio;
 		if (gpio > highest_gpio)
@@ -491,12 +883,12 @@
 	if (highest_gpio < lowest_gpio) {
 		dev_err(&spmi->dev, "%s: no device nodes specified in"
 					" topology\n", __func__);
-		ret = -EINVAL;
+		rc = -EINVAL;
 		goto err_probe;
 	} else if (lowest_gpio == 0) {
 		dev_err(&spmi->dev, "%s: 0 is not a valid PMIC GPIO\n",
 								__func__);
-		ret = -EINVAL;
+		rc = -EINVAL;
 		goto err_probe;
 	}
 
@@ -512,7 +904,7 @@
 	if (!q_chip->pmic_gpios || !q_chip->chip_gpios) {
 		dev_err(&spmi->dev, "%s: unable to allocate memory\n",
 								__func__);
-		ret = -ENOMEM;
+		rc = -ENOMEM;
 		goto err_probe;
 	}
 
@@ -521,7 +913,7 @@
 	if (!q_chip->int_ctrl) {
 		dev_err(&spmi->dev, "%s: Can't find interrupt parent\n",
 								__func__);
-		ret = -EINVAL;
+		rc = -EINVAL;
 		goto err_probe;
 	}
 
@@ -534,20 +926,13 @@
 				__func__, spmi->dev_node[i].of_node->full_name);
 		}
 
-		prop = of_get_property(spmi->dev_node[i].of_node,
-				"qcom,qpnp-gpio-num", &len);
-		if (!prop) {
+		rc = of_property_read_u32(spmi->dev_node[i].of_node,
+							"qcom,gpio-num", &gpio);
+		if (rc) {
 			dev_err(&spmi->dev, "%s: unable to get"
-				" qcom,qpnp-gpio-num property\n", __func__);
-			ret = -EINVAL;
-			goto err_probe;
-		} else if (len != sizeof(__be32)) {
-			dev_err(&spmi->dev, "%s: Invalid qcom,qpnp-gpio-num"
-				" property\n", __func__);
-			ret = -EINVAL;
+				" qcom,gpio-num property\n", __func__);
 			goto err_probe;
 		}
-		gpio = be32_to_cpup(prop);
 
 		q_spec = kzalloc(sizeof(struct qpnp_gpio_spec),
 							GFP_KERNEL);
@@ -555,13 +940,26 @@
 			dev_err(&spmi->dev, "%s: unable to allocate"
 						" memory\n",
 					__func__);
-			ret = -ENOMEM;
+			rc = -ENOMEM;
 			goto err_probe;
 		}
 
 		q_spec->slave = spmi->sid;
 		q_spec->offset = res->start;
 		q_spec->gpio_chip_idx = i;
+		q_spec->pmic_gpio = gpio;
+		q_spec->node = spmi->dev_node[i].of_node;
+		q_spec->q_chip = q_chip;
+
+		rc = spmi_ext_register_readl(spmi->ctrl, q_spec->slave,
+				Q_REG_ADDR(q_spec, Q_REG_TYPE), &buf[0], 2);
+		if (rc) {
+			dev_err(&spmi->dev, "%s: unable to read type regs\n",
+						__func__);
+			goto err_probe;
+		}
+		q_spec->type	= buf[0];
+		q_spec->subtype = buf[1];
 
 		/* call into irq_domain to get irq mapping */
 		intspec[0] = q_chip->spmi->sid;
@@ -572,10 +970,10 @@
 		if (!q_spec->irq) {
 			dev_err(&spmi->dev, "%s: invalid irq for gpio"
 					" %u\n", __func__, gpio);
-			ret = -EINVAL;
+			rc = -EINVAL;
 			goto err_probe;
 		}
-		/* initialize lookup table entries */
+		/* initialize lookup table params */
 		qpnp_pmic_gpio_set_spec(q_chip, gpio, q_spec);
 		qpnp_chip_gpio_set_spec(q_chip, i, q_spec);
 	}
@@ -597,69 +995,49 @@
 	if (rc) {
 		dev_err(&spmi->dev, "%s: Can't add gpio chip, rc = %d\n",
 								__func__, rc);
-		ret = rc;
 		goto err_probe;
 	}
 
-	/* now configure gpio defaults if they exist */
+	/* now configure gpio config defaults if they exist */
 	for (i = 0; i < spmi->num_dev_node; i++) {
 		q_spec = qpnp_chip_gpio_get_spec(q_chip, i);
-		if (WARN_ON(!q_spec))
-			return -ENODEV;
-
-		/* It's not an error to not config a default */
-		prop = of_get_property(spmi->dev_node[i].of_node,
-				"qcom,qpnp-gpio-cfg", &len);
-		/* 8 data values constitute one tuple */
-		if (prop && (len != (8 * sizeof(__be32)))) {
-			dev_err(&spmi->dev, "%s: invalid format for"
-				" qcom,qpnp-gpio-cfg property\n",
-							__func__);
-			ret = -EINVAL;
+		if (WARN_ON(!q_spec)) {
+			rc = -ENODEV;
 			goto err_probe;
-		} else if (prop) {
-			rc = qpnp_gpio_config_default(spmi, prop,
-				     q_chip->gpio_chip.base + i);
-			if (rc) {
-				ret = rc;
-				goto err_probe;
-			}
-		} else {
-			/* initialize with hardware defaults */
-			rc = spmi_ext_register_readl(
-				q_chip->spmi->ctrl, q_spec->slave,
-				Q_REG_ADDR(q_spec, Q_REG_IO_CTL1),
-				&q_spec->regs[Q_REG_I_IO_CTL1],
-				Q_NUM_CTL_REGS);
-			q_spec->regs[Q_REG_I_EN_CTL1] |=
-				(1 << Q_REG_MASTER_EN_SHIFT);
-			rc = spmi_ext_register_writel(
-				q_chip->spmi->ctrl, q_spec->slave,
-				Q_REG_ADDR(q_spec, Q_REG_EN_CTL1),
-				&q_spec->regs[Q_REG_EN_CTL1], 1);
-			if (rc) {
-				dev_err(&spmi->dev, "%s: spmi write"
-						" failed\n", __func__);
-				ret = rc;
-				goto err_probe;
-			}
 		}
+
+		rc = qpnp_gpio_cache_regs(q_chip, q_spec);
+		if (rc)
+			goto err_probe;
+
+		rc = qpnp_gpio_apply_config(q_chip, q_spec);
+		if (rc)
+			goto err_probe;
 	}
 
 	dev_dbg(&spmi->dev, "%s: gpio_chip registered between %d-%u\n",
 			__func__, q_chip->gpio_chip.base,
 			(q_chip->gpio_chip.base + q_chip->gpio_chip.ngpio) - 1);
+
+	rc = qpnp_gpio_debugfs_create(q_chip);
+	if (rc) {
+		dev_err(&spmi->dev, "%s: debugfs creation failed\n", __func__);
+		goto err_probe;
+	}
+
 	return 0;
 
 err_probe:
 	qpnp_gpio_free_chip(q_chip);
-	return ret;
+	return rc;
 }
 
 static int qpnp_gpio_remove(struct spmi_device *spmi)
 {
 	struct qpnp_gpio_chip *q_chip = dev_get_drvdata(&spmi->dev);
 
+	debugfs_remove_recursive(q_chip->dfs_dir);
+
 	return qpnp_gpio_free_chip(q_chip);
 }
 
@@ -687,11 +1065,21 @@
 
 static int __init qpnp_gpio_init(void)
 {
+#ifdef CONFIG_GPIO_QPNP_DEBUG
+	driver_dfs_dir = debugfs_create_dir("qpnp_gpio", NULL);
+	if (driver_dfs_dir == NULL)
+		pr_err("Cannot register top level debugfs directory\n");
+#endif
+
 	return spmi_driver_register(&qpnp_gpio_driver);
 }
 
 static void __exit qpnp_gpio_exit(void)
 {
+#ifdef CONFIG_GPIO_QPNP_DEBUG
+	debugfs_remove_recursive(driver_dfs_dir);
+#endif
+	spmi_driver_unregister(&qpnp_gpio_driver);
 }
 
 MODULE_DESCRIPTION("QPNP PMIC gpio driver");
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 6823a5a..9597d18 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -632,8 +632,6 @@
 	return data;
 
 out:
-	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
-				buffer->size);
 	kfree(data);
 	return ERR_PTR(ret);
 }
@@ -1495,21 +1493,28 @@
 		mutex_unlock(&client->lock);
 		if (copy_to_user((void __user *)arg, &data, sizeof(data)))
 			return -EFAULT;
+		if (data.fd < 0)
+			return data.fd;
 		break;
 	}
 	case ION_IOC_IMPORT:
 	{
 		struct ion_fd_data data;
+		int ret = 0;
 		if (copy_from_user(&data, (void __user *)arg,
 				   sizeof(struct ion_fd_data)))
 			return -EFAULT;
 
 		data.handle = ion_import_fd(client, data.fd);
-		if (IS_ERR(data.handle))
+		if (IS_ERR(data.handle)) {
+			ret = PTR_ERR(data.handle);
 			data.handle = NULL;
+		}
 		if (copy_to_user((void __user *)arg, &data,
 				 sizeof(struct ion_fd_data)))
 			return -EFAULT;
+		if (ret < 0)
+			return ret;
 		break;
 	}
 	case ION_IOC_CUSTOM:
@@ -1563,6 +1568,8 @@
 		if (!data.handle)
 			ion_free(client, handle);
 
+		if (ret < 0)
+			return ret;
 		break;
 
 	}
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index 84789ef..ca2380b 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -274,8 +274,9 @@
 	struct iommu_domain *domain;
 	int ret = 0;
 	unsigned long extra;
-	int prot = ION_IS_CACHED(flags) ? 1 : 0;
 	struct scatterlist *sglist = 0;
+	int prot = IOMMU_WRITE | IOMMU_READ;
+	prot |= ION_IS_CACHED(flags) ? IOMMU_CACHE : 0;
 
 	data->mapped_size = iova_length;
 
@@ -320,7 +321,8 @@
 
 	if (extra) {
 		unsigned long extra_iova_addr = data->iova_addr + buffer->size;
-		ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+		ret = msm_iommu_map_extra(domain, extra_iova_addr, extra,
+					  SZ_4K, prot);
 		if (ret)
 			goto out2;
 	}
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index b383e68..7f57fe6 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -60,8 +60,12 @@
  *			kernel space (un-cached).
  * @umap_count:	the total number of times this heap has been mapped in
  *		user space.
+ * @iommu_iova: saved iova when mapping full heap at once.
+ * @iommu_partition: partition used to map full heap.
  * @reusable: indicates if the memory should be reused via fmem.
  * @reserved_vrange: reserved virtual address range for use with fmem
+ * @iommu_map_all:	Indicates whether we should map whole heap into IOMMU.
+ * @iommu_2x_map_domain: Indicates the domain to use for overmapping.
  */
 struct ion_cp_heap {
 	struct ion_heap heap;
@@ -80,8 +84,13 @@
 	unsigned long kmap_cached_count;
 	unsigned long kmap_uncached_count;
 	unsigned long umap_count;
+	unsigned long iommu_iova[MAX_DOMAINS];
+	unsigned long iommu_partition[MAX_DOMAINS];
 	int reusable;
 	void *reserved_vrange;
+	int iommu_map_all;
+	int iommu_2x_map_domain;
+
 };
 
 enum {
@@ -247,6 +256,30 @@
 	return offset;
 }
 
+static void iommu_unmap_all(unsigned long domain_num,
+			    struct ion_cp_heap *cp_heap)
+{
+	unsigned long left_to_unmap = cp_heap->total_size;
+	unsigned long order = get_order(SZ_64K);
+	unsigned long page_size = SZ_64K;
+
+	struct iommu_domain *domain = msm_get_iommu_domain(domain_num);
+	if (domain) {
+		unsigned long temp_iova = cp_heap->iommu_iova[domain_num];
+
+		while (left_to_unmap) {
+			iommu_unmap(domain, temp_iova, order);
+			temp_iova += page_size;
+			left_to_unmap -= page_size;
+		}
+		if (domain_num == cp_heap->iommu_2x_map_domain)
+			msm_iommu_unmap_extra(domain, temp_iova,
+					      cp_heap->total_size, SZ_64K);
+	} else {
+		pr_err("Unable to get IOMMU domain %lu\n", domain_num);
+	}
+}
+
 void ion_cp_free(struct ion_heap *heap, ion_phys_addr_t addr,
 		       unsigned long size)
 {
@@ -265,6 +298,26 @@
 			pr_err("%s: unable to transition heap to T-state\n",
 				__func__);
 	}
+
+	/* Unmap everything if we previously mapped the whole heap at once. */
+	if (!cp_heap->allocated_bytes) {
+		unsigned int i;
+		for (i = 0; i < MAX_DOMAINS; ++i) {
+			if (cp_heap->iommu_iova[i]) {
+				unsigned long vaddr_len = cp_heap->total_size;
+
+				if (i == cp_heap->iommu_2x_map_domain)
+					vaddr_len <<= 1;
+				iommu_unmap_all(i, cp_heap);
+
+				msm_free_iova_address(cp_heap->iommu_iova[i], i,
+						cp_heap->iommu_partition[i],
+						vaddr_len);
+			}
+			cp_heap->iommu_iova[i] = 0;
+			cp_heap->iommu_partition[i] = 0;
+		}
+	}
 	mutex_unlock(&cp_heap->lock);
 }
 
@@ -566,6 +619,75 @@
 	return ret_value;
 }
 
+static int iommu_map_all(unsigned long domain_num, struct ion_cp_heap *cp_heap,
+			int partition, unsigned long prot)
+{
+	unsigned long left_to_map = cp_heap->total_size;
+	unsigned long order = get_order(SZ_64K);
+	unsigned long page_size = SZ_64K;
+	int ret_value = 0;
+	unsigned long virt_addr_len = cp_heap->total_size;
+	struct iommu_domain *domain = msm_get_iommu_domain(domain_num);
+
+	/* If we are mapping into the video domain we need to map twice the
+	 * size of the heap to account for prefetch issue in video core.
+	 */
+	if (domain_num == cp_heap->iommu_2x_map_domain)
+		virt_addr_len <<= 1;
+
+	if (cp_heap->total_size & (SZ_64K-1)) {
+		pr_err("Heap size is not aligned to 64K, cannot map into IOMMU\n");
+		ret_value = -EINVAL;
+	}
+	if (cp_heap->base & (SZ_64K-1)) {
+		pr_err("Heap physical address is not aligned to 64K, cannot map into IOMMU\n");
+		ret_value = -EINVAL;
+	}
+	if (!ret_value && domain) {
+		unsigned long temp_phys = cp_heap->base;
+		unsigned long temp_iova =
+				msm_allocate_iova_address(domain_num, partition,
+						virt_addr_len, SZ_64K);
+		if (!temp_iova) {
+			pr_err("%s: could not allocate iova from domain %lu, partition %d\n",
+				__func__, domain_num, partition);
+			ret_value = -ENOMEM;
+			goto out;
+		}
+		cp_heap->iommu_iova[domain_num] = temp_iova;
+
+		while (left_to_map) {
+			int ret = iommu_map(domain, temp_iova, temp_phys,
+					    order, prot);
+			if (ret) {
+				pr_err("%s: could not map %lx in domain %p, error: %d\n",
+					__func__, temp_iova, domain, ret);
+				ret_value = -EAGAIN;
+				goto free_iova;
+			}
+			temp_iova += page_size;
+			temp_phys += page_size;
+			left_to_map -= page_size;
+		}
+		if (domain_num == cp_heap->iommu_2x_map_domain)
+			ret_value = msm_iommu_map_extra(domain, temp_iova,
+							cp_heap->total_size,
+							SZ_64K, prot);
+		if (ret_value)
+			goto free_iova;
+	} else {
+		pr_err("Unable to get IOMMU domain %lu\n", domain_num);
+		ret_value = -ENOMEM;
+	}
+	goto out;
+
+free_iova:
+	msm_free_iova_address(cp_heap->iommu_iova[domain_num], domain_num,
+			      partition, virt_addr_len);
+out:
+	return ret_value;
+}
+
 static int ion_cp_heap_map_iommu(struct ion_buffer *buffer,
 				struct ion_iommu_map *data,
 				unsigned int domain_num,
@@ -577,8 +699,11 @@
 	struct iommu_domain *domain;
 	int ret = 0;
 	unsigned long extra;
-	int prot = ION_IS_CACHED(flags) ? 1 : 0;
 	struct scatterlist *sglist = 0;
+	struct ion_cp_heap *cp_heap =
+		container_of(buffer->heap, struct ion_cp_heap, heap);
+	int prot = IOMMU_WRITE | IOMMU_READ;
+	prot |= ION_IS_CACHED(flags) ? IOMMU_CACHE : 0;
 
 	data->mapped_size = iova_length;
 
@@ -587,6 +712,32 @@
 		return 0;
 	}
 
+	if (cp_heap->iommu_iova[domain_num]) {
+		/* Already mapped. */
+		unsigned long offset = buffer->priv_phys - cp_heap->base;
+		data->iova_addr = cp_heap->iommu_iova[domain_num] + offset;
+		return 0;
+	} else if (cp_heap->iommu_map_all) {
+		ret = iommu_map_all(domain_num, cp_heap, partition_num, prot);
+		if (!ret) {
+			unsigned long offset =
+					buffer->priv_phys - cp_heap->base;
+			data->iova_addr =
+				cp_heap->iommu_iova[domain_num] + offset;
+			cp_heap->iommu_partition[domain_num] = partition_num;
+			/*
+			clear delayed map flag so that we don't interfere
+			with this feature (we are already delaying).
+			*/
+			data->flags &= ~ION_IOMMU_UNMAP_DELAYED;
+			return 0;
+		} else {
+			cp_heap->iommu_iova[domain_num] = 0;
+			cp_heap->iommu_partition[domain_num] = 0;
+			return ret;
+		}
+	}
+
 	extra = iova_length - buffer->size;
 
 	data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
@@ -619,7 +770,8 @@
 
 	if (extra) {
 		unsigned long extra_iova_addr = data->iova_addr + buffer->size;
-		ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+		ret = msm_iommu_map_extra(domain, extra_iova_addr, extra,
+					  SZ_4K, prot);
 		if (ret)
 			goto out2;
 	}
@@ -642,11 +794,20 @@
 	unsigned int domain_num;
 	unsigned int partition_num;
 	struct iommu_domain *domain;
+	struct ion_cp_heap *cp_heap =
+		container_of(data->buffer->heap, struct ion_cp_heap, heap);
 
 	if (!msm_use_iommu())
 		return;
 
+
 	domain_num = iommu_map_domain(data);
+
+	/* If we are mapping everything we'll wait to unmap until everything
+	   is freed. */
+	if (cp_heap->iommu_iova[domain_num])
+		return;
+
 	partition_num = iommu_map_partition(data);
 
 	domain = msm_get_iommu_domain(domain_num);
@@ -727,7 +888,13 @@
 			cp_heap->request_region = extra_data->request_region;
 		if (extra_data->release_region)
 			cp_heap->release_region = extra_data->release_region;
+		cp_heap->iommu_map_all =
+				extra_data->iommu_map_all;
+		cp_heap->iommu_2x_map_domain =
+				extra_data->iommu_2x_map_domain;
+
 	}
+
 	return &cp_heap->heap;
 
 destroy_pool:
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index baf0a66..312ca42 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -181,8 +181,9 @@
 	struct iommu_domain *domain;
 	int ret = 0;
 	unsigned long extra;
-	int prot = ION_IS_CACHED(flags) ? 1 : 0;
 	struct ion_iommu_priv_data *buffer_data = buffer->priv_virt;
+	int prot = IOMMU_WRITE | IOMMU_READ;
+	prot |= ION_IS_CACHED(flags) ? IOMMU_CACHE : 0;
 
 	BUG_ON(!msm_use_iommu());
 
@@ -214,7 +215,8 @@
 
 	if (extra) {
 		unsigned long extra_iova_addr = data->iova_addr + buffer->size;
-		ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+		ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, SZ_4K,
+					  prot);
 		if (ret)
 			goto out2;
 	}
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index 9bb240c..ed9ae27 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -228,7 +228,8 @@
 	int npages = buffer->size >> PAGE_SHIFT;
 	void *vaddr = buffer->priv_virt;
 	struct scatterlist *sglist = 0;
-	int prot = ION_IS_CACHED(flags) ? 1 : 0;
+	int prot = IOMMU_WRITE | IOMMU_READ;
+	prot |= ION_IS_CACHED(flags) ? IOMMU_CACHE : 0;
 
 	if (!ION_IS_CACHED(flags))
 		return -EINVAL;
@@ -281,7 +282,8 @@
 
 	extra_iova_addr = data->iova_addr + buffer->size;
 	if (extra) {
-		ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+		ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, SZ_4K,
+					  prot);
 		if (ret)
 			goto out2;
 	}
@@ -440,9 +442,10 @@
 	int ret = 0;
 	struct iommu_domain *domain;
 	unsigned long extra;
-	int prot = ION_IS_CACHED(flags) ? 1 : 0;
 	struct scatterlist *sglist = 0;
 	struct page *page = 0;
+	int prot = IOMMU_WRITE | IOMMU_READ;
+	prot |= ION_IS_CACHED(flags) ? IOMMU_CACHE : 0;
 
 	if (!ION_IS_CACHED(flags))
 		return -EINVAL;
@@ -488,7 +491,8 @@
 
 	if (extra) {
 		unsigned long extra_iova_addr = data->iova_addr + buffer->size;
-		ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+		ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, SZ_4K,
+					  prot);
 		if (ret)
 			goto out2;
 	}
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 15c0ec5..c8bfce3 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -213,6 +213,45 @@
 	}
 }
 
+static int is_heap_overlapping(const struct ion_platform_heap *heap1,
+				const struct ion_platform_heap *heap2)
+{
+	unsigned long heap1_base = heap1->base;
+	unsigned long heap2_base = heap2->base;
+	unsigned long heap1_end = heap1->base + heap1->size - 1;
+	unsigned long heap2_end = heap2->base + heap2->size - 1;
+
+	if (heap1_base == heap2_base)
+		return 1;
+	if (heap1_base < heap2_base && heap1_end >= heap2_base)
+		return 1;
+	if (heap2_base < heap1_base && heap2_end >= heap1_base)
+		return 1;
+	return 0;
+}
+
+static void check_for_heap_overlap(const struct ion_platform_heap heap_list[],
+				   unsigned long nheaps)
+{
+	unsigned long i;
+	unsigned long j;
+
+	for (i = 0; i < nheaps; ++i) {
+		const struct ion_platform_heap *heap1 = &heap_list[i];
+		if (!heap1->base)
+			continue;
+		for (j = i + 1; j < nheaps; ++j) {
+			const struct ion_platform_heap *heap2 = &heap_list[j];
+			if (!heap2->base)
+				continue;
+			if (is_heap_overlapping(heap1, heap2)) {
+				panic("Memory in heap %s overlaps with heap %s\n",
+					heap1->name, heap2->name);
+			}
+		}
+	}
+}
+
 static int msm_ion_probe(struct platform_device *pdev)
 {
 	struct ion_platform_data *pdata = pdev->dev.platform_data;
@@ -258,6 +297,8 @@
 
 		ion_device_add_heap(idev, heaps[i]);
 	}
+
+	check_for_heap_overlap(pdata->heaps, num_heaps);
 	platform_set_drvdata(pdev, idev);
 	return 0;
 
diff --git a/drivers/gpu/msm/a2xx_reg.h b/drivers/gpu/msm/a2xx_reg.h
index 4c0bd19..41cb601 100644
--- a/drivers/gpu/msm/a2xx_reg.h
+++ b/drivers/gpu/msm/a2xx_reg.h
@@ -140,24 +140,9 @@
 	struct rb_edram_info_t f;
 };
 
-#define RBBM_READ_ERROR_UNUSED0_SIZE		2
-#define RBBM_READ_ERROR_READ_ADDRESS_SIZE	15
-#define RBBM_READ_ERROR_UNUSED1_SIZE		13
-#define RBBM_READ_ERROR_READ_REQUESTER_SIZE	1
-#define RBBM_READ_ERROR_READ_ERROR_SIZE		1
-
-struct rbbm_read_error_t {
-	unsigned int unused0:RBBM_READ_ERROR_UNUSED0_SIZE;
-	unsigned int read_address:RBBM_READ_ERROR_READ_ADDRESS_SIZE;
-	unsigned int unused1:RBBM_READ_ERROR_UNUSED1_SIZE;
-	unsigned int read_requester:RBBM_READ_ERROR_READ_REQUESTER_SIZE;
-	unsigned int read_error:RBBM_READ_ERROR_READ_ERROR_SIZE;
-};
-
-union rbbm_read_error_u {
-	unsigned int val:32;
-	struct rbbm_read_error_t f;
-};
+#define RBBM_READ_ERROR_ADDRESS_MASK	0x0001fffc
+#define RBBM_READ_ERROR_REQUESTER	(1<<30)
+#define RBBM_READ_ERROR_ERROR		(1<<31)
 
 #define CP_RB_CNTL_RB_BUFSZ_SIZE                           6
 #define CP_RB_CNTL_UNUSED0_SIZE                            2
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 00dba96..bfbf411 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -69,10 +69,9 @@
 
 static struct adreno_device device_3d0 = {
 	.dev = {
+		KGSL_DEVICE_COMMON_INIT(device_3d0.dev),
 		.name = DEVICE_3D0_NAME,
 		.id = KGSL_DEVICE_3D0,
-		.ver_major = DRIVER_VERSION_MAJOR,
-		.ver_minor = DRIVER_VERSION_MINOR,
 		.mh = {
 			.mharb  = ADRENO_CFG_MHARB,
 			/* Remove 1k boundary check in z470 to avoid a GPU
@@ -90,12 +89,8 @@
 			.config = ADRENO_MMU_CONFIG,
 		},
 		.pwrctrl = {
-			.regulator_name = "fs_gfx3d",
 			.irq_name = KGSL_3D0_IRQ,
 		},
-		.mutex = __MUTEX_INITIALIZER(device_3d0.dev.mutex),
-		.state = KGSL_STATE_INIT,
-		.active_cnt = 0,
 		.iomemname = KGSL_3D0_REG_MEMORY,
 		.ftbl = &adreno_functable,
 #ifdef CONFIG_HAS_EARLYSUSPEND
@@ -263,7 +258,7 @@
 	 */
 
 	if (adreno_is_a3xx(adreno_dev)) {
-		kgsl_mmu_device_setstate(device, flags);
+		kgsl_mmu_device_setstate(&device->mmu, flags);
 		return;
 	}
 
@@ -349,7 +344,7 @@
 		adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_PMODE,
 					&link[0], sizedwords);
 	} else {
-		kgsl_mmu_device_setstate(device, flags);
+		kgsl_mmu_device_setstate(&device->mmu, flags);
 	}
 }
 
@@ -483,8 +478,6 @@
 	adreno_dev = ADRENO_DEVICE(device);
 	device->parentdev = &pdev->dev;
 
-	init_completion(&device->recovery_gate);
-
 	status = adreno_ringbuffer_init(device);
 	if (status != 0)
 		goto error;
@@ -575,7 +568,7 @@
 	}
 
 	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
-	kgsl_mmu_stop(device);
+	kgsl_mmu_stop(&device->mmu);
 error_clk_off:
 	kgsl_pwrctrl_disable(device);
 
@@ -590,7 +583,7 @@
 
 	adreno_ringbuffer_stop(&adreno_dev->ringbuffer);
 
-	kgsl_mmu_stop(device);
+	kgsl_mmu_stop(&device->mmu);
 
 	device->ftbl->irqctrl(device, 0);
 	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 95378a1..a7ea20c 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -108,8 +108,10 @@
 /* A2XX register sets defined in adreno_a2xx.c */
 extern const unsigned int a200_registers[];
 extern const unsigned int a220_registers[];
+extern const unsigned int a225_registers[];
 extern const unsigned int a200_registers_count;
 extern const unsigned int a220_registers_count;
+extern const unsigned int a225_registers_count;
 
 /* A3XX register set defined in adreno_a3xx.c */
 extern const unsigned int a3xx_registers[];
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 050fd83..eb936f8 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -55,7 +55,6 @@
 	0x4000, 0x4003, 0x4800, 0x4805, 0x4900, 0x4900, 0x4908, 0x4908,
 };
 
-/* A220, A225 */
 const unsigned int a220_registers[] = {
 	0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
 	0x0046, 0x0047, 0x01C0, 0x01C1, 0x01C3, 0x01C8, 0x01D5, 0x01D9,
@@ -85,8 +84,40 @@
 	0x4900, 0x4900, 0x4908, 0x4908,
 };
 
+const unsigned int a225_registers[] = {
+	0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
+	0x0046, 0x0047, 0x013C, 0x013C, 0x0140, 0x014F, 0x01C0, 0x01C1,
+	0x01C3, 0x01C8, 0x01D5, 0x01D9, 0x01DC, 0x01DD, 0x01EA, 0x01EA,
+	0x01EE, 0x01F3, 0x01F6, 0x01F7, 0x01FC, 0x01FF, 0x0391, 0x0392,
+	0x039B, 0x039E, 0x03B2, 0x03B5, 0x03B7, 0x03B7, 0x03F8, 0x03FB,
+	0x0440, 0x0440, 0x0443, 0x0444, 0x044B, 0x044B, 0x044D, 0x044F,
+	0x0452, 0x0452, 0x0454, 0x045B, 0x047F, 0x047F, 0x0578, 0x0587,
+	0x05C9, 0x05C9, 0x05D0, 0x05D0, 0x0601, 0x0604, 0x0606, 0x0609,
+	0x060B, 0x060E, 0x0613, 0x0614, 0x0A29, 0x0A2B, 0x0A2F, 0x0A31,
+	0x0A40, 0x0A40, 0x0A42, 0x0A43, 0x0A45, 0x0A45, 0x0A4E, 0x0A4F,
+	0x0C01, 0x0C1D, 0x0C30, 0x0C30, 0x0C38, 0x0C39, 0x0C3C, 0x0C3C,
+	0x0C80, 0x0C81, 0x0C88, 0x0C93, 0x0D00, 0x0D03, 0x0D05, 0x0D06,
+	0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1, 0x0DC8, 0x0DD4,
+	0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04, 0x0E17, 0x0E1E,
+	0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0, 0x0ED4, 0x0ED7,
+	0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x2000, 0x200F, 0x2080, 0x2082,
+	0x2100, 0x2109, 0x210C, 0x2114, 0x2180, 0x2184, 0x21F5, 0x21F7,
+	0x2200, 0x2202, 0x2204, 0x2206, 0x2208, 0x2210, 0x2220, 0x2222,
+	0x2280, 0x2282, 0x2294, 0x2294, 0x2297, 0x2297, 0x2300, 0x230A,
+	0x2312, 0x2312, 0x2315, 0x2316, 0x2318, 0x231D, 0x2324, 0x2326,
+	0x2340, 0x2357, 0x2360, 0x2360, 0x2380, 0x2383, 0x2400, 0x240F,
+	0x2480, 0x2482, 0x2500, 0x2509, 0x250C, 0x2514, 0x2580, 0x2584,
+	0x25F5, 0x25F7, 0x2600, 0x2602, 0x2604, 0x2606, 0x2608, 0x2610,
+	0x2620, 0x2622, 0x2680, 0x2682, 0x2694, 0x2694, 0x2697, 0x2697,
+	0x2700, 0x270A, 0x2712, 0x2712, 0x2715, 0x2716, 0x2718, 0x271D,
+	0x2724, 0x2726, 0x2740, 0x2757, 0x2760, 0x2760, 0x2780, 0x2783,
+	0x4000, 0x4003, 0x4800, 0x4806, 0x4808, 0x4808, 0x4900, 0x4900,
+	0x4908, 0x4908,
+};
+
 const unsigned int a200_registers_count = ARRAY_SIZE(a200_registers) / 2;
 const unsigned int a220_registers_count = ARRAY_SIZE(a220_registers) / 2;
+const unsigned int a225_registers_count = ARRAY_SIZE(a225_registers) / 2;
 
 /*
  *
@@ -1510,7 +1541,7 @@
 
 	if (context == NULL) {
 		/* No context - set the default apgetable and thats it */
-		kgsl_mmu_setstate(device, device->mmu.defaultpagetable);
+		kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable);
 		return;
 	}
 
@@ -1523,7 +1554,7 @@
 		KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
 	cmds[4] = context->id;
 	adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE, cmds, 5);
-	kgsl_mmu_setstate(device, context->pagetable);
+	kgsl_mmu_setstate(&device->mmu, context->pagetable);
 
 #ifndef CONFIG_MSM_KGSL_CFF_DUMP_NO_CONTEXT_MEM_DUMP
 	kgsl_cffdump_syncmem(NULL, &context->gpustate,
@@ -1694,21 +1725,33 @@
 {
 	unsigned int status = 0;
 	unsigned int rderr = 0;
+	unsigned int addr = 0;
+	const char *source;
 
 	adreno_regread(device, REG_RBBM_INT_STATUS, &status);
 
 	if (status & RBBM_INT_CNTL__RDERR_INT_MASK) {
-		union rbbm_read_error_u rerr;
 		adreno_regread(device, REG_RBBM_READ_ERROR, &rderr);
-		rerr.val = rderr;
-		if (rerr.f.read_address == REG_CP_INT_STATUS &&
-			rerr.f.read_error &&
-			rerr.f.read_requester)
+		source = (rderr & RBBM_READ_ERROR_REQUESTER)
+			 ? "host" : "cp";
+		/* convert to dword address */
+		addr = (rderr & RBBM_READ_ERROR_ADDRESS_MASK) >> 2;
+
+		/*
+		 * Log CP_INT_STATUS interrupts from the CP at a
+		 * lower level because they can happen frequently
+		 * and are worked around in a2xx_irq_handler.
+		 */
+		if (addr == REG_CP_INT_STATUS &&
+			rderr & RBBM_READ_ERROR_ERROR &&
+			rderr & RBBM_READ_ERROR_REQUESTER)
 			KGSL_DRV_WARN(device,
-				"rbbm read error interrupt: %08x\n", rderr);
+				"rbbm read error interrupt: %s reg: %04X\n",
+				source, addr);
 		else
 			KGSL_DRV_CRIT(device,
-				"rbbm read error interrupt: %08x\n", rderr);
+				"rbbm read error interrupt: %s reg: %04X\n",
+				source, addr);
 	}
 
 	status &= RBBM_INT_MASK;
diff --git a/drivers/gpu/msm/adreno_a2xx_snapshot.c b/drivers/gpu/msm/adreno_a2xx_snapshot.c
index 091db22..2368264 100644
--- a/drivers/gpu/msm/adreno_a2xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a2xx_snapshot.c
@@ -240,9 +240,12 @@
 	if (adreno_is_a20x(adreno_dev)) {
 		regs.regs = (unsigned int *) a200_registers;
 		regs.count = a200_registers_count;
-	} else {
+	} else if (adreno_is_a220(adreno_dev)) {
 		regs.regs = (unsigned int *) a220_registers;
 		regs.count = a220_registers_count;
+	} else if (adreno_is_a225(adreno_dev)) {
+		regs.regs = (unsigned int *) a225_registers;
+		regs.count = a225_registers_count;
 	}
 
 	/* Master set of (non debug) registers */
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 6b58545..5187eb1 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2257,7 +2257,7 @@
 
 	if (context == NULL) {
 		/* No context - set the default pagetable and thats it */
-		kgsl_mmu_setstate(device, device->mmu.defaultpagetable);
+		kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable);
 		return;
 	}
 
@@ -2270,7 +2270,7 @@
 		KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
 	cmds[4] = context->id;
 	adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE, cmds, 5);
-	kgsl_mmu_setstate(device, context->pagetable);
+	kgsl_mmu_setstate(&device->mmu, context->pagetable);
 
 	/*
 	 * Restore GMEM.  (note: changes shader.
@@ -2599,7 +2599,7 @@
 	adreno_regwrite(device, A3XX_RBBM_AHB_CTL1, 0xA6FFFFFF);
 
 	/* Turn on the power counters */
-	adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, 0x00003000);
+	adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, 0x00030000);
 
 	/* Turn on hang detection - this spews a lot of useful information
 	 * into the RBBM registers on a hang */
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 6bdf284..ec38f75 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -661,7 +661,7 @@
 
 	kgsl_regread(device, MH_MMU_MPU_END, &r1);
 	kgsl_regread(device, MH_MMU_VA_RANGE, &r2);
-	r3 = kgsl_mmu_get_current_ptbase(device);
+	r3 = kgsl_mmu_get_current_ptbase(&device->mmu);
 	KGSL_LOG_DUMP(device,
 		"        MPU_END    = %08X | VA_RANGE = %08X | PT_BASE  ="
 		" %08X\n", r1, r2, r3);
@@ -706,7 +706,7 @@
 	else if (adreno_is_a3xx(adreno_dev))
 		adreno_dump_a3xx(device);
 
-	pt_base = kgsl_mmu_get_current_ptbase(device);
+	pt_base = kgsl_mmu_get_current_ptbase(&device->mmu);
 	cur_pt_base = pt_base;
 
 	kgsl_regread(device, REG_CP_RB_BASE, &cp_rb_base);
@@ -859,6 +859,9 @@
 		else if (adreno_is_a22x(adreno_dev))
 			adreno_dump_regs(device, a220_registers,
 					a220_registers_count);
+		else if (adreno_is_a225(adreno_dev))
+			adreno_dump_regs(device, a225_registers,
+				a225_registers_count);
 		else if (adreno_is_a3xx(adreno_dev))
 			adreno_dump_regs(device, a3xx_registers,
 					a3xx_registers_count);
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index fe01764..8d900b0 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -235,10 +235,8 @@
 	if (rb->flags & KGSL_FLAGS_STARTED)
 		return 0;
 
-	if (init_ram) {
+	if (init_ram)
 		rb->timestamp[KGSL_MEMSTORE_GLOBAL] = 0;
-		GSL_RB_INIT_TIMESTAMP(rb);
-	}
 
 	kgsl_sharedmem_set(&rb->memptrs_desc, 0, 0,
 			   sizeof(struct kgsl_rbmemptrs));
@@ -339,8 +337,9 @@
 	if (status != 0)
 		return status;
 
+	/* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
 	if (adreno_is_a305(adreno_dev) || adreno_is_a320(adreno_dev))
-		adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000F0602);
+		adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000E0602);
 
 	rb->rptr = 0;
 	rb->wptr = 0;
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index 7c93b3b..ae2e4c7 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -70,7 +70,6 @@
 
 /* enable timestamp (...scratch0) memory shadowing */
 #define GSL_RB_MEMPTRS_SCRATCH_MASK 0x1
-#define GSL_RB_INIT_TIMESTAMP(rb)
 
 /* mem rptr */
 #define GSL_RB_CNTL_NO_UPDATE 0x0 /* enable */
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index 2dc6f6c..a0907d7 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -531,7 +531,7 @@
 	int skip_pktsize = 1;
 
 	/* Get the physical address of the MMU pagetable */
-	ptbase = kgsl_mmu_get_current_ptbase(device);
+	ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
 
 	/* Get the current read pointers for the RB */
 	kgsl_regread(device, REG_CP_RB_RPTR, &rptr);
@@ -792,7 +792,7 @@
 	memset(vbo, 0, sizeof(vbo));
 
 	/* Get the physical address of the MMU pagetable */
-	ptbase = kgsl_mmu_get_current_ptbase(device);
+	ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
 
 	/* Dump the ringbuffer */
 	snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_RB,
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 321c59e..adf2772 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -25,6 +25,8 @@
 #include <linux/ashmem.h>
 #include <linux/major.h>
 #include <linux/ion.h>
+#include <linux/io.h>
+#include <mach/socinfo.h>
 
 #include "kgsl.h"
 #include "kgsl_debugfs.h"
@@ -385,7 +387,7 @@
 	idr_remove(&dev_priv->device->context_idr, id);
 }
 
-static void kgsl_timestamp_expired(struct work_struct *work)
+void kgsl_timestamp_expired(struct work_struct *work)
 {
 	struct kgsl_device *device = container_of(work, struct kgsl_device,
 		ts_expired_ws);
@@ -415,6 +417,7 @@
 
 	mutex_unlock(&device->mutex);
 }
+EXPORT_SYMBOL(kgsl_timestamp_expired);
 
 static void kgsl_check_idle_locked(struct kgsl_device *device)
 {
@@ -537,6 +540,10 @@
 			INIT_COMPLETION(device->hwaccess_gate);
 			device->ftbl->suspend_context(device);
 			device->ftbl->stop(device);
+			if (device->idle_wakelock.name)
+				wake_unlock(&device->idle_wakelock);
+			pm_qos_update_request(&device->pm_qos_req_dma,
+						PM_QOS_DEFAULT_VALUE);
 			kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND);
 			break;
 		case KGSL_STATE_SLUMBER:
@@ -647,6 +654,8 @@
 	KGSL_PWR_WARN(device, "late resume start\n");
 	mutex_lock(&device->mutex);
 	device->pwrctrl.restore_slumber = 0;
+	if (device->pwrscale.policy == NULL)
+		kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
 	kgsl_pwrctrl_wake(device);
 	mutex_unlock(&device->mutex);
 	kgsl_check_idle(device);
@@ -1842,10 +1851,20 @@
 	kgsl_check_idle(dev_priv->device);
 	return result;
 
- error_put_file_ptr:
-	if (entry->priv_data)
-		fput(entry->priv_data);
-
+error_put_file_ptr:
+	switch (entry->memtype) {
+	case KGSL_MEM_ENTRY_PMEM:
+	case KGSL_MEM_ENTRY_ASHMEM:
+		if (entry->priv_data)
+			fput(entry->priv_data);
+		break;
+	case KGSL_MEM_ENTRY_ION:
+		ion_unmap_dma(kgsl_ion_client, entry->priv_data);
+		ion_free(kgsl_ion_client, entry->priv_data);
+		break;
+	default:
+		break;
+	}
 error:
 	kfree(entry);
 	kgsl_check_idle(dev_priv->device);
@@ -2318,7 +2337,7 @@
 };
 EXPORT_SYMBOL(kgsl_driver);
 
-void kgsl_unregister_device(struct kgsl_device *device)
+static void _unregister_device(struct kgsl_device *device)
 {
 	int minor;
 
@@ -2327,43 +2346,15 @@
 		if (device == kgsl_driver.devp[minor])
 			break;
 	}
-
-	mutex_unlock(&kgsl_driver.devlock);
-
-	if (minor == KGSL_DEVICE_MAX)
-		return;
-
-	kgsl_device_snapshot_close(device);
-
-	kgsl_cffdump_close(device->id);
-	kgsl_pwrctrl_uninit_sysfs(device);
-
-	wake_lock_destroy(&device->idle_wakelock);
-	pm_qos_remove_request(&device->pm_qos_req_dma);
-
-	idr_destroy(&device->context_idr);
-
-	if (device->memstore.hostptr)
-		kgsl_sharedmem_free(&device->memstore);
-
-	kgsl_mmu_close(device);
-
-	if (device->work_queue) {
-		destroy_workqueue(device->work_queue);
-		device->work_queue = NULL;
+	if (minor != KGSL_DEVICE_MAX) {
+		device_destroy(kgsl_driver.class,
+				MKDEV(MAJOR(kgsl_driver.major), minor));
+		kgsl_driver.devp[minor] = NULL;
 	}
-
-	device_destroy(kgsl_driver.class,
-		       MKDEV(MAJOR(kgsl_driver.major), minor));
-
-	mutex_lock(&kgsl_driver.devlock);
-	kgsl_driver.devp[minor] = NULL;
 	mutex_unlock(&kgsl_driver.devlock);
 }
-EXPORT_SYMBOL(kgsl_unregister_device);
 
-int
-kgsl_register_device(struct kgsl_device *device)
+static int _register_device(struct kgsl_device *device)
 {
 	int minor, ret;
 	dev_t dev;
@@ -2377,7 +2368,6 @@
 			break;
 		}
 	}
-
 	mutex_unlock(&kgsl_driver.devlock);
 
 	if (minor == KGSL_DEVICE_MAX) {
@@ -2393,75 +2383,17 @@
 				    device->name);
 
 	if (IS_ERR(device->dev)) {
+		mutex_lock(&kgsl_driver.devlock);
+		kgsl_driver.devp[minor] = NULL;
+		mutex_unlock(&kgsl_driver.devlock);
 		ret = PTR_ERR(device->dev);
 		KGSL_CORE_ERR("device_create(%s): %d\n", device->name, ret);
-		goto err_devlist;
+		return ret;
 	}
 
 	dev_set_drvdata(device->parentdev, device);
-
-	/* Generic device initialization */
-	init_waitqueue_head(&device->wait_queue);
-
-	kgsl_cffdump_open(device->id);
-
-	init_completion(&device->hwaccess_gate);
-	init_completion(&device->suspend_gate);
-
-	ATOMIC_INIT_NOTIFIER_HEAD(&device->ts_notifier_list);
-
-	setup_timer(&device->idle_timer, kgsl_timer, (unsigned long) device);
-	ret = kgsl_create_device_workqueue(device);
-	if (ret)
-		goto err_devlist;
-
-	INIT_WORK(&device->idle_check_ws, kgsl_idle_check);
-	INIT_WORK(&device->ts_expired_ws, kgsl_timestamp_expired);
-
-	INIT_LIST_HEAD(&device->events);
-
-	device->last_expired_ctxt_id = KGSL_CONTEXT_INVALID;
-
-	ret = kgsl_mmu_init(device);
-	if (ret != 0)
-		goto err_dest_work_q;
-
-	ret = kgsl_allocate_contiguous(&device->memstore, KGSL_MEMSTORE_SIZE);
-	if (ret != 0)
-		goto err_close_mmu;
-
-	wake_lock_init(&device->idle_wakelock, WAKE_LOCK_IDLE, device->name);
-	pm_qos_add_request(&device->pm_qos_req_dma, PM_QOS_CPU_DMA_LATENCY,
-				PM_QOS_DEFAULT_VALUE);
-
-	idr_init(&device->context_idr);
-
-	/* Initalize the snapshot engine */
-	kgsl_device_snapshot_init(device);
-
-	/* sysfs and debugfs initalization - failure here is non fatal */
-
-	/* Initialize logging */
-	kgsl_device_debugfs_init(device);
-
-	/* Initialize common sysfs entries */
-	kgsl_pwrctrl_init_sysfs(device);
-
 	return 0;
-
-err_close_mmu:
-	kgsl_mmu_close(device);
-err_dest_work_q:
-	destroy_workqueue(device->work_queue);
-	device->work_queue = NULL;
-err_devlist:
-	mutex_lock(&kgsl_driver.devlock);
-	kgsl_driver.devp[minor] = NULL;
-	mutex_unlock(&kgsl_driver.devlock);
-
-	return ret;
 }
-EXPORT_SYMBOL(kgsl_register_device);
 
 int kgsl_device_platform_probe(struct kgsl_device *device)
 {
@@ -2471,7 +2403,12 @@
 	struct platform_device *pdev =
 		container_of(device->parentdev, struct platform_device, dev);
 
-	pm_runtime_enable(device->parentdev);
+	status = _register_device(device);
+	if (status)
+		return status;
+
+	/* Initialize logging first, so that failures below actually print. */
+	kgsl_device_debugfs_init(device);
 
 	status = kgsl_pwrctrl_init(device);
 	if (status)
@@ -2496,29 +2433,40 @@
 	device->reg_phys = res->start;
 	device->reg_len = resource_size(res);
 
-	if (!request_mem_region(device->reg_phys, device->reg_len,
-		device->name)) {
+	if (!devm_request_mem_region(device->dev, device->reg_phys,
+				device->reg_len, device->name)) {
 		KGSL_DRV_ERR(device, "request_mem_region failed\n");
 		status = -ENODEV;
 		goto error_pwrctrl_close;
 	}
 
-	device->reg_virt = ioremap(device->reg_phys, device->reg_len);
+	device->reg_virt = devm_ioremap(device->dev, device->reg_phys,
+					device->reg_len);
 
 	if (device->reg_virt == NULL) {
 		KGSL_DRV_ERR(device, "ioremap failed\n");
 		status = -ENODEV;
-		goto error_release_mem;
+		goto error_pwrctrl_close;
+	}
+	/*acquire interrupt */
+	device->pwrctrl.interrupt_num =
+		platform_get_irq_byname(pdev, device->pwrctrl.irq_name);
+
+	if (device->pwrctrl.interrupt_num <= 0) {
+		KGSL_DRV_ERR(device, "platform_get_irq_byname failed: %d\n",
+					 device->pwrctrl.interrupt_num);
+		status = -EINVAL;
+		goto error_pwrctrl_close;
 	}
 
-	status = request_irq(device->pwrctrl.interrupt_num, kgsl_irq_handler,
-			     IRQF_TRIGGER_HIGH, device->name, device);
+	status = devm_request_irq(device->dev, device->pwrctrl.interrupt_num,
+				  kgsl_irq_handler, IRQF_TRIGGER_HIGH,
+				  device->name, device);
 	if (status) {
 		KGSL_DRV_ERR(device, "request_irq(%d) failed: %d\n",
 			      device->pwrctrl.interrupt_num, status);
-		goto error_iounmap;
+		goto error_pwrctrl_close;
 	}
-	device->pwrctrl.have_irq = 1;
 	disable_irq(device->pwrctrl.interrupt_num);
 
 	KGSL_DRV_INFO(device,
@@ -2528,38 +2476,78 @@
 
 	result = kgsl_drm_init(pdev);
 	if (result)
-		goto error_iounmap;
+		goto error_pwrctrl_close;
 
-	status = kgsl_register_device(device);
-	if (!status)
-		return status;
+	kgsl_cffdump_open(device->id);
 
-	free_irq(device->pwrctrl.interrupt_num, NULL);
-	device->pwrctrl.have_irq = 0;
-error_iounmap:
-	iounmap(device->reg_virt);
-	device->reg_virt = NULL;
-error_release_mem:
-	release_mem_region(device->reg_phys, device->reg_len);
+	setup_timer(&device->idle_timer, kgsl_timer, (unsigned long) device);
+	status = kgsl_create_device_workqueue(device);
+	if (status)
+		goto error_pwrctrl_close;
+
+	status = kgsl_mmu_init(device);
+	if (status != 0) {
+		KGSL_DRV_ERR(device, "kgsl_mmu_init failed %d\n", status);
+		goto error_dest_work_q;
+	}
+
+	status = kgsl_allocate_contiguous(&device->memstore,
+		sizeof(struct kgsl_devmemstore));
+
+	if (status != 0) {
+		KGSL_DRV_ERR(device, "kgsl_allocate_contiguous failed %d\n",
+				status);
+		goto error_close_mmu;
+	}
+
+	wake_lock_init(&device->idle_wakelock, WAKE_LOCK_IDLE, device->name);
+	pm_qos_add_request(&device->pm_qos_req_dma, PM_QOS_CPU_DMA_LATENCY,
+				PM_QOS_DEFAULT_VALUE);
+
+	/* Initalize the snapshot engine */
+	kgsl_device_snapshot_init(device);
+
+	/* Initialize common sysfs entries */
+	kgsl_pwrctrl_init_sysfs(device);
+
+	return 0;
+
+error_close_mmu:
+	kgsl_mmu_close(device);
+error_dest_work_q:
+	destroy_workqueue(device->work_queue);
+	device->work_queue = NULL;
 error_pwrctrl_close:
 	kgsl_pwrctrl_close(device);
 error:
+	_unregister_device(device);
 	return status;
 }
 EXPORT_SYMBOL(kgsl_device_platform_probe);
 
 void kgsl_device_platform_remove(struct kgsl_device *device)
 {
-	kgsl_unregister_device(device);
+	kgsl_device_snapshot_close(device);
 
-	if (device->reg_virt != NULL) {
-		iounmap(device->reg_virt);
-		device->reg_virt = NULL;
-		release_mem_region(device->reg_phys, device->reg_len);
+	kgsl_cffdump_close(device->id);
+	kgsl_pwrctrl_uninit_sysfs(device);
+
+	wake_lock_destroy(&device->idle_wakelock);
+	pm_qos_remove_request(&device->pm_qos_req_dma);
+
+	idr_destroy(&device->context_idr);
+
+	kgsl_sharedmem_free(&device->memstore);
+
+	kgsl_mmu_close(device);
+
+	if (device->work_queue) {
+		destroy_workqueue(device->work_queue);
+		device->work_queue = NULL;
 	}
 	kgsl_pwrctrl_close(device);
 
-	pm_runtime_disable(device->parentdev);
+	_unregister_device(device);
 }
 EXPORT_SYMBOL(kgsl_device_platform_remove);
 
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 9f80a73..da3e4b2 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -44,7 +44,7 @@
 #define KGSL_PAGETABLE_ENTRY_SIZE  4
 
 /* Pagetable Virtual Address base */
-#define KGSL_PAGETABLE_BASE	0x66000000
+#define KGSL_PAGETABLE_BASE	0x10000000
 
 /* Extra accounting entries needed in the pagetable */
 #define KGSL_PT_EXTRA_ENTRIES      16
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index b42e606..0964458 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -199,6 +199,26 @@
 	s64 on_time;
 };
 
+void kgsl_timestamp_expired(struct work_struct *work);
+
+#define KGSL_DEVICE_COMMON_INIT(_dev) \
+	.hwaccess_gate = COMPLETION_INITIALIZER((_dev).hwaccess_gate),\
+	.suspend_gate = COMPLETION_INITIALIZER((_dev).suspend_gate),\
+	.recovery_gate = COMPLETION_INITIALIZER((_dev).recovery_gate),\
+	.ts_notifier_list = ATOMIC_NOTIFIER_INIT((_dev).ts_notifier_list),\
+	.idle_check_ws = __WORK_INITIALIZER((_dev).idle_check_ws,\
+			kgsl_idle_check),\
+	.ts_expired_ws  = __WORK_INITIALIZER((_dev).ts_expired_ws,\
+			kgsl_timestamp_expired),\
+	.context_idr = IDR_INIT((_dev).context_idr),\
+	.events = LIST_HEAD_INIT((_dev).events),\
+	.wait_queue = __WAIT_QUEUE_HEAD_INITIALIZER((_dev).wait_queue),\
+	.mutex = __MUTEX_INITIALIZER((_dev).mutex),\
+	.state = KGSL_STATE_INIT,\
+	.ver_major = DRIVER_VERSION_MAJOR,\
+	.ver_minor = DRIVER_VERSION_MINOR,\
+	.last_expired_ctxt_id = KGSL_CONTEXT_INVALID
+
 struct kgsl_context {
 	uint32_t id;
 
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index 1d80a30..a477439 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -518,14 +518,6 @@
 			"for GPUMMU: %x\n", CONFIG_MSM_KGSL_PAGE_TABLE_SIZE);
 			return -EINVAL;
 		}
-
-		/* allocate memory used for completing r/w operations that
-		 * cannot be mapped by the MMU
-		 */
-		status = kgsl_allocate_contiguous(&mmu->setstate_memory, 64);
-		if (!status)
-			kgsl_sharedmem_set(&mmu->setstate_memory, 0, 0,
-					   mmu->setstate_memory.size);
 	}
 
 	dev_info(mmu->device->dev, "|%s| MMU type set for device is GPUMMU\n",
@@ -686,12 +678,10 @@
 	return 0;
 }
 
-static int kgsl_gpummu_stop(struct kgsl_mmu *mmu)
+static void kgsl_gpummu_stop(struct kgsl_mmu *mmu)
 {
 	kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
 	mmu->flags &= ~KGSL_FLAGS_STARTED;
-
-	return 0;
 }
 
 static int kgsl_gpummu_close(struct kgsl_mmu *mmu)
@@ -727,6 +717,9 @@
 	.mmu_device_setstate = kgsl_gpummu_default_setstate,
 	.mmu_pagefault = kgsl_gpummu_pagefault,
 	.mmu_get_current_ptbase = kgsl_gpummu_get_current_ptbase,
+	.mmu_enable_clk = NULL,
+	.mmu_disable_clk = NULL,
+	.mmu_get_hwpagetable_asid = NULL,
 };
 
 struct kgsl_mmu_pt_ops gpummu_pt_ops = {
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index bf2a4ee..7d527e4 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -16,169 +16,452 @@
 #include <linux/genalloc.h>
 #include <linux/slab.h>
 #include <linux/iommu.h>
-#include <mach/iommu.h>
 #include <linux/msm_kgsl.h>
 
 #include "kgsl.h"
 #include "kgsl_device.h"
 #include "kgsl_mmu.h"
 #include "kgsl_sharedmem.h"
+#include "kgsl_iommu.h"
 
 /*
- * On APQ8064, KGSL can control a maximum of 4 IOMMU devices: 2 user and 2
- * priv domains, 1 each for each of the AXI ports attached to the GPU.  8660
- * and 8960 have only one AXI port, so maximum allowable IOMMU devices for those
- * chips is 2.
+ * kgsl_iommu_disable_clk - Disable iommu clocks
+ * @mmu - Pointer to mmu structure
+ *
+ * Disables iommu clocks
+ * Return - void
  */
+static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu)
+{
+	struct kgsl_iommu *iommu = mmu->priv;
+	struct msm_iommu_drvdata *iommu_drvdata;
+	int i, j;
 
-#define KGSL_IOMMU_MAX_DEV 4
+	for (i = 0; i < iommu->unit_count; i++) {
+		struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+		for (j = 0; j < iommu_unit->dev_count; j++) {
+			if (!iommu_unit->dev[j].clk_enabled)
+				continue;
+			iommu_drvdata = dev_get_drvdata(
+					iommu_unit->dev[j].dev->parent);
+			if (iommu_drvdata->clk)
+				clk_disable_unprepare(iommu_drvdata->clk);
+			clk_disable_unprepare(iommu_drvdata->pclk);
+			iommu_unit->dev[j].clk_enabled = false;
+		}
+	}
+}
 
-struct kgsl_iommu_device {
-	struct device *dev;
-	int attached;
-};
+/*
+ * kgsl_iommu_enable_clk - Enable iommu clocks
+ * @mmu - Pointer to mmu structure
+ * @ctx_id - The context bank whose clocks are to be turned on
+ *
+ * Enables iommu clocks of a given context
+ * Return: 0 on success else error code
+ */
+static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu,
+				int ctx_id)
+{
+	int ret = 0;
+	int i, j;
+	struct kgsl_iommu *iommu = mmu->priv;
+	struct msm_iommu_drvdata *iommu_drvdata;
 
-struct kgsl_iommu {
-	struct kgsl_iommu_device dev[KGSL_IOMMU_MAX_DEV];
-	int dev_count;
-};
+	for (i = 0; i < iommu->unit_count; i++) {
+		struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+		for (j = 0; j < iommu_unit->dev_count; j++) {
+			if (iommu_unit->dev[j].clk_enabled ||
+				ctx_id != iommu_unit->dev[j].ctx_id)
+				continue;
+			iommu_drvdata =
+			dev_get_drvdata(iommu_unit->dev[j].dev->parent);
+			ret = clk_prepare_enable(iommu_drvdata->pclk);
+			if (ret)
+				goto done;
+			if (iommu_drvdata->clk) {
+				ret = clk_prepare_enable(iommu_drvdata->clk);
+				if (ret) {
+					clk_disable_unprepare(
+						iommu_drvdata->pclk);
+					goto done;
+				}
+			}
+			iommu_unit->dev[j].clk_enabled = true;
+		}
+	}
+done:
+	if (ret)
+		kgsl_iommu_disable_clk(mmu);
+	return ret;
+}
 
+/*
+ * kgsl_iommu_pt_equal - Check if pagetables are equal
+ * @pt - Pointer to pagetable
+ * @pt_base - Address of a pagetable that the IOMMU register is
+ * programmed with
+ *
+ * Checks whether the pt_base is equal to the base address of
+ * the pagetable which is contained in the pt structure
+ * Return - Non-zero if the pagetable addresses are equal else 0
+ */
 static int kgsl_iommu_pt_equal(struct kgsl_pagetable *pt,
 					unsigned int pt_base)
 {
-	struct iommu_domain *domain = pt ? pt->priv : NULL;
-	return domain && pt_base && ((unsigned int)domain == pt_base);
+	struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
+	unsigned int domain_ptbase = iommu_pt ?
+				iommu_get_pt_base_addr(iommu_pt->domain) : 0;
+	/* Only compare the valid address bits of the pt_base */
+	domain_ptbase &= (KGSL_IOMMU_TTBR0_PA_MASK <<
+				KGSL_IOMMU_TTBR0_PA_SHIFT);
+	pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK <<
+				KGSL_IOMMU_TTBR0_PA_SHIFT);
+	return domain_ptbase && pt_base &&
+		(domain_ptbase == pt_base);
 }
 
+/*
+ * kgsl_iommu_destroy_pagetable - Free up reaources help by a pagetable
+ * @mmu_specific_pt - Pointer to pagetable which is to be freed
+ *
+ * Return - void
+ */
 static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
 {
-	struct iommu_domain *domain = mmu_specific_pt;
-	if (domain)
-		iommu_domain_free(domain);
+	struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
+	if (iommu_pt->domain)
+		iommu_domain_free(iommu_pt->domain);
+	if (iommu_pt->iommu) {
+		if ((KGSL_IOMMU_ASID_REUSE == iommu_pt->asid) &&
+			iommu_pt->iommu->asid_reuse)
+			iommu_pt->iommu->asid_reuse--;
+		if (!iommu_pt->iommu->asid_reuse ||
+			(KGSL_IOMMU_ASID_REUSE != iommu_pt->asid))
+			clear_bit(iommu_pt->asid, iommu_pt->iommu->asids);
+	}
+	kfree(iommu_pt);
 }
 
+/*
+ * kgsl_iommu_create_pagetable - Create a IOMMU pagetable
+ *
+ * Allocate memory to hold a pagetable and allocate the IOMMU
+ * domain which is the actual IOMMU pagetable
+ * Return - void
+ */
 void *kgsl_iommu_create_pagetable(void)
 {
-	struct iommu_domain *domain = iommu_domain_alloc(0);
-	if (!domain)
-		KGSL_CORE_ERR("Failed to create iommu domain\n");
+	struct kgsl_iommu_pt *iommu_pt;
 
-	return domain;
+	iommu_pt = kzalloc(sizeof(struct kgsl_iommu_pt), GFP_KERNEL);
+	if (!iommu_pt) {
+		KGSL_CORE_ERR("kzalloc(%d) failed\n",
+				sizeof(struct kgsl_iommu_pt));
+		return NULL;
+	}
+	iommu_pt->domain = iommu_domain_alloc(0);
+	if (!iommu_pt->domain) {
+		KGSL_CORE_ERR("Failed to create iommu domain\n");
+		kfree(iommu_pt);
+		return NULL;
+	}
+	return iommu_pt;
 }
 
+/*
+ * kgsl_detach_pagetable_iommu_domain - Detach the IOMMU unit from a
+ * pagetable
+ * @mmu - Pointer to the device mmu structure
+ * @priv - Flag indicating whether the private or user context is to be
+ * detached
+ *
+ * Detach the IOMMU unit with the domain that is contained in the
+ * hwpagetable of the given mmu. After detaching the IOMMU unit is not
+ * in use because the PTBR will not be set after a detach
+ * Return - void
+ */
 static void kgsl_detach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
 {
-	struct iommu_domain *domain;
+	struct kgsl_iommu_pt *iommu_pt;
 	struct kgsl_iommu *iommu = mmu->priv;
-	int i;
+	int i, j;
 
 	BUG_ON(mmu->hwpagetable == NULL);
 	BUG_ON(mmu->hwpagetable->priv == NULL);
 
-	domain = mmu->hwpagetable->priv;
+	iommu_pt = mmu->hwpagetable->priv;
 
-	for (i = 0; i < iommu->dev_count; i++) {
-		iommu_detach_device(domain, iommu->dev[i].dev);
-		iommu->dev[i].attached = 0;
-		KGSL_MEM_INFO(mmu->device,
-			"iommu %p detached from user dev of MMU: %p\n",
-			domain, mmu);
+	for (i = 0; i < iommu->unit_count; i++) {
+		struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+		for (j = 0; j < iommu_unit->dev_count; j++) {
+			if (iommu_unit->dev[j].attached) {
+				iommu_detach_device(iommu_pt->domain,
+						iommu_unit->dev[j].dev);
+				iommu_unit->dev[j].attached = false;
+				KGSL_MEM_INFO(mmu->device, "iommu %p detached "
+					"from user dev of MMU: %p\n",
+					iommu_pt->domain, mmu);
+			}
+		}
 	}
 }
 
+/*
+ * kgsl_attach_pagetable_iommu_domain - Attach the IOMMU unit to a
+ * pagetable, i.e set the IOMMU's PTBR to the pagetable address and
+ * setup other IOMMU registers for the device so that it becomes
+ * active
+ * @mmu - Pointer to the device mmu structure
+ * @priv - Flag indicating whether the private or user context is to be
+ * attached
+ *
+ * Attach the IOMMU unit with the domain that is contained in the
+ * hwpagetable of the given mmu.
+ * Return - 0 on success else error code
+ */
 static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
 {
-	struct iommu_domain *domain;
+	struct kgsl_iommu_pt *iommu_pt;
 	struct kgsl_iommu *iommu = mmu->priv;
-	int i, ret = 0;
+	int i, j, ret = 0;
 
 	BUG_ON(mmu->hwpagetable == NULL);
 	BUG_ON(mmu->hwpagetable->priv == NULL);
 
-	domain = mmu->hwpagetable->priv;
+	iommu_pt = mmu->hwpagetable->priv;
 
-	for (i = 0; i < iommu->dev_count; i++) {
-		if (iommu->dev[i].attached == 0) {
-			ret = iommu_attach_device(domain, iommu->dev[i].dev);
-			if (ret) {
-				KGSL_MEM_ERR(mmu->device,
-					"Failed to attach device, err %d\n",
+	/*
+	 * Loop through all the iommu devcies under all iommu units and
+	 * attach the domain
+	 */
+	for (i = 0; i < iommu->unit_count; i++) {
+		struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+		for (j = 0; j < iommu_unit->dev_count; j++) {
+			if (!iommu_unit->dev[j].attached) {
+				ret = iommu_attach_device(iommu_pt->domain,
+							iommu_unit->dev[j].dev);
+				if (ret) {
+					KGSL_MEM_ERR(mmu->device,
+						"Failed to attach device, err %d\n",
 						ret);
-				goto done;
+					goto done;
+				}
+				iommu_unit->dev[j].attached = true;
+				KGSL_MEM_INFO(mmu->device,
+				"iommu pt %p attached to dev %p, ctx_id %d\n",
+				iommu_pt->domain, iommu_unit->dev[j].dev,
+				iommu_unit->dev[j].ctx_id);
 			}
-
-			iommu->dev[i].attached = 1;
-			KGSL_MEM_INFO(mmu->device,
-				"iommu %p detached from user dev of MMU: %p\n",
-				domain, mmu);
 		}
 	}
-
 done:
 	return ret;
 }
 
-static int _get_iommu_ctxs(struct kgsl_iommu *iommu, struct kgsl_device *device,
-	struct kgsl_device_iommu_data *data)
+/*
+ * _get_iommu_ctxs - Get device pointer to IOMMU contexts
+ * @mmu - Pointer to mmu device
+ * data - Pointer to the platform data containing information about
+ * iommu devices for one iommu unit
+ * unit_id - The IOMMU unit number. This is not a specific ID but just
+ * a serial number. The serial numbers are treated as ID's of the
+ * IOMMU units
+ *
+ * Return - 0 on success else error code
+ */
+static int _get_iommu_ctxs(struct kgsl_mmu *mmu,
+	struct kgsl_device_iommu_data *data, unsigned int unit_id)
 {
+	struct kgsl_iommu *iommu = mmu->priv;
+	struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id];
 	int i;
 
-	for (i = 0; i < data->iommu_ctx_count; i++) {
-		if (iommu->dev_count >= KGSL_IOMMU_MAX_DEV) {
-			KGSL_CORE_ERR("Tried to attach too many IOMMU "
-				"devices\n");
-			return -ENOMEM;
-		}
+	if (data->iommu_ctx_count > KGSL_IOMMU_MAX_DEVS_PER_UNIT) {
+		KGSL_CORE_ERR("Too many iommu devices defined for an "
+				"IOMMU unit\n");
+		return -EINVAL;
+	}
 
-		if (!data->iommu_ctx_names[i])
+	for (i = 0; i < data->iommu_ctx_count; i++) {
+		if (!data->iommu_ctxs[i].iommu_ctx_name)
 			continue;
 
-		iommu->dev[iommu->dev_count].dev =
-			msm_iommu_get_ctx(data->iommu_ctx_names[i]);
-		if (iommu->dev[iommu->dev_count].dev == NULL) {
-			KGSL_CORE_ERR("Failed to iommu dev handle for "
-				"device %s\n", data->iommu_ctx_names[i]);
+		iommu_unit->dev[iommu_unit->dev_count].dev =
+			msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
+		if (iommu_unit->dev[iommu_unit->dev_count].dev == NULL) {
+			KGSL_CORE_ERR("Failed to get iommu dev handle for "
+			"device %s\n", data->iommu_ctxs[i].iommu_ctx_name);
 			return -EINVAL;
 		}
+		if (KGSL_IOMMU_CONTEXT_USER != data->iommu_ctxs[i].ctx_id &&
+			KGSL_IOMMU_CONTEXT_PRIV != data->iommu_ctxs[i].ctx_id) {
+			KGSL_CORE_ERR("Invalid context ID defined: %d\n",
+					data->iommu_ctxs[i].ctx_id);
+			return -EINVAL;
+		}
+		iommu_unit->dev[iommu_unit->dev_count].ctx_id =
+						data->iommu_ctxs[i].ctx_id;
+		KGSL_DRV_INFO(mmu->device,
+				"Obtained dev handle %p for iommu context %s\n",
+				iommu_unit->dev[iommu_unit->dev_count].dev,
+				data->iommu_ctxs[i].iommu_ctx_name);
 
-		iommu->dev_count++;
+		iommu_unit->dev_count++;
 	}
 
 	return 0;
 }
 
-static int kgsl_get_iommu_ctxt(struct kgsl_iommu *iommu,
-				struct kgsl_device *device)
+/*
+ * kgsl_get_iommu_ctxt - Get device pointer to IOMMU contexts
+ * @mmu - Pointer to mmu device
+ *
+ * Get the device pointers for the IOMMU user and priv contexts of the
+ * kgsl device
+ * Return - 0 on success else error code
+ */
+static int kgsl_get_iommu_ctxt(struct kgsl_mmu *mmu)
 {
-	struct kgsl_device_platform_data *pdata =
-		kgsl_device_get_drvdata(device);
+	struct platform_device *pdev =
+		container_of(mmu->device->parentdev, struct platform_device,
+				dev);
+	struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
+	struct kgsl_iommu *iommu = mmu->device->mmu.priv;
 	int i, ret = 0;
 
-	/* Go through the IOMMU data and attach all the domains */
+	/* Go through the IOMMU data and get all the context devices */
+	if (KGSL_IOMMU_MAX_UNITS < pdata_dev->iommu_count) {
+		KGSL_CORE_ERR("Too many IOMMU units defined\n");
+		ret = -EINVAL;
+		goto  done;
+	}
 
-	for (i = 0; i < pdata->iommu_count; i++) {
-		ret = _get_iommu_ctxs(iommu, device,
-			&pdata->iommu_data[i]);
+	for (i = 0; i < pdata_dev->iommu_count; i++) {
+		ret = _get_iommu_ctxs(mmu, &pdata_dev->iommu_data[i], i);
 		if (ret)
 			break;
 	}
-
+	iommu->unit_count = pdata_dev->iommu_count;
+done:
 	return ret;
 }
 
+/*
+ * kgsl_set_register_map - Map the IOMMU regsiters in the memory descriptors
+ * of the respective iommu units
+ * @mmu - Pointer to mmu structure
+ *
+ * Return - 0 on success else error code
+ */
+static int kgsl_set_register_map(struct kgsl_mmu *mmu)
+{
+	struct platform_device *pdev =
+		container_of(mmu->device->parentdev, struct platform_device,
+				dev);
+	struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
+	struct kgsl_iommu *iommu = mmu->device->mmu.priv;
+	struct kgsl_iommu_unit *iommu_unit;
+	int i = 0, ret = 0;
+
+	for (; i < pdata_dev->iommu_count; i++) {
+		struct kgsl_device_iommu_data data = pdata_dev->iommu_data[i];
+		iommu_unit = &iommu->iommu_units[i];
+		/* set up the IOMMU register map for the given IOMMU unit */
+		if (!data.physstart || !data.physend) {
+			KGSL_CORE_ERR("The register range for IOMMU unit not"
+					" specified\n");
+			ret = -EINVAL;
+			goto err;
+		}
+		iommu_unit->reg_map.hostptr = ioremap(data.physstart,
+					data.physend - data.physstart + 1);
+		if (!iommu_unit->reg_map.hostptr) {
+			KGSL_CORE_ERR("Failed to map SMMU register address "
+				"space from %x to %x\n", data.physstart,
+				data.physend - data.physstart + 1);
+			ret = -ENOMEM;
+			i--;
+			goto err;
+		}
+		iommu_unit->reg_map.size = data.physend - data.physstart + 1;
+		iommu_unit->reg_map.physaddr = data.physstart;
+		memdesc_sg_phys(&iommu_unit->reg_map, data.physstart,
+				iommu_unit->reg_map.size);
+	}
+	iommu->unit_count = pdata_dev->iommu_count;
+	return ret;
+err:
+	/* Unmap any mapped IOMMU regions */
+	for (; i >= 0; i--) {
+		iommu_unit = &iommu->iommu_units[i];
+		iounmap(iommu_unit->reg_map.hostptr);
+		iommu_unit->reg_map.size = 0;
+		iommu_unit->reg_map.physaddr = 0;
+	}
+	return ret;
+}
+
+/*
+ * kgsl_iommu_pt_get_base_addr - Get the address of the pagetable that the
+ * IOMMU ttbr0 register is programmed with
+ * @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
+ *
+ * Return - actual pagetable address that the ttbr0 register is programmed
+ * with
+ */
+static unsigned int kgsl_iommu_pt_get_base_addr(struct kgsl_pagetable *pt)
+{
+	struct kgsl_iommu_pt *iommu_pt = pt->priv;
+	return iommu_get_pt_base_addr(iommu_pt->domain);
+}
+
+/*
+ * kgsl_iommu_get_pt_lsb - Return the lsb of the ttbr0 IOMMU register
+ * @mmu - Pointer to mmu structure
+ * @hostptr - Pointer to the IOMMU register map. This is used to match
+ * the iommu device whose lsb value is to be returned
+ * @ctx_id - The context bank whose lsb valus is to be returned
+ * Return - returns the lsb which is the last 14 bits of the ttbr0 IOMMU
+ * register. ttbr0 is the actual PTBR for of the IOMMU. The last 14 bits
+ * are only programmed once in the beginning when a domain is attached
+ * does not change.
+ */
+static int kgsl_iommu_get_pt_lsb(struct kgsl_mmu *mmu,
+				unsigned int unit_id,
+				enum kgsl_iommu_context_id ctx_id)
+{
+	struct kgsl_iommu *iommu = mmu->priv;
+	int i, j;
+	for (i = 0; i < iommu->unit_count; i++) {
+		struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+		for (j = 0; j < iommu_unit->dev_count; j++)
+			if (unit_id == i &&
+				ctx_id == iommu_unit->dev[j].ctx_id)
+				return iommu_unit->dev[j].pt_lsb;
+	}
+	return 0;
+}
+
 static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
 				struct kgsl_pagetable *pagetable)
 {
 	if (mmu->flags & KGSL_FLAGS_STARTED) {
+		struct kgsl_iommu *iommu = mmu->priv;
+		struct kgsl_iommu_pt *iommu_pt = pagetable->priv;
 		/* page table not current, then setup mmu to use new
 		 *  specified page table
 		 */
 		if (mmu->hwpagetable != pagetable) {
-			kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
-			kgsl_detach_pagetable_iommu_domain(mmu);
+			unsigned int flags = 0;
 			mmu->hwpagetable = pagetable;
-			if (mmu->hwpagetable)
-				kgsl_attach_pagetable_iommu_domain(mmu);
+			/* force tlb flush if asid is reused */
+			if (iommu->asid_reuse &&
+				(KGSL_IOMMU_ASID_REUSE == iommu_pt->asid))
+				flags |= KGSL_MMUFLAGS_TLBFLUSH;
+			flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
+							mmu->device->id);
+			kgsl_setstate(mmu, KGSL_MMUFLAGS_PTUPDATE | flags);
 		}
 	}
 }
@@ -199,39 +482,151 @@
 				sizeof(struct kgsl_iommu));
 		return -ENOMEM;
 	}
-
-	status = kgsl_get_iommu_ctxt(iommu, mmu->device);
-	if (status) {
-		kfree(iommu);
-		iommu = NULL;
+	iommu->asids = kzalloc(BITS_TO_LONGS(KGSL_IOMMU_MAX_ASIDS) *
+				sizeof(unsigned long), GFP_KERNEL);
+	if (!iommu->asids) {
+		KGSL_CORE_ERR("kzalloc(%d) failed\n",
+				sizeof(struct kgsl_iommu));
+		status = -ENOMEM;
+		goto done;
 	}
+
 	mmu->priv = iommu;
+	status = kgsl_get_iommu_ctxt(mmu);
+	if (status)
+		goto done;
+	status = kgsl_set_register_map(mmu);
+	if (status)
+		goto done;
 
 	dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
 			__func__);
+done:
+	if (status) {
+		kfree(iommu->asids);
+		kfree(iommu);
+		mmu->priv = NULL;
+	}
+	return status;
+}
+
+/*
+ * kgsl_iommu_setup_defaultpagetable - Setup the initial defualtpagetable
+ * for iommu. This function is only called once during first start, successive
+ * start do not call this funciton.
+ * @mmu - Pointer to mmu structure
+ *
+ * Create the  initial defaultpagetable and setup the iommu mappings to it
+ * Return - 0 on success else error code
+ */
+static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu)
+{
+	int status = 0;
+	int i = 0;
+	struct kgsl_iommu *iommu = mmu->priv;
+	struct kgsl_iommu_pt *iommu_pt;
+
+	mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
+	/* Return error if the default pagetable doesn't exist */
+	if (mmu->defaultpagetable == NULL) {
+		status = -ENOMEM;
+		goto err;
+	}
+	/* Map the IOMMU regsiters to only defaultpagetable */
+	for (i = 0; i < iommu->unit_count; i++) {
+		iommu->iommu_units[i].reg_map.priv |= KGSL_MEMFLAGS_GLOBAL;
+		status = kgsl_mmu_map(mmu->defaultpagetable,
+			&(iommu->iommu_units[i].reg_map),
+			GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+		if (status) {
+			iommu->iommu_units[i].reg_map.priv &=
+							~KGSL_MEMFLAGS_GLOBAL;
+			goto err;
+		}
+	}
+	/*
+	 * The dafault pagetable always has asid 0 assigned by the iommu driver
+	 * and asid 1 is assigned to the private context.
+	 */
+	iommu_pt = mmu->defaultpagetable->priv;
+	iommu_pt->asid = 0;
+	set_bit(0, iommu->asids);
+	set_bit(1, iommu->asids);
+	return status;
+err:
+	for (i--; i >= 0; i--) {
+		kgsl_mmu_unmap(mmu->defaultpagetable,
+				&(iommu->iommu_units[i].reg_map));
+		iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMFLAGS_GLOBAL;
+	}
+	if (mmu->defaultpagetable) {
+		kgsl_mmu_putpagetable(mmu->defaultpagetable);
+		mmu->defaultpagetable = NULL;
+	}
 	return status;
 }
 
 static int kgsl_iommu_start(struct kgsl_mmu *mmu)
 {
 	int status;
+	struct kgsl_iommu *iommu = mmu->priv;
+	int i, j;
 
 	if (mmu->flags & KGSL_FLAGS_STARTED)
 		return 0;
 
+	if (mmu->defaultpagetable == NULL) {
+		status = kgsl_iommu_setup_defaultpagetable(mmu);
+		if (status)
+			return -ENOMEM;
+	}
 	kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
-	if (mmu->defaultpagetable == NULL)
-		mmu->defaultpagetable =
-			kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
-	/* Return error if the default pagetable doesn't exist */
-	if (mmu->defaultpagetable == NULL)
-		return -ENOMEM;
+
 	mmu->hwpagetable = mmu->defaultpagetable;
 
 	status = kgsl_attach_pagetable_iommu_domain(mmu);
-	if (!status)
+	if (!status) {
 		mmu->flags |= KGSL_FLAGS_STARTED;
+	} else {
+		kgsl_detach_pagetable_iommu_domain(mmu);
+		mmu->hwpagetable = NULL;
+	}
+	status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
+	if (status) {
+		KGSL_CORE_ERR("clk enable failed\n");
+		goto done;
+	}
+	status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
+	if (status) {
+		KGSL_CORE_ERR("clk enable failed\n");
+		goto done;
+	}
+	/* Get the lsb value of pagetables set in the IOMMU ttbr0 register as
+	 * that value should not change when we change pagetables, so while
+	 * changing pagetables we can use this lsb value of the pagetable w/o
+	 * having to read it again
+	 */
+	for (i = 0; i < iommu->unit_count; i++) {
+		struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+		for (j = 0; j < iommu_unit->dev_count; j++)
+			iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(
+						KGSL_IOMMU_GET_IOMMU_REG(
+						iommu_unit->reg_map.hostptr,
+						iommu_unit->dev[j].ctx_id,
+						TTBR0));
+	}
+	iommu->asid = KGSL_IOMMU_GET_IOMMU_REG(
+				iommu->iommu_units[0].reg_map.hostptr,
+				KGSL_IOMMU_CONTEXT_USER,
+				CONTEXTIDR);
 
+	kgsl_iommu_disable_clk(mmu);
+
+done:
+	if (status) {
+		kgsl_iommu_disable_clk(mmu);
+		kgsl_detach_pagetable_iommu_domain(mmu);
+	}
 	return status;
 }
 
@@ -241,8 +636,7 @@
 {
 	int ret;
 	unsigned int range = memdesc->size;
-	struct iommu_domain *domain = (struct iommu_domain *)
-					mmu_specific_pt;
+	struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
 
 	/* All GPU addresses as assigned are page aligned, but some
 	   functions purturb the gpuaddr with an offset, so apply the
@@ -253,10 +647,10 @@
 	if (range == 0 || gpuaddr == 0)
 		return 0;
 
-	ret = iommu_unmap_range(domain, gpuaddr, range);
+	ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
 	if (ret)
 		KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
-			"with err: %d\n", domain, gpuaddr,
+			"with err: %d\n", iommu_pt->domain, gpuaddr,
 			range, ret);
 
 	return 0;
@@ -270,20 +664,20 @@
 {
 	int ret;
 	unsigned int iommu_virt_addr;
-	struct iommu_domain *domain = mmu_specific_pt;
+	struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
 
-	BUG_ON(NULL == domain);
+	BUG_ON(NULL == iommu_pt);
 
 
 	iommu_virt_addr = memdesc->gpuaddr;
 
-	ret = iommu_map_range(domain, iommu_virt_addr, memdesc->sg,
-				memdesc->size, 0);
+	ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
+				memdesc->size, (IOMMU_READ | IOMMU_WRITE));
 	if (ret) {
 		KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
-				"failed with err: %d\n", domain,
+				"failed with err: %d\n", iommu_pt->domain,
 				iommu_virt_addr, memdesc->sg, memdesc->size,
-				0, ret);
+				(IOMMU_READ | IOMMU_WRITE), ret);
 		return ret;
 	}
 
@@ -298,7 +692,7 @@
 	return ret;
 }
 
-static int kgsl_iommu_stop(struct kgsl_mmu *mmu)
+static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
 {
 	/*
 	 *  stop device mmu
@@ -309,17 +703,29 @@
 	if (mmu->flags & KGSL_FLAGS_STARTED) {
 		/* detach iommu attachment */
 		kgsl_detach_pagetable_iommu_domain(mmu);
+		mmu->hwpagetable = NULL;
 
 		mmu->flags &= ~KGSL_FLAGS_STARTED;
 	}
-
-	return 0;
 }
 
 static int kgsl_iommu_close(struct kgsl_mmu *mmu)
 {
+	struct kgsl_iommu *iommu = mmu->priv;
+	int i;
+	for (i = 0; i < iommu->unit_count; i++) {
+		if (iommu->iommu_units[i].reg_map.gpuaddr)
+			kgsl_mmu_unmap(mmu->defaultpagetable,
+			&(iommu->iommu_units[i].reg_map));
+		if (iommu->iommu_units[i].reg_map.hostptr)
+			iounmap(iommu->iommu_units[i].reg_map.hostptr);
+		kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
+				iommu->iommu_units[i].reg_map.sglen);
+	}
 	if (mmu->defaultpagetable)
 		kgsl_mmu_putpagetable(mmu->defaultpagetable);
+	kfree(iommu->asids);
+	kfree(iommu);
 
 	return 0;
 }
@@ -327,11 +733,127 @@
 static unsigned int
 kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
 {
-	/* Current base is always the hwpagetables domain as we
-	 * do not use per process pagetables right not for iommu.
-	 * This will change when we switch to per process pagetables.
+	unsigned int pt_base;
+	struct kgsl_iommu *iommu = mmu->priv;
+	/* Return the current pt base by reading IOMMU pt_base register */
+	kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
+	pt_base = readl_relaxed(iommu->iommu_units[0].reg_map.hostptr +
+			(KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
+			KGSL_IOMMU_TTBR0);
+	kgsl_iommu_disable_clk(mmu);
+	return pt_base & (KGSL_IOMMU_TTBR0_PA_MASK <<
+				KGSL_IOMMU_TTBR0_PA_SHIFT);
+}
+
+/*
+ * kgsl_iommu_get_hwpagetable_asid - Returns asid(application space ID) for a
+ * pagetable
+ * @mmu - Pointer to mmu structure
+ *
+ * Allocates an asid to a IOMMU domain if it does not already have one. asid's
+ * are unique identifiers for pagetable that can be used to selectively flush
+ * tlb entries of the IOMMU unit.
+ * Return - asid to be used with the IOMMU domain
+ */
+static int kgsl_iommu_get_hwpagetable_asid(struct kgsl_mmu *mmu)
+{
+	struct kgsl_iommu *iommu = mmu->priv;
+	struct kgsl_iommu_pt *iommu_pt = mmu->hwpagetable->priv;
+
+	/*
+	 * If the iommu pagetable does not have any asid assigned and is not the
+	 * default pagetable then assign asid.
 	 */
-	return (unsigned int)mmu->hwpagetable->priv;
+	if (!iommu_pt->asid && iommu_pt != mmu->defaultpagetable->priv) {
+		iommu_pt->asid = find_first_zero_bit(iommu->asids,
+							KGSL_IOMMU_MAX_ASIDS);
+		/* No free bits means reuse asid */
+		if (iommu_pt->asid >= KGSL_IOMMU_MAX_ASIDS) {
+			iommu_pt->asid = KGSL_IOMMU_ASID_REUSE;
+			iommu->asid_reuse++;
+		}
+		set_bit(iommu_pt->asid, iommu->asids);
+		/*
+		 * Store pointer to asids list so that during pagetable destroy
+		 * the asid assigned to this pagetable may be cleared
+		 */
+		iommu_pt->iommu = iommu;
+	}
+	/* Return the asid + the constant part of asid that never changes */
+	return (iommu_pt->asid & (KGSL_IOMMU_CONTEXTIDR_ASID_MASK <<
+				KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT)) +
+		(iommu->asid & ~(KGSL_IOMMU_CONTEXTIDR_ASID_MASK <<
+				KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT));
+}
+
+/*
+ * kgsl_iommu_default_setstate - Change the IOMMU pagetable or flush IOMMU tlb
+ * of the primary context bank
+ * @mmu - Pointer to mmu structure
+ * @flags - Flags indicating whether pagetable has to chnage or tlb is to be
+ * flushed or both
+ *
+ * Based on flags set the new pagetable fo the IOMMU unit or flush it's tlb or
+ * do both by doing direct register writes to the IOMMu registers through the
+ * cpu
+ * Return - void
+ */
+static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
+					uint32_t flags)
+{
+	struct kgsl_iommu *iommu = mmu->priv;
+	int temp;
+	int i;
+	unsigned int pt_base = kgsl_iommu_pt_get_base_addr(
+					mmu->hwpagetable);
+	unsigned int pt_val;
+
+	if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
+		KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
+		return;
+	}
+	/* Mask off the lsb of the pt base address since lsb will not change */
+	pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK << KGSL_IOMMU_TTBR0_PA_SHIFT);
+	if (flags & KGSL_MMUFLAGS_PTUPDATE) {
+		kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
+		for (i = 0; i < iommu->unit_count; i++) {
+			/* get the lsb value which should not change when
+			 * changing ttbr0 */
+			pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
+						KGSL_IOMMU_CONTEXT_USER);
+			pt_val += pt_base;
+
+			KGSL_IOMMU_SET_IOMMU_REG(
+				iommu->iommu_units[i].reg_map.hostptr,
+				KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
+
+			mb();
+			temp = KGSL_IOMMU_GET_IOMMU_REG(
+				iommu->iommu_units[i].reg_map.hostptr,
+				KGSL_IOMMU_CONTEXT_USER, TTBR0);
+			/* Set asid */
+			KGSL_IOMMU_SET_IOMMU_REG(
+				iommu->iommu_units[i].reg_map.hostptr,
+				KGSL_IOMMU_CONTEXT_USER, CONTEXTIDR,
+				kgsl_iommu_get_hwpagetable_asid(mmu));
+			mb();
+			temp = KGSL_IOMMU_GET_IOMMU_REG(
+					iommu->iommu_units[i].reg_map.hostptr,
+					KGSL_IOMMU_CONTEXT_USER, CONTEXTIDR);
+		}
+	}
+	/* Flush tlb */
+	if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
+		for (i = 0; i < iommu->unit_count; i++) {
+			KGSL_IOMMU_SET_IOMMU_REG(
+				iommu->iommu_units[i].reg_map.hostptr,
+				KGSL_IOMMU_CONTEXT_USER, CTX_TLBIASID,
+				kgsl_iommu_get_hwpagetable_asid(mmu));
+			mb();
+		}
+	}
+	/* Disable smmu clock */
+	kgsl_iommu_disable_clk(mmu);
 }
 
 struct kgsl_mmu_ops iommu_ops = {
@@ -340,9 +862,12 @@
 	.mmu_start = kgsl_iommu_start,
 	.mmu_stop = kgsl_iommu_stop,
 	.mmu_setstate = kgsl_iommu_setstate,
-	.mmu_device_setstate = NULL,
+	.mmu_device_setstate = kgsl_iommu_default_setstate,
 	.mmu_pagefault = NULL,
 	.mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
+	.mmu_enable_clk = kgsl_iommu_enable_clk,
+	.mmu_disable_clk = kgsl_iommu_disable_clk,
+	.mmu_get_hwpagetable_asid = kgsl_iommu_get_hwpagetable_asid,
 };
 
 struct kgsl_mmu_pt_ops iommu_pt_ops = {
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
new file mode 100644
index 0000000..c2e84a6
--- /dev/null
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -0,0 +1,128 @@
+/* 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.
+ *
+ */
+#ifndef __KGSL_IOMMU_H
+#define __KGSL_IOMMU_H
+
+#include <mach/iommu.h>
+
+/* IOMMU registers and masks */
+#define KGSL_IOMMU_TTBR0			0x10
+#define KGSL_IOMMU_TTBR1			0x14
+#define KGSL_IOMMU_TTBR0_PA_MASK		0x0003FFFF
+#define KGSL_IOMMU_TTBR0_PA_SHIFT		14
+#define KGSL_IOMMU_CTX_TLBIALL			0x800
+#define KGSL_IOMMU_CONTEXTIDR			0x8
+#define KGSL_IOMMU_CONTEXTIDR_ASID_MASK		0xFF
+#define KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT	0
+#define KGSL_IOMMU_CTX_TLBIASID			0x804
+#define KGSL_IOMMU_CTX_SHIFT			12
+
+#define KGSL_IOMMU_MAX_ASIDS			256
+#define KGSL_IOMMU_ASID_REUSE			2
+
+/*
+ * Max number of iommu units that the gpu core can have
+ * On APQ8064, KGSL can control a maximum of 2 IOMMU units.
+ */
+#define KGSL_IOMMU_MAX_UNITS 2
+
+/* Max number of iommu contexts per IOMMU unit */
+#define KGSL_IOMMU_MAX_DEVS_PER_UNIT 2
+
+/* Macros to read/write IOMMU registers */
+#define KGSL_IOMMU_SET_IOMMU_REG(base_addr, ctx, REG, val)		\
+		writel_relaxed(val, base_addr +				\
+				(ctx << KGSL_IOMMU_CTX_SHIFT) +		\
+				KGSL_IOMMU_##REG)
+
+#define KGSL_IOMMU_GET_IOMMU_REG(base_addr, ctx, REG)			\
+		readl_relaxed(base_addr +				\
+			(ctx << KGSL_IOMMU_CTX_SHIFT) +			\
+			KGSL_IOMMU_##REG)
+
+/* Gets the lsb value of pagetable */
+#define KGSL_IOMMMU_PT_LSB(pt_val)					\
+		(pt_val & ~(KGSL_IOMMU_TTBR0_PA_MASK <<			\
+				KGSL_IOMMU_TTBR0_PA_SHIFT))
+
+/*
+ * struct kgsl_iommu_device - Structure holding data about iommu contexts
+ * @dev: Device pointer to iommu context
+ * @attached: Indicates whether this iommu context is presently attached to
+ * a pagetable/domain or not
+ * @pt_lsb: The LSB of IOMMU_TTBR0 register which is the pagetable
+ * register
+ * @ctx_id: This iommu units context id. It can be either 0 or 1
+ * @clk_enabled: If set indicates that iommu clocks of this iommu context
+ * are on, else the clocks are off
+ */
+struct kgsl_iommu_device {
+	struct device *dev;
+	bool attached;
+	unsigned int pt_lsb;
+	enum kgsl_iommu_context_id ctx_id;
+	bool clk_enabled;
+};
+
+/*
+ * struct kgsl_iommu_unit - Structure holding data about iommu units. An IOMMU
+ * units is basically a separte IOMMU h/w block with it's own IOMMU contexts
+ * @dev: Pointer to array of struct kgsl_iommu_device which has information
+ * about the IOMMU contexts under this IOMMU unit
+ * @dev_count: Number of IOMMU contexts that are valid in the previous feild
+ * @reg_map: Memory descriptor which holds the mapped address of this IOMMU
+ * units register range
+ */
+struct kgsl_iommu_unit {
+	struct kgsl_iommu_device dev[KGSL_IOMMU_MAX_DEVS_PER_UNIT];
+	unsigned int dev_count;
+	struct kgsl_memdesc reg_map;
+};
+
+/*
+ * struct kgsl_iommu - Structure holding iommu data for kgsl driver
+ * @dev: Array of kgsl_iommu_device which contain information about
+ * iommu contexts owned by graphics cores
+ * @unit_count: Number of IOMMU units that are available for this
+ * instance of the IOMMU driver
+ * @iommu_last_cmd_ts: The timestamp of last command submitted that
+ * aceeses iommu registers
+ * @device: Pointer to kgsl device
+ * @asids: A bit structure indicating which id's are presently used
+ * @asid: Contains the initial value of IOMMU_CONTEXTIDR when a domain
+ * is first attached
+ * asid_reuse: Holds the number of times the reuse asid is reused
+ */
+struct kgsl_iommu {
+	struct kgsl_iommu_unit iommu_units[KGSL_IOMMU_MAX_UNITS];
+	unsigned int unit_count;
+	unsigned int iommu_last_cmd_ts;
+	struct kgsl_device *device;
+	unsigned long *asids;
+	unsigned int asid;
+	unsigned int asid_reuse;
+};
+
+/*
+ * struct kgsl_iommu_pt - Iommu pagetable structure private to kgsl driver
+ * @domain: Pointer to the iommu domain that contains the iommu pagetable
+ * @iommu: Pointer to iommu structure
+ * @asid: The asid assigned to this domain
+ */
+struct kgsl_iommu_pt {
+	struct iommu_domain *domain;
+	struct kgsl_iommu *iommu;
+	unsigned int asid;
+};
+
+#endif
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 2b359ec..606d861 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -322,16 +322,6 @@
 		return 0;
 }
 
-unsigned int kgsl_mmu_get_current_ptbase(struct kgsl_device *device)
-{
-	struct kgsl_mmu *mmu = &device->mmu;
-	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
-		return 0;
-	else
-		return mmu->mmu_ops->mmu_get_current_ptbase(mmu);
-}
-EXPORT_SYMBOL(kgsl_mmu_get_current_ptbase);
-
 int
 kgsl_mmu_get_ptname_from_ptbase(unsigned int pt_base)
 {
@@ -351,41 +341,32 @@
 }
 EXPORT_SYMBOL(kgsl_mmu_get_ptname_from_ptbase);
 
-void kgsl_mmu_setstate(struct kgsl_device *device,
-			struct kgsl_pagetable *pagetable)
-{
-	struct kgsl_mmu *mmu = &device->mmu;
-
-	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
-		return;
-	else
-		mmu->mmu_ops->mmu_setstate(mmu,
-					pagetable);
-}
-EXPORT_SYMBOL(kgsl_mmu_setstate);
-
 int kgsl_mmu_init(struct kgsl_device *device)
 {
+	int status = 0;
 	struct kgsl_mmu *mmu = &device->mmu;
 
 	mmu->device = device;
+	status = kgsl_allocate_contiguous(&mmu->setstate_memory, PAGE_SIZE);
+	if (status)
+		return status;
+	kgsl_sharedmem_set(&mmu->setstate_memory, 0, 0,
+				mmu->setstate_memory.size);
 
 	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type) {
-		int status = 0;
-		status = kgsl_allocate_contiguous(&mmu->setstate_memory, 64);
-		if (!status) {
-			kgsl_sharedmem_set(&mmu->setstate_memory, 0, 0,
-					mmu->setstate_memory.size);
-			dev_info(device->dev, "|%s| MMU type set for device is "
+		dev_info(device->dev, "|%s| MMU type set for device is "
 				"NOMMU\n", __func__);
-		}
-		return status;
+		goto done;
 	} else if (KGSL_MMU_TYPE_GPU == kgsl_mmu_type)
 		mmu->mmu_ops = &gpummu_ops;
 	else if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type)
 		mmu->mmu_ops = &iommu_ops;
 
-	return mmu->mmu_ops->mmu_init(mmu);
+	status =  mmu->mmu_ops->mmu_init(mmu);
+done:
+	if (status)
+		kgsl_sharedmem_free(&mmu->setstate_memory);
+	return status;
 }
 EXPORT_SYMBOL(kgsl_mmu_init);
 
@@ -405,18 +386,35 @@
 }
 EXPORT_SYMBOL(kgsl_mmu_start);
 
+static void mh_axi_error(struct kgsl_device *device, const char* type)
+{
+	unsigned int reg, gpu_err, phys_err, pt_base;
+
+	kgsl_regread(device, MH_AXI_ERROR, &reg);
+	pt_base = kgsl_mmu_get_current_ptbase(&device->mmu);
+	/*
+	 * Read gpu virtual and physical addresses that
+	 * caused the error from the debug data.
+	 */
+	kgsl_regwrite(device, MH_DEBUG_CTRL, 44);
+	kgsl_regread(device, MH_DEBUG_DATA, &gpu_err);
+	kgsl_regwrite(device, MH_DEBUG_CTRL, 45);
+	kgsl_regread(device, MH_DEBUG_DATA, &phys_err);
+	KGSL_MEM_CRIT(device,
+			"axi %s error: %08x pt %08x gpu %08x phys %08x\n",
+			type, reg, pt_base, gpu_err, phys_err);
+}
+
 void kgsl_mh_intrcallback(struct kgsl_device *device)
 {
 	unsigned int status = 0;
-	unsigned int reg;
 
 	kgsl_regread(device, MH_INTERRUPT_STATUS, &status);
-	kgsl_regread(device, MH_AXI_ERROR, &reg);
 
 	if (status & MH_INTERRUPT_MASK__AXI_READ_ERROR)
-		KGSL_MEM_CRIT(device, "axi read error interrupt: %08x\n", reg);
+		mh_axi_error(device, "read");
 	if (status & MH_INTERRUPT_MASK__AXI_WRITE_ERROR)
-		KGSL_MEM_CRIT(device, "axi write error interrupt: %08x\n", reg);
+		mh_axi_error(device, "write");
 	if (status & MH_INTERRUPT_MASK__MMU_PAGE_FAULT)
 		device->mmu.mmu_ops->mmu_pagefault(&device->mmu);
 
@@ -523,11 +521,8 @@
 	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
 		return (void *)(-1);
 
-#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
-	if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type)
-		name = KGSL_MMU_GLOBAL_PT;
-#else
-		name = KGSL_MMU_GLOBAL_PT;
+#ifndef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
+	name = KGSL_MMU_GLOBAL_PT;
 #endif
 	pt = kgsl_get_pagetable(name);
 
@@ -548,23 +543,14 @@
 	struct kgsl_device *device = mmu->device;
 	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
 		return;
-	else if (device->ftbl->setstate)
+	else if (device->ftbl->setstate && (KGSL_MMU_TYPE_IOMMU !=
+						kgsl_mmu_type))
 		device->ftbl->setstate(device, flags);
 	else if (mmu->mmu_ops->mmu_device_setstate)
 		mmu->mmu_ops->mmu_device_setstate(mmu, flags);
 }
 EXPORT_SYMBOL(kgsl_setstate);
 
-void kgsl_mmu_device_setstate(struct kgsl_device *device, uint32_t flags)
-{
-	struct kgsl_mmu *mmu = &device->mmu;
-	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
-		return;
-	else if (mmu->mmu_ops->mmu_device_setstate)
-		mmu->mmu_ops->mmu_device_setstate(mmu, flags);
-}
-EXPORT_SYMBOL(kgsl_mmu_device_setstate);
-
 void kgsl_mh_start(struct kgsl_device *device)
 {
 	struct kgsl_mh *mh = &device->mh;
@@ -746,27 +732,15 @@
 }
 EXPORT_SYMBOL(kgsl_mmu_map_global);
 
-int kgsl_mmu_stop(struct kgsl_device *device)
-{
-	struct kgsl_mmu *mmu = &device->mmu;
-
-	if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE)
-		return 0;
-	else
-		return mmu->mmu_ops->mmu_stop(mmu);
-}
-EXPORT_SYMBOL(kgsl_mmu_stop);
-
 int kgsl_mmu_close(struct kgsl_device *device)
 {
 	struct kgsl_mmu *mmu = &device->mmu;
 
-	if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) {
-		kgsl_sharedmem_free(&mmu->setstate_memory);
+	kgsl_sharedmem_free(&mmu->setstate_memory);
+	if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE)
 		return 0;
-	} else {
+	else
 		return mmu->mmu_ops->mmu_close(mmu);
-	}
 }
 EXPORT_SYMBOL(kgsl_mmu_close);
 
@@ -814,16 +788,6 @@
 }
 EXPORT_SYMBOL(kgsl_mmu_enabled);
 
-int kgsl_mmu_pt_equal(struct kgsl_pagetable *pt,
-			unsigned int pt_base)
-{
-	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
-		return true;
-	else
-		return pt->pt_ops->mmu_pt_equal(pt, pt_base);
-}
-EXPORT_SYMBOL(kgsl_mmu_pt_equal);
-
 enum kgsl_mmutype kgsl_mmu_get_mmutype(void)
 {
 	return kgsl_mmu_type;
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index e35f368..24eaba4 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -122,7 +122,7 @@
 	int (*mmu_init) (struct kgsl_mmu *mmu);
 	int (*mmu_close) (struct kgsl_mmu *mmu);
 	int (*mmu_start) (struct kgsl_mmu *mmu);
-	int (*mmu_stop) (struct kgsl_mmu *mmu);
+	void (*mmu_stop) (struct kgsl_mmu *mmu);
 	void (*mmu_setstate) (struct kgsl_mmu *mmu,
 		struct kgsl_pagetable *pagetable);
 	void (*mmu_device_setstate) (struct kgsl_mmu *mmu,
@@ -130,6 +130,11 @@
 	void (*mmu_pagefault) (struct kgsl_mmu *mmu);
 	unsigned int (*mmu_get_current_ptbase)
 			(struct kgsl_mmu *mmu);
+	void (*mmu_disable_clk)
+		(struct kgsl_mmu *mmu);
+	int (*mmu_enable_clk)
+		(struct kgsl_mmu *mmu, int ctx_id);
+	int (*mmu_get_hwpagetable_asid)(struct kgsl_mmu *mmu);
 };
 
 struct kgsl_mmu_pt_ops {
@@ -169,7 +174,6 @@
 void kgsl_mh_intrcallback(struct kgsl_device *device);
 int kgsl_mmu_init(struct kgsl_device *device);
 int kgsl_mmu_start(struct kgsl_device *device);
-int kgsl_mmu_stop(struct kgsl_device *device);
 int kgsl_mmu_close(struct kgsl_device *device);
 int kgsl_mmu_map(struct kgsl_pagetable *pagetable,
 		 struct kgsl_memdesc *memdesc,
@@ -180,19 +184,57 @@
 		    struct kgsl_memdesc *memdesc);
 unsigned int kgsl_virtaddr_to_physaddr(void *virtaddr);
 void kgsl_setstate(struct kgsl_mmu *mmu, uint32_t flags);
-void kgsl_mmu_device_setstate(struct kgsl_device *device, uint32_t flags);
-void kgsl_mmu_setstate(struct kgsl_device *device,
-			struct kgsl_pagetable *pt);
 int kgsl_mmu_get_ptname_from_ptbase(unsigned int pt_base);
 int kgsl_mmu_pt_get_flags(struct kgsl_pagetable *pt,
 			enum kgsl_deviceid id);
 void kgsl_mmu_ptpool_destroy(void *ptpool);
 void *kgsl_mmu_ptpool_init(int entries);
 int kgsl_mmu_enabled(void);
-int kgsl_mmu_pt_equal(struct kgsl_pagetable *pt,
-			unsigned int pt_base);
 void kgsl_mmu_set_mmutype(char *mmutype);
-unsigned int kgsl_mmu_get_current_ptbase(struct kgsl_device *device);
 enum kgsl_mmutype kgsl_mmu_get_mmutype(void);
 unsigned int kgsl_mmu_get_ptsize(void);
+
+/*
+ * Static inline functions of MMU that simply call the SMMU specific
+ * function using a function pointer. These functions can be thought
+ * of as wrappers around the actual function
+ */
+
+static inline unsigned int kgsl_mmu_get_current_ptbase(struct kgsl_mmu *mmu)
+{
+	if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_current_ptbase)
+		return mmu->mmu_ops->mmu_get_current_ptbase(mmu);
+	else
+		return 0;
+}
+
+static inline void kgsl_mmu_setstate(struct kgsl_mmu *mmu,
+			struct kgsl_pagetable *pagetable)
+{
+	if (mmu->mmu_ops && mmu->mmu_ops->mmu_setstate)
+		mmu->mmu_ops->mmu_setstate(mmu, pagetable);
+}
+
+static inline void kgsl_mmu_device_setstate(struct kgsl_mmu *mmu,
+						uint32_t flags)
+{
+	if (mmu->mmu_ops && mmu->mmu_ops->mmu_device_setstate)
+		mmu->mmu_ops->mmu_device_setstate(mmu, flags);
+}
+
+static inline void kgsl_mmu_stop(struct kgsl_mmu *mmu)
+{
+	if (mmu->mmu_ops && mmu->mmu_ops->mmu_stop)
+		mmu->mmu_ops->mmu_stop(mmu);
+}
+
+static inline int kgsl_mmu_pt_equal(struct kgsl_pagetable *pt,
+			unsigned int pt_base)
+{
+	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_get_mmutype())
+		return 1;
+	else
+		return pt->pt_ops->mmu_pt_equal(pt, pt_base);
+}
+
 #endif /* __KGSL_MMU_H */
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 6fa7da2..3a29d71 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -11,6 +11,7 @@
  *
  */
 #include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
 #include <mach/msm_iomap.h>
 #include <mach/msm_bus.h>
 
@@ -403,7 +404,7 @@
 			trace_kgsl_bus(device, state);
 			if (pwr->ebi1_clk) {
 				clk_set_rate(pwr->ebi1_clk, 0);
-				clk_disable(pwr->ebi1_clk);
+				clk_disable_unprepare(pwr->ebi1_clk);
 			}
 			if (pwr->pcl)
 				msm_bus_scale_client_update_request(pwr->pcl,
@@ -414,7 +415,7 @@
 			&pwr->power_flags)) {
 			trace_kgsl_bus(device, state);
 			if (pwr->ebi1_clk) {
-				clk_enable(pwr->ebi1_clk);
+				clk_prepare_enable(pwr->ebi1_clk);
 				clk_set_rate(pwr->ebi1_clk,
 					pwr->pwrlevels[pwr->active_pwrlevel].
 					bus_freq);
@@ -522,7 +523,7 @@
 		clk_set_rate(pwr->grp_clks[0], pwr->
 				pwrlevels[pwr->num_pwrlevels - 1].gpu_freq);
 
-	pwr->gpu_reg = regulator_get(NULL, pwr->regulator_name);
+	pwr->gpu_reg = regulator_get(&pdev->dev, "vdd");
 	if (IS_ERR(pwr->gpu_reg))
 		pwr->gpu_reg = NULL;
 
@@ -552,17 +553,8 @@
 		}
 	}
 
-	/*acquire interrupt */
-	pwr->interrupt_num =
-		platform_get_irq_byname(pdev, pwr->irq_name);
 
-	if (pwr->interrupt_num <= 0) {
-		KGSL_PWR_ERR(device, "platform_get_irq_byname failed: %d\n",
-					 pwr->interrupt_num);
-		result = -EINVAL;
-		goto done;
-	}
-
+	pm_runtime_enable(device->parentdev);
 	register_early_suspend(&device->display_off);
 	return result;
 
@@ -582,16 +574,9 @@
 
 	KGSL_PWR_INFO(device, "close device %d\n", device->id);
 
+	pm_runtime_disable(device->parentdev);
 	unregister_early_suspend(&device->display_off);
 
-	if (pwr->interrupt_num > 0) {
-		if (pwr->have_irq) {
-			free_irq(pwr->interrupt_num, NULL);
-			pwr->have_irq = 0;
-		}
-		pwr->interrupt_num = 0;
-	}
-
 	clk_put(pwr->ebi1_clk);
 
 	if (pwr->pcl)
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index a677fec..1e5c21c 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -39,7 +39,6 @@
 
 struct kgsl_pwrctrl {
 	int interrupt_num;
-	int have_irq;
 	struct clk *ebi1_clk;
 	struct clk *grp_clks[KGSL_MAX_CLKS];
 	unsigned long power_flags;
@@ -54,7 +53,6 @@
 	uint32_t pcl;
 	unsigned int nap_allowed;
 	unsigned int idle_needed;
-	const char *regulator_name;
 	const char *irq_name;
 	s64 time;
 	struct kgsl_busy busy;
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index e0825c3..4daff5f 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -180,7 +180,8 @@
 	struct tz_priv *priv;
 
 	/* Trustzone is only valid for some SOCs */
-	if (!(cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064()))
+	if (!(cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064() ||
+		cpu_is_msm8930()))
 		return -EINVAL;
 
 	priv = pwrscale->priv = kzalloc(sizeof(struct tz_priv), GFP_KERNEL);
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 24ea571..f61c74f 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -122,7 +122,7 @@
 	header->current_context = -1;
 
 	/* Get the current PT base */
-	header->ptbase = kgsl_mmu_get_current_ptbase(device);
+	header->ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
 	/* And the PID for the task leader */
 	pid = header->pid = kgsl_mmu_get_ptname_from_ptbase(header->ptbase);
 
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 3ca9e18..846a9a1 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -132,10 +132,9 @@
 
 static struct z180_device device_2d0 = {
 	.dev = {
+		KGSL_DEVICE_COMMON_INIT(device_2d0.dev),
 		.name = DEVICE_2D0_NAME,
 		.id = KGSL_DEVICE_2D0,
-		.ver_major = DRIVER_VERSION_MAJOR,
-		.ver_minor = DRIVER_VERSION_MINOR,
 		.mh = {
 			.mharb = Z180_CFG_MHARB,
 			.mh_intf_cfg1 = 0x00032f07,
@@ -150,30 +149,19 @@
 			.config = Z180_MMU_CONFIG,
 		},
 		.pwrctrl = {
-			.regulator_name = "fs_gfx2d0",
 			.irq_name = KGSL_2D0_IRQ,
 		},
-		.mutex = __MUTEX_INITIALIZER(device_2d0.dev.mutex),
-		.state = KGSL_STATE_INIT,
-		.active_cnt = 0,
 		.iomemname = KGSL_2D0_REG_MEMORY,
 		.ftbl = &z180_functable,
-#ifdef CONFIG_HAS_EARLYSUSPEND
-		.display_off = {
-			.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING,
-			.suspend = kgsl_early_suspend_driver,
-			.resume = kgsl_late_resume_driver,
-		},
-#endif
 	},
+	.cmdwin_lock = __SPIN_LOCK_INITIALIZER(device_2d1.cmdwin_lock),
 };
 
 static struct z180_device device_2d1 = {
 	.dev = {
+		KGSL_DEVICE_COMMON_INIT(device_2d1.dev),
 		.name = DEVICE_2D1_NAME,
 		.id = KGSL_DEVICE_2D1,
-		.ver_major = DRIVER_VERSION_MAJOR,
-		.ver_minor = DRIVER_VERSION_MINOR,
 		.mh = {
 			.mharb = Z180_CFG_MHARB,
 			.mh_intf_cfg1 = 0x00032f07,
@@ -188,22 +176,12 @@
 			.config = Z180_MMU_CONFIG,
 		},
 		.pwrctrl = {
-			.regulator_name = "fs_gfx2d1",
 			.irq_name = KGSL_2D1_IRQ,
 		},
-		.mutex = __MUTEX_INITIALIZER(device_2d1.dev.mutex),
-		.state = KGSL_STATE_INIT,
-		.active_cnt = 0,
 		.iomemname = KGSL_2D1_REG_MEMORY,
 		.ftbl = &z180_functable,
-		.display_off = {
-#ifdef CONFIG_HAS_EARLYSUSPEND
-			.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING,
-			.suspend = kgsl_early_suspend_driver,
-			.resume = kgsl_late_resume_driver,
-#endif
-		},
 	},
+	.cmdwin_lock = __SPIN_LOCK_INITIALIZER(device_2d1.cmdwin_lock),
 };
 
 static irqreturn_t z180_irq_handler(struct kgsl_device *device)
@@ -464,7 +442,7 @@
 	    (ctrl & KGSL_CONTEXT_CTX_SWITCH)) {
 		KGSL_CMD_INFO(device, "context switch %d -> %d\n",
 			context->id, z180_dev->ringbuffer.prevctx);
-		kgsl_mmu_setstate(device, pagetable);
+		kgsl_mmu_setstate(&device->mmu, pagetable);
 		cnt = PACKETSIZE_STATESTREAM;
 		ofs = 0;
 	}
@@ -540,7 +518,6 @@
 	device->parentdev = &pdev->dev;
 
 	z180_dev = Z180_DEVICE(device);
-	spin_lock_init(&z180_dev->cmdwin_lock);
 
 	status = z180_ringbuffer_init(device);
 	if (status != 0)
@@ -613,7 +590,7 @@
 
 	del_timer_sync(&device->idle_timer);
 
-	kgsl_mmu_stop(device);
+	kgsl_mmu_stop(&device->mmu);
 
 	/* Disable the clocks before the power rail. */
 	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index c7aa2ce..dc1feaa 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -2,6 +2,7 @@
  *  GPIO driven matrix keyboard driver
  *
  *  Copyright (c) 2008 Marek Vasut <marek.vasut@gmail.com>
+ *  Copyright (c) 2012, Code Aurora Forum. All rights reserved.
  *
  *  Based on corgikbd.c
  *
@@ -34,7 +35,7 @@
 
 	uint32_t last_key_state[MATRIX_MAX_COLS];
 	struct delayed_work work;
-	spinlock_t lock;
+	struct mutex lock;
 	bool scan_pending;
 	bool stopped;
 	bool gpio_all_disabled;
@@ -162,19 +163,17 @@
 
 	activate_all_cols(pdata, true);
 
-	/* Enable IRQs again */
-	spin_lock_irq(&keypad->lock);
+	mutex_lock(&keypad->lock);
 	keypad->scan_pending = false;
 	enable_row_irqs(keypad);
-	spin_unlock_irq(&keypad->lock);
+	mutex_unlock(&keypad->lock);
 }
 
 static irqreturn_t matrix_keypad_interrupt(int irq, void *id)
 {
 	struct matrix_keypad *keypad = id;
-	unsigned long flags;
 
-	spin_lock_irqsave(&keypad->lock, flags);
+	mutex_lock(&keypad->lock);
 
 	/*
 	 * See if another IRQ beaten us to it and scheduled the
@@ -190,7 +189,7 @@
 		msecs_to_jiffies(keypad->pdata->debounce_ms));
 
 out:
-	spin_unlock_irqrestore(&keypad->lock, flags);
+	mutex_unlock(&keypad->lock);
 	return IRQ_HANDLED;
 }
 
@@ -341,10 +340,11 @@
 		}
 	} else {
 		for (i = 0; i < pdata->num_row_gpios; i++) {
-			err = request_any_context_irq(
+			err = request_threaded_irq(
 					gpio_to_irq(pdata->row_gpios[i]),
+					NULL,
 					matrix_keypad_interrupt,
-					IRQF_DISABLED |
+					IRQF_DISABLED | IRQF_ONESHOT |
 					IRQF_TRIGGER_RISING |
 					IRQF_TRIGGER_FALLING,
 					"matrix-keypad", keypad);
@@ -417,7 +417,7 @@
 	keypad->row_shift = row_shift;
 	keypad->stopped = true;
 	INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan);
-	spin_lock_init(&keypad->lock);
+	mutex_init(&keypad->lock);
 
 	input_dev->name		= pdev->name;
 	input_dev->id.bustype	= BUS_HOST;
@@ -479,6 +479,7 @@
 	for (i = 0; i < pdata->num_col_gpios; i++)
 		gpio_free(pdata->col_gpios[i]);
 
+	mutex_destroy(&keypad->lock);
 	input_unregister_device(keypad->input_dev);
 	platform_set_drvdata(pdev, NULL);
 	kfree(keypad->keycodes);
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 60c200e..4706c1c 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -194,6 +194,18 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called leds-msm-pdm.
 
+config LEDS_PMIC_MPP
+        tristate "LED Support for Qualcomm PMIC MPP connected LEDs"
+        depends on LEDS_CLASS && MSM_SMD
+        help
+          This option enables support for LEDs connected to  PMIC MPPs
+	  on Qualcomm reference boards.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called leds-pmic-mpp.
+
 config LEDS_GPIO_PLATFORM
 	bool "Platform device bindings for GPIO LEDs"
 	depends on LEDS_GPIO
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 819abc0..de6dcd1 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -47,6 +47,7 @@
 obj-$(CONFIG_LEDS_NETXBIG)		+= leds-netxbig.o
 obj-$(CONFIG_LEDS_ASIC3)		+= leds-asic3.o
 obj-$(CONFIG_LEDS_PMIC8058)		+= leds-pmic8058.o
+obj-$(CONFIG_LEDS_PMIC_MPP)		+= leds-pmic-mpp.o
 obj-$(CONFIG_LEDS_QCIBL)		+= leds-qci-backlight.o
 obj-$(CONFIG_LEDS_MSM_PDM)		+= leds-msm-pdm.o
 
diff --git a/drivers/leds/leds-pmic-mpp.c b/drivers/leds/leds-pmic-mpp.c
new file mode 100644
index 0000000..0de41de
--- /dev/null
+++ b/drivers/leds/leds-pmic-mpp.c
@@ -0,0 +1,140 @@
+/* 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+
+#include <mach/pmic.h>
+
+#define LED_MPP(x)		((x) & 0xFF)
+#define LED_CURR(x)		((x) >> 16)
+
+struct pmic_mpp_led_data {
+	struct led_classdev cdev;
+	int curr;
+	int mpp;
+};
+
+static void pm_mpp_led_set(struct led_classdev *led_cdev,
+	enum led_brightness value)
+{
+	struct pmic_mpp_led_data *led;
+	int ret;
+
+	led = container_of(led_cdev, struct pmic_mpp_led_data, cdev);
+
+	if (value < LED_OFF || value > led->cdev.max_brightness) {
+		dev_err(led->cdev.dev, "Invalid brightness value");
+		return;
+	}
+
+	ret = pmic_secure_mpp_config_i_sink(led->mpp, led->curr,
+			value ? PM_MPP__I_SINK__SWITCH_ENA :
+				PM_MPP__I_SINK__SWITCH_DIS);
+	if (ret)
+		dev_err(led_cdev->dev, "can't set mpp led\n");
+}
+
+static int pmic_mpp_led_probe(struct platform_device *pdev)
+{
+	const struct led_platform_data *pdata = pdev->dev.platform_data;
+	struct pmic_mpp_led_data *led, *tmp_led;
+	int i, rc;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "platform data not supplied\n");
+		return -EINVAL;
+	}
+
+	led = kcalloc(pdata->num_leds, sizeof(*led), GFP_KERNEL);
+	if (!led) {
+		dev_err(&pdev->dev, "failed to alloc memory\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pdev, led);
+
+	for (i = 0; i < pdata->num_leds; i++) {
+		tmp_led	= &led[i];
+		tmp_led->cdev.name = pdata->leds[i].name;
+		tmp_led->cdev.brightness_set = pm_mpp_led_set;
+		tmp_led->cdev.brightness = LED_OFF;
+		tmp_led->cdev.max_brightness = LED_FULL;
+		tmp_led->mpp = LED_MPP(pdata->leds[i].flags);
+		tmp_led->curr = LED_CURR(pdata->leds[i].flags);
+
+		if (tmp_led->curr < PM_MPP__I_SINK__LEVEL_5mA ||
+			tmp_led->curr > PM_MPP__I_SINK__LEVEL_40mA) {
+			dev_err(&pdev->dev, "invalid current\n");
+			goto unreg_led_cdev;
+		}
+
+		rc = led_classdev_register(&pdev->dev, &tmp_led->cdev);
+		if (rc) {
+			dev_err(&pdev->dev, "failed to register led\n");
+			goto unreg_led_cdev;
+		}
+	}
+
+	return 0;
+
+unreg_led_cdev:
+	while (i)
+		led_classdev_unregister(&led[--i].cdev);
+
+	kfree(led);
+	return rc;
+
+}
+
+static int __devexit pmic_mpp_led_remove(struct platform_device *pdev)
+{
+	const struct led_platform_data *pdata = pdev->dev.platform_data;
+	struct pmic_mpp_led_data *led = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < pdata->num_leds; i++)
+		led_classdev_unregister(&led[i].cdev);
+
+	kfree(led);
+
+	return 0;
+}
+
+static struct platform_driver pmic_mpp_led_driver = {
+	.probe		= pmic_mpp_led_probe,
+	.remove		= __devexit_p(pmic_mpp_led_remove),
+	.driver		= {
+		.name	= "pmic-mpp-leds",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init pmic_mpp_led_init(void)
+{
+	return platform_driver_register(&pmic_mpp_led_driver);
+}
+module_init(pmic_mpp_led_init);
+
+static void __exit pmic_mpp_led_exit(void)
+{
+	platform_driver_unregister(&pmic_mpp_led_driver);
+}
+module_exit(pmic_mpp_led_exit);
+
+MODULE_DESCRIPTION("PMIC MPP LEDs driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:pmic-mpp-leds");
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
index ee214c3..f41a4ef 100644
--- a/drivers/media/dvb/Kconfig
+++ b/drivers/media/dvb/Kconfig
@@ -84,4 +84,8 @@
 	depends on DVB_CORE
 source "drivers/media/dvb/frontends/Kconfig"
 
+comment "Qualcomm MPQ adapter"
+	depends on ARCH_MSM && DVB_CORE
+source "drivers/media/dvb/mpq/Kconfig"
+
 endif # DVB_CAPTURE_DRIVERS
diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile
index a1a0875..68877c8 100644
--- a/drivers/media/dvb/Makefile
+++ b/drivers/media/dvb/Makefile
@@ -18,3 +18,5 @@
 		ngene/
 
 obj-$(CONFIG_DVB_FIREDTV)	+= firewire/
+obj-$(CONFIG_DVB_MPQ)		+= mpq/
+
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index eb91fd8..ff0c9d8 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -7,6 +7,8 @@
  * Copyright (c) 2000 Nokia Research Center
  *                    Tampere, FINLAND
  *
+ * 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 Lesser General Public License
  * as published by the Free Software Foundation; either version 2.1
@@ -190,6 +192,14 @@
 				struct dmx_section_filter * source,
 				enum dmx_success success);
 
+typedef int (*dmx_ts_fullness) (
+				struct dmx_ts_feed *source,
+				int required_space);
+
+typedef int (*dmx_section_fullness) (
+				struct dmx_section_filter *source,
+				int required_space);
+
 /*--------------------------------------------------------------------------*/
 /* DVB Front-End */
 /*--------------------------------------------------------------------------*/
@@ -247,7 +257,7 @@
 	void* priv;                  /* Pointer to private data of the API client */
 	int (*open) (struct dmx_demux* demux);
 	int (*close) (struct dmx_demux* demux);
-	int (*write) (struct dmx_demux* demux, const char __user *buf, size_t count);
+	int (*write) (struct dmx_demux *demux, const char *buf, size_t count);
 	int (*allocate_ts_feed) (struct dmx_demux* demux,
 				 struct dmx_ts_feed** feed,
 				 dmx_ts_cb callback);
@@ -271,7 +281,20 @@
 
 	int (*get_caps) (struct dmx_demux* demux, struct dmx_caps *caps);
 
-	int (*set_source) (struct dmx_demux* demux, const dmx_source_t *src);
+	int (*set_source) (struct dmx_demux *demux, const dmx_source_t *src);
+
+	int (*set_tsp_format) (struct dmx_demux *demux,
+				enum dmx_tsp_format_t tsp_format);
+
+	int (*set_tsp_out_format) (struct dmx_demux *demux,
+				enum dmx_tsp_format_t tsp_format);
+
+	int (*set_playback_mode) (struct dmx_demux *demux,
+				 enum dmx_playback_mode_t mode,
+				 dmx_ts_fullness ts_fullness_callback,
+				 dmx_section_fullness sec_fullness_callback);
+
+	int (*write_cancel) (struct dmx_demux *demux);
 
 	int (*get_stc) (struct dmx_demux* demux, unsigned int num,
 			u64 *stc, unsigned int *base);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index e4b5c03..ed3f731 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -4,6 +4,8 @@
  * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
  *		      for convergence integrated media GmbH
  *
+ * 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 Lesser General Public License
  * as published by the Free Software Foundation; either version 2.1
@@ -28,6 +30,7 @@
 #include <linux/poll.h>
 #include <linux/ioctl.h>
 #include <linux/wait.h>
+#include <linux/mm.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include "dmxdev.h"
@@ -81,12 +84,15 @@
 			break;
 		}
 
-		ret = wait_event_interruptible(src->queue,
-					       !dvb_ringbuffer_empty(src) ||
-					       (src->error != 0));
+		ret = wait_event_interruptible(src->queue, (!src->data) ||
+						!dvb_ringbuffer_empty(src) ||
+						(src->error != 0));
 		if (ret < 0)
 			break;
 
+		if (!src->data)
+			return 0;
+
 		if (src->error) {
 			ret = src->error;
 			dvb_ringbuffer_flush(src);
@@ -104,6 +110,9 @@
 		buf += ret;
 	}
 
+	if (count - todo) /* some data was read? */
+		wake_up_all(&src->queue);
+
 	return (count - todo) ? (count - todo) : ret;
 }
 
@@ -126,8 +135,11 @@
 	struct dvb_device *dvbdev = file->private_data;
 	struct dmxdev *dmxdev = dvbdev->priv;
 	struct dmx_frontend *front;
+	void *mem;
 
-	dprintk("function : %s\n", __func__);
+	dprintk("function : %s(%X)\n",
+			__func__,
+			(file->f_flags & O_ACCMODE));
 
 	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
@@ -145,21 +157,20 @@
 	}
 
 	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
-		void *mem;
 		if (!dvbdev->readers) {
 			mutex_unlock(&dmxdev->mutex);
 			return -EBUSY;
 		}
-		mem = vmalloc(DVR_BUFFER_SIZE);
+		mem = vmalloc_user(DVR_BUFFER_SIZE);
 		if (!mem) {
 			mutex_unlock(&dmxdev->mutex);
 			return -ENOMEM;
 		}
 		dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
 		dvbdev->readers--;
-	}
-
-	if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+	} else if (!dvbdev->writers) {
+		dmxdev->dvr_in_exit = 0;
+		dmxdev->dvr_processing_input = 0;
 		dmxdev->dvr_orig_fe = dmxdev->demux->frontend;
 
 		if (!dmxdev->demux->write) {
@@ -173,9 +184,22 @@
 			mutex_unlock(&dmxdev->mutex);
 			return -EINVAL;
 		}
+
+		mem = vmalloc_user(DVR_BUFFER_SIZE);
+		if (!mem) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ENOMEM;
+		}
+
 		dmxdev->demux->disconnect_frontend(dmxdev->demux);
 		dmxdev->demux->connect_frontend(dmxdev->demux, front);
+
+		dvb_ringbuffer_init(&dmxdev->dvr_input_buffer,
+							mem,
+							DVR_BUFFER_SIZE);
+		dvbdev->writers--;
 	}
+
 	dvbdev->users++;
 	mutex_unlock(&dmxdev->mutex);
 	return 0;
@@ -188,11 +212,6 @@
 
 	mutex_lock(&dmxdev->mutex);
 
-	if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
-		dmxdev->demux->disconnect_frontend(dmxdev->demux);
-		dmxdev->demux->connect_frontend(dmxdev->demux,
-						dmxdev->dvr_orig_fe);
-	}
 	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
 		dvbdev->readers++;
 		if (dmxdev->dvr_buffer.data) {
@@ -201,6 +220,51 @@
 			spin_lock_irq(&dmxdev->lock);
 			dmxdev->dvr_buffer.data = NULL;
 			spin_unlock_irq(&dmxdev->lock);
+			wake_up_all(&dmxdev->dvr_buffer.queue);
+			vfree(mem);
+		}
+	} else {
+		int i;
+
+		dmxdev->dvr_in_exit = 1;
+		wake_up_all(&dmxdev->dvr_input_buffer.queue);
+
+		/*
+		 * There might be dmx filters reading now from DVR
+		 * device, in PULL mode, they might be also stalled
+		 * on output, signal to them that DVR is exiting.
+		 */
+		if (dmxdev->playback_mode == DMX_PB_MODE_PULL) {
+			wake_up_all(&dmxdev->dvr_buffer.queue);
+
+			for (i = 0; i < dmxdev->filternum; i++)
+				if (dmxdev->filter[i].state == DMXDEV_STATE_GO)
+					wake_up_all(
+					&dmxdev->filter[i].buffer.queue);
+		}
+
+		/* notify kernel demux that we are canceling */
+		if (dmxdev->demux->write_cancel)
+			dmxdev->demux->write_cancel(dmxdev->demux);
+
+		/*
+		 * Now flush dvr-in workqueue so that no one
+		 * would process data from dvr input buffer any more
+		 * before it gets freed.
+		 */
+		flush_workqueue(dmxdev->dvr_input_workqueue);
+
+		dvbdev->writers++;
+		dmxdev->demux->disconnect_frontend(dmxdev->demux);
+		dmxdev->demux->connect_frontend(dmxdev->demux,
+						dmxdev->dvr_orig_fe);
+
+		if (dmxdev->dvr_input_buffer.data) {
+			void *mem = dmxdev->dvr_input_buffer.data;
+			mb();
+			spin_lock_irq(&dmxdev->dvr_in_lock);
+			dmxdev->dvr_input_buffer.data = NULL;
+			spin_unlock_irq(&dmxdev->dvr_in_lock);
 			vfree(mem);
 		}
 	}
@@ -217,17 +281,20 @@
 	return 0;
 }
 
-static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
-			     size_t count, loff_t *ppos)
+
+static int dvb_dvr_mmap(struct file *filp, struct vm_area_struct *vma)
 {
-	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_device *dvbdev = filp->private_data;
 	struct dmxdev *dmxdev = dvbdev->priv;
+	struct dvb_ringbuffer *buffer;
+	int vma_size;
+	int buffer_size;
 	int ret;
 
-	if (!dmxdev->demux->write)
-		return -EOPNOTSUPP;
-	if ((file->f_flags & O_ACCMODE) != O_WRONLY)
+	if (((filp->f_flags & O_ACCMODE) == O_RDONLY) &&
+		(vma->vm_flags & VM_WRITE))
 		return -EINVAL;
+
 	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
 
@@ -235,11 +302,114 @@
 		mutex_unlock(&dmxdev->mutex);
 		return -ENODEV;
 	}
-	ret = dmxdev->demux->write(dmxdev->demux, buf, count);
+
+	if ((filp->f_flags & O_ACCMODE) == O_RDONLY)
+		buffer = &dmxdev->dvr_buffer;
+	else
+		buffer = &dmxdev->dvr_input_buffer;
+
+	vma_size = vma->vm_end - vma->vm_start;
+
+	/* Make sure requested mapping is not larger than buffer size */
+	buffer_size = buffer->size + (PAGE_SIZE-1);
+	buffer_size = buffer_size & ~(PAGE_SIZE-1);
+
+	if (vma_size != buffer_size) {
+		mutex_unlock(&dmxdev->mutex);
+		return -EINVAL;
+	}
+
+	ret = remap_vmalloc_range(vma, buffer->data, 0);
+	if (ret) {
+		mutex_unlock(&dmxdev->mutex);
+		return ret;
+	}
+
+	vma->vm_flags |= VM_RESERVED;
+	vma->vm_flags |= VM_DONTEXPAND;
+
 	mutex_unlock(&dmxdev->mutex);
 	return ret;
 }
 
+static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
+			     size_t count, loff_t *ppos)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dmxdev *dmxdev = dvbdev->priv;
+	struct dvb_ringbuffer *src = &dmxdev->dvr_input_buffer;
+	int ret;
+	size_t todo;
+	ssize_t free_space;
+
+	if (!dmxdev->demux->write)
+		return -EOPNOTSUPP;
+
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+		return -EINVAL;
+
+	if ((file->f_flags & O_NONBLOCK) &&
+		(dvb_ringbuffer_free(src) == 0))
+		return -EWOULDBLOCK;
+
+	ret = 0;
+	for (todo = count; todo > 0; todo -= ret) {
+		ret = wait_event_interruptible(src->queue,
+						   (!src->data) ||
+					       (dvb_ringbuffer_free(src)) ||
+					       (src->error != 0) ||
+					       (dmxdev->dvr_in_exit));
+
+		if (ret < 0)
+			return ret;
+
+		if (mutex_lock_interruptible(&dmxdev->mutex))
+			return -ERESTARTSYS;
+
+		if (!src->data) {
+			mutex_unlock(&dmxdev->mutex);
+			return 0;
+		}
+
+		if (dmxdev->exit || dmxdev->dvr_in_exit) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ENODEV;
+		}
+
+		if (src->error) {
+			ret = src->error;
+			dvb_ringbuffer_flush(src);
+			mutex_unlock(&dmxdev->mutex);
+			wake_up_all(&src->queue);
+			return ret;
+		}
+
+		free_space = dvb_ringbuffer_free(src);
+
+		if (free_space > todo)
+			free_space = todo;
+
+		ret = dvb_ringbuffer_write_user(src, buf, free_space);
+
+		if (ret < 0) {
+			mutex_unlock(&dmxdev->mutex);
+			return ret;
+		}
+
+		buf += ret;
+
+		mutex_unlock(&dmxdev->mutex);
+
+		wake_up_all(&src->queue);
+
+		if (!work_pending(&dmxdev->dvr_input_work))
+			queue_work(dmxdev->dvr_input_workqueue,
+						&dmxdev->dvr_input_work);
+	}
+
+	return (count - todo) ? (count - todo) : ret;
+}
+
 static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
 			    loff_t *ppos)
 {
@@ -254,39 +424,223 @@
 				      buf, count, ppos);
 }
 
-static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
-				      unsigned long size)
+static void dvr_input_work_func(struct work_struct *worker)
 {
-	struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer;
+	struct dmxdev *dmxdev =
+		container_of(worker, struct dmxdev, dvr_input_work);
+	struct dvb_ringbuffer *src = &dmxdev->dvr_input_buffer;
+	int ret;
+	size_t todo;
+	size_t split;
+
+	while (1) {
+		/* wait for input */
+		ret = wait_event_interruptible(src->queue,
+						   (!src->data) ||
+					       (dvb_ringbuffer_avail(src)) ||
+					       (src->error != 0) ||
+					       (dmxdev->dvr_in_exit));
+
+		if (ret < 0)
+			break;
+
+		spin_lock(&dmxdev->dvr_in_lock);
+
+		if (!src->data || dmxdev->exit || dmxdev->dvr_in_exit) {
+			spin_unlock(&dmxdev->dvr_in_lock);
+			break;
+		}
+
+		if (src->error) {
+			spin_unlock(&dmxdev->dvr_in_lock);
+			wake_up_all(&src->queue);
+			break;
+		}
+
+		dmxdev->dvr_processing_input = 1;
+
+		ret = dvb_ringbuffer_avail(src);
+		todo = ret;
+
+		split = (src->pread + ret > src->size) ?
+				src->size - src->pread :
+				0;
+
+		/*
+		 * In DVR PULL mode, write might block.
+		 * Lock on DVR buffer is released before calling to
+		 * write, if DVR was released meanwhile, dvr_in_exit is
+		 * prompted. Lock is aquired when updating the read pointer
+		 * again to preserve read/write pointers consistancy
+		 */
+		if (split > 0) {
+			spin_unlock(&dmxdev->dvr_in_lock);
+			dmxdev->demux->write(dmxdev->demux,
+						src->data + src->pread,
+						split);
+
+			if (dmxdev->dvr_in_exit)
+				break;
+
+			spin_lock(&dmxdev->dvr_in_lock);
+
+			todo -= split;
+			DVB_RINGBUFFER_SKIP(src, split);
+		}
+
+		spin_unlock(&dmxdev->dvr_in_lock);
+		dmxdev->demux->write(dmxdev->demux,
+					src->data + src->pread, todo);
+
+		if (dmxdev->dvr_in_exit)
+			break;
+
+		spin_lock(&dmxdev->dvr_in_lock);
+
+		DVB_RINGBUFFER_SKIP(src, todo);
+		dmxdev->dvr_processing_input = 0;
+		spin_unlock(&dmxdev->dvr_in_lock);
+
+		wake_up_all(&src->queue);
+	}
+}
+
+static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
+						unsigned int f_flags,
+						unsigned long size)
+{
+	struct dvb_ringbuffer *buf;
 	void *newmem;
 	void *oldmem;
+	spinlock_t *lock;
 
 	dprintk("function : %s\n", __func__);
 
+	if ((f_flags & O_ACCMODE) == O_RDONLY) {
+		buf = &dmxdev->dvr_buffer;
+		lock = &dmxdev->lock;
+	} else {
+		buf = &dmxdev->dvr_input_buffer;
+		lock = &dmxdev->dvr_in_lock;
+	}
+
 	if (buf->size == size)
 		return 0;
 	if (!size)
 		return -EINVAL;
 
-	newmem = vmalloc(size);
+	newmem = vmalloc_user(size);
 	if (!newmem)
 		return -ENOMEM;
 
 	oldmem = buf->data;
 
-	spin_lock_irq(&dmxdev->lock);
+	spin_lock_irq(lock);
+
+	if (((f_flags & O_ACCMODE) != O_RDONLY) &&
+		(dmxdev->dvr_processing_input)) {
+		spin_unlock_irq(lock);
+		vfree(oldmem);
+		return -EBUSY;
+	}
+
 	buf->data = newmem;
 	buf->size = size;
 
 	/* reset and not flush in case the buffer shrinks */
 	dvb_ringbuffer_reset(buf);
-	spin_unlock_irq(&dmxdev->lock);
+
+	spin_unlock_irq(lock);
 
 	vfree(oldmem);
 
 	return 0;
 }
 
+static int dvb_dvr_get_buffer_status(struct dmxdev *dmxdev,
+				unsigned int f_flags,
+				struct dmx_buffer_status *dmx_buffer_status)
+{
+	struct dvb_ringbuffer *buf;
+	spinlock_t *lock;
+
+	if ((f_flags & O_ACCMODE) == O_RDONLY) {
+		buf = &dmxdev->dvr_buffer;
+		lock = &dmxdev->lock;
+	} else {
+		buf = &dmxdev->dvr_input_buffer;
+		lock = &dmxdev->dvr_in_lock;
+	}
+
+	spin_lock_irq(lock);
+
+	dmx_buffer_status->error = buf->error;
+	if (buf->error)
+		dvb_ringbuffer_flush(buf);
+
+	dmx_buffer_status->fullness = dvb_ringbuffer_avail(buf);
+	dmx_buffer_status->free_bytes = dvb_ringbuffer_free(buf);
+	dmx_buffer_status->read_offset = buf->pread;
+	dmx_buffer_status->write_offset = buf->pwrite;
+	dmx_buffer_status->size = buf->size;
+
+	spin_unlock_irq(lock);
+
+	return 0;
+}
+
+static int dvb_dvr_release_data(struct dmxdev *dmxdev,
+					unsigned int f_flags,
+					u32 bytes_count)
+{
+	ssize_t buff_fullness;
+
+	if (!(f_flags & O_ACCMODE) == O_RDONLY)
+		return -EINVAL;
+
+	if (!bytes_count)
+		return 0;
+
+	buff_fullness = dvb_ringbuffer_avail(&dmxdev->dvr_buffer);
+
+	if (bytes_count > buff_fullness)
+		return -EINVAL;
+
+	DVB_RINGBUFFER_SKIP(&dmxdev->dvr_buffer, bytes_count);
+	wake_up_all(&dmxdev->dvr_buffer.queue);
+	return 0;
+}
+
+static int dvb_dvr_feed_data(struct dmxdev *dmxdev,
+					unsigned int f_flags,
+					u32 bytes_count)
+{
+	ssize_t free_space;
+	struct dvb_ringbuffer *buffer = &dmxdev->dvr_input_buffer;
+
+	if ((f_flags & O_ACCMODE) == O_RDONLY)
+		return -EINVAL;
+
+	if (!bytes_count)
+		return 0;
+
+	free_space = dvb_ringbuffer_free(buffer);
+
+	if (bytes_count > free_space)
+		return -EINVAL;
+
+	buffer->pwrite =
+		(buffer->pwrite + bytes_count) % buffer->size;
+
+	wake_up_all(&buffer->queue);
+
+	if (!work_pending(&dmxdev->dvr_input_work))
+		queue_work(dmxdev->dvr_input_workqueue,
+					&dmxdev->dvr_input_work);
+
+	return 0;
+}
+
 static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter
 					       *dmxdevfilter, int state)
 {
@@ -309,7 +663,7 @@
 	if (dmxdevfilter->state >= DMXDEV_STATE_GO)
 		return -EBUSY;
 
-	newmem = vmalloc(size);
+	newmem = vmalloc_user(size);
 	if (!newmem)
 		return -ENOMEM;
 
@@ -324,6 +678,212 @@
 	spin_unlock_irq(&dmxdevfilter->dev->lock);
 
 	vfree(oldmem);
+	return 0;
+}
+
+static int dvb_dmxdev_set_pes_buffer_size(struct dmxdev_filter *dmxdevfilter,
+					unsigned long size)
+{
+	if (dmxdevfilter->pes_buffer_size == size)
+		return 0;
+	if (!size)
+		return -EINVAL;
+	if (dmxdevfilter->state >= DMXDEV_STATE_GO)
+		return -EBUSY;
+
+	dmxdevfilter->pes_buffer_size = size;
+
+	return 0;
+}
+
+static int dvb_dmxdev_set_source(struct dmxdev_filter *dmxdevfilter,
+					dmx_source_t *source)
+{
+	struct dmxdev *dev;
+
+	if (dmxdevfilter->state == DMXDEV_STATE_GO)
+		return -EBUSY;
+
+	dev = dmxdevfilter->dev;
+
+	dev->source = *source;
+
+	if (dev->demux->set_source)
+		return dev->demux->set_source(dev->demux, source);
+
+	return 0;
+}
+
+static int dvb_dmxdev_ts_fullness_callback(
+				struct dmx_ts_feed *filter,
+				int required_space)
+{
+	struct dmxdev_filter *dmxdevfilter = filter->priv;
+	struct dvb_ringbuffer *src;
+	int ret;
+
+	if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
+		|| dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
+		src = &dmxdevfilter->buffer;
+	else
+		src = &dmxdevfilter->dev->dvr_buffer;
+
+	do {
+		ret = 0;
+
+		if (dmxdevfilter->dev->dvr_in_exit)
+			return -ENODEV;
+
+		spin_lock(&dmxdevfilter->dev->lock);
+
+		if ((!src->data) ||
+			(dmxdevfilter->state != DMXDEV_STATE_GO))
+			ret = -EINVAL;
+		else if (src->error)
+			ret = src->error;
+
+		if (ret) {
+			spin_unlock(&dmxdevfilter->dev->lock);
+			return ret;
+		}
+
+		if (required_space <= dvb_ringbuffer_free(src)) {
+			spin_unlock(&dmxdevfilter->dev->lock);
+			return 0;
+		}
+
+		spin_unlock(&dmxdevfilter->dev->lock);
+
+		ret = wait_event_interruptible(src->queue,
+				(!src->data) ||
+				(dvb_ringbuffer_free(src) >= required_space) ||
+				(src->error != 0) ||
+				(dmxdevfilter->state != DMXDEV_STATE_GO) ||
+				dmxdevfilter->dev->dvr_in_exit);
+
+		if (ret < 0)
+			return ret;
+	} while (1);
+}
+
+static int dvb_dmxdev_sec_fullness_callback(
+				struct dmx_section_filter *filter,
+				int required_space)
+{
+	struct dmxdev_filter *dmxdevfilter = filter->priv;
+	struct dvb_ringbuffer *src = &dmxdevfilter->buffer;
+	int ret;
+
+	do {
+		ret = 0;
+
+		if (dmxdevfilter->dev->dvr_in_exit)
+			return -ENODEV;
+
+		spin_lock(&dmxdevfilter->dev->lock);
+
+		if ((!src->data) ||
+			(dmxdevfilter->state != DMXDEV_STATE_GO))
+			ret = -EINVAL;
+		else if (src->error)
+			ret = src->error;
+
+		if (ret) {
+			spin_unlock(&dmxdevfilter->dev->lock);
+			return ret;
+		}
+
+		if (required_space <= dvb_ringbuffer_free(src)) {
+			spin_unlock(&dmxdevfilter->dev->lock);
+			return 0;
+		}
+
+		spin_unlock(&dmxdevfilter->dev->lock);
+
+		ret = wait_event_interruptible(src->queue,
+				(!src->data) ||
+				(dvb_ringbuffer_free(src) >= required_space) ||
+				(src->error != 0) ||
+				(dmxdevfilter->state != DMXDEV_STATE_GO) ||
+				dmxdevfilter->dev->dvr_in_exit);
+
+		if (ret < 0)
+			return ret;
+	} while (1);
+}
+
+static int dvb_dmxdev_set_playback_mode(struct dmxdev_filter *dmxdevfilter,
+					enum dmx_playback_mode_t playback_mode)
+{
+	struct dmxdev *dmxdev = dmxdevfilter->dev;
+
+	if ((playback_mode != DMX_PB_MODE_PUSH) &&
+		(playback_mode != DMX_PB_MODE_PULL))
+		return -EINVAL;
+
+	if (((dmxdev->source < DMX_SOURCE_DVR0) ||
+		!dmxdev->demux->set_playback_mode ||
+		!(dmxdev->capabilities & DMXDEV_CAP_PULL_MODE)) &&
+		(playback_mode == DMX_PB_MODE_PULL))
+		return -EPERM;
+
+	if (dmxdevfilter->state == DMXDEV_STATE_GO)
+		return -EBUSY;
+
+	dmxdev->playback_mode = playback_mode;
+
+	return dmxdev->demux->set_playback_mode(
+				dmxdev->demux,
+				dmxdev->playback_mode,
+				dvb_dmxdev_ts_fullness_callback,
+				dvb_dmxdev_sec_fullness_callback);
+}
+
+static int dvb_dmxdev_get_buffer_status(
+		struct dmxdev_filter *dmxdevfilter,
+		struct dmx_buffer_status *dmx_buffer_status)
+{
+	struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
+
+	if (!buf->data)
+		return -EINVAL;
+
+	spin_lock_irq(&dmxdevfilter->dev->lock);
+
+	dmx_buffer_status->error = buf->error;
+	if (buf->error)
+		dvb_ringbuffer_flush(buf);
+
+	dmx_buffer_status->fullness = dvb_ringbuffer_avail(buf);
+	dmx_buffer_status->free_bytes = dvb_ringbuffer_free(buf);
+	dmx_buffer_status->read_offset = buf->pread;
+	dmx_buffer_status->write_offset = buf->pwrite;
+	dmx_buffer_status->size = buf->size;
+
+	spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+	return 0;
+}
+
+static int dvb_dmxdev_release_data(struct dmxdev_filter *dmxdevfilter,
+					u32 bytes_count)
+{
+	ssize_t buff_fullness;
+
+	if (!dmxdevfilter->buffer.data)
+		return -EINVAL;
+
+	if (!bytes_count)
+		return 0;
+
+	buff_fullness = dvb_ringbuffer_avail(&dmxdevfilter->buffer);
+
+	if (bytes_count > buff_fullness)
+		return -EINVAL;
+
+	DVB_RINGBUFFER_SKIP(&dmxdevfilter->buffer, bytes_count);
+
+	wake_up_all(&dmxdevfilter->buffer.queue);
 
 	return 0;
 }
@@ -336,7 +896,7 @@
 	spin_lock_irq(&dmxdevfilter->dev->lock);
 	dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
 	spin_unlock_irq(&dmxdevfilter->dev->lock);
-	wake_up(&dmxdevfilter->buffer.queue);
+	wake_up_all(&dmxdevfilter->buffer.queue);
 }
 
 static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
@@ -362,7 +922,7 @@
 	int ret;
 
 	if (dmxdevfilter->buffer.error) {
-		wake_up(&dmxdevfilter->buffer.queue);
+		wake_up_all(&dmxdevfilter->buffer.queue);
 		return 0;
 	}
 	spin_lock(&dmxdevfilter->dev->lock);
@@ -387,7 +947,7 @@
 	if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
 		dmxdevfilter->state = DMXDEV_STATE_DONE;
 	spin_unlock(&dmxdevfilter->dev->lock);
-	wake_up(&dmxdevfilter->buffer.queue);
+	wake_up_all(&dmxdevfilter->buffer.queue);
 	return 0;
 }
 
@@ -402,18 +962,34 @@
 
 	spin_lock(&dmxdevfilter->dev->lock);
 	if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
-		spin_unlock(&dmxdevfilter->dev->lock);
-		return 0;
-	}
-
-	if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
+		if ((dmxdevfilter->dev->capabilities &
+			DMXDEV_CAP_PCR_EXTRACTION) &&
+			((dmxdevfilter->params.pes.pes_type == DMX_PES_PCR0) ||
+			(dmxdevfilter->params.pes.pes_type == DMX_PES_PCR1) ||
+			(dmxdevfilter->params.pes.pes_type == DMX_PES_PCR2) ||
+			(dmxdevfilter->params.pes.pes_type == DMX_PES_PCR3))) {
+			/*
+			 * Support for reporting PCR and STC pairs to user.
+			 * Reported data should have the following format:
+			 * <8 bit flags><64 bits of STC> <64bits of PCR>
+			 * STC and PCR values are in 27MHz.
+			 * The current flags that are defined:
+			 * 0x00000001: discontinuity_indicator
+			 */
+			buffer = &dmxdevfilter->buffer;
+		} else {
+			spin_unlock(&dmxdevfilter->dev->lock);
+			return 0;
+		}
+	} else if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
 	    || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
 		buffer = &dmxdevfilter->buffer;
 	else
 		buffer = &dmxdevfilter->dev->dvr_buffer;
+
 	if (buffer->error) {
 		spin_unlock(&dmxdevfilter->dev->lock);
-		wake_up(&buffer->queue);
+		wake_up_all(&buffer->queue);
 		return 0;
 	}
 	ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
@@ -424,7 +1000,7 @@
 		buffer->error = ret;
 	}
 	spin_unlock(&dmxdevfilter->dev->lock);
-	wake_up(&buffer->queue);
+	wake_up_all(&buffer->queue);
 	return 0;
 }
 
@@ -534,6 +1110,8 @@
 	}
 
 	dvb_ringbuffer_flush(&dmxdevfilter->buffer);
+	wake_up_all(&dmxdevfilter->buffer.queue);
+
 	return 0;
 }
 
@@ -600,7 +1178,9 @@
 	tsfeed = feed->ts;
 	tsfeed->priv = filter;
 
-	ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout);
+	ret = tsfeed->set(tsfeed, feed->pid,
+					ts_type, ts_pes,
+					filter->pes_buffer_size, timeout);
 	if (ret < 0) {
 		dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
 		return ret;
@@ -629,7 +1209,7 @@
 		dvb_dmxdev_filter_stop(filter);
 
 	if (!filter->buffer.data) {
-		mem = vmalloc(filter->buffer.size);
+		mem = vmalloc_user(filter->buffer.size);
 		if (!mem)
 			return -ENOMEM;
 		spin_lock_irq(&filter->dev->lock);
@@ -649,7 +1229,6 @@
 		*secfilter = NULL;
 		*secfeed = NULL;
 
-
 		/* find active filter/feed with same PID */
 		for (i = 0; i < dmxdev->filternum; i++) {
 			if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
@@ -763,6 +1342,8 @@
 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
 	init_timer(&dmxdevfilter->timer);
 
+	dmxdevfilter->pes_buffer_size = 32768;
+
 	dvbdev->users++;
 
 	mutex_unlock(&dmxdev->mutex);
@@ -788,7 +1369,7 @@
 	}
 
 	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);
-	wake_up(&dmxdevfilter->buffer.queue);
+	wake_up_all(&dmxdevfilter->buffer.queue);
 	mutex_unlock(&dmxdevfilter->mutex);
 	mutex_unlock(&dmxdev->mutex);
 	return 0;
@@ -1023,6 +1604,24 @@
 		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
+	case DMX_GET_BUFFER_STATUS:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_get_buffer_status(dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_RELEASE_DATA:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_release_data(dmxdevfilter, arg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
 	case DMX_GET_PES_PIDS:
 		if (!dmxdev->demux->get_pes_pids) {
 			ret = -EINVAL;
@@ -1040,11 +1639,59 @@
 		break;
 
 	case DMX_SET_SOURCE:
-		if (!dmxdev->demux->set_source) {
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_set_source(dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_SET_TS_PACKET_FORMAT:
+		if (!dmxdev->demux->set_tsp_format) {
 			ret = -EINVAL;
 			break;
 		}
-		ret = dmxdev->demux->set_source(dmxdev->demux, parg);
+
+		if (dmxdevfilter->state >= DMXDEV_STATE_GO) {
+			ret = -EBUSY;
+			break;
+		}
+		ret = dmxdev->demux->set_tsp_format(
+				dmxdev->demux,
+				*(enum dmx_tsp_format_t *)parg);
+		break;
+
+	case DMX_SET_TS_OUT_FORMAT:
+		if (!dmxdev->demux->set_tsp_out_format) {
+			ret = -EINVAL;
+			break;
+		}
+
+		if (dmxdevfilter->state >= DMXDEV_STATE_GO) {
+			ret = -EBUSY;
+			break;
+		}
+
+		ret = dmxdev->demux->set_tsp_out_format(
+				dmxdev->demux,
+				*(enum dmx_tsp_format_t *)parg);
+		break;
+
+	case DMX_SET_DECODER_BUFFER_SIZE:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+
+		ret = dvb_dmxdev_set_pes_buffer_size(dmxdevfilter, arg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
+	case DMX_SET_PLAYBACK_MODE:
+		ret = dvb_dmxdev_set_playback_mode(
+				dmxdevfilter,
+				*(enum dmx_playback_mode_t *)parg);
 		break;
 
 	case DMX_GET_STC:
@@ -1114,6 +1761,59 @@
 	return mask;
 }
 
+static int dvb_demux_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct dmxdev_filter *dmxdevfilter = filp->private_data;
+	struct dmxdev *dmxdev = dmxdevfilter->dev;
+	int ret;
+	int vma_size;
+	int buffer_size;
+
+	vma_size = vma->vm_end - vma->vm_start;
+
+	if (vma->vm_flags & VM_WRITE)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&dmxdev->mutex))
+		return -ERESTARTSYS;
+
+	if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+		mutex_unlock(&dmxdev->mutex);
+		return -ERESTARTSYS;
+	}
+
+	if (!dmxdevfilter->buffer.data) {
+		mutex_unlock(&dmxdevfilter->mutex);
+		mutex_unlock(&dmxdev->mutex);
+		return -EINVAL;
+	}
+
+	/* Make sure requested mapping is not larger than buffer size */
+	buffer_size = dmxdevfilter->buffer.size + (PAGE_SIZE-1);
+	buffer_size = buffer_size & ~(PAGE_SIZE-1);
+
+	if (vma_size != buffer_size) {
+		mutex_unlock(&dmxdevfilter->mutex);
+		mutex_unlock(&dmxdev->mutex);
+		return -EINVAL;
+	}
+
+	ret = remap_vmalloc_range(vma, dmxdevfilter->buffer.data, 0);
+	if (ret) {
+		mutex_unlock(&dmxdevfilter->mutex);
+		mutex_unlock(&dmxdev->mutex);
+		return ret;
+	}
+
+	vma->vm_flags |= VM_RESERVED;
+	vma->vm_flags |= VM_DONTEXPAND;
+
+	mutex_unlock(&dmxdevfilter->mutex);
+	mutex_unlock(&dmxdev->mutex);
+
+	return 0;
+}
+
 static int dvb_demux_release(struct inode *inode, struct file *file)
 {
 	struct dmxdev_filter *dmxdevfilter = file->private_data;
@@ -1144,6 +1844,7 @@
 	.release = dvb_demux_release,
 	.poll = dvb_demux_poll,
 	.llseek = default_llseek,
+	.mmap = dvb_demux_mmap,
 };
 
 static struct dvb_device dvbdev_demux = {
@@ -1166,7 +1867,19 @@
 
 	switch (cmd) {
 	case DMX_SET_BUFFER_SIZE:
-		ret = dvb_dvr_set_buffer_size(dmxdev, arg);
+		ret = dvb_dvr_set_buffer_size(dmxdev, file->f_flags, arg);
+		break;
+
+	case DMX_GET_BUFFER_STATUS:
+		ret = dvb_dvr_get_buffer_status(dmxdev, file->f_flags, parg);
+		break;
+
+	case DMX_RELEASE_DATA:
+		ret = dvb_dvr_release_data(dmxdev, file->f_flags, arg);
+		break;
+
+	case DMX_FEED_DATA:
+		ret = dvb_dvr_feed_data(dmxdev, file->f_flags, arg);
 		break;
 
 	default:
@@ -1191,16 +1904,22 @@
 
 	dprintk("function : %s\n", __func__);
 
-	poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
-
 	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+		poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
+
 		if (dmxdev->dvr_buffer.error)
 			mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
 
 		if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
 			mask |= (POLLIN | POLLRDNORM | POLLPRI);
-	} else
-		mask |= (POLLOUT | POLLWRNORM | POLLPRI);
+	} else {
+		poll_wait(file, &dmxdev->dvr_input_buffer.queue, wait);
+		if (dmxdev->dvr_input_buffer.error)
+			mask |= (POLLOUT | POLLRDNORM | POLLPRI | POLLERR);
+
+		if (dvb_ringbuffer_free(&dmxdev->dvr_input_buffer))
+			mask |= (POLLOUT | POLLRDNORM | POLLPRI);
+	}
 
 	return mask;
 }
@@ -1209,6 +1928,7 @@
 	.owner = THIS_MODULE,
 	.read = dvb_dvr_read,
 	.write = dvb_dvr_write,
+	.mmap = dvb_dvr_mmap,
 	.unlocked_ioctl = dvb_dvr_ioctl,
 	.open = dvb_dvr_open,
 	.release = dvb_dvr_release,
@@ -1234,8 +1954,19 @@
 	if (!dmxdev->filter)
 		return -ENOMEM;
 
+	dmxdev->dvr_input_workqueue =
+		create_singlethread_workqueue("dvr_workqueue");
+
+	if (dmxdev->dvr_input_workqueue == NULL) {
+		vfree(dmxdev->filter);
+		return -ENOMEM;
+	}
+
+	dmxdev->playback_mode = DMX_PB_MODE_PUSH;
+
 	mutex_init(&dmxdev->mutex);
 	spin_lock_init(&dmxdev->lock);
+	spin_lock_init(&dmxdev->dvr_in_lock);
 	for (i = 0; i < dmxdev->filternum; i++) {
 		dmxdev->filter[i].dev = dmxdev;
 		dmxdev->filter[i].buffer.data = NULL;
@@ -1249,6 +1980,10 @@
 			    dmxdev, DVB_DEVICE_DVR);
 
 	dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
+	dvb_ringbuffer_init(&dmxdev->dvr_input_buffer, NULL, 8192);
+
+	INIT_WORK(&dmxdev->dvr_input_work,
+			  dvr_input_work_func);
 
 	return 0;
 }
@@ -1267,6 +2002,9 @@
 				dmxdev->dvr_dvbdev->users==1);
 	}
 
+	flush_workqueue(dmxdev->dvr_input_workqueue);
+	destroy_workqueue(dmxdev->dvr_input_workqueue);
+
 	dvb_unregister_device(dmxdev->dvbdev);
 	dvb_unregister_device(dmxdev->dvr_dvbdev);
 
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index 02ebe28..82f8f6d 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -4,6 +4,8 @@
  * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
  *                    for convergence integrated media GmbH
  *
+ * 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 Lesser General Public License
  * as published by the Free Software Foundation; either version 2.1
@@ -32,7 +34,7 @@
 #include <linux/string.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
-
+#include <linux/workqueue.h>
 #include <linux/dvb/dmx.h>
 
 #include "dvbdev.h"
@@ -83,14 +85,18 @@
 
 	struct mutex mutex;
 
+	/* relevent for decoder PES */
+	unsigned long pes_buffer_size;
+
 	/* only for sections */
 	struct timer_list timer;
 	int todo;
 	u8 secheader[3];
 };
 
-
 struct dmxdev {
+	struct work_struct dvr_input_work;
+
 	struct dvb_device *dvbdev;
 	struct dvb_device *dvr_dvbdev;
 
@@ -99,16 +105,28 @@
 
 	int filternum;
 	int capabilities;
+#define DMXDEV_CAP_DUPLEX			0x1
+#define DMXDEV_CAP_PULL_MODE		0x2
+#define DMXDEV_CAP_PCR_EXTRACTION	0x4
+
+	enum dmx_playback_mode_t playback_mode;
+	dmx_source_t source;
 
 	unsigned int exit:1;
-#define DMXDEV_CAP_DUPLEX 1
+	unsigned int dvr_in_exit:1;
+	unsigned int dvr_processing_input:1;
+
 	struct dmx_frontend *dvr_orig_fe;
 
 	struct dvb_ringbuffer dvr_buffer;
+	struct dvb_ringbuffer dvr_input_buffer;
+	struct workqueue_struct *dvr_input_workqueue;
+
 #define DVR_BUFFER_SIZE (10*188*1024)
 
 	struct mutex mutex;
 	spinlock_t lock;
+	spinlock_t dvr_in_lock;
 };
 
 
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index faa3671..966b48d 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -5,6 +5,8 @@
  *		       & Marcus Metzler <marcus@convergence.de>
  *			 for convergence integrated media GmbH
  *
+ * 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 Lesser General Public License
  * as published by the Free Software Foundation; either version 2.1
@@ -50,6 +52,14 @@
 MODULE_PARM_DESC(dvb_demux_speedcheck,
 		"enable transport stream speed check");
 
+/* counter advancing for each new dvb-demux device */
+static int dvb_demux_index;
+
+static int dvb_demux_performancecheck;
+module_param(dvb_demux_performancecheck, int, 0644);
+MODULE_PARM_DESC(dvb_demux_performancecheck,
+		"enable transport stream performance check, reported through debugfs");
+
 #define dprintk_tscheck(x...) do {                              \
 		if (dvb_demux_tscheck && printk_ratelimit())    \
 			printk(x);                              \
@@ -95,6 +105,19 @@
 	memcpy(d, s, len);
 }
 
+static u32 dvb_dmx_calc_time_delta(struct timespec past_time)
+{
+	struct timespec curr_time, delta_time;
+	u64 delta_time_us;
+
+	curr_time = current_kernel_time();
+	delta_time = timespec_sub(curr_time, past_time);
+	delta_time_us = ((s64)delta_time.tv_sec * USEC_PER_SEC) +
+					delta_time.tv_nsec / 1000;
+
+	return (u32)delta_time_us;
+}
+
 /******************************************************************************
  * Software filter functions
  ******************************************************************************/
@@ -120,8 +143,14 @@
 		printk("missed packet!\n");
 	*/
 
-	if (buf[1] & 0x40)	// PUSI ?
+	/* PUSI ? */
+	if (buf[1] & 0x40) {
 		feed->peslen = 0xfffa;
+		feed->pusi_seen = 1;
+	}
+
+	if (feed->pusi_seen == 0)
+		return 0;
 
 	feed->peslen += count;
 
@@ -164,10 +193,23 @@
 		return 0;
 
 	if (sec->check_crc) {
+		struct timespec pre_crc_time;
+
+		if (dvb_demux_performancecheck)
+			pre_crc_time = current_kernel_time();
+
 		section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0);
 		if (section_syntax_indicator &&
-		    demux->check_crc32(feed, sec->secbuf, sec->seclen))
+		    demux->check_crc32(feed, sec->secbuf, sec->seclen)) {
+			if (dvb_demux_performancecheck)
+				demux->total_crc_time +=
+					dvb_dmx_calc_time_delta(pre_crc_time);
 			return -1;
+		}
+
+		if (dvb_demux_performancecheck)
+			demux->total_crc_time +=
+				dvb_dmx_calc_time_delta(pre_crc_time);
 	}
 
 	do {
@@ -351,6 +393,161 @@
 	return 0;
 }
 
+static inline void dvb_dmx_swfilter_output_packet(
+	struct dvb_demux_feed *feed,
+	const u8 *buf)
+{
+	u8 time_stamp[4] = {0};
+	struct dvb_demux *demux = feed->demux;
+
+	/*
+	 * if we output 192 packet with timestamp at head of packet,
+	 * output the timestamp now before the 188 TS packet
+	 */
+	if (demux->tsp_out_format == DMX_TSP_FORMAT_192_HEAD)
+		feed->cb.ts(time_stamp, 4, NULL, 0, &feed->feed.ts, DMX_OK);
+
+	feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
+
+	/*
+	 * if we output 192 packet with timestamp at tail of packet,
+	 * output the timestamp now after the 188 TS packet
+	 */
+	if (demux->tsp_out_format == DMX_TSP_FORMAT_192_TAIL)
+		feed->cb.ts(time_stamp, 4, NULL, 0, &feed->feed.ts, DMX_OK);
+}
+
+static inline void dvb_dmx_configure_decoder_fullness(
+						struct dvb_demux *demux,
+						int initialize)
+{
+	struct dvb_demux_feed *feed;
+	int j;
+
+	for (j = 0; j < demux->feednum; j++) {
+		feed = &demux->feed[j];
+
+		if ((feed->state != DMX_STATE_GO) ||
+			(feed->type != DMX_TYPE_TS) ||
+			!(feed->ts_type & TS_DECODER))
+			continue;
+
+		if (initialize) {
+			if (demux->decoder_fullness_init)
+				demux->decoder_fullness_init(feed);
+		} else {
+			if (demux->decoder_fullness_abort)
+				demux->decoder_fullness_abort(feed);
+		}
+	}
+}
+
+static inline int dvb_dmx_swfilter_buffer_check(
+					struct dvb_demux *demux,
+					u16 pid)
+{
+	int desired_space;
+	int ret;
+	struct dmx_ts_feed *ts;
+	struct dvb_demux_filter *f;
+	struct dvb_demux_feed *feed;
+	int was_locked;
+	int i, j;
+
+	if (likely(spin_is_locked(&demux->lock)))
+		was_locked = 1;
+	else
+		was_locked = 0;
+
+	/*
+	 * Check that there's enough free space for data output.
+	 * If there no space, wait for it (block).
+	 * Since this function is called while spinlock
+	 * is aquired, the lock should be released first.
+	 * Once we get control back, lock is aquired back
+	 * and checks that the filter is still valid.
+	 */
+	for (j = 0; j < demux->feednum; j++) {
+		feed = &demux->feed[j];
+
+		if (demux->sw_filter_abort)
+			return -ENODEV;
+
+		if ((feed->state != DMX_STATE_GO) ||
+			((feed->pid != pid) && (feed->pid != 0x2000)))
+			continue;
+
+		if (feed->type == DMX_TYPE_TS) {
+			desired_space = 192; /* upper bound */
+			ts = &feed->feed.ts;
+
+			if (feed->ts_type & TS_PACKET) {
+				if (likely(was_locked))
+					spin_unlock(&demux->lock);
+
+				ret = demux->buffer_ctrl.ts(ts, desired_space);
+
+				if (likely(was_locked))
+					spin_lock(&demux->lock);
+
+				if (ret < 0)
+					continue;
+			}
+
+			if (demux->sw_filter_abort)
+				return -ENODEV;
+
+			if (!ts->is_filtering)
+				continue;
+
+			if ((feed->ts_type & TS_DECODER) &&
+				(demux->decoder_fullness_wait)) {
+				if (likely(was_locked))
+					spin_unlock(&demux->lock);
+
+				ret = demux->decoder_fullness_wait(
+								feed,
+								desired_space);
+
+				if (likely(was_locked))
+					spin_lock(&demux->lock);
+
+				if (ret < 0)
+					continue;
+			}
+
+			continue;
+		}
+
+		/* else - section case */
+		desired_space = feed->feed.sec.tsfeedp + 188; /* upper bound */
+		for (i = 0; i < demux->filternum; i++) {
+			if (demux->sw_filter_abort)
+				return -EPERM;
+
+			if (!feed->feed.sec.is_filtering)
+				continue;
+
+			f = &demux->filter[i];
+			if (f->feed != feed)
+				continue;
+
+			if (likely(was_locked))
+				spin_unlock(&demux->lock);
+
+			ret = demux->buffer_ctrl.sec(&f->filter, desired_space);
+
+			if (likely(was_locked))
+				spin_lock(&demux->lock);
+
+			if (ret < 0)
+				break;
+		}
+	}
+
+	return 0;
+}
+
 static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
 						const u8 *buf)
 {
@@ -362,8 +559,7 @@
 			if (feed->ts_type & TS_PAYLOAD_ONLY)
 				dvb_dmx_swfilter_payload(feed, buf);
 			else
-				feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
-					    DMX_OK);
+				dvb_dmx_swfilter_output_packet(feed, buf);
 		}
 		if (feed->ts_type & TS_DECODER)
 			if (feed->demux->write_to_decoder)
@@ -446,6 +642,10 @@
 		/* end check */
 	};
 
+	if (demux->playback_mode == DMX_PB_MODE_PULL)
+		if (dvb_dmx_swfilter_buffer_check(demux, pid) < 0)
+			return;
+
 	list_for_each_entry(feed, &demux->feed_list, list_head) {
 		if ((feed->pid != pid) && (feed->pid != 0x2000))
 			continue;
@@ -457,16 +657,25 @@
 
 		if (feed->pid == pid)
 			dvb_dmx_swfilter_packet_type(feed, buf);
-		else if (feed->pid == 0x2000)
-			feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
+		else if ((feed->pid == 0x2000) &&
+			     (feed->feed.ts.is_filtering))
+			dvb_dmx_swfilter_output_packet(feed, buf);
 	}
 }
 
 void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
 			      size_t count)
 {
+	struct timespec pre_time;
+
+	if (dvb_demux_performancecheck)
+		pre_time = current_kernel_time();
+
 	spin_lock(&demux->lock);
 
+	demux->sw_filter_abort = 0;
+	dvb_dmx_configure_decoder_fullness(demux, 1);
+
 	while (count--) {
 		if (buf[0] == 0x47)
 			dvb_dmx_swfilter_packet(demux, buf);
@@ -474,18 +683,24 @@
 	}
 
 	spin_unlock(&demux->lock);
+
+	if (dvb_demux_performancecheck)
+		demux->total_process_time += dvb_dmx_calc_time_delta(pre_time);
 }
 
 EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
 
 static inline int find_next_packet(const u8 *buf, int pos, size_t count,
-				   const int pktsize)
+				   const int pktsize, const int leadingbytes)
 {
 	int start = pos, lost;
 
 	while (pos < count) {
-		if (buf[pos] == 0x47 ||
-		    (pktsize == 204 && buf[pos] == 0xB8))
+		if ((buf[pos] == 0x47 && !leadingbytes) ||
+		    (pktsize == 204 && buf[pos] == 0xB8) ||
+			(pktsize == 192 && leadingbytes &&
+			 (pos+leadingbytes < count) &&
+				buf[pos+leadingbytes] == 0x47))
 			break;
 		pos++;
 	}
@@ -495,7 +710,9 @@
 		/* This garbage is part of a valid packet? */
 		int backtrack = pos - pktsize;
 		if (backtrack >= 0 && (buf[backtrack] == 0x47 ||
-		    (pktsize == 204 && buf[backtrack] == 0xB8)))
+		    (pktsize == 204 && buf[backtrack] == 0xB8) ||
+			(pktsize == 192 &&
+			buf[backtrack+leadingbytes] == 0x47)))
 			return backtrack;
 	}
 
@@ -504,13 +721,20 @@
 
 /* Filter all pktsize= 188 or 204 sized packets and skip garbage. */
 static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
-		size_t count, const int pktsize)
+		size_t count, const int pktsize, const int leadingbytes)
 {
 	int p = 0, i, j;
 	const u8 *q;
+	struct timespec pre_time;
+
+	if (dvb_demux_performancecheck)
+		pre_time = current_kernel_time();
 
 	spin_lock(&demux->lock);
 
+	demux->sw_filter_abort = 0;
+	dvb_dmx_configure_decoder_fullness(demux, 1);
+
 	if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
 		i = demux->tsbufp;
 		j = pktsize - i;
@@ -520,14 +744,22 @@
 			goto bailout;
 		}
 		memcpy(&demux->tsbuf[i], buf, j);
-		if (demux->tsbuf[0] == 0x47) /* double check */
+		if (pktsize == 192 &&
+			leadingbytes &&
+			demux->tsbuf[leadingbytes] == 0x47)  /* double check */
+			dvb_dmx_swfilter_packet(demux, demux->tsbuf+4);
+		else if (demux->tsbuf[0] == 0x47) /* double check */
 			dvb_dmx_swfilter_packet(demux, demux->tsbuf);
 		demux->tsbufp = 0;
 		p += j;
 	}
 
 	while (1) {
-		p = find_next_packet(buf, p, count, pktsize);
+		p = find_next_packet(buf, p, count, pktsize, leadingbytes);
+
+		if (demux->sw_filter_abort)
+			goto bailout;
+
 		if (p >= count)
 			break;
 		if (count - p < pktsize)
@@ -540,6 +772,10 @@
 			demux->tsbuf[0] = 0x47;
 			q = demux->tsbuf;
 		}
+
+		if (pktsize == 192 && leadingbytes)
+			q = &buf[p+leadingbytes];
+
 		dvb_dmx_swfilter_packet(demux, q);
 		p += pktsize;
 	}
@@ -554,20 +790,55 @@
 
 bailout:
 	spin_unlock(&demux->lock);
+
+	if (dvb_demux_performancecheck)
+		demux->total_process_time += dvb_dmx_calc_time_delta(pre_time);
 }
 
 void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
 {
-	_dvb_dmx_swfilter(demux, buf, count, 188);
+	_dvb_dmx_swfilter(demux, buf, count, 188, 0);
 }
 EXPORT_SYMBOL(dvb_dmx_swfilter);
 
 void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
 {
-	_dvb_dmx_swfilter(demux, buf, count, 204);
+	_dvb_dmx_swfilter(demux, buf, count, 204, 0);
 }
 EXPORT_SYMBOL(dvb_dmx_swfilter_204);
 
+void dvb_dmx_swfilter_format(
+			struct dvb_demux *demux,
+			const u8 *buf,
+			size_t count,
+			enum dmx_tsp_format_t tsp_format)
+{
+	switch (tsp_format) {
+	case DMX_TSP_FORMAT_188:
+		_dvb_dmx_swfilter(demux, buf, count, 188, 0);
+		break;
+
+	case DMX_TSP_FORMAT_192_TAIL:
+		_dvb_dmx_swfilter(demux, buf, count, 192, 0);
+		break;
+
+	case DMX_TSP_FORMAT_192_HEAD:
+		_dvb_dmx_swfilter(demux, buf, count, 192, 4);
+		break;
+
+	case DMX_TSP_FORMAT_204:
+		_dvb_dmx_swfilter(demux, buf, count, 204, 0);
+		break;
+
+	default:
+		printk(KERN_ERR "%s: invalid TS packet format (format=%d)\n",
+			   __func__,
+			   tsp_format);
+		break;
+	}
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter_format);
+
 static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux)
 {
 	int i;
@@ -778,6 +1049,13 @@
 	feed->peslen = 0xfffa;
 	feed->buffer = NULL;
 
+	/* default behaviour - pass first PES data even if it is
+	 * partial PES data from previous PES that we didn't receive its header.
+	 * Override this to 0 in your start_feed function in order to handle
+	 * first PES differently.
+	 */
+	feed->pusi_seen = 1;
+
 	(*ts_feed) = &feed->feed.ts;
 	(*ts_feed)->parent = dmx;
 	(*ts_feed)->priv = NULL;
@@ -1119,30 +1397,54 @@
 	return 0;
 }
 
-static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count)
+static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count)
 {
 	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-	void *p;
 
 	if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
 		return -EINVAL;
 
-	p = memdup_user(buf, count);
-	if (IS_ERR(p))
-		return PTR_ERR(p);
-	if (mutex_lock_interruptible(&dvbdemux->mutex)) {
-		kfree(p);
-		return -ERESTARTSYS;
-	}
-	dvb_dmx_swfilter(dvbdemux, p, count);
-	kfree(p);
-	mutex_unlock(&dvbdemux->mutex);
+	dvb_dmx_swfilter_format(dvbdemux, buf, count, dvbdemux->tsp_format);
 
 	if (signal_pending(current))
 		return -EINTR;
 	return count;
 }
 
+static int dvbdmx_write_cancel(struct dmx_demux *demux)
+{
+	struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
+
+	spin_lock_irq(&dvbdmx->lock);
+
+	/* cancel any pending wait for decoder's buffers */
+	dvbdmx->sw_filter_abort = 1;
+	dvbdmx->tsbufp = 0;
+	dvb_dmx_configure_decoder_fullness(dvbdmx, 0);
+
+	spin_unlock_irq(&dvbdmx->lock);
+
+	return 0;
+}
+
+static int dvbdmx_set_playback_mode(struct dmx_demux *demux,
+				 enum dmx_playback_mode_t mode,
+				 dmx_ts_fullness ts_fullness_callback,
+				 dmx_section_fullness sec_fullness_callback)
+{
+	struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
+
+	mutex_lock(&dvbdmx->mutex);
+
+	dvbdmx->playback_mode = mode;
+	dvbdmx->buffer_ctrl.ts = ts_fullness_callback;
+	dvbdmx->buffer_ctrl.sec = sec_fullness_callback;
+
+	mutex_unlock(&dvbdmx->mutex);
+
+	return 0;
+}
+
 static int dvbdmx_add_frontend(struct dmx_demux *demux,
 			       struct dmx_frontend *frontend)
 {
@@ -1214,6 +1516,40 @@
 	return 0;
 }
 
+static int dvbdmx_set_tsp_format(
+	struct dmx_demux *demux,
+	enum dmx_tsp_format_t tsp_format)
+{
+	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+	if ((tsp_format > DMX_TSP_FORMAT_204) ||
+		(tsp_format < DMX_TSP_FORMAT_188))
+		return -EINVAL;
+
+	mutex_lock(&dvbdemux->mutex);
+
+	dvbdemux->tsp_format = tsp_format;
+	mutex_unlock(&dvbdemux->mutex);
+	return 0;
+}
+
+static int dvbdmx_set_tsp_out_format(
+	struct dmx_demux *demux,
+	enum dmx_tsp_format_t tsp_format)
+{
+	struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+	if ((tsp_format > DMX_TSP_FORMAT_192_HEAD) ||
+		(tsp_format < DMX_TSP_FORMAT_188))
+		return -EINVAL;
+
+	mutex_lock(&dvbdemux->mutex);
+
+	dvbdemux->tsp_out_format = tsp_format;
+	mutex_unlock(&dvbdemux->mutex);
+	return 0;
+}
+
 int dvb_dmx_init(struct dvb_demux *dvbdemux)
 {
 	int i;
@@ -1232,6 +1568,30 @@
 		dvbdemux->filter = NULL;
 		return -ENOMEM;
 	}
+
+	dvbdemux->total_process_time = 0;
+	dvbdemux->total_crc_time = 0;
+	snprintf(dvbdemux->alias,
+			MAX_DVB_DEMUX_NAME_LEN,
+			"demux%d",
+			dvb_demux_index++);
+
+	dvbdemux->debugfs_demux_dir = debugfs_create_dir(dvbdemux->alias, NULL);
+
+	if (dvbdemux->debugfs_demux_dir != NULL) {
+		debugfs_create_u32(
+			"total_processing_time",
+			S_IRUGO|S_IWUGO,
+			dvbdemux->debugfs_demux_dir,
+			&dvbdemux->total_process_time);
+
+		debugfs_create_u32(
+			"total_crc_time",
+			S_IRUGO|S_IWUGO,
+			dvbdemux->debugfs_demux_dir,
+			&dvbdemux->total_crc_time);
+	}
+
 	for (i = 0; i < dvbdemux->filternum; i++) {
 		dvbdemux->filter[i].state = DMX_STATE_FREE;
 		dvbdemux->filter[i].index = i;
@@ -1258,6 +1618,9 @@
 	dvbdemux->recording = 0;
 	dvbdemux->tsbufp = 0;
 
+	dvbdemux->tsp_format = DMX_TSP_FORMAT_188;
+	dvbdemux->tsp_out_format = DMX_TSP_FORMAT_188;
+
 	if (!dvbdemux->check_crc32)
 		dvbdemux->check_crc32 = dvb_dmx_crc32;
 
@@ -1269,6 +1632,8 @@
 	dmx->open = dvbdmx_open;
 	dmx->close = dvbdmx_close;
 	dmx->write = dvbdmx_write;
+	dmx->write_cancel = dvbdmx_write_cancel;
+	dmx->set_playback_mode = dvbdmx_set_playback_mode;
 	dmx->allocate_ts_feed = dvbdmx_allocate_ts_feed;
 	dmx->release_ts_feed = dvbdmx_release_ts_feed;
 	dmx->allocate_section_feed = dvbdmx_allocate_section_feed;
@@ -1281,6 +1646,9 @@
 	dmx->disconnect_frontend = dvbdmx_disconnect_frontend;
 	dmx->get_pes_pids = dvbdmx_get_pes_pids;
 
+	dmx->set_tsp_format = dvbdmx_set_tsp_format;
+	dmx->set_tsp_out_format = dvbdmx_set_tsp_out_format;
+
 	mutex_init(&dvbdemux->mutex);
 	spin_lock_init(&dvbdemux->lock);
 
@@ -1291,6 +1659,9 @@
 
 void dvb_dmx_release(struct dvb_demux *dvbdemux)
 {
+	if (dvbdemux->debugfs_demux_dir != NULL)
+		debugfs_remove_recursive(dvbdemux->debugfs_demux_dir);
+
 	vfree(dvbdemux->cnt_storage);
 	vfree(dvbdemux->filter);
 	vfree(dvbdemux->feed);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index a7d876f..297f3df 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -4,6 +4,8 @@
  * Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler
  *                         for convergence integrated media GmbH
  *
+ * 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 Lesser General Public License
  * as published by the Free Software Foundation; either version 2.1
@@ -27,6 +29,7 @@
 #include <linux/timer.h>
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
+#include <linux/debugfs.h>
 
 #include "demux.h"
 
@@ -107,6 +110,10 @@
 	int (*stop_feed)(struct dvb_demux_feed *feed);
 	int (*write_to_decoder)(struct dvb_demux_feed *feed,
 				 const u8 *buf, size_t len);
+	int (*decoder_fullness_init)(struct dvb_demux_feed *feed);
+	int (*decoder_fullness_wait)(struct dvb_demux_feed *feed,
+				 size_t required_space);
+	int (*decoder_fullness_abort)(struct dvb_demux_feed *feed);
 	u32 (*check_crc32)(struct dvb_demux_feed *feed,
 			    const u8 *buf, size_t len);
 	void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst,
@@ -136,6 +143,28 @@
 
 	struct timespec speed_last_time; /* for TS speed check */
 	uint32_t speed_pkts_cnt; /* for TS speed check */
+
+	enum dmx_tsp_format_t tsp_format;
+	enum dmx_tsp_format_t tsp_out_format;
+
+	enum dmx_playback_mode_t playback_mode;
+	int sw_filter_abort;
+
+	struct {
+		dmx_ts_fullness ts;
+		dmx_section_fullness sec;
+	} buffer_ctrl;
+
+	/*
+	 * the following is used for debugfs exposing info
+	 * about dvb demux performance.
+	 */
+#define MAX_DVB_DEMUX_NAME_LEN 10
+	char alias[MAX_DVB_DEMUX_NAME_LEN];
+
+	u32 total_process_time;
+	u32 total_crc_time;
+	struct dentry *debugfs_demux_dir;
 };
 
 int dvb_dmx_init(struct dvb_demux *dvbdemux);
@@ -145,5 +174,10 @@
 void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
 void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf,
 			  size_t count);
+void dvb_dmx_swfilter_format(
+			struct dvb_demux *demux, const u8 *buf,
+			size_t count,
+			enum dmx_tsp_format_t tsp_format);
+
 
 #endif /* _DVB_DEMUX_H_ */
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
index a5712cd..36cc475 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
@@ -5,6 +5,8 @@
  * Copyright (C) 2003 Oliver Endriss
  * Copyright (C) 2004 Andrew de Quincey
  *
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
  * based on code originally found in av7110.c & dvb_ci.c:
  * Copyright (C) 1999-2003 Ralph  Metzler
  *                       & Marcus Metzler for convergence integrated media GmbH
@@ -37,6 +39,8 @@
 
 #define PKT_READY 0
 #define PKT_DISPOSED 1
+#define PKT_PENDING 2
+
 
 
 void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
@@ -166,6 +170,35 @@
 	return len;
 }
 
+ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
+					const u8 *buf, size_t len)
+{
+	size_t todo = len;
+	size_t split;
+	ssize_t oldpwrite = rbuf->pwrite;
+
+	split = (rbuf->pwrite + len > rbuf->size) ?
+			rbuf->size - rbuf->pwrite :
+			0;
+
+	if (split > 0) {
+		if (copy_from_user(rbuf->data + rbuf->pwrite, buf, split))
+			return -EFAULT;
+		buf += split;
+		todo -= split;
+		rbuf->pwrite = 0;
+	}
+
+	if (copy_from_user(rbuf->data + rbuf->pwrite, buf, todo)) {
+		rbuf->pwrite = oldpwrite;
+		return -EFAULT;
+	}
+
+	rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
+
+	return len;
+}
+
 ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len)
 {
 	int status;
@@ -180,6 +213,31 @@
 	return status;
 }
 
+ssize_t dvb_ringbuffer_pkt_start(struct dvb_ringbuffer *rbuf, size_t len)
+{
+	ssize_t oldpwrite = rbuf->pwrite;
+
+	DVB_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8);
+	DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff);
+	DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_PENDING);
+
+	return oldpwrite;
+}
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_start);
+
+int dvb_ringbuffer_pkt_close(struct dvb_ringbuffer *rbuf, ssize_t idx)
+{
+	idx = (idx + 2) % rbuf->size;
+
+	if (rbuf->data[idx] != PKT_PENDING)
+		return -EINVAL;
+
+	rbuf->data[idx] = PKT_READY;
+
+	return 0;
+}
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_close);
+
 ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
 				int offset, u8 __user *buf, size_t len)
 {
@@ -187,6 +245,9 @@
 	size_t split;
 	size_t pktlen;
 
+	if (DVB_RINGBUFFER_PEEK(rbuf, (idx+2)) != PKT_READY)
+		return -EINVAL;
+
 	pktlen = rbuf->data[idx] << 8;
 	pktlen |= rbuf->data[(idx + 1) % rbuf->size];
 	if (offset > pktlen) return -EINVAL;
@@ -207,6 +268,7 @@
 
 	return len;
 }
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_read_user);
 
 ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
 				int offset, u8* buf, size_t len)
@@ -215,9 +277,13 @@
 	size_t split;
 	size_t pktlen;
 
+	if (rbuf->data[(idx + 2) % rbuf->size] != PKT_READY)
+		return -EINVAL;
+
 	pktlen = rbuf->data[idx] << 8;
 	pktlen |= rbuf->data[(idx + 1) % rbuf->size];
 	if (offset > pktlen) return -EINVAL;
+
 	if ((offset + len) > pktlen) len = pktlen - offset;
 
 	idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
@@ -232,6 +298,7 @@
 	memcpy(buf, rbuf->data+idx, todo);
 	return len;
 }
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_read);
 
 void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx)
 {
@@ -251,6 +318,7 @@
 		}
 	}
 }
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_dispose);
 
 ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen)
 {
@@ -279,6 +347,9 @@
 			return idx;
 		}
 
+		if (curpktstatus == PKT_PENDING)
+			return -EFAULT;
+
 		consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE;
 		idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
 	}
@@ -286,8 +357,7 @@
 	// no packets available
 	return -1;
 }
-
-
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_next);
 
 EXPORT_SYMBOL(dvb_ringbuffer_init);
 EXPORT_SYMBOL(dvb_ringbuffer_empty);
@@ -297,3 +367,5 @@
 EXPORT_SYMBOL(dvb_ringbuffer_read_user);
 EXPORT_SYMBOL(dvb_ringbuffer_read);
 EXPORT_SYMBOL(dvb_ringbuffer_write);
+EXPORT_SYMBOL(dvb_ringbuffer_write_user);
+
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
index 41f04da..8b591a6 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
@@ -5,6 +5,8 @@
  * Copyright (C) 2003 Oliver Endriss
  * Copyright (C) 2004 Andrew de Quincey
  *
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
  * based on code originally found in av7110.c & dvb_ci.c:
  * Copyright (C) 1999-2003 Ralph Metzler & Marcus Metzler
  *                         for convergence integrated media GmbH
@@ -134,6 +136,8 @@
 extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
 				    size_t len);
 
+extern ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
+					const u8 *buf, size_t len);
 
 /**
  * Write a packet into the ringbuffer.
@@ -183,4 +187,30 @@
 extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen);
 
 
+/**
+ * Start a new packet that will be written directly by the user to the packet buffer.
+ * The function only writes the header of the packet into the packet buffer,
+ * and the packet is in pending state (can't be read by the reader) until it is
+ * closed using dvb_ringbuffer_pkt_close. You must write the data into the
+ * packet buffer using dvb_ringbuffer_write followed by
+ * dvb_ringbuffer_pkt_close.
+ *
+ * <rbuf> Ringbuffer concerned.
+ * <len> Size of the packet's data
+ * returns Index of the packet's header that was started.
+ */
+extern ssize_t dvb_ringbuffer_pkt_start(struct dvb_ringbuffer *rbuf,
+						size_t len);
+
+/**
+ * Close a packet that was started using dvb_ringbuffer_pkt_start.
+ * The packet will be marked as ready to be ready.
+ *
+ * <rbuf> Ringbuffer concerned.
+ * <idx> Packet index that was returned by dvb_ringbuffer_pkt_start
+ * returns error status, -EINVAL if the provided index is invalid
+ */
+extern int dvb_ringbuffer_pkt_close(struct dvb_ringbuffer *rbuf, ssize_t idx);
+
+
 #endif /* _DVB_RINGBUFFER_H_ */
diff --git a/drivers/media/dvb/mpq/Kconfig b/drivers/media/dvb/mpq/Kconfig
new file mode 100644
index 0000000..868ad8c
--- /dev/null
+++ b/drivers/media/dvb/mpq/Kconfig
@@ -0,0 +1,12 @@
+config DVB_MPQ
+	tristate "Qualcomm Multimedia Processor DVB Adapter"
+	depends on ARCH_MSM && DVB_CORE
+	default n
+
+	help
+	  Support for Qualcomm MPQ based DVB adapter.
+	  Say Y or M if you own such a device and want to use it.
+
+source "drivers/media/dvb/mpq/demux/Kconfig"
+
+
diff --git a/drivers/media/dvb/mpq/Makefile b/drivers/media/dvb/mpq/Makefile
new file mode 100644
index 0000000..7ccf13e
--- /dev/null
+++ b/drivers/media/dvb/mpq/Makefile
@@ -0,0 +1,5 @@
+
+obj-$(CONFIG_DVB_MPQ)	    += adapter/
+obj-$(CONFIG_DVB_MPQ_DEMUX) += demux/
+
+
diff --git a/drivers/media/dvb/mpq/adapter/Makefile b/drivers/media/dvb/mpq/adapter/Makefile
new file mode 100644
index 0000000..ed664da
--- /dev/null
+++ b/drivers/media/dvb/mpq/adapter/Makefile
@@ -0,0 +1,8 @@
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/mpq/include/
+
+obj-$(CONFIG_DVB_MPQ) += mpq-adapter.o
+
+mpq-adapter-y := mpq_adapter.o mpq_stream_buffer.o
+
diff --git a/drivers/media/dvb/mpq/adapter/mpq_adapter.c b/drivers/media/dvb/mpq/adapter/mpq_adapter.c
new file mode 100644
index 0000000..9664f04
--- /dev/null
+++ b/drivers/media/dvb/mpq/adapter/mpq_adapter.c
@@ -0,0 +1,212 @@
+/* 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 "mpq_adapter.h"
+#include "mpq_dvb_debug.h"
+
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/* data-structure holding MPQ adapter information */
+static struct
+{
+	/* MPQ adapter registered to dvb-core */
+	struct dvb_adapter adapter;
+
+	/* mutex protect against the data-structure */
+	struct mutex mutex;
+
+	/* List of stream interfaces registered to the MPQ adapter */
+	struct {
+		/* pointer to the stream buffer using for data tunneling */
+		struct mpq_streambuffer *stream_buffer;
+
+		/* callback triggered when the stream interface is registered */
+		mpq_adapter_stream_if_callback callback;
+
+		/* parameter passed to the callback function */
+		void *user_param;
+	} interfaces[MPQ_ADAPTER_MAX_NUM_OF_INTERFACES];
+} mpq_info;
+
+
+/**
+ * Initialize MPQ DVB adapter module.
+ *
+ * Return     error status
+ */
+static int __init mpq_adapter_init(void)
+{
+	int i;
+	int result;
+
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	mutex_init(&mpq_info.mutex);
+
+	/* reset stream interfaces list */
+	for (i = 0; i < MPQ_ADAPTER_MAX_NUM_OF_INTERFACES; i++) {
+		mpq_info.interfaces[i].stream_buffer = NULL;
+		mpq_info.interfaces[i].callback = NULL;
+	}
+
+	/* regsiter a new dvb-adapter to dvb-core */
+	result = dvb_register_adapter(&mpq_info.adapter,
+								  "Qualcomm DVB adapter",
+								  THIS_MODULE,
+								  NULL,
+								  adapter_nr);
+
+	if (result < 0) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: dvb_register_adapter failed, errno %d\n",
+			__func__,
+			result);
+	}
+
+	return result;
+}
+
+
+/**
+ * Cleanup MPQ DVB adapter module.
+ */
+static void __exit mpq_adapter_exit(void)
+{
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	/* un-regsiter adapter from dvb-core */
+	dvb_unregister_adapter(&mpq_info.adapter);
+	mutex_destroy(&mpq_info.mutex);
+}
+
+struct dvb_adapter *mpq_adapter_get(void)
+{
+	return &mpq_info.adapter;
+}
+EXPORT_SYMBOL(mpq_adapter_get);
+
+
+int mpq_adapter_register_stream_if(
+		enum mpq_adapter_stream_if interface_id,
+		struct mpq_streambuffer *stream_buffer)
+{
+	int ret;
+
+	if (interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES) {
+		ret = -EINVAL;
+		goto register_failed;
+	}
+
+	if (mutex_lock_interruptible(&mpq_info.mutex)) {
+		ret = -ERESTARTSYS;
+		goto register_failed;
+	}
+
+	if (mpq_info.interfaces[interface_id].stream_buffer != NULL) {
+		/* already registered interface */
+		ret = -EINVAL;
+		goto register_failed_unlock_mutex;
+	}
+
+	mpq_info.interfaces[interface_id].stream_buffer = stream_buffer;
+	mutex_unlock(&mpq_info.mutex);
+
+	/*
+	 * If callback is installed, trigger it to notify that
+	 * stream interface was registered.
+	 */
+	if (mpq_info.interfaces[interface_id].callback != NULL) {
+		mpq_info.interfaces[interface_id].callback(
+				interface_id,
+				mpq_info.interfaces[interface_id].user_param);
+	}
+
+	return 0;
+
+register_failed_unlock_mutex:
+	mutex_unlock(&mpq_info.mutex);
+register_failed:
+	return ret;
+}
+EXPORT_SYMBOL(mpq_adapter_register_stream_if);
+
+
+int mpq_adapter_unregister_stream_if(
+		enum mpq_adapter_stream_if interface_id)
+{
+	if (interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&mpq_info.mutex))
+		return -ERESTARTSYS;
+
+	/* clear the registered interface */
+	mpq_info.interfaces[interface_id].stream_buffer = NULL;
+
+	mutex_unlock(&mpq_info.mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(mpq_adapter_unregister_stream_if);
+
+
+int mpq_adapter_get_stream_if(
+		enum mpq_adapter_stream_if interface_id,
+		struct mpq_streambuffer **stream_buffer)
+{
+	if ((interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES) ||
+		(stream_buffer == NULL))
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&mpq_info.mutex))
+		return -ERESTARTSYS;
+
+	*stream_buffer = mpq_info.interfaces[interface_id].stream_buffer;
+
+	mutex_unlock(&mpq_info.mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(mpq_adapter_get_stream_if);
+
+
+int mpq_adapter_notify_stream_if(
+		enum mpq_adapter_stream_if interface_id,
+		mpq_adapter_stream_if_callback callback,
+		void *user_param)
+{
+	if (interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&mpq_info.mutex))
+		return -ERESTARTSYS;
+
+	mpq_info.interfaces[interface_id].callback = callback;
+	mpq_info.interfaces[interface_id].user_param = user_param;
+
+	mutex_unlock(&mpq_info.mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(mpq_adapter_notify_stream_if);
+
+
+module_init(mpq_adapter_init);
+module_exit(mpq_adapter_exit);
+
+MODULE_DESCRIPTION("Qualcomm MPQ adapter");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c b/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c
new file mode 100644
index 0000000..738d730
--- /dev/null
+++ b/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c
@@ -0,0 +1,224 @@
+/* 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/sched.h>
+#include <linux/wait.h>
+#include "mpq_dvb_debug.h"
+#include "mpq_stream_buffer.h"
+
+
+void mpq_streambuffer_init(
+		struct mpq_streambuffer *sbuff,
+		void *data_buff, size_t data_buff_len,
+		void *packet_buff, size_t packet_buff_size)
+{
+	dvb_ringbuffer_init(&sbuff->raw_data, data_buff, data_buff_len);
+	dvb_ringbuffer_init(&sbuff->packet_data, packet_buff, packet_buff_size);
+}
+EXPORT_SYMBOL(mpq_streambuffer_init);
+
+
+ssize_t mpq_streambuffer_pkt_next(
+		struct mpq_streambuffer *sbuff,
+		ssize_t idx, size_t *pktlen)
+{
+	return dvb_ringbuffer_pkt_next(&sbuff->packet_data, idx, pktlen);
+}
+EXPORT_SYMBOL(mpq_streambuffer_pkt_next);
+
+
+ssize_t mpq_streambuffer_pkt_read(
+		struct mpq_streambuffer *sbuff,
+		size_t idx,
+		struct mpq_streambuffer_packet_header *packet,
+		u8 *user_data)
+{
+	size_t ret;
+	size_t read_len;
+
+	/* read-out the packet header first */
+	ret = dvb_ringbuffer_pkt_read(
+				&sbuff->packet_data, idx, 0,
+				(u8 *)packet,
+				sizeof(struct mpq_streambuffer_packet_header));
+
+	/* verify length, at least packet header should exist */
+	if (ret != sizeof(struct mpq_streambuffer_packet_header))
+		return -EINVAL;
+
+	read_len = ret;
+
+	/* read-out private user-data if there are such */
+	if ((packet->user_data_len) && (user_data != NULL)) {
+		ret = dvb_ringbuffer_pkt_read(
+				&sbuff->packet_data,
+				idx,
+				sizeof(struct mpq_streambuffer_packet_header),
+				user_data,
+				packet->user_data_len);
+
+		if (ret < 0)
+			return ret;
+
+		read_len += ret;
+	}
+
+	return read_len;
+}
+EXPORT_SYMBOL(mpq_streambuffer_pkt_read);
+
+
+int mpq_streambuffer_pkt_dispose(
+			struct mpq_streambuffer *sbuff,
+			size_t idx,
+			int dispose_data)
+{
+	int ret;
+	struct mpq_streambuffer_packet_header packet;
+
+	if (dispose_data) {
+		/* read-out the packet header first */
+		ret = dvb_ringbuffer_pkt_read(
+				&sbuff->packet_data,
+				idx,
+				0,
+				(u8 *)&packet,
+				sizeof(struct mpq_streambuffer_packet_header));
+
+		if (ret != sizeof(struct mpq_streambuffer_packet_header))
+			return -EINVAL;
+
+		/* Advance the read pointer in the raw-data buffer first */
+		ret = mpq_streambuffer_data_read_dispose(
+							sbuff,
+							packet.raw_data_len);
+		if (ret != 0)
+			return ret;
+	}
+
+	/* Now clear the packet from the packet header */
+	dvb_ringbuffer_pkt_dispose(&sbuff->packet_data, idx);
+
+	return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_pkt_dispose);
+
+
+int mpq_streambuffer_pkt_write(
+			struct mpq_streambuffer *sbuff,
+			struct mpq_streambuffer_packet_header *packet,
+			u8 *user_data)
+{
+	ssize_t idx;
+	size_t len;
+
+	len =
+		sizeof(struct mpq_streambuffer_packet_header) +
+		packet->user_data_len;
+
+	/* Make sure enough space available for packet header */
+	if (dvb_ringbuffer_free(&sbuff->packet_data) < len)
+		return -ENOSPC;
+
+	/* Starting writting packet header */
+	idx = dvb_ringbuffer_pkt_start(&sbuff->packet_data, len);
+
+	/* Write non-user private data header */
+	dvb_ringbuffer_write(
+				&sbuff->packet_data,
+				(u8 *)packet,
+				sizeof(struct mpq_streambuffer_packet_header));
+
+	/* Write user's own private data header */
+	dvb_ringbuffer_write(&sbuff->packet_data,
+						 user_data,
+						 packet->user_data_len);
+
+	dvb_ringbuffer_pkt_close(&sbuff->packet_data, idx);
+
+	wake_up_all(&sbuff->packet_data.queue);
+
+	return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_pkt_write);
+
+
+ssize_t mpq_streambuffer_data_write(
+			struct mpq_streambuffer *sbuff,
+			const u8 *buf, size_t len)
+{
+	int res;
+
+	if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len))
+		return -ENOSPC;
+
+	res = dvb_ringbuffer_write(&sbuff->raw_data, buf, len);
+	wake_up_all(&sbuff->raw_data.queue);
+
+	return res;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_write);
+
+
+int mpq_streambuffer_data_write_deposit(
+				struct mpq_streambuffer *sbuff,
+				size_t len)
+{
+	if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len))
+		return -ENOSPC;
+
+	sbuff->raw_data.pwrite =
+		(sbuff->raw_data.pwrite+len) % sbuff->raw_data.size;
+
+	wake_up_all(&sbuff->raw_data.queue);
+
+	return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_write_deposit);
+
+
+size_t mpq_streambuffer_data_read(
+				struct mpq_streambuffer *sbuff,
+				u8 *buf, size_t len)
+{
+	int actual_len;
+
+	actual_len = dvb_ringbuffer_avail(&sbuff->raw_data);
+	if (actual_len < len)
+		len = actual_len;
+
+	if (actual_len)
+		dvb_ringbuffer_read(&sbuff->raw_data, buf, actual_len);
+
+	wake_up_all(&sbuff->raw_data.queue);
+
+	return actual_len;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_read);
+
+
+int mpq_streambuffer_data_read_dispose(
+			struct mpq_streambuffer *sbuff,
+			size_t len)
+{
+	if (unlikely(dvb_ringbuffer_avail(&sbuff->raw_data) < len))
+		return -EINVAL;
+
+	DVB_RINGBUFFER_SKIP(&sbuff->raw_data, len);
+
+	wake_up_all(&sbuff->raw_data.queue);
+	return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_read_dispose);
+
diff --git a/drivers/media/dvb/mpq/demux/Kconfig b/drivers/media/dvb/mpq/demux/Kconfig
new file mode 100644
index 0000000..34961c2
--- /dev/null
+++ b/drivers/media/dvb/mpq/demux/Kconfig
@@ -0,0 +1,45 @@
+config DVB_MPQ_DEMUX
+	tristate "DVB Demux Device"
+	depends on DVB_MPQ && ION && ION_MSM
+	default n
+
+	help
+	  Support for Qualcomm based dvb demux device.
+	  Say Y or M if you own such a device and want to use it.
+
+config DVB_MPQ_NUM_DMX_DEVICES
+	int "Number of demux devices"
+	depends on DVB_MPQ_DEMUX
+	default 4
+	range 1 255
+
+	help
+	  Configure number of demux devices. Depends on your use-cases for maximum concurrent stream playback.
+
+choice
+	prompt "Demux Hardware Plugin"
+	depends on DVB_MPQ_DEMUX
+	default DVB_MPQ_TSIF
+	help
+	  Enable support of specific demux HW plugin depending on the existing HW support.
+	  Depending on the enabled HW, demux may take advantage of HW capbailities to perform some tasks in HW instead of SW.
+
+	config DVB_MPQ_TSPP1
+		bool "TSPPv1 plugin"
+		depends on TSPP
+		help
+			Use this option of your HW has Transport Stream Packet Processor (TSPP) version1 support
+
+	config DVB_MPQ_TSPP2
+		bool "TSPPv2 plugin"
+		depends on TSPP
+		help
+			Use this option of your HW has Transport Stream Packet Processor (TSPP) version2 support
+
+	config DVB_MPQ_TSIF
+		bool "TSIF plugin"
+		depends on TSIF
+		help
+			Use this option of your HW has only TSIF input without any Transport Stream Packet Processor (TSPP) support
+endchoice
+
diff --git a/drivers/media/dvb/mpq/demux/Makefile b/drivers/media/dvb/mpq/demux/Makefile
new file mode 100644
index 0000000..b9310c3
--- /dev/null
+++ b/drivers/media/dvb/mpq/demux/Makefile
@@ -0,0 +1,14 @@
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/mpq/include/
+
+obj-$(CONFIG_DVB_MPQ_DEMUX) += mpq-dmx-hw-plugin.o
+
+mpq-dmx-hw-plugin-y := mpq_dmx_plugin_common.o
+
+mpq-dmx-hw-plugin-$(CONFIG_DVB_MPQ_TSPP1) += mpq_dmx_plugin_tspp_v1.o
+
+mpq-dmx-hw-plugin-$(CONFIG_DVB_MPQ_TSPP2) += mpq_dmx_plugin_tspp_v2.o
+
+mpq-dmx-hw-plugin-$(CONFIG_DVB_MPQ_TSIF) += mpq_dmx_plugin_tsif.o
+
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
new file mode 100644
index 0000000..e7bbfcb
--- /dev/null
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
@@ -0,0 +1,1239 @@
+/* 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/vmalloc.h>
+#include "mpq_dvb_debug.h"
+#include "mpq_dmx_plugin_common.h"
+
+
+/* Length of mandatory fields that must exist in header of video PES */
+#define PES_MANDATORY_FIELDS_LEN			9
+
+
+/*
+ * 500 PES header packets in the meta-data buffer,
+ * should be more than enough
+ */
+#define VIDEO_NUM_OF_PES_PACKETS			500
+
+#define VIDEO_META_DATA_BUFFER_SIZE              \
+	(VIDEO_NUM_OF_PES_PACKETS *                  \
+	  (DVB_RINGBUFFER_PKTHDRSIZE +               \
+	   sizeof(struct mpq_streambuffer_packet_header) + \
+	   sizeof(struct mpq_adapter_video_meta_data)))
+
+/*
+ * The following threshold defines gap from end of ring-buffer
+ * from which new PES payload will not be written to make
+ * sure that the PES payload does not wrap-around at end of the
+ * buffer. Instead, padding will be inserted and the new PES will
+ * be written from the beginning of the buffer.
+ * Setting this to 0 means no padding will be added.
+ */
+#define VIDEO_WRAP_AROUND_THRESHOLD			(1024*1024+512*1024)
+
+/*
+ * PCR/STC information length saved in ring-buffer.
+ * PCR / STC are saved in ring-buffer in the following form:
+ * <8 bit flags><64 bits of STC> <64bits of PCR>
+ * STC and PCR values are in 27MHz.
+ * The current flags that are defined:
+ * 0x00000001: discontinuity_indicator
+ */
+#define PCR_STC_LEN							17
+
+
+/* Number of demux devices, has default of linux configuration */
+static int mpq_demux_device_num = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
+module_param(mpq_demux_device_num, int, S_IRUGO);
+
+
+/* Global data-structure for managing demux devices */
+static struct
+{
+	/* ION demux client used for memory allocation */
+	struct ion_client *ion_client;
+
+	/* demux devices array */
+	struct mpq_demux *devices;
+
+	/* Stream buffers objects used for tunneling to decoders */
+	struct mpq_streambuffer
+		decoder_buffers[MPQ_ADAPTER_MAX_NUM_OF_INTERFACES];
+
+	/*
+	 * Indicates whether we allow decoder's data to
+	 * wrap-around in the output buffer or padding is
+	 * inserted in such case.
+	 */
+	int decoder_data_wrap;
+} mpq_dmx_info;
+
+
+/* Check that PES header is valid and that it is a video PES */
+static int mpq_dmx_is_valid_video_pes(struct pes_packet_header *pes_header)
+{
+	/* start-code valid? */
+	if ((pes_header->packet_start_code_prefix_1 != 0) ||
+		(pes_header->packet_start_code_prefix_2 != 0) ||
+		(pes_header->packet_start_code_prefix_3 != 1))
+		return -EINVAL;
+
+	/* stream_id is video? */
+	if ((pes_header->stream_id & 0xF0) != 0xE0)
+		return -EINVAL;
+
+	return 0;
+}
+
+
+/* Extend dvb-demux debugfs with HW statistics */
+void mpq_dmx_init_hw_statistics(struct mpq_demux *mpq_demux)
+{
+	/*
+	 * Extend dvb-demux debugfs with HW statistics.
+	 * Note that destruction of debugfs directory is done
+	 * when dvb-demux is terminated.
+	 */
+	mpq_demux->hw_notification_count = 0;
+	mpq_demux->hw_notification_rate = 0;
+	mpq_demux->hw_notification_size = 0;
+	mpq_demux->decoder_tsp_drop_count = 0;
+
+	if (mpq_demux->demux.debugfs_demux_dir != NULL) {
+		debugfs_create_u32(
+			"hw_notification_rate",
+			S_IRUGO|S_IWUGO,
+			mpq_demux->demux.debugfs_demux_dir,
+			&mpq_demux->hw_notification_rate);
+
+		debugfs_create_u32(
+			"hw_notification_count",
+			S_IRUGO|S_IWUGO,
+			mpq_demux->demux.debugfs_demux_dir,
+			&mpq_demux->hw_notification_count);
+
+		debugfs_create_u32(
+			"hw_notification_size",
+			S_IRUGO|S_IWUGO,
+			mpq_demux->demux.debugfs_demux_dir,
+			&mpq_demux->hw_notification_size);
+
+		debugfs_create_u32(
+			"decoder_tsp_drop_count",
+			S_IRUGO|S_IWUGO,
+			mpq_demux->demux.debugfs_demux_dir,
+			&mpq_demux->decoder_tsp_drop_count);
+	}
+}
+EXPORT_SYMBOL(mpq_dmx_init_hw_statistics);
+
+
+/* Update dvb-demux debugfs with HW notification statistics */
+void mpq_dmx_update_hw_statistics(struct mpq_demux *mpq_demux)
+{
+	struct timespec curr_time, delta_time;
+	u64 delta_time_ms;
+
+	curr_time = current_kernel_time();
+	if (likely(mpq_demux->hw_notification_count)) {
+		/* calculate time-delta between notifications */
+		delta_time =
+			timespec_sub(
+					curr_time,
+					mpq_demux->last_notification_time);
+
+		delta_time_ms = (u64)timespec_to_ns(&delta_time);
+		delta_time_ms = div64_u64(delta_time_ms, 1000000); /* ns->ms */
+
+		mpq_demux->hw_notification_rate = delta_time_ms;
+	}
+
+	mpq_demux->hw_notification_count++;
+	mpq_demux->last_notification_time = curr_time;
+}
+EXPORT_SYMBOL(mpq_dmx_update_hw_statistics);
+
+
+int mpq_dmx_plugin_init(mpq_dmx_init dmx_init_func)
+{
+	int i;
+	int result;
+	struct mpq_demux *mpq_demux;
+	struct dvb_adapter *mpq_adapter;
+
+	MPQ_DVB_DBG_PRINT("%s executed, device num %d\n",
+					  __func__,
+					  mpq_demux_device_num);
+
+	mpq_adapter = mpq_adapter_get();
+
+	if (mpq_adapter == NULL) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_adapter is not valid\n",
+			__func__);
+		result = -EPERM;
+		goto init_failed;
+	}
+
+	if (mpq_demux_device_num == 0) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_demux_device_num set to 0\n",
+			__func__);
+
+		result = -EPERM;
+		goto init_failed;
+	}
+
+	mpq_dmx_info.devices = NULL;
+	mpq_dmx_info.ion_client = NULL;
+
+	/* TODO: the following should be set based on the decoder */
+	mpq_dmx_info.decoder_data_wrap = 0;
+
+	/* Allocate memory for all MPQ devices */
+	mpq_dmx_info.devices =
+		vmalloc(mpq_demux_device_num*sizeof(struct mpq_demux));
+
+	if (!mpq_dmx_info.devices) {
+		MPQ_DVB_ERR_PRINT(
+				"%s: failed to allocate devices memory\n",
+				__func__);
+
+		result = -ENOMEM;
+		goto init_failed;
+	}
+
+	/* Zero allocated memory */
+	memset(mpq_dmx_info.devices,
+		   0,
+		   mpq_demux_device_num*sizeof(struct mpq_demux));
+
+	/*
+	 * Create a new ION client used by demux to allocate memory
+	 * for decoder's buffers.
+	 */
+	mpq_dmx_info.ion_client =
+		msm_ion_client_create(UINT_MAX, "demux client");
+
+	if (IS_ERR_OR_NULL(mpq_dmx_info.ion_client)) {
+		MPQ_DVB_ERR_PRINT(
+				"%s: msm_ion_client_create\n",
+				__func__);
+
+		result = PTR_ERR(mpq_dmx_info.ion_client);
+		mpq_dmx_info.ion_client = NULL;
+		goto init_failed_free_demux_devices;
+	}
+
+	/* Initialize and register all demux devices to the system */
+	for (i = 0; i < mpq_demux_device_num; i++) {
+		mpq_demux = mpq_dmx_info.devices+i;
+
+		/* initialize demux source to memory by default */
+		mpq_demux->source = DMX_SOURCE_DVR0 + i;
+
+		/*
+		 * Give the plugin pointer to the ion client so
+		 * that it can allocate memory from ION if it requires so
+		 */
+		mpq_demux->ion_client = mpq_dmx_info.ion_client;
+
+		spin_lock_init(&mpq_demux->feed_lock);
+
+		/*
+		 * mpq_demux_plugin_hw_init should be implemented
+		 * by the specific plugin
+		 */
+		result = dmx_init_func(mpq_adapter, mpq_demux);
+		if (result < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: dmx_init_func (errno=%d)\n",
+				__func__,
+				result);
+
+			goto init_failed_free_demux_devices;
+		}
+
+		mpq_demux->is_initialized = 1;
+
+		/*
+		 * Add capability of receiving input from memory.
+		 * Every demux in our system may be connected to memory input,
+		 * or any live input.
+		 */
+		mpq_demux->fe_memory.source = DMX_MEMORY_FE;
+		result =
+			mpq_demux->demux.dmx.add_frontend(
+					&mpq_demux->demux.dmx,
+					&mpq_demux->fe_memory);
+
+		if (result < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: add_frontend (mem) failed (errno=%d)\n",
+				__func__,
+				result);
+
+			goto init_failed_free_demux_devices;
+		}
+	}
+
+	return 0;
+
+init_failed_free_demux_devices:
+	mpq_dmx_plugin_exit();
+init_failed:
+	return result;
+}
+EXPORT_SYMBOL(mpq_dmx_plugin_init);
+
+
+void mpq_dmx_plugin_exit(void)
+{
+	int i;
+	struct mpq_demux *mpq_demux;
+
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	if (mpq_dmx_info.ion_client != NULL) {
+		ion_client_destroy(mpq_dmx_info.ion_client);
+		mpq_dmx_info.ion_client = NULL;
+	}
+
+	if (mpq_dmx_info.devices != NULL) {
+		for (i = 0; i < mpq_demux_device_num; i++) {
+			mpq_demux = mpq_dmx_info.devices+i;
+
+			if (mpq_demux->is_initialized) {
+				mpq_demux->demux.dmx.remove_frontend(
+							&mpq_demux->demux.dmx,
+							&mpq_demux->fe_memory);
+
+				dvb_dmxdev_release(&mpq_demux->dmxdev);
+				dvb_dmx_release(&mpq_demux->demux);
+			}
+		}
+
+		vfree(mpq_dmx_info.devices);
+		mpq_dmx_info.devices = NULL;
+	}
+}
+EXPORT_SYMBOL(mpq_dmx_plugin_exit);
+
+
+int mpq_dmx_set_source(
+		struct dmx_demux *demux,
+		const dmx_source_t *src)
+{
+	int i;
+	int dvr_index;
+	int dmx_index;
+	struct mpq_demux *mpq_demux = (struct mpq_demux *)demux->priv;
+
+	if ((mpq_dmx_info.devices == NULL) || (mpq_demux == NULL)) {
+		MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * For dvr sources,
+	 * verify that this source is connected to the respective demux
+	 */
+	dmx_index = mpq_demux - mpq_dmx_info.devices;
+
+	if (*src >= DMX_SOURCE_DVR0) {
+		dvr_index = *src - DMX_SOURCE_DVR0;
+
+		if (dvr_index != dmx_index) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: can't connect demux%d to dvr%d\n",
+				__func__,
+				dmx_index,
+				dvr_index);
+			return -EINVAL;
+		}
+	}
+
+	/*
+	 * For front-end sources,
+	 * verify that this source is not already set to different demux
+	 */
+	for (i = 0; i < mpq_demux_device_num; i++) {
+		if ((&mpq_dmx_info.devices[i] != mpq_demux) &&
+			(mpq_dmx_info.devices[i].source == *src)) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: demux%d source can't be set,\n"
+				"demux%d occupies this source already\n",
+				__func__,
+				dmx_index,
+				i);
+			return -EBUSY;
+		}
+	}
+
+	mpq_demux->source = *src;
+	return 0;
+}
+EXPORT_SYMBOL(mpq_dmx_set_source);
+
+
+int mpq_dmx_init_video_feed(struct dvb_demux_feed *feed)
+{
+	int ret;
+	void *packet_buffer;
+	void *payload_buffer;
+	struct mpq_video_feed_info *feed_data;
+	struct mpq_demux *mpq_demux =
+		(struct mpq_demux *)feed->demux->priv;
+	struct mpq_streambuffer *stream_buffer;
+	int actual_buffer_size;
+
+	/* Allocate memory for private feed data */
+	feed_data = vmalloc(sizeof(struct mpq_video_feed_info));
+
+	if (feed_data == NULL) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: FAILED to private video feed data\n",
+			__func__);
+
+		ret = -ENOMEM;
+		goto init_failed;
+	}
+
+	/* Allocate packet buffer holding the meta-data */
+	packet_buffer = vmalloc(VIDEO_META_DATA_BUFFER_SIZE);
+
+	if (packet_buffer == NULL) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: FAILED to allocate packets buffer\n",
+			__func__);
+
+		ret = -ENOMEM;
+		goto init_failed_free_priv_data;
+	}
+
+	/*
+	 * Allocate payload buffer through ION.
+	 * TODO: for scrambling support, need to check if the
+	 * stream is scrambled and allocate the buffer with secure
+	 * flag set.
+	 */
+
+	if (mpq_dmx_info.decoder_data_wrap)
+		actual_buffer_size =
+			feed->buffer_size;
+	else
+		actual_buffer_size =
+			feed->buffer_size + VIDEO_WRAP_AROUND_THRESHOLD;
+
+	actual_buffer_size += (SZ_4K - 1);
+	actual_buffer_size &= ~(SZ_4K - 1);
+
+	feed_data->payload_buff_handle =
+		ion_alloc(mpq_demux->ion_client,
+				  actual_buffer_size,
+				  SZ_4K,
+				  ION_HEAP(ION_CP_MM_HEAP_ID));
+
+	if (IS_ERR_OR_NULL(feed_data->payload_buff_handle)) {
+		ret = PTR_ERR(feed_data->payload_buff_handle);
+
+		MPQ_DVB_ERR_PRINT(
+			"%s: FAILED to allocate payload buffer %d\n",
+			__func__,
+			ret);
+
+		goto init_failed_free_packet_buffer;
+	}
+
+	payload_buffer =
+		ion_map_kernel(mpq_demux->ion_client,
+					   feed_data->payload_buff_handle,
+					   0);
+
+	if (IS_ERR_OR_NULL(payload_buffer)) {
+		ret = PTR_ERR(payload_buffer);
+
+		MPQ_DVB_ERR_PRINT(
+			"%s: FAILED to map payload buffer %d\n",
+			__func__,
+			ret);
+
+		goto init_failed_free_payload_buffer;
+	}
+
+	/* Register the new stream-buffer interface to MPQ adapter */
+	switch (feed->pes_type) {
+	case DMX_TS_PES_VIDEO0:
+		feed_data->stream_interface =
+			MPQ_ADAPTER_VIDEO0_STREAM_IF;
+		break;
+
+	case DMX_TS_PES_VIDEO1:
+		feed_data->stream_interface =
+			MPQ_ADAPTER_VIDEO1_STREAM_IF;
+		break;
+
+	case DMX_TS_PES_VIDEO2:
+		feed_data->stream_interface =
+			MPQ_ADAPTER_VIDEO2_STREAM_IF;
+		break;
+
+	case DMX_TS_PES_VIDEO3:
+		feed_data->stream_interface =
+			MPQ_ADAPTER_VIDEO3_STREAM_IF;
+		break;
+
+	default:
+		MPQ_DVB_ERR_PRINT(
+			"%s: Invalid pes type %d\n",
+			__func__,
+			feed->pes_type);
+		ret = -EINVAL;
+		goto init_failed_unmap_payload_buffer;
+	}
+
+	/* make sure not occupied already */
+	stream_buffer = NULL;
+	mpq_adapter_get_stream_if(
+			feed_data->stream_interface,
+			&stream_buffer);
+	if (stream_buffer != NULL) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: Video interface %d already occupied!\n",
+			__func__,
+			feed_data->stream_interface);
+		ret = -EBUSY;
+		goto init_failed_unmap_payload_buffer;
+	}
+
+	feed_data->video_buffer =
+		&mpq_dmx_info.decoder_buffers[feed_data->stream_interface];
+
+	mpq_streambuffer_init(
+			feed_data->video_buffer,
+			payload_buffer,
+			actual_buffer_size,
+			packet_buffer,
+			VIDEO_META_DATA_BUFFER_SIZE);
+
+	ret =
+		mpq_adapter_register_stream_if(
+			feed_data->stream_interface,
+			feed_data->video_buffer);
+
+	if (ret < 0) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_adapter_register_stream_if failed, "
+			"err = %d\n",
+			__func__,
+			ret);
+		goto init_failed_unmap_payload_buffer;
+	}
+
+	feed->buffer_size = actual_buffer_size;
+	feed_data->pes_payload_address =
+		(u32)feed_data->video_buffer->raw_data.data;
+
+	feed_data->pes_header_left_bytes = PES_MANDATORY_FIELDS_LEN;
+	feed_data->pes_header_offset = 0;
+	feed->pusi_seen = 0;
+	feed->peslen = 0;
+	feed_data->fullness_wait_cancel = 0;
+
+	spin_lock(&mpq_demux->feed_lock);
+	feed->priv = (void *)feed_data;
+	spin_unlock(&mpq_demux->feed_lock);
+
+	return 0;
+
+init_failed_unmap_payload_buffer:
+	ion_unmap_kernel(mpq_demux->ion_client,
+					 feed_data->payload_buff_handle);
+init_failed_free_payload_buffer:
+	ion_free(mpq_demux->ion_client,
+			feed_data->payload_buff_handle);
+init_failed_free_packet_buffer:
+	vfree(packet_buffer);
+init_failed_free_priv_data:
+	vfree(feed_data);
+	feed->priv = NULL;
+init_failed:
+
+	return ret;
+}
+EXPORT_SYMBOL(mpq_dmx_init_video_feed);
+
+
+int mpq_dmx_terminate_video_feed(struct dvb_demux_feed *feed)
+{
+	struct mpq_video_feed_info *feed_data;
+	struct mpq_demux *mpq_demux;
+
+	if (feed->priv == NULL) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid feed, feed->priv is NULL\n",
+			__func__);
+
+		return -EINVAL;
+	}
+
+	mpq_demux =
+		(struct mpq_demux *)feed->demux->priv;
+
+	feed_data =
+		(struct mpq_video_feed_info *)feed->priv;
+
+	spin_lock(&mpq_demux->feed_lock);
+	feed->priv = NULL;
+	spin_unlock(&mpq_demux->feed_lock);
+
+	wake_up_all(&feed_data->video_buffer->raw_data.queue);
+
+	mpq_adapter_unregister_stream_if(
+		feed_data->stream_interface);
+
+	vfree(feed_data->video_buffer->packet_data.data);
+
+	ion_unmap_kernel(mpq_demux->ion_client,
+					 feed_data->payload_buff_handle);
+
+	ion_free(mpq_demux->ion_client,
+			 feed_data->payload_buff_handle);
+
+	vfree(feed_data);
+
+	return 0;
+}
+EXPORT_SYMBOL(mpq_dmx_terminate_video_feed);
+
+int mpq_dmx_decoder_fullness_init(struct dvb_demux_feed *feed)
+{
+	struct mpq_demux *mpq_demux;
+
+	mpq_demux =
+		(struct mpq_demux *)feed->demux->priv;
+
+	if (mpq_dmx_is_video_feed(feed)) {
+		struct mpq_video_feed_info *feed_data;
+
+		spin_lock(&mpq_demux->feed_lock);
+
+		if (feed->priv == NULL) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: invalid feed, feed->priv is NULL\n",
+				__func__);
+			spin_unlock(&mpq_demux->feed_lock);
+			return -EINVAL;
+		}
+
+		feed_data =
+			(struct mpq_video_feed_info *)feed->priv;
+
+		feed_data->fullness_wait_cancel = 0;
+
+		spin_unlock(&mpq_demux->feed_lock);
+
+		return 0;
+	}
+
+	/* else */
+	MPQ_DVB_DBG_PRINT(
+		"%s: Invalid feed type %d\n",
+		__func__,
+		feed->pes_type);
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(mpq_dmx_decoder_fullness_init);
+
+int mpq_dmx_decoder_fullness_wait(
+		struct dvb_demux_feed *feed,
+		size_t required_space)
+{
+	struct mpq_demux *mpq_demux;
+
+	mpq_demux =
+		(struct mpq_demux *)feed->demux->priv;
+
+	if (mpq_dmx_is_video_feed(feed)) {
+		int ret;
+		int gap;
+		struct mpq_video_feed_info *feed_data;
+		struct dvb_ringbuffer *video_buff;
+
+		spin_lock(&mpq_demux->feed_lock);
+
+		if (feed->priv == NULL) {
+			spin_unlock(&mpq_demux->feed_lock);
+			return -EINVAL;
+		}
+
+		feed_data =
+			(struct mpq_video_feed_info *)feed->priv;
+
+		video_buff =
+			&feed_data->video_buffer->raw_data;
+
+		/*
+		 * If we are now starting new PES and the
+		 * PES payload may wrap-around, extra padding
+		 * needs to be pushed into the buffer.
+		 */
+		gap = video_buff->size - video_buff->pwrite;
+		if ((!mpq_dmx_info.decoder_data_wrap) &&
+			(gap < VIDEO_WRAP_AROUND_THRESHOLD))
+			required_space += gap;
+
+		ret = 0;
+		if ((feed_data != NULL) &&
+			(!feed_data->fullness_wait_cancel) &&
+			(dvb_ringbuffer_free(video_buff) < required_space)) {
+			DEFINE_WAIT(__wait);
+			for (;;) {
+				prepare_to_wait(
+					&video_buff->queue,
+					&__wait,
+					TASK_INTERRUPTIBLE);
+
+				if ((feed->priv == NULL) ||
+					(feed_data->fullness_wait_cancel) ||
+					(dvb_ringbuffer_free(video_buff) >=
+					required_space))
+					break;
+
+				if (!signal_pending(current)) {
+					spin_unlock(&mpq_demux->feed_lock);
+					schedule();
+					spin_lock(&mpq_demux->feed_lock);
+					continue;
+				}
+				ret = -ERESTARTSYS;
+				break;
+			}
+			finish_wait(&video_buff->queue, &__wait);
+		}
+
+		if (ret < 0) {
+			spin_unlock(&mpq_demux->feed_lock);
+			return ret;
+		}
+
+		if ((feed->priv == NULL) ||
+			(feed_data->fullness_wait_cancel)) {
+			spin_unlock(&mpq_demux->feed_lock);
+			return -EINVAL;
+		}
+
+		spin_unlock(&mpq_demux->feed_lock);
+		return 0;
+	}
+
+	/* else */
+	MPQ_DVB_DBG_PRINT(
+		"%s: Invalid feed type %d\n",
+		__func__,
+		feed->pes_type);
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(mpq_dmx_decoder_fullness_wait);
+
+int mpq_dmx_decoder_fullness_abort(struct dvb_demux_feed *feed)
+{
+	struct mpq_demux *mpq_demux;
+
+	mpq_demux =
+		(struct mpq_demux *)feed->demux->priv;
+
+	if (mpq_dmx_is_video_feed(feed)) {
+		struct mpq_video_feed_info *feed_data;
+		struct dvb_ringbuffer *video_buff;
+
+		spin_lock(&mpq_demux->feed_lock);
+
+		if (feed->priv == NULL) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: invalid feed, feed->priv is NULL\n",
+				__func__);
+			spin_unlock(&mpq_demux->feed_lock);
+			return -EINVAL;
+		}
+
+		feed_data =
+			(struct mpq_video_feed_info *)feed->priv;
+
+		video_buff =
+			&feed_data->video_buffer->raw_data;
+
+		feed_data->fullness_wait_cancel = 1;
+		spin_unlock(&mpq_demux->feed_lock);
+
+		wake_up_all(&video_buff->queue);
+
+		return 0;
+	}
+
+	/* else */
+	MPQ_DVB_ERR_PRINT(
+		"%s: Invalid feed type %d\n",
+		__func__,
+		feed->pes_type);
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(mpq_dmx_decoder_fullness_abort);
+
+int mpq_dmx_process_video_packet(
+			struct dvb_demux_feed *feed,
+			const u8 *buf)
+{
+	int bytes_avail;
+	int left_size;
+	int copy_len;
+	u32 ts_payload_offset;
+	struct mpq_video_feed_info *feed_data;
+	const struct ts_packet_header *ts_header;
+	struct mpq_streambuffer *stream_buffer;
+	struct pes_packet_header *pes_header;
+	struct mpq_demux *mpq_demux;
+
+	mpq_demux =
+		(struct mpq_demux *)feed->demux->priv;
+
+	spin_lock(&mpq_demux->feed_lock);
+
+	feed_data =
+		(struct mpq_video_feed_info *)feed->priv;
+
+	if (unlikely(feed_data == NULL)) {
+		spin_unlock(&mpq_demux->feed_lock);
+		return 0;
+	}
+
+	ts_header = (const struct ts_packet_header *)buf;
+
+	stream_buffer =
+			feed_data->video_buffer;
+
+	pes_header =
+			&feed_data->pes_header;
+
+/*	printk("TS packet: %X %X %X %X %X%X %X %X %X\n",
+		ts_header->sync_byte,
+		ts_header->transport_error_indicator,
+		ts_header->payload_unit_start_indicator,
+		ts_header->transport_priority,
+		ts_header->pid_msb,
+		ts_header->pid_lsb,
+		ts_header->transport_scrambling_control,
+		ts_header->adaptation_field_control,
+		ts_header->continuity_counter);*/
+
+	/* Make sure this TS packet has a payload and not scrambled */
+	if ((ts_header->sync_byte != 0x47) ||
+		(ts_header->adaptation_field_control == 0) ||
+		(ts_header->adaptation_field_control == 2) ||
+		(ts_header->transport_scrambling_control)) {
+		/* continue to next packet */
+		spin_unlock(&mpq_demux->feed_lock);
+		return 0;
+	}
+
+	if (ts_header->payload_unit_start_indicator) { /* PUSI? */
+		if (feed->pusi_seen) { /* Did we see PUSI before? */
+			struct mpq_streambuffer_packet_header packet;
+			struct mpq_adapter_video_meta_data meta_data;
+
+			/*
+			 * Close previous PES.
+			 * Push new packet to the meta-data buffer.
+			 * Double check that we are not in middle of
+			 * previous PES header parsing.
+			 */
+
+			if (0 == feed_data->pes_header_left_bytes) {
+				packet.raw_data_addr =
+					feed_data->pes_payload_address;
+
+				packet.raw_data_len = feed->peslen;
+
+				if ((!mpq_dmx_info.decoder_data_wrap) &&
+					((feed_data->pes_payload_address +
+					feed->peslen) >
+					((u32)stream_buffer->raw_data.data +
+					stream_buffer->raw_data.size)))
+					MPQ_DVB_ERR_PRINT(
+						"%s: "
+						"Video data has wrapped-around!\n",
+						__func__);
+
+				packet.user_data_len =
+					sizeof(struct
+						mpq_adapter_video_meta_data);
+
+				if ((pes_header->pts_dts_flag == 2) ||
+					(pes_header->pts_dts_flag == 3))
+					meta_data.pts_exist = 1;
+				else
+					meta_data.pts_exist = 0;
+
+				meta_data.pts =
+					((u64)pes_header->pts_1 << 30) |
+					((u64)pes_header->pts_2 << 22) |
+					((u64)pes_header->pts_3 << 15) |
+					((u64)pes_header->pts_4 << 7) |
+					(u64)pes_header->pts_5;
+
+				if (pes_header->pts_dts_flag == 3)
+					meta_data.dts_exist = 1;
+				else
+					meta_data.dts_exist = 0;
+
+				meta_data.dts =
+					((u64)pes_header->dts_1 << 30) |
+					((u64)pes_header->dts_2 << 22) |
+					((u64)pes_header->dts_3 << 15) |
+					((u64)pes_header->dts_4 << 7) |
+					(u64)pes_header->dts_5;
+
+				meta_data.is_padding = 0;
+
+				if (mpq_streambuffer_pkt_write(
+						stream_buffer,
+						&packet,
+						(u8 *)&meta_data) < 0)
+					MPQ_DVB_ERR_PRINT(
+						"%s: "
+						"Couldn't write packet. "
+						"Should never happen\n",
+						__func__);
+			} else {
+				MPQ_DVB_ERR_PRINT(
+					"%s: received PUSI"
+					"while handling PES header"
+					"of previous PES\n",
+					__func__);
+			}
+
+			/* Reset PES info */
+			feed_data->pes_payload_address =
+				(u32)stream_buffer->raw_data.data +
+				stream_buffer->raw_data.pwrite;
+
+			feed->peslen = 0;
+			feed_data->pes_header_offset = 0;
+			feed_data->pes_header_left_bytes =
+				PES_MANDATORY_FIELDS_LEN;
+		} else {
+			feed->pusi_seen = 1;
+		}
+	}
+
+	/*
+	 * Parse PES data only if PUSI was encountered,
+	 * otherwise the data is dropped
+	 */
+	if (!feed->pusi_seen) {
+		spin_unlock(&mpq_demux->feed_lock);
+		return 0; /* drop and wait for next packets */
+	}
+
+	ts_payload_offset = sizeof(struct ts_packet_header);
+
+	/* Skip adaptation field if exists */
+	if (ts_header->adaptation_field_control == 3)
+		ts_payload_offset += buf[ts_payload_offset] + 1;
+
+	bytes_avail = 188 - ts_payload_offset;
+
+	/* Got the mandatory fields of the video PES header? */
+	if (feed_data->pes_header_offset < PES_MANDATORY_FIELDS_LEN) {
+		left_size =
+			PES_MANDATORY_FIELDS_LEN -
+			feed_data->pes_header_offset;
+
+		copy_len = (left_size > bytes_avail) ?
+					bytes_avail :
+					left_size;
+
+		memcpy((u8 *)pes_header+feed_data->pes_header_offset,
+				buf+ts_payload_offset,
+				copy_len);
+
+		feed_data->pes_header_offset += copy_len;
+
+		if (left_size > bytes_avail) {
+			spin_unlock(&mpq_demux->feed_lock);
+			return 0;
+		}
+
+		/* else - we have beginning of PES header */
+		bytes_avail -= left_size;
+		ts_payload_offset += left_size;
+
+		/* Make sure the PES packet is valid */
+		if (mpq_dmx_is_valid_video_pes(pes_header) < 0) {
+			/*
+			 * Since the new PES header parsing
+			 * failed, reset pusi_seen to drop all
+			 * data until next PUSI
+			 */
+			feed->pusi_seen = 0;
+			feed_data->pes_header_offset = 0;
+
+			MPQ_DVB_ERR_PRINT(
+				"%s: invalid packet\n",
+				__func__);
+
+			spin_unlock(&mpq_demux->feed_lock);
+			return 0;
+		}
+
+		feed_data->pes_header_left_bytes =
+			pes_header->pes_header_data_length;
+	}
+
+	/* Remainning header bytes that need to be processed? */
+	if (feed_data->pes_header_left_bytes) {
+		/* Did we capture the PTS value (if exist)? */
+		if ((bytes_avail != 0) &&
+			(feed_data->pes_header_offset <
+			 (PES_MANDATORY_FIELDS_LEN+5)) &&
+			((pes_header->pts_dts_flag == 2) ||
+			 (pes_header->pts_dts_flag == 3))) {
+
+			/* 5 more bytes should be there */
+			left_size =
+				PES_MANDATORY_FIELDS_LEN +
+				5 -
+				feed_data->pes_header_offset;
+
+			copy_len = (left_size > bytes_avail) ?
+						bytes_avail :
+						left_size;
+
+			memcpy((u8 *)pes_header+
+				feed_data->pes_header_offset,
+				buf+ts_payload_offset,
+				copy_len);
+
+			feed_data->pes_header_offset += copy_len;
+			feed_data->pes_header_left_bytes -= copy_len;
+
+			if (left_size > bytes_avail) {
+				spin_unlock(&mpq_demux->feed_lock);
+				return 0;
+			}
+
+			/* else - we have the PTS */
+			bytes_avail -= copy_len;
+			ts_payload_offset += copy_len;
+		}
+
+		/* Did we capture the DTS value (if exist)? */
+		if ((bytes_avail != 0) &&
+			(feed_data->pes_header_offset <
+			 (PES_MANDATORY_FIELDS_LEN+10)) &&
+			(pes_header->pts_dts_flag == 3)) {
+
+			/* 5 more bytes should be there */
+			left_size =
+				PES_MANDATORY_FIELDS_LEN +
+				10 -
+				feed_data->pes_header_offset;
+
+			copy_len = (left_size > bytes_avail) ?
+						bytes_avail :
+						left_size;
+
+			memcpy((u8 *)pes_header+
+				feed_data->pes_header_offset,
+				buf+ts_payload_offset,
+				copy_len);
+
+			feed_data->pes_header_offset += copy_len;
+			feed_data->pes_header_left_bytes -= copy_len;
+
+			if (left_size > bytes_avail) {
+				spin_unlock(&mpq_demux->feed_lock);
+				return 0;
+			}
+
+			/* else - we have the DTS */
+			bytes_avail -= copy_len;
+			ts_payload_offset += copy_len;
+		}
+
+		/* Any more header bytes?! */
+		if (feed_data->pes_header_left_bytes >= bytes_avail) {
+			feed_data->pes_header_left_bytes -= bytes_avail;
+			spin_unlock(&mpq_demux->feed_lock);
+			return 0;
+		}
+
+		/* Got PES header, process payload */
+		bytes_avail -= feed_data->pes_header_left_bytes;
+		ts_payload_offset += feed_data->pes_header_left_bytes;
+		feed_data->pes_header_left_bytes = 0;
+	}
+
+	/*
+	 * If we reached here,
+	 * then we are now at the PES payload data
+	 */
+	if (bytes_avail == 0) {
+		spin_unlock(&mpq_demux->feed_lock);
+		return 0;
+	}
+
+	if (feed->peslen == 0) { /* starting new PES */
+		/* gap till end of the buffer */
+		int gap =
+			stream_buffer->raw_data.size -
+			stream_buffer->raw_data.pwrite;
+
+		if ((!mpq_dmx_info.decoder_data_wrap) &&
+			(gap < VIDEO_WRAP_AROUND_THRESHOLD)) {
+			struct mpq_streambuffer_packet_header packet;
+			struct mpq_adapter_video_meta_data meta_data;
+
+			/*
+			 * Do not start writting new PES from
+			 * this location to prevent possible
+			 * wrap-around of the payload, fill padding instead.
+			 */
+
+			/* push a packet with padding indication */
+			meta_data.is_padding = 1;
+
+			packet.raw_data_len = gap;
+			packet.user_data_len =
+				sizeof(struct mpq_adapter_video_meta_data);
+			packet.raw_data_addr =
+				feed_data->pes_payload_address;
+
+			if (mpq_streambuffer_data_write_deposit(
+						stream_buffer,
+						gap) < 0) {
+				MPQ_DVB_ERR_PRINT(
+					"%s: mpq_streambuffer_data_write_deposit "
+					"failed!\n",
+					__func__);
+			} else if (mpq_streambuffer_pkt_write(
+							stream_buffer,
+							&packet,
+							(u8 *)&meta_data) < 0) {
+				MPQ_DVB_ERR_PRINT(
+					"%s: "
+					"Couldn't write packet. "
+					"Should never happen\n",
+					__func__);
+			} else {
+				feed_data->pes_payload_address =
+					(u32)stream_buffer->raw_data.data +
+					stream_buffer->raw_data.pwrite;
+			}
+		}
+	}
+
+	if (mpq_streambuffer_data_write(
+				stream_buffer,
+				buf+ts_payload_offset,
+				bytes_avail) < 0)
+		mpq_demux->decoder_tsp_drop_count++;
+	else
+		feed->peslen += bytes_avail;
+
+	spin_unlock(&mpq_demux->feed_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(mpq_dmx_process_video_packet);
+
+
+int mpq_dmx_process_pcr_packet(
+			struct dvb_demux_feed *feed,
+			const u8 *buf)
+{
+	int i;
+	u64 pcr;
+	u64 stc;
+	u8 output[PCR_STC_LEN];
+	struct mpq_demux *mpq_demux =
+		(struct mpq_demux *)feed->demux->priv;
+	const struct ts_packet_header *ts_header;
+	const struct ts_adaptation_field *adaptation_field;
+
+	/*
+	 * When we play from front-end, we configure HW
+	 * to output the extra timestamp, if we are playing
+	 * from DVR, make sure the format is 192 packet.
+	 */
+	if ((mpq_demux->source >= DMX_SOURCE_DVR0) &&
+		(mpq_demux->demux.tsp_format != DMX_TSP_FORMAT_192_TAIL)) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid packet format %d for PCR extraction\n",
+			__func__,
+			mpq_demux->demux.tsp_format);
+
+		 return -EINVAL;
+	}
+
+	ts_header = (const struct ts_packet_header *)buf;
+
+	/* Make sure this TS packet has a adaptation field */
+	if ((ts_header->sync_byte != 0x47) ||
+		(ts_header->adaptation_field_control == 0) ||
+		(ts_header->adaptation_field_control == 1)) {
+		return 0;
+	}
+
+	adaptation_field = (const struct ts_adaptation_field *)
+			(buf + sizeof(struct ts_packet_header));
+
+	if ((!adaptation_field->adaptation_field_length) ||
+		(!adaptation_field->PCR_flag))
+		return 0; /* 0 adaptation field or no PCR */
+
+	pcr = ((u64)adaptation_field->program_clock_reference_base_1) << 25;
+	pcr += ((u64)adaptation_field->program_clock_reference_base_2) << 17;
+	pcr += ((u64)adaptation_field->program_clock_reference_base_3) << 9;
+	pcr += ((u64)adaptation_field->program_clock_reference_base_4) << 1;
+	pcr += adaptation_field->program_clock_reference_base_5;
+	pcr *= 300;
+	pcr +=
+		(((u64)adaptation_field->program_clock_reference_ext_1) << 8) +
+		adaptation_field->program_clock_reference_ext_2;
+
+	stc = buf[189] << 16;
+	stc += buf[190] << 8;
+	stc += buf[191];
+	stc *= 256; /* convert from 105.47 KHZ to 27MHz */
+
+	output[0] = adaptation_field->discontinuity_indicator;
+
+	for (i = 1; i <= 8; i++)
+		output[i] = (stc >> ((8-i) << 3)) & 0xFF;
+
+	for (i = 9; i <= 16; i++)
+		output[i] = (pcr >> ((16-i) << 3)) & 0xFF;
+
+	feed->cb.ts(output, PCR_STC_LEN,
+				NULL, 0,
+				&feed->feed.ts, DMX_OK);
+	return 0;
+}
+EXPORT_SYMBOL(mpq_dmx_process_pcr_packet);
+
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
new file mode 100644
index 0000000..d90bd89
--- /dev/null
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
@@ -0,0 +1,494 @@
+/* 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.
+ */
+
+#ifndef _MPQ_DMX_PLUGIN_COMMON_H
+#define _MPQ_DMX_PLUGIN_COMMON_H
+
+#include <linux/ion.h>
+
+#include "dvbdev.h"
+#include "dmxdev.h"
+#include "demux.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "mpq_adapter.h"
+
+
+/**
+ * Total number of filters per demux,
+ * including section and PES feeds
+ */
+#define MPQ_DMX_MAX_NUM_OF_FILTERS			64
+
+/**
+ * TSIF alias name length
+ */
+#define TSIF_NAME_LENGTH					10
+
+/**
+ * struct mpq_demux - mpq demux information
+ * @demux: The dvb_demux instance used by mpq_demux
+ * @dmxdev: The dmxdev instance used by mpq_demux
+ * @fe_memory: Handle of front-end memory source to mpq_demux
+ * @source: The current source connected to the demux
+ * @is_initialized: Indicates whether this demux device was
+ *                  initialized or not.
+ * @ion_client: ION demux client used to allocate memory from ION.
+ * @feed_lock: Lock used to protect against private feed data
+ * @hw_notification_rate: Notification rate in msec, exposed in debugfs.
+ * @hw_notification_count: Notification count, exposed in debugfs.
+ * @hw_notification_size: Notification size in bytes, exposed in debugfs.
+ * @decoder_tsp_drop_count: Counter of number of dropped TS packets
+ * due to decoder buffer fullness, exposed in debugfs.
+ * @last_notification_time: Time of last HW notification.
+ */
+struct mpq_demux {
+	struct dvb_demux demux;
+	struct dmxdev dmxdev;
+	struct dmx_frontend fe_memory;
+	dmx_source_t source;
+	int is_initialized;
+	struct ion_client *ion_client;
+	spinlock_t feed_lock;
+
+	/* debug-fs */
+	u32 hw_notification_rate;
+	u32 hw_notification_count;
+	u32 hw_notification_size;
+	u32 decoder_tsp_drop_count;
+	struct timespec last_notification_time;
+};
+
+/**
+ * mpq_dmx_init - initialization and registration function of
+ * single MPQ demux device
+ *
+ * @adapter: The adapter to register mpq_demux to
+ * @mpq_demux: The mpq demux to initialize
+ *
+ * Every HW pluging need to provide implementation of such
+ * function that will be called for each demux device on the
+ * module initialization. The function mpq_demux_plugin_init
+ * should be called during the HW plugin module initialization.
+ */
+typedef int (*mpq_dmx_init)(
+				struct dvb_adapter *mpq_adapter,
+				struct mpq_demux *demux);
+
+/**
+ * struct ts_packet_header - Transport packet header
+ * as defined in MPEG2 transport stream standard.
+ */
+struct ts_packet_header {
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned sync_byte:8;
+	unsigned transport_error_indicator:1;
+	unsigned payload_unit_start_indicator:1;
+	unsigned transport_priority:1;
+	unsigned pid_msb:5;
+	unsigned pid_lsb:8;
+	unsigned transport_scrambling_control:2;
+	unsigned adaptation_field_control:2;
+	unsigned continuity_counter:4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned sync_byte:8;
+	unsigned pid_msb:5;
+	unsigned transport_priority:1;
+	unsigned payload_unit_start_indicator:1;
+	unsigned transport_error_indicator:1;
+	unsigned pid_lsb:8;
+	unsigned continuity_counter:4;
+	unsigned adaptation_field_control:2;
+	unsigned transport_scrambling_control:2;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+} __packed;
+
+/**
+ * struct ts_adaptation_field - Adaptation field prefix
+ * as defined in MPEG2 transport stream standard.
+ */
+struct ts_adaptation_field {
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned adaptation_field_length:8;
+	unsigned discontinuity_indicator:1;
+	unsigned random_access_indicator:1;
+	unsigned elementary_stream_priority_indicator:1;
+	unsigned PCR_flag:1;
+	unsigned OPCR_flag:1;
+	unsigned splicing_point_flag:1;
+	unsigned transport_private_data_flag:1;
+	unsigned adaptation_field_extension_flag:1;
+	unsigned program_clock_reference_base_1:8;
+	unsigned program_clock_reference_base_2:8;
+	unsigned program_clock_reference_base_3:8;
+	unsigned program_clock_reference_base_4:8;
+	unsigned program_clock_reference_base_5:1;
+	unsigned reserved:6;
+	unsigned program_clock_reference_ext_1:1;
+	unsigned program_clock_reference_ext_2:8;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned adaptation_field_length:8;
+	unsigned adaptation_field_extension_flag:1;
+	unsigned transport_private_data_flag:1;
+	unsigned splicing_point_flag:1;
+	unsigned OPCR_flag:1;
+	unsigned PCR_flag:1;
+	unsigned elementary_stream_priority_indicator:1;
+	unsigned random_access_indicator:1;
+	unsigned discontinuity_indicator:1;
+	unsigned program_clock_reference_base_1:8;
+	unsigned program_clock_reference_base_2:8;
+	unsigned program_clock_reference_base_3:8;
+	unsigned program_clock_reference_base_4:8;
+	unsigned program_clock_reference_ext_1:1;
+	unsigned reserved:6;
+	unsigned program_clock_reference_base_5:1;
+	unsigned program_clock_reference_ext_2:8;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+} __packed;
+
+
+/*
+ * PES packet header containing dts and/or pts values
+ * as defined in MPEG2 transport stream standard.
+ */
+struct pes_packet_header {
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unsigned packet_start_code_prefix_1:8;
+	unsigned packet_start_code_prefix_2:8;
+	unsigned packet_start_code_prefix_3:8;
+	unsigned stream_id:8;
+	unsigned pes_packet_length_msb:8;
+	unsigned pes_packet_length_lsb:8;
+	unsigned reserved_bits0:2;
+	unsigned pes_scrambling_control:2;
+	unsigned pes_priority:1;
+	unsigned data_alignment_indicator:1;
+	unsigned copyright:1;
+	unsigned original_or_copy:1;
+	unsigned pts_dts_flag:2;
+	unsigned escr_flag:1;
+	unsigned es_rate_flag:1;
+	unsigned dsm_trick_mode_flag:1;
+	unsigned additional_copy_info_flag:1;
+	unsigned pes_crc_flag:1;
+	unsigned pes_extension_flag:1;
+	unsigned pes_header_data_length:8;
+	unsigned reserved_bits1:4;
+	unsigned pts_1:3;
+	unsigned marker_bit0:1;
+	unsigned pts_2:8;
+	unsigned pts_3:7;
+	unsigned marker_bit1:1;
+	unsigned pts_4:8;
+	unsigned pts_5:7;
+	unsigned marker_bit2:1;
+	unsigned reserved_bits2:4;
+	unsigned dts_1:3;
+	unsigned marker_bit3:1;
+	unsigned dts_2:8;
+	unsigned dts_3:7;
+	unsigned marker_bit4:1;
+	unsigned dts_4:8;
+	unsigned dts_5:7;
+	unsigned marker_bit5:1;
+	unsigned reserved_bits3:4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned packet_start_code_prefix_1:8;
+	unsigned packet_start_code_prefix_2:8;
+	unsigned packet_start_code_prefix_3:8;
+	unsigned stream_id:8;
+	unsigned pes_packet_length_lsb:8;
+	unsigned pes_packet_length_msb:8;
+	unsigned original_or_copy:1;
+	unsigned copyright:1;
+	unsigned data_alignment_indicator:1;
+	unsigned pes_priority:1;
+	unsigned pes_scrambling_control:2;
+	unsigned reserved_bits0:2;
+	unsigned pes_extension_flag:1;
+	unsigned pes_crc_flag:1;
+	unsigned additional_copy_info_flag:1;
+	unsigned dsm_trick_mode_flag:1;
+	unsigned es_rate_flag:1;
+	unsigned escr_flag:1;
+	unsigned pts_dts_flag:2;
+	unsigned pes_header_data_length:8;
+	unsigned marker_bit0:1;
+	unsigned pts_1:3;
+	unsigned reserved_bits1:4;
+	unsigned pts_2:8;
+	unsigned marker_bit1:1;
+	unsigned pts_3:7;
+	unsigned pts_4:8;
+	unsigned marker_bit2:1;
+	unsigned pts_5:7;
+	unsigned marker_bit3:1;
+	unsigned dts_1:3;
+	unsigned reserved_bits2:4;
+	unsigned dts_2:8;
+	unsigned marker_bit4:1;
+	unsigned dts_3:7;
+	unsigned dts_4:8;
+	unsigned marker_bit5:1;
+	unsigned dts_5:7;
+	unsigned reserved_bits3:4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+} __packed;
+
+/*
+ * mpq_video_feed_info - private data used for video feed.
+ *
+ * @plugin_data: Underlying plugin's own private data.
+ * @video_buffer: Holds the streamer buffer shared with
+ * the decoder for feeds having the data going to the decoder.
+ * @pes_header: Used for feeds that output data to decoder,
+ * holds PES header of current processed PES.
+ * @pes_header_left_bytes: Used for feeds that output data to decoder,
+ * holds remainning PES header bytes of current processed PES.
+ * @pes_header_offset: Holds the offset within the current processed
+ * pes header.
+ * @fullness_wait_cancel: Flag used to signal to abort waiting for
+ * decoder's fullness.
+ * @pes_payload_address: Used for feeds that output data to decoder,
+ * holds current PES payload start address.
+ * @payload_buff_handle: ION handle for the allocated payload buffer
+ * @stream_interface: The ID of the video stream interface registered
+ * with this stream buffer.
+ */
+struct mpq_video_feed_info {
+	void *plugin_data;
+	struct mpq_streambuffer *video_buffer;
+	struct pes_packet_header pes_header;
+	u32 pes_header_left_bytes;
+	u32 pes_header_offset;
+	u32 pes_payload_address;
+	int fullness_wait_cancel;
+	struct ion_handle *payload_buff_handle;
+	enum mpq_adapter_stream_if stream_interface;
+};
+
+/**
+ * mpq_demux_plugin_init - Initialize demux devices and register
+ * them to the dvb adapter.
+ *
+ * @dmx_init_func: Pointer to the function to be used
+ *  to initialize demux of the udnerlying HW plugin.
+ *
+ * Return     error code
+ *
+ * Should be called at the HW plugin module initialization.
+ */
+int mpq_dmx_plugin_init(mpq_dmx_init dmx_init_func);
+
+/**
+ * mpq_demux_plugin_exit - terminate demux devices.
+ *
+ * Should be called at the HW plugin module termination.
+ */
+void mpq_dmx_plugin_exit(void);
+
+/**
+ * mpq_dmx_set_source - implmenetation of set_source routine.
+ *
+ * @demux: The demux device to set its source.
+ * @src: The source to be set.
+ *
+ * Return     error code
+ *
+ * Can be used by the underlying plugins to implement kernel
+ * demux API set_source routine.
+ */
+int mpq_dmx_set_source(struct dmx_demux *demux, const dmx_source_t *src);
+
+/**
+ * mpq_dmx_init_video_feed - Initializes video feed
+ * used to pass data to decoder directly.
+ *
+ * @feed: The feed used for the video TS packets
+ *
+ * Return     error code.
+ *
+ * If the underlying plugin wishes to perform SW PES assmebly
+ * for the video data and stream it to the decoder, it should
+ * call this function when video feed is initialized before
+ * using mpq_dmx_process_video_packet.
+ *
+ * The function allocates mpq_video_feed_info and saves in
+ * feed->priv.
+ */
+int mpq_dmx_init_video_feed(struct dvb_demux_feed *feed);
+
+/**
+ * mpq_dmx_terminate_video_feed - Free private data of
+ * video feed allocated in mpq_dmx_init_video_feed
+ *
+ * @feed: The feed used for the video TS packets
+ *
+ * Return     error code.
+ */
+int mpq_dmx_terminate_video_feed(struct dvb_demux_feed *feed);
+
+/**
+ * mpq_dmx_decoder_fullness_init - Initialize waiting
+ * mechanism on decoder's buffer fullness.
+ *
+ * @feed: The decoder's feed
+ *
+ * Return     error code.
+ */
+int mpq_dmx_decoder_fullness_init(
+		struct dvb_demux_feed *feed);
+
+/**
+ * mpq_dmx_decoder_fullness_wait - Checks whether decoder buffer
+ * have free space as required, if not, wait for it.
+ *
+ * @feed: The decoder's feed
+ * @required_space: the required free space to wait for
+ *
+ * Return     error code.
+ */
+int mpq_dmx_decoder_fullness_wait(
+		struct dvb_demux_feed *feed,
+		size_t required_space);
+
+/**
+ * mpq_dmx_decoder_fullness_abort - Aborts waiting
+ * on decoder's buffer fullness if any waiting is done
+ * now. After calling this, to wait again the user must
+ * call mpq_dmx_decoder_fullness_init.
+ *
+ * @feed: The decoder's feed
+ *
+ * Return     error code.
+ */
+int mpq_dmx_decoder_fullness_abort(
+		struct dvb_demux_feed *feed);
+
+/**
+ * mpq_dmx_process_video_packet - Assemble PES data and output it
+ * to the stream-buffer connected to the decoder.
+ *
+ * @feed: The feed used for the video TS packets
+ * @buf: The buffer holding video TS packet.
+ *
+ * Return     error code.
+ *
+ * The function assumes it receives buffer with single TS packet
+ * of the relevant PID.
+ * If the output buffer is full while assembly, the function drops
+ * the packet and does not write them to the output buffer.
+ * Scrambled packets are bypassed.
+ */
+int mpq_dmx_process_video_packet(
+		struct dvb_demux_feed *feed,
+		const u8 *buf);
+
+/**
+ * mpq_dmx_process_pcr_packet - Extract PCR/STC pairs from
+ * a 192 bytes packet.
+ *
+ * @feed: The feed used for the PCR TS packets
+ * @buf: The buffer holding pcr/stc packet.
+ *
+ * Return     error code.
+ *
+ * The function assumes it receives buffer with single TS packet
+ * of the relevant PID, and that it has 4 bytes
+ * suffix as extra timestamp in the following format:
+ *
+ * Byte3: TSIF flags
+ * Byte0-2: TTS, 0..2^24-1 at 105.47 Khz (27*10^6/256).
+ *
+ * The function callbacks dmxdev after extraction of the pcr/stc
+ * pair.
+ */
+int mpq_dmx_process_pcr_packet(
+			struct dvb_demux_feed *feed,
+			const u8 *buf);
+
+/**
+ * mpq_dmx_is_video_feed - Returns whether the PES feed
+ * is video one.
+ *
+ * @feed: The feed to be checked.
+ *
+ * Return     1 if feed is video feed, 0 otherwise.
+ */
+static inline int mpq_dmx_is_video_feed(struct dvb_demux_feed *feed)
+{
+	if (feed->type != DMX_TYPE_TS)
+		return 0;
+
+	if (feed->ts_type & (~TS_DECODER))
+		return 0;
+
+	if ((feed->pes_type == DMX_TS_PES_VIDEO0) ||
+		(feed->pes_type == DMX_TS_PES_VIDEO1) ||
+		(feed->pes_type == DMX_TS_PES_VIDEO2) ||
+		(feed->pes_type == DMX_TS_PES_VIDEO3))
+		return 1;
+
+	return 0;
+}
+
+/**
+ * mpq_dmx_is_pcr_feed - Returns whether the PES feed
+ * is PCR one.
+ *
+ * @feed: The feed to be checked.
+ *
+ * Return     1 if feed is PCR feed, 0 otherwise.
+ */
+static inline int mpq_dmx_is_pcr_feed(struct dvb_demux_feed *feed)
+{
+	if (feed->type != DMX_TYPE_TS)
+		return 0;
+
+	if (feed->ts_type & (~TS_DECODER))
+		return 0;
+
+	if ((feed->pes_type == DMX_TS_PES_PCR0) ||
+		(feed->pes_type == DMX_TS_PES_PCR1) ||
+		(feed->pes_type == DMX_TS_PES_PCR2) ||
+		(feed->pes_type == DMX_TS_PES_PCR3))
+		return 1;
+
+	return 0;
+}
+
+/**
+ * mpq_dmx_init_hw_statistics -
+ * Extend dvb-demux debugfs with HW statistics.
+ *
+ * @mpq_demux: The mpq_demux device to initialize.
+ */
+void mpq_dmx_init_hw_statistics(struct mpq_demux *mpq_demux);
+
+
+/**
+ * mpq_dmx_update_hw_statistics -
+ * Update dvb-demux debugfs with HW notification statistics.
+ *
+ * @mpq_demux: The mpq_demux device to update.
+ */
+void mpq_dmx_update_hw_statistics(struct mpq_demux *mpq_demux);
+
+#endif /* _MPQ_DMX_PLUGIN_COMMON_H */
+
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
new file mode 100644
index 0000000..5894a65
--- /dev/null
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
@@ -0,0 +1,747 @@
+/* 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/tsif_api.h>
+#include <linux/workqueue.h>
+#include <linux/moduleparam.h>
+#include "mpq_dvb_debug.h"
+#include "mpq_dmx_plugin_common.h"
+
+/* TSIF HW configuration: */
+#define TSIF_COUNT				2
+/* When TSIF driver notifies demux that new packets are received */
+#define DMX_TSIF_PACKETS_IN_CHUNK_DEF		16
+#define DMX_TSIF_CHUNKS_IN_BUF			8
+#define DMX_TSIF_TIME_LIMIT			10000
+/* TSIF_DRIVER_MODE: 3 means manual control from debugfs. use 1 normally. */
+#define DMX_TSIF_DRIVER_MODE_DEF		1
+
+
+/* module parameters for load time configuration: */
+static int threshold = DMX_TSIF_PACKETS_IN_CHUNK_DEF;
+static int mode = DMX_TSIF_DRIVER_MODE_DEF;
+module_param(threshold, int, S_IRUGO);
+module_param(mode, int, S_IRUGO);
+
+/*
+ * Work scheduled each time TSIF notifies dmx
+ * of new TS packet
+ */
+struct tsif_work {
+	struct work_struct work;
+	int tsif_id;
+};
+
+
+/*
+ * TSIF driver information
+ */
+struct tsif_driver_info {
+	/* handler to TSIF driver */
+	void *tsif_handler;
+	/* TSIF driver data buffer pointer */
+	void *data_buffer;
+	/* TSIF driver data buffer size, in packets */
+	int buffer_size;
+	/* TSIF driver read pointer */
+	int ri;
+	/* TSIF driver write pointer */
+	int wi;
+	/* TSIF driver state */
+	enum tsif_state state;
+};
+
+
+/*
+ * The following structure hold singelton information
+ * required for dmx implementation on top of TSIF.
+ */
+static struct
+{
+	/* Information for each TSIF input processing */
+	struct {
+		/* work used to submit to workqueue for processing */
+		struct tsif_work work;
+
+		/* workqueue that processes TS packets from specific TSIF */
+		struct workqueue_struct *workqueue;
+
+		/* TSIF alias */
+		char name[TSIF_NAME_LENGTH];
+
+		/* TSIF driver information */
+		struct tsif_driver_info tsif_driver;
+
+		/* TSIF reference count (counts start/stop operations */
+		int ref_count;
+
+		/* Pointer to the demux connected to this TSIF */
+		struct mpq_demux *mpq_demux;
+
+		/* mutex protecting the data-structure */
+		struct mutex mutex;
+	} tsif[TSIF_COUNT];
+} mpq_dmx_tsif_info;
+
+
+/**
+ * Worker function that processes the TS packets notified by the TSIF driver.
+ *
+ * @worker: the executed work
+ */
+static void mpq_dmx_tsif_work(struct work_struct *worker)
+{
+	struct tsif_work *tsif_work =
+		container_of(worker, struct tsif_work, work);
+	struct mpq_demux *mpq_demux;
+	struct tsif_driver_info *tsif_driver;
+	size_t packets = 0;
+	int tsif = tsif_work->tsif_id;
+
+	mpq_demux = mpq_dmx_tsif_info.tsif[tsif].mpq_demux;
+	tsif_driver = &(mpq_dmx_tsif_info.tsif[tsif].tsif_driver);
+
+	MPQ_DVB_DBG_PRINT(
+		"%s executed, tsif = %d\n",
+		__func__,
+		tsif);
+
+	if (mutex_lock_interruptible(&mpq_dmx_tsif_info.tsif[tsif].mutex))
+		return;
+
+	/* Check if driver handler is still valid */
+	if (tsif_driver->tsif_handler == NULL) {
+		mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+		MPQ_DVB_ERR_PRINT("%s: tsif_driver->tsif_handler is NULL!\n",
+				__func__);
+		return;
+	}
+
+	tsif_get_state(tsif_driver->tsif_handler, &(tsif_driver->ri),
+				&(tsif_driver->wi), &(tsif_driver->state));
+
+	if ((tsif_driver->wi == tsif_driver->ri) ||
+		(tsif_driver->state == tsif_state_stopped) ||
+		(tsif_driver->state == tsif_state_error)) {
+
+		mpq_demux->hw_notification_size = 0;
+
+		mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid TSIF state (%d), wi = (%d), ri = (%d)\n",
+			__func__,
+			tsif_driver->state, tsif_driver->wi, tsif_driver->ri);
+		return;
+	}
+
+	if (tsif_driver->wi > tsif_driver->ri) {
+		packets = (tsif_driver->wi - tsif_driver->ri);
+		mpq_demux->hw_notification_size = packets;
+
+		dvb_dmx_swfilter_format(
+			&mpq_demux->demux,
+			(tsif_driver->data_buffer +
+			(tsif_driver->ri * TSIF_PKT_SIZE)),
+			(packets * TSIF_PKT_SIZE),
+			DMX_TSP_FORMAT_192_TAIL);
+
+		tsif_driver->ri =
+			(tsif_driver->ri + packets) % tsif_driver->buffer_size;
+
+		tsif_reclaim_packets(tsif_driver->tsif_handler,
+					tsif_driver->ri);
+	} else {
+		/*
+		 * wi < ri, means wraparound on cyclic buffer.
+		 * Handle in two stages.
+		 */
+		packets = (tsif_driver->buffer_size - tsif_driver->ri);
+		mpq_demux->hw_notification_size = packets;
+
+		dvb_dmx_swfilter_format(
+			&mpq_demux->demux,
+			(tsif_driver->data_buffer +
+			(tsif_driver->ri * TSIF_PKT_SIZE)),
+			(packets * TSIF_PKT_SIZE),
+			DMX_TSP_FORMAT_192_TAIL);
+
+		/* tsif_driver->ri should be 0 after this */
+		tsif_driver->ri =
+			(tsif_driver->ri + packets) % tsif_driver->buffer_size;
+
+		packets = tsif_driver->wi;
+		if (packets > 0) {
+			mpq_demux->hw_notification_size += packets;
+
+			dvb_dmx_swfilter_format(
+				&mpq_demux->demux,
+				(tsif_driver->data_buffer +
+				(tsif_driver->ri * TSIF_PKT_SIZE)),
+				(packets * TSIF_PKT_SIZE),
+				DMX_TSP_FORMAT_192_TAIL);
+
+			tsif_driver->ri =
+				(tsif_driver->ri + packets) %
+				tsif_driver->buffer_size;
+		}
+
+		tsif_reclaim_packets(tsif_driver->tsif_handler,
+					tsif_driver->ri);
+	}
+
+	mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+}
+
+
+/**
+ * Callback function from TSIF driver when new data is ready.
+ *
+ * @user: user-data holding TSIF number
+ */
+static void mpq_tsif_callback(void *user)
+{
+	int tsif = (int)user;
+	struct work_struct *work;
+	struct mpq_demux *mpq_demux;
+
+	MPQ_DVB_DBG_PRINT("%s executed, tsif = %d\n", __func__,	tsif);
+
+	/* Save statistics on TSIF notifications */
+	mpq_demux = mpq_dmx_tsif_info.tsif[tsif].mpq_demux;
+	mpq_dmx_update_hw_statistics(mpq_demux);
+
+	work = &mpq_dmx_tsif_info.tsif[tsif].work.work;
+
+	/* Scheudle a new work to demux workqueue */
+	if (!work_pending(work))
+		queue_work(mpq_dmx_tsif_info.tsif[tsif].workqueue, work);
+}
+
+
+/**
+ * Attach to TSIF driver and start TSIF operation.
+ *
+ * @mpq_demux: the mpq_demux we are working on.
+ *
+ * Return	error code.
+ */
+static int mpq_tsif_dmx_start(struct mpq_demux *mpq_demux)
+{
+	int ret = 0;
+	int tsif;
+	struct tsif_driver_info *tsif_driver;
+
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	/* determine the TSIF we are reading from */
+	if (mpq_demux->source == DMX_SOURCE_FRONT0) {
+		tsif = 0;
+	} else if (mpq_demux->source == DMX_SOURCE_FRONT1) {
+		tsif = 1;
+	} else {
+		/* invalid source */
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid input source (%d)\n",
+			__func__,
+			mpq_demux->source);
+
+		return -EINVAL;
+	}
+
+	if (mutex_lock_interruptible(&mpq_dmx_tsif_info.tsif[tsif].mutex))
+		return -ERESTARTSYS;
+
+	if (mpq_dmx_tsif_info.tsif[tsif].ref_count == 0) {
+		tsif_driver = &(mpq_dmx_tsif_info.tsif[tsif].tsif_driver);
+
+		/* Attach to TSIF driver */
+
+		tsif_driver->tsif_handler =
+			tsif_attach(tsif, mpq_tsif_callback, (void *)tsif);
+		if (IS_ERR_OR_NULL(tsif_driver->tsif_handler)) {
+			tsif_driver->tsif_handler = NULL;
+			mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+			MPQ_DVB_DBG_PRINT("%s: tsif_attach(%d) failed\n",
+					__func__, tsif);
+			return -ENODEV;
+		}
+
+		/* Set TSIF driver mode */
+		ret = tsif_set_mode(tsif_driver->tsif_handler,
+					mode);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT("%s: tsif_set_mode (%d) failed\n",
+				__func__, mode);
+		}
+
+		/* Set TSIF buffer configuration */
+		ret = tsif_set_buf_config(tsif_driver->tsif_handler,
+						threshold,
+						DMX_TSIF_CHUNKS_IN_BUF);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: tsif_set_buf_config (%d, %d) failed\n",
+				__func__, threshold,
+				DMX_TSIF_CHUNKS_IN_BUF);
+			MPQ_DVB_ERR_PRINT("Using default TSIF driver values\n");
+		}
+
+
+		/* Set TSIF driver time limit */
+		/* TODO: needed?? */
+/*		ret = tsif_set_time_limit(tsif_driver->tsif_handler,
+						DMX_TSIF_TIME_LIMIT);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: tsif_set_time_limit (%d) failed\n",
+				__func__, DMX_TSIF_TIME_LIMIT);
+		}
+*/
+
+		/* Start TSIF driver */
+		ret = tsif_start(tsif_driver->tsif_handler);
+		if (ret < 0) {
+			mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+			MPQ_DVB_ERR_PRINT("%s: tsif_start failed\n", __func__);
+			return ret;
+		}
+
+		/*
+		 * Get data buffer information from TSIF driver
+		 * (must be called after tsif_start)
+		 */
+		tsif_get_info(tsif_driver->tsif_handler,
+				&(tsif_driver->data_buffer),
+				&(tsif_driver->buffer_size));
+
+		/* save pointer to the mpq_demux we are working on */
+		mpq_dmx_tsif_info.tsif[tsif].mpq_demux = mpq_demux;
+	}
+	mpq_dmx_tsif_info.tsif[tsif].ref_count++;
+
+	mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+
+	return ret;
+}
+
+
+/**
+ * Stop TSIF operation and detach from TSIF driver.
+ *
+ * @mpq_demux: the mpq_demux we are working on.
+ *
+ * Return	error code.
+ */
+static int mpq_tsif_dmx_stop(struct mpq_demux *mpq_demux)
+{
+	int tsif;
+	struct tsif_driver_info *tsif_driver;
+
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	/* determine the TSIF we are reading from */
+	if (mpq_demux->source == DMX_SOURCE_FRONT0) {
+		tsif = 0;
+	} else if (mpq_demux->source == DMX_SOURCE_FRONT1) {
+		tsif = 1;
+	} else {
+		/* invalid source */
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid input source (%d)\n",
+			__func__,
+			mpq_demux->source);
+
+		return -EINVAL;
+	}
+
+	if (mutex_lock_interruptible(&mpq_dmx_tsif_info.tsif[tsif].mutex))
+		return -ERESTARTSYS;
+
+	mpq_dmx_tsif_info.tsif[tsif].ref_count--;
+
+	if (mpq_dmx_tsif_info.tsif[tsif].ref_count == 0) {
+		tsif_driver = &(mpq_dmx_tsif_info.tsif[tsif].tsif_driver);
+		tsif_stop(tsif_driver->tsif_handler);
+		tsif_detach(tsif_driver->tsif_handler);
+		/*
+		 * temporarily release mutex and flush the work queue
+		 * before setting tsif_handler to NULL
+		 */
+		mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+		flush_workqueue(mpq_dmx_tsif_info.tsif[tsif].workqueue);
+		/* re-acquire mutex */
+		if (mutex_lock_interruptible(
+				&mpq_dmx_tsif_info.tsif[tsif].mutex))
+			return -ERESTARTSYS;
+
+		tsif_driver->tsif_handler = NULL;
+		tsif_driver->data_buffer = NULL;
+		tsif_driver->buffer_size = 0;
+		mpq_dmx_tsif_info.tsif[tsif].mpq_demux = NULL;
+	}
+
+	mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+
+	return 0;
+}
+
+
+/**
+ * Start filtering according to feed parameter.
+ *
+ * @feed: the feed we are working on.
+ *
+ * Return	error code.
+ */
+static int mpq_tsif_dmx_start_filtering(struct dvb_demux_feed *feed)
+{
+	int ret = 0;
+	struct mpq_demux *mpq_demux =
+		(struct mpq_demux *)feed->demux->priv;
+
+	MPQ_DVB_DBG_PRINT(
+		"%s(%d) executed\n",
+		__func__,
+		feed->pid);
+
+	if (mpq_demux == NULL) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid mpq_demux handle\n",
+			__func__);
+
+		return -EINVAL;
+	}
+
+	if (mpq_demux->source < DMX_SOURCE_DVR0) {
+		/* Source from TSIF, need to configure TSIF hardware */
+		ret = mpq_tsif_dmx_start(mpq_demux);
+
+		if (ret < 0) {
+			MPQ_DVB_DBG_PRINT(
+				"%s: mpq_tsif_dmx_start failed(%d)\n",
+				__func__,
+				ret);
+			return ret;
+		}
+	}
+
+	/* Always feed sections/PES starting from a new one and
+	 * do not partial transfer data from older one
+	 */
+	feed->pusi_seen = 0;
+
+	/*
+	 * For video PES, data is tunneled to the decoder,
+	 * initialize tunneling and pes parsing.
+	 */
+	if (mpq_dmx_is_video_feed(feed)) {
+		ret = mpq_dmx_init_video_feed(feed);
+
+		if (ret < 0) {
+			MPQ_DVB_DBG_PRINT(
+				"%s: mpq_dmx_init_video_feed failed(%d)\n",
+				__func__,
+				ret);
+
+			if (mpq_demux->source < DMX_SOURCE_DVR0)
+				mpq_tsif_dmx_stop(mpq_demux);
+
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+
+/**
+ * Stop filtering according to feed parameter.
+ *
+ * @feed: the feed we are working on.
+ *
+ * Return	error code.
+ */
+static int mpq_tsif_dmx_stop_filtering(struct dvb_demux_feed *feed)
+{
+	int ret = 0;
+	struct mpq_demux *mpq_demux =
+		(struct mpq_demux *)feed->demux->priv;
+
+	MPQ_DVB_DBG_PRINT(
+		"%s(%d) executed\n",
+		__func__,
+		feed->pid);
+
+	if (mpq_demux == NULL) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid mpq_demux handle\n",
+			__func__);
+
+		return -EINVAL;
+	}
+
+	/*
+	 * For video PES, data is tunneled to the decoder,
+	 * terminate tunnel and pes parsing.
+	 */
+	if (mpq_dmx_is_video_feed(feed))
+		mpq_dmx_terminate_video_feed(feed);
+
+	if (mpq_demux->source < DMX_SOURCE_DVR0) {
+		/* Source from TSIF, need to configure TSIF hardware */
+		ret = mpq_tsif_dmx_stop(mpq_demux);
+	}
+
+	return ret;
+}
+
+
+/**
+ * TSIF demux plugin write-to-decoder function.
+ *
+ * @feed: The feed we are working on.
+ * @buf: The data buffer to process.
+ * @len: The data buffer length.
+ *
+ * Return	error code
+ */
+static int mpq_tsif_dmx_write_to_decoder(
+					struct dvb_demux_feed *feed,
+					const u8 *buf,
+					size_t len)
+{
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	/*
+	 * It is assumed that this function is called once for each
+	 * TS packet of the relevant feed.
+	 */
+	if (len > TSIF_PKT_SIZE)
+		MPQ_DVB_DBG_PRINT(
+				"%s: warnning - len larger than one packet\n",
+				__func__);
+
+	if (mpq_dmx_is_video_feed(feed))
+		return mpq_dmx_process_video_packet(feed, buf);
+
+	if (mpq_dmx_is_pcr_feed(feed))
+		return mpq_dmx_process_pcr_packet(feed, buf);
+
+	return 0;
+}
+
+
+/**
+ * Initialize a single demux device.
+ *
+ * @mpq_adapter: MPQ DVB adapter
+ * @mpq_demux: The demux device to initialize
+ *
+ * Return	error code
+ */
+static int mpq_tsif_dmx_init(
+		struct dvb_adapter *mpq_adapter,
+		struct mpq_demux *mpq_demux)
+{
+	int result;
+
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	/* 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_CRC_CHECKING		|
+		DMX_TS_DESCRAMBLING;
+
+	/* Set dvb-demux "virtual" function pointers */
+	mpq_demux->demux.priv = (void *)mpq_demux;
+	mpq_demux->demux.filternum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+	mpq_demux->demux.feednum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+	mpq_demux->demux.start_feed = mpq_tsif_dmx_start_filtering;
+	mpq_demux->demux.stop_feed = mpq_tsif_dmx_stop_filtering;
+	mpq_demux->demux.write_to_decoder = mpq_tsif_dmx_write_to_decoder;
+
+	mpq_demux->demux.decoder_fullness_init =
+		mpq_dmx_decoder_fullness_init;
+
+	mpq_demux->demux.decoder_fullness_wait =
+		mpq_dmx_decoder_fullness_wait;
+
+	mpq_demux->demux.decoder_fullness_abort =
+		mpq_dmx_decoder_fullness_abort;
+
+	/* Initialize dvb_demux object */
+	result = dvb_dmx_init(&mpq_demux->demux);
+	if (result < 0) {
+		MPQ_DVB_ERR_PRINT("%s: dvb_dmx_init failed\n", __func__);
+		goto init_failed;
+	}
+
+	/* Now initailize the dmx-dev object */
+	mpq_demux->dmxdev.filternum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+	mpq_demux->dmxdev.demux = &mpq_demux->demux.dmx;
+	mpq_demux->dmxdev.capabilities =
+		DMXDEV_CAP_DUPLEX |
+		DMXDEV_CAP_PULL_MODE |
+		DMXDEV_CAP_PCR_EXTRACTION;
+
+	mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
+
+	result = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter);
+	if (result < 0) {
+		MPQ_DVB_ERR_PRINT("%s: dvb_dmxdev_init failed (errno=%d)\n",
+						  __func__,
+						  result);
+		goto init_failed_dmx_release;
+	}
+
+	/* Extend dvb-demux debugfs with TSIF statistics. */
+	mpq_dmx_init_hw_statistics(mpq_demux);
+
+	return 0;
+
+init_failed_dmx_release:
+	dvb_dmx_release(&mpq_demux->demux);
+init_failed:
+	return result;
+}
+
+
+/**
+ * Module initialization function.
+ *
+ * Return	error code
+ */
+static int __init mpq_dmx_tsif_plugin_init(void)
+{
+	int i;
+	int ret;
+
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	/* check module parameters validity */
+	if (threshold < 1) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid threshold parameter, using %d instead\n",
+			__func__, DMX_TSIF_PACKETS_IN_CHUNK_DEF);
+		threshold = DMX_TSIF_PACKETS_IN_CHUNK_DEF;
+	}
+	if ((mode < 1) || (mode > 3)) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid mode parameter, using %d instead\n",
+			__func__, DMX_TSIF_DRIVER_MODE_DEF);
+		mode = DMX_TSIF_DRIVER_MODE_DEF;
+	}
+
+	for (i = 0; i < TSIF_COUNT; i++) {
+		mpq_dmx_tsif_info.tsif[i].work.tsif_id = i;
+
+		INIT_WORK(&mpq_dmx_tsif_info.tsif[i].work.work,
+				  mpq_dmx_tsif_work);
+
+		snprintf(mpq_dmx_tsif_info.tsif[i].name,
+				TSIF_NAME_LENGTH,
+				"tsif_%d",
+				i);
+
+		mpq_dmx_tsif_info.tsif[i].workqueue =
+			create_singlethread_workqueue(
+				mpq_dmx_tsif_info.tsif[i].name);
+
+		if (mpq_dmx_tsif_info.tsif[i].workqueue == NULL) {
+			int j;
+
+			for (j = 0; j < i; j++) {
+				destroy_workqueue(
+					mpq_dmx_tsif_info.tsif[j].workqueue);
+				mutex_destroy(&mpq_dmx_tsif_info.tsif[j].mutex);
+			}
+
+			MPQ_DVB_ERR_PRINT(
+				"%s: create_singlethread_workqueue failed\n",
+				__func__);
+
+			return -ENOMEM;
+		}
+
+		mutex_init(&mpq_dmx_tsif_info.tsif[i].mutex);
+
+		mpq_dmx_tsif_info.tsif[i].tsif_driver.tsif_handler = NULL;
+		mpq_dmx_tsif_info.tsif[i].ref_count = 0;
+	}
+
+	ret = mpq_dmx_plugin_init(mpq_tsif_dmx_init);
+
+	if (ret < 0) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_dmx_plugin_init failed (errno=%d)\n",
+			__func__,
+			ret);
+
+		for (i = 0; i < TSIF_COUNT; i++) {
+			destroy_workqueue(mpq_dmx_tsif_info.tsif[i].workqueue);
+			mutex_destroy(&mpq_dmx_tsif_info.tsif[i].mutex);
+		}
+	}
+
+	return ret;
+}
+
+
+/**
+ * Module exit function.
+ */
+static void __exit mpq_dmx_tsif_plugin_exit(void)
+{
+	int i;
+	struct tsif_driver_info *tsif_driver;
+
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	for (i = 0; i < TSIF_COUNT; i++) {
+		mutex_lock(&mpq_dmx_tsif_info.tsif[i].mutex);
+
+		tsif_driver = &(mpq_dmx_tsif_info.tsif[i].tsif_driver);
+		if (mpq_dmx_tsif_info.tsif[i].ref_count > 0) {
+			mpq_dmx_tsif_info.tsif[i].ref_count = 0;
+			if (tsif_driver->tsif_handler)
+				tsif_stop(tsif_driver->tsif_handler);
+		}
+		/* Detach from TSIF driver to avoid further notifications. */
+		if (tsif_driver->tsif_handler)
+			tsif_detach(tsif_driver->tsif_handler);
+
+		/* release mutex to allow work queue to finish scheduled work */
+		mutex_unlock(&mpq_dmx_tsif_info.tsif[i].mutex);
+		/* flush the work queue and destroy it */
+		flush_workqueue(mpq_dmx_tsif_info.tsif[i].workqueue);
+		destroy_workqueue(mpq_dmx_tsif_info.tsif[i].workqueue);
+
+		mutex_destroy(&mpq_dmx_tsif_info.tsif[i].mutex);
+	}
+
+	mpq_dmx_plugin_exit();
+}
+
+
+module_init(mpq_dmx_tsif_plugin_init);
+module_exit(mpq_dmx_tsif_plugin_exit);
+
+MODULE_DESCRIPTION("Qualcomm demux TSIF HW Plugin");
+MODULE_LICENSE("GPL v2");
+
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
new file mode 100644
index 0000000..406ae52
--- /dev/null
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
@@ -0,0 +1,847 @@
+/* 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/workqueue.h>
+#include <mach/msm_tspp.h>
+#include "mpq_dvb_debug.h"
+#include "mpq_dmx_plugin_common.h"
+
+
+#define TSIF_COUNT						2
+
+#define TSPP_FILTERS_COUNT				16
+
+/* For each TSIF we allocate two pipes, one for PES and one for sections */
+#define TSPP_PES_CHANNEL				0
+#define TSPP_SECTION_CHANNEL			1
+
+/* the channel_id set to TSPP driver based on TSIF number and channel type */
+#define TSPP_CHANNEL_ID(tsif, ch)		((tsif << 1) + ch)
+#define TSPP_IS_PES_CHANNEL(ch_id)		((ch_id & 0x1) == 0)
+#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
+
+/* dvb-demux defines pid 0x2000 as full capture pid */
+#define TSPP_PASS_THROUGH_PID			0x2000
+
+/* TODO - NEED TO SET THESE PROPERLY
+ * once TSPP driver is ready, reduce TSPP_BUFFER_SIZE
+ * to single packet and set TSPP_BUFFER_COUNT accordingly
+ */
+
+#define TSPP_RAW_TTS_SIZE				192
+
+/* Size of single descriptor */
+#define TSPP_BUFFER_SIZE				(TSPP_RAW_TTS_SIZE * 35)
+
+/* Number of descriptors, total size: TSPP_BUFFER_SIZE*TSPP_BUFFER_COUNT */
+#define TSPP_BUFFER_COUNT				(16)
+
+/* When TSPP notifies demux that new packets are received */
+#define TSPP_NOTIFICATION_SIZE			(TSPP_RAW_TTS_SIZE * 100)
+
+/* Channel timeout in msec */
+#define TSPP_CHANNEL_TIMEOUT			16
+
+
+/*
+ * Work scheduled each time TSPP notifies dmx
+ * of new TS packet in some channel
+ */
+struct tspp_work {
+	struct work_struct work;
+	int channel_id;
+};
+
+/* The following structure hold singelton information
+ * required for dmx implementation on top of TSPP.
+ */
+static struct
+{
+	/* Information for each TSIF input processing */
+	struct {
+		/*
+		 * TSPP pipe holding all TS packets with PES data.
+		 * The following is reference count for number of feeds
+		 * allocated on that pipe.
+		 */
+		int pes_channel_ref;
+
+		/* work used to submit to workqueue to process pes channel */
+		struct tspp_work pes_work;
+
+		/*
+		 * TSPP pipe holding all TS packets with section data.
+		 * The following is reference count for number of feeds
+		 * allocated on that pipe.
+		 */
+		int section_channel_ref;
+
+		/* work used to submit to workqueue to process pes channel */
+		struct tspp_work section_work;
+
+		/*
+		 * Holds PIDs of allocated TSPP filters along with
+		 * how many feeds are opened on same PID.
+		 */
+		struct {
+			int pid;
+			int ref_count;
+		} filters[TSPP_FILTERS_COUNT];
+
+		/* workqueue that processes TS packets from specific TSIF */
+		struct workqueue_struct *workqueue;
+
+		/* TSIF alias */
+		char name[TSIF_NAME_LENGTH];
+
+		/* Pointer to the demux connected to this TSIF */
+		struct mpq_demux *mpq_demux;
+
+		/* mutex protecting the data-structure */
+		struct mutex mutex;
+	} tsif[TSIF_COUNT];
+} mpq_dmx_tspp_info;
+
+
+/**
+ * Returns a free filter slot that can be used.
+ *
+ * @tsif: The TSIF to allocate filter from
+ * @channel_id: The channel allocating filter to
+ *
+ * Return  filter index or -1 if no filters available
+ *
+ * To give priority to PES data, for pes filters
+ * the table is scanned from high to low priority,
+ * and sections from low to high priority. This way TSPP
+ * would get a match on PES data filters faster as they
+ * are scanned first.
+ */
+static int mpq_tspp_get_free_filter_slot(int tsif, int channel_id)
+{
+	int i;
+
+	if (TSPP_IS_PES_CHANNEL(channel_id)) {
+		for (i = 0; i < TSPP_FILTERS_COUNT; i++)
+			if (mpq_dmx_tspp_info.tsif[tsif].filters[i].pid == -1)
+				return i;
+	} else {
+		for (i = TSPP_FILTERS_COUNT-1; i >= 0; i--)
+			if (mpq_dmx_tspp_info.tsif[tsif].filters[i].pid == -1)
+				return i;
+	}
+
+	return -ENOMEM;
+}
+
+/**
+ * Returns filter index of specific pid.
+ *
+ * @tsif: The TSIF to which the pid is allocated
+ * @pid: The pid to search for
+ *
+ * Return  filter index or -1 if no filter available
+ */
+static int mpq_tspp_get_filter_slot(int tsif, int pid)
+{
+	int i;
+
+	for (i = 0; i < TSPP_FILTERS_COUNT; i++)
+		if (mpq_dmx_tspp_info.tsif[tsif].filters[i].pid == pid)
+			return i;
+
+	return -EINVAL;
+}
+
+/**
+ * Worker function that processes the TS packets notified by TSPP.
+ *
+ * @worker: the executed work
+ */
+static void mpq_dmx_tspp_work(struct work_struct *worker)
+{
+	struct tspp_work *tspp_work =
+		container_of(worker, struct tspp_work, work);
+	struct mpq_demux *mpq_demux;
+	int channel_id = tspp_work->channel_id;
+	int tsif = TSPP_GET_TSIF_NUM(channel_id);
+	const struct tspp_data_descriptor *tspp_data_desc;
+	int ref_count;
+
+	mpq_demux = mpq_dmx_tspp_info.tsif[tsif].mpq_demux;
+
+	/* Lock against the TSPP filters data-structure */
+	if (mutex_lock_interruptible(&mpq_dmx_tspp_info.tsif[tsif].mutex))
+		return;
+
+	/* Make sure channel is still active */
+	if (TSPP_IS_PES_CHANNEL(channel_id))
+		ref_count = mpq_dmx_tspp_info.tsif[tsif].pes_channel_ref;
+	else
+		ref_count = mpq_dmx_tspp_info.tsif[tsif].section_channel_ref;
+
+	if (ref_count == 0) {
+		mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+		return;
+	}
+
+	mpq_demux->hw_notification_size = 0;
+
+	/* Go through all filled descriptors and perform demuxing on them */
+	while ((tspp_data_desc = tspp_get_buffer(0, channel_id)) != NULL) {
+		mpq_demux->hw_notification_size +=
+			(tspp_data_desc->size / TSPP_RAW_TTS_SIZE);
+
+		dvb_dmx_swfilter_format(
+				&mpq_demux->demux,
+				tspp_data_desc->virt_base,
+				tspp_data_desc->size,
+				DMX_TSP_FORMAT_192_TAIL);
+
+		/* Notify TSPP that the buffer is no longer needed */
+		tspp_release_buffer(0, channel_id, tspp_data_desc->id);
+	}
+
+	mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+}
+
+/**
+ * Callback function from TSPP when new data is ready.
+ *
+ * @channel_id: Channel with new TS packets
+ * @user: user-data holding TSIF number
+ */
+static void mpq_tspp_callback(u32 channel_id, void *user)
+{
+	int tsif = (int)user;
+	struct work_struct *work;
+	struct mpq_demux *mpq_demux;
+
+	/* Save statistics on TSPP notifications */
+	mpq_demux = mpq_dmx_tspp_info.tsif[tsif].mpq_demux;
+	mpq_dmx_update_hw_statistics(mpq_demux);
+
+	if (TSPP_IS_PES_CHANNEL(channel_id))
+		work = &mpq_dmx_tspp_info.tsif[tsif].pes_work.work;
+	else
+		work = &mpq_dmx_tspp_info.tsif[tsif].section_work.work;
+
+	/* Scheudle a new work to demux workqueue */
+	if (!work_pending(work))
+		queue_work(mpq_dmx_tspp_info.tsif[tsif].workqueue, work);
+}
+
+/**
+ * Configure TSPP channel to filter the PID of new feed.
+ *
+ * @feed: The feed to configure the channel with
+ *
+ * Return  error status
+ *
+ * The function checks if the new PID can be added to an already
+ * allocated channel, if not, a new channel is allocated and configured.
+ */
+static int mpq_tspp_dmx_add_channel(struct dvb_demux_feed *feed)
+{
+	struct mpq_demux *mpq_demux = (struct mpq_demux *)feed->demux->priv;
+	enum tspp_source tspp_source;
+	struct tspp_filter tspp_filter;
+	int tsif;
+	int ret;
+	int channel_id;
+	int *channel_ref_count;
+
+	/* determine the TSIF we are reading from */
+	if (mpq_demux->source == DMX_SOURCE_FRONT0) {
+		tsif = 0;
+		tspp_source = TSPP_SOURCE_TSIF0;
+	} else if (mpq_demux->source == DMX_SOURCE_FRONT1) {
+		tsif = 1;
+		tspp_source = TSPP_SOURCE_TSIF1;
+	} else {
+		/* invalid source */
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid input source (%d)\n",
+			__func__,
+			mpq_demux->source);
+
+		return -EINVAL;
+	}
+
+	if (mutex_lock_interruptible(&mpq_dmx_tspp_info.tsif[tsif].mutex))
+		return -ERESTARTSYS;
+
+	/*
+	 * It is possible that this PID was already requested before.
+	 * Can happen if we play and record same PES or PCR
+	 * piggypacked on video packet.
+	 */
+	ret = mpq_tspp_get_filter_slot(tsif, feed->pid);
+	if (ret >= 0) {
+		/* PID already configured */
+		mpq_dmx_tspp_info.tsif[tsif].filters[ret].ref_count++;
+		mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+		return 0;
+	}
+
+	/* determine to which pipe the feed should be routed: section or pes */
+	if ((feed->type == DMX_TYPE_PES) || (feed->type == DMX_TYPE_TS)) {
+		channel_id = TSPP_CHANNEL_ID(tsif, TSPP_PES_CHANNEL);
+		channel_ref_count =
+			&mpq_dmx_tspp_info.tsif[tsif].pes_channel_ref;
+	} else {
+		channel_id = TSPP_CHANNEL_ID(tsif, TSPP_SECTION_CHANNEL);
+		channel_ref_count =
+			&mpq_dmx_tspp_info.tsif[tsif].section_channel_ref;
+	}
+
+	/* check if required TSPP pipe is already allocated or not */
+	if (*channel_ref_count == 0) {
+		ret = tspp_open_channel(0, channel_id);
+
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: tspp_open_channel(%d) failed (%d)\n",
+				__func__,
+				channel_id,
+				ret);
+
+			goto add_channel_failed;
+		}
+
+		/* set TSPP source */
+		ret = tspp_open_stream(0, channel_id, tspp_source);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: tspp_select_source(%d,%d) failed (%d)\n",
+				__func__,
+				channel_id,
+				tspp_source,
+				ret);
+
+			goto add_channel_close_ch;
+		}
+
+		/* register notification on TS packets */
+		tspp_register_notification(0,
+					   channel_id,
+					   mpq_tspp_callback,
+					   (void *)tsif,
+					   TSPP_CHANNEL_TIMEOUT);
+
+		/* TODO: register allocater and provide allocation function
+		 * that allocate 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);
+		if (ret < 0) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: tspp_allocate_buffers(%d) failed (%d)\n",
+				__func__,
+				channel_id,
+				ret);
+
+			goto add_channel_unregister_notif;
+		}
+
+		mpq_dmx_tspp_info.tsif[tsif].mpq_demux = mpq_demux;
+	}
+
+	/* add new PID to the existing pipe */
+	ret = mpq_tspp_get_free_filter_slot(tsif, channel_id);
+	if (ret < 0) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_allocate_filter_slot(%d, %d) failed\n",
+			__func__,
+			tsif,
+			channel_id);
+
+		goto add_channel_unregister_notif;
+	}
+
+	mpq_dmx_tspp_info.tsif[tsif].filters[ret].pid = feed->pid;
+	mpq_dmx_tspp_info.tsif[tsif].filters[ret].ref_count++;
+
+	tspp_filter.priority = ret;
+	if (feed->pid == TSPP_PASS_THROUGH_PID) {
+		/* pass all pids */
+		tspp_filter.pid = 0;
+		tspp_filter.mask = 0;
+	} else {
+		tspp_filter.pid = feed->pid;
+		tspp_filter.mask = TSPP_PID_MASK;
+	}
+
+	/*
+	 * Include TTS in RAW packets, if you change this to
+	 * TSPP_MODE_RAW_NO_SUFFIX you must also change TSPP_RAW_TTS_SIZE
+	 * accordingly.
+	 */
+	tspp_filter.mode = TSPP_MODE_RAW;
+	tspp_filter.source = tspp_source;
+	tspp_filter.decrypt = 0;
+	ret = tspp_add_filter(0, channel_id, &tspp_filter);
+	if (ret < 0) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: tspp_add_filter(%d) failed (%d)\n",
+			__func__,
+			channel_id,
+			ret);
+
+		goto add_channel_free_filter_slot;
+	}
+
+	(*channel_ref_count)++;
+
+	mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+	return 0;
+
+add_channel_free_filter_slot:
+	mpq_dmx_tspp_info.tsif[tsif].filters[tspp_filter.priority].pid = -1;
+	mpq_dmx_tspp_info.tsif[tsif].filters[tspp_filter.priority].ref_count--;
+add_channel_unregister_notif:
+	tspp_unregister_notification(0, channel_id);
+add_channel_close_ch:
+	tspp_close_channel(0, channel_id);
+add_channel_failed:
+	mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+	return ret;
+}
+
+/**
+ * Removes filter from TSPP.
+ *
+ * @feed: The feed to remove
+ *
+ * Return  error status
+ *
+ * The function checks if this is the only PID allocated within
+ * the channel, if so, the channel is closed as well.
+ */
+static int mpq_tspp_dmx_remove_channel(struct dvb_demux_feed *feed)
+{
+	int tsif;
+	int ret;
+	int channel_id;
+	int *channel_ref_count;
+	struct tspp_filter tspp_filter;
+	struct mpq_demux *mpq_demux = (struct mpq_demux *)feed->demux->priv;
+
+	/* determine the TSIF we are reading from */
+	if (mpq_demux->source == DMX_SOURCE_FRONT0) {
+		tsif = 0;
+	} else if (mpq_demux->source == DMX_SOURCE_FRONT1) {
+		tsif = 1;
+	} else {
+		/* invalid source */
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid input source (%d)\n",
+			__func__,
+			mpq_demux->source);
+
+		return -EINVAL;
+	}
+
+	if (mutex_lock_interruptible(&mpq_dmx_tspp_info.tsif[tsif].mutex))
+		return -ERESTARTSYS;
+
+	/* determine to which pipe the feed should be routed: section or pes */
+	if ((feed->type == DMX_TYPE_PES) || (feed->type == DMX_TYPE_TS)) {
+		channel_id = TSPP_CHANNEL_ID(tsif, TSPP_PES_CHANNEL);
+		channel_ref_count =
+			&mpq_dmx_tspp_info.tsif[tsif].pes_channel_ref;
+	} else {
+		channel_id = TSPP_CHANNEL_ID(tsif, TSPP_SECTION_CHANNEL);
+		channel_ref_count =
+			&mpq_dmx_tspp_info.tsif[tsif].section_channel_ref;
+	}
+
+	/* check if required TSPP pipe is already allocated or not */
+	if (*channel_ref_count == 0) {
+		/* invalid feed provided as the channel is not allocated */
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid feed (%d)\n",
+			__func__,
+			channel_id);
+
+		ret = -EINVAL;
+		goto remove_channel_failed;
+	}
+
+	tspp_filter.priority = mpq_tspp_get_filter_slot(tsif, feed->pid);
+
+	if (tspp_filter.priority < 0) {
+		/* invalid feed provided as it has no filter allocated */
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_tspp_get_filter_slot failed (%d,%d)\n",
+			__func__,
+			feed->pid,
+			tsif);
+
+		ret = -EINVAL;
+		goto remove_channel_failed;
+	}
+
+	mpq_dmx_tspp_info.tsif[tsif].filters[tspp_filter.priority].ref_count--;
+
+	if (mpq_dmx_tspp_info.tsif[tsif].
+		filters[tspp_filter.priority].ref_count) {
+		/*
+		 * there are still references to this pid, do not
+		 * remove the filter yet
+		 */
+		mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+		return 0;
+	}
+
+	ret = tspp_remove_filter(0, channel_id, &tspp_filter);
+	if (ret < 0) {
+		/* invalid feed provided as it has no filter allocated */
+		MPQ_DVB_ERR_PRINT(
+			"%s: tspp_remove_filter failed (%d,%d)\n",
+			__func__,
+			channel_id,
+			tspp_filter.priority);
+
+		goto remove_channel_failed_restore_count;
+	}
+
+	mpq_dmx_tspp_info.tsif[tsif].filters[tspp_filter.priority].pid = -1;
+	(*channel_ref_count)--;
+
+	if (*channel_ref_count == 0) {
+		/* channel is not used any more, release it */
+		tspp_unregister_notification(0, channel_id);
+		tspp_close_channel(0, channel_id);
+	}
+
+	mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+	return 0;
+
+remove_channel_failed_restore_count:
+	mpq_dmx_tspp_info.tsif[tsif].filters[tspp_filter.priority].ref_count++;
+
+remove_channel_failed:
+	mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+	return ret;
+}
+
+static int mpq_tspp_dmx_start_filtering(struct dvb_demux_feed *feed)
+{
+	int ret;
+	struct mpq_demux *mpq_demux =
+		(struct mpq_demux *)feed->demux->priv;
+
+	MPQ_DVB_DBG_PRINT(
+		"%s(%d) executed\n",
+		__func__,
+		feed->pid);
+
+	if (mpq_demux == NULL) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: invalid mpq_demux handle\n",
+			__func__);
+
+		return -EINVAL;
+	}
+
+	if (mpq_demux->source < DMX_SOURCE_DVR0) {
+		/* source from TSPP, need to configure tspp pipe */
+		ret = mpq_tspp_dmx_add_channel(feed);
+
+		if (ret < 0) {
+			MPQ_DVB_DBG_PRINT(
+				"%s: mpq_tspp_dmx_add_channel failed(%d)\n",
+				__func__,
+				ret);
+			return ret;
+		}
+	}
+
+	/*
+	 * Always feed sections/PES starting from a new one and
+	 * do not partial transfer data from older one
+	 */
+	feed->pusi_seen = 0;
+
+	/*
+	 * For video PES, data is tunneled to the decoder,
+	 * initialize tunneling and pes parsing.
+	 */
+	if (mpq_dmx_is_video_feed(feed)) {
+		ret = mpq_dmx_init_video_feed(feed);
+
+		if (ret < 0) {
+			MPQ_DVB_DBG_PRINT(
+				"%s: mpq_dmx_init_video_feed failed(%d)\n",
+				__func__,
+				ret);
+
+			if (mpq_demux->source < DMX_SOURCE_DVR0)
+				mpq_tspp_dmx_remove_channel(feed);
+
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int mpq_tspp_dmx_stop_filtering(struct dvb_demux_feed *feed)
+{
+	int ret = 0;
+	struct mpq_demux *mpq_demux = (struct mpq_demux *)feed->demux->priv;
+
+	MPQ_DVB_DBG_PRINT(
+		"%s(%d) executed\n",
+		__func__,
+		feed->pid);
+
+	/*
+	 * For video PES, data is tunneled to the decoder,
+	 * terminate tunnel and pes parsing.
+	 */
+	if (mpq_dmx_is_video_feed(feed))
+		mpq_dmx_terminate_video_feed(feed);
+
+	if (mpq_demux->source < DMX_SOURCE_DVR0) {
+		/* source from TSPP, need to configure tspp pipe */
+		ret = mpq_tspp_dmx_remove_channel(feed);
+	}
+
+	return ret;
+}
+
+static int mpq_tspp_dmx_write_to_decoder(
+					struct dvb_demux_feed *feed,
+					const u8 *buf,
+					size_t len)
+{
+	/*
+	 * It is assumed that this function is called once for each
+	 * TS packet of the relevant feed.
+	 */
+	if (len > TSPP_RAW_TTS_SIZE)
+		MPQ_DVB_DBG_PRINT(
+				"%s: warnning - len larger than one packet\n",
+				__func__);
+
+	if (mpq_dmx_is_video_feed(feed))
+		return mpq_dmx_process_video_packet(feed, buf);
+
+	if (mpq_dmx_is_pcr_feed(feed))
+		return mpq_dmx_process_pcr_packet(feed, buf);
+
+	return 0;
+}
+
+static int mpq_tspp_dmx_init(
+			struct dvb_adapter *mpq_adapter,
+			struct mpq_demux *mpq_demux)
+{
+	int result;
+
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	/* 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_CRC_CHECKING			|
+		DMX_TS_DESCRAMBLING;
+
+	/* Set dvb-demux "virtual" function pointers */
+	mpq_demux->demux.priv = (void *)mpq_demux;
+	mpq_demux->demux.filternum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+	mpq_demux->demux.feednum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+	mpq_demux->demux.start_feed = mpq_tspp_dmx_start_filtering;
+	mpq_demux->demux.stop_feed = mpq_tspp_dmx_stop_filtering;
+	mpq_demux->demux.write_to_decoder = mpq_tspp_dmx_write_to_decoder;
+
+	mpq_demux->demux.decoder_fullness_init =
+		mpq_dmx_decoder_fullness_init;
+
+	mpq_demux->demux.decoder_fullness_wait =
+		mpq_dmx_decoder_fullness_wait;
+
+	mpq_demux->demux.decoder_fullness_abort =
+		mpq_dmx_decoder_fullness_abort;
+
+	/* Initialize dvb_demux object */
+	result = dvb_dmx_init(&mpq_demux->demux);
+	if (result < 0) {
+		MPQ_DVB_ERR_PRINT("%s: dvb_dmx_init failed\n", __func__);
+		goto init_failed;
+	}
+
+	/* Now initailize the dmx-dev object */
+	mpq_demux->dmxdev.filternum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+	mpq_demux->dmxdev.demux = &mpq_demux->demux.dmx;
+	mpq_demux->dmxdev.capabilities =
+		DMXDEV_CAP_DUPLEX |
+		DMXDEV_CAP_PULL_MODE |
+		DMXDEV_CAP_PCR_EXTRACTION;
+
+	mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
+
+	result = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter);
+	if (result < 0) {
+		MPQ_DVB_ERR_PRINT("%s: dvb_dmxdev_init failed (errno=%d)\n",
+						  __func__,
+						  result);
+		goto init_failed_dmx_release;
+	}
+
+	/* Extend dvb-demux debugfs with TSPP statistics. */
+	mpq_dmx_init_hw_statistics(mpq_demux);
+
+	return 0;
+
+init_failed_dmx_release:
+	dvb_dmx_release(&mpq_demux->demux);
+init_failed:
+	return result;
+}
+
+static int __init mpq_dmx_tspp_plugin_init(void)
+{
+	int i;
+	int j;
+	int ret;
+
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	for (i = 0; i < TSIF_COUNT; i++) {
+		mpq_dmx_tspp_info.tsif[i].pes_channel_ref = 0;
+
+		mpq_dmx_tspp_info.tsif[i].pes_work.channel_id =
+			TSPP_CHANNEL_ID(i, TSPP_PES_CHANNEL);
+
+		INIT_WORK(&mpq_dmx_tspp_info.tsif[i].pes_work.work,
+				  mpq_dmx_tspp_work);
+
+		mpq_dmx_tspp_info.tsif[i].section_channel_ref = 0;
+
+		mpq_dmx_tspp_info.tsif[i].section_work.channel_id =
+			TSPP_CHANNEL_ID(i, TSPP_SECTION_CHANNEL);
+
+		INIT_WORK(&mpq_dmx_tspp_info.tsif[i].section_work.work,
+				  mpq_dmx_tspp_work);
+
+		for (j = 0; j < TSPP_FILTERS_COUNT; j++) {
+			mpq_dmx_tspp_info.tsif[i].filters[j].pid = -1;
+			mpq_dmx_tspp_info.tsif[i].filters[j].ref_count = 0;
+		}
+
+		snprintf(mpq_dmx_tspp_info.tsif[i].name,
+				TSIF_NAME_LENGTH,
+				"tsif_%d",
+				i);
+
+		mpq_dmx_tspp_info.tsif[i].workqueue =
+			create_singlethread_workqueue(
+				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__);
+
+			return -ENOMEM;
+		}
+
+		mutex_init(&mpq_dmx_tspp_info.tsif[i].mutex);
+	}
+
+	ret = mpq_dmx_plugin_init(mpq_tspp_dmx_init);
+
+	if (ret < 0) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_dmx_plugin_init failed (errno=%d)\n",
+			__func__,
+			ret);
+
+		for (i = 0; i < TSIF_COUNT; i++) {
+			destroy_workqueue(mpq_dmx_tspp_info.tsif[i].workqueue);
+			mutex_destroy(&mpq_dmx_tspp_info.tsif[i].mutex);
+		}
+	}
+
+	return ret;
+}
+
+static void __exit mpq_dmx_tspp_plugin_exit(void)
+{
+	int i;
+
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	for (i = 0; i < TSIF_COUNT; i++) {
+		mutex_lock(&mpq_dmx_tspp_info.tsif[i].mutex);
+
+		if (mpq_dmx_tspp_info.tsif[i].pes_channel_ref) {
+			tspp_unregister_notification(0, TSPP_PES_CHANNEL);
+			tspp_close_channel(0,
+				TSPP_CHANNEL_ID(i, TSPP_PES_CHANNEL));
+		}
+
+		if (mpq_dmx_tspp_info.tsif[i].section_channel_ref) {
+			tspp_unregister_notification(0, TSPP_SECTION_CHANNEL);
+			tspp_close_channel(0,
+				TSPP_CHANNEL_ID(i, TSPP_SECTION_CHANNEL));
+		}
+
+		/* TODO: if we allocate buffer
+		 * to TSPP ourself, need to free those as well
+		 */
+
+		mutex_unlock(&mpq_dmx_tspp_info.tsif[i].mutex);
+		flush_workqueue(mpq_dmx_tspp_info.tsif[i].workqueue);
+		destroy_workqueue(mpq_dmx_tspp_info.tsif[i].workqueue);
+		mutex_destroy(&mpq_dmx_tspp_info.tsif[i].mutex);
+	}
+
+	mpq_dmx_plugin_exit();
+}
+
+
+module_init(mpq_dmx_tspp_plugin_init);
+module_exit(mpq_dmx_tspp_plugin_exit);
+
+MODULE_DESCRIPTION("Qualcomm demux TSPP version 1 HW Plugin");
+MODULE_LICENSE("GPL v2");
+
+
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c
new file mode 100644
index 0000000..d3c2c50
--- /dev/null
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c
@@ -0,0 +1,132 @@
+/* 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 "mpq_dvb_debug.h"
+#include "mpq_dmx_plugin_common.h"
+
+
+static int mpq_tspp_dmx_start_filtering(struct dvb_demux_feed *feed)
+{
+	MPQ_DVB_DBG_PRINT(
+		"%s(%d) executed\n",
+		__func__,
+		feed->pid);
+
+	/* Always feed sections/PES starting from a new one and
+	 * do not partial transfer data from older one
+	 */
+	feed->pusi_seen = 0;
+	return 0;
+}
+
+static int mpq_tspp_dmx_stop_filtering(struct dvb_demux_feed *feed)
+{
+	MPQ_DVB_DBG_PRINT(
+		"%s(%d) executed\n",
+		__func__,
+		feed->pid);
+
+	return 0;
+}
+
+/**
+ * Initialize a single demux device.
+ *
+ * @mpq_adapter: MPQ DVB adapter
+ * @mpq_demux: The demux device to initialize
+ *
+ * Return     error code
+ */
+static int mpq_tspp_dmx_init(
+				struct dvb_adapter *mpq_adapter,
+				struct mpq_demux *mpq_demux)
+{
+	int result;
+
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	/* 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_CRC_CHECKING			|
+		DMX_TS_DESCRAMBLING;
+
+	/* Set dvb-demux "virtual" function pointers */
+	mpq_demux->demux.priv = (void *)mpq_demux;
+	mpq_demux->demux.filternum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+	mpq_demux->demux.feednum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+	mpq_demux->demux.start_feed = mpq_tspp_dmx_start_filtering;
+	mpq_demux->demux.stop_feed = mpq_tspp_dmx_stop_filtering;
+	mpq_demux->demux.write_to_decoder = NULL;
+	mpq_demux->demux.decoder_fullness_init = NULL;
+	mpq_demux->demux.decoder_fullness_wait = NULL;
+	mpq_demux->demux.decoder_fullness_abort = NULL;
+
+	/* Initialize dvb_demux object */
+	result = dvb_dmx_init(&mpq_demux->demux);
+	if (result < 0) {
+		MPQ_ERR_PRINT("%s: dvb_dmx_init failed\n", __func__);
+		goto init_failed;
+	}
+
+	/* Now initailize the dmx-dev object */
+	mpq_demux->dmxdev.filternum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+	mpq_demux->dmxdev.demux = &mpq_demux->demux.dmx;
+	mpq_demux->dmxdev.capabilities =
+		DMXDEV_CAP_DUPLEX |
+		DMXDEV_CAP_PULL_MODE |
+		DMXDEV_CAP_PCR_EXTRACTION;
+
+	mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
+
+	result = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter);
+	if (result < 0) {
+		MPQ_DVB_ERR_PRINT("%s: dvb_dmxdev_init failed (errno=%d)\n",
+						  __func__,
+						  result);
+
+		goto init_failed_dmx_release;
+	}
+
+	return 0;
+
+init_failed_dmx_release:
+	dvb_dmx_release(&mpq_demux->demux);
+init_failed:
+	return result;
+}
+
+static int __init mpq_dmx_tspp_plugin_init(void)
+{
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+	return mpq_dmx_plugin_init(mpq_tspp_dmx_init);
+}
+
+static void __exit mpq_dmx_tspp_plugin_exit(void)
+{
+	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+	mpq_dmx_plugin_exit();
+}
+
+
+module_init(mpq_dmx_tspp_plugin_init);
+module_exit(mpq_dmx_tspp_plugin_exit);
+
+MODULE_DESCRIPTION("Qualcomm demux TSPP version2 HW Plugin");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/media/dvb/mpq/include/mpq_adapter.h b/drivers/media/dvb/mpq/include/mpq_adapter.h
new file mode 100644
index 0000000..c720f91
--- /dev/null
+++ b/drivers/media/dvb/mpq/include/mpq_adapter.h
@@ -0,0 +1,146 @@
+/* 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.
+ */
+
+#ifndef _MPQ_ADAPTER_H
+#define _MPQ_ADAPTER_H
+
+#include "dvbdev.h"
+#include "mpq_stream_buffer.h"
+
+
+
+/** IDs of interfaces holding stream-buffers */
+enum mpq_adapter_stream_if {
+	/** Interface holding stream-buffer for video0 stream */
+	MPQ_ADAPTER_VIDEO0_STREAM_IF = 0,
+
+	/** Interface holding stream-buffer for video1 stream */
+	MPQ_ADAPTER_VIDEO1_STREAM_IF = 1,
+
+	/** Interface holding stream-buffer for video1 stream */
+	MPQ_ADAPTER_VIDEO2_STREAM_IF = 2,
+
+	/** Interface holding stream-buffer for video1 stream */
+	MPQ_ADAPTER_VIDEO3_STREAM_IF = 3,
+
+	/** Maximum number of interfaces holding stream-buffers */
+	MPQ_ADAPTER_MAX_NUM_OF_INTERFACES,
+};
+
+
+/** The meta-data used for video interface */
+struct mpq_adapter_video_meta_data {
+	/**
+	 * Indication whether this packet is just a padding packet.
+	 * In this case packet should be just disposed along
+	 * with the padding in the raw-data buffer.
+	 */
+	int is_padding;
+
+	/** Indication whether PTS exist */
+	int pts_exist;
+
+	/** Indication whether DTS exist */
+	int dts_exist;
+
+	/** PTS value associated with the PES data if any */
+	u64 pts;
+
+	/** DTS value associated with the PES data if any */
+	u64 dts;
+} __packed;
+
+
+/** Callback function to notify on registrations of specific interfaces */
+typedef void (*mpq_adapter_stream_if_callback)(
+				enum mpq_adapter_stream_if interface_id,
+				void *user_param);
+
+
+/**
+ * mpq_adapter_get - Returns pointer to Qualcomm DVB adapter
+ *
+ * Return     dvb adapter or NULL if not exist.
+ */
+struct dvb_adapter *mpq_adapter_get(void);
+
+
+/**
+ * mpq_adapter_register_stream_if - Register a stream interface.
+ *
+ * @interface_id: The interface id
+ * @stream_buffer: The buffer used for the interface
+ *
+ * Return     error status
+ *
+ * Stream interface used to connect between two units in tunneling
+ * mode using mpq_streambuffer implementation.
+ * The producer of the interface should register the new interface,
+ * consumer may get the interface using mpq_adapter_get_stream_if.
+ *
+ * Note that the function holds a pointer to this interface,
+ * stream_buffer pointer assumed to be valid as long as interface
+ * is active.
+ */
+int mpq_adapter_register_stream_if(
+		enum mpq_adapter_stream_if interface_id,
+		struct mpq_streambuffer *stream_buffer);
+
+
+/**
+ * mpq_adapter_unregister_stream_if - Un-register a stream interface.
+ *
+ * @interface_id: The interface id
+ *
+ * Return     error status
+ */
+int mpq_adapter_unregister_stream_if(
+		enum mpq_adapter_stream_if interface_id);
+
+
+/**
+ * mpq_adapter_get_stream_if - Get buffer used for a stream interface.
+ *
+ * @interface_id: The interface id
+ * @stream_buffer: The returned stream buffer
+ *
+ * Return     error status
+ */
+int mpq_adapter_get_stream_if(
+		enum mpq_adapter_stream_if interface_id,
+		struct mpq_streambuffer **stream_buffer);
+
+
+/**
+ * mpq_adapter_notify_stream_if - Register notification
+ * to be triggered when a stream interface is registered.
+ *
+ * @interface_id: The interface id
+ * @callback: The callback to be triggered when the interface is registered
+ * @user_param: A parameter that is passed back to the callback function
+ *				when triggered.
+ *
+ * Return     error status
+ *
+ * Producer may use this to register notification when desired
+ * interface registered in the system and query its information
+ * afterwards using mpq_adapter_get_stream_if.
+ * To remove the callback, this function should be called with NULL
+ * value in callback parameter.
+ */
+int mpq_adapter_notify_stream_if(
+		enum mpq_adapter_stream_if interface_id,
+		mpq_adapter_stream_if_callback callback,
+		void *user_param);
+
+#endif /* _MPQ_ADAPTER_H */
+
diff --git a/drivers/media/dvb/mpq/include/mpq_dvb_debug.h b/drivers/media/dvb/mpq/include/mpq_dvb_debug.h
new file mode 100644
index 0000000..4890b85
--- /dev/null
+++ b/drivers/media/dvb/mpq/include/mpq_dvb_debug.h
@@ -0,0 +1,38 @@
+/* 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.
+ */
+
+#ifndef _MPQ_DVB_DEBUG_H
+#define _MPQ_DVB_DEBUG_H
+
+/* Enable this line if you want to output debug printouts */
+#define MPG_DVB_DEBUG_ENABLE
+
+#undef MPQ_DVB_DBG_PRINT		/* undef it, just in case */
+
+#ifdef MPG_DVB_DEBUG_ENABLE
+#define MPQ_DVB_DBG_PRINT(fmt, args...) pr_debug(fmt, ## args)
+#define MPQ_DVB_ERR_PRINT(fmt, args...) pr_err(fmt, ## args)
+#else  /* MPG_DVB_DEBUG_ENABLE */
+#define MPQ_DVB_DBG_PRINT(fmt, args...)
+#define MPQ_DVB_ERR_PRINT(fmt, args...)
+#endif /* MPG_DVB_DEBUG_ENABLE */
+
+
+/*
+ * The following can be used to disable specific printout
+ * by adding a letter to the end of MPQ_DVB_DBG_PRINT
+ */
+#undef MPQ_DVB_DBG_PRINTT
+#define MPQ_DVB_DBG_PRINTT(fmt, args...)
+
+#endif /* _MPQ_DVB_DEBUG_H */
+
diff --git a/drivers/media/dvb/mpq/include/mpq_stream_buffer.h b/drivers/media/dvb/mpq/include/mpq_stream_buffer.h
new file mode 100644
index 0000000..4ea4222
--- /dev/null
+++ b/drivers/media/dvb/mpq/include/mpq_stream_buffer.h
@@ -0,0 +1,269 @@
+/* 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.
+ */
+
+#ifndef _MPQ_STREAM_BUFFER_H
+#define _MPQ_STREAM_BUFFER_H
+
+#include "dvb_ringbuffer.h"
+
+
+/**
+ * DOC: MPQ Stream Buffer
+ *
+ * A stream buffer implmenetation used to transfer data between two units
+ * such as demux and decoders. The implementation relies on dvb_ringbuffer
+ * implementation. Refer to dvb_ringbuffer.h for details.
+ *
+ * The implementation uses two dvb_ringbuffers, one to pass the
+ * raw-data (PES payload for example) and the other to pass
+ * meta-data (information from PES header for example).
+ *
+ * The meta-data uses dvb_ringbuffer packet interface. Each meta-data
+ * packet hold the address and size of raw-data described by the
+ * meta-data packet, in addition to user's own parameters if any required.
+ *
+ * Contrary to dvb_ringbuffer implementation, this API makes sure there's
+ * enough data to read/write when making read/write operations.
+ * Users interested to flush/reset specific buffer, check for bytes
+ * ready or space available for write should use the respective services
+ * in dvb_ringbuffer (dvb_ringbuffer_avail, dvb_ringbuffer_free,
+ * dvb_ringbuffer_reset, dvb_ringbuffer_flush,
+ * dvb_ringbuffer_flush_spinlock_wakeup).
+ *
+ * Concurrency protection is handled in the same manner as in
+ * dvb_ringbuffer implementation.
+ *
+ * Typical call flow from producer:
+ *
+ * - Start writting the raw-data of new packet, the following call is
+ *   repeated until end of data of the specific packet
+ *
+ *     mpq_streambuffer_data_write(...)
+ *
+ * - Now write a new packet describing the new available raw-data
+ *     mpq_streambuffer_pkt_write(...)
+ *
+ * Typical call flow from consumer:
+ *
+ * - Poll for next available packet:
+ *      mpq_streambuffer_pkt_next(&streambuff,-1)
+ *
+ *   In different approach, consumer can wait on event for new data and then
+ *   call mpq_streambuffer_pkt_next, waiting for data can be done as follows:
+ *
+ *      wait_event_interruptible(
+ *			streambuff->packet_data->queue,
+ *			!dvb_ringbuffer_empty(&streambuff->packet_data) ||
+ *			(streambuff->packet_data.error != 0);
+ *
+ * - Get the new packet information:
+ *      mpq_streambuffer_pkt_read(..)
+ *
+ * - Read the raw-data of the new packet. Here you can use two methods:
+ *
+ *   1. Read the data to a user supplied buffer:
+ *         mpq_streambuffer_data_read()
+ *
+ *      In this case memory copy is done, read pointer is updated in the raw
+ *      data buffer, the amount of raw-data is provided part of the
+ *      packet's information. User should then call mpq_streambuffer_pkt_dispose
+ *      with dispose_data set to 0 as the raw-data was already disposed.
+ *
+ *   2. Access the data directly using the raw-data address. The address
+ *      of the raw data is provided part of the packet's information. User
+ *      then should call mpq_streambuffer_pkt_dispose with dispose_data set
+ *      to 1 to dispose the packet along with it's raw-data.
+ */
+
+/**
+ * struct mpq_streambuffer - mpq stream buffer representation
+ *
+ * @raw_data: The buffer used to hold the raw-data
+ * @packet_data: The buffer user to hold the meta-data
+ */
+struct mpq_streambuffer {
+	struct dvb_ringbuffer raw_data;
+	struct dvb_ringbuffer packet_data;
+};
+
+/**
+ * struct mpq_streambuffer_packet_header - packet header saved in packet buffer
+ * @user_data_len: length of private user (meta) data
+ * @raw_data_addr: raw-data address in the raw-buffer described by the packet
+ * @raw_data_len: size of raw-data in the raw-data buffer (can be 0)
+ *
+ * The packet structure that is saved in each packet-buffer:
+ * user_data_len
+ * raw_data_addr
+ * raw_data_len
+ * private user-data bytes
+ */
+struct mpq_streambuffer_packet_header {
+	u32 user_data_len;
+	u32	raw_data_addr;
+	u32	raw_data_len;
+} __packed;
+
+/**
+ * mpq_streambuffer_init - Initialize a new stream buffer
+ *
+ * @sbuff: The buffer to initialize
+ * @data_buff: The buffer holding raw-data
+ * @data_buff_len: Size of raw-data buffer
+ * @packet_buff: The buffer holding meta-data
+ * @packet_buff_size: Size of meta-data buffer
+ */
+void mpq_streambuffer_init(
+		struct mpq_streambuffer *sbuff,
+		void *data_buff, size_t data_buff_len,
+		void *packet_buff, size_t packet_buff_size);
+
+/**
+ * mpq_streambuffer_packet_next - Returns index of next avaialble packet.
+ *
+ * @sbuff: The stream buffer
+ * @idx: Previous packet index or -1 to return index of the the first
+ *       available packet.
+ * @pktlen: The length of the ready packet
+ *
+ * Return index to the packet-buffer, -1 if buffer is empty
+ *
+ * After getting the index, the user of this function can either
+ * access the packet buffer directly using the returned index
+ * or ask to read the data back from the buffer using mpq_ringbuffer_pkt_read
+ */
+ssize_t mpq_streambuffer_pkt_next(
+		struct mpq_streambuffer *sbuff,
+		ssize_t idx, size_t *pktlen);
+
+/**
+ * mpq_streambuffer_pkt_read - Reads out the packet from the provided index.
+ *
+ * @sbuff: The stream buffer
+ * @idx: The index of the packet to be read
+ * @packet: The read packet's header
+ * @user_data: The read private user data
+ *
+ * Return  The actual number of bytes read, -EINVAL if the packet is
+ * already disposed or the packet-data is invalid.
+ *
+ * The packet is not disposed after this function is called, to dispose it
+ * along with the raw-data it points to use mpq_streambuffer_pkt_dispose.
+ * If there are no private user-data, the user-data pointer can be NULL.
+ * The caller of this function must make sure that the private user-data
+ * buffer has enough space for the private user-data length
+ */
+ssize_t mpq_streambuffer_pkt_read(
+		struct mpq_streambuffer *sbuff,
+		size_t idx,
+		struct mpq_streambuffer_packet_header *packet,
+		u8 *user_data);
+
+/**
+ * mpq_streambuffer_pkt_dispose - Disposes a packet from the packet buffer
+ *
+ * @sbuff: The stream buffer
+ * @idx: The index of the packet to be disposed
+ * @dispose_data: Indicates whether to update the read pointer inside the
+ * raw-data buffer for the respective data pointed by the packet.
+ *
+ * Return  error status, -EINVAL if the packet-data is invalid
+ *
+ * The function updates the read pointer inside the raw-data buffer
+ * for the respective data pointed by the packet if dispose_data is set.
+ */
+int mpq_streambuffer_pkt_dispose(
+		struct mpq_streambuffer *sbuff,
+		size_t idx,
+		int dispose_data);
+
+/**
+ * mpq_streambuffer_pkt_write - Write a new packet to the packet buffer.
+ *
+ * @sbuff: The stream buffer
+ * @packet: The packet header to write
+ * @user_data: The private user-data to be written
+ *
+ * Return  error status, -ENOSPC if there's no space to write the packet
+ */
+int mpq_streambuffer_pkt_write(
+		struct mpq_streambuffer *sbuff,
+		struct mpq_streambuffer_packet_header *packet,
+		u8 *user_data);
+
+/**
+ * mpq_streambuffer_data_write - Write data to raw-data buffer
+ *
+ * @sbuff: The stream buffer
+ * @buf: The buffer holding the data to be written
+ * @len: The length of the data buffer
+ *
+ * Return  The actual number of bytes written or -ENOSPC if
+ *			no space to write the data
+ */
+ssize_t mpq_streambuffer_data_write(
+		struct mpq_streambuffer *sbuff,
+		const u8 *buf, size_t len);
+
+/**
+ * mpq_streambuffer_data_write_deposit - Advances the raw-buffer write pointer.
+ * Assumes the raw-data was written by the user directly
+ *
+ * @sbuff: The stream buffer
+ * @len: The length of the raw-data that was already written
+ *
+ * Return  error status
+ */
+int mpq_streambuffer_data_write_deposit(
+		struct mpq_streambuffer *sbuff,
+		size_t len);
+
+/**
+ * mpq_streambuffer_data_read - Reads out raw-data to the provided buffer.
+ *
+ * @sbuff: The stream buffer
+ * @buf: The buffer to read the raw-data data to
+ * @len: The length of the buffer that will hold the raw-data
+ *
+ * Return  The actual number of bytes read
+ *
+ * This fucntion copies the data from the ring-buffer to the
+ * provided buf parameter. The user can save the extra copy by accessing
+ * the data pointer directly and reading from it, then update the
+ * read pointer by the amount of data that was read using
+ * mpq_streambuffer_data_read_dispose
+ */
+size_t mpq_streambuffer_data_read(
+		struct mpq_streambuffer *sbuff,
+		u8 *buf, size_t len);
+
+/**
+ * mpq_streambuffer_data_read_dispose - Advances the raw-buffer read pointer.
+ * Assumes the raw-data was read by the user directly.
+ *
+ * @sbuff: The stream buffer
+ * @len: The length of the raw-data to be disposed
+ *
+ * Return  error status, -EINVAL if buffer there's no enough data to
+ *			be disposed
+ *
+ * The user can instead dipose a packet along with the data in the
+ * raw-data buffer using mpq_streambuffer_pkt_dispose.
+ */
+int mpq_streambuffer_data_read_dispose(
+		struct mpq_streambuffer *sbuff,
+		size_t len);
+
+
+
+#endif /* _MPQ_STREAM_BUFFER_H */
+
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index a276e84..fd72638 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -963,7 +963,8 @@
 
 	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
 		HCI_OCF_FM_DEFAULT_DATA_WRITE);
-	return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_wr)),
+
+	return radio_hci_send_cmd(hdev, opcode, (def_data_wr->length+2),
 	def_data_wr);
 }
 
@@ -2470,7 +2471,7 @@
 			radio->fm_hdev);
 	if (retval < 0)
 		FMDERR("Disable Failed after calibration %d", retval);
-		return retval;
+	return retval;
 }
 static int iris_vidioc_g_ctrl(struct file *file, void *priv,
 		struct v4l2_control *ctrl)
@@ -2726,10 +2727,44 @@
 	case V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT:
 		data = (ctrl->controls[0]).string;
 		memset(&default_data, 0, sizeof(default_data));
-		if (copy_from_user(&default_data, data, sizeof(default_data)))
+		/*
+		 * Check if length of the 'FM Default Data' to be sent
+		 * is within the maximum  'FM Default Data' packet limit.
+		 * Max. 'FM Default Data' packet length is 251 bytes:
+		 *	1 byte    - XFR Mode
+		 *	1 byte    - length of the default data
+		 *	249 bytes - actual data to be configured
+		 */
+		if (ctrl->controls[0].size > (DEFAULT_DATA_SIZE + 2)) {
+			pr_err("%s: Default data buffer overflow!\n", __func__);
+			return -EINVAL;
+		}
+
+		/* copy only 'size' bytes of data as requested by user */
+		retval = copy_from_user(&default_data, data,
+			ctrl->controls[0].size);
+		if (retval > 0) {
+			pr_err("%s: Failed to copy %d bytes of default data"
+				" passed by user\n", __func__, retval);
 			return -EFAULT;
+		}
+		FMDBG("%s: XFR Mode\t: 0x%x\n", __func__, default_data.mode);
+		FMDBG("%s: XFR Data Length\t: %d\n", __func__,
+			default_data.length);
+		/*
+		 * Check if the 'length' of the actual XFR data to be configured
+		 * is valid or not. Length of actual XFR data should be always
+		 * 2 bytes less than the total length of the 'FM Default Data'.
+		 * Length of 'FM Default Data' DEF_DATA_LEN: (1+1+XFR Data Size)
+		 * Length of 'Actual XFR Data' XFR_DATA_LEN: (DEF_DATA_LEN - 2)
+		 */
+		if (default_data.length != (ctrl->controls[0].size - 2)) {
+			pr_err("%s: Invalid 'length' parameter passed for "
+				"actual xfr data\n", __func__);
+			return -EINVAL;
+		}
 		retval = hci_def_data_write(&default_data, radio->fm_hdev);
-			break;
+		break;
 	case V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION:
 		data = (ctrl->controls[0]).string;
 		bytes_to_copy = (ctrl->controls[0]).size;
@@ -3377,7 +3412,12 @@
 					struct v4l2_hw_freq_seek *seek)
 {
 	struct iris_device *radio = video_get_drvdata(video_devdata(file));
-	return iris_search(radio, CTRL_ON, seek->seek_upward);
+	int dir;
+	if (seek->seek_upward)
+		dir = SRCH_DIR_UP;
+	else
+		dir = SRCH_DIR_DOWN;
+	return iris_search(radio, CTRL_ON, dir);
 }
 
 static int iris_vidioc_querycap(struct file *file, void *priv,
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index acf551e..c15609f 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -3561,14 +3561,21 @@
 {
 
 	struct tavarua_device  *radio = video_get_drvdata(video_devdata(file));
-	enum tavarua_buf_t buf_type = buffer->index;
-	struct kfifo *data_fifo;
-	unsigned char *buf = (unsigned char *)buffer->m.userptr;
-	unsigned int len = buffer->length;
+	enum tavarua_buf_t buf_type = -1;
+	unsigned char buf_fifo[STD_BUF_SIZE] = {0};
+	struct kfifo *data_fifo = NULL;
+	unsigned char *buf = NULL;
+	unsigned int len = 0, retval = -1;
+
+	if ((radio == NULL) || (buffer == NULL)) {
+		FMDERR("radio/buffer is NULL\n");
+		return -ENXIO;
+	}
+	buf_type = buffer->index;
+	buf = (unsigned char *)buffer->m.userptr;
+	len = buffer->length;
 	FMDBG("%s: requesting buffer %d\n", __func__, buf_type);
-	/* check if we can access the user buffer */
-	if (!access_ok(VERIFY_WRITE, buf, len))
-		return -EFAULT;
+
 	if ((buf_type < TAVARUA_BUF_MAX) && (buf_type >= 0)) {
 		data_fifo = &radio->data_buf[buf_type];
 		if (buf_type == TAVARUA_BUF_EVENTS) {
@@ -3581,10 +3588,20 @@
 		FMDERR("invalid buffer type\n");
 		return -EINVAL;
 	}
-	buffer->bytesused = kfifo_out_locked(data_fifo, buf, len,
-					&radio->buf_lock[buf_type]);
+	if (len <= STD_BUF_SIZE) {
+		buffer->bytesused = kfifo_out_locked(data_fifo, &buf_fifo[0],
+					len, &radio->buf_lock[buf_type]);
+	} else {
+		FMDERR("kfifo_out_locked can not use len more than 128\n");
+		return -EINVAL;
+	}
+	retval = copy_to_user(buf, &buf_fifo[0], buffer->bytesused);
+	if (retval > 0) {
+		FMDERR("Failed to copy %d bytes of data\n", retval);
+		return -EAGAIN;
+	}
 
-	return 0;
+	return retval;
 }
 
 /*=============================================================================
@@ -3633,8 +3650,13 @@
 					struct v4l2_hw_freq_seek *seek)
 {
 	struct tavarua_device  *radio = video_get_drvdata(video_devdata(file));
+	int dir;
+	if (seek->seek_upward)
+		dir = SRCH_DIR_UP;
+	else
+		dir = SRCH_DIR_DOWN;
 	FMDBG("starting search\n");
-	return tavarua_search(radio, CTRL_ON, seek->seek_upward);
+	return tavarua_search(radio, CTRL_ON, dir);
 }
 
 /*
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 5508c3d..c07bdc4 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -24,6 +24,17 @@
 	   LIRC daemon handles protocol decoding for IR reception and
 	   encoding for IR transmitting (aka "blasting").
 
+config USER_RC_INPUT
+	tristate "User Space Input device wrapper for Remote Control"
+	depends on RC_CORE
+
+	---help---
+	   Say Y if you want to report remote control input events
+	   from userspace.
+
+	   To compile this driver as a module, choose M here: the module will
+	   be called user-rc-input.
+
 source "drivers/media/rc/keymaps/Kconfig"
 
 config IR_NEC_DECODER
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index 523fcd0..b9c1e21 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -11,6 +11,7 @@
 obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
 obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
 obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
+obj-$(CONFIG_USER_RC_INPUT) += user-rc-input.o
 
 # stand-alone IR receivers/transmitters
 obj-$(CONFIG_IR_IMON) += imon.o
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 6d8cc5c..3416c91 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -87,7 +87,7 @@
 	rcdev->input_name = GPIO_IR_DEVICE_NAME;
 	rcdev->input_id.bustype = BUS_HOST;
 	rcdev->driver_name = GPIO_IR_DRIVER_NAME;
-	rcdev->map_name = RC_MAP_RC6_PHILIPS;
+	rcdev->map_name = RC_MAP_SAMSUNG_NECX;
 
 	gpio_dev->rcdev = rcdev;
 	gpio_dev->gpio_nr = pdata->gpio_nr;
@@ -115,7 +115,7 @@
 	if (rc < 0)
 		goto err_request_irq;
 
-	device_init_wakeup(pdata->can_wakeup);
+	device_init_wakeup(&pdev->dev, pdata->can_wakeup);
 
 	return 0;
 
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 198298b..17aed88 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -84,6 +84,7 @@
 			rc-trekstor.o \
 			rc-tt-1500.o \
 			rc-twinhan1027.o \
+			rc-ue-rf4ce.o \
 			rc-videomate-m1f.o \
 			rc-videomate-s350.o \
 			rc-videomate-tv-pvr.o \
diff --git a/drivers/media/rc/keymaps/rc-ue-rf4ce.c b/drivers/media/rc/keymaps/rc-ue-rf4ce.c
new file mode 100644
index 0000000..af40976
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-ue-rf4ce.c
@@ -0,0 +1,82 @@
+/* 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 <media/rc-map.h>
+
+static struct rc_map_table ue_rf4ce[] = {
+	{ 0x0a, KEY_SETUP },
+	{ 0x6b, KEY_POWER },
+	{ 0x00, KEY_OK },
+	{ 0x03, KEY_LEFT },
+	{ 0x04, KEY_RIGHT },
+	{ 0x01, KEY_UP },
+	{ 0x02, KEY_DOWN },
+	{ 0x53, KEY_HOMEPAGE },
+	{ 0x0d, KEY_EXIT },
+	{ 0x72, KEY_TV },
+	{ 0x73, KEY_VIDEO },
+	{ 0x74, KEY_COMPOSE },
+	{ 0x71, KEY_AUX },
+	{ 0x45, KEY_STOP },
+	{ 0x0b, KEY_LIST },
+	{ 0x47, KEY_RECORD },
+	{ 0x48, KEY_REWIND },
+	{ 0x44, KEY_PLAY },
+	{ 0x49, KEY_FASTFORWARD },
+	{ 0x4c, KEY_BACK },
+	{ 0x46, KEY_PAUSE },
+	{ 0x4b, KEY_NEXT },
+	{ 0x41, KEY_VOLUMEUP },
+	{ 0x42, KEY_VOLUMEDOWN },
+	{ 0x32, KEY_LAST },
+	{ 0x43, KEY_MUTE },
+	{ 0x30, KEY_CHANNELUP },
+	{ 0x31, KEY_CHANNELDOWN },
+
+	{ 0x20, KEY_NUMERIC_0 },
+	{ 0x21, KEY_NUMERIC_1 },
+	{ 0x22, KEY_NUMERIC_2 },
+	{ 0x23, KEY_NUMERIC_3 },
+	{ 0x24, KEY_NUMERIC_4 },
+	{ 0x25, KEY_NUMERIC_5 },
+	{ 0x26, KEY_NUMERIC_6 },
+	{ 0x27, KEY_NUMERIC_7 },
+	{ 0x28, KEY_NUMERIC_8 },
+	{ 0x29, KEY_NUMERIC_9 },
+	{ 0x34, KEY_INSERT },
+	{ 0x2b, KEY_ENTER },
+};
+
+static struct rc_map_list ue_rf4ce_map = {
+	.map = {
+		.scan    = ue_rf4ce,
+		.size    = ARRAY_SIZE(ue_rf4ce),
+		.rc_type = RC_TYPE_OTHER,
+		.name    = RC_MAP_UE_RF4CE,
+	}
+};
+
+static int __init init_rc_map_ue_rf4ce(void)
+{
+	return rc_map_register(&ue_rf4ce_map);
+}
+
+static void __exit exit_rc_map_ue_rf4ce(void)
+{
+	rc_map_unregister(&ue_rf4ce_map);
+}
+
+module_init(init_rc_map_ue_rf4ce)
+module_exit(exit_rc_map_ue_rf4ce)
+
+MODULE_DESCRIPTION("UE RF4CE Remote Keymap ");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/rc/user-rc-input.c b/drivers/media/rc/user-rc-input.c
new file mode 100644
index 0000000..f1a9334
--- /dev/null
+++ b/drivers/media/rc/user-rc-input.c
@@ -0,0 +1,251 @@
+/* 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/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+
+#include <media/rc-core.h>
+#include <media/user-rc-input.h>
+
+#define MAX_RC_DEVICES		1
+#define USER_RC_INPUT_DEV_NAME	"user-rc-input"
+#define USER_RC_INPUT_DRV_NAME	"rc-user-input"
+
+struct user_rc_input_dev {
+	struct cdev rc_input_cdev;
+	struct class *rc_input_class;
+	struct device *rc_input_dev;
+	struct rc_dev *rcdev;
+	dev_t rc_input_base_dev;
+	struct device *dev;
+	int in_use;
+};
+
+static int user_rc_input_open(struct inode *inode, struct file *file)
+{
+	struct cdev *input_cdev	= inode->i_cdev;
+	struct user_rc_input_dev *input_dev =
+	container_of(input_cdev, struct user_rc_input_dev, rc_input_cdev);
+
+	if (input_dev->in_use) {
+		dev_err(input_dev->dev,
+		"Device is already open..only one instance is allowed\n");
+		return -EBUSY;
+	}
+	input_dev->in_use++;
+	file->private_data = input_dev;
+
+	return 0;
+}
+
+static int user_rc_input_release(struct inode *inode, struct file *file)
+{
+	struct user_rc_input_dev *input_dev = file->private_data;
+
+	input_dev->in_use--;
+
+	return 0;
+}
+
+static ssize_t user_rc_input_write(struct file *file, const char __user *buffer,
+						size_t count, loff_t *ppos)
+{
+	int ret;
+	struct user_rc_input_dev *input_dev = file->private_data;
+	__u8 *buf;
+
+	buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
+	if (!buf) {
+		dev_err(input_dev->dev,
+			"kmalloc failed...Insufficient memory\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (copy_from_user(buf, buffer, count)) {
+		dev_err(input_dev->dev, "Copy from user failed\n");
+		ret = -EFAULT;
+		goto out_free;
+	}
+
+	switch (buf[0])	{
+	case USER_CONTROL_PRESSED:
+		dev_dbg(input_dev->dev, "user controlled"
+					" pressed 0x%x\n", buf[1]);
+		rc_keydown(input_dev->rcdev, buf[1], 0);
+		break;
+	case USER_CONTROL_REPEATED:
+		dev_dbg(input_dev->dev, "user controlled"
+					" repeated 0x%x\n", buf[1]);
+		rc_repeat(input_dev->rcdev);
+		break;
+	case USER_CONTROL_RELEASED:
+		dev_dbg(input_dev->dev, "user controlled"
+					" released 0x%x\n", buf[1]);
+		rc_keyup(input_dev->rcdev);
+		break;
+	}
+
+out_free:
+	kfree(buf);
+out:
+	return ret;
+}
+
+const struct file_operations fops = {
+	.owner  = THIS_MODULE,
+	.open   = user_rc_input_open,
+	.write  = user_rc_input_write,
+	.release = user_rc_input_release,
+};
+
+static int __devinit user_rc_input_probe(struct platform_device *pdev)
+{
+	struct user_rc_input_dev *user_rc_dev;
+	struct rc_dev *rcdev;
+	int retval;
+
+	user_rc_dev = kzalloc(sizeof(struct user_rc_input_dev), GFP_KERNEL);
+	if (!user_rc_dev)
+		return -ENOMEM;
+
+	user_rc_dev->rc_input_class = class_create(THIS_MODULE,
+						"user-rc-input-loopback");
+
+	if (IS_ERR(user_rc_dev->rc_input_class)) {
+		retval = PTR_ERR(user_rc_dev->rc_input_class);
+		goto err;
+	}
+
+	retval = alloc_chrdev_region(&user_rc_dev->rc_input_base_dev, 0,
+				MAX_RC_DEVICES,	USER_RC_INPUT_DEV_NAME);
+
+	if (retval) {
+		dev_err(&pdev->dev,
+			"alloc_chrdev_region failed\n");
+		goto alloc_chrdev_err;
+	}
+
+	dev_info(&pdev->dev, "User space report key event input "
+					"loopback driver registered, "
+		"major %d\n", MAJOR(user_rc_dev->rc_input_base_dev));
+
+	cdev_init(&user_rc_dev->rc_input_cdev, &fops);
+	retval = cdev_add(&user_rc_dev->rc_input_cdev,
+				user_rc_dev->rc_input_base_dev,
+							MAX_RC_DEVICES);
+	if (retval) {
+		dev_err(&pdev->dev, "cdev_add failed\n");
+		goto cdev_add_err;
+	}
+	user_rc_dev->rc_input_dev =
+				device_create(user_rc_dev->rc_input_class,
+									NULL,
+				MKDEV(MAJOR(user_rc_dev->rc_input_base_dev),
+				0), NULL, "user-rc-input-dev%d", 0);
+
+	if (IS_ERR(user_rc_dev->rc_input_dev)) {
+		retval = PTR_ERR(user_rc_dev->rc_input_dev);
+		dev_err(&pdev->dev, "device_create failed\n");
+		goto device_create_err;
+	}
+
+	rcdev = rc_allocate_device();
+	if (!rcdev) {
+		dev_err(&pdev->dev, "failed to allocate rc device");
+		retval = -ENOMEM;
+		goto err_allocate_device;
+	}
+
+	rcdev->driver_type = RC_DRIVER_SCANCODE;
+	rcdev->allowed_protos = RC_TYPE_OTHER;
+	rcdev->input_name = USER_RC_INPUT_DEV_NAME;
+	rcdev->input_id.bustype = BUS_HOST;
+	rcdev->driver_name = USER_RC_INPUT_DRV_NAME;
+	rcdev->map_name = RC_MAP_UE_RF4CE;
+
+	retval = rc_register_device(rcdev);
+	if (retval < 0) {
+		dev_err(&pdev->dev, "failed to register rc device\n");
+		goto rc_register_err;
+	}
+	user_rc_dev->rcdev = rcdev;
+	user_rc_dev->dev = &pdev->dev;
+	platform_set_drvdata(pdev, user_rc_dev);
+	user_rc_dev->in_use = 0;
+
+	return 0;
+
+rc_register_err:
+	rc_free_device(rcdev);
+err_allocate_device:
+	device_destroy(user_rc_dev->rc_input_class,
+			MKDEV(MAJOR(user_rc_dev->rc_input_base_dev), 0));
+cdev_add_err:
+	unregister_chrdev_region(user_rc_dev->rc_input_base_dev,
+							MAX_RC_DEVICES);
+device_create_err:
+	cdev_del(&user_rc_dev->rc_input_cdev);
+alloc_chrdev_err:
+	class_destroy(user_rc_dev->rc_input_class);
+err:
+	kfree(user_rc_dev);
+	return retval;
+}
+
+static int __devexit user_rc_input_remove(struct platform_device *pdev)
+{
+	struct user_rc_input_dev *user_rc_dev = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	rc_free_device(user_rc_dev->rcdev);
+	device_destroy(user_rc_dev->rc_input_class,
+			MKDEV(MAJOR(user_rc_dev->rc_input_base_dev), 0));
+	unregister_chrdev_region(user_rc_dev->rc_input_base_dev,
+							MAX_RC_DEVICES);
+	cdev_del(&user_rc_dev->rc_input_cdev);
+	class_destroy(user_rc_dev->rc_input_class);
+	kfree(user_rc_dev);
+
+	return 0;
+}
+
+static struct platform_driver user_rc_input_driver = {
+	.probe  = user_rc_input_probe,
+	.remove = __devexit_p(user_rc_input_remove),
+	.driver = {
+		.name   = USER_RC_INPUT_DRV_NAME,
+		.owner  = THIS_MODULE,
+	},
+};
+
+static int __init user_rc_input_init(void)
+{
+	return platform_driver_register(&user_rc_input_driver);
+}
+module_init(user_rc_input_init);
+
+static void __exit user_rc_input_exit(void)
+{
+	platform_driver_unregister(&user_rc_input_driver);
+}
+module_exit(user_rc_input_exit);
+
+MODULE_DESCRIPTION("User RC Input driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 07a31a3..5aaef24 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -572,7 +572,7 @@
 config MSM_VCAP
 	tristate "Qualcomm MSM VCAP"
 	depends on VIDEO_DEV && VIDEO_V4L2
-	default n
+	default y
 	---help---
 		Enables VCAP driver. This device allows for video capture and
 		video processing using the v4l2 api
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index c00f4c6..fbc3a37 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -57,7 +57,7 @@
 	  Say Y here if this is msm7627A variant platform.
 config WEBCAM_OV7692_QRD
 	bool "Sensor OV7692 QRD(VGA YUV)"
-	depends on MSM_CAMERA && ARCH_MSM7X27A
+	depends on MSM_CAMERA && (ARCH_MSM7X27A || ARCH_MSM8X60)
 	default n
 	---help---
 	  Omni Vision VGA YUV Sensor for QRD Devices
@@ -211,6 +211,18 @@
 	bool "Qualcomm MSM actuator support"
 	depends on MSM_CAMERA
 
+config MSM_EEPROM
+	bool "Qualcomm MSM EEPROM support"
+	depends on MSM_CAMERA
+
+config IMX074_EEPROM
+	bool "IMX074 EEPROM support"
+	depends on MSM_CAMERA
+
+config IMX091_EEPROM
+	bool "IMX091 EEPROM support"
+	depends on MSM_CAMERA
+
 config MSM_GEMINI
 	tristate "Qualcomm MSM Gemini Jpeg Engine support"
 	depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM8960)
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 4fd6e49..ebfed6c 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -7,9 +7,12 @@
 obj-$(CONFIG_MSM_CAMERA) += io/
 ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
   EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
+  EXTRA_CFLAGS += -Idrivers/media/video/msm/io
+  EXTRA_CFLAGS += -Idrivers/media/video/msm/eeprom
   EXTRA_CFLAGS += -Idrivers/media/video/msm/sensors
+  EXTRA_CFLAGS += -Idrivers/media/video/msm/actuators
   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) += sensors/ actuators/ csi/
+  obj-$(CONFIG_MSM_CAMERA) += io/ eeprom/ sensors/ actuators/ csi/
 else
   obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
 endif
diff --git a/drivers/media/video/msm/actuators/msm_actuator.c b/drivers/media/video/msm/actuators/msm_actuator.c
index e16766c..e4d8368 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.c
+++ b/drivers/media/video/msm/actuators/msm_actuator.c
@@ -368,9 +368,8 @@
 	return rc;
 }
 
-int32_t msm_actuator_af_power_down(void *cfg_data)
+int32_t msm_actuator_power_down(struct msm_actuator_ctrl_t *a_ctrl)
 {
-	struct msm_actuator_ctrl_t *a_ctrl = &msm_actuator_t;
 	int32_t rc = 0;
 	int16_t step_pos = 0;
 	int16_t i = 0;
@@ -501,9 +500,9 @@
 }
 
 
-int32_t msm_actuator_config(void __user *argp)
+int32_t msm_actuator_config(struct msm_actuator_ctrl_t *a_ctrl,
+							void __user *argp)
 {
-	struct msm_actuator_ctrl_t *a_ctrl = &msm_actuator_t;
 	struct msm_actuator_cfg_data cdata;
 	int32_t rc = 0;
 	if (copy_from_user(&cdata,
@@ -554,13 +553,19 @@
 	}
 
 	act_ctrl_t = (struct msm_actuator_ctrl_t *)(id->driver_data);
-	i2c_set_clientdata(client, (void *)&act_ctrl_t->actuator_ext_ctrl);
-	CDBG("%s client = %x act ctrl t = %x\n",
-		__func__,
-		(unsigned int) client,
-		(unsigned int)&act_ctrl_t->actuator_ext_ctrl);
+	CDBG("%s client = %x\n",
+		__func__, (unsigned int) client);
 	act_ctrl_t->i2c_client.client = client;
 
+	/* Assign name for sub device */
+	snprintf(act_ctrl_t->sdev.name, sizeof(act_ctrl_t->sdev.name),
+			 "%s", act_ctrl_t->i2c_driver->driver.name);
+
+	/* Initialize sub device */
+	v4l2_i2c_subdev_init(&act_ctrl_t->sdev,
+		act_ctrl_t->i2c_client.client,
+		act_ctrl_t->act_v4l2_subdev_ops);
+
 	CDBG("%s succeeded\n", __func__);
 	return rc;
 
@@ -569,16 +574,11 @@
 	return rc;
 }
 
-int32_t msm_actuator_power_up(void *act_info)
+int32_t msm_actuator_power_up(struct msm_actuator_ctrl_t *a_ctrl)
 {
 	int rc = 0;
-	struct msm_actuator_ctrl_t *a_ctrl = &msm_actuator_t;
-	struct msm_actuator_info *ptr;
 	CDBG("%s called\n", __func__);
 
-	ptr = act_info;
-	a_ctrl->vcm_pwd = ptr->vcm_pwd;
-	a_ctrl->vcm_enable = ptr->vcm_enable;
 	CDBG("vcm info: %x %x\n", a_ctrl->vcm_pwd,
 		a_ctrl->vcm_enable);
 	if (a_ctrl->vcm_enable) {
@@ -591,31 +591,6 @@
 	return rc;
 }
 
-
-int32_t msm_actuator_create_subdevice(void *info, void *dev)
-{
-	struct msm_actuator_info *act_info = (struct msm_actuator_info *)info;
-	struct i2c_board_info const *board_info = act_info->board_info;
-	struct v4l2_subdev *sdev = (struct v4l2_subdev *)dev;
-	struct msm_actuator_ctrl_t *a_ctrl = &msm_actuator_t;
-	int32_t rc = -EFAULT;
-
-	CDBG("%s called\n", __func__);
-
-	/* Store the sub device in actuator structure */
-	a_ctrl->sdev = sdev;
-
-	/* Assign name for sub device */
-	snprintf(sdev->name, sizeof(sdev->name), "%s", board_info->type);
-
-	/* Initialize sub device */
-	v4l2_i2c_subdev_init(sdev,
-		a_ctrl->i2c_client.client,
-		a_ctrl->act_v4l2_subdev_ops);
-
-	return rc;
-}
-
 DEFINE_MUTEX(msm_actuator_mutex);
 
 static const struct i2c_device_id msm_actuator_i2c_id[] = {
@@ -639,7 +614,41 @@
 	return i2c_add_driver(msm_actuator_t.i2c_driver);
 }
 
-static struct v4l2_subdev_core_ops msm_actuator_subdev_core_ops;
+long msm_actuator_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	struct msm_actuator_ctrl_t *a_ctrl = get_actrl(sd);
+	void __user *argp = (void __user *)arg;
+	switch (cmd) {
+	case VIDIOC_MSM_ACTUATOR_CFG:
+		return msm_actuator_config(a_ctrl, argp);
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+int32_t msm_actuator_power(struct v4l2_subdev *sd, int on)
+{
+	int rc = 0;
+	struct msm_actuator_ctrl_t *a_ctrl = get_actrl(sd);
+	mutex_lock(a_ctrl->actuator_mutex);
+	if (on)
+		rc = msm_actuator_power_up(a_ctrl);
+	else
+		rc = msm_actuator_power_down(a_ctrl);
+	mutex_unlock(a_ctrl->actuator_mutex);
+	return rc;
+}
+
+struct msm_actuator_ctrl_t *get_actrl(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct msm_actuator_ctrl_t, sdev);
+}
+
+static struct v4l2_subdev_core_ops msm_actuator_subdev_core_ops = {
+	.ioctl = msm_actuator_subdev_ioctl,
+	.s_power = msm_actuator_power,
+};
 
 static struct v4l2_subdev_ops msm_actuator_subdev_ops = {
 	.core = &msm_actuator_subdev_core_ops,
@@ -648,12 +657,6 @@
 static struct msm_actuator_ctrl_t msm_actuator_t = {
 	.i2c_driver = &msm_actuator_i2c_driver,
 	.act_v4l2_subdev_ops = &msm_actuator_subdev_ops,
-	.actuator_ext_ctrl = {
-		.a_power_up = msm_actuator_power_up,
-		.a_create_subdevice = msm_actuator_create_subdevice,
-		.a_config = msm_actuator_config,
-		.a_power_down = msm_actuator_af_power_down,
-	},
 
 	.curr_step_pos = 0,
 	.curr_region_index = 0,
diff --git a/drivers/media/video/msm/actuators/msm_actuator.h b/drivers/media/video/msm/actuators/msm_actuator.h
index 803a641b..4f936e7 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.h
+++ b/drivers/media/video/msm/actuators/msm_actuator.h
@@ -51,8 +51,6 @@
 			struct msm_actuator_move_params_t *);
 	int32_t (*actuator_move_focus) (struct msm_actuator_ctrl_t *,
 			struct msm_actuator_move_params_t *);
-	int (*actuator_power_down) (struct msm_actuator_ctrl_t *);
-	int32_t (*actuator_config)(void __user *);
 	int32_t (*actuator_i2c_write)(struct msm_actuator_ctrl_t *,
 			int16_t, uint32_t);
 	int32_t (*actuator_write_focus)(struct msm_actuator_ctrl_t *,
@@ -71,10 +69,9 @@
 	struct i2c_driver *i2c_driver;
 	struct msm_camera_i2c_client i2c_client;
 	struct mutex *actuator_mutex;
-	struct msm_actuator_ctrl actuator_ext_ctrl;
 	struct msm_actuator_func_tbl *func_tbl;
 	enum msm_actuator_data_type i2c_data_type;
-	struct v4l2_subdev *sdev;
+	struct v4l2_subdev sdev;
 	struct v4l2_subdev_ops *act_v4l2_subdev_ops;
 
 	int16_t curr_step_pos;
@@ -92,6 +89,7 @@
 	uint16_t initial_code;
 };
 
+struct msm_actuator_ctrl_t *get_actrl(struct v4l2_subdev *sd);
 int32_t msm_actuator_i2c_write(struct msm_actuator_ctrl_t *a_ctrl,
 		int16_t next_lens_position, uint32_t hw_params);
 int32_t msm_actuator_init_focus(struct msm_actuator_ctrl_t *a_ctrl,
@@ -100,7 +98,6 @@
 int32_t msm_actuator_i2c_write_b_af(struct msm_actuator_ctrl_t *a_ctrl,
 		uint8_t msb,
 		uint8_t lsb);
-int32_t msm_actuator_config(void __user *cfg_data);
 int32_t msm_actuator_move_focus(struct msm_actuator_ctrl_t *a_ctrl,
 		struct msm_actuator_move_params_t *move_params);
 int32_t msm_actuator_piezo_move_focus(
@@ -113,7 +110,6 @@
 int32_t msm_actuator_piezo_set_default_focus(
 		struct msm_actuator_ctrl_t *a_ctrl,
 		struct msm_actuator_move_params_t *move_params);
-int32_t msm_actuator_af_power_down(void *cfg_data);
 int32_t msm_actuator_i2c_probe(struct i2c_client *client,
 		const struct i2c_device_id *id);
 int32_t msm_actuator_write_focus(struct msm_actuator_ctrl_t *a_ctrl,
@@ -122,6 +118,11 @@
 int32_t msm_actuator_write_focus2(struct msm_actuator_ctrl_t *a_ctrl,
 		uint16_t curr_lens_pos, struct damping_params_t *damping_params,
 		int8_t sign_direction, int16_t code_boundary);
-int32_t msm_actuator_create_subdevice(void *info, void *dev);
+long msm_actuator_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg);
+int32_t msm_actuator_power(struct v4l2_subdev *sd, int on);
+
+#define VIDIOC_MSM_ACTUATOR_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 11, void __user *)
 
 #endif
diff --git a/drivers/media/video/msm/csi/msm_csic.c b/drivers/media/video/msm/csi/msm_csic.c
index b4adbaf..6a5a647 100644
--- a/drivers/media/video/msm/csi/msm_csic.c
+++ b/drivers/media/video/msm/csi/msm_csic.c
@@ -379,6 +379,8 @@
 	.core = &msm_csic_subdev_core_ops,
 };
 
+static const struct v4l2_subdev_internal_ops msm_csic_internal_ops;
+
 static int __devinit csic_probe(struct platform_device *pdev)
 {
 	struct csic_device *new_csic_dev;
@@ -391,6 +393,10 @@
 	}
 
 	v4l2_subdev_init(&new_csic_dev->subdev, &msm_csic_subdev_ops);
+	new_csic_dev->subdev.internal_ops = &msm_csic_internal_ops;
+	new_csic_dev->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(new_csic_dev->subdev.name,
+			ARRAY_SIZE(new_csic_dev->subdev.name), "msm_csic");
 	v4l2_set_subdevdata(&new_csic_dev->subdev, new_csic_dev);
 	platform_set_drvdata(pdev, &new_csic_dev->subdev);
 	mutex_init(&new_csic_dev->mutex);
@@ -431,6 +437,8 @@
 	new_csic_dev->base = NULL;
 
 	new_csic_dev->pdev = pdev;
+	msm_cam_register_subdev_node(
+		&new_csic_dev->subdev, CSIC_DEV, pdev->id);
 	return 0;
 
 csic_no_resource:
diff --git a/drivers/media/video/msm/csi/msm_csid.c b/drivers/media/video/msm/csi/msm_csid.c
index 0cd2cf0..c04ece2 100644
--- a/drivers/media/video/msm/csi/msm_csid.c
+++ b/drivers/media/video/msm/csi/msm_csid.c
@@ -211,10 +211,11 @@
 
 	init_completion(&csid_dev->reset_complete);
 
-	enable_irq(csid_dev->irq->start);
+	rc = request_irq(csid_dev->irq->start, msm_csid_irq,
+		IRQF_TRIGGER_RISING, "csid", csid_dev);
 
 	msm_csid_reset(csid_dev);
-	return 0;
+	return rc;
 
 clk_enable_failed:
 	msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info,
@@ -230,10 +231,15 @@
 
 static int msm_csid_release(struct v4l2_subdev *sd)
 {
+	uint32_t irq;
 	struct csid_device *csid_dev;
 	csid_dev = v4l2_get_subdevdata(sd);
 
-	disable_irq(csid_dev->irq->start);
+	irq = msm_camera_io_r(csid_dev->base + CSID_IRQ_STATUS_ADDR);
+	msm_camera_io_w(irq, csid_dev->base + CSID_IRQ_CLEAR_CMD_ADDR);
+	msm_camera_io_w(0, csid_dev->base + CSID_IRQ_MASK_ADDR);
+
+	free_irq(csid_dev->irq->start, csid_dev);
 
 	msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info,
 		csid_dev->csid_clk, ARRAY_SIZE(csid_clk_info), 0);
@@ -275,6 +281,8 @@
 	return rc;
 }
 
+static const struct v4l2_subdev_internal_ops msm_csid_internal_ops;
+
 static struct v4l2_subdev_core_ops msm_csid_subdev_core_ops = {
 	.g_chip_ident = &msm_csid_subdev_g_chip_ident,
 	.ioctl = &msm_csid_subdev_ioctl,
@@ -296,6 +304,10 @@
 	}
 
 	v4l2_subdev_init(&new_csid_dev->subdev, &msm_csid_subdev_ops);
+	new_csid_dev->subdev.internal_ops = &msm_csid_internal_ops;
+	new_csid_dev->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(new_csid_dev->subdev.name,
+			ARRAY_SIZE(new_csid_dev->subdev.name), "msm_csid");
 	v4l2_set_subdevdata(&new_csid_dev->subdev, new_csid_dev);
 	platform_set_drvdata(pdev, &new_csid_dev->subdev);
 	mutex_init(&new_csid_dev->mutex);
@@ -322,18 +334,8 @@
 		goto csid_no_resource;
 	}
 
-	rc = request_irq(new_csid_dev->irq->start, msm_csid_irq,
-		IRQF_TRIGGER_RISING, "csid", new_csid_dev);
-	if (rc < 0) {
-		release_mem_region(new_csid_dev->mem->start,
-			resource_size(new_csid_dev->mem));
-		pr_err("%s: irq request fail\n", __func__);
-		rc = -EBUSY;
-		goto csid_no_resource;
-	}
-	disable_irq(new_csid_dev->irq->start);
-
 	new_csid_dev->pdev = pdev;
+	msm_cam_register_subdev_node(&new_csid_dev->subdev, CSID_DEV, pdev->id);
 	return 0;
 
 csid_no_resource:
diff --git a/drivers/media/video/msm/csi/msm_csiphy.c b/drivers/media/video/msm/csi/msm_csiphy.c
index aef017f..7c59ae8 100644
--- a/drivers/media/video/msm/csi/msm_csiphy.c
+++ b/drivers/media/video/msm/csi/msm_csiphy.c
@@ -263,6 +263,8 @@
 	return rc;
 }
 
+static const struct v4l2_subdev_internal_ops msm_csiphy_internal_ops;
+
 static struct v4l2_subdev_core_ops msm_csiphy_subdev_core_ops = {
 	.g_chip_ident = &msm_csiphy_subdev_g_chip_ident,
 	.ioctl = &msm_csiphy_subdev_ioctl,
@@ -284,6 +286,10 @@
 	}
 
 	v4l2_subdev_init(&new_csiphy_dev->subdev, &msm_csiphy_subdev_ops);
+	new_csiphy_dev->subdev.internal_ops = &msm_csiphy_internal_ops;
+	new_csiphy_dev->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(new_csiphy_dev->subdev.name,
+			ARRAY_SIZE(new_csiphy_dev->subdev.name), "msm_csiphy");
 	v4l2_set_subdevdata(&new_csiphy_dev->subdev, new_csiphy_dev);
 	platform_set_drvdata(pdev, &new_csiphy_dev->subdev);
 
@@ -323,6 +329,8 @@
 	disable_irq(new_csiphy_dev->irq->start);
 
 	new_csiphy_dev->pdev = pdev;
+	msm_cam_register_subdev_node(
+		&new_csiphy_dev->subdev, CSIPHY_DEV, pdev->id);
 	return 0;
 
 csiphy_no_resource:
diff --git a/drivers/media/video/msm/csi/msm_ispif.c b/drivers/media/video/msm/csi/msm_ispif.c
index cbb9e03..728e510 100644
--- a/drivers/media/video/msm/csi/msm_ispif.c
+++ b/drivers/media/video/msm/csi/msm_ispif.c
@@ -599,6 +599,8 @@
 	.video = &msm_ispif_subdev_video_ops,
 };
 
+static const struct v4l2_subdev_internal_ops msm_ispif_internal_ops;
+
 static int __devinit ispif_probe(struct platform_device *pdev)
 {
 	int rc = 0;
@@ -610,6 +612,10 @@
 	}
 
 	v4l2_subdev_init(&ispif->subdev, &msm_ispif_subdev_ops);
+	ispif->subdev.internal_ops = &msm_ispif_internal_ops;
+	ispif->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(ispif->subdev.name,
+			ARRAY_SIZE(ispif->subdev.name), "msm_ispif");
 	v4l2_set_subdevdata(&ispif->subdev, ispif);
 	platform_set_drvdata(pdev, &ispif->subdev);
 	snprintf(ispif->subdev.name, sizeof(ispif->subdev.name),
@@ -645,6 +651,7 @@
 	}
 
 	ispif->pdev = pdev;
+	msm_cam_register_subdev_node(&ispif->subdev, ISPIF_DEV, pdev->id);
 	return 0;
 
 ispif_no_mem:
diff --git a/drivers/media/video/msm/eeprom/Makefile b/drivers/media/video/msm/eeprom/Makefile
new file mode 100644
index 0000000..f7b7f5d
--- /dev/null
+++ b/drivers/media/video/msm/eeprom/Makefile
@@ -0,0 +1,5 @@
+GCC_VERSION      := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
+EXTRA_CFLAGS += -Idrivers/media/video/msm/io
+obj-$(CONFIG_MSM_EEPROM) += msm_camera_eeprom.o
+obj-$(CONFIG_IMX074_EEPROM) += imx074_eeprom.o
+obj-$(CONFIG_IMX091_EEPROM) += imx091_eeprom.o
\ No newline at end of file
diff --git a/drivers/media/video/msm/eeprom/imx074_eeprom.c b/drivers/media/video/msm/eeprom/imx074_eeprom.c
new file mode 100644
index 0000000..f46bc94
--- /dev/null
+++ b/drivers/media/video/msm/eeprom/imx074_eeprom.c
@@ -0,0 +1,111 @@
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "msm_camera_eeprom.h"
+#include "msm_camera_i2c.h"
+
+DEFINE_MUTEX(imx074_eeprom_mutex);
+static struct msm_eeprom_ctrl_t imx074_eeprom_t;
+
+static const struct i2c_device_id imx074_eeprom_i2c_id[] = {
+	{"imx074_eeprom", (kernel_ulong_t)&imx074_eeprom_t},
+	{ }
+};
+
+static struct i2c_driver imx074_eeprom_i2c_driver = {
+	.id_table = imx074_eeprom_i2c_id,
+	.probe  = msm_eeprom_i2c_probe,
+	.remove = __exit_p(imx074_eeprom_i2c_remove),
+	.driver = {
+		.name = "imx074_eeprom",
+	},
+};
+
+static int __init imx074_eeprom_i2c_add_driver(void)
+{
+	int rc = 0;
+	rc = i2c_add_driver(imx074_eeprom_t.i2c_driver);
+	return rc;
+}
+
+static struct v4l2_subdev_core_ops imx074_eeprom_subdev_core_ops = {
+	.ioctl = msm_eeprom_subdev_ioctl,
+};
+
+static struct v4l2_subdev_ops imx074_eeprom_subdev_ops = {
+	.core = &imx074_eeprom_subdev_core_ops,
+};
+
+uint8_t imx074_wbcalib_data[6];
+struct msm_calib_wb imx074_wb_data;
+
+static struct msm_camera_eeprom_info_t imx074_calib_supp_info = {
+	{FALSE, 0, 0, 1},
+	{TRUE, 6, 0, 1024},
+	{FALSE, 0, 0, 1},
+	{FALSE, 0, 0, 1},
+};
+
+static struct msm_camera_eeprom_read_t imx074_eeprom_read_tbl[] = {
+	{0x10, &imx074_wbcalib_data[0], 6, 0},
+};
+
+
+static struct msm_camera_eeprom_data_t imx074_eeprom_data_tbl[] = {
+	{&imx074_wb_data, sizeof(struct msm_calib_wb)},
+};
+
+static void imx074_format_wbdata(void)
+{
+	imx074_wb_data.r_over_g = (uint16_t)(imx074_wbcalib_data[0] << 8) |
+		imx074_wbcalib_data[1];
+	imx074_wb_data.b_over_g = (uint16_t)(imx074_wbcalib_data[2] << 8) |
+		imx074_wbcalib_data[3];
+	imx074_wb_data.gr_over_gb = (uint16_t)(imx074_wbcalib_data[4] << 8) |
+		imx074_wbcalib_data[5];
+}
+
+void imx074_format_calibrationdata(void)
+{
+	imx074_format_wbdata();
+}
+static struct msm_eeprom_ctrl_t imx074_eeprom_t = {
+	.i2c_driver = &imx074_eeprom_i2c_driver,
+	.i2c_addr = 0xA4,
+	.eeprom_v4l2_subdev_ops = &imx074_eeprom_subdev_ops,
+
+	.i2c_client = {
+		.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+	},
+
+	.eeprom_mutex = &imx074_eeprom_mutex,
+
+	.func_tbl = {
+		.eeprom_init = NULL,
+		.eeprom_release = NULL,
+		.eeprom_get_info = msm_camera_eeprom_get_info,
+		.eeprom_get_data = msm_camera_eeprom_get_data,
+		.eeprom_set_dev_addr = NULL,
+		.eeprom_format_data = imx074_format_calibrationdata,
+	},
+	.info = &imx074_calib_supp_info,
+	.info_size = sizeof(struct msm_camera_eeprom_info_t),
+	.read_tbl = imx074_eeprom_read_tbl,
+	.read_tbl_size = ARRAY_SIZE(imx074_eeprom_read_tbl),
+	.data_tbl = imx074_eeprom_data_tbl,
+	.data_tbl_size = ARRAY_SIZE(imx074_eeprom_data_tbl),
+};
+
+subsys_initcall(imx074_eeprom_i2c_add_driver);
+MODULE_DESCRIPTION("IMX074 EEPROM");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/eeprom/imx091_eeprom.c b/drivers/media/video/msm/eeprom/imx091_eeprom.c
new file mode 100644
index 0000000..8b34513
--- /dev/null
+++ b/drivers/media/video/msm/eeprom/imx091_eeprom.c
@@ -0,0 +1,126 @@
+/* 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 "msm_camera_eeprom.h"
+#include "msm_camera_i2c.h"
+
+DEFINE_MUTEX(imx091_eeprom_mutex);
+static struct msm_eeprom_ctrl_t imx091_eeprom_t;
+
+static const struct i2c_device_id imx091_eeprom_i2c_id[] = {
+	{"imx091_eeprom", (kernel_ulong_t)&imx091_eeprom_t},
+	{ }
+};
+
+static struct i2c_driver imx091_eeprom_i2c_driver = {
+	.id_table = imx091_eeprom_i2c_id,
+	.probe  = msm_eeprom_i2c_probe,
+	.remove = __exit_p(imx091_eeprom_i2c_remove),
+	.driver = {
+		.name = "imx091_eeprom",
+	},
+};
+
+static int __init imx091_eeprom_i2c_add_driver(void)
+{
+	int rc = 0;
+	rc = i2c_add_driver(imx091_eeprom_t.i2c_driver);
+	return rc;
+}
+
+static struct v4l2_subdev_core_ops imx091_eeprom_subdev_core_ops = {
+	.ioctl = msm_eeprom_subdev_ioctl,
+};
+
+static struct v4l2_subdev_ops imx091_eeprom_subdev_ops = {
+	.core = &imx091_eeprom_subdev_core_ops,
+};
+
+uint8_t imx091_wbcalib_data[6];
+uint8_t imx091_afcalib_data[6];
+struct msm_calib_wb imx091_wb_data;
+struct msm_calib_af imx091_af_data;
+
+static struct msm_camera_eeprom_info_t imx091_calib_supp_info = {
+	{TRUE, 6, 1, 1},
+	{TRUE, 6, 0, 32768},
+	{FALSE, 0, 0, 1},
+	{FALSE, 0, 0, 1},
+};
+
+static struct msm_camera_eeprom_read_t imx091_eeprom_read_tbl[] = {
+	{0x05, &imx091_wbcalib_data[0], 6, 0},
+	{0x0B, &imx091_afcalib_data[0], 6, 0},
+};
+
+
+static struct msm_camera_eeprom_data_t imx091_eeprom_data_tbl[] = {
+	{&imx091_wb_data, sizeof(struct msm_calib_wb)},
+	{&imx091_af_data, sizeof(struct msm_calib_af)},
+};
+
+static void imx091_format_wbdata(void)
+{
+	imx091_wb_data.r_over_g = (uint16_t)(imx091_wbcalib_data[1] << 8) |
+		(imx091_wbcalib_data[0] - 0x32);
+	imx091_wb_data.b_over_g = (uint16_t)(imx091_wbcalib_data[3] << 8) |
+		(imx091_wbcalib_data[2] - 0x32);
+	imx091_wb_data.gr_over_gb = (uint16_t)(imx091_wbcalib_data[5] << 8) |
+		(imx091_wbcalib_data[4] - 0x32);
+}
+
+static void imx091_format_afdata(void)
+{
+	imx091_af_data.inf_dac = (uint16_t)(imx091_afcalib_data[1] << 8) |
+		imx091_afcalib_data[0];
+	imx091_af_data.macro_dac = (uint16_t)(imx091_afcalib_data[3] << 8) |
+		imx091_afcalib_data[2];
+	imx091_af_data.start_dac = (uint16_t)(imx091_afcalib_data[5] << 8) |
+		imx091_afcalib_data[4];
+}
+
+void imx091_format_calibrationdata(void)
+{
+	imx091_format_wbdata();
+	imx091_format_afdata();
+}
+static struct msm_eeprom_ctrl_t imx091_eeprom_t = {
+	.i2c_driver = &imx091_eeprom_i2c_driver,
+	.i2c_addr = 0xA1,
+	.eeprom_v4l2_subdev_ops = &imx091_eeprom_subdev_ops,
+
+	.i2c_client = {
+		.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+	},
+
+	.eeprom_mutex = &imx091_eeprom_mutex,
+
+	.func_tbl = {
+		.eeprom_init = NULL,
+		.eeprom_release = NULL,
+		.eeprom_get_info = msm_camera_eeprom_get_info,
+		.eeprom_get_data = msm_camera_eeprom_get_data,
+		.eeprom_set_dev_addr = NULL,
+		.eeprom_format_data = imx091_format_calibrationdata,
+	},
+	.info = &imx091_calib_supp_info,
+	.info_size = sizeof(struct msm_camera_eeprom_info_t),
+	.read_tbl = imx091_eeprom_read_tbl,
+	.read_tbl_size = ARRAY_SIZE(imx091_eeprom_read_tbl),
+	.data_tbl = imx091_eeprom_data_tbl,
+	.data_tbl_size = ARRAY_SIZE(imx091_eeprom_data_tbl),
+};
+
+subsys_initcall(imx091_eeprom_i2c_add_driver);
+MODULE_DESCRIPTION("imx091 EEPROM");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/eeprom/msm_camera_eeprom.c b/drivers/media/video/msm/eeprom/msm_camera_eeprom.c
new file mode 100644
index 0000000..96a6e04
--- /dev/null
+++ b/drivers/media/video/msm/eeprom/msm_camera_eeprom.c
@@ -0,0 +1,196 @@
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include "msm_camera_eeprom.h"
+
+int32_t msm_camera_eeprom_read(struct msm_eeprom_ctrl_t *ectrl,
+	uint32_t reg_addr, void *data, uint32_t num_byte,
+	uint16_t convert_endian)
+{
+	int rc = 0;
+	if (ectrl->func_tbl.eeprom_set_dev_addr != NULL)
+		ectrl->func_tbl.eeprom_set_dev_addr(ectrl, &reg_addr);
+
+	if (!convert_endian) {
+		rc = msm_camera_i2c_read_seq(
+			&ectrl->i2c_client, reg_addr, data, num_byte);
+	} else {
+		unsigned char buf[num_byte];
+		uint8_t *data_ptr = (uint8_t *) data;
+		int i;
+		rc = msm_camera_i2c_read_seq(
+			&ectrl->i2c_client, reg_addr, buf, num_byte);
+		for (i = 0; i < num_byte; i += 2) {
+			data_ptr[i] = buf[i+1];
+			data_ptr[i+1] = buf[i];
+		}
+	}
+	return rc;
+}
+
+int32_t msm_camera_eeprom_read_tbl(struct msm_eeprom_ctrl_t *ectrl,
+	struct msm_camera_eeprom_read_t *read_tbl, uint16_t tbl_size)
+{
+	int i, rc = 0;
+	CDBG("%s: open\n", __func__);
+	if (read_tbl == NULL)
+		return rc;
+
+	for (i = 0; i < tbl_size; i++) {
+		rc = msm_camera_eeprom_read
+			(ectrl, read_tbl[i].reg_addr,
+			read_tbl[i].dest_ptr, read_tbl[i].num_byte,
+			read_tbl[i].convert_endian);
+		if (rc < 0) {
+			pr_err("%s: read failed\n", __func__);
+			return rc;
+		}
+	}
+	CDBG("%s: done\n", __func__);
+	return rc;
+}
+
+int32_t msm_camera_eeprom_get_info(struct msm_eeprom_ctrl_t *ectrl,
+	struct msm_camera_eeprom_info_t *einfo)
+{
+	int rc = 0;
+	CDBG("%s: open\n", __func__);
+	memcpy(einfo, ectrl->info, ectrl->info_size);
+	CDBG("%s: done =%d\n", __func__, rc);
+	return rc;
+}
+
+int32_t msm_camera_eeprom_get_data(struct msm_eeprom_ctrl_t *ectrl,
+	struct msm_eeprom_data_t *edata)
+{
+	int rc = 0;
+	if (edata->index >= ectrl->data_tbl_size)
+		return -EFAULT;
+	if (copy_to_user(edata->eeprom_data,
+		ectrl->data_tbl[edata->index].data,
+		ectrl->data_tbl[edata->index].size))
+		rc = -EFAULT;
+	return rc;
+}
+
+int32_t msm_eeprom_config(struct msm_eeprom_ctrl_t *e_ctrl,
+	void __user *argp)
+{
+	struct msm_eeprom_cfg_data cdata;
+	int32_t rc = 0;
+	if (copy_from_user(&cdata,
+		(void *)argp,
+		sizeof(struct msm_eeprom_cfg_data)))
+		return -EFAULT;
+	mutex_lock(e_ctrl->eeprom_mutex);
+
+	switch (cdata.cfgtype) {
+	case CFG_GET_EEPROM_INFO:
+		if (e_ctrl->func_tbl.eeprom_get_info == NULL) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = e_ctrl->func_tbl.eeprom_get_info(e_ctrl,
+			&cdata.cfg.get_info);
+
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct msm_eeprom_cfg_data)))
+			rc = -EFAULT;
+		break;
+	case CFG_GET_EEPROM_DATA:
+		if (e_ctrl->func_tbl.eeprom_get_data == NULL) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = e_ctrl->func_tbl.eeprom_get_data(e_ctrl,
+			&cdata.cfg.get_data);
+
+		if (copy_to_user((void *)argp,
+			&cdata,
+			sizeof(struct msm_eeprom_cfg_data)))
+			rc = -EFAULT;
+		break;
+	default:
+		break;
+	}
+	mutex_unlock(e_ctrl->eeprom_mutex);
+	return rc;
+}
+
+struct msm_eeprom_ctrl_t *get_ectrl(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct msm_eeprom_ctrl_t, sdev);
+}
+
+long msm_eeprom_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	struct msm_eeprom_ctrl_t *e_ctrl = get_ectrl(sd);
+	void __user *argp = (void __user *)arg;
+	switch (cmd) {
+	case VIDIOC_MSM_EEPROM_CFG:
+		return msm_eeprom_config(e_ctrl, argp);
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+int32_t msm_eeprom_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	struct msm_eeprom_ctrl_t *e_ctrl_t = NULL;
+	CDBG("%s called\n", __func__);
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	e_ctrl_t = (struct msm_eeprom_ctrl_t *)(id->driver_data);
+	e_ctrl_t->i2c_client.client = client;
+
+	if (e_ctrl_t->i2c_addr != 0)
+		e_ctrl_t->i2c_client.client->addr = e_ctrl_t->i2c_addr;
+
+	CDBG("%s client = %x\n", __func__, (unsigned int) client);
+
+	/* Assign name for sub device */
+	snprintf(e_ctrl_t->sdev.name, sizeof(e_ctrl_t->sdev.name),
+		"%s", e_ctrl_t->i2c_driver->driver.name);
+
+	if (e_ctrl_t->func_tbl.eeprom_init != NULL) {
+		rc = e_ctrl_t->func_tbl.eeprom_init(e_ctrl_t,
+			e_ctrl_t->i2c_client.client->adapter);
+	}
+	msm_camera_eeprom_read_tbl(e_ctrl_t,
+		e_ctrl_t->read_tbl,
+		e_ctrl_t->read_tbl_size);
+
+	if (e_ctrl_t->func_tbl.eeprom_format_data != NULL)
+		e_ctrl_t->func_tbl.eeprom_format_data();
+
+	if (e_ctrl_t->func_tbl.eeprom_release != NULL)
+		rc = e_ctrl_t->func_tbl.eeprom_release(e_ctrl_t);
+
+
+	/* Initialize sub device */
+	v4l2_i2c_subdev_init(&e_ctrl_t->sdev,
+		e_ctrl_t->i2c_client.client,
+		e_ctrl_t->eeprom_v4l2_subdev_ops);
+	CDBG("%s success resut=%d\n", __func__, rc);
+	return rc;
+
+probe_failure:
+	pr_err("%s failed! rc = %d\n", __func__, rc);
+	return rc;
+}
diff --git a/drivers/media/video/msm/eeprom/msm_camera_eeprom.h b/drivers/media/video/msm/eeprom/msm_camera_eeprom.h
new file mode 100644
index 0000000..830e5d8
--- /dev/null
+++ b/drivers/media/video/msm/eeprom/msm_camera_eeprom.h
@@ -0,0 +1,82 @@
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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_CAMERA_EEPROM_H
+#define MSM_CAMERA_EEPROM_H
+
+#include <linux/delay.h>
+#include <mach/camera.h>
+#include <media/v4l2-subdev.h>
+#include "msm_camera_i2c.h"
+
+#define TRUE  1
+#define FALSE 0
+
+struct msm_eeprom_ctrl_t;
+
+struct msm_camera_eeprom_fn_t {
+	int32_t (*eeprom_init)
+		(struct msm_eeprom_ctrl_t *ectrl,
+		struct i2c_adapter *adapter);
+	int32_t (*eeprom_release)
+		(struct msm_eeprom_ctrl_t *ectrl);
+	int32_t (*eeprom_get_info)
+		(struct msm_eeprom_ctrl_t *ectrl,
+		 struct msm_camera_eeprom_info_t *einfo);
+	int32_t (*eeprom_get_data)
+		(struct msm_eeprom_ctrl_t *ectrl,
+		 struct msm_eeprom_data_t *edata);
+	void (*eeprom_set_dev_addr)
+		(struct msm_eeprom_ctrl_t*, uint32_t*);
+	void (*eeprom_format_data)
+		(void);
+};
+
+struct msm_camera_eeprom_read_t {
+	uint32_t reg_addr;
+	void *dest_ptr;
+	uint32_t num_byte;
+	uint16_t convert_endian;
+};
+
+struct msm_camera_eeprom_data_t {
+	void *data;
+	uint16_t size;
+};
+
+struct msm_eeprom_ctrl_t {
+	struct msm_camera_i2c_client i2c_client;
+	uint16_t i2c_addr;
+	struct i2c_driver *i2c_driver;
+	struct mutex *eeprom_mutex;
+	struct v4l2_subdev sdev;
+	struct v4l2_subdev_ops *eeprom_v4l2_subdev_ops;
+	struct msm_camera_eeprom_fn_t func_tbl;
+	struct msm_camera_eeprom_info_t *info;
+	uint16_t info_size;
+	struct msm_camera_eeprom_read_t *read_tbl;
+	uint16_t read_tbl_size;
+	struct msm_camera_eeprom_data_t *data_tbl;
+	uint16_t data_tbl_size;
+};
+
+int32_t msm_camera_eeprom_get_data(struct msm_eeprom_ctrl_t *ectrl,
+	struct msm_eeprom_data_t *edata);
+int32_t msm_camera_eeprom_get_info(struct msm_eeprom_ctrl_t *ectrl,
+	struct msm_camera_eeprom_info_t *einfo);
+int32_t msm_eeprom_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id);
+long msm_eeprom_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg);
+
+#define VIDIOC_MSM_EEPROM_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 12, void __user *)
+#endif
diff --git a/drivers/media/video/msm/gemini/msm_gemini_platform.c b/drivers/media/video/msm/gemini/msm_gemini_platform.c
index fb5b035..1ebc2f1 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_platform.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_platform.c
@@ -82,17 +82,17 @@
 }
 
 static struct msm_cam_clk_info gemini_8x_clk_info[] = {
-	{"ijpeg_clk", 228571000},
-	{"ijpeg_pclk", -1},
+	{"core_clk", 228571000},
+	{"iface_clk", -1},
 };
 
 static struct msm_cam_clk_info gemini_7x_clk_info[] = {
-	{"jpeg_clk", 153600000},
-	{"jpeg_pclk", -1},
+	{"core_clk", 153600000},
+	{"iface_clk", -1},
 };
 
 static struct msm_cam_clk_info gemini_imem_clk_info[] = {
-	{"imem_clk", -1},
+	{"mem_clk", -1},
 };
 
 int msm_gemini_platform_init(struct platform_device *pdev,
@@ -159,7 +159,7 @@
 	if (pgmn_dev->hw_version != GEMINI_7X) {
 		if (pgmn_dev->gemini_fs == NULL) {
 			pgmn_dev->gemini_fs =
-				regulator_get(&pgmn_dev->pdev->dev, "fs_ijpeg");
+				regulator_get(&pgmn_dev->pdev->dev, "vdd");
 			if (IS_ERR(pgmn_dev->gemini_fs)) {
 				pr_err("%s: Regulator FS_ijpeg get failed %ld\n",
 					__func__, PTR_ERR(pgmn_dev->gemini_fs));
diff --git a/drivers/media/video/msm/io/Makefile b/drivers/media/video/msm/io/Makefile
index dddcbf6..64df7fb 100644
--- a/drivers/media/video/msm/io/Makefile
+++ b/drivers/media/video/msm/io/Makefile
@@ -3,7 +3,7 @@
 obj-$(CONFIG_MSM_CAMERA)   += msm_camera_io_util.o
 EXTRA_CFLAGS += -Idrivers/media/video/msm
 ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
-  obj-$(CONFIG_MSM_CAMERA) += msm_camera_i2c.o msm_camera_eeprom.o msm_camera_i2c_mux.o
+  obj-$(CONFIG_MSM_CAMERA) += msm_camera_i2c.o msm_camera_i2c_mux.o
   obj-$(CONFIG_ARCH_MSM7X27A) += msm_io_7x27a_v4l2.o
   obj-$(CONFIG_ARCH_MSM8X60) += msm_io_vfe31_v4l2.o
   obj-$(CONFIG_ARCH_MSM7X30) += msm_io_vfe31_v4l2.o
diff --git a/drivers/media/video/msm/io/msm_camera_eeprom.c b/drivers/media/video/msm/io/msm_camera_eeprom.c
deleted file mode 100644
index 34dba26..0000000
--- a/drivers/media/video/msm/io/msm_camera_eeprom.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/* Copyright (c) 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.
- */
-
-#include "msm_camera_eeprom.h"
-
-int32_t msm_camera_eeprom_init(struct msm_camera_eeprom_client *ectrl,
-	struct i2c_adapter *adapter)
-{
-	CDBG("%s: open", __func__);
-	ectrl->i2c_client->client =
-		i2c_new_dummy(adapter, ectrl->i2c_addr >> 1);
-	if (ectrl->i2c_client->client == NULL) {
-		CDBG("%s: eeprom i2c get client failed\n", __func__);
-		return -EFAULT;
-	}
-	ectrl->i2c_client->client->addr = ectrl->i2c_addr;
-	CDBG("%s: done", __func__);
-	return 0;
-}
-
-int32_t msm_camera_eeprom_release(struct msm_camera_eeprom_client *ectrl)
-{
-	if (ectrl->i2c_client->client != NULL) {
-		i2c_unregister_device(ectrl->i2c_client->client);
-		ectrl->i2c_client->client = NULL;
-	}
-	return 0;
-}
-
-int32_t msm_camera_eeprom_read(struct msm_camera_eeprom_client *ectrl,
-	uint16_t reg_addr, void *data, uint32_t num_byte,
-	uint16_t convert_endian)
-{
-	int rc = 0;
-	if (ectrl->func_tbl.eeprom_set_dev_addr != NULL)
-		ectrl->func_tbl.eeprom_set_dev_addr(ectrl, &reg_addr);
-
-	if (!convert_endian) {
-		rc = msm_camera_i2c_read_seq(
-			ectrl->i2c_client, reg_addr, data, num_byte);
-	} else {
-		unsigned char buf[num_byte];
-		uint8_t *data_ptr = (uint8_t *) data;
-		int i;
-		rc = msm_camera_i2c_read_seq(
-			ectrl->i2c_client, reg_addr, buf, num_byte);
-		for (i = 0; i < num_byte; i++)
-			data_ptr[i] = buf[num_byte-i-1];
-	}
-	return rc;
-}
-
-int32_t msm_camera_eeprom_read_tbl(struct msm_camera_eeprom_client *ectrl,
-	struct msm_camera_eeprom_read_t *read_tbl, uint16_t tbl_size)
-{
-	int i, rc = 0;
-	CDBG("%s: open", __func__);
-	if (read_tbl == NULL)
-		return rc;
-
-	for (i = 0; i < tbl_size; i++) {
-		rc = msm_camera_eeprom_read
-			(ectrl, read_tbl[i].reg_addr,
-			read_tbl[i].dest_ptr, read_tbl[i].num_byte,
-			read_tbl[i].convert_endian);
-		if (rc < 0)	{
-			CDBG("%s: read failed\n", __func__);
-			return rc;
-		}
-	}
-	CDBG("%s: done", __func__);
-	return rc;
-}
-
-int32_t msm_camera_eeprom_get_data(struct msm_camera_eeprom_client *ectrl,
-	struct sensor_eeprom_data_t *edata)
-{
-	int rc = 0;
-	if (edata->index >= ectrl->data_tbl_size)
-		return -EFAULT;
-	if (copy_to_user(edata->eeprom_data,
-		ectrl->data_tbl[edata->index].data,
-		ectrl->data_tbl[edata->index].size))
-		rc = -EFAULT;
-	return rc;
-}
-
diff --git a/drivers/media/video/msm/io/msm_camera_eeprom.h b/drivers/media/video/msm/io/msm_camera_eeprom.h
deleted file mode 100644
index 9dd7b54..0000000
--- a/drivers/media/video/msm/io/msm_camera_eeprom.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* Copyright (c) 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.
- */
-
-#include <linux/delay.h>
-#include <mach/camera.h>
-#include "msm_camera_i2c.h"
-
-struct msm_camera_eeprom_client;
-
-struct msm_camera_eeprom_fn_t {
-	int32_t (*eeprom_init)
-		(struct msm_camera_eeprom_client *ectrl,
-		struct i2c_adapter *adapter);
-	int32_t (*eeprom_release)
-		(struct msm_camera_eeprom_client *ectrl);
-	int32_t (*eeprom_get_data)
-		(struct msm_camera_eeprom_client *ectrl,
-		 struct sensor_eeprom_data_t *edata);
-	void (*eeprom_set_dev_addr)
-		(struct msm_camera_eeprom_client*, uint16_t*);
-};
-
-struct msm_camera_eeprom_read_t {
-	uint16_t reg_addr;
-	void *dest_ptr;
-	uint32_t num_byte;
-	uint16_t convert_endian;
-};
-
-struct msm_camera_eeprom_data_t {
-	void *data;
-	uint16_t size;
-};
-
-struct msm_camera_eeprom_client {
-	struct msm_camera_i2c_client *i2c_client;
-	uint16_t i2c_addr;
-	struct msm_camera_eeprom_fn_t func_tbl;
-	struct msm_camera_eeprom_read_t *read_tbl;
-	uint16_t read_tbl_size;
-	struct msm_camera_eeprom_data_t *data_tbl;
-	uint16_t data_tbl_size;
-};
-
-int32_t msm_camera_eeprom_init(struct msm_camera_eeprom_client *ectrl,
-	struct i2c_adapter *adapter);
-int32_t msm_camera_eeprom_release(struct msm_camera_eeprom_client *ectrl);
-int32_t msm_camera_eeprom_read(struct msm_camera_eeprom_client *ectrl,
-	uint16_t reg_addr, void *data, uint32_t num_byte,
-	uint16_t convert_endian);
-int32_t msm_camera_eeprom_read_tbl(struct msm_camera_eeprom_client *ectrl,
-	struct msm_camera_eeprom_read_t *read_tbl, uint16_t tbl_size);
-int32_t msm_camera_eeprom_get_data(struct msm_camera_eeprom_client *ectrl,
-	struct sensor_eeprom_data_t *edata);
-
-
-
diff --git a/drivers/media/video/msm/io/msm_camera_i2c.c b/drivers/media/video/msm/io/msm_camera_i2c.c
index a3cc012..6f45637 100644
--- a/drivers/media/video/msm/io/msm_camera_i2c.c
+++ b/drivers/media/video/msm/io/msm_camera_i2c.c
@@ -252,7 +252,7 @@
 		enum msm_camera_i2c_data_type dt;
 		if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) {
 			rc = msm_camera_i2c_poll(client, reg_conf_tbl->reg_addr,
-				reg_conf_tbl->reg_addr, reg_conf_tbl->dt);
+				reg_conf_tbl->reg_data, reg_conf_tbl->dt);
 		} else {
 			if (reg_conf_tbl->dt == 0)
 				dt = data_type;
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 af60426..4049266 100644
--- a/drivers/media/video/msm/io/msm_camera_io_util.c
+++ b/drivers/media/video/msm/io/msm_camera_io_util.c
@@ -370,7 +370,7 @@
 			usleep_range(gpio_conf->cam_gpio_set_tbl[i].delay,
 				gpio_conf->cam_gpio_set_tbl[i].delay + 1000);
 		}
-	} else if (!gpio_conf->gpio_no_mux) {
+	} else {
 		for (i = gpio_conf->cam_gpio_set_tbl_size - 1; i >= 0; i--) {
 			if (gpio_conf->cam_gpio_set_tbl[i].flags)
 				gpio_set_value_cansleep(
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index ff97fa3..fa9aace 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -19,7 +19,14 @@
 #include <linux/spinlock.h>
 #include <linux/proc_fs.h>
 #include "msm.h"
+#include "msm_csid.h"
+#include "msm_csic.h"
+#include "msm_csiphy.h"
+#include "msm_ispif.h"
 #include "msm_sensor.h"
+#include "msm_actuator.h"
+#include "msm_vfe32.h"
+#include "msm_camera_eeprom.h"
 
 #define MSM_MAX_CAMERA_SENSORS 5
 
@@ -84,7 +91,7 @@
 static int32_t msm_find_free_queue(void)
 {
 	int i;
-	for (i = 0; i < NUM_SERVER_QUEUE; i++) {
+	for (i = 0; i < MAX_NUM_ACTIVE_CAMERA; i++) {
 		struct msm_cam_server_queue *queue;
 		queue = &g_server_dev.server_queue[i];
 		if (!queue->queue_active)
@@ -93,11 +100,50 @@
 	return -EINVAL;
 }
 
+uint32_t msm_camera_get_mctl_handle(void)
+{
+	uint32_t i;
+	if ((g_server_dev.mctl_handle_cnt << 8) == 0)
+		g_server_dev.mctl_handle_cnt++;
+	for (i = 0; i < MAX_NUM_ACTIVE_CAMERA; i++) {
+		if (g_server_dev.mctl[i].handle == 0) {
+			g_server_dev.mctl[i].handle =
+				(++g_server_dev.mctl_handle_cnt) << 8 | i;
+			memset(&g_server_dev.mctl[i].mctl,
+				   0, sizeof(g_server_dev.mctl[i].mctl));
+			return g_server_dev.mctl[i].handle;
+		}
+	}
+	return 0;
+}
+
+struct msm_cam_media_controller *msm_camera_get_mctl(uint32_t handle)
+{
+	uint32_t mctl_index;
+	mctl_index = handle & 0xff;
+	if ((mctl_index < MAX_NUM_ACTIVE_CAMERA) &&
+		(g_server_dev.mctl[mctl_index].handle == handle))
+		return &g_server_dev.mctl[mctl_index].mctl;
+	return NULL;
+}
+
+void msm_camera_free_mctl(uint32_t handle)
+{
+	uint32_t mctl_index;
+	mctl_index = handle & 0xff;
+	if ((mctl_index < MAX_NUM_ACTIVE_CAMERA) &&
+		(g_server_dev.mctl[mctl_index].handle == handle))
+		g_server_dev.mctl[mctl_index].handle = 0;
+	else
+		pr_err("%s: invalid free handle\n", __func__);
+}
+
 /* callback function from all subdevices of a msm_cam_v4l2_device */
 static void msm_cam_v4l2_subdev_notify(struct v4l2_subdev *sd,
 				unsigned int notification, void *arg)
 {
 	struct msm_cam_v4l2_device *pcam;
+	struct msm_cam_media_controller *pmctl;
 
 	if (sd == NULL)
 		return;
@@ -107,10 +153,9 @@
 	if (pcam == NULL)
 		return;
 
-	/* forward to media controller for any changes*/
-	if (pcam->mctl.mctl_notify) {
-		pcam->mctl.mctl_notify(&pcam->mctl, notification, arg);
-	}
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	if (pmctl == NULL)
+		return;
 }
 
 static int msm_ctrl_cmd_done(void *arg)
@@ -516,7 +561,10 @@
 	ctrlcmd.type = MSM_V4L2_SET_CTRL_CMD;
 	ctrlcmd.length = cmd_len + value_len;
 	ctrlcmd.value = (void *)ctrl_data;
-	ctrlcmd.timeout_ms = 1000;
+	if (tmp_cmd->timeout_ms > 0)
+		ctrlcmd.timeout_ms = tmp_cmd->timeout_ms;
+	else
+		ctrlcmd.timeout_ms = 1000;
 	ctrlcmd.vnode_id = pcam->vnode_id;
 	ctrlcmd.queue_idx = pcam->server_queue_idx;
 	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
@@ -1166,6 +1214,7 @@
 	int rc;
 	/* get the video device */
 	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
+	struct msm_cam_media_controller *pmctl;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
 	pcam_inst = container_of(f->private_data,
 		struct msm_cam_v4l2_dev_inst, eventHandle);
@@ -1176,8 +1225,12 @@
 		(void *)pfmt->fmt.pix.priv);
 	WARN_ON(pctx != f->private_data);
 
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	if (pmctl == NULL)
+		return -EINVAL;
+
 	if (!pcam_inst->vbqueue_initialized) {
-		pcam->mctl.mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq,
+		pmctl->mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq,
 					V4L2_BUF_TYPE_VIDEO_CAPTURE);
 		pcam_inst->vbqueue_initialized = 1;
 	}
@@ -1199,6 +1252,7 @@
 {
 	int rc;
 	struct msm_cam_v4l2_device *pcam = video_drvdata(f);
+	struct msm_cam_media_controller *pmctl;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
 	pcam_inst = container_of(f->private_data,
 			struct msm_cam_v4l2_dev_inst, eventHandle);
@@ -1206,8 +1260,12 @@
 	D("%s Inst %p\n", __func__, pcam_inst);
 	WARN_ON(pctx != f->private_data);
 
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	if (pmctl == NULL)
+		return -EINVAL;
+
 	if (!pcam_inst->vbqueue_initialized) {
-		pcam->mctl.mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq,
+		pmctl->mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq,
 					V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 		pcam_inst->vbqueue_initialized = 1;
 	}
@@ -1443,6 +1501,8 @@
 	struct msm_cam_v4l2_device *pcam)
 {
 	int rc = 0;
+	struct msm_cam_media_controller *pmctl;
+
 	D("%s\n", __func__);
 
 	if (!ps || !pcam) {
@@ -1465,19 +1525,14 @@
 	D("config pcam = 0x%p\n", ps->pcam_active);
 
 	/* initialization the media controller module*/
-	msm_mctl_init_module(pcam);
+	msm_mctl_init(pcam);
 
-	/*yyan: for single VFE msms (8660, 8960v1), just populate the session
+	/*for single VFE msms (8660, 8960v1), just populate the session
 	with our VFE devices that registered*/
-	pcam->mctl.isp_sdev = ps->isp_subdev[0];
-
-
-	/*yyan: 8960 bring up - no VPE and flash; populate later*/
-	pcam->mctl.vpe_sdev = NULL;
-	pcam->mctl.flash_sdev = NULL;
-
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	pmctl->axi_sdev = ps->axi_device[0];
+	pmctl->isp_sdev = ps->isp_subdev[0];
 	return rc;
-
 }
 
 /* close an active camera session to server */
@@ -1496,6 +1551,7 @@
 	atomic_dec(&ps->number_pcam_active);
 	ps->pcam_active = NULL;
 
+	msm_mctl_free(pcam);
 	return rc;
 }
 /* v4l2_file_operations */
@@ -1511,6 +1567,8 @@
 	/* get the video device */
 	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
+	struct msm_cam_media_controller *pmctl = NULL;
+	struct msm_cam_server_queue *queue = NULL;
 
 	D("%s\n", __func__);
 
@@ -1552,12 +1610,11 @@
 			pcam->vnode_id, pcam->use_count);
 	pcam->use_count++;
 	if (pcam->use_count == 1) {
-		struct msm_cam_server_queue *queue;
 		pcam->server_queue_idx = server_q_idx;
 		queue = &g_server_dev.server_queue[server_q_idx];
 		queue->ctrl = NULL;
 		queue->ctrl_data = kzalloc(sizeof(uint8_t) *
-				max_control_command_size, GFP_KERNEL);
+			max_control_command_size, GFP_KERNEL);
 		msm_queue_init(&queue->ctrl_q, "control");
 		msm_queue_init(&queue->eventData_q, "eventdata");
 		queue->queue_active = 1;
@@ -1566,50 +1623,39 @@
 		if (rc < 0) {
 			pr_err("%s: cam_server_open_session failed %d\n",
 			__func__, rc);
-			goto err;
+			goto msm_cam_server_open_session_failed;
 		}
+
+		pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-		pcam->mctl.client = msm_ion_client_create(-1, "camera");
-		kref_init(&pcam->mctl.refcount);
+		pmctl->client = msm_ion_client_create(-1, "camera");
+		kref_init(&pmctl->refcount);
 		ion_client_created = 1;
 #endif
+
 		/* Should be set to sensor ops if any but right now its OK!! */
-		if (!pcam->mctl.mctl_open) {
-			D("%s: media contoller is not inited\n",
-				 __func__);
+		if (!pmctl->mctl_open) {
+			D("%s: media contoller is not inited\n", __func__);
 			rc = -ENODEV;
-			goto err;
+			goto mctl_open_failed;
 		}
 
 		/* Now we really have to activate the camera */
 		D("%s: call mctl_open\n", __func__);
-		rc = pcam->mctl.mctl_open(&(pcam->mctl), MSM_APPS_ID_V4L2);
-
+		rc = pmctl->mctl_open(pmctl, MSM_APPS_ID_V4L2);
 		if (rc < 0) {
 			pr_err("%s: HW open failed rc = 0x%x\n",  __func__, rc);
-			goto err;
+			goto mctl_open_failed;
 		}
-		pcam->mctl.sync.pcam_sync = pcam;
+		pmctl->pcam_ptr = pcam;
 
-		/* Register isp subdev */
-		rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
-					pcam->mctl.isp_sdev->sd);
-		if (rc < 0) {
-			pr_err("%s: v4l2_device_register_subdev failed rc = %d\n",
-				__func__, rc);
-			goto err;
-		}
-		if (pcam->mctl.isp_sdev->sd_vpe) {
-			rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
-						pcam->mctl.isp_sdev->sd_vpe);
-			if (rc < 0) {
-				goto err;
-			}
-		}
 		rc = msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
-							pcam->pvdev);
+			pcam->pvdev);
 		if (rc < 0) {
-			goto err;
+			pr_err("%s: msm_setup_v4l2_event_queue failed %d",
+				__func__, rc);
+			goto mctl_event_q_setup_failed;
 		}
 	}
 	pcam_inst->vbqueue_initialized = 0;
@@ -1620,28 +1666,47 @@
 	D("f->private_data = 0x%x, pcam = 0x%x\n",
 		(u32)f->private_data, (u32)pcam_inst);
 
-
 	if (pcam->use_count == 1) {
 		rc = msm_send_open_server(pcam);
 		if (rc < 0) {
-			mutex_unlock(&pcam->vid_lock);
-			pr_err("%s failed\n", __func__);
-			return rc;
+			pr_err("%s: msm_send_open_server failed %d\n",
+				__func__, rc);
+			goto msm_send_open_server_failed;
 		}
 	}
 	mutex_unlock(&pcam->vid_lock);
 	D("%s: end", __func__);
-	/* rc = msm_cam_server_open_session(g_server_dev, pcam);*/
 	return rc;
 
-err:
+msm_send_open_server_failed:
+	v4l2_fh_del(&pcam_inst->eventHandle);
+	v4l2_fh_exit(&pcam_inst->eventHandle);
+mctl_event_q_setup_failed:
+	if (pmctl->mctl_release)
+		if (pmctl->mctl_release(pmctl) < 0)
+			pr_err("%s: mctl_release failed\n", __func__);
+mctl_open_failed:
 	if (pcam->use_count == 1) {
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 		if (ion_client_created) {
 			pr_err("%s: destroy ion client", __func__);
-			kref_put(&pcam->mctl.refcount, msm_release_ion_client);
+			kref_put(&pmctl->refcount, msm_release_ion_client);
 		}
 #endif
+		if (msm_cam_server_close_session(&g_server_dev, pcam) < 0)
+			pr_err("%s: msm_cam_server_close_session failed\n",
+				__func__);
+	}
+msm_cam_server_open_session_failed:
+	if (pcam->use_count == 1) {
+		queue->queue_active = 0;
+		msm_drain_eventq(&queue->eventData_q);
+		kfree(queue->ctrl_data);
+		queue->ctrl_data = NULL;
+		msm_queue_drain(&queue->ctrl_q, list_control);
+		msm_drain_eventq(&queue->eventData_q);
+		queue = NULL;
+
 		pcam->dev_inst[i] = NULL;
 		pcam->use_count = 0;
 	}
@@ -1656,10 +1721,16 @@
 	int phyaddr;
 	int retval;
 	unsigned long size;
-	struct msm_sync *sync = &pcam_inst->pcam->mctl.sync;
 	int rc = 0;
+	struct msm_cam_media_controller *mctl;
 
-	rc = msm_pmem_region_get_phy_addr(&sync->pmem_stats,
+	mctl = msm_camera_get_mctl(pcam_inst->pcam->mctl_handle);
+	if (!mctl) {
+		pr_err("%s: invalid mctl pointer", __func__);
+		return -EFAULT;
+	}
+
+	rc = msm_pmem_region_get_phy_addr(&mctl->stats_info.pmem_stats_list,
 			&pcam_inst->mem_map,
 			&phyaddr);
 	if (rc) {
@@ -1722,6 +1793,7 @@
 	struct msm_cam_v4l2_device *pcam;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
 	struct msm_cam_server_queue *queue;
+	struct msm_cam_media_controller *pmctl;
 	pcam_inst = container_of(f->private_data,
 		struct msm_cam_v4l2_dev_inst, eventHandle);
 	pcam = pcam_inst->pcam;
@@ -1730,17 +1802,23 @@
 		return -EINVAL;
 	}
 
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	if (!pmctl) {
+		pr_err("%s NULL mctl pointer\n", __func__);
+		return -EINVAL;
+	}
+
 	mutex_lock(&pcam->vid_lock);
 
 	if (pcam_inst->streamon) {
 		/*something went wrong since instance
 		is closing without streamoff*/
-		if (pcam->mctl.mctl_release) {
-			rc = pcam->mctl.mctl_release(&(pcam->mctl));
+		if (pmctl->mctl_release) {
+			rc = pmctl->mctl_release(pmctl);
 			if (rc < 0)
 				pr_err("mctl_release fails %d\n", rc);
 		}
-		pcam->mctl.mctl_release = NULL;/*so that it isn't closed again*/
+		pmctl->mctl_release = NULL;/*so that it isn't closed again*/
 	}
 
 	pcam_inst->streamon = 0;
@@ -1760,24 +1838,18 @@
 	f->private_data = NULL;
 
 	if (pcam->use_count == 0) {
-		v4l2_device_unregister_subdev(pcam->mctl.isp_sdev->sd);
-		v4l2_device_unregister_subdev(pcam->mctl.isp_sdev->sd_vpe);
-		rc = msm_cam_server_close_session(&g_server_dev, pcam);
-		if (rc < 0)
-			pr_err("msm_cam_server_close_session fails %d\n", rc);
-
 		if (g_server_dev.use_count > 0) {
 			rc = msm_send_close_server(pcam);
 			if (rc < 0)
 				pr_err("msm_send_close_server failed %d\n", rc);
 		}
-		if (pcam->mctl.mctl_release) {
-			rc = pcam->mctl.mctl_release(&(pcam->mctl));
+		if (pmctl->mctl_release) {
+			rc = pmctl->mctl_release(pmctl);
 			if (rc < 0)
 				pr_err("mctl_release fails %d\n", rc);
 		}
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-		kref_put(&pcam->mctl.refcount, msm_release_ion_client);
+		kref_put(&pmctl->refcount, msm_release_ion_client);
 #endif
 		queue = &g_server_dev.server_queue[pcam->server_queue_idx];
 		queue->queue_active = 0;
@@ -1787,6 +1859,10 @@
 		queue->ctrl_data = NULL;
 		msm_queue_drain(&queue->ctrl_q, list_control);
 		msm_drain_eventq(&queue->eventData_q);
+		rc = msm_cam_server_close_session(&g_server_dev, pcam);
+		if (rc < 0)
+			pr_err("msm_cam_server_close_session fails %d\n", rc);
+
 		if (g_server_dev.use_count == 0)
 			mutex_unlock(&g_server_dev.server_lock);
 	}
@@ -1852,16 +1928,18 @@
 	switch (cmd) {
 	case MSM_CAM_V4L2_IOCTL_GET_CAMERA_INFO:
 		if (copy_from_user(&temp_cam_info,
-				(void __user *)ioctl_ptr->ioctl_ptr,
-				sizeof(struct msm_camera_info))) {
+			(void __user *)ioctl_ptr->ioctl_ptr,
+			sizeof(struct msm_camera_info))) {
 			rc = -EINVAL;
 			return rc;
 		}
 		for (i = 0; i < g_server_dev.camera_info.num_cameras; i++) {
 			if (copy_to_user((void __user *)
-			temp_cam_info.video_dev_name[i],
-			 g_server_dev.camera_info.video_dev_name[i],
-			strlen(g_server_dev.camera_info.video_dev_name[i]))) {
+				temp_cam_info.video_dev_name[i],
+				g_server_dev.camera_info.video_dev_name[i],
+				strnlen(
+				g_server_dev.camera_info.video_dev_name[i],
+				MAX_DEV_NAME_LEN))) {
 				rc = -EINVAL;
 				return rc;
 			}
@@ -2002,6 +2080,7 @@
 		break;
 	}
 	default:
+		pr_err("%s: Invalid IOCTL = %d", __func__, cmd);
 		break;
 	}
 	return rc;
@@ -2077,7 +2156,7 @@
 		return -EFAULT;
 	}
 
-	pcam = mctl->sync.pcam_sync;
+	pcam = mctl->pcam_ptr;
 	ktime_get_ts(&v4l2_ev.timestamp);
 	v4l2_event_queue(pcam->pvdev, &v4l2_ev);
 	return 0;
@@ -2095,43 +2174,50 @@
 	D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
 
 	switch (cmd) {
-		/* memory management shall be handeld here*/
+	/* memory management shall be handeld here*/
 	case MSM_CAM_IOCTL_REGISTER_PMEM:
 		return msm_register_pmem(
-			&config_cam->p_mctl->sync.pmem_stats,
+			&config_cam->p_mctl->stats_info.pmem_stats_list,
 			(void __user *)arg, config_cam->p_mctl->client);
 		break;
 
 	case MSM_CAM_IOCTL_UNREGISTER_PMEM:
 		return msm_pmem_table_del(
-			&config_cam->p_mctl->sync.pmem_stats,
+			&config_cam->p_mctl->stats_info.pmem_stats_list,
 			(void __user *)arg, config_cam->p_mctl->client);
 		break;
+
 	case VIDIOC_SUBSCRIBE_EVENT:
 		if (copy_from_user(&temp_sub,
 			(void __user *)arg,
 			sizeof(struct v4l2_event_subscription))) {
-				rc = -EINVAL;
-				return rc;
+			rc = -EINVAL;
+			return rc;
 		}
 		rc = msm_server_v4l2_subscribe_event
 			(&config_cam->config_stat_event_queue.eventHandle,
-				 &temp_sub);
-		if (rc < 0)
+			&temp_sub);
+		if (rc < 0) {
+			pr_err("%s: cam_v4l2_subscribe_event failed rc=%d\n",
+				__func__, rc);
 			return rc;
+		}
 		break;
 
 	case VIDIOC_UNSUBSCRIBE_EVENT:
 		if (copy_from_user(&temp_sub, (void __user *)arg,
-			  sizeof(struct v4l2_event_subscription))) {
+			sizeof(struct v4l2_event_subscription))) {
 			rc = -EINVAL;
 			return rc;
 		}
 		rc = msm_server_v4l2_unsubscribe_event
 			(&config_cam->config_stat_event_queue.eventHandle,
-			 &temp_sub);
-		if (rc < 0)
+			&temp_sub);
+		if (rc < 0) {
+			pr_err("%s: server_unsubscribe_event failed rc=%d\n",
+				__func__, rc);
 			return rc;
+		}
 		break;
 
 	case VIDIOC_DQEVENT: {
@@ -2277,9 +2363,8 @@
 static int msm_open_config(struct inode *inode, struct file *fp)
 {
 	int rc;
-
-	struct msm_cam_config_dev *config_cam =
-	container_of(inode->i_cdev, struct msm_cam_config_dev, config_cdev);
+	struct msm_cam_config_dev *config_cam = container_of(inode->i_cdev,
+		struct msm_cam_config_dev, config_cdev);
 
 	D("%s: open %s\n", __func__, fp->f_path.dentry->d_name.name);
 
@@ -2292,22 +2377,27 @@
 
 	/*config_cam->isp_subdev = g_server_dev.pcam_active->mctl.isp_sdev;*/
 	/* assume there is only one active camera possible*/
-	config_cam->p_mctl = &g_server_dev.pcam_active->mctl;
+	config_cam->p_mctl =
+		msm_camera_get_mctl(g_server_dev.pcam_active->mctl_handle);
 
-	INIT_HLIST_HEAD(&config_cam->p_mctl->sync.pmem_stats);
-	spin_lock_init(&config_cam->p_mctl->sync.pmem_stats_spinlock);
+	INIT_HLIST_HEAD(&config_cam->p_mctl->stats_info.pmem_stats_list);
+	spin_lock_init(&config_cam->p_mctl->stats_info.pmem_stats_spinlock);
 
 	config_cam->p_mctl->config_device = config_cam;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 	kref_get(&config_cam->p_mctl->refcount);
+#endif
 	fp->private_data = config_cam;
 	return rc;
 }
 
 static int msm_close_config(struct inode *node, struct file *f)
 {
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 	struct msm_cam_config_dev *config_cam = f->private_data;
 	D("%s Decrementing ref count of config node ", __func__);
 	kref_put(&config_cam->p_mctl->refcount, msm_release_ion_client);
+#endif
 	return 0;
 }
 
@@ -2347,7 +2437,7 @@
 };
 
 int msm_setup_v4l2_event_queue(struct v4l2_fh *eventHandle,
-					struct video_device *pvdev)
+	struct video_device *pvdev)
 {
 	int rc = 0;
 	/* v4l2_fh support */
@@ -2357,6 +2447,7 @@
 	rc = v4l2_fh_init(eventHandle, pvdev);
 	if (rc < 0)
 		return rc;
+
 	if (eventHandle->events == NULL) {
 		rc = v4l2_event_init(eventHandle);
 		if (rc < 0)
@@ -2370,7 +2461,6 @@
 
 	v4l2_fh_add(eventHandle);
 	return rc;
-
 }
 
 static int msm_setup_config_dev(int node, char *device_name)
@@ -2391,8 +2481,8 @@
 	D("%s\n", __func__);
 
 	devno = MKDEV(MAJOR(msm_devno), dev_num+1);
-	device_config = device_create(msm_class, NULL, devno, NULL,
-					"%s%d", device_name, dev_num);
+	device_config = device_create(msm_class, NULL, devno, NULL, "%s%d",
+		device_name, dev_num);
 
 	if (IS_ERR(device_config)) {
 		rc = PTR_ERR(device_config);
@@ -2400,8 +2490,7 @@
 		goto config_setup_fail;
 	}
 
-	cdev_init(&config_cam->config_cdev,
-			&msm_fops_config);
+	cdev_init(&config_cam->config_cdev, &msm_fops_config);
 	config_cam->config_cdev.owner = THIS_MODULE;
 
 	rc = cdev_add(&config_cam->config_cdev, devno, 1);
@@ -2410,12 +2499,12 @@
 		device_destroy(msm_class, devno);
 		goto config_setup_fail;
 	}
-	g_server_dev.config_info.config_dev_name[dev_num]
-		= dev_name(device_config);
+
+	g_server_dev.config_info.config_dev_name[dev_num] =
+		dev_name(device_config);
 	D("%s Connected config device %s\n", __func__,
 		g_server_dev.config_info.config_dev_name[dev_num]);
-	g_server_dev.config_info.config_dev_id[dev_num]
-		= dev_num;
+	g_server_dev.config_info.config_dev_id[dev_num] = dev_num;
 
 	config_cam->config_stat_event_queue.pvdev = video_device_alloc();
 	if (config_cam->config_stat_event_queue.pvdev == NULL) {
@@ -2428,6 +2517,7 @@
 		config_cam->config_stat_event_queue.pvdev);
 	if (rc < 0) {
 		pr_err("%s failed to initialize event queue\n", __func__);
+		video_device_release(config_cam->config_stat_event_queue.pvdev);
 		goto config_setup_fail;
 	}
 
@@ -2436,7 +2526,175 @@
 config_setup_fail:
 	kfree(config_cam);
 	return rc;
+}
 
+static void msm_cam_server_subdev_notify(struct v4l2_subdev *sd,
+				unsigned int notification, void *arg)
+{
+	int rc = -EINVAL;
+	struct msm_sensor_ctrl_t *s_ctrl;
+	struct msm_camera_sensor_info *sinfo;
+	struct msm_camera_device_platform_data *camdev;
+	uint8_t csid_core = 0;
+
+	if (notification == NOTIFY_CID_CHANGE ||
+		notification == NOTIFY_ISPIF_STREAM ||
+		notification == NOTIFY_PCLK_CHANGE ||
+		notification == NOTIFY_CSIPHY_CFG ||
+		notification == NOTIFY_CSID_CFG ||
+		notification == NOTIFY_CSIC_CFG) {
+		s_ctrl = get_sctrl(sd);
+		sinfo = (struct msm_camera_sensor_info *) s_ctrl->sensordata;
+		camdev = sinfo->pdata;
+		csid_core = camdev->csid_core;
+	}
+
+	switch (notification) {
+	case NOTIFY_CID_CHANGE:
+		/* reconfig the ISPIF*/
+		if (g_server_dev.ispif_device) {
+			struct msm_ispif_params_list ispif_params;
+			ispif_params.len = 1;
+			ispif_params.params[0].intftype = PIX0;
+			ispif_params.params[0].cid_mask = 0x0001;
+			ispif_params.params[0].csid = csid_core;
+
+			rc = v4l2_subdev_call(
+				g_server_dev.ispif_device, core, ioctl,
+				VIDIOC_MSM_ISPIF_CFG, &ispif_params);
+			if (rc < 0)
+				return;
+		}
+		break;
+	case NOTIFY_ISPIF_STREAM:
+		/* call ISPIF stream on/off */
+		rc = v4l2_subdev_call(g_server_dev.ispif_device, video,
+				s_stream, (int)arg);
+		if (rc < 0)
+			return;
+
+		break;
+	case NOTIFY_ISP_MSG_EVT:
+	case NOTIFY_VFE_MSG_OUT:
+	case NOTIFY_VFE_MSG_STATS:
+	case NOTIFY_VFE_MSG_COMP_STATS:
+	case NOTIFY_VFE_BUF_EVT:
+	case NOTIFY_VFE_BUF_FREE_EVT:
+		if (g_server_dev.isp_subdev[0] &&
+			g_server_dev.isp_subdev[0]->isp_notify) {
+			rc = g_server_dev.isp_subdev[0]->isp_notify(
+				g_server_dev.vfe_device[0], notification, arg);
+		}
+		break;
+	case NOTIFY_VPE_MSG_EVT: {
+		struct msm_cam_media_controller *pmctl =
+		(struct msm_cam_media_controller *)
+		v4l2_get_subdev_hostdata(sd);
+		struct msm_vpe_resp *vdata = (struct msm_vpe_resp *)arg;
+		msm_mctl_pp_notify(pmctl,
+		(struct msm_mctl_pp_frame_info *)
+		vdata->extdata);
+		break;
+	}
+	case NOTIFY_VFE_IRQ:{
+		struct msm_vfe_cfg_cmd cfg_cmd;
+		struct msm_camvfe_params vfe_params;
+		cfg_cmd.cmd_type = CMD_VFE_PROCESS_IRQ;
+		vfe_params.vfe_cfg = &cfg_cmd;
+		vfe_params.data = arg;
+		rc = v4l2_subdev_call(g_server_dev.vfe_device[0],
+			core, ioctl, 0, &vfe_params);
+	}
+		break;
+	case NOTIFY_AXI_IRQ:
+		rc = v4l2_subdev_call(g_server_dev.axi_device[0],
+			core, ioctl, VIDIOC_MSM_AXI_IRQ, arg);
+		break;
+	case NOTIFY_PCLK_CHANGE:
+		if (g_server_dev.axi_device[0])
+			rc = v4l2_subdev_call(g_server_dev.axi_device[0], video,
+				s_crystal_freq, *(uint32_t *)arg, 0);
+		else
+			rc = v4l2_subdev_call(g_server_dev.vfe_device[0], video,
+				s_crystal_freq, *(uint32_t *)arg, 0);
+		break;
+	case NOTIFY_CSIPHY_CFG:
+		rc = v4l2_subdev_call(g_server_dev.csiphy_device[csid_core],
+			core, ioctl, VIDIOC_MSM_CSIPHY_CFG, arg);
+		break;
+	case NOTIFY_CSID_CFG:
+		rc = v4l2_subdev_call(g_server_dev.csid_device[csid_core],
+			core, ioctl, VIDIOC_MSM_CSID_CFG, arg);
+		break;
+	case NOTIFY_CSIC_CFG:
+		rc = v4l2_subdev_call(g_server_dev.csic_device[csid_core],
+			core, ioctl, VIDIOC_MSM_CSIC_CFG, arg);
+		break;
+	default:
+		break;
+	}
+
+	return;
+}
+
+int msm_cam_register_subdev_node(struct v4l2_subdev *sd,
+	enum msm_cam_subdev_type sdev_type, uint8_t index)
+{
+	struct video_device *vdev;
+	int err = 0;
+
+	if (sdev_type == CSIPHY_DEV) {
+		if (index >= MAX_NUM_CSIPHY_DEV)
+			return -EINVAL;
+		g_server_dev.csiphy_device[index] = sd;
+	} else if (sdev_type == CSID_DEV) {
+		if (index >= MAX_NUM_CSID_DEV)
+			return -EINVAL;
+		g_server_dev.csid_device[index] = sd;
+	} else if (sdev_type == CSIC_DEV) {
+		if (index >= MAX_NUM_CSIC_DEV)
+			return -EINVAL;
+		g_server_dev.csic_device[index] = sd;
+	} else if (sdev_type == ISPIF_DEV) {
+		g_server_dev.ispif_device = sd;
+	} else if (sdev_type == VFE_DEV) {
+		if (index >= MAX_NUM_VFE_DEV)
+			return -EINVAL;
+		g_server_dev.vfe_device[index] = sd;
+	} else if (sdev_type == VPE_DEV) {
+		if (index >= MAX_NUM_VPE_DEV)
+			return -EINVAL;
+		g_server_dev.vpe_device[index] = sd;
+	} else if (sdev_type == AXI_DEV) {
+		if (index >= MAX_NUM_AXI_DEV)
+			return -EINVAL;
+		g_server_dev.axi_device[index] = sd;
+	}
+
+	err = v4l2_device_register_subdev(&g_server_dev.v4l2_dev, sd);
+	if (err < 0)
+		return err;
+
+	/* Register a device node for every subdev marked with the
+	 * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
+	 */
+	if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
+		return err;
+
+	vdev = &sd->devnode;
+	strlcpy(vdev->name, sd->name, sizeof(vdev->name));
+	vdev->v4l2_dev = &g_server_dev.v4l2_dev;
+	vdev->fops = &v4l2_subdev_fops;
+	vdev->release = video_device_release_empty;
+	err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
+						  sd->owner);
+	if (err < 0)
+		return err;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	sd->entity.v4l.major = VIDEO_MAJOR;
+	sd->entity.v4l.minor = vdev->minor;
+#endif
+	return 0;
 }
 
 static int msm_setup_server_dev(struct platform_device *pdev)
@@ -2446,7 +2704,7 @@
 	D("%s\n", __func__);
 	g_server_dev.server_pdev = pdev;
 	g_server_dev.v4l2_dev.dev = &pdev->dev;
-
+	g_server_dev.v4l2_dev.notify = msm_cam_server_subdev_notify;
 	rc = v4l2_device_register(g_server_dev.v4l2_dev.dev,
 			&g_server_dev.v4l2_dev);
 	if (rc < 0)
@@ -2471,13 +2729,13 @@
 	video_set_drvdata(g_server_dev.video_dev, &g_server_dev);
 
 	strlcpy(g_server_dev.media_dev.model, "qcamera",
-			sizeof(g_server_dev.media_dev.model));
+		sizeof(g_server_dev.media_dev.model));
 	g_server_dev.media_dev.dev = &pdev->dev;
 	rc = media_device_register(&g_server_dev.media_dev);
 	g_server_dev.v4l2_dev.mdev = &g_server_dev.media_dev;
 
 	rc = video_register_device(g_server_dev.video_dev,
-			VFL_TYPE_GRABBER, 100);
+		VFL_TYPE_GRABBER, 100);
 
 	mutex_init(&g_server_dev.server_lock);
 	mutex_init(&g_server_dev.server_queue_lock);
@@ -2493,10 +2751,13 @@
 		&g_server_dev.server_command_queue.eventHandle,
 		g_server_dev.server_command_queue.pvdev);
 
-	if (rc < 0)
+	if (rc < 0) {
 		pr_err("%s failed to initialize event queue\n", __func__);
+		video_device_release(g_server_dev.server_command_queue.pvdev);
+		return rc;
+	}
 
-	for (i = 0; i < NUM_SERVER_QUEUE; i++) {
+	for (i = 0; i < MAX_NUM_ACTIVE_CAMERA; i++) {
 		struct msm_cam_server_queue *queue;
 		queue = &g_server_dev.server_queue[i];
 		queue->queue_active = 0;
@@ -2510,7 +2771,7 @@
 {
 	int rc = -ENOMEM;
 	struct video_device *pvdev = NULL;
-	struct i2c_client *client = v4l2_get_subdevdata(pcam->mctl.sensor_sdev);
+	struct i2c_client *client = v4l2_get_subdevdata(pcam->sensor_sdev);
 	D("%s\n", __func__);
 
 	/* first register the v4l2 device */
@@ -2529,20 +2790,20 @@
 		return rc;
 	}
 
-	strlcpy(pcam->mctl.media_dev.model, QCAMERA_NAME,
-			sizeof(pcam->mctl.media_dev.model));
-	pcam->mctl.media_dev.dev = &client->dev;
-	rc = media_device_register(&pcam->mctl.media_dev);
+	strlcpy(pcam->media_dev.model, QCAMERA_NAME,
+			sizeof(pcam->media_dev.model));
+	pcam->media_dev.dev = &client->dev;
+	rc = media_device_register(&pcam->media_dev);
 	pvdev->v4l2_dev = &pcam->v4l2_dev;
-	pcam->v4l2_dev.mdev = &pcam->mctl.media_dev;
+	pcam->v4l2_dev.mdev = &pcam->media_dev;
 
 	/* init video device's driver interface */
 	D("sensor name = %s, sizeof(pvdev->name)=%d\n",
-		pcam->mctl.sensor_sdev->name, sizeof(pvdev->name));
+		pcam->sensor_sdev->name, sizeof(pvdev->name));
 
 	/* device info - strlcpy is safer than strncpy but
 	   only if architecture supports*/
-	strlcpy(pvdev->name, pcam->mctl.sensor_sdev->name, sizeof(pvdev->name));
+	strlcpy(pvdev->name, pcam->sensor_sdev->name, sizeof(pvdev->name));
 
 	pvdev->release   = video_device_release;
 	pvdev->fops	  = &g_msm_fops;
@@ -2589,23 +2850,13 @@
 	return rc;
 }
 
-static int msm_sync_destroy(struct msm_sync *sync)
+static struct v4l2_subdev *msm_actuator_probe(
+	struct msm_actuator_info *actuator_info)
 {
-	if (sync) {
-		mutex_destroy(&sync->lock);
-		wake_lock_destroy(&sync->wake_lock);
-	}
-	return 0;
-}
-
-static int msm_actuator_probe(struct msm_actuator_info *actuator_info,
-			      struct v4l2_subdev *act_sdev,
-			      struct msm_actuator_ctrl *actctrl)
-{
-	int rc = 0;
+	struct v4l2_subdev *act_sdev;
 	struct i2c_adapter *adapter = NULL;
+	struct msm_actuator_ctrl_t *actrl;
 	void *act_client = NULL;
-	struct msm_actuator_ctrl *a_ext_ctrl = NULL;
 
 	D("%s called\n", __func__);
 
@@ -2620,14 +2871,19 @@
 	if (!act_client)
 		goto device_fail;
 
-	a_ext_ctrl = (struct msm_actuator_ctrl *)i2c_get_clientdata(act_client);
-	if (!a_ext_ctrl)
+	act_sdev = (struct v4l2_subdev *)i2c_get_clientdata(act_client);
+	if (act_sdev == NULL)
 		goto client_fail;
 
-	*actctrl = *a_ext_ctrl;
-	a_ext_ctrl->a_create_subdevice((void *)actuator_info,
-				       (void *)act_sdev);
-	return rc;
+	if (actuator_info->vcm_enable) {
+		actrl = get_actrl(act_sdev);
+		if (actrl) {
+			actrl->vcm_enable = actuator_info->vcm_enable;
+			actrl->vcm_pwd = actuator_info->vcm_pwd;
+		}
+	}
+
+	return act_sdev;
 
 client_fail:
 	i2c_unregister_device(act_client);
@@ -2635,21 +2891,44 @@
 	i2c_put_adapter(adapter);
 	adapter = NULL;
 probe_fail:
-	actctrl->a_power_up = NULL;
-	actctrl->a_power_down = NULL;
-	actctrl->a_config = NULL;
-	actctrl->a_create_subdevice = NULL;
-	return rc;
+	return NULL;
 }
 
-static int msm_sync_init(struct msm_sync *sync,
-	struct platform_device *pdev)
+static struct v4l2_subdev *msm_eeprom_probe(
+	struct msm_eeprom_info *eeprom_info)
 {
-	int rc = 0;
-	wake_lock_init(&sync->wake_lock, WAKE_LOCK_IDLE, "msm_camera");
-	sync->opencnt = 0;
-	mutex_init(&sync->lock);
-	return rc;
+	struct v4l2_subdev *eeprom_sdev;
+	struct i2c_adapter *adapter = NULL;
+	void *eeprom_client = NULL;
+
+	D("%s called\n", __func__);
+
+	if (!eeprom_info)
+		goto probe_fail;
+
+	adapter = i2c_get_adapter(eeprom_info->bus_id);
+	if (!adapter)
+		goto probe_fail;
+
+	eeprom_client = i2c_new_device(adapter, eeprom_info->board_info);
+	if (!eeprom_client)
+		goto device_fail;
+
+	eeprom_sdev = (struct v4l2_subdev *)i2c_get_clientdata(eeprom_client);
+	if (eeprom_sdev == NULL)
+		goto client_fail;
+
+	return eeprom_sdev;
+client_fail:
+	pr_err("%s client_fail\n", __func__);
+	i2c_unregister_device(eeprom_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
@@ -2661,8 +2940,6 @@
 	struct msm_camera_sensor_info *sdata;
 	struct msm_cam_v4l2_device *pcam;
 	struct msm_sensor_ctrl_t *s_ctrl;
-	struct v4l2_subdev *act_sdev = NULL;
-	struct msm_actuator_ctrl *actctrl = NULL;
 
 	D("%s for %s\n", __func__, sensor_sd->name);
 
@@ -2674,34 +2951,16 @@
 		return -ENOMEM;
 	}
 
-	pcam->mctl.sensor_sdev = sensor_sd;
+	pcam->sensor_sdev = sensor_sd;
 	s_ctrl = get_sctrl(sensor_sd);
 	sdata = (struct msm_camera_sensor_info *) s_ctrl->sensordata;
 
-	pcam->mctl.act_sdev = kzalloc(sizeof(struct v4l2_subdev),
-								  GFP_KERNEL);
-	if (!pcam->mctl.act_sdev) {
-		pr_err("%s: could not allocate mem for actuator v4l2_subdev\n",
-			   __func__);
-		kfree(pcam);
-		return -ENOMEM;
-	}
+	pcam->act_sdev = msm_actuator_probe(sdata->actuator_info);
+	pcam->eeprom_sdev = msm_eeprom_probe(sdata->eeprom_info);
 
-	act_sdev = pcam->mctl.act_sdev;
-	actctrl = &pcam->mctl.sync.actctrl;
-
-	msm_actuator_probe(sdata->actuator_info,
-					   act_sdev, actctrl);
-
-	/* setup a manager object*/
-	rc = msm_sync_init(&pcam->mctl.sync, NULL);
-	if (rc < 0)
-		goto failure;
 	D("%s: pcam =0x%p\n", __func__, pcam);
-	D("%s: &pcam->mctl.sync =0x%p\n", __func__, &pcam->mctl.sync);
 
-	pcam->mctl.sync.sdata = sdata;
-	pcam->mctl.sync.pcam_sync = pcam;
+	pcam->sdata = sdata;
 
 	/* init the user count and lock*/
 	pcam->use_count = 0;
@@ -2751,8 +3010,8 @@
 	/*Temporary solution to store info in media device structure
 	  until we can expand media device structure to support more
 	  device info*/
-	snprintf(pcam->mctl.media_dev.serial,
-			sizeof(pcam->mctl.media_dev.serial),
+	snprintf(pcam->media_dev.serial,
+			sizeof(pcam->media_dev.serial),
 			"%s-%d-%d", QCAMERA_NAME,
 			sdata->sensor_platform_info->mount_angle,
 			sdata->camera_type);
@@ -2765,15 +3024,16 @@
 		g_server_dev.camera_info.num_cameras);
 
 	/* register the subdevice, must be done for callbacks */
-	rc = v4l2_device_register_subdev(&pcam->v4l2_dev, sensor_sd);
+	rc = msm_cam_register_subdev_node(sensor_sd, SENSOR_DEV, vnode_count);
 	if (rc < 0) {
 		D("%s sensor sub device register failed\n",
 			__func__);
 		goto failure;
 	}
 
-	if (sdata->actuator_info) {
-		rc = v4l2_device_register_subdev(&pcam->v4l2_dev, act_sdev);
+	if (pcam->act_sdev) {
+		rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
+				pcam->act_sdev);
 		if (rc < 0) {
 			D("%s actuator sub device register failed\n",
 			  __func__);
@@ -2781,14 +3041,19 @@
 		}
 	}
 
+	if (pcam->eeprom_sdev) {
+		rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
+			pcam->eeprom_sdev);
+		if (rc < 0) {
+			D("%s eeprom sub device register failed\n", __func__);
+			goto failure;
+		}
+	}
+
 	pcam->vnode_id = vnode_count++;
 	return rc;
 
 failure:
-	/* mutex_destroy not needed at this moment as the associated
-	implemenation of mutex_init is not consuming resources */
-	msm_sync_destroy(&pcam->mctl.sync);
-	kfree(act_sdev);
 	kzfree(pcam);
 	return rc;
 }
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index c4373a7..04e224c 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -50,6 +50,27 @@
 #define MSM_GEMINI_DRV_NAME "msm_gemini"
 #define MSM_I2C_MUX_DRV_NAME "msm_cam_i2c_mux"
 
+#define MAX_NUM_CSIPHY_DEV 3
+#define MAX_NUM_CSID_DEV 3
+#define MAX_NUM_CSIC_DEV 3
+#define MAX_NUM_ISPIF_DEV 1
+#define MAX_NUM_VFE_DEV 2
+#define MAX_NUM_AXI_DEV 2
+#define MAX_NUM_VPE_DEV 1
+
+enum msm_cam_subdev_type {
+	CSIPHY_DEV,
+	CSID_DEV,
+	CSIC_DEV,
+	ISPIF_DEV,
+	VFE_DEV,
+	AXI_DEV,
+	VPE_DEV,
+	SENSOR_DEV,
+	ACTUATOR_DEV,
+	EEPROM_DEV,
+};
+
 /* msm queue management APIs*/
 
 #define msm_dequeue(queue, member) ({	   \
@@ -127,6 +148,8 @@
 	NOTIFY_CSID_CFG, /* arg = msm_camera_csid_params */
 	NOTIFY_CSIC_CFG, /* arg = msm_camera_csic_params */
 	NOTIFY_VFE_BUF_FREE_EVT, /* arg = msm_camera_csic_params */
+	NOTIFY_VFE_IRQ,
+	NOTIFY_AXI_IRQ,
 	NOTIFY_INVALID
 };
 
@@ -204,8 +227,6 @@
 	int (*mctl_open)(struct msm_cam_media_controller *p_mctl,
 					 const char *const apps_id);
 	int (*mctl_cb)(void);
-	int (*mctl_notify)(struct msm_cam_media_controller *p_mctl,
-			unsigned int notification, void *arg);
 	int (*mctl_cmd)(struct msm_cam_media_controller *p_mctl,
 					unsigned int cmd, unsigned long arg);
 	int (*mctl_release)(struct msm_cam_media_controller *p_mctl);
@@ -214,38 +235,38 @@
 				struct vb2_queue *q, enum v4l2_buf_type type);
 	int (*mctl_ufmt_init)(struct msm_cam_media_controller *p_mctl);
 
-	struct v4l2_fh  eventHandle; /* event queue to export events */
-	/* most-frequently accessed manager object*/
-	struct msm_sync sync;
-
-	/*Media device node*/
-	struct media_device media_dev;
-
 	/* the following reflect the HW topology information*/
-	/*mandatory*/
 	struct v4l2_subdev *sensor_sdev; /* sensor sub device */
-	struct v4l2_subdev mctl_sdev;   /*  media control sub device */
-	struct platform_device *plat_dev;
-	/*optional*/
-	struct msm_isp_ops *isp_sdev;    /* isp sub device : camif/VFE */
-	struct v4l2_subdev *vpe_sdev;    /* vpe sub device : VPE */
-	struct v4l2_subdev *flash_sdev;    /* vpe sub device : VPE */
-	struct msm_cam_config_dev *config_device;
+	struct v4l2_subdev *act_sdev; /* actuator sub device */
 	struct v4l2_subdev *csiphy_sdev; /*csiphy sub device*/
 	struct v4l2_subdev *csid_sdev; /*csid sub device*/
 	struct v4l2_subdev *csic_sdev; /*csid sub device*/
 	struct v4l2_subdev *ispif_sdev; /* ispif sub device */
-	struct v4l2_subdev *act_sdev; /* actuator sub device */
 	struct v4l2_subdev *gemini_sdev; /* gemini sub device */
+	struct v4l2_subdev *vpe_sdev; /* vpe sub device */
+	struct v4l2_subdev *axi_sdev; /* axi sub device */
+	struct v4l2_subdev *eeprom_sdev; /* eeprom sub device */
 
+	struct msm_isp_ops *isp_sdev;    /* isp sub device : camif/VFE */
+	struct msm_cam_config_dev *config_device;
+
+	/*mctl session control information*/
+	uint8_t opencnt; /*mctl ref count*/
+	const char *apps_id; /*ID for app that open this session*/
+	struct mutex lock;
+	struct wake_lock wake_lock; /*avoid low power mode when active*/
 	struct pm_qos_request_list pm_qos_req_list;
 	struct msm_mctl_pp_info pp_info;
+	struct msm_mctl_stats_t stats_info; /*stats pmem info*/
+	uint32_t vfe_output_mode; /* VFE output mode */
 	struct ion_client *client;
 	struct kref refcount;
-	/* VFE output mode.
-	* Used to interpret the Primary/Secondary messages
-	* to preview/video/main/thumbnail image types*/
-	uint32_t vfe_output_mode;
+
+	/*pcam ptr*/
+	struct msm_cam_v4l2_device *pcam_ptr;
+
+	/*sensor info*/
+	struct msm_camera_sensor_info *sdata;
 };
 
 /* abstract camera device represents a VFE and connected sensor */
@@ -253,14 +274,13 @@
 	char *config_dev_name;
 
 	/*int (*isp_init)(struct msm_cam_v4l2_device *pcam);*/
-	int (*isp_open)(struct v4l2_subdev *sd, struct v4l2_subdev *sd_vpe,
-		struct v4l2_subdev *gemini_sdev, struct msm_sync *sync);
+	int (*isp_open)(struct v4l2_subdev *sd,
+		struct msm_cam_media_controller *mctl);
 	int (*isp_config)(struct msm_cam_media_controller *pmctl,
 		 unsigned int cmd, unsigned long arg);
 	int (*isp_notify)(struct v4l2_subdev *sd,
 		unsigned int notification, void *arg);
-	void (*isp_release)(struct msm_sync *psync,
-		struct v4l2_subdev *gemini_sdev);
+	void (*isp_release)(struct v4l2_subdev *sd);
 	int (*isp_pp_cmd)(struct msm_cam_media_controller *pmctl,
 		 struct msm_mctl_pp_cmd, void *data);
 
@@ -314,57 +334,33 @@
 
 /* abstract camera device for each sensor successfully probed*/
 struct msm_cam_v4l2_device {
-	/* standard device interfaces */
-	/* parent of video device to trace back */
-	struct device dev;
-	/* sensor's platform device*/
-	struct platform_device *pdev;
-	/* V4l2 device */
-	struct v4l2_device v4l2_dev;
-	/* will be registered as /dev/video*/
-	struct video_device *pvdev;
+
+	/* device node information */
+	int vnode_id;
+	struct v4l2_device v4l2_dev; /* V4l2 device */
+	struct video_device *pvdev; /* registered as /dev/video*/
+	struct msm_cam_mctl_node mctl_node; /* node for buffer management */
+	struct media_device media_dev; /* node to get video node info*/
+
+	/* device session information */
 	int use_count;
-	/* will be used to init/release HW */
-	struct msm_cam_media_controller mctl;
-
-	/* parent device */
-	struct device *parent_dev;
-
 	struct mutex vid_lock;
+	uint32_t server_queue_idx;
+	uint32_t mctl_handle;
+	struct msm_cam_v4l2_dev_inst *dev_inst[MSM_DEV_INST_MAX];
+	struct msm_cam_v4l2_dev_inst *dev_inst_map[MSM_MAX_IMG_MODE];
+	int op_mode;
+
 	/* v4l2 format support */
 	struct msm_isp_color_fmt *usr_fmts;
 	int num_fmts;
-	/* preview or snapshot */
-	u32 mode;
-	u32 memsize;
 
-	int op_mode;
-	int vnode_id;
-	struct msm_cam_v4l2_dev_inst *dev_inst[MSM_DEV_INST_MAX];
-	struct msm_cam_v4l2_dev_inst *dev_inst_map[MSM_MAX_IMG_MODE];
-	/* native config device */
-	struct cdev cdev;
-
-	/* The message queue is used by the control thread to send commands
-	 * to the config thread, and also by the HW to send messages to the
-	 * config thread.  Thus it is the only queue that is accessed from
-	 * both interrupt and process context.
-	 */
-	/* struct msm_device_queue event_q; */
-
-	/* This queue used by the config thread to send responses back to the
-	 * control thread.  It is accessed only from a process context.
-	 * TO BE REMOVED
-	 */
-	uint32_t server_queue_idx;
-	struct msm_device_queue ctrl_q;
-
-	struct mutex lock;
-	uint8_t ctrl_data[max_control_command_size];
-	struct msm_ctrl_cmd ctrl;
-	uint32_t event_mask;
-	struct msm_cam_mctl_node mctl_node;
+	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 msm_camera_sensor_info *sdata;
 };
+
 static inline struct msm_cam_v4l2_device *to_pcam(
 	struct v4l2_device *v4l2_dev)
 {
@@ -388,7 +384,7 @@
 	struct msm_mem_map_info mem_map;
 };
 
-#define NUM_SERVER_QUEUE 5
+#define MAX_NUM_ACTIVE_CAMERA 2
 
 struct msm_cam_server_queue {
 	uint32_t queue_active;
@@ -399,6 +395,11 @@
 	uint32_t evt_id;
 };
 
+struct msm_cam_server_mctl_inst {
+	struct msm_cam_media_controller mctl;
+	uint32_t handle;
+};
+
 /* abstract camera server device for all sensor successfully probed*/
 struct msm_cam_server_dev {
 
@@ -422,9 +423,12 @@
 	/* This queue used by the config thread to send responses back to the
 	 * control thread.  It is accessed only from a process context.
 	 */
-	struct msm_cam_server_queue server_queue[NUM_SERVER_QUEUE];
+	struct msm_cam_server_queue server_queue[MAX_NUM_ACTIVE_CAMERA];
 	uint32_t server_evt_id;
 
+	struct msm_cam_server_mctl_inst mctl[MAX_NUM_ACTIVE_CAMERA];
+	uint32_t mctl_handle_cnt;
+
 	int use_count;
 	/* all the registered ISP subdevice*/
 	struct msm_isp_ops *isp_subdev[MSM_MAX_CAMERA_CONFIGS];
@@ -432,6 +436,14 @@
 	struct msm_mctl_node_info mctl_node_info;
 	struct mutex server_lock;
 	struct mutex server_queue_lock;
+	/*v4l2 subdevs*/
+	struct v4l2_subdev *csiphy_device[MAX_NUM_CSIPHY_DEV];
+	struct v4l2_subdev *csid_device[MAX_NUM_CSID_DEV];
+	struct v4l2_subdev *csic_device[MAX_NUM_CSIC_DEV];
+	struct v4l2_subdev *ispif_device;
+	struct v4l2_subdev *vfe_device[MAX_NUM_VFE_DEV];
+	struct v4l2_subdev *axi_device[MAX_NUM_AXI_DEV];
+	struct v4l2_subdev *vpe_device[MAX_NUM_VPE_DEV];
 };
 
 /* camera server related functions */
@@ -447,7 +459,8 @@
 int msm_sensor_register(struct v4l2_subdev *);
 int msm_isp_init_module(int g_num_config_nodes);
 
-int msm_mctl_init_module(struct msm_cam_v4l2_device *pcam);
+int msm_mctl_init(struct msm_cam_v4l2_device *pcam);
+int msm_mctl_free(struct msm_cam_v4l2_device *pcam);
 int msm_mctl_buf_init(struct msm_cam_v4l2_device *pcam);
 int msm_mctl_init_user_formats(struct msm_cam_v4l2_device *pcam);
 int msm_mctl_buf_done(struct msm_cam_media_controller *pmctl,
@@ -475,25 +488,24 @@
 					struct msm_pmem_region *reg,
 					uint8_t maxcount);
 unsigned long msm_pmem_stats_vtop_lookup(
-				struct msm_sync *sync,
+				struct msm_cam_media_controller *mctl,
 				unsigned long buffer,
 				int fd);
-unsigned long msm_pmem_stats_ptov_lookup(struct msm_sync *sync,
-						unsigned long addr, int *fd);
+unsigned long msm_pmem_stats_ptov_lookup(
+	struct msm_cam_media_controller *mctl,
+	unsigned long addr, int *fd);
 
-int msm_vfe_subdev_init(struct v4l2_subdev *sd, void *data,
-					struct platform_device *pdev);
-void msm_vfe_subdev_release(struct platform_device *pdev);
+int msm_vfe_subdev_init(struct v4l2_subdev *sd,
+			struct msm_cam_media_controller *mctl);
+void msm_vfe_subdev_release(struct v4l2_subdev *sd);
 
 int msm_isp_subdev_ioctl(struct v4l2_subdev *sd,
 	struct msm_vfe_cfg_cmd *cfgcmd, void *data);
-int msm_vpe_subdev_init(struct v4l2_subdev *sd, void *data,
-	struct platform_device *pdev);
-int msm_gemini_subdev_init(struct v4l2_subdev *sd);
-void msm_vpe_subdev_release(struct platform_device *pdev);
+int msm_vpe_subdev_init(struct v4l2_subdev *sd,
+			struct msm_cam_media_controller *mctl);
+int msm_gemini_subdev_init(struct v4l2_subdev *gemini_sd);
+void msm_vpe_subdev_release(void);
 void msm_gemini_subdev_release(struct v4l2_subdev *gemini_sd);
-int msm_isp_subdev_ioctl_vpe(struct v4l2_subdev *isp_subdev,
-	struct msm_mctl_pp_cmd *cmd, void *data);
 int msm_mctl_is_pp_msg_type(struct msm_cam_media_controller *p_mctl,
 	int msg_type);
 int msm_mctl_do_pp(struct msm_cam_media_controller *p_mctl,
@@ -549,6 +561,11 @@
 int msm_mctl_pp_mctl_divert_done(struct msm_cam_media_controller *p_mctl,
 					void __user *arg);
 void msm_release_ion_client(struct kref *ref);
+int msm_cam_register_subdev_node(struct v4l2_subdev *sd,
+			enum msm_cam_subdev_type sdev_type, uint8_t index);
+uint32_t msm_camera_get_mctl_handle(void);
+struct msm_cam_media_controller *msm_camera_get_mctl(uint32_t handle);
+void msm_camera_free_mctl(uint32_t handle);
 #endif /* __KERNEL__ */
 
 #endif /* _MSM_H */
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 59e37dd..d678d86 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -150,9 +150,9 @@
 	struct msm_free_buf free_buf, temp_free_buf;
 	struct msm_camvfe_params vfe_params;
 	struct msm_vfe_cfg_cmd cfgcmd;
-	struct msm_sync *sync =
-		(struct msm_sync *)v4l2_get_subdev_hostdata(sd);
-	struct msm_cam_v4l2_device *pcam = sync->pcam_sync;
+	struct msm_cam_media_controller *pmctl =
+		(struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
+	struct msm_cam_v4l2_device *pcam = pmctl->pcam_ptr;
 
 	int vfe_id = vdata->evt_msg.msg_id;
 	if (!pcam) {
@@ -161,7 +161,7 @@
 		return rc;
 	}
 	/* Convert the vfe msg to the image mode */
-	image_mode = msm_isp_vfe_msg_to_img_mode(&pcam->mctl, vfe_id);
+	image_mode = msm_isp_vfe_msg_to_img_mode(pmctl, vfe_id);
 	BUG_ON(image_mode < 0);
 	switch (vdata->type) {
 	case VFE_MSG_V32_START:
@@ -169,14 +169,14 @@
 	case VFE_MSG_V2X_PREVIEW:
 		D("%s Got V32_START_*: Getting ping addr id = %d",
 						__func__, vfe_id);
-		msm_mctl_reserve_free_buf(&pcam->mctl, NULL,
+		msm_mctl_reserve_free_buf(pmctl, NULL,
 					image_mode, &free_buf);
 		cfgcmd.cmd_type = CMD_CONFIG_PING_ADDR;
 		cfgcmd.value = &vfe_id;
 		vfe_params.vfe_cfg = &cfgcmd;
 		vfe_params.data = (void *)&free_buf;
 		rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
-		msm_mctl_reserve_free_buf(&pcam->mctl, NULL,
+		msm_mctl_reserve_free_buf(pmctl, NULL,
 					image_mode, &free_buf);
 		cfgcmd.cmd_type = CMD_CONFIG_PONG_ADDR;
 		cfgcmd.value = &vfe_id;
@@ -188,7 +188,7 @@
 	case VFE_MSG_V2X_CAPTURE:
 		pr_debug("%s Got V32_CAPTURE: getting buffer for id = %d",
 						__func__, vfe_id);
-		msm_mctl_reserve_free_buf(&pcam->mctl, NULL,
+		msm_mctl_reserve_free_buf(pmctl, NULL,
 					image_mode, &free_buf);
 		cfgcmd.cmd_type = CMD_CONFIG_PING_ADDR;
 		cfgcmd.value = &vfe_id;
@@ -196,7 +196,7 @@
 		vfe_params.data = (void *)&free_buf;
 		rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
 		temp_free_buf = free_buf;
-		if (msm_mctl_reserve_free_buf(&pcam->mctl, NULL,
+		if (msm_mctl_reserve_free_buf(pmctl, NULL,
 					image_mode, &free_buf)) {
 			/* Write the same buffer into PONG */
 			free_buf = temp_free_buf;
@@ -234,7 +234,7 @@
 	case VFE_MSG_OUTPUT_IRQ:
 		D("%s Got OUTPUT_IRQ: Getting free buf id = %d",
 						__func__, vfe_id);
-		msm_mctl_reserve_free_buf(&pcam->mctl, NULL,
+		msm_mctl_reserve_free_buf(pmctl, NULL,
 					image_mode, &free_buf);
 		cfgcmd.cmd_type = CMD_CONFIG_FREE_BUF_ADDR;
 		cfgcmd.value = &vfe_id;
@@ -259,12 +259,11 @@
 	int rc = 0;
 	struct v4l2_event v4l2_evt;
 	struct msm_isp_event_ctrl *isp_event;
-	struct msm_sync *sync =
-		(struct msm_sync *)v4l2_get_subdev_hostdata(sd);
-	struct msm_cam_media_controller *pmctl = &sync->pcam_sync->mctl;
+	struct msm_cam_media_controller *pmctl =
+		(struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
 	struct msm_free_buf buf;
 
-	if (!sync) {
+	if (!pmctl) {
 		pr_err("%s: no context in dsp callback.\n", __func__);
 		rc = -EINVAL;
 		return rc;
@@ -347,17 +346,17 @@
 		struct msm_stats_buf *stats_buf = NULL;
 
 		isp_event->isp_data.isp_msg.msg_id = MSG_ID_STATS_COMPOSITE;
-		stats->aec.buff = msm_pmem_stats_ptov_lookup(&pmctl->sync,
+		stats->aec.buff = msm_pmem_stats_ptov_lookup(pmctl,
 					stats->aec.buff, &(stats->aec.fd));
-		stats->awb.buff = msm_pmem_stats_ptov_lookup(&pmctl->sync,
+		stats->awb.buff = msm_pmem_stats_ptov_lookup(pmctl,
 					stats->awb.buff, &(stats->awb.fd));
-		stats->af.buff = msm_pmem_stats_ptov_lookup(&pmctl->sync,
+		stats->af.buff = msm_pmem_stats_ptov_lookup(pmctl,
 					stats->af.buff, &(stats->af.fd));
-		stats->ihist.buff = msm_pmem_stats_ptov_lookup(&pmctl->sync,
+		stats->ihist.buff = msm_pmem_stats_ptov_lookup(pmctl,
 					stats->ihist.buff, &(stats->ihist.fd));
-		stats->rs.buff = msm_pmem_stats_ptov_lookup(&pmctl->sync,
+		stats->rs.buff = msm_pmem_stats_ptov_lookup(pmctl,
 					stats->rs.buff, &(stats->rs.fd));
-		stats->cs.buff = msm_pmem_stats_ptov_lookup(&pmctl->sync,
+		stats->cs.buff = msm_pmem_stats_ptov_lookup(pmctl,
 					stats->cs.buff, &(stats->cs.fd));
 
 		stats_buf = kmalloc(sizeof(struct msm_stats_buf), GFP_ATOMIC);
@@ -379,7 +378,7 @@
 		isp_event->isp_data.isp_msg.msg_id = isp_stats->id;
 		isp_event->isp_data.isp_msg.frame_id =
 			isp_stats->frameCounter;
-		stats.buffer = msm_pmem_stats_ptov_lookup(&pmctl->sync,
+		stats.buffer = msm_pmem_stats_ptov_lookup(pmctl,
 						isp_stats->buffer,
 						&(stats.fd));
 		switch (isp_stats->id) {
@@ -448,68 +447,41 @@
 	return rc;
 }
 
-static int msm_isp_notify_vpe(struct v4l2_subdev *sd, void *arg)
-{
-	struct msm_sync *sync =
-		(struct msm_sync *)v4l2_get_subdev_hostdata(sd);
-	struct msm_vpe_resp *vdata = (struct msm_vpe_resp *)arg;
-	if (sync == NULL) {
-		pr_err("%s: VPE subdev hostdata not set\n", __func__);
-		return -EINVAL;
-	}
-
-	msm_mctl_pp_notify(&sync->pcam_sync->mctl,
-		(struct msm_mctl_pp_frame_info *)vdata->extdata);
-	return 0;
-}
-
 static int msm_isp_notify(struct v4l2_subdev *sd,
 	unsigned int notification, void *arg)
 {
-	if (notification == NOTIFY_VPE_MSG_EVT)
-		return msm_isp_notify_vpe(sd, arg);
-	else
-		return msm_isp_notify_vfe(sd, notification, arg);
+	return msm_isp_notify_vfe(sd, notification, arg);
 }
 
 /* This function is called by open() function, so we need to init HW*/
 static int msm_isp_open(struct v4l2_subdev *sd,
-	struct v4l2_subdev *sd_vpe, struct v4l2_subdev *gemini_sdev,
-	struct msm_sync *sync)
+	struct msm_cam_media_controller *mctl)
 {
 	/* init vfe and senor, register sync callbacks for init*/
 	int rc = 0;
 	D("%s\n", __func__);
-	if (!sync) {
+	if (!mctl) {
 		pr_err("%s: param is NULL", __func__);
 		return -EINVAL;
 	}
 
-
-	rc = msm_vfe_subdev_init(sd, sync, sync->pdev);
+	rc = msm_vfe_subdev_init(sd, mctl);
 	if (rc < 0) {
 		pr_err("%s: vfe_init failed at %d\n",
 					__func__, rc);
 	}
-	D("%s: init vpe subdev", __func__);
-	rc = msm_vpe_subdev_init(sd_vpe, sync, sync->pdev);
-	if (rc < 0) {
-		pr_err("%s: vpe_init failed at %d\n",
-					__func__, rc);
-	}
 	return rc;
 }
 
-static void msm_isp_release(struct msm_sync *psync,
-		struct v4l2_subdev *gemini_sdev)
+static void msm_isp_release(
+	struct v4l2_subdev *sd)
 {
 	D("%s\n", __func__);
-	msm_vfe_subdev_release(psync->pdev);
-	msm_vpe_subdev_release(psync->pdev);
+	msm_vfe_subdev_release(sd);
 }
 
 static int msm_config_vfe(struct v4l2_subdev *sd,
-	struct msm_sync *sync, void __user *arg)
+	struct msm_cam_media_controller *mctl, void __user *arg)
 {
 	struct msm_vfe_cfg_cmd cfgcmd;
 	struct msm_pmem_region region[8];
@@ -525,9 +497,10 @@
 	switch (cfgcmd.cmd_type) {
 	case CMD_STATS_AF_ENABLE:
 		axi_data.bufnum1 =
-			msm_pmem_region_lookup(&sync->pmem_stats,
-					MSM_PMEM_AF, &region[0],
-					NUM_STAT_OUTPUT_BUFFERS);
+			msm_pmem_region_lookup(
+				&mctl->stats_info.pmem_stats_list,
+				MSM_PMEM_AF, &region[0],
+				NUM_STAT_OUTPUT_BUFFERS);
 		if (!axi_data.bufnum1) {
 			pr_err("%s %d: pmem region lookup error\n",
 				__func__, __LINE__);
@@ -538,9 +511,10 @@
 							&axi_data);
 	case CMD_STATS_AEC_ENABLE:
 		axi_data.bufnum1 =
-			msm_pmem_region_lookup(&sync->pmem_stats,
-			MSM_PMEM_AEC, &region[0],
-			NUM_STAT_OUTPUT_BUFFERS);
+			msm_pmem_region_lookup(
+				&mctl->stats_info.pmem_stats_list,
+				MSM_PMEM_AEC, &region[0],
+				NUM_STAT_OUTPUT_BUFFERS);
 		if (!axi_data.bufnum1) {
 			pr_err("%s %d: pmem region lookup error\n",
 				__func__, __LINE__);
@@ -551,9 +525,10 @@
 							&axi_data);
 	case CMD_STATS_AWB_ENABLE:
 		axi_data.bufnum1 =
-			msm_pmem_region_lookup(&sync->pmem_stats,
-			MSM_PMEM_AWB, &region[0],
-			NUM_STAT_OUTPUT_BUFFERS);
+			msm_pmem_region_lookup(
+				&mctl->stats_info.pmem_stats_list,
+				MSM_PMEM_AWB, &region[0],
+				NUM_STAT_OUTPUT_BUFFERS);
 		if (!axi_data.bufnum1) {
 			pr_err("%s %d: pmem region lookup error\n",
 				__func__, __LINE__);
@@ -564,9 +539,10 @@
 							&axi_data);
 	case CMD_STATS_AEC_AWB_ENABLE:
 		axi_data.bufnum1 =
-			msm_pmem_region_lookup(&sync->pmem_stats,
-			MSM_PMEM_AEC_AWB, &region[0],
-			NUM_STAT_OUTPUT_BUFFERS);
+			msm_pmem_region_lookup(
+				&mctl->stats_info.pmem_stats_list,
+				MSM_PMEM_AEC_AWB, &region[0],
+				NUM_STAT_OUTPUT_BUFFERS);
 		if (!axi_data.bufnum1) {
 			pr_err("%s %d: pmem region lookup error\n",
 				__func__, __LINE__);
@@ -577,9 +553,10 @@
 							&axi_data);
 	case CMD_STATS_IHIST_ENABLE:
 		axi_data.bufnum1 =
-			msm_pmem_region_lookup(&sync->pmem_stats,
-			MSM_PMEM_IHIST, &region[0],
-			NUM_STAT_OUTPUT_BUFFERS);
+			msm_pmem_region_lookup(
+				&mctl->stats_info.pmem_stats_list,
+				MSM_PMEM_IHIST, &region[0],
+				NUM_STAT_OUTPUT_BUFFERS);
 		if (!axi_data.bufnum1) {
 			pr_err("%s %d: pmem region lookup error\n",
 				__func__, __LINE__);
@@ -590,9 +567,10 @@
 							&axi_data);
 	case CMD_STATS_RS_ENABLE:
 		axi_data.bufnum1 =
-			msm_pmem_region_lookup(&sync->pmem_stats,
-			MSM_PMEM_RS, &region[0],
-			NUM_STAT_OUTPUT_BUFFERS);
+			msm_pmem_region_lookup(
+				&mctl->stats_info.pmem_stats_list,
+				MSM_PMEM_RS, &region[0],
+				NUM_STAT_OUTPUT_BUFFERS);
 		if (!axi_data.bufnum1) {
 			pr_err("%s %d: pmem region lookup error\n",
 				__func__, __LINE__);
@@ -603,9 +581,10 @@
 							&axi_data);
 	case CMD_STATS_CS_ENABLE:
 		axi_data.bufnum1 =
-			msm_pmem_region_lookup(&sync->pmem_stats,
-			MSM_PMEM_CS, &region[0],
-			NUM_STAT_OUTPUT_BUFFERS);
+			msm_pmem_region_lookup(
+				&mctl->stats_info.pmem_stats_list,
+				MSM_PMEM_CS, &region[0],
+				NUM_STAT_OUTPUT_BUFFERS);
 		if (!axi_data.bufnum1) {
 			pr_err("%s %d: pmem region lookup error\n",
 				__func__, __LINE__);
@@ -626,92 +605,8 @@
 	return -EINVAL;
 }
 
-static int msm_vpe_frame_cfg(struct msm_sync *sync,
-				void *cfgcmdin)
-{
-	int rc = -EIO;
-	struct axidata axi_data;
-	void *data = &axi_data;
-	struct msm_pmem_region region[8];
-	int pmem_type;
-
-	struct msm_vpe_cfg_cmd *cfgcmd;
-	cfgcmd = (struct msm_vpe_cfg_cmd *)cfgcmdin;
-
-	memset(&axi_data, 0, sizeof(axi_data));
-	CDBG("In vpe_frame_cfg cfgcmd->cmd_type = %d\n",
-		cfgcmd->cmd_type);
-	switch (cfgcmd->cmd_type) {
-	case CMD_AXI_CFG_VPE:
-		pmem_type = MSM_PMEM_VIDEO_VPE;
-		axi_data.bufnum1 =
-			msm_pmem_region_lookup_2(&sync->pmem_frames, pmem_type,
-								&region[0], 8);
-		CDBG("axi_data.bufnum1 = %d\n", axi_data.bufnum1);
-		if (!axi_data.bufnum1) {
-			pr_err("%s %d: pmem region lookup error\n",
-				__func__, __LINE__);
-			return -EINVAL;
-		}
-		pmem_type = MSM_PMEM_VIDEO;
-		break;
-	default:
-		pr_err("%s: unknown command type %d\n",
-			__func__, cfgcmd->cmd_type);
-		break;
-	}
-	axi_data.region = &region[0];
-	CDBG("out vpe_frame_cfg cfgcmd->cmd_type = %d\n",
-		cfgcmd->cmd_type);
-	/* send the AXI configuration command to driver */
-	if (sync->vpefn.vpe_config)
-		rc = sync->vpefn.vpe_config(cfgcmd, data);
-	return rc;
-}
-
-static int msm_stats_axi_cfg(struct v4l2_subdev *sd,
-		struct msm_sync *sync, struct msm_vfe_cfg_cmd *cfgcmd)
-{
-	int rc = -EIO;
-	struct axidata axi_data;
-	void *data = &axi_data;
-	struct msm_pmem_region region[3];
-	int pmem_type = MSM_PMEM_MAX;
-
-	memset(&axi_data, 0, sizeof(axi_data));
-
-	switch (cfgcmd->cmd_type) {
-	case CMD_STATS_AF_AXI_CFG:
-		pmem_type = MSM_PMEM_AF;
-		break;
-	case CMD_GENERAL:
-		data = NULL;
-		break;
-	default:
-		pr_err("%s: unknown command type %d\n",
-			__func__, cfgcmd->cmd_type);
-		return -EINVAL;
-	}
-
-	if (cfgcmd->cmd_type != CMD_GENERAL) {
-		axi_data.bufnum1 =
-			msm_pmem_region_lookup(&sync->pmem_stats, pmem_type,
-				&region[0], NUM_STAT_OUTPUT_BUFFERS);
-		if (!axi_data.bufnum1) {
-			pr_err("%s %d: pmem region lookup error\n",
-				__func__, __LINE__);
-			return -EINVAL;
-		}
-		axi_data.region = &region[0];
-	}
-
-	/* send the AEC/AWB STATS configuration command to driver */
-	rc = msm_isp_subdev_ioctl(sd, cfgcmd, data);
-	return rc;
-}
-
 static int msm_axi_config(struct v4l2_subdev *sd,
-			struct msm_sync *sync, void __user *arg)
+		struct msm_cam_media_controller *mctl, void __user *arg)
 {
 	struct msm_vfe_cfg_cmd cfgcmd;
 
@@ -721,15 +616,10 @@
 	}
 
 	switch (cfgcmd.cmd_type) {
-	case CMD_AXI_CFG_VIDEO:
-	case CMD_AXI_CFG_PREVIEW:
-	case CMD_AXI_CFG_SNAP:
-	case CMD_AXI_CFG_ZSL:
-	case CMD_AXI_CFG_VIDEO_ALL_CHNLS:
-	case CMD_AXI_CFG_ZSL_ALL_CHNLS:
-	case CMD_RAW_PICT_AXI_CFG:
 	case CMD_AXI_CFG_PRIM:
 	case CMD_AXI_CFG_SEC:
+	case CMD_AXI_CFG_ZSL:
+	case CMD_RAW_PICT_AXI_CFG:
 	case CMD_AXI_CFG_PRIM_ALL_CHNLS:
 	case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC:
 	case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC_ALL_CHNLS:
@@ -739,13 +629,6 @@
 		 * controller free queue.
 		 */
 		return msm_isp_subdev_ioctl(sd, &cfgcmd, NULL);
-	case CMD_AXI_CFG_VPE:
-		return 0;
-		return msm_vpe_frame_cfg(sync, (void *)&cfgcmd);
-
-	case CMD_STATS_AXI_CFG:
-	case CMD_STATS_AF_AXI_CFG:
-		return msm_stats_axi_cfg(sd, sync, &cfgcmd);
 
 	default:
 		pr_err("%s: unknown command type %d\n",
@@ -757,39 +640,8 @@
 	return 0;
 }
 
-static int msm_set_crop(struct msm_sync *sync, void __user *arg)
-{
-	struct crop_info crop;
-
-	if (copy_from_user(&crop,
-				arg,
-				sizeof(struct crop_info))) {
-		ERR_COPY_FROM_USER();
-		return -EFAULT;
-	}
-
-	if (!sync->croplen) {
-		sync->cropinfo = kmalloc(crop.len, GFP_KERNEL);
-		if (!sync->cropinfo)
-			return -ENOMEM;
-	} else if (sync->croplen < crop.len)
-		return -EINVAL;
-
-	if (copy_from_user(sync->cropinfo,
-				crop.info,
-				crop.len)) {
-		ERR_COPY_FROM_USER();
-		kfree(sync->cropinfo);
-		return -EFAULT;
-	}
-
-	sync->croplen = crop.len;
-
-	return 0;
-}
-
 static int msm_put_stats_buffer(struct v4l2_subdev *sd,
-			struct msm_sync *sync, void __user *arg)
+			struct msm_cam_media_controller *mctl, void __user *arg)
 {
 	int rc = -EIO;
 
@@ -804,7 +656,7 @@
 	}
 
 	CDBG("%s\n", __func__);
-	pphy = msm_pmem_stats_vtop_lookup(sync, buf.buffer, buf.fd);
+	pphy = msm_pmem_stats_vtop_lookup(mctl, buf.buffer, buf.fd);
 
 	if (pphy != 0) {
 		if (buf.type == STAT_AF)
@@ -862,27 +714,16 @@
 
 	case MSM_CAM_IOCTL_CONFIG_VFE:
 		/* Coming from config thread for update */
-		rc = msm_config_vfe(sd, &pmctl->sync, argp);
-		break;
-
-	case MSM_CAM_IOCTL_CONFIG_VPE:
-		/* Coming from config thread for update */
-		/*rc = msm_config_vpe(pmsm->sync, argp);*/
-		rc = 0;
+		rc = msm_config_vfe(sd, pmctl, argp);
 		break;
 
 	case MSM_CAM_IOCTL_AXI_CONFIG:
-	case MSM_CAM_IOCTL_AXI_VPE_CONFIG:
 		D("Received MSM_CAM_IOCTL_AXI_CONFIG\n");
-		rc = msm_axi_config(sd, &pmctl->sync, argp);
-		break;
-
-	case MSM_CAM_IOCTL_SET_CROP:
-		rc = msm_set_crop(&pmctl->sync, argp);
+		rc = msm_axi_config(sd, pmctl, argp);
 		break;
 
 	case MSM_CAM_IOCTL_RELEASE_STATS_BUFFER:
-		rc = msm_put_stats_buffer(sd, &pmctl->sync, argp);
+		rc = msm_put_stats_buffer(sd, pmctl, argp);
 		break;
 
 	default:
@@ -945,15 +786,3 @@
 	vfe_params.data = data;
 	return v4l2_subdev_call(isp_subdev, core, ioctl, 0, &vfe_params);
 }
-
-int msm_isp_subdev_ioctl_vpe(struct v4l2_subdev *isp_subdev,
-	struct msm_mctl_pp_cmd *cmd, void *data)
-{
-	int rc = 0;
-	struct msm_mctl_pp_params parm;
-	parm.cmd = cmd;
-	parm.data = data;
-	rc = v4l2_subdev_call(isp_subdev, core, ioctl, 0, &parm);
-	return rc;
-}
-
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 37a1ff2..e878063 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -33,6 +33,10 @@
 #include "msm_csiphy.h"
 #include "msm_ispif.h"
 #include "msm_sensor.h"
+#include "msm_actuator.h"
+#include "msm_vpe.h"
+#include "msm_vfe32.h"
+#include "msm_camera_eeprom.h"
 
 #ifdef CONFIG_MSM_CAMERA_DEBUG
 #define D(fmt, args...) pr_debug("msm_mctl: " fmt, ##args)
@@ -127,57 +131,14 @@
 
 };
 
-/*
- *  V4l2 subdevice operations
- */
-static	int mctl_subdev_log_status(struct v4l2_subdev *sd)
-{
-	return -EINVAL;
-}
-
-static long mctl_subdev_ioctl(struct v4l2_subdev *sd,
-				 unsigned int cmd, void *arg)
-{
-	struct msm_cam_media_controller *pmctl = NULL;
-	if (!sd) {
-		pr_err("%s: param is NULL", __func__);
-		return -EINVAL;
-	} else
-		pmctl = (struct msm_cam_media_controller *)
-		v4l2_get_subdevdata(sd);
-
-
-	return -EINVAL;
-}
-
-
-static int mctl_subdev_g_mbus_fmt(struct v4l2_subdev *sd,
-					 struct v4l2_mbus_framefmt *mf)
-{
-	return -EINVAL;
-}
-
-static struct v4l2_subdev_core_ops mctl_subdev_core_ops = {
-	.log_status = mctl_subdev_log_status,
-	.ioctl = mctl_subdev_ioctl,
-};
-
-static struct v4l2_subdev_video_ops mctl_subdev_video_ops = {
-	.g_mbus_fmt = mctl_subdev_g_mbus_fmt,
-};
-
-static struct v4l2_subdev_ops mctl_subdev_ops = {
-	.core = &mctl_subdev_core_ops,
-	.video  = &mctl_subdev_video_ops,
-};
-
-static int msm_get_sensor_info(struct msm_sync *sync,
-				void __user *arg)
+static int msm_get_sensor_info(
+	struct msm_cam_media_controller *mctl,
+	void __user *arg)
 {
 	int rc = 0;
 	struct msm_camsensor_info info;
 	struct msm_camera_sensor_info *sdata;
-	struct msm_cam_v4l2_device *pcam = sync->pcam_sync;
+	struct msm_cam_v4l2_device *pcam = mctl->pcam_ptr;
 	if (copy_from_user(&info,
 			arg,
 			sizeof(struct msm_camsensor_info))) {
@@ -185,7 +146,7 @@
 		return -EFAULT;
 	}
 
-	sdata = sync->sdata;
+	sdata = mctl->sdata;
 	D("%s: sensor_name %s\n", __func__, sdata->sensor_name);
 
 	memcpy(&info.name[0], sdata->sensor_name, MAX_SENSOR_NAME);
@@ -209,110 +170,6 @@
 	return rc;
 }
 
-/* called by other subdev to notify any changes*/
-
-static int msm_mctl_notify(struct msm_cam_media_controller *p_mctl,
-	unsigned int notification, void *arg)
-{
-	int rc = -EINVAL;
-	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(p_mctl->sensor_sdev);
-	struct msm_camera_sensor_info *sinfo =
-		(struct msm_camera_sensor_info *) s_ctrl->sensordata;
-	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
-	uint8_t csid_core = camdev->csid_core;
-	switch (notification) {
-	case NOTIFY_CID_CHANGE:
-		/* reconfig the ISPIF*/
-		if (p_mctl->ispif_sdev) {
-			struct msm_ispif_params_list ispif_params;
-			ispif_params.len = 1;
-			ispif_params.params[0].intftype = PIX0;
-			ispif_params.params[0].cid_mask = 0x0001;
-			ispif_params.params[0].csid = csid_core;
-
-			rc = v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl,
-				VIDIOC_MSM_ISPIF_CFG, &ispif_params);
-		} else {
-			pr_err("%s: invalid ispif_sdev\n", __func__);
-		}
-		break;
-	case NOTIFY_ISPIF_STREAM:
-		/* call ISPIF stream on/off */
-		if (p_mctl->ispif_sdev) {
-			rc = v4l2_subdev_call(p_mctl->ispif_sdev, video,
-					s_stream, (int)arg);
-		} else {
-			pr_err("%s: invalid ispif_sdev\n", __func__);
-		}
-
-		break;
-	case NOTIFY_ISP_MSG_EVT:
-	case NOTIFY_VFE_MSG_OUT:
-	case NOTIFY_VFE_MSG_STATS:
-	case NOTIFY_VFE_MSG_COMP_STATS:
-	case NOTIFY_VFE_BUF_EVT:
-	case NOTIFY_VFE_BUF_FREE_EVT:
-		if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_notify) {
-			rc = p_mctl->isp_sdev->isp_notify(
-				p_mctl->isp_sdev->sd, notification, arg);
-		} else {
-			pr_err("%s: invalid isp_sdev\n", __func__);
-		}
-
-		break;
-	case NOTIFY_VPE_MSG_EVT:
-		if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_notify) {
-			rc = p_mctl->isp_sdev->isp_notify(
-				p_mctl->isp_sdev->sd_vpe, notification, arg);
-		} else {
-			pr_err("%s: invalid isp_sdev\n", __func__);
-		}
-
-		break;
-	case NOTIFY_PCLK_CHANGE:
-		if (p_mctl->isp_sdev && p_mctl->isp_sdev->sd) {
-			rc = v4l2_subdev_call(p_mctl->isp_sdev->sd, video,
-					s_crystal_freq, *(uint32_t *)arg, 0);
-		} else {
-			pr_err("%s: invalid ispif_sdev\n", __func__);
-		}
-
-		break;
-	case NOTIFY_CSIPHY_CFG:
-		if (p_mctl->csiphy_sdev) {
-			rc = v4l2_subdev_call(p_mctl->csiphy_sdev,
-					core, ioctl, VIDIOC_MSM_CSIPHY_CFG,
-					arg);
-		} else {
-			pr_err("%s: invalid csiphy_sdev\n", __func__);
-		}
-
-		break;
-	case NOTIFY_CSID_CFG:
-		if (p_mctl->csid_sdev) {
-			rc = v4l2_subdev_call(p_mctl->csid_sdev,
-					core, ioctl, VIDIOC_MSM_CSID_CFG, arg);
-		} else {
-			pr_err("%s: invalid csid_sdev\n", __func__);
-		}
-
-		break;
-	case NOTIFY_CSIC_CFG:
-		if (p_mctl->csic_sdev) {
-			rc = v4l2_subdev_call(p_mctl->csic_sdev,
-					core, ioctl, VIDIOC_MSM_CSIC_CFG, arg);
-		} else {
-			pr_err("%s: invalid csic_sdev\n", __func__);
-		}
-
-		break;
-	default:
-		break;
-	}
-
-	return rc;
-}
-
 static int msm_mctl_set_vfe_output_mode(struct msm_cam_media_controller
 					*p_mctl, void __user *arg)
 {
@@ -345,7 +202,7 @@
 	switch (cmd) {
 		/* sensor config*/
 	case MSM_CAM_IOCTL_GET_SENSOR_INFO:
-			rc = msm_get_sensor_info(&p_mctl->sync, argp);
+			rc = msm_get_sensor_info(p_mctl, argp);
 			break;
 
 	case MSM_CAM_IOCTL_SENSOR_IO_CFG:
@@ -394,8 +251,6 @@
 
 	case MSM_CAM_IOCTL_GET_ACTUATOR_INFO: {
 		struct msm_actuator_cfg_data cdata;
-		CDBG("%s: act_config: %p\n", __func__,
-			p_mctl->sync.actctrl.a_config);
 		if (copy_from_user(&cdata,
 			(void *)argp,
 			sizeof(struct msm_actuator_cfg_data))) {
@@ -405,10 +260,10 @@
 		cdata.is_af_supported = 0;
 		rc = 0;
 
-		if (p_mctl->sync.actctrl.a_config) {
+		if (p_mctl->act_sdev) {
 			struct msm_camera_sensor_info *sdata;
 
-			sdata = p_mctl->sync.sdata;
+			sdata = p_mctl->sdata;
 			CDBG("%s: Act_cam_Name %d\n", __func__,
 				sdata->actuator_info->cam_name);
 
@@ -433,8 +288,9 @@
 
 	case MSM_CAM_IOCTL_ACTUATOR_IO_CFG: {
 		struct msm_actuator_cfg_data act_data;
-		if (p_mctl->sync.actctrl.a_config) {
-			rc = p_mctl->sync.actctrl.a_config(argp);
+		if (p_mctl->act_sdev) {
+			rc = v4l2_subdev_call(p_mctl->act_sdev,
+				core, ioctl, VIDIOC_MSM_ACTUATOR_CFG, argp);
 		} else {
 			rc = copy_from_user(
 				&act_data,
@@ -456,6 +312,33 @@
 		break;
 	}
 
+	case MSM_CAM_IOCTL_EEPROM_IO_CFG: {
+		struct msm_eeprom_cfg_data eeprom_data;
+		if (p_mctl->eeprom_sdev) {
+			eeprom_data.is_eeprom_supported = 1;
+			rc = v4l2_subdev_call(p_mctl->eeprom_sdev,
+				core, ioctl, VIDIOC_MSM_EEPROM_CFG, argp);
+		} else {
+			rc = copy_from_user(
+				&eeprom_data,
+				(void *)argp,
+				sizeof(struct msm_eeprom_cfg_data));
+			if (rc != 0) {
+				rc = -EFAULT;
+				break;
+			}
+			eeprom_data.is_eeprom_supported = 0;
+			rc = copy_to_user((void *)argp,
+					 &eeprom_data,
+					 sizeof(struct msm_eeprom_cfg_data));
+			if (rc != 0) {
+				rc = -EFAULT;
+				break;
+			}
+		}
+		break;
+	}
+
 	case MSM_CAM_IOCTL_GET_KERNEL_SYSTEM_TIME: {
 		struct timeval timestamp;
 		if (copy_from_user(&timestamp, argp, sizeof(timestamp))) {
@@ -475,7 +358,7 @@
 			ERR_COPY_FROM_USER();
 			rc = -EFAULT;
 		} else {
-			rc = msm_flash_ctrl(p_mctl->sync.sdata, &flash_info);
+			rc = msm_flash_ctrl(p_mctl->sdata, &flash_info);
 		}
 		break;
 	}
@@ -508,6 +391,13 @@
 			(void __user *)arg);
 		break;
 			/* ISFIF config*/
+	case MSM_CAM_IOCTL_AXI_CONFIG:
+		if (p_mctl->axi_sdev)
+			rc = v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
+				VIDIOC_MSM_AXI_CFG, (void __user *)arg);
+		else
+			rc = p_mctl->isp_sdev->isp_config(p_mctl, cmd, arg);
+		break;
 	default:
 		/* ISP config*/
 		D("%s:%d: go to default. Calling msm_isp_config\n",
@@ -627,7 +517,7 @@
 		if (!dev)
 			goto out_put_driver;
 
-		p_mctl->isp_sdev->sd_vpe = dev_get_drvdata(dev);
+		p_mctl->vpe_sdev = dev_get_drvdata(dev);
 		put_driver(driver);
 	}
 
@@ -671,7 +561,6 @@
 				 const char *const apps_id)
 {
 	int rc = 0;
-	struct msm_sync *sync = NULL;
 	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(p_mctl->sensor_sdev);
 	struct msm_camera_sensor_info *sinfo =
 		(struct msm_camera_sensor_info *) s_ctrl->sensordata;
@@ -683,37 +572,33 @@
 		return -EINVAL;
 	}
 
-	/* msm_sync_init() muct be called before*/
-	sync = &(p_mctl->sync);
-
-	mutex_lock(&sync->lock);
+	mutex_lock(&p_mctl->lock);
 	/* open sub devices - once only*/
-	if (!sync->opencnt) {
+	if (!p_mctl->opencnt) {
 		uint32_t csid_version;
-		wake_lock(&sync->wake_lock);
+		wake_lock(&p_mctl->wake_lock);
 
 		csid_core = camdev->csid_core;
 		rc = msm_mctl_register_subdevs(p_mctl, csid_core);
 		if (rc < 0) {
 			pr_err("%s: msm_mctl_register_subdevs failed:%d\n",
 				__func__, rc);
-			goto msm_open_done;
+			goto register_sdev_failed;
 		}
 
-		/* then sensor - move sub dev later*/
+		/* then sensor - move sub dev later */
 		rc = v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 1);
-
 		if (rc < 0) {
-			pr_err("%s: isp init failed: %d\n", __func__, rc);
-			goto msm_open_done;
+			pr_err("%s: sensor powerup failed: %d\n", __func__, rc);
+			goto sensor_sdev_failed;
 		}
-		if (sync->actctrl.a_power_up)
-			rc = sync->actctrl.a_power_up(
-				sync->sdata->actuator_info);
 
+		if (p_mctl->act_sdev)
+			rc = v4l2_subdev_call(p_mctl->act_sdev,
+				core, s_power, 1);
 		if (rc < 0) {
 			pr_err("%s: act power failed:%d\n", __func__, rc);
-			goto msm_open_done;
+			goto act_power_up_failed;
 		}
 
 		if (camdev->is_csiphy) {
@@ -721,8 +606,8 @@
 				VIDIOC_MSM_CSIPHY_INIT, NULL);
 			if (rc < 0) {
 				pr_err("%s: csiphy initialization failed %d\n",
-				__func__, rc);
-				goto msm_open_done;
+					__func__, rc);
+				goto csiphy_init_failed;
 			}
 		}
 
@@ -731,30 +616,50 @@
 				VIDIOC_MSM_CSID_INIT, &csid_version);
 			if (rc < 0) {
 				pr_err("%s: csid initialization failed %d\n",
-				__func__, rc);
-				goto msm_open_done;
+					__func__, rc);
+				goto csid_init_failed;
 			}
 		}
+
 		if (camdev->is_csic) {
 			rc = v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
 				VIDIOC_MSM_CSIC_INIT, &csid_version);
 			if (rc < 0) {
 				pr_err("%s: csic initialization failed %d\n",
-				__func__, rc);
-				goto msm_open_done;
+					__func__, rc);
+				goto csic_init_failed;
 			}
 		}
 
 		/* ISP first*/
-		if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_open)
+		if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_open) {
 			rc = p_mctl->isp_sdev->isp_open(
-				p_mctl->isp_sdev->sd,
-				p_mctl->isp_sdev->sd_vpe,
-				p_mctl->gemini_sdev,
-				sync);
-		if (rc < 0) {
-			pr_err("%s: isp init failed: %d\n", __func__, rc);
-			goto msm_open_done;
+				p_mctl->isp_sdev->sd, p_mctl);
+			if (rc < 0) {
+				pr_err("%s: isp init failed: %d\n",
+					__func__, rc);
+				goto isp_open_failed;
+			}
+		}
+
+		if (p_mctl->axi_sdev) {
+			rc = v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
+				VIDIOC_MSM_AXI_INIT, p_mctl);
+			if (rc < 0) {
+				pr_err("%s: axi initialization failed %d\n",
+					__func__, rc);
+				goto axi_init_failed;
+			}
+		}
+
+		if (camdev->is_vpe) {
+			rc = v4l2_subdev_call(p_mctl->vpe_sdev, core, ioctl,
+				VIDIOC_MSM_VPE_INIT, p_mctl);
+			if (rc < 0) {
+				pr_err("%s: vpe initialization failed %d\n",
+				__func__, rc);
+				goto vpe_init_failed;
+			}
 		}
 
 		if (camdev->is_ispif) {
@@ -762,24 +667,66 @@
 				VIDIOC_MSM_ISPIF_INIT, &csid_version);
 			if (rc < 0) {
 				pr_err("%s: ispif initialization failed %d\n",
-				__func__, rc);
-				goto msm_open_done;
+					__func__, rc);
+				goto ispif_init_failed;
 			}
 		}
 
 		if (camdev->is_ispif) {
 			pm_qos_add_request(&p_mctl->pm_qos_req_list,
-					PM_QOS_CPU_DMA_LATENCY,
-					PM_QOS_DEFAULT_VALUE);
+				PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
 			pm_qos_update_request(&p_mctl->pm_qos_req_list,
-					MSM_V4L2_SWFI_LATENCY);
+				MSM_V4L2_SWFI_LATENCY);
 		}
-		sync->apps_id = apps_id;
-		sync->opencnt++;
+		p_mctl->apps_id = apps_id;
+		p_mctl->opencnt++;
+	} else {
+		D("%s: camera is already open", __func__);
 	}
+	mutex_unlock(&p_mctl->lock);
 
-msm_open_done:
-	mutex_unlock(&sync->lock);
+	return rc;
+
+ispif_init_failed:
+	if (camdev->is_vpe)
+		if (v4l2_subdev_call(p_mctl->vpe_sdev, core, ioctl,
+			VIDIOC_MSM_VPE_RELEASE, NULL) < 0)
+			pr_err("%s: vpe release failed %d\n", __func__, rc);
+vpe_init_failed:
+	if (p_mctl->axi_sdev)
+		if (v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
+			VIDIOC_MSM_AXI_RELEASE, NULL) < 0)
+			pr_err("%s: axi release failed %d\n", __func__, rc);
+axi_init_failed:
+	if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release)
+		p_mctl->isp_sdev->isp_release(p_mctl->isp_sdev->sd);
+isp_open_failed:
+	if (camdev->is_csic)
+		if (v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
+			VIDIOC_MSM_CSIC_RELEASE, NULL) < 0)
+			pr_err("%s: csic release failed %d\n", __func__, rc);
+csic_init_failed:
+	if (camdev->is_csid)
+		if (v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
+			VIDIOC_MSM_CSID_RELEASE, NULL) < 0)
+			pr_err("%s: csid release failed %d\n", __func__, rc);
+csid_init_failed:
+	if (camdev->is_csiphy)
+		if (v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
+			VIDIOC_MSM_CSIPHY_RELEASE, NULL) < 0)
+			pr_err("%s: csiphy release failed %d\n", __func__, rc);
+csiphy_init_failed:
+	if (p_mctl->act_sdev)
+		if (v4l2_subdev_call(p_mctl->act_sdev, core,
+			s_power, 0) < 0)
+			pr_err("%s: act power down failed:%d\n", __func__, rc);
+act_power_up_failed:
+	if (v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 0) < 0)
+		pr_err("%s: sensor powerdown failed: %d\n", __func__, rc);
+sensor_sdev_failed:
+register_sdev_failed:
+	wake_unlock(&p_mctl->wake_lock);
+	mutex_unlock(&p_mctl->lock);
 	return rc;
 }
 
@@ -804,9 +751,19 @@
 			VIDIOC_MSM_CSIC_RELEASE, NULL);
 	}
 
+	if (camdev->is_vpe) {
+		v4l2_subdev_call(p_mctl->vpe_sdev, core, ioctl,
+			VIDIOC_MSM_VPE_RELEASE, NULL);
+	}
+
+	if (p_mctl->axi_sdev) {
+		v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
+			VIDIOC_MSM_AXI_RELEASE, NULL);
+	}
+
 	if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release)
-		p_mctl->isp_sdev->isp_release(&p_mctl->sync,
-				p_mctl->gemini_sdev);
+		p_mctl->isp_sdev->isp_release(
+			p_mctl->isp_sdev->sd);
 
 	if (camdev->is_csid) {
 		v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
@@ -823,19 +780,19 @@
 				PM_QOS_DEFAULT_VALUE);
 		pm_qos_remove_request(&p_mctl->pm_qos_req_list);
 	}
-	if (p_mctl->sync.actctrl.a_power_down)
-		p_mctl->sync.actctrl.a_power_down(
-			p_mctl->sync.sdata->actuator_info);
+
+	if (p_mctl->act_sdev)
+		v4l2_subdev_call(p_mctl->act_sdev, core, s_power, 0);
 
 	v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 0);
 
-	wake_unlock(&p_mctl->sync.wake_lock);
+	wake_unlock(&p_mctl->wake_lock);
 	return rc;
 }
 
 int msm_mctl_init_user_formats(struct msm_cam_v4l2_device *pcam)
 {
-	struct v4l2_subdev *sd = pcam->mctl.sensor_sdev;
+	struct v4l2_subdev *sd = pcam->sensor_sdev;
 	enum v4l2_mbus_pixelcode pxlcode;
 	int numfmt_sensor = 0;
 	int numfmt = 0;
@@ -893,35 +850,70 @@
 }
 
 /* this function plug in the implementation of a v4l2_subdev */
-int msm_mctl_init_module(struct msm_cam_v4l2_device *pcam)
+int msm_mctl_init(struct msm_cam_v4l2_device *pcam)
 {
 	struct msm_cam_media_controller *pmctl = NULL;
 	D("%s\n", __func__);
 	if (!pcam) {
 		pr_err("%s: param is NULL", __func__);
 		return -EINVAL;
-	} else
-		pmctl = &pcam->mctl;
+	}
+	pcam->mctl_handle = msm_camera_get_mctl_handle();
+	if (pcam->mctl_handle == 0) {
+		pr_err("%s: cannot get mctl handle", __func__);
+		return -EINVAL;
+	}
 
-	pmctl->sync.opencnt = 0;
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	if (!pmctl) {
+		pr_err("%s: invalid mctl controller", __func__);
+		return -EINVAL;
+	}
+
+	wake_lock_init(&pmctl->wake_lock, WAKE_LOCK_IDLE, "msm_camera");
+	mutex_init(&pmctl->lock);
+	pmctl->opencnt = 0;
 
 	/* init module operations*/
 	pmctl->mctl_open = msm_mctl_open;
 	pmctl->mctl_cmd = msm_mctl_cmd;
-	pmctl->mctl_notify = msm_mctl_notify;
 	pmctl->mctl_release = msm_mctl_release;
 	/* init mctl buf */
 	msm_mctl_buf_init(pcam);
 	memset(&pmctl->pp_info, 0, sizeof(pmctl->pp_info));
 	pmctl->vfe_output_mode = 0;
 	spin_lock_init(&pmctl->pp_info.lock);
-	/* init sub device*/
-	v4l2_subdev_init(&(pmctl->mctl_sdev), &mctl_subdev_ops);
-	v4l2_set_subdevdata(&(pmctl->mctl_sdev), pmctl);
+
+	pmctl->act_sdev = pcam->act_sdev;
+	pmctl->eeprom_sdev = pcam->eeprom_sdev;
+	pmctl->sensor_sdev = pcam->sensor_sdev;
+	pmctl->sdata = pcam->sdata;
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	pmctl->client = msm_ion_client_create(-1, "camera");
+	kref_init(&pmctl->refcount);
+#endif
 
 	return 0;
 }
 
+int msm_mctl_free(struct msm_cam_v4l2_device *pcam)
+{
+	int rc = 0;
+	struct msm_cam_media_controller *pmctl = NULL;
+	D("%s\n", __func__);
+
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	if (!pmctl) {
+		pr_err("%s: invalid mctl controller", __func__);
+		return -EINVAL;
+	}
+
+	mutex_destroy(&pmctl->lock);
+	wake_lock_destroy(&pmctl->wake_lock);
+	msm_camera_free_mctl(pcam->mctl_handle);
+	return rc;
+}
 
 /* mctl node v4l2_file_operations */
 static int msm_mctl_dev_open(struct file *f)
@@ -930,6 +922,7 @@
 	/* get the video device */
 	struct msm_cam_v4l2_device *pcam  = NULL;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
+	struct msm_cam_media_controller *pmctl;
 	D("%s : E ", __func__);
 
 	if (f == NULL) {
@@ -942,6 +935,7 @@
 		pr_err("%s NULL pointer passed in!\n", __func__);
 		return rc;
 	}
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
 
 	mutex_lock(&pcam->mctl_node.dev_lock);
 	for (i = 0; i < MSM_DEV_INST_MAX; i++) {
@@ -966,7 +960,6 @@
 
 	D("%s pcam_inst %p my_index = %d\n", __func__,
 		pcam_inst, pcam_inst->my_index);
-	D("%s for %s\n", __func__, pcam->mctl.sensor_sdev->name);
 	rc = msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
 					pcam->mctl_node.pvdev);
 	if (rc < 0) {
@@ -974,7 +967,7 @@
 		return rc;
 	}
 	pcam_inst->vbqueue_initialized = 0;
-	kref_get(&pcam->mctl.refcount);
+	kref_get(&pmctl->refcount);
 	f->private_data = &pcam_inst->eventHandle;
 
 	D("f->private_data = 0x%x, pcam = 0x%x\n",
@@ -1024,6 +1017,7 @@
 	int rc = 0;
 	struct msm_cam_v4l2_device *pcam;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
+	struct msm_cam_media_controller *pmctl;
 	pcam_inst = container_of(f->private_data,
 		struct msm_cam_v4l2_dev_inst, eventHandle);
 	pcam = pcam_inst->pcam;
@@ -1034,6 +1028,7 @@
 		return -EINVAL;
 	}
 
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
 	mutex_lock(&pcam->mctl_node.dev_lock);
 	pcam_inst->streamon = 0;
 	pcam->mctl_node.dev_inst_map[pcam_inst->image_mode] = NULL;
@@ -1045,7 +1040,7 @@
 	v4l2_fh_exit(&pcam_inst->eventHandle);
 
 	kfree(pcam_inst);
-	kref_put(&pcam->mctl.refcount, msm_release_ion_client);
+	kref_put(&pmctl->refcount, msm_release_ion_client);
 	f->private_data = NULL;
 	mutex_unlock(&pcam->mctl_node.dev_lock);
 	D("%s : X ", __func__);
@@ -1085,8 +1080,8 @@
 		return -EINVAL;
 	}
 
-	strlcpy(pcaps->driver, pcam->mctl.sensor_sdev->name,
-		sizeof(pcaps->driver));
+	strlcpy(pcaps->driver, pcam->media_dev.dev->driver->name,
+			sizeof(pcaps->driver));
 	pcaps->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
 	return 0;
 }
@@ -1437,6 +1432,7 @@
 	int rc = 0;
 	/* get the video device */
 	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
+	struct msm_cam_media_controller *pmctl;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
 	pcam_inst = container_of(f->private_data,
 		struct msm_cam_v4l2_dev_inst, eventHandle);
@@ -1447,8 +1443,9 @@
 		(void *)pfmt->fmt.pix.priv);
 	WARN_ON(pctx != f->private_data);
 
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
 	if (!pcam_inst->vbqueue_initialized) {
-		pcam->mctl.mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq,
+		pmctl->mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq,
 					V4L2_BUF_TYPE_VIDEO_CAPTURE);
 		pcam_inst->vbqueue_initialized = 1;
 	}
@@ -1461,6 +1458,7 @@
 {
 	int rc = 0, i;
 	struct msm_cam_v4l2_device *pcam = video_drvdata(f);
+	struct msm_cam_media_controller *pmctl;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
 	pcam_inst = container_of(f->private_data,
 			struct msm_cam_v4l2_dev_inst, eventHandle);
@@ -1469,8 +1467,9 @@
 		pcam_inst, pcam_inst->vbqueue_initialized);
 	WARN_ON(pctx != f->private_data);
 
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
 	if (!pcam_inst->vbqueue_initialized) {
-		pcam->mctl.mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq,
+		pmctl->mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq,
 					V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 		pcam_inst->vbqueue_initialized = 1;
 	}
@@ -1657,7 +1656,7 @@
 {
 	int rc = -EINVAL;
 	struct video_device *pvdev = NULL;
-	struct i2c_client *client = v4l2_get_subdevdata(pcam->mctl.sensor_sdev);
+	struct i2c_client *client = v4l2_get_subdevdata(pcam->sensor_sdev);
 
 	D("%s\n", __func__);
 
@@ -1679,11 +1678,11 @@
 
 	/* init video device's driver interface */
 	D("sensor name = %s, sizeof(pvdev->name)=%d\n",
-			pcam->mctl.sensor_sdev->name, sizeof(pvdev->name));
+			pcam->sensor_sdev->name, sizeof(pvdev->name));
 
 	/* device info - strlcpy is safer than strncpy but
 	   only if architecture supports*/
-	strlcpy(pvdev->name, pcam->mctl.sensor_sdev->name,
+	strlcpy(pvdev->name, pcam->sensor_sdev->name,
 			sizeof(pvdev->name));
 
 	pvdev->release   = video_device_release;
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index 8148f1f..5bc81a7 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -75,6 +75,7 @@
 {
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
 	struct msm_cam_v4l2_device *pcam;
+	struct msm_cam_media_controller *pmctl;
 	struct videobuf2_contig_pmem *mem;
 	struct vb2_queue	*vq;
 	uint32_t buf_idx;
@@ -112,6 +113,7 @@
 			pcam_inst->plane_info.plane[0].offset;
 	}
 	buf_idx = vb->v4l2_buf.index;
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
 	for (i = 0; i < vb->num_planes; i++) {
 		mem = vb2_plane_cookie(vb, i);
 		if (buf_type == VIDEOBUF2_MULTIPLE_PLANES)
@@ -122,7 +124,7 @@
 			rc = videobuf2_pmem_contig_user_get(mem, &offset,
 				buf_type,
 				pcam_inst->buf_offset[buf_idx][i].addr_offset,
-				pcam_inst->path, pcam->mctl.client);
+				pcam_inst->path, pmctl->client);
 		else
 			rc = videobuf2_pmem_contig_mmap_get(mem, &offset,
 				buf_type, pcam_inst->path);
@@ -194,6 +196,7 @@
 static void msm_vb2_ops_buf_cleanup(struct vb2_buffer *vb)
 {
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
+	struct msm_cam_media_controller *pmctl;
 	struct msm_cam_v4l2_device *pcam;
 	struct videobuf2_contig_pmem *mem;
 	struct msm_frame_buffer *buf, *tmp;
@@ -248,9 +251,10 @@
 		}
 		spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
 	}
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
 	for (i = 0; i < vb->num_planes; i++) {
 		mem = vb2_plane_cookie(vb, i);
-		videobuf2_pmem_contig_user_put(mem, pcam->mctl.client);
+		videobuf2_pmem_contig_user_put(mem, pmctl->client);
 	}
 	buf->state = MSM_BUFFER_STATE_UNUSED;
 }
@@ -328,12 +332,12 @@
 					int image_mode, int node_type)
 {
 	if ((image_mode >= 0) && node_type &&
-		pmctl->sync.pcam_sync->mctl_node.dev_inst_map[image_mode])
-		return pmctl->sync.pcam_sync->
+		pmctl->pcam_ptr->mctl_node.dev_inst_map[image_mode])
+		return pmctl->pcam_ptr->
 				mctl_node.dev_inst_map[image_mode]->my_index;
 	else if ((image_mode >= 0) &&
-		pmctl->sync.pcam_sync->dev_inst_map[image_mode])
-		return	pmctl->sync.pcam_sync->
+		pmctl->pcam_ptr->dev_inst_map[image_mode])
+		return	pmctl->pcam_ptr->
 				dev_inst_map[image_mode]->my_index;
 	else
 		return -EINVAL;
@@ -440,7 +444,7 @@
 				__func__);
 			return idx;
 		}
-		pcam_inst = p_mctl->sync.pcam_sync->dev_inst[idx];
+		pcam_inst = p_mctl->pcam_ptr->dev_inst[idx];
 		rc = msm_mctl_buf_done_proc(p_mctl, pcam_inst,
 				image_mode, fbuf,
 				&frame_id, 1);
@@ -450,7 +454,9 @@
 
 int msm_mctl_buf_init(struct msm_cam_v4l2_device *pcam)
 {
-	pcam->mctl.mctl_vbqueue_init = msm_vbqueue_init;
+	struct msm_cam_media_controller *pmctl;
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	pmctl->mctl_vbqueue_init = msm_vbqueue_init;
 	return 0;
 }
 
@@ -475,7 +481,7 @@
 				int image_mode)
 {
 	struct msm_cam_v4l2_dev_inst *pcam_inst = NULL;
-	struct msm_cam_v4l2_device *pcam = pmctl->sync.pcam_sync;
+	struct msm_cam_v4l2_device *pcam = pmctl->pcam_ptr;
 	int idx;
 
 	if (image_mode >= 0) {
@@ -646,9 +652,9 @@
 		return idx;
 	}
 	if (node_type)
-		pcam_inst = pmctl->sync.pcam_sync->mctl_node.dev_inst[idx];
+		pcam_inst = pmctl->pcam_ptr->mctl_node.dev_inst[idx];
 	else
-		pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx];
+		pcam_inst = pmctl->pcam_ptr->dev_inst[idx];
 	if (!pcam_inst) {
 		pr_err("%s Invalid instance, cannot send buf to user",
 			__func__);
@@ -682,7 +688,7 @@
 		pr_err("%s Invalid instance, cant get buffer\n", __func__);
 		return NULL;
 	}
-	pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx];
+	pcam_inst = pmctl->pcam_ptr->dev_inst[idx];
 	if (!pcam_inst->streamon) {
 		D("%s: stream 0x%p is off\n", __func__, pcam_inst);
 		return NULL;
@@ -721,7 +727,7 @@
 		pr_err("%s Invalid instance, cant put buffer\n", __func__);
 		return idx;
 	}
-	pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx];
+	pcam_inst = pmctl->pcam_ptr->dev_inst[idx];
 	if (!pcam_inst->streamon) {
 		D("%s: stream 0x%p is off\n", __func__, pcam_inst);
 		return rc;
@@ -756,7 +762,7 @@
 		pr_err("%s Invalid instance, cant delete buffer\n", __func__);
 		return idx;
 	}
-	pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx];
+	pcam_inst = pmctl->pcam_ptr->dev_inst[idx];
 	D("%s: idx = %d, pinst=0x%p", __func__, idx, pcam_inst);
 	spin_lock_irqsave(&pcam_inst->vq_irqlock, flags);
 	if (!list_empty(&pcam_inst->free_vq)) {
@@ -780,7 +786,7 @@
 	int idx = 0;
 	struct msm_frame_buffer *buf = NULL;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
-	struct msm_cam_v4l2_device *pcam = pmctl->sync.pcam_sync;
+	struct msm_cam_v4l2_device *pcam = pmctl->pcam_ptr;
 	unsigned long flags = 0;
 
 	if (pcam->mctl_node.dev_inst_map[image_mode]) {
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
index 82c5bf7..e1138aa 100644
--- a/drivers/media/video/msm/msm_mctl_pp.c
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -28,6 +28,7 @@
 #include <linux/android_pmem.h>
 
 #include "msm.h"
+#include "msm_vpe.h"
 
 #ifdef CONFIG_MSM_CAMERA_DEBUG
 #define D(fmt, args...) pr_debug("msm_mctl: " fmt, ##args)
@@ -35,6 +36,18 @@
 #define D(fmt, args...) do {} while (0)
 #endif
 
+
+static int msm_mctl_pp_vpe_ioctl(struct v4l2_subdev *vpe_sd,
+	struct msm_mctl_pp_cmd *cmd, void *data)
+{
+	int rc = 0;
+	struct msm_mctl_pp_params parm;
+	parm.cmd = cmd;
+	parm.data = data;
+	rc = v4l2_subdev_call(vpe_sd, core, ioctl, VIDIOC_MSM_VPE_CFG, &parm);
+	return rc;
+}
+
 static int msm_mctl_pp_buf_divert(
 			struct msm_cam_media_controller *pmctl,
 			struct msm_cam_v4l2_dev_inst *pcam_inst,
@@ -156,7 +169,7 @@
 		int image_mode, struct msm_free_buf *fbuf, int *node_type)
 {
 	struct msm_cam_v4l2_dev_inst *pcam_inst = NULL;
-	struct msm_cam_v4l2_device *pcam = pmctl->sync.pcam_sync;
+	struct msm_cam_v4l2_device *pcam = pmctl->pcam_ptr;
 	int idx;
 
 	if (image_mode >= 0) {
@@ -381,13 +394,13 @@
 	switch (pp_cmd->id) {
 	case VPE_CMD_INIT:
 	case VPE_CMD_DEINIT:
-		rc = msm_isp_subdev_ioctl_vpe(
-			p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+		rc = msm_mctl_pp_vpe_ioctl(
+			p_mctl->vpe_sdev, pp_cmd, NULL);
 		break;
 	case VPE_CMD_DISABLE:
 	case VPE_CMD_RESET:
-		rc = msm_isp_subdev_ioctl_vpe(
-			p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+		rc = msm_mctl_pp_vpe_ioctl(
+			p_mctl->vpe_sdev, pp_cmd, NULL);
 		break;
 	case VPE_CMD_ENABLE: {
 		struct msm_vpe_clock_rate clk_rate;
@@ -406,8 +419,8 @@
 			return -EFAULT;
 		}
 		pp_cmd->value = (void *)&clk_rate;
-		rc = msm_isp_subdev_ioctl_vpe(
-			p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+		rc = msm_mctl_pp_vpe_ioctl(
+			p_mctl->vpe_sdev, pp_cmd, NULL);
 		pp_cmd->value = argp;
 		break;
 	}
@@ -425,8 +438,8 @@
 			&flush_buf, pp_cmd->value, sizeof(flush_buf)))
 			return -EFAULT;
 		pp_cmd->value = (void *)&flush_buf;
-		rc = msm_isp_subdev_ioctl_vpe(
-			p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+		rc = msm_mctl_pp_vpe_ioctl(
+			p_mctl->vpe_sdev, pp_cmd, NULL);
 		if (rc == 0) {
 			if (copy_to_user((void *)argp,
 						&flush_buf,
@@ -453,8 +466,8 @@
 			sizeof(op_mode_cfg)))
 			return -EFAULT;
 		pp_cmd->value = (void *)&op_mode_cfg;
-		rc = msm_isp_subdev_ioctl_vpe(
-			p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+		rc = msm_mctl_pp_vpe_ioctl(
+			p_mctl->vpe_sdev, pp_cmd, NULL);
 		break;
 	}
 	case VPE_CMD_INPUT_PLANE_CFG: {
@@ -471,8 +484,8 @@
 			&input_cfg, pp_cmd->value, sizeof(input_cfg)))
 			return -EFAULT;
 		pp_cmd->value = (void *)&input_cfg;
-		rc = msm_isp_subdev_ioctl_vpe(
-			p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+		rc = msm_mctl_pp_vpe_ioctl(
+			p_mctl->vpe_sdev, pp_cmd, NULL);
 		break;
 	}
 	case VPE_CMD_OUTPUT_PLANE_CFG: {
@@ -492,8 +505,8 @@
 			return -EFAULT;
 		}
 		pp_cmd->value = (void *)&output_cfg;
-		rc = msm_isp_subdev_ioctl_vpe(
-			p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+		rc = msm_mctl_pp_vpe_ioctl(
+			p_mctl->vpe_sdev, pp_cmd, NULL);
 		break;
 	}
 	case VPE_CMD_INPUT_PLANE_UPDATE: {
@@ -510,8 +523,8 @@
 			sizeof(input_update_cfg)))
 			return -EFAULT;
 		pp_cmd->value = (void *)&input_update_cfg;
-		rc = msm_isp_subdev_ioctl_vpe(
-			p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+		rc = msm_mctl_pp_vpe_ioctl(
+			p_mctl->vpe_sdev, pp_cmd, NULL);
 		break;
 	}
 	case VPE_CMD_SCALE_CFG_TYPE: {
@@ -528,8 +541,8 @@
 			sizeof(scaler_cfg)))
 			return -EFAULT;
 		pp_cmd->value = (void *)&scaler_cfg;
-		rc = msm_isp_subdev_ioctl_vpe(
-			p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+		rc = msm_mctl_pp_vpe_ioctl(
+			p_mctl->vpe_sdev, pp_cmd, NULL);
 		break;
 	}
 	case VPE_CMD_ZOOM: {
@@ -559,14 +572,14 @@
 				zoom->pp_frame_cmd.cookie,
 				zoom->pp_frame_cmd.vpe_output_action,
 				zoom->pp_frame_cmd.path);
-		idx = msm_mctl_pp_path_to_inst_index(p_mctl->sync.pcam_sync,
+		idx = msm_mctl_pp_path_to_inst_index(p_mctl->pcam_ptr,
 			zoom->pp_frame_cmd.path);
 		if (idx < 0) {
 			pr_err("%s Invalid path, returning\n", __func__);
 			kfree(zoom);
 			return idx;
 		}
-		pcam_inst = p_mctl->sync.pcam_sync->dev_inst[idx];
+		pcam_inst = p_mctl->pcam_ptr->dev_inst[idx];
 		if (!pcam_inst) {
 			pr_err("%s Invalid instance, returning\n", __func__);
 			kfree(zoom);
@@ -593,8 +606,8 @@
 			kfree(zoom);
 			break;
 		}
-		rc = msm_isp_subdev_ioctl_vpe(
-			p_mctl->isp_sdev->sd_vpe, pp_cmd, (void *)zoom);
+		rc = msm_mctl_pp_vpe_ioctl(
+			p_mctl->vpe_sdev, pp_cmd, (void *)zoom);
 		if (rc) {
 			kfree(zoom);
 			break;
@@ -809,7 +822,7 @@
 		return -EINVAL;
 	}
 	/* Always reserve the buffer from user's video node */
-	pcam_inst = p_mctl->sync.pcam_sync->dev_inst[image_mode];
+	pcam_inst = p_mctl->pcam_ptr->dev_inst[image_mode];
 	if (!pcam_inst) {
 		pr_err("%s Instance already closed ", __func__);
 		return -EINVAL;
diff --git a/drivers/media/video/msm/msm_mem.c b/drivers/media/video/msm/msm_mem.c
index 4f7e5d2..751626a 100644
--- a/drivers/media/video/msm/msm_mem.c
+++ b/drivers/media/video/msm/msm_mem.c
@@ -346,14 +346,15 @@
 }
 
 unsigned long msm_pmem_stats_vtop_lookup(
-				struct msm_sync *sync,
+				struct msm_cam_media_controller *mctl,
 				unsigned long buffer,
 				int fd)
 {
 	struct msm_pmem_region *region;
 	struct hlist_node *node, *n;
 
-	hlist_for_each_entry_safe(region, node, n, &sync->pmem_stats, list) {
+	hlist_for_each_entry_safe(region, node, n,
+	&mctl->stats_info.pmem_stats_list, list) {
 		if (((unsigned long)(region->info.vaddr) == buffer) &&
 						(region->info.fd == fd) &&
 						region->info.active == 0) {
@@ -365,13 +366,15 @@
 	return 0;
 }
 
-unsigned long msm_pmem_stats_ptov_lookup(struct msm_sync *sync,
-						unsigned long addr, int *fd)
+unsigned long msm_pmem_stats_ptov_lookup(
+		struct msm_cam_media_controller *mctl,
+		unsigned long addr, int *fd)
 {
 	struct msm_pmem_region *region;
 	struct hlist_node *node, *n;
 
-	hlist_for_each_entry_safe(region, node, n, &sync->pmem_stats, list) {
+	hlist_for_each_entry_safe(region, node, n,
+	&mctl->stats_info.pmem_stats_list, list) {
 		if (addr == region->paddr && region->info.active) {
 			/* offset since we could pass vaddr inside a
 			 * registered pmem buffer */
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.c b/drivers/media/video/msm/msm_vfe31_v4l2.c
index d60f4b7..90ba214 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.c
@@ -54,7 +54,6 @@
 #define CAMIF_CFG_RMSK             0x1fffff
 
 static struct vfe31_ctrl_type *vfe31_ctrl;
-static void  *vfe_syncdata;
 static uint32_t vfe_clk_rate;
 
 struct vfe31_isr_queue_cmd {
@@ -748,31 +747,26 @@
 	atomic_set(&vfe31_ctrl->vstate, 1);
 }
 
-static int vfe31_start_recording(void)
+static int vfe31_start_recording(struct msm_cam_media_controller *pmctl)
 {
-	struct msm_sync *sync = vfe_syncdata;
 	msm_camio_bus_scale_cfg(
-		sync->sdata->pdata->cam_bus_scale_table, S_VIDEO);
+		pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO);
 	vfe31_ctrl->recording_state = VFE_STATE_START_REQUESTED;
 	msm_camera_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
 	return 0;
 }
 
-static int vfe31_stop_recording(void)
+static int vfe31_stop_recording(struct msm_cam_media_controller *pmctl)
 {
-	struct msm_sync *sync = vfe_syncdata;
 	vfe31_ctrl->recording_state = VFE_STATE_STOP_REQUESTED;
 	msm_camera_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
 	msm_camio_bus_scale_cfg(
-		sync->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+		pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
 	return 0;
 }
 
-static void vfe31_start_liveshot(void){
-	struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
-	if (p_sync)
-		p_sync->liveshot_enabled = true;
-
+static void vfe31_start_liveshot(struct msm_cam_media_controller *pmctl)
+{
 	/* Hardcode 1 live snapshot for now. */
 	vfe31_ctrl->outpath.out0.capture_cnt = 1;
 	vfe31_ctrl->vfe_capture_count = vfe31_ctrl->outpath.out0.capture_cnt;
@@ -781,9 +775,8 @@
 	msm_camera_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
 }
 
-static int vfe31_zsl(void)
+static int vfe31_zsl(struct msm_cam_media_controller *pmctl)
 {
-	struct msm_sync *sync = vfe_syncdata;
 	uint32_t irq_comp_mask = 0;
 	/* capture command is valid for both idle and active state. */
 	irq_comp_mask	=
@@ -845,16 +838,17 @@
 	msm_camera_io_w(irq_comp_mask, vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
 	vfe31_start_common();
 	msm_camio_bus_scale_cfg(
-		sync->sdata->pdata->cam_bus_scale_table, S_ZSL);
+		pmctl->sdata->pdata->cam_bus_scale_table, S_ZSL);
 
 	msm_camera_io_w(1, vfe31_ctrl->vfebase + 0x18C);
 	msm_camera_io_w(1, vfe31_ctrl->vfebase + 0x188);
 	return 0;
 }
-static int vfe31_capture_raw(uint32_t num_frames_capture)
+static int vfe31_capture_raw(
+	struct msm_cam_media_controller *pmctl,
+	uint32_t num_frames_capture)
 {
 	uint32_t irq_comp_mask = 0;
-	struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
 
 	vfe31_ctrl->outpath.out0.capture_cnt = num_frames_capture;
 	vfe31_ctrl->vfe_capture_count = num_frames_capture;
@@ -870,19 +864,16 @@
 
 	msm_camera_io_w(irq_comp_mask, vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
 	msm_camio_bus_scale_cfg(
-		p_sync->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
+		pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
 	vfe31_start_common();
 	return 0;
 }
 
-static int vfe31_capture(uint32_t num_frames_capture)
+static int vfe31_capture(
+	struct msm_cam_media_controller *pmctl,
+	uint32_t num_frames_capture)
 {
 	uint32_t irq_comp_mask = 0;
-	struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
-	if (p_sync) {
-		p_sync->snap_count = num_frames_capture;
-		p_sync->thumb_count = num_frames_capture;
-	}
 	/* capture command is valid for both idle and active state. */
 	vfe31_ctrl->outpath.out1.capture_cnt = num_frames_capture;
 	if (vfe31_ctrl->operation_mode == VFE_OUTPUTS_MAIN_AND_THUMB ||
@@ -932,7 +923,7 @@
 	msm_camera_io_w(irq_comp_mask, vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
 	msm_camera_io_r(vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
 	msm_camio_bus_scale_cfg(
-		p_sync->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
+		pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
 
 	vfe31_start_common();
 	/* for debug */
@@ -941,10 +932,9 @@
 	return 0;
 }
 
-static int vfe31_start(void)
+static int vfe31_start(struct msm_cam_media_controller *pmctl)
 {
 	uint32_t irq_comp_mask = 0;
-	struct msm_sync *sync = vfe_syncdata;
 
 	irq_comp_mask	=
 		msm_camera_io_r(vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
@@ -1007,7 +997,7 @@
 		break;
 	}
 	msm_camio_bus_scale_cfg(
-		sync->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+		pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
 	vfe31_start_common();
 	return 0;
 }
@@ -1241,7 +1231,9 @@
 		NOTIFY_ISP_MSG_EVT, (void *)&isp_msg_evt);
 }
 
-static int vfe31_proc_general(struct msm_isp_cmd *cmd)
+static int vfe31_proc_general(
+	struct msm_cam_media_controller *pmctl,
+	struct msm_isp_cmd *cmd)
 {
 	int i , rc = 0;
 	uint32_t old_val = 0 , new_val = 0;
@@ -1278,7 +1270,7 @@
 			rc = -EINVAL;
 			goto proc_general_done;
 		}
-		rc = vfe31_start();
+		rc = vfe31_start(pmctl);
 		break;
 	case VFE_CMD_UPDATE:
 		vfe31_update();
@@ -1298,7 +1290,7 @@
 			rc = -EINVAL;
 			goto proc_general_done;
 		}
-		rc = vfe31_capture_raw(snapshot_cnt);
+		rc = vfe31_capture_raw(pmctl, snapshot_cnt);
 		break;
 	case VFE_CMD_CAPTURE:
 		if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value),
@@ -1339,7 +1331,7 @@
 			rc = -EINVAL;
 			goto proc_general_done;
 		}
-		rc = vfe31_capture(snapshot_cnt);
+		rc = vfe31_capture(pmctl, snapshot_cnt);
 		break;
 	case VFE_CMD_START_RECORDING:
 		pr_info("vfe31_proc_general: cmdID = %s\n",
@@ -1360,12 +1352,12 @@
 			rc = -EINVAL;
 			goto proc_general_done;
 		}
-		rc = vfe31_start_recording();
+		rc = vfe31_start_recording(pmctl);
 		break;
 	case VFE_CMD_STOP_RECORDING:
 		pr_info("vfe31_proc_general: cmdID = %s\n",
 			vfe31_general_cmd[cmd->id]);
-		rc = vfe31_stop_recording();
+		rc = vfe31_stop_recording(pmctl);
 		break;
 	case VFE_CMD_OPERATION_CFG:
 		if (cmd->length != V31_OPERATION_CFG_LEN) {
@@ -1756,7 +1748,7 @@
 			rc = -EINVAL;
 			goto proc_general_done;
 		}
-		vfe31_start_liveshot();
+		vfe31_start_liveshot(pmctl);
 		break;
 
 	case VFE_CMD_DEMOSAICV3:
@@ -2057,7 +2049,7 @@
 		if (rc < 0)
 			goto proc_general_done;
 
-		rc = vfe31_zsl();
+		rc = vfe31_zsl(pmctl);
 		break;
 
 	case VFE_CMD_ASF_CFG:
@@ -3316,6 +3308,8 @@
 static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd,
 			unsigned int subdev_cmd, void *arg)
 {
+	struct msm_cam_media_controller *pmctl =
+		(struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
 	struct msm_isp_cmd vfecmd;
 	struct msm_camvfe_params *vfe_params =
 		(struct msm_camvfe_params *)arg;
@@ -3419,7 +3413,7 @@
 	}
 	switch (cmd->cmd_type) {
 	case CMD_GENERAL: {
-		rc = vfe31_proc_general(&vfecmd);
+		rc = vfe31_proc_general(pmctl, &vfecmd);
 		}
 		break;
 	case CMD_CONFIG_PING_ADDR: {
@@ -3685,13 +3679,11 @@
 	usleep_range(10000, 15000);
 }
 
-int msm_vfe_subdev_init(struct v4l2_subdev *sd, void *data,
-	struct platform_device *pdev)
+int msm_vfe_subdev_init(struct v4l2_subdev *sd,
+		struct msm_cam_media_controller *mctl)
 {
 	int rc = 0;
-	struct msm_sync *sync = data;
-	v4l2_set_subdev_hostdata(sd, data);
-	vfe_syncdata = data;
+	v4l2_set_subdev_hostdata(sd, mctl);
 
 	spin_lock_init(&vfe31_ctrl->stop_flag_lock);
 	spin_lock_init(&vfe31_ctrl->state_lock);
@@ -3722,7 +3714,7 @@
 		pr_err("%s: vfe ioremap failed\n", __func__);
 		goto vfe_remap_failed;
 	}
-	if (!sync->sdata->csi_if) {
+	if (!mctl->sdata->csi_if) {
 		vfe31_ctrl->camifbase = ioremap(vfe31_ctrl->camifmem->start,
 			resource_size(vfe31_ctrl->camifmem));
 		if (!vfe31_ctrl->camifbase) {
@@ -3754,7 +3746,7 @@
 	if (rc < 0)
 		goto vfe_clk_enable_failed;
 
-	if (!sync->sdata->csi_if) {
+	if (!mctl->sdata->csi_if) {
 		rc = msm_cam_clk_enable(&vfe31_ctrl->pdev->dev,
 			vfe_camif_clk_info,
 			vfe31_ctrl->vfe_camif_clk,
@@ -3765,9 +3757,9 @@
 	}
 
 	msm_camio_bus_scale_cfg(
-		sync->sdata->pdata->cam_bus_scale_table, S_INIT);
+		mctl->sdata->pdata->cam_bus_scale_table, S_INIT);
 	msm_camio_bus_scale_cfg(
-		sync->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+		mctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
 	vfe31_ctrl->register_total = VFE31_REGISTER_TOTAL;
 
 	enable_irq(vfe31_ctrl->vfeirq->start);
@@ -3779,7 +3771,7 @@
 	regulator_put(vfe31_ctrl->fs_vfe);
 	vfe31_ctrl->fs_vfe = NULL;
 vfe_fs_failed:
-	if (!sync->sdata->csi_if)
+	if (!mctl->sdata->csi_if)
 		iounmap(vfe31_ctrl->camifbase);
 camif_remap_failed:
 	iounmap(vfe31_ctrl->vfebase);
@@ -3788,13 +3780,14 @@
 	return rc;
 }
 
-void msm_vfe_subdev_release(struct platform_device *pdev)
+void msm_vfe_subdev_release(struct v4l2_subdev *sd)
 {
-	struct msm_sync *sync = vfe_syncdata;
+	struct msm_cam_media_controller *pmctl =
+		(struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
 	disable_irq(vfe31_ctrl->vfeirq->start);
 	tasklet_kill(&vfe31_tasklet);
 
-	if (!sync->sdata->csi_if)
+	if (!pmctl->sdata->csi_if)
 		msm_cam_clk_enable(&vfe31_ctrl->pdev->dev,
 			vfe_camif_clk_info,
 			vfe31_ctrl->vfe_camif_clk,
@@ -3808,7 +3801,7 @@
 		vfe31_ctrl->fs_vfe = NULL;
 	}
 	CDBG("%s, 31ee_irq\n", __func__);
-	if (!sync->sdata->csi_if)
+	if (!pmctl->sdata->csi_if)
 		iounmap(vfe31_ctrl->camifbase);
 	iounmap(vfe31_ctrl->vfebase);
 
@@ -3816,10 +3809,10 @@
 		pr_warning("%s, Warning IRQ Count not ZERO\n", __func__);
 
 	msm_camio_bus_scale_cfg(
-		sync->sdata->pdata->cam_bus_scale_table, S_EXIT);
-	vfe_syncdata = NULL;
+		pmctl->sdata->pdata->cam_bus_scale_table, S_EXIT);
 }
 
+static const struct v4l2_subdev_internal_ops msm_vfe_internal_ops;
 
 static int __devinit vfe31_probe(struct platform_device *pdev)
 {
@@ -3832,6 +3825,8 @@
 	}
 
 	v4l2_subdev_init(&vfe31_ctrl->subdev, &msm_vfe_subdev_ops);
+	vfe31_ctrl->subdev.internal_ops = &msm_vfe_internal_ops;
+	vfe31_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 	snprintf(vfe31_ctrl->subdev.name,
 			 sizeof(vfe31_ctrl->subdev.name), "vfe3.1");
 	v4l2_set_subdevdata(&vfe31_ctrl->subdev, vfe31_ctrl);
@@ -3894,6 +3889,7 @@
 	disable_irq(vfe31_ctrl->vfeirq->start);
 
 	vfe31_ctrl->pdev = pdev;
+	msm_cam_register_subdev_node(&vfe31_ctrl->subdev, VFE_DEV, 0);
 	return 0;
 
 vfe31_no_resource:
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index b8344fb..becdd95 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -48,7 +48,6 @@
 	vfe32_put_ch_ping_addr((chn), (addr)))
 
 static struct vfe32_ctrl_type *vfe32_ctrl;
-static void  *vfe_syncdata;
 static uint32_t vfe_clk_rate;
 
 struct vfe32_isr_queue_cmd {
@@ -726,31 +725,26 @@
 	atomic_set(&vfe32_ctrl->vstate, 1);
 }
 
-static int vfe32_start_recording(void)
+static int vfe32_start_recording(struct msm_cam_media_controller *pmctl)
 {
-	struct msm_sync *sync = vfe_syncdata;
 	msm_camio_bus_scale_cfg(
-		sync->sdata->pdata->cam_bus_scale_table, S_VIDEO);
+		pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO);
 	vfe32_ctrl->recording_state = VFE_STATE_START_REQUESTED;
 	msm_camera_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
 	return 0;
 }
 
-static int vfe32_stop_recording(void)
+static int vfe32_stop_recording(struct msm_cam_media_controller *pmctl)
 {
-	struct msm_sync *sync = vfe_syncdata;
 	vfe32_ctrl->recording_state = VFE_STATE_STOP_REQUESTED;
 	msm_camera_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
 	msm_camio_bus_scale_cfg(
-		sync->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+		pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
 	return 0;
 }
 
-static void vfe32_start_liveshot(void){
-	struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
-	if (p_sync)
-		p_sync->liveshot_enabled = true;
-
+static void vfe32_start_liveshot(struct msm_cam_media_controller *pmctl)
+{
 	/* Hardcode 1 live snapshot for now. */
 	vfe32_ctrl->outpath.out0.capture_cnt = 1;
 	vfe32_ctrl->vfe_capture_count = vfe32_ctrl->outpath.out0.capture_cnt;
@@ -759,9 +753,8 @@
 	msm_camera_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
 }
 
-static int vfe32_zsl(void)
+static int vfe32_zsl(struct msm_cam_media_controller *pmctl)
 {
-	struct msm_sync *sync = vfe_syncdata;
 	uint32_t irq_comp_mask = 0;
 	/* capture command is valid for both idle and active state. */
 	irq_comp_mask	=
@@ -823,16 +816,17 @@
 	msm_camera_io_w(irq_comp_mask, vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
 	vfe32_start_common();
 	msm_camio_bus_scale_cfg(
-		sync->sdata->pdata->cam_bus_scale_table, S_ZSL);
+		pmctl->sdata->pdata->cam_bus_scale_table, S_ZSL);
 
 	msm_camera_io_w(1, vfe32_ctrl->vfebase + 0x18C);
 	msm_camera_io_w(1, vfe32_ctrl->vfebase + 0x188);
 	return 0;
 }
-static int vfe32_capture_raw(uint32_t num_frames_capture)
+static int vfe32_capture_raw(
+	struct msm_cam_media_controller *pmctl,
+	uint32_t num_frames_capture)
 {
 	uint32_t irq_comp_mask = 0;
-	struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
 
 	vfe32_ctrl->outpath.out0.capture_cnt = num_frames_capture;
 	vfe32_ctrl->vfe_capture_count = num_frames_capture;
@@ -848,19 +842,17 @@
 
 	msm_camera_io_w(irq_comp_mask, vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
 	msm_camio_bus_scale_cfg(
-		p_sync->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
+		pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
 	vfe32_start_common();
 	return 0;
 }
 
-static int vfe32_capture(uint32_t num_frames_capture)
+static int vfe32_capture(
+	struct msm_cam_media_controller *pmctl,
+	uint32_t num_frames_capture)
 {
 	uint32_t irq_comp_mask = 0;
-	struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
-	if (p_sync) {
-		p_sync->snap_count = num_frames_capture;
-		p_sync->thumb_count = num_frames_capture;
-	}
+
 	/* capture command is valid for both idle and active state. */
 	vfe32_ctrl->outpath.out1.capture_cnt = num_frames_capture;
 	if (vfe32_ctrl->operation_mode == VFE_OUTPUTS_MAIN_AND_THUMB ||
@@ -910,7 +902,7 @@
 	msm_camera_io_w(irq_comp_mask, vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
 	msm_camera_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
 	msm_camio_bus_scale_cfg(
-		p_sync->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
+		pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
 
 	vfe32_start_common();
 	/* for debug */
@@ -919,10 +911,9 @@
 	return 0;
 }
 
-static int vfe32_start(void)
+static int vfe32_start(struct msm_cam_media_controller *pmctl)
 {
 	uint32_t irq_comp_mask = 0;
-	struct msm_sync *sync = vfe_syncdata;
 
 	irq_comp_mask	=
 		msm_camera_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
@@ -986,7 +977,7 @@
 	}
 
 	msm_camio_bus_scale_cfg(
-		sync->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+		pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
 	vfe32_start_common();
 	return 0;
 }
@@ -1259,7 +1250,9 @@
 			(void *)&isp_msg_evt);
 }
 
-static int vfe32_proc_general(struct msm_isp_cmd *cmd)
+static int vfe32_proc_general(
+	struct msm_cam_media_controller *pmctl,
+	struct msm_isp_cmd *cmd)
 {
 	int i , rc = 0;
 	uint32_t old_val = 0 , new_val = 0;
@@ -1296,7 +1289,7 @@
 			rc = -EINVAL;
 			goto proc_general_done;
 		}
-		rc = vfe32_start();
+		rc = vfe32_start(pmctl);
 		break;
 	case VFE_CMD_UPDATE:
 		vfe32_update();
@@ -1316,7 +1309,7 @@
 			rc = -EINVAL;
 			goto proc_general_done;
 		}
-		rc = vfe32_capture_raw(snapshot_cnt);
+		rc = vfe32_capture_raw(pmctl, snapshot_cnt);
 		break;
 	case VFE_CMD_CAPTURE:
 		if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value),
@@ -1357,7 +1350,7 @@
 			rc = -EINVAL;
 			goto proc_general_done;
 		}
-		rc = vfe32_capture(snapshot_cnt);
+		rc = vfe32_capture(pmctl, snapshot_cnt);
 		break;
 	case VFE_CMD_START_RECORDING:
 		pr_info("vfe32_proc_general: cmdID = %s\n",
@@ -1378,12 +1371,12 @@
 			rc = -EINVAL;
 			goto proc_general_done;
 		}
-		rc = vfe32_start_recording();
+		rc = vfe32_start_recording(pmctl);
 		break;
 	case VFE_CMD_STOP_RECORDING:
 		pr_info("vfe32_proc_general: cmdID = %s\n",
 			vfe32_general_cmd[cmd->id]);
-		rc = vfe32_stop_recording();
+		rc = vfe32_stop_recording(pmctl);
 		break;
 	case VFE_CMD_OPERATION_CFG: {
 		if (cmd->length != V32_OPERATION_CFG_LEN) {
@@ -1793,7 +1786,7 @@
 			rc = -EINVAL;
 			goto proc_general_done;
 		}
-		vfe32_start_liveshot();
+		vfe32_start_liveshot(pmctl);
 		break;
 
 	case VFE_CMD_LINEARIZATION_CFG:
@@ -2242,7 +2235,7 @@
 		if (rc < 0)
 			goto proc_general_done;
 
-		rc = vfe32_zsl();
+		rc = vfe32_zsl(pmctl);
 		break;
 
 	case VFE_CMD_ASF_CFG:
@@ -3427,9 +3420,9 @@
 	return;
 }
 
-static void vfe32_process_stats_irq(uint32_t *irqstatus)
+static void vfe32_process_stats_irq(uint32_t irqstatus)
 {
-	uint32_t status_bits = VFE_COM_STATUS & *irqstatus;
+	uint32_t status_bits = VFE_COM_STATUS & irqstatus;
 
 	if ((vfe32_ctrl->hfr_mode != HFR_MODE_OFF) &&
 		(vfe32_ctrl->vfeFrameId % vfe32_ctrl->hfr_mode != 0)) {
@@ -3441,47 +3434,113 @@
 	return;
 }
 
-static void vfe32_do_tasklet(unsigned long data)
+static void vfe32_process_irq(uint32_t irqstatus)
+{
+	if (irqstatus &
+		VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK) {
+		vfe32_process_stats_irq(irqstatus);
+		return;
+	}
+
+	switch (irqstatus) {
+	case VFE_IRQ_STATUS0_CAMIF_SOF_MASK:
+		CDBG("irq	camifSofIrq\n");
+		vfe32_process_camif_sof_irq();
+		break;
+	case VFE_IRQ_STATUS0_REG_UPDATE_MASK:
+		CDBG("irq	regUpdateIrq\n");
+		vfe32_process_reg_update_irq();
+		break;
+	case VFE_IMASK_WHILE_STOPPING_1:
+		CDBG("irq	resetAckIrq\n");
+		vfe32_process_reset_irq();
+		break;
+	case VFE_IRQ_STATUS0_STATS_AEC:
+		CDBG("Stats AEC irq occured.\n");
+		vfe32_process_stats_ae_irq();
+		break;
+	case VFE_IRQ_STATUS0_STATS_AWB:
+		CDBG("Stats AWB irq occured.\n");
+		vfe32_process_stats_awb_irq();
+		break;
+	case VFE_IRQ_STATUS0_STATS_AF:
+		CDBG("Stats AF irq occured.\n");
+		vfe32_process_stats_af_irq();
+		break;
+	case VFE_IRQ_STATUS0_STATS_IHIST:
+		CDBG("Stats IHIST irq occured.\n");
+		vfe32_process_stats_ihist_irq();
+		break;
+	case VFE_IRQ_STATUS0_STATS_RS:
+		CDBG("Stats RS irq occured.\n");
+		vfe32_process_stats_rs_irq();
+		break;
+	case VFE_IRQ_STATUS0_STATS_CS:
+		CDBG("Stats CS irq occured.\n");
+		vfe32_process_stats_cs_irq();
+		break;
+	case VFE_IRQ_STATUS0_SYNC_TIMER0:
+		CDBG("SYNC_TIMER 0 irq occured.\n");
+		vfe32_send_isp_msg(vfe32_ctrl,
+			MSG_ID_SYNC_TIMER0_DONE);
+		break;
+	case VFE_IRQ_STATUS0_SYNC_TIMER1:
+		CDBG("SYNC_TIMER 1 irq occured.\n");
+		vfe32_send_isp_msg(vfe32_ctrl,
+			MSG_ID_SYNC_TIMER1_DONE);
+		break;
+	case VFE_IRQ_STATUS0_SYNC_TIMER2:
+		CDBG("SYNC_TIMER 2 irq occured.\n");
+		vfe32_send_isp_msg(vfe32_ctrl,
+			MSG_ID_SYNC_TIMER2_DONE);
+		break;
+	default:
+		pr_err("Invalid IRQ status\n");
+	}
+}
+
+static void axi32_do_tasklet(unsigned long data)
 {
 	unsigned long flags;
-
+	struct axi_ctrl_t *axi_ctrl = (struct axi_ctrl_t *)data;
 	struct vfe32_isr_queue_cmd *qcmd = NULL;
 
-	CDBG("=== vfe32_do_tasklet start ===\n");
+	CDBG("=== axi32_do_tasklet start ===\n");
 
 	while (atomic_read(&irq_cnt)) {
-		spin_lock_irqsave(&vfe32_ctrl->tasklet_lock, flags);
-		qcmd = list_first_entry(&vfe32_ctrl->tasklet_q,
+		spin_lock_irqsave(&axi_ctrl->tasklet_lock, flags);
+		qcmd = list_first_entry(&axi_ctrl->tasklet_q,
 			struct vfe32_isr_queue_cmd, list);
 		atomic_sub(1, &irq_cnt);
 
 		if (!qcmd) {
-			spin_unlock_irqrestore(&vfe32_ctrl->tasklet_lock,
+			spin_unlock_irqrestore(&axi_ctrl->tasklet_lock,
 				flags);
 			return;
 		}
 
 		list_del(&qcmd->list);
-		spin_unlock_irqrestore(&vfe32_ctrl->tasklet_lock,
+		spin_unlock_irqrestore(&axi_ctrl->tasklet_lock,
 			flags);
 
 		if (qcmd->vfeInterruptStatus0 &
-				VFE_IRQ_STATUS0_CAMIF_SOF_MASK) {
-			CDBG("irq	camifSofIrq\n");
-			vfe32_process_camif_sof_irq();
-		}
+				VFE_IRQ_STATUS0_CAMIF_SOF_MASK)
+			v4l2_subdev_notify(&axi_ctrl->subdev,
+				NOTIFY_VFE_IRQ,
+				(void *)VFE_IRQ_STATUS0_CAMIF_SOF_MASK);
+
 		/* interrupt to be processed,  *qcmd has the payload.  */
 		if (qcmd->vfeInterruptStatus0 &
-				VFE_IRQ_STATUS0_REG_UPDATE_MASK) {
-			CDBG("irq	regUpdateIrq\n");
-			vfe32_process_reg_update_irq();
-		}
+				VFE_IRQ_STATUS0_REG_UPDATE_MASK)
+			v4l2_subdev_notify(&axi_ctrl->subdev,
+				NOTIFY_VFE_IRQ,
+				(void *)VFE_IRQ_STATUS0_REG_UPDATE_MASK);
 
 		if (qcmd->vfeInterruptStatus1 &
-				VFE_IMASK_WHILE_STOPPING_1) {
-			CDBG("irq	resetAckIrq\n");
-			vfe32_process_reset_irq();
-		}
+				VFE_IMASK_WHILE_STOPPING_1)
+			v4l2_subdev_notify(&axi_ctrl->subdev,
+				NOTIFY_VFE_IRQ,
+				(void *)VFE_IMASK_WHILE_STOPPING_1);
 
 		if (atomic_read(&vfe32_ctrl->vstate)) {
 			if (qcmd->vfeInterruptStatus1 &
@@ -3491,113 +3550,88 @@
 					qcmd->vfeInterruptStatus1 &
 					VFE32_IMASK_ERROR_ONLY_1);
 			}
-			/* next, check output path related interrupts. */
-			if (qcmd->vfeInterruptStatus0 &
-				VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK) {
-				CDBG("Image composite done 0 irq occured.\n");
-				vfe32_process_output_path_irq_0();
-			}
-			if (qcmd->vfeInterruptStatus0 &
-				VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK) {
-				CDBG("Image composite done 1 irq occured.\n");
-				vfe32_process_output_path_irq_1();
-			}
-			/* in snapshot mode if done then send
-			snapshot done message */
-			if (vfe32_ctrl->operation_mode ==
-					VFE_OUTPUTS_THUMB_AND_MAIN ||
-				vfe32_ctrl->operation_mode ==
-					VFE_OUTPUTS_MAIN_AND_THUMB ||
-				vfe32_ctrl->operation_mode ==
-					VFE_OUTPUTS_THUMB_AND_JPEG ||
-				vfe32_ctrl->operation_mode ==
-					VFE_OUTPUTS_JPEG_AND_THUMB ||
-				vfe32_ctrl->operation_mode ==
-					VFE_OUTPUTS_RAW) {
-				if ((vfe32_ctrl->outpath.out0.capture_cnt == 0)
-						&& (vfe32_ctrl->outpath.out1.
-						capture_cnt == 0)) {
-					msm_camera_io_w_mb(
-						CAMIF_COMMAND_STOP_IMMEDIATELY,
-						vfe32_ctrl->vfebase +
-						VFE_CAMIF_COMMAND);
-					vfe32_send_isp_msg(vfe32_ctrl,
-						MSG_ID_SNAPSHOT_DONE);
-				}
-			}
+			v4l2_subdev_notify(&axi_ctrl->subdev,
+				NOTIFY_AXI_IRQ,
+				(void *)qcmd->vfeInterruptStatus0);
+
 			/* then process stats irq. */
 			if (vfe32_ctrl->stats_comp) {
 				/* process stats comb interrupt. */
 				if (qcmd->vfeInterruptStatus0 &
 					VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK) {
 					CDBG("Stats composite irq occured.\n");
-					vfe32_process_stats_irq(
-						&qcmd->vfeInterruptStatus0);
+					v4l2_subdev_notify(&axi_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)qcmd->vfeInterruptStatus0);
 				}
 			} else {
 				/* process individual stats interrupt. */
 				if (qcmd->vfeInterruptStatus0 &
-						VFE_IRQ_STATUS0_STATS_AEC) {
-					CDBG("Stats AEC irq occured.\n");
-					vfe32_process_stats_ae_irq();
-				}
+						VFE_IRQ_STATUS0_STATS_AEC)
+					v4l2_subdev_notify(&axi_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS0_STATS_AEC);
+
 				if (qcmd->vfeInterruptStatus0 &
-						VFE_IRQ_STATUS0_STATS_AWB) {
-					CDBG("Stats AWB irq occured.\n");
-					vfe32_process_stats_awb_irq();
-				}
+						VFE_IRQ_STATUS0_STATS_AWB)
+					v4l2_subdev_notify(&axi_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS0_STATS_AWB);
+
 				if (qcmd->vfeInterruptStatus0 &
-						VFE_IRQ_STATUS0_STATS_AF) {
-					CDBG("Stats AF irq occured.\n");
-					vfe32_process_stats_af_irq();
-				}
+						VFE_IRQ_STATUS0_STATS_AF)
+					v4l2_subdev_notify(&axi_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS0_STATS_AF);
+
 				if (qcmd->vfeInterruptStatus0 &
-						VFE_IRQ_STATUS0_STATS_IHIST) {
-					CDBG("Stats IHIST irq occured.\n");
-					vfe32_process_stats_ihist_irq();
-				}
+						VFE_IRQ_STATUS0_STATS_IHIST)
+					v4l2_subdev_notify(&axi_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS0_STATS_IHIST);
+
 				if (qcmd->vfeInterruptStatus0 &
-						VFE_IRQ_STATUS0_STATS_RS) {
-					CDBG("Stats RS irq occured.\n");
-					vfe32_process_stats_rs_irq();
-				}
+						VFE_IRQ_STATUS0_STATS_RS)
+					v4l2_subdev_notify(&axi_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS0_STATS_RS);
+
 				if (qcmd->vfeInterruptStatus0 &
-						VFE_IRQ_STATUS0_STATS_CS) {
-					CDBG("Stats CS irq occured.\n");
-					vfe32_process_stats_cs_irq();
-				}
+						VFE_IRQ_STATUS0_STATS_CS)
+					v4l2_subdev_notify(&axi_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS0_STATS_CS);
+
 				if (qcmd->vfeInterruptStatus0 &
-						VFE_IRQ_STATUS0_SYNC_TIMER0) {
-					CDBG("SYNC_TIMER 0 irq occured.\n");
-					vfe32_send_isp_msg(vfe32_ctrl,
-						MSG_ID_SYNC_TIMER0_DONE);
-				}
+						VFE_IRQ_STATUS0_SYNC_TIMER0)
+					v4l2_subdev_notify(&axi_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS0_SYNC_TIMER0);
+
 				if (qcmd->vfeInterruptStatus0 &
-						VFE_IRQ_STATUS0_SYNC_TIMER1) {
-					CDBG("SYNC_TIMER 1 irq occured.\n");
-					vfe32_send_isp_msg(vfe32_ctrl,
-						MSG_ID_SYNC_TIMER1_DONE);
-				}
+						VFE_IRQ_STATUS0_SYNC_TIMER1)
+					v4l2_subdev_notify(&axi_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS0_SYNC_TIMER1);
+
 				if (qcmd->vfeInterruptStatus0 &
-						VFE_IRQ_STATUS0_SYNC_TIMER2) {
-					CDBG("SYNC_TIMER 2 irq occured.\n");
-					vfe32_send_isp_msg(vfe32_ctrl,
-						MSG_ID_SYNC_TIMER2_DONE);
-				}
+						VFE_IRQ_STATUS0_SYNC_TIMER2)
+					v4l2_subdev_notify(&axi_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS0_SYNC_TIMER2);
 			}
 		}
 		kfree(qcmd);
 	}
-	CDBG("=== vfe32_do_tasklet end ===\n");
+	CDBG("=== axi32_do_tasklet end ===\n");
 }
 
-DECLARE_TASKLET(vfe32_tasklet, vfe32_do_tasklet, 0);
-
 static irqreturn_t vfe32_parse_irq(int irq_num, void *data)
 {
 	unsigned long flags;
 	struct vfe32_irq_status irq;
 	struct vfe32_isr_queue_cmd *qcmd;
+	struct axi_ctrl_t *axi_ctrl = data;
 
 	CDBG("vfe_parse_irq\n");
 
@@ -3628,18 +3662,20 @@
 	qcmd->vfeInterruptStatus0 = irq.vfeIrqStatus0;
 	qcmd->vfeInterruptStatus1 = irq.vfeIrqStatus1;
 
-	spin_lock_irqsave(&vfe32_ctrl->tasklet_lock, flags);
-	list_add_tail(&qcmd->list, &vfe32_ctrl->tasklet_q);
+	spin_lock_irqsave(&axi_ctrl->tasklet_lock, flags);
+	list_add_tail(&qcmd->list, &axi_ctrl->tasklet_q);
 
 	atomic_add(1, &irq_cnt);
-	spin_unlock_irqrestore(&vfe32_ctrl->tasklet_lock, flags);
-	tasklet_schedule(&vfe32_tasklet);
+	spin_unlock_irqrestore(&axi_ctrl->tasklet_lock, flags);
+	tasklet_schedule(&axi_ctrl->vfe32_tasklet);
 	return IRQ_HANDLED;
 }
 
 static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd,
 			unsigned int subdev_cmd, void *arg)
 {
+	struct msm_cam_media_controller *pmctl =
+		(struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
 	struct msm_isp_cmd vfecmd;
 	struct msm_camvfe_params *vfe_params =
 		(struct msm_camvfe_params *)arg;
@@ -3651,7 +3687,10 @@
 	struct vfe_cmd_stats_buf *scfg = NULL;
 	struct msm_pmem_region   *regptr = NULL;
 	struct vfe_cmd_stats_ack *sack = NULL;
-	if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
+	if (cmd->cmd_type == CMD_VFE_PROCESS_IRQ) {
+		vfe32_process_irq((uint32_t) data);
+		return rc;
+	} else if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
 		cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
 		cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
 		cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
@@ -3743,7 +3782,7 @@
 	}
 	switch (cmd->cmd_type) {
 	case CMD_GENERAL:
-		rc = vfe32_proc_general(&vfecmd);
+		rc = vfe32_proc_general(pmctl, &vfecmd);
 		break;
 
 	case CMD_CONFIG_PING_ADDR: {
@@ -3788,7 +3827,201 @@
 	case CMD_STATS_CS_BUF_RELEASE:
 		vfe32_stats_cs_ack(sack);
 		break;
+	default:
+		pr_err("%s Unsupported AXI configuration %x ", __func__,
+			cmd->cmd_type);
+		break;
+	}
+vfe32_config_done:
+	kfree(scfg);
+	kfree(sack);
+	CDBG("%s done: rc = %d\n", __func__, (int) rc);
+	return rc;
+}
 
+static struct msm_cam_clk_info vfe32_clk_info[] = {
+	{"vfe_clk", 228570000},
+	{"vfe_pclk", -1},
+	{"csi_vfe_clk", -1},
+};
+
+static int msm_axi_subdev_s_crystal_freq(struct v4l2_subdev *sd,
+						u32 freq, u32 flags)
+{
+	int rc = 0;
+	int round_rate;
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+
+	round_rate = clk_round_rate(axi_ctrl->vfe_clk[0], freq);
+	if (rc < 0) {
+		pr_err("%s: clk_round_rate failed %d\n",
+					__func__, rc);
+		return rc;
+	}
+
+	vfe_clk_rate = round_rate;
+	rc = clk_set_rate(axi_ctrl->vfe_clk[0], round_rate);
+	if (rc < 0)
+		pr_err("%s: clk_set_rate failed %d\n",
+					__func__, rc);
+
+	return rc;
+}
+
+static const struct v4l2_subdev_core_ops msm_vfe_subdev_core_ops = {
+	.ioctl = msm_vfe_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_vfe_subdev_ops = {
+	.core = &msm_vfe_subdev_core_ops,
+};
+
+int msm_axi_subdev_init(struct v4l2_subdev *sd,
+			struct msm_cam_media_controller *mctl)
+{
+	int rc = 0;
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+	v4l2_set_subdev_hostdata(sd, mctl);
+	spin_lock_init(&axi_ctrl->tasklet_lock);
+	INIT_LIST_HEAD(&axi_ctrl->tasklet_q);
+
+	axi_ctrl->vfebase = ioremap(axi_ctrl->vfemem->start,
+		resource_size(axi_ctrl->vfemem));
+	if (!axi_ctrl->vfebase) {
+		rc = -ENOMEM;
+		pr_err("%s: vfe ioremap failed\n", __func__);
+		goto remap_failed;
+	}
+
+	vfe32_ctrl->vfebase = axi_ctrl->vfebase;
+
+	if (axi_ctrl->fs_vfe == NULL) {
+		axi_ctrl->fs_vfe =
+			regulator_get(&axi_ctrl->pdev->dev, "fs_vfe");
+		if (IS_ERR(axi_ctrl->fs_vfe)) {
+			pr_err("%s: Regulator FS_VFE get failed %ld\n",
+				__func__, PTR_ERR(axi_ctrl->fs_vfe));
+			axi_ctrl->fs_vfe = NULL;
+			goto fs_failed;
+		} else if (regulator_enable(axi_ctrl->fs_vfe)) {
+			pr_err("%s: Regulator FS_VFE enable failed\n",
+							__func__);
+			regulator_put(axi_ctrl->fs_vfe);
+			axi_ctrl->fs_vfe = NULL;
+			goto fs_failed;
+		}
+	}
+
+	rc = msm_cam_clk_enable(&axi_ctrl->pdev->dev, vfe32_clk_info,
+			axi_ctrl->vfe_clk, ARRAY_SIZE(vfe32_clk_info), 1);
+	if (rc < 0)
+		goto clk_enable_failed;
+
+	msm_camio_bus_scale_cfg(
+		mctl->sdata->pdata->cam_bus_scale_table, S_INIT);
+	msm_camio_bus_scale_cfg(
+		mctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+
+	if (msm_camera_io_r(vfe32_ctrl->vfebase + V32_GET_HW_VERSION_OFF) ==
+		VFE32_HW_NUMBER)
+		vfe32_ctrl->register_total = VFE32_REGISTER_TOTAL;
+	else
+		vfe32_ctrl->register_total = VFE33_REGISTER_TOTAL;
+
+	enable_irq(axi_ctrl->vfeirq->start);
+
+	return rc;
+clk_enable_failed:
+	regulator_disable(axi_ctrl->fs_vfe);
+	regulator_put(axi_ctrl->fs_vfe);
+	axi_ctrl->fs_vfe = NULL;
+fs_failed:
+	iounmap(axi_ctrl->vfebase);
+	axi_ctrl->vfebase = NULL;
+remap_failed:
+	disable_irq(axi_ctrl->vfeirq->start);
+	return rc;
+}
+
+int msm_vfe_subdev_init(struct v4l2_subdev *sd,
+			struct msm_cam_media_controller *mctl)
+{
+	int rc = 0;
+	v4l2_set_subdev_hostdata(sd, mctl);
+
+	spin_lock_init(&vfe32_ctrl->stop_flag_lock);
+	spin_lock_init(&vfe32_ctrl->state_lock);
+	spin_lock_init(&vfe32_ctrl->io_lock);
+	spin_lock_init(&vfe32_ctrl->update_ack_lock);
+
+	spin_lock_init(&vfe32_ctrl->aec_ack_lock);
+	spin_lock_init(&vfe32_ctrl->awb_ack_lock);
+	spin_lock_init(&vfe32_ctrl->af_ack_lock);
+	spin_lock_init(&vfe32_ctrl->ihist_ack_lock);
+	spin_lock_init(&vfe32_ctrl->rs_ack_lock);
+	spin_lock_init(&vfe32_ctrl->cs_ack_lock);
+	spin_lock_init(&vfe32_ctrl->comp_stats_ack_lock);
+	spin_lock_init(&vfe32_ctrl->sd_notify_lock);
+
+	vfe32_ctrl->update_linear = false;
+	vfe32_ctrl->update_rolloff = false;
+	vfe32_ctrl->update_la = false;
+	vfe32_ctrl->update_gamma = false;
+	vfe32_ctrl->hfr_mode = HFR_MODE_OFF;
+
+	return rc;
+}
+
+void msm_axi_subdev_release(struct v4l2_subdev *sd)
+{
+	struct msm_cam_media_controller *pmctl =
+		(struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+	CDBG("%s, free_irq\n", __func__);
+	disable_irq(axi_ctrl->vfeirq->start);
+	tasklet_kill(&axi_ctrl->vfe32_tasklet);
+	msm_cam_clk_enable(&axi_ctrl->pdev->dev, vfe32_clk_info,
+			axi_ctrl->vfe_clk, ARRAY_SIZE(vfe32_clk_info), 0);
+	if (axi_ctrl->fs_vfe) {
+		regulator_disable(axi_ctrl->fs_vfe);
+		regulator_put(axi_ctrl->fs_vfe);
+		axi_ctrl->fs_vfe = NULL;
+	}
+	iounmap(axi_ctrl->vfebase);
+	axi_ctrl->vfebase = NULL;
+
+	if (atomic_read(&irq_cnt))
+		pr_warning("%s, Warning IRQ Count not ZERO\n", __func__);
+
+	msm_camio_bus_scale_cfg(
+		pmctl->sdata->pdata->cam_bus_scale_table, S_EXIT);
+}
+
+void msm_vfe_subdev_release(struct v4l2_subdev *sd)
+{
+	vfe32_ctrl->vfebase = 0;
+}
+
+static int msm_axi_config(struct v4l2_subdev *sd, void __user *arg)
+{
+	struct msm_vfe_cfg_cmd cfgcmd;
+	struct msm_isp_cmd vfecmd;
+	int rc = 0;
+
+	if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
+		ERR_COPY_FROM_USER();
+		return -EFAULT;
+	}
+
+	if (copy_from_user(&vfecmd,
+			(void __user *)(cfgcmd.value),
+			sizeof(vfecmd))) {
+		pr_err("%s %d: copy_from_user failed\n", __func__,
+			__LINE__);
+		return -EFAULT;
+	}
+
+	switch (cfgcmd.cmd_type) {
 	case CMD_AXI_CFG_PRIM: {
 		uint32_t *axio = NULL;
 		axio = kmalloc(vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length,
@@ -3886,175 +4119,102 @@
 		break;
 	case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC_ALL_CHNLS:
 		pr_err("%s Invalid/Unsupported AXI configuration %x",
-			__func__, cmd->cmd_type);
+			__func__, cfgcmd.cmd_type);
 		break;
 	default:
 		pr_err("%s Unsupported AXI configuration %x ", __func__,
-			cmd->cmd_type);
+			cfgcmd.cmd_type);
 		break;
 	}
-vfe32_config_done:
-	kfree(scfg);
-	kfree(sack);
-	CDBG("%s done: rc = %d\n", __func__, (int) rc);
 	return rc;
 }
 
-static struct msm_cam_clk_info vfe32_clk_info[] = {
-	{"vfe_clk", 228570000},
-	{"vfe_pclk", -1},
-	{"csi_vfe_clk", -1},
-};
-
-static int msm_vfe_subdev_s_crystal_freq(struct v4l2_subdev *sd,
-						u32 freq, u32 flags)
+static void msm_axi_process_irq(struct v4l2_subdev *sd, void *arg)
 {
-	int rc = 0;
-	int round_rate;
-
-	round_rate = clk_round_rate(vfe32_ctrl->vfe_clk[0], freq);
-	if (rc < 0) {
-		pr_err("%s: clk_round_rate failed %d\n",
-					__func__, rc);
-		return rc;
+	uint32_t irqstatus = (uint32_t) arg;
+	/* next, check output path related interrupts. */
+	if (irqstatus &
+		VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK) {
+		CDBG("Image composite done 0 irq occured.\n");
+		vfe32_process_output_path_irq_0();
 	}
-
-	vfe_clk_rate = round_rate;
-	rc = clk_set_rate(vfe32_ctrl->vfe_clk[0], round_rate);
-	if (rc < 0)
-		pr_err("%s: clk_set_rate failed %d\n",
-					__func__, rc);
-
-	return rc;
-}
-
-static const struct v4l2_subdev_video_ops msm_vfe_subdev_video_ops = {
-	.s_crystal_freq = msm_vfe_subdev_s_crystal_freq,
-};
-
-static const struct v4l2_subdev_core_ops msm_vfe_subdev_core_ops = {
-	.ioctl = msm_vfe_subdev_ioctl,
-};
-
-static const struct v4l2_subdev_ops msm_vfe_subdev_ops = {
-	.core = &msm_vfe_subdev_core_ops,
-	.video = &msm_vfe_subdev_video_ops,
-};
-
-int msm_vfe_subdev_init(struct v4l2_subdev *sd, void *data,
-	struct platform_device *pdev)
-{
-	int rc = 0;
-	struct msm_sync *sync = data;
-	v4l2_set_subdev_hostdata(sd, data);
-	vfe_syncdata = data;
-
-	spin_lock_init(&vfe32_ctrl->stop_flag_lock);
-	spin_lock_init(&vfe32_ctrl->state_lock);
-	spin_lock_init(&vfe32_ctrl->io_lock);
-	spin_lock_init(&vfe32_ctrl->update_ack_lock);
-	spin_lock_init(&vfe32_ctrl->tasklet_lock);
-
-	spin_lock_init(&vfe32_ctrl->aec_ack_lock);
-	spin_lock_init(&vfe32_ctrl->awb_ack_lock);
-	spin_lock_init(&vfe32_ctrl->af_ack_lock);
-	spin_lock_init(&vfe32_ctrl->ihist_ack_lock);
-	spin_lock_init(&vfe32_ctrl->rs_ack_lock);
-	spin_lock_init(&vfe32_ctrl->cs_ack_lock);
-	spin_lock_init(&vfe32_ctrl->comp_stats_ack_lock);
-	spin_lock_init(&vfe32_ctrl->sd_notify_lock);
-	INIT_LIST_HEAD(&vfe32_ctrl->tasklet_q);
-
-	vfe32_ctrl->update_linear = false;
-	vfe32_ctrl->update_rolloff = false;
-	vfe32_ctrl->update_la = false;
-	vfe32_ctrl->update_gamma = false;
-	vfe32_ctrl->hfr_mode = HFR_MODE_OFF;
-
-	enable_irq(vfe32_ctrl->vfeirq->start);
-
-	vfe32_ctrl->vfebase = ioremap(vfe32_ctrl->vfemem->start,
-		resource_size(vfe32_ctrl->vfemem));
-	if (!vfe32_ctrl->vfebase) {
-		rc = -ENOMEM;
-		pr_err("%s: vfe ioremap failed\n", __func__);
-		goto vfe_remap_failed;
+	if (irqstatus &
+		VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK) {
+		CDBG("Image composite done 1 irq occured.\n");
+		vfe32_process_output_path_irq_1();
 	}
-
-	if (vfe32_ctrl->fs_vfe == NULL) {
-		vfe32_ctrl->fs_vfe =
-			regulator_get(&vfe32_ctrl->pdev->dev, "fs_vfe");
-		if (IS_ERR(vfe32_ctrl->fs_vfe)) {
-			pr_err("%s: Regulator FS_VFE get failed %ld\n",
-				__func__, PTR_ERR(vfe32_ctrl->fs_vfe));
-			vfe32_ctrl->fs_vfe = NULL;
-			goto vfe_fs_failed;
-		} else if (regulator_enable(vfe32_ctrl->fs_vfe)) {
-			pr_err("%s: Regulator FS_VFE enable failed\n",
-							__func__);
-			regulator_put(vfe32_ctrl->fs_vfe);
-			vfe32_ctrl->fs_vfe = NULL;
-			goto vfe_fs_failed;
+	/* in snapshot mode if done then send
+	snapshot done message */
+	if (vfe32_ctrl->operation_mode ==
+			VFE_OUTPUTS_THUMB_AND_MAIN ||
+		vfe32_ctrl->operation_mode ==
+			VFE_OUTPUTS_MAIN_AND_THUMB ||
+		vfe32_ctrl->operation_mode ==
+			VFE_OUTPUTS_THUMB_AND_JPEG ||
+		vfe32_ctrl->operation_mode ==
+			VFE_OUTPUTS_JPEG_AND_THUMB ||
+		vfe32_ctrl->operation_mode ==
+			VFE_OUTPUTS_RAW) {
+		if ((vfe32_ctrl->outpath.out0.capture_cnt == 0)
+				&& (vfe32_ctrl->outpath.out1.
+				capture_cnt == 0)) {
+			msm_camera_io_w_mb(
+				CAMIF_COMMAND_STOP_IMMEDIATELY,
+				vfe32_ctrl->vfebase +
+				VFE_CAMIF_COMMAND);
+			vfe32_send_isp_msg(vfe32_ctrl,
+				MSG_ID_SNAPSHOT_DONE);
 		}
 	}
-
-	rc = msm_cam_clk_enable(&vfe32_ctrl->pdev->dev, vfe32_clk_info,
-			vfe32_ctrl->vfe_clk, ARRAY_SIZE(vfe32_clk_info), 1);
-	if (rc < 0)
-		goto vfe_clk_enable_failed;
-
-	msm_camio_bus_scale_cfg(
-		sync->sdata->pdata->cam_bus_scale_table, S_INIT);
-	msm_camio_bus_scale_cfg(
-		sync->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
-
-	if (msm_camera_io_r(vfe32_ctrl->vfebase + V32_GET_HW_VERSION_OFF) ==
-		VFE32_HW_NUMBER)
-		vfe32_ctrl->register_total = VFE32_REGISTER_TOTAL;
-	else
-		vfe32_ctrl->register_total = VFE33_REGISTER_TOTAL;
-
-	return rc;
-
-vfe_clk_enable_failed:
-	regulator_disable(vfe32_ctrl->fs_vfe);
-	regulator_put(vfe32_ctrl->fs_vfe);
-	vfe32_ctrl->fs_vfe = NULL;
-vfe_fs_failed:
-	iounmap(vfe32_ctrl->vfebase);
-	vfe32_ctrl->vfebase = NULL;
-vfe_remap_failed:
-	disable_irq(vfe32_ctrl->vfeirq->start);
-	return rc;
 }
 
-void msm_vfe_subdev_release(struct platform_device *pdev)
+static const struct v4l2_subdev_internal_ops msm_vfe_internal_ops;
+
+static long msm_axi_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
 {
-	struct msm_sync *sync = vfe_syncdata;
-	CDBG("%s, free_irq\n", __func__);
-	disable_irq(vfe32_ctrl->vfeirq->start);
-	tasklet_kill(&vfe32_tasklet);
-	msm_cam_clk_enable(&vfe32_ctrl->pdev->dev, vfe32_clk_info,
-			vfe32_ctrl->vfe_clk, ARRAY_SIZE(vfe32_clk_info), 0);
-	if (vfe32_ctrl->fs_vfe) {
-		regulator_disable(vfe32_ctrl->fs_vfe);
-		regulator_put(vfe32_ctrl->fs_vfe);
-		vfe32_ctrl->fs_vfe = NULL;
+	int rc = -ENOIOCTLCMD;
+	switch (cmd) {
+	case VIDIOC_MSM_AXI_INIT:
+		rc = msm_axi_subdev_init(sd,
+			(struct msm_cam_media_controller *)arg);
+		break;
+	case VIDIOC_MSM_AXI_CFG:
+		rc = msm_axi_config(sd, arg);
+		break;
+	case VIDIOC_MSM_AXI_IRQ:
+		msm_axi_process_irq(sd, arg);
+		rc = 0;
+		break;
+	case VIDIOC_MSM_AXI_RELEASE:
+		msm_axi_subdev_release(sd);
+		rc = 0;
+		break;
+	default:
+		pr_err("%s: command not found\n", __func__);
 	}
-	iounmap(vfe32_ctrl->vfebase);
-	vfe32_ctrl->vfebase = NULL;
-
-	if (atomic_read(&irq_cnt))
-		pr_warning("%s, Warning IRQ Count not ZERO\n", __func__);
-
-	msm_camio_bus_scale_cfg(
-		sync->sdata->pdata->cam_bus_scale_table, S_EXIT);
-	vfe_syncdata = NULL;
+	return rc;
 }
 
+static const struct v4l2_subdev_core_ops msm_axi_subdev_core_ops = {
+	.ioctl = msm_axi_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_video_ops msm_axi_subdev_video_ops = {
+	.s_crystal_freq = msm_axi_subdev_s_crystal_freq,
+};
+
+static const struct v4l2_subdev_ops msm_axi_subdev_ops = {
+	.core = &msm_axi_subdev_core_ops,
+	.video = &msm_axi_subdev_video_ops,
+};
+
+static const struct v4l2_subdev_internal_ops msm_axi_internal_ops;
+
 static int __devinit vfe32_probe(struct platform_device *pdev)
 {
 	int rc = 0;
+	struct axi_ctrl_t *axi_ctrl;
 	CDBG("%s: device id = %d\n", __func__, pdev->id);
 	vfe32_ctrl = kzalloc(sizeof(struct vfe32_ctrl_type), GFP_KERNEL);
 	if (!vfe32_ctrl) {
@@ -4062,52 +4222,69 @@
 		return -ENOMEM;
 	}
 
+	axi_ctrl = kzalloc(sizeof(struct axi_ctrl_t), GFP_KERNEL);
+	v4l2_subdev_init(&axi_ctrl->subdev, &msm_axi_subdev_ops);
+	axi_ctrl->subdev.internal_ops = &msm_axi_internal_ops;
+	axi_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(axi_ctrl->subdev.name,
+			 sizeof(axi_ctrl->subdev.name), "axi");
+	v4l2_set_subdevdata(&axi_ctrl->subdev, axi_ctrl);
+	axi_ctrl->pdev = pdev;
+	msm_cam_register_subdev_node(&axi_ctrl->subdev, AXI_DEV, 0);
+
 	v4l2_subdev_init(&vfe32_ctrl->subdev, &msm_vfe_subdev_ops);
+	vfe32_ctrl->subdev.internal_ops = &msm_vfe_internal_ops;
+	vfe32_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 	snprintf(vfe32_ctrl->subdev.name,
 			 sizeof(vfe32_ctrl->subdev.name), "vfe3.2");
 	v4l2_set_subdevdata(&vfe32_ctrl->subdev, vfe32_ctrl);
 	platform_set_drvdata(pdev, &vfe32_ctrl->subdev);
 
-	vfe32_ctrl->vfemem = platform_get_resource_byname(pdev,
+	axi_ctrl->vfemem = platform_get_resource_byname(pdev,
 					IORESOURCE_MEM, "vfe32");
-	if (!vfe32_ctrl->vfemem) {
+	if (!axi_ctrl->vfemem) {
 		pr_err("%s: no mem resource?\n", __func__);
 		rc = -ENODEV;
 		goto vfe32_no_resource;
 	}
-	vfe32_ctrl->vfeirq = platform_get_resource_byname(pdev,
+	axi_ctrl->vfeirq = platform_get_resource_byname(pdev,
 					IORESOURCE_IRQ, "vfe32");
-	if (!vfe32_ctrl->vfeirq) {
+	if (!axi_ctrl->vfeirq) {
 		pr_err("%s: no irq resource?\n", __func__);
 		rc = -ENODEV;
 		goto vfe32_no_resource;
 	}
 
-	vfe32_ctrl->vfeio = request_mem_region(vfe32_ctrl->vfemem->start,
-		resource_size(vfe32_ctrl->vfemem), pdev->name);
-	if (!vfe32_ctrl->vfeio) {
+	axi_ctrl->vfeio = request_mem_region(axi_ctrl->vfemem->start,
+		resource_size(axi_ctrl->vfemem), pdev->name);
+	if (!axi_ctrl->vfeio) {
 		pr_err("%s: no valid mem region\n", __func__);
 		rc = -EBUSY;
 		goto vfe32_no_resource;
 	}
 
-	rc = request_irq(vfe32_ctrl->vfeirq->start, vfe32_parse_irq,
-		IRQF_TRIGGER_RISING, "vfe", 0);
+	rc = request_irq(axi_ctrl->vfeirq->start, vfe32_parse_irq,
+		IRQF_TRIGGER_RISING, "vfe", axi_ctrl);
 	if (rc < 0) {
-		release_mem_region(vfe32_ctrl->vfemem->start,
-			resource_size(vfe32_ctrl->vfemem));
+		release_mem_region(axi_ctrl->vfemem->start,
+			resource_size(axi_ctrl->vfemem));
 		pr_err("%s: irq request fail\n", __func__);
 		rc = -EBUSY;
 		goto vfe32_no_resource;
 	}
 
-	disable_irq(vfe32_ctrl->vfeirq->start);
+	disable_irq(axi_ctrl->vfeirq->start);
+
+	tasklet_init(&axi_ctrl->vfe32_tasklet,
+		axi32_do_tasklet, (unsigned long)axi_ctrl);
 
 	vfe32_ctrl->pdev = pdev;
+	msm_cam_register_subdev_node(&vfe32_ctrl->subdev, VFE_DEV, 0);
 	return 0;
 
 vfe32_no_resource:
 	kfree(vfe32_ctrl);
+	kfree(axi_ctrl);
 	return 0;
 }
 
diff --git a/drivers/media/video/msm/msm_vfe32.h b/drivers/media/video/msm/msm_vfe32.h
index 0d8be58..d1faded 100644
--- a/drivers/media/video/msm/msm_vfe32.h
+++ b/drivers/media/video/msm/msm_vfe32.h
@@ -901,6 +901,23 @@
 	uint32_t bufToRender;
 };
 
+struct axi_ctrl_t {
+	struct v4l2_subdev subdev;
+	struct platform_device *pdev;
+	struct resource *vfeirq;
+	spinlock_t  tasklet_lock;
+	struct list_head tasklet_q;
+
+	void __iomem *vfebase;
+	void *syncdata;
+
+	struct resource	*vfemem;
+	struct resource *vfeio;
+	struct regulator *fs_vfe;
+	struct clk *vfe_clk[3];
+	struct tasklet_struct vfe32_tasklet;
+};
+
 struct vfe32_ctrl_type {
 	uint16_t operation_mode;     /* streaming or snapshot */
 	struct vfe32_output_path outpath;
@@ -934,17 +951,9 @@
 	int8_t update_gamma;
 	enum vfe_output_state liveshot_state;
 
-	spinlock_t  tasklet_lock;
-	struct list_head tasklet_q;
 	void __iomem *vfebase;
-	void *syncdata;
 	uint32_t register_total;
 
-	struct resource	*vfemem;
-	struct resource *vfeio;
-	struct resource *vfeirq;
-	struct regulator *fs_vfe;
-
 	uint32_t stats_comp;
 	atomic_t vstate;
 	uint32_t vfe_capture_count;
@@ -969,7 +978,6 @@
 	/* v4l2 subdev */
 	struct v4l2_subdev subdev;
 	struct platform_device *pdev;
-	struct clk *vfe_clk[3];
 	spinlock_t  sd_notify_lock;
 	uint32_t hfr_mode;
 	uint32_t frame_skip_cnt;
@@ -994,4 +1002,17 @@
 struct vfe_cmd_stats_buf {
 	uint32_t statsBuf[VFE_STATS_BUFFER_COUNT];
 };
+
+#define VIDIOC_MSM_AXI_INIT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 18, struct msm_cam_media_controller *)
+
+#define VIDIOC_MSM_AXI_RELEASE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 19, struct msm_cam_media_controller *)
+
+#define VIDIOC_MSM_AXI_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 20, void *)
+
+#define VIDIOC_MSM_AXI_IRQ \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 21, void *)
+
 #endif /* __MSM_VFE32_H__ */
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index acd9158..dd567d1 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -22,6 +22,7 @@
 #include <media/v4l2-subdev.h>
 #include <media/msm_isp.h>
 #include <mach/msm_adsp.h>
+#include <linux/clk.h>
 #include <mach/clk.h>
 #include <mach/camera.h>
 #include "msm_vfe7x27a_v4l2.h"
@@ -340,7 +341,6 @@
 static uint32_t extlen;
 
 struct mutex vfe_lock;
-static void     *vfe_syncdata;
 static int apps_reset;
 static uint8_t vfestopped;
 
@@ -409,7 +409,7 @@
 
 	CDBG("%s:id=%d\n", __func__, id);
 	if (id != VFE_ADSP_EVENT) {
-		data = kzalloc(len, GFP_KERNEL);
+		data = kzalloc(len, GFP_ATOMIC);
 		if (!data) {
 			pr_err("%s: rp: cannot allocate buffer\n", __func__);
 			return;
@@ -1643,12 +1643,11 @@
 	{"vfe_clk", 192000000},
 };
 
-int msm_vfe_subdev_init(struct v4l2_subdev *sd, void *data,
-	struct platform_device *pdev)
+int msm_vfe_subdev_init(struct v4l2_subdev *sd,
+		struct msm_cam_media_controller *mctl)
 {
 	int rc = 0;
-	v4l2_set_subdev_hostdata(sd, data);
-	vfe_syncdata = data;
+	v4l2_set_subdev_hostdata(sd, mctl);
 
 	spin_lock_init(&vfe2x_ctrl->sd_notify_lock);
 	spin_lock_init(&vfe2x_ctrl->table_lock);
@@ -1702,24 +1701,24 @@
 	return rc;
 }
 
-int msm_vpe_subdev_init(struct v4l2_subdev *sd, void *data,
-	struct platform_device *pdev)
+int msm_vpe_subdev_init(struct v4l2_subdev *sd,
+			struct msm_cam_media_controller *mctl)
 {
 	return 0;
 }
 
-void msm_vpe_subdev_release(struct platform_device *pdev)
+void msm_vpe_subdev_release(void)
 {
 	return;
 }
 
-void msm_vfe_subdev_release(struct platform_device *pdev)
+void msm_vfe_subdev_release(struct v4l2_subdev *sd)
 {
 	CDBG("msm_cam_clk_enable: disable vfe_clk\n");
 	msm_cam_clk_enable(&vfe2x_ctrl->pdev->dev, vfe2x_clk_info,
 			vfe2x_ctrl->vfe_clk, ARRAY_SIZE(vfe2x_clk_info), 0);
-	vfe_syncdata = NULL;
 	apps_reset = 1;
+
 	msm_adsp_disable(qcam_mod);
 	msm_adsp_disable(vfe_mod);
 
@@ -1731,14 +1730,42 @@
 	return;
 }
 
+static int msm_vfe_subdev_s_crystal_freq(struct v4l2_subdev *sd,
+	u32 freq, u32 flags)
+{
+	int rc = 0;
+	int round_rate;
+
+	round_rate = clk_round_rate(vfe2x_ctrl->vfe_clk[0], freq);
+	if (rc < 0) {
+		pr_err("%s: clk_round_rate failed %d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	rc = clk_set_rate(vfe2x_ctrl->vfe_clk[0], round_rate);
+	if (rc < 0)
+		pr_err("%s: clk_set_rate failed %d\n",
+			__func__, rc);
+
+	return rc;
+}
+
+static const struct v4l2_subdev_video_ops msm_vfe_subdev_video_ops = {
+	.s_crystal_freq = msm_vfe_subdev_s_crystal_freq,
+};
+
 static const struct v4l2_subdev_core_ops msm_vfe_subdev_core_ops = {
 	.ioctl = msm_vfe_subdev_ioctl,
 };
 
 static const struct v4l2_subdev_ops msm_vfe_subdev_ops = {
 	.core = &msm_vfe_subdev_core_ops,
+	.video = &msm_vfe_subdev_video_ops,
 };
 
+static const struct v4l2_subdev_internal_ops msm_vfe_internal_ops;
+
 static int __devinit vfe2x_probe(struct platform_device *pdev)
 {
 	CDBG("%s: device id = %d\n", __func__, pdev->id);
@@ -1749,12 +1776,15 @@
 	}
 
 	v4l2_subdev_init(&vfe2x_ctrl->subdev, &msm_vfe_subdev_ops);
+	vfe2x_ctrl->subdev.internal_ops = &msm_vfe_internal_ops;
+	vfe2x_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 	snprintf(vfe2x_ctrl->subdev.name,
 			 sizeof(vfe2x_ctrl->subdev.name), "vfe2.x");
 	v4l2_set_subdevdata(&vfe2x_ctrl->subdev, vfe2x_ctrl);
 	platform_set_drvdata(pdev, &vfe2x_ctrl->subdev);
 
 	vfe2x_ctrl->pdev = pdev;
+	msm_cam_register_subdev_node(&vfe2x_ctrl->subdev, VFE_DEV, 0);
 	return 0;
 }
 
diff --git a/drivers/media/video/msm/msm_vpe.c b/drivers/media/video/msm/msm_vpe.c
index cd503f9..71c10ad 100644
--- a/drivers/media/video/msm/msm_vpe.c
+++ b/drivers/media/video/msm/msm_vpe.c
@@ -50,10 +50,12 @@
 	/*  enable the frame irq, bit 0 = Display list 0 ROI done */
 	msm_camera_io_w_mb(1, vpe_ctrl->vpebase + VPE_INTR_ENABLE_OFFSET);
 	msm_camera_io_dump(vpe_ctrl->vpebase, 0x120);
+	msm_camera_io_dump(vpe_ctrl->vpebase + 0x00400, 0x18);
 	msm_camera_io_dump(vpe_ctrl->vpebase + 0x10000, 0x250);
 	msm_camera_io_dump(vpe_ctrl->vpebase + 0x30000, 0x20);
 	msm_camera_io_dump(vpe_ctrl->vpebase + 0x50000, 0x30);
 	msm_camera_io_dump(vpe_ctrl->vpebase + 0x50400, 0x10);
+
 	/* this triggers the operation. */
 	msm_camera_io_w(1, vpe_ctrl->vpebase + VPE_DL0_START_OFFSET);
 	wmb();
@@ -582,68 +584,10 @@
 	return rc;
 }
 
-static long msm_vpe_subdev_ioctl(struct v4l2_subdev *sd,
-			unsigned int subdev_cmd, void *arg)
-{
-	struct msm_mctl_pp_params *vpe_params =
-		(struct msm_mctl_pp_params *)arg;
-	struct msm_mctl_pp_cmd *cmd = vpe_params->cmd;
-	int rc = 0;
-	switch (cmd->id) {
-	case VPE_CMD_INIT:
-	case VPE_CMD_DEINIT:
-		break;
-	case VPE_CMD_RESET:
-		rc = vpe_reset();
-		break;
-	case VPE_CMD_OPERATION_MODE_CFG:
-		rc = vpe_operation_config(cmd->value);
-		break;
-	case VPE_CMD_INPUT_PLANE_CFG:
-		vpe_input_plane_config(cmd->value);
-		break;
-	case VPE_CMD_OUTPUT_PLANE_CFG:
-		vpe_output_plane_config(cmd->value);
-		break;
-	case VPE_CMD_SCALE_CFG_TYPE:
-		vpe_update_scale_coef(cmd->value);
-		break;
-	case VPE_CMD_ZOOM: {
-		rc = msm_vpe_do_pp(cmd,
-			(struct msm_mctl_pp_frame_info *)vpe_params->data);
-		break;
-	}
-	case VPE_CMD_ENABLE: {
-		struct msm_vpe_clock_rate *clk_rate = cmd->value;
-		int turbo_mode = (int)clk_rate->rate;
-		rc = turbo_mode ? vpe_enable(VPE_TURBO_MODE_CLOCK_RATE) :
-			vpe_enable(VPE_NORMAL_MODE_CLOCK_RATE);
-		break;
-	}
-	case VPE_CMD_DISABLE:
-		rc = vpe_disable();
-		break;
-	case VPE_CMD_INPUT_PLANE_UPDATE:
-	case VPE_CMD_FLUSH:
-	default:
-		break;
-	}
-	CDBG("%s: end, id = %d, rc = %d", __func__, cmd->id, rc);
-	return rc;
-}
+static int msm_vpe_resource_init(void);
 
-static const struct v4l2_subdev_core_ops msm_vpe_subdev_core_ops = {
-	.ioctl = msm_vpe_subdev_ioctl,
-};
-
-static const struct v4l2_subdev_ops msm_vpe_subdev_ops = {
-	.core = &msm_vpe_subdev_core_ops,
-};
-
-static int msm_vpe_resource_init(struct platform_device *pdev);
-
-int msm_vpe_subdev_init(struct v4l2_subdev *sd, void *data,
-	struct platform_device *pdev)
+int msm_vpe_subdev_init(struct v4l2_subdev *sd,
+		struct msm_cam_media_controller *mctl)
 {
 	int rc = 0;
 	CDBG("%s:begin", __func__);
@@ -653,19 +597,19 @@
 	}
 	atomic_set(&vpe_init_done, 1);
 
-	rc = msm_vpe_resource_init(pdev);
+	rc = msm_vpe_resource_init();
 	if (rc < 0) {
 		atomic_set(&vpe_init_done, 0);
 		return rc;
 	}
-	v4l2_set_subdev_hostdata(sd, data);
+	v4l2_set_subdev_hostdata(sd, mctl);
 	spin_lock_init(&vpe_ctrl->lock);
 	CDBG("%s:end", __func__);
 	return rc;
 }
 EXPORT_SYMBOL(msm_vpe_subdev_init);
 
-static int msm_vpe_resource_init(struct platform_device *pdev)
+static int msm_vpe_resource_init(void)
 {
 	int rc = 0;
 
@@ -686,7 +630,7 @@
 	return rc;  /* this rc should have error code. */
 }
 
-void msm_vpe_subdev_release(struct platform_device *pdev)
+void msm_vpe_subdev_release(void)
 {
 	if (!atomic_read(&vpe_init_done)) {
 		/* no VPE object created */
@@ -702,6 +646,77 @@
 }
 EXPORT_SYMBOL(msm_vpe_subdev_release);
 
+static long msm_vpe_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int subdev_cmd, void *arg)
+{
+	struct msm_mctl_pp_params *vpe_params;
+	struct msm_mctl_pp_cmd *cmd;
+	int rc = 0;
+
+	if (subdev_cmd == VIDIOC_MSM_VPE_INIT) {
+		struct msm_cam_media_controller *mctl =
+			(struct msm_cam_media_controller *)arg;
+		msm_vpe_subdev_init(sd, mctl);
+	} else if (subdev_cmd == VIDIOC_MSM_VPE_RELEASE) {
+		msm_vpe_subdev_release();
+	} else if (subdev_cmd == VIDIOC_MSM_VPE_CFG) {
+		vpe_params = (struct msm_mctl_pp_params *)arg;
+		cmd = vpe_params->cmd;
+		switch (cmd->id) {
+		case VPE_CMD_INIT:
+		case VPE_CMD_DEINIT:
+			break;
+		case VPE_CMD_RESET:
+			rc = vpe_reset();
+			break;
+		case VPE_CMD_OPERATION_MODE_CFG:
+			rc = vpe_operation_config(cmd->value);
+			break;
+		case VPE_CMD_INPUT_PLANE_CFG:
+			vpe_input_plane_config(cmd->value);
+			break;
+		case VPE_CMD_OUTPUT_PLANE_CFG:
+			vpe_output_plane_config(cmd->value);
+			break;
+		case VPE_CMD_SCALE_CFG_TYPE:
+			vpe_update_scale_coef(cmd->value);
+			break;
+		case VPE_CMD_ZOOM: {
+			rc = msm_vpe_do_pp(cmd,
+			(struct msm_mctl_pp_frame_info *)vpe_params->data);
+			break;
+		}
+		case VPE_CMD_ENABLE: {
+			struct msm_vpe_clock_rate *clk_rate = cmd->value;
+			int turbo_mode = (int)clk_rate->rate;
+			rc = turbo_mode ?
+				vpe_enable(VPE_TURBO_MODE_CLOCK_RATE) :
+				vpe_enable(VPE_NORMAL_MODE_CLOCK_RATE);
+			break;
+		}
+		case VPE_CMD_DISABLE:
+			rc = vpe_disable();
+			break;
+		case VPE_CMD_INPUT_PLANE_UPDATE:
+		case VPE_CMD_FLUSH:
+		default:
+			break;
+		}
+		CDBG("%s: end, id = %d, rc = %d", __func__, cmd->id, rc);
+	}
+	return rc;
+}
+
+static const struct v4l2_subdev_core_ops msm_vpe_subdev_core_ops = {
+	.ioctl = msm_vpe_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_vpe_subdev_ops = {
+	.core = &msm_vpe_subdev_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops msm_vpe_internal_ops;
+
 static int __devinit vpe_probe(struct platform_device *pdev)
 {
 	int rc = 0;
@@ -714,6 +729,8 @@
 
 	v4l2_subdev_init(&vpe_ctrl->subdev, &msm_vpe_subdev_ops);
 	v4l2_set_subdevdata(&vpe_ctrl->subdev, vpe_ctrl);
+	vpe_ctrl->subdev.internal_ops = &msm_vpe_internal_ops;
+	vpe_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 	snprintf(vpe_ctrl->subdev.name, sizeof(vpe_ctrl->subdev.name), "vpe");
 	platform_set_drvdata(pdev, &vpe_ctrl->subdev);
 
@@ -741,7 +758,7 @@
 	}
 
 	rc = request_irq(vpe_ctrl->vpeirq->start, vpe_parse_irq,
-		IRQF_TRIGGER_RISING, "vfe", 0);
+		IRQF_TRIGGER_RISING, "vpe", 0);
 	if (rc < 0) {
 		release_mem_region(vpe_ctrl->vpemem->start,
 			resource_size(vpe_ctrl->vpemem));
@@ -753,6 +770,7 @@
 	disable_irq(vpe_ctrl->vpeirq->start);
 
 	vpe_ctrl->pdev = pdev;
+	msm_cam_register_subdev_node(&vpe_ctrl->subdev, VPE_DEV, pdev->id);
 	return 0;
 
 vpe_no_resource:
diff --git a/drivers/media/video/msm/msm_vpe.h b/drivers/media/video/msm/msm_vpe.h
index 46c9d2f..0d14626 100644
--- a/drivers/media/video/msm/msm_vpe.h
+++ b/drivers/media/video/msm/msm_vpe.h
@@ -60,7 +60,8 @@
 #define VPE_SCALE_COEFF_LSP_0_OFFSET          0x50400
 #define VPE_SCALE_COEFF_MSP_0_OFFSET          0x50404
 
-#define VPE_AXI_ARB_2_OFFSET                  0x004C
+#define VPE_AXI_ARB_1_OFFSET                  0x00408
+#define VPE_AXI_ARB_2_OFFSET                  0x0040C
 
 #define VPE_SCALE_COEFF_LSBn(n)	(0x50400 + 8 * (n))
 #define VPE_SCALE_COEFF_MSBn(n)	(0x50404 + 8 * (n))
@@ -177,6 +178,14 @@
 	int32_t phase_step_y;
 };
 
+#define VIDIOC_MSM_VPE_INIT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct msm_cam_media_controller *)
+
+#define VIDIOC_MSM_VPE_RELEASE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 16, struct msm_cam_media_controller *)
+
+#define VIDIOC_MSM_VPE_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 17, struct msm_mctl_pp_params *)
 
 #endif /*_MSM_VPE_H_*/
 
diff --git a/drivers/media/video/msm/sensors/Makefile b/drivers/media/video/msm/sensors/Makefile
index 07cea70..13dc446 100644
--- a/drivers/media/video/msm/sensors/Makefile
+++ b/drivers/media/video/msm/sensors/Makefile
@@ -1,6 +1,7 @@
 GCC_VERSION      := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
 EXTRA_CFLAGS += -Idrivers/media/video/msm
 EXTRA_CFLAGS += -Idrivers/media/video/msm/io
+EXTRA_CFLAGS += -Idrivers/media/video/msm/eeprom
 EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
 obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor.o
 obj-$(CONFIG_OV5647) += ov5647_v4l2.o
diff --git a/drivers/media/video/msm/sensors/imx074_v4l2.c b/drivers/media/video/msm/sensors/imx074_v4l2.c
index 67b7140..7e41418 100644
--- a/drivers/media/video/msm/sensors/imx074_v4l2.c
+++ b/drivers/media/video/msm/sensors/imx074_v4l2.c
@@ -224,8 +224,6 @@
 	.vert_offset = 3,
 };
 
-static struct sensor_calib_data imx074_calib_data;
-
 static const struct i2c_device_id imx074_i2c_id[] = {
 	{SENSOR_NAME, (kernel_ulong_t)&imx074_s_ctrl},
 	{ }
@@ -243,37 +241,6 @@
 	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
 };
 
-static struct msm_camera_i2c_client imx074_eeprom_i2c_client = {
-	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
-};
-
-static struct msm_camera_eeprom_read_t imx074_eeprom_read_tbl[] = {
-	{0x10, &imx074_calib_data.r_over_g, 2, 1},
-	{0x12, &imx074_calib_data.b_over_g, 2, 1},
-	{0x14, &imx074_calib_data.gr_over_gb, 2, 1},
-};
-
-static struct msm_camera_eeprom_data_t imx074_eeprom_data_tbl[] = {
-	{&imx074_calib_data, sizeof(struct sensor_calib_data)},
-};
-
-static struct msm_camera_eeprom_client imx074_eeprom_client = {
-	.i2c_client = &imx074_eeprom_i2c_client,
-	.i2c_addr = 0xA4,
-
-	.func_tbl = {
-		.eeprom_set_dev_addr = NULL,
-		.eeprom_init = msm_camera_eeprom_init,
-		.eeprom_release = msm_camera_eeprom_release,
-		.eeprom_get_data = msm_camera_eeprom_get_data,
-	},
-
-	.read_tbl = imx074_eeprom_read_tbl,
-	.read_tbl_size = ARRAY_SIZE(imx074_eeprom_read_tbl),
-	.data_tbl = imx074_eeprom_data_tbl,
-	.data_tbl_size = ARRAY_SIZE(imx074_eeprom_data_tbl),
-};
-
 static int __init msm_sensor_init_module(void)
 {
 	return i2c_add_driver(&imx074_i2c_driver);
@@ -309,6 +276,7 @@
 	.sensor_config = msm_sensor_config,
 	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
+	.sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
 };
 
 static struct msm_sensor_reg_t imx074_regs = {
@@ -333,7 +301,6 @@
 	.msm_sensor_reg = &imx074_regs,
 	.sensor_i2c_client = &imx074_sensor_i2c_client,
 	.sensor_i2c_addr = 0x34,
-	.sensor_eeprom_client = &imx074_eeprom_client,
 	.sensor_output_reg_addr = &imx074_reg_addr,
 	.sensor_id_info = &imx074_id_info,
 	.sensor_exp_gain_info = &imx074_exp_gain_info,
diff --git a/drivers/media/video/msm/sensors/imx091.c b/drivers/media/video/msm/sensors/imx091.c
index 62e97ac..70c3f6e 100644
--- a/drivers/media/video/msm/sensors/imx091.c
+++ b/drivers/media/video/msm/sensors/imx091.c
@@ -303,6 +303,7 @@
 	.sensor_config = msm_sensor_config,
 	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
+	.sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
 };
 
 static struct msm_sensor_reg_t imx091_regs = {
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index cc56ccf..ff5bb49 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -16,6 +16,32 @@
 #include "msm_camera_i2c_mux.h"
 
 /*=============================================================*/
+int32_t msm_sensor_adjust_frame_lines(struct msm_sensor_ctrl_t *s_ctrl,
+	uint16_t res)
+{
+	uint16_t cur_line = 0;
+	uint16_t exp_fl_lines = 0;
+	if (s_ctrl->sensor_exp_gain_info) {
+		msm_camera_i2c_read(s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
+			&cur_line,
+			MSM_CAMERA_I2C_WORD_DATA);
+		exp_fl_lines = cur_line +
+			s_ctrl->sensor_exp_gain_info->vert_offset;
+		if (exp_fl_lines > s_ctrl->msm_sensor_reg->
+			output_settings[res].frame_length_lines)
+			msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+				s_ctrl->sensor_output_reg_addr->
+				frame_length_lines,
+				exp_fl_lines,
+				MSM_CAMERA_I2C_WORD_DATA);
+		CDBG("%s cur_fl_lines %d, exp_fl_lines %d\n", __func__,
+			s_ctrl->msm_sensor_reg->
+			output_settings[res].frame_length_lines,
+			exp_fl_lines);
+	}
+	return 0;
+}
 
 int32_t msm_sensor_write_init_settings(struct msm_sensor_ctrl_t *s_ctrl)
 {
@@ -38,6 +64,12 @@
 		return rc;
 
 	rc = msm_sensor_write_output_settings(s_ctrl, res);
+	if (rc < 0)
+		return rc;
+
+	if (s_ctrl->func_tbl->sensor_adjust_frame_lines)
+		rc = s_ctrl->func_tbl->sensor_adjust_frame_lines(s_ctrl, res);
+
 	return rc;
 }
 
@@ -173,47 +205,6 @@
 	return 0;
 }
 
-int32_t msm_sensor_setting3(struct msm_sensor_ctrl_t *s_ctrl,
-			int update_type, int res)
-{
-	int32_t rc = 0;
-	static int csi_config;
-	if (update_type == MSM_SENSOR_REG_INIT) {
-		CDBG("Register INIT\n");
-		s_ctrl->curr_csi_params = NULL;
-		csi_config = 0;
-		msm_camera_i2c_write(
-			s_ctrl->sensor_i2c_client,
-			0x0e, 0x08,
-			MSM_CAMERA_I2C_BYTE_DATA);
-	} else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
-		CDBG("PERIODIC : %d\n", res);
-		if (res == 0)
-			return 0;
-		if (!csi_config) {
-			msm_sensor_write_conf_array(
-				s_ctrl->sensor_i2c_client,
-				s_ctrl->msm_sensor_reg->mode_settings, res);
-			msleep(30);
-			s_ctrl->curr_csic_params = s_ctrl->csic_params[res];
-			CDBG("CSI config in progress\n");
-			v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
-				NOTIFY_CSIC_CFG,
-				s_ctrl->curr_csic_params);
-			CDBG("CSI config is done\n");
-			mb();
-			msleep(30);
-			msm_camera_i2c_write(
-					s_ctrl->sensor_i2c_client,
-					0x0e, 0x00,
-					MSM_CAMERA_I2C_BYTE_DATA);
-			csi_config = 1;
-		}
-		msleep(50);
-	}
-	return rc;
-}
-
 int32_t msm_sensor_setting1(struct msm_sensor_ctrl_t *s_ctrl,
 			int update_type, int res)
 {
@@ -500,24 +491,6 @@
 				rc = -EFAULT;
 			break;
 
-		case CFG_GET_EEPROM_DATA:
-			if (s_ctrl->sensor_eeprom_client == NULL ||
-				s_ctrl->sensor_eeprom_client->
-				func_tbl.eeprom_get_data == NULL) {
-				rc = -EFAULT;
-				break;
-			}
-			rc = s_ctrl->sensor_eeprom_client->
-				func_tbl.eeprom_get_data(
-				s_ctrl->sensor_eeprom_client,
-				&cdata.cfg.eeprom_data);
-
-			if (copy_to_user((void *)argp,
-				&cdata,
-				sizeof(struct sensor_eeprom_data_t)))
-				rc = -EFAULT;
-			break;
-
 		default:
 			rc = -EFAULT;
 			break;
@@ -614,6 +587,7 @@
 		msm_sensor_enable_i2c_mux(data->sensor_platform_info->i2c_conf);
 
 	return rc;
+
 enable_clk_failed:
 		msm_camera_config_gpio_table(data, 0);
 config_gpio_failed:
@@ -670,13 +644,14 @@
 			s_ctrl->sensor_id_info->sensor_id_reg_addr, &chipid,
 			MSM_CAMERA_I2C_WORD_DATA);
 	if (rc < 0) {
-		CDBG("%s: read id failed\n", __func__);
+		pr_err("%s: %s: read id failed\n", __func__,
+			s_ctrl->sensordata->sensor_name);
 		return rc;
 	}
 
 	CDBG("msm_sensor id: %d\n", chipid);
 	if (chipid != s_ctrl->sensor_id_info->sensor_id) {
-		CDBG("msm_sensor_match_id chip id doesnot match\n");
+		pr_err("msm_sensor_match_id chip id doesnot match\n");
 		return -ENODEV;
 	}
 	return rc;
@@ -732,25 +707,6 @@
 	if (rc < 0)
 		goto probe_fail;
 
-	if (s_ctrl->sensor_eeprom_client != NULL) {
-		struct msm_camera_eeprom_client *eeprom_client =
-			s_ctrl->sensor_eeprom_client;
-		if (eeprom_client->func_tbl.eeprom_init != NULL &&
-			eeprom_client->func_tbl.eeprom_release != NULL) {
-			rc = eeprom_client->func_tbl.eeprom_init(
-				eeprom_client,
-				s_ctrl->sensor_i2c_client->client->adapter);
-			if (rc < 0)
-				goto probe_fail;
-
-			rc = msm_camera_eeprom_read_tbl(eeprom_client,
-			eeprom_client->read_tbl, eeprom_client->read_tbl_size);
-			eeprom_client->func_tbl.eeprom_release(eeprom_client);
-			if (rc < 0)
-				goto probe_fail;
-		}
-	}
-
 	snprintf(s_ctrl->sensor_v4l2_subdev.name,
 		sizeof(s_ctrl->sensor_v4l2_subdev.name), "%s", id->name);
 	v4l2_i2c_subdev_init(&s_ctrl->sensor_v4l2_subdev, client,
@@ -772,10 +728,30 @@
 	int rc = 0;
 	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
 	mutex_lock(s_ctrl->msm_sensor_mutex);
-	if (on)
+	if (on) {
 		rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
-	else
+		if (rc < 0) {
+			pr_err("%s: %s power_up failed rc = %d\n", __func__,
+				s_ctrl->sensordata->sensor_name, rc);
+		} else {
+			if (s_ctrl->func_tbl->sensor_match_id)
+				rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl);
+			else
+				rc = msm_sensor_match_id(s_ctrl);
+			if (rc < 0) {
+				pr_err("%s: %s match_id failed  rc=%d\n",
+					__func__,
+					s_ctrl->sensordata->sensor_name, rc);
+				if (s_ctrl->func_tbl->sensor_power_down(s_ctrl)
+					< 0)
+					pr_err("%s: %s power_down failed\n",
+					__func__,
+					s_ctrl->sensordata->sensor_name);
+			}
+		}
+	} else {
 		rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+	}
 	mutex_unlock(s_ctrl->msm_sensor_mutex);
 	return rc;
 }
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index 0104b98..22cc05b 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -133,6 +133,8 @@
 		(struct msm_sensor_ctrl_t *);
 	int (*sensor_power_up) (struct msm_sensor_ctrl_t *);
 	int32_t (*sensor_match_id)(struct msm_sensor_ctrl_t *s_ctrl);
+	int (*sensor_adjust_frame_lines)
+		(struct msm_sensor_ctrl_t *s_ctrl, uint16_t res);
 };
 
 struct msm_sensor_ctrl_t {
@@ -142,8 +144,6 @@
 	struct msm_camera_i2c_client *sensor_i2c_client;
 	uint16_t sensor_i2c_addr;
 
-	struct msm_camera_eeprom_client *sensor_eeprom_client;
-
 	struct msm_sensor_output_reg_addr_t *sensor_output_reg_addr;
 	struct msm_sensor_id_info_t *sensor_id_info;
 	struct msm_sensor_exp_gain_info_t *sensor_exp_gain_info;
@@ -223,6 +223,9 @@
 int32_t msm_sensor_write_output_settings(struct msm_sensor_ctrl_t *s_ctrl,
 	uint16_t res);
 
+int32_t msm_sensor_adjust_frame_lines(struct msm_sensor_ctrl_t *s_ctrl,
+	uint16_t res);
+
 int32_t msm_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
 			int update_type, int res);
 
@@ -242,7 +245,7 @@
 
 struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd);
 
-#if (defined CONFIG_WEBCAM_OV7692_QRD || defined CONFIG_OV5647)
+#if defined(CONFIG_OV5647)
 	extern int lcd_camera_power_onoff(int on);
 #endif
 
diff --git a/drivers/media/video/msm/sensors/ov2720.c b/drivers/media/video/msm/sensors/ov2720.c
index 05556eb..7531a26 100644
--- a/drivers/media/video/msm/sensors/ov2720.c
+++ b/drivers/media/video/msm/sensors/ov2720.c
@@ -261,6 +261,297 @@
 	{0x3509, 0x20},
 };
 
+static struct msm_camera_i2c_reg_conf ov2720_60fps_settings[] = {
+	{0x3718, 0x10},
+	{0x3702, 0x18},
+	{0x373a, 0x3c},
+	{0x3715, 0x01},
+	{0x3703, 0x1d},
+	{0x3705, 0x0b},
+	{0x3730, 0x1f},
+	{0x3704, 0x3f},
+	{0x3f06, 0x1d},
+	{0x371c, 0x00},
+	{0x371d, 0x83},
+	{0x371e, 0x00},
+	{0x371f, 0xb6},
+	{0x3708, 0x63},
+	{0x3709, 0x52},
+	{0x3800, 0x01},
+	{0x3801, 0x42},
+	{0x3802, 0x00},
+	{0x3803, 0x40},
+	{0x3804, 0x06},
+	{0x3805, 0x61},
+	{0x3806, 0x04},
+	{0x3807, 0x08},
+	{0x3808, 0x02},
+	{0x3809, 0x80},
+	{0x380a, 0x01},
+	{0x380b, 0xe0},
+	{0x380c, 0x03},
+	{0x380d, 0x0c},
+	{0x380e, 0x02},
+	{0x380f, 0x00},
+	{0x3810, 0x00},
+	{0x3811, 0x0f},
+	{0x3812, 0x00},
+	{0x3813, 0x02},
+	{0x3820, 0x80},
+	{0x3821, 0x06},
+	{0x3814, 0x31},
+	{0x3815, 0x31},
+	{0x3612, 0x0b},
+	{0x3618, 0x04},
+	{0x3a08, 0x02},
+	{0x3a09, 0x67},
+	{0x3a0a, 0x02},
+	{0x3a0b, 0x00},
+	{0x3a0d, 0x00},
+	{0x3a0e, 0x00},
+	{0x4520, 0x0a},
+	{0x4837, 0x29},
+	{0x3000, 0xff},
+	{0x3001, 0xff},
+	{0x3002, 0xf0},
+	{0x3600, 0x08},
+	{0x3621, 0xc0},
+	{0x3632, 0xd2},
+	{0x3633, 0x23},
+	{0x3634, 0x54},
+	{0x3f01, 0x0c},
+	{0x5001, 0xc1},
+	{0x3614, 0xf0},
+	{0x3630, 0x2d},
+	{0x370b, 0x62},
+	{0x3706, 0x61},
+	{0x4000, 0x02},
+	{0x4002, 0xc5},
+	{0x4005, 0x08},
+	{0x404f, 0x84},
+	{0x4051, 0x00},
+	{0x5000, 0xff},
+	{0x3a18, 0x00},
+	{0x3a19, 0x80},
+	{0x3503, 0x07},
+	{0x4521, 0x00},
+	{0x5183, 0xb0},
+	{0x5184, 0xb0},
+	{0x5185, 0xb0},
+	{0x370c, 0x0c},
+	{0x3035, 0x30},
+	{0x3036, 0x14},
+	{0x3037, 0x21},
+	{0x303e, 0x19},
+	{0x3038, 0x06},
+	{0x3018, 0x04},
+	{0x3000, 0x00},
+	{0x3001, 0x00},
+	{0x3002, 0x00},
+	{0x3a0f, 0x40},
+	{0x3a10, 0x38},
+	{0x3a1b, 0x48},
+	{0x3a1e, 0x30},
+	{0x3a11, 0x90},
+	{0x3a1f, 0x10},
+	{0x3011, 0x22},
+	{0x3a00, 0x58},
+};
+
+static struct msm_camera_i2c_reg_conf ov2720_90fps_settings[] = {
+	{0x3718, 0x10},
+	{0x3702, 0x18},
+	{0x373a, 0x3c},
+	{0x3715, 0x01},
+	{0x3703, 0x1d},
+	{0x3705, 0x0b},
+	{0x3730, 0x1f},
+	{0x3704, 0x3f},
+	{0x3f06, 0x1d},
+	{0x371c, 0x00},
+	{0x371d, 0x83},
+	{0x371e, 0x00},
+	{0x371f, 0xb6},
+	{0x3708, 0x63},
+	{0x3709, 0x52},
+	{0x3800, 0x01},
+	{0x3801, 0x42},
+	{0x3802, 0x00},
+	{0x3803, 0x40},
+	{0x3804, 0x06},
+	{0x3805, 0x61},
+	{0x3806, 0x04},
+	{0x3807, 0x08},
+	{0x3808, 0x02},
+	{0x3809, 0x80},
+	{0x380a, 0x01},
+	{0x380b, 0xe0},
+	{0x380c, 0x03},
+	{0x380d, 0x0c},
+	{0x380e, 0x02},
+	{0x380f, 0x00},
+	{0x3810, 0x00},
+	{0x3811, 0x0f},
+	{0x3812, 0x00},
+	{0x3813, 0x02},
+	{0x3820, 0x80},
+	{0x3821, 0x06},
+	{0x3814, 0x31},
+	{0x3815, 0x31},
+	{0x3612, 0x0b},
+	{0x3618, 0x04},
+	{0x3a08, 0x02},
+	{0x3a09, 0x67},
+	{0x3a0a, 0x02},
+	{0x3a0b, 0x00},
+	{0x3a0d, 0x00},
+	{0x3a0e, 0x00},
+	{0x4520, 0x0a},
+	{0x4837, 0x29},
+	{0x3000, 0xff},
+	{0x3001, 0xff},
+	{0x3002, 0xf0},
+	{0x3600, 0x08},
+	{0x3621, 0xc0},
+	{0x3632, 0xd2},
+	{0x3633, 0x23},
+	{0x3634, 0x54},
+	{0x3f01, 0x0c},
+	{0x5001, 0xc1},
+	{0x3614, 0xf0},
+	{0x3630, 0x2d},
+	{0x370b, 0x62},
+	{0x3706, 0x61},
+	{0x4000, 0x02},
+	{0x4002, 0xc5},
+	{0x4005, 0x08},
+	{0x404f, 0x84},
+	{0x4051, 0x00},
+	{0x5000, 0xff},
+	{0x3a18, 0x00},
+	{0x3a19, 0x80},
+	{0x3503, 0x07},
+	{0x4521, 0x00},
+	{0x5183, 0xb0},
+	{0x5184, 0xb0},
+	{0x5185, 0xb0},
+	{0x370c, 0x0c},
+	{0x3035, 0x20},
+	{0x3036, 0x14},
+	{0x3037, 0x21},
+	{0x303e, 0x19},
+	{0x3038, 0x06},
+	{0x3018, 0x04},
+	{0x3000, 0x00},
+	{0x3001, 0x00},
+	{0x3002, 0x00},
+	{0x3a0f, 0x40},
+	{0x3a10, 0x38},
+	{0x3a1b, 0x48},
+	{0x3a1e, 0x30},
+	{0x3a11, 0x90},
+	{0x3a1f, 0x10},
+	{0x3011, 0x22},
+	{0x3a00, 0x58},
+};
+
+static struct msm_camera_i2c_reg_conf ov2720_120fps_settings[] = {
+	{0x3718, 0x10},
+	{0x3702, 0x18},
+	{0x373a, 0x3c},
+	{0x3715, 0x01},
+	{0x3703, 0x1d},
+	{0x3705, 0x0b},
+	{0x3730, 0x1f},
+	{0x3704, 0x3f},
+	{0x3f06, 0x1d},
+	{0x371c, 0x00},
+	{0x371d, 0x83},
+	{0x371e, 0x00},
+	{0x371f, 0xb6},
+	{0x3708, 0x63},
+	{0x3709, 0x52},
+	{0x3800, 0x01},
+	{0x3801, 0x42},
+	{0x3802, 0x00},
+	{0x3803, 0x40},
+	{0x3804, 0x06},
+	{0x3805, 0x61},
+	{0x3806, 0x04},
+	{0x3807, 0x08},
+	{0x3808, 0x02},
+	{0x3809, 0x80},
+	{0x380a, 0x01},
+	{0x380b, 0xe0},
+	{0x380c, 0x03},
+	{0x380d, 0x0c},
+	{0x380e, 0x02},
+	{0x380f, 0x00},
+	{0x3810, 0x00},
+	{0x3811, 0x0f},
+	{0x3812, 0x00},
+	{0x3813, 0x02},
+	{0x3820, 0x80},
+	{0x3821, 0x06},
+	{0x3814, 0x31},
+	{0x3815, 0x31},
+	{0x3612, 0x0b},
+	{0x3618, 0x04},
+	{0x3a08, 0x02},
+	{0x3a09, 0x67},
+	{0x3a0a, 0x02},
+	{0x3a0b, 0x00},
+	{0x3a0d, 0x00},
+	{0x3a0e, 0x00},
+	{0x4520, 0x0a},
+	{0x4837, 0x29},
+	{0x3000, 0xff},
+	{0x3001, 0xff},
+	{0x3002, 0xf0},
+	{0x3600, 0x08},
+	{0x3621, 0xc0},
+	{0x3632, 0xd2},
+	{0x3633, 0x23},
+	{0x3634, 0x54},
+	{0x3f01, 0x0c},
+	{0x5001, 0xc1},
+	{0x3614, 0xf0},
+	{0x3630, 0x2d},
+	{0x370b, 0x62},
+	{0x3706, 0x61},
+	{0x4000, 0x02},
+	{0x4002, 0xc5},
+	{0x4005, 0x08},
+	{0x404f, 0x84},
+	{0x4051, 0x00},
+	{0x5000, 0xff},
+	{0x3a18, 0x00},
+	{0x3a19, 0x80},
+	{0x3503, 0x07},
+	{0x4521, 0x00},
+	{0x5183, 0xb0},
+	{0x5184, 0xb0},
+	{0x5185, 0xb0},
+	{0x370c, 0x0c},
+	{0x3035, 0x10},
+	{0x3036, 0x14},
+	{0x3037, 0x21},
+	{0x303e, 0x19},
+	{0x3038, 0x06},
+	{0x3018, 0x04},
+	{0x3000, 0x00},
+	{0x3001, 0x00},
+	{0x3002, 0x00},
+	{0x3a0f, 0x40},
+	{0x3a10, 0x38},
+	{0x3a1b, 0x48},
+	{0x3a1e, 0x30},
+	{0x3a11, 0x90},
+	{0x3a1f, 0x10},
+	{0x3011, 0x22},
+	{0x3a00, 0x58},
+};
+
 static struct msm_camera_i2c_reg_conf ov2720_recommend_settings[] = {
 	{0x0103, 0x01},
 	{0x3718, 0x10},
@@ -302,6 +593,12 @@
 	ARRAY_SIZE(ov2720_vga_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
 	{&ov2720_720_settings[0],
 	ARRAY_SIZE(ov2720_720_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+	{&ov2720_60fps_settings[0],
+	ARRAY_SIZE(ov2720_60fps_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+	{&ov2720_90fps_settings[0],
+	ARRAY_SIZE(ov2720_90fps_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+	{&ov2720_120fps_settings[0],
+	ARRAY_SIZE(ov2720_120fps_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
 };
 
 static struct msm_sensor_output_info_t ov2720_dimensions[] = {
@@ -332,6 +629,33 @@
 		.op_pixel_clk = 72000000,
 		.binning_factor = 1,
 	},
+	{
+		.x_output = 0x280, /* 640 */
+		.y_output = 0x1E0, /* 480 */
+		.line_length_pclk = 0x30C, /* 780 */
+		.frame_length_lines = 0x200, /* 512 */
+		.vt_pixel_clk = 24000000,
+		.op_pixel_clk = 24000000,
+		.binning_factor = 1,
+	},
+	{
+		.x_output = 0x280, /* 640 */
+		.y_output = 0x1E0, /* 480 */
+		.line_length_pclk = 0x30C, /* 780 */
+		.frame_length_lines = 0x200, /* 512 */
+		.vt_pixel_clk = 36000000,
+		.op_pixel_clk = 36000000,
+		.binning_factor = 1,
+	},
+	{
+		.x_output = 0x280, /* 640 */
+		.y_output = 0x1E0, /* 480 */
+		.line_length_pclk = 0x30C, /* 780 */
+		.frame_length_lines = 0x200, /* 512 */
+		.vt_pixel_clk = 48000000,
+		.op_pixel_clk = 48000000,
+		.binning_factor = 1,
+	},
 };
 
 static struct msm_camera_csid_vc_cfg ov2720_cid_cfg[] = {
@@ -357,6 +681,9 @@
 	&ov2720_csi_params,
 	&ov2720_csi_params,
 	&ov2720_csi_params,
+	&ov2720_csi_params,
+	&ov2720_csi_params,
+	&ov2720_csi_params,
 };
 
 static struct msm_sensor_output_reg_addr_t ov2720_reg_addr = {
@@ -456,6 +783,7 @@
 	.sensor_config = msm_sensor_config,
 	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
+	.sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
 };
 
 static struct msm_sensor_reg_t ov2720_regs = {
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
index ca2bb98..d30d48b 100644
--- a/drivers/media/video/msm/sensors/ov5647_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -32,11 +32,12 @@
 };
 
 static struct msm_camera_i2c_reg_conf ov5647_groupon_settings[] = {
-	{0x0104, 0x01},
+	{0x3208, 0x0},
 };
 
 static struct msm_camera_i2c_reg_conf ov5647_groupoff_settings[] = {
-	{0x0104, 0x0},
+	{0x3208, 0x10},
+	{0x3208, 0xa0},
 };
 
 static struct msm_camera_i2c_reg_conf ov5647_prev_settings[] = {
@@ -100,6 +101,65 @@
 	{0x4004, 0x04},
 };
 
+static struct msm_camera_i2c_reg_conf ov5647_video_60fps_settings[] = {
+	{0x3035, 0x21},
+	{0x3036, 0x38},
+	{0x3821, 0x07},
+	{0x3820, 0x41},
+	{0x3612, 0x49},
+	{0x3618, 0x00},
+	{0x380c, 0x07},
+	{0x380d, 0x30},
+	{0x380e, 0x01},
+	{0x380f, 0xf8},
+	{0x3814, 0x71},
+	{0x3815, 0x71},
+	{0x3709, 0x52},
+	{0x3808, 0x02},
+	{0x3809, 0x80},
+	{0x380a, 0x01},
+	{0x380b, 0xe0},
+	{0x3800, 0x00},
+	{0x3801, 0x10},
+	{0x3802, 0x00},
+	{0x3803, 0x00},
+	{0x3804, 0x0a},
+	{0x3805, 0x2f},
+	{0x3806, 0x07},
+	{0x3807, 0x9f},
+	{0x4004, 0x02},
+};
+
+static struct msm_camera_i2c_reg_conf ov5647_video_90fps_settings[] = {
+	{0x3035, 0x11},
+	{0x3036, 0x2a},
+	{0x3821, 0x07},
+	{0x3820, 0x41},
+	{0x3612, 0x49},
+	{0x3618, 0x00},
+	{0x380c, 0x07},
+	{0x380d, 0x30},
+	{0x380e, 0x01},
+	{0x380f, 0xf8},
+	{0x3814, 0x71},
+	{0x3815, 0x71},
+	{0x3709, 0x52},
+	{0x3808, 0x02},
+	{0x3809, 0x80},
+	{0x380a, 0x01},
+	{0x380b, 0xe0},
+	{0x3800, 0x00},
+	{0x3801, 0x10},
+	{0x3802, 0x00},
+	{0x3803, 0x00},
+	{0x3804, 0x0a},
+	{0x3805, 0x2f},
+	{0x3806, 0x07},
+	{0x3807, 0x9f},
+	{0x4004, 0x02},
+};
+
+
 static struct msm_camera_i2c_reg_conf ov5647_recommend_settings[] = {
 	{0x3035, 0x11},
 	{0x303c, 0x11},
@@ -234,6 +294,8 @@
 	{0x518a, 0x04},
 	{0x518b, 0x00},
 	{0x5000, 0x06}, /*No lenc,WBC on*/
+	{0x4005, 0x18},
+	{0x4051, 0x8f},
 };
 
 
@@ -247,6 +309,10 @@
 	ARRAY_SIZE(ov5647_snap_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
 	{&ov5647_prev_settings[0],
 	ARRAY_SIZE(ov5647_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+	{&ov5647_video_60fps_settings[0],
+	ARRAY_SIZE(ov5647_video_60fps_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+	{&ov5647_video_90fps_settings[0],
+	ARRAY_SIZE(ov5647_video_90fps_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
 };
 
 static struct msm_camera_csi_params ov5647_csi_params = {
@@ -286,6 +352,25 @@
 		.op_pixel_clk = 159408000,
 		.binning_factor = 0x0,
 	},
+	{ /* For 60fps */
+		.x_output = 0x280,  /*640*/
+		.y_output = 0x1E0,   /*480*/
+		.line_length_pclk = 0x73C,
+		.frame_length_lines = 0x1F8,
+		.vt_pixel_clk = 56004480,
+		.op_pixel_clk = 159408000,
+		.binning_factor = 0x0,
+	},
+	{ /* For 90fps */
+		.x_output = 0x280,  /*640*/
+		.y_output = 0x1E0,   /*480*/
+		.line_length_pclk = 0x73C,
+		.frame_length_lines = 0x1F8,
+		.vt_pixel_clk = 56004480,
+		.op_pixel_clk = 159408000,
+		.binning_factor = 0x0,
+	},
+
 };
 
 static struct msm_sensor_output_reg_addr_t ov5647_reg_addr = {
@@ -298,6 +383,8 @@
 static struct msm_camera_csi_params *ov5647_csi_params_array[] = {
 	&ov5647_csi_params,
 	&ov5647_csi_params,
+	&ov5647_csi_params,
+	&ov5647_csi_params,
 };
 
 static struct msm_sensor_id_info_t ov5647_id_info = {
@@ -323,7 +410,7 @@
 		uint16_t gain, uint32_t line)
 {
 
-	uint16_t max_line;
+	static uint16_t max_line = 1964;
 	uint8_t gain_lsb, gain_hsb;
 	u8 intg_time_hsb, intg_time_msb, intg_time_lsb;
 
@@ -333,8 +420,8 @@
 	CDBG(KERN_ERR "snapshot exposure seting 0x%x, 0x%x, %d"
 		, gain, line, line);
 
+	s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
 	if (line > 1964) {
-		s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
 		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
 			s_ctrl->sensor_output_reg_addr->frame_length_lines,
 			(uint8_t)((line+4) >> 8),
@@ -344,21 +431,17 @@
 			s_ctrl->sensor_output_reg_addr->frame_length_lines + 1,
 			(uint8_t)((line+4) & 0x00FF),
 			MSM_CAMERA_I2C_BYTE_DATA);
-		s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
-
 		max_line = line + 4;
-	} else if (line > 1968) {
-		s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+	} else if (max_line > 1968) {
 		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
 			s_ctrl->sensor_output_reg_addr->frame_length_lines,
-			(uint8_t)((line+4) >> 8),
+			(uint8_t)(1968 >> 8),
 			MSM_CAMERA_I2C_BYTE_DATA);
 
 		 msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
 			s_ctrl->sensor_output_reg_addr->frame_length_lines + 1,
-			(uint8_t)((line+4) & 0x00FF),
+			(uint8_t)(1968 & 0x00FF),
 			MSM_CAMERA_I2C_BYTE_DATA);
-		s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
 			max_line = 1968;
 	}
 
@@ -370,8 +453,6 @@
 	intg_time_lsb = (u8) (line & 0x00FF);
 
 	/* FIXME for BLC trigger */
-	s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
-
 	/* Coarse Integration Time */
 	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
 		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
@@ -397,7 +478,7 @@
 
 	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
 		s_ctrl->sensor_exp_gain_info->global_gain_addr + 1,
-		gain_lsb-1,
+		gain_lsb^0x1,
 		MSM_CAMERA_I2C_BYTE_DATA);
 
 	/* Coarse Integration Time */
@@ -439,18 +520,20 @@
 						uint16_t gain, uint32_t line)
 {
 
-	uint16_t max_line;
+	static uint16_t max_line = 984;
 	u8 intg_time_hsb, intg_time_msb, intg_time_lsb;
 	uint8_t gain_lsb, gain_hsb;
 
-	pr_info(KERN_ERR "preview exposure setting 0x%x, 0x%x, %d",
+	CDBG(KERN_ERR "preview exposure setting 0x%x, 0x%x, %d",
 		 gain, line, line);
 
 	gain_lsb = (uint8_t) (gain);
 	gain_hsb = (uint8_t)((gain & 0x300)>>8);
+
+	s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+
 	/* adjust frame rate */
 	if (line > 980 && line <= 984) {
-
 		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
 		s_ctrl->sensor_output_reg_addr->frame_length_lines,
 		(uint8_t)((line+4) >> 8),
@@ -461,7 +544,7 @@
 		(uint8_t)((line+4) & 0x00FF),
 		MSM_CAMERA_I2C_BYTE_DATA);
 		max_line = line + 4;
-	} else if (line > 984) {
+	} else if (max_line > 984) {
 
 		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
 		s_ctrl->sensor_output_reg_addr->frame_length_lines,
@@ -481,7 +564,6 @@
 	intg_time_msb = (u8) ((line & 0xFF00) >> 8);
 	intg_time_lsb = (u8) (line & 0x00FF);
 
-	s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
 
 	/* Coarse Integration Time */
 	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
@@ -634,12 +716,12 @@
 {
 	int32_t rc = 0;
 	static int csi_config;
-
 	s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
 	if (csi_config == 0 || res == 0)
 		msleep(66);
 	else
 		msleep(266);
+
 	msm_camera_i2c_write(
 			s_ctrl->sensor_i2c_client,
 			0x4800, 0x25,
diff --git a/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c b/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
index 9fe2e8a..2324495 100644
--- a/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
@@ -13,252 +13,16 @@
 
 #include "msm_sensor.h"
 #define SENSOR_NAME "ov7692"
-#define PLATFORM_DRIVER_NAME "msm_camera_ov7692"
-#define ov7692_obj ov7692_##obj
-#define MSB                             1
-#define LSB                             0
 
 DEFINE_MUTEX(ov7692_mut);
 static struct msm_sensor_ctrl_t ov7692_s_ctrl;
 
-static struct msm_camera_i2c_reg_conf ov7692_prev_settings[] = {
-	{0x12, 0x80},
-	{0x0e, 0x08},
-	{0x69, 0x52},
-	{0x1e, 0xb3},
-	{0x48, 0x42},
-	{0xff, 0x01},
-	{0xae, 0xa0},
-	{0xa8, 0x26},
-	{0xb4, 0xc0},
-	{0xb5, 0x40},
-	{0xff, 0x00},
-	{0x0c, 0x00},
-	{0x62, 0x10},
-	{0x12, 0x00},
-	{0x17, 0x65},
-	{0x18, 0xa4},
-	{0x19, 0x0a},
-	{0x1a, 0xf6},
-	{0x3e, 0x30},
-	{0x64, 0x0a},
-	{0xff, 0x01},
-	{0xb4, 0xc0},
-	{0xff, 0x00},
-	{0x67, 0x20},
-	{0x81, 0x3f},
-	{0xcc, 0x02},
-	{0xcd, 0x80},
-	{0xce, 0x01},
-	{0xcf, 0xe0},
-	{0xc8, 0x02},
-	{0xc9, 0x80},
-	{0xca, 0x01},
-	{0xcb, 0xe0},
-	{0xd0, 0x48},
-	{0x82, 0x03},
-	{0x70, 0x00},
-	{0x71, 0x34},
-	{0x74, 0x28},
-	{0x75, 0x98},
-	{0x76, 0x00},
-	{0x77, 0x64},
-	{0x78, 0x01},
-	{0x79, 0xc2},
-	{0x7a, 0x4e},
-	{0x7b, 0x1f},
-	{0x7c, 0x00},
-	{0x11, 0x00},
-	{0x20, 0x00},
-	{0x21, 0x23},
-	{0x50, 0x9a},
-	{0x51, 0x80},
-	{0x4c, 0x7d},
-	{0x85, 0x10},
-	{0x86, 0x00},
-	{0x87, 0x00},
-	{0x88, 0x00},
-	{0x89, 0x2a},
-	{0x8a, 0x26},
-	{0x8b, 0x22},
-	{0xbb, 0x7a},
-	{0xbc, 0x69},
-	{0xbd, 0x11},
-	{0xbe, 0x13},
-	{0xbf, 0x81},
-	{0xc0, 0x96},
-	{0xc1, 0x1e},
-	{0xb7, 0x05},
-	{0xb8, 0x09},
-	{0xb9, 0x00},
-	{0xba, 0x18},
-	{0x5a, 0x1f},
-	{0x5b, 0x9f},
-	{0x5c, 0x6a},
-	{0x5d, 0x42},
-	{0x24, 0x78},
-	{0x25, 0x68},
-	{0x26, 0xb3},
-	{0xa3, 0x0b},
-	{0xa4, 0x15},
-	{0xa5, 0x2a},
-	{0xa6, 0x51},
-	{0xa7, 0x63},
-	{0xa8, 0x74},
-	{0xa9, 0x83},
-	{0xaa, 0x91},
-	{0xab, 0x9e},
-	{0xac, 0xaa},
-	{0xad, 0xbe},
-	{0xae, 0xce},
-	{0xaf, 0xe5},
-	{0xb0, 0xf3},
-	{0xb1, 0xfb},
-	{0xb2, 0x06},
-	{0x8c, 0x5c},
-	{0x8d, 0x11},
-	{0x8e, 0x12},
-	{0x8f, 0x19},
-	{0x90, 0x50},
-	{0x91, 0x20},
-	{0x92, 0x96},
-	{0x93, 0x80},
-	{0x94, 0x13},
-	{0x95, 0x1b},
-	{0x96, 0xff},
-	{0x97, 0x00},
-	{0x98, 0x3d},
-	{0x99, 0x36},
-	{0x9a, 0x51},
-	{0x9b, 0x43},
-	{0x9c, 0xf0},
-	{0x9d, 0xf0},
-	{0x9e, 0xf0},
-	{0x9f, 0xff},
-	{0xa0, 0x68},
-	{0xa1, 0x62},
-	{0xa2, 0x0e},
-
+static struct msm_camera_i2c_reg_conf ov7692_start_settings[] = {
+	{0x0e, 0x00},
 };
 
-static struct msm_camera_i2c_reg_conf ov7692_snap_settings[] = {
-	{0x12, 0x80},
+static struct msm_camera_i2c_reg_conf ov7692_stop_settings[] = {
 	{0x0e, 0x08},
-	{0x69, 0x52},
-	{0x1e, 0xb3},
-	{0x48, 0x42},
-	{0xff, 0x01},
-	{0xae, 0xa0},
-	{0xa8, 0x26},
-	{0xb4, 0xc0},
-	{0xb5, 0x40},
-	{0xff, 0x00},
-	{0x0c, 0x00},
-	{0x62, 0x10},
-	{0x12, 0x00},
-	{0x17, 0x65},
-	{0x18, 0xa4},
-	{0x19, 0x0a},
-	{0x1a, 0xf6},
-	{0x3e, 0x30},
-	{0x64, 0x0a},
-	{0xff, 0x01},
-	{0xb4, 0xc0},
-	{0xff, 0x00},
-	{0x67, 0x20},
-	{0x81, 0x3f},
-	{0xcc, 0x02},
-	{0xcd, 0x80},
-	{0xce, 0x01},
-	{0xcf, 0xe0},
-	{0xc8, 0x02},
-	{0xc9, 0x80},
-	{0xca, 0x01},
-	{0xcb, 0xe0},
-	{0xd0, 0x48},
-	{0x82, 0x03},
-	{0x70, 0x00},
-	{0x71, 0x34},
-	{0x74, 0x28},
-	{0x75, 0x98},
-	{0x76, 0x00},
-	{0x77, 0x64},
-	{0x78, 0x01},
-	{0x79, 0xc2},
-	{0x7a, 0x4e},
-	{0x7b, 0x1f},
-	{0x7c, 0x00},
-	{0x11, 0x00},
-	{0x20, 0x00},
-	{0x21, 0x23},
-	{0x50, 0x9a},
-	{0x51, 0x80},
-	{0x4c, 0x7d},
-	{0x85, 0x10},
-	{0x86, 0x00},
-	{0x87, 0x00},
-	{0x88, 0x00},
-	{0x89, 0x2a},
-	{0x8a, 0x26},
-	{0x8b, 0x22},
-	{0xbb, 0x7a},
-	{0xbc, 0x69},
-	{0xbd, 0x11},
-	{0xbe, 0x13},
-	{0xbf, 0x81},
-	{0xc0, 0x96},
-	{0xc1, 0x1e},
-	{0xb7, 0x05},
-	{0xb8, 0x09},
-	{0xb9, 0x00},
-	{0xba, 0x18},
-	{0x5a, 0x1f},
-	{0x5b, 0x9f},
-	{0x5c, 0x6a},
-	{0x5d, 0x42},
-	{0x24, 0x78},
-	{0x25, 0x68},
-	{0x26, 0xb3},
-	{0xa3, 0x0b},
-	{0xa4, 0x15},
-	{0xa5, 0x2a},
-	{0xa6, 0x51},
-	{0xa7, 0x63},
-	{0xa8, 0x74},
-	{0xa9, 0x83},
-	{0xaa, 0x91},
-	{0xab, 0x9e},
-	{0xac, 0xaa},
-	{0xad, 0xbe},
-	{0xae, 0xce},
-	{0xaf, 0xe5},
-	{0xb0, 0xf3},
-	{0xb1, 0xfb},
-	{0xb2, 0x06},
-	{0x8c, 0x5c},
-	{0x8d, 0x11},
-	{0x8e, 0x12},
-	{0x8f, 0x19},
-	{0x90, 0x50},
-	{0x91, 0x20},
-	{0x92, 0x96},
-	{0x93, 0x80},
-	{0x94, 0x13},
-	{0x95, 0x1b},
-	{0x96, 0xff},
-	{0x97, 0x00},
-	{0x98, 0x3d},
-	{0x99, 0x36},
-	{0x9a, 0x51},
-	{0x9b, 0x43},
-	{0x9c, 0xf0},
-	{0x9d, 0xf0},
-	{0x9e, 0xf0},
-	{0x9f, 0xff},
-	{0xa0, 0x68},
-	{0xa1, 0x62},
-	{0xa2, 0x0e},
-
 };
 
 static struct msm_camera_i2c_reg_conf ov7692_recommend_settings[] = {
@@ -287,14 +51,6 @@
 	{0xff, 0x00},
 	{0x67, 0x20},
 	{0x81, 0x3f},
-	{0xcc, 0x02},
-	{0xcd, 0x80},
-	{0xce, 0x01},
-	{0xcf, 0xe0},
-	{0xc8, 0x02},
-	{0xc9, 0x80},
-	{0xca, 0x01},
-	{0xcb, 0xe0},
 	{0xd0, 0x48},
 	{0x82, 0x03},
 	{0x70, 0x00},
@@ -378,7 +134,17 @@
 	{0xa0, 0x68},
 	{0xa1, 0x62},
 	{0xa2, 0x0e},
+};
 
+static struct msm_camera_i2c_reg_conf ov7692_full_settings[] = {
+	{0xcc, 0x02},
+	{0xcd, 0x80},
+	{0xce, 0x01},
+	{0xcf, 0xe0},
+	{0xc8, 0x02},
+	{0xc9, 0x80},
+	{0xca, 0x01},
+	{0xcb, 0xe0},
 };
 
 static struct v4l2_subdev_info ov7692_subdev_info[] = {
@@ -398,10 +164,8 @@
 };
 
 static struct msm_camera_i2c_conf_array ov7692_confs[] = {
-	{&ov7692_snap_settings[0],
-	ARRAY_SIZE(ov7692_snap_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
-	{&ov7692_prev_settings[0],
-	ARRAY_SIZE(ov7692_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+	{&ov7692_full_settings[0],
+	ARRAY_SIZE(ov7692_full_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
 };
 
 static struct msm_sensor_output_info_t ov7692_dimensions[] = {
@@ -414,15 +178,6 @@
 		.op_pixel_clk = 9216000,
 		.binning_factor = 1,
 	},
-	{
-		.x_output = 0x280,
-		.y_output = 0x1E0,
-		.line_length_pclk = 0x290,
-		.frame_length_lines = 0x1EC,
-		.vt_pixel_clk = 9216000,
-		.op_pixel_clk = 9216000,
-		.binning_factor = 1,
-	},
 };
 
 
@@ -436,7 +191,6 @@
 
 static struct msm_camera_csi_params *ov7692_csi_params_array[] = {
 	&ov7692_csi_params,
-	&ov7692_csi_params,
 };
 
 static struct msm_sensor_output_reg_addr_t ov7692_reg_addr = {
@@ -451,77 +205,11 @@
 	.sensor_id = 0x7692,
 };
 
-static struct msm_sensor_exp_gain_info_t ov7692_exp_gain_info = {
-	.coarse_int_time_addr = 0x0202,
-	.global_gain_addr = 0x0204,
-	.vert_offset = 4,
-};
-
-static inline uint8_t ov7692_byte(uint16_t word, uint8_t offset)
-{
-	return word >> (offset * BITS_PER_BYTE);
-}
-
-
 static const struct i2c_device_id ov7692_i2c_id[] = {
 	{SENSOR_NAME, (kernel_ulong_t)&ov7692_s_ctrl},
 	{ }
 };
-static int ov7692_pwdn_gpio;
-static int ov7692_reset_gpio;
 
-static int ov7692_probe_init_gpio(const struct msm_camera_sensor_info *data)
-{
-	int rc = 0;
-	CDBG("%s: entered\n", __func__);
-
-	ov7692_pwdn_gpio = data->sensor_pwd;
-	ov7692_reset_gpio = data->sensor_reset ;
-
-	CDBG("%s: pwdn_gpio:%d, reset_gpio:%d\n", __func__,
-			ov7692_pwdn_gpio, ov7692_reset_gpio);
-
-	if (data->sensor_reset_enable)
-		gpio_direction_output(data->sensor_reset, 1);
-
-	gpio_direction_output(data->sensor_pwd, 1);
-
-	return rc;
-
-}
-static void ov7692_power_on(void)
-{
-	CDBG("%s\n", __func__);
-	gpio_set_value(ov7692_pwdn_gpio, 0);
-}
-
-static void ov7692_power_down(void)
-{
-	CDBG("%s\n", __func__);
-	gpio_set_value(ov7692_pwdn_gpio, 1);
-}
-
-int32_t ov7692_sensor_i2c_probe(struct i2c_client *client,
-		const struct i2c_device_id *id)
-{
-	int32_t rc = 0;
-	struct msm_sensor_ctrl_t *s_ctrl;
-	rc = msm_sensor_i2c_probe(client, id);
-
-	ov7692_power_down();
-
-	if (client->dev.platform_data == NULL) {
-		pr_err("%s: NULL sensor data\n", __func__);
-		return -EFAULT;
-	}
-
-	s_ctrl = client->dev.platform_data;
-	if (s_ctrl->sensordata->pmic_gpio_enable)
-		lcd_camera_power_onoff(0);
-
-	return rc;
-
-}
 
 static struct i2c_driver ov7692_i2c_driver = {
 	.id_table = ov7692_i2c_id,
@@ -559,152 +247,26 @@
 	.video  = &ov7692_subdev_video_ops,
 };
 
-static int32_t ov7692_i2c_txdata(struct i2c_client *ov7692_client,
-		unsigned short saddr,
-		unsigned char *txdata, int length)
-{
-	struct i2c_msg msg[] = {
-		{
-			.addr = saddr,
-			.flags = 0,
-			.len = 2,
-			.buf = txdata,
-		},
-	};
-	if (i2c_transfer(ov7692_client->adapter, msg, 1) < 0) {
-		CDBG("ov7692_i2c_txdata faild 0x%x\n", ov7692_client->addr);
-		return -EIO;
-	}
-
-	return 0;
-}
-static int32_t ov7692_i2c_write_b_sensor(struct i2c_client *ov7692_client,
-		uint8_t waddr,
-		uint8_t bdata)
-{
-	int32_t rc = -EFAULT;
-	unsigned char buf[2];
-
-	memset(buf, 0, sizeof(buf));
-	buf[0] = waddr;
-	buf[1] = bdata;
-	CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata);
-	rc = ov7692_i2c_txdata(ov7692_client, ov7692_client->addr >> 1, buf, 2);
-	if (rc < 0)
-		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
-		waddr, bdata);
-
-	return rc;
-}
-
-static int32_t ov7692_write_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
-		uint16_t gain, uint32_t line)
-{
-	CDBG("ov7692_write_exp_gain : Not supported\n");
-	return 0;
-}
-
-int32_t ov7692_sensor_set_fps(struct msm_sensor_ctrl_t *s_ctrl,
-		struct fps_cfg *fps)
-{
-	CDBG("ov7692_sensor_set_fps: Not supported\n");
-	return 0;
-}
-
-
-
-static void ov7692_sw_reset(struct msm_sensor_ctrl_t *s_ctrl)
-{
-
-	CDBG("%s\n", __func__);
-	ov7692_i2c_write_b_sensor(s_ctrl->sensor_i2c_client->client,
-			0x12, 0x80);
-}
-
-static void ov7692_hw_reset(void)
-{
-	CDBG("--CAMERA-- %s ... (Start...)\n", __func__);
-	gpio_set_value(ov7692_reset_gpio, 1);   /*reset camera reset pin*/
-	usleep_range(5000, 5100);
-	gpio_set_value(ov7692_reset_gpio, 0);
-	usleep_range(5000, 5100);
-	gpio_set_value(ov7692_reset_gpio, 1);
-	usleep_range(1000, 1100);
-	CDBG("--CAMERA-- %s ... (End...)\n", __func__);
-}
-
-
-
-int32_t ov7692_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
-{
-	int32_t rc = 0;
-	struct msm_camera_sensor_info *info = NULL;
-
-	CDBG("%s: %d\n", __func__, __LINE__);
-
-	rc = msm_sensor_power_up(s_ctrl);
-	if (rc < 0) {
-		CDBG("%s: msm_sensor_power_up failed\n", __func__);
-		return rc;
-	}
-	info = s_ctrl->sensordata;
-
-	rc = ov7692_probe_init_gpio(info);
-	if (rc < 0) {
-		CDBG("%s: gpio init failed\n", __func__);
-		goto power_up_fail;
-	}
-	/* turn on LDO for PVT */
-	if (info->pmic_gpio_enable)
-		lcd_camera_power_onoff(1);
-
-	ov7692_power_down();
-
-	usleep_range(5000, 5100);
-
-	ov7692_power_on();
-	usleep_range(5000, 5100);
-
-	if (info->sensor_reset_enable)
-		ov7692_hw_reset();
-	else
-		ov7692_sw_reset(s_ctrl);
-
-	return rc;
-
-power_up_fail:
-	CDBG("ov7692_sensor_power_up: OV7692 SENSOR POWER UP FAILS!\n");
-	if (info->pmic_gpio_enable)
-		lcd_camera_power_onoff(0);
-	return rc;
-
-
-}
 
 
 static struct msm_sensor_fn_t ov7692_func_tbl = {
 	.sensor_start_stream = msm_sensor_start_stream,
 	.sensor_stop_stream = msm_sensor_stop_stream,
-	.sensor_group_hold_on = msm_sensor_group_hold_on,
-	.sensor_group_hold_off = msm_sensor_group_hold_off,
-	.sensor_set_fps = ov7692_sensor_set_fps,
-	.sensor_csi_setting = msm_sensor_setting3,
+	.sensor_csi_setting = msm_sensor_setting1,
 	.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
 	.sensor_mode_init = msm_sensor_mode_init,
 	.sensor_get_output_info = msm_sensor_get_output_info,
 	.sensor_config = msm_sensor_config,
-	.sensor_power_up = ov7692_sensor_power_up,
+	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
-	.sensor_write_exp_gain = ov7692_write_exp_gain,
-	.sensor_write_snapshot_exp_gain = ov7692_write_exp_gain,
 };
 
 static struct msm_sensor_reg_t ov7692_regs = {
 	.default_data_type = MSM_CAMERA_I2C_BYTE_DATA,
-	.start_stream_conf_size = 0,
-	.stop_stream_conf_size = 0,
-	.group_hold_on_conf_size = 0,
-	.group_hold_off_conf_size = 0,
+	.start_stream_conf = ov7692_start_settings,
+	.start_stream_conf_size = ARRAY_SIZE(ov7692_start_settings),
+	.stop_stream_conf = ov7692_stop_settings,
+	.stop_stream_conf_size = ARRAY_SIZE(ov7692_stop_settings),
 	.init_settings = &ov7692_init_conf[0],
 	.init_size = ARRAY_SIZE(ov7692_init_conf),
 	.mode_settings = &ov7692_confs[0],
@@ -718,7 +280,6 @@
 	.sensor_i2c_addr = 0x78,
 	.sensor_output_reg_addr = &ov7692_reg_addr,
 	.sensor_id_info = &ov7692_id_info,
-	.sensor_exp_gain_info = &ov7692_exp_gain_info,
 	.cam_mode = MSM_SENSOR_MODE_INVALID,
 	.csic_params = &ov7692_csi_params_array[0],
 	.msm_sensor_mutex = &ov7692_mut,
@@ -731,5 +292,5 @@
 };
 
 module_init(msm_sensor_init_module);
-MODULE_DESCRIPTION("Omni VGA YUV sensor driver");
+MODULE_DESCRIPTION("Omnivision VGA YUV sensor driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/sensors/s5k3l1yx.c b/drivers/media/video/msm/sensors/s5k3l1yx.c
index 8d022b6..debda88 100644
--- a/drivers/media/video/msm/sensors/s5k3l1yx.c
+++ b/drivers/media/video/msm/sensors/s5k3l1yx.c
@@ -652,6 +652,7 @@
 	.sensor_config = msm_sensor_config,
 	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
+	.sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
 };
 
 static struct msm_sensor_reg_t s5k3l1yx_regs = {
diff --git a/drivers/media/video/msm/sensors/s5k4e1_v4l2.c b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
index 6671073..2d25824 100644
--- a/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
+++ b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
@@ -406,6 +406,36 @@
 	return 0;
 }
 
+int32_t s5k4e1_sensor_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int rc = 0;
+	struct msm_camera_sensor_info *s_info;
+
+	rc = msm_sensor_i2c_probe(client, id);
+
+	s_info = client->dev.platform_data;
+	if (s_info == NULL) {
+		pr_err("%s %s NULL sensor data\n", __func__, client->name);
+		return -EFAULT;
+	}
+
+	if (s_info->actuator_info->vcm_enable) {
+		rc = gpio_request(s_info->actuator_info->vcm_pwd,
+				"msm_actuator");
+		if (rc < 0)
+			pr_err("%s: gpio_request:msm_actuator %d failed\n",
+				__func__, s_info->actuator_info->vcm_pwd);
+		rc = gpio_direction_output(s_info->actuator_info->vcm_pwd, 0);
+		if (rc < 0)
+			pr_err("%s: gpio:msm_actuator %d direction can't be set\n",
+				__func__, s_info->actuator_info->vcm_pwd);
+		gpio_free(s_info->actuator_info->vcm_pwd);
+	}
+
+	return rc;
+}
+
 static const struct i2c_device_id s5k4e1_i2c_id[] = {
 	{SENSOR_NAME, (kernel_ulong_t)&s5k4e1_s_ctrl},
 	{ }
@@ -413,7 +443,7 @@
 
 static struct i2c_driver s5k4e1_i2c_driver = {
 	.id_table = s5k4e1_i2c_id,
-	.probe  = msm_sensor_i2c_probe,
+	.probe  = s5k4e1_sensor_i2c_probe,
 	.driver = {
 		.name = SENSOR_NAME,
 	},
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
index e9c710a..b7ae0f4 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.c
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -244,9 +244,11 @@
 		WFD_MSG_DBG("EVENT: not expected = %d\n", event);
 		venc_stop_done(client_ctx, status);
 		break;
-	case VCD_EVT_RESP_PAUSE:
 	case VCD_EVT_RESP_FLUSH_INPUT_DONE:
 	case VCD_EVT_RESP_FLUSH_OUTPUT_DONE:
+		venc_notify_client(client_ctx);
+		break;
+	case VCD_EVT_RESP_PAUSE:
 	case VCD_EVT_IND_OUTPUT_RECONFIG:
 		WFD_MSG_DBG("EVENT: not expected = %d\n", event);
 		break;
@@ -1935,6 +1937,46 @@
 					 (u8 *)kernel_vaddr);
 }
 
+static long venc_flush_buffers(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct venc_inst *inst = sd->dev_priv;
+	struct video_client_ctx *client_ctx = &inst->venc_client;
+	if (!client_ctx) {
+		WFD_MSG_ERR("Invalid input\n");
+		return -EINVAL;
+	}
+	rc = vcd_flush(client_ctx->vcd_handle, VCD_FLUSH_INPUT);
+	if (rc) {
+		WFD_MSG_ERR("Failed to flush input buffers\n");
+		rc = -EIO;
+		goto flush_failed;
+	}
+	wait_for_completion(&client_ctx->event);
+	if (client_ctx->event_status) {
+		WFD_MSG_ERR("callback for vcd_flush input returned error: %u",
+				client_ctx->event_status);
+		rc = -EIO;
+		goto flush_failed;
+	}
+	rc = vcd_flush(client_ctx->vcd_handle, VCD_FLUSH_OUTPUT);
+	if (rc) {
+		WFD_MSG_ERR("Failed to flush output buffers\n");
+		rc = -EIO;
+		goto flush_failed;
+	}
+	wait_for_completion(&client_ctx->event);
+	if (client_ctx->event_status) {
+		WFD_MSG_ERR("callback for vcd_flush output returned error: %u",
+				client_ctx->event_status);
+		rc = -EIO;
+		goto flush_failed;
+	}
+
+flush_failed:
+	return rc;
+}
+
 static long venc_free_input_buffer(struct v4l2_subdev *sd, void *arg)
 {
 	int del_rc = 0, free_rc = 0;
@@ -2203,6 +2245,9 @@
 	case FREE_RECON_BUFFERS:
 		rc = venc_free_recon_buffers(sd, arg);
 		break;
+	case ENCODE_FLUSH:
+		rc = venc_flush_buffers(sd, arg);
+		break;
 	default:
 		rc = -1;
 		break;
diff --git a/drivers/media/video/msm/wfd/enc-subdev.h b/drivers/media/video/msm/wfd/enc-subdev.h
index cafc9d5..5873e62 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.h
+++ b/drivers/media/video/msm/wfd/enc-subdev.h
@@ -74,6 +74,7 @@
 #define FREE_OUTPUT_BUFFER _IOWR('V', 21, struct mem_region *)
 #define FREE_INPUT_BUFFER _IOWR('V', 22, struct mem_region *)
 #define FREE_RECON_BUFFERS _IO('V', 23)
+#define ENCODE_FLUSH _IO('V', 24)
 
 extern int venc_init(struct v4l2_subdev *sd, u32 val);
 extern int venc_load_fw(struct v4l2_subdev *sd);
diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm/wfd/wfd-ioctl.c
index 7ab5d17..2242aa8 100644
--- a/drivers/media/video/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm/wfd/wfd-ioctl.c
@@ -517,8 +517,10 @@
 			core, ioctl, MDP_DQ_BUFFER, (void *)&obuf_mdp);
 
 		if (rc) {
-			WFD_MSG_ERR("Either streamoff called or"
-						" MDP REPORTED ERROR\n");
+			if (rc != -ENOBUFS)
+				WFD_MSG_ERR("MDP reported err %d\n", rc);
+
+			WFD_MSG_ERR("Streamoff called\n");
 			break;
 		} else {
 			wfd_stats_update(&inst->stats,
@@ -614,6 +616,10 @@
 		WFD_MSG_ERR("Failed to stop VSG\n");
 
 	kthread_stop(inst->mdp_task);
+	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+			ENCODE_FLUSH, (void *)inst->venc_inst);
+	if (rc)
+		WFD_MSG_ERR("Failed to flush encoder\n");
 	WFD_MSG_DBG("enc stop\n");
 	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
 			ENCODE_STOP, (void *)inst->venc_inst);
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
new file mode 100644
index 0000000..25b5c5c
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -0,0 +1,244 @@
+/* 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/slab.h>
+#include "msm_smem.h"
+
+struct smem_client {
+	int mem_type;
+	void *clnt;
+};
+
+static int ion_user_to_kernel(struct smem_client *client,
+			int fd, u32 offset, struct msm_smem *mem)
+{
+	struct ion_handle *hndl;
+	unsigned long ionflag;
+	size_t len;
+	int rc = 0;
+	hndl = ion_import_fd(client->clnt, fd);
+	if (IS_ERR_OR_NULL(hndl)) {
+		pr_err("Failed to get handle: %p, %d, %d, %p\n",
+				client, fd, offset, hndl);
+		rc = -ENOMEM;
+		goto fail_import_fd;
+	}
+	rc = ion_handle_get_flags(client->clnt, hndl, &ionflag);
+	if (rc) {
+		pr_err("Failed to get ion flags: %d", rc);
+		goto fail_map;
+	}
+	rc = ion_phys(client->clnt, hndl, &mem->paddr, &len);
+	if (rc) {
+		pr_err("Failed to get physical address\n");
+		goto fail_map;
+	}
+	mem->kvaddr = ion_map_kernel(client->clnt, hndl, ionflag);
+	if (!mem->kvaddr) {
+		pr_err("Failed to map shared mem in kernel\n");
+		rc = -EIO;
+		goto fail_map;
+	}
+
+	mem->kvaddr += offset;
+	mem->paddr += offset;
+	mem->mem_type = client->mem_type;
+	mem->smem_priv = hndl;
+	mem->device_addr = mem->paddr;
+	mem->size = len;
+	return rc;
+fail_map:
+	ion_free(client->clnt, hndl);
+fail_import_fd:
+	return rc;
+}
+
+static int alloc_ion_mem(struct smem_client *client, size_t size,
+		u32 align, u32 flags, struct msm_smem *mem)
+{
+	struct ion_handle *hndl;
+	size_t len;
+	int rc = 0;
+	flags = flags | ION_HEAP(ION_CP_MM_HEAP_ID);
+	hndl = ion_alloc(client->clnt, size, align, flags);
+	if (IS_ERR_OR_NULL(hndl)) {
+		pr_err("Failed to allocate shared memory = %p, %d, %d, 0x%x\n",
+				client, size, align, flags);
+		rc = -ENOMEM;
+		goto fail_shared_mem_alloc;
+	}
+	mem->mem_type = client->mem_type;
+	mem->smem_priv = hndl;
+	if (ion_phys(client->clnt, hndl, &mem->paddr, &len)) {
+		pr_err("Failed to get physical address\n");
+		rc = -EIO;
+		goto fail_map;
+	}
+	mem->device_addr = mem->paddr;
+	mem->size = size;
+	mem->kvaddr = ion_map_kernel(client->clnt, hndl, 0);
+	if (!mem->kvaddr) {
+		pr_err("Failed to map shared mem in kernel\n");
+		rc = -EIO;
+		goto fail_map;
+	}
+	return rc;
+fail_map:
+	ion_free(client->clnt, hndl);
+fail_shared_mem_alloc:
+	return rc;
+}
+
+static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
+{
+	ion_unmap_kernel(client->clnt, mem->smem_priv);
+	ion_free(client->clnt, mem->smem_priv);
+}
+
+static void *ion_new_client(void)
+{
+	struct ion_client *client = NULL;
+	client = msm_ion_client_create(-1, "video_client");
+	if (!client)
+		pr_err("Failed to create smem client\n");
+	return client;
+};
+
+static void ion_delete_client(struct smem_client *client)
+{
+	ion_client_destroy(client->clnt);
+}
+
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset)
+{
+	struct smem_client *client = clt;
+	int rc = 0;
+	struct msm_smem *mem;
+	if (fd < 0) {
+		pr_err("Invalid fd: %d\n", fd);
+		return NULL;
+	}
+	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+	if (!mem) {
+		pr_err("Failed to allocte shared mem\n");
+		return NULL;
+	}
+	switch (client->mem_type) {
+	case SMEM_ION:
+		rc = ion_user_to_kernel(clt, fd, offset, mem);
+		break;
+	default:
+		pr_err("Mem type not supported\n");
+		rc = -EINVAL;
+		break;
+	}
+	if (rc) {
+		pr_err("Failed to allocate shared memory\n");
+		kfree(mem);
+		mem = NULL;
+	}
+	return mem;
+}
+
+void *msm_smem_new_client(enum smem_type mtype)
+{
+	struct smem_client *client = NULL;
+	void *clnt = NULL;
+	switch (mtype) {
+	case SMEM_ION:
+		clnt = ion_new_client();
+		break;
+	default:
+		pr_err("Mem type not supported\n");
+		break;
+	}
+	if (clnt) {
+		client = kzalloc(sizeof(*client), GFP_KERNEL);
+		if (client) {
+			client->mem_type = mtype;
+			client->clnt = clnt;
+		}
+	} else {
+		pr_err("Failed to create new client: mtype = %d\n", mtype);
+	}
+	return client;
+};
+
+struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags)
+{
+	struct smem_client *client;
+	int rc = 0;
+	struct msm_smem *mem;
+
+	client = clt;
+	if (!client) {
+		pr_err("Invalid  client passed\n");
+		return NULL;
+	}
+	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+	if (!mem) {
+		pr_err("Failed to allocate shared mem\n");
+		return NULL;
+	}
+	switch (client->mem_type) {
+	case SMEM_ION:
+		rc = alloc_ion_mem(client, size, align, flags, mem);
+		break;
+	default:
+		pr_err("Mem type not supported\n");
+		rc = -EINVAL;
+		break;
+	}
+	if (rc) {
+		pr_err("Failed to allocate shared memory\n");
+		kfree(mem);
+		mem = NULL;
+	}
+	return mem;
+}
+
+void msm_smem_free(void *clt, struct msm_smem *mem)
+{
+	struct smem_client *client = clt;
+	if (!client || !mem) {
+		pr_err("Invalid  client/handle passed\n");
+		return;
+	}
+	switch (client->mem_type) {
+	case SMEM_ION:
+		free_ion_mem(client, mem);
+		break;
+	default:
+		pr_err("Mem type not supported\n");
+		break;
+	}
+	kfree(mem);
+};
+
+void msm_smem_delete_client(void *clt)
+{
+	struct smem_client *client = clt;
+	if (!client) {
+		pr_err("Invalid  client passed\n");
+		return;
+	}
+	switch (client->mem_type) {
+	case SMEM_ION:
+		ion_delete_client(client);
+		break;
+	default:
+		pr_err("Mem type not supported\n");
+		break;
+	}
+	kfree(client);
+}
diff --git a/drivers/media/video/msm_vidc/msm_smem.h b/drivers/media/video/msm_vidc/msm_smem.h
new file mode 100644
index 0000000..84d12cc
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_smem.h
@@ -0,0 +1,38 @@
+/* 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.
+ *
+ */
+#ifndef _MSM_SMEM_H_
+#define _MSM_SMEM_H_
+
+#include <linux/types.h>
+#include <linux/ion.h>
+
+enum smem_type {
+	SMEM_ION,
+};
+
+struct msm_smem {
+	int mem_type;
+	size_t size;
+	void *kvaddr;
+	unsigned long paddr;
+	unsigned long device_addr;
+	/*Device address and others to follow*/
+	void *smem_priv;
+};
+
+void *msm_smem_new_client(enum smem_type mtype);
+struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags);
+void msm_smem_free(void *clt, struct msm_smem *mem);
+void msm_smem_delete_client(void *clt);
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset);
+#endif
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
new file mode 100644
index 0000000..f125cdc
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -0,0 +1,505 @@
+/* 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/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/version.h>
+#include <linux/slab.h>
+
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+#include "vidc_hal_api.h"
+#include "msm_smem.h"
+
+#define BASE_DEVICE_NUMBER 32
+
+struct msm_vidc_drv *vidc_driver;
+
+struct buffer_info {
+	struct list_head list;
+	int type;
+	int fd;
+	int buff_off;
+	int size;
+	u32 uvaddr;
+	struct msm_smem *handle;
+};
+
+struct msm_v4l2_vid_inst {
+	void *vidc_inst;
+	void *mem_client;
+	struct list_head registered_bufs;
+};
+
+struct buffer_info *get_registered_buf(struct list_head *list,
+				int fd, u32 buff_off, u32 size)
+{
+	struct buffer_info *temp;
+	struct buffer_info *ret = NULL;
+	if (!list || fd < 0) {
+		pr_err("%s Invalid input\n", __func__);
+		goto err_invalid_input;
+	}
+	if (!list_empty(list)) {
+		list_for_each_entry(temp, list, list) {
+			if (temp && temp->fd == fd &&
+			(CONTAINS(temp->buff_off, temp->size, buff_off)
+			|| CONTAINS(buff_off, size, temp->buff_off)
+			|| OVERLAPS(buff_off, size,
+				temp->buff_off, temp->size))) {
+				pr_err("This memory region is already mapped\n");
+				ret = temp;
+				break;
+			}
+		}
+	}
+err_invalid_input:
+	return ret;
+}
+
+static int msm_v4l2_open(struct file *filp)
+{
+	int rc = 0;
+	struct video_device *vdev = video_devdata(filp);
+	struct msm_video_device *vid_dev =
+		container_of(vdev, struct msm_video_device, vdev);
+	struct msm_vidc_core *core = video_drvdata(filp);
+	void *inst;
+	struct msm_v4l2_vid_inst *v4l2_inst = kzalloc(sizeof(*v4l2_inst),
+						GFP_KERNEL);
+	if (!v4l2_inst) {
+		pr_err("Failed to allocate memory for this instance\n");
+		rc = -ENOMEM;
+		goto fail_nomem;
+	}
+	v4l2_inst->mem_client = msm_smem_new_client(SMEM_ION);
+	if (!v4l2_inst->mem_client) {
+		pr_err("Failed to create memory client\n");
+		rc = -ENOMEM;
+		goto fail_mem_client;
+	}
+	inst = msm_vidc_open(core->id, vid_dev->type);
+	if (!inst) {
+		pr_err("Failed to create video instance, core: %d, type = %d\n",
+			core->id, vid_dev->type);
+		rc = -ENOMEM;
+		goto fail_open;
+	}
+	INIT_LIST_HEAD(&v4l2_inst->registered_bufs);
+	v4l2_inst->vidc_inst = inst;
+	filp->private_data = v4l2_inst;
+	return rc;
+fail_open:
+	msm_smem_delete_client(v4l2_inst->mem_client);
+fail_mem_client:
+	kfree(v4l2_inst);
+fail_nomem:
+	return rc;
+}
+
+static int msm_v4l2_close(struct file *filp)
+{
+	int rc;
+	struct list_head *ptr, *next;
+	struct buffer_info *binfo;
+	struct msm_v4l2_vid_inst *v4l2_inst = filp->private_data;
+	rc = msm_vidc_close(v4l2_inst->vidc_inst);
+	list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
+		binfo = list_entry(ptr, struct buffer_info, list);
+		list_del(&binfo->list);
+		msm_smem_free(v4l2_inst->mem_client, binfo->handle);
+		kfree(binfo);
+	}
+	msm_smem_delete_client(v4l2_inst->mem_client);
+	kfree(v4l2_inst);
+	return rc;
+}
+
+static int msm_v4l2_querycap(struct file *filp, void *fh,
+			struct v4l2_capability *cap)
+{
+	struct msm_v4l2_vid_inst *v4l2_inst = filp->private_data;
+	return msm_vidc_querycap(v4l2_inst->vidc_inst, cap);
+}
+
+int msm_v4l2_enum_fmt(struct file *file, void *fh,
+					struct v4l2_fmtdesc *f)
+{
+	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+	return msm_vidc_enum_fmt(v4l2_inst->vidc_inst, f);
+}
+
+int msm_v4l2_s_fmt(struct file *file, void *fh,
+					struct v4l2_format *f)
+{
+	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+	return msm_vidc_s_fmt(v4l2_inst->vidc_inst, f);
+}
+
+int msm_v4l2_g_fmt(struct file *file, void *fh,
+					struct v4l2_format *f)
+{
+	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+	return msm_vidc_g_fmt(v4l2_inst->vidc_inst, f);
+}
+
+int msm_v4l2_s_ctrl(struct file *file, void *fh,
+					struct v4l2_control *a)
+{
+	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+	return msm_vidc_s_ctrl(v4l2_inst->vidc_inst, a);
+}
+
+int msm_v4l2_g_ctrl(struct file *file, void *fh,
+					struct v4l2_control *a)
+{
+	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+	return msm_vidc_g_ctrl(v4l2_inst->vidc_inst, a);
+}
+
+int msm_v4l2_reqbufs(struct file *file, void *fh,
+				struct v4l2_requestbuffers *b)
+{
+	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+	return msm_vidc_reqbufs(v4l2_inst->vidc_inst, b);
+}
+
+int msm_v4l2_prepare_buf(struct file *file, void *fh,
+				struct v4l2_buffer *b)
+{
+	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+	struct msm_smem *handle;
+	struct buffer_info *binfo;
+	int rc = 0;
+	int i;
+	if (!v4l2_inst->mem_client) {
+		pr_err("Failed to get memory client\n");
+		rc = -ENOMEM;
+		goto exit;
+	}
+	for (i = 0; i < b->length; ++i) {
+		binfo = get_registered_buf(&v4l2_inst->registered_bufs,
+				b->m.planes[i].reserved[0],
+				b->m.planes[i].reserved[1],
+				b->m.planes[i].length);
+		if (binfo) {
+			pr_err("This memory region has already been prepared\n");
+			rc = -EINVAL;
+			goto exit;
+		}
+		binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+		if (!binfo) {
+			pr_err("Out of memory\n");
+			rc = -ENOMEM;
+			goto exit;
+		}
+		handle = msm_smem_user_to_kernel(v4l2_inst->mem_client,
+				b->m.planes[i].reserved[0],
+				b->m.planes[i].reserved[1]);
+		if (!handle) {
+			pr_err("Failed to get device buffer address\n");
+			kfree(binfo);
+			goto exit;
+		}
+		binfo->type = b->type;
+		binfo->fd = b->m.planes[i].reserved[0];
+		binfo->buff_off = b->m.planes[i].reserved[1];
+		binfo->size = b->m.planes[i].length;
+		binfo->uvaddr = b->m.planes[i].m.userptr;
+		binfo->handle = handle;
+		pr_debug("Registering buffer: %d, %d, %d\n",
+				b->m.planes[i].reserved[0],
+				b->m.planes[i].reserved[1],
+				b->m.planes[i].length);
+		list_add_tail(&binfo->list, &v4l2_inst->registered_bufs);
+		b->m.planes[i].m.userptr = handle->device_addr;
+	}
+	rc = msm_vidc_prepare_buf(v4l2_inst->vidc_inst, b);
+exit:
+	return rc;
+}
+
+int msm_v4l2_qbuf(struct file *file, void *fh,
+				struct v4l2_buffer *b)
+{
+	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+	struct buffer_info *binfo;
+	int rc = 0;
+	int i;
+	for (i = 0; i < b->length; ++i) {
+		binfo = get_registered_buf(&v4l2_inst->registered_bufs,
+				b->m.planes[i].reserved[0],
+				b->m.planes[i].reserved[1],
+				b->m.planes[i].length);
+		if (!binfo) {
+			pr_err("This buffer is not registered: %d, %d, %d\n",
+				b->m.planes[i].reserved[0],
+				b->m.planes[i].reserved[1],
+				b->m.planes[i].length);
+			rc = -EINVAL;
+			goto err_invalid_buff;
+		}
+		b->m.planes[i].m.userptr = binfo->handle->device_addr;
+		pr_debug("Queueing device address = %ld\n",
+				binfo->handle->device_addr);
+	}
+	rc = msm_vidc_qbuf(v4l2_inst->vidc_inst, b);
+err_invalid_buff:
+	return rc;
+}
+
+int msm_v4l2_dqbuf(struct file *file, void *fh,
+				struct v4l2_buffer *b)
+{
+	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+	return msm_vidc_dqbuf(v4l2_inst->vidc_inst, b);
+}
+
+int msm_v4l2_streamon(struct file *file, void *fh,
+				enum v4l2_buf_type i)
+{
+	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+	return msm_vidc_streamon(v4l2_inst->vidc_inst, i);
+}
+
+int msm_v4l2_streamoff(struct file *file, void *fh,
+				enum v4l2_buf_type i)
+{
+	struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+	return msm_vidc_streamoff(v4l2_inst->vidc_inst, i);
+}
+static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
+	.vidioc_querycap = msm_v4l2_querycap,
+	.vidioc_enum_fmt_vid_cap_mplane = msm_v4l2_enum_fmt,
+	.vidioc_enum_fmt_vid_out_mplane = msm_v4l2_enum_fmt,
+	.vidioc_s_fmt_vid_cap_mplane = msm_v4l2_s_fmt,
+	.vidioc_s_fmt_vid_out_mplane = msm_v4l2_s_fmt,
+	.vidioc_g_fmt_vid_cap_mplane = msm_v4l2_g_fmt,
+	.vidioc_g_fmt_vid_out_mplane = msm_v4l2_g_fmt,
+	.vidioc_reqbufs = msm_v4l2_reqbufs,
+	.vidioc_prepare_buf = msm_v4l2_prepare_buf,
+	.vidioc_qbuf = msm_v4l2_qbuf,
+	.vidioc_dqbuf = msm_v4l2_dqbuf,
+	.vidioc_streamon = msm_v4l2_streamon,
+	.vidioc_streamoff = msm_v4l2_streamoff,
+	.vidioc_s_ctrl = msm_v4l2_s_ctrl,
+	.vidioc_g_ctrl = msm_v4l2_g_ctrl,
+};
+
+static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = {
+};
+
+static unsigned int msm_v4l2_poll(struct file *filp,
+	struct poll_table_struct *pt)
+{
+	struct msm_v4l2_vid_inst *v4l2_inst = filp->private_data;
+	return msm_vidc_poll(v4l2_inst->vidc_inst, filp, pt);
+}
+
+static const struct v4l2_file_operations msm_v4l2_vidc_fops = {
+	.owner = THIS_MODULE,
+	.open = msm_v4l2_open,
+	.release = msm_v4l2_close,
+	.ioctl = video_ioctl2,
+	.poll = msm_v4l2_poll,
+};
+
+void msm_vidc_release_video_device(struct video_device *pvdev)
+{
+}
+
+static int msm_vidc_initialize_core(struct platform_device *pdev,
+				struct msm_vidc_core *core)
+{
+	struct resource *res;
+	int i = 0;
+	if (!core)
+		return -EINVAL;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		pr_err("Failed to get IORESOURCE_MEM\n");
+		return -ENODEV;
+	}
+	core->register_base = res->start;
+	core->register_size = resource_size(res);
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		pr_err("Failed to get IORESOURCE_IRQ\n");
+		return -ENODEV;
+	}
+	core->irq = res->start;
+	INIT_LIST_HEAD(&core->instances);
+	mutex_init(&core->sync_lock);
+	spin_lock_init(&core->lock);
+	core->base_addr = 0x34f00000;
+	core->state = VIDC_CORE_UNINIT;
+	for (i = SYS_MSG_INDEX(SYS_MSG_START);
+		i <= SYS_MSG_INDEX(SYS_MSG_END); i++) {
+		init_completion(&core->completions[i]);
+	}
+	return 0;
+}
+
+static int __devinit msm_vidc_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	unsigned long flags;
+	char debugfs_name[MAX_DEBUGFS_NAME];
+
+	core = kzalloc(sizeof(*core), GFP_KERNEL);
+	if (!core || !vidc_driver) {
+		pr_err("Failed to allocate memory for device core\n");
+		rc = -ENOMEM;
+		goto err_no_mem;
+	}
+	rc = msm_vidc_initialize_core(pdev, core);
+	if (rc) {
+		pr_err("Failed to init core\n");
+		goto err_v4l2_register;
+	}
+	rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
+	if (rc) {
+		pr_err("Failed to register v4l2 device\n");
+		goto err_v4l2_register;
+	}
+	core->vdev[MSM_VIDC_DECODER].vdev.release =
+		msm_vidc_release_video_device;
+	core->vdev[MSM_VIDC_DECODER].vdev.fops = &msm_v4l2_vidc_fops;
+	core->vdev[MSM_VIDC_DECODER].vdev.ioctl_ops = &msm_v4l2_ioctl_ops;
+	core->vdev[MSM_VIDC_DECODER].type = MSM_VIDC_DECODER;
+	rc = video_register_device(&core->vdev[MSM_VIDC_DECODER].vdev,
+					VFL_TYPE_GRABBER, BASE_DEVICE_NUMBER);
+	if (rc) {
+		pr_err("Failed to register video decoder device");
+		goto err_dec_register;
+	}
+	video_set_drvdata(&core->vdev[MSM_VIDC_DECODER].vdev, core);
+
+	core->vdev[MSM_VIDC_ENCODER].vdev.release =
+		msm_vidc_release_video_device;
+	core->vdev[MSM_VIDC_ENCODER].vdev.fops = &msm_v4l2_vidc_fops;
+	core->vdev[MSM_VIDC_ENCODER].vdev.ioctl_ops = &msm_v4l2_ioctl_ops;
+	core->vdev[MSM_VIDC_ENCODER].type = MSM_VIDC_ENCODER;
+	rc = video_register_device(&core->vdev[MSM_VIDC_ENCODER].vdev,
+				VFL_TYPE_GRABBER, BASE_DEVICE_NUMBER + 1);
+	if (rc) {
+		pr_err("Failed to register video encoder device");
+		goto err_enc_register;
+	}
+	video_set_drvdata(&core->vdev[MSM_VIDC_ENCODER].vdev, core);
+	core->device = vidc_hal_add_device(core->id, core->base_addr,
+			core->register_base, core->register_size, core->irq,
+			&handle_cmd_response);
+	if (!core->device) {
+		pr_err("Failed to create interrupt handler");
+		goto err_cores_exceeded;
+	}
+
+	spin_lock_irqsave(&vidc_driver->lock, flags);
+	if (vidc_driver->num_cores  + 1 > MSM_VIDC_CORES_MAX) {
+		spin_unlock_irqrestore(&vidc_driver->lock, flags);
+		pr_err("Maximum cores already exist, core_no = %d\n",
+				vidc_driver->num_cores);
+		goto err_cores_exceeded;
+	}
+
+	core->id = vidc_driver->num_cores++;
+	list_add_tail(&core->list, &vidc_driver->cores);
+	spin_unlock_irqrestore(&vidc_driver->lock, flags);
+	snprintf(debugfs_name, MAX_DEBUGFS_NAME, "core%d", core->id);
+	core->debugfs_root = debugfs_create_dir(debugfs_name,
+						vidc_driver->debugfs_root);
+	pdev->dev.platform_data = core;
+	return rc;
+
+err_cores_exceeded:
+	video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
+err_enc_register:
+	video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
+err_dec_register:
+	v4l2_device_unregister(&core->v4l2_dev);
+err_v4l2_register:
+	kfree(core);
+err_no_mem:
+	return rc;
+}
+
+static int __devexit msm_vidc_remove(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_vidc_core *core = pdev->dev.platform_data;
+	vidc_hal_delete_device(core->device);
+	video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
+	video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
+	v4l2_device_unregister(&core->v4l2_dev);
+	kfree(core);
+	return rc;
+}
+static const struct of_device_id msm_vidc_dt_match[] = {
+	{.compatible = "qcom,msm-vidc"},
+};
+
+MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
+
+static struct platform_driver msm_vidc_driver = {
+	.probe = msm_vidc_probe,
+	.remove = msm_vidc_remove,
+	.driver = {
+		.name = "msm_vidc",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_vidc_dt_match,
+	},
+};
+
+static int __init msm_vidc_init(void)
+{
+	int rc = 0;
+	vidc_driver = kzalloc(sizeof(*vidc_driver),
+						GFP_KERNEL);
+	if (!vidc_driver) {
+		pr_err("Failed to allocate memroy for msm_vidc_drv\n");
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&vidc_driver->cores);
+	spin_lock_init(&vidc_driver->lock);
+	vidc_driver->debugfs_root = debugfs_create_dir("msm_vidc", NULL);
+	if (!vidc_driver->debugfs_root)
+		pr_err("Failed to create debugfs for msm_vidc\n");
+
+	rc = platform_driver_register(&msm_vidc_driver);
+	if (rc) {
+		pr_err("Failed to register platform driver\n");
+		kfree(vidc_driver);
+		vidc_driver = NULL;
+	}
+
+	return rc;
+}
+
+static void __exit msm_vidc_exit(void)
+{
+	platform_driver_unregister(&msm_vidc_driver);
+	debugfs_remove_recursive(vidc_driver->debugfs_root);
+	kfree(vidc_driver);
+	vidc_driver = NULL;
+}
+
+module_init(msm_vidc_init);
+module_exit(msm_vidc_exit);
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
new file mode 100644
index 0000000..879d324
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -0,0 +1,872 @@
+/* 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/slab.h>
+
+#include "msm_vidc_internal.h"
+#include "msm_vidc_common.h"
+#include "vidc_hal_api.h"
+#include "msm_smem.h"
+
+#define MSM_VDEC_DVC_NAME "msm_vdec_8974"
+#define MAX_PLANES 1
+#define DEFAULT_HEIGHT 720
+#define DEFAULT_WIDTH 1280
+#define MIN_NUM_OUTPUT_BUFFERS 2
+#define MAX_NUM_OUTPUT_BUFFERS 6
+
+static const char *const mpeg_video_vidc_divx_format[] = {
+	"DIVX Format 4",
+	"DIVX Format 5",
+	"DIVX Format 6",
+	NULL
+};
+static const char *mpeg_video_stream_format[] = {
+	"NAL Format Start Codes",
+	"NAL Format One NAL Per Buffer",
+	"NAL Format One Byte Length",
+	"NAL Format Two Byte Length",
+	"NAL Format Four Byte Length",
+	NULL
+};
+static const char *const mpeg_video_output_order[] = {
+	"Display Order",
+	"Decode Order",
+	NULL
+};
+static const struct msm_vidc_ctrl msm_vdec_ctrls[] = {
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT,
+		.name = "NAL Format",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_NAL_PER_BUFFER) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_BYTE_LENGTH) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_TWO_BYTE_LENGTH) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH)
+		),
+		.qmenu = mpeg_video_stream_format,
+		.step = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER,
+		.name = "Output Order",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE)
+			),
+		.qmenu = mpeg_video_output_order,
+		.step = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE,
+		.name = "Picture Type Decoding",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 15,
+		.default_value = 15,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO,
+		.name = "Keep Aspect Ratio",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE,
+		.name = "Deblocker Mode",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT,
+		.name = "Divx Format",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_5) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6)
+			),
+		.qmenu = mpeg_video_vidc_divx_format,
+		.step = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING,
+		.name = "MB Error Map Reporting",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER,
+		.name = "control",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+};
+
+#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
+
+static u32 get_frame_size_nv12(int plane,
+					u32 height, u32 width)
+{
+	int stride = (width + 31) & (~31);
+	return height * stride * 3/2;
+}
+static u32 get_frame_size_nv21(int plane,
+					u32 height, u32 width)
+{
+	return height * width * 2;
+}
+
+static u32 get_frame_size_compressed(int plane,
+					u32 height, u32 width)
+{
+	return 0x500000;
+}
+
+static const struct msm_vidc_format vdec_formats[] = {
+	{
+		.name = "YCbCr Semiplanar 4:2:0",
+		.description = "Y/CbCr 4:2:0",
+		.fourcc = V4L2_PIX_FMT_NV12,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_nv12,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "Mpeg4",
+		.description = "Mpeg4 compressed format",
+		.fourcc = V4L2_PIX_FMT_MPEG4,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "Mpeg2",
+		.description = "Mpeg2 compressed format",
+		.fourcc = V4L2_PIX_FMT_MPEG2,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "H263",
+		.description = "H263 compressed format",
+		.fourcc = V4L2_PIX_FMT_H263,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "H264",
+		.description = "H264 compressed format",
+		.fourcc = V4L2_PIX_FMT_H264,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "YCrCb Semiplanar 4:2:0",
+		.description = "Y/CrCb 4:2:0",
+		.fourcc = V4L2_PIX_FMT_NV21,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_nv21,
+		.type = CAPTURE_PORT,
+	},
+};
+
+int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+	int rc = 0;
+	struct vb2_queue *q;
+	q = msm_comm_get_vb2q(inst, i);
+	if (!q) {
+		pr_err("Failed to find buffer queue for type = %d\n", i);
+		return -EINVAL;
+	}
+	pr_debug("Calling streamon\n");
+	rc = vb2_streamon(q, i);
+	if (rc)
+		pr_err("streamon failed on port: %d\n", i);
+	return rc;
+}
+
+int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+	int rc = 0;
+	struct vb2_queue *q;
+	unsigned long flags;
+	struct list_head *ptr, *next;
+	struct internal_buf *buf;
+	struct extradata_buf *ebuf;
+
+	q = msm_comm_get_vb2q(inst, i);
+	if (!q) {
+		pr_err("Failed to find buffer queue for type = %d\n", i);
+		return -EINVAL;
+	}
+	spin_lock_irqsave(&inst->lock, flags);
+	list_for_each_safe(ptr, next, &inst->internalbufs) {
+		buf = list_entry(ptr, struct internal_buf, list);
+		list_del(&buf->list);
+		msm_smem_free(inst->mem_client, buf->handle);
+		kfree(buf);
+		}
+	list_for_each_safe(ptr, next, &inst->extradatabufs) {
+		ebuf = list_entry(ptr, struct extradata_buf, list);
+		list_del(&ebuf->list);
+		msm_smem_free(inst->mem_client, ebuf->handle);
+		kfree(ebuf);
+		}
+	spin_unlock_irqrestore(&inst->lock, flags);
+
+	pr_debug("Calling streamoff\n");
+	rc = vb2_streamoff(q, i);
+	if (rc)
+		pr_err("streamoff failed on port: %d\n", i);
+	return rc;
+}
+
+int msm_vdec_prepare_buf(struct msm_vidc_inst *inst,
+					struct v4l2_buffer *b)
+{
+	int rc = 0;
+	int i;
+	struct vidc_buffer_addr_info buffer_info;
+	switch (b->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
+		struct extradata_buf *binfo;
+		for (i = 0; i < b->length; i++) {
+			pr_err("device_addr = %ld, size = %d\n",
+				b->m.planes[i].m.userptr,
+				b->m.planes[i].length);
+			buffer_info.buffer_size = b->m.planes[i].length;
+			buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+			buffer_info.num_buffers = 1;
+			buffer_info.align_device_addr =
+				b->m.planes[i].m.userptr;
+			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+			if (!binfo) {
+				pr_err("Failed to allocate shared mem\n");
+				return -ENOMEM;
+			}
+			binfo->device_addr = b->m.planes[i].m.userptr;
+			rc = msm_comm_allocate_extradata_buffers(inst, binfo);
+			if (rc) {
+				pr_err("msm_comm_allocate_extradata_buffers failed");
+				break;
+			}
+			buffer_info.extradata_size = binfo->handle->size;
+			buffer_info.extradata_addr = binfo->handle->device_addr;
+			rc = vidc_hal_session_set_buffers((void *)inst->session,
+					&buffer_info);
+			if (rc) {
+				pr_err("vidc_hal_session_set_buffers failed");
+				break;
+			}
+		}
+		break;
+	}
+	default:
+		pr_err("Buffer type not recognized: %d\n", b->type);
+		break;
+	}
+	return rc;
+}
+
+int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	struct vb2_queue *q = NULL;
+	int rc = 0;
+	q = msm_comm_get_vb2q(inst, b->type);
+	if (!q) {
+		pr_err("Failed to find buffer queue for type = %d\n", b->type);
+		return -EINVAL;
+	}
+	rc = vb2_qbuf(q, b);
+	if (rc)
+		pr_err("Failed to qbuf, %d\n", rc);
+	return rc;
+}
+int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	struct vb2_queue *q = NULL;
+	int rc = 0;
+	q = msm_comm_get_vb2q(inst, b->type);
+	if (!q) {
+		pr_err("Failed to find buffer queue for type = %d\n", b->type);
+		return -EINVAL;
+	}
+	rc = vb2_dqbuf(q, b, true);
+	if (rc)
+		pr_err("Failed to qbuf, %d\n", rc);
+	return rc;
+}
+
+int msm_vdec_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
+{
+	struct vb2_queue *q = NULL;
+	int rc = 0;
+	if (!inst || !b) {
+		pr_err("Invalid input, inst = %p, buffer = %p\n", inst, b);
+		return -EINVAL;
+	}
+	q = msm_comm_get_vb2q(inst, b->type);
+	if (!q) {
+		pr_err("Failed to find buffer queue for type = %d\n", b->type);
+		return -EINVAL;
+	}
+
+	rc = vb2_reqbufs(q, b);
+	if (rc)
+		pr_err("Failed to get reqbufs, %d\n", rc);
+	return rc;
+}
+
+int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	const struct msm_vidc_format *fmt = NULL;
+	int rc = 0;
+	int i;
+	if (!inst || !f) {
+		pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+		return -EINVAL;
+	}
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		fmt = inst->fmts[CAPTURE_PORT];
+	else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		fmt = inst->fmts[OUTPUT_PORT];
+
+	if (fmt) {
+		f->fmt.pix_mp.pixelformat = fmt->fourcc;
+		f->fmt.pix_mp.height = inst->height;
+		f->fmt.pix_mp.width = inst->width;
+		for (i = 0; i < fmt->num_planes; ++i) {
+			f->fmt.pix_mp.plane_fmt[i].sizeimage =
+			fmt->get_frame_size(i, inst->height, inst->width);
+		}
+	} else {
+		pr_err("Buf type not recognized, type = %d\n",
+					f->type);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	const struct msm_vidc_format *fmt = NULL;
+	int rc = 0;
+	int i;
+	if (!inst || !f) {
+		pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+		return -EINVAL;
+	}
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		inst->width = f->fmt.pix_mp.width;
+		inst->height = f->fmt.pix_mp.height;
+		fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
+			ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
+			CAPTURE_PORT);
+		if (fmt && fmt->type != CAPTURE_PORT) {
+			pr_err("Format: %d not supported on CAPTURE port\n",
+					f->fmt.pix_mp.pixelformat);
+			rc = -EINVAL;
+			goto err_invalid_fmt;
+		}
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
+			ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
+			OUTPUT_PORT);
+		if (fmt && fmt->type != OUTPUT_PORT) {
+			pr_err("Format: %d not supported on OUTPUT port\n",
+					f->fmt.pix_mp.pixelformat);
+			rc = -EINVAL;
+			goto err_invalid_fmt;
+		}
+	}
+
+	if (fmt) {
+		for (i = 0; i < fmt->num_planes; ++i) {
+			f->fmt.pix_mp.plane_fmt[i].sizeimage =
+				fmt->get_frame_size(i, f->fmt.pix_mp.height,
+						f->fmt.pix_mp.width);
+		}
+		inst->fmts[fmt->type] = fmt;
+		if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+			rc = msm_comm_try_state(inst, MSM_VIDC_OPEN);
+			if (rc) {
+				pr_err("Failed to open instance\n");
+				goto err_invalid_fmt;
+			}
+		}
+	} else {
+		pr_err("Buf type not recognized, type = %d\n",
+					f->type);
+		rc = -EINVAL;
+	}
+err_invalid_fmt:
+	return rc;
+}
+
+int msm_vdec_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
+{
+	if (!inst || !cap) {
+		pr_err("Invalid input, inst = %p, cap = %p\n", inst, cap);
+		return -EINVAL;
+	}
+	strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, MSM_VDEC_DVC_NAME, sizeof(cap->card));
+	cap->bus_info[0] = 0;
+	cap->version = MSM_VIDC_VERSION;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+						V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+						V4L2_CAP_STREAMING;
+	memset(cap->reserved, 0, sizeof(cap->reserved));
+	return 0;
+}
+
+int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
+{
+	const struct msm_vidc_format *fmt = NULL;
+	int rc = 0;
+	if (!inst || !f) {
+		pr_err("Invalid input, inst = %p, f = %p\n", inst, f);
+		return -EINVAL;
+	}
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		fmt = msm_comm_get_pixel_fmt_index(vdec_formats,
+			ARRAY_SIZE(vdec_formats), f->index, CAPTURE_PORT);
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		fmt = msm_comm_get_pixel_fmt_index(vdec_formats,
+			ARRAY_SIZE(vdec_formats), f->index, OUTPUT_PORT);
+		f->flags = V4L2_FMT_FLAG_COMPRESSED;
+	}
+
+	memset(f->reserved, 0 , sizeof(f->reserved));
+	if (fmt) {
+		strlcpy(f->description, fmt->description,
+				sizeof(f->description));
+		f->pixelformat = fmt->fourcc;
+	} else {
+		pr_err("No more formats found\n");
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static int msm_vdec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
+			unsigned int *num_planes, unsigned long sizes[],
+			void *alloc_ctxs[])
+{
+	int i, rc = 0;
+	struct msm_vidc_inst *inst;
+	struct hal_frame_size frame_sz;
+	unsigned long flags;
+	if (!q || !q->drv_priv) {
+		pr_err("Invalid input, q = %p\n", q);
+		return -EINVAL;
+	}
+	inst = q->drv_priv;
+	switch (q->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		*num_planes = 1;
+		if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
+				*num_buffers > MAX_NUM_OUTPUT_BUFFERS)
+			*num_buffers = MIN_NUM_OUTPUT_BUFFERS;
+		for (i = 0; i < *num_planes; i++) {
+			sizes[i] = inst->fmts[OUTPUT_PORT]->get_frame_size(
+					i, inst->height, inst->width);
+		}
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		pr_debug("Getting bufreqs on capture plane\n");
+		rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+		if (rc) {
+			pr_err("Failed to open instance\n");
+			break;
+		}
+		frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
+		frame_sz.width = inst->width;
+		frame_sz.height = inst->height;
+		pr_debug("width = %d, height = %d\n",
+				frame_sz.width, frame_sz.height);
+		rc = vidc_hal_session_set_property((void *)inst->session,
+				HAL_PARAM_FRAME_SIZE, &frame_sz);
+		if (rc) {
+			pr_err("Failed to set hal property for framesize\n");
+			break;
+		}
+		rc = msm_comm_try_get_bufreqs(inst);
+		if (rc) {
+			pr_err("Failed to get buffer requirements: %d\n", rc);
+			break;
+		}
+		*num_planes = 1;
+		spin_lock_irqsave(&inst->lock, flags);
+		*num_buffers = inst->buff_req.buffer[1].buffer_count_actual;
+		spin_unlock_irqrestore(&inst->lock, flags);
+		pr_debug("size = %d, alignment = %d\n",
+				inst->buff_req.buffer[1].buffer_size,
+				inst->buff_req.buffer[1].buffer_alignment);
+		for (i = 0; i < *num_planes; i++) {
+			sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
+					i, inst->height, inst->width);
+		}
+
+		break;
+	default:
+		pr_err("Invalid q type = %d\n", q->type);
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static inline int start_streaming(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	unsigned long flags;
+	struct vb2_buf_entry *temp;
+	struct list_head *ptr, *next;
+	struct v4l2_control control;
+	struct hal_nal_stream_format_supported stream_format;
+	struct hal_enable_picture enable_picture;
+	struct hal_enable hal_property;
+	struct hal_enable prop;
+	u32 control_idx = 0;
+	enum hal_property property_id = 0;
+	u32 property_val = 0;
+	void *pdata;
+	rc = msm_comm_set_scratch_buffers(inst);
+	if (rc) {
+		pr_err("Failed to set scratch buffers: %d\n", rc);
+		goto fail_start;
+	}
+	for (; control_idx < NUM_CTRLS; control_idx++) {
+		control.id = msm_vdec_ctrls[control_idx].id;
+		rc = v4l2_g_ctrl(&inst->ctrl_handler, &control);
+		if (rc) {
+			pr_err("Failed to get control value for ID=%d\n",
+				   msm_vdec_ctrls[control_idx].id);
+		} else {
+			property_id = 0;
+			switch (control.id) {
+			case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT:
+				property_id =
+					HAL_PARAM_NAL_STREAM_FORMAT_SELECT;
+				stream_format.nal_stream_format_supported =
+					(0x00000001 << control.value);
+				pdata = &stream_format;
+				break;
+			case V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER:
+				property_id = HAL_PARAM_VDEC_OUTPUT_ORDER;
+				property_val = control.value;
+				pdata = &property_val;
+				break;
+			case V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE:
+				property_id =
+					HAL_PARAM_VDEC_PICTURE_TYPE_DECODE;
+				enable_picture.picture_type = control.value;
+				pdata = &enable_picture;
+				break;
+			case V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO:
+				property_id =
+				HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO;
+				hal_property.enable = control.value;
+				pdata = &hal_property;
+				break;
+			case V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE:
+				property_id =
+					HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER;
+				hal_property.enable = control.value;
+				pdata = &hal_property;
+				break;
+			case V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT:
+				property_id = HAL_PARAM_DIVX_FORMAT;
+				property_val = control.value;
+				pdata = &property_val;
+				break;
+			case V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING:
+				property_id =
+					HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING;
+				hal_property.enable = control.value;
+				pdata = &hal_property;
+				break;
+			case V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER:
+				property_id =
+					HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER;
+				hal_property.enable = control.value;
+				pdata = &hal_property;
+				break;
+			default:
+				break;
+			}
+			if (property_id) {
+				pr_err("Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
+					   property_id,
+					   msm_vdec_ctrls[control_idx].id,
+					   control.value);
+				rc = vidc_hal_session_set_property((void *)
+						inst->session, property_id,
+						pdata);
+			}
+			if (rc)
+				pr_err("Failed to set hal property for framesize\n");
+		}
+	}
+
+	prop.enable = 1;
+	rc = vidc_hal_session_set_property((void *)inst->session,
+			HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER, &prop);
+	if (rc)
+		pr_err("Failed to set smooth streaming\n");
+
+	rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
+	if (rc) {
+		pr_err("Failed to move inst: %p to start done state\n",
+				inst);
+		goto fail_start;
+	}
+	spin_lock_irqsave(&inst->lock, flags);
+	if (!list_empty(&inst->pendingq)) {
+		list_for_each_safe(ptr, next, &inst->pendingq) {
+			temp = list_entry(ptr, struct vb2_buf_entry, list);
+			rc = msm_comm_qbuf(temp->vb);
+			if (rc) {
+				pr_err("Failed to qbuf to hardware\n");
+				break;
+			}
+			list_del(&temp->list);
+			kfree(temp);
+		}
+	}
+	spin_unlock_irqrestore(&inst->lock, flags);
+	return rc;
+fail_start:
+	return rc;
+}
+
+static int msm_vdec_start_streaming(struct vb2_queue *q)
+{
+	struct msm_vidc_inst *inst;
+	int rc = 0;
+	if (!q || !q->drv_priv) {
+		pr_err("Invalid input, q = %p\n", q);
+		return -EINVAL;
+	}
+	inst = q->drv_priv;
+	pr_debug("Streamon called on: %d capability\n", q->type);
+	switch (q->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		if (inst->vb2_bufq[CAPTURE_PORT].streaming)
+			rc = start_streaming(inst);
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		if (inst->vb2_bufq[OUTPUT_PORT].streaming)
+			rc = start_streaming(inst);
+		break;
+	default:
+		pr_err("Q-type is not supported: %d\n", q->type);
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static int msm_vdec_stop_streaming(struct vb2_queue *q)
+{
+	struct msm_vidc_inst *inst;
+	int rc = 0;
+	if (!q || !q->drv_priv) {
+		pr_err("Invalid input, q = %p\n", q);
+		return -EINVAL;
+	}
+	inst = q->drv_priv;
+	pr_debug("Streamoff called on: %d capability\n", q->type);
+	switch (q->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+		break;
+	default:
+		pr_err("Q-type is not supported: %d\n", q->type);
+		rc = -EINVAL;
+		break;
+	}
+	if (rc)
+		pr_err("Failed to move inst: %p, cap = %d to state: %d\n",
+				inst, q->type, MSM_VIDC_CLOSE_DONE);
+	return rc;
+}
+
+static void msm_vdec_buf_queue(struct vb2_buffer *vb)
+{
+	int rc;
+	rc = msm_comm_qbuf(vb);
+	if (rc)
+		pr_err("Failed to queue buffer: %d\n", rc);
+}
+
+static const struct vb2_ops msm_vdec_vb2q_ops = {
+	.queue_setup = msm_vdec_queue_setup,
+	.start_streaming = msm_vdec_start_streaming,
+	.buf_queue = msm_vdec_buf_queue,
+	.stop_streaming = msm_vdec_stop_streaming,
+};
+
+const struct vb2_ops *msm_vdec_get_vb2q_ops(void)
+{
+	return &msm_vdec_vb2q_ops;
+}
+
+int msm_vdec_inst_init(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	if (!inst) {
+		pr_err("Invalid input = %p\n", inst);
+		return -EINVAL;
+	}
+	inst->fmts[OUTPUT_PORT] = &vdec_formats[1];
+	inst->fmts[CAPTURE_PORT] = &vdec_formats[0];
+	inst->height = DEFAULT_HEIGHT;
+	inst->width = DEFAULT_WIDTH;
+	return rc;
+}
+
+static int msm_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	return 0;
+}
+static int msm_vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops msm_vdec_ctrl_ops = {
+
+	.s_ctrl = msm_vdec_op_s_ctrl,
+	.g_volatile_ctrl = msm_vdec_op_g_volatile_ctrl,
+};
+
+const struct v4l2_ctrl_ops *msm_vdec_get_ctrl_ops(void)
+{
+	return &msm_vdec_ctrl_ops;
+}
+
+int msm_vdec_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl)
+{
+	return v4l2_s_ctrl(&inst->ctrl_handler, ctrl);
+}
+int msm_vdec_g_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl)
+{
+	return v4l2_g_ctrl(&inst->ctrl_handler, ctrl);
+}
+int msm_vdec_ctrl_init(struct msm_vidc_inst *inst)
+{
+	int idx = 0;
+	struct v4l2_ctrl_config ctrl_cfg;
+	int ret_val = 0;
+
+	ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS);
+
+	if (ret_val) {
+		pr_err("CTRL ERR: Control handler init failed, %d\n",
+				inst->ctrl_handler.error);
+		return ret_val;
+	}
+
+	for (; idx < NUM_CTRLS; idx++) {
+		if (IS_PRIV_CTRL(msm_vdec_ctrls[idx].id)) {
+			/*add private control*/
+			ctrl_cfg.def = msm_vdec_ctrls[idx].default_value;
+			ctrl_cfg.flags = 0;
+			ctrl_cfg.id = msm_vdec_ctrls[idx].id;
+			/*ctrl_cfg.is_private =
+			 * msm_vdec_ctrls[idx].is_private;
+			 * ctrl_cfg.is_volatile =
+			 * msm_vdec_ctrls[idx].is_volatile;*/
+			ctrl_cfg.max = msm_vdec_ctrls[idx].maximum;
+			ctrl_cfg.min = msm_vdec_ctrls[idx].minimum;
+			ctrl_cfg.menu_skip_mask =
+				msm_vdec_ctrls[idx].menu_skip_mask;
+			ctrl_cfg.name = msm_vdec_ctrls[idx].name;
+			ctrl_cfg.ops = &msm_vdec_ctrl_ops;
+			ctrl_cfg.step = msm_vdec_ctrls[idx].step;
+			ctrl_cfg.type = msm_vdec_ctrls[idx].type;
+			ctrl_cfg.qmenu = msm_vdec_ctrls[idx].qmenu;
+
+			v4l2_ctrl_new_custom(&inst->ctrl_handler,
+					&ctrl_cfg, NULL);
+		} else {
+			if (msm_vdec_ctrls[idx].type == V4L2_CTRL_TYPE_MENU) {
+				v4l2_ctrl_new_std_menu(&inst->ctrl_handler,
+					&msm_vdec_ctrl_ops,
+					msm_vdec_ctrls[idx].id,
+					msm_vdec_ctrls[idx].maximum,
+					msm_vdec_ctrls[idx].menu_skip_mask,
+					msm_vdec_ctrls[idx].default_value);
+			} else {
+				v4l2_ctrl_new_std(&inst->ctrl_handler,
+					&msm_vdec_ctrl_ops,
+					msm_vdec_ctrls[idx].id,
+					msm_vdec_ctrls[idx].minimum,
+					msm_vdec_ctrls[idx].maximum,
+					msm_vdec_ctrls[idx].step,
+					msm_vdec_ctrls[idx].default_value);
+			}
+		}
+	}
+	ret_val = inst->ctrl_handler.error;
+	if (ret_val)
+		pr_err("CTRL ERR: Error adding ctrls to ctrl handle, %d\n",
+				inst->ctrl_handler.error);
+	return ret_val;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vdec.h b/drivers/media/video/msm_vidc/msm_vdec.h
new file mode 100644
index 0000000..6529065
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vdec.h
@@ -0,0 +1,35 @@
+/* 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.
+ *
+ */
+#ifndef _MSM_VDEC_H_
+#define _MSM_VDEC_H_
+
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+
+int msm_vdec_inst_init(struct msm_vidc_inst *inst);
+int msm_vdec_ctrl_init(struct msm_vidc_inst *inst);
+int msm_vdec_querycap(void *instance, struct v4l2_capability *cap);
+int msm_vdec_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
+int msm_vdec_s_fmt(void *instance, struct v4l2_format *f);
+int msm_vdec_g_fmt(void *instance, struct v4l2_format *f);
+int msm_vdec_s_ctrl(void *instance, struct v4l2_control *a);
+int msm_vdec_g_ctrl(void *instance, struct v4l2_control *a);
+int msm_vdec_reqbufs(void *instance, struct v4l2_requestbuffers *b);
+int msm_vdec_prepare_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+struct vb2_ops *msm_vdec_get_vb2q_ops(void);
+
+#endif
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
new file mode 100644
index 0000000..cae2d6f
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -0,0 +1,522 @@
+/* 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/slab.h>
+
+#include "msm_vidc_internal.h"
+#include "msm_vidc_common.h"
+#include "vidc_hal_api.h"
+#include "msm_smem.h"
+
+#define MSM_VENC_DVC_NAME "msm_venc_8974"
+#define DEFAULT_HEIGHT 720
+#define DEFAULT_WIDTH 1280
+#define MIN_NUM_OUTPUT_BUFFERS 2
+#define MAX_NUM_OUTPUT_BUFFERS 8
+static u32 get_frame_size_nv12(int plane, u32 height, u32 width)
+{
+	int stride = (width + 31) & (~31);
+	return height * stride * 3/2;
+}
+static u32 get_frame_size_nv21(int plane, u32 height, u32 width)
+{
+	return height * width * 2;
+}
+
+static u32 get_frame_size_compressed(int plane, u32 height, u32 width)
+{
+	return width * height / 2;
+}
+
+static const struct msm_vidc_format venc_formats[] = {
+	{
+		.name = "YCbCr Semiplanar 4:2:0",
+		.description = "Y/CbCr 4:2:0",
+		.fourcc = V4L2_PIX_FMT_NV12,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_nv12,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "Mpeg4",
+		.description = "Mpeg4 compressed format",
+		.fourcc = V4L2_PIX_FMT_MPEG4,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "H263",
+		.description = "H263 compressed format",
+		.fourcc = V4L2_PIX_FMT_H263,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "H264",
+		.description = "H264 compressed format",
+		.fourcc = V4L2_PIX_FMT_H264,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "YCrCb Semiplanar 4:2:0",
+		.description = "Y/CrCb 4:2:0",
+		.fourcc = V4L2_PIX_FMT_NV21,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_nv21,
+		.type = OUTPUT_PORT,
+	},
+};
+
+static int msm_venc_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
+			unsigned int *num_planes, unsigned long sizes[],
+			void *alloc_ctxs[])
+{
+	int i, rc = 0;
+	struct msm_vidc_inst *inst;
+	struct hal_frame_size frame_sz;
+	unsigned long flags;
+	if (!q || !q->drv_priv) {
+		pr_err("Invalid input, q = %p\n", q);
+		return -EINVAL;
+	}
+	inst = q->drv_priv;
+	switch (q->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		*num_planes = 1;
+		if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
+				*num_buffers > MAX_NUM_OUTPUT_BUFFERS)
+			*num_buffers = MIN_NUM_OUTPUT_BUFFERS;
+		for (i = 0; i < *num_planes; i++) {
+			sizes[i] = inst->fmts[OUTPUT_PORT]->get_frame_size(
+					i, inst->height, inst->width);
+		}
+		break;
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+		if (rc) {
+			pr_err("Failed to open instance\n");
+			break;
+		}
+		frame_sz.buffer_type = HAL_BUFFER_INPUT;
+		frame_sz.width = inst->width;
+		frame_sz.height = inst->height;
+		pr_debug("width = %d, height = %d\n",
+				frame_sz.width, frame_sz.height);
+		rc = vidc_hal_session_set_property((void *)inst->session,
+				HAL_PARAM_FRAME_SIZE, &frame_sz);
+		if (rc) {
+			pr_err("Failed to set hal property for framesize\n");
+			break;
+		}
+		rc = msm_comm_try_get_bufreqs(inst);
+		if (rc) {
+			pr_err("Failed to get buffer requirements: %d\n", rc);
+			break;
+		}
+		*num_planes = 1;
+		spin_lock_irqsave(&inst->lock, flags);
+		*num_buffers = inst->buff_req.buffer[0].buffer_count_actual;
+		spin_unlock_irqrestore(&inst->lock, flags);
+		pr_debug("size = %d, alignment = %d, count = %d\n",
+				inst->buff_req.buffer[0].buffer_size,
+				inst->buff_req.buffer[0].buffer_alignment,
+				inst->buff_req.buffer[0].buffer_count_actual);
+		for (i = 0; i < *num_planes; i++) {
+			sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
+					i, inst->height, inst->width);
+		}
+
+		break;
+	default:
+		pr_err("Invalid q type = %d\n", q->type);
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static inline int start_streaming(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	unsigned long flags;
+	struct vb2_buf_entry *temp;
+	struct list_head *ptr, *next;
+	rc = msm_comm_set_scratch_buffers(inst);
+	if (rc) {
+		pr_err("Failed to set scratch buffers: %d\n", rc);
+		goto fail_start;
+	}
+	rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
+	if (rc) {
+		pr_err("Failed to move inst: %p to start done state\n",
+				inst);
+		goto fail_start;
+	}
+	spin_lock_irqsave(&inst->lock, flags);
+	if (!list_empty(&inst->pendingq)) {
+		list_for_each_safe(ptr, next, &inst->pendingq) {
+			temp = list_entry(ptr, struct vb2_buf_entry, list);
+			rc = msm_comm_qbuf(temp->vb);
+			if (rc) {
+				pr_err("Failed to qbuf to hardware\n");
+				break;
+			}
+			list_del(&temp->list);
+			kfree(temp);
+		}
+	}
+	spin_unlock_irqrestore(&inst->lock, flags);
+	return rc;
+fail_start:
+	return rc;
+}
+
+static int msm_venc_start_streaming(struct vb2_queue *q)
+{
+	struct msm_vidc_inst *inst;
+	int rc = 0;
+	if (!q || !q->drv_priv) {
+		pr_err("Invalid input, q = %p\n", q);
+		return -EINVAL;
+	}
+	inst = q->drv_priv;
+	pr_debug("Streamon called on: %d capability\n", q->type);
+	switch (q->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		if (inst->vb2_bufq[CAPTURE_PORT].streaming)
+			rc = start_streaming(inst);
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		if (inst->vb2_bufq[OUTPUT_PORT].streaming)
+			rc = start_streaming(inst);
+		break;
+	default:
+		pr_err("Q-type is not supported: %d\n", q->type);
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static int msm_venc_stop_streaming(struct vb2_queue *q)
+{
+	struct msm_vidc_inst *inst;
+	int rc = 0;
+	if (!q || !q->drv_priv) {
+		pr_err("Invalid input, q = %p\n", q);
+		return -EINVAL;
+	}
+	inst = q->drv_priv;
+	pr_debug("Streamoff called on: %d capability\n", q->type);
+	switch (q->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+		break;
+	default:
+		pr_err("Q-type is not supported: %d\n", q->type);
+		rc = -EINVAL;
+		break;
+	}
+	if (rc)
+		pr_err("Failed to move inst: %p, cap = %d to state: %d\n",
+				inst, q->type, MSM_VIDC_CLOSE_DONE);
+	return rc;
+}
+
+static void msm_venc_buf_queue(struct vb2_buffer *vb)
+{
+	int rc;
+	rc = msm_comm_qbuf(vb);
+	if (rc)
+		pr_err("Failed to queue buffer: %d\n", rc);
+}
+
+static const struct vb2_ops msm_venc_vb2q_ops = {
+	.queue_setup = msm_venc_queue_setup,
+	.start_streaming = msm_venc_start_streaming,
+	.buf_queue = msm_venc_buf_queue,
+	.stop_streaming = msm_venc_stop_streaming,
+};
+
+const struct vb2_ops *msm_venc_get_vb2q_ops(void)
+{
+	return &msm_venc_vb2q_ops;
+}
+
+int msm_venc_inst_init(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	if (!inst) {
+		pr_err("Invalid input = %p\n", inst);
+		return -EINVAL;
+	}
+	inst->fmts[CAPTURE_PORT] = &venc_formats[1];
+	inst->fmts[OUTPUT_PORT] = &venc_formats[0];
+	inst->height = DEFAULT_HEIGHT;
+	inst->width = DEFAULT_WIDTH;
+	return rc;
+}
+
+int msm_venc_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
+{
+	if (!inst || !cap) {
+		pr_err("Invalid input, inst = %p, cap = %p\n", inst, cap);
+		return -EINVAL;
+	}
+	strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, MSM_VENC_DVC_NAME, sizeof(cap->card));
+	cap->bus_info[0] = 0;
+	cap->version = MSM_VIDC_VERSION;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+						V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+						V4L2_CAP_STREAMING;
+	memset(cap->reserved, 0, sizeof(cap->reserved));
+	return 0;
+}
+
+int msm_venc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
+{
+	const struct msm_vidc_format *fmt = NULL;
+	int rc = 0;
+	if (!inst || !f) {
+		pr_err("Invalid input, inst = %p, f = %p\n", inst, f);
+		return -EINVAL;
+	}
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		fmt = msm_comm_get_pixel_fmt_index(venc_formats,
+			ARRAY_SIZE(venc_formats), f->index, CAPTURE_PORT);
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		fmt = msm_comm_get_pixel_fmt_index(venc_formats,
+			ARRAY_SIZE(venc_formats), f->index, OUTPUT_PORT);
+		f->flags = V4L2_FMT_FLAG_COMPRESSED;
+	}
+
+	memset(f->reserved, 0 , sizeof(f->reserved));
+	if (fmt) {
+		strlcpy(f->description, fmt->description,
+				sizeof(f->description));
+		f->pixelformat = fmt->fourcc;
+	} else {
+		pr_err("No more formats found\n");
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	const struct msm_vidc_format *fmt = NULL;
+	int rc = 0;
+	int i;
+	if (!inst || !f) {
+		pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+		return -EINVAL;
+	}
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats,
+			ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
+			CAPTURE_PORT);
+		if (fmt && fmt->type != CAPTURE_PORT) {
+			pr_err("Format: %d not supported on CAPTURE port\n",
+					f->fmt.pix_mp.pixelformat);
+			rc = -EINVAL;
+			goto exit;
+		}
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		inst->width = f->fmt.pix_mp.width;
+		inst->height = f->fmt.pix_mp.height;
+		fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats,
+			ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
+			OUTPUT_PORT);
+		if (fmt && fmt->type != OUTPUT_PORT) {
+			pr_err("Format: %d not supported on OUTPUT port\n",
+					f->fmt.pix_mp.pixelformat);
+			rc = -EINVAL;
+			goto exit;
+		}
+	}
+
+	if (fmt) {
+		for (i = 0; i < fmt->num_planes; ++i) {
+			f->fmt.pix_mp.plane_fmt[i].sizeimage =
+				fmt->get_frame_size(i, f->fmt.pix_mp.height,
+						f->fmt.pix_mp.width);
+		}
+		inst->fmts[fmt->type] = fmt;
+		if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+			rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+			if (rc) {
+				pr_err("Failed to open instance\n");
+				goto exit;
+			}
+		}
+	} else {
+		pr_err("Buf type not recognized, type = %d\n",
+					f->type);
+		rc = -EINVAL;
+	}
+exit:
+	return rc;
+}
+
+int msm_venc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	const struct msm_vidc_format *fmt = NULL;
+	int rc = 0;
+	int i;
+	if (!inst || !f) {
+		pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+		return -EINVAL;
+	}
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		fmt = inst->fmts[CAPTURE_PORT];
+	else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		fmt = inst->fmts[OUTPUT_PORT];
+
+	if (fmt) {
+		f->fmt.pix_mp.pixelformat = fmt->fourcc;
+		f->fmt.pix_mp.height = inst->height;
+		f->fmt.pix_mp.width = inst->width;
+		for (i = 0; i < fmt->num_planes; ++i) {
+			f->fmt.pix_mp.plane_fmt[i].sizeimage =
+			fmt->get_frame_size(i, inst->height, inst->width);
+		}
+	} else {
+		pr_err("Buf type not recognized, type = %d\n",
+					f->type);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+int msm_venc_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
+{
+	struct vb2_queue *q = NULL;
+	int rc = 0;
+	if (!inst || !b) {
+		pr_err("Invalid input, inst = %p, buffer = %p\n", inst, b);
+		return -EINVAL;
+	}
+	q = msm_comm_get_vb2q(inst, b->type);
+	if (!q) {
+		pr_err("Failed to find buffer queue for type = %d\n", b->type);
+		return -EINVAL;
+	}
+
+	rc = vb2_reqbufs(q, b);
+	if (rc)
+		pr_err("Failed to get reqbufs, %d\n", rc);
+	return rc;
+}
+
+int msm_venc_prepare_buf(struct msm_vidc_inst *inst,
+					struct v4l2_buffer *b)
+{
+	int rc = 0;
+	int i;
+	struct vidc_buffer_addr_info buffer_info;
+
+	switch (b->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		for (i = 0; i < b->length; i++) {
+			pr_err("device_addr = %ld, size = %d\n",
+				b->m.planes[i].m.userptr,
+				b->m.planes[i].length);
+			buffer_info.buffer_size = b->m.planes[i].length;
+			buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+			buffer_info.num_buffers = 1;
+			buffer_info.align_device_addr =
+				b->m.planes[i].m.userptr;
+			buffer_info.extradata_size = 0;
+			buffer_info.extradata_addr = 0;
+			rc = vidc_hal_session_set_buffers((void *)inst->session,
+					&buffer_info);
+			if (rc)
+				pr_err("vidc_hal_session_set_buffers failed");
+		}
+		break;
+	default:
+		pr_err("Buffer type not recognized: %d\n", b->type);
+		break;
+	}
+	return rc;
+}
+
+int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	struct vb2_queue *q = NULL;
+	int rc = 0;
+	q = msm_comm_get_vb2q(inst, b->type);
+	if (!q) {
+		pr_err("Failed to find buffer queue for type = %d\n", b->type);
+		return -EINVAL;
+	}
+	rc = vb2_qbuf(q, b);
+	if (rc)
+		pr_err("Failed to qbuf, %d\n", rc);
+	return rc;
+}
+
+int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	struct vb2_queue *q = NULL;
+	int rc = 0;
+	q = msm_comm_get_vb2q(inst, b->type);
+	if (!q) {
+		pr_err("Failed to find buffer queue for type = %d\n", b->type);
+		return -EINVAL;
+	}
+	rc = vb2_dqbuf(q, b, true);
+	if (rc)
+		pr_err("Failed to qbuf, %d\n", rc);
+	return rc;
+}
+
+int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+	int rc = 0;
+	struct vb2_queue *q;
+	q = msm_comm_get_vb2q(inst, i);
+	if (!q) {
+		pr_err("Failed to find buffer queue for type = %d\n", i);
+		return -EINVAL;
+	}
+	pr_debug("Calling streamon\n");
+	rc = vb2_streamon(q, i);
+	if (rc)
+		pr_err("streamon failed on port: %d\n", i);
+	return rc;
+}
+
+int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+	int rc = 0;
+	struct vb2_queue *q;
+	q = msm_comm_get_vb2q(inst, i);
+	if (!q) {
+		pr_err("Failed to find buffer queue for type = %d\n", i);
+		return -EINVAL;
+	}
+	pr_debug("Calling streamoff\n");
+	rc = vb2_streamoff(q, i);
+	if (rc)
+		pr_err("streamoff failed on port: %d\n", i);
+	return rc;
+}
diff --git a/drivers/media/video/msm_vidc/msm_venc.h b/drivers/media/video/msm_vidc/msm_venc.h
new file mode 100644
index 0000000..4a156dd
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_venc.h
@@ -0,0 +1,35 @@
+/* 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.
+ *
+ */
+#ifndef _MSM_VENC_H_
+#define _MSM_VENC_H_
+
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+
+int msm_venc_inst_init(struct msm_vidc_inst *inst);
+int msm_venc_ctrl_init(struct msm_vidc_inst *inst);
+int msm_venc_querycap(void *instance, struct v4l2_capability *cap);
+int msm_venc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
+int msm_venc_s_fmt(void *instance, struct v4l2_format *f);
+int msm_venc_g_fmt(void *instance, struct v4l2_format *f);
+int msm_venc_s_ctrl(void *instance, struct v4l2_control *a);
+int msm_venc_g_ctrl(void *instance, struct v4l2_control *a);
+int msm_venc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
+int msm_venc_prepare_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+struct vb2_ops *msm_venc_get_vb2q_ops(void);
+
+#endif
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
new file mode 100644
index 0000000..4725f5f
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -0,0 +1,339 @@
+/* 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/slab.h>
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+#include "msm_vdec.h"
+#include "msm_venc.h"
+#include "msm_vidc_common.h"
+#include "msm_smem.h"
+
+int msm_vidc_poll(void *instance, struct file *filp,
+		struct poll_table_struct *wait)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst = instance;
+	struct vb2_queue *outq = &inst->vb2_bufq[OUTPUT_PORT];
+	struct vb2_queue *capq = &inst->vb2_bufq[CAPTURE_PORT];
+	struct vb2_buffer *out_vb = NULL;
+	struct vb2_buffer *cap_vb = NULL;
+	unsigned long flags;
+	if (!outq->streaming && !capq->streaming) {
+		pr_err("Returning POLLERR from here: %d, %d\n",
+			outq->streaming, capq->streaming);
+		return POLLERR;
+	}
+	poll_wait(filp, &capq->done_wq, wait);
+	poll_wait(filp, &outq->done_wq, wait);
+	spin_lock_irqsave(&capq->done_lock, flags);
+	if (!list_empty(&capq->done_list))
+		cap_vb = list_first_entry(&capq->done_list, struct vb2_buffer,
+								done_entry);
+	if (cap_vb && (cap_vb->state == VB2_BUF_STATE_DONE
+				|| cap_vb->state == VB2_BUF_STATE_ERROR))
+		rc |= POLLIN | POLLRDNORM;
+	spin_unlock_irqrestore(&capq->done_lock, flags);
+	spin_lock_irqsave(&outq->done_lock, flags);
+	if (!list_empty(&outq->done_list))
+		out_vb = list_first_entry(&outq->done_list, struct vb2_buffer,
+								done_entry);
+	if (out_vb && (out_vb->state == VB2_BUF_STATE_DONE
+				|| out_vb->state == VB2_BUF_STATE_ERROR))
+		rc |= POLLOUT | POLLWRNORM;
+	spin_unlock_irqrestore(&outq->done_lock, flags);
+	return rc;
+}
+
+int msm_vidc_querycap(void *instance, struct v4l2_capability *cap)
+{
+	struct msm_vidc_inst *inst = instance;
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_querycap(instance, cap);
+	else if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_querycap(instance, cap);
+	return -EINVAL;
+}
+int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f)
+{
+	struct msm_vidc_inst *inst = instance;
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_enum_fmt(instance, f);
+	else if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_enum_fmt(instance, f);
+	return -EINVAL;
+}
+int msm_vidc_s_fmt(void *instance, struct v4l2_format *f)
+{
+	struct msm_vidc_inst *inst = instance;
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_s_fmt(instance, f);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_s_fmt(instance, f);
+	return -EINVAL;
+}
+int msm_vidc_g_fmt(void *instance, struct v4l2_format *f)
+{
+	struct msm_vidc_inst *inst = instance;
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_g_fmt(instance, f);
+	else if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_g_fmt(instance, f);
+	return -EINVAL;
+}
+int msm_vidc_s_ctrl(void *instance, struct v4l2_control *control)
+{
+	struct msm_vidc_inst *inst = instance;
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_s_ctrl(instance, control);
+	return -EINVAL;
+}
+int msm_vidc_g_ctrl(void *instance, struct v4l2_control *control)
+{
+	struct msm_vidc_inst *inst = instance;
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_g_ctrl(instance, control);
+	return -EINVAL;
+}
+int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b)
+{
+	struct msm_vidc_inst *inst = instance;
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_reqbufs(instance, b);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_reqbufs(instance, b);
+	return -EINVAL;
+}
+
+int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b)
+{
+	struct msm_vidc_inst *inst = instance;
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_prepare_buf(instance, b);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_prepare_buf(instance, b);
+	return -EINVAL;
+}
+
+int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
+{
+	struct msm_vidc_inst *inst = instance;
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_qbuf(instance, b);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_qbuf(instance, b);
+	return -EINVAL;
+}
+
+int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b)
+{
+	struct msm_vidc_inst *inst = instance;
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_dqbuf(instance, b);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_dqbuf(instance, b);
+	return -EINVAL;
+}
+
+int msm_vidc_streamon(void *instance, enum v4l2_buf_type i)
+{
+	struct msm_vidc_inst *inst = instance;
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_streamon(instance, i);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_streamon(instance, i);
+	return -EINVAL;
+}
+
+int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i)
+{
+	struct msm_vidc_inst *inst = instance;
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_streamoff(instance, i);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_streamoff(instance, i);
+	return -EINVAL;
+}
+
+void *vidc_get_userptr(void *alloc_ctx, unsigned long vaddr,
+				unsigned long size, int write)
+{
+	return NULL;
+}
+
+void vidc_put_userptr(void *buf_priv)
+{
+}
+
+static const struct vb2_mem_ops msm_vidc_vb2_mem_ops = {
+	.get_userptr = vidc_get_userptr,
+	.put_userptr = vidc_put_userptr,
+};
+
+static inline int vb2_bufq_init(struct msm_vidc_inst *inst,
+		enum v4l2_buf_type type, enum session_type sess)
+{
+	struct vb2_queue *q = NULL;
+	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		q = &inst->vb2_bufq[CAPTURE_PORT];
+	} else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		q = &inst->vb2_bufq[OUTPUT_PORT];
+	} else {
+		pr_err("buf_type = %d not recognised\n", type);
+		return -EINVAL;
+	}
+	q->type = type;
+	q->io_modes = VB2_MMAP | VB2_USERPTR;
+	q->io_flags = 0;
+	if (sess == MSM_VIDC_DECODER)
+		q->ops = msm_vdec_get_vb2q_ops();
+	else if (sess == MSM_VIDC_ENCODER)
+		q->ops = msm_venc_get_vb2q_ops();
+	q->mem_ops = &msm_vidc_vb2_mem_ops;
+	q->drv_priv = inst;
+	return vb2_queue_init(q);
+}
+
+void *msm_vidc_open(int core_id, int session_type)
+{
+	struct msm_vidc_inst *inst = NULL;
+	struct msm_vidc_core *core = NULL;
+	unsigned long flags;
+	int rc = 0;
+	int i = 0;
+	if (core_id >= MSM_VIDC_CORES_MAX ||
+			session_type >= MSM_VIDC_MAX_DEVICES) {
+		pr_err("Invalid input, core_id = %d, session = %d\n",
+			core_id, session_type);
+		goto err_invalid_core;
+	}
+	core = get_vidc_core(core_id);
+	if (!core) {
+		pr_err("Failed to find core for core_id = %d\n", core_id);
+		goto err_invalid_core;
+	}
+
+	inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+	if (!inst) {
+		pr_err("Unable to allocate video instance\n");
+		goto err_no_mem;
+	}
+	mutex_init(&inst->sync_lock);
+	spin_lock_init(&inst->lock);
+	inst->session_type = session_type;
+	INIT_LIST_HEAD(&inst->pendingq);
+	INIT_LIST_HEAD(&inst->internalbufs);
+	INIT_LIST_HEAD(&inst->extradatabufs);
+	inst->state = MSM_VIDC_CORE_UNINIT_DONE;
+	inst->core = core;
+	for (i = SESSION_MSG_INDEX(SESSION_MSG_START);
+		i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) {
+		init_completion(&inst->completions[i]);
+	}
+	inst->mem_client = msm_smem_new_client(SMEM_ION);
+	if (!inst->mem_client) {
+		pr_err("Failed to create memory client\n");
+		goto fail_mem_client;
+	}
+	if (session_type == MSM_VIDC_DECODER) {
+		msm_vdec_inst_init(inst);
+		msm_vdec_ctrl_init(inst);
+	} else if (session_type == MSM_VIDC_ENCODER) {
+		msm_venc_inst_init(inst);
+	}
+	rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+			session_type);
+	if (rc) {
+		pr_err("Failed to initialize vb2 queue on capture port\n");
+		goto fail_init;
+	}
+	rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+			session_type);
+	if (rc) {
+		pr_err("Failed to initialize vb2 queue on capture port\n");
+		goto fail_init;
+	}
+	rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT);
+	if (rc) {
+		pr_err("Failed to move video instance to init state\n");
+		goto fail_init;
+	}
+	spin_lock_irqsave(&core->lock, flags);
+	list_add_tail(&inst->list, &core->instances);
+	spin_unlock_irqrestore(&core->lock, flags);
+	return inst;
+fail_init:
+	msm_smem_delete_client(inst->mem_client);
+fail_mem_client:
+	kfree(inst);
+	inst = NULL;
+err_no_mem:
+err_invalid_core:
+	return inst;
+}
+
+static void cleanup_instance(struct msm_vidc_inst *inst)
+{
+	unsigned long flags;
+	struct list_head *ptr, *next;
+	struct vb2_buf_entry *entry;
+	struct internal_buf *buf;
+	struct extradata_buf *ebuf;
+	if (inst) {
+		spin_lock_irqsave(&inst->lock, flags);
+		list_for_each_safe(ptr, next, &inst->pendingq) {
+			entry = list_entry(ptr, struct vb2_buf_entry, list);
+			list_del(&entry->list);
+			kfree(entry);
+		}
+		list_for_each_safe(ptr, next, &inst->internalbufs) {
+			buf = list_entry(ptr, struct internal_buf, list);
+			list_del(&buf->list);
+			msm_smem_free(inst->mem_client, buf->handle);
+			kfree(buf);
+		}
+		list_for_each_safe(ptr, next, &inst->extradatabufs) {
+			ebuf = list_entry(ptr, struct extradata_buf, list);
+			list_del(&ebuf->list);
+			msm_smem_free(inst->mem_client, ebuf->handle);
+			kfree(ebuf);
+		}
+		spin_unlock_irqrestore(&inst->lock, flags);
+		msm_smem_delete_client(inst->mem_client);
+	}
+}
+
+int msm_vidc_close(void *instance)
+{
+	struct msm_vidc_inst *inst = instance;
+	struct msm_vidc_inst *temp;
+	struct msm_vidc_core *core;
+	struct list_head *ptr, *next;
+	int rc = 0;
+	core = inst->core;
+	mutex_lock(&core->sync_lock);
+	list_for_each_safe(ptr, next, &core->instances) {
+		temp = list_entry(ptr, struct msm_vidc_inst, list);
+		if (temp == inst) {
+			list_del(&inst->list);
+			kfree(inst);
+		}
+	}
+	mutex_unlock(&core->sync_lock);
+	rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT);
+	if (rc)
+		pr_err("Failed to move video instance to init state\n");
+	cleanup_instance(inst);
+	pr_debug("Closed the instance\n");
+	return 0;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
new file mode 100644
index 0000000..e889b1c
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -0,0 +1,929 @@
+/* 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/sched.h>
+#include <linux/slab.h>
+
+#include "msm_vidc_common.h"
+#include "vidc_hal_api.h"
+#include "msm_smem.h"
+
+#define HW_RESPONSE_TIMEOUT 5000
+
+#define IS_ALREADY_IN_STATE(__p, __d) ({\
+	int __rc = (__p >= __d);\
+	__rc; \
+})
+
+struct msm_vidc_core *get_vidc_core(int core_id)
+{
+	struct msm_vidc_core *core;
+	int found = 0;
+	unsigned long flags;
+	if (core_id > MSM_VIDC_CORES_MAX) {
+		pr_err("Core id = %d is greater than max = %d\n",
+			core_id, MSM_VIDC_CORES_MAX);
+		return NULL;
+	}
+	spin_lock_irqsave(&vidc_driver->lock, flags);
+	list_for_each_entry(core, &vidc_driver->cores, list) {
+		if (core && core->id == core_id)
+			found = 1;
+			break;
+	}
+	spin_unlock_irqrestore(&vidc_driver->lock, flags);
+	if (found)
+		return core;
+	return NULL;
+}
+
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_index(
+	const struct msm_vidc_format fmt[], int size, int index, int fmt_type)
+{
+	int i, k = 0;
+	if (!fmt || index < 0) {
+		pr_err("Invalid inputs, fmt = %p, index = %d\n",
+						fmt, index);
+		return NULL;
+	}
+	for (i = 0; i < size; i++) {
+		if (fmt[i].type != fmt_type)
+			continue;
+		if (k == index)
+			break;
+		k++;
+	}
+	if (i == size) {
+		pr_err("Format not found\n");
+		return NULL;
+	}
+	return &fmt[i];
+}
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
+	const struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type)
+{
+	int i;
+	if (!fmt) {
+		pr_err("Invalid inputs, fmt = %p\n", fmt);
+		return NULL;
+	}
+	for (i = 0; i < size; i++) {
+		if (fmt[i].fourcc == fourcc)
+				break;
+	}
+	if (i == size) {
+		pr_err("Format not found\n");
+		return NULL;
+	}
+	return &fmt[i];
+}
+
+struct vb2_queue *msm_comm_get_vb2q(
+		struct msm_vidc_inst *inst,	enum v4l2_buf_type type)
+{
+	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return &inst->vb2_bufq[CAPTURE_PORT];
+	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return &inst->vb2_bufq[OUTPUT_PORT];
+	return NULL;
+}
+
+static void handle_sys_init_done(enum command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_core *core;
+	struct vidc_hal_sys_init_done *sys_init_msg;
+	int index = SYS_MSG_INDEX(cmd);
+	if (!response) {
+		pr_err("Failed to get valid response for sys init\n");
+		return;
+	}
+	core = get_vidc_core(response->device_id);
+	if (!core) {
+		pr_err("Wrong device_id received\n");
+		return;
+	}
+	pr_debug("index = %d\n", index);
+	pr_debug("ptr = %p\n", &(core->completions[index]));
+	complete(&(core->completions[index]));
+	sys_init_msg = response->data;
+	if (!sys_init_msg) {
+		pr_err("sys_init_done message not proper\n");
+		return;
+	}
+}
+
+static inline void change_inst_state(struct msm_vidc_inst *inst,
+	enum instance_state state)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&inst->lock, flags);
+	pr_debug("Moved inst: %p from state: %d to state: %d\n",
+		   inst, inst->state, state);
+	inst->state = state;
+	spin_unlock_irqrestore(&inst->lock, flags);
+}
+
+static int signal_session_msg_receipt(enum command_response cmd,
+		struct msm_vidc_inst *inst)
+{
+	if (!inst) {
+		pr_err("Invalid(%p) instance id\n", inst);
+		return -EINVAL;
+	}
+	complete(&inst->completions[SESSION_MSG_INDEX(cmd)]);
+	return 0;
+}
+
+static int wait_for_sess_signal_receipt(struct msm_vidc_inst *inst,
+	enum command_response cmd)
+{
+	int rc = 0;
+	rc = wait_for_completion_timeout(
+		&inst->completions[SESSION_MSG_INDEX(cmd)],
+		msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+	if (!rc) {
+		pr_err("Wait interrupted or timeout: %d\n", rc);
+		rc = -EIO;
+	} else {
+		rc = 0;
+	}
+	return rc;
+}
+
+static int wait_for_state(struct msm_vidc_inst *inst,
+	enum instance_state flipped_state,
+	enum instance_state desired_state,
+	enum command_response hal_cmd)
+{
+	int rc = 0;
+	if (IS_ALREADY_IN_STATE(flipped_state, desired_state)) {
+		pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+		goto err_same_state;
+	}
+	pr_debug("Waiting for hal_cmd: %d\n", hal_cmd);
+	rc = wait_for_sess_signal_receipt(inst, hal_cmd);
+	if (!rc)
+		change_inst_state(inst, desired_state);
+err_same_state:
+	return rc;
+}
+
+static void handle_session_init_done(enum command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+	if (response) {
+		inst = (struct msm_vidc_inst *)response->session_id;
+		signal_session_msg_receipt(cmd, inst);
+		return;
+	} else {
+		pr_err("Failed to get valid response for session init\n");
+	}
+}
+
+static void handle_session_prop_info(enum command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+	unsigned long flags;
+	if (!response || !response->data) {
+		pr_err("Failed to get valid response for prop info\n");
+		return;
+	}
+	inst = (struct msm_vidc_inst *)response->session_id;
+	spin_lock_irqsave(&inst->lock, flags);
+	memcpy(&inst->buff_req, response->data,
+			sizeof(struct buffer_requirements));
+	spin_unlock_irqrestore(&inst->lock, flags);
+	signal_session_msg_receipt(cmd, inst);
+}
+
+static void handle_load_resource_done(enum command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+	if (response)
+		inst = (struct msm_vidc_inst *)response->session_id;
+	else
+		pr_err("Failed to get valid response for load resource\n");
+}
+
+static void handle_start_done(enum command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+	if (response) {
+		inst = (struct msm_vidc_inst *)response->session_id;
+		signal_session_msg_receipt(cmd, inst);
+	} else {
+		pr_err("Failed to get valid response for start done\n");
+	}
+}
+
+static void handle_stop_done(enum command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+	if (response) {
+		inst = (struct msm_vidc_inst *)response->session_id;
+		signal_session_msg_receipt(cmd, inst);
+	} else {
+		pr_err("Failed to get valid response for stop done\n");
+	}
+}
+
+static void handle_release_res_done(enum command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+	if (response) {
+		inst = (struct msm_vidc_inst *)response->session_id;
+		signal_session_msg_receipt(cmd, inst);
+	} else {
+		pr_err("Failed to get valid response for release"
+			   " resource done\n");
+	}
+}
+
+static void handle_session_close(enum command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+	if (response) {
+		inst = (struct msm_vidc_inst *)response->session_id;
+		signal_session_msg_receipt(cmd, inst);
+	} else {
+		pr_err("Failed to get valid response for session close\n");
+	}
+}
+
+static struct vb2_buffer *get_vb_from_device_addr(struct vb2_queue *q,
+		u32 dev_addr)
+{
+	struct vb2_buffer *vb = NULL;
+	int found = 0;
+	if (!q) {
+		pr_err("Invalid parameter\n");
+		return NULL;
+	}
+	list_for_each_entry(vb, &q->queued_list, queued_entry) {
+		if (vb->v4l2_planes[0].m.userptr == dev_addr) {
+			found = 1;
+			break;
+		}
+	}
+	if (!found) {
+		pr_err("Failed to find the buffer in queued list: %d, %d\n",
+			dev_addr, q->type);
+		vb = NULL;
+	}
+	return vb;
+}
+
+static void handle_ebd(enum command_response cmd, void *data)
+{
+	struct msm_vidc_cb_data_done *response = data;
+	struct vb2_buffer *vb;
+	if (!response) {
+		pr_err("Invalid response from vidc_hal\n");
+		return;
+	}
+	vb = response->clnt_data;
+	if (vb)
+		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+}
+
+static void handle_fbd(enum command_response cmd, void *data)
+{
+	struct msm_vidc_cb_data_done *response = data;
+	struct msm_vidc_inst *inst;
+	struct vb2_buffer *vb;
+	struct vidc_hal_fbd *fill_buf_done;
+	if (!response) {
+		pr_err("Invalid response from vidc_hal\n");
+		return;
+	}
+	inst = (struct msm_vidc_inst *)response->session_id;
+	fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
+	vb = get_vb_from_device_addr(&inst->vb2_bufq[CAPTURE_PORT],
+		(u32)fill_buf_done->packet_buffer1);
+	if (vb) {
+		vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
+		pr_err("Filled length = %d\n", vb->v4l2_planes[0].bytesused);
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
+			vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
+		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+	}
+}
+
+void handle_cmd_response(enum command_response cmd, void *data)
+{
+	pr_debug("Command response = %d\n", cmd);
+	switch (cmd) {
+	case SYS_INIT_DONE:
+		handle_sys_init_done(cmd, data);
+		break;
+	case SESSION_INIT_DONE:
+		handle_session_init_done(cmd, data);
+		break;
+	case SESSION_PROPERTY_INFO:
+		handle_session_prop_info(cmd, data);
+		break;
+	case SESSION_LOAD_RESOURCE_DONE:
+		handle_load_resource_done(cmd, data);
+		break;
+	case SESSION_START_DONE:
+		handle_start_done(cmd, data);
+		break;
+	case SESSION_ETB_DONE:
+		handle_ebd(cmd, data);
+		break;
+	case SESSION_FTB_DONE:
+		handle_fbd(cmd, data);
+		break;
+	case SESSION_STOP_DONE:
+		handle_stop_done(cmd, data);
+		break;
+	case SESSION_RELEASE_RESOURCE_DONE:
+		handle_release_res_done(cmd, data);
+		break;
+	case SESSION_END_DONE:
+		handle_session_close(cmd, data);
+		break;
+	default:
+		pr_err("response unhandled\n");
+		break;
+	}
+}
+
+static int msm_comm_init_core_done(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core = inst->core;
+	unsigned long flags;
+	int rc = 0;
+	mutex_lock(&core->sync_lock);
+	if (core->state >= VIDC_CORE_INIT_DONE) {
+		pr_err("Video core: %d is already in state: %d\n",
+				core->id, core->state);
+		goto core_already_inited;
+	}
+	pr_debug("Waiting for SYS_INIT_DONE\n");
+	rc = wait_for_completion_timeout(
+		&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)],
+		msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+	if (!rc) {
+		pr_err("Wait interrupted or timeout: %d\n", rc);
+		rc = -EIO;
+		goto exit;
+	} else {
+		spin_lock_irqsave(&core->lock, flags);
+		core->state = VIDC_CORE_INIT_DONE;
+		spin_unlock_irqrestore(&core->lock, flags);
+	}
+	pr_debug("SYS_INIT_DONE!!!\n");
+core_already_inited:
+	change_inst_state(inst, MSM_VIDC_CORE_INIT_DONE);
+	rc = 0;
+exit:
+	mutex_unlock(&core->sync_lock);
+	return rc;
+}
+
+static int msm_comm_init_core(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_core *core = inst->core;
+	unsigned long flags;
+	mutex_lock(&core->sync_lock);
+	if (core->state >= VIDC_CORE_INIT) {
+		pr_err("Video core: %d is already in state: %d\n",
+				core->id, core->state);
+		goto core_already_inited;
+	}
+	init_completion(&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)]);
+	rc = vidc_hal_core_init(core->device);
+	if (rc) {
+		pr_err("Failed to init core, id = %d\n", core->id);
+		goto exit;
+	}
+	spin_lock_irqsave(&core->lock, flags);
+	core->state = VIDC_CORE_INIT;
+	spin_unlock_irqrestore(&core->lock, flags);
+core_already_inited:
+	change_inst_state(inst, MSM_VIDC_CORE_INIT);
+exit:
+	mutex_unlock(&core->sync_lock);
+	return rc;
+}
+
+static int msm_vidc_deinit_core(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_vidc_core *core = inst->core;
+	unsigned long flags;
+	mutex_lock(&core->sync_lock);
+	if (core->state == VIDC_CORE_UNINIT) {
+		pr_err("Video core: %d is already in state: %d\n",
+				core->id, core->state);
+		goto core_already_uninited;
+	}
+	if (list_empty(&core->instances)) {
+		pr_debug("Calling vidc_hal_core_release\n");
+		rc = vidc_hal_core_release(core->device);
+		if (rc) {
+			pr_err("Failed to release core, id = %d\n", core->id);
+			goto exit;
+		}
+		spin_lock_irqsave(&core->lock, flags);
+		core->state = VIDC_CORE_UNINIT;
+		spin_unlock_irqrestore(&core->lock, flags);
+	}
+core_already_uninited:
+	change_inst_state(inst, MSM_VIDC_CORE_UNINIT);
+exit:
+	mutex_unlock(&core->sync_lock);
+	return rc;
+}
+
+static enum hal_domain get_hal_domain(int session_type)
+{
+	enum hal_domain domain;
+	switch (session_type) {
+	case MSM_VIDC_ENCODER:
+		domain = HAL_VIDEO_DOMAIN_ENCODER;
+		break;
+	case MSM_VIDC_DECODER:
+		domain = HAL_VIDEO_DOMAIN_DECODER;
+		break;
+	default:
+		pr_err("Wrong domain\n");
+		domain = HAL_UNUSED_DOMAIN;
+		break;
+	}
+	return domain;
+}
+
+static enum hal_video_codec get_hal_codec_type(int fourcc)
+{
+	enum hal_video_codec codec;
+	pr_debug("codec in %s is 0x%x", __func__, fourcc);
+	switch (fourcc) {
+	case V4L2_PIX_FMT_H264:
+	case V4L2_PIX_FMT_H264_NO_SC:
+		codec = HAL_VIDEO_CODEC_H264;
+		break;
+	case V4L2_PIX_FMT_H263:
+		codec = HAL_VIDEO_CODEC_H263;
+		break;
+	case V4L2_PIX_FMT_MPEG1:
+		codec = HAL_VIDEO_CODEC_MPEG1;
+		break;
+	case V4L2_PIX_FMT_MPEG2:
+		codec = HAL_VIDEO_CODEC_MPEG2;
+		break;
+	case V4L2_PIX_FMT_MPEG4:
+		codec = HAL_VIDEO_CODEC_MPEG4;
+		break;
+	case V4L2_PIX_FMT_VC1_ANNEX_G:
+	case V4L2_PIX_FMT_VC1_ANNEX_L:
+		codec = HAL_VIDEO_CODEC_VC1;
+		break;
+		/*HAL_VIDEO_CODEC_MVC
+		  HAL_VIDEO_CODEC_DIVX_311
+		  HAL_VIDEO_CODEC_DIVX
+		  HAL_VIDEO_CODEC_SPARK
+		  HAL_VIDEO_CODEC_VP6
+		  HAL_VIDEO_CODEC_VP7
+		  HAL_VIDEO_CODEC_VP8*/
+	default:
+		pr_err("Wrong codec: %d\n", fourcc);
+		codec = HAL_UNUSED_CODEC;
+	}
+	return codec;
+}
+
+static int msm_comm_session_init(int flipped_state,
+	struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	int fourcc = 0;
+	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_OPEN)) {
+		pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+		goto exit;
+	}
+	if (inst->session_type == MSM_VIDC_DECODER) {
+		fourcc = inst->fmts[OUTPUT_PORT]->fourcc;
+	} else if (inst->session_type == MSM_VIDC_ENCODER) {
+		fourcc = inst->fmts[CAPTURE_PORT]->fourcc;
+	} else {
+		pr_err("Invalid session\n");
+		return -EINVAL;
+	}
+	init_completion(
+		&inst->completions[SESSION_MSG_INDEX(SESSION_INIT_DONE)]);
+	inst->session = vidc_hal_session_init(inst->core->device, (u32) inst,
+					get_hal_domain(inst->session_type),
+					get_hal_codec_type(fourcc));
+	if (!inst->session) {
+		pr_err("Failed to call session init for: %d, %d, %d, %d\n",
+				(int)inst->core->device, (int)inst,
+				inst->session_type, fourcc);
+		goto exit;
+	}
+	change_inst_state(inst, MSM_VIDC_OPEN);
+exit:
+	return rc;
+}
+
+static int msm_vidc_load_resources(int flipped_state,
+	struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_LOAD_RESOURCES)) {
+		pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+		goto exit;
+	}
+	rc = vidc_hal_session_load_res((void *) inst->session);
+	if (rc) {
+		pr_err("Failed to send load resources\n");
+		goto exit;
+	}
+	change_inst_state(inst, MSM_VIDC_LOAD_RESOURCES);
+exit:
+	return rc;
+}
+
+static int msm_vidc_start(int flipped_state, struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_START)) {
+		pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+		goto exit;
+	}
+	init_completion(
+		&inst->completions[SESSION_MSG_INDEX(SESSION_START_DONE)]);
+	rc = vidc_hal_session_start((void *) inst->session);
+	if (rc) {
+		pr_err("Failed to send load resources\n");
+		goto exit;
+	}
+	change_inst_state(inst, MSM_VIDC_START);
+exit:
+	return rc;
+}
+
+static int msm_vidc_stop(int flipped_state, struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_STOP)) {
+		pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+		goto exit;
+	}
+	pr_debug("Send Stop to hal\n");
+	init_completion(
+		&inst->completions[SESSION_MSG_INDEX(SESSION_STOP_DONE)]);
+	rc = vidc_hal_session_stop((void *) inst->session);
+	if (rc) {
+		pr_err("Failed to send stop\n");
+		goto exit;
+	}
+	change_inst_state(inst, MSM_VIDC_STOP);
+exit:
+	return rc;
+}
+
+static int msm_vidc_release_res(int flipped_state, struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_RELEASE_RESOURCES)) {
+		pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+		goto exit;
+	}
+	pr_debug("Send release res to hal\n");
+	init_completion(
+	&inst->completions[SESSION_MSG_INDEX(SESSION_RELEASE_RESOURCE_DONE)]);
+	rc = vidc_hal_session_release_res((void *) inst->session);
+	if (rc) {
+		pr_err("Failed to send load resources\n");
+		goto exit;
+	}
+	change_inst_state(inst, MSM_VIDC_RELEASE_RESOURCES);
+exit:
+	return rc;
+}
+
+static int msm_comm_session_close(int flipped_state, struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_CLOSE)) {
+		pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+		goto exit;
+	}
+	pr_debug("Send session close to hal\n");
+	init_completion(
+		&inst->completions[SESSION_MSG_INDEX(SESSION_END_DONE)]);
+	rc = vidc_hal_session_end((void *) inst->session);
+	if (rc) {
+		pr_err("Failed to send load resources\n");
+		goto exit;
+	}
+	change_inst_state(inst, MSM_VIDC_OPEN);
+exit:
+	return rc;
+}
+
+int msm_comm_try_state(struct msm_vidc_inst *inst, int state)
+{
+	int rc = 0;
+	int flipped_state;
+	if (!inst) {
+		pr_err("Invalid instance pointer = %p\n", inst);
+		return -EINVAL;
+	}
+	pr_debug("Trying to move inst: %p from: 0x%x to 0x%x\n",
+				inst, inst->state, state);
+	mutex_lock(&inst->sync_lock);
+	flipped_state = inst->state;
+	if (flipped_state < MSM_VIDC_STOP
+		&& state > MSM_VIDC_STOP) {
+		flipped_state = MSM_VIDC_STOP + (MSM_VIDC_STOP - flipped_state);
+		flipped_state &= 0xFFFE;
+		flipped_state = flipped_state - 1;
+	} else if (flipped_state > MSM_VIDC_STOP
+		&& state < MSM_VIDC_STOP) {
+		flipped_state = MSM_VIDC_STOP -
+				(flipped_state - MSM_VIDC_STOP + 1);
+		flipped_state &= 0xFFFE;
+		flipped_state = flipped_state - 1;
+	}
+	pr_debug("flipped_state = 0x%x\n", flipped_state);
+	switch (flipped_state) {
+	case MSM_VIDC_CORE_UNINIT_DONE:
+	case MSM_VIDC_CORE_INIT:
+		rc = msm_comm_init_core(inst);
+		if (rc || state <= inst->state)
+			break;
+	case MSM_VIDC_CORE_INIT_DONE:
+		rc = msm_comm_init_core_done(inst);
+		if (rc || state <= inst->state)
+			break;
+	case MSM_VIDC_OPEN:
+		rc = msm_comm_session_init(flipped_state, inst);
+		if (rc || state <= inst->state)
+			break;
+	case MSM_VIDC_OPEN_DONE:
+		rc = wait_for_state(inst, flipped_state, MSM_VIDC_OPEN_DONE,
+			SESSION_INIT_DONE);
+		if (rc || state <= inst->state)
+			break;
+	case MSM_VIDC_LOAD_RESOURCES:
+		rc = msm_vidc_load_resources(flipped_state, inst);
+		if (rc || state <= inst->state)
+			break;
+	case MSM_VIDC_LOAD_RESOURCES_DONE:
+	case MSM_VIDC_START:
+		rc = msm_vidc_start(flipped_state, inst);
+		if (rc || state <= inst->state)
+			break;
+	case MSM_VIDC_START_DONE:
+		rc = wait_for_state(inst, flipped_state, MSM_VIDC_START_DONE,
+				SESSION_START_DONE);
+		if (rc || state <= inst->state)
+			break;
+	case MSM_VIDC_STOP:
+		rc = msm_vidc_stop(flipped_state, inst);
+		if (rc || state <= inst->state)
+			break;
+	case MSM_VIDC_STOP_DONE:
+		rc = wait_for_state(inst, flipped_state, MSM_VIDC_STOP_DONE,
+				SESSION_STOP_DONE);
+		if (rc || state <= inst->state)
+			break;
+		pr_debug("Moving to Stop Done state\n");
+	case MSM_VIDC_RELEASE_RESOURCES:
+		rc = msm_vidc_release_res(flipped_state, inst);
+		if (rc || state <= inst->state)
+			break;
+	case MSM_VIDC_RELEASE_RESOURCES_DONE:
+		rc = wait_for_state(inst, flipped_state,
+			MSM_VIDC_RELEASE_RESOURCES_DONE,
+			SESSION_RELEASE_RESOURCE_DONE);
+		if (rc || state <= inst->state)
+			break;
+		pr_debug("Moving to release resources done state\n");
+	case MSM_VIDC_CLOSE:
+		rc = msm_comm_session_close(flipped_state, inst);
+		if (rc || state <= inst->state)
+			break;
+	case MSM_VIDC_CLOSE_DONE:
+		rc = wait_for_state(inst, flipped_state, MSM_VIDC_CLOSE_DONE,
+			SESSION_END_DONE);
+		if (rc || state <= inst->state)
+			break;
+	case MSM_VIDC_CORE_UNINIT:
+		pr_debug("***************Sending core uninit\n");
+		rc = msm_vidc_deinit_core(inst);
+		if (rc || state == inst->state)
+			break;
+	default:
+		pr_err("State not recognized\n");
+		rc = -EINVAL;
+		break;
+	}
+	mutex_unlock(&inst->sync_lock);
+	if (rc)
+		pr_err("Failed to move from state: %d to %d\n",
+			inst->state, state);
+	return rc;
+}
+
+int msm_comm_qbuf(struct vb2_buffer *vb)
+{
+	int rc = 0;
+	struct vb2_queue *q;
+	struct msm_vidc_inst *inst;
+	unsigned long flags;
+	struct vb2_buf_entry *entry;
+	struct vidc_frame_data frame_data;
+	q = vb->vb2_queue;
+	inst = q->drv_priv;
+
+	if (!inst || !vb) {
+		pr_err("Invalid input: %p, %p\n", inst, vb);
+		return -EINVAL;
+	}
+	if (inst->state != MSM_VIDC_START_DONE) {
+			entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+			if (!entry) {
+				pr_err("Out of memory\n");
+				goto err_no_mem;
+			}
+			entry->vb = vb;
+			pr_debug("Queueing buffer in pendingq\n");
+			spin_lock_irqsave(&inst->lock, flags);
+			list_add_tail(&entry->list, &inst->pendingq);
+			spin_unlock_irqrestore(&inst->lock, flags);
+	} else {
+		memset(&frame_data, 0 , sizeof(struct vidc_frame_data));
+		frame_data.alloc_len = vb->v4l2_planes[0].length;
+		frame_data.filled_len = vb->v4l2_planes[0].bytesused;
+		frame_data.device_addr = vb->v4l2_planes[0].m.userptr;
+		frame_data.clnt_data = (u32)vb;
+		if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+			frame_data.buffer_type = HAL_BUFFER_INPUT;
+			if (vb->v4l2_buf.flags & V4L2_BUF_FLAG_EOS) {
+				frame_data.flags = HAL_BUFFERFLAG_EOS;
+				pr_debug("Received EOS on output capability\n");
+			}
+			pr_debug("Sending etb to hal: Alloc: %d :filled: %d\n",
+				frame_data.alloc_len, frame_data.filled_len);
+			rc = vidc_hal_session_etb((void *) inst->session,
+					&frame_data);
+			pr_debug("Sent etb to HAL\n");
+		} else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+			struct extradata_buf *addr;
+			struct list_head *ptr, *next;
+			frame_data.filled_len = 0;
+			frame_data.buffer_type = HAL_BUFFER_OUTPUT;
+			frame_data.extradata_addr = 0;
+			list_for_each_safe(ptr, next, &inst->extradatabufs) {
+				addr = list_entry(ptr,
+						struct extradata_buf, list);
+				if (addr->device_addr ==
+						frame_data.device_addr) {
+					frame_data.extradata_addr =
+						addr->handle->device_addr;
+					break;
+				}
+			}
+			pr_debug("Sending ftb to hal...: Alloc: %d :filled: %d"
+				" extradata_addr: %d\n", frame_data.alloc_len,
+				   frame_data.filled_len,
+				   frame_data.extradata_addr);
+			rc = vidc_hal_session_ftb((void *) inst->session,
+					&frame_data);
+		} else {
+			pr_err("This capability is not supported: %d\n",
+				q->type);
+			rc = -EINVAL;
+		}
+	}
+	if (rc)
+		pr_err("Failed to queue buffer\n");
+err_no_mem:
+	return rc;
+}
+
+int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	mutex_lock(&inst->sync_lock);
+	init_completion(
+		&inst->completions[SESSION_MSG_INDEX(SESSION_PROPERTY_INFO)]);
+	rc = vidc_hal_session_get_buf_req((void *) inst->session);
+	if (rc) {
+		pr_err("Failed to get property\n");
+		goto exit;
+	}
+	rc = wait_for_completion_timeout(
+		&inst->completions[SESSION_MSG_INDEX(SESSION_PROPERTY_INFO)],
+		msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+	if (!rc) {
+		pr_err("Wait interrupted or timeout: %d\n", rc);
+		rc = -EIO;
+		goto exit;
+	}
+	rc = 0;
+exit:
+	mutex_unlock(&inst->sync_lock);
+	return rc;
+}
+
+int msm_comm_allocate_extradata_buffers(struct msm_vidc_inst *inst,
+	struct extradata_buf *binfo)
+{
+	int rc = 0;
+	unsigned long flags;
+	struct msm_smem *handle;
+	pr_debug("Extradata: num = %d, size = %d, align = %d\n",
+			inst->buff_req.buffer[4].buffer_count_actual,
+			inst->buff_req.buffer[4].buffer_size,
+			inst->buff_req.buffer[4].buffer_alignment);
+	if (!inst->buff_req.buffer[4].buffer_size) {
+		pr_err("invalid size: %d",
+			   inst->buff_req.buffer[4].buffer_size);
+		rc = -ENOMEM;
+		goto err_no_mem;
+	}
+	handle = msm_smem_alloc(inst->mem_client,
+			inst->buff_req.buffer[4].buffer_size,
+			inst->buff_req.buffer[4].buffer_alignment, 0);
+	if (!handle) {
+		pr_err("Failed to allocate Extradata memory\n");
+		rc = -ENOMEM;
+		goto err_no_mem;
+	}
+	binfo->handle = handle;
+	spin_lock_irqsave(&inst->lock, flags);
+	list_add_tail(&binfo->list, &inst->extradatabufs);
+	spin_unlock_irqrestore(&inst->lock, flags);
+err_no_mem:
+	return rc;
+}
+
+int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_smem *handle;
+	struct internal_buf *binfo;
+	struct vidc_buffer_addr_info buffer_info;
+	unsigned long flags;
+	int i;
+	pr_debug("scratch: num = %d, size = %d\n",
+			inst->buff_req.buffer[6].buffer_count_actual,
+			inst->buff_req.buffer[6].buffer_size);
+	for (i = 0; i < inst->buff_req.buffer[6].buffer_count_actual;
+				i++) {
+		handle = msm_smem_alloc(inst->mem_client,
+				inst->buff_req.buffer[6].buffer_size, 1, 0);
+		if (!handle) {
+			pr_err("Failed to allocate scratch memory\n");
+			rc = -ENOMEM;
+			goto err_no_mem;
+		}
+		binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+		if (!binfo) {
+			pr_err("Out of memory\n");
+			rc = -ENOMEM;
+			goto err_no_mem;
+		}
+		binfo->handle = handle;
+		spin_lock_irqsave(&inst->lock, flags);
+		list_add_tail(&binfo->list, &inst->internalbufs);
+		spin_unlock_irqrestore(&inst->lock, flags);
+		buffer_info.buffer_size =
+				inst->buff_req.buffer[6].buffer_size;
+		buffer_info.buffer_type = HAL_BUFFER_INTERNAL_SCRATCH;
+		buffer_info.num_buffers = 1;
+		buffer_info.align_device_addr = handle->device_addr;
+		rc = vidc_hal_session_set_buffers((void *) inst->session,
+				&buffer_info);
+		if (rc) {
+			pr_err("vidc_hal_session_set_buffers failed");
+			break;
+		}
+	}
+err_no_mem:
+	return rc;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
new file mode 100644
index 0000000..45bfa7b
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -0,0 +1,38 @@
+/* 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.
+ *
+ */
+
+#ifndef _MSM_VIDC_COMMON_H_
+#define _MSM_VIDC_COMMON_H_
+#include "msm_vidc_internal.h"
+struct vb2_buf_entry {
+	struct list_head list;
+	struct vb2_buffer *vb;
+};
+struct msm_vidc_core *get_vidc_core(int core_id);
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_index(
+	const struct msm_vidc_format fmt[], int size, int index, int fmt_type);
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
+	const struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type);
+struct vb2_queue *msm_comm_get_vb2q(
+		struct msm_vidc_inst *inst, enum v4l2_buf_type type);
+int msm_comm_try_state(struct msm_vidc_inst *inst, int state);
+int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst);
+int msm_comm_allocate_extradata_buffers(struct msm_vidc_inst *inst,
+	struct extradata_buf *binfo);
+int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
+int msm_comm_qbuf(struct vb2_buffer *vb);
+#define IS_PRIV_CTRL(idx) (\
+		(V4L2_CTRL_ID2CLASS(idx) == V4L2_CTRL_CLASS_MPEG) && \
+		V4L2_CTRL_DRIVER_PRIV(idx))
+
+#endif
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
new file mode 100644
index 0000000..dce2dee
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -0,0 +1,166 @@
+/* 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.
+ *
+ */
+
+#ifndef _MSM_VIDC_INTERNAL_H_
+#define _MSM_VIDC_INTERNAL_H_
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/completion.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+#include <media/msm_vidc.h>
+
+#include "vidc_hal_api.h"
+
+#define MSM_VIDC_DRV_NAME "msm_vidc_driver"
+#define MSM_VIDC_VERSION KERNEL_VERSION(0, 0, 1);
+#define MAX_DEBUGFS_NAME 50
+#define DEFAULT_TIMEOUT 3
+
+#define SYS_MSG_START VIDC_EVENT_CHANGE
+#define SYS_MSG_END SYS_DEBUG
+#define SESSION_MSG_START SESSION_LOAD_RESOURCE_DONE
+#define SESSION_MSG_END SESSION_PROPERTY_INFO
+#define SYS_MSG_INDEX(__msg) (__msg - SYS_MSG_START)
+#define SESSION_MSG_INDEX(__msg) (__msg - SESSION_MSG_START)
+
+enum vidc_ports {
+	OUTPUT_PORT,
+	CAPTURE_PORT,
+	MAX_PORT_NUM
+};
+
+enum vidc_core_state {
+	VIDC_CORE_UNINIT = 0,
+	VIDC_CORE_INIT,
+	VIDC_CORE_INIT_DONE,
+};
+
+/*Donot change the enum values unless
+ * you know what you are doing*/
+enum instance_state {
+	MSM_VIDC_CORE_UNINIT_DONE = 0x0001,
+	MSM_VIDC_CORE_INIT,
+	MSM_VIDC_CORE_INIT_DONE,
+	MSM_VIDC_OPEN,
+	MSM_VIDC_OPEN_DONE,
+	MSM_VIDC_LOAD_RESOURCES,
+	MSM_VIDC_LOAD_RESOURCES_DONE,
+	MSM_VIDC_START,
+	MSM_VIDC_START_DONE,
+	MSM_VIDC_STOP,
+	MSM_VIDC_STOP_DONE,
+	MSM_VIDC_RELEASE_RESOURCES,
+	MSM_VIDC_RELEASE_RESOURCES_DONE,
+	MSM_VIDC_CLOSE,
+	MSM_VIDC_CLOSE_DONE,
+	MSM_VIDC_CORE_UNINIT,
+};
+
+struct buf_info {
+	struct list_head list;
+	struct vb2_buffer *buf;
+};
+
+struct internal_buf {
+	struct list_head list;
+	struct msm_smem *handle;
+};
+
+struct extradata_buf {
+	struct list_head list;
+	struct msm_smem *handle;
+	u32 device_addr;
+};
+
+struct msm_vidc_format {
+	char name[64];
+	u8 description[32];
+	u32 fourcc;
+	int num_planes;
+	int type;
+	u32 (*get_frame_size)(int plane, u32 height, u32 width);
+};
+
+struct msm_vidc_drv {
+	spinlock_t lock;
+	struct list_head cores;
+	int num_cores;
+	struct dentry *debugfs_root;
+};
+
+struct msm_video_device {
+	int type;
+	struct video_device vdev;
+};
+
+struct msm_vidc_core {
+	struct list_head list;
+	struct mutex sync_lock;
+	int id;
+	void *device;
+	struct msm_video_device vdev[MSM_VIDC_MAX_DEVICES];
+	struct v4l2_device v4l2_dev;
+	spinlock_t lock;
+	struct list_head instances;
+	struct dentry *debugfs_root;
+	u32 base_addr;
+	u32 register_base;
+	u32 register_size;
+	u32 irq;
+	enum vidc_core_state state;
+	struct completion completions[SYS_MSG_END - SYS_MSG_START + 1];
+};
+
+struct msm_vidc_inst {
+	struct list_head list;
+	struct mutex sync_lock;
+	struct msm_vidc_core *core;
+	int session_type;
+	void *session;
+	u32 width;
+	u32 height;
+	int state;
+	const struct msm_vidc_format *fmts[MAX_PORT_NUM];
+	struct vb2_queue vb2_bufq[MAX_PORT_NUM];
+	spinlock_t lock;
+	struct list_head pendingq;
+	struct list_head internalbufs;
+	struct list_head extradatabufs;
+	struct buffer_requirements buff_req;
+	void *mem_client;
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1];
+};
+
+extern struct msm_vidc_drv *vidc_driver;
+
+struct msm_vidc_ctrl {
+	u32 id;
+	char name[64];
+	enum v4l2_ctrl_type type;
+	s32 minimum;
+	s32 maximum;
+	s32 default_value;
+	u32 step;
+	u32 menu_skip_mask;
+	const char * const *qmenu;
+};
+
+void handle_cmd_response(enum command_response cmd, void *data);
+#endif
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 670d0f8..219f7a0 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -537,9 +537,9 @@
 	.release	= video_device_release,
 };
 
-int vcap_reg_powerup(struct vcap_dev *dev)
+int vcap_reg_powerup(struct vcap_dev *dev, struct device *ddev)
 {
-	dev->fs_vcap = regulator_get(NULL, "fs_vcap");
+	dev->fs_vcap = regulator_get(ddev, "vdd");
 	if (IS_ERR(dev->fs_vcap)) {
 		pr_err("%s: Regulator FS_VCAP get failed %ld\n", __func__,
 			PTR_ERR(dev->fs_vcap));
@@ -715,7 +715,7 @@
 {
 	int rc;
 
-	rc = vcap_reg_powerup(dev);
+	rc = vcap_reg_powerup(dev, ddev);
 	if (rc < 0)
 		goto reg_failed;
 	rc = vcap_clk_powerup(dev, ddev);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 54e1b9a..3b6a56a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -869,6 +869,13 @@
 	  This driver implements several miscellaneous APIs that may be needed
 	  in order to control the PM8XXX PMIC chip.
 
+config MFD_PM8XXX_SPK
+	tristate "Support for Qualcomm PM8xxx speaker APIs"
+	depends on MFD_PM8XXX
+	help
+	  This driver implements several external speaker amplifier APIs that
+	  may be needed in order to control the PM8XXX PMIC chip.
+
 config MFD_PM8XXX_BATT_ALARM
 	tristate "Support for Qualcomm PM8xxx battery voltage alarm"
 	depends on MFD_PM8XXX
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index fd887ea..3c10f63 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -123,4 +123,5 @@
 obj-$(CONFIG_MFD_PM8XXX_DEBUG) 	+= pm8xxx-debug.o
 obj-$(CONFIG_MFD_PM8XXX_PWM) 	+= pm8xxx-pwm.o
 obj-$(CONFIG_MFD_PM8XXX_MISC) 	+= pm8xxx-misc.o
+obj-$(CONFIG_MFD_PM8XXX_SPK) 	+= pm8xxx-spk.o
 obj-$(CONFIG_MFD_PM8XXX_BATT_ALARM) 	+= pm8xxx-batt-alarm.o
diff --git a/drivers/mfd/marimba-core.c b/drivers/mfd/marimba-core.c
index e168c49..12746dd 100644
--- a/drivers/mfd/marimba-core.c
+++ b/drivers/mfd/marimba-core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* 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
@@ -169,6 +169,11 @@
 	u8 mask_value[num_bytes];
 
 	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);
 
@@ -177,6 +182,12 @@
 					& ~mask) | (value[i] & mask);
 
 	msg = &marimba->xfer_msg[0];
+	if (marimba->client == NULL) {
+		pr_err("%s: Unable to access the Marimba slave device.\n",
+								__func__);
+		return -ENODEV;
+	}
+
 	msg->addr = marimba->client->addr;
 	msg->flags = 0;
 	msg->len = num_bytes + 1;
@@ -748,7 +759,7 @@
 	}
 }
 
-static int marimba_probe(struct i2c_client *client,
+static int __devinit marimba_probe(struct i2c_client *client,
 				const struct i2c_device_id *id)
 {
 	struct marimba_platform_data *pdata = client->dev.platform_data;
diff --git a/drivers/mfd/pm8038-core.c b/drivers/mfd/pm8038-core.c
index b03b7ac..f48c302 100644
--- a/drivers/mfd/pm8038-core.c
+++ b/drivers/mfd/pm8038-core.c
@@ -32,6 +32,9 @@
 #define REG_RTC_BASE		0x11D
 #define REG_IRQ_BASE            0x1BB
 
+#define REG_SPK_BASE		0x253
+#define REG_SPK_REGISTERS	3
+
 #define PM8038_VERSION_MASK	0xFFF0
 #define PM8038_VERSION_VALUE	0x09F0
 #define PM8038_REVISION_MASK	0x000F
@@ -273,6 +276,22 @@
 	.id		= -1,
 };
 
+static const struct resource resources_spk[] __devinitconst = {
+	[0] = {
+		.name   = PM8XXX_SPK_DEV_NAME,
+		.start  = REG_SPK_BASE,
+		.end    = REG_SPK_BASE + REG_SPK_REGISTERS,
+		.flags  = IORESOURCE_IO,
+	},
+};
+
+static struct mfd_cell spk_cell __devinitdata = {
+	.name           = PM8XXX_SPK_DEV_NAME,
+	.id             = -1,
+	.num_resources	= ARRAY_SIZE(resources_spk),
+	.resources	= resources_spk,
+};
+
 static struct mfd_cell debugfs_cell __devinitdata = {
 	.name		= "pm8xxx-debug",
 	.id		= 0,
@@ -516,6 +535,16 @@
 		}
 	}
 
+	if (pdata->spk_pdata) {
+		spk_cell.platform_data = pdata->spk_pdata;
+		spk_cell.pdata_size = sizeof(struct pm8xxx_spk_platform_data);
+		ret = mfd_add_devices(pmic->dev, 0, &spk_cell, 1, NULL, 0);
+		if (ret) {
+			pr_err("Failed to add spk subdevice ret=%d\n", ret);
+			goto bail;
+		}
+	}
+
 	if (pdata->num_regulators > 0 && pdata->regulator_pdatas) {
 		ret = pm8038_add_regulators(pdata, pmic, irq_base);
 		if (ret) {
diff --git a/drivers/mfd/pm8xxx-misc.c b/drivers/mfd/pm8xxx-misc.c
index 64c0bd1..080a87c 100644
--- a/drivers/mfd/pm8xxx-misc.c
+++ b/drivers/mfd/pm8xxx-misc.c
@@ -145,6 +145,11 @@
 #define MP3_1_SHIFT	5
 #define MP3_2_SHIFT	2
 
+#define REG_HSED_BIAS0_CNTL2		0xA1
+#define REG_HSED_BIAS1_CNTL2		0x135
+#define REG_HSED_BIAS2_CNTL2		0x138
+#define HSED_EN_MASK			0xC0
+
 struct pm8xxx_misc_chip {
 	struct list_head			link;
 	struct pm8xxx_misc_platform_data	pdata;
@@ -502,6 +507,8 @@
 		case PM8XXX_VERSION_8901:
 			rc = __pm8901_reset_pwr_off(chip, reset);
 			break;
+		case PM8XXX_VERSION_8038:
+		case PM8XXX_VERSION_8917:
 		case PM8XXX_VERSION_8921:
 			rc = __pm8921_reset_pwr_off(chip, reset);
 			break;
@@ -1098,6 +1105,52 @@
 }
 EXPORT_SYMBOL_GPL(pm8xxx_aux_clk_control);
 
+int pm8xxx_hsed_bias_control(enum pm8xxx_hsed_bias bias, bool enable)
+{
+	struct pm8xxx_misc_chip *chip;
+	unsigned long flags;
+	int rc = 0;
+	u16 addr;
+
+	switch (bias) {
+	case PM8XXX_HSED_BIAS0:
+		addr = REG_HSED_BIAS0_CNTL2;
+		break;
+	case PM8XXX_HSED_BIAS1:
+		addr = REG_HSED_BIAS1_CNTL2;
+		break;
+	case PM8XXX_HSED_BIAS2:
+		addr = REG_HSED_BIAS2_CNTL2;
+		break;
+	default:
+		pr_err("Invalid BIAS line\n");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&pm8xxx_misc_chips_lock, flags);
+
+	/* Loop over all attached PMICs and call specific functions for them. */
+	list_for_each_entry(chip, &pm8xxx_misc_chips, link) {
+		switch (chip->version) {
+		case PM8XXX_VERSION_8058:
+		case PM8XXX_VERSION_8921:
+			rc = pm8xxx_misc_masked_write(chip, addr,
+				HSED_EN_MASK, enable ? HSED_EN_MASK : 0);
+			if (rc < 0)
+				pr_err("Enable HSED BIAS failed rc=%d\n", rc);
+			break;
+		default:
+			/* Functionality not supported */
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&pm8xxx_misc_chips_lock, flags);
+
+	return rc;
+}
+EXPORT_SYMBOL(pm8xxx_hsed_bias_control);
+
 static int __devinit pm8xxx_misc_probe(struct platform_device *pdev)
 {
 	const struct pm8xxx_misc_platform_data *pdata = pdev->dev.platform_data;
diff --git a/drivers/mfd/pm8xxx-spk.c b/drivers/mfd/pm8xxx-spk.c
new file mode 100644
index 0000000..297ddfa
--- /dev/null
+++ b/drivers/mfd/pm8xxx-spk.c
@@ -0,0 +1,279 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+#include <linux/debugfs.h>
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/spk.h>
+
+#define PM8XXX_SPK_CTL1_REG_OFF		0
+#define PM8XXX_SPK_TEST_REG_1_OFF	1
+#define PM8XXX_SPK_TEST_REG_2_OFF	2
+
+#define PM8XXX_SPK_BANK_SEL		4
+#define PM8XXX_SPK_BANK_WRITE		0x80
+#define PM8XXX_SPK_BANK_VAL_MASK	0xF
+
+#define BOOST_6DB_GAIN_EN_MASK		0x8
+#define VSEL_LD0_1P1			0x0
+#define VSEL_LD0_1P2			0x2
+#define VSEL_LD0_1P0			0x4
+
+#define PWM_EN_MASK			0xF
+#define PM8XXX_SPK_TEST_REG_1_BANKS	8
+#define PM8XXX_SPK_TEST_REG_2_BANKS	2
+
+#define PM8XXX_SPK_GAIN			0x5
+#define PM8XXX_ADD_EN			0x1
+
+struct pm8xxx_spk_chip {
+	struct list_head                        link;
+	struct pm8xxx_spk_platform_data		pdata;
+	struct device                           *dev;
+	enum pm8xxx_version                     version;
+	struct mutex				spk_mutex;
+	u16					base;
+	u16					end;
+};
+
+static struct pm8xxx_spk_chip *the_spk_chip;
+
+static inline bool spk_defined(void)
+{
+	if (the_spk_chip == NULL || IS_ERR(the_spk_chip))
+		return false;
+	return true;
+}
+
+static int pm8xxx_spk_bank_write(u16 reg, u16 bank, u8 val)
+{
+	int rc = 0;
+	u8 bank_val = PM8XXX_SPK_BANK_WRITE | (bank << PM8XXX_SPK_BANK_SEL);
+
+	bank_val |= (val & PM8XXX_SPK_BANK_VAL_MASK);
+	mutex_lock(&the_spk_chip->spk_mutex);
+	rc = pm8xxx_writeb(the_spk_chip->dev->parent, reg, bank_val);
+	if (rc)
+		pr_err("pm8xxx_writeb(): rc=%d\n", rc);
+	mutex_unlock(&the_spk_chip->spk_mutex);
+	return rc;
+}
+
+
+static int pm8xxx_spk_read(u16 addr)
+{
+	int rc = 0;
+	u8 val = 0;
+
+	mutex_lock(&the_spk_chip->spk_mutex);
+	rc = pm8xxx_readb(the_spk_chip->dev->parent,
+			the_spk_chip->base + addr, &val);
+	if (rc) {
+		pr_err("pm8xxx_spk_readb() failed: rc=%d\n", rc);
+		val = rc;
+	}
+	mutex_unlock(&the_spk_chip->spk_mutex);
+
+	return val;
+}
+
+static int pm8xxx_spk_write(u16 addr, u8 val)
+{
+	int rc = 0;
+
+	mutex_lock(&the_spk_chip->spk_mutex);
+	rc = pm8xxx_writeb(the_spk_chip->dev->parent,
+			the_spk_chip->base + addr, val);
+	if (rc)
+		pr_err("pm8xxx_writeb() failed: rc=%d\n", rc);
+	mutex_unlock(&the_spk_chip->spk_mutex);
+	return rc;
+}
+
+int pm8xxx_spk_mute(bool mute)
+{
+	u8 val = 0;
+	int ret = 0;
+	if (spk_defined() == false) {
+		pr_err("Invalid spk handle or no spk_chip\n");
+		return -ENODEV;
+	}
+
+	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;
+}
+EXPORT_SYMBOL_GPL(pm8xxx_spk_mute);
+
+int pm8xxx_spk_gain(u8 gain)
+{
+	u8 val;
+	int ret = 0;
+
+	if (spk_defined() == false) {
+		pr_err("Invalid spk handle or no spk_chip\n");
+		return -ENODEV;
+	}
+
+	val = pm8xxx_spk_read(PM8XXX_SPK_CTL1_REG_OFF);
+	if (val < 0)
+		return val;
+	val |= (gain << 4);
+	ret = pm8xxx_spk_write(PM8XXX_SPK_CTL1_REG_OFF, val);
+	if (!ret) {
+		pm8xxx_spk_bank_write(the_spk_chip->base
+			+ PM8XXX_SPK_TEST_REG_1_OFF,
+			0, BOOST_6DB_GAIN_EN_MASK | VSEL_LD0_1P2);
+	}
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pm8xxx_spk_gain);
+
+int pm8xxx_spk_enable(int enable)
+{
+	int val = 0;
+	u16 addr;
+	int ret = 0;
+
+	if (spk_defined() == false) {
+		pr_err("Invalid spk handle or no spk_chip\n");
+		return -ENODEV;
+	}
+
+	addr = the_spk_chip->base + PM8XXX_SPK_TEST_REG_1_OFF;
+	val = pm8xxx_spk_read(PM8XXX_SPK_CTL1_REG_OFF);
+	if (val < 0)
+		return val;
+	val |= (enable << 3);
+	ret = pm8xxx_spk_write(PM8XXX_SPK_CTL1_REG_OFF, val);
+	if (!ret)
+		ret = pm8xxx_spk_bank_write(addr, 6, PWM_EN_MASK);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pm8xxx_spk_enable);
+
+static int pm8xxx_spk_config(void)
+{
+	u16 addr;
+	int ret = 0;
+
+	if (spk_defined() == false) {
+		pr_err("Invalid spk handle or no spk_chip\n");
+		return -ENODEV;
+	}
+
+	addr = the_spk_chip->base + PM8XXX_SPK_TEST_REG_1_OFF;
+	ret = pm8xxx_spk_bank_write(addr, 6, PWM_EN_MASK & 0);
+	if (!ret)
+		ret = pm8xxx_spk_gain(PM8XXX_SPK_GAIN);
+	return ret;
+}
+
+static int __devinit pm8xxx_spk_probe(struct platform_device *pdev)
+{
+	const struct pm8xxx_spk_platform_data *pdata = pdev->dev.platform_data;
+	int ret = 0;
+
+	if (!pdata) {
+		pr_err("missing platform data\n");
+		return -EINVAL;
+	}
+
+	the_spk_chip = kzalloc(sizeof(struct pm8xxx_spk_chip), GFP_KERNEL);
+	if (the_spk_chip == NULL) {
+		pr_err("kzalloc() failed.\n");
+		return -ENOMEM;
+	}
+
+	mutex_init(&the_spk_chip->spk_mutex);
+
+	the_spk_chip->dev = &pdev->dev;
+	the_spk_chip->version = pm8xxx_get_version(the_spk_chip->dev->parent);
+	switch (pm8xxx_get_version(the_spk_chip->dev->parent)) {
+	case PM8XXX_VERSION_8038:
+		break;
+	default:
+		ret = -ENODEV;
+		goto err_handle;
+	}
+
+	memcpy(&(the_spk_chip->pdata), pdata,
+			sizeof(struct pm8xxx_spk_platform_data));
+
+	the_spk_chip->base = pdev->resource[0].start;
+	the_spk_chip->end = pdev->resource[0].end;
+
+	if (the_spk_chip->pdata.spk_add_enable) {
+		int val;
+		val = pm8xxx_spk_read(PM8XXX_SPK_CTL1_REG_OFF);
+		if (val < 0) {
+			ret = val;
+			goto err_handle;
+		}
+		val |= (the_spk_chip->pdata.spk_add_enable & PM8XXX_ADD_EN);
+		ret = pm8xxx_spk_write(PM8XXX_SPK_CTL1_REG_OFF, val);
+		if (ret < 0)
+			goto err_handle;
+	}
+	return pm8xxx_spk_config();
+err_handle:
+	pr_err("pm8xxx_spk_probe failed."
+			"Audio unavailable on speaker.\n");
+	mutex_destroy(&the_spk_chip->spk_mutex);
+	kfree(the_spk_chip);
+	return ret;
+}
+
+static int __devexit pm8xxx_spk_remove(struct platform_device *pdev)
+{
+	if (spk_defined() == false) {
+		pr_err("Invalid spk handle or no spk_chip\n");
+		return -ENODEV;
+	}
+	mutex_destroy(&the_spk_chip->spk_mutex);
+	kfree(the_spk_chip);
+	return 0;
+}
+
+static struct platform_driver pm8xxx_spk_driver = {
+	.probe		= pm8xxx_spk_probe,
+	.remove		= __devexit_p(pm8xxx_spk_remove),
+	.driver		= {
+		.name = PM8XXX_SPK_DEV_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pm8xxx_spk_init(void)
+{
+	return platform_driver_register(&pm8xxx_spk_driver);
+}
+subsys_initcall(pm8xxx_spk_init);
+
+static void __exit pm8xxx_spk_exit(void)
+{
+	platform_driver_unregister(&pm8xxx_spk_driver);
+}
+module_exit(pm8xxx_spk_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PM8XXX SPK driver");
+MODULE_ALIAS("platform:" PM8XXX_SPK_DEV_NAME);
diff --git a/drivers/misc/tsif.c b/drivers/misc/tsif.c
index 42faa07..ace5b0c 100644
--- a/drivers/misc/tsif.c
+++ b/drivers/misc/tsif.c
@@ -1,7 +1,7 @@
 /*
  * TSIF Driver
  *
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * 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
@@ -680,7 +680,7 @@
 		tsif_device->state = tsif_state_flushing;
 		while (tsif_device->xfer[0].busy ||
 		       tsif_device->xfer[1].busy) {
-			msm_dmov_flush(tsif_device->dma);
+			msm_dmov_flush(tsif_device->dma, 1);
 			msleep(10);
 		}
 	}
@@ -760,7 +760,7 @@
 			      offsetof(struct tsif_dmov_cmd, box_ptr));
 		hdr->complete_func = tsif_dmov_complete_func;
 	}
-	msm_dmov_flush(tsif_device->dma);
+	msm_dmov_flush(tsif_device->dma, 1);
 	return 0;
 err:
 	dev_err(&tsif_device->pdev->dev, "Failed to allocate DMA buffers\n");
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 843a707..925c032 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -232,6 +232,11 @@
 {
 	init_completion(&mrq->completion);
 	mrq->done = mmc_wait_done;
+	if (mmc_card_removed(host->card)) {
+		mrq->cmd->error = -ENOMEDIUM;
+		complete(&mrq->completion);
+		return;
+	}
 	mmc_start_request(host, mrq);
 }
 
diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c
index 92990b9..f9999c5 100644
--- a/drivers/mmc/core/quirks.c
+++ b/drivers/mmc/core/quirks.c
@@ -29,6 +29,18 @@
 #define SDIO_DEVICE_ID_MSM_WCN1314	0x2881
 #endif
 
+#ifndef SDIO_VENDOR_ID_MSM_QCA
+#define SDIO_VENDOR_ID_MSM_QCA		0x271
+#endif
+
+#ifndef SDIO_DEVICE_ID_MSM_QCA_AR6003_1
+#define SDIO_DEVICE_ID_MSM_QCA_AR6003_1	0x300
+#endif
+
+#ifndef SDIO_DEVICE_ID_MSM_QCA_AR6003_2
+#define SDIO_DEVICE_ID_MSM_QCA_AR6003_2	0x301
+#endif
+
 /*
  * This hook just adds a quirk for all sdio devices
  */
@@ -51,6 +63,12 @@
 	SDIO_FIXUP(SDIO_VENDOR_ID_MSM, SDIO_DEVICE_ID_MSM_WCN1314,
 		   remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
 
+	SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6003_1,
+		   remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+
+	SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6003_2,
+		   remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+
 	SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
 		   add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
 
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 39e6ce3..13fe3e6 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -707,7 +707,7 @@
 	}
 
 	if (!err && host->sdio_irqs)
-		mmc_signal_sdio_irq(host);
+		wake_up_process(host->sdio_irq_thread);
 	mmc_release_host(host);
 
 	/*
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 28505636..c442907 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -27,10 +27,23 @@
 
 #include "sdio_ops.h"
 
-static int process_sdio_pending_irqs(struct mmc_card *card)
+static int process_sdio_pending_irqs(struct mmc_host *host)
 {
+	struct mmc_card *card = host->card;
 	int i, ret, count;
 	unsigned char pending;
+	struct sdio_func *func;
+
+	/*
+	 * Optimization, if there is only 1 function interrupt registered
+	 * and we know an IRQ was signaled then call irq handler directly.
+	 * Otherwise do the full probe.
+	 */
+	func = card->sdio_single_irq;
+	if (func && host->sdio_irq_pending) {
+		func->irq_handler(func);
+		return 1;
+	}
 
 	ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending);
 	if (ret) {
@@ -42,7 +55,7 @@
 	count = 0;
 	for (i = 1; i <= 7; i++) {
 		if (pending & (1 << i)) {
-			struct sdio_func *func = card->sdio_func[i - 1];
+			func = card->sdio_func[i - 1];
 			if (!func) {
 				printk(KERN_WARNING "%s: pending IRQ for "
 					"non-existent function\n",
@@ -104,7 +117,8 @@
 		ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort);
 		if (ret)
 			break;
-		ret = process_sdio_pending_irqs(host->card);
+		ret = process_sdio_pending_irqs(host);
+		host->sdio_irq_pending = false;
 		mmc_release_host(host);
 
 		/*
@@ -192,6 +206,24 @@
 	return 0;
 }
 
+/* If there is only 1 function registered set sdio_single_irq */
+static void sdio_single_irq_set(struct mmc_card *card)
+{
+	struct sdio_func *func;
+	int i;
+
+	card->sdio_single_irq = NULL;
+	if ((card->host->caps & MMC_CAP_SDIO_IRQ) &&
+			card->host->sdio_irqs == 1)
+		for (i = 0; i < card->sdio_funcs; i++) {
+			func = card->sdio_func[i];
+			if (func && func->irq_handler) {
+				card->sdio_single_irq = func;
+				break;
+			}
+		}
+}
+
 /**
  *	sdio_claim_irq - claim the IRQ for a SDIO function
  *	@func: SDIO function
@@ -233,6 +265,7 @@
 	ret = sdio_card_irq_get(func->card);
 	if (ret)
 		func->irq_handler = NULL;
+	sdio_single_irq_set(func->card);
 
 	return ret;
 }
@@ -257,6 +290,7 @@
 	if (func->irq_handler) {
 		func->irq_handler = NULL;
 		sdio_card_irq_put(func->card);
+		sdio_single_irq_set(func->card);
 	}
 
 	ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 0e096eb..0d11dca 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -79,6 +79,9 @@
 static int  msmsdcc_dbg_init(void);
 #endif
 
+static int msmsdcc_prep_xfer(struct msmsdcc_host *host, struct mmc_data
+			     *data);
+
 static u64 dma_mask = DMA_BIT_MASK(32);
 static unsigned int msmsdcc_pwrsave = 1;
 
@@ -150,6 +153,7 @@
 static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
 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 inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
 {
@@ -481,8 +485,9 @@
 		if (!mrq->data->error)
 			mrq->data->error = -EIO;
 	}
-	dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
-		     host->dma.dir);
+	if (!mrq->data->host_cookie)
+		dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
+			     host->dma.num_ents, host->dma.dir);
 
 	if (host->curr.user_pages) {
 		struct scatterlist *sg = host->dma.sg;
@@ -648,9 +653,9 @@
 	}
 
 	/* Unmap sg buffers */
-	dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
-			 host->sps.dir);
-
+	if (!mrq->data->host_cookie)
+		dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
+			     host->sps.num_ents, host->sps.dir);
 	host->sps.sg = NULL;
 	host->sps.busy = 0;
 
@@ -719,8 +724,9 @@
 		mrq->data->error = -EIO;
 
 	/* Unmap sg buffers */
-	dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
-			 host->sps.dir);
+	if (!mrq->data->host_cookie)
+		dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
+			     host->sps.num_ents, host->sps.dir);
 
 	host->sps.sg = NULL;
 	host->sps.busy = 0;
@@ -815,15 +821,13 @@
 	else
 		host->dma.dir = DMA_TO_DEVICE;
 
-	n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
-			host->dma.num_ents, host->dma.dir);
-
-	if (n != host->dma.num_ents) {
-		pr_err("%s: Unable to map in all sg elements\n",
-		       mmc_hostname(host->mmc));
-		host->dma.sg = NULL;
-		host->dma.num_ents = 0;
-		return -ENOMEM;
+	if (!data->host_cookie) {
+		n = msmsdcc_prep_xfer(host, data);
+		if (unlikely(n < 0)) {
+			host->dma.sg = NULL;
+			host->dma.num_ents = 0;
+			return -ENOMEM;
+		}
 	}
 
 	/* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
@@ -892,8 +896,9 @@
 
 unmap:
 	if (err) {
-		dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
-				host->dma.num_ents, host->dma.dir);
+		if (!data->host_cookie)
+			dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
+				     host->dma.num_ents, host->dma.dir);
 		pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
 				mmc_hostname(host->mmc), err);
 	}
@@ -901,6 +906,44 @@
 	return err;
 }
 
+static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
+			     struct mmc_data *data)
+{
+	int rc = 0;
+	unsigned int dir;
+
+	/* Prevent memory corruption */
+	BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
+
+	if (data->flags & MMC_DATA_READ)
+		dir = DMA_FROM_DEVICE;
+	else
+		dir = DMA_TO_DEVICE;
+
+	/* Make sg buffers DMA ready */
+	rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+			dir);
+
+	if (unlikely(rc != data->sg_len)) {
+		pr_err("%s: Unable to map in all sg elements, rc=%d\n",
+		       mmc_hostname(host->mmc), rc);
+		rc = -ENOMEM;
+		goto dma_map_err;
+	}
+
+	pr_debug("%s: %s: %s: sg_len=%d\n",
+		mmc_hostname(host->mmc), __func__,
+		dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
+		data->sg_len);
+
+	goto out;
+
+dma_map_err:
+	dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+		     data->flags);
+out:
+	return rc;
+}
 #ifdef CONFIG_MMC_MSM_SPS_SUPPORT
 /**
  * Submits data transfer request to SPS driver
@@ -915,7 +958,7 @@
  * @return 0 if success else negative value
  */
 static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
-				struct mmc_data *data)
+				  struct mmc_data *data)
 {
 	int rc = 0;
 	u32 flags;
@@ -924,9 +967,6 @@
 	struct scatterlist *sg = data->sg;
 	struct sps_pipe *sps_pipe_handle;
 
-	/* Prevent memory corruption */
-	BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
-
 	host->sps.sg = data->sg;
 	host->sps.num_ents = data->sg_len;
 	host->sps.xfer_req_cnt = 0;
@@ -938,24 +978,15 @@
 		sps_pipe_handle = host->sps.cons.pipe_handle;
 	}
 
-	/* Make sg buffers DMA ready */
-	rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
-			host->sps.dir);
-
-	if (rc != data->sg_len) {
-		pr_err("%s: Unable to map in all sg elements, rc=%d\n",
-		       mmc_hostname(host->mmc), rc);
-		host->sps.sg = NULL;
-		host->sps.num_ents = 0;
-		rc = -ENOMEM;
-		goto dma_map_err;
+	if (!data->host_cookie) {
+		rc = msmsdcc_prep_xfer(host, data);
+		if (unlikely(rc < 0)) {
+			host->dma.sg = NULL;
+			host->dma.num_ents = 0;
+			goto out;
+		}
 	}
 
-	pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
-		mmc_hostname(host->mmc), __func__,
-		host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
-		(u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
-
 	for (i = 0; i < data->sg_len; i++) {
 		/*
 		 * Check if this is the last buffer to transfer?
@@ -992,8 +1023,9 @@
 
 dma_map_err:
 	/* unmap sg buffers */
-	dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
-			host->sps.dir);
+	if (!data->host_cookie)
+		dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
+			     host->sps.num_ents, host->sps.dir);
 out:
 	return rc;
 }
@@ -1020,11 +1052,8 @@
 	if (/*interrupt*/0)
 		*c |= MCI_CPSM_INTERRUPT;
 
-	if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
-		cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
-		cmd->opcode == MMC_WRITE_BLOCK ||
-		cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
-		cmd->opcode == SD_IO_RW_EXTENDED)
+	/* DAT_CMD bit should be set for all ADTC */
+	if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
 		*c |= MCI_CSPM_DATCMD;
 
 	/* Check if AUTO CMD19 is required or not? */
@@ -1556,10 +1585,17 @@
 	struct mmc_command *cmd = host->curr.cmd;
 
 	host->curr.cmd = NULL;
-	cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
-	cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
-	cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
-	cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
+	if (mmc_resp_type(cmd))
+		cmd->resp[0] = readl_relaxed(host->base + MMCIRESPONSE0);
+	/*
+	 * Read rest of the response registers only if
+	 * long response is expected for this command
+	 */
+	if (mmc_resp_type(cmd) & MMC_RSP_136) {
+		cmd->resp[1] = readl_relaxed(host->base + MMCIRESPONSE1);
+		cmd->resp[2] = readl_relaxed(host->base + MMCIRESPONSE2);
+		cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
+	}
 
 	if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
 		pr_debug("%s: CMD%d: Command timeout\n",
@@ -1576,8 +1612,7 @@
 	if (!cmd->data || cmd->error) {
 		if (host->curr.data && host->dma.sg &&
 			host->is_dma_mode)
-			msm_dmov_stop_cmd(host->dma.channel,
-					  &host->dma.hdr, 0);
+			msm_dmov_flush(host->dma.channel, 0);
 		else if (host->curr.data && host->sps.sg &&
 			host->is_sps_mode){
 			/* Stop current SPS transfer */
@@ -1730,8 +1765,7 @@
 				msmsdcc_data_err(host, data, status);
 				host->curr.data_xfered = 0;
 				if (host->dma.sg && host->is_dma_mode)
-					msm_dmov_stop_cmd(host->dma.channel,
-							  &host->dma.hdr, 0);
+					msm_dmov_flush(host->dma.channel, 0);
 				else if (host->sps.sg && host->is_sps_mode) {
 					/* Stop current SPS transfer */
 					msmsdcc_sps_exit_curr_xfer(host);
@@ -1828,6 +1862,63 @@
 }
 
 static void
+msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
+		bool is_first_request)
+{
+	struct msmsdcc_host *host = mmc_priv(mmc);
+	struct mmc_data *data = mrq->data;
+	int rc = 0;
+
+	if (unlikely(!data)) {
+		pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
+		       __func__);
+		return;
+	}
+	if (unlikely(data->host_cookie)) {
+		/* Very wrong */
+		data->host_cookie = 0;
+		pr_err("%s: %s Request reposted for prepare\n",
+		       mmc_hostname(mmc), __func__);
+		return;
+	}
+
+	if (!msmsdcc_is_dma_possible(host, data))
+		return;
+
+	rc = msmsdcc_prep_xfer(host, data);
+	if (unlikely(rc < 0)) {
+		data->host_cookie = 0;
+		return;
+	}
+
+	data->host_cookie = 1;
+}
+
+static void
+msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
+{
+	struct msmsdcc_host *host = mmc_priv(mmc);
+	unsigned int dir;
+	struct mmc_data *data = mrq->data;
+
+	if (unlikely(!data)) {
+		pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
+		       __func__);
+		return;
+	}
+	if (data->flags & MMC_DATA_READ)
+		dir = DMA_FROM_DEVICE;
+	else
+		dir = DMA_TO_DEVICE;
+
+	if (data->host_cookie)
+		dma_unmap_sg(mmc_dev(host->mmc), data->sg,
+			     data->sg_len, dir);
+
+	data->host_cookie = 0;
+}
+
+static void
 msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
 {
 	if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
@@ -1845,7 +1936,7 @@
 msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
 {
 	struct msmsdcc_host *host = mmc_priv(mmc);
-	unsigned long		flags;
+	unsigned long		flags, timeout;
 
 	/*
 	 * Get the SDIO AL client out of LPM.
@@ -1861,10 +1952,6 @@
 	}
 
 	spin_lock_irqsave(&host->lock, flags);
-	WARN(host->curr.mrq, "Request in progress\n");
-	WARN(!host->pwr, "SDCC power is turned off\n");
-	WARN(!host->clks_on, "SDCC clocks are turned off\n");
-	WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
 
 	if (host->eject) {
 		if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
@@ -1880,11 +1967,41 @@
 	}
 
 	/*
-	 * Kick the software command timeout timer here.
-	 * Timer expires in 10 secs.
+	 * Don't start the request if SDCC is not in proper state to handle it
+	 */
+	if (!host->pwr || !host->clks_on || host->sdcc_irq_disabled) {
+		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);
+		msmsdcc_dump_sdcc_state(host);
+		mrq->cmd->error = -EIO;
+		if (mrq->data) {
+			mrq->data->error = -EIO;
+			mrq->data->bytes_xfered = 0;
+		}
+		spin_unlock_irqrestore(&host->lock, flags);
+		mmc_request_done(mmc, mrq);
+		return;
+	}
+
+	WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
+	     " other request (CMD%d) is in progress\n",
+	     mmc_hostname(host->mmc), __func__,
+	     mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
+
+	/*
+	 * Set timeout value to 10 secs (or more in case of buggy cards)
+	 */
+	if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
+		timeout = 20000;
+	else
+		timeout = MSM_MMC_REQ_TIMEOUT;
+	/*
+	 * Kick the software request timeout timer here with the timeout
+	 * value identified above
 	 */
 	mod_timer(&host->req_tout_timer,
-			(jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
+			(jiffies + msecs_to_jiffies(timeout)));
 
 	host->curr.mrq = mrq;
 	if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
@@ -2829,17 +2946,39 @@
 }
 
 #ifdef CONFIG_PM_RUNTIME
+static void msmsdcc_print_rpm_info(struct msmsdcc_host *host)
+{
+	struct device *dev = mmc_dev(host->mmc);
+
+	pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
+		" is_suspended=%d, disable_depth=%d, runtime_error=%d,"
+		" request_pending=%d, request=%d\n",
+		mmc_hostname(host->mmc), dev->power.runtime_status,
+		atomic_read(&dev->power.usage_count),
+		dev->power.is_suspended, dev->power.disable_depth,
+		dev->power.runtime_error, dev->power.request_pending,
+		dev->power.request);
+}
+
 static int msmsdcc_enable(struct mmc_host *mmc)
 {
-	int rc;
+	int rc = 0;
 	struct device *dev = mmc->parent;
 	struct msmsdcc_host *host = mmc_priv(mmc);
 
 	msmsdcc_pm_qos_update_latency(host, 1);
 
-	if (mmc->card && mmc_card_sdio(mmc->card) && host->is_resumed)
+	if (mmc->card && mmc_card_sdio(mmc->card))
 		return 0;
 
+	if (host->sdcc_suspended && host->pending_resume &&
+			!pm_runtime_suspended(dev)) {
+		host->pending_resume = false;
+		pm_runtime_get_noresume(dev);
+		rc = msmsdcc_runtime_resume(dev);
+		goto out;
+	}
+
 	if (dev->power.runtime_status == RPM_SUSPENDING) {
 		if (mmc->suspend_task == current) {
 			pm_runtime_get_noresume(dev);
@@ -2849,14 +2988,14 @@
 
 	rc = pm_runtime_get_sync(dev);
 
+out:
 	if (rc < 0) {
 		pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
 				__func__, rc);
+		msmsdcc_print_rpm_info(host);
 		return rc;
 	}
 
-	host->is_resumed = true;
-out:
 	return 0;
 }
 
@@ -2875,22 +3014,42 @@
 
 	rc = pm_runtime_put_sync(mmc->parent);
 
-	if (rc < 0)
+	/*
+	 * Ignore -EAGAIN as that is not fatal, it means that
+	 * either runtime usage count is non-zero or the runtime
+	 * pm itself is disabled or not in proper state to process
+	 * idle notification.
+	 */
+	if (rc < 0 && (rc != -EAGAIN)) {
 		pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
 				__func__, rc);
-	else
-		host->is_resumed = false;
+		msmsdcc_print_rpm_info(host);
+		return rc;
+	}
 
-	return rc;
+	return 0;
 }
 #else
+static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
+
 static int msmsdcc_enable(struct mmc_host *mmc)
 {
+	struct device *dev = mmc->parent;
 	struct msmsdcc_host *host = mmc_priv(mmc);
 	unsigned long flags;
+	int rc = 0;
 
 	msmsdcc_pm_qos_update_latency(host, 1);
 
+	if (mmc->card && mmc_card_sdio(mmc->card))
+		return 0;
+
+	if (host->sdcc_suspended && host->pending_resume) {
+		host->pending_resume = false;
+		rc = msmsdcc_runtime_resume(dev);
+		goto out;
+	}
+
 	mutex_lock(&host->clk_mutex);
 	spin_lock_irqsave(&host->lock, flags);
 	if (!host->clks_on) {
@@ -2902,6 +3061,13 @@
 	spin_unlock_irqrestore(&host->lock, flags);
 	mutex_unlock(&host->clk_mutex);
 
+out:
+	if (rc < 0) {
+		pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
+				__func__, rc);
+		return rc;
+	}
+
 	return 0;
 }
 
@@ -3481,6 +3647,8 @@
 static const struct mmc_host_ops msmsdcc_ops = {
 	.enable		= msmsdcc_enable,
 	.disable	= msmsdcc_disable,
+	.pre_req        = msmsdcc_pre_req,
+	.post_req       = msmsdcc_post_req,
 	.request	= msmsdcc_request,
 	.set_ios	= msmsdcc_set_ios,
 	.get_ro		= msmsdcc_get_ro,
@@ -4121,7 +4289,7 @@
 				mmc_hostname(host->mmc), host->dma.busy,
 				host->dma.channel, host->dma.crci);
 		else if (host->is_sps_mode) {
-			if (host->sps.busy)
+			if (host->sps.busy && host->clks_on)
 				msmsdcc_print_regs("SDCC-DML", host->dml_base,
 						   host->dml_memres->start,
 						   16);
@@ -4139,6 +4307,7 @@
 		mmc_hostname(host->mmc), host->curr.got_dataend,
 		host->prog_enable, host->curr.wait_for_auto_prog_done,
 		host->curr.got_auto_prog_done);
+	msmsdcc_print_rpm_info(host);
 }
 
 static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
@@ -4169,8 +4338,7 @@
 				mrq->data->error = -ETIMEDOUT;
 			host->curr.data_xfered = 0;
 			if (host->dma.sg && host->is_dma_mode) {
-				msm_dmov_stop_cmd(host->dma.channel,
-						&host->dma.hdr, 0);
+				msm_dmov_flush(host->dma.channel, 0);
 			} else if (host->sps.sg && host->is_sps_mode) {
 				/* Stop current SPS transfer */
 				msmsdcc_sps_exit_curr_xfer(host);
@@ -5157,23 +5325,8 @@
 	if (host->plat->status_irq)
 		disable_irq(host->plat->status_irq);
 
-	if (!pm_runtime_suspended(dev)) {
-		if (!(mmc->card && mmc_card_sdio(mmc->card))) {
-			/*
-			 * decrement power.usage_counter if it's
-			 * not zero earlier
-			 */
-			pm_runtime_put_noidle(dev);
-			rc = pm_runtime_suspend(dev);
-		}
-
-		/*
-		 * if device runtime PM status is still not suspended
-		 * then perform suspend here.
-		 */
-		if (!pm_runtime_suspended(dev))
-			rc = msmsdcc_runtime_suspend(dev);
-	}
+	if (!pm_runtime_suspended(dev))
+		rc = msmsdcc_runtime_suspend(dev);
 
 	return rc;
 }
@@ -5211,8 +5364,11 @@
 	if (host->plat->is_sdio_al_client)
 		return 0;
 
-	if (!pm_runtime_suspended(dev))
+	if (mmc->card && mmc_card_sdio(mmc->card))
 		rc = msmsdcc_runtime_resume(dev);
+	else
+		host->pending_resume = true;
+
 	if (host->plat->status_irq) {
 		msmsdcc_check_status((unsigned long)host);
 		enable_irq(host->plat->status_irq);
@@ -5222,12 +5378,30 @@
 }
 
 #else
-#define msmsdcc_runtime_suspend NULL
-#define msmsdcc_runtime_resume NULL
-#define msmsdcc_runtime_idle NULL
-#define msmsdcc_pm_suspend NULL
-#define msmsdcc_pm_resume NULL
-#define msmsdcc_suspend_noirq NULL
+static int msmsdcc_runtime_suspend(struct device *dev)
+{
+	return 0;
+}
+static int msmsdcc_runtime_idle(struct device *dev)
+{
+	return 0;
+}
+static int msmsdcc_pm_suspend(struct device *dev)
+{
+	return 0;
+}
+static int msmsdcc_pm_resume(struct device *dev)
+{
+	return 0;
+}
+static int msmsdcc_suspend_noirq(struct device *dev)
+{
+	return 0;
+}
+static int msmsdcc_runtime_resume(struct device *dev)
+{
+	return 0;
+}
 #endif
 
 static const struct dev_pm_ops msmsdcc_dev_pm_ops = {
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 50477da..e6bd16c 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -212,10 +212,7 @@
 
 #define MSM_MMC_IDLE_TIMEOUT	5000 /* msecs */
 
-/*
- * Set the request timeout to 10secs to allow
- * bad cards/controller to respond.
- */
+/* Set the request timeout to 10secs */
 #define MSM_MMC_REQ_TIMEOUT	10000 /* msecs */
 #define MSM_MMC_DISABLE_TIMEOUT        200 /* msecs */
 
@@ -384,7 +381,6 @@
 	unsigned int	dummy_52_needed;
 	unsigned int	dummy_52_sent;
 
-	bool		is_resumed;
 	struct wake_lock	sdio_wlock;
 	struct wake_lock	sdio_suspend_wlock;
 	struct timer_list req_tout_timer;
@@ -401,6 +397,7 @@
 	bool sdcc_suspended;
 	bool sdio_wakeupirq_disabled;
 	struct mutex clk_mutex;
+	bool pending_resume;
 };
 
 int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave);
diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c
index 0bf972a..31dabd5 100644
--- a/drivers/net/ks8851.c
+++ b/drivers/net/ks8851.c
@@ -622,10 +622,8 @@
 	netif_dbg(ks, intr, ks->netdev,
 		  "%s: status 0x%04x\n", __func__, status);
 
-	if (status & IRQ_LCI) {
-		/* should do something about checking link status */
+	if (status & IRQ_LCI)
 		handled |= IRQ_LCI;
-	}
 
 	if (status & IRQ_LDI) {
 		u16 pmecr = ks8851_rdreg16(ks, KS_PMECR);
@@ -688,6 +686,9 @@
 
 	mutex_unlock(&ks->lock);
 
+	if (status & IRQ_LCI)
+		mii_check_link(&ks->mii);
+
 	if (status & IRQ_TXI)
 		netif_wake_queue(ks->netdev);
 
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index b83e871..bb16fbb 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -283,13 +283,15 @@
 	---help---
 	  A driver for Qualcomm WLAN SDIO Libra chipset.
 
-config ATH6K_LEGACY
-	tristate "QCA AR6003 wlan SDIO driver"
+config ATH6K_LEGACY_EXT
+	tristate "QCA AR6003 wlan SDIO driver - External"
 	depends on MMC_MSM && WLAN
 	select WIRELESS_EXT
 	select WEXT_PRIV
 	---help---
-	This module adds support for wireless adapters based on QCA AR6003 chipset running over SDIO.
+	  This module adds support for wireless adapters based on QCA AR6003 chipset
+	  running over SDIO. Driver is built outside of kernel tree, this config
+	  only enables configurations required for QCA AR6003 wlan driver.
 
 config WCNSS_CORE
 	tristate "Qualcomm WCNSS CORE driver"
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 39bcf16..ea5b851 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -697,7 +697,7 @@
 
 	for (i = 0; total < prop->length; total += l, p += l) {
 		l = strlen(p) + 1;
-		if ((*p != 0) && (i++ == index)) {
+		if (i++ == index) {
 			*output = p;
 			return 0;
 		}
@@ -735,11 +735,9 @@
 
 	p = prop->value;
 
-	for (i = 0; total < prop->length; total += l, p += l) {
+	for (i = 0; total < prop->length; total += l, p += l, i++)
 		l = strlen(p) + 1;
-		if (*p != 0)
-			i++;
-	}
+
 	return i;
 }
 EXPORT_SYMBOL_GPL(of_property_count_strings);
diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c
index 9059603..3007662 100644
--- a/drivers/of/gpio.c
+++ b/drivers/of/gpio.c
@@ -21,8 +21,9 @@
 #include <linux/slab.h>
 
 /**
- * of_get_gpio_flags - Get a GPIO number and flags to use with GPIO API
+ * of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API
  * @np:		device node to get GPIO from
+ * @propname:	property name containing gpio specifier(s)
  * @index:	index of the GPIO
  * @flags:	a flags pointer to fill in
  *
@@ -30,8 +31,8 @@
  * value on the error condition. If @flags is not NULL the function also fills
  * in flags for the GPIO.
  */
-int of_get_gpio_flags(struct device_node *np, int index,
-		      enum of_gpio_flags *flags)
+int of_get_named_gpio_flags(struct device_node *np, const char *propname,
+                           int index, enum of_gpio_flags *flags)
 {
 	int ret;
 	struct device_node *gpio_np;
@@ -40,7 +41,7 @@
 	const void *gpio_spec;
 	const __be32 *gpio_cells;
 
-	ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index,
+	ret = of_parse_phandles_with_args(np, propname, "#gpio-cells", index,
 					  &gpio_np, &gpio_spec);
 	if (ret) {
 		pr_debug("%s: can't parse gpios property\n", __func__);
@@ -79,7 +80,7 @@
 	pr_debug("%s exited with status %d\n", __func__, ret);
 	return ret;
 }
-EXPORT_SYMBOL(of_get_gpio_flags);
+EXPORT_SYMBOL(of_get_named_gpio_flags);
 
 /**
  * of_gpio_count - Count GPIOs for a device
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index f2981bf..d7edb82 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.c
@@ -20,7 +20,6 @@
 
 #include "bam.h"
 #include "sps_bam.h"
-#include "spsi.h"
 
 /**
  *  Valid BAM Hardware version.
@@ -823,9 +822,46 @@
 }
 
 /**
+ * Output BAM register content
+ * including the TEST_BUS register content under
+ * different TEST_BUS_SEL values.
+ */
+static void bam_output_register_content(void *base)
+{
+	u32 num_pipes;
+	u32 test_bus_selection[] = {0x1, 0x2, 0x3, 0x4, 0xD, 0x10,
+			0x41, 0x42, 0x43, 0x44, 0x45, 0x46};
+	u32 i;
+	u32 size = sizeof(test_bus_selection) / sizeof(u32);
+
+	for (i = 0; i < size; i++) {
+		bam_write_reg_field(base, TEST_BUS_SEL, BAM_TESTBUS_SEL,
+					test_bus_selection[i]);
+
+		SPS_INFO("sps:bam 0x%x(va);BAM_TEST_BUS_REG is"
+			"0x%x when BAM_TEST_BUS_SEL is 0x%x.",
+			(u32) base, bam_read_reg(base, TEST_BUS_REG),
+			bam_read_reg_field(base, TEST_BUS_SEL,
+					BAM_TESTBUS_SEL));
+	}
+
+	print_bam_reg(base);
+
+	num_pipes = bam_read_reg_field(base, NUM_PIPES,
+					BAM_NUM_PIPES);
+	SPS_INFO("sps:bam 0x%x(va) has %d pipes.",
+			(u32) base, num_pipes);
+
+	for (i = 0; i < num_pipes; i++)
+		print_bam_pipe_reg(base, i);
+
+}
+
+/**
  * Get BAM IRQ source and clear global IRQ status
  */
-u32 bam_check_irq_source(void *base, u32 ee, u32 mask)
+u32 bam_check_irq_source(void *base, u32 ee, u32 mask,
+				enum sps_callback_case *cb_case)
 {
 	u32 source = bam_read_reg(base, IRQ_SRCS_EE(ee));
 	u32 clr = source & (1UL << 31);
@@ -833,19 +869,27 @@
 	if (clr) {
 		u32 status = 0;
 		status = bam_read_reg(base, IRQ_STTS);
+
+		if (status & IRQ_STTS_BAM_ERROR_IRQ) {
+			SPS_ERR("sps:bam 0x%x(va);bam irq status="
+				"0x%x.\nsps: BAM_ERROR_IRQ\n",
+				(u32) base, status);
+			bam_output_register_content(base);
+			*cb_case = SPS_CALLBACK_BAM_ERROR_IRQ;
+		} else if (status & IRQ_STTS_BAM_HRESP_ERR_IRQ) {
+			SPS_ERR("sps:bam 0x%x(va);bam irq status="
+				"0x%x.\nsps: BAM_HRESP_ERR_IRQ\n",
+				(u32) base, status);
+			bam_output_register_content(base);
+			*cb_case = SPS_CALLBACK_BAM_HRESP_ERR_IRQ;
+		} else
+			SPS_INFO("sps:bam 0x%x(va);bam irq status="
+				"0x%x.", (u32) base, status);
+
 		bam_write_reg(base, IRQ_CLR, status);
-		if (printk_ratelimit()) {
-			if (status & IRQ_STTS_BAM_ERROR_IRQ)
-				SPS_ERR("sps:bam 0x%x(va);bam irq status="
-					"0x%x.\nsps: BAM_ERROR_IRQ\n",
-					(u32) base, status);
-			else
-				SPS_INFO("sps:bam 0x%x(va);bam irq status="
-					"0x%x.", (u32) base, status);
-		}
 	}
 
-	source &= mask;
+	source &= (mask|(1UL << 31));
 	return source;
 }
 
diff --git a/drivers/platform/msm/sps/bam.h b/drivers/platform/msm/sps/bam.h
index 789769f..3521ffa 100644
--- a/drivers/platform/msm/sps/bam.h
+++ b/drivers/platform/msm/sps/bam.h
@@ -18,6 +18,7 @@
 #include <linux/types.h>	/* u32 */
 #include <linux/io.h>		/* ioread32() */
 #include <linux/bitops.h>	/* find_first_bit() */
+#include "spsi.h"
 
 /* Pipe mode */
 enum bam_pipe_mode {
@@ -166,10 +167,13 @@
  *
  * @mask - active pipes mask.
  *
+ * @case - callback case.
+ *
  * @return IRQ status
  *
  */
-u32 bam_check_irq_source(void *base, u32 ee, u32 mask);
+u32 bam_check_irq_source(void *base, u32 ee, u32 mask,
+				enum sps_callback_case *cb_case);
 
 /**
  * Initialize a BAM pipe
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index 6c8b1f9..0abd739 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -136,13 +136,19 @@
 	/* Get BAM interrupt source(s) */
 	if ((dev->state & BAM_STATE_MTI) == 0) {
 		u32 mask = dev->pipe_active_mask;
-		source = bam_check_irq_source(dev->base,
-							  dev->props.ee,
-							  mask);
+		enum sps_callback_case cb_case;
+		source = bam_check_irq_source(dev->base, dev->props.ee,
+						mask, &cb_case);
 
 		SPS_DBG1("sps:bam_isr:bam=0x%x;source=0x%x;mask=0x%x.",
 				BAM_ID(dev), source, mask);
 
+		if ((source & (1UL << 31)) && (dev->props.callback)) {
+			SPS_INFO("sps:bam_isr:bam=0x%x;callback for case %d.",
+				BAM_ID(dev), cb_case);
+			dev->props.callback(cb_case, dev->props.user);
+		}
+
 		/* Mask any non-local source */
 		source &= dev->pipe_active_mask;
 	} else {
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 053b81f..c040fac 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -19,6 +19,7 @@
 #include <linux/usb/msm_hsusb.h>
 #include <mach/usb_bam.h>
 #include <mach/sps.h>
+#include <linux/workqueue.h>
 
 #define USB_SUMMING_THRESHOLD 512
 #define CONNECTIONS_NUM		4
@@ -29,11 +30,20 @@
 static struct sps_mem_buffer data_mem_buf[CONNECTIONS_NUM][2];
 static struct sps_mem_buffer desc_mem_buf[CONNECTIONS_NUM][2];
 static struct platform_device *usb_bam_pdev;
+static struct workqueue_struct *usb_bam_wq;
+
+struct usb_bam_wake_event_info {
+	struct sps_register_event event;
+	int (*callback)(void *);
+	void *param;
+	struct work_struct wake_w;
+};
 
 struct usb_bam_connect_info {
 	u8 idx;
 	u8 *src_pipe;
 	u8 *dst_pipe;
+	struct usb_bam_wake_event_info peer_event;
 	bool enabled;
 };
 
@@ -48,7 +58,7 @@
 						u8 *usb_pipe_idx)
 {
 	int ret;
-	struct sps_pipe *pipe = sps_pipes[connection_idx][pipe_dir];
+	struct sps_pipe **pipe = &sps_pipes[connection_idx][pipe_dir];
 	struct sps_connect *connection =
 		&sps_connections[connection_idx][pipe_dir];
 	struct msm_usb_bam_platform_data *pdata =
@@ -58,13 +68,13 @@
 			(struct usb_bam_pipe_connect *)(pdata->connections +
 			 bam_offset(pdata) + (2*connection_idx+pipe_dir));
 
-	pipe = sps_alloc_endpoint();
-	if (pipe == NULL) {
+	*pipe = sps_alloc_endpoint();
+	if (*pipe == NULL) {
 		pr_err("%s: sps_alloc_endpoint failed\n", __func__);
 		return -ENOMEM;
 	}
 
-	ret = sps_get_config(pipe, connection);
+	ret = sps_get_config(*pipe, connection);
 	if (ret) {
 		pr_err("%s: tx get config failed %d\n", __func__, ret);
 		goto get_config_failed;
@@ -114,7 +124,7 @@
 	connection->desc = desc_mem_buf[connection_idx][pipe_dir];
 	connection->event_thresh = 512;
 
-	ret = sps_connect(pipe, connection);
+	ret = sps_connect(*pipe, connection);
 	if (ret < 0) {
 		pr_err("%s: tx connect error %d\n", __func__, ret);
 		goto error;
@@ -122,10 +132,10 @@
 	return 0;
 
 error:
-	sps_disconnect(pipe);
+	sps_disconnect(*pipe);
 fifo_setup_error:
 get_config_failed:
-	sps_free_endpoint(pipe);
+	sps_free_endpoint(*pipe);
 	return ret;
 }
 
@@ -168,6 +178,58 @@
 	return 0;
 }
 
+static void usb_bam_wake_work(struct work_struct *w)
+{
+	struct usb_bam_wake_event_info *wake_event_info =
+		container_of(w, struct usb_bam_wake_event_info, wake_w);
+
+	wake_event_info->callback(wake_event_info->param);
+}
+
+static void usb_bam_wake_cb(struct sps_event_notify *notify)
+{
+	struct usb_bam_wake_event_info *wake_event_info =
+		(struct usb_bam_wake_event_info *)notify->user;
+
+	queue_work(usb_bam_wq, &wake_event_info->wake_w);
+}
+
+int usb_bam_register_wake_cb(u8 idx,
+	int (*callback)(void *user), void* param)
+{
+	struct sps_pipe *pipe = sps_pipes[idx][PEER_PERIPHERAL_TO_USB];
+	struct sps_connect *sps_connection =
+		&sps_connections[idx][PEER_PERIPHERAL_TO_USB];
+	struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
+	struct usb_bam_wake_event_info *wake_event_info =
+		&connection->peer_event;
+	int ret;
+
+	wake_event_info->param = param;
+	wake_event_info->callback = callback;
+	wake_event_info->event.mode = SPS_TRIGGER_CALLBACK;
+	wake_event_info->event.xfer_done = NULL;
+	wake_event_info->event.callback = callback ? usb_bam_wake_cb : NULL;
+	wake_event_info->event.user = wake_event_info;
+	wake_event_info->event.options = SPS_O_WAKEUP;
+	ret = sps_register_event(pipe, &wake_event_info->event);
+	if (ret) {
+		pr_err("%s: sps_register_event() failed %d\n", __func__, ret);
+		return ret;
+	}
+
+	sps_connection->options = callback ?
+		(SPS_O_AUTO_ENABLE | SPS_O_WAKEUP | SPS_O_WAKEUP_IS_ONESHOT) :
+			SPS_O_AUTO_ENABLE;
+	ret = sps_set_config(pipe, sps_connection);
+	if (ret) {
+		pr_err("%s: sps_set_config() failed %d\n", __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 static int usb_bam_init(void)
 {
 	u32 h_usb;
@@ -275,8 +337,11 @@
 
 	dev_dbg(&pdev->dev, "usb_bam_probe\n");
 
-	for (i = 0; i < CONNECTIONS_NUM; i++)
+	for (i = 0; i < CONNECTIONS_NUM; i++) {
 		usb_bam_connections[i].enabled = 0;
+		INIT_WORK(&usb_bam_connections[i].peer_event.wake_w,
+			usb_bam_wake_work);
+	}
 
 	if (!pdev->dev.platform_data) {
 		dev_err(&pdev->dev, "missing platform_data\n");
@@ -288,11 +353,26 @@
 	if (ret)
 		dev_err(&pdev->dev, "failed to create device file\n");
 
+	usb_bam_wq = alloc_workqueue("usb_bam_wq",
+		WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+	if (!usb_bam_wq) {
+		pr_err("unable to create workqueue usb_bam_wq\n");
+		return -ENOMEM;
+	}
+
 	return ret;
 }
 
+static int usb_bam_remove(struct platform_device *pdev)
+{
+	destroy_workqueue(usb_bam_wq);
+
+	return 0;
+}
+
 static struct platform_driver usb_bam_driver = {
 	.probe = usb_bam_probe,
+	.remove = usb_bam_remove,
 	.driver = { .name = "usb_bam", },
 };
 
diff --git a/drivers/power/msm_charger.c b/drivers/power/msm_charger.c
index 0cd7967..8594ec2 100644
--- a/drivers/power/msm_charger.c
+++ b/drivers/power/msm_charger.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -991,7 +991,7 @@
 		usb_chg_current = mA;
 }
 
-static int __init determine_initial_batt_status(void)
+static int determine_initial_batt_status(void)
 {
 	if (is_battery_present())
 		if (is_battery_id_valid())
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index aa1a589..b0439bc 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -132,6 +132,10 @@
 	unsigned int		rconn_mohm;
 	struct mutex		last_ocv_uv_mutex;
 	int			last_ocv_uv;
+	int			last_cc_uah; /* used for Iavg calc for UUC */
+	struct timeval		t;
+	int			last_uuc_uah;
+	int			enable_fcc_learning;
 };
 
 static struct pm8921_bms_chip *the_chip;
@@ -966,6 +970,8 @@
 		convert_vbatt_raw_to_uv(chip, usb_chg,
 			raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
 		chip->last_ocv_uv = raw->last_good_ocv_uv;
+		/* forget the old cc value upon ocv */
+		chip->last_cc_uah = 0;
 	} else {
 		raw->last_good_ocv_uv = chip->last_ocv_uv;
 	}
@@ -1147,20 +1153,128 @@
 	*val = cc_uah;
 }
 
-static int calculate_unusable_charge_uah(struct pm8921_bms_chip *chip,
-				int rbatt, int fcc_uah,
-				int batt_temp, int chargecycles)
+static int calculate_uuc_uah_at_given_current(struct pm8921_bms_chip *chip,
+				 int batt_temp, int chargecycles,
+				int rbatt, int fcc_uah, int i_ma)
 {
-	int voltage_unusable_uv, pc_unusable;
+	int unusable_uv, pc_unusable, uuc;
 
-	/* calculate unusable charge */
-	voltage_unusable_uv = (rbatt * chip->i_test)
-						+ (chip->v_failure * 1000);
-	pc_unusable = calculate_pc(chip, voltage_unusable_uv,
-						batt_temp, chargecycles);
-	pr_debug("rbatt = %umilliOhms unusable_v =%d unusable_pc = %d\n",
-			rbatt, voltage_unusable_uv, pc_unusable);
-	return (fcc_uah * pc_unusable) / 100;
+	/* calculate unusable charge with itest */
+	unusable_uv = (rbatt * i_ma) + (chip->v_failure * 1000);
+	pc_unusable = calculate_pc(chip, unusable_uv, batt_temp, chargecycles);
+	uuc = (fcc_uah * pc_unusable) / 100;
+	pr_debug("For i_ma = %d, unusable_uv = %d unusable_pc = %d uuc = %d\n",
+					i_ma, unusable_uv, pc_unusable, uuc);
+	return uuc;
+}
+
+/* soc_rbatt when uuc_reported should be equal to uuc_now */
+#define SOC_RBATT_CHG		80
+#define SOC_RBATT_DISCHG	10
+static int calculate_unusable_charge_uah(struct pm8921_bms_chip *chip,
+				int rbatt, int fcc_uah, int cc_uah,
+				int soc_rbatt, int batt_temp, int chargecycles)
+{
+	struct timeval now;
+	int delta_time_s;
+	int delta_cc_uah;
+	int iavg_ua, iavg_ma;
+	int uuc_uah_itest, uuc_uah_iavg, uuc_now, uuc_reported;
+	s64 stepsize = 0;
+	int firsttime = 0;
+
+	delta_cc_uah = cc_uah - chip->last_cc_uah;
+	do_gettimeofday(&now);
+	if (chip->t.tv_sec != 0) {
+		delta_time_s = (now.tv_sec - chip->t.tv_sec);
+	} else {
+		/* uuc calculation for the first time */
+		delta_time_s = 0;
+		firsttime = 1;
+	}
+
+	if (delta_time_s != 0)
+		iavg_ua = div_s64((s64)delta_cc_uah * 3600, delta_time_s);
+	else
+		iavg_ua = 0;
+
+	iavg_ma = iavg_ua/1000;
+
+	pr_debug("t.tv_sec = %d, now.tv_sec = %d\n", (int)chip->t.tv_sec,
+				(int)now.tv_sec);
+
+	pr_debug("delta_time_s = %d iavg_ma = %d\n", delta_time_s, iavg_ma);
+
+	if (iavg_ma == 0) {
+		pr_debug("Iavg = 0 returning last uuc = %d\n",
+				chip->last_uuc_uah);
+		uuc_reported = chip->last_uuc_uah;
+		goto out;
+	}
+
+	/* calculate unusable charge with itest */
+	uuc_uah_itest = calculate_uuc_uah_at_given_current(chip,
+					batt_temp, chargecycles,
+					rbatt, fcc_uah, chip->i_test);
+
+	pr_debug("itest = %d uuc_itest = %d\n", chip->i_test, uuc_uah_itest);
+
+	/* calculate unusable charge with iavg */
+	iavg_ma = max(0, iavg_ma);
+	uuc_uah_iavg = calculate_uuc_uah_at_given_current(chip,
+					batt_temp, chargecycles,
+					rbatt, fcc_uah, iavg_ma);
+	pr_debug("iavg = %d uuc_iavg = %d\n", iavg_ma, uuc_uah_iavg);
+
+	if (firsttime) {
+		if (cc_uah < chip->last_cc_uah)
+			chip->last_uuc_uah = uuc_uah_itest;
+		else
+			chip->last_uuc_uah = uuc_uah_iavg;
+		pr_debug("firsttime uuc_prev = %d\n", chip->last_uuc_uah);
+	}
+
+	uuc_now = min(uuc_uah_itest, uuc_uah_iavg);
+
+	uuc_reported = -EINVAL;
+	if (cc_uah < chip->last_cc_uah) {
+		/* charging */
+		if (uuc_now < chip->last_uuc_uah) {
+			stepsize = max(1, (SOC_RBATT_CHG - soc_rbatt));
+			/* uuc_reported = uuc_prev + deltauuc / stepsize */
+			uuc_reported = div_s64 (stepsize * chip->last_uuc_uah
+					+ (uuc_now - chip->last_uuc_uah),
+					stepsize);
+			uuc_reported = max(0, uuc_reported);
+		}
+	} else {
+		if (uuc_now > chip->last_uuc_uah) {
+			stepsize = max(1, (soc_rbatt - SOC_RBATT_DISCHG));
+			/* uuc_reported = uuc_prev + deltauuc / stepsize */
+			uuc_reported = div_s64 (stepsize * chip->last_uuc_uah
+					+ (uuc_now - chip->last_uuc_uah),
+					stepsize);
+			uuc_reported = max(0, uuc_reported);
+		}
+	}
+	if (uuc_reported == -EINVAL)
+		uuc_reported = chip->last_uuc_uah;
+
+	pr_debug("uuc_now = %d uuc_prev = %d stepsize = %d uuc_reported = %d\n",
+			uuc_now, chip->last_uuc_uah, (int)stepsize,
+			uuc_reported);
+
+out:
+	/* remember the reported uuc */
+	chip->last_uuc_uah = uuc_reported;
+
+	/* remember cc_uah */
+	chip->last_cc_uah = cc_uah;
+
+	/* remember this time */
+	chip->t = now;
+
+	return uuc_reported;
 }
 
 /* calculate remainging charge at the time of ocv */
@@ -1211,7 +1325,9 @@
 	*rbatt = get_rbatt(chip, soc_rbatt, batt_temp);
 
 	*unusable_charge_uah = calculate_unusable_charge_uah(chip, *rbatt,
-					*fcc_uah, batt_temp, chargecycles);
+					*fcc_uah, *cc_uah, soc_rbatt,
+					batt_temp,
+					chargecycles);
 	pr_debug("UUC = %uuAh\n", *unusable_charge_uah);
 }
 
@@ -1644,6 +1760,8 @@
 #define OCV_TOL_MASK			0xF0
 #define IBAT_TOL_DEFAULT	0x03
 #define IBAT_TOL_NOCHG		0x0F
+#define OCV_TOL_DEFAULT		0x20
+#define OCV_TOL_NO_OCV		0x00
 void pm8921_bms_charging_began(void)
 {
 	int batt_temp, rc;
@@ -1705,7 +1823,7 @@
 
 	bms_end_ocv_uv = raw.last_good_ocv_uv;
 
-	if (is_battery_full
+	if (is_battery_full && the_chip->enable_fcc_learning
 		&& the_chip->start_percent <= MIN_START_PERCENT_FOR_LEARNING) {
 		int fcc_uah, new_fcc_uah, delta_fcc_uah;
 
@@ -1745,6 +1863,11 @@
 
 		the_chip->last_ocv_uv = the_chip->max_voltage_uv;
 		raw.last_good_ocv_uv = the_chip->max_voltage_uv;
+		/*
+		 * since we are treating this as an ocv event
+		 * forget the old cc value
+		 */
+		the_chip->last_cc_uah = 0;
 		pr_debug("EOC ocv_reading = 0x%x cc = 0x%x\n",
 				the_chip->ocv_reading_at_100,
 				the_chip->cc_reading_at_100);
@@ -1776,6 +1899,22 @@
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_charging_end);
 
+int pm8921_bms_stop_ocv_updates(struct pm8921_bms_chip *chip)
+{
+	pr_debug("stopping ocv updates\n");
+	return pm_bms_masked_write(chip, BMS_TOLERANCES,
+			OCV_TOL_MASK, OCV_TOL_NO_OCV);
+}
+EXPORT_SYMBOL_GPL(pm8921_bms_stop_ocv_updates);
+
+int pm8921_bms_start_ocv_updates(struct pm8921_bms_chip *chip)
+{
+	pr_debug("stopping ocv updates\n");
+	return pm_bms_masked_write(chip, BMS_TOLERANCES,
+			OCV_TOL_MASK, OCV_TOL_DEFAULT);
+}
+EXPORT_SYMBOL_GPL(pm8921_bms_start_ocv_updates);
+
 static irqreturn_t pm8921_bms_sbi_write_ok_handler(int irq, void *data)
 {
 	pr_debug("irq = %d triggered", irq);
@@ -2110,6 +2249,8 @@
 	CALIB_HKADC,
 	CALIB_CCADC,
 	GET_VBAT_VSENSE_SIMULTANEOUS,
+	STOP_OCV,
+	START_OCV,
 };
 
 static int test_batt_temp = 5;
@@ -2202,13 +2343,30 @@
 		pm8921_bms_get_simultaneous_battery_voltage_and_current(
 			&ibat_ua,
 			&vbat_uv);
+	default:
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static int set_calc(void *data, u64 val)
+{
+	int param = (int)data;
+	int ret = 0;
+
+	switch (param) {
+	case STOP_OCV:
+		pm8921_bms_stop_ocv_updates(the_chip);
+		break;
+	case START_OCV:
+		pm8921_bms_start_ocv_updates(the_chip);
 		break;
 	default:
 		ret = -EINVAL;
 	}
 	return ret;
 }
-DEFINE_SIMPLE_ATTRIBUTE(calc_fops, get_calc, NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(calc_fops, get_calc, set_calc, "%llu\n");
 
 static int get_reading(void *data, u64 * val)
 {
@@ -2346,6 +2504,10 @@
 				(void *)CALIB_HKADC, &calc_fops);
 	debugfs_create_file("calib_ccadc", 0644, chip->dent,
 				(void *)CALIB_CCADC, &calc_fops);
+	debugfs_create_file("stop_ocv", 0644, chip->dent,
+				(void *)STOP_OCV, &calc_fops);
+	debugfs_create_file("start_ocv", 0644, chip->dent,
+				(void *)START_OCV, &calc_fops);
 
 	debugfs_create_file("simultaneous", 0644, chip->dent,
 			(void *)GET_VBAT_VSENSE_SIMULTANEOUS, &calc_fops);
@@ -2467,6 +2629,7 @@
 	chip->ref1p25v_channel = pdata->bms_cdata.ref1p25v_channel;
 	chip->batt_id_channel = pdata->bms_cdata.batt_id_channel;
 	chip->revision = pm8xxx_get_revision(chip->dev->parent);
+	chip->enable_fcc_learning = pdata->enable_fcc_learning;
 	INIT_WORK(&chip->calib_hkadc_work, calibrate_hkadc_work);
 
 	rc = request_irqs(chip, pdev);
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 8e9d753..e7797b1 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -77,6 +77,7 @@
 #define CHG_ITRIM		0x35B
 #define CHG_TTRIM		0x35C
 #define CHG_COMP_OVR		0x20A
+#define IUSB_FINE_RES		0x2B6
 
 /* check EOC every 10 seconds */
 #define EOC_CHECK_PERIOD_MS	10000
@@ -243,6 +244,7 @@
 	bool				keep_btm_on_suspend;
 	bool				ext_charging;
 	bool				ext_charge_done;
+	bool				iusb_fine_res;
 	DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
 	struct work_struct		battery_id_valid_work;
 	int64_t				batt_id_min;
@@ -657,50 +659,110 @@
 }
 
 struct usb_ma_limit_entry {
-	int usb_ma;
+	int	usb_ma;
+	u8	value;
 };
 
 static struct usb_ma_limit_entry usb_ma_table[] = {
-	{100},
-	{500},
-	{700},
-	{850},
-	{900},
-	{1100},
-	{1300},
-	{1500},
+	{100, 0x0},
+	{200, 0x1},
+	{500, 0x2},
+	{600, 0x3},
+	{700, 0x4},
+	{800, 0x5},
+	{850, 0x6},
+	{900, 0x8},
+	{950, 0x7},
+	{1000, 0x9},
+	{1100, 0xA},
+	{1200, 0xB},
+	{1300, 0xC},
+	{1400, 0xD},
+	{1500, 0xE},
+	{1600, 0xF},
 };
 
 #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)
 {
-	u8 temp;
+	u8 temp, fineres;
+	int rc;
+
+	fineres = PM8917_IUSB_FINE_RES & usb_ma_table[reg_val].value;
+	reg_val = usb_ma_table[reg_val].value >> 1;
 
 	if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
 		pr_err("bad mA=%d asked to set\n", reg_val);
 		return -EINVAL;
 	}
-	temp = reg_val << 2;
-	return pm_chg_masked_write(chip, PBL_ACCESS2, PM8921_CHG_IUSB_MASK,
-					 temp);
+	temp = reg_val << PM8921_CHG_IUSB_SHIFT;
+
+	/* IUSB_FINE_RES */
+	if (chip->iusb_fine_res) {
+		/* Clear IUSB_FINE_RES bit to avoid overshoot */
+		rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
+			PM8917_IUSB_FINE_RES, 0);
+
+		rc |= pm_chg_masked_write(chip, PBL_ACCESS2,
+			PM8921_CHG_IUSB_MASK, temp);
+
+		if (rc) {
+			pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
+			return rc;
+		}
+
+		if (fineres) {
+			rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
+				PM8917_IUSB_FINE_RES, fineres);
+			if (rc)
+				pr_err("Failed to write ISUB_FINE_RES rc=%d\n",
+					rc);
+		}
+	} else {
+		rc = pm_chg_masked_write(chip, PBL_ACCESS2,
+			PM8921_CHG_IUSB_MASK, temp);
+		if (rc)
+			pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
+	}
+
+	return rc;
 }
 
 static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
 {
-	u8 temp;
-	int rc;
+	u8 temp, fineres;
+	int rc, i;
 
+	fineres = 0;
 	*mA = 0;
 	rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
 	if (rc) {
 		pr_err("err=%d reading PBL_ACCESS2\n", rc);
 		return rc;
 	}
+
+	if (chip->iusb_fine_res) {
+		rc = pm8xxx_readb(chip->dev->parent, IUSB_FINE_RES, &fineres);
+		if (rc) {
+			pr_err("err=%d reading IUSB_FINE_RES\n", rc);
+			return rc;
+		}
+	}
 	temp &= PM8921_CHG_IUSB_MASK;
-	temp = temp >> 2;
-	*mA = usb_ma_table[temp].usb_ma;
+	temp = temp >> PM8921_CHG_IUSB_SHIFT;
+
+	temp = (temp << 1) | (fineres & PM8917_IUSB_FINE_RES);
+	for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
+		if (usb_ma_table[i].value == temp)
+			break;
+	}
+
+	*mA = usb_ma_table[i].usb_ma;
+
 	return rc;
 }
 
@@ -1450,8 +1512,12 @@
 static void __pm8921_charger_vbus_draw(unsigned int mA)
 {
 	int i, rc;
+	if (!the_chip) {
+		pr_err("called before init\n");
+		return;
+	}
 
-	if (mA > 0 && mA <= 2) {
+	if (mA >= 0 && mA <= 2) {
 		usb_chg_current = 0;
 		rc = pm_chg_iusbmax_set(the_chip, 0);
 		if (rc) {
@@ -1468,6 +1534,11 @@
 			if (usb_ma_table[i].usb_ma <= mA)
 				break;
 		}
+
+		/* Check if IUSB_FINE_RES is available */
+		if ((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);
@@ -1792,6 +1863,8 @@
 	chip->ext_charging = false;
 	chip->ext_charge_done = false;
 	bms_notify_check(chip);
+	/* Update battery charging LEDs and user space battery info */
+	power_supply_changed(&chip->batt_psy);
 }
 
 static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
@@ -1846,6 +1919,8 @@
 	/* Start BMS */
 	schedule_delayed_work(&chip->eoc_work, delay);
 	wake_lock(&chip->eoc_wake_lock);
+	/* Update battery charging LEDs and user space battery info */
+	power_supply_changed(&chip->batt_psy);
 }
 
 static void turn_off_usb_ovp_fet(struct pm8921_chg_chip *chip)
@@ -1972,6 +2047,12 @@
 
 		if (i < (ARRAY_SIZE(usb_ma_table) - 1))
 			i++;
+		/* Get next correct entry if IUSB_FINE_RES is not available */
+		while (!the_chip->iusb_fine_res
+			&& (usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
+			&& i < (ARRAY_SIZE(usb_ma_table) - 1))
+			i++;
+
 		*value = usb_ma_table[i].usb_ma;
 	}
 }
@@ -3411,6 +3492,10 @@
 	if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
 		pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
 
+	/* Enable isub_fine resolution AICL for PM8917 */
+	if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
+		chip->iusb_fine_res = true;
+
 	pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
 
 	/* Disable EOC FSM processing */
diff --git a/drivers/regulator/qpnp-regulator.c b/drivers/regulator/qpnp-regulator.c
index fe728b2..ddc8589 100644
--- a/drivers/regulator/qpnp-regulator.c
+++ b/drivers/regulator/qpnp-regulator.c
@@ -166,6 +166,13 @@
 #define QPNP_BOOST_CURRENT_LIMIT_ENABLE_MASK	0x80
 #define QPNP_BOOST_CURRENT_LIMIT_MASK		0x07
 
+/*
+ * This voltage in uV is returned by get_voltage functions when there is no way
+ * to determine the current voltage level.  It is needed because the regulator
+ * framework treats a 0 uV voltage as an error.
+ */
+#define VOLTAGE_UNKNOWN 1
+
 struct qpnp_voltage_range {
 	int					min_uV;
 	int					max_uV;
@@ -243,15 +250,18 @@
  * properties to hold.
  */
 static struct qpnp_voltage_range pldo_ranges[] = {
-	VOLTAGE_RANGE(0,  375000,  375000, 1512500, 12500),
-	VOLTAGE_RANGE(2,  750000, 1525000, 1537500, 12500),
+	VOLTAGE_RANGE(2,  750000,  750000, 1537500, 12500),
 	VOLTAGE_RANGE(3, 1500000, 1550000, 3075000, 25000),
 	VOLTAGE_RANGE(4, 1750000, 3100000, 4900000, 50000),
 };
 
-static struct qpnp_voltage_range nldo_ranges[] = {
-	VOLTAGE_RANGE(0,  375000,  375000, 1512500, 12500),
-	VOLTAGE_RANGE(2,  750000, 1525000, 1537500, 12500),
+static struct qpnp_voltage_range nldo1_ranges[] = {
+	VOLTAGE_RANGE(2,  750000,  750000, 1537500, 12500),
+};
+
+static struct qpnp_voltage_range nldo2_ranges[] = {
+	VOLTAGE_RANGE(1,  375000,  375000,  768750,  6250),
+	VOLTAGE_RANGE(2,  750000,  775000, 1537500, 12500),
 };
 
 static struct qpnp_voltage_range smps_ranges[] = {
@@ -260,7 +270,7 @@
 };
 
 static struct qpnp_voltage_range ftsmps_ranges[] = {
-	VOLTAGE_RANGE(0,   80000,   80000, 1355000,  5000),
+	VOLTAGE_RANGE(0,   80000,  350000, 1355000,  5000),
 	VOLTAGE_RANGE(1,  160000, 1360000, 2710000, 10000),
 };
 
@@ -269,7 +279,10 @@
 };
 
 static struct qpnp_voltage_set_points pldo_set_points = SET_POINTS(pldo_ranges);
-static struct qpnp_voltage_set_points nldo_set_points = SET_POINTS(nldo_ranges);
+static struct qpnp_voltage_set_points nldo1_set_points
+					= SET_POINTS(nldo1_ranges);
+static struct qpnp_voltage_set_points nldo2_set_points
+					= SET_POINTS(nldo2_ranges);
 static struct qpnp_voltage_set_points smps_set_points = SET_POINTS(smps_ranges);
 static struct qpnp_voltage_set_points ftsmps_set_points
 					= SET_POINTS(ftsmps_ranges);
@@ -279,7 +292,8 @@
 
 static struct qpnp_voltage_set_points *all_set_points[] = {
 	&pldo_set_points,
-	&nldo_set_points,
+	&nldo1_set_points,
+	&nldo2_set_points,
 	&smps_set_points,
 	&ftsmps_set_points,
 	&boost_set_points,
@@ -629,7 +643,7 @@
 	if (!range) {
 		vreg_err(vreg, "voltage unknown, range %d is invalid\n",
 			range_sel);
-		return -EINVAL;
+		return VOLTAGE_UNKNOWN;
 	}
 
 	return range->step_uV * voltage_sel + range->min_uV;
@@ -949,11 +963,9 @@
 
 static const struct qpnp_regulator_mapping supported_regulators[] = {
 	QPNP_VREG_MAP(HF_BUCK,  GP_CTL,    SMPS,   smps,   smps,   100000),
-	QPNP_VREG_MAP(LDO,      N50,       LDO,    ldo,    nldo,     5000),
-	QPNP_VREG_MAP(LDO,      N150,      LDO,    ldo,    nldo,    10000),
-	QPNP_VREG_MAP(LDO,      N300,      LDO,    ldo,    nldo,    10000),
-	QPNP_VREG_MAP(LDO,      N600,      LDO,    ldo,    nldo,    10000),
-	QPNP_VREG_MAP(LDO,      N1200,     LDO,    ldo,    nldo,    10000),
+	QPNP_VREG_MAP(LDO,      N300,      LDO,    ldo,    nldo1,   10000),
+	QPNP_VREG_MAP(LDO,      N600,      LDO,    ldo,    nldo2,   10000),
+	QPNP_VREG_MAP(LDO,      N1200,     LDO,    ldo,    nldo2,   10000),
 	QPNP_VREG_MAP(LDO,      P50,       LDO,    ldo,    pldo,     5000),
 	QPNP_VREG_MAP(LDO,      P150,      LDO,    ldo,    pldo,    10000),
 	QPNP_VREG_MAP(LDO,      P300,      LDO,    ldo,    pldo,    10000),
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 69e0546..2fc95af 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -39,6 +39,7 @@
 #include <linux/remote_spinlock.h>
 #include <linux/pm_qos_params.h>
 #include <linux/of.h>
+#include <linux/of_gpio.h>
 #include "spi_qsd.h"
 
 static inline int msm_spi_configure_gsbi(struct msm_spi *dd,
@@ -1076,8 +1077,8 @@
 						 "timeout\n", __func__);
 				dd->cur_msg->status = -EIO;
 				if (dd->mode == SPI_DMOV_MODE) {
-					msm_dmov_flush(dd->tx_dma_chan);
-					msm_dmov_flush(dd->rx_dma_chan);
+					msm_dmov_flush(dd->tx_dma_chan, 1);
+					msm_dmov_flush(dd->rx_dma_chan, 1);
 				}
 				break;
 		}
@@ -1672,8 +1673,8 @@
 		return;
 
 	while (dd->mode == SPI_DMOV_MODE && limit++ < 50) {
-		msm_dmov_flush(dd->tx_dma_chan);
-		msm_dmov_flush(dd->rx_dma_chan);
+		msm_dmov_flush(dd->tx_dma_chan, 1);
+		msm_dmov_flush(dd->rx_dma_chan, 1);
 		msleep(10);
 	}
 
@@ -1739,8 +1740,8 @@
 					  SPI_INPUT_FIFO;
 
 	/* Clear remaining activities on channel */
-	msm_dmov_flush(dd->tx_dma_chan);
-	msm_dmov_flush(dd->rx_dma_chan);
+	msm_dmov_flush(dd->tx_dma_chan, 1);
+	msm_dmov_flush(dd->rx_dma_chan, 1);
 
 	return 0;
 }
@@ -1773,6 +1774,7 @@
 	int                     clk_enabled = 0;
 	int                     pclk_enabled = 0;
 	struct msm_spi_platform_data *pdata;
+	enum of_gpio_flags flags;
 
 	master = spi_alloc_master(&pdev->dev, sizeof(struct msm_spi));
 	if (!master) {
@@ -1797,9 +1799,35 @@
 			rc = -ENOMEM;
 			goto err_probe_exit;
 		}
+
+		for (i = 0; i < ARRAY_SIZE(spi_rsrcs); ++i) {
+			dd->spi_gpios[i] = of_get_gpio_flags(pdev->dev.of_node,
+								i, &flags);
+		}
+
+		for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i) {
+			dd->cs_gpios[i].gpio_num = of_get_named_gpio_flags(
+						pdev->dev.of_node, "cs-gpios",
+						i, &flags);
+			dd->cs_gpios[i].valid = 0;
+		}
 	} else {
 		pdata = pdev->dev.platform_data;
 		dd->qup_ver = SPI_QUP_VERSION_NONE;
+
+		for (i = 0; i < ARRAY_SIZE(spi_rsrcs); ++i) {
+			resource = platform_get_resource(pdev, IORESOURCE_IO,
+							i);
+			dd->spi_gpios[i] = resource ? resource->start : -1;
+		}
+
+		for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i) {
+			resource = platform_get_resource(pdev, IORESOURCE_IO,
+						i + ARRAY_SIZE(spi_rsrcs));
+			dd->cs_gpios[i].gpio_num = resource ?
+							resource->start : -1;
+			dd->cs_gpios[i].valid = 0;
+		}
 	}
 
 	dd->pdata = pdata;
@@ -1852,18 +1880,6 @@
 		}
 	}
 
-	for (i = 0; i < ARRAY_SIZE(spi_rsrcs); ++i) {
-		resource = platform_get_resource(pdev, IORESOURCE_IO, i);
-		dd->spi_gpios[i] = resource ? resource->start : -1;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i) {
-		resource = platform_get_resource(pdev, IORESOURCE_IO,
-				i + ARRAY_SIZE(spi_rsrcs));
-		dd->cs_gpios[i].gpio_num = resource ? resource->start : -1;
-		dd->cs_gpios[i].valid = 0;
-	}
-
 	rc = msm_spi_request_gpios(dd);
 	if (rc)
 		goto err_probe_gpio;
diff --git a/drivers/staging/qcache/fmem.c b/drivers/staging/qcache/fmem.c
index 4250ff5..1f78799 100644
--- a/drivers/staging/qcache/fmem.c
+++ b/drivers/staging/qcache/fmem.c
@@ -60,6 +60,10 @@
 {
 	struct fmem_platform_data *pdata = pdev->dev.platform_data;
 
+	if (!pdata->phys)
+		pdata->phys = allocate_contiguous_ebi_nomap(pdata->size,
+			pdata->align);
+
 #ifdef CONFIG_MEMORY_HOTPLUG
 	fmem_section_start = pdata->phys >> PA_SECTION_SHIFT;
 	fmem_section_end = (pdata->phys - 1 + pdata->size) >> PA_SECTION_SHIFT;
diff --git a/drivers/thermal/msm8960_tsens.c b/drivers/thermal/msm8960_tsens.c
index 71df297..fbb377e 100644
--- a/drivers/thermal/msm8960_tsens.c
+++ b/drivers/thermal/msm8960_tsens.c
@@ -24,6 +24,7 @@
 #include <linux/msm_tsens.h>
 #include <linux/io.h>
 #include <linux/err.h>
+#include <linux/pm.h>
 
 #include <mach/msm_iomap.h>
 #include <mach/socinfo.h>
@@ -134,6 +135,9 @@
 #define TSENS_8064_S5_STATUS_ADDR		(MSM_CLK_CTL_BASE + 0x00003664)
 #define TSENS_8064_SEQ_SENSORS				5
 #define TSENS_8064_S4_S5_OFFSET				40
+#define TSENS_CNTL_RESUME_MASK				0xfffffff9
+#define TSENS_8960_SENSOR_MASK				0xf8
+#define TSENS_8064_SENSOR_MASK				0x3ff8
 
 static int tsens_status_cntl_start;
 
@@ -153,6 +157,8 @@
 	int				tsens_factor;
 	uint32_t			tsens_num_sensor;
 	enum platform_type		hw_type;
+	int				pm_tsens_thr_data;
+	int				pm_tsens_cntl;
 	struct tsens_tm_device_sensor	sensor[0];
 };
 
@@ -265,9 +271,6 @@
 		return -EINVAL;
 
 	if (mode != tm_sensor->mode) {
-		pr_info("%s: mode: %d --> %d\n", __func__, tm_sensor->mode,
-									 mode);
-
 		reg = readl_relaxed(TSENS_CNTL_ADDR);
 
 		mask = 1 << (tm_sensor->sensor_num + TSENS_SENSOR0_SHIFT);
@@ -686,6 +689,83 @@
 	}
 }
 
+#ifdef CONFIG_PM
+static int tsens_suspend(struct device *dev)
+{
+	int i = 0;
+
+	tmdev->pm_tsens_thr_data = readl_relaxed(TSENS_THRESHOLD_ADDR);
+	tmdev->pm_tsens_cntl = readl_relaxed(TSENS_CNTL_ADDR);
+	writel_relaxed(tmdev->pm_tsens_cntl &
+		~(TSENS_8960_SLP_CLK_ENA | TSENS_EN), TSENS_CNTL_ADDR);
+	tmdev->prev_reading_avail = 0;
+	for (i = 0; i < tmdev->tsens_num_sensor; i++)
+		tmdev->sensor[i].mode = THERMAL_DEVICE_DISABLED;
+	disable_irq_nosync(TSENS_UPPER_LOWER_INT);
+	mb();
+	return 0;
+}
+
+static int tsens_resume(struct device *dev)
+{
+	unsigned int reg_cntl = 0, reg_cfg = 0, reg_sensor_mask = 0;
+	unsigned int reg_status_cntl = 0, reg_thr_data = 0, i = 0;
+
+	reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
+	writel_relaxed(reg_cntl | TSENS_SW_RST, TSENS_CNTL_ADDR);
+
+	if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615) {
+		reg_cntl |= TSENS_8960_SLP_CLK_ENA |
+			(TSENS_MEASURE_PERIOD << 18) |
+			TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
+			SENSORS_EN;
+		writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
+	} else if (tmdev->hw_type == APQ_8064) {
+		reg_cntl |= TSENS_8960_SLP_CLK_ENA |
+			(TSENS_MEASURE_PERIOD << 18) |
+			TSENS_8064_SENSORS_EN;
+		writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
+		reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
+		reg_status_cntl |= TSENS_MIN_STATUS_MASK |
+			TSENS_MAX_STATUS_MASK;
+		writel_relaxed(reg_status_cntl, TSENS_8064_STATUS_CNTL);
+	}
+
+	reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
+	reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
+		(TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
+	writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
+
+	writel_relaxed((tmdev->pm_tsens_cntl & TSENS_CNTL_RESUME_MASK),
+						TSENS_CNTL_ADDR);
+	reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
+	writel_relaxed(tmdev->pm_tsens_thr_data, TSENS_THRESHOLD_ADDR);
+	reg_thr_data = readl_relaxed(TSENS_THRESHOLD_ADDR);
+	if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615)
+		reg_sensor_mask = ((reg_cntl & TSENS_8960_SENSOR_MASK)
+				>> TSENS_SENSOR0_SHIFT);
+	else {
+		reg_sensor_mask = ((reg_cntl & TSENS_8064_SENSOR_MASK)
+				>> TSENS_SENSOR0_SHIFT);
+	}
+
+	for (i = 0; i < tmdev->tsens_num_sensor; i++) {
+		if (reg_sensor_mask & TSENS_MASK1)
+			tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
+		reg_sensor_mask >>= 1;
+	}
+
+	enable_irq(TSENS_UPPER_LOWER_INT);
+	mb();
+	return 0;
+}
+
+static const struct dev_pm_ops tsens_pm_ops = {
+	.suspend	= tsens_suspend,
+	.resume		= tsens_resume,
+};
+#endif
+
 static void tsens_disable_mode(void)
 {
 	unsigned int reg_cntl = 0;
@@ -717,8 +797,7 @@
 			(TSENS_MEASURE_PERIOD << 18) |
 			TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
 			TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
-			(((1 << tmdev->tsens_num_sensor) - 1) <<
-			TSENS_SENSOR0_SHIFT);
+			SENSORS_EN;
 		writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
 		reg_cntl |= TSENS_EN;
 		writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
@@ -744,8 +823,7 @@
 	} else if (tmdev->hw_type == APQ_8064) {
 		reg_cntl |= TSENS_8960_SLP_CLK_ENA |
 			(TSENS_MEASURE_PERIOD << 18) |
-			(((1 << tmdev->tsens_num_sensor) - 1) <<
-			 TSENS_SENSOR0_SHIFT);
+			TSENS_8064_SENSORS_EN;
 		writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
 		reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
 		reg_status_cntl |= TSENS_LOWER_STATUS_CLR |
@@ -910,7 +988,7 @@
 	return rc;
 }
 
-static int __init tsens_tm_init(void)
+static int __devinit tsens_tm_probe(struct platform_device *pdev)
 {
 	int rc, i;
 
@@ -958,7 +1036,7 @@
 	return rc;
 }
 
-static void __exit tsens_tm_remove(void)
+static int __devexit tsens_tm_remove(struct platform_device *pdev)
 {
 	int i;
 
@@ -969,10 +1047,32 @@
 		thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
 	kfree(tmdev);
 	tmdev = NULL;
+	return 0;
 }
 
-module_init(tsens_tm_init);
-module_exit(tsens_tm_remove);
+static struct platform_driver tsens_tm_driver = {
+	.probe = tsens_tm_probe,
+	.remove = tsens_tm_remove,
+	.driver = {
+		.name = "tsens8960-tm",
+		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm	= &tsens_pm_ops,
+#endif
+	},
+};
+
+static int __init _tsens_tm_init(void)
+{
+	return platform_driver_register(&tsens_tm_driver);
+}
+module_init(_tsens_tm_init);
+
+static void __exit _tsens_tm_remove(void)
+{
+	platform_driver_unregister(&tsens_tm_driver);
+}
+module_exit(_tsens_tm_remove);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("MSM8960 Temperature Sensor driver");
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 32e9dc0..72bc8de 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -626,6 +626,9 @@
 	unsigned long flags;
 	unsigned int baud, mr;
 
+	if (!termios->c_cflag)
+		return;
+
 	spin_lock_irqsave(&port->lock, flags);
 
 	/* calculate and set baud rate */
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 5b0b279..d310381 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -769,8 +769,7 @@
 		 */
 		mb();
 		/* do discard flush */
-		msm_dmov_stop_cmd(msm_uport->dma_rx_channel,
-				  &msm_uport->rx.xfer, 0);
+		msm_dmov_flush(msm_uport->dma_rx_channel, 0);
 	}
 
 	msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
@@ -831,8 +830,7 @@
 	if (msm_uport->rx.flush == FLUSH_NONE) {
 		wake_lock(&msm_uport->rx.wake_lock);
 		/* do discard flush */
-		msm_dmov_stop_cmd(msm_uport->dma_rx_channel,
-				  &msm_uport->rx.xfer, 0);
+		msm_dmov_flush(msm_uport->dma_rx_channel, 0);
 	}
 	if (msm_uport->rx.flush != FLUSH_SHUTDOWN)
 		msm_uport->rx.flush = FLUSH_STOP;
@@ -1427,7 +1425,7 @@
 
 		if (rx->flush == FLUSH_NONE) {
 			rx->flush = FLUSH_DATA_READY;
-			msm_dmov_flush(msm_uport->dma_rx_channel);
+			msm_dmov_flush(msm_uport->dma_rx_channel, 1);
 		}
 	}
 	/* tx ready interrupt */
diff --git a/drivers/tty/serial/msm_serial_hs_hwreg.h b/drivers/tty/serial/msm_serial_hs_hwreg.h
index 780a3c2..81f3d54 100644
--- a/drivers/tty/serial/msm_serial_hs_hwreg.h
+++ b/drivers/tty/serial/msm_serial_hs_hwreg.h
@@ -1,6 +1,6 @@
 /* drivers/serial/msm_serial_hs_hwreg.h
  *
- * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2009, 2012, Code Aurora Forum. All rights reserved.
  * 
  * All source code in this file is licensed under the following license
  * except where indicated.
@@ -160,9 +160,12 @@
 #define UARTDM_MR1_CTS_CTL_BMSK 0x40
 #define UARTDM_MR1_RX_RDY_CTL_BMSK 0x80
 
-#define UARTDM_MR2_LOOP_MODE_BMSK        0x80
-#define UARTDM_MR2_ERROR_MODE_BMSK       0x40
-#define UARTDM_MR2_BITS_PER_CHAR_BMSK    0x30
+#define UARTDM_MR2_LOOP_MODE_BMSK		0x80
+#define UARTDM_MR2_ERROR_MODE_BMSK		0x40
+#define UARTDM_MR2_BITS_PER_CHAR_BMSK		0x30
+#define UARTDM_MR2_RX_ZERO_CHAR_OFF		0x100
+#define UARTDM_MR2_RX_ERROR_CHAR_OFF		0x200
+#define UARTDM_MR2_RX_BREAK_ZERO_CHAR_OFF	0x100
 
 #define UARTDM_MR2_BITS_PER_CHAR_8	(0x3 << 4)
 
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index 285d1de..62d25cf 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -792,6 +792,9 @@
 	unsigned int baud, mr;
 	unsigned int vid;
 
+	if (!termios->c_cflag)
+		return;
+
 	spin_lock_irqsave(&port->lock, flags);
 
 	/* calculate and set baud rate */
@@ -1170,7 +1173,7 @@
 {
 	struct uart_port *port;
 	unsigned int vid;
-	int baud = 0, flow, bits, parity;
+	int baud = 0, flow, bits, parity, mr2;
 	int ret;
 
 	if (unlikely(co->index >= UART_NR || co->index < 0))
@@ -1205,6 +1208,12 @@
 	msm_hsl_set_baud_rate(port, baud);
 
 	ret = uart_set_options(port, co, baud, parity, bits, flow);
+
+	mr2 = msm_hsl_read(port, regmap[vid][UARTDM_MR2]);
+	mr2 |= UARTDM_MR2_RX_ERROR_CHAR_OFF;
+	mr2 |= UARTDM_MR2_RX_BREAK_ZERO_CHAR_OFF;
+	msm_hsl_write(port, mr2, regmap[vid][UARTDM_MR2]);
+
 	msm_hsl_reset(port);
 	/* Enable transmitter */
 	msm_hsl_write(port, CR_PROTECTION_EN, regmap[vid][UARTDM_CR]);
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index fd119c6..d74959e 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -27,6 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/utsname.h>
 #include <linux/platform_device.h>
+#include <linux/pm_qos_params.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/composite.h>
@@ -121,6 +122,8 @@
 	struct mutex mutex;
 	bool connected;
 	bool sw_connected;
+	char pm_qos[5];
+	struct pm_qos_request_list pm_qos_req_dma;
 	struct work_struct work;
 };
 
@@ -191,6 +194,25 @@
 	USB_CONFIGURED,
 };
 
+static void android_pm_qos_update_latency(struct android_dev *dev, int vote)
+{
+	struct android_usb_platform_data *pdata = dev->pdata;
+	u32 swfi_latency = 0;
+	static int last_vote = -1;
+
+	if (!pdata || vote == last_vote)
+		return;
+
+	swfi_latency = pdata->swfi_latency + 1;
+	if (vote)
+		pm_qos_update_request(&dev->pm_qos_req_dma,
+				swfi_latency);
+	else
+		pm_qos_update_request(&dev->pm_qos_req_dma,
+				PM_QOS_DEFAULT_VALUE);
+	last_vote = vote;
+}
+
 static void android_work(struct work_struct *data)
 {
 	struct android_dev *dev = container_of(data, struct android_dev, work);
@@ -209,6 +231,10 @@
 	} else if (dev->connected != dev->sw_connected) {
 		uevent_envp = dev->connected ? connected : disconnected;
 		next_state = dev->connected ? USB_CONNECTED : USB_DISCONNECTED;
+		if (dev->connected && strncmp(dev->pm_qos, "low", 3))
+			android_pm_qos_update_latency(dev, 1);
+		else if (!dev->connected || !strncmp(dev->pm_qos, "low", 3))
+			android_pm_qos_update_latency(dev, 0);
 	}
 	dev->sw_connected = dev->connected;
 	spin_unlock_irqrestore(&cdev->lock, flags);
@@ -1313,6 +1339,25 @@
 	return size;
 }
 
+static ssize_t pm_qos_show(struct device *pdev,
+			   struct device_attribute *attr, char *buf)
+{
+	struct android_dev *dev = dev_get_drvdata(pdev);
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", dev->pm_qos);
+}
+
+static ssize_t pm_qos_store(struct device *pdev,
+			   struct device_attribute *attr,
+			   const char *buff, size_t size)
+{
+	struct android_dev *dev = dev_get_drvdata(pdev);
+
+	strlcpy(dev->pm_qos, buff, sizeof(dev->pm_qos));
+
+	return size;
+}
+
 static ssize_t state_show(struct device *pdev, struct device_attribute *attr,
 			   char *buf)
 {
@@ -1387,6 +1432,8 @@
 
 static DEVICE_ATTR(functions, S_IRUGO | S_IWUSR, functions_show, functions_store);
 static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
+static DEVICE_ATTR(pm_qos, S_IRUGO | S_IWUSR,
+		pm_qos_show, pm_qos_store);
 static DEVICE_ATTR(state, S_IRUGO, state_show, NULL);
 static DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR,
 		remote_wakeup_show, remote_wakeup_store);
@@ -1403,6 +1450,7 @@
 	&dev_attr_iSerial,
 	&dev_attr_functions,
 	&dev_attr_enable,
+	&dev_attr_pm_qos,
 	&dev_attr_state,
 	&dev_attr_remote_wakeup,
 	NULL
@@ -1630,6 +1678,12 @@
 		goto err_probe;
 	}
 
+	/* pm qos request to prevent apps idle power collapse */
+	if (pdata && pdata->swfi_latency)
+		pm_qos_add_request(&dev->pm_qos_req_dma,
+			PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
+	strlcpy(dev->pm_qos, "high", sizeof(dev->pm_qos));
+
 	return ret;
 err_probe:
 	android_destroy_device(dev);
@@ -1641,10 +1695,14 @@
 static int android_remove(struct platform_device *pdev)
 {
 	struct android_dev *dev = _android_dev;
+	struct android_usb_platform_data *pdata = pdev->dev.platform_data;
 
 	android_destroy_device(dev);
 	class_destroy(android_class);
 	usb_composite_unregister(&android_usb_driver);
+	if (pdata && pdata->swfi_latency)
+		pm_qos_remove_request(&dev->pm_qos_req_dma);
+
 	return 0;
 }
 
diff --git a/drivers/usb/gadget/ci13xxx_msm_hsic.c b/drivers/usb/gadget/ci13xxx_msm_hsic.c
index eeacceb..39d4720 100644
--- a/drivers/usb/gadget/ci13xxx_msm_hsic.c
+++ b/drivers/usb/gadget/ci13xxx_msm_hsic.c
@@ -65,6 +65,7 @@
 	struct msm_xo_voter	*xo_handle;
 	struct workqueue_struct *wq;
 	struct work_struct	suspend_w;
+	struct msm_hsic_peripheral_platform_data *pdata;
 };
 
 static int msm_hsic_init_vddcx(struct msm_hsic_per *mhsic, int init)
@@ -365,8 +366,10 @@
 	 */
 	mb();
 
-	clk_disable(mhsic->iface_clk);
-	clk_disable(mhsic->core_clk);
+	if (!mhsic->pdata->keep_core_clk_on_suspend_workaround) {
+		clk_disable(mhsic->iface_clk);
+		clk_disable(mhsic->core_clk);
+	}
 	clk_disable(mhsic->phy_clk);
 	clk_disable(mhsic->cal_clk);
 
@@ -416,8 +419,10 @@
 		dev_err(mhsic->dev, "%s failed to vote for TCXO %d\n",
 				__func__, ret);
 
-	clk_enable(mhsic->iface_clk);
-	clk_enable(mhsic->core_clk);
+	if (!mhsic->pdata->keep_core_clk_on_suspend_workaround) {
+		clk_enable(mhsic->iface_clk);
+		clk_enable(mhsic->core_clk);
+	}
 	clk_enable(mhsic->phy_clk);
 	clk_enable(mhsic->cal_clk);
 
@@ -611,9 +616,17 @@
 	struct resource *res;
 	struct msm_hsic_per *mhsic;
 	int ret = 0;
+	struct msm_hsic_peripheral_platform_data *pdata;
 
 	dev_dbg(&pdev->dev, "msm-hsic probe\n");
 
+	if (!pdev->dev.platform_data) {
+		dev_err(&pdev->dev, "No platform data given. Bailing out\n");
+		return -ENODEV;
+	} else {
+		pdata = pdev->dev.platform_data;
+	}
+
 	mhsic = kzalloc(sizeof(struct msm_hsic_per), GFP_KERNEL);
 	if (!mhsic) {
 		dev_err(&pdev->dev, "unable to allocate msm_hsic\n");
@@ -622,6 +635,7 @@
 	the_mhsic = mhsic;
 	platform_set_drvdata(pdev, mhsic);
 	mhsic->dev = &pdev->dev;
+	mhsic->pdata = pdata;
 
 	mhsic->irq = platform_get_irq(pdev, 0);
 	if (mhsic->irq < 0) {
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index d754a88..b612a0b 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -3273,15 +3273,6 @@
 	udc->gadget.dev.parent   = dev;
 	udc->gadget.dev.release  = udc_release;
 
-	retval = hw_device_init(regs);
-	if (retval < 0)
-		goto free_udc;
-
-	for (i = 0; i < hw_ep_max; i++) {
-		struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
-		INIT_LIST_HEAD(&mEp->ep.ep_list);
-	}
-
 	udc->transceiver = otg_get_transceiver();
 
 	if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
@@ -3291,6 +3282,15 @@
 		}
 	}
 
+	retval = hw_device_init(regs);
+	if (retval < 0)
+		goto put_transceiver;
+
+	for (i = 0; i < hw_ep_max; i++) {
+		struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+		INIT_LIST_HEAD(&mEp->ep.ep_list);
+	}
+
 	if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) {
 		retval = hw_device_reset(udc);
 		if (retval)
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 958ed31..fcbc75c 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -414,6 +414,60 @@
 	kfree(f->name);
 }
 
+static void frmnet_suspend(struct usb_function *f)
+{
+	struct f_rmnet *dev = func_to_rmnet(f);
+	unsigned		port_num;
+	enum transport_type	dxport = rmnet_ports[dev->port_num].data_xport;
+
+	pr_debug("%s: data xport: %s dev: %p portno: %d\n",
+		__func__, xport_to_str(dxport),
+		dev, dev->port_num);
+
+	port_num = rmnet_ports[dev->port_num].data_xport_num;
+	switch (dxport) {
+	case USB_GADGET_XPORT_BAM:
+		break;
+	case USB_GADGET_XPORT_BAM2BAM:
+		gbam_suspend(&dev->port, port_num, dxport);
+		break;
+	case USB_GADGET_XPORT_HSIC:
+		break;
+	case USB_GADGET_XPORT_NONE:
+		break;
+	default:
+		pr_err("%s: Un-supported transport: %s\n", __func__,
+				xport_to_str(dxport));
+	}
+}
+
+static void frmnet_resume(struct usb_function *f)
+{
+	struct f_rmnet *dev = func_to_rmnet(f);
+	unsigned		port_num;
+	enum transport_type	dxport = rmnet_ports[dev->port_num].data_xport;
+
+	pr_debug("%s: data xport: %s dev: %p portno: %d\n",
+		__func__, xport_to_str(dxport),
+		dev, dev->port_num);
+
+	port_num = rmnet_ports[dev->port_num].data_xport_num;
+	switch (dxport) {
+	case USB_GADGET_XPORT_BAM:
+		break;
+	case USB_GADGET_XPORT_BAM2BAM:
+		gbam_resume(&dev->port, port_num, dxport);
+		break;
+	case USB_GADGET_XPORT_HSIC:
+		break;
+	case USB_GADGET_XPORT_NONE:
+		break;
+	default:
+		pr_err("%s: Un-supported transport: %s\n", __func__,
+				xport_to_str(dxport));
+	}
+}
+
 static void frmnet_disable(struct usb_function *f)
 {
 	struct f_rmnet *dev = func_to_rmnet(f);
@@ -912,6 +966,8 @@
 	f->disable = frmnet_disable;
 	f->set_alt = frmnet_set_alt;
 	f->setup = frmnet_setup;
+	f->suspend = frmnet_suspend;
+	f->resume = frmnet_resume;
 	dev->port.send_cpkt_response = frmnet_send_cpkt_response;
 	dev->port.disconnect = frmnet_disconnect;
 	dev->port.connect = frmnet_connect;
diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 0921b4f..863ddcd 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -1109,6 +1109,7 @@
 	struct msm_endpoint *ept = ui->ept + bit;
 	struct msm_request *req;
 	unsigned long flags;
+	int req_dequeue = 1;
 	unsigned info;
 
 	/*
@@ -1128,12 +1129,23 @@
 			break;
 		}
 
+dequeue:
 		/* clean speculative fetches on req->item->info */
 		dma_coherent_post_ops();
 		info = req->item->info;
 		/* if the transaction is still in-flight, stop here */
-		if (info & INFO_ACTIVE)
-			break;
+		if (info & INFO_ACTIVE) {
+			if (req_dequeue) {
+				req_dequeue = 0;
+				ui->dTD_update_fail_count++;
+				ept->dTD_update_fail_count++;
+				udelay(10);
+				goto dequeue;
+			} else {
+				break;
+			}
+		}
+		req_dequeue = 0;
 
 		del_timer(&ept->prime_timer);
 		/* advance ept queue to the next request */
@@ -2289,13 +2301,14 @@
 static int msm72k_pullup(struct usb_gadget *_gadget, int is_active)
 {
 	struct usb_info *ui = container_of(_gadget, struct usb_info, gadget);
+	struct msm_otg *otg = to_msm_otg(ui->xceiv);
 	unsigned long flags;
 
-
 	atomic_set(&ui->softconnect, is_active);
 
 	spin_lock_irqsave(&ui->lock, flags);
-	if (ui->usb_state == USB_STATE_NOTATTACHED || ui->driver == NULL) {
+	if (ui->usb_state == USB_STATE_NOTATTACHED || ui->driver == NULL ||
+		atomic_read(&otg->chg_type) == USB_CHG_TYPE__WALLCHARGER) {
 		spin_unlock_irqrestore(&ui->lock, flags);
 		return 0;
 	}
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 3113c45..d379c66 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -1214,3 +1214,49 @@
 
 	return ret;
 }
+
+static int gbam_wake_cb(void *param)
+{
+	struct gbam_port	*port = (struct gbam_port *)param;
+	struct bam_ch_info *d;
+	struct f_rmnet		*dev;
+
+	dev = port_to_rmnet(port->gr);
+	d = &port->data_ch;
+
+	pr_debug("%s: woken up by peer\n", __func__);
+
+	return usb_gadget_wakeup(dev->cdev->gadget);
+}
+
+void gbam_suspend(struct grmnet *gr, u8 port_num, enum transport_type trans)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info *d;
+
+	if (trans != USB_GADGET_XPORT_BAM2BAM)
+		return;
+
+	port = bam2bam_ports[port_num];
+	d = &port->data_ch;
+
+	pr_debug("%s: suspended port %d\n", __func__, port_num);
+
+	usb_bam_register_wake_cb(d->connection_idx, gbam_wake_cb, port);
+}
+
+void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans)
+{
+	struct gbam_port	*port;
+	struct bam_ch_info *d;
+
+	if (trans != USB_GADGET_XPORT_BAM2BAM)
+		return;
+
+	port = bam2bam_ports[port_num];
+	d = &port->data_ch;
+
+	pr_debug("%s: resumed port %d\n", __func__, port_num);
+
+	usb_bam_register_wake_cb(d->connection_idx, NULL, NULL);
+}
diff --git a/drivers/usb/gadget/u_rmnet.h b/drivers/usb/gadget/u_rmnet.h
index 386101c..0f7c4fb 100644
--- a/drivers/usb/gadget/u_rmnet.h
+++ b/drivers/usb/gadget/u_rmnet.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -50,6 +50,8 @@
 int gbam_connect(struct grmnet *gr, u8 port_num,
 				 enum transport_type trans, u8 connection_idx);
 void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans);
+void gbam_suspend(struct grmnet *gr, u8 port_num, enum transport_type trans);
+void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans);
 int gsmd_ctrl_connect(struct grmnet *gr, int port_num);
 void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num);
 int gsmd_ctrl_setup(unsigned int count);
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 0c71c8b..902d07cb 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -889,6 +889,12 @@
 			pstatus = ehci_readl(ehci,
 					 &ehci->regs->port_status[i]);
 
+			/*set RS bit in case of remote wakeup*/
+			if (ehci_is_TDI(ehci) && !(cmd & CMD_RUN) &&
+					(pstatus & PORT_SUSPEND))
+				ehci_writel(ehci, cmd | CMD_RUN,
+						&ehci->regs->command);
+
 			if (pstatus & PORT_OWNER)
 				continue;
 			if (!(test_bit(i, &ehci->suspended_ports) &&
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 1457ab2..5ee1908 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -345,7 +345,9 @@
 	 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
 	 * in failure case.
 	 */
-	val = readl_relaxed(USB_PORTSC) | PORTSC_PHCD;
+	val = readl_relaxed(USB_PORTSC);
+	val &= ~PORT_RWC_BITS;
+	val |= PORTSC_PHCD;
 	writel_relaxed(val, USB_PORTSC);
 	while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
 		if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
@@ -444,7 +446,8 @@
 	if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD))
 		goto skip_phy_resume;
 
-	temp = readl_relaxed(USB_PORTSC) & ~PORTSC_PHCD;
+	temp = readl_relaxed(USB_PORTSC);
+	temp &= ~(PORT_RWC_BITS | PORTSC_PHCD);
 	writel_relaxed(temp, USB_PORTSC);
 	while (cnt < PHY_RESUME_TIMEOUT_USEC) {
 		if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD) &&
@@ -486,6 +489,7 @@
 
 	if (atomic_read(&mehci->in_lpm)) {
 		disable_irq_nosync(hcd->irq);
+		dev_dbg(mehci->dev, "phy async intr\n");
 		mehci->async_int = true;
 		pm_runtime_get(mehci->dev);
 		return IRQ_HANDLED;
@@ -766,8 +770,6 @@
 	debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
 }
 
-
-
 static int __devinit ehci_hsic_msm_probe(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd;
@@ -1031,8 +1033,14 @@
 #ifdef CONFIG_PM_RUNTIME
 static int msm_hsic_runtime_idle(struct device *dev)
 {
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
 	dev_dbg(dev, "EHCI runtime idle\n");
 
+	/*don't allow runtime suspend in the middle of remote wakeup*/
+	if (readl_relaxed(USB_PORTSC) & PORT_RESUME)
+		return -EAGAIN;
+
 	return 0;
 }
 
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index 17fa7b1..4657283 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -33,10 +33,13 @@
 #include <linux/usb/msm_hsusb_hw.h>
 #include <linux/usb/msm_hsusb.h>
 #include <mach/clk.h>
+#include <mach/msm_xo.h>
 #include <mach/msm_iomap.h>
 
 #define MSM_USB_BASE (hcd->regs)
 
+#define PDEV_NAME_LEN 20
+
 struct msm_hcd {
 	struct ehci_hcd				ehci;
 	struct device				*dev;
@@ -47,6 +50,7 @@
 	struct regulator			*hsusb_3p3;
 	struct regulator			*hsusb_1p8;
 	struct regulator			*vbus;
+	struct msm_xo_voter			*xo_handle;
 	bool					async_int;
 	bool					vbus_on;
 	atomic_t				in_lpm;
@@ -539,6 +543,7 @@
 {
 	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
 	unsigned long timeout;
+	int ret;
 	u32 portsc;
 
 	if (atomic_read(&mhcd->in_lpm)) {
@@ -588,6 +593,12 @@
 	clk_disable_unprepare(mhcd->iface_clk);
 	clk_disable_unprepare(mhcd->core_clk);
 
+	/* usb phy does not require TCXO clock, hence vote for TCXO disable */
+	ret = msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_OFF);
+	if (ret)
+		dev_err(mhcd->dev, "%s failed to devote for "
+			"TCXO D0 buffer%d\n", __func__, ret);
+
 	msm_ehci_config_vddcx(mhcd, 0);
 
 	atomic_set(&mhcd->in_lpm, 1);
@@ -604,6 +615,7 @@
 	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
 	unsigned long timeout;
 	unsigned temp;
+	int ret;
 
 	if (!atomic_read(&mhcd->in_lpm)) {
 		dev_dbg(mhcd->dev, "%s called in !in_lpm\n", __func__);
@@ -612,6 +624,12 @@
 
 	wake_lock(&mhcd->wlock);
 
+	/* Vote for TCXO when waking up the phy */
+	ret = msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_ON);
+	if (ret)
+		dev_err(mhcd->dev, "%s failed to vote for "
+			"TCXO D0 buffer%d\n", __func__, ret);
+
 	clk_prepare_enable(mhcd->core_clk);
 	clk_prepare_enable(mhcd->iface_clk);
 
@@ -816,6 +834,7 @@
 	struct resource *res;
 	struct msm_hcd *mhcd;
 	const struct msm_usb_host_platform_data *pdata;
+	char pdev_name[PDEV_NAME_LEN];
 	int ret;
 
 	dev_dbg(&pdev->dev, "ehci_msm2 probe\n");
@@ -853,11 +872,27 @@
 	mhcd = hcd_to_mhcd(hcd);
 	mhcd->dev = &pdev->dev;
 
+	snprintf(pdev_name, PDEV_NAME_LEN, "%s.%d", pdev->name, pdev->id);
+	mhcd->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, pdev_name);
+	if (IS_ERR(mhcd->xo_handle)) {
+		dev_err(&pdev->dev, "%s not able to get the handle "
+			"to vote for TCXO D0 buffer\n", __func__);
+		ret = PTR_ERR(mhcd->xo_handle);
+		goto unmap;
+	}
+
+	ret = msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_ON);
+	if (ret) {
+		dev_err(&pdev->dev, "%s failed to vote for TCXO "
+			"D0 buffer%d\n", __func__, ret);
+		goto free_xo_handle;
+	}
+
 	ret = msm_ehci_init_clocks(mhcd, 1);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to initialize clocks\n");
 		ret = -ENODEV;
-		goto unmap;
+		goto devote_xo_handle;
 	}
 
 	ret = msm_ehci_init_vddcx(mhcd, 1);
@@ -931,6 +966,10 @@
 	msm_ehci_init_vddcx(mhcd, 0);
 deinit_clocks:
 	msm_ehci_init_clocks(mhcd, 0);
+devote_xo_handle:
+	msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_OFF);
+free_xo_handle:
+	msm_xo_put(mhcd->xo_handle);
 unmap:
 	iounmap(hcd->regs);
 put_hcd:
@@ -950,6 +989,7 @@
 
 	usb_remove_hcd(hcd);
 
+	msm_xo_put(mhcd->xo_handle);
 	msm_ehci_vbus_power(mhcd, 0);
 	msm_ehci_init_vbus(mhcd, 0);
 	msm_ehci_ldo_enable(mhcd, 0);
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 9794918..96e5a90 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -88,7 +88,8 @@
 		return;
 	}
 
-	cbs->read_complete_cb(cbs->ctxt,
+	if (cbs && cbs->read_complete_cb)
+		cbs->read_complete_cb(cbs->ctxt,
 			urb->transfer_buffer,
 			urb->transfer_buffer_length,
 			urb->status < 0 ? urb->status : urb->actual_length);
@@ -172,7 +173,8 @@
 		return;
 	}
 
-	cbs->write_complete_cb(cbs->ctxt,
+	if (cbs && cbs->write_complete_cb)
+		cbs->write_complete_cb(cbs->ctxt,
 			urb->transfer_buffer,
 			urb->transfer_buffer_length,
 			urb->status < 0 ? urb->status : urb->actual_length);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index f319eb5..4dd6aff 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -39,7 +39,6 @@
 #include <linux/regulator/consumer.h>
 #include <linux/mfd/pm8xxx/pm8921-charger.h>
 #include <linux/mfd/pm8xxx/misc.h>
-#include <linux/pm_qos_params.h>
 #include <linux/power_supply.h>
 
 #include <mach/clk.h>
@@ -71,25 +70,6 @@
 static bool debug_aca_enabled;
 static bool debug_bus_voting_enabled;
 
-/* Prevent idle power collapse(pc) while operating in peripheral mode */
-static void otg_pm_qos_update_latency(struct msm_otg *dev, int vote)
-{
-	struct msm_otg_platform_data *pdata = dev->pdata;
-	u32 swfi_latency = 0;
-
-	if (!pdata || !pdata->swfi_latency)
-		return;
-
-	swfi_latency = pdata->swfi_latency + 1;
-
-	if (vote)
-		pm_qos_update_request(&dev->pm_qos_req_dma,
-				swfi_latency);
-	else
-		pm_qos_update_request(&dev->pm_qos_req_dma,
-				PM_QOS_DEFAULT_VALUE);
-}
-
 static struct regulator *hsusb_3p3;
 static struct regulator *hsusb_1p8;
 static struct regulator *hsusb_vddcx;
@@ -1308,11 +1288,7 @@
 		 */
 		if (pdata->setup_gpio)
 			pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
-		/*
-		 * vote for minimum dma_latency to prevent idle
-		 * power collapse(pc) while running in peripheral mode.
-		 */
-		otg_pm_qos_update_latency(motg, 1);
+
 		/* Configure BUS performance parameters for MAX bandwidth */
 		if (motg->bus_perf_client && debug_bus_voting_enabled) {
 			ret = msm_bus_scale_client_update_request(
@@ -1325,7 +1301,6 @@
 	} else {
 		dev_dbg(otg->dev, "gadget off\n");
 		usb_gadget_vbus_disconnect(otg->gadget);
-		otg_pm_qos_update_latency(motg, 0);
 		/* Configure BUS performance parameters to default */
 		if (motg->bus_perf_client) {
 			ret = msm_bus_scale_client_update_request(
@@ -3213,11 +3188,6 @@
 	else
 		clk_set_rate(motg->clk, 60000000);
 
-	/* pm qos request to prevent apps idle power collapse */
-	if (motg->pdata->swfi_latency)
-		pm_qos_add_request(&motg->pm_qos_req_dma,
-			PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
-
 	/*
 	 * USB Core is running its protocol engine based on CORE CLK,
 	 * CORE CLK  must be running at >55Mhz for correct HSUSB
@@ -3452,8 +3422,6 @@
 	if (!IS_ERR(motg->phy_reset_clk))
 		clk_put(motg->phy_reset_clk);
 free_motg:
-	if (motg->pdata->swfi_latency)
-		pm_qos_remove_request(&motg->pm_qos_req_dma);
 	kfree(motg);
 	return ret;
 }
@@ -3523,9 +3491,6 @@
 		clk_put(motg->clk);
 	clk_put(motg->core_clk);
 
-	if (motg->pdata->swfi_latency)
-		pm_qos_remove_request(&motg->pm_qos_req_dma);
-
 	if (motg->bus_perf_client)
 		msm_bus_scale_unregister_client(motg->bus_perf_client);
 
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 2a08101..94de730 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -734,6 +734,10 @@
 		}
 	}
 
+	spin_lock_irq(&intfdata->susp_lock);
+	intfdata->suspended = 0;
+	spin_unlock_irq(&intfdata->susp_lock);
+
 	for (i = 0; i < serial->num_ports; i++) {
 		/* walk all ports */
 		port = serial->port[i];
@@ -759,9 +763,6 @@
 		play_delayed(port);
 		spin_unlock_irq(&intfdata->susp_lock);
 	}
-	spin_lock_irq(&intfdata->susp_lock);
-	intfdata->suspended = 0;
-	spin_unlock_irq(&intfdata->susp_lock);
 err_out:
 	return err;
 }
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index 5d12e97..7f603dd 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -2056,6 +2056,7 @@
 	pinfo->xres = timing->active_h;
 	pinfo->yres = timing->active_v;
 	pinfo->clk_rate = timing->pixel_freq*1000;
+	pinfo->frame_rate = 60;
 
 	pinfo->lcdc.h_back_porch = timing->back_porch_h;
 	pinfo->lcdc.h_front_porch = timing->front_porch_h;
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index 375f82f..7f6585c 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -4136,6 +4136,8 @@
 	/* HDMI_USEC_REFTIMER[0x0208] */
 	HDMI_OUTP(0x0208, 0x0001001B);
 
+	hdmi_msm_set_mode(TRUE);
+
 	hdmi_msm_video_setup(external_common_state->video_resolution);
 	if (!hdmi_msm_is_dvi_mode())
 		hdmi_msm_audio_setup();
@@ -4152,8 +4154,6 @@
 	HDMI_OUTP(0x0258, ~(1 << 28) & hpd_ctrl);
 	HDMI_OUTP(0x0258, (1 << 28) | hpd_ctrl);
 
-	hdmi_msm_set_mode(TRUE);
-
 	/* Setup HPD IRQ */
 	HDMI_OUTP(0x0254, 4 | (external_common_state->hpd_state ? 0 : 2));
 
@@ -4539,7 +4539,6 @@
 	hdmi_msm_state->hdcp_timer.data = (uint32)NULL;
 
 	hdmi_msm_state->hdcp_timer.expires = 0xffffffffL;
-	add_timer(&hdmi_msm_state->hdcp_timer);
 #endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
 
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
diff --git a/drivers/video/msm/lcdc_toshiba_fwvga_pt.c b/drivers/video/msm/lcdc_toshiba_fwvga_pt.c
index 3e81471..77606cf 100644
--- a/drivers/video/msm/lcdc_toshiba_fwvga_pt.c
+++ b/drivers/video/msm/lcdc_toshiba_fwvga_pt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -436,7 +436,7 @@
 	pinfo->bl_max = 100;
 	pinfo->bl_min = 1;
 
-	if (cpu_is_msm7x25a() || cpu_is_msm7x25aa()) {
+	if (cpu_is_msm7x25a() || cpu_is_msm7x25aa() || cpu_is_msm7x25ab()) {
 		pinfo->yres = 320;
 		pinfo->lcdc.h_back_porch = 10;
 		pinfo->lcdc.h_front_porch = 21;
diff --git a/drivers/video/msm/lvds.c b/drivers/video/msm/lvds.c
index 8f1e510..18225fb 100644
--- a/drivers/video/msm/lvds.c
+++ b/drivers/video/msm/lvds.c
@@ -143,9 +143,9 @@
 			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
 			MDP_OUTP(MDP_BASE +  0xc2028, 0x00121314);
 			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */
-			MDP_OUTP(MDP_BASE +  0xc202c, 0x1706071b);
+			MDP_OUTP(MDP_BASE +  0xc202c, 0x0f16171b);
 			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_6_TO_4 */
-			MDP_OUTP(MDP_BASE +  0xc2030, 0x000e0f16);
+			MDP_OUTP(MDP_BASE +  0xc2030, 0x0006070e);
 		}
 		if (mfd->panel_info.lvds.channel_mode ==
 			LVDS_DUAL_CHANNEL_MODE) {
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 2ca9296..471ed4e 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -2071,7 +2071,7 @@
 	}
 	disable_irq(mdp_irq);
 
-	footswitch = regulator_get(NULL, "fs_mdp");
+	footswitch = regulator_get(&pdev->dev, "vdd");
 	if (IS_ERR(footswitch))
 		footswitch = NULL;
 	else {
diff --git a/drivers/video/msm/mdp4_dtv.c b/drivers/video/msm/mdp4_dtv.c
index f7e74e6..f0353bd 100644
--- a/drivers/video/msm/mdp4_dtv.c
+++ b/drivers/video/msm/mdp4_dtv.c
@@ -149,7 +149,7 @@
 	}
 	pr_info("%s: tv_src_clk=%dkHz, pm_qos_rate=%ldkHz, [%d]\n", __func__,
 		mfd->fbi->var.pixclock/1000, pm_qos_rate, ret);
-
+	mfd->panel_info.clk_rate = mfd->fbi->var.pixclock;
 	clk_prepare_enable(hdmi_clk);
 	clk_reset(hdmi_clk, CLK_RESET_ASSERT);
 	udelay(20);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 7cc73de..34fd399 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -1470,6 +1470,33 @@
 	return cnt;
 }
 
+static void mdp4_overlay_bg_solidfill_clear(uint32 mixer_num)
+{
+	struct mdp4_overlay_pipe *bg_pipe;
+	unsigned char *rgb_base;
+	uint32 rgb_src_format;
+	int pnum;
+
+	bg_pipe = mdp4_overlay_stage_pipe(mixer_num,
+		MDP4_MIXER_STAGE_BASE);
+	if (bg_pipe && bg_pipe->pipe_type == OVERLAY_TYPE_BF) {
+		bg_pipe = mdp4_overlay_stage_pipe(mixer_num,
+				MDP4_MIXER_STAGE0);
+	}
+
+	if (bg_pipe && bg_pipe->pipe_type == OVERLAY_TYPE_RGB) {
+		rgb_src_format = mdp4_overlay_format(bg_pipe);
+		if (!(rgb_src_format & MDP4_FORMAT_SOLID_FILL)) {
+			pnum = bg_pipe->pipe_num - OVERLAY_PIPE_RGB1;
+			rgb_base = MDP_BASE + MDP4_RGB_BASE;
+			rgb_base += MDP4_RGB_OFF * pnum;
+			outpdw(rgb_base + 0x50, rgb_src_format);
+			outpdw(rgb_base + 0x0058, bg_pipe->op_mode);
+			mdp4_overlay_reg_flush(bg_pipe, 0);
+		}
+	}
+}
+
 static void mdp4_mixer_stage_commit(int mixer)
 {
 	struct mdp4_overlay_pipe *pipe;
@@ -2573,6 +2600,12 @@
 		hdmi_prim_display)) {
 			ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = NULL;
 	} else {
+		if (pipe->is_fg &&
+			!mdp4_overlay_is_rgb_type(pipe->src_format)) {
+			mdp4_overlay_bg_solidfill_clear(pipe->mixer_num);
+			pipe->is_fg = 0;
+		}
+
 		mdp4_mixer_stage_down(pipe);
 
 		if (pipe->mixer_num == MDP4_MIXER0) {
@@ -2856,6 +2889,11 @@
 		mdp4_overlay_rgb_setup(pipe);	/* rgb pipe */
 	}
 
+	if ((ctrl->panel_mode & MDP4_PANEL_DTV) ||
+		(ctrl->panel_mode & MDP4_PANEL_LCDC) ||
+		(ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO))
+		mdp4_overlay_reg_flush(pipe, 0);
+
 	mdp4_mixer_stage_up(pipe);
 
 	if (pipe->mixer_num == MDP4_MIXER2) {
@@ -2870,7 +2908,6 @@
 		ctrl->mixer1_played++;
 		/* enternal interface */
 		if (ctrl->panel_mode & MDP4_PANEL_DTV) {
-			mdp4_overlay_reg_flush(pipe, 0);
 			mdp4_overlay_dtv_start();
 			mdp4_overlay_dtv_ov_done_push(mfd, pipe);
 			if (!mfd->use_ov1_blt)
@@ -2881,7 +2918,6 @@
 		/* primary interface */
 		ctrl->mixer0_played++;
 		if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
-			mdp4_overlay_reg_flush(pipe, 0);
 			if (!mfd->use_ov0_blt)
 				mdp4_overlay_update_blt_mode(mfd);
 			mdp4_overlay_lcdc_start();
@@ -2889,7 +2925,6 @@
 		}
 #ifdef CONFIG_FB_MSM_MIPI_DSI
 		else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
-			mdp4_overlay_reg_flush(pipe, 0);
 			if (!mfd->use_ov0_blt)
 				mdp4_overlay_update_blt_mode(mfd);
 			mdp4_overlay_dsi_video_start();
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index b9760bf..e3917e6 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -470,6 +470,28 @@
 	mfd->ov_start = true;
 }
 
+static void mdp4_overlay_dtv_wait4dmae(struct msm_fb_data_type *mfd)
+{
+	unsigned long flag;
+
+	if (!dtv_pipe) {
+		pr_debug("%s: no mixer1 base layer pipe allocated!\n",
+			 __func__);
+		return;
+	}
+	/* enable irq */
+	spin_lock_irqsave(&mdp_spin_lock, flag);
+	mdp_enable_irq(MDP_DMA_E_TERM);
+	INIT_COMPLETION(dtv_pipe->comp);
+	mfd->dma->waiting = TRUE;
+	outp32(MDP_INTR_CLEAR, INTR_DMA_E_DONE);
+	mdp_intr_mask |= INTR_DMA_E_DONE;
+	outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+	spin_unlock_irqrestore(&mdp_spin_lock, flag);
+	wait_for_completion_killable(&dtv_pipe->comp);
+	mdp_disable_irq(MDP_DMA_E_TERM);
+}
+
 static void mdp4_overlay_dtv_wait4_ov_done(struct msm_fb_data_type *mfd,
 	struct mdp4_overlay_pipe *pipe)
 {
@@ -490,6 +512,9 @@
 	wait_for_completion_timeout(&dtv_pipe->comp,
 			msecs_to_jiffies(VSYNC_PERIOD*2));
 	mdp_disable_irq(MDP_OVERLAY1_TERM);
+
+	if (dtv_pipe->blt_addr)
+		mdp4_overlay_dtv_wait4dmae(mfd);
 }
 
 void mdp4_overlay_dtv_start(void)
@@ -601,28 +626,6 @@
 	mdp_disable_irq(MDP_DMA_E_TERM);
 }
 
-static void mdp4_overlay_dtv_wait4dmae(struct msm_fb_data_type *mfd)
-{
-	unsigned long flag;
-
-	if (!dtv_pipe) {
-		pr_debug("%s: no mixer1 base layer pipe allocated!\n",
-			 __func__);
-		return;
-	}
-	/* enable irq */
-	spin_lock_irqsave(&mdp_spin_lock, flag);
-	mdp_enable_irq(MDP_DMA_E_TERM);
-	INIT_COMPLETION(dtv_pipe->comp);
-	mfd->dma->waiting = TRUE;
-	outp32(MDP_INTR_CLEAR, INTR_DMA_E_DONE);
-	mdp_intr_mask |= INTR_DMA_E_DONE;
-	outp32(MDP_INTR_ENABLE, mdp_intr_mask);
-	spin_unlock_irqrestore(&mdp_spin_lock, flag);
-	wait_for_completion_killable(&dtv_pipe->comp);
-	mdp_disable_irq(MDP_DMA_E_TERM);
-}
-
 static void mdp4_dtv_do_blt(struct msm_fb_data_type *mfd, int enable)
 {
 	unsigned long flag;
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index f92fb43..2fba83d 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -203,7 +203,7 @@
 	if (mfd->dma->busy == TRUE) {
 		if (busy_wait_cnt == 0)
 			INIT_COMPLETION(mfd->dma->comp);
-		busy_wait_cnt++;
+		busy_wait_cnt = 1;
 		need_wait++;
 	}
 	spin_unlock_irqrestore(&mdp_spin_lock, flag);
@@ -220,22 +220,21 @@
 {
 	spin_lock(&mdp_spin_lock);
 	dma->busy = FALSE;
-	spin_unlock(&mdp_spin_lock);
-	complete(&dma->comp);
 	if (busy_wait_cnt)
-		busy_wait_cnt--;
-
+		busy_wait_cnt = 0;
 	mdp_disable_irq_nosync(MDP_OVERLAY2_TERM);
+	spin_unlock(&mdp_spin_lock);
+	complete_all(&dma->comp);
 	pr_debug("%s ovdone interrupt\n", __func__);
 
 }
 void mdp4_writeback_overlay_kickoff(struct msm_fb_data_type *mfd,
-		struct mdp4_overlay_pipe *pipe)
+				    struct mdp4_overlay_pipe *pipe)
 {
 	unsigned long flag;
 	spin_lock_irqsave(&mdp_spin_lock, flag);
 	mdp_enable_irq(MDP_OVERLAY2_TERM);
-	INIT_COMPLETION(writeback_pipe->comp);
+
 	mfd->dma->busy = TRUE;
 	outp32(MDP_INTR_CLEAR, INTR_OVERLAY2_DONE);
 	mdp_intr_mask |= INTR_OVERLAY2_DONE;
@@ -247,7 +246,6 @@
 	mdp_pipe_kickoff(MDP_OVERLAY2_TERM, mfd);
 	wmb();
 	pr_debug("%s: before ov done interrupt\n", __func__);
-	wait_for_completion_killable(&mfd->dma->comp);
 }
 void mdp4_writeback_dma_stop(struct msm_fb_data_type *mfd)
 {
diff --git a/drivers/video/msm/mipi_NT35510.c b/drivers/video/msm/mipi_NT35510.c
index eaf1868..964df4e 100644
--- a/drivers/video/msm/mipi_NT35510.c
+++ b/drivers/video/msm/mipi_NT35510.c
@@ -418,6 +418,7 @@
 static char video27[2] = {
 	0x35, 0x00,
 };
+static char config_video_MADCTL[2] = {0x36, 0xC0};
 static struct dsi_cmd_desc nt35510_video_display_on_cmds[] = {
 	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video0), video0},
 	{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video1), video1},
@@ -453,11 +454,15 @@
 			display_on},
 };
 
+static struct dsi_cmd_desc nt35510_video_display_on_cmds_rotate[] = {
+	{DTYPE_DCS_WRITE1, 1, 0, 0, 150,
+		sizeof(config_video_MADCTL), config_video_MADCTL},
+};
 static int mipi_nt35510_lcd_on(struct platform_device *pdev)
 {
 	struct msm_fb_data_type *mfd;
 	struct mipi_panel_info *mipi;
-
+	static int rotate;
 	mfd = platform_get_drvdata(pdev);
 	if (!mfd)
 		return -ENODEV;
@@ -467,10 +472,19 @@
 
 	mipi  = &mfd->panel_info.mipi;
 
+	if (mipi_nt35510_pdata && mipi_nt35510_pdata->rotate_panel)
+		rotate = mipi_nt35510_pdata->rotate_panel();
+
 	if (mipi->mode == DSI_VIDEO_MODE) {
 		mipi_dsi_cmds_tx(mfd, &nt35510_tx_buf,
 			nt35510_video_display_on_cmds,
 			ARRAY_SIZE(nt35510_video_display_on_cmds));
+
+		if (rotate) {
+			mipi_dsi_cmds_tx(mfd, &nt35510_tx_buf,
+				nt35510_video_display_on_cmds_rotate,
+			ARRAY_SIZE(nt35510_video_display_on_cmds_rotate));
+		}
 	} else if (mipi->mode == DSI_CMD_MODE) {
 		mipi_dsi_cmds_tx(mfd, &nt35510_tx_buf,
 			nt35510_cmd_display_on_cmds,
diff --git a/drivers/video/msm/mipi_chimei_wuxga.c b/drivers/video/msm/mipi_chimei_wuxga.c
index 7abb0d4..6ddf74d 100644
--- a/drivers/video/msm/mipi_chimei_wuxga.c
+++ b/drivers/video/msm/mipi_chimei_wuxga.c
@@ -125,7 +125,7 @@
 	pinfo->lcdc.hsync_skew = 0;
 
 	/* Backlight levels - controled via PMIC pwm gpio */
-	pinfo->bl_max = 15;
+	pinfo->bl_max = PWM_LEVEL;
 	pinfo->bl_min = 1;
 
 	/* mipi - general */
diff --git a/drivers/video/msm/mipi_chimei_wxga_pt.c b/drivers/video/msm/mipi_chimei_wxga_pt.c
index 4729d83..1ab50b7 100644
--- a/drivers/video/msm/mipi_chimei_wxga_pt.c
+++ b/drivers/video/msm/mipi_chimei_wxga_pt.c
@@ -121,7 +121,7 @@
 	pinfo->lcdc.hsync_skew = 0;
 
 	/* Backlight levels - controled via PMIC pwm gpio */
-	pinfo->bl_max = 15;
+	pinfo->bl_max = PWM_LEVEL;
 	pinfo->bl_min = 1;
 
 	/* mipi - general */
diff --git a/drivers/video/msm/mipi_renesas.c b/drivers/video/msm/mipi_renesas.c
index 6a7027a..c9dc8255 100644
--- a/drivers/video/msm/mipi_renesas.c
+++ b/drivers/video/msm/mipi_renesas.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1138,7 +1138,7 @@
 	mipi_dsi_cmds_tx(mfd, &renesas_tx_buf, renesas_display_on_cmds,
 			ARRAY_SIZE(renesas_display_on_cmds));
 
-	if (cpu_is_msm7x25a() || cpu_is_msm7x25aa()) {
+	if (cpu_is_msm7x25a() || cpu_is_msm7x25aa() || cpu_is_msm7x25ab()) {
 		mipi_dsi_cmds_tx(mfd, &renesas_tx_buf, renesas_hvga_on_cmds,
 			ARRAY_SIZE(renesas_hvga_on_cmds));
 	}
diff --git a/drivers/video/msm/mipi_tc358764_dsi2lvds.c b/drivers/video/msm/mipi_tc358764_dsi2lvds.c
index 1624534..f7f353f 100644
--- a/drivers/video/msm/mipi_tc358764_dsi2lvds.c
+++ b/drivers/video/msm/mipi_tc358764_dsi2lvds.c
@@ -188,12 +188,9 @@
 #define DEBUG01		0x05A4	/* LVDS Data */
 
 /* PWM */
-static u32 d2l_pwm_freq_hz = (66*1000);
+static u32 d2l_pwm_freq_hz = (3.921*1000);
 
-/* 1366x768 uses pwm at 66 KHZ */
-/* 1200x1920 uses pwm at 25 KHZ */
 #define PWM_FREQ_HZ	(d2l_pwm_freq_hz)
-#define PWM_LEVEL 15
 #define PWM_PERIOD_USEC (USEC_PER_SEC / PWM_FREQ_HZ)
 #define PWM_DUTY_LEVEL (PWM_PERIOD_USEC / PWM_LEVEL)
 
@@ -559,10 +556,7 @@
 	/* Set gpio#4=U/D=0, gpio#3=L/R=1 , gpio#2,1=CABC=0, gpio#0=NA. */
 	mipi_d2l_write_reg(mfd, GPIOO, d2l_gpio_out_val);
 
-	if (mfd->panel_info.xres == 1366)
-		d2l_pwm_freq_hz = (66*1000);
-	else
-		d2l_pwm_freq_hz = (25*1000);
+	d2l_pwm_freq_hz = (3.921*1000);
 
 	if (bl_level == 0)
 		bl_level = PWM_LEVEL * 2 / 3 ; /* Default ON value */
diff --git a/drivers/video/msm/mipi_tc358764_dsi2lvds.h b/drivers/video/msm/mipi_tc358764_dsi2lvds.h
index 072d1f4..1b949f0 100644
--- a/drivers/video/msm/mipi_tc358764_dsi2lvds.h
+++ b/drivers/video/msm/mipi_tc358764_dsi2lvds.h
@@ -14,6 +14,8 @@
 #ifndef MIPI_TC358764_DSI2LVDS_H
 #define MIPI_TC358764_DSI2LVDS_H
 
+#define PWM_LEVEL 255
+
 int mipi_tc358764_dsi2lvds_register(struct msm_panel_info *pinfo,
 	u32 channel_id, u32 panel_id);
 #endif  /* MIPI_TC358764_DSI2LVDS_H */
diff --git a/drivers/video/msm/mipi_toshiba.h b/drivers/video/msm/mipi_toshiba.h
index 632bbd3..4107161 100644
--- a/drivers/video/msm/mipi_toshiba.h
+++ b/drivers/video/msm/mipi_toshiba.h
@@ -21,9 +21,9 @@
 int mipi_toshiba_device_register(struct msm_panel_info *pinfo,
 					u32 channel, u32 panel);
 
-#define MIPI_TOSHIBA_PWM_FREQ_HZ 300
+#define MIPI_TOSHIBA_PWM_FREQ_HZ 3921
 #define MIPI_TOSHIBA_PWM_PERIOD_USEC (USEC_PER_SEC / MIPI_TOSHIBA_PWM_FREQ_HZ)
-#define MIPI_TOSHIBA_PWM_LEVEL 100
+#define MIPI_TOSHIBA_PWM_LEVEL 255
 #define MIPI_TOSHIBA_PWM_DUTY_LEVEL \
 	(MIPI_TOSHIBA_PWM_PERIOD_USEC / MIPI_TOSHIBA_PWM_LEVEL)
 
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index c6b0440..b4d8db0 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -1194,6 +1194,7 @@
 
 	mfd->var_xres = panel_info->xres;
 	mfd->var_yres = panel_info->yres;
+	mfd->var_frame_rate = panel_info->frame_rate;
 
 	var->pixclock = mfd->panel_info.clk_rate;
 	mfd->var_pixclock = var->pixclock;
@@ -1229,22 +1230,45 @@
 		/*
 		 * id field for fb app
 		 */
-	    id = (int *)&mfd->panel;
+	id = (int *)&mfd->panel;
 
-#if defined(CONFIG_FB_MSM_MDP22)
-	snprintf(fix->id, sizeof(fix->id), "msmfb22_%x", (__u32) *id);
-#elif defined(CONFIG_FB_MSM_MDP30)
-	snprintf(fix->id, sizeof(fix->id), "msmfb30_%x", (__u32) *id);
-#elif defined(CONFIG_FB_MSM_MDP31)
-	snprintf(fix->id, sizeof(fix->id), "msmfb31_%x", (__u32) *id);
-#elif defined(CONFIG_FB_MSM_MDP40)
-	snprintf(fix->id, sizeof(fix->id), "msmfb40_%x", (__u32) *id);
-#elif defined(CONFIG_FB_MSM_MDP_NONE)
-	snprintf(fix->id, sizeof(fix->id), "msmfb0_%x", (__u32) *id);
-#else
-	error CONFIG_FB_MSM_MDP undefined !
-#endif
-	 fbi->fbops = &msm_fb_ops;
+	switch (mdp_rev) {
+	case MDP_REV_20:
+		snprintf(fix->id, sizeof(fix->id), "msmfb20_%x", (__u32) *id);
+		break;
+	case MDP_REV_22:
+		snprintf(fix->id, sizeof(fix->id), "msmfb22_%x", (__u32) *id);
+		break;
+	case MDP_REV_30:
+		snprintf(fix->id, sizeof(fix->id), "msmfb30_%x", (__u32) *id);
+		break;
+	case MDP_REV_303:
+		snprintf(fix->id, sizeof(fix->id), "msmfb303_%x", (__u32) *id);
+		break;
+	case MDP_REV_31:
+		snprintf(fix->id, sizeof(fix->id), "msmfb31_%x", (__u32) *id);
+		break;
+	case MDP_REV_40:
+		snprintf(fix->id, sizeof(fix->id), "msmfb40_%x", (__u32) *id);
+		break;
+	case MDP_REV_41:
+		snprintf(fix->id, sizeof(fix->id), "msmfb41_%x", (__u32) *id);
+		break;
+	case MDP_REV_42:
+		snprintf(fix->id, sizeof(fix->id), "msmfb42_%x", (__u32) *id);
+		break;
+	case MDP_REV_43:
+		snprintf(fix->id, sizeof(fix->id), "msmfb43_%x", (__u32) *id);
+		break;
+	case MDP_REV_44:
+		snprintf(fix->id, sizeof(fix->id), "msmfb44_%x", (__u32) *id);
+		break;
+	default:
+		snprintf(fix->id, sizeof(fix->id), "msmfb0_%x", (__u32) *id);
+		break;
+	}
+
+	fbi->fbops = &msm_fb_ops;
 	fbi->flags = FBINFO_FLAG_DEFAULT;
 	fbi->pseudo_palette = msm_fb_pseudo_palette;
 
@@ -1736,6 +1760,27 @@
 	return 0;
 }
 
+int msm_fb_check_frame_rate(struct msm_fb_data_type *mfd
+						, struct fb_info *info)
+{
+	int panel_height, panel_width, var_frame_rate, fps_mod;
+	struct fb_var_screeninfo *var = &info->var;
+	fps_mod = 0;
+	if ((mfd->panel_info.type == DTV_PANEL) ||
+		(mfd->panel_info.type == HDMI_PANEL)) {
+		panel_height = var->yres + var->upper_margin +
+			var->vsync_len + var->lower_margin;
+		panel_width = var->xres + var->right_margin +
+			var->hsync_len + var->left_margin;
+		var_frame_rate = ((var->pixclock)/(panel_height * panel_width));
+		if (mfd->var_frame_rate != var_frame_rate) {
+			fps_mod = 1;
+			mfd->var_frame_rate = var_frame_rate;
+		}
+	}
+	return fps_mod;
+}
+
 static int msm_fb_set_par(struct fb_info *info)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
@@ -1777,7 +1822,8 @@
 		(mfd->hw_refresh && ((mfd->fb_imgType != old_imgType) ||
 				(mfd->var_pixclock != var->pixclock) ||
 				(mfd->var_xres != var->xres) ||
-				(mfd->var_yres != var->yres)))) {
+				(mfd->var_yres != var->yres) ||
+				(msm_fb_check_frame_rate(mfd, info))))) {
 		mfd->var_xres = var->xres;
 		mfd->var_yres = var->yres;
 		mfd->var_pixclock = var->pixclock;
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index 3becc46..b63c022 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -148,6 +148,7 @@
 	__u32 var_xres;
 	__u32 var_yres;
 	__u32 var_pixclock;
+	__u32 var_frame_rate;
 
 #ifdef MSM_FB_ENABLE_DBGFS
 	struct dentry *sub_dir;
@@ -210,5 +211,7 @@
 
 void fill_black_screen(void);
 void unfill_black_screen(void);
+int msm_fb_check_frame_rate(struct msm_fb_data_type *mfd,
+				struct fb_info *info);
 
 #endif /* MSM_FB_H */
diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h
index 7744e7a..9d16b7b 100644
--- a/drivers/video/msm/msm_fb_panel.h
+++ b/drivers/video/msm/msm_fb_panel.h
@@ -164,6 +164,7 @@
 	__u32 clk_max;
 	__u32 frame_count;
 	__u32 is_3d_panel;
+	__u32 frame_rate;
 
 
 	struct mddi_panel_info mddi;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
index 6ebc955..8da0995 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
@@ -252,13 +252,11 @@
 	void *ptr;
 	u32 status = VCD_S_SUCCESS;
 	DDL_MSG_HIGH("ddl_encode_start");
-	if (vidc_msg_timing) {
-		if (first_time < 2) {
-			ddl_reset_core_time_variables(ENC_OP_TIME);
-			first_time++;
-		 }
-		ddl_set_core_start_time(__func__, ENC_OP_TIME);
-	}
+	if (first_time < 2) {
+		ddl_reset_core_time_variables(ENC_OP_TIME);
+		first_time++;
+	 }
+	ddl_set_core_start_time(__func__, ENC_OP_TIME);
 	ddl_context = ddl_get_context();
 	if (!DDL_IS_INITIALIZED(ddl_context)) {
 		DDL_MSG_ERROR("ddl_enc_start:Not_inited");
@@ -300,6 +298,27 @@
 				encoder->seq_header.virtual_base_addr,
 				encoder->seq_header.buffer_size,
 				ION_IOC_CLEAN_INV_CACHES);
+	if (encoder->slice_delivery_info.enable) {
+		DDL_MSG_LOW("%s: slice mode allocate memory for struct\n",
+					__func__);
+		ptr = ddl_pmem_alloc(&encoder->batch_frame.slice_batch_in,
+				DDL_ENC_SLICE_BATCH_INPSTRUCT_SIZE,
+				DDL_LINEAR_BUFFER_ALIGN_BYTES);
+		if (ptr) {
+			ptr = ddl_pmem_alloc(
+				&encoder->batch_frame.slice_batch_out,
+				DDL_ENC_SLICE_BATCH_OUTSTRUCT_SIZE,
+				DDL_LINEAR_BUFFER_ALIGN_BYTES);
+		}
+		if (!ptr) {
+			ddl_pmem_free(&encoder->batch_frame.slice_batch_in);
+			ddl_pmem_free(&encoder->batch_frame.slice_batch_out);
+			ddl_free_enc_hw_buffers(ddl);
+			ddl_pmem_free(&encoder->seq_header);
+			DDL_MSG_ERROR("ddlEncStart:SeqHdrAllocFailed");
+			return VCD_ERR_ALLOC_FAIL;
+		}
+	}
 	if (!ddl_take_command_channel(ddl_context, ddl, client_data))
 		return VCD_ERR_BUSY;
 	ddl_vidc_channel_set(ddl);
@@ -316,10 +335,8 @@
 	u32 status = VCD_S_SUCCESS;
 
 	DDL_MSG_HIGH("ddl_decode_start");
-	if (vidc_msg_timing) {
-		ddl_reset_core_time_variables(DEC_OP_TIME);
-		ddl_reset_core_time_variables(DEC_IP_TIME);
-	}
+	ddl_reset_core_time_variables(DEC_OP_TIME);
+	ddl_reset_core_time_variables(DEC_IP_TIME);
 	ddl_context = ddl_get_context();
 	if (!DDL_IS_INITIALIZED(ddl_context)) {
 		DDL_MSG_ERROR("ddl_dec_start:Not_inited");
@@ -451,11 +468,20 @@
 	struct ddl_client_context *ddl =
 		(struct ddl_client_context *) ddl_handle;
 	struct ddl_context *ddl_context;
+	struct ddl_encoder_data *encoder =
+		&ddl->codec_data.encoder;
 	u32 vcd_status = VCD_S_SUCCESS;
+	if (encoder->slice_delivery_info.enable) {
+		return ddl_encode_frame_batch(ddl_handle,
+					input_frame,
+					output_bit,
+					1,
+					encoder->slice_delivery_info.num_slices,
+					client_data);
+	}
 
 	DDL_MSG_HIGH("ddl_encode_frame");
-	if (vidc_msg_timing)
-		ddl_set_core_start_time(__func__, ENC_OP_TIME);
+	ddl_set_core_start_time(__func__, ENC_OP_TIME);
 	ddl_context = ddl_get_context();
 	if (!DDL_IS_INITIALIZED(ddl_context)) {
 		DDL_MSG_ERROR("ddl_enc_frame:Not_inited");
@@ -519,6 +545,76 @@
 	return vcd_status;
 }
 
+u32 ddl_encode_frame_batch(u32 *ddl_handle,
+	struct ddl_frame_data_tag *input_frame,
+	struct ddl_frame_data_tag *output_bit,
+	u32 num_in_frames, u32 num_out_frames,
+	void *client_data)
+{
+	struct ddl_client_context *ddl =
+		(struct ddl_client_context *) ddl_handle;
+	struct ddl_context *ddl_context;
+	u32 vcd_status = VCD_S_SUCCESS;
+	struct ddl_encoder_data *encoder;
+
+	DDL_MSG_LOW("ddl_encode_frame_batch");
+	ddl_context = ddl_get_context();
+	if (!DDL_IS_INITIALIZED(ddl_context)) {
+		DDL_MSG_ERROR("ddl_enc_frame:Not_inited");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+	if (DDL_IS_BUSY(ddl_context)) {
+		DDL_MSG_ERROR("ddl_enc_frame:Ddl_busy");
+		return VCD_ERR_BUSY;
+	}
+	if (!ddl || ddl->decoding) {
+		DDL_MSG_ERROR("ddl_enc_frame:Bad_handle");
+	return VCD_ERR_BAD_HANDLE;
+	}
+	if (!input_frame || !input_frame->vcd_frm.physical	||
+		!input_frame->vcd_frm.data_len) {
+		DDL_MSG_ERROR("ddl_enc_frame:Bad_input_params");
+		return VCD_ERR_ILLEGAL_PARM;
+	}
+	if ((((u32) input_frame->vcd_frm.physical +
+		input_frame->vcd_frm.offset) &
+		(DDL_STREAMBUF_ALIGN_GUARD_BYTES))) {
+		DDL_MSG_ERROR("ddl_enc_frame:Un_aligned_yuv_start_address");
+		return VCD_ERR_ILLEGAL_PARM;
+	}
+	if (!output_bit || !output_bit->vcd_frm.physical ||
+		!output_bit->vcd_frm.alloc_len) {
+		DDL_MSG_ERROR("ddl_enc_frame:Bad_output_params");
+		return VCD_ERR_ILLEGAL_PARM;
+	}
+	if ((ddl->codec_data.encoder.output_buf_req.sz +
+		output_bit->vcd_frm.offset) >
+		output_bit->vcd_frm.alloc_len)
+		DDL_MSG_ERROR("ddl_enc_frame:offset_large,"
+			"Exceeds_min_buf_size");
+	if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_FRAME)) {
+		DDL_MSG_ERROR("ddl_enc_frame:Wrong_state");
+		return VCD_ERR_ILLEGAL_OP;
+	}
+	if (!ddl_take_command_channel(ddl_context, ddl, client_data))
+		return VCD_ERR_BUSY;
+	encoder = &ddl->codec_data.encoder;
+	if (encoder->slice_delivery_info.enable) {
+		DDL_MEMCPY((void *)&(encoder->batch_frame.output_frame[0]),
+			(void *)output_bit,
+			sizeof(struct ddl_frame_data_tag) * num_out_frames);
+		encoder->batch_frame.num_output_frames = num_out_frames;
+		ddl->input_frame = *input_frame;
+		vcd_status = ddl_insert_input_frame_to_pool(ddl, input_frame);
+		if (!vcd_status)
+			ddl_vidc_encode_slice_batch_run(ddl);
+		else
+			DDL_MSG_ERROR("insert to frame pool failed %u",
+					vcd_status);
+	}
+	return vcd_status;
+}
+
 u32 ddl_decode_end(u32 *ddl_handle, void *client_data)
 {
 	struct ddl_client_context *ddl =
@@ -526,10 +622,8 @@
 	struct ddl_context *ddl_context;
 
 	DDL_MSG_HIGH("ddl_decode_end");
-	if (vidc_msg_timing) {
-		ddl_reset_core_time_variables(DEC_OP_TIME);
-		ddl_reset_core_time_variables(DEC_IP_TIME);
-	}
+	ddl_reset_core_time_variables(DEC_OP_TIME);
+	ddl_reset_core_time_variables(DEC_IP_TIME);
 	ddl_context = ddl_get_context();
 	if (!DDL_IS_INITIALIZED(ddl_context)) {
 		DDL_MSG_ERROR("ddl_dec_end:Not_inited");
@@ -563,8 +657,7 @@
 	struct ddl_context *ddl_context;
 
 	DDL_MSG_HIGH("ddl_encode_end");
-	if (vidc_msg_timing)
-		ddl_reset_core_time_variables(ENC_OP_TIME);
+	ddl_reset_core_time_variables(ENC_OP_TIME);
 	ddl_context = ddl_get_context();
 	if (!DDL_IS_INITIALIZED(ddl_context)) {
 		DDL_MSG_ERROR("ddl_enc_end:Not_inited");
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index c3874fa..86f282e 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -84,6 +84,8 @@
 
 #define DDL_MAX_NUM_IN_INPUTFRAME_POOL          (DDL_MAX_NUM_OF_B_FRAME + 1)
 
+#define MDP_MIN_TILE_HEIGHT			96
+
 enum ddl_mem_area {
 	DDL_FW_MEM	= 0x0,
 	DDL_MM_MEM	= 0x1,
@@ -100,6 +102,7 @@
 	struct ion_handle *alloc_handle;
 	u32 buffer_size;
 	enum ddl_mem_area mem_type;
+	void *pil_cookie;
 };
 enum ddl_cmd_state{
 	DDL_CMD_INVALID         = 0x0,
@@ -113,6 +116,7 @@
 	DDL_CMD_ENCODE_FRAME    = 0x8,
 	DDL_CMD_EOS             = 0x9,
 	DDL_CMD_CHANNEL_END     = 0xA,
+	DDL_CMD_ENCODE_CONTINUE = 0xB,
 	DDL_CMD_32BIT           = 0x7FFFFFFF
 };
 enum ddl_client_state{
@@ -129,6 +133,7 @@
 	DDL_CLIENT_WAIT_FOR_CHEND          = 0xA,
 	DDL_CLIENT_FATAL_ERROR             = 0xB,
 	DDL_CLIENT_FAVIDC_ERROR            = 0xC,
+	DDL_CLIENT_WAIT_FOR_CONTINUE       = 0xD,
 	DDL_CLIENT_32BIT                   = 0x7FFFFFFF
 };
 struct ddl_hw_interface{
@@ -215,6 +220,15 @@
 struct ddl_codec_data_hdr{
 	u32  decoding;
 };
+struct ddl_batch_frame_data {
+	struct ddl_buf_addr slice_batch_in;
+	struct ddl_buf_addr slice_batch_out;
+	struct ddl_frame_data_tag input_frame;
+	struct ddl_frame_data_tag output_frame
+			[DDL_MAX_NUM_BFRS_FOR_SLICE_BATCH];
+	u32 num_output_frames;
+	u32 out_frm_next_frmindex;
+};
 struct ddl_encoder_data{
 	struct ddl_codec_data_hdr   hdr;
 	struct vcd_property_codec   codec;
@@ -262,6 +276,8 @@
 	u32  ext_enc_control_val;
 	u32  num_references_for_p_frame;
 	u32  closed_gop;
+	struct vcd_property_slice_delivery_info slice_delivery_info;
+	struct ddl_batch_frame_data batch_frame;
 };
 struct ddl_decoder_data {
 	struct ddl_codec_data_hdr  hdr;
@@ -303,6 +319,8 @@
 	u32  cont_mode;
 	u32  reconfig_detected;
 	u32  dmx_disable;
+	int avg_dec_time;
+	int dec_time_sum;
 };
 union ddl_codec_data{
 	struct ddl_codec_data_hdr  hdr;
@@ -344,6 +362,8 @@
 		(struct vidc_1080p_enc_seq_start_param *param);
 	void(*vidc_encode_frame_start[2])
 		(struct vidc_1080p_enc_frame_start_param *param);
+	void(*vidc_encode_slice_batch_start[2])
+		(struct vidc_1080p_enc_frame_start_param *param);
 	u32 frame_channel_depth;
 };
 struct ddl_client_context{
@@ -375,9 +395,12 @@
 void ddl_vidc_channel_end(struct ddl_client_context *);
 void ddl_vidc_encode_init_codec(struct ddl_client_context *);
 void ddl_vidc_decode_init_codec(struct ddl_client_context *);
+void ddl_vidc_encode_frame_continue(struct ddl_client_context *);
 void ddl_vidc_encode_frame_run(struct ddl_client_context *);
+void ddl_vidc_encode_slice_batch_run(struct ddl_client_context *);
 void ddl_vidc_decode_frame_run(struct ddl_client_context *);
 void ddl_vidc_decode_eos_run(struct ddl_client_context *ddl);
+void ddl_vidc_encode_eos_run(struct ddl_client_context *ddl);
 void ddl_release_context_buffers(struct ddl_context *);
 void ddl_release_client_internal_buffers(struct ddl_client_context *ddl);
 u32  ddl_vidc_decode_set_buffers(struct ddl_client_context *);
@@ -438,9 +461,10 @@
 
 u32 ddl_get_input_frame_from_pool(struct ddl_client_context *ddl,
 	u8 *input_buffer_address);
+u32 ddl_get_stream_buf_from_batch_pool(struct ddl_client_context *ddl,
+	struct ddl_frame_data_tag *stream_buffer);
 u32 ddl_insert_input_frame_to_pool(struct ddl_client_context *ddl,
 	struct ddl_frame_data_tag *ddl_input_frame);
-
 void ddl_decoder_chroma_dpb_change(struct ddl_client_context *ddl);
 u32  ddl_check_reconfig(struct ddl_client_context *ddl);
 void ddl_handle_reconfig(u32 res_change, struct ddl_client_context *ddl);
@@ -458,5 +482,9 @@
 u32 ddl_fw_init(struct ddl_buf_addr *dram_base);
 void ddl_get_fw_info(const unsigned char **fw_array_addr,
 	unsigned int *fw_size);
-void ddl_fw_release(void);
+void ddl_fw_release(struct ddl_buf_addr *);
+int ddl_vidc_decode_get_avg_time(struct ddl_client_context *ddl);
+void ddl_vidc_decode_reset_avg_time(struct ddl_client_context *ddl);
+void ddl_calc_core_proc_time(const char *func_name, u32 index,
+		struct ddl_client_context *ddl);
 #endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.h
index 433dad4..5c1ee21 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.h
@@ -62,6 +62,11 @@
 	u32 disable_static_region_as_flag;
 	u32 disable_activity_region_flag;
 };
+struct vcd_property_slice_delivery_info {
+	u32  enable;
+	u32  num_slices;
+	u32  num_slices_enc;
+};
 struct ddl_property_dec_pic_buffers{
 	struct ddl_frame_data_tag *dec_pic_buffers;
 	u32 no_of_dec_pic_buf;
@@ -94,6 +99,11 @@
 u32 ddl_encode_frame(u32 *ddl_handle,
 	struct ddl_frame_data_tag *input_frame,
 	struct ddl_frame_data_tag *output_bit, void *client_data);
+u32 ddl_encode_frame_batch(u32 *ddl_handle,
+	struct ddl_frame_data_tag *input_frame,
+	struct ddl_frame_data_tag *output_bit,
+	u32 num_in_frames, u32 num_out_frames,
+	void *client_data);
 u32 ddl_encode_end(u32 *ddl_handle, void *client_data);
 u32 ddl_decode_start(u32 *ddl_handle, struct vcd_sequence_hdr *header,
 	void *client_data);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
index a8ccebf..41604b0 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
@@ -64,13 +64,20 @@
 #define DDL_FW_INST_GLOBAL_CONTEXT_SPACE_SIZE  (DDL_KILO_BYTE(800))
 #define DDL_FW_H264DEC_CONTEXT_SPACE_SIZE      (DDL_KILO_BYTE(800))
 #define DDL_FW_H264ENC_CONTEXT_SPACE_SIZE      (DDL_KILO_BYTE(20))
-#define DDL_FW_OTHER_CONTEXT_SPACE_SIZE        (DDL_KILO_BYTE(10))
+#define DDL_FW_OTHER_CONTEXT_SPACE_SIZE        (DDL_KILO_BYTE(20))
 
 #define VCD_DEC_CPB_SIZE         (DDL_KILO_BYTE(512))
 #define DDL_DBG_CORE_DUMP_SIZE   (DDL_KILO_BYTE(10))
+#define DDL_VIDC_1080P_BASE_OFFSET_SHIFT        11
 
 #define DDL_BUFEND_PAD                    256
 #define DDL_ENC_SEQHEADER_SIZE            (512+DDL_BUFEND_PAD)
+#define DDL_ENC_SLICE_BATCH_FACTOR         5
+#define DDL_MAX_NUM_BFRS_FOR_SLICE_BATCH   8
+#define DDL_ENC_SLICE_BATCH_INPSTRUCT_SIZE (128 + \
+				32 * DDL_MAX_NUM_BFRS_FOR_SLICE_BATCH)
+#define DDL_ENC_SLICE_BATCH_OUTSTRUCT_SIZE (64 + \
+				64 * DDL_MAX_NUM_BFRS_FOR_SLICE_BATCH)
 #define DDL_MAX_BUFFER_COUNT              32
 #define DDL_MIN_BUFFER_COUNT              1
 
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index 62f0976..6d3a05a 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -353,7 +353,7 @@
 void ddl_release_context_buffers(struct ddl_context *ddl_context)
 {
 	ddl_pmem_free(&ddl_context->metadata_shared_input);
-	ddl_fw_release();
+	ddl_fw_release(&ddl_context->dram_base_a);
 }
 
 void ddl_release_client_internal_buffers(struct ddl_client_context *ddl)
@@ -375,10 +375,14 @@
 		struct ddl_encoder_data *encoder =
 			&(ddl->codec_data.encoder);
 		ddl_pmem_free(&encoder->seq_header);
+		ddl_pmem_free(&encoder->batch_frame.slice_batch_in);
+		ddl_pmem_free(&encoder->batch_frame.slice_batch_out);
 		ddl_vidc_encode_dynamic_property(ddl, false);
 		encoder->dynamic_prop_change = 0;
 		ddl_free_enc_hw_buffers(ddl);
 	}
+	ddl_pmem_free(&ddl->shared_mem[0]);
+	ddl_pmem_free(&ddl->shared_mem[1]);
 }
 
 u32 ddl_codec_type_transact(struct ddl_client_context *ddl,
@@ -651,8 +655,9 @@
 		ptr = ddl_pmem_alloc(&dec_bufs->context, buf_size.sz_context,
 			DDL_KILO_BYTE(2));
 		if (!ptr)
-			status = VCD_ERR_ALLOC_FAIL;
-		msm_ion_do_cache_op(ddl_context->video_ion_client,
+			goto fail_free_exit;
+		else
+			msm_ion_do_cache_op(ddl_context->video_ion_client,
 					dec_bufs->context.alloc_handle,
 					dec_bufs->context.virtual_base_addr,
 					dec_bufs->context.buffer_size,
@@ -663,77 +668,77 @@
 		ptr = ddl_pmem_alloc(&dec_bufs->h264_nb_ip, buf_size.sz_nb_ip,
 			DDL_KILO_BYTE(2));
 		if (!ptr)
-			status = VCD_ERR_ALLOC_FAIL;
+			goto fail_free_exit;
 	}
 	if (buf_size.sz_vert_nb_mv > 0) {
 		dec_bufs->h264_vert_nb_mv.mem_type = DDL_MM_MEM;
 		ptr = ddl_pmem_alloc(&dec_bufs->h264_vert_nb_mv,
 			buf_size.sz_vert_nb_mv, DDL_KILO_BYTE(2));
 		if (!ptr)
-			status = VCD_ERR_ALLOC_FAIL;
+			goto fail_free_exit;
 	}
 	if (buf_size.sz_nb_dcac > 0) {
 		dec_bufs->nb_dcac.mem_type = DDL_MM_MEM;
 		ptr = ddl_pmem_alloc(&dec_bufs->nb_dcac, buf_size.sz_nb_dcac,
 			DDL_KILO_BYTE(2));
 		if (!ptr)
-			status = VCD_ERR_ALLOC_FAIL;
+			goto fail_free_exit;
 	}
 	if (buf_size.sz_upnb_mv > 0) {
 		dec_bufs->upnb_mv.mem_type = DDL_MM_MEM;
 		ptr = ddl_pmem_alloc(&dec_bufs->upnb_mv, buf_size.sz_upnb_mv,
 			DDL_KILO_BYTE(2));
 		if (!ptr)
-			status = VCD_ERR_ALLOC_FAIL;
+			goto fail_free_exit;
 	}
 	if (buf_size.sz_sub_anchor_mv > 0) {
 		dec_bufs->sub_anchor_mv.mem_type = DDL_MM_MEM;
 		ptr = ddl_pmem_alloc(&dec_bufs->sub_anchor_mv,
 			buf_size.sz_sub_anchor_mv, DDL_KILO_BYTE(2));
 		if (!ptr)
-			status = VCD_ERR_ALLOC_FAIL;
+			goto fail_free_exit;
 	}
 	if (buf_size.sz_overlap_xform > 0) {
 		dec_bufs->overlay_xform.mem_type = DDL_MM_MEM;
 		ptr = ddl_pmem_alloc(&dec_bufs->overlay_xform,
 			buf_size.sz_overlap_xform, DDL_KILO_BYTE(2));
 		if (!ptr)
-			status = VCD_ERR_ALLOC_FAIL;
+			goto fail_free_exit;
 	}
 	if (buf_size.sz_bit_plane3 > 0) {
 		dec_bufs->bit_plane3.mem_type = DDL_MM_MEM;
 		ptr = ddl_pmem_alloc(&dec_bufs->bit_plane3,
 			buf_size.sz_bit_plane3, DDL_KILO_BYTE(2));
 		if (!ptr)
-			status = VCD_ERR_ALLOC_FAIL;
+			goto fail_free_exit;
 	}
 	if (buf_size.sz_bit_plane2 > 0) {
 		dec_bufs->bit_plane2.mem_type = DDL_MM_MEM;
 		ptr = ddl_pmem_alloc(&dec_bufs->bit_plane2,
 			buf_size.sz_bit_plane2, DDL_KILO_BYTE(2));
 		if (!ptr)
-			status = VCD_ERR_ALLOC_FAIL;
+			goto fail_free_exit;
 	}
 	if (buf_size.sz_bit_plane1 > 0) {
 		dec_bufs->bit_plane1.mem_type = DDL_MM_MEM;
 		ptr = ddl_pmem_alloc(&dec_bufs->bit_plane1,
 			buf_size.sz_bit_plane1, DDL_KILO_BYTE(2));
 		if (!ptr)
-			status = VCD_ERR_ALLOC_FAIL;
+			goto fail_free_exit;
 	}
 	if (buf_size.sz_stx_parser > 0) {
 		dec_bufs->stx_parser.mem_type = DDL_MM_MEM;
 		ptr = ddl_pmem_alloc(&dec_bufs->stx_parser,
 			buf_size.sz_stx_parser, DDL_KILO_BYTE(2));
 		if (!ptr)
-			status = VCD_ERR_ALLOC_FAIL;
+			goto fail_free_exit;
 	}
 	if (buf_size.sz_desc > 0) {
 		dec_bufs->desc.mem_type = DDL_MM_MEM;
 		ptr = ddl_pmem_alloc(&dec_bufs->desc, buf_size.sz_desc,
 			DDL_KILO_BYTE(2));
 		if (!ptr)
-			status = VCD_ERR_ALLOC_FAIL;
+			goto fail_free_exit;
 		else {
 			if (!res_trk_check_for_sec_session()) {
 				memset(dec_bufs->desc.align_virtual_addr,
@@ -747,8 +752,10 @@
 			}
 		}
 	}
-	if (status)
-		ddl_free_dec_hw_buffers(ddl);
+	return status;
+fail_free_exit:
+	status = VCD_ERR_ALLOC_FAIL;
+	ddl_free_dec_hw_buffers(ddl);
 	return status;
 }
 
@@ -876,66 +883,70 @@
 			ptr = ddl_pmem_alloc(&enc_bufs->mv, buf_size.sz_mv,
 				DDL_KILO_BYTE(2));
 			if (!ptr)
-				status = VCD_ERR_ALLOC_FAIL;
+				goto fail_enc_free_exit;
 		}
 		if (buf_size.sz_col_zero > 0) {
 			enc_bufs->col_zero.mem_type = DDL_MM_MEM;
 			ptr = ddl_pmem_alloc(&enc_bufs->col_zero,
 				buf_size.sz_col_zero, DDL_KILO_BYTE(2));
-		if (!ptr)
-			status = VCD_ERR_ALLOC_FAIL;
+			if (!ptr)
+				goto fail_enc_free_exit;
 		}
 		if (buf_size.sz_md > 0) {
 			enc_bufs->md.mem_type = DDL_MM_MEM;
 			ptr = ddl_pmem_alloc(&enc_bufs->md, buf_size.sz_md,
 				DDL_KILO_BYTE(2));
 			if (!ptr)
-				status = VCD_ERR_ALLOC_FAIL;
+				goto fail_enc_free_exit;
 		}
 		if (buf_size.sz_pred > 0) {
 			enc_bufs->pred.mem_type = DDL_MM_MEM;
 			ptr = ddl_pmem_alloc(&enc_bufs->pred,
 				buf_size.sz_pred, DDL_KILO_BYTE(2));
 			if (!ptr)
-				status = VCD_ERR_ALLOC_FAIL;
+				goto fail_enc_free_exit;
 		}
 		if (buf_size.sz_nbor_info > 0) {
 			enc_bufs->nbor_info.mem_type = DDL_MM_MEM;
 			ptr = ddl_pmem_alloc(&enc_bufs->nbor_info,
 				buf_size.sz_nbor_info, DDL_KILO_BYTE(2));
 			if (!ptr)
-				status = VCD_ERR_ALLOC_FAIL;
+				goto fail_enc_free_exit;
 		}
 		if (buf_size.sz_acdc_coef > 0) {
 			enc_bufs->acdc_coef.mem_type = DDL_MM_MEM;
 			ptr = ddl_pmem_alloc(&enc_bufs->acdc_coef,
 				buf_size.sz_acdc_coef, DDL_KILO_BYTE(2));
 			if (!ptr)
-				status = VCD_ERR_ALLOC_FAIL;
+				goto fail_enc_free_exit;
 		}
 		if (buf_size.sz_mb_info > 0) {
 			enc_bufs->mb_info.mem_type = DDL_MM_MEM;
 			ptr = ddl_pmem_alloc(&enc_bufs->mb_info,
 				buf_size.sz_mb_info, DDL_KILO_BYTE(2));
 			if (!ptr)
-				status = VCD_ERR_ALLOC_FAIL;
+				goto fail_enc_free_exit;
 		}
 		if (buf_size.sz_context > 0) {
 			enc_bufs->context.mem_type = DDL_MM_MEM;
 			ptr = ddl_pmem_alloc(&enc_bufs->context,
 				buf_size.sz_context, DDL_KILO_BYTE(2));
 			if (!ptr)
-				status = VCD_ERR_ALLOC_FAIL;
-			msm_ion_do_cache_op(ddl_context->video_ion_client,
+				goto fail_enc_free_exit;
+			else
+				msm_ion_do_cache_op(
+					ddl_context->video_ion_client,
 					enc_bufs->context.alloc_handle,
 					enc_bufs->context.virtual_base_addr,
 					enc_bufs->context.buffer_size,
 					ION_IOC_CLEAN_INV_CACHES);
 		}
-		if (status)
-			ddl_free_enc_hw_buffers(ddl);
 	}
 	return status;
+fail_enc_free_exit:
+	status = VCD_ERR_ALLOC_FAIL;
+	ddl_free_enc_hw_buffers(ddl);
+	return status;
 }
 
 void ddl_decoder_chroma_dpb_change(struct ddl_client_context *ddl)
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 830c777c3..5b9aea8 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
@@ -29,7 +29,11 @@
 	enum vidc_1080p_encode_frame frame_type);
 static void ddl_get_dec_profile_level(struct ddl_decoder_data *decoder,
 	u32 profile, u32 level);
-static void ddl_handle_enc_frame_done(struct ddl_client_context *ddl);
+static void ddl_handle_enc_frame_done(struct ddl_client_context *ddl,
+	u32 eos_present);
+static void ddl_handle_slice_done_slice_batch(struct ddl_client_context *ddl);
+static void ddl_handle_enc_frame_done_slice_mode(
+		struct ddl_client_context *ddl, u32 eos_present);
 
 static void ddl_fw_status_done_callback(struct ddl_context *ddl_context)
 {
@@ -113,9 +117,8 @@
 			ddl->client_state = DDL_CLIENT_WAIT_FOR_INITCODEC;
 			ddl->instance_id = instance_id;
 			if (ddl->decoding) {
-				if (vidc_msg_timing)
-					ddl_calc_core_proc_time(__func__,
-						DEC_OP_TIME);
+				ddl_calc_core_proc_time(__func__,
+						DEC_OP_TIME, ddl);
 				if (ddl->codec_data.decoder.header_in_start)
 					ddl_vidc_decode_init_codec(ddl);
 				else {
@@ -141,14 +144,13 @@
 {
 	struct ddl_encoder_data *encoder;
 
-	DDL_MSG_MED("ddl_encoder_seq_done_callback");
+	DDL_MSG_HIGH("ddl_encoder_seq_done_callback");
 	if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_INITCODECDONE)) {
 		DDL_MSG_ERROR("STATE-CRITICAL-INITCODEC");
 		ddl_client_fatal_cb(ddl);
 		return true;
 	}
-	if (vidc_msg_timing)
-		ddl_calc_core_proc_time(__func__, ENC_OP_TIME);
+	ddl_calc_core_proc_time(__func__, ENC_OP_TIME, ddl);
 	ddl->cmd_state = DDL_CMD_INVALID;
 	DDL_MSG_LOW("ddl_state_transition: %s ~~> DDL_CLIENT_WAIT_FOR_FRAME",
 	ddl_get_state_string(ddl->client_state));
@@ -245,8 +247,7 @@
 		DDL_MSG_ERROR("STATE-CRITICAL-HDDONE");
 		ddl_client_fatal_cb(ddl);
 	} else {
-		if (vidc_msg_timing)
-			ddl_calc_core_proc_time(__func__, DEC_OP_TIME);
+		ddl_calc_core_proc_time(__func__, DEC_OP_TIME, ddl);
 		ddl->cmd_state = DDL_CMD_INVALID;
 		DDL_MSG_LOW("ddl_state_transition: %s ~~>"
 			"DDL_CLIENT_WAIT_FOR_DPB",
@@ -466,10 +467,8 @@
 			DDL_MSG_LOW("ddl_state_transition: %s ~~>"
 				"DDL_CLIENT_WAIT_FOR_FRAME",
 				ddl_get_state_string(ddl->client_state));
-			if (vidc_msg_timing) {
-				ddl_calc_core_proc_time(__func__, DEC_OP_TIME);
-				ddl_reset_core_time_variables(DEC_OP_TIME);
-			}
+			ddl_calc_core_proc_time(__func__, DEC_OP_TIME, ddl);
+			ddl_reset_core_time_variables(DEC_OP_TIME);
 			ddl->client_state = DDL_CLIENT_WAIT_FOR_FRAME;
 			ddl_vidc_decode_frame_run(ddl);
 			ret_status = false;
@@ -486,60 +485,40 @@
 		&(ddl->codec_data.encoder);
 	struct vcd_frame_data *output_frame =
 		&(ddl->output_frame.vcd_frm);
-	u32 bottom_frame_tag;
+	u32 eos_present = false;
 
-	DDL_MSG_MED("ddl_encoder_frame_run_callback");
+	DDL_MSG_MED("ddl_encoder_frame_run_callback\n");
 	if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_FRAME_DONE) &&
 		!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_EOS_DONE)) {
 		DDL_MSG_ERROR("STATE-CRITICAL-ENCFRMRUN");
 		ddl_client_fatal_cb(ddl);
 	} else {
-		if (vidc_msg_timing)
-			ddl_calc_core_proc_time(__func__, ENC_OP_TIME);
+		ddl_calc_core_proc_time(__func__, ENC_OP_TIME, ddl);
 		DDL_MSG_LOW("ENC_FRM_RUN_DONE");
 		ddl->cmd_state = DDL_CMD_INVALID;
 		vidc_1080p_get_encode_frame_info(&encoder->enc_frame_info);
-		vidc_sm_get_frame_tags(&ddl->shared_mem
-			[ddl->command_channel],
-			&output_frame->ip_frm_tag, &bottom_frame_tag);
 
 		if (encoder->meta_data_enable_flag)
 			vidc_sm_get_metadata_status(&ddl->shared_mem
 				[ddl->command_channel],
 				&encoder->enc_frame_info.meta_data_exists);
 
+		if (VCD_FRAME_FLAG_EOS & ddl->input_frame.vcd_frm.flags) {
+				DDL_MSG_LOW("%s EOS detected\n", __func__);
+				eos_present = true;
+		}
+
 		if (encoder->enc_frame_info.enc_frame_size ||
 			(encoder->enc_frame_info.enc_frame ==
 			VIDC_1080P_ENCODE_FRAMETYPE_SKIPPED) ||
 			DDLCLIENT_STATE_IS(ddl,
 			DDL_CLIENT_WAIT_FOR_EOS_DONE)) {
-			u8 *input_buffer_address = NULL;
-			output_frame->data_len =
-				encoder->enc_frame_info.enc_frame_size;
-			output_frame->flags |= VCD_FRAME_FLAG_ENDOFFRAME;
-			ddl_get_encoded_frame(output_frame,
-				encoder->codec.codec,
-				encoder->enc_frame_info.enc_frame);
-			ddl_process_encoder_metadata(ddl);
-			ddl_vidc_encode_dynamic_property(ddl, false);
-			ddl->input_frame.frm_trans_end = false;
-			input_buffer_address = ddl_context->dram_base_a.\
-				align_physical_addr +
-				encoder->enc_frame_info.enc_luma_address;
-			ddl_get_input_frame_from_pool(ddl,
-				input_buffer_address);
-			ddl_context->ddl_callback(VCD_EVT_RESP_INPUT_DONE,
-				VCD_S_SUCCESS, &(ddl->input_frame),
-				sizeof(struct ddl_frame_data_tag),
-				(u32 *)ddl, ddl->client_data);
-			ddl->output_frame.frm_trans_end =
-				DDLCLIENT_STATE_IS(ddl,
-				DDL_CLIENT_WAIT_FOR_EOS_DONE) ? false : true;
-			ddl_context->ddl_callback(VCD_EVT_RESP_OUTPUT_DONE,
-				VCD_S_SUCCESS, &(ddl->output_frame),
-				sizeof(struct ddl_frame_data_tag),
-				(u32 *)ddl, ddl->client_data);
-
+			if (encoder->slice_delivery_info.enable) {
+				ddl_handle_enc_frame_done_slice_mode(ddl,
+								eos_present);
+			} else {
+				ddl_handle_enc_frame_done(ddl, eos_present);
+			}
 			if (DDLCLIENT_STATE_IS(ddl,
 				DDL_CLIENT_WAIT_FOR_EOS_DONE) &&
 				encoder->i_period.b_frames) {
@@ -547,7 +526,7 @@
 					(ddl->extra_output_buf_count >
 					encoder->i_period.b_frames)) {
 					DDL_MSG_ERROR("Invalid B frame output"
-								"buffer index");
+								  "buffer index");
 				} else {
 					struct vidc_1080p_enc_frame_start_param
 						enc_param;
@@ -581,7 +560,11 @@
 					ddl_context->vidc_encode_frame_start
 						[ddl->command_channel]
 						(&enc_param);
-				} } else {
+					}
+				} else if (eos_present &&
+					encoder->slice_delivery_info.enable) {
+					ddl_vidc_encode_eos_run(ddl);
+				} else {
 				DDL_MSG_LOW("ddl_state_transition: %s ~~>"
 					"DDL_CLIENT_WAIT_FOR_FRAME",
 					ddl_get_state_string(
@@ -885,6 +868,7 @@
 	vidc_1080p_clear_returned_channel_inst_id();
 	ddl = ddl_get_current_ddl_client_for_channel_id(ddl_context,
 			ddl_context->response_cmd_ch_id);
+	DDL_MSG_LOW("ddl_encoder_eos_done\n");
 	if (ddl == NULL) {
 		DDL_MSG_ERROR("NO_DDL_CONTEXT");
 	} else {
@@ -896,9 +880,11 @@
 				&(ddl->codec_data.encoder);
 			vidc_1080p_get_encode_frame_info(
 				&encoder->enc_frame_info);
-			ddl_handle_enc_frame_done(ddl);
+			if (!encoder->slice_delivery_info.enable) {
+				ddl_handle_enc_frame_done(ddl, true);
+				ddl->cmd_state = DDL_CMD_INVALID;
+			}
 			DDL_MSG_LOW("encoder_eos_done");
-			ddl->cmd_state = DDL_CMD_INVALID;
 			DDL_MSG_LOW("ddl_state_transition: %s ~~>"
 				"DDL_CLIENT_WAIT_FOR_FRAME",
 				ddl_get_state_string(ddl->client_state));
@@ -913,6 +899,35 @@
 	}
 }
 
+static u32 ddl_slice_done_callback(struct ddl_context *ddl_context)
+{
+	struct ddl_client_context *ddl;
+	u32 channel_inst_id;
+	u32 return_status = true;
+	DDL_MSG_LOW("ddl_sliceDoneCallback");
+	vidc_1080p_get_returned_channel_inst_id(&channel_inst_id);
+	vidc_1080p_clear_returned_channel_inst_id();
+	ddl = ddl_get_current_ddl_client_for_channel_id(ddl_context,
+			ddl_context->response_cmd_ch_id);
+	if (ddl == NULL) {
+		DDL_MSG_ERROR("NO_DDL_CONTEXT");
+		return_status = false;
+	} else if (ddl->cmd_state == DDL_CMD_ENCODE_FRAME) {
+			ddl->cmd_state = DDL_CMD_INVALID;
+			if (DDLCLIENT_STATE_IS(ddl,
+				DDL_CLIENT_WAIT_FOR_FRAME_DONE)) {
+				ddl_handle_slice_done_slice_batch(ddl);
+			} else {
+				DDL_MSG_ERROR("STATE-CRITICAL-ENCFRMRUN : %s\n",
+					 __func__);
+				ddl_client_fatal_cb(ddl);
+			}
+	} else {
+		DDL_MSG_ERROR("UNKNOWN_SLICEDONE : %s\n", __func__);
+	}
+	return return_status;
+}
+
 static u32 ddl_process_intr_status(struct ddl_context *ddl_context,
 	u32 intr_status)
 {
@@ -931,6 +946,9 @@
 	case VIDC_1080P_RISC2HOST_CMD_FRAME_DONE_RET:
 		return_status = ddl_frame_run_callback(ddl_context);
 	break;
+	case VIDC_1080P_RISC2HOST_CMD_SLICE_DONE_RET:
+		 ddl_slice_done_callback(ddl_context);
+	break;
 	case VIDC_1080P_RISC2HOST_CMD_SYS_INIT_RET:
 		ddl_sys_init_done_callback(ddl_context,
 			ddl_context->response_cmd_ch_id);
@@ -963,6 +981,8 @@
 {
 	struct ddl_context *ddl_context;
 	struct ddl_hw_interface  *ddl_hw_response;
+	struct ddl_client_context *ddl;
+	struct ddl_encoder_data *encoder;
 
 	ddl_context = ddl_get_context();
 	if (!ddl_context->core_virtual_base_addr) {
@@ -971,12 +991,37 @@
 		ddl_hw_response = &ddl_context->ddl_hw_response;
 		vidc_1080p_get_risc2host_cmd(&ddl_hw_response->cmd,
 			&ddl_hw_response->arg1, &ddl_hw_response->arg2,
-			&ddl_hw_response->arg3, &ddl_hw_response->arg4);
+			&ddl_hw_response->arg3,
+			&ddl_hw_response->arg4);
+		DDL_MSG_LOW("%s vidc_1080p_get_risc2host_cmd cmd = %u"
+			"arg1 = %u arg2 = %u arg3 = %u"
+			"arg4 = %u\n",
+			__func__, ddl_hw_response->cmd,
+			ddl_hw_response->arg1, ddl_hw_response->arg2,
+			ddl_hw_response->arg3,
+			ddl_hw_response->arg4);
+		ddl = ddl_get_current_ddl_client_for_channel_id(ddl_context,
+			ddl_context->response_cmd_ch_id);
+		if (ddl) {
+			encoder = &(ddl->codec_data.encoder);
+			if (encoder && encoder->slice_delivery_info.enable
+			&&
+			((ddl_hw_response->cmd ==
+				VIDC_1080P_RISC2HOST_CMD_SLICE_DONE_RET)
+			|| (ddl_hw_response->cmd ==
+				VIDC_1080P_RISC2HOST_CMD_FRAME_DONE_RET))) {
+				vidc_sm_set_encoder_slice_batch_int_ctrl(
+				&ddl->shared_mem[ddl->command_channel],
+				1);
+			}
+		}
 		vidc_1080p_clear_risc2host_cmd();
 		vidc_1080p_clear_interrupt();
 		vidc_1080p_get_risc2host_cmd_status(ddl_hw_response->arg2,
 			&ddl_context->cmd_err_status,
 			&ddl_context->disp_pic_err_status);
+		DDL_MSG_LOW("%s cmd_err_status = %d\n", __func__,
+				ddl_context->cmd_err_status);
 		ddl_context->response_cmd_ch_id = ddl_hw_response->arg1;
 	}
 }
@@ -1028,8 +1073,7 @@
 	input_vcd_frm->offset += dec_disp_info->input_bytes_consumed;
 	input_vcd_frm->data_len -= dec_disp_info->input_bytes_consumed;
 	ddl->input_frame.frm_trans_end = frame_transact_end;
-	if (vidc_msg_timing)
-		ddl_calc_core_proc_time(__func__, DEC_IP_TIME);
+	ddl_calc_core_proc_time(__func__, DEC_IP_TIME, ddl);
 	ddl_context->ddl_callback(VCD_EVT_RESP_INPUT_DONE, VCD_S_SUCCESS,
 		&ddl->input_frame, sizeof(struct ddl_frame_data_tag),
 		(u32 *)ddl, ddl->client_data);
@@ -1233,8 +1277,7 @@
 		}
 		output_vcd_frm->flags |= VCD_FRAME_FLAG_ENDOFFRAME;
 		output_frame->frm_trans_end = frame_transact_end;
-		if (vidc_msg_timing)
-			ddl_calc_core_proc_time(__func__, DEC_OP_TIME);
+		ddl_calc_core_proc_time(__func__, DEC_OP_TIME, ddl);
 		ddl_process_decoder_metadata(ddl);
 		vidc_sm_get_aspect_ratio_info(
 			&ddl->shared_mem[ddl->command_channel],
@@ -1638,39 +1681,214 @@
 	decoder->level.level = level;
 }
 
-static void ddl_handle_enc_frame_done(struct ddl_client_context *ddl)
+static void ddl_handle_enc_frame_done(struct ddl_client_context *ddl,
+					u32 eos_present)
 {
 	struct ddl_context       *ddl_context = ddl->ddl_context;
 	struct ddl_encoder_data  *encoder = &(ddl->codec_data.encoder);
 	struct vcd_frame_data    *output_frame = &(ddl->output_frame.vcd_frm);
 	u32 bottom_frame_tag;
-	u8  *input_buffer_address = NULL;
+	u8 *input_buffer_address = NULL;
 
 	vidc_sm_get_frame_tags(&ddl->shared_mem[ddl->command_channel],
 		&output_frame->ip_frm_tag, &bottom_frame_tag);
 	output_frame->data_len = encoder->enc_frame_info.enc_frame_size;
 	output_frame->flags |= VCD_FRAME_FLAG_ENDOFFRAME;
 	(void)ddl_get_encoded_frame(output_frame,
-		encoder->codec.codec, encoder->enc_frame_info.enc_frame);
+		encoder->codec.codec, encoder->enc_frame_info.enc_frame
+								);
 	ddl_process_encoder_metadata(ddl);
 	ddl_vidc_encode_dynamic_property(ddl, false);
 	ddl->input_frame.frm_trans_end = false;
 	input_buffer_address = ddl_context->dram_base_a.align_physical_addr +
 			encoder->enc_frame_info.enc_luma_address;
 	ddl_get_input_frame_from_pool(ddl, input_buffer_address);
-
 	ddl_context->ddl_callback(VCD_EVT_RESP_INPUT_DONE,
-		VCD_S_SUCCESS, &(ddl->input_frame),
-		sizeof(struct ddl_frame_data_tag),
-		(u32 *) ddl, ddl->client_data);
-
-	ddl->output_frame.frm_trans_end =
-		DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_EOS_DONE)
-			? false : true;
-
+					VCD_S_SUCCESS, &(ddl->input_frame),
+					sizeof(struct ddl_frame_data_tag),
+					(u32 *) ddl, ddl->client_data);
+	ddl->output_frame.frm_trans_end = eos_present ?
+		false : true;
 	ddl_context->ddl_callback(VCD_EVT_RESP_OUTPUT_DONE,
-		VCD_S_SUCCESS, &(ddl->output_frame),
-		sizeof(struct ddl_frame_data_tag),
-		(u32 *) ddl, ddl->client_data);
+				VCD_S_SUCCESS, &(ddl->output_frame),
+				sizeof(struct ddl_frame_data_tag),
+				(u32 *) ddl, ddl->client_data);
+}
 
+static void ddl_handle_slice_done_slice_batch(struct ddl_client_context *ddl)
+{
+	struct ddl_context       *ddl_context = ddl->ddl_context;
+	struct ddl_encoder_data  *encoder = &(ddl->codec_data.encoder);
+	struct vcd_frame_data    *output_frame = NULL;
+	u32 bottom_frame_tag;
+	struct vidc_1080p_enc_slice_batch_out_param *slice_output = NULL;
+	u32 num_slices_comp = 0;
+	u32 index = 0;
+	u32 start_bfr_idx = 0;
+	u32 actual_idx = 0;
+
+	DDL_MSG_LOW("%s\n", __func__);
+	vidc_sm_get_num_slices_comp(
+			&ddl->shared_mem[ddl->command_channel],
+			&num_slices_comp);
+	slice_output = (struct vidc_1080p_enc_slice_batch_out_param *)
+		(encoder->batch_frame.slice_batch_out.align_virtual_addr);
+	DDL_MSG_LOW(" after get no of slices = %d\n", num_slices_comp);
+	if (slice_output == NULL)
+		DDL_MSG_ERROR(" slice_output is NULL\n");
+	encoder->slice_delivery_info.num_slices_enc += num_slices_comp;
+	if (vidc_msg_timing) {
+		ddl_calc_core_proc_time_cnt(__func__, ENC_SLICE_OP_TIME,
+					num_slices_comp);
+		ddl_set_core_start_time(__func__, ENC_SLICE_OP_TIME);
+	}
+	DDL_MSG_LOW("%s : Slices Completed %d Total slices %d OutBfrInfo:"
+			"Cmd %d Size %d\n",
+			__func__,
+			num_slices_comp,
+			encoder->slice_delivery_info.num_slices_enc,
+			slice_output->cmd_type,
+			slice_output->output_size);
+	start_bfr_idx = encoder->batch_frame.out_frm_next_frmindex;
+	for (index = 0; index < num_slices_comp; index++) {
+		actual_idx =
+		slice_output->slice_info[start_bfr_idx+index].stream_buffer_idx;
+		DDL_MSG_LOW("Slice Info: OutBfrIndex %d SliceSize %d\n",
+			actual_idx,
+			slice_output->slice_info[start_bfr_idx+index].
+			stream_buffer_size);
+		output_frame = &(
+			encoder->batch_frame.output_frame[actual_idx].vcd_frm);
+		DDL_MSG_LOW("OutBfr: vcd_frm 0x%x frmbfr(virtual) 0x%x"
+			"frmbfr(physical) 0x%x\n",
+			&output_frame,
+			output_frame.virtual_base_addr,
+			output_frame.physical_base_addr);
+		vidc_1080p_get_encode_frame_info(&encoder->enc_frame_info);
+		vidc_sm_get_frame_tags(&ddl->shared_mem
+			[ddl->command_channel],
+			&output_frame->ip_frm_tag, &bottom_frame_tag);
+		ddl_get_encoded_frame(output_frame,
+				encoder->codec.codec,
+				encoder->enc_frame_info.enc_frame);
+		output_frame->data_len =
+			slice_output->slice_info[actual_idx].stream_buffer_size;
+		ddl->output_frame =
+			encoder->batch_frame.output_frame[actual_idx];
+		ddl->output_frame.frm_trans_end = false;
+		ddl_context->ddl_callback(VCD_EVT_RESP_OUTPUT_DONE,
+				VCD_S_SUCCESS, &(ddl->output_frame),
+				sizeof(struct ddl_frame_data_tag),
+				(u32 *) ddl, ddl->client_data);
+		ddl->input_frame.frm_trans_end = false;
+		DDL_MSG_LOW("%s Set i/p o/p transactions to false\n", __func__);
+	}
+	encoder->batch_frame.out_frm_next_frmindex = start_bfr_idx + index;
+	ddl->cmd_state = DDL_CMD_ENCODE_FRAME;
+	vidc_sm_set_encoder_slice_batch_int_ctrl(
+			&ddl->shared_mem[ddl->command_channel],
+			0);
+}
+
+static void ddl_handle_enc_frame_done_slice_mode(
+		struct ddl_client_context *ddl, u32 eos_present)
+{
+	struct ddl_context       *ddl_context = ddl->ddl_context;
+	struct ddl_encoder_data  *encoder = &(ddl->codec_data.encoder);
+	struct vcd_frame_data    *output_frame = NULL;
+	u32 bottom_frame_tag;
+	u8 *input_buffer_address = NULL;
+	struct vidc_1080p_enc_slice_batch_out_param *slice_output = NULL;
+	u32 num_slices_comp = 0;
+	u32 index = 0;
+	u32 start_bfr_idx = 0;
+	u32 actual_idx = 0;
+	struct vcd_transc *transc;
+
+	DDL_MSG_LOW("%s\n", __func__);
+	vidc_sm_get_num_slices_comp(
+				&ddl->shared_mem[ddl->command_channel],
+				&num_slices_comp);
+	slice_output = (struct vidc_1080p_enc_slice_batch_out_param *)
+		encoder->batch_frame.slice_batch_out.align_virtual_addr;
+	encoder->slice_delivery_info.num_slices_enc += num_slices_comp;
+	if (vidc_msg_timing) {
+		ddl_calc_core_proc_time_cnt(__func__, ENC_OP_TIME,
+					num_slices_comp);
+	}
+	DDL_MSG_LOW("%s Slices Completed %d Total slices done = %d"
+		" OutBfrInfo: Cmd %d Size %d",
+		__func__,
+		num_slices_comp,
+		encoder->slice_delivery_info.num_slices_enc,
+		slice_output->cmd_type,
+		slice_output->output_size);
+	start_bfr_idx = encoder->batch_frame.out_frm_next_frmindex;
+	if ((encoder->slice_delivery_info.num_slices_enc %
+		encoder->batch_frame.num_output_frames) != 0) {
+		DDL_MSG_ERROR("ERROR : %d %d\n",
+		encoder->slice_delivery_info.num_slices_enc,
+		encoder->batch_frame.num_output_frames);
+	}
+	for (index = 0; index < num_slices_comp; index++) {
+		actual_idx =
+			slice_output->slice_info[start_bfr_idx+index]. \
+			stream_buffer_idx;
+		DDL_MSG_LOW("Slice Info: OutBfrIndex %d SliceSize %d",
+			actual_idx,
+			slice_output->slice_info[start_bfr_idx+index]. \
+			stream_buffer_size, 0);
+		output_frame =
+		&(encoder->batch_frame.output_frame[actual_idx].vcd_frm);
+		DDL_MSG_LOW("OutBfr: vcd_frm 0x%x frmbfr(virtual) 0x%x"
+				"frmbfr(physical) 0x%x",
+				&output_frame,
+				output_frame.virtual_base_addr,
+				output_frame.physical_base_addr);
+		vidc_1080p_get_encode_frame_info(
+			&encoder->enc_frame_info);
+		vidc_sm_get_frame_tags(&ddl->shared_mem
+			[ddl->command_channel],
+			&output_frame->ip_frm_tag, &bottom_frame_tag);
+		ddl_get_encoded_frame(output_frame,
+				encoder->codec.codec,
+				encoder->enc_frame_info.enc_frame);
+		output_frame->data_len =
+			slice_output->slice_info[actual_idx].stream_buffer_size;
+		ddl->output_frame =
+			encoder->batch_frame.output_frame[actual_idx];
+		DDL_MSG_LOW(" %s actual_idx = %d"
+		"encoder->batch_frame.num_output_frames = %d\n", __func__,
+		actual_idx, encoder->batch_frame.num_output_frames);
+		if (encoder->batch_frame.num_output_frames == (actual_idx+1)) {
+			output_frame->flags |= VCD_FRAME_FLAG_ENDOFFRAME;
+			ddl_vidc_encode_dynamic_property(ddl, false);
+			ddl->input_frame.frm_trans_end = true;
+			DDL_MSG_LOW("%s End of frame detected\n", __func__);
+			input_buffer_address =
+				ddl_context->dram_base_a.align_physical_addr +
+				encoder->enc_frame_info.enc_luma_address;
+			ddl_get_input_frame_from_pool(ddl,
+				input_buffer_address);
+			transc = (struct vcd_transc *)(ddl->client_data);
+			if (eos_present)
+				ddl->output_frame.frm_trans_end = false;
+			else
+				ddl->output_frame.frm_trans_end = true;
+		}
+		DDL_MSG_LOW("%s Before output done cb\n", __func__);
+		transc = (struct vcd_transc *)(ddl->client_data);
+		ddl->output_frame.vcd_frm = *output_frame;
+		ddl_context->ddl_callback(VCD_EVT_RESP_OUTPUT_DONE,
+				VCD_S_SUCCESS, &(ddl->output_frame),
+				sizeof(struct ddl_frame_data_tag),
+				(u32 *) ddl, ddl->client_data);
+	}
+	if (encoder->batch_frame.num_output_frames == (actual_idx+1)) {
+		DDL_MSG_LOW("%s sending input done\n", __func__);
+		ddl_context->ddl_callback(VCD_EVT_RESP_INPUT_DONE,
+				VCD_S_SUCCESS, &(ddl->input_frame),
+				sizeof(struct ddl_frame_data_tag),
+				(u32 *) ddl, ddl->client_data);
+	}
 }
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index 7b284e9..363fe53 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -287,6 +287,9 @@
 				ddl_set_default_decoder_buffer_req(decoder,
 					true);
 			}
+			DDL_MSG_LOW("set  VCD_I_FRAME_SIZE width = %d"
+				" height = %d\n",
+				frame_size->width, frame_size->height);
 			vcd_status = VCD_S_SUCCESS;
 		}
 	}
@@ -608,7 +611,15 @@
 		struct vcd_property_multi_slice *multi_slice =
 			(struct vcd_property_multi_slice *)
 				property_value;
-
+		DDL_MSG_HIGH("VCD_I_MULTI_SLICE eMSliceSel %d  nMSliceSize %d"
+				"Tot#of MB %d encoder->frame_size.width = %d"
+				"encoder->frame_size.height = %d",
+				(int)multi_slice->m_slice_sel,
+				multi_slice->m_slice_size,
+				DDL_NO_OF_MB(encoder->frame_size.width,
+					encoder->frame_size.height),
+				encoder->frame_size.width,
+				encoder->frame_size.height);
 		switch (multi_slice->m_slice_sel) {
 		case VCD_MSLICE_OFF:
 			vcd_status = VCD_S_SUCCESS;
@@ -618,11 +629,14 @@
 				vcd_status = VCD_S_SUCCESS;
 		break;
 		case VCD_MSLICE_BY_MB_COUNT:
-			if (multi_slice->m_slice_size >= 1 &&
+		{
+			if ((multi_slice->m_slice_size >= 1) &&
 				(multi_slice->m_slice_size <=
 				DDL_NO_OF_MB(encoder->frame_size.width,
-				encoder->frame_size.height)))
+					encoder->frame_size.height))) {
 				vcd_status = VCD_S_SUCCESS;
+			}
+		}
 		break;
 		case VCD_MSLICE_BY_BYTE_COUNT:
 			if (multi_slice->m_slice_size > 0)
@@ -850,6 +864,9 @@
 			encoder->client_output_buf_req.sz =
 				DDL_ALIGN(buffer_req->sz,
 				DDL_KILO_BYTE(4));
+			DDL_MSG_LOW("%s encoder->client_output_buf_req.sz"
+				"  = %d\n", __func__,
+				encoder->client_output_buf_req.sz);
 			vcd_status = VCD_S_SUCCESS;
 		}
 	}
@@ -920,8 +937,14 @@
 	case VCD_I_METADATA_HEADER:
 		DDL_MSG_LOW("Meta Data Interface is Requested");
 		if (!res_trk_check_for_sec_session()) {
-			vcd_status = ddl_set_metadata_params(ddl,
-				property_hdr, property_value);
+			if (!encoder->slice_delivery_info.enable) {
+				vcd_status = ddl_set_metadata_params(ddl,
+						property_hdr, property_value);
+			} else {
+				DDL_MSG_ERROR("Ignoring meta data settting in "
+					"slice mode: %s\n", __func__);
+				vcd_status = VCD_S_SUCCESS;
+			}
 		} else {
 			DDL_MSG_ERROR("Meta Data Interface is not "
 				"supported in secure session");
@@ -946,6 +969,70 @@
 		}
 		break;
 	}
+	case VCD_I_SLICE_DELIVERY_MODE:
+	{
+		size_t output_buf_size;
+		u32 num_mb, num_slices;
+		struct vcd_property_hdr slice_property_hdr;
+		struct vcd_property_meta_data_enable slice_meta_data;
+		DDL_MSG_HIGH("Set property VCD_I_SLICE_DELIVERY_MODE\n");
+		if (sizeof(u32) == property_hdr->sz &&
+			encoder->codec.codec == VCD_CODEC_H264 &&
+			encoder->multi_slice.m_slice_sel
+				 == VCD_MSLICE_BY_MB_COUNT &&
+			DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_OPEN)) {
+			encoder->slice_delivery_info.enable
+				= *(u32 *)property_value;
+			DDL_MSG_HIGH("set encoder->slice_delivery_mode"
+				"  = %u\n",
+				encoder->slice_delivery_info.enable);
+			output_buf_size =
+				encoder->client_output_buf_req.sz;
+			num_mb = DDL_NO_OF_MB(encoder->frame_size.width,
+					encoder->frame_size.height);
+			num_slices = num_mb/
+				encoder->multi_slice.m_slice_size;
+			num_slices = ((num_mb - num_slices *
+				encoder->multi_slice.m_slice_size) > 0)
+				? (num_slices + 1) : num_slices;
+			encoder->slice_delivery_info.num_slices =
+				num_slices;
+			if (num_slices <= DDL_MAX_NUM_BFRS_FOR_SLICE_BATCH) {
+				encoder->client_output_buf_req.min_count
+				= ((DDL_ENC_SLICE_BATCH_FACTOR * num_slices + 2)
+				> DDL_MAX_BUFFER_COUNT)
+				? DDL_MAX_BUFFER_COUNT :
+				(DDL_ENC_SLICE_BATCH_FACTOR * num_slices + 2);
+				output_buf_size =
+				encoder->client_output_buf_req.sz/num_slices;
+				encoder->client_output_buf_req.sz =
+				DDL_ALIGN(output_buf_size, DDL_KILO_BYTE(4));
+				encoder->output_buf_req =
+				encoder->client_output_buf_req;
+				DDL_MSG_HIGH("%s num_mb = %u num_slices = %u "
+				"output_buf_count = %u "
+				"output_buf_size = %u aligned size = %u\n",
+				__func__, num_mb, num_slices,
+				encoder->client_output_buf_req.min_count,
+				output_buf_size,
+				encoder->client_output_buf_req.sz);
+				slice_property_hdr.prop_id =
+					VCD_I_METADATA_ENABLE;
+				slice_property_hdr.sz =
+				sizeof(struct vcd_property_meta_data_enable);
+				ddl_get_metadata_params(ddl,
+						&slice_property_hdr,
+						&slice_meta_data);
+				slice_meta_data.meta_data_enable_flag
+					&= ~VCD_METADATA_ENC_SLICE;
+				ddl_set_metadata_params(ddl,
+						&slice_property_hdr,
+						&slice_meta_data);
+				vcd_status = VCD_S_SUCCESS;
+			}
+		}
+		break;
+	}
 	case VCD_REQ_PERF_LEVEL:
 		vcd_status = VCD_S_SUCCESS;
 		break;
@@ -1354,7 +1441,10 @@
 			property_hdr->sz) {
 				*(struct vcd_buffer_requirement *)
 			property_value = encoder->client_output_buf_req;
-				vcd_status = VCD_S_SUCCESS;
+			DDL_MSG_LOW("%s encoder->client_output_buf_req = %d\n",
+				 __func__,
+				encoder->client_output_buf_req.sz);
+			vcd_status = VCD_S_SUCCESS;
 		}
 	break;
 	case VCD_I_BUFFER_FORMAT:
@@ -1421,6 +1511,14 @@
 			vcd_status = VCD_S_SUCCESS;
 		}
 	break;
+	case VCD_I_SLICE_DELIVERY_MODE:
+		if (sizeof(struct vcd_property_slice_delivery_info) ==
+			property_hdr->sz) {
+			*(struct vcd_property_slice_delivery_info *)
+				property_value = encoder->slice_delivery_info;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
 	default:
 		vcd_status = VCD_ERR_ILLEGAL_OP;
 		break;
@@ -1579,6 +1677,9 @@
 		encoder->closed_gop = true;
 	ddl_set_default_metadata_flag(ddl);
 	ddl_set_default_encoder_buffer_req(encoder);
+	encoder->slice_delivery_info.enable = 0;
+	encoder->slice_delivery_info.num_slices = 0;
+	encoder->slice_delivery_info.num_slices_enc = 0;
 }
 
 static void ddl_set_default_enc_profile(struct ddl_encoder_data *encoder)
@@ -1725,8 +1826,7 @@
 	encoder->client_input_buf_req = encoder->input_buf_req;
 	memset(&encoder->output_buf_req , 0 ,
 		sizeof(struct vcd_buffer_requirement));
-	encoder->output_buf_req.min_count    =
-		encoder->i_period.b_frames + 2;
+	encoder->output_buf_req.min_count = encoder->i_period.b_frames + 2;
 	encoder->output_buf_req.actual_count =
 		encoder->output_buf_req.min_count + 3;
 	encoder->output_buf_req.max_count    = DDL_MAX_BUFFER_COUNT;
@@ -1737,6 +1837,8 @@
 		DDL_ALIGN(y_cb_cr_size, DDL_KILO_BYTE(4));
 	ddl_set_default_encoder_metadata_buffer_size(encoder);
 	encoder->client_output_buf_req = encoder->output_buf_req;
+	DDL_MSG_LOW("%s encoder->client_output_buf_req.sz = %d\n",
+		__func__, encoder->client_output_buf_req.sz);
 }
 
 u32 ddl_set_default_decoder_buffer_req(struct ddl_decoder_data *decoder,
@@ -1753,7 +1855,7 @@
 		if (!decoder->cont_mode)
 			min_dpb = ddl_decoder_min_num_dpb(decoder);
 		else
-			min_dpb = 5;
+			min_dpb = res_trk_get_min_dpb_count();
 		frame_size = &decoder->client_frame_size;
 		output_buf_req = &decoder->client_output_buf_req;
 		input_buf_req = &decoder->client_input_buf_req;
@@ -1767,6 +1869,19 @@
 		input_buf_req = &decoder->actual_input_buf_req;
 		min_dpb = decoder->min_dpb_num;
 		y_cb_cr_size = decoder->y_cb_cr_size;
+		if ((decoder->buf_format.buffer_format ==
+			VCD_BUFFER_FORMAT_TILE_4x2) &&
+			(frame_size->height < MDP_MIN_TILE_HEIGHT)) {
+			frame_size->height = MDP_MIN_TILE_HEIGHT;
+			ddl_calculate_stride(frame_size,
+				!decoder->progressive_only);
+			y_cb_cr_size = ddl_get_yuv_buffer_size(
+				frame_size,
+				&decoder->buf_format,
+				(!decoder->progressive_only),
+				decoder->hdr.decoding, NULL);
+		} else
+			y_cb_cr_size = decoder->y_cb_cr_size;
 	}
 	memset(output_buf_req, 0,
 		sizeof(struct vcd_buffer_requirement));
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index cce779e..ac81916 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -156,6 +156,24 @@
 #define VIDC_SM_NEW_I_PERIOD_VALUE_BMASK       0xffffffff
 #define VIDC_SM_NEW_I_PERIOD_VALUE_SHFT        0
 
+#define VIDC_SM_BATCH_INPUT_ADDR                                  0x00a4
+#define VIDC_SM_BATCH_INPUT_ADDR_VALUE_BMSK                       0xffffffff
+#define VIDC_SM_BATCH_INPUT_ADDRL_VALUE_SHFT                      0
+#define VIDC_SM_BATCH_OUTPUT_ADDR                                 0x00a8
+#define VIDC_SM_BATCH_OUTPUT_ADDR_VALUE_BMSK                      0xffffffff
+#define VIDC_SM_BATCH_OUTPUT_ADDR_VALUE_SHFT                      0
+#define VIDC_SM_BATCH_OUTPUT_SIZE_ADDR                            0x00ac
+#define VIDC_SM_BATCH_OUTPUT_SIZE_VALUE_BMSK                      0xffffffff
+#define VIDC_SM_BATCH_OUTPUT_SIZE_VALUE_SHFT                      0
+#define VIDC_SM_ENC_SLICE_BATCH_INT_CTRL_ADDR                     0x01c8
+#define VIDC_SM_ENC_SLICE_BATCH_INT_CTRL_VALUE_BMSK               0x1
+#define VIDC_SM_ENC_SLICE_BATCH_INT_CTRL_VALUE_SHFT               0
+#define VIDC_SM_ENC_NUM_OF_SLICE_ADDR                             0x01cc
+#define VIDC_SM_ENC_NUM_OF_SLICE_VALUE_BMSK                       0xffffffff
+#define VIDC_SM_ENC_NUM_OF_SLICE_VALUE_SHFT                       0
+#define VIDC_SM_ENC_NUM_OF_SLICE_COMP_ADDR                        0x01d0
+#define VIDC_SM_ENC_NUM_OF_SLICE_COMP_VALUE_BMSK                  0xffffffff
+#define VIDC_SM_ENC_NUM_OF_SLICE_COMP_VALUE_SHFT                  0
 
 #define VIDC_SM_ALLOCATED_LUMA_DPB_SIZE_ADDR               0x0064
 #define VIDC_SM_ALLOCATED_CHROMA_DPB_SIZE_ADDR             0x0068
@@ -799,3 +817,48 @@
 			VIDC_SM_EXTENDED_PAR_HEIGHT_SHFT);
 	}
 }
+
+void vidc_sm_set_encoder_slice_batch_int_ctrl(struct ddl_buf_addr *shared_mem,
+	u32 slice_batch_int_enable)
+{
+	u32 slice_batch_int_ctrl = VIDC_SETFIELD((slice_batch_int_enable) ?
+				1 : 0,
+				VIDC_SM_ENC_EXT_CTRL_HEC_ENABLE_SHFT,
+				VIDC_SM_ENC_EXT_CTRL_HEC_ENABLE_BMSK);
+	DDL_MEM_WRITE_32(shared_mem,
+			VIDC_SM_ENC_SLICE_BATCH_INT_CTRL_ADDR,
+			slice_batch_int_ctrl);
+}
+
+void vidc_sm_get_num_slices_comp(struct ddl_buf_addr *shared_mem,
+	u32 *num_slices_comp)
+{
+	*num_slices_comp = DDL_MEM_READ_32(shared_mem,
+				VIDC_SM_ENC_NUM_OF_SLICE_COMP_ADDR);
+}
+
+void vidc_sm_set_encoder_batch_config(struct ddl_buf_addr *shared_mem,
+				u32 num_slices,
+				u32 input_addr, u32 output_addr,
+				u32 output_buffer_size)
+{
+	DDL_MEM_WRITE_32(shared_mem,
+			VIDC_SM_ENC_NUM_OF_SLICE_ADDR,
+			num_slices);
+	DDL_MEM_WRITE_32(shared_mem,
+			VIDC_SM_BATCH_INPUT_ADDR,
+			input_addr);
+	DDL_MEM_WRITE_32(shared_mem,
+			VIDC_SM_BATCH_OUTPUT_ADDR,
+			output_addr);
+	DDL_MEM_WRITE_32(shared_mem,
+			VIDC_SM_BATCH_OUTPUT_SIZE_ADDR,
+			output_buffer_size);
+}
+
+void vidc_sm_get_encoder_batch_output_size(struct ddl_buf_addr *shared_mem,
+	u32 *output_buffer_size)
+{
+	*output_buffer_size = DDL_MEM_READ_32(shared_mem,
+			VIDC_SM_BATCH_OUTPUT_SIZE_ADDR);
+}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index b0e6758..7d9896f 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -181,4 +181,14 @@
 	enum vidc_sm_num_stuff_bytes_consume_info consume_info);
 void vidc_sm_get_aspect_ratio_info(struct ddl_buf_addr *shared_mem,
 	struct vcd_aspect_ratio *aspect_ratio_info);
+void vidc_sm_set_encoder_slice_batch_int_ctrl(struct ddl_buf_addr *shared_mem,
+	u32 slice_batch_int_enable);
+void vidc_sm_get_num_slices_comp(struct ddl_buf_addr *shared_mem,
+	u32 *num_slices_comp);
+void vidc_sm_set_encoder_batch_config(struct ddl_buf_addr *shared_mem,
+				u32 num_slices,
+				u32 input_addr, u32 output_addr,
+				u32 output_buffer_size);
+void vidc_sm_get_encoder_batch_output_size(struct ddl_buf_addr *shared_mem,
+	u32 *output_buffer_size);
 #endif
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 126698c..260cd72 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
@@ -11,7 +11,9 @@
  *
  */
 #include <linux/memory_alloc.h>
+#include <linux/delay.h>
 #include <mach/msm_subsystem_map.h>
+#include <mach/peripheral-loader.h>
 #include "vcd_ddl_utils.h"
 #include "vcd_ddl.h"
 #include "vcd_res_tracker_api.h"
@@ -46,6 +48,9 @@
 	unsigned long ionflag = 0;
 	unsigned long flags = 0;
 	int ret = 0;
+	ion_phys_addr_t phyaddr = 0;
+	size_t len = 0;
+	int rc = 0;
 	DBG_PMEM("\n%s() IN: Requested alloc size(%u)", __func__, (u32)sz);
 	if (!addr) {
 		DDL_MSG_ERROR("\n%s() Invalid Parameters", __func__);
@@ -86,28 +91,42 @@
 				goto free_ion_alloc;
 		}
 		addr->virtual_base_addr = (u8 *) kernel_vaddr;
-		ret = ion_map_iommu(ddl_context->video_ion_client,
-				addr->alloc_handle,
-				VIDEO_DOMAIN,
-				VIDEO_MAIN_POOL,
-				SZ_4K,
-				0,
-				&iova,
-				&buffer_size,
-				UNCACHED, 0);
-		if (ret) {
-			DDL_MSG_ERROR("%s():DDL ION ion map iommu failed\n",
-						 __func__);
-			goto unmap_ion_alloc;
+		if (res_trk_check_for_sec_session()) {
+			rc = ion_phys(ddl_context->video_ion_client,
+				addr->alloc_handle, &phyaddr,
+					&len);
+			if (rc || !phyaddr) {
+				DDL_MSG_ERROR(
+				"%s():DDL ION client physical failed\n",
+				__func__);
+				goto unmap_ion_alloc;
+			}
+			addr->alloced_phys_addr = phyaddr;
+		} else {
+			ret = ion_map_iommu(ddl_context->video_ion_client,
+					addr->alloc_handle,
+					VIDEO_DOMAIN,
+					VIDEO_MAIN_POOL,
+					SZ_4K,
+					0,
+					&iova,
+					&buffer_size,
+					UNCACHED, 0);
+			if (ret) {
+				DDL_MSG_ERROR(
+				"%s():DDL ION ion map iommu failed\n",
+				 __func__);
+				goto unmap_ion_alloc;
+			}
+			addr->alloced_phys_addr = (phys_addr_t) iova;
 		}
-		addr->alloced_phys_addr = (phys_addr_t) iova;
 		if (!addr->alloced_phys_addr) {
 			DDL_MSG_ERROR("%s():DDL ION client physical failed\n",
-						 __func__);
+						__func__);
 			goto unmap_ion_alloc;
 		}
 		addr->mapped_buffer = NULL;
-		addr->physical_base_addr = (u8 *) iova;
+		addr->physical_base_addr = (u8 *) addr->alloced_phys_addr;
 		addr->align_physical_addr = (u8 *) DDL_ALIGN((u32)
 			addr->physical_base_addr, alignment);
 		offset = (u32)(addr->align_physical_addr -
@@ -185,10 +204,12 @@
 		if (!IS_ERR_OR_NULL(addr->alloc_handle)) {
 			ion_unmap_kernel(ddl_context->video_ion_client,
 					addr->alloc_handle);
-			ion_unmap_iommu(ddl_context->video_ion_client,
+			if (!res_trk_check_for_sec_session()) {
+				ion_unmap_iommu(ddl_context->video_ion_client,
 					addr->alloc_handle,
 					VIDEO_DOMAIN,
 					VIDEO_MAIN_POOL);
+			}
 			ion_free(ddl_context->video_ion_client,
 				addr->alloc_handle);
 			}
@@ -332,23 +353,67 @@
 
 u32 ddl_fw_init(struct ddl_buf_addr *dram_base)
 {
-
 	u8 *dest_addr;
-
 	dest_addr = DDL_GET_ALIGNED_VITUAL(*dram_base);
-	if (vidc_video_codec_fw_size > dram_base->buffer_size ||
-		!vidc_video_codec_fw)
-		return false;
 	DDL_MSG_LOW("FW Addr / FW Size : %x/%d", (u32)vidc_video_codec_fw,
 		vidc_video_codec_fw_size);
-	memcpy(dest_addr, vidc_video_codec_fw,
-		vidc_video_codec_fw_size);
+	if (res_trk_check_for_sec_session() && res_trk_is_cp_enabled()) {
+		if (res_trk_enable_footswitch()) {
+			pr_err("Failed to enable footswitch");
+			return false;
+		}
+		if (res_trk_enable_iommu_clocks()) {
+			res_trk_disable_footswitch();
+			pr_err("Failed to enable iommu clocks\n");
+			return false;
+		}
+		dram_base->pil_cookie = pil_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");
+			return false;
+		}
+	} else {
+		if (vidc_video_codec_fw_size > dram_base->buffer_size ||
+				!vidc_video_codec_fw)
+			return false;
+		memcpy(dest_addr, vidc_video_codec_fw,
+				vidc_video_codec_fw_size);
+	}
 	return true;
 }
 
-void ddl_fw_release(void)
+void ddl_fw_release(struct ddl_buf_addr *dram_base)
 {
-	res_trk_close_secure_session();
+	void *cookie = dram_base->pil_cookie;
+	if (res_trk_is_cp_enabled() &&
+		res_trk_check_for_sec_session()) {
+		res_trk_close_secure_session();
+		if (IS_ERR_OR_NULL(cookie)) {
+			pr_err("Invalid params");
+		return;
+	}
+	if (res_trk_enable_footswitch()) {
+		pr_err("Failed to enable footswitch");
+		return;
+	}
+	if (res_trk_enable_iommu_clocks()) {
+		res_trk_disable_footswitch();
+		pr_err("Failed to enable iommu clocks\n");
+		return;
+	}
+	pil_put(cookie);
+	if (res_trk_disable_iommu_clocks())
+		pr_err("Failed to disable iommu clocks\n");
+	if (res_trk_disable_footswitch())
+		pr_err("Failed to disable footswitch\n");
+	} else {
+	if (res_trk_check_for_sec_session())
+		res_trk_close_secure_session();
+		res_trk_release_fw_addr();
+	}
 }
 
 void ddl_set_core_start_time(const char *func_name, u32 index)
@@ -361,13 +426,45 @@
 	if (!time_data->ddl_t1) {
 		time_data->ddl_t1 = act_time;
 		DDL_MSG_LOW("\n%s(): Start Time (%u)", func_name, act_time);
-	} else {
+	} else if (vidc_msg_timing) {
 		DDL_MSG_TIME("\n%s(): Timer already started! St(%u) Act(%u)",
 			func_name, time_data->ddl_t1, act_time);
 	}
 }
 
-void ddl_calc_core_proc_time(const char *func_name, u32 index)
+void ddl_calc_core_proc_time(const char *func_name, u32 index,
+			struct ddl_client_context *ddl)
+{
+	struct time_data *time_data = &proc_time[index];
+	struct ddl_decoder_data *decoder = NULL;
+	if (time_data->ddl_t1) {
+		int ddl_t2;
+		struct timeval ddl_tv;
+		do_gettimeofday(&ddl_tv);
+		ddl_t2 = (ddl_tv.tv_sec * 1000) + (ddl_tv.tv_usec / 1000);
+		time_data->ddl_ttotal += (ddl_t2 - time_data->ddl_t1);
+		time_data->ddl_count++;
+		if (vidc_msg_timing) {
+			DDL_MSG_TIME("\n%s(): cnt(%u) End Time (%u)"
+				"Diff(%u) Avg(%u)",
+				func_name, time_data->ddl_count, ddl_t2,
+				ddl_t2 - time_data->ddl_t1,
+				time_data->ddl_ttotal/time_data->ddl_count);
+		}
+		if ((index == DEC_OP_TIME) && (time_data->ddl_count > 2) &&
+					(time_data->ddl_count < 6)) {
+			decoder = &(ddl->codec_data.decoder);
+			decoder->dec_time_sum = decoder->dec_time_sum +
+				ddl_t2 - time_data->ddl_t1;
+			if (time_data->ddl_count == 5)
+				decoder->avg_dec_time =
+					decoder->dec_time_sum / 3;
+		}
+		time_data->ddl_t1 = 0;
+	}
+}
+
+void ddl_calc_core_proc_time_cnt(const char *func_name, u32 index, u32 count)
 {
 	struct time_data *time_data = &proc_time[index];
 	if (time_data->ddl_t1) {
@@ -376,7 +473,7 @@
 		do_gettimeofday(&ddl_tv);
 		ddl_t2 = (ddl_tv.tv_sec * 1000) + (ddl_tv.tv_usec / 1000);
 		time_data->ddl_ttotal += (ddl_t2 - time_data->ddl_t1);
-		time_data->ddl_count++;
+		time_data->ddl_count += count;
 		DDL_MSG_TIME("\n%s(): cnt(%u) End Time (%u) Diff(%u) Avg(%u)",
 			func_name, time_data->ddl_count, ddl_t2,
 			ddl_t2 - time_data->ddl_t1,
@@ -385,9 +482,37 @@
 	}
 }
 
+void ddl_update_core_start_time(const char *func_name, u32 index)
+{
+	u32 act_time;
+	struct timeval ddl_tv;
+	struct time_data *time_data = &proc_time[index];
+	do_gettimeofday(&ddl_tv);
+	act_time = (ddl_tv.tv_sec * 1000) + (ddl_tv.tv_usec / 1000);
+	time_data->ddl_t1 = act_time;
+	DDL_MSG_LOW("\n%s(): Start time updated Act(%u)",
+				func_name, act_time);
+}
+
 void ddl_reset_core_time_variables(u32 index)
 {
 	proc_time[index].ddl_t1 = 0;
 	proc_time[index].ddl_ttotal = 0;
 	proc_time[index].ddl_count = 0;
 }
+
+int ddl_get_core_decode_proc_time(u32 *ddl_handle)
+{
+	int avg_time = 0;
+	struct ddl_client_context *ddl =
+		(struct ddl_client_context *) ddl_handle;
+	avg_time = ddl_vidc_decode_get_avg_time(ddl);
+	return avg_time;
+}
+
+void ddl_reset_avg_dec_time(u32 *ddl_handle)
+{
+	struct ddl_client_context *ddl =
+		(struct ddl_client_context *) ddl_handle;
+	ddl_vidc_decode_reset_avg_time(ddl);
+}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
index 10b3404..bbde7ae 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
@@ -24,6 +24,7 @@
 	DEC_OP_TIME,
 	DEC_IP_TIME,
 	ENC_OP_TIME,
+	ENC_SLICE_OP_TIME,
 	MAX_TIME_DATA
 };
 
@@ -65,9 +66,13 @@
 
 #define DDL_MIN(x, y)  ((x < y) ? x : y)
 #define DDL_MAX(x, y)  ((x > y) ? x : y)
+#define DDL_MEMCPY(dest, src, len)  memcpy((dest), (src), (len))
+#define DDL_MEMSET(src, value, len) memset((src), (value), (len))
 
 void ddl_set_core_start_time(const char *func_name, u32 index);
-void ddl_calc_core_proc_time(const char *func_name, u32 index);
 void ddl_reset_core_time_variables(u32 index);
-
+void ddl_calc_core_proc_time_cnt(const char *func_name, u32 index, u32 count);
+void ddl_update_core_start_time(const char *func_name, u32 index);
+int ddl_get_core_decode_proc_time(u32 *ddl_handle);
+void ddl_reset_avg_dec_time(u32 *ddl_handle);
 #endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index 66e129c..97c8d0d 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -21,6 +21,7 @@
 #else
 #define DDL_PIX_CACHE_ENABLE  true
 #endif
+static unsigned int run_cnt;
 
 void ddl_vidc_core_init(struct ddl_context *ddl_context)
 {
@@ -57,6 +58,10 @@
 		vidc_1080p_encode_frame_start_ch0;
 	ddl_context->vidc_encode_frame_start[1] =
 		vidc_1080p_encode_frame_start_ch1;
+	ddl_context->vidc_encode_slice_batch_start[0] =
+		vidc_1080p_encode_slice_batch_start_ch0;
+	ddl_context->vidc_encode_slice_batch_start[1] =
+		vidc_1080p_encode_slice_batch_start_ch1;
 	vidc_1080p_release_sw_reset();
 	ddl_context->pix_cache_enable = DDL_PIX_CACHE_ENABLE;
 	if (ddl_context->pix_cache_enable) {
@@ -106,8 +111,7 @@
 	u32 pix_cache_ctrl, ctxt_mem_offset, ctxt_mem_size;
 
 	if (ddl->decoding) {
-		if (vidc_msg_timing)
-			ddl_set_core_start_time(__func__, DEC_OP_TIME);
+		ddl_set_core_start_time(__func__, DEC_OP_TIME);
 		vcd_codec = &(ddl->codec_data.decoder.codec.codec);
 		pix_cache_ctrl = (u32)dec_pix_cache;
 		ctxt_mem_offset = DDL_ADDR_OFFSET(ddl_context->dram_base_a,
@@ -192,8 +196,7 @@
 	struct vidc_1080p_dec_seq_start_param seq_start_param;
 	u32 seq_size;
 
-	if (vidc_msg_timing)
-		ddl_set_core_start_time(__func__, DEC_OP_TIME);
+	ddl_set_core_start_time(__func__, DEC_OP_TIME);
 	vidc_1080p_set_decode_mpeg4_pp_filter(decoder->post_filter.post_filter);
 	vidc_sm_set_concealment_color(&ddl->shared_mem[ddl->command_channel],
 		DDL_CONCEALMENT_Y_COLOR, DDL_CONCEALMENT_C_COLOR);
@@ -515,6 +518,29 @@
 		i_multi_slice_size, i_multi_slice_byte);
 }
 
+static void ddl_vidc_encode_set_batch_slice_info(
+	struct ddl_client_context *ddl)
+{
+	struct ddl_context *ddl_context = ddl->ddl_context;
+	struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
+	DDL_MSG_LOW("%s\n", __func__);
+	encoder->batch_frame.slice_batch_out.buffer_size =
+					encoder->output_buf_req.sz;
+	DDL_MSG_LOW("encoder->batch_frame.slice_batch_out.buffer_size = %d\n",
+			encoder->batch_frame.slice_batch_out.buffer_size);
+	vidc_sm_set_encoder_batch_config(
+			&ddl->shared_mem[ddl->command_channel],
+			1,
+			DDL_ADDR_OFFSET(ddl_context->dram_base_a,
+			encoder->batch_frame.slice_batch_in),
+			DDL_ADDR_OFFSET(ddl_context->dram_base_a,
+			encoder->batch_frame.slice_batch_out),
+			encoder->batch_frame.slice_batch_out.buffer_size);
+	vidc_sm_set_encoder_slice_batch_int_ctrl(
+			&ddl->shared_mem[ddl->command_channel],
+			0);
+}
+
 void ddl_vidc_encode_init_codec(struct ddl_client_context *ddl)
 {
 	struct ddl_context *ddl_context = ddl->ddl_context;
@@ -724,6 +750,7 @@
 	u32 dpb_addr_y[4], dpb_addr_c[4];
 	u32 index, y_addr, c_addr;
 
+	DDL_MSG_LOW("%s\n", __func__);
 	ddl_vidc_encode_set_metadata_output_buf(ddl);
 
 	encoder->enc_frame_info.meta_data_exists = false;
@@ -769,6 +796,7 @@
 	if (encoder->intra_frame_insertion)
 		encoder->intra_frame_insertion = false;
 	enc_param.input_flush = false;
+	enc_param.slice_enable = false;
 		vidc_sm_set_encoder_vop_time(
 			&ddl->shared_mem[ddl->command_channel], true,
 			encoder->vop_timing.vop_time_resolution,
@@ -800,6 +828,142 @@
 		&enc_param);
 }
 
+void ddl_vidc_encode_frame_continue(struct ddl_client_context *ddl)
+{
+	struct ddl_context *ddl_context = ddl->ddl_context;
+	struct vcd_frame_data *input_vcd_frm = &(ddl->input_frame.vcd_frm);
+	u32 address_offset;
+	address_offset = (u32)(ddl->output_frame.vcd_frm.physical -
+			ddl_context->dram_base_a.align_physical_addr) >>
+			DDL_VIDC_1080P_BASE_OFFSET_SHIFT;
+	DDL_MSG_LOW("%s\n", __func__);
+	if (VCD_FRAME_FLAG_EOS & input_vcd_frm->flags)
+		ddl->client_state = DDL_CLIENT_WAIT_FOR_EOS_DONE;
+	else
+		ddl->client_state = DDL_CLIENT_WAIT_FOR_FRAME_DONE;
+	ddl->cmd_state = DDL_CMD_ENCODE_CONTINUE;
+	vidc_1080p_set_host2risc_cmd(VIDC_1080P_HOST2RISC_CMD_CONTINUE_ENC,
+		address_offset,
+		0, 0, 0);
+}
+
+void ddl_vidc_encode_slice_batch_run(struct ddl_client_context *ddl)
+{
+	struct vidc_1080p_enc_frame_start_param enc_param;
+	struct ddl_context *ddl_context = ddl->ddl_context;
+	struct ddl_encoder_data  *encoder = &(ddl->codec_data.encoder);
+	struct ddl_enc_buffers *enc_buffers = &(encoder->hw_bufs);
+	struct vcd_frame_data *input_vcd_frm =
+		&(ddl->input_frame.vcd_frm);
+	u32 dpb_addr_y[4], dpb_addr_c[4];
+	u32 index, y_addr, c_addr;
+	u32 bitstream_size;
+	struct vidc_1080p_enc_slice_batch_in_param *slice_batch_in =
+		(struct vidc_1080p_enc_slice_batch_in_param *)
+		encoder->batch_frame.slice_batch_in.align_virtual_addr;
+	DDL_MSG_LOW("%s\n", __func__);
+	DDL_MEMSET(slice_batch_in, 0,
+		sizeof(struct vidc_1080p_enc_slice_batch_in_param));
+	DDL_MEMSET(encoder->batch_frame.slice_batch_in.align_virtual_addr, 0,
+		sizeof(struct vidc_1080p_enc_slice_batch_in_param));
+	encoder->batch_frame.out_frm_next_frmindex = 0;
+	bitstream_size = encoder->batch_frame.output_frame[0].vcd_frm.alloc_len;
+	encoder->output_buf_req.sz = bitstream_size;
+	y_addr = DDL_OFFSET(ddl_context->dram_base_b.align_physical_addr,
+			input_vcd_frm->physical);
+	c_addr = (y_addr + encoder->input_buf_size.size_y);
+	enc_param.encode = VIDC_1080P_ENC_TYPE_SLICE_BATCH_START;
+	DDL_MSG_LOW("ddl_state_transition: %s ~~>"
+		"DDL_CLIENT_WAIT_FOR_FRAME_DONE",
+		ddl_get_state_string(ddl->client_state));
+	slice_batch_in->cmd_type = VIDC_1080P_ENC_TYPE_SLICE_BATCH_START;
+	ddl->client_state = DDL_CLIENT_WAIT_FOR_FRAME_DONE;
+	ddl->cmd_state = DDL_CMD_ENCODE_FRAME;
+	vidc_1080p_set_encode_circular_intra_refresh(
+		encoder->intra_refresh.cir_mb_number);
+	ddl_vidc_encode_set_multi_slice_info(encoder);
+	enc_param.cmd_seq_num = ++ddl_context->cmd_seq_num;
+	enc_param.inst_id = ddl->instance_id;
+	enc_param.shared_mem_addr_offset = DDL_ADDR_OFFSET(
+			ddl_context->dram_base_a,
+			ddl->shared_mem[ddl->command_channel]);
+	enc_param.current_y_addr_offset = y_addr;
+	enc_param.current_c_addr_offset = c_addr;
+	enc_param.stream_buffer_size = bitstream_size;
+	slice_batch_in->num_stream_buffer =
+		encoder->batch_frame.num_output_frames;
+	slice_batch_in->stream_buffer_size = bitstream_size;
+	DDL_MSG_LOW("%s slice_batch_in->num_stream_buffer = %u size = %u\n",
+			 __func__, slice_batch_in->num_stream_buffer,
+			slice_batch_in->stream_buffer_size);
+	for (index = 0; index < encoder->batch_frame.num_output_frames;
+		index++) {
+		slice_batch_in->stream_buffer_addr_offset[index] =
+		((DDL_OFFSET(ddl_context->dram_base_b.align_physical_addr,
+		encoder->batch_frame.output_frame[index].vcd_frm.physical)) >>
+			DDL_VIDC_1080P_BASE_OFFSET_SHIFT);
+	}
+	slice_batch_in->input_size = VIDC_1080P_SLICE_BATCH_IN_SIZE(index);
+	enc_param.intra_frame = encoder->intra_frame_insertion;
+	if (encoder->intra_frame_insertion)
+		encoder->intra_frame_insertion = false;
+	enc_param.input_flush = false;
+	enc_param.slice_enable =
+		encoder->slice_delivery_info.enable;
+	vidc_sm_set_encoder_vop_time(
+			&ddl->shared_mem[ddl->command_channel], true,
+			encoder->vop_timing.vop_time_resolution,
+			ddl->input_frame.frm_delta);
+	vidc_sm_set_frame_tag(&ddl->shared_mem[ddl->command_channel],
+			ddl->input_frame.vcd_frm.ip_frm_tag);
+	DDL_MSG_LOW("%sdpb_count = %d\n", __func__, enc_buffers->dpb_count);
+	if (ddl_context->pix_cache_enable) {
+		for (index = 0; index < enc_buffers->dpb_count;
+			index++) {
+			dpb_addr_y[index] =
+				(u32) VIDC_1080P_DEC_DPB_RESET_VALUE;
+			dpb_addr_c[index] = (u32) enc_buffers->dpb_c
+				[index].align_physical_addr;
+		}
+
+		dpb_addr_y[index] = (u32) input_vcd_frm->physical;
+		dpb_addr_c[index] = (u32) input_vcd_frm->physical +
+				encoder->input_buf_size.size_y;
+
+		vidc_pix_cache_init_luma_chroma_base_addr(
+			enc_buffers->dpb_count + 1, dpb_addr_y, dpb_addr_c);
+		vidc_pix_cache_set_frame_size(encoder->frame_size.width,
+			encoder->frame_size.height);
+		vidc_pix_cache_set_frame_range(enc_buffers->sz_dpb_y,
+			enc_buffers->sz_dpb_c);
+		vidc_pix_cache_clear_cache_tags();
+	}
+	if ((!encoder->rc_level.frame_level_rc) &&
+		(!encoder->rc_level.mb_level_rc)) {
+		encoder->session_qp.p_frame_qp++;
+		if (encoder->session_qp.p_frame_qp > encoder->qp_range.max_qp)
+			encoder->session_qp.p_frame_qp =
+						encoder->qp_range.min_qp;
+		vidc_sm_set_pand_b_frame_qp(
+			&ddl->shared_mem[ddl->command_channel],
+				encoder->session_qp.b_frame_qp,
+				encoder->session_qp.p_frame_qp);
+	}
+
+	if (vidc_msg_timing) {
+		if (run_cnt < 2) {
+			ddl_reset_core_time_variables(ENC_OP_TIME);
+			ddl_reset_core_time_variables(ENC_SLICE_OP_TIME);
+			run_cnt++;
+		 }
+		ddl_update_core_start_time(__func__, ENC_SLICE_OP_TIME);
+		ddl_set_core_start_time(__func__, ENC_OP_TIME);
+	}
+	ddl_vidc_encode_set_batch_slice_info(ddl);
+	ddl_context->vidc_encode_slice_batch_start[ddl->command_channel] (
+			&enc_param);
+}
+
 u32 ddl_vidc_decode_set_buffers(struct ddl_client_context *ddl)
 {
 	struct ddl_context *ddl_context = ddl->ddl_context;
@@ -827,8 +991,7 @@
 #ifdef DDL_BUF_LOG
 	ddl_list_buffers(ddl);
 #endif
-	if (vidc_msg_timing)
-		ddl_set_core_start_time(__func__, DEC_OP_TIME);
+	ddl_set_core_start_time(__func__, DEC_OP_TIME);
 	ddl_decoder_dpb_transact(decoder, NULL, DDL_DPB_OP_INIT);
 	if (ddl_decoder_dpb_init(ddl) == VCD_ERR_FAIL)
 		return VCD_ERR_FAIL;
@@ -875,10 +1038,8 @@
 	struct ddl_mask *dpb_mask = &ddl->codec_data.decoder.dpb_mask;
 	struct vidc_1080p_dec_frame_start_param dec_param;
 	u32 dpb_addr_y[32], index;
-	if (vidc_msg_timing) {
-		ddl_set_core_start_time(__func__, DEC_OP_TIME);
-		ddl_set_core_start_time(__func__, DEC_IP_TIME);
-	}
+	ddl_set_core_start_time(__func__, DEC_OP_TIME);
+	ddl_set_core_start_time(__func__, DEC_IP_TIME);
 	if ((!bit_stream->data_len) || (!bit_stream->physical)) {
 		ddl_vidc_decode_eos_run(ddl);
 		return;
@@ -976,3 +1137,44 @@
 	ddl_context->vidc_decode_frame_start[ddl->command_channel] (
 		&dec_param);
 }
+
+void ddl_vidc_encode_eos_run(struct ddl_client_context *ddl)
+{
+	struct vidc_1080p_enc_frame_start_param enc_param;
+	struct ddl_context *ddl_context = ddl->ddl_context;
+	struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
+	DDL_MSG_LOW("%s\n", __func__);
+	ddl->client_state = DDL_CLIENT_WAIT_FOR_EOS_DONE;
+	ddl_vidc_encode_dynamic_property(ddl, true);
+	ddl->client_state = DDL_CMD_EOS;
+	DDL_MEMSET(&enc_param, 0, sizeof(enc_param));
+	enc_param.encode = VIDC_1080P_ENC_TYPE_LAST_FRAME_DATA;
+	enc_param.cmd_seq_num = ++ddl_context->cmd_seq_num;
+	enc_param.inst_id = ddl->instance_id;
+	enc_param.shared_mem_addr_offset =
+		DDL_ADDR_OFFSET(ddl_context->dram_base_a,
+		ddl->shared_mem[ddl->command_channel]);
+	enc_param.current_y_addr_offset = 0;
+	enc_param.current_c_addr_offset = 0;
+	enc_param.stream_buffer_size = 0;
+	enc_param.intra_frame = encoder->intra_frame_insertion;
+	vidc_sm_set_frame_tag(&ddl->shared_mem[ddl->command_channel],
+				ddl->input_frame.vcd_frm.ip_frm_tag);
+	ddl_context->vidc_encode_frame_start[ddl->command_channel](
+						&enc_param);
+}
+
+int ddl_vidc_decode_get_avg_time(struct ddl_client_context *ddl)
+{
+	int avg_time = 0;
+	struct ddl_decoder_data *decoder = &(ddl->codec_data.decoder);
+	avg_time = decoder->avg_dec_time;
+	return avg_time;
+}
+
+void ddl_vidc_decode_reset_avg_time(struct ddl_client_context *ddl)
+{
+	struct ddl_decoder_data *decoder = &(ddl->codec_data.decoder);
+	decoder->avg_dec_time = 0;
+	decoder->dec_time_sum = 0;
+}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vidc.c b/drivers/video/msm/vidc/1080p/ddl/vidc.c
index 75014cc..d399847 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vidc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -77,6 +77,10 @@
 #define VIDC_1080P_ENC_TYPE_FRAME_DATA       0x00020000
 #define VIDC_1080P_ENC_TYPE_LAST_FRAME_DATA  0x00030000
 
+#define VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_BMSK   0x00004000
+#define VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_SHFT   14
+#define VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_BMSK      0x80000000
+#define VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_SHFT      31
 #define VIDC_1080P_MAX_INTRA_PERIOD 0xffff
 
 u8 *VIDC_BASE_PTR;
@@ -779,6 +783,7 @@
 void vidc_1080p_encode_frame_start_ch0(
 	struct vidc_1080p_enc_frame_start_param *param)
 {
+	u32 input_flush;
 	VIDC_HWIO_OUT(REG_695082, VIDC_1080P_RISC2HOST_CMD_EMPTY);
 	VIDC_HWIO_OUT(REG_666957, VIDC_1080P_INIT_CH_INST_ID);
 	VIDC_HWIO_OUT(REG_117192,
@@ -791,8 +796,15 @@
 		VIDC_1080P_BASE_OFFSET_SHIFT);
 	VIDC_HWIO_OUT(REG_190381, param->intra_frame);
 	VIDC_HWIO_OUT(REG_889944, param->shared_mem_addr_offset);
-	VIDC_HWIO_OUT(REG_404623, param->input_flush);
+	input_flush = VIDC_SETFIELD(param->input_flush,
+			VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_SHFT,
+			VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_BMSK);
+	input_flush |= VIDC_SETFIELD(param->slice_enable,
+			VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_SHFT,
+			VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_BMSK);
+	VIDC_HWIO_OUT(REG_404623, input_flush);
 	VIDC_HWIO_OUT(REG_397087, param->cmd_seq_num);
+
 	VIDC_HWIO_OUT(REG_666957, (u32)param->encode |
 		param->inst_id);
 }
@@ -800,7 +812,7 @@
 void vidc_1080p_encode_frame_start_ch1(
 	struct vidc_1080p_enc_frame_start_param *param)
 {
-
+	u32 input_flush;
 	VIDC_HWIO_OUT(REG_695082, VIDC_1080P_RISC2HOST_CMD_EMPTY);
 	VIDC_HWIO_OUT(REG_313350, VIDC_1080P_INIT_CH_INST_ID);
 	VIDC_HWIO_OUT(REG_980194,
@@ -813,12 +825,71 @@
 		VIDC_1080P_BASE_OFFSET_SHIFT);
 	VIDC_HWIO_OUT(REG_887095, param->intra_frame);
 	VIDC_HWIO_OUT(REG_652528, param->shared_mem_addr_offset);
-	VIDC_HWIO_OUT(REG_404623, param->input_flush);
+	input_flush = VIDC_SETFIELD(param->input_flush,
+			VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_SHFT,
+			VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_BMSK);
+	input_flush |= VIDC_SETFIELD(param->slice_enable,
+			VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_SHFT,
+			VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_BMSK);
+
+	VIDC_HWIO_OUT(REG_404623, input_flush);
 	VIDC_HWIO_OUT(REG_254093, param->cmd_seq_num);
 	VIDC_HWIO_OUT(REG_313350, (u32)param->encode |
 		param->inst_id);
 }
 
+void vidc_1080p_encode_slice_batch_start_ch0(
+	struct vidc_1080p_enc_frame_start_param *param)
+{
+	u32 input_flush;
+	VIDC_HWIO_OUT(REG_695082, VIDC_1080P_RISC2HOST_CMD_EMPTY);
+	VIDC_HWIO_OUT(REG_666957, VIDC_1080P_INIT_CH_INST_ID);
+	VIDC_HWIO_OUT(REG_612810, param->current_y_addr_offset >>
+		VIDC_1080P_BASE_OFFSET_SHIFT);
+	VIDC_HWIO_OUT(REG_175608, param->current_c_addr_offset >>
+		VIDC_1080P_BASE_OFFSET_SHIFT);
+	VIDC_HWIO_OUT(REG_190381, param->intra_frame);
+	VIDC_HWIO_OUT(REG_889944, param->shared_mem_addr_offset);
+	input_flush = VIDC_SETFIELD(param->input_flush,
+			VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_SHFT,
+			VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_BMSK);
+	input_flush |= VIDC_SETFIELD(param->slice_enable,
+			VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_SHFT,
+			VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_BMSK);
+	VIDC_HWIO_OUT(REG_404623, input_flush);
+	VIDC_HWIO_OUT(REG_397087, param->cmd_seq_num);
+
+	VIDC_HWIO_OUT(REG_666957, (u32)param->encode |
+		param->inst_id);
+
+}
+
+void vidc_1080p_encode_slice_batch_start_ch1(
+	struct vidc_1080p_enc_frame_start_param *param)
+{
+	u32 input_flush;
+	VIDC_HWIO_OUT(REG_695082, VIDC_1080P_RISC2HOST_CMD_EMPTY);
+	VIDC_HWIO_OUT(REG_313350, VIDC_1080P_INIT_CH_INST_ID);
+	VIDC_HWIO_OUT(REG_655721, param->current_y_addr_offset >>
+		VIDC_1080P_BASE_OFFSET_SHIFT);
+	VIDC_HWIO_OUT(REG_548308,  param->current_c_addr_offset >>
+		VIDC_1080P_BASE_OFFSET_SHIFT);
+	VIDC_HWIO_OUT(REG_887095, param->intra_frame);
+	VIDC_HWIO_OUT(REG_652528, param->shared_mem_addr_offset);
+	input_flush = VIDC_SETFIELD(param->input_flush,
+			VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_SHFT,
+			VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_BMSK);
+	input_flush |= VIDC_SETFIELD(param->slice_enable,
+			VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_SHFT,
+			VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_BMSK);
+
+	VIDC_HWIO_OUT(REG_404623, input_flush);
+	VIDC_HWIO_OUT(REG_254093, param->cmd_seq_num);
+	VIDC_HWIO_OUT(REG_313350, (u32)param->encode |
+		param->inst_id);
+
+}
+
 void vidc_1080p_set_encode_picture(u32 number_p, u32 number_b)
 {
 	u32 picture, ifrm_ctrl;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vidc.h b/drivers/video/msm/vidc/1080p/ddl/vidc.h
index 7573ee8..7460ef3 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vidc.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vidc.h
@@ -21,11 +21,13 @@
 #define VIDC_1080P_RISC2HOST_CMD_CLOSE_CH_RET        2
 #define VIDC_1080P_RISC2HOST_CMD_SEQ_DONE_RET        4
 #define VIDC_1080P_RISC2HOST_CMD_FRAME_DONE_RET      5
+#define VIDC_1080P_RISC2HOST_CMD_SLICE_DONE_RET      6
 #define VIDC_1080P_RISC2HOST_CMD_ENC_COMPLETE_RET    7
 #define VIDC_1080P_RISC2HOST_CMD_SYS_INIT_RET        8
 #define VIDC_1080P_RISC2HOST_CMD_FW_STATUS_RET       9
 #define VIDC_1080P_RISC2HOST_CMD_FLUSH_COMMAND_RET  12
 #define VIDC_1080P_RISC2HOST_CMD_ABORT_RET          13
+#define VIDC_1080P_RISC2HOST_CMD_BATCH_ENC_RET      14
 #define VIDC_1080P_RISC2HOST_CMD_INIT_BUFFERS_RET   15
 #define VIDC_1080P_RISC2HOST_CMD_EDFU_INT_RET       16
 #define VIDC_1080P_RISC2HOST_CMD_ERROR_RET          32
@@ -188,7 +190,9 @@
 #define VIDC_1080P_ITLB_MISS_EXCEPTION_HANDLER        0x100
 #define VIDC_1080P_DATA_PAGE_FAULT_EXCEPTION_HANDLER  0x200
 #define VIDC_1080P_INST_PAGE_FAULT_EXCEPTION_HANDLER  0x400
-
+#define VIDC_1080P_SLICE_BATCH_MAX_STRM_BFR           8
+#define VIDC_1080P_SLICE_BATCH_IN_SIZE(idx)           (4 * sizeof(u32) + \
+							idx * sizeof(u32))
 enum vidc_1080p_reset{
 	VIDC_1080P_RESET_IN_SEQ_FIRST_STAGE   = 0x0,
 	VIDC_1080P_RESET_IN_SEQ_SECOND_STAGE  = 0x1,
@@ -318,10 +322,11 @@
 	VIDC_1080P_DEC_TYPE_32BIT            = 0x7FFFFFFF
 };
 enum vidc_1080p_encode{
-	VIDC_1080P_ENC_TYPE_SEQ_HEADER       = 0x00010000,
-	VIDC_1080P_ENC_TYPE_FRAME_DATA       = 0x00020000,
-	VIDC_1080P_ENC_TYPE_LAST_FRAME_DATA  = 0x00030000,
-	VIDC_1080P_ENC_TYPE_32BIT            = 0x7FFFFFFF
+	VIDC_1080P_ENC_TYPE_SEQ_HEADER        = 0x00010000,
+	VIDC_1080P_ENC_TYPE_FRAME_DATA        = 0x00020000,
+	VIDC_1080P_ENC_TYPE_LAST_FRAME_DATA   = 0x00030000,
+	VIDC_1080P_ENC_TYPE_SLICE_BATCH_START = 0x00070000,
+	VIDC_1080P_ENC_TYPE_32BIT             = 0x7FFFFFFF
 };
 struct vidc_1080p_dec_seq_start_param{
 	u32 cmd_seq_num;
@@ -391,6 +396,7 @@
 	u32 stream_buffer_size;
 	u32 intra_frame;
 	u32 input_flush;
+	u32 slice_enable;
 	enum vidc_1080p_encode encode;
 };
 struct vidc_1080p_enc_frame_info{
@@ -402,6 +408,23 @@
 	enum vidc_1080p_encode_frame enc_frame;
 	u32 meta_data_exists;
 };
+struct vidc_1080p_enc_slice_batch_in_param {
+	u32 cmd_type;
+	u32 input_size;
+	u32 num_stream_buffer;
+	u32 stream_buffer_size;
+	u32 stream_buffer_addr_offset[VIDC_1080P_SLICE_BATCH_MAX_STRM_BFR];
+};
+struct vidc_1080p_enc_slice_info {
+	u32 stream_buffer_idx;
+	u32 stream_buffer_size;
+};
+struct vidc_1080p_enc_slice_batch_out_param {
+	u32 cmd_type;
+	u32 output_size;
+	struct vidc_1080p_enc_slice_info slice_info
+		[VIDC_1080P_SLICE_BATCH_MAX_STRM_BFR];
+};
 struct vidc_1080p_dec_disp_info{
 	u32 disp_resl_change;
 	u32 dec_resl_change;
@@ -519,6 +542,10 @@
 	struct vidc_1080p_enc_frame_start_param *param);
 void vidc_1080p_encode_frame_start_ch1(
 	struct vidc_1080p_enc_frame_start_param *param);
+void vidc_1080p_encode_slice_batch_start_ch0(
+	struct vidc_1080p_enc_frame_start_param *param);
+void vidc_1080p_encode_slice_batch_start_ch1(
+	struct vidc_1080p_enc_frame_start_param *param);
 void vidc_1080p_set_encode_picture(u32 ifrm_ctrl, u32 number_b);
 void vidc_1080p_set_encode_multi_slice_control(
 	enum vidc_1080p_MSlice_selection multiple_slice_selection,
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 e94a302..e71259a 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
@@ -25,6 +25,9 @@
 #include "vidc.h"
 #include "vcd_res_tracker.h"
 
+#define PIL_FW_BASE_ADDR 0x9fe00000
+#define PIL_FW_SIZE 0x200000
+
 static unsigned int vidc_clk_table[3] = {
 	48000000, 133330000, 200000000
 };
@@ -64,7 +67,7 @@
 	unsigned long *kernel_vaddr = NULL;
 
 	ddl_context = ddl_get_context();
-	if (res_trk_get_enable_ion()) {
+	if (res_trk_get_enable_ion() && addr->alloc_handle) {
 		kernel_vaddr = (unsigned long *) ion_map_kernel(
 					ddl_context->video_ion_client,
 					addr->alloc_handle, UNCACHED);
@@ -97,31 +100,42 @@
 		addr->align_virtual_addr = addr->virtual_base_addr + offset;
 		addr->buffer_size = buffer_size;
 	} else {
-		if (!addr->alloced_phys_addr) {
-			pr_err(" %s() alloced addres NULL", __func__);
-			goto bail_out;
+		if (!res_trk_check_for_sec_session()) {
+			if (!addr->alloced_phys_addr) {
+				pr_err(" %s() alloced addres NULL", __func__);
+				goto bail_out;
+			}
+			flags = MSM_SUBSYSTEM_MAP_IOVA |
+				MSM_SUBSYSTEM_MAP_KADDR;
+			if (alignment == DDL_KILO_BYTE(128))
+					index = 1;
+			else if (alignment > SZ_4K)
+				flags |= MSM_SUBSYSTEM_ALIGN_IOVA_8K;
+			addr->mapped_buffer =
+			msm_subsystem_map_buffer(
+			(unsigned long)addr->alloced_phys_addr,
+			sz, flags, &restrk_mmu_subsystem[index],
+			sizeof(restrk_mmu_subsystem[index])/
+				sizeof(unsigned int));
+			if (IS_ERR(addr->mapped_buffer)) {
+				pr_err(" %s() buffer map failed", __func__);
+				goto bail_out;
+			}
+			mapped_buffer = addr->mapped_buffer;
+			if (!mapped_buffer->vaddr || !mapped_buffer->iova[0]) {
+				pr_err("%s() map buffers failed\n", __func__);
+				goto bail_out;
+			}
+			addr->physical_base_addr =
+				 (u8 *)mapped_buffer->iova[0];
+			addr->virtual_base_addr =
+					mapped_buffer->vaddr;
+		} else {
+			addr->physical_base_addr =
+				(u8 *) addr->alloced_phys_addr;
+			addr->virtual_base_addr =
+				(u8 *)addr->alloced_phys_addr;
 		}
-		flags = MSM_SUBSYSTEM_MAP_IOVA | MSM_SUBSYSTEM_MAP_KADDR;
-		if (alignment == DDL_KILO_BYTE(128))
-				index = 1;
-		else if (alignment > SZ_4K)
-			flags |= MSM_SUBSYSTEM_ALIGN_IOVA_8K;
-
-		addr->mapped_buffer =
-		msm_subsystem_map_buffer((unsigned long)addr->alloced_phys_addr,
-		sz, flags, &restrk_mmu_subsystem[index],
-		sizeof(restrk_mmu_subsystem[index])/sizeof(unsigned int));
-		if (IS_ERR(addr->mapped_buffer)) {
-			pr_err(" %s() buffer map failed", __func__);
-			goto bail_out;
-		}
-		mapped_buffer = addr->mapped_buffer;
-		if (!mapped_buffer->vaddr || !mapped_buffer->iova[0]) {
-			pr_err("%s() map buffers failed\n", __func__);
-			goto bail_out;
-		}
-		addr->physical_base_addr = (u8 *)mapped_buffer->iova[0];
-		addr->virtual_base_addr = mapped_buffer->vaddr;
 		addr->align_physical_addr = (u8 *) DDL_ALIGN((u32)
 		addr->physical_base_addr, alignment);
 		offset = (u32)(addr->align_physical_addr -
@@ -131,7 +145,7 @@
 	}
 	return addr->virtual_base_addr;
 bail_out:
-	if (addr->mapped_buffer)
+	if (IS_ERR(addr->mapped_buffer))
 		msm_subsystem_unmap_buffer(addr->mapped_buffer);
 	return NULL;
 ion_unmap_bail_out:
@@ -143,62 +157,84 @@
 	return NULL;
 }
 
-static void *res_trk_pmem_alloc
+static void res_trk_pmem_free(struct ddl_buf_addr *addr)
+{
+	struct ddl_context *ddl_context;
+	ddl_context = ddl_get_context();
+	if (ddl_context->video_ion_client) {
+		if (addr && addr->alloc_handle) {
+			ion_free(ddl_context->video_ion_client,
+			 addr->alloc_handle);
+			addr->alloc_handle = NULL;
+		}
+	} else {
+		if (addr->mapped_buffer)
+			msm_subsystem_unmap_buffer(addr->mapped_buffer);
+		if (addr->alloced_phys_addr)
+			free_contiguous_memory_by_paddr(
+			(unsigned long)addr->alloced_phys_addr);
+	}
+	memset(addr, 0 , sizeof(struct ddl_buf_addr));
+}
+static int res_trk_pmem_alloc
 	(struct ddl_buf_addr *addr, size_t sz, u32 alignment)
 {
 	u32 alloc_size;
 	struct ddl_context *ddl_context;
+	int rc = 0;
 	DBG_PMEM("\n%s() IN: Requested alloc size(%u)", __func__, (u32)sz);
 	if (!addr) {
 		DDL_MSG_ERROR("\n%s() Invalid Parameters", __func__);
+		rc = -EINVAL;
 		goto bail_out;
 	}
 	ddl_context = ddl_get_context();
 	res_trk_set_mem_type(addr->mem_type);
 	alloc_size = (sz + alignment);
 	if (res_trk_get_enable_ion()) {
-		if (!ddl_context->video_ion_client)
-			ddl_context->video_ion_client =
-				res_trk_get_ion_client();
-		if (!ddl_context->video_ion_client) {
-			DDL_MSG_ERROR("%s() :DDL ION Client Invalid handle\n",
-						 __func__);
-			goto bail_out;
+		if (!res_trk_is_cp_enabled() ||
+			 !res_trk_check_for_sec_session()) {
+			if (!ddl_context->video_ion_client)
+				ddl_context->video_ion_client =
+					res_trk_get_ion_client();
+			if (!ddl_context->video_ion_client) {
+				DDL_MSG_ERROR(
+				"%s() :DDL ION Client Invalid handle\n",
+						__func__);
+				rc = -ENOMEM;
+				goto bail_out;
+			}
+			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());
+			if (IS_ERR_OR_NULL(addr->alloc_handle)) {
+				DDL_MSG_ERROR("%s() :DDL ION alloc failed\n",
+						__func__);
+				rc = -ENOMEM;
+				goto bail_out;
+			}
+		} else {
+			addr->alloc_handle = NULL;
+			addr->alloced_phys_addr = PIL_FW_BASE_ADDR;
+			addr->buffer_size = sz;
 		}
-		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());
-		if (IS_ERR_OR_NULL(addr->alloc_handle)) {
-			DDL_MSG_ERROR("%s() :DDL ION alloc failed\n",
-						 __func__);
-			goto free_acm_ion_alloc;
-		}
-		return (void *) addr->alloc_handle;
 	} else {
 		addr->alloced_phys_addr = (phys_addr_t)
-		allocate_contiguous_memory_nomap(alloc_size,
-			res_trk_get_mem_type(), SZ_4K);
+			allocate_contiguous_memory_nomap(alloc_size,
+					res_trk_get_mem_type(), SZ_4K);
 		if (!addr->alloced_phys_addr) {
 			DDL_MSG_ERROR("%s() : acm alloc failed (%d)\n",
-					 __func__, alloc_size);
+					__func__, alloc_size);
+			rc = -ENOMEM;
 			goto bail_out;
 		}
 		addr->buffer_size = sz;
-		return (void *)addr->alloced_phys_addr;
-	}
-
-
-free_acm_ion_alloc:
-	if (ddl_context->video_ion_client) {
-		if (addr->alloc_handle) {
-			ion_free(ddl_context->video_ion_client,
-				addr->alloc_handle);
-			addr->alloc_handle = NULL;
-		}
+		return rc;
 	}
 bail_out:
-	return NULL;
+	return rc;
 }
 
 static void res_trk_pmem_unmap(struct ddl_buf_addr *addr)
@@ -211,10 +247,12 @@
 		if (addr->physical_base_addr) {
 			ion_unmap_kernel(resource_context.res_ion_client,
 					addr->alloc_handle);
-			ion_unmap_iommu(resource_context.res_ion_client,
+			if (!res_trk_check_for_sec_session()) {
+				ion_unmap_iommu(resource_context.res_ion_client,
 				addr->alloc_handle,
 				VIDEO_DOMAIN,
 				VIDEO_FIRMWARE_POOL);
+			}
 			addr->virtual_base_addr = NULL;
 			addr->physical_base_addr = NULL;
 		}
@@ -388,7 +426,9 @@
 		VCDRES_MSG_ERROR("Error : pm_runtime_get failed\n");
 		goto bail_out;
 	}
-	resource_context.footswitch = regulator_get(NULL, "fs_ved");
+	if (!resource_context.footswitch)
+		resource_context.footswitch =
+			regulator_get(resource_context.device, "vdd");
 	if (IS_ERR(resource_context.footswitch)) {
 		VCDRES_MSG_ERROR("foot switch get failed\n");
 		resource_context.footswitch = NULL;
@@ -413,6 +453,35 @@
 	return video_client;
 }
 
+int res_trk_enable_footswitch(void)
+{
+	int rc = 0;
+	mutex_lock(&resource_context.lock);
+	if (!resource_context.footswitch)
+		resource_context.footswitch = regulator_get(NULL, "fs_ved");
+	if (IS_ERR(resource_context.footswitch)) {
+		VCDRES_MSG_ERROR("foot switch get failed\n");
+		resource_context.footswitch = NULL;
+		rc = -EINVAL;
+	} else
+		rc = regulator_enable(resource_context.footswitch);
+	mutex_unlock(&resource_context.lock);
+	return rc;
+}
+
+int res_trk_disable_footswitch(void)
+{
+	mutex_lock(&resource_context.lock);
+	if (resource_context.footswitch) {
+		if (regulator_disable(resource_context.footswitch))
+			VCDRES_MSG_ERROR("Regulator disable failed\n");
+		regulator_put(resource_context.footswitch);
+		resource_context.footswitch = NULL;
+	}
+	mutex_unlock(&resource_context.lock);
+	return 0;
+}
+
 u32 res_trk_power_up(void)
 {
 	VCDRES_MSG_LOW("clk_regime_rail_enable");
@@ -438,6 +507,7 @@
 {
 	VCDRES_MSG_LOW("clk_regime_rail_disable");
 	res_trk_pmem_unmap(&resource_context.firmware_addr);
+	res_trk_pmem_free(&resource_context.firmware_addr);
 #ifdef CONFIG_MSM_BUS_SCALING
 	msm_bus_scale_client_update_request(resource_context.pcl, 0);
 	msm_bus_scale_unregister_client(resource_context.pcl);
@@ -640,14 +710,6 @@
 		}
 		resource_context.core_type = VCD_CORE_1080P;
 		resource_context.firmware_addr.mem_type = DDL_FW_MEM;
-		if (!res_trk_pmem_alloc(&resource_context.firmware_addr,
-			VIDC_FW_SIZE, DDL_KILO_BYTE(128))) {
-			pr_err("%s() Firmware buffer allocation failed",
-				   __func__);
-			if (!res_trk_check_for_sec_session())
-				memset(&resource_context.firmware_addr, 0,
-				sizeof(resource_context.firmware_addr));
-		}
 	}
 }
 
@@ -657,20 +719,47 @@
 
 u32 res_trk_get_firmware_addr(struct ddl_buf_addr *firm_addr)
 {
+	int rc = 0;
+	size_t size = 0;
 	if (!firm_addr || resource_context.firmware_addr.mapped_buffer) {
 		pr_err("%s() invalid params", __func__);
 		return -EINVAL;
 	}
+	if (res_trk_is_cp_enabled() && res_trk_check_for_sec_session())
+		size = PIL_FW_SIZE;
+	else
+		size = VIDC_FW_SIZE;
+
+	if (res_trk_pmem_alloc(&resource_context.firmware_addr,
+				size, DDL_KILO_BYTE(128))) {
+		pr_err("%s() Firmware buffer allocation failed",
+				__func__);
+		memset(&resource_context.firmware_addr, 0,
+				sizeof(resource_context.firmware_addr));
+		rc = -ENOMEM;
+		goto fail_alloc;
+	}
 	if (!res_trk_pmem_map(&resource_context.firmware_addr,
 		resource_context.firmware_addr.buffer_size,
 		DDL_KILO_BYTE(128))) {
 		pr_err("%s() Firmware buffer mapping failed",
 			   __func__);
-		return -EINVAL;
+		rc = -ENOMEM;
+		goto fail_map;
 	}
 	memcpy(firm_addr, &resource_context.firmware_addr,
 		sizeof(struct ddl_buf_addr));
 	return 0;
+fail_map:
+	res_trk_pmem_free(&resource_context.firmware_addr);
+fail_alloc:
+	return rc;
+}
+
+void res_trk_release_fw_addr(void)
+{
+	res_trk_pmem_unmap(&resource_context.firmware_addr);
+	res_trk_pmem_free(&resource_context.firmware_addr);
 }
 
 int res_trk_check_for_sec_session(void)
@@ -702,15 +791,27 @@
 		return mem_type;
 	}
 	if (resource_context.vidc_platform_data->enable_ion) {
-		if (res_trk_check_for_sec_session())
-			mem_type = (ION_HEAP(mem_type) | ION_SECURE);
-		else
-			mem_type = (ION_HEAP(mem_type) |
-					ION_HEAP(ION_IOMMU_HEAP_ID));
+		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;
 }
 
+u32 res_trk_is_cp_enabled(void)
+{
+	if (resource_context.vidc_platform_data->cp_enabled)
+		return 1;
+	else
+		return 0;
+}
+
 u32 res_trk_get_enable_ion(void)
 {
 	if (resource_context.vidc_platform_data->enable_ion)
@@ -728,6 +829,10 @@
 	return resource_context.disable_dmx;
 }
 
+u32 res_trk_get_min_dpb_count(void){
+	return resource_context.vidc_platform_data->cont_mode_dpb_count;
+}
+
 void res_trk_set_mem_type(enum ddl_mem_area mem_type)
 {
 	resource_context.res_mem_type = mem_type;
@@ -840,8 +945,8 @@
 			pr_err("IOMMU clock enabled failed while close");
 			goto error_close;
 		}
-		msm_ion_unsecure_heap(ION_HEAP(resource_context.memtype));
 		msm_ion_unsecure_heap(ION_HEAP(resource_context.cmd_mem_type));
+		msm_ion_unsecure_heap(ION_HEAP(resource_context.memtype));
 		res_trk_disable_iommu_clocks();
 		mutex_unlock(&resource_context.secure_lock);
 	}
@@ -870,3 +975,17 @@
 	}
 	return res_trk_perf_level;
 }
+
+u32 res_trk_estimate_perf_level(u32 pn_perf_lvl)
+{
+	VCDRES_MSG_MED("%s(), req_perf_lvl = %d", __func__, pn_perf_lvl);
+	if ((pn_perf_lvl >= RESTRK_1080P_VGA_PERF_LEVEL) &&
+		(pn_perf_lvl < RESTRK_1080P_720P_PERF_LEVEL)) {
+		return RESTRK_1080P_720P_PERF_LEVEL;
+	} else if ((pn_perf_lvl >= RESTRK_1080P_720P_PERF_LEVEL) &&
+			(pn_perf_lvl < RESTRK_1080P_MAX_PERF_LEVEL)) {
+		return RESTRK_1080P_MAX_PERF_LEVEL;
+	} else {
+		return pn_perf_lvl;
+	}
+}
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 7d68412..99b123c 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
@@ -31,9 +31,11 @@
 u32 res_trk_get_firmware_addr(struct ddl_buf_addr *firm_addr);
 int res_trk_get_mem_type(void);
 u32 res_trk_get_enable_ion(void);
+u32 res_trk_is_cp_enabled(void);
 u32 res_trk_get_disable_fullhd(void);
 struct ion_client *res_trk_get_ion_client(void);
 u32 res_trk_get_disable_dmx(void);
+u32 res_trk_get_min_dpb_count(void);
 void res_trk_set_mem_type(enum ddl_mem_area mem_type);
 int res_trk_enable_iommu_clocks(void);
 int res_trk_disable_iommu_clocks(void);
@@ -43,4 +45,8 @@
 void res_trk_secure_set(void);
 void res_trk_secure_unset(void);
 u32 get_res_trk_perf_level(enum vcd_perf_level);
+int res_trk_enable_footswitch(void);
+int res_trk_disable_footswitch(void);
+void res_trk_release_fw_addr(void);
+u32 res_trk_estimate_perf_level(u32 pn_perf_lvl);
 #endif
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h
index 9dc495b..7e201cf 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h
@@ -57,6 +57,12 @@
 	u32 activity_region_flag;
 };
 
+struct vcd_property_slice_delivery_info {
+	u32  enable;
+	u32  num_slices;
+	u32  num_slices_enc;
+};
+
 struct ddl_frame_data_tag;
 
 struct ddl_property_dec_pic_buffers {
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c
index fe71dc1..5fa9b09 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c
@@ -290,6 +290,8 @@
 			decoder->client_output_buf_req.actual_count
 			&& decoder->progressive_only)
 			need_reconfig = false;
+		if (input_vcd_frm->flags & VCD_FRAME_FLAG_EOS)
+			need_reconfig = false;
 		if ((input_vcd_frm->data_len <= seq_hdr_info.dec_frm_size ||
 			 (input_vcd_frm->flags & VCD_FRAME_FLAG_CODECCONFIG)) &&
 			(!need_reconfig ||
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 17dedb8..aa0d4b8 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
@@ -231,3 +231,12 @@
 	proc_time[index].ddl_ttotal = 0;
 	proc_time[index].ddl_count = 0;
 }
+int ddl_get_core_decode_proc_time(u32 *ddl_handle)
+{
+	return 0;
+}
+
+void ddl_reset_avg_dec_time(u32 *ddl_handle)
+{
+	return;
+}
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.h b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.h
index 539f753..59bb620 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.h
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.h
@@ -46,6 +46,10 @@
 
 void ddl_reset_core_time_variables(u32 index);
 
+int ddl_get_core_decode_proc_time(u32 *ddl_handle);
+
+void ddl_reset_avg_dec_time(u32 *ddl_handle);
+
 #define DDL_ASSERT(x)
 #define DDL_MEMSET(src, value, len) memset((src), (value), (len))
 #define DDL_MEMCPY(dest, src, len)  memcpy((dest), (src), (len))
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 f8ec0dc..e51bf45 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
@@ -757,3 +757,15 @@
 {
 	return -ENOTSUPP;
 }
+u32 res_trk_is_cp_enabled(void)
+{
+	if (resource_context.vidc_platform_data->cp_enabled)
+		return 1;
+	else
+		return 0;
+}
+u32 res_trk_estimate_perf_level(u32 pn_perf_lvl)
+{
+	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 cc414e2..75fdb3e 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
@@ -30,6 +30,7 @@
 u32 res_trk_get_mem_type(void);
 u32 res_trk_get_disable_fullhd(void);
 u32 res_trk_get_enable_ion(void);
+u32 res_trk_is_cp_enabled(void);
 struct ion_client *res_trk_get_ion_client(void);
 void res_trk_set_mem_type(enum ddl_mem_area mem_type);
 int res_trk_check_for_sec_session(void);
@@ -38,4 +39,5 @@
 void res_trk_secure_set(void);
 void res_trk_secure_unset(void);
 u32 get_res_trk_perf_level(enum vcd_perf_level perf_level);
+u32 res_trk_estimate_perf_level(u32 pn_perf_lvl);
 #endif
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index 420fc19..11177b8 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -347,7 +347,7 @@
 		ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
 				pmem_fd, kernel_vaddr, buffer_index,
 				&buff_handle);
-		if (ion_flag == CACHED) {
+		if (ion_flag == CACHED && buff_handle) {
 			msm_ion_do_cache_op(client_ctx->user_ion_client,
 					buff_handle,
 					(unsigned long *) kernel_vaddr,
@@ -890,19 +890,35 @@
 				 __func__);
 			goto import_ion_error;
 		}
-		rc = ion_map_iommu(client_ctx->user_ion_client,
+		if (res_trk_check_for_sec_session()) {
+			rc = ion_phys(client_ctx->user_ion_client,
 				client_ctx->h264_mv_ion_handle,
-				VIDEO_DOMAIN, VIDEO_MAIN_POOL,
-				SZ_4K, 0, (unsigned long *)&iova,
-				(unsigned long *)&buffer_size, UNCACHED, 0);
-		if (rc) {
-			ERR("%s():get_ION_kernel physical addr fail\n",
-					 __func__);
-			goto ion_map_error;
+				(unsigned long *) (&(vcd_h264_mv_buffer->
+				physical_addr)), &len);
+			if (rc) {
+				ERR("%s():get_ION_kernel physical addr fail\n",
+					__func__);
+				goto ion_map_error;
+			}
+			vcd_h264_mv_buffer->client_data = NULL;
+			vcd_h264_mv_buffer->dev_addr = (u8 *)
+				vcd_h264_mv_buffer->physical_addr;
+		} else {
+			rc = ion_map_iommu(client_ctx->user_ion_client,
+					client_ctx->h264_mv_ion_handle,
+					VIDEO_DOMAIN, VIDEO_MAIN_POOL,
+					SZ_4K, 0, (unsigned long *)&iova,
+					(unsigned long *)&buffer_size,
+					UNCACHED, 0);
+			if (rc) {
+				ERR("%s():get_ION_kernel physical addr fail\n",
+						 __func__);
+				goto ion_map_error;
+			}
+			vcd_h264_mv_buffer->physical_addr = (u8 *) iova;
+			vcd_h264_mv_buffer->client_data = NULL;
+			vcd_h264_mv_buffer->dev_addr = (u8 *) iova;
 		}
-		vcd_h264_mv_buffer->physical_addr = (u8 *) iova;
-		vcd_h264_mv_buffer->client_data = NULL;
-		vcd_h264_mv_buffer->dev_addr = (u8 *) iova;
 	}
 	DBG("Virt: %p, Phys %p, fd: %d", vcd_h264_mv_buffer->
 		kernel_virtual_addr, vcd_h264_mv_buffer->physical_addr,
@@ -997,10 +1013,12 @@
 	if (!IS_ERR_OR_NULL(client_ctx->h264_mv_ion_handle)) {
 		ion_unmap_kernel(client_ctx->user_ion_client,
 					client_ctx->h264_mv_ion_handle);
-		ion_unmap_iommu(client_ctx->user_ion_client,
+		if (!res_trk_check_for_sec_session()) {
+			ion_unmap_iommu(client_ctx->user_ion_client,
 				client_ctx->h264_mv_ion_handle,
 				VIDEO_DOMAIN,
 				VIDEO_MAIN_POOL);
+		}
 		ion_free(client_ctx->user_ion_client,
 					client_ctx->h264_mv_ion_handle);
 		 client_ctx->h264_mv_ion_handle = NULL;
@@ -1252,7 +1270,7 @@
 						kernel_vaddr,
 						buffer_index,
 						&buff_handle);
-			if (ion_flag == CACHED) {
+			if (ion_flag == CACHED && buff_handle) {
 				msm_ion_do_cache_op(client_ctx->user_ion_client,
 				buff_handle,
 				(unsigned long *)kernel_vaddr,
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index d93d07e..1b77b67 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -265,7 +265,7 @@
 		ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
 					pmem_fd, kernel_vaddr, buffer_index,
 					&buff_handle);
-		if (ion_flag == CACHED) {
+		if (ion_flag == CACHED && buff_handle) {
 			msm_ion_do_cache_op(client_ctx->user_ion_client,
 				buff_handle,
 				(unsigned long *) kernel_vaddr,
@@ -1604,6 +1604,20 @@
 		}
 		if (!result) {
 			ERR("setting VEN_IOCTL_(G)SET_LIVE_MODE failed\n");
+		}
+		break;
+	}
+	case VEN_IOCTL_SET_SLICE_DELIVERY_MODE:
+	{
+		struct vcd_property_hdr vcd_property_hdr;
+		u32 vcd_status = VCD_ERR_FAIL;
+		u32 enable = true;
+		vcd_property_hdr.prop_id = VCD_I_SLICE_DELIVERY_MODE;
+		vcd_property_hdr.sz = sizeof(u32);
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+						&vcd_property_hdr, &enable);
+		if (vcd_status) {
+			pr_err(" Setting slice delivery mode failed");
 			return -EIO;
 		}
 		break;
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index ac732c1..bbbe0cf 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -31,6 +31,7 @@
 #include <media/msm/vidc_type.h>
 #include <media/msm/vcd_api.h>
 #include <media/msm/vidc_init.h>
+#include "vcd_res_tracker_api.h"
 #include "venc_internal.h"
 
 #if DEBUG
@@ -1687,7 +1688,7 @@
 				&buff_handle);
 
 		if (vcd_input_buffer.data_len > 0) {
-			if (ion_flag == CACHED) {
+			if (ion_flag == CACHED && buff_handle) {
 				msm_ion_do_cache_op(
 				client_ctx->user_ion_client,
 				buff_handle,
@@ -1768,6 +1769,8 @@
 	unsigned long ionflag = 0;
 	unsigned long iova = 0;
 	unsigned long buffer_size = 0;
+	size_t ion_len = -1;
+	unsigned long phy_addr;
 
 	if (!client_ctx || !venc_recon) {
 		pr_err("%s() Invalid params", __func__);
@@ -1836,24 +1839,39 @@
 				 __func__);
 			goto import_ion_error;
 		}
-		rc = ion_map_iommu(client_ctx->user_ion_client,
+		if (res_trk_check_for_sec_session()) {
+			rc = ion_phys(client_ctx->user_ion_client,
 				client_ctx->recon_buffer_ion_handle[i],
-				VIDEO_DOMAIN,
-				VIDEO_MAIN_POOL,
-				SZ_4K,
-				0,
-				(unsigned long *)&iova,
-				(unsigned long *)&buffer_size,
-				UNCACHED, 0);
-		if (rc) {
-			ERR("%s():ION map iommu addr fail\n",
-				 __func__);
-			goto map_ion_error;
+				&phy_addr, &ion_len);
+			if (rc) {
+				ERR("%s():get_ION_kernel physical addr fail\n",
+					__func__);
+				goto map_ion_error;
+			}
+			control->physical_addr =  (u8 *) phy_addr;
+			len = (unsigned long) ion_len;
+			control->client_data = NULL;
+			control->dev_addr = (u8 *)control->physical_addr;
+		} else {
+			rc = ion_map_iommu(client_ctx->user_ion_client,
+					client_ctx->recon_buffer_ion_handle[i],
+					VIDEO_DOMAIN,
+					VIDEO_MAIN_POOL,
+					SZ_4K,
+					0,
+					(unsigned long *)&iova,
+					(unsigned long *)&buffer_size,
+					UNCACHED, 0);
+			if (rc) {
+				ERR("%s():ION map iommu addr fail\n",
+					 __func__);
+				goto map_ion_error;
+			}
+			control->physical_addr =  (u8 *) iova;
+			len = buffer_size;
+			control->client_data = NULL;
+			control->dev_addr = (u8 *)iova;
 		}
-		control->physical_addr =  (u8 *) iova;
-		len = buffer_size;
-		control->client_data = NULL;
-		control->dev_addr = (u8 *)iova;
 	}
 
 	vcd_property_hdr.prop_id = VCD_I_RECON_BUFFERS;
@@ -1922,10 +1940,12 @@
 		if (client_ctx->recon_buffer_ion_handle[i]) {
 			ion_unmap_kernel(client_ctx->user_ion_client,
 				client_ctx->recon_buffer_ion_handle[i]);
-			ion_unmap_iommu(client_ctx->user_ion_client,
+			if (!res_trk_check_for_sec_session()) {
+				ion_unmap_iommu(client_ctx->user_ion_client,
 				client_ctx->recon_buffer_ion_handle[i],
 				VIDEO_DOMAIN,
 				VIDEO_MAIN_POOL);
+			}
 			ion_free(client_ctx->user_ion_client,
 				client_ctx->recon_buffer_ion_handle[i]);
 			client_ctx->recon_buffer_ion_handle[i] = NULL;
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index 6fdb1c6..23c990a 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -63,7 +63,7 @@
 static irqreturn_t vidc_isr(int irq, void *dev);
 static spinlock_t vidc_spin_lock;
 
-u32 vidc_msg_timing, vidc_msg_pmem;
+u32 vidc_msg_timing, vidc_msg_pmem, vidc_msg_register;
 
 #ifdef VIDC_ENABLE_DBGFS
 struct dentry *vidc_debugfs_root;
@@ -311,6 +311,8 @@
 				(u32 *) &vidc_msg_timing);
 		vidc_debugfs_file_create(root, "vidc_msg_pmem",
 				(u32 *) &vidc_msg_pmem);
+		vidc_debugfs_file_create(root, "vidc_msg_register",
+				(u32 *) &vidc_msg_register);
 	}
 #endif
 	return 0;
@@ -343,28 +345,32 @@
 {
 	u32 status = true;
 
-	mutex_lock(&vidc_device_p->lock);
-	if (!vidc_device_p->get_firmware) {
-		status = res_trk_download_firmware();
-		if (!status)
-			goto error;
-		vidc_device_p->get_firmware = 1;
-	}
-	vidc_device_p->firmware_refcount++;
+	if (!res_trk_check_for_sec_session()) {
+		mutex_lock(&vidc_device_p->lock);
+		if (!vidc_device_p->get_firmware) {
+			status = res_trk_download_firmware();
+			if (!status)
+				goto error;
+			vidc_device_p->get_firmware = 1;
+		}
+		vidc_device_p->firmware_refcount++;
 error:
-	mutex_unlock(&vidc_device_p->lock);
+		mutex_unlock(&vidc_device_p->lock);
+	}
 	return status;
 }
 EXPORT_SYMBOL(vidc_load_firmware);
 
 void vidc_release_firmware(void)
 {
-	mutex_lock(&vidc_device_p->lock);
-	if (vidc_device_p->firmware_refcount > 0)
-		vidc_device_p->firmware_refcount--;
-	else
-		vidc_device_p->firmware_refcount = 0;
-	mutex_unlock(&vidc_device_p->lock);
+	if (!res_trk_check_for_sec_session()) {
+		mutex_lock(&vidc_device_p->lock);
+		if (vidc_device_p->firmware_refcount > 0)
+			vidc_device_p->firmware_refcount--;
+		else
+			vidc_device_p->firmware_refcount = 0;
+		mutex_unlock(&vidc_device_p->lock);
+	}
 }
 EXPORT_SYMBOL(vidc_release_firmware);
 
@@ -426,11 +432,14 @@
 				ion_unmap_kernel(client_ctx->user_ion_client,
 						buf_addr_table[i].
 						buff_ion_handle);
-				ion_unmap_iommu(client_ctx->user_ion_client,
+				if (!res_trk_check_for_sec_session()) {
+					ion_unmap_iommu(
+						client_ctx->user_ion_client,
 						buf_addr_table[i].
 						buff_ion_handle,
 						VIDEO_DOMAIN,
 						VIDEO_MAIN_POOL);
+				}
 				ion_free(client_ctx->user_ion_client,
 						buf_addr_table[i].
 						buff_ion_handle);
@@ -447,10 +456,12 @@
 		if (!IS_ERR_OR_NULL(client_ctx->user_ion_client)) {
 			ion_unmap_kernel(client_ctx->user_ion_client,
 					client_ctx->h264_mv_ion_handle);
-			ion_unmap_iommu(client_ctx->user_ion_client,
+			if (!res_trk_check_for_sec_session()) {
+				ion_unmap_iommu(client_ctx->user_ion_client,
 					client_ctx->h264_mv_ion_handle,
 					VIDEO_DOMAIN,
 					VIDEO_MAIN_POOL);
+			}
 			ion_free(client_ctx->user_ion_client,
 					client_ctx->h264_mv_ion_handle);
 			client_ctx->h264_mv_ion_handle = NULL;
@@ -559,6 +570,7 @@
 	unsigned long iova = 0;
 	int ret = 0;
 	unsigned long buffer_size  = 0;
+	size_t ion_len;
 
 	if (!client_ctx || !length)
 		return false;
@@ -640,23 +652,41 @@
 				*kernel_vaddr = (unsigned long)NULL;
 				goto ion_free_error;
 			}
-			ret = ion_map_iommu(client_ctx->user_ion_client,
+			if (res_trk_check_for_sec_session()) {
+				if (ion_phys(client_ctx->user_ion_client,
 					buff_ion_handle,
-					VIDEO_DOMAIN,
-					VIDEO_MAIN_POOL,
-					SZ_8K,
-					length,
-					(unsigned long *) &iova,
-					(unsigned long *) &buffer_size,
-					UNCACHED, ION_IOMMU_UNMAP_DELAYED);
-			if (ret) {
-				ERR("%s():ION iommu map fail\n",
-				 __func__);
-				goto ion_map_error;
+					&phys_addr, &ion_len)) {
+					ERR("%s():ION physical addr fail\n",
+					__func__);
+					goto ion_map_error;
+				}
+				len = (unsigned long) ion_len;
+				buf_addr_table[*num_of_buffers].client_data =
+					 NULL;
+				buf_addr_table[*num_of_buffers].dev_addr =
+					 phys_addr;
+			} else {
+				ret = ion_map_iommu(client_ctx->user_ion_client,
+						buff_ion_handle,
+						VIDEO_DOMAIN,
+						VIDEO_MAIN_POOL,
+						SZ_8K,
+						length,
+						(unsigned long *) &iova,
+						(unsigned long *) &buffer_size,
+						UNCACHED,
+						ION_IOMMU_UNMAP_DELAYED);
+				if (ret) {
+					ERR("%s():ION iommu map fail\n",
+					 __func__);
+					goto ion_map_error;
+				}
+				phys_addr = iova;
+				buf_addr_table[*num_of_buffers].client_data =
+						 NULL;
+				buf_addr_table[*num_of_buffers].dev_addr =
+						 iova;
 			}
-			phys_addr = iova;
-			buf_addr_table[*num_of_buffers].client_data = NULL;
-			buf_addr_table[*num_of_buffers].dev_addr = iova;
 		}
 		phys_addr += buffer_addr_offset;
 		(*kernel_vaddr) += buffer_addr_offset;
@@ -803,10 +833,12 @@
 	if (buf_addr_table[i].buff_ion_handle) {
 		ion_unmap_kernel(client_ctx->user_ion_client,
 				buf_addr_table[i].buff_ion_handle);
-		ion_unmap_iommu(client_ctx->user_ion_client,
+		if (!res_trk_check_for_sec_session()) {
+			ion_unmap_iommu(client_ctx->user_ion_client,
 				buf_addr_table[i].buff_ion_handle,
 				VIDEO_DOMAIN,
 				VIDEO_MAIN_POOL);
+		}
 		ion_free(client_ctx->user_ion_client,
 				buf_addr_table[i].buff_ion_handle);
 		buf_addr_table[i].buff_ion_handle = NULL;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd.h b/drivers/video/msm/vidc/common/vcd/vcd.h
index 0d1ff7e..3e02030 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd.h
@@ -393,4 +393,8 @@
 u32 vcd_req_perf_level(struct vcd_clnt_ctxt *cctxt,
 	struct vcd_property_perf_level *);
 
+u32 vcd_set_num_slices(struct vcd_clnt_ctxt *cctxt);
+
+u32 vcd_update_decoder_perf_level(struct vcd_dev_ctxt *dev_ctxt, u32 perf_lvl);
+
 #endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_core.h b/drivers/video/msm/vidc/common/vcd/vcd_core.h
index e33c8cd..d228146 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_core.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_core.h
@@ -185,6 +185,7 @@
 	u32 live;
 	u32 decoding;
 	u32 bframe;
+	u32 num_slices;
 
 	struct vcd_property_frame_rate frm_rate;
 	u32 frm_p_units;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
index 9576387..49d885c 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
@@ -954,6 +954,9 @@
 	u32 rc = VCD_S_SUCCESS;
 	u32 client_inited = false;
 	u32 fail_all_open = false;
+	struct ddl_context *ddl_context;
+
+	ddl_context = ddl_get_context();
 
 	VCD_MSG_LOW("vcd_dev_cb_in_initing:");
 
@@ -1027,6 +1030,8 @@
 
 			tmp_client = client;
 			client = client->next;
+			if (tmp_client == dev_ctxt->cctxt_list_head)
+				fail_all_open = true;
 
 			vcd_destroy_client_context(tmp_client);
 		}
@@ -1035,6 +1040,10 @@
 	if (!client_inited || fail_all_open) {
 		VCD_MSG_ERROR("All client open requests failed");
 
+		DDL_IDLE(ddl_context);
+
+		vcd_handle_device_init_failed(drv_ctxt,
+			DEVICE_STATE_EVENT_NUMBER(close));
 		dev_ctxt->pending_cmd = VCD_CMD_DEVICE_TERM;
 	} else {
 		if (vcd_power_event(dev_ctxt, NULL,
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
index 01bd931..beaa872 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
@@ -297,6 +297,21 @@
 	return rc;
 }
 
+u32 vcd_update_decoder_perf_level(struct vcd_dev_ctxt *dev_ctxt, u32 perf_lvl)
+{
+	u32 rc = VCD_S_SUCCESS;
+
+	if (res_trk_set_perf_level(perf_lvl,
+		&dev_ctxt->curr_perf_lvl, dev_ctxt)) {
+		dev_ctxt->set_perf_lvl_pending = false;
+	} else {
+		rc = VCD_ERR_FAIL;
+		dev_ctxt->set_perf_lvl_pending = true;
+	}
+
+	return rc;
+}
+
 u32 vcd_update_clnt_perf_lvl(
 	struct vcd_clnt_ctxt *cctxt,
      struct vcd_property_frame_rate *fps, u32 frm_p_units)
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index fd8d02a..2df7144 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -19,6 +19,8 @@
 
 #define MAX(x, y) (((x) > (y)) ? (x) : (y))
 #define MAP_TABLE_SZ 64
+#define VCD_ENC_MAX_OUTBFRS_PER_FRAME 8
+#define MAX_DEC_TIME 33
 
 struct vcd_msm_map_buffer {
 	phys_addr_t phy_addr;
@@ -942,7 +944,6 @@
 		list_del(&entry->list);
 		pool->q_len--;
 	}
-
 	return entry;
 }
 
@@ -1122,6 +1123,7 @@
 	cctxt->bframe = 0;
 	cctxt->cmd_q.pending_cmd = VCD_CMD_NONE;
 	cctxt->status.last_evt = VCD_EVT_RESP_BASE;
+	cctxt->num_slices = 1;
 	return rc;
 }
 
@@ -1293,6 +1295,7 @@
 		}
 
 	} else {
+		vcd_set_num_slices(transc->cctxt);
 		rc = ddl_encode_start(transc->cctxt->ddl_handle,
 					  (void *)transc);
 	}
@@ -1491,8 +1494,11 @@
 	struct vcd_buffer_entry *op_buf_entry = NULL;
 	u32 rc = VCD_S_SUCCESS;
 	u32 evcode = 0;
+	u32 perf_level = 0;
+	int decodeTime = 0;
 	struct ddl_frame_data_tag ddl_ip_frm;
-	struct ddl_frame_data_tag ddl_op_frm;
+	struct ddl_frame_data_tag *ddl_op_frm;
+	u32 out_buf_cnt = 0;
 
 	VCD_MSG_LOW("vcd_submit_frame:");
 	cctxt = transc->cctxt;
@@ -1504,34 +1510,62 @@
 	transc->flags = ip_frm_entry->flags;
 	ip_frm_entry->ip_frm_tag = (u32) transc;
 	memset(&ddl_ip_frm, 0, sizeof(ddl_ip_frm));
-	memset(&ddl_op_frm, 0, sizeof(ddl_op_frm));
 	if (cctxt->decoding) {
+		decodeTime = ddl_get_core_decode_proc_time(cctxt->ddl_handle);
+		if (decodeTime > MAX_DEC_TIME) {
+			if (res_trk_get_curr_perf_level(&perf_level)) {
+				vcd_update_decoder_perf_level(dev_ctxt,
+				   res_trk_estimate_perf_level(perf_level));
+				ddl_reset_avg_dec_time(cctxt->ddl_handle);
+			} else
+				VCD_MSG_ERROR("%s(): retrieve curr_perf_level"
+						"returned FALSE\n", __func__);
+		}
 		evcode = CLIENT_STATE_EVENT_NUMBER(decode_frame);
 		ddl_ip_frm.vcd_frm = *ip_frm_entry;
 		rc = ddl_decode_frame(cctxt->ddl_handle, &ddl_ip_frm,
-							   (void *) transc);
+							(void *) transc);
 	} else {
-		op_buf_entry = vcd_buffer_pool_entry_de_q(
-			&cctxt->out_buf_pool);
-		if (!op_buf_entry) {
-			VCD_MSG_ERROR("Sched provided frame when no"
-				"op buffer was present");
-			rc = VCD_ERR_FAIL;
-		} else {
+		ddl_op_frm = (struct ddl_frame_data_tag *)
+			kmalloc((sizeof(struct ddl_frame_data_tag) *
+			VCD_ENC_MAX_OUTBFRS_PER_FRAME), GFP_KERNEL);
+		if (!ddl_op_frm) {
+			VCD_MSG_ERROR("Memory allocation failure");
+			return VCD_ERR_ALLOC_FAIL;
+		}
+		memset(ddl_op_frm, 0, (sizeof(struct ddl_frame_data_tag) *
+			VCD_ENC_MAX_OUTBFRS_PER_FRAME));
+		for (out_buf_cnt = 0; out_buf_cnt < cctxt->num_slices ;
+				out_buf_cnt++) {
+			op_buf_entry = vcd_buffer_pool_entry_de_q(
+				&cctxt->out_buf_pool);
+			if (!op_buf_entry) {
+				VCD_MSG_ERROR("Sched provided frame when no"
+					"op buffer was present");
+				rc = VCD_ERR_FAIL;
+				break;
+			}
 			op_buf_entry->in_use = true;
 			cctxt->out_buf_pool.in_use++;
-			ddl_ip_frm.vcd_frm = *ip_frm_entry;
-			ddl_ip_frm.frm_delta =
-				vcd_calculate_frame_delta(cctxt,
-					ip_frm_entry);
-
-			ddl_op_frm.vcd_frm = op_buf_entry->frame;
-
-			evcode = CLIENT_STATE_EVENT_NUMBER(encode_frame);
-
-			rc = ddl_encode_frame(cctxt->ddl_handle,
-				&ddl_ip_frm, &ddl_op_frm, (void *) transc);
+			ddl_op_frm[out_buf_cnt].vcd_frm = op_buf_entry->frame;
+			VCD_MSG_LOW("%s : buffer_cnt = %d framebfr(virtual)"
+				" 0x%p", __func__, out_buf_cnt,
+				op_buf_entry->frame.virtual);
+			VCD_MSG_LOW("framebfr(physical) 0x%p bfrlength %d",
+				op_buf_entry->frame.physical,
+				op_buf_entry->frame.alloc_len);
 		}
+		ddl_ip_frm.vcd_frm = *ip_frm_entry;
+		ddl_ip_frm.frm_delta =
+			vcd_calculate_frame_delta(cctxt,
+				ip_frm_entry);
+		evcode = CLIENT_STATE_EVENT_NUMBER(encode_frame);
+
+		if (!VCD_FAILED(rc)) {
+			rc = ddl_encode_frame(cctxt->ddl_handle,
+				&ddl_ip_frm, &ddl_op_frm[0], (void *) transc);
+		}
+		kfree(ddl_op_frm);
 	}
 	ip_frm_entry->ip_frm_tag = transc->ip_frm_tag;
 	if (!VCD_FAILED(rc)) {
@@ -1875,8 +1909,10 @@
 
 void vcd_release_trans_tbl_entry(struct vcd_transc *trans_entry)
 {
-	if (trans_entry)
+	if (trans_entry) {
 		trans_entry->in_use = false;
+		VCD_MSG_LOW("%s in_use set to false\n", __func__);
+	}
 }
 
 u32 vcd_handle_input_done(
@@ -1888,6 +1924,7 @@
 		(struct ddl_frame_data_tag *) payload;
 	struct vcd_buffer_entry *orig_frame = NULL;
 	u32 rc;
+	VCD_MSG_LOW("%s\n", __func__);
 
 	if (!cctxt->status.frame_submitted &&
 		!cctxt->status.frame_delayed) {
@@ -1935,8 +1972,11 @@
 	transc->ip_buf_entry = NULL;
 	transc->input_done = true;
 
-	if (transc->input_done && transc->frame_done)
+	if (transc->input_done && transc->frame_done) {
+		VCD_MSG_LOW("%s Calling vcd_release_trans_tbl_entry\n",
+		__func__);
 		vcd_release_trans_tbl_entry(transc);
+	}
 
 	if (VCD_FAILED(status)) {
 		VCD_MSG_ERROR("INPUT_DONE returned err = 0x%x", status);
@@ -1975,6 +2015,7 @@
 		(struct ddl_frame_data_tag *) payload;
 	u32 rc = VCD_ERR_FAIL, codec_config = false;
 	u32 core_type = res_trk_get_core_type();
+	VCD_MSG_LOW("%s\n", __func__);
 	rc = vcd_validate_io_done_pyld(cctxt, payload, status);
 	if (rc == VCD_ERR_CLIENT_FATAL)
 		vcd_handle_clnt_fatal_input_done(cctxt, frame->frm_trans_end);
@@ -2080,6 +2121,7 @@
 	struct ddl_frame_data_tag *frame =
 		(struct ddl_frame_data_tag *)payload;
 	u32 rc = VCD_S_SUCCESS;
+	VCD_MSG_LOW("%s\n", __func__);
 
 	if (!cctxt->status.frame_submitted &&
 		!cctxt->status.frame_delayed) {
@@ -2140,6 +2182,7 @@
 	struct vcd_transc *transc;
 	struct ddl_frame_data_tag *frame =
 		(struct ddl_frame_data_tag *)payload;
+	VCD_MSG_LOW("%s\n", __func__);
 
 	rc = vcd_validate_io_done_pyld(cctxt, payload, VCD_S_SUCCESS);
 	if (rc == VCD_ERR_CLIENT_FATAL)
@@ -2173,6 +2216,7 @@
 	struct vcd_transc *transc;
 	u32 rc;
 	s64 time_stamp;
+	VCD_MSG_LOW("%s\n", __func__);
 
 	rc = vcd_validate_io_done_pyld(cctxt, payload, status);
 	if (rc == VCD_ERR_CLIENT_FATAL)
@@ -2262,7 +2306,7 @@
 	struct ddl_frame_data_tag *frame =
 		(struct ddl_frame_data_tag *) payload;
 	u32 rc = VCD_S_SUCCESS;
-	VCD_MSG_LOW("vcd_handle_frame_done_in_eos:");
+	VCD_MSG_LOW("%s\n", __func__);
 	rc = vcd_validate_io_done_pyld(cctxt, payload, status);
 	if (rc == VCD_ERR_CLIENT_FATAL)
 		vcd_handle_clnt_fatal(cctxt, frame->frm_trans_end);
@@ -3326,3 +3370,24 @@
 		 0, cctxt, cctxt->client_data);
 	}
 }
+
+u32 vcd_set_num_slices(struct vcd_clnt_ctxt *cctxt)
+{
+	struct vcd_property_hdr prop_hdr;
+	struct vcd_property_slice_delivery_info slice_delivery_info;
+	u32 rc = VCD_S_SUCCESS;
+	prop_hdr.prop_id = VCD_I_SLICE_DELIVERY_MODE;
+	prop_hdr.sz = prop_hdr.sz =
+		sizeof(struct vcd_property_slice_delivery_info);
+	rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr,
+				&slice_delivery_info);
+	VCD_FAILED_RETURN(rc, "Failed: Get VCD_I_SLICE_DELIVERY_MODE");
+	if (slice_delivery_info.enable) {
+		cctxt->num_slices = slice_delivery_info.num_slices;
+		VCD_MSG_LOW("%s slice delivery mode num_slices = %u\n",
+					__func__, cctxt->num_slices);
+	} else {
+		cctxt->num_slices = 1;
+	}
+	return rc;
+}
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index f078f3a..7f963e6 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -5,6 +5,8 @@
  *                  & Ralph  Metzler <ralph@convergence.de>
  *                    for convergence integrated media GmbH
  *
+ * 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 Lesser General Public License
  * as published by the Free Software Foundation; either version 2.1
@@ -119,6 +121,29 @@
 	__u32          flags;
 };
 
+struct dmx_buffer_status {
+	/* size of buffer in bytes */
+	unsigned int size;
+
+	/* fullness of buffer in bytes */
+	unsigned int fullness;
+
+	/*
+	 * How many bytes are free
+	 * It's the same as: size-fullness-1
+	 */
+	unsigned int free_bytes;
+
+	/* read pointer offset in bytes */
+	unsigned int read_offset;
+
+	/* write pointer offset in bytes */
+	unsigned int write_offset;
+
+	/* non-zero if data error occured */
+	int error;
+};
+
 typedef struct dmx_caps {
 	__u32 caps;
 	int num_decoders;
@@ -135,6 +160,34 @@
 	DMX_SOURCE_DVR3
 } dmx_source_t;
 
+enum dmx_tsp_format_t {
+	DMX_TSP_FORMAT_188 = 0,
+	DMX_TSP_FORMAT_192_TAIL,
+	DMX_TSP_FORMAT_192_HEAD,
+	DMX_TSP_FORMAT_204,
+};
+
+enum dmx_playback_mode_t {
+	/*
+	 * In push mode, if one of output buffers
+	 * is full, the buffer would overflow
+	 * and demux continue processing incoming stream.
+	 * This is the default mode. When playing from frontend,
+	 * this is the only mode that is allowed.
+	 */
+	DMX_PB_MODE_PUSH = 0,
+
+	/*
+	 * In pull mode, if one of output buffers
+	 * is full, demux stalls waiting for free space,
+	 * this would cause DVR input buffer fullness
+	 * to accumulate.
+	 * This mode is possible only when playing
+	 * from DVR.
+	 */
+	DMX_PB_MODE_PULL,
+};
+
 struct dmx_stc {
 	unsigned int num;	/* input : which STC? 0..N */
 	unsigned int base;	/* output: divisor for stc to get 90 kHz clock */
@@ -153,5 +206,12 @@
 #define DMX_GET_STC              _IOWR('o', 50, struct dmx_stc)
 #define DMX_ADD_PID              _IOW('o', 51, __u16)
 #define DMX_REMOVE_PID           _IOW('o', 52, __u16)
+#define DMX_SET_TS_PACKET_FORMAT _IOW('o', 53, enum dmx_tsp_format_t)
+#define DMX_SET_TS_OUT_FORMAT	 _IOW('o', 54, enum dmx_tsp_format_t)
+#define DMX_SET_DECODER_BUFFER_SIZE	_IO('o', 55)
+#define DMX_GET_BUFFER_STATUS	 _IOR('o', 56, struct dmx_buffer_status)
+#define DMX_RELEASE_DATA		 _IO('o', 57)
+#define DMX_FEED_DATA			 _IO('o', 58)
+#define DMX_SET_PLAYBACK_MODE	 _IOW('o', 59, enum dmx_playback_mode_t)
 
 #endif /*_DVBDMX_H_*/
diff --git a/include/linux/fmem.h b/include/linux/fmem.h
index 44b7005..e4fa82c 100644
--- a/include/linux/fmem.h
+++ b/include/linux/fmem.h
@@ -22,6 +22,7 @@
 	unsigned long size;
 	unsigned long reserved_size_low;
 	unsigned long reserved_size_high;
+	unsigned long align;
 };
 
 struct fmem_data {
diff --git a/include/linux/genlock.h b/include/linux/genlock.h
index 9351a15..587c49d 100644
--- a/include/linux/genlock.h
+++ b/include/linux/genlock.h
@@ -21,7 +21,8 @@
 #define GENLOCK_WRLOCK 1
 #define GENLOCK_RDLOCK 2
 
-#define GENLOCK_NOBLOCK (1 << 0)
+#define GENLOCK_NOBLOCK       (1 << 0)
+#define GENLOCK_WRITE_TO_READ (1 << 1)
 
 struct genlock_lock {
 	int fd;
@@ -37,6 +38,8 @@
 	struct genlock_lock)
 #define GENLOCK_IOC_ATTACH _IOW(GENLOCK_IOC_MAGIC, 2, \
 	struct genlock_lock)
+
+/* Deprecated */
 #define GENLOCK_IOC_LOCK _IOW(GENLOCK_IOC_MAGIC, 3, \
 	struct genlock_lock)
 
@@ -44,4 +47,6 @@
 #define GENLOCK_IOC_RELEASE _IO(GENLOCK_IOC_MAGIC, 4)
 #define GENLOCK_IOC_WAIT _IOW(GENLOCK_IOC_MAGIC, 5, \
 	struct genlock_lock)
+#define GENLOCK_IOC_DREADLOCK _IOW(GENLOCK_IOC_MAGIC, 6, \
+	struct genlock_lock)
 #endif
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index ed1f112..01c5ca9 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -28,9 +28,18 @@
 #define IOMMU_CACHE	(4) /* DMA cache coherency */
 
 struct device;
+struct iommu_domain;
+
+/* iommu fault flags */
+#define IOMMU_FAULT_READ	0x0
+#define IOMMU_FAULT_WRITE	0x1
+
+typedef int (*iommu_fault_handler_t)(struct iommu_domain *,
+				struct device *, unsigned long, int);
 
 struct iommu_domain {
 	void *priv;
+	iommu_fault_handler_t handler;
 };
 
 #define IOMMU_CAP_CACHE_COHERENCY	0x1
@@ -79,6 +88,47 @@
 extern int iommu_domain_has_cap(struct iommu_domain *domain,
 				unsigned long cap);
 extern phys_addr_t iommu_get_pt_base_addr(struct iommu_domain *domain);
+extern void iommu_set_fault_handler(struct iommu_domain *domain,
+					iommu_fault_handler_t handler);
+
+/**
+ * report_iommu_fault() - report about an IOMMU fault to the IOMMU framework
+ * @domain: the iommu domain where the fault has happened
+ * @dev: the device where the fault has happened
+ * @iova: the faulting address
+ * @flags: mmu fault flags (e.g. IOMMU_FAULT_READ/IOMMU_FAULT_WRITE/...)
+ *
+ * This function should be called by the low-level IOMMU implementations
+ * whenever IOMMU faults happen, to allow high-level users, that are
+ * interested in such events, to know about them.
+ *
+ * This event may be useful for several possible use cases:
+ * - mere logging of the event
+ * - dynamic TLB/PTE loading
+ * - if restarting of the faulting device is required
+ *
+ * Returns 0 on success and an appropriate error code otherwise (if dynamic
+ * PTE/TLB loading will one day be supported, implementations will be able
+ * to tell whether it succeeded or not according to this return value).
+ *
+ * Specifically, -ENOSYS is returned if a fault handler isn't installed
+ * (though fault handlers can also return -ENOSYS, in case they want to
+ * elicit the default behavior of the IOMMU drivers).
+ */
+static inline int report_iommu_fault(struct iommu_domain *domain,
+		struct device *dev, unsigned long iova, int flags)
+{
+	int ret = -ENOSYS;
+
+	/*
+	 * if upper layers showed interest and installed a fault handler,
+	 * invoke it.
+	 */
+	if (domain->handler)
+		ret = domain->handler(domain, dev, iova, flags);
+
+	return ret;
+}
 
 #else /* CONFIG_IOMMU_API */
 
@@ -152,6 +202,12 @@
 {
 	return 0;
 }
+
+static inline void iommu_set_fault_handler(struct iommu_domain *domain,
+					iommu_fault_handler_t handler)
+{
+}
+
 #endif /* CONFIG_IOMMU_API */
 
 #endif /* __LINUX_IOMMU_H */
diff --git a/include/linux/ion.h b/include/linux/ion.h
index ae49bce..b5495a0 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -177,6 +177,8 @@
  *			or not.
  * @fixed_position	If nonzero, position in the fixed area.
  * @virt_addr:		Virtual address used when using fmem.
+ * @iommu_map_all:	Indicates whether we should map whole heap into IOMMU.
+ * @iommu_2x_map_domain: Indicates the domain to use for overmapping.
  * @request_region:	function to be called when the number of allocations
  *			goes from 0 -> 1
  * @release_region:	function to be called when the number of allocations
@@ -192,6 +194,8 @@
 	int reusable;
 	int mem_is_fmem;
 	enum ion_fixed_position fixed_position;
+	int iommu_map_all;
+	int iommu_2x_map_domain;
 	ion_virt_addr_t *virt_addr;
 	int (*request_region)(void *);
 	int (*release_region)(void *);
diff --git a/include/linux/iopoll.h b/include/linux/iopoll.h
index 0104abc..7169870 100644
--- a/include/linux/iopoll.h
+++ b/include/linux/iopoll.h
@@ -43,7 +43,7 @@
 		if ((cond) || (timeout_us && time_after(jiffies, timeout))) \
 			break; \
 		if (sleep_us) \
-			usleep_range(1, sleep_us); \
+			usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); \
 	} \
 	(cond) ? 0 : -ETIMEDOUT; \
 })
diff --git a/include/linux/mfd/pm8xxx/gpio.h b/include/linux/mfd/pm8xxx/gpio.h
index 9918620..ccd9c10 100644
--- a/include/linux/mfd/pm8xxx/gpio.h
+++ b/include/linux/mfd/pm8xxx/gpio.h
@@ -78,6 +78,16 @@
 #define PM8038_GPIO_VIN_L3		5
 #define PM8038_GPIO_VIN_L17		6
 
+/* vin_sel: Voltage Input Select on PM8018*/
+#define PM8018_GPIO_VIN_L4		0
+#define PM8018_GPIO_VIN_L14		1
+#define PM8018_GPIO_VIN_S3		2
+#define PM8018_GPIO_VIN_L6		3
+#define PM8018_GPIO_VIN_L2		4
+#define PM8018_GPIO_VIN_L5		5
+#define PM8018_GPIO_VIN_L8		6
+#define PM8018_GPIO_VIN_VPH		7
+
 /* out_strength */
 #define	PM_GPIO_STRENGTH_NO		0
 #define	PM_GPIO_STRENGTH_HIGH		1
diff --git a/include/linux/mfd/pm8xxx/misc.h b/include/linux/mfd/pm8xxx/misc.h
index 77683ce..c4b0ea4 100644
--- a/include/linux/mfd/pm8xxx/misc.h
+++ b/include/linux/mfd/pm8xxx/misc.h
@@ -89,6 +89,12 @@
 	XO_DIV_64,
 };
 
+enum pm8xxx_hsed_bias {
+	PM8XXX_HSED_BIAS0,
+	PM8XXX_HSED_BIAS1,
+	PM8XXX_HSED_BIAS2,
+};
+
 #if defined(CONFIG_MFD_PM8XXX_MISC) || defined(CONFIG_MFD_PM8XXX_MISC_MODULE)
 
 /**
@@ -210,6 +216,14 @@
 				enum pm8xxx_aux_clk_div divider,
 				bool enable);
 
+/**
+ * pm8xxx_hsed_bias_control - Control the HSED_BIAS signal
+ * @bias: the bias line to be controlled (of the 3)
+ * @enable: enable/disable the bias line
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_hsed_bias_control(enum pm8xxx_hsed_bias bias, bool enable);
 #else
 
 static inline int pm8xxx_reset_pwr_off(int reset)
@@ -259,6 +273,11 @@
 {
 	return -ENODEV;
 }
+static inline int pm8xxx_hsed_bias_control(enum pm8xxx_hsed_bias bias,
+							bool enable)
+{
+	return -ENODEV;
+}
 
 #endif
 
diff --git a/include/linux/mfd/pm8xxx/pm8038.h b/include/linux/mfd/pm8xxx/pm8038.h
index 4d3c78f..90557b9 100644
--- a/include/linux/mfd/pm8xxx/pm8038.h
+++ b/include/linux/mfd/pm8xxx/pm8038.h
@@ -32,6 +32,7 @@
 #include <linux/mfd/pm8xxx/pm8921-bms.h>
 #include <linux/leds-pm8xxx.h>
 #include <linux/mfd/pm8xxx/ccadc.h>
+#include <linux/mfd/pm8xxx/spk.h>
 
 #define PM8038_CORE_DEV_NAME "pm8038-core"
 
@@ -78,6 +79,7 @@
 	struct pm8xxx_adc_platform_data		*adc_pdata;
 	struct pm8xxx_led_platform_data		*leds_pdata;
 	struct pm8xxx_ccadc_platform_data	*ccadc_pdata;
+	struct pm8xxx_spk_platform_data		*spk_pdata;
 };
 
 #endif
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index 4dc3c80..537e0b5 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -118,6 +118,8 @@
  *			calculated or the peak system current (mA)
  * @v_failure:		the voltage at which the battery is considered empty(mV)
  * @calib_delay_ms:	how often should the adc calculate gain and offset
+ * @enable_fcc_learning:	if set the driver will learn full charge
+ *				capacity of the battery upon end of charge
  */
 struct pm8921_bms_platform_data {
 	struct pm8xxx_bms_core_data	bms_cdata;
@@ -128,6 +130,7 @@
 	unsigned int			calib_delay_ms;
 	unsigned int			max_voltage_uv;
 	unsigned int			rconn_mohm;
+	int				enable_fcc_learning;
 };
 
 #if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
diff --git a/include/linux/mfd/pm8xxx/spk.h b/include/linux/mfd/pm8xxx/spk.h
new file mode 100644
index 0000000..1155d2f
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/spk.h
@@ -0,0 +1,47 @@
+/* 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.
+ */
+
+#ifndef __SPK_PM8XXX_H__
+#define __SPK_PM8XXX_H__
+
+#define PM8XXX_SPK_DEV_NAME     "pm8xxx-spk"
+
+/**
+ * struct pm8xxx_spk_pdata - SPK driver platform data
+ * @spk_add_enable: variable stating SPK secondary input adding capability
+ */
+struct pm8xxx_spk_platform_data {
+	bool spk_add_enable;
+};
+
+/*
+ * pm8xxx_spk_mute - mute/unmute speaker pamp
+ *
+ * @mute: bool value for mute
+ */
+int pm8xxx_spk_mute(bool mute);
+
+/*
+ * pm8xxx_spk_gain - Set Speaker gain
+ *
+ * @gain: Speaker gain
+ */
+int pm8xxx_spk_gain(u8 gain);
+
+/*
+ * pm8xxx_spk_enable - Enable/Disable Speaker
+ *
+ * @enable: bool enable/disable Speaker
+ */
+int pm8xxx_spk_enable(int enable);
+
+#endif /* __SPK_PM8XXX_H__ */
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 8a0c4d5..aa808dc 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -228,6 +228,7 @@
 	struct sdio_cccr	cccr;		/* common card info */
 	struct sdio_cis		cis;		/* common tuple info */
 	struct sdio_func	*sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */
+	struct sdio_func	*sdio_single_irq; /* SDIO function when only one IRQ active */
 	unsigned		num_info;	/* number of info strings */
 	const char		**info;		/* info strings */
 	struct sdio_func_tuple	*tuples;	/* unknown common tuples */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index a2ee306..c9a17de 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -317,6 +317,7 @@
 
 	unsigned int		sdio_irqs;
 	struct task_struct	*sdio_irq_thread;
+	bool			sdio_irq_pending;
 	atomic_t		sdio_irq_thread_abort;
 
 	mmc_pm_flag_t		pm_flags;	/* requested pm features */
@@ -411,6 +412,7 @@
 static inline void mmc_signal_sdio_irq(struct mmc_host *host)
 {
 	host->ops->enable_sdio_irq(host, 0);
+	host->sdio_irq_pending = true;
 	wake_up_process(host->sdio_irq_thread);
 }
 
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 244b957..e67190f 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -157,8 +157,18 @@
 #define KGSL_2D1_REG_MEMORY	"kgsl_2d1_reg_memory"
 #define KGSL_2D1_IRQ		"kgsl_2d1_irq"
 
+enum kgsl_iommu_context_id {
+	KGSL_IOMMU_CONTEXT_USER = 0,
+	KGSL_IOMMU_CONTEXT_PRIV = 1,
+};
+
+struct kgsl_iommu_ctx {
+	const char *iommu_ctx_name;
+	enum kgsl_iommu_context_id ctx_id;
+};
+
 struct kgsl_device_iommu_data {
-	const char **iommu_ctx_names;
+	const struct kgsl_iommu_ctx *iommu_ctxs;
 	int iommu_ctx_count;
 	unsigned int physstart;
 	unsigned int physend;
diff --git a/include/linux/msm_rotator.h b/include/linux/msm_rotator.h
index 02ffd59..0f15a8b 100644
--- a/include/linux/msm_rotator.h
+++ b/include/linux/msm_rotator.h
@@ -52,7 +52,6 @@
 	unsigned int number_of_clocks;
 	unsigned int hardware_version_number;
 	struct msm_rot_clocks *rotator_clks;
-	const char *regulator_name;
 #ifdef CONFIG_MSM_BUS_SCALING
 	struct msm_bus_scale_pdata *bus_scale_table;
 #endif
diff --git a/include/linux/msm_tsens.h b/include/linux/msm_tsens.h
index f5472ec..1b0d399 100644
--- a/include/linux/msm_tsens.h
+++ b/include/linux/msm_tsens.h
@@ -26,11 +26,13 @@
 	MSM_TYPE
 };
 
+#define TSENS_MAX_SENSORS		11
+
 struct tsens_platform_data {
+	int				slope[TSENS_MAX_SENSORS];
 	int				tsens_factor;
 	uint32_t			tsens_num_sensor;
 	enum platform_type		hw_type;
-	int				slope[11];
 };
 
 struct tsens_device {
diff --git a/include/linux/msm_vidc_enc.h b/include/linux/msm_vidc_enc.h
index bf149eb..519c537 100644
--- a/include/linux/msm_vidc_enc.h
+++ b/include/linux/msm_vidc_enc.h
@@ -454,6 +454,10 @@
 #define VEN_IOCTL_GET_EXTRADATA \
 	_IOR(VEN_IOCTLBASE_ENC, 49, struct venc_ioctl_msg)
 
+/*IOCTL params:SET: InputData - NULL, OutputData - NULL.*/
+#define VEN_IOCTL_SET_SLICE_DELIVERY_MODE \
+	_IO(VEN_IOCTLBASE_ENC, 50)
+
 struct venc_switch{
 	unsigned char	status;
 };
diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h
index 6598c04..aec8025 100644
--- a/include/linux/of_gpio.h
+++ b/include/linux/of_gpio.h
@@ -46,8 +46,9 @@
 	return container_of(gc, struct of_mm_gpio_chip, gc);
 }
 
-extern int of_get_gpio_flags(struct device_node *np, int index,
-			     enum of_gpio_flags *flags);
+extern int of_get_named_gpio_flags(struct device_node *np,
+		const char *list_name, int index, enum of_gpio_flags *flags);
+
 extern unsigned int of_gpio_count(struct device_node *np);
 
 extern int of_mm_gpiochip_add(struct device_node *np,
@@ -60,8 +61,8 @@
 #else /* CONFIG_OF_GPIO */
 
 /* Drivers may not strictly depend on the GPIO support, so let them link. */
-static inline int of_get_gpio_flags(struct device_node *np, int index,
-				    enum of_gpio_flags *flags)
+static inline int of_get_named_gpio_flags(struct device_node *np,
+		const char *list_name, int index, enum of_gpio_flags *flags)
 {
 	return -ENOSYS;
 }
@@ -77,7 +78,38 @@
 #endif /* CONFIG_OF_GPIO */
 
 /**
- * of_get_gpio - Get a GPIO number to use with GPIO API
+ * of_get_gpio_flags() - Get a GPIO number and flags to use with GPIO API
+ * @np:		device node to get GPIO from
+ * @index:	index of the GPIO
+ * @flags:	a flags pointer to fill in
+ *
+ * Returns GPIO number to use with Linux generic GPIO API, or one of the errno
+ * value on the error condition. If @flags is not NULL the function also fills
+ * in flags for the GPIO.
+ */
+static inline int of_get_gpio_flags(struct device_node *np, int index,
+		      enum of_gpio_flags *flags)
+{
+	return of_get_named_gpio_flags(np, "gpios", index, flags);
+}
+
+/**
+ * of_get_named_gpio() - Get a GPIO number to use with GPIO API
+ * @np:		device node to get GPIO from
+ * @propname:	Name of property containing gpio specifier(s)
+ * @index:	index of the GPIO
+ *
+ * Returns GPIO number to use with Linux generic GPIO API, or one of the errno
+ * value on the error condition.
+ */
+static inline int of_get_named_gpio(struct device_node *np,
+                                   const char *propname, int index)
+{
+	return of_get_named_gpio_flags(np, propname, index, NULL);
+}
+
+/**
+ * of_get_gpio() - Get a GPIO number to use with GPIO API
  * @np:		device node to get GPIO from
  * @index:	index of the GPIO
  *
diff --git a/include/linux/qpnp/gpio.h b/include/linux/qpnp/gpio.h
index a31b7f3..e7fb53e 100644
--- a/include/linux/qpnp/gpio.h
+++ b/include/linux/qpnp/gpio.h
@@ -12,12 +12,16 @@
 
 #include <mach/qpnp.h>
 
+#define QPNP_GPIO_DIR_IN			0
 #define QPNP_GPIO_DIR_OUT			1
-#define QPNP_GPIO_DIR_IN			2
-#define QPNP_GPIO_DIR_BOTH	(QPNP_GPIO_DIR_OUT | QPNP_GPIO_DIR_IN)
+#define QPNP_GPIO_DIR_BOTH			2
 
-#define QPNP_GPIO_OUT_BUF_OPEN_DRAIN		1
+#define QPNP_GPIO_INVERT_DISABLE		0
+#define QPNP_GPIO_INVERT_ENABLE			1
+
 #define QPNP_GPIO_OUT_BUF_CMOS			0
+#define QPNP_GPIO_OUT_BUF_OPEN_DRAIN_NMOS	1
+#define QPNP_GPIO_OUT_BUF_OPEN_DRAIN_PMOS	2
 
 #define QPNP_GPIO_VIN0				0
 #define QPNP_GPIO_VIN1				1
@@ -39,14 +43,17 @@
 #define QPNP_GPIO_OUT_STRENGTH_MED		2
 #define QPNP_GPIO_OUT_STRENGTH_HIGH		3
 
-#define QPNP_GPIO_FUNC_NORMAL			0
-#define QPNP_GPIO_FUNC_PAIRED			1
-#define QPNP_GPIO_FUNC_1			2
-#define QPNP_GPIO_FUNC_2			3
-#define QPNP_GPIO_DTEST1			4
-#define QPNP_GPIO_DTEST2			5
-#define QPNP_GPIO_DTEST3			6
-#define QPNP_GPIO_DTEST4			7
+#define QPNP_GPIO_SRC_FUNC_NORMAL		0
+#define QPNP_GPIO_SRC_FUNC_PAIRED		1
+#define QPNP_GPIO_SRC_FUNC_1			2
+#define QPNP_GPIO_SRC_FUNC_2			3
+#define QPNP_GPIO_SRC_DTEST1			4
+#define QPNP_GPIO_SRC_DTEST2			5
+#define QPNP_GPIO_SRC_DTEST3			6
+#define QPNP_GPIO_SRC_DTEST4			7
+
+#define QPNP_GPIO_MASTER_DISABLE		0
+#define QPNP_GPIO_MASTER_ENABLE			1
 
 /**
  * struct qpnp_gpio_cfg - structure to specify gpio configurtion values
@@ -54,7 +61,8 @@
  *			both. Should be of the type QPNP_GPIO_DIR_*
  * @output_type:	indicates gpio should be configured as CMOS or open
  *			drain. Should be of the type QPNP_GPIO_OUT_BUF_*
- * @output_value:	The gpio output value of the gpio line - 0 or 1
+ * @invert:		Invert the signal of the gpio line -
+ *			QPNP_GPIO_INVERT_DISABLE or QPNP_GPIO_INVERT_ENABLE
  * @pull:		Indicates whether a pull up or pull down should be
  *			applied. If a pullup is required the current strength
  *			needs to be specified. Current values of 30uA, 1.5uA,
@@ -68,21 +76,22 @@
  * @source_sel:		choose alternate function for the gpio. Certain gpios
  *			can be paired (shorted) with each other. Some gpio pin
  *			can act as alternate functions. This parameter should
- *			be of type QPNP_GPIO_FUNC_*
- * @master_en:		1 = Enable features within the GPIO block based on
- *			configurations.
- *			0 = Completely disable the GPIO block and let the pin
- *			float with high impedance regardless of other settings.
+ *			be of type QPNP_GPIO_SRC_*.
+ * @master_en:		QPNP_GPIO_MASTER_ENABLE = Enable features within the
+ *			GPIO block based on configurations.
+ *			QPNP_GPIO_MASTER_DISABLE = Completely disable the GPIO
+ *			block and let the pin float with high impedance
+ *			regardless of other settings.
  */
 struct qpnp_gpio_cfg {
-	int		direction;
-	int		output_type;
-	int		output_value;
-	int		pull;
-	int		vin_sel;
-	int		out_strength;
-	int		src_select;
-	int		master_en;
+	unsigned int direction;
+	unsigned int output_type;
+	unsigned int invert;
+	unsigned int pull;
+	unsigned int vin_sel;
+	unsigned int out_strength;
+	unsigned int src_select;
+	unsigned int master_en;
 };
 
 /**
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index b920a72..f13b52b 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1370,6 +1370,16 @@
 }
 #endif /* NET_SKBUFF_DATA_USES_OFFSET */
 
+static inline void skb_mac_header_rebuild(struct sk_buff *skb)
+{
+	if (skb_mac_header_was_set(skb)) {
+		const unsigned char *old_mac = skb_mac_header(skb);
+
+		skb_set_mac_header(skb, -skb->mac_len);
+		memmove(skb_mac_header(skb), old_mac, skb->mac_len);
+	}
+}
+
 static inline int skb_checksum_start_offset(const struct sk_buff *skb)
 {
 	return skb->csum_start - skb_headroom(skb);
diff --git a/include/linux/usb/android.h b/include/linux/usb/android.h
index 9d7e4a8..6d3c3ad 100644
--- a/include/linux/usb/android.h
+++ b/include/linux/usb/android.h
@@ -19,6 +19,7 @@
 
 struct android_usb_platform_data {
 	int (*update_pid_and_serial_num)(uint32_t, const char *);
+	u32 swfi_latency;
 };
 
 #endif	/* __LINUX_USB_ANDROID_H */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 4c0ae07..b53d9dd 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -23,7 +23,6 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/wakelock.h>
-#include <linux/pm_qos_params.h>
 
 /*
  * The following are bit fields describing the usb_request.udc_priv word.
@@ -160,19 +159,6 @@
 };
 
 /**
- * SPS Pipes direction.
- *
- * USB_TO_PEER_PERIPHERAL	USB (as Producer) to other
- *                          peer peripheral.
- * PEER_PERIPHERAL_TO_USB	Other Peripheral to
- *                          USB (as consumer).
- */
-enum usb_bam_pipe_dir {
-	USB_TO_PEER_PERIPHERAL,
-	PEER_PERIPHERAL_TO_USB,
-};
-
-/**
  * struct msm_otg_platform_data - platform device data
  *              for msm_otg driver.
  * @phy_init_seq: PHY configuration sequence. val, reg pairs
@@ -188,7 +174,6 @@
  * @mhl_enable: indicates MHL connector or not.
  * @disable_reset_on_disconnect: perform USB PHY and LINK reset
  *              on USB cable disconnection.
- * @swfi_latency: miminum latency to allow swfi.
  * @enable_dcd: Enable Data Contact Detection circuit. if not set
  *              wait for 600msec before proceeding to primary
  *              detection.
@@ -206,7 +191,6 @@
 	int pmic_id_irq;
 	bool mhl_enable;
 	bool disable_reset_on_disconnect;
-	u32 swfi_latency;
 	bool enable_dcd;
 	struct msm_bus_scale_pdata *bus_scale_table;
 };
@@ -277,8 +261,6 @@
  *             connected. Useful only when ACA_A charger is
  *             connected.
  * @mA_port: The amount of current drawn by the attached B-device.
- * @pm_qos_req_dma: miminum DMA latency to vote against idle power
-	collapse when cable is connected.
  * @id_timer: The timer used for polling ID line to detect ACA states.
  * @xo_handle: TCXO buffer handle
  * @bus_perf_client: Bus performance client handle to request BUS bandwidth
@@ -341,7 +323,6 @@
 	unsigned long lpm_flags;
 #define PHY_PWR_COLLAPSED		BIT(0)
 #define PHY_RETENTIONED			BIT(1)
-	struct pm_qos_request_list pm_qos_req_dma;
 	int reset_counter;
 	unsigned long b_last_se0_sess;
 	unsigned long tmouts;
@@ -361,6 +342,10 @@
 	unsigned int dock_connect_irq;
 };
 
+struct msm_hsic_peripheral_platform_data {
+	bool keep_core_clk_on_suspend_workaround;
+};
+
 struct usb_bam_pipe_connect {
 	u32 src_phy_addr;
 	int src_pipe_index;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 147b068..a3b45c9 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -656,6 +656,7 @@
 /* Cache handling flags */
 #define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE	0x0800
 #define V4L2_BUF_FLAG_NO_CACHE_CLEAN		0x1000
+#define V4L2_BUF_FLAG_EOS		0x2000
 
 /*
  *	O V E R L A Y   P R E V I E W
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index 51cc78f..e776d41 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -52,6 +52,7 @@
 #define VCD_I_DISABLE_DMX_SUPPORT (VCD_START_BASE + 0x24)
 #define VCD_I_ENABLE_SPS_PPS_FOR_IDR (VCD_START_BASE + 0x25)
 #define VCD_REQ_PERF_LEVEL (VCD_START_BASE + 0x26)
+#define VCD_I_SLICE_DELIVERY_MODE (VCD_START_BASE + 0x27)
 
 #define VCD_START_REQ      (VCD_START_BASE + 0x1000)
 #define VCD_I_REQ_IFRAME   (VCD_START_REQ + 0x1)
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 7aae5e1..3f647dc 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -187,6 +187,9 @@
 #define MSM_CAM_IOCTL_GET_ACTUATOR_INFO \
 	_IOW(MSM_CAM_IOCTL_MAGIC, 52, struct msm_actuator_cfg_data *)
 
+#define MSM_CAM_IOCTL_EEPROM_IO_CFG \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 53, struct msm_eeprom_cfg_data *)
+
 struct msm_mctl_pp_cmd {
 	int32_t  id;
 	uint16_t length;
@@ -438,6 +441,7 @@
 #define CMD_AXI_CFG_ZSL_ALL_CHNLS 49
 #define CMD_AXI_CFG_VIDEO_ALL_CHNLS 50
 #define CMD_VFE_BUFFER_RELEASE 51
+#define CMD_VFE_PROCESS_IRQ 52
 
 #define CMD_AXI_CFG_PRIM		0xF1
 #define CMD_AXI_CFG_PRIM_ALL_CHNLS	0xF2
@@ -777,18 +781,19 @@
 #define CFG_GET_3D_CALI_DATA 30
 #define CFG_GET_CALIB_DATA		31
 #define CFG_GET_OUTPUT_INFO		32
-#define CFG_GET_EEPROM_DATA		33
-#define CFG_SET_ACTUATOR_INFO		34
-#define CFG_GET_ACTUATOR_INFO           35
+#define CFG_GET_EEPROM_INFO		33
+#define CFG_GET_EEPROM_DATA		34
+#define CFG_SET_ACTUATOR_INFO		35
+#define CFG_GET_ACTUATOR_INFO           36
 /* TBD: QRD */
-#define CFG_SET_SATURATION            36
-#define CFG_SET_SHARPNESS             37
-#define CFG_SET_TOUCHAEC              38
-#define CFG_SET_AUTO_FOCUS            39
-#define CFG_SET_AUTOFLASH             40
-#define CFG_SET_EXPOSURE_COMPENSATION 41
-#define CFG_SET_ISO                   42
-#define CFG_MAX			43
+#define CFG_SET_SATURATION            37
+#define CFG_SET_SHARPNESS             38
+#define CFG_SET_TOUCHAEC              39
+#define CFG_SET_AUTO_FOCUS            40
+#define CFG_SET_AUTOFLASH             41
+#define CFG_SET_EXPOSURE_COMPENSATION 42
+#define CFG_SET_ISO                   43
+#define CFG_MAX			44
 
 
 #define MOVE_NEAR	0
@@ -1075,11 +1080,6 @@
 	uint16_t num_info;
 };
 
-struct sensor_eeprom_data_t {
-	void *eeprom_data;
-	uint16_t index;
-};
-
 struct mirror_flip {
 	int32_t x_mirror;
 	int32_t y_flip;
@@ -1090,6 +1090,11 @@
 	uint32_t y;
 };
 
+struct msm_eeprom_data_t {
+	void *eeprom_data;
+	uint16_t index;
+};
+
 struct sensor_cfg_data {
 	int cfgtype;
 	int mode;
@@ -1115,7 +1120,7 @@
 		struct sensor_3d_exp_cfg sensor_3d_exp;
 		struct sensor_calib_data calib_info;
 		struct sensor_output_info_t output_info;
-		struct sensor_eeprom_data_t eeprom_data;
+		struct msm_eeprom_data_t eeprom_data;
 		/* QRD */
 		uint16_t antibanding;
 		uint8_t contrast;
@@ -1249,6 +1254,60 @@
 	} cfg;
 };
 
+struct msm_eeprom_support {
+	uint16_t is_supported;
+	uint16_t size;
+	uint16_t index;
+	uint16_t qvalue;
+};
+
+struct msm_calib_wb {
+	uint16_t r_over_g;
+	uint16_t b_over_g;
+	uint16_t gr_over_gb;
+};
+
+struct msm_calib_af {
+	uint16_t macro_dac;
+	uint16_t inf_dac;
+	uint16_t start_dac;
+};
+
+struct msm_calib_lsc {
+	uint16_t r_gain[221];
+	uint16_t b_gain[221];
+	uint16_t gr_gain[221];
+	uint16_t gb_gain[221];
+};
+
+struct pixel_t {
+	int x;
+	int y;
+};
+
+struct msm_calib_dpc {
+	uint16_t validcount;
+	struct pixel_t snapshot_coord[128];
+	struct pixel_t preview_coord[128];
+	struct pixel_t video_coord[128];
+};
+
+struct msm_camera_eeprom_info_t {
+	struct msm_eeprom_support af;
+	struct msm_eeprom_support wb;
+	struct msm_eeprom_support lsc;
+	struct msm_eeprom_support dpc;
+};
+
+struct msm_eeprom_cfg_data {
+	int cfgtype;
+	uint8_t is_eeprom_supported;
+	union {
+		struct msm_eeprom_data_t get_data;
+		struct msm_camera_eeprom_info_t get_info;
+	} cfg;
+};
+
 struct sensor_large_data {
 	int cfgtype;
 	union {
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
new file mode 100644
index 0000000..b883ffa
--- /dev/null
+++ b/include/media/msm_vidc.h
@@ -0,0 +1,47 @@
+/* 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.
+ *
+ */
+
+#ifndef _MSM_VIDC_H_
+#define _MSM_VIDC_H_
+
+#include <linux/videodev2.h>
+#include <linux/poll.h>
+
+enum core_id {
+	MSM_VIDC_CORE_0 = 0,
+	MSM_VIDC_CORES_MAX,
+};
+
+enum session_type {
+	MSM_VIDC_ENCODER = 0,
+	MSM_VIDC_DECODER,
+	MSM_VIDC_MAX_DEVICES,
+};
+
+void *msm_vidc_open(int core_id, int session_type);
+int msm_vidc_close(void *instance);
+int msm_vidc_querycap(void *instance, struct v4l2_capability *cap);
+int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
+int msm_vidc_s_fmt(void *instance, struct v4l2_format *f);
+int msm_vidc_g_fmt(void *instance, struct v4l2_format *f);
+int msm_vidc_s_ctrl(void *instance, struct v4l2_control *a);
+int msm_vidc_g_ctrl(void *instance, struct v4l2_control *a);
+int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
+int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_streamon(void *instance, enum v4l2_buf_type i);
+int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i);
+int msm_vidc_poll(void *instance, struct file *filp,
+		struct poll_table_struct *pt);
+#endif
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 2114287..d906c9f 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -143,6 +143,7 @@
 #define RC_MAP_TREKSTOR                  "rc-trekstor"
 #define RC_MAP_TT_1500                   "rc-tt-1500"
 #define RC_MAP_TWINHAN_VP1027_DVBS       "rc-twinhan1027"
+#define RC_MAP_UE_RF4CE			 "rc-ue-rf4ce"
 #define RC_MAP_VIDEOMATE_M1F             "rc-videomate-m1f"
 #define RC_MAP_VIDEOMATE_S350            "rc-videomate-s350"
 #define RC_MAP_VIDEOMATE_TV_PVR          "rc-videomate-tv-pvr"
diff --git a/include/media/tavarua.h b/include/media/tavarua.h
index 381f5c4..52194f9 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               (64)
+#define STD_BUF_SIZE               (128)
 /* Search direction */
 #define SRCH_DIR_UP                 (0)
 #define SRCH_DIR_DOWN               (1)
diff --git a/include/media/user-rc-input.h b/include/media/user-rc-input.h
new file mode 100644
index 0000000..e58e40f
--- /dev/null
+++ b/include/media/user-rc-input.h
@@ -0,0 +1,21 @@
+/* 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.
+ */
+
+#ifndef __USER_RC_INPUT_H__
+#define __USER_RC_INPUT_H__
+
+#define USER_CONTROL_PRESSED    0x01
+#define USER_CONTROL_REPEATED   0x02
+#define USER_CONTROL_RELEASED   0x03
+
+#endif /* __USER_RC_INPUT_H__ */
+
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 7e9f5f4..d218fab 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -99,6 +99,28 @@
  */
 #define BT_AMP_POLICY_PREFER_AMP       2
 
+#define BT_LE_PARAMS	100
+
+#define BT_LE_SCAN_WINDOW_MIN		0x0004
+#define BT_LE_SCAN_WINDOW_MAX		0x4000
+#define BT_LE_SCAN_WINDOW_DEF		0x0004
+
+#define BT_LE_SCAN_INTERVAL_MIN		0x0004
+#define BT_LE_SCAN_INTERVAL_MAX		0x4000
+#define BT_LE_SCAN_INTERVAL_DEF		0x0008
+
+#define BT_LE_CONN_INTERVAL_MIN		0x0006
+#define BT_LE_CONN_INTERVAL_MAX		0x0C80
+#define BT_LE_CONN_INTERVAL_MIN_DEF	0x0008
+#define BT_LE_CONN_INTERVAL_MAX_DEF	0x0100
+
+#define BT_LE_LATENCY_MAX		0x01F4
+#define BT_LE_LATENCY_DEF		0x0000
+
+#define BT_LE_SUP_TO_MIN		0x000A
+#define BT_LE_SUP_TO_MAX		0x0C80
+#define BT_LE_SUP_TO_DEFAULT		0X03E8
+
 #define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg)
 #define BT_ERR(fmt, arg...)  printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
 #define BT_DBG(fmt, arg...)  pr_debug("%s: " fmt "\n" , __func__ , ## arg)
@@ -142,6 +164,20 @@
 
 #define bt_sk(__sk) ((struct bt_sock *) __sk)
 
+struct bt_le_params {
+	__u8  prohibit_remote_chg;
+	__u8  filter_policy;
+	__u16 scan_interval;
+	__u16 scan_window;
+	__u16 interval_min;
+	__u16 interval_max;
+	__u16 latency;
+	__u16 supervision_timeout;
+	__u16 min_ce_len;
+	__u16 max_ce_len;
+	__u16 conn_timeout;
+};
+
 struct bt_sock {
 	struct sock sk;
 	bdaddr_t    src;
@@ -149,6 +185,7 @@
 	struct list_head accept_q;
 	struct sock *parent;
 	u32 defer_setup;
+	struct bt_le_params le_params;
 };
 
 struct bt_sock_list {
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 5053bd8..5749293 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -304,6 +304,7 @@
 	__u8		auth_initiator;
 	__u8		power_save;
 	__u16		disc_timeout;
+	__u16		conn_timeout;
 	unsigned long	pend;
 
 	__u8		remote_cap;
@@ -597,6 +598,10 @@
 struct hci_conn *hci_connect(struct hci_dev *hdev, int type,
 					__u16 pkt_type, bdaddr_t *dst,
 					__u8 sec_level, __u8 auth_type);
+struct hci_conn *hci_le_connect(struct hci_dev *hdev, __u16 pkt_type,
+					bdaddr_t *dst, __u8 sec_level,
+					__u8 auth_type,
+					struct bt_le_params *le_params);
 int hci_conn_check_link_mode(struct hci_conn *conn);
 int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type);
 int hci_conn_change_link_key(struct hci_conn *conn);
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index b903c5c..a098f3e 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -685,6 +685,7 @@
 int l2cap_ertm_tx(struct sock *sk, struct bt_l2cap_control *control,
 			struct sk_buff_head *skbs, u8 event);
 
+int l2cap_sock_le_params_valid(struct bt_le_params *le_params);
 void l2cap_sock_set_timer(struct sock *sk, long timeout);
 void l2cap_sock_clear_timer(struct sock *sk);
 void __l2cap_sock_close(struct sock *sk, int reason);
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 782ee8d..134d044 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 AFE_PORT_INVALID 0xFFFF
-#define SLIMBUS_INVALID AFE_PORT_INVALID
+#define SLIMBUS_EXTPROC_RX AFE_PORT_INVALID
 
 #define AFE_PORT_CMD_START 0x000100ca
 
@@ -352,8 +352,53 @@
 	u16 reserved;
 } __attribute__ ((packed));
 
+/* Parameter ID used to configure and enable/disable the loopback path. The
+ * difference with respect to the existing API, AFE_PORT_CMD_LOOPBACK, is that
+ * it allows Rx port to be configured as source port in loopback path. Port-id
+ * in AFE_PORT_CMD_SET_PARAM cmd is the source port whcih can be Tx or Rx port.
+ * In addition, we can configure the type of routing mode to handle different
+ * use cases.
+*/
+enum {
+	/* Regular loopback from source to destination port */
+	LB_MODE_DEFAULT = 1,
+	/* Sidetone feed from Tx source to Rx destination port */
+	LB_MODE_SIDETONE,
+	/* Echo canceller reference, voice + audio + DTMF */
+	LB_MODE_EC_REF_VOICE_AUDIO,
+	/* Echo canceller reference, voice alone */
+	LB_MODE_EC_REF_VOICE
+};
+
+#define AFE_PARAM_ID_LOOPBACK_CONFIG 0x0001020B
+#define AFE_API_VERSION_LOOPBACK_CONFIG 0x1
+struct afe_param_loopback_cfg {
+	/* Minor version used for tracking the version of the configuration
+	 * interface.
+	 */
+	uint32_t loopback_cfg_minor_version;
+
+	/* Destination Port Id. */
+	uint16_t dst_port_id;
+
+	/* Specifies data path type from src to dest port. Supported values:
+	 * LB_MODE_DEFAULT
+	 * LB_MODE_SIDETONE
+	 * LB_MODE_EC_REF_VOICE_AUDIO
+	 * LB_MODE_EC_REF_VOICE
+	 */
+	uint16_t routing_mode;
+
+	/* Specifies whether to enable (1) or disable (0) an AFE loopback. */
+	uint16_t enable;
+
+	/* Reserved for 32-bit alignment. This field must be set to 0. */
+	uint16_t reserved;
+} __packed;
 
 #define AFE_MODULE_ID_PORT_INFO		0x00010200
+/* Module ID for the loopback-related parameters. */
+#define AFE_MODULE_LOOPBACK           0x00010205
 struct afe_param_payload {
 	u32 module_id;
 	u32 param_id;
@@ -364,6 +409,7 @@
 		struct afe_param_sampling_rate sampling_rate;
 		struct afe_param_channels      channels;
 		struct afe_param_loopback_gain loopback_gain;
+		struct afe_param_loopback_cfg loopback_cfg;
 	} __attribute__((packed)) param;
 } __attribute__ ((packed));
 
@@ -770,7 +816,10 @@
 
 #define PCM_FORMAT_MAX_NUM_CHANNEL  8
 
-
+/* Maximum number of channels supported
+ * in ASM_ENCDEC_DEC_CHAN_MAP command
+ */
+#define MAX_CHAN_MAP_CHANNELS 16
 /*
  *  Multiple-channel PCM decoder format block structure used in the
  *  #ASM_STREAM_CMD_OPEN_WRITE command.
@@ -980,6 +1029,32 @@
 	u16 sce_right;
 };
 
+struct asm_dec_chan_map {
+	u32 num_channels;			  /* Number of decoder output
+						   * channels. A value of 0
+						   * indicates native channel
+						   * mapping, which is valid
+						   * only for NT mode. This
+						   * means the output of the
+						   * decoder is to be preserved
+						   * as is.
+						   */
+
+	u8 channel_mapping[MAX_CHAN_MAP_CHANNELS];/* Channel array of size
+						   * num_channels. It can grow
+						   * till MAX_CHAN_MAP_CHANNELS.
+						   * Channel[i] mapping
+						   * describes channel I inside
+						   * the decoder output buffer.
+						   * Valid channel mapping
+						   * values are to be present at
+						   * the beginning of the array.
+						   * All remaining elements of
+						   * the array are to be filled
+						   * with PCM_CHANNEL_NULL.
+						   */
+};
+
 struct asm_encode_cfg_blk {
 	u32 frames_per_buf;
 	u32 format_id;
@@ -1132,6 +1207,14 @@
 	struct asm_dual_mono channel_map;
 } __packed;
 
+#define ASM_ENCDEC_DEC_CHAN_MAP				 0x00010D82
+struct asm_stream_cmd_encdec_channelmap {
+	struct apr_hdr hdr;
+	u32            param_id;
+	u32            param_size;
+	struct asm_dec_chan_map chan_map;
+} __packed;
+
 #define ASM_STREAM _CMD_ADJUST_SAMPLES                   0x00010C0A
 struct asm_stream_cmd_adjust_samples{
 	struct apr_hdr hdr;
diff --git a/include/sound/msm-dai-q6.h b/include/sound/msm-dai-q6.h
index 89a6a47..6328256 100644
--- a/include/sound/msm-dai-q6.h
+++ b/include/sound/msm-dai-q6.h
@@ -32,8 +32,8 @@
 	int pcm_clk_rate;
 };
 
-struct msm_mi2s_data {
-	u32 capability; /* RX or TX */
-	u16 sd_lines;
+struct msm_mi2s_pdata {
+	u16 rx_sd_lines;
+	u16 tx_sd_lines;
 };
 #endif
diff --git a/include/sound/q6afe.h b/include/sound/q6afe.h
index 9893075..8cdcc18 100644
--- a/include/sound/q6afe.h
+++ b/include/sound/q6afe.h
@@ -74,6 +74,7 @@
 int afe_open(u16 port_id, union afe_port_config *afe_config, int rate);
 int afe_close(int port_id);
 int afe_loopback(u16 enable, u16 rx_port, u16 tx_port);
+int afe_loopback_cfg(u16 enable, u16 dst_port, u16 src_port, u16 mode);
 int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain);
 int afe_loopback_gain(u16 port_id, u16 volume);
 int afe_validate_port(u16 port_id);
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index aec4171..968d46e 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -247,6 +247,9 @@
 int q6asm_cfg_dual_mono_aac(struct audio_client *ac,
 			uint16_t sce_left, uint16_t sce_right);
 
+int q6asm_set_encdec_chan_map(struct audio_client *ac,
+			uint32_t num_channels);
+
 int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
 		uint16_t min_rate, uint16_t max_rate,
 		uint16_t reduced_rate_level, uint16_t rate_modulation_cmd);
diff --git a/include/sound/snd_compress_params.h b/include/sound/snd_compress_params.h
index 472d0ac..e9f6748 100644
--- a/include/sound/snd_compress_params.h
+++ b/include/sound/snd_compress_params.h
@@ -236,6 +236,9 @@
 
 struct snd_enc_wma {
 	__u32 super_block_align; /* WMA Type-specific data */
+	__u32 bits_per_sample;
+	__u32 channelmask;
+	__u32 encodeopt;
 };
 
 
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
index df80c42..f4ceeea 100644
--- a/net/bluetooth/amp.c
+++ b/net/bluetooth/amp.c
@@ -374,13 +374,11 @@
 {
 	struct amp_mgr *mgr;
 
-	read_lock(&amp_mgr_list_lock);
 	list_for_each_entry(mgr, &amp_mgr_list, list) {
 		if (mgr->discovered)
 			send_a2mp_cl(mgr, next_ident(mgr),
 					A2MP_CHANGE_NOTIFY, 0, NULL);
 	}
-	read_unlock(&amp_mgr_list_lock);
 }
 
 static inline int discover_req(struct amp_mgr *mgr, struct sk_buff *skb)
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index d60bf00..25b559b1 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -44,33 +44,77 @@
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
 
-static void hci_le_connect(struct hci_conn *conn)
+struct hci_conn *hci_le_connect(struct hci_dev *hdev, __u16 pkt_type,
+				bdaddr_t *dst, __u8 sec_level, __u8 auth_type,
+				struct bt_le_params *le_params)
 {
-	struct hci_dev *hdev = conn->hdev;
+	struct hci_conn *le;
 	struct hci_cp_le_create_conn cp;
+	struct adv_entry *entry;
+	struct link_key *key;
 
-	BT_DBG("%p", conn);
+	BT_DBG("%p", hdev);
 
-	conn->state = BT_CONNECT;
-	conn->out = 1;
-	conn->link_mode |= HCI_LM_MASTER;
-	conn->sec_level = BT_SECURITY_LOW;
-	conn->type = LE_LINK;
+	le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
+	if (le) {
+		hci_conn_hold(le);
+		return le;
+	}
+
+	key = hci_find_link_key_type(hdev, dst, KEY_TYPE_LTK);
+	if (!key) {
+		entry = hci_find_adv_entry(hdev, dst);
+		if (entry)
+			le = hci_le_conn_add(hdev, dst,
+					entry->bdaddr_type);
+		else
+			le = hci_le_conn_add(hdev, dst, 0);
+	} else {
+		le = hci_le_conn_add(hdev, dst, key->addr_type);
+	}
+
+	if (!le)
+		return ERR_PTR(-ENOMEM);
+
+	hci_conn_hold(le);
+
+	le->state = BT_CONNECT;
+	le->out = 1;
+	le->link_mode |= HCI_LM_MASTER;
+	le->sec_level = BT_SECURITY_LOW;
+	le->type = LE_LINK;
 
 	memset(&cp, 0, sizeof(cp));
-	cp.scan_interval = cpu_to_le16(0x0004);
-	cp.scan_window = cpu_to_le16(0x0004);
-	bacpy(&cp.peer_addr, &conn->dst);
-	cp.peer_addr_type = conn->dst_type;
-	cp.conn_interval_min = cpu_to_le16(0x0008);
-	cp.conn_interval_max = cpu_to_le16(0x0100);
-	cp.supervision_timeout = cpu_to_le16(1000);
-	cp.min_ce_len = cpu_to_le16(0x0001);
-	cp.max_ce_len = cpu_to_le16(0x0001);
+	if (l2cap_sock_le_params_valid(le_params)) {
+		cp.supervision_timeout =
+				cpu_to_le16(le_params->supervision_timeout);
+		cp.scan_interval = cpu_to_le16(le_params->scan_interval);
+		cp.scan_window = cpu_to_le16(le_params->scan_window);
+		cp.conn_interval_min = cpu_to_le16(le_params->interval_min);
+		cp.conn_interval_max = cpu_to_le16(le_params->interval_max);
+		cp.conn_latency = cpu_to_le16(le_params->latency);
+		cp.min_ce_len = cpu_to_le16(le_params->min_ce_len);
+		cp.max_ce_len = cpu_to_le16(le_params->max_ce_len);
+		le->conn_timeout = le_params->conn_timeout;
+	} else {
+		cp.supervision_timeout = cpu_to_le16(BT_LE_SUP_TO_DEFAULT);
+		cp.scan_interval = cpu_to_le16(BT_LE_SCAN_INTERVAL_DEF);
+		cp.scan_window = cpu_to_le16(BT_LE_SCAN_WINDOW_DEF);
+		cp.conn_interval_min = cpu_to_le16(BT_LE_CONN_INTERVAL_MIN_DEF);
+		cp.conn_interval_max = cpu_to_le16(BT_LE_CONN_INTERVAL_MAX_DEF);
+		cp.conn_latency = cpu_to_le16(BT_LE_LATENCY_DEF);
+		le->conn_timeout = 5;
+	}
+	bacpy(&cp.peer_addr, &le->dst);
+	cp.peer_addr_type = le->dst_type;
 
 	hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
+
+	return le;
 }
+EXPORT_SYMBOL(hci_le_connect);
 
 static void hci_le_connect_cancel(struct hci_conn *conn)
 {
@@ -685,41 +729,12 @@
 {
 	struct hci_conn *acl;
 	struct hci_conn *sco;
-	struct hci_conn *le;
 
 	BT_DBG("%s dst %s", hdev->name, batostr(dst));
 
-	if (type == LE_LINK) {
-		struct adv_entry *entry;
-		struct link_key *key;
-
-		le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
-		if (le) {
-			hci_conn_hold(le);
-			return le;
-		}
-
-		key = hci_find_link_key_type(hdev, dst, KEY_TYPE_LTK);
-		if (!key) {
-			entry = hci_find_adv_entry(hdev, dst);
-			if (entry)
-				le = hci_le_conn_add(hdev, dst,
-						entry->bdaddr_type);
-			else
-				le = hci_le_conn_add(hdev, dst, 0);
-		} else {
-			le = hci_le_conn_add(hdev, dst, key->addr_type);
-		}
-
-		if (!le)
-			return ERR_PTR(-ENOMEM);
-
-		hci_le_connect(le);
-
-		hci_conn_hold(le);
-
-		return le;
-	}
+	if (type == LE_LINK)
+		return hci_le_connect(hdev, pkt_type, dst, sec_level,
+							auth_type, NULL);
 
 	acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
 	if (!acl) {
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 598c310..395a95c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1368,6 +1368,7 @@
 {
 	struct hci_cp_le_create_conn *cp;
 	struct hci_conn *conn;
+	unsigned long exp = msecs_to_jiffies(5000);
 
 	BT_DBG("%s status 0x%x", hdev->name, status);
 
@@ -1396,11 +1397,11 @@
 				conn->out = 1;
 			else
 				BT_ERR("No memory for new connection");
-		}
+		} else
+			exp = msecs_to_jiffies(conn->conn_timeout * 1000);
 
-		if (conn)
-			mod_timer(&conn->disc_timer,
-					jiffies + msecs_to_jiffies(5000));
+		if (conn && exp)
+			mod_timer(&conn->disc_timer, jiffies + exp);
 	}
 
 	hci_dev_unlock(hdev);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 37ee9b1..a7b95d3 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1277,8 +1277,9 @@
 		conn = hcon->l2cap_data;
 	} else {
 		if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA)
-			hcon = hci_connect(hdev, LE_LINK, 0, dst,
-					l2cap_pi(sk)->sec_level, auth_type);
+			hcon = hci_le_connect(hdev, 0, dst,
+					l2cap_pi(sk)->sec_level, auth_type,
+					&bt_sk(sk)->le_params);
 		else
 			hcon = hci_connect(hdev, ACL_LINK, 0, dst,
 					l2cap_pi(sk)->sec_level, auth_type);
@@ -1308,7 +1309,17 @@
 		sk->sk_state_change(sk);
 	} else {
 		sk->sk_state = BT_CONNECT;
-		l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
+		/* If we have valid LE Params, let timeout override default */
+		if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA &&
+			l2cap_sock_le_params_valid(&bt_sk(sk)->le_params)) {
+			u16 timeout = bt_sk(sk)->le_params.conn_timeout;
+
+			if (timeout)
+				l2cap_sock_set_timer(sk,
+						msecs_to_jiffies(timeout*1000));
+		} else
+			l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
+
 		sk->sk_state_change(sk);
 
 		if (hcon->state == BT_CONNECTED) {
@@ -3354,6 +3365,7 @@
 		break;
 
 	case L2CAP_MODE_STREAMING:
+		l2cap_setup_txwin(pi);
 		rfc.txwin_size      = 0;
 		rfc.max_transmit    = 0;
 		rfc.retrans_timeout = 0;
@@ -5668,7 +5680,8 @@
 	struct hci_conn *hcon = conn->hcon;
 	struct l2cap_conn_param_update_req *req;
 	struct l2cap_conn_param_update_rsp rsp;
-	u16 min, max, latency, to_multiplier, cmd_len;
+	struct sock *sk;
+	u16 min, max, latency, timeout, cmd_len;
 	int err;
 
 	if (!(hcon->link_mode & HCI_LM_MASTER))
@@ -5678,28 +5691,32 @@
 	if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
 		return -EPROTO;
 
-	req = (struct l2cap_conn_param_update_req *) data;
-	min		= __le16_to_cpu(req->min);
-	max		= __le16_to_cpu(req->max);
-	latency		= __le16_to_cpu(req->latency);
-	to_multiplier	= __le16_to_cpu(req->to_multiplier);
-
-	BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
-						min, max, latency, to_multiplier);
-
 	memset(&rsp, 0, sizeof(rsp));
+	rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
 
-	err = l2cap_check_conn_param(min, max, latency, to_multiplier);
-	if (err)
-		rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
-	else
-		rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
+	sk = l2cap_find_sock_by_fixed_cid_and_dir(4, conn->src, conn->dst, 0);
+
+	if (sk && !bt_sk(sk)->le_params.prohibit_remote_chg) {
+		req = (struct l2cap_conn_param_update_req *) data;
+		min = __le16_to_cpu(req->min);
+		max = __le16_to_cpu(req->max);
+		latency = __le16_to_cpu(req->latency);
+		timeout = __le16_to_cpu(req->to_multiplier);
+
+		err = l2cap_check_conn_param(min, max, latency, timeout);
+		if (!err) {
+			rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
+			hci_le_conn_update(hcon, min, max, latency, timeout);
+			bt_sk(sk)->le_params.interval_min = min;
+			bt_sk(sk)->le_params.interval_max = max;
+			bt_sk(sk)->le_params.latency = latency;
+			bt_sk(sk)->le_params.supervision_timeout = timeout;
+		}
+	}
 
 	l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
 							sizeof(rsp), &rsp);
 
-	if (!err)
-		hci_le_conn_update(hcon, min, max, latency, to_multiplier);
 
 	return 0;
 }
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 8eb1e16..33d5d22 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -78,6 +78,23 @@
 	sk_stop_timer(sk, &sk->sk_timer);
 }
 
+int l2cap_sock_le_params_valid(struct bt_le_params *le_params)
+{
+	if (!le_params || le_params->latency > BT_LE_LATENCY_MAX ||
+			le_params->scan_window > BT_LE_SCAN_WINDOW_MAX ||
+			le_params->scan_interval < BT_LE_SCAN_INTERVAL_MIN ||
+			le_params->scan_window > le_params->scan_interval ||
+			le_params->interval_min < BT_LE_CONN_INTERVAL_MIN ||
+			le_params->interval_max > BT_LE_CONN_INTERVAL_MAX ||
+			le_params->interval_min > le_params->interval_max ||
+			le_params->supervision_timeout < BT_LE_SUP_TO_MIN ||
+			le_params->supervision_timeout > BT_LE_SUP_TO_MAX) {
+		return 0;
+	}
+
+	return 1;
+}
+
 static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
 {
 	struct sock *sk;
@@ -547,6 +564,17 @@
 			err = -EFAULT;
 		break;
 
+	case BT_LE_PARAMS:
+		if (l2cap_pi(sk)->scid != L2CAP_CID_LE_DATA) {
+			err = -EINVAL;
+			break;
+		}
+
+		if (copy_to_user(optval, (char *) &bt_sk(sk)->le_params,
+						sizeof(bt_sk(sk)->le_params)))
+			err = -EFAULT;
+		break;
+
 	default:
 		err = -ENOPROTOOPT;
 		break;
@@ -671,6 +699,7 @@
 	struct sock *sk = sock->sk;
 	struct bt_security sec;
 	struct bt_power pwr;
+	struct bt_le_params le_params;
 	struct l2cap_conn *conn;
 	int len, err = 0;
 	u32 opt;
@@ -786,6 +815,41 @@
 
 		break;
 
+	case BT_LE_PARAMS:
+		if (l2cap_pi(sk)->scid != L2CAP_CID_LE_DATA) {
+			err = -EINVAL;
+			break;
+		}
+
+		if (copy_from_user((char *) &le_params, optval,
+					sizeof(struct bt_le_params))) {
+			err = -EFAULT;
+			break;
+		}
+
+		conn = l2cap_pi(sk)->conn;
+		if (!conn || !conn->hcon ||
+				l2cap_pi(sk)->scid != L2CAP_CID_LE_DATA) {
+			memcpy(&bt_sk(sk)->le_params, &le_params,
+							sizeof(le_params));
+			break;
+		}
+
+		if (!conn->hcon->out ||
+				!l2cap_sock_le_params_valid(&le_params)) {
+			err = -EINVAL;
+			break;
+		}
+
+		memcpy(&bt_sk(sk)->le_params, &le_params, sizeof(le_params));
+
+		hci_le_conn_update(conn->hcon,
+				le_params.interval_min,
+				le_params.interval_max,
+				le_params.latency,
+				le_params.supervision_timeout);
+		break;
+
 	default:
 		err = -ENOPROTOOPT;
 		break;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index e15609c..80f4bd6 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1623,8 +1623,8 @@
 
 	entry = hci_find_adv_entry(hdev, &cp->bdaddr);
 	if (entry && entry->flags & 0x04) {
-		conn = hci_connect(hdev, LE_LINK, 0, &cp->bdaddr, sec_level,
-								auth_type);
+		conn = hci_le_connect(hdev, 0, &cp->bdaddr, sec_level,
+							auth_type, NULL);
 	} else {
 		/* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
 		if (io_cap == 0x04)
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c
index 6341818..e3db3f9 100644
--- a/net/ipv4/xfrm4_mode_beet.c
+++ b/net/ipv4/xfrm4_mode_beet.c
@@ -110,10 +110,7 @@
 
 	skb_push(skb, sizeof(*iph));
 	skb_reset_network_header(skb);
-
-	memmove(skb->data - skb->mac_len, skb_mac_header(skb),
-		skb->mac_len);
-	skb_set_mac_header(skb, -skb->mac_len);
+	skb_mac_header_rebuild(skb);
 
 	xfrm4_beet_make_header(skb);
 
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
index 534972e..ed4bf11 100644
--- a/net/ipv4/xfrm4_mode_tunnel.c
+++ b/net/ipv4/xfrm4_mode_tunnel.c
@@ -66,7 +66,6 @@
 
 static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
 {
-	const unsigned char *old_mac;
 	int err = -EINVAL;
 
 	if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP)
@@ -84,10 +83,9 @@
 	if (!(x->props.flags & XFRM_STATE_NOECN))
 		ipip_ecn_decapsulate(skb);
 
-	old_mac = skb_mac_header(skb);
-	skb_set_mac_header(skb, -skb->mac_len);
-	memmove(skb_mac_header(skb), old_mac, skb->mac_len);
 	skb_reset_network_header(skb);
+	skb_mac_header_rebuild(skb);
+
 	err = 0;
 
 out:
diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c
index 3437d7d..f37cba9 100644
--- a/net/ipv6/xfrm6_mode_beet.c
+++ b/net/ipv6/xfrm6_mode_beet.c
@@ -80,7 +80,6 @@
 static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb)
 {
 	struct ipv6hdr *ip6h;
-	const unsigned char *old_mac;
 	int size = sizeof(struct ipv6hdr);
 	int err;
 
@@ -90,10 +89,7 @@
 
 	__skb_push(skb, size);
 	skb_reset_network_header(skb);
-
-	old_mac = skb_mac_header(skb);
-	skb_set_mac_header(skb, -skb->mac_len);
-	memmove(skb_mac_header(skb), old_mac, skb->mac_len);
+	skb_mac_header_rebuild(skb);
 
 	xfrm6_beet_make_header(skb);
 
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c
index 4d6edff..23ecd68 100644
--- a/net/ipv6/xfrm6_mode_tunnel.c
+++ b/net/ipv6/xfrm6_mode_tunnel.c
@@ -63,7 +63,6 @@
 static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
 {
 	int err = -EINVAL;
-	const unsigned char *old_mac;
 
 	if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6)
 		goto out;
@@ -80,10 +79,9 @@
 	if (!(x->props.flags & XFRM_STATE_NOECN))
 		ipip6_ecn_decapsulate(skb);
 
-	old_mac = skb_mac_header(skb);
-	skb_set_mac_header(skb, -skb->mac_len);
-	memmove(skb_mac_header(skb), old_mac, skb->mac_len);
 	skb_reset_network_header(skb);
+	skb_mac_header_rebuild(skb);
+
 	err = 0;
 
 out:
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index d3e509e..94dd695 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -824,7 +824,7 @@
 
 #define ALL_INIT_DATA_SECTIONS \
 	".init.setup$", ".init.rodata$", \
-	".devinit.rodata$", ".cpuinit.rodata$", ".meminit.rodata$" \
+	".devinit.rodata$", ".cpuinit.rodata$", ".meminit.rodata$", \
 	".init.data$", ".devinit.data$", ".cpuinit.data$", ".meminit.data$"
 #define ALL_EXIT_DATA_SECTIONS \
 	".exit.data$", ".devexit.data$", ".cpuexit.data$", ".memexit.data$"
@@ -1469,6 +1469,13 @@
 	return 0;
 }
 
+#ifndef R_ARM_CALL
+#define R_ARM_CALL	28
+#endif
+#ifndef R_ARM_JUMP24
+#define R_ARM_JUMP24	29
+#endif
+
 static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
 {
 	unsigned int r_typ = ELF_R_TYPE(r->r_info);
@@ -1480,6 +1487,8 @@
 		              (elf->symtab_start + ELF_R_SYM(r->r_info));
 		break;
 	case R_ARM_PC24:
+	case R_ARM_CALL:
+	case R_ARM_JUMP24:
 		/* From ARM ABI: ((S + A) | T) - P */
 		r->r_addend = (int)(long)(elf->hdr +
 		              sechdr->sh_offset +
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 1fe28a2..9041bd7 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -31,6 +31,8 @@
 #include <linux/bitops.h>
 #include <linux/delay.h>
 #include <linux/pm_runtime.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
 #include "wcd9304.h"
 
 #define WCD9304_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
@@ -66,6 +68,21 @@
 
 #define SITAR_FAKE_INS_THRESHOLD_MS 2500
 #define SITAR_FAKE_REMOVAL_MIN_PERIOD_MS 50
+#define SITAR_MBHC_BUTTON_MIN 0x8000
+#define SITAR_GPIO_IRQ_DEBOUNCE_TIME_US 5000
+
+#define SITAR_ACQUIRE_LOCK(x) do { mutex_lock(&x); } while (0)
+#define SITAR_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
+
+#define MBHC_NUM_DCE_PLUG_DETECT 3
+#define SITAR_MBHC_FAKE_INSERT_LOW 10
+#define SITAR_MBHC_FAKE_INSERT_HIGH 80
+#define SITAR_MBHC_FAKE_INSERT_VOLT_DELTA_MV 500
+#define SITAR_HS_DETECT_PLUG_TIME_MS (5 * 1000)
+#define SITAR_HS_DETECT_PLUG_INERVAL_MS 100
+#define NUM_ATTEMPTS_TO_REPORT 5
+#define SITAR_MBHC_STATUS_REL_DETECTION 0x0C
+#define SITAR_MBHC_GPIO_REL_DEBOUNCE_TIME_MS 200
 
 static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
 static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
@@ -139,6 +156,21 @@
 	u8 nbounce_wait;
 };
 
+enum sitar_mbhc_plug_type {
+	PLUG_TYPE_INVALID = -1,
+	PLUG_TYPE_NONE,
+	PLUG_TYPE_HEADSET,
+	PLUG_TYPE_HEADPHONE,
+	PLUG_TYPE_HIGH_HPH,
+};
+
+enum sitar_mbhc_state {
+	MBHC_STATE_NONE = -1,
+	MBHC_STATE_POTENTIAL,
+	MBHC_STATE_POTENTIAL_RECOVERY,
+	MBHC_STATE_RELEASE,
+};
+
 struct sitar_priv {
 	struct snd_soc_codec *codec;
 	u32 mclk_freq;
@@ -167,15 +199,10 @@
 	void *calibration;
 	struct mbhc_internal_cal_data mbhc_data;
 
-	struct snd_soc_jack *headset_jack;
-	struct snd_soc_jack *button_jack;
-
 	struct wcd9xxx_pdata *pdata;
 	u32 anc_slot;
 
 	bool no_mic_headset_override;
-	/* Delayed work to report long button press */
-	struct delayed_work btn0_dwork;
 
 	struct mbhc_micbias_regs mbhc_bias_regs;
 	u8 cfilt_k_value;
@@ -207,6 +234,23 @@
 
 	/* num of slim ports required */
 	struct sitar_codec_dai_data dai[NUM_CODEC_DAIS];
+
+	/* Currently, only used for mbhc purpose, to protect
+	 * concurrent execution of mbhc threaded irq handlers and
+	 * kill race between DAPM and MBHC.But can serve as a
+	 * general lock to protect codec resource
+	 */
+	struct mutex codec_resource_lock;
+
+	struct sitar_mbhc_config mbhc_cfg;
+	bool in_gpio_handler;
+	u8 current_plug;
+	bool lpi_enabled;
+	enum sitar_mbhc_state mbhc_state;
+	struct work_struct hs_correct_plug_work;
+	bool hs_detect_work_stop;
+	struct delayed_work mbhc_btn_dwork;
+	unsigned long mbhc_last_resume; /* in jiffies */
 };
 
 #ifdef CONFIG_DEBUG_FS
@@ -234,7 +278,7 @@
 		return -EINVAL;
 	}
 
-	pr_err("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
+	pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
 
 	return 0;
 }
@@ -277,7 +321,7 @@
 		snd_soc_read(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx)) &
 		(1 << band_idx);
 
-	pr_err("%s: IIR #%d band #%d enable %d\n", __func__,
+	pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
 		iir_idx, band_idx,
 		(uint32_t)ucontrol->value.integer.value[0]);
 	return 0;
@@ -298,7 +342,7 @@
 	snd_soc_update_bits(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx),
 		(1 << band_idx), (value << band_idx));
 
-	pr_err("%s: IIR #%d band #%d enable %d\n", __func__,
+	pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
 		iir_idx, band_idx, value);
 	return 0;
 }
@@ -344,7 +388,7 @@
 	ucontrol->value.integer.value[4] =
 		get_iir_band_coeff(codec, iir_idx, band_idx, 4);
 
-	pr_err("%s: IIR #%d band #%d b0 = 0x%x\n"
+	pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
 		"%s: IIR #%d band #%d b1 = 0x%x\n"
 		"%s: IIR #%d band #%d b2 = 0x%x\n"
 		"%s: IIR #%d band #%d a1 = 0x%x\n"
@@ -412,7 +456,7 @@
 	set_iir_band_coeff(codec, iir_idx, band_idx, 4,
 				ucontrol->value.integer.value[4]);
 
-	pr_err("%s: IIR #%d band #%d b0 = 0x%x\n"
+	pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
 		"%s: IIR #%d band #%d b1 = 0x%x\n"
 		"%s: IIR #%d band #%d b2 = 0x%x\n"
 		"%s: IIR #%d band #%d a1 = 0x%x\n"
@@ -734,16 +778,12 @@
 	SOC_DAPM_SINGLE("Switch", SITAR_A_RX_EAR_EN, 5, 1, 0),
 };
 
-static const struct snd_kcontrol_new hphl_switch[] = {
-	SOC_DAPM_SINGLE("Switch", SITAR_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
-};
-
 static void sitar_codec_enable_adc_block(struct snd_soc_codec *codec,
 	int enable)
 {
 	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
 
-	pr_err("%s %d\n", __func__, enable);
+	pr_debug("%s %d\n", __func__, enable);
 
 	if (enable) {
 		sitar->adc_count++;
@@ -765,7 +805,7 @@
 	struct snd_soc_codec *codec = w->codec;
 	u16 adc_reg;
 
-	pr_err("%s %d\n", __func__, event);
+	pr_debug("%s %d\n", __func__, event);
 
 	if (w->reg == SITAR_A_TX_1_2_EN)
 		adc_reg = SITAR_A_TX_1_2_TEST_CTL;
@@ -818,7 +858,7 @@
 	struct snd_soc_codec *codec = w->codec;
 	u16 lineout_gain_reg;
 
-	pr_err("%s %d %s\n", __func__, event, w->name);
+	pr_debug("%s %d %s\n", __func__, event, w->name);
 
 	switch (w->shift) {
 	case 0:
@@ -838,7 +878,7 @@
 		snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x10);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
-		pr_err("%s: sleeping 16 ms after %s PA turn on\n",
+		pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
 				__func__, w->name);
 		usleep_range(16000, 16000);
 		break;
@@ -886,7 +926,7 @@
 	tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
 	tx_dmic_ctl_reg = SITAR_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
 
-	pr_err("%s %d\n", __func__, event);
+	pr_debug("%s %d\n", __func__, event);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -910,27 +950,41 @@
 	return 0;
 }
 
-
-static void sitar_codec_disable_button_presses(struct snd_soc_codec *codec)
-{
-	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL, 0x80);
-	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL, 0x00);
-}
-
 static void sitar_codec_start_hs_polling(struct snd_soc_codec *codec)
 {
 	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	int mbhc_state = sitar->mbhc_state;
+
+	pr_debug("%s: enter\n", __func__);
+	if (!sitar->mbhc_polling_active) {
+		pr_debug("Polling is not active, do not start polling\n");
+		return;
+	}
+	snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
+
+
+	if (!sitar->no_mic_headset_override) {
+		if (mbhc_state == MBHC_STATE_POTENTIAL) {
+			pr_debug("%s recovering MBHC state macine\n", __func__);
+			sitar->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
+			/* set to max button press threshold */
+			snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B2_CTL,
+				      0x7F);
+			snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL,
+				      0xFF);
+			snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL,
+				       0x7F);
+			snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL,
+				      0xFF);
+			/* set to max */
+			snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B6_CTL,
+				      0x7F);
+			snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B5_CTL,
+				      0xFF);
+		}
+	}
 
 	snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
-	wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
-	if (!sitar->no_mic_headset_override) {
-		wcd9xxx_enable_irq(codec->control_data,
-				SITAR_IRQ_MBHC_POTENTIAL);
-		wcd9xxx_enable_irq(codec->control_data,
-				SITAR_IRQ_MBHC_RELEASE);
-	} else {
-		sitar_codec_disable_button_presses(codec);
-	}
 	snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x1);
 	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
 	snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x1);
@@ -940,14 +994,15 @@
 {
 	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
 
-	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
-	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
-	if (!sitar->no_mic_headset_override) {
-		wcd9xxx_disable_irq(codec->control_data,
-			SITAR_IRQ_MBHC_POTENTIAL);
-		wcd9xxx_disable_irq(codec->control_data,
-			SITAR_IRQ_MBHC_RELEASE);
+	pr_debug("%s: enter\n", __func__);
+	if (!sitar->mbhc_polling_active) {
+		pr_debug("polling not active, nothing to pause\n");
+		return;
 	}
+
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+	pr_debug("%s: leave\n", __func__);
+
 }
 
 static void sitar_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
@@ -966,6 +1021,7 @@
 			sitar->mbhc_bias_regs.cfilt_ctl) & 0x40;
 
 	if (cur_mode_val != reg_mode_val) {
+		SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
 		if (sitar->mbhc_polling_active) {
 			sitar_codec_pause_hs_polling(codec);
 			mbhc_was_polling = true;
@@ -974,7 +1030,8 @@
 			sitar->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
 		if (mbhc_was_polling)
 			sitar_codec_start_hs_polling(codec);
-		pr_err("%s: CFILT mode change (%x to %x)\n", __func__,
+		SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
+		pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
 			cur_mode_val, reg_mode_val);
 	} else {
 		pr_err("%s: CFILT Value is already %x\n",
@@ -1077,10 +1134,10 @@
 	u8 hph_reg_val = 0;
 	if (left)
 		hph_reg_val = snd_soc_read(codec,
-					  SITAR_A_RX_HPH_L_DAC_CTL);
+					   SITAR_A_RX_HPH_L_DAC_CTL);
 	else
 		hph_reg_val = snd_soc_read(codec,
-					  SITAR_A_RX_HPH_R_DAC_CTL);
+					   SITAR_A_RX_HPH_R_DAC_CTL);
 
 	return (hph_reg_val & 0xC0) ? true : false;
 }
@@ -1094,7 +1151,8 @@
 
 	switch (vddio_switch) {
 	case 1:
-		if (sitar->mbhc_polling_active) {
+		if (sitar->mbhc_micbias_switched == 0 &&
+			sitar->mbhc_polling_active) {
 
 			sitar_codec_pause_hs_polling(codec);
 			/* Enable Mic Bias switch to VDDIO */
@@ -1113,7 +1171,7 @@
 			sitar_codec_start_hs_polling(codec);
 
 			sitar->mbhc_micbias_switched = true;
-			pr_err("%s: Enabled MBHC Mic bias to VDDIO Switch\n",
+			pr_debug("%s: Enabled MBHC Mic bias to VDDIO Switch\n",
 				__func__);
 		}
 		break;
@@ -1138,7 +1196,7 @@
 				sitar_codec_start_hs_polling(codec);
 
 			sitar->mbhc_micbias_switched = false;
-			pr_err("%s: Disabled MBHC Mic bias to VDDIO Switch\n",
+			pr_debug("%s: Disabled MBHC Mic bias to VDDIO Switch\n",
 				__func__);
 		}
 		break;
@@ -1156,7 +1214,7 @@
 	char *internal1_text = "Internal1";
 	char *internal2_text = "Internal2";
 
-	pr_err("%s %d\n", __func__, event);
+	pr_debug("%s %d\n", __func__, event);
 	switch (w->reg) {
 	case SITAR_A_MICB_1_CTL:
 		micb_int_reg = SITAR_A_MICB_1_INT_RBIAS;
@@ -1176,9 +1234,11 @@
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		/* Decide whether to switch the micbias for MBHC */
-		if ((w->reg == sitar->mbhc_bias_regs.ctl_reg)
-				&& sitar->mbhc_micbias_switched)
+		if (w->reg == sitar->mbhc_bias_regs.ctl_reg) {
+			SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
 			sitar_codec_switch_micbias(codec, 0);
+			SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
+		}
 
 		snd_soc_update_bits(codec, w->reg, 0x1E, 0x00);
 		sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
@@ -1191,8 +1251,10 @@
 	case SND_SOC_DAPM_POST_PMU:
 		if (sitar->mbhc_polling_active &&
 		    sitar->micbias == micb_line) {
+			SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
 			sitar_codec_pause_hs_polling(codec);
 			sitar_codec_start_hs_polling(codec);
+			SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
 		}
 		break;
 	case SND_SOC_DAPM_POST_PMD:
@@ -1218,7 +1280,7 @@
 	struct snd_soc_codec *codec = w->codec;
 	u16 dec_reset_reg;
 
-	pr_err("%s %d\n", __func__, event);
+	pr_debug("%s %d\n", __func__, event);
 
 	if (w->reg == SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL)
 		dec_reset_reg = SITAR_A_CDC_CLK_TX_RESET_B1_CTL;
@@ -1242,7 +1304,7 @@
 {
 	struct snd_soc_codec *codec = w->codec;
 
-	pr_err("%s %d %s\n", __func__, event, w->name);
+	pr_debug("%s %d %s\n", __func__, event, w->name);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -1290,7 +1352,7 @@
 {
 	struct snd_soc_codec *codec = w->codec;
 
-	pr_err("%s %d\n", __func__, event);
+	pr_debug("%s %d\n", __func__, event);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -1302,12 +1364,12 @@
 	}
 	return 0;
 }
-static int sitar_hphr_dac_event(struct snd_soc_dapm_widget *w,
+static int sitar_hph_dac_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
 
-	pr_err("%s %s %d\n", __func__, w->name, event);
+	pr_debug("%s %s %d\n", __func__, w->name, event);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -1333,18 +1395,22 @@
 {
 	struct snd_soc_codec *codec;
 
-	if (sitar) {
-		pr_info("%s: clear ocp status %x\n", __func__, jack_status);
-		codec = sitar->codec;
+	if (!sitar) {
+		pr_err("%s: Bad sitar private data\n", __func__);
+		return;
+	}
+
+	pr_info("%s: clear ocp status %x\n", __func__, jack_status);
+	codec = sitar->codec;
+	if (sitar->hph_status & jack_status) {
 		sitar->hph_status &= ~jack_status;
-		if (sitar->headset_jack)
-			sitar_snd_soc_jack_report(sitar, sitar->headset_jack,
-						 sitar->hph_status,
-						 SITAR_JACK_MASK);
-		snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
-		0x00);
-		snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
-		0x10);
+		if (sitar->mbhc_cfg.headset_jack)
+			sitar_snd_soc_jack_report(sitar,
+						sitar->mbhc_cfg.headset_jack,
+						sitar->hph_status,
+						SITAR_JACK_MASK);
+		snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10, 0x00);
+		snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10, 0x10);
 		/* reset retry counter as PA is turned off signifying
 		* start of new OCP detection session
 		*/
@@ -1353,8 +1419,6 @@
 		else
 			sitar->hphrocp_cnt = 0;
 		wcd9xxx_enable_irq(codec->control_data, irq);
-	} else {
-		pr_err("%s: Bad sitar private data\n", __func__);
 	}
 }
 
@@ -1378,16 +1442,18 @@
 	struct snd_soc_codec *codec = w->codec;
 	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
 	u8 mbhc_micb_ctl_val;
-	pr_err("%s: event = %d\n", __func__, event);
+	pr_debug("%s: event = %d\n", __func__, event);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		mbhc_micb_ctl_val = snd_soc_read(codec,
 				sitar->mbhc_bias_regs.ctl_reg);
 
-		if (!(mbhc_micb_ctl_val & 0x80)
-				&& !sitar->mbhc_micbias_switched)
+		if (!(mbhc_micb_ctl_val & 0x80)) {
+			SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
 			sitar_codec_switch_micbias(codec, 1);
+			SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
+		}
 
 		break;
 
@@ -1413,10 +1479,11 @@
 				schedule_work(&sitar->hphrocp_work);
 		}
 
-		if (sitar->mbhc_micbias_switched)
-			sitar_codec_switch_micbias(codec, 0);
+		SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
+		sitar_codec_switch_micbias(codec, 0);
+		SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
 
-		pr_err("%s: sleep 10 ms after %s PA disable.\n", __func__,
+		pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
 				w->name);
 		usleep_range(10000, 10000);
 
@@ -1431,7 +1498,7 @@
 	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
 	unsigned int cfilt;
 
-	switch (sitar->micbias) {
+	switch (sitar->mbhc_cfg.micbias) {
 	case SITAR_MICBIAS1:
 		cfilt = sitar->pdata->micbias.bias1_cfilt_sel;
 		micbias_regs->mbhc_reg = SITAR_A_MICB_1_MBHC;
@@ -1471,7 +1538,7 @@
 {
 	struct snd_soc_codec *codec = w->codec;
 
-	pr_err("%s %d\n", __func__, event);
+	pr_debug("%s %d\n", __func__, event);
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
@@ -1527,15 +1594,16 @@
 	SND_SOC_DAPM_PGA_E("HPHL", SITAR_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
 		sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
 			SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MIXER("HPHL DAC", SITAR_A_RX_HPH_L_DAC_CTL, 7, 0,
-		hphl_switch, ARRAY_SIZE(hphl_switch)),
 
 	SND_SOC_DAPM_PGA_E("HPHR", SITAR_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
 		sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
 			SND_SOC_DAPM_POST_PMD),
 
+	SND_SOC_DAPM_DAC_E("HPHL DAC", NULL, SITAR_A_RX_HPH_L_DAC_CTL, 7, 0,
+		sitar_hph_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, SITAR_A_RX_HPH_R_DAC_CTL, 7, 0,
-		sitar_hphr_dac_event,
+		sitar_hph_dac_event,
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
 	/* Speaker */
@@ -1708,7 +1776,7 @@
 	{"HEADPHONE", NULL, "HPHR"},
 
 	{"HPHL", NULL, "HPHL DAC"},
-	{"HPHL DAC", "Switch", "DAC4 MUX"},
+	{"HPHL DAC", "NULL", "DAC4 MUX"},
 	{"HPHR", NULL, "HPHR DAC"},
 	{"HPHR DAC", NULL, "RX3 MIX1"},
 
@@ -1908,7 +1976,7 @@
 	* interrupt handlers
 	*/
 
-	pr_err("%s, choice is %d, current is %d\n", __func__, choice,
+	pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
 		sitar->bandgap_type);
 
 	if (sitar->bandgap_type == choice)
@@ -1978,7 +2046,7 @@
 {
 	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
 
-	pr_err("%s\n", __func__);
+	pr_debug("%s\n", __func__);
 
 	if (config_mode) {
 		sitar_codec_enable_config_mode(codec, 1);
@@ -2005,7 +2073,7 @@
 static void sitar_codec_disable_clock_block(struct snd_soc_codec *codec)
 {
 	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
-	pr_err("%s\n", __func__);
+	pr_debug("%s\n", __func__);
 	snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x00);
 	ndelay(160);
 	snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x02);
@@ -2015,9 +2083,9 @@
 
 static int sitar_codec_mclk_index(const struct sitar_priv *sitar)
 {
-	if (sitar->mclk_freq == SITAR_MCLK_RATE_12288KHZ)
+	if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_12288KHZ)
 		return 0;
-	else if (sitar->mclk_freq == SITAR_MCLK_RATE_9600KHZ)
+	else if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_9600KHZ)
 		return 1;
 	else {
 		BUG_ON(1);
@@ -2031,7 +2099,7 @@
 	struct sitar_mbhc_btn_detect_cfg *btn_det;
 	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
 
-	btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->calibration);
+	btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
 
 	snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL,
 		      sitar->mbhc_data.v_ins_hu & 0xFF);
@@ -2077,7 +2145,7 @@
 	if ((wcd9xxx != NULL) && (wcd9xxx->dev != NULL) &&
 			(wcd9xxx->dev->parent != NULL))
 		pm_runtime_get_sync(wcd9xxx->dev->parent);
-	pr_err("%s(): substream = %s  stream = %d\n" , __func__,
+	pr_debug("%s(): substream = %s  stream = %d\n" , __func__,
 		substream->name, substream->stream);
 
 	return 0;
@@ -2092,16 +2160,18 @@
 		pm_runtime_mark_last_busy(wcd9xxx->dev->parent);
 		pm_runtime_put(wcd9xxx->dev->parent);
 	}
-	pr_err("%s(): substream = %s  stream = %d\n" , __func__,
+	pr_debug("%s(): substream = %s  stream = %d\n" , __func__,
 		substream->name, substream->stream);
 }
 
-int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable)
+int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
 {
 	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
 
-	pr_err("%s() mclk_enable = %u\n", __func__, mclk_enable);
+	pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
 
+	if (dapm)
+		SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
 	if (mclk_enable) {
 		sitar->mclk_enabled = true;
 
@@ -2120,6 +2190,8 @@
 	} else {
 
 		if (!sitar->mclk_enabled) {
+			if (dapm)
+				SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
 			pr_err("Error, MCLK already diabled\n");
 			return -EINVAL;
 		}
@@ -2143,13 +2215,15 @@
 				SITAR_BANDGAP_OFF);
 		}
 	}
+	if (dapm)
+		SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
 	return 0;
 }
 
 static int sitar_set_dai_sysclk(struct snd_soc_dai *dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	pr_err("%s\n", __func__);
+	pr_debug("%s\n", __func__);
 	return 0;
 }
 
@@ -2158,7 +2232,7 @@
 	u8 val = 0;
 	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
 
-	pr_err("%s\n", __func__);
+	pr_debug("%s\n", __func__);
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
 		/* CPU is master */
@@ -2265,7 +2339,7 @@
 	u16 tx_fs_reg, rx_fs_reg;
 	u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
 
-	pr_err("%s: DAI-ID %x\n", __func__, dai->id);
+	pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
 
 	switch (params_rate(params)) {
 	case 8000:
@@ -2558,13 +2632,25 @@
 	return bias_value;
 }
 
-static short sitar_codec_sta_dce(struct snd_soc_codec *codec, int dce)
+static void sitar_turn_onoff_rel_detection(struct snd_soc_codec *codec,
+				bool on)
 {
-	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
+}
+
+static short __sitar_codec_sta_dce(struct snd_soc_codec *codec, int dce,
+				   bool override_bypass, bool noreldetection)
+{
 	short bias_value;
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+	if (noreldetection)
+		sitar_turn_onoff_rel_detection(codec, false);
 
 	/* Turn on the override */
-	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
+	if (!override_bypass)
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
 	if (dce) {
 		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
 		snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
@@ -2589,24 +2675,73 @@
 		snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x0);
 	}
 	/* Turn off the override after measuring mic voltage */
-	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
+	if (!override_bypass)
+		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
+
+	if (noreldetection)
+		sitar_turn_onoff_rel_detection(codec, true);
+	wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
 
 	return bias_value;
 }
 
+static short sitar_codec_sta_dce(struct snd_soc_codec *codec, int dce,
+				bool norel)
+{
+	return __sitar_codec_sta_dce(codec, dce, false, norel);
+}
+
+static void sitar_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	const struct sitar_mbhc_general_cfg *generic =
+	    SITAR_MBHC_CAL_GENERAL_PTR(sitar->mbhc_cfg.calibration);
+
+	if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
+		sitar_codec_enable_config_mode(codec, 1);
+
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
+
+	snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
+
+	usleep_range(generic->t_shutdown_plug_rem,
+		     generic->t_shutdown_plug_rem);
+
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
+	if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
+		sitar_codec_enable_config_mode(codec, 0);
+
+	snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x00);
+}
+
+static void sitar_codec_cleanup_hs_polling(struct snd_soc_codec *codec)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	sitar_codec_shutdown_hs_removal_detect(codec);
+
+	if (!sitar->mclk_enabled) {
+		sitar_codec_disable_clock_block(codec);
+		sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
+	}
+
+	sitar->mbhc_polling_active = false;
+	sitar->mbhc_state = MBHC_STATE_NONE;
+}
+
+/* called only from interrupt which is under codec_resource_lock acquisition */
 static short sitar_codec_setup_hs_polling(struct snd_soc_codec *codec)
 {
 	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
 	short bias_value;
 	u8 cfilt_mode;
 
-	if (!sitar->calibration) {
+	if (!sitar->mbhc_cfg.calibration) {
 		pr_err("Error, no sitar calibration\n");
 		return -ENODEV;
 	}
 
-	sitar->mbhc_polling_active = true;
-
 	if (!sitar->mclk_enabled) {
 		sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_MBHC_MODE);
 		sitar_enable_rx_bias(codec, 1);
@@ -2615,13 +2750,11 @@
 
 	snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x01);
 
-	snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS, 0xE0, 0xE0);
-
 	/* Make sure CFILT is in fast mode, save current mode */
-	cfilt_mode = snd_soc_read(codec,
-		sitar->mbhc_bias_regs.cfilt_ctl);
-	snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl,
-		0x70, 0x00);
+	cfilt_mode = snd_soc_read(codec, sitar->mbhc_bias_regs.cfilt_ctl);
+	snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
+
+	snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
 
 	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
 	snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
@@ -2639,7 +2772,8 @@
 
 	sitar_codec_calibrate_hs_polling(codec);
 
-	bias_value = sitar_codec_sta_dce(codec, 0);
+	/* don't flip override */
+	bias_value = __sitar_codec_sta_dce(codec, 1, true, true);
 	snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40,
 			    cfilt_mode);
 	snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
@@ -2647,111 +2781,21 @@
 	return bias_value;
 }
 
-static int sitar_codec_enable_hs_detect(struct snd_soc_codec *codec,
-		int insertion)
+static int sitar_cancel_btn_work(struct sitar_priv *sitar)
 {
-	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
-	int central_bias_enabled = 0;
-	const struct sitar_mbhc_general_cfg *generic =
-	    SITAR_MBHC_CAL_GENERAL_PTR(sitar->calibration);
-	const struct sitar_mbhc_plug_detect_cfg *plug_det =
-	    SITAR_MBHC_CAL_PLUG_DET_PTR(sitar->calibration);
-	u8 wg_time;
+	int r = 0;
+	struct wcd9xxx *core = dev_get_drvdata(sitar->codec->dev->parent);
 
-	if (!sitar->calibration) {
-		pr_err("Error, no sitar calibration\n");
-		return -EINVAL;
+	if (cancel_delayed_work_sync(&sitar->mbhc_btn_dwork)) {
+		/* if scheduled mbhc_btn_dwork is canceled from here,
+		 * we have to unlock from here instead btn_work */
+		wcd9xxx_unlock_sleep(core);
+		r = 1;
 	}
-
-	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x1, 0);
-
-	if (insertion) {
-		/* Make sure mic bias and Mic line schmitt trigger
-		* are turned OFF
-		*/
-		snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg,
-			0x81, 0x01);
-		snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg,
-			0x90, 0x00);
-		wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
-		wg_time += 1;
-
-		/* Enable HPH Schmitt Trigger */
-		snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x11, 0x11);
-		snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x0C,
-			plug_det->hph_current << 2);
-
-		/* Turn off HPH PAs and DAC's during insertion detection to
-		* avoid false insertion interrupts
-		*/
-		if (sitar->mbhc_micbias_switched)
-			sitar_codec_switch_micbias(codec, 0);
-		snd_soc_update_bits(codec, SITAR_A_RX_HPH_CNP_EN, 0x30, 0x00);
-		snd_soc_update_bits(codec, SITAR_A_RX_HPH_L_DAC_CTL,
-			0xC0, 0x00);
-		snd_soc_update_bits(codec, SITAR_A_RX_HPH_R_DAC_CTL,
-			0xC0, 0x00);
-		usleep_range(wg_time * 1000, wg_time * 1000);
-
-		/* setup for insetion detection */
-		snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x02, 0x02);
-		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x2, 0);
-	} else {
-		/* Make sure the HPH schmitt trigger is OFF */
-		snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x12, 0x00);
-
-		/* enable the mic line schmitt trigger */
-		snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg, 0x60,
-			plug_det->mic_current << 5);
-		snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg,
-			0x80, 0x80);
-		usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
-		snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg,
-			0x10, 0x10);
-
-		/* Setup for low power removal detection */
-		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
-	}
-
-	if (snd_soc_read(codec, SITAR_A_CDC_MBHC_B1_CTL) & 0x4) {
-		if (!(sitar->clock_active)) {
-			sitar_codec_enable_config_mode(codec, 1);
-			snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL,
-				0x06, 0);
-			usleep_range(generic->t_shutdown_plug_rem,
-				generic->t_shutdown_plug_rem);
-			sitar_codec_enable_config_mode(codec, 0);
-		} else
-			snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL,
-				0x06, 0);
-	}
-
-	snd_soc_update_bits(codec, sitar->mbhc_bias_regs.int_rbias, 0x80, 0);
-
-	/* If central bandgap disabled */
-	if (!(snd_soc_read(codec, SITAR_A_PIN_CTL_OE1) & 1)) {
-		snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE1, 0x3, 0x3);
-		usleep_range(generic->t_bg_fast_settle,
-			generic->t_bg_fast_settle);
-		central_bias_enabled = 1;
-	}
-
-	/* If LDO_H disabled */
-	if (snd_soc_read(codec, SITAR_A_PIN_CTL_OE0) & 0x80) {
-		snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE0, 0x10, 0);
-		snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE0, 0x80, 0x80);
-		usleep_range(generic->t_ldoh, generic->t_ldoh);
-		snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE0, 0x80, 0);
-
-		if (central_bias_enabled)
-			snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE1, 0x1, 0);
-	}
-
-	wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
-	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
-	return 0;
+	return r;
 }
 
+
 static u16 sitar_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
 				 s16 vin_mv)
 {
@@ -2783,58 +2827,63 @@
 				 u16 bias_value)
 {
 	struct sitar_priv *sitar;
+	s16 value, z, mb;
 	s32 mv;
 
 	sitar = snd_soc_codec_get_drvdata(codec);
+	value = bias_value;
 
 	if (dce) {
-		mv = ((s32)bias_value - (s32)sitar->mbhc_data.dce_z) *
-		     (s32)sitar->mbhc_data.micb_mv /
-		     (s32)(sitar->mbhc_data.dce_mb - sitar->mbhc_data.dce_z);
+		z = (sitar->mbhc_data.dce_z);
+		mb = (sitar->mbhc_data.dce_mb);
+		mv = (value - z) * (s32)sitar->mbhc_data.micb_mv / (mb - z);
 	} else {
-		mv = ((s32)bias_value - (s32)sitar->mbhc_data.sta_z) *
-		     (s32)sitar->mbhc_data.micb_mv /
-		     (s32)(sitar->mbhc_data.sta_mb - sitar->mbhc_data.sta_z);
+		z = (sitar->mbhc_data.sta_z);
+		mb = (sitar->mbhc_data.sta_mb);
+		mv = (value - z) * (s32)sitar->mbhc_data.micb_mv / (mb - z);
 	}
 
 	return mv;
 }
 
-static void btn0_lpress_fn(struct work_struct *work)
+static void btn_lpress_fn(struct work_struct *work)
 {
 	struct delayed_work *delayed_work;
 	struct sitar_priv *sitar;
 	short bias_value;
 	int dce_mv, sta_mv;
-	struct sitar *core;
+	struct wcd9xxx *core;
 
 	pr_debug("%s:\n", __func__);
 
 	delayed_work = to_delayed_work(work);
-	sitar = container_of(delayed_work, struct sitar_priv, btn0_dwork);
+	sitar = container_of(delayed_work, struct sitar_priv, mbhc_btn_dwork);
 	core = dev_get_drvdata(sitar->codec->dev->parent);
 
 	if (sitar) {
-		if (sitar->button_jack) {
+		if (sitar->mbhc_cfg.button_jack) {
 			bias_value = sitar_codec_read_sta_result(sitar->codec);
 			sta_mv = sitar_codec_sta_dce_v(sitar->codec, 0,
-						bias_value);
+							bias_value);
 			bias_value = sitar_codec_read_dce_result(sitar->codec);
 			dce_mv = sitar_codec_sta_dce_v(sitar->codec, 1,
-						bias_value);
+							bias_value);
 			pr_debug("%s: Reporting long button press event"
-				 " STA: %d, DCE: %d\n", __func__,
-				 sta_mv, dce_mv);
-			sitar_snd_soc_jack_report(sitar, sitar->button_jack,
-						  SND_JACK_BTN_0,
-						  SND_JACK_BTN_0);
+			" STA: %d, DCE: %d\n", __func__, sta_mv, dce_mv);
+			sitar_snd_soc_jack_report(sitar,
+						sitar->mbhc_cfg.button_jack,
+						sitar->buttons_pressed,
+						sitar->buttons_pressed);
 		}
 	} else {
 		pr_err("%s: Bad sitar private data\n", __func__);
 	}
 
+	pr_debug("%s: leave\n", __func__);
+	wcd9xxx_unlock_sleep(core);
 }
 
+
 void sitar_mbhc_cal(struct snd_soc_codec *codec)
 {
 	struct sitar_priv *sitar;
@@ -2844,24 +2893,29 @@
 	u32 mclk_rate;
 	u32 dce_wait, sta_wait;
 	u8 *n_cic;
+	void *calibration;
 
 	sitar = snd_soc_codec_get_drvdata(codec);
+	calibration = sitar->mbhc_cfg.calibration;
+
+	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+	sitar_turn_onoff_rel_detection(codec, false);
 
 	/* First compute the DCE / STA wait times
 	 * depending on tunable parameters.
 	 * The value is computed in microseconds
 	 */
-	btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->calibration);
+	btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(calibration);
 	n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
 	ncic = n_cic[sitar_codec_mclk_index(sitar)];
-	nmeas = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->calibration)->n_meas;
-	navg = SITAR_MBHC_CAL_GENERAL_PTR(sitar->calibration)->mbhc_navg;
-	mclk_rate = sitar->mclk_freq;
-	dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
+	nmeas = SITAR_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
+	navg = SITAR_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
+	mclk_rate = sitar->mbhc_cfg.mclk_rate;
+	dce_wait = (1000 * 512 * 60 * (nmeas + 1)) / (mclk_rate / 1000);
 	sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
 
-	sitar->mbhc_data.t_dce = dce_wait;
-	sitar->mbhc_data.t_sta = sta_wait;
+	sitar->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
+	sitar->mbhc_data.t_sta = DEFAULT_STA_WAIT;
 
 	/* LDOH and CFILT are already configured during pdata handling.
 	 * Only need to make sure CFILT and bandgap are in Fast mode.
@@ -2876,9 +2930,10 @@
 	 * to perform ADC calibration
 	 */
 	snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x60,
-			    sitar->micbias << 5);
+			    sitar->mbhc_cfg.micbias << 5);
 	snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
 	snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x60, 0x60);
+	snd_soc_write(codec, SITAR_A_TX_4_MBHC_TEST_CTL, 0x78);
 	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
 
 	/* DCE measurement for 0 volts */
@@ -2925,6 +2980,9 @@
 
 	snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
 	usleep_range(100, 100);
+
+	wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+	sitar_turn_onoff_rel_detection(codec, true);
 }
 
 void *sitar_mbhc_cal_btn_det_mp(const struct sitar_mbhc_btn_detect_cfg* btn_det,
@@ -2962,21 +3020,22 @@
 	int i;
 
 	sitar = snd_soc_codec_get_drvdata(codec);
-	btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->calibration);
-	plug_type = SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->calibration);
+	btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
+	plug_type = SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
 
 	n_ready = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_READY);
-	if (sitar->mclk_freq == SITAR_MCLK_RATE_12288KHZ) {
+	if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_12288KHZ) {
 		sitar->mbhc_data.npoll = 9;
 		sitar->mbhc_data.nbounce_wait = 30;
-	} else if (sitar->mclk_freq == SITAR_MCLK_RATE_9600KHZ) {
+	} else if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_9600KHZ) {
 		sitar->mbhc_data.npoll = 7;
 		sitar->mbhc_data.nbounce_wait = 23;
 	}
 
-	sitar->mbhc_data.t_sta_dce = ((1000 * 256) / (sitar->mclk_freq / 1000) *
-				      n_ready[sitar_codec_mclk_index(sitar)]) +
-				     10;
+	sitar->mbhc_data.t_sta_dce = ((1000 * 256) /
+				(sitar->mbhc_cfg.mclk_rate / 1000) *
+				n_ready[sitar_codec_mclk_index(sitar)]) +
+				10;
 	sitar->mbhc_data.v_ins_hu =
 	    sitar_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
 	sitar->mbhc_data.v_ins_h =
@@ -2998,7 +3057,7 @@
 	    sitar_codec_v_sta_dce(codec, DCE, btn_delta_mv);
 
 	sitar->mbhc_data.v_brh = sitar->mbhc_data.v_b1_h;
-	sitar->mbhc_data.v_brl = 0xFA55;
+	sitar->mbhc_data.v_brl = SITAR_MBHC_BUTTON_MIN;
 
 	sitar->mbhc_data.v_no_mic =
 	    sitar_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
@@ -3012,9 +3071,10 @@
 	int n;
 	u8 *n_cic, *gain;
 
+	pr_err("%s(): ENTER\n", __func__);
 	sitar = snd_soc_codec_get_drvdata(codec);
-	generic = SITAR_MBHC_CAL_GENERAL_PTR(sitar->calibration);
-	btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->calibration);
+	generic = SITAR_MBHC_CAL_GENERAL_PTR(sitar->mbhc_cfg.calibration);
+	btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
 
 	for (n = 0; n < 8; n++) {
 		if (n != 7) {
@@ -3049,7 +3109,13 @@
 	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x78,
 			    btn_det->mbhc_nsc << 3);
 
+	snd_soc_update_bits(codec, SITAR_A_MICB_1_MBHC, 0x03,
+						sitar->mbhc_cfg.micbias);
+
 	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
+
+	snd_soc_update_bits(codec, SITAR_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
+
 }
 
 static bool sitar_mbhc_fw_validate(const struct firmware *fw)
@@ -3083,13 +3149,563 @@
 
 	return true;
 }
+
+
+static void sitar_turn_onoff_override(struct snd_soc_codec *codec, bool on)
+{
+	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
+}
+
+/* called under codec_resource_lock acquisition */
+void sitar_set_and_turnoff_hph_padac(struct snd_soc_codec *codec)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	u8 wg_time;
+
+	wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
+	wg_time += 1;
+
+	/* If headphone PA is on, check if userspace receives
+	 * removal event to sync-up PA's state */
+	if (sitar_is_hph_pa_on(codec)) {
+		pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
+		set_bit(SITAR_HPHL_PA_OFF_ACK, &sitar->hph_pa_dac_state);
+		set_bit(SITAR_HPHR_PA_OFF_ACK, &sitar->hph_pa_dac_state);
+	} else {
+		pr_debug("%s PA is off\n", __func__);
+	}
+
+	if (sitar_is_hph_dac_on(codec, 1))
+		set_bit(SITAR_HPHL_DAC_OFF_ACK, &sitar->hph_pa_dac_state);
+	if (sitar_is_hph_dac_on(codec, 0))
+		set_bit(SITAR_HPHR_DAC_OFF_ACK, &sitar->hph_pa_dac_state);
+
+	snd_soc_update_bits(codec, SITAR_A_RX_HPH_CNP_EN, 0x30, 0x00);
+	snd_soc_update_bits(codec, SITAR_A_RX_HPH_L_DAC_CTL,
+			    0xC0, 0x00);
+	snd_soc_update_bits(codec, SITAR_A_RX_HPH_R_DAC_CTL,
+			    0xC0, 0x00);
+	usleep_range(wg_time * 1000, wg_time * 1000);
+}
+
+static void sitar_clr_and_turnon_hph_padac(struct sitar_priv *sitar)
+{
+	bool pa_turned_on = false;
+	struct snd_soc_codec *codec = sitar->codec;
+	u8 wg_time;
+
+	wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
+	wg_time += 1;
+
+	if (test_and_clear_bit(SITAR_HPHR_DAC_OFF_ACK,
+			       &sitar->hph_pa_dac_state)) {
+		pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
+		snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_R_DAC_CTL,
+				    0xC0, 0xC0);
+	}
+	if (test_and_clear_bit(SITAR_HPHL_DAC_OFF_ACK,
+			       &sitar->hph_pa_dac_state)) {
+		pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
+		snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_L_DAC_CTL,
+				    0xC0, 0xC0);
+	}
+
+	if (test_and_clear_bit(SITAR_HPHR_PA_OFF_ACK,
+			       &sitar->hph_pa_dac_state)) {
+		pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
+		snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x10,
+				    1 << 4);
+		pa_turned_on = true;
+	}
+	if (test_and_clear_bit(SITAR_HPHL_PA_OFF_ACK,
+			       &sitar->hph_pa_dac_state)) {
+		pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
+		snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x20,
+				    1 << 5);
+		pa_turned_on = true;
+	}
+
+	if (pa_turned_on) {
+		pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
+				__func__);
+		usleep_range(wg_time * 1000, wg_time * 1000);
+	}
+}
+
+static void sitar_codec_report_plug(struct snd_soc_codec *codec, int insertion,
+				    enum snd_jack_types jack_type)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	if (!insertion) {
+		/* Report removal */
+		sitar->hph_status &= ~jack_type;
+		if (sitar->mbhc_cfg.headset_jack) {
+			/* cancel possibly scheduled btn work and
+			* report release if we reported button press */
+			if (sitar_cancel_btn_work(sitar)) {
+				pr_debug("%s: button press is canceled\n",
+					__func__);
+			} else if (sitar->buttons_pressed) {
+				pr_debug("%s: Reporting release for reported "
+					 "button press %d\n", __func__,
+					 jack_type);
+				sitar_snd_soc_jack_report(sitar,
+						 sitar->mbhc_cfg.button_jack, 0,
+						 sitar->buttons_pressed);
+				sitar->buttons_pressed &=
+							~SITAR_JACK_BUTTON_MASK;
+			}
+			pr_debug("%s: Reporting removal %d\n", __func__,
+				 jack_type);
+			sitar_snd_soc_jack_report(sitar,
+						  sitar->mbhc_cfg.headset_jack,
+						  sitar->hph_status,
+						  SITAR_JACK_MASK);
+		}
+		sitar_set_and_turnoff_hph_padac(codec);
+		hphocp_off_report(sitar, SND_JACK_OC_HPHR,
+				  SITAR_IRQ_HPH_PA_OCPR_FAULT);
+		hphocp_off_report(sitar, SND_JACK_OC_HPHL,
+				  SITAR_IRQ_HPH_PA_OCPL_FAULT);
+		sitar->current_plug = PLUG_TYPE_NONE;
+		sitar->mbhc_polling_active = false;
+	} else {
+		/* Report insertion */
+		sitar->hph_status |= jack_type;
+
+		if (jack_type == SND_JACK_HEADPHONE)
+			sitar->current_plug = PLUG_TYPE_HEADPHONE;
+		else if (jack_type == SND_JACK_HEADSET) {
+			sitar->mbhc_polling_active = true;
+			sitar->current_plug = PLUG_TYPE_HEADSET;
+		}
+		if (sitar->mbhc_cfg.headset_jack) {
+			pr_debug("%s: Reporting insertion %d\n", __func__,
+				 jack_type);
+			sitar_snd_soc_jack_report(sitar,
+						  sitar->mbhc_cfg.headset_jack,
+						  sitar->hph_status,
+						  SITAR_JACK_MASK);
+		}
+		sitar_clr_and_turnon_hph_padac(sitar);
+	}
+}
+
+
+static bool sitar_hs_gpio_level_remove(struct sitar_priv *sitar)
+{
+	return (gpio_get_value_cansleep(sitar->mbhc_cfg.gpio) !=
+		sitar->mbhc_cfg.gpio_level_insert);
+}
+
+static bool sitar_is_invalid_insert_delta(struct snd_soc_codec *codec,
+					int mic_volt, int mic_volt_prev)
+{
+	int delta = abs(mic_volt - mic_volt_prev);
+	if (delta > SITAR_MBHC_FAKE_INSERT_VOLT_DELTA_MV) {
+		pr_debug("%s: volt delta %dmv\n", __func__, delta);
+		return true;
+	}
+	return false;
+}
+
+static bool sitar_is_invalid_insertion_range(struct snd_soc_codec *codec,
+				       s32 mic_volt)
+{
+	bool invalid = false;
+
+	if (mic_volt < SITAR_MBHC_FAKE_INSERT_HIGH
+			&& (mic_volt > SITAR_MBHC_FAKE_INSERT_LOW)) {
+		invalid = true;
+	}
+
+	return invalid;
+}
+
+static bool sitar_codec_is_invalid_plug(struct snd_soc_codec *codec,
+	s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT],
+	enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT])
+{
+	int i;
+	bool r = false;
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	struct sitar_mbhc_plug_type_cfg *plug_type_ptr =
+		SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
+
+	for (i = 0 ; i < MBHC_NUM_DCE_PLUG_DETECT && !r; i++) {
+		if (mic_mv[i] < plug_type_ptr->v_no_mic)
+			plug_type[i] = PLUG_TYPE_HEADPHONE;
+		else if (mic_mv[i] < plug_type_ptr->v_hs_max)
+			plug_type[i] = PLUG_TYPE_HEADSET;
+		else if (mic_mv[i] > plug_type_ptr->v_hs_max)
+			plug_type[i] = PLUG_TYPE_HIGH_HPH;
+
+		r = sitar_is_invalid_insertion_range(codec, mic_mv[i]);
+		if (!r && i > 0) {
+			if (plug_type[i-1] != plug_type[i])
+				r = true;
+			else
+				r = sitar_is_invalid_insert_delta(codec,
+							mic_mv[i],
+							mic_mv[i - 1]);
+		}
+	}
+
+	return r;
+}
+
+/* called under codec_resource_lock acquisition */
+void sitar_find_plug_and_report(struct snd_soc_codec *codec,
+				enum sitar_mbhc_plug_type plug_type)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	if (plug_type == PLUG_TYPE_HEADPHONE
+		&& sitar->current_plug == PLUG_TYPE_NONE) {
+		/* Nothing was reported previously
+		 * reporte a headphone
+		 */
+		sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
+		sitar_codec_cleanup_hs_polling(codec);
+	} else if (plug_type == PLUG_TYPE_HEADSET) {
+		/* If Headphone was reported previously, this will
+		 * only report the mic line
+		 */
+		sitar_codec_report_plug(codec, 1, SND_JACK_HEADSET);
+		msleep(100);
+		sitar_codec_start_hs_polling(codec);
+	} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
+		if (sitar->current_plug == PLUG_TYPE_NONE)
+			sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
+		sitar_codec_cleanup_hs_polling(codec);
+		pr_debug("setup mic trigger for further detection\n");
+		sitar->lpi_enabled = true;
+		/* TODO ::: sitar_codec_enable_hs_detect */
+		pr_err("%s(): High impedence hph not supported\n", __func__);
+	}
+}
+
+/* should be called under interrupt context that hold suspend */
+static void sitar_schedule_hs_detect_plug(struct sitar_priv *sitar)
+{
+	pr_debug("%s: scheduling sitar_hs_correct_gpio_plug\n", __func__);
+	sitar->hs_detect_work_stop = false;
+	wcd9xxx_lock_sleep(sitar->codec->control_data);
+	schedule_work(&sitar->hs_correct_plug_work);
+}
+
+/* called under codec_resource_lock acquisition */
+static void sitar_cancel_hs_detect_plug(struct sitar_priv *sitar)
+{
+	pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
+	sitar->hs_detect_work_stop = true;
+	wmb();
+	SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
+	if (cancel_work_sync(&sitar->hs_correct_plug_work)) {
+		pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
+		wcd9xxx_unlock_sleep(sitar->codec->control_data);
+	}
+	SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
+}
+
+static void sitar_hs_correct_gpio_plug(struct work_struct *work)
+{
+	struct sitar_priv *sitar;
+	struct snd_soc_codec *codec;
+	int retry = 0, i;
+	bool correction = false;
+	s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
+	short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
+	enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
+	unsigned long timeout;
+
+	sitar = container_of(work, struct sitar_priv, hs_correct_plug_work);
+	codec = sitar->codec;
+
+	pr_debug("%s: enter\n", __func__);
+	sitar->mbhc_cfg.mclk_cb_fn(codec, 1, false);
+
+	/* Keep override on during entire plug type correction work.
+	 *
+	 * This is okay under the assumption that any GPIO irqs which use
+	 * MBHC block cancel and sync this work so override is off again
+	 * prior to GPIO interrupt handler's MBHC block usage.
+	 * Also while this correction work is running, we can guarantee
+	 * DAPM doesn't use any MBHC block as this work only runs with
+	 * headphone detection.
+	 */
+	sitar_turn_onoff_override(codec, true);
+
+	timeout = jiffies + msecs_to_jiffies(SITAR_HS_DETECT_PLUG_TIME_MS);
+	while (!time_after(jiffies, timeout)) {
+		++retry;
+		rmb();
+		if (sitar->hs_detect_work_stop) {
+			pr_debug("%s: stop requested\n", __func__);
+			break;
+		}
+
+		msleep(SITAR_HS_DETECT_PLUG_INERVAL_MS);
+		if (sitar_hs_gpio_level_remove(sitar)) {
+			pr_debug("%s: GPIO value is low\n", __func__);
+			break;
+		}
+
+		/* can race with removal interrupt */
+		SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
+		for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
+			mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
+			mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
+			pr_debug("%s : DCE run %d, mic_mv = %d(%x)\n",
+				 __func__, retry, mic_mv[i], mb_v[i]);
+		}
+		SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
+
+		if (sitar_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
+			pr_debug("Invalid plug in attempt # %d\n", retry);
+			if (retry == NUM_ATTEMPTS_TO_REPORT &&
+			    sitar->current_plug == PLUG_TYPE_NONE) {
+				sitar_codec_report_plug(codec, 1,
+							SND_JACK_HEADPHONE);
+			}
+		} else if (!sitar_codec_is_invalid_plug(codec, mic_mv,
+							plug_type) &&
+			   plug_type[0] == PLUG_TYPE_HEADPHONE) {
+			pr_debug("Good headphone detected, continue polling mic\n");
+			if (sitar->current_plug == PLUG_TYPE_NONE) {
+				sitar_codec_report_plug(codec, 1,
+							SND_JACK_HEADPHONE);
+			}
+		} else {
+			SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
+			/* Turn off override */
+			sitar_turn_onoff_override(codec, false);
+			sitar_find_plug_and_report(codec, plug_type[0]);
+			SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
+			pr_debug("Attempt %d found correct plug %d\n", retry,
+				 plug_type[0]);
+			correction = true;
+			break;
+		}
+	}
+
+	/* Turn off override */
+	if (!correction)
+		sitar_turn_onoff_override(codec, false);
+
+	sitar->mbhc_cfg.mclk_cb_fn(codec, 0, false);
+	pr_debug("%s: leave\n", __func__);
+	/* unlock sleep */
+	wcd9xxx_unlock_sleep(sitar->codec->control_data);
+}
+
+/* called under codec_resource_lock acquisition */
+static void sitar_codec_decide_gpio_plug(struct snd_soc_codec *codec)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
+	s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
+	enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
+	int i;
+
+	pr_debug("%s: enter\n", __func__);
+
+	sitar_turn_onoff_override(codec, true);
+	mb_v[0] = sitar_codec_setup_hs_polling(codec);
+	mic_mv[0] = sitar_codec_sta_dce_v(codec, 1, mb_v[0]);
+	pr_debug("%s: DCE run 1, mic_mv = %d\n", __func__, mic_mv[0]);
+
+	for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
+		mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
+		mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
+		pr_debug("%s: DCE run %d, mic_mv = %d\n", __func__, i + 1,
+			 mic_mv[i]);
+	}
+	sitar_turn_onoff_override(codec, false);
+
+	if (sitar_hs_gpio_level_remove(sitar)) {
+		pr_debug("%s: GPIO value is low when determining plug\n",
+			 __func__);
+		return;
+	}
+
+	if (sitar_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
+		sitar_schedule_hs_detect_plug(sitar);
+	} else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
+		sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
+		sitar_schedule_hs_detect_plug(sitar);
+	} else if (plug_type[0] == PLUG_TYPE_HEADSET) {
+		pr_debug("%s: Valid plug found, determine plug type\n",
+			 __func__);
+		sitar_find_plug_and_report(codec, plug_type[0]);
+	}
+
+}
+
+/* called under codec_resource_lock acquisition */
+static void sitar_codec_detect_plug_type(struct snd_soc_codec *codec)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	const struct sitar_mbhc_plug_detect_cfg *plug_det =
+	    SITAR_MBHC_CAL_PLUG_DET_PTR(sitar->mbhc_cfg.calibration);
+
+	if (plug_det->t_ins_complete > 20)
+		msleep(plug_det->t_ins_complete);
+	else
+		usleep_range(plug_det->t_ins_complete * 1000,
+			     plug_det->t_ins_complete * 1000);
+
+	if (sitar_hs_gpio_level_remove(sitar))
+		pr_debug("%s: GPIO value is low when determining "
+				 "plug\n", __func__);
+	else
+		sitar_codec_decide_gpio_plug(codec);
+
+	return;
+}
+
+static void sitar_hs_gpio_handler(struct snd_soc_codec *codec)
+{
+	bool insert;
+	struct sitar_priv *priv = snd_soc_codec_get_drvdata(codec);
+	bool is_removed = false;
+
+	pr_debug("%s: enter\n", __func__);
+
+	priv->in_gpio_handler = true;
+	/* Wait here for debounce time */
+	usleep_range(SITAR_GPIO_IRQ_DEBOUNCE_TIME_US,
+		     SITAR_GPIO_IRQ_DEBOUNCE_TIME_US);
+
+	SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
+
+	/* cancel pending button press */
+	if (sitar_cancel_btn_work(priv))
+		pr_debug("%s: button press is canceled\n", __func__);
+
+	insert = (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
+		  priv->mbhc_cfg.gpio_level_insert);
+	if ((priv->current_plug == PLUG_TYPE_NONE) && insert) {
+		priv->lpi_enabled = false;
+		wmb();
+
+		/* cancel detect plug */
+		sitar_cancel_hs_detect_plug(priv);
+
+		/* Disable Mic Bias pull down and HPH Switch to GND */
+		snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01,
+				    0x00);
+		snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x01, 0x00);
+		sitar_codec_detect_plug_type(codec);
+	} else if ((priv->current_plug != PLUG_TYPE_NONE) && !insert) {
+		priv->lpi_enabled = false;
+		wmb();
+
+		/* cancel detect plug */
+		sitar_cancel_hs_detect_plug(priv);
+
+		if (priv->current_plug == PLUG_TYPE_HEADPHONE) {
+			sitar_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
+			is_removed = true;
+		} else if (priv->current_plug == PLUG_TYPE_HEADSET) {
+			sitar_codec_pause_hs_polling(codec);
+			sitar_codec_cleanup_hs_polling(codec);
+			sitar_codec_report_plug(codec, 0, SND_JACK_HEADSET);
+			is_removed = true;
+		}
+
+		if (is_removed) {
+			/* Enable Mic Bias pull down and HPH Switch to GND */
+			snd_soc_update_bits(codec,
+					    priv->mbhc_bias_regs.ctl_reg, 0x01,
+					    0x01);
+			snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x01,
+					    0x01);
+			/* Make sure mic trigger is turned off */
+			snd_soc_update_bits(codec,
+					    priv->mbhc_bias_regs.ctl_reg,
+					    0x01, 0x01);
+			snd_soc_update_bits(codec,
+					    priv->mbhc_bias_regs.mbhc_reg,
+					    0x90, 0x00);
+			/* Reset MBHC State Machine */
+			snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL,
+					    0x08, 0x08);
+			snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL,
+					    0x08, 0x00);
+			/* Turn off override */
+			sitar_turn_onoff_override(codec, false);
+		}
+	}
+
+	priv->in_gpio_handler = false;
+	SITAR_RELEASE_LOCK(priv->codec_resource_lock);
+	pr_debug("%s: leave\n", __func__);
+}
+
+static irqreturn_t sitar_mechanical_plug_detect_irq(int irq, void *data)
+{
+	int r = IRQ_HANDLED;
+	struct snd_soc_codec *codec = data;
+
+	if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
+		pr_warn("%s(): Failed to hold suspend\n", __func__);
+		r = IRQ_NONE;
+	} else {
+		sitar_hs_gpio_handler(codec);
+		wcd9xxx_unlock_sleep(codec->control_data);
+	}
+	return r;
+}
+
+static int sitar_mbhc_init_and_calibrate(struct snd_soc_codec *codec)
+{
+	int rc = 0;
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	sitar->mbhc_cfg.mclk_cb_fn(codec, 1, false);
+	sitar_mbhc_init(codec);
+	sitar_mbhc_cal(codec);
+	sitar_mbhc_calc_thres(codec);
+	sitar->mbhc_cfg.mclk_cb_fn(codec, 0, false);
+	sitar_codec_calibrate_hs_polling(codec);
+
+	/* Enable Mic Bias pull down and HPH Switch to GND */
+	snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg,
+						0x01, 0x01);
+	snd_soc_update_bits(codec, SITAR_A_MBHC_HPH,
+						0x01, 0x01);
+
+	rc = request_threaded_irq(sitar->mbhc_cfg.gpio_irq,
+				NULL,
+				sitar_mechanical_plug_detect_irq,
+				(IRQF_TRIGGER_RISING |
+				IRQF_TRIGGER_FALLING),
+				"sitar-hs-gpio", codec);
+
+	if (!IS_ERR_VALUE(rc)) {
+		rc = enable_irq_wake(sitar->mbhc_cfg.gpio_irq);
+		snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL,
+							0x10, 0x10);
+		wcd9xxx_enable_irq(codec->control_data,
+					SITAR_IRQ_HPH_PA_OCPL_FAULT);
+		wcd9xxx_enable_irq(codec->control_data,
+					SITAR_IRQ_HPH_PA_OCPR_FAULT);
+		/* Bootup time detection */
+		sitar_hs_gpio_handler(codec);
+	}
+
+	return rc;
+}
+
 static void mbhc_fw_read(struct work_struct *work)
 {
 	struct delayed_work *dwork;
 	struct sitar_priv *sitar;
 	struct snd_soc_codec *codec;
 	const struct firmware *fw;
-	int ret = -1, retry = 0, rc;
+	int ret = -1, retry = 0;
 
 	dwork = to_delayed_work(work);
 	sitar = container_of(dwork, struct sitar_priv,
@@ -3124,80 +3740,53 @@
 		sitar->mbhc_fw = fw;
 	}
 
-	sitar->mclk_cb(codec, 1);
-	sitar_mbhc_init(codec);
-	sitar_mbhc_cal(codec);
-	sitar_mbhc_calc_thres(codec);
-	sitar->mclk_cb(codec, 0);
-	sitar_codec_calibrate_hs_polling(codec);
-	rc = sitar_codec_enable_hs_detect(codec, 1);
-
-	if (IS_ERR_VALUE(rc))
-		pr_err("%s: Failed to setup MBHC detection\n", __func__);
-
+	sitar_mbhc_init_and_calibrate(codec);
 }
 
 int sitar_hs_detect(struct snd_soc_codec *codec,
-		    struct snd_soc_jack *headset_jack,
-		    struct snd_soc_jack *button_jack,
-		    void *calibration, enum sitar_micbias_num micbias,
-		    int (*mclk_cb_fn) (struct snd_soc_codec*, int),
-		    int read_fw_bin, u32 mclk_rate)
+			const struct sitar_mbhc_config *cfg)
 {
 	struct sitar_priv *sitar;
 	int rc = 0;
 
-	if (!codec || !calibration) {
+	if (!codec || !cfg->calibration) {
 		pr_err("Error: no codec or calibration\n");
 		return -EINVAL;
 	}
 
-	if (mclk_rate != SITAR_MCLK_RATE_12288KHZ) {
-		if (mclk_rate == SITAR_MCLK_RATE_9600KHZ)
+	if (cfg->mclk_rate != SITAR_MCLK_RATE_12288KHZ) {
+		if (cfg->mclk_rate == SITAR_MCLK_RATE_9600KHZ)
 			pr_err("Error: clock rate %dHz is not yet supported\n",
-				mclk_rate);
+				cfg->mclk_rate);
 		else
-			pr_err("Error: unsupported clock rate %d\n", mclk_rate);
+			pr_err("Error: unsupported clock rate %d\n",
+				   cfg->mclk_rate);
 		return -EINVAL;
 	}
 
 	sitar = snd_soc_codec_get_drvdata(codec);
-	sitar->headset_jack = headset_jack;
-	sitar->button_jack = button_jack;
-	sitar->micbias = micbias;
-	sitar->calibration = calibration;
-	sitar->mclk_cb = mclk_cb_fn;
-	sitar->mclk_freq = mclk_rate;
+	sitar->mbhc_cfg = *cfg;
+	sitar->in_gpio_handler = false;
+	sitar->current_plug = PLUG_TYPE_NONE;
+	sitar->lpi_enabled = false;
 	sitar_get_mbhc_micbias_regs(codec, &sitar->mbhc_bias_regs);
 
 	/* Put CFILT in fast mode by default */
 	snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl,
-		0x40, SITAR_CFILT_FAST_MODE);
+			    0x40, SITAR_CFILT_FAST_MODE);
+
 	INIT_DELAYED_WORK(&sitar->mbhc_firmware_dwork, mbhc_fw_read);
-	INIT_DELAYED_WORK(&sitar->btn0_dwork, btn0_lpress_fn);
+	INIT_DELAYED_WORK(&sitar->mbhc_btn_dwork, btn_lpress_fn);
 	INIT_WORK(&sitar->hphlocp_work, hphlocp_off_report);
 	INIT_WORK(&sitar->hphrocp_work, hphrocp_off_report);
+	INIT_WORK(&sitar->hs_correct_plug_work,
+			  sitar_hs_correct_gpio_plug);
 
-	if (!read_fw_bin) {
-		sitar->mclk_cb(codec, 1);
-		sitar_mbhc_init(codec);
-		sitar_mbhc_cal(codec);
-		sitar_mbhc_calc_thres(codec);
-		sitar->mclk_cb(codec, 0);
-		sitar_codec_calibrate_hs_polling(codec);
-		rc =  sitar_codec_enable_hs_detect(codec, 1);
+	if (!sitar->mbhc_cfg.read_fw_bin) {
+		rc = sitar_mbhc_init_and_calibrate(codec);
 	} else {
 		schedule_delayed_work(&sitar->mbhc_firmware_dwork,
-				usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
-	}
-
-	if (!IS_ERR_VALUE(rc)) {
-		snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
-			0x10);
-		wcd9xxx_enable_irq(codec->control_data,
-			SITAR_IRQ_HPH_PA_OCPL_FAULT);
-		wcd9xxx_enable_irq(codec->control_data,
-			SITAR_IRQ_HPH_PA_OCPR_FAULT);
+					usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
 	}
 
 	return rc;
@@ -3211,7 +3800,7 @@
 	struct sitar_mbhc_btn_detect_cfg *btn_det;
 	int i, btn = -1;
 
-	btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(priv->calibration);
+	btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
 	v_btn_low = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_V_BTN_LOW);
 	v_btn_high = sitar_mbhc_cal_btn_det_mp(btn_det,
 				SITAR_BTN_DET_V_BTN_HIGH);
@@ -3261,33 +3850,76 @@
 	return mask;
 }
 
+
 static irqreturn_t sitar_dce_handler(int irq, void *data)
 {
 	int i, mask;
-	short bias_value_dce;
-	s32 bias_mv_dce;
+	short dce, sta, bias_value_dce;
+	s32 mv, stamv, bias_mv_dce;
 	int btn = -1, meas = 0;
 	struct sitar_priv *priv = data;
 	const struct sitar_mbhc_btn_detect_cfg *d =
-	    SITAR_MBHC_CAL_BTN_DET_PTR(priv->calibration);
+	    SITAR_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
 	short btnmeas[d->n_btn_meas + 1];
 	struct snd_soc_codec *codec = priv->codec;
 	struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
+	int n_btn_meas = d->n_btn_meas;
+	u8 mbhc_status = snd_soc_read(codec, SITAR_A_CDC_MBHC_B1_STATUS) & 0x3E;
 
-	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
-	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+	pr_debug("%s: enter\n", __func__);
 
-	bias_value_dce = sitar_codec_read_dce_result(codec);
-	bias_mv_dce = sitar_codec_sta_dce_v(codec, 1, bias_value_dce);
+	SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
+	if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
+		pr_debug("%s: mbhc is being recovered, skip button press\n",
+			 __func__);
+		goto done;
+	}
+
+	priv->mbhc_state = MBHC_STATE_POTENTIAL;
+
+	if (!priv->mbhc_polling_active) {
+		pr_warn("%s: mbhc polling is not active, skip button press\n",
+			__func__);
+		goto done;
+	}
+
+	dce = sitar_codec_read_dce_result(codec);
+	mv = sitar_codec_sta_dce_v(codec, 1, dce);
+
+	/* If GPIO interrupt already kicked in, ignore button press */
+	if (priv->in_gpio_handler) {
+		pr_debug("%s: GPIO State Changed, ignore button press\n",
+			 __func__);
+		btn = -1;
+		goto done;
+	}
+
+	if (mbhc_status != SITAR_MBHC_STATUS_REL_DETECTION) {
+		if (priv->mbhc_last_resume &&
+		    !time_after(jiffies, priv->mbhc_last_resume + HZ)) {
+			pr_debug("%s: Button is already released shortly after "
+				 "resume\n", __func__);
+			n_btn_meas = 0;
+		} else {
+			pr_debug("%s: Button is already released without "
+				 "resume", __func__);
+			sta = sitar_codec_read_sta_result(codec);
+			stamv = sitar_codec_sta_dce_v(codec, 0, sta);
+			btn = sitar_determine_button(priv, mv);
+			if (btn != sitar_determine_button(priv, stamv))
+				btn = -1;
+			goto done;
+		}
+	}
 
 	/* determine pressed button */
-	btnmeas[meas++] = sitar_determine_button(priv, bias_mv_dce);
+	btnmeas[meas++] = sitar_determine_button(priv, mv);
 	pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
-		 meas - 1, bias_value_dce, bias_mv_dce, btnmeas[meas - 1]);
-	if (d->n_btn_meas == 0)
+		 meas - 1, dce, mv, btnmeas[meas - 1]);
+	if (n_btn_meas == 0)
 		btn = btnmeas[0];
 	for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
-		bias_value_dce = sitar_codec_sta_dce(codec, 1);
+		bias_value_dce = sitar_codec_sta_dce(codec, 1, false);
 		bias_mv_dce = sitar_codec_sta_dce_v(codec, 1, bias_value_dce);
 		btnmeas[meas] = sitar_determine_button(priv, bias_mv_dce);
 		pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
@@ -3305,147 +3937,133 @@
 				/* button pressed */
 				btn = btnmeas[meas];
 				break;
+			} else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
+				/* if left measurements are less than n_btn_con,
+				 * it's impossible to find button number */
+				break;
 			}
 		}
-		/* if left measurements are less than n_btn_con,
-		 * it's impossible to find button number */
-		if ((d->n_btn_meas - meas) < d->n_btn_con)
-			break;
 	}
 
 	if (btn >= 0) {
+		if (priv->in_gpio_handler) {
+			pr_debug("%s: GPIO already triggered, ignore button "
+				 "press\n", __func__);
+			goto done;
+		}
 		mask = sitar_get_button_mask(btn);
 		priv->buttons_pressed |= mask;
-
-		msleep(100);
-
-		/* XXX: assuming button 0 has the lowest micbias voltage */
-		if (btn == 0) {
-			wcd9xxx_lock_sleep(core);
-			if (schedule_delayed_work(&priv->btn0_dwork,
-						  msecs_to_jiffies(400)) == 0) {
-				WARN(1, "Button pressed twice without release"
-				     "event\n");
-				wcd9xxx_unlock_sleep(core);
-			}
-		} else {
-			pr_debug("%s: Reporting short button %d(0x%x) press\n",
-				  __func__, btn, mask);
-			sitar_snd_soc_jack_report(priv, priv->button_jack, mask,
-						  mask);
+		wcd9xxx_lock_sleep(core);
+		if (schedule_delayed_work(&priv->mbhc_btn_dwork,
+					  msecs_to_jiffies(400)) == 0) {
+			WARN(1, "Button pressed twice without release"
+			     "event\n");
+			wcd9xxx_unlock_sleep(core);
 		}
 	} else {
 		pr_debug("%s: bogus button press, too short press?\n",
 			 __func__);
 	}
 
+ done:
+	pr_debug("%s: leave\n", __func__);
+	SITAR_RELEASE_LOCK(priv->codec_resource_lock);
 	return IRQ_HANDLED;
 }
 
+static int sitar_is_fake_press(struct sitar_priv *priv)
+{
+	int i;
+	int r = 0;
+	struct snd_soc_codec *codec = priv->codec;
+	const int dces = MBHC_NUM_DCE_PLUG_DETECT;
+	short mb_v;
+
+	for (i = 0; i < dces; i++) {
+		usleep_range(10000, 10000);
+		if (i == 0) {
+			mb_v = sitar_codec_sta_dce(codec, 0, true);
+			pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
+			sitar_codec_sta_dce_v(codec, 0, mb_v));
+			if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
+				mb_v > (short)priv->mbhc_data.v_ins_hu) {
+				r = 1;
+				break;
+			}
+		} else {
+			mb_v = sitar_codec_sta_dce(codec, 1, true);
+			pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
+			sitar_codec_sta_dce_v(codec, 1, mb_v));
+			if (mb_v < (short)priv->mbhc_data.v_b1_h ||
+				mb_v > (short)priv->mbhc_data.v_ins_h) {
+				r = 1;
+				break;
+			}
+		}
+	}
+
+	return r;
+}
+
 static irqreturn_t sitar_release_handler(int irq, void *data)
 {
 	int ret;
-	short mb_v;
 	struct sitar_priv *priv = data;
 	struct snd_soc_codec *codec = priv->codec;
-	struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
 
 	pr_debug("%s: enter\n", __func__);
-	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE);
 
-	if (priv->buttons_pressed & SND_JACK_BTN_0) {
-		ret = cancel_delayed_work(&priv->btn0_dwork);
+	SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
+	priv->mbhc_state = MBHC_STATE_RELEASE;
 
+	if (priv->buttons_pressed & SITAR_JACK_BUTTON_MASK) {
+		ret = sitar_cancel_btn_work(priv);
 		if (ret == 0) {
-			pr_debug("%s: Reporting long button 0 release event\n",
+			pr_debug("%s: Reporting long button release event\n",
 				 __func__);
-			if (priv->button_jack)
+			if (priv->mbhc_cfg.button_jack)
 				sitar_snd_soc_jack_report(priv,
-							  priv->button_jack, 0,
-							  SND_JACK_BTN_0);
+						  priv->mbhc_cfg.button_jack, 0,
+						  priv->buttons_pressed);
 		} else {
-			/* if scheduled btn0_dwork is canceled from here,
-			 * we have to unlock from here instead btn0_work */
-			wcd9xxx_unlock_sleep(core);
-			mb_v = sitar_codec_sta_dce(codec, 0);
-			pr_debug("%s: Mic Voltage on release STA: %d,%d\n",
-				 __func__, mb_v,
-				 sitar_codec_sta_dce_v(codec, 0, mb_v));
-
-			if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
-			    mb_v > (short)priv->mbhc_data.v_ins_hu)
-				pr_debug("%s: Fake buttton press interrupt\n",
+			if (sitar_is_fake_press(priv)) {
+				pr_debug("%s: Fake button press interrupt\n",
 					 __func__);
-			else if (priv->button_jack) {
-				pr_debug("%s: Reporting short button 0 "
-					 "press and release\n", __func__);
-				sitar_snd_soc_jack_report(priv,
-							  priv->button_jack,
-							  SND_JACK_BTN_0,
-							  SND_JACK_BTN_0);
-				sitar_snd_soc_jack_report(priv,
-							  priv->button_jack, 0,
-							  SND_JACK_BTN_0);
+			} else if (priv->mbhc_cfg.button_jack) {
+				if (priv->in_gpio_handler) {
+					pr_debug("%s: GPIO kicked in, ignore\n",
+						 __func__);
+				} else {
+					pr_debug("%s: Reporting short button 0 "
+						 "press and release\n",
+						 __func__);
+					sitar_snd_soc_jack_report(priv,
+						priv->mbhc_cfg.button_jack,
+						priv->buttons_pressed,
+						priv->buttons_pressed);
+					sitar_snd_soc_jack_report(priv,
+						priv->mbhc_cfg.button_jack, 0,
+						priv->buttons_pressed);
+				}
 			}
 		}
 
-		priv->buttons_pressed &= ~SND_JACK_BTN_0;
-	}
-
-	if (priv->buttons_pressed) {
-		pr_debug("%s:reporting button release mask 0x%x\n", __func__,
-			 priv->buttons_pressed);
-		sitar_snd_soc_jack_report(priv, priv->button_jack, 0,
-					  priv->buttons_pressed);
-		/* hardware doesn't detect another button press until
-		 * already pressed button is released.
-		 * therefore buttons_pressed has only one button's mask. */
 		priv->buttons_pressed &= ~SITAR_JACK_BUTTON_MASK;
 	}
 
+	sitar_codec_calibrate_hs_polling(codec);
+
+	if (priv->mbhc_cfg.gpio)
+		msleep(SITAR_MBHC_GPIO_REL_DEBOUNCE_TIME_MS);
+
 	sitar_codec_start_hs_polling(codec);
+
+	pr_debug("%s: leave\n", __func__);
+	SITAR_RELEASE_LOCK(priv->codec_resource_lock);
+
 	return IRQ_HANDLED;
 }
 
-static void sitar_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
-{
-	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
-	const struct sitar_mbhc_general_cfg *generic =
-	    SITAR_MBHC_CAL_GENERAL_PTR(sitar->calibration);
-
-	if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
-		sitar_codec_enable_config_mode(codec, 1);
-
-	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
-	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
-
-	snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
-
-	usleep_range(generic->t_shutdown_plug_rem,
-		     generic->t_shutdown_plug_rem);
-
-	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
-	if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
-		sitar_codec_enable_config_mode(codec, 0);
-
-	snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x00);
-}
-
-static void sitar_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
-{
-	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
-
-	sitar_codec_shutdown_hs_removal_detect(codec);
-
-	if (!sitar->mclk_enabled) {
-		snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS, 0xE0, 0x00);
-		sitar_codec_disable_clock_block(codec);
-		sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
-	}
-
-	sitar->mbhc_polling_active = false;
-}
-
 static irqreturn_t sitar_hphl_ocp_irq(int irq, void *data)
 {
 	struct sitar_priv *sitar = data;
@@ -3466,11 +4084,11 @@
 					  SITAR_IRQ_HPH_PA_OCPL_FAULT);
 			sitar->hphlocp_cnt = 0;
 			sitar->hph_status |= SND_JACK_OC_HPHL;
-			if (sitar->headset_jack)
+			if (sitar->mbhc_cfg.headset_jack)
 				sitar_snd_soc_jack_report(sitar,
-							  sitar->headset_jack,
-							  sitar->hph_status,
-							  SITAR_JACK_MASK);
+						sitar->mbhc_cfg.headset_jack,
+						sitar->hph_status,
+						SITAR_JACK_MASK);
 		}
 	} else {
 		pr_err("%s: Bad sitar private data\n", __func__);
@@ -3499,11 +4117,11 @@
 					 SITAR_IRQ_HPH_PA_OCPR_FAULT);
 			sitar->hphrocp_cnt = 0;
 			sitar->hph_status |= SND_JACK_OC_HPHR;
-			if (sitar->headset_jack)
+			if (sitar->mbhc_cfg.headset_jack)
 				sitar_snd_soc_jack_report(sitar,
-							 sitar->headset_jack,
-							 sitar->hph_status,
-							 SITAR_JACK_MASK);
+						sitar->mbhc_cfg.headset_jack,
+						sitar->hph_status,
+						SITAR_JACK_MASK);
 		}
 	} else {
 		pr_err("%s: Bad sitar private data\n", __func__);
@@ -3512,252 +4130,131 @@
 	return IRQ_HANDLED;
 }
 
-static void sitar_sync_hph_state(struct sitar_priv *sitar)
-{
-	if (test_and_clear_bit(SITAR_HPHR_PA_OFF_ACK,
-				&sitar->hph_pa_dac_state)) {
-		pr_err("%s: HPHR clear flag and enable PA\n", __func__);
-		snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x10,
-				   1 << 4);
-	}
-	if (test_and_clear_bit(SITAR_HPHL_PA_OFF_ACK,
-				&sitar->hph_pa_dac_state)) {
-		pr_err("%s: HPHL clear flag and enable PA\n", __func__);
-		snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x20,
-				   1 << 5);
-	}
-
-	if (test_and_clear_bit(SITAR_HPHR_DAC_OFF_ACK,
-				&sitar->hph_pa_dac_state)) {
-		pr_err("%s: HPHR clear flag and enable DAC\n", __func__);
-		snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_R_DAC_CTL,
-				   0xC0, 0xC0);
-	}
-	if (test_and_clear_bit(SITAR_HPHL_DAC_OFF_ACK,
-				&sitar->hph_pa_dac_state)) {
-		pr_err("%s: HPHL clear flag and enable DAC\n", __func__);
-		snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_L_DAC_CTL,
-				   0xC0, 0xC0);
-	}
-}
-
 static irqreturn_t sitar_hs_insert_irq(int irq, void *data)
 {
 	struct sitar_priv *priv = data;
 	struct snd_soc_codec *codec = priv->codec;
-	const struct sitar_mbhc_plug_detect_cfg *plug_det =
-	    SITAR_MBHC_CAL_PLUG_DET_PTR(priv->calibration);
-	int ldo_h_on, micb_cfilt_on;
-	short mb_v;
-	u8 is_removal;
-	int mic_mv;
 
 	pr_debug("%s: enter\n", __func__);
+	SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
 	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
 
-	is_removal = snd_soc_read(codec, SITAR_A_CDC_MBHC_INT_CTL) & 0x02;
 	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
 
 	/* Turn off both HPH and MIC line schmitt triggers */
 	snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
 	snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
+	snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
 
-	if (priv->mbhc_fake_ins_start &&
-	    time_after(jiffies, priv->mbhc_fake_ins_start +
-			msecs_to_jiffies(SITAR_FAKE_INS_THRESHOLD_MS))) {
-		pr_debug("%s: fake context interrupt, reset insertion\n",
-			 __func__);
-		priv->mbhc_fake_ins_start = 0;
-		sitar_codec_shutdown_hs_polling(codec);
-		sitar_codec_enable_hs_detect(codec, 1);
-		return IRQ_HANDLED;
-	}
+	pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
 
-	ldo_h_on = snd_soc_read(codec, SITAR_A_LDO_H_MODE_1) & 0x80;
-	micb_cfilt_on = snd_soc_read(codec, priv->mbhc_bias_regs.cfilt_ctl)
-			    & 0x80;
+	rmb();
+	if (priv->lpi_enabled)
+		msleep(100);
 
-	if (!ldo_h_on)
-		snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
-	if (!micb_cfilt_on)
-		snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
-				    0x80, 0x80);
-	if (plug_det->t_ins_complete > 20)
-		msleep(plug_det->t_ins_complete);
-	else
-		usleep_range(plug_det->t_ins_complete * 1000,
-			     plug_det->t_ins_complete * 1000);
-
-	if (!ldo_h_on)
-		snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x0);
-	if (!micb_cfilt_on)
-		snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
-							0x80, 0x0);
-
-	if (is_removal) {
-		/*
-		* If headphone is removed while playback is in progress,
-		* it is possible that micbias will be switched to VDDIO.
-		*/
-		if (priv->mbhc_micbias_switched)
-			sitar_codec_switch_micbias(codec, 0);
-		priv->hph_status &= ~SND_JACK_HEADPHONE;
-
-		/* If headphone PA is on, check if userspace receives
-		* removal event to sync-up PA's state */
-		if (sitar_is_hph_pa_on(codec)) {
-			set_bit(SITAR_HPHL_PA_OFF_ACK, &priv->hph_pa_dac_state);
-			set_bit(SITAR_HPHR_PA_OFF_ACK, &priv->hph_pa_dac_state);
-		}
-
-		if (sitar_is_hph_dac_on(codec, 1))
-			set_bit(SITAR_HPHL_DAC_OFF_ACK,
-				&priv->hph_pa_dac_state);
-		if (sitar_is_hph_dac_on(codec, 0))
-			set_bit(SITAR_HPHR_DAC_OFF_ACK,
-				&priv->hph_pa_dac_state);
-
-		if (priv->headset_jack) {
-			pr_err("%s: Reporting removal\n", __func__);
-			sitar_snd_soc_jack_report(priv, priv->headset_jack,
-						 priv->hph_status,
-						 SITAR_JACK_MASK);
-		}
-		sitar_codec_shutdown_hs_removal_detect(codec);
-		sitar_codec_enable_hs_detect(codec, 1);
-		return IRQ_HANDLED;
-	}
-
-	mb_v = sitar_codec_setup_hs_polling(codec);
-	mic_mv = sitar_codec_sta_dce_v(codec, 0, mb_v);
-
-	if (mb_v > (short) priv->mbhc_data.v_ins_hu) {
-		pr_debug("%s: Fake insertion interrupt since %dmsec ago, "
-			 "STA : %d,%d\n", __func__,
-			 (priv->mbhc_fake_ins_start ?
-			     jiffies_to_msecs(jiffies -
-					      priv->mbhc_fake_ins_start) :
-			     0),
-			 mb_v, mic_mv);
-		if (time_after(jiffies,
-			priv->mbhc_fake_ins_start +
-			msecs_to_jiffies(SITAR_FAKE_INS_THRESHOLD_MS))) {
-			/* Disable HPH trigger and enable MIC line trigger */
-			snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x12,
-					    0x00);
-			snd_soc_update_bits(codec,
-					    priv->mbhc_bias_regs.mbhc_reg, 0x60,
-					    plug_det->mic_current << 5);
-			snd_soc_update_bits(codec,
-					    priv->mbhc_bias_regs.mbhc_reg,
-					    0x80, 0x80);
-			usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
-			snd_soc_update_bits(codec,
-					    priv->mbhc_bias_regs.mbhc_reg,
-					    0x10, 0x10);
-		} else {
-			if (priv->mbhc_fake_ins_start == 0)
-				priv->mbhc_fake_ins_start = jiffies;
-			/* Setup normal insert detection
-			 * Enable HPH Schmitt Trigger
-			 */
-			snd_soc_update_bits(codec, SITAR_A_MBHC_HPH,
-					    0x13 | 0x0C,
-					    0x13 | plug_det->hph_current << 2);
-		}
-		/* Setup for insertion detection */
-		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x2, 0);
-		wcd9xxx_enable_irq(codec->control_data,
-					SITAR_IRQ_MBHC_INSERTION);
-		snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
-
-	} else if (mb_v < (short) priv->mbhc_data.v_no_mic) {
-		pr_debug("%s: Headphone Detected, mb_v: %d,%d\n",
-			 __func__, mb_v, mic_mv);
-		priv->mbhc_fake_ins_start = 0;
-		priv->hph_status |= SND_JACK_HEADPHONE;
-		if (priv->headset_jack) {
-			pr_debug("%s: Reporting insertion %d\n", __func__,
-				 SND_JACK_HEADPHONE);
-			sitar_snd_soc_jack_report(priv, priv->headset_jack,
-						  priv->hph_status,
-						  SITAR_JACK_MASK);
-		}
-		sitar_codec_shutdown_hs_polling(codec);
-		sitar_codec_enable_hs_detect(codec, 0);
-		sitar_sync_hph_state(priv);
+	rmb();
+	if (!priv->lpi_enabled) {
+		pr_debug("%s: lpi is disabled\n", __func__);
+	} else if (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
+		   priv->mbhc_cfg.gpio_level_insert) {
+		pr_debug("%s: Valid insertion, "
+			 "detect plug type\n", __func__);
+		sitar_codec_decide_gpio_plug(codec);
 	} else {
-		pr_debug("%s: Headset detected, mb_v: %d,%d\n",
-			__func__, mb_v, mic_mv);
-		priv->mbhc_fake_ins_start = 0;
-		priv->hph_status |= SND_JACK_HEADSET;
-		if (priv->headset_jack) {
-			pr_debug("%s: Reporting insertion %d\n", __func__,
-				 SND_JACK_HEADSET);
-			sitar_snd_soc_jack_report(priv, priv->headset_jack,
-						  priv->hph_status,
-						  SITAR_JACK_MASK);
+		pr_debug("%s: Invalid insertion, "
+			 "stop plug detection\n", __func__);
+	}
+	SITAR_RELEASE_LOCK(priv->codec_resource_lock);
+	return IRQ_HANDLED;
+}
+
+static bool is_valid_mic_voltage(struct snd_soc_codec *codec, s32 mic_mv)
+{
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	struct sitar_mbhc_plug_type_cfg *plug_type =
+		SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
+
+	return (!(mic_mv > SITAR_MBHC_FAKE_INSERT_LOW
+				&& mic_mv < SITAR_MBHC_FAKE_INSERT_HIGH)
+			&& (mic_mv > plug_type->v_no_mic)
+			&& (mic_mv < plug_type->v_hs_max)) ? true : false;
+}
+
+/* called under codec_resource_lock acquisition
+ * returns true if mic voltage range is back to normal insertion
+ * returns false either if timedout or removed */
+static bool sitar_hs_remove_settle(struct snd_soc_codec *codec)
+{
+	int i;
+	bool timedout, settled = false;
+	s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
+	short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
+	unsigned long retry = 0, timeout;
+	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+	timeout = jiffies + msecs_to_jiffies(SITAR_HS_DETECT_PLUG_TIME_MS);
+	while (!(timedout = time_after(jiffies, timeout))) {
+		retry++;
+		if (sitar_hs_gpio_level_remove(sitar)) {
+			pr_debug("%s: GPIO indicates removal\n", __func__);
+			break;
 		}
-		/* avoid false button press detect */
-		msleep(50);
-		sitar_codec_start_hs_polling(codec);
-		sitar_sync_hph_state(priv);
+
+		if (retry > 1)
+			msleep(250);
+		else
+			msleep(50);
+
+		if (sitar_hs_gpio_level_remove(sitar)) {
+			pr_debug("%s: GPIO indicates removal\n", __func__);
+			break;
+		}
+
+		sitar_turn_onoff_override(codec, true);
+		for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
+			mb_v[i] = __sitar_codec_sta_dce(codec, 1,  true, true);
+			mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
+			pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
+				 __func__, retry, mic_mv[i], mb_v[i]);
+		}
+		sitar_turn_onoff_override(codec, false);
+
+		if (sitar_hs_gpio_level_remove(sitar)) {
+			pr_debug("%s: GPIO indicates removal\n", __func__);
+			break;
+		}
+
+		for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
+			if (!is_valid_mic_voltage(codec, mic_mv[i]))
+				break;
+
+		if (i == MBHC_NUM_DCE_PLUG_DETECT) {
+			pr_debug("%s: MIC voltage settled\n", __func__);
+			settled = true;
+			msleep(200);
+			break;
+		}
 	}
 
-	return IRQ_HANDLED;
+	if (timedout)
+		pr_debug("%s: Microphone did not settle in %d seconds\n",
+			 __func__, SITAR_HS_DETECT_PLUG_TIME_MS);
+	return settled;
 }
 
 static irqreturn_t sitar_hs_remove_irq(int irq, void *data)
 {
-	short bias_value;
 	struct sitar_priv *priv = data;
 	struct snd_soc_codec *codec = priv->codec;
-	const struct sitar_mbhc_general_cfg *generic =
-	    SITAR_MBHC_CAL_GENERAL_PTR(priv->calibration);
-	int fake_removal = 0;
-	int min_us = SITAR_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
 
 	pr_debug("%s: enter, removal interrupt\n", __func__);
-	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
-	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
-	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE);
 
-	usleep_range(generic->t_shutdown_plug_rem,
-		     generic->t_shutdown_plug_rem);
-
-	do {
-		bias_value = sitar_codec_sta_dce(codec, 1);
-		pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
-			 sitar_codec_sta_dce_v(codec, 1, bias_value), min_us);
-		if (bias_value < (short)priv->mbhc_data.v_ins_h) {
-			fake_removal = 1;
-			break;
-		}
-		min_us -= priv->mbhc_data.t_dce;
-	} while (min_us > 0);
-
-	if (fake_removal) {
-		pr_debug("False alarm, headset not actually removed\n");
+	SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
+	if (sitar_hs_remove_settle(codec))
 		sitar_codec_start_hs_polling(codec);
-	} else {
-		/*
-		 * If this removal is not false, first check the micbias
-		 * switch status and switch it to LDOH if it is already
-		 * switched to VDDIO.
-		 */
-		if (priv->mbhc_micbias_switched)
-			sitar_codec_switch_micbias(codec, 0);
-		priv->hph_status &= ~SND_JACK_HEADSET;
-		if (priv->headset_jack) {
-			pr_err("%s: Reporting removal\n", __func__);
-			sitar_snd_soc_jack_report(priv, priv->headset_jack, 0,
-						 SITAR_JACK_MASK);
-		}
-		sitar_codec_shutdown_hs_polling(codec);
+	pr_debug("%s: remove settle done\n", __func__);
 
-		sitar_codec_enable_hs_detect(codec, 1);
-	}
-
+	SITAR_RELEASE_LOCK(priv->codec_resource_lock);
 	return IRQ_HANDLED;
 }
 
@@ -4015,7 +4512,10 @@
 	sitar->config_mode_active = false;
 	sitar->mbhc_polling_active = false;
 	sitar->no_mic_headset_override = false;
+	mutex_init(&sitar->codec_resource_lock);
 	sitar->codec = codec;
+	sitar->mbhc_state = MBHC_STATE_NONE;
+	sitar->mbhc_last_resume = 0;
 	sitar->pdata = dev_get_platdata(codec->dev->parent);
 	sitar_update_reg_defaults(codec);
 	sitar_codec_init_reg(codec);
@@ -4057,7 +4557,6 @@
 			SITAR_IRQ_MBHC_REMOVAL);
 		goto err_remove_irq;
 	}
-	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
 
 	ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL,
 		sitar_dce_handler, "DC Estimation detect", sitar);
@@ -4066,7 +4565,6 @@
 			SITAR_IRQ_MBHC_POTENTIAL);
 		goto err_potential_irq;
 	}
-	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
 
 	ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE,
 		sitar_release_handler, "Button Release detect", sitar);
@@ -4075,7 +4573,6 @@
 			SITAR_IRQ_MBHC_RELEASE);
 		goto err_release_irq;
 	}
-	wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE);
 
 	ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_SLIMBUS,
 		sitar_slimbus_irq, "SLIMBUS Slave", sitar);
@@ -4151,6 +4648,7 @@
 			SITAR_IRQ_MBHC_INSERTION, sitar);
 err_insert_irq:
 err_pdata:
+	mutex_destroy(&sitar->codec_resource_lock);
 	kfree(sitar);
 	return ret;
 }
@@ -4163,12 +4661,15 @@
 	wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL, sitar);
 	wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL, sitar);
 	wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION, sitar);
+	SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
 	sitar_codec_disable_clock_block(codec);
+	SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
 	sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
 	if (sitar->mbhc_fw)
 		release_firmware(sitar->mbhc_fw);
 	for (i = 0; i < ARRAY_SIZE(sitar_dai); i++)
 		kfree(sitar->dai[i].ch_num);
+	mutex_destroy(&sitar->codec_resource_lock);
 	kfree(sitar);
 	return 0;
 }
@@ -4232,7 +4733,10 @@
 
 static int sitar_resume(struct device *dev)
 {
+	struct platform_device *pdev = to_platform_device(dev);
+	struct sitar_priv *sitar = platform_get_drvdata(pdev);
 	dev_dbg(dev, "%s: system resume\n", __func__);
+	sitar->mbhc_last_resume = jiffies;
 	return 0;
 }
 
diff --git a/sound/soc/codecs/wcd9304.h b/sound/soc/codecs/wcd9304.h
index cfe839b..70b3f0b 100644
--- a/sound/soc/codecs/wcd9304.h
+++ b/sound/soc/codecs/wcd9304.h
@@ -156,12 +156,29 @@
 	u16 _beta[3];
 } __packed;
 
+struct sitar_mbhc_config {
+	struct snd_soc_jack *headset_jack;
+	struct snd_soc_jack *button_jack;
+	bool read_fw_bin;
+	/* void* calibration contains:
+	 *  struct tabla_mbhc_general_cfg generic;
+	 *  struct tabla_mbhc_plug_detect_cfg plug_det;
+	 *  struct tabla_mbhc_plug_type_cfg plug_type;
+	 *  struct tabla_mbhc_btn_detect_cfg btn_det;
+	 *  struct tabla_mbhc_imped_detect_cfg imped_det;
+	 * Note: various size depends on btn_det->num_btn
+	 */
+	void *calibration;
+	enum sitar_micbias_num micbias;
+	int (*mclk_cb_fn) (struct snd_soc_codec*, int, bool);
+	unsigned int mclk_rate;
+	unsigned int gpio;
+	unsigned int gpio_irq;
+	int gpio_level_insert;
+};
+
 extern int sitar_hs_detect(struct snd_soc_codec *codec,
-			   struct snd_soc_jack *headset_jack,
-			   struct snd_soc_jack *button_jack,
-			   void *calibration, enum sitar_micbias_num micbis,
-			   int (*mclk_cb_fn) (struct snd_soc_codec*, int),
-			   int read_fw_bin, u32 mclk_rate);
+			const struct sitar_mbhc_config *cfg);
 
 #ifndef anc_header_dec
 struct anc_header {
@@ -171,7 +188,8 @@
 #define anc_header_dec
 #endif
 
-extern int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable);
+extern int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable,
+							 bool dapm);
 
 extern void *sitar_mbhc_cal_btn_det_mp(const struct sitar_mbhc_btn_detect_cfg
 				       *btn_det,
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index d2f58a5..2d5eab2 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -66,8 +66,9 @@
 #define AIF1_CAP 2
 #define AIF2_PB 3
 #define AIF2_CAP 4
+#define AIF3_CAP 5
 
-#define NUM_CODEC_DAIS 4
+#define NUM_CODEC_DAIS 5
 #define TABLA_COMP_DIGITAL_GAIN_OFFSET 3
 
 struct tabla_codec_dai_data {
@@ -3038,12 +3039,26 @@
 
 	{"SLIM TX3", NULL, "SLIM TX3 MUX"},
 	{"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
+	{"SLIM TX3 MUX", "RMIX1", "RX1 MIX1"},
+	{"SLIM TX3 MUX", "RMIX2", "RX2 MIX1"},
+	{"SLIM TX3 MUX", "RMIX3", "RX3 MIX1"},
+	{"SLIM TX3 MUX", "RMIX4", "RX4 MIX1"},
+	{"SLIM TX3 MUX", "RMIX5", "RX5 MIX1"},
+	{"SLIM TX3 MUX", "RMIX6", "RX6 MIX1"},
+	{"SLIM TX3 MUX", "RMIX7", "RX7 MIX1"},
 
 	{"SLIM TX4", NULL, "SLIM TX4 MUX"},
 	{"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
 
 	{"SLIM TX5", NULL, "SLIM TX5 MUX"},
 	{"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
+	{"SLIM TX5 MUX", "RMIX1", "RX1 MIX1"},
+	{"SLIM TX5 MUX", "RMIX2", "RX2 MIX1"},
+	{"SLIM TX5 MUX", "RMIX3", "RX3 MIX1"},
+	{"SLIM TX5 MUX", "RMIX4", "RX4 MIX1"},
+	{"SLIM TX5 MUX", "RMIX5", "RX5 MIX1"},
+	{"SLIM TX5 MUX", "RMIX6", "RX6 MIX1"},
+	{"SLIM TX5 MUX", "RMIX7", "RX7 MIX1"},
 
 	{"SLIM TX6", NULL, "SLIM TX6 MUX"},
 	{"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
@@ -3059,6 +3074,13 @@
 	{"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
 	{"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
 	{"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
+	{"SLIM TX7 MUX", "RMIX1", "RX1 MIX1"},
+	{"SLIM TX7 MUX", "RMIX2", "RX2 MIX1"},
+	{"SLIM TX7 MUX", "RMIX3", "RX3 MIX1"},
+	{"SLIM TX7 MUX", "RMIX4", "RX4 MIX1"},
+	{"SLIM TX7 MUX", "RMIX5", "RX5 MIX1"},
+	{"SLIM TX7 MUX", "RMIX6", "RX6 MIX1"},
+	{"SLIM TX7 MUX", "RMIX7", "RX7 MIX1"},
 
 	{"SLIM TX8", NULL, "SLIM TX8 MUX"},
 	{"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
@@ -3776,7 +3798,8 @@
 			tabla->dai[dai->id - 1].ch_act = 0;
 			tabla->dai[dai->id - 1].ch_tot = rx_num;
 		}
-	} else if (dai->id == AIF1_CAP || dai->id == AIF2_CAP) {
+	} else if (dai->id == AIF1_CAP || dai->id == AIF2_CAP ||
+		   dai->id == AIF3_CAP) {
 		for (i = 0; i < tx_num; i++) {
 			tabla->dai[dai->id - 1].ch_num[i]  = tx_slot[i];
 			tabla->dai[dai->id - 1].ch_act = 0;
@@ -3828,8 +3851,11 @@
 		*tx_num = tabla_dai[dai->id - 1].capture.channels_max;
 		tx_slot[0] = tx_ch[cnt];
 		tx_slot[1] = tx_ch[1 + cnt];
-		tx_slot[2] = tx_ch[3 + cnt];
-		tx_slot[3] = tx_ch[5 + cnt];
+		tx_slot[2] = tx_ch[5 + cnt];
+	} else if (dai->id == AIF3_CAP) {
+		*tx_num = tabla_dai[dai->id - 1].capture.channels_max;
+		tx_slot[cnt] = tx_ch[2 + cnt];
+		tx_slot[cnt + 1] = tx_ch[4 + cnt];
 	}
 
 	return 0;
@@ -3891,7 +3917,8 @@
 	 * If current dai is a tx dai, set sample rate to
 	 * all the txfe paths that are currently not active
 	 */
-	if ((dai->id == AIF1_CAP) || (dai->id == AIF2_CAP)) {
+	if ((dai->id == AIF1_CAP) || (dai->id == AIF2_CAP) ||
+	    (dai->id == AIF3_CAP)) {
 
 		tx_state = snd_soc_read(codec,
 				TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
@@ -4054,6 +4081,20 @@
 		},
 		.ops = &tabla_dai_ops,
 	},
+	{
+		.name = "tabla_tx3",
+		.id = AIF3_CAP,
+		.capture = {
+			.stream_name = "AIF3 Capture",
+			.rates = WCD9310_RATES,
+			.formats = TABLA_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tabla_dai_ops,
+	},
 };
 
 static struct snd_soc_dai_driver tabla_i2s_dai[] = {
@@ -4104,7 +4145,8 @@
 	case SND_SOC_DAPM_POST_PMU:
 		for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
 			if ((tabla_dai[j].id == AIF1_CAP) ||
-			    (tabla_dai[j].id == AIF2_CAP))
+			    (tabla_dai[j].id == AIF2_CAP) ||
+			    (tabla_dai[j].id == AIF3_CAP))
 				continue;
 			if (!strncmp(w->sname,
 				tabla_dai[j].playback.stream_name, 13)) {
@@ -4121,7 +4163,8 @@
 	case SND_SOC_DAPM_POST_PMD:
 		for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
 			if ((tabla_dai[j].id == AIF1_CAP) ||
-			    (tabla_dai[j].id == AIF2_CAP))
+			    (tabla_dai[j].id == AIF2_CAP) ||
+			    (tabla_dai[j].id == AIF3_CAP))
 				continue;
 			if (!strncmp(w->sname,
 				tabla_dai[j].playback.stream_name, 13)) {
@@ -4521,17 +4564,17 @@
 				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, 0, 0, &sb_tx3_mux),
-	SND_SOC_DAPM_AIF_OUT_E("SLIM TX3", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+	SND_SOC_DAPM_AIF_OUT_E("SLIM TX3", "AIF3 Capture", 0, SND_SOC_NOPM, 0,
 				0, tabla_codec_enable_slimtx,
 				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, 0, 0, &sb_tx4_mux),
-	SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
+	SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
 				0, tabla_codec_enable_slimtx,
 				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
-	SND_SOC_DAPM_AIF_OUT_E("SLIM TX5", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+	SND_SOC_DAPM_AIF_OUT_E("SLIM TX5", "AIF3 Capture", 0, SND_SOC_NOPM, 0,
 				0, tabla_codec_enable_slimtx,
 				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
@@ -7406,6 +7449,9 @@
 		case AIF2_CAP:
 			ch_cnt = tabla_dai[i].capture.channels_max;
 			break;
+		case AIF3_CAP:
+			ch_cnt = tabla_dai[i].capture.channels_max;
+			break;
 		default:
 			continue;
 		}
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index 3d489ff..c8ef419 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -62,7 +62,9 @@
 enum {
 	SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
 	SLIM_1_TX_1 = 146, /* BT-SCO and USB RX */
-	SLIM_2_RX_1 = 147, /* HDMI RX */
+	SLIM_3_RX_1 = 151, /* External echo-cancellation ref */
+	SLIM_3_RX_2 = 152, /* External echo-cancellation ref */
+	SLIM_3_TX_1 = 147, /* HDMI RX */
 	SLIM_4_TX_1 = 148, /* In-call recording RX */
 	SLIM_4_TX_2 = 149, /* In-call recording RX */
 	SLIM_4_RX_1 = 150, /* In-call music delivery TX */
@@ -80,6 +82,7 @@
 static int msm_ext_top_spk_pamp;
 static int msm_slim_0_rx_ch = 1;
 static int msm_slim_0_tx_ch = 1;
+static int msm_slim_3_rx_ch = 1;
 
 static int msm_btsco_rate = BTSCO_RATE_8KHZ;
 static int msm_btsco_ch = 1;
@@ -343,7 +346,7 @@
 
 		if (codec_clk) {
 			clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
-			clk_enable(codec_clk);
+			clk_prepare_enable(codec_clk);
 			tabla_mclk_enable(codec, 1, dapm);
 		} else {
 			pr_err("%s: Error setting Tabla MCLK\n", __func__);
@@ -359,7 +362,7 @@
 			pr_debug("%s: disabling MCLK. clk_users = %d\n",
 					 __func__, clk_users);
 			tabla_mclk_enable(codec, 0, dapm);
-			clk_disable(codec_clk);
+			clk_disable_unprepare(codec_clk);
 		}
 	}
 	return 0;
@@ -381,7 +384,7 @@
 
 		if (codec_clk) {
 			clk_set_rate(codec_clk, 12288000);
-			clk_enable(codec_clk);
+			clk_prepare_enable(codec_clk);
 			tabla_mclk_enable(w->codec, 1, true);
 
 		} else {
@@ -404,7 +407,7 @@
 					__func__, clk_users);
 
 			tabla_mclk_enable(w->codec, 0, true);
-			clk_disable(codec_clk);
+			clk_disable_unprepare(codec_clk);
 		}
 		break;
 	}
@@ -442,7 +445,7 @@
 	SND_SOC_DAPM_MIC("Digital Mic6", NULL),
 };
 
-static const struct snd_soc_dapm_route apq8064_audio_map[] = {
+static const struct snd_soc_dapm_route apq8064_common_audio_map[] = {
 
 	{"RX_BIAS", NULL, "MCLK"},
 	{"LDO_H", NULL, "MCLK"},
@@ -457,13 +460,6 @@
 	{"Ext Spk Top Neg", NULL, "LINEOUT4"},
 
 	/************   Analog MIC Paths  ************/
-	/**
-	 * Analog mic7 (Front Top Mic) on Liquid.
-	 * Used as Handset mic on CDP.
-	 * Not there on MTP.
-	 */
-	{"AMIC1", NULL, "MIC BIAS1 External"},
-	{"MIC BIAS1 External", NULL, "Analog mic7"},
 
 	/* Headset Mic */
 	{"AMIC2", NULL, "MIC BIAS2 External"},
@@ -475,6 +471,59 @@
 
 	{"AMIC4", NULL, "MIC BIAS1 Internal2"},
 	{"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
+};
+
+static const struct snd_soc_dapm_route apq8064_mtp_audio_map[] = {
+
+	/************   Digital MIC Paths  ************/
+
+	/*
+	 * Digital Mic1 (Front bottom Left) on MTP.
+	 * Conncted to DMIC1 Input on Tabla codec.
+	 */
+	{"DMIC1", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic1"},
+
+	/**
+	 * Digital Mic2 (Front bottom right) on MTP.
+	 * Conncted to DMIC2 Input on Tabla codec.
+	 */
+	{"DMIC2", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Digital Mic2"},
+
+	/**
+	 * Digital Mic3 (Back bottom) on MTP.
+	 * Conncted to DMIC3 Input on Tabla codec.
+	 */
+	{"DMIC3", NULL, "MIC BIAS3 External"},
+	{"MIC BIAS3 External", NULL, "Digital Mic3"},
+
+	/**
+	 * Digital Mic4 (Back top) on MTP.
+	 * Conncted to DMIC4 Input on Tabla codec.
+	 */
+	{"DMIC4", NULL, "MIC BIAS3 External"},
+	{"MIC BIAS3 External", NULL, "Digital Mic4"},
+
+	/**
+	 * Digital Mic5 (Top front Mic) on MTP.
+	 * Conncted to DMIC6 Input on Tabla codec.
+	 */
+	{"DMIC6", NULL, "MIC BIAS4 External"},
+	{"MIC BIAS4 External", NULL, "Digital Mic5"},
+
+};
+
+static const struct snd_soc_dapm_route apq8064_liquid_cdp_audio_map[] = {
+
+	/************   Analog MIC Paths  ************/
+	/**
+	 * Analog mic7 (Front Top Mic) on Liquid.
+	 * Used as Handset mic on CDP.
+	 * Not there on MTP.
+	 */
+	{"AMIC1", NULL, "MIC BIAS1 External"},
+	{"MIC BIAS1 External", NULL, "Analog mic7"},
 
 
 	/************   Digital MIC Paths  ************/
@@ -590,6 +639,25 @@
 	return 1;
 }
 
+static int msm_slim_3_rx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_slim_3_rx_ch  = %d\n", __func__,
+			msm_slim_3_rx_ch);
+	ucontrol->value.integer.value[0] = msm_slim_3_rx_ch - 1;
+	return 0;
+}
+
+static int msm_slim_3_rx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_slim_3_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_slim_3_rx_ch = %d\n", __func__,
+			msm_slim_3_rx_ch);
+	return 1;
+}
+
 static int msm_btsco_rate_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -667,6 +735,24 @@
 	return 0;
 }
 
+static const struct snd_kcontrol_new slim_3_mixer_controls[] = {
+	SOC_ENUM_EXT("SLIM_3_RX Channels", msm_enum[1],
+		msm_slim_3_rx_ch_get, msm_slim_3_rx_ch_put),
+};
+
+static int msm_slim_3_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int err = 0;
+	struct snd_soc_platform *platform = rtd->platform;
+
+	err = snd_soc_add_platform_controls(platform,
+			slim_3_mixer_controls,
+		ARRAY_SIZE(slim_3_mixer_controls));
+	if (err < 0)
+		return err;
+	return 0;
+}
+
 static int msm_incall_rec_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int err = 0;
@@ -799,6 +885,13 @@
 			user_set_tx_ch =  msm_slim_0_tx_ch;
 		else if (codec_dai->id  == 4)
 			user_set_tx_ch =  params_channels(params);
+		else if (codec_dai->id == 5) {
+			/* DAI 5 is used for external EC reference from codec.
+			 * Since Rx is fed as reference for EC, the config of
+			 * this DAI is based on that of the Rx path.
+			 */
+			user_set_tx_ch =  msm_slim_0_rx_ch;
+		}
 
 		pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
 			codec_dai->name, codec_dai->id, user_set_tx_ch);
@@ -873,6 +966,35 @@
 	return ret;
 }
 
+static int msm_slimbus_3_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+	unsigned int rx_ch[2] = {SLIM_3_RX_1, SLIM_3_RX_2};
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		pr_debug("%s: slim_3_rx_ch %d, sch %d %d\n",
+			 __func__, msm_slim_3_rx_ch,
+				 rx_ch[0], rx_ch[1]);
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+				msm_slim_3_rx_ch, rx_ch);
+		if (ret < 0) {
+			pr_err("%s: Erorr %d setting SLIM_3 RX channel map\n",
+				__func__, ret);
+
+			goto end;
+		}
+	} else {
+		pr_err("%s: SLIMBUS_3_TX not defined for this DAI\n", __func__);
+	}
+
+end:
+	return ret;
+}
+
 static int msm_slimbus_4_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params)
 {
@@ -940,8 +1062,16 @@
 	snd_soc_dapm_new_controls(dapm, apq8064_dapm_widgets,
 				ARRAY_SIZE(apq8064_dapm_widgets));
 
-	snd_soc_dapm_add_routes(dapm, apq8064_audio_map,
-		ARRAY_SIZE(apq8064_audio_map));
+	snd_soc_dapm_add_routes(dapm, apq8064_common_audio_map,
+		ARRAY_SIZE(apq8064_common_audio_map));
+
+	if (machine_is_apq8064_mtp()) {
+		snd_soc_dapm_add_routes(dapm, apq8064_mtp_audio_map,
+			ARRAY_SIZE(apq8064_mtp_audio_map));
+	} else  {
+		snd_soc_dapm_add_routes(dapm, apq8064_liquid_cdp_audio_map,
+			ARRAY_SIZE(apq8064_liquid_cdp_audio_map));
+	}
 
 	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
 	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
@@ -1039,6 +1169,22 @@
 	return 0;
 }
 
+static int msm_slim_3_rx_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);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_slim_3_rx_ch;
+
+	return 0;
+}
+
 static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 			struct snd_pcm_hw_params *params)
 {
@@ -1203,6 +1349,12 @@
 	.shutdown = msm_shutdown,
 };
 
+static struct snd_soc_ops msm_slimbus_3_be_ops = {
+	.startup = msm_startup,
+	.hw_params = msm_slimbus_3_hw_params,
+	.shutdown = msm_shutdown,
+};
+
 static struct snd_soc_ops msm_slimbus_4_be_ops = {
 	.startup = msm_startup,
 	.hw_params = msm_slimbus_4_hw_params,
@@ -1451,7 +1603,7 @@
 		.codec_name = "tabla_codec",
 		.codec_dai_name = "tabla_rx2",
 		.no_pcm = 1,
-		/* .be_id = do not care */
+		.be_id = MSM_BACKEND_DAI_EXTPROC_RX,
 		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
 		.init = &msm_stubrx_init,
 		.ops = &msm_be_ops,
@@ -1464,7 +1616,7 @@
 		.codec_name = "tabla_codec",
 		.codec_dai_name = "tabla_tx1",
 		.no_pcm = 1,
-		/* .be_id = do not care */
+		.be_id = MSM_BACKEND_DAI_EXTPROC_TX,
 		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
 		.ops = &msm_be_ops,
 	},
@@ -1500,6 +1652,7 @@
 		.platform_name = "msm-pcm-hostless",
 		.codec_name = "tabla_codec",
 		.codec_dai_name = "tabla_tx2",
+		.ignore_suspend = 1,
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ops = &msm_be_ops,
 	},
@@ -1533,6 +1686,36 @@
 		.init = &msm_incall_rec_init,
 		.ops = &msm_slimbus_4_be_ops,
 	},
+	{
+		.name = LPASS_BE_STUB_1_TX,
+		.stream_name = "Stub1 Capture",
+		.cpu_dai_name = "msm-dai-stub",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "tabla_codec",
+		.codec_dai_name	= "tabla_tx3",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_EXTPROC_EC_TX,
+		/* This BE is used for external EC reference from codec. Since
+		 * Rx is fed as reference for EC, the config of this DAI is
+		 * based on that of the Rx path.
+		 */
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm_be_ops,
+	},
+	{
+
+		.name = LPASS_BE_SLIMBUS_3_RX,
+		.stream_name = "Slimbus3 Playback",
+		.cpu_dai_name = "msm-dai-q6.16390",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.init = &msm_slim_3_init,
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+		.be_hw_params_fixup = msm_slim_3_rx_be_hw_params_fixup,
+		.ops = &msm_slimbus_3_be_ops,
+	},
 };
 
 struct snd_soc_card snd_soc_card_msm = {
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index 760f13d..f02a7ef 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -321,7 +321,7 @@
 
 		if (codec_clk) {
 			clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
-			clk_enable(codec_clk);
+			clk_prepare_enable(codec_clk);
 			tabla_mclk_enable(codec, 1, dapm);
 		} else {
 			pr_err("%s: Error setting Tabla MCLK\n", __func__);
@@ -337,7 +337,7 @@
 			pr_debug("%s: disabling MCLK. clk_users = %d\n",
 					 __func__, clk_users);
 			tabla_mclk_enable(codec, 0, dapm);
-			clk_disable(codec_clk);
+			clk_disable_unprepare(codec_clk);
 		}
 	}
 	return 0;
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index ea05a58e..50f527f 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -134,6 +134,7 @@
 static int msm_ext_top_spk_pamp;
 static int msm_slim_0_rx_ch = 1;
 static int msm_slim_0_tx_ch = 1;
+static int msm_hdmi_rx_ch = 2;
 
 static struct clk *codec_clk;
 static int clk_users;
@@ -392,7 +393,7 @@
 
 		if (codec_clk) {
 			clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
-			clk_enable(codec_clk);
+			clk_prepare_enable(codec_clk);
 			tabla_mclk_enable(codec, 1, dapm);
 		} else {
 			pr_err("%s: Error setting Tabla MCLK\n", __func__);
@@ -407,7 +408,7 @@
 		if (!clk_users) {
 			pr_debug("%s: disabling MCLK. clk_users = %d\n",
 					 __func__, clk_users);
-			clk_disable(codec_clk);
+			clk_disable_unprepare(codec_clk);
 			tabla_mclk_enable(codec, 0, dapm);
 		}
 	}
@@ -430,7 +431,7 @@
 
 		if (codec_clk) {
 			clk_set_rate(codec_clk, 12288000);
-			clk_enable(codec_clk);
+			clk_prepare_enable(codec_clk);
 			tabla_mclk_enable(w->codec, 1, true);
 
 		} else {
@@ -452,7 +453,7 @@
 			pr_debug("%s: disabling MCLK. clk_users = %d\n",
 					__func__, clk_users);
 
-			clk_disable(codec_clk);
+			clk_disable_unprepare(codec_clk);
 			tabla_mclk_enable(w->codec, 0, true);
 		}
 		break;
@@ -515,11 +516,15 @@
 static const char *spk_function[] = {"Off", "On"};
 static const char *slim0_rx_ch_text[] = {"One", "Two"};
 static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
+static const char *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five", "Six"};
+
 
 static const struct soc_enum msm_enum[] = {
 	SOC_ENUM_SINGLE_EXT(2, spk_function),
 	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
 	SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
+	SOC_ENUM_SINGLE_EXT(5, hdmi_rx_ch_text),
+
 };
 
 static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
@@ -560,6 +565,26 @@
 	return 1;
 }
 
+static int msm_hdmi_rx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_hdmi_rx_ch  = %d\n", __func__,
+			msm_hdmi_rx_ch);
+	ucontrol->value.integer.value[0] = msm_hdmi_rx_ch - 2;
+	return 0;
+}
+
+static int msm_hdmi_rx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_hdmi_rx_ch = ucontrol->value.integer.value[0] + 2;
+
+	pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__,
+		msm_hdmi_rx_ch);
+	return 1;
+}
+
+
 static const struct snd_kcontrol_new tabla_msm_controls[] = {
 	SOC_ENUM_EXT("Speaker Function", msm_enum[0], msm_get_spk,
 		msm_set_spk),
@@ -567,6 +592,9 @@
 		msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
 	SOC_ENUM_EXT("SLIM_0_TX Channels", msm_enum[2],
 		msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
+	SOC_ENUM_EXT("HDMI_RX Channels", msm_enum[3],
+		msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put),
+
 };
 
 static void *def_tabla_mbhc_cal(void)
@@ -861,6 +889,7 @@
 			channels->min, channels->max);
 
 	rate->min = rate->max = 48000;
+	channels->min =  channels->max = msm_hdmi_rx_ch;
 
 	return 0;
 }
@@ -985,12 +1014,12 @@
 {
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		if (sec_i2s_rx_bit_clk) {
-			clk_disable(sec_i2s_rx_bit_clk);
+			clk_disable_unprepare(sec_i2s_rx_bit_clk);
 			clk_put(sec_i2s_rx_bit_clk);
 			sec_i2s_rx_bit_clk = NULL;
 		}
 		if (sec_i2s_rx_osr_clk) {
-			clk_disable(sec_i2s_rx_osr_clk);
+			clk_disable_unprepare(sec_i2s_rx_osr_clk);
 			clk_put(sec_i2s_rx_osr_clk);
 			sec_i2s_rx_osr_clk = NULL;
 		}
@@ -1040,20 +1069,20 @@
 			return PTR_ERR(sec_i2s_rx_osr_clk);
 		}
 		clk_set_rate(sec_i2s_rx_osr_clk, I2S_MCLK_RATE);
-		clk_enable(sec_i2s_rx_osr_clk);
+		clk_prepare_enable(sec_i2s_rx_osr_clk);
 		sec_i2s_rx_bit_clk = clk_get(cpu_dai->dev, "bit_clk");
 		if (IS_ERR(sec_i2s_rx_bit_clk)) {
 			pr_err("Failed to get sec i2s osr_clk\n");
-			clk_disable(sec_i2s_rx_osr_clk);
+			clk_disable_unprepare(sec_i2s_rx_osr_clk);
 			clk_put(sec_i2s_rx_osr_clk);
 			return PTR_ERR(sec_i2s_rx_bit_clk);
 		}
 		clk_set_rate(sec_i2s_rx_bit_clk, 1);
-		ret = clk_enable(sec_i2s_rx_bit_clk);
+		ret = clk_prepare_enable(sec_i2s_rx_bit_clk);
 		if (ret != 0) {
 			pr_err("Unable to enable sec i2s rx_bit_clk\n");
 			clk_put(sec_i2s_rx_bit_clk);
-			clk_disable(sec_i2s_rx_osr_clk);
+			clk_disable_unprepare(sec_i2s_rx_osr_clk);
 			clk_put(sec_i2s_rx_osr_clk);
 			return ret;
 		}
@@ -1095,7 +1124,7 @@
 		.name = "MSM8960 Media2",
 		.stream_name = "MultiMedia2",
 		.cpu_dai_name	= "MultiMedia2",
-		.platform_name  = "msm-pcm-dsp",
+		.platform_name  = "msm-multi-ch-pcm-dsp",
 		.dynamic = 1,
 		.dsp_link = &fe_media,
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
@@ -1302,7 +1331,7 @@
 	{
 		.name = LPASS_BE_MI2S_TX,
 		.stream_name = "MI2S Capture",
-		.cpu_dai_name = "msm-dai-q6.7",
+		.cpu_dai_name = "msm-dai-q6-mi2s",
 		.platform_name = "msm-pcm-routing",
 		.codec_name     = "msm-stub-codec.1",
 		.codec_dai_name = "msm-stub-tx",
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index cb760fa..776337d 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -49,7 +49,7 @@
 				SNDRV_PCM_INFO_INTERLEAVED |
 				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
 	.formats =	      SNDRV_PCM_FMTBIT_S16_LE,
-	.rates =		SNDRV_PCM_RATE_8000_48000,
+	.rates =		SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
 	.rate_min =	     8000,
 	.rate_max =	     48000,
 	.channels_min =	 1,
@@ -191,6 +191,7 @@
 	struct compr_audio *compr = runtime->private_data;
 	struct msm_audio *prtd = &compr->prtd;
 	struct asm_aac_cfg aac_cfg;
+	struct asm_wma_cfg wma_cfg;
 	int ret;
 
 	pr_debug("compressed stream prepare\n");
@@ -219,7 +220,7 @@
 		aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
 		aac_cfg.format = 0x03;
 		aac_cfg.ch_cfg = runtime->channels;
-		aac_cfg.sample_rate =  runtime->rate;
+		aac_cfg.sample_rate = runtime->rate;
 		ret = q6asm_media_format_block_aac(prtd->audio_client,
 					&aac_cfg);
 		if (ret < 0)
@@ -229,6 +230,26 @@
 		pr_debug("compressd playback, no need to send"
 			" the decoder params\n");
 		break;
+	case SND_AUDIOCODEC_WMA:
+		pr_debug("SND_AUDIOCODEC_WMA\n");
+		memset(&wma_cfg, 0x0, sizeof(struct asm_wma_cfg));
+		wma_cfg.format_tag = compr->info.codec_param.codec.format;
+		wma_cfg.ch_cfg = runtime->channels;
+		wma_cfg.sample_rate = runtime->rate;
+		wma_cfg.avg_bytes_per_sec =
+			compr->info.codec_param.codec.bit_rate/8;
+		wma_cfg.block_align = compr->info.codec_param.codec.align;
+		wma_cfg.valid_bits_per_sample =
+		compr->info.codec_param.codec.options.wma.bits_per_sample;
+		wma_cfg.ch_mask =
+			compr->info.codec_param.codec.options.wma.channelmask;
+		wma_cfg.encode_opt =
+			compr->info.codec_param.codec.options.wma.encodeopt;
+		ret = q6asm_media_format_block_wma(prtd->audio_client,
+					&wma_cfg);
+		if (ret < 0)
+			pr_err("%s: CMD Format block failed\n", __func__);
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -294,6 +315,7 @@
 	compr->info.compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
 	compr->info.compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
 	compr->info.compr_cap.codecs[2] = SND_AUDIOCODEC_AC3_PASS_THROUGH;
+	compr->info.compr_cap.codecs[3] = SND_AUDIOCODEC_WMA;
 	/* Add new codecs here */
 }
 
@@ -612,6 +634,10 @@
 			pr_debug("SND_AUDIOCODEC_AC3_PASS_THROUGH\n");
 			compr->codec = FORMAT_AC3;
 			break;
+		case SND_AUDIOCODEC_WMA:
+			pr_debug("SND_AUDIOCODEC_WMA\n");
+			compr->codec = FORMAT_WMA_V9;
+			break;
 		default:
 			pr_debug("FORMAT_LINEAR_PCM\n");
 			compr->codec = FORMAT_LINEAR_PCM;
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 23134ea..6c44cba 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -50,7 +50,8 @@
 	{
 		.playback = {
 			.stream_name = "Multimedia1 Playback",
-			.rates = SNDRV_PCM_RATE_8000_48000,
+			.rates = (SNDRV_PCM_RATE_8000_48000|
+					SNDRV_PCM_RATE_KNOT),
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 			.channels_min = 1,
 			.channels_max = 2,
@@ -59,20 +60,22 @@
 		},
 		.capture = {
 			.stream_name = "Multimedia1 Capture",
-			.rates = SNDRV_PCM_RATE_8000_48000,
+			.rates = (SNDRV_PCM_RATE_8000_48000|
+					SNDRV_PCM_RATE_KNOT),
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 			.channels_min = 1,
 			.channels_max = 4,
 			.rate_min =     8000,
 			.rate_max =	48000,
 		},
-		.ops = &msm_fe_dai_ops,
+		.ops = &msm_fe_Multimedia_dai_ops,
 		.name = "MultiMedia1",
 	},
 	{
 		.playback = {
 			.stream_name = "Multimedia2 Playback",
-			.rates = SNDRV_PCM_RATE_8000_48000,
+			.rates = (SNDRV_PCM_RATE_8000_48000|
+					SNDRV_PCM_RATE_KNOT),
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 			.channels_min = 1,
 			.channels_max = 6,
@@ -81,14 +84,15 @@
 		},
 		.capture = {
 			.stream_name = "Multimedia2 Capture",
-			.rates = SNDRV_PCM_RATE_8000_48000,
+			.rates = (SNDRV_PCM_RATE_8000_48000|
+					SNDRV_PCM_RATE_KNOT),
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 			.channels_min = 1,
 			.channels_max = 2,
 			.rate_min =     8000,
 			.rate_max =	48000,
 		},
-		.ops = &msm_fe_dai_ops,
+		.ops = &msm_fe_Multimedia_dai_ops,
 		.name = "MultiMedia2",
 	},
 	{
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index c1304c8..fb7756c 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -36,9 +36,17 @@
 	DECLARE_BITMAP(status_mask, STATUS_MAX);
 	u32 rate;
 	u32 channels;
+	u32 bitwidth;
 	union afe_port_config port_config;
 };
 
+struct msm_dai_q6_mi2s_dai_data {
+	struct msm_dai_q6_dai_data tx_dai;
+	struct msm_dai_q6_dai_data rx_dai;
+	struct snd_pcm_hw_constraint_list rate_constraint;
+	struct snd_pcm_hw_constraint_list bitwidth_constraint;
+};
+
 static struct clk *pcm_clk;
 static DEFINE_MUTEX(aux_pcm_mutex);
 static int aux_pcm_count;
@@ -106,6 +114,316 @@
 	return num_bits_set;
 }
 
+static int msm_dai_q6_mi2s_startup(struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+		dev_get_drvdata(dai->dev);
+
+	dev_dbg(dai->dev, "%s: cnst list %p\n", __func__,
+		mi2s_dai_data->rate_constraint.list);
+
+	if (mi2s_dai_data->rate_constraint.list) {
+		snd_pcm_hw_constraint_list(substream->runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE,
+				&mi2s_dai_data->rate_constraint);
+		snd_pcm_hw_constraint_list(substream->runtime, 0,
+				SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+				&mi2s_dai_data->bitwidth_constraint);
+	}
+
+	return 0;
+}
+
+static int msm_dai_q6_mi2s_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+		dev_get_drvdata(dai->dev);
+	struct msm_dai_q6_dai_data *dai_data =
+		(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+		&mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
+
+	dai_data->channels = params_channels(params);
+	switch (dai_data->channels) {
+	case 2:
+		dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
+		break;
+	case 1:
+		dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
+		break;
+	default:
+		pr_warn("greater than stereo has not been validated");
+		break;
+	}
+	dai_data->rate = params_rate(params);
+	dai_data->port_config.mi2s.bitwidth = 16;
+	dai_data->bitwidth = 16;
+	if (!mi2s_dai_data->rate_constraint.list) {
+		mi2s_dai_data->rate_constraint.list = &dai_data->rate;
+		mi2s_dai_data->bitwidth_constraint.list = &dai_data->bitwidth;
+	}
+	return 0;
+}
+
+static int msm_dai_q6_mi2s_get_lineconfig(u16 sd_lines, u16 *config_ptr,
+	unsigned int *ch_cnt)
+{
+	u8 num_of_sd_lines;
+
+	num_of_sd_lines = num_of_bits_set(sd_lines);
+
+	switch (num_of_sd_lines) {
+	case 0:
+		pr_debug("%s: no line is assigned\n", __func__);
+		break;
+	case 1:
+		switch (sd_lines) {
+		case MSM_MI2S_SD0:
+			*config_ptr = AFE_I2S_SD0;
+			break;
+		case MSM_MI2S_SD1:
+			*config_ptr = AFE_I2S_SD1;
+			break;
+		case MSM_MI2S_SD2:
+			*config_ptr = AFE_I2S_SD2;
+			break;
+		case MSM_MI2S_SD3:
+			*config_ptr = AFE_I2S_SD3;
+			break;
+		default:
+			pr_err("%s: invalid SD line\n",
+				   __func__);
+			goto error_invalid_data;
+		}
+		break;
+	case 2:
+		switch (sd_lines) {
+		case MSM_MI2S_SD0 | MSM_MI2S_SD1:
+			*config_ptr = AFE_I2S_QUAD01;
+			break;
+		case MSM_MI2S_SD2 | MSM_MI2S_SD3:
+			*config_ptr = AFE_I2S_QUAD23;
+			break;
+		default:
+			pr_err("%s: invalid SD line\n",
+				   __func__);
+			goto error_invalid_data;
+		}
+		break;
+	case 3:
+		switch (sd_lines) {
+		case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2:
+			*config_ptr = AFE_I2S_6CHS;
+			break;
+		default:
+			pr_err("%s: invalid SD lines\n",
+				   __func__);
+			goto error_invalid_data;
+		}
+		break;
+	case 4:
+		switch (sd_lines) {
+		case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 | MSM_MI2S_SD3:
+			*config_ptr = AFE_I2S_8CHS;
+			break;
+		default:
+			pr_err("%s: invalid SD lines\n",
+				   __func__);
+			goto error_invalid_data;
+		}
+		break;
+	default:
+		pr_err("%s: invalid SD lines\n", __func__);
+		goto error_invalid_data;
+	}
+
+	*ch_cnt = num_of_sd_lines;
+
+	return 0;
+
+error_invalid_data:
+	return -EINVAL;
+}
+
+static int msm_dai_q6_mi2s_platform_data_validation(
+	struct platform_device *pdev, struct snd_soc_dai_driver *dai_driver)
+{
+	struct msm_dai_q6_mi2s_dai_data *dai_data = dev_get_drvdata(&pdev->dev);
+	struct msm_mi2s_pdata *mi2s_pdata =
+			(struct msm_mi2s_pdata *) pdev->dev.platform_data;
+	u16 sdline_config;
+	unsigned int ch_cnt;
+	int rc = 0;
+
+	if ((mi2s_pdata->rx_sd_lines & mi2s_pdata->tx_sd_lines) ||
+	    (!mi2s_pdata->rx_sd_lines && !mi2s_pdata->tx_sd_lines)) {
+		dev_err(&pdev->dev,
+			"error sd line conflict or no line assigned\n");
+		rc = -EINVAL;
+		goto rtn;
+	}
+
+	rc = msm_dai_q6_mi2s_get_lineconfig(mi2s_pdata->rx_sd_lines,
+					    &sdline_config, &ch_cnt);
+
+	if (IS_ERR_VALUE(rc)) {
+		dev_err(&pdev->dev, "invalid MI2S RX sd line config\n");
+		goto rtn;
+	}
+
+	if (ch_cnt) {
+		dai_data->rx_dai.port_config.mi2s.line = sdline_config;
+		dai_driver->playback.channels_min = 1;
+		dai_driver->playback.channels_max = ch_cnt << 1;
+	} else {
+		dai_driver->playback.channels_min = 0;
+		dai_driver->playback.channels_max = 0;
+	}
+	rc = msm_dai_q6_mi2s_get_lineconfig(mi2s_pdata->tx_sd_lines,
+					    &sdline_config, &ch_cnt);
+
+	if (IS_ERR_VALUE(rc)) {
+		dev_err(&pdev->dev, "invalid MI2S TX sd line config\n");
+		goto rtn;
+	}
+
+	if (ch_cnt) {
+		dai_data->tx_dai.port_config.mi2s.line = sdline_config;
+		dai_driver->capture.channels_min = 1;
+		dai_driver->capture.channels_max = ch_cnt << 1;
+	} else {
+		dai_driver->capture.channels_min = 0;
+		dai_driver->capture.channels_max = 0;
+	}
+
+	dev_info(&pdev->dev, "%s: playback sdline %x capture sdline %x\n",
+		 __func__, dai_data->rx_dai.port_config.mi2s.line,
+		 dai_data->tx_dai.port_config.mi2s.line);
+	dev_info(&pdev->dev, "%s: playback ch_max %d capture ch_mx %d\n",
+		 __func__, dai_driver->playback.channels_max,
+		 dai_driver->capture.channels_max);
+rtn:
+	return rc;
+}
+
+static int msm_dai_q6_mi2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+	dev_get_drvdata(dai->dev);
+
+	if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask) ||
+	    test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask)) {
+		dev_err(dai->dev, "%s: err chg i2s mode while dai running",
+			__func__);
+		return -EPERM;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		mi2s_dai_data->rx_dai.port_config.mi2s.ws = 1;
+		mi2s_dai_data->tx_dai.port_config.mi2s.ws = 1;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		mi2s_dai_data->rx_dai.port_config.mi2s.ws = 0;
+		mi2s_dai_data->tx_dai.port_config.mi2s.ws = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int msm_dai_q6_mi2s_prepare(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+		dev_get_drvdata(dai->dev);
+	struct msm_dai_q6_dai_data *dai_data =
+		(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+		&mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
+	int rc = 0;
+
+	if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+		/* PORT START should be set if prepare called in active state */
+		rc = afe_q6_interface_prepare();
+		if (IS_ERR_VALUE(rc))
+			dev_err(dai->dev, "fail to open AFE APR\n");
+	}
+	return rc;
+}
+
+static int msm_dai_q6_mi2s_trigger(struct snd_pcm_substream *substream, int cmd,
+		struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+		dev_get_drvdata(dai->dev);
+	struct msm_dai_q6_dai_data *dai_data =
+		(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+		&mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
+	u16 port_id = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+		MI2S_RX : MI2S_TX);
+	int rc = 0;
+
+	dev_dbg(dai->dev, "%s: cmd:%d dai_data->status_mask = %ld",
+		__func__, cmd, *dai_data->status_mask);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+			afe_port_start_nowait(port_id,
+				&dai_data->port_config, dai_data->rate);
+			set_bit(STATUS_PORT_STARTED,
+				dai_data->status_mask);
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+			afe_port_stop_nowait(port_id);
+			clear_bit(STATUS_PORT_STARTED,
+				dai_data->status_mask);
+		}
+		break;
+
+	default:
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static void msm_dai_q6_mi2s_shutdown(struct snd_pcm_substream *substream,
+				     struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+		dev_get_drvdata(dai->dev);
+	struct msm_dai_q6_dai_data *dai_data =
+		(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+		&mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
+	u16 port_id = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+		MI2S_RX : MI2S_TX);
+	int rc = 0;
+
+	if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+		rc = afe_close(port_id);
+		if (IS_ERR_VALUE(rc))
+			dev_err(dai->dev, "fail to close AFE port\n");
+		clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
+	}
+
+	if (!test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask) &&
+	    !test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask)) {
+		mi2s_dai_data->rate_constraint.list = NULL;
+		mi2s_dai_data->bitwidth_constraint.list = NULL;
+	}
+
+}
+
 static int msm_dai_q6_cdc_hw_params(struct snd_pcm_hw_params *params,
 				    struct snd_soc_dai *dai, int stream)
 {
@@ -134,121 +452,6 @@
 	return 0;
 }
 
-static int msm_dai_q6_mi2s_hw_params(struct snd_pcm_hw_params *params,
-				    struct snd_soc_dai *dai, int stream)
-{
-	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
-	struct msm_mi2s_data *mi2s_pdata =
-			(struct msm_mi2s_data *) dai->dev->platform_data;
-
-	dai_data->channels = params_channels(params);
-	if (num_of_bits_set(mi2s_pdata->sd_lines) == 1) {
-		switch (dai_data->channels) {
-		case 2:
-			dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
-			break;
-		case 1:
-			dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
-			break;
-		default:
-			pr_warn("greater than stereo has not been validated");
-			break;
-		}
-	}
-	dai_data->rate = params_rate(params);
-	/* Q6 only supports 16 as now */
-	dai_data->port_config.mi2s.bitwidth = 16;
-
-	pr_debug("%s: format = %d, channel = %d, line = %d\n",
-		   __func__, dai_data->port_config.mi2s.format,
-		   dai_data->port_config.mi2s.channel,
-		   dai_data->port_config.mi2s.line);
-	return 0;
-}
-
-static int msm_dai_q6_mi2s_platform_data_validation(
-					struct snd_soc_dai *dai)
-{
-	u8 num_of_sd_lines;
-	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
-	struct msm_mi2s_data *mi2s_pdata =
-			(struct msm_mi2s_data *)dai->dev->platform_data;
-	struct snd_soc_dai_driver *dai_driver =
-			(struct snd_soc_dai_driver *)dai->driver;
-
-	num_of_sd_lines = num_of_bits_set(mi2s_pdata->sd_lines);
-
-	switch (num_of_sd_lines) {
-	case 1:
-		switch (mi2s_pdata->sd_lines) {
-		case MSM_MI2S_SD0:
-			dai_data->port_config.mi2s.line = AFE_I2S_SD0;
-			break;
-		case MSM_MI2S_SD1:
-			dai_data->port_config.mi2s.line = AFE_I2S_SD1;
-			break;
-		case MSM_MI2S_SD2:
-			dai_data->port_config.mi2s.line = AFE_I2S_SD2;
-			break;
-		case MSM_MI2S_SD3:
-			dai_data->port_config.mi2s.line = AFE_I2S_SD3;
-			break;
-		default:
-			pr_err("%s: invalid SD line\n",
-				   __func__);
-			goto error_invalid_data;
-		}
-		break;
-	case 2:
-		switch (mi2s_pdata->sd_lines) {
-		case MSM_MI2S_SD0 | MSM_MI2S_SD1:
-			dai_data->port_config.mi2s.line = AFE_I2S_QUAD01;
-			break;
-		case MSM_MI2S_SD2 | MSM_MI2S_SD3:
-			dai_data->port_config.mi2s.line = AFE_I2S_QUAD23;
-			break;
-		default:
-			pr_err("%s: invalid SD line\n",
-				   __func__);
-			goto error_invalid_data;
-		}
-		break;
-	case 3:
-		switch (mi2s_pdata->sd_lines) {
-		case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2:
-			dai_data->port_config.mi2s.line = AFE_I2S_6CHS;
-			break;
-		default:
-			pr_err("%s: invalid SD lines\n",
-				   __func__);
-			goto error_invalid_data;
-		}
-		break;
-	case 4:
-		switch (mi2s_pdata->sd_lines) {
-		case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 | MSM_MI2S_SD3:
-			dai_data->port_config.mi2s.line = AFE_I2S_8CHS;
-			break;
-		default:
-			pr_err("%s: invalid SD lines\n",
-				   __func__);
-			goto error_invalid_data;
-		}
-		break;
-	default:
-		pr_err("%s: invalid SD lines\n", __func__);
-		goto error_invalid_data;
-	}
-	if (mi2s_pdata->capability == MSM_MI2S_CAP_RX)
-		dai_driver->playback.channels_max = num_of_sd_lines << 1;
-	else if (mi2s_pdata->capability == MSM_MI2S_CAP_TX)
-		dai_driver->capture.channels_max = num_of_sd_lines << 1;
-	return 0;
-
-error_invalid_data:
-	return -EINVAL;
-}
-
 static int msm_dai_q6_cdc_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
@@ -384,12 +587,10 @@
 	case SECONDARY_I2S_RX:
 		rc = msm_dai_q6_cdc_hw_params(params, dai, substream->stream);
 		break;
-	case MI2S_RX:
-	case MI2S_TX:
-		rc = msm_dai_q6_mi2s_hw_params(params, dai, substream->stream);
-		break;
+
 	case SLIMBUS_0_RX:
 	case SLIMBUS_1_RX:
+	case SLIMBUS_3_RX:
 	case SLIMBUS_0_TX:
 	case SLIMBUS_1_TX:
 	case SLIMBUS_2_TX:
@@ -457,7 +658,7 @@
 	pr_debug("%s: dai->id = %d aux_pcm_count = %d\n", __func__,
 			dai->id, aux_pcm_count);
 
-	clk_disable(pcm_clk);
+	clk_disable_unprepare(pcm_clk);
 	rc = afe_close(PCM_RX); /* can block */
 	if (IS_ERR_VALUE(rc))
 		dev_err(dai->dev, "fail to close PCM_RX  AFE port\n");
@@ -559,7 +760,7 @@
 		return rc;
 	}
 
-	clk_enable(pcm_clk);
+	clk_prepare_enable(pcm_clk);
 	clk_reset(pcm_clk, CLK_RESET_DEASSERT);
 
 	mutex_unlock(&aux_pcm_mutex);
@@ -766,43 +967,68 @@
 
 	return 0;
 }
+
 static int msm_dai_q6_dai_mi2s_probe(struct snd_soc_dai *dai)
 {
-	struct msm_dai_q6_dai_data *dai_data;
-	struct msm_mi2s_data *mi2s_pdata =
-			(struct msm_mi2s_data *)dai->dev->platform_data;
-	const struct snd_kcontrol_new *kcontrol;
+	struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+		dev_get_drvdata(dai->dev);
+	struct snd_kcontrol *kcontrol = NULL;
 	int rc = 0;
 
-	dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
-		GFP_KERNEL);
+	if (mi2s_dai_data->rx_dai.port_config.mi2s.line) {
+		kcontrol = snd_ctl_new1(&mi2s_config_controls[0],
+					&mi2s_dai_data->rx_dai);
+		rc = snd_ctl_add(dai->card->snd_card, kcontrol);
 
-	if (!dai_data) {
-		dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
-		dai->id);
-		rc = -ENOMEM;
-		goto rtn;
-	} else
-		dev_set_drvdata(dai->dev, dai_data);
-
-	rc = msm_dai_q6_mi2s_platform_data_validation(dai);
-	if (rc != 0) {
-		pr_err("%s: The msm_dai_q6_mi2s_platform_data_validation failed\n",
-			    __func__);
-		kfree(dai_data);
-		goto rtn;
+		if (IS_ERR_VALUE(rc)) {
+			dev_err(dai->dev, "%s: err add RX fmt ctl\n", __func__);
+			goto rtn;
+		}
 	}
-	if (mi2s_pdata->capability == MSM_MI2S_CAP_RX)
-		kcontrol = &mi2s_config_controls[0];
-	else
-		kcontrol = &mi2s_config_controls[2];
 
-	rc = snd_ctl_add(dai->card->snd_card,
-					 snd_ctl_new1(kcontrol, dai_data));
+	if (mi2s_dai_data->tx_dai.port_config.mi2s.line) {
+		rc = snd_ctl_add(dai->card->snd_card,
+				 snd_ctl_new1(&mi2s_config_controls[2],
+					      &mi2s_dai_data->tx_dai));
+
+		if (IS_ERR_VALUE(rc)) {
+			if (kcontrol)
+				snd_ctl_remove(dai->card->snd_card, kcontrol);
+			dev_err(dai->dev, "%s: err add TX fmt ctl\n", __func__);
+		}
+	}
+
 rtn:
 	return rc;
 }
 
+static int msm_dai_q6_dai_mi2s_remove(struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+		dev_get_drvdata(dai->dev);
+	int rc;
+
+	/* If AFE port is still up, close it */
+	if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask)) {
+		rc = afe_close(MI2S_RX); /* can block */
+		if (IS_ERR_VALUE(rc))
+			dev_err(dai->dev, "fail to close MI2S_RX port\n");
+		clear_bit(STATUS_PORT_STARTED,
+			  mi2s_dai_data->rx_dai.status_mask);
+	}
+	if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->tx_dai.status_mask)) {
+		rc = afe_close(MI2S_TX); /* can block */
+		if (IS_ERR_VALUE(rc))
+			dev_err(dai->dev, "fail to close MI2S_TX port\n");
+		clear_bit(STATUS_PORT_STARTED,
+			  mi2s_dai_data->tx_dai.status_mask);
+	}
+	kfree(mi2s_dai_data);
+	snd_soc_unregister_dai(dai->dev);
+
+	return 0;
+}
+
 static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
 {
 	struct msm_dai_q6_dai_data *dai_data;
@@ -866,8 +1092,6 @@
 	switch (dai->id) {
 	case PRIMARY_I2S_TX:
 	case PRIMARY_I2S_RX:
-	case MI2S_RX:
-	case MI2S_TX:
 	case SECONDARY_I2S_RX:
 		rc = msm_dai_q6_cdc_set_fmt(dai, fmt);
 		break;
@@ -894,6 +1118,7 @@
 	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 from 138 to 144, for TX port
@@ -947,6 +1172,15 @@
 	return rc;
 }
 
+static struct snd_soc_dai_ops msm_dai_q6_mi2s_ops = {
+	.startup	= msm_dai_q6_mi2s_startup,
+	.prepare	= msm_dai_q6_mi2s_prepare,
+	.trigger	= msm_dai_q6_mi2s_trigger,
+	.hw_params	= msm_dai_q6_mi2s_hw_params,
+	.shutdown	= msm_dai_q6_mi2s_shutdown,
+	.set_fmt	= msm_dai_q6_mi2s_set_fmt,
+};
+
 static struct snd_soc_dai_ops msm_dai_q6_ops = {
 	.prepare	= msm_dai_q6_prepare,
 	.trigger	= msm_dai_q6_trigger,
@@ -1169,32 +1403,25 @@
 	.remove = msm_dai_q6_dai_auxpcm_remove,
 };
 
-static struct snd_soc_dai_driver msm_dai_q6_mi2s_rx_dai = {
+/* Channel min and max are initialized base on platform data */
+static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai = {
 	.playback = {
 		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
 		SNDRV_PCM_RATE_16000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-		.channels_min = 1,
 		.rate_min =     8000,
 		.rate_max =	48000,
 	},
-	.ops = &msm_dai_q6_ops,
-	.probe = msm_dai_q6_dai_mi2s_probe,
-	.remove = msm_dai_q6_dai_probe,
-};
-
-static struct snd_soc_dai_driver msm_dai_q6_mi2s_tx_dai = {
 	.capture = {
 		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
 		SNDRV_PCM_RATE_16000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
-		.channels_min = 1,
-		.rate_min = 8000,
-		.rate_max = 48000,
+		.rate_min =     8000,
+		.rate_max =     48000,
 	},
-	.ops = &msm_dai_q6_ops,
+	.ops = &msm_dai_q6_mi2s_ops,
 	.probe = msm_dai_q6_dai_mi2s_probe,
-	.remove = msm_dai_q6_dai_remove,
+	.remove = msm_dai_q6_dai_mi2s_remove,
 };
 
 static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_rx_dai = {
@@ -1241,6 +1468,21 @@
 	.remove = msm_dai_q6_dai_remove,
 };
 
+static struct snd_soc_dai_driver msm_dai_q6_slimbus_3_rx_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 = 2,
+		.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)
 {
@@ -1264,14 +1506,7 @@
 		rc = snd_soc_register_dai(&pdev->dev,
 				&msm_dai_q6_aux_pcm_tx_dai);
 		break;
-	case MI2S_RX:
-		rc = snd_soc_register_dai(&pdev->dev,
-					&msm_dai_q6_mi2s_rx_dai);
-		break;
-	case MI2S_TX:
-		rc = snd_soc_register_dai(&pdev->dev,
-					&msm_dai_q6_mi2s_tx_dai);
-		break;
+
 	case SLIMBUS_0_RX:
 	case SLIMBUS_4_RX:
 		rc = snd_soc_register_dai(&pdev->dev,
@@ -1294,6 +1529,10 @@
 		rc = snd_soc_register_dai(&pdev->dev,
 				&msm_dai_q6_slimbus_2_tx_dai);
 		break;
+	case SLIMBUS_3_RX:
+		rc = snd_soc_register_dai(&pdev->dev,
+				&msm_dai_q6_slimbus_3_rx_dai);
+		break;
 	case INT_BT_SCO_RX:
 		rc = snd_soc_register_dai(&pdev->dev,
 					&msm_dai_q6_bt_sco_rx_dai);
@@ -1338,6 +1577,49 @@
 	return 0;
 }
 
+static __devinit int msm_dai_q6_mi2s_dev_probe(struct platform_device *pdev)
+{
+	struct msm_dai_q6_mi2s_dai_data *dai_data;
+	int rc = 0;
+
+	dev_dbg(&pdev->dev, "%s: pdev %p dev %p\n", __func__, pdev, &pdev->dev);
+
+	dai_data = kzalloc(sizeof(struct msm_dai_q6_mi2s_dai_data),
+		GFP_KERNEL);
+
+	if (!dai_data) {
+		dev_err(&pdev->dev, "fail to allocate dai data\n");
+		rc = -ENOMEM;
+		goto rtn;
+	} else
+		dev_set_drvdata(&pdev->dev, dai_data);
+
+	rc = msm_dai_q6_mi2s_platform_data_validation(pdev,
+						      &msm_dai_q6_mi2s_dai);
+	if (IS_ERR_VALUE(rc))
+		goto err_pdata;
+
+	dai_data->rate_constraint.count = 1;
+	dai_data->bitwidth_constraint.count = 1;
+	rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_mi2s_dai);
+
+	if (IS_ERR_VALUE(rc))
+		goto err_pdata;
+
+	return 0;
+
+err_pdata:
+	kfree(dai_data);
+rtn:
+	return rc;
+}
+
+static __devexit int msm_dai_q6_mi2s_dev_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_dai(&pdev->dev);
+	return 0;
+}
+
 static struct platform_driver msm_dai_q6_driver = {
 	.probe  = msm_dai_q6_dev_probe,
 	.remove = msm_dai_q6_dev_remove,
@@ -1347,9 +1629,30 @@
 	},
 };
 
+static struct platform_driver msm_dai_q6_mi2s_driver = {
+	.probe  = msm_dai_q6_mi2s_dev_probe,
+	.remove = msm_dai_q6_mi2s_dev_remove,
+	.driver = {
+		.name = "msm-dai-q6-mi2s",
+		.owner = THIS_MODULE,
+	},
+};
+
 static int __init msm_dai_q6_init(void)
 {
-	return platform_driver_register(&msm_dai_q6_driver);
+	int rc1, rc2;
+
+	rc1 = platform_driver_register(&msm_dai_q6_mi2s_driver);
+
+	if (IS_ERR_VALUE(rc1))
+		pr_err("%s: fail to register mi2s dai driver\n", __func__);
+
+	rc2 = platform_driver_register(&msm_dai_q6_driver);
+
+	if (IS_ERR_VALUE(rc2))
+		pr_err("%s: fail to register mi2s dai driver\n", __func__);
+
+	return (IS_ERR_VALUE(rc1) && IS_ERR_VALUE(rc2)) ? -1 : 0;
 }
 module_init(msm_dai_q6_init);
 
diff --git a/sound/soc/msm/msm-multi-ch-pcm-q6.c b/sound/soc/msm/msm-multi-ch-pcm-q6.c
index 0a8282c..734d34f 100644
--- a/sound/soc/msm/msm-multi-ch-pcm-q6.c
+++ b/sound/soc/msm/msm-multi-ch-pcm-q6.c
@@ -45,10 +45,11 @@
 };
 static struct snd_msm_volume multi_ch_pcm_audio = {NULL, 0x2000};
 
-#define PLAYBACK_NUM_PERIODS	8
-#define PLAYBACK_PERIOD_SIZE	4032
-#define CAPTURE_NUM_PERIODS	16
-#define CAPTURE_PERIOD_SIZE	320
+#define PLAYBACK_NUM_PERIODS		8
+#define PLAYBACK_MAX_PERIOD_SIZE	4032
+#define PLAYBACK_MIN_PERIOD_SIZE        256
+#define CAPTURE_NUM_PERIODS		16
+#define CAPTURE_PERIOD_SIZE		320
 
 static struct snd_pcm_hardware msm_pcm_hardware_capture = {
 	.info =                 (SNDRV_PCM_INFO_MMAP |
@@ -77,14 +78,14 @@
 				SNDRV_PCM_INFO_INTERLEAVED |
 				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
 	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
-	.rates =                SNDRV_PCM_RATE_8000_48000,
+	.rates =                SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
 	.rate_min =             8000,
 	.rate_max =             48000,
 	.channels_min =         1,
 	.channels_max =         6,
-	.buffer_bytes_max =     PLAYBACK_NUM_PERIODS * PLAYBACK_PERIOD_SIZE,
-	.period_bytes_min =	PLAYBACK_PERIOD_SIZE,
-	.period_bytes_max =     PLAYBACK_PERIOD_SIZE,
+	.buffer_bytes_max =     PLAYBACK_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
+	.period_bytes_min =     PLAYBACK_MIN_PERIOD_SIZE,
+	.period_bytes_max =     PLAYBACK_MAX_PERIOD_SIZE,
 	.periods_min =          PLAYBACK_NUM_PERIODS,
 	.periods_max =          PLAYBACK_NUM_PERIODS,
 	.fifo_size =            0,
@@ -378,6 +379,17 @@
 	if (ret < 0)
 		pr_err("snd_pcm_hw_constraint_integer failed\n");
 
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret = snd_pcm_hw_constraint_minmax(runtime,
+			SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+			PLAYBACK_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
+			PLAYBACK_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
+		if (ret < 0) {
+			pr_err("constraint for buffer bytes min max ret = %d\n",
+									ret);
+		}
+	}
+
 	prtd->dsp_cnt = 0;
 	runtime->private_data = prtd;
 	pr_debug("substream->pcm->device = %d\n", substream->pcm->device);
@@ -683,10 +695,22 @@
 	else
 		dir = OUT;
 
-	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+	if (dir == OUT) {
+		ret = q6asm_audio_client_buf_alloc_contiguous(dir,
 			prtd->audio_client,
 			runtime->hw.period_bytes_min,
 			runtime->hw.periods_max);
+	} else {
+		/*
+		 *TODO : Need to Add Async IO changes. All period
+		 * size might not be supported.
+		 */
+		ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+			prtd->audio_client,
+			(params_buffer_bytes(params) / params_periods(params)),
+			params_periods(params));
+	}
+
 	if (ret < 0) {
 		pr_err("Audio Start: Buffer Allocation failed rc = %d\n", ret);
 		return -ENOMEM;
@@ -699,7 +723,10 @@
 	dma_buf->private_data = NULL;
 	dma_buf->area = buf[0].data;
 	dma_buf->addr =  buf[0].phys;
-	dma_buf->bytes = runtime->hw.buffer_bytes_max;
+	if (dir == OUT)
+		dma_buf->bytes = runtime->hw.buffer_bytes_max;
+	else
+		dma_buf->bytes = params_buffer_bytes(params);
 	if (!dma_buf->area)
 		return -ENOMEM;
 
diff --git a/sound/soc/msm/msm-pcm-afe.c b/sound/soc/msm/msm-pcm-afe.c
index 2135a35..482cbee 100644
--- a/sound/soc/msm/msm-pcm-afe.c
+++ b/sound/soc/msm/msm-pcm-afe.c
@@ -29,6 +29,8 @@
 #include <sound/control.h>
 #include <sound/q6adm.h>
 #include <asm/dma.h>
+#include <linux/memory_alloc.h>
+#include <mach/msm_subsystem_map.h>
 #include "msm-pcm-afe.h"
 
 #define MIN_PERIOD_SIZE (128 * 2)
@@ -380,13 +382,18 @@
 	if (dma_buf == NULL) {
 		pr_debug("dma_buf is NULL\n");
 			goto done;
-		}
-	if (dma_buf->area != NULL) {
-		dma_free_coherent(substream->pcm->card->dev,
-			runtime->hw.buffer_bytes_max, dma_buf->area,
-			dma_buf->addr);
-		dma_buf->area = NULL;
 	}
+
+	if (dma_buf->area) {
+		if (msm_subsystem_unmap_buffer(prtd->mem_buffer) < 0) {
+			pr_err("%s: unmap buffer failed\n", __func__);
+			prtd->mem_buffer = NULL;
+			dma_buf->area = NULL;
+		}
+	}
+
+	if (dma_buf->addr)
+		free_contiguous_memory_by_paddr(dma_buf->addr);
 done:
 	pr_debug("%s: dai->id =%x\n", __func__, dai->id);
 	mutex_unlock(&prtd->lock);
@@ -416,14 +423,21 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct pcm_afe_info *prtd = runtime->private_data;
+	int result = 0;
 
 	pr_debug("%s\n", __func__);
 	prtd->mmap_flag = 1;
-	dma_mmap_coherent(substream->pcm->card->dev, vma,
-				runtime->dma_area,
-				runtime->dma_addr,
-				runtime->dma_bytes);
-	return 0;
+	if (runtime->dma_addr && runtime->dma_bytes) {
+		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+		result = remap_pfn_range(vma, vma->vm_start,
+				runtime->dma_addr >> PAGE_SHIFT,
+				runtime->dma_bytes,
+				vma->vm_page_prot);
+	} else {
+		pr_err("Physical address or size of buf is NULL");
+		return -EINVAL;
+	}
+	return result;
 }
 static int msm_afe_trigger(struct snd_pcm_substream *substream, int cmd)
 {
@@ -457,6 +471,7 @@
 	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
 	struct pcm_afe_info *prtd = runtime->private_data;
 	int rc;
+	unsigned int flags = 0;
 
 	pr_debug("%s:\n", __func__);
 
@@ -465,17 +480,46 @@
 	dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
 	dma_buf->dev.dev = substream->pcm->card->dev;
 	dma_buf->private_data = NULL;
-	dma_buf->area = dma_alloc_coherent(dma_buf->dev.dev,
-				runtime->hw.buffer_bytes_max,
-				&dma_buf->addr, GFP_KERNEL);
 
-	pr_debug("%s: dma_buf->area: 0x%p, dma_buf->addr: 0x%x", __func__,
-			(unsigned int *) dma_buf->area, dma_buf->addr);
-	if (!dma_buf->area) {
-		pr_err("%s:MSM AFE memory allocation failed\n", __func__);
+	dma_buf->addr = allocate_contiguous_ebi_nomap(
+				runtime->hw.buffer_bytes_max, SZ_4K);
+	if (!dma_buf->addr) {
+		pr_err("%s:MSM AFE physical memory allocation failed\n",
+							__func__);
 		mutex_unlock(&prtd->lock);
 		return -ENOMEM;
 	}
+
+	flags = MSM_SUBSYSTEM_MAP_KADDR | MSM_SUBSYSTEM_MAP_CACHED;
+
+	prtd->mem_buffer = msm_subsystem_map_buffer(dma_buf->addr,
+				runtime->hw.buffer_bytes_max, flags,
+				NULL, 0);
+	if (IS_ERR((void *) prtd->mem_buffer)) {
+		pr_err("%s: map_buffer failed error = %ld\n", __func__,
+				PTR_ERR((void *)prtd->mem_buffer));
+		free_contiguous_memory_by_paddr(dma_buf->addr);
+		mutex_unlock(&prtd->lock);
+		return -ENOMEM;
+	}
+
+	dma_buf->area = prtd->mem_buffer->vaddr;
+
+	pr_debug("%s: dma_buf->area: 0x%p, dma_buf->addr: 0x%x", __func__,
+			(unsigned int *) dma_buf->area, dma_buf->addr);
+
+	if (!dma_buf->area) {
+		pr_err("%s: Invalid Virtual address\n", __func__);
+		if (prtd->mem_buffer) {
+			msm_subsystem_unmap_buffer(prtd->mem_buffer);
+			prtd->mem_buffer = NULL;
+			dma_buf->area = NULL;
+		}
+		free_contiguous_memory_by_paddr(dma_buf->addr);
+		mutex_unlock(&prtd->lock);
+		return -ENOMEM;
+	}
+
 	dma_buf->bytes = runtime->hw.buffer_bytes_max;
 	memset(dma_buf->area, 0, runtime->hw.buffer_bytes_max);
 	prtd->dma_addr = (u32) dma_buf->addr;
diff --git a/sound/soc/msm/msm-pcm-afe.h b/sound/soc/msm/msm-pcm-afe.h
index 7a60a73..38026d5 100644
--- a/sound/soc/msm/msm-pcm-afe.h
+++ b/sound/soc/msm/msm-pcm-afe.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -30,6 +30,7 @@
 	int prepared;
 	struct hrtimer hrt;
 	int poll_time;
+	struct msm_mapped_buffer *mem_buffer;
 };
 
 
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index 4686386..ec0d947 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -71,7 +71,7 @@
 				SNDRV_PCM_INFO_INTERLEAVED |
 				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
 	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
-	.rates =                SNDRV_PCM_RATE_8000_48000,
+	.rates =                SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
 	.rate_min =             8000,
 	.rate_max =             48000,
 	.channels_min =         1,
@@ -333,21 +333,20 @@
 			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 */
 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 		runtime->hw = msm_pcm_hardware_capture;
 	}
 
-	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);
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		prtd->cmd_ack = 1;
-
 	ret = snd_pcm_hw_constraint_list(runtime, 0,
 				SNDRV_PCM_HW_PARAM_RATE,
 				&constraints_sample_rates);
@@ -619,6 +618,7 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct msm_audio *prtd = runtime->private_data;
 	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
 	struct audio_buffer *buf;
 	int dir, ret;
 	int format = FORMAT_LINEAR_PCM;
@@ -641,6 +641,12 @@
 			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);
 	}
 
 	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 18001b0..02cc6ce 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -134,7 +134,10 @@
 	{ SLIMBUS_1_TX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_4_RX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_4_TX, 0, 0, 0, 0, 0},
-	{ SLIMBUS_INVALID, 0, 0, 0, 0, 0},
+	{ SLIMBUS_3_RX, 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},
 };
 
 
@@ -150,6 +153,16 @@
 	{INVALID_SESSION, INVALID_SESSION},
 };
 
+static uint8_t is_be_dai_extproc(int be_dai)
+{
+	if (be_dai == MSM_BACKEND_DAI_EXTPROC_RX ||
+	    be_dai == MSM_BACKEND_DAI_EXTPROC_TX ||
+	    be_dai == MSM_BACKEND_DAI_EXTPROC_EC_TX)
+		return 1;
+	else
+		return 0;
+}
+
 static void msm_pcm_routing_build_matrix(int fedai_id, int dspst_id,
 	int path_type)
 {
@@ -161,10 +174,10 @@
 		MSM_AFE_PORT_TYPE_RX : MSM_AFE_PORT_TYPE_TX);
 
 	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
-		if ((afe_get_port_type(msm_bedais[i].port_id) ==
-			port_type) &&
-			msm_bedais[i].active && (test_bit(fedai_id,
-				&msm_bedais[i].fe_sessions)))
+		if (!is_be_dai_extproc(i) &&
+		    (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
+		    (msm_bedais[i].active) &&
+		    (test_bit(fedai_id, &msm_bedais[i].fe_sessions)))
 			payload.copp_ids[payload.num_copps++] =
 					msm_bedais[i].port_id;
 	}
@@ -200,14 +213,13 @@
 
 	fe_dai_map[fedai_id][session_type] = dspst_id;
 	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
-		if ((afe_get_port_type(msm_bedais[i].port_id) ==
-			port_type) && msm_bedais[i].active &&
-			(test_bit(fedai_id,
-			&msm_bedais[i].fe_sessions))) {
-
+		if (!is_be_dai_extproc(i) &&
+		    (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
+		    (msm_bedais[i].active) &&
+		    (test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
 			mode = afe_get_port_type(msm_bedais[i].port_id);
 			adm_connect_afe_port(mode, dspst_id,
-				msm_bedais[i].port_id);
+					     msm_bedais[i].port_id);
 			break;
 		}
 	}
@@ -244,10 +256,10 @@
 	if (eq_data[fedai_id].enable)
 		msm_send_eq_values(fedai_id);
 	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
-		if ((afe_get_port_type(msm_bedais[i].port_id) ==
-			port_type) && msm_bedais[i].active &&
-			(test_bit(fedai_id,
-			&msm_bedais[i].fe_sessions))) {
+		if (!is_be_dai_extproc(i) &&
+		    (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
+		    (msm_bedais[i].active) &&
+		    (test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
 
 			channels = msm_bedais[i].channel;
 
@@ -297,10 +309,10 @@
 	mutex_lock(&routing_lock);
 
 	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
-		if ((afe_get_port_type(msm_bedais[i].port_id) ==
-			port_type) && msm_bedais[i].active &&
-			(test_bit(fedai_id,
-			&msm_bedais[i].fe_sessions)))
+		if (!is_be_dai_extproc(i) &&
+		    (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
+		    (msm_bedais[i].active) &&
+		    (test_bit(fedai_id, &msm_bedais[i].fe_sessions)))
 			adm_close(msm_bedais[i].port_id);
 	}
 
@@ -1156,7 +1168,7 @@
 };
 
 static const struct snd_kcontrol_new stub_rx_mixer_controls[] = {
-	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_INVALID,
+	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_EXTPROC_RX,
 	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
 	msm_routing_put_voice_stub_mixer),
 };
@@ -1167,6 +1179,12 @@
 	msm_routing_put_voice_stub_mixer),
 };
 
+static const struct snd_kcontrol_new slimbus_3_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_3_RX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+};
+
 static const struct snd_kcontrol_new tx_voice_mixer_controls[] = {
 	SOC_SINGLE_EXT("PRI_TX_Voice", MSM_BACKEND_DAI_PRI_I2S_TX,
 	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -1228,7 +1246,7 @@
 };
 
 static const struct snd_kcontrol_new tx_voice_stub_mixer_controls[] = {
-	SOC_SINGLE_EXT("STUB_TX_HL", MSM_BACKEND_DAI_INVALID,
+	SOC_SINGLE_EXT("STUB_TX_HL", MSM_BACKEND_DAI_EXTPROC_TX,
 	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
 	msm_routing_put_voice_stub_mixer),
 	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
@@ -1237,6 +1255,9 @@
 	SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
 	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
 	msm_routing_put_voice_stub_mixer),
+	SOC_SINGLE_EXT("STUB_1_TX_HL", MSM_BACKEND_DAI_EXTPROC_EC_TX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
 };
 
 static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
@@ -1269,6 +1290,11 @@
 	msm_routing_put_port_mixer),
 };
 
+static const struct snd_kcontrol_new sbus_3_rx_port_mixer_controls[] = {
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_RX", MSM_BACKEND_DAI_SLIMBUS_3_RX,
+	MSM_BACKEND_DAI_INT_BT_SCO_RX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
+};
 static const struct snd_kcontrol_new bt_sco_rx_port_mixer_controls[] = {
 	SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_INT_BT_SCO_RX,
 	MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
@@ -1581,6 +1607,8 @@
 	SND_SOC_DAPM_AIF_IN("STUB_TX", "Stub Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("SLIMBUS_1_RX", "Slimbus1 Playback", 0, 0, 0, 0),
 	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),
 
 	/* Switch Definitions */
 	SND_SOC_DAPM_SWITCH("SLIMBUS_DL_HL", SND_SOC_NOPM, 0, 0,
@@ -1660,6 +1688,8 @@
 	stub_rx_mixer_controls, ARRAY_SIZE(stub_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("SLIMBUS_1_RX Mixer", SND_SOC_NOPM, 0, 0,
 	slimbus_1_rx_mixer_controls, ARRAY_SIZE(slimbus_1_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SLIMBUS_3_RX_Voice Mixer", SND_SOC_NOPM, 0, 0,
+	slimbus_3_rx_mixer_controls, ARRAY_SIZE(slimbus_3_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Port Mixer",
 	SND_SOC_NOPM, 0, 0, sbus_0_rx_port_mixer_controls,
 	ARRAY_SIZE(sbus_0_rx_port_mixer_controls)),
@@ -1681,6 +1711,9 @@
 	SND_SOC_DAPM_MIXER("SEC_I2S_RX Port Mixer",
 	SND_SOC_NOPM, 0, 0, sec_i2s_rx_port_mixer_controls,
 	ARRAY_SIZE(sec_i2s_rx_port_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SLIMBUS_3_RX Port Mixer",
+	SND_SOC_NOPM, 0, 0, sbus_3_rx_port_mixer_controls,
+	ARRAY_SIZE(sbus_3_rx_port_mixer_controls)),
 };
 
 static const struct snd_soc_dapm_route intercon[] = {
@@ -1846,6 +1879,7 @@
 	{"Voice Stub Tx Mixer", "STUB_TX_HL", "STUB_TX"},
 	{"Voice Stub Tx Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"Voice Stub Tx Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+	{"Voice Stub Tx Mixer", "STUB_1_TX_HL", "STUB_1_TX"},
 	{"VOICE_STUB_UL", NULL, "Voice Stub Tx Mixer"},
 
 	{"STUB_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -1854,10 +1888,16 @@
 	{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Mixer"},
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
 
+	{"SLIMBUS_3_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"SLIMBUS_3_RX", NULL, "SLIMBUS_3_RX_Voice Mixer"},
+
 	{"SLIMBUS_1_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
 	{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Port Mixer"},
 	{"INTERNAL_BT_SCO_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Port Mixer"},
+	{"SLIMBUS_3_RX Port Mixer", "INTERNAL_BT_SCO_RX", "INT_BT_SCO_RX"},
+	{"SLIMBUS_3_RX", NULL, "SLIMBUS_3_RX Port Mixer"},
+
 
 	{"HDMI_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
 	{"HDMI", NULL, "HDMI_RX Port Mixer"},
@@ -2079,10 +2119,8 @@
 		return 0;
 	}
 	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
-		if ((test_bit(fedai_id,
-			&msm_bedais[i].fe_sessions))) {
+		if (test_bit(fedai_id, &msm_bedais[i].fe_sessions))
 			return msm_bedais[i].active;
-		}
 	}
 	return 0;
 }
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index 546c396..5f5c12a 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -37,7 +37,8 @@
 #define LPASS_BE_STUB_TX "(Backend) STUB_TX"
 #define LPASS_BE_SLIMBUS_1_RX "(Backend) SLIMBUS_1_RX"
 #define LPASS_BE_SLIMBUS_1_TX "(Backend) SLIMBUS_1_TX"
-
+#define LPASS_BE_STUB_1_TX "(Backend) STUB_1_TX"
+#define LPASS_BE_SLIMBUS_3_RX "(Backend) SLIMBUS_3_RX"
 #define LPASS_BE_SLIMBUS_4_RX "(Backend) SLIMBUS_4_RX"
 #define LPASS_BE_SLIMBUS_4_TX "(Backend) SLIMBUS_4_TX"
 
@@ -88,7 +89,10 @@
 	MSM_BACKEND_DAI_SLIMBUS_1_TX,
 	MSM_BACKEND_DAI_SLIMBUS_4_RX,
 	MSM_BACKEND_DAI_SLIMBUS_4_TX,
-	MSM_BACKEND_DAI_INVALID,
+	MSM_BACKEND_DAI_SLIMBUS_3_RX,
+	MSM_BACKEND_DAI_EXTPROC_RX,
+	MSM_BACKEND_DAI_EXTPROC_TX,
+	MSM_BACKEND_DAI_EXTPROC_EC_TX,
 	MSM_BACKEND_DAI_MAX,
 };
 
diff --git a/sound/soc/msm/msm7201.c b/sound/soc/msm/msm7201.c
index a6a3266..2a73fd6 100644
--- a/sound/soc/msm/msm7201.c
+++ b/sound/soc/msm/msm7201.c
@@ -48,6 +48,7 @@
 	unsigned long   vers;
 	unsigned long   vers2;
 	unsigned long   rpc_set_snd_device;
+	unsigned long	rpc_set_device_vol;
 	int device;
 };
 
@@ -125,6 +126,7 @@
 	 * index for snd_set_device
 	 */
 	snd_rpc_ids.rpc_set_snd_device = 2;
+	snd_rpc_ids.rpc_set_device_vol = 3;
 	return 0;
 }
 
@@ -235,6 +237,67 @@
 	return rc;
 }
 
+static int snd_msm_device_vol_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2; /* Device/Volume */
+
+	/*
+	 * The number of devices supported is 37 (0 to 36)
+	 */
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 36;
+	return 0;
+}
+
+static int snd_msm_device_vol_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = 0;
+	struct snd_vol_req {
+		struct rpc_request_hdr hdr;
+		uint32_t device;
+		uint32_t method;
+		uint32_t volume;
+		uint32_t cb_func;
+		uint32_t client_data;
+	} req;
+
+	snd_rpc_ids.device = (int)ucontrol->value.integer.value[0];
+
+	if ((ucontrol->value.integer.value[1] < 0) ||
+		(ucontrol->value.integer.value[1] > 6)) {
+		pr_err("Device volume should be in range of 1 to 6\n");
+		return -EINVAL;
+	}
+	if ((ucontrol->value.integer.value[0] > 36) ||
+		(ucontrol->value.integer.value[0] < 0)) {
+		pr_err("Device range supported is 0 to 36\n");
+		return -EINVAL;
+	}
+
+	req.device = cpu_to_be32((int)ucontrol->value.integer.value[0]);
+	req.method = cpu_to_be32(0);
+	req.volume = cpu_to_be32((int)ucontrol->value.integer.value[1]);
+	req.cb_func = -1;
+	req.client_data = cpu_to_be32(0);
+
+	rc = msm_rpc_call(snd_ep, snd_rpc_ids.rpc_set_device_vol ,
+			&req, sizeof(req), 5 * HZ);
+
+	if (rc < 0) {
+		printk(KERN_ERR "%s: snd rpc call failed! rc = %d\n",
+			__func__, rc);
+	} else {
+		printk(KERN_ERR "%s: device [%d] volume set to [%d]\n",
+				__func__, (int)ucontrol->value.integer.value[0],
+				(int)ucontrol->value.integer.value[1]);
+	}
+
+	return rc;
+}
+
 /* Supported range -50dB to 18dB */
 static const DECLARE_TLV_DB_LINEAR(db_scale_linear, -5000, 1800);
 
@@ -262,6 +325,8 @@
 	snd_msm_volume_get, snd_msm_volume_put, 0, db_scale_linear),
 	MSM_EXT("device", 0, snd_msm_device_info, snd_msm_device_get, \
 						 snd_msm_device_put, 0),
+	MSM_EXT("Device Volume", 0, snd_msm_device_vol_info, NULL, \
+						 snd_msm_device_vol_put, 0),
 };
 
 static int msm_new_mixer(struct snd_soc_codec *codec)
diff --git a/sound/soc/msm/msm8660-apq-wm8903.c b/sound/soc/msm/msm8660-apq-wm8903.c
index a163006..e697c3f 100644
--- a/sound/soc/msm/msm8660-apq-wm8903.c
+++ b/sound/soc/msm/msm8660-apq-wm8903.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -188,7 +188,7 @@
 			return ret;
 		}
 
-		wm8903_mclk = clk_get(NULL, "i2s_mic_osr_clk");
+		wm8903_mclk = clk_get_sys(NULL, "i2s_mic_osr_clk");
 		if (IS_ERR(wm8903_mclk)) {
 			pr_err("Failed to get i2s_mic_osr_clk\n");
 			gpio_free(MSM_CDC_MIC_I2S_MCLK);
@@ -196,7 +196,7 @@
 		}
 		/* Master clock OSR 256 */
 		clk_set_rate(wm8903_mclk, 48000 * 256);
-		ret = clk_enable(wm8903_mclk);
+		ret = clk_prepare_enable(wm8903_mclk);
 		if (ret != 0) {
 			pr_err("Unable to enable i2s_mic_osr_clk\n");
 			gpio_free(MSM_CDC_MIC_I2S_MCLK);
@@ -205,7 +205,7 @@
 		}
 	} else {
 		if (wm8903_mclk) {
-			clk_disable(wm8903_mclk);
+			clk_disable_unprepare(wm8903_mclk);
 			clk_put(wm8903_mclk);
 			gpio_free(MSM_CDC_MIC_I2S_MCLK);
 			wm8903_mclk = NULL;
@@ -308,30 +308,30 @@
 			pr_err("cpu_dai set_fmt error\n");
 			return ret;
 		}
-		spkr_osr_clk = clk_get(NULL, "i2s_spkr_osr_clk");
+		spkr_osr_clk = clk_get_sys(NULL, "i2s_spkr_osr_clk");
 		if (IS_ERR(spkr_osr_clk)) {
 			pr_err("Failed to get i2s_spkr_osr_clk\n");
 			return PTR_ERR(spkr_osr_clk);
 		}
 		clk_set_rate(spkr_osr_clk, 48000 * 256);
-		ret = clk_enable(spkr_osr_clk);
+		ret = clk_prepare_enable(spkr_osr_clk);
 		if (ret != 0) {
 			pr_err("Unable to enable i2s_spkr_osr_clk\n");
 			clk_put(spkr_osr_clk);
 			return ret;
 		}
-		spkr_bit_clk = clk_get(NULL, "i2s_spkr_bit_clk");
+		spkr_bit_clk = clk_get_sys(NULL, "i2s_spkr_bit_clk");
 		if (IS_ERR(spkr_bit_clk)) {
 			pr_err("Failed to get i2s_spkr_bit_clk\n");
-			clk_disable(spkr_osr_clk);
+			clk_disable_unprepare(spkr_osr_clk);
 			clk_put(spkr_osr_clk);
 			return PTR_ERR(spkr_bit_clk);
 		}
 		clk_set_rate(spkr_bit_clk, 0);
-		ret = clk_enable(spkr_bit_clk);
+		ret = clk_prepare_enable(spkr_bit_clk);
 		if (ret != 0) {
 			pr_err("Unable to enable i2s_spkr_bit_clk\n");
-			clk_disable(spkr_osr_clk);
+			clk_disable_unprepare(spkr_osr_clk);
 			clk_put(spkr_osr_clk);
 			clk_put(spkr_bit_clk);
 			return ret;
@@ -351,13 +351,13 @@
 			return ret;
 		}
 
-		mic_bit_clk = clk_get(NULL, "i2s_mic_bit_clk");
+		mic_bit_clk = clk_get_sys(NULL, "i2s_mic_bit_clk");
 		if (IS_ERR(mic_bit_clk)) {
 			pr_err("Failed to get i2s_mic_bit_clk\n");
 			return PTR_ERR(mic_bit_clk);
 		}
 		clk_set_rate(mic_bit_clk, 0);
-		ret = clk_enable(mic_bit_clk);
+		ret = clk_prepare_enable(mic_bit_clk);
 		if (ret != 0) {
 			pr_err("Unable to enable i2s_mic_bit_clk\n");
 			clk_put(mic_bit_clk);
@@ -375,17 +375,17 @@
 		tx_hw_param_status = 0;
 		rx_hw_param_status = 0;
 		if (spkr_bit_clk) {
-			clk_disable(spkr_bit_clk);
+			clk_disable_unprepare(spkr_bit_clk);
 			clk_put(spkr_bit_clk);
 			spkr_bit_clk = NULL;
 		}
 		if (spkr_osr_clk) {
-			clk_disable(spkr_osr_clk);
+			clk_disable_unprepare(spkr_osr_clk);
 			clk_put(spkr_osr_clk);
 			spkr_osr_clk = NULL;
 		}
 		if (mic_bit_clk) {
-			clk_disable(mic_bit_clk);
+			clk_disable_unprepare(mic_bit_clk);
 			clk_put(mic_bit_clk);
 			mic_bit_clk = NULL;
 		}
diff --git a/sound/soc/msm/msm8660.c b/sound/soc/msm/msm8660.c
index 8469507..4cbfd45 100644
--- a/sound/soc/msm/msm8660.c
+++ b/sound/soc/msm/msm8660.c
@@ -170,7 +170,7 @@
 		/* Master clock OSR 256 */
 		/* Initially set to Lowest sample rate Needed */
 		clk_set_rate(rx_osr_clk, 8000 * 256);
-		ret = clk_enable(rx_osr_clk);
+		ret = clk_prepare_enable(rx_osr_clk);
 		if (ret != 0) {
 			pr_debug("Unable to enable i2s_spkr_osr_clk\n");
 			clk_put(rx_osr_clk);
@@ -179,16 +179,16 @@
 		rx_bit_clk = clk_get(NULL, "i2s_spkr_bit_clk");
 		if (IS_ERR(rx_bit_clk)) {
 			pr_debug("Failed to get i2s_spkr_bit_clk\n");
-			clk_disable(rx_osr_clk);
+			clk_disable_unprepare(rx_osr_clk);
 			clk_put(rx_osr_clk);
 			return PTR_ERR(rx_bit_clk);
 		}
 		clk_set_rate(rx_bit_clk, 8);
-		ret = clk_enable(rx_bit_clk);
+		ret = clk_prepare_enable(rx_bit_clk);
 		if (ret != 0) {
 			pr_debug("Unable to enable i2s_spkr_bit_clk\n");
 			clk_put(rx_bit_clk);
-			clk_disable(rx_osr_clk);
+			clk_disable_unprepare(rx_osr_clk);
 			clk_put(rx_osr_clk);
 			return ret;
 		}
@@ -203,7 +203,7 @@
 		}
 		/* Master clock OSR 256 */
 		clk_set_rate(tx_osr_clk, 8000 * 256);
-		ret = clk_enable(tx_osr_clk);
+		ret = clk_prepare_enable(tx_osr_clk);
 		if (ret != 0) {
 			pr_debug("Unable to enable i2s_mic_osr_clk\n");
 			clk_put(tx_osr_clk);
@@ -212,16 +212,16 @@
 		tx_bit_clk = clk_get(NULL, "i2s_mic_bit_clk");
 		if (IS_ERR(tx_bit_clk)) {
 			pr_debug("Failed to get i2s_mic_bit_clk\n");
-			clk_disable(tx_osr_clk);
+			clk_disable_unprepare(tx_osr_clk);
 			clk_put(tx_osr_clk);
 			return PTR_ERR(tx_bit_clk);
 		}
 		clk_set_rate(tx_bit_clk, 8);
-		ret = clk_enable(tx_bit_clk);
+		ret = clk_prepare_enable(tx_bit_clk);
 		if (ret != 0) {
 			pr_debug("Unable to enable i2s_mic_bit_clk\n");
 			clk_put(tx_bit_clk);
-			clk_disable(tx_osr_clk);
+			clk_disable_unprepare(tx_osr_clk);
 			clk_put(tx_osr_clk);
 			return ret;
 		}
@@ -243,12 +243,12 @@
 		timpani_poweramp_off();
 		msleep(30);
 		if (rx_bit_clk) {
-			clk_disable(rx_bit_clk);
+			clk_disable_unprepare(rx_bit_clk);
 			clk_put(rx_bit_clk);
 			rx_bit_clk = NULL;
 		}
 		if (rx_osr_clk) {
-			clk_disable(rx_osr_clk);
+			clk_disable_unprepare(rx_osr_clk);
 			clk_put(rx_osr_clk);
 			rx_osr_clk = NULL;
 		}
@@ -257,12 +257,12 @@
 		msm_snddev_disable_dmic_power();
 		msleep(30);
 		if (tx_bit_clk) {
-			clk_disable(tx_bit_clk);
+			clk_disable_unprepare(tx_bit_clk);
 			clk_put(tx_bit_clk);
 			tx_bit_clk = NULL;
 		}
 		if (tx_osr_clk) {
-			clk_disable(tx_osr_clk);
+			clk_disable_unprepare(tx_osr_clk);
 			clk_put(tx_osr_clk);
 			tx_osr_clk = NULL;
 		}
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index 04b0fb0..3f7e399 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -13,7 +13,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
-#include <linux/mfd/pm8xxx/misc.h>
+#include <linux/mfd/pm8xxx/spk.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
@@ -36,6 +36,8 @@
 #define BTSCO_RATE_8KHZ 8000
 #define BTSCO_RATE_16KHZ 16000
 
+#define SPK_AMP_POS	0x1
+#define SPK_AMP_NEG	0x2
 #define SITAR_EXT_CLK_RATE 12288000
 
 #define SITAR_MBHC_DEF_BUTTONS 3
@@ -45,6 +47,7 @@
 static int msm8930_slim_0_rx_ch = 1;
 static int msm8930_slim_0_tx_ch = 1;
 
+static int msm8930_ext_spk_pamp;
 static int msm8930_btsco_rate = BTSCO_RATE_8KHZ;
 static int msm8930_btsco_ch = 1;
 
@@ -55,7 +58,24 @@
 
 static struct snd_soc_jack hs_jack;
 static struct snd_soc_jack button_jack;
-static void *sitar_mbhc_cal;
+
+static int msm8930_enable_codec_ext_clk(
+		struct snd_soc_codec *codec, int enable,
+		bool dapm);
+
+static struct sitar_mbhc_config mbhc_cfg = {
+	.headset_jack = &hs_jack,
+	.button_jack = &button_jack,
+	.read_fw_bin = false,
+	.calibration = NULL,
+	.micbias = SITAR_MICBIAS2,
+	.mclk_cb_fn = msm8930_enable_codec_ext_clk,
+	.mclk_rate = SITAR_EXT_CLK_RATE,
+	.gpio = 0,
+	.gpio_irq = 0,
+	.gpio_level_insert = 1,
+};
+
 
 static void msm8930_ext_control(struct snd_soc_codec *codec)
 {
@@ -94,16 +114,87 @@
 	return 1;
 }
 
+static void msm8960_ext_spk_power_amp_on(u32 spk)
+{
+	if (spk & (SPK_AMP_POS | SPK_AMP_NEG)) {
+		if ((msm8930_ext_spk_pamp & SPK_AMP_POS) &&
+			(msm8930_ext_spk_pamp & SPK_AMP_NEG)) {
+
+			pr_debug("%s() External Bottom Speaker Ampl already "
+				"turned on. spk = 0x%08x\n", __func__, spk);
+			return;
+		}
+
+		msm8930_ext_spk_pamp |= spk;
+
+		if ((msm8930_ext_spk_pamp & SPK_AMP_POS) &&
+			(msm8930_ext_spk_pamp & SPK_AMP_NEG)) {
+
+			pm8xxx_spk_enable(MSM8930_SPK_ON);
+			pr_debug("%s: slepping 4 ms after turning on external "
+				" Left Speaker Ampl\n", __func__);
+			usleep_range(4000, 4000);
+		}
+
+	} else  {
+
+		pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
+			__func__, spk);
+		return;
+	}
+}
+
+static void msm8960_ext_spk_power_amp_off(u32 spk)
+{
+	if (spk & (SPK_AMP_POS | SPK_AMP_NEG)) {
+		if (!msm8930_ext_spk_pamp)
+			return;
+
+		pm8xxx_spk_enable(MSM8930_SPK_OFF);
+		msm8930_ext_spk_pamp = 0;
+		pr_debug("%s: slepping 4 ms after turning on external "
+			" Left Speaker Ampl\n", __func__);
+		usleep_range(4000, 4000);
+
+	} else  {
+
+		pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
+			__func__, spk);
+		return;
+	}
+}
+
 static int msm8930_spkramp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *k, int event)
 {
 	pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
-	/* TODO: add external speaker power amps support */
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		if (!strncmp(w->name, "Ext Spk Left Pos", 17))
+			msm8960_ext_spk_power_amp_on(SPK_AMP_POS);
+		else if (!strncmp(w->name, "Ext Spk Left Neg", 17))
+			msm8960_ext_spk_power_amp_on(SPK_AMP_NEG);
+		else {
+			pr_err("%s() Invalid Speaker Widget = %s\n",
+					__func__, w->name);
+			return -EINVAL;
+		}
+	} else {
+		if (!strncmp(w->name, "Ext Spk Left Pos", 17))
+			msm8960_ext_spk_power_amp_off(SPK_AMP_POS);
+		else if (!strncmp(w->name, "Ext Spk Left Neg", 17))
+			msm8960_ext_spk_power_amp_off(SPK_AMP_NEG);
+		else {
+			pr_err("%s() Invalid Speaker Widget = %s\n",
+					__func__, w->name);
+			return -EINVAL;
+		}
+	}
 	return 0;
 }
 
-int msm8930_enable_codec_ext_clk(
-		struct snd_soc_codec *codec, int enable)
+static int msm8930_enable_codec_ext_clk(
+		struct snd_soc_codec *codec, int enable,
+		bool dapm)
 {
 	pr_debug("%s: enable = %d\n", __func__, enable);
 	if (enable) {
@@ -115,7 +206,7 @@
 		if (codec_clk) {
 			clk_set_rate(codec_clk, SITAR_EXT_CLK_RATE);
 			clk_prepare_enable(codec_clk);
-			sitar_mclk_enable(codec, 1);
+			sitar_mclk_enable(codec, 1, dapm);
 		} else {
 			pr_err("%s: Error setting Sitar MCLK\n", __func__);
 			clk_users--;
@@ -129,7 +220,7 @@
 		if (!clk_users) {
 			pr_debug("%s: disabling MCLK. clk_users = %d\n",
 					 __func__, clk_users);
-			sitar_mclk_enable(codec, 0);
+			sitar_mclk_enable(codec, 0, dapm);
 			clk_disable_unprepare(codec_clk);
 		}
 	}
@@ -143,9 +234,9 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		return msm8930_enable_codec_ext_clk(w->codec, 1);
+		return msm8930_enable_codec_ext_clk(w->codec, 1, true);
 	case SND_SOC_DAPM_POST_PMD:
-		return msm8930_enable_codec_ext_clk(w->codec, 0);
+		return msm8930_enable_codec_ext_clk(w->codec, 0, true);
 	}
 	return 0;
 }
@@ -156,7 +247,7 @@
 	msm8930_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_SPK("Ext Spk Left Pos", msm8930_spkramp_event),
-	SND_SOC_DAPM_SPK("Ext Spk Left Neg", NULL),
+	SND_SOC_DAPM_SPK("Ext Spk Left Neg", msm8930_spkramp_event),
 
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
 	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
@@ -520,6 +611,10 @@
 	}
 	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
 
+	mbhc_cfg.gpio = 37;
+	mbhc_cfg.gpio_irq = gpio_to_irq(mbhc_cfg.gpio);
+	sitar_hs_detect(codec, &mbhc_cfg);
+
 	return 0;
 }
 
@@ -978,8 +1073,8 @@
 		pr_err("%s: Not the right machine type\n", __func__);
 		return -ENODEV ;
 	}
-	sitar_mbhc_cal = def_sitar_mbhc_cal();
-	if (!sitar_mbhc_cal) {
+	mbhc_cfg.calibration = def_sitar_mbhc_cal();
+	if (!mbhc_cfg.calibration) {
 		pr_err("Calibration data allocation failed\n");
 		return -ENOMEM;
 	}
@@ -987,7 +1082,7 @@
 	msm8930_snd_device = platform_device_alloc("soc-audio", 0);
 	if (!msm8930_snd_device) {
 		pr_err("Platform device allocation failed\n");
-		kfree(sitar_mbhc_cal);
+		kfree(mbhc_cfg.calibration);
 		return -ENOMEM;
 	}
 
@@ -995,7 +1090,7 @@
 	ret = platform_device_add(msm8930_snd_device);
 	if (ret) {
 		platform_device_put(msm8930_snd_device);
-		kfree(sitar_mbhc_cal);
+		kfree(mbhc_cfg.calibration);
 		return ret;
 	}
 
@@ -1018,7 +1113,7 @@
 	}
 	msm8930_free_headset_mic_gpios();
 	platform_device_unregister(msm8930_snd_device);
-	kfree(sitar_mbhc_cal);
+	kfree(mbhc_cfg.calibration);
 }
 module_exit(msm8930_audio_exit);
 
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 44fab3f..f78f58d 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -344,7 +344,7 @@
 		if (clk_users == 1) {
 			if (codec_clk) {
 				clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
-				clk_enable(codec_clk);
+				clk_prepare_enable(codec_clk);
 				tabla_mclk_enable(codec, 1, dapm);
 			} else {
 				pr_err("%s: Error setting Tabla MCLK\n",
@@ -361,7 +361,7 @@
 				pr_debug("%s: disabling MCLK. clk_users = %d\n",
 					 __func__, clk_users);
 				tabla_mclk_enable(codec, 0, dapm);
-				clk_disable(codec_clk);
+				clk_disable_unprepare(codec_clk);
 			}
 		} else {
 			pr_err("%s: Error releasing Tabla MCLK\n", __func__);
@@ -1370,6 +1370,7 @@
 		.platform_name = "msm-pcm-hostless",
 		.codec_name = "tabla1x_codec",
 		.codec_dai_name = "tabla_tx2",
+		.ignore_suspend = 1,
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ops = &msm8960_be_ops,
 	},
@@ -1410,6 +1411,7 @@
 		.platform_name = "msm-pcm-hostless",
 		.codec_name = "tabla_codec",
 		.codec_dai_name = "tabla_tx2",
+		.ignore_suspend = 1,
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ops = &msm8960_be_ops,
 	},
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index dc120b08..9f058b9 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -147,6 +147,7 @@
 	case HDMI_RX:
 	case SLIMBUS_0_RX:
 	case SLIMBUS_1_RX:
+	case SLIMBUS_3_RX:
 	case INT_BT_SCO_RX:
 	case INT_BT_A2DP_RX:
 	case INT_FM_RX:
@@ -206,6 +207,7 @@
 	case SLIMBUS_1_RX:
 	case SLIMBUS_1_TX:
 	case SLIMBUS_2_TX:
+	case SLIMBUS_3_RX:
 	case INT_BT_SCO_RX:
 	case INT_BT_SCO_TX:
 	case INT_BT_A2DP_RX:
@@ -271,6 +273,7 @@
 	case SLIMBUS_1_RX: return IDX_SLIMBUS_1_RX;
 	case SLIMBUS_1_TX: return IDX_SLIMBUS_1_TX;
 	case SLIMBUS_2_TX: return IDX_SLIMBUS_2_TX;
+	case SLIMBUS_3_RX: return IDX_SLIMBUS_3_RX;
 	case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
 	case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
 	case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
@@ -305,6 +308,7 @@
 	case SLIMBUS_1_RX:
 	case SLIMBUS_1_TX:
 	case SLIMBUS_2_TX:
+	case SLIMBUS_3_RX:
 	case SLIMBUS_4_RX:
 	case SLIMBUS_4_TX:
 		ret_size = SIZEOF_CFG_CMD(afe_port_slimbus_sch_cfg);
@@ -676,7 +680,7 @@
 	return ret;
 }
 
-int afe_loopback(u16 enable, u16 rx_port, u16 tx_port)
+int afe_loopback(u16 enable, u16 dst_port, u16 src_port)
 {
 	struct afe_loopback_command lb_cmd;
 	int ret = 0;
@@ -685,6 +689,11 @@
 	if (ret != 0)
 		return ret;
 
+	if ((afe_get_port_type(dst_port) == MSM_AFE_PORT_TYPE_RX) &&
+		(afe_get_port_type(src_port) == MSM_AFE_PORT_TYPE_RX))
+		return afe_loopback_cfg(enable, dst_port, src_port,
+					LB_MODE_EC_REF_VOICE_AUDIO);
+
 	lb_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 						APR_HDR_LEN(20), APR_PKT_VER);
 	lb_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
@@ -693,8 +702,8 @@
 	lb_cmd.hdr.dest_port = 0;
 	lb_cmd.hdr.token = 0;
 	lb_cmd.hdr.opcode = AFE_PORT_CMD_LOOPBACK;
-	lb_cmd.tx_port_id = tx_port;
-	lb_cmd.rx_port_id = rx_port;
+	lb_cmd.tx_port_id = src_port;
+	lb_cmd.rx_port_id = dst_port;
 	lb_cmd.mode = 0xFFFF;
 	lb_cmd.enable = (enable ? 1 : 0);
 	atomic_set(&this_afe.state, 1);
@@ -716,6 +725,63 @@
 	return ret;
 }
 
+int afe_loopback_cfg(u16 enable, u16 dst_port, u16 src_port, u16 mode)
+{
+	struct afe_port_cmd_set_param lp_cfg;
+	int ret = 0;
+
+	ret = afe_q6_interface_prepare();
+	if (ret != 0)
+		return ret;
+
+	pr_debug("%s: src_port %d, dst_port %d\n",
+		  __func__, src_port, dst_port);
+
+	lp_cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	lp_cfg.hdr.pkt_size = sizeof(lp_cfg);
+	lp_cfg.hdr.src_port = 0;
+	lp_cfg.hdr.dest_port = 0;
+	lp_cfg.hdr.token = 0;
+	lp_cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM;
+
+	lp_cfg.port_id = src_port;
+	lp_cfg.payload_size	= sizeof(struct afe_param_payload);
+	lp_cfg.payload_address	= 0;
+
+	lp_cfg.payload.module_id = AFE_MODULE_LOOPBACK;
+	lp_cfg.payload.param_id	= AFE_PARAM_ID_LOOPBACK_CONFIG;
+	lp_cfg.payload.param_size = sizeof(struct afe_param_loopback_cfg);
+	lp_cfg.payload.reserved	= 0;
+
+	lp_cfg.payload.param.loopback_cfg.loopback_cfg_minor_version =
+			AFE_API_VERSION_LOOPBACK_CONFIG;
+	lp_cfg.payload.param.loopback_cfg.dst_port_id = dst_port;
+	lp_cfg.payload.param.loopback_cfg.routing_mode = mode;
+	lp_cfg.payload.param.loopback_cfg.enable = enable;
+	lp_cfg.payload.param.loopback_cfg.reserved = 0;
+
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lp_cfg);
+	if (ret < 0) {
+		pr_err("%s: AFE loopback config failed for src_port %d, dst_port %d\n",
+			   __func__, src_port, dst_port);
+		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_loopback_gain(u16 port_id, u16 volume)
 {
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index f3a2383..ba5c79d 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -1791,6 +1791,67 @@
 	return -EINVAL;
 }
 
+int q6asm_set_encdec_chan_map(struct audio_client *ac,
+			uint32_t num_channels)
+{
+	struct asm_stream_cmd_encdec_channelmap chan_map;
+	u8 *channel_mapping;
+
+	int rc = 0;
+
+	pr_debug("%s: Session %d, num_channels = %d\n",
+			 __func__, ac->session, num_channels);
+
+	q6asm_add_hdr(ac, &chan_map.hdr, sizeof(chan_map), TRUE);
+
+	chan_map.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+	chan_map.param_id = ASM_ENCDEC_DEC_CHAN_MAP;
+	chan_map.param_size = sizeof(struct asm_dec_chan_map);
+	chan_map.chan_map.num_channels = num_channels;
+
+	channel_mapping =
+		chan_map.chan_map.channel_mapping;
+
+	memset(channel_mapping, PCM_CHANNEL_NULL, MAX_CHAN_MAP_CHANNELS);
+	if (num_channels == 1)  {
+		channel_mapping[0] = PCM_CHANNEL_FL;
+	} else if (num_channels == 2) {
+		channel_mapping[0] = PCM_CHANNEL_FL;
+		channel_mapping[1] = PCM_CHANNEL_FR;
+	} else if (num_channels == 6) {
+		channel_mapping[0] = PCM_CHANNEL_FC;
+		channel_mapping[1] = PCM_CHANNEL_FL;
+		channel_mapping[2] = PCM_CHANNEL_FR;
+		channel_mapping[3] = PCM_CHANNEL_LB;
+		channel_mapping[4] = PCM_CHANNEL_RB;
+		channel_mapping[5] = PCM_CHANNEL_LFE;
+	} else {
+		pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
+				num_channels);
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &chan_map);
+	if (rc < 0) {
+		pr_err("%s:Command opcode[0x%x]paramid[0x%x] failed\n",
+				__func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
+				ASM_ENCDEC_DEC_CHAN_MAP);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s:timeout opcode[0x%x]\n", __func__,
+						chan_map.hdr.opcode);
+		rc = -ETIMEDOUT;
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return rc;
+}
+
 int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
 		uint16_t min_rate, uint16_t max_rate,
 		uint16_t reduced_rate_level, uint16_t rate_modulation_cmd)
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index f4b4dd1..18a1f43 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -2217,14 +2217,8 @@
 	mvm_set_voice_timing.hdr.opcode = VSS_ICOMMON_CMD_SET_VOICE_TIMING;
 	mvm_set_voice_timing.timing.mode = 0;
 	mvm_set_voice_timing.timing.enc_offset = 8000;
-	if (machine_is_apq8064_sim()) {
-		pr_debug("%s: Machine is apq8064 sim\n", __func__);
-		mvm_set_voice_timing.timing.dec_req_offset = 0;
-		mvm_set_voice_timing.timing.dec_offset = 18000;
-	} else {
-		mvm_set_voice_timing.timing.dec_req_offset = 3300;
-		mvm_set_voice_timing.timing.dec_offset = 8300;
-	}
+	mvm_set_voice_timing.timing.dec_req_offset = 3300;
+	mvm_set_voice_timing.timing.dec_offset = 8300;
 
 	v->mvm_state = CMD_STATUS_FAIL;