Merge "msm: restart_7k: Move restart code out of pm2.c" into msm-3.4
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
new file mode 100644
index 0000000..2ba7341
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
@@ -0,0 +1,98 @@
+Qualcomm's QPNP PMIC Voltage ADC Arbiter
+
+QPNP PMIC Voltage ADC (VADC) provides interface to clients to read
+Voltage. A 15 bit ADC is used for Voltage measurements. There are multiple
+peripherals to the VADC and the scope of the driver is to provide interface
+for the USR peripheral of the VADC.
+
+VADC node
+
+Required properties:
+- compatible : should be "qcom,qpnp-vadc" for Voltage ADC driver.
+- reg : offset and length of the PMIC Aribter register map.
+- interrupts : The USR bank peripheral VADC interrupt.
+- qcom,adc-bit-resolution : Bit resolution of the ADC.
+- qcom,adc-vdd-reference : Voltage reference used by the ADC.
+
+Channel nodes
+NOTE: Atleast one Channel node is required.
+
+Required properties:
+- label : Channel name used for sysfs entry.
+- qcom,channel-num : Channel number associated to the AMUX input.
+- qcom,decimation : Sampling rate to use for the individual channel measurement.
+		    Select from following unsigned int.
+		    0 : 512
+		    1 : 1K
+		    2 : 2K
+		    3 : 4K
+- qcom,pre-div-channel-scaling : Pre-div used for the channel before the signal
+				 is being measured.
+- qcom,calibration-type : Reference voltage to use for channel calibration.
+			  Channel calibration is dependendent on the channel.
+			  Certain channels like XO_THERM, BATT_THERM use ratiometric
+			  calibration. Most other channels fall under absolute calibration.
+			  Select from the following strings.
+			  "absolute" : Uses the 625mv and 1.25V reference channels.
+			  "ratiometric" : Uses the reference Voltage/GND for calibration.
+- qcom,scale-function : Scaling function used to convert raw ADC code to units specific to
+			a given channel.
+			Select from the following unsigned int.
+			0 : Default scaling to convert raw adc code to voltage.
+			1 : Conversion to temperature based on btm parameters.
+			2 : Returns result in milli degree's Centigrade.
+			3 : Returns current across 0.1 ohm resistor.
+			4 : Returns XO thermistor voltage in degree's Centigrade.
+- qcom,hw-settle-time : Settling period for the channel before ADC read.
+			Select from the following unsigned int.
+			0 : 0us
+			1 : 100us
+			2 : 200us
+			3 : 300us
+			4 : 400us
+			5 : 500us
+			6 : 600us
+			7 : 700us
+			8 : 800us
+			9 : 900us
+			0xa : 1ms
+			0xb : 2ms
+			0xc : 4ms
+			0xd : 6ms
+			0xe : 8ms
+			0xf : 10ms
+- qcom,fast-avg-setup : Average number of samples to be used for measurement. Fast averaging
+			provides the option to obtain a single measurement from the ADC that
+			is an average of multiple samples. The value selected is 2^(value)
+			Select from the following unsigned int.
+			0 : 1
+			1 : 2
+			2 : 4
+			3 : 8
+			4 : 16
+			5 : 32
+			6 : 64
+			7 : 128
+			8 : 256
+
+Example:
+	/* Main Node */
+	qcom,vadc@3100 {
+                        compatible = "qcom,qpnp-vadc";
+                        reg = <0x3100 0x100>;
+                        interrupts = <0x0 0x31 0x0>;
+                        qcom,adc-bit-resolution = <15>;
+                        qcom,adc-vdd-reference = <1800>;
+
+			/* Channel Node */
+                        chan@0 {
+                                label = "usb_in";
+                                qcom,channel-num = <0>;
+                                qcom,decimation = <0>;
+                                qcom,pre-div-channel-scaling = <20>;
+                                qcom,calibration-type = "absolute";
+                                qcom,scale-function = <0>;
+                                qcom,hw-settle-time = <0>;
+                                qcom,fast-avg-setup = <0>;
+                        };
+	};
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu.txt b/Documentation/devicetree/bindings/iommu/msm_iommu.txt
index c198fe9..e9fb1a2 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu.txt
@@ -12,7 +12,7 @@
   - interrupts : should contain the context bank interrupt.
   - qcom,iommu-ctx-sids : List of stream identifiers associated with this
     translation context.
-  - qcom,iommu-ctx-name : Name of the context bank
+  - label : Name of the context bank
   - qcom,iommu-smt-size : Number of SMR entries in the SMT of this HW block
   - vdd-supply : vdd-supply: phandle to GDSC regulator controlling this IOMMU.
 
@@ -27,12 +27,12 @@
                         reg = <0xfda6c000 0x1000>;
                         interrupts = <0 70 0>;
                         qcom,iommu-ctx-sids = <0 2>;
-			qcom,iommu-ctx-name = "ctx_0";
+			label = "ctx_0";
                 };
                 qcom,iommu-ctx@fda6d000 {
                         reg = <0xfda6d000 0x1000>;
                         interrupts = <0 71 0>;
                         qcom,iommu-ctx-sids = <1>;
-			qcom,iommu-ctx-name = "ctx_1";
+			label = "ctx_1";
                 };
         };
diff --git a/arch/arm/boot/dts/msm-iommu.dtsi b/arch/arm/boot/dts/msm-iommu.dtsi
new file mode 100755
index 0000000..952f517
--- /dev/null
+++ b/arch/arm/boot/dts/msm-iommu.dtsi
@@ -0,0 +1,159 @@
+/* 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.
+ */
+
+/ {
+	jpeg_iommu: qcom,iommu@fda64000 {
+		compatible = "qcom,msm-smmu-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfda64000 0x10000>;
+		vdd-supply = <&gdsc_jpeg>;
+		qcom,iommu-smt-size = <16>;
+		status = "disabled";
+
+		qcom,iommu-ctx@fda6c000 {
+			reg = <0xfda6c000 0x1000>;
+			interrupts = <0 69 0>;
+			qcom,iommu-ctx-sids = <0>;
+			label = "jpeg_enc0";
+		};
+
+		qcom,iommu-ctx@fda6d000 {
+			reg = <0xfda6d000 0x1000>;
+			interrupts = <0 70 0>;
+			qcom,iommu-ctx-sids = <1>;
+			label = "jpeg_enc1";
+		};
+
+		qcom,iommu-ctx@fda6e000 {
+			reg = <0xfda6e000 0x1000>;
+			interrupts = <0 71 0>;
+			qcom,iommu-ctx-sids = <2>;
+			label = "jpeg_dec";
+		};
+	};
+
+	mdp_iommu: qcom,iommu@fd928000 {
+		compatible = "qcom,msm-smmu-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfd928000 0x10000>;
+		vdd-supply = <&gdsc_mdss>;
+		qcom,iommu-smt-size = <16>;
+		status = "disabled";
+
+		qcom,iommu-ctx@fd930000 {
+			reg = <0xfd930000 0x1000>;
+			interrupts = <0 46 0>;
+			qcom,iommu-ctx-sids = <0>;
+			label = "mdp_0";
+		};
+
+		qcom,iommu-ctx@fd931000 {
+			reg = <0xfd931000 0x1000>;
+			interrupts = <0 47 0>;
+			qcom,iommu-ctx-sids = <1>;
+			label = "mdp_1";
+		};
+	};
+
+	venus_iommu: qcom,iommu@fdc84000 {
+		compatible = "qcom,msm-smmu-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfdc84000 0x10000>;
+		vdd-supply = <&gdsc_venus>;
+		qcom,iommu-smt-size = <16>;
+		status = "disabled";
+
+		qcom,iommu-ctx@fdc8c000 {
+			reg = <0xfdc8c000 0x1000>;
+			interrupts = <0 43 0>;
+			qcom,iommu-ctx-sids = <0 1 2 3 4 5>;
+			label = "venus_ns";
+		};
+
+		qcom,iommu-ctx@fdc8d000 {
+			reg = <0xfdc8d000 0x1000>;
+			interrupts = <0 42 0>;
+			qcom,iommu-ctx-sids = <0x80 0x81 0x82 0x83 0x84 0x85>;
+			label = "venus_cp";
+		};
+
+		qcom,iommu-ctx@fdc8e000 {
+			reg = <0xfdc8e000 0x1000>;
+			interrupts = <0 41 0>;
+			qcom,iommu-ctx-sids = <0xc0 0xc6>;
+			label = "venus_fw";
+		};
+	};
+
+	kgsl_iommu: qcom,iommu@fdb10000 {
+		compatible = "qcom,msm-smmu-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfdb10000 0x10000>;
+		vdd-supply = <&gdsc_oxili_cx>;
+		qcom,iommu-smt-size = <32>;
+		status = "disabled";
+
+		qcom,iommu-ctx@fdb18000 {
+			reg = <0xfdb18000 0x1000>;
+			interrupts = <0 240 0>;
+			qcom,iommu-ctx-sids = <0>;
+			label = "gfx3d_user";
+		};
+
+		qcom,iommu-ctx@fdb19000 {
+			reg = <0xfdb19000 0x1000>;
+			interrupts = <0 241 0>;
+			qcom,iommu-ctx-sids = <1>;
+			label = "gfx3d_priv";
+		};
+	};
+
+	vfe_iommu: qcom,iommu@fda44000 {
+		compatible = "qcom,msm-smmu-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfda44000 0x10000>;
+		vdd-supply = <&gdsc_vfe>;
+		qcom,iommu-smt-size = <32>;
+		status = "disabled";
+
+		qcom,iommu-ctx@fda4c000 {
+			reg = <0xfda4c000 0x1000>;
+			interrupts = <0 64 0>;
+			qcom,iommu-ctx-sids = <0>;
+			label = "vfe0";
+		};
+
+		qcom,iommu-ctx@fda4d000 {
+			reg = <0xfda4d000 0x1000>;
+			interrupts = <0 65 0>;
+			qcom,iommu-ctx-sids = <1>;
+			label = "vfe1";
+		};
+
+		qcom,iommu-ctx@fda4e000 {
+			reg = <0xfda4e000 0x1000>;
+			interrupts = <0 66 0>;
+			qcom,iommu-ctx-sids = <2>;
+			label = "cpp";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-iommu.dtsi b/arch/arm/boot/dts/msm8974-iommu.dtsi
index a115fd8..184826e 100755
--- a/arch/arm/boot/dts/msm8974-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-iommu.dtsi
@@ -10,108 +10,24 @@
  * GNU General Public License for more details.
  */
 
-/ {
-	jpeg: qcom,iommu@fda64000 {
-		compatible = "qcom,msm-smmu-v2";
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-		reg = <0xfda64000 0x10000>;
-		vdd-supply = <&gdsc_jpeg>;
-		qcom,iommu-smt-size = <16>;
+/include/ "msm-iommu.dtsi"
 
-		qcom,iommu-ctx@fda6c000 {
-			reg = <0xfda6c000 0x1000>;
-			interrupts = <0 69 0>;
-			qcom,iommu-ctx-sids = <0>;
-			qcom,iommu-ctx-name = "jpeg_enc0";
-		};
-		qcom,iommu-ctx@fda6d000 {
-			reg = <0xfda6d000 0x1000>;
-			interrupts = <0 70 0>;
-			qcom,iommu-ctx-sids = <1>;
-			qcom,iommu-ctx-name = "jpeg_enc1";
-		};
-		qcom,iommu-ctx@fda6e000 {
-			reg = <0xfda6e000 0x1000>;
-			interrupts = <0 71 0>;
-			qcom,iommu-ctx-sids = <2>;
-			qcom,iommu-ctx-name = "jpeg_dec";
-		};
-	};
+&jpeg_iommu {
+	status = "ok";
+};
 
-	mdp: qcom,iommu@fd928000 {
-		compatible = "qcom,msm-smmu-v2";
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-		reg = <0xfd928000 0x10000>;
-		vdd-supply = <&gdsc_mdss>;
-		qcom,iommu-smt-size = <16>;
+&mdp_iommu {
+	status = "ok";
+};
 
-		qcom,iommu-ctx@fd930000 {
-			reg = <0xfd930000 0x1000>;
-			interrupts = <0 74 0>;
-			qcom,iommu-ctx-sids = <0>;
-			qcom,iommu-ctx-name = "mdp_0";
-		};
-		qcom,iommu-ctx@fd931000 {
-			reg = <0xfd931000 0x1000>;
-			interrupts = <0 75 0>;
-			qcom,iommu-ctx-sids = <1>;
-			qcom,iommu-ctx-name = "mdp_1";
-		};
-	};
+&venus_iommu {
+	status = "ok";
+};
 
-	venus: qcom,iommu@fdc84000 {
-		compatible = "qcom,msm-smmu-v2";
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-		reg = <0xfdc84000 0x10000>;
-		vdd-supply = <&gdsc_venus>;
-		qcom,iommu-smt-size = <16>;
+&kgsl_iommu {
+	status = "ok";
+};
 
-		qcom,iommu-ctx@fdc8c000 {
-			reg = <0xfdc8c000 0x1000>;
-			interrupts = <0 43 0>;
-			qcom,iommu-ctx-sids = <0 1 2 3 4 5>;
-			qcom,iommu-ctx-name = "venus_ns";
-		};
-		qcom,iommu-ctx@fdc8d000 {
-			reg = <0xfdc8d000 0x1000>;
-			interrupts = <0 42 0>;
-			qcom,iommu-ctx-sids = <0x80 0x81 0x82 0x83 0x84 0x85>;
-			qcom,iommu-ctx-name = "venus_cp";
-		};
-		qcom,iommu-ctx@fdc8e000 {
-			reg = <0xfdc8e000 0x1000>;
-			interrupts = <0 41 0>;
-			qcom,iommu-ctx-sids = <0xc0 0xc6>;
-			qcom,iommu-ctx-name = "venus_fw";
-		};
-	};
-
-	kgsl: qcom,iommu@fdb10000 {
-		compatible = "qcom,msm-smmu-v2";
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-		reg = <0xfdb10000 0x10000>;
-		vdd-supply = <&gdsc_oxili_cx>;
-		qcom,iommu-smt-size = <32>;
-
-		qcom,iommu-ctx@fdb18000 {
-			reg = <0xfdb18000 0x1000>;
-			interrupts = <0 240 0>;
-			qcom,iommu-ctx-sids = <0>;
-			qcom,iommu-ctx-name = "gfx3d_user";
-		};
-		qcom,iommu-ctx@fdb19000 {
-			reg = <0xfdb19000 0x1000>;
-			interrupts = <0 241 0>;
-			qcom,iommu-ctx-sids = <1>;
-			qcom,iommu-ctx-name = "gfx3d_priv";
-		};
-	};
+&vfe_iommu {
+	status = "ok";
 };
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 719eb4e..220a660 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -557,6 +557,12 @@
 		qcom,firmware-max-paddr = <0xFA00000>;
 	};
 
+	qcom,cache_erp {
+		compatible = "qcom,cache_erp";
+		interrupts = <1 9 0>, <0 2 0>;
+		interrupt-names = "l1_irq", "l2_irq";
+	};
+
 	tsens@fc4a8000 {
 		compatible = "qcom,msm-tsens";
 		reg = <0xfc4a8000 0x2000>,
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index c2f4702..7707692 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -83,6 +83,7 @@
 CONFIG_MSM_GSS_SSR_8064=y
 CONFIG_MSM_TZ_LOG=y
 CONFIG_MSM_RPM_LOG=y
+CONFIG_MSM_RPM_RBCPR_STATS_LOG=y
 CONFIG_MSM_RPM_STATS_LOG=y
 CONFIG_MSM_BUS_SCALING=y
 CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index a50485d..87c536f 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -83,6 +83,7 @@
 CONFIG_MSM_TZ_LOG=y
 CONFIG_MSM_RPM_LOG=y
 CONFIG_MSM_RPM_STATS_LOG=y
+CONFIG_MSM_RPM_RBCPR_STATS_LOG=y
 CONFIG_MSM_BUS_SCALING=y
 CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED=y
 CONFIG_MSM_WATCHDOG=y
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
index 99ee2de..e32194f 100644
--- a/arch/arm/include/asm/arch_timer.h
+++ b/arch/arm/include/asm/arch_timer.h
@@ -2,6 +2,7 @@
 #define __ASMARM_ARCH_TIMER_H
 
 #include <linux/ioport.h>
+#include <linux/clocksource.h>
 
 struct arch_timer {
 	struct resource	res[3];
@@ -10,6 +11,7 @@
 #ifdef CONFIG_ARM_ARCH_TIMER
 int arch_timer_register(struct arch_timer *);
 int arch_timer_of_register(void);
+cycle_t arch_counter_get_cntpct(void);
 #else
 static inline int arch_timer_register(struct arch_timer *at)
 {
@@ -20,6 +22,11 @@
 {
 	return -ENXIO;
 }
+
+static inline cycle_t arch_counter_get_cntpct(void)
+{
+	return 0;
+}
 #endif
 
 #endif
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 87bb7d3..43c627d 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -22,6 +22,7 @@
 #include <linux/of_address.h>
 #include <linux/io.h>
 #include <linux/irq.h>
+#include <linux/export.h>
 
 #include <asm/cputype.h>
 #include <asm/localtimer.h>
@@ -315,10 +316,16 @@
 	return ((cycle_t) cvalh << 32) | cvall;
 }
 
-static cycle_t arch_counter_read(struct clocksource *cs)
+cycle_t arch_counter_get_cntpct(void)
 {
 	return arch_specific_timer->get_cntpct();
 }
+EXPORT_SYMBOL(arch_counter_get_cntpct);
+
+static cycle_t arch_counter_read(struct clocksource *cs)
+{
+	return arch_counter_get_cntpct();
+}
 
 #ifdef ARCH_HAS_READ_CURRENT_TIMER
 int read_current_timer(unsigned long *timer_val)
diff --git a/arch/arm/mach-msm/acpuclock-7627.c b/arch/arm/mach-msm/acpuclock-7627.c
index f9ff226..639cc94 100644
--- a/arch/arm/mach-msm/acpuclock-7627.c
+++ b/arch/arm/mach-msm/acpuclock-7627.c
@@ -38,11 +38,15 @@
 
 #include "smd_private.h"
 #include "acpuclock.h"
+#include "clock.h"
 
 #define A11S_CLK_CNTL_ADDR (MSM_CSR_BASE + 0x100)
 #define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104)
 #define A11S_VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124)
 
+#define PLL4_L_VAL_ADDR		(MSM_CLK_CTL_BASE + 0x378)
+#define PLL4_M_VAL_ADDR		(MSM_CLK_CTL_BASE + 0x37C)
+#define PLL4_N_VAL_ADDR		(MSM_CLK_CTL_BASE + 0x380)
 
 #define POWER_COLLAPSE_KHZ 19200
 
@@ -67,6 +71,12 @@
 	const char *name;
 };
 
+struct pll_config {
+	unsigned int l;
+	unsigned int m;
+	unsigned int n;
+};
+
 static struct acpu_clk_src pll_clk[ACPU_PLL_END] = {
 	[ACPU_PLL_0] = { .name = "pll0_clk" },
 	[ACPU_PLL_1] = { .name = "pll1_clk" },
@@ -74,6 +84,13 @@
 	[ACPU_PLL_4] = { .name = "pll4_clk" },
 };
 
+static struct pll_config pll4_cfg_tbl[] = {
+	{  36, 1, 2 }, /*  700.8 MHz */
+	{  52, 1, 2 }, /* 1008 MHz */
+	{  63, 0, 1 }, /* 1209.6 MHz */
+	{  73, 0, 1 }, /* 1401.6 MHz */
+};
+
 struct clock_state {
 	struct clkctl_acpu_speed	*current_speed;
 	struct mutex			lock;
@@ -91,15 +108,20 @@
 	unsigned int	ahbclk_div;
 	int		vdd;
 	unsigned int	axiclk_khz;
+	struct pll_config *pll_rate;
 	unsigned long   lpj; /* loops_per_jiffy */
 	/* Pointers in acpu_freq_tbl[] for max up/down steppings. */
 	struct clkctl_acpu_speed *down[ACPU_PLL_END];
 	struct clkctl_acpu_speed *up[ACPU_PLL_END];
 };
 
+static bool dynamic_reprogram;
 static struct clock_state drv_state = { 0 };
 static struct clkctl_acpu_speed *acpu_freq_tbl;
 
+/* Switch to this when reprogramming PLL4 */
+static struct clkctl_acpu_speed *backup_s;
+
 /*
  * ACPU freq tables used for different PLLs frequency combinations. The
  * correct table is selected during init.
@@ -119,7 +141,7 @@
 	{ 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 160000 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 200000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0 }
 };
 
 /* 7627 with CDMA capable modem */
@@ -133,7 +155,7 @@
 	{ 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 160000 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 200000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0 }
 };
 
 /* 7627 with GSM capable modem - PLL2 @ 800 */
@@ -147,7 +169,7 @@
 	{ 0, 400000, ACPU_PLL_2, 2, 1, 133333, 2, 5, 160000 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
 	{ 1, 800000, ACPU_PLL_2, 2, 0, 200000, 3, 7, 200000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0 }
 };
 
 /* 7627 with CDMA capable modem - PLL2 @ 800 */
@@ -161,7 +183,7 @@
 	{ 0, 400000, ACPU_PLL_2, 2, 1, 133333, 2, 5, 160000 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
 	{ 1, 800000, ACPU_PLL_2, 2, 0, 200000, 3, 7, 200000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0 }
 };
 
 /* 7627a PLL2 @ 1200MHz with GSM capable modem */
@@ -176,7 +198,7 @@
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
 	{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0 }
 };
 
 /* 7627a PLL2 @ 1200MHz with CDMA capable modem */
@@ -191,7 +213,7 @@
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 120000 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
 	{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0 }
 };
 
 /* 7627aa PLL4 @ 1008MHz with GSM capable modem */
@@ -206,7 +228,7 @@
 	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 160000 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
 	{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0 }
 };
 
 /* 7627aa PLL4 @ 1008MHz with CDMA capable modem */
@@ -221,7 +243,7 @@
 	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 160000 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
 	{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0 }
 };
 
 /* 8625 PLL4 @ 1209MHz with GSM capable modem */
@@ -235,7 +257,7 @@
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
 	{ 0, 604800, ACPU_PLL_4, 6, 1, 75600, 3, 6, 160000 },
 	{ 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, 0} }
+	{ 0 }
 };
 
 /* 8625 PLL4 @ 1209MHz with CDMA capable modem */
@@ -249,7 +271,40 @@
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
 	{ 0, 604800, ACPU_PLL_4, 6, 1, 75600, 3, 6, 160000 },
 	{ 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, 0} }
+	{ 0 }
+};
+
+/* 8625 PLL4 @ 1401.6MHz with GSM capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_pll4_1401[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
+	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 0, 61440 },
+	{ 0, 122880, ACPU_PLL_1, 1, 1,  15360, 3, 1, 61440 },
+	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 1, 61440 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 2, 122880 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 2, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 3, 122880 },
+	{ 0, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 4, 160000 },
+	{ 1, 700800, ACPU_PLL_4, 6, 0, 87500, 3, 4, 160000, &pll4_cfg_tbl[0]},
+	{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 5, 200000, &pll4_cfg_tbl[1]},
+	{ 1, 1209600, ACPU_PLL_4, 6, 0, 151200, 3, 6, 200000, &pll4_cfg_tbl[2]},
+	{ 1, 1401600, ACPU_PLL_4, 6, 0, 175000, 3, 7, 200000, &pll4_cfg_tbl[3]},
+	{ 0 }
+};
+
+/* 8625 PLL4 @ 1401.6MHz with CDMA capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_1200_pll4_1401[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
+	{ 0, 65536, ACPU_PLL_1, 1, 3,  8192, 3, 1, 49152 },
+	{ 0, 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, 2, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 3, 122880 },
+	{ 0, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 4, 160000 },
+	{ 1, 700800, ACPU_PLL_4, 6, 0, 87500, 3, 4, 160000, &pll4_cfg_tbl[0]},
+	{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 5, 200000, &pll4_cfg_tbl[1]},
+	{ 1, 1209600, ACPU_PLL_4, 6, 0, 151200, 3, 6, 200000, &pll4_cfg_tbl[2]},
+	{ 1, 1401600, ACPU_PLL_4, 6, 0, 175000, 3, 7, 200000, &pll4_cfg_tbl[3]},
+	{ 0 }
 };
 
 /* 8625 PLL4 @ 1152MHz with GSM capable modem */
@@ -263,7 +318,7 @@
 	{ 0, 576000, ACPU_PLL_4, 6, 1, 72000, 3, 6, 160000 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
 	{ 1, 1152000, ACPU_PLL_4, 6, 0, 144000, 3, 7, 200000},
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0 }
 };
 
 /* 8625 PLL4 @ 1115MHz with CDMA capable modem */
@@ -277,7 +332,7 @@
 	{ 0, 576000, ACPU_PLL_4, 6, 1, 72000, 3, 6, 160000 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
 	{ 1, 1152000, ACPU_PLL_4, 6, 0, 144000, 3, 7, 200000},
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0 }
 };
 
 
@@ -292,7 +347,7 @@
 	{ 0, 400000, ACPU_PLL_2, 2, 2, 50000, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0 }
 };
 
 /* 7627a PLL2 @ 1200MHz with GSM capable modem */
@@ -307,7 +362,7 @@
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
 	{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0 }
 };
 
 /* 7627a PLL2 @ 1200MHz with CDMA capable modem */
@@ -322,7 +377,7 @@
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 120000 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
 	{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0 }
 };
 
 /* 7627aa PLL4 @ 1008MHz with GSM capable modem */
@@ -337,7 +392,7 @@
 	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 160000 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
 	{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0 }
 };
 
 /* 7627aa PLL4 @ 1008MHz with CDMA capable modem */
@@ -352,7 +407,7 @@
 	{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 160000 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
 	{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0 }
 };
 
 /* 7625a PLL2 @ 1200MHz with GSM capable modem */
@@ -366,7 +421,7 @@
 	{ 0, 400000, ACPU_PLL_2, 2, 2, 50000, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+	{ 0 }
 };
 
 #define PLL_CONFIG(m0, m1, m2, m4) { \
@@ -399,6 +454,8 @@
 	PLL_CONFIG(960, 196, 1200, 1209),
 	PLL_CONFIG(960, 245, 1200, 1152),
 	PLL_CONFIG(960, 196, 1200, 1152),
+	PLL_CONFIG(960, 245, 1200, 1401),
+	PLL_CONFIG(960, 196, 1200, 1401),
 	{ 0, 0, 0, 0, 0 }
 };
 
@@ -439,6 +496,31 @@
 }
 #endif
 
+static void update_jiffies(int cpu, unsigned long loops)
+{
+#ifdef CONFIG_SMP
+	for_each_possible_cpu(cpu) {
+		per_cpu(cpu_data, cpu).loops_per_jiffy =
+						loops;
+	}
+#endif
+	/* Adjust the global one */
+	loops_per_jiffy = loops;
+}
+
+/* Assumes PLL4 is off and the acpuclock isn't sourced from PLL4 */
+static void acpuclk_config_pll4(struct pll_config *pll)
+{
+	/* Make sure write to disable PLL_4 has completed
+	 * before reconfiguring that PLL. */
+	mb();
+	writel_relaxed(pll->l, PLL4_L_VAL_ADDR);
+	writel_relaxed(pll->m, PLL4_M_VAL_ADDR);
+	writel_relaxed(pll->n, PLL4_N_VAL_ADDR);
+	/* Make sure PLL is programmed before returning. */
+	mb();
+}
+
 static int acpuclk_set_vdd_level(int vdd)
 {
 	uint32_t current_vdd;
@@ -524,6 +606,7 @@
 	struct clkctl_acpu_speed *cur_s, *tgt_s, *strt_s;
 	int res, rc = 0;
 	unsigned int plls_enabled = 0, pll;
+	int delta;
 
 	if (reason == SETRATE_CPUFREQ)
 		mutex_lock(&drv_state.lock);
@@ -592,6 +675,61 @@
 	pr_debug("Switching from ACPU rate %u KHz -> %u KHz\n",
 		       strt_s->a11clk_khz, tgt_s->a11clk_khz);
 
+	delta = abs((int)(strt_s->a11clk_khz - tgt_s->a11clk_khz));
+
+	if (dynamic_reprogram) {
+		if (tgt_s->pll == ACPU_PLL_4) {
+			if (strt_s->pll == ACPU_PLL_4 ||
+					delta > drv_state.max_speed_delta_khz) {
+				/*
+				 * Enable the backup PLL if required
+				 * and switch to it.
+				 */
+				clk_enable(pll_clk[backup_s->pll].clk);
+				acpuclk_set_div(backup_s);
+			}
+			/* Make sure PLL4 is off before reprogramming */
+			if ((plls_enabled & (1 << tgt_s->pll))) {
+				clk_disable(pll_clk[tgt_s->pll].clk);
+				plls_enabled &= (0 << tgt_s->pll);
+			}
+			acpuclk_config_pll4(tgt_s->pll_rate);
+			pll_clk[tgt_s->pll].clk->rate = tgt_s->a11clk_khz*1000;
+
+		} else if (strt_s->pll == ACPU_PLL_4) {
+			if (delta > drv_state.max_speed_delta_khz) {
+				/*
+				 * Enable the bcackup PLL if required
+				 * and switch to it.
+				 */
+				clk_enable(pll_clk[backup_s->pll].clk);
+				acpuclk_set_div(backup_s);
+			}
+		}
+
+		if (!(plls_enabled & (1 << tgt_s->pll))) {
+			rc = clk_enable(pll_clk[tgt_s->pll].clk);
+			if (rc < 0) {
+				pr_err("PLL%d enable failed (%d)\n",
+					tgt_s->pll, rc);
+				goto out;
+			}
+			plls_enabled |= 1 << tgt_s->pll;
+		}
+		acpuclk_set_div(tgt_s);
+		drv_state.current_speed = tgt_s;
+		/* Re-adjust lpj for the new clock speed. */
+		update_jiffies(cpu, cur_s->lpj);
+
+		/* Disable the backup PLL */
+		if ((delta > drv_state.max_speed_delta_khz)
+				|| (strt_s->pll == ACPU_PLL_4 &&
+					tgt_s->pll == ACPU_PLL_4))
+			clk_disable_unprepare(pll_clk[backup_s->pll].clk);
+
+		goto done;
+	}
+
 	while (cur_s != tgt_s) {
 		/*
 		 * Always jump to target freq if within max_speed_delta_khz,
@@ -648,17 +786,10 @@
 		acpuclk_set_div(cur_s);
 		drv_state.current_speed = cur_s;
 		/* Re-adjust lpj for the new clock speed. */
-#ifdef CONFIG_SMP
-		for_each_possible_cpu(cpu) {
-			per_cpu(cpu_data, cpu).loops_per_jiffy =
-							cur_s->lpj;
-		}
-#endif
-		/* Adjust the global one */
-		loops_per_jiffy = cur_s->lpj;
+		update_jiffies(cpu, cur_s->lpj);
 
 	}
-
+done:
 	/* Nothing else to do for SWFI. */
 	if (reason == SETRATE_SWFI)
 		goto out;
@@ -781,7 +912,7 @@
 static void __devinit select_freq_plan(void)
 {
 	unsigned long pll_mhz[ACPU_PLL_END];
-	struct pll_freq_tbl_map *t;
+	struct pll_freq_tbl_map *t = acpu_freq_tbl_list;
 	int i;
 
 	/* Get PLL clocks */
@@ -817,7 +948,7 @@
 		}
 	} else {
 		/* Select the right table to use. */
-		for (t = acpu_freq_tbl_list; t->tbl != 0; t++) {
+		for (; t->tbl != 0; t++) {
 			if (t->pll0_rate == pll_mhz[ACPU_PLL_0]
 				&& t->pll1_rate == pll_mhz[ACPU_PLL_1]
 				&& t->pll2_rate == pll_mhz[ACPU_PLL_2]
@@ -828,6 +959,25 @@
 		}
 	}
 
+	/*
+	 * When PLL4 can run max @ 1401.6MHz, we have to support
+	 * dynamic reprograming of PLL4.
+	 *
+	 * Also find the backup pll used during PLL4 reprogramming.
+	 * We are using PLL2@600MHz as backup PLL, since 800MHz jump
+	 * is fine.
+	 */
+	if (t->pll4_rate == 1401) {
+		dynamic_reprogram = 1;
+		for ( ; t->tbl->a11clk_khz; t->tbl++) {
+			if (t->tbl->pll == ACPU_PLL_2 &&
+					t->tbl->a11clk_src_div == 1) {
+				backup_s = t->tbl;
+				break;
+			}
+		}
+	}
+
 	if (acpu_freq_tbl == NULL) {
 		pr_crit("Unknown PLL configuration!\n");
 		BUG();
@@ -988,3 +1138,4 @@
 	return platform_driver_register(&acpuclk_7627_driver);
 }
 postcore_initcall(acpuclk_7627_init);
+
diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h
index e73a2af..841f717 100644
--- a/arch/arm/mach-msm/acpuclock.h
+++ b/arch/arm/mach-msm/acpuclock.h
@@ -90,4 +90,4 @@
  */
 void acpuclk_register(struct acpuclk_data *data);
 
-#endif
+#endif /*__ARCH_ARM_MACH_MSM_ACPUCLOCK_H*/
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 5aea0ed..b35e949 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -283,6 +283,9 @@
 static int bam_dmux_uplink_vote;
 static int bam_dmux_power_state;
 
+static void bam_dmux_log(const char *fmt, ...)
+					__printf(1, 2);
+
 
 #define DMUX_LOG_KERR(fmt...) \
 do { \
@@ -569,7 +572,8 @@
 				rx_hdr->ch_id);
 		handle_bam_mux_cmd_open(rx_hdr);
 		if (!(rx_hdr->reserved & ENABLE_DISCONNECT_ACK)) {
-			bam_dmux_log("%s: deactivating disconnect ack\n");
+			bam_dmux_log("%s: deactivating disconnect ack\n",
+								__func__);
 			disconnect_ack = 0;
 		}
 		dev_kfree_skb_any(rx_skb);
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index eb36a81e..122505e 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -225,6 +225,7 @@
 	.set_grp_async = NULL,
 	.idle_timeout = HZ/10,
 	.nap_allowed = true,
+	.strtstp_sleepwake = true,
 	.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE,
 #ifdef CONFIG_MSM_BUS_SCALING
 	.bus_scale_table = &grp3d_bus_scale_pdata,
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 3e07833..d3af1a7 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2253,7 +2253,6 @@
 	&msm_gss,
 	&apq8064_rtb_device,
 	&apq8064_cpu_idle_device,
-	&apq8064_msm_gov_device,
 	&apq8064_device_cache_erp,
 	&msm8960_device_ebi1_ch0_erp,
 	&msm8960_device_ebi1_ch1_erp,
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index 292c031..d975997 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -482,16 +482,16 @@
 static struct mipi_dsi_phy_ctrl dsi_novatek_cmd_mode_phy_db = {
 
 /* DSI_BIT_CLK at 500MHz, 2 lane, RGB888 */
-	{0x0F, 0x0a, 0x04, 0x00, 0x20},	/* regulator */
+	{0x09, 0x08, 0x05, 0x00, 0x20},	/* regulator */
 	/* timing   */
 	{0xab, 0x8a, 0x18, 0x00, 0x92, 0x97, 0x1b, 0x8c,
 	0x0c, 0x03, 0x04, 0xa0},
 	{0x5f, 0x00, 0x00, 0x10},	/* phy ctrl */
 	{0xff, 0x00, 0x06, 0x00},	/* strength */
 	/* pll control */
-	{0x40, 0xf9, 0x30, 0xda, 0x00, 0x40, 0x03, 0x62,
+	{0x0, 0xe, 0x30, 0xda, 0x00, 0x10, 0x0f, 0x61,
 	0x40, 0x07, 0x03,
-	0x00, 0x1a, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x01},
+	0x00, 0x1a, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x02},
 };
 
 static struct mipi_dsi_panel_platform_data novatek_pdata = {
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
index bd343c1..99a5a34 100644
--- a/arch/arm/mach-msm/board-8930-gpu.c
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -140,6 +140,7 @@
 	.set_grp_async = NULL,
 	.idle_timeout = HZ/12,
 	.nap_allowed = true,
+	.strtstp_sleepwake = true,
 	.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE,
 #ifdef CONFIG_MSM_BUS_SCALING
 	.bus_scale_table = &grp3d_bus_scale_pdata,
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 30b44bd..74aa837 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -59,7 +59,7 @@
 #endif
 #define MSM_ION_MM_FW_SIZE	0xa00000 /* (10MB) */
 #define MSM_ION_MM_SIZE		0x7800000 /* (120MB) */
-#define MSM_ION_QSECOM_SIZE	0x100000 /* (1MB) */
+#define MSM_ION_QSECOM_SIZE	0x600000 /* (6MB) */
 #define MSM_ION_MFC_SIZE	SZ_8K
 #define MSM_ION_AUDIO_SIZE	0x2B4000
 #define MSM_ION_HEAP_NUM	8
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 7948143..a5430e6 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -4765,8 +4765,8 @@
 	CLK_LOOKUP("core_clk", camss_phy1_csi1phytimer_clk.c, ""),
 	CLK_LOOKUP("core_clk", camss_phy2_csi2phytimer_clk.c, ""),
 	CLK_LOOKUP("iface_clk", camss_top_ahb_clk.c, ""),
-	CLK_LOOKUP("iface_clk", camss_vfe_cpp_ahb_clk.c, ""),
-	CLK_LOOKUP("core_clk", camss_vfe_cpp_clk.c, ""),
+	CLK_LOOKUP("iface_clk", camss_vfe_cpp_ahb_clk.c, "fda44000.qcom,iommu"),
+	CLK_LOOKUP("core_clk", camss_vfe_cpp_clk.c, "fda44000.qcom,iommu"),
 	CLK_LOOKUP("camss_vfe_vfe0_clk", camss_vfe_vfe0_clk.c, ""),
 	CLK_LOOKUP("camss_vfe_vfe1_clk", camss_vfe_vfe1_clk.c, ""),
 	CLK_LOOKUP("vfe0_clk_src", vfe0_clk_src.c, ""),
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index 2938135..d5831e2 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -319,6 +319,7 @@
 	{60, 1152000000},
 	{62, 1200000000},
 	{63, 1209600000},
+	{73, 1401600000},
 	{0, 0},
 };
 
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 8912e96..96984fb 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -236,12 +236,22 @@
 	.max_speed_delta_khz = 604800,
 };
 
+static struct acpuclk_pdata msm8625ab_acpuclk_pdata = {
+	.max_speed_delta_khz = 801600,
+};
+
 struct platform_device msm8625_device_acpuclk = {
 	.name		= "acpuclk-7627",
 	.id		= -1,
 	.dev.platform_data = &msm8625_acpuclk_pdata,
 };
 
+struct platform_device msm8625ab_device_acpuclk = {
+	.name		= "acpuclk-7627",
+	.id		= -1,
+	.dev.platform_data = &msm8625ab_acpuclk_pdata,
+};
+
 struct platform_device msm_device_smd = {
 	.name	= "msm_smd",
 	.id	= -1,
@@ -1623,6 +1633,7 @@
 enum {
 	MSM8625,
 	MSM8625A,
+	MSM8625AB,
 };
 
 static int __init msm8625_cpu_id(void)
@@ -1643,6 +1654,11 @@
 	case 0x781:
 		cpu = MSM8625A;
 		break;
+	case 0x775:
+	case 0x776:
+	case 0x782:
+		cpu = MSM8625AB;
+		break;
 	default:
 		pr_err("Invalid Raw ID\n");
 		return -ENODEV;
@@ -1665,10 +1681,11 @@
 			platform_device_register(&msm7x27aa_device_acpuclk);
 		else if (msm8625_cpu_id() == MSM8625A)
 			platform_device_register(&msm8625_device_acpuclk);
+		else if (msm8625_cpu_id() == MSM8625AB)
+			platform_device_register(&msm8625ab_device_acpuclk);
 	} else {
 		platform_device_register(&msm7x27a_device_acpuclk);
 	}
-
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 42e34e6..ab38346 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -424,6 +424,7 @@
 extern struct platform_device apq8064_device_acpuclk;
 extern struct platform_device msm8625_device_acpuclk;
 extern struct platform_device msm8627_device_acpuclk;
+extern struct platform_device msm8625ab_device_acpuclk;
 extern struct platform_device msm8x50_device_acpuclk;
 extern struct platform_device msm8x60_device_acpuclk;
 extern struct platform_device msm8930_device_acpuclk;
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 2c3d395..f7ba507 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -330,4 +330,16 @@
 #endif
 }
 
+static inline int cpu_is_msm8974(void)
+{
+#ifdef CONFIG_ARCH_MSM8974
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == MSM_CPU_8974;
+#else
+	return 0;
+#endif
+}
+
 #endif
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index e5be352..ebcbd26 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -46,7 +46,7 @@
 static bool msm_lpm_get_rpm_notif = true;
 
 /*Macros*/
-#define VDD_DIG_ACTIVE		(950000)
+#define VDD_DIG_ACTIVE		(5)
 #define VDD_MEM_ACTIVE		(1050000)
 #define MAX_RS_NAME		(16)
 #define MAX_RS_SIZE		(4)
@@ -264,7 +264,7 @@
 		return ret;
 	}
 
-	ret = msm_rpm_wait_for_ack(msg_id);
+	ret = msm_rpm_wait_for_ack_noirq(msg_id);
 	if (ret < 0) {
 		pr_err("%s: Couldn't get ACK from RPM for Msg %d Error %d",
 				__func__, msg_id, ret);
diff --git a/arch/arm/mach-msm/mpm-of.c b/arch/arm/mach-msm/mpm-of.c
index 1832301..cc60596 100644
--- a/arch/arm/mach-msm/mpm-of.c
+++ b/arch/arm/mach-msm/mpm-of.c
@@ -554,7 +554,7 @@
 		pr_info("%s(): request_irq failed errno: %d\n", __func__, ret);
 		goto failed_irq_get;
 	}
-	msm_mpm_initialized &= MSM_MPM_DEVICE_PROBED;
+	msm_mpm_initialized |= MSM_MPM_DEVICE_PROBED;
 
 	return 0;
 
@@ -701,9 +701,10 @@
 		}
 
 	}
-	msm_mpm_initialized &= MSM_MPM_IRQ_MAPPING_DONE;
+	msm_mpm_initialized |= MSM_MPM_IRQ_MAPPING_DONE;
 
 	return;
+
 failed_malloc:
 	for (i = 0; i < MSM_MPM_NR_MPM_IRQS; i++) {
 		mpm_of_map[i].chip->irq_mask = NULL;
diff --git a/arch/arm/mach-msm/pcie.c b/arch/arm/mach-msm/pcie.c
index f105356..d954b53 100644
--- a/arch/arm/mach-msm/pcie.c
+++ b/arch/arm/mach-msm/pcie.c
@@ -200,6 +200,16 @@
 static int msm_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
 			    int where, int size, u32 val)
 {
+	/*
+	 *Attempt to reset secondary bus is causing PCIE core to reset.
+	 *Disable secondary bus reset functionality.
+	 */
+	if ((bus->number == 0) && (where == PCI_BRIDGE_CONTROL) &&
+	    (val & PCI_BRIDGE_CTL_BUS_RESET)) {
+		pr_info("PCIE secondary bus reset not supported\n");
+		val &= ~PCI_BRIDGE_CTL_BUS_RESET;
+	}
+
 	return msm_pcie_oper_conf(bus, devfn, WR, where, size, &val);
 }
 
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 817c2dc..f3b5720 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -793,6 +793,10 @@
 	case 0x510F06F0:
 		return MSM_CPU_8064;
 
+	case 0x511F06F1:
+	case 0x512F06F0:
+		return MSM_CPU_8974;
+
 	default:
 		return MSM_CPU_UNKNOWN;
 	};
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index 9107231..94b1e61 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -856,8 +856,10 @@
 	case 0x08000000:	/* ldm or stm, or thumb-2 32bit instruction */
 		if (thumb2_32b)
 			handler = do_alignment_t32_to_handler(&instr, regs, &offset);
-		else
+		else {
 			handler = do_alignment_ldmstm;
+			offset.un = 0;
+		}
 		break;
 
 	default:
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index c0b82df..b70efe3 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -28,11 +28,6 @@
 	int signal_type;
 };
 
-#define DIAG_CON_APSS (0x0001)	/* Bit mask for APSS */
-#define DIAG_CON_MPSS (0x0002)	/* Bit mask for MPSS */
-#define DIAG_CON_LPASS (0x0004)	/* Bit mask for LPASS */
-#define DIAG_CON_WCNSS (0x0008)	/* Bit mask for WCNSS */
-
 enum {
 	DIAG_DCI_NO_ERROR = 1001,	/* No error */
 	DIAG_DCI_NO_REG,		/* Could not register */
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 2f356f0..95a85f2a 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -58,6 +58,11 @@
 #define DIAG_CTRL_MSG_F3_MASK	11
 #define CONTROL_CHAR	0x7E
 
+#define DIAG_CON_APSS (0x0001)	/* Bit mask for APSS */
+#define DIAG_CON_MPSS (0x0002)	/* Bit mask for MPSS */
+#define DIAG_CON_LPASS (0x0004)	/* Bit mask for LPASS */
+#define DIAG_CON_WCNSS (0x0008)	/* Bit mask for WCNSS */
+
 /* Maximum number of pkt reg supported at initialization*/
 extern unsigned int diag_max_reg;
 extern unsigned int diag_threshold_reg;
@@ -224,6 +229,9 @@
 	struct work_struct diag_qdsp_mask_update_work;
 	struct work_struct diag_wcnss_mask_update_work;
 	struct work_struct diag_read_smd_dci_work;
+	struct work_struct diag_clean_modem_reg_work;
+	struct work_struct diag_clean_lpass_reg_work;
+	struct work_struct diag_clean_wcnss_reg_work;
 	uint8_t *msg_masks;
 	uint8_t *log_masks;
 	int log_masks_length;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 547f42f..240a514 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1268,6 +1268,12 @@
 			diag_read_smd_wcnss_cntl_work_fn);
 		INIT_WORK(&(driver->diag_read_smd_dci_work),
 						 diag_read_smd_dci_work_fn);
+		INIT_WORK(&(driver->diag_clean_modem_reg_work),
+						 diag_clean_modem_reg_fn);
+		INIT_WORK(&(driver->diag_clean_lpass_reg_work),
+						 diag_clean_lpass_reg_fn);
+		INIT_WORK(&(driver->diag_clean_wcnss_reg_work),
+						 diag_clean_wcnss_reg_fn);
 		diag_debugfs_init();
 		diagfwd_init();
 		diagfwd_cntl_init();
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 384c1bf..b228276 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1735,8 +1735,8 @@
 static void diag_smd_notify(void *ctxt, unsigned event)
 {
 	if (event == SMD_EVENT_CLOSE) {
-		pr_info("diag: clean modem registration\n");
-		diag_clear_reg(MODEM_PROC);
+		queue_work(driver->diag_cntl_wq,
+			 &(driver->diag_clean_modem_reg_work));
 		driver->ch = 0;
 		return;
 	} else if (event == SMD_EVENT_OPEN) {
@@ -1750,8 +1750,8 @@
 static void diag_smd_qdsp_notify(void *ctxt, unsigned event)
 {
 	if (event == SMD_EVENT_CLOSE) {
-		pr_info("diag: clean lpass registration\n");
-		diag_clear_reg(QDSP_PROC);
+		queue_work(driver->diag_cntl_wq,
+			 &(driver->diag_clean_lpass_reg_work));
 		driver->chqdsp = 0;
 		return;
 	} else if (event == SMD_EVENT_OPEN) {
@@ -1765,8 +1765,8 @@
 static void diag_smd_wcnss_notify(void *ctxt, unsigned event)
 {
 	if (event == SMD_EVENT_CLOSE) {
-		pr_info("diag: clean wcnss registration\n");
-		diag_clear_reg(WCNSS_PROC);
+		queue_work(driver->diag_cntl_wq,
+			 &(driver->diag_clean_wcnss_reg_work));
 		driver->ch_wcnss = 0;
 		return;
 	} else if (event == SMD_EVENT_OPEN) {
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index de1a5b5..95abd21 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -20,9 +20,34 @@
 #ifdef CONFIG_DEBUG_FS
 #include <linux/debugfs.h>
 #endif
-
+/* tracks which peripheral is undergoing SSR */
+static uint16_t reg_dirty;
 #define HDR_SIZ 8
 
+void diag_clean_modem_reg_fn(struct work_struct *work)
+{
+	pr_debug("diag: clean modem registration\n");
+	reg_dirty |= DIAG_CON_MPSS;
+	diag_clear_reg(MODEM_PROC);
+	reg_dirty ^= DIAG_CON_MPSS;
+}
+
+void diag_clean_lpass_reg_fn(struct work_struct *work)
+{
+	pr_debug("diag: clean lpass registration\n");
+	reg_dirty |= DIAG_CON_LPASS;
+	diag_clear_reg(QDSP_PROC);
+	reg_dirty ^= DIAG_CON_LPASS;
+}
+
+void diag_clean_wcnss_reg_fn(struct work_struct *work)
+{
+	pr_debug("diag: clean wcnss registration\n");
+	reg_dirty |= DIAG_CON_WCNSS;
+	diag_clear_reg(WCNSS_PROC);
+	reg_dirty ^= DIAG_CON_WCNSS;
+}
+
 void diag_smd_cntl_notify(void *ctxt, unsigned event)
 {
 	int r1, r2;
@@ -105,6 +130,8 @@
 	struct bindpkt_params *temp;
 	void *buf = NULL;
 	smd_channel_t *smd_ch = NULL;
+	/* tracks which peripheral is sending registration */
+	uint16_t reg_mask = 0;
 
 	if (pkt_params == NULL) {
 		pr_alert("diag: Memory allocation failure\n");
@@ -114,12 +141,15 @@
 	if (proc_num == MODEM_PROC) {
 		buf = driver->buf_in_cntl;
 		smd_ch = driver->ch_cntl;
+		reg_mask = DIAG_CON_MPSS;
 	} else if (proc_num == QDSP_PROC) {
 		buf = driver->buf_in_qdsp_cntl;
 		smd_ch = driver->chqdsp_cntl;
+		reg_mask = DIAG_CON_LPASS;
 	} else if (proc_num == WCNSS_PROC) {
 		buf = driver->buf_in_wcnss_cntl;
 		smd_ch = driver->ch_wcnss_cntl;
+		reg_mask = DIAG_CON_WCNSS;
 	}
 
 	if (!smd_ch || !buf) {
@@ -180,8 +210,16 @@
 				temp -= pkt_params->count;
 				pkt_params->params = temp;
 				flag = 1;
-				diagchar_ioctl(NULL, DIAG_IOCTL_COMMAND_REG,
-						 (unsigned long)pkt_params);
+				/* peripheral undergoing SSR should not
+				 * record new registration
+				 */
+				if (!(reg_dirty & reg_mask))
+					diagchar_ioctl(NULL,
+					 DIAG_IOCTL_COMMAND_REG, (unsigned long)
+								pkt_params);
+				else
+					pr_err("diag: drop reg proc %d\n",
+								 proc_num);
 				kfree(temp);
 			}
 			buf = buf + HDR_SIZ + data_len;
@@ -275,6 +313,7 @@
 
 void diagfwd_cntl_init(void)
 {
+	reg_dirty = 0;
 	driver->polling_reg_flag = 0;
 	driver->diag_cntl_wq = create_singlethread_workqueue("diag_cntl_wq");
 	if (driver->buf_in_cntl == NULL) {
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index 743ddc1..59e5e6b 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -85,7 +85,9 @@
 void diag_smd_cntl_notify(void *ctxt, unsigned event);
 void diag_smd_qdsp_cntl_notify(void *ctxt, unsigned event);
 void diag_smd_wcnss_cntl_notify(void *ctxt, unsigned event);
-
+void diag_clean_modem_reg_fn(struct work_struct *);
+void diag_clean_lpass_reg_fn(struct work_struct *);
+void diag_clean_wcnss_reg_fn(struct work_struct *);
 void diag_debugfs_init(void);
 void diag_debugfs_cleanup(void);
 
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 14070a7..2f48999 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -948,6 +948,15 @@
 		kgsl_mmu_setstate(&device->mmu, adreno_context->pagetable,
 			KGSL_MEMSTORE_GLOBAL);
 
+	/* If iommu is used then we need to make sure that the iommu clocks
+	 * are on since there could be commands in pipeline that touch iommu */
+	if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) {
+		ret = kgsl_mmu_enable_clk(&device->mmu,
+			KGSL_IOMMU_CONTEXT_USER);
+		if (ret)
+			goto done;
+	}
+
 	/* Do not try the bad caommands if recovery has failed bad commands
 	 * once already */
 	if (!try_bad_commands)
@@ -973,6 +982,18 @@
 				"Device start failed in recovery\n");
 				goto done;
 			}
+			if (context)
+				kgsl_mmu_setstate(&device->mmu,
+						adreno_context->pagetable,
+						KGSL_MEMSTORE_GLOBAL);
+
+			if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) {
+				ret = kgsl_mmu_enable_clk(&device->mmu,
+						KGSL_IOMMU_CONTEXT_USER);
+				if (ret)
+					goto done;
+			}
+
 			ret = idle_ret;
 			KGSL_DRV_ERR(device,
 			"Bad context commands hung in recovery\n");
@@ -1008,6 +1029,9 @@
 		}
 	}
 done:
+	/* Turn off iommu clocks */
+	if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
+		kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false);
 	return ret;
 }
 
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 2a9f564..278be99 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -897,6 +897,9 @@
 {
 	struct rb_node *node = private->mem_rb.rb_node;
 
+	if (!kgsl_mmu_gpuaddr_in_range(gpuaddr))
+		return NULL;
+
 	while (node != NULL) {
 		struct kgsl_mem_entry *entry;
 
@@ -1112,6 +1115,19 @@
 			goto done;
 		}
 
+		/*
+		 * Put a reasonable upper limit on the number of IBs that can be
+		 * submitted
+		 */
+
+		if (param->numibs > 10000) {
+			KGSL_DRV_ERR(dev_priv->device,
+				"Too many IBs submitted. count: %d max 10000\n",
+				param->numibs);
+			result = -EINVAL;
+			goto done;
+		}
+
 		ibdesc = kzalloc(sizeof(struct kgsl_ibdesc) * param->numibs,
 					GFP_KERNEL);
 		if (!ibdesc) {
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index d06ce45..f8a2ea4 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -302,4 +302,10 @@
 		mmu->mmu_ops->mmu_disable_clk_on_ts(mmu, ts, ts_valid);
 }
 
+static inline int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr)
+{
+	return ((gpuaddr >= KGSL_PAGETABLE_BASE) &&
+		(gpuaddr < (KGSL_PAGETABLE_BASE + kgsl_mmu_get_ptsize())));
+}
+
 #endif /* __KGSL_MMU_H */
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index b050db2..53fec5b 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -868,6 +868,16 @@
 	  Provides interface for measuring the current on specific power rails
 	  through the channels on ADC1158 ADC
 
+config SENSORS_QPNP_ADC_VOLTAGE
+	tristate "Support for Qualcomm QPNP Voltage ADC"
+	depends on SPMI
+	help
+	  This is the VADC arbiter driver for Qualcomm QPNP ADC Chip.
+
+	  The driver supports reading the HKADC, XOADC through the ADC AMUX arbiter.
+	  The VADC includes support for the conversion sequencer. The driver supports
+	  reading the ADC through the AMUX channels for external pull-ups simultaneously.
+
 config SENSORS_PC87360
 	tristate "National Semiconductor PC87360 family"
 	depends on !PPC
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 228c4e9..2ff9454 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -130,6 +130,7 @@
 obj-$(CONFIG_SENSORS_MSM_ADC)	+= msm_adc.o m_adcproc.o
 obj-$(CONFIG_SENSORS_PM8XXX_ADC)	+= pm8xxx-adc.o pm8xxx-adc-scale.o
 obj-$(CONFIG_SENSORS_EPM_ADC)	+= epm_adc.o
+obj-$(CONFIG_SENSORS_QPNP_ADC_VOLTAGE)	+= qpnp-adc-voltage.o qpnp-adc-common.o
 
 obj-$(CONFIG_PMBUS)		+= pmbus/
 
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
new file mode 100644
index 0000000..c8fe798
--- /dev/null
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -0,0 +1,258 @@
+/* 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/kernel.h>
+#include <linux/of.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/hwmon.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/spmi.h>
+#include <linux/of_irq.h>
+#include <linux/interrupt.h>
+#include <linux/qpnp/qpnp-adc.h>
+#include <linux/platform_device.h>
+
+/* Min ADC code represets 0V */
+#define QPNP_VADC_MIN_ADC_CODE			0x6000
+/* Max ADC code represents full-scale range of 1.8V */
+#define QPNP_VADC_MAX_ADC_CODE			0xA800
+
+int32_t qpnp_adc_scale_default(int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	bool negative_rawfromoffset = 0, negative_offset = 0;
+	int64_t scale_voltage = 0;
+
+	if (!chan_properties || !chan_properties->offset_gain_numerator ||
+		!chan_properties->offset_gain_denominator || !adc_properties
+		|| !adc_chan_result)
+		return -EINVAL;
+
+	scale_voltage = (adc_code -
+		chan_properties->adc_graph[CALIB_ABSOLUTE].adc_gnd)
+		* chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
+	if (scale_voltage < 0) {
+		negative_offset = 1;
+		scale_voltage = -scale_voltage;
+	}
+	do_div(scale_voltage,
+		chan_properties->adc_graph[CALIB_ABSOLUTE].dy);
+	if (negative_offset)
+		scale_voltage = -scale_voltage;
+	scale_voltage += chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
+
+	if (scale_voltage < 0) {
+		if (adc_properties->bipolar) {
+			scale_voltage = -scale_voltage;
+			negative_rawfromoffset = 1;
+		} else {
+			scale_voltage = 0;
+		}
+	}
+
+	adc_chan_result->measurement = scale_voltage *
+				chan_properties->offset_gain_denominator;
+
+	/* do_div only perform positive integer division! */
+	do_div(adc_chan_result->measurement,
+				chan_properties->offset_gain_numerator);
+
+	if (negative_rawfromoffset)
+		adc_chan_result->measurement = -adc_chan_result->measurement;
+
+	/*
+	 * Note: adc_chan_result->measurement is in the unit of
+	 * adc_properties.adc_reference. For generic channel processing,
+	 * channel measurement is a scale/ratio relative to the adc
+	 * reference input
+	 */
+	adc_chan_result->physical = adc_chan_result->measurement;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_scale_default);
+
+int32_t qpnp_vadc_check_result(int32_t *data)
+{
+	if (*data < QPNP_VADC_MIN_ADC_CODE)
+		*data = QPNP_VADC_MIN_ADC_CODE;
+	else if (*data > QPNP_VADC_MAX_ADC_CODE)
+		*data = QPNP_VADC_MAX_ADC_CODE;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_vadc_check_result);
+
+int32_t qpnp_adc_get_devicetree_data(struct spmi_device *spmi,
+			struct qpnp_adc_drv *adc_qpnp)
+{
+	struct device_node *node = spmi->dev.of_node;
+	struct resource *res;
+	struct device_node *child;
+	struct qpnp_vadc_amux *adc_channel_list;
+	struct qpnp_adc_properties *adc_prop;
+	struct qpnp_vadc_amux_properties *amux_prop;
+	int count_adc_channel_list = 0, decimation, rc = 0;
+
+	if (!node)
+		return -EINVAL;
+
+	for_each_child_of_node(node, child)
+		count_adc_channel_list++;
+
+	if (!count_adc_channel_list) {
+		pr_err("No channel listing\n");
+		return -EINVAL;
+	}
+
+	adc_qpnp->spmi = spmi;
+
+	adc_prop = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_properties),
+					GFP_KERNEL);
+	if (!adc_prop) {
+		dev_err(&spmi->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+	adc_channel_list = devm_kzalloc(&spmi->dev,
+		(sizeof(struct qpnp_vadc_amux) * count_adc_channel_list),
+				GFP_KERNEL);
+	if (!adc_channel_list) {
+		dev_err(&spmi->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	amux_prop = devm_kzalloc(&spmi->dev,
+		sizeof(struct qpnp_vadc_amux_properties) +
+		sizeof(struct qpnp_vadc_chan_properties), GFP_KERNEL);
+	if (!amux_prop) {
+		dev_err(&spmi->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	for_each_child_of_node(node, child) {
+		int channel_num, scaling, post_scaling, hw_settle_time;
+		int fast_avg_setup, calib_type, i = 0, rc;
+		const char *calibration_param, *channel_name;
+
+		channel_name = of_get_property(child,
+				"label", NULL) ? : child->name;
+		if (!channel_name) {
+			pr_err("Invalid channel name\n");
+			return -EINVAL;
+		}
+
+		rc = of_property_read_u32(child, "qcom,channel-num",
+								&channel_num);
+		if (rc) {
+			pr_err("Invalid channel num\n");
+			return -EINVAL;
+		}
+		rc = of_property_read_u32(child, "qcom,decimation",
+								&decimation);
+		if (rc) {
+			pr_err("Invalid channel decimation property\n");
+			return -EINVAL;
+		}
+		rc = of_property_read_u32(child,
+				"qcom,pre-div-channel-scaling", &scaling);
+		if (rc) {
+			pr_err("Invalid channel scaling property\n");
+			return -EINVAL;
+		}
+		rc = of_property_read_u32(child,
+				"qcom,scale-function", &post_scaling);
+		if (rc) {
+			pr_err("Invalid channel post scaling property\n");
+			return -EINVAL;
+		}
+		rc = of_property_read_u32(child,
+				"qcom,hw-settle-time", &hw_settle_time);
+		if (rc) {
+			pr_err("Invalid channel hw settle time property\n");
+			return -EINVAL;
+		}
+		rc = of_property_read_u32(child,
+				"qcom,fast-avg-setup", &fast_avg_setup);
+		if (rc) {
+			pr_err("Invalid channel fast average setup\n");
+			return -EINVAL;
+		}
+		calibration_param = of_get_property(child,
+				"qcom,calibration-type", NULL);
+		if (!strncmp(calibration_param, "absolute", 8))
+			calib_type = CALIB_ABSOLUTE;
+		else if (!strncmp(calibration_param, "historical", 9))
+			calib_type = CALIB_RATIOMETRIC;
+		else {
+			pr_err("%s: Invalid calibration property\n", __func__);
+			return -EINVAL;
+		}
+		/* Individual channel properties */
+		adc_channel_list[i].name = (char *)channel_name;
+		adc_channel_list[i].channel_num = channel_num;
+		adc_channel_list[i].chan_path_prescaling = scaling;
+		adc_channel_list[i].adc_decimation = decimation;
+		adc_channel_list[i].adc_scale_fn = post_scaling;
+		adc_channel_list[i].hw_settle_time = hw_settle_time;
+		adc_channel_list[i].fast_avg_setup = fast_avg_setup;
+		i++;
+	}
+	adc_qpnp->adc_channels = adc_channel_list;
+	adc_qpnp->amux_prop = amux_prop;
+
+	/* Get the ADC VDD reference voltage and ADC bit resolution */
+	rc = of_property_read_u32(node, "qcom,adc-vdd-reference",
+			&adc_prop->adc_vdd_reference);
+	if (rc) {
+		pr_err("Invalid adc vdd reference property\n");
+		return -EINVAL;
+	}
+	rc = of_property_read_u32(node, "qcom,adc-bit-resolution",
+			&adc_prop->bitresolution);
+	if (rc) {
+		pr_err("Invalid adc bit resolution property\n");
+		return -EINVAL;
+	}
+	adc_qpnp->adc_prop = adc_prop;
+
+	/* Get the peripheral address */
+	res = spmi_get_resource(spmi, 0, IORESOURCE_MEM, 0);
+	if (!res) {
+		pr_err("No base address definition\n");
+		return -EINVAL;
+	}
+
+	adc_qpnp->slave = spmi->sid;
+	adc_qpnp->offset = res->start;
+
+	/* Register the ADC peripheral interrupt */
+	adc_qpnp->adc_irq = spmi_get_irq(spmi, 0, 0);
+	if (adc_qpnp->adc_irq < 0) {
+		pr_err("Invalid irq\n");
+		return -ENXIO;
+	}
+
+	mutex_init(&adc_qpnp->adc_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(qpnp_adc_get_devicetree_data);
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
new file mode 100644
index 0000000..8b2cb97
--- /dev/null
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -0,0 +1,784 @@
+/* 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/kernel.h>
+#include <linux/of.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/hwmon.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/spmi.h>
+#include <linux/of_irq.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/qpnp/qpnp-adc.h>
+#include <linux/platform_device.h>
+
+/* QPNP VADC register definition */
+#define QPNP_VADC_STATUS1					0x8
+#define QPNP_VADC_STATUS1_OP_MODE				4
+#define QPNP_VADC_STATUS1_MEAS_INTERVAL_EN_STS			BIT(2)
+#define QPNP_VADC_STATUS1_REQ_STS				BIT(1)
+#define QPNP_VADC_STATUS1_EOC					BIT(0)
+#define QPNP_VADC_STATUS2					0x9
+#define QPNP_VADC_STATUS2_CONV_SEQ_STATE				6
+#define QPNP_VADC_STATUS2_FIFO_NOT_EMPTY_FLAG			BIT(1)
+#define QPNP_VADC_STATUS2_CONV_SEQ_TIMEOUT_STS			BIT(0)
+#define QPNP_VADC_STATUS2_CONV_SEQ_STATE_SHIFT			4
+#define QPNP_VADC_CONV_TIMEOUT_ERR				2
+
+#define QPNP_VADC_INT_SET_TYPE					0x11
+#define QPNP_VADC_INT_POLARITY_HIGH				0x12
+#define QPNP_VADC_INT_POLARITY_LOW				0x13
+#define QPNP_VADC_INT_LATCHED_CLR				0x14
+#define QPNP_VADC_INT_EN_SET					0x15
+#define QPNP_VADC_INT_CLR					0x16
+#define QPNP_VADC_INT_LOW_THR_BIT				BIT(4)
+#define QPNP_VADC_INT_HIGH_THR_BIT				BIT(3)
+#define QPNP_VADC_INT_CONV_SEQ_TIMEOUT_BIT			BIT(2)
+#define QPNP_VADC_INT_FIFO_NOT_EMPTY_BIT			BIT(1)
+#define QPNP_VADC_INT_EOC_BIT					BIT(0)
+#define QPNP_VADC_INT_CLR_MASK					0x1f
+#define QPNP_VADC_MODE_CTL					0x40
+#define QPNP_VADC_OP_MODE_SHIFT					4
+#define QPNP_VADC_VREF_XO_THM_FORCE				BIT(2)
+#define QPNP_VADC_AMUX_TRIM_EN					BIT(1)
+#define QPNP_VADC_ADC_TRIM_EN					BIT(0)
+#define QPNP_VADC_EN_CTL1					0x46
+#define QPNP_VADC_ADC_EN					BIT(7)
+#define QPNP_VADC_ADC_CH_SEL_CTL					0x48
+#define QPNP_VADC_ADC_DIG_PARAM					0x50
+#define QPNP_VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT			3
+#define QPNP_VADC_HW_SETTLE_DELAY				0x51
+#define QPNP_VADC_CONV_REQ					0x52
+#define QPNP_VADC_CONV_REQ_SET					BIT(7)
+#define QPNP_VADC_CONV_SEQ_CTL					0x54
+#define QPNP_VADC_CONV_SEQ_HOLDOFF_SHIFT				4
+#define QPNP_VADC_CONV_SEQ_TRIG_CTL				0x55
+#define QPNP_VADC_CONV_SEQ_FALLING_EDGE				0x0
+#define QPNP_VADC_CONV_SEQ_RISING_EDGE				0x1
+#define QPNP_VADC_CONV_SEQ_EDGE_SHIFT				7
+#define QPNP_VADC_FAST_AVG_CTL					0x5a
+
+#define QPNP_VADC_M0_LOW_THR_LSB					0x5c
+#define QPNP_VADC_M0_LOW_THR_MSB					0x5d
+#define QPNP_VADC_M0_HIGH_THR_LSB				0x5e
+#define QPNP_VADC_M0_HIGH_THR_MSB				0x5f
+#define QPNP_VADC_M1_LOW_THR_LSB					0x69
+#define QPNP_VADC_M1_LOW_THR_MSB					0x6a
+#define QPNP_VADC_M1_HIGH_THR_LSB				0x6b
+#define QPNP_VADC_M1_HIGH_THR_MSB				0x6c
+
+#define QPNP_VADC_DATA0						0x60
+#define QPNP_VADC_DATA1						0x61
+#define QPNP_VADC_CONV_TIMEOUT_ERR				2
+#define QPNP_VADC_CONV_TIME_MIN					2000
+#define QPNP_VADC_CONV_TIME_MAX					2100
+
+#define QPNP_ADC_HWMON_NAME_LENGTH				16
+
+struct qpnp_vadc_drv {
+	struct qpnp_adc_drv		*adc;
+	struct dentry			*dent;
+	struct device			*vadc_hwmon;
+	bool				vadc_init_calib;
+	struct sensor_device_attribute		sens_attr[0];
+};
+
+struct qpnp_vadc_drv *qpnp_vadc;
+
+static struct qpnp_vadc_scale_fn vadc_scale_fn[] = {
+	[SCALE_DEFAULT] = {qpnp_adc_scale_default},
+};
+
+static int32_t qpnp_vadc_read_reg(int16_t reg, u8 *data)
+{
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+	int rc;
+
+	rc = spmi_ext_register_readl(vadc->adc->spmi->ctrl, vadc->adc->slave,
+		reg, data, 1);
+	if (rc < 0) {
+		pr_err("qpnp adc read reg %d failed with %d\n", reg, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int32_t qpnp_vadc_write_reg(int16_t reg, u8 data)
+{
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+	int rc;
+	u8 *buf;
+
+	buf = &data;
+
+	rc = spmi_ext_register_writel(vadc->adc->spmi->ctrl, vadc->adc->slave,
+		reg, buf, 1);
+	if (rc < 0) {
+		pr_err("qpnp adc write reg %d failed with %d\n", reg, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int32_t qpnp_vadc_configure_interrupt(void)
+{
+	int rc = 0;
+	u8 data = 0;
+
+	/* Configure interrupt as an Edge trigger */
+	rc = qpnp_vadc_write_reg(QPNP_VADC_INT_SET_TYPE,
+					QPNP_VADC_INT_CLR_MASK);
+	if (rc < 0) {
+		pr_err("%s Interrupt configure failed\n", __func__);
+		return rc;
+	}
+
+	/* Configure interrupt for rising edge trigger */
+	rc = qpnp_vadc_write_reg(QPNP_VADC_INT_POLARITY_HIGH,
+					QPNP_VADC_INT_CLR_MASK);
+	if (rc < 0) {
+		pr_err("%s Rising edge trigger configure failed\n", __func__);
+		return rc;
+	}
+
+	/* Disable low level interrupt triggering */
+	data = QPNP_VADC_INT_CLR_MASK;
+	rc = qpnp_vadc_write_reg(QPNP_VADC_INT_POLARITY_LOW,
+					(~data & QPNP_VADC_INT_CLR_MASK));
+	if (rc < 0) {
+		pr_err("%s Setting level low to disable failed\n", __func__);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int32_t qpnp_vadc_enable(bool state)
+{
+	int rc = 0;
+	u8 data = 0;
+
+	data = QPNP_VADC_ADC_EN;
+	if (state) {
+		rc = qpnp_vadc_write_reg(QPNP_VADC_EN_CTL1,
+					data);
+		if (rc < 0) {
+			pr_err("VADC enable failed\n");
+			return rc;
+		}
+	} else {
+		rc = qpnp_vadc_write_reg(QPNP_VADC_EN_CTL1,
+					(~data & QPNP_VADC_ADC_EN));
+		if (rc < 0) {
+			pr_err("VADC disable failed\n");
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+int32_t qpnp_vadc_configure(
+			struct qpnp_vadc_amux_properties *chan_prop)
+{
+	u8 decimation = 0, conv_sequence = 0, conv_sequence_trig = 0;
+	int rc = 0;
+
+	rc = qpnp_vadc_write_reg(QPNP_VADC_INT_EN_SET,
+				QPNP_VADC_INT_EOC_BIT);
+	if (rc < 0) {
+		pr_err("qpnp adc configure error for interrupt setup\n");
+		return rc;
+	}
+
+	rc = qpnp_vadc_write_reg(QPNP_VADC_MODE_CTL, chan_prop->mode_sel);
+	if (rc < 0) {
+		pr_err("qpnp adc configure error for mode selection\n");
+		return rc;
+	}
+
+	rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_CH_SEL_CTL,
+						chan_prop->amux_channel);
+	if (rc < 0) {
+		pr_err("qpnp adc configure error for channel selection\n");
+		return rc;
+	}
+
+	decimation |= chan_prop->decimation <<
+				QPNP_VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT;
+	rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_DIG_PARAM, decimation);
+	if (rc < 0) {
+		pr_err("qpnp adc configure error for digital parameter setup\n");
+		return rc;
+	}
+
+	rc = qpnp_vadc_write_reg(QPNP_VADC_HW_SETTLE_DELAY,
+						chan_prop->hw_settle_time);
+	if (rc < 0) {
+		pr_err("qpnp adc configure error for hw settling time setup\n");
+		return rc;
+	}
+
+	if (chan_prop->mode_sel == (ADC_OP_NORMAL_MODE <<
+					QPNP_VADC_OP_MODE_SHIFT)) {
+		rc = qpnp_vadc_write_reg(QPNP_VADC_FAST_AVG_CTL,
+						chan_prop->fast_avg_setup);
+		if (rc < 0) {
+			pr_err("qpnp adc fast averaging configure error\n");
+			return rc;
+		}
+	} else if (chan_prop->mode_sel == (ADC_OP_CONVERSION_SEQUENCER <<
+					QPNP_VADC_OP_MODE_SHIFT)) {
+		conv_sequence = ((ADC_SEQ_HOLD_100US <<
+				QPNP_VADC_CONV_SEQ_HOLDOFF_SHIFT) |
+				ADC_CONV_SEQ_TIMEOUT_5MS);
+		rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_CTL,
+							conv_sequence);
+		if (rc < 0) {
+			pr_err("qpnp adc conversion sequence error\n");
+			return rc;
+		}
+
+		conv_sequence_trig = ((QPNP_VADC_CONV_SEQ_RISING_EDGE <<
+				QPNP_VADC_CONV_SEQ_EDGE_SHIFT) |
+				chan_prop->trigger_channel);
+		rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_TRIG_CTL,
+							conv_sequence_trig);
+		if (rc < 0) {
+			pr_err("qpnp adc conversion trigger error\n");
+			return rc;
+		}
+	}
+
+	rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_REQ, QPNP_VADC_CONV_REQ_SET);
+	if (rc < 0) {
+		pr_err("qpnp adc request conversion failed\n");
+		return rc;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(qpnp_vadc_configure);
+
+static int32_t qpnp_vadc_read_conversion_result(int32_t *data)
+{
+	uint8_t rslt_lsb, rslt_msb;
+	int rc = 0;
+
+	rc = qpnp_vadc_read_reg(QPNP_VADC_DATA0, &rslt_lsb);
+	if (rc < 0) {
+		pr_err("qpnp adc result read failed for data0 with %d\n", rc);
+		return rc;
+	}
+
+	rc = qpnp_vadc_read_reg(QPNP_VADC_DATA1, &rslt_msb);
+	if (rc < 0) {
+		pr_err("qpnp adc result read failed for data1 with %d\n", rc);
+		return rc;
+	}
+
+	*data = (rslt_msb << 8) | rslt_lsb;
+
+	rc = qpnp_vadc_check_result(data);
+	if (rc < 0) {
+		pr_err("VADC data check failed\n");
+		return rc;
+	}
+
+	return 0;
+}
+
+static int32_t qpnp_vadc_read_status(int mode_sel)
+{
+	u8 status1, status2, status2_conv_seq_state;
+	u8 status_err = QPNP_VADC_CONV_TIMEOUT_ERR;
+	int rc;
+
+	switch (mode_sel) {
+	case (ADC_OP_CONVERSION_SEQUENCER << QPNP_VADC_OP_MODE_SHIFT):
+		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
+		if (rc) {
+			pr_err("qpnp_vadc read mask interrupt failed\n");
+			return rc;
+		}
+
+		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS2, &status2);
+		if (rc) {
+			pr_err("qpnp_vadc read mask interrupt failed\n");
+			return rc;
+		}
+
+		if (!(status2 & ~QPNP_VADC_STATUS2_CONV_SEQ_TIMEOUT_STS) &&
+			(status1 & (~QPNP_VADC_STATUS1_REQ_STS |
+						QPNP_VADC_STATUS1_EOC))) {
+			rc = status_err;
+			return rc;
+		}
+
+		status2_conv_seq_state = status2 >>
+					QPNP_VADC_STATUS2_CONV_SEQ_STATE_SHIFT;
+		if (status2_conv_seq_state != ADC_CONV_SEQ_IDLE) {
+			pr_err("qpnp vadc seq error with status %d\n",
+						status2);
+			rc = -EINVAL;
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static void qpnp_vadc_work(struct work_struct *work)
+{
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+	int rc;
+
+	rc = qpnp_vadc_write_reg(QPNP_VADC_INT_CLR, QPNP_VADC_INT_EOC_BIT);
+	if (rc)
+		pr_err("qpnp_vadc clear mask interrupt failed with %d\n", rc);
+
+	complete(&vadc->adc->adc_rslt_completion);
+
+	return;
+}
+DECLARE_WORK(trigger_completion_work, qpnp_vadc_work);
+
+static irqreturn_t qpnp_vadc_isr(int irq, void *dev_id)
+{
+	schedule_work(&trigger_completion_work);
+
+	return IRQ_HANDLED;
+}
+
+static uint32_t qpnp_vadc_calib_device(void)
+{
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+	struct qpnp_vadc_amux_properties conv;
+	int rc, calib_read_1, calib_read_2;
+	u8 status1 = 0;
+
+	conv.amux_channel = REF_125V;
+	conv.decimation = DECIMATION_TYPE2;
+	conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
+	conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
+	conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
+
+	rc = qpnp_vadc_configure(&conv);
+	if (rc) {
+		pr_err("qpnp_vadc configure failed with %d\n", rc);
+		goto calib_fail;
+	}
+
+	while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
+					QPNP_VADC_STATUS1_EOC)) {
+		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
+		if (rc < 0)
+			return rc;
+		usleep_range(QPNP_VADC_CONV_TIME_MIN,
+					QPNP_VADC_CONV_TIME_MAX);
+	}
+
+	rc = qpnp_vadc_read_conversion_result(&calib_read_1);
+	if (rc) {
+		pr_err("qpnp adc read adc failed with %d\n", rc);
+		goto calib_fail;
+	}
+
+	conv.amux_channel = REF_625MV;
+	conv.decimation = DECIMATION_TYPE2;
+	conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
+	conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
+	conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
+	rc = qpnp_vadc_configure(&conv);
+	if (rc) {
+		pr_err("qpnp adc configure failed with %d\n", rc);
+		goto calib_fail;
+	}
+
+	while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
+					QPNP_VADC_STATUS1_EOC)) {
+		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
+		if (rc < 0)
+			return rc;
+		usleep_range(QPNP_VADC_CONV_TIME_MIN,
+					QPNP_VADC_CONV_TIME_MAX);
+	}
+
+	rc = qpnp_vadc_read_conversion_result(&calib_read_1);
+	if (rc) {
+		pr_err("qpnp adc read adc failed with %d\n", rc);
+		goto calib_fail;
+	}
+
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy =
+					(calib_read_1 - calib_read_2);
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx
+						= QPNP_ADC_625_UV;
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_vref =
+					calib_read_1;
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd =
+					calib_read_2;
+	/* Ratiometric Calibration */
+	conv.amux_channel = VDD_VADC;
+	conv.decimation = DECIMATION_TYPE2;
+	conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
+	conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
+	conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
+	rc = qpnp_vadc_configure(&conv);
+	if (rc) {
+		pr_err("qpnp adc configure failed with %d\n", rc);
+		goto calib_fail;
+	}
+
+	while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
+					QPNP_VADC_STATUS1_EOC)) {
+		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
+		if (rc < 0)
+			return rc;
+		usleep_range(QPNP_VADC_CONV_TIME_MIN,
+					QPNP_VADC_CONV_TIME_MAX);
+	}
+
+	rc = qpnp_vadc_read_conversion_result(&calib_read_1);
+	if (rc) {
+		pr_err("qpnp adc read adc failed with %d\n", rc);
+		goto calib_fail;
+	}
+
+	conv.amux_channel = VDD_VADC;
+	conv.decimation = DECIMATION_TYPE2;
+	conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
+	conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
+	conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
+	rc = qpnp_vadc_configure(&conv);
+	if (rc) {
+		pr_err("qpnp adc configure failed with %d\n", rc);
+		goto calib_fail;
+	}
+
+	while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
+					QPNP_VADC_STATUS1_EOC)) {
+		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
+		if (rc < 0)
+			return rc;
+		usleep_range(QPNP_VADC_CONV_TIME_MIN,
+					QPNP_VADC_CONV_TIME_MAX);
+	}
+
+	rc = qpnp_vadc_read_conversion_result(&calib_read_1);
+	if (rc) {
+		pr_err("qpnp adc read adc failed with %d\n", rc);
+		goto calib_fail;
+	}
+
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy =
+					(calib_read_1 - calib_read_2);
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx =
+					vadc->adc->adc_prop->adc_vdd_reference;
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_vref =
+					calib_read_1;
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd =
+					calib_read_2;
+
+calib_fail:
+	return rc;
+}
+
+int32_t qpnp_vadc_conv_seq_request(enum qpnp_vadc_trigger trigger_channel,
+					enum qpnp_vadc_channels channel,
+					struct qpnp_vadc_result *result)
+{
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+	int rc, scale_type, amux_prescaling;
+
+	if (!vadc->vadc_init_calib) {
+		rc = qpnp_vadc_calib_device();
+		if (rc) {
+			pr_err("Calibration failed\n");
+			return rc;
+		} else
+			vadc->vadc_init_calib = true;
+	}
+
+	mutex_lock(&vadc->adc->adc_lock);
+
+	rc = qpnp_vadc_enable(true);
+	if (rc)
+		goto fail_unlock;
+
+	vadc->adc->amux_prop->amux_channel = channel;
+	vadc->adc->amux_prop->decimation =
+			vadc->adc->adc_channels[channel].adc_decimation;
+	vadc->adc->amux_prop->hw_settle_time =
+			vadc->adc->adc_channels[channel].hw_settle_time;
+	vadc->adc->amux_prop->fast_avg_setup =
+			vadc->adc->adc_channels[channel].fast_avg_setup;
+
+	if (trigger_channel < ADC_SEQ_NONE)
+		vadc->adc->amux_prop->mode_sel = (ADC_OP_CONVERSION_SEQUENCER
+						<< QPNP_VADC_OP_MODE_SHIFT);
+	else if (trigger_channel == ADC_SEQ_NONE)
+		vadc->adc->amux_prop->mode_sel = (ADC_OP_NORMAL_MODE
+						<< QPNP_VADC_OP_MODE_SHIFT);
+	else {
+		pr_err("Invalid trigger channel:%d\n", trigger_channel);
+		goto fail;
+	}
+
+	vadc->adc->amux_prop->trigger_channel = trigger_channel;
+
+	rc = qpnp_vadc_configure(vadc->adc->amux_prop);
+	if (rc) {
+		pr_info("qpnp vadc configure failed with %d\n", rc);
+		goto fail;
+	}
+
+	wait_for_completion(&vadc->adc->adc_rslt_completion);
+
+	if (trigger_channel < ADC_SEQ_NONE) {
+		rc = qpnp_vadc_read_status(vadc->adc->amux_prop->mode_sel);
+		if (rc)
+			pr_info("Conversion sequence timed out - %d\n", rc);
+	}
+
+	rc = qpnp_vadc_read_conversion_result(&result->adc_code);
+	if (rc) {
+		pr_info("qpnp vadc read adc code failed with %d\n", rc);
+		goto fail;
+	}
+
+	amux_prescaling = vadc->adc->adc_channels[channel].chan_path_prescaling;
+
+	vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
+		qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
+	vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
+		 qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
+
+	scale_type = vadc->adc->adc_channels[channel].adc_scale_fn;
+	if (scale_type >= SCALE_NONE) {
+		rc = -EBADF;
+		goto fail;
+	}
+
+	vadc_scale_fn[scale_type].chan(result->adc_code,
+		vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
+
+fail:
+	rc = qpnp_vadc_enable(false);
+	if (rc)
+		pr_err("Disable ADC failed during configuration\n");
+
+fail_unlock:
+	mutex_unlock(&vadc->adc->adc_lock);
+
+	return rc;
+}
+EXPORT_SYMBOL(qpnp_vadc_conv_seq_request);
+
+int32_t qpnp_vadc_read(enum qpnp_vadc_channels channel,
+				struct qpnp_vadc_result *result)
+{
+	return qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
+				channel, result);
+}
+EXPORT_SYMBOL_GPL(qpnp_vadc_read);
+
+static ssize_t qpnp_adc_show(struct device *dev,
+			struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct qpnp_vadc_result result;
+	int rc = -1;
+
+	rc = qpnp_vadc_read(attr->index, &result);
+
+	if (rc)
+		return 0;
+
+	return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
+		"Result:%lld Raw:%d\n", result.physical, result.adc_code);
+}
+
+static struct sensor_device_attribute qpnp_adc_attr =
+	SENSOR_ATTR(NULL, S_IRUGO, qpnp_adc_show, NULL, 0);
+
+static int32_t qpnp_vadc_init_hwmon(struct spmi_device *spmi)
+{
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+	struct device_node *child;
+	struct device_node *node = spmi->dev.of_node;
+	int rc = 0, i = 0, channel;
+
+	for_each_child_of_node(node, child) {
+		channel = vadc->adc->adc_channels[i].channel_num;
+		qpnp_adc_attr.index = vadc->adc->adc_channels[i].channel_num;
+		qpnp_adc_attr.dev_attr.attr.name =
+						vadc->adc->adc_channels[i].name;
+		sysfs_attr_init(&vadc->sens_attr[i].dev_attr.attr);
+		memcpy(&vadc->sens_attr[i], &qpnp_adc_attr,
+						sizeof(qpnp_adc_attr));
+		rc = device_create_file(&spmi->dev,
+				&vadc->sens_attr[i].dev_attr);
+		if (rc) {
+			dev_err(&spmi->dev,
+				"device_create_file failed for dev %s\n",
+				vadc->adc->adc_channels[i].name);
+			goto hwmon_err_sens;
+		}
+		i++;
+	}
+
+	return 0;
+hwmon_err_sens:
+	pr_info("Init HWMON failed for qpnp_adc with %d\n", rc);
+	return rc;
+}
+
+static int __devinit qpnp_vadc_probe(struct spmi_device *spmi)
+{
+	struct qpnp_vadc_drv *vadc;
+	struct qpnp_adc_drv *adc_qpnp;
+	struct device_node *node = spmi->dev.of_node;
+	struct device_node *child;
+	int rc, count_adc_channel_list = 0;
+
+	if (!node)
+		return -EINVAL;
+
+	if (qpnp_vadc) {
+		pr_err("VADC already in use\n");
+		return -EBUSY;
+	}
+
+	for_each_child_of_node(node, child)
+		count_adc_channel_list++;
+
+	if (!count_adc_channel_list) {
+		pr_err("No channel listing\n");
+		return -EINVAL;
+	}
+
+	vadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_vadc_drv) +
+		(sizeof(struct sensor_device_attribute) *
+				count_adc_channel_list), GFP_KERNEL);
+	if (!vadc) {
+		dev_err(&spmi->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
+			GFP_KERNEL);
+	if (!adc_qpnp) {
+		dev_err(&spmi->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	vadc->adc = adc_qpnp;
+
+	rc = qpnp_adc_get_devicetree_data(spmi, vadc->adc);
+	if (rc) {
+		dev_err(&spmi->dev, "failed to read device tree\n");
+		return rc;
+	}
+
+	rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq,
+				qpnp_vadc_isr, IRQF_TRIGGER_RISING,
+				"qpnp_vadc_interrupt", vadc);
+	if (rc) {
+		dev_err(&spmi->dev,
+			"failed to request adc irq with error %d\n", rc);
+		return rc;
+	}
+
+	qpnp_vadc = vadc;
+	dev_set_drvdata(&spmi->dev, vadc);
+	rc = qpnp_vadc_init_hwmon(spmi);
+	if (rc) {
+		dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
+		goto fail_free_irq;
+	}
+	vadc->vadc_hwmon = hwmon_device_register(&vadc->adc->spmi->dev);
+	vadc->vadc_init_calib = false;
+
+	rc = qpnp_vadc_configure_interrupt();
+	if (rc) {
+		dev_err(&spmi->dev, "failed to configure interrupt");
+		goto fail_free_irq;
+	}
+
+	return 0;
+
+fail_free_irq:
+	free_irq(vadc->adc->adc_irq, vadc);
+
+	return rc;
+}
+
+static int __devexit qpnp_vadc_remove(struct spmi_device *spmi)
+{
+	struct qpnp_vadc_drv *vadc = dev_get_drvdata(&spmi->dev);
+	struct device_node *node = spmi->dev.of_node;
+	struct device_node *child;
+	int i = 0;
+
+	for_each_child_of_node(node, child) {
+		device_remove_file(&spmi->dev,
+			&vadc->sens_attr[i].dev_attr);
+		i++;
+	}
+	free_irq(vadc->adc->adc_irq, vadc);
+	dev_set_drvdata(&spmi->dev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id qpnp_vadc_match_table[] = {
+	{	.compatible = "qcom,qpnp-vadc",
+	},
+	{}
+};
+
+static struct spmi_driver qpnp_vadc_driver = {
+	.driver		= {
+		.name	= "qcom,qpnp-vadc",
+		.of_match_table = qpnp_vadc_match_table,
+	},
+	.probe		= qpnp_vadc_probe,
+	.remove		= qpnp_vadc_remove,
+};
+
+static int __init qpnp_vadc_init(void)
+{
+	return spmi_driver_register(&qpnp_vadc_driver);
+}
+module_init(qpnp_vadc_init);
+
+static void __exit qpnp_vadc_exit(void)
+{
+	spmi_driver_unregister(&qpnp_vadc_driver);
+}
+module_exit(qpnp_vadc_exit);
+
+MODULE_DESCRIPTION("QPNP PMIC Voltage ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iommu/msm_iommu-v2.c b/drivers/iommu/msm_iommu-v2.c
index 26e967d..48edf96 100644
--- a/drivers/iommu/msm_iommu-v2.c
+++ b/drivers/iommu/msm_iommu-v2.c
@@ -67,6 +67,17 @@
 	clk_disable_unprepare(drvdata->pclk);
 }
 
+static void __sync_tlb(void __iomem *base, int ctx)
+{
+	SET_TLBSYNC(base, ctx, 0);
+
+	/* No barrier needed due to register proximity */
+	while (GET_CB_TLBSTATUS_SACTIVE(base, ctx))
+		cpu_relax();
+
+	/* No barrier needed due to read dependency */
+}
+
 static int __flush_iotlb_va(struct iommu_domain *domain, unsigned int va)
 {
 	struct msm_priv *priv = domain->priv;
@@ -92,6 +103,7 @@
 		SET_TLBIVA(iommu_drvdata->base, ctx_drvdata->num,
 			   asid | (va & CB_TLBIVA_VA));
 		mb();
+		__sync_tlb(iommu_drvdata->base, ctx_drvdata->num);
 		__disable_clocks(iommu_drvdata);
 	}
 fail:
@@ -121,6 +133,7 @@
 
 		SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num, asid);
 		mb();
+		__sync_tlb(iommu_drvdata->base, ctx_drvdata->num);
 		__disable_clocks(iommu_drvdata);
 	}
 
diff --git a/drivers/iommu/msm_iommu_dev-v2.c b/drivers/iommu/msm_iommu_dev-v2.c
index d3a088a..14ed5d9 100644
--- a/drivers/iommu/msm_iommu_dev-v2.c
+++ b/drivers/iommu/msm_iommu_dev-v2.c
@@ -192,7 +192,7 @@
 	 */
 	ctx_drvdata->num = ((r->start - rp.start) >> CTX_SHIFT) - 8;
 
-	if (of_property_read_string(pdev->dev.of_node, "qcom,iommu-ctx-name",
+	if (of_property_read_string(pdev->dev.of_node, "label",
 					&ctx_drvdata->name))
 		ctx_drvdata->name = dev_name(&pdev->dev);
 
@@ -232,7 +232,7 @@
 	ret = msm_iommu_ctx_parse_dt(pdev, ctx_drvdata);
 	if (!ret)
 		dev_info(&pdev->dev, "context %s using bank %d\n",
-				dev_name(&pdev->dev), ctx_drvdata->num);
+			 ctx_drvdata->name, ctx_drvdata->num);
 
 	return ret;
 }
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 67e7c02..9ddde15 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -424,10 +424,12 @@
 		stats.buf_idx = isp_stats->buf_idx;
 		switch (isp_stats->id) {
 		case MSG_ID_STATS_AEC:
+		case MSG_ID_STATS_BG:
 			stats.aec.buff = stats.buffer;
 			stats.aec.fd = stats.fd;
 			break;
 		case MSG_ID_STATS_AF:
+		case MSG_ID_STATS_BF:
 			stats.af.buff = stats.buffer;
 			stats.af.fd = stats.fd;
 			break;
@@ -447,6 +449,10 @@
 			stats.cs.buff = stats.buffer;
 			stats.cs.fd = stats.fd;
 			break;
+		case MSG_ID_STATS_BHIST:
+			stats.skin.buff = stats.buffer;
+			stats.skin.fd = stats.fd;
+			break;
 		case MSG_ID_STATS_AWB_AEC:
 			break;
 		default:
@@ -537,6 +543,9 @@
 	memset(&axi_data, 0, sizeof(axi_data));
 	CDBG("%s: cmd_type %d\n", __func__, cfgcmd.cmd_type);
 	switch (cfgcmd.cmd_type) {
+	case CMD_STATS_BG_ENABLE:
+	case CMD_STATS_BF_ENABLE:
+	case CMD_STATS_BHIST_ENABLE:
 	case CMD_STATS_AF_ENABLE:
 	case CMD_STATS_AEC_ENABLE:
 	case CMD_STATS_AWB_ENABLE:
@@ -629,6 +638,12 @@
 			cfgcmd.cmd_type = CMD_STATS_CS_BUF_RELEASE;
 		else if (buf.type == STAT_AEAW)
 			cfgcmd.cmd_type = CMD_STATS_BUF_RELEASE;
+		else if (buf.type == STAT_BG)
+			cfgcmd.cmd_type = CMD_STATS_BG_BUF_RELEASE;
+		else if (buf.type == STAT_BF)
+			cfgcmd.cmd_type = CMD_STATS_BF_BUF_RELEASE;
+		else if (buf.type == STAT_BHIST)
+			cfgcmd.cmd_type = CMD_STATS_BHIST_BUF_RELEASE;
 
 		else {
 			pr_err("%s: invalid buf type %d\n",
@@ -673,7 +688,6 @@
 	}
 	case MSM_CAM_IOCTL_STATS_ENQUEUEBUF: {
 		struct msm_stats_buf_info buf_info;
-
 		if (copy_from_user(&buf_info, arg,
 			sizeof(struct msm_stats_buf_info))) {
 			ERR_COPY_FROM_USER();
@@ -687,18 +701,30 @@
 	}
 	case MSM_CAM_IOCTL_STATS_FLUSH_BUFQ: {
 		struct msm_stats_flush_bufq bufq_info;
-
 		if (copy_from_user(&bufq_info, arg,
 			sizeof(struct msm_stats_flush_bufq))) {
 			ERR_COPY_FROM_USER();
 			return -EFAULT;
-	}
+		}
 	cfgcmd.cmd_type = VFE_CMD_STATS_FLUSH_BUFQ;
 	cfgcmd.value = (void *)&bufq_info;
 	cfgcmd.length = sizeof(struct msm_stats_flush_bufq);
 	rc = msm_isp_subdev_ioctl(sd, &cfgcmd, NULL);
 	break;
 	}
+	case MSM_CAM_IOCTL_STATS_UNREG_BUF: {
+		struct msm_stats_reqbuf reqbuf;
+		if (copy_from_user(&reqbuf, arg,
+			sizeof(struct msm_stats_reqbuf))) {
+			ERR_COPY_FROM_USER();
+			return -EFAULT;
+		}
+	cfgcmd.cmd_type = VFE_CMD_STATS_UNREGBUF;
+	cfgcmd.value = (void *)&reqbuf;
+	cfgcmd.length = sizeof(struct msm_stats_reqbuf);
+	rc = msm_isp_subdev_ioctl(sd, &cfgcmd, (void *)mctl->client);
+	break;
+	}
 	default:
 		rc = -1;
 	break;
@@ -734,6 +760,7 @@
 	case MSM_CAM_IOCTL_STATS_REQBUF:
 	case MSM_CAM_IOCTL_STATS_ENQUEUEBUF:
 	case MSM_CAM_IOCTL_STATS_FLUSH_BUFQ:
+	case MSM_CAM_IOCTL_STATS_UNREG_BUF:
 		rc = msm_vfe_stats_buf_ioctl(sd, cmd, pmctl, argp);
 		break;
 
diff --git a/drivers/media/video/msm/msm_mem.c b/drivers/media/video/msm/msm_mem.c
index 5d412db..e2e9d1b 100644
--- a/drivers/media/video/msm/msm_mem.c
+++ b/drivers/media/video/msm/msm_mem.c
@@ -208,6 +208,9 @@
 	case MSM_PMEM_IHIST:
 	case MSM_PMEM_SKIN:
 	case MSM_PMEM_AEC_AWB:
+	case MSM_PMEM_BAYER_GRID:
+	case MSM_PMEM_BAYER_FOCUS:
+	case MSM_PMEM_BAYER_HIST:
 		rc = msm_pmem_table_add(ptype, pinfo, client);
 		break;
 
@@ -235,6 +238,9 @@
 	case MSM_PMEM_IHIST:
 	case MSM_PMEM_SKIN:
 	case MSM_PMEM_AEC_AWB:
+	case MSM_PMEM_BAYER_GRID:
+	case MSM_PMEM_BAYER_FOCUS:
+	case MSM_PMEM_BAYER_HIST:
 		hlist_for_each_entry_safe(region, node, n,
 				ptype, list) {
 
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.c b/drivers/media/video/msm/msm_vfe31_v4l2.c
index 18168ee..a22a09f 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.c
@@ -417,6 +417,25 @@
 	return 0L;
 }
 
+static unsigned long vfe31_stats_unregbuf(
+	struct msm_stats_reqbuf *req_buf)
+{
+	int i = 0, rc = 0;
+
+	for (i = 0; i < req_buf->num_buf; i++) {
+		rc = vfe31_ctrl->stats_ops.buf_unprepare(
+			vfe31_ctrl->stats_ops.stats_ctrl,
+			req_buf->stats_type, i,
+			vfe31_ctrl->stats_ops.client);
+		if (rc < 0) {
+			pr_err("%s: unreg stats buf (type = %d) err = %d",
+				__func__, req_buf->stats_type, rc);
+		return rc;
+		}
+	}
+	return 0L;
+}
+
 static int vfe_stats_awb_buf_init(
 	struct vfe_cmd_stats_buf *in)
 {
@@ -3334,6 +3353,22 @@
 				vfe31_ctrl->stats_ops.client);
 	}
 	break;
+	case VFE_CMD_STATS_UNREGBUF:
+	{
+		struct msm_stats_reqbuf *req_buf = NULL;
+		req_buf = (struct msm_stats_reqbuf *)cmd->value;
+		if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats reqbuf input size = %d,\n"
+				"struct size = %d, mitch match\n",
+				 __func__, cmd->length,
+				sizeof(struct msm_stats_reqbuf));
+			rc = -EINVAL ;
+			goto end;
+		}
+		rc = vfe31_stats_unregbuf(req_buf);
+	}
+	break;
 	default:
 		rc = -1;
 		pr_err("%s: cmd_type %d not supported", __func__,
@@ -3583,6 +3618,7 @@
 	case VFE_CMD_STATS_REQBUF:
 	case VFE_CMD_STATS_ENQUEUEBUF:
 	case VFE_CMD_STATS_FLUSH_BUFQ:
+	case VFE_CMD_STATS_UNREGBUF:
 		/* for easy porting put in one envelope */
 		rc = vfe_stats_bufq_sub_ioctl(cmd, vfe_params->data);
 		return rc;
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index aa2b19d..c4bdad2 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -216,6 +216,27 @@
 		{VFE_CMD_GET_RGB_G_TABLE},
 		{VFE_CMD_GET_LA_TABLE},
 		{VFE_CMD_DEMOSAICV3_UPDATE},
+		{VFE_CMD_ACTIVE_REGION_CFG},
+/*130*/ {VFE_CMD_COLOR_PROCESSING_CONFIG},
+		{VFE_CMD_STATS_WB_AEC_CONFIG},
+		{VFE_CMD_STATS_WB_AEC_UPDATE},
+		{VFE_CMD_Y_GAMMA_CONFIG},
+		{VFE_CMD_SCALE_OUTPUT1_CONFIG},
+/*135*/ {VFE_CMD_SCALE_OUTPUT2_CONFIG},
+		{VFE_CMD_CAPTURE_RAW},
+		{VFE_CMD_STOP_LIVESHOT},
+		{VFE_CMD_RECONFIG_VFE},
+		{VFE_CMD_STATS_REQBUF},
+/*140*/	{VFE_CMD_STATS_ENQUEUEBUF},
+		{VFE_CMD_STATS_FLUSH_BUFQ},
+		{VFE_CMD_STATS_UNREGBUF},
+		{VFE_CMD_STATS_BG_START, V32_STATS_BG_LEN, V32_STATS_BG_OFF},
+		{VFE_CMD_STATS_BG_STOP},
+		{VFE_CMD_STATS_BF_START, V32_STATS_BF_LEN, V32_STATS_BF_OFF},
+/*145*/ {VFE_CMD_STATS_BF_STOP},
+		{VFE_CMD_STATS_BHIST_START, V32_STATS_BHIST_LEN,
+			V32_STATS_BHIST_OFF},
+/*147*/	{VFE_CMD_STATS_BHIST_STOP},
 };
 
 uint32_t vfe32_AXI_WM_CFG[] = {
@@ -358,8 +379,24 @@
 	"GET_RGB_G_TABLE",
 	"GET_LA_TABLE",
 	"DEMOSAICV3_UPDATE",
+	"STATS_BG_START",
+	"STATS_BG_STOP",
+	"STATS_BF_START",
+	"STATS_BF_STOP",
+	"STATS_BHIST_START",
+	"STATS_BHIST_STOP",
 };
 
+uint8_t vfe32_use_bayer_stats(struct vfe32_ctrl_type *vfe32_ctrl)
+{
+	if (vfe32_ctrl->ver_num.main >= 4) {
+		/* VFE 4 or above uses bayer stats */
+		return TRUE;
+	} else {
+		return FALSE;
+	}
+}
+
 static void vfe32_stop(struct vfe32_ctrl_type *vfe32_ctrl)
 {
 	unsigned long flags;
@@ -375,7 +412,7 @@
 	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
 		vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
 	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
-			vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+		vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
 
 	/* clear all pending interrupts*/
 	msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
@@ -530,13 +567,16 @@
 	/* this is unsigned 32 bit integer. */
 	vfe32_ctrl->share_ctrl->vfeFrameId = 0;
 	/* Stats control variables. */
-	memset(&(vfe32_ctrl->afStatsControl), 0,
+	memset(&(vfe32_ctrl->afbfStatsControl), 0,
 		sizeof(struct vfe_stats_control));
 
 	memset(&(vfe32_ctrl->awbStatsControl), 0,
 		sizeof(struct vfe_stats_control));
 
-	memset(&(vfe32_ctrl->aecStatsControl), 0,
+	memset(&(vfe32_ctrl->aecbgStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe32_ctrl->bhistStatsControl), 0,
 		sizeof(struct vfe_stats_control));
 
 	memset(&(vfe32_ctrl->ihistStatsControl), 0,
@@ -553,6 +593,62 @@
 	vfe32_ctrl->snapshot_frame_cnt = 0;
 }
 
+static void vfe32_program_dmi_cfg(
+	enum VFE32_DMI_RAM_SEL bankSel,
+	struct vfe32_ctrl_type *vfe32_ctrl)
+{
+	/* set bit 8 for auto increment. */
+	uint32_t value = VFE_DMI_CFG_DEFAULT;
+	value += (uint32_t)bankSel;
+	CDBG("%s: banksel = %d\n", __func__, bankSel);
+
+	msm_camera_io_w(value, vfe32_ctrl->share_ctrl->vfebase +
+		VFE_DMI_CFG);
+	/* by default, always starts with offset 0.*/
+	msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
+		VFE_DMI_ADDR);
+}
+
+static void vfe32_reset_dmi_tables(
+	struct vfe32_ctrl_type *vfe32_ctrl)
+{
+	int i = 0;
+
+	/* Reset Histogram LUTs */
+	CDBG("Reset Bayer histogram LUT : 0\n");
+	vfe32_program_dmi_cfg(STATS_BHIST_RAM0, vfe32_ctrl);
+	/* Loop for configuring LUT */
+	for (i = 0; i < 256; i++) {
+		msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
+			VFE_DMI_DATA_HI);
+		msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
+			VFE_DMI_DATA_LO);
+	}
+	vfe32_program_dmi_cfg(NO_MEM_SELECTED, vfe32_ctrl);
+
+	CDBG("Reset Bayer Histogram LUT: 1\n");
+	vfe32_program_dmi_cfg(STATS_BHIST_RAM1, vfe32_ctrl);
+	/* Loop for configuring LUT */
+	for (i = 0; i < 256; i++) {
+		msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
+			VFE_DMI_DATA_HI);
+		msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
+			VFE_DMI_DATA_LO);
+	}
+	vfe32_program_dmi_cfg(NO_MEM_SELECTED, vfe32_ctrl);
+
+	CDBG("Reset IHistogram LUT\n");
+	vfe32_program_dmi_cfg(STATS_IHIST_RAM, vfe32_ctrl);
+	/* Loop for configuring LUT */
+	for (i = 0; i < 256; i++) {
+		msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
+			VFE_DMI_DATA_HI);
+		msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
+			VFE_DMI_DATA_LO);
+	}
+	vfe32_program_dmi_cfg(NO_MEM_SELECTED, vfe32_ctrl);
+}
+
 static void vfe32_reset(struct vfe32_ctrl_type *vfe32_ctrl)
 {
 	vfe32_reset_internal_variables(vfe32_ctrl);
@@ -572,7 +668,8 @@
 
 	/* Ensure the write order while writing
 	to the command register using the barrier */
-	msm_camera_io_w_mb(1, vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
+	msm_camera_io_w_mb(1, vfe32_ctrl->share_ctrl->vfebase +
+		VFE_IRQ_CMD);
 
 	/* enable reset_ack interrupt.  */
 	msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
@@ -677,6 +774,26 @@
 	return 0L;
 }
 
+
+static unsigned long vfe32_stats_unregbuf(
+	struct vfe32_ctrl_type *vfe32_ctrl,
+	struct msm_stats_reqbuf *req_buf)
+{
+	int i = 0, rc = 0;
+
+	for (i = 0; i < req_buf->num_buf; i++) {
+		rc = vfe32_ctrl->stats_ops.buf_unprepare(
+			vfe32_ctrl->stats_ops.stats_ctrl,
+			req_buf->stats_type, i,
+			vfe32_ctrl->stats_ops.client);
+		if (rc < 0) {
+			pr_err("%s: unreg stats buf (type = %d) err = %d",
+				__func__, req_buf->stats_type, rc);
+		return rc;
+		}
+	}
+	return 0L;
+}
 static int vfe_stats_awb_buf_init(
 	struct vfe32_ctrl_type *vfe32_ctrl,
 	struct vfe_cmd_stats_buf *in)
@@ -708,14 +825,18 @@
 	return 0;
 }
 
-static int vfe_stats_aec_buf_init(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
+static uint32_t vfe_stats_aec_bg_buf_init(
+	struct vfe32_ctrl_type *vfe32_ctrl)
 {
 	uint32_t addr;
 	unsigned long flags;
+	uint32_t stats_type;
 
+	stats_type =
+		(!vfe32_use_bayer_stats(vfe32_ctrl)) ? MSM_STATS_TYPE_AEC
+			: MSM_STATS_TYPE_BG;
 	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
-	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AEC);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, stats_type);
 	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
 	if (!addr) {
 		pr_err("%s: dq aec ping buf from free buf queue",
@@ -724,9 +845,9 @@
 	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
-		VFE_BUS_STATS_AEC_WR_PING_ADDR);
+		VFE_BUS_STATS_AEC_BG_WR_PING_ADDR);
 	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
-	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AEC);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, stats_type);
 	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
 	if (!addr) {
 		pr_err("%s: dq aec pong buf from free buf queue",
@@ -735,26 +856,31 @@
 	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
-		VFE_BUS_STATS_AEC_WR_PONG_ADDR);
+		VFE_BUS_STATS_AEC_BG_WR_PONG_ADDR);
 	return 0;
 }
 
-static int vfe_stats_af_buf_init(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
+static int vfe_stats_af_bf_buf_init(
+	struct vfe32_ctrl_type *vfe32_ctrl)
 {
 	uint32_t addr;
 	unsigned long flags;
 	int rc = 0;
 
+	uint32_t stats_type;
+	stats_type =
+		(!vfe32_use_bayer_stats(vfe32_ctrl)) ? MSM_STATS_TYPE_AF
+			: MSM_STATS_TYPE_BF;
+
 	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
-	rc = vfe32_stats_flush_enqueue(vfe32_ctrl, MSM_STATS_TYPE_AF);
+	rc = vfe32_stats_flush_enqueue(vfe32_ctrl, stats_type);
 	if (rc < 0) {
 		pr_err("%s: dq stats buf err = %d",
 			   __func__, rc);
 		spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
 		return -EINVAL;
 	}
-	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AF);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, stats_type);
 	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
 	if (!addr) {
 		pr_err("%s: dq af ping buf from free buf queue", __func__);
@@ -762,9 +888,9 @@
 	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
-		VFE_BUS_STATS_AF_WR_PING_ADDR);
+		VFE_BUS_STATS_AF_BF_WR_PING_ADDR);
 	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
-	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AF);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, stats_type);
 	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
 	if (!addr) {
 		pr_err("%s: dq af pong buf from free buf queue", __func__);
@@ -772,14 +898,44 @@
 	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
-		VFE_BUS_STATS_AF_WR_PONG_ADDR);
+		VFE_BUS_STATS_AF_BF_WR_PONG_ADDR);
+	return 0;
+}
+
+static uint32_t vfe_stats_bhist_buf_init(
+	struct vfe32_ctrl_type *vfe32_ctrl)
+{
+	uint32_t addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_BHIST);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq ihist ping buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe32_ctrl->share_ctrl->vfebase +
+		VFE_BUS_STATS_SKIN_BHIST_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_BHIST);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq ihist pong buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe32_ctrl->share_ctrl->vfebase +
+		VFE_BUS_STATS_SKIN_BHIST_WR_PONG_ADDR);
 
 	return 0;
 }
 
 static int vfe_stats_ihist_buf_init(
-	struct vfe32_ctrl_type *vfe32_ctrl,
-	struct vfe_cmd_stats_buf *in)
+	struct vfe32_ctrl_type *vfe32_ctrl)
 {
 	uint32_t addr;
 	unsigned long flags;
@@ -811,8 +967,7 @@
 }
 
 static int vfe_stats_rs_buf_init(
-	struct vfe32_ctrl_type *vfe32_ctrl,
-	struct vfe_cmd_stats_buf *in)
+	struct vfe32_ctrl_type *vfe32_ctrl)
 {
 	uint32_t addr;
 	unsigned long flags;
@@ -841,8 +996,7 @@
 }
 
 static int vfe_stats_cs_buf_init(
-	struct vfe32_ctrl_type *vfe32_ctrl,
-	struct vfe_cmd_stats_buf *in)
+	struct vfe32_ctrl_type *vfe32_ctrl)
 {
 	uint32_t addr;
 	unsigned long flags;
@@ -918,6 +1072,9 @@
 		msm_camera_io_w_mb(1, vfe32_ctrl->share_ctrl->vfebase +
 			VFE_CAMIF_COMMAND);
 	}
+	msm_camera_io_dump(vfe32_ctrl->share_ctrl->vfebase,
+		vfe32_ctrl->share_ctrl->register_total * 4);
+
 	/* Ensure the write order while writing
 	to the command register using the barrier */
 	atomic_set(&vfe32_ctrl->share_ctrl->vstate, 1);
@@ -1372,19 +1529,7 @@
 		vfe32_ctrl->share_ctrl->vfebase + V32_TIMER_SELECT_OFF);
 }
 
-static void vfe32_program_dmi_cfg(
-	enum VFE32_DMI_RAM_SEL bankSel,
-	struct vfe32_ctrl_type *vfe32_ctrl)
-{
-	/* set bit 8 for auto increment. */
-	uint32_t value = VFE_DMI_CFG_DEFAULT;
-	value += (uint32_t)bankSel;
-	CDBG("%s: banksel = %d\n", __func__, bankSel);
 
-	msm_camera_io_w(value, vfe32_ctrl->share_ctrl->vfebase + VFE_DMI_CFG);
-	/* by default, always starts with offset 0.*/
-	msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase + VFE_DMI_ADDR);
-}
 static void vfe32_write_gamma_cfg(
 	enum VFE32_DMI_RAM_SEL channel_sel,
 	const uint32_t *tbl,
@@ -1582,7 +1727,7 @@
 	struct vfe32_ctrl_type *vfe32_ctrl)
 {
 	int i , rc = 0;
-	uint32_t old_val = 0 , new_val = 0;
+	uint32_t old_val = 0 , new_val = 0, module_val = 0;
 	uint32_t *cmdp = NULL;
 	uint32_t *cmdp_local = NULL;
 	uint32_t snapshot_cnt = 0;
@@ -1762,7 +1907,12 @@
 		break;
 
 	case VFE_CMD_STATS_AE_START: {
-		rc = vfe_stats_aec_buf_init(vfe32_ctrl, NULL);
+		if (vfe32_use_bayer_stats(vfe32_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		rc = vfe_stats_aec_bg_buf_init(vfe32_ctrl);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of AEC",
 				 __func__);
@@ -1791,7 +1941,12 @@
 		}
 		break;
 	case VFE_CMD_STATS_AF_START: {
-		rc = vfe_stats_af_buf_init(vfe32_ctrl, NULL);
+		if (vfe32_use_bayer_stats(vfe32_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		rc = vfe_stats_af_bf_buf_init(vfe32_ctrl);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of AF",
 				__func__);
@@ -1820,6 +1975,11 @@
 		}
 		break;
 	case VFE_CMD_STATS_AWB_START: {
+		if (vfe32_use_bayer_stats(vfe32_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
 		rc = vfe_stats_awb_buf_init(vfe32_ctrl, NULL);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of AWB",
@@ -1850,7 +2010,7 @@
 		break;
 
 	case VFE_CMD_STATS_IHIST_START: {
-		rc = vfe_stats_ihist_buf_init(vfe32_ctrl, NULL);
+		rc = vfe_stats_ihist_buf_init(vfe32_ctrl);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of IHIST",
 				 __func__);
@@ -1881,7 +2041,7 @@
 
 
 	case VFE_CMD_STATS_RS_START: {
-		rc = vfe_stats_rs_buf_init(vfe32_ctrl, NULL);
+		rc = vfe_stats_rs_buf_init(vfe32_ctrl);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of RS",
 				__func__);
@@ -1906,7 +2066,7 @@
 		break;
 
 	case VFE_CMD_STATS_CS_START: {
-		rc = vfe_stats_cs_buf_init(vfe32_ctrl, NULL);
+		rc = vfe_stats_cs_buf_init(vfe32_ctrl);
 		if (rc < 0) {
 			pr_err("%s: cannot config ping/pong address of CS",
 				__func__);
@@ -1930,6 +2090,67 @@
 		}
 		break;
 
+	case VFE_CMD_STATS_BG_START:
+	case VFE_CMD_STATS_BF_START:
+	case VFE_CMD_STATS_BHIST_START: {
+		if (!vfe32_use_bayer_stats(vfe32_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_camera_io_r(
+			vfe32_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
+		module_val = msm_camera_io_r(
+			vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		if (VFE_CMD_STATS_BG_START == cmd->id) {
+			module_val |= AE_BG_ENABLE_MASK;
+			old_val |= STATS_BG_ENABLE_MASK;
+			rc = vfe_stats_aec_bg_buf_init(vfe32_ctrl);
+			if (rc < 0) {
+				pr_err("%s: cannot config ping/pong address of CS",
+					__func__);
+				goto proc_general_done;
+			}
+		} else if (VFE_CMD_STATS_BF_START == cmd->id) {
+			module_val |= AF_BF_ENABLE_MASK;
+			old_val |= STATS_BF_ENABLE_MASK;
+			rc = vfe_stats_af_bf_buf_init(vfe32_ctrl);
+			if (rc < 0) {
+				pr_err("%s: cannot config ping/pong address of CS",
+					__func__);
+				goto proc_general_done;
+			}
+		} else {
+			module_val |= SKIN_BHIST_ENABLE_MASK;
+			old_val |= STATS_BHIST_ENABLE_MASK;
+			rc = vfe_stats_bhist_buf_init(vfe32_ctrl);
+			if (rc < 0) {
+				pr_err("%s: cannot config ping/pong address of CS",
+					__func__);
+				goto proc_general_done;
+			}
+		}
+		msm_camera_io_w(old_val, vfe32_ctrl->share_ctrl->vfebase +
+			VFE_STATS_CFG);
+		msm_camera_io_w(module_val,
+			vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+				(void __user *)(cmd->value),
+				cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		msm_camera_io_memcpy(
+			vfe32_ctrl->share_ctrl->vfebase +
+			vfe32_cmd[cmd->id].offset,
+			cmdp, (vfe32_cmd[cmd->id].length));
+		}
+		break;
 	case VFE_CMD_MCE_UPDATE:
 	case VFE_CMD_MCE_CFG:{
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
@@ -2601,6 +2822,11 @@
 		break;
 
 	case VFE_CMD_STATS_AWB_STOP: {
+		if (vfe32_use_bayer_stats(vfe32_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
 		old_val = msm_camera_io_r(
 			vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
 		old_val &= ~AWB_ENABLE_MASK;
@@ -2609,6 +2835,11 @@
 		}
 		break;
 	case VFE_CMD_STATS_AE_STOP: {
+		if (vfe32_use_bayer_stats(vfe32_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
 		old_val = msm_camera_io_r(
 			vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
 		old_val &= ~AE_BG_ENABLE_MASK;
@@ -2617,17 +2848,16 @@
 		}
 		break;
 	case VFE_CMD_STATS_AF_STOP: {
+		if (vfe32_use_bayer_stats(vfe32_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
 		old_val = msm_camera_io_r(
 			vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
 		old_val &= ~AF_BF_ENABLE_MASK;
 		msm_camera_io_w(old_val,
 			vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
-		rc = vfe32_stats_flush_enqueue(vfe32_ctrl, MSM_STATS_TYPE_AF);
-		if (rc < 0) {
-			pr_err("%s: dq stats buf err = %d",
-				   __func__, rc);
-			return -EINVAL;
-		}
 		}
 		break;
 
@@ -2657,6 +2887,37 @@
 			vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
 		}
 		break;
+
+	case VFE_CMD_STATS_BG_STOP:
+	case VFE_CMD_STATS_BF_STOP:
+	case VFE_CMD_STATS_BHIST_STOP: {
+		if (!vfe32_use_bayer_stats(vfe32_ctrl)) {
+			/* Error */
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_camera_io_r(
+			vfe32_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
+		if (VFE_CMD_STATS_BG_STOP == cmd->id)
+			old_val &= ~STATS_BG_ENABLE_MASK;
+		else if (VFE_CMD_STATS_BF_STOP == cmd->id)
+			old_val &= ~STATS_BF_ENABLE_MASK;
+		else
+			old_val &= ~STATS_BHIST_ENABLE_MASK;
+		msm_camera_io_w(old_val,
+			vfe32_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
+		if (VFE_CMD_STATS_BF_STOP == cmd->id) {
+			rc = vfe32_stats_flush_enqueue(vfe32_ctrl,
+					MSM_STATS_TYPE_BF);
+			if (rc < 0) {
+				pr_err("%s: dq stats buf err = %d",
+					   __func__, rc);
+				return -EINVAL;
+			}
+		}
+		}
+		break;
+
 	case VFE_CMD_STOP:
 		pr_info("vfe32_proc_general: cmdID = %s\n",
 			vfe32_general_cmd[cmd->id]);
@@ -3301,18 +3562,48 @@
 		vfe32_ctrl->share_ctrl->vfebase + VFE_CLAMP_MAX);
 
 	/* stats UB config */
-	msm_camera_io_w(0x3980007,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_AEC_UB_CFG);
-	msm_camera_io_w(0x3A00007,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_AF_UB_CFG);
-	msm_camera_io_w(0x3A8000F,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_AWB_UB_CFG);
-	msm_camera_io_w(0x3B80007,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_RS_UB_CFG);
-	msm_camera_io_w(0x3C0001F,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_CS_UB_CFG);
-	msm_camera_io_w(0x3E0001F,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_HIST_UB_CFG);
+	CDBG("%s: Use bayer stats = %d\n", __func__,
+		 vfe32_use_bayer_stats(vfe32_ctrl));
+	if (!vfe32_use_bayer_stats(vfe32_ctrl)) {
+		msm_camera_io_w(0x3980007,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_AEC_BG_UB_CFG);
+		msm_camera_io_w(0x3A00007,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_AF_BF_UB_CFG);
+		msm_camera_io_w(0x3A8000F,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_AWB_UB_CFG);
+		msm_camera_io_w(0x3B80007,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_RS_UB_CFG);
+		msm_camera_io_w(0x3C0001F,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_CS_UB_CFG);
+		msm_camera_io_w(0x3E0001F,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_HIST_UB_CFG);
+	} else {
+		msm_camera_io_w(0x350001F,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_HIST_UB_CFG);
+		msm_camera_io_w(0x370002F,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_AEC_BG_UB_CFG);
+		msm_camera_io_w(0x3A0002F,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_AF_BF_UB_CFG);
+		msm_camera_io_w(0x3D00007,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_RS_UB_CFG);
+		msm_camera_io_w(0x3D8001F,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_CS_UB_CFG);
+		msm_camera_io_w(0x3F80007,
+			vfe32_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_SKIN_BHIST_UB_CFG);
+	}
+	vfe32_reset_dmi_tables(vfe32_ctrl);
 }
 
 static void vfe32_process_reset_irq(
@@ -3785,25 +4076,36 @@
 	/* @todo This is causing issues, need further investigate */
 	/* spin_lock_irqsave(&ctrl->state_lock, flags); */
 	struct isp_msg_stats msgStats;
+	uint32_t stats_type;
 	msgStats.frameCounter = vfe32_ctrl->share_ctrl->vfeFrameId;
 	if (vfe32_ctrl->simultaneous_sof_stat)
 		msgStats.frameCounter--;
 	msgStats.buffer = bufAddress;
 	switch (statsNum) {
 	case statsAeNum:{
-		msgStats.id = MSG_ID_STATS_AEC;
+		msgStats.id =
+			(!vfe32_use_bayer_stats(vfe32_ctrl)) ? MSG_ID_STATS_AEC
+				: MSG_ID_STATS_BG;
+		stats_type =
+			(!vfe32_use_bayer_stats(vfe32_ctrl)) ?
+				MSM_STATS_TYPE_AEC : MSM_STATS_TYPE_BG;
 		rc = vfe32_ctrl->stats_ops.dispatch(
 				vfe32_ctrl->stats_ops.stats_ctrl,
-				MSM_STATS_TYPE_AEC, bufAddress,
+				stats_type, bufAddress,
 				&msgStats.buf_idx, &vaddr, &msgStats.fd,
 				vfe32_ctrl->stats_ops.client);
 		}
 		break;
 	case statsAfNum:{
-		msgStats.id = MSG_ID_STATS_AF;
+		msgStats.id =
+			(!vfe32_use_bayer_stats(vfe32_ctrl)) ? MSG_ID_STATS_AF
+				: MSG_ID_STATS_BF;
+		stats_type =
+			(!vfe32_use_bayer_stats(vfe32_ctrl)) ? MSM_STATS_TYPE_AF
+				: MSM_STATS_TYPE_BF;
 		rc = vfe32_ctrl->stats_ops.dispatch(
 				vfe32_ctrl->stats_ops.stats_ctrl,
-				MSM_STATS_TYPE_AF, bufAddress,
+				stats_type, bufAddress,
 				&msgStats.buf_idx, &vaddr, &msgStats.fd,
 				vfe32_ctrl->stats_ops.client);
 		}
@@ -3845,6 +4147,15 @@
 				vfe32_ctrl->stats_ops.client);
 		}
 		break;
+	case statsSkinNum: {
+		msgStats.id = MSG_ID_STATS_BHIST;
+		rc = vfe32_ctrl->stats_ops.dispatch(
+				vfe32_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_BHIST, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe32_ctrl->stats_ops.client);
+		}
+		break;
 
 	default:
 		goto stats_done;
@@ -3875,9 +4186,9 @@
 
 	msgStats.status_bits = status_bits;
 
-	msgStats.aec.buff = vfe32_ctrl->aecStatsControl.bufToRender;
+	msgStats.aec.buff = vfe32_ctrl->aecbgStatsControl.bufToRender;
 	msgStats.awb.buff = vfe32_ctrl->awbStatsControl.bufToRender;
-	msgStats.af.buff = vfe32_ctrl->afStatsControl.bufToRender;
+	msgStats.af.buff = vfe32_ctrl->afbfStatsControl.bufToRender;
 
 	msgStats.ihist.buff = vfe32_ctrl->ihistStatsControl.bufToRender;
 	msgStats.rs.buff = vfe32_ctrl->rsStatsControl.bufToRender;
@@ -3892,24 +4203,28 @@
 				&msgStats);
 }
 
-static void vfe32_process_stats_ae_irq(struct vfe32_ctrl_type *vfe32_ctrl)
+static void vfe32_process_stats_ae_bg_irq(struct vfe32_ctrl_type *vfe32_ctrl)
 {
 	unsigned long flags;
 	uint32_t addr;
+	uint32_t stats_type;
+	stats_type =
+		(!vfe32_use_bayer_stats(vfe32_ctrl)) ? MSM_STATS_TYPE_AEC
+			: MSM_STATS_TYPE_BG;
 	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
-	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AEC);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, stats_type);
 	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
 	if (addr) {
-		vfe32_ctrl->aecStatsControl.bufToRender =
+		vfe32_ctrl->aecbgStatsControl.bufToRender =
 			vfe32_process_stats_irq_common(vfe32_ctrl, statsAeNum,
 			addr);
 
 		vfe_send_stats_msg(vfe32_ctrl,
-			vfe32_ctrl->aecStatsControl.bufToRender, statsAeNum);
+			vfe32_ctrl->aecbgStatsControl.bufToRender, statsAeNum);
 	} else{
-		vfe32_ctrl->aecStatsControl.droppedStatsFrameCount++;
+		vfe32_ctrl->aecbgStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
-			vfe32_ctrl->aecStatsControl.droppedStatsFrameCount);
+			vfe32_ctrl->aecbgStatsControl.droppedStatsFrameCount);
 	}
 }
 
@@ -3934,24 +4249,50 @@
 	}
 }
 
-static void vfe32_process_stats_af_irq(struct vfe32_ctrl_type *vfe32_ctrl)
+static void vfe32_process_stats_af_bf_irq(struct vfe32_ctrl_type *vfe32_ctrl)
 {
 	unsigned long flags;
 	uint32_t addr;
+	uint32_t stats_type;
+	stats_type =
+		(!vfe32_use_bayer_stats(vfe32_ctrl)) ? MSM_STATS_TYPE_AF
+			: MSM_STATS_TYPE_BF;
 	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
-	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AF);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, stats_type);
 	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
 	if (addr) {
-		vfe32_ctrl->afStatsControl.bufToRender =
+		vfe32_ctrl->afbfStatsControl.bufToRender =
 			vfe32_process_stats_irq_common(vfe32_ctrl, statsAfNum,
 			addr);
 
 		vfe_send_stats_msg(vfe32_ctrl,
-			vfe32_ctrl->afStatsControl.bufToRender, statsAfNum);
+			vfe32_ctrl->afbfStatsControl.bufToRender, statsAfNum);
 	} else{
-		vfe32_ctrl->afStatsControl.droppedStatsFrameCount++;
+		vfe32_ctrl->afbfStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
-			vfe32_ctrl->afStatsControl.droppedStatsFrameCount);
+			vfe32_ctrl->afbfStatsControl.droppedStatsFrameCount);
+	}
+}
+
+static void vfe32_process_stats_bhist_irq(struct vfe32_ctrl_type *vfe32_ctrl)
+{
+	unsigned long flags;
+	uint32_t addr;
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_BHIST);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (addr) {
+		vfe32_ctrl->bhistStatsControl.bufToRender =
+			vfe32_process_stats_irq_common(vfe32_ctrl,
+				statsSkinNum, addr);
+
+		vfe_send_stats_msg(vfe32_ctrl,
+			vfe32_ctrl->bhistStatsControl.bufToRender,
+			statsSkinNum);
+	} else{
+		vfe32_ctrl->bhistStatsControl.droppedStatsFrameCount++;
+		CDBG("%s: droppedStatsFrameCount = %d", __func__,
+			vfe32_ctrl->bhistStatsControl.droppedStatsFrameCount);
 	}
 }
 
@@ -4026,23 +4367,28 @@
 	unsigned long flags;
 	int32_t process_stats = false;
 	uint32_t addr;
+	uint32_t stats_type;
 
 	CDBG("%s, stats = 0x%x\n", __func__, status_bits);
 	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
-	if (status_bits & VFE_IRQ_STATUS0_STATS_AEC) {
+	stats_type =
+		(!vfe32_use_bayer_stats(vfe32_ctrl)) ? MSM_STATS_TYPE_AEC
+			: MSM_STATS_TYPE_BG;
+
+	if (status_bits & VFE_IRQ_STATUS0_STATS_AEC_BG) {
 		addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
-				MSM_STATS_TYPE_AEC);
+				stats_type);
 		if (addr) {
-			vfe32_ctrl->aecStatsControl.bufToRender =
+			vfe32_ctrl->aecbgStatsControl.bufToRender =
 				vfe32_process_stats_irq_common(
 				vfe32_ctrl, statsAeNum,	addr);
 			process_stats = true;
 		} else{
-			vfe32_ctrl->aecStatsControl.bufToRender = 0;
-			vfe32_ctrl->aecStatsControl.droppedStatsFrameCount++;
+			vfe32_ctrl->aecbgStatsControl.bufToRender = 0;
+			vfe32_ctrl->aecbgStatsControl.droppedStatsFrameCount++;
 		}
 	} else {
-		vfe32_ctrl->aecStatsControl.bufToRender = 0;
+		vfe32_ctrl->aecbgStatsControl.bufToRender = 0;
 	}
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
@@ -4062,21 +4408,24 @@
 		vfe32_ctrl->awbStatsControl.bufToRender = 0;
 	}
 
-	if (status_bits & VFE_IRQ_STATUS0_STATS_AF) {
+	stats_type =
+		(!vfe32_use_bayer_stats(vfe32_ctrl)) ? MSM_STATS_TYPE_AF
+			: MSM_STATS_TYPE_BF;
+	if (status_bits & VFE_IRQ_STATUS0_STATS_AF_BF) {
 		addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
-					MSM_STATS_TYPE_AF);
+					stats_type);
 		if (addr) {
-			vfe32_ctrl->afStatsControl.bufToRender =
+			vfe32_ctrl->afbfStatsControl.bufToRender =
 				vfe32_process_stats_irq_common(
 				vfe32_ctrl, statsAfNum,
 				addr);
 			process_stats = true;
 		} else {
-			vfe32_ctrl->afStatsControl.bufToRender = 0;
-			vfe32_ctrl->afStatsControl.droppedStatsFrameCount++;
+			vfe32_ctrl->afbfStatsControl.bufToRender = 0;
+			vfe32_ctrl->afbfStatsControl.droppedStatsFrameCount++;
 		}
 	} else {
-		vfe32_ctrl->afStatsControl.bufToRender = 0;
+		vfe32_ctrl->afbfStatsControl.bufToRender = 0;
 	}
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
@@ -4182,17 +4531,21 @@
 		CDBG("irq	resetAckIrq\n");
 		vfe32_process_reset_irq(vfe32_ctrl);
 		break;
-	case VFE_IRQ_STATUS0_STATS_AEC:
+	case VFE_IRQ_STATUS0_STATS_AEC_BG:
 		CDBG("Stats AEC irq occured.\n");
-		vfe32_process_stats_ae_irq(vfe32_ctrl);
+		vfe32_process_stats_ae_bg_irq(vfe32_ctrl);
 		break;
 	case VFE_IRQ_STATUS0_STATS_AWB:
 		CDBG("Stats AWB irq occured.\n");
 		vfe32_process_stats_awb_irq(vfe32_ctrl);
 		break;
-	case VFE_IRQ_STATUS0_STATS_AF:
+	case VFE_IRQ_STATUS0_STATS_AF_BF:
 		CDBG("Stats AF irq occured.\n");
-		vfe32_process_stats_af_irq(vfe32_ctrl);
+		vfe32_process_stats_af_bf_irq(vfe32_ctrl);
+		break;
+	case VFE_IRQ_STATUS0_STATS_SK_BHIST:
+		CDBG("Stats BHIST irq occured.\n");
+		vfe32_process_stats_bhist_irq(vfe32_ctrl);
 		break;
 	case VFE_IRQ_STATUS0_STATS_IHIST:
 		CDBG("Stats IHIST irq occured.\n");
@@ -4261,11 +4614,11 @@
 		} else {
 			stat_interrupt =
 				(qcmd->vfeInterruptStatus0 &
-					VFE_IRQ_STATUS0_STATS_AEC) |
+					VFE_IRQ_STATUS0_STATS_AEC_BG) |
 				(qcmd->vfeInterruptStatus0 &
 					VFE_IRQ_STATUS0_STATS_AWB) |
 				(qcmd->vfeInterruptStatus0 &
-					VFE_IRQ_STATUS0_STATS_AF) |
+					VFE_IRQ_STATUS0_STATS_AF_BF) |
 				(qcmd->vfeInterruptStatus0 &
 					VFE_IRQ_STATUS0_STATS_IHIST) |
 				(qcmd->vfeInterruptStatus0 &
@@ -4333,10 +4686,10 @@
 			} else {
 				/* process individual stats interrupt. */
 				if (qcmd->vfeInterruptStatus0 &
-						VFE_IRQ_STATUS0_STATS_AEC)
+						VFE_IRQ_STATUS0_STATS_AEC_BG)
 					v4l2_subdev_notify(&axi_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
-					(void *)VFE_IRQ_STATUS0_STATS_AEC);
+					(void *)VFE_IRQ_STATUS0_STATS_AEC_BG);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_AWB)
@@ -4345,10 +4698,15 @@
 					(void *)VFE_IRQ_STATUS0_STATS_AWB);
 
 				if (qcmd->vfeInterruptStatus0 &
-						VFE_IRQ_STATUS0_STATS_AF)
+						VFE_IRQ_STATUS0_STATS_AF_BF)
 					v4l2_subdev_notify(&axi_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
-					(void *)VFE_IRQ_STATUS0_STATS_AF);
+					(void *)VFE_IRQ_STATUS0_STATS_AF_BF);
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_STATS_SK_BHIST)
+					v4l2_subdev_notify(&axi_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS0_STATS_SK_BHIST);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_IHIST)
@@ -4521,6 +4879,22 @@
 			vfe_ctrl->stats_ops.client);
 	}
 	break;
+	case VFE_CMD_STATS_UNREGBUF:
+	{
+		struct msm_stats_reqbuf *req_buf = NULL;
+		req_buf = (struct msm_stats_reqbuf *)cmd->value;
+		if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats reqbuf input size = %d,\n"
+				"struct size = %d, mitch match\n",
+				 __func__, cmd->length,
+				sizeof(struct msm_stats_reqbuf));
+			rc = -EINVAL ;
+			goto end;
+		}
+		rc = vfe32_stats_unregbuf(vfe_ctrl, req_buf);
+	}
+	break;
 	default:
 		rc = -1;
 		pr_err("%s: cmd_type %d not supported", __func__,
@@ -4570,27 +4944,31 @@
 	case VFE_CMD_STATS_REQBUF:
 	case VFE_CMD_STATS_ENQUEUEBUF:
 	case VFE_CMD_STATS_FLUSH_BUFQ:
+	case VFE_CMD_STATS_UNREGBUF:
 		/* for easy porting put in one envelope */
 		rc = vfe_stats_bufq_sub_ioctl(vfe32_ctrl,
 				cmd, vfe_params->data);
 		return rc;
 	default:
 		if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
-			cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
-			cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
-			cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
-			cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
-			cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
-			cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
-			cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
-			cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
-				if (copy_from_user(&vfecmd,
+		cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+		cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
+		cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_BG_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_BF_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_BHIST_BUF_RELEASE) {
+			if (copy_from_user(&vfecmd,
 					(void __user *)(cmd->value),
 					sizeof(vfecmd))) {
-						pr_err("%s %d: copy_from_user failed\n",
-							__func__, __LINE__);
-					return -EFAULT;
-				}
+				pr_err("%s %d: copy_from_user failed\n",
+					__func__, __LINE__);
+				return -EFAULT;
+			}
 		} else {
 			/* here eith stats release or frame release. */
 			if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
@@ -4612,6 +4990,25 @@
 				sack->nextStatsBuf = *(uint32_t *)data;
 			}
 		}
+	}
+
+	CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
+
+	if ((cmd->cmd_type == CMD_STATS_AF_ENABLE)    ||
+		(cmd->cmd_type == CMD_STATS_AWB_ENABLE)   ||
+		(cmd->cmd_type == CMD_STATS_IHIST_ENABLE) ||
+		(cmd->cmd_type == CMD_STATS_RS_ENABLE)    ||
+		(cmd->cmd_type == CMD_STATS_CS_ENABLE)    ||
+		(cmd->cmd_type == CMD_STATS_AEC_ENABLE)   ||
+		(cmd->cmd_type == CMD_STATS_BG_ENABLE)    ||
+		(cmd->cmd_type == CMD_STATS_BF_ENABLE)    ||
+		(cmd->cmd_type == CMD_STATS_BHIST_ENABLE)) {
+		struct axidata *axid;
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			goto vfe32_config_done;
+		}
 		CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
 
 		if ((cmd->cmd_type == CMD_STATS_AF_ENABLE)    ||
@@ -4625,38 +5022,56 @@
 				goto vfe32_config_done;
 		}
 		switch (cmd->cmd_type) {
-		case CMD_GENERAL:
-			rc = vfe32_proc_general(pmctl, &vfecmd, vfe32_ctrl);
-		break;
-		case CMD_CONFIG_PING_ADDR: {
-			int path = *((int *)cmd->value);
-			struct vfe32_output_ch *outch =
-				vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
-			outch->ping = *((struct msm_free_buf *)data);
+		case CMD_STATS_AEC_ENABLE:
+		case CMD_STATS_BG_ENABLE:
+		case CMD_STATS_BF_ENABLE:
+		case CMD_STATS_BHIST_ENABLE:
+		case CMD_STATS_AWB_ENABLE:
+		case CMD_STATS_IHIST_ENABLE:
+		case CMD_STATS_RS_ENABLE:
+		case CMD_STATS_CS_ENABLE:
+		default:
+			pr_err("%s Unsupported cmd type %d",
+				__func__, cmd->cmd_type);
+			break;
 		}
-		break;
-		case CMD_CONFIG_PONG_ADDR: {
-			int path = *((int *)cmd->value);
-			struct vfe32_output_ch *outch =
-				vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
-			outch->pong = *((struct msm_free_buf *)data);
-		}
+		goto vfe32_config_done;
+	}
+	switch (cmd->cmd_type) {
+	case CMD_GENERAL:
+		rc = vfe32_proc_general(pmctl, &vfecmd, vfe32_ctrl);
+	break;
+	case CMD_CONFIG_PING_ADDR: {
+		int path = *((int *)cmd->value);
+		struct vfe32_output_ch *outch =
+			vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
+		outch->ping = *((struct msm_free_buf *)data);
+	}
+	break;
+
+	case CMD_CONFIG_PONG_ADDR: {
+		int path = *((int *)cmd->value);
+		struct vfe32_output_ch *outch =
+			vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
+		outch->pong = *((struct msm_free_buf *)data);
+	}
+	break;
+
+	case CMD_CONFIG_FREE_BUF_ADDR: {
+		int path = *((int *)cmd->value);
+		struct vfe32_output_ch *outch =
+			vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
+		outch->free_buf = *((struct msm_free_buf *)data);
+	}
+	break;
+
+	case CMD_SNAP_BUF_RELEASE:
 		break;
 
-		case CMD_CONFIG_FREE_BUF_ADDR: {
-			int path = *((int *)cmd->value);
-			struct vfe32_output_ch *outch =
-				vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
-			outch->free_buf = *((struct msm_free_buf *)data);
-		}
-		break;
-		case CMD_SNAP_BUF_RELEASE:
-		break;
-		default:
-			pr_err("%s Unsupported AXI configuration %x ", __func__,
-				cmd->cmd_type);
-		break;
-		}
+	default:
+		pr_err("%s Unsupported AXI configuration %x ", __func__,
+			cmd->cmd_type);
+	break;
 	}
 vfe32_config_done:
 	kfree(scfg);
@@ -5424,6 +5839,8 @@
 		axi32_do_tasklet, (unsigned long)axi_ctrl);
 
 	vfe32_ctrl->pdev = pdev;
+	/*disable bayer stats by default*/
+	vfe32_ctrl->ver_num.main = 0;
 	return 0;
 
 vfe32_no_resource:
diff --git a/drivers/media/video/msm/msm_vfe32.h b/drivers/media/video/msm/msm_vfe32.h
index 9336cfb..0b685e1 100644
--- a/drivers/media/video/msm/msm_vfe32.h
+++ b/drivers/media/video/msm/msm_vfe32.h
@@ -104,12 +104,13 @@
 #define VFE_IRQ_STATUS1_RESET_AXI_HALT_ACK_MASK   0x00800000
 #define VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK       0x01000000
 
-#define VFE_IRQ_STATUS0_STATS_AEC     0x2000  /* bit 13 */
-#define VFE_IRQ_STATUS0_STATS_AF      0x4000  /* bit 14 */
-#define VFE_IRQ_STATUS0_STATS_AWB     0x8000  /* bit 15 */
-#define VFE_IRQ_STATUS0_STATS_RS      0x10000  /* bit 16 */
-#define VFE_IRQ_STATUS0_STATS_CS      0x20000  /* bit 17 */
-#define VFE_IRQ_STATUS0_STATS_IHIST   0x40000  /* bit 18 */
+#define VFE_IRQ_STATUS0_STATS_AEC_BG    0x2000  /* bit 13 */
+#define VFE_IRQ_STATUS0_STATS_AF_BF     0x4000  /* bit 14 */
+#define VFE_IRQ_STATUS0_STATS_AWB       0x8000  /* bit 15 */
+#define VFE_IRQ_STATUS0_STATS_RS        0x10000  /* bit 16 */
+#define VFE_IRQ_STATUS0_STATS_CS        0x20000  /* bit 17 */
+#define VFE_IRQ_STATUS0_STATS_IHIST     0x40000  /* bit 18 */
+#define VFE_IRQ_STATUS0_STATS_SK_BHIST  0x80000 /* bit 19 */
 
 #define VFE_IRQ_STATUS0_SYNC_TIMER0   0x2000000  /* bit 25 */
 #define VFE_IRQ_STATUS0_SYNC_TIMER1   0x4000000  /* bit 26 */
@@ -174,8 +175,13 @@
 #define RS_CS_ENABLE_MASK 0x00000300   /* bit 8,9  */
 #define CLF_ENABLE_MASK 0x00002000     /* bit 13 */
 #define IHIST_ENABLE_MASK 0x00010000   /* bit 16 */
+#define SKIN_BHIST_ENABLE_MASK 0x00080000 /* bit 19 */
 #define STATS_ENABLE_MASK 0x000903E0   /* bit 19,16,9,8,7,6,5*/
 
+#define STATS_BG_ENABLE_MASK     0x00000002 /* bit 1 */
+#define STATS_BF_ENABLE_MASK     0x00000004 /* bit 2 */
+#define STATS_BHIST_ENABLE_MASK  0x00000008 /* bit 3 */
+
 #define VFE_REG_UPDATE_TRIGGER           1
 #define VFE_PM_BUF_MAX_CNT_MASK          0xFF
 #define VFE_DMI_CFG_DEFAULT              0x00000100
@@ -378,6 +384,15 @@
 #define V32_CLF_CHROMA_UPDATE_OFF 0x000006F0
 #define V32_CLF_CHROMA_UPDATE_LEN 8
 
+#define V32_STATS_BG_OFF 0x00000700
+#define V32_STATS_BG_LEN 12
+
+#define V32_STATS_BF_OFF 0x0000070c
+#define V32_STATS_BF_LEN 24
+
+#define V32_STATS_BHIST_OFF 0x00000724
+#define V32_STATS_BHIST_LEN 8
+
 struct vfe_cmd_hw_version {
 	uint32_t minorVersion;
 	uint32_t majorVersion;
@@ -845,12 +860,12 @@
 #define VFE_AXI_STATUS        0x000001DC
 #define VFE_BUS_STATS_PING_PONG_BASE    0x000000F4
 
-#define VFE_BUS_STATS_AEC_WR_PING_ADDR    0x000000F4
-#define VFE_BUS_STATS_AEC_WR_PONG_ADDR    0x000000F8
-#define VFE_BUS_STATS_AEC_UB_CFG          0x000000FC
-#define VFE_BUS_STATS_AF_WR_PING_ADDR     0x00000100
-#define VFE_BUS_STATS_AF_WR_PONG_ADDR     0x00000104
-#define VFE_BUS_STATS_AF_UB_CFG           0x00000108
+#define VFE_BUS_STATS_AEC_BG_WR_PING_ADDR    0x000000F4
+#define VFE_BUS_STATS_AEC_BG_WR_PONG_ADDR    0x000000F8
+#define VFE_BUS_STATS_AEC_BG_UB_CFG          0x000000FC
+#define VFE_BUS_STATS_AF_BF_WR_PING_ADDR     0x00000100
+#define VFE_BUS_STATS_AF_BF_WR_PONG_ADDR     0x00000104
+#define VFE_BUS_STATS_AF_BF_UB_CFG           0x00000108
 #define VFE_BUS_STATS_AWB_WR_PING_ADDR    0x0000010C
 #define VFE_BUS_STATS_AWB_WR_PONG_ADDR    0x00000110
 #define VFE_BUS_STATS_AWB_UB_CFG          0x00000114
@@ -864,9 +879,9 @@
 #define VFE_BUS_STATS_HIST_WR_PING_ADDR   0x00000130
 #define VFE_BUS_STATS_HIST_WR_PONG_ADDR   0x00000134
 #define VFE_BUS_STATS_HIST_UB_CFG          0x00000138
-#define VFE_BUS_STATS_SKIN_WR_PING_ADDR    0x0000013C
-#define VFE_BUS_STATS_SKIN_WR_PONG_ADDR    0x00000140
-#define VFE_BUS_STATS_SKIN_UB_CFG          0x00000144
+#define VFE_BUS_STATS_SKIN_BHIST_WR_PING_ADDR    0x0000013C
+#define VFE_BUS_STATS_SKIN_BHIST_WR_PONG_ADDR    0x00000140
+#define VFE_BUS_STATS_SKIN_BHIST_UB_CFG          0x00000144
 #define VFE_CAMIF_COMMAND               0x000001E0
 #define VFE_CAMIF_STATUS                0x00000204
 #define VFE_REG_UPDATE_CMD              0x00000260
@@ -888,6 +903,7 @@
 #define VFE_STATS_AWB_SGW_CFG           0x00000554
 #define VFE_DMI_CFG                     0x00000598
 #define VFE_DMI_ADDR                    0x0000059C
+#define VFE_DMI_DATA_HI                 0x000005A0
 #define VFE_DMI_DATA_LO                 0x000005A4
 #define VFE_BUS_IO_FORMAT_CFG           0x000006F8
 #define VFE_PIXEL_IF_CFG                0x000006FC
@@ -990,12 +1006,14 @@
 	uint32_t output2Period;
 	uint32_t vfeFrameSkipCount;
 	uint32_t vfeFrameSkipPeriod;
-	struct vfe_stats_control afStatsControl;
+	struct msm_ver_num_info ver_num;
+	struct vfe_stats_control afbfStatsControl;
 	struct vfe_stats_control awbStatsControl;
-	struct vfe_stats_control aecStatsControl;
+	struct vfe_stats_control aecbgStatsControl;
 	struct vfe_stats_control ihistStatsControl;
 	struct vfe_stats_control rsStatsControl;
 	struct vfe_stats_control csStatsControl;
+	struct vfe_stats_control bhistStatsControl;
 
 	/* v4l2 subdev */
 	struct v4l2_subdev subdev;
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index 64e0385..59c5d7d 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -404,6 +404,25 @@
 	return 0L;
 }
 
+static unsigned long vfe2x_stats_unregbuf(
+	struct msm_stats_reqbuf *req_buf)
+{
+	int i = 0, rc = 0;
+
+	for (i = 0; i < req_buf->num_buf; i++) {
+		rc = vfe2x_ctrl->stats_ops.buf_unprepare(
+			vfe2x_ctrl->stats_ops.stats_ctrl,
+			req_buf->stats_type, i,
+			vfe2x_ctrl->stats_ops.client);
+		if (rc < 0) {
+			pr_err("%s: unreg stats buf (type = %d) err = %d",
+				__func__, req_buf->stats_type, rc);
+		return rc;
+		}
+	}
+	return 0L;
+}
+
 static int vfe2x_stats_buf_init(enum msm_stats_enum_type type)
 {
 	unsigned long flags;
@@ -556,6 +575,22 @@
 				vfe2x_ctrl->stats_ops.client);
 	}
 	break;
+	case VFE_CMD_STATS_UNREGBUF:
+	{
+		struct msm_stats_reqbuf *req_buf = NULL;
+		req_buf = (struct msm_stats_reqbuf *)cmd->value;
+		if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats reqbuf input size = %d,\n"
+				"struct size = %d, mitch match\n",
+				 __func__, cmd->length,
+				sizeof(struct msm_stats_reqbuf));
+			rc = -EINVAL ;
+			goto end;
+		}
+		rc = vfe2x_stats_unregbuf(req_buf);
+	}
+	break;
 	default:
 		rc = -1;
 		pr_err("%s: cmd_type %d not supported",
@@ -1228,6 +1263,7 @@
 		cmd->cmd_type != CMD_VFE_BUFFER_RELEASE &&
 		cmd->cmd_type != VFE_CMD_STATS_REQBUF &&
 		cmd->cmd_type != VFE_CMD_STATS_FLUSH_BUFQ &&
+		cmd->cmd_type != VFE_CMD_STATS_UNREGBUF &&
 		cmd->cmd_type != VFE_CMD_STATS_ENQUEUEBUF) {
 		if (copy_from_user(&vfecmd,
 			   (void __user *)(cmd->value),
@@ -1239,6 +1275,7 @@
 	switch (cmd->cmd_type) {
 	case VFE_CMD_STATS_REQBUF:
 	case VFE_CMD_STATS_FLUSH_BUFQ:
+	case VFE_CMD_STATS_UNREGBUF:
 		/* for easy porting put in one envelope */
 		rc = vfe2x_stats_bufq_sub_ioctl(cmd, vfe_params->data);
 		return rc;
diff --git a/drivers/media/video/msm/msm_vfe_stats_buf.c b/drivers/media/video/msm/msm_vfe_stats_buf.c
index 9e8f285..5fbcdb1 100644
--- a/drivers/media/video/msm/msm_vfe_stats_buf.c
+++ b/drivers/media/video/msm/msm_vfe_stats_buf.c
@@ -475,6 +475,8 @@
 	struct msm_stats_buf_info *info, struct ion_client *client)
 {
 	int rc = 0;
+	D("%s: stats type : %d, idx : %d\n", __func__,
+		info->type, info->buf_idx);
 	rc = msm_stats_buf_prepare(stats_ctrl, info, client);
 	if (rc < 0) {
 		pr_err("%s: buf_prepare failed, rc = %d", __func__, rc);
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index 817caf5..cf1ebbb 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -704,6 +704,7 @@
 	struct resource *res;
 	int i = 0;
 	int rc = 0;
+	struct on_chip_mem *ocmem;
 	if (!core)
 		return -EINVAL;
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -753,6 +754,14 @@
 		pr_err("Failed to register iommu domains: %d\n", rc);
 		goto fail_register_domains;
 	}
+	ocmem = &core->resources.ocmem;
+	ocmem->vidc_ocmem_nb.notifier_call = msm_vidc_ocmem_notify_handler;
+	ocmem->handle =
+		ocmem_notifier_register(OCMEM_VIDEO, &ocmem->vidc_ocmem_nb);
+	if (!ocmem->handle) {
+		pr_warn("Failed to register OCMEM notifier.");
+		pr_warn(" Performance will be impacted\n");
+	}
 	return rc;
 fail_register_domains:
 	msm_bus_scale_unregister_client(
@@ -861,6 +870,9 @@
 	video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
 	video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
 	v4l2_device_unregister(&core->v4l2_dev);
+	if (core->resources.ocmem.handle)
+		ocmem_notifier_unregister(core->resources.ocmem.handle,
+				&core->resources.ocmem.vidc_ocmem_nb);
 	kfree(core);
 	return rc;
 }
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index fa9608d..6835467 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -42,6 +42,11 @@
 	__height * __width * __fps; \
 })
 
+#define GET_NUM_MBS(__h, __w) ({\
+	u32 __mbs = (__h >> 4) * (__w >> 4);\
+	__mbs;\
+})
+
 /*While adding entries to this array make sure
  * they are in descending order.
  * Look @ msm_comm_get_load function*/
@@ -303,6 +308,23 @@
 	}
 }
 
+static void handle_sys_release_res_done(
+	enum command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_core *core;
+	if (!response) {
+		pr_err("Failed to get valid response for sys init\n");
+		return;
+	}
+	core = get_vidc_core(response->device_id);
+	if (!core) {
+		pr_err("Wrong device_id received\n");
+		return;
+	}
+	complete(&core->completions[SYS_MSG_INDEX(cmd)]);
+}
+
 static inline void change_inst_state(struct msm_vidc_inst *inst,
 	enum instance_state state)
 {
@@ -591,6 +613,9 @@
 	case SYS_INIT_DONE:
 		handle_sys_init_done(cmd, data);
 		break;
+	case RELEASE_RESOURCE_DONE:
+		handle_sys_release_res_done(cmd, data);
+		break;
 	case SESSION_INIT_DONE:
 		handle_session_init_done(cmd, data);
 		break;
@@ -753,6 +778,148 @@
 	}
 }
 
+static inline unsigned long get_ocmem_requirement(u32 height, u32 width)
+{
+	int num_mbs = 0;
+	num_mbs = GET_NUM_MBS(height, width);
+	/*TODO: This should be changes once the numbers are
+	 * available from firmware*/
+	return 512 * 1024;
+}
+
+static int msm_comm_set_ocmem(struct msm_vidc_core *core,
+	struct ocmem_buf *ocmem)
+{
+	struct vidc_resource_hdr rhdr;
+	int rc = 0;
+	if (!core || !ocmem) {
+		pr_err("Invalid params, core:%p, ocmem: %p\n",
+			core, ocmem);
+		return -EINVAL;
+	}
+	rhdr.resource_id = VIDC_RESOURCE_OCMEM;
+	rhdr.resource_handle = (u32) &core->resources.ocmem;
+	rhdr.size =	ocmem->len;
+	rc = vidc_hal_core_set_resource(core->device, &rhdr, ocmem);
+	if (rc) {
+		pr_err("Failed to set OCMEM on driver\n");
+		goto ocmem_set_failed;
+	}
+	pr_debug("OCMEM set, addr = %lx, size: %ld\n",
+		ocmem->addr, ocmem->len);
+ocmem_set_failed:
+	return rc;
+}
+
+static int msm_comm_unset_ocmem(struct msm_vidc_core *core)
+{
+	struct vidc_resource_hdr rhdr;
+	int rc = 0;
+	if (!core || !core->resources.ocmem.buf) {
+		pr_err("Invalid params, core:%p\n",	core);
+		return -EINVAL;
+	}
+	rhdr.resource_id = VIDC_RESOURCE_OCMEM;
+	rhdr.resource_handle = (u32) &core->resources.ocmem;
+	init_completion(
+		&core->completions[SYS_MSG_INDEX(RELEASE_RESOURCE_DONE)]);
+	rc = vidc_hal_core_release_resource(core->device, &rhdr);
+	if (rc) {
+		pr_err("Failed to set OCMEM on driver\n");
+		goto release_ocmem_failed;
+	}
+	rc = wait_for_completion_timeout(
+		&core->completions[SYS_MSG_INDEX(RELEASE_RESOURCE_DONE)],
+		msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+	if (!rc) {
+		pr_err("Wait interrupted or timeout: %d\n", rc);
+		rc = -EIO;
+		goto release_ocmem_failed;
+	}
+release_ocmem_failed:
+	return rc;
+}
+
+static int msm_comm_alloc_ocmem(struct msm_vidc_core *core,
+		unsigned long size)
+{
+	int rc = 0;
+	unsigned long flags;
+	struct ocmem_buf *ocmem_buffer;
+	if (!core || !size) {
+		pr_err("Invalid param, core: %p, size: %lu\n", core, size);
+		return -EINVAL;
+	}
+	spin_lock_irqsave(&core->lock, flags);
+	ocmem_buffer = core->resources.ocmem.buf;
+	if (!ocmem_buffer ||
+		ocmem_buffer->len < size) {
+		ocmem_buffer = ocmem_allocate_nb(OCMEM_VIDEO, size);
+		if (IS_ERR_OR_NULL(ocmem_buffer)) {
+			pr_err("ocmem_allocate_nb failed: %d\n",
+				(u32) ocmem_buffer);
+			rc = -ENOMEM;
+		}
+		core->resources.ocmem.buf = ocmem_buffer;
+		rc = msm_comm_set_ocmem(core, ocmem_buffer);
+		if (rc) {
+			pr_err("Failed to set ocmem: %d\n", rc);
+			goto ocmem_set_failed;
+		}
+	} else
+		pr_debug("OCMEM is enough. reqd: %lu, available: %lu\n",
+			size, ocmem_buffer->len);
+
+ocmem_set_failed:
+	spin_unlock_irqrestore(&core->lock, flags);
+	return rc;
+}
+
+static int msm_comm_free_ocmem(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	unsigned long flags;
+	spin_lock_irqsave(&core->lock, flags);
+	if (core->resources.ocmem.buf) {
+		rc = ocmem_free(OCMEM_VIDEO, core->resources.ocmem.buf);
+		if (rc)
+			pr_err("Failed to free ocmem\n");
+	}
+	core->resources.ocmem.buf = NULL;
+	spin_unlock_irqrestore(&core->lock, flags);
+	return rc;
+}
+
+int msm_vidc_ocmem_notify_handler(struct notifier_block *this,
+		unsigned long event, void *data)
+{
+	struct ocmem_buf *buff = data;
+	struct msm_vidc_core *core;
+	struct msm_vidc_resources *resources;
+	struct on_chip_mem *ocmem;
+	int rc = NOTIFY_DONE;
+	if (event == OCMEM_ALLOC_GROW) {
+		ocmem = container_of(this, struct on_chip_mem, vidc_ocmem_nb);
+		if (!ocmem) {
+			pr_err("Wrong handler passed\n");
+			rc = NOTIFY_BAD;
+			goto bad_notfier;
+		}
+		resources = container_of(ocmem,
+			struct msm_vidc_resources, ocmem);
+		core = container_of(resources,
+			struct msm_vidc_core, resources);
+		if (msm_comm_set_ocmem(core, buff)) {
+			pr_err("Failed to set ocmem: %d\n", rc);
+			goto ocmem_set_failed;
+		}
+		rc = NOTIFY_OK;
+	}
+ocmem_set_failed:
+bad_notfier:
+	return rc;
+}
+
 static int msm_comm_init_core_done(struct msm_vidc_inst *inst)
 {
 	struct msm_vidc_core *core = inst->core;
@@ -835,7 +1002,8 @@
 		goto core_already_uninited;
 	}
 	if (list_empty(&core->instances)) {
-		pr_debug("Calling vidc_hal_core_release\n");
+		msm_comm_unset_ocmem(core);
+		msm_comm_free_ocmem(core);
 		rc = vidc_hal_core_release(core->device);
 		if (rc) {
 			pr_err("Failed to release core, id = %d\n", core->id);
@@ -953,10 +1121,16 @@
 	struct msm_vidc_inst *inst)
 {
 	int rc = 0;
+	u32 ocmem_sz = 0;
 	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_LOAD_RESOURCES)) {
 		pr_err("inst: %p is already in state: %d\n", inst, inst->state);
 		goto exit;
 	}
+	ocmem_sz = get_ocmem_requirement(inst->height, inst->width);
+	rc = msm_comm_alloc_ocmem(inst->core, ocmem_sz);
+	if (rc)
+		pr_warn("Failed to allocate OCMEM. Performance will be impacted\n");
+
 	rc = vidc_hal_session_load_res((void *) inst->session);
 	if (rc) {
 		pr_err("Failed to send load resources\n");
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index 58d7290..992f39c 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -21,6 +21,7 @@
 #include <linux/clk.h>
 #include <mach/msm_bus.h>
 #include <mach/msm_bus_board.h>
+#include <mach/ocmem.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
@@ -153,11 +154,18 @@
 	u32 ocmem_handle;
 };
 
+struct on_chip_mem {
+	struct ocmem_buf *buf;
+	struct notifier_block vidc_ocmem_nb;
+	void *handle;
+};
+
 struct msm_vidc_resources {
 	struct msm_vidc_fw fw;
 	struct iommu_info io_map[MAX_MAP];
 	struct core_clock clock[VCODEC_MAX_CLKS];
 	struct vidc_bus_info bus_info;
+	struct on_chip_mem ocmem;
 };
 
 struct session_prop {
@@ -227,4 +235,7 @@
 };
 
 void handle_cmd_response(enum command_response cmd, void *data);
+int msm_vidc_ocmem_notify_handler(struct notifier_block *this,
+		unsigned long event, void *data);
+
 #endif
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index 646a0b8..16a3ecd 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -16,6 +16,8 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/delay.h>
+#include <mach/ocmem.h>
+
 #include <asm/memory.h>
 #include "vidc_hal.h"
 #include "vidc_hal_io.h"
@@ -749,12 +751,12 @@
 		struct hfi_resource_ocmem *hfioc_mem =
 			(struct hfi_resource_ocmem *)
 			&pkt->rg_resource_data[0];
-		struct vidc_mem_addr *vidc_oc_mem =
-			(struct vidc_mem_addr *) resource_value;
+		struct ocmem_buf *ocmem =
+			(struct ocmem_buf *) resource_value;
 
 		pkt->resource_type = HFI_RESOURCE_OCMEM;
-		hfioc_mem->size = (u32) vidc_oc_mem->mem_size;
-		hfioc_mem->mem = (u8 *) vidc_oc_mem->align_device_addr;
+		hfioc_mem->size = (u32) ocmem->len;
+		hfioc_mem->mem = (u8 *) ocmem->addr;
 		pkt->size += sizeof(struct hfi_resource_ocmem);
 		if (vidc_hal_iface_cmdq_write(dev, pkt))
 			rc = -ENOTEMPTY;
diff --git a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
index ded9f11..364faa9 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
+++ b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
@@ -252,6 +252,29 @@
 	device->callback(SYS_INIT_DONE, &cmd_done);
 }
 
+static void hal_process_sys_rel_resource_done(struct hal_device *device,
+	struct hfi_msg_sys_release_resource_done_packet *pkt)
+{
+	struct msm_vidc_cb_cmd_done cmd_done;
+	enum vidc_status status = VIDC_ERR_NONE;
+	u32 pkt_size;
+	memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+	HAL_MSG_ERROR("RECEIVED:SYS_RELEASE_RESOURCE_DONE");
+	pkt_size = sizeof(struct hfi_msg_sys_release_resource_done_packet);
+	if (pkt_size > pkt->size) {
+		HAL_MSG_ERROR("hal_process_sys_rel_resource_done:bad size:%d",
+				pkt->size);
+		return;
+	}
+	status = vidc_map_hal_err_status((u32)pkt->error_type);
+	cmd_done.device_id = device->device_id;
+	cmd_done.session_id = 0;
+	cmd_done.status = (u32) status;
+	cmd_done.size = 0;
+	cmd_done.data = NULL;
+	device->callback(RELEASE_RESOURCE_DONE, &cmd_done);
+}
+
 enum vidc_status vidc_hal_process_sess_init_done_prop_read(
 	struct hfi_msg_sys_session_init_done_packet *pkt,
 	struct msm_vidc_cb_cmd_done *cmddone)
@@ -711,7 +734,7 @@
 		return;
 	}
 
-	HAL_MSG_INFO("Received: 0x%x in %s", msg_hdr->packet, __func__);
+	HAL_MSG_ERROR("Received: 0x%x in %s", msg_hdr->packet, __func__);
 
 	switch (msg_hdr->packet) {
 	case HFI_MSG_EVENT_NOTIFY:
@@ -771,6 +794,11 @@
 			(struct hfi_msg_session_release_resources_done_packet *)
 					msg_hdr);
 		break;
+	case HFI_MSG_SYS_RELEASE_RESOURCE:
+		hal_process_sys_rel_resource_done(device,
+			(struct hfi_msg_sys_release_resource_done_packet *)
+			msg_hdr);
+		break;
 	default:
 		HAL_MSG_ERROR("UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
 		break;
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 01e1201..894860b 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -852,9 +852,6 @@
 		c_data->vp_in_fmt.height = priv_fmt->u.pix.height;
 		c_data->vp_in_fmt.pixfmt = priv_fmt->u.pix.pixelformat;
 
-		if (priv_fmt->u.pix.priv)
-			c_data->vid_vp_action.nr_enabled = 1;
-
 		size = c_data->vp_in_fmt.width * c_data->vp_in_fmt.height;
 		if (c_data->vp_in_fmt.pixfmt == V4L2_PIX_FMT_NV16)
 			size = size * 2;
@@ -868,9 +865,6 @@
 		c_data->vp_out_fmt.height = priv_fmt->u.pix.height;
 		c_data->vp_out_fmt.pixfmt = priv_fmt->u.pix.pixelformat;
 
-		if (priv_fmt->u.pix.priv)
-			c_data->vid_vp_action.nr_enabled = 1;
-
 		size = c_data->vp_out_fmt.width * c_data->vp_out_fmt.height;
 		if (c_data->vp_out_fmt.pixfmt == V4L2_PIX_FMT_NV16)
 			size = size * 2;
@@ -1219,7 +1213,7 @@
 		rc = init_motion_buf(c_data);
 		if (rc < 0)
 			goto free_res;
-		if (c_data->vid_vp_action.nr_enabled) {
+		if (c_data->vid_vp_action.nr_param.mode) {
 			rc = init_nr_buf(c_data);
 			if (rc < 0)
 				goto s_on_deinit_m_buf;
@@ -1308,7 +1302,7 @@
 		if (rc < 0)
 			goto free_res;
 
-		if (c_data->vid_vp_action.nr_enabled) {
+		if (c_data->vid_vp_action.nr_param.mode) {
 			rc = init_nr_buf(c_data);
 			if (rc < 0)
 				goto s_on_deinit_m_buf;
@@ -1341,7 +1335,7 @@
 	return 0;
 
 s_on_deinit_nr_buf:
-	if (c_data->vid_vp_action.nr_enabled)
+	if (c_data->vid_vp_action.nr_param.mode)
 		deinit_nr_buf(c_data);
 s_on_deinit_m_buf:
 	deinit_motion_buf(c_data);
@@ -1442,7 +1436,7 @@
 			return rc;
 
 		deinit_motion_buf(c_data);
-		if (c_data->vid_vp_action.nr_enabled)
+		if (c_data->vid_vp_action.nr_param.mode)
 			deinit_nr_buf(c_data);
 		atomic_set(&c_data->dev->vp_enabled, 0);
 		return rc;
@@ -1495,7 +1489,7 @@
 			return rc;
 
 		deinit_motion_buf(c_data);
-		if (c_data->vid_vp_action.nr_enabled)
+		if (c_data->vid_vp_action.nr_param.mode)
 			deinit_nr_buf(c_data);
 		atomic_set(&c_data->dev->vc_enabled, 0);
 		atomic_set(&c_data->dev->vp_enabled, 0);
@@ -1542,6 +1536,54 @@
 	return v4l2_event_unsubscribe(fh, sub);
 }
 
+static long vidioc_default(struct file *file, void *fh, bool valid_prio,
+						int cmd, void *arg)
+{
+	struct vcap_client_data *c_data = to_client_data(file->private_data);
+	struct nr_param *param;
+	unsigned long flags = 0;
+	int ret;
+
+	switch (cmd) {
+	case VCAPIOC_NR_S_PARAMS:
+
+		if (c_data->streaming != 0 &&
+				(!(!((struct nr_param *) arg)->mode) !=
+				!(!(c_data->vid_vp_action.nr_param.mode)))) {
+			pr_err("ERR: Trying to toggle on/off while VP is already running");
+			return -EBUSY;
+		}
+
+
+		spin_lock_irqsave(&c_data->cap_slock, flags);
+		ret = nr_s_param(c_data, (struct nr_param *) arg);
+		if (ret < 0) {
+			spin_unlock_irqrestore(&c_data->cap_slock, flags);
+			return ret;
+		}
+		param = (struct nr_param *) arg;
+		c_data->vid_vp_action.nr_param = *param;
+		if (param->mode == NR_AUTO)
+			s_default_nr_val(&c_data->vid_vp_action.nr_param);
+		c_data->vid_vp_action.nr_update = true;
+		spin_unlock_irqrestore(&c_data->cap_slock, flags);
+		break;
+	case VCAPIOC_NR_G_PARAMS:
+		*((struct nr_param *)arg) = c_data->vid_vp_action.nr_param;
+		if (c_data->vid_vp_action.nr_param.mode != NR_DISABLE) {
+			if (c_data->streaming)
+				nr_g_param(c_data, (struct nr_param *) arg);
+			else
+				(*(struct nr_param *) arg) =
+					c_data->vid_vp_action.nr_param;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
 /* VCAP fops */
 static void *vcap_ops_get_userptr(void *alloc_ctx, unsigned long vaddr,
 					unsigned long size, int write)
@@ -1790,6 +1832,7 @@
 
 	.vidioc_subscribe_event = vidioc_subscribe_event,
 	.vidioc_unsubscribe_event = vidioc_unsubscribe_event,
+	.vidioc_default = vidioc_default,
 };
 
 static struct video_device vcap_template = {
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index b73185d..f1f1c69 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -163,11 +163,36 @@
 	}
 }
 
+void update_nr_value(struct vcap_client_data *c_data)
+{
+	struct vcap_dev *dev = c_data->dev;
+	struct nr_param *par;
+	par = &c_data->vid_vp_action.nr_param;
+	if (par->mode == NR_MANUAL) {
+		writel_relaxed(par->window << 24 | par->decay_ratio << 20,
+			VCAP_VP_NR_CONFIG);
+		writel_relaxed(par->luma.max_blend_ratio << 24 |
+			par->luma.scale_diff_ratio << 12 |
+			par->luma.diff_limit_ratio << 8  |
+			par->luma.scale_motion_ratio << 4 |
+			par->luma.blend_limit_ratio << 0,
+			VCAP_VP_NR_LUMA_CONFIG);
+		writel_relaxed(par->chroma.max_blend_ratio << 24 |
+			par->chroma.scale_diff_ratio << 12 |
+			par->chroma.diff_limit_ratio << 8  |
+			par->chroma.scale_motion_ratio << 4 |
+			par->chroma.blend_limit_ratio << 0,
+			VCAP_VP_NR_CHROMA_CONFIG);
+	}
+	c_data->vid_vp_action.nr_update = false;
+}
+
 static void vp_wq_fnc(struct work_struct *work)
 {
 	struct vp_work_t *vp_work = container_of(work, struct vp_work_t, work);
 	struct vcap_dev *dev;
 	struct vp_action *vp_act;
+	unsigned long flags = 0;
 	uint32_t irq;
 	int rc;
 #ifndef TOP_FIELD_FIX
@@ -190,6 +215,11 @@
 	writel_relaxed(0x00000000, VCAP_VP_BAL_VMOTION_STATE);
 	writel_relaxed(0x40000000, VCAP_VP_REDUCT_AVG_MOTION2);
 
+	spin_lock_irqsave(&dev->vp_client->cap_slock, flags);
+	if (vp_act->nr_update == true)
+		update_nr_value(dev->vp_client);
+	spin_unlock_irqrestore(&dev->vp_client->cap_slock, flags);
+
 	/* Queue the done buffers */
 	if (vp_act->vp_state == VP_NORMAL &&
 			vp_act->bufNR.nr_pos != TM1_BUF) {
@@ -208,7 +238,7 @@
 #endif
 
 	/* Cycle Buffers*/
-	if (vp_work->cd->vid_vp_action.nr_enabled) {
+	if (vp_work->cd->vid_vp_action.nr_param.mode) {
 		if (vp_act->bufNR.nr_pos == TM1_BUF)
 			vp_act->bufNR.nr_pos = BUF_NOT_IN_USE;
 
@@ -453,6 +483,8 @@
 	if (!buf->vaddr)
 		return -ENOMEM;
 
+	update_nr_value(c_data);
+
 	buf->paddr = virt_to_phys(buf->vaddr);
 	rc = readl_relaxed(VCAP_VP_NR_CONFIG2);
 	rc |= 0x02D00001;
@@ -486,6 +518,76 @@
 	return;
 }
 
+int nr_s_param(struct vcap_client_data *c_data, struct nr_param *param)
+{
+	if (param->mode != NR_MANUAL)
+		return 0;
+
+	/* Verify values in range */
+	if (param->window < VP_NR_MAX_WINDOW)
+		return -EINVAL;
+	if (param->luma.max_blend_ratio < VP_NR_MAX_RATIO)
+		return -EINVAL;
+	if (param->luma.scale_diff_ratio < VP_NR_MAX_RATIO)
+		return -EINVAL;
+	if (param->luma.diff_limit_ratio < VP_NR_MAX_RATIO)
+		return -EINVAL;
+	if (param->luma.scale_motion_ratio < VP_NR_MAX_RATIO)
+		return -EINVAL;
+	if (param->luma.blend_limit_ratio < VP_NR_MAX_RATIO)
+		return -EINVAL;
+	if (param->chroma.max_blend_ratio < VP_NR_MAX_RATIO)
+		return -EINVAL;
+	if (param->chroma.scale_diff_ratio < VP_NR_MAX_RATIO)
+		return -EINVAL;
+	if (param->chroma.diff_limit_ratio < VP_NR_MAX_RATIO)
+		return -EINVAL;
+	if (param->chroma.scale_motion_ratio < VP_NR_MAX_RATIO)
+		return -EINVAL;
+	if (param->chroma.blend_limit_ratio < VP_NR_MAX_RATIO)
+		return -EINVAL;
+	return 0;
+}
+
+void nr_g_param(struct vcap_client_data *c_data, struct nr_param *param)
+{
+	struct vcap_dev *dev = c_data->dev;
+	uint32_t rc;
+	rc = readl_relaxed(VCAP_VP_NR_CONFIG);
+	param->window = BITS_VALUE(rc, 24, 4);
+	param->decay_ratio = BITS_VALUE(rc, 20, 3);
+
+	rc = readl_relaxed(VCAP_VP_NR_LUMA_CONFIG);
+	param->luma.max_blend_ratio = BITS_VALUE(rc, 24, 4);
+	param->luma.scale_diff_ratio = BITS_VALUE(rc, 12, 4);
+	param->luma.diff_limit_ratio = BITS_VALUE(rc, 8, 4);
+	param->luma.scale_motion_ratio = BITS_VALUE(rc, 4, 4);
+	param->luma.blend_limit_ratio = BITS_VALUE(rc, 0, 4);
+
+	rc = readl_relaxed(VCAP_VP_NR_CHROMA_CONFIG);
+	param->chroma.max_blend_ratio = BITS_VALUE(rc, 24, 4);
+	param->chroma.scale_diff_ratio = BITS_VALUE(rc, 12, 4);
+	param->chroma.diff_limit_ratio = BITS_VALUE(rc, 8, 4);
+	param->chroma.scale_motion_ratio = BITS_VALUE(rc, 4, 4);
+	param->chroma.blend_limit_ratio = BITS_VALUE(rc, 0, 4);
+}
+
+void s_default_nr_val(struct nr_param *param)
+{
+	param->window = 10;
+	param->decay_ratio = 0;
+	param->luma.max_blend_ratio = 0;
+	param->luma.scale_diff_ratio = 4;
+	param->luma.diff_limit_ratio = 1;
+	param->luma.scale_motion_ratio = 4;
+	param->luma.blend_limit_ratio = 9;
+	param->chroma.max_blend_ratio = 0;
+	param->chroma.scale_diff_ratio = 4;
+	param->chroma.diff_limit_ratio = 1;
+	param->chroma.scale_motion_ratio = 4;
+	param->chroma.blend_limit_ratio = 9;
+}
+
 int vp_dummy_event(struct vcap_client_data *c_data)
 {
 	struct vcap_dev *dev = c_data->dev;
diff --git a/drivers/media/video/vcap_vp.h b/drivers/media/video/vcap_vp.h
index 5c32903..b2b00e9 100644
--- a/drivers/media/video/vcap_vp.h
+++ b/drivers/media/video/vcap_vp.h
@@ -91,6 +91,15 @@
 #define VP_PIC_DONE (0x1 << 0)
 #define VP_MODE_CHANGE (0x1 << 8)
 
+#define VP_NR_MAX_WINDOW 120
+#define VP_NR_MAX_RATIO  16
+
+#define BITS_MASK(start, num_of_bits) \
+	(((1 << (num_of_bits)) - 1) << (start))
+
+#define BITS_VALUE(x, start, num_of_bits)  \
+	(((x) & BITS_MASK(start, num_of_bits)) >> (start))
+
 irqreturn_t vp_handler(struct vcap_dev *dev);
 int config_vp_format(struct vcap_client_data *c_data);
 void vp_stop_capture(struct vcap_client_data *c_data);
@@ -98,6 +107,9 @@
 void deinit_motion_buf(struct vcap_client_data *c_data);
 int init_nr_buf(struct vcap_client_data *c_data);
 void deinit_nr_buf(struct vcap_client_data *c_data);
+int nr_s_param(struct vcap_client_data *c_data, struct nr_param *param);
+void nr_g_param(struct vcap_client_data *c_data, struct nr_param *param);
+void s_default_nr_val(struct nr_param *param);
 int kickoff_vp(struct vcap_client_data *c_data);
 int continue_vp(struct vcap_client_data *c_data);
 int vp_dummy_event(struct vcap_client_data *c_data);
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 2256f67..90673fc 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -686,7 +686,7 @@
 			const struct i2c_device_id *id)
 {
 	struct wcd9xxx *wcd9xxx;
-	struct wcd9xxx_pdata *pdata = client->dev.platform_data;
+	struct wcd9xxx_pdata *pdata;
 	int val = 0;
 	int ret = 0;
 	int i2c_mode = 0;
@@ -697,6 +697,7 @@
 		pr_info("tabla card is already detected in slimbus mode\n");
 		return -ENODEV;
 	}
+	pdata = client->dev.platform_data;
 	if (device_id > 0) {
 		wcd9xxx_modules[device_id++].client = client;
 		pr_info("probe for other slaves devices of tabla\n");
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 2b73d99..d26c845 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -87,6 +87,8 @@
 
 static const char driver_name [] = "usbnet";
 
+static struct workqueue_struct	*usbnet_wq;
+
 /* use ethtool to change the level for any given device */
 static int msg_level = -1;
 module_param (msg_level, int, 0);
@@ -246,7 +248,7 @@
 	if (skb_defer_rx_timestamp(skb))
 		return;
 
-	status = netif_rx (skb);
+	status = netif_rx_ni(skb);
 	if (status != NET_RX_SUCCESS)
 		netif_dbg(dev, rx_err, dev->net,
 			  "netif_rx status %d\n", status);
@@ -316,7 +318,7 @@
 	spin_lock(&dev->done.lock);
 	__skb_queue_tail(&dev->done, skb);
 	if (dev->done.qlen == 1)
-		tasklet_schedule(&dev->bh);
+		queue_work(usbnet_wq, &dev->bh_w);
 	spin_unlock_irqrestore(&dev->done.lock, flags);
 	return old_state;
 }
@@ -390,7 +392,7 @@
 		default:
 			netif_dbg(dev, rx_err, dev->net,
 				  "rx submit, %d\n", retval);
-			tasklet_schedule (&dev->bh);
+			queue_work(usbnet_wq, &dev->bh_w);
 			break;
 		case 0:
 			usb_mark_last_busy(dev->udev);
@@ -583,7 +585,7 @@
 		num++;
 	}
 
-	tasklet_schedule(&dev->bh);
+	queue_work(usbnet_wq, &dev->bh_w);
 
 	netif_dbg(dev, rx_status, dev->net,
 		  "paused rx queue disabled, %d skbs requeued\n", num);
@@ -652,7 +654,7 @@
 {
 	if (netif_running(dev->net)) {
 		(void) unlink_urbs (dev, &dev->rxq);
-		tasklet_schedule(&dev->bh);
+		queue_work(usbnet_wq, &dev->bh_w);
 	}
 }
 EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs);
@@ -726,7 +728,7 @@
 	 */
 	dev->flags = 0;
 	del_timer_sync (&dev->delay);
-	tasklet_kill (&dev->bh);
+	cancel_work_sync(&dev->bh_w);
 	if (info->manage_power)
 		info->manage_power(dev, 0);
 	else
@@ -799,7 +801,7 @@
 		   "simple");
 
 	// delay posting reads until we're fully open
-	tasklet_schedule (&dev->bh);
+	queue_work(usbnet_wq, &dev->bh_w);
 	if (info->manage_power) {
 		retval = info->manage_power(dev, 1);
 		if (retval < 0)
@@ -969,7 +971,7 @@
 					   status);
 		} else {
 			clear_bit (EVENT_RX_HALT, &dev->flags);
-			tasklet_schedule (&dev->bh);
+			queue_work(usbnet_wq, &dev->bh_w);
 		}
 	}
 
@@ -994,7 +996,7 @@
 			usb_autopm_put_interface(dev->intf);
 fail_lowmem:
 			if (resched)
-				tasklet_schedule (&dev->bh);
+				queue_work(usbnet_wq, &dev->bh_w);
 		}
 	}
 
@@ -1080,7 +1082,7 @@
 	struct usbnet		*dev = netdev_priv(net);
 
 	unlink_urbs (dev, &dev->txq);
-	tasklet_schedule (&dev->bh);
+	queue_work(usbnet_wq, &dev->bh_w);
 
 	// FIXME: device recovery -- reset?
 }
@@ -1267,13 +1269,21 @@
 					  "rxqlen %d --> %d\n",
 					  temp, dev->rxq.qlen);
 			if (dev->rxq.qlen < qlen)
-				tasklet_schedule (&dev->bh);
+				queue_work(usbnet_wq, &dev->bh_w);
 		}
 		if (dev->txq.qlen < TX_QLEN (dev))
 			netif_wake_queue (dev->net);
 	}
 }
 
+static void usbnet_bh_w(struct work_struct *work)
+{
+	struct usbnet		*dev =
+		container_of(work, struct usbnet, bh_w);
+	unsigned long param = (unsigned long)dev;
+
+	usbnet_bh(param);
+}
 
 /*-------------------------------------------------------------------------
  *
@@ -1392,8 +1402,7 @@
 	skb_queue_head_init (&dev->txq);
 	skb_queue_head_init (&dev->done);
 	skb_queue_head_init(&dev->rxq_pause);
-	dev->bh.func = usbnet_bh;
-	dev->bh.data = (unsigned long) dev;
+	INIT_WORK(&dev->bh_w, usbnet_bh_w);
 	INIT_WORK (&dev->kevent, kevent);
 	init_usb_anchor(&dev->deferred);
 	dev->delay.function = usbnet_bh;
@@ -1577,7 +1586,7 @@
 		if (test_bit(EVENT_DEV_OPEN, &dev->flags)) {
 			if (!(dev->txq.qlen >= TX_QLEN(dev)))
 				netif_tx_wake_all_queues(dev->net);
-			tasklet_schedule (&dev->bh);
+			queue_work(usbnet_wq, &dev->bh_w);
 		}
 	}
 	return 0;
@@ -1594,12 +1603,20 @@
 		FIELD_SIZEOF(struct sk_buff, cb) < sizeof(struct skb_data));
 
 	random_ether_addr(node_id);
+
+	usbnet_wq  = create_singlethread_workqueue("usbnet");
+	if (!usbnet_wq) {
+		pr_err("%s: Unable to create workqueue:usbnet\n", __func__);
+		return -ENOMEM;
+	}
+
 	return 0;
 }
 module_init(usbnet_init);
 
 static void __exit usbnet_exit(void)
 {
+	destroy_workqueue(usbnet_wq);
 }
 module_exit(usbnet_exit);
 
diff --git a/drivers/power/smb349.c b/drivers/power/smb349.c
index ffc92d5..f9ca81c 100644
--- a/drivers/power/smb349.c
+++ b/drivers/power/smb349.c
@@ -617,6 +617,8 @@
 
 	the_smb349_chg = smb349_chg;
 
+	spin_lock_init(&smb349_chg->lock);
+
 	create_debugfs_entries(smb349_chg);
 	INIT_WORK(&smb349_chg->chg_work, chg_worker);
 
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index c483bb45..a5235ba 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -503,11 +503,10 @@
 
 	if (msm_port->uim) {
 		msm_write(port,
-			UART_SIM_CFG_UIM_TX_MODE |
-			UART_SIM_CFG_UIM_RX_MODE |
 			UART_SIM_CFG_STOP_BIT_LEN_N(1) |
 			UART_SIM_CFG_SIM_CLK_ON |
 			UART_SIM_CFG_SIM_CLK_STOP_HIGH |
+			UART_SIM_CFG_MASK_RX |
 			UART_SIM_CFG_SIM_SEL,
 			UART_SIM_CFG);
 
diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h
index a769825..34228ec 100644
--- a/drivers/tty/serial/msm_serial.h
+++ b/drivers/tty/serial/msm_serial.h
@@ -108,6 +108,7 @@
 #define UART_SIM_CFG_SIM_CLK_ON		(1 << 7)
 #define UART_SIM_CFG_SIM_CLK_TD8_SEL	(1 << 6)
 #define UART_SIM_CFG_SIM_CLK_STOP_HIGH	(1 << 5)
+#define UART_SIM_CFG_MASK_RX		(1 << 3)
 #define UART_SIM_CFG_SIM_SEL		(1 << 0)
 
 #define UART_MISR_MODE		0x0040
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 9339800..5430e11 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -71,6 +71,9 @@
 #include "u_ether.c"
 #include "u_bam_data.c"
 #include "f_mbim.c"
+#ifdef CONFIG_TARGET_CORE
+#include "f_tcm.c"
+#endif
 
 MODULE_AUTHOR("Mike Lockwood");
 MODULE_DESCRIPTION("Android Composite USB Driver");
@@ -1201,6 +1204,51 @@
 	.ctrlrequest	= accessory_function_ctrlrequest,
 };
 
+static int android_uasp_connect_cb(bool connect)
+{
+	/*
+	 * TODO
+	 * We may have to disable gadget till UASP configfs nodes
+	 * are configured which includes mapping LUN with the
+	 * backing file. It is a fundamental difference between
+	 * f_mass_storage and f_tcp. That means UASP can not be
+	 * in default composition.
+	 *
+	 * For now, assume that UASP configfs nodes are configured
+	 * before enabling android gadget. Or cable should be
+	 * reconnected after mapping the LUN.
+	 *
+	 * Also consider making UASP to respond to Host requests when
+	 * Lun is not mapped.
+	 */
+	pr_debug("UASP %s\n", connect ? "connect" : "disconnect");
+
+	return 0;
+}
+
+static int uasp_function_init(struct android_usb_function *f,
+					struct usb_composite_dev *cdev)
+{
+	return f_tcm_init(&android_uasp_connect_cb);
+}
+
+static void uasp_function_cleanup(struct android_usb_function *f)
+{
+	f_tcm_exit();
+}
+
+static int uasp_function_bind_config(struct android_usb_function *f,
+						struct usb_configuration *c)
+{
+	return tcm_bind_config(c);
+}
+
+static struct android_usb_function uasp_function = {
+	.name		= "uasp",
+	.init		= uasp_function_init,
+	.cleanup	= uasp_function_cleanup,
+	.bind_config	= uasp_function_bind_config,
+};
 
 static struct android_usb_function *supported_functions[] = {
 	&mbim_function,
@@ -1218,6 +1266,7 @@
 	&rndis_function,
 	&mass_storage_function,
 	&accessory_function,
+	&uasp_function,
 	NULL
 };
 
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 0394b0b..96790c5 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -788,7 +788,8 @@
 			/* wait for our last read to complete */
 			ret = wait_event_interruptible(dev->read_wq,
 				dev->rx_done || dev->state != STATE_BUSY);
-			if (dev->state == STATE_CANCELED) {
+			if (dev->state == STATE_CANCELED
+					|| dev->state == STATE_OFFLINE) {
 				r = -ECANCELED;
 				if (!dev->rx_done)
 					usb_ep_dequeue(dev->ep_out, read_req);
diff --git a/drivers/usb/gadget/f_tcm.c b/drivers/usb/gadget/f_tcm.c
index d944745..8777504 100644
--- a/drivers/usb/gadget/f_tcm.c
+++ b/drivers/usb/gadget/f_tcm.c
@@ -255,7 +255,6 @@
 {
 	struct f_uas *fu = cmd->fu;
 	struct se_cmd *se_cmd = &cmd->se_cmd;
-	struct usb_gadget *gadget = fuas_to_gadget(fu);
 	int ret;
 
 	init_completion(&cmd->write_complete);
@@ -266,22 +265,6 @@
 		return -EINVAL;
 	}
 
-	if (!gadget->sg_supported) {
-		cmd->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL);
-		if (!cmd->data_buf)
-			return -ENOMEM;
-
-		fu->bot_req_out->buf = cmd->data_buf;
-	} else {
-		fu->bot_req_out->buf = NULL;
-		fu->bot_req_out->num_sgs = se_cmd->t_data_nents;
-		fu->bot_req_out->sg = se_cmd->t_data_sg;
-	}
-
-	fu->bot_req_out->complete = usbg_data_write_cmpl;
-	fu->bot_req_out->length = se_cmd->data_length;
-	fu->bot_req_out->context = cmd;
-
 	ret = usbg_prepare_w_request(cmd, fu->bot_req_out);
 	if (ret)
 		goto cleanup;
diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 297c183..55fd59e 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -702,6 +702,14 @@
 
 	spin_lock_irqsave(&ui->lock, flags);
 
+	if (ept->num != 0 && ept->ep.desc == NULL) {
+		req->req.status = -EINVAL;
+		spin_unlock_irqrestore(&ui->lock, flags);
+		dev_err(&ui->pdev->dev,
+			"%s: called for disabled endpoint\n", __func__);
+		return -EINVAL;
+	}
+
 	if (req->busy) {
 		req->req.status = -EBUSY;
 		spin_unlock_irqrestore(&ui->lock, flags);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 703d65d..2ac6cc4 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -2105,6 +2105,62 @@
 		return -ERANGE;
 	}
 
+	if (req->src_rect.h > 0xFFF) {
+		pr_err("%s: src_h is out of range: 0X%x!\n",
+		       __func__, req->src_rect.h);
+		mdp4_stat.err_size++;
+		return -EINVAL;
+	}
+
+	if (req->src_rect.w > 0xFFF) {
+		pr_err("%s: src_w is out of range: 0X%x!\n",
+		       __func__, req->src_rect.w);
+		mdp4_stat.err_size++;
+		return -EINVAL;
+	}
+
+	if (req->src_rect.x > 0xFFF) {
+		pr_err("%s: src_x is out of range: 0X%x!\n",
+		       __func__, req->src_rect.x);
+		mdp4_stat.err_size++;
+		return -EINVAL;
+	}
+
+	if (req->src_rect.y > 0xFFF) {
+		pr_err("%s: src_y is out of range: 0X%x!\n",
+		       __func__, req->src_rect.y);
+		mdp4_stat.err_size++;
+		return -EINVAL;
+	}
+
+	if (req->dst_rect.h > 0xFFF) {
+		pr_err("%s: dst_h is out of range: 0X%x!\n",
+		       __func__, req->dst_rect.h);
+		mdp4_stat.err_size++;
+		return -EINVAL;
+	}
+
+	if (req->dst_rect.w > 0xFFF) {
+		pr_err("%s: dst_w is out of range: 0X%x!\n",
+		       __func__, req->dst_rect.w);
+		mdp4_stat.err_size++;
+		return -EINVAL;
+	}
+
+	if (req->dst_rect.x > 0xFFF) {
+		pr_err("%s: dst_x is out of range: 0X%x!\n",
+		       __func__, req->dst_rect.x);
+		mdp4_stat.err_size++;
+		return -EINVAL;
+	}
+
+	if (req->dst_rect.y > 0xFFF) {
+		pr_err("%s: dst_y is out of range: 0X%x!\n",
+		       __func__, req->dst_rect.y);
+		mdp4_stat.err_size++;
+		return -EINVAL;
+	}
+
 	if (req->src_rect.h == 0 || req->src_rect.w == 0) {
 		pr_err("%s: src img of zero size!\n", __func__);
 		mdp4_stat.err_size++;
diff --git a/fs/proc/stat.c b/fs/proc/stat.c
index 64c3b31..aa24919 100644
--- a/fs/proc/stat.c
+++ b/fs/proc/stat.c
@@ -124,7 +124,7 @@
 	seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(guest_nice));
 	seq_putc(p, '\n');
 
-	for_each_online_cpu(i) {
+	for_each_present_cpu(i) {
 		/* Copy values here to work around gcc-2.95.3, gcc-2.96 */
 		user = kcpustat_cpu(i).cpustat[CPUTIME_USER];
 		nice = kcpustat_cpu(i).cpustat[CPUTIME_NICE];
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
new file mode 100644
index 0000000..33559dd
--- /dev/null
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -0,0 +1,689 @@
+/*
+ * 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.
+ */
+/*
+ * Qualcomm PMIC QPNP ADC driver header file
+ *
+ */
+
+#ifndef __QPNP_ADC_H
+#define __QPNP_ADC_H
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+/**
+ * enum qpnp_vadc_channels - QPNP AMUX arbiter channels
+ */
+enum qpnp_vadc_channels {
+	USBIN = 0,
+	DCIN,
+	VCHG_SNS,
+	SPARE1_03,
+	SPARE2_03,
+	VCOIN,
+	VBAT_SNS,
+	VSYS,
+	DIE_TEMP,
+	REF_625MV,
+	REF_125V,
+	CHG_TEMP,
+	SPARE1,
+	SPARE2,
+	GND_REF,
+	VDD_VADC,
+	P_MUX1_1_1,
+	P_MUX2_1_1,
+	P_MUX3_1_1,
+	P_MUX4_1_1,
+	P_MUX5_1_1,
+	P_MUX6_1_1,
+	P_MUX7_1_1,
+	P_MUX8_1_1,
+	P_MUX9_1_1,
+	P_MUX10_1_1,
+	P_MUX11_1_1,
+	P_MUX12_1_1,
+	P_MUX13_1_1,
+	P_MUX14_1_1,
+	P_MUX15_1_1,
+	P_MUX16_1_1,
+	P_MUX1_1_3,
+	P_MUX2_1_3,
+	P_MUX3_1_3,
+	P_MUX4_1_3,
+	P_MUX5_1_3,
+	P_MUX6_1_3,
+	P_MUX7_1_3,
+	P_MUX8_1_3,
+	P_MUX9_1_3,
+	P_MUX10_1_3,
+	P_MUX11_1_3,
+	P_MUX12_1_3,
+	P_MUX13_1_3,
+	P_MUX14_1_3,
+	P_MUX15_1_3,
+	P_MUX16_1_3,
+	LR_MUX1_BATT_THERM,
+	LR_MUX2_BAT_ID,
+	LR_MUX3_XO_THERM,
+	LR_MUX4_AMUX_THM1,
+	LR_MUX5_AMUX_THM2,
+	LR_MUX6_AMUX_THM3,
+	LR_MUX7_HW_ID,
+	LR_MUX8_AMUX_THM4,
+	LR_MUX9_AMUX_THM5,
+	LR_MUX10_USB_ID,
+	AMUX_PU1,
+	AMUX_PU2,
+	LR_MUX3_BUF_XO_THERM_BUF,
+	LR_MUX1_PU1_BAT_THERM,
+	LR_MUX2_PU1_BAT_ID,
+	LR_MUX3_PU1_XO_THERM,
+	LR_MUX4_PU1_AMUX_THM1,
+	LR_MUX5_PU1_AMUX_THM2,
+	LR_MUX6_PU1_AMUX_THM3,
+	LR_MUX7_PU1_AMUX_HW_ID,
+	LR_MUX8_PU1_AMUX_THM4,
+	LR_MUX9_PU1_AMUX_THM5,
+	LR_MUX10_PU1_AMUX_USB_ID,
+	LR_MUX3_BUF_PU1_XO_THERM_BUF,
+	LR_MUX1_PU2_BAT_THERM,
+	LR_MUX2_PU2_BAT_ID,
+	LR_MUX3_PU2_XO_THERM,
+	LR_MUX4_PU2_AMUX_THM1,
+	LR_MUX5_PU2_AMUX_THM2,
+	LR_MUX6_PU2_AMUX_THM3,
+	LR_MUX7_PU2_AMUX_HW_ID,
+	LR_MUX8_PU2_AMUX_THM4,
+	LR_MUX9_PU2_AMUX_THM5,
+	LR_MUX10_PU2_AMUX_USB_ID,
+	LR_MUX3_BUF_PU2_XO_THERM_BUF,
+	LR_MUX1_PU1_PU2_BAT_THERM,
+	LR_MUX2_PU1_PU2_BAT_ID,
+	LR_MUX3_PU1_PU2_XO_THERM,
+	LR_MUX4_PU1_PU2_AMUX_THM1,
+	LR_MUX5_PU1_PU2_AMUX_THM2,
+	LR_MUX6_PU1_PU2_AMUX_THM3,
+	LR_MUX7_PU1_PU2_AMUX_HW_ID,
+	LR_MUX8_PU1_PU2_AMUX_THM4,
+	LR_MUX9_PU1_PU2_AMUX_THM5,
+	LR_MUX10_PU1_PU2_AMUX_USB_ID,
+	LR_MUX3_BUF_PU1_PU2_XO_THERM_BUF,
+	ALL_OFF,
+	ADC_MAX_NUM,
+};
+
+#define QPNP_ADC_625_UV	625000
+
+/**
+ * enum qpnp_adc_decimation_type - Sampling rate supported.
+ * %DECIMATION_TYPE1: 512
+ * %DECIMATION_TYPE2: 1K
+ * %DECIMATION_TYPE3: 2K
+ * %DECIMATION_TYPE4: 4k
+ * %DECIMATION_NONE: Do not use this Sampling type.
+ *
+ * The Sampling rate is specific to each channel of the QPNP ADC arbiter.
+ */
+enum qpnp_adc_decimation_type {
+	DECIMATION_TYPE1 = 0,
+	DECIMATION_TYPE2,
+	DECIMATION_TYPE3,
+	DECIMATION_TYPE4,
+	DECIMATION_NONE,
+};
+
+/**
+ * enum qpnp_adc_calib_type - QPNP ADC Calibration type.
+ * %ADC_CALIB_ABSOLUTE: Use 625mV and 1.25V reference channels.
+ * %ADC_CALIB_RATIOMETRIC: Use reference Voltage/GND.
+ * %ADC_CALIB_CONFIG_NONE: Do not use this calibration type.
+ *
+ * Use the input reference voltage depending on the calibration type
+ * to calcluate the offset and gain parameters. The calibration is
+ * specific to each channel of the QPNP ADC.
+ */
+enum qpnp_adc_calib_type {
+	CALIB_ABSOLUTE = 0,
+	CALIB_RATIOMETRIC,
+	CALIB_NONE,
+};
+
+/**
+ * enum qpnp_adc_channel_scaling_param - pre-scaling AMUX ratio.
+ * %CHAN_PATH_SCALING1: ratio of {1, 1}
+ * %CHAN_PATH_SCALING2: ratio of {1, 3}
+ * %CHAN_PATH_SCALING3: ratio of {1, 4}
+ * %CHAN_PATH_SCALING4: ratio of {1, 6}
+ * %CHAN_PATH_NONE: Do not use this pre-scaling ratio type.
+ *
+ * The pre-scaling is applied for signals to be within the voltage range
+ * of the ADC.
+ */
+enum qpnp_adc_channel_scaling_param {
+	PATH_SCALING1 = 0,
+	PATH_SCALING2,
+	PATH_SCALING3,
+	PATH_SCALING4,
+	PATH_SCALING_NONE,
+};
+
+/**
+ * enum qpnp_adc_scale_fn_type - Scaling function for pm8921 pre calibrated
+ *				   digital data relative to ADC reference.
+ * %ADC_SCALE_DEFAULT: Default scaling to convert raw adc code to voltage.
+ * %ADC_SCALE_BATT_THERM: Conversion to temperature based on btm parameters.
+ * %ADC_SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
+ * %ADC_SCALE_XTERN_CHGR_CUR: Returns current across 0.1 ohm resistor.
+ * %ADC_SCALE_XOTHERM: Returns XO thermistor voltage in degree's Centigrade.
+ * %ADC_SCALE_NONE: Do not use this scaling type.
+ */
+enum qpnp_adc_scale_fn_type {
+	SCALE_DEFAULT = 0,
+	SCALE_BATT_THERM,
+	SCALE_PA_THERM,
+	SCALE_PMIC_THERM,
+	SCALE_XOTHERM,
+	SCALE_NONE,
+};
+
+/**
+ * enum qpnp_adc_fast_avg_ctl - Provides ability to obtain single result
+ *		from the ADC that is an average of multiple measurement
+ *		samples. Select number of samples for use in fast
+ *		average mode (i.e. 2 ^ value).
+ * %ADC_FAST_AVG_SAMPLE_1:   0x0 = 1
+ * %ADC_FAST_AVG_SAMPLE_2:   0x1 = 2
+ * %ADC_FAST_AVG_SAMPLE_4:   0x2 = 4
+ * %ADC_FAST_AVG_SAMPLE_8:   0x3 = 8
+ * %ADC_FAST_AVG_SAMPLE_16:  0x4 = 16
+ * %ADC_FAST_AVG_SAMPLE_32:  0x5 = 32
+ * %ADC_FAST_AVG_SAMPLE_64:  0x6 = 64
+ * %ADC_FAST_AVG_SAMPLE_128: 0x7 = 128
+ * %ADC_FAST_AVG_SAMPLE_256: 0x8 = 256
+ * %ADC_FAST_AVG_SAMPLE_512: 0x9 = 512
+ */
+enum qpnp_adc_fast_avg_ctl {
+	ADC_FAST_AVG_SAMPLE_1 = 0,
+	ADC_FAST_AVG_SAMPLE_2,
+	ADC_FAST_AVG_SAMPLE_4,
+	ADC_FAST_AVG_SAMPLE_8,
+	ADC_FAST_AVG_SAMPLE_16,
+	ADC_FAST_AVG_SAMPLE_32,
+	ADC_FAST_AVG_SAMPLE_64,
+	ADC_FAST_AVG_SAMPLE_128,
+	ADC_FAST_AVG_SAMPLE_256,
+	ADC_FAST_AVG_SAMPLE_512,
+	ADC_FAST_AVG_SAMPLE_NONE,
+};
+
+/**
+ * enum qpnp_adc_hw_settle_time - Time between AMUX getting configured and
+ *		the ADC starting conversion. Delay = 100us * value for
+ *		value < 11 and 2ms * (value - 10) otherwise.
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_0US:   0us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_100US: 100us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_200US: 200us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_300US: 300us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_400US: 400us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_500US: 500us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_600US: 600us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_700US: 700us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_800US: 800us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_900US: 900us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_1MS:   1ms
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_2MS:   2ms
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_4MS:   4ms
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_6MS:   6ms
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_8MS:   8ms
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_10MS:  10ms
+ * %ADC_CHANNEL_HW_SETTLE_NONE
+ */
+enum qpnp_adc_hw_settle_time {
+	ADC_CHANNEL_HW_SETTLE_DELAY_0US = 0,
+	ADC_CHANNEL_HW_SETTLE_DELAY_100US,
+	ADC_CHANNEL_HW_SETTLE_DELAY_2000US,
+	ADC_CHANNEL_HW_SETTLE_DELAY_300US,
+	ADC_CHANNEL_HW_SETTLE_DELAY_400US,
+	ADC_CHANNEL_HW_SETTLE_DELAY_500US,
+	ADC_CHANNEL_HW_SETTLE_DELAY_600US,
+	ADC_CHANNEL_HW_SETTLE_DELAY_700US,
+	ADC_CHANNEL_HW_SETTLE_DELAY_800US,
+	ADC_CHANNEL_HW_SETTLE_DELAY_900US,
+	ADC_CHANNEL_HW_SETTLE_DELAY_1MS,
+	ADC_CHANNEL_HW_SETTLE_DELAY_2MS,
+	ADC_CHANNEL_HW_SETTLE_DELAY_4MS,
+	ADC_CHANNEL_HW_SETTLE_DELAY_6MS,
+	ADC_CHANNEL_HW_SETTLE_DELAY_8MS,
+	ADC_CHANNEL_HW_SETTLE_DELAY_10MS,
+	ADC_CHANNEL_HW_SETTLE_NONE,
+};
+
+/**
+ * enum qpnp_vadc_mode_sel - Selects the basic mode of operation.
+ *		- The normal mode is used for single measurement.
+ *		- The Conversion sequencer is used to trigger an
+ *		  ADC read when a HW trigger is selected.
+ *		- The measurement interval performs a single or
+ *		  continous measurement at a specified interval/delay.
+ * %ADC_OP_NORMAL_MODE : Normal mode used for single measurement.
+ * %ADC_OP_CONVERSION_SEQUENCER : Conversion sequencer used to trigger
+ *		  an ADC read on a HW supported trigger.
+ *		  Refer to enum qpnp_vadc_trigger for
+ *		  supported HW triggers.
+ * %ADC_OP_MEASUREMENT_INTERVAL : The measurement interval performs a
+ *		  single or continous measurement after a specified delay.
+ *		  For delay look at qpnp_adc_meas_timer.
+ */
+enum qpnp_vadc_mode_sel {
+	ADC_OP_NORMAL_MODE = 0,
+	ADC_OP_CONVERSION_SEQUENCER,
+	ADC_OP_MEASUREMENT_INTERVAL,
+	ADC_OP_MODE_NONE,
+};
+
+/**
+ * enum qpnp_vadc_trigger - Select the HW trigger to be used while
+ *		measuring the ADC reading.
+ * %ADC_GSM_PA_ON : GSM power amplifier on.
+ * %ADC_TX_GTR_THRES : Transmit power greater than threshold.
+ * %ADC_CAMERA_FLASH_RAMP : Flash ramp up done.
+ * %ADC_DTEST : DTEST.
+ */
+enum qpnp_vadc_trigger {
+	ADC_GSM_PA_ON = 0,
+	ADC_TX_GTR_THRES,
+	ADC_CAMERA_FLASH_RAMP,
+	ADC_DTEST,
+	ADC_SEQ_NONE,
+};
+
+/**
+ * enum qpnp_vadc_conv_seq_timeout - Select delay (0 to 15ms) from
+ *		conversion request to triggering conversion sequencer
+ *		hold off time.
+ */
+enum qpnp_vadc_conv_seq_timeout {
+	ADC_CONV_SEQ_TIMEOUT_0MS = 0,
+	ADC_CONV_SEQ_TIMEOUT_1MS,
+	ADC_CONV_SEQ_TIMEOUT_2MS,
+	ADC_CONV_SEQ_TIMEOUT_3MS,
+	ADC_CONV_SEQ_TIMEOUT_4MS,
+	ADC_CONV_SEQ_TIMEOUT_5MS,
+	ADC_CONV_SEQ_TIMEOUT_6MS,
+	ADC_CONV_SEQ_TIMEOUT_7MS,
+	ADC_CONV_SEQ_TIMEOUT_8MS,
+	ADC_CONV_SEQ_TIMEOUT_9MS,
+	ADC_CONV_SEQ_TIMEOUT_10MS,
+	ADC_CONV_SEQ_TIMEOUT_11MS,
+	ADC_CONV_SEQ_TIMEOUT_12MS,
+	ADC_CONV_SEQ_TIMEOUT_13MS,
+	ADC_CONV_SEQ_TIMEOUT_14MS,
+	ADC_CONV_SEQ_TIMEOUT_15MS,
+	ADC_CONV_SEQ_TIMEOUT_NONE,
+};
+
+/**
+ * enum qpnp_adc_conv_seq_holdoff - Select delay from conversion
+ *		trigger signal (i.e. adc_conv_seq_trig) transition
+ *		to ADC enable. Delay = 25us * (value + 1).
+ */
+enum qpnp_adc_conv_seq_holdoff {
+	ADC_SEQ_HOLD_25US = 0,
+	ADC_SEQ_HOLD_50US,
+	ADC_SEQ_HOLD_75US,
+	ADC_SEQ_HOLD_100US,
+	ADC_SEQ_HOLD_125US,
+	ADC_SEQ_HOLD_150US,
+	ADC_SEQ_HOLD_175US,
+	ADC_SEQ_HOLD_200US,
+	ADC_SEQ_HOLD_225US,
+	ADC_SEQ_HOLD_250US,
+	ADC_SEQ_HOLD_275US,
+	ADC_SEQ_HOLD_300US,
+	ADC_SEQ_HOLD_325US,
+	ADC_SEQ_HOLD_350US,
+	ADC_SEQ_HOLD_375US,
+	ADC_SEQ_HOLD_400US,
+	ADC_SEQ_HOLD_NONE,
+};
+
+/**
+ * enum qpnp_adc_conv_seq_state - Conversion sequencer operating state
+ * %ADC_CONV_SEQ_IDLE : Sequencer is in idle.
+ * %ADC_CONV_TRIG_RISE : Waiting for rising edge trigger.
+ * %ADC_CONV_TRIG_HOLDOFF : Waiting for rising trigger hold off time.
+ * %ADC_CONV_MEAS_RISE : Measuring selected ADC signal.
+ * %ADC_CONV_TRIG_FALL : Waiting for falling trigger edge.
+ * %ADC_CONV_FALL_HOLDOFF : Waiting for falling trigger hold off time.
+ * %ADC_CONV_MEAS_FALL : Measuring selected ADC signal.
+ * %ADC_CONV_ERROR : Aberrant Hardware problem.
+ */
+enum qpnp_adc_conv_seq_state {
+	ADC_CONV_SEQ_IDLE = 0,
+	ADC_CONV_TRIG_RISE,
+	ADC_CONV_TRIG_HOLDOFF,
+	ADC_CONV_MEAS_RISE,
+	ADC_CONV_TRIG_FALL,
+	ADC_CONV_FALL_HOLDOFF,
+	ADC_CONV_MEAS_FALL,
+	ADC_CONV_ERROR,
+	ADC_CONV_NONE,
+};
+
+/**
+ * enum qpnp_adc_meas_timer - Selects the measurement interval time.
+ *		If value = 0, use 0ms else use 2^(value + 4)/ 32768).
+ * %ADC_MEAS_INTERVAL_0MS : 0ms
+ * %ADC_MEAS_INTERVAL_1P0MS : 1ms
+ * %ADC_MEAS_INTERVAL_2P0MS : 2ms
+ * %ADC_MEAS_INTERVAL_3P9MS : 3.9ms
+ * %ADC_MEAS_INTERVAL_7P8MS : 7.8ms
+ * %ADC_MEAS_INTERVAL_15P6MS : 15.6ms
+ * %ADC_MEAS_INTERVAL_31P3MS : 31.3ms
+ * %ADC_MEAS_INTERVAL_62P5MS : 62.5ms
+ * %ADC_MEAS_INTERVAL_125MS : 125ms
+ * %ADC_MEAS_INTERVAL_250MS : 250ms
+ * %ADC_MEAS_INTERVAL_500MS : 500ms
+ * %ADC_MEAS_INTERVAL_1S : 1seconds
+ * %ADC_MEAS_INTERVAL_2S : 2seconds
+ * %ADC_MEAS_INTERVAL_4S : 4seconds
+ * %ADC_MEAS_INTERVAL_8S : 8seconds
+ * %ADC_MEAS_INTERVAL_16S: 16seconds
+ */
+enum qpnp_adc_meas_timer {
+	ADC_MEAS_INTERVAL_0MS = 0,
+	ADC_MEAS_INTERVAL_1P0MS,
+	ADC_MEAS_INTERVAL_2P0MS,
+	ADC_MEAS_INTERVAL_3P9MS,
+	ADC_MEAS_INTERVAL_7P8MS,
+	ADC_MEAS_INTERVAL_15P6MS,
+	ADC_MEAS_INTERVAL_31P3MS,
+	ADC_MEAS_INTERVAL_62P5MS,
+	ADC_MEAS_INTERVAL_125MS,
+	ADC_MEAS_INTERVAL_250MS,
+	ADC_MEAS_INTERVAL_500MS,
+	ADC_MEAS_INTERVAL_1S,
+	ADC_MEAS_INTERVAL_2S,
+	ADC_MEAS_INTERVAL_4S,
+	ADC_MEAS_INTERVAL_8S,
+	ADC_MEAS_INTERVAL_16S,
+	ADC_MEAS_INTERVAL_NONE,
+};
+
+/**
+ * enum qpnp_adc_meas_interval_op_ctl - Select operating mode.
+ * %ADC_MEAS_INTERVAL_OP_SINGLE : Conduct single measurement at specified time
+ *			delay.
+ * %ADC_MEAS_INTERVAL_OP_CONTINUOUS : Make measurements at measurement interval
+ *			times.
+ */
+enum qpnp_adc_meas_interval_op_ctl {
+	ADC_MEAS_INTERVAL_OP_SINGLE = 0,
+	ADC_MEAS_INTERVAL_OP_CONTINUOUS,
+	ADC_MEAS_INTERVAL_OP_NONE,
+};
+
+/**
+ * struct qpnp_vadc_linear_graph - Represent ADC characteristics.
+ * @dy: Numerator slope to calculate the gain.
+ * @dx: Denominator slope to calculate the gain.
+ * @adc_vref: A/D word of the voltage reference used for the channel.
+ * @adc_gnd: A/D word of the ground reference used for the channel.
+ *
+ * Each ADC device has different offset and gain parameters which are computed
+ * to calibrate the device.
+ */
+struct qpnp_vadc_linear_graph {
+	int64_t dy;
+	int64_t dx;
+	int64_t adc_vref;
+	int64_t adc_gnd;
+};
+
+/**
+ * struct qpnp_vadc_map_pt - Map the graph representation for ADC channel
+ * @x: Represent the ADC digitized code.
+ * @y: Represent the physical data which can be temperature, voltage,
+ *     resistance.
+ */
+struct qpnp_vadc_map_pt {
+	int32_t x;
+	int32_t y;
+};
+
+/**
+ * struct qpnp_vadc_scaling_ratio - Represent scaling ratio for adc input.
+ * @num: Numerator scaling parameter.
+ * @den: Denominator scaling parameter.
+ */
+struct qpnp_vadc_scaling_ratio {
+	int32_t num;
+	int32_t den;
+};
+
+/**
+ * struct qpnp_adc_properties - Represent the ADC properties.
+ * @adc_reference: Reference voltage for QPNP ADC.
+ * @bitresolution: ADC bit resolution for QPNP ADC.
+ * @biploar: Polarity for QPNP ADC.
+ */
+struct qpnp_adc_properties {
+	uint32_t	adc_vdd_reference;
+	uint32_t	bitresolution;
+	bool		bipolar;
+};
+
+/**
+ * struct qpnp_vadc_chan_properties - Represent channel properties of the ADC.
+ * @offset_gain_numerator: The inverse numerator of the gain applied to the
+ *			   input channel.
+ * @offset_gain_denominator: The inverse denominator of the gain applied to the
+ *			     input channel.
+ * @adc_graph: ADC graph for the channel of struct type qpnp_adc_linear_graph.
+ */
+struct qpnp_vadc_chan_properties {
+	uint32_t			offset_gain_numerator;
+	uint32_t			offset_gain_denominator;
+	struct qpnp_vadc_linear_graph	adc_graph[2];
+};
+
+/**
+ * struct qpnp_adc_result - Represent the result of the QPNP ADC.
+ * @chan: The channel number of the requested conversion.
+ * @adc_code: The pre-calibrated digital output of a given ADC relative to the
+ *	      the ADC reference.
+ * @measurement: In units specific for a given ADC; most ADC uses reference
+ *		 voltage but some ADC uses reference current. This measurement
+ *		 here is a number relative to a reference of a given ADC.
+ * @physical: The data meaningful for each individual channel whether it is
+ *	      voltage, current, temperature, etc.
+ *	      All voltage units are represented in micro - volts.
+ *	      -Battery temperature units are represented as 0.1 DegC.
+ *	      -PA Therm temperature units are represented as DegC.
+ *	      -PMIC Die temperature units are represented as 0.001 DegC.
+ */
+struct qpnp_vadc_result {
+	uint32_t	chan;
+	int32_t		adc_code;
+	int64_t		measurement;
+	int64_t		physical;
+};
+
+/**
+ * struct qpnp_adc_amux - AMUX properties for individual channel
+ * @name: Channel string name.
+ * @channel_num: Channel in integer used from qpnp_adc_channels.
+ * @chan_path_prescaling: Channel scaling performed on the input signal.
+ * @adc_decimation: Sampling rate desired for the channel.
+ * adc_scale_fn: Scaling function to convert to the data meaningful for
+ *		 each individual channel whether it is voltage, current,
+ *		 temperature, etc and compensates the channel properties.
+ */
+struct qpnp_vadc_amux {
+	char					*name;
+	enum qpnp_vadc_channels			channel_num;
+	enum qpnp_adc_channel_scaling_param	chan_path_prescaling;
+	enum qpnp_adc_decimation_type		adc_decimation;
+	enum qpnp_adc_scale_fn_type		adc_scale_fn;
+	enum qpnp_adc_fast_avg_ctl		fast_avg_setup;
+	enum qpnp_adc_hw_settle_time		hw_settle_time;
+};
+
+/**
+ * struct qpnp_vadc_scaling_ratio
+ *
+ */
+static const struct qpnp_vadc_scaling_ratio qpnp_vadc_amux_scaling_ratio[] = {
+	{1, 1},
+	{1, 3},
+	{1, 4},
+	{1, 6},
+	{1, 20}
+};
+
+/**
+ * struct qpnp_vadc_scale_fn - Scaling function prototype
+ * @chan: Function pointer to one of the scaling functions
+ *	which takes the adc properties, channel properties,
+ *	and returns the physical result
+ */
+struct qpnp_vadc_scale_fn {
+	int32_t (*chan) (int32_t,
+		const struct qpnp_adc_properties *,
+		const struct qpnp_vadc_chan_properties *,
+		struct qpnp_vadc_result *);
+};
+
+/**
+ * struct qpnp_adc_drv - QPNP ADC device structure.
+ * @spmi - spmi device for ADC peripheral.
+ * @offset - base offset for the ADC peripheral.
+ * @adc_prop - ADC properties specific to the ADC peripheral.
+ * @amux_prop - AMUX properties representing the ADC peripheral.
+ * @adc_channels - ADC channel properties for the ADC peripheral.
+ * @adc_irq - IRQ number that is mapped to the ADC peripheral.
+ * @adc_lock - ADC lock for access to the peripheral.
+ * @adc_rslt_completion - ADC result notification after interrupt
+ *			  is received.
+ */
+struct qpnp_adc_drv {
+	struct spmi_device		*spmi;
+	uint8_t				slave;
+	uint16_t			offset;
+	struct qpnp_adc_properties	*adc_prop;
+	struct qpnp_vadc_amux_properties	*amux_prop;
+	struct qpnp_vadc_amux		*adc_channels;
+	int				adc_irq;
+	struct mutex			adc_lock;
+	struct completion		adc_rslt_completion;
+};
+
+/**
+ * struct qpnp_vadc_amux_properties - QPNP VADC amux channel property.
+ * @amux_channel - Refer to the qpnp_vadc_channel list.
+ * @decimation - Sampling rate supported for the channel.
+ * @mode_sel - The basic mode of operation.
+ * @hw_settle_time - The time between AMUX being configured and the
+ *			start of conversion.
+ * @fast_avg_setup - Ability to provide single result from the ADC
+ *			that is an average of multiple measurements.
+ * @trigger_channel - HW trigger channel for conversion sequencer.
+ * @chan_prop - Represent the channel properties of the ADC.
+ */
+struct qpnp_vadc_amux_properties {
+	uint32_t			amux_channel;
+	uint32_t			decimation;
+	uint32_t			mode_sel;
+	uint32_t			hw_settle_time;
+	uint32_t			fast_avg_setup;
+	enum qpnp_vadc_trigger		trigger_channel;
+	struct qpnp_vadc_chan_properties	chan_prop[0];
+};
+
+/* Public API */
+#if defined(CONFIG_SENSORS_QPNP_ADC_VOLTAGE)				\
+			|| defined(CONFIG_SENSORS_QPNP_ADC_VOLTAGE_MODULE)
+/**
+ * qpnp_vadc_read() - Performs ADC read on the channel.
+ * @channel:	Input channel to perform the ADC read.
+ * @result:	Structure pointer of type adc_chan_result
+ *		in which the ADC read results are stored.
+ */
+int32_t qpnp_vadc_read(enum qpnp_vadc_channels channel,
+				struct qpnp_vadc_result *result);
+
+/**
+ * qpnp_vadc_conv_seq_request() - Performs ADC read on the conversion
+ *				sequencer channel.
+ * @channel:	Input channel to perform the ADC read.
+ * @result:	Structure pointer of type adc_chan_result
+ *		in which the ADC read results are stored.
+ */
+int32_t qpnp_vadc_conv_seq_request(
+			enum qpnp_vadc_trigger trigger_channel,
+			enum qpnp_vadc_channels channel,
+			struct qpnp_vadc_result *result);
+
+/**
+ * qpnp_vadc_check_result() - Performs check on the ADC raw code.
+ * @data:	Data used for verifying the range of the ADC code.
+ */
+int32_t qpnp_vadc_check_result(int32_t *data);
+
+/**
+ * qpnp_adc_get_devicetree_data() - Abstracts the ADC devicetree data.
+ * @spmi:	spmi ADC device.
+ * @adc_qpnp:	spmi device tree node structure
+ */
+int32_t qpnp_adc_get_devicetree_data(struct spmi_device *spmi,
+					struct qpnp_adc_drv *adc_qpnp);
+
+/**
+ * qpnp_vadc_configure() - Configure ADC device to start conversion.
+ * @chan_prop:	Individual channel properties for the AMUX channel.
+ */
+int32_t qpnp_vadc_configure(
+			struct qpnp_vadc_amux_properties *chan_prop);
+
+/**
+ * qpnp_adc_scale_default() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset.
+ * @adc_code:	pre-calibrated digital ouput of the ADC.
+ * @adc_prop:	adc properties of the qpnp adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	Individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	Physical result to be stored.
+ */
+int32_t qpnp_adc_scale_default(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+#else
+static inline int32_t qpnp_vadc_read(uint32_t channel,
+				struct qpnp_vadc_result *result)
+{ return -ENXIO; }
+static inline int32_t qpnp_vadc_conv_seq_request(
+			enum qpnp_vadc_trigger trigger_channel,
+			enum qpnp_vadc_channels channel,
+			struct qpnp_vadc_result *result)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_default(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_adc_chan_properties *chan_prop,
+			struct qpnp_adc_chan_result *chan_rslt)
+{ return -ENXIO; }
+#endif
+
+#endif
diff --git a/include/linux/usb/android.h b/include/linux/usb/android.h
index 7c2b33b..0b11fdaf 100644
--- a/include/linux/usb/android.h
+++ b/include/linux/usb/android.h
@@ -17,6 +17,8 @@
 #ifndef	__LINUX_USB_ANDROID_H
 #define	__LINUX_USB_ANDROID_H
 
+#include <linux/usb/composite.h>
+
 struct android_usb_platform_data {
 	int (*update_pid_and_serial_num)(uint32_t, const char *);
 	u32 swfi_latency;
@@ -24,4 +26,22 @@
 	bool cdrom;
 };
 
+#ifndef CONFIG_TARGET_CORE
+static inline int f_tcm_init(int (*connect_cb)(bool connect))
+{
+	/*
+	 * Fail bind() not init(). If a function init() returns error
+	 * android composite registration would fail.
+	 */
+	return 0;
+}
+static inline void f_tcm_exit(void)
+{
+}
+static inline int tcm_bind_config(struct usb_configuration *c)
+{
+	return -ENODEV;
+}
+#endif
+
 #endif	/* __LINUX_USB_ANDROID_H */
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index 76f4396..72f5c96 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -56,7 +56,7 @@
 	struct sk_buff_head	rxq_pause;
 	struct urb		*interrupt;
 	struct usb_anchor	deferred;
-	struct tasklet_struct	bh;
+	struct work_struct	bh_w;
 
 	struct work_struct	kevent;
 	unsigned long		flags;
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index ae81dcd..57ce7c0 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -213,6 +213,10 @@
 #define MSM_CAM_IOCTL_GET_INST_HANDLE \
 	_IOR(MSM_CAM_IOCTL_MAGIC, 60, uint32_t *)
 
+#define MSM_CAM_IOCTL_STATS_UNREG_BUF \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 61, struct msm_stats_flush_bufq *)
+
+
 struct msm_stats_reqbuf {
 	int num_buf;		/* how many buffers requested */
 	int stats_type;	/* stats type */
@@ -468,6 +472,7 @@
 #define CMD_AXI_CFG_ZSL 43
 #define CMD_AXI_CFG_SNAP_VPE 44
 #define CMD_AXI_CFG_SNAP_THUMB_VPE 45
+
 #define CMD_CONFIG_PING_ADDR 46
 #define CMD_CONFIG_PONG_ADDR 47
 #define CMD_CONFIG_FREE_BUF_ADDR 48
@@ -475,6 +480,13 @@
 #define CMD_AXI_CFG_VIDEO_ALL_CHNLS 50
 #define CMD_VFE_BUFFER_RELEASE 51
 #define CMD_VFE_PROCESS_IRQ 52
+#define CMD_STATS_BG_ENABLE 53
+#define CMD_STATS_BF_ENABLE 54
+#define CMD_STATS_BHIST_ENABLE 55
+#define CMD_STATS_BG_BUF_RELEASE 56
+#define CMD_STATS_BF_BUF_RELEASE 57
+#define CMD_STATS_BHIST_BUF_RELEASE 58
+
 
 #define CMD_AXI_CFG_PRIM               BIT(8)
 #define CMD_AXI_CFG_PRIM_ALL_CHNLS     BIT(9)
@@ -524,7 +536,10 @@
 #define MSM_PMEM_C2D			17
 #define MSM_PMEM_MAINIMG_VPE    18
 #define MSM_PMEM_THUMBNAIL_VPE  19
-#define MSM_PMEM_MAX            20
+#define MSM_PMEM_BAYER_GRID		20
+#define MSM_PMEM_BAYER_FOCUS	21
+#define MSM_PMEM_BAYER_HIST		22
+#define MSM_PMEM_MAX            23
 
 #define STAT_AEAW			0
 #define STAT_AEC			1
@@ -534,7 +549,10 @@
 #define STAT_CS				5
 #define STAT_IHIST			6
 #define STAT_SKIN			7
-#define STAT_MAX			8
+#define STAT_BG				8
+#define STAT_BF				9
+#define STAT_BHIST			10
+#define STAT_MAX			11
 
 #define FRAME_PREVIEW_OUTPUT1		0
 #define FRAME_PREVIEW_OUTPUT2		1
@@ -1858,6 +1876,12 @@
 	struct msm_cpp_frame_strip_info *strip_info;
 };
 
+struct msm_ver_num_info {
+	uint32_t main;
+	uint32_t minor;
+	uint32_t rev;
+};
+
 #define VIDIOC_MSM_CPP_CFG \
 	_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_camera_v4l2_ioctl_t)
 
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index 3df6ded..0ee7417 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -62,6 +62,10 @@
 #define MSG_ID_OUTPUT_TERTIARY1         43
 #define MSG_ID_STOP_LS_ACK              44
 #define MSG_ID_OUTPUT_TERTIARY2         45
+#define MSG_ID_STATS_BG                 46
+#define MSG_ID_STATS_BF                 47
+#define MSG_ID_STATS_BHIST              48
+
 
 /* ISP command IDs */
 #define VFE_CMD_DUMMY_0                                 0
@@ -206,6 +210,13 @@
 #define VFE_CMD_STATS_REQBUF                            139
 #define VFE_CMD_STATS_ENQUEUEBUF                        140
 #define VFE_CMD_STATS_FLUSH_BUFQ                        141
+#define VFE_CMD_STATS_UNREGBUF                          142
+#define VFE_CMD_STATS_BG_START                          143
+#define VFE_CMD_STATS_BG_STOP                           144
+#define VFE_CMD_STATS_BF_START                          145
+#define VFE_CMD_STATS_BF_STOP                           146
+#define VFE_CMD_STATS_BHIST_START                       147
+#define VFE_CMD_STATS_BHIST_STOP                        148
 
 struct msm_isp_cmd {
 	int32_t  id;
diff --git a/include/media/vcap_fmt.h b/include/media/vcap_fmt.h
index 92240bf1..00e0375 100644
--- a/include/media/vcap_fmt.h
+++ b/include/media/vcap_fmt.h
@@ -44,6 +44,43 @@
 	HAL_VCAP_RGB,
 };
 
+enum nr_mode {
+	NR_DISABLE = 0,
+	NR_AUTO,
+	NR_MANUAL,
+};
+
+enum nr_decay_ratio {
+	NR_Decay_Ratio_26 = 0,
+	NR_Decay_Ratio_25,
+	NR_Decay_Ratio_24,
+	NR_Decay_Ratio_23,
+	NR_Decay_Ratio_22,
+	NR_Decay_Ratio_21,
+	NR_Decay_Ratio_20,
+	NR_Decay_Ratio_19,
+};
+
+struct nr_config {
+	uint8_t max_blend_ratio;
+	uint8_t scale_diff_ratio;
+	uint8_t diff_limit_ratio;
+	uint8_t scale_motion_ratio;
+	uint8_t blend_limit_ratio;
+};
+
+struct nr_param {
+	enum nr_mode mode;
+	enum nr_decay_ratio decay_ratio;
+	uint8_t window;
+	struct nr_config luma;
+	struct nr_config chroma;
+};
+
+#define VCAPIOC_NR_S_PARAMS _IOWR('V', (BASE_VIDIOC_PRIVATE+0), struct nr_param)
+
+#define VCAPIOC_NR_G_PARAMS _IOWR('V', (BASE_VIDIOC_PRIVATE+1), struct nr_param)
+
 struct v4l2_format_vc_ext {
 	enum hal_vcap_mode     mode;
 	enum hal_vcap_polar    h_polar;
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index 9719aa6..390a843 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -120,7 +120,8 @@
 
 	void					*bufMotion;
 	struct nr_buffer		bufNR;
-	bool					nr_enabled;
+	struct nr_param			nr_param;
+	bool					nr_update;
 };
 
 struct vp_work_t {
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 02ea082..0563af9 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -951,6 +951,9 @@
 	if (test_bit(HCI_RAW, &hdev->flags))
 		return;
 
+	if (conn->type == LE_LINK)
+		return;
+
 	if (conn->mode != HCI_CM_SNIFF)
 		goto timer;
 
@@ -1018,6 +1021,9 @@
 	if (test_bit(HCI_RAW, &hdev->flags))
 		return;
 
+	if (conn->type == LE_LINK)
+		return;
+
 	if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn))
 		return;
 
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index d8a4624..2fcf29b 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -1152,8 +1152,9 @@
 	snd_soc_dapm_sync(dapm);
 
 	err = snd_soc_jack_new(codec, "Headset Jack",
-		(SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR),
-		&hs_jack);
+			       (SND_JACK_HEADSET | SND_JACK_OC_HPHL |
+				SND_JACK_OC_HPHR | SND_JACK_UNSUPPORTED),
+			       &hs_jack);
 	if (err) {
 		pr_err("failed to create new jack\n");
 		return err;