Merge "Bluetooth: Set security level based on remote device features." into msm-3.0
diff --git a/Documentation/devicetree/bindings/spmi/msm-qpnp-gpio.txt b/Documentation/devicetree/bindings/spmi/msm-qpnp-gpio.txt
new file mode 100644
index 0000000..f07d3c2
--- /dev/null
+++ b/Documentation/devicetree/bindings/spmi/msm-qpnp-gpio.txt
@@ -0,0 +1,142 @@
+* msm-qpnp-gpio
+
+msm-qpnp-gpio is a GPIO chip driver for the MSM SPMI implementation.
+It creates a spmi_device for every spmi-dev-container block of device_nodes.
+These device_nodes contained within specify the PMIC GPIO number associated
+with each GPIO chip. The driver will map these to Linux GPIO numbers.
+
+[PMIC GPIO Device Declarations]
+
+-Root Node-
+
+Required properties :
+ - spmi-dev-container : Used to specify the following child nodes as part of the
+   same SPMI device.
+ - gpio-controller : Specify as gpio-contoller. All child nodes will belong to this
+   gpio_chip.
+ - #gpio-cells: We encode a PMIC GPIO number and a 32-bit flag field to
+   specify the gpio configuration. This must be set to '2'.
+ - #address-cells: Specify one address field. This must be set to '1'.
+ - #size-cells: Specify one size-cell. This must be set to '1'.
+ - compatible = "qcom,qpnp-gpio" : Specify driver matching for this driver.
+
+-Child Nodes-
+
+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.
+
+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
+			both.
+			QPNP_GPIO_DIR_OUT  = 1,
+			QPNP_GPIO_DIR_IN   = 2,
+			QPNP_GPIO_DIR_BOTH = 3
+
+   @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
+
+   @output_value:	The gpio output value of the gpio line - 0 or 1
+   @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.
+			QPNP_GPIO_PULL_UP_30	 = 0,
+			QPNP_GPIO_PULL_UP_1P5	 = 1,
+			QPNP_GPIO_PULL_UP_31P5	 = 2,
+			QPNP_GPIO_PULL_UP_1P5_30 = 3,
+			QPNP_GPIO_PULL_DN	 = 4,
+			QPNP_GPIO_PULL_NO	 = 5
+
+  @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,
+			QPNP_GPIO_VIN1 = 1,
+			QPNP_GPIO_VIN2 = 2,
+			QPNP_GPIO_VIN3 = 3,
+			QPNP_GPIO_VIN4 = 4,
+			QPNP_GPIO_VIN5 = 5,
+			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,
+			QPNP_GPIO_OUT_STRENGTH_MED  = 2,
+			QPNP_GPIO_OUT_STRENGTH_LOW  = 3
+
+  @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_DTEST1	= 4,
+			QPNP_GPIO_DTEST2	= 5,
+			QPNP_GPIO_DTEST3	= 6,
+			QPNP_GPIO_DTEST4	= 7
+
+  @inv_int_pol:		Invert polarity before feeding the line to the interrupt
+			module in pmic. This feature will almost be never used
+			since the pm8xxx interrupt block can detect both edges
+			and both levels.
+  @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.
+
+[PMIC GPIO clients]
+
+Required properties :
+ - gpios : Contains 3 fields of the form <&gpio_controller pmic_gpio_num flags>
+
+[Example]
+
+qpnp: qcom,spmi@fc4c0000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		interrupt-controller;
+		#interrupt-cells = <3>;
+
+		qcom,pm8941@0 {
+			spmi-slave-container;
+			reg = <0x0>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			pm8941_gpios: gpios {
+				spmi-dev-container;
+				compatible = "qcom,qpnp-gpio";
+				gpio-controller;
+				#gpio-cells = <2>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+
+				qcom,pm8941_gpio1@0xc000 {
+					reg = <0xc000 0x100>;
+					qcom,qpnp-gpio-num = <62>;
+				};
+
+				qcom,pm8941_gpio2@0xc100 {
+					reg = <0xc100 0x100>;
+					qcom,qpnp-gpio-num = <20>;
+					qcom,qpnp-gpio-cfg = <0x1 0x1 0x1 0x2 0x3 0x2 0x0 0x0 0x1>;
+				};
+			};
+
+			qcom,testgpio@1000 {
+				compatible = "qcom,qpnp-testgpio";
+				reg = <0x1000 0x1000>;
+				gpios = <&pm8941_gpios 62 0x0 &pm8941_gpios 20 0x1>;
+			};
+		};
+	};
+};
diff --git a/Documentation/devicetree/bindings/spmi/msm-spmi.txt b/Documentation/devicetree/bindings/spmi/msm-spmi.txt
index 8fe415b..d50037f 100644
--- a/Documentation/devicetree/bindings/spmi/msm-spmi.txt
+++ b/Documentation/devicetree/bindings/spmi/msm-spmi.txt
@@ -1,13 +1,28 @@
 * SPMI
 
-The spmi Device Tree support interprets up to two levels of Device Tree
+The SPMI Device Tree support interprets up to three levels of Device Tree
 topology. The first level is required and specifies only a slave address.
 The second level is optional and allows for the specification of different
-offsets within the same 16-bit address space underneath a particular SPMI
-slave ID. Within the second level, any number of address ranges can be
-associated with a particular device within that 16-bit range.
+device nodes within the same 16-bit address space underneath a particular
+SPMI slave ID. Within the second level, any number of address ranges can be
+associated with a particular device within that 16-bit range. An additional
+flag allows for the possiblity to specify that all device nodes should
+have their resources dedicated to only one spmi_device. This flag can
+be specified at the second level, or an optional third level. By default
+without this flag, one spmi_device is created for each device_node.
 
-First level
+[Root Node]
+
+Recommended properties :
+ - interrupt-controller : Used to specify the root node as the
+   interrupt controller for SPMI devices.
+ - #interrupt-cells : The number of cells used to express one interrupt.
+
+Notes :
+ - It is considered an error to include either spmi-container-dev or
+ spmi-slave-dev in the Root Node.
+
+[First Level Nodes]
 
 Required properites :
 
@@ -22,51 +37,124 @@
  - interrupt-parent : the phandle for the interrupt controller that
    services interrupts for this device.
 
-Second level
+[Second Level Nodes]
 
 Required properties :
  - spmi-slave-container: Used by the parser to understand that this is the
-   second level of the tree.
+   second level of the tree that includes device nodes associated with the
+   same slave_id.
  - reg: <a b> where a is < 65536 and b is a size. Each device supports an
    arbitrary number of address ranges.
  - compatible : "qcom," prefixed string to match against the driver.
 
 Recommended properties :
 
- - interrupts : <a b c> where a is the slave ID, b is is the peripheral ID,
+ - interrupts : <a b c> where a is the slave ID, b is the peripheral ID,
    c is the device interrupt number (0-7). Each device supports any arbitrary
    number of interrupts.
  - interrupt-parent : the phandle for the interrupt controller that
    services interrupts for this device.
 
-Example:
+Optional properties :
+
+ - spmi-dev-container: This specifies that all the device nodes specified for
+   this slave_id should have their resources coalesced into only one
+   spmi_device.
+
+[Third Level Nodes]
+
+Required properties :
+
+  - spmi-dev-container: This specifies that all the device nodes specified for
+   this slave_id should have their resources coalesced into only one
+   spmi_device.
+  - reg: <a b> where a is < 65536 and b is a size. Each device supports an
+   arbitrary number of address ranges.
+  - compatible : "qcom," prefixed string to match against the driver.
+
+Recommended properties :
+
+ - interrupts : <a b c> where a is the slave ID, b is the peripheral ID,
+   c is the device interrupt number (0-7). Each device supports any arbitrary
+   number of interrupts.
+ - interrupt-parent : the phandle for the interrupt controller that
+   services interrupts for this device.
+
+Notes :
+ - It is considered an error to include spmi-slave-dev at this level.
+
+[Example]
 
 / {
-	qcom,spmi@fc4c0000 {
+	qpnp: qcom,spmi@fc4c0000 {
 		#address-cells = <1>;
 		#size-cells = <0>;
-		interrupt-parent = <&qpnpint>;
-		pmic8941@d {
+		interrupt-controller;
+		#interrupt-cells = <3>;
+
+		testint@f {
+			interrupt-parent = <&qpnp>;
+			compatible = "qcom,qpnp-testint";
+			reg = <0xf>;
+			interrupts = <0x3 0x15 0x0 0x3 0x15 0x02 0x1 0x47 0x0>;
+
+		};
+
+		pm8941@0 {
+			spmi-slave-container;
+			reg = <0x0>;
 			#address-cells = <1>;
 			#size-cells = <1>;
-			reg = <0xd>;
+
+			pm8941_gpios: gpios {
+				spmi-dev-container;
+				compatible = "qcom,qpnp-gpio";
+				gpio-controller;
+				#gpio-cells = <1>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+
+				pm8941_gpio1@0xc000 {
+					compatible = "qcom,qpnp-gpio";
+					reg = <0xc000 0x100>;
+					qcom,qpnp_gpio = <1>;
+					interrupt-parent = <&qpnp>;
+					interrupts = <0x3 0x15 0x02 0x1 0x47 0x0>;
+				};
+
+				pm8941_gpio2@0xc100 {
+					compatible = "qcom,qpnp-gpio";
+					reg = <0xc100 0x100>;
+					qcom,qpnp_gpio = <2>;
+					interrupt-parent = <&qpnp>;
+					interrupts = <0x3 0x15 0x0>;
+				};
+			};
+
+			testgpio@0x1000 {
+				compatible = "qcom,qpnp-testgpio";
+				reg = <0x1000 0x1000>;
+				qpnp-gpios = <&pm8941_gpios 0x0>;
+			};
+		};
+		pm8841@2 {
 			spmi-slave-container;
-
-			coincell@2800 {
-				compatible = "qcom,qpnp-coincell";
-				reg = <0x2800 0x4000>;
-				interrupts = <0xd 0x28 0x6  0xd 0x28 0x3>;
-
-			};
-			pon@800 {
-				compatible = "qcom,qpnp-pon";
-				reg = <0x800 0x4000>;
-			};
-		};
-		customer_dev@2 {
-			compatible = "qcom,qpnp-pon";
 			reg = <0x2>;
-			interrupts = <0x2 0x08 0x1  0x2 0x8 0x3>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			spmi-dev-container;
+			compatible = "qcom,qpnp-gpio";
+
+			pm8841_gpio1@0xc000 {
+				reg = <0xc000 0x100>;
+				qcom,qpnp_gpio = <1>;
+			};
+
+			pm8841_gpio2@0xc100 {
+				reg = <0xc100 0x100>;
+				qcom,qpnp_gpio = <2>;
+			};
 		};
+
 	};
 };
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index f5046dc..e6f6998 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -645,6 +645,7 @@
 	select GENERIC_TIME
 	select GENERIC_ALLOCATOR
 	select HAVE_SCHED_CLOCK
+	select HAVE_CLK_PREPARE
 	help
 	  Support for Qualcomm MSM/QSD based systems.  This runs on the
 	  apps processor of the MSM/QSD and depends on a shared memory
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 0b89d45..e9479c6 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -104,6 +104,8 @@
 # CONFIG_BATTERY_MSM is not set
 # CONFIG_HWMON is not set
 # CONFIG_MFD_SUPPORT is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_STUB=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
 CONFIG_FB=y
diff --git a/arch/arm/configs/msm7627-perf_defconfig b/arch/arm/configs/msm7627-perf_defconfig
index ea5c7c9..3fbe374 100644
--- a/arch/arm/configs/msm7627-perf_defconfig
+++ b/arch/arm/configs/msm7627-perf_defconfig
@@ -263,6 +263,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 # CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_SDIO_SUPPORT=y
 CONFIG_SWITCH=y
diff --git a/arch/arm/configs/msm7627_defconfig b/arch/arm/configs/msm7627_defconfig
index 0841f7e..f05b5f7 100644
--- a/arch/arm/configs/msm7627_defconfig
+++ b/arch/arm/configs/msm7627_defconfig
@@ -261,6 +261,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 # CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_SDIO_SUPPORT=y
 CONFIG_SWITCH=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 31e04f1..44986a4 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -58,6 +58,7 @@
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0xC800000
 CONFIG_CP_ACCESS=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
@@ -230,7 +231,9 @@
 # CONFIG_HWMON is not set
 CONFIG_MARIMBA_CORE=y
 CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
 # CONFIG_RC_CORE is not set
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
 # CONFIG_MT9T013 is not set
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index bb54f68..6ba9790 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -58,6 +58,7 @@
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0xC800000
 CONFIG_CP_ACCESS=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
@@ -231,7 +232,9 @@
 # CONFIG_HWMON is not set
 CONFIG_MARIMBA_CORE=y
 CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
 # CONFIG_RC_CORE is not set
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
 # CONFIG_MT9T013 is not set
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
index 761b75e..b6c56b6 100644
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ b/arch/arm/configs/msm7630-perf_defconfig
@@ -329,6 +329,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 # CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_SDIO_SUPPORT=y
 CONFIG_MMC_MSM_CARD_HW_DETECTION=y
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index ab94d66..851f189 100644
--- a/arch/arm/configs/msm7630_defconfig
+++ b/arch/arm/configs/msm7630_defconfig
@@ -331,6 +331,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 # CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_SDIO_SUPPORT=y
 CONFIG_MMC_MSM_CARD_HW_DETECTION=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index 0b49871..494b3a3 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -385,6 +385,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 # CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_SDIO_SUPPORT=y
 CONFIG_MMC_MSM_CARD_HW_DETECTION=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 2bef915..9b850da 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -386,6 +386,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 # CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_SDIO_SUPPORT=y
 CONFIG_MMC_MSM_CARD_HW_DETECTION=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index d14757b..288381b 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -308,7 +308,9 @@
 CONFIG_REGULATOR_PM8XXX=y
 CONFIG_REGULATOR_GPIO=y
 CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
 CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
 CONFIG_USB_VIDEO_CLASS=y
@@ -392,6 +394,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 # CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_CARD_HW_DETECTION=y
 CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index dafaffc..d12df73 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -308,7 +308,9 @@
 CONFIG_REGULATOR_PM8XXX=y
 CONFIG_REGULATOR_GPIO=y
 CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
 CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
 CONFIG_USB_VIDEO_CLASS=y
@@ -392,6 +394,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 # CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_CARD_HW_DETECTION=y
 CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index d4552f8..c709178 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -235,6 +235,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 # CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_SDIO_SUPPORT=y
 CONFIG_MMC_MSM_CARD_HW_DETECTION=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 7216c12..20a5449 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -2107,5 +2107,60 @@
 	  separately. This will guarantee that the last acesses for each cpu
 	  will be logged but there will be fewer entries per cpu
 
+config MSM_CACHE_ERP
+	bool "Cache / CPU error reporting"
+	depends on ARCH_MSM_KRAIT
+	help
+	  Say 'Y' here to enable reporting of cache and TLB errors to the kernel
+	  log. Enabling this feature can be used as a system debugging technique
+	  if cache corruption is suspected. Cache error statistics will also be
+	  reported in /proc/cpu/msm_cache_erp.
+
+	  For production builds, you should probably say 'N' here.
+
+config MSM_L1_ERR_PANIC
+	bool "Panic on L1 cache / TLB errors"
+	depends on MSM_CACHE_ERP
+	help
+	  To cause the kernel to panic whenever an L1 cache or TLB error is
+	  detected, say 'Y' here. This may be useful as a debugging technique if
+	  general system instability is suspected.
+
+	  For production builds, you should probably say 'N' here.
+
+
+config MSM_L2_ERP_PORT_PANIC
+	bool "Panic on L2 master port errors"
+	depends on MSM_CACHE_ERP
+	help
+	  Master port errors can occur when a memory request is not properly
+	  handled by the destination slave. Enable this option to catch drivers
+	  which attempt to access bad areas of the address space, or access
+	  hardware registers in an improper state (such as certain clocks not
+	  being on). This option may help with debugging, though production
+	  builds should probably say 'N' here.
+
+config MSM_L2_ERP_1BIT_PANIC
+	bool "Panic on recoverable L2 soft errors"
+	depends on MSM_CACHE_ERP
+	help
+	  Enable this option to cause a kernel panic whenever the L2 cache
+	  encounters a single-bit (correctable) soft error. This option should
+	  only be enabled when doing low-level debugging where cache corruption
+	  is suspected.
+
+	  For production builds, you should definitely say 'N' here.
+
+config MSM_L2_ERP_2BIT_PANIC
+	bool "Panic on unrecoverable L2 soft errors"
+	depends on MSM_CACHE_ERP
+	help
+	  Enable this option to cause a kernel panic whenever the L2 cache
+	  encounters a double-bit (non-correctable) soft error. Debug builds
+	  will likely benefit from having this option enabled to catch cache
+	  problems as soon as possible.
+
+	  For production builds, it may be acceptable to say 'N' here, since
+	  an uncorrectable error might not necessarily cause further problems.
 
 endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 6cde804..c4d2c54 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -260,7 +260,7 @@
 obj-$(CONFIG_MACH_APQ8064_RUMI3) += board-8064-all.o board-8064-regulator.o
 obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o board-9615-gpiomux.o board-9615-storage.o
 obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o
-obj-$(CONFIG_ARCH_MSMCOPPER) += board-copper.o board-dt.o
+obj-$(CONFIG_ARCH_MSMCOPPER) += board-copper.o board-dt.o board-copper-regulator.o
 
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
@@ -329,3 +329,4 @@
 
 obj-$(CONFIG_ARCH_MSM8960) += mdm2.o mdm_common.o
 obj-$(CONFIG_MSM_RTB) += msm_rtb.o
+obj-$(CONFIG_MSM_CACHE_ERP) += cache_erp.o
diff --git a/arch/arm/mach-msm/acpuclock-7201.c b/arch/arm/mach-msm/acpuclock-7201.c
index ae4b084..687033c 100644
--- a/arch/arm/mach-msm/acpuclock-7201.c
+++ b/arch/arm/mach-msm/acpuclock-7201.c
@@ -219,6 +219,34 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
+/* 8625 PLL4 @ 1209MHz with GSM capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_pll4_1209[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
+	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 1, 61440 },
+	{ 1, 122880, ACPU_PLL_1, 1, 1,  15360, 3, 2, 61440 },
+	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3, 61440 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
+	{ 0, 604800, ACPU_PLL_4, 6, 1, 75600, 3, 6, 200000 },
+	{ 1, 1209600, ACPU_PLL_4, 6, 0, 151200, 3, 7, 200000},
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
+/* 8625 PLL4 @ 1209MHz with CDMA capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_1200_pll4_1209[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
+	{ 0, 65536, ACPU_PLL_1, 1, 3,  8192, 3, 1, 49152 },
+	{ 1, 98304, ACPU_PLL_1, 1, 1,  12288, 3, 2, 49152 },
+	{ 1, 196608, ACPU_PLL_1, 1, 0, 24576, 3, 3, 98304 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
+	{ 0, 604800, ACPU_PLL_4, 6, 1, 75600, 3, 6, 200000 },
+	{ 1, 1209600, ACPU_PLL_4, 6, 0, 151200, 3, 7, 200000},
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+};
+
 /* 7625a PLL2 @ 1200MHz with GSM capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_25a[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
@@ -333,6 +361,8 @@
 	PLL_CONFIG(960, 589, 1200, 800),
 	PLL_CONFIG(960, 737, 1200, 1008),
 	PLL_CONFIG(960, 589, 1200, 1008),
+	PLL_CONFIG(960, 245, 1200, 1209),
+	PLL_CONFIG(960, 196, 1200, 1209),
 	{ 0, 0, 0, 0, 0 }
 };
 
@@ -875,3 +905,9 @@
 	.max_speed_delta_khz = 504000,
 	.init = acpuclk_7627_init,
 };
+
+struct acpuclk_soc_data acpuclk_8625_soc_data __initdata = {
+	/* TODO: Need to update speed delta from H/w Team */
+	.max_speed_delta_khz = 604800,
+	.init = acpuclk_7627_init,
+};
diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h
index ef6c359..c5f0ee3 100644
--- a/arch/arm/mach-msm/acpuclock.h
+++ b/arch/arm/mach-msm/acpuclock.h
@@ -110,5 +110,6 @@
 extern struct acpuclk_soc_data acpuclk_9615_soc_data;
 extern struct acpuclk_soc_data acpuclk_8930_soc_data;
 extern struct acpuclk_soc_data acpuclk_8064_soc_data;
+extern struct acpuclk_soc_data acpuclk_8625_soc_data;
 
 #endif
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 97f8722..7b9bdac 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -236,7 +236,6 @@
 static struct completion dfab_unvote_completion;
 static DEFINE_SPINLOCK(wakelock_reference_lock);
 static int wakelock_reference_count;
-static struct delayed_work msm9615_bam_init_work;
 static int a2_pc_disabled_wakelock_skipped;
 /* End A2 power collaspe */
 
@@ -1639,10 +1638,9 @@
 	if (polling_mode)
 		rx_switch_to_interrupt_mode();
 
-	queue_rx();
-
 	toggle_apps_ack();
 	complete_all(&bam_connection_completion);
+	queue_rx();
 }
 
 static void disconnect_to_bam(void)
@@ -1959,10 +1957,10 @@
 	}
 
 	bam_mux_initialized = 1;
-	queue_rx();
 	toggle_apps_ack();
 	bam_connection_is_active = 1;
 	complete_all(&bam_connection_completion);
+	queue_rx();
 	return 0;
 
 rx_event_reg_failed:
@@ -2034,7 +2032,7 @@
 	return ret;
 }
 
-static void msm9615_bam_init(struct work_struct *work)
+static void msm9615_bam_init(void)
 {
 	int ret = 0;
 
@@ -2079,19 +2077,10 @@
 	} else if (new_state & SMSM_A2_POWER_CONTROL) {
 		bam_dmux_log("%s: init\n", __func__);
 		grab_wakelock();
-		if (cpu_is_msm9615()) {
-			/*
-			 * even though a2 has signaled it is ready via the
-			 * SMSM_A2_POWER_CONTROL bit, it has not yet
-			 * enabled the pipes as needed by sps_connect
-			 * in satallite mode.  Add a short delay to give modem
-			 * time to enable the pipes.
-			 */
-			schedule_delayed_work(&msm9615_bam_init_work,
-						msecs_to_jiffies(100));
-		} else {
+		if (cpu_is_msm9615())
+			msm9615_bam_init();
+		else
 			bam_init();
-		}
 	} else {
 		bam_dmux_log("%s: bad state change\n", __func__);
 		pr_err("%s: unsupported state change\n", __func__);
@@ -2159,7 +2148,6 @@
 	init_completion(&bam_connection_completion);
 	init_completion(&dfab_unvote_completion);
 	INIT_DELAYED_WORK(&ul_timeout_work, ul_timeout);
-	INIT_DELAYED_WORK(&msm9615_bam_init_work, msm9615_bam_init);
 	wake_lock_init(&bam_wakelock, WAKE_LOCK_SUSPEND, "bam_dmux_wakelock");
 
 	rc = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_A2_POWER_CONTROL,
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index f23bf2a..70d76fb 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -512,6 +512,9 @@
 	msm_gpiomux_install(apq8064_cam_common_configs,
 			ARRAY_SIZE(apq8064_cam_common_configs));
 
+	if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
+		sensor_board_info_imx074.mount_angle = 0;
+
 	platform_device_register(&msm8960_device_i2c_mux_gsbi4);
 	platform_device_register(&msm8960_device_csiphy0);
 	platform_device_register(&msm8960_device_csiphy1);
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 8c87925..bf82e40 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -82,22 +82,6 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
-static struct gpiomux_setting audio_auxpcm[] = {
-	/* Suspended state */
-	{
-		.func = GPIOMUX_FUNC_GPIO,
-		.drv = GPIOMUX_DRV_2MA,
-		.pull = GPIOMUX_PULL_NONE,
-	},
-	/* Active state */
-	{
-		.func = GPIOMUX_FUNC_1,
-		.drv = GPIOMUX_DRV_2MA,
-		.pull = GPIOMUX_PULL_NONE,
-	},
-};
-
-
 static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv  = GPIOMUX_DRV_2MA,
@@ -448,37 +432,6 @@
 	},
 };
 
-static struct msm_gpiomux_config apq8064_audio_auxpcm_configs[] __initdata = {
-	{
-		.gpio = 43,
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
-			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
-		},
-	},
-	{
-		.gpio = 44,
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
-			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
-		},
-	},
-	{
-		.gpio = 45,
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
-			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
-		},
-	},
-	{
-		.gpio = 46,
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
-			[GPIOMUX_ACTIVE] = &audio_auxpcm[1],
-		},
-	},
-};
-
 /* External 3.3 V regulator enable */
 static struct msm_gpiomux_config apq8064_ext_regulator_configs[] __initdata = {
 	{
@@ -633,8 +586,9 @@
 	msm_gpiomux_install(apq8064_audio_codec_configs,
 			ARRAY_SIZE(apq8064_audio_codec_configs));
 
-	msm_gpiomux_install(apq8064_audio_auxpcm_configs,
-			ARRAY_SIZE(apq8064_audio_auxpcm_configs));
+	pr_debug("%s(): audio-auxpcm: Include GPIO configs"
+		" as audio is not the primary user"
+		" for these GPIO Pins\n", __func__);
 
 	msm_gpiomux_install(apq8064_ext_regulator_configs,
 			ARRAY_SIZE(apq8064_ext_regulator_configs));
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index 84dbea8..9099266 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -31,18 +31,6 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
-static struct gpiomux_setting spi_active_config2 = {
-	.func = GPIOMUX_FUNC_2,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting spi_suspended_config2 = {
-	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_2MA,
-	.pull = GPIOMUX_PULL_UP,
-};
-
 static struct gpiomux_setting gsbi3_suspended_cfg = {
 	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_2MA,
@@ -313,13 +301,6 @@
 		},
 	},
 	{
-		.gpio      = 14,		/* GSBI1 SPI_CS_1 */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &spi_suspended_config2,
-			[GPIOMUX_ACTIVE] = &spi_active_config2,
-		},
-	},
-	{
 		.gpio      = 16,	/* GSBI3 I2C QUP SDA */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gsbi3_suspended_cfg,
@@ -346,18 +327,6 @@
 		},
 	},
 	{
-		.gpio      = 24,	/* GSBI5 UART2 */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gsbi5,
-		},
-	},
-	{
-		.gpio      = 25,	/* GSBI5 UART2 */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gsbi5,
-		},
-	},
-	{
 		.gpio      = 44,	/* GSBI12 I2C QUP SDA */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gsbi12,
diff --git a/arch/arm/mach-msm/board-copper-regulator.c b/arch/arm/mach-msm/board-copper-regulator.c
new file mode 100644
index 0000000..a7f0eac
--- /dev/null
+++ b/arch/arm/mach-msm/board-copper-regulator.c
@@ -0,0 +1,322 @@
+/*
+ * 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/platform_device.h>
+#include <linux/regulator/stub-regulator.h>
+
+#define VREG_CONSUMERS(_name) \
+	static struct regulator_consumer_supply vreg_consumers_##_name[]
+
+/*
+ * Consumer specific regulator names:
+ *			 regulator name		consumer dev_name
+ */
+VREG_CONSUMERS(S1B) = {
+	REGULATOR_SUPPLY("8841_s1",		NULL),
+};
+VREG_CONSUMERS(S2B) = {
+	REGULATOR_SUPPLY("8841_s2",		NULL),
+};
+VREG_CONSUMERS(S3B) = {
+	REGULATOR_SUPPLY("8841_s3",		NULL),
+};
+VREG_CONSUMERS(S4B) = {
+	REGULATOR_SUPPLY("8841_s4",		NULL),
+};
+VREG_CONSUMERS(S5B) = {
+	REGULATOR_SUPPLY("8841_s5",		NULL),
+};
+VREG_CONSUMERS(S6B) = {
+	REGULATOR_SUPPLY("8841_s6",		NULL),
+};
+VREG_CONSUMERS(S7B) = {
+	REGULATOR_SUPPLY("8841_s7",		NULL),
+};
+VREG_CONSUMERS(S8B) = {
+	REGULATOR_SUPPLY("8841_s8",		NULL),
+};
+VREG_CONSUMERS(S1) = {
+	REGULATOR_SUPPLY("8941_s1",		NULL),
+};
+VREG_CONSUMERS(S2) = {
+	REGULATOR_SUPPLY("8941_s2",		NULL),
+};
+VREG_CONSUMERS(S3) = {
+	REGULATOR_SUPPLY("8941_s3",		NULL),
+};
+VREG_CONSUMERS(L1) = {
+	REGULATOR_SUPPLY("8941_l1",		NULL),
+};
+VREG_CONSUMERS(L2) = {
+	REGULATOR_SUPPLY("8941_l2",		NULL),
+};
+VREG_CONSUMERS(L3) = {
+	REGULATOR_SUPPLY("8941_l3",		NULL),
+};
+VREG_CONSUMERS(L4) = {
+	REGULATOR_SUPPLY("8941_l4",		NULL),
+};
+VREG_CONSUMERS(L5) = {
+	REGULATOR_SUPPLY("8941_l5",		NULL),
+};
+VREG_CONSUMERS(L6) = {
+	REGULATOR_SUPPLY("8941_l6",		NULL),
+};
+VREG_CONSUMERS(L7) = {
+	REGULATOR_SUPPLY("8941_l7",		NULL),
+};
+VREG_CONSUMERS(L8) = {
+	REGULATOR_SUPPLY("8941_l8",		NULL),
+};
+VREG_CONSUMERS(L9) = {
+	REGULATOR_SUPPLY("8941_l9",		NULL),
+};
+VREG_CONSUMERS(L10) = {
+	REGULATOR_SUPPLY("8941_l10",		NULL),
+};
+VREG_CONSUMERS(L11) = {
+	REGULATOR_SUPPLY("8941_l11",		NULL),
+};
+VREG_CONSUMERS(L12) = {
+	REGULATOR_SUPPLY("8941_l12",		NULL),
+};
+VREG_CONSUMERS(L13) = {
+	REGULATOR_SUPPLY("8941_l13",		NULL),
+};
+VREG_CONSUMERS(L14) = {
+	REGULATOR_SUPPLY("8941_l14",		NULL),
+};
+VREG_CONSUMERS(L15) = {
+	REGULATOR_SUPPLY("8941_l15",		NULL),
+};
+VREG_CONSUMERS(L16) = {
+	REGULATOR_SUPPLY("8941_l16",		NULL),
+};
+VREG_CONSUMERS(L17) = {
+	REGULATOR_SUPPLY("8941_l17",		NULL),
+};
+VREG_CONSUMERS(L18) = {
+	REGULATOR_SUPPLY("8941_l18",		NULL),
+};
+VREG_CONSUMERS(L19) = {
+	REGULATOR_SUPPLY("8941_l19",		NULL),
+};
+VREG_CONSUMERS(L20) = {
+	REGULATOR_SUPPLY("8941_l20",		NULL),
+};
+VREG_CONSUMERS(L21) = {
+	REGULATOR_SUPPLY("8941_l21",		NULL),
+};
+VREG_CONSUMERS(L22) = {
+	REGULATOR_SUPPLY("8941_l22",		NULL),
+};
+VREG_CONSUMERS(L23) = {
+	REGULATOR_SUPPLY("8941_l23",		NULL),
+};
+VREG_CONSUMERS(L24) = {
+	REGULATOR_SUPPLY("8941_l24",		NULL),
+};
+VREG_CONSUMERS(LVS1) = {
+	REGULATOR_SUPPLY("8941_lvs1",		NULL),
+};
+VREG_CONSUMERS(LVS2) = {
+	REGULATOR_SUPPLY("8941_lvs2",		NULL),
+};
+VREG_CONSUMERS(LVS3) = {
+	REGULATOR_SUPPLY("8941_lvs3",		NULL),
+};
+
+#define PM8X41_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
+			 _always_on, _supply_regulator, _hpm_min, _system_uA)  \
+	struct stub_regulator_pdata vreg_dev_##_id##_pdata __devinitdata = { \
+		.init_data = { \
+			.constraints = { \
+				.valid_modes_mask	= _modes, \
+				.valid_ops_mask		= _ops, \
+				.min_uV			= _min_uV, \
+				.max_uV			= _max_uV, \
+				.input_uV		= _max_uV, \
+				.apply_uV		= 0,	\
+				.always_on		= _always_on, \
+				.name			= _name, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id), \
+			.consumer_supplies	= vreg_consumers_##_id, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.hpm_min_load		= _hpm_min, \
+		.system_uA		= _system_uA, \
+	}
+
+#define PM8X41_LDO(_id, _name, _always_on, _min_uV, _max_uV, \
+		_supply_regulator, _hpm_min, _system_uA) \
+	PM8X41_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, _always_on, \
+		_supply_regulator, _hpm_min, _system_uA)
+
+#define PM8X41_SMPS(_id, _name, _always_on, _min_uV, _max_uV, \
+		_supply_regulator, _hpm_min, _system_uA) \
+	PM8X41_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, _always_on, \
+		_supply_regulator, _hpm_min, _system_uA)
+
+#define PM8X41_FTSMPS(_id, _name, _always_on, _min_uV, _max_uV, \
+		_supply_regulator, _hpm_min, _system_uA) \
+	PM8X41_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
+		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS \
+		| REGULATOR_CHANGE_MODE, _always_on, \
+		_supply_regulator, _hpm_min, _system_uA)
+
+#define PM8X41_VS(_id, _name, _always_on, _supply_regulator) \
+	PM8X41_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, \
+		 _always_on, _supply_regulator, 0, 0)
+
+/* PM8x41 regulator constraints */
+
+/*	    ID      name     a_on  min_uV   max_uV  supply    hpm_min sys_uA  */
+PM8X41_SMPS(S1B,   "8841_s1", 0, 900000,  1150000,  NULL,       100000, 0);
+PM8X41_FTSMPS(S2B, "8841_s2", 0, 900000,  1150000,  NULL,       100000, 0);
+PM8X41_SMPS(S3B,   "8841_s3", 0, 1150000, 1150000, NULL,       100000, 0);
+PM8X41_FTSMPS(S4B, "8841_s4", 0, 900000,  900000,  NULL,       100000, 0);
+PM8X41_FTSMPS(S5B, "8841_s5", 0, 850000,  1100000, NULL,       100000, 0);
+PM8X41_FTSMPS(S6B, "8841_s6", 0, 850000,  1100000, NULL,       100000, 0);
+PM8X41_FTSMPS(S7B, "8841_s7", 0, 850000,  1100000, NULL,       100000, 0);
+PM8X41_FTSMPS(S8B, "8841_s8", 0, 850000,  1100000, NULL,       100000, 0);
+PM8X41_SMPS(S1,   "8941_s1", 0, 1300000, 1300000, NULL,       100000, 0);
+PM8X41_SMPS(S2,   "8941_s2", 0, 2150000, 2150000, NULL,       100000, 0);
+PM8X41_SMPS(S3,   "8941_s3", 0, 1800000, 1800000, NULL,       100000, 0);
+PM8X41_LDO(L1,     "8941_l1",  0, 1225000, 1225000, "8941_s1", 100000, 0);
+PM8X41_LDO(L2,     "8941_l2",  0, 1200000, 1200000, "8941_s3", 5000,   0);
+PM8X41_LDO(L3,     "8941_l3",  0, 1200000, 1200000, "8941_s1", 10000,  0);
+PM8X41_LDO(L4,     "8941_l4",  0, 1150000, 1150000, "8941_s1", 10000,  0);
+PM8X41_LDO(L5,     "8941_l5",  0, 1800000, 1800000, "8941_s2", 1000,   0);
+PM8X41_LDO(L6,     "8941_l6",  0, 1800000, 1800000, "8941_s2", 10000,  0);
+PM8X41_LDO(L7,     "8941_l7",  0, 1800000, 1800000, "8941_s2", 1000,   0);
+PM8X41_LDO(L8,     "8941_l8",  0, 1800000, 1800000, NULL,       1000,   0);
+PM8X41_LDO(L9,     "8941_l9",  0, 1800000, 2950000, NULL,       10000,  0);
+PM8X41_LDO(L10,    "8941_l10", 0, 1800000, 2950000, NULL,       10000,  0);
+PM8X41_LDO(L11,    "8941_l11", 0, 1250000, 1250000, "8941_s1", 10000,  0);
+PM8X41_LDO(L12,    "8941_l12", 0, 1800000, 1800000, "8941_s2", 10000,  0);
+PM8X41_LDO(L13,    "8941_l13", 0, 2950000, 2950000, NULL,       10000,  0);
+PM8X41_LDO(L14,    "8941_l14", 0, 1800000, 1800000, "8941_s2", 10000,  0);
+PM8X41_LDO(L15,    "8941_l15", 0, 2050000, 2050000, "8941_s2", 10000,  0);
+PM8X41_LDO(L16,    "8941_l16", 0, 2700000, 2700000, NULL,       10000,  0);
+PM8X41_LDO(L17,    "8941_l17", 0, 2850000, 2850000, NULL,       10000,  0);
+PM8X41_LDO(L18,    "8941_l18", 0, 2850000, 2850000, NULL,       10000,  0);
+PM8X41_LDO(L19,    "8941_l19", 0, 2900000, 2900000, NULL,       10000,  0);
+PM8X41_LDO(L20,    "8941_l20", 0, 2950000, 2950000, NULL,       10000,  0);
+PM8X41_LDO(L21,    "8941_l21", 0, 2950000, 2950000, NULL,       10000,  0);
+PM8X41_LDO(L22,    "8941_l22", 0, 3000000, 3000000, NULL,       10000,  0);
+PM8X41_LDO(L23,    "8941_l23", 0, 3000000, 3000000, NULL,       10000,  0);
+PM8X41_LDO(L24,    "8941_l24", 0, 3075000, 3075000, NULL,       5000,   0);
+
+/*	  ID	      name     a_on   supply  */
+PM8X41_VS(LVS1,    "8941_lvs1", 0, "8941_s3");
+PM8X41_VS(LVS2,    "8941_lvs2", 0, "8941_s3");
+PM8X41_VS(LVS3,    "8941_lvs3", 0, "8941_s3");
+
+#define VREG_DEVICE(_name, _devid)					       \
+		vreg_device_##_name __devinitdata =			       \
+		{							       \
+			.name = STUB_REGULATOR_DRIVER_NAME,		       \
+			.id = _devid,					       \
+			.dev = { .platform_data = &vreg_dev_##_name##_pdata }, \
+		}
+
+static struct platform_device VREG_DEVICE(S1B, 0);
+static struct platform_device VREG_DEVICE(S2B, 1);
+static struct platform_device VREG_DEVICE(S3B, 3);
+static struct platform_device VREG_DEVICE(S4B, 4);
+static struct platform_device VREG_DEVICE(S5B, 5);
+static struct platform_device VREG_DEVICE(S6B, 6);
+static struct platform_device VREG_DEVICE(S7B, 7);
+static struct platform_device VREG_DEVICE(S8B, 8);
+static struct platform_device VREG_DEVICE(S1, 9);
+static struct platform_device VREG_DEVICE(S2, 10);
+static struct platform_device VREG_DEVICE(S3, 11);
+static struct platform_device VREG_DEVICE(L1, 12);
+static struct platform_device VREG_DEVICE(L2, 13);
+static struct platform_device VREG_DEVICE(L3, 14);
+static struct platform_device VREG_DEVICE(L4, 15);
+static struct platform_device VREG_DEVICE(L5, 16);
+static struct platform_device VREG_DEVICE(L6, 17);
+static struct platform_device VREG_DEVICE(L7, 18);
+static struct platform_device VREG_DEVICE(L8, 19);
+static struct platform_device VREG_DEVICE(L9, 20);
+static struct platform_device VREG_DEVICE(L10, 21);
+static struct platform_device VREG_DEVICE(L11, 22);
+static struct platform_device VREG_DEVICE(L12, 23);
+static struct platform_device VREG_DEVICE(L13, 24);
+static struct platform_device VREG_DEVICE(L14, 25);
+static struct platform_device VREG_DEVICE(L15, 26);
+static struct platform_device VREG_DEVICE(L16, 27);
+static struct platform_device VREG_DEVICE(L17, 28);
+static struct platform_device VREG_DEVICE(L18, 29);
+static struct platform_device VREG_DEVICE(L19, 30);
+static struct platform_device VREG_DEVICE(L20, 31);
+static struct platform_device VREG_DEVICE(L21, 32);
+static struct platform_device VREG_DEVICE(L22, 33);
+static struct platform_device VREG_DEVICE(L23, 34);
+static struct platform_device VREG_DEVICE(L24, 35);
+static struct platform_device VREG_DEVICE(LVS1, 36);
+static struct platform_device VREG_DEVICE(LVS2, 37);
+static struct platform_device VREG_DEVICE(LVS3, 38);
+
+struct platform_device *msm_copper_stub_regulator_devices[] __devinitdata = {
+	&vreg_device_S1B,
+	&vreg_device_S2B,
+	&vreg_device_S3B,
+	&vreg_device_S4B,
+	&vreg_device_S5B,
+	&vreg_device_S6B,
+	&vreg_device_S7B,
+	&vreg_device_S8B,
+	&vreg_device_S1,
+	&vreg_device_S2,
+	&vreg_device_S3,
+	&vreg_device_L1,
+	&vreg_device_L2,
+	&vreg_device_L3,
+	&vreg_device_L4,
+	&vreg_device_L5,
+	&vreg_device_L6,
+	&vreg_device_L7,
+	&vreg_device_L8,
+	&vreg_device_L9,
+	&vreg_device_L10,
+	&vreg_device_L11,
+	&vreg_device_L12,
+	&vreg_device_L13,
+	&vreg_device_L14,
+	&vreg_device_L15,
+	&vreg_device_L16,
+	&vreg_device_L17,
+	&vreg_device_L18,
+	&vreg_device_L19,
+	&vreg_device_L20,
+	&vreg_device_L21,
+	&vreg_device_L22,
+	&vreg_device_L23,
+	&vreg_device_L24,
+	&vreg_device_LVS1,
+	&vreg_device_LVS2,
+	&vreg_device_LVS3,
+};
+
+int msm_copper_stub_regulator_devices_len __devinitdata =
+			ARRAY_SIZE(msm_copper_stub_regulator_devices);
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index c30be16..97ea645 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -26,6 +26,7 @@
 #ifdef CONFIG_ANDROID_PMEM
 #include <linux/android_pmem.h>
 #endif
+#include <linux/regulator/stub-regulator.h>
 #include <asm/mach/map.h>
 #include <asm/hardware/gic.h>
 #include <mach/board.h>
@@ -39,6 +40,7 @@
 #include <mach/msm_smd.h>
 #include <mach/qpnp-int.h>
 #include "clock.h"
+#include "devices.h"
 
 #define MSM_KERNEL_EBI1_MEM_SIZE	0x280000
 #ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
@@ -357,6 +359,8 @@
 	platform_device_register(&ion_dev);
 #endif
 	platform_device_register(&msm_device_smd_copper);
+	platform_add_devices(msm_copper_stub_regulator_devices,
+					msm_copper_stub_regulator_devices_len);
 }
 
 static struct of_device_id irq_match[] __initdata  = {
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index ea3a36d..7fecf59 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -24,6 +24,12 @@
 #include "board-msm7627a.h"
 #include <mach/vreg.h>
 
+#define GPIO_SKU1_CAM_VGA_SHDN    18
+#define GPIO_SKU1_CAM_VGA_RESET_N 29
+#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
+
 #ifdef CONFIG_MSM_CAMERA_V4L2
 static uint32_t camera_off_gpio_table[] = {
 	GPIO_CFG(15, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
@@ -66,6 +72,22 @@
 	.gpio_no_mux = 1,
 };
 
+#ifdef CONFIG_WEBCAM_OV7692_QRD
+static struct msm_camera_gpio_conf gpio_conf_ov7692 = {
+	.camera_off_table = camera_off_gpio_table,
+	.camera_on_table = camera_on_gpio_table,
+	.gpio_no_mux = 1,
+};
+#endif
+
+#ifdef CONFIG_OV5647
+static struct msm_camera_gpio_conf gpio_conf_ov5647 = {
+	.camera_off_table = camera_off_gpio_table,
+	.camera_on_table = camera_on_gpio_table,
+	.gpio_no_mux = 1,
+};
+#endif
+
 #ifdef CONFIG_MSM_CAMERA_FLASH
 static struct msm_camera_sensor_flash_src msm_flash_src = {
 	.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
@@ -133,6 +155,83 @@
 };
 #endif
 
+#ifdef CONFIG_WEBCAM_OV7692_QRD
+static struct msm_camera_sensor_platform_info sensor_board_info_ov7692 = {
+	.mount_angle = 90,
+	.cam_vreg = msm_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_cam_vreg),
+	.gpio_conf = &gpio_conf_ov7692,
+};
+
+static struct msm_camera_sensor_flash_data flash_ov7692 = {
+	.flash_type     = MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov7692_data = {
+	.sensor_name	    = "ov7692",
+	.sensor_reset_enable    = 0,
+	.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,
+	.flash_data	     = &flash_ov7692,
+	.sensor_platform_info   = &sensor_board_info_ov7692,
+	.csi_if		 = 1,
+	.camera_type = FRONT_CAMERA_2D,
+};
+#endif
+
+#ifdef CONFIG_OV5647
+
+#ifdef CONFIG_AD5046_ACT
+static struct i2c_board_info ad5046_actuator_i2c_info = {
+	I2C_BOARD_INFO("ad5046_act", 0x18 >> 1),
+};
+
+static struct msm_actuator_info ad5046_actuator_info = {
+	.board_info     = &ad5046_actuator_i2c_info,
+	.bus_id         = MSM_GSBI0_QUP_I2C_BUS_ID,
+	.vcm_pwd        = GPIO_SKU3_CAM_5MP_CAM_DRIVER_PWDN,
+	.vcm_enable     = 1,
+};
+#endif
+
+static struct msm_camera_sensor_platform_info sensor_board_info_ov5647 = {
+	.mount_angle = 90,
+	.cam_vreg = msm_cam_vreg,
+	.num_vreg = ARRAY_SIZE(msm_cam_vreg),
+	.gpio_conf = &gpio_conf_ov5647,
+};
+
+static struct msm_camera_sensor_flash_src msm_flash_src_ov5647 = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_LED,
+	._fsrc.led_src.led_name = "flashlight",
+	._fsrc.led_src.led_name_len = 10,
+};
+
+static struct msm_camera_sensor_flash_data flash_ov5647 = {
+	.flash_type             = MSM_CAMERA_FLASH_LED,
+	.flash_src              = &msm_flash_src_ov5647,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov5647_data = {
+	.sensor_name    = "ov5647",
+	.sensor_reset_enable = 1,
+	.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,
+	.flash_data     = &flash_ov5647,
+	.sensor_platform_info   = &sensor_board_info_ov5647,
+	.csi_if                 = 1,
+	.camera_type	= BACK_CAMERA_2D,
+
+#ifdef CONFIG_AD5046_ACT
+	.actuator_info = &ad5046_actuator_info
+#endif
+};
+
+#endif
 #ifdef CONFIG_MT9E013
 static struct msm_camera_sensor_flash_data flash_mt9e013 = {
 	.flash_type             = MSM_CAMERA_FLASH_LED,
@@ -158,38 +257,6 @@
 };
 #endif
 
-#ifdef CONFIG_IMX072
-static struct msm_camera_sensor_platform_info imx072_sensor_7627a_info = {
-	.mount_angle = 90
-};
-
-static struct msm_camera_sensor_flash_data flash_imx072 = {
-	.flash_type             = MSM_CAMERA_FLASH_LED,
-	.flash_src              = &msm_flash_src
-};
-
-static struct msm_camera_sensor_info msm_camera_sensor_imx072_data = {
-	.sensor_name    = "imx072",
-	.sensor_reset_enable = 1,
-	.sensor_reset   = GPIO_CAM_GP_CAMIF_RESET_N, /* TODO 106,*/
-	.pmic_gpio_enable  = 0,
-	.sensor_pwd             = 85,
-	.vcm_pwd                = GPIO_CAM_GP_CAM_PWDN,
-	.vcm_enable             = 1,
-	.pdata                  = &msm_camera_device_data_csi1,
-	.flash_data             = &flash_imx072,
-	.sensor_platform_info = &imx072_sensor_7627a_info,
-	.csi_if                 = 1
-};
-
-static struct platform_device msm_camera_sensor_imx072 = {
-	.name   = "msm_camera_imx072",
-	.dev    = {
-		.platform_data = &msm_camera_sensor_imx072_data,
-	},
-};
-#endif
-
 #ifdef CONFIG_WEBCAM_OV9726
 static struct msm_camera_sensor_flash_data flash_ov9726 = {
 	.flash_type             = MSM_CAMERA_FLASH_LED,
@@ -225,37 +292,43 @@
 		sensor_board_info_mt9e013.num_vreg = 0;
 		sensor_board_info_ov9726.cam_vreg = NULL;
 		sensor_board_info_ov9726.num_vreg = 0;
+		sensor_board_info_ov7692.cam_vreg = NULL;
+		sensor_board_info_ov7692.num_vreg = 0;
+		sensor_board_info_ov5647.cam_vreg = NULL;
+		sensor_board_info_ov5647.num_vreg = 0;
 	}
-	platform_device_register(&msm7x27a_device_csic0);
-	platform_device_register(&msm7x27a_device_csic1);
+	if (machine_is_msm8625_surf() || machine_is_msm8625_evb()) {
+		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);
+	}
 	platform_device_register(&msm7x27a_device_clkctl);
 	platform_device_register(&msm7x27a_device_vfe);
 }
 
 static struct i2c_board_info i2c_camera_devices[] = {
-	#ifdef CONFIG_S5K4E1
 	{
 		I2C_BOARD_INFO("s5k4e1", 0x36),
 		.platform_data = &msm_camera_sensor_s5k4e1_data,
 	},
-	#endif
-	#ifdef CONFIG_WEBCAM_OV9726
 	{
 		I2C_BOARD_INFO("ov9726", 0x10),
 		.platform_data = &msm_camera_sensor_ov9726_data,
 	},
-	#endif
-	#ifdef CONFIG_IMX072
-	{
-		I2C_BOARD_INFO("imx072", 0x34),
-	},
-	#endif
-	#ifdef CONFIG_MT9E013
 	{
 		I2C_BOARD_INFO("mt9e013", 0x6C >> 2),
 		.platform_data = &msm_camera_sensor_mt9e013_data,
 	},
-	#endif
+	{
+		I2C_BOARD_INFO("ov7692", 0x78),
+		.platform_data = &msm_camera_sensor_ov7692_data,
+	},
+	{
+		I2C_BOARD_INFO("ov5647", 0x36 << 1),
+		.platform_data = &msm_camera_sensor_ov5647_data,
+	},
 	{
 		I2C_BOARD_INFO("sc628a", 0x6E),
 	},
@@ -339,13 +412,7 @@
 	gpio_direction_output(QRD_GPIO_CAM_5MP_RESET, 1);
 	gpio_direction_output(QRD_GPIO_CAM_3MP_PWDN, 1);
 }
-
-#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_SKU1_CAM_VGA_SHDN    18
-#define GPIO_SKU1_CAM_VGA_RESET_N 29
+#endif
 
 static void evb_camera_gpio_cfg(void)
 {
@@ -419,6 +486,8 @@
 
 }
 
+#ifndef CONFIG_MSM_CAMERA_V4L2
+
 static void msm_camera_vreg_config(int vreg_en)
 {
 	int rc = vreg_en ?
@@ -889,7 +958,6 @@
 				ARRAY_SIZE(cam_exp_i2c_info));
 }
 
-#ifndef CONFIG_MSM_CAMERA_V4L2
 #define LCD_CAMERA_LDO_2V8 35 /* SKU1&SKU3 2.8V LDO */
 #define SKU3_LCD_CAMERA_LDO_1V8 40 /* SKU3 1.8V LDO */
 
@@ -984,24 +1052,28 @@
 	return rc;
 }
 EXPORT_SYMBOL(lcd_camera_power_onoff);
-#endif
 
 void __init msm7627a_camera_init(void)
 {
+
 #ifndef CONFIG_MSM_CAMERA_V4L2
 	int rc;
+#endif
 
 	pr_debug("msm7627a_camera_init Entered\n");
 	/* 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()) {
+		evb_camera_gpio_cfg();
 		lcd_camera_power_init();
 
+	}
+
+#ifndef CONFIG_MSM_CAMERA_V4L2
 	if (machine_is_msm7627a_qrd1()) {
 		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()) {
-		evb_camera_gpio_cfg();
 		platform_add_devices(camera_devices_evb,
 				ARRAY_SIZE(camera_devices_evb));
 	} else if (machine_is_msm7627a_qrd3())
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index b3d7de4..a83cde0 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -439,6 +439,72 @@
 	.p_addr = 0,
 };
 
+/* 8625 PM platform data */
+static struct msm_pm_platform_data msm8625_pm_data[MSM_PM_SLEEP_MODE_NR * 2] = {
+	/* CORE0 entries */
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 16000,
+					.residency = 20000,
+	},
+
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 12000,
+					.residency = 20000,
+	},
+
+	/* picked latency & redisdency values from 7x30 */
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 500,
+					.residency = 6000,
+	},
+
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 1,
+					.suspend_enabled = 1,
+					.latency = 2,
+					.residency = 10,
+	},
+
+	/* picked latency & redisdency values from 7x30 */
+	[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 0,
+					.suspend_enabled = 0,
+					.latency = 500,
+					.residency = 6000,
+	},
+
+	[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+					.idle_supported = 1,
+					.suspend_supported = 1,
+					.idle_enabled = 1,
+					.suspend_enabled = 1,
+					.latency = 2,
+					.residency = 10,
+	},
+
+};
+
+static struct msm_pm_boot_platform_data msm_pm_8625_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR,
+	.v_addr = MSM_CFG_CTL_BASE,
+};
+
 static struct android_pmem_platform_data android_pmem_adsp_pdata = {
 	.name = "pmem_adsp",
 	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
@@ -774,6 +840,7 @@
 {
 	reserve_info = &msm7627a_reserve_info;
 	msm_reserve();
+	msm_pm_8625_boot_pdata.p_addr = memblock_alloc(SZ_8, SZ_64K);
 }
 
 static void msmqrd_adsp_add_pdev(void)
@@ -1145,6 +1212,11 @@
 		msm_pm_set_platform_data(msm7627a_pm_data,
 				ARRAY_SIZE(msm7627a_pm_data));
 		BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	} else {
+		msm_pm_set_platform_data(msm8625_pm_data,
+				ARRAY_SIZE(msm8625_pm_data));
+		BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata));
+		msm8x25_spm_device_init();
 	}
 
 	msm_fb_add_devices();
diff --git a/arch/arm/mach-msm/cache_erp.c b/arch/arm/mach-msm/cache_erp.c
new file mode 100644
index 0000000..3c317e9
--- /dev/null
+++ b/arch/arm/mach-msm/cache_erp.c
@@ -0,0 +1,475 @@
+/* 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/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/cpu.h>
+#include <mach/msm-krait-l2-accessors.h>
+
+#define CESR_DCTPE		BIT(0)
+#define CESR_DCDPE		BIT(1)
+#define CESR_ICTPE		BIT(2)
+#define CESR_ICDPE		BIT(3)
+#define CESR_DCTE		(BIT(4) | BIT(5))
+#define CESR_ICTE		(BIT(6) | BIT(7))
+#define CESR_TLBMH		BIT(16)
+#define CESR_I_MASK		0x000000CC
+
+#define L2ESR_IND_ADDR		0x204
+#define L2ESYNR0_IND_ADDR	0x208
+#define L2ESYNR1_IND_ADDR	0x209
+#define L2EAR0_IND_ADDR		0x20C
+#define L2EAR1_IND_ADDR		0x20D
+
+#define L2ESR_MPDCD		BIT(0)
+#define L2ESR_MPSLV             BIT(1)
+#define L2ESR_TSESB             BIT(2)
+#define L2ESR_TSEDB             BIT(3)
+#define L2ESR_DSESB             BIT(4)
+#define L2ESR_DSEDB             BIT(5)
+#define L2ESR_MSE		BIT(6)
+#define L2ESR_MPLDREXNOK	BIT(8)
+
+#define L2ESR_CPU_MASK		0x0F
+#define L2ESR_CPU_SHIFT		16
+
+#ifdef CONFIG_MSM_L1_ERR_PANIC
+#define ERP_L1_ERR(a) panic(a)
+#else
+#define ERP_L1_ERR(a) do { } while (0)
+#endif
+
+#ifdef CONFIG_MSM_L2_ERP_PORT_PANIC
+#define ERP_PORT_ERR(a) panic(a)
+#else
+#define ERP_PORT_ERR(a) WARN(1, a)
+#endif
+
+#ifdef CONFIG_MSM_L2_ERP_1BIT_PANIC
+#define ERP_1BIT_ERR(a) panic(a)
+#else
+#define ERP_1BIT_ERR(a) do { } while (0)
+#endif
+
+#ifdef CONFIG_MSM_L2_ERP_2BIT_PANIC
+#define ERP_2BIT_ERR(a) panic(a)
+#else
+#define ERP_2BIT_ERR(a) do { } while (0)
+#endif
+
+#define MODULE_NAME "msm_cache_erp"
+
+struct msm_l1_err_stats {
+	unsigned int dctpe;
+	unsigned int dcdpe;
+	unsigned int ictpe;
+	unsigned int icdpe;
+	unsigned int dcte;
+	unsigned int icte;
+	unsigned int tlbmh;
+};
+
+struct msm_l2_err_stats {
+	unsigned int mpdcd;
+	unsigned int mpslv;
+	unsigned int tsesb;
+	unsigned int tsedb;
+	unsigned int dsesb;
+	unsigned int dsedb;
+	unsigned int mse;
+	unsigned int mplxrexnok;
+};
+
+static DEFINE_PER_CPU(struct msm_l1_err_stats, msm_l1_erp_stats);
+static struct msm_l2_err_stats msm_l2_erp_stats;
+
+static int l1_erp_irq, l2_erp_irq;
+static struct proc_dir_entry *procfs_entry;
+
+static inline unsigned int read_cesr(void)
+{
+	unsigned int cesr;
+	asm volatile ("mrc p15, 7, %0, c15, c0, 1" : "=r" (cesr));
+	return cesr;
+}
+
+static inline void write_cesr(unsigned int cesr)
+{
+	asm volatile ("mcr p15, 7, %[cesr], c15, c0, 1" : : [cesr]"r" (cesr));
+}
+
+static inline unsigned int read_cesynr(void)
+{
+	unsigned int cesynr;
+	asm volatile ("mrc p15, 7, %0, c15, c0, 3" : "=r" (cesynr));
+	return cesynr;
+}
+
+static int proc_read_status(char *page, char **start, off_t off, int count,
+			    int *eof, void *data)
+{
+	struct msm_l1_err_stats *l1_stats;
+	char *p = page;
+	int len, cpu, ret, bytes_left = PAGE_SIZE;
+
+	for_each_present_cpu(cpu) {
+		l1_stats = &per_cpu(msm_l1_erp_stats, cpu);
+
+		ret = snprintf(p, bytes_left,
+			"CPU %d:\n"	\
+			"\tD-cache tag parity errors:\t%u\n"	\
+			"\tD-cache data parity errors:\t%u\n"	\
+			"\tI-cache tag parity errors:\t%u\n"	\
+			"\tI-cache data parity errors:\t%u\n"	\
+			"\tD-cache timing errors:\t\t%u\n"	\
+			"\tI-cache timing errors:\t\t%u\n"	\
+			"\tTLB multi-hit errors:\t\t%u\n\n",	\
+			cpu,
+			l1_stats->dctpe,
+			l1_stats->dcdpe,
+			l1_stats->ictpe,
+			l1_stats->icdpe,
+			l1_stats->dcte,
+			l1_stats->icte,
+			l1_stats->tlbmh);
+		p += ret;
+		bytes_left -= ret;
+	}
+
+	p += snprintf(p, bytes_left,
+			"L2 master port decode errors:\t\t%u\n"	\
+			"L2 master port slave errors:\t\t%u\n"		\
+			"L2 tag soft errors, single-bit:\t\t%u\n"	\
+			"L2 tag soft errors, double-bit:\t\t%u\n"	\
+			"L2 data soft errors, single-bit:\t%u\n"	\
+			"L2 data soft errors, double-bit:\t%u\n"	\
+			"L2 modified soft errors:\t\t%u\n"		\
+			"L2 master port LDREX NOK errors:\t%u\n",
+			msm_l2_erp_stats.mpdcd,
+			msm_l2_erp_stats.mpslv,
+			msm_l2_erp_stats.tsesb,
+			msm_l2_erp_stats.tsedb,
+			msm_l2_erp_stats.dsesb,
+			msm_l2_erp_stats.dsedb,
+			msm_l2_erp_stats.mse,
+			msm_l2_erp_stats.mplxrexnok);
+
+	len = (p - page) - off;
+	if (len < 0)
+		len = 0;
+
+	*eof = (len <= count) ? 1 : 0;
+	*start = page + off;
+
+	return len;
+}
+
+static irqreturn_t msm_l1_erp_irq(int irq, void *dev_id)
+{
+	struct msm_l1_err_stats *l1_stats = dev_id;
+	unsigned int cesr = read_cesr();
+	unsigned int i_cesynr, d_cesynr;
+
+	pr_alert("L1 Error detected on CPU %d!\n", smp_processor_id());
+	pr_alert("\tCESR    = 0x%08x\n", cesr);
+
+	if (cesr & CESR_DCTPE) {
+		pr_alert("D-cache tag parity error\n");
+		l1_stats->dctpe++;
+	}
+
+	if (cesr & CESR_DCDPE) {
+		pr_alert("D-cache data parity error\n");
+		l1_stats->dcdpe++;
+	}
+
+	if (cesr & CESR_ICTPE) {
+		pr_alert("I-cache tag parity error\n");
+		l1_stats->ictpe++;
+	}
+
+	if (cesr & CESR_ICDPE) {
+		pr_alert("I-cache data parity error\n");
+		l1_stats->icdpe++;
+	}
+
+	if (cesr & CESR_DCTE) {
+		pr_alert("D-cache timing error\n");
+		l1_stats->dcte++;
+	}
+
+	if (cesr & CESR_ICTE) {
+		pr_alert("I-cache timing error\n");
+		l1_stats->icte++;
+	}
+
+	if (cesr & CESR_TLBMH) {
+		pr_alert("TLB multi-hit error\n");
+		l1_stats->tlbmh++;
+	}
+
+	if (cesr & (CESR_ICTPE | CESR_ICDPE | CESR_ICTE)) {
+		i_cesynr = read_cesynr();
+		pr_alert("I-side CESYNR = 0x%08x\n", i_cesynr);
+		write_cesr(CESR_I_MASK);
+
+		/*
+		 * Clear the I-side bits from the captured CESR value so that we
+		 * don't accidentally clear any new I-side errors when we do
+		 * the CESR write-clear operation.
+		 */
+		cesr &= ~CESR_I_MASK;
+	}
+
+	if (cesr & (CESR_DCTPE | CESR_DCDPE | CESR_DCTE)) {
+		d_cesynr = read_cesynr();
+		pr_alert("D-side CESYNR = 0x%08x\n", d_cesynr);
+	}
+
+	/* Clear the interrupt bits we processed */
+	write_cesr(cesr);
+
+	ERP_L1_ERR("L1 cache / TLB error detected");
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t msm_l2_erp_irq(int irq, void *dev_id)
+{
+	unsigned int l2esr;
+	unsigned int l2esynr0;
+	unsigned int l2esynr1;
+	unsigned int l2ear0;
+	unsigned int l2ear1;
+	int soft_error = 0;
+	int port_error = 0;
+	int unrecoverable = 0;
+
+	l2esr = get_l2_indirect_reg(L2ESR_IND_ADDR);
+	l2esynr0 = get_l2_indirect_reg(L2ESYNR0_IND_ADDR);
+	l2esynr1 = get_l2_indirect_reg(L2ESYNR1_IND_ADDR);
+	l2ear0 = get_l2_indirect_reg(L2EAR0_IND_ADDR);
+	l2ear1 = get_l2_indirect_reg(L2EAR1_IND_ADDR);
+
+	pr_alert("L2 Error detected!\n");
+	pr_alert("\tL2ESR    = 0x%08x\n", l2esr);
+	pr_alert("\tL2ESYNR0 = 0x%08x\n", l2esynr0);
+	pr_alert("\tL2ESYNR1 = 0x%08x\n", l2esynr1);
+	pr_alert("\tL2EAR0   = 0x%08x\n", l2ear0);
+	pr_alert("\tL2EAR1   = 0x%08x\n", l2ear1);
+	pr_alert("\tCPU bitmap = 0x%x\n", (l2esr >> L2ESR_CPU_SHIFT) &
+						    L2ESR_CPU_MASK);
+
+	if (l2esr & L2ESR_MPDCD) {
+		pr_alert("L2 master port decode error\n");
+		port_error++;
+		msm_l2_erp_stats.mpdcd++;
+	}
+
+	if (l2esr & L2ESR_MPSLV) {
+		pr_alert("L2 master port slave error\n");
+		port_error++;
+		msm_l2_erp_stats.mpslv++;
+	}
+
+	if (l2esr & L2ESR_TSESB) {
+		pr_alert("L2 tag soft error, single-bit\n");
+		soft_error++;
+		msm_l2_erp_stats.tsesb++;
+	}
+
+	if (l2esr & L2ESR_TSEDB) {
+		pr_alert("L2 tag soft error, double-bit\n");
+		soft_error++;
+		unrecoverable++;
+		msm_l2_erp_stats.tsedb++;
+	}
+
+	if (l2esr & L2ESR_DSESB) {
+		pr_alert("L2 data soft error, single-bit\n");
+		soft_error++;
+		msm_l2_erp_stats.dsesb++;
+	}
+
+	if (l2esr & L2ESR_DSEDB) {
+		pr_alert("L2 data soft error, double-bit\n");
+		soft_error++;
+		unrecoverable++;
+		msm_l2_erp_stats.dsedb++;
+	}
+
+	if (l2esr & L2ESR_MSE) {
+		pr_alert("L2 modified soft error\n");
+		soft_error++;
+		msm_l2_erp_stats.mse++;
+	}
+
+	if (l2esr & L2ESR_MPLDREXNOK) {
+		pr_alert("L2 master port LDREX received Normal OK response\n");
+		port_error++;
+		msm_l2_erp_stats.mplxrexnok++;
+	}
+
+	if (port_error)
+		ERP_PORT_ERR("L2 master port error detected");
+
+	if (soft_error && !unrecoverable)
+		ERP_1BIT_ERR("L2 single-bit error detected");
+
+	if (unrecoverable)
+		ERP_2BIT_ERR("L2 double-bit error detected, trouble ahead");
+
+	set_l2_indirect_reg(L2ESR_IND_ADDR, l2esr);
+	return IRQ_HANDLED;
+}
+
+static void enable_erp_irq_callback(void *info)
+{
+	enable_percpu_irq(l1_erp_irq, IRQ_TYPE_LEVEL_HIGH);
+}
+
+static void disable_erp_irq_callback(void *info)
+{
+	disable_percpu_irq(l1_erp_irq);
+}
+
+static int cache_erp_cpu_callback(struct notifier_block *nfb,
+					    unsigned long action, void *hcpu)
+{
+	switch (action & (~CPU_TASKS_FROZEN)) {
+	case CPU_STARTING:
+		enable_erp_irq_callback(NULL);
+		break;
+
+	case CPU_DYING:
+		disable_erp_irq_callback(NULL);
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block cache_erp_cpu_notifier = {
+	.notifier_call = cache_erp_cpu_callback,
+};
+
+static int msm_cache_erp_probe(struct platform_device *pdev)
+{
+	struct resource *r;
+	int ret, cpu;
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "l1_irq");
+
+	if (!r) {
+		pr_err("Could not get L1 resource\n");
+		ret = -ENODEV;
+		goto fail;
+	}
+
+	l1_erp_irq = r->start;
+
+	ret = request_percpu_irq(l1_erp_irq, msm_l1_erp_irq, "MSM_L1",
+				 &msm_l1_erp_stats);
+
+	if (ret) {
+		pr_err("Failed to request the L1 cache error interrupt\n");
+		goto fail;
+	}
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "l2_irq");
+
+	if (!r) {
+		pr_err("Could not get L2 resource\n");
+		ret = -ENODEV;
+		goto fail_l1;
+	}
+
+	l2_erp_irq = r->start;
+	ret = request_irq(l2_erp_irq, msm_l2_erp_irq, 0, "MSM_L2", NULL);
+
+	if (ret) {
+		pr_err("Failed to request the L2 cache error interrupt\n");
+		goto fail_l1;
+	}
+
+	procfs_entry = create_proc_entry("cpu/msm_cache_erp", S_IRUGO, NULL);
+
+	if (!procfs_entry) {
+		pr_err("Failed to create procfs node for cache error reporting\n");
+		ret = -ENODEV;
+		goto fail_l2;
+	}
+
+	get_online_cpus();
+	register_hotcpu_notifier(&cache_erp_cpu_notifier);
+	for_each_cpu(cpu, cpu_online_mask)
+		smp_call_function_single(cpu, enable_erp_irq_callback, NULL, 1);
+	put_online_cpus();
+
+	procfs_entry->read_proc = proc_read_status;
+	return 0;
+
+fail_l2:
+	free_irq(l2_erp_irq, NULL);
+fail_l1:
+	free_percpu_irq(l1_erp_irq, NULL);
+fail:
+	return  ret;
+}
+
+static int msm_cache_erp_remove(struct platform_device *pdev)
+{
+	int cpu;
+	if (procfs_entry)
+		remove_proc_entry("cpu/msm_cache_erp", NULL);
+
+	get_online_cpus();
+	unregister_hotcpu_notifier(&cache_erp_cpu_notifier);
+	for_each_cpu(cpu, cpu_online_mask)
+		smp_call_function_single(cpu, disable_erp_irq_callback, NULL,
+					 1);
+	put_online_cpus();
+
+	free_percpu_irq(l1_erp_irq, NULL);
+
+	disable_irq(l2_erp_irq);
+	free_irq(l2_erp_irq, NULL);
+	return 0;
+}
+
+static struct platform_driver msm_cache_erp_driver = {
+	.probe = msm_cache_erp_probe,
+	.remove = msm_cache_erp_remove,
+	.driver = {
+		.name = MODULE_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_cache_erp_init(void)
+{
+	return platform_driver_register(&msm_cache_erp_driver);
+}
+
+static void __exit msm_cache_erp_exit(void)
+{
+	platform_driver_unregister(&msm_cache_erp_driver);
+}
+
+
+module_init(msm_cache_erp_init);
+module_exit(msm_cache_erp_exit);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM cache error reporting driver");
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
index 8d040fe..24a676f 100644
--- a/arch/arm/mach-msm/clock-7x30.c
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -234,6 +234,7 @@
 		.rate = 19200000,
 		.ops = &clk_ops_tcxo,
 		CLK_INIT(tcxo_clk.c),
+		.warned = true,
 	},
 };
 
@@ -259,6 +260,7 @@
 		.rate = 24576000,
 		.ops = &clk_ops_lpxo,
 		CLK_INIT(lpxo_clk.c),
+		.warned = true,
 	},
 };
 
@@ -272,6 +274,7 @@
 		.rate = 768000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll1_clk.c),
+		.warned = true,
 	},
 };
 
@@ -285,6 +288,7 @@
 		.rate = 806400000, /* TODO: Support scaling */
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll2_clk.c),
+		.warned = true,
 	},
 };
 
@@ -311,6 +315,7 @@
 		.rate = 891000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll4_clk.c),
+		.warned = true,
 	},
 };
 
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 38ea570..98a32c6 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -26,7 +26,6 @@
 #include <mach/msm_iomap.h>
 #include <mach/clk.h>
 #include <mach/rpm-regulator.h>
-#include <mach/msm_xo.h>
 #include <mach/socinfo.h>
 
 #include "clock-local.h"
@@ -468,57 +467,8 @@
  * Clock Descriptions
  */
 
-static struct msm_xo_voter *xo_pxo, *xo_cxo;
-
-static int pxo_clk_enable(struct clk *clk)
-{
-	return msm_xo_mode_vote(xo_pxo, MSM_XO_MODE_ON);
-}
-
-static void pxo_clk_disable(struct clk *clk)
-{
-	msm_xo_mode_vote(xo_pxo, MSM_XO_MODE_OFF);
-}
-
-static struct clk_ops clk_ops_pxo = {
-	.enable = pxo_clk_enable,
-	.disable = pxo_clk_disable,
-	.is_local = local_clk_is_local,
-};
-
-static struct fixed_clk pxo_clk = {
-	.c = {
-		.dbg_name = "pxo_clk",
-		.rate = 27000000,
-		.ops = &clk_ops_pxo,
-		CLK_INIT(pxo_clk.c),
-	},
-};
-
-static int cxo_clk_enable(struct clk *clk)
-{
-	return msm_xo_mode_vote(xo_cxo, MSM_XO_MODE_ON);
-}
-
-static void cxo_clk_disable(struct clk *clk)
-{
-	msm_xo_mode_vote(xo_cxo, MSM_XO_MODE_OFF);
-}
-
-static struct clk_ops clk_ops_cxo = {
-	.enable = cxo_clk_enable,
-	.disable = cxo_clk_disable,
-	.is_local = local_clk_is_local,
-};
-
-static struct fixed_clk cxo_clk = {
-	.c = {
-		.dbg_name = "cxo_clk",
-		.rate = 19200000,
-		.ops = &clk_ops_cxo,
-		CLK_INIT(cxo_clk.c),
-	},
-};
+DEFINE_CLK_RPM_BRANCH(pxo_clk, pxo_a_clk, PXO, 27000000);
+DEFINE_CLK_RPM_BRANCH(cxo_clk, cxo_a_clk, CXO, 19200000);
 
 static struct pll_clk pll2_clk = {
 	.mode_reg = MM_PLL1_MODE_REG,
@@ -528,6 +478,7 @@
 		.rate = 800000000,
 		.ops = &clk_ops_pll,
 		CLK_INIT(pll2_clk.c),
+		.warned = true,
 	},
 };
 
@@ -541,6 +492,7 @@
 		.vdd_class = &vdd_sr2_pll,
 		.fmax[VDD_SR2_PLL_ON] = ULONG_MAX,
 		CLK_INIT(pll3_clk.c),
+		.warned = true,
 	},
 };
 
@@ -554,6 +506,7 @@
 		.rate = 393216000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll4_clk.c),
+		.warned = true,
 	},
 };
 
@@ -567,6 +520,7 @@
 		.rate = 384000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll8_clk.c),
+		.warned = true,
 	},
 };
 
@@ -580,6 +534,7 @@
 		.rate = 480000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll14_clk.c),
+		.warned = true,
 	},
 };
 
@@ -591,6 +546,7 @@
 		.rate = 975000000,
 		.ops = &clk_ops_pll,
 		CLK_INIT(pll15_clk.c),
+		.warned = true,
 	},
 };
 
@@ -4896,6 +4852,8 @@
 };
 
 static struct clk_lookup msm_clocks_8064[] = {
+	CLK_LOOKUP("xo",		cxo_a_clk.c,	""),
+	CLK_LOOKUP("xo",		pxo_a_clk.c,	""),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"msm_otg"),
 	CLK_LOOKUP("cxo",		cxo_clk.c,	"wcnss_wlan.0"),
 	CLK_LOOKUP("cxo",		cxo_clk.c,	"pil_riva"),
@@ -5175,6 +5133,8 @@
 };
 
 static struct clk_lookup msm_clocks_8960[] = {
+	CLK_LOOKUP("xo",		cxo_a_clk.c,	""),
+	CLK_LOOKUP("xo",		pxo_a_clk.c,	""),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"msm_otg"),
 	CLK_LOOKUP("cxo",		cxo_clk.c,	"wcnss_wlan.0"),
 	CLK_LOOKUP("cxo",		cxo_clk.c,	"pil_riva"),
@@ -5693,6 +5653,8 @@
 /* Local clock driver initialization. */
 static void __init msm8960_clock_init(void)
 {
+	/* Keep PXO on whenever APPS cpu is active */
+	clk_prepare_enable(&pxo_a_clk.c);
 
 	if (cpu_is_apq8064()) {
 		vdd_sr2_pll.set_vdd = set_vdd_sr2_pll_8064;
@@ -5701,17 +5663,6 @@
 		vdd_sr2_pll.set_vdd = set_vdd_sr2_pll_8930;
 	}
 
-	xo_pxo = msm_xo_get(MSM_XO_PXO, "clock-8960");
-	if (IS_ERR(xo_pxo)) {
-		pr_err("%s: msm_xo_get(PXO) failed.\n", __func__);
-		BUG();
-	}
-	xo_cxo = msm_xo_get(MSM_XO_CXO, "clock-8960");
-	if (IS_ERR(xo_cxo)) {
-		pr_err("%s: msm_xo_get(CXO) failed.\n", __func__);
-		BUG();
-	}
-
 	/*
 	 * Change the freq tables for and voltage requirements for
 	 * clocks which differ between 8960 and 8064.
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 4fa81b6..4da4454 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -24,7 +24,6 @@
 
 #include <mach/msm_iomap.h>
 #include <mach/clk.h>
-#include <mach/msm_xo.h>
 #include <mach/scm-io.h>
 #include <mach/rpm.h>
 #include <mach/rpm-regulator.h>
@@ -298,62 +297,8 @@
 	.fmax[VDD_DIG_##l2] = (f2), \
 	.fmax[VDD_DIG_##l3] = (f3)
 
-static struct msm_xo_voter *xo_pxo, *xo_cxo;
-
-static bool xo_clk_is_local(struct clk *clk)
-{
-	return false;
-}
-
-static int pxo_clk_enable(struct clk *clk)
-{
-	return msm_xo_mode_vote(xo_pxo, MSM_XO_MODE_ON);
-}
-
-static void pxo_clk_disable(struct clk *clk)
-{
-	msm_xo_mode_vote(xo_pxo, MSM_XO_MODE_OFF);
-}
-
-static struct clk_ops clk_ops_pxo = {
-	.enable = pxo_clk_enable,
-	.disable = pxo_clk_disable,
-	.is_local = xo_clk_is_local,
-};
-
-static struct fixed_clk pxo_clk = {
-	.c = {
-		.dbg_name = "pxo_clk",
-		.rate = 27000000,
-		.ops = &clk_ops_pxo,
-		CLK_INIT(pxo_clk.c),
-	},
-};
-
-static int cxo_clk_enable(struct clk *clk)
-{
-	return msm_xo_mode_vote(xo_cxo, MSM_XO_MODE_ON);
-}
-
-static void cxo_clk_disable(struct clk *clk)
-{
-	msm_xo_mode_vote(xo_cxo, MSM_XO_MODE_OFF);
-}
-
-static struct clk_ops clk_ops_cxo = {
-	.enable = cxo_clk_enable,
-	.disable = cxo_clk_disable,
-	.is_local = xo_clk_is_local,
-};
-
-static struct fixed_clk cxo_clk = {
-	.c = {
-		.dbg_name = "cxo_clk",
-		.rate = 19200000,
-		.ops = &clk_ops_cxo,
-		CLK_INIT(cxo_clk.c),
-	},
-};
+DEFINE_CLK_RPM_BRANCH(pxo_clk, pxo_a_clk, PXO, 27000000);
+DEFINE_CLK_RPM_BRANCH(cxo_clk, cxo_a_clk, CXO, 19200000);
 
 static struct pll_vote_clk pll8_clk = {
 	.en_reg = BB_PLL_ENA_SC0_REG,
@@ -365,6 +310,7 @@
 		.rate = 384000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll8_clk.c),
+		.warned = true,
 	},
 };
 
@@ -376,6 +322,7 @@
 		.rate = 800000000,
 		.ops = &clk_ops_pll,
 		CLK_INIT(pll2_clk.c),
+		.warned = true,
 	},
 };
 
@@ -387,6 +334,7 @@
 		.rate = 0, /* TODO: Detect rate dynamically */
 		.ops = &clk_ops_pll,
 		CLK_INIT(pll3_clk.c),
+		.warned = true,
 	},
 };
 
@@ -425,6 +373,7 @@
 		.rate = 540672000,
 		.ops = &clk_ops_pll4,
 		CLK_INIT(pll4_clk.c),
+		.warned = true,
 	},
 };
 
@@ -3547,7 +3496,9 @@
 };
 
 static struct clk_lookup msm_clocks_8x60[] = {
-	CLK_LOOKUP("cxo",		cxo_clk.c,	NULL),
+	CLK_LOOKUP("xo",		cxo_clk.c,	""),
+	CLK_LOOKUP("xo",		cxo_a_clk.c,	""),
+	CLK_LOOKUP("xo",		pxo_a_clk.c,	""),
 	CLK_LOOKUP("xo",		pxo_clk.c,	"pil_modem"),
 	CLK_LOOKUP("pll4",		pll4_clk.c,	"pil_qdsp6v3"),
 	CLK_LOOKUP("measure",		measure_clk.c,	"debug"),
@@ -3888,18 +3839,9 @@
 /* Local clock driver initialization. */
 static void __init msm8660_clock_init(void)
 {
-	xo_pxo = msm_xo_get(MSM_XO_PXO, "clock-8x60");
-	if (IS_ERR(xo_pxo)) {
-		pr_err("%s: msm_xo_get(PXO) failed.\n", __func__);
-		BUG();
-	}
-	xo_cxo = msm_xo_get(MSM_XO_CXO, "clock-8x60");
-	if (IS_ERR(xo_cxo)) {
-		pr_err("%s: msm_xo_get(CXO) failed.\n", __func__);
-		BUG();
-	}
-
 	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
+	/* Keep PXO on whenever APPS cpu is active */
+	clk_prepare_enable(&pxo_a_clk.c);
 	/* Initialize clock registers. */
 	reg_init();
 
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index ca14afa..3e059b6 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -25,7 +25,6 @@
 
 #include <mach/msm_iomap.h>
 #include <mach/clk.h>
-#include <mach/msm_xo.h>
 #include <mach/rpm-9615.h>
 #include <mach/rpm-regulator.h>
 
@@ -208,32 +207,7 @@
  * Clock Descriptions
  */
 
-static struct msm_xo_voter *xo_cxo;
-
-static int cxo_clk_enable(struct clk *clk)
-{
-	return msm_xo_mode_vote(xo_cxo, MSM_XO_MODE_ON);
-}
-
-static void cxo_clk_disable(struct clk *clk)
-{
-	msm_xo_mode_vote(xo_cxo, MSM_XO_MODE_OFF);
-}
-
-static struct clk_ops clk_ops_cxo = {
-	.enable = cxo_clk_enable,
-	.disable = cxo_clk_disable,
-	.is_local = local_clk_is_local,
-};
-
-static struct fixed_clk cxo_clk = {
-	.c = {
-		.dbg_name = "cxo_clk",
-		.rate = 19200000,
-		.ops = &clk_ops_cxo,
-		CLK_INIT(cxo_clk.c),
-	},
-};
+DEFINE_CLK_RPM_BRANCH(cxo_clk, cxo_a_clk, CXO, 19200000);
 
 static DEFINE_SPINLOCK(soft_vote_lock);
 
@@ -294,6 +268,7 @@
 		.rate = 276000000,
 		.ops = &clk_ops_pll_acpu_vote,
 		CLK_INIT(pll0_clk.c),
+		.warned = true,
 	},
 };
 
@@ -308,6 +283,7 @@
 		.rate = 276000000,
 		.ops = &clk_ops_pll_acpu_vote,
 		CLK_INIT(pll0_acpu_clk.c),
+		.warned = true,
 	},
 };
 
@@ -321,6 +297,7 @@
 		.rate = 393216000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll4_clk.c),
+		.warned = true,
 	},
 };
 
@@ -338,6 +315,7 @@
 		.rate = 384000000,
 		.ops = &clk_ops_pll_acpu_vote,
 		CLK_INIT(pll8_clk.c),
+		.warned = true,
 	},
 };
 
@@ -352,6 +330,7 @@
 		.rate = 384000000,
 		.ops = &clk_ops_pll_acpu_vote,
 		CLK_INIT(pll8_acpu_clk.c),
+		.warned = true,
 	},
 };
 
@@ -362,6 +341,7 @@
 		.rate = 440000000,
 		.ops = &clk_ops_pll,
 		CLK_INIT(pll9_acpu_clk.c),
+		.warned = true,
 	},
 };
 
@@ -375,6 +355,7 @@
 		.rate = 480000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll14_clk.c),
+		.warned = true,
 	},
 };
 
@@ -1380,12 +1361,7 @@
 static DEFINE_CLK_VOTER(dfab_sps_clk, &dfab_clk.c);
 static DEFINE_CLK_VOTER(dfab_bam_dmux_clk, &dfab_clk.c);
 static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c);
-
-/*
- * TODO: replace dummy_clk below with ebi1_clk.c once the
- * bus driver starts voting on ebi1 rates.
- */
-static DEFINE_CLK_VOTER(ebi1_adm_clk,    &dummy_clk);
+static DEFINE_CLK_VOTER(ebi1_adm_clk, &ebi1_clk.c);
 
 #ifdef CONFIG_DEBUG_FS
 struct measure_sel {
@@ -1623,6 +1599,7 @@
 };
 
 static struct clk_lookup msm_clocks_9615[] = {
+	CLK_LOOKUP("xo",	cxo_a_clk.c,	""),
 	CLK_LOOKUP("xo",	cxo_clk.c,	"msm_otg"),
 	CLK_LOOKUP("xo",	cxo_clk.c,	"BAM_RMNT"),
 	CLK_LOOKUP("pll0",	pll0_clk.c,	NULL),
@@ -1733,11 +1710,6 @@
 	CLK_LOOKUP("q6sw_clk",		q6sw_clk, NULL),
 	CLK_LOOKUP("q6fw_clk",		q6fw_clk, NULL),
 	CLK_LOOKUP("q6_func_clk",	q6_func_clk, NULL),
-
-	/* TODO: Make this real when RPM's ready. */
-	CLK_DUMMY("ebi1_msmbus_clk",	ebi1_msmbus_clk.c, NULL, OFF),
-	CLK_DUMMY("mem_clk",		ebi1_adm_clk.c, "msm_dmov", OFF),
-
 };
 
 static void set_fsm_mode(void __iomem *mode_reg)
@@ -1861,13 +1833,9 @@
 /* Local clock driver initialization. */
 static void __init msm9615_clock_init(void)
 {
-	xo_cxo = msm_xo_get(MSM_XO_CXO, "clock-9615");
-	if (IS_ERR(xo_cxo)) {
-		pr_err("%s: msm_xo_get(CXO) failed.\n", __func__);
-		BUG();
-	}
-
 	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
+	/* Keep CXO on whenever APPS cpu is active */
+	clk_prepare_enable(&cxo_a_clk.c);
 
 	clk_ops_pll.enable = sr_pll_clk_enable;
 
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index 411a272..31be6af 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -92,9 +92,9 @@
 	int rc = 0;
 
 	if (val)
-		rc = clk_enable(clock);
+		rc = clk_prepare_enable(clock);
 	else
-		clk_disable(clock);
+		clk_disable_unprepare(clock);
 
 	return rc;
 }
diff --git a/arch/arm/mach-msm/clock-pcom-lookup.c b/arch/arm/mach-msm/clock-pcom-lookup.c
index f43a468..a0defe3 100644
--- a/arch/arm/mach-msm/clock-pcom-lookup.c
+++ b/arch/arm/mach-msm/clock-pcom-lookup.c
@@ -320,6 +320,8 @@
 	CLK_LOOKUP("cam_clk",		cam_m_clk.c,	"0-0036"),
 	CLK_LOOKUP("cam_clk",		cam_m_clk.c,	"0-001b"),
 	CLK_LOOKUP("cam_clk",		cam_m_clk.c,	"0-0010"),
+	CLK_LOOKUP("cam_clk",		cam_m_clk.c,	"0-0078"),
+	CLK_LOOKUP("cam_clk",		cam_m_clk.c,	"0-006c"),
 	CLK_LOOKUP("csi_clk",		csi0_clk.c,	"msm_camera_ov9726.0"),
 	CLK_LOOKUP("csi_pclk",		csi0_p_clk.c,	"msm_camera_ov9726.0"),
 	CLK_LOOKUP("csi_vfe_clk",	csi0_vfe_clk.c,	"msm_camera_ov9726.0"),
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index f6b2b45..b5b6ca7 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -38,6 +38,7 @@
 	{50, 960000000},
 	{52, 1008000000},
 	{62, 1200000000},
+	{63, 1209600000},
 	{0, 0},
 };
 
diff --git a/arch/arm/mach-msm/clock-rpm.h b/arch/arm/mach-msm/clock-rpm.h
index 2f4a17c..b0d5693 100644
--- a/arch/arm/mach-msm/clock-rpm.h
+++ b/arch/arm/mach-msm/clock-rpm.h
@@ -67,36 +67,38 @@
 		}, \
 	};
 
-#define DEFINE_CLK_RPM_BRANCH(name, active, r_id, rate) \
+#define DEFINE_CLK_RPM_BRANCH(name, active, r_id, r) \
 	static struct rpm_clk active; \
 	static struct rpm_clk name = { \
 		.rpm_clk_id = MSM_RPM_ID_##r_id##_CLK, \
 		.rpm_status_id = MSM_RPM_STATUS_ID_##r_id##_CLK, \
 		.peer = &active, \
-		.last_set_khz = ((rate) / 1000), \
-		.last_set_sleep_khz = ((rate) / 1000), \
+		.last_set_khz = ((r) / 1000), \
+		.last_set_sleep_khz = ((r) / 1000), \
 		.branch = true, \
 		.c = { \
 			.ops = &clk_ops_rpm_branch, \
 			.flags = CLKFLAG_SKIP_AUTO_OFF, \
 			.dbg_name = #name, \
-			.rate = (rate), \
+			.rate = (r), \
 			CLK_INIT(name.c), \
+			.warned = true, \
 		}, \
 	}; \
 	static struct rpm_clk active = { \
 		.rpm_clk_id = MSM_RPM_ID_##r_id##_CLK, \
 		.rpm_status_id = MSM_RPM_STATUS_ID_##r_id##_CLK, \
 		.peer = &name, \
-		.last_set_khz = ((rate) / 1000), \
+		.last_set_khz = ((r) / 1000), \
 		.active_only = true, \
 		.branch = true, \
 		.c = { \
 			.ops = &clk_ops_rpm_branch, \
 			.flags = CLKFLAG_SKIP_AUTO_OFF, \
 			.dbg_name = #active, \
-			.rate = (rate), \
+			.rate = (r), \
 			CLK_INIT(active.c), \
+			.warned = true, \
 		}, \
 	};
 
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 5b89fa9..7f0cafd 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -127,6 +127,41 @@
 	unvote_vdd_level(clk->vdd_class, level);
 }
 
+int clk_prepare(struct clk *clk)
+{
+	int ret = 0;
+	struct clk *parent;
+	if (!clk)
+		return 0;
+
+	mutex_lock(&clk->prepare_lock);
+	if (clk->prepare_count == 0) {
+		parent = clk_get_parent(clk);
+
+		ret = clk_prepare(parent);
+		if (ret)
+			goto out;
+		ret = clk_prepare(clk->depends);
+		if (ret)
+			goto err_prepare_depends;
+
+		if (clk->ops->prepare)
+			ret = clk->ops->prepare(clk);
+		if (ret)
+			goto err_prepare_clock;
+	}
+	clk->prepare_count++;
+out:
+	mutex_unlock(&clk->prepare_lock);
+	return ret;
+err_prepare_clock:
+	clk_unprepare(clk->depends);
+err_prepare_depends:
+	clk_unprepare(parent);
+	goto out;
+}
+EXPORT_SYMBOL(clk_prepare);
+
 /*
  * Standard clock functions defined in include/linux/clk.h
  */
@@ -140,6 +175,10 @@
 		return 0;
 
 	spin_lock_irqsave(&clk->lock, flags);
+	if (WARN(!clk->warned && !clk->prepare_count,
+				"%s: Don't call enable on unprepared clocks\n",
+				clk->dbg_name))
+		clk->warned = true;
 	if (clk->count == 0) {
 		parent = clk_get_parent(clk);
 
@@ -193,6 +232,11 @@
 		return;
 
 	spin_lock_irqsave(&clk->lock, flags);
+	if (WARN(!clk->warned && !clk->prepare_count,
+				"%s: Never called prepare or calling disable "
+				"after unprepare\n",
+				clk->dbg_name))
+		clk->warned = true;
 	if (WARN(clk->count == 0, "%s is unbalanced", clk->dbg_name))
 		goto out;
 	if (clk->count == 1) {
@@ -210,6 +254,37 @@
 }
 EXPORT_SYMBOL(clk_disable);
 
+void clk_unprepare(struct clk *clk)
+{
+	if (!clk)
+		return;
+
+	mutex_lock(&clk->prepare_lock);
+	if (!clk->prepare_count) {
+		if (WARN(!clk->warned, "%s is unbalanced (prepare)",
+				clk->dbg_name))
+			clk->warned = true;
+		goto out;
+	}
+	if (clk->prepare_count == 1) {
+		struct clk *parent = clk_get_parent(clk);
+
+		if (WARN(!clk->warned && clk->count,
+			"%s: Don't call unprepare when the clock is enabled\n",
+				clk->dbg_name))
+			clk->warned = true;
+
+		if (clk->ops->unprepare)
+			clk->ops->unprepare(clk);
+		clk_unprepare(clk->depends);
+		clk_unprepare(parent);
+	}
+	clk->prepare_count--;
+out:
+	mutex_unlock(&clk->prepare_lock);
+}
+EXPORT_SYMBOL(clk_unprepare);
+
 int clk_reset(struct clk *clk, enum clk_reset_action action)
 {
 	if (!clk->ops->reset)
@@ -335,7 +410,7 @@
 		if (clk->ops->handoff && !(clk->flags & CLKFLAG_HANDOFF_RATE)) {
 			if (clk->ops->handoff(clk)) {
 				clk->flags |= CLKFLAG_HANDOFF_RATE;
-				clk_enable(clk);
+				clk_prepare_enable(clk);
 			}
 		}
 	}
@@ -372,11 +447,11 @@
 			}
 			spin_unlock_irqrestore(&clk->lock, flags);
 			/*
-			 * Calling clk_disable() outside the lock is safe since
+			 * Calling this outside the lock is safe since
 			 * it doesn't need to be atomic with the flag change.
 			 */
 			if (handoff)
-				clk_disable(clk);
+				clk_disable_unprepare(clk);
 		}
 	}
 	pr_info("clock_late_init() disabled %d unused clocks\n", count);
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 4210bd9..bce2e0f 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -21,6 +21,7 @@
 #include <linux/list.h>
 #include <linux/clkdev.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 
 #include <mach/clk.h>
 
@@ -63,8 +64,10 @@
 	}
 
 struct clk_ops {
+	int (*prepare)(struct clk *clk);
 	int (*enable)(struct clk *clk);
 	void (*disable)(struct clk *clk);
+	void (*unprepare)(struct clk *clk);
 	void (*auto_off)(struct clk *clk);
 	void (*enable_hwcg)(struct clk *clk);
 	void (*disable_hwcg)(struct clk *clk);
@@ -85,11 +88,14 @@
 
 /**
  * struct clk
+ * @prepare_count: prepare refcount
+ * @prepare_lock: protects clk_prepare()/clk_unprepare() path and @prepare_count
  * @count: enable refcount
  * @lock: protects clk_enable()/clk_disable() path and @count
  * @depends: non-direct parent of clock to enable when this clock is enabled
  * @vdd_class: voltage scaling requirement class
  * @fmax: maximum frequency in Hz supported at each voltage level
+ * @warned: true if the clock has warned of incorrect usage, false otherwise
  */
 struct clk {
 	uint32_t flags;
@@ -103,12 +109,16 @@
 	struct list_head children;
 	struct list_head siblings;
 
+	bool warned;
 	unsigned count;
 	spinlock_t lock;
+	unsigned prepare_count;
+	struct mutex prepare_lock;
 };
 
 #define CLK_INIT(name) \
 	.lock = __SPIN_LOCK_UNLOCKED((name).lock), \
+	.prepare_lock = __MUTEX_INITIALIZER((name).prepare_lock), \
 	.children = LIST_HEAD_INIT((name).children), \
 	.siblings = LIST_HEAD_INIT((name).siblings)
 
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 657751b..6a3a10c 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -636,6 +636,12 @@
 		.name	= "peripheral_status_irq",
 		.flags	= IORESOURCE_IRQ,
 	},
+	{
+		.start	= MSM_GPIO_TO_INT(88),
+		.end	= MSM_GPIO_TO_INT(88),
+		.name	= "wakeup_irq",
+		.flags	= IORESOURCE_IRQ,
+	},
 };
 
 static u64 dma_mask = DMA_BIT_MASK(32);
@@ -1386,9 +1392,14 @@
 	},
 };
 
+static struct smd_subsystem_restart_config smd_ssr_config = {
+	.disable_smsm_reset_handshake = 1,
+};
+
 static struct smd_platform smd_platform_data = {
 	.num_ss_configs = ARRAY_SIZE(smd_config_list),
 	.smd_ss_configs = smd_config_list,
+	.smd_ssr_config = &smd_ssr_config,
 };
 
 struct platform_device msm_device_smd_apq8064 = {
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 718cfb1..4c02215 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1090,9 +1090,14 @@
 	},
 };
 
+static struct smd_subsystem_restart_config smd_ssr_config = {
+	.disable_smsm_reset_handshake = 1,
+};
+
 static struct smd_platform smd_platform_data = {
 	.num_ss_configs = ARRAY_SIZE(smd_config_list),
 	.smd_ss_configs = smd_config_list,
+	.smd_ssr_config = &smd_ssr_config,
 };
 
 
diff --git a/arch/arm/mach-msm/devices-iommu.c b/arch/arm/mach-msm/devices-iommu.c
index 3d2d2e7..057a006 100644
--- a/arch/arm/mach-msm/devices-iommu.c
+++ b/arch/arm/mach-msm/devices-iommu.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
@@ -391,6 +391,7 @@
 	.id = 0,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &jpegd_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_jpegd_resources),
 	.resource = msm_iommu_jpegd_resources,
@@ -401,6 +402,7 @@
 	.id = 1,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &vpe_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_vpe_resources),
 	.resource = msm_iommu_vpe_resources,
@@ -411,6 +413,7 @@
 	.id = 2,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &mdp0_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_mdp0_resources),
 	.resource = msm_iommu_mdp0_resources,
@@ -421,6 +424,7 @@
 	.id = 3,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &mdp1_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_mdp1_resources),
 	.resource = msm_iommu_mdp1_resources,
@@ -431,6 +435,7 @@
 	.id = 4,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &rot_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_rot_resources),
 	.resource = msm_iommu_rot_resources,
@@ -441,6 +446,7 @@
 	.id = 5,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &ijpeg_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_ijpeg_resources),
 	.resource = msm_iommu_ijpeg_resources,
@@ -451,6 +457,7 @@
 	.id = 6,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &vfe_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_vfe_resources),
 	.resource = msm_iommu_vfe_resources,
@@ -461,6 +468,7 @@
 	.id = 7,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &vcodec_a_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_vcodec_a_resources),
 	.resource = msm_iommu_vcodec_a_resources,
@@ -471,6 +479,7 @@
 	.id = 8,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &vcodec_b_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_vcodec_b_resources),
 	.resource = msm_iommu_vcodec_b_resources,
@@ -481,6 +490,7 @@
 	.id = 9,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &gfx3d_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_gfx3d_resources),
 	.resource = msm_iommu_gfx3d_resources,
@@ -491,6 +501,7 @@
 	.id = 10,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &gfx3d1_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_gfx3d1_resources),
 	.resource = msm_iommu_gfx3d1_resources,
@@ -501,6 +512,7 @@
 	.id = 10,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &gfx2d0_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_gfx2d0_resources),
 	.resource = msm_iommu_gfx2d0_resources,
@@ -511,6 +523,7 @@
 	.id = 11,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &gfx2d1_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_gfx2d1_resources),
 	.resource = msm_iommu_gfx2d1_resources,
@@ -521,6 +534,7 @@
 	.id = 11,
 	.dev = {
 		.parent = &msm_root_iommu_dev.dev,
+		.platform_data = &vcap_iommu,
 	},
 	.num_resources = ARRAY_SIZE(msm_iommu_vcap_resources),
 	.resource = msm_iommu_vcap_resources,
@@ -683,6 +697,7 @@
 	.id = 0,
 	.dev = {
 		.parent = &msm_device_iommu_jpegd.dev,
+		.platform_data = &jpegd_src_ctx,
 	},
 };
 
@@ -691,6 +706,7 @@
 	.id = 1,
 	.dev = {
 		.parent = &msm_device_iommu_jpegd.dev,
+		.platform_data = &jpegd_dst_ctx,
 	},
 };
 
@@ -699,6 +715,7 @@
 	.id = 2,
 	.dev = {
 		.parent = &msm_device_iommu_vpe.dev,
+		.platform_data = &vpe_src_ctx,
 	},
 };
 
@@ -707,6 +724,7 @@
 	.id = 3,
 	.dev = {
 		.parent = &msm_device_iommu_vpe.dev,
+		.platform_data = &vpe_dst_ctx,
 	},
 };
 
@@ -715,6 +733,7 @@
 	.id = 4,
 	.dev = {
 		.parent = &msm_device_iommu_mdp0.dev,
+		.platform_data = &mdp_vg1_ctx,
 	},
 };
 
@@ -723,6 +742,7 @@
 	.id = 5,
 	.dev = {
 		.parent = &msm_device_iommu_mdp0.dev,
+		.platform_data = &mdp_rgb1_ctx,
 	},
 };
 
@@ -731,6 +751,7 @@
 	.id = 6,
 	.dev = {
 		.parent = &msm_device_iommu_mdp1.dev,
+		.platform_data = &mdp_vg2_ctx,
 	},
 };
 
@@ -739,6 +760,7 @@
 	.id = 7,
 	.dev = {
 		.parent = &msm_device_iommu_mdp1.dev,
+		.platform_data = &mdp_rgb2_ctx,
 	},
 };
 
@@ -747,6 +769,7 @@
 	.id = 8,
 	.dev = {
 		.parent = &msm_device_iommu_rot.dev,
+		.platform_data = &rot_src_ctx,
 	},
 };
 
@@ -755,6 +778,7 @@
 	.id = 9,
 	.dev = {
 		.parent = &msm_device_iommu_rot.dev,
+		.platform_data = &rot_dst_ctx,
 	},
 };
 
@@ -763,6 +787,7 @@
 	.id = 10,
 	.dev = {
 		.parent = &msm_device_iommu_ijpeg.dev,
+		.platform_data = &ijpeg_src_ctx,
 	},
 };
 
@@ -771,6 +796,7 @@
 	.id = 11,
 	.dev = {
 		.parent = &msm_device_iommu_ijpeg.dev,
+		.platform_data = &ijpeg_dst_ctx,
 	},
 };
 
@@ -779,6 +805,7 @@
 	.id = 12,
 	.dev = {
 		.parent = &msm_device_iommu_vfe.dev,
+		.platform_data = &vfe_imgwr_ctx,
 	},
 };
 
@@ -787,6 +814,7 @@
 	.id = 13,
 	.dev = {
 		.parent = &msm_device_iommu_vfe.dev,
+		.platform_data = &vfe_misc_ctx,
 	},
 };
 
@@ -795,6 +823,7 @@
 	.id = 14,
 	.dev = {
 		.parent = &msm_device_iommu_vcodec_a.dev,
+		.platform_data = &vcodec_a_stream_ctx,
 	},
 };
 
@@ -803,6 +832,7 @@
 	.id = 15,
 	.dev = {
 		.parent = &msm_device_iommu_vcodec_a.dev,
+		.platform_data = &vcodec_a_mm1_ctx,
 	},
 };
 
@@ -811,6 +841,7 @@
 	.id = 16,
 	.dev = {
 		.parent = &msm_device_iommu_vcodec_b.dev,
+		.platform_data = &vcodec_b_mm2_ctx,
 	},
 };
 
@@ -819,6 +850,7 @@
 	.id = 17,
 	.dev = {
 		.parent = &msm_device_iommu_gfx3d.dev,
+		.platform_data = &gfx3d_user_ctx,
 	},
 };
 
@@ -827,6 +859,7 @@
 	.id = 18,
 	.dev = {
 		.parent = &msm_device_iommu_gfx3d.dev,
+		.platform_data = &gfx3d_priv_ctx,
 	},
 };
 
@@ -835,6 +868,7 @@
 	.id = 19,
 	.dev = {
 		.parent = &msm_device_iommu_gfx3d1.dev,
+		.platform_data = &gfx3d1_user_ctx,
 	},
 };
 
@@ -843,6 +877,7 @@
 	.id = 20,
 	.dev = {
 		.parent = &msm_device_iommu_gfx3d1.dev,
+		.platform_data = &gfx3d1_priv_ctx,
 	},
 };
 
@@ -851,6 +886,7 @@
 	.id = 19,
 	.dev = {
 		.parent = &msm_device_iommu_gfx2d0.dev,
+		.platform_data = &gfx2d0_2d0_ctx,
 	},
 };
 
@@ -859,6 +895,7 @@
 	.id = 20,
 	.dev = {
 		.parent = &msm_device_iommu_gfx2d1.dev,
+		.platform_data = &gfx2d1_2d1_ctx,
 	},
 };
 
@@ -867,6 +904,7 @@
 	.id = 21,
 	.dev = {
 		.parent = &msm_device_iommu_vcap.dev,
+		.platform_data = &vcap_vc_ctx,
 	},
 };
 
@@ -875,11 +913,11 @@
 	.id = 22,
 	.dev = {
 		.parent = &msm_device_iommu_vcap.dev,
+		.platform_data = &vcap_vp_ctx,
 	},
 };
 
 static struct platform_device *msm_iommu_common_devs[] = {
-	&msm_device_iommu_jpegd,
 	&msm_device_iommu_vpe,
 	&msm_device_iommu_mdp0,
 	&msm_device_iommu_mdp1,
@@ -901,32 +939,11 @@
 	&msm_device_iommu_vcap,
 };
 
-static struct msm_iommu_dev *msm_iommu_common_data[] = {
-	&jpegd_iommu,
-	&vpe_iommu,
-	&mdp0_iommu,
-	&mdp1_iommu,
-	&rot_iommu,
-	&ijpeg_iommu,
-	&vfe_iommu,
-	&vcodec_a_iommu,
-	&vcodec_b_iommu,
-	&gfx3d_iommu,
-};
-
-static struct msm_iommu_dev *msm_iommu_gfx2d_data[] = {
-	&gfx2d0_iommu,
-	&gfx2d1_iommu,
-};
-
-static struct msm_iommu_dev *msm_iommu_8064_data[] = {
-	&gfx3d1_iommu,
-	&vcap_iommu,
+static struct platform_device *msm_iommu_jpegd_devs[] = {
+	&msm_device_iommu_jpegd,
 };
 
 static struct platform_device *msm_iommu_common_ctx_devs[] = {
-	&msm_device_jpegd_src_ctx,
-	&msm_device_jpegd_dst_ctx,
 	&msm_device_vpe_src_ctx,
 	&msm_device_vpe_dst_ctx,
 	&msm_device_mdp_vg1_ctx,
@@ -958,102 +975,11 @@
 	&msm_device_vcap_vp_ctx,
 };
 
-static struct msm_iommu_ctx_dev *msm_iommu_common_ctx_data[] = {
-	&jpegd_src_ctx,
-	&jpegd_dst_ctx,
-	&vpe_src_ctx,
-	&vpe_dst_ctx,
-	&mdp_vg1_ctx,
-	&mdp_rgb1_ctx,
-	&mdp_vg2_ctx,
-	&mdp_rgb2_ctx,
-	&rot_src_ctx,
-	&rot_dst_ctx,
-	&ijpeg_src_ctx,
-	&ijpeg_dst_ctx,
-	&vfe_imgwr_ctx,
-	&vfe_misc_ctx,
-	&vcodec_a_stream_ctx,
-	&vcodec_a_mm1_ctx,
-	&vcodec_b_mm2_ctx,
-	&gfx3d_user_ctx,
-	&gfx3d_priv_ctx,
+static struct platform_device *msm_iommu_jpegd_ctx_devs[] = {
+	&msm_device_jpegd_src_ctx,
+	&msm_device_jpegd_dst_ctx,
 };
 
-static struct msm_iommu_ctx_dev *msm_iommu_gfx2d_ctx_data[] = {
-	&gfx2d0_2d0_ctx,
-	&gfx2d1_2d1_ctx,
-};
-
-static struct msm_iommu_ctx_dev *msm_iommu_8064_ctx_data[] = {
-	&gfx3d1_user_ctx,
-	&gfx3d1_priv_ctx,
-	&vcap_vc_ctx,
-	&vcap_vp_ctx,
-};
-
-static int iommu_init_devs(struct platform_device *devs[],
-	struct msm_iommu_dev *data[], int size)
-{
-	int ret, i;
-
-	for (i = 0; i < size; i++) {
-		ret = platform_device_add_data(devs[i],
-			  data[i], sizeof(struct msm_iommu_dev));
-		if (ret != 0) {
-			pr_err("platform_device_add_data failed, "
-			       "i = %d\n", i);
-			goto failure_unwind;
-		}
-
-		ret = platform_device_register(devs[i]);
-
-		if (ret != 0) {
-			pr_err("platform_device_register iommu failed, "
-			       "i = %d\n", i);
-			goto failure_unwind;
-		}
-	}
-	return 0;
-
-failure_unwind:
-	while (--i >= 0)
-		platform_device_unregister(devs[i]);
-
-	return ret;
-}
-
-
-static int iommu_init_ctx_devs(struct platform_device *ctx_devs[],
-	struct msm_iommu_ctx_dev *ctx_data[], int size)
-{
-	int ret, i;
-
-	for (i = 0; i < size; i++) {
-		ret = platform_device_add_data(ctx_devs[i],
-				ctx_data[i], sizeof(struct msm_iommu_ctx_dev));
-		if (ret != 0) {
-			pr_err("platform_device_add_data iommu failed, "
-			       "i = %d\n", i);
-			goto failure_unwind;
-		}
-
-		ret = platform_device_register(ctx_devs[i]);
-		if (ret != 0) {
-			pr_err("platform_device_register ctx failed, "
-			       "i = %d\n", i);
-			goto failure_unwind;
-		}
-	}
-	return 0;
-
-failure_unwind:
-	while (--i >= 0)
-		platform_device_unregister(ctx_devs[i]);
-
-	return ret;
-}
-
 static int __init iommu_init(void)
 {
 	int ret;
@@ -1069,45 +995,55 @@
 	}
 
 	/* Initialize common devs */
-	ret = iommu_init_devs(msm_iommu_common_devs,
-			 msm_iommu_common_data,
+	ret = platform_add_devices(msm_iommu_common_devs,
 			 ARRAY_SIZE(msm_iommu_common_devs));
 	if (ret != 0)
 		goto failure2;
 
 	/* Initialize soc-specific devs */
 	if (cpu_is_apq8064()) {
-		ret = iommu_init_devs(msm_iommu_8064_devs,
-				 msm_iommu_8064_data,
+		ret = platform_add_devices(msm_iommu_8064_devs,
 				 ARRAY_SIZE(msm_iommu_8064_devs));
 	} else {
-		ret = iommu_init_devs(msm_iommu_gfx2d_devs,
-					 msm_iommu_gfx2d_data,
-					ARRAY_SIZE(msm_iommu_gfx2d_devs));
+		ret = platform_add_devices(msm_iommu_gfx2d_devs,
+				 ARRAY_SIZE(msm_iommu_gfx2d_devs));
 	}
 	if (ret != 0)
 		goto failure2;
 
+	if (!cpu_is_msm8930()) {
+		ret = platform_add_devices(msm_iommu_jpegd_devs,
+			ARRAY_SIZE(msm_iommu_jpegd_devs));
+
+		if (ret != 0)
+			goto failure2;
+	}
+
 	/* Initialize common ctx_devs */
-	ret = iommu_init_ctx_devs(msm_iommu_common_ctx_devs,
-				 msm_iommu_common_ctx_data,
+	ret = platform_add_devices(msm_iommu_common_ctx_devs,
 				 ARRAY_SIZE(msm_iommu_common_ctx_devs));
 	if (ret != 0)
 		goto failure2;
 
 	/* Initialize soc-specific ctx_devs */
 	if (cpu_is_apq8064()) {
-		ret = iommu_init_ctx_devs(msm_iommu_8064_ctx_devs,
-				msm_iommu_8064_ctx_data,
+		ret = platform_add_devices(msm_iommu_8064_ctx_devs,
 				ARRAY_SIZE(msm_iommu_8064_ctx_devs));
 	} else {
-		ret = iommu_init_ctx_devs(msm_iommu_gfx2d_ctx_devs,
-					msm_iommu_gfx2d_ctx_data,
+		ret = platform_add_devices(msm_iommu_gfx2d_ctx_devs,
 					ARRAY_SIZE(msm_iommu_gfx2d_ctx_devs));
 	}
 	if (ret != 0)
 		goto failure2;
 
+	if (!cpu_is_msm8930()) {
+		ret = platform_add_devices(msm_iommu_jpegd_ctx_devs,
+			ARRAY_SIZE(msm_iommu_jpegd_ctx_devs));
+
+		if (ret != 0)
+			goto failure2;
+	}
+
 	return 0;
 
 failure2:
@@ -1133,6 +1069,11 @@
 			platform_device_unregister(msm_iommu_gfx2d_ctx_devs[i]);
 	}
 
+	if (!cpu_is_msm8930()) {
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_ctx_devs); i++)
+			platform_device_unregister(msm_iommu_jpegd_ctx_devs[i]);
+	}
+
 	/* Common devs. */
 	for (i = 0; i < ARRAY_SIZE(msm_iommu_common_devs); ++i)
 		platform_device_unregister(msm_iommu_common_devs[i]);
@@ -1146,6 +1087,11 @@
 			platform_device_unregister(msm_iommu_gfx2d_devs[i]);
 	}
 
+	if (!cpu_is_msm8930()) {
+		for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_devs); i++)
+			platform_device_unregister(msm_iommu_jpegd_devs[i]);
+	}
+
 	platform_device_unregister(&msm_root_iommu_dev);
 }
 
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 903694e..f7e67cb 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -1532,6 +1532,36 @@
 	.size = ARRAY_SIZE(msm_clock_8625_dummy),
 };
 
+enum {
+	MSM8625,
+	MSM8625A,
+};
+
+static int __init msm8625_cpu_id(void)
+{
+	int raw_id, cpu;
+
+	raw_id = socinfo_get_raw_id();
+	switch (raw_id) {
+	/* Part number for 1GHz part */
+	case 0x770:
+	case 0x771:
+	case 0x780:
+		cpu = MSM8625;
+		break;
+	/* Part number for 1.2GHz part */
+	case 0x773:
+	case 0x774:
+	case 0x781:
+		cpu = MSM8625A;
+		break;
+	default:
+		pr_err("Invalid Raw ID\n");
+		return -ENODEV;
+	}
+	return cpu;
+}
+
 int __init msm7x2x_misc_init(void)
 {
 	if (machine_is_msm8625_rumi3()) {
@@ -1540,10 +1570,16 @@
 	}
 
 	msm_clock_init(&msm7x27a_clock_init_data);
-	if (cpu_is_msm7x27aa() || cpu_is_msm8625())
+	if (cpu_is_msm7x27aa())
 		acpuclk_init(&acpuclk_7x27aa_soc_data);
-	else
+	else if (cpu_is_msm8625()) {
+		if (msm8625_cpu_id() == MSM8625)
+			acpuclk_init(&acpuclk_7x27aa_soc_data);
+		else if (msm8625_cpu_id() == MSM8625A)
+			acpuclk_init(&acpuclk_8625_soc_data);
+	 } else {
 		acpuclk_init(&acpuclk_7x27a_soc_data);
+	 }
 
 
 	return 0;
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 4371c23..2eb716a 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -324,5 +324,6 @@
 extern struct platform_device msm_bus_8064_cpss_fpb;
 
 extern struct platform_device mdm_8064_device;
-
 extern struct platform_device msm_dsps_device_8064;
+extern struct platform_device *msm_copper_stub_regulator_devices[];
+extern int msm_copper_stub_regulator_devices_len;
diff --git a/arch/arm/mach-msm/include/mach/irqs-8930.h b/arch/arm/mach-msm/include/mach/irqs-8930.h
index ed927bd..bfc32f6 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8930.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8930.h
@@ -152,10 +152,10 @@
 #define SPS_MTI_2				(GIC_SPI_START + 109)
 #define SPS_MTI_3				(GIC_SPI_START + 110)
 #define GPS_PPS_OUT				(GIC_SPI_START + 111)
-#define SPS_MTI_5				(GIC_SPI_START + 112)
-#define SPS_MTI_6				(GIC_SPI_START + 113)
-#define SPS_MTI_7				(GIC_SPI_START + 114)
-#define SPS_MTI_8				(GIC_SPI_START + 115)
+/* SPI IRQ 112 is unused */
+/* SPI IRQ 113 is unused */
+/* SPI IRQ 114 is unused */
+/* SPI IRQ 115 is unused */
 #define TLMM_MSM_DIR_CONN_IRQ_11		(GIC_SPI_START + 116)
 #define TLMM_MSM_DIR_CONN_IRQ_10		(GIC_SPI_START + 117)
 #define BAM_DMA1				(GIC_SPI_START + 118)
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index 183afed..d896013 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -123,9 +123,19 @@
 
 };
 
+/*
+ * Subsystem Restart Configuration
+ *
+ * @disable_smsm_reset_handshake
+ */
+struct smd_subsystem_restart_config {
+	int disable_smsm_reset_handshake;
+};
+
 struct smd_platform {
 	uint32_t num_ss_configs;
 	struct smd_subsystem_config *smd_ss_configs;
+	struct smd_subsystem_restart_config *smd_ssr_config;
 };
 
 #ifdef CONFIG_MSM_SMD
diff --git a/arch/arm/mach-msm/include/mach/msm_xo.h b/arch/arm/mach-msm/include/mach/msm_xo.h
index 7760647..f9795b4 100644
--- a/arch/arm/mach-msm/include/mach/msm_xo.h
+++ b/arch/arm/mach-msm/include/mach/msm_xo.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
@@ -19,8 +19,6 @@
 	MSM_XO_TCXO_A1,
 	MSM_XO_TCXO_A2,
 	MSM_XO_CORE,
-	MSM_XO_PXO,
-	MSM_XO_CXO,
 	NUM_MSM_XO_IDS
 };
 
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 215fdb3..407c55a 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -68,6 +68,7 @@
 enum msm_cpu socinfo_get_msm_cpu(void);
 uint32_t socinfo_get_id(void);
 uint32_t socinfo_get_version(void);
+uint32_t socinfo_get_raw_id(void);
 char *socinfo_get_build_id(void);
 uint32_t socinfo_get_platform_type(void);
 uint32_t socinfo_get_platform_subtype(void);
diff --git a/arch/arm/mach-msm/msm_xo.c b/arch/arm/mach-msm/msm_xo.c
index f7d2bcb..52bbaeb 100644
--- a/arch/arm/mach-msm/msm_xo.c
+++ b/arch/arm/mach-msm/msm_xo.c
@@ -82,8 +82,6 @@
 	msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_TCXO_A1], "TCXO A1");
 	msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_TCXO_A2], "TCXO A2");
 	msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_CORE], "TCXO Core");
-	msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_PXO], "PXO during sleep");
-	msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_CXO], "CXO");
 	spin_unlock_irqrestore(&msm_xo_lock, flags);
 
 	return 0;
@@ -109,13 +107,14 @@
 			&msm_xo_voters_ops);
 	return IS_ERR(entry) ? PTR_ERR(entry) : 0;
 }
-late_initcall(msm_xo_debugfs_init);
+#else
+static int __init msm_xo_debugfs_init(void) { return 0; }
 #endif
 
 static int msm_xo_update_vote(struct msm_xo *xo)
 {
 	int ret;
-	unsigned vote, prev_vote = xo->mode, ctx_set;
+	unsigned vote, prev_vote = xo->mode;
 	struct msm_rpm_iv_pair cmd;
 
 	if (xo->votes[MSM_XO_MODE_ON])
@@ -133,36 +132,21 @@
 	 * command fails we'll rollback.
 	 */
 	xo->mode = vote;
-
-	if (xo == &msm_xo_sources[MSM_XO_PXO]) {
-		cmd.id = MSM_RPM_ID_PXO_CLK;
-		cmd.value = msm_xo_sources[MSM_XO_PXO].mode ? 1 : 0;
-		ret = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_SLEEP, &cmd, 1);
-	} else if (xo == &msm_xo_sources[MSM_XO_CXO]) {
-		cmd.id = MSM_RPM_ID_CXO_CLK;
-		cmd.value = msm_xo_sources[MSM_XO_CXO].mode ? 1 : 0;
-		if (cpu_is_msm9615())
-			ctx_set = MSM_RPM_CTX_SET_SLEEP;
-		else
-			ctx_set = MSM_RPM_CTX_SET_0;
-		ret = msm_rpmrs_set_noirq(ctx_set, &cmd, 1);
-	} else {
-		cmd.id = MSM_RPM_ID_CXO_BUFFERS;
-		cmd.value = (msm_xo_sources[MSM_XO_TCXO_D0].mode << 0)  |
-			    (msm_xo_sources[MSM_XO_TCXO_D1].mode << 8)  |
-			    (msm_xo_sources[MSM_XO_TCXO_A0].mode << 16) |
-			    (msm_xo_sources[MSM_XO_TCXO_A1].mode << 24) |
-			    (msm_xo_sources[MSM_XO_TCXO_A2].mode << 28) |
-			    /*
-			     * 8660 RPM has XO_CORE at bit 18 and 8960 RPM has
-			     * XO_CORE at bit 20. Since the opposite bit is
-			     * reserved in both cases, just set both and be
-			     * done with it.
-			     */
-			    ((msm_xo_sources[MSM_XO_CORE].mode ? 1 : 0) << 20) |
-			    ((msm_xo_sources[MSM_XO_CORE].mode ? 1 : 0) << 18);
-		ret = msm_rpm_set_noirq(MSM_RPM_CTX_SET_0, &cmd, 1);
-	}
+	cmd.id = MSM_RPM_ID_CXO_BUFFERS;
+	cmd.value = (msm_xo_sources[MSM_XO_TCXO_D0].mode << 0)  |
+		    (msm_xo_sources[MSM_XO_TCXO_D1].mode << 8)  |
+		    (msm_xo_sources[MSM_XO_TCXO_A0].mode << 16) |
+		    (msm_xo_sources[MSM_XO_TCXO_A1].mode << 24) |
+		    (msm_xo_sources[MSM_XO_TCXO_A2].mode << 28) |
+		    /*
+		     * 8660 RPM has XO_CORE at bit 18 and 8960 RPM has
+		     * XO_CORE at bit 20. Since the opposite bit is
+		     * reserved in both cases, just set both and be
+		     * done with it.
+		     */
+		    ((msm_xo_sources[MSM_XO_CORE].mode ? 1 : 0) << 20) |
+		    ((msm_xo_sources[MSM_XO_CORE].mode ? 1 : 0) << 18);
+	ret = msm_rpm_set_noirq(MSM_RPM_CTX_SET_0, &cmd, 1);
 
 	if (ret)
 		xo->mode = prev_vote;
@@ -299,39 +283,17 @@
 
 int __init msm_xo_init(void)
 {
-	int i;
-	int ret = 0;
-	struct msm_rpm_iv_pair cmd[2];
+	int i, ret;
+	struct msm_rpm_iv_pair cmd[1];
 
 	for (i = 0; i < ARRAY_SIZE(msm_xo_sources); i++)
 		INIT_LIST_HEAD(&msm_xo_sources[i].voters);
 
-	if (cpu_is_msm9615()) {
-		cmd[0].id = MSM_RPM_ID_CXO_CLK;
-		cmd[0].value = 1;
-		ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, cmd, 1);
-		if (ret)
-			goto out;
-
-		cmd[0].id = MSM_RPM_ID_CXO_CLK;
-		cmd[0].value = 0;
-		ret = msm_rpmrs_set(MSM_RPM_CTX_SET_SLEEP, cmd, 1);
-		goto out;
-	}
-
-	cmd[0].id = MSM_RPM_ID_PXO_CLK;
-	cmd[0].value = 1;
-	cmd[1].id = MSM_RPM_ID_CXO_BUFFERS;
-	cmd[1].value = 0;
-	ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, cmd, 2);
-	if (ret)
-		goto out;
-
-	cmd[0].id = MSM_RPM_ID_PXO_CLK;
+	cmd[0].id = MSM_RPM_ID_CXO_BUFFERS;
 	cmd[0].value = 0;
-	ret = msm_rpmrs_set(MSM_RPM_CTX_SET_SLEEP, cmd, 1);
+	ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, cmd, ARRAY_SIZE(cmd));
 	if (ret)
-		goto out;
-out:
-	return ret;
+		return ret;
+	msm_xo_debugfs_init();
+	return 0;
 }
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 9321b40..d7f2623 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -654,6 +654,7 @@
 	struct notifier_block nb;
 };
 
+static int disable_smsm_reset_handshake;
 static struct platform_device loopback_tty_pdev = {.name = "LOOPBACK_TTY"};
 
 static LIST_HEAD(smd_ch_closed_list);
@@ -2338,7 +2339,7 @@
 			/* If we get an interrupt and the apps SMSM_RESET
 			   bit is already set, the modem is acking the
 			   app's reset ack. */
-			if (!cpu_is_msm8960() && !cpu_is_msm8930())
+			if (!disable_smsm_reset_handshake)
 				apps &= ~SMSM_RESET;
 			/* Issue a fake irq to handle any
 			 * smd state changes during reset
@@ -2349,7 +2350,7 @@
 			modem_queue_start_reset_notify();
 
 		} else if (modm & SMSM_RESET) {
-			if (!cpu_is_msm8960() && !cpu_is_msm8930())
+			if (!disable_smsm_reset_handshake)
 				apps |= SMSM_RESET;
 
 			pr_err("\nSMSM: Modem SMSM state changed to SMSM_RESET.");
@@ -2871,6 +2872,10 @@
 	num_ss = smd_platform_data->num_ss_configs;
 	smd_ss_config_list = smd_platform_data->smd_ss_configs;
 
+	if (smd_platform_data->smd_ssr_config)
+		disable_smsm_reset_handshake = smd_platform_data->
+			   smd_ssr_config->disable_smsm_reset_handshake;
+
 	for (i = 0; i < num_ss; i++) {
 		cfg = &smd_ss_config_list[i];
 
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 8f3263e..8328ee2 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -477,4 +477,12 @@
 	  This option enables support for on-chip GPIO found on Qualcomm PM8xxx
 	  PMICs through RPC.
 
+config GPIO_QPNP
+	depends on ARCH_MSMCOPPER
+	depends on OF_SPMI
+	depends on MSM_QPNP_INT
+	tristate "Qualcomm QPNP GPIO support"
+	help
+	  Say 'y' here to include support for the Qualcomm QPNP gpio
+	  support. QPNP is a SPMI based PMIC implementation.
 endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 83972f1..db19ac8 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -51,3 +51,4 @@
 obj-$(CONFIG_GPIO_PM8XXX)	+= pm8xxx-gpio.o
 obj-$(CONFIG_GPIO_PM8XXX_MPP) 	+= pm8xxx-mpp.o
 obj-$(CONFIG_GPIO_PM8XXX_RPC)	+= gpio-pm8xxx-rpc.o
+obj-$(CONFIG_GPIO_QPNP)		+= qpnp-gpio.o
diff --git a/drivers/gpio/qpnp-gpio.c b/drivers/gpio/qpnp-gpio.c
new file mode 100644
index 0000000..b09b040
--- /dev/null
+++ b/drivers/gpio/qpnp-gpio.c
@@ -0,0 +1,706 @@
+/* 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/interrupt.h>
+#include <linux/types.h>
+#include <linux/spmi.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/qpnp/gpio.h>
+
+#include <mach/qpnp.h>
+
+#define Q_REG_ADDR(q_spec, reg_index)	\
+		((q_spec)->offset + reg_index)
+
+#define Q_REG_STATUS1			0x8
+#define Q_NUM_CTL_REGS			5
+
+/* 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
+
+/* 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
+
+/* 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
+#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_MASTER_EN_SHIFT		7
+#define Q_REG_MASTER_EN_MASK		0x80
+
+
+struct qpnp_gpio_spec {
+	uint8_t slave;			/* 0-15 */
+	uint16_t offset;		/* 0-255 */
+	uint32_t gpio_chip_idx;		/* offset from gpio_chip base */
+	int irq;			/* logical IRQ number */
+	u8 regs[Q_NUM_CTL_REGS];	/* Control regs */
+};
+
+struct qpnp_gpio_chip {
+	struct gpio_chip	gpio_chip;
+	struct spmi_device	*spmi;
+	struct qpnp_gpio_spec	**pmic_gpios;
+	struct qpnp_gpio_spec	**chip_gpios;
+	uint32_t		pmic_gpio_lowest;
+	uint32_t		pmic_gpio_highest;
+	struct device_node	*int_ctrl;
+	struct list_head	chip_list;
+};
+
+static LIST_HEAD(qpnp_gpio_chips);
+static DEFINE_MUTEX(qpnp_gpio_chips_lock);
+
+static inline void qpnp_pmic_gpio_set_spec(struct qpnp_gpio_chip *q_chip,
+					      uint32_t pmic_gpio,
+					      struct qpnp_gpio_spec *spec)
+{
+	q_chip->pmic_gpios[pmic_gpio - q_chip->pmic_gpio_lowest] = spec;
+}
+
+static inline struct qpnp_gpio_spec *qpnp_pmic_gpio_get_spec(
+						struct qpnp_gpio_chip *q_chip,
+						uint32_t pmic_gpio)
+{
+	if (pmic_gpio < q_chip->pmic_gpio_lowest ||
+	    pmic_gpio > q_chip->pmic_gpio_highest)
+		return NULL;
+
+	return q_chip->pmic_gpios[pmic_gpio - q_chip->pmic_gpio_lowest];
+}
+
+static inline struct qpnp_gpio_spec *qpnp_chip_gpio_get_spec(
+						struct qpnp_gpio_chip *q_chip,
+						uint32_t chip_gpio)
+{
+	if (chip_gpio > q_chip->gpio_chip.ngpio)
+		return NULL;
+
+	return q_chip->chip_gpios[chip_gpio];
+}
+
+static inline void qpnp_chip_gpio_set_spec(struct qpnp_gpio_chip *q_chip,
+					      uint32_t chip_gpio,
+					      struct qpnp_gpio_spec *spec)
+{
+	q_chip->chip_gpios[chip_gpio] = spec;
+}
+
+int qpnp_gpio_config(int gpio, struct qpnp_gpio_cfg *param)
+{
+	int rc, chip_offset;
+	struct qpnp_gpio_chip *q_chip;
+	struct qpnp_gpio_spec *q_spec = NULL;
+	struct gpio_chip *gpio_chip;
+
+	if (param == NULL)
+		return -EINVAL;
+
+	mutex_lock(&qpnp_gpio_chips_lock);
+	list_for_each_entry(q_chip, &qpnp_gpio_chips, chip_list) {
+		gpio_chip = &q_chip->gpio_chip;
+		if (gpio >= gpio_chip->base
+				&& gpio < gpio_chip->base + gpio_chip->ngpio) {
+			chip_offset = gpio - gpio_chip->base;
+			q_spec = qpnp_chip_gpio_get_spec(q_chip, chip_offset);
+			if (WARN_ON(!q_spec)) {
+				mutex_unlock(&qpnp_gpio_chips_lock);
+				return -ENODEV;
+			}
+			break;
+		}
+	}
+	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->inv_int_pol
+			    << 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__);
+
+	return rc;
+}
+EXPORT_SYMBOL(qpnp_gpio_config);
+
+int qpnp_gpio_map_gpio(uint16_t slave_id, uint32_t pmic_gpio)
+{
+	struct qpnp_gpio_chip *q_chip;
+	struct qpnp_gpio_spec *q_spec = NULL;
+
+	mutex_lock(&qpnp_gpio_chips_lock);
+	list_for_each_entry(q_chip, &qpnp_gpio_chips, chip_list) {
+		if (q_chip->spmi->sid != slave_id)
+			continue;
+		if (q_chip->pmic_gpio_lowest <= pmic_gpio &&
+		    q_chip->pmic_gpio_highest >= pmic_gpio) {
+			q_spec = qpnp_pmic_gpio_get_spec(q_chip, pmic_gpio);
+			mutex_unlock(&qpnp_gpio_chips_lock);
+			if (WARN_ON(!q_spec))
+				return -ENODEV;
+			return q_chip->gpio_chip.base + q_spec->gpio_chip_idx;
+		}
+	}
+	mutex_unlock(&qpnp_gpio_chips_lock);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(qpnp_gpio_map_gpio);
+
+static int qpnp_gpio_to_irq(struct gpio_chip *gpio_chip, unsigned offset)
+{
+	struct qpnp_gpio_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
+	struct qpnp_gpio_spec *q_spec;
+
+	q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
+	if (!q_spec)
+		return -EINVAL;
+
+	return q_spec->irq;
+}
+
+static int qpnp_gpio_get(struct gpio_chip *gpio_chip, unsigned offset)
+{
+	int rc, ret_val;
+	struct qpnp_gpio_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
+	struct qpnp_gpio_spec *q_spec = NULL;
+	u8 buf[1];
+
+	if (WARN_ON(!q_chip))
+		return -ENODEV;
+
+	q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
+	if (WARN_ON(!q_spec))
+		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) {
+		/* INT_RT_STS */
+		rc = spmi_ext_register_readl(q_chip->spmi->ctrl, q_spec->slave,
+				Q_REG_ADDR(q_spec, Q_REG_STATUS1),
+				&buf[0], 1);
+		return buf[0];
+
+	} else {
+		ret_val = (q_spec->regs[Q_REG_I_OUTPUT_CTL2] &
+			       Q_REG_OUT_INVERT_MASK) >> Q_REG_OUT_INVERT_SHIFT;
+		return ret_val;
+	}
+
+	return 0;
+}
+
+static int __qpnp_gpio_set(struct qpnp_gpio_chip *q_chip,
+			   struct qpnp_gpio_spec *q_spec, int value)
+{
+	int rc;
+
+	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);
+
+	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);
+	if (rc)
+		dev_err(&q_chip->spmi->dev, "%s: spmi write failed\n",
+								__func__);
+	return rc;
+}
+
+
+static void qpnp_gpio_set(struct gpio_chip *gpio_chip,
+		unsigned offset, int value)
+{
+	struct qpnp_gpio_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
+	struct qpnp_gpio_spec *q_spec;
+
+	if (WARN_ON(!q_chip))
+		return;
+
+	q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
+	if (WARN_ON(!q_spec))
+		return;
+
+	__qpnp_gpio_set(q_chip, q_spec, value);
+}
+
+static int qpnp_gpio_set_direction(struct qpnp_gpio_chip *q_chip,
+				   struct qpnp_gpio_spec *q_spec, int direction)
+{
+	int rc;
+
+	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);
+	}
+
+	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);
+	return rc;
+}
+
+static int qpnp_gpio_direction_input(struct gpio_chip *gpio_chip,
+		unsigned offset)
+{
+	struct qpnp_gpio_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
+	struct qpnp_gpio_spec *q_spec;
+
+	if (WARN_ON(!q_chip))
+		return -ENODEV;
+
+	q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
+	if (WARN_ON(!q_spec))
+		return -ENODEV;
+
+	return qpnp_gpio_set_direction(q_chip, q_spec, QPNP_GPIO_DIR_IN);
+}
+
+static int qpnp_gpio_direction_output(struct gpio_chip *gpio_chip,
+		unsigned offset,
+		int val)
+{
+	int rc;
+	struct qpnp_gpio_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
+	struct qpnp_gpio_spec *q_spec;
+
+	if (WARN_ON(!q_chip))
+		return -ENODEV;
+
+	q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
+	if (WARN_ON(!q_spec))
+		return -ENODEV;
+
+	rc = __qpnp_gpio_set(q_chip, q_spec, val);
+	if (rc)
+		return rc;
+
+	rc = qpnp_gpio_set_direction(q_chip, q_spec, QPNP_GPIO_DIR_OUT);
+
+	return rc;
+}
+
+static int qpnp_gpio_of_gpio_xlate(struct gpio_chip *gpio_chip,
+				   struct device_node *np,
+				   const void *gpio_spec, u32 *flags)
+{
+	struct qpnp_gpio_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
+	struct qpnp_gpio_spec *q_spec;
+	const __be32 *gpio = gpio_spec;
+	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__);
+		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);
+		return -EINVAL;
+	}
+
+	if (flags)
+		*flags = be32_to_cpu(gpio[1]);
+
+	return q_spec->gpio_chip_idx;
+}
+
+static int qpnp_gpio_config_default(struct spmi_device *spmi,
+					const __be32 *prop, int gpio)
+{
+	struct qpnp_gpio_cfg param;
+	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"
+		" p[8]: 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]),
+		be32_to_cpup(&prop[8]));
+
+	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.inv_int_pol  =	be32_to_cpup(&prop[7]);
+	param.master_en    =	be32_to_cpup(&prop[8]);
+
+	rc = qpnp_gpio_config(gpio, &param);
+	if (rc)
+		dev_err(&spmi->dev, "%s: unable to set default config for"
+				" gpio %d\n", __func__, gpio);
+	return rc;
+}
+
+static int qpnp_gpio_free_chip(struct qpnp_gpio_chip *q_chip)
+{
+	struct spmi_device *spmi = q_chip->spmi;
+	int rc, i;
+
+	if (q_chip->chip_gpios)
+		for (i = 0; i < spmi->num_dev_node; i++)
+			kfree(q_chip->chip_gpios[i]);
+
+	mutex_lock(&qpnp_gpio_chips_lock);
+	list_del(&q_chip->chip_list);
+	mutex_unlock(&qpnp_gpio_chips_lock);
+	rc = gpiochip_remove(&q_chip->gpio_chip);
+	if (rc)
+		dev_err(&q_chip->spmi->dev, "%s: unable to remove gpio\n",
+				__func__);
+	kfree(q_chip->chip_gpios);
+	kfree(q_chip->pmic_gpios);
+	kfree(q_chip);
+	return rc;
+}
+
+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];
+
+	q_chip = kzalloc(sizeof(*q_chip), GFP_KERNEL);
+	if (!q_chip) {
+		dev_err(&spmi->dev, "%s: Can't allocate gpio_chip\n",
+								__func__);
+		return -ENOMEM;
+	}
+	q_chip->spmi = spmi;
+	dev_set_drvdata(&spmi->dev, q_chip);
+
+	mutex_lock(&qpnp_gpio_chips_lock);
+	list_add(&q_chip->chip_list, &qpnp_gpio_chips);
+	mutex_unlock(&qpnp_gpio_chips_lock);
+
+	/* 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) {
+			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;
+			goto err_probe;
+		}
+
+		gpio = be32_to_cpup(prop);
+		if (gpio < lowest_gpio)
+			lowest_gpio = gpio;
+		if (gpio > highest_gpio)
+			highest_gpio = gpio;
+	}
+
+	if (highest_gpio < lowest_gpio) {
+		dev_err(&spmi->dev, "%s: no device nodes specified in"
+					" topology\n", __func__);
+		ret = -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;
+		goto err_probe;
+	}
+
+	q_chip->pmic_gpio_lowest = lowest_gpio;
+	q_chip->pmic_gpio_highest = highest_gpio;
+
+	/* allocate gpio lookup tables */
+	q_chip->pmic_gpios = kzalloc(sizeof(struct qpnp_gpio_spec *) *
+						highest_gpio - lowest_gpio + 1,
+						GFP_KERNEL);
+	q_chip->chip_gpios = kzalloc(sizeof(struct qpnp_gpio_spec *) *
+						spmi->num_dev_node, GFP_KERNEL);
+	if (!q_chip->pmic_gpios || !q_chip->chip_gpios) {
+		dev_err(&spmi->dev, "%s: unable to allocate memory\n",
+								__func__);
+		ret = -ENOMEM;
+		goto err_probe;
+	}
+
+	/* get interrupt controller device_node */
+	q_chip->int_ctrl = of_irq_find_parent(spmi->dev.of_node);
+	if (!q_chip->int_ctrl) {
+		dev_err(&spmi->dev, "%s: Can't find interrupt parent\n",
+								__func__);
+		ret = -EINVAL;
+		goto err_probe;
+	}
+
+	/* now scan through again and populate the lookup table */
+	for (i = 0; i < spmi->num_dev_node; i++) {
+		res = qpnp_get_resource(spmi, i, IORESOURCE_MEM, 0);
+		if (!res) {
+			dev_err(&spmi->dev, "%s: node %s is missing has no"
+				" base address definition\n",
+				__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) {
+			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;
+			goto err_probe;
+		}
+		gpio = be32_to_cpup(prop);
+
+		q_spec = kzalloc(sizeof(struct qpnp_gpio_spec),
+							GFP_KERNEL);
+		if (!q_spec) {
+			dev_err(&spmi->dev, "%s: unable to allocate"
+						" memory\n",
+					__func__);
+			ret = -ENOMEM;
+			goto err_probe;
+		}
+
+		q_spec->slave = spmi->sid;
+		q_spec->offset = res->start;
+		q_spec->gpio_chip_idx = i;
+
+		/* call into irq_domain to get irq mapping */
+		intspec[0] = q_chip->spmi->sid;
+		intspec[1] = (q_spec->offset >> 8) & 0xFF;
+		intspec[2] = 0;
+		q_spec->irq = irq_create_of_mapping(q_chip->int_ctrl,
+							intspec, 3);
+		if (!q_spec->irq) {
+			dev_err(&spmi->dev, "%s: invalid irq for gpio"
+					" %u\n", __func__, gpio);
+			ret = -EINVAL;
+			goto err_probe;
+		}
+		/* initialize lookup table entries */
+		qpnp_pmic_gpio_set_spec(q_chip, gpio, q_spec);
+		qpnp_chip_gpio_set_spec(q_chip, i, q_spec);
+	}
+
+	q_chip->gpio_chip.base = -1;
+	q_chip->gpio_chip.ngpio = spmi->num_dev_node;
+	q_chip->gpio_chip.label = "qpnp-gpio";
+	q_chip->gpio_chip.direction_input = qpnp_gpio_direction_input;
+	q_chip->gpio_chip.direction_output = qpnp_gpio_direction_output;
+	q_chip->gpio_chip.to_irq = qpnp_gpio_to_irq;
+	q_chip->gpio_chip.get = qpnp_gpio_get;
+	q_chip->gpio_chip.set = qpnp_gpio_set;
+	q_chip->gpio_chip.dev = &spmi->dev;
+	q_chip->gpio_chip.of_xlate = qpnp_gpio_of_gpio_xlate;
+	q_chip->gpio_chip.of_gpio_n_cells = 2;
+	q_chip->gpio_chip.can_sleep = 0;
+
+	rc = gpiochip_add(&q_chip->gpio_chip);
+	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 */
+	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);
+		/* 9 data values constitute one tuple */
+		if (prop && (len != (9 * sizeof(__be32)))) {
+			dev_err(&spmi->dev, "%s: invalid format for"
+				" qcom,qpnp-gpio-cfg property\n",
+							__func__);
+			ret = -EINVAL;
+			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;
+			}
+		}
+	}
+
+	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);
+	return 0;
+
+err_probe:
+	qpnp_gpio_free_chip(q_chip);
+	return ret;
+}
+
+static int qpnp_gpio_remove(struct spmi_device *spmi)
+{
+	struct qpnp_gpio_chip *q_chip = dev_get_drvdata(&spmi->dev);
+
+	return qpnp_gpio_free_chip(q_chip);
+}
+
+static struct of_device_id spmi_match_table[] = {
+	{	.compatible = "qcom,qpnp-gpio",
+	},
+	{}
+};
+
+static const struct spmi_device_id qpnp_gpio_id[] = {
+	{ "qcom,qpnp-gpio", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spmi, qpnp_gpio_id);
+
+static struct spmi_driver qpnp_gpio_driver = {
+	.driver		= {
+		.name	= "qcom,qpnp-gpio",
+		.of_match_table = spmi_match_table,
+	},
+	.probe		= qpnp_gpio_probe,
+	.remove		= qpnp_gpio_remove,
+	.id_table	= qpnp_gpio_id,
+};
+
+static int __init qpnp_gpio_init(void)
+{
+	return spmi_driver_register(&qpnp_gpio_driver);
+}
+
+static void __exit qpnp_gpio_exit(void)
+{
+}
+
+MODULE_AUTHOR(
+	"Michael Bohan <mbohan@codeaurora.org>");
+MODULE_DESCRIPTION("QPNP PMIC gpio driver");
+MODULE_LICENSE("GPLv2");
+
+module_init(qpnp_gpio_init);
+module_exit(qpnp_gpio_exit);
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 0cadc33..eb017de 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -420,7 +420,7 @@
 static unsigned int
 adreno_getchipid(struct kgsl_device *device)
 {
-	if (cpu_is_apq8064())
+	if (cpu_is_apq8064() || cpu_is_msm8930())
 		return a3xx_getchipid(device);
 	else
 		return a2xx_getchipid(device);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 805e0c1..50a6fab 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -903,10 +903,6 @@
 	struct kgsl_ibdesc *ibdesc;
 	struct kgsl_context *context;
 
-#ifdef CONFIG_MSM_KGSL_DRM
-	kgsl_gpu_mem_flush(DRM_KGSL_GEM_CACHE_OP_TO_DEV);
-#endif
-
 	context = kgsl_find_context(dev_priv, param->drawctxt_id);
 	if (context == NULL) {
 		result = -EINVAL;
@@ -994,10 +990,6 @@
 	kfree(ibdesc);
 done:
 
-#ifdef CONFIG_MSM_KGSL_DRM
-	kgsl_gpu_mem_flush(DRM_KGSL_GEM_CACHE_OP_FROM_DEV);
-#endif
-
 	return result;
 }
 
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 3e8aac3..b2fe095 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -160,7 +160,6 @@
 #ifdef CONFIG_MSM_KGSL_DRM
 extern int kgsl_drm_init(struct platform_device *dev);
 extern void kgsl_drm_exit(void);
-extern void kgsl_gpu_mem_flush(int op);
 #else
 static inline int kgsl_drm_init(struct platform_device *dev)
 {
diff --git a/drivers/gpu/msm/kgsl_drm.c b/drivers/gpu/msm/kgsl_drm.c
index e3f6f3b..03f8c42 100644
--- a/drivers/gpu/msm/kgsl_drm.c
+++ b/drivers/gpu/msm/kgsl_drm.c
@@ -156,22 +156,6 @@
 	kgsl_cache_range_op(memdesc, cacheop);
 }
 
-/* Flush all the memory mapped in the MMU */
-
-void kgsl_gpu_mem_flush(int op)
-{
-	struct drm_kgsl_gem_object *entry;
-
-	list_for_each_entry(entry, &kgsl_mem_list, list) {
-		kgsl_gem_mem_flush(&entry->memdesc, entry->type, op);
-	}
-
-	/* Takes care of WT/WC case.
-	 * More useful when we go barrierless
-	 */
-	dmb();
-}
-
 /* TODO:
  * Add vsync wait */
 
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index ea67835..406d0c9 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -284,7 +284,7 @@
 DEVICE_ATTR(gpuclk, 0644, kgsl_pwrctrl_gpuclk_show, kgsl_pwrctrl_gpuclk_store);
 DEVICE_ATTR(max_gpuclk, 0644, kgsl_pwrctrl_max_gpuclk_show,
 	kgsl_pwrctrl_max_gpuclk_store);
-DEVICE_ATTR(pwrnap, 0666, kgsl_pwrctrl_pwrnap_show, kgsl_pwrctrl_pwrnap_store);
+DEVICE_ATTR(pwrnap, 0664, kgsl_pwrctrl_pwrnap_show, kgsl_pwrctrl_pwrnap_store);
 DEVICE_ATTR(idle_timer, 0644, kgsl_pwrctrl_idle_timer_show,
 	kgsl_pwrctrl_idle_timer_store);
 DEVICE_ATTR(gpubusy, 0644, kgsl_pwrctrl_gpubusy_show,
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index 4c9a239..d0b2a41 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -90,7 +90,7 @@
 	return ret;
 }
 
-PWRSCALE_ATTR(policy, 0666, pwrscale_policy_show, pwrscale_policy_store);
+PWRSCALE_ATTR(policy, 0664, pwrscale_policy_show, pwrscale_policy_store);
 
 static ssize_t pwrscale_avail_policies_show(struct kgsl_device *device,
 					    char *buf)
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 7264c25..f61a196 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -13,6 +13,8 @@
 #include <linux/vmalloc.h>
 #include <linux/memory_alloc.h>
 #include <asm/cacheflush.h>
+#include <linux/slab.h>
+#include <linux/kmemleak.h>
 
 #include "kgsl.h"
 #include "kgsl_sharedmem.h"
@@ -427,6 +429,8 @@
 		goto done;
 	}
 
+	kmemleak_not_leak(memdesc->sg);
+
 	memdesc->sglen = sglen;
 	sg_init_table(memdesc->sg, sglen);
 
@@ -499,6 +503,8 @@
 		return -ENOMEM;
 	}
 
+	kmemleak_not_leak(ptr);
+
 	protflags = GSL_PT_PAGE_RV;
 	if (!(flags & KGSL_MEMFLAGS_GPUREADONLY))
 		protflags |= GSL_PT_PAGE_WV;
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 67a1c2d..e54110d 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -17,6 +17,8 @@
 #include <linux/dma-mapping.h>
 #include <linux/vmalloc.h>
 #include "kgsl_mmu.h"
+#include <linux/slab.h>
+#include <linux/kmemleak.h>
 
 struct kgsl_device;
 struct kgsl_process_private;
@@ -86,6 +88,8 @@
 	if (memdesc->sg == NULL)
 		return -ENOMEM;
 
+	kmemleak_not_leak(memdesc->sg);
+
 	memdesc->sglen = 1;
 	sg_init_table(memdesc->sg, 1);
 	sg_set_page(&memdesc->sg[0], page, size, 0);
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index e70a0a5..a4b4b0d 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -48,9 +48,16 @@
 	depends on MSM_CAMERA
 	---help---
 	  OV 5M Bayer Sensor with AutoFocus
+
+config AD5046_ACT
+	bool "Lens actuator ad5046"
+	depends on MSM_CAMERA && OV5647
+	---help---
+	  ad5046 lens actuator driver for ov5647.
+	  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 && !MSM_CAMERA_V4L2
+	depends on MSM_CAMERA && ARCH_MSM7X27A
 	default n
 	---help---
 	  Omni Vision VGA YUV Sensor for QRD Devices
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 67cd62e..2843d30 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -39,14 +39,14 @@
   obj-$(CONFIG_IMX074) += imx074.o imx074_reg.o
   obj-$(CONFIG_MT9E013) += mt9e013.o mt9e013_reg.o
   obj-$(CONFIG_WEBCAM_OV9726) += ov9726.o ov9726_reg.o
+  obj-$(CONFIG_OV5647) += ov5647.o ov5647_reg.o
   obj-$(CONFIG_S5K4E1) += s5k4e1.o s5k4e1_reg.o
+  obj-$(CONFIG_WEBCAM_OV7692) += ov7692.o
+  obj-$(CONFIG_WEBCAM_OV7692_QRD) += ov7692_qrd.o
 endif
 obj-$(CONFIG_QS_S5K4E1) += qs_s5k4e1.o qs_s5k4e1_reg.o
 obj-$(CONFIG_VB6801) += vb6801.o
 obj-$(CONFIG_IMX072) += imx072.o imx072_reg.o
-obj-$(CONFIG_OV5647) += ov5647.o ov5647_reg.o
-obj-$(CONFIG_WEBCAM_OV7692) += ov7692.o
-obj-$(CONFIG_WEBCAM_OV7692_QRD) += ov7692_qrd.o
 obj-$(CONFIG_OV5640) += ov5640.o
 obj-$(CONFIG_MT9D112) += mt9d112.o mt9d112_reg.o
 
diff --git a/drivers/media/video/msm/actuators/Makefile b/drivers/media/video/msm/actuators/Makefile
index f0a0c69..d492155 100644
--- a/drivers/media/video/msm/actuators/Makefile
+++ b/drivers/media/video/msm/actuators/Makefile
@@ -4,3 +4,4 @@
 obj-$(CONFIG_MSM_ACTUATOR) += msm_actuator.o
 obj-$(CONFIG_IMX074_ACT) += imx074_act.o
 obj-$(CONFIG_DW9712_ACT) += dw9712_act.o
+obj-$(CONFIG_AD5046_ACT) += ad5046_act.o
diff --git a/drivers/media/video/msm/actuators/ad5046_act.c b/drivers/media/video/msm/actuators/ad5046_act.c
new file mode 100644
index 0000000..d99774b
--- /dev/null
+++ b/drivers/media/video/msm/actuators/ad5046_act.c
@@ -0,0 +1,315 @@
+/* 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_actuator.h"
+#include "msm_camera_i2c.h"
+
+#define	AD5046_TOTAL_STEPS_NEAR_TO_FAR			32
+static uint8_t  mode_mask = 0x09;
+DEFINE_MUTEX(ad5046_act_mutex);
+static struct msm_actuator_ctrl_t ad5046_act_t;
+
+static struct region_params_t g_regions[] = {
+	/* step_bound[0] - macro side boundary
+	 * step_bound[1] - infinity side boundary
+	 */
+	/* Region 1 */
+	{
+		.step_bound = {AD5046_TOTAL_STEPS_NEAR_TO_FAR, 0},
+		.code_per_step = 2,
+	},
+};
+
+static uint16_t g_scenario[] = {
+	/* MOVE_NEAR and MOVE_FAR dir*/
+	AD5046_TOTAL_STEPS_NEAR_TO_FAR,
+};
+
+static int32_t ad5046_af_i2c_txdata(unsigned short saddr,
+				unsigned char *txdata, int length,
+				struct msm_actuator_ctrl_t *a_ctrl)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = length,
+			.buf = txdata,
+		},
+	};
+	if (i2c_transfer(a_ctrl->i2c_client.client->adapter, msg, 1) < 0) {
+		pr_err("ad5046_af_i2c_txdata faild 0x%x\n", saddr);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t ad5046_af_i2c_write_b_sensor(struct msm_actuator_ctrl_t *a_ctrl,
+			      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;
+	rc = ad5046_af_i2c_txdata(a_ctrl->i2c_addr, buf, 2, a_ctrl);
+	if (rc < 0)
+		pr_err("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+				waddr, bdata);
+
+	return rc;
+}
+
+static int32_t ad5046_wrapper_i2c_write(struct msm_actuator_ctrl_t *a_ctrl,
+	int16_t next_lens_position, void *params)
+{
+	uint8_t msb, lsb;
+
+	msb = (next_lens_position & 0xFF00) >> 8;
+	lsb = next_lens_position & 0xFF;
+	ad5046_af_i2c_write_b_sensor(a_ctrl, msb, lsb);
+
+	return 0;
+}
+
+int32_t msm_ad5046_act_move_focus(
+	struct msm_actuator_ctrl_t *a_ctrl,
+	int dir,
+	int32_t num_steps)
+{
+	int32_t rc = 0;
+	int8_t sign_dir = 0;
+	int16_t dest_step_pos = 0;
+	uint8_t code_val_msb, code_val_lsb;
+
+	CDBG("%s called, dir %d, num_steps %d\n",
+		__func__,
+		dir,
+		num_steps);
+
+	/* Determine sign direction */
+	if (dir == MOVE_NEAR)
+		sign_dir = 20;
+	else if (dir == MOVE_FAR)
+		sign_dir = -20;
+	else {
+		pr_err("Illegal focus direction\n");
+		rc = -EINVAL;
+		return rc;
+	}
+
+	/* Determine destination step position */
+	dest_step_pos = a_ctrl->curr_step_pos +
+		(sign_dir * num_steps);
+
+	if (dest_step_pos < 0)
+		dest_step_pos = 0;
+	else if (dest_step_pos > 1023)
+		dest_step_pos = 1023;
+
+	if (dest_step_pos == a_ctrl->curr_step_pos)
+		return rc;
+
+	a_ctrl->curr_step_pos = dest_step_pos;
+
+	code_val_msb = (uint8_t)((dest_step_pos & 0x03FF) >> 4);
+	code_val_lsb = (uint8_t)((dest_step_pos & 0x000F) << 4);
+	code_val_lsb |= mode_mask;
+
+	rc = ad5046_af_i2c_write_b_sensor(a_ctrl, code_val_msb, code_val_lsb);
+	/* DAC Setting */
+	if (rc != 0) {
+		CDBG(KERN_ERR "%s: WRITE ERROR lsb = 0x%x, msb = 0x%x",
+			__func__, code_val_lsb, code_val_msb);
+	} else {
+		CDBG(KERN_ERR "%s: Successful lsb = 0x%x, msb = 0x%x",
+			__func__, code_val_lsb, code_val_msb);
+		/* delay may set based on the steps moved
+		when I2C write successful */
+		msleep(100);
+	}
+	return 0;
+}
+
+static int32_t ad5046_set_default_focus(
+	struct msm_actuator_ctrl_t *a_ctrl)
+{
+	uint8_t  code_val_msb = 0;
+	uint8_t  code_val_lsb = 0;
+	int rc = 0;
+
+	CDBG("ad5046_set_default_focus called\n");
+
+	if (!a_ctrl->step_position_table)
+		a_ctrl->func_tbl.actuator_init_table(a_ctrl);
+
+	a_ctrl->curr_step_pos = 200;
+
+	code_val_msb = (a_ctrl->curr_step_pos & 0x03FF) >> 4;
+	code_val_lsb = (a_ctrl->curr_step_pos & 0x000F) << 4;
+	code_val_lsb |= mode_mask;
+
+	CDBG(KERN_ERR "ad5046_set_default_focus:lens pos = %d",
+		 a_ctrl->curr_step_pos);
+	rc = ad5046_af_i2c_write_b_sensor(a_ctrl, code_val_msb, code_val_lsb);
+	/* DAC Setting */
+	if (rc != 0)
+		CDBG(KERN_ERR "%s: WRITE ERROR lsb = 0x%x, msb = 0x%x",
+			__func__, code_val_lsb, code_val_msb);
+	else
+		CDBG(KERN_ERR "%s: WRITE successful lsb = 0x%x, msb = 0x%x",
+			__func__, code_val_lsb, code_val_msb);
+
+	usleep_range(10000, 11000);
+	return 0;
+}
+
+static const struct i2c_device_id ad5046_act_i2c_id[] = {
+	{"ad5046_act", (kernel_ulong_t)&ad5046_act_t},
+	{ }
+};
+
+static int ad5046_act_config(void __user *argp)
+{
+	LINFO("%s called\n", __func__);
+	return (int) msm_actuator_config(&ad5046_act_t, argp);
+}
+
+static int ad5046_i2c_add_driver_table(void)
+{
+	LINFO("%s called\n", __func__);
+	return (int) msm_actuator_init_table(&ad5046_act_t);
+}
+
+int32_t ad5046_act_i2c_probe(
+	struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int32_t rc = 0;
+
+	rc = msm_actuator_i2c_probe(client, id);
+
+	msleep(50);
+
+	return rc;
+}
+static struct i2c_driver ad5046_act_i2c_driver = {
+	.id_table = ad5046_act_i2c_id,
+	.probe  = ad5046_act_i2c_probe,
+	.remove = __exit_p(ad5046_act_i2c_remove),
+	.driver = {
+		.name = "ad5046_act",
+	},
+};
+
+static int __init ad5046_i2c_add_driver(void)
+{
+	int rc = 0;
+
+	LINFO("%s called :%x\n", __func__, ad5046_act_t.i2c_addr);
+	rc = i2c_add_driver(ad5046_act_t.i2c_driver);
+	LINFO("%s called:%d %x\n", __func__, rc, ad5046_act_t.i2c_addr);
+	return rc;
+}
+
+static struct v4l2_subdev_core_ops ad5046_act_subdev_core_ops;
+
+static struct v4l2_subdev_ops ad5046_act_subdev_ops = {
+	.core = &ad5046_act_subdev_core_ops,
+};
+
+static int32_t ad5046_act_create_subdevice(
+	void *board_info,
+	void *sdev)
+{
+	int rc = 0;
+
+	struct msm_actuator_info *ptr;
+	LINFO("%s called\n", __func__);
+
+	ptr = board_info;
+	ad5046_act_t.vcm_pwd = ptr->vcm_pwd;
+	ad5046_act_t.vcm_enable = ptr->vcm_enable;
+	LINFO("vcm info: %x %x\n", ad5046_act_t.vcm_pwd,
+				ad5046_act_t.vcm_enable);
+	if (ad5046_act_t.vcm_enable) {
+		rc = gpio_request(ad5046_act_t.vcm_pwd, "ov5647_af");
+		if (!rc) {
+			LINFO("Enable VCM PWD\n");
+			gpio_direction_output(ad5046_act_t.vcm_pwd, 1);
+		}
+		msleep(20);
+
+	}
+	return (int) msm_actuator_create_subdevice(&ad5046_act_t,
+		ptr->board_info,
+		(struct v4l2_subdev *)sdev);
+}
+
+static struct msm_actuator_ctrl_t ad5046_act_t = {
+	.i2c_driver = &ad5046_act_i2c_driver,
+	.i2c_addr = 0x18>>1,
+	.act_v4l2_subdev_ops = &ad5046_act_subdev_ops,
+	.actuator_ext_ctrl = {
+		.a_init_table = ad5046_i2c_add_driver_table,
+		.a_create_subdevice = ad5046_act_create_subdevice,
+		.a_config = ad5046_act_config,
+	},
+
+	.i2c_client = {
+		.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+	},
+
+	.set_info = {
+		.total_steps = AD5046_TOTAL_STEPS_NEAR_TO_FAR,
+	},
+
+	.curr_step_pos = 0,
+	.curr_region_index = 0,
+	.initial_code = 0x0,
+	.actuator_mutex = &ad5046_act_mutex,
+
+	.func_tbl = {
+		.actuator_init_table = msm_actuator_init_table,
+		.actuator_move_focus = msm_ad5046_act_move_focus,
+		.actuator_set_default_focus = ad5046_set_default_focus,
+		.actuator_i2c_write = ad5046_wrapper_i2c_write,
+	},
+
+	.get_info = {
+		.focal_length_num = 46,
+		.focal_length_den = 10,
+		.f_number_num = 265,
+		.f_number_den = 100,
+		.f_pix_num = 14,
+		.f_pix_den = 10,
+		.total_f_dist_num = 197681,
+		.total_f_dist_den = 1000,
+	},
+
+	/* Initialize scenario */
+	.ringing_scenario[MOVE_NEAR] = g_scenario,
+	.scenario_size[MOVE_NEAR] = ARRAY_SIZE(g_scenario),
+	.ringing_scenario[MOVE_FAR] = g_scenario,
+	.scenario_size[MOVE_FAR] = ARRAY_SIZE(g_scenario),
+
+	/* Initialize region params */
+	.region_params = g_regions,
+	.region_size = ARRAY_SIZE(g_regions),
+};
+
+subsys_initcall(ad5046_i2c_add_driver);
+MODULE_DESCRIPTION("AD5046 actuator");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 78c474e..a7f6a8c 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -2392,6 +2392,13 @@
 		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);
+	pvdev->v4l2_dev = &pcam->v4l2_dev;
+	pcam->v4l2_dev.mdev = &pcam->mctl.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));
@@ -2406,6 +2413,10 @@
 	pvdev->minor	 = -1;
 	pvdev->vfl_type  = 1;
 
+	media_entity_init(&pvdev->entity, 0, NULL, 0);
+	pvdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
+	pvdev->entity.group_id = QCAMERA_VNODE_GROUP_ID;
+
 	/* register v4l2 video device to kernel as /dev/videoXX */
 	D("video_register_device\n");
 	rc = video_register_device(pvdev,
@@ -2415,6 +2426,7 @@
 		pr_err("%s: video_register_device failed\n", __func__);
 		goto reg_fail;
 	}
+	pvdev->entity.name = video_device_node_name(pvdev);
 	D("%s: video device registered as /dev/video%d\n",
 		__func__, pvdev->num);
 
@@ -2600,6 +2612,15 @@
 		g_server_dev.mctl_node_info.mctl_node_name
 		[g_server_dev.mctl_node_info.num_mctl_nodes]);
 
+	/*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),
+			"%s-%d-%d", QCAMERA_NAME,
+			sdata->sensor_platform_info->mount_angle,
+			sdata->camera_type);
+
 	g_server_dev.camera_info.num_cameras++;
 	g_server_dev.mctl_node_info.num_mctl_nodes++;
 
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index c90ab44..dd65c01 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -218,6 +218,8 @@
 	/* 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*/
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 492bcce..628fa62 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -177,7 +177,7 @@
 	int rc = 0;
 	struct msm_camsensor_info info;
 	struct msm_camera_sensor_info *sdata;
-
+	struct msm_cam_v4l2_device *pcam = sync->pcam_sync;
 	if (copy_from_user(&info,
 			arg,
 			sizeof(struct msm_camsensor_info))) {
@@ -191,7 +191,11 @@
 	memcpy(&info.name[0], sdata->sensor_name, MAX_SENSOR_NAME);
 	info.flash_enabled = sdata->flash_data->flash_type !=
 					MSM_CAMERA_FLASH_NONE;
-
+	info.pxlcode = pcam->usr_fmts[0].pxlcode;
+	info.flashtype = sdata->flash_type; /* two flash_types here? */
+	info.camera_type = sdata->camera_type;
+	info.sensor_type = 0; /* need to add YUV/SOC in probing */
+	info.mount_angle = sdata->sensor_platform_info->mount_angle;
 	/* copy back to user space */
 	if (copy_to_user((void *)arg,
 				&info,
@@ -199,7 +203,6 @@
 		ERR_COPY_TO_USER();
 		rc = -EFAULT;
 	}
-
 	return rc;
 }
 
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index 07a4c89..e1f4532 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -1138,7 +1138,6 @@
 	case CMD_AXI_CFG_SEC: {
 		CDBG("CMD_AXI_CFG_SEC\n");
 		raw_mode = 0;
-		vfe2x_ctrl->output_mode =  OUTPUT_SEC;
 		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
 		if (!axio) {
 			pr_err("NULL axio\n");
@@ -1191,7 +1190,6 @@
 	case CMD_AXI_CFG_PRIM: {
 		CDBG("CMD_AXI_CFG_PRIM : %d\n", op_mode);
 		raw_mode = 0;
-		vfe2x_ctrl->output_mode =  OUTPUT_PRIM;
 		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
 		if (!axio) {
 			pr_err("NULL axio\n");
@@ -1257,7 +1255,6 @@
 	case CMD_AXI_CFG_SEC|CMD_AXI_CFG_PRIM: {
 		CDBG("CMD_AXI_CFG_SEC|PRIM\n");
 		raw_mode = 0;
-		vfe2x_ctrl->output_mode =  OUTPUT_SEC|OUTPUT_PRIM;
 		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
 		if (!axio) {
 			pr_err("NULL axio\n");
@@ -1333,7 +1330,6 @@
 		break;
 	case CMD_RAW_PICT_AXI_CFG: {
 		CDBG("CMD_RAW_PICT_AXI_CFG:%d\n", op_mode);
-		vfe2x_ctrl->output_mode =  OUTPUT_PRIM;
 		raw_mode = 1;
 		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
 		if (!axio) {
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.h b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
index 33d6c17..90237bd 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
@@ -79,7 +79,6 @@
 } __packed;
 
 struct vfe2x_ctrl_type {
-	uint16_t output_mode;
 	struct buf_info prev;
 	struct buf_info video;
 	struct buf_info snap;
diff --git a/drivers/media/video/msm/sensors/Makefile b/drivers/media/video/msm/sensors/Makefile
index cfc0fe0..ef8993c 100644
--- a/drivers/media/video/msm/sensors/Makefile
+++ b/drivers/media/video/msm/sensors/Makefile
@@ -10,3 +10,5 @@
 obj-$(CONFIG_S5K4E1) += s5k4e1_v4l2.o
 obj-$(CONFIG_MT9E013) += mt9e013_v4l2.o
 obj-$(CONFIG_WEBCAM_OV9726) += ov9726_v4l2.o
+obj-$(CONFIG_WEBCAM_OV7692_QRD) += ov7692_qrd_v4l2.o
+obj-$(CONFIG_OV5647) += ov5647_v4l2.o
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index cade3d6..e40a528 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -173,6 +173,100 @@
 	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_setting2(struct msm_sensor_ctrl_t *s_ctrl,
+			int update_type, int res)
+{
+	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);
+	if (update_type == MSM_SENSOR_REG_INIT) {
+		CDBG("Register INIT\n");
+		s_ctrl->curr_csi_params = NULL;
+		msm_camera_i2c_write(
+				s_ctrl->sensor_i2c_client,
+				0x103, 0x1,
+				MSM_CAMERA_I2C_BYTE_DATA);
+		msm_sensor_enable_debugfs(s_ctrl);
+		msm_sensor_write_init_settings(s_ctrl);
+		csi_config = 0;
+	} else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
+		CDBG("PERIODIC : %d\n", res);
+		msm_sensor_write_conf_array(
+			s_ctrl->sensor_i2c_client,
+			s_ctrl->msm_sensor_reg->mode_settings, res);
+		msleep(30);
+		if (!csi_config) {
+			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);
+			csi_config = 1;
+		msm_camera_i2c_write(
+			s_ctrl->sensor_i2c_client,
+			0x100, 0x1,
+			MSM_CAMERA_I2C_BYTE_DATA);
+		}
+		msm_camera_i2c_write(
+			s_ctrl->sensor_i2c_client,
+			0x4800, 0x4,
+			MSM_CAMERA_I2C_BYTE_DATA);
+		msleep(266);
+		s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
+		msleep(50);
+	}
+	return rc;
+}
+
 int32_t msm_sensor_setting1(struct msm_sensor_ctrl_t *s_ctrl,
 			int update_type, int res)
 {
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index 2b1be1e..d1a6cee 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -226,6 +226,12 @@
 int32_t msm_sensor_setting1(struct msm_sensor_ctrl_t *s_ctrl,
 			int update_type, int res);
 
+int32_t msm_sensor_setting2(struct msm_sensor_ctrl_t *s_ctrl,
+			int update_type, int res);
+
+int32_t msm_sensor_setting3(struct msm_sensor_ctrl_t *s_ctrl,
+			int update_type, int res);
+
 int msm_sensor_enable_debugfs(struct msm_sensor_ctrl_t *s_ctrl);
 
 long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd,
@@ -233,6 +239,10 @@
 
 struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd);
 
+#if (defined CONFIG_WEBCAM_OV7692_QRD || defined CONFIG_OV5647)
+	extern int lcd_camera_power_onoff(int on);
+#endif
+
 #define VIDIOC_MSM_SENSOR_CFG \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 10, void __user *)
 
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
new file mode 100644
index 0000000..052305c
--- /dev/null
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -0,0 +1,634 @@
+/* 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_sensor.h"
+#define SENSOR_NAME "ov5647"
+#define PLATFORM_DRIVER_NAME "msm_camera_ov5647"
+#define ov5647_obj ov5647_##obj
+
+static struct msm_sensor_ctrl_t ov5647_s_ctrl;
+
+DEFINE_MUTEX(ov5647_mut);
+
+
+
+static struct msm_camera_i2c_reg_conf ov5647_start_settings[] = {
+	{0x4202, 0x00},  /* streaming on */
+};
+
+static struct msm_camera_i2c_reg_conf ov5647_stop_settings[] = {
+	{0x4202, 0x0f},  /* streaming off*/
+};
+
+static struct msm_camera_i2c_reg_conf ov5647_groupon_settings[] = {
+	{0x0104, 0x01},
+};
+
+static struct msm_camera_i2c_reg_conf ov5647_groupoff_settings[] = {
+	{0x0104, 0x0},
+};
+
+static struct msm_camera_i2c_reg_conf ov5647_prev_settings[] = {
+	/*1280*960 Reference Setting 24M MCLK 2lane 280Mbps/lane 30fps
+	for back to preview*/
+	{0x3035, 0x21},
+	{0x3036, 0x37},
+	{0x3821, 0x07},
+	{0x3820, 0x41},
+	{0x3612, 0x09},
+	{0x3618, 0x00},
+	{0x380c, 0x07},
+	{0x380d, 0x68},
+	{0x380e, 0x03},
+	{0x380f, 0xd8},
+	{0x3814, 0x31},
+	{0x3815, 0x31},
+	{0x3709, 0x52},
+	{0x3808, 0x05},
+	{0x3809, 0x00},
+	{0x380a, 0x03},
+	{0x380b, 0xc0},
+	{0x3800, 0x00},
+	{0x3801, 0x18},
+	{0x3802, 0x00},
+	{0x3803, 0x0e},
+	{0x3804, 0x0a},
+	{0x3805, 0x27},
+	{0x3806, 0x07},
+	{0x3807, 0x95},
+	{0x4004, 0x02},
+};
+
+static struct msm_camera_i2c_reg_conf ov5647_snap_settings[] = {
+	/*2608*1952 Reference Setting 24M MCLK 2lane 280Mbps/lane 30fps*/
+	{0x3035, 0x21},
+	{0x3036, 0x4f},
+	{0x3821, 0x06},
+	{0x3820, 0x00},
+	{0x3612, 0x0b},
+	{0x3618, 0x04},
+	{0x380c, 0x0a},
+	{0x380d, 0x8c},
+	{0x380e, 0x07},
+	{0x380f, 0xb0},
+	{0x3814, 0x11},
+	{0x3815, 0x11},
+	{0x3709, 0x12},
+	{0x3808, 0x0a},
+	{0x3809, 0x30},
+	{0x380a, 0x07},
+	{0x380b, 0xa0},
+	{0x3800, 0x00},
+	{0x3801, 0x04},
+	{0x3802, 0x00},
+	{0x3803, 0x00},
+	{0x3804, 0x0a},
+	{0x3805, 0x3b},
+	{0x3806, 0x07},
+	{0x3807, 0xa3},
+	{0x4004, 0x04},
+};
+
+static struct msm_camera_i2c_reg_conf ov5647_recommend_settings[] = {
+	{0x3035, 0x11},
+	{0x303c, 0x11},
+	{0x370c, 0x03},
+	{0x5000, 0x06},
+	{0x5003, 0x08},
+	{0x5a00, 0x08},
+	{0x3000, 0xff},
+	{0x3001, 0xff},
+	{0x3002, 0xff},
+	{0x301d, 0xf0},
+	{0x3a18, 0x00},
+	{0x3a19, 0xf8},
+	{0x3c01, 0x80},
+	{0x3b07, 0x0c},
+	{0x3708, 0x64},
+	{0x3630, 0x2e},
+	{0x3632, 0xe2},
+	{0x3633, 0x23},
+	{0x3634, 0x44},
+	{0x3620, 0x64},
+	{0x3621, 0xe0},
+	{0x3600, 0x37},
+	{0x3704, 0xa0},
+	{0x3703, 0x5a},
+	{0x3715, 0x78},
+	{0x3717, 0x01},
+	{0x3731, 0x02},
+	{0x370b, 0x60},
+	{0x3705, 0x1a},
+	{0x3f05, 0x02},
+	{0x3f06, 0x10},
+	{0x3f01, 0x0a},
+	{0x3a08, 0x01},
+	{0x3a0f, 0x58},
+	{0x3a10, 0x50},
+	{0x3a1b, 0x58},
+	{0x3a1e, 0x50},
+	{0x3a11, 0x60},
+	{0x3a1f, 0x28},
+	{0x4001, 0x02},
+	{0x4000, 0x09},
+	{0x3000, 0x00},
+	{0x3001, 0x00},
+	{0x3002, 0x00},
+	{0x3017, 0xe0},
+	{0x301c, 0xfc},
+	{0x3636, 0x06},
+	{0x3016, 0x08},
+	{0x3827, 0xec},
+	{0x3018, 0x44},
+	{0x3035, 0x21},
+	{0x3106, 0xf5},
+	{0x3034, 0x18},
+	{0x301c, 0xf8},
+	/*lens setting*/
+	{0x5000, 0x86},
+	{0x5800, 0x11},
+	{0x5801, 0x0c},
+	{0x5802, 0x0a},
+	{0x5803, 0x0b},
+	{0x5804, 0x0d},
+	{0x5805, 0x13},
+	{0x5806, 0x09},
+	{0x5807, 0x05},
+	{0x5808, 0x03},
+	{0x5809, 0x03},
+	{0x580a, 0x06},
+	{0x580b, 0x08},
+	{0x580c, 0x05},
+	{0x580d, 0x01},
+	{0x580e, 0x00},
+	{0x580f, 0x00},
+	{0x5810, 0x02},
+	{0x5811, 0x06},
+	{0x5812, 0x05},
+	{0x5813, 0x01},
+	{0x5814, 0x00},
+	{0x5815, 0x00},
+	{0x5816, 0x02},
+	{0x5817, 0x06},
+	{0x5818, 0x09},
+	{0x5819, 0x05},
+	{0x581a, 0x04},
+	{0x581b, 0x04},
+	{0x581c, 0x06},
+	{0x581d, 0x09},
+	{0x581e, 0x11},
+	{0x581f, 0x0c},
+	{0x5820, 0x0b},
+	{0x5821, 0x0b},
+	{0x5822, 0x0d},
+	{0x5823, 0x13},
+	{0x5824, 0x22},
+	{0x5825, 0x26},
+	{0x5826, 0x26},
+	{0x5827, 0x24},
+	{0x5828, 0x24},
+	{0x5829, 0x24},
+	{0x582a, 0x22},
+	{0x582b, 0x20},
+	{0x582c, 0x22},
+	{0x582d, 0x26},
+	{0x582e, 0x22},
+	{0x582f, 0x22},
+	{0x5830, 0x42},
+	{0x5831, 0x22},
+	{0x5832, 0x02},
+	{0x5833, 0x24},
+	{0x5834, 0x22},
+	{0x5835, 0x22},
+	{0x5836, 0x22},
+	{0x5837, 0x26},
+	{0x5838, 0x42},
+	{0x5839, 0x26},
+	{0x583a, 0x06},
+	{0x583b, 0x26},
+	{0x583c, 0x24},
+	{0x583d, 0xce},
+	/* manual AWB,manual AE,close Lenc,open WBC*/
+	{0x3503, 0x03}, /*manual AE*/
+	{0x3501, 0x10},
+	{0x3502, 0x80},
+	{0x350a, 0x00},
+	{0x350b, 0x7f},
+	{0x5001, 0x01}, /*manual AWB*/
+	{0x5180, 0x08},
+	{0x5186, 0x04},
+	{0x5187, 0x00},
+	{0x5188, 0x04},
+	{0x5189, 0x00},
+	{0x518a, 0x04},
+	{0x518b, 0x00},
+	{0x5000, 0x06}, /*No lenc,WBC on*/
+};
+
+
+static struct msm_camera_i2c_conf_array ov5647_init_conf[] = {
+	{&ov5647_recommend_settings[0],
+	ARRAY_SIZE(ov5647_recommend_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}
+};
+
+static struct msm_camera_i2c_conf_array ov5647_confs[] = {
+	{&ov5647_snap_settings[0],
+	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},
+};
+
+static struct msm_camera_csi_params ov5647_csi_params = {
+	.data_format = CSI_8BIT,
+	.lane_cnt    = 2,
+	.lane_assign = 0xe4,
+	.dpcm_scheme = 0,
+	.settle_cnt  = 10,
+};
+
+static struct v4l2_subdev_info ov5647_subdev_info[] = {
+	{
+		.code   = V4L2_MBUS_FMT_SBGGR10_1X10,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.fmt    = 1,
+		.order    = 0,
+	},
+	/* more can be supported, to be added later */
+};
+
+static struct msm_sensor_output_info_t ov5647_dimensions[] = {
+	{ /* For SNAPSHOT */
+		.x_output = 0xA30,  /*2608*/  /*for 5Mp*/
+		.y_output = 0x7A0,   /*1952*/
+		.line_length_pclk = 0xA8C,
+		.frame_length_lines = 0x7B0,
+		.vt_pixel_clk = 159408000,
+		.op_pixel_clk = 159408000,
+		.binning_factor = 0x0,
+	},
+	{ /* For PREVIEW */
+		.x_output = 0x500,  /*2608*/  /*for 5Mp*/
+		.y_output = 0x3C0,   /*1952*/
+		.line_length_pclk = 0x768 * 2,
+		.frame_length_lines = 0x3D8,
+		.vt_pixel_clk = 159408000,
+		.op_pixel_clk = 159408000,
+		.binning_factor = 0x0,
+	},
+};
+
+static struct msm_sensor_output_reg_addr_t ov5647_reg_addr = {
+	.x_output = 0x3808,
+	.y_output = 0x380A,
+	.line_length_pclk = 0x380C,
+	.frame_length_lines = 0x380E,
+};
+
+static struct msm_camera_csi_params *ov5647_csi_params_array[] = {
+	&ov5647_csi_params,
+	&ov5647_csi_params,
+};
+
+static struct msm_sensor_id_info_t ov5647_id_info = {
+	.sensor_id_reg_addr = 0x300a,
+	.sensor_id = 0x5647,
+};
+
+static struct msm_sensor_exp_gain_info_t ov5647_exp_gain_info = {
+	.coarse_int_time_addr = 0x3500,
+	.global_gain_addr = 0x350A,
+	.vert_offset = 4,
+};
+
+void ov5647_sensor_reset_stream(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	msm_camera_i2c_write(
+		s_ctrl->sensor_i2c_client,
+		0x103, 0x1,
+		MSM_CAMERA_I2C_BYTE_DATA);
+}
+
+static int32_t ov5647_write_pict_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
+		uint16_t gain, uint32_t line)
+{
+
+	uint16_t max_line;
+	uint8_t gain_lsb, gain_hsb;
+	u8 intg_time_hsb, intg_time_msb, intg_time_lsb;
+
+	gain_lsb = (uint8_t) (gain);
+	gain_hsb = (uint8_t)((gain & 0x300)>>8);
+
+	CDBG(KERN_ERR "snapshot exposure seting 0x%x, 0x%x, %d"
+		, gain, line, line);
+
+	if (line > 1964) {
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_exp_gain_info->vert_offset,
+			(uint8_t)((line+4) >> 8),
+			MSM_CAMERA_I2C_BYTE_DATA);
+
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_exp_gain_info->vert_offset + 1,
+			(uint8_t)((line+4) & 0x00FF),
+			MSM_CAMERA_I2C_BYTE_DATA);
+
+		max_line = line + 4;
+	} else if (line > 1968) {
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_exp_gain_info->vert_offset,
+			(uint8_t)((line+4) >> 8),
+			MSM_CAMERA_I2C_BYTE_DATA);
+
+		 msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_exp_gain_info->vert_offset + 1,
+			(uint8_t)((line+4) & 0x00FF),
+			MSM_CAMERA_I2C_BYTE_DATA);
+			max_line = 1968;
+	}
+
+
+	line = line<<4;
+	/* ov5647 need this operation */
+	intg_time_hsb = (u8)(line>>16);
+	intg_time_msb = (u8) ((line & 0xFF00) >> 8);
+	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,
+		intg_time_hsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 1,
+		intg_time_msb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 2,
+		intg_time_lsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	/* gain */
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->global_gain_addr,
+		gain_hsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->global_gain_addr + 1,
+		gain_lsb-1,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	/* Coarse Integration Time */
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
+		intg_time_hsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 1,
+		intg_time_msb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 2,
+		intg_time_lsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	/* gain */
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->global_gain_addr,
+		gain_hsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->global_gain_addr + 1,
+		gain_lsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+
+	s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+	return 0;
+
+}
+
+
+static int32_t ov5647_write_prev_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
+						uint16_t gain, uint32_t line)
+{
+
+	uint16_t max_line;
+	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",
+		 gain, line, line);
+
+	gain_lsb = (uint8_t) (gain);
+	gain_hsb = (uint8_t)((gain & 0x300)>>8);
+	/* adjust frame rate */
+	if (line > 980) {
+
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->vert_offset,
+		(uint8_t)((line+4) >> 8),
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->vert_offset + 1,
+		(uint8_t)((line+4) & 0x00FF),
+		MSM_CAMERA_I2C_BYTE_DATA);
+		max_line = line + 4;
+	} else if (line > 984) {
+
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->vert_offset,
+		(uint8_t)(984 >> 8),
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->vert_offset + 1 ,
+		(uint8_t)(984 & 0x00FF),
+		MSM_CAMERA_I2C_BYTE_DATA);
+		max_line = 984;
+	}
+
+	line = line<<4;
+	/* ov5647 need this operation */
+	intg_time_hsb = (u8)(line>>16);
+	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,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
+		intg_time_hsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 1,
+		intg_time_msb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 2,
+		intg_time_lsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	/* gain */
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->global_gain_addr,
+		gain_hsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->global_gain_addr + 1,
+		gain_lsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+
+	return 0;
+}
+
+static const struct i2c_device_id ov5647_i2c_id[] = {
+	{SENSOR_NAME, (kernel_ulong_t)&ov5647_s_ctrl},
+	{ }
+};
+
+static struct i2c_driver ov5647_i2c_driver = {
+	.id_table = ov5647_i2c_id,
+	.probe  = msm_sensor_i2c_probe,
+	.driver = {
+		.name = SENSOR_NAME,
+	},
+};
+
+
+
+static struct msm_camera_i2c_client ov5647_sensor_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static int __init msm_sensor_init_module(void)
+{
+	return i2c_add_driver(&ov5647_i2c_driver);
+}
+
+static struct v4l2_subdev_core_ops ov5647_subdev_core_ops = {
+	.ioctl = msm_sensor_subdev_ioctl,
+	.s_power = msm_sensor_power,
+};
+
+static struct v4l2_subdev_video_ops ov5647_subdev_video_ops = {
+	.enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
+};
+
+static struct v4l2_subdev_ops ov5647_subdev_ops = {
+	.core = &ov5647_subdev_core_ops,
+	.video  = &ov5647_subdev_video_ops,
+};
+
+int32_t ov5647_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+	struct msm_camera_sensor_info *info = NULL;
+
+	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;
+
+	gpio_direction_output(info->sensor_pwd, 1);
+	gpio_direction_output(info->sensor_reset, 0);
+	usleep_range(1000, 1100);
+	/* turn on ldo and vreg */
+	if (info->pmic_gpio_enable)
+		lcd_camera_power_onoff(1);
+
+	gpio_direction_output(info->sensor_pwd, 0);
+	usleep_range(4000, 4100);
+	gpio_direction_output(info->sensor_reset, 1);
+	usleep_range(2000, 2100);
+
+	return rc;
+
+}
+static struct msm_sensor_fn_t ov5647_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 = msm_sensor_set_fps,
+	.sensor_write_exp_gain = ov5647_write_prev_exp_gain,
+	.sensor_write_snapshot_exp_gain = ov5647_write_pict_exp_gain,
+	.sensor_setting = msm_sensor_setting2,
+	.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 = ov5647_sensor_power_up,
+	.sensor_power_down = msm_sensor_power_down,
+};
+
+static struct msm_sensor_reg_t ov5647_regs = {
+	.default_data_type = MSM_CAMERA_I2C_BYTE_DATA,
+	.start_stream_conf = ov5647_start_settings,
+	.start_stream_conf_size = ARRAY_SIZE(ov5647_start_settings),
+	.stop_stream_conf = ov5647_stop_settings,
+	.stop_stream_conf_size = ARRAY_SIZE(ov5647_stop_settings),
+	.group_hold_on_conf = ov5647_groupon_settings,
+	.group_hold_on_conf_size = ARRAY_SIZE(ov5647_groupon_settings),
+	.group_hold_off_conf = ov5647_groupoff_settings,
+	.group_hold_off_conf_size =
+		ARRAY_SIZE(ov5647_groupoff_settings),
+	.init_settings = &ov5647_init_conf[0],
+	.init_size = ARRAY_SIZE(ov5647_init_conf),
+	.mode_settings = &ov5647_confs[0],
+	.output_settings = &ov5647_dimensions[0],
+	.num_conf = ARRAY_SIZE(ov5647_confs),
+};
+
+static struct msm_sensor_ctrl_t ov5647_s_ctrl = {
+	.msm_sensor_reg = &ov5647_regs,
+	.sensor_i2c_client = &ov5647_sensor_i2c_client,
+	.sensor_i2c_addr =  0x36 << 1 ,
+	.sensor_output_reg_addr = &ov5647_reg_addr,
+	.sensor_id_info = &ov5647_id_info,
+	.sensor_exp_gain_info = &ov5647_exp_gain_info,
+	.cam_mode = MSM_SENSOR_MODE_INVALID,
+	.csic_params = &ov5647_csi_params_array[0],
+	.msm_sensor_mutex = &ov5647_mut,
+	.sensor_i2c_driver = &ov5647_i2c_driver,
+	.sensor_v4l2_subdev_info = ov5647_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov5647_subdev_info),
+	.sensor_v4l2_subdev_ops = &ov5647_subdev_ops,
+	.func_tbl = &ov5647_func_tbl,
+	.clk_rate = MSM_SENSOR_MCLK_24HZ,
+};
+
+module_init(msm_sensor_init_module);
+MODULE_DESCRIPTION("Omnivision WXGA Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c b/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
new file mode 100644
index 0000000..f33d303
--- /dev/null
+++ b/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
@@ -0,0 +1,695 @@
+/* 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_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_snap_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_recommend_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 v4l2_subdev_info ov7692_subdev_info[] = {
+	{
+		.code   = V4L2_MBUS_FMT_YUYV8_2X8,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.fmt    = 1,
+		.order    = 0,
+	},
+	/* more can be supported, to be added later */
+};
+
+
+static struct msm_camera_i2c_conf_array ov7692_init_conf[] = {
+	{&ov7692_recommend_settings[0],
+	ARRAY_SIZE(ov7692_recommend_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}
+};
+
+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},
+};
+
+static struct msm_sensor_output_info_t ov7692_dimensions[] = {
+	{
+		.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,
+	},
+	{
+		.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,
+	},
+};
+
+
+static struct msm_camera_csi_params ov7692_csi_params = {
+	.data_format = CSI_8BIT,
+	.lane_cnt    = 1,
+	.lane_assign = 0xe4,
+	.dpcm_scheme = 0,
+	.settle_cnt  = 0x14,
+};
+
+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 = {
+	.x_output = 0xCC,
+	.y_output = 0xCE,
+	.line_length_pclk = 0xC8,
+	.frame_length_lines = 0xCA,
+};
+
+static struct msm_sensor_id_info_t ov7692_id_info = {
+	.sensor_id_reg_addr = 0x0A,
+	.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 struct i2c_driver ov7692_i2c_driver = {
+	.id_table = ov7692_i2c_id,
+	.probe  = msm_sensor_i2c_probe,
+	.driver = {
+		.name = SENSOR_NAME,
+	},
+};
+
+static struct msm_camera_i2c_client ov7692_sensor_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+};
+
+static int __init msm_sensor_init_module(void)
+{
+	int rc = 0;
+	CDBG("OV7692\n");
+
+	rc = i2c_add_driver(&ov7692_i2c_driver);
+
+	return rc;
+}
+
+static struct v4l2_subdev_core_ops ov7692_subdev_core_ops = {
+	.ioctl = msm_sensor_subdev_ioctl,
+	.s_power = msm_sensor_power,
+};
+
+static struct v4l2_subdev_video_ops ov7692_subdev_video_ops = {
+	.enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
+};
+
+static struct v4l2_subdev_ops ov7692_subdev_ops = {
+	.core = &ov7692_subdev_core_ops,
+	.video  = &ov7692_subdev_video_ops,
+};
+
+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);
+}
+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 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 = msm_sensor_set_fps,
+	.sensor_setting = msm_sensor_setting3,
+	.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_down = msm_sensor_power_down,
+};
+
+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,
+	.init_settings = &ov7692_init_conf[0],
+	.init_size = ARRAY_SIZE(ov7692_init_conf),
+	.mode_settings = &ov7692_confs[0],
+	.output_settings = &ov7692_dimensions[0],
+	.num_conf = ARRAY_SIZE(ov7692_confs),
+};
+
+static struct msm_sensor_ctrl_t ov7692_s_ctrl = {
+	.msm_sensor_reg = &ov7692_regs,
+	.sensor_i2c_client = &ov7692_sensor_i2c_client,
+	.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,
+	.sensor_i2c_driver = &ov7692_i2c_driver,
+	.sensor_v4l2_subdev_info = ov7692_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov7692_subdev_info),
+	.sensor_v4l2_subdev_ops = &ov7692_subdev_ops,
+	.func_tbl = &ov7692_func_tbl,
+	.clk_rate = MSM_SENSOR_MCLK_24HZ,
+};
+
+module_init(msm_sensor_init_module);
+MODULE_DESCRIPTION("Omni VGA YUV sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c
index 5a016bb..ebd58ab 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.c
+++ b/drivers/net/usb/rmnet_usb_ctrl.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
@@ -66,7 +66,7 @@
 	return snprintf(buf, PAGE_SIZE, "%u\n", dev->mdm_wait_timeout);
 }
 
-static DEVICE_ATTR(modem_wait, 0666, modem_wait_show, modem_wait_store);
+static DEVICE_ATTR(modem_wait, 0664, modem_wait_show, modem_wait_store);
 
 static int	ctl_msg_dbg_mask;
 module_param_named(dump_ctrl_msg, ctl_msg_dbg_mask, int,
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
index 1eb6845..ae3f934 100644
--- a/drivers/net/usb/rmnet_usb_data.c
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -466,6 +466,11 @@
 
 	status = rmnet_usb_ctrl_probe(iface, unet->status,
 		(struct rmnet_ctrl_dev *)unet->data[1]);
+	if (status)
+		goto out;
+
+	/* allow modem to wake up suspended system */
+	device_set_wakeup_enable(&udev->dev, 1);
 out:
 	return status;
 }
@@ -477,6 +482,7 @@
 	struct rmnet_ctrl_dev	*dev;
 
 	udev = interface_to_usbdev(intf);
+	device_set_wakeup_enable(&udev->dev, 0);
 
 	unet = usb_get_intfdata(intf);
 	if (!unet) {
diff --git a/drivers/of/of_spmi.c b/drivers/of/of_spmi.c
index 2032b46..112497c 100644
--- a/drivers/of/of_spmi.c
+++ b/drivers/of/of_spmi.c
@@ -18,6 +18,7 @@
 #include <linux/of_spmi.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/types.h>
 
 struct of_spmi_dev_info {
 	struct spmi_controller *ctrl;
@@ -30,14 +31,49 @@
 	uint32_t num_irq;
 };
 
-static void of_spmi_sum_resources(struct of_spmi_res_info *r_info, bool has_reg)
+/*
+ * Initialize r_info structure for safe usage
+ */
+static inline void of_spmi_init_resource(struct of_spmi_res_info *r_info,
+					 struct device_node *node)
+{
+	r_info->node = node;
+	r_info->num_reg = 0;
+	r_info->num_irq = 0;
+}
+
+/*
+ * Allocate dev_node array for spmi_device
+ */
+static inline int of_spmi_alloc_device_store(struct of_spmi_dev_info *d_info,
+					     uint32_t num_dev_node)
+{
+	d_info->b_info.num_dev_node = num_dev_node;
+	d_info->b_info.dev_node = kzalloc(sizeof(struct spmi_resource) *
+						num_dev_node, GFP_KERNEL);
+	if (!d_info->b_info.dev_node)
+		return -ENOMEM;
+
+	return 0;
+}
+
+/*
+ * Calculate the number of resources to allocate
+ *
+ * The caller is responsible for initializing the of_spmi_res_info structure.
+ */
+static void of_spmi_sum_node_resources(struct of_spmi_res_info *r_info,
+				       bool has_reg)
 {
 	struct of_irq oirq;
 	uint64_t size;
 	uint32_t flags;
+	int i = 0;
 
-	while (of_irq_map_one(r_info->node, r_info->num_irq, &oirq) == 0)
-		r_info->num_irq++;
+	while (of_irq_map_one(r_info->node, i, &oirq) == 0)
+		i++;
+
+	r_info->num_irq += i;
 
 	if (!has_reg)
 		return;
@@ -48,16 +84,32 @@
 	 * parent buses have a size-cell of 0. But SPMI does have a
 	 * size-cell of 0.
 	 */
-	while (of_get_address(r_info->node, r_info->num_reg,
-						&size, &flags) != NULL)
-		r_info->num_reg++;
+	i = 0;
+	while (of_get_address(r_info->node, i, &size, &flags) != NULL)
+		i++;
+
+	r_info->num_reg += i;
 }
 
-/**
- * Allocate resources for a child of a spmi-slave node.
+/*
+ * free spmi_resource for the spmi_device
  */
-static int of_spmi_allocate_resources(struct of_spmi_dev_info *d_info,
-				      struct of_spmi_res_info *r_info)
+static void of_spmi_free_device_resources(struct of_spmi_dev_info *d_info)
+{
+	int i;
+
+	for (i = 0; i < d_info->b_info.num_dev_node; i++)
+		kfree(d_info->b_info.dev_node[i].resource);
+
+	kfree(d_info->b_info.dev_node);
+}
+
+/*
+ * Gather node resources and populate
+ */
+static void of_spmi_populate_node_resources(struct of_spmi_dev_info *d_info,
+					    struct of_spmi_res_info *r_info,
+					    int idx)
 
 {
 	uint32_t num_irq = r_info->num_irq, num_reg = r_info->num_reg;
@@ -67,13 +119,10 @@
 	uint64_t size;
 	uint32_t flags;
 
-	if (num_irq || num_reg) {
-		res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL);
-		if (!res)
-			return -ENOMEM;
+	res = d_info->b_info.dev_node[idx].resource;
+	d_info->b_info.dev_node[idx].of_node = r_info->node;
 
-		d_info->b_info.num_resources = num_reg + num_irq;
-		d_info->b_info.resource = res;
+	if ((num_irq || num_reg) && (res != NULL)) {
 		for (i = 0; i < num_reg; i++, res++) {
 			/* Addresses are always 16 bits */
 			addrp = of_get_address(r_info->node, i, &size, &flags);
@@ -85,10 +134,34 @@
 		WARN_ON(of_irq_to_resource_table(r_info->node, res, num_irq) !=
 								num_irq);
 	}
+}
+
+/*
+ * Allocate enough memory to handle the resources associated with the
+ * device_node. The number of device nodes included in this allocation
+ * depends on whether the spmi-dev-container flag is specified or not.
+ */
+static int of_spmi_allocate_node_resources(struct of_spmi_dev_info *d_info,
+					   struct of_spmi_res_info *r_info,
+					   uint32_t idx)
+{
+	uint32_t num_irq = r_info->num_irq, num_reg = r_info->num_reg;
+	struct resource *res = NULL;
+
+	if (num_irq || num_reg) {
+		res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL);
+		if (!res)
+			return -ENOMEM;
+	}
+	d_info->b_info.dev_node[idx].num_resources = num_reg + num_irq;
+	d_info->b_info.dev_node[idx].resource = res;
 
 	return 0;
 }
 
+/*
+ * create a single spmi_device
+ */
 static int of_spmi_create_device(struct of_spmi_dev_info *d_info,
 				 struct device_node *node)
 {
@@ -117,6 +190,71 @@
 	return 0;
 }
 
+/*
+ * Walks all children of a node containing the spmi-dev-container
+ * binding. This special type of spmi_device can include resources
+ * from more than one device node.
+ */
+static void of_spmi_walk_dev_container(struct of_spmi_dev_info *d_info,
+					struct device_node *container)
+{
+	struct of_spmi_res_info r_info = {};
+	struct spmi_controller *ctrl = d_info->ctrl;
+	struct device_node *node;
+	int rc, i, num_dev_node = 0;
+
+	/* first count the total number of device_nodes */
+	for_each_child_of_node(container, node)
+		num_dev_node++;
+
+	rc = of_spmi_alloc_device_store(d_info, num_dev_node);
+	if (rc) {
+		dev_err(&ctrl->dev, "%s: unable to allocate"
+				" device resources\n", __func__);
+		return;
+	}
+
+	/* allocate resources per device_node */
+	i = 0;
+	for_each_child_of_node(container, node) {
+		of_spmi_init_resource(&r_info, node);
+		of_spmi_sum_node_resources(&r_info, 1);
+		rc = of_spmi_allocate_node_resources(d_info, &r_info, i);
+		if (rc) {
+			dev_err(&ctrl->dev, "%s: unable to allocate"
+					" resources\n", __func__);
+			of_spmi_free_device_resources(d_info);
+			return;
+		}
+		i++;
+	}
+
+	/**
+	 * Now we need to cycle through again and actually populate
+	 * the resources for each node.
+	 */
+	i = 0;
+	for_each_child_of_node(container, node) {
+		of_spmi_init_resource(&r_info, node);
+		of_spmi_sum_node_resources(&r_info, 1);
+		of_spmi_populate_node_resources(d_info, &r_info, i);
+		i++;
+	}
+
+	rc = of_spmi_create_device(d_info, container);
+	if (rc) {
+		dev_err(&ctrl->dev, "%s: unable to create device for"
+				" node %s\n", __func__, container->full_name);
+		of_spmi_free_device_resources(d_info);
+		return;
+	}
+}
+
+/*
+ * Walks all children of a node containing the spmi-slave-container
+ * binding. This indicates that all spmi_devices created from this
+ * point all share the same slave_id.
+ */
 static void of_spmi_walk_slave_container(struct of_spmi_dev_info *d_info,
 					struct device_node *container)
 {
@@ -127,59 +265,133 @@
 	for_each_child_of_node(container, node) {
 		struct of_spmi_res_info r_info;
 
-		r_info.node = node;
-		of_spmi_sum_resources(&r_info, 1);
+		/**
+		 * Check to see if this node contains children which
+		 * should be all created as the same spmi_device.
+		 */
+		if (of_get_property(node, "spmi-dev-container", NULL)) {
+			of_spmi_walk_dev_container(d_info, node);
+			continue;
+		}
 
-		rc = of_spmi_allocate_resources(d_info, &r_info);
+		rc = of_spmi_alloc_device_store(d_info, 1);
+		if (rc) {
+			dev_err(&ctrl->dev, "%s: unable to allocate"
+					" device resources\n", __func__);
+			goto slave_err;
+		}
+
+		of_spmi_init_resource(&r_info, node);
+		of_spmi_sum_node_resources(&r_info, 1);
+
+		rc = of_spmi_allocate_node_resources(d_info, &r_info, 0);
 		if (rc) {
 			dev_err(&ctrl->dev, "%s: unable to allocate"
 						" resources\n", __func__);
-			return;
+			goto slave_err;
 		}
+
+		of_spmi_populate_node_resources(d_info, &r_info, 0);
+
 		rc = of_spmi_create_device(d_info, node);
 		if (rc) {
 			dev_err(&ctrl->dev, "%s: unable to create device for"
 				     " node %s\n", __func__, node->full_name);
-			return;
+			goto slave_err;
 		}
 	}
+	return;
+
+slave_err:
+	of_spmi_free_device_resources(d_info);
 }
 
 int of_spmi_register_devices(struct spmi_controller *ctrl)
 {
-	struct device_node *node;
+	struct device_node *node = ctrl->dev.of_node;
 
 	/* Only register child devices if the ctrl has a node pointer set */
-	if (!ctrl->dev.of_node)
+	if (!node)
 		return -ENODEV;
 
+	if (of_get_property(node, "spmi-slave-container", NULL)) {
+		dev_err(&ctrl->dev, "%s: structural error: spmi-slave-container"
+			" is prohibited at the root level\n", __func__);
+		return -EINVAL;
+	} else if (of_get_property(node, "spmi-dev-container", NULL)) {
+		dev_err(&ctrl->dev, "%s: structural error: spmi-dev-container"
+			" is prohibited at the root level\n", __func__);
+		return -EINVAL;
+	}
+
+	/**
+	 * Make best effort to launch as many nodes as possible. If there are
+	 * syntax errors, we will simply ignore that subtree and keep going.
+	 */
 	for_each_child_of_node(ctrl->dev.of_node, node) {
 		struct of_spmi_dev_info d_info = {};
 		const __be32 *slave_id;
-		int len, rc;
+		int len, rc, have_dev_container = 0;
 
 		slave_id = of_get_property(node, "reg", &len);
 		if (!slave_id) {
-			dev_err(&ctrl->dev, "of_spmi: invalid sid "
-					"on %s\n", node->full_name);
+			dev_err(&ctrl->dev, "%s: invalid sid "
+					"on %s\n", __func__, node->full_name);
 			continue;
 		}
 
 		d_info.b_info.slave_id = be32_to_cpup(slave_id);
 		d_info.ctrl = ctrl;
 
+		if (of_get_property(node, "spmi-dev-container", NULL))
+			have_dev_container = 1;
 		if (of_get_property(node, "spmi-slave-container", NULL)) {
-			of_spmi_walk_slave_container(&d_info, node);
-			continue;
+			if (have_dev_container)
+				of_spmi_walk_dev_container(&d_info, node);
+			else
+				of_spmi_walk_slave_container(&d_info, node);
 		} else {
 			struct of_spmi_res_info r_info;
 
-			r_info.node = node;
-			of_spmi_sum_resources(&r_info, 0);
-			rc = of_spmi_allocate_resources(&d_info, &r_info);
-			if (rc)
+			/**
+			 * A dev container at the second level without a slave
+			 * container is considered an error.
+			 */
+			if (have_dev_container) {
+				dev_err(&ctrl->dev, "%s: structural error,"
+				     " node %s has spmi-dev-container without"
+				     " specifying spmi-slave-container\n",
+				     __func__, node->full_name);
 				continue;
-			of_spmi_create_device(&d_info, node);
+			}
+
+			rc = of_spmi_alloc_device_store(&d_info, 1);
+			if (rc) {
+				dev_err(&ctrl->dev, "%s: unable to allocate"
+					" device resources\n", __func__);
+				continue;
+			}
+
+			of_spmi_init_resource(&r_info, node);
+			of_spmi_sum_node_resources(&r_info, 0);
+			rc = of_spmi_allocate_node_resources(&d_info,
+								&r_info, 0);
+			if (rc) {
+				dev_err(&ctrl->dev, "%s: unable to allocate"
+						" resources\n", __func__);
+				of_spmi_free_device_resources(&d_info);
+				continue;
+			}
+
+			of_spmi_populate_node_resources(&d_info, &r_info, 0);
+
+			rc = of_spmi_create_device(&d_info, node);
+			if (rc) {
+				dev_err(&ctrl->dev, "%s: unable to create"
+						" device\n", __func__);
+				of_spmi_free_device_resources(&d_info);
+				continue;
+			}
 		}
 	}
 
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index f157ff3..819aa2e 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -16,6 +16,7 @@
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
 #include <linux/errno.h>
+#include <linux/power_supply.h>
 #include <linux/mfd/pm8xxx/pm8921-bms.h>
 #include <linux/mfd/pm8xxx/core.h>
 #include <linux/mfd/pm8xxx/pm8xxx-adc.h>
@@ -90,6 +91,8 @@
 	struct delayed_work	calib_ccadc_work;
 	unsigned int		calib_delay_ms;
 	unsigned int		revision;
+	unsigned int		xoadc_v0625_usb_present;
+	unsigned int		xoadc_v0625_usb_absent;
 	unsigned int		xoadc_v0625;
 	unsigned int		xoadc_v125;
 	unsigned int		batt_temp_channel;
@@ -117,6 +120,9 @@
 #define DEFAULT_OCV_MICROVOLTS		3900000
 #define DEFAULT_CHARGE_CYCLES		0
 
+static int last_usb_cal_delta_uv = 1800;
+module_param(last_usb_cal_delta_uv, int, 0644);
+
 static int last_chargecycles = DEFAULT_CHARGE_CYCLES;
 static int last_charge_increase;
 module_param(last_chargecycles, int, 0644);
@@ -302,6 +308,23 @@
 	return 0;
 }
 
+static int usb_chg_plugged_in(void)
+{
+	union power_supply_propval ret = {0,};
+	static struct power_supply *psy;
+
+	if (psy == NULL) {
+		psy = power_supply_get_by_name("usb");
+		if (psy == NULL)
+			return 0;
+	}
+
+	if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret))
+		return 0;
+
+	return ret.intval;
+}
+
 #define HOLD_OREG_DATA		BIT(1)
 static int pm_bms_lock_output_data(struct pm8921_bms_chip *chip)
 {
@@ -396,18 +419,32 @@
 #define XOADC_CALIB_UV		625000
 #define VBATT_MUL_FACTOR	3
 static int adjust_xo_vbatt_reading(struct pm8921_bms_chip *chip,
-							unsigned int uv)
+					int usb_chg, unsigned int uv)
 {
-	u64 numerator, denominator;
+	s64 numerator, denominator;
+	int local_delta;
 
 	if (uv == 0)
 		return 0;
 
-	numerator = ((u64)uv - chip->xoadc_v0625) * XOADC_CALIB_UV;
-	denominator =  chip->xoadc_v125 - chip->xoadc_v0625;
+	/* dont adjust if not calibrated */
+	if (chip->xoadc_v0625 == 0 || chip->xoadc_v125 == 0) {
+		pr_debug("No cal yet return %d\n", VBATT_MUL_FACTOR * uv);
+		return VBATT_MUL_FACTOR * uv;
+	}
+
+	if (usb_chg)
+		local_delta = last_usb_cal_delta_uv;
+	else
+		local_delta = 0;
+
+	pr_debug("using delta = %d\n", local_delta);
+	numerator = ((s64)uv - chip->xoadc_v0625 - local_delta)
+							* XOADC_CALIB_UV;
+	denominator =  (s64)chip->xoadc_v125 - chip->xoadc_v0625 - local_delta;
 	if (denominator == 0)
 		return uv * VBATT_MUL_FACTOR;
-	return (XOADC_CALIB_UV + div_u64(numerator, denominator))
+	return (XOADC_CALIB_UV + local_delta + div_s64(numerator, denominator))
 						* VBATT_MUL_FACTOR;
 }
 
@@ -474,11 +511,12 @@
 }
 
 static int convert_vbatt_raw_to_uv(struct pm8921_bms_chip *chip,
+					int usb_chg,
 					uint16_t reading, int *result)
 {
 	*result = xoadc_reading_to_microvolt(reading);
 	pr_debug("raw = %04x vbatt = %u\n", reading, *result);
-	*result = adjust_xo_vbatt_reading(chip, *result);
+	*result = adjust_xo_vbatt_reading(chip, usb_chg, *result);
 	pr_debug("after adj vbatt = %u\n", *result);
 	return 0;
 }
@@ -778,6 +816,7 @@
 	int16_t vsense_raw;
 	int16_t vbat_raw;
 	int vsense_uv;
+	int usb_chg;
 
 	if (the_chip == NULL) {
 		pr_err("Called to early\n");
@@ -803,7 +842,9 @@
 
 	mutex_unlock(&the_chip->bms_output_lock);
 
-	convert_vbatt_raw_to_uv(the_chip, vbat_raw, vbat_uv);
+	usb_chg = usb_chg_plugged_in();
+
+	convert_vbatt_raw_to_uv(the_chip, usb_chg, vbat_raw, vbat_uv);
 	convert_vsense_to_uv(the_chip, vsense_raw, &vsense_uv);
 	*ibat_ua = vsense_uv * 1000 / (int)the_chip->r_sense;
 
@@ -818,6 +859,8 @@
 static int read_soc_params_raw(struct pm8921_bms_chip *chip,
 				struct pm8921_soc_params *raw)
 {
+	int usb_chg;
+
 	mutex_lock(&chip->bms_output_lock);
 	pm_bms_lock_output_data(chip);
 
@@ -834,13 +877,14 @@
 	pm_bms_unlock_output_data(chip);
 	mutex_unlock(&chip->bms_output_lock);
 
-	convert_vbatt_raw_to_uv(chip,
+	usb_chg = usb_chg_plugged_in();
+	convert_vbatt_raw_to_uv(chip, usb_chg,
 			raw->vbatt_for_rbatt_raw, &raw->vbatt_for_rbatt_uv);
-	convert_vbatt_raw_to_uv(chip,
+	convert_vbatt_raw_to_uv(chip, usb_chg,
 			raw->ocv_for_rbatt_raw, &raw->ocv_for_rbatt_uv);
-	convert_vbatt_raw_to_uv(chip,
+	convert_vbatt_raw_to_uv(chip, usb_chg,
 			raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
-	convert_vsense_to_uv(chip,
+	convert_vbatt_raw_to_uv(chip, usb_chg,
 			raw->vsense_for_rbatt_raw, &raw->vsense_for_rbatt_uv);
 
 	if (raw->last_good_ocv_uv)
@@ -866,9 +910,9 @@
 {
 	unsigned int  r_batt;
 
-	if (raw->ocv_for_rbatt_uv == 0
-		|| raw->ocv_for_rbatt_uv == raw->vbatt_for_rbatt_uv
-		|| raw->vsense_for_rbatt_raw == 0) {
+	if (raw->ocv_for_rbatt_uv <= 0
+		|| raw->ocv_for_rbatt_uv <= raw->vbatt_for_rbatt_uv
+		|| raw->vsense_for_rbatt_raw <= 0) {
 		pr_debug("rbatt readings unavailable ocv = %d, vbatt = %d,"
 					"vsen = %d\n",
 					raw->ocv_for_rbatt_uv,
@@ -1180,11 +1224,13 @@
 
 	return soc;
 }
-
+#define MIN_DELTA_625_UV	1000
 static void calib_hkadc(struct pm8921_bms_chip *chip)
 {
 	int voltage, rc;
 	struct pm8xxx_adc_chan_result result;
+	int usb_chg;
+	int this_delta;
 
 	rc = pm8xxx_adc_read(the_chip->ref1p25v_channel, &result);
 	if (rc) {
@@ -1204,10 +1250,30 @@
 		return;
 	}
 	voltage = xoadc_reading_to_microvolt(result.adc_code);
-	pr_debug("result 0.625V = 0x%x, voltage = %duV adc_meas = %lld\n",
-				result.adc_code, voltage, result.measurement);
+
+	usb_chg = usb_chg_plugged_in();
+	pr_debug("result 0.625V = 0x%x, voltage = %duV adc_meas = %lld "
+				"usb_chg = %d\n",
+				result.adc_code, voltage, result.measurement,
+				usb_chg);
+
+	if (usb_chg)
+		chip->xoadc_v0625_usb_present = voltage;
+	else
+		chip->xoadc_v0625_usb_absent = voltage;
 
 	chip->xoadc_v0625 = voltage;
+	if (chip->xoadc_v0625_usb_present && chip->xoadc_v0625_usb_absent) {
+		this_delta = chip->xoadc_v0625_usb_present
+						- chip->xoadc_v0625_usb_absent;
+		pr_debug("this_delta= %duV\n", this_delta);
+		if (this_delta > MIN_DELTA_625_UV)
+			last_usb_cal_delta_uv = this_delta;
+		pr_debug("625V_present= %d, 625V_absent= %d, delta = %duV\n",
+			chip->xoadc_v0625_usb_present,
+			chip->xoadc_v0625_usb_absent,
+			last_usb_cal_delta_uv);
+	}
 }
 
 static void calibrate_hkadc_work(struct work_struct *work)
@@ -1592,6 +1658,7 @@
 {
 	int ocv_uv, rc;
 	int16_t ocv_raw;
+	int usb_chg;
 
 	/*
 	 * Check if a ocv is available in bms hw,
@@ -1600,7 +1667,8 @@
 	 */
 	ocv_uv = 0;
 	pm_bms_read_output_data(chip, LAST_GOOD_OCV_VALUE, &ocv_raw);
-	rc = convert_vbatt_raw_to_uv(chip, ocv_raw, &ocv_uv);
+	usb_chg = usb_chg_plugged_in();
+	rc = convert_vbatt_raw_to_uv(chip, usb_chg, ocv_raw, &ocv_uv);
 	if (rc || ocv_uv == 0) {
 		rc = adc_based_ocv(chip, &ocv_uv);
 		if (rc) {
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 60d4e64..78757f9 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -415,6 +415,13 @@
 				disable ? CHG_CHARGE_DIS_BIT : 0);
 }
 
+static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
+{
+	u8 temp;
+
+	pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
+	return  temp & CHG_CHARGE_DIS_BIT;
+}
 #define PM8921_CHG_V_MIN_MV	3240
 #define PM8921_CHG_V_STEP_MV	20
 #define PM8921_CHG_V_STEP_10MV_OFFSET_BIT	BIT(7)
@@ -1044,7 +1051,13 @@
 	}
 }
 
-static enum power_supply_property pm_power_props[] = {
+static enum power_supply_property pm_power_props_usb[] = {
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+};
+
+static enum power_supply_property pm_power_props_mains[] = {
 	POWER_SUPPLY_PROP_PRESENT,
 	POWER_SUPPLY_PROP_ONLINE,
 };
@@ -1054,7 +1067,53 @@
 };
 
 #define USB_WALL_THRESHOLD_MA	500
-static int pm_power_get_property(struct power_supply *psy,
+static int pm_power_get_property_mains(struct power_supply *psy,
+				  enum power_supply_property psp,
+				  union power_supply_propval *val)
+{
+	int current_max;
+
+	/* Check if called before init */
+	if (!the_chip)
+		return -EINVAL;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_PRESENT:
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = 0;
+		if (charging_disabled)
+			return 0;
+
+		/* check external charger first before the dc path */
+		if (is_ext_charging(the_chip)) {
+			val->intval = 1;
+			return 0;
+		}
+
+		if (pm_is_chg_charge_dis(the_chip)) {
+			val->intval = 0;
+			return 0;
+		}
+
+		if (the_chip->dc_present) {
+			val->intval = 1;
+			return 0;
+		}
+
+		/* USB with max current greater than 500 mA connected */
+		pm_chg_iusbmax_get(the_chip, &current_max);
+		if (current_max > USB_WALL_THRESHOLD_MA)
+			val->intval = is_usb_chg_plugged_in(the_chip);
+			return 0;
+
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int pm_power_get_property_usb(struct power_supply *psy,
 				  enum power_supply_property psp,
 				  union power_supply_propval *val)
 {
@@ -1066,8 +1125,12 @@
 
 	switch (psp) {
 	case POWER_SUPPLY_PROP_CURRENT_MAX:
-		pm_chg_iusbmax_get(the_chip, &current_max);
-		val->intval = current_max;
+		if (pm_is_chg_charge_dis(the_chip)) {
+			val->intval = 0;
+		} else {
+			pm_chg_iusbmax_get(the_chip, &current_max);
+			val->intval = current_max;
+		}
 		break;
 	case POWER_SUPPLY_PROP_PRESENT:
 	case POWER_SUPPLY_PROP_ONLINE:
@@ -1075,6 +1138,13 @@
 		if (charging_disabled)
 			return 0;
 
+		/*
+		 * if drawing any current from usb is disabled behave
+		 * as if no usb cable is connected
+		 */
+		if (pm_is_chg_charge_dis(the_chip))
+			return 0;
+
 		/* USB charging */
 		if (psy->type == POWER_SUPPLY_TYPE_USB ||
 				psy->type == POWER_SUPPLY_TYPE_USB_DCP ||
@@ -1083,22 +1153,6 @@
 			val->intval = is_usb_chg_plugged_in(the_chip);
 			return 0;
 		}
-
-		/* DC charging */
-		if (psy->type == POWER_SUPPLY_TYPE_MAINS) {
-			/* external charger is connected */
-			if (the_chip->dc_present || is_ext_charging(the_chip)) {
-				val->intval = 1;
-				return 0;
-			}
-			/* USB with max current greater than 500 mA connected */
-			pm_chg_iusbmax_get(the_chip, &current_max);
-			if (current_max > USB_WALL_THRESHOLD_MA)
-				val->intval = is_usb_chg_plugged_in(the_chip);
-			return 0;
-		}
-
-		pr_err("Unkown POWER_SUPPLY_TYPE %d\n", psy->type);
 		break;
 	default:
 		return -EINVAL;
@@ -1667,6 +1721,7 @@
 {
 	int usb_present;
 
+	pm_chg_failed_clear(chip, 1);
 	usb_present = is_usb_chg_plugged_in(chip);
 	if (chip->usb_present ^ usb_present) {
 		notify_usb_of_the_plugin_event(usb_present);
@@ -2328,6 +2383,7 @@
 	struct pm8921_chg_chip *chip = container_of(dwork,
 				struct pm8921_chg_chip, update_heartbeat_work);
 
+	pm_chg_failed_clear(chip, 1);
 	power_supply_changed(&chip->batt_psy);
 	schedule_delayed_work(&chip->update_heartbeat_work,
 			      round_jiffies_relative(msecs_to_jiffies
@@ -2456,7 +2512,10 @@
 	struct pm8921_chg_chip *chip = container_of(dwork,
 				struct pm8921_chg_chip, eoc_work);
 	static int count;
-	int end = is_charging_finished(chip);
+	int end;
+
+	pm_chg_failed_clear(chip, 1);
+	end = is_charging_finished(chip);
 
 	if (end == CHG_NOT_IN_PROGRESS) {
 			/* enable fastchg irq */
@@ -3457,17 +3516,17 @@
 	chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
 	chip->usb_psy.supplied_to = pm_power_supplied_to,
 	chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
-	chip->usb_psy.properties = pm_power_props,
-	chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props),
-	chip->usb_psy.get_property = pm_power_get_property,
+	chip->usb_psy.properties = pm_power_props_usb,
+	chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb),
+	chip->usb_psy.get_property = pm_power_get_property_usb,
 
 	chip->dc_psy.name = "pm8921-dc",
 	chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
 	chip->dc_psy.supplied_to = pm_power_supplied_to,
 	chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
-	chip->dc_psy.properties = pm_power_props,
-	chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props),
-	chip->dc_psy.get_property = pm_power_get_property,
+	chip->dc_psy.properties = pm_power_props_mains,
+	chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains),
+	chip->dc_psy.get_property = pm_power_get_property_mains,
 
 	chip->batt_psy.name = "battery",
 	chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 49e0d0e..fb1a99f 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -344,5 +344,14 @@
 	  chip. It is only supposed to be used when Linux on application
 	  processor is the master in control of XO buffers.
 
+config REGULATOR_STUB
+	tristate "Stub Regulator"
+	help
+	  This driver adds stub regulator support. The driver is absent of any
+	  real hardware based implementation. It allows for clients to register
+	  their regulator device constraints and use all of the standard
+	  regulator interfaces. This is useful for bringing up new platforms
+	  when the real hardware based implementation may not be yet available.
+	  Clients can use the real regulator device names with proper
+	  constraint checking while the real driver is being developed.
 endif
-
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 5318cff..74b1f71 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -48,5 +48,6 @@
 obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
 obj-$(CONFIG_REGULATOR_PM8058_XO) += pm8058-xo.o
 obj-$(CONFIG_REGULATOR_PM8XXX) += pm8xxx-regulator.o
+obj-$(CONFIG_REGULATOR_STUB) += stub-regulator.o
 
 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/stub-regulator.c b/drivers/regulator/stub-regulator.c
new file mode 100644
index 0000000..afac80a
--- /dev/null
+++ b/drivers/regulator/stub-regulator.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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/stub-regulator.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#define STUB_REGULATOR_MAX_NAME 40
+
+struct regulator_stub {
+	struct regulator_desc	rdesc;
+	struct regulator_dev	*rdev;
+	int			voltage;
+	bool			enabled;
+	int			mode;
+	int			hpm_min_load;
+	int			system_uA;
+	char			name[STUB_REGULATOR_MAX_NAME];
+};
+
+static int regulator_stub_set_voltage(struct regulator_dev *rdev, int min_uV,
+				  int max_uV, unsigned *selector)
+{
+	struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
+	vreg_priv->voltage = min_uV;
+	return 0;
+}
+
+static int regulator_stub_get_voltage(struct regulator_dev *rdev)
+{
+	struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
+	return vreg_priv->voltage;
+}
+
+static int regulator_stub_list_voltage(struct regulator_dev *rdev,
+				    unsigned selector)
+{
+	struct regulation_constraints *constraints = rdev->constraints;
+
+	if (selector >= 2)
+		return -EINVAL;
+	else if (selector == 0)
+		return constraints->min_uV;
+	else
+		return constraints->max_uV;
+}
+
+static unsigned int regulator_stub_get_mode(struct regulator_dev *rdev)
+{
+	struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
+	return vreg_priv->mode;
+}
+
+static int regulator_stub_set_mode(struct regulator_dev *rdev,
+				   unsigned int mode)
+{
+	struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
+
+	if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
+		dev_err(&rdev->dev, "%s: invalid mode requested %u\n",
+							__func__, mode);
+		return -EINVAL;
+	}
+	vreg_priv->mode = mode;
+	return 0;
+}
+
+static unsigned int regulator_stub_get_optimum_mode(struct regulator_dev *rdev,
+		int input_uV, int output_uV, int load_uA)
+{
+	struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
+	unsigned int mode;
+
+	if (load_uA + vreg_priv->system_uA >= vreg_priv->hpm_min_load)
+		mode = REGULATOR_MODE_NORMAL;
+	else
+		mode = REGULATOR_MODE_IDLE;
+
+	return mode;
+}
+
+static int regulator_stub_enable(struct regulator_dev *rdev)
+{
+	struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
+	vreg_priv->enabled = true;
+	return 0;
+}
+
+static int regulator_stub_disable(struct regulator_dev *rdev)
+{
+	struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
+	vreg_priv->enabled = false;
+	return 0;
+}
+
+static int regulator_stub_is_enabled(struct regulator_dev *rdev)
+{
+	struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
+	return vreg_priv->enabled;
+}
+
+/* Real regulator operations. */
+static struct regulator_ops regulator_stub_ops = {
+	.enable			= regulator_stub_enable,
+	.disable		= regulator_stub_disable,
+	.is_enabled		= regulator_stub_is_enabled,
+	.set_voltage		= regulator_stub_set_voltage,
+	.get_voltage		= regulator_stub_get_voltage,
+	.list_voltage		= regulator_stub_list_voltage,
+	.set_mode		= regulator_stub_set_mode,
+	.get_mode		= regulator_stub_get_mode,
+	.get_optimum_mode	= regulator_stub_get_optimum_mode,
+};
+
+static void regulator_stub_cleanup(struct regulator_stub *vreg_priv)
+{
+	if (vreg_priv && vreg_priv->rdev)
+		regulator_unregister(vreg_priv->rdev);
+	kfree(vreg_priv);
+}
+
+static int __devinit regulator_stub_probe(struct platform_device *pdev)
+{
+	struct stub_regulator_pdata *vreg_pdata;
+	struct regulator_desc *rdesc;
+	struct regulator_stub *vreg_priv;
+	int rc;
+
+	vreg_pdata = pdev->dev.platform_data;
+	if (!vreg_pdata) {
+		dev_err(&pdev->dev, "%s: no platform data\n", __func__);
+		return -EINVAL;
+	}
+
+	vreg_priv = kzalloc(sizeof(*vreg_priv), GFP_KERNEL);
+	if (!vreg_priv) {
+		dev_err(&pdev->dev, "%s: Unable to allocate memory\n",
+				__func__);
+		return -ENOMEM;
+	}
+	dev_set_drvdata(&pdev->dev, vreg_priv);
+
+	rdesc = &vreg_priv->rdesc;
+	strncpy(vreg_priv->name, vreg_pdata->init_data.constraints.name,
+						   STUB_REGULATOR_MAX_NAME);
+	rdesc->name = vreg_priv->name;
+	rdesc->ops = &regulator_stub_ops;
+
+	/*
+	 * Ensure that voltage set points are handled correctly for regulators
+	 * which have a specified voltage constraint range, as well as those
+	 * that do not.
+	 */
+	if (vreg_pdata->init_data.constraints.min_uV == 0 &&
+	    vreg_pdata->init_data.constraints.max_uV == 0)
+		rdesc->n_voltages = 0;
+	else
+		rdesc->n_voltages = 2;
+
+	rdesc->id    = pdev->id;
+	rdesc->owner = THIS_MODULE;
+	rdesc->type  = REGULATOR_VOLTAGE;
+	vreg_priv->system_uA = vreg_pdata->system_uA;
+	vreg_priv->hpm_min_load = vreg_pdata->hpm_min_load;
+
+	vreg_priv->rdev = regulator_register(rdesc, &pdev->dev,
+			&(vreg_pdata->init_data), vreg_priv);
+	if (IS_ERR(vreg_priv->rdev)) {
+		rc = PTR_ERR(vreg_priv->rdev);
+		vreg_priv->rdev = NULL;
+		dev_err(&pdev->dev, "%s: regulator_register failed\n",
+				__func__);
+		goto err_probe;
+	}
+
+	return 0;
+
+err_probe:
+	regulator_stub_cleanup(vreg_priv);
+	return rc;
+}
+
+static int __devexit regulator_stub_remove(struct platform_device *pdev)
+{
+	struct regulator_stub *vreg_priv = dev_get_drvdata(&pdev->dev);
+
+	regulator_stub_cleanup(vreg_priv);
+	return 0;
+}
+
+static struct platform_driver regulator_stub_driver = {
+	.probe	= regulator_stub_probe,
+	.remove	= __devexit_p(regulator_stub_remove),
+	.driver	= {
+		.name	= STUB_REGULATOR_DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init regulator_stub_init(void)
+{
+	return platform_driver_register(&regulator_stub_driver);
+}
+postcore_initcall(regulator_stub_init);
+
+static void __exit regulator_stub_exit(void)
+{
+	platform_driver_unregister(&regulator_stub_driver);
+}
+module_exit(regulator_stub_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("stub regulator driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform: " STUB_REGULATOR_DRIVER_NAME);
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index 2842cd8..20a290a 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -233,9 +233,9 @@
 	spmidev->name = info->name;
 	spmidev->sid  = info->slave_id;
 	spmidev->dev.of_node = info->of_node;
-	spmidev->resource = info->resource;
-	spmidev->num_resources = info->num_resources;
 	spmidev->dev.platform_data = (void *)info->platform_data;
+	spmidev->num_dev_node = info->num_dev_node;
+	spmidev->dev_node = info->dev_node;
 
 	rc = spmi_add_device(spmidev);
 	if (rc < 0) {
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 7e731de..91c3123 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -164,6 +164,18 @@
 	.bNumConfigurations   = 1,
 };
 
+static struct usb_otg_descriptor otg_descriptor = {
+	.bLength =		sizeof otg_descriptor,
+	.bDescriptorType =	USB_DT_OTG,
+	.bmAttributes =		USB_OTG_SRP | USB_OTG_HNP,
+	.bcdOTG               = __constant_cpu_to_le16(0x0200),
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+	(struct usb_descriptor_header *) &otg_descriptor,
+	NULL,
+};
+
 static struct usb_configuration android_config_driver = {
 	.label		= "android",
 	.unbind		= android_unbind_config,
@@ -1352,6 +1364,9 @@
 	strings_dev[STRING_SERIAL_IDX].id = id;
 	device_desc.iSerialNumber = id;
 
+	if (gadget_is_otg(cdev->gadget))
+		android_config_driver.descriptors = otg_desc;
+
 	gcnum = usb_gadget_controller_number(gadget);
 	if (gcnum >= 0)
 		device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index 8ea4632..fac777c 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -47,7 +47,8 @@
 	.flags			= CI13XXX_REGS_SHARED |
 				  CI13XXX_REQUIRE_TRANSCEIVER |
 				  CI13XXX_PULLUP_ON_VBUS |
-				  CI13XXX_ZERO_ITC,
+				  CI13XXX_ZERO_ITC |
+				  CI13XXX_IS_OTG,
 
 	.notify_event		= ci13xxx_msm_notify_event,
 };
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 0fc9a03..b64a38a 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -1918,6 +1918,11 @@
 	udc->configured = 0;
 	spin_unlock_irqrestore(udc->lock, flags);
 
+	gadget->b_hnp_enable = 0;
+	gadget->a_hnp_support = 0;
+	gadget->host_request = 0;
+	gadget->otg_srp_reqd = 0;
+
 	/* flush all endpoints */
 	gadget_for_each_ep(ep, gadget) {
 		usb_ep_fifo_flush(ep);
@@ -2046,8 +2051,15 @@
 	}
 
 	if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
-		/* Assume that device is bus powered for now. */
-		*((u16 *)req->buf) = _udc->remote_wakeup << 1;
+		if (setup->wIndex == OTG_STATUS_SELECTOR) {
+			*((u8 *)req->buf) = _udc->gadget.host_request <<
+						HOST_REQUEST_FLAG;
+			req->length = 1;
+		} else {
+			/* Assume that device is bus powered for now. */
+			*((u16 *)req->buf) = _udc->remote_wakeup << 1;
+		}
+		/* TODO: D1 - Remote Wakeup; D0 - Self Powered */
 		retval = 0;
 	} else if ((setup->bRequestType & USB_RECIP_MASK) \
 		   == USB_RECIP_ENDPOINT) {
@@ -2297,8 +2309,7 @@
 			    type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
 			    type != (USB_DIR_IN|USB_RECIP_INTERFACE))
 				goto delegate;
-			if (le16_to_cpu(req.wLength) != 2 ||
-			    le16_to_cpu(req.wValue)  != 0)
+			if (le16_to_cpu(req.wValue)  != 0)
 				break;
 			err = isr_get_status_response(udc, &req);
 			break;
@@ -2342,6 +2353,16 @@
 					udc->remote_wakeup = 1;
 					err = isr_setup_status_phase(udc);
 					break;
+				case USB_DEVICE_B_HNP_ENABLE:
+					udc->gadget.b_hnp_enable = 1;
+					err = isr_setup_status_phase(udc);
+					break;
+				case USB_DEVICE_A_HNP_SUPPORT:
+					udc->gadget.a_hnp_support = 1;
+					err = isr_setup_status_phase(udc);
+					break;
+				case USB_DEVICE_A_ALT_HNP_SUPPORT:
+					break;
 				case USB_DEVICE_TEST_MODE:
 					tmode = le16_to_cpu(req.wIndex) >> 8;
 					switch (tmode) {
@@ -2354,11 +2375,21 @@
 						err = isr_setup_status_phase(
 								udc);
 						break;
+					case TEST_OTG_SRP_REQD:
+						udc->gadget.otg_srp_reqd = 1;
+						err = isr_setup_status_phase(
+								udc);
+						break;
+					case TEST_OTG_HNP_REQD:
+						udc->gadget.host_request = 1;
+						err = isr_setup_status_phase(
+								udc);
+						break;
 					default:
 						break;
 					}
 				default:
-					goto delegate;
+					break;
 				}
 			} else {
 				goto delegate;
@@ -3206,7 +3237,10 @@
 	udc->gadget.ops          = &usb_gadget_ops;
 	udc->gadget.speed        = USB_SPEED_UNKNOWN;
 	udc->gadget.is_dualspeed = 1;
-	udc->gadget.is_otg       = 0;
+	if (udc->udc_driver->flags & CI13XXX_IS_OTG)
+		udc->gadget.is_otg       = 1;
+	else
+		udc->gadget.is_otg       = 0;
 	udc->gadget.name         = driver->name;
 
 	INIT_LIST_HEAD(&udc->gadget.ep_list);
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index fce611a..13b54c7 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -125,6 +125,7 @@
 #define CI13XXX_PULLUP_ON_VBUS		BIT(2)
 #define CI13XXX_DISABLE_STREAMING	BIT(3)
 #define CI13XXX_ZERO_ITC		BIT(4)
+#define CI13XXX_IS_OTG			BIT(5)
 
 #define CI13XXX_CONTROLLER_RESET_EVENT		0
 #define CI13XXX_CONTROLLER_CONNECT_EVENT	1
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 39c53da..19ad77f 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -67,7 +67,7 @@
 
 	spinlock_t		req_lock;	/* guard {rx,tx}_reqs */
 	struct list_head	tx_reqs, rx_reqs;
-	atomic_t		tx_qlen;
+	unsigned		tx_qlen;
 
 	struct sk_buff_head	rx_frames;
 
@@ -484,7 +484,6 @@
 	spin_unlock(&dev->req_lock);
 	dev_kfree_skb_any(skb);
 
-	atomic_dec(&dev->tx_qlen);
 	if (netif_carrier_ok(dev->net))
 		netif_wake_queue(dev->net);
 }
@@ -599,10 +598,18 @@
 	req->length = length;
 
 	/* throttle highspeed IRQ rate back slightly */
-	if (gadget_is_dualspeed(dev->gadget))
-		req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
-			? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
-			: 0;
+	if (gadget_is_dualspeed(dev->gadget) &&
+			 (dev->gadget->speed == USB_SPEED_HIGH)) {
+		dev->tx_qlen++;
+		if (dev->tx_qlen == qmult) {
+			req->no_interrupt = 0;
+			dev->tx_qlen = 0;
+		} else {
+			req->no_interrupt = 1;
+		}
+	} else {
+		req->no_interrupt = 0;
+	}
 
 	retval = usb_ep_queue(in, req, GFP_ATOMIC);
 	switch (retval) {
@@ -611,7 +618,6 @@
 		break;
 	case 0:
 		net->trans_start = jiffies;
-		atomic_inc(&dev->tx_qlen);
 	}
 
 	if (retval) {
@@ -637,7 +643,7 @@
 	rx_fill(dev, gfp_flags);
 
 	/* and open the tx floodgates */
-	atomic_set(&dev->tx_qlen, 0);
+	dev->tx_qlen = 0;
 	netif_wake_queue(dev->net);
 }
 
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index d438555..657bc42 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -1203,10 +1203,9 @@
 			ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
 #ifdef	CONFIG_USB_OTG
 			if (hcd->self.otg_port == (wIndex + 1) &&
-					hcd->self.b_hnp_enable &&
-					ehci->start_hnp) {
+					hcd->self.b_hnp_enable) {
 				set_bit(wIndex, &ehci->suspended_ports);
-				ehci->start_hnp(ehci);
+				otg_start_hnp(ehci->transceiver);
 				break;
 			}
 #endif
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index dd3ec34..795e7a8 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -24,6 +24,7 @@
 
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/irq.h>
 #include <linux/err.h>
 #include <linux/wakelock.h>
 #include <linux/pm_runtime.h>
@@ -53,6 +54,7 @@
 	struct msm_xo_voter	*xo_handle;
 	struct wake_lock	wlock;
 	int			peripheral_status_irq;
+	int			wakeup_irq;
 };
 
 static inline struct msm_hsic_hcd *hcd_to_hsic(struct usb_hcd *hcd)
@@ -734,7 +736,7 @@
 {
 	struct msm_hsic_hcd *mehci = dev_id;
 
-	pr_debug("%s: mechi:%p dev_id:%p\n", __func__, mehci, dev_id);
+	pr_debug("%s: mehci:%p dev_id:%p\n", __func__, mehci, dev_id);
 
 	if (mehci)
 		msm_hsic_config_gpios(mehci, 0);
@@ -742,6 +744,16 @@
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t msm_hsic_wakeup_irq(int irq, void *data)
+{
+	struct msm_hsic_hcd *mehci = data;
+
+	dev_dbg(mehci->dev, "%s: hsic remote wakeup interrupt\n", __func__);
+
+	return IRQ_HANDLED;
+}
+
+
 static int __devinit ehci_hsic_msm_probe(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd;
@@ -856,6 +868,24 @@
 				__func__, mehci->peripheral_status_irq, ret);
 	}
 
+	/* configure wakeup irq */
+	ret = platform_get_irq(pdev, 2);
+	if (ret > 0) {
+		mehci->wakeup_irq = ret;
+		dev_dbg(&pdev->dev, "wakeup_irq: %d\n", mehci->wakeup_irq);
+		ret = request_irq(mehci->wakeup_irq, msm_hsic_wakeup_irq,
+				IRQF_TRIGGER_LOW,
+				"msm_hsic_wakeup", mehci);
+		if (!ret) {
+			disable_irq_nosync(mehci->wakeup_irq);
+			enable_irq_wake(mehci->wakeup_irq);
+		} else {
+			dev_err(&pdev->dev, "request_irq(%d) failed: %d\n",
+					mehci->wakeup_irq, ret);
+			mehci->wakeup_irq = 0;
+		}
+	}
+
 	/*
 	 * This pdev->dev is assigned parent of root-hub by USB core,
 	 * hence, runtime framework automatically calls this driver's
@@ -893,6 +923,10 @@
 
 	if (mehci->peripheral_status_irq)
 		free_irq(mehci->peripheral_status_irq, mehci);
+	if (mehci->wakeup_irq) {
+		disable_irq_wake(mehci->wakeup_irq);
+		free_irq(mehci->wakeup_irq, mehci);
+	}
 
 	device_init_wakeup(&pdev->dev, 0);
 	pm_runtime_set_suspended(&pdev->dev);
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index f45f257..5649fd0 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -176,6 +176,7 @@
 		goto put_transceiver;
 	}
 
+	hcd_to_ehci(hcd)->transceiver = otg;
 	device_init_wakeup(&pdev->dev, 1);
 	pm_runtime_enable(&pdev->dev);
 
@@ -199,6 +200,7 @@
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_set_suspended(&pdev->dev);
 
+	hcd_to_ehci(hcd)->transceiver = NULL;
 	otg_set_host(otg, NULL);
 	otg_put_transceiver(otg);
 
diff --git a/drivers/usb/host/ehci-msm72k.c b/drivers/usb/host/ehci-msm72k.c
index b3939ef..bf2cbd1 100644
--- a/drivers/usb/host/ehci-msm72k.c
+++ b/drivers/usb/host/ehci-msm72k.c
@@ -605,19 +605,6 @@
 	return retval;
 }
 
-#ifdef	CONFIG_USB_OTG
-static void ehci_msm_start_hnp(struct ehci_hcd *ehci)
-{
-	struct usb_hcd *hcd = ehci_to_hcd(ehci);
-	struct msmusb_hcd *mhcd = hcd_to_mhcd(hcd);
-
-	/* OTG driver handles HNP */
-	otg_start_hnp(mhcd->xceiv);
-}
-#else
-#define ehci_msm_start_hnp	NULL
-#endif
-
 static int msm_xusb_init_host(struct platform_device *pdev,
 			      struct msmusb_hcd *mhcd)
 {
@@ -645,9 +632,9 @@
 		otg = container_of(mhcd->xceiv, struct msm_otg, otg);
 		hcd->regs = otg->regs;
 		otg->start_host = msm_hsusb_start_host;
-		ehci->start_hnp = ehci_msm_start_hnp;
 
 		ret = otg_set_host(mhcd->xceiv, &hcd->self);
+		ehci->transceiver = mhcd->xceiv;
 		break;
 	case USB_PHY_SERIAL_PMIC:
 		hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
@@ -753,6 +740,7 @@
 	case USB_PHY_INTEGRATED:
 		if (pdata->vbus_init)
 			pdata->vbus_init(0);
+		hcd_to_ehci(hcd)->transceiver = NULL;
 		otg_set_host(mhcd->xceiv, NULL);
 		otg_put_transceiver(mhcd->xceiv);
 		cancel_work_sync(&mhcd->otg_work);
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 05c7faf..2c4f291 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -124,8 +124,6 @@
 	ktime_t			last_periodic_enable;
 	u32			command;
 
-	void (*start_hnp)(struct ehci_hcd *ehci);
-
 	/* SILICON QUIRKS */
 	unsigned		no_selective_suspend:1;
 	unsigned		has_fsl_port_bug:1; /* FreeScale */
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index dd07d4e..7ee02df 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -33,6 +33,7 @@
 #include <linux/usb/ulpi.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/hcd.h>
+#include <linux/usb/quirks.h>
 #include <linux/usb/msm_hsusb.h>
 #include <linux/usb/msm_hsusb_hw.h>
 #include <linux/regulator/consumer.h>
@@ -49,8 +50,8 @@
 #define DRIVER_NAME	"msm_otg"
 
 #define ID_TIMER_FREQ		(jiffies + msecs_to_jiffies(2000))
+#define ID_TIMER_INITIAL_FREQ	(jiffies + msecs_to_jiffies(1000))
 #define ULPI_IO_TIMEOUT_USEC	(10 * 1000)
-
 #define USB_PHY_3P3_VOL_MIN	3050000 /* uV */
 #define USB_PHY_3P3_VOL_MAX	3300000 /* uV */
 #define USB_PHY_3P3_HPM_LOAD	50000	/* uA */
@@ -581,25 +582,190 @@
 	return 0;
 }
 
+static const char *timer_string(int bit)
+{
+	switch (bit) {
+	case A_WAIT_VRISE:		return "a_wait_vrise";
+	case A_WAIT_VFALL:		return "a_wait_vfall";
+	case B_SRP_FAIL:		return "b_srp_fail";
+	case A_WAIT_BCON:		return "a_wait_bcon";
+	case A_AIDL_BDIS:		return "a_aidl_bdis";
+	case A_BIDL_ADIS:		return "a_bidl_adis";
+	case B_ASE0_BRST:		return "b_ase0_brst";
+	case A_TST_MAINT:		return "a_tst_maint";
+	case B_TST_SRP:			return "b_tst_srp";
+	case B_TST_CONFIG:		return "b_tst_config";
+	default:			return "UNDEFINED";
+	}
+}
+
+static enum hrtimer_restart msm_otg_timer_func(struct hrtimer *hrtimer)
+{
+	struct msm_otg *motg = container_of(hrtimer, struct msm_otg, timer);
+
+	switch (motg->active_tmout) {
+	case A_WAIT_VRISE:
+		/* TODO: use vbus_vld interrupt */
+		set_bit(A_VBUS_VLD, &motg->inputs);
+		break;
+	case A_TST_MAINT:
+		/* OTG PET: End session after TA_TST_MAINT */
+		set_bit(A_BUS_DROP, &motg->inputs);
+		break;
+	case B_TST_SRP:
+		/*
+		 * OTG PET: Initiate SRP after TB_TST_SRP of
+		 * previous session end.
+		 */
+		set_bit(B_BUS_REQ, &motg->inputs);
+		break;
+	case B_TST_CONFIG:
+		clear_bit(A_CONN, &motg->inputs);
+		break;
+	default:
+		set_bit(motg->active_tmout, &motg->tmouts);
+	}
+
+	pr_debug("expired %s timer\n", timer_string(motg->active_tmout));
+	queue_work(system_nrt_wq, &motg->sm_work);
+	return HRTIMER_NORESTART;
+}
+
+static void msm_otg_del_timer(struct msm_otg *motg)
+{
+	int bit = motg->active_tmout;
+
+	pr_debug("deleting %s timer. remaining %lld msec\n", timer_string(bit),
+			div_s64(ktime_to_us(hrtimer_get_remaining(
+					&motg->timer)), 1000));
+	hrtimer_cancel(&motg->timer);
+	clear_bit(bit, &motg->tmouts);
+}
+
+static void msm_otg_start_timer(struct msm_otg *motg, int time, int bit)
+{
+	clear_bit(bit, &motg->tmouts);
+	motg->active_tmout = bit;
+	pr_debug("starting %s timer\n", timer_string(bit));
+	hrtimer_start(&motg->timer,
+			ktime_set(time / 1000, (time % 1000) * 1000000),
+			HRTIMER_MODE_REL);
+}
+
+static void msm_otg_init_timer(struct msm_otg *motg)
+{
+	hrtimer_init(&motg->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	motg->timer.function = msm_otg_timer_func;
+}
+
+static int msm_otg_start_hnp(struct otg_transceiver *otg)
+{
+	struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+
+	if (otg->state != OTG_STATE_A_HOST) {
+		pr_err("HNP can not be initiated in %s state\n",
+				otg_state_string(otg->state));
+		return -EINVAL;
+	}
+
+	pr_debug("A-Host: HNP initiated\n");
+	clear_bit(A_BUS_REQ, &motg->inputs);
+	queue_work(system_nrt_wq, &motg->sm_work);
+	return 0;
+}
+
+static int msm_otg_start_srp(struct otg_transceiver *otg)
+{
+	struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+	u32 val;
+	int ret = 0;
+
+	if (otg->state != OTG_STATE_B_IDLE) {
+		pr_err("SRP can not be initiated in %s state\n",
+				otg_state_string(otg->state));
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if ((jiffies - motg->b_last_se0_sess) < msecs_to_jiffies(TB_SRP_INIT)) {
+		pr_debug("initial conditions of SRP are not met. Try again"
+				"after some time\n");
+		ret = -EAGAIN;
+		goto out;
+	}
+
+	pr_debug("B-Device SRP started\n");
+
+	/*
+	 * PHY won't pull D+ high unless it detects Vbus valid.
+	 * Since by definition, SRP is only done when Vbus is not valid,
+	 * software work-around needs to be used to spoof the PHY into
+	 * thinking it is valid. This can be done using the VBUSVLDEXTSEL and
+	 * VBUSVLDEXT register bits.
+	 */
+	ulpi_write(otg, 0x03, 0x97);
+	/*
+	 * Harware auto assist data pulsing: Data pulse is given
+	 * for 7msec; wait for vbus
+	 */
+	val = readl_relaxed(USB_OTGSC);
+	writel_relaxed((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP, USB_OTGSC);
+
+	/* VBUS plusing is obsoleted in OTG 2.0 supplement */
+out:
+	return ret;
+}
+
+static void msm_otg_host_hnp_enable(struct otg_transceiver *otg, bool enable)
+{
+	struct usb_hcd *hcd = bus_to_hcd(otg->host);
+	struct usb_device *rhub = otg->host->root_hub;
+
+	if (enable) {
+		pm_runtime_disable(&rhub->dev);
+		rhub->state = USB_STATE_NOTATTACHED;
+		hcd->driver->bus_suspend(hcd);
+		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+	} else {
+		usb_remove_hcd(hcd);
+		msm_otg_reset(otg);
+		usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
+	}
+}
+
 static int msm_otg_set_suspend(struct otg_transceiver *otg, int suspend)
 {
 	struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
 
-	/*
-	 * Allow bus suspend only for host mode.  Device mode bus suspend
-	 * is not implemented yet.
-	 */
-	if (!test_bit(ID, &motg->inputs) || test_bit(ID_A, &motg->inputs)) {
-		/*
-		 * ID_GND --> ID_A transition can not be detected in LPM.
-		 * Disallow host bus suspend when ACA is enabled.
-		 */
-		if (suspend && !aca_enabled())
-			pm_runtime_put(otg->dev);
-		else
-			pm_runtime_resume(otg->dev);
-	}
+	if (aca_enabled() || (test_bit(ID, &motg->inputs) &&
+				 !test_bit(ID_A, &motg->inputs)))
+		return 0;
 
+	if (suspend) {
+		switch (otg->state) {
+		case OTG_STATE_A_WAIT_BCON:
+			if (TA_WAIT_BCON > 0)
+				break;
+			/* fall through */
+		case OTG_STATE_A_HOST:
+			pr_debug("host bus suspend\n");
+			clear_bit(A_BUS_REQ, &motg->inputs);
+			queue_work(system_nrt_wq, &motg->sm_work);
+			break;
+		default:
+			break;
+		}
+	} else {
+		switch (otg->state) {
+		case OTG_STATE_A_SUSPEND:
+			/* Remote wakeup or resume */
+			set_bit(A_BUS_REQ, &motg->inputs);
+			otg->state = OTG_STATE_A_HOST;
+			break;
+		default:
+			break;
+		}
+	}
 	return 0;
 }
 
@@ -905,6 +1071,11 @@
 
 static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
 {
+	struct usb_gadget *g = motg->otg.gadget;
+
+	if (g && g->is_a_peripheral)
+		return;
+
 	if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
 		motg->chg_type == USB_ACA_A_CHARGER ||
 		motg->chg_type == USB_ACA_B_CHARGER ||
@@ -987,11 +1158,9 @@
 			unsigned long action, void *priv)
 {
 	struct msm_otg *motg = container_of(self, struct msm_otg, usbdev_nb);
+	struct otg_transceiver *otg = &motg->otg;
 	struct usb_device *udev = priv;
 
-	if (!aca_enabled())
-		goto out;
-
 	if (action == USB_BUS_ADD || action == USB_BUS_REMOVE)
 		goto out;
 
@@ -1008,17 +1177,47 @@
 
 	switch (action) {
 	case USB_DEVICE_ADD:
-		usb_disable_autosuspend(udev);
+		if (aca_enabled())
+			usb_disable_autosuspend(udev);
+		if (otg->state == OTG_STATE_A_WAIT_BCON) {
+			pr_debug("B_CONN set\n");
+			set_bit(B_CONN, &motg->inputs);
+			msm_otg_del_timer(motg);
+			otg->state = OTG_STATE_A_HOST;
+			/*
+			 * OTG PET: A-device must end session within
+			 * 10 sec after PET enumeration.
+			 */
+			if (udev->quirks & USB_QUIRK_OTG_PET)
+				msm_otg_start_timer(motg, TA_TST_MAINT,
+						A_TST_MAINT);
+		}
 		/* fall through */
 	case USB_DEVICE_CONFIG:
 		if (udev->actconfig)
 			motg->mA_port = udev->actconfig->desc.bMaxPower * 2;
 		else
 			motg->mA_port = IUNIT;
+		if (otg->state == OTG_STATE_B_HOST)
+			msm_otg_del_timer(motg);
 		break;
 	case USB_DEVICE_REMOVE:
-		motg->mA_port = IUNIT;
-		break;
+		if ((otg->state == OTG_STATE_A_HOST) ||
+			(otg->state == OTG_STATE_A_SUSPEND)) {
+			pr_debug("B_CONN clear\n");
+			clear_bit(B_CONN, &motg->inputs);
+			/*
+			 * OTG PET: A-device must end session after
+			 * PET disconnection if it is enumerated
+			 * with bcdDevice[0] = 1. USB core sets
+			 * bus->otg_vbus_off for us. clear it here.
+			 */
+			if (udev->bus->otg_vbus_off) {
+				udev->bus->otg_vbus_off = 0;
+				set_bit(A_BUS_DROP, &motg->inputs);
+			}
+			queue_work(system_nrt_wq, &motg->sm_work);
+		}
 	default:
 		break;
 	}
@@ -1101,7 +1300,7 @@
 			msm_hsusb_vbus_power(motg, 0);
 			otg->host = NULL;
 			otg->state = OTG_STATE_UNDEFINED;
-			schedule_work(&motg->sm_work);
+			queue_work(system_nrt_wq, &motg->sm_work);
 		} else {
 			otg->host = NULL;
 		}
@@ -1115,6 +1314,9 @@
 	hcd = bus_to_hcd(host);
 	hcd->power_budget = motg->pdata->power_budget;
 
+#ifdef CONFIG_USB_OTG
+	host->otg_port = 1;
+#endif
 	motg->usbdev_nb.notifier_call = msm_otg_usbdev_notify;
 	usb_register_notify(&motg->usbdev_nb);
 	otg->host = host;
@@ -1126,7 +1328,7 @@
 	 */
 	if (motg->pdata->mode == USB_HOST || otg->gadget) {
 		pm_runtime_get_sync(otg->dev);
-		schedule_work(&motg->sm_work);
+		queue_work(system_nrt_wq, &motg->sm_work);
 	}
 
 	return 0;
@@ -1202,7 +1404,7 @@
 			msm_otg_start_peripheral(otg, 0);
 			otg->gadget = NULL;
 			otg->state = OTG_STATE_UNDEFINED;
-			schedule_work(&motg->sm_work);
+			queue_work(system_nrt_wq, &motg->sm_work);
 		} else {
 			otg->gadget = NULL;
 		}
@@ -1218,7 +1420,7 @@
 	 */
 	if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
 		pm_runtime_get_sync(otg->dev);
-		schedule_work(&motg->sm_work);
+		queue_work(system_nrt_wq, &motg->sm_work);
 	}
 
 	return 0;
@@ -1380,6 +1582,7 @@
 static void msm_otg_id_timer_func(unsigned long data)
 {
 	struct msm_otg *motg = (struct msm_otg *) data;
+	struct otg_transceiver *otg = &motg->otg;
 
 	if (!aca_enabled())
 		return;
@@ -1389,11 +1592,15 @@
 		return;
 	}
 
+	if (otg->state == OTG_STATE_A_SUSPEND)
+		goto out;
+
 	if (msm_chg_check_aca_intr(motg)) {
 		dev_dbg(motg->otg.dev, "timer: aca work\n");
-		schedule_work(&motg->sm_work);
+		queue_work(system_nrt_wq, &motg->sm_work);
 	}
 
+out:
 	if (!test_bit(ID, &motg->inputs) || test_bit(ID_A, &motg->inputs))
 		mod_timer(&motg->id_timer, ID_TIMER_FREQ);
 }
@@ -1734,16 +1941,22 @@
 	case USB_CHG_STATE_DETECTED:
 		msm_chg_block_off(motg);
 		msm_chg_enable_aca_det(motg);
+		/*
+		 * Spurious interrupt is seen after enabling ACA detection
+		 * due to which charger detection fails in case of PET.
+		 * Add delay of 100 microsec to avoid that.
+		 */
+		udelay(100);
 		msm_chg_enable_aca_intr(motg);
 		dev_dbg(otg->dev, "chg_type = %s\n",
 			chg_to_string(motg->chg_type));
-		schedule_work(&motg->sm_work);
+		queue_work(system_nrt_wq, &motg->sm_work);
 		return;
 	default:
 		return;
 	}
 
-	schedule_delayed_work(&motg->chg_work, delay);
+	queue_delayed_work(system_nrt_wq, &motg->chg_work, delay);
 }
 
 /*
@@ -1771,10 +1984,12 @@
 				clear_bit(B_SESS_VLD, &motg->inputs);
 			}
 		} else if (pdata->otg_control == OTG_PHY_CONTROL) {
-			if (otgsc & OTGSC_ID)
+			if (otgsc & OTGSC_ID) {
 				set_bit(ID, &motg->inputs);
-			else
+			} else {
 				clear_bit(ID, &motg->inputs);
+				set_bit(A_BUS_REQ, &motg->inputs);
+			}
 			if (otgsc & OTGSC_BSV)
 				set_bit(B_SESS_VLD, &motg->inputs);
 			else
@@ -1820,11 +2035,12 @@
 {
 	struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
 	struct otg_transceiver *otg = &motg->otg;
+	bool work = 0, srp_reqd;
 
 	pm_runtime_resume(otg->dev);
+	pr_debug("%s work\n", otg_state_string(otg->state));
 	switch (otg->state) {
 	case OTG_STATE_UNDEFINED:
-		dev_dbg(otg->dev, "OTG_STATE_UNDEFINED state\n");
 		msm_otg_reset(otg);
 		msm_otg_init_sm(motg);
 		otg->state = OTG_STATE_B_IDLE;
@@ -1836,31 +2052,15 @@
 		}
 		/* FALL THROUGH */
 	case OTG_STATE_B_IDLE:
-		dev_dbg(otg->dev, "OTG_STATE_B_IDLE state\n");
 		if ((!test_bit(ID, &motg->inputs) ||
 				test_bit(ID_A, &motg->inputs)) && otg->host) {
-			if (motg->chg_type == USB_ACA_DOCK_CHARGER)
-				msm_otg_notify_charger(motg,
-						IDEV_ACA_CHG_MAX);
-			else if (test_bit(ID_A, &motg->inputs))
-				msm_otg_notify_charger(motg,
-						IDEV_ACA_CHG_MAX - IUNIT);
-			else
-				msm_hsusb_vbus_power(motg, 1);
-			msm_otg_start_host(otg, 1);
-			/*
-			 * Link can not generate PHY_ALT interrupt
-			 * in host mode when no device is attached
-			 * to the port.  It is also observed PHY_ALT
-			 * interrupt missing upon Micro-A cable disconnect.
-			 * Hence disable PHY_ALT interrupt and perform
-			 * polling to detect RID change.
-			 */
-			msm_chg_enable_aca_det(motg);
-			msm_chg_disable_aca_intr(motg);
-			mod_timer(&motg->id_timer, ID_TIMER_FREQ);
-			otg->state = OTG_STATE_A_HOST;
+			pr_debug("!id || id_A\n");
+			clear_bit(B_BUS_REQ, &motg->inputs);
+			set_bit(A_BUS_REQ, &motg->inputs);
+			otg->state = OTG_STATE_A_IDLE;
+			work = 1;
 		} else if (test_bit(B_SESS_VLD, &motg->inputs)) {
+			pr_debug("b_sess_vld\n");
 			switch (motg->chg_state) {
 			case USB_CHG_STATE_UNDEFINED:
 				msm_chg_detect_work(&motg->chg_work.work);
@@ -1906,7 +2106,18 @@
 			default:
 				break;
 			}
+		} else if (test_bit(B_BUS_REQ, &motg->inputs)) {
+			pr_debug("b_sess_end && b_bus_req\n");
+			if (msm_otg_start_srp(otg) < 0) {
+				clear_bit(B_BUS_REQ, &motg->inputs);
+				work = 1;
+				break;
+			}
+			otg->state = OTG_STATE_B_SRP_INIT;
+			msm_otg_start_timer(motg, TB_SRP_FAIL, B_SRP_FAIL);
+			break;
 		} else {
+			pr_debug("chg_work cancel");
 			cancel_delayed_work_sync(&motg->chg_work);
 			msm_otg_notify_charger(motg, 0);
 			motg->chg_state = USB_CHG_STATE_UNDEFINED;
@@ -1916,64 +2127,451 @@
 			pm_runtime_suspend(otg->dev);
 		}
 		break;
-	case OTG_STATE_B_PERIPHERAL:
-		dev_dbg(otg->dev, "OTG_STATE_B_PERIPHERAL state\n");
-		if (!test_bit(B_SESS_VLD, &motg->inputs) ||
-				!test_bit(ID, &motg->inputs) ||
-				!test_bit(ID_C, &motg->inputs)) {
-			msm_otg_start_peripheral(otg, 0);
+	case OTG_STATE_B_SRP_INIT:
+		if (!test_bit(ID, &motg->inputs) ||
+				test_bit(ID_A, &motg->inputs) ||
+				test_bit(ID_C, &motg->inputs) ||
+				(test_bit(B_SESS_VLD, &motg->inputs) &&
+				!test_bit(ID_B, &motg->inputs))) {
+			pr_debug("!id || id_a/c || b_sess_vld+!id_b\n");
+			msm_otg_del_timer(motg);
 			otg->state = OTG_STATE_B_IDLE;
-			schedule_work(w);
+			/*
+			 * clear VBUSVLDEXTSEL and VBUSVLDEXT register
+			 * bits after SRP initiation.
+			 */
+			ulpi_write(otg, 0x0, 0x98);
+			work = 1;
+		} else if (test_bit(B_SRP_FAIL, &motg->tmouts)) {
+			pr_debug("b_srp_fail\n");
+			pr_info("A-device did not respond to SRP\n");
+			clear_bit(B_BUS_REQ, &motg->inputs);
+			clear_bit(B_SRP_FAIL, &motg->tmouts);
+			otg_send_event(OTG_EVENT_NO_RESP_FOR_SRP);
+			ulpi_write(otg, 0x0, 0x98);
+			otg->state = OTG_STATE_B_IDLE;
+			motg->b_last_se0_sess = jiffies;
+			work = 1;
+		}
+		break;
+	case OTG_STATE_B_PERIPHERAL:
+		if (!test_bit(ID, &motg->inputs) ||
+				test_bit(ID_A, &motg->inputs) ||
+				test_bit(ID_B, &motg->inputs) ||
+				!test_bit(B_SESS_VLD, &motg->inputs)) {
+			pr_debug("!id  || id_a/b || !b_sess_vld\n");
+			msm_otg_notify_charger(motg, 0);
+			srp_reqd = otg->gadget->otg_srp_reqd;
+			msm_otg_start_peripheral(otg, 0);
+			motg->chg_state = USB_CHG_STATE_UNDEFINED;
+			motg->chg_type = USB_INVALID_CHARGER;
+			if (test_bit(ID_B, &motg->inputs))
+				clear_bit(ID_B, &motg->inputs);
+			clear_bit(B_BUS_REQ, &motg->inputs);
+			otg->state = OTG_STATE_B_IDLE;
+			motg->b_last_se0_sess = jiffies;
+			if (srp_reqd)
+				msm_otg_start_timer(motg,
+					TB_TST_SRP, B_TST_SRP);
+			else
+				work = 1;
+		} else if (test_bit(B_BUS_REQ, &motg->inputs) &&
+				otg->gadget->b_hnp_enable &&
+				test_bit(A_BUS_SUSPEND, &motg->inputs)) {
+			pr_debug("b_bus_req && b_hnp_en && a_bus_suspend\n");
+			msm_otg_start_timer(motg, TB_ASE0_BRST, B_ASE0_BRST);
+			/* D+ pullup should not be disconnected within 4msec
+			 * after A device suspends the bus. Otherwise PET will
+			 * fail the compliance test.
+			 */
+			udelay(1000);
+			msm_otg_start_peripheral(otg, 0);
+			otg->state = OTG_STATE_B_WAIT_ACON;
+			/*
+			 * start HCD even before A-device enable
+			 * pull-up to meet HNP timings.
+			 */
+			otg->host->is_b_host = 1;
+			msm_otg_start_host(otg, 1);
 		} else if (test_bit(ID_C, &motg->inputs)) {
 			msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
 		}
 		break;
-	case OTG_STATE_A_HOST:
-		dev_dbg(otg->dev, "OTG_STATE_A_HOST state\n");
-		if (test_bit(ID, &motg->inputs) &&
-				!test_bit(ID_A, &motg->inputs)) {
-			msm_otg_start_host(otg, 0);
-			msm_hsusb_vbus_power(motg, 0);
-			msleep(100); /* TA_WAIT_VFALL */
+	case OTG_STATE_B_WAIT_ACON:
+		if (!test_bit(ID, &motg->inputs) ||
+				test_bit(ID_A, &motg->inputs) ||
+				test_bit(ID_B, &motg->inputs) ||
+				!test_bit(B_SESS_VLD, &motg->inputs)) {
+			pr_debug("!id || id_a/b || !b_sess_vld\n");
+			msm_otg_del_timer(motg);
 			/*
-			 * Exit point of host mode.
-			 *
-			 * 1. Micro-A cable disconnect: Just schedule
-			 * the work. PHY is reset in B_IDLE and LPM
-			 * is allowed.
-			 * 2. ID_GND --> ID_B: No need to reset the PHY.
-			 * HCD core clears all PORTSC bits and initializes
-			 * the controller to host mode in remove_hcd.
-			 * Restore PORTSC transceiver select bits (ULPI)
-			 * and reset the controller to change MODE bits.
-			 * PHY_ALT interrupt can not occur in host mode.
+			 * A-device is physically disconnected during
+			 * HNP. Remove HCD.
 			 */
-			del_timer_sync(&motg->id_timer);
-			if (motg->chg_state != USB_CHG_STATE_UNDEFINED) {
-				msm_otg_link_reset(motg);
-				msm_chg_enable_aca_intr(motg);
-			}
+			msm_otg_start_host(otg, 0);
+			otg->host->is_b_host = 0;
+
+			clear_bit(B_BUS_REQ, &motg->inputs);
+			clear_bit(A_BUS_SUSPEND, &motg->inputs);
+			motg->b_last_se0_sess = jiffies;
 			otg->state = OTG_STATE_B_IDLE;
-			schedule_work(w);
+			msm_otg_reset(otg);
+			work = 1;
+		} else if (test_bit(A_CONN, &motg->inputs)) {
+			pr_debug("a_conn\n");
+			clear_bit(A_BUS_SUSPEND, &motg->inputs);
+			otg->state = OTG_STATE_B_HOST;
+			/*
+			 * PET disconnects D+ pullup after reset is generated
+			 * by B device in B_HOST role which is not detected by
+			 * B device. As workaorund , start timer of 300msec
+			 * and stop timer if A device is enumerated else clear
+			 * A_CONN.
+			 */
+			msm_otg_start_timer(motg, TB_TST_CONFIG,
+						B_TST_CONFIG);
+		} else if (test_bit(B_ASE0_BRST, &motg->tmouts)) {
+			pr_debug("b_ase0_brst_tmout\n");
+			pr_info("B HNP fail:No response from A device\n");
+			msm_otg_start_host(otg, 0);
+			msm_otg_reset(otg);
+			otg->host->is_b_host = 0;
+			clear_bit(B_ASE0_BRST, &motg->tmouts);
+			clear_bit(A_BUS_SUSPEND, &motg->inputs);
+			clear_bit(B_BUS_REQ, &motg->inputs);
+			otg_send_event(OTG_EVENT_HNP_FAILED);
+			otg->state = OTG_STATE_B_IDLE;
+			work = 1;
+		} else if (test_bit(ID_C, &motg->inputs)) {
+			msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
+		}
+		break;
+	case OTG_STATE_B_HOST:
+		if (!test_bit(B_BUS_REQ, &motg->inputs) ||
+				!test_bit(A_CONN, &motg->inputs) ||
+				!test_bit(B_SESS_VLD, &motg->inputs)) {
+			pr_debug("!b_bus_req || !a_conn || !b_sess_vld\n");
+			clear_bit(A_CONN, &motg->inputs);
+			clear_bit(B_BUS_REQ, &motg->inputs);
+			msm_otg_start_host(otg, 0);
+			otg->host->is_b_host = 0;
+			otg->state = OTG_STATE_B_IDLE;
+			msm_otg_reset(otg);
+			work = 1;
+		} else if (test_bit(ID_C, &motg->inputs)) {
+			msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
+		}
+		break;
+	case OTG_STATE_A_IDLE:
+		otg->default_a = 1;
+		if (test_bit(ID, &motg->inputs) &&
+			!test_bit(ID_A, &motg->inputs)) {
+			pr_debug("id && !id_a\n");
+			otg->default_a = 0;
+			clear_bit(A_BUS_DROP, &motg->inputs);
+			otg->state = OTG_STATE_B_IDLE;
+			del_timer_sync(&motg->id_timer);
+			msm_otg_link_reset(motg);
+			msm_chg_enable_aca_intr(motg);
+			msm_otg_notify_charger(motg, 0);
+			work = 1;
+		} else if (!test_bit(A_BUS_DROP, &motg->inputs) &&
+				(test_bit(A_SRP_DET, &motg->inputs) ||
+				 test_bit(A_BUS_REQ, &motg->inputs))) {
+			pr_debug("!a_bus_drop && (a_srp_det || a_bus_req)\n");
+
+			clear_bit(A_SRP_DET, &motg->inputs);
+			/* Disable SRP detection */
+			writel_relaxed((readl_relaxed(USB_OTGSC) &
+					~OTGSC_INTSTS_MASK) &
+					~OTGSC_DPIE, USB_OTGSC);
+
+			otg->state = OTG_STATE_A_WAIT_VRISE;
+			/* VBUS should not be supplied before end of SRP pulse
+			 * generated by PET, if not complaince test fail.
+			 */
+			usleep_range(10000, 12000);
+			/* ACA: ID_A: Stop charging untill enumeration */
+			if (test_bit(ID_A, &motg->inputs))
+				msm_otg_notify_charger(motg, 0);
+			else
+				msm_hsusb_vbus_power(motg, 1);
+			msm_otg_start_timer(motg, TA_WAIT_VRISE, A_WAIT_VRISE);
+		} else {
+			pr_debug("No session requested\n");
+			clear_bit(A_BUS_DROP, &motg->inputs);
+			if (test_bit(ID_A, &motg->inputs)) {
+					msm_otg_notify_charger(motg,
+							IDEV_ACA_CHG_MAX);
+			} else if (!test_bit(ID, &motg->inputs)) {
+				msm_otg_notify_charger(motg, 0);
+				/*
+				 * A-device is not providing power on VBUS.
+				 * Enable SRP detection.
+				 */
+				writel_relaxed(0x13, USB_USBMODE);
+				writel_relaxed((readl_relaxed(USB_OTGSC) &
+						~OTGSC_INTSTS_MASK) |
+						OTGSC_DPIE, USB_OTGSC);
+				mb();
+			}
+		}
+		break;
+	case OTG_STATE_A_WAIT_VRISE:
+		if ((test_bit(ID, &motg->inputs) &&
+				!test_bit(ID_A, &motg->inputs)) ||
+				test_bit(A_BUS_DROP, &motg->inputs) ||
+				test_bit(A_WAIT_VRISE, &motg->tmouts)) {
+			pr_debug("id || a_bus_drop || a_wait_vrise_tmout\n");
+			clear_bit(A_BUS_REQ, &motg->inputs);
+			msm_otg_del_timer(motg);
+			msm_hsusb_vbus_power(motg, 0);
+			otg->state = OTG_STATE_A_WAIT_VFALL;
+			msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
+		} else if (test_bit(A_VBUS_VLD, &motg->inputs)) {
+			pr_debug("a_vbus_vld\n");
+			otg->state = OTG_STATE_A_WAIT_BCON;
+			if (TA_WAIT_BCON > 0)
+				msm_otg_start_timer(motg, TA_WAIT_BCON,
+					A_WAIT_BCON);
+			msm_otg_start_host(otg, 1);
+			msm_chg_enable_aca_det(motg);
+			msm_chg_disable_aca_intr(motg);
+			mod_timer(&motg->id_timer, ID_TIMER_INITIAL_FREQ);
+			if (msm_chg_check_aca_intr(motg))
+				work = 1;
+		}
+		break;
+	case OTG_STATE_A_WAIT_BCON:
+		if ((test_bit(ID, &motg->inputs) &&
+				!test_bit(ID_A, &motg->inputs)) ||
+				test_bit(A_BUS_DROP, &motg->inputs) ||
+				test_bit(A_WAIT_BCON, &motg->tmouts)) {
+			pr_debug("(id && id_a/b/c) || a_bus_drop ||"
+					"a_wait_bcon_tmout\n");
+			if (test_bit(A_WAIT_BCON, &motg->tmouts)) {
+				pr_info("Device No Response\n");
+				otg_send_event(OTG_EVENT_DEV_CONN_TMOUT);
+			}
+			msm_otg_del_timer(motg);
+			clear_bit(A_BUS_REQ, &motg->inputs);
+			clear_bit(B_CONN, &motg->inputs);
+			msm_otg_start_host(otg, 0);
+			/*
+			 * ACA: ID_A with NO accessory, just the A plug is
+			 * attached to ACA: Use IDCHG_MAX for charging
+			 */
+			if (test_bit(ID_A, &motg->inputs))
+				msm_otg_notify_charger(motg, IDEV_CHG_MIN);
+			else
+				msm_hsusb_vbus_power(motg, 0);
+			otg->state = OTG_STATE_A_WAIT_VFALL;
+			msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
+		} else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
+			pr_debug("!a_vbus_vld\n");
+			clear_bit(B_CONN, &motg->inputs);
+			msm_otg_del_timer(motg);
+			msm_otg_start_host(otg, 0);
+			otg->state = OTG_STATE_A_VBUS_ERR;
+			msm_otg_reset(otg);
+		} else if (test_bit(ID_A, &motg->inputs)) {
+			msm_hsusb_vbus_power(motg, 0);
+		} else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
+			/*
+			 * If TA_WAIT_BCON is infinite, we don;t
+			 * turn off VBUS. Enter low power mode.
+			 */
+			if (TA_WAIT_BCON < 0)
+				pm_runtime_put_sync(otg->dev);
+		} else if (!test_bit(ID, &motg->inputs)) {
+			msm_hsusb_vbus_power(motg, 1);
+		}
+		break;
+	case OTG_STATE_A_HOST:
+		if ((test_bit(ID, &motg->inputs) &&
+				!test_bit(ID_A, &motg->inputs)) ||
+				test_bit(A_BUS_DROP, &motg->inputs)) {
+			pr_debug("id_a/b/c || a_bus_drop\n");
+			clear_bit(B_CONN, &motg->inputs);
+			clear_bit(A_BUS_REQ, &motg->inputs);
+			msm_otg_del_timer(motg);
+			otg->state = OTG_STATE_A_WAIT_VFALL;
+			msm_otg_start_host(otg, 0);
+			if (!test_bit(ID_A, &motg->inputs))
+				msm_hsusb_vbus_power(motg, 0);
+			msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
+		} else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
+			pr_debug("!a_vbus_vld\n");
+			clear_bit(B_CONN, &motg->inputs);
+			msm_otg_del_timer(motg);
+			otg->state = OTG_STATE_A_VBUS_ERR;
+			msm_otg_start_host(otg, 0);
+			msm_otg_reset(otg);
+		} else if (!test_bit(A_BUS_REQ, &motg->inputs)) {
+			/*
+			 * a_bus_req is de-asserted when root hub is
+			 * suspended or HNP is in progress.
+			 */
+			pr_debug("!a_bus_req\n");
+			msm_otg_del_timer(motg);
+			otg->state = OTG_STATE_A_SUSPEND;
+			if (otg->host->b_hnp_enable)
+				msm_otg_start_timer(motg, TA_AIDL_BDIS,
+						A_AIDL_BDIS);
+			else
+				pm_runtime_put_sync(otg->dev);
+		} else if (!test_bit(B_CONN, &motg->inputs)) {
+			pr_debug("!b_conn\n");
+			msm_otg_del_timer(motg);
+			otg->state = OTG_STATE_A_WAIT_BCON;
+			if (TA_WAIT_BCON > 0)
+				msm_otg_start_timer(motg, TA_WAIT_BCON,
+					A_WAIT_BCON);
+			if (msm_chg_check_aca_intr(motg))
+				work = 1;
+		} else if (test_bit(ID_A, &motg->inputs)) {
+			msm_otg_del_timer(motg);
+			msm_hsusb_vbus_power(motg, 0);
+			if (motg->chg_type == USB_ACA_DOCK_CHARGER)
+				msm_otg_notify_charger(motg,
+						IDEV_ACA_CHG_MAX);
+			else
+				msm_otg_notify_charger(motg,
+						IDEV_CHG_MIN - motg->mA_port);
+		} else if (!test_bit(ID, &motg->inputs)) {
+			motg->chg_state = USB_CHG_STATE_UNDEFINED;
+			motg->chg_type = USB_INVALID_CHARGER;
+			msm_otg_notify_charger(motg, 0);
+			msm_hsusb_vbus_power(motg, 1);
+		}
+		break;
+	case OTG_STATE_A_SUSPEND:
+		if ((test_bit(ID, &motg->inputs) &&
+				!test_bit(ID_A, &motg->inputs)) ||
+				test_bit(A_BUS_DROP, &motg->inputs) ||
+				test_bit(A_AIDL_BDIS, &motg->tmouts)) {
+			pr_debug("id_a/b/c || a_bus_drop ||"
+					"a_aidl_bdis_tmout\n");
+			msm_otg_del_timer(motg);
+			clear_bit(B_CONN, &motg->inputs);
+			otg->state = OTG_STATE_A_WAIT_VFALL;
+			msm_otg_start_host(otg, 0);
+			msm_otg_reset(otg);
+			if (!test_bit(ID_A, &motg->inputs))
+				msm_hsusb_vbus_power(motg, 0);
+			msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
+		} else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
+			pr_debug("!a_vbus_vld\n");
+			msm_otg_del_timer(motg);
+			clear_bit(B_CONN, &motg->inputs);
+			otg->state = OTG_STATE_A_VBUS_ERR;
+			msm_otg_start_host(otg, 0);
+			msm_otg_reset(otg);
+		} else if (!test_bit(B_CONN, &motg->inputs) &&
+				otg->host->b_hnp_enable) {
+			pr_debug("!b_conn && b_hnp_enable");
+			otg->state = OTG_STATE_A_PERIPHERAL;
+			msm_otg_host_hnp_enable(otg, 1);
+			otg->gadget->is_a_peripheral = 1;
+			msm_otg_start_peripheral(otg, 1);
+		} else if (!test_bit(B_CONN, &motg->inputs) &&
+				!otg->host->b_hnp_enable) {
+			pr_debug("!b_conn && !b_hnp_enable");
+			/*
+			 * bus request is dropped during suspend.
+			 * acquire again for next device.
+			 */
+			set_bit(A_BUS_REQ, &motg->inputs);
+			otg->state = OTG_STATE_A_WAIT_BCON;
+			if (TA_WAIT_BCON > 0)
+				msm_otg_start_timer(motg, TA_WAIT_BCON,
+					A_WAIT_BCON);
 		} else if (test_bit(ID_A, &motg->inputs)) {
 			msm_hsusb_vbus_power(motg, 0);
 			msm_otg_notify_charger(motg,
-					IDEV_ACA_CHG_MAX - motg->mA_port);
+					IDEV_CHG_MIN - motg->mA_port);
 		} else if (!test_bit(ID, &motg->inputs)) {
 			msm_otg_notify_charger(motg, 0);
 			msm_hsusb_vbus_power(motg, 1);
 		}
 		break;
+	case OTG_STATE_A_PERIPHERAL:
+		if ((test_bit(ID, &motg->inputs) &&
+				!test_bit(ID_A, &motg->inputs)) ||
+				test_bit(A_BUS_DROP, &motg->inputs)) {
+			pr_debug("id _f/b/c || a_bus_drop\n");
+			/* Clear BIDL_ADIS timer */
+			msm_otg_del_timer(motg);
+			otg->state = OTG_STATE_A_WAIT_VFALL;
+			msm_otg_start_peripheral(otg, 0);
+			otg->gadget->is_a_peripheral = 0;
+			msm_otg_start_host(otg, 0);
+			msm_otg_reset(otg);
+			if (!test_bit(ID_A, &motg->inputs))
+				msm_hsusb_vbus_power(motg, 0);
+			msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
+		} else if (!test_bit(A_VBUS_VLD, &motg->inputs)) {
+			pr_debug("!a_vbus_vld\n");
+			/* Clear BIDL_ADIS timer */
+			msm_otg_del_timer(motg);
+			otg->state = OTG_STATE_A_VBUS_ERR;
+			msm_otg_start_peripheral(otg, 0);
+			otg->gadget->is_a_peripheral = 0;
+			msm_otg_start_host(otg, 0);
+		} else if (test_bit(A_BIDL_ADIS, &motg->tmouts)) {
+			pr_debug("a_bidl_adis_tmout\n");
+			msm_otg_start_peripheral(otg, 0);
+			otg->gadget->is_a_peripheral = 0;
+			otg->state = OTG_STATE_A_WAIT_BCON;
+			set_bit(A_BUS_REQ, &motg->inputs);
+			msm_otg_host_hnp_enable(otg, 0);
+			if (TA_WAIT_BCON > 0)
+				msm_otg_start_timer(motg, TA_WAIT_BCON,
+					A_WAIT_BCON);
+		} else if (test_bit(ID_A, &motg->inputs)) {
+			msm_hsusb_vbus_power(motg, 0);
+			msm_otg_notify_charger(motg,
+					IDEV_CHG_MIN - motg->mA_port);
+		} else if (!test_bit(ID, &motg->inputs)) {
+			msm_otg_notify_charger(motg, 0);
+			msm_hsusb_vbus_power(motg, 1);
+		}
+		break;
+	case OTG_STATE_A_WAIT_VFALL:
+		if (test_bit(A_WAIT_VFALL, &motg->tmouts)) {
+			clear_bit(A_VBUS_VLD, &motg->inputs);
+			otg->state = OTG_STATE_A_IDLE;
+			work = 1;
+		}
+		break;
+	case OTG_STATE_A_VBUS_ERR:
+		if ((test_bit(ID, &motg->inputs) &&
+				!test_bit(ID_A, &motg->inputs)) ||
+				test_bit(A_BUS_DROP, &motg->inputs) ||
+				test_bit(A_CLR_ERR, &motg->inputs)) {
+			otg->state = OTG_STATE_A_WAIT_VFALL;
+			if (!test_bit(ID_A, &motg->inputs))
+				msm_hsusb_vbus_power(motg, 0);
+			msm_otg_start_timer(motg, TA_WAIT_VFALL, A_WAIT_VFALL);
+			motg->chg_state = USB_CHG_STATE_UNDEFINED;
+			motg->chg_type = USB_INVALID_CHARGER;
+			msm_otg_notify_charger(motg, 0);
+		}
+		break;
 	default:
 		break;
 	}
+	if (work)
+		queue_work(system_nrt_wq, &motg->sm_work);
 }
 
 static irqreturn_t msm_otg_irq(int irq, void *data)
 {
 	struct msm_otg *motg = data;
 	struct otg_transceiver *otg = &motg->otg;
-	u32 otgsc = 0, usbsts;
+	u32 otgsc = 0, usbsts, pc;
+	bool work = 0;
+	irqreturn_t ret = IRQ_HANDLED;
 
 	if (atomic_read(&motg->in_lpm)) {
 		pr_debug("OTG IRQ: in LPM\n");
@@ -1984,44 +2582,144 @@
 	}
 
 	usbsts = readl(USB_USBSTS);
-	if ((usbsts & PHY_ALT_INT)) {
-		dev_dbg(otg->dev, "PHY_ALT interrupt\n");
-		writel(PHY_ALT_INT, USB_USBSTS);
-		if (msm_chg_check_aca_intr(motg)) {
-			dev_dbg(otg->dev, "ACA work from IRQ\n");
-			schedule_work(&motg->sm_work);
-		}
-		return IRQ_HANDLED;
-	}
-
 	otgsc = readl(USB_OTGSC);
-	if (!(otgsc & (OTGSC_IDIS | OTGSC_BSVIS)))
+
+	if (!(otgsc & OTG_OTGSTS_MASK) && !(usbsts & OTG_USBSTS_MASK))
 		return IRQ_NONE;
 
 	if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
 		if (otgsc & OTGSC_ID) {
-			dev_dbg(otg->dev, "ID set\n");
+			pr_debug("Id set\n");
 			set_bit(ID, &motg->inputs);
 		} else {
-			dev_dbg(otg->dev, "ID clear\n");
+			pr_debug("Id clear\n");
+			/*
+			 * Assert a_bus_req to supply power on
+			 * VBUS when Micro/Mini-A cable is connected
+			 * with out user intervention.
+			 */
+			set_bit(A_BUS_REQ, &motg->inputs);
 			clear_bit(ID, &motg->inputs);
 			msm_chg_enable_aca_det(motg);
 		}
-		schedule_work(&motg->sm_work);
-	} else if ((otgsc & OTGSC_BSVIS) && (otgsc & OTGSC_BSVIE)) {
+		writel_relaxed(otgsc, USB_OTGSC);
+		work = 1;
+	} else if (otgsc & OTGSC_DPIS) {
+		pr_debug("DPIS detected\n");
+		writel_relaxed(otgsc, USB_OTGSC);
+		set_bit(A_SRP_DET, &motg->inputs);
+		set_bit(A_BUS_REQ, &motg->inputs);
+		work = 1;
+	} else if (otgsc & OTGSC_BSVIS) {
+		writel_relaxed(otgsc, USB_OTGSC);
+		/*
+		 * BSV interrupt comes when operating as an A-device
+		 * (VBUS on/off).
+		 * But, handle BSV when charger is removed from ACA in ID_A
+		 */
+		if ((otg->state >= OTG_STATE_A_IDLE) &&
+			!test_bit(ID_A, &motg->inputs))
+			return IRQ_HANDLED;
 		if (otgsc & OTGSC_BSV) {
-			dev_dbg(otg->dev, "BSV set\n");
+			pr_debug("BSV set\n");
 			set_bit(B_SESS_VLD, &motg->inputs);
 		} else {
-			dev_dbg(otg->dev, "BSV clear\n");
+			pr_debug("BSV clear\n");
 			clear_bit(B_SESS_VLD, &motg->inputs);
 			msm_chg_check_aca_intr(motg);
 		}
-		schedule_work(&motg->sm_work);
+		work = 1;
+	} else if (usbsts & STS_PCI) {
+		pc = readl_relaxed(USB_PORTSC);
+		pr_debug("portsc = %x\n", pc);
+		ret = IRQ_NONE;
+		/*
+		 * HCD Acks PCI interrupt. We use this to switch
+		 * between different OTG states.
+		 */
+		work = 1;
+		switch (otg->state) {
+		case OTG_STATE_A_SUSPEND:
+			if (otg->host->b_hnp_enable && (pc & PORTSC_CSC) &&
+					!(pc & PORTSC_CCS)) {
+				pr_debug("B_CONN clear\n");
+				clear_bit(B_CONN, &motg->inputs);
+				msm_otg_del_timer(motg);
+			}
+			break;
+		case OTG_STATE_A_PERIPHERAL:
+			/*
+			 * A-peripheral observed activity on bus.
+			 * clear A_BIDL_ADIS timer.
+			 */
+			msm_otg_del_timer(motg);
+			work = 0;
+			break;
+		case OTG_STATE_B_WAIT_ACON:
+			if ((pc & PORTSC_CSC) && (pc & PORTSC_CCS)) {
+				pr_debug("A_CONN set\n");
+				set_bit(A_CONN, &motg->inputs);
+				/* Clear ASE0_BRST timer */
+				msm_otg_del_timer(motg);
+			}
+			break;
+		case OTG_STATE_B_HOST:
+			if ((pc & PORTSC_CSC) && !(pc & PORTSC_CCS)) {
+				pr_debug("A_CONN clear\n");
+				clear_bit(A_CONN, &motg->inputs);
+				msm_otg_del_timer(motg);
+			}
+			break;
+		case OTG_STATE_A_WAIT_BCON:
+			if (TA_WAIT_BCON < 0)
+				set_bit(A_BUS_REQ, &motg->inputs);
+		default:
+			work = 0;
+			break;
+		}
+	} else if (usbsts & STS_URI) {
+		ret = IRQ_NONE;
+		switch (otg->state) {
+		case OTG_STATE_A_PERIPHERAL:
+			/*
+			 * A-peripheral observed activity on bus.
+			 * clear A_BIDL_ADIS timer.
+			 */
+			msm_otg_del_timer(motg);
+			work = 0;
+			break;
+		default:
+			work = 0;
+			break;
+		}
+	} else if (usbsts & STS_SLI) {
+		ret = IRQ_NONE;
+		work = 0;
+		switch (otg->state) {
+		case OTG_STATE_B_PERIPHERAL:
+			if (otg->gadget->b_hnp_enable) {
+				set_bit(A_BUS_SUSPEND, &motg->inputs);
+				set_bit(B_BUS_REQ, &motg->inputs);
+				work = 1;
+			}
+			break;
+		case OTG_STATE_A_PERIPHERAL:
+			msm_otg_start_timer(motg, TA_BIDL_ADIS,
+					A_BIDL_ADIS);
+			break;
+		default:
+			break;
+		}
+	} else if ((usbsts & PHY_ALT_INT)) {
+		writel_relaxed(PHY_ALT_INT, USB_USBSTS);
+		if (msm_chg_check_aca_intr(motg))
+			work = 1;
+		ret = IRQ_HANDLED;
 	}
+	if (work)
+		queue_work(system_nrt_wq, &motg->sm_work);
 
-	writel(otgsc, USB_OTGSC);
-	return IRQ_HANDLED;
+	return ret;
 }
 
 static void msm_otg_set_vbus_state(int online)
@@ -2044,7 +2742,7 @@
 		return;
 	}
 
-	schedule_work(&motg->sm_work);
+	queue_work(system_nrt_wq, &motg->sm_work);
 }
 
 static irqreturn_t msm_pmic_id_irq(int irq, void *data)
@@ -2060,10 +2758,11 @@
 	} else {
 		pr_debug("PMIC: ID clear\n");
 		clear_bit(ID, &motg->inputs);
+		set_bit(A_BUS_REQ, &motg->inputs);
 	}
 
 	if (motg->otg.state != OTG_STATE_UNDEFINED)
-		schedule_work(&motg->sm_work);
+		queue_work(system_nrt_wq, &motg->sm_work);
 
 	return IRQ_HANDLED;
 }
@@ -2159,7 +2858,7 @@
 	}
 
 	pm_runtime_resume(otg->dev);
-	schedule_work(&motg->sm_work);
+	queue_work(system_nrt_wq, &motg->sm_work);
 out:
 	return status;
 }
@@ -2622,6 +3321,7 @@
 	mb();
 
 	wake_lock_init(&motg->wlock, WAKE_LOCK_SUSPEND, "msm_otg");
+	msm_otg_init_timer(motg);
 	INIT_WORK(&motg->sm_work, msm_otg_sm_work);
 	INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
 	setup_timer(&motg->id_timer, msm_otg_id_timer_func,
@@ -2637,6 +3337,8 @@
 	otg->set_host = msm_otg_set_host;
 	otg->set_peripheral = msm_otg_set_peripheral;
 	otg->set_power = msm_otg_set_power;
+	otg->start_hnp = msm_otg_start_hnp;
+	otg->start_srp = msm_otg_start_srp;
 	otg->set_suspend = msm_otg_set_suspend;
 
 	otg->io_ops = &msm_otg_io_ops;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index e613f29..c3874fa 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.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
@@ -239,6 +239,7 @@
 	struct vcd_property_intra_refresh_mb_number  intra_refresh;
 	struct vcd_property_buffer_format  buf_format;
 	struct vcd_property_buffer_format  recon_buf_format;
+	struct vcd_property_sps_pps_for_idr_enable sps_pps;
 	struct ddl_buf_addr  seq_header;
 	struct vcd_buffer_requirement  input_buf_req;
 	struct vcd_buffer_requirement  output_buf_req;
@@ -260,7 +261,7 @@
 	u32  mb_info_enable;
 	u32  ext_enc_control_val;
 	u32  num_references_for_p_frame;
-	u32	 closed_gop;
+	u32  closed_gop;
 };
 struct ddl_decoder_data {
 	struct ddl_codec_data_hdr  hdr;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_errors.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_errors.c
index d658647..a2327d5 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_errors.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_errors.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
@@ -236,7 +236,6 @@
 	case VIDC_1080P_ERROR_PICTURE_STRUCTURE_ERR:
 	case VIDC_1080P_ERROR_SLICE_ADDR_INVALID:
 	case VIDC_1080P_ERROR_NON_FRAME_DATA_RECEIVED:
-	case VIDC_1080P_ERROR_INCOMPLETE_FRAME:
 	case VIDC_1080P_ERROR_NALU_HEADER_ERROR:
 	case VIDC_1080P_ERROR_SPS_PARSE_ERROR:
 	case VIDC_1080P_ERROR_PPS_PARSE_ERROR:
@@ -309,6 +308,8 @@
 	case VIDC_1080P_WARN_BIT_RATE_NOT_SUPPORTED:
 	case VIDC_1080P_WARN_COLOR_DIFF_FORMAT_NOT_SUPPORTED:
 	case VIDC_1080P_WARN_NULL_EXTRA_METADATA_POINTER:
+	case VIDC_1080P_WARN_DEBLOCKING_NOT_DONE:
+	case VIDC_1080P_WARN_INCOMPLETE_FRAME:
 	case VIDC_1080P_ERROR_NULL_FW_DEBUG_INFO_POINTER:
 	case VIDC_1080P_ERROR_ALLOC_DEBUG_INFO_SIZE_INSUFFICIENT:
 	case VIDC_1080P_WARN_METADATA_NO_SPACE_NUM_CONCEAL_MB:
@@ -322,6 +323,9 @@
 	case VIDC_1080P_WARN_METADATA_NO_SPACE_MB_INFO:
 	case VIDC_1080P_WARN_METADATA_NO_SPACE_SLICE_SIZE:
 	case VIDC_1080P_WARN_RESOLUTION_WARNING:
+	case VIDC_1080P_WARN_NO_LONG_TERM_REFERENCE:
+	case VIDC_1080P_WARN_NO_SPACE_MPEG2_DATA_DUMP:
+	case VIDC_1080P_WARN_METADATA_NO_SPACE_MISSING_MB:
 		status = true;
 		DDL_MSG_ERROR("VIDC_WARNING_IGNORED");
 	break;
@@ -626,6 +630,12 @@
 	case VIDC_1080P_WARN_NULL_EXTRA_METADATA_POINTER:
 		string = "VIDC_1080P_WARN_NULL_EXTRA_METADATA_POINTER";
 	break;
+	case VIDC_1080P_WARN_DEBLOCKING_NOT_DONE:
+		string = "VIDC_1080P_WARN_DEBLOCKING_NOT_DONE";
+	break;
+	case VIDC_1080P_WARN_INCOMPLETE_FRAME:
+		string = "VIDC_1080P_WARN_INCOMPLETE_FRAME";
+	break;
 	case VIDC_1080P_ERROR_NULL_FW_DEBUG_INFO_POINTER:
 		string = "VIDC_1080P_ERROR_NULL_FW_DEBUG_INFO_POINTER";
 	break;
@@ -666,6 +676,15 @@
 	case VIDC_1080P_WARN_RESOLUTION_WARNING:
 		string = "VIDC_1080P_WARN_RESOLUTION_WARNING";
 	break;
+	case VIDC_1080P_WARN_NO_LONG_TERM_REFERENCE:
+		string = "VIDC_1080P_WARN_NO_LONG_TERM_REFERENCE";
+	break;
+	case VIDC_1080P_WARN_NO_SPACE_MPEG2_DATA_DUMP:
+		string = "VIDC_1080P_WARN_NO_SPACE_MPEG2_DATA_DUMP";
+	break;
+	case VIDC_1080P_WARN_METADATA_NO_SPACE_MISSING_MB:
+		string = "VIDC_1080P_WARN_METADATA_NO_SPACE_MISSING_MB";
+	break;
 	}
 	if (string)
 		DDL_MSG_ERROR("Error code = 0x%x : %s", error_code, string);
@@ -733,9 +752,6 @@
 	case VIDC_1080P_ERROR_NON_FRAME_DATA_RECEIVED:
 		string = "VIDC_1080P_ERROR_NON_FRAME_DATA_RECEIVED";
 	break;
-	case VIDC_1080P_ERROR_INCOMPLETE_FRAME:
-		string = "VIDC_1080P_ERROR_INCOMPLETE_FRAME";
-	break;
 	case VIDC_1080P_ERROR_NALU_HEADER_ERROR:
 		string = "VIDC_1080P_ERROR_NALU_HEADER_ERROR";
 	break;
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 444db9f..40c5408 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -928,6 +928,21 @@
 	case VCD_I_META_BUFFER_MODE:
 		vcd_status = VCD_S_SUCCESS;
 		break;
+	case VCD_I_ENABLE_SPS_PPS_FOR_IDR:
+	{
+		struct vcd_property_sps_pps_for_idr_enable *sps_pps =
+		(struct vcd_property_sps_pps_for_idr_enable *) property_value;
+
+		if ((sizeof(struct vcd_property_sps_pps_for_idr_enable)) ==
+		property_hdr->sz) {
+			DDL_MSG_LOW("SPS PPS generation for IDR Encode "
+				"is Requested");
+			encoder->sps_pps.sps_pps_for_idr_enable_flag =
+			sps_pps->sps_pps_for_idr_enable_flag;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
 	default:
 		DDL_MSG_ERROR("INVALID ID %d\n", (int)property_hdr->prop_id);
 		vcd_status = VCD_ERR_ILLEGAL_OP;
@@ -1392,6 +1407,14 @@
 			property_value);
 		vcd_status = VCD_S_SUCCESS;
 	break;
+	case VCD_I_ENABLE_SPS_PPS_FOR_IDR:
+		if (sizeof(struct vcd_property_sps_pps_for_idr_enable) ==
+			property_hdr->sz) {
+			*(struct vcd_property_sps_pps_for_idr_enable *)
+				property_value = encoder->sps_pps;
+			vcd_status = VCD_S_SUCCESS;
+		}
+	break;
 	default:
 		vcd_status = VCD_ERR_ILLEGAL_OP;
 		break;
@@ -1959,5 +1982,6 @@
 		encoder->frame_rate.fps_numerator = DDL_INITIAL_FRAME_RATE;
 		encoder->frame_rate.fps_denominator = 1;
 		ddl_set_default_enc_property(ddl);
+		encoder->sps_pps.sps_pps_for_idr_enable_flag = false;
 	}
 }
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 561cb7c..c46a349 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
@@ -85,6 +85,8 @@
 #define VIDC_SM_ENC_EXT_CTRL_VBV_BUFFER_SIZE_SHFT    16
 #define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_BMSK  0x80
 #define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_SHFT  7
+#define VIDC_SM_ENC_EXT_CTRL_SPS_PPS_CONTROL_BMSK    0X100
+#define VIDC_SM_ENC_EXT_CTRL_SPS_PPS_CONTROL_SHFT    8
 #define VIDC_SM_ENC_EXT_CTRL_SEQ_HDR_CTRL_BMSK       0x8
 #define VIDC_SM_ENC_EXT_CTRL_SEQ_HDR_CTRL_SHFT       3
 #define VIDC_SM_ENC_EXT_CTRL_FRAME_SKIP_ENABLE_BMSK  0x6
@@ -213,6 +215,8 @@
 #define VIDC_SM_SEI_ENABLE_RECOVERY_POINT_SEI_BMSK  0x00000001
 #define VIDC_SM_SEI_ENABLE_RECOVERY_POINT_SEI_SHFT  0
 
+#define VIDC_SM_NUM_STUFF_BYTES_CONSUME_ADDR    0X01ac
+
 #define VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK	0x40
 #define VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_SHFT	6
 
@@ -361,7 +365,7 @@
 	*shared_mem, u32 hec_enable,
 	enum VIDC_SM_frame_skip frame_skip_mode,
 	u32 seq_hdr_in_band, u32 vbv_buffer_size, u32 cpcfc_enable,
-	u32 closed_gop_enable)
+	u32 sps_pps_control, u32 closed_gop_enable)
 {
 	u32 enc_ctrl;
 
@@ -380,6 +384,9 @@
 			VIDC_SETFIELD((cpcfc_enable) ? 1 : 0,
 			VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_SHFT,
 			VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_BMSK) |
+			VIDC_SETFIELD((sps_pps_control) ? 1 : 0,
+			VIDC_SM_ENC_EXT_CTRL_SPS_PPS_CONTROL_SHFT,
+			VIDC_SM_ENC_EXT_CTRL_SPS_PPS_CONTROL_BMSK) |
 			VIDC_SETFIELD(closed_gop_enable,
 			VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_SHFT,
 			VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK);
@@ -755,3 +762,11 @@
 	DDL_MEM_WRITE_32(shared_mem, VIDC_SM_ERROR_CONCEALMENT_CONFIG_ADDR,
 			error_conceal_config);
 }
+
+void vidc_sm_set_decoder_stuff_bytes_consumption(
+	struct ddl_buf_addr *shared_mem,
+	enum vidc_sm_num_stuff_bytes_consume_info consume_info)
+{
+	DDL_MEM_WRITE_32(shared_mem, VIDC_SM_NUM_STUFF_BYTES_CONSUME_ADDR,
+	consume_info);
+}
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 bc8b303..798a537 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
@@ -73,6 +73,11 @@
 	VIDC_SM_PROFILE_INFO_MAX      = 0x7fffffff
 };
 
+enum vidc_sm_num_stuff_bytes_consume_info {
+	VIDC_SM_NUM_STUFF_BYTES_CONSUME_ALL  = 0x0,
+	VIDC_SM_NUM_STUFF_BYTES_CONSUME_NONE = 0xffffffff
+};
+
 void vidc_sm_get_extended_decode_status(struct ddl_buf_addr *shared_mem,
 	u32 *more_field_needed,
 	u32 *resl_change);
@@ -100,7 +105,8 @@
 void vidc_sm_set_extended_encoder_control(
 	struct ddl_buf_addr *shared_mem, u32 hec_enable,
 	enum VIDC_SM_frame_skip  frame_skip_mode, u32 seq_hdr_in_band,
-	u32 vbv_buffer_size, u32 cpcfc_enable, u32 closed_gop_enable);
+	u32 vbv_buffer_size, u32 cpcfc_enable, u32 sps_pps_control,
+	u32 closed_gop_enable);
 void vidc_sm_set_encoder_param_change(struct ddl_buf_addr *shared_mem,
 	u32 bit_rate_chg, u32 frame_rate_chg, u32 i_period_chg);
 void vidc_sm_set_encoder_vop_time(struct ddl_buf_addr *shared_mem,
@@ -170,4 +176,7 @@
 	u32 *sei_enable);
 void vidc_sm_set_error_concealment_config(struct ddl_buf_addr *shared_mem,
 	u32 inter_slice, u32 intra_slice, u32 conceal_config_enable);
+void vidc_sm_set_decoder_stuff_bytes_consumption(
+	struct ddl_buf_addr *shared_mem,
+	enum vidc_sm_num_stuff_bytes_consume_info consume_info);
 #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 c406371..66e129c 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -263,6 +263,10 @@
 			VIDC_SM_RECOVERY_POINT_SEI);
 	ddl_context->vidc_decode_seq_start[ddl->command_channel](
 		&seq_start_param);
+
+	vidc_sm_set_decoder_stuff_bytes_consumption(
+		&ddl->shared_mem[ddl->command_channel],
+		VIDC_SM_NUM_STUFF_BYTES_CONSUME_NONE);
 }
 
 void ddl_vidc_decode_dynamic_property(struct ddl_client_context *ddl,
@@ -548,7 +552,8 @@
 	vidc_sm_set_extended_encoder_control(&ddl->shared_mem
 		[ddl->command_channel], hdr_ext_control,
 		r_cframe_skip, false, 0,
-		h263_cpfc_enable, encoder->closed_gop);
+		h263_cpfc_enable, encoder->sps_pps.sps_pps_for_idr_enable_flag,
+		encoder->closed_gop);
 	vidc_sm_set_encoder_init_rc_value(&ddl->shared_mem
 		[ddl->command_channel],
 		encoder->target_bit_rate.target_bitrate);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vidc.h b/drivers/video/msm/vidc/1080p/ddl/vidc.h
index 55db33c..7573ee8 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vidc.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vidc.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
@@ -94,7 +94,6 @@
 #define VIDC_1080P_ERROR_SLICE_ADDR_INVALID       121
 #define VIDC_1080P_ERROR_NON_PAIRED_FIELD_NOT_SUPPORTED         122
 #define VIDC_1080P_ERROR_NON_FRAME_DATA_RECEIVED                123
-#define VIDC_1080P_ERROR_INCOMPLETE_FRAME                       124
 #define VIDC_1080P_ERROR_NO_BUFFER_RELEASED_FROM_HOST           125
 #define VIDC_1080P_ERROR_NULL_FW_DEBUG_INFO_POINTER             126
 #define VIDC_1080P_ERROR_ALLOC_DEBUG_INFO_SIZE_INSUFFICIENT     127
@@ -126,10 +125,16 @@
 #define VIDC_1080P_WARN_BIT_RATE_NOT_SUPPORTED           168
 #define VIDC_1080P_WARN_COLOR_DIFF_FORMAT_NOT_SUPPORTED  169
 #define VIDC_1080P_WARN_NULL_EXTRA_METADATA_POINTER      170
+#define VIDC_1080P_WARN_DEBLOCKING_NOT_DONE              178
+#define VIDC_1080P_WARN_INCOMPLETE_FRAME                 179
 #define VIDC_1080P_WARN_METADATA_NO_SPACE_MB_INFO        180
 #define VIDC_1080P_WARN_METADATA_NO_SPACE_SLICE_SIZE     181
 #define VIDC_1080P_WARN_RESOLUTION_WARNING               182
 
+#define VIDC_1080P_WARN_NO_LONG_TERM_REFERENCE           183
+#define VIDC_1080P_WARN_NO_SPACE_MPEG2_DATA_DUMP         190
+#define VIDC_1080P_WARN_METADATA_NO_SPACE_MISSING_MB     191
+
 #define VIDC_1080P_H264_ENC_TYPE_P       0
 #define VIDC_1080P_H264_ENC_TYPE_B       1
 #define VIDC_1080P_H264_ENC_TYPE_IDR     2
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 70fe6ca..e7cc68e 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1242,6 +1242,18 @@
 	NL80211_ATTR_IE_PROBE_RESP,
 	NL80211_ATTR_IE_ASSOC_RESP,
 
+	NL80211_ATTR_STA_WME,
+	NL80211_ATTR_SUPPORT_AP_UAPSD,
+
+	NL80211_ATTR_ROAM_SUPPORT,
+
+	NL80211_ATTR_SCHED_SCAN_MATCH,
+	NL80211_ATTR_MAX_MATCH_SETS,
+
+	NL80211_ATTR_PMKSA_CANDIDATE,
+
+	NL80211_ATTR_TX_NO_CCK_RATE,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
diff --git a/include/linux/of_spmi.h b/include/linux/of_spmi.h
index d07ce63..fe09dec 100644
--- a/include/linux/of_spmi.h
+++ b/include/linux/of_spmi.h
@@ -14,6 +14,17 @@
 #include <linux/of_irq.h>
 
 #ifdef CONFIG_OF_SPMI
+/**
+ * of_spmi_register_devices() - Register devices in the SPMI Device Tree
+ * @ctrl: spmi_controller which devices should be registered to.
+ *
+ * This routine scans the SPMI Device Tree, allocating resources and
+ * creating spmi_devices according to the SPMI bus Device Tree
+ * hierarchy. Details of this hierarchy can be found in
+ * Documentation/devicetree/bindings/spmi. This routine is normally
+ * called from the probe routine of the driver registering as a
+ * spmi_controller.
+ */
 int of_spmi_register_devices(struct spmi_controller *ctrl);
 #else
 static int of_spmi_register_devices(struct spmi_controller *ctrl)
diff --git a/include/linux/qpnp/gpio.h b/include/linux/qpnp/gpio.h
new file mode 100644
index 0000000..0447a08
--- /dev/null
+++ b/include/linux/qpnp/gpio.h
@@ -0,0 +1,114 @@
+/* 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/qpnp.h>
+
+#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_OUT_BUF_OPEN_DRAIN		1
+#define QPNP_GPIO_OUT_BUF_CMOS			0
+
+#define QPNP_GPIO_VIN0				0
+#define QPNP_GPIO_VIN1				1
+#define QPNP_GPIO_VIN2				2
+#define QPNP_GPIO_VIN3				3
+#define QPNP_GPIO_VIN4				4
+#define QPNP_GPIO_VIN5				5
+#define QPNP_GPIO_VIN6				6
+#define QPNP_GPIO_VIN7				7
+
+#define QPNP_GPIO_PULL_UP_30			0
+#define QPNP_GPIO_PULL_UP_1P5			1
+#define QPNP_GPIO_PULL_UP_31P5			2
+#define QPNP_GPIO_PULL_UP_1P5_30		3
+#define QPNP_GPIO_PULL_DN			4
+#define QPNP_GPIO_PULL_NO			5
+
+#define QPNP_GPIO_OUT_STRENGTH_LOW		1
+#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
+
+/**
+ * struct qpnp_gpio_cfg - structure to specify gpio configurtion values
+ * @direction:		indicates whether the gpio should be input, output, or
+ *			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
+ * @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. This value
+ *			should be one of the QPNP_GPIO_PULL_*
+ * @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.
+ * @out_strength:	the amount of current supplied for an output gpio,
+ *			should be of the type QPNP_GPIO_STRENGTH_*
+ * @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_*
+ * @inv_int_pol:	Invert polarity before feeding the line to the interrupt
+ *			module in pmic. This feature will almost be never used
+ *			since the pm8xxx interrupt block can detect both edges
+ *			and both levels.
+ * @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.
+ */
+struct qpnp_gpio_cfg {
+	int		direction;
+	int		output_type;
+	int		output_value;
+	int		pull;
+	int		vin_sel;
+	int		out_strength;
+	int		src_select;
+	int		inv_int_pol;
+	int		master_en;
+};
+
+/**
+ * qpnp_gpio_config - Apply gpio configuration for Linux gpio
+ * @gpio: Linux gpio number to configure.
+ * @param: parameters to configure.
+ *
+ * This routine takes a Linux gpio number that corresponds with a
+ * PMIC gpio and applies the configuration specified in 'param'.
+ * This gpio number can be ascertained by of_get_gpio_flags() or
+ * the qpnp_gpio_map_gpio() API.
+ */
+int qpnp_gpio_config(int gpio, struct qpnp_gpio_cfg *param);
+
+/**
+ * qpnp_gpio_map_gpio - Obtain Linux GPIO number from device spec
+ * @slave_id: slave_id of the spmi_device for the gpio in question.
+ * @pmic_gpio: PMIC gpio number to lookup.
+ *
+ * This routine is used in legacy configurations that do not support
+ * Device Tree. If you are using Device Tree, you should not use this.
+ * For such cases, use of_get_gpio() instead.
+ */
+int qpnp_gpio_map_gpio(uint16_t slave_id, uint32_t pmic_gpio);
diff --git a/include/linux/regulator/stub-regulator.h b/include/linux/regulator/stub-regulator.h
new file mode 100644
index 0000000..1119c51
--- /dev/null
+++ b/include/linux/regulator/stub-regulator.h
@@ -0,0 +1,33 @@
+/* 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 __STUB_REGULATOR_H__
+#define __STUB_REGULATOR_H__
+
+#include <linux/regulator/machine.h>
+
+#define STUB_REGULATOR_DRIVER_NAME "stub-regulator"
+
+/**
+ * struct stub_regulator_pdata - stub regulator device data
+ * @init_data:		regulator constraints
+ * @hpm_min_load:	minimum load in uA that will result in the regulator
+ *			being set to high power mode
+ * @system_uA:		current drawn from regulator not accounted for by any
+ *			regulator framework consumer
+ */
+struct stub_regulator_pdata {
+	struct regulator_init_data	init_data;
+	int				hpm_min_load;
+	int				system_uA;
+};
+#endif
diff --git a/include/linux/spmi.h b/include/linux/spmi.h
index ffcb24e..927978a 100644
--- a/include/linux/spmi.h
+++ b/include/linux/spmi.h
@@ -88,24 +88,36 @@
 #define to_spmi_driver(d) container_of(d, struct spmi_driver, driver)
 
 /**
+ * struct spmi_resource: spmi_resource for one device_node
+ * @num_resources: number of resources for this device node
+ * @resources: array of resources for this device_node
+ * @of_node: device_node of the resource in question
+ */
+struct spmi_resource {
+	struct resource		*resource;
+	u32			num_resources;
+	struct device_node	*of_node;
+};
+
+/**
  * Client/device handle (struct spmi_device):
  * ------------------------------------------
- * This is the client/device handle returned when a SPMI device
- * is registered with a controller.
- * Pointer to this structure is used by client-driver as a handle.
- * @dev: driver model representation of the device.
- * @name: name of driver to use with this device.
- * @ctrl: SPMI controller managing the bus hosting this device.
- * @resource: array of resources for this device_node
- * @num_resources: number of resources for this device node
- * @sid: slave identifier.
+ *  This is the client/device handle returned when a SPMI device
+ *  is registered with a controller.
+ *  Pointer to this structure is used by client-driver as a handle.
+ *  @dev: Driver model representation of the device.
+ *  @name: Name of driver to use with this device.
+ *  @ctrl: SPMI controller managing the bus hosting this device.
+ *  @dev_node: array of SPMI resources - one entry per device_node.
+ *  @num_dev_node: number of device_node structures.
+ *  @sid: Slave Identifier.
  */
 struct spmi_device {
 	struct device		dev;
 	const char		*name;
 	struct spmi_controller	*ctrl;
-	struct resource		*resource;
-	u32			num_resources;
+	struct spmi_resource	*dev_node;
+	u32			num_dev_node;
 	u8			sid;
 };
 #define to_spmi_device(d) container_of(d, struct spmi_device, dev)
@@ -115,16 +127,16 @@
  * @slave_id: slave identifier.
  * @spmi_device: device to be registered with the SPMI framework.
  * @of_node: pointer to the OpenFirmware device node.
- * @num_resources: number of resources for this device node
- * @resource: array of resources for this device_node
+ * @dev_node: one spmi_resource for each device_node.
+ * @num_dev_node: number of device_node structures.
  * @platform_data: goes to spmi_device.dev.platform_data
  */
 struct spmi_boardinfo {
 	char			name[SPMI_NAME_SIZE];
 	uint8_t			slave_id;
 	struct device_node	*of_node;
-	u32			num_resources;
-	struct resource		*resource;
+	struct spmi_resource	*dev_node;
+	u32			num_dev_node;
 	const void		*platform_data;
 };
 
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index f2ad7e1..5845cb6 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -183,6 +183,46 @@
 	struct msm_bus_scale_pdata *bus_scale_table;
 };
 
+/* Timeout (in msec) values (min - max) associated with OTG timers */
+
+#define TA_WAIT_VRISE	100	/* ( - 100)  */
+#define TA_WAIT_VFALL	500	/* ( - 1000) */
+
+/*
+ * This option is set for embedded hosts or OTG devices in which leakage
+ * currents are very minimal.
+ */
+#ifdef CONFIG_USB_OTG
+#define TA_WAIT_BCON	30000	/* (1100 - 30000) */
+#else
+#define TA_WAIT_BCON	-1
+#endif
+
+#define TA_AIDL_BDIS	500	/* (200 - ) */
+#define TA_BIDL_ADIS	155	/* (155 - 200) */
+#define TB_SRP_FAIL	6000	/* (5000 - 6000) */
+#define TB_ASE0_BRST	200	/* (155 - ) */
+
+/* TB_SSEND_SRP and TB_SE0_SRP are combined */
+#define TB_SRP_INIT	2000	/* (1500 - ) */
+
+#define TA_TST_MAINT	10100	/* (9900 - 10100) */
+#define TB_TST_SRP	3000	/* ( - 5000) */
+#define TB_TST_CONFIG	300
+
+/* Timeout variables */
+
+#define A_WAIT_VRISE	0
+#define A_WAIT_VFALL	1
+#define A_WAIT_BCON	2
+#define A_AIDL_BDIS	3
+#define A_BIDL_ADIS	4
+#define B_SRP_FAIL	5
+#define B_ASE0_BRST	6
+#define A_TST_MAINT	7
+#define B_TST_SRP	8
+#define B_TST_CONFIG	9
+
 /**
  * struct msm_otg: OTG driver data. Shared by HCD and DCD.
  * @otg: USB OTG Transceiver structure.
@@ -229,6 +269,18 @@
 #define ID_A		2
 #define ID_B		3
 #define ID_C		4
+#define A_BUS_DROP	5
+#define A_BUS_REQ	6
+#define A_SRP_DET	7
+#define A_VBUS_VLD	8
+#define B_CONN		9
+#define ADP_CHANGE	10
+#define POWER_UP	11
+#define A_CLR_ERR	12
+#define A_BUS_RESUME	13
+#define A_BUS_SUSPEND	14
+#define A_CONN		15
+#define B_BUS_REQ	16
 	unsigned long inputs;
 	struct work_struct sm_work;
 	atomic_t in_lpm;
@@ -269,6 +321,10 @@
 #define PHY_OTG_COMP_DISABLED		BIT(2)
 	struct pm_qos_request_list pm_qos_req_dma;
 	int reset_counter;
+	unsigned long b_last_se0_sess;
+	unsigned long tmouts;
+	u8 active_tmout;
+	struct hrtimer timer;
 };
 
 struct msm_hsic_host_platform_data {
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index fcd91da..8a05136 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -33,6 +33,8 @@
 #define PORTSC_PHCD            (1 << 23) /* phy suspend mode */
 #define PORTSC_PTS_MASK         (3 << 30)
 #define PORTSC_PTS_ULPI         (3 << 30)
+#define PORTSC_CSC              (1 << 1)
+#define PORTSC_CCS              (1 << 0)
 
 #define USB_ULPI_VIEWPORT    (MSM_USB_BASE + 0x0170)
 #define ULPI_RUN              (1 << 30)
@@ -54,14 +56,26 @@
 #define PHY_IDHV_INTEN          (1 << 8) /* PHY ID HV interrupt */
 #define PHY_OTGSESSVLDHV_INTEN  (1 << 9) /* PHY Session Valid HV int. */
 
+#define STS_PCI                 (1 << 2) /* R/WC - Port Change Detect */
+#define STS_URI                 (1 << 6) /* R/WC - RESET recv'd */
+#define STS_SLI                 (1 << 8) /* R/WC - suspend state entered */
+
 /* OTG definitions */
 #define OTGSC_INTSTS_MASK	(0x7f << 16)
 #define OTGSC_IDPU		(1 << 5)
+#define OTGSC_INTR_MASK		(0x7f << 24)
+#define OTGSC_HADP		(1 << 6)
 #define OTGSC_ID		(1 << 8)
 #define OTGSC_BSV		(1 << 11)
 #define OTGSC_IDIS		(1 << 16)
 #define OTGSC_BSVIS		(1 << 19)
 #define OTGSC_IDIE		(1 << 24)
 #define OTGSC_BSVIE		(1 << 27)
+#define OTGSC_DPIE		(1 << 30)
+#define OTGSC_DPIS		(1 << 22)
+
+/* OTG interrupt status mask */
+#define OTG_USBSTS_MASK		(STS_PCI | STS_URI | STS_SLI | PHY_ALT_INT)
+#define OTG_OTGSTS_MASK		(OTGSC_IDIS | OTGSC_BSVIS | OTGSC_DPIS)
 
 #endif /* __LINUX_USB_GADGET_MSM72K_UDC_H__ */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index ebd2b75..fa3ddf8 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1344,6 +1344,7 @@
 enum v4l2_mpeg_video_header_mode {
 	V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE			= 0,
 	V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME	= 1,
+	V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME		= 2,
 
 };
 #define V4L2_CID_MPEG_VIDEO_MAX_REF_PIC			(V4L2_CID_MPEG_BASE+217)
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index 0279216..0b501ea 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -50,6 +50,7 @@
 #define VCD_I_META_BUFFER_MODE (VCD_START_BASE + 0x22)
 #define VCD_I_DISABLE_DMX (VCD_START_BASE + 0x23)
 #define VCD_I_DISABLE_DMX_SUPPORT (VCD_START_BASE + 0x24)
+#define VCD_I_ENABLE_SPS_PPS_FOR_IDR (VCD_START_BASE + 0x25)
 
 #define VCD_START_REQ      (VCD_START_BASE + 0x1000)
 #define VCD_I_REQ_IFRAME   (VCD_START_REQ + 0x1)
@@ -347,4 +348,8 @@
 	int alignment;
 };
 
+struct vcd_property_sps_pps_for_idr_enable {
+	u32 sps_pps_for_idr_enable_flag;
+};
+
 #endif
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 6a7f99b..cf7157c 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -1190,7 +1190,6 @@
 	uint32_t s_mount_angle[MSM_MAX_CAMERA_SENSORS];
 	const char *video_dev_name[MSM_MAX_CAMERA_SENSORS];
 	enum sensor_type_t sensor_type[MSM_MAX_CAMERA_SENSORS];
-
 };
 
 struct msm_cam_config_dev_info {
@@ -1225,6 +1224,13 @@
 	uint8_t flash_enabled;
 	int8_t total_steps;
 	uint8_t support_3d;
+	enum flash_type flashtype;
+	enum sensor_type_t sensor_type;
+	uint32_t pxlcode; /* enum v4l2_mbus_pixelcode */
+	uint32_t camera_type; /* msm_camera_type */
+	int mount_angle;
+	uint32_t max_width;
+	uint32_t max_height;
 };
 
 #define V4L2_SINGLE_PLANE	0
@@ -1252,4 +1258,8 @@
 	uint8_t vpe_can_use;
 };
 
+#define QCAMERA_NAME "qcamera"
+#define QCAMERA_DEVICE_GROUP_ID 1
+#define QCAMERA_VNODE_GROUP_ID 2
+
 #endif /* __LINUX_MSM_CAMERA_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 8be88bb..4898ea2 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -847,9 +847,11 @@
  * @n_channels: total number of channels to scan
  * @ie: optional information element(s) to add into Probe Request or %NULL
  * @ie_len: length of ie in octets
+ * @rates: bitmap of rates to advertise for each band
  * @wiphy: the wiphy this was for
  * @dev: the interface
  * @aborted: (internal) scan request was notified as aborted
+ * @no_cck: used to send probe requests at non CCK rate in 2GHz band
  */
 struct cfg80211_scan_request {
 	struct cfg80211_ssid *ssids;
@@ -858,10 +860,13 @@
 	const u8 *ie;
 	size_t ie_len;
 
+	u32 rates[IEEE80211_NUM_BANDS];
+
 	/* internal */
 	struct wiphy *wiphy;
 	struct net_device *dev;
 	bool aborted;
+	bool no_cck;
 
 	/* keep last */
 	struct ieee80211_channel *channels[0];
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 17a80bf..78f12b3 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -447,6 +447,9 @@
 		      enum nl80211_channel_type channel_type);
 
 u16 cfg80211_calculate_bitrate(struct rate_info *rate);
+int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
+			   const u8 *rates, unsigned int n_rates,
+			   u32 *mask);
 
 int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
 				 u32 beacon_int);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1a84262..c92906c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -183,10 +183,12 @@
 	[NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 },
 	[NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
 	[NL80211_ATTR_HIDDEN_SSID] = { .type = NLA_U32 },
+	[NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED },
 	[NL80211_ATTR_IE_PROBE_RESP] = { .type = NLA_BINARY,
 					 .len = IEEE80211_MAX_DATA_LEN },
 	[NL80211_ATTR_IE_ASSOC_RESP] = { .type = NLA_BINARY,
 					 .len = IEEE80211_MAX_DATA_LEN },
+	[NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG },
 };
 
 /* policy for the key attributes */
@@ -3378,7 +3380,6 @@
 	struct nlattr *attr;
 	struct wiphy *wiphy;
 	int err, tmp, n_ssids = 0, n_channels, i;
-	enum ieee80211_band band;
 	size_t ie_len;
 
 	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
@@ -3398,6 +3399,7 @@
 		if (!n_channels)
 			return -EINVAL;
 	} else {
+		enum ieee80211_band band;
 		n_channels = 0;
 
 		for (band = 0; band < IEEE80211_NUM_BANDS; band++)
@@ -3458,6 +3460,8 @@
 			i++;
 		}
 	} else {
+		enum ieee80211_band band;
+
 		/* all channels */
 		for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
 			int j;
@@ -3503,9 +3507,30 @@
 		       nla_data(info->attrs[NL80211_ATTR_IE]),
 		       request->ie_len);
 	}
+	for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+		request->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;
+	if (info->attrs[NL80211_ATTR_SCAN_SUPP_RATES]) {
+		nla_for_each_nested(attr,
+				    info->attrs[NL80211_ATTR_SCAN_SUPP_RATES],
+				    tmp) {
+			enum ieee80211_band band = nla_type(attr);
+			if (band < 0 || band >= IEEE80211_NUM_BANDS) {
+				err = -EINVAL;
+				goto out_free;
+			}
+			err = ieee80211_get_ratemask(wiphy->bands[band],
+						     nla_data(attr),
+						     nla_len(attr),
+						     &request->rates[band]);
+			if (err)
+				goto out_free;
+		}
+	}
 
 	request->dev = dev;
 	request->wiphy = &rdev->wiphy;
+	request->no_cck =
+		nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
 
 	rdev->scan_req = request;
 	err = rdev->ops->scan(&rdev->wiphy, dev, request);
@@ -4360,25 +4385,11 @@
 			nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
 		struct ieee80211_supported_band *sband =
 			wiphy->bands[ibss.channel->band];
-		int i, j;
-
-		if (n_rates == 0)
-			return -EINVAL;
-
-		for (i = 0; i < n_rates; i++) {
-			int rate = (rates[i] & 0x7f) * 5;
-			bool found = false;
-
-			for (j = 0; j < sband->n_bitrates; j++) {
-				if (sband->bitrates[j].bitrate == rate) {
-					found = true;
-					ibss.basic_rates |= BIT(j);
-					break;
-				}
-			}
-			if (!found)
-				return -EINVAL;
-		}
+		int err;
+		err = ieee80211_get_ratemask(sband, rates, n_rates,
+					     &ibss.basic_rates);
+		if (err)
+			return err;
 	}
 
 	if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index cbbc927..0aa09bd 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -862,6 +862,8 @@
 		if (wreq->scan_type == IW_SCAN_TYPE_PASSIVE)
 			creq->n_ssids = 0;
 	}
+	for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+		creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;
 
 	rdev->scan_req = creq;
 	err = rdev->ops->scan(wiphy, dev, creq);
diff --git a/net/wireless/util.c b/net/wireless/util.c
index c69e653..c87358b 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1014,3 +1014,32 @@
 
 	return -EBUSY;
 }
+
+int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
+			   const u8 *rates, unsigned int n_rates,
+			   u32 *mask)
+{
+	int i, j;
+	if (n_rates == 0 || n_rates > NL80211_MAX_SUPP_RATES)
+		return -EINVAL;
+	*mask = 0;
+	for (i = 0; i < n_rates; i++) {
+		int rate = (rates[i] & 0x7f) * 5;
+		bool found = false;
+		for (j = 0; j < sband->n_bitrates; j++) {
+			if (sband->bitrates[j].bitrate == rate) {
+				found = true;
+				*mask |= BIT(j);
+				break;
+			}
+		}
+		if (!found)
+			return -EINVAL;
+	}
+	/*
+	 * mask must have at least one bit set here since we
+	 * didn't accept a 0-length rates array nor allowed
+	 * entries in the array that didn't exist
+	 */
+	return 0;
+}
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 4396b07..46a49e7 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2848,8 +2848,11 @@
 # unbounded string functions are overflow risks
 		my %str_fns = (
 			"sprintf" => "snprintf",
-			"strcpy"  => "strncpy",
-			"strcat"  => "strncat",
+			"strcpy"  => "strlcpy",
+			"strncpy"  => "strlcpy",
+			"strcat"  => "strlcat",
+			"strncat"  => "strlcat",
+			"vsprintf"  => "vsnprintf",
 			"strcmp"  => "strncmp",
 			"strcasecmp" => "strncasecmp",
 			"strchr" => "strnchr",
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index d79af8c..828aaca 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -72,6 +72,7 @@
 static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
 static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
 static struct snd_soc_dai_driver tabla_dai[];
+static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
 
 enum tabla_bandgap_type {
 	TABLA_BANDGAP_OFF = 0,
@@ -236,6 +237,11 @@
 	/*compander*/
 	int comp_enabled[COMPANDER_MAX];
 	u32 comp_fs[COMPANDER_MAX];
+
+	/* Maintain the status of AUX PGA */
+	int aux_pga_cnt;
+	u8 aux_l_gain;
+	u8 aux_r_gain;
 };
 
 #ifdef CONFIG_DEBUG_FS
@@ -863,6 +869,11 @@
 	SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
 	SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
 
+	SOC_SINGLE_TLV("AUX_PGA_LEFT Volume", TABLA_A_AUX_L_GAIN, 0, 39, 0,
+		aux_pga_gain),
+	SOC_SINGLE_TLV("AUX_PGA_RIGHT Volume", TABLA_A_AUX_R_GAIN, 0, 39, 0,
+		aux_pga_gain),
+
 	SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
 	SOC_SINGLE("MICBIAS2 CAPLESS Switch", TABLA_A_MICB_2_CTL, 4, 1, 1),
 	SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
@@ -1278,6 +1289,94 @@
 	SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
 };
 
+static const struct snd_kcontrol_new hphl_pa_mix[] = {
+	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
+					7, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
+					7, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
+					TABLA_A_AUX_L_PA_CONN_INV, 7, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
+					TABLA_A_AUX_R_PA_CONN_INV, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new hphr_pa_mix[] = {
+	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
+					6, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
+					6, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
+					TABLA_A_AUX_L_PA_CONN_INV, 6, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
+					TABLA_A_AUX_R_PA_CONN_INV, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lineout1_pa_mix[] = {
+	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
+					5, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
+					5, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
+					TABLA_A_AUX_L_PA_CONN_INV, 5, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
+					TABLA_A_AUX_R_PA_CONN_INV, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new lineout2_pa_mix[] = {
+	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
+					4, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
+					4, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
+					TABLA_A_AUX_L_PA_CONN_INV, 4, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
+					TABLA_A_AUX_R_PA_CONN_INV, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new lineout3_pa_mix[] = {
+	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
+					3, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
+					3, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
+					TABLA_A_AUX_L_PA_CONN_INV, 3, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
+					TABLA_A_AUX_R_PA_CONN_INV, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new lineout4_pa_mix[] = {
+	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
+					2, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
+					2, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
+					TABLA_A_AUX_L_PA_CONN_INV, 2, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
+					TABLA_A_AUX_R_PA_CONN_INV, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new lineout5_pa_mix[] = {
+	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
+					1, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
+					1, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
+					TABLA_A_AUX_L_PA_CONN_INV, 1, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
+					TABLA_A_AUX_R_PA_CONN_INV, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new ear_pa_mix[] = {
+	SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
+					0, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
+					0, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
+					TABLA_A_AUX_L_PA_CONN_INV, 0, 1, 0),
+	SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
+					TABLA_A_AUX_R_PA_CONN_INV, 0, 1, 0),
+};
+
 static const struct snd_kcontrol_new lineout3_ground_switch =
 	SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
 
@@ -1357,6 +1456,260 @@
 	return 0;
 }
 
+static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
+{
+	snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
+	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
+		0x80);
+	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
+		0x04);
+	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
+		0x01);
+	usleep_range(1000, 1000);
+	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
+		0x00);
+}
+
+static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
+	enum tabla_bandgap_type choice)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	/* TODO lock resources accessed by audio streams and threaded
+	 * interrupt handlers
+	 */
+
+	pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
+		tabla->bandgap_type);
+
+	if (tabla->bandgap_type == choice)
+		return;
+
+	if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
+		(choice == TABLA_BANDGAP_AUDIO_MODE)) {
+		tabla_codec_enable_audio_mode_bandgap(codec);
+	} else if (choice == TABLA_BANDGAP_MBHC_MODE) {
+		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
+			0x2);
+		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
+			0x80);
+		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
+			0x4);
+		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
+			0x01);
+		usleep_range(1000, 1000);
+		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
+			0x00);
+	} else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
+		(choice == TABLA_BANDGAP_AUDIO_MODE)) {
+		snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
+		usleep_range(100, 100);
+		tabla_codec_enable_audio_mode_bandgap(codec);
+	} else if (choice == TABLA_BANDGAP_OFF) {
+		snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
+	} else {
+		pr_err("%s: Error, Invalid bandgap settings\n", __func__);
+	}
+	tabla->bandgap_type = choice;
+}
+
+static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	pr_debug("%s\n", __func__);
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
+	ndelay(160);
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
+	tabla->clock_active = false;
+}
+
+static int tabla_codec_mclk_index(const struct tabla_priv *tabla)
+{
+	if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ)
+		return 0;
+	else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ)
+		return 1;
+	else {
+		BUG_ON(1);
+		return -EINVAL;
+	}
+}
+
+static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32  enable)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	if (enable) {
+		tabla->rx_bias_count++;
+		if (tabla->rx_bias_count == 1)
+			snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
+				0x80, 0x80);
+	} else {
+		tabla->rx_bias_count--;
+		if (!tabla->rx_bias_count)
+			snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
+				0x80, 0x00);
+	}
+}
+
+static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
+	int enable)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s: enable = %d\n", __func__, enable);
+	if (enable) {
+		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
+		snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
+		usleep_range(5, 5);
+		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
+			0x80);
+		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
+			0x80);
+		usleep_range(10, 10);
+		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
+		usleep_range(20, 20);
+		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
+	} else {
+		snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
+			0);
+		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
+		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
+	}
+	tabla->config_mode_active = enable ? true : false;
+
+	return 0;
+}
+
+static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
+	int config_mode)
+{
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s: config_mode = %d\n", __func__, config_mode);
+
+	if (config_mode) {
+		tabla_codec_enable_config_mode(codec, 1);
+		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
+		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
+		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
+		usleep_range(1000, 1000);
+	} else
+		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
+
+	if (!config_mode && tabla->mbhc_polling_active) {
+		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
+		tabla_codec_enable_config_mode(codec, 0);
+
+	}
+
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
+	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
+	snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
+	usleep_range(50, 50);
+	tabla->clock_active = true;
+	return 0;
+}
+
+static int tabla_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s: %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		tabla_codec_enable_bandgap(codec,
+					TABLA_BANDGAP_AUDIO_MODE);
+		tabla_enable_rx_bias(codec, 1);
+
+		snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
+						0x08, 0x08);
+		/* Enable Zero Cross detect for AUX PGA channel
+		 * and set the initial AUX PGA gain to NEG_0P0_DB
+		 * to avoid glitches.
+		 */
+		if (w->reg == TABLA_A_AUX_L_EN) {
+			snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
+						0x20, 0x20);
+			tabla->aux_l_gain = snd_soc_read(codec,
+							TABLA_A_AUX_L_GAIN);
+			snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
+		} else {
+			snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
+						0x20, 0x20);
+			tabla->aux_r_gain = snd_soc_read(codec,
+							TABLA_A_AUX_R_GAIN);
+			snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
+		}
+		if (tabla->aux_pga_cnt++ == 1
+			&& !tabla->mclk_enabled) {
+			tabla_codec_enable_clock_block(codec, 1);
+			pr_debug("AUX PGA enabled RC osc\n");
+		}
+		break;
+
+	case SND_SOC_DAPM_POST_PMU:
+		if (w->reg == TABLA_A_AUX_L_EN)
+			snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
+				tabla->aux_l_gain);
+		else
+			snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
+				tabla->aux_r_gain);
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		/* Mute AUX PGA channel in use before disabling AUX PGA */
+		if (w->reg == TABLA_A_AUX_L_EN) {
+			tabla->aux_l_gain = snd_soc_read(codec,
+							TABLA_A_AUX_L_GAIN);
+			snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
+		} else {
+			tabla->aux_r_gain = snd_soc_read(codec,
+							TABLA_A_AUX_R_GAIN);
+			snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
+		}
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		tabla_enable_rx_bias(codec, 0);
+
+		snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
+						0x08, 0x00);
+		if (w->reg == TABLA_A_AUX_L_EN) {
+			snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
+					tabla->aux_l_gain);
+			snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
+							0x20, 0x00);
+		} else {
+			snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
+					tabla->aux_r_gain);
+			snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
+						0x20, 0x00);
+		}
+
+		if (tabla->aux_pga_cnt-- == 0) {
+			if (tabla->mbhc_polling_active)
+				tabla_codec_enable_bandgap(codec,
+					TABLA_BANDGAP_MBHC_MODE);
+			else
+				tabla_codec_enable_bandgap(codec,
+					TABLA_BANDGAP_OFF);
+
+			if (!tabla->mclk_enabled &&
+				!tabla->mbhc_polling_active) {
+				tabla_codec_enable_clock_block(codec, 0);
+			}
+		}
+		break;
+	}
+	return 0;
+}
+
 static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
@@ -1945,24 +2298,6 @@
 	return 0;
 }
 
-
-static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32  enable)
-{
-	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-
-	if (enable) {
-		tabla->rx_bias_count++;
-		if (tabla->rx_bias_count == 1)
-			snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
-				0x80, 0x80);
-	} else {
-		tabla->rx_bias_count--;
-		if (!tabla->rx_bias_count)
-			snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
-				0x80, 0x00);
-	}
-}
-
 static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -2270,7 +2605,8 @@
 
 	/* Earpiece (RX MIX1) */
 	{"EAR", NULL, "EAR PA"},
-	{"EAR PA", NULL, "DAC1"},
+	{"EAR PA", NULL, "EAR_PA_MIXER"},
+	{"EAR_PA_MIXER", NULL, "DAC1"},
 	{"DAC1", NULL, "CP"},
 
 	{"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
@@ -2281,8 +2617,11 @@
 	{"HEADPHONE", NULL, "HPHL"},
 	{"HEADPHONE", NULL, "HPHR"},
 
-	{"HPHL", NULL, "HPHL DAC"},
-	{"HPHR", NULL, "HPHR DAC"},
+	{"HPHL", NULL, "HPHL_PA_MIXER"},
+	{"HPHL_PA_MIXER", NULL, "HPHL DAC"},
+
+	{"HPHR", NULL, "HPHR_PA_MIXER"},
+	{"HPHR_PA_MIXER", NULL, "HPHR DAC"},
 
 	{"HPHL DAC", NULL, "CP"},
 	{"HPHR DAC", NULL, "CP"},
@@ -2310,11 +2649,16 @@
 	{"LINEOUT4", NULL, "LINEOUT4 PA"},
 	{"LINEOUT5", NULL, "LINEOUT5 PA"},
 
-	{"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
-	{"LINEOUT2 PA", NULL, "LINEOUT2 DAC"},
-	{"LINEOUT3 PA", NULL, "LINEOUT3 DAC"},
-	{"LINEOUT4 PA", NULL, "LINEOUT4 DAC"},
-	{"LINEOUT5 PA", NULL, "LINEOUT5 DAC"},
+	{"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
+	{"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
+	{"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
+	{"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
+	{"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
+	{"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
+	{"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
+	{"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
+	{"LINEOUT5 PA", NULL, "LINEOUT5_PA_MIXER"},
+	{"LINEOUT5_PA_MIXER", NULL, "LINEOUT5 DAC"},
 
 	{"LINEOUT1 DAC", NULL, "RX3 MIX1"},
 	{"LINEOUT5 DAC", NULL, "RX7 MIX1"},
@@ -2488,6 +2832,42 @@
 	{"ADC5", NULL, "AMIC5"},
 	{"ADC6", NULL, "AMIC6"},
 
+	/* AUX PGA Connections */
+	{"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+	{"HPHL_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+	{"HPHL_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+	{"HPHL_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+	{"HPHR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+	{"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+	{"HPHR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+	{"HPHR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+	{"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+	{"LINEOUT1_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+	{"LINEOUT1_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+	{"LINEOUT1_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+	{"LINEOUT2_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+	{"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+	{"LINEOUT2_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+	{"LINEOUT2_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+	{"LINEOUT3_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+	{"LINEOUT3_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+	{"LINEOUT3_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+	{"LINEOUT3_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+	{"LINEOUT4_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+	{"LINEOUT4_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+	{"LINEOUT4_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+	{"LINEOUT4_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+	{"LINEOUT5_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+	{"LINEOUT5_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+	{"LINEOUT5_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+	{"LINEOUT5_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+	{"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+	{"EAR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+	{"EAR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+	{"EAR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+	{"AUX_PGA_Left", NULL, "AMIC5"},
+	{"AUX_PGA_Right", NULL, "AMIC6"},
+
 	{"IIR1", NULL, "IIR1 INP1 MUX"},
 	{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
 	{"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
@@ -2590,7 +2970,6 @@
 	unsigned int value)
 {
 	int ret;
-
 	BUG_ON(reg > TABLA_MAX_REGISTER);
 
 	if (!tabla_volatile(codec, reg)) {
@@ -2624,150 +3003,11 @@
 	return val;
 }
 
-static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
-{
-	snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
-	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
-		0x80);
-	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
-		0x04);
-	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
-		0x01);
-	usleep_range(1000, 1000);
-	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
-		0x00);
-}
-
-static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
-	enum tabla_bandgap_type choice)
-{
-	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-
-	/* TODO lock resources accessed by audio streams and threaded
-	 * interrupt handlers
-	 */
-
-	pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
-		tabla->bandgap_type);
-
-	if (tabla->bandgap_type == choice)
-		return;
-
-	if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
-		(choice == TABLA_BANDGAP_AUDIO_MODE)) {
-		tabla_codec_enable_audio_mode_bandgap(codec);
-	} else if (choice == TABLA_BANDGAP_MBHC_MODE) {
-		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
-			0x2);
-		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
-			0x80);
-		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
-			0x4);
-		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
-			0x01);
-		usleep_range(1000, 1000);
-		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
-			0x00);
-	} else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
-		(choice == TABLA_BANDGAP_AUDIO_MODE)) {
-		snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
-		usleep_range(100, 100);
-		tabla_codec_enable_audio_mode_bandgap(codec);
-	} else if (choice == TABLA_BANDGAP_OFF) {
-		snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
-	} else {
-		pr_err("%s: Error, Invalid bandgap settings\n", __func__);
-	}
-	tabla->bandgap_type = choice;
-}
-
-static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
-	int enable)
-{
-	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-
-	if (enable) {
-		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
-		snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
-		usleep_range(5, 5);
-		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
-			0x80);
-		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
-			0x80);
-		usleep_range(10, 10);
-		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
-		usleep_range(20, 20);
-		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
-	} else {
-		snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
-			0);
-		snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
-		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
-	}
-	tabla->config_mode_active = enable ? true : false;
-
-	return 0;
-}
-
-static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
-	int config_mode)
-{
-	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-
-	pr_debug("%s: config_mode = %d\n", __func__, config_mode);
-
-	if (config_mode) {
-		tabla_codec_enable_config_mode(codec, 1);
-		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
-		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
-		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
-		usleep_range(1000, 1000);
-	} else
-		snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
-
-	if (!config_mode && tabla->mbhc_polling_active) {
-		snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
-		tabla_codec_enable_config_mode(codec, 0);
-
-	}
-
-	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
-	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
-	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
-	snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
-	usleep_range(50, 50);
-	tabla->clock_active = true;
-	return 0;
-}
-static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
-{
-	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-	pr_debug("%s\n", __func__);
-	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
-	ndelay(160);
-	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
-	snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
-	tabla->clock_active = false;
-}
-
-static int tabla_codec_mclk_index(const struct tabla_priv *tabla)
-{
-	if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ)
-		return 0;
-	else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ)
-		return 1;
-	else {
-		BUG_ON(1);
-		return -EINVAL;
-	}
-}
-
 static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
 {
 	u8 *n_ready, *n_cic;
 	struct tabla_mbhc_btn_detect_cfg *btn_det;
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-
 	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
 
 	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
@@ -3662,6 +3902,42 @@
 	/* Sidetone */
 	SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
 	SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
+
+	/* AUX PGA */
+	SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TABLA_A_AUX_L_EN, 7, 0,
+		tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU |	SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("AUX_PGA_Right", NULL, TABLA_A_AUX_R_EN, 7, 0,
+		tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMD),
+
+	/* Lineout, ear and HPH PA Mixers */
+	SND_SOC_DAPM_MIXER("HPHL_PA_MIXER", SND_SOC_NOPM, 0, 0,
+		hphl_pa_mix, ARRAY_SIZE(hphl_pa_mix)),
+
+	SND_SOC_DAPM_MIXER("HPHR_PA_MIXER", SND_SOC_NOPM, 0, 0,
+		hphr_pa_mix, ARRAY_SIZE(hphr_pa_mix)),
+
+	SND_SOC_DAPM_MIXER("LINEOUT1_PA_MIXER", SND_SOC_NOPM, 0, 0,
+		lineout1_pa_mix, ARRAY_SIZE(lineout1_pa_mix)),
+
+	SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
+		lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
+
+	SND_SOC_DAPM_MIXER("LINEOUT3_PA_MIXER", SND_SOC_NOPM, 0, 0,
+		lineout3_pa_mix, ARRAY_SIZE(lineout3_pa_mix)),
+
+	SND_SOC_DAPM_MIXER("LINEOUT4_PA_MIXER", SND_SOC_NOPM, 0, 0,
+		lineout4_pa_mix, ARRAY_SIZE(lineout4_pa_mix)),
+
+	SND_SOC_DAPM_MIXER("LINEOUT5_PA_MIXER", SND_SOC_NOPM, 0, 0,
+		lineout5_pa_mix, ARRAY_SIZE(lineout5_pa_mix)),
+
+	SND_SOC_DAPM_MIXER("EAR_PA_MIXER", SND_SOC_NOPM, 0, 0,
+		ear_pa_mix, ARRAY_SIZE(ear_pa_mix)),
 };
 
 static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
@@ -5272,7 +5548,9 @@
 	}
 	tabla->pdata = dev_get_platdata(codec->dev->parent);
 	tabla->intf_type = wcd9xxx_get_intf_type();
-
+	tabla->aux_pga_cnt = 0;
+	tabla->aux_l_gain = 0x1F;
+	tabla->aux_r_gain = 0x1F;
 	tabla_update_reg_address(tabla);
 	tabla_update_reg_defaults(codec);
 	tabla_codec_init_reg(codec);
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index ae4e403..a97bf87 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -55,7 +55,7 @@
 
 #define TABLA_EXT_CLK_RATE 12288000
 
-#define TABLA_MBHC_DEF_BUTTONS 3
+#define TABLA_MBHC_DEF_BUTTONS 8
 #define TABLA_MBHC_DEF_RLOADS 5
 
 static u32 top_spk_pamp_gpio  = PM8921_GPIO_PM_TO_SYS(18);
@@ -604,7 +604,7 @@
 	void *tabla_cal;
 	struct tabla_mbhc_btn_detect_cfg *btn_cfg;
 	u16 *btn_low, *btn_high;
-	u8 *n_cic, *gain;
+	u8 *n_ready, *n_cic, *gain;
 
 	tabla_cal = kzalloc(TABLA_MBHC_CAL_SIZE(TABLA_MBHC_DEF_BUTTONS,
 						TABLA_MBHC_DEF_RLOADS),
@@ -625,25 +625,21 @@
 	S(mic_current, TABLA_PID_MIC_5_UA);
 	S(hph_current, TABLA_PID_MIC_5_UA);
 	S(t_mic_pid, 100);
-	S(t_ins_complete, 1000);
+	S(t_ins_complete, 250);
 	S(t_ins_retry, 200);
 #undef S
 #define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
 	S(v_no_mic, 30);
-	S(v_hs_max, 1450);
+	S(v_hs_max, 1550);
 #undef S
 #define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
-	S(c[0], 6);
-	S(c[1], 10);
-	S(c[2], 10);
-	S(c[3], 14);
-	S(c[4], 14);
-	S(c[5], 16);
-	S(c[6], 0);
-	S(c[7], 0);
-	S(nc, 5);
-	S(n_meas, 11);
+	S(c[0], 62);
+	S(c[1], 124);
+	S(nc, 1);
+	S(n_meas, 3);
 	S(mbhc_nsc, 11);
+	S(n_btn_meas, 1);
+	S(n_btn_con, 2);
 	S(num_btn, TABLA_MBHC_DEF_BUTTONS);
 	S(v_btn_press_delta_sta, 100);
 	S(v_btn_press_delta_cic, 50);
@@ -651,15 +647,28 @@
 	btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal);
 	btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
 	btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
-	btn_low[0] = 0;
-	btn_high[0] = 40;
-	btn_low[1] = 60;
-	btn_high[1] = 140;
-	btn_low[2] = 160;
-	btn_high[2] = 240;
+	btn_low[0] = -50;
+	btn_high[0] = 10;
+	btn_low[1] = 11;
+	btn_high[1] = 38;
+	btn_low[2] = 39;
+	btn_high[2] = 64;
+	btn_low[3] = 65;
+	btn_high[3] = 91;
+	btn_low[4] = 92;
+	btn_high[4] = 115;
+	btn_low[5] = 116;
+	btn_high[5] = 141;
+	btn_low[6] = 142;
+	btn_high[6] = 163;
+	btn_low[7] = 164;
+	btn_high[7] = 250;
+	n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
+	n_ready[0] = 48;
+	n_ready[1] = 38;
 	n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
-	n_cic[0] = 120;
-	n_cic[1] = 94;
+	n_cic[0] = 60;
+	n_cic[1] = 47;
 	gain = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_GAIN);
 	gain[0] = 11;
 	gain[1] = 9;
@@ -777,7 +786,7 @@
 	}
 
 	err = snd_soc_jack_new(codec, "Button Jack",
-				SND_JACK_BTN_0, &button_jack);
+			       TABLA_JACK_BUTTON_MASK, &button_jack);
 	if (err) {
 		pr_err("failed to create new jack\n");
 		return err;
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 14da1ba..4f19160 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -259,7 +259,7 @@
 {
 	bool rc = false;
 
-	if (be_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+	if (fe_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
 		/* recheck FE ID in the mixer control defined in this file */
 		pr_err("%s: bad MM ID\n", __func__);
 		return rc;