Merge "qseecom: Fix QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ kernel crash"
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index b489f7a..4e3abc2 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -136,6 +136,8 @@
 					is present, and vise versa.
 - qcom,cpr-enable:		Present: CPR enabled by default.
 				Not Present: CPR disable by default.
+- qcom,use-tz-api:		Present: CPR reads efuse parameters through trustzone API.
+				Not Present: CPR reads efuse parameters directly.
 
 
 Example:
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
index d07eba6..3947f75 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -28,11 +28,21 @@
 			core can be used for freq control.
 - qcom,core-limit-temp: Threshold temperature to start shutting down cores
 			in degC
-- qcom,core-temp-hysterisis: Degrees C below which the cores will be brought
+- qcom,core-temp-hysteresis: Degrees C below which the cores will be brought
 			online in sequence.
 - qcom,core-control-mask: The cpu mask that will be used to determine if a
 			core can be controlled or not. A mask of 0 indicates
 			the feature is disabled.
+- qcom,hotplug-temp: Threshold temperature to start shutting down cores
+			in degC. This will be used when polling based
+			core control is disabled. The difference between hotplug-temp
+			and core-limit-temp is that core-limit-temp is used during
+			early boot prior to thermal_sys being available for hotplug.
+- qcom,hotplug-temp-hysteresis: Degrees C below which thermal will not force the
+			cores to be offlined. Cores can be brought online if needed.
+- qcpm,cpu-sensors:     List of type names in thermal zone device struct which maps
+			to cpu0, cpu1, cpu2, cpu3 in sequence depending on how many
+			cpus there are.
 - qcom,vdd-restriction-temp: When temperature is below this threshold, will
 			enable vdd restriction which will set higher voltage on
 			key voltage rails, in degC.
@@ -81,8 +91,12 @@
 		qcom,freq-step = <2>;
 		qcom,freq-control-mask = <0xf>
 		qcom,core-limit-temp = <90>;
-		qcom,core-temp-hysterisis = <10>;
+		qcom,core-temp-hysteresis = <10>;
 		qcom,core-control-mask = <7>;
+		qcom,hotplug-temp = <110>;
+		qcom,hotplug-temp-hysteresis = <20>;
+		qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor6",
+				"tsens_tz_sensor7", "tsens_tz_sensor8";
 		qcom,pmic-sw-mode-temp = <90>;
 		qcom,pmic-sw-mode-temp-hysteresis = <80>;
 		qcom,pmic-sw-mode-regs = "vdd-dig";
diff --git a/Documentation/devicetree/bindings/arm/msm/rpm-master-stats.txt b/Documentation/devicetree/bindings/arm/msm/rpm-master-stats.txt
new file mode 100644
index 0000000..0239674
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/rpm-master-stats.txt
@@ -0,0 +1,29 @@
+* RPM Master Stats
+
+RPM maintains each master data in RPM message RAM at a specific
+offset. It tells about the individual masters information at
+any given time like "number of active cores in sub system",
+"number of shutdowns" and "wakeup reason for SS" etc. These stats
+can be show to the user using the debugfs interface of the kernel.
+To achieve this device tree node has been added and it will hold
+the address of the RPM RAM from where master stats are read.
+Added version number to distinguish the type of data structure
+being read from the RAM for different targets.
+
+The required properties for rpm-master-stats are:
+
+- compatible: "qcom,rpm-master-stats".
+- reg: The address on the RPM RAM from where stats are read.
+- qcom,masters: Each master name.
+- qcom,master-offset: Offset required to access each master stats area.
+- qcom,master-stats-version: Version number.
+
+Example:
+
+qcom,rpm-stats@fc428150 {
+		compatible = "qcom,rpm-stats";
+		reg = <0xfc428150 0x1000>;
+		qcom,masters = "APSS", "MPSS", "LPSS", "PRONTO";
+		qcom,master-offset = <2560>;
+		qcom,master-stats-version = <2>;
+};
diff --git a/Documentation/devicetree/bindings/arm/msm/smdtty.txt b/Documentation/devicetree/bindings/arm/msm/smdtty.txt
new file mode 100644
index 0000000..f661b84
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/smdtty.txt
@@ -0,0 +1,40 @@
+Qualcomm Shared Memory TTY Driver (smdtty)
+
+[Root level node]
+Required properties:
+-compatible : should be "qcom,smdtty"
+
+[Second level nodes]
+qcom,smdtty-port-names
+Required properties:
+-qcom,smdtty-remote: the remote subsystem name
+-qcom,smdtty-port-name : the smd channel name
+
+Optional properties:
+-qcom,smdtty-dev-name : the smdtty device name
+
+Required alias:
+- The index into TTY subsystem is specified via an alias with the following format
+         'smd{n}' where n is the tty device index.
+
+Example:
+	aliases {
+		smd1 = &smdtty_apps_fm;
+		smd36 = &smdtty_loopback;
+	};
+
+	qcom,smdtty {
+		compatible = "qcom,smdtty";
+
+		smdtty_apps_fm: qcom,smdtty-apps-fm {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_FM";
+		};
+
+		smdtty_loopback: smdtty-loopback {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "LOOPBACK";
+			qcom,smdtty-dev-name = "LOOPBACK_TTY";
+		};
+	};
+
diff --git a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
index a2d8359..d9a0d59 100644
--- a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
+++ b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
@@ -42,6 +42,10 @@
 - qcom,saw2-spm-cmd-spc: The Standalone PC command sequence
 - qcom,saw2-spm-cmd-pc: The Power Collapse command sequence
 - qcom,saw2-spm-cmd-gdhs: L2 GDHS command sequence
+- qcom,L2-spm-is-apcs-master: Boolean indicates if the target uses L2 SAW to
+	control the gang rail. If this is not specified the driver assumes
+	that the cpus run with their own separate rails and each cpu's spm
+	talks to its regulator.
 
 Example:
 	qcom,spm@f9089000 {
diff --git a/Documentation/devicetree/bindings/batterydata/batterydata.txt b/Documentation/devicetree/bindings/batterydata/batterydata.txt
index 985fb4c..8fbb1bd 100644
--- a/Documentation/devicetree/bindings/batterydata/batterydata.txt
+++ b/Documentation/devicetree/bindings/batterydata/batterydata.txt
@@ -22,7 +22,10 @@
 - qcom,v-cutoff-uv : The cutoff voltage of the battery at which the device
 			should shutdown gracefully.
 - qcom,chg-term-ua : The termination charging current of the battery.
-- qcom,batt-id-kohm : The battery id resistance of the battery.
+- qcom,batt-id-kohm : The battery id resistance of the battery. It can be
+			used as an array which could support multiple IDs for one battery
+			module when the ID resistance of some battery modules goes across
+			several ranges.
 
 Profile data node required subnodes:
 - qcom,fcc-temp-lut : An 1-dimensional lookup table node that encodes
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 44134f8..49cd567 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -215,6 +215,10 @@
 - qcom,mdss-dsi-off-command-state:	String that specifies the ctrl state for sending OFF commands.
 					"dsi_lp_mode" = DSI low power mode (default)
 					"dsi_hs_mode" = DSI high speed mode
+- qcom,mdss-pan-physical-width-dimension:	Specifies panel physical width in mm which corresponds
+					to the physical width in the framebuffer information.
+- qcom,mdss-pan-physical-height-dimension:	Specifies panel physical height in mm which corresponds
+					to the physical height in the framebuffer information.
 
 
 Note, if a given optional qcom,* binding is not present, then the driver will configure
@@ -303,5 +307,7 @@
 		qcom,mdss-dsi-bl-pmic-bank-select = <0>;
 		qcom,mdss-dsi-bl-pmic-pwm-frequency = <0>;
 		qcom,mdss-dsi-pwm-gpio = <&pm8941_mpps 5 0>;
+		qcom,mdss-pan-physical-width-dimension = <60>;
+		qcom,mdss-pan-physical-height-dimension = <140>;
 	};
 };
diff --git a/Documentation/devicetree/bindings/input/misc/cm36283.txt b/Documentation/devicetree/bindings/input/misc/cm36283.txt
new file mode 100644
index 0000000..b5ee7d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/misc/cm36283.txt
@@ -0,0 +1,40 @@
+Capella cm36283 L/P sensor
+
+Required properties:
+
+ - compatible		: Should be "capella,cm36283".
+ - reg				: i2c slave address of the device.
+ - interrupt-parent	: Parent of interrupt.
+ - interrupts		: L/P sample interrupt to indicate new data ready.
+ - vdd-supply		: Power supply needed to power up the device.
+ - vio-supply		: IO power supply needed for IO and I2C.
+ - capella,interrupt-gpio	: The gpio pin for the interrupt.
+ - capella,levels	: The adc value for light sensor to trigger different light level.
+ - capella,ps_close_thd_set	: The threshold adc value for proximity sensor to trigger close  interrupt.
+ - capella,ps_away_thd_set: The threshold adc value for proximity sensor to trigger away interrupt.
+ - capella,ls_cmd	: The initial value to configure cm36283 ALS_CONF register.
+ - capella,ps_conf1_val	: The initial value to configure cm36283 PS_CONF1 register.
+ - capella,ps_conf3_val	: The initial value to configure cm36283 PS_CONF3 register.
+
+Optional properties:
+
+ - capella,use-polling	: Property to specify if using polling instead of interrupt for adc value report.
+
+Example:
+
+		capella@60 {
+				compatible = "capella,cm36283";
+				reg = <0x60>;
+				interrupt-parent = <&msmgpio>;
+				interrupts = <80 0x2>;
+				vdd-supply = <&pm8110_l19>;
+				vio-supply = <&pm8110_l14>;
+				capella,use-polling;
+				capella,interrupt-gpio = <80>;
+				capella,levels = <0x0A 0xA0 0xE1 0x140 0x280 0x500 0xA28 0x16A8 0x1F40 0x2800>;
+				capella,ps_close_thd_set = <0xa>;
+				capella,ps_away_thd_set = <0x5>;
+				capella,ls_cmd = <0x44>;  /* PS_IT=160ms, INT_PERS=2*/
+				capella,ps_conf1_val = <0x0006>;  /*CM36283_PS_ITB_1_2 | CM36283_PS_DR_1_40| CM36283_PS_IT_1T | CM36283_PS_PERS_2 | CM36283_PS_RES_1*/
+				capella,ps_conf3_val = <0x3010>;  /* CM36283_PS_MS_NORMAL | CM36283_PS_PROL_255 | CM36283_PS_SMART_PERS_ENABLE, */
+		};
diff --git a/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt
index d77e96c..c563067e 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt
@@ -23,6 +23,10 @@
  - focaltech,display-coords : display coordinates in pixels. It is a four
 				tuple consisting of min x, min y, max x and
 				max y values
+ - focaltech,name	: name of the controller
+ - focaltech,group-id	: group id of this device
+ - focaltech,hard-reset-delay-ms : hard reset delay in ms
+ - focaltech,soft-reset-delay-ms : soft reset delay in ms
 
 Optional properties:
 
@@ -33,21 +37,45 @@
  - focaltech,no-force-update : to specify force update is allowed
  - focaltech,button-map : button map of key codes. The number
 				of key codes depend on panel
+ - focaltech,fw-name	: specify the firmware file name
+ - focaltech,fw-delay-aa-ms : specify the "aa" delay in ms for firmware upgrade
+ - focaltech,fw-delay-55-ms : specify the "55" delay in ms for firmware upgrade
+ - focaltech,fw-upgrade-id1 : specify the upgrade id1 for firmware upgrade
+ - focaltech,fw-upgrade-id2 : specify the upgrade id2 for firmware upgrade
+ - focaltech,fw-delay-readid-ms : specify the read id delay in ms for firmware upgrade
+ - focaltech,fw-delay-era-flsh-ms : specify the erase flash delay in ms for firmware upgrade
+ - focaltech,fw-auto-cal	: specify whether calibration is needed after firmware upgrade
+ - focaltech,fw-vkey-support	: specify if virtual keys are supported through firmware
 
 Example:
-	i2c@f9924000 {
-		ft5x06_ts@38 {
+	i2c@f9923000{
+		focaltech@38{
 			compatible = "focaltech,5x06";
 			reg = <0x38>;
 			interrupt-parent = <&msmgpio>;
-			interrupts = <61 0x2>;
-			vdd-supply = <&pm8941_l22>;
-			vcc_i2c-supply = <&pm8941_s3>;
-			focaltech,reset-gpio = <&msmgpio 60 0x00>;
-			focaltech,irq-gpio = <&msmgpio 61 0x00>;
-			focaltech,panel-coords = <0 0 480 800>;
+			interrupts = <1 0x2>;
+			vdd-supply = <&pm8110_l19>;
+			vcc_i2c-supply = <&pm8110_l14>;
+			focaltech,name = "ft6x06";
+			focaltech,family-id = <0x06>;
+			focaltech,reset-gpio = <&msmgpio 0 0x00>;
+			focaltech,irq-gpio = <&msmgpio 1 0x00>;
 			focaltech,display-coords = <0 0 480 800>;
-			focaltech,button-map= <158 102 139 217>;
-			focaltech,family-id = <0x0a>;
+			focaltech,panel-coords = <0 0 480 800>;
+			focaltech,button-map= <139 102 158>;
+			focaltech,no-force-update;
+			focaltech,i2c-pull-up;
+			focaltech,group-id = <1>;
+			focaltech,hard-reset-delay = <20>;
+			focaltech,soft-reset-delay = <150>;
+			focaltech,num-max-touches = <2>;
+			focaltech,fw-name = "ft_8610_qrd_fw.bin";
+			focaltech,fw-delay-aa-ms = <100>;
+			focaltech,fw-delay-55-ms = <30>;
+			focaltech,fw-upgrade-id1 = <0x79>;
+			focaltech,fw-upgrade-id2 = <0x08>;
+			focaltech,fw-delay-readid-ms = <10>;
+			focaltech,fw-delay-era-flsh-ms = <2000>;
+			focaltech,fw-auto-cal;
 		};
 	};
diff --git a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
new file mode 100644
index 0000000..3e223e6
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
@@ -0,0 +1,74 @@
+Goodix GT9xx series touch controller
+
+Required properties:
+
+ - compatible		: Should be "goodix,gt9xx"
+ - reg			: I2C slave address of the device.
+ - interrupt-parent	: Parent of interrupt.
+ - interrupts		: Configuration of touch panel controller interrupt
+				GPIO.
+ - goodix,family-id	: Family identification of the controller.
+ - interrupt-gpios	: Interrupt gpio which is to provide interrupts to
+				host, same as "interrupts" node.
+ - reset-gpios		: Reset gpio to control the reset of chip.
+ - goodix,display-coords	: Display coordinates in pixels. It is a four
+				tuple consisting of min x, min y, max x and
+				max y values.
+
+Optional properties:
+
+ - avdd-supply		: Power supply needed to power up the device, this is
+				for fixed voltage external regulator.
+ - vdd-supply		: Power supply needed to power up the device, when use
+				external regulator, do not add this property.
+ - vcc-i2c-supply	: Power source required to power up i2c bus.
+				GT9xx series can provide 1.8V from internal
+				LDO, add this properties base on hardware
+				design.
+ - goodix,panel-coords	: Panel coordinates for the chip in pixels.
+				It is a four tuple consisting of min x,
+				min y, max x and max y values.
+ - goodix,i2c-pull-up	: To specify pull up is required.
+ - goodix,no-force-update	: To specify force update is allowed.
+ - goodix,button-map	: Button map of key codes. The number of key codes
+				depend on panel.
+ - goodix,cfg-data	: Touchpanel controller configuration data, ask vendor
+				to provide that. Default configuration will be
+				used if this property is not present.
+
+Example:
+i2c@f9927000 {
+		goodix@5d {
+			compatible = "goodix,gt9xx";
+			reg = <0x5d>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <17 0x2008>;
+			reset-gpios = <&msmgpio 16 0x00>;
+			interrupt-gpios = <&msmgpio 17 0x00>;
+			avdd-supply = <&tp_power>;
+			goodix,panel-coords = <0 0 720 1200>;
+			goodix,display-coords = <0 0 720 1080>;
+			goodix,button-map= <158 102 139>;
+			goodix,family-id = <0x0>;
+			goodix,cfg-data = [
+		41 D0 02 00 05 0A 05 01 01 08
+		12 58 50 41 03 05 00 00 00 00
+		00 00 00 00 00 00 00 8C 2E 0E
+		28 24 73 13 00 00 00 83 03 1D
+		40 02 00 00 00 03 64 32 00 00
+		00 1A 38 94 C0 02 00 00 00 04
+		9E 1C 00 8D 20 00 7A 26 00 6D
+		2C 00 60 34 00 60 10 38 68 00
+		F0 50 35 FF FF 27 00 00 00 00
+		00 01 1B 14 0C 14 00 00 01 00
+		00 00 00 00 00 00 00 00 00 00
+		00 00 02 04 06 08 0A 0C 0E 10
+		12 14 16 18 1A 1C FF FF FF FF
+		FF FF FF FF FF FF FF FF FF FF
+		FF FF 00 02 04 06 08 0A 0C 0F
+		10 12 13 14 16 18 1C 1D 1E 1F
+		20 21 22 24 26 28 29 2A FF FF
+		FF FF FF FF FF FF FF 22 22 22
+		22 22 22 FF 07 01];
+		};
+};
diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
index 0f35e73..8fd813c 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
@@ -14,12 +14,14 @@
  - vdd-supply		: Analog power supply needed to power device
  - vcc_i2c-supply		: Power source required to pull up i2c bus
  - synaptics,i2c-pull-up	: specify to indicate pull up is needed
+ - synaptics,disable-gpios	: specify to disable gpios in suspend (power saving)
  - synaptics,button-map		: virtual key code mappings to be used
  - synaptics,x-flip		: modify orientation of the x axis
  - synaptics,y-flip		: modify orientation of the y axis
  - synaptics,panel-x		: panel x dimension
  - synaptics,panel-y		: panel y dimension
  - synaptics,fw-image-name	: name of firmware .img file in /etc/firmware
+ - synaptics,power-down		: fully power down regulators in suspend
 
 Example:
 	i2c@f9927000 { /* BLSP1 QUP5 */
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index 9524360..f7e50eb 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -45,9 +45,9 @@
 - qcom,saftey-timer: include for safety timer use, otherwise watchdog timer will be used
 - linux,default-trigger: trigger the led from external modules such as display
 - qcom,default-state:  default state of the led, should be "on" or "off"
-- qcom,torch-enable: set flash led to torch mode
-- flash_boost-supply: SMBB regulator for LED flash mode
-- torch_boost-supply: SMBB regulator for LED torch mode
+- qcom,torch-enable: set flash led to torch mode functionality and triggers software workaround for torch if hardware does not support
+- flash-boost-supply: SMBB regulator for LED flash mode
+- torch-boost-supply: SMBB regulator for LED torch mode
 
 RGB Led is a tri-colored led, Red, Blue & Green.
 
@@ -222,8 +222,8 @@
 	qcom,leds@d300 {
 			compatible = "qcom,leds-qpnp";
 			status = "okay";
-			flash_boost-supply = <&pm8941_chg_boost>;
-			torch_boost-supply = <&pm8941_boost>;
+			flash-boost-supply = <&pm8941_chg_boost>;
+			torch-boost-supply = <&pm8941_boost>;
 			qcom,flash_0 {
 				qcom,max-current = <1000>;
 				qcom,default-state = "off";
@@ -238,6 +238,7 @@
 				linux,name = "led:flash_0";
 				qcom,current = <625>;
 				qcom,id = <1>;
+				qcom,no-torch-module;
 			};
 	};
 
diff --git a/Documentation/devicetree/bindings/media/video/msm-eeprom.txt b/Documentation/devicetree/bindings/media/video/msm-eeprom.txt
new file mode 100644
index 0000000..893c033
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-eeprom.txt
@@ -0,0 +1,106 @@
+* Qualcomm MSM EEPROM
+
+EEPROM is an one time programmed(OTP) device that stores the calibration data
+use for camera sensor. It may either be integrated in the sensor module or in
+the sensor itself. As a result, the power, clock and GPIOs may be the same as
+the camera sensor. The following describes the page block map, power supply,
+clock, GPIO and power on sequence properties of the EEPROM device.
+
+Required properties:
+- cell-index: eeprom hardware core index
+- compatible :
+    - "qcom,eeprom"
+- reg : offset and length of eeprom device registers.
+- qcom,eeprom-name : should specify relevant names of the eeprom module
+    library.
+- qcom,slave-addr : should specify the slave address of the eeprom.
+- qcom,cci-master : should specify the cci core index that eeprom use.
+- qcom,num-blocks : should specify the total block number that eeprom contains,
+    every block should contains page poll and mem.
+- qcom,page%d : number %d page size, start address, address type, data,
+    data type, delay in ms. size 0 stand for non-paged.
+    - address type : 1 byte, 2 word.
+    - data type : 1 byte, 2 word.
+- qcom,poll%d : number %d poll size, poll reg address, address type, data,
+    data type, delay in ms. size 0 stand for not used.
+    - address type : 1 byte, 2 word.
+    - data type : 1 byte, 2 word.
+- qcom,mem%d : number %d memory size, start address, address type, data,
+    data type, delay in ms. size 0 stand for not used.
+    - address type : 1 byte, 2 word.
+    - data type : 1 byte, 2 word.
+- cam_vdig-supply : should contain regulator to be used for the digital vdd.
+- cam_vio-supply : should contain regulator to be used for the IO vdd.
+- qcom,cam-vreg-name : should specify the regulator name to be used for
+    this eeprom.
+- qcom,cam-vreg-type : should specify the regulator type to be used for
+    this eeprom.
+- qcom,cam-vreg-min-voltage : should specify minimum voltage level
+    for eeprom in uV.
+- qcom,cam-vreg-max-voltage : should specify maximum voltage level
+    for eeprom in uV.
+- qcom,cam-vreg-op-mode : should specify current level for eeprom in uA.
+- qcom,gpio-no-mux : should specify the gpio mux type.
+- gpios : should specify the gpios to be used for the eeprom.
+- qcom,gpio-reset : should specify the reset gpio index.
+- qcom,gpio-standby : should specify the standby gpio index.
+- qcom,gpio-req-tbl-num : should specify the gpio table index.
+- qcom,gpio-req-tbl-flags : should specify the gpio functions.
+- qcom,gpio-req-tbl-label : should specify the gpio labels.
+- qcom,cam-power-seq-type : should specify the power on sequence types.
+- qcom,cam-power-seq-val : should specify the power on sequence values.
+- qcom,cam-power-seq-cfg-val : should specify the power on sequence config
+    values.
+- qcom,cam-power-seq-delay : should specify the power on sequence delay
+    time in ms.
+
+Optional properties:
+- qcom,pageen%d : number %d page enable reg size, start address, address type,
+    data, data type, delay in ms. size 0 stand for not used.
+
+Example:
+
+    eeprom0: qcom,eeprom@60 {
+        cell-index = <0>;
+        reg = <0x60 0x0>;
+        qcom,eeprom-name = "msm_eeprom";
+        compatible = "qcom,eeprom";
+        qcom,slave-addr = <0x60>;
+        qcom,cci-master = <0>;
+        qcom,num-blocks = <2>;
+        qcom,page0 = <1 0x0100 2 0x01 1 1>;
+        qcom,poll0 = <0 0x0 2 0 1 1>;
+        qcom,mem0 = <0 0x0 2 0 1 0>;
+        qcom,page1 = <1 0x0200 2 0x8 1 1>;
+        qcom,pageen1 = <1 0x0202 2 0x01 1 10>;
+        qcom,poll1 = <0 0x0 2 0 1 1>;
+        qcom,mem1 = <32 0x3000 2 0 1 0>;
+
+        cam_vdig-supply = <&pm8226_l5>;
+        cam_vio-supply = <&pm8226_lvs1>;
+        qcom,cam-vreg-name = "cam_vdig", "cam_vio";
+        qcom,cam-vreg-type = <0 1>;
+        qcom,cam-vreg-min-voltage = <1200000 0>;
+        qcom,cam-vreg-max-voltage = <1200000 0>;
+        qcom,cam-vreg-op-mode = <200000 0>;
+        qcom,gpio-no-mux = <0>;
+        gpios = <&msmgpio 26 0>,
+            <&msmgpio 37 0>,
+            <&msmgpio 36 0>;
+        qcom,gpio-reset = <1>;
+        qcom,gpio-standby = <2>;
+        qcom,gpio-req-tbl-num = <0 1 2>;
+        qcom,gpio-req-tbl-flags = <1 0 0>;
+        qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+            "CAM_RESET1",
+            "CAM_STANDBY";
+        qcom,cam-power-seq-type = "sensor_vreg",
+            "sensor_vreg", "sensor_clk",
+            "sensor_gpio", "sensor_gpio";
+        qcom,cam-power-seq-val = "cam_vdig",
+            "cam_vio", "sensor_cam_mclk",
+            "sensor_gpio_reset",
+            "sensor_gpio_standby";
+        qcom,cam-power-seq-cfg-val = <1 1 24000000 1 1>;
+        qcom,cam-power-seq-delay = <1 1 5 5 10>;
+    };
diff --git a/Documentation/devicetree/bindings/media/video/msm-vfe.txt b/Documentation/devicetree/bindings/media/video/msm-vfe.txt
index f02f35e..dd8eb15 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vfe.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vfe.txt
@@ -8,9 +8,13 @@
 - reg : offset and length of the register set for the device
     for the vfe operating in compatible mode.
 - reg-names : should specify relevant names to each reg property defined.
+    - "vfe" - Required.
+    - "vfe_vbif" - Optional for "vfe32". Required for "vfe40".
+    - "tcsr" - Optional for "vfe32". Required for "vfe40".
 - interrupts : should contain the vfe interrupt.
 - interrupt-names : should specify relevant names to each interrupts
   property defined.
+    - "vfe" - Required.
 - vdd-supply: phandle to GDSC regulator controlling VFE core.
 
 Example:
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index 013d56e..d502f78 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -73,7 +73,8 @@
 	- qcom,pad-pull-off - Suspend pull configuration for sdc tlmm pins.
 	- qcom,pad-drv-on - Active drive strength configuration for sdc tlmm pins.
 	- qcom,pad-drv-off - Suspend drive strength configuration for sdc tlmm pins.
-	Tlmm pins are specified as <clk cmd data>
+	Tlmm pins are specified as <clk cmd data> and starting with eMMC5.0 as
+	<clk cmd data rclk>
 
 	- qcom,bus-bw-vectors-bps: specifies array of throughput values in
 	Bytes/sec. The values in the array are determined according to
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 4a5e58c..b1c4ebb 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -81,6 +81,11 @@
 - qcom,resume-soc			Capacity in percent at which charging should resume
 					when a fully charged battery drops below this level.
 - qcom,chg-vadc				Corresponding VADC device's phandle.
+- qcom,pmic-revid			The phandle to the revid node of the pmic on which charger
+					peripheral is present. This property is a must on PMIC chips
+					that exhibit inaccuracies in battery current readings. This
+					phandle is used to check the version of the PMIC and apply
+					necessary software workarounds.
 
 Sub node required structure:
 - A qcom,chg node must be a child of an SPMI node that has specified
@@ -176,6 +181,9 @@
 			 - regulator-name:	A string used as a descriptive name
 						for the boost regulator.
 
+			qcom,batfet:
+			 - regulator-name:	A string used as a descriptive name
+						for the batfet regulator.
 Example:
 	pm8941-chg {
 		spmi-dev-container;
@@ -205,6 +213,7 @@
 		qcom,btc-disabled = <0>;
 		qcom,chg-vadc = <&pm8941_vadc>;
 		qcom,chg-adc_tm = <&pm8941_adc_tm>;
+		qcom,pmic-revid = <&pm8941_revid>;
 
 		qcom,chgr@1000 {
 			reg = <0x1000 0x100>;
@@ -303,6 +312,10 @@
 		regulator-name = "8941_smbb_boost";
 	};
 
+	&pm8941_chg_batif  {
+		regulator-name = "batfet";
+	};
+
 	&pm8941_chg_otg {
 		regulator-name = "8941_smbb_otg";
 	};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index b618597..6e4f7fc 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -434,7 +434,8 @@
 			    amplifier.
 
 - qcom,headset-jack-type-NO: Adjust GPIO level based on the headset jack type.
-
+- qcom,tapan-codec-9302: Indicates that this device node is for WCD9302 audio
+			    codec.
 
 * APQ8074 ASoC Machine driver
 
@@ -664,6 +665,7 @@
 - qcom,cdc-us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
 - qcom,cdc-lineout-spkr-gpios : GPIO which controls external PAs to enable Lineout1/2 speaker
 - qcom,cdc-vdd-spkr-gpios : GPIO which controls PA for VDD speaker
+- qcom,headset-jack-type-NC: Set if the headset jack type is NC (Normally Closed)
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/taiko_codec.txt
index 9abf54e..489eb38 100644
--- a/Documentation/devicetree/bindings/sound/taiko_codec.txt
+++ b/Documentation/devicetree/bindings/sound/taiko_codec.txt
@@ -35,6 +35,12 @@
  - qcom,cdc-vddcx-2-voltage: cx-2 supply's voltage level min and max in mV.
  - qcom,cdc-vddcx-2-current: cx-2 supply's max current in mA.
 
+ - cdc-vdd-buckhelper-supply: phandle of helper regulator supply's
+				device tree node. This supply is a helper regulator for
+				cdc-vdd-buck-supply regulator.
+ - cdc-vdd-buckhelper-voltage: helper supply's voltage level min and max in mV.
+ - qcom,cdc-vdd-buckhelper-current: helper supply's max current in mA.
+
  - qcom,cdc-static-supplies: List of supplies to be enabled prior to codec
 			     hardware probe.  Supplies in this list will be
 			     stay enabled.
@@ -76,6 +82,10 @@
 				dynamically.
 				Supplies in this list are off by default.
 
+- qcom,cdc-cp-supplies: List of supplies required for codec chargepump enable
+				Supplies in this list can be enabled/disabled dynamically and
+				are off by default.
+
  - qcom,cdc-micbias2-headset-only: Boolean. Allow micbias 2 only to headset mic.
 
 Example:
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index b93dc4d..7ca741c 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -126,6 +126,7 @@
 
 Required properties :
 - compatible : should be "qcom,hsic-smsc-hub"
+- smsc,model-id : should be either <3503> or <4604> depending on hub model
 - smsc,<gpio-name>-gpio : handle to the GPIO node, see "gpios property"
   in Documentation/devicetree/bindings/gpio/gpio.txt.
   Required "gpio-name" is "reset" and optionally - "refclk", "int".
@@ -137,6 +138,7 @@
 Example SMSC HSIC HUB :
 	hsic_hub {
 		compatible = "qcom,hsic-smsc-hub";
+		smsc,model-id = <4604>;
 		ranges;
 		smsc,reset-gpio = <&pm8941_gpios 8 0x00>;
 		smsc,refclk-gpio = <&pm8941_gpios 16 0x00>;
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 527c50c..9fd3afe 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -9,6 +9,7 @@
 arm	ARM Ltd.
 atmel	Atmel Corporation
 bosch	Bosch Sensortec GmbH
+capella	Capella Microsystems, Inc.
 cavium	Cavium, Inc.
 chrp	Common Hardware Reference Platform
 cortina	Cortina Systems, Inc.
@@ -19,6 +20,7 @@
 focaltech Focaltech systems
 fsl	Freescale Semiconductor
 GEFanuc	GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+goodix	Goodix. Ltd.
 gef	GE Fanuc Intelligent Platforms Embedded Systems, Inc.
 hp	Hewlett Packard
 ibm	International Business Machines (IBM)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 69b2cd2..58fc698 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -290,6 +290,14 @@
 	 timer counter page should be mapped by the kernel.  User-space apps
 	 will read directly from the page at this address.
 
+config ARCH_RANDOM
+	bool "SOC specific random number generation"
+	help
+	 Allow the kernel to use an architecture specific implementation for
+	 random number generation
+
+	 If unsure, say N
+
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
diff --git a/arch/arm/boot/dts/apq8026-v1-mtp.dts b/arch/arm/boot/dts/apq8026-v1-mtp.dts
index 7900ddf..87a0271 100644
--- a/arch/arm/boot/dts/apq8026-v1-mtp.dts
+++ b/arch/arm/boot/dts/apq8026-v1-mtp.dts
@@ -22,8 +22,8 @@
 };
 
 &cci {
-	/* Rotate rear camera to 0 degrees */
+	/* Rotate rear camera to 180 degrees */
 	qcom,camera@6f {
-	qcom,mount-angle = <0>;
+	qcom,mount-angle = <180>;
 	};
 };
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index acd0bb9..46f5f22 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -62,6 +62,7 @@
 
 	hsic_hub {
 		compatible = "qcom,hsic-smsc-hub";
+		smsc,model-id = <4604>;
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges;
@@ -604,7 +605,7 @@
 	};
 
 	qcom,dc-chgpth@1400 {
-		status = "ok";
+		status = "disabled";
 	};
 
 	qcom,boost@1500 {
diff --git a/arch/arm/boot/dts/batterydata-qrd-4v2-1300mah.dtsi b/arch/arm/boot/dts/batterydata-qrd-4v2-1300mah.dtsi
new file mode 100644
index 0000000..103da50
--- /dev/null
+++ b/arch/arm/boot/dts/batterydata-qrd-4v2-1300mah.dtsi
@@ -0,0 +1,105 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+qcom,qrd-4v2-1300mah-data {
+	qcom,fcc-mah = <1300>;
+	qcom,default-rbatt-mohm = <172>;
+	qcom,rbatt-capacitive-mohm = <0>;
+	qcom,flat-ocv-threshold-uv = <3800000>;
+	qcom,max-voltage-uv = <4200000>;
+	qcom,v-cutoff-uv = <3400000>;
+	qcom,chg-term-ua = <100000>;
+	qcom,batt-id-kohm = <100>;
+
+	qcom,rbatt-sf-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 15 10 9>,
+				<8 7 6 5 4>,
+				<3 2 1 0>;
+		qcom,lut-data = <604 192 100 79 71>,
+				<605 192 100 79 71>,
+				<641 205 103 81 72>,
+				<641 221 108 84 75>,
+				<622 238 115 87 77>,
+				<612 254 123 92 79>,
+				<605 252 137 96 83>,
+				<607 219 154 104 87>,
+				<613 202 135 109 89>,
+				<626 200 106 90 77>,
+				<656 201 101 82 75>,
+				<684 204 100 84 77>,
+				<710 211 100 85 79>,
+				<747 224 106 89 82>,
+				<806 241 116 90 80>,
+				<905 260 119 87 77>,
+				<1046 291 113 87 77>,
+				<1309 329 116 90 79>,
+				<1476 300 126 97 83>,
+				<1598 311 127 98 84>,
+				<1771 323 130 99 85>,
+				<1984 342 136 101 86>,
+				<2438 368 140 101 86>,
+				<3381 388 137 100 84>,
+				<4913 414 141 99 86>,
+				<6979 468 155 104 90>,
+				<9968 565 192 113 98>,
+				<16163 833 350 140 120>,
+				<36511 6483 4872 472 1095>;
+	};
+
+	qcom,fcc-temp-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-data = <1343 1353 1408 1345 1342>;
+	};
+
+	qcom,pc-temp-ocv-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 15 10 9>,
+				<8 7 6 5 4>,
+				<3 2 1 0>;
+		qcom,lut-data = <4177 4174 4199 4167 4162>,
+				<4107 4112 4141 4109 4106>,
+				<4058 4064 4091 4061 4059>,
+				<3996 4015 4044 4017 4015>,
+				<3947 3975 4001 3978 3976>,
+				<3909 3939 3962 3943 3940>,
+				<3874 3901 3926 3911 3907>,
+				<3845 3858 3892 3882 3878>,
+				<3821 3826 3851 3849 3846>,
+				<3801 3804 3815 3810 3808>,
+				<3788 3789 3793 3789 3787>,
+				<3778 3780 3778 3776 3773>,
+				<3769 3776 3770 3767 3764>,
+				<3757 3772 3766 3762 3757>,
+				<3740 3765 3762 3754 3744>,
+				<3714 3747 3750 3739 3724>,
+				<3668 3706 3717 3710 3697>,
+				<3602 3644 3662 3662 3654>,
+				<3533 3571 3601 3607 3605>,
+				<3518 3557 3583 3592 3590>,
+				<3500 3543 3565 3576 3574>,
+				<3478 3528 3546 3559 3557>,
+				<3451 3506 3521 3538 3534>,
+				<3417 3473 3481 3505 3496>,
+				<3377 3423 3424 3454 3444>,
+				<3327 3361 3351 3391 3380>,
+				<3261 3279 3258 3310 3297>,
+				<3165 3165 3138 3198 3182>,
+				<3000 3000 3000 3000 3000>;
+	};
+};
diff --git a/arch/arm/boot/dts/batterydata-qrd-4v2-1800mah.dtsi b/arch/arm/boot/dts/batterydata-qrd-4v2-1800mah.dtsi
new file mode 100644
index 0000000..e44e943
--- /dev/null
+++ b/arch/arm/boot/dts/batterydata-qrd-4v2-1800mah.dtsi
@@ -0,0 +1,105 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+qcom,qrd-4v2-1800mah-data {
+	qcom,fcc-mah = <1800>;
+	qcom,default-rbatt-mohm = <146>;
+	qcom,rbatt-capacitive-mohm = <0>;
+	qcom,flat-ocv-threshold-uv = <3800000>;
+	qcom,max-voltage-uv = <4200000>;
+	qcom,v-cutoff-uv = <3400000>;
+	qcom,chg-term-ua = <100000>;
+	qcom,batt-id-kohm = <47>;
+
+	qcom,rbatt-sf-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 15 10 9>,
+				<8 7 6 5 4>,
+				<3 2 1 0>;
+		qcom,lut-data = <904 234 100 85 80>,
+				<905 234 100 85 80>,
+				<934 244 102 86 81>,
+				<928 254 105 87 82>,
+				<933 268 109 89 84>,
+				<924 280 114 91 85>,
+				<913 283 123 96 88>,
+				<916 267 135 103 91>,
+				<930 252 137 110 95>,
+				<954 247 117 106 95>,
+				<990 247 103 88 85>,
+				<1036 253 104 86 84>,
+				<1101 264 108 89 85>,
+				<1211 286 112 93 88>,
+				<1366 340 120 95 87>,
+				<1601 394 128 95 87>,
+				<2178 402 128 97 89>,
+				<5419 423 126 97 89>,
+				<10789 528 128 97 91>,
+				<13463 589 132 100 91>,
+				<17695 678 137 102 92>,
+				<23046 814 145 104 93>,
+				<30725 1019 153 106 93>,
+				<41382 1359 156 106 93>,
+				<56311 1959 165 108 95>,
+				<77209 3523 189 117 99>,
+				<104609 6039 235 127 105>,
+				<138858 9711 352 141 112>,
+				<165825 15373 1069 246 226>;
+	};
+
+	qcom,fcc-temp-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-data = <1859 1868 1873 1861 1859>;
+	};
+
+	qcom,pc-temp-ocv-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 15 10 9>,
+				<8 7 6 5 4>,
+				<3 2 1 0>;
+		qcom,lut-data = <4178 4176 4174 4169 4163>,
+				<4090 4100 4105 4101 4099>,
+				<4029 4049 4053 4050 4048>,
+				<3973 3998 4006 4004 4002>,
+				<3932 3959 3965 3962 3960>,
+				<3891 3920 3928 3925 3922>,
+				<3855 3882 3894 3891 3889>,
+				<3825 3844 3862 3862 3859>,
+				<3803 3813 3829 3834 3831>,
+				<3788 3792 3797 3802 3800>,
+				<3777 3780 3778 3776 3773>,
+				<3764 3775 3771 3767 3763>,
+				<3749 3769 3766 3763 3757>,
+				<3725 3756 3758 3755 3750>,
+				<3687 3727 3736 3735 3729>,
+				<3631 3675 3698 3698 3691>,
+				<3571 3607 3637 3642 3637>,
+				<3514 3548 3568 3572 3570>,
+				<3458 3506 3519 3522 3522>,
+				<3444 3498 3511 3516 3515>,
+				<3430 3489 3503 3509 3508>,
+				<3413 3477 3493 3500 3500>,
+				<3395 3461 3478 3488 3486>,
+				<3373 3433 3446 3463 3456>,
+				<3346 3394 3397 3418 3410>,
+				<3307 3341 3334 3361 3352>,
+				<3251 3270 3254 3287 3277>,
+				<3160 3167 3152 3183 3172>,
+				<3000 3000 3000 3000 3000>;
+	};
+};
diff --git a/arch/arm/boot/dts/batterydata-qrd-4v2-2000mah.dtsi b/arch/arm/boot/dts/batterydata-qrd-4v2-2000mah.dtsi
new file mode 100644
index 0000000..f24513c
--- /dev/null
+++ b/arch/arm/boot/dts/batterydata-qrd-4v2-2000mah.dtsi
@@ -0,0 +1,105 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+qcom,qrd-4v2-2000mah-data {
+	qcom,fcc-mah = <2000>;
+	qcom,default-rbatt-mohm = <138>;
+	qcom,rbatt-capacitive-mohm = <0>;
+	qcom,flat-ocv-threshold-uv = <3800000>;
+	qcom,max-voltage-uv = <4200000>;
+	qcom,v-cutoff-uv = <3400000>;
+	qcom,chg-term-ua = <100000>;
+	qcom,batt-id-kohm = <130 115>;
+
+	qcom,rbatt-sf-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 15 10 9>,
+				<8 7 6 5 4>,
+				<3 2 1 0>;
+		qcom,lut-data = <1191 250 100 78 69>,
+				<1192 250 100 78 69>,
+				<1242 263 102 80 70>,
+				<1192 277 105 81 71>,
+				<1202 294 108 83 72>,
+				<1205 308 113 86 73>,
+				<1234 313 118 90 76>,
+				<1255 294 131 96 80>,
+				<1284 276 139 103 84>,
+				<1321 271 115 89 74>,
+				<1363 273 104 81 72>,
+				<1400 283 103 79 71>,
+				<1404 295 105 81 71>,
+				<1428 313 108 84 73>,
+				<1489 341 112 87 74>,
+				<1615 374 115 84 73>,
+				<1813 404 117 85 73>,
+				<2121 387 127 89 76>,
+				<2310 366 115 88 77>,
+				<2543 386 116 89 77>,
+				<2879 415 118 92 78>,
+				<3633 457 122 93 78>,
+				<5901 507 128 94 79>,
+				<9939 561 131 93 79>,
+				<16631 634 129 94 78>,
+				<26968 794 134 97 81>,
+				<42610 1203 145 102 85>,
+				<64024 2628 174 115 94>,
+				<115224 17430 577 620 4155>;
+	};
+
+	qcom,fcc-temp-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-data = <2024 2033 2035 2031 2027>;
+	};
+
+	qcom,pc-temp-ocv-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 15 10 9>,
+				<8 7 6 5 4>,
+				<3 2 1 0>;
+		qcom,lut-data = <4179 4177 4173 4170 4164>,
+				<4097 4107 4108 4106 4104>,
+				<4040 4060 4059 4057 4054>,
+				<3974 4007 4012 4012 4009>,
+				<3929 3968 3972 3972 3969>,
+				<3889 3933 3937 3935 3933>,
+				<3852 3896 3905 3904 3900>,
+				<3822 3859 3876 3875 3872>,
+				<3797 3827 3846 3847 3844>,
+				<3777 3803 3809 3809 3806>,
+				<3758 3787 3788 3786 3784>,
+				<3740 3779 3777 3774 3771>,
+				<3717 3774 3771 3768 3763>,
+				<3685 3767 3767 3764 3758>,
+				<3649 3757 3761 3756 3749>,
+				<3613 3734 3747 3738 3724>,
+				<3578 3689 3711 3706 3694>,
+				<3538 3615 3649 3648 3643>,
+				<3483 3543 3564 3568 3567>,
+				<3470 3533 3553 3556 3556>,
+				<3453 3522 3542 3545 3545>,
+				<3434 3509 3531 3534 3533>,
+				<3414 3492 3519 3521 3519>,
+				<3388 3467 3498 3499 3492>,
+				<3358 3428 3457 3459 3447>,
+				<3321 3374 3397 3400 3387>,
+				<3268 3300 3318 3323 3307>,
+				<3182 3188 3207 3213 3191>,
+				<3000 3000 3000 3000 3000>;
+	};
+};
diff --git a/arch/arm/boot/dts/batterydata-qrd-4v35-2000mah.dtsi b/arch/arm/boot/dts/batterydata-qrd-4v35-2000mah.dtsi
new file mode 100644
index 0000000..b45f0f8
--- /dev/null
+++ b/arch/arm/boot/dts/batterydata-qrd-4v35-2000mah.dtsi
@@ -0,0 +1,109 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+qcom,qrd-4v35-2000mAh-data {
+	qcom,fcc-mah = <2000>;
+	qcom,default-rbatt-mohm = <172>;
+	qcom,rbatt-capacitive-mohm = <0>;
+	qcom,flat-ocv-threshold-uv = <3800000>;
+	qcom,max-voltage-uv = <4350000>;
+	qcom,v-cutoff-uv = <3400000>;
+	qcom,chg-term-ua = <100000>;
+	qcom,batt-id-kohm = <200>;
+
+	qcom,rbatt-sf-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 16 13 11>,
+				<10 9 8 7 6>,
+				<5 4 3 2 1>;
+		qcom,lut-data = <2422 324 100 79 72>,
+				<2417 325 100 79 71>,
+				<2344 327 100 80 72>,
+				<2416 336 102 81 73>,
+				<2072 354 107 82 73>,
+				<1961 372 113 84 75>,
+				<1929 341 118 87 77>,
+				<1929 321 130 93 80>,
+				<2041 306 140 104 85>,
+				<2202 292 119 96 83>,
+				<2374 290 98 80 73>,
+				<2550 292 98 79 72>,
+				<2727 294 99 81 73>,
+				<2904 303 100 82 75>,
+				<3091 323 100 81 73>,
+				<3278 348 100 80 73>,
+				<3470 376 99 79 72>,
+				<3627 386 100 79 72>,
+				<3672 398 100 80 71>,
+				<3812 424 100 80 73>,
+				<3895 443 101 80 73>,
+				<3985 465 102 82 75>,
+				<4094 497 105 83 76>,
+				<4211 533 109 85 79>,
+				<4335 579 113 87 80>,
+				<4505 612 113 85 76>,
+				<4693 643 113 86 77>,
+				<4930 712 120 90 81>,
+				<5283 835 145 111 107>,
+				<10293 15765 5566 6904 2547>;
+	};
+
+	qcom,fcc-temp-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-data = <2096 2124 2121 2118 2103>;
+	};
+
+	qcom,pc-temp-ocv-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 16 13 11>,
+				<10 9 8 7 6>,
+				<5 4 3 2 1>,
+				<0>;
+		qcom,lut-data = <4340 4340 4335 4330 4323>,
+				<4217 4260 4265 4263 4258>,
+				<4135 4203 4207 4205 4201>,
+				<4084 4150 4152 4150 4146>,
+				<3992 4101 4101 4097 4093>,
+				<3934 4049 4051 4046 4044>,
+				<3889 3974 3995 3998 3999>,
+				<3852 3926 3958 3961 3959>,
+				<3832 3892 3921 3923 3921>,
+				<3819 3859 3874 3877 3877>,
+				<3807 3831 3838 3838 3838>,
+				<3796 3809 3815 3815 3814>,
+				<3784 3792 3797 3797 3796>,
+				<3770 3780 3783 3782 3781>,
+				<3754 3770 3772 3769 3764>,
+				<3737 3758 3763 3754 3742>,
+				<3717 3737 3744 3735 3720>,
+				<3700 3713 3718 3710 3696>,
+				<3687 3701 3692 3683 3671>,
+				<3674 3695 3689 3681 3669>,
+				<3667 3692 3688 3680 3669>,
+				<3659 3690 3687 3680 3668>,
+				<3649 3687 3685 3678 3667>,
+				<3636 3683 3683 3676 3664>,
+				<3618 3674 3679 3671 3658>,
+				<3596 3652 3663 3652 3632>,
+				<3566 3611 3620 3606 3584>,
+				<3522 3547 3555 3540 3517>,
+				<3460 3449 3461 3446 3424>,
+				<3356 3282 3312 3299 3273>,
+				<3000 3000 3000 3000 3000>;
+	};
+};
diff --git a/arch/arm/boot/dts/batterydata-qrd-4v35-2500mah.dtsi b/arch/arm/boot/dts/batterydata-qrd-4v35-2500mah.dtsi
new file mode 100644
index 0000000..e3540f0
--- /dev/null
+++ b/arch/arm/boot/dts/batterydata-qrd-4v35-2500mah.dtsi
@@ -0,0 +1,105 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+qcom,qrd-4v35-2500mAh-data {
+	qcom,fcc-mah = <2500>;
+	qcom,default-rbatt-mohm = <198>;
+	qcom,rbatt-capacitive-mohm = <0>;
+	qcom,flat-ocv-threshold-uv = <3800000>;
+	qcom,max-voltage-uv = <4350000>;
+	qcom,v-cutoff-uv = <3400000>;
+	qcom,chg-term-ua = <100000>;
+	qcom,batt-id-kohm = <470>;
+
+	qcom,rbatt-sf-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 15 10 9>,
+				<8 7 6 5 4>,
+				<3 2 1 0>;
+		qcom,lut-data = <1809 428 100 64 57>,
+				<1805 428 100 64 57>,
+				<1674 443 103 65 57>,
+				<1611 447 108 66 58>,
+				<1407 474 113 69 59>,
+				<1379 462 122 74 61>,
+				<1335 381 124 74 63>,
+				<1346 388 135 79 66>,
+				<1410 382 123 82 68>,
+				<1479 372 101 68 60>,
+				<1542 363 100 66 59>,
+				<1605 368 101 66 60>,
+				<1665 406 102 68 61>,
+				<1722 460 103 70 61>,
+				<1779 525 103 68 61>,
+				<1840 593 104 66 59>,
+				<1914 669 104 65 58>,
+				<2016 779 104 65 59>,
+				<1955 827 107 67 60>,
+				<2006 855 112 69 61>,
+				<2057 882 116 71 63>,
+				<2103 925 123 72 66>,
+				<2162 955 128 73 62>,
+				<2218 991 123 69 61>,
+				<2286 1035 122 69 62>,
+				<2382 1083 130 72 65>,
+				<2780 1158 153 83 81>,
+				<5073 1464 724 393 147>,
+				<46882 49515 42109 55595 11697>;
+	};
+
+	qcom,fcc-temp-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-data = <2578 2580 2590 2584 2573>;
+	};
+
+	qcom,pc-temp-ocv-lut {
+		qcom,lut-col-legend = <(-20) 0 25 40 60>;
+		qcom,lut-row-legend = <100 95 90 85 80>,
+				<75 70 65 60 55>,
+				<50 45 40 35 30>,
+				<25 20 15 10 9>,
+				<8 7 6 5 4>,
+				<3 2 1 0>;
+		qcom,lut-data = <4326 4323 4321 4319 4311>,
+				<4192 4235 4253 4254 4249>,
+				<4110 4175 4198 4199 4194>,
+				<4058 4121 4146 4146 4141>,
+				<3952 4076 4096 4096 4091>,
+				<3906 4017 4052 4048 4043>,
+				<3859 3942 3990 3997 3999>,
+				<3828 3905 3954 3962 3959>,
+				<3813 3869 3911 3918 3916>,
+				<3799 3836 3866 3870 3868>,
+				<3786 3808 3837 3840 3840>,
+				<3772 3788 3815 3818 3817>,
+				<3758 3777 3796 3799 3798>,
+				<3743 3765 3780 3783 3781>,
+				<3726 3751 3767 3767 3761>,
+				<3707 3733 3753 3749 3736>,
+				<3684 3713 3731 3727 3713>,
+				<3654 3697 3699 3697 3685>,
+				<3616 3678 3683 3680 3669>,
+				<3605 3673 3682 3679 3667>,
+				<3594 3667 3680 3678 3666>,
+				<3578 3660 3676 3675 3662>,
+				<3561 3647 3666 3667 3647>,
+				<3541 3628 3637 3640 3610>,
+				<3514 3598 3586 3590 3556>,
+				<3478 3550 3515 3523 3485>,
+				<3425 3476 3414 3429 3387>,
+				<3330 3350 3272 3276 3222>,
+				<3000 3000 3000 3000 3000>;
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
index 5b7cc79..0b3fec4 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
@@ -61,7 +61,7 @@
 				29 01 00 00 00 00 03 D6 44 44
 				29 01 00 00 00 00 0D D7 00 00 00 00 00 00 00 00 00 00 00 00
 				29 01 00 00 00 00 0E D8 00 00 00 00 00 00 00 00 00 00 00 00 00
-				29 01 00 00 00 00 03 D9 00 28
+				29 01 00 00 00 00 03 D9 03 06
 				29 01 00 00 00 00 03 E5 00 FF
 				29 01 00 00 00 00 05 E6 F3 EC E7 DF
 				29 01 00 00 00 00 0B E7 F3 D9 CC CD B3 A6 99 99 99 95
diff --git a/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi
index befc29c..b2aeed3 100644
--- a/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi
@@ -10,7 +10,7 @@
  * GNU General Public License for more details.
  */
 
-/ {
+&soc {
 	qcom,dsi_v2_hx8379a_wvga_video {
 		compatible = "qcom,dsi-panel-v2";
 		label = "HX8379A WVGA video mode dsi panel";
@@ -21,7 +21,7 @@
 		qcom,mdss-pan-res = <480 800>;
 		qcom,mdss-pan-bpp = <24>;
 		qcom,mdss-pan-dest = "display_1";
-		qcom,mdss-pan-porch-values = <90 17 90 2 3 11>;
+		qcom,mdss-pan-porch-values = <100 40 70 6 4 6>;
 		qcom,mdss-pan-underflow-clr = <0xff>;
 		qcom,mdss-pan-bl-levels = <1 255>;
 		qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
@@ -41,8 +41,8 @@
 		qcom,mdss-pan-dsi-dma-tr = <0x04>;
 		qcom,mdss-pan-dsi-frame-rate = <60>;
 		qcom,panel-phy-regulatorSettings =[02 08 05 00 20 03];
-		qcom,panel-phy-timingSettings = [5D 12 0C  00 33 39
-						 10 16 15  03 04 00];
+		qcom,panel-phy-timingSettings = [75 1A 11  00 3D 45
+						 15 1D 1C  03 04 00];
 		qcom,panel-phy-strengthCtrl = [ff 06];
 		qcom,panel-phy-bistCtrl = [03 03 00 00 0f 00];
 		qcom,panel-phy-laneConfig =
@@ -54,34 +54,32 @@
 
 		qcom,on-cmds-dsi-state = "DSI_LP_MODE";
 		qcom,panel-on-cmds = [
-					29 01 00 00 01 04
+					39 01 00 00 00 04
 						B9 FF 83 79
-					23 01 00 00 01 02
-						BA 51
-					29 01 00 00 01 14
+					39 01 00 00 00 03
+						BA 51 93
+					39 01 00 00 00 14
 						B1 00 50 44
 						EA 8D 08 11
-						0F 0F 24 2C
+						11 11 27 2F
 						9A 1A 42 0B
 						6E F1 00 E6
-					29 01 00 00 01 0e
+					39 01 00 00 00 0E
 						B2 00 00 3C
 						08 04 19 22
 						00 FF 08 04
 						19 20
-					29 01 00 00 01 20
-						B4 80 08 00
+					39 01 00 00 00 20
+						B4 82 08 00
 						32 10 03 32
 						13 70 32 10
 						08 37 01 28
-						05 37 08 3C
-						20 44 44 08
+						07 37 08 3C
+						08 44 44 08
 						00 40 08 28
 						08 30 30 04
-					23 01 00 00 01 02
-						cc 02
-					29 01 00 00 01 30
-						D5 00 00 08
+					39 01 00 00 00 30
+						D5 00 00 0A
 						00 01 05 00
 						03 00 88 88
 						88 88 23 01
@@ -93,18 +91,20 @@
 						88 88 88 88
 						88 88 00 00
 						00 00 00 00
-					29 01 00 00 01 24
-						E0 79 00 00
-						02 1C 1F 33
-						28 3E 07 0E
-						0F 15 17 16
-						16 13 19 00
-						00 02 1C 1F
-						33 28 3E 07
-						0E 0F 15 17
-						16 16 13 19
-					29 01 00 00 01 05
-						B6 00 A6 00 A6
+					39 01 00 00 00 24
+						E0 79 05 0F
+						14 26 29 3F
+						2B 44 04 0E
+						12 15 18 16
+						16 12 15 05
+						0F 14 26 29
+						3F 2B 44 04
+						0E 12 15 18
+						16 16 12 15
+					23 01 00 00 00 02
+						cc 02
+					39 01 00 00 00 05
+						B6 00 9C 00 9C
 					05 01 00 00 96 02
 						11 00
 					05 01 00 00 78 02
diff --git a/arch/arm/boot/dts/dsi-v2-panel-otm8018b-fwvga-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-otm8018b-fwvga-video.dtsi
index c2c64da..b598d6c 100644
--- a/arch/arm/boot/dts/dsi-v2-panel-otm8018b-fwvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-v2-panel-otm8018b-fwvga-video.dtsi
@@ -10,7 +10,7 @@
  * GNU General Public License for more details.
  */
 
-/ {
+&soc  {
 	qcom,dsi_v2_otm8018b_fwvga_video {
 		compatible = "qcom,dsi-panel-v2";
 		label = "OTM8018B FWVGA video mode dsi panel";
diff --git a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-cmd.dtsi b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-cmd.dtsi
index f57a7bd..fd8d218 100644
--- a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-cmd.dtsi
@@ -10,8 +10,8 @@
  * GNU General Public License for more details.
  */
 
-/ {
-	qcom,dsi_v2_truly_wvga_video {
+&soc  {
+	qcom,dsi_v2_truly_wvga_cmd {
 		compatible = "qcom,dsi-panel-v2";
 		label = "Truly WVGA command mode dsi panel";
 		qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
@@ -65,43 +65,81 @@
 						b0 04
 					29 01 00 00 00 03
 						b3 02 00
+					29 01 00 00 00 03
+						b6 51 83
+					29 01 00 00 00 05
+						b7 00 80 15 25
+					29 01 00 00 00 14
+						b8 00 07 07 ff c8 c8 01 18 10 10
+						37 5a 87 de ff 00 00 00 00
+					29 01 00 00 00 05
+						b9 00 00 00 00
 					23 01 00 00 00 02
 						bd 00
 					29 01 00 00 00 03
-						c0 18 66
+						c0 02 43
 					29 01 00 00 00 10
-						c1 23 31 99 21 20 00 30 28 0c 0c
+						c1 43 31 99 21 20 00 10 28 0c 0c
 						00 00 00 21 01
 					29 01 00 00 00 07
-						c2 00 06 06 01 03 00
+						c2 28 06 06 01 03 00
+					29 01 00 00 00 04
+						c3 40 00 03
+					29 01 00 00 00 03
+						6f 03 00
+					29 01 00 00 00 03
+						c4 00 01
+					29 01 00 00 00 03
+						c6 00 00
+					29 01 00 00 00 06
+						c7 11 8d a0 f5 27
 					29 01 00 00 00 19
-						c8 04 10 18 20 2e 46 3c 28 1f 18
-						10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+						c8 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
 					29 01 00 00 00 19
-						c9 04 10 18 20 2e 46 3c 28 1f 18
-						10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+						c9 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
 					29 01 00 00 00 19
-						ca 04 10 18 20 2e 46 3c 28 1f 18
-						10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+						ca 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
 					29 01 00 00 00 11
-						d0 29 03 ce a6 00 43 20 10 01 00
+						d0 99 03 ce a6 00 43 20 10 01 00
 						01 01 00 03 01 00
 					29 01 00 00 00 08
 						d1 18 0C 23 03 75 02 50
 					23 01 00 00 00 02
-						d3 11
+						d3 33
 					29 01 00 00 00 03
 						d5 2a 2a
+					29 01 00 00 00 02
+						d6 28
+					29 01 00 00 00 10
+						d7 01 00 aa c0 2a 2c 22	12 71 0a 12 00 a0
+						00 03
+					29 01 00 00 00 09
+						d8 44 44 22 44 21 46 42 40
+					29 01 00 00 00 04
+						d9 cf 2d 51
+					29 01 00 00 00 02
+						da 01
 					29 01 00 00 00 03
-						de 01 51
+						de 01 4f
+					29 01 00 00 00 07
+						e1 00 00 00 00 00 00
 					23 01 00 00 00 02
-						e6 51
+						e6 4f
+					29 01 00 00 00 06
+						f3 06 00 00 24 00
+					29 01 00 00 00 02
+						f8 00
 					23 01 00 00 00 02
 						fa 03
-					23 01 00 00 64 02
-						d6 28
-					15 01 00 00 00 02
-						36 41
+					29 01 00 00 00 04
+						fb 00 00 00
+					29 01 00 00 00 06
+						fc 00 00 00 00 00
+					29 01 00 00 00 05
+						fd 00 00 70 00
 					39 01 00 00 00 05
 						2a 00 00 01 df
 					39 01 00 00 00 05
@@ -111,10 +149,12 @@
 					39 01 00 00 00 03
 						44 00 50
 					15 01 00 00 00 02
+						36 41
+					15 01 00 00 00 02
 						3a 77
 					05 01 00 00 7D 02
 						11 00
-					05 01 00 00 14 02
+					05 01 00 00 3c 02
 						29 00
 					];
 		qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
diff --git a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
index 8be8d71..538f2d8 100644
--- a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
@@ -10,7 +10,7 @@
  * GNU General Public License for more details.
  */
 
-/ {
+&soc  {
 	qcom,dsi_v2_truly_wvga_video {
 		compatible = "qcom,dsi-panel-v2";
 		label = "Truly WVGA video mode dsi panel";
@@ -61,41 +61,81 @@
 						b0 04
 					29 01 00 00 00 03
 						b3 02 00
+					29 01 00 00 00 03
+						b6 51 83
+					29 01 00 00 00 05
+						b7 00 80 15 25
+					29 01 00 00 00 14
+						b8 00 07 07 ff c8 c8 01 18 10 10
+						37 5a 87 de ff 00 00 00 00
+					29 01 00 00 00 05
+						b9 00 00 00 00
 					23 01 00 00 00 02
 						bd 00
 					29 01 00 00 00 03
-						c0 18 66
+						c0 02 43
 					29 01 00 00 00 10
-						c1 23 31 99 21 20 00 30 28 0c 0c
+						c1 43 31 99 21 20 00 10 28 0c 0c
 						00 00 00 21 01
 					29 01 00 00 00 07
-						c2 00 06 06 01 03 00
+						c2 28 06 06 01 03 00
+					29 01 00 00 00 04
+						c3 40 00 03
+					29 01 00 00 00 03
+						6f 03 00
+					29 01 00 00 00 03
+						c4 00 01
+					29 01 00 00 00 03
+						c6 00 00
+					29 01 00 00 00 06
+						c7 11 8d a0 f5 27
 					29 01 00 00 00 19
-						c8 04 10 18 20 2e 46 3c 28 1f 18
-						10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+						c8 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
 					29 01 00 00 00 19
-						c9 04 10 18 20 2e 46 3c 28 1f 18
-						10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+						c9 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
 					29 01 00 00 00 19
-						ca 04 10 18 20 2e 46 3c 28 1f 18
-						10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+						ca 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
 					29 01 00 00 00 11
-						d0 29 03 ce a6 00 43 20 10 01 00
+						d0 99 03 ce a6 00 43 20 10 01 00
 						01 01 00 03 01 00
 					29 01 00 00 00 08
 						d1 18 0C 23 03 75 02 50
 					23 01 00 00 00 02
-						d3 11
+						d3 33
 					29 01 00 00 00 03
 						d5 2a 2a
+					29 01 00 00 00 02
+						d6 28
+					29 01 00 00 00 10
+						d7 01 00 aa c0 2a 2c 22	12 71 0a 12 00 a0
+						00 03
+					29 01 00 00 00 09
+						d8 44 44 22 44 21 46 42 40
+					29 01 00 00 00 04
+						d9 cf 2d 51
+					29 01 00 00 00 02
+						da 01
 					29 01 00 00 00 03
-						de 01 51
+						de 01 4f
+					29 01 00 00 00 07
+						e1 00 00 00 00 00 00
 					23 01 00 00 00 02
-						e6 51
+						e6 4f
+					29 01 00 00 00 06
+						f3 06 00 00 24 00
+					29 01 00 00 00 02
+						f8 00
 					23 01 00 00 00 02
 						fa 03
-					23 01 00 00 64 02
-						d6 28
+					29 01 00 00 00 04
+						fb 00 00 00
+					29 01 00 00 00 06
+						fc 00 00 00 00 00
+					29 01 00 00 00 05
+						fd 00 00 70 00
 					39 01 00 00 00 05
 						2a 00 00 01 df
 					39 01 00 00 00 05
@@ -110,11 +150,15 @@
 						3a 77
 					05 01 00 00 7D 02
 						11 00
-					05 01 00 00 14 02
+					05 01 00 00 3c 02
 						29 00
 					];
 		qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
-					05 01 00 00 78 02 10 00];
+					05 01 00 00 78 02 10 00
+					23 01 00 00 10 02
+						b0 04
+					23 01 00 00 20 02
+						b1 01];
 		qcom,off-cmds-dsi-state = "DSI_LP_MODE";
 	};
 };
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 1d7eaa5..1820dc7 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -218,6 +218,7 @@
 			interrupt-names = "eoc-int-en-set";
 			qcom,adc-bit-resolution = <15>;
 			qcom,adc-vdd-reference = <1800>;
+			qcom,vadc-poll-eoc;
 
 			chan@8 {
 				label = "die_temp";
@@ -263,6 +264,7 @@
 			qcom,adc-bit-resolution = <16>;
 			qcom,adc-vdd-reference = <1800>;
 			qcom,iadc-vadc = <&pm8110_vadc>;
+			qcom,iadc-poll-eoc;
 
 			chan@0 {
 				label = "internal_rsense";
@@ -346,14 +348,14 @@
 						<0x0 0x40 0x6>,
 						<0x0 0x40 0x7>;
 
-				interrupt-names = "vsense_for_r",
-						  "vsense_avg",
-						  "sw_cc_thr",
-						  "ocv_thr",
-						  "charge_begin",
-						  "good_ocv",
+				interrupt-names = "cc_thr",
 						  "ocv_for_r",
-						  "cc_thr";
+						  "good_ocv",
+						  "charge_begin",
+						  "ocv_thr",
+						  "sw_cc_thr",
+						  "vsense_avg",
+						  "vsense_for_r";
 			};
 		};
 
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index ccbcc72..5642d4d 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -22,7 +22,7 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
-		qcom,revid@100 {
+		pm8226_revid: qcom,revid@100 {
 			compatible = "qcom,qpnp-revid";
 			reg = <0x100 0x100>;
 		};
@@ -48,11 +48,7 @@
 
 			qcom,pon_2 {
 				qcom,pon-type = <1>;
-				qcom,support-reset = <1>;
 				qcom,pull-up = <1>;
-				qcom,s1-timer = <0>;
-				qcom,s2-timer = <2000>;
-				qcom,s2-type = <1>;
 				linux,code = <114>;
 			};
 
@@ -85,6 +81,7 @@
 			qcom,tchg-mins = <150>;
 			qcom,chg-vadc = <&pm8226_vadc>;
 			qcom,chg-adc_tm = <&pm8226_adc_tm>;
+			qcom,pmic-revid = <&pm8226_revid>;
 			qcom,ibatmax-warm-ma = <350>;
 			qcom,warm-bat-decidegc = <450>;
 			qcom,warm-bat-mv = <4100>;
@@ -225,14 +222,14 @@
 						<0x0 0x40 0x6>,
 						<0x0 0x40 0x7>;
 
-				interrupt-names = "vsense_for_r",
-						  "vsense_avg",
-						  "sw_cc_thr",
-						  "ocv_thr",
-						  "charge_begin",
-						  "good_ocv",
+				interrupt-names = "cc_thr",
 						  "ocv_for_r",
-						  "cc_thr";
+						  "good_ocv",
+						  "charge_begin",
+						  "ocv_thr",
+						  "sw_cc_thr",
+						  "vsense_avg",
+						  "vsense_for_r";
 			};
 		};
 
@@ -825,43 +822,55 @@
 			status = "disabled";
 		};
 
-                qcom,leds@d300 {
-                        compatible = "qcom,leds-qpnp";
-                        status = "okay";
-                        reg = <0xd300 0x100>;
-                        label = "flash";
-			flash_boost-supply = <&pm8226_chg_boost>;
-                        pm8226_flash0: qcom,flash_0 {
-                                qcom,max-current = <1000>;
-                                qcom,default-state = "off";
-                                qcom,headroom = <0>;
-                                qcom,duration = <1280>;
-                                qcom,clamp-curr = <200>;
-                                qcom,startup-dly = <1>;
-                                qcom,safety-timer;
-                                label = "flash";
-                                linux,default-trigger =
-                                        "flash0_trigger";
-                                qcom,id = <1>;
-                                linux,name = "led:flash_0";
-                                qcom,current = <625>;
-                        };
+		qcom,leds@d300 {
+			compatible = "qcom,leds-qpnp";
+			status = "okay";
+			reg = <0xd300 0x100>;
+			label = "flash";
+			flash-boost-supply = <&pm8226_chg_boost>;
+			pm8226_flash0: qcom,flash_0 {
+				qcom,max-current = <1000>;
+				qcom,default-state = "off";
+				qcom,headroom = <0>;
+				qcom,duration = <1280>;
+				qcom,clamp-curr = <200>;
+				qcom,startup-dly = <1>;
+				qcom,safety-timer;
+				label = "flash";
+				linux,default-trigger =
+						"flash0_trigger";
+				qcom,id = <1>;
+				linux,name = "led:flash_0";
+				qcom,current = <625>;
+			};
 
-                        pm8226_flash1: qcom,flash_1 {
-                                qcom,max-current = <1000>;
-                                qcom,default-state = "off";
-                                qcom,headroom = <0>;
-                                qcom,duration = <1280>;
-                                qcom,clamp-curr = <200>;
-                                qcom,startup-dly = <1>;
-                                qcom,safety-timer;
-                                linux,default-trigger =
-                                        "flash1_trigger";
-                                label = "flash";
-                                qcom,id = <2>;
-                                linux,name = "led:flash_1";
-                                qcom,current = <625>;
-                        };
+			pm8226_flash1: qcom,flash_1 {
+				qcom,max-current = <1000>;
+				qcom,default-state = "off";
+				qcom,headroom = <0>;
+				qcom,duration = <1280>;
+				qcom,clamp-curr = <200>;
+				qcom,startup-dly = <1>;
+				qcom,safety-timer;
+				linux,default-trigger =
+						"flash1_trigger";
+				label = "flash";
+				qcom,id = <2>;
+				linux,name = "led:flash_1";
+				qcom,current = <625>;
+			};
+
+			pm8226_torch: qcom,flash_torch {
+				qcom,max-current = <200>;
+				qcom,default-state = "off";
+				linux,default-trigger =
+						"torch_trigger";
+				label = "flash";
+				qcom,id = <1>;
+				linux,name = "led:flash_torch";
+				qcom,current = <120>;
+				qcom,torch-enable;
+			};
                 };
 	};
 };
diff --git a/arch/arm/boot/dts/msm-pm8841.dtsi b/arch/arm/boot/dts/msm-pm8841.dtsi
index a2d80ec..43bd0c9 100644
--- a/arch/arm/boot/dts/msm-pm8841.dtsi
+++ b/arch/arm/boot/dts/msm-pm8841.dtsi
@@ -238,5 +238,28 @@
 				reg = <0x2b00 0x100>;
 			};
 		};
+
+		krait_regulator_pmic: qcom,krait-regulator-pmic@2000 {
+			spmi-dev-container;
+			compatible = "qcom,krait-regulator-pmic";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			status = "disabled";
+
+			qcom,ctl@2000 {
+				status = "disabled";
+				reg = <0x2000 0x100>;
+			};
+
+			qcom,ps@2100 {
+				status = "disabled";
+				reg = <0x2100 0x100>;
+			};
+
+			qcom,freq@2200 {
+				status = "disabled";
+				reg = <0x2200 0x100>;
+			};
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index ed5756f..583cd3c 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -1253,8 +1253,8 @@
 		compatible = "qcom,leds-qpnp";
 		reg = <0xd300 0x100>;
 		label = "flash";
-		flash_boost-supply = <&pm8941_chg_boost>;
-		torch_boost-supply = <&pm8941_boost>;
+		flash-boost-supply = <&pm8941_chg_boost>;
+		torch-boost-supply = <&pm8941_boost>;
 	};
 
 	qcom,leds@d400 {
diff --git a/arch/arm/boot/dts/msm-pma8084.dtsi b/arch/arm/boot/dts/msm-pma8084.dtsi
index 808f0f6..c070443 100644
--- a/arch/arm/boot/dts/msm-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm-pma8084.dtsi
@@ -264,6 +264,7 @@
 			interrupt-names = "eoc-int-en-set";
 			qcom,adc-bit-resolution = <15>;
 			qcom,adc-vdd-reference = <1800>;
+			qcom,vadc-poll-eoc;
 
 			chan@8 {
 				label = "die_temp";
@@ -813,5 +814,28 @@
 			compatible = "qcom,qpnp-regulator";
 			status = "disabled";
 		};
+
+		krait_regulator_pmic: qcom,krait-regulator-pmic@2900 {
+			spmi-dev-container;
+			compatible = "qcom,krait-regulator-pmic";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			status = "disabled";
+
+			qcom,ctl@2900 {
+				reg = <0x2900 0x100>;
+				status = "disabled";
+			};
+
+			qcom,ps@2a00 {
+				reg = <0x2a00 0x100>;
+				status = "disabled";
+			};
+
+			qcom,freq@2b00 {
+				reg = <0x2b00 0x100>;
+				status = "disabled";
+			};
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
index f807814..5d7a7ec 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
@@ -18,6 +18,7 @@
 		compatible = "qcom,camera-led-flash";
 		qcom,flash-type = <1>;
 		qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+		qcom,torch-source = <&pm8226_torch>;
 	};
 };
 
@@ -38,7 +39,7 @@
 		qcom,csid-sd-index = <0>;
 		qcom,actuator-src = <&actuator0>;
 		qcom,led-flash-src = <&led_flash0>;
-		qcom,mount-angle = <0>;
+		qcom,mount-angle = <180>;
 		qcom,sensor-name = "ov8825";
 		cam_vdig-supply = <&pm8226_l5>;
 		cam_vana-supply = <&pm8226_l19>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
index 56e8a09..5d1e1c8 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
@@ -18,6 +18,7 @@
 		compatible = "qcom,camera-led-flash";
 		qcom,flash-type = <1>;
 		qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+		qcom,torch-source = <&pm8226_torch>;
 	};
 };
 
@@ -38,7 +39,7 @@
 		qcom,csid-sd-index = <0>;
 		qcom,actuator-src = <&actuator0>;
 		qcom,led-flash-src = <&led_flash0>;
-		qcom,mount-angle = <90>;
+		qcom,mount-angle = <270>;
 		qcom,sensor-name = "ov8825";
 		cam_vdig-supply = <&pm8226_l5>;
 		cam_vana-supply = <&pm8226_l19>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
index fb24a25..3eacef2 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
@@ -18,6 +18,7 @@
 		compatible = "qcom,camera-led-flash";
 		qcom,flash-type = <1>;
 		qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+		qcom,torch-source = <&pm8226_torch>;
 	};
 };
 
@@ -30,6 +31,79 @@
 		qcom,cci-master = <0>;
 	};
 
+	eeprom0: qcom,eeprom@6c {
+		cell-index = <0>;
+		reg = <0x6c 0x0>;
+		qcom,eeprom-name = "truly_cm7700";
+		compatible = "qcom,eeprom";
+		qcom,slave-addr = <0x6c>;
+		qcom,cci-master = <0>;
+		qcom,num-blocks = <9>;
+		qcom,page0 = <1 0x0100 2 0x01 1 1>;
+		qcom,poll0 = <0 0x0 2 0 1 1>;
+		qcom,mem0 = <0 0x0 2 0 1 0>;
+		qcom,page1 = <1 0x3d84 2 0x8 1 1>;
+		qcom,pageen1 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll1 = <0 0x0 2 0 1 1>;
+		qcom,mem1 = <32 0x3d00 2 0 1 0>;
+		qcom,page2 = <1 0x3d84 2 0x9 1 1>;
+		qcom,pageen2 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll2 = <0 0x0 2 0 1 1>;
+		qcom,mem2 = <32 0x3d00 2 0 1 0>;
+		qcom,page3 = <1 0x3d84 2 0xa 1 1>;
+		qcom,pageen3 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll3 = <0 0x0 2 0 1 1>;
+		qcom,mem3 = <32 0x3d00 2 0 1 0>;
+		qcom,page4 = <1 0x3d84 2 0xb 1 1>;
+		qcom,pageen4 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll4 = <0 0x0 2 0 1 1>;
+		qcom,mem4 = <32 0x3d00 2 0 1 0>;
+		qcom,page5 = <1 0x3d84 2 0xc 1 1>;
+		qcom,pageen5 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll5 = <0 0x0 2 0 1 1>;
+		qcom,mem5 = <32 0x3d00 2 0 1 0>;
+		qcom,page6 = <1 0x3d84 2 0xd 1 1>;
+		qcom,pageen6 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll6 = <0 0x0 2 0 1 1>;
+		qcom,mem6 = <32 0x3d00 2 0 1 0>;
+		qcom,page7 = <1 0x3d84 2 0xe 1 1>;
+		qcom,pageen7 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll7 = <0 0x0 2 0 1 1>;
+		qcom,mem7 = <32 0x3d00 2 0 1 0>;
+		qcom,page8 = <1 0x3d84 2 0xf 1 1>;
+		qcom,pageen8 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll8 = <0 0x0 2 0 1 1>;
+		qcom,mem8 = <32 0x3d00 2 0 1 0>;
+
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio";
+		qcom,cam-vreg-type = <0 1>;
+		qcom,cam-vreg-min-voltage = <1200000 0>;
+		qcom,cam-vreg-max-voltage = <1200000 0>;
+		qcom,cam-vreg-op-mode = <200000 0>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+			<&msmgpio 37 0>,
+			<&msmgpio 36 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+			"CAM_RESET1",
+			"CAM_STANDBY";
+		qcom,cam-power-seq-type = "sensor_vreg",
+			"sensor_vreg", "sensor_clk",
+			"sensor_gpio", "sensor_gpio";
+		qcom,cam-power-seq-val = "cam_vdig",
+			"cam_vio", "sensor_cam_mclk",
+			"sensor_gpio_reset",
+			"sensor_gpio_standby";
+		qcom,cam-power-seq-cfg-val = <1 1 24000000 1 1>;
+		qcom,cam-power-seq-delay = <1 1 5 5 10>;
+	};
+
 	qcom,camera@6f {
 		compatible = "qcom,ov8825";
 		reg = <0x6f>;
@@ -38,7 +112,8 @@
 		qcom,csid-sd-index = <0>;
 		qcom,actuator-src = <&actuator0>;
 		qcom,led-flash-src = <&led_flash0>;
-		qcom,mount-angle = <270>;
+		qcom,eeprom-src = <&eeprom0>;
+		qcom,mount-angle = <90>;
 		qcom,sensor-name = "ov8825";
 		cam_vdig-supply = <&pm8226_l5>;
 		cam_vana-supply = <&pm8226_l19>;
@@ -75,6 +150,108 @@
 		qcom,cci-master = <0>;
 	};
 
+	eeprom1: qcom,eeprom@18{
+		cell-index = <1>;
+		reg = <0x18 0x0>;
+		qcom,eeprom-name = "sunny_p12v01m";
+		compatible = "qcom,eeprom";
+		qcom,slave-addr = <0x20>;
+		qcom,cci-master = <0>;
+		qcom,num-blocks = <16>;
+		qcom,page0 = <1 0x0100 2 0x01 1 1>;
+		qcom,poll0 = <0 0x0 2 0 1 1>;
+		qcom,mem0 = <0 0x0 2 0 1 0>;
+		qcom,page1 = <1 0x3d84 2 0xc1 1 1>;
+		qcom,pageen1 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll1 = <0 0x0 2 0 1 1>;
+		qcom,mem1 = <16 0x3d00 2 0 1 0>;
+		qcom,page2 = <1 0x3d84 2 0xc2 1 1>;
+		qcom,pageen2 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll2 = <0 0x0 2 0 1 1>;
+		qcom,mem2 = <16 0x3d00 2 0 1 0>;
+		qcom,page3 = <1 0x3d84 2 0xc3 1 1>;
+		qcom,pageen3 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll3 = <0 0x0 2 0 1 1>;
+		qcom,mem3 = <16 0x3d00 2 0 1 0>;
+		qcom,page4 = <1 0x3d84 2 0xc4 1 1>;
+		qcom,pageen4 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll4 = <0 0x0 2 0 1 1>;
+		qcom,mem4 = <16 0x3d00 2 0 1 0>;
+		qcom,page5 = <1 0x3d84 2 0xc5 1 1>;
+		qcom,pageen5 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll5 = <0 0x0 2 0 1 1>;
+		qcom,mem5 = <16 0x3d00 2 0 1 0>;
+		qcom,page6 = <1 0x3d84 2 0xc6 1 1>;
+		qcom,pageen6 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll6 = <0 0x0 2 0 1 1>;
+		qcom,mem6 = <16 0x3d00 2 0 1 0>;
+		qcom,page7 = <1 0x3d84 2 0xc7 1 1>;
+		qcom,pageen7 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll7 = <0 0x0 2 0 1 1>;
+		qcom,mem7 = <16 0x3d00 2 0 1 0>;
+		qcom,page8 = <1 0x3d84 2 0xc8 1 1>;
+		qcom,pageen8 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll8 = <0 0x0 2 0 1 1>;
+		qcom,mem8 = <16 0x3d00 2 0 1 0>;
+		qcom,page9 = <1 0x3d84 2 0xc9 1 1>;
+		qcom,pageen9 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll9 = <0 0x0 2 0 1 1>;
+		qcom,mem9 = <16 0x3d00 2 0 1 0>;
+		qcom,page10 = <1 0x3d84 2 0xca 1 1>;
+		qcom,pageen10 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll10 = <0 0x0 2 0 1 1>;
+		qcom,mem10 = <16 0x3d00 2 0 1 0>;
+		qcom,page11 = <1 0x3d84 2 0xcb 1 1>;
+		qcom,pageen11 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll11 = <0 0x0 2 0 1 1>;
+		qcom,mem11 = <16 0x3d00 2 0 1 0>;
+		qcom,page12 = <1 0x3d84 2 0xcc 1 1>;
+		qcom,pageen12 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll12 = <0 0x0 2 0 1 1>;
+		qcom,mem12 = <16 0x3d00 2 0 1 0>;
+		qcom,page13 = <1 0x3d84 2 0xcd 1 1>;
+		qcom,pageen13 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll13 = <0 0x0 2 0 1 1>;
+		qcom,mem13 = <16 0x3d00 2 0 1 0>;
+		qcom,page14 = <1 0x3d84 2 0xce 1 1>;
+		qcom,pageen14 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll14 = <0 0x0 2 0 1 1>;
+		qcom,mem14 = <16 0x3d00 2 0 1 0>;
+		qcom,page15 = <1 0x3d84 2 0xcf 1 1>;
+		qcom,pageen15 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll15 = <0 0x0 2 0 1 1>;
+		qcom,mem15 = <16 0x3d00 2 0 1 0>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		cam_vana-supply = <&pm8226_l19>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vana";
+		qcom,cam-vreg-type = <1 0>;
+		qcom,cam-vreg-min-voltage = <0 2850000>;
+		qcom,cam-vreg-max-voltage = <0 2850000>;
+		qcom,cam-vreg-op-mode = <0 80000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+			<&msmgpio 37 0>,
+			<&msmgpio 36 0>,
+			<&msmgpio 22 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vdig = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+			"CAM_RESET1",
+			"CAM_STANDBY",
+			"CAM_VDIG";
+		qcom,cam-power-seq-type = "sensor_vreg",
+			"sensor_vreg", "sensor_gpio",
+			"sensor_gpio", "sensor_gpio" , "sensor_clk";
+		qcom,cam-power-seq-val = "cam_vio", "cam_vana","sensor_gpio_vdig",
+			 "sensor_gpio_reset",
+			"sensor_gpio_standby","sensor_cam_mclk" ;
+		qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>;
+		qcom,cam-power-seq-delay = <1 1 10 10 10 5>;
+	};
+
 	qcom,camera@6c {
 		compatible = "qcom,ov12830";
 		reg = <0x6c>;
@@ -83,7 +260,8 @@
 		qcom,csid-sd-index = <0>;
 		qcom,actuator-src = <&actuator1>;
 		qcom,led-flash-src = <&led_flash0>;
-		qcom,mount-angle = <270>;
+		qcom,eeprom-src = <&eeprom1>;
+		qcom,mount-angle = <90>;
 		qcom,sensor-name = "skuf_ov12830_p12v01c";
 		cam_vdig-supply = <&pm8226_l5>;
 		cam_vana-supply = <&pm8226_l19>;
@@ -157,12 +335,79 @@
 		status = "ok";
 	};
 
+	eeprom2: qcom,eeprom@6b{
+		cell-index = <2>;
+		reg = <0x6b 0x0>;
+		qcom,eeprom-name = "sunny_p5v23c";
+		compatible = "qcom,eeprom";
+		qcom,slave-addr = <0x6c>;
+		qcom,cci-master = <0>;
+		qcom,num-blocks = <7>;
+
+		qcom,page0 = <1 0x0100 2 0x01 1 1>;
+		qcom,poll0 = <0 0x0 2 0 1 1>;
+		qcom,mem0 = <0 0x0 2 0 1 0>;
+
+		qcom,page1 = <1 0x3d84 2 0xc0 1 1>;
+		qcom,poll1 = <0 0x0 2 0 1 1>;
+		qcom,mem1 = <0 0x0 2 0 1 0>;
+		qcom,page2 = <1 0x3d85 2 0x00 1 1>;
+		qcom,poll2 = <0 0x0 2 0 1 1>;
+		qcom,mem2 = <0 0x0 2 0 1 0>;
+		qcom,page3 = <1 0x3d86 2 0x0f 1 1>;
+		qcom,pageen3 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll3 = <0 0x0 2 0 1 1>;
+		qcom,mem3 = <16 0x3d00 2 0 1 0>;
+
+		qcom,page4 = <1 0x3d84 2 0xc0 1 1>;
+		qcom,poll4 = <0 0x0 2 0 1 1>;
+		qcom,mem4 = <0 0x0 2 0 1 0>;
+		qcom,page5 = <1 0x3d85 2 0x10 1 1>;
+		qcom,poll5 = <0 0x0 2 0 1 1>;
+		qcom,mem5 = <0 0x0 2 0 1 0>;
+		qcom,page6 = <1 0x3d86 2 0x1f 1 1>;
+		qcom,pageen6 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll6 = <0 0x0 2 0 1 1>;
+		qcom,mem6 = <16 0x3d00 2 0 1 0>;
+
+		cam_vio-supply = <&pm8226_lvs1>;
+		cam_vana-supply = <&pm8226_l19>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+		qcom,cam-vreg-type = <0 1 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+			<&msmgpio 28 0>,
+			<&msmgpio 35 0>,
+			<&msmgpio 21 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vdig = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+			"CAM_RESET",
+			"CAM_STANDBY",
+			"CAM_VDIG";
+		qcom,cam-power-seq-type = "sensor_vreg",
+			"sensor_vreg", "sensor_gpio",
+			"sensor_gpio", "sensor_gpio" , "sensor_clk";
+		qcom,cam-power-seq-val = "cam_vio", "cam_vana","sensor_gpio_vdig",
+			 "sensor_gpio_reset",
+			"sensor_gpio_standby","sensor_cam_mclk" ;
+		qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>;
+		qcom,cam-power-seq-delay = <1 1 10 10 10 5>;
+	};
+
 	qcom,camera@6a {
 		compatible = "qcom,ov5648";
 		reg = <0x6a>;
 		qcom,slave-id = <0x6c 0x300a 0x5648>;
 		qcom,csiphy-sd-index = <1>;
 		qcom,csid-sd-index = <1>;
+		qcom,eeprom-src = <&eeprom2>;
 		qcom,mount-angle = <270>;
 		qcom,sensor-name = "skuf_ov5648_p5v23c";
 		cam_vdig-supply = <&pm8226_l5>;
@@ -192,7 +437,7 @@
 		qcom,gpio-set-tbl-delay = <1000 4000>;
 		qcom,csi-lane-assign = <0x4320>;
 		qcom,csi-lane-mask = <0x3>;
-		qcom,sensor-position = <0>;
+		qcom,sensor-position = <1>;
 		qcom,sensor-mode = <1>;
 		qcom,cci-master = <0>;
 		status = "ok";
diff --git a/arch/arm/boot/dts/msm8226-camera.dtsi b/arch/arm/boot/dts/msm8226-camera.dtsi
index 617d738..4987dae 100644
--- a/arch/arm/boot/dts/msm8226-camera.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera.dtsi
@@ -74,8 +74,9 @@
 		cell-index = <0>;
 		compatible = "qcom,vfe40";
 		reg = <0xfda10000 0x1000>,
-		      <0xfda40000 0x200>;
-		reg-names = "vfe", "vfe_vbif";
+			<0xfda40000 0x200>,
+			<0xfd4a8000 0x4>;
+		reg-names = "vfe", "vfe_vbif", "tcsr";
 		interrupts = <0 57 0>;
 		interrupt-names = "vfe";
 		vdd-supply = <&gdsc_vfe>;
@@ -103,7 +104,7 @@
 		compatible = "qcom,cpp";
 		reg = <0xfda04000 0x100>,
 		      <0xfda40000 0x200>,
-		      <0xfda18000 0x008>;
+		      <0xfda18000 0x018>;
 		reg-names = "cpp", "cpp_vbif", "cpp_hw";
 		interrupts = <0 49 0>;
 		interrupt-names = "cpp";
diff --git a/arch/arm/boot/dts/msm8226-cdp.dtsi b/arch/arm/boot/dts/msm8226-cdp.dtsi
index 104cb4c..253ce3f 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-cdp.dtsi
@@ -35,7 +35,6 @@
 			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
 			synaptics,button-map = <139 102 158>;
 			synaptics,i2c-pull-up;
-			synaptics,power-down;
 		};
 	};
 
@@ -111,6 +110,24 @@
 		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
 		qcom,headset-jack-type-NO;
 	};
+
+	sound-9302 {
+		qcom,audio-routing =
+			"RX_BIAS", "MCLK",
+			"LDO_H", "MCLK",
+			"SPK_OUT", "MCLK",
+			"SPK_OUT", "EXT_VDD_SPKR",
+			"AMIC1", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Handset Mic",
+			"AMIC2", "MIC BIAS2 External",
+			"MIC BIAS2 External", "Headset Mic",
+			"AMIC3", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Handset Mic";
+
+		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+		qcom,headset-jack-type-NO;
+	};
 };
 
 &sdcc1 {
@@ -257,7 +274,7 @@
 			qcom,led_mpp_4 {
 				label = "mpp";
 				linux,name = "green";
-				linux,default-trigger = "none";
+				linux,default-trigger = "battery-full";
 				qcom,default-state = "off";
 				qcom,max-current = <40>;
 				qcom,current-setting = <5>;
@@ -283,7 +300,7 @@
 			qcom,led_mpp_6 {
 				label = "mpp";
 				linux,name = "red";
-				linux,default-trigger = "none";
+				linux,default-trigger = "battery-charging";
 				qcom,default-state = "off";
 				qcom,max-current = <40>;
 				qcom,current-setting = <5>;
@@ -325,6 +342,12 @@
 				qcom,id = <0>;
 			};
 		};
+
+		qcom,vibrator@c000 {
+			status = "okay";
+			qcom,vib-timeout-ms = <15000>;
+			qcom,vib-vtg-level-mV = <3100>;
+		};
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8226-ion.dtsi b/arch/arm/boot/dts/msm8226-ion.dtsi
index 9574b7d..30c3209 100644
--- a/arch/arm/boot/dts/msm8226-ion.dtsi
+++ b/arch/arm/boot/dts/msm8226-ion.dtsi
@@ -55,18 +55,12 @@
 			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
 			qcom,memory-reservation-size = <0x314000>;
 		};
+
 		qcom,ion-heap@23 { /* OTHER PIL HEAP */
 			compatible = "qcom,msm-ion-reserve";
 			reg = <23>;
 			qcom,heap-align = <0x1000>;
-			qcom,memory-fixed = <0x06400000 0x2000000>;
-		};
-		qcom,ion-heap@26 { /* MODEM PIL HEAP */
-			compatible = "qcom,msm-ion-reserve";
-			reg = <26>;
-			qcom,heap-align = <0x1000>;
-			qcom,memory-fixed = <0x08400000 0x4E00000>;
-
+			qcom,memory-fixed = <0x0dc00000 0x1900000>;
 		};
 
 	};
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 5f991fb..8852a8d 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -41,7 +41,7 @@
 		qcom,vbif-settings = <0x004 0x00000001>,
 				     <0x0D8 0x00000707>,
 				     <0x124 0x00000003>;
-		qcom,mdp-settings = <0x02E0 0x000000A9>,
+		qcom,mdp-settings = <0x02E0 0x000000A5>,
 				    <0x02E4 0x00000055>;
 
 		mdss_fb0: qcom,mdss_fb_primary {
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-mtp.dtsi
index 977c772..68621fc 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-mtp.dtsi
@@ -35,7 +35,6 @@
 			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
 			synaptics,button-map = <139 102 158>;
 			synaptics,i2c-pull-up;
-			synaptics,power-down;
 		};
 	};
 
@@ -105,14 +104,31 @@
 			"MIC BIAS1 External", "Handset Mic",
 			"AMIC2", "MIC BIAS2 External",
 			"MIC BIAS2 External", "Headset Mic",
-			"AMIC3", "MIC BIAS1 External",
-			"MIC BIAS1 External", "ANCRight Headset Mic",
 			"AMIC4", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCRight Headset Mic",
+			"AMIC5", "MIC BIAS2 External",
 			"MIC BIAS2 External", "ANCLeft Headset Mic";
 
 		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
 		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
 	};
+
+	sound-9302 {
+		qcom,audio-routing =
+			"RX_BIAS", "MCLK",
+			"LDO_H", "MCLK",
+			"SPK_OUT", "MCLK",
+			"SPK_OUT", "EXT_VDD_SPKR",
+			"AMIC1", "MIC BIAS1 Internal1",
+			"MIC BIAS1 Internal1", "Handset Mic",
+			"AMIC2", "MIC BIAS2 External",
+			"MIC BIAS2 External", "Headset Mic",
+			"AMIC3", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Handset Mic";
+
+		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+	};
 };
 
 &usb_otg {
@@ -261,7 +277,7 @@
 			qcom,led_mpp_4 {
 				label = "mpp";
 				linux,name = "green";
-				linux,default-trigger = "none";
+				linux,default-trigger = "battery-full";
 				qcom,default-state = "off";
 				qcom,max-current = <40>;
 				qcom,current-setting = <5>;
@@ -287,7 +303,7 @@
 			qcom,led_mpp_6 {
 				label = "mpp";
 				linux,name = "red";
-				linux,default-trigger = "none";
+				linux,default-trigger = "battery-charging";
 				qcom,default-state = "off";
 				qcom,max-current = <40>;
 				qcom,current-setting = <5>;
@@ -333,6 +349,12 @@
 				qcom,id = <0>;
 			};
 		};
+
+		qcom,vibrator@c000 {
+			status = "okay";
+			qcom,vib-timeout-ms = <15000>;
+			qcom,vib-vtg-level-mV = <3100>;
+		};
 	};
 };
 
@@ -446,6 +468,11 @@
 
 &pm8226_bms {
 	status = "ok";
+	qcom,enable-fcc-learning;
+	qcom,min-fcc-learning-soc = <20>;
+	qcom,min-fcc-ocv-pc = <30>;
+	qcom,min-fcc-learning-samples = <5>;
+	qcom,fcc-resolution = <10>;
 };
 
 &pm8226_chg {
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index a10b499..88c44e6 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -16,7 +16,6 @@
 &soc {
 	serial@f991f000 {
 		status = "ok";
-		qcom,cont-splash-enabled;
 	};
 
 	i2c@f9927000 { /* BLSP1 QUP5 */
@@ -31,7 +30,6 @@
 			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
 			synaptics,button-map = <139 102 158>;
 			synaptics,i2c-pull-up;
-			synaptics,power-down;
 		};
 		focaltech@38 {
 			compatible = "focaltech,5x06";
@@ -117,15 +115,33 @@
 			"MIC BIAS1 External", "Handset Mic",
 			"AMIC2", "MIC BIAS2 External",
 			"MIC BIAS2 External", "Headset Mic",
-			"AMIC3", "MIC BIAS1 External",
-			"MIC BIAS1 External", "ANCRight Headset Mic",
 			"AMIC4", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCRight Headset Mic",
+			"AMIC5", "MIC BIAS2 External",
 			"MIC BIAS2 External", "ANCLeft Headset Mic";
 
 		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
 		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
 		qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
 	};
+
+	sound-9302 {
+		qcom,audio-routing =
+			"RX_BIAS", "MCLK",
+			"LDO_H", "MCLK",
+			"SPK_OUT", "MCLK",
+			"SPK_OUT", "EXT_VDD_SPKR",
+			"AMIC1", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Handset Mic",
+			"AMIC2", "MIC BIAS2 External",
+			"MIC BIAS2 External", "Headset Mic",
+			"AMIC3", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Handset Mic";
+
+		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+		qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
+	};
 };
 
 &sdcc1 {
@@ -344,16 +360,28 @@
 	};
 };
 
+/ {
+	qrd_batterydata: qcom,battery-data {
+		qcom,rpull-up-kohm = <100>;
+		qcom,vref-batt-therm = <1800000>;
+
+		/include/ "batterydata-qrd-4v35-2000mah.dtsi"
+	};
+};
+
 &pm8226_bms {
 	status = "okay";
-	qcom,batt-type = <4>;
-	qcom,max-voltage-uv = <4350000>;
+	qcom,enable-fcc-learning;
+	qcom,min-fcc-learning-soc = <20>;
+	qcom,min-fcc-ocv-pc = <30>;
+	qcom,min-fcc-learning-samples = <5>;
+	qcom,fcc-resolution = <10>;
+	qcom,battery-data = <&qrd_batterydata>;
 };
 
 &pm8226_chg {
 	status = "okay";
-	qcom,vddmax-mv = <4350>;
-	qcom,vddsafe-mv = <4380>;
+	qcom,battery-data = <&qrd_batterydata>;
 	qcom,tchg-mins = <240>;
 };
 
diff --git a/arch/arm/boot/dts/msm8226-v1-mtp.dts b/arch/arm/boot/dts/msm8226-v1-mtp.dts
index 6f03dca..c32adbe 100644
--- a/arch/arm/boot/dts/msm8226-v1-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-v1-mtp.dts
@@ -25,8 +25,8 @@
 };
 
 &cci {
-	/* Rotate rear camera to 0 degrees */
+	/* Rotate rear camera to 180 degrees */
 	qcom,camera@6f {
-	qcom,mount-angle = <0>;
+	qcom,mount-angle = <180>;
 	};
 };
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
similarity index 82%
copy from arch/arm/boot/dts/msm8610-pm.dtsi
copy to arch/arm/boot/dts/msm8226-v1-pm.dtsi
index d31a65c..dcf46e6 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
@@ -24,7 +24,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
@@ -41,9 +41,9 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		};
+	};
 
 	qcom,spm@f90a9000 {
 		compatible = "qcom,spm-v2";
@@ -56,10 +56,10 @@
 		qcom,saw2-spm-dly= <0x3c102800>;
 		qcom,saw2-spm-ctl = <0x8>;
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
-		qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
-				0b 94 5b 80 10 06 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 07 60 3b 76 76
-				0b 94 5b 80 10 06 26 30 0f];
+		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
+				0b 94 5b 80 10 26 30 0f];
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
+				0b 94 5b 80 10 26 30 0f];
 	};
 
 	qcom,spm@f90b9000 {
@@ -75,7 +75,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
@@ -99,6 +99,7 @@
 		qcom,saw2-spm-cmd-pc = [00 32 b0 10 e0 d0 6b c0 42 f0
 				11 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
 				50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
+		qcom,L2-spm-is-apcs-master;
 	};
 
 	qcom,lpm-levels {
@@ -167,24 +168,40 @@
 			<53 104>, /* mdss_irq */
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
 			<2 216>, /* tsens_upper_lower_int */
+			<0xff 18>,  /* APC_qgicQTmrSecPhysIrptReq */
+			<0xff 19>,  /* APC_qgicQTmrNonSecPhysIrptReq */
+			<0xff 35>,  /* WDT_barkInt */
+			<0xff 40>,  /* qtmr_phy_irq[0] */
+			<0xff 47>,  /* rbif_irq[0] */
 			<0xff 56>,  /* q6_wdog_expired_irq */
 			<0xff 57>,  /* mss_to_apps_irq(0) */
 			<0xff 58>,  /* mss_to_apps_irq(1) */
 			<0xff 59>,  /* mss_to_apps_irq(2) */
 			<0xff 60>,  /* mss_to_apps_irq(3) */
 			<0xff 61>,  /* mss_a2_bam_irq */
+			<0xff 65>,  /* o_gc_sys_irq[0] */
+			<0xff 74>,  /* venus0_mmu_cirpt[1] */
+			<0xff 75>,  /* venus0_mmu_cirpt[0] */
+			<0xff 78>,  /* mdss_mmu_cirpt[0] */
+			<0xff 79>,  /* mdss_mmu_cirpt[1] */
+			<0xff 97>,  /* camss_vfe_mmu_cirpt[1] */
+			<0xff 102>, /* camss_jpeg_mmu_cirpt[1] */
+			<0xff 109>, /* ocmem_dm_nonsec_irq */
+			<0xff 131>, /* blsp1_qup_5_irq */
+			<0xff 141>, /* blsp1_uart_3_irq */
+			<0xff 155>, /* sdc1_irq(0) */
+			<0xff 157>, /* sdc2_irq(0) */
+			<0xff 161>, /* lpass_irq_out_spare[4] */
+			<0xff 162>, /* lpass_irq_out_spare[5]*/
+			<0xff 170>, /* sdc1_pwr_cmd_irq */
 			<0xff 173>, /* o_wcss_apss_smd_hi */
 			<0xff 174>, /* o_wcss_apss_smd_med */
 			<0xff 175>, /* o_wcss_apss_smd_low */
 			<0xff 176>, /* o_wcss_apss_smsm_irq */
 			<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
 			<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
-			<0xff 179>, /* o_wcss_apss_asic_intr
+			<0xff 179>, /* o_wcss_apss_asic_intr */
 			<0xff 181>, /* o_wcss_apss_wdog_bite_and_reset_rdy */
-			<0xff 161>, /* lpass_irq_out_spare[4] /
-			<0xff 162>, /* lpass_irq_out_spare[5]*/
-			<0xff 234>, /* lpass_irq_out_spare[6]*/
-			<0xff 235>, /* lpass_irq_out_spare[7]*/
 			<0xff 188>, /* lpass_irq_out_apcs(0) */
 			<0xff 189>, /* lpass_irq_out_apcs(1) */
 			<0xff 190>, /* lpass_irq_out_apcs(2) */
@@ -199,12 +216,16 @@
 			<0xff 205>, /* rpm_ipc(25) */
 			<0xff 206>, /* rpm_ipc(26) */
 			<0xff 207>, /* rpm_ipc(27) */
+			<0xff 234>, /* lpass_irq_out_spare[6]*/
+			<0xff 235>, /* lpass_irq_out_spare[7]*/
+			<0xff 240>, /* summary_irq_kpss */
+			<0xff 253>, /* sdc2_pwr_cmd_irq */
 			<0xff 258>, /* rpm_ipc(28) */
 			<0xff 259>, /* rpm_ipc(29) */
-			<0xff 275>, /* rpm_ipc(30) */
-			<0xff 276>, /* rpm_ipc(31) */
 			<0xff 269>, /* rpm_wdog_expired_irq */
-			<0xff 240>; /* summary_irq_kpss */
+			<0xff 270>, /* blsp1_bam_irq[0] */
+			<0xff 275>, /* rpm_ipc(30) */
+			<0xff 276>; /* rpm_ipc(31) */
 
 		qcom,gpio-parent = <&msmgpio>;
 		qcom,gpio-map = <3  1>,
@@ -287,4 +308,12 @@
 		reg = <0xfc000000 0x1a0000>;
 		qcom,start-offset = <0x190010>;
 	};
+
+	qcom,rpm-master-stats@fc428150 {
+		compatible = "qcom,rpm-master-stats";
+		reg = <0xfc428150 0x3200>;
+		qcom,masters = "APSS", "MPSS", "LPSS", "PRONTO";
+		qcom,master-stats-version = <2>;
+		qcom,master-offset = <2560>;
+	};
 };
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
index 3e0e4e4..e08cbc9 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
@@ -55,6 +55,52 @@
 		qcom,cdc-vdd-spkr-gpios;
 		qcom,cdc-us-euro-gpios;
 	};
+
+	tp_power: regulator-tp {
+		compatible = "regulator-fixed";
+		regulator-name = "tp_power";
+		regulator-min-microvolt = <2800000>;
+		regulator-max-microvolt = <2800000>;
+		gpio = <&msmgpio 15 0>;
+		startup-delay-us = <20000>;
+		enable-active-high;
+	};
+
+	i2c@f9927000 {
+		goodix@5d {
+			compatible = "goodix,gt9xx";
+			reg = <0x5d>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <17 0x2008>;
+			reset-gpios = <&msmgpio 16 0x00>;
+			interrupt-gpios = <&msmgpio 17 0x00>;
+			avdd-supply = <&tp_power>;
+			goodix,panel-coords = <0 0 720 1200>;
+			goodix,display-coords = <0 0 720 1080>;
+			goodix,button-map= <158 102 139>;
+			goodix,family-id = <0x0>;
+			goodix,cfg-data = [
+			41 D0 02 00 05 0A 35 01 01 0F
+			2D 08 55 32 03 04 00 00 00 00
+			00 00 05 0A 0C 0F 0A 8C 0E 0E
+			30 2E B8 08 00 00 00 83 03 1D
+			00 00 00 00 00 00 00 00 00 00
+			00 2D 62 94 C5 02 05 00 00 04
+			96 30 00 80 39 00 71 42 00 63
+			4D 00 56 5A 00 56 10 38 68 00
+			56 50 35 AA AA 27 00 00 00 00
+			00 01 1B 14 0C 14 00 00 01 00
+			00 00 00 00 00 00 00 00 00 00
+			00 00 02 04 06 08 0A 0C 0E 10
+			12 14 16 18 1A 1C FF FF FF FF
+			FF FF FF FF FF FF FF FF FF FF
+			FF FF 00 02 04 06 08 0A 0C 0F
+			10 12 13 14 16 18 1C 1D 1E 1F
+			20 21 22 24 26 28 29 2A FF FF
+			FF FF FF FF FF FF FF FF FF FF
+			FF FF FF FF 06 01];
+		};
+	};
 };
 
 &spmi_bus {
@@ -67,6 +113,12 @@
 			status = "disabled";
 		};
 	};
+
+	qcom,pm8226@1 {
+		qcom,leds@d800 {
+			status = "disabled";
+		};
+	};
 };
 
 &pm8226_mpps {
@@ -113,3 +165,18 @@
 		qcom,fast-avg-setup = <0>;
 	};
 };
+
+&qrd_batterydata {
+	qcom,rpull-up-kohm = <100>;
+	qcom,vref-batt-therm = <1800000>;
+
+	/include/ "batterydata-qrd-4v35-2500mah.dtsi"
+};
+
+&pm8226_bms {
+	qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8226_chg {
+	qcom,battery-data = <&qrd_batterydata>;
+};
diff --git a/arch/arm/boot/dts/msm8226-v1.dtsi b/arch/arm/boot/dts/msm8226-v1.dtsi
index 2833673..8d127e8 100644
--- a/arch/arm/boot/dts/msm8226-v1.dtsi
+++ b/arch/arm/boot/dts/msm8226-v1.dtsi
@@ -17,6 +17,7 @@
  */
 
 /include/ "msm8226.dtsi"
+/include/ "msm8226-v1-pm.dtsi"
 
 &tsens {
 	qcom,sensors = <4>;
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
similarity index 80%
rename from arch/arm/boot/dts/msm8226-pm.dtsi
rename to arch/arm/boot/dts/msm8226-v2-pm.dtsi
index ef0a55e..9ee47e2 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
@@ -24,7 +24,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
@@ -41,7 +41,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
@@ -58,7 +58,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
@@ -75,7 +75,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
@@ -96,9 +96,12 @@
 		qcom,phase-port = <0x1>;
 		qcom,pfm-port = <0x2>;
 		qcom,saw2-spm-cmd-ret = [00 03 00 0f];
+		qcom,saw2-spm-cmd-gdhs = [00 20 32 6b c0 e0 d0 42 07 50
+				4e 02 02 d0 e0 c0 22 6b 02 32 50 0f];
 		qcom,saw2-spm-cmd-pc = [00 32 b0 10 e0 d0 6b c0 42 f0
 				11 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
 				50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
+		qcom,L2-spm-is-apcs-master;
 	};
 
 	qcom,lpm-levels {
@@ -130,7 +133,7 @@
 		qcom,lpm-level@2 {
 			reg = <0x2>;
 			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_retention";
+			qcom,l2 = "l2_cache_gdhs";
 			qcom,latency-us = <20000>;
 			qcom,ss-power = <138>;
 			qcom,energy-overhead = <1208400>;
@@ -167,28 +170,46 @@
 			<53 104>, /* mdss_irq */
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
 			<2 216>, /* tsens_upper_lower_int */
+			<0xff 18>,  /* APC_qgicQTmrSecPhysIrptReq */
+			<0xff 19>,  /* APC_qgicQTmrNonSecPhysIrptReq */
+			<0xff 35>,  /* WDT_barkInt */
+			<0xff 40>,  /* qtmr_phy_irq[0] */
+			<0xff 47>,  /* rbif_irq[0] */
 			<0xff 56>,  /* q6_wdog_expired_irq */
 			<0xff 57>,  /* mss_to_apps_irq(0) */
 			<0xff 58>,  /* mss_to_apps_irq(1) */
 			<0xff 59>,  /* mss_to_apps_irq(2) */
 			<0xff 60>,  /* mss_to_apps_irq(3) */
 			<0xff 61>,  /* mss_a2_bam_irq */
+			<0xff 65>,  /* o_gc_sys_irq[0] */
+			<0xff 74>,  /* venus0_mmu_cirpt[1] */
+			<0xff 75>,  /* venus0_mmu_cirpt[0] */
+			<0xff 78>,  /* mdss_mmu_cirpt[0] */
+			<0xff 79>,  /* mdss_mmu_cirpt[1] */
+			<0xff 97>,  /* camss_vfe_mmu_cirpt[1] */
+			<0xff 102>, /* camss_jpeg_mmu_cirpt[1] */
+			<0xff 109>, /* ocmem_dm_nonsec_irq */
+			<0xff 131>, /* blsp1_qup_5_irq */
+			<0xff 141>, /* blsp1_uart_3_irq */
+			<0xff 155>, /* sdc1_irq(0) */
+			<0xff 157>, /* sdc2_irq(0) */
+			<0xff 161>, /* lpass_irq_out_spare[4] */
+			<0xff 162>, /* lpass_irq_out_spare[5]*/
+			<0xff 170>, /* sdc1_pwr_cmd_irq */
 			<0xff 173>, /* o_wcss_apss_smd_hi */
 			<0xff 174>, /* o_wcss_apss_smd_med */
 			<0xff 175>, /* o_wcss_apss_smd_low */
 			<0xff 176>, /* o_wcss_apss_smsm_irq */
 			<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
 			<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
-			<0xff 179>, /* o_wcss_apss_asic_intr
+			<0xff 179>, /* o_wcss_apss_asic_intr */
 			<0xff 181>, /* o_wcss_apss_wdog_bite_and_reset_rdy */
 			<0xff 188>, /* lpass_irq_out_apcs(0) */
 			<0xff 189>, /* lpass_irq_out_apcs(1) */
 			<0xff 190>, /* lpass_irq_out_apcs(2) */
 			<0xff 191>, /* lpass_irq_out_apcs(3) */
 			<0xff 192>, /* lpass_irq_out_apcs(4) */
-			<0xff 194>, /* lpass_irq_out_apcs[6] */
-			<0xff 195>, /* lpass_irq_out_apcs[7] */
-			<0xff 196>, /* lpass_irq_out_apcs[8] */
+			<0xff 194>, /* lpass_irq_out_apcs(6) */
 			<0xff 200>, /* rpm_ipc(4) */
 			<0xff 201>, /* rpm_ipc(5) */
 			<0xff 202>, /* rpm_ipc(6) */
@@ -197,12 +218,16 @@
 			<0xff 205>, /* rpm_ipc(25) */
 			<0xff 206>, /* rpm_ipc(26) */
 			<0xff 207>, /* rpm_ipc(27) */
+			<0xff 234>, /* lpass_irq_out_spare[6]*/
+			<0xff 235>, /* lpass_irq_out_spare[7]*/
+			<0xff 240>, /* summary_irq_kpss */
+			<0xff 253>, /* sdc2_pwr_cmd_irq */
 			<0xff 258>, /* rpm_ipc(28) */
 			<0xff 259>, /* rpm_ipc(29) */
-			<0xff 275>, /* rpm_ipc(30) */
-			<0xff 276>, /* rpm_ipc(31) */
 			<0xff 269>, /* rpm_wdog_expired_irq */
-			<0xff 240>; /* summary_irq_kpss */
+			<0xff 270>, /* blsp1_bam_irq[0] */
+			<0xff 275>, /* rpm_ipc(30) */
+			<0xff 276>; /* rpm_ipc(31) */
 
 		qcom,gpio-parent = <&msmgpio>;
 		qcom,gpio-map = <3  1>,
@@ -285,4 +310,12 @@
 		reg = <0xfc000000 0x1a0000>;
 		qcom,start-offset = <0x190010>;
 	};
+
+	qcom,rpm-master-stats@fc428150 {
+		compatible = "qcom,rpm-master-stats";
+		reg = <0xfc428150 0x3200>;
+		qcom,masters = "APSS", "MPSS", "LPSS", "PRONTO";
+		qcom,master-stats-version = <2>;
+		qcom,master-offset = <2560>;
+	};
 };
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts b/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
index 0a3148b..7aadd71 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
@@ -31,3 +31,11 @@
 		qcom,cont-splash-enabled;
         };
 };
+
+&pm8226_bms {
+        qcom,use-external-rsense;
+};
+
+&pm8226_iadc {
+	qcom,rsense = <10000000>;
+};
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
index 0a4657d..da38a88 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
@@ -56,6 +56,52 @@
 		qcom,cdc-vdd-spkr-gpios;
 		qcom,cdc-us-euro-gpios;
 	};
+
+	tp_power: regulator-tp {
+		compatible = "regulator-fixed";
+		regulator-name = "tp_power";
+		regulator-min-microvolt = <2800000>;
+		regulator-max-microvolt = <2800000>;
+		gpio = <&msmgpio 15 0>;
+		startup-delay-us = <20000>;
+		enable-active-high;
+	};
+
+	i2c@f9927000 {
+		goodix@5d {
+			compatible = "goodix,gt9xx";
+			reg = <0x5d>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <17 0x2008>;
+			reset-gpios = <&msmgpio 16 0x00>;
+			interrupt-gpios = <&msmgpio 17 0x00>;
+			avdd-supply = <&tp_power>;
+			goodix,panel-coords = <0 0 720 1200>;
+			goodix,display-coords = <0 0 720 1080>;
+			goodix,button-map= <158 102 139>;
+			goodix,family-id = <0x0>;
+			goodix,cfg-data = [
+			41 D0 02 00 05 0A 35 01 01 0F
+			2D 08 55 32 03 04 00 00 00 00
+			00 00 05 0A 0C 0F 0A 8C 0E 0E
+			30 2E B8 08 00 00 00 83 03 1D
+			00 00 00 00 00 00 00 00 00 00
+			00 2D 62 94 C5 02 05 00 00 04
+			96 30 00 80 39 00 71 42 00 63
+			4D 00 56 5A 00 56 10 38 68 00
+			56 50 35 AA AA 27 00 00 00 00
+			00 01 1B 14 0C 14 00 00 01 00
+			00 00 00 00 00 00 00 00 00 00
+			00 00 02 04 06 08 0A 0C 0E 10
+			12 14 16 18 1A 1C FF FF FF FF
+			FF FF FF FF FF FF FF FF FF FF
+			FF FF 00 02 04 06 08 0A 0C 0F
+			10 12 13 14 16 18 1C 1D 1E 1F
+			20 21 22 24 26 28 29 2A FF FF
+			FF FF FF FF FF FF FF FF FF FF
+			FF FF FF FF 06 01];
+		};
+	};
 };
 
 &spmi_bus {
@@ -68,6 +114,12 @@
 			status = "disabled";
 		};
 	};
+
+	qcom,pm8226@1 {
+		qcom,leds@d800 {
+			status = "disabled";
+		};
+	};
 };
 
 &pm8226_mpps {
@@ -114,3 +166,23 @@
 		qcom,fast-avg-setup = <0>;
 	};
 };
+
+&qrd_batterydata {
+	qcom,rpull-up-kohm = <100>;
+	qcom,vref-batt-therm = <1800000>;
+
+	/include/ "batterydata-qrd-4v35-2500mah.dtsi"
+};
+
+&pm8226_bms {
+	qcom,use-external-rsense;
+	qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8226_chg {
+	qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8226_iadc {
+	qcom,rsense = <10000000>;
+};
diff --git a/arch/arm/boot/dts/msm8226-v2.dtsi b/arch/arm/boot/dts/msm8226-v2.dtsi
index 2b3b7c2..9681d2a 100644
--- a/arch/arm/boot/dts/msm8226-v2.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2.dtsi
@@ -17,6 +17,7 @@
  */
 
 /include/ "msm8226.dtsi"
+/include/ "msm8226-v2-pm.dtsi"
 
 &pm8226_l3 {
 	regulator-min-microvolt = <750000>;
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 4b78238..0ae0fc6 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -51,7 +51,6 @@
 /include/ "msm8226-camera.dtsi"
 /include/ "msm-gdsc.dtsi"
 /include/ "msm8226-iommu.dtsi"
-/include/ "msm8226-pm.dtsi"
 /include/ "msm8226-smp2p.dtsi"
 /include/ "msm8226-gpu.dtsi"
 /include/ "msm8226-bus.dtsi"
@@ -332,20 +331,21 @@
 			qcom,cdc-vdd-px-voltage = <1800000 1800000>;
 			qcom,cdc-vdd-px-current = <25000>;
 
-			cdc-vdd-a-1p2v-supply = <&pm8226_l4>;
-			qcom,cdc-vdd-a-1p2v-voltage = <1200000 1200000>;
-			qcom,cdc-vdd-a-1p2v-current = <10000>;
-
 			cdc-vdd-cx-supply = <&pm8226_l4>;
 			qcom,cdc-vdd-cx-voltage = <1200000 1200000>;
-			qcom,cdc-vdd-cx-current = <10000>;
+			qcom,cdc-vdd-cx-current = <2000>;
 
-			qcom,cdc-static-supplies = "cdc-vdd-buck",
-						   "cdc-vdd-h",
+			cdc-vdd-buckhelper-supply = <&pm8226_l25>;
+			qcom,cdc-vdd-buckhelper-voltage = <1775000 2125000>;
+			qcom,cdc-vdd-buckhelper-current = <10000>;
+
+			qcom,cdc-static-supplies = "cdc-vdd-h",
 						   "cdc-vdd-px",
-						   "cdc-vdd-a-1p2v",
 						   "cdc-vdd-cx";
 
+			qcom,cdc-cp-supplies = "cdc-vdd-buck",
+						"cdc-vdd-buckhelper";
+
 			qcom,cdc-micbias-ldoh-v = <0x3>;
 			qcom,cdc-micbias-cfilt1-mv = <1800>;
 			qcom,cdc-micbias-cfilt2-mv = <2700>;
@@ -377,6 +377,18 @@
 		qcom,prim-auxpcm-gpio-set = "prim-gpio-prim";
 	};
 
+	sound-9302 {
+		compatible = "qcom,msm8226-audio-tapan";
+		qcom,model = "msm8226-tapan9302-snd-card";
+		qcom,tapan-mclk-clk-freq = <9600000>;
+		qcom,prim-auxpcm-gpio-clk  = <&msmgpio 63 0>;
+		qcom,prim-auxpcm-gpio-sync = <&msmgpio 64 0>;
+		qcom,prim-auxpcm-gpio-din  = <&msmgpio 65 0>;
+		qcom,prim-auxpcm-gpio-dout = <&msmgpio 66 0>;
+		qcom,prim-auxpcm-gpio-set = "prim-gpio-prim";
+		qcom,tapan-codec-9302;
+	};
+
 	qcom,msm-pcm {
 		compatible = "qcom,msm-pcm-dsp";
 		qcom,msm-pcm-dsp-id = <0>;
@@ -912,6 +924,8 @@
 		interrupts = <0 99 0>;
 		qcom,i2c-bus-freq = <384000>;
 		qcom,i2c-src-freq = <19200000>;
+		qcom,sda-gpio = <&msmgpio 18 0>;
+		qcom,scl-gpio = <&msmgpio 19 0>;
 	};
 
 	qcom,acpuclk@f9011050 {
@@ -1028,9 +1042,11 @@
 		qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
 	};
 
-	qcom,msm-mem-hole {
+	memory_hole: qcom,msm-mem-hole {
 		compatible = "qcom,msm-mem-hole";
-		qcom,memblock-remove = <0x6400000 0x9b00000>; /* Address and Size of Hole */
+		qcom,memblock-remove = <0x08400000 0x4000000
+					0x0d200000 0x2300000
+					0x0fa00000 0x500000>; /* Address and Size of Hole */
 	};
 
 	tsens: tsens@fc4a8000 {
diff --git a/arch/arm/boot/dts/msm8610-bus.dtsi b/arch/arm/boot/dts/msm8610-bus.dtsi
index cef04ef..6b72e66 100644
--- a/arch/arm/boot/dts/msm8610-bus.dtsi
+++ b/arch/arm/boot/dts/msm8610-bus.dtsi
@@ -952,6 +952,7 @@
 			cell-id = <2048>;
 			label = "fab_mmss_noc";
 			qcom,masterp = <1>;
+			qcom,gateway;
 			qcom,qport = <1>;
 			qcom,buswidth = <8>;
 			qcom,ws = <10000>;
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dtsi
similarity index 94%
rename from arch/arm/boot/dts/msm8610-cdp.dts
rename to arch/arm/boot/dts/msm8610-cdp.dtsi
index f3470c2..8403dfd 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dtsi
@@ -10,19 +10,6 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
-
-/include/ "msm8610.dtsi"
-/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
-/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
-
-/ {
-	model = "Qualcomm MSM 8610 CDP";
-	compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
-	qcom,msm-id = <147 1 0>, <165 1 0>, <161 1 0>, <162 1 0>,
-		      <163 1 0>, <164 1 0>, <166 1 0>;
-};
-
 &soc {
 	serial@f991e000 {
 		status = "ok";
@@ -52,7 +39,7 @@
 				/* Object 6, Instance = 0 */
 				00 00 00 00 00 00
 				/* Object 38, Instance = 0 */
-				1D 02 00 0A 06 0D 00 00
+				1D 03 00 1E 07 0D 00 00
 				/* Object 7, Instance = 0 */
 				20 08 32
 				/* Object 8, Instance = 0 */
@@ -60,7 +47,7 @@
 				/* Object 9, Instance = 0 */
 				83 00 00 13 0B 00 20 32 01 03
 				00 32 05 30 0A 05 0A 00 70 03
-				FC 01 00 36 2F D8 00 00 40 00
+				FC 01 04 2F F8 DC 00 00 40 00
 				00 0A 00 00 02
 				/* Object 18, Instance = 0 */
 				00 00
@@ -143,12 +130,21 @@
             "AMIC1", "MIC BIAS External",
             "AMIC2", "MIC BIAS Internal2";
     };
+
+	qcom,dsi_v2_truly_wvga_video {
+		qcom,cont-splash-enabled;
+	};
 };
 
 &i2c_cdc  {
 	msm8x10_wcd_codec@0d{
 		compatible = "qcom,msm8x10-wcd-i2c";
 		reg = <0x0d>;
+
+		interrupt-parent = <&wcd9xxx_intc>;
+		interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+			      17 18 19 20 21 22 23>;
+
 		cdc-vdda-cp-supply = <&pm8110_s4>;
 		qcom,cdc-vdda-cp-voltage = <1800000 2150000>;
 		qcom,cdc-vdda-cp-current = <650000>;
@@ -226,10 +222,9 @@
 				qcom,source-sel = <8>;
 				qcom,mode-ctrl = <0x10>;
 				qcom,pwm-channel = <0>;
-				qcom,pwm-us = <14>;
+				qcom,pwm-us = <27>;
 				qcom,vin-ctrl = <0x03>;
 				qcom,mode = "pwm";
-				qcom,min-brightness = <19>;
 			};
 		};
 	};
@@ -247,8 +242,6 @@
 
 &sdhc_1 {
 	vdd-supply = <&pm8110_l17>;
-	qcom,vdd-always-on;
-	qcom,vdd-lpm-sup;
 	qcom,vdd-voltage-level = <2900000 2900000>;
 	qcom,vdd-current-level = <200 400000>;
 
diff --git a/arch/arm/boot/dts/msm8610-coresight.dtsi b/arch/arm/boot/dts/msm8610-coresight.dtsi
index 2041bf6..98a99a7 100644
--- a/arch/arm/boot/dts/msm8610-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8610-coresight.dtsi
@@ -16,6 +16,8 @@
 		reg = <0xfc326000 0x1000>,
 		      <0xfc37c000 0x3000>;
 		reg-names = "tmc-base", "bam-base";
+		interrupts = <0 166 0>;
+		interrupt-names = "byte-cntr-irq";
 
 		qcom,memory-reservation-type = "EBI1";
 		qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dtsi
similarity index 90%
rename from arch/arm/boot/dts/msm8610-mtp.dts
rename to arch/arm/boot/dts/msm8610-mtp.dtsi
index 0d4c174..8ed6ae2 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dtsi
@@ -10,19 +10,6 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
-
-/include/ "msm8610.dtsi"
-/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
-/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
-
-/ {
-	model = "Qualcomm MSM 8610 MTP";
-	compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
-	qcom,msm-id = <147 8 0>, <165 8 0>, <161 8 0>, <162 8 0>,
-		      <163 8 0>, <164 8 0>, <166 8 0>;
-};
-
 &soc {
 	serial@f991e000 {
 		status = "ok";
@@ -52,7 +39,7 @@
 				/* Object 6, Instance = 0 */
 				00 00 00 00 00 00
 				/* Object 38, Instance = 0 */
-				1D 02 00 0A 06 0D 00 00
+				1D 03 00 1E 07 0D 00 00
 				/* Object 7, Instance = 0 */
 				20 08 32
 				/* Object 8, Instance = 0 */
@@ -60,7 +47,7 @@
 				/* Object 9, Instance = 0 */
 				83 00 00 13 0B 00 20 32 01 03
 				00 32 05 30 0A 05 0A 00 70 03
-				FC 01 00 36 2F D8 00 00 40 00
+				FC 01 04 2F F8 DC 00 00 40 00
 				00 0A 00 00 02
 				/* Object 18, Instance = 0 */
 				00 00
@@ -127,6 +114,23 @@
 			fsl,irq-gpio = <&msmgpio 81 0x00>;
 			fsl,sensors-position = <5>;
 		};
+		capella@60 {
+			compatible = "capella,cm36283";
+			reg = <0x60>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <80 0x2>;
+			vdd-supply = <&pm8110_l19>;
+			vio-supply = <&pm8110_l14>;
+			capella,use-polling;
+			capella,interrupt-gpio = <&msmgpio 80 0x2>;
+			capella,levels = <0x0A 0xA0 0xE1 0x140 0x280 0x500 0xA28 0x16A8 0x1F40
+				0x2800>;
+			capella,ps_close_thd_set = <0xa>;
+			capella,ps_away_thd_set = <0x5>;
+			capella,ls_cmd = <0x44>; /* PS_IT=160ms, INT_PERS=2*/
+			capella,ps_conf1_val = <0x0006>;
+			capella,ps_conf3_val = <0x3010>;
+		};
 	};
 
 	gen-vkeys {
@@ -181,12 +185,21 @@
             "AMIC1", "MIC BIAS External",
             "AMIC2", "MIC BIAS Internal2";
     };
+
+	qcom,dsi_v2_truly_wvga_video {
+		qcom,cont-splash-enabled;
+	};
 };
 
 &i2c_cdc  {
 	msm8x10_wcd_codec@0d{
 		compatible = "qcom,msm8x10-wcd-i2c";
 		reg = <0x0d>;
+
+		interrupt-parent = <&wcd9xxx_intc>;
+		interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+			      17 18 19 20 21 22 23>;
+
 		cdc-vdda-cp-supply = <&pm8110_s4>;
 		qcom,cdc-vdda-cp-voltage = <1800000 2150000>;
 		qcom,cdc-vdda-cp-current = <650000>;
@@ -264,10 +277,9 @@
 				qcom,source-sel = <8>;
 				qcom,mode-ctrl = <0x10>;
 				qcom,pwm-channel = <0>;
-				qcom,pwm-us = <14>;
+				qcom,pwm-us = <27>;
 				qcom,vin-ctrl = <0x03>;
 				qcom,mode = "pwm";
-				qcom,min-brightness = <19>;
 			};
 		};
 	};
@@ -285,8 +297,6 @@
 
 &sdhc_1 {
 	vdd-supply = <&pm8110_l17>;
-	qcom,vdd-always-on;
-	qcom,vdd-lpm-sup;
 	qcom,vdd-voltage-level = <2900000 2900000>;
 	qcom,vdd-current-level = <200 400000>;
 
diff --git a/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi b/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi
index e73573a..bdcb285 100644
--- a/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi
@@ -18,7 +18,7 @@
                 qcom,slave-id = <0x40 0x04 0xc0>;
                 qcom,csiphy-sd-index = <0>;
                 qcom,csid-sd-index = <0>;
-                qcom,mount-angle = <270>;
+                qcom,mount-angle = <90>;
                 qcom,sensor-name = "hi256";
                 cam_vdig-supply = <&pm8110_l2>;
                 cam_vana-supply = <&pm8110_l19>;
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuaa.dts b/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
similarity index 71%
rename from arch/arm/boot/dts/msm8610-qrd-skuaa.dts
rename to arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
index aeaf8ca..b1b47d8 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuaa.dts
+++ b/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
@@ -10,19 +10,7 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
-
 /include/ "msm8610-qrd.dtsi"
-/include/ "dsi-v2-panel-hx8379a-wvga-video.dtsi"
-/include/ "msm8610-qrd-camera-sensor.dtsi"
-
-/ {
-	model = "Qualcomm MSM 8610 QRD";
-	compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
-	qcom,board-id = <11 1>, <11 0>;
-	qcom,msm-id = <147 0>, <165 0>, <161 0>, <162 0>,
-				  <163 0>, <164 0>, <166 0>;
-};
 
 &soc {
     sound {
@@ -39,9 +27,33 @@
 
         qcom,ext-spk-amp-gpio = <&msmgpio 92 0x0>;
     };
+
+	qcom,dsi_v2_hx8379a_wvga_video {
+		qcom,cont-splash-enabled;
+	};
+};
+
+/ {
+	qrd_batterydata: qcom,battery-data {
+		qcom,rpull-up-kohm = <100>;
+		qcom,vref-batt-therm = <1800000>;
+
+		/include/ "batterydata-qrd-4v2-1300mah.dtsi"
+	};
 };
 
 &pm8110_bms {
 	status = "ok";
-	qcom,batt-type = <5>;
+	qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8110_chg {
+	qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8110_vadc {
+	chan@30 {
+		label = "batt_therm";
+		qcom,scale-function = <7>;
+	};
 };
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuab.dts b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
similarity index 69%
rename from arch/arm/boot/dts/msm8610-qrd-skuab.dts
rename to arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
index 947a312..649bc71 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuab.dts
+++ b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
@@ -10,19 +10,7 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
-
 /include/ "msm8610-qrd.dtsi"
-/include/ "dsi-v2-panel-otm8018b-fwvga-video.dtsi"
-/include/ "msm8612-qrd-camera-sensor.dtsi"
-
-/ {
-	model = "Qualcomm MSM 8610 QRD";
-	compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
-	qcom,board-id = <11 3>;
-	qcom,msm-id = <147 0>, <165 0>, <161 0>, <162 0>,
-				  <163 0>, <164 0>, <166 0>;
-};
 
 &soc {
     sound {
@@ -78,9 +66,49 @@
 			fsl,irq-gpio = <&msmgpio 81 0x00>;
 			fsl,sensors-position = <1>;
 		};
+		stk@48 {
+			compatible = "stk,stk3x1x";
+			reg = <0x48>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <80 0x2>;
+			vdd-supply = <&pm8110_l19>;
+			vio-supply = <&pm8110_l14>;
+			stk,irq-gpio = <&msmgpio 80 0x02>;
+			stk,transmittance = <340>;
+			stk,state-reg = <0x00>;
+			stk,psctrl-reg = <0x71>;
+			stk,alsctrl-reg = <0x38>;
+			stk,ledctrl-reg = <0xFF>;
+			stk,wait-reg = <0x07>;
+			stk,ps-thdh = <150>;
+			stk,ps-thdl = <100>;
+		};
+	};
+
+	usb@f9a55000 {
+               qcom,hsusb-otg-phy-init-seq =
+                       <0x44 0x80 0x6a 0x81 0x34 0x82 0x23 0x83 0xffffffff>;
 	};
 
 	qcom,dsi_v2_otm8018b_fwvga_video {
-		status = "ok";
+		qcom,cont-splash-enabled;
 	};
 };
+
+/ {
+	qrd_batterydata: qcom,battery-data {
+		qcom,rpull-up-kohm = <100>;
+		qcom,vref-batt-therm = <1800000>;
+
+		/include/ "batterydata-qrd-4v2-1800mah.dtsi"
+	};
+};
+
+&pm8110_bms {
+	status = "ok";
+	qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8110_chg {
+	qcom,battery-data = <&qrd_batterydata>;
+};
diff --git a/arch/arm/boot/dts/msm8610-qrd.dtsi b/arch/arm/boot/dts/msm8610-qrd.dtsi
index bd1705f..1688890 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd.dtsi
@@ -26,8 +26,6 @@
  * };
  */
 
-/include/ "msm8610.dtsi"
-
 &soc {
 	i2c@f9923000{
 		focaltech@38{
@@ -37,6 +35,7 @@
 			interrupts = <1 0x2>;
 			vdd-supply = <&pm8110_l19>;
 			vcc_i2c-supply = <&pm8110_l14>;
+			focaltech,name = "ft6x06";
 			focaltech,family-id = <0x06>;
 			focaltech,reset-gpio = <&msmgpio 0 0x00>;
 			focaltech,irq-gpio = <&msmgpio 1 0x00>;
@@ -45,6 +44,17 @@
 			focaltech,button-map= <139 102 158>;
 			focaltech,no-force-update;
 			focaltech,i2c-pull-up;
+			focaltech,group-id = <1>;
+			focaltech,hard-reset-delay-ms = <20>;
+			focaltech,soft-reset-delay-ms = <150>;
+			focaltech,num-max-touches = <2>;
+			focaltech,fw-name = "ft_8610_qrd_fw.bin";
+			focaltech,fw-delay-aa-ms = <100>;
+			focaltech,fw-delay-55-ms = <30>;
+			focaltech,fw-upgrade-id1 = <0x79>;
+			focaltech,fw-upgrade-id2 = <0x08>;
+			focaltech,fw-delay-readid-ms = <10>;
+			focaltech,fw-delay-era-flsh-ms = <2000>;
 		};
 	};
 
@@ -139,6 +149,11 @@
 	msm8x10_wcd_codec@0d{
 		compatible = "qcom,msm8x10-wcd-i2c";
 		reg = <0x0d>;
+
+		interrupt-parent = <&wcd9xxx_intc>;
+		interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+			     17 18 19 20 21 22 23>;
+
 		cdc-vdda-cp-supply = <&pm8110_s4>;
 		qcom,cdc-vdda-cp-voltage = <1800000 2150000>;
 		qcom,cdc-vdda-cp-current = <650000>;
@@ -216,10 +231,9 @@
 				qcom,source-sel = <8>;
 				qcom,mode-ctrl = <0x10>;
 				qcom,pwm-channel = <0>;
-				qcom,pwm-us = <14>;
+				qcom,pwm-us = <27>;
 				qcom,vin-ctrl = <0x03>;
 				qcom,mode = "pwm";
-				qcom,min-brightness = <19>;
 			};
 		};
 	};
@@ -237,8 +251,6 @@
 
 &sdhc_1 {
 	vdd-supply = <&pm8110_l17>;
-	qcom,vdd-always-on;
-	qcom,vdd-lpm-sup;
 	qcom,vdd-voltage-level = <2900000 2900000>;
 	qcom,vdd-current-level = <200 400000>;
 
@@ -344,3 +356,14 @@
 	mpp@a300 { /* MPP 4 */
 	};
 };
+
+&pm8110_vadc {
+	chan@30 {
+		label = "batt_therm";
+		qcom,scale-function = <6>;
+	};
+};
+
+&android_usb {
+	qcom,android-usb-cdrom;
+};
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 34cbd99..b74d487 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -79,6 +79,7 @@
 		qcom,cpr-fuse-redun-ro-sel = <44 26 29>;
 
 		qcom,cpr-enable;
+		qcom,use-tz-api;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8610-sim.dts b/arch/arm/boot/dts/msm8610-sim.dts
index 7c57fe6..33176b9 100644
--- a/arch/arm/boot/dts/msm8610-sim.dts
+++ b/arch/arm/boot/dts/msm8610-sim.dts
@@ -30,6 +30,11 @@
 	msm8x10_wcd_codec@0d{
 		compatible = "qcom,msm8x10-wcd-i2c";
 		reg = <0x0d>;
+
+		interrupt-parent = <&wcd9xxx_intc>;
+		interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+			      17 18 19 20 21 22 23>;
+
 		cdc-vdda-cp-supply = <&pm8110_s4>;
 		qcom,cdc-vdda-cp-voltage = <2150000 2150000>;
 		qcom,cdc-vdda-cp-current = <650000>;
diff --git a/arch/arm/boot/dts/msm8610-v1-cdp.dts b/arch/arm/boot/dts/msm8610-v1-cdp.dts
new file mode 100644
index 0000000..ba0851f
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v1-cdp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "msm8610-v1.dtsi"
+/include/ "msm8610-cdp.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8610 CDP";
+	compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
+	qcom,msm-id = <147 1 0>, <165 1 0>, <161 1 0>, <162 1 0>,
+		      <163 1 0>, <164 1 0>, <166 1 0>;
+};
+
+
diff --git a/arch/arm/boot/dts/msm8610-v1-mtp.dts b/arch/arm/boot/dts/msm8610-v1-mtp.dts
new file mode 100644
index 0000000..010903f
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v1-mtp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "msm8610-v1.dtsi"
+/include/ "msm8610-mtp.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8610 MTP";
+	compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
+	qcom,msm-id = <147 8 0>, <165 8 0>, <161 8 0>, <162 8 0>,
+		      <163 8 0>, <164 8 0>, <166 8 0>;
+};
+
+
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
similarity index 89%
copy from arch/arm/boot/dts/msm8610-pm.dtsi
copy to arch/arm/boot/dts/msm8610-v1-pm.dtsi
index d31a65c..bd0aa0f 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
@@ -99,6 +99,7 @@
 		qcom,saw2-spm-cmd-pc = [00 32 b0 10 e0 d0 6b c0 42 f0
 				11 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
 				50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
+		qcom,L2-spm-is-apcs-master;
 	};
 
 	qcom,lpm-levels {
@@ -179,9 +180,9 @@
 			<0xff 176>, /* o_wcss_apss_smsm_irq */
 			<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
 			<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
-			<0xff 179>, /* o_wcss_apss_asic_intr
+			<0xff 179>, /* o_wcss_apss_asic_intr */
 			<0xff 181>, /* o_wcss_apss_wdog_bite_and_reset_rdy */
-			<0xff 161>, /* lpass_irq_out_spare[4] /
+			<0xff 161>, /* lpass_irq_out_spare[4] */
 			<0xff 162>, /* lpass_irq_out_spare[5]*/
 			<0xff 234>, /* lpass_irq_out_spare[6]*/
 			<0xff 235>, /* lpass_irq_out_spare[7]*/
@@ -208,45 +209,43 @@
 
 		qcom,gpio-parent = <&msmgpio>;
 		qcom,gpio-map = <3  1>,
-			<4  4 >,
-			<5  5 >,
-			<6  9 >,
-			<7  13>,
-			<8  17>,
-			<9  21>,
-			<10  27>,
-			<11  29>,
-			<12  31>,
-			<13  33>,
-			<14  35>,
-			<15  37>,
-			<16  38>,
-			<17  39>,
-			<18  41>,
-			<19  46>,
-			<20  48>,
-			<21  49>,
-			<22  50>,
-			<23  51>,
-			<24  52>,
-			<25  54>,
-			<26  62>,
-			<27  63>,
-			<28  64>,
-			<29  65>,
-			<30  66>,
-			<31  67>,
-			<32  68>,
-			<33  69>,
-			<34  71>,
-			<35  72>,
-			<36  106>,
-			<37  107>,
-			<38  108>,
-			<39  109>,
-			<40  110>,
-			<54  111>,
-			<55  113>;
+			<4  5 >,
+			<5  9 >,
+			<6  14>,
+			<7  15>,
+			<8  32>,
+			<9  33>,
+			<10  34>,
+			<11  35>,
+			<12  41>,
+			<13  42>,
+			<14  72>,
+			<15  73>,
+			<16  74>,
+			<17  75>,
+			<18  76>,
+			<19  77>,
+			<20  78>,
+			<21  79>,
+			<22  80>,
+			<23  81>,
+			<24  82>,
+			<25  83>,
+			<26  84>,
+			<27  85>,
+			<28  87>,
+			<29  90>,
+			<30  91>,
+			<31  92>,
+			<32  93>,
+			<33  94>,
+			<34  95>,
+			<35  96>,
+			<36  97>,
+			<37  98>,
+			<38  99>,
+			<39  100>,
+			<40  101>;
 	};
 
 	qcom,pm-8x60@fe805664 {
@@ -287,4 +286,12 @@
 		reg = <0xfc000000 0x1a0000>;
 		qcom,start-offset = <0x190010>;
 	};
+
+	qcom,rpm-master-stats@fc428150 {
+		compatible = "qcom,rpm-master-stats";
+		reg = <0xfc428150 0x3200>;
+		qcom,masters = "APSS", "MPSS", "LPSS", "PRONTO";
+		qcom,master-stats-version = <2>;
+		qcom,master-offset = <2560>;
+	};
 };
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/boot/dts/msm8610-v1-qrd-skuaa.dts
similarity index 62%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/boot/dts/msm8610-v1-qrd-skuaa.dts
index 607ba8c..ba53acc 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/boot/dts/msm8610-v1-qrd-skuaa.dts
@@ -8,11 +8,17 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
  */
 
-#include "adreno.h"
+/dts-v1/;
 
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+/include/ "msm8610-v1.dtsi"
+/include/ "msm8610-qrd-skuaa.dtsi"
+/include/ "dsi-v2-panel-hx8379a-wvga-video.dtsi"
+/include/ "msm8610-qrd-camera-sensor.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8610v1 QRD SKUAA";
+	compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
+	qcom,board-id = <11 1>, <11 0>;
+};
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/boot/dts/msm8610-v1-qrd-skuab.dts
similarity index 62%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/boot/dts/msm8610-v1-qrd-skuab.dts
index 607ba8c..5e19997 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/boot/dts/msm8610-v1-qrd-skuab.dts
@@ -8,11 +8,17 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
  */
 
-#include "adreno.h"
+/dts-v1/;
 
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+/include/ "msm8610-v1.dtsi"
+/include/ "msm8610-qrd-skuab.dtsi"
+/include/ "dsi-v2-panel-otm8018b-fwvga-video.dtsi"
+/include/ "msm8612-qrd-camera-sensor.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8610v1 QRD SKUAB";
+	compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
+	qcom,board-id = <11 3>;
+};
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/boot/dts/msm8610-v1.dtsi
similarity index 60%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/boot/dts/msm8610-v1.dtsi
index 607ba8c..9d8c411 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/boot/dts/msm8610-v1.dtsi
@@ -8,11 +8,18 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
  */
 
-#include "adreno.h"
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8610.dtsi file.
+ */
 
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+/include/ "msm8610.dtsi"
+/include/ "msm8610-v1-pm.dtsi"
+
+/ {
+	qcom,msm-id = <147 0>, <165 0>, <161 0>, <162 0>,
+			<163 0>, <164 0>, <166 0>;
+};
diff --git a/arch/arm/boot/dts/msm8610-v2-cdp.dts b/arch/arm/boot/dts/msm8610-v2-cdp.dts
new file mode 100644
index 0000000..51ef7a2
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v2-cdp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "msm8610-v2.dtsi"
+/include/ "msm8610-cdp.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8610v2 CDP";
+	compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
+	qcom,msm-id = <147 1 0x10001>, <165 1 0x10001>, <161 1 0x10001>, <162 1 0x10001>,
+		      <163 1 0x10001>, <164 1 0x10001>, <166 1 0x10001>;
+};
+
+
diff --git a/arch/arm/boot/dts/msm8610-v2-mtp.dts b/arch/arm/boot/dts/msm8610-v2-mtp.dts
new file mode 100644
index 0000000..e1c9bb8
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v2-mtp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "msm8610-v2.dtsi"
+/include/ "msm8610-mtp.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8610v2 MTP";
+	compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
+	qcom,msm-id = <147 8 0x10001>, <165 8 0x10001>, <161 8 0x10001>, <162 8 0x10001>,
+		      <163 8 0x10001>, <164 8 0x10001>, <166 8 0x10001>;
+};
+
+
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
similarity index 94%
rename from arch/arm/boot/dts/msm8610-pm.dtsi
rename to arch/arm/boot/dts/msm8610-v2-pm.dtsi
index d31a65c..dba3da4 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
@@ -24,7 +24,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
@@ -41,7 +41,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 		};
 
@@ -58,7 +58,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 06 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 06 26 30 0f];
 	};
 
@@ -75,7 +75,7 @@
 		qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
 		qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
-		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+		qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
 				0b 94 5b 80 10 26 30 0f];
 	};
 
@@ -96,9 +96,12 @@
 		qcom,phase-port = <0x1>;
 		qcom,pfm-port = <0x2>;
 		qcom,saw2-spm-cmd-ret = [00 03 00 0f];
+		qcom,saw2-spm-cmd-gdhs = [00 20 32 6b c0 e0 d0 42 07 50
+				4e 02 02 d0 e0 c0 22 6b 02 32 50 0f];
 		qcom,saw2-spm-cmd-pc = [00 32 b0 10 e0 d0 6b c0 42 f0
 				11 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
 				50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
+		qcom,L2-spm-is-apcs-master;
 	};
 
 	qcom,lpm-levels {
@@ -130,7 +133,7 @@
 		qcom,lpm-level@2 {
 			reg = <0x2>;
 			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_retention";
+			qcom,l2 = "l2_cache_gdhs";
 			qcom,latency-us = <20000>;
 			qcom,ss-power = <138>;
 			qcom,energy-overhead = <1208400>;
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/boot/dts/msm8610-v2-qrd-skuaa.dts
similarity index 62%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/boot/dts/msm8610-v2-qrd-skuaa.dts
index 607ba8c..677365f 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/boot/dts/msm8610-v2-qrd-skuaa.dts
@@ -8,11 +8,18 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
  */
 
-#include "adreno.h"
+/dts-v1/;
 
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+/include/ "msm8610-v2.dtsi"
+/include/ "msm8610-qrd-skuaa.dtsi"
+/include/ "dsi-v2-panel-hx8379a-wvga-video.dtsi"
+/include/ "msm8610-qrd-camera-sensor.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8610v2 QRD SKUAA";
+	compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
+	qcom,board-id = <11 1>, <11 0>;
+};
+
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/boot/dts/msm8610-v2-qrd-skuab.dts
similarity index 62%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/boot/dts/msm8610-v2-qrd-skuab.dts
index 607ba8c..ccc38fc 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/boot/dts/msm8610-v2-qrd-skuab.dts
@@ -8,11 +8,17 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
  */
 
-#include "adreno.h"
+/dts-v1/;
 
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+/include/ "msm8610-v2.dtsi"
+/include/ "msm8610-qrd-skuab.dtsi"
+/include/ "dsi-v2-panel-otm8018b-fwvga-video.dtsi"
+/include/ "msm8612-qrd-camera-sensor.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8610v2 QRD SKUAB";
+	compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
+	qcom,board-id = <11 3>;
+};
diff --git a/arch/arm/boot/dts/msm8610-v2.dtsi b/arch/arm/boot/dts/msm8610-v2.dtsi
new file mode 100644
index 0000000..a1f466a
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v2.dtsi
@@ -0,0 +1,25 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8610.dtsi file.
+ */
+
+/include/ "msm8610.dtsi"
+/include/ "msm8610-v2-pm.dtsi"
+
+/ {
+	qcom,msm-id = <147 0x10001>, <165 0x10001>, <161 0x10001>, <162 0x10001>,
+				  <163 0x10001>, <164 0x10001>, <166 0x10001>;
+};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 00d0d15..89a7cff 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -40,7 +40,6 @@
 /include/ "msm8610-gpu.dtsi"
 /include/ "msm-gdsc.dtsi"
 /include/ "msm8610-coresight.dtsi"
-/include/ "msm8610-pm.dtsi"
 /include/ "msm8610-smp2p.dtsi"
 /include/ "msm8610-bus.dtsi"
 /include/ "msm8610-mdss.dtsi"
@@ -70,6 +69,15 @@
 		qcom,direct-connect-irqs = <8>;
 	};
 
+	wcd9xxx_intc: wcd9xxx_irq {
+		compatible = "qcom,wcd9xxx-irq";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupt-parent = <&intc>;
+		interrupts = <0 31 0>;
+		interrupt-names = "cdc-int";
+	};
+
 	qcom,mpm2-sleep-counter@fc4a3000 {
 		compatible = "qcom,mpm2-sleep-counter";
 		reg = <0xfc4a3000 0x1000>;
@@ -176,7 +184,7 @@
 		qcom,buffer-type-tz-usage-map = <0x1 0x1>,
 						<0x1fe 0x2>;
 		qcom,hfi = "q6";
-		qcom,max-hw-load = <108000>; /* 720p @ 30 * 1 */
+		qcom,max-hw-load = <244800>; /* 1080p @ 30 * 1 */
 		qcom,vidc-iommu-domains {
 			qcom,domain-ns {
 				qcom,vidc-domain-phandle = <&q6_domain_ns>;
@@ -241,7 +249,7 @@
 				<87 512 60000 960000>;
 	};
 
-	android_usb@fe8050c8 {
+	android_usb: android_usb@fe8050c8 {
 		compatible = "qcom,android-usb";
 		reg = <0xfe8050c8 0xc8>;
 		qcom,android-usb-swfi-latency = <1>;
@@ -258,8 +266,6 @@
 		interrupt-names = "core_irq", "bam_irq";
 
 		vdd-supply = <&pm8110_l17>;
-		qcom,vdd-always-on;
-		qcom,vdd-lpm-sup;
 		qcom,vdd-voltage-level = <2900000 2900000>;
 		qcom,vdd-current-level = <9000 400000>;
 
@@ -472,6 +478,7 @@
 		qcom,i2c-src-freq = <19200000>;
 		qcom,sda-gpio = <&msmgpio 2 0>;
 		qcom,scl-gpio = <&msmgpio 3 0>;
+                qcom,master-id = <86>;
 	};
 
 	i2c_cdc: i2c@f9927000 { /* BLSP1 QUP5 */
@@ -484,6 +491,8 @@
                 interrupt-names = "qup_err_intr";
                 interrupts = <0 99 0>;
                 qcom,i2c-bus-freq = <100000>;
+                qcom,i2c-src-freq = <19200000>;
+                qcom,master-id = <86>;
         };
 
 	i2c: i2c@f9928000 { /* BLSP1 QUP6 */
@@ -499,6 +508,7 @@
 		qcom,i2c-src-freq = <19200000>;
 		qcom,sda-gpio = <&msmgpio 16 0>;
 		qcom,scl-gpio = <&msmgpio 17 0>;
+                qcom,master-id = <86>;
 	};
 
 	i2c@f9925000 { /* BLSP-1 QUP-3 */
@@ -511,6 +521,10 @@
 		interrupt-names = "qup_err_intr";
 		interrupts = <0 97 0>;
 		qcom,i2c-bus-freq = <100000>;
+                qcom,i2c-src-freq = <19200000>;
+                qcom,sda-gpio = <&msmgpio 10 0>;
+                qcom,scl-gpio = <&msmgpio 11 0>;
+                qcom,master-id = <86>;
 	};
 
 	spi_4: spi@f9926000 { /* BLSP1 QUP4 */
@@ -929,10 +943,16 @@
 };
 
 &gdsc_vfe {
+	qcom,clock-names = "core_clk", "iface_clk", "bus_clk";
+	qcom,skip-logic-collapse;
+	qcom,retain-periph;
+	qcom,retain-mem;
 	status = "ok";
 };
 
 &gdsc_oxili_cx {
+	qcom,clock-names = "core_clk", "iface_clk", "mem_clk";
+	qcom,skip-logic-collapse;
 	status = "ok";
 };
 
diff --git a/arch/arm/boot/dts/msm8926-qrd-skug.dts b/arch/arm/boot/dts/msm8926-qrd-skug.dts
new file mode 100644
index 0000000..d0f231d
--- /dev/null
+++ b/arch/arm/boot/dts/msm8926-qrd-skug.dts
@@ -0,0 +1,37 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/include/ "msm8926.dtsi"
+/include/ "msm8226-qrd.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8926 QRD SKUG";
+	compatible = "qcom,msm8926-qrd", "qcom,msm8926", "qcom,qrd";
+	qcom,board-id = <11 5>;
+	qcom,msm-id = <200 0>;
+};
+
+&qrd_batterydata {
+	qcom,rpull-up-kohm = <100>;
+	qcom,vref-batt-therm = <1800000>;
+
+	/include/ "batterydata-qrd-4v2-2000mah.dtsi"
+};
+
+&pm8226_bms {
+	qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8226_chg {
+	qcom,battery-data = <&qrd_batterydata>;
+};
diff --git a/arch/arm/boot/dts/msm8926.dtsi b/arch/arm/boot/dts/msm8926.dtsi
index 013da90a..4b96b66 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -17,6 +17,7 @@
  */
 
 /include/ "msm8226.dtsi"
+/include/ "msm8226-v2-pm.dtsi"
 
 / {
 	model = "Qualcomm MSM 8926";
@@ -64,9 +65,9 @@
 &apc_vreg_corner {
 	qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
 				2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3>;
-	qcom,pvs-corner-ceiling-slow = <1160000 1160000 1280000>;
-	qcom,pvs-corner-ceiling-nom  =  <980000 1080000 1200000>;
-	qcom,pvs-corner-ceiling-fast =  <900000 1000000 1140000>;
+	qcom,pvs-corner-ceiling-slow = <1050000 1160000 1280000>;
+	qcom,pvs-corner-ceiling-nom  = <1050000 1080000 1200000>;
+	qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
 	qcom,cpr-step-quotient = <30>;
 	qcom,cpr-up-threshold = <0>;
 	qcom,cpr-down-threshold = <5>;
@@ -77,3 +78,12 @@
 	qcom,sensors = <6>;
 	qcom,slope = <2901 2846 3038 2955 2901 2846>;
 };
+
+&msmgpio {
+	ngpio = <120>;
+};
+
+&memory_hole {
+	qcom,memblock-remove = <0x08000000 0x7500000
+				0x0fa00000 0x500000>; /* Address and size of the hole */
+};
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index 1413e0c..610f237 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -107,8 +107,9 @@
 		cell-index = <0>;
 		compatible = "qcom,vfe40";
 		reg = <0xfda10000 0x1000>,
-			<0xfda40000 0x200>;
-		reg-names = "vfe", "vfe_vbif";
+			<0xfda40000 0x200>,
+			<0xfd4a8000 0x4>;
+		reg-names = "vfe", "vfe_vbif", "tcsr";
 		interrupts = <0 57 0>;
 		interrupt-names = "vfe";
 		vdd-supply = <&gdsc_vfe>;
@@ -118,8 +119,9 @@
 		cell-index = <1>;
 		compatible = "qcom,vfe40";
 		reg = <0xfda14000 0x1000>,
-			<0xfda40000 0x200>;
-		reg-names = "vfe", "vfe_vbif";
+			<0xfda40000 0x200>,
+			<0xfd4a8000 0x4>;
+		reg-names = "vfe", "vfe_vbif", "tcsr";
 		interrupts = <0 58 0>;
 		interrupt-names = "vfe";
 		vdd-supply = <&gdsc_vfe>;
@@ -167,7 +169,7 @@
 		compatible = "qcom,cpp";
 		reg = <0xfda04000 0x100>,
 			<0xfda40000 0x200>,
-			<0xfda18000 0x008>;
+			<0xfda18000 0x018>;
 		reg-names = "cpp", "cpp_vbif", "cpp_hw";
 		interrupts = <0 49 0>;
 		interrupt-names = "cpp";
@@ -179,6 +181,7 @@
 		compatible = "qcom,camera-led-flash";
 		qcom,flash-type = <1>;
 		qcom,flash-source = <&pm8941_flash0 &pm8941_flash1>;
+		qcom,torch-source = <&pm8941_torch>;
 	};
 
 	cci: qcom,cci@fda0C000 {
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index 63f6d59..455ed2d 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -55,5 +55,12 @@
 			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
 			qcom,memory-reservation-size = <0x614000>;
 		};
+
+		qcom,ion-heap@23 { /* OTHER PIL HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <23>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-fixed = <0x05d00000 0x1e00000>;
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index f90599a..1803f91 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -375,6 +375,7 @@
 
 	hsic_hub {
 		compatible = "qcom,hsic-smsc-hub";
+		smsc,model-id = <3503>;
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges;
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index f8a8fa6..b615ebe 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -158,7 +158,7 @@
 		qcom,hdmi-tx-supply-names = "hpd-gdsc", "hpd-5v", "core-vdda", "core-vcc";
 		qcom,hdmi-tx-min-voltage-level = <0 0 1800000 1800000>;
 		qcom,hdmi-tx-max-voltage-level = <0 0 1800000 1800000>;
-		qcom,hdmi-tx-peak-current = <0 0 1800000 0>;
+		qcom,hdmi-tx-peak-current = <0 0 300000 0>;
 
 		qcom,hdmi-tx-cec = <&msmgpio 31 0>;
 		qcom,hdmi-tx-ddc-clk = <&msmgpio 32 0>;
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index eae9032..a88a709 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -463,7 +463,7 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges;
-		qcom,pfm-threshold = <73>;
+		qcom,pfm-threshold = <76>;
 		qcom,use-phase-scaling-factor;
 
 		krait0_vreg: regulator@f9088000 {
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index 7362b64..0115d89 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -127,6 +127,7 @@
 		qcom,saw2-spm-cmd-gdhs = [00 20 32 42 07 44 22 50 02 32 50 0f];
 		qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 42 07 01 b0 12 44
 				50 02 32 50 0f];
+		qcom,L2-spm-is-apcs-master;
 	};
 
 	qcom,lpm-levels {
@@ -217,7 +218,7 @@
 			<0xff 176>, /* o_wcss_apss_smsm_irq */
 			<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
 			<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
-			<0xff 179>, /* o_wcss_apss_asic_intr
+			<0xff 179>, /* o_wcss_apss_asic_intr */
 
 			<0xff 188>, /* lpass_irq_out_apcs(0) */
 			<0xff 189>, /* lpass_irq_out_apcs(1) */
@@ -315,4 +316,13 @@
 		reg-names = "phys_addr_base";
 		qcom,sleep-stats-version = <2>;
 	};
+
+	qcom,rpm-master-stats@fc428150 {
+		compatible = "qcom,rpm-master-stats";
+		reg = <0xfc428150 0x3200>;
+		qcom,masters = "APSS", "MPSS", "LPSS", "PRONTO";
+		qcom,master-stats-version = <2>;
+		qcom,master-offset = <2560>;
+	};
+
 };
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index 86a61cd..249c963 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -165,3 +165,19 @@
 	qcom,retain-mem;
 	qcom,retain-periph;
 };
+
+&krait_regulator_pmic {
+	status = "ok";
+
+	qcom,ctl@2000 {
+		status = "ok";
+	};
+
+	qcom,ps@2100 {
+		status = "ok";
+	};
+
+	qcom,freq@2200 {
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index 1235c6e..8836975 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -123,6 +123,7 @@
 		qcom,saw2-spm-cmd-gdhs = [00 32 42 07 44 50 02 32 50 0f];
 		qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 42 07 01 b0 12 44
 				50 02 32 50 0f];
+		qcom,L2-spm-is-apcs-master;
 	};
 
 	qcom,lpm-levels {
@@ -219,6 +220,7 @@
 			<0xff 58>,  /* mss_to_apps_irq(1) */
 			<0xff 59>,  /* mss_to_apps_irq(2) */
 			<0xff 60>,  /* mss_to_apps_irq(3) */
+			<0xff 61>,  /* mss_a2_bam_irq */
 			<0xff 70>,  /* iommu_pmon_nonsecure_irq */
 			<0xff 97>,  /* iommu_nonsecure_irq */
 			<0xff 105>, /* iommu_pmon_nonsecure_irq */
@@ -345,4 +347,12 @@
 		reg = <0xfc000000 0x1a0000>;
 		qcom,start-offset = <0x190010>;
 	};
+
+	qcom,rpm-master-stats@fc428150 {
+		compatible = "qcom,rpm-master-stats";
+		reg = <0xfc428150 0x3200>;
+		qcom,masters = "APSS", "MPSS", "LPSS", "PRONTO";
+		qcom,master-stats-version = <2>;
+		qcom,master-offset = <2560>;
+	};
 };
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 9d5e50b..af4030f 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -168,3 +168,19 @@
 &tspp {
 	vdd_cx-supply = <&pm8841_s2_corner>;
 };
+
+&krait_regulator_pmic {
+	status = "ok";
+
+	qcom,ctl@2000 {
+		status = "ok";
+	};
+
+	qcom,ps@2100 {
+		status = "ok";
+	};
+
+	qcom,freq@2200 {
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index c8e3d96..1845e17 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -24,6 +24,19 @@
 		sdhc2 = &sdhc_2; /* SDC2 SD card slot */
 		sdhc3 = &sdhc_3; /* SDC3 SDIO slot */
 		sdhc4 = &sdhc_4; /* SDC4 SDIO slot */
+
+		/* smdtty devices */
+		smd1 = &smdtty_apps_fm;
+		smd2 = &smdtty_apps_riva_bt_acl;
+		smd3 = &smdtty_apps_riva_bt_cmd;
+		smd4 = &smdtty_mbalbridge;
+		smd5 = &smdtty_apps_riva_ant_cmd;
+		smd6 = &smdtty_apps_riva_ant_data;
+		smd7 = &smdtty_data1;
+		smd11 = &smdtty_data11;
+		smd21 = &smdtty_data21;
+		smd27 = &smdtty_gps_nmea;
+		smd36 = &smdtty_loopback;
 	};
 
 	cpus {
@@ -1504,6 +1517,10 @@
 		qcom,core-limit-temp = <80>;
 		qcom,core-temp-hysteresis = <10>;
 		qcom,core-control-mask = <0xe>;
+		qcom,hotplug-temp = <110>;
+		qcom,hotplug-temp-hysteresis = <20>;
+		qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor6",
+				"tsens_tz_sensor7", "tsens_tz_sensor8";
 		qcom,vdd-restriction-temp = <5>;
 		qcom,vdd-restriction-temp-hysteresis = <10>;
 		qcom,pmic-sw-mode-temp = <85>;
@@ -1540,7 +1557,7 @@
 
         memory_hole: qcom,msm-mem-hole {
                 compatible = "qcom,msm-mem-hole";
-                qcom,memblock-remove = <0x7b00000 0x8400000>; /* Address and Size of Hole */
+                qcom,memblock-remove = <0x5d00000 0xa200000>; /* Address and Size of Hole */
         };
 
 	uart7: uart@f995d000 { /*BLSP #2, UART #7 */
@@ -1668,6 +1685,66 @@
 		compatible = "qcom,l2-pmu";
 		interrupts = <0 1 0>;
 	};
+
+	qcom,smdtty {
+		compatible = "qcom,smdtty";
+
+		smdtty_apps_fm: qcom,smdtty-apps-fm {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_FM";
+		};
+
+		smdtty_apps_riva_bt_acl: smdtty-apps-riva-bt-acl {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_BT_ACL";
+		};
+
+		smdtty_apps_riva_bt_cmd: qcom,smdtty-apps-riva-bt-cmd {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_BT_CMD";
+		};
+
+		smdtty_mbalbridge: qcom,smdtty-mbalbridge {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "MBALBRIDGE";
+		};
+
+		smdtty_apps_riva_ant_cmd: smdtty-apps-riva-ant-cmd {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_ANT_CMD";
+		};
+
+		smdtty_apps_riva_ant_data: smdtty-apps-riva-ant-data {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_ANT_DATA";
+		};
+
+		smdtty_data1: qcom,smdtty-data1 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA1";
+		};
+
+		smdtty_data11: qcom,smdtty-data11 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA11";
+		};
+
+		smdtty_data21: qcom,smdtty-data21 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA21";
+		};
+
+		smdtty_gps_nmea: smdtty-gpsnmea {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "GPSNMEA";
+		};
+
+		smdtty_loopback: smdtty-loopback {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "LOOPBACK";
+			qcom,smdtty-dev-name = "LOOPBACK_TTY";
+		};
+	};
 };
 
 &gdsc_venus {
diff --git a/arch/arm/boot/dts/msm8974pro-ab.dtsi b/arch/arm/boot/dts/msm8974pro-ab.dtsi
index 88687bd..5809069 100644
--- a/arch/arm/boot/dts/msm8974pro-ab.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ab.dtsi
@@ -39,3 +39,19 @@
 &tspp {
 	vdd_cx-supply = <&pm8841_s2_corner>;
 };
+
+&krait_regulator_pmic {
+	status = "ok";
+
+	qcom,ctl@2000 {
+		status = "ok";
+	};
+
+	qcom,ps@2100 {
+		status = "ok";
+	};
+
+	qcom,freq@2200 {
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-mtp.dts b/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
index 862dbee..237c9f9 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
@@ -123,3 +123,12 @@
 		qcom,thermal-node;
 	};
 };
+
+&sdhc_1 {
+	reg = <0xf9824900 0x1a0>, <0xf9824000 0x800>;
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 200000000 400000000>;
+	qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+	qcom,pad-pull-on = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
+	qcom,pad-pull-off = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi b/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
index 250afd2..debf7fb 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
@@ -62,10 +62,6 @@
 		vbus_dwc3-supply = <&pm8941_mvs1>;
 	};
 
-	qcom,mdss_dsi_toshiba_720p_video {
-		qcom,rst-gpio = <&pma8084_gpios 20 0>;
-	};
-
 	gpio_keys {
 		camera_snapshot {
 			gpios = <&pma8084_gpios 3 0x1>;
diff --git a/arch/arm/boot/dts/msm8974pro-ac-regulator.dtsi b/arch/arm/boot/dts/msm8974pro-ac-regulator.dtsi
index 9d7f316..e0473b7 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-regulator.dtsi
@@ -479,7 +479,7 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges;
-		qcom,pfm-threshold = <73>;
+		qcom,pfm-threshold = <76>;
 
 		krait0_vreg: regulator@f9088000 {
 			compatible = "qcom,krait-regulator";
diff --git a/arch/arm/boot/dts/msm8974pro-ac.dtsi b/arch/arm/boot/dts/msm8974pro-ac.dtsi
index 032c256..4c55169 100644
--- a/arch/arm/boot/dts/msm8974pro-ac.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac.dtsi
@@ -52,6 +52,7 @@
 		vdd-supply = <&pma8084_l22>;
 		vddio-supply = <&pma8084_l12>;
 		vdda-supply = <&pma8084_l2>;
+		qcom,platform-reset-gpio = <&pma8084_gpios 20 0>;
 	};
 
 	qcom,mdss_dsi@fd922e00 {
@@ -188,3 +189,19 @@
 &tspp {
 	vdd_cx-supply = <&pma8084_s2_corner>;
 };
+
+&krait_regulator_pmic {
+	status = "ok";
+
+	qcom,ctl@2900 {
+		status = "ok";
+	};
+
+	qcom,ps@2a00 {
+		status = "ok";
+	};
+
+	qcom,freq@2b00 {
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ion.dtsi b/arch/arm/boot/dts/msm8974pro-ion.dtsi
new file mode 100644
index 0000000..7faee21
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-ion.dtsi
@@ -0,0 +1,30 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	qcom,ion {
+
+		qcom,ion-heap@23 { /* OTHER PIL HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <23>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-fixed = <0x05400000 0x2700000>;
+		};
+
+		qcom,ion-heap@26 { /* MODEM HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <26>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-fixed = <0x08000000 0x5000000>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974pro-pm.dtsi b/arch/arm/boot/dts/msm8974pro-pm.dtsi
new file mode 100644
index 0000000..9e1f83f
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-pm.dtsi
@@ -0,0 +1,341 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	qcom,spm@f9089000 {
+		compatible = "qcom,spm-v2";
+	#address-cells = <1>;
+	#size-cells = <1>;
+		reg = <0xf9089000 0x1000>;
+		qcom,core-id = <0>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+	};
+
+	qcom,spm@f9099000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9099000 0x1000>;
+		qcom,core-id = <1>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+	};
+
+	qcom,spm@f90a9000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf90a9000 0x1000>;
+		qcom,core-id = <2>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+	};
+
+	qcom,spm@f90b9000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf90b9000 0x1000>;
+		qcom,core-id = <3>;
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x01>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+		qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+			30 06 26 30 0F];
+	};
+
+	qcom,spm@f9012000 {
+		compatible = "qcom,spm-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9012000 0x1000>;
+		qcom,core-id = <0xffff>; /* L2/APCS SAW */
+		qcom,saw2-ver-reg = <0xfd0>;
+		qcom,saw2-cfg = <0x14>;
+		qcom,saw2-avs-ctl = <0>;
+		qcom,saw2-avs-hysteresis = <0>;
+		qcom,saw2-avs-limit = <0>;
+		qcom,saw2-avs-dly= <0>;
+		qcom,saw2-spm-dly= <0x3C102800>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-pmic-data0 = <0x02030080>;
+		qcom,saw2-pmic-data1 = <0x00030000>;
+		qcom,vctl-timeout-us = <50>;
+		qcom,vctl-port = <0x0>;
+		qcom,phase-port = <0x1>;
+		qcom,pfm-port = <0x2>;
+		qcom,saw2-spm-cmd-ret = [1f 00 03 00 0f];
+		qcom,saw2-spm-cmd-gdhs = [00 32 42 07 44 50 02 32 50 0f];
+		qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 42 07 01 b0 12 44
+				50 02 32 50 0f];
+		qcom,L2-spm-is-apcs-master;
+	};
+
+	qcom,lpm-levels {
+		compatible = "qcom,lpm-levels";
+		qcom,default-l2-state = "l2_cache_retention";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,lpm-level@0 {
+			reg = <0x0>;
+			qcom,mode = "wfi";
+			qcom,l2 = "l2_cache_retention";
+			qcom,latency-us = <1>;
+			qcom,ss-power = <715>;
+			qcom,energy-overhead = <17700>;
+			qcom,time-overhead = <2>;
+		};
+
+		qcom,lpm-level@1 {
+			reg = <0x1>;
+			qcom,mode = "retention";
+			qcom,l2 = "l2_cache_retention";
+			qcom,latency-us = <35>;
+			qcom,ss-power = <542>;
+			qcom,energy-overhead = <34920>;
+			qcom,time-overhead = <40>;
+		};
+
+
+		qcom,lpm-level@2 {
+			reg = <0x2>;
+			qcom,mode = "standalone_pc";
+			qcom,l2 = "l2_cache_retention";
+			qcom,latency-us = <300>;
+			qcom,ss-power = <476>;
+			qcom,energy-overhead = <225300>;
+			qcom,time-overhead = <350>;
+		};
+
+		qcom,lpm-level@3 {
+			reg = <0x3>;
+			qcom,mode = "pc";
+			qcom,l2 = "l2_cache_gdhs";
+			qcom,gpio-detectable;
+			qcom,latency-us = <20000>;
+			qcom,ss-power = <163>;
+			qcom,energy-overhead = <1577736>;
+			qcom,time-overhead = <5067>;
+		};
+
+		qcom,lpm-level@4 {
+			reg = <0x4>;
+			qcom,mode = "pc";
+			qcom,l2 = "l2_cache_pc";
+			qcom,latency-us = <30000>;
+			qcom,ss-power = <83>;
+			qcom,energy-overhead = <2274420>;
+			qcom,time-overhead = <6605>;
+		};
+	};
+
+	qcom,pm-boot {
+		compatible = "qcom,pm-boot";
+		qcom,mode = "tz";
+	};
+
+	qcom,mpm@fc4281d0 {
+		compatible = "qcom,mpm-v2";
+		reg = <0xfc4281d0 0x1000>, /* MSM_RPM_MPM_BASE 4K */
+		    <0xf9011008 0x4>;   /* MSM_APCS_GCC_BASE 4K */
+		reg-names = "vmpm", "ipc";
+		interrupts = <0 171 1>;
+
+		qcom,ipc-bit-offset = <1>;
+
+		qcom,gic-parent = <&intc>;
+		qcom,gic-map = <2 216>, /* tsens_upper_lower_int */
+			<47 165>, /* usb30_hs_phy_irq */
+			<50 172>, /* usb1_hs_async_wakeup_irq */
+			<53 104>, /* mdss_irq */
+			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+			<0xff 56>,  /* modem_watchdog */
+			<0xff 57>,  /* mss_to_apps_irq(0) */
+			<0xff 58>,  /* mss_to_apps_irq(1) */
+			<0xff 59>,  /* mss_to_apps_irq(2) */
+			<0xff 60>,  /* mss_to_apps_irq(3) */
+			<0xff 61>,  /* mss_a2_bam_irq */
+			<0xff 70>,  /* iommu_pmon_nonsecure_irq */
+			<0xff 97>,  /* iommu_nonsecure_irq */
+			<0xff 105>, /* iommu_pmon_nonsecure_irq */
+			<0xff 173>, /* o_wcss_apss_smd_hi */
+			<0xff 174>, /* o_wcss_apss_smd_med */
+			<0xff 175>, /* o_wcss_apss_smd_low */
+			<0xff 176>, /* o_wcss_apss_smsm_irq */
+			<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
+			<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
+			<0xff 179>, /* o_wcss_apss_asic_intr */
+
+			<0xff 181>, /* wcnss watchdog */
+			<0xff 188>, /* lpass_irq_out_apcs(0) */
+			<0xff 189>, /* lpass_irq_out_apcs(1) */
+			<0xff 190>, /* lpass_irq_out_apcs(2) */
+			<0xff 191>, /* lpass_irq_out_apcs(3) */
+			<0xff 192>, /* lpass_irq_out_apcs(4) */
+			<0xff 193>, /* lpass_irq_out_apcs(5) */
+			<0xff 194>, /* lpass_irq_out_apcs(6) */
+			<0xff 195>, /* lpass_irq_out_apcs(7) */
+			<0xff 196>, /* lpass_irq_out_apcs(8) */
+			<0xff 197>, /* lpass_irq_out_apcs(9) */
+			<0xff 200>, /* rpm_ipc(4) */
+			<0xff 201>, /* rpm_ipc(5) */
+			<0xff 202>, /* rpm_ipc(6) */
+			<0xff 203>, /* rpm_ipc(7) */
+			<0xff 204>, /* rpm_ipc(24) */
+			<0xff 205>, /* rpm_ipc(25) */
+			<0xff 206>, /* rpm_ipc(26) */
+			<0xff 207>, /* rpm_ipc(27) */
+			<0xff 211>, /* usb_dwc3_otg */
+			<0xff 240>; /* summary_irq_kpss */
+
+		qcom,gpio-parent = <&msmgpio>;
+		qcom,gpio-map = <3  102>,
+			<4  1 >,
+			<5  5 >,
+			<6  9 >,
+			<7  18>,
+			<8  20>,
+			<9  24>,
+			<10  27>,
+			<11  28>,
+			<12  34>,
+			<13  35>,
+			<14  37>,
+			<15  42>,
+			<16  44>,
+			<17  46>,
+			<18  50>,
+			<19  54>,
+			<20  59>,
+			<21  61>,
+			<22  62>,
+			<23  64>,
+			<24  65>,
+			<25  66>,
+			<26  67>,
+			<27  68>,
+			<28  71>,
+			<29  72>,
+			<30  73>,
+			<31  74>,
+			<32  75>,
+			<33  77>,
+			<34  79>,
+			<35  80>,
+			<36  82>,
+			<37  86>,
+			<38  92>,
+			<39  93>,
+			<40  95>,
+			<41  144>;
+	};
+
+	qcom,pm-8x60@fe805664 {
+		compatible = "qcom,pm-8x60";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfe805664 0x40>;
+		qcom,pc-mode = "tz_l2_int";
+		qcom,use-sync-timer;
+		qcom,cpus-as-clocks;
+
+		qcom,pm-snoc-client {
+			compatible = "qcom,pm-snoc-client";
+			qcom,msm-bus,name = "ocimem_snoc";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,vectors-KBps =
+				<54 585 0 0>,
+				<54 585 0 800000>;
+		};
+	};
+
+	qcom,cpu-sleep-status@f9088008{
+		compatible = "qcom,cpu-sleep-status";
+		reg = <0xf9088008 0x100>;
+		qcom,cpu-alias-addr = <0x10000>;
+		qcom,sleep-status-mask= <0x80000>;
+	};
+
+	qcom,rpm-log@fc19dc00 {
+		compatible = "qcom,rpm-log";
+		reg = <0xfc19dc00 0x4000>;
+		qcom,rpm-addr-phys = <0xfc000000>;
+		qcom,offset-version = <4>;
+		qcom,offset-page-buffer-addr = <36>;
+		qcom,offset-log-len = <40>;
+		qcom,offset-log-len-mask = <44>;
+		qcom,offset-page-indices = <56>;
+	};
+
+	qcom,rpm-stats@fc19dba0 {
+		compatible = "qcom,rpm-stats";
+		reg = <0xfc19dba0 0x1000>;
+		reg-names = "phys_addr_base";
+		qcom,sleep-stats-version = <2>;
+	};
+
+	qcom,rpm-rbcpr-stats@fc000000 {
+		compatible = "qcom,rpmrbcpr-stats";
+		reg = <0xfc000000 0x1a0000>;
+		qcom,start-offset = <0x190010>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index b80eb0f..9b0638d 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -19,7 +19,8 @@
 /include/ "msm8974.dtsi"
 /include/ "msm8974-v2-iommu.dtsi"
 /include/ "msm8974-v2-iommu-domains.dtsi"
-/include/ "msm8974-v2-pm.dtsi"
+/include/ "msm8974pro-pm.dtsi"
+/include/ "msm8974pro-ion.dtsi"
 
 &soc {
 	android_usb@fe8050c8 {
@@ -126,7 +127,7 @@
 
 &msm_vidc {
 	qcom,vidc-ns-map = <0x40000000 0x40000000>;
-	qcom,load-freq-tbl = <979200 465000000>,
+	qcom,load-freq-tbl = <1036800 465000000>,
 		<783360 465000000>,
 		<489600 266670000>,
 		<244800 133330000>;
@@ -161,19 +162,40 @@
 		<1608000 604000>,
 		<2576000 967000>,
 		<4680000 1404000>,
-		<49880000 1496000>;
+		<4988000 1496000>;
 	qcom,dec-ddr-ab-ib = <0 0>,
 		<208000 303000>,
-		<536000 303000>,
-		<1012000 303000>,
-		<2024000 606000>,
-		<3240000 970000>,
-		<4048000 1212000>,
-		<4264000 1279000>;
-	qcom,iommu-groups = <&venus_domain_ns &venus_domain_sec_bitstream
-			&venus_domain_sec_pixel &venus_domain_sec_non_pixel>;
-	qcom,iommu-group-buffer-types = <0xfff 0x91 0x42 0x120>;
+		<536000 1600000>,
+		<1012000 1600000>,
+		<2024000 1600000>,
+		<3240000 1600000>,
+		<4048000 1600000>,
+		<4264000 1600000>;
+	qcom,max-hw-load = <1281600>; /* max(4k X 2304 @ 24, 4k X 2160 @ 30) + 1080p @ 30 */
 	qcom,buffer-type-tz-usage-table = <0x91 0x1>,
 					<0x42 0x2>,
 					<0x120 0x3>;
+	qcom,vidc-iommu-domains {
+		qcom,domain-ns {
+			qcom,vidc-domain-phandle = <&venus_domain_ns>;
+			qcom,vidc-partition-buffer-types = <0x1ff>,
+							<0x200>;
+		};
+		qcom,domain-sec-bs {
+			qcom,vidc-domain-phandle = <&venus_domain_sec_bitstream>;
+			qcom,vidc-partition-buffer-types = <0x91>;
+		};
+		qcom,domain-sec-px {
+			qcom,vidc-domain-phandle = <&venus_domain_sec_pixel>;
+			qcom,vidc-partition-buffer-types = <0x42>;
+		};
+		qcom,domain-sec-np {
+			qcom,vidc-domain-phandle = <&venus_domain_sec_non_pixel>;
+			qcom,vidc-partition-buffer-types = <0x120>;
+		};
+	};
+};
+
+&memory_hole {
+	qcom,memblock-remove = <0x05400000 0xab00000>; /* Address and size of the hole */
 };
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 7989f2b..1e6cdf2 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -192,4 +192,12 @@
 		reg = <0xfc000000 0x1a0000>;
 		qcom,start-offset = <0x190010>;
 	};
+
+	qcom,rpm-master-stats@fc428150 {
+		compatible = "qcom,rpm-master-stats";
+		reg = <0xfc428150 0x3200>;
+		qcom,masters = "APSS", "MPSS", "LPSS";
+		qcom,master-stats-version = <2>;
+		qcom,master-offset = <2560>;
+	};
 };
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 31d133a..7d96cb1 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -1,6 +1,5 @@
 # CONFIG_ARM_PATCH_PHYS_VIRT is not set
 CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_RCU_FAST_NO_HZ=y
 CONFIG_IKCONFIG=y
@@ -61,7 +60,7 @@
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_ADSP_LOADER=y
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
@@ -72,6 +71,7 @@
 CONFIG_MSM_RTB_SEPARATE_CPUS=y
 CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
 CONFIG_MSM_BOOT_STATS=y
+CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
@@ -98,14 +98,17 @@
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
 CONFIG_INET=y
 CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_IP_MULTIPLE_TABLES=y
 CONFIG_IP_ROUTE_VERBOSE=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
 CONFIG_IPV6=y
@@ -142,6 +145,7 @@
 CONFIG_NETFILTER_XT_TARGET_LOG=y
 CONFIG_NETFILTER_XT_TARGET_MARK=y
 CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
 CONFIG_NETFILTER_XT_MATCH_COMMENT=y
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
@@ -223,6 +227,7 @@
 CONFIG_DM_CRYPT=y
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
+CONFIG_TUN=y
 CONFIG_KS8851=y
 # CONFIG_MSM_RMNET is not set
 CONFIG_MSM_RMNET_BAM=y
@@ -290,6 +295,7 @@
 # CONFIG_MSM_CAMERA is not set
 CONFIG_OV8825=y
 CONFIG_OV12830=y
+CONFIG_IMX135=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_EEPROM=y
 CONFIG_MSM_CPP=y
@@ -415,8 +421,10 @@
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_SET_MODULE_RONX=y
 CONFIG_KEYS=y
+CONFIG_CRYPTO_NULL=y
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_XCBC=y
 CONFIG_CRYPTO_TWOFISH=y
 CONFIG_NFC_QNCI=y
 CONFIG_CRYPTO_DEV_QCRYPTO=m
@@ -425,3 +433,5 @@
 CONFIG_MOBICORE_SUPPORT=m
 CONFIG_MOBICORE_API=m
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
+CONFIG_TOUCHSCREEN_GT9XX=y
+CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 24ac0d8..1d5c492 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -1,6 +1,5 @@
 # CONFIG_ARM_PATCH_PHYS_VIRT is not set
 CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_RCU_FAST_NO_HZ=y
 CONFIG_IKCONFIG=y
@@ -61,7 +60,7 @@
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_ADSP_LOADER=y
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
@@ -73,6 +72,7 @@
 CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
 CONFIG_MSM_BOOT_STATS=y
 CONFIG_MSM_XPU_ERR_FATAL=y
+CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
@@ -99,14 +99,17 @@
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
 CONFIG_INET=y
 CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_IP_MULTIPLE_TABLES=y
 CONFIG_IP_ROUTE_VERBOSE=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
 CONFIG_IPV6=y
@@ -143,6 +146,7 @@
 CONFIG_NETFILTER_XT_TARGET_LOG=y
 CONFIG_NETFILTER_XT_TARGET_MARK=y
 CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
 CONFIG_NETFILTER_XT_MATCH_COMMENT=y
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
@@ -205,6 +209,7 @@
 CONFIG_BT_HIDP=y
 CONFIG_BT_HCISMD=y
 CONFIG_CFG80211=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
 CONFIG_NL80211_TESTMODE=y
 CONFIG_CMA=y
 CONFIG_BLK_DEV_LOOP=y
@@ -294,6 +299,7 @@
 # CONFIG_MSM_CAMERA is not set
 CONFIG_OV8825=y
 CONFIG_OV12830=y
+CONFIG_IMX135=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_EEPROM=y
 CONFIG_MSM_CPP=y
@@ -466,8 +472,10 @@
 CONFIG_EARLY_PRINTK=y
 CONFIG_DEBUG_SET_MODULE_RONX=y
 CONFIG_KEYS=y
+CONFIG_CRYPTO_NULL=y
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_XCBC=y
 CONFIG_CRYPTO_TWOFISH=y
 CONFIG_NFC_QNCI=y
 CONFIG_CRYPTO_DEV_QCRYPTO=m
@@ -476,3 +484,5 @@
 CONFIG_MOBICORE_SUPPORT=m
 CONFIG_MOBICORE_API=m
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
+CONFIG_TOUCHSCREEN_GT9XX=y
+CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index b9d37b8..03ddb3a 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -62,15 +62,13 @@
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_ADSP_LOADER=y
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
 CONFIG_MSM_OCMEM_NONSECURE=y
 CONFIG_MSM_OCMEM_POWER_DISABLE=y
 CONFIG_SENSORS_ADSP=y
-CONFIG_MSM_RTB=y
-CONFIG_MSM_RTB_SEPARATE_CPUS=y
 CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
 CONFIG_MSM_BOOT_STATS=y
 CONFIG_NO_HZ=y
@@ -234,6 +232,7 @@
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_INPUT_GPIO=m
+# CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_SERIAL_MSM_HSL=y
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
 CONFIG_DIAG_CHAR=y
@@ -392,3 +391,4 @@
 CONFIG_SENSORS_STK3X1X=y
 CONFIG_SENSORS_MMA8X5X=y
 CONFIG_LOGCAT_SIZE=64
+CONFIG_SENSORS_CAPELLA_CM36283=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index a5f0704..9788e7c 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -1,6 +1,5 @@
 # CONFIG_ARM_PATCH_PHYS_VIRT is not set
 CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_RCU_FAST_NO_HZ=y
 CONFIG_IKCONFIG=y
@@ -60,7 +59,7 @@
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_ADSP_LOADER=y
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
@@ -71,6 +70,7 @@
 CONFIG_MSM_RTB_SEPARATE_CPUS=y
 CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
 CONFIG_MSM_BOOT_STATS=y
+CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
@@ -203,6 +203,7 @@
 CONFIG_BT_HIDP=y
 CONFIG_BT_HCISMD=y
 CONFIG_CFG80211=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
 CONFIG_NL80211_TESTMODE=y
 CONFIG_CMA=y
 CONFIG_BLK_DEV_LOOP=y
@@ -232,6 +233,7 @@
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_INPUT_GPIO=m
+# CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_SERIAL_MSM_HSL=y
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
 CONFIG_DIAG_CHAR=y
@@ -436,3 +438,4 @@
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
 CONFIG_SENSORS_STK3X1X=y
 CONFIG_SENSORS_MMA8X5X=y
+CONFIG_SENSORS_CAPELLA_CM36283=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 9b55c3b..1d645e2 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -253,6 +253,7 @@
 CONFIG_BT_HCIUART_IBS=y
 CONFIG_MSM_BT_POWER=y
 CONFIG_CFG80211=m
+CONFIG_CFG80211_INTERNAL_REGDB=y
 # CONFIG_CFG80211_WEXT is not set
 CONFIG_RFKILL=y
 CONFIG_GENLOCK=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 7901e93..3bc159a 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -68,7 +68,7 @@
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_ADSP_LOADER=y
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
@@ -159,6 +159,7 @@
 CONFIG_NETFILTER_XT_TARGET_LOG=y
 CONFIG_NETFILTER_XT_TARGET_MARK=y
 CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
 CONFIG_NETFILTER_XT_MATCH_COMMENT=y
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 8520f23..118fdd4 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -68,7 +68,7 @@
 CONFIG_MSM_WATCHDOG_V2=y
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_ADSP_LOADER=y
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
@@ -165,6 +165,7 @@
 CONFIG_NETFILTER_XT_TARGET_LOG=y
 CONFIG_NETFILTER_XT_TARGET_MARK=y
 CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
 CONFIG_NETFILTER_XT_MATCH_COMMENT=y
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
@@ -240,6 +241,7 @@
 CONFIG_BT_HCIUART_ATH3K=y
 CONFIG_MSM_BT_POWER=y
 CONFIG_CFG80211=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
 CONFIG_NL80211_TESTMODE=y
 CONFIG_RFKILL=y
 CONFIG_GENLOCK=y
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/include/asm/archrandom.h
similarity index 75%
rename from drivers/gpu/msm/adreno_trace.c
rename to arch/arm/include/asm/archrandom.h
index 607ba8c..5530d45 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/include/asm/archrandom.h
@@ -11,8 +11,10 @@
  *
  */
 
-#include "adreno.h"
+#ifndef ARM_ASM_ARCHRANDOM_H
+#define ARM_ASM_ARCHRANDOM_H
 
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+extern int arch_get_random_long(unsigned long *v);
+extern int arch_get_random_int(unsigned int *v);
+
+#endif
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index ac4c7a3..9e27592 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -291,7 +291,7 @@
 	return 0;
 }
 
-static inline cycle_t counter_get_cntpct_mem(void)
+static inline cycle_t notrace counter_get_cntpct_mem(void)
 {
 	u32 cvall, cvalh, thigh;
 
@@ -304,7 +304,7 @@
 	return ((cycle_t) cvalh << 32) | cvall;
 }
 
-static inline cycle_t counter_get_cntpct_cp15(void)
+static inline cycle_t notrace counter_get_cntpct_cp15(void)
 {
 	u32 cvall, cvalh;
 
@@ -312,7 +312,7 @@
 	return ((cycle_t) cvalh << 32) | cvall;
 }
 
-static inline cycle_t counter_get_cntvct_mem(void)
+static inline cycle_t notrace counter_get_cntvct_mem(void)
 {
 	u32 cvall, cvalh, thigh;
 
@@ -325,7 +325,7 @@
 	return ((cycle_t) cvalh << 32) | cvall;
 }
 
-static inline cycle_t counter_get_cntvct_cp15(void)
+static inline cycle_t notrace counter_get_cntvct_cp15(void)
 {
 	u32 cvall, cvalh;
 
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index a70b300..32b5b26 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -555,13 +555,15 @@
 
 static DEFINE_RAW_SPINLOCK(stop_lock);
 
+static struct pt_regs __percpu regs_before_stop;
 /*
  * ipi_cpu_stop - handle IPI from smp_send_stop()
  */
-static void ipi_cpu_stop(unsigned int cpu)
+static void ipi_cpu_stop(unsigned int cpu, struct pt_regs *regs)
 {
 	if (system_state == SYSTEM_BOOTING ||
 	    system_state == SYSTEM_RUNNING) {
+		per_cpu(regs_before_stop, cpu) = *regs;
 		raw_spin_lock(&stop_lock);
 		printk(KERN_CRIT "CPU%u: stopping\n", cpu);
 		dump_stack();
@@ -676,7 +678,7 @@
 
 	case IPI_CPU_STOP:
 		irq_enter();
-		ipi_cpu_stop(cpu);
+		ipi_cpu_stop(cpu, regs);
 		irq_exit();
 		break;
 
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index ae59e5a..0bf55ae 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -93,6 +93,9 @@
 		_text = .;
 		HEAD_TEXT
 	}
+#ifdef CONFIG_STRICT_MEMORY_RWX
+	. = ALIGN(1<<SECTION_SHIFT);
+#endif
 
 	.text : {			/* Real text segment		*/
 		_stext = .;		/* Text and read-only data	*/
@@ -115,10 +118,10 @@
 		*(.got)			/* Global offset table		*/
 			ARM_CPU_KEEP(PROC_INFO)
 	}
+
 #ifdef CONFIG_STRICT_MEMORY_RWX
 	. = ALIGN(1<<SECTION_SHIFT);
 #endif
-
 	RO_DATA(PAGE_SIZE)
 
 #ifdef CONFIG_ARM_UNWIND
@@ -156,6 +159,9 @@
 	.init.proc.info : {
 		ARM_CPU_DISCARD(PROC_INFO)
 	}
+#ifdef CONFIG_STRICT_MEMORY_RWX
+	. = ALIGN(1<<SECTION_SHIFT);
+#endif
 	.init.arch.info : {
 		__arch_info_begin = .;
 		*(.arch.info.init)
@@ -190,10 +196,6 @@
 		INIT_RAM_FS
 	}
 #ifndef CONFIG_XIP_KERNEL
-#ifdef CONFIG_STRICT_MEMORY_RWX
-	. = ALIGN(1<<SECTION_SHIFT);
-#endif
-	__init_data = .;
 	.exit.data : {
 		ARM_EXIT_KEEP(EXIT_DATA)
 	}
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 5c0d2cf..87e3e5b 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -2626,7 +2626,7 @@
 config MSM_ADSP_LOADER
         tristate "ADSP loader support"
         select SND_SOC_MSM_APRV2_INTF
-	depends on MSM_AUDIO_QDSP6V2 && m
+	depends on MSM_AUDIO_QDSP6V2
         help
           Enable ADSP image loader.
 	  The ADSP loader brings ADSP out of reset
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index e4a647f..89eb589 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -75,7 +75,7 @@
 $(obj)/smd_rpc_sym.c: $(src)/smd_rpc_sym $(src)/mkrpcsym.pl
 	$(call if_changed,mkrpcsym)
 
-obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o remote_spinlock.o smd_private.o smem.o
+obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o remote_spinlock.o smd_private.o smem.o smd_init_dt.o smd_init_plat.o
 obj-$(CONFIG_MSM_SMP2P) += smp2p.o smp2p_debug.o smp2p_gpio.o
 obj-$(CONFIG_MSM_SMP2P_TEST) += smp2p_loopback.o smp2p_test.o smp2p_gpio_test.o smp2p_spinlock_test.o
 obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o
@@ -296,7 +296,7 @@
 obj-$(CONFIG_ARCH_MSM8610) += gdsc.o
 obj-$(CONFIG_ARCH_MPQ8092) += gdsc.o
 obj-$(CONFIG_ARCH_APQ8084) += gdsc.o
-obj-$(CONFIG_KRAIT_REGULATOR) += krait-regulator.o
+obj-$(CONFIG_KRAIT_REGULATOR) += krait-regulator.o  krait-regulator-pmic.o
 obj-$(CONFIG_ARCH_MSMKRYPTON) += board-krypton.o board-krypton-gpiomux.o
 obj-$(CONFIG_ARCH_MSMSAMARIUM) += board-samarium.o board-samarium-gpiomux.o
 obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
@@ -431,3 +431,4 @@
 
 obj-$(CONFIG_WALL_CLK) += wallclk.o
 obj-$(CONFIG_WALL_CLK_SYSFS) += wallclk_sysfs.o
+obj-$(CONFIG_ARCH_RANDOM) += early_random.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 9296515..910264e 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -109,6 +109,7 @@
         dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-cdp.dtb
         dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-mtp.dtb
         dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-qrd.dtb
+        dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-qrd-skug.dtb
         dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v1-qrd-skuf.dtb
         dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v2-qrd-skuf.dtb
         dtb-$(CONFIG_ARCH_MSM8226)	+= apq8026-v1-xpm.dtb
@@ -133,12 +134,16 @@
 
 # MSM8610
    zreladdr-$(CONFIG_ARCH_MSM8610)	:= 0x00008000
-        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-cdp.dtb
-        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-mtp.dtb
+        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-v1-cdp.dtb
+        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-v2-cdp.dtb
+        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-v1-mtp.dtb
+        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-v2-mtp.dtb
         dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-rumi.dtb
         dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-sim.dtb
-        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-qrd-skuaa.dtb
-        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-qrd-skuab.dtb
+        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-v1-qrd-skuaa.dtb
+        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-v1-qrd-skuab.dtb
+        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-v2-qrd-skuaa.dtb
+        dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-v2-qrd-skuab.dtb
 
 # MSMSAMARIUM
    zreladdr-$(CONFIG_ARCH_MSMSAMARIUM)	:= 0x00008000
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 6d848d2..8410019 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -899,38 +899,460 @@
 	{ 0, { 0 } }
 };
 
-static struct acpu_level acpu_freq_tbl_pro_pvs0[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000, 999 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000, 999 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 999 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  805000, 999 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  815000, 999 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  825000, 999 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  835000, 999 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  845000, 999 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  855000, 999 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  865000, 999 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  875000, 999 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  890000, 999 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  900000, 999 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  915000, 999 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  925000, 999 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  940000, 999 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  950000, 999 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  965000, 999 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  980000, 999 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  995000, 999 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1010000, 999 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1025000, 999 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1040000, 999 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1055000, 999 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1070000, 999 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1085000, 999 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1100000, 999 },
-	/* higher frequencies aren't available for bring up */
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs0[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 101 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  780000, 120 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  790000, 139 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 159 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  810000, 180 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  820000, 200 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  830000, 221 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  840000, 242 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  850000, 264 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  865000, 287 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  875000, 308 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  890000, 333 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  900000, 356 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  915000, 380 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  925000, 404 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  940000, 430 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  955000, 456 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  970000, 482 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  985000, 510 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1000000, 538 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1015000, 565 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1030000, 596 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1045000, 627 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1060000, 659 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1075000, 691 },
 	{ 0, { 0 } }
 };
 
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs1[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  785000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  795000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  805000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  815000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  825000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  835000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  850000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  860000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  870000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  885000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  895000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  905000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  920000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  935000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  950000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  965000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  980000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  995000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1005000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1020000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1035000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1050000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs2[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 101 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 120 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  760000, 139 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  770000, 159 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  780000, 180 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  790000, 200 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 221 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  810000, 242 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  820000, 264 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  830000, 287 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  840000, 308 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  850000, 333 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  865000, 356 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  875000, 380 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  885000, 404 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  900000, 430 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  915000, 456 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  930000, 482 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  945000, 510 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  955000, 538 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  970000, 565 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  980000, 596 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  995000, 627 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1010000, 659 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1025000, 691 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs3[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  755000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  765000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  785000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  795000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  805000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  815000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  825000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  835000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  850000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  860000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  885000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  900000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  910000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  925000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  935000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  945000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  960000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  970000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  985000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1000000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs4[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  755000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  765000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  785000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  795000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  805000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  815000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  825000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  835000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  845000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  855000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  870000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  885000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  895000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  905000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  915000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  925000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  935000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  950000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  960000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  975000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs5[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  725000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  725000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  725000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  725000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  725000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  735000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  745000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  755000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  765000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  785000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  795000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  805000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  815000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  825000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  835000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  845000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  855000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  865000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  875000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  885000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  895000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  905000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  915000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  930000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  940000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  950000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs6[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  725000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  725000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  725000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  725000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  725000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  725000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  735000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  745000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  755000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  765000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  775000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  785000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  795000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  805000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  815000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  825000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  835000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  845000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  850000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  860000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  870000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  880000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  890000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  895000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  905000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  915000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  925000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs0[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  805000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  815000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  825000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  835000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  845000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  855000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  885000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  900000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  915000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  930000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  945000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  960000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  980000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1000000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1020000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1040000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1060000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1080000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1100000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs1[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  800000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  805000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  815000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  825000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  835000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  845000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  855000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  870000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  885000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  900000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  915000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  930000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  945000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  960000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  975000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  995000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1015000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1035000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1055000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1075000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs2[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  780000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  790000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  800000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  810000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  820000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  830000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  840000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  850000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  865000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  880000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  895000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  910000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  925000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  940000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  955000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  970000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  990000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1010000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1030000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1050000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs3[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  775000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  780000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  790000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  800000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  810000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  820000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  830000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  840000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  850000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  865000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  880000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  895000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  910000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  925000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  940000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  955000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  970000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  985000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1005000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1025000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs4[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  750000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  750000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  750000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  750000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  760000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  770000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  780000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  790000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  800000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  810000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  820000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  830000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  840000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  850000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  865000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  880000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  895000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  910000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  925000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  940000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  955000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  970000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  985000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1000000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs5[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  750000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  750000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  750000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  750000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  750000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  760000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  770000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  780000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  790000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  800000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  810000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  820000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  830000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  840000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  850000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  860000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  870000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  885000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  900000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  915000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  930000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  945000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  960000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19),  975000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs6[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  725000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  725000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  725000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  725000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  725000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  725000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  725000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  725000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  725000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  725000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  735000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  745000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  755000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  765000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  775000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  785000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  795000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  805000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  815000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  825000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  835000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  845000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  855000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  865000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  875000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  890000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  905000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  920000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  935000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19),  950000, 800},
+	{ 0, { 0 } }
+};
 
 static struct pvs_table pvs_v1[NUM_SPEED_BINS][NUM_PVS] __initdata = {
 	/* 8974v1 1.7GHz Parts */
@@ -974,45 +1396,45 @@
 };
 
 static struct pvs_table pvs_pro[NUM_SPEED_BINS][NUM_PVS] __initdata = {
-	/* Not used by 8974Pro */
-	[0][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+	/* 2.0 GHz is not used on 8974Pro */
+	[0][0] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
+	[0][1] = { acpu_freq_tbl_2g_pvs1, sizeof(acpu_freq_tbl_2g_pvs1) },
+	[0][2] = { acpu_freq_tbl_2g_pvs2, sizeof(acpu_freq_tbl_2g_pvs2) },
+	[0][3] = { acpu_freq_tbl_2g_pvs3, sizeof(acpu_freq_tbl_2g_pvs3) },
+	[0][4] = { acpu_freq_tbl_2g_pvs4, sizeof(acpu_freq_tbl_2g_pvs4) },
+	[0][5] = { acpu_freq_tbl_2g_pvs5, sizeof(acpu_freq_tbl_2g_pvs5) },
+	[0][6] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
+	[0][7] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
 
-	/* 8974Pro AB Bringup */
-	[1][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+	/* 8974Pro AB 2.3GHz */
+	[1][0] = { acpu_ftbl_pro_2p3g_pvs0, sizeof(acpu_ftbl_pro_2p3g_pvs0) },
+	[1][1] = { acpu_ftbl_pro_2p3g_pvs1, sizeof(acpu_ftbl_pro_2p3g_pvs1) },
+	[1][2] = { acpu_ftbl_pro_2p3g_pvs2, sizeof(acpu_ftbl_pro_2p3g_pvs2) },
+	[1][3] = { acpu_ftbl_pro_2p3g_pvs3, sizeof(acpu_ftbl_pro_2p3g_pvs3) },
+	[1][4] = { acpu_ftbl_pro_2p3g_pvs4, sizeof(acpu_ftbl_pro_2p3g_pvs4) },
+	[1][5] = { acpu_ftbl_pro_2p3g_pvs5, sizeof(acpu_ftbl_pro_2p3g_pvs5) },
+	[1][6] = { acpu_ftbl_pro_2p3g_pvs6, sizeof(acpu_ftbl_pro_2p3g_pvs6) },
+	[1][7] = { acpu_ftbl_pro_2p3g_pvs6, sizeof(acpu_ftbl_pro_2p3g_pvs6) },
 
-	/* Not used by 8974Pro */
-	[2][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+	/* 2.2GHz is not used on 8974Pro */
+	[2][0] = { acpu_freq_tbl_2p2g_pvs0, sizeof(acpu_freq_tbl_2p2g_pvs0) },
+	[2][1] = { acpu_freq_tbl_2p2g_pvs1, sizeof(acpu_freq_tbl_2p2g_pvs1) },
+	[2][2] = { acpu_freq_tbl_2p2g_pvs2, sizeof(acpu_freq_tbl_2p2g_pvs2) },
+	[2][3] = { acpu_freq_tbl_2p2g_pvs3, sizeof(acpu_freq_tbl_2p2g_pvs3) },
+	[2][4] = { acpu_freq_tbl_2p2g_pvs4, sizeof(acpu_freq_tbl_2p2g_pvs4) },
+	[2][5] = { acpu_freq_tbl_2p2g_pvs5, sizeof(acpu_freq_tbl_2p2g_pvs5) },
+	[2][6] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
+	[2][7] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
 
-	/* 8974Pro Bringup */
-	[3][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+	/* 8974Pro AC 2.5GHz */
+	[3][0] = { acpu_ftbl_pro_2p5g_pvs0, sizeof(acpu_ftbl_pro_2p5g_pvs0) },
+	[3][1] = { acpu_ftbl_pro_2p5g_pvs1, sizeof(acpu_ftbl_pro_2p5g_pvs1) },
+	[3][2] = { acpu_ftbl_pro_2p5g_pvs2, sizeof(acpu_ftbl_pro_2p5g_pvs2) },
+	[3][3] = { acpu_ftbl_pro_2p5g_pvs3, sizeof(acpu_ftbl_pro_2p5g_pvs3) },
+	[3][4] = { acpu_ftbl_pro_2p5g_pvs4, sizeof(acpu_ftbl_pro_2p5g_pvs4) },
+	[3][5] = { acpu_ftbl_pro_2p5g_pvs5, sizeof(acpu_ftbl_pro_2p5g_pvs5) },
+	[3][6] = { acpu_ftbl_pro_2p5g_pvs6, sizeof(acpu_ftbl_pro_2p5g_pvs6) },
+	[3][7] = { acpu_ftbl_pro_2p5g_pvs6, sizeof(acpu_ftbl_pro_2p5g_pvs6) },
 };
 
 static struct msm_bus_scale_pdata bus_scale_data __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index e3a3f54..ba162a1 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -61,8 +61,8 @@
 	u32 regval;
 
 	regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
-	regval &= ~0x3;
-	regval |= (pri_src_sel & 0x3);
+	regval &= ~(0x3 | (0x3 << 8));
+	regval |= pri_src_sel | (pri_src_sel << 8);
 	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
 	/* Wait for switch to complete. */
 	mb();
@@ -75,8 +75,8 @@
 	u32 regval;
 
 	regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
-	regval &= ~(0x3 << 2);
-	regval |= ((sec_src_sel & 0x3) << 2);
+	regval &= ~((0x3 << 2) | (0x3 << 10));
+	regval |= (sec_src_sel << 2) | (sec_src_sel << 10);
 	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
 	/* Wait for switch to complete. */
 	mb();
@@ -784,7 +784,7 @@
 
 	/* Set PRI_SRC_SEL_HFPLL_DIV2 divider to div-2. */
 	regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
-	regval &= ~(0x3 << 6);
+	regval &= ~(0x3 << 6 | 0x3 << 14);
 	set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
 
 	/* Enable and switch to the target clock source. */
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 78a73c4..ebb90af 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -57,7 +57,7 @@
 
 static struct gpiomux_setting synaptics_reset_sus_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_6MA,
+	.drv = GPIOMUX_DRV_2MA,
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
@@ -230,6 +230,184 @@
 	},
 };
 
+static struct gpiomux_setting gpio_nc_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting goodix_ldo_en_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting goodix_ldo_en_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting goodix_int_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting goodix_int_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting goodix_reset_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting goodix_reset_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config msm_qrd_blsp_configs[] __initdata = {
+	{
+		.gpio      = 2,		/* NC */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_nc_cfg,
+		},
+	},
+	{
+		.gpio      = 3,		/* NC */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_nc_cfg,
+		},
+	},
+	{
+		.gpio      = 4,		/* NC */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_nc_cfg,
+		},
+	},
+	{
+		.gpio      = 14,	/* NC */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_nc_cfg,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm_qrd_goodix_configs[] __initdata = {
+	{
+		.gpio = 15,		/* LDO EN */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &goodix_ldo_en_act_cfg,
+			[GPIOMUX_SUSPENDED] = &goodix_ldo_en_sus_cfg,
+		},
+	},
+	{
+		.gpio = 16,		/* RESET */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &goodix_reset_act_cfg,
+			[GPIOMUX_SUSPENDED] = &goodix_reset_sus_cfg,
+		},
+	},
+	{
+		.gpio = 17,		/* INT */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &goodix_int_act_cfg,
+			[GPIOMUX_SUSPENDED] = &goodix_int_sus_cfg,
+		},
+	},
+	{
+		.gpio      = 18,		/* BLSP1 QUP5 I2C_SDA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+	{
+		.gpio      = 19,		/* BLSP1 QUP5 I2C_SCL */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+};
+
+static struct gpiomux_setting nfc_ldo_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting nfc_ldo_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting nfc_regc_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting nfc_regc_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting nfc_wake_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting nfc_wake_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config msm_qrd_nfc_configs[] __initdata = {
+	{					/*  NFC  LDO EN */
+		.gpio      = 0,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &nfc_ldo_act_cfg,
+			[GPIOMUX_SUSPENDED] = &nfc_ldo_sus_cfg,
+		},
+	},
+	{					/*  NFC  REGC*/
+		.gpio      = 1,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &nfc_regc_act_cfg,
+			[GPIOMUX_SUSPENDED] = &nfc_regc_sus_cfg,
+		},
+	},
+	{					/*  NFC   WAKE */
+		.gpio      = 5,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &nfc_wake_act_cfg,
+			[GPIOMUX_SUSPENDED] = &nfc_wake_sus_cfg,
+		},
+	},
+	{					/*  NFC   */
+		.gpio      = 10,		/* BLSP1 QUP3 I2C_DAT */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+	{					/*  NFC   */
+		.gpio      = 11,		/* BLSP1 QUP3 I2C_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+		},
+	},
+};
+
 static struct gpiomux_setting sd_card_det_active_config = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_2MA,
@@ -571,13 +749,28 @@
 	msm_gpiomux_install(msm_keypad_configs,
 			ARRAY_SIZE(msm_keypad_configs));
 
-	msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+	if (of_board_is_qrd())
+		msm_gpiomux_install(msm_qrd_blsp_configs,
+			ARRAY_SIZE(msm_qrd_blsp_configs));
+	else
+		msm_gpiomux_install(msm_blsp_configs,
+			ARRAY_SIZE(msm_blsp_configs));
+
 	msm_gpiomux_install(wcnss_5wire_interface,
 				ARRAY_SIZE(wcnss_5wire_interface));
 
 	msm_gpiomux_install(&sd_card_det, 1);
-	msm_gpiomux_install(msm_synaptics_configs,
-			ARRAY_SIZE(msm_synaptics_configs));
+	if (of_board_is_qrd())
+		msm_gpiomux_install(msm_qrd_goodix_configs,
+				ARRAY_SIZE(msm_qrd_goodix_configs));
+	else
+		msm_gpiomux_install(msm_synaptics_configs,
+				ARRAY_SIZE(msm_synaptics_configs));
+
+	if (of_board_is_qrd())
+		msm_gpiomux_install(msm_qrd_nfc_configs,
+				ARRAY_SIZE(msm_qrd_nfc_configs));
+
 	msm_gpiomux_install_nowrite(msm_lcd_configs,
 			ARRAY_SIZE(msm_lcd_configs));
 	msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 01f1468..dc9c13d 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -422,14 +422,14 @@
 	{
 		.gpio = 18, /* FLASH_LED_EN */
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
 			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
 		},
 	},
 	{
 		.gpio = 19, /* FLASH_LED_NOW */
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_settings[0],
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
 			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
 		},
 	},
@@ -511,6 +511,62 @@
 	},
 };
 
+static struct gpiomux_setting interrupt_gpio_active = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting interrupt_gpio_suspend_pullup = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting interrupt_gpio_suspend_pulldown = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config msm_interrupt_configs[] __initdata = {
+	{
+		.gpio = 77,	/* NFC_IRQ */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &interrupt_gpio_active,
+			[GPIOMUX_SUSPENDED] = &interrupt_gpio_suspend_pullup,
+		},
+	},
+	{
+		.gpio = 78,	/*ETH_INT */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &interrupt_gpio_active,
+			[GPIOMUX_SUSPENDED] = &interrupt_gpio_suspend_pullup,
+		},
+	},
+	{
+		.gpio = 80,	/*ALSP_INT */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &interrupt_gpio_active,
+			[GPIOMUX_SUSPENDED] = &interrupt_gpio_suspend_pullup,
+		},
+	},
+	{
+		.gpio = 81,	/*ACCEL_INT1 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &interrupt_gpio_active,
+			[GPIOMUX_SUSPENDED] = &interrupt_gpio_suspend_pulldown,
+		},
+	},
+	{
+		.gpio = 82,	/*ACCEL_INT2 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &interrupt_gpio_active,
+			[GPIOMUX_SUSPENDED] = &interrupt_gpio_suspend_pulldown,
+		},
+	},
+};
+
 void __init msm8610_init_gpiomux(void)
 {
 	int rc;
@@ -539,4 +595,7 @@
 	msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
 	msm_gpiomux_install(msm_gpio_int_configs,
 			ARRAY_SIZE(msm_gpio_int_configs));
+	if (of_board_is_qrd())
+		msm_gpiomux_install(msm_interrupt_configs,
+			ARRAY_SIZE(msm_interrupt_configs));
 }
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 37567ed..f234712 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -75,7 +75,7 @@
 #include <linux/mfd/wcd9xxx/pdata.h>
 #endif
 
-#include <linux/smsc3503.h>
+#include <linux/smsc_hub.h>
 #include <linux/msm_ion.h>
 #include <mach/ion.h>
 #include <mach/mdm2.h>
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 8a79687..b72cdab 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -353,7 +353,6 @@
 #define GPLL1_N_VAL                                        (0x004C)
 #define GPLL1_USER_CTL                                     (0x0050)
 #define GPLL1_STATUS                                       (0x005C)
-#define PERIPH_NOC_AHB_CBCR                                (0x0184)
 #define NOC_CONF_XPU_AHB_CBCR                              (0x01C0)
 #define MMSS_NOC_CFG_AHB_CBCR                              (0x024C)
 #define MSS_CFG_AHB_CBCR                                   (0x0280)
@@ -1394,17 +1393,6 @@
 	},
 };
 
-static struct branch_clk gcc_periph_noc_ahb_clk = {
-	.cbcr_reg = PERIPH_NOC_AHB_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[GCC_BASE],
-	.c = {
-		.dbg_name = "gcc_periph_noc_ahb_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(gcc_periph_noc_ahb_clk.c),
-	},
-};
-
 static struct local_vote_clk gcc_prng_ahb_clk = {
 	.cbcr_reg = PRNG_AHB_CBCR,
 	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
@@ -1571,7 +1559,6 @@
 };
 
 static struct measure_mux_entry measure_mux_GCC[] = {
-	{ &gcc_periph_noc_ahb_clk.c,  GCC_BASE, 0x0010 },
 	{ &gcc_mss_cfg_ahb_clk.c,  GCC_BASE, 0x0030 },
 	{ &gcc_mss_q6_bimc_axi_clk.c,  GCC_BASE, 0x0031 },
 	{ &gcc_usb_hsic_ahb_clk.c,  GCC_BASE, 0x0058 },
@@ -3400,6 +3387,10 @@
 	/* eeprom clocks */
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6c.qcom,eeprom"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6c.qcom,eeprom"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "18.qcom,eeprom"),
+	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "18.qcom,eeprom"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6b.qcom,eeprom"),
+	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6b.qcom,eeprom"),
 
 	/* CCI clocks */
 	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 4fb3f43..92dab97 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -240,6 +240,7 @@
 #define                 GFX3D_CMD_RCGR	    0x4000
 #define               OXILI_GFX3D_CBCR	    0x4028
 #define                OXILI_GFX3D_BCR	    0x4030
+#define                 GMEM_GFX3D_BCR	    0x4040
 #define                  OXILI_AHB_BCR	    0x4044
 #define                 OXILI_AHB_CBCR	    0x403C
 #define                   AHB_CMD_RCGR	    0x5000
@@ -507,6 +508,7 @@
 static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(bimc_acpu_a_clk, &bimc_a_clk.c, LONG_MAX);
 
+static DEFINE_CLK_VOTER(pnoc_keepalive_a_clk, &pnoc_a_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(pnoc_iommu_clk, &pnoc_clk.c, LONG_MAX);
 
@@ -1549,7 +1551,6 @@
 	F_END,
 };
 
-static struct branch_clk mmss_mmssnoc_axi_clk;
 static struct rcg_clk axi_clk_src = {
 	.cmd_rcgr_reg = AXI_CMD_RCGR,
 	.set_rate = set_rate_hid,
@@ -1561,7 +1562,6 @@
 		.ops = &clk_ops_rcg,
 		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
 		CLK_INIT(axi_clk_src.c),
-		.depends = &mmss_mmssnoc_axi_clk.c
 	},
 };
 
@@ -2146,6 +2146,7 @@
 
 static struct branch_clk csi_vfe_clk = {
 	.cbcr_reg = CSI_VFE_CBCR,
+	.bcr_reg = CSI_VFE_BCR,
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
@@ -2216,6 +2217,7 @@
 
 static struct branch_clk gmem_gfx3d_clk = {
 	.cbcr_reg = GMEM_GFX3D_CBCR,
+	.bcr_reg = GMEM_GFX3D_BCR,
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
@@ -2261,6 +2263,7 @@
 	},
 };
 
+static struct branch_clk mmss_mmssnoc_axi_clk;
 static struct branch_clk mdp_axi_clk = {
 	.cbcr_reg = MDP_AXI_CBCR,
 	.base = &virt_bases[MMSS_BASE],
@@ -2271,6 +2274,7 @@
 		.dbg_name = "mdp_axi_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(mdp_axi_clk.c),
+		.depends = &mmss_mmssnoc_axi_clk.c,
 	},
 };
 
@@ -2326,6 +2330,7 @@
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
+		.parent = &axi_clk_src.c,
 		.dbg_name = "mmss_mmssnoc_axi_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(mmss_mmssnoc_axi_clk.c),
@@ -2341,6 +2346,7 @@
 		.dbg_name = "mmss_s0_axi_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(mmss_s0_axi_clk.c),
+		.depends = &mmss_mmssnoc_axi_clk.c,
 	},
 };
 
@@ -2357,6 +2363,7 @@
 
 static struct branch_clk oxili_ahb_clk = {
 	.cbcr_reg = OXILI_AHB_CBCR,
+	.bcr_reg = OXILI_AHB_BCR,
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
@@ -2368,6 +2375,7 @@
 
 static struct branch_clk oxili_gfx3d_clk = {
 	.cbcr_reg = OXILI_GFX3D_CBCR,
+	.bcr_reg = OXILI_GFX3D_BCR,
 	.has_sibling = 0,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
@@ -2380,6 +2388,7 @@
 
 static struct branch_clk vfe_clk = {
 	.cbcr_reg = VFE_CBCR,
+	.bcr_reg = VFE_BCR,
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
@@ -2392,6 +2401,7 @@
 
 static struct branch_clk vfe_ahb_clk = {
 	.cbcr_reg = VFE_AHB_CBCR,
+	.bcr_reg = VFE_AHB_BCR,
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
@@ -2403,6 +2413,7 @@
 
 static struct branch_clk vfe_axi_clk = {
 	.cbcr_reg = VFE_AXI_CBCR,
+	.bcr_reg = VFE_AXI_BCR,
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
 	 /* FIXME: Remove this once simulation is fixed. */
@@ -2412,6 +2423,7 @@
 		.dbg_name = "vfe_axi_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(vfe_axi_clk.c),
+		.depends = &mmss_mmssnoc_axi_clk.c,
 	},
 };
 
@@ -2767,7 +2779,7 @@
 	CLK_LOOKUP("core_clk",  gcc_blsp1_uart3_apps_clk.c, "f991f000.serial"),
 	CLK_LOOKUP("iface_clk",  gcc_blsp1_ahb_clk.c, "f991e000.serial"),
 	CLK_LOOKUP("core_clk",  gcc_blsp1_uart2_apps_clk.c, "f991e000.serial"),
-
+	CLK_LOOKUP("bus_clk", pnoc_keepalive_a_clk.c, ""),
 	CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "msm_sps"),
 
 	CLK_LOOKUP("bus_clk", snoc_clk.c, ""),
@@ -3132,6 +3144,14 @@
 	CLK_LOOKUP("iface_clk",    gcc_ce1_ahb_clk.c, "fd404000.qcom,qcrypto"),
 	CLK_LOOKUP("bus_clk",      gcc_ce1_axi_clk.c, "fd404000.qcom,qcrypto"),
 	CLK_LOOKUP("core_clk_src", ce1_clk_src.c,     "fd404000.qcom,qcrypto"),
+
+	/* GDSC clocks */
+	CLK_LOOKUP("core_clk", vfe_clk.c,	"fd8c36a4.qcom,gdsc"),
+	CLK_LOOKUP("iface_clk", vfe_ahb_clk.c,	"fd8c36a4.qcom,gdsc"),
+	CLK_LOOKUP("bus_clk",  vfe_axi_clk.c,	"fd8c36a4.qcom,gdsc"),
+	CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fd8c4034.qcom,gdsc"),
+	CLK_LOOKUP("iface_clk", oxili_ahb_clk.c, "fd8c4034.qcom,gdsc"),
+	CLK_LOOKUP("mem_clk", gmem_gfx3d_clk.c, "fd8c4034.qcom,gdsc"),
 };
 
 static struct clk_lookup msm_clocks_8610_rumi[] = {
@@ -3229,8 +3249,11 @@
 	 * to remain on whenever CPUs aren't power collapsed.
 	 */
 	clk_prepare_enable(&gcc_xo_a_clk_src.c);
-
-
+	/*
+	 * Hold an active set vote for the PNOC AHB source. Sleep set vote is 0.
+	 */
+	clk_set_rate(&pnoc_keepalive_a_clk.c, 19200000);
+	clk_prepare_enable(&pnoc_keepalive_a_clk.c);
 	/* Set rates for single-rate clocks. */
 	clk_set_rate(&usb_hs_system_clk_src.c,
 			usb_hs_system_clk_src.freq_tbl[0].freq_hz);
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index b7852fe..4488869 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -549,19 +549,21 @@
 	u32 cbcr_val;
 	unsigned long irq_flags;
 	struct branch_clk *branch = to_branch_clk(c);
-	int ret = 0;
+	int delay_us = 0, ret = 0;
 
 	spin_lock_irqsave(&local_clock_reg_lock, irq_flags);
 	cbcr_val = readl_relaxed(CBCR_REG(branch));
 	switch (flags) {
 	case CLKFLAG_RETAIN_PERIPH:
 		cbcr_val |= BIT(13);
+		delay_us = 1;
 		break;
 	case CLKFLAG_NORETAIN_PERIPH:
 		cbcr_val &= ~BIT(13);
 		break;
 	case CLKFLAG_RETAIN_MEM:
 		cbcr_val |= BIT(14);
+		delay_us = 1;
 		break;
 	case CLKFLAG_NORETAIN_MEM:
 		cbcr_val &= ~BIT(14);
@@ -570,17 +572,11 @@
 		ret = -EINVAL;
 	}
 	writel_relaxed(cbcr_val, CBCR_REG(branch));
-	/*
-	 * 8974v2.2 has a requirement that writes to set bits 13 and 14 are
-	 * separated by at least 2 bus cycles. Cover one of these cycles by
-	 * performing an extra write here. The other cycle is covered by the
-	 * read-modify-write design of this function.
-	 */
-	writel_relaxed(cbcr_val, CBCR_REG(branch));
-	spin_unlock_irqrestore(&local_clock_reg_lock, irq_flags);
-
-	/* Make sure write is issued before returning. */
+	/* Make sure power is enabled before returning. */
 	mb();
+	udelay(delay_us);
+
+	spin_unlock_irqrestore(&local_clock_reg_lock, irq_flags);
 
 	return ret;
 }
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index 60a62ec..b69b155 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -28,6 +28,7 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/cpr-regulator.h>
+#include <mach/scm.h>
 
 /* Register Offsets for RB-CPR and Bit Definitions */
 
@@ -153,6 +154,9 @@
 	u32		pvs_bin;
 	u32		process;
 
+	/* Control parameter to read efuse parameters by trustzone API */
+	bool		use_tz_api;
+
 	/* APC voltage regulator */
 	struct regulator	*vdd_apc;
 
@@ -223,6 +227,45 @@
 			pr_debug(message, ##__VA_ARGS__); \
 	} while (0)
 
+
+static u64 cpr_read_efuse_row(struct cpr_regulator *cpr_vreg, u32 row_num)
+{
+	int rc;
+	u64 efuse_bits;
+	struct cpr_read_req {
+		u32 row_address;
+		int addr_type;
+	} req;
+
+	struct cpr_read_rsp {
+		u32 row_data[2];
+		u32 status;
+	} rsp;
+
+	if (cpr_vreg->use_tz_api != true) {
+		efuse_bits = readll_relaxed(cpr_vreg->efuse_base
+			+ row_num * BYTES_PER_FUSE_ROW);
+		return efuse_bits;
+	}
+
+	req.row_address = cpr_vreg->efuse_addr + row_num * BYTES_PER_FUSE_ROW;
+	req.addr_type = 0;
+	efuse_bits = 0;
+
+	rc = scm_call(SCM_SVC_FUSE, SCM_FUSE_READ,
+			&req, sizeof(req), &rsp, sizeof(rsp));
+
+	if (rc) {
+		pr_err("read row %d failed, err code = %d", row_num, rc);
+	} else {
+		efuse_bits = ((u64)(rsp.row_data[1]) << 32) +
+				(u64)rsp.row_data[0];
+	}
+
+	return efuse_bits;
+}
+
+
 static bool cpr_is_allowed(struct cpr_regulator *cpr_vreg)
 {
 	if (cpr_vreg->cpr_fuse_disable || !cpr_enable)
@@ -933,18 +976,17 @@
 static int __devinit cpr_is_fuse_redundant(struct cpr_regulator *cpr_vreg,
 					 u32 redun_sel[4])
 {
-	u32 fuse_bits;
+	u64 fuse_bits;
 	int redundant;
 
-	fuse_bits = readl_relaxed(cpr_vreg->efuse_base
-				  + redun_sel[0] * BYTES_PER_FUSE_ROW);
+	fuse_bits = cpr_read_efuse_row(cpr_vreg, redun_sel[0]);
 	fuse_bits = (fuse_bits >> redun_sel[1]) & ((1 << redun_sel[2]) - 1);
 	if (fuse_bits == redun_sel[3])
 		redundant = 1;
 	else
 		redundant = 0;
 
-	pr_info("[row:%d] = 0x%x @%d:%d = %d?: redundant=%d\n",
+	pr_info("[row:%d] = 0x%llx @%d:%d = %d?: redundant=%d\n",
 		redun_sel[0], fuse_bits,
 		redun_sel[1], redun_sel[2], redun_sel[3], redundant);
 	return redundant;
@@ -954,7 +996,7 @@
 			       struct cpr_regulator *cpr_vreg)
 {
 	struct device_node *of_node = pdev->dev.of_node;
-	u32 efuse_bits;
+	u64 efuse_bits;
 	int rc, process;
 	u32 pvs_fuse[3], pvs_fuse_redun_sel[4];
 	bool redundant;
@@ -986,8 +1028,8 @@
 	}
 
 	/* Construct PVS process # from the efuse bits */
-	efuse_bits = readl_relaxed(cpr_vreg->efuse_base +
-				   pvs_fuse[0] * BYTES_PER_FUSE_ROW);
+
+	efuse_bits = cpr_read_efuse_row(cpr_vreg, pvs_fuse[0]);
 	cpr_vreg->pvs_bin = (efuse_bits >> pvs_fuse[1]) &
 				   ((1 << pvs_fuse[2]) - 1);
 
@@ -1001,7 +1043,7 @@
 	}
 
 	process = cpr_vreg->pvs_bin_process[cpr_vreg->pvs_bin];
-	pr_info("[row:%d] = 0x%08X, n_bits=%d, bin=%d (%d)\n",
+	pr_info("[row:%d] = 0x%llX, n_bits=%d, bin=%d (%d)\n",
 		pvs_fuse[0], efuse_bits, pvs_fuse[2],
 		cpr_vreg->pvs_bin, process);
 
@@ -1147,8 +1189,7 @@
 	}
 
 	/* Read the control bits of eFuse */
-	fuse_bits = readll_relaxed(cpr_vreg->efuse_base
-				   + cpr_fuse_row * BYTES_PER_FUSE_ROW);
+	fuse_bits = cpr_read_efuse_row(cpr_vreg, cpr_fuse_row);
 	pr_info("[row:%d] = 0x%llx\n", cpr_fuse_row, fuse_bits);
 
 	if (redundant) {
@@ -1175,8 +1216,8 @@
 					  &temp_row, rc);
 			if (rc)
 				return rc;
-			fuse_bits_2 = readll_relaxed(cpr_vreg->efuse_base
-					+ temp_row * BYTES_PER_FUSE_ROW);
+
+			fuse_bits_2 = cpr_read_efuse_row(cpr_vreg, temp_row);
 			pr_info("[original row:%d] = 0x%llx\n",
 				temp_row, fuse_bits_2);
 		}
@@ -1391,6 +1432,7 @@
 		pr_err("efuse_addr missing: res=%p\n", res);
 		return -EINVAL;
 	}
+
 	cpr_vreg->efuse_addr = res->start;
 	len = res->end - res->start + 1;
 
@@ -1402,6 +1444,12 @@
 				cpr_vreg->efuse_addr);
 		return -EINVAL;
 	}
+
+	if (of_property_read_bool(pdev->dev.of_node, "qcom,use-tz-api"))
+		cpr_vreg->use_tz_api = true;
+	else
+		cpr_vreg->use_tz_api = false;
+
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 4daccb1..2fd1bf3 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -2634,11 +2634,12 @@
 
 static struct msm_rpm_master_stats_platform_data msm_rpm_master_stat_pdata = {
 	.masters = master_names,
-	.nomasters = ARRAY_SIZE(master_names),
+	.num_masters = ARRAY_SIZE(master_names),
+	.master_offset = 32,
 };
 
 struct platform_device apq8064_rpm_master_stat_device = {
-	.name = "msm_rpm_master_stat",
+	.name = "msm_rpm_master_stats",
 	.id = -1,
 	.num_resources	= ARRAY_SIZE(resources_rpm_master_stats),
 	.resource	= resources_rpm_master_stats,
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index e2a57f9..c4fe0df 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -610,11 +610,12 @@
 
 static struct msm_rpm_master_stats_platform_data msm_rpm_master_stat_pdata = {
 	.masters = master_names,
-	.nomasters = ARRAY_SIZE(master_names),
+	.num_masters = ARRAY_SIZE(master_names),
+	.master_offset = 32,
 };
 
 struct platform_device msm8930_rpm_master_stat_device = {
-	.name = "msm_rpm_master_stat",
+	.name = "msm_rpm_master_stats",
 	.id = -1,
 	.num_resources	= ARRAY_SIZE(resources_rpm_master_stats),
 	.resource	= resources_rpm_master_stats,
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 71f58a6..6664e17 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -4018,11 +4018,12 @@
 
 static struct msm_rpm_master_stats_platform_data msm_rpm_master_stat_pdata = {
 	.masters = master_names,
-	.nomasters = ARRAY_SIZE(master_names),
+	.num_masters = ARRAY_SIZE(master_names),
+	.master_offset = 32,
 };
 
 struct platform_device msm8960_rpm_master_stat_device = {
-	.name = "msm_rpm_master_stat",
+	.name = "msm_rpm_master_stats",
 	.id = -1,
 	.num_resources	= ARRAY_SIZE(resources_rpm_master_stats),
 	.resource	= resources_rpm_master_stats,
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 483d8b3..6a48646 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -1431,11 +1431,12 @@
 
 static struct msm_rpm_master_stats_platform_data msm_rpm_master_stat_pdata = {
 	.masters = master_names,
-	.nomasters = ARRAY_SIZE(master_names),
+	.num_masters = ARRAY_SIZE(master_names),
+	.master_offset = 32,
 };
 
 struct platform_device msm9615_rpm_master_stat_device = {
-	.name = "msm_rpm_master_stat",
+	.name = "msm_rpm_master_stats",
 	.id = -1,
 	.num_resources	= ARRAY_SIZE(resources_rpm_master_stats),
 	.resource	= resources_rpm_master_stats,
diff --git a/arch/arm/mach-msm/early_random.c b/arch/arm/mach-msm/early_random.c
new file mode 100644
index 0000000..e315b86
--- /dev/null
+++ b/arch/arm/mach-msm/early_random.c
@@ -0,0 +1,83 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+
+#include <mach/scm.h>
+
+#include <asm/io.h>
+#include <asm/cacheflush.h>
+
+#define TZ_SVC_CRYPTO	10
+#define PRNG_CMD_ID	0x01
+
+static int use_arch_random = 1;
+struct tz_prng_data {
+	uint8_t		*out_buf;
+	uint32_t	out_buf_sz;
+} __packed;
+
+DEFINE_SCM_BUFFER(common_scm_buf)
+DEFINE_MUTEX(arch_random_lock);
+#define RANDOM_BUFFER_SIZE	PAGE_SIZE
+char random_buffer[RANDOM_BUFFER_SIZE] __aligned(PAGE_SIZE);
+
+int arch_get_random_common(void *v, size_t size)
+{
+	struct tz_prng_data data;
+	int ret;
+	u32 resp;
+
+	if (!use_arch_random)
+		return 0;
+
+	if (size > sizeof(random_buffer))
+		return 0;
+
+	mutex_lock(&arch_random_lock);
+	data.out_buf = (uint8_t *) virt_to_phys(random_buffer);
+	data.out_buf_sz = size;
+
+	ret = scm_call_noalloc(TZ_SVC_CRYPTO, PRNG_CMD_ID, &data,
+			sizeof(data), &resp, sizeof(resp),
+			common_scm_buf, SCM_BUFFER_SIZE(common_scm_buf));
+	if (!ret) {
+		dmac_inv_range(random_buffer, random_buffer +
+						RANDOM_BUFFER_SIZE);
+		outer_inv_range(
+			(unsigned long) virt_to_phys(random_buffer),
+			(unsigned long) virt_to_phys(random_buffer) +
+						RANDOM_BUFFER_SIZE);
+		memcpy(v, random_buffer, size);
+	}
+	mutex_unlock(&arch_random_lock);
+	return !ret;
+}
+
+int arch_get_random_long(unsigned long *v)
+{
+	return arch_get_random_common(v, sizeof(unsigned long));
+}
+
+int arch_get_random_int(unsigned int *v)
+{
+	return arch_get_random_common(v, sizeof(unsigned int));
+}
+
+int arch_random_init(void)
+{
+	use_arch_random = 0;
+
+	return 0;
+}
+module_init(arch_random_init);
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
index 774548c..ea4865d 100644
--- a/arch/arm/mach-msm/gdsc.c
+++ b/arch/arm/mach-msm/gdsc.c
@@ -111,6 +111,13 @@
 	uint32_t regval;
 	int i, ret = 0;
 
+	for (i = sc->clock_count-1; i >= 0; i--) {
+		if (sc->toggle_mem)
+			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+		if (sc->toggle_periph)
+			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
+	}
+
 	if (sc->toggle_logic) {
 		regval = readl_relaxed(sc->gdscr);
 		regval |= SW_COLLAPSE_MASK;
@@ -123,18 +130,11 @@
 			dev_err(&rdev->dev, "%s disable timed out\n",
 				sc->rdesc.name);
 	} else {
-		for (i = 0; i < sc->clock_count; i++)
+		for (i = sc->clock_count-1; i >= 0; i--)
 			clk_reset(sc->clocks[i], CLK_RESET_ASSERT);
 		sc->resets_asserted = true;
 	}
 
-	for (i = 0; i < sc->clock_count; i++) {
-		if (sc->toggle_mem)
-			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
-		if (sc->toggle_periph)
-			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
-	}
-
 	return ret;
 }
 
@@ -225,20 +225,9 @@
 
 	retain_mem = of_property_read_bool(pdev->dev.of_node,
 					    "qcom,retain-mem");
+	sc->toggle_mem = !retain_mem;
 	retain_periph = of_property_read_bool(pdev->dev.of_node,
 					    "qcom,retain-periph");
-	for (i = 0; i < sc->clock_count; i++) {
-		if (retain_mem || (regval & PWR_ON_MASK))
-			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
-		else
-			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
-
-		if (retain_periph || (regval & PWR_ON_MASK))
-			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
-		else
-			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
-	}
-	sc->toggle_mem = !retain_mem;
 	sc->toggle_periph = !retain_periph;
 	sc->toggle_logic = !of_property_read_bool(pdev->dev.of_node,
 						"qcom,skip-logic-collapse");
@@ -255,6 +244,18 @@
 		}
 	}
 
+	for (i = 0; i < sc->clock_count; i++) {
+		if (retain_mem || (regval & PWR_ON_MASK))
+			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
+		else
+			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+
+		if (retain_periph || (regval & PWR_ON_MASK))
+			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
+		else
+			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
+	}
+
 	sc->rdev = regulator_register(&sc->rdesc, &pdev->dev, init_data, sc,
 				      pdev->dev.of_node);
 	if (IS_ERR(sc->rdev)) {
diff --git a/arch/arm/mach-msm/include/mach/camera2.h b/arch/arm/mach-msm/include/mach/camera2.h
index 887c594..a9da79e 100644
--- a/arch/arm/mach-msm/include/mach/camera2.h
+++ b/arch/arm/mach-msm/include/mach/camera2.h
@@ -114,6 +114,7 @@
 
 struct eeprom_memory_map_t {
 	struct eeprom_map_t page;
+	struct eeprom_map_t pageen;
 	struct eeprom_map_t poll;
 	struct eeprom_map_t mem;
 };
diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h
index bfcce73..45be31f 100644
--- a/arch/arm/mach-msm/include/mach/gpio.h
+++ b/arch/arm/mach-msm/include/mach/gpio.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
  * Author: Mike Lockwood <lockwood@android.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -188,6 +188,7 @@
 	TLMM_PULL_SDC1_CLK,
 	TLMM_PULL_SDC1_CMD,
 	TLMM_PULL_SDC1_DATA,
+	TLMM_PULL_SDC1_RCLK,
 };
 
 #if defined(CONFIG_GPIO_MSM_V2) || defined(CONFIG_GPIO_MSM_V3)
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index 2653ae4..cd07662 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -316,6 +316,15 @@
  */
 int __init msm_smd_init(void);
 
+/**
+ * smd_remote_ss_to_edge() - return edge type from remote ss type
+ * @name:	remote subsystem name
+ *
+ * Returns the edge type connected between the local subsystem(APPS)
+ * and remote subsystem @name.
+ */
+int smd_remote_ss_to_edge(const char *name);
+
 #else
 
 static inline int smd_open(const char *name, smd_channel_t **ch, void *priv,
@@ -447,6 +456,11 @@
 {
 	return 0;
 }
+
+static inline int smd_remote_ss_to_edge(const char *name)
+{
+	return -EINVAL;
+}
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smem.h b/arch/arm/mach-msm/include/mach/msm_smem.h
index a121791..5556db9 100644
--- a/arch/arm/mach-msm/include/mach/msm_smem.h
+++ b/arch/arm/mach-msm/include/mach/msm_smem.h
@@ -27,7 +27,6 @@
 };
 
 #define SMEM_NUM_SMD_STREAM_CHANNELS        64
-#define SMEM_NUM_SMD_BLOCK_CHANNELS         64
 
 enum {
 	/* fixed items */
@@ -87,13 +86,13 @@
 	SMEM_ID_VENDOR1,
 	SMEM_ID_VENDOR2,
 	SMEM_HW_SW_BUILD_ID,
-	SMEM_SMD_BLOCK_PORT_BASE_ID,
-	SMEM_SMD_BLOCK_PORT_PROC0_HEAP = SMEM_SMD_BLOCK_PORT_BASE_ID +
-						SMEM_NUM_SMD_BLOCK_CHANNELS,
-	SMEM_SMD_BLOCK_PORT_PROC1_HEAP = SMEM_SMD_BLOCK_PORT_PROC0_HEAP +
-						SMEM_NUM_SMD_BLOCK_CHANNELS,
-	SMEM_I2C_MUTEX = SMEM_SMD_BLOCK_PORT_PROC1_HEAP +
-						SMEM_NUM_SMD_BLOCK_CHANNELS,
+	SMEM_SMD_BASE_ID_2,
+	SMEM_SMD_FIFO_BASE_ID_2 = SMEM_SMD_BASE_ID_2 +
+						SMEM_NUM_SMD_STREAM_CHANNELS,
+	SMEM_CHANNEL_ALLOC_TBL_2 = SMEM_SMD_FIFO_BASE_ID_2 +
+						SMEM_NUM_SMD_STREAM_CHANNELS,
+	SMEM_I2C_MUTEX = SMEM_CHANNEL_ALLOC_TBL_2 +
+						SMEM_NUM_SMD_STREAM_CHANNELS,
 	SMEM_SCLK_CONVERSION,
 	SMEM_SMD_SMSM_INTR_MUX,
 	SMEM_SMSM_CPU_INTR_MASK,
diff --git a/arch/arm/mach-msm/include/mach/qpnp-int.h b/arch/arm/mach-msm/include/mach/qpnp-int.h
index 2b86216..1f31ea5 100644
--- a/arch/arm/mach-msm/include/mach/qpnp-int.h
+++ b/arch/arm/mach-msm/include/mach/qpnp-int.h
@@ -71,6 +71,28 @@
  */
 int qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
 		       struct qpnp_irq_spec *spec);
+
+/**
+ * qpnpint_show_irq - Prints the Linux interrupt number
+ *
+ * Pass a PMIC Arbiter interrupt to Linux.
+ */
+int qpnpint_show_irq(struct spmi_controller *spmi_ctrl,
+		       struct qpnp_irq_spec *spec);
+
+#ifdef CONFIG_MSM_SHOW_RESUME_IRQ
+extern int msm_show_resume_irq_mask;
+static inline bool qpnpint_show_resume_irq(void)
+{
+	return msm_show_resume_irq_mask;
+}
+#else
+static inline bool qpnpint_show_resume_irq(void)
+{
+	return false;
+}
+#endif
+
 #else
 static inline int __init qpnpint_of_init(struct device_node *node,
 				  struct device_node *parent)
@@ -97,5 +119,15 @@
 {
 	return -ENXIO;
 }
+int qpnpint_show_irq(struct spmi_controller *spmi_ctrl,
+		       struct qpnp_irq_spec *spec)
+{
+	return -ENXIO;
+}
+
+static inline bool qpnpint_show_resume_irq(void)
+{
+	return false;
+}
 #endif /* CONFIG_MSM_QPNP_INT */
 #endif /* QPNPINT_H */
diff --git a/arch/arm/mach-msm/include/mach/scm.h b/arch/arm/mach-msm/include/mach/scm.h
index 4186603..9d186ce 100644
--- a/arch/arm/mach-msm/include/mach/scm.h
+++ b/arch/arm/mach-msm/include/mach/scm.h
@@ -26,10 +26,24 @@
 #define SCM_SVC_ES			0x10
 #define SCM_SVC_TZSCHEDULER		0xFC
 
+#define SCM_FUSE_READ			0x7
+
+#define DEFINE_SCM_BUFFER(__n) \
+static char __n[PAGE_SIZE] __aligned(PAGE_SIZE);
+
+#define SCM_BUFFER_SIZE(__buf)	sizeof(__buf)
+
+#define SCM_BUFFER_PHYS(__buf)	virt_to_phys(__buf)
+
 #ifdef CONFIG_MSM_SCM
 extern int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
 		void *resp_buf, size_t resp_len);
 
+extern int scm_call_noalloc(u32 svc_id, u32 cmd_id, const void *cmd_buf,
+		size_t cmd_len, void *resp_buf, size_t resp_len,
+		void *scm_buf, size_t scm_buf_size);
+
+
 extern s32 scm_call_atomic1(u32 svc, u32 cmd, u32 arg1);
 extern s32 scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2);
 extern s32 scm_call_atomic3(u32 svc, u32 cmd, u32 arg1, u32 arg2, u32 arg3);
@@ -50,6 +64,13 @@
 	return 0;
 }
 
+static inline int scm_call_noalloc(u32 svc_id, u32 cmd_id,
+		const void *cmd_buf, size_t cmd_len, void *resp_buf,
+		size_t resp_len, void *scm_buf, size_t scm_buf_size)
+{
+	return 0;
+}
+
 static inline s32 scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
 {
 	return 0;
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 863a2d7..6fe945c 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -1350,7 +1350,7 @@
 	struct msm_ipc_router_xprt_info *xprt_info)
 {
 	int i;
-	struct msm_ipc_routing_table_entry *rt_entry;
+	struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
 
 	if (!xprt_info) {
 		pr_err("%s: Invalid xprt_info\n", __func__);
@@ -1360,7 +1360,8 @@
 	down_write(&server_list_lock_lha2);
 	down_write(&routing_table_lock_lha3);
 	for (i = 0; i < RT_HASH_SIZE; i++) {
-		list_for_each_entry(rt_entry, &routing_table[i], list) {
+		list_for_each_entry_safe(rt_entry, tmp_rt_entry,
+					 &routing_table[i], list) {
 			down_write(&rt_entry->lock_lha4);
 			if (rt_entry->xprt_info != xprt_info) {
 				up_write(&rt_entry->lock_lha4);
@@ -1369,6 +1370,8 @@
 			cleanup_rmt_ports(xprt_info, rt_entry);
 			rt_entry->xprt_info = NULL;
 			up_write(&rt_entry->lock_lha4);
+			list_del(&rt_entry->list);
+			kfree(rt_entry);
 		}
 	}
 	up_write(&routing_table_lock_lha3);
diff --git a/arch/arm/mach-msm/krait-regulator-pmic.c b/arch/arm/mach-msm/krait-regulator-pmic.c
new file mode 100644
index 0000000..5081e7b
--- /dev/null
+++ b/arch/arm/mach-msm/krait-regulator-pmic.c
@@ -0,0 +1,403 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"PMIC PDN %s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/spmi.h>
+#include <linux/delay.h>
+
+#define KRAIT_REG_PMIC_DEV_NAME "qcom,krait-regulator-pmic"
+
+#define REG_DIG_MAJOR		0x01
+#define REG_DIG_MINOR		0x00
+
+#define REG_PERPH_TYPE		0x04
+#define CTRL_TYPE_VAL		0x1C
+#define PS_TYPE_VAL		0x1C
+#define FREQ_TYPE_VAL		0x1D
+
+#define REG_PERPH_SUBTYPE	0x05
+#define CTRL_SUBTYPE_VAL	0x08
+#define PS_SUBTYPE_VAL		0x01
+#define FREQ_SUBTYPE_VAL	0x19
+
+#define REG_V_CTL1		0x40
+#define V_CTL1_VAL		0x00
+
+#define REG_MODE_CTL		0x45
+#define NPM_MODE_BIT		BIT(7)
+#define AUTO_MODE_BIT		BIT(6)
+
+#define REG_EN_CTL		0x46
+#define EN_BIT			BIT(7)
+
+#define REG_PD_CTL		0x48
+#define PD_CTL_VAL		0x08
+
+#define REG_MULTIPHASE_CTL	0x51
+#define MULTIPHASE_EN_BIT	BIT(7)
+
+#define REG_PHASE_CTL		0x52
+#define BALANCE_EN_BIT		BIT(7)
+
+#define REG_VS_CTL		0x61
+#define VS_CTL_VAL		0x85
+
+#define REG_GANG_CTL2		0xC1
+#define GANG_EN_BIT		BIT(7)
+
+#define REG_PWM_CL			0x60
+
+struct krait_vreg_pmic_chip {
+	struct spmi_device	*spmi;
+	u16			ctrl_base;
+	u16			ps_base;
+	u16			freq_base;
+	u8			ctrl_dig_major;
+	u8			ctrl_dig_minor;
+};
+
+static struct krait_vreg_pmic_chip *the_chip;
+
+static struct of_device_id krait_vreg_pmic_match_table[] = {
+	{ .compatible = KRAIT_REG_PMIC_DEV_NAME },
+	{}
+};
+
+static int read_byte(struct spmi_device *spmi, u16 addr, u8 *val)
+{
+	int rc;
+
+	rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, addr, val, 1);
+	if (rc) {
+		pr_err("SPMI read failed [%d,0x%04x] rc=%d\n",
+							spmi->sid, addr, rc);
+		return rc;
+	}
+	return 0;
+}
+
+static int write_byte(struct spmi_device *spmi, u16 addr, u8 *val)
+{
+	int rc;
+
+	rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid, addr, val, 1);
+	if (rc) {
+		pr_err("SPMI write failed [%d,0x%04x] val = 0x%02x rc=%d\n",
+						spmi->sid, addr, *val, rc);
+		return rc;
+	}
+	return 0;
+}
+
+#define ISTEP_MA			500
+#define IOFFSET_MA			1000
+#define OVERSHOOT_DIG_MAJOR		1
+#define OVERSHOOT_DIG_MINOR		1
+static bool v_overshoot_fixed(void)
+{
+	if (the_chip->ctrl_dig_major > OVERSHOOT_DIG_MAJOR
+		|| (the_chip->ctrl_dig_major == OVERSHOOT_DIG_MAJOR
+		&& the_chip->ctrl_dig_minor > OVERSHOOT_DIG_MINOR)) {
+		pr_debug("fixed in h/w\n");
+		return true;
+	}
+	return false;
+}
+
+/**
+ * krait_pmic_is_ready - function to check if the driver is initialized
+ *
+ * CONTEXT: Can be called in atomic context
+ *
+ * RETURNS: true if this driver has initialized, false otherwise
+ */
+bool krait_pmic_is_ready(void)
+{
+	if (the_chip == NULL) {
+		pr_debug("kait_regulator_pmic not ready yet\n");
+		return false;
+	}
+	return true;
+}
+EXPORT_SYMBOL(krait_pmic_is_ready);
+
+#define I_PFM_MA		2000
+
+/**
+ * krait_pmic_post_pfm_entry - workarounds after entering pfm mode
+ *
+ * CONTEXT: Can be called in atomic context
+ *
+ * RETURNS: 0 on success, error code on failure
+ */
+int krait_pmic_post_pfm_entry(void)
+{
+	u8 setpoint;
+	int rc;
+
+	if (the_chip == NULL) {
+		pr_debug("kait_regulator_pmic not ready yet\n");
+		return -ENXIO;
+	}
+
+	if (v_overshoot_fixed())
+		return 0;
+
+	setpoint = (I_PFM_MA - IOFFSET_MA) / ISTEP_MA;
+	rc = write_byte(the_chip->spmi,
+			the_chip->ps_base + REG_PWM_CL, &setpoint);
+	pr_debug("wrote 0x%02x->[%d 0x%04x] rc = %d\n", setpoint,
+			the_chip->spmi->sid,
+			the_chip->ps_base + REG_PWM_CL, rc);
+	return rc;
+}
+EXPORT_SYMBOL(krait_pmic_post_pfm_entry);
+
+#define I_PWM_MA		3500
+/**
+ * krait_pmic_post_pwm_entry - workarounds after entering pwm mode
+ *
+ * CONTEXT: Can be called in atomic context
+ *
+ * RETURNS: 0 on success, error code on failure
+ */
+int krait_pmic_post_pwm_entry(void)
+{
+	u8 setpoint;
+	int rc;
+
+	if (the_chip == NULL) {
+		pr_debug("kait_regulator_pmic not ready yet\n");
+		return -ENXIO;
+	}
+
+	if (v_overshoot_fixed())
+		return 0;
+
+	udelay(50);
+	setpoint = (I_PWM_MA - IOFFSET_MA) / ISTEP_MA;
+
+	rc = write_byte(the_chip->spmi,
+			the_chip->ps_base + REG_PWM_CL, &setpoint);
+	pr_debug("wrote 0x%02x->[%d 0x%04x] rc = %d\n", setpoint,
+			the_chip->spmi->sid,
+			the_chip->ps_base + REG_PWM_CL, rc);
+	return rc;
+}
+EXPORT_SYMBOL(krait_pmic_post_pwm_entry);
+
+#define READ_BYTE(chip, addr, val, rc)				\
+do {								\
+	rc = read_byte(chip->spmi, (addr), &val);		\
+	if (rc)						\
+		pr_err("register read failed rc=%d\n", rc);	\
+} while (0)
+
+#define GANGED_VREG_COUNT	4
+static int gang_configuration_check(struct krait_vreg_pmic_chip *chip)
+{
+	u8 val;
+	int rc;
+	int i;
+
+	return 0;
+
+	READ_BYTE(chip, chip->ctrl_base + REG_V_CTL1, val, rc);
+	if (rc)
+		return rc;
+	BUG_ON(val != V_CTL1_VAL);
+
+	READ_BYTE(chip, chip->ctrl_base + REG_MODE_CTL, val, rc);
+	if (rc)
+		return rc;
+	/* The Auto mode should be off */
+	BUG_ON(val & AUTO_MODE_BIT);
+	/* The NPM mode should be on */
+	BUG_ON(!(val & NPM_MODE_BIT));
+
+	READ_BYTE(chip, chip->ctrl_base + REG_EN_CTL, val, rc);
+	if (rc)
+		return rc;
+	/* The en bit should be set */
+	BUG_ON(val & EN_BIT);
+
+	READ_BYTE(chip, chip->ctrl_base + REG_PD_CTL, val, rc);
+	if (rc)
+		return rc;
+	BUG_ON(val != PD_CTL_VAL);
+
+	READ_BYTE(chip, chip->ctrl_base + REG_MULTIPHASE_CTL, val, rc);
+	if (rc)
+		return rc;
+	BUG_ON(!(val & MULTIPHASE_EN_BIT));
+
+	READ_BYTE(chip, chip->ctrl_base + REG_PHASE_CTL, val, rc);
+	if (rc)
+		return rc;
+	BUG_ON(!(val & BALANCE_EN_BIT));
+
+	READ_BYTE(chip, chip->ctrl_base + REG_VS_CTL, val, rc);
+	if (rc)
+		return rc;
+	BUG_ON(val != VS_CTL_VAL);
+
+	for (i = 0; i < GANGED_VREG_COUNT; i++) {
+		READ_BYTE(chip,
+			chip->ctrl_base + i * 0x300 + REG_GANG_CTL2, val, rc);
+		if (rc)
+			return rc;
+
+		if (!(val & GANG_EN_BIT)) {
+			pr_err("buck = %d, ctrl gang not enabled\n", i);
+			BUG();
+		}
+	}
+
+	for (i = 0; i < GANGED_VREG_COUNT; i++) {
+		READ_BYTE(chip,
+			chip->ps_base + i * 0x300 + REG_GANG_CTL2, val, rc);
+		if (rc)
+			return rc;
+
+		if (!(val & GANG_EN_BIT)) {
+			pr_err("buck = %d, ps gang not enabled\n", i);
+			BUG();
+		}
+	}
+
+	for (i = 0; i < GANGED_VREG_COUNT; i++) {
+		READ_BYTE(chip,
+			chip->freq_base + i * 0x300 + REG_GANG_CTL2, val, rc);
+		if (rc)
+			return rc;
+
+		if (!(val & GANG_EN_BIT)) {
+			pr_err("buck = %d, freq gang not enabled\n", i);
+			BUG();
+		}
+	}
+	return 0;
+}
+
+static int __devinit krait_vreg_pmic_probe(struct spmi_device *spmi)
+{
+	u8 type, subtype;
+	int rc;
+	struct krait_vreg_pmic_chip *chip;
+	struct spmi_resource *spmi_resource;
+	struct resource *resource;
+
+	chip = devm_kzalloc(&spmi->dev, sizeof *chip, GFP_KERNEL);
+	if (chip == NULL) {
+		pr_err("kzalloc() failed.\n");
+		return -ENOMEM;
+	}
+
+	chip->spmi = spmi;
+
+	spmi_for_each_container_dev(spmi_resource, spmi) {
+		if (!spmi_resource) {
+			pr_err("spmi resource absent\n");
+			return -ENXIO;
+		}
+
+		resource = spmi_get_resource(spmi, spmi_resource,
+							IORESOURCE_MEM, 0);
+		if (!(resource && resource->start)) {
+			pr_err("node %s IO resource absent!\n",
+					spmi->dev.of_node->full_name);
+			return -ENXIO;
+		}
+
+		rc = read_byte(chip->spmi,
+				resource->start + REG_PERPH_TYPE,
+				&type);
+		if (rc) {
+			pr_err("Peripheral type read failed rc=%d\n", rc);
+			return -ENXIO;
+		}
+
+		rc = read_byte(chip->spmi,
+				resource->start + REG_PERPH_SUBTYPE,
+				&subtype);
+		if (rc) {
+			pr_err("Peripheral subtype read failed rc=%d\n", rc);
+			return -ENXIO;
+		}
+
+		if (type == CTRL_TYPE_VAL && subtype == CTRL_SUBTYPE_VAL)
+			chip->ctrl_base = resource->start;
+		else if (type == PS_TYPE_VAL && subtype == PS_SUBTYPE_VAL)
+			chip->ps_base = resource->start;
+		else if (type == FREQ_TYPE_VAL && subtype == FREQ_SUBTYPE_VAL)
+			chip->freq_base = resource->start;
+	}
+
+	if (chip->ctrl_base == 0) {
+		pr_err("ctrl base address missing\n");
+		return -ENXIO;
+	}
+
+	if (chip->ps_base == 0) {
+		pr_err("ps base address missing\n");
+		return -ENXIO;
+	}
+
+	if (chip->freq_base == 0) {
+		pr_err("freq base address missing\n");
+		return -ENXIO;
+	}
+
+	READ_BYTE(chip, chip->ctrl_base + REG_DIG_MAJOR,
+			chip->ctrl_dig_major, rc);
+	if (rc)
+		return rc;
+
+	READ_BYTE(chip, chip->ctrl_base + REG_DIG_MINOR,
+			chip->ctrl_dig_minor, rc);
+	if (rc)
+		return rc;
+
+	gang_configuration_check(chip);
+
+	the_chip = chip;
+	return 0;
+}
+
+static struct spmi_driver qpnp_revid_driver = {
+	.probe	= krait_vreg_pmic_probe,
+	.driver	= {
+		.name		= KRAIT_REG_PMIC_DEV_NAME,
+		.owner		= THIS_MODULE,
+		.of_match_table	= krait_vreg_pmic_match_table,
+	},
+};
+
+static int __init qpnp_revid_init(void)
+{
+	return spmi_driver_register(&qpnp_revid_driver);
+}
+
+static void __exit qpnp_revid_exit(void)
+{
+	return spmi_driver_unregister(&qpnp_revid_driver);
+}
+
+module_init(qpnp_revid_init);
+module_exit(qpnp_revid_exit);
+
+MODULE_DESCRIPTION("KRAIT REGULATOR PMIC DRIVER");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/msm/adreno_trace.c b/arch/arm/mach-msm/krait-regulator-pmic.h
similarity index 70%
copy from drivers/gpu/msm/adreno_trace.c
copy to arch/arm/mach-msm/krait-regulator-pmic.h
index 607ba8c..06ca3ea 100644
--- a/drivers/gpu/msm/adreno_trace.c
+++ b/arch/arm/mach-msm/krait-regulator-pmic.h
@@ -8,11 +8,11 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
  */
 
-#include "adreno.h"
-
-/* Instantiate tracepoints */
-#define CREATE_TRACE_POINTS
-#include "adreno_trace.h"
+#ifndef __ARCH_ARM_MACH_MSM_KRAIT_REGULATOR_PMIC_H
+#define __ARCH_ARM_MACH_MSM_KRAIT_REGULATOR_PMIC_H
+bool krait_pmic_is_ready(void);
+int krait_pmic_post_pfm_entry(void);
+int krait_pmic_post_pwm_entry(void);
+#endif
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 9c5f197..4fee0ae 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -29,7 +29,9 @@
 #include <linux/regulator/krait-regulator.h>
 #include <linux/debugfs.h>
 #include <linux/syscore_ops.h>
+#include <linux/cpu.h>
 #include <mach/msm_iomap.h>
+#include "krait-regulator-pmic.h"
 
 #include "spm.h"
 #include "pm.h"
@@ -222,8 +224,9 @@
 	int				cpu_num;
 	int				coeff1;
 	int				coeff2;
-	bool				online;
+	bool				reg_en;
 	int				online_at_probe;
+	bool				force_bhs;
 };
 
 DEFINE_PER_CPU(struct krait_power_vreg *, krait_vregs);
@@ -372,7 +375,7 @@
 		phase_scaling_factor = pvreg->efuse_phase_scaling_factor;
 
 	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
-		if (!kvreg->online)
+		if (!kvreg->reg_en)
 			continue;
 
 		if (kvreg->mode == LDO_MODE) {
@@ -414,7 +417,7 @@
 	struct krait_power_vreg *kvreg;
 
 	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
-		if (kvreg->online)
+		if (kvreg->reg_en)
 			online_total++;
 	}
 	return online_total;
@@ -427,7 +430,7 @@
 	struct pmic_gang_vreg *pvreg = from->pvreg;
 
 	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
-		if (!kvreg->online)
+		if (!kvreg->reg_en)
 			continue;
 		load_total += kvreg->load;
 	}
@@ -474,16 +477,18 @@
 	}
 
 	/* First check if the coeff is low for PFM mode */
-	if (load_total <= pvreg->pfm_threshold && n_online == 1) {
+	if (load_total <= pvreg->pfm_threshold
+			&& n_online == 1
+			&& krait_pmic_is_ready()) {
 		if (!pvreg->pfm_mode) {
 			rc = msm_spm_enable_fts_lpm(PMIC_FTS_MODE_PFM);
 			if (rc) {
 				pr_err("%s PFM en failed load_t %d rc = %d\n",
 					from->name, load_total, rc);
 				return rc;
-			} else {
-				pvreg->pfm_mode = true;
 			}
+			krait_pmic_post_pfm_entry();
+			pvreg->pfm_mode = true;
 		}
 		return rc;
 	}
@@ -495,10 +500,10 @@
 			pr_err("%s PFM exit failed load %d rc = %d\n",
 				from->name, coeff_total, rc);
 			return rc;
-		} else {
-			pvreg->pfm_mode = false;
-			udelay(PWM_SETTLING_TIME_US);
 		}
+		pvreg->pfm_mode = false;
+		krait_pmic_post_pwm_entry();
+		udelay(PWM_SETTLING_TIME_US);
 	}
 
 	/* calculate phases */
@@ -565,7 +570,7 @@
 
 	mutex_lock(&pvreg->krait_power_vregs_lock);
 	kvreg->load = load_uA;
-	if (!kvreg->online) {
+	if (!kvreg->reg_en) {
 		mutex_unlock(&pvreg->krait_power_vregs_lock);
 		return kvreg->mode;
 	}
@@ -588,10 +593,10 @@
 	return kvreg->mode;
 }
 
-static int switch_to_using_hs(struct krait_power_vreg *kvreg)
+static void __switch_to_using_bhs(void *info)
 {
-	if (kvreg->mode == HS_MODE)
-		return 0;
+	struct krait_power_vreg *kvreg = info;
+
 	/* enable bhs */
 	if (version > KPSS_VERSION_2P0) {
 		krait_masked_write(kvreg, APC_PWR_GATE_MODE,
@@ -645,21 +650,18 @@
 
 	kvreg->mode = HS_MODE;
 	pr_debug("%s using BHS\n", kvreg->name);
-	return 0;
 }
 
-static int switch_to_using_ldo(struct krait_power_vreg *kvreg)
+static void __switch_to_using_ldo(void *info)
 {
-	if (kvreg->mode == LDO_MODE
-		&& get_krait_ldo_uv(kvreg) == kvreg->uV - kvreg->ldo_delta_uV)
-		return 0;
+	struct krait_power_vreg *kvreg = info;
 
 	/*
 	 * if the krait is in ldo mode and a voltage change is requested on the
 	 * ldo switch to using hs before changing ldo voltage
 	 */
 	if (kvreg->mode == LDO_MODE)
-		switch_to_using_hs(kvreg);
+		__switch_to_using_bhs(kvreg);
 
 	set_krait_ldo_uv(kvreg, kvreg->uV - kvreg->ldo_delta_uV);
 	if (version > KPSS_VERSION_2P0) {
@@ -698,7 +700,25 @@
 
 	kvreg->mode = LDO_MODE;
 	pr_debug("%s using LDO\n", kvreg->name);
-	return 0;
+}
+
+static int switch_to_using_ldo(struct krait_power_vreg *kvreg)
+{
+	if (kvreg->mode == LDO_MODE
+		&& get_krait_ldo_uv(kvreg) == kvreg->uV - kvreg->ldo_delta_uV)
+		return 0;
+
+	return smp_call_function_single(kvreg->cpu_num,
+			__switch_to_using_ldo, kvreg, 1);
+}
+
+static int switch_to_using_bhs(struct krait_power_vreg *kvreg)
+{
+	if (kvreg->mode == HS_MODE)
+		return 0;
+
+	return smp_call_function_single(kvreg->cpu_num,
+			__switch_to_using_bhs, kvreg, 1);
 }
 
 static int set_pmic_gang_voltage(struct pmic_gang_vreg *pvreg, int uV)
@@ -740,7 +760,7 @@
 
 	setpoint = DIV_ROUND_UP(uV, LV_RANGE_STEP);
 
-	rc = msm_spm_apcs_set_vdd(setpoint);
+	rc = msm_spm_set_vdd(0, setpoint); /* value of CPU is don't care */
 	if (rc < 0)
 		pr_err("could not set %duV setpt = 0x%x rc = %d\n",
 				uV, setpoint, rc);
@@ -750,6 +770,41 @@
 	return rc;
 }
 
+static int configure_ldo_or_hs_one(struct krait_power_vreg *kvreg, int vmax)
+{
+	int rc;
+
+	if (!kvreg->reg_en)
+		return 0;
+
+	if (kvreg->force_bhs)
+		/*
+		 * The cpu is in transitory phase where it is being
+		 * prepared to be offlined or onlined and is being
+		 * forced to run on BHS during that time
+		 */
+		return 0;
+
+	if (kvreg->uV <= kvreg->ldo_threshold_uV
+		&& kvreg->uV - kvreg->ldo_delta_uV + kvreg->headroom_uV
+			<= vmax) {
+		rc = switch_to_using_ldo(kvreg);
+		if (rc < 0) {
+			pr_err("could not switch %s to ldo rc = %d\n",
+						kvreg->name, rc);
+			return rc;
+		}
+	} else {
+		rc = switch_to_using_bhs(kvreg);
+		if (rc < 0) {
+			pr_err("could not switch %s to hs rc = %d\n",
+						kvreg->name, rc);
+			return rc;
+		}
+	}
+	return 0;
+}
+
 static int configure_ldo_or_hs_all(struct krait_power_vreg *from, int vmax)
 {
 	struct pmic_gang_vreg *pvreg = from->pvreg;
@@ -757,27 +812,12 @@
 	int rc = 0;
 
 	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
-		if (!kvreg->online)
-			continue;
-		if (kvreg->uV <= kvreg->ldo_threshold_uV
-			&& kvreg->uV - kvreg->ldo_delta_uV + kvreg->headroom_uV
-				<= vmax) {
-			rc = switch_to_using_ldo(kvreg);
-			if (rc < 0) {
-				pr_err("could not switch %s to ldo rc = %d\n",
-							kvreg->name, rc);
-				return rc;
-			}
-		} else {
-			rc = switch_to_using_hs(kvreg);
-			if (rc < 0) {
-				pr_err("could not switch %s to hs rc = %d\n",
-							kvreg->name, rc);
-				return rc;
-			}
+		rc = configure_ldo_or_hs_one(kvreg, vmax);
+		if (rc) {
+			pr_err("could not switch %s\n", kvreg->name);
+			break;
 		}
 	}
-
 	return rc;
 }
 
@@ -856,7 +896,7 @@
 	struct krait_power_vreg *kvreg;
 
 	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
-		if (!kvreg->online)
+		if (!kvreg->reg_en)
 			continue;
 
 		v = kvreg->uV;
@@ -896,7 +936,7 @@
 		rc = krait_voltage_decrease(kvreg, vmax);
 
 	if (rc < 0) {
-		dev_err(&rdev->dev, "%s failed to set %duV from %duV rc = %d\n",
+		pr_err("%s failed to set %duV from %duV rc = %d\n",
 				kvreg->name, requested_uV, orig_krait_uV, rc);
 	}
 
@@ -927,7 +967,7 @@
 	}
 
 	mutex_lock(&pvreg->krait_power_vregs_lock);
-	if (!kvreg->online) {
+	if (!kvreg->reg_en) {
 		kvreg->uV = min_uV;
 		mutex_unlock(&pvreg->krait_power_vregs_lock);
 		return 0;
@@ -943,7 +983,7 @@
 {
 	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
 
-	return kvreg->online;
+	return kvreg->reg_en;
 }
 
 static int krait_power_enable(struct regulator_dev *rdev)
@@ -953,8 +993,9 @@
 	int rc;
 
 	mutex_lock(&pvreg->krait_power_vregs_lock);
+	pr_debug("enable %s\n", kvreg->name);
 	__krait_power_mdd_enable(kvreg, true);
-	kvreg->online = true;
+	kvreg->reg_en = true;
 	rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV, kvreg->load);
 	if (rc < 0)
 		goto en_err;
@@ -975,7 +1016,8 @@
 	int rc;
 
 	mutex_lock(&pvreg->krait_power_vregs_lock);
-	kvreg->online = false;
+	pr_debug("disable %s\n", kvreg->name);
+	kvreg->reg_en = false;
 
 	rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV, kvreg->load);
 	if (rc < 0)
@@ -999,6 +1041,69 @@
 	.is_enabled		= krait_power_is_enabled,
 };
 
+static int krait_regulator_cpu_callback(struct notifier_block *nfb,
+					    unsigned long action, void *hcpu)
+{
+	int cpu = (int)hcpu;
+	struct krait_power_vreg *kvreg = per_cpu(krait_vregs, cpu);
+	struct pmic_gang_vreg *pvreg = kvreg->pvreg;
+
+	pr_debug("start state=0x%02x, cpu=%d is_online=%d\n",
+			(int)action, cpu, cpu_online(cpu));
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_UP_PREPARE:
+		mutex_lock(&pvreg->krait_power_vregs_lock);
+		kvreg->force_bhs = true;
+		/*
+		 * cpu is offline at this point, force bhs on which ever cpu
+		 * this callback is running on
+		 */
+		pr_debug("%s force BHS locally\n", kvreg->name);
+		__switch_to_using_bhs(kvreg);
+		mutex_unlock(&pvreg->krait_power_vregs_lock);
+		break;
+	case CPU_UP_CANCELED:
+	case CPU_ONLINE:
+		mutex_lock(&pvreg->krait_power_vregs_lock);
+		kvreg->force_bhs = false;
+		/*
+		 * switch the cpu to proper bhs/ldo, the cpu is online at this
+		 * point. The gang voltage and mode votes for the cpu were
+		 * submitted in CPU_UP_PREPARE phase
+		 */
+		configure_ldo_or_hs_one(kvreg, pvreg->pmic_vmax_uV);
+		mutex_unlock(&pvreg->krait_power_vregs_lock);
+		break;
+	case CPU_DOWN_PREPARE:
+		mutex_lock(&pvreg->krait_power_vregs_lock);
+		kvreg->force_bhs = true;
+		/*
+		 * switch the cpu to run on bhs using smp function calls. Note
+		 * that the cpu is online at this point.
+		 */
+		pr_debug("%s force BHS remotely\n", kvreg->name);
+		switch_to_using_bhs(kvreg);
+		mutex_unlock(&pvreg->krait_power_vregs_lock);
+		break;
+	case CPU_DOWN_FAILED:
+		mutex_lock(&pvreg->krait_power_vregs_lock);
+		kvreg->force_bhs = false;
+		configure_ldo_or_hs_one(kvreg, pvreg->pmic_vmax_uV);
+		mutex_unlock(&pvreg->krait_power_vregs_lock);
+		break;
+	default:
+		break;
+	}
+
+	pr_debug("done state=0x%02x, cpu=%d is_online=%d\n",
+			(int)action, cpu, cpu_online(cpu));
+	return NOTIFY_OK;
+}
+
+static struct notifier_block krait_cpu_notifier = {
+	.notifier_call = krait_regulator_cpu_callback,
+};
+
 static struct dentry *dent;
 static int get_retention_dbg_uV(void *data, u64 *val)
 {
@@ -1481,11 +1586,14 @@
 				KRAIT_REGULATOR_DRIVER_NAME, rc);
 		return rc;
 	}
+
+	register_hotcpu_notifier(&krait_cpu_notifier);
 	return platform_driver_register(&krait_pdn_driver);
 }
 
 static void __exit krait_power_exit(void)
 {
+	unregister_hotcpu_notifier(&krait_cpu_notifier);
 	platform_driver_unregister(&krait_power_driver);
 	platform_driver_unregister(&krait_pdn_driver);
 }
diff --git a/arch/arm/mach-msm/mpm-of.c b/arch/arm/mach-msm/mpm-of.c
index a0746f9..e364393 100644
--- a/arch/arm/mach-msm/mpm-of.c
+++ b/arch/arm/mach-msm/mpm-of.c
@@ -219,12 +219,16 @@
 	hlist_for_each_entry(node, elem, &irq_hash[hashfn(d->hwirq)], node) {
 		if ((node->hwirq == d->hwirq)
 				&& (d->domain == node->domain)) {
-			/* Update the linux irq mapping */
-			msm_mpm_irqs_m2a[node->pin] = d->irq;
+			/*
+			 * Update the linux irq mapping. No update required for
+			 * bypass interrupts
+			 */
+			if (node->pin != 0xff)
+				msm_mpm_irqs_m2a[node->pin] = d->irq;
 			break;
 		}
 	}
-	return node ? node->pin : 0;
+	return elem ? node->pin : 0;
 }
 
 static int msm_mpm_enable_irq_exclusive(
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
index 3ff7530..058e409 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
@@ -652,15 +652,6 @@
 			MSM_BUS_DBG("ab: %llu ib: %llu\n", curr_bw, curr_clk);
 		}
 
-		if (index == 0) {
-			/* This check protects the bus driver from clients
-			 * that can leave non-zero requests after
-			 * unregistering.
-			 * */
-			req_clk = 0;
-			req_bw = 0;
-		}
-
 		if (!pdata->active_only) {
 			ret = update_path(src, pnode, req_clk, req_bw,
 				curr_clk, curr_bw, 0, pdata->active_only);
@@ -782,11 +773,47 @@
  */
 void msm_bus_scale_unregister_client(uint32_t cl)
 {
+	int i;
 	struct msm_bus_client *client = (struct msm_bus_client *)(cl);
+	bool warn = false;
 	if (IS_ERR_OR_NULL(client))
 		return;
-	if (client->curr != 0)
+
+	for (i = 0; i < client->pdata->usecase->num_paths; i++) {
+		if ((client->pdata->usecase[0].vectors[i].ab) ||
+			(client->pdata->usecase[0].vectors[i].ib)) {
+			warn = true;
+			break;
+		}
+	}
+
+	if (warn) {
+		int num_paths = client->pdata->usecase->num_paths;
+		int ab[num_paths], ib[num_paths];
+		WARN(1, "%s called unregister with non-zero vectors\n",
+			client->pdata->name);
+
+		/*
+		 * Save client values and zero them out to
+		 * cleanly unregister
+		 */
+		for (i = 0; i < num_paths; i++) {
+			ab[i] = client->pdata->usecase[0].vectors[i].ab;
+			ib[i] = client->pdata->usecase[0].vectors[i].ib;
+			client->pdata->usecase[0].vectors[i].ab = 0;
+			client->pdata->usecase[0].vectors[i].ib = 0;
+		}
+
 		msm_bus_scale_client_update_request(cl, 0);
+
+		/* Restore client vectors if required for re-registering. */
+		for (i = 0; i < num_paths; i++) {
+			client->pdata->usecase[0].vectors[i].ab = ab[i];
+			client->pdata->usecase[0].vectors[i].ib = ib[i];
+		}
+	} else if (client->curr != 0)
+		msm_bus_scale_client_update_request(cl, 0);
+
 	MSM_BUS_DBG("Unregistering client %d\n", cl);
 	mutex_lock(&msm_bus_lock);
 	msm_bus_scale_client_reset_pnodes(cl);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_id.c b/arch/arm/mach-msm/msm_bus/msm_bus_id.c
index 7e9883f..25a749a 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_id.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_id.c
@@ -35,16 +35,22 @@
 		if (!fabreg->info[i].gateway) {
 			fabreg->info[i].priv_id = fabid + fabreg->info[i].id;
 			if (fabreg->info[i].id < SLAVE_ID_KEY) {
-				WARN(fabreg->info[i].id >= MSM_BUS_MASTER_LAST,
-					"id %d exceeds array size!\n",
-					fabreg->info[i].id);
+				if (fabreg->info[i].id >= MSM_BUS_MASTER_LAST) {
+					WARN(1, "id %d exceeds array size!\n",
+						fabreg->info[i].id);
+					continue;
+				}
+
 				master_iids[fabreg->info[i].id] =
 					fabreg->info[i].priv_id;
 			} else {
-				WARN((fabreg->info[i].id - SLAVE_ID_KEY) >=
-					(MSM_BUS_SLAVE_LAST - SLAVE_ID_KEY),
-					"id %d exceeds array size!\n",
-					fabreg->info[i].id);
+				if ((fabreg->info[i].id - SLAVE_ID_KEY) >=
+					(MSM_BUS_SLAVE_LAST - SLAVE_ID_KEY)) {
+					WARN(1, "id %d exceeds array size!\n",
+						fabreg->info[i].id);
+					continue;
+				}
+
 				slave_iids[fabreg->info[i].id - (SLAVE_ID_KEY)]
 					= fabreg->info[i].priv_id;
 			}
diff --git a/arch/arm/mach-msm/msm_cache_dump.c b/arch/arm/mach-msm/msm_cache_dump.c
index 86e8963..a5593bf 100644
--- a/arch/arm/mach-msm/msm_cache_dump.c
+++ b/arch/arm/mach-msm/msm_cache_dump.c
@@ -23,15 +23,16 @@
 #include <linux/notifier.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/dma-mapping.h>
 #include <mach/scm.h>
 #include <mach/msm_cache_dump.h>
-#include <mach/memory.h>
 #include <mach/msm_iomap.h>
 #include <mach/msm_memory_dump.h>
 
 #define L2_DUMP_OFFSET 0x14
 
-static unsigned long msm_cache_dump_addr;
+static dma_addr_t msm_cache_dump_addr;
+static void *msm_cache_dump_vaddr;
 
 /*
  * These should not actually be dereferenced. There's no
@@ -76,7 +77,6 @@
 		unsigned long buf;
 		unsigned long size;
 	} l1_cache_data;
-	void *temp;
 	u32 l1_size, l2_size;
 	unsigned long total_size;
 
@@ -102,19 +102,20 @@
 	};
 
 	total_size = l1_size + l2_size;
-	msm_cache_dump_addr = allocate_contiguous_ebi_nomap(total_size, SZ_4K);
+	msm_cache_dump_vaddr = (void *) dma_alloc_coherent(&pdev->dev,
+					total_size, &msm_cache_dump_addr,
+					GFP_KERNEL);
 
-	if (!msm_cache_dump_addr) {
+	if (!msm_cache_dump_vaddr) {
 		pr_err("%s: Could not get memory for cache dumping\n",
 			__func__);
 		return -ENOMEM;
 	}
 
-	temp = ioremap(msm_cache_dump_addr, total_size);
-	memset(temp, 0xFF, total_size);
+	memset(msm_cache_dump_vaddr, 0xFF, total_size);
 	/* Clean caches before sending buffer to TZ */
-	clean_caches((unsigned long) temp, total_size, msm_cache_dump_addr);
-	iounmap(temp);
+	clean_caches((unsigned long) msm_cache_dump_vaddr, total_size,
+			msm_cache_dump_addr);
 
 	l1_cache_data.buf = msm_cache_dump_addr;
 	l1_cache_data.size = l1_size;
@@ -126,8 +127,9 @@
 		pr_err("%s: could not register L1 buffer ret = %d.\n",
 			__func__, ret);
 
-	l1_dump = (struct l1_cache_dump *)msm_cache_dump_addr;
-	l2_dump = (struct l2_cache_dump *)(msm_cache_dump_addr + l1_size);
+	l1_dump = (struct l1_cache_dump *)(uint32_t)msm_cache_dump_addr;
+	l2_dump = (struct l2_cache_dump *)(uint32_t)(msm_cache_dump_addr
+								+ l1_size);
 
 #if defined(CONFIG_MSM_CACHE_DUMP_ON_PANIC)
 	l1_cache_data.buf = msm_cache_dump_addr + l1_size;
diff --git a/arch/arm/mach-msm/msm_rtb.c b/arch/arm/mach-msm/msm_rtb.c
index fdf39be..28b2195 100644
--- a/arch/arm/mach-msm/msm_rtb.c
+++ b/arch/arm/mach-msm/msm_rtb.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -89,7 +89,7 @@
 	.notifier_call  = msm_rtb_panic_notifier,
 };
 
-int msm_rtb_event_should_log(enum logk_event_type log_type)
+int notrace msm_rtb_event_should_log(enum logk_event_type log_type)
 {
 	return msm_rtb.initialized && msm_rtb.enabled &&
 		((1 << (log_type & ~LOGTYPE_NOPC)) & msm_rtb.filter);
@@ -203,7 +203,7 @@
 }
 #endif
 
-int uncached_logk_pc(enum logk_event_type log_type, void *caller,
+int notrace uncached_logk_pc(enum logk_event_type log_type, void *caller,
 				void *data)
 {
 	int i;
@@ -219,7 +219,7 @@
 }
 EXPORT_SYMBOL(uncached_logk_pc);
 
-noinline int uncached_logk(enum logk_event_type log_type, void *data)
+noinline int notrace uncached_logk(enum logk_event_type log_type, void *data)
 {
 	return uncached_logk_pc(log_type, __builtin_return_address(0), data);
 }
diff --git a/arch/arm/mach-msm/perf_trace_counters.c b/arch/arm/mach-msm/perf_trace_counters.c
index 65b0d28..8fa73ae 100644
--- a/arch/arm/mach-msm/perf_trace_counters.c
+++ b/arch/arm/mach-msm/perf_trace_counters.c
@@ -106,7 +106,7 @@
 	dir = debugfs_create_dir("perf_debug_tp", NULL);
 	if (!dir)
 		return -ENOMEM;
-	file = debugfs_create_file("enabled", 0777, dir,
+	file = debugfs_create_file("enabled", 0660, dir,
 		&value, &fops_perftp);
 	if (!file) {
 		debugfs_remove(dir);
diff --git a/arch/arm/mach-msm/qdsp6v2/adsp-loader.c b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
index e74fdf9..0506e7e 100644
--- a/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
+++ b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
@@ -20,39 +20,60 @@
 #include <mach/subsystem_restart.h>
 #include <mach/qdsp6v2/apr.h>
 #include <linux/of_device.h>
+#include <linux/sysfs.h>
 
 #define Q6_PIL_GET_DELAY_MS 100
+#define BOOT_CMD 1
+
+static ssize_t adsp_boot_store(struct kobject *kobj,
+	struct kobj_attribute *attr,
+	const char *buf, size_t count);
 
 struct adsp_loader_private {
 	void *pil_h;
+	struct kobject *boot_adsp_obj;
+	struct attribute_group *attr_group;
 };
 
-static int adsp_loader_probe(struct platform_device *pdev)
+static struct kobj_attribute adsp_boot_attribute =
+	__ATTR(boot, 0220, NULL, adsp_boot_store);
+
+static struct attribute *attrs[] = {
+	&adsp_boot_attribute.attr,
+	NULL,
+};
+
+static struct platform_device *adsp_private;
+
+static void adsp_loader_do(struct platform_device *pdev)
 {
-	struct adsp_loader_private *priv;
-	int rc = 0;
+
+	struct adsp_loader_private *priv = NULL;
+
 	const char *adsp_dt = "qcom,adsp-state";
+	int rc = 0;
 	u32 adsp_state;
 
 	rc = of_property_read_u32(pdev->dev.of_node, adsp_dt, &adsp_state);
 	if (rc) {
 		dev_err(&pdev->dev,
 			"%s: ADSP state = %x\n", __func__, adsp_state);
-		return rc;
+		return;
 	}
 
 	if (adsp_state == APR_SUBSYS_DOWN) {
-		priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-		if (!priv)
-			return -ENOMEM;
+		if (pdev) {
+			priv = platform_get_drvdata(pdev);
+		} else {
+			pr_err("%s: Private data get failed\n", __func__);
+			goto fail;
+		}
 
-		platform_set_drvdata(pdev, priv);
 
 		priv->pil_h = subsystem_get("adsp");
 		if (IS_ERR(priv->pil_h)) {
-			pr_err("%s: pil get adsp failed, error:%d\n",
-				__func__, rc);
-			devm_kfree(&pdev->dev, priv);
+			pr_err("%s: pil get failed,\n",
+				__func__);
 			goto fail;
 		}
 
@@ -60,25 +81,123 @@
 		apr_set_q6_state(APR_SUBSYS_LOADED);
 	} else if (adsp_state == APR_SUBSYS_LOADED) {
 		dev_dbg(&pdev->dev,
-			"%s:MDM9x25 ADSP state = %x\n", __func__, adsp_state);
+			"%s: ADSP state = %x\n", __func__, adsp_state);
 		apr_set_q6_state(APR_SUBSYS_LOADED);
 	}
 
-	/* Query for MMPM API */
 
 	pr_info("%s: Q6/ADSP image is loaded\n", __func__);
+	return;
 fail:
-	return rc;
+
+	pr_err("%s: Q6/ADSP image loading failed\n", __func__);
+	return;
+}
+
+
+static ssize_t adsp_boot_store(struct kobject *kobj,
+	struct kobj_attribute *attr,
+	const char *buf,
+	size_t count)
+{
+	int boot = 0;
+	sscanf(buf, "%du", &boot);
+
+	if (boot == BOOT_CMD) {
+		pr_debug("%s:going to call adsp_loader_do", __func__);
+		adsp_loader_do(adsp_private);
+	}
+	return count;
+}
+
+static int adsp_loader_init_sysfs(struct platform_device *pdev)
+{
+	int ret = -EINVAL;
+	struct adsp_loader_private *priv = NULL;
+	adsp_private = NULL;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		pr_err("%s: memory alloc failed\n", __func__);
+		ret = -ENOMEM;
+		goto error_return;
+	}
+
+	platform_set_drvdata(pdev, priv);
+
+	priv->pil_h = NULL;
+	priv->boot_adsp_obj = NULL;
+	priv->attr_group = devm_kzalloc(&pdev->dev,
+				sizeof(*(priv->attr_group)),
+				GFP_KERNEL);
+	if (!priv->attr_group) {
+		pr_err("%s: malloc attr_group failed\n",
+						__func__);
+		ret = -ENOMEM;
+		goto error_return;
+	}
+
+	priv->attr_group->attrs = attrs;
+
+	priv->boot_adsp_obj = kobject_create_and_add("boot_adsp", kernel_kobj);
+	if (!priv->boot_adsp_obj) {
+		pr_err("%s: sysfs create and add failed\n",
+						__func__);
+		ret = -ENOMEM;
+		goto error_return;
+	}
+
+	ret = sysfs_create_group(priv->boot_adsp_obj, priv->attr_group);
+	if (ret) {
+		pr_err("%s: sysfs create group failed %d\n", \
+							__func__, ret);
+		goto error_return;
+	}
+
+	adsp_private = pdev;
+
+	return 0;
+
+error_return:
+
+	if (priv->boot_adsp_obj) {
+		kobject_del(priv->boot_adsp_obj);
+		priv->boot_adsp_obj = NULL;
+	}
+
+	return ret;
 }
 
 static int adsp_loader_remove(struct platform_device *pdev)
 {
-	struct adsp_loader_private *priv;
+	struct adsp_loader_private *priv = NULL;
 
 	priv = platform_get_drvdata(pdev);
-	if (priv != NULL)
+
+	if (!priv)
+		return 0;
+
+	if (priv->pil_h) {
 		subsystem_put(priv->pil_h);
-	pr_info("%s: Q6/ADSP image is unloaded\n", __func__);
+		priv->pil_h = NULL;
+	}
+
+	if (priv->boot_adsp_obj) {
+		sysfs_remove_group(priv->boot_adsp_obj, priv->attr_group);
+		kobject_del(priv->boot_adsp_obj);
+		priv->boot_adsp_obj = NULL;
+	}
+
+	return 0;
+}
+
+static int adsp_loader_probe(struct platform_device *pdev)
+{
+	int ret = adsp_loader_init_sysfs(pdev);
+	if (ret != 0) {
+		pr_err("%s: Error in initing sysfs\n", __func__);
+		return ret;
+	}
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_aac.c
index f4eb318..caeb79d 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_aac.c
@@ -262,6 +262,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_aac_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c b/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
index 056a161..fc023c1 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -120,6 +120,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_amrnb_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c b/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
index 54ca4e8..256da4d 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -122,6 +122,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_amrwb_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
index 2889c14..902e06d 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -199,6 +199,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 	config_debug_fs(audio);
 	pr_debug("%s: AMRWBPLUS dec success mode[%d]session[%d]\n", __func__,
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_evrc.c b/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
index 261642c..3498e69 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -128,6 +128,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_evrc_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_mp3.c b/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
index ebcca3c..d2f0270 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
@@ -128,6 +128,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_mp3_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
index 8153145..0a8ce8e 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
@@ -282,6 +282,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_multi_aac_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c b/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
index 69a9fcb..4993226 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -133,6 +133,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_qcelp_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index 8baac01..a1463bc 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -1095,6 +1095,7 @@
 	int rc = 0;
 	int i;
 	struct audio_aio_event *e_node = NULL;
+	struct list_head *ptr, *next;
 
 	/* Settings will be re-config at AUDIO_SET_CONFIG,
 	 * but at least we need to have initial config
@@ -1147,28 +1148,35 @@
 		else {
 			pr_err("%s[%p]:event pkt alloc failed\n",
 				__func__, audio);
-			break;
+			rc = -ENOMEM;
+			goto cleanup;
 		}
 	}
 	audio->client = msm_audio_ion_client_create(UINT_MAX,
 						    "Audio_Dec_Client");
 	if (IS_ERR_OR_NULL(audio->client)) {
 		pr_err("Unable to create ION client\n");
-		rc = -EACCES;
-		goto fail;
+		rc = -ENOMEM;
+		goto cleanup;
 	}
 	pr_debug("Ion client create in audio_aio_open %p", audio->client);
 
 	rc = register_volume_listener(audio);
 	if (rc < 0)
-		goto fail;
+		goto ion_cleanup;
 
 	return 0;
-
+ion_cleanup:
+	msm_audio_ion_client_destroy(audio->client);
+	audio->client = NULL;
+cleanup:
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		e_node = list_first_entry(&audio->free_event_queue,
+				   struct audio_aio_event, list);
+		list_del(&e_node->list);
+		kfree(e_node);
+	}
 fail:
-	q6asm_audio_client_free(audio->ac);
-	kfree(audio->codec_cfg);
-	kfree(audio);
 	return rc;
 }
 
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_wma.c b/arch/arm/mach-msm/qdsp6v2/audio_wma.c
index 1d1da1a..5e3de86 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_wma.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -167,6 +167,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_wma_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c b/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
index 2b2d772..ce49cac 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -227,6 +227,10 @@
 		goto fail;
 	}
 	rc = audio_aio_open(audio, file);
+	if (rc < 0) {
+		pr_err("audio_aio_open rc=%d\n", rc);
+		goto fail;
+	}
 
 #ifdef CONFIG_DEBUG_FS
 	snprintf(name, sizeof name, "msm_wmapro_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index c85f7a1..37fd650 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -159,6 +159,21 @@
 }
 EXPORT_SYMBOL(msm_set_restart_mode);
 
+static bool scm_pmic_arbiter_disable_supported;
+/*
+ * Force the SPMI PMIC arbiter to shutdown so that no more SPMI transactions
+ * are sent from the MSM to the PMIC.  This is required in order to avoid an
+ * SPMI lockup on certain PMIC chips if PS_HOLD is lowered in the middle of
+ * an SPMI transaction.
+ */
+static void halt_spmi_pmic_arbiter(void)
+{
+	if (scm_pmic_arbiter_disable_supported) {
+		pr_crit("Calling SCM to disable SPMI PMIC arbiter\n");
+		scm_call_atomic1(SCM_SVC_PWR, SCM_IO_DISABLE_PMIC_ARBITER, 0);
+	}
+}
+
 static void __msm_power_off(int lower_pshold)
 {
 	printk(KERN_CRIT "Powering off the SoC\n");
@@ -169,10 +184,12 @@
 	qpnp_pon_system_pwr_off(PON_POWER_OFF_SHUTDOWN);
 
 	if (lower_pshold) {
-		if (!use_restart_v2())
+		if (!use_restart_v2()) {
 			__raw_writel(0, PSHOLD_CTL_SU);
-		else
+		} else {
+			halt_spmi_pmic_arbiter();
 			__raw_writel(0, MSM_MPM2_PSHOLD_BASE);
+		}
 
 		mdelay(10000);
 		printk(KERN_ERR "Powering off has failed\n");
@@ -298,6 +315,7 @@
 	} else {
 		/* Needed to bypass debug image on some chips */
 		msm_disable_wdog_debug();
+		halt_spmi_pmic_arbiter();
 		__raw_writel(0, MSM_MPM2_PSHOLD_BASE);
 	}
 
@@ -340,6 +358,9 @@
 	restart_reason = MSM_IMEM_BASE + RESTART_REASON_ADDR;
 	pm_power_off = msm_power_off;
 
+	if (scm_is_call_available(SCM_SVC_PWR, SCM_IO_DISABLE_PMIC_ARBITER) > 0)
+		scm_pmic_arbiter_disable_supported = true;
+
 	return 0;
 }
 early_initcall(msm_restart_init);
diff --git a/arch/arm/mach-msm/rpm_master_stat.c b/arch/arm/mach-msm/rpm_master_stat.c
index 49a1039..3e1789f 100644
--- a/arch/arm/mach-msm/rpm_master_stat.c
+++ b/arch/arm/mach-msm/rpm_master_stat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -22,39 +22,57 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/mm.h>
+#include <linux/of.h>
 #include <asm/uaccess.h>
 
 #include <mach/msm_iomap.h>
 #include "rpm_stats.h"
-#define MSG_RAM_SIZE_PER_MASTER	32
 
-enum {
-	NUMSHUTDOWNS,
-	ACTIVECORES,
-	MASTER_ID_MAX,
-};
+#define RPM_MASTERS_BUF_LEN 400
 
-static char *msm_rpm_master_stats_id_labels[MASTER_ID_MAX] = {
-	[NUMSHUTDOWNS] = "num_shutdowns",
-	[ACTIVECORES] = "active_cores",
-};
+#define SNPRINTF(buf, size, format, ...) \
+	do { \
+		if (size > 0) { \
+			int ret; \
+			ret = snprintf(buf, size, format, ## __VA_ARGS__); \
+			if (ret > size) { \
+				buf += size; \
+				size = 0; \
+			} else { \
+				buf += ret; \
+				size -= ret; \
+			} \
+		} \
+	} while (0)
 
+#define GET_MASTER_NAME(a, prvdata) \
+	((a >= prvdata->num_masters) ? "Invalid Master Name" : \
+	 prvdata->master_names[a])
+
+#define GET_FIELD(a) ((strnstr(#a, ".", 80) + 1))
 
 struct msm_rpm_master_stats {
-	unsigned long numshutdowns;
-	unsigned long active_cores;
+	uint32_t active_cores;
+	uint32_t numshutdowns;
+	uint64_t shutdown_req;
+	uint64_t wakeup_ind;
+	uint64_t bringup_req;
+	uint64_t bringup_ack;
+	uint32_t wakeup_reason; /* 0 = rude wakeup, 1 = scheduled wakeup */
+	uint32_t last_sleep_transition_duration;
+	uint32_t last_wake_transition_duration;
 };
 
 struct msm_rpm_master_stats_private_data {
 	void __iomem *reg_base;
 	u32 len;
 	char **master_names;
-	u32 nomasters;
-	char buf[256];
+	u32 num_masters;
+	char buf[RPM_MASTERS_BUF_LEN];
 	struct msm_rpm_master_stats_platform_data *platform_data;
 };
 
-static int msm_rpm_master_stats_file_close(struct inode *inode,
+int msm_rpm_master_stats_file_close(struct inode *inode,
 		struct file *file)
 {
 	struct msm_rpm_master_stats_private_data *private = file->private_data;
@@ -67,53 +85,138 @@
 }
 
 static int msm_rpm_master_copy_stats(
-		struct msm_rpm_master_stats_private_data *pdata)
+		struct msm_rpm_master_stats_private_data *prvdata)
 {
 	struct msm_rpm_master_stats record;
-	static int nomasters;
-	int count;
+	struct msm_rpm_master_stats_platform_data *pdata;
+	static int master_cnt;
+	int count, j = 0;
+	char *buf;
 	static DEFINE_MUTEX(msm_rpm_master_stats_mutex);
-	int j = 0;
 
 	mutex_lock(&msm_rpm_master_stats_mutex);
-	/*
-	 * iterrate possible nomasters times.
-	 * 8960, 8064 have 5 masters.
-	 * 8930 has 4 masters.
-	 * 9x15 has 3 masters.
-	 */
-	if (nomasters > pdata->nomasters - 1) {
-		nomasters = 0;
+
+	/* Iterate possible number of masters */
+	if (master_cnt > prvdata->num_masters - 1) {
+		master_cnt = 0;
 		mutex_unlock(&msm_rpm_master_stats_mutex);
 		return 0;
 	}
 
-	record.numshutdowns = readl_relaxed(pdata->reg_base +
-			(nomasters * MSG_RAM_SIZE_PER_MASTER));
-	record.active_cores = readl_relaxed(pdata->reg_base +
-				(nomasters * MSG_RAM_SIZE_PER_MASTER + 4));
+	pdata = prvdata->platform_data;
+	count = RPM_MASTERS_BUF_LEN;
+	buf = prvdata->buf;
 
-	count = snprintf(pdata->buf, sizeof(pdata->buf),
-		"%s\n\t%s:%lu\n\t%s:%lu\n",
-		pdata->master_names[nomasters],
-		msm_rpm_master_stats_id_labels[0],
-		record.numshutdowns,
-		msm_rpm_master_stats_id_labels[1],
-		record.active_cores);
+	if (prvdata->platform_data->version == 2) {
+		SNPRINTF(buf, count, "%s\n",
+				GET_MASTER_NAME(master_cnt, prvdata));
 
-	j = find_first_bit(&record.active_cores, BITS_PER_LONG);
+		record.shutdown_req = readll_relaxed(prvdata->reg_base +
+			(master_cnt * pdata->master_offset +
+			offsetof(struct msm_rpm_master_stats, shutdown_req)));
+
+		SNPRINTF(buf, count, "\t%s:0x%llX\n",
+			GET_FIELD(record.shutdown_req),
+			record.shutdown_req);
+
+		record.wakeup_ind = readll_relaxed(prvdata->reg_base +
+			(master_cnt * pdata->master_offset +
+			offsetof(struct msm_rpm_master_stats, wakeup_ind)));
+
+		SNPRINTF(buf, count, "\t%s:0x%llX\n",
+			GET_FIELD(record.wakeup_ind),
+			record.wakeup_ind);
+
+		record.bringup_req = readll_relaxed(prvdata->reg_base +
+			(master_cnt * pdata->master_offset +
+			offsetof(struct msm_rpm_master_stats, bringup_req)));
+
+		SNPRINTF(buf, count, "\t%s:0x%llX\n",
+			GET_FIELD(record.bringup_req),
+			record.bringup_req);
+
+		record.bringup_ack = readll_relaxed(prvdata->reg_base +
+			(master_cnt * pdata->master_offset +
+			offsetof(struct msm_rpm_master_stats, bringup_ack)));
+
+		SNPRINTF(buf, count, "\t%s:0x%llX\n",
+			GET_FIELD(record.bringup_ack),
+			record.bringup_ack);
+
+		record.last_sleep_transition_duration =
+				readl_relaxed(prvdata->reg_base +
+				(master_cnt * pdata->master_offset +
+				offsetof(struct msm_rpm_master_stats,
+				last_sleep_transition_duration)));
+
+		SNPRINTF(buf, count, "\t%s:0x%x\n",
+			GET_FIELD(record.last_sleep_transition_duration),
+			record.last_sleep_transition_duration);
+
+		record.last_wake_transition_duration =
+				readl_relaxed(prvdata->reg_base +
+				(master_cnt * pdata->master_offset +
+				offsetof(struct msm_rpm_master_stats,
+				last_wake_transition_duration)));
+
+		SNPRINTF(buf, count, "\t%s:0x%x\n",
+			GET_FIELD(record.last_wake_transition_duration),
+			record.last_wake_transition_duration);
+
+		record.wakeup_reason = readl_relaxed(prvdata->reg_base +
+					(master_cnt * pdata->master_offset +
+					offsetof(struct msm_rpm_master_stats,
+					wakeup_reason)));
+
+		SNPRINTF(buf, count, "\t%s:0x%x\n",
+			GET_FIELD(record.wakeup_reason),
+			record.wakeup_reason);
+
+		record.numshutdowns = readl_relaxed(prvdata->reg_base +
+			(master_cnt * pdata->master_offset +
+			 offsetof(struct msm_rpm_master_stats, numshutdowns)));
+
+		SNPRINTF(buf, count, "\t%s:0x%x\n",
+			GET_FIELD(record.numshutdowns),
+			record.numshutdowns);
+
+		record.active_cores = readl_relaxed(prvdata->reg_base +
+			(master_cnt * pdata->master_offset) +
+			offsetof(struct msm_rpm_master_stats, active_cores));
+
+		SNPRINTF(buf, count, "\t%s:0x%x\n",
+			GET_FIELD(record.active_cores),
+			record.active_cores);
+	} else {
+		SNPRINTF(buf, count, "%s\n",
+				GET_MASTER_NAME(master_cnt, prvdata));
+
+		record.numshutdowns = readl_relaxed(prvdata->reg_base +
+				(master_cnt * pdata->master_offset) + 0x0);
+
+		SNPRINTF(buf, count, "\t%s:0x%0x\n",
+			GET_FIELD(record.numshutdowns),
+			record.numshutdowns);
+
+		record.active_cores = readl_relaxed(prvdata->reg_base +
+				(master_cnt * pdata->master_offset) + 0x4);
+
+		SNPRINTF(buf, count, "\t%s:0x%0x\n",
+			GET_FIELD(record.active_cores),
+			record.active_cores);
+	}
+
+	j = find_first_bit((unsigned long *)&record.active_cores,
+							BITS_PER_LONG);
 	while (j < BITS_PER_LONG) {
-		count += snprintf(pdata->buf + count,
-			sizeof(pdata->buf) - count,
-			"\t\tcore%d\n", j);
-		j = find_next_bit(&record.active_cores,
+		SNPRINTF(buf, count, "\t\tcore%d\n", j);
+		j = find_next_bit((unsigned long *)&record.active_cores,
 				BITS_PER_LONG, j + 1);
 	}
 
-
-	nomasters++;
+	master_cnt++;
 	mutex_unlock(&msm_rpm_master_stats_mutex);
-	return count;
+	return RPM_MASTERS_BUF_LEN - count;
 }
 
 static int msm_rpm_master_stats_file_read(struct file *file, char __user *bufu,
@@ -151,7 +254,7 @@
 	pdata = inode->i_private;
 
 	file->private_data =
-		kmalloc(sizeof(struct msm_rpm_master_stats_private_data),
+		kzalloc(sizeof(struct msm_rpm_master_stats_private_data),
 			GFP_KERNEL);
 
 	if (!file->private_data)
@@ -159,7 +262,7 @@
 	prvdata = file->private_data;
 
 	prvdata->reg_base = ioremap(pdata->phys_addr_base,
-		pdata->phys_size);
+						pdata->phys_size);
 	if (!prvdata->reg_base) {
 		kfree(file->private_data);
 		prvdata = NULL;
@@ -170,7 +273,7 @@
 	}
 
 	prvdata->len = 0;
-	prvdata->nomasters = pdata->nomasters;
+	prvdata->num_masters = pdata->num_masters;
 	prvdata->master_names = pdata->masters;
 	prvdata->platform_data = pdata;
 	return 0;
@@ -184,27 +287,108 @@
 	.llseek   = no_llseek,
 };
 
+static struct msm_rpm_master_stats_platform_data
+			*msm_rpm_master_populate_pdata(struct device *dev)
+{
+	struct msm_rpm_master_stats_platform_data *pdata;
+	struct device_node *node = dev->of_node;
+	int rc = 0, i;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(dev, "could not allocate memory for platform data\n");
+		goto err;
+	}
+
+	rc = of_property_read_u32(node, "qcom,master-stats-version",
+							&pdata->version);
+	if (rc) {
+		dev_err(dev, "master-stats-version missing rc=%d\n", rc);
+		goto err;
+	}
+
+	rc = of_property_read_u32(node, "qcom,master-offset",
+							&pdata->master_offset);
+	if (rc) {
+		dev_err(dev, "master-offset missing rc=%d\n", rc);
+		goto err;
+	}
+
+	pdata->num_masters = of_property_count_strings(node, "qcom,masters");
+	if (pdata->num_masters < 0) {
+		dev_err(dev, "Failed to get number of masters =%d\n",
+						pdata->num_masters);
+		goto err;
+	}
+
+	pdata->masters = devm_kzalloc(dev, sizeof(char *) * pdata->num_masters,
+								GFP_KERNEL);
+	if (!pdata->masters) {
+		dev_err(dev, "%s:Failed to allocated memory\n", __func__);
+		goto err;
+	}
+
+	/*
+	 * Read master names from DT
+	 */
+	for (i = 0; i < pdata->num_masters; i++) {
+		const char *master_name;
+		of_property_read_string_index(node, "qcom,masters",
+							i, &master_name);
+		pdata->masters[i] = devm_kzalloc(dev, sizeof(char) *
+				strlen(master_name) + 1, GFP_KERNEL);
+		if (!pdata->masters[i]) {
+			dev_err(dev, "%s:Failed to get memory\n", __func__);
+			goto err;
+		}
+		strlcpy(pdata->masters[i], master_name,
+					strlen(master_name) + 1);
+	}
+	return pdata;
+err:
+	return NULL;
+}
+
 static  int __devinit msm_rpm_master_stats_probe(struct platform_device *pdev)
 {
 	struct dentry *dent;
 	struct msm_rpm_master_stats_platform_data *pdata;
-	struct resource *res;
+	struct resource *res = NULL;
 
-	pdata = pdev->dev.platform_data;
-	if (!pdata)
+	if (!pdev)
 		return -EINVAL;
 
+	if (pdev->dev.of_node)
+		pdata = msm_rpm_master_populate_pdata(&pdev->dev);
+	else
+		pdata = pdev->dev.platform_data;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "%s: Unable to get pdata\n", __func__);
+		return -ENOMEM;
+	}
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res) {
+		dev_err(&pdev->dev,
+			"%s: Failed to get IO resource from platform device",
+			__func__);
+		return -ENXIO;
+	}
+
 	pdata->phys_addr_base = res->start;
 	pdata->phys_size = resource_size(res);
 
 	dent = debugfs_create_file("rpm_master_stats", S_IRUGO, NULL,
-			pdev->dev.platform_data, &msm_rpm_master_stats_fops);
+					pdata, &msm_rpm_master_stats_fops);
 
 	if (!dent) {
-		pr_err("%s: ERROR debugfs_create_file failed\n", __func__);
+		dev_err(&pdev->dev, "%s: ERROR debugfs_create_file failed\n",
+								__func__);
 		return -ENOMEM;
 	}
+
 	platform_set_drvdata(pdev, dent);
 	return 0;
 }
@@ -219,12 +403,18 @@
 	return 0;
 }
 
+static struct of_device_id rpm_master_table[] = {
+	{.compatible = "qcom,rpm-master-stats"},
+	{},
+};
+
 static struct platform_driver msm_rpm_master_stats_driver = {
 	.probe	= msm_rpm_master_stats_probe,
 	.remove = __devexit_p(msm_rpm_master_stats_remove),
 	.driver = {
-		.name = "msm_rpm_master_stat",
+		.name = "msm_rpm_master_stats",
 		.owner = THIS_MODULE,
+		.of_match_table = rpm_master_table,
 	},
 };
 
diff --git a/arch/arm/mach-msm/rpm_stats.h b/arch/arm/mach-msm/rpm_stats.h
index c1dfe34..34c1b99 100644
--- a/arch/arm/mach-msm/rpm_stats.h
+++ b/arch/arm/mach-msm/rpm_stats.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -31,9 +31,11 @@
 	 * it allocates 256 bytes for this use.
 	 * No of masters differs for different targets.
 	 * Based on the number of masters, linux rpm stat
-	 * driver reads (32 * nomasters) bytes to display
+	 * driver reads (32 * num_masters) bytes to display
 	 * master stats.
 	 */
-	 u32 nomasters;
+	 s32 num_masters;
+	 u32 master_offset;
+	 u32 version;
 };
 #endif
diff --git a/arch/arm/mach-msm/scm.c b/arch/arm/mach-msm/scm.c
index e9f44e3..266b759 100644
--- a/arch/arm/mach-msm/scm.c
+++ b/arch/arm/mach-msm/scm.c
@@ -31,6 +31,9 @@
 
 static DEFINE_MUTEX(scm_lock);
 
+#define SCM_BUF_LEN(__cmd_size, __resp_size)	\
+	(sizeof(struct scm_command) + sizeof(struct scm_response) + \
+		__cmd_size + __resp_size)
 /**
  * struct scm_command - one SCM command buffer
  * @len: total available memory for command and response
@@ -76,42 +79,6 @@
 };
 
 /**
- * alloc_scm_command() - Allocate an SCM command
- * @cmd_size: size of the command buffer
- * @resp_size: size of the response buffer
- *
- * Allocate an SCM command, including enough room for the command
- * and response headers as well as the command and response buffers.
- *
- * Returns a valid &scm_command on success or %NULL if the allocation fails.
- */
-static struct scm_command *alloc_scm_command(size_t cmd_size, size_t resp_size)
-{
-	struct scm_command *cmd;
-	size_t len = sizeof(*cmd) + sizeof(struct scm_response) + cmd_size +
-		resp_size;
-
-	cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL);
-	if (cmd) {
-		cmd->len = len;
-		cmd->buf_offset = offsetof(struct scm_command, buf);
-		cmd->resp_hdr_offset = cmd->buf_offset + cmd_size;
-	}
-	return cmd;
-}
-
-/**
- * free_scm_command() - Free an SCM command
- * @cmd: command to free
- *
- * Free an SCM command.
- */
-static inline void free_scm_command(struct scm_command *cmd)
-{
-	kfree(cmd);
-}
-
-/**
  * scm_command_to_response() - Get a pointer to a scm_response
  * @cmd: command
  *
@@ -224,6 +191,92 @@
 }
 
 /**
+ * scm_call_common() - Send an SCM command
+ * @svc_id: service identifier
+ * @cmd_id: command identifier
+ * @cmd_buf: command buffer
+ * @cmd_len: length of the command buffer
+ * @resp_buf: response buffer
+ * @resp_len: length of the response buffer
+ * @scm_buf: internal scm structure used for passing data
+ * @scm_buf_len: length of the internal scm structure
+ *
+ * Core function to scm call. Initializes the given cmd structure with
+ * appropriate values and makes the actual scm call. Validation of cmd
+ * pointer and length must occur in the calling function.
+ *
+ * Returns the appropriate error code from the scm call
+ */
+
+static int scm_call_common(u32 svc_id, u32 cmd_id, const void *cmd_buf,
+				size_t cmd_len, void *resp_buf, size_t resp_len,
+				struct scm_command *scm_buf,
+				size_t scm_buf_length)
+{
+	int ret;
+	struct scm_response *rsp;
+	unsigned long start, end;
+
+	scm_buf->len = scm_buf_length;
+	scm_buf->buf_offset = offsetof(struct scm_command, buf);
+	scm_buf->resp_hdr_offset = scm_buf->buf_offset + cmd_len;
+	scm_buf->id = (svc_id << 10) | cmd_id;
+
+	if (cmd_buf)
+		memcpy(scm_get_command_buffer(scm_buf), cmd_buf, cmd_len);
+
+	mutex_lock(&scm_lock);
+	ret = __scm_call(scm_buf);
+	mutex_unlock(&scm_lock);
+	if (ret)
+		return ret;
+
+	rsp = scm_command_to_response(scm_buf);
+	start = (unsigned long)rsp;
+
+	do {
+		scm_inv_range(start, start + sizeof(*rsp));
+	} while (!rsp->is_complete);
+
+	end = (unsigned long)scm_get_response_buffer(rsp) + resp_len;
+	scm_inv_range(start, end);
+
+	if (resp_buf)
+		memcpy(resp_buf, scm_get_response_buffer(rsp), resp_len);
+
+	return ret;
+}
+
+/**
+ * scm_call_noalloc - Send an SCM command
+ *
+ * Same as scm_call except clients pass in a buffer (@scm_buf) to be used for
+ * scm internal structures. The buffer should be allocated with
+ * DEFINE_SCM_BUFFER to account for the proper alignment and size.
+ */
+int scm_call_noalloc(u32 svc_id, u32 cmd_id, const void *cmd_buf,
+		size_t cmd_len, void *resp_buf, size_t resp_len,
+		void *scm_buf, size_t scm_buf_len)
+{
+	int ret;
+	size_t len = SCM_BUF_LEN(cmd_len, resp_len);
+
+	if (cmd_len > scm_buf_len || resp_len > scm_buf_len ||
+	    len > scm_buf_len)
+		return -EINVAL;
+
+	if (!IS_ALIGNED((unsigned long)scm_buf, PAGE_SIZE))
+		return -EINVAL;
+
+	memset(scm_buf, 0, scm_buf_len);
+
+	ret = scm_call_common(svc_id, cmd_id, cmd_buf, cmd_len, resp_buf,
+				resp_len, scm_buf, len);
+	return ret;
+
+}
+
+/**
  * scm_call() - Send an SCM command
  * @svc_id: service identifier
  * @cmd_id: command identifier
@@ -244,39 +297,20 @@
 int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
 		void *resp_buf, size_t resp_len)
 {
-	int ret;
 	struct scm_command *cmd;
-	struct scm_response *rsp;
-	unsigned long start, end;
+	int ret;
+	size_t len = SCM_BUF_LEN(cmd_len, resp_len);
 
-	cmd = alloc_scm_command(cmd_len, resp_len);
+	if (cmd_len > len || resp_len > len)
+		return -EINVAL;
+
+	cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL);
 	if (!cmd)
 		return -ENOMEM;
 
-	cmd->id = (svc_id << 10) | cmd_id;
-	if (cmd_buf)
-		memcpy(scm_get_command_buffer(cmd), cmd_buf, cmd_len);
-
-	mutex_lock(&scm_lock);
-	ret = __scm_call(cmd);
-	mutex_unlock(&scm_lock);
-	if (ret)
-		goto out;
-
-	rsp = scm_command_to_response(cmd);
-	start = (unsigned long)rsp;
-
-	do {
-		scm_inv_range(start, start + sizeof(*rsp));
-	} while (!rsp->is_complete);
-
-	end = (unsigned long)scm_get_response_buffer(rsp) + resp_len;
-	scm_inv_range(start, end);
-
-	if (resp_buf)
-		memcpy(resp_buf, scm_get_response_buffer(rsp), resp_len);
-out:
-	free_scm_command(cmd);
+	ret = scm_call_common(svc_id, cmd_id, cmd_buf, cmd_len, resp_buf,
+				resp_len, cmd, len);
+	kfree(cmd);
 	return ret;
 }
 EXPORT_SYMBOL(scm_call);
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index e148868..deb1cc7 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -55,24 +55,6 @@
 #include "modem_notifier.h"
 #include "smem_private.h"
 
-#if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM8X60) \
-	|| defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_FSM9XXX) \
-	|| defined(CONFIG_ARCH_MSM9615)	|| defined(CONFIG_ARCH_APQ8064)
-#define CONFIG_QDSP6 1
-#endif
-
-#if defined(CONFIG_ARCH_MSM8X60) || defined(CONFIG_ARCH_MSM8960) \
-	|| defined(CONFIG_ARCH_APQ8064)
-#define CONFIG_DSPS 1
-#endif
-
-#if defined(CONFIG_ARCH_MSM8960) \
-	|| defined(CONFIG_ARCH_APQ8064)
-#define CONFIG_WCNSS 1
-#define CONFIG_DSPS_SMSM 1
-#endif
-
-#define MODULE_NAME "msm_smd"
 #define SMD_VERSION 0x00020000
 #define SMSM_SNAPSHOT_CNT 64
 #define SMSM_SNAPSHOT_SIZE ((SMSM_NUM_ENTRIES + 1) * 4)
@@ -86,14 +68,6 @@
 #define LEGACY_MODEM_SMSM_MASK (SMSM_RESET | SMSM_INIT | SMSM_SMDINIT \
 			| SMSM_RUN | SMSM_SYSTEM_DOWNLOAD)
 
-enum {
-	MSM_SMD_DEBUG = 1U << 0,
-	MSM_SMSM_DEBUG = 1U << 1,
-	MSM_SMD_INFO = 1U << 2,
-	MSM_SMSM_INFO = 1U << 3,
-	MSM_SMx_POWER_INFO = 1U << 4,
-};
-
 struct smsm_shared_info {
 	uint32_t *state;
 	uint32_t *intr_mask;
@@ -127,32 +101,14 @@
 	uint32_t intr_mask_clear;
 };
 
-struct interrupt_config_item {
-	/* must be initialized */
-	irqreturn_t (*irq_handler)(int req, void *data);
-	/* outgoing interrupt config (set from platform data) */
-	uint32_t out_bit_pos;
-	void __iomem *out_base;
-	uint32_t out_offset;
-	int irq_id;
-};
-
-struct interrupt_config {
-	struct interrupt_config_item smd;
-	struct interrupt_config_item smsm;
-};
-
-static irqreturn_t smd_modem_irq_handler(int irq, void *data);
-static irqreturn_t smsm_modem_irq_handler(int irq, void *data);
-static irqreturn_t smd_dsp_irq_handler(int irq, void *data);
-static irqreturn_t smsm_dsp_irq_handler(int irq, void *data);
-static irqreturn_t smd_dsps_irq_handler(int irq, void *data);
-static irqreturn_t smsm_dsps_irq_handler(int irq, void *data);
-static irqreturn_t smd_wcnss_irq_handler(int irq, void *data);
-static irqreturn_t smsm_wcnss_irq_handler(int irq, void *data);
-static irqreturn_t smd_rpm_irq_handler(int irq, void *data);
 static irqreturn_t smsm_irq_handler(int irq, void *data);
 
+/*
+ * Interrupt configuration consists of static configuration for the supported
+ * processors that is done here along with interrupt configuration that is
+ * added by the separate initialization modules (device tree, platform data, or
+ * hard coded).
+ */
 static struct interrupt_config private_intr_config[NUM_SMD_SUBSYSTEMS] = {
 	[SMD_MODEM] = {
 		.smd.irq_handler = smd_modem_irq_handler,
@@ -188,10 +144,10 @@
 	SMSM_APPS_DEM_I = 3,
 };
 
-static int msm_smd_debug_mask = MSM_SMx_POWER_INFO;
+int msm_smd_debug_mask = MSM_SMx_POWER_INFO;
 module_param_named(debug_mask, msm_smd_debug_mask,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
-static void *smd_log_ctx;
+void *smd_log_ctx;
 #define NUM_LOG_PAGES 4
 
 #define IPC_LOG(level, x...) do { \
@@ -248,124 +204,9 @@
 
 static inline void smd_write_intr(unsigned int val,
 				const void __iomem *addr);
-
-#if defined(CONFIG_ARCH_MSM7X30)
-#define MSM_TRIG_A2M_SMD_INT     \
-			(smd_write_intr(1 << 0, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2Q6_SMD_INT    \
-			(smd_write_intr(1 << 8, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2M_SMSM_INT    \
-			(smd_write_intr(1 << 5, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2Q6_SMSM_INT   \
-			(smd_write_intr(1 << 8, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2DSPS_SMD_INT
-#define MSM_TRIG_A2DSPS_SMSM_INT
-#define MSM_TRIG_A2WCNSS_SMD_INT
-#define MSM_TRIG_A2WCNSS_SMSM_INT
-#elif defined(CONFIG_ARCH_MSM8X60)
-#define MSM_TRIG_A2M_SMD_INT     \
-			(smd_write_intr(1 << 3, MSM_GCC_BASE + 0x8))
-#define MSM_TRIG_A2Q6_SMD_INT    \
-			(smd_write_intr(1 << 15, MSM_GCC_BASE + 0x8))
-#define MSM_TRIG_A2M_SMSM_INT    \
-			(smd_write_intr(1 << 4, MSM_GCC_BASE + 0x8))
-#define MSM_TRIG_A2Q6_SMSM_INT   \
-			(smd_write_intr(1 << 14, MSM_GCC_BASE + 0x8))
-#define MSM_TRIG_A2DSPS_SMD_INT  \
-			(smd_write_intr(1, MSM_SIC_NON_SECURE_BASE + 0x4080))
-#define MSM_TRIG_A2DSPS_SMSM_INT
-#define MSM_TRIG_A2WCNSS_SMD_INT
-#define MSM_TRIG_A2WCNSS_SMSM_INT
-#elif defined(CONFIG_ARCH_MSM9615)
-#define MSM_TRIG_A2M_SMD_INT     \
-			(smd_write_intr(1 << 3, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2Q6_SMD_INT    \
-			(smd_write_intr(1 << 15, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2M_SMSM_INT    \
-			(smd_write_intr(1 << 4, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2Q6_SMSM_INT   \
-			(smd_write_intr(1 << 14, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2DSPS_SMD_INT
-#define MSM_TRIG_A2DSPS_SMSM_INT
-#define MSM_TRIG_A2WCNSS_SMD_INT
-#define MSM_TRIG_A2WCNSS_SMSM_INT
-#elif defined(CONFIG_ARCH_FSM9XXX)
-#define MSM_TRIG_A2Q6_SMD_INT	\
-			(smd_write_intr(1 << 10, MSM_GCC_BASE + 0x8))
-#define MSM_TRIG_A2Q6_SMSM_INT	\
-			(smd_write_intr(1 << 10, MSM_GCC_BASE + 0x8))
-#define MSM_TRIG_A2M_SMD_INT	\
-			(smd_write_intr(1 << 0, MSM_GCC_BASE + 0x8))
-#define MSM_TRIG_A2M_SMSM_INT	\
-			(smd_write_intr(1 << 5, MSM_GCC_BASE + 0x8))
-#define MSM_TRIG_A2DSPS_SMD_INT
-#define MSM_TRIG_A2DSPS_SMSM_INT
-#define MSM_TRIG_A2WCNSS_SMD_INT
-#define MSM_TRIG_A2WCNSS_SMSM_INT
-#elif defined(CONFIG_ARCH_MSM7X01A) || defined(CONFIG_ARCH_MSM7x25)
-#define MSM_TRIG_A2M_SMD_INT     \
-			(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (0) * 4))
-#define MSM_TRIG_A2Q6_SMD_INT
-#define MSM_TRIG_A2M_SMSM_INT    \
-			(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (5) * 4))
-#define MSM_TRIG_A2Q6_SMSM_INT
-#define MSM_TRIG_A2DSPS_SMD_INT
-#define MSM_TRIG_A2DSPS_SMSM_INT
-#define MSM_TRIG_A2WCNSS_SMD_INT
-#define MSM_TRIG_A2WCNSS_SMSM_INT
-#elif defined(CONFIG_ARCH_MSM7X27) || defined(CONFIG_ARCH_MSM7X27A)
-#define MSM_TRIG_A2M_SMD_INT     \
-			(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (0) * 4))
-#define MSM_TRIG_A2Q6_SMD_INT
-#define MSM_TRIG_A2M_SMSM_INT    \
-			(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (5) * 4))
-#define MSM_TRIG_A2Q6_SMSM_INT
-#define MSM_TRIG_A2DSPS_SMD_INT
-#define MSM_TRIG_A2DSPS_SMSM_INT
-#define MSM_TRIG_A2WCNSS_SMD_INT
-#define MSM_TRIG_A2WCNSS_SMSM_INT
-#else /* use platform device / device tree configuration */
-#define MSM_TRIG_A2M_SMD_INT
-#define MSM_TRIG_A2Q6_SMD_INT
-#define MSM_TRIG_A2M_SMSM_INT
-#define MSM_TRIG_A2Q6_SMSM_INT
-#define MSM_TRIG_A2DSPS_SMD_INT
-#define MSM_TRIG_A2DSPS_SMSM_INT
-#define MSM_TRIG_A2WCNSS_SMD_INT
-#define MSM_TRIG_A2WCNSS_SMSM_INT
-#endif
-
-/*
- * stub out legacy macros if they are not being used so that the legacy
- * code compiles even though it is not used
- *
- * these definitions should not be used in active code and will cause
- * an early failure
- */
-#ifndef INT_A9_M2A_0
-#define INT_A9_M2A_0 -1
-#endif
-#ifndef INT_A9_M2A_5
-#define INT_A9_M2A_5 -1
-#endif
-#ifndef INT_ADSP_A11
-#define INT_ADSP_A11 -1
-#endif
 #ifndef INT_ADSP_A11_SMSM
 #define INT_ADSP_A11_SMSM -1
 #endif
-#ifndef INT_DSPS_A11
-#define INT_DSPS_A11 -1
-#endif
-#ifndef INT_DSPS_A11_SMSM
-#define INT_DSPS_A11_SMSM -1
-#endif
-#ifndef INT_WCNSS_A11
-#define INT_WCNSS_A11 -1
-#endif
-#ifndef INT_WCNSS_A11_SMSM
-#define INT_WCNSS_A11_SMSM -1
-#endif
 
 #define SMD_LOOPBACK_CID 100
 
@@ -421,9 +262,6 @@
 		++interrupt_stats[SMD_MODEM].smd_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	} else {
-		++interrupt_stats[SMD_MODEM].smd_out_hardcode_count;
-		MSM_TRIG_A2M_SMD_INT;
 	}
 }
 
@@ -437,9 +275,6 @@
 		++interrupt_stats[SMD_Q6].smd_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	} else {
-		++interrupt_stats[SMD_Q6].smd_out_hardcode_count;
-		MSM_TRIG_A2Q6_SMD_INT;
 	}
 }
 
@@ -453,9 +288,6 @@
 		++interrupt_stats[SMD_DSPS].smd_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	} else {
-		++interrupt_stats[SMD_DSPS].smd_out_hardcode_count;
-		MSM_TRIG_A2DSPS_SMD_INT;
 	}
 }
 
@@ -469,9 +301,6 @@
 		++interrupt_stats[SMD_WCNSS].smd_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	} else {
-		++interrupt_stats[SMD_WCNSS].smd_out_hardcode_count;
-		MSM_TRIG_A2WCNSS_SMD_INT;
 	}
 }
 
@@ -492,13 +321,13 @@
 {
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_MODEM].smsm;
+
+	SMx_POWER_INFO("SMSM Apps->%s", "MODEM");
+
 	if (intr->out_base) {
 		++interrupt_stats[SMD_MODEM].smsm_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	} else {
-		++interrupt_stats[SMD_MODEM].smsm_out_hardcode_count;
-		MSM_TRIG_A2M_SMSM_INT;
 	}
 }
 
@@ -506,13 +335,13 @@
 {
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_Q6].smsm;
+
+	SMx_POWER_INFO("SMSM Apps->%s", "ADSP");
+
 	if (intr->out_base) {
 		++interrupt_stats[SMD_Q6].smsm_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	} else {
-		++interrupt_stats[SMD_Q6].smsm_out_hardcode_count;
-		MSM_TRIG_A2Q6_SMSM_INT;
 	}
 }
 
@@ -520,13 +349,13 @@
 {
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_DSPS].smsm;
+
+	SMx_POWER_INFO("SMSM Apps->%s", "DSPS");
+
 	if (intr->out_base) {
 		++interrupt_stats[SMD_DSPS].smsm_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	} else {
-		++interrupt_stats[SMD_DSPS].smsm_out_hardcode_count;
-		MSM_TRIG_A2DSPS_SMSM_INT;
 	}
 }
 
@@ -535,13 +364,12 @@
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_WCNSS].smsm;
 
+	SMx_POWER_INFO("SMSM Apps->%s", "WCNSS");
+
 	if (intr->out_base) {
 		++interrupt_stats[SMD_WCNSS].smsm_out_config_count;
 		smd_write_intr(intr->out_bit_pos,
 		intr->out_base + intr->out_offset);
-	} else {
-		++interrupt_stats[SMD_WCNSS].smsm_out_hardcode_count;
-		MSM_TRIG_A2WCNSS_SMSM_INT;
 	}
 }
 
@@ -694,13 +522,6 @@
 	struct smd_half_channel_word_access ch1;
 };
 
-struct edge_to_pid {
-	uint32_t	local_pid;
-	uint32_t	remote_pid;
-	char		subsys_name[SMD_MAX_CH_NAME_LEN];
-	bool		initialized;
-};
-
 /**
  * Maps edge type to local and remote processor ID's.
  */
@@ -733,7 +554,7 @@
 	struct notifier_block nb;
 };
 
-static int disable_smsm_reset_handshake;
+int disable_smsm_reset_handshake;
 static struct platform_device loopback_tty_pdev = {.name = "LOOPBACK_TTY"};
 
 static LIST_HEAD(smd_ch_closed_list);
@@ -745,14 +566,17 @@
 static LIST_HEAD(smd_ch_list_wcnss);
 static LIST_HEAD(smd_ch_list_rpm);
 
-static unsigned char smd_ch_allocated[64];
+/* 2 total supported tables of channels */
+static unsigned char smd_ch_allocated[SMEM_NUM_SMD_STREAM_CHANNELS * 2];
 static struct work_struct probe_work;
 
 static void finalize_channel_close_fn(struct work_struct *work);
 static DECLARE_WORK(finalize_channel_close_work, finalize_channel_close_fn);
 static struct workqueue_struct *channel_close_wq;
 
-static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm);
+#define PRI_ALLOC_TBL 1
+#define SEC_ALLOC_TBL 2
+static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm, int table_id);
 
 static bool smd_edge_inited(int edge)
 {
@@ -763,26 +587,33 @@
    hence use a lock */
 static DEFINE_MUTEX(smd_probe_lock);
 
-static void smd_channel_probe_worker(struct work_struct *work)
+/**
+ * scan_alloc_table - Scans a specified SMD channel allocation table in SMEM for
+ *			newly created channels that need to be made locally
+ *			visable
+ *
+ * @shared: pointer to the table array in SMEM
+ * @smd_ch_allocated: pointer to an array indicating already allocated channels
+ * table_id: identifier for this channel allocation table
+ *
+ * The smd_probe_lock must be locked by the calling function.  Shared and
+ * smd_ch_allocated are assumed to be valid pointers.
+ */
+static void scan_alloc_table(struct smd_alloc_elm *shared,
+				char *smd_ch_allocated,
+				int table_id)
 {
-	struct smd_alloc_elm *shared;
 	unsigned n;
 	uint32_t type;
 
-	shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
-
-	if (!shared) {
-		pr_err("%s: allocation table not initialized\n", __func__);
-		return;
-	}
-
-	mutex_lock(&smd_probe_lock);
-	for (n = 0; n < 64; n++) {
+	for (n = 0; n < SMEM_NUM_SMD_STREAM_CHANNELS; n++) {
 		if (smd_ch_allocated[n])
 			continue;
 
-		/* channel should be allocated only if APPS
-		   processor is involved */
+		/*
+		 * channel should be allocated only if APPS processor is
+		 * involved
+		 */
 		type = SMD_CHANNEL_TYPE(shared[n].type);
 		if (type >= ARRAY_SIZE(edge_to_pids) ||
 				edge_to_pids[type].local_pid != SMD_APPS)
@@ -793,15 +624,52 @@
 			continue;
 
 		if (!smd_initialized && !smd_edge_inited(type)) {
-			SMD_INFO("Probe skipping ch %d, edge not inited\n", n);
+			SMD_INFO(
+				"Probe skipping tbl %d, ch %d, edge not inited\n",
+				table_id, n);
 			continue;
 		}
 
-		if (!smd_alloc_channel(&shared[n]))
+		if (!smd_alloc_channel(&shared[n], table_id))
 			smd_ch_allocated[n] = 1;
 		else
-			SMD_INFO("Probe skipping ch %d, not allocated\n", n);
+			SMD_INFO(
+				"Probe skipping tbl %d, ch %d, not allocated\n",
+				table_id, n);
 	}
+}
+
+/**
+ * smd_channel_probe_worker() - Scan for newly created SMD channels and init
+ *				local structures so the channels are visable to
+ *				local clients
+ *
+ * @work: work_struct corresponding to an instance of this function running on
+ *		a workqueue.
+ */
+static void smd_channel_probe_worker(struct work_struct *work)
+{
+	struct smd_alloc_elm *shared;
+
+	shared = smem_find(ID_CH_ALLOC_TBL,
+				sizeof(*shared) * SMEM_NUM_SMD_STREAM_CHANNELS);
+
+	if (!shared) {
+		pr_err("%s: allocation table not initialized\n", __func__);
+		return;
+	}
+
+	mutex_lock(&smd_probe_lock);
+
+	scan_alloc_table(shared, smd_ch_allocated, PRI_ALLOC_TBL);
+
+	shared = smem_find(SMEM_CHANNEL_ALLOC_TBL_2,
+			sizeof(*shared) * SMEM_NUM_SMD_STREAM_CHANNELS);
+	if (shared)
+		scan_alloc_table(shared,
+			&(smd_ch_allocated[SMEM_NUM_SMD_STREAM_CHANNELS]),
+			SEC_ALLOC_TBL);
+
 	mutex_unlock(&smd_probe_lock);
 }
 
@@ -860,6 +728,29 @@
 	return ret;
 }
 
+/**
+ * smd_remote_ss_to_edge() - return edge type from remote ss type
+ * @name:	remote subsystem name
+ *
+ * Returns the edge type connected between the local subsystem(APPS)
+ * and remote subsystem @name.
+ */
+int smd_remote_ss_to_edge(const char *name)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(edge_to_pids); ++i) {
+		if (edge_to_pids[i].subsys_name[0] != 0x0) {
+			if (!strncmp(edge_to_pids[i].subsys_name, name,
+								strlen(name)))
+				return i;
+		}
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(smd_remote_ss_to_edge);
+
 /*
  * Returns a pointer to the subsystem name or NULL if no
  * subsystem name is available.
@@ -1384,7 +1275,7 @@
 	SMx_POWER_INFO("SMD Int %s->Apps\n", subsys);
 }
 
-static irqreturn_t smd_modem_irq_handler(int irq, void *data)
+irqreturn_t smd_modem_irq_handler(int irq, void *data)
 {
 	log_irq(SMD_APPS_MODEM);
 	++interrupt_stats[SMD_MODEM].smd_in_count;
@@ -1393,7 +1284,7 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t smd_dsp_irq_handler(int irq, void *data)
+irqreturn_t smd_dsp_irq_handler(int irq, void *data)
 {
 	log_irq(SMD_APPS_QDSP);
 	++interrupt_stats[SMD_Q6].smd_in_count;
@@ -1402,7 +1293,7 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t smd_dsps_irq_handler(int irq, void *data)
+irqreturn_t smd_dsps_irq_handler(int irq, void *data)
 {
 	log_irq(SMD_APPS_DSPS);
 	++interrupt_stats[SMD_DSPS].smd_in_count;
@@ -1411,7 +1302,7 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t smd_wcnss_irq_handler(int irq, void *data)
+irqreturn_t smd_wcnss_irq_handler(int irq, void *data)
 {
 	log_irq(SMD_APPS_WCNSS);
 	++interrupt_stats[SMD_WCNSS].smd_in_count;
@@ -1420,7 +1311,7 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t smd_rpm_irq_handler(int irq, void *data)
+irqreturn_t smd_rpm_irq_handler(int irq, void *data)
 {
 	log_irq(SMD_APPS_RPM);
 	++interrupt_stats[SMD_RPM].smd_in_count;
@@ -1661,15 +1552,41 @@
 }
 
 #if (defined(CONFIG_MSM_SMD_PKG4) || defined(CONFIG_MSM_SMD_PKG3))
-static int smd_alloc_v2(struct smd_channel *ch)
+/**
+ * smd_alloc_v2() - Init local channel structure with information stored in SMEM
+ *
+ * @ch: pointer to the local structure for this channel
+ * @table_id: the id of the table this channel resides in. 1 = first table, 2 =
+ *		second table, etc
+ * @returns: -EINVAL for failure; 0 for success
+ *
+ * ch must point to an allocated instance of struct smd_channel that is zeroed
+ * out, and has the n and type members already initialized to the correct values
+ */
+static int smd_alloc_v2(struct smd_channel *ch, int table_id)
 {
 	void *buffer;
 	unsigned buffer_sz;
+	unsigned base_id;
+	unsigned fifo_id;
+
+	switch (table_id) {
+	case PRI_ALLOC_TBL:
+		base_id = SMEM_SMD_BASE_ID;
+		fifo_id = SMEM_SMD_FIFO_BASE_ID;
+		break;
+	case SEC_ALLOC_TBL:
+		base_id = SMEM_SMD_BASE_ID_2;
+		fifo_id = SMEM_SMD_FIFO_BASE_ID_2;
+		break;
+	default:
+		SMD_INFO("Invalid table_id:%d passed to smd_alloc\n", table_id);
+		return -EINVAL;
+	}
 
 	if (is_word_access_ch(ch->type)) {
 		struct smd_shared_v2_word_access *shared2;
-		shared2 = smem_alloc(SMEM_SMD_BASE_ID + ch->n,
-						sizeof(*shared2));
+		shared2 = smem_alloc(base_id + ch->n, sizeof(*shared2));
 		if (!shared2) {
 			SMD_INFO("smem_alloc failed ch=%d\n", ch->n);
 			return -EINVAL;
@@ -1678,8 +1595,7 @@
 		ch->recv = &shared2->ch1;
 	} else {
 		struct smd_shared_v2 *shared2;
-		shared2 = smem_alloc(SMEM_SMD_BASE_ID + ch->n,
-							sizeof(*shared2));
+		shared2 = smem_alloc(base_id + ch->n, sizeof(*shared2));
 		if (!shared2) {
 			SMD_INFO("smem_alloc failed ch=%d\n", ch->n);
 			return -EINVAL;
@@ -1689,7 +1605,7 @@
 	}
 	ch->half_ch = get_half_ch_funcs(ch->type);
 
-	buffer = smem_get_entry(SMEM_SMD_FIFO_BASE_ID + ch->n, &buffer_sz);
+	buffer = smem_get_entry(fifo_id + ch->n, &buffer_sz);
 	if (!buffer) {
 		SMD_INFO("smem_get_entry failed\n");
 		return -EINVAL;
@@ -1714,7 +1630,7 @@
 }
 
 #else /* define v1 for older targets */
-static int smd_alloc_v2(struct smd_channel *ch)
+static int smd_alloc_v2(struct smd_channel *ch, int table_id)
 {
 	return -EINVAL;
 }
@@ -1738,7 +1654,16 @@
 
 #endif
 
-static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm)
+/**
+ * smd_alloc_channel() - Create and init local structures for a newly allocated
+ *			SMD channel
+ *
+ * @alloc_elm: the allocation element stored in SMEM for this channel
+ * @table_id: the id of the table this channel resides in. 1 = first table, 2 =
+ *		seconds table, etc
+ * @returns: -1 for failure; 0 for success
+ */
+static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm, int table_id)
 {
 	struct smd_channel *ch;
 
@@ -1750,7 +1675,7 @@
 	ch->n = alloc_elm->cid;
 	ch->type = SMD_CHANNEL_TYPE(alloc_elm->type);
 
-	if (smd_alloc_v2(ch) && smd_alloc_v1(ch)) {
+	if (smd_alloc_v2(ch, table_id) && smd_alloc_v1(ch)) {
 		kfree(ch);
 		return -1;
 	}
@@ -2712,28 +2637,28 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t smsm_modem_irq_handler(int irq, void *data)
+irqreturn_t smsm_modem_irq_handler(int irq, void *data)
 {
 	SMx_POWER_INFO("SMSM Int Modem->Apps\n");
 	++interrupt_stats[SMD_MODEM].smsm_in_count;
 	return smsm_irq_handler(irq, data);
 }
 
-static irqreturn_t smsm_dsp_irq_handler(int irq, void *data)
+irqreturn_t smsm_dsp_irq_handler(int irq, void *data)
 {
 	SMx_POWER_INFO("SMSM Int LPASS->Apps\n");
 	++interrupt_stats[SMD_Q6].smsm_in_count;
 	return smsm_irq_handler(irq, data);
 }
 
-static irqreturn_t smsm_dsps_irq_handler(int irq, void *data)
+irqreturn_t smsm_dsps_irq_handler(int irq, void *data)
 {
 	SMx_POWER_INFO("SMSM Int DSPS->Apps\n");
 	++interrupt_stats[SMD_DSPS].smsm_in_count;
 	return smsm_irq_handler(irq, data);
 }
 
-static irqreturn_t smsm_wcnss_irq_handler(int irq, void *data)
+irqreturn_t smsm_wcnss_irq_handler(int irq, void *data)
 {
 	SMx_POWER_INFO("SMSM Int WCNSS->Apps\n");
 	++interrupt_stats[SMD_WCNSS].smsm_in_count;
@@ -2825,7 +2750,8 @@
 	old_state = __raw_readl(SMSM_STATE_ADDR(smsm_entry));
 	new_state = (old_state & ~clear_mask) | set_mask;
 	__raw_writel(new_state, SMSM_STATE_ADDR(smsm_entry));
-	SMSM_DBG("smsm_change_state %x\n", new_state);
+	SMx_POWER_INFO("%s %d:%08x->%08x", __func__, smsm_entry,
+			old_state, new_state);
 	notify_other_smsm(SMSM_APPS_STATE, (old_state ^ new_state));
 
 	spin_unlock_irqrestore(&smem_lock, flags);
@@ -3090,523 +3016,6 @@
 }
 EXPORT_SYMBOL(smsm_state_cb_deregister);
 
-int smd_core_init(void)
-{
-	int r;
-	unsigned long flags = IRQF_TRIGGER_RISING;
-	SMD_INFO("smd_core_init()\n");
-
-	r = request_irq(INT_A9_M2A_0, smd_modem_irq_handler,
-			flags, "smd_dev", 0);
-	if (r < 0)
-		return r;
-	interrupt_stats[SMD_MODEM].smd_interrupt_id = INT_A9_M2A_0;
-	r = enable_irq_wake(INT_A9_M2A_0);
-	if (r < 0)
-		pr_err("smd_core_init: "
-		       "enable_irq_wake failed for INT_A9_M2A_0\n");
-
-	r = request_irq(INT_A9_M2A_5, smsm_modem_irq_handler,
-			flags, "smsm_dev", 0);
-	if (r < 0) {
-		free_irq(INT_A9_M2A_0, 0);
-		return r;
-	}
-	interrupt_stats[SMD_MODEM].smsm_interrupt_id = INT_A9_M2A_5;
-	r = enable_irq_wake(INT_A9_M2A_5);
-	if (r < 0)
-		pr_err("smd_core_init: "
-		       "enable_irq_wake failed for INT_A9_M2A_5\n");
-
-#if defined(CONFIG_QDSP6)
-#if (INT_ADSP_A11 == INT_ADSP_A11_SMSM)
-		flags |= IRQF_SHARED;
-#endif
-	r = request_irq(INT_ADSP_A11, smd_dsp_irq_handler,
-			flags, "smd_dev", smd_dsp_irq_handler);
-	if (r < 0) {
-		free_irq(INT_A9_M2A_0, 0);
-		free_irq(INT_A9_M2A_5, 0);
-		return r;
-	}
-
-	interrupt_stats[SMD_Q6].smd_interrupt_id = INT_ADSP_A11;
-	r = request_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler,
-			flags, "smsm_dev", smsm_dsp_irq_handler);
-	if (r < 0) {
-		free_irq(INT_A9_M2A_0, 0);
-		free_irq(INT_A9_M2A_5, 0);
-		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
-		return r;
-	}
-
-	interrupt_stats[SMD_Q6].smsm_interrupt_id = INT_ADSP_A11_SMSM;
-	r = enable_irq_wake(INT_ADSP_A11);
-	if (r < 0)
-		pr_err("smd_core_init: "
-		       "enable_irq_wake failed for INT_ADSP_A11\n");
-
-#if (INT_ADSP_A11 != INT_ADSP_A11_SMSM)
-	r = enable_irq_wake(INT_ADSP_A11_SMSM);
-	if (r < 0)
-		pr_err("smd_core_init: enable_irq_wake "
-		       "failed for INT_ADSP_A11_SMSM\n");
-#endif
-	flags &= ~IRQF_SHARED;
-#endif
-
-#if defined(CONFIG_DSPS)
-	r = request_irq(INT_DSPS_A11, smd_dsps_irq_handler,
-			flags, "smd_dev", smd_dsps_irq_handler);
-	if (r < 0) {
-		free_irq(INT_A9_M2A_0, 0);
-		free_irq(INT_A9_M2A_5, 0);
-		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
-		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
-		return r;
-	}
-
-	interrupt_stats[SMD_DSPS].smd_interrupt_id = INT_DSPS_A11;
-	r = enable_irq_wake(INT_DSPS_A11);
-	if (r < 0)
-		pr_err("smd_core_init: "
-		       "enable_irq_wake failed for INT_ADSP_A11\n");
-#endif
-
-#if defined(CONFIG_WCNSS)
-	r = request_irq(INT_WCNSS_A11, smd_wcnss_irq_handler,
-			flags, "smd_dev", smd_wcnss_irq_handler);
-	if (r < 0) {
-		free_irq(INT_A9_M2A_0, 0);
-		free_irq(INT_A9_M2A_5, 0);
-		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
-		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
-		free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
-		return r;
-	}
-
-	interrupt_stats[SMD_WCNSS].smd_interrupt_id = INT_WCNSS_A11;
-	r = enable_irq_wake(INT_WCNSS_A11);
-	if (r < 0)
-		pr_err("smd_core_init: "
-		       "enable_irq_wake failed for INT_WCNSS_A11\n");
-
-	r = request_irq(INT_WCNSS_A11_SMSM, smsm_wcnss_irq_handler,
-			flags, "smsm_dev", smsm_wcnss_irq_handler);
-	if (r < 0) {
-		free_irq(INT_A9_M2A_0, 0);
-		free_irq(INT_A9_M2A_5, 0);
-		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
-		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
-		free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
-		free_irq(INT_WCNSS_A11, smd_wcnss_irq_handler);
-		return r;
-	}
-
-	interrupt_stats[SMD_WCNSS].smsm_interrupt_id = INT_WCNSS_A11_SMSM;
-	r = enable_irq_wake(INT_WCNSS_A11_SMSM);
-	if (r < 0)
-		pr_err("smd_core_init: "
-		       "enable_irq_wake failed for INT_WCNSS_A11_SMSM\n");
-#endif
-
-#if defined(CONFIG_DSPS_SMSM)
-	r = request_irq(INT_DSPS_A11_SMSM, smsm_dsps_irq_handler,
-			flags, "smsm_dev", smsm_dsps_irq_handler);
-	if (r < 0) {
-		free_irq(INT_A9_M2A_0, 0);
-		free_irq(INT_A9_M2A_5, 0);
-		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
-		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
-		free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
-		free_irq(INT_WCNSS_A11, smd_wcnss_irq_handler);
-		free_irq(INT_WCNSS_A11_SMSM, smsm_wcnss_irq_handler);
-		return r;
-	}
-
-	interrupt_stats[SMD_DSPS].smsm_interrupt_id = INT_DSPS_A11_SMSM;
-	r = enable_irq_wake(INT_DSPS_A11_SMSM);
-	if (r < 0)
-		pr_err("smd_core_init: "
-		       "enable_irq_wake failed for INT_DSPS_A11_SMSM\n");
-#endif
-	SMD_INFO("smd_core_init() done\n");
-
-	return 0;
-}
-
-static int intr_init(struct interrupt_config_item *private_irq,
-			struct smd_irq_config *platform_irq,
-			struct platform_device *pdev
-			)
-{
-	int irq_id;
-	int ret;
-	int ret_wake;
-
-	private_irq->out_bit_pos = platform_irq->out_bit_pos;
-	private_irq->out_offset = platform_irq->out_offset;
-	private_irq->out_base = platform_irq->out_base;
-
-	irq_id = platform_get_irq_byname(
-					pdev,
-					platform_irq->irq_name
-				);
-	SMD_DBG("smd: %s: register irq: %s id: %d\n", __func__,
-				platform_irq->irq_name, irq_id);
-	ret = request_irq(irq_id,
-				private_irq->irq_handler,
-				platform_irq->flags,
-				platform_irq->device_name,
-				(void *)platform_irq->dev_id
-			);
-	if (ret < 0) {
-		platform_irq->irq_id = ret;
-		private_irq->irq_id = ret;
-	} else {
-		platform_irq->irq_id = irq_id;
-		private_irq->irq_id = irq_id;
-		ret_wake = enable_irq_wake(irq_id);
-		if (ret_wake < 0) {
-			pr_err("smd: enable_irq_wake failed on %s",
-					platform_irq->irq_name);
-		}
-	}
-
-	return ret;
-}
-
-int smd_core_platform_init(struct platform_device *pdev)
-{
-	int i;
-	int ret;
-	uint32_t num_ss;
-	struct smd_platform *smd_platform_data;
-	struct smd_subsystem_config *smd_ss_config_list;
-	struct smd_subsystem_config *cfg;
-	int err_ret = 0;
-
-	smd_platform_data = pdev->dev.platform_data;
-	num_ss = smd_platform_data->num_ss_configs;
-	smd_ss_config_list = smd_platform_data->smd_ss_configs;
-
-	if (smd_platform_data->smd_ssr_config)
-		disable_smsm_reset_handshake = smd_platform_data->
-			   smd_ssr_config->disable_smsm_reset_handshake;
-
-	for (i = 0; i < num_ss; i++) {
-		cfg = &smd_ss_config_list[i];
-
-		ret = intr_init(
-			&private_intr_config[cfg->irq_config_id].smd,
-			&cfg->smd_int,
-			pdev
-			);
-
-		if (ret < 0) {
-			err_ret = ret;
-			pr_err("smd: register irq failed on %s\n",
-				cfg->smd_int.irq_name);
-			goto intr_failed;
-		}
-
-		interrupt_stats[cfg->irq_config_id].smd_interrupt_id
-						 = cfg->smd_int.irq_id;
-		/* only init smsm structs if this edge supports smsm */
-		if (cfg->smsm_int.irq_id)
-			ret = intr_init(
-				&private_intr_config[cfg->irq_config_id].smsm,
-				&cfg->smsm_int,
-				pdev
-				);
-
-		if (ret < 0) {
-			err_ret = ret;
-			pr_err("smd: register irq failed on %s\n",
-				cfg->smsm_int.irq_name);
-			goto intr_failed;
-		}
-
-		if (cfg->smsm_int.irq_id)
-			interrupt_stats[cfg->irq_config_id].smsm_interrupt_id
-						 = cfg->smsm_int.irq_id;
-		if (cfg->subsys_name)
-			strlcpy(edge_to_pids[cfg->edge].subsys_name,
-				cfg->subsys_name, SMD_MAX_CH_NAME_LEN);
-	}
-
-	SMD_INFO("smd_core_platform_init() done\n");
-
-	return 0;
-
-intr_failed:
-	pr_err("smd: deregistering IRQs\n");
-	for (i = 0; i < num_ss; ++i) {
-		cfg = &smd_ss_config_list[i];
-
-		if (cfg->smd_int.irq_id >= 0)
-			free_irq(cfg->smd_int.irq_id,
-				(void *)cfg->smd_int.dev_id
-				);
-		if (cfg->smsm_int.irq_id >= 0)
-			free_irq(cfg->smsm_int.irq_id,
-				(void *)cfg->smsm_int.dev_id
-				);
-	}
-	return err_ret;
-}
-
-static int msm_smsm_probe(struct platform_device *pdev)
-{
-	uint32_t edge;
-	char *key;
-	int ret;
-	uint32_t irq_offset;
-	uint32_t irq_bitmask;
-	uint32_t irq_line;
-	struct interrupt_config_item *private_irq;
-	struct device_node *node;
-	void *irq_out_base;
-	resource_size_t irq_out_size;
-	struct platform_device *parent_pdev;
-	struct resource *r;
-
-	disable_smsm_reset_handshake = 1;
-
-	node = pdev->dev.of_node;
-
-	if (!pdev->dev.parent) {
-		pr_err("%s: missing link to parent device\n", __func__);
-		return -ENODEV;
-	}
-
-	parent_pdev = to_platform_device(pdev->dev.parent);
-
-	key = "irq-reg-base";
-	r = platform_get_resource_byname(parent_pdev, IORESOURCE_MEM, key);
-	if (!r)
-		goto missing_key;
-	irq_out_size = resource_size(r);
-	irq_out_base = ioremap_nocache(r->start, irq_out_size);
-	if (!irq_out_base) {
-		pr_err("%s: ioremap_nocache() of irq_out_base addr:%pr size:%pr\n",
-				__func__, &r->start, &irq_out_size);
-		return -ENOMEM;
-	}
-	SMSM_DBG("%s: %s = %p", __func__, key, irq_out_base);
-
-	key = "qcom,smsm-edge";
-	ret = of_property_read_u32(node, key, &edge);
-	if (ret)
-		goto missing_key;
-	SMSM_DBG("%s: %s = %d", __func__, key, edge);
-
-	key = "qcom,smsm-irq-offset";
-	ret = of_property_read_u32(node, key, &irq_offset);
-	if (ret)
-		goto missing_key;
-	SMSM_DBG("%s: %s = %x", __func__, key, irq_offset);
-
-	key = "qcom,smsm-irq-bitmask";
-	ret = of_property_read_u32(node, key, &irq_bitmask);
-	if (ret)
-		goto missing_key;
-	SMSM_DBG("%s: %s = %x", __func__, key, irq_bitmask);
-
-	key = "interrupts";
-	irq_line = irq_of_parse_and_map(node, 0);
-	if (!irq_line)
-		goto missing_key;
-	SMSM_DBG("%s: %s = %d", __func__, key, irq_line);
-
-	private_irq = &private_intr_config[edge_to_pids[edge].remote_pid].smsm;
-	private_irq->out_bit_pos = irq_bitmask;
-	private_irq->out_offset = irq_offset;
-	private_irq->out_base = irq_out_base;
-	private_irq->irq_id = irq_line;
-
-	ret = request_irq(irq_line,
-				private_irq->irq_handler,
-				IRQF_TRIGGER_RISING,
-				"smsm_dev",
-				NULL);
-	if (ret < 0) {
-		pr_err("%s: request_irq() failed on %d\n", __func__, irq_line);
-		return ret;
-	} else {
-		ret = enable_irq_wake(irq_line);
-		if (ret < 0)
-			pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
-					irq_line);
-	}
-
-	if (smsm_init())
-		pr_err("smsm_init() failed\n");
-
-	smsm_irq_handler(0, 0);
-
-	return 0;
-
-missing_key:
-	pr_err("%s: missing key: %s", __func__, key);
-	return -ENODEV;
-}
-
-static int msm_smd_probe(struct platform_device *pdev)
-{
-	uint32_t edge;
-	char *key;
-	int ret;
-	uint32_t irq_offset;
-	uint32_t irq_bitmask;
-	uint32_t irq_line;
-	unsigned long irq_flags = IRQF_TRIGGER_RISING;
-	const char *pilstr;
-	struct interrupt_config_item *private_irq;
-	struct device_node *node;
-	void *irq_out_base;
-	resource_size_t irq_out_size;
-	struct platform_device *parent_pdev;
-	struct resource *r;
-
-	node = pdev->dev.of_node;
-
-	if (!pdev->dev.parent) {
-		pr_err("%s: missing link to parent device\n", __func__);
-		return -ENODEV;
-	}
-
-	parent_pdev = to_platform_device(pdev->dev.parent);
-
-	key = "irq-reg-base";
-	r = platform_get_resource_byname(parent_pdev, IORESOURCE_MEM, key);
-	if (!r)
-		goto missing_key;
-	irq_out_size = resource_size(r);
-	irq_out_base = ioremap_nocache(r->start, irq_out_size);
-	if (!irq_out_base) {
-		pr_err("%s: ioremap_nocache() of irq_out_base addr:%pr size:%pr\n",
-				__func__, &r->start, &irq_out_size);
-		return -ENOMEM;
-	}
-	SMD_DBG("%s: %s = %p", __func__, key, irq_out_base);
-
-	key = "qcom,smd-edge";
-	ret = of_property_read_u32(node, key, &edge);
-	if (ret)
-		goto missing_key;
-	SMD_DBG("%s: %s = %d", __func__, key, edge);
-
-	key = "qcom,smd-irq-offset";
-	ret = of_property_read_u32(node, key, &irq_offset);
-	if (ret)
-		goto missing_key;
-	SMD_DBG("%s: %s = %x", __func__, key, irq_offset);
-
-	key = "qcom,smd-irq-bitmask";
-	ret = of_property_read_u32(node, key, &irq_bitmask);
-	if (ret)
-		goto missing_key;
-	SMD_DBG("%s: %s = %x", __func__, key, irq_bitmask);
-
-	key = "interrupts";
-	irq_line = irq_of_parse_and_map(node, 0);
-	if (!irq_line)
-		goto missing_key;
-	SMD_DBG("%s: %s = %d", __func__, key, irq_line);
-
-	key = "qcom,pil-string";
-	pilstr = of_get_property(node, key, NULL);
-	if (pilstr)
-		SMD_DBG("%s: %s = %s", __func__, key, pilstr);
-
-	key = "qcom,irq-no-suspend";
-	ret = of_property_read_bool(node, key);
-	if (ret)
-		irq_flags |= IRQF_NO_SUSPEND;
-
-	private_irq = &private_intr_config[edge_to_pids[edge].remote_pid].smd;
-	private_irq->out_bit_pos = irq_bitmask;
-	private_irq->out_offset = irq_offset;
-	private_irq->out_base = irq_out_base;
-	private_irq->irq_id = irq_line;
-
-	ret = request_irq(irq_line,
-				private_irq->irq_handler,
-				irq_flags,
-				"smd_dev",
-				NULL);
-	if (ret < 0) {
-		pr_err("%s: request_irq() failed on %d\n", __func__, irq_line);
-		return ret;
-	} else {
-		ret = enable_irq_wake(irq_line);
-		if (ret < 0)
-			pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
-					irq_line);
-	}
-
-	if (pilstr)
-		strlcpy(edge_to_pids[edge].subsys_name, pilstr,
-						SMD_MAX_CH_NAME_LEN);
-
-	edge_to_pids[edge].initialized = true;
-
-	schedule_work(&probe_work);
-
-	return 0;
-
-missing_key:
-	pr_err("%s: missing key: %s", __func__, key);
-	return -ENODEV;
-}
-
-static int msm_smd_probe_legacy(struct platform_device *pdev)
-{
-	int ret;
-
-	if (!smem_initialized_check())
-		return -ENODEV;
-
-	SMD_INFO("smd probe\n");
-
-	if (smsm_init()) {
-		pr_err("smsm_init() failed\n");
-		return -1;
-	}
-
-	if (pdev) {
-		if (pdev->dev.of_node) {
-			pr_err("%s: invalid device tree init\n", __func__);
-			return -ENODEV;
-		} else if (pdev->dev.platform_data) {
-			ret = smd_core_platform_init(pdev);
-			if (ret) {
-				pr_err(
-				"SMD: smd_core_platform_init() failed\n");
-				return -ENODEV;
-			}
-		} else {
-			ret = smd_core_init();
-			if (ret) {
-				pr_err("smd_core_init() failed\n");
-				return -ENODEV;
-			}
-		}
-	} else {
-		pr_err("SMD: PDEV not found\n");
-		return -ENODEV;
-	}
-
-	smd_initialized = 1;
-
-	smd_alloc_loopback_channel();
-	smsm_irq_handler(0, 0);
-	tasklet_schedule(&smd_fake_irq_tasklet);
-
-	return 0;
-}
-
 static int restart_notifier_cb(struct notifier_block *this,
 				  unsigned long code,
 				  void *data);
@@ -3650,6 +3059,137 @@
 	return NOTIFY_DONE;
 }
 
+/**
+ * smd_post_init() - SMD post initialization
+ * @is_leagcy:	1 for Leagcy/platform device init sequence
+ *		0 for device tree init sequence
+ *
+ * This function is used by the legacy and device tree initialization
+ * to complete the SMD init sequence.
+ */
+void smd_post_init(bool is_legacy)
+{
+	if (is_legacy) {
+		smd_initialized = 1;
+		smd_alloc_loopback_channel();
+		tasklet_schedule(&smd_fake_irq_tasklet);
+	} else {
+		schedule_work(&probe_work);
+	}
+}
+
+/**
+ * smsm_post_init() - SMSM post initialization
+ * @returns:	0 for success, standard Linux error code otherwise
+ *
+ * This function is used by the legacy and device tree initialization
+ * to complete the SMSM init sequence.
+ */
+int smsm_post_init(void)
+{
+	int ret;
+
+	ret = smsm_init();
+	if (ret) {
+		pr_err("smsm_init() failed ret = %d\n", ret);
+		return ret;
+	}
+	smsm_irq_handler(0, 0);
+
+	return ret;
+}
+
+/**
+ * smd_get_intr_config() - Get interrupt configuration structure
+ * @edge:	edge type identifes local and remote processor
+ * @returns:	pointer to interrupt configuration
+ *
+ * This function returns the interrupt configuration of remote processor
+ * based on the edge type.
+ */
+struct interrupt_config *smd_get_intr_config(uint32_t edge)
+{
+	if (edge >= ARRAY_SIZE(edge_to_pids))
+		return NULL;
+	return &private_intr_config[edge_to_pids[edge].remote_pid];
+}
+
+/**
+ * smd_get_edge_remote_pid() - Get the remote processor ID
+ * @edge:	edge type identifes local and remote processor
+ * @returns:	remote processor ID
+ *
+ * This function returns remote processor ID based on edge type.
+ */
+int smd_edge_to_remote_pid(uint32_t edge)
+{
+	if (edge >= ARRAY_SIZE(edge_to_pids))
+		return -EINVAL;
+	return edge_to_pids[edge].remote_pid;
+}
+
+/**
+ * smd_set_edge_subsys_name() - Set the subsystem name
+ * @edge:		edge type identifies local and remote processor
+ * @sussys_name:	pointer to subsystem name
+ *
+ * This function is used to set the subsystem name for given edge type.
+ */
+void smd_set_edge_subsys_name(uint32_t edge, const char *subsys_name)
+{
+	if (edge <= ARRAY_SIZE(edge_to_pids))
+		strlcpy(edge_to_pids[edge].subsys_name,
+			subsys_name, SMD_MAX_CH_NAME_LEN);
+	else
+		pr_err("%s: Invalid edge type[%d]\n", __func__, edge);
+}
+
+/**
+ * smd_set_edge_initialized() - Set the edge initialized status
+ * @edge:	edge type identifies local and remote processor
+ *
+ * This function set the initialized varibale based on edge type.
+ */
+void smd_set_edge_initialized(uint32_t edge)
+{
+	if (edge <= ARRAY_SIZE(edge_to_pids))
+		edge_to_pids[edge].initialized = true;
+	else
+		pr_err("%s: Invalid edge type[%d]\n", __func__, edge);
+}
+
+/**
+ * smd_cfg_smd_intr() - Set the SMD interrupt configuration
+ * @proc:	remote processor ID
+ * @mask:	bit position in IRQ register
+ * @ptr:	IRQ register
+ *
+ * This function is called in Legacy init sequence and used to set
+ * the SMD interrupt configurations for particular processor.
+ */
+void smd_cfg_smd_intr(uint32_t proc, uint32_t mask, void *ptr)
+{
+	private_intr_config[proc].smd.out_bit_pos = mask;
+	private_intr_config[proc].smd.out_base = ptr;
+	private_intr_config[proc].smd.out_offset = 0;
+}
+
+/*
+ * smd_cfg_smsm_intr() -  Set the SMSM interrupt configuration
+ * @proc:	remote processor ID
+ * @mask:	bit position in IRQ register
+ * @ptr:	IRQ register
+ *
+ * This function is called in Legacy init sequence and used to set
+ * the SMSM interrupt configurations for particular processor.
+ */
+void smd_cfg_smsm_intr(uint32_t proc, uint32_t mask, void *ptr)
+{
+	private_intr_config[proc].smsm.out_bit_pos = mask;
+	private_intr_config[proc].smsm.out_base = ptr;
+	private_intr_config[proc].smsm.out_offset = 0;
+}
+
 static __init int modem_restart_late_init(void)
 {
 	int i;
@@ -3667,42 +3207,6 @@
 }
 late_initcall(modem_restart_late_init);
 
-static struct of_device_id msm_smd_match_table[] = {
-	{ .compatible = "qcom,smd" },
-	{},
-};
-
-static struct platform_driver msm_smd_driver = {
-	.probe = msm_smd_probe,
-	.driver = {
-		.name = "msm_smd_dt",
-		.owner = THIS_MODULE,
-		.of_match_table = msm_smd_match_table,
-	},
-};
-
-static struct of_device_id msm_smsm_match_table[] = {
-	{ .compatible = "qcom,smsm" },
-	{},
-};
-
-static struct platform_driver msm_smsm_driver = {
-	.probe = msm_smsm_probe,
-	.driver = {
-		.name = "msm_smsm",
-		.owner = THIS_MODULE,
-		.of_match_table = msm_smsm_match_table,
-	},
-};
-
-static struct platform_driver msm_smd_driver_legacy = {
-	.probe = msm_smd_probe_legacy,
-	.driver = {
-		.name = MODULE_NAME,
-		.owner = THIS_MODULE,
-	},
-};
-
 int __init msm_smd_init(void)
 {
 	static bool registered;
@@ -3727,27 +3231,12 @@
 		return -ENOMEM;
 	}
 
-	rc = platform_driver_register(&msm_smd_driver_legacy);
-	if (rc) {
-		pr_err("%s: msm_smd_driver_legacy register failed %d\n",
-			__func__, rc);
-		return rc;
-	}
-
-	rc = platform_driver_register(&msm_smd_driver);
+	rc = msm_smd_driver_register();
 	if (rc) {
 		pr_err("%s: msm_smd_driver register failed %d\n",
 			__func__, rc);
 		return rc;
 	}
-
-	rc = platform_driver_register(&msm_smsm_driver);
-	if (rc) {
-		pr_err("%s: msm_smsm_driver register failed %d\n",
-			__func__, rc);
-		return rc;
-	}
-
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/smd_init_dt.c b/arch/arm/mach-msm/smd_init_dt.c
new file mode 100644
index 0000000..d888a72
--- /dev/null
+++ b/arch/arm/mach-msm/smd_init_dt.c
@@ -0,0 +1,322 @@
+/* arch/arm/mach-msm/smd_init_dt.c
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifdef CONFIG_OF
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <mach/msm_ipc_logging.h>
+#include <smd_private.h>
+
+#define MODULE_NAME "msm_smd"
+#define IPC_LOG(level, x...) do { \
+	if (smd_log_ctx) \
+		ipc_log_string(smd_log_ctx, x); \
+	else \
+		printk(level x); \
+	} while (0)
+
+#if defined(CONFIG_MSM_SMD_DEBUG)
+#define SMD_DBG(x...) do {				\
+		if (msm_smd_debug_mask & MSM_SMD_DEBUG) \
+			IPC_LOG(KERN_DEBUG, x);		\
+	} while (0)
+
+#define SMSM_DBG(x...) do {					\
+		if (msm_smd_debug_mask & MSM_SMSM_DEBUG)	\
+			IPC_LOG(KERN_DEBUG, x);		\
+	} while (0)
+#else
+#define SMD_DBG(x...) do { } while (0)
+#define SMSM_DBG(x...) do { } while (0)
+#endif
+
+static int msm_smsm_probe(struct platform_device *pdev)
+{
+	uint32_t edge;
+	char *key;
+	int ret;
+	uint32_t irq_offset;
+	uint32_t irq_bitmask;
+	uint32_t irq_line;
+	struct interrupt_config_item *private_irq;
+	struct device_node *node;
+	void *irq_out_base;
+	resource_size_t irq_out_size;
+	struct platform_device *parent_pdev;
+	struct resource *r;
+	struct interrupt_config *private_intr_config;
+	uint32_t remote_pid;
+
+	disable_smsm_reset_handshake = 1;
+
+	node = pdev->dev.of_node;
+
+	if (!pdev->dev.parent) {
+		pr_err("%s: missing link to parent device\n", __func__);
+		return -ENODEV;
+	}
+
+	parent_pdev = to_platform_device(pdev->dev.parent);
+
+	key = "irq-reg-base";
+	r = platform_get_resource_byname(parent_pdev, IORESOURCE_MEM, key);
+	if (!r)
+		goto missing_key;
+	irq_out_size = resource_size(r);
+	irq_out_base = ioremap_nocache(r->start, irq_out_size);
+	if (!irq_out_base) {
+		pr_err("%s: ioremap_nocache() of irq_out_base addr:%pr size:%pr\n",
+				__func__, &r->start, &irq_out_size);
+		return -ENOMEM;
+	}
+	SMSM_DBG("%s: %s = %p", __func__, key, irq_out_base);
+
+	key = "qcom,smsm-edge";
+	ret = of_property_read_u32(node, key, &edge);
+	if (ret)
+		goto missing_key;
+	SMSM_DBG("%s: %s = %d", __func__, key, edge);
+
+	key = "qcom,smsm-irq-offset";
+	ret = of_property_read_u32(node, key, &irq_offset);
+	if (ret)
+		goto missing_key;
+	SMSM_DBG("%s: %s = %x", __func__, key, irq_offset);
+
+	key = "qcom,smsm-irq-bitmask";
+	ret = of_property_read_u32(node, key, &irq_bitmask);
+	if (ret)
+		goto missing_key;
+	SMSM_DBG("%s: %s = %x", __func__, key, irq_bitmask);
+
+	key = "interrupts";
+	irq_line = irq_of_parse_and_map(node, 0);
+	if (!irq_line)
+		goto missing_key;
+	SMSM_DBG("%s: %s = %d", __func__, key, irq_line);
+
+	private_intr_config = smd_get_intr_config(edge);
+	if (!private_intr_config) {
+		pr_err("%s: invalid edge\n", __func__);
+		return -ENODEV;
+	}
+	private_irq = &private_intr_config->smsm;
+	private_irq->out_bit_pos = irq_bitmask;
+	private_irq->out_offset = irq_offset;
+	private_irq->out_base = irq_out_base;
+	private_irq->irq_id = irq_line;
+	remote_pid = smd_edge_to_remote_pid(edge);
+	interrupt_stats[remote_pid].smsm_interrupt_id = irq_line;
+
+	ret = request_irq(irq_line,
+				private_irq->irq_handler,
+				IRQF_TRIGGER_RISING,
+				"smsm_dev",
+				NULL);
+	if (ret < 0) {
+		pr_err("%s: request_irq() failed on %d\n", __func__, irq_line);
+		return ret;
+	} else {
+		ret = enable_irq_wake(irq_line);
+		if (ret < 0)
+			pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
+					irq_line);
+	}
+
+	ret = smsm_post_init();
+	if (ret) {
+		pr_err("smd_post_init() failed ret=%d\n", ret);
+		return ret;
+	}
+
+	return 0;
+
+missing_key:
+	pr_err("%s: missing key: %s", __func__, key);
+	return -ENODEV;
+}
+
+static int msm_smd_probe(struct platform_device *pdev)
+{
+	uint32_t edge;
+	char *key;
+	int ret;
+	uint32_t irq_offset;
+	uint32_t irq_bitmask;
+	uint32_t irq_line;
+	unsigned long irq_flags = IRQF_TRIGGER_RISING;
+	const char *pilstr;
+	struct interrupt_config_item *private_irq;
+	struct device_node *node;
+	void *irq_out_base;
+	resource_size_t irq_out_size;
+	struct platform_device *parent_pdev;
+	struct resource *r;
+	struct interrupt_config *private_intr_config;
+	uint32_t remote_pid;
+
+	node = pdev->dev.of_node;
+
+	if (!pdev->dev.parent) {
+		pr_err("%s: missing link to parent device\n", __func__);
+		return -ENODEV;
+	}
+
+	parent_pdev = to_platform_device(pdev->dev.parent);
+
+	key = "irq-reg-base";
+	r = platform_get_resource_byname(parent_pdev, IORESOURCE_MEM, key);
+	if (!r)
+		goto missing_key;
+	irq_out_size = resource_size(r);
+	irq_out_base = ioremap_nocache(r->start, irq_out_size);
+	if (!irq_out_base) {
+		pr_err("%s: ioremap_nocache() of irq_out_base addr:%pr size:%pr\n",
+				__func__, &r->start, &irq_out_size);
+		return -ENOMEM;
+	}
+	SMD_DBG("%s: %s = %p", __func__, key, irq_out_base);
+
+	key = "qcom,smd-edge";
+	ret = of_property_read_u32(node, key, &edge);
+	if (ret)
+		goto missing_key;
+	SMD_DBG("%s: %s = %d", __func__, key, edge);
+
+	key = "qcom,smd-irq-offset";
+	ret = of_property_read_u32(node, key, &irq_offset);
+	if (ret)
+		goto missing_key;
+	SMD_DBG("%s: %s = %x", __func__, key, irq_offset);
+
+	key = "qcom,smd-irq-bitmask";
+	ret = of_property_read_u32(node, key, &irq_bitmask);
+	if (ret)
+		goto missing_key;
+	SMD_DBG("%s: %s = %x", __func__, key, irq_bitmask);
+
+	key = "interrupts";
+	irq_line = irq_of_parse_and_map(node, 0);
+	if (!irq_line)
+		goto missing_key;
+	SMD_DBG("%s: %s = %d", __func__, key, irq_line);
+
+	key = "qcom,pil-string";
+	pilstr = of_get_property(node, key, NULL);
+	if (pilstr)
+		SMD_DBG("%s: %s = %s", __func__, key, pilstr);
+
+	key = "qcom,irq-no-suspend";
+	ret = of_property_read_bool(node, key);
+	if (ret)
+		irq_flags |= IRQF_NO_SUSPEND;
+
+	private_intr_config = smd_get_intr_config(edge);
+	if (!private_intr_config) {
+		pr_err("%s: invalid edge\n", __func__);
+		return -ENODEV;
+	}
+	private_irq = &private_intr_config->smd;
+	private_irq->out_bit_pos = irq_bitmask;
+	private_irq->out_offset = irq_offset;
+	private_irq->out_base = irq_out_base;
+	private_irq->irq_id = irq_line;
+	remote_pid = smd_edge_to_remote_pid(edge);
+	interrupt_stats[remote_pid].smd_interrupt_id = irq_line;
+
+	ret = request_irq(irq_line,
+				private_irq->irq_handler,
+				irq_flags,
+				"smd_dev",
+				NULL);
+	if (ret < 0) {
+		pr_err("%s: request_irq() failed on %d\n", __func__, irq_line);
+		return ret;
+	} else {
+		ret = enable_irq_wake(irq_line);
+		if (ret < 0)
+			pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
+					irq_line);
+	}
+
+	if (pilstr)
+		smd_set_edge_subsys_name(edge, pilstr);
+
+	smd_set_edge_initialized(edge);
+	smd_post_init(0);
+	return 0;
+
+missing_key:
+	pr_err("%s: missing key: %s", __func__, key);
+	return -ENODEV;
+}
+
+static struct of_device_id msm_smd_match_table[] = {
+	{ .compatible = "qcom,smd" },
+	{},
+};
+
+static struct platform_driver msm_smd_driver = {
+	.probe = msm_smd_probe,
+	.driver = {
+		.name = MODULE_NAME ,
+		.owner = THIS_MODULE,
+		.of_match_table = msm_smd_match_table,
+	},
+};
+
+static struct of_device_id msm_smsm_match_table[] = {
+	{ .compatible = "qcom,smsm" },
+	{},
+};
+
+static struct platform_driver msm_smsm_driver = {
+	.probe = msm_smsm_probe,
+	.driver = {
+		.name = "msm_smsm",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_smsm_match_table,
+	},
+};
+
+int msm_smd_driver_register(void)
+{
+	int rc;
+
+	rc = platform_driver_register(&msm_smd_driver);
+	if (rc) {
+		pr_err("%s: smd_driver register failed %d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	rc = platform_driver_register(&msm_smsm_driver);
+	if (rc) {
+		pr_err("%s: msm_smsm_driver register failed %d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_smd_driver_register);
+
+MODULE_DESCRIPTION("MSM SMD Device Tree Init");
+MODULE_LICENSE("GPL v2");
+#endif
diff --git a/arch/arm/mach-msm/smd_init_plat.c b/arch/arm/mach-msm/smd_init_plat.c
new file mode 100644
index 0000000..c6f6cd9
--- /dev/null
+++ b/arch/arm/mach-msm/smd_init_plat.c
@@ -0,0 +1,535 @@
+/* arch/arm/mach-msm/smd_init_plat.c
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef CONFIG_OF
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/msm_ipc_logging.h>
+#include <smd_private.h>
+
+#define MODULE_NAME "msm_smd"
+#define IPC_LOG(level, x...) do { \
+	if (smd_log_ctx) \
+		ipc_log_string(smd_log_ctx, x); \
+	else \
+		printk(level x); \
+	} while (0)
+
+#if defined(CONFIG_MSM_SMD_DEBUG)
+#define SMD_DBG(x...) do {				\
+		if (msm_smd_debug_mask & MSM_SMD_DEBUG) \
+			IPC_LOG(KERN_DEBUG, x);		\
+	} while (0)
+
+#define SMD_INFO(x...) do {				\
+		if (msm_smd_debug_mask & MSM_SMD_INFO)	\
+			IPC_LOG(KERN_INFO, x);		\
+	} while (0)
+#else
+#define SMD_DBG(x...) do { } while (0)
+#define SMD_INFO(x...) do { } while (0)
+#endif
+
+#if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM8X60) \
+	|| defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_FSM9XXX) \
+	|| defined(CONFIG_ARCH_MSM9615)	|| defined(CONFIG_ARCH_APQ8064)
+#define CONFIG_QDSP6 1
+#endif
+
+#if defined(CONFIG_ARCH_MSM8X60) || defined(CONFIG_ARCH_MSM8960) \
+	|| defined(CONFIG_ARCH_APQ8064)
+#define CONFIG_DSPS 1
+#endif
+
+#if defined(CONFIG_ARCH_MSM8960) \
+	|| defined(CONFIG_ARCH_APQ8064)
+#define CONFIG_WCNSS 1
+#define CONFIG_DSPS_SMSM 1
+#endif
+
+#if defined(CONFIG_ARCH_MSM7X30)
+#define MSM_CFG_A2M_SMD_INT     \
+		(smd_cfg_smd_intr(SMD_MODEM, 1 << 0, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_CFG_A2Q6_SMD_INT    \
+		(smd_cfg_smd_intr(SMD_Q6, 1 << 8, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_CFG_A2M_SMSM_INT    \
+		(smd_cfg_smsm_intr(SMD_MODEM, 1 << 5, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_CFG_A2Q6_SMSM_INT   \
+		(smd_cfg_smsm_intr(SMD_Q6, 1 << 8, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_CFG_A2DSPS_SMD_INT
+#define MSM_CFG_A2DSPS_SMSM_INT
+#define MSM_CFG_A2WCNSS_SMD_INT
+#define MSM_CFG_A2WCNSS_SMSM_INT
+#elif defined(CONFIG_ARCH_MSM8X60)
+#define MSM_CFG_A2M_SMD_INT     \
+		(smd_cfg_smd_intr(SMD_MODEM, 1 << 3, MSM_GCC_BASE + 0x8))
+#define MSM_CFG_A2Q6_SMD_INT    \
+		(smd_cfg_smd_intr(SMD_Q6, 1 << 15, MSM_GCC_BASE + 0x8))
+#define MSM_CFG_A2M_SMSM_INT    \
+		(smd_cfg_smsm_intr(SMD_MODEM, 1 << 4, MSM_GCC_BASE + 0x8))
+#define MSM_CFG_A2Q6_SMSM_INT   \
+		(smd_cfg_smsm_intr(SMD_Q6, 1 << 14, MSM_GCC_BASE + 0x8))
+#define MSM_CFG_A2DSPS_SMD_INT  \
+		(smd_cfg_smd_intr(SMD_DSPS, 1,		\
+					MSM_SIC_NON_SECURE_BASE + 0x4080))
+#define MSM_CFG_A2DSPS_SMSM_INT
+#define MSM_CFG_A2WCNSS_SMD_INT
+#define MSM_CFG_A2WCNSS_SMSM_INT
+#elif defined(CONFIG_ARCH_MSM9615)
+#define MSM_CFG_A2M_SMD_INT     \
+		(smd_cfg_smd_intr(SMD_MODEM, 1 << 3, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_CFG_A2Q6_SMD_INT    \
+		(smd_cfg_smd_intr(SMD_Q6, 1 << 15, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_CFG_A2M_SMSM_INT    \
+		(smd_cfg_smsm_intr(SMD_MODEM, 1 << 4, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_CFG_A2Q6_SMSM_INT   \
+		(smd_cfg_smsm_intr(SMD_Q6, 1 << 14, MSM_APCS_GCC_BASE + 0x8))
+#define MSM_CFG_A2DSPS_SMD_INT
+#define MSM_CFG_A2DSPS_SMSM_INT
+#define MSM_CFG_A2WCNSS_SMD_INT
+#define MSM_CFG_A2WCNSS_SMSM_INT
+#elif defined(CONFIG_ARCH_FSM9XXX)
+#define MSM_CFG_A2Q6_SMD_INT	\
+		(smd_cfg_smd_intr(SMD_Q6, 1 << 10, MSM_GCC_BASE + 0x8))
+#define MSM_CFG_A2Q6_SMSM_INT	\
+		(smd_cfg_smsm_intr(SMD_Q6, 1 << 10, MSM_GCC_BASE + 0x8))
+#define MSM_CFG_A2M_SMD_INT	\
+		(smd_cfg_smd_intr(SMD_MODEM, 1 << 0, MSM_GCC_BASE + 0x8))
+#define MSM_CFG_A2M_SMSM_INT	\
+		(smd_cfg_smsm_intr(SMD_MODEM, 1 << 5, MSM_GCC_BASE + 0x8))
+#define MSM_CFG_A2DSPS_SMD_INT
+#define MSM_CFG_A2DSPS_SMSM_INT
+#define MSM_CFG_A2WCNSS_SMD_INT
+#define MSM_CFG_A2WCNSS_SMSM_INT
+#elif defined(CONFIG_ARCH_MSM7X01A) || defined(CONFIG_ARCH_MSM7x25)
+#define MSM_CFG_A2M_SMD_INT     \
+		(smd_cfg_smd_intr(SMD_MODEM, 1, MSM_CSR_BASE + 0x400 + (0) * 4))
+#define MSM_CFG_A2Q6_SMD_INT
+#define MSM_CFG_A2M_SMSM_INT    \
+		(smd_cfg_smsm_intr(SMD_MODEM, 1,	\
+					MSM_CSR_BASE + 0x400 + (5) * 4))
+#define MSM_CFG_A2Q6_SMSM_INT
+#define MSM_CFG_A2DSPS_SMD_INT
+#define MSM_CFG_A2DSPS_SMSM_INT
+#define MSM_CFG_A2WCNSS_SMD_INT
+#define MSM_CFG_A2WCNSS_SMSM_INT
+#elif defined(CONFIG_ARCH_MSM7X27) || defined(CONFIG_ARCH_MSM7X27A)
+#define MSM_CFG_A2M_SMD_INT     \
+		(smd_cfg_smd_intr(SMD_MODEM, 1, MSM_CSR_BASE + 0x400 + (0) * 4))
+#define MSM_CFG_A2Q6_SMD_INT
+#define MSM_CFG_A2M_SMSM_INT    \
+		(smd_cfg_smsm_intr(SMD_MODEM, 1,	\
+					MSM_CSR_BASE + 0x400 + (5) * 4))
+#define MSM_CFG_A2Q6_SMSM_INT
+#define MSM_CFG_A2DSPS_SMD_INT
+#define MSM_CFG_A2DSPS_SMSM_INT
+#define MSM_CFG_A2WCNSS_SMD_INT
+#define MSM_CFG_A2WCNSS_SMSM_INT
+#else /* use platform device / device tree configuration */
+#define MSM_CFG_A2M_SMD_INT
+#define MSM_CFG_A2Q6_SMD_INT
+#define MSM_CFG_A2M_SMSM_INT
+#define MSM_CFG_A2Q6_SMSM_INT
+#define MSM_CFG_A2DSPS_SMD_INT
+#define MSM_CFG_A2DSPS_SMSM_INT
+#define MSM_CFG_A2WCNSS_SMD_INT
+#define MSM_CFG_A2WCNSS_SMSM_INT
+#endif
+
+/*
+ * stub out legacy macros if they are not being used so that the legacy
+ * code compiles even though it is not used
+ *
+ * these definitions should not be used in active code and will cause
+ * an early failure
+ */
+#ifndef INT_A9_M2A_0
+#define INT_A9_M2A_0 -1
+#endif
+#ifndef INT_A9_M2A_5
+#define INT_A9_M2A_5 -1
+#endif
+#ifndef INT_ADSP_A11
+#define INT_ADSP_A11 -1
+#endif
+#ifndef INT_ADSP_A11_SMSM
+#define INT_ADSP_A11_SMSM -1
+#endif
+#ifndef INT_DSPS_A11
+#define INT_DSPS_A11 -1
+#endif
+#ifndef INT_DSPS_A11_SMSM
+#define INT_DSPS_A11_SMSM -1
+#endif
+#ifndef INT_WCNSS_A11
+#define INT_WCNSS_A11 -1
+#endif
+#ifndef INT_WCNSS_A11_SMSM
+#define INT_WCNSS_A11_SMSM -1
+#endif
+
+static int intr_init(struct interrupt_config_item *private_irq,
+			struct smd_irq_config *platform_irq,
+			struct platform_device *pdev
+			)
+{
+	int irq_id;
+	int ret;
+	int ret_wake;
+
+	private_irq->out_bit_pos = platform_irq->out_bit_pos;
+	private_irq->out_offset = platform_irq->out_offset;
+	private_irq->out_base = platform_irq->out_base;
+
+	irq_id = platform_get_irq_byname(
+					pdev,
+					platform_irq->irq_name
+				);
+	SMD_DBG("smd: %s: register irq: %s id: %d\n", __func__,
+				platform_irq->irq_name, irq_id);
+	ret = request_irq(irq_id,
+				private_irq->irq_handler,
+				platform_irq->flags,
+				platform_irq->device_name,
+				(void *)platform_irq->dev_id
+			);
+	if (ret < 0) {
+		platform_irq->irq_id = ret;
+		private_irq->irq_id = ret;
+	} else {
+		platform_irq->irq_id = irq_id;
+		private_irq->irq_id = irq_id;
+		ret_wake = enable_irq_wake(irq_id);
+		if (ret_wake < 0) {
+			pr_err("smd: enable_irq_wake failed on %s",
+					platform_irq->irq_name);
+		}
+	}
+
+	return ret;
+}
+
+int smd_core_init(void)
+{
+	int r;
+	unsigned long flags = IRQF_TRIGGER_RISING;
+	SMD_INFO("smd_core_init()\n");
+
+	MSM_CFG_A2M_SMD_INT;
+	MSM_CFG_A2Q6_SMD_INT;
+	MSM_CFG_A2M_SMSM_INT;
+	MSM_CFG_A2Q6_SMSM_INT;
+	MSM_CFG_A2DSPS_SMD_INT;
+	MSM_CFG_A2DSPS_SMSM_INT;
+	MSM_CFG_A2WCNSS_SMD_INT;
+	MSM_CFG_A2WCNSS_SMSM_INT;
+
+	r = request_irq(INT_A9_M2A_0, smd_modem_irq_handler,
+			flags, "smd_dev", 0);
+	if (r < 0)
+		return r;
+	interrupt_stats[SMD_MODEM].smd_interrupt_id = INT_A9_M2A_0;
+	r = enable_irq_wake(INT_A9_M2A_0);
+	if (r < 0)
+		pr_err("%s: enable_irq_wake failed for INT_A9_M2A_0\n",
+			__func__);
+
+	r = request_irq(INT_A9_M2A_5, smsm_modem_irq_handler,
+			flags, "smsm_dev", 0);
+	if (r < 0) {
+		free_irq(INT_A9_M2A_0, 0);
+		return r;
+	}
+	interrupt_stats[SMD_MODEM].smsm_interrupt_id = INT_A9_M2A_5;
+	r = enable_irq_wake(INT_A9_M2A_5);
+	if (r < 0)
+		pr_err("%s: enable_irq_wake failed for INT_A9_M2A_5\n",
+			__func__);
+
+#if defined(CONFIG_QDSP6)
+#if (INT_ADSP_A11 == INT_ADSP_A11_SMSM)
+		flags |= IRQF_SHARED;
+#endif
+	r = request_irq(INT_ADSP_A11, smd_dsp_irq_handler,
+			flags, "smd_dev", smd_dsp_irq_handler);
+	if (r < 0) {
+		free_irq(INT_A9_M2A_0, 0);
+		free_irq(INT_A9_M2A_5, 0);
+		return r;
+	}
+
+	interrupt_stats[SMD_Q6].smd_interrupt_id = INT_ADSP_A11;
+	r = request_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler,
+			flags, "smsm_dev", smsm_dsp_irq_handler);
+	if (r < 0) {
+		free_irq(INT_A9_M2A_0, 0);
+		free_irq(INT_A9_M2A_5, 0);
+		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
+		return r;
+	}
+
+	interrupt_stats[SMD_Q6].smsm_interrupt_id = INT_ADSP_A11_SMSM;
+	r = enable_irq_wake(INT_ADSP_A11);
+	if (r < 0)
+		pr_err("%s: enable_irq_wake failed for INT_ADSP_A11\n",
+			__func__);
+
+#if (INT_ADSP_A11 != INT_ADSP_A11_SMSM)
+	r = enable_irq_wake(INT_ADSP_A11_SMSM);
+	if (r < 0)
+		pr_err("%s: enable_irq_wake failed for INT_ADSP_A11_SMSM\n",
+			__func__);
+#endif
+	flags &= ~IRQF_SHARED;
+#endif
+
+#if defined(CONFIG_DSPS)
+	r = request_irq(INT_DSPS_A11, smd_dsps_irq_handler,
+			flags, "smd_dev", smd_dsps_irq_handler);
+	if (r < 0) {
+		free_irq(INT_A9_M2A_0, 0);
+		free_irq(INT_A9_M2A_5, 0);
+		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
+		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
+		return r;
+	}
+
+	interrupt_stats[SMD_DSPS].smd_interrupt_id = INT_DSPS_A11;
+	r = enable_irq_wake(INT_DSPS_A11);
+	if (r < 0)
+		pr_err("%s: enable_irq_wake failed for INT_ADSP_A11\n",
+			__func__);
+#endif
+
+#if defined(CONFIG_WCNSS)
+	r = request_irq(INT_WCNSS_A11, smd_wcnss_irq_handler,
+			flags, "smd_dev", smd_wcnss_irq_handler);
+	if (r < 0) {
+		free_irq(INT_A9_M2A_0, 0);
+		free_irq(INT_A9_M2A_5, 0);
+		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
+		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
+		free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
+		return r;
+	}
+
+	interrupt_stats[SMD_WCNSS].smd_interrupt_id = INT_WCNSS_A11;
+	r = enable_irq_wake(INT_WCNSS_A11);
+	if (r < 0)
+		pr_err("%s: enable_irq_wake failed for INT_WCNSS_A11\n",
+			__func__);
+
+	r = request_irq(INT_WCNSS_A11_SMSM, smsm_wcnss_irq_handler,
+			flags, "smsm_dev", smsm_wcnss_irq_handler);
+	if (r < 0) {
+		free_irq(INT_A9_M2A_0, 0);
+		free_irq(INT_A9_M2A_5, 0);
+		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
+		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
+		free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
+		free_irq(INT_WCNSS_A11, smd_wcnss_irq_handler);
+		return r;
+	}
+
+	interrupt_stats[SMD_WCNSS].smsm_interrupt_id = INT_WCNSS_A11_SMSM;
+	r = enable_irq_wake(INT_WCNSS_A11_SMSM);
+	if (r < 0)
+		pr_err("%s: enable_irq_wake failed for INT_WCNSS_A11_SMSM\n",
+			__func__);
+#endif
+
+#if defined(CONFIG_DSPS_SMSM)
+	r = request_irq(INT_DSPS_A11_SMSM, smsm_dsps_irq_handler,
+			flags, "smsm_dev", smsm_dsps_irq_handler);
+	if (r < 0) {
+		free_irq(INT_A9_M2A_0, 0);
+		free_irq(INT_A9_M2A_5, 0);
+		free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
+		free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
+		free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
+		free_irq(INT_WCNSS_A11, smd_wcnss_irq_handler);
+		free_irq(INT_WCNSS_A11_SMSM, smsm_wcnss_irq_handler);
+		return r;
+	}
+
+	interrupt_stats[SMD_DSPS].smsm_interrupt_id = INT_DSPS_A11_SMSM;
+	r = enable_irq_wake(INT_DSPS_A11_SMSM);
+	if (r < 0)
+		pr_err("%s: enable_irq_wake failed for INT_DSPS_A11_SMSM\n",
+			__func__);
+#endif
+	SMD_INFO("smd_core_init() done\n");
+
+	return 0;
+}
+
+int smd_core_platform_init(struct platform_device *pdev)
+{
+	int i;
+	int ret;
+	uint32_t num_ss;
+	struct smd_platform *smd_platform_data;
+	struct smd_subsystem_config *smd_ss_config_list;
+	struct smd_subsystem_config *cfg;
+	struct interrupt_config *private_intr_config;
+	int err_ret = 0;
+
+	smd_platform_data = pdev->dev.platform_data;
+	num_ss = smd_platform_data->num_ss_configs;
+	smd_ss_config_list = smd_platform_data->smd_ss_configs;
+
+	if (smd_platform_data->smd_ssr_config)
+		disable_smsm_reset_handshake = smd_platform_data->
+			   smd_ssr_config->disable_smsm_reset_handshake;
+
+	for (i = 0; i < num_ss; i++) {
+		cfg = &smd_ss_config_list[i];
+		private_intr_config = smd_get_intr_config(cfg->edge);
+		if (!private_intr_config) {
+			pr_err("%s: invalid edge\n", __func__);
+			goto intr_failed;
+		}
+
+		ret = intr_init(
+			&private_intr_config->smd,
+			&cfg->smd_int,
+			pdev
+			);
+
+		if (ret < 0) {
+			err_ret = ret;
+			pr_err("smd: register irq failed on %s\n",
+				cfg->smd_int.irq_name);
+			goto intr_failed;
+		}
+
+		interrupt_stats[cfg->irq_config_id].smd_interrupt_id
+						 = cfg->smd_int.irq_id;
+		/* only init smsm structs if this edge supports smsm */
+		if (cfg->smsm_int.irq_id)
+			ret = intr_init(
+				&private_intr_config->smsm,
+				&cfg->smsm_int,
+				pdev
+				);
+
+		if (ret < 0) {
+			err_ret = ret;
+			pr_err("smd: register irq failed on %s\n",
+				cfg->smsm_int.irq_name);
+			goto intr_failed;
+		}
+
+		if (cfg->smsm_int.irq_id)
+			interrupt_stats[cfg->irq_config_id].smsm_interrupt_id
+						 = cfg->smsm_int.irq_id;
+		if (cfg->subsys_name)
+			smd_set_edge_subsys_name(cfg->edge, cfg->subsys_name);
+
+		smd_set_edge_initialized(cfg->edge);
+	}
+
+	SMD_INFO("smd_core_platform_init() done\n");
+
+	return 0;
+
+intr_failed:
+	pr_err("smd: deregistering IRQs\n");
+	for (i = 0; i < num_ss; ++i) {
+		cfg = &smd_ss_config_list[i];
+
+		if (cfg->smd_int.irq_id >= 0)
+			free_irq(cfg->smd_int.irq_id,
+				(void *)cfg->smd_int.dev_id
+				);
+		if (cfg->smsm_int.irq_id >= 0)
+			free_irq(cfg->smsm_int.irq_id,
+				(void *)cfg->smsm_int.dev_id
+				);
+	}
+	return err_ret;
+}
+
+static int msm_smd_probe_legacy(struct platform_device *pdev)
+{
+	int ret;
+
+	if (!smem_initialized_check())
+		return -ENODEV;
+
+	SMD_INFO("smd probe\n");
+	if (pdev) {
+		if (pdev->dev.of_node) {
+			pr_err("%s: invalid device tree init\n", __func__);
+			return -ENODEV;
+		} else if (pdev->dev.platform_data) {
+			ret = smd_core_platform_init(pdev);
+			if (ret) {
+				pr_err(
+				"SMD: smd_core_platform_init() failed\n");
+				return -ENODEV;
+			}
+		} else {
+			ret = smd_core_init();
+			if (ret) {
+				pr_err("smd_core_init() failed\n");
+				return -ENODEV;
+			}
+		}
+	} else {
+		pr_err("SMD: PDEV not found\n");
+		return -ENODEV;
+	}
+
+	ret = smsm_post_init();
+	if (ret) {
+		pr_err("smd_post_init() failed ret = %d\n", ret);
+		return ret;
+	}
+	smd_post_init(1);
+
+	return 0;
+}
+
+static struct platform_driver msm_smd_driver_legacy = {
+	.probe = msm_smd_probe_legacy,
+	.driver = {
+		.name = MODULE_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+int msm_smd_driver_register(void)
+{
+
+	int rc;
+
+	rc = platform_driver_register(&msm_smd_driver_legacy);
+	if (rc) {
+		pr_err("%s: smd_driver register failed %d\n",
+			__func__, rc);
+		return rc;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(msm_smd_driver_register);
+
+MODULE_DESCRIPTION("MSM SMD Legacy/Platform Device Init");
+MODULE_LICENSE("GPL v2");
+#endif
diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h
index 2096063..4664197 100644
--- a/arch/arm/mach-msm/smd_private.h
+++ b/arch/arm/mach-msm/smd_private.h
@@ -21,6 +21,7 @@
 #include <linux/errno.h>
 #include <linux/remote_spinlock.h>
 #include <linux/platform_device.h>
+#include <linux/interrupt.h>
 #include <mach/msm_smsm.h>
 #include <mach/msm_smd.h>
 
@@ -213,4 +214,60 @@
 	uint32_t smsm_interrupt_id;
 };
 extern struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
+
+struct interrupt_config_item {
+	/* must be initialized */
+	irqreturn_t (*irq_handler)(int req, void *data);
+	/* outgoing interrupt config (set from platform data) */
+	uint32_t out_bit_pos;
+	void __iomem *out_base;
+	uint32_t out_offset;
+	int irq_id;
+};
+
+enum {
+	MSM_SMD_DEBUG = 1U << 0,
+	MSM_SMSM_DEBUG = 1U << 1,
+	MSM_SMD_INFO = 1U << 2,
+	MSM_SMSM_INFO = 1U << 3,
+	MSM_SMx_POWER_INFO = 1U << 4,
+};
+
+struct interrupt_config {
+	struct interrupt_config_item smd;
+	struct interrupt_config_item smsm;
+};
+
+struct edge_to_pid {
+	uint32_t	local_pid;
+	uint32_t	remote_pid;
+	char		subsys_name[SMD_MAX_CH_NAME_LEN];
+	bool		initialized;
+};
+
+extern void *smd_log_ctx;
+extern int msm_smd_debug_mask;
+extern int disable_smsm_reset_handshake;
+extern bool smem_initialized_check(void);
+
+extern irqreturn_t smd_modem_irq_handler(int irq, void *data);
+extern irqreturn_t smsm_modem_irq_handler(int irq, void *data);
+extern irqreturn_t smd_dsp_irq_handler(int irq, void *data);
+extern irqreturn_t smsm_dsp_irq_handler(int irq, void *data);
+extern irqreturn_t smd_dsps_irq_handler(int irq, void *data);
+extern irqreturn_t smsm_dsps_irq_handler(int irq, void *data);
+extern irqreturn_t smd_wcnss_irq_handler(int irq, void *data);
+extern irqreturn_t smsm_wcnss_irq_handler(int irq, void *data);
+extern irqreturn_t smd_rpm_irq_handler(int irq, void *data);
+
+extern int msm_smd_driver_register(void);
+extern void smd_post_init(bool is_legacy);
+extern int smsm_post_init(void);
+
+extern struct interrupt_config *smd_get_intr_config(uint32_t edge);
+extern int smd_edge_to_remote_pid(uint32_t edge);
+extern void smd_set_edge_subsys_name(uint32_t edge, const char *subsys_name);
+extern void smd_set_edge_initialized(uint32_t edge);
+extern void smd_cfg_smd_intr(uint32_t proc, uint32_t mask, void *ptr);
+extern void smd_cfg_smsm_intr(uint32_t proc, uint32_t mask, void *ptr);
 #endif
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index 3461e49..6df1da4 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -36,9 +36,11 @@
 
 #include "smd_private.h"
 
+#define MODULE_NAME "msm_smdtty"
 #define MAX_SMD_TTYS 37
 #define MAX_TTY_BUF_SIZE 2048
 #define MAX_RA_WAKE_LOCK_NAME_LEN 32
+#define SMD_TTY_PROBE_WAIT_TIMEOUT 3000
 #define SMD_TTY_LOG_PAGES 2
 
 #define SMD_TTY_INFO(buf...) \
@@ -58,6 +60,9 @@
 static void *smd_tty_log_ctx;
 static DEFINE_MUTEX(smd_tty_lock);
 
+static struct delayed_work smd_tty_probe_work;
+static int smd_tty_probe_done;
+
 struct smd_tty_info {
 	smd_channel_t *ch;
 	struct tty_port port;
@@ -77,7 +82,10 @@
 	spinlock_t ra_lock;		/* Read Available Lock*/
 	char ra_wake_lock_name[MAX_RA_WAKE_LOCK_NAME_LEN];
 	struct wake_lock ra_wake_lock;	/* Read Available Wakelock */
-	struct smd_config *smd;
+
+	uint32_t edge;
+	char ch_name[SMD_MAX_CH_NAME_LEN];
+	char dev_name[SMD_MAX_CH_NAME_LEN];
 };
 
 /**
@@ -95,6 +103,12 @@
 	uint32_t edge;
 };
 
+/**
+ * struct smd_config smd_configs[]: Legacy configuration
+ *
+ * An array of all SMD tty channel supported in legacy targets.
+ * Future targets use either platform device or device tree configuration.
+ */
 static struct smd_config smd_configs[] = {
 	{0, "DS", NULL, SMD_APPS_MODEM},
 	{1, "APPS_FM", NULL, SMD_APPS_WCNSS},
@@ -104,6 +118,7 @@
 	{5, "APPS_RIVA_ANT_CMD", NULL, SMD_APPS_WCNSS},
 	{6, "APPS_RIVA_ANT_DATA", NULL, SMD_APPS_WCNSS},
 	{7, "DATA1", NULL, SMD_APPS_MODEM},
+	{8, "DATA4", NULL, SMD_APPS_MODEM},
 	{11, "DATA11", NULL, SMD_APPS_MODEM},
 	{21, "DATA21", NULL, SMD_APPS_MODEM},
 	{27, "GPSNMEA", NULL, SMD_APPS_MODEM},
@@ -326,7 +341,7 @@
 	const char *peripheral = NULL;
 
 
-	if (n >= MAX_SMD_TTYS || !smd_tty[n].smd)
+	if (n >= MAX_SMD_TTYS || !smd_tty[n].ch_name)
 		return -ENODEV;
 
 	info = smd_tty + n;
@@ -334,13 +349,13 @@
 	mutex_lock(&smd_tty_lock);
 	tty->driver_data = info;
 
-	peripheral = smd_edge_to_subsystem(smd_tty[n].smd->edge);
+	peripheral = smd_edge_to_subsystem(smd_tty[n].edge);
 	if (peripheral) {
 		info->pil = subsystem_get(peripheral);
 		if (IS_ERR(info->pil)) {
 			SMD_TTY_INFO(
 				"%s failed on smd_tty device :%s subsystem_get failed for %s",
-				__func__, smd_tty[n].smd->port_name,
+				__func__, info->ch_name,
 				peripheral);
 
 			/*
@@ -379,13 +394,13 @@
 			if (res == 0) {
 				SMD_TTY_INFO(
 					"Timed out waiting for SMD channel %s",
-					smd_tty[n].smd->port_name);
+					info->ch_name);
 				res = -ETIMEDOUT;
 				goto release_pil;
 			} else if (res < 0) {
 				SMD_TTY_INFO(
 					"Error waiting for SMD channel %s : %d\n",
-					smd_tty[n].smd->port_name, res);
+					info->ch_name, res);
 				goto release_pil;
 			}
 		}
@@ -393,18 +408,18 @@
 
 	tasklet_init(&info->tty_tsklt, smd_tty_read, (unsigned long)info);
 	wake_lock_init(&info->wake_lock, WAKE_LOCK_SUSPEND,
-			smd_tty[n].smd->port_name);
+			info->ch_name);
 	scnprintf(info->ra_wake_lock_name, MAX_RA_WAKE_LOCK_NAME_LEN,
-		  "SMD_TTY_%s_RA", smd_tty[n].smd->port_name);
+		  "SMD_TTY_%s_RA", info->ch_name);
 	wake_lock_init(&info->ra_wake_lock, WAKE_LOCK_SUSPEND,
 			info->ra_wake_lock_name);
 
-	res = smd_named_open_on_edge(smd_tty[n].smd->port_name,
-				     smd_tty[n].smd->edge, &info->ch, info,
+	res = smd_named_open_on_edge(info->ch_name,
+				     smd_tty[n].edge, &info->ch, info,
 				     smd_tty_notify);
 	if (res < 0) {
 		SMD_TTY_INFO("%s: %s open failed %d\n",
-			      __func__, smd_tty[n].smd->port_name, res);
+			      __func__, info->ch_name, res);
 		goto release_wl_tl;
 	}
 
@@ -414,11 +429,11 @@
 		res = -ETIMEDOUT;
 	if (res < 0) {
 		SMD_TTY_INFO("%s: wait for %s smd_open failed %d\n",
-			      __func__, smd_tty[n].smd->port_name, res);
+			      __func__, info->ch_name, res);
 		goto close_ch;
 	}
 	SMD_TTY_INFO("%s with PID %u opened port %s",
-		      current->comm, current->pid, smd_tty[n].smd->port_name);
+		      current->comm, current->pid, info->ch_name);
 	smd_disable_read_intr(info->ch);
 	mutex_unlock(&smd_tty_lock);
 	return 0;
@@ -464,7 +479,7 @@
 
 	SMD_TTY_INFO("%s with PID %u closed port %s",
 			current->comm, current->pid,
-			info->smd->port_name);
+			info->ch_name);
 	tty->driver_data = NULL;
 	del_timer(&info->buf_req_timer);
 
@@ -513,7 +528,7 @@
 	if (len > avail)
 		len = avail;
 	SMD_TTY_INFO("[WRITE]: PID %u -> port %s %x bytes",
-			current->pid, info->smd->port_name, len);
+			current->pid, info->ch_name, len);
 
 	return smd_write(info->ch, buf, len);
 }
@@ -613,18 +628,15 @@
 static int smd_tty_dummy_probe(struct platform_device *pdev)
 {
 	int n;
-	int idx;
 
-	for (n = 0; n < ARRAY_SIZE(smd_configs); ++n) {
-		idx = smd_configs[n].tty_dev_index;
-
-		if (!smd_configs[n].dev_name)
+	for (n = 0; n < MAX_SMD_TTYS; ++n) {
+		if (!smd_tty[n].dev_name)
 			continue;
 
-		if (pdev->id == smd_configs[n].edge &&
-			!strncmp(pdev->name, smd_configs[n].dev_name,
+		if (pdev->id == smd_tty[n].edge &&
+			!strncmp(pdev->name, smd_tty[n].dev_name,
 					SMD_MAX_CH_NAME_LEN)) {
-			complete_all(&smd_tty[idx].ch_allocated);
+			complete_all(&smd_tty[n].ch_allocated);
 			return 0;
 		}
 	}
@@ -649,14 +661,10 @@
 
 static struct tty_driver *smd_tty_driver;
 
-static int __init smd_tty_init(void)
+static int smd_tty_register_driver(void)
 {
 	int ret;
-	int n;
-	int idx;
-	struct tty_port *port;
 
-	smd_tty_log_init();
 	smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS);
 	if (smd_tty_driver == 0) {
 		SMD_TTY_ERR("%s - Driver allocation failed", __func__);
@@ -683,14 +691,63 @@
 	if (ret) {
 		put_tty_driver(smd_tty_driver);
 		SMD_TTY_ERR("%s: driver registration failed %d", __func__, ret);
+	}
+
+	return ret;
+}
+
+static int smd_tty_device_init(int idx)
+{
+	int ret;
+	struct tty_port *port;
+
+	port = &smd_tty[idx].port;
+	tty_port_init(port);
+	port->ops = &smd_tty_port_ops;
+	/* TODO: For kernel >= 3.7 use tty_port_register_device */
+	smd_tty[idx].device_ptr = tty_register_device(smd_tty_driver, idx, 0);
+	init_completion(&smd_tty[idx].ch_allocated);
+
+	/* register platform device */
+	smd_tty[idx].driver.probe = smd_tty_dummy_probe;
+	smd_tty[idx].driver.driver.name = smd_tty[idx].dev_name;
+	smd_tty[idx].driver.driver.owner = THIS_MODULE;
+	spin_lock_init(&smd_tty[idx].reset_lock);
+	spin_lock_init(&smd_tty[idx].ra_lock);
+	smd_tty[idx].is_open = 0;
+	setup_timer(&smd_tty[idx].buf_req_timer, buf_req_retry,
+			(unsigned long)&smd_tty[idx]);
+	init_waitqueue_head(&smd_tty[idx].ch_opened_wait_queue);
+	ret = platform_driver_register(&smd_tty[idx].driver);
+
+	return ret;
+}
+
+static int __init smd_tty_core_init(void)
+{
+	int ret;
+	int n;
+	int idx;
+
+	ret = smd_tty_register_driver();
+	if (ret) {
+		pr_err("%s: driver registration failed %d\n", __func__, ret);
 		return ret;
 	}
 
 	for (n = 0; n < ARRAY_SIZE(smd_configs); ++n) {
 		idx = smd_configs[n].tty_dev_index;
+		smd_tty[idx].edge = smd_configs[n].edge;
 
-		if (smd_configs[n].dev_name == NULL)
-			smd_configs[n].dev_name = smd_configs[n].port_name;
+		strlcpy(smd_tty[idx].ch_name, smd_configs[n].port_name,
+							SMD_MAX_CH_NAME_LEN);
+		if (smd_configs[n].dev_name == NULL) {
+			strlcpy(smd_tty[idx].dev_name, smd_tty[idx].ch_name,
+							SMD_MAX_CH_NAME_LEN);
+		} else {
+			strlcpy(smd_tty[idx].dev_name, smd_configs[n].dev_name,
+							SMD_MAX_CH_NAME_LEN);
+		}
 
 		if (idx == DS_IDX) {
 			/*
@@ -713,39 +770,19 @@
 				continue;
 		}
 
-		port = &smd_tty[idx].port;
-		tty_port_init(port);
-		port->ops = &smd_tty_port_ops;
-		/* TODO: For kernel >= 3.7 use tty_port_register_device */
-		smd_tty[idx].device_ptr =
-			tty_register_device(smd_tty_driver, idx, 0);
+		ret = smd_tty_device_init(idx);
 		if (device_create_file(smd_tty[idx].device_ptr,
 					&dev_attr_open_timeout))
 			SMD_TTY_ERR(
 				"%s: Unable to create device attributes for %s",
 				__func__, smd_configs[n].port_name);
 
-		init_completion(&smd_tty[idx].ch_allocated);
-
-		/* register platform device */
-		smd_tty[idx].driver.probe = smd_tty_dummy_probe;
-		smd_tty[idx].driver.driver.name = smd_configs[n].dev_name;
-		smd_tty[idx].driver.driver.owner = THIS_MODULE;
-		spin_lock_init(&smd_tty[idx].reset_lock);
-		spin_lock_init(&smd_tty[idx].ra_lock);
-		smd_tty[idx].is_open = 0;
-		setup_timer(&smd_tty[idx].buf_req_timer, buf_req_retry,
-				(unsigned long)&smd_tty[idx]);
-		init_waitqueue_head(&smd_tty[idx].ch_opened_wait_queue);
-		ret = platform_driver_register(&smd_tty[idx].driver);
-
 		if (ret) {
 			SMD_TTY_ERR(
 				"%s: init failed %d (%d)", __func__, idx, ret);
 			smd_tty[idx].driver.probe = NULL;
 			goto out;
 		}
-		smd_tty[idx].smd = &smd_configs[n];
 	}
 	INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
 	return 0;
@@ -766,4 +803,155 @@
 	return ret;
 }
 
+static int __init smd_tty_devicetree_init(struct platform_device *pdev)
+{
+	int ret;
+	int idx;
+	int edge;
+	char *key;
+	const char *ch_name;
+	const char *dev_name;
+	const char *remote_ss;
+	struct device_node *node;
+
+	ret = smd_tty_register_driver();
+	if (ret) {
+		SMD_TTY_ERR("%s: driver registration failed %d\n",
+						__func__, ret);
+		return ret;
+	}
+
+	for_each_child_of_node(pdev->dev.of_node, node) {
+
+		ret = of_alias_get_id(node, "smd");
+		SMD_TTY_INFO("%s:adding smd%d\n", __func__, ret);
+
+		if (ret < 0 || ret >= MAX_SMD_TTYS)
+			goto error;
+		idx = ret;
+
+		key = "qcom,smdtty-remote";
+		remote_ss = of_get_property(node, key, NULL);
+		if (!remote_ss)
+			goto error;
+
+		edge = smd_remote_ss_to_edge(remote_ss);
+		if (edge < 0)
+			goto error;
+		smd_tty[idx].edge = edge;
+
+		key = "qcom,smdtty-port-name";
+		ch_name = of_get_property(node, key, NULL);
+		if (!ch_name)
+			goto error;
+		strlcpy(smd_tty[idx].ch_name, ch_name,
+					SMD_MAX_CH_NAME_LEN);
+
+		key = "qcom,smdtty-dev-name";
+		dev_name = of_get_property(node, key, NULL);
+		if (!dev_name) {
+			strlcpy(smd_tty[idx].dev_name, smd_tty[idx].ch_name,
+							SMD_MAX_CH_NAME_LEN);
+		} else {
+			strlcpy(smd_tty[idx].dev_name, dev_name,
+						SMD_MAX_CH_NAME_LEN);
+		}
+
+		ret = smd_tty_device_init(idx);
+		if (ret) {
+			SMD_TTY_ERR("%s: init failed %d (%d)\n", __func__,
+								idx, ret);
+			smd_tty[idx].driver.probe = NULL;
+			goto error;
+		}
+	}
+	INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
+
+	return 0;
+
+error:
+	SMD_TTY_ERR("%s: unregister platform device\n", __func__);
+	/*Unregister platform devices*/
+	for_each_child_of_node(pdev->dev.of_node, node) {
+
+		key = "qcom,smdtty-dev-idx";
+		ret = of_property_read_u32(node, key, &idx);
+		if (ret || idx >= MAX_SMD_TTYS)
+			goto out;
+
+		if (smd_tty[idx].driver.probe) {
+			platform_driver_unregister(&smd_tty[idx].driver);
+			tty_unregister_device(smd_tty_driver, idx);
+		}
+	}
+out:
+	tty_unregister_driver(smd_tty_driver);
+	put_tty_driver(smd_tty_driver);
+	return ret;
+}
+
+static int __devinit msm_smd_tty_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	if (pdev) {
+		if (pdev->dev.of_node) {
+			ret = smd_tty_devicetree_init(pdev);
+			if (ret) {
+				SMD_TTY_ERR("%s: device tree init failed\n",
+								__func__);
+				return ret;
+			}
+		}
+	}
+
+	smd_tty_probe_done = 1;
+	return 0;
+}
+
+static void smd_tty_probe_worker(struct work_struct *work)
+{
+	int ret;
+	if (!smd_tty_probe_done) {
+		ret = smd_tty_core_init();
+		if (ret < 0)
+			SMD_TTY_ERR("smd_tty_core_init failed ret = %d\n", ret);
+	}
+
+}
+
+static struct of_device_id msm_smd_tty_match_table[] = {
+	{ .compatible = "qcom,smdtty" },
+	{},
+};
+
+static struct platform_driver msm_smd_tty_driver = {
+	.probe = msm_smd_tty_probe,
+	.driver = {
+		.name = MODULE_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = msm_smd_tty_match_table,
+	 },
+};
+
+
+static int __init smd_tty_init(void)
+{
+	int rc;
+
+	smd_tty_log_init();
+	rc = platform_driver_register(&msm_smd_tty_driver);
+	if (rc) {
+		SMD_TTY_ERR("%s: msm_smd_tty_driver register failed %d\n",
+								__func__, rc);
+		return rc;
+	}
+
+	INIT_DELAYED_WORK(&smd_tty_probe_work, smd_tty_probe_worker);
+	schedule_delayed_work(&smd_tty_probe_work,
+				msecs_to_jiffies(SMD_TTY_PROBE_WAIT_TIMEOUT));
+
+	return 0;
+}
+
 module_init(smd_tty_init);
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 6cb04c7..2f615f7 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -75,6 +75,7 @@
 	PLATFORM_SUBTYPE_SKUAA = 0x1,
 	PLATFORM_SUBTYPE_SKUF = 0x2,
 	PLATFORM_SUBTYPE_SKUAB = 0x3,
+	PLATFORM_SUBTYPE_SKUG = 0x5,
 	PLATFORM_SUBTYPE_QRD_INVALID,
 };
 
@@ -83,6 +84,8 @@
 	[PLATFORM_SUBTYPE_SKUAA] = "SKUAA",
 	[PLATFORM_SUBTYPE_SKUF] = "SKUF",
 	[PLATFORM_SUBTYPE_SKUAB] = "SKUAB",
+	[PLATFORM_SUBTYPE_SKUG] = "SKUG",
+	[PLATFORM_SUBTYPE_QRD_INVALID] = "INVALID",
 };
 
 enum {
@@ -666,7 +669,7 @@
 		if (hw_subtype >= PLATFORM_SUBTYPE_QRD_INVALID) {
 			pr_err("%s: Invalid hardware platform sub type for qrd found\n",
 				__func__);
-			hw_subtype = PLATFORM_SUBTYPE_QRD;
+			hw_subtype = PLATFORM_SUBTYPE_QRD_INVALID;
 		}
 		return snprintf(buf, PAGE_SIZE, "%-.32s\n",
 					qrd_hw_platform_subtype[hw_subtype]);
@@ -788,6 +791,16 @@
 {
 	uint32_t hw_subtype;
 	hw_subtype = socinfo_get_platform_subtype();
+	if (HW_PLATFORM_QRD == socinfo_get_platform_type()) {
+		if (hw_subtype >= PLATFORM_SUBTYPE_QRD_INVALID) {
+			pr_err("%s: Invalid hardware platform sub type for qrd found\n",
+				__func__);
+			hw_subtype = PLATFORM_SUBTYPE_QRD_INVALID;
+		}
+		return snprintf(buf, PAGE_SIZE, "%-.32s\n",
+					qrd_hw_platform_subtype[hw_subtype]);
+	}
+
 	return snprintf(buf, PAGE_SIZE, "%-.32s\n",
 		hw_platform_subtype[hw_subtype]);
 }
diff --git a/arch/arm/mach-msm/spm-regulator.c b/arch/arm/mach-msm/spm-regulator.c
index 244a779..08ac56a 100644
--- a/arch/arm/mach-msm/spm-regulator.c
+++ b/arch/arm/mach-msm/spm-regulator.c
@@ -120,7 +120,7 @@
 			return rc;
 	}
 
-	rc = msm_spm_apcs_set_vdd(vreg->vlevel);
+	rc = msm_spm_set_vdd(0, vreg->vlevel); /* value of CPU is don't care */
 	if (rc) {
 		pr_err("%s: msm_spm_set_vdd failed %d\n", vreg->rdesc.name, rc);
 		return rc;
diff --git a/arch/arm/mach-msm/spm.h b/arch/arm/mach-msm/spm.h
index 77b7bf7..3207011 100644
--- a/arch/arm/mach-msm/spm.h
+++ b/arch/arm/mach-msm/spm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -150,7 +150,6 @@
 /* Public functions */
 
 int msm_spm_l2_set_low_power_mode(unsigned int mode, bool notify_rpm);
-int msm_spm_apcs_set_vdd(unsigned int vlevel);
 int msm_spm_apcs_set_phase(unsigned int phase_cnt);
 int msm_spm_enable_fts_lpm(uint32_t mode);
 
@@ -166,20 +165,17 @@
 {
 	return -ENOSYS;
 }
+
 static inline int msm_spm_l2_init(struct msm_spm_platform_data *data)
 {
 	return -ENOSYS;
 }
+
 static inline void msm_spm_l2_reinit(void)
 {
 	/* empty */
 }
 
-static inline int msm_spm_apcs_set_vdd(unsigned int vlevel)
-{
-	return -ENOSYS;
-}
-
 static inline int msm_spm_apcs_set_phase(unsigned int phase_cnt)
 {
 	return -ENOSYS;
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index fc05fce..3ac1348 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -48,18 +48,29 @@
 
 static struct msm_spm_device msm_spm_l2_device;
 static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_spm_device, msm_cpu_spm_device);
-
+static bool msm_spm_L2_apcs_master;
 
 static void msm_spm_smp_set_vdd(void *data)
 {
 	struct msm_spm_device *dev;
 	struct msm_spm_vdd_info *info = (struct msm_spm_vdd_info *)data;
 
-	dev = &per_cpu(msm_cpu_spm_device, info->cpu);
+	if (msm_spm_L2_apcs_master)
+		dev = &msm_spm_l2_device;
+	else
+		dev = &per_cpu(msm_cpu_spm_device, info->cpu);
+
 	if (!dev->initialized)
 		return;
+
+	if (msm_spm_L2_apcs_master)
+		get_cpu();
+
 	dev->cpu_vdd = info->vlevel;
 	info->err = msm_spm_drv_set_vdd(&dev->reg_data, info->vlevel);
+
+	if (msm_spm_L2_apcs_master)
+		put_cpu();
 }
 
 /**
@@ -76,7 +87,8 @@
 	info.vlevel = vlevel;
 	info.err = -ENODEV;
 
-	if ((smp_processor_id() != cpu) && cpu_online(cpu)) {
+	if (!msm_spm_L2_apcs_master && (smp_processor_id() != cpu) &&
+			cpu_online(cpu)) {
 		/**
 		 * We do not want to set the voltage of another core from
 		 * this core, as its possible that we may race the vdd change
@@ -111,7 +123,10 @@
 {
 	struct msm_spm_device *dev;
 
-	dev = &per_cpu(msm_cpu_spm_device, cpu);
+	if (msm_spm_L2_apcs_master)
+		dev = &msm_spm_l2_device;
+	else
+		dev = &per_cpu(msm_cpu_spm_device, cpu);
 	return dev->cpu_vdd;
 }
 EXPORT_SYMBOL(msm_spm_get_vdd);
@@ -293,18 +308,6 @@
 EXPORT_SYMBOL(msm_spm_l2_reinit);
 
 /**
- * msm_spm_apcs_set_vdd(): Set Apps processor core sub-system voltage
- * @vlevel: Encoded PMIC data.
- */
-int msm_spm_apcs_set_vdd(unsigned int vlevel)
-{
-	if (!msm_spm_l2_device.initialized)
-		return -ENXIO;
-	return msm_spm_drv_set_vdd(&msm_spm_l2_device.reg_data, vlevel);
-}
-EXPORT_SYMBOL(msm_spm_apcs_set_vdd);
-
-/**
  * msm_spm_apcs_set_phase(): Set number of SMPS phases.
  * phase_cnt: Number of phases to be set active
  */
@@ -468,6 +471,10 @@
 		ret = of_property_read_u32(node, key, &val);
 		if (!ret)
 			spm_data.pfm_port = val;
+
+		key = "qcom,L2-spm-is-apcs-master";
+		msm_spm_L2_apcs_master =
+			of_property_read_bool(pdev->dev.of_node, key);
 	}
 
 	for (i = 0; i < ARRAY_SIZE(spm_of_data); i++) {
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 34cb153..e82ea2b 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -909,6 +909,14 @@
 				    "TCM link");
 #endif
 
+#ifdef CONFIG_STRICT_MEMORY_RWX
+	poison_init_mem((char *)__arch_info_begin,
+		__init_end - (char *)__arch_info_begin);
+	reclaimed_initmem = free_area(__phys_to_pfn(__pa(__arch_info_begin)),
+				    __phys_to_pfn(__pa(__init_end)),
+				    "init");
+	totalram_pages += reclaimed_initmem;
+#else
 	poison_init_mem(__init_begin, __init_end - __init_begin);
 	if (!machine_is_integrator() && !machine_is_cintegrator()) {
 		reclaimed_initmem = free_area(__phys_to_pfn(__pa(__init_begin)),
@@ -916,6 +924,7 @@
 					    "init");
 		totalram_pages += reclaimed_initmem;
 	}
+#endif
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index c2efc34..e5a60a9 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -1379,8 +1379,6 @@
 }
 EXPORT_SYMBOL(mem_text_write_kernel_word);
 
-extern char __init_data[];
-
 static void __init map_lowmem(void)
 {
 	struct memblock_region *reg;
@@ -1401,7 +1399,7 @@
 #ifdef CONFIG_STRICT_MEMORY_RWX
 		if (start <= __pa(_text) && __pa(_text) < end) {
 			map.length = SECTION_SIZE;
-			map.type = MT_MEMORY;
+			map.type = MT_MEMORY_RW;
 
 			create_mapping(&map);
 
@@ -1421,14 +1419,15 @@
 
 			map.pfn = __phys_to_pfn(__pa(__init_begin));
 			map.virtual = (unsigned long)__init_begin;
-			map.length = __init_data - __init_begin;
-			map.type = MT_MEMORY;
+			map.length = (char *)__arch_info_begin - __init_begin;
+			map.type = MT_MEMORY_RX;
 
 			create_mapping(&map);
 
-			map.pfn = __phys_to_pfn(__pa(__init_data));
-			map.virtual = (unsigned long)__init_data;
-			map.length = __phys_to_virt(end) - (unsigned int)__init_data;
+			map.pfn = __phys_to_pfn(__pa(__arch_info_begin));
+			map.virtual = (unsigned long)__arch_info_begin;
+			map.length = __phys_to_virt(end) -
+				(unsigned long)__arch_info_begin;
 			map.type = MT_MEMORY_RW;
 		} else {
 			map.length = end - start;
diff --git a/block/blk-core.c b/block/blk-core.c
index 40d9b35..123f79a 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -2058,8 +2058,10 @@
 			 * not be passed by new incoming requests
 			 */
 			rq->cmd_flags |= REQ_STARTED;
-			if (rq->cmd_flags & REQ_URGENT)
+			if (rq->cmd_flags & REQ_URGENT) {
+				WARN_ON(q->dispatched_urgent);
 				q->dispatched_urgent = true;
+			}
 			trace_block_rq_issue(q, rq);
 		}
 
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index b4711cb..32629e2 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -239,9 +239,6 @@
 	unsigned long workload_expires;
 	struct cfq_group *serving_group;
 
-	unsigned int nr_urgent_pending;
-	unsigned int nr_urgent_in_flight;
-
 	/*
 	 * Each priority tree is sorted by next_request position.  These
 	 * trees are used when determining if two or more queues are
@@ -2094,14 +2091,6 @@
 	(RQ_CFQG(rq))->dispatched++;
 	elv_dispatch_sort(q, rq);
 
-	if (rq->cmd_flags & REQ_URGENT) {
-		if (!cfqd->nr_urgent_pending)
-			WARN_ON(1);
-		else
-			cfqd->nr_urgent_pending--;
-		cfqd->nr_urgent_in_flight++;
-	}
-
 	cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]++;
 	cfqq->nr_sectors += blk_rq_sectors(rq);
 	cfq_blkiocg_update_dispatch_stats(&cfqq->cfqg->blkg, blk_rq_bytes(rq),
@@ -3205,69 +3194,6 @@
 	}
 }
 
-/*
- * Called when a request (rq) is reinserted (to cfqq). Check if there's
- * something we should do about it
- */
-static void
-cfq_rq_requeued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
-		struct request *rq)
-{
-	struct cfq_io_cq *cic = RQ_CIC(rq);
-
-	cfqd->rq_queued++;
-	if (rq->cmd_flags & REQ_PRIO)
-		cfqq->prio_pending++;
-
-	cfqq->dispatched--;
-	(RQ_CFQG(rq))->dispatched--;
-
-	cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]--;
-
-	cfq_update_io_thinktime(cfqd, cfqq, cic);
-	cfq_update_io_seektime(cfqd, cfqq, rq);
-	cfq_update_idle_window(cfqd, cfqq, cic);
-
-	cfqq->last_request_pos = blk_rq_pos(rq) + blk_rq_sectors(rq);
-
-	if (cfqq == cfqd->active_queue) {
-		if (cfq_cfqq_wait_request(cfqq)) {
-			if (blk_rq_bytes(rq) > PAGE_CACHE_SIZE ||
-			    cfqd->busy_queues > 1) {
-				cfq_del_timer(cfqd, cfqq);
-				cfq_clear_cfqq_wait_request(cfqq);
-			} else {
-				cfq_blkiocg_update_idle_time_stats(
-						&cfqq->cfqg->blkg);
-				cfq_mark_cfqq_must_dispatch(cfqq);
-			}
-		}
-	} else if (cfq_should_preempt(cfqd, cfqq, rq)) {
-		cfq_preempt_queue(cfqd, cfqq);
-	}
-}
-
-static int cfq_reinsert_request(struct request_queue *q, struct request *rq)
-{
-	struct cfq_data *cfqd = q->elevator->elevator_data;
-	struct cfq_queue *cfqq = RQ_CFQQ(rq);
-
-	if (!cfqq || cfqq->cfqd != cfqd)
-		return -EIO;
-
-	cfq_log_cfqq(cfqd, cfqq, "re-insert_request");
-	list_add(&rq->queuelist, &cfqq->fifo);
-	cfq_add_rq_rb(rq);
-
-	cfq_rq_requeued(cfqd, cfqq, rq);
-	if (rq->cmd_flags & REQ_URGENT) {
-			if (cfqd->nr_urgent_in_flight)
-				cfqd->nr_urgent_in_flight--;
-			cfqd->nr_urgent_pending++;
-	}
-	return 0;
-}
-
 static void cfq_insert_request(struct request_queue *q, struct request *rq)
 {
 	struct cfq_data *cfqd = q->elevator->elevator_data;
@@ -3282,45 +3208,7 @@
 	cfq_blkiocg_update_io_add_stats(&(RQ_CFQG(rq))->blkg,
 			&cfqd->serving_group->blkg, rq_data_dir(rq),
 			rq_is_sync(rq));
-
 	cfq_rq_enqueued(cfqd, cfqq, rq);
-
-	if (rq->cmd_flags & REQ_URGENT) {
-		WARN_ON(1);
-		blk_dump_rq_flags(rq, "");
-		rq->cmd_flags &= ~REQ_URGENT;
-	}
-
-	/* Request is considered URGENT if:
-	 * 1. The queue being served is of a lower IO priority then the new
-	 *    request
-	 * OR:
-	 * 2. The workload being performed is ASYNC
-	 * Only READ requests may be considered as URGENT
-	 */
-	if ((cfqd->active_queue &&
-		 cfqq->ioprio_class < cfqd->active_queue->ioprio_class) ||
-		(cfqd->serving_type == ASYNC_WORKLOAD &&
-		 rq_data_dir(rq) == READ)) {
-		rq->cmd_flags |= REQ_URGENT;
-		cfqd->nr_urgent_pending++;
-	}
-}
-
-
-/**
- * cfq_urgent_pending() - Return TRUE if there is an urgent
- *			  request on scheduler
- * @q:	requests queue
- */
-static bool cfq_urgent_pending(struct request_queue *q)
-{
-	struct cfq_data *cfqd = q->elevator->elevator_data;
-
-	if (cfqd->nr_urgent_pending && !cfqd->nr_urgent_in_flight)
-		return true;
-
-	return false;
 }
 
 /*
@@ -3404,14 +3292,6 @@
 	const int sync = rq_is_sync(rq);
 	unsigned long now;
 
-	if (rq->cmd_flags & REQ_URGENT) {
-		if (!cfqd->nr_urgent_in_flight)
-			WARN_ON(1);
-		else
-			cfqd->nr_urgent_in_flight--;
-		rq->cmd_flags &= ~REQ_URGENT;
-	}
-
 	now = jiffies;
 	cfq_log_cfqq(cfqd, cfqq, "complete rqnoidle %d",
 		     !!(rq->cmd_flags & REQ_NOIDLE));
@@ -3979,8 +3859,6 @@
 		.elevator_bio_merged_fn =	cfq_bio_merged,
 		.elevator_dispatch_fn =		cfq_dispatch_requests,
 		.elevator_add_req_fn =		cfq_insert_request,
-		.elevator_reinsert_req_fn	= cfq_reinsert_request,
-		.elevator_is_urgent_fn		= cfq_urgent_pending,
 		.elevator_activate_req_fn =	cfq_activate_request,
 		.elevator_deactivate_req_fn =	cfq_deactivate_request,
 		.elevator_completed_req_fn =	cfq_completed_request,
diff --git a/block/elevator.c b/block/elevator.c
index 55f1f1e..44193a8 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -842,6 +842,7 @@
 
 	if (rq->cmd_flags & REQ_URGENT) {
 		q->notified_urgent = false;
+		WARN_ON(!q->dispatched_urgent);
 		q->dispatched_urgent = false;
 	}
 	/*
diff --git a/drivers/base/sync.c b/drivers/base/sync.c
index 2e35996..abde6d9 100644
--- a/drivers/base/sync.c
+++ b/drivers/base/sync.c
@@ -34,7 +34,7 @@
 static void sync_fence_signal_pt(struct sync_pt *pt);
 static int _sync_pt_has_signaled(struct sync_pt *pt);
 static void sync_fence_free(struct kref *kref);
-static void sync_dump(void);
+static void sync_dump(struct sync_fence *fence);
 
 static LIST_HEAD(sync_timeline_list_head);
 static DEFINE_SPINLOCK(sync_timeline_list_lock);
@@ -611,7 +611,7 @@
 
 	if (fence->status < 0) {
 		pr_info("fence error %d on [%p]\n", fence->status, fence);
-		sync_dump();
+		sync_dump(fence);
 		return fence->status;
 	}
 
@@ -619,7 +619,7 @@
 		if (timeout > 0) {
 			pr_info("fence timeout on [%p] after %dms\n", fence,
 				jiffies_to_msecs(timeout));
-			sync_dump();
+			sync_dump(fence);
 		}
 		return -ETIME;
 	}
@@ -986,7 +986,7 @@
 
 #define DUMP_CHUNK 256
 static char sync_dump_buf[64 * 1024];
-void sync_dump(void)
+static void sync_dump(struct sync_fence *fence)
 {
        struct seq_file s = {
                .buf = sync_dump_buf,
@@ -994,7 +994,9 @@
        };
        int i;
 
-       sync_debugfs_show(&s, NULL);
+       seq_printf(&s, "fence:\n--------------\n");
+       sync_print_fence(&s, fence);
+       seq_printf(&s, "\n");
 
        for (i = 0; i < s.count; i += DUMP_CHUNK) {
                if ((s.count - i) > DUMP_CHUNK) {
@@ -1009,7 +1011,7 @@
        }
 }
 #else
-static void sync_dump(void)
+static void sync_dump(struct sync_fence *fence)
 {
 }
 #endif
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index a779b24..97dc26d 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -209,9 +209,16 @@
 		event_id_packet = *(uint16_t *)(buf + temp_len);
 		event_id = event_id_packet & 0x0FFF; /* extract 12 bits */
 		if (event_id_packet & 0x8000) {
+			/* The packet has the two smallest byte of the
+			 * timestamp
+			 */
 			timestamp_len = 2;
-			memset(timestamp, 0, 8);
 		} else {
+			/* The packet has the full timestamp. The first event
+			 * will always have full timestamp. Save it in the
+			 * timestamp buffer and use it for subsequent events if
+			 * necessary.
+			 */
 			timestamp_len = 8;
 			memcpy(timestamp, buf + temp_len + 2, timestamp_len);
 		}
@@ -459,6 +466,7 @@
 	if ((read_len + 9) >= USER_SPACE_DATA) {
 		pr_err("diag: dci: Invalid length while forming dci pkt in %s",
 								__func__);
+		mutex_unlock(&driver->dci_mutex);
 		return -EIO;
 	}
 
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index a24fc54..aa88b37 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -350,19 +350,21 @@
 		bytes_written = scnprintf(buf+bytes_in_buffer, bytes_remaining,
 			"i: %3d, cmd_code: %4x, subsys_id: %4x, "
 			"client: %2d, cmd_code_lo: %4x, "
-			"cmd_code_hi: %4x, process_id: %5d\n",
+			"cmd_code_hi: %4x, process_id: %5d %s\n",
 			i,
 			driver->table[i].cmd_code,
 			driver->table[i].subsys_id,
 			driver->table[i].client_id,
 			driver->table[i].cmd_code_lo,
 			driver->table[i].cmd_code_hi,
-			driver->table[i].process_id);
+			driver->table[i].process_id,
+			(diag_find_polling_reg(i) ? "<- Polling cmd reg" : ""));
 
 		bytes_in_buffer += bytes_written;
 
 		/* Check if there is room to add another table entry */
 		bytes_remaining = buf_size - bytes_in_buffer;
+
 		if (bytes_remaining < bytes_written)
 			break;
 	}
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index c91095e..9c27180 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -19,12 +19,15 @@
 #include "diagfwd_cntl.h"
 #include "diag_masks.h"
 
-int diag_event_config;
 int diag_event_num_bytes;
 
+#define DIAG_CTRL_MASK_INVALID		0
+#define DIAG_CTRL_MASK_ALL_DISABLED	1
+#define DIAG_CTRL_MASK_ALL_ENABLED	2
+#define DIAG_CTRL_MASK_VALID		3
+
 #define ALL_EQUIP_ID		100
 #define ALL_SSID		-1
-#define MAX_SSID_PER_RANGE	100
 
 #define FEATURE_MASK_LEN_BYTES		2
 
@@ -106,6 +109,8 @@
 	uint8_t *parse_ptr, *ptr = driver->msg_masks;
 
 	mutex_lock(&driver->diagchar_mutex);
+	driver->msg_status = rt_mask ? DIAG_CTRL_MASK_ALL_ENABLED :
+						DIAG_CTRL_MASK_ALL_DISABLED;
 	while (*(uint32_t *)(ptr + 4)) {
 		first_ssid = *(uint32_t *)ptr;
 		ptr += 8; /* increment by 8 to skip 'last' */
@@ -129,9 +134,9 @@
 	uint8_t *ptr = driver->msg_masks;
 	uint8_t *ptr_buffer_start = &(*(driver->msg_masks));
 	uint8_t *ptr_buffer_end = &(*(driver->msg_masks)) + MSG_MASK_SIZE;
+	uint32_t copy_len = (end - start + 1) * sizeof(int);
 
 	mutex_lock(&driver->diagchar_mutex);
-
 	/* First SSID can be zero : So check that last is non-zero */
 	while (*(uint32_t *)(ptr + 4)) {
 		first = *(uint32_t *)ptr;
@@ -148,11 +153,19 @@
 				actual_last = end;
 				*(uint32_t *)(actual_last_ptr) = end;
 			}
+			if (actual_last-first >= MAX_SSID_PER_RANGE) {
+				pr_err("diag: In %s, truncating ssid range, %d-%d to max allowed: %d",
+						__func__, first, actual_last,
+						MAX_SSID_PER_RANGE);
+				copy_len = MAX_SSID_PER_RANGE;
+				actual_last = first + MAX_SSID_PER_RANGE;
+				*(uint32_t *)actual_last_ptr = actual_last;
+			}
 			if (CHK_OVERFLOW(ptr_buffer_start, ptr, ptr_buffer_end,
-					  (((end - start)+1)*4))) {
+								copy_len)) {
 				pr_debug("diag: update ssid start %d, end %d\n",
 								 start, end);
-				memcpy(ptr, buf , ((end - start)+1)*4);
+				memcpy(ptr, buf, copy_len);
 			} else
 				pr_alert("diag: Not enough space MSG_MASK\n");
 			found = 1;
@@ -177,6 +190,7 @@
 		} else
 			pr_alert("diag: Not enough buffer space for MSG_MASK\n");
 	}
+	driver->msg_status = DIAG_CTRL_MASK_VALID;
 	mutex_unlock(&driver->diagchar_mutex);
 	diag_print_mask_table();
 }
@@ -186,28 +200,29 @@
 	uint8_t *ptr = driver->event_masks;
 
 	mutex_lock(&driver->diagchar_mutex);
-	if (toggle)
+	if (toggle) {
+		driver->event_status = DIAG_CTRL_MASK_ALL_ENABLED;
 		memset(ptr, 0xFF, EVENT_MASK_SIZE);
-	else
+	} else {
+		driver->event_status = DIAG_CTRL_MASK_ALL_DISABLED;
 		memset(ptr, 0, EVENT_MASK_SIZE);
+	}
 	mutex_unlock(&driver->diagchar_mutex);
 }
 
 
-static void diag_update_event_mask(uint8_t *buf, int toggle, int num_bytes)
+static void diag_update_event_mask(uint8_t *buf, int num_bytes)
 {
 	uint8_t *ptr = driver->event_masks;
 	uint8_t *temp = buf + 2;
 
 	mutex_lock(&driver->diagchar_mutex);
-	if (!toggle)
-		memset(ptr, 0 , EVENT_MASK_SIZE);
-	else
-		if (CHK_OVERFLOW(ptr, ptr,
-				 ptr+EVENT_MASK_SIZE, num_bytes))
-			memcpy(ptr, temp , num_bytes);
-		else
-			printk(KERN_CRIT "Not enough buffer space for EVENT_MASK\n");
+	if (CHK_OVERFLOW(ptr, ptr, ptr+EVENT_MASK_SIZE, num_bytes)) {
+		memcpy(ptr, temp, num_bytes);
+		driver->event_status = DIAG_CTRL_MASK_VALID;
+	} else {
+		pr_err("diag: In %s, not enough buffer space\n", __func__);
+	}
 	mutex_unlock(&driver->diagchar_mutex);
 }
 
@@ -226,6 +241,7 @@
 			    (parse_ptr->num_items + 7)/8);
 		parse_ptr++;
 	}
+	driver->log_status = DIAG_CTRL_MASK_ALL_DISABLED;
 	mutex_unlock(&driver->diagchar_mutex);
 }
 
@@ -282,10 +298,13 @@
 	}
 	ptr_data = driver->log_masks + offset;
 	if (CHK_OVERFLOW(driver->log_masks, ptr_data, driver->log_masks
-					 + LOG_MASK_SIZE, (num_items+7)/8))
-		memcpy(ptr_data, temp , (num_items+7)/8);
-	else
+					 + LOG_MASK_SIZE, (num_items+7)/8)) {
+		memcpy(ptr_data, temp, (num_items+7)/8);
+		driver->log_status = DIAG_CTRL_MASK_VALID;
+	} else {
 		pr_err("diag: Not enough buffer space for LOG_MASK\n");
+		driver->log_status = DIAG_CTRL_MASK_INVALID;
+	}
 	mutex_unlock(&driver->diagchar_mutex);
 }
 
@@ -300,11 +319,11 @@
 		return;
 	}
 
+	diag_send_feature_mask_update(smd_info);
 	diag_send_msg_mask_update(smd_info->ch, ALL_SSID, ALL_SSID,
 						smd_info->peripheral);
 	diag_send_log_mask_update(smd_info->ch, ALL_EQUIP_ID);
 	diag_send_event_mask_update(smd_info->ch, diag_event_num_bytes);
-	diag_send_feature_mask_update(smd_info);
 
 	if (smd_info->notify_context == SMD_EVENT_OPEN)
 		diag_send_diag_mode_update_by_smd(smd_info,
@@ -330,15 +349,36 @@
 		driver->log_mask->num_items = ptr->num_items;
 		driver->log_mask->data_len  = 11 + size;
 		driver->log_mask->stream_id = 1; /* 2, if dual stream */
-		driver->log_mask->status = 3; /* status for valid mask */
 		driver->log_mask->equip_id = ptr->equip_id;
-		driver->log_mask->log_mask_size = size;
+		driver->log_mask->status = driver->log_status;
+		switch (driver->log_status) {
+		case DIAG_CTRL_MASK_ALL_DISABLED:
+			driver->log_mask->log_mask_size = 0;
+			break;
+		case DIAG_CTRL_MASK_ALL_ENABLED:
+			driver->log_mask->log_mask_size = 0;
+			break;
+		case DIAG_CTRL_MASK_VALID:
+			driver->log_mask->log_mask_size = size;
+			break;
+		default:
+			/* Log status is not set or the buffer is corrupted */
+			pr_err("diag: In %s, invalid status %d", __func__,
+							driver->log_status);
+			driver->log_mask->status = DIAG_CTRL_MASK_INVALID;
+		}
+
+		if (driver->msg_mask->status == DIAG_CTRL_MASK_INVALID) {
+			mutex_unlock(&driver->diag_cntl_mutex);
+			return;
+		}
 		/* send only desired update, NOT ALL */
 		if (equip_id == ALL_EQUIP_ID || equip_id ==
 					 driver->log_mask->equip_id) {
 			memcpy(buf, driver->log_mask, header_size);
-			memcpy(buf+header_size, driver->log_masks+ptr->index,
-									 size);
+			if (driver->log_status == DIAG_CTRL_MASK_VALID)
+				memcpy(buf + header_size,
+				       driver->log_masks+ptr->index, size);
 			if (ch) {
 				while (retry_count < 3) {
 					wr_size = smd_write(ch, buf,
@@ -380,11 +420,34 @@
 	driver->event_mask->cmd_type = DIAG_CTRL_MSG_EVENT_MASK;
 	driver->event_mask->data_len = 7 + num_bytes;
 	driver->event_mask->stream_id = 1; /* 2, if dual stream */
-	driver->event_mask->status = 3; /* status for valid mask */
-	driver->event_mask->event_config = diag_event_config; /* event config */
-	driver->event_mask->event_mask_size = num_bytes;
+	driver->event_mask->status = driver->event_status;
+
+	switch (driver->event_status) {
+	case DIAG_CTRL_MASK_ALL_DISABLED:
+		driver->event_mask->event_config = 0;
+		driver->event_mask->event_mask_size = 0;
+		break;
+	case DIAG_CTRL_MASK_ALL_ENABLED:
+		driver->event_mask->event_config = 1;
+		driver->event_mask->event_mask_size = 0;
+		break;
+	case DIAG_CTRL_MASK_VALID:
+		driver->event_mask->event_config = 1;
+		driver->event_mask->event_mask_size = num_bytes;
+		memcpy(buf + header_size, driver->event_masks, num_bytes);
+		break;
+	default:
+		/* Event status is not set yet or the buffer is corrupted */
+		pr_err("diag: In %s, invalid status %d", __func__,
+							driver->event_status);
+		driver->event_mask->status = DIAG_CTRL_MASK_INVALID;
+	}
+
+	if (driver->event_mask->status == DIAG_CTRL_MASK_INVALID) {
+		mutex_unlock(&driver->diag_cntl_mutex);
+		return;
+	}
 	memcpy(buf, driver->event_mask, header_size);
-	memcpy(buf+header_size, driver->event_masks, num_bytes);
 	if (ch) {
 		while (retry_count < 3) {
 			wr_size = smd_write(ch, buf, header_size + num_bytes);
@@ -418,44 +481,78 @@
 		ptr += 4;
 		actual_last = *(uint32_t *)ptr;
 		ptr += 4;
-		if ((updated_ssid_first >= first && updated_ssid_last <=
-			 actual_last) || (updated_ssid_first == ALL_SSID)) {
-			/* send f3 mask update */
-			driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
-			driver->msg_mask->msg_mask_size = actual_last -
-								 first + 1;
-			driver->msg_mask->data_len = 11 +
-					 4 * (driver->msg_mask->msg_mask_size);
-			driver->msg_mask->stream_id = 1; /* 2, if dual stream */
-			driver->msg_mask->status = 3; /* status valid mask */
-			driver->msg_mask->msg_mode = 0; /* Legcay mode */
-			driver->msg_mask->ssid_first = first;
-			driver->msg_mask->ssid_last = actual_last;
-			memcpy(buf, driver->msg_mask, header_size);
+		if (!((updated_ssid_first >= first && updated_ssid_last <=
+			 actual_last) || (updated_ssid_first == ALL_SSID))) {
+			ptr += MAX_SSID_PER_RANGE*4;
+			continue;
+		}
+		/* send f3 mask update */
+		driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
+		driver->msg_mask->status = driver->msg_status;
+		switch (driver->msg_status) {
+		case DIAG_CTRL_MASK_ALL_DISABLED:
+			driver->msg_mask->msg_mask_size = 0;
+			break;
+		case DIAG_CTRL_MASK_ALL_ENABLED:
+			driver->msg_mask->msg_mask_size = 1;
 			memcpy(buf+header_size, ptr,
 				 4 * (driver->msg_mask->msg_mask_size));
-			if (ch) {
-				while (retry_count < 3) {
-					size = smd_write(ch, buf, header_size +
-					 4*(driver->msg_mask->msg_mask_size));
-					if (size == -ENOMEM) {
-						retry_count++;
-						usleep_range(10000, 10100);
-					} else
-						break;
-				}
-				if (size != header_size +
-					 4*(driver->msg_mask->msg_mask_size))
-					pr_err("diag: proc %d, msg mask update fail %d, tried %d\n",
-						proc, size, (header_size +
-					4*(driver->msg_mask->msg_mask_size)));
-				else
-					pr_debug("diag: sending mask update for ssid first %d, last %d on PROC %d\n",
-						first, actual_last, proc);
-			} else
-				pr_err("diag: proc %d, ch invalid msg mask update\n",
-					proc);
+			break;
+		case DIAG_CTRL_MASK_VALID:
+			driver->msg_mask->msg_mask_size = actual_last -
+								first + 1;
+			/* Limit the msg_mask_size to MAX_SSID_PER_RANGE */
+			if (driver->msg_mask->msg_mask_size >
+							MAX_SSID_PER_RANGE) {
+				pr_err("diag: in %s, Invalid msg mask size %d, max: %d",
+					__func__,
+				       driver->msg_mask->msg_mask_size,
+				       MAX_SSID_PER_RANGE);
+				driver->msg_mask->msg_mask_size =
+							MAX_SSID_PER_RANGE;
+			}
+			memcpy(buf+header_size, ptr,
+				 4 * (driver->msg_mask->msg_mask_size));
+			break;
+		default:
+			/* Msg status is not set or the buffer is corrupted */
+			pr_err("diag: In %s, invalid status %d", __func__,
+							driver->msg_status);
+			driver->msg_mask->status = DIAG_CTRL_MASK_INVALID;
 		}
+
+		if (driver->msg_mask->status == DIAG_CTRL_MASK_INVALID) {
+			mutex_unlock(&driver->diag_cntl_mutex);
+			return;
+		}
+		driver->msg_mask->data_len = 11 +
+					4 * (driver->msg_mask->msg_mask_size);
+		driver->msg_mask->stream_id = 1; /* 2, if dual stream */
+		driver->msg_mask->msg_mode = 0; /* Legcay mode */
+		driver->msg_mask->ssid_first = first;
+		driver->msg_mask->ssid_last = actual_last;
+		memcpy(buf, driver->msg_mask, header_size);
+		if (ch) {
+			while (retry_count < 3) {
+				size = smd_write(ch, buf, header_size +
+				 4*(driver->msg_mask->msg_mask_size));
+				if (size == -ENOMEM) {
+					retry_count++;
+					usleep_range(10000, 10100);
+				} else
+					break;
+			}
+			if (size != header_size +
+				 4*(driver->msg_mask->msg_mask_size))
+				pr_err("diag: proc %d, msg mask update fail %d, tried %d\n",
+					proc, size, (header_size +
+				4*(driver->msg_mask->msg_mask_size)));
+			else
+				pr_debug("diag: sending mask update for ssid first %d, last %d on PROC %d\n",
+					first, actual_last, proc);
+		} else
+			pr_err("diag: proc %d, ch invalid msg mask update\n",
+								proc);
 		ptr += MAX_SSID_PER_RANGE*4;
 	}
 	mutex_unlock(&driver->diag_cntl_mutex);
@@ -706,8 +803,8 @@
 #endif
 	} else if (*buf == 0x82) {	/* event mask change */
 		buf += 4;
-		diag_event_num_bytes =  (*(uint16_t *)buf)/8+1;
-		diag_update_event_mask(buf, 1, (*(uint16_t *)buf)/8+1);
+		diag_event_num_bytes = (*(uint16_t *)buf)/8+1;
+		diag_update_event_mask(buf, diag_event_num_bytes);
 		diag_update_userspace_clients(EVENT_MASKS_TYPE);
 #if defined(CONFIG_DIAG_OVER_USB)
 		if (chk_apps_only()) {
@@ -729,7 +826,6 @@
 		}
 #endif
 	} else if (*buf == 0x60) {
-		diag_event_config = *(buf+1);
 		diag_toggle_event_mask(*(buf+1));
 		diag_update_userspace_clients(EVENT_MASKS_TYPE);
 #if defined(CONFIG_DIAG_OVER_USB)
@@ -764,6 +860,10 @@
 
 void diag_masks_init(void)
 {
+	driver->event_status = DIAG_CTRL_MASK_INVALID;
+	driver->msg_status = DIAG_CTRL_MASK_INVALID;
+	driver->log_status = DIAG_CTRL_MASK_INVALID;
+
 	if (driver->event_mask == NULL) {
 		driver->event_mask = kzalloc(sizeof(
 			struct diag_ctrl_event_mask), GFP_KERNEL);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 7ef1d80..e5acb6c 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -64,6 +64,8 @@
 #define NUM_MEMORY_POOLS	4
 #endif
 
+#define MAX_SSID_PER_RANGE	200
+
 #define MODEM_DATA		0
 #define LPASS_DATA		1
 #define WCNSS_DATA		2
@@ -73,7 +75,13 @@
 #define HSIC_2_DATA		6
 #define SMUX_DATA		10
 #define APPS_PROC		1
-#define MSG_MASK_SIZE 10000
+/*
+ * Each row contains First (uint32_t), Last (uint32_t), Actual
+ * last (uint32_t) values along with the range of SSIDs
+ * (MAX_SSID_PER_RANGE*uint32_t).
+ * And there are MSG_MASK_TBL_CNT rows.
+ */
+#define MSG_MASK_SIZE		((MAX_SSID_PER_RANGE+3) * 4 * MSG_MASK_TBL_CNT)
 #define LOG_MASK_SIZE 8000
 #define EVENT_MASK_SIZE 1000
 #define USER_SPACE_DATA 8192
@@ -362,9 +370,12 @@
 	struct work_struct diag_drain_work;
 	struct workqueue_struct *diag_cntl_wq;
 	uint8_t *msg_masks;
+	uint8_t msg_status;
 	uint8_t *log_masks;
+	uint8_t log_status;
 	int log_masks_length;
 	uint8_t *event_masks;
+	uint8_t event_status;
 	uint8_t log_on_demand_support;
 	struct diag_master_table *table;
 	uint8_t *pkt_buf;
@@ -412,5 +423,6 @@
 extern uint16_t wrap_count;
 
 void diag_get_timestamp(char *time_str);
+int diag_find_polling_reg(int i);
 
 #endif
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 24d7fac..19ff6f4 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -327,17 +327,19 @@
 	subsys_id = driver->table[i].subsys_id;
 	cmd_code_lo = driver->table[i].cmd_code_lo;
 	cmd_code_hi = driver->table[i].cmd_code_hi;
-	if (driver->table[i].cmd_code == 0x0C)
-		return 1;
-	else if (driver->table[i].cmd_code == 0xFF) {
-		if (subsys_id == 0x04 && cmd_code_hi == 0x0E &&
-			 cmd_code_lo == 0x0E)
+
+	if (driver->table[i].cmd_code == 0xFF) {
+		if (subsys_id == 0xFF && cmd_code_hi >= 0x0C &&
+			 cmd_code_lo <= 0x0C)
 			return 1;
-		else if (subsys_id == 0x08 && cmd_code_hi == 0x02 &&
-			 cmd_code_lo == 0x02)
+		if (subsys_id == 0x04 && cmd_code_hi >= 0x0E &&
+			 cmd_code_lo <= 0x0E)
 			return 1;
-		else if (subsys_id == 0x32 && cmd_code_hi == 0x03  &&
-			 cmd_code_lo == 0x03)
+		else if (subsys_id == 0x08 && cmd_code_hi >= 0x02 &&
+			 cmd_code_lo <= 0x02)
+			return 1;
+		else if (subsys_id == 0x32 && cmd_code_hi >= 0x03  &&
+			 cmd_code_lo <= 0x03)
 			return 1;
 	}
 	return 0;
@@ -356,7 +358,8 @@
 	}
 	/* re-scan the registration table */
 	for (i = 0; i < diag_max_reg; i++) {
-		if (diag_find_polling_reg(i) == 1) {
+		if (driver->table[i].process_id != 0 &&
+				diag_find_polling_reg(i) == 1) {
 			driver->polling_reg_flag = 1;
 			break;
 		}
@@ -1271,17 +1274,6 @@
 						data->write_ptr_1->length);
 					data->in_busy_1 = 0;
 				}
-				if (data->in_busy_2 == 1) {
-					num_data++;
-					/*Copy the length of data being passed*/
-					COPY_USER_SPACE_OR_EXIT(buf+ret,
-						(data->write_ptr_2->length), 4);
-					/*Copy the actual data being passed*/
-					COPY_USER_SPACE_OR_EXIT(buf+ret,
-						*(data->buf_in_2),
-						data->write_ptr_2->length);
-					data->in_busy_2 = 0;
-				}
 			}
 		}
 #ifdef CONFIG_DIAG_SDIO_PIPE
diff --git a/drivers/char/diag/diagchar_hdlc.c b/drivers/char/diag/diagchar_hdlc.c
index 2369c4d..7b24591 100644
--- a/drivers/char/diag/diagchar_hdlc.c
+++ b/drivers/char/diag/diagchar_hdlc.c
@@ -18,6 +18,7 @@
 #include <linux/fs.h>
 #include <linux/device.h>
 #include <linux/uaccess.h>
+#include <linux/ratelimit.h>
 #include <linux/crc-ccitt.h>
 #include "diagchar_hdlc.h"
 #include "diagchar.h"
@@ -234,3 +235,37 @@
 
 	return pkt_bnd;
 }
+
+int crc_check(uint8_t *buf, uint16_t len)
+{
+	uint16_t crc = CRC_16_L_SEED;
+	uint8_t sent_crc[2] = {0, 0};
+
+	/*
+	 * The minimum length of a valid incoming packet is 4. 1 byte
+	 * of data and 3 bytes for CRC
+	 */
+	if (!buf || len < 4) {
+		pr_err_ratelimited("diag: In %s, invalid packet or length, buf: 0x%x, len: %d",
+				   __func__, (int)buf, len);
+		return -EIO;
+	}
+
+	/*
+	 * Run CRC check for the original input. Skip the last 3 CRC
+	 * bytes
+	 */
+	crc = crc_ccitt(crc, buf, len-3);
+	crc ^= CRC_16_L_SEED;
+
+	/* Check the computed CRC against the original CRC bytes. */
+	sent_crc[0] = buf[len-3];
+	sent_crc[1] = buf[len-2];
+	if (crc != *((uint16_t *)sent_crc)) {
+		pr_debug("diag: In %s, crc mismatch. expected: %x, sent %x.\n",
+				__func__, crc, *((uint16_t *)sent_crc));
+		return -EIO;
+	}
+
+	return 0;
+}
diff --git a/drivers/char/diag/diagchar_hdlc.h b/drivers/char/diag/diagchar_hdlc.h
index e3378ac..2ba46f5 100644
--- a/drivers/char/diag/diagchar_hdlc.h
+++ b/drivers/char/diag/diagchar_hdlc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2009, 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2009, 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -53,6 +53,8 @@
 
 int diag_hdlc_decode(struct diag_hdlc_decode_type *hdlc);
 
+int crc_check(uint8_t *buf, uint16_t len);
+
 #define ESC_CHAR     0x7D
 #define ESC_MASK     0x20
 
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index a1f6b2c..1e8b0ba 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1514,7 +1514,7 @@
 void diag_process_hdlc(void *data, unsigned len)
 {
 	struct diag_hdlc_decode_type hdlc;
-	int ret, type = 0;
+	int ret, type = 0, crc_chk = 0;
 
 	mutex_lock(&driver->diag_hdlc_mutex);
 
@@ -1528,6 +1528,16 @@
 	hdlc.escaping = 0;
 
 	ret = diag_hdlc_decode(&hdlc);
+	if (ret) {
+		crc_chk = crc_check(hdlc.dest_ptr, hdlc.dest_idx);
+		if (crc_chk) {
+			/* CRC check failed. */
+			pr_err_ratelimited("diag: In %s, bad CRC. Dropping packet\n",
+								__func__);
+			mutex_unlock(&driver->diag_hdlc_mutex);
+			return;
+		}
+	}
 
 	/*
 	 * If the message is 3 bytes or less in length then the message is
@@ -1550,9 +1560,8 @@
 			return;
 		}
 	} else if (driver->debug_flag) {
-		printk(KERN_ERR "Packet dropped due to bad HDLC coding/CRC"
-				" errors or partial packet received, packet"
-				" length = %d\n", len);
+		pr_err("diag: In %s, partial packet received, dropping packet, len: %d\n",
+								__func__, len);
 		print_hex_dump(KERN_DEBUG, "Dropped Packet Data: ", 16, 1,
 					   DUMP_PREFIX_ADDRESS, data, len, 1);
 		driver->debug_flag = 0;
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index c501700..3225817 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -45,6 +45,8 @@
 #define tmc_writel(drvdata, val, off)	__raw_writel((val), drvdata->base + off)
 #define tmc_readl(drvdata, off)		__raw_readl(drvdata->base + off)
 
+#define tmc_readl_no_log(drvdata, off)	__raw_readl_no_log(drvdata->base + off)
+
 #define TMC_LOCK(drvdata)						\
 do {									\
 	mb();								\
@@ -651,7 +653,7 @@
 	bufp = drvdata->buf;
 	while (1) {
 		for (i = 0; i < memwords; i++) {
-			read_data = tmc_readl(drvdata, TMC_RRD);
+			read_data = tmc_readl_no_log(drvdata, TMC_RRD);
 			if (read_data == 0xFFFFFFFF)
 				goto out;
 			memcpy(bufp, &read_data, BYTES_PER_WORD);
@@ -1451,14 +1453,17 @@
 
 	if (!drvdata->byte_cntr_present) {
 		dev_info(&pdev->dev, "Byte Counter feature absent\n");
-		return 0;
+		goto out;
 	}
 
 	drvdata->byte_cntr_irq = platform_get_irq_byname(pdev,
 							"byte-cntr-irq");
 	if (drvdata->byte_cntr_irq < 0) {
+		/* Even though this is an error condition, we do not fail
+		 * the probe as the byte counter feature is optional
+		 */
 		dev_err(&pdev->dev, "Byte-cntr-irq not specified\n");
-		return 0;
+		goto err;
 	}
 	ret = devm_request_irq(&pdev->dev, drvdata->byte_cntr_irq,
 			tmc_etr_byte_cntr_irq,
@@ -1466,7 +1471,7 @@
 			node_name, drvdata);
 	if (ret) {
 		dev_err(&pdev->dev, "Request irq failed\n");
-		return ret;
+		goto err;
 	}
 	init_waitqueue_head(&drvdata->wq);
 	node_size += strlen(node_name);
@@ -1477,10 +1482,14 @@
 	ret = tmc_etr_byte_cntr_dev_register(drvdata);
 	if (ret) {
 		dev_err(&pdev->dev, "Byte cntr node not registered\n");
-		return ret;
+		goto err;
 	}
 	dev_info(&pdev->dev, "Byte Counter feature enabled\n");
 	return 0;
+err:
+	drvdata->byte_cntr_present = false;
+out:
+	return ret;
 }
 
 static void tmc_etr_byte_cntr_exit(struct tmc_drvdata *drvdata)
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 418c488..e6b2a3c 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -346,6 +346,7 @@
 	dbs_tuners_ins.sampling_rate = new_rate
 				     = max(new_rate, min_sampling_rate);
 
+	get_online_cpus();
 	for_each_online_cpu(cpu) {
 		struct cpufreq_policy *policy;
 		struct cpu_dbs_info_s *dbs_info;
@@ -380,6 +381,7 @@
 		}
 		mutex_unlock(&dbs_info->timer_mutex);
 	}
+	put_online_cpus();
 }
 
 static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
@@ -584,8 +586,8 @@
 
 	dbs_tuners_ins.powersave_bias = input;
 
-	mutex_lock(&dbs_mutex);
 	get_online_cpus();
+	mutex_lock(&dbs_mutex);
 
 	if (!bypass) {
 		if (reenable_timer) {
@@ -661,8 +663,8 @@
 		}
 	}
 
-	put_online_cpus();
 	mutex_unlock(&dbs_mutex);
+	put_online_cpus();
 
 	return count;
 }
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 0e4b309..c726694 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -564,7 +564,7 @@
 
 	creq.qce_cb = qcedev_cipher_req_cb;
 	creq.areq = (void *)&qcedev_areq->cipher_req;
-
+	creq.flags = 0;
 	ret = qce_ablk_cipher_req(podev->qce, &creq);
 unsupported:
 	if (ret)
@@ -640,6 +640,7 @@
 	sreq.size = qcedev_areq->sha_req.sreq.nbytes;
 	sreq.src = qcedev_areq->sha_req.sreq.src;
 	sreq.areq = (void *)&qcedev_areq->sha_req;
+	sreq.flags = 0;
 
 	ret = qce_process_sha_req(podev->qce, &sreq);
 
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index c98cbba..ae57d6c 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -492,6 +492,7 @@
 	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
 
 	q_alg = container_of(alg, struct qcrypto_alg, cipher_alg);
+	ctx->flags = 0;
 
 	/* update context with ptr to cp */
 	ctx->cp = q_alg->cp;
@@ -517,6 +518,8 @@
 	/* update context with ptr to cp */
 	sha_ctx->cp = q_alg->cp;
 	sha_ctx->sg = NULL;
+	sha_ctx->flags = 0;
+
 	sha_ctx->tmp_tbuf = kzalloc(SHA_MAX_BLOCK_SIZE +
 					SHA_MAX_DIGEST_SIZE, GFP_KERNEL);
 	if (sha_ctx->tmp_tbuf == NULL) {
diff --git a/drivers/gpio/gpio-msm-common.c b/drivers/gpio/gpio-msm-common.c
index 3115628..3d18809 100644
--- a/drivers/gpio/gpio-msm-common.c
+++ b/drivers/gpio/gpio-msm-common.c
@@ -84,6 +84,7 @@
 	{SDC1_HDRV_PULL_CTL, 13}, /* TLMM_PULL_SDC1_CLK  */
 	{SDC1_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC1_CMD  */
 	{SDC1_HDRV_PULL_CTL, 9},  /* TLMM_PULL_SDC1_DATA */
+	{SDC1_HDRV_PULL_CTL, 15}, /* TLMM_PULL_SDC1_RCLK  */
 };
 
 /*
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index 1ea3cd2..d9e9e09 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -136,12 +136,18 @@
 	return NULL;
 }
 
-static int ion_iommu_buffer_zero(struct ion_iommu_priv_data *data)
+static int ion_iommu_buffer_zero(struct ion_iommu_priv_data *data,
+				bool is_cached)
 {
-	int i, j;
+	int i, j, k;
 	unsigned int npages_to_vmap;
 	unsigned int total_pages;
 	void *ptr = NULL;
+	/*
+	 * It's cheaper just to use writecombine memory and skip the
+	 * cache vs. using a cache memory and trying to flush it afterwards
+	 */
+	pgprot_t pgprot = pgprot_writecombine(pgprot_kernel);
 
 	/*
 	 * As an optimization, we manually zero out all of the
@@ -161,7 +167,7 @@
 		for (j = 0; j < MAX_VMAP_RETRIES && npages_to_vmap;
 			++j) {
 			ptr = vmap(&data->pages[i], npages_to_vmap,
-					VM_IOREMAP, pgprot_kernel);
+					VM_IOREMAP, pgprot);
 			if (ptr)
 				break;
 			else
@@ -171,6 +177,20 @@
 			return -ENOMEM;
 
 		memset(ptr, 0, npages_to_vmap * PAGE_SIZE);
+		if (is_cached) {
+			/*
+			 * invalidate the cache to pick up the zeroing
+			 */
+			for (k = 0; k < npages_to_vmap; k++) {
+				void *p = kmap_atomic(data->pages[i + k]);
+				phys_addr_t phys = page_to_phys(
+							data->pages[i + k]);
+
+				dmac_inv_range(p, p + PAGE_SIZE);
+				outer_inv_range(phys, phys + PAGE_SIZE);
+				kunmap_atomic(p);
+			}
+		}
 		vunmap(ptr);
 	}
 
@@ -269,7 +289,7 @@
 
 
 		if (flags & ION_FLAG_POOL_FORCE_ALLOC) {
-			ret = ion_iommu_buffer_zero(data);
+			ret = ion_iommu_buffer_zero(data, ION_IS_CACHED(flags));
 			if (ret) {
 				pr_err("Couldn't vmap the pages for zeroing\n");
 				goto err3;
@@ -328,7 +348,7 @@
 		return;
 
 	if (!(buffer->flags & ION_FLAG_POOL_FORCE_ALLOC))
-		ion_iommu_buffer_zero(data);
+		ion_iommu_buffer_zero(data, ION_IS_CACHED(buffer->flags));
 
 	for_each_sg(table->sgl, sg, table->nents, i) {
 		int order = get_order(sg_dma_len(sg));
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index aac183b..118e033 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -22,11 +22,9 @@
 msm_adreno-y += \
 	adreno_ringbuffer.o \
 	adreno_drawctxt.o \
-	adreno_dispatch.o \
 	adreno_postmortem.o \
 	adreno_snapshot.o \
 	adreno_coresight.o \
-	adreno_trace.o \
 	adreno_a2xx.o \
 	adreno_a2xx_trace.o \
 	adreno_a2xx_snapshot.o \
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 0c398c4..b5945da 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -240,6 +240,7 @@
 #define A3XX_PC_PERFCOUNTER1_SELECT 0xC49
 #define A3XX_PC_PERFCOUNTER2_SELECT 0xC4A
 #define A3XX_PC_PERFCOUNTER3_SELECT 0xC4B
+#define A3XX_GRAS_TSE_DEBUG_ECO 0xC81
 #define A3XX_GRAS_PERFCOUNTER0_SELECT 0xC88
 #define A3XX_GRAS_PERFCOUNTER1_SELECT 0xC89
 #define A3XX_GRAS_PERFCOUNTER2_SELECT 0xC8A
@@ -269,8 +270,10 @@
 #define A3XX_GRAS_CL_USER_PLANE_Z5 0xCB6
 #define A3XX_GRAS_CL_USER_PLANE_W5 0xCB7
 #define A3XX_RB_GMEM_BASE_ADDR 0xCC0
+#define A3XX_RB_DEBUG_ECO_CONTROLS_ADDR 0xCC1
 #define A3XX_RB_PERFCOUNTER0_SELECT   0xCC6
 #define A3XX_RB_PERFCOUNTER1_SELECT   0xCC7
+#define A3XX_RB_FRAME_BUFFER_DIMENSION 0xCE0
 #define A3XX_HLSQ_PERFCOUNTER0_SELECT 0xE00
 #define A3XX_HLSQ_PERFCOUNTER1_SELECT 0xE01
 #define A3XX_HLSQ_PERFCOUNTER2_SELECT 0xE02
@@ -308,6 +311,9 @@
 #define A3XX_GRAS_CL_CLIP_CNTL 0x2040
 #define A3XX_GRAS_CL_GB_CLIP_ADJ 0x2044
 #define A3XX_GRAS_CL_VPORT_XOFFSET 0x2048
+#define A3XX_GRAS_CL_VPORT_XSCALE 0x2049
+#define A3XX_GRAS_CL_VPORT_YOFFSET 0x204A
+#define A3XX_GRAS_CL_VPORT_YSCALE 0x204B
 #define A3XX_GRAS_CL_VPORT_ZOFFSET 0x204C
 #define A3XX_GRAS_CL_VPORT_ZSCALE 0x204D
 #define A3XX_GRAS_SU_POINT_MINMAX 0x2068
@@ -323,30 +329,75 @@
 #define A3XX_RB_MODE_CONTROL 0x20C0
 #define A3XX_RB_RENDER_CONTROL 0x20C1
 #define A3XX_RB_MSAA_CONTROL 0x20C2
+#define A3XX_RB_ALPHA_REFERENCE 0x20C3
 #define A3XX_RB_MRT_CONTROL0 0x20C4
 #define A3XX_RB_MRT_BUF_INFO0 0x20C5
+#define A3XX_RB_MRT_BUF_BASE0 0x20C6
 #define A3XX_RB_MRT_BLEND_CONTROL0 0x20C7
+#define A3XX_RB_MRT_CONTROL1 0x20C8
+#define A3XX_RB_MRT_BUF_INFO1 0x20C9
+#define A3XX_RB_MRT_BUF_BASE1 0x20CA
 #define A3XX_RB_MRT_BLEND_CONTROL1 0x20CB
+#define A3XX_RB_MRT_CONTROL2 0x20CC
+#define A3XX_RB_MRT_BUF_INFO2 0x20CD
+#define A3XX_RB_MRT_BUF_BASE2 0x20CE
 #define A3XX_RB_MRT_BLEND_CONTROL2 0x20CF
+#define A3XX_RB_MRT_CONTROL3 0x20D0
+#define A3XX_RB_MRT_BUF_INFO3 0x20D1
+#define A3XX_RB_MRT_BUF_BASE3 0x20D2
 #define A3XX_RB_MRT_BLEND_CONTROL3 0x20D3
 #define A3XX_RB_BLEND_RED 0x20E4
+#define A3XX_RB_BLEND_GREEN 0x20E5
+#define A3XX_RB_BLEND_BLUE 0x20E6
+#define A3XX_RB_BLEND_ALPHA 0x20E7
+#define A3XX_RB_CLEAR_COLOR_DW0 0x20E8
+#define A3XX_RB_CLEAR_COLOR_DW1 0x20E9
+#define A3XX_RB_CLEAR_COLOR_DW2 0x20EA
+#define A3XX_RB_CLEAR_COLOR_DW3 0x20EB
 #define A3XX_RB_COPY_CONTROL 0x20EC
+#define A3XX_RB_COPY_DEST_BASE 0x20ED
+#define A3XX_RB_COPY_DEST_PITCH 0x20EE
 #define A3XX_RB_COPY_DEST_INFO 0x20EF
 #define A3XX_RB_DEPTH_CONTROL 0x2100
+#define A3XX_RB_DEPTH_CLEAR 0x2101
+#define A3XX_RB_DEPTH_BUF_INFO 0x2102
+#define A3XX_RB_DEPTH_BUF_PITCH 0x2103
 #define A3XX_RB_STENCIL_CONTROL 0x2104
+#define A3XX_RB_STENCIL_CLEAR 0x2105
+#define A3XX_RB_STENCIL_BUF_INFO 0x2106
+#define A3XX_RB_STENCIL_BUF_PITCH 0x2107
+#define A3XX_RB_STENCIL_REF_MASK 0x2108
+#define A3XX_RB_STENCIL_REF_MASK_BF 0x2109
+#define A3XX_RB_LRZ_VSC_CONTROL 0x210C
+#define A3XX_RB_WINDOW_OFFSET 0x210E
+#define A3XX_RB_SAMPLE_COUNT_CONTROL 0x2110
+#define A3XX_RB_SAMPLE_COUNT_ADDR 0x2111
+#define A3XX_RB_Z_CLAMP_MIN 0x2114
+#define A3XX_RB_Z_CLAMP_MAX 0x2115
 #define A3XX_PC_VSTREAM_CONTROL 0x21E4
 #define A3XX_PC_VERTEX_REUSE_BLOCK_CNTL 0x21EA
 #define A3XX_PC_PRIM_VTX_CNTL 0x21EC
 #define A3XX_PC_RESTART_INDEX 0x21ED
 #define A3XX_HLSQ_CONTROL_0_REG 0x2200
+#define A3XX_HLSQ_CONTROL_1_REG 0x2201
+#define A3XX_HLSQ_CONTROL_2_REG 0x2202
+#define A3XX_HLSQ_CONTROL_3_REG 0x2203
 #define A3XX_HLSQ_VS_CONTROL_REG 0x2204
+#define A3XX_HLSQ_FS_CONTROL_REG 0x2205
+#define A3XX_HLSQ_CONST_VSPRESV_RANGE_REG 0x2206
 #define A3XX_HLSQ_CONST_FSPRESV_RANGE_REG 0x2207
 #define A3XX_HLSQ_CL_NDRANGE_0_REG 0x220A
+#define A3XX_HLSQ_CL_NDRANGE_1_REG 0x220B
 #define A3XX_HLSQ_CL_NDRANGE_2_REG 0x220C
+#define A3XX_HLSQ_CL_NDRANGE_3_REG 0x220D
+#define A3XX_HLSQ_CL_NDRANGE_4_REG 0x220E
+#define A3XX_HLSQ_CL_NDRANGE_5_REG 0x220F
+#define A3XX_HLSQ_CL_NDRANGE_6_REG 0x2210
 #define A3XX_HLSQ_CL_CONTROL_0_REG 0x2211
 #define A3XX_HLSQ_CL_CONTROL_1_REG 0x2212
 #define A3XX_HLSQ_CL_KERNEL_CONST_REG 0x2214
 #define A3XX_HLSQ_CL_KERNEL_GROUP_X_REG 0x2215
+#define A3XX_HLSQ_CL_KERNEL_GROUP_Y_REG 0x2216
 #define A3XX_HLSQ_CL_KERNEL_GROUP_Z_REG 0x2217
 #define A3XX_HLSQ_CL_WG_OFFSET_REG 0x221A
 #define A3XX_VFD_CONTROL_0 0x2240
@@ -363,10 +414,21 @@
 #define A3XX_SP_VS_CTRL_REG0 0x22C4
 #define A3XX_SP_VS_CTRL_REG1 0x22C5
 #define A3XX_SP_VS_PARAM_REG 0x22C6
+#define A3XX_SP_VS_OUT_REG_0 0x22C7
+#define A3XX_SP_VS_OUT_REG_1 0x22C8
+#define A3XX_SP_VS_OUT_REG_2 0x22C9
+#define A3XX_SP_VS_OUT_REG_3 0x22CA
+#define A3XX_SP_VS_OUT_REG_4 0x22CB
+#define A3XX_SP_VS_OUT_REG_5 0x22CC
+#define A3XX_SP_VS_OUT_REG_6 0x22CD
 #define A3XX_SP_VS_OUT_REG_7 0x22CE
 #define A3XX_SP_VS_VPC_DST_REG_0 0x22D0
+#define A3XX_SP_VS_VPC_DST_REG_1 0x22D1
+#define A3XX_SP_VS_VPC_DST_REG_2 0x22D2
+#define A3XX_SP_VS_VPC_DST_REG_3 0x22D3
 #define A3XX_SP_VS_OBJ_OFFSET_REG 0x22D4
 #define A3XX_SP_VS_OBJ_START_REG 0x22D5
+#define A3XX_SP_VS_PVT_MEM_PARAM_REG 0x22D6
 #define A3XX_SP_VS_PVT_MEM_ADDR_REG 0x22D7
 #define A3XX_SP_VS_PVT_MEM_SIZE_REG 0x22D8
 #define A3XX_SP_VS_LENGTH_REG 0x22DF
@@ -374,13 +436,19 @@
 #define A3XX_SP_FS_CTRL_REG1 0x22E1
 #define A3XX_SP_FS_OBJ_OFFSET_REG 0x22E2
 #define A3XX_SP_FS_OBJ_START_REG 0x22E3
+#define A3XX_SP_FS_PVT_MEM_PARAM_REG 0x22E4
 #define A3XX_SP_FS_PVT_MEM_ADDR_REG 0x22E5
 #define A3XX_SP_FS_PVT_MEM_SIZE_REG 0x22E6
 #define A3XX_SP_FS_FLAT_SHAD_MODE_REG_0 0x22E8
 #define A3XX_SP_FS_FLAT_SHAD_MODE_REG_1 0x22E9
 #define A3XX_SP_FS_OUTPUT_REG 0x22EC
 #define A3XX_SP_FS_MRT_REG_0 0x22F0
+#define A3XX_SP_FS_MRT_REG_1 0x22F1
+#define A3XX_SP_FS_MRT_REG_2 0x22F2
+#define A3XX_SP_FS_MRT_REG_3 0x22F3
 #define A3XX_SP_FS_IMAGE_OUTPUT_REG_0 0x22F4
+#define A3XX_SP_FS_IMAGE_OUTPUT_REG_1 0x22F5
+#define A3XX_SP_FS_IMAGE_OUTPUT_REG_2 0x22F6
 #define A3XX_SP_FS_IMAGE_OUTPUT_REG_3 0x22F7
 #define A3XX_SP_FS_LENGTH_REG 0x22FF
 #define A3XX_TPL1_TP_VS_TEX_OFFSET 0x2340
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 8875d74..dcaa4e1 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -32,7 +32,6 @@
 
 #include "adreno.h"
 #include "adreno_pm4types.h"
-#include "adreno_trace.h"
 
 #include "a2xx_reg.h"
 #include "a3xx_reg.h"
@@ -72,6 +71,8 @@
 	 | (MMU_CONFIG << MH_MMU_CONFIG__TC_R_CLNT_BEHAVIOR__SHIFT)	\
 	 | (MMU_CONFIG << MH_MMU_CONFIG__PA_W_CLNT_BEHAVIOR__SHIFT))
 
+#define KGSL_LOG_LEVEL_DEFAULT 3
+
 static const struct kgsl_functable adreno_functable;
 
 static struct adreno_device device_3d0 = {
@@ -101,6 +102,13 @@
 		.iomemname = KGSL_3D0_REG_MEMORY,
 		.shadermemname = KGSL_3D0_SHADER_MEMORY,
 		.ftbl = &adreno_functable,
+		.cmd_log = KGSL_LOG_LEVEL_DEFAULT,
+		.ctxt_log = KGSL_LOG_LEVEL_DEFAULT,
+		.drv_log = KGSL_LOG_LEVEL_DEFAULT,
+		.mem_log = KGSL_LOG_LEVEL_DEFAULT,
+		.pwr_log = KGSL_LOG_LEVEL_DEFAULT,
+		.ft_log = KGSL_LOG_LEVEL_DEFAULT,
+		.pm_dump_enable = 0,
 	},
 	.gmem_base = 0,
 	.gmem_size = SZ_256K,
@@ -114,6 +122,12 @@
 	.long_ib_detect = 1,
 };
 
+/* This set of registers are used for Hang detection
+ * If the values of these registers are same after
+ * KGSL_TIMEOUT_PART time, GPU hang is reported in
+ * kernel log.
+ */
+
 unsigned int ft_detect_regs[FT_DETECT_REGS_COUNT];
 
 /*
@@ -202,6 +216,8 @@
 		512, 0, 2, SZ_128K, 0x3FF037, 0x3FF016 },
 };
 
+static unsigned int adreno_isidle(struct kgsl_device *device);
+
 /**
  * adreno_perfcounter_init: Reserve kernel performance counters
  * @device: device to configure
@@ -585,9 +601,23 @@
 
 static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
 {
+	irqreturn_t result;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 
-	return adreno_dev->gpudev->irq_handler(adreno_dev);
+	result = adreno_dev->gpudev->irq_handler(adreno_dev);
+
+	device->pwrctrl.irq_last = 1;
+	if (device->requested_state == KGSL_STATE_NONE) {
+		kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
+		queue_work(device->work_queue, &device->idle_check_ws);
+	}
+
+	/* Reset the time-out in our idle timer */
+	mod_timer_pending(&device->idle_timer,
+		jiffies + device->pwrctrl.interval_timeout);
+	mod_timer_pending(&device->hang_timer,
+		(jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
+	return result;
 }
 
 static void adreno_cleanup_pt(struct kgsl_device *device,
@@ -604,36 +634,44 @@
 
 	kgsl_mmu_unmap(pagetable, &adreno_dev->profile.shared_buffer);
 
+	kgsl_mmu_unmap(pagetable, &adreno_dev->pwron_fixup);
+
 	kgsl_mmu_unmap(pagetable, &device->mmu.setstate_memory);
 }
 
 static int adreno_setup_pt(struct kgsl_device *device,
 			struct kgsl_pagetable *pagetable)
 {
-	int result = 0;
+	int result;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
 
 	result = kgsl_mmu_map_global(pagetable, &rb->buffer_desc);
-	if (result)
-		goto error;
 
-	result = kgsl_mmu_map_global(pagetable, &rb->memptrs_desc);
-	if (result)
-		goto unmap_buffer_desc;
+	if (!result)
+		result = kgsl_mmu_map_global(pagetable, &rb->memptrs_desc);
 
-	result = kgsl_mmu_map_global(pagetable, &device->memstore);
-	if (result)
-		goto unmap_memptrs_desc;
+	if (!result)
+		result = kgsl_mmu_map_global(pagetable, &device->memstore);
 
-	result = kgsl_mmu_map_global(pagetable,
-					&adreno_dev->profile.shared_buffer);
-	if (result)
-		goto unmap_profile_shared;
+	if (!result)
+		result = kgsl_mmu_map_global(pagetable,
+			&adreno_dev->profile.shared_buffer);
 
-	result = kgsl_mmu_map_global(pagetable, &device->mmu.setstate_memory);
-	if (result)
-		goto unmap_memstore_desc;
+	if (!result)
+		result = kgsl_mmu_map_global(pagetable,
+			&adreno_dev->pwron_fixup);
+
+
+	if (!result)
+		result = kgsl_mmu_map_global(pagetable,
+			&device->mmu.setstate_memory);
+
+	if (result) {
+		/* On error clean up what we have wrought */
+		adreno_cleanup_pt(device, pagetable);
+		return result;
+	}
 
 	/*
 	 * Set the mpu end to the last "normal" global memory we use.
@@ -642,22 +680,8 @@
 	 */
 	device->mh.mpu_range = device->mmu.setstate_memory.gpuaddr +
 				device->mmu.setstate_memory.size;
-	return result;
 
-unmap_profile_shared:
-	kgsl_mmu_unmap(pagetable, &adreno_dev->profile.shared_buffer);
-
-unmap_memstore_desc:
-	kgsl_mmu_unmap(pagetable, &device->memstore);
-
-unmap_memptrs_desc:
-	kgsl_mmu_unmap(pagetable, &rb->memptrs_desc);
-
-unmap_buffer_desc:
-	kgsl_mmu_unmap(pagetable, &rb->buffer_desc);
-
-error:
-	return result;
+	return 0;
 }
 
 static unsigned int _adreno_iommu_setstate_v0(struct kgsl_device *device,
@@ -888,13 +912,12 @@
 static bool adreno_use_default_setstate(struct adreno_device *adreno_dev)
 {
 	return (adreno_isidle(&adreno_dev->dev) ||
-		adreno_dev->drawctxt_active == NULL ||
 		KGSL_STATE_ACTIVE != adreno_dev->dev.state ||
 		atomic_read(&adreno_dev->dev.active_cnt) == 0 ||
 		adreno_dev->dev.cff_dump_enable);
 }
 
-static int adreno_iommu_setstate(struct kgsl_device *device,
+static void adreno_iommu_setstate(struct kgsl_device *device,
 					unsigned int context_id,
 					uint32_t flags)
 {
@@ -907,24 +930,22 @@
 	struct kgsl_context *context;
 	struct adreno_context *adreno_ctx = NULL;
 	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
-	unsigned int result;
 
 	if (adreno_use_default_setstate(adreno_dev)) {
 		kgsl_mmu_device_setstate(&device->mmu, flags);
-		return 0;
+		return;
 	}
 	num_iommu_units = kgsl_mmu_get_num_iommu_units(&device->mmu);
 
 	context = kgsl_context_get(device, context_id);
 	if (context == NULL)
-		return -EINVAL;
+		return;
 
 	adreno_ctx = ADRENO_CONTEXT(context);
 
-	result = kgsl_mmu_enable_clk(&device->mmu, KGSL_IOMMU_CONTEXT_USER);
-
-	if (result)
-		goto done;
+	if (kgsl_mmu_enable_clk(&device->mmu,
+				KGSL_IOMMU_CONTEXT_USER))
+		return;
 
 	pt_val = kgsl_mmu_get_pt_base_addr(&device->mmu,
 				device->mmu.hwpagetable);
@@ -958,24 +979,14 @@
 	 * This returns the per context timestamp but we need to
 	 * use the global timestamp for iommu clock disablement
 	 */
-	result = adreno_ringbuffer_issuecmds(device, adreno_ctx,
-			KGSL_CMD_FLAGS_PMODE, &link[0], sizedwords);
+	adreno_ringbuffer_issuecmds(device, adreno_ctx, KGSL_CMD_FLAGS_PMODE,
+			&link[0], sizedwords);
 
-	/*
-	 * On error disable the IOMMU clock right away otherwise turn it off
-	 * after the command has been retired
-	 */
-	if (result)
-		kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false);
-	else
-		kgsl_mmu_disable_clk_on_ts(&device->mmu, rb->global_ts, true);
-
-done:
+	kgsl_mmu_disable_clk_on_ts(&device->mmu, rb->global_ts, true);
 	kgsl_context_put(context);
-	return result;
 }
 
-static int adreno_gpummu_setstate(struct kgsl_device *device,
+static void adreno_gpummu_setstate(struct kgsl_device *device,
 					unsigned int context_id,
 					uint32_t flags)
 {
@@ -986,7 +997,6 @@
 	unsigned int mh_mmu_invalidate = 0x00000003; /*invalidate all and tc */
 	struct kgsl_context *context;
 	struct adreno_context *adreno_ctx = NULL;
-	int ret = 0;
 
 	/*
 	 * Fix target freeze issue by adding TLB flush for each submit
@@ -1003,8 +1013,7 @@
 	if (!adreno_use_default_setstate(adreno_dev)) {
 		context = kgsl_context_get(device, context_id);
 		if (context == NULL)
-			return -EINVAL;
-
+			return;
 		adreno_ctx = ADRENO_CONTEXT(context);
 
 		if (flags & KGSL_MMUFLAGS_PTUPDATE) {
@@ -1079,7 +1088,7 @@
 			sizedwords += 2;
 		}
 
-		ret = adreno_ringbuffer_issuecmds(device, adreno_ctx,
+		adreno_ringbuffer_issuecmds(device, adreno_ctx,
 					KGSL_CMD_FLAGS_PMODE,
 					&link[0], sizedwords);
 
@@ -1087,11 +1096,9 @@
 	} else {
 		kgsl_mmu_device_setstate(&device->mmu, flags);
 	}
-
-	return ret;
 }
 
-static int adreno_setstate(struct kgsl_device *device,
+static void adreno_setstate(struct kgsl_device *device,
 			unsigned int context_id,
 			uint32_t flags)
 {
@@ -1100,8 +1107,6 @@
 		return adreno_gpummu_setstate(device, context_id, flags);
 	else if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
 		return adreno_iommu_setstate(device, context_id, flags);
-
-	return 0;
 }
 
 static unsigned int
@@ -1577,10 +1582,6 @@
 	if (status)
 		goto error_close_rb;
 
-	status = adreno_dispatcher_init(adreno_dev);
-	if (status)
-		goto error_close_device;
-
 	adreno_debugfs_init(device);
 	adreno_profile_init(device);
 
@@ -1596,8 +1597,6 @@
 
 	return 0;
 
-error_close_device:
-	kgsl_device_platform_remove(device);
 error_close_rb:
 	adreno_ringbuffer_close(&adreno_dev->ringbuffer);
 error:
@@ -1620,7 +1619,6 @@
 	kgsl_pwrscale_detach_policy(device);
 	kgsl_pwrscale_close(device);
 
-	adreno_dispatcher_close(adreno_dev);
 	adreno_ringbuffer_close(&adreno_dev->ringbuffer);
 	kgsl_device_platform_remove(device);
 
@@ -1632,7 +1630,8 @@
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	int i;
 
-	kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
+	if (KGSL_STATE_DUMP_AND_FT != device->state)
+		kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
 
 	/* Power up the device */
 	kgsl_pwrctrl_enable(device);
@@ -1690,6 +1689,10 @@
 	/* Power down the device */
 	kgsl_pwrctrl_disable(device);
 
+	/* Certain targets need the fixup.  You know who you are */
+	if (adreno_is_a330v2(adreno_dev))
+		adreno_a3xx_pwron_fixup_init(adreno_dev);
+
 	return 0;
 }
 
@@ -1702,18 +1705,19 @@
 
 	kgsl_cffdump_open(device);
 
-	kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
+	if (KGSL_STATE_DUMP_AND_FT != device->state)
+		kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
 
 	regulator_left_on = (regulator_is_enabled(device->pwrctrl.gpu_reg) ||
 				(device->pwrctrl.gpu_cx &&
 				regulator_is_enabled(device->pwrctrl.gpu_cx)));
 
-	/* Clear any GPU faults that might have been left over */
-	adreno_set_gpu_fault(adreno_dev, 0);
-
 	/* Power up the device */
 	kgsl_pwrctrl_enable(device);
 
+	/* Set the bit to indicate that we've just powered on */
+	set_bit(ADRENO_DEVICE_PWRON, &adreno_dev->priv);
+
 	/* Set up a2xx special case */
 	if (adreno_is_a2xx(adreno_dev)) {
 		/*
@@ -1756,10 +1760,10 @@
 	if (status)
 		goto error_irq_off;
 
-	adreno_perfcounter_start(adreno_dev);
+	mod_timer(&device->hang_timer,
+		(jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
 
-	/* Start the dispatcher */
-	adreno_dispatcher_start(adreno_dev);
+	adreno_perfcounter_start(adreno_dev);
 
 	device->reset_counter++;
 
@@ -1790,7 +1794,6 @@
 
 	adreno_dev->drawctxt_active = NULL;
 
-	adreno_dispatcher_stop(adreno_dev);
 	adreno_ringbuffer_stop(&adreno_dev->ringbuffer);
 
 	kgsl_mmu_stop(&device->mmu);
@@ -1798,6 +1801,7 @@
 	device->ftbl->irqctrl(device, 0);
 	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
 	del_timer_sync(&device->idle_timer);
+	del_timer_sync(&device->hang_timer);
 
 	adreno_ocmem_gmem_free(adreno_dev);
 
@@ -1809,48 +1813,918 @@
 	return 0;
 }
 
-/**
- * adreno_reset() - Helper function to reset the GPU
- * @device: Pointer to the KGSL device structure for the GPU
- *
- * Try to reset the GPU to recover from a fault.  First, try to do a low latency
- * soft reset.  If the soft reset fails for some reason, then bring out the big
- * guns and toggle the footswitch.
+/*
+ * Set the reset status of all contexts to
+ * INNOCENT_CONTEXT_RESET_EXT except for the bad context
+ * since thats the guilty party, if fault tolerance failed then
+ * mark all as guilty
  */
-int adreno_reset(struct kgsl_device *device)
+
+static int _mark_context_status(int id, void *ptr, void *data)
+{
+	unsigned int ft_status = *((unsigned int *) data);
+	struct kgsl_context *context = ptr;
+	struct adreno_context *adreno_context = ADRENO_CONTEXT(context);
+
+	if (ft_status) {
+		context->reset_status =
+				KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
+		adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
+	} else if (KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT !=
+		context->reset_status) {
+		if (adreno_context->flags & (CTXT_FLAGS_GPU_HANG |
+			CTXT_FLAGS_GPU_HANG_FT))
+			context->reset_status =
+			KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
+		else
+			context->reset_status =
+			KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT;
+	}
+
+	return 0;
+}
+
+static void adreno_mark_context_status(struct kgsl_device *device,
+					int ft_status)
+{
+	/* Mark the status for all the contexts in the device */
+
+	read_lock(&device->context_lock);
+	idr_for_each(&device->context_idr, _mark_context_status, &ft_status);
+	read_unlock(&device->context_lock);
+}
+
+/*
+ * For hung contexts set the current memstore value to the most recent issued
+ * timestamp - this resets the status and lets the system continue on
+ */
+
+static int _set_max_ts(int id, void *ptr, void *data)
+{
+	struct kgsl_device *device = data;
+	struct kgsl_context *context = ptr;
+	struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
+
+	if (drawctxt && drawctxt->flags & CTXT_FLAGS_GPU_HANG) {
+		kgsl_sharedmem_writel(device, &device->memstore,
+			KGSL_MEMSTORE_OFFSET(context->id,
+			soptimestamp), drawctxt->timestamp);
+		kgsl_sharedmem_writel(device, &device->memstore,
+			KGSL_MEMSTORE_OFFSET(context->id,
+			eoptimestamp), drawctxt->timestamp);
+	}
+
+	return 0;
+}
+
+static void adreno_set_max_ts_for_bad_ctxs(struct kgsl_device *device)
+{
+	read_lock(&device->context_lock);
+	idr_for_each(&device->context_idr, _set_max_ts, device);
+	read_unlock(&device->context_lock);
+}
+
+static void adreno_destroy_ft_data(struct adreno_ft_data *ft_data)
+{
+	vfree(ft_data->rb_buffer);
+	vfree(ft_data->bad_rb_buffer);
+	vfree(ft_data->good_rb_buffer);
+}
+
+static int _find_start_of_cmd_seq(struct adreno_ringbuffer *rb,
+					unsigned int *ptr,
+					bool inc)
+{
+	int status = -EINVAL;
+	unsigned int val1;
+	unsigned int size = rb->buffer_desc.size;
+	unsigned int start_ptr = *ptr;
+
+	while ((start_ptr / sizeof(unsigned int)) != rb->wptr) {
+		if (inc)
+			start_ptr = adreno_ringbuffer_inc_wrapped(start_ptr,
+									size);
+		else
+			start_ptr = adreno_ringbuffer_dec_wrapped(start_ptr,
+									size);
+		kgsl_sharedmem_readl(&rb->buffer_desc, &val1, start_ptr);
+		/* Ensure above read is finished before next read */
+		rmb();
+		if (KGSL_CMD_IDENTIFIER == val1) {
+			if ((start_ptr / sizeof(unsigned int)) != rb->wptr)
+				start_ptr = adreno_ringbuffer_dec_wrapped(
+							start_ptr, size);
+				*ptr = start_ptr;
+				status = 0;
+				break;
+		}
+	}
+	return status;
+}
+
+static int _find_cmd_seq_after_eop_ts(struct adreno_ringbuffer *rb,
+					unsigned int *rb_rptr,
+					unsigned int global_eop,
+					bool inc)
+{
+	int status = -EINVAL;
+	unsigned int temp_rb_rptr = *rb_rptr;
+	unsigned int size = rb->buffer_desc.size;
+	unsigned int val[3];
+	int i = 0;
+	bool check = false;
+
+	if (inc && temp_rb_rptr / sizeof(unsigned int) != rb->wptr)
+		return status;
+
+	do {
+		/*
+		 * when decrementing we need to decrement first and
+		 * then read make sure we cover all the data
+		 */
+		if (!inc)
+			temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
+					temp_rb_rptr, size);
+		kgsl_sharedmem_readl(&rb->buffer_desc, &val[i],
+					temp_rb_rptr);
+		/* Ensure above read is finished before next read */
+		rmb();
+
+		if (check && ((inc && val[i] == global_eop) ||
+			(!inc && (val[i] ==
+			cp_type3_packet(CP_MEM_WRITE, 2) ||
+			val[i] == CACHE_FLUSH_TS)))) {
+			/* decrement i, i.e i = (i - 1 + 3) % 3 if
+			 * we are going forward, else increment i */
+			i = (i + 2) % 3;
+			if (val[i] == rb->device->memstore.gpuaddr +
+				KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+						eoptimestamp)) {
+				int j = ((i + 2) % 3);
+				if ((inc && (val[j] == CACHE_FLUSH_TS ||
+						val[j] == cp_type3_packet(
+							CP_MEM_WRITE, 2))) ||
+					(!inc && val[j] == global_eop)) {
+						/* Found the global eop */
+						status = 0;
+						break;
+				}
+			}
+			/* if no match found then increment i again
+			 * since we decremented before matching */
+			i = (i + 1) % 3;
+		}
+		if (inc)
+			temp_rb_rptr = adreno_ringbuffer_inc_wrapped(
+						temp_rb_rptr, size);
+
+		i = (i + 1) % 3;
+		if (2 == i)
+			check = true;
+	} while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr);
+	/* temp_rb_rptr points to the command stream after global eop,
+	 * move backward till the start of command sequence */
+	if (!status) {
+		status = _find_start_of_cmd_seq(rb, &temp_rb_rptr, false);
+		if (!status) {
+			*rb_rptr = temp_rb_rptr;
+			KGSL_FT_INFO(rb->device,
+			"Offset of cmd sequence after eop timestamp: 0x%x\n",
+			temp_rb_rptr / sizeof(unsigned int));
+		}
+	}
+	if (status)
+		KGSL_FT_ERR(rb->device,
+		"Failed to find the command sequence after eop timestamp %x\n",
+		global_eop);
+	return status;
+}
+
+static int _find_hanging_ib_sequence(struct adreno_ringbuffer *rb,
+				unsigned int *rb_rptr,
+				unsigned int ib1)
+{
+	int status = -EINVAL;
+	unsigned int temp_rb_rptr = *rb_rptr;
+	unsigned int size = rb->buffer_desc.size;
+	unsigned int val[2];
+	int i = 0;
+	bool check = false;
+	bool ctx_switch = false;
+
+	while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr) {
+		kgsl_sharedmem_readl(&rb->buffer_desc, &val[i], temp_rb_rptr);
+		/* Ensure above read is finished before next read */
+		rmb();
+
+		if (check && val[i] == ib1) {
+			/* decrement i, i.e i = (i - 1 + 2) % 2 */
+			i = (i + 1) % 2;
+			if (adreno_cmd_is_ib(val[i])) {
+				/* go till start of command sequence */
+				status = _find_start_of_cmd_seq(rb,
+						&temp_rb_rptr, false);
+
+				KGSL_FT_INFO(rb->device,
+				"Found the hanging IB at offset 0x%x\n",
+				temp_rb_rptr / sizeof(unsigned int));
+				break;
+			}
+			/* if no match the increment i since we decremented
+			 * before checking */
+			i = (i + 1) % 2;
+		}
+		/* Make sure you do not encounter a context switch twice, we can
+		 * encounter it once for the bad context as the start of search
+		 * can point to the context switch */
+		if (val[i] == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
+			if (ctx_switch) {
+				KGSL_FT_ERR(rb->device,
+				"Context switch encountered before bad "
+				"IB found\n");
+				break;
+			}
+			ctx_switch = true;
+		}
+		i = (i + 1) % 2;
+		if (1 == i)
+			check = true;
+		temp_rb_rptr = adreno_ringbuffer_inc_wrapped(temp_rb_rptr,
+								size);
+	}
+	if  (!status)
+		*rb_rptr = temp_rb_rptr;
+	return status;
+}
+
+static void adreno_setup_ft_data(struct kgsl_device *device,
+					struct adreno_ft_data *ft_data)
 {
 	int ret = 0;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+	struct kgsl_context *context;
+	struct adreno_context *adreno_context;
+	unsigned int rb_rptr = rb->wptr * sizeof(unsigned int);
 
-	/* Try soft reset first */
-	if (adreno_soft_reset(device) != 0) {
+	memset(ft_data, 0, sizeof(*ft_data));
+	ft_data->start_of_replay_cmds = 0xFFFFFFFF;
+	ft_data->replay_for_snapshot = 0xFFFFFFFF;
+
+	adreno_readreg(adreno_dev, ADRENO_REG_CP_IB1_BASE, &ft_data->ib1);
+
+	kgsl_sharedmem_readl(&device->memstore, &ft_data->context_id,
+			KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+			current_context));
+
+	kgsl_sharedmem_readl(&device->memstore,
+			&ft_data->global_eop,
+			KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+			eoptimestamp));
+
+	/* Ensure context id and global eop ts read complete */
+	rmb();
+
+	ft_data->rb_buffer = vmalloc(rb->buffer_desc.size);
+	if (!ft_data->rb_buffer) {
+		KGSL_MEM_ERR(device, "vmalloc(%d) failed\n",
+				rb->buffer_desc.size);
+		return;
+	}
+
+	ft_data->bad_rb_buffer = vmalloc(rb->buffer_desc.size);
+	if (!ft_data->bad_rb_buffer) {
+		KGSL_MEM_ERR(device, "vmalloc(%d) failed\n",
+				rb->buffer_desc.size);
+		return;
+	}
+
+	ft_data->good_rb_buffer = vmalloc(rb->buffer_desc.size);
+	if (!ft_data->good_rb_buffer) {
+		KGSL_MEM_ERR(device, "vmalloc(%d) failed\n",
+				rb->buffer_desc.size);
+		return;
+	}
+	ft_data->status = 0;
+
+	/* find the start of bad command sequence in rb */
+	context = kgsl_context_get(device, ft_data->context_id);
+
+	ft_data->ft_policy = adreno_dev->ft_policy;
+
+	if (!ft_data->ft_policy)
+		ft_data->ft_policy = KGSL_FT_DEFAULT_POLICY;
+
+	/* Look for the command stream that is right after the global eop */
+	ret = _find_cmd_seq_after_eop_ts(rb, &rb_rptr,
+					ft_data->global_eop + 1, false);
+	if (ret) {
+		ft_data->ft_policy |= KGSL_FT_TEMP_DISABLE;
+		goto done;
+	} else {
+		ft_data->start_of_replay_cmds = rb_rptr;
+		ft_data->ft_policy &= ~KGSL_FT_TEMP_DISABLE;
+	}
+
+	if (context) {
+		adreno_context = ADRENO_CONTEXT(context);
+		if (adreno_context->flags & CTXT_FLAGS_PREAMBLE) {
+			if (ft_data->ib1) {
+				ret = _find_hanging_ib_sequence(rb,
+						&rb_rptr, ft_data->ib1);
+				if (ret) {
+					KGSL_FT_ERR(device,
+					"Start not found for replay IB seq\n");
+					goto done;
+				}
+				ft_data->start_of_replay_cmds = rb_rptr;
+				ft_data->replay_for_snapshot = rb_rptr;
+			}
+		}
+	}
+
+done:
+	kgsl_context_put(context);
+}
+
+static int
+_adreno_check_long_ib(struct kgsl_device *device)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	unsigned int curr_global_ts = 0;
+
+	/* check if the global ts is still the same */
+	kgsl_sharedmem_readl(&device->memstore,
+			&curr_global_ts,
+			KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+			eoptimestamp));
+	/* Ensure above read is finished before long ib check */
+	rmb();
+
+	/* Mark long ib as handled */
+	adreno_dev->long_ib = 0;
+
+	if (curr_global_ts == adreno_dev->long_ib_ts) {
+		KGSL_FT_ERR(device,
+			"IB ran too long, invalidate ctxt\n");
+		return 1;
+	} else {
+		/* Do nothing GPU has gone ahead */
+		KGSL_FT_INFO(device, "false long ib detection return\n");
+		return 0;
+	}
+}
+
+/**
+ * adreno_soft_reset() -  Do a soft reset of the GPU hardware
+ * @device: KGSL device to soft reset
+ *
+ * "soft reset" the GPU hardware - this is a fast path GPU reset
+ * The GPU hardware is reset but we never pull power so we can skip
+ * a lot of the standard adreno_stop/adreno_start sequence
+ */
+int adreno_soft_reset(struct kgsl_device *device)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	int ret;
+
+	/* If the jump table index is 0 soft reset is not supported */
+	if ((!adreno_dev->pm4_jt_idx) || (!adreno_dev->gpudev->soft_reset)) {
+		dev_WARN_ONCE(device->dev, 1, "Soft reset not supported");
+		return -EINVAL;
+	}
+
+	if (adreno_dev->drawctxt_active)
+		kgsl_context_put(&adreno_dev->drawctxt_active->base);
+
+	adreno_dev->drawctxt_active = NULL;
+
+	/* Stop the ringbuffer */
+	adreno_ringbuffer_stop(&adreno_dev->ringbuffer);
+
+	/* Delete the idle timer */
+	del_timer_sync(&device->idle_timer);
+
+	/* Make sure we are totally awake */
+	kgsl_pwrctrl_enable(device);
+
+	/* Reset the GPU */
+	adreno_dev->gpudev->soft_reset(adreno_dev);
+
+	/* Reinitialize the GPU */
+	adreno_dev->gpudev->start(adreno_dev);
+
+	/* Enable IRQ */
+	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
+	device->ftbl->irqctrl(device, 1);
+
+	/*
+	 * Restart the ringbuffer - we can go down the warm start path because
+	 * power was never yanked
+	 */
+	ret = adreno_ringbuffer_warm_start(&adreno_dev->ringbuffer);
+	if (ret)
+		return ret;
+
+	device->reset_counter++;
+
+	return 0;
+}
+
+static int
+_adreno_ft_restart_device(struct kgsl_device *device,
+			   struct kgsl_context *context)
+{
+	/* If device soft reset fails try hard reset */
+	if (adreno_soft_reset(device))
 		KGSL_DEV_ERR_ONCE(device, "Device soft reset failed\n");
+	else
+		/* Soft reset is successful */
+		goto reset_done;
 
-		/* If it failed, then pull the power */
-		ret = adreno_stop(device);
-		if (ret)
-			return ret;
+	/* restart device */
+	if (adreno_stop(device)) {
+		KGSL_FT_ERR(device, "Device stop failed\n");
+		return 1;
+	}
 
-		ret = adreno_start(device);
+	if (adreno_init(device)) {
+		KGSL_FT_ERR(device, "Device init failed\n");
+		return 1;
+	}
 
-		if (ret)
-			return ret;
+	if (adreno_start(device)) {
+		KGSL_FT_ERR(device, "Device start failed\n");
+		return 1;
+	}
+
+reset_done:
+	if (context)
+		kgsl_mmu_setstate(&device->mmu, 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()) {
+		if (kgsl_mmu_enable_clk(&device->mmu,
+				KGSL_IOMMU_CONTEXT_USER))
+			return 1;
+	}
+
+	return 0;
+}
+
+static inline void
+_adreno_debug_ft_info(struct kgsl_device *device,
+			struct adreno_ft_data *ft_data)
+{
+
+	/*
+	 * Dumping rb is a very useful tool to debug FT.
+	 * It will tell us if we are extracting the rb correctly
+	 * NOP'ing the right IB, skipping the EOF correctly etc.
+	 */
+	if (device->ft_log >= 7)  {
+
+		/* Print fault tolerance data here */
+		KGSL_FT_INFO(device, "Temp RB buffer size 0x%X\n",
+			ft_data->rb_size);
+		adreno_dump_rb(device, ft_data->rb_buffer,
+			ft_data->rb_size<<2, 0, ft_data->rb_size);
+
+		KGSL_FT_INFO(device, "Bad RB buffer size 0x%X\n",
+			ft_data->bad_rb_size);
+		adreno_dump_rb(device, ft_data->bad_rb_buffer,
+			ft_data->bad_rb_size<<2, 0, ft_data->bad_rb_size);
+
+		KGSL_FT_INFO(device, "Good RB buffer size 0x%X\n",
+			ft_data->good_rb_size);
+		adreno_dump_rb(device, ft_data->good_rb_buffer,
+			ft_data->good_rb_size<<2, 0, ft_data->good_rb_size);
+
+	}
+}
+
+static int
+_adreno_ft_resubmit_rb(struct kgsl_device *device,
+			struct adreno_ringbuffer *rb,
+			struct kgsl_context *context,
+			struct adreno_ft_data *ft_data,
+			unsigned int *buff, unsigned int size)
+{
+	unsigned int ret = 0;
+	unsigned int retry_num = 0;
+
+	_adreno_debug_ft_info(device, ft_data);
+
+	do {
+		ret = _adreno_ft_restart_device(device, context);
+		if (ret == 0)
+			break;
+		/*
+		 * If device restart fails sleep for 20ms before
+		 * attempting restart. This allows GPU HW to settle
+		 * and improve the chances of next restart to be
+		 * successful.
+		 */
+		msleep(20);
+		KGSL_FT_ERR(device, "Retry device restart %d\n", retry_num);
+		retry_num++;
+	} while (retry_num < 4);
+
+	if (ret) {
+		KGSL_FT_ERR(device, "Device restart failed\n");
+		BUG_ON(1);
+		goto done;
+	}
+
+	if (size) {
+
+		/* submit commands and wait for them to pass */
+		adreno_ringbuffer_restore(rb, buff, size);
+
+		ret = adreno_idle(device);
+	}
+
+done:
+	return ret;
+}
+
+
+static int
+_adreno_ft(struct kgsl_device *device,
+			struct adreno_ft_data *ft_data)
+{
+	int ret = 0, i;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+	struct kgsl_context *context;
+	struct adreno_context *adreno_context = NULL;
+	struct adreno_context *last_active_ctx = adreno_dev->drawctxt_active;
+	unsigned int long_ib = 0;
+	static int no_context_ft;
+	struct kgsl_mmu *mmu = &device->mmu;
+
+	context = kgsl_context_get(device, ft_data->context_id);
+
+	if (context == NULL) {
+		KGSL_FT_ERR(device, "Last context unknown id:%d\n",
+			ft_data->context_id);
+		if (no_context_ft) {
+			/*
+			 * If 2 consecutive no context ft occurred then
+			 * just reset GPU
+			 */
+			no_context_ft = 0;
+			goto play_good_cmds;
+		}
+	} else {
+		no_context_ft = 0;
+		adreno_context = ADRENO_CONTEXT(context);
+		adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
+		/*
+		 * set the invalid ts flag to 0 for this context since we have
+		 * detected a hang for it
+		 */
+		context->wait_on_invalid_ts = false;
+
+		if (!(adreno_context->flags & CTXT_FLAGS_PER_CONTEXT_TS)) {
+			ft_data->status = 1;
+			KGSL_FT_ERR(device, "Fault tolerance not supported\n");
+			goto play_good_cmds;
+		}
+
+		/*
+		 *  This flag will be set by userspace for contexts
+		 *  that do not want to be fault tolerant (ex: OPENCL)
+		 */
+		if (adreno_context->flags & CTXT_FLAGS_NO_FAULT_TOLERANCE) {
+			ft_data->status = 1;
+			KGSL_FT_ERR(device,
+			"No FT set for this context play good cmds\n");
+			goto play_good_cmds;
+		}
+
+	}
+
+	/* Check if we detected a long running IB, if false return */
+	if ((adreno_context) && (adreno_dev->long_ib)) {
+		long_ib = _adreno_check_long_ib(device);
+		if (!long_ib) {
+			adreno_context->flags &= ~CTXT_FLAGS_GPU_HANG;
+			return 0;
+		}
 	}
 
 	/*
-	 * If active_cnt is non-zero then the system was active before
-	 * going into a reset - put it back in that state
+	 * Extract valid contents from rb which can still be executed after
+	 * hang
 	 */
+	adreno_ringbuffer_extract(rb, ft_data);
 
-	if (atomic_read(&device->active_cnt))
-		kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
+	/* If long IB detected do not attempt replay of bad cmds */
+	if (long_ib) {
+		ft_data->status = 1;
+		_adreno_debug_ft_info(device, ft_data);
+		goto play_good_cmds;
+	}
 
-	/* Set the page table back to the default page table */
-	kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable,
-			KGSL_MEMSTORE_GLOBAL);
+	if ((ft_data->ft_policy & KGSL_FT_DISABLE) ||
+		(ft_data->ft_policy & KGSL_FT_TEMP_DISABLE)) {
+		KGSL_FT_ERR(device, "NO FT policy play only good cmds\n");
+		ft_data->status = 1;
+		goto play_good_cmds;
+	}
 
+	/* Do not try to replay if hang is due to a pagefault */
+	if (context && test_bit(KGSL_CONTEXT_PAGEFAULT, &context->priv)) {
+		/* Resume MMU */
+		mmu->mmu_ops->mmu_pagefault_resume(mmu);
+		if ((ft_data->context_id == context->id) &&
+			(ft_data->global_eop == context->pagefault_ts)) {
+			ft_data->ft_policy &= ~KGSL_FT_REPLAY;
+			KGSL_FT_ERR(device, "MMU fault skipping replay\n");
+		}
+		clear_bit(KGSL_CONTEXT_PAGEFAULT, &context->priv);
+	}
+
+	if (ft_data->ft_policy & KGSL_FT_REPLAY) {
+		ret = _adreno_ft_resubmit_rb(device, rb, context, ft_data,
+				ft_data->bad_rb_buffer, ft_data->bad_rb_size);
+
+		if (ret) {
+			KGSL_FT_ERR(device, "Replay status: 1\n");
+			ft_data->status = 1;
+		} else
+			goto play_good_cmds;
+	}
+
+	if (ft_data->ft_policy & KGSL_FT_SKIPIB) {
+		for (i = 0; i < ft_data->bad_rb_size; i++) {
+			if ((ft_data->bad_rb_buffer[i] ==
+					CP_HDR_INDIRECT_BUFFER_PFD) &&
+				(ft_data->bad_rb_buffer[i+1] == ft_data->ib1)) {
+
+				ft_data->bad_rb_buffer[i] = cp_nop_packet(2);
+				ft_data->bad_rb_buffer[i+1] =
+							KGSL_NOP_IB_IDENTIFIER;
+				ft_data->bad_rb_buffer[i+2] =
+							KGSL_NOP_IB_IDENTIFIER;
+				break;
+			}
+		}
+
+		if ((i == (ft_data->bad_rb_size)) || (!ft_data->ib1)) {
+			KGSL_FT_ERR(device, "Bad IB to NOP not found\n");
+			ft_data->status = 1;
+			goto play_good_cmds;
+		}
+
+		ret = _adreno_ft_resubmit_rb(device, rb, context, ft_data,
+				ft_data->bad_rb_buffer, ft_data->bad_rb_size);
+
+		if (ret) {
+			KGSL_FT_ERR(device, "NOP faulty IB status: 1\n");
+			ft_data->status = 1;
+		} else {
+			ft_data->status = 0;
+			goto play_good_cmds;
+		}
+	}
+
+	if (ft_data->ft_policy & KGSL_FT_SKIPFRAME) {
+		for (i = 0; i < ft_data->bad_rb_size; i++) {
+			if (ft_data->bad_rb_buffer[i] ==
+					KGSL_END_OF_FRAME_IDENTIFIER) {
+				ft_data->bad_rb_buffer[0] = cp_nop_packet(i);
+				break;
+			}
+		}
+
+		/* EOF not found in RB, discard till EOF in
+		   next IB submission */
+		if (adreno_context && (i == ft_data->bad_rb_size)) {
+			adreno_context->flags |= CTXT_FLAGS_SKIP_EOF;
+			KGSL_FT_INFO(device,
+			"EOF not found in RB, skip next issueib till EOF\n");
+			ft_data->bad_rb_buffer[0] = cp_nop_packet(i);
+		}
+
+		ret = _adreno_ft_resubmit_rb(device, rb, context, ft_data,
+				ft_data->bad_rb_buffer, ft_data->bad_rb_size);
+
+		if (ret) {
+			KGSL_FT_ERR(device, "Skip EOF status: 1\n");
+			ft_data->status = 1;
+		} else {
+			ft_data->status = 0;
+			goto play_good_cmds;
+		}
+	}
+
+play_good_cmds:
+
+	if (ft_data->status)
+		KGSL_FT_ERR(device, "Bad context commands failed\n");
+	else {
+		KGSL_FT_INFO(device, "Bad context commands success\n");
+
+		if (adreno_context) {
+			adreno_context->flags = (adreno_context->flags &
+				~CTXT_FLAGS_GPU_HANG) | CTXT_FLAGS_GPU_HANG_FT;
+		}
+
+		if (last_active_ctx)
+			_kgsl_context_get(&last_active_ctx->base);
+
+		adreno_dev->drawctxt_active = last_active_ctx;
+	}
+
+	ret = _adreno_ft_resubmit_rb(device, rb, context, ft_data,
+			ft_data->good_rb_buffer, ft_data->good_rb_size);
+
+	if (ret) {
+		/*
+		 * If we fail here we can try to invalidate another
+		 * context and try fault tolerance again, although
+		 * we will only try ft with no context once to avoid
+		 * going into continuous loop of trying ft with no context
+		 */
+		if (!context)
+			no_context_ft = 1;
+		ret = -EAGAIN;
+		KGSL_FT_ERR(device, "Playing good commands unsuccessful\n");
+		goto done;
+	} else
+		KGSL_FT_INFO(device, "Playing good commands successful\n");
+
+	/* ringbuffer now has data from the last valid context id,
+	 * so restore the active_ctx to the last valid context */
+	if (ft_data->last_valid_ctx_id) {
+		struct kgsl_context *last_ctx = kgsl_context_get(device,
+			ft_data->last_valid_ctx_id);
+
+		adreno_dev->drawctxt_active = ADRENO_CONTEXT(last_ctx);
+	}
+
+done:
+	/* Turn off iommu clocks */
+	if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
+		kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false);
+
+	kgsl_context_put(context);
 	return ret;
 }
 
+static int
+adreno_ft(struct kgsl_device *device,
+			struct adreno_ft_data *ft_data)
+{
+	int ret = 0;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+
+	/*
+	 * If GPU FT is turned off do not run FT.
+	 * If GPU stall detection is suspected to be false,
+	 * we can use this option to confirm stall detection.
+	 */
+	if (ft_data->ft_policy & KGSL_FT_OFF) {
+		KGSL_FT_ERR(device, "GPU FT turned off\n");
+		return 0;
+	}
+
+	KGSL_FT_INFO(device,
+	"Start Parameters: IB1: 0x%X, "
+	"Bad context_id: %u, global_eop: 0x%x\n",
+	ft_data->ib1, ft_data->context_id, ft_data->global_eop);
+
+	KGSL_FT_INFO(device, "Last issued global timestamp: %x\n",
+			rb->global_ts);
+
+	/* We may need to replay commands multiple times based on whether
+	 * multiple contexts hang the GPU */
+	while (true) {
+
+		ret = _adreno_ft(device, ft_data);
+
+		if (-EAGAIN == ret) {
+			/* setup new fault tolerance parameters and retry, this
+			 * means more than 1 contexts are causing hang */
+			adreno_destroy_ft_data(ft_data);
+			adreno_setup_ft_data(device, ft_data);
+			KGSL_FT_INFO(device,
+			"Retry. Parameters: "
+			"IB1: 0x%X, Bad context_id: %u, global_eop: 0x%x\n",
+			ft_data->ib1, ft_data->context_id,
+			ft_data->global_eop);
+		} else {
+			break;
+		}
+	}
+
+	if (ret)
+		goto done;
+
+	/* Restore correct states after fault tolerance */
+	if (adreno_dev->drawctxt_active)
+		device->mmu.hwpagetable =
+			adreno_dev->drawctxt_active->base.pagetable;
+	else
+		device->mmu.hwpagetable = device->mmu.defaultpagetable;
+	kgsl_sharedmem_writel(device, &device->memstore,
+			KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+			eoptimestamp), rb->global_ts);
+
+	/* switch to NULL ctxt */
+	if (adreno_dev->drawctxt_active != NULL)
+		adreno_drawctxt_switch(adreno_dev, NULL, 0);
+
+done:
+	adreno_set_max_ts_for_bad_ctxs(device);
+	adreno_mark_context_status(device, ret);
+	KGSL_FT_ERR(device, "policy 0x%X status 0x%x\n",
+			ft_data->ft_policy, ret);
+	return ret;
+}
+
+int
+adreno_dump_and_exec_ft(struct kgsl_device *device)
+{
+	int result = -ETIMEDOUT;
+	struct adreno_ft_data ft_data;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+	unsigned int curr_pwrlevel;
+
+	if (device->state == KGSL_STATE_HUNG)
+		goto done;
+	if (device->state == KGSL_STATE_DUMP_AND_FT) {
+		mutex_unlock(&device->mutex);
+		wait_for_completion(&device->ft_gate);
+		mutex_lock(&device->mutex);
+		if (device->state != KGSL_STATE_HUNG)
+			result = 0;
+	} else {
+		/*
+		 * While fault tolerance is happening we do not want the
+		 * idle_timer to fire and attempt to change any device state
+		 */
+		del_timer_sync(&device->idle_timer);
+
+		kgsl_pwrctrl_set_state(device, KGSL_STATE_DUMP_AND_FT);
+		INIT_COMPLETION(device->ft_gate);
+		/* Detected a hang */
+
+		kgsl_cffdump_hang(device);
+		/* Run fault tolerance at max power level */
+		curr_pwrlevel = pwr->active_pwrlevel;
+		kgsl_pwrctrl_pwrlevel_change(device, pwr->max_pwrlevel);
+
+		/* Get the fault tolerance data as soon as hang is detected */
+		adreno_setup_ft_data(device, &ft_data);
+
+		/*
+		 * If long ib is detected, do not attempt postmortem or
+		 * snapshot, if GPU is still executing commands
+		 * we will get errors
+		 */
+		if (!adreno_dev->long_ib) {
+			/*
+			 * Trigger an automatic dump of the state to
+			 * the console
+			 */
+			kgsl_postmortem_dump(device, 0);
+
+			/*
+			* Make a GPU snapshot.  For now, do it after the
+			* PM dump so we can at least be sure the PM dump
+			* will work as it always has
+			*/
+			kgsl_device_snapshot(device, 1);
+		}
+
+		result = adreno_ft(device, &ft_data);
+		adreno_destroy_ft_data(&ft_data);
+
+		/* restore power level */
+		kgsl_pwrctrl_pwrlevel_change(device, curr_pwrlevel);
+
+		if (result) {
+			kgsl_pwrctrl_set_state(device, KGSL_STATE_HUNG);
+		} else {
+			kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
+			mod_timer(&device->hang_timer,
+				(jiffies +
+				msecs_to_jiffies(KGSL_TIMEOUT_PART)));
+		}
+		complete_all(&device->ft_gate);
+	}
+done:
+	return result;
+}
+EXPORT_SYMBOL(adreno_dump_and_exec_ft);
+
 /**
  * _ft_sysfs_store() -  Common routine to write to FT sysfs files
  * @buf: value to write
@@ -2248,185 +3122,140 @@
 	return status;
 }
 
-/**
- * adreno_hw_isidle() - Check if the GPU core is idle
- * @device: Pointer to the KGSL device structure for the GPU
- *
- * Return true if the RBBM status register for the GPU type indicates that the
- * hardware is idle
- */
-static bool adreno_hw_isidle(struct kgsl_device *device)
-{
-	unsigned int reg_rbbm_status;
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-
-	/* Don't consider ourselves idle if there is an IRQ pending */
-	if (adreno_dev->gpudev->irq_pending(adreno_dev))
-		return false;
-
-	adreno_readreg(adreno_dev, ADRENO_REG_RBBM_STATUS,
-		&reg_rbbm_status);
-
-	if (adreno_is_a2xx(adreno_dev)) {
-		if (reg_rbbm_status == 0x110)
-			return true;
-	} else if (adreno_is_a3xx(adreno_dev)) {
-		if (!(reg_rbbm_status & 0x80000000))
-			return true;
-	}
-
-	return false;
-}
-
-/**
- * adreno_soft_reset() -  Do a soft reset of the GPU hardware
- * @device: KGSL device to soft reset
- *
- * "soft reset" the GPU hardware - this is a fast path GPU reset
- * The GPU hardware is reset but we never pull power so we can skip
- * a lot of the standard adreno_stop/adreno_start sequence
- */
-int adreno_soft_reset(struct kgsl_device *device)
+static int adreno_ringbuffer_drain(struct kgsl_device *device,
+	unsigned int *regs)
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	int ret;
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+	unsigned long wait = jiffies;
+	unsigned long timeout = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
+	unsigned int rptr;
 
-	if (!adreno_dev->gpudev->soft_reset) {
-		dev_WARN_ONCE(device->dev, 1, "Soft reset not supported");
-		return -EINVAL;
-	}
+	do {
+		/*
+		 * Wait is "jiffies" first time in the loop to start
+		 * GPU stall detection immediately.
+		 */
+		if (time_after(jiffies, wait)) {
+			/* Check to see if the core is hung */
+			if (adreno_ft_detect(device, regs))
+				return -ETIMEDOUT;
 
-	if (adreno_dev->drawctxt_active)
-		kgsl_context_put(&adreno_dev->drawctxt_active->base);
-
-	adreno_dev->drawctxt_active = NULL;
-
-	/* Stop the ringbuffer */
-	adreno_ringbuffer_stop(&adreno_dev->ringbuffer);
-
-	if (kgsl_pwrctrl_isenabled(device))
-		device->ftbl->irqctrl(device, 0);
-
-	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
-
-	adreno_set_gpu_fault(adreno_dev, 0);
-
-	/* Delete the idle timer */
-	del_timer_sync(&device->idle_timer);
-
-	/* Make sure we are totally awake */
-	kgsl_pwrctrl_enable(device);
-
-	/* Reset the GPU */
-	adreno_dev->gpudev->soft_reset(adreno_dev);
-
-	/* Reinitialize the GPU */
-	adreno_dev->gpudev->start(adreno_dev);
-
-	/* Enable IRQ */
-	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
-	device->ftbl->irqctrl(device, 1);
-
-	/*
-	 * If we have offsets for the jump tables we can try to do a warm start,
-	 * otherwise do a full ringbuffer restart
-	 */
-
-	if (adreno_dev->pm4_jt_idx)
-		ret = adreno_ringbuffer_warm_start(&adreno_dev->ringbuffer);
-	else
-		ret = adreno_ringbuffer_start(&adreno_dev->ringbuffer);
-
-	if (ret)
-		return ret;
-
-	device->reset_counter++;
+			wait = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
+		}
+		rptr = adreno_get_rptr(rb);
+		if (time_after(jiffies, timeout)) {
+			KGSL_DRV_ERR(device, "rptr: %x, wptr: %x\n",
+				rptr, rb->wptr);
+			return -ETIMEDOUT;
+		}
+	} while (rptr != rb->wptr);
 
 	return 0;
 }
 
-/*
- * adreno_isidle() - return true if the GPU hardware is idle
- * @device: Pointer to the KGSL device structure for the GPU
- *
- * Return true if the GPU hardware is idle and there are no commands pending in
- * the ringbuffer
- */
-bool adreno_isidle(struct kgsl_device *device)
-{
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	unsigned int rptr;
-
-	if (!kgsl_pwrctrl_isenabled(device))
-		return true;
-
-	rptr = adreno_get_rptr(&adreno_dev->ringbuffer);
-
-	if (rptr == adreno_dev->ringbuffer.wptr)
-		return adreno_hw_isidle(device);
-
-	return false;
-}
-
-/**
- * adreno_idle() - wait for the GPU hardware to go idle
- * @device: Pointer to the KGSL device structure for the GPU
- *
- * Wait up to ADRENO_IDLE_TIMEOUT milliseconds for the GPU hardware to go quiet.
- */
-
+/* Caller must hold the device mutex. */
 int adreno_idle(struct kgsl_device *device)
 {
+	unsigned long wait_time;
+	unsigned long wait_time_part;
+	unsigned int prev_reg_val[FT_DETECT_REGS_COUNT];
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	unsigned long wait = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
 
-	/*
-	 * Make sure the device mutex is held so the dispatcher can't send any
-	 * more commands to the hardware
-	 */
+	memset(prev_reg_val, 0, sizeof(prev_reg_val));
 
-	BUG_ON(!mutex_is_locked(&device->mutex));
+	kgsl_cffdump_regpoll(device,
+		adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS) << 2,
+		0x00000000, 0x80000000);
 
-	if (adreno_is_a3xx(adreno_dev))
-		kgsl_cffdump_regpoll(device,
-			adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS) << 2,
-			0x00000000, 0x80000000);
-	else
-		kgsl_cffdump_regpoll(device,
-			adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS) << 2,
-			0x110, 0x110);
+retry:
+	/* First, wait for the ringbuffer to drain */
+	if (adreno_ringbuffer_drain(device, prev_reg_val))
+		goto err;
 
-	while (time_before(jiffies, wait)) {
-		/*
-		 * If we fault, stop waiting and return an error. The dispatcher
-		 * will clean up the fault from the work queue, but we need to
-		 * make sure we don't block it by waiting for an idle that
-		 * will never come.
-		 */
+	/* now, wait for the GPU to finish its operations */
+	wait_time = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
+	wait_time_part = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
 
-		if (adreno_gpu_fault(adreno_dev) != 0)
-			return -EDEADLK;
-
+	while (time_before(jiffies, wait_time)) {
 		if (adreno_isidle(device))
 			return 0;
+
+		/* Dont wait for timeout, detect hang faster.  */
+		if (time_after(jiffies, wait_time_part)) {
+			wait_time_part = jiffies +
+				msecs_to_jiffies(KGSL_TIMEOUT_PART);
+			if ((adreno_ft_detect(device, prev_reg_val)))
+				goto err;
+		}
+
 	}
 
+err:
+	KGSL_DRV_ERR(device, "spun too long waiting for RB to idle\n");
+	if (KGSL_STATE_DUMP_AND_FT != device->state &&
+		!adreno_dump_and_exec_ft(device)) {
+		wait_time = jiffies + ADRENO_IDLE_TIMEOUT;
+		goto retry;
+	}
 	return -ETIMEDOUT;
 }
 
 /**
- * adreno_drain() - Drain the dispatch queue
- * @device: Pointer to the KGSL device structure for the GPU
- *
- * Tell the dispatcher to pause - this has the effect of draining the inflight
- * command batches
+ * is_adreno_rbbm_status_idle - Check if GPU core is idle by probing
+ * rbbm_status register
+ * @device - Pointer to the GPU device whose idle status is to be
+ * checked
+ * @returns - Returns whether the core is idle (based on rbbm_status)
+ * false if the core is active, true if the core is idle
  */
-static int adreno_drain(struct kgsl_device *device)
+static bool is_adreno_rbbm_status_idle(struct kgsl_device *device)
 {
+	unsigned int reg_rbbm_status;
+	bool status = false;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 
-	adreno_dispatcher_pause(adreno_dev);
-	return 0;
+	/* Is the core idle? */
+	adreno_readreg(adreno_dev, ADRENO_REG_RBBM_STATUS,
+				&reg_rbbm_status);
+
+	if (adreno_is_a2xx(adreno_dev)) {
+		if (reg_rbbm_status == 0x110)
+			status = true;
+	} else {
+		if (!(reg_rbbm_status & 0x80000000))
+			status = true;
+	}
+	return status;
+}
+
+static unsigned int adreno_isidle(struct kgsl_device *device)
+{
+	int status = false;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+
+	/* If the device isn't active, don't force it on. */
+	if (kgsl_pwrctrl_isenabled(device)) {
+		/* Is the ring buffer is empty? */
+		unsigned int rptr = adreno_get_rptr(rb);
+		if (rptr == rb->wptr) {
+			/*
+			 * Are there interrupts pending? If so then pretend we
+			 * are not idle - this avoids the possiblity that we go
+			 * to a lower power state without handling interrupts
+			 * first.
+			 */
+
+			if (!adreno_dev->gpudev->irq_pending(adreno_dev)) {
+				/* Is the core idle? */
+				status = is_adreno_rbbm_status_idle(device);
+			}
+		}
+	} else {
+		status = true;
+	}
+	return status;
 }
 
 /* Caller must hold the device mutex. */
@@ -2500,6 +3329,9 @@
 	if (kgsl_gpuaddr_in_memdesc(&device->memstore, gpuaddr, size))
 		return &device->memstore;
 
+	if (kgsl_gpuaddr_in_memdesc(&adreno_dev->pwron_fixup, gpuaddr, size))
+		return &adreno_dev->pwron_fixup;
+
 	if (kgsl_gpuaddr_in_memdesc(&device->mmu.setstate_memory, gpuaddr,
 					size))
 		return &device->mmu.setstate_memory;
@@ -2597,6 +3429,324 @@
 	__raw_writel(value, reg);
 }
 
+static unsigned int _get_context_id(struct kgsl_context *k_ctxt)
+{
+	unsigned int context_id = KGSL_MEMSTORE_GLOBAL;
+
+	if (k_ctxt != NULL) {
+		struct adreno_context *a_ctxt = ADRENO_CONTEXT(k_ctxt);
+		if (kgsl_context_detached(k_ctxt))
+			context_id = KGSL_CONTEXT_INVALID;
+		else if (a_ctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
+			context_id = k_ctxt->id;
+	}
+
+	return context_id;
+}
+
+static unsigned int adreno_check_hw_ts(struct kgsl_device *device,
+		struct kgsl_context *context, unsigned int timestamp)
+{
+	int status = 0;
+	unsigned int ref_ts, enableflag;
+	unsigned int context_id = _get_context_id(context);
+
+	/*
+	 * If the context ID is invalid, we are in a race with
+	 * the context being destroyed by userspace so bail.
+	 */
+	if (context_id == KGSL_CONTEXT_INVALID) {
+		KGSL_DRV_WARN(device, "context was detached");
+		return -EINVAL;
+	}
+
+	status = kgsl_check_timestamp(device, context, timestamp);
+	if (status)
+		return status;
+
+	kgsl_sharedmem_readl(&device->memstore, &enableflag,
+			KGSL_MEMSTORE_OFFSET(context_id, ts_cmp_enable));
+	/*
+	 * Barrier is needed here to make sure the read from memstore
+	 * has posted
+	 */
+
+	mb();
+
+	if (enableflag) {
+		kgsl_sharedmem_readl(&device->memstore, &ref_ts,
+				KGSL_MEMSTORE_OFFSET(context_id,
+					ref_wait_ts));
+
+		/* Make sure the memstore read has posted */
+		mb();
+		if (timestamp_cmp(ref_ts, timestamp) >= 0) {
+			kgsl_sharedmem_writel(device, &device->memstore,
+					KGSL_MEMSTORE_OFFSET(context_id,
+						ref_wait_ts), timestamp);
+			/* Make sure the memstore write is posted */
+			wmb();
+		}
+	} else {
+		kgsl_sharedmem_writel(device, &device->memstore,
+				KGSL_MEMSTORE_OFFSET(context_id,
+					ref_wait_ts), timestamp);
+		enableflag = 1;
+		kgsl_sharedmem_writel(device, &device->memstore,
+				KGSL_MEMSTORE_OFFSET(context_id,
+					ts_cmp_enable), enableflag);
+
+		/* Make sure the memstore write gets posted */
+		wmb();
+
+		/*
+		 * submit a dummy packet so that even if all
+		 * commands upto timestamp get executed we will still
+		 * get an interrupt
+		 */
+
+		if (context && device->state != KGSL_STATE_SLUMBER) {
+			adreno_ringbuffer_issuecmds(device,
+					ADRENO_CONTEXT(context),
+					KGSL_CMD_FLAGS_GET_INT, NULL, 0);
+		}
+	}
+
+	return 0;
+}
+
+/* Return 1 if the event timestmp has already passed, 0 if it was marked */
+static int adreno_next_event(struct kgsl_device *device,
+		struct kgsl_event *event)
+{
+	return adreno_check_hw_ts(device, event->context, event->timestamp);
+}
+
+static int adreno_check_interrupt_timestamp(struct kgsl_device *device,
+		struct kgsl_context *context, unsigned int timestamp)
+{
+	int status;
+
+	mutex_lock(&device->mutex);
+	status = adreno_check_hw_ts(device, context, timestamp);
+	mutex_unlock(&device->mutex);
+
+	return status;
+}
+
+/*
+ wait_event_interruptible_timeout checks for the exit condition before
+ placing a process in wait q. For conditional interrupts we expect the
+ process to already be in its wait q when its exit condition checking
+ function is called.
+*/
+#define kgsl_wait_event_interruptible_timeout(wq, condition, timeout, io)\
+({									\
+	long __ret = timeout;						\
+	if (io)						\
+		__wait_io_event_interruptible_timeout(wq, condition, __ret);\
+	else						\
+		__wait_event_interruptible_timeout(wq, condition, __ret);\
+	__ret;								\
+})
+
+
+
+unsigned int adreno_ft_detect(struct kgsl_device *device,
+						unsigned int *prev_reg_val)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+	unsigned int curr_reg_val[FT_DETECT_REGS_COUNT];
+	unsigned int fast_hang_detected = 1;
+	unsigned int i;
+	static unsigned long next_hang_detect_time;
+	static unsigned int prev_global_ts;
+	unsigned int curr_global_ts = 0;
+	unsigned int curr_context_id = 0;
+	static struct adreno_context *curr_context;
+	static struct kgsl_context *context;
+	static char pid_name[TASK_COMM_LEN] = "unknown";
+
+	if (!adreno_dev->fast_hang_detect)
+		fast_hang_detected = 0;
+
+	if (!(adreno_dev->ringbuffer.flags & KGSL_FLAGS_STARTED))
+		return 0;
+
+	if (is_adreno_rbbm_status_idle(device) &&
+		(kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED)
+		 == rb->global_ts)) {
+
+		/*
+		 * On A2XX if the RPTR != WPTR and the device is idle, then
+		 * the last write to WPTR probably failed to latch so write it
+		 * again
+		 */
+
+		if (adreno_is_a2xx(adreno_dev)) {
+			unsigned int rptr;
+			adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR,
+						&rptr);
+			if (rptr != adreno_dev->ringbuffer.wptr)
+				adreno_writereg(adreno_dev,
+					ADRENO_REG_CP_RB_WPTR,
+					adreno_dev->ringbuffer.wptr);
+		}
+
+		return 0;
+	}
+
+	/*
+	 * Time interval between hang detection should be KGSL_TIMEOUT_PART
+	 * or more, if next hang detection is requested < KGSL_TIMEOUT_PART
+	 * from the last time do nothing.
+	 */
+	if ((next_hang_detect_time) &&
+		(time_before(jiffies, next_hang_detect_time)))
+			return 0;
+	else
+		next_hang_detect_time = (jiffies +
+			msecs_to_jiffies(KGSL_TIMEOUT_PART-1));
+
+	/* Read the current Hang detect reg values here */
+	for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
+		if (ft_detect_regs[i] == 0)
+			continue;
+		kgsl_regread(device, ft_detect_regs[i],
+			&curr_reg_val[i]);
+	}
+
+	/* Read the current global timestamp here */
+	kgsl_sharedmem_readl(&device->memstore,
+			&curr_global_ts,
+			KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+			eoptimestamp));
+	/* Make sure the memstore read has posted */
+	mb();
+
+	if (curr_global_ts == prev_global_ts) {
+
+		/* If we don't already have a good context, get it. */
+		if (kgsl_context_detached(context)) {
+			kgsl_context_put(context);
+			context = NULL;
+			curr_context = NULL;
+			strlcpy(pid_name, "unknown", sizeof(pid_name));
+
+			kgsl_sharedmem_readl(&device->memstore,
+				&curr_context_id,
+				KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+				current_context));
+			/* Make sure the memstore read has posted */
+			mb();
+
+			context = kgsl_context_get(device, curr_context_id);
+			if (context != NULL) {
+				struct task_struct *task;
+				curr_context = ADRENO_CONTEXT(context);
+				curr_context->ib_gpu_time_used = 0;
+				task = find_task_by_vpid(context->pid);
+				if (task)
+					get_task_comm(pid_name, task);
+			} else {
+				KGSL_DRV_ERR(device,
+					"Fault tolerance no context found\n");
+			}
+		}
+		for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
+			if (curr_reg_val[i] != prev_reg_val[i])
+				fast_hang_detected = 0;
+		}
+
+		if (fast_hang_detected) {
+			KGSL_FT_ERR(device,
+				"Proc %s, ctxt_id %d ts %d triggered fault tolerance"
+				" on global ts %d\n",
+				pid_name, context ? context->id : 0,
+				(kgsl_readtimestamp(device, context,
+				KGSL_TIMESTAMP_RETIRED) + 1),
+				curr_global_ts + 1);
+			return 1;
+		}
+
+		if (curr_context != NULL) {
+
+			curr_context->ib_gpu_time_used += KGSL_TIMEOUT_PART;
+			KGSL_FT_INFO(device,
+			"Proc %s used GPU Time %d ms on timestamp 0x%X\n",
+			pid_name, curr_context->ib_gpu_time_used,
+			curr_global_ts+1);
+
+			if ((adreno_dev->long_ib_detect) &&
+				(!(curr_context->flags &
+				 CTXT_FLAGS_NO_FAULT_TOLERANCE)) &&
+				(curr_context->ib_gpu_time_used >
+					KGSL_TIMEOUT_LONG_IB_DETECTION) &&
+				(adreno_dev->long_ib_ts != curr_global_ts)) {
+						KGSL_FT_ERR(device,
+						"Proc %s, ctxt_id %d ts %d"
+						"used GPU for %d ms long ib "
+						"detected on global ts %d\n",
+						pid_name, context->id,
+						(kgsl_readtimestamp(device,
+						context,
+						KGSL_TIMESTAMP_RETIRED)+1),
+						curr_context->ib_gpu_time_used,
+						curr_global_ts+1);
+						adreno_dev->long_ib = 1;
+						adreno_dev->long_ib_ts =
+								curr_global_ts;
+						curr_context->ib_gpu_time_used =
+								0;
+						return 1;
+			}
+		}
+	} else {
+		/* GPU is moving forward */
+		prev_global_ts = curr_global_ts;
+		kgsl_context_put(context);
+		context = NULL;
+		curr_context = NULL;
+		strlcpy(pid_name, "unknown", sizeof(pid_name));
+		adreno_dev->long_ib = 0;
+		adreno_dev->long_ib_ts = 0;
+	}
+
+
+	/* If hangs are not detected copy the current reg values
+	 * to previous values and return no hang */
+	for (i = 0; i < FT_DETECT_REGS_COUNT; i++)
+			prev_reg_val[i] = curr_reg_val[i];
+	return 0;
+}
+
+static int _check_pending_timestamp(struct kgsl_device *device,
+		struct kgsl_context *context, unsigned int timestamp)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	unsigned int context_id = _get_context_id(context);
+	unsigned int ts_issued;
+
+	if (context_id == KGSL_CONTEXT_INVALID)
+		return -EINVAL;
+
+	ts_issued = adreno_context_timestamp(context, &adreno_dev->ringbuffer);
+
+	if (timestamp_cmp(timestamp, ts_issued) <= 0)
+		return 0;
+
+	if (context && !context->wait_on_invalid_ts) {
+		KGSL_DRV_ERR(device, "Cannot wait for invalid ts <%d:0x%x>, last issued ts <%d:0x%x>\n",
+			context_id, timestamp, context_id, ts_issued);
+
+			/* Only print this message once */
+			context->wait_on_invalid_ts = true;
+	}
+
+	return -EINVAL;
+}
+
 /**
  * adreno_waittimestamp - sleep while waiting for the specified timestamp
  * @device - pointer to a KGSL device structure
@@ -2604,35 +3754,147 @@
  * @timestamp - GPU timestamp to wait for
  * @msecs - amount of time to wait (in milliseconds)
  *
- * Wait up to 'msecs' milliseconds for the specified timestamp to expire.
+ * Wait 'msecs' milliseconds for the specified timestamp to expire. Wake up
+ * every KGSL_TIMEOUT_PART milliseconds to check for a device hang and process
+ * one if it happened.  Otherwise, spend most of our time in an interruptible
+ * wait for the timestamp interrupt to be processed.  This function must be
+ * called with the mutex already held.
  */
 static int adreno_waittimestamp(struct kgsl_device *device,
-		struct kgsl_context *context,
-		unsigned int timestamp,
-		unsigned int msecs)
+				struct kgsl_context *context,
+				unsigned int timestamp,
+				unsigned int msecs)
 {
-	int ret;
-	struct adreno_context *drawctxt;
+	static unsigned int io_cnt;
+	struct adreno_context *adreno_ctx = context ? ADRENO_CONTEXT(context) :
+		NULL;
+	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+	unsigned int context_id = _get_context_id(context);
+	unsigned int time_elapsed = 0;
+	unsigned int wait;
+	int ts_compare = 1;
+	int io, ret = -ETIMEDOUT;
 
-	if (context == NULL) {
-		/* If they are doing then complain once */
-		dev_WARN_ONCE(device->dev, 1,
-			"IOCTL_KGSL_DEVICE_WAITTIMESTAMP is deprecated\n");
+	if (context_id == KGSL_CONTEXT_INVALID) {
+		KGSL_DRV_WARN(device, "context was detached");
 		return -EINVAL;
 	}
 
-	/* Return -EINVAL if the context has been detached */
-	if (kgsl_context_detached(context))
-		return -EINVAL;
+	/*
+	 * Check to see if the requested timestamp is "newer" then the last
+	 * timestamp issued. If it is complain once and return error.  Only
+	 * print the message once per context so that badly behaving
+	 * applications don't spam the logs
+	 */
 
-	ret = adreno_drawctxt_wait(ADRENO_DEVICE(device), context,
-		timestamp, msecs_to_jiffies(msecs));
+	if (adreno_ctx && !(adreno_ctx->flags & CTXT_FLAGS_USER_GENERATED_TS)) {
+		if (_check_pending_timestamp(device, context, timestamp))
+			return -EINVAL;
 
-	/* If the context got invalidated then return a specific error */
-	drawctxt = ADRENO_CONTEXT(context);
+		/* Reset the invalid timestamp flag on a valid wait */
+		context->wait_on_invalid_ts = false;
+	}
 
-	if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
-		ret = -EDEADLK;
+	/*
+	 * On the first time through the loop only wait 100ms.
+	 * this gives enough time for the engine to start moving and oddly
+	 * provides better hang detection results than just going the full
+	 * KGSL_TIMEOUT_PART right off the bat. The exception to this rule
+	 * is if msecs happens to be < 100ms then just use 20ms or the msecs,
+	 * whichever is larger because anything less than 20 is unreliable
+	 */
+
+	if (msecs == 0 || msecs >= 100)
+		wait = 100;
+	else
+		wait = (msecs > 20) ? msecs : 20;
+
+	do {
+		long status;
+
+		/*
+		 * if the timestamp happens while we're not
+		 * waiting, there's a chance that an interrupt
+		 * will not be generated and thus the timestamp
+		 * work needs to be queued.
+		 */
+
+		if (kgsl_check_timestamp(device, context, timestamp)) {
+			queue_work(device->work_queue, &device->ts_expired_ws);
+			ret = 0;
+			break;
+		}
+
+		/*
+		 * For proper power accounting sometimes we need to call
+		 * io_wait_interruptible_timeout and sometimes we need to call
+		 * plain old wait_interruptible_timeout. We call the regular
+		 * timeout N times out of 100, where N is a number specified by
+		 * the current power level
+		 */
+
+		io_cnt = (io_cnt + 1) % 100;
+		io = (io_cnt < pwr->pwrlevels[pwr->active_pwrlevel].io_fraction)
+			? 0 : 1;
+
+		mutex_unlock(&device->mutex);
+
+		/* Wait for a timestamp event */
+		status = kgsl_wait_event_interruptible_timeout(
+			device->wait_queue,
+			adreno_check_interrupt_timestamp(device, context,
+				timestamp), msecs_to_jiffies(wait), io);
+
+		mutex_lock(&device->mutex);
+
+		/*
+		 * If status is non zero then either the condition was satisfied
+		 * or there was an error.  In either event, this is the end of
+		 * the line for us
+		 */
+
+		if (status != 0) {
+			ret = (status > 0) ? 0 : (int) status;
+			break;
+		}
+		time_elapsed += wait;
+
+		/* If user specified timestamps are being used, wait at least
+		 * KGSL_SYNCOBJ_SERVER_TIMEOUT msecs for the user driver to
+		 * issue a IB for a timestamp before checking to see if the
+		 * current timestamp we are waiting for is valid or not
+		 */
+
+		if (ts_compare && (adreno_ctx &&
+			(adreno_ctx->flags & CTXT_FLAGS_USER_GENERATED_TS))) {
+			if (time_elapsed > KGSL_SYNCOBJ_SERVER_TIMEOUT) {
+				ret = _check_pending_timestamp(device, context,
+					timestamp);
+				if (ret)
+					break;
+
+				/* Don't do this check again */
+				ts_compare = 0;
+
+				/*
+				 * Reset the invalid timestamp flag on a valid
+				 * wait
+				 */
+				context->wait_on_invalid_ts = false;
+			}
+		}
+
+		/*
+		 * We want to wait the floor of KGSL_TIMEOUT_PART
+		 * and (msecs - time_elapsed).
+		 */
+
+		if (KGSL_TIMEOUT_PART < (msecs - time_elapsed))
+			wait = KGSL_TIMEOUT_PART;
+		else
+			wait = (msecs - time_elapsed);
+
+	} while (!msecs || time_elapsed < msecs);
 
 	return ret;
 }
@@ -2641,13 +3903,13 @@
 		struct kgsl_context *context, enum kgsl_timestamp_type type)
 {
 	unsigned int timestamp = 0;
-	unsigned int id = context ? context->id : KGSL_MEMSTORE_GLOBAL;
+	unsigned int context_id = _get_context_id(context);
 
 	/*
-	 * If the context is detached we are in a race with
+	 * If the context ID is invalid, we are in a race with
 	 * the context being destroyed by userspace so bail.
 	 */
-	if (context && kgsl_context_detached(context)) {
+	if (context_id == KGSL_CONTEXT_INVALID) {
 		KGSL_DRV_WARN(device, "context was detached");
 		return timestamp;
 	}
@@ -2661,11 +3923,11 @@
 	}
 	case KGSL_TIMESTAMP_CONSUMED:
 		kgsl_sharedmem_readl(&device->memstore, &timestamp,
-			KGSL_MEMSTORE_OFFSET(id, soptimestamp));
+			KGSL_MEMSTORE_OFFSET(context_id, soptimestamp));
 		break;
 	case KGSL_TIMESTAMP_RETIRED:
 		kgsl_sharedmem_readl(&device->memstore, &timestamp,
-			KGSL_MEMSTORE_OFFSET(id, eoptimestamp));
+			KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp));
 		break;
 	}
 
@@ -2825,7 +4087,6 @@
 	.gpuid = adreno_gpuid,
 	.snapshot = adreno_snapshot,
 	.irq_handler = adreno_irq_handler,
-	.drain = adreno_drain,
 	/* Optional functions */
 	.setstate = adreno_setstate,
 	.drawctxt_create = adreno_drawctxt_create,
@@ -2833,7 +4094,7 @@
 	.drawctxt_destroy = adreno_drawctxt_destroy,
 	.setproperty = adreno_setproperty,
 	.postmortem_dump = adreno_dump,
-	.drawctxt_sched = adreno_drawctxt_sched,
+	.next_event = adreno_next_event,
 };
 
 static struct platform_driver adreno_platform_driver = {
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 3a19a17..9a070a6 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -35,11 +35,13 @@
 #define ADRENO_CHIPID_PATCH(_id) ((_id) & 0xFF)
 
 /* Flags to control command packet settings */
-#define KGSL_CMD_FLAGS_NONE             0
-#define KGSL_CMD_FLAGS_PMODE		BIT(0)
-#define KGSL_CMD_FLAGS_INTERNAL_ISSUE   BIT(1)
-#define KGSL_CMD_FLAGS_WFI              BIT(2)
-#define KGSL_CMD_FLAGS_PROFILE		BIT(3)
+#define KGSL_CMD_FLAGS_NONE             0x00000000
+#define KGSL_CMD_FLAGS_PMODE		0x00000001
+#define KGSL_CMD_FLAGS_INTERNAL_ISSUE	0x00000002
+#define KGSL_CMD_FLAGS_GET_INT		0x00000004
+#define KGSL_CMD_FLAGS_PROFILE		0x00000008
+#define KGSL_CMD_FLAGS_PWRON_FIXUP	0x00000010
+#define KGSL_CMD_FLAGS_EOF	        0x00000100
 
 /* Command identifiers */
 #define KGSL_CONTEXT_TO_MEM_IDENTIFIER	0x2EADBEEF
@@ -51,6 +53,7 @@
 #define KGSL_NOP_IB_IDENTIFIER	        0x20F20F20
 #define KGSL_START_OF_PROFILE_IDENTIFIER	0x2DEFADE1
 #define KGSL_END_OF_PROFILE_IDENTIFIER	0x2DEFADE2
+#define KGSL_PWRON_FIXUP_IDENTIFIER	0x2AFAFAFA
 
 #ifdef CONFIG_MSM_SCM
 #define ADRENO_DEFAULT_PWRSCALE_POLICY  (&kgsl_pwrscale_policy_tz)
@@ -95,55 +98,11 @@
 	TRACE_BUS_CTL,
 };
 
-#define ADRENO_SOFT_FAULT 1
-#define ADRENO_HARD_FAULT 2
-#define ADRENO_TIMEOUT_FAULT 3
-
-/*
- * Maximum size of the dispatcher ringbuffer - the actual inflight size will be
- * smaller then this but this size will allow for a larger range of inflight
- * sizes that can be chosen at runtime
- */
-
-#define ADRENO_DISPATCH_CMDQUEUE_SIZE 128
-
-/**
- * struct adreno_dispatcher - container for the adreno GPU dispatcher
- * @mutex: Mutex to protect the structure
- * @state: Current state of the dispatcher (active or paused)
- * @timer: Timer to monitor the progress of the command batches
- * @inflight: Number of command batch operations pending in the ringbuffer
- * @fault: Non-zero if a fault was detected.
- * @pending: Priority list of contexts waiting to submit command batches
- * @plist_lock: Spin lock to protect the pending queue
- * @cmdqueue: Queue of command batches currently flight
- * @head: pointer to the head of of the cmdqueue.  This is the oldest pending
- * operation
- * @tail: pointer to the tail of the cmdqueue.  This is the most recently
- * submitted operation
- * @work: work_struct to put the dispatcher in a work queue
- * @kobj: kobject for the dispatcher directory in the device sysfs node
- */
-struct adreno_dispatcher {
-	struct mutex mutex;
-	unsigned int state;
-	struct timer_list timer;
-	struct timer_list fault_timer;
-	unsigned int inflight;
-	atomic_t fault;
-	struct plist_head pending;
-	spinlock_t plist_lock;
-	struct kgsl_cmdbatch *cmdqueue[ADRENO_DISPATCH_CMDQUEUE_SIZE];
-	unsigned int head;
-	unsigned int tail;
-	struct work_struct work;
-	struct kobject kobj;
-};
-
 struct adreno_gpudev;
 
 struct adreno_device {
 	struct kgsl_device dev;    /* Must be first field in this struct */
+	unsigned long priv;
 	unsigned int chip_id;
 	enum adreno_gpurev gpurev;
 	unsigned long gmem_base;
@@ -180,7 +139,19 @@
 	unsigned int ocmem_base;
 	unsigned int gpu_cycles;
 	struct adreno_profile profile;
-	struct adreno_dispatcher dispatcher;
+	struct kgsl_memdesc pwron_fixup;
+	unsigned int pwron_fixup_dwords;
+};
+
+/**
+ * enum adreno_device_flags - Private flags for the adreno_device
+ * @ADRENO_DEVICE_PWRON - Set during init after a power collapse
+ * @ADRENO_DEVICE_PWRON_FIXUP - Set if the target requires the shader fixup
+ * after power collapse
+ */
+enum adreno_device_flags {
+	ADRENO_DEVICE_PWRON = 0,
+	ADRENO_DEVICE_PWRON_FIXUP = 1,
 };
 
 #define PERFCOUNTER_FLAG_NONE 0x0
@@ -311,9 +282,9 @@
 
 	/* GPU specific function hooks */
 	int (*ctxt_create)(struct adreno_device *, struct adreno_context *);
-	int (*ctxt_save)(struct adreno_device *, struct adreno_context *);
-	int (*ctxt_restore)(struct adreno_device *, struct adreno_context *);
-	int (*ctxt_draw_workaround)(struct adreno_device *,
+	void (*ctxt_save)(struct adreno_device *, struct adreno_context *);
+	void (*ctxt_restore)(struct adreno_device *, struct adreno_context *);
+	void (*ctxt_draw_workaround)(struct adreno_device *,
 					struct adreno_context *);
 	irqreturn_t (*irq_handler)(struct adreno_device *);
 	void (*irq_control)(struct adreno_device *, int);
@@ -336,6 +307,46 @@
 	void (*postmortem_dump)(struct adreno_device *adreno_dev);
 };
 
+/*
+ * struct adreno_ft_data - Structure that contains all information to
+ * perform gpu fault tolerance
+ * @ib1 - IB1 that the GPU was executing when hang happened
+ * @context_id - Context which caused the hang
+ * @global_eop - eoptimestamp at time of hang
+ * @rb_buffer - Buffer that holds the commands from good contexts
+ * @rb_size - Number of valid dwords in rb_buffer
+ * @bad_rb_buffer - Buffer that holds commands from the hanging context
+ * bad_rb_size - Number of valid dwords in bad_rb_buffer
+ * @good_rb_buffer - Buffer that holds commands from good contexts
+ * good_rb_size - Number of valid dwords in good_rb_buffer
+ * @last_valid_ctx_id - The last context from which commands were placed in
+ * ringbuffer before the GPU hung
+ * @step - Current fault tolerance step being executed
+ * @err_code - Fault tolerance error code
+ * @fault - Indicates whether the hang was caused due to a pagefault
+ * @start_of_replay_cmds - Offset in ringbuffer from where commands can be
+ * replayed during fault tolerance
+ * @replay_for_snapshot - Offset in ringbuffer where IB's can be saved for
+ * replaying with snapshot
+ */
+struct adreno_ft_data {
+	unsigned int ib1;
+	unsigned int context_id;
+	unsigned int global_eop;
+	unsigned int *rb_buffer;
+	unsigned int rb_size;
+	unsigned int *bad_rb_buffer;
+	unsigned int bad_rb_size;
+	unsigned int *good_rb_buffer;
+	unsigned int good_rb_size;
+	unsigned int last_valid_ctx_id;
+	unsigned int status;
+	unsigned int ft_policy;
+	unsigned int err_code;
+	unsigned int start_of_replay_cmds;
+	unsigned int replay_for_snapshot;
+};
+
 #define FT_DETECT_REGS_COUNT 12
 
 struct log_field {
@@ -344,16 +355,13 @@
 };
 
 /* Fault Tolerance policy flags */
-#define  KGSL_FT_OFF                      0
-#define  KGSL_FT_REPLAY                   1
-#define  KGSL_FT_SKIPIB                   2
-#define  KGSL_FT_SKIPFRAME                3
-#define  KGSL_FT_DISABLE                  4
-#define  KGSL_FT_TEMP_DISABLE             5
-#define  KGSL_FT_DEFAULT_POLICY (BIT(KGSL_FT_REPLAY) + BIT(KGSL_FT_SKIPIB))
-
-/* This internal bit is used to skip the PM dump on replayed command batches */
-#define  KGSL_FT_SKIP_PMDUMP              31
+#define  KGSL_FT_OFF                      BIT(0)
+#define  KGSL_FT_REPLAY                   BIT(1)
+#define  KGSL_FT_SKIPIB                   BIT(2)
+#define  KGSL_FT_SKIPFRAME                BIT(3)
+#define  KGSL_FT_DISABLE                  BIT(4)
+#define  KGSL_FT_TEMP_DISABLE             BIT(5)
+#define  KGSL_FT_DEFAULT_POLICY           (KGSL_FT_REPLAY + KGSL_FT_SKIPIB)
 
 /* Pagefault policy flags */
 #define KGSL_FT_PAGEFAULT_INT_ENABLE         BIT(0)
@@ -363,14 +371,6 @@
 #define KGSL_FT_PAGEFAULT_DEFAULT_POLICY     (KGSL_FT_PAGEFAULT_INT_ENABLE + \
 					KGSL_FT_PAGEFAULT_GPUHALT_ENABLE)
 
-#define ADRENO_FT_TYPES \
-	{ BIT(KGSL_FT_OFF), "off" }, \
-	{ BIT(KGSL_FT_REPLAY), "replay" }, \
-	{ BIT(KGSL_FT_SKIPIB), "skipib" }, \
-	{ BIT(KGSL_FT_SKIPFRAME), "skipframe" }, \
-	{ BIT(KGSL_FT_DISABLE), "disable" }, \
-	{ BIT(KGSL_FT_TEMP_DISABLE), "temp" }
-
 extern struct adreno_gpudev adreno_a2xx_gpudev;
 extern struct adreno_gpudev adreno_a3xx_gpudev;
 
@@ -400,7 +400,6 @@
 int adreno_coresight_init(struct platform_device *pdev);
 
 int adreno_idle(struct kgsl_device *device);
-bool adreno_isidle(struct kgsl_device *device);
 
 void adreno_shadermem_regread(struct kgsl_device *device,
 						unsigned int offsetwords,
@@ -427,23 +426,13 @@
 void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain,
 		int hang);
 
-void adreno_dispatcher_start(struct adreno_device *adreno_dev);
-int adreno_dispatcher_init(struct adreno_device *adreno_dev);
-void adreno_dispatcher_close(struct adreno_device *adreno_dev);
-int adreno_dispatcher_idle(struct adreno_device *adreno_dev,
-		unsigned int timeout);
-void adreno_dispatcher_irq_fault(struct kgsl_device *device);
-void adreno_dispatcher_stop(struct adreno_device *adreno_dev);
+int adreno_dump_and_exec_ft(struct kgsl_device *device);
 
-int adreno_dispatcher_queue_cmd(struct adreno_device *adreno_dev,
-		struct adreno_context *drawctxt, struct kgsl_cmdbatch *cmdbatch,
-		uint32_t *timestamp);
+void adreno_dump_rb(struct kgsl_device *device, const void *buf,
+			 size_t len, int start, int size);
 
-void adreno_dispatcher_schedule(struct kgsl_device *device);
-void adreno_dispatcher_pause(struct adreno_device *adreno_dev);
-void adreno_dispatcher_queue_context(struct kgsl_device *device,
-	struct adreno_context *drawctxt);
-int adreno_reset(struct kgsl_device *device);
+unsigned int adreno_ft_detect(struct kgsl_device *device,
+						unsigned int *prev_reg_val);
 
 int adreno_ft_init_sysfs(struct kgsl_device *device);
 void adreno_ft_uninit_sysfs(struct kgsl_device *device);
@@ -463,6 +452,7 @@
 
 int adreno_soft_reset(struct kgsl_device *device);
 
+int adreno_a3xx_pwron_fixup_init(struct adreno_device *adreno_dev);
 
 static inline int adreno_is_a200(struct adreno_device *adreno_dev)
 {
@@ -560,7 +550,9 @@
 {
 	if (k_ctxt) {
 		struct adreno_context *a_ctxt = ADRENO_CONTEXT(k_ctxt);
-		return a_ctxt->timestamp;
+
+		if (a_ctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
+			return a_ctxt->timestamp;
 	}
 	return rb->global_ts;
 }
@@ -759,31 +751,4 @@
 		return ADRENO_REG_REGISTER_MAX;
 	return adreno_dev->gpudev->reg_offsets->offsets[offset_name];
 }
-
-/**
- * adreno_gpu_fault() - Return the current state of the GPU
- * @adreno_dev: A ponter to the adreno_device to query
- *
- * Return 0 if there is no fault or positive with the last type of fault that
- * occurred
- */
-static inline unsigned int adreno_gpu_fault(struct adreno_device *adreno_dev)
-{
-	smp_rmb();
-	return atomic_read(&adreno_dev->dispatcher.fault);
-}
-
-/**
- * adreno_set_gpu_fault() - Set the current fault status of the GPU
- * @adreno_dev: A pointer to the adreno_device to set
- * @state: fault state to set
- *
- */
-static inline void adreno_set_gpu_fault(struct adreno_device *adreno_dev,
-	int state)
-{
-	atomic_set(&adreno_dev->dispatcher.fault, state);
-	smp_wmb();
-}
-
 #endif /*__ADRENO_H */
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index cce4f91..3d72c5c 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1451,7 +1451,7 @@
 	return ret;
 }
 
-static int a2xx_drawctxt_draw_workaround(struct adreno_device *adreno_dev,
+static void a2xx_drawctxt_draw_workaround(struct adreno_device *adreno_dev,
 					struct adreno_context *context)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
@@ -1468,7 +1468,7 @@
 				ADRENO_NUM_CTX_SWITCH_ALLOWED_BEFORE_DRAW)
 			adreno_dev->gpudev->ctx_switches_since_last_draw = 0;
 		else
-			return 0;
+			return;
 		/*
 		 * Issue an empty draw call to avoid possible hangs due to
 		 * repeated idles without intervening draw calls.
@@ -1499,46 +1499,41 @@
 					| adreno_dev->pix_shader_start;
 	}
 
-	return adreno_ringbuffer_issuecmds(device, context,
-			KGSL_CMD_FLAGS_PMODE, &cmd[0], cmds - cmd);
+	adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_PMODE,
+			&cmd[0], cmds - cmd);
 }
 
-static int a2xx_drawctxt_save(struct adreno_device *adreno_dev,
+static void a2xx_drawctxt_save(struct adreno_device *adreno_dev,
 			struct adreno_context *context)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
-	int ret;
 
 	if (context == NULL || (context->flags & CTXT_FLAGS_BEING_DESTROYED))
-		return 0;
+		return;
 
-	if (context->state == ADRENO_CONTEXT_STATE_INVALID)
-		return 0;
+	if (context->flags & CTXT_FLAGS_GPU_HANG)
+		KGSL_CTXT_WARN(device,
+			"Current active context has caused gpu hang\n");
 
 	if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
 		kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
 			context->reg_save[1],
 			context->reg_save[2] << 2, true);
 		/* save registers and constants. */
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_NONE,
 			context->reg_save, 3);
 
-		if (ret)
-			return ret;
-
 		if (context->flags & CTXT_FLAGS_SHADER_SAVE) {
 			kgsl_cffdump_syncmem(context->base.device,
 				&context->gpustate,
 				context->shader_save[1],
 				context->shader_save[2] << 2, true);
 			/* save shader partitioning and instructions. */
-			ret = adreno_ringbuffer_issuecmds(device, context,
+			adreno_ringbuffer_issuecmds(device, context,
 				KGSL_CMD_FLAGS_PMODE,
 				context->shader_save, 3);
 
-			if (ret)
-				return ret;
 			kgsl_cffdump_syncmem(context->base.device,
 				&context->gpustate,
 				context->shader_fixup[1],
@@ -1547,13 +1542,10 @@
 			 * fixup shader partitioning parameter for
 			 *  SET_SHADER_BASES.
 			 */
-			ret = adreno_ringbuffer_issuecmds(device, context,
+			adreno_ringbuffer_issuecmds(device, context,
 				KGSL_CMD_FLAGS_NONE,
 				context->shader_fixup, 3);
 
-			if (ret)
-				return ret;
-
 			context->flags |= CTXT_FLAGS_SHADER_RESTORE;
 		}
 	}
@@ -1566,41 +1558,32 @@
 		/* save gmem.
 		 * (note: changes shader. shader must already be saved.)
 		 */
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_PMODE,
 			context->context_gmem_shadow.gmem_save, 3);
 
-		if (ret)
-			return ret;
-
 		kgsl_cffdump_syncmem(context->base.device, &context->gpustate,
 			context->chicken_restore[1],
 			context->chicken_restore[2] << 2, true);
 
 		/* Restore TP0_CHICKEN */
 		if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
-			ret = adreno_ringbuffer_issuecmds(device, context,
+			adreno_ringbuffer_issuecmds(device, context,
 				KGSL_CMD_FLAGS_NONE,
 				context->chicken_restore, 3);
-
-			if (ret)
-				return ret;
 		}
 		adreno_dev->gpudev->ctx_switches_since_last_draw = 0;
 
 		context->flags |= CTXT_FLAGS_GMEM_RESTORE;
 	} else if (adreno_is_a2xx(adreno_dev))
-		return a2xx_drawctxt_draw_workaround(adreno_dev, context);
-
-	return 0;
+		a2xx_drawctxt_draw_workaround(adreno_dev, context);
 }
 
-static int a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
+static void a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
 			struct adreno_context *context)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 	unsigned int cmds[5];
-	int ret = 0;
 
 	if (context == NULL) {
 		/* No context - set the default pagetable and thats it */
@@ -1615,7 +1598,7 @@
 			: KGSL_CONTEXT_INVALID;
 		kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable,
 				  id);
-		return 0;
+		return;
 	}
 
 	cmds[0] = cp_nop_packet(1);
@@ -1624,11 +1607,8 @@
 	cmds[3] = device->memstore.gpuaddr +
 		KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
 	cmds[4] = context->base.id;
-	ret = adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
+	adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
 					cmds, 5);
-	if (ret)
-		return ret;
-
 	kgsl_mmu_setstate(&device->mmu, context->base.pagetable,
 			context->base.id);
 
@@ -1641,11 +1621,9 @@
 			context->context_gmem_shadow.gmem_restore[2] << 2,
 			true);
 
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_PMODE,
 			context->context_gmem_shadow.gmem_restore, 3);
-		if (ret)
-			return ret;
 
 		if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
 			kgsl_cffdump_syncmem(context->base.device,
@@ -1654,11 +1632,9 @@
 				context->chicken_restore[2] << 2, true);
 
 			/* Restore TP0_CHICKEN */
-			ret = adreno_ringbuffer_issuecmds(device, context,
+			adreno_ringbuffer_issuecmds(device, context,
 				KGSL_CMD_FLAGS_NONE,
 				context->chicken_restore, 3);
-			if (ret)
-				return ret;
 		}
 
 		context->flags &= ~CTXT_FLAGS_GMEM_RESTORE;
@@ -1670,10 +1646,8 @@
 			context->reg_restore[2] << 2, true);
 
 		/* restore registers and constants. */
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_NONE, context->reg_restore, 3);
-		if (ret)
-			return ret;
 
 		/* restore shader instructions & partitioning. */
 		if (context->flags & CTXT_FLAGS_SHADER_RESTORE) {
@@ -1682,22 +1656,18 @@
 				context->shader_restore[1],
 				context->shader_restore[2] << 2, true);
 
-			ret = adreno_ringbuffer_issuecmds(device, context,
+			adreno_ringbuffer_issuecmds(device, context,
 				KGSL_CMD_FLAGS_NONE,
 				context->shader_restore, 3);
-			if (ret)
-				return ret;
 		}
 	}
 
 	if (adreno_is_a20x(adreno_dev)) {
 		cmds[0] = cp_type3_packet(CP_SET_BIN_BASE_OFFSET, 1);
 		cmds[1] = context->bin_base_offset;
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_NONE, cmds, 2);
 	}
-
-	return ret;
 }
 
 /*
@@ -1764,14 +1734,13 @@
 
 	if (!status) {
 		if (master_status & MASTER_INT_SIGNAL__CP_INT_STAT) {
-			/*
-			 * This indicates that we could not read CP_INT_STAT.
-			 * As a precaution schedule the dispatcher to check
-			 * things out. Since we did not ack any interrupts this
-			 * interrupt will be generated again
-			 */
+			/* This indicates that we could not read CP_INT_STAT.
+			 * As a precaution just wake up processes so
+			 * they can check their timestamps. Since, we
+			 * did not ack any interrupts this interrupt will
+			 * be generated again */
 			KGSL_DRV_WARN(device, "Unable to read CP_INT_STATUS\n");
-			adreno_dispatcher_schedule(device);
+			wake_up_interruptible_all(&device->wait_queue);
 		} else
 			KGSL_DRV_WARN(device, "Spurious interrput detected\n");
 		return;
@@ -1797,7 +1766,7 @@
 
 	if (status & (CP_INT_CNTL__IB1_INT_MASK | CP_INT_CNTL__RB_INT_MASK)) {
 		queue_work(device->work_queue, &device->ts_expired_ws);
-		adreno_dispatcher_schedule(device);
+		wake_up_interruptible_all(&device->wait_queue);
 	}
 }
 
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index c4f81fa..f9110ea 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2382,38 +2382,32 @@
 	return ret;
 }
 
-static int a3xx_drawctxt_save(struct adreno_device *adreno_dev,
+static void a3xx_drawctxt_save(struct adreno_device *adreno_dev,
 			   struct adreno_context *context)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
-	int ret;
 
 	if (context == NULL || (context->flags & CTXT_FLAGS_BEING_DESTROYED))
-		return 0;
+		return;
 
-	if (context->state == ADRENO_CONTEXT_STATE_INVALID)
-		return 0;
+	if (context->flags & CTXT_FLAGS_GPU_HANG)
+		KGSL_CTXT_WARN(device,
+			       "Current active context has caused gpu hang\n");
 
 	if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
 		/* Fixup self modifying IBs for save operations */
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_NONE, context->save_fixup, 3);
-		if (ret)
-			return ret;
 
 		/* save registers and constants. */
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_NONE,
 			context->regconstant_save, 3);
-		if (ret)
-			return ret;
 
 		if (context->flags & CTXT_FLAGS_SHADER_SAVE) {
 			/* Save shader instructions */
-			ret = adreno_ringbuffer_issuecmds(device, context,
+			adreno_ringbuffer_issuecmds(device, context,
 				KGSL_CMD_FLAGS_PMODE, context->shader_save, 3);
-			if (ret)
-				return ret;
 
 			context->flags |= CTXT_FLAGS_SHADER_RESTORE;
 		}
@@ -2431,25 +2425,19 @@
 			context->context_gmem_shadow.gmem_save[1],
 			context->context_gmem_shadow.gmem_save[2] << 2, true);
 
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 					KGSL_CMD_FLAGS_PMODE,
 					    context->context_gmem_shadow.
 					    gmem_save, 3);
-		if (ret)
-			return ret;
-
 		context->flags |= CTXT_FLAGS_GMEM_RESTORE;
 	}
-
-	return 0;
 }
 
-static int a3xx_drawctxt_restore(struct adreno_device *adreno_dev,
+static void a3xx_drawctxt_restore(struct adreno_device *adreno_dev,
 			      struct adreno_context *context)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 	unsigned int cmds[5];
-	int ret = 0;
 
 	if (context == NULL) {
 		/* No context - set the default pagetable and thats it */
@@ -2464,7 +2452,7 @@
 			: KGSL_CONTEXT_INVALID;
 		kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable,
 				  id);
-		return 0;
+		return;
 	}
 
 	cmds[0] = cp_nop_packet(1);
@@ -2473,11 +2461,8 @@
 	cmds[3] = device->memstore.gpuaddr +
 		KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
 	cmds[4] = context->base.id;
-	ret = adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
+	adreno_ringbuffer_issuecmds(device, context, KGSL_CMD_FLAGS_NONE,
 					cmds, 5);
-	if (ret)
-		return ret;
-
 	kgsl_mmu_setstate(&device->mmu, context->base.pagetable,
 			context->base.id);
 
@@ -2493,47 +2478,508 @@
 			context->context_gmem_shadow.gmem_restore[2] << 2,
 			true);
 
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 					KGSL_CMD_FLAGS_PMODE,
 					    context->context_gmem_shadow.
 					    gmem_restore, 3);
-		if (ret)
-			return ret;
 		context->flags &= ~CTXT_FLAGS_GMEM_RESTORE;
 	}
 
 	if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_NONE, context->reg_restore, 3);
-		if (ret)
-			return ret;
 
 		/* Fixup self modifying IBs for restore operations */
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_NONE,
 			context->restore_fixup, 3);
-		if (ret)
-			return ret;
 
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_NONE,
 			context->constant_restore, 3);
-		if (ret)
-			return ret;
 
 		if (context->flags & CTXT_FLAGS_SHADER_RESTORE)
-			ret = adreno_ringbuffer_issuecmds(device, context,
+			adreno_ringbuffer_issuecmds(device, context,
 				KGSL_CMD_FLAGS_NONE,
 				context->shader_restore, 3);
-			if (ret)
-				return ret;
+
 		/* Restore HLSQ_CONTROL_0 register */
-		ret = adreno_ringbuffer_issuecmds(device, context,
+		adreno_ringbuffer_issuecmds(device, context,
 			KGSL_CMD_FLAGS_NONE,
 			context->hlsqcontrol_restore, 3);
 	}
+}
 
-	return ret;
+static const unsigned int _a3xx_pwron_fixup_fs_instructions[] = {
+	0x00000000, 0x302CC300, 0x00000000, 0x302CC304,
+	0x00000000, 0x302CC308, 0x00000000, 0x302CC30C,
+	0x00000000, 0x302CC310, 0x00000000, 0x302CC314,
+	0x00000000, 0x302CC318, 0x00000000, 0x302CC31C,
+	0x00000000, 0x302CC320, 0x00000000, 0x302CC324,
+	0x00000000, 0x302CC328, 0x00000000, 0x302CC32C,
+	0x00000000, 0x302CC330, 0x00000000, 0x302CC334,
+	0x00000000, 0x302CC338, 0x00000000, 0x302CC33C,
+	0x00000000, 0x00000400, 0x00020000, 0x63808003,
+	0x00060004, 0x63828007, 0x000A0008, 0x6384800B,
+	0x000E000C, 0x6386800F, 0x00120010, 0x63888013,
+	0x00160014, 0x638A8017, 0x001A0018, 0x638C801B,
+	0x001E001C, 0x638E801F, 0x00220020, 0x63908023,
+	0x00260024, 0x63928027, 0x002A0028, 0x6394802B,
+	0x002E002C, 0x6396802F, 0x00320030, 0x63988033,
+	0x00360034, 0x639A8037, 0x003A0038, 0x639C803B,
+	0x003E003C, 0x639E803F, 0x00000000, 0x00000400,
+	0x00000003, 0x80D60003, 0x00000007, 0x80D60007,
+	0x0000000B, 0x80D6000B, 0x0000000F, 0x80D6000F,
+	0x00000013, 0x80D60013, 0x00000017, 0x80D60017,
+	0x0000001B, 0x80D6001B, 0x0000001F, 0x80D6001F,
+	0x00000023, 0x80D60023, 0x00000027, 0x80D60027,
+	0x0000002B, 0x80D6002B, 0x0000002F, 0x80D6002F,
+	0x00000033, 0x80D60033, 0x00000037, 0x80D60037,
+	0x0000003B, 0x80D6003B, 0x0000003F, 0x80D6003F,
+	0x00000000, 0x03000000, 0x00000000, 0x00000000,
+};
+
+/**
+ * adreno_a3xx_pwron_fixup_init() - Initalize a special command buffer to run a
+ * post-power collapse shader workaround
+ * @adreno_dev: Pointer to a adreno_device struct
+ *
+ * Some targets require a special workaround shader to be executed after
+ * power-collapse.  Construct the IB once at init time and keep it
+ * handy
+ *
+ * Returns: 0 on success or negative on error
+ */
+int adreno_a3xx_pwron_fixup_init(struct adreno_device *adreno_dev)
+{
+	unsigned int *cmds;
+	int count = ARRAY_SIZE(_a3xx_pwron_fixup_fs_instructions);
+	int ret;
+
+	/* Return if the fixup is already in place */
+	if (test_bit(ADRENO_DEVICE_PWRON_FIXUP, &adreno_dev->priv))
+		return 0;
+
+	ret = kgsl_allocate_contiguous(&adreno_dev->pwron_fixup, PAGE_SIZE);
+
+	if (ret)
+		return ret;
+
+	adreno_dev->pwron_fixup.flags |= KGSL_MEMFLAGS_GPUREADONLY;
+
+	cmds = adreno_dev->pwron_fixup.hostptr;
+
+	*cmds++ = cp_type0_packet(A3XX_UCHE_CACHE_INVALIDATE0_REG, 2);
+	*cmds++ = 0x00000000;
+	*cmds++ = 0x90000000;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_REG_RMW, 3);
+	*cmds++ = A3XX_RBBM_CLOCK_CTL;
+	*cmds++ = 0xFFFCFFFF;
+	*cmds++ = 0x00010000;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_0_REG, 1);
+	*cmds++ = 0x1E000150;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
+	*cmds++ = CP_REG(A3XX_HLSQ_CONTROL_0_REG);
+	*cmds++ = 0x1E000150;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_0_REG, 1);
+	*cmds++ = 0x1E000150;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_1_REG, 1);
+	*cmds++ = 0x00000040;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_2_REG, 1);
+	*cmds++ = 0x80000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_3_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_VS_CONTROL_REG, 1);
+	*cmds++ = 0x00000001;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_FS_CONTROL_REG, 1);
+	*cmds++ = 0x0D001002;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CONST_VSPRESV_RANGE_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CONST_FSPRESV_RANGE_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_0_REG, 1);
+	*cmds++ = 0x00401101;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_1_REG, 1);
+	*cmds++ = 0x00000400;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_2_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_3_REG, 1);
+	*cmds++ = 0x00000001;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_4_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_5_REG, 1);
+	*cmds++ = 0x00000001;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_6_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_CONTROL_0_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_CONTROL_1_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_KERNEL_CONST_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_KERNEL_GROUP_X_REG, 1);
+	*cmds++ = 0x00000010;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_KERNEL_GROUP_Y_REG, 1);
+	*cmds++ = 0x00000001;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_KERNEL_GROUP_Z_REG, 1);
+	*cmds++ = 0x00000001;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_WG_OFFSET_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_SP_CTRL_REG, 1);
+	*cmds++ = 0x00040000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_CTRL_REG0, 1);
+	*cmds++ = 0x0000000A;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_CTRL_REG1, 1);
+	*cmds++ = 0x00000001;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_PARAM_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_4, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_5, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_6, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_7, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_VPC_DST_REG_0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_VPC_DST_REG_1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_VPC_DST_REG_2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_VPC_DST_REG_3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OBJ_OFFSET_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_OBJ_START_REG, 1);
+	*cmds++ = 0x00000004;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_PVT_MEM_PARAM_REG, 1);
+	*cmds++ = 0x04008001;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_PVT_MEM_ADDR_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_PVT_MEM_SIZE_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_VS_LENGTH_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_CTRL_REG0, 1);
+	*cmds++ = 0x0DB0400A;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_CTRL_REG1, 1);
+	*cmds++ = 0x00300402;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_OBJ_OFFSET_REG, 1);
+	*cmds++ = 0x00010000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_OBJ_START_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_PVT_MEM_PARAM_REG, 1);
+	*cmds++ = 0x04008001;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_PVT_MEM_ADDR_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_PVT_MEM_SIZE_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_FLAT_SHAD_MODE_REG_0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_FLAT_SHAD_MODE_REG_1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_OUTPUT_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_MRT_REG_0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_MRT_REG_1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_MRT_REG_2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_MRT_REG_3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_IMAGE_OUTPUT_REG_0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_IMAGE_OUTPUT_REG_1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_IMAGE_OUTPUT_REG_2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_IMAGE_OUTPUT_REG_3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_SP_FS_LENGTH_REG, 1);
+	*cmds++ = 0x0000000D;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_CLIP_CNTL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_GB_CLIP_ADJ, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_VPORT_XOFFSET, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_VPORT_XSCALE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_VPORT_YOFFSET, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_VPORT_YSCALE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_VPORT_ZOFFSET, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_VPORT_ZSCALE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_X0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Y0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Z0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_W0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_X1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Y1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Z1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_W1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_X2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Y2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Z2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_W2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_X3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Y3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Z3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_W3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_X4, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Y4, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Z4, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_W4, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_X5, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Y5, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Z5, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_W5, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SU_POINT_MINMAX, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SU_POINT_SIZE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SU_POLY_OFFSET_OFFSET, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SU_POLY_OFFSET_SCALE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SU_MODE_CONTROL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SC_CONTROL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SC_SCREEN_SCISSOR_TL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SC_SCREEN_SCISSOR_BR, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SC_WINDOW_SCISSOR_BR, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_SC_WINDOW_SCISSOR_TL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_TSE_DEBUG_ECO, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_PERFCOUNTER0_SELECT, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_PERFCOUNTER1_SELECT, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_PERFCOUNTER2_SELECT, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_GRAS_PERFCOUNTER3_SELECT, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MODE_CONTROL, 1);
+	*cmds++ = 0x00008000;
+	*cmds++ = cp_type0_packet(A3XX_RB_RENDER_CONTROL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MSAA_CONTROL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_ALPHA_REFERENCE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_CONTROL0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_CONTROL1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_CONTROL2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_CONTROL3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_INFO0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_INFO1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_INFO2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_INFO3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_BASE0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_BASE1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_BASE2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_BASE3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BLEND_CONTROL0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BLEND_CONTROL1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BLEND_CONTROL2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_MRT_BLEND_CONTROL3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_BLEND_RED, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_BLEND_GREEN, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_BLEND_BLUE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_BLEND_ALPHA, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_CLEAR_COLOR_DW0, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_CLEAR_COLOR_DW1, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_CLEAR_COLOR_DW2, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_CLEAR_COLOR_DW3, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_COPY_CONTROL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_COPY_DEST_BASE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_COPY_DEST_PITCH, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_COPY_DEST_INFO, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_DEPTH_CONTROL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_DEPTH_CLEAR, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_DEPTH_BUF_INFO, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_DEPTH_BUF_PITCH, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_STENCIL_CONTROL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_STENCIL_CLEAR, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_STENCIL_BUF_INFO, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_STENCIL_BUF_PITCH, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_STENCIL_REF_MASK, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_STENCIL_REF_MASK_BF, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_LRZ_VSC_CONTROL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_WINDOW_OFFSET, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_SAMPLE_COUNT_CONTROL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_SAMPLE_COUNT_ADDR, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_Z_CLAMP_MIN, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_Z_CLAMP_MAX, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_GMEM_BASE_ADDR, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_DEBUG_ECO_CONTROLS_ADDR, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_PERFCOUNTER0_SELECT, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_PERFCOUNTER1_SELECT, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_RB_FRAME_BUFFER_DIMENSION, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_LOAD_STATE, 4);
+	*cmds++ = (1 << CP_LOADSTATE_DSTOFFSET_SHIFT) |
+		(0 << CP_LOADSTATE_STATESRC_SHIFT) |
+		(6 << CP_LOADSTATE_STATEBLOCKID_SHIFT) |
+		(1 << CP_LOADSTATE_NUMOFUNITS_SHIFT);
+	*cmds++ = (1 << CP_LOADSTATE_STATETYPE_SHIFT) |
+		(0 << CP_LOADSTATE_EXTSRCADDR_SHIFT);
+	*cmds++ = 0x00400000;
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_LOAD_STATE, 4);
+	*cmds++ = (2 << CP_LOADSTATE_DSTOFFSET_SHIFT) |
+		(6 << CP_LOADSTATE_STATEBLOCKID_SHIFT) |
+		(1 << CP_LOADSTATE_NUMOFUNITS_SHIFT);
+	*cmds++ = (1 << CP_LOADSTATE_STATETYPE_SHIFT);
+	*cmds++ = 0x00400220;
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_LOAD_STATE, 4);
+	*cmds++ = (6 << CP_LOADSTATE_STATEBLOCKID_SHIFT) |
+		(1 << CP_LOADSTATE_NUMOFUNITS_SHIFT);
+	*cmds++ = (1 << CP_LOADSTATE_STATETYPE_SHIFT);
+	*cmds++ = 0x00000000;
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_LOAD_STATE, 2 + count);
+	*cmds++ = (6 << CP_LOADSTATE_STATEBLOCKID_SHIFT) |
+		(13 << CP_LOADSTATE_NUMOFUNITS_SHIFT);
+	*cmds++ = 0x00000000;
+
+	memcpy(cmds, _a3xx_pwron_fixup_fs_instructions, count << 2);
+
+	cmds += count;
+
+	*cmds++ = cp_type3_packet(CP_EXEC_CL, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CL_CONTROL_0_REG, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_0_REG, 1);
+	*cmds++ = 0x1E000150;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
+	*cmds++ = CP_REG(A3XX_HLSQ_CONTROL_0_REG);
+	*cmds++ = 0x1E000050;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_REG_RMW, 3);
+	*cmds++ = A3XX_RBBM_CLOCK_CTL;
+	*cmds++ = 0xFFFCFFFF;
+	*cmds++ = 0x00000000;
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0x00000000;
+
+	/*
+	 * Remember the number of dwords in the command buffer for when we
+	 * program the indirect buffer call in the ringbuffer
+	 */
+	adreno_dev->pwron_fixup_dwords =
+		(cmds - (unsigned int *) adreno_dev->pwron_fixup.hostptr);
+
+	/* Mark the flag in ->priv to show that we have the fix */
+	set_bit(ADRENO_DEVICE_PWRON_FIXUP, &adreno_dev->priv);
+	return 0;
 }
 
 static int a3xx_rb_init(struct adreno_device *adreno_dev,
@@ -2596,7 +3042,7 @@
 
 		/* Clear the error */
 		kgsl_regwrite(device, A3XX_RBBM_AHB_CMD, (1 << 3));
-		goto done;
+		return;
 	}
 	case A3XX_INT_RBBM_REG_TIMEOUT:
 		err = "RBBM: AHB register timeout";
@@ -2637,23 +3083,21 @@
 	case A3XX_INT_UCHE_OOB_ACCESS:
 		err = "UCHE:  Out of bounds access";
 		break;
-	default:
-		return;
 	}
+
 	KGSL_DRV_CRIT(device, "%s\n", err);
 	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
-
-done:
-	/* Trigger a fault in the dispatcher - this will effect a restart */
-	adreno_dispatcher_irq_fault(device);
 }
 
 static void a3xx_cp_callback(struct adreno_device *adreno_dev, int irq)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 
+	/* Wake up everybody waiting for the interrupt */
+	wake_up_interruptible_all(&device->wait_queue);
+
+	/* Schedule work to free mem and issue ibs */
 	queue_work(device->work_queue, &device->ts_expired_ws);
-	adreno_dispatcher_schedule(device);
 }
 
 /**
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
deleted file mode 100644
index 4d3172b..0000000
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ /dev/null
@@ -1,1646 +0,0 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/jiffies.h>
-#include <linux/err.h>
-
-#include "kgsl.h"
-#include "adreno.h"
-#include "adreno_ringbuffer.h"
-#include "adreno_trace.h"
-
-#define ADRENO_DISPATCHER_ACTIVE 0
-#define ADRENO_DISPATCHER_PAUSE 1
-
-#define CMDQUEUE_NEXT(_i, _s) (((_i) + 1) % (_s))
-
-/* Number of commands that can be queued in a context before it sleeps */
-static unsigned int _context_cmdqueue_size = 50;
-
-/* Number of milliseconds to wait for the context queue to clear */
-static unsigned int _context_queue_wait = 10000;
-
-/* Number of command batches sent at a time from a single context */
-static unsigned int _context_cmdbatch_burst = 5;
-
-/* Number of command batches inflight in the ringbuffer at any time */
-static unsigned int _dispatcher_inflight = 15;
-
-/* Command batch timeout (in milliseconds) */
-static unsigned int _cmdbatch_timeout = 2000;
-
-/* Interval for reading and comparing fault detection registers */
-static unsigned int _fault_timer_interval = 50;
-
-/* Local array for the current set of fault detect registers */
-static unsigned int fault_detect_regs[FT_DETECT_REGS_COUNT];
-
-/* The last retired global timestamp read during fault detect */
-static unsigned int fault_detect_ts;
-
-/**
- * fault_detect_read() - Read the set of fault detect registers
- * @device: Pointer to the KGSL device struct
- *
- * Read the set of fault detect registers and store them in the local array.
- * This is for the initial values that are compared later with
- * fault_detect_read_compare
- */
-static void fault_detect_read(struct kgsl_device *device)
-{
-	int i;
-
-	fault_detect_ts = kgsl_readtimestamp(device, NULL,
-		KGSL_TIMESTAMP_RETIRED);
-
-	for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
-		if (ft_detect_regs[i] == 0)
-			continue;
-		kgsl_regread(device, ft_detect_regs[i],
-			&fault_detect_regs[i]);
-	}
-}
-
-/*
- * Check to see if the device is idle and that the global timestamp is up to
- * date
- */
-static inline bool _isidle(struct kgsl_device *device)
-{
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	unsigned int ts;
-
-	ts = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
-
-	if (adreno_isidle(device) == true &&
-		(ts >= adreno_dev->ringbuffer.global_ts))
-		return true;
-
-	return false;
-}
-
-/**
- * fault_detect_read_compare() - Read the fault detect registers and compare
- * them to the current value
- * @device: Pointer to the KGSL device struct
- *
- * Read the set of fault detect registers and compare them to the current set
- * of registers.  Return 1 if any of the register values changed
- */
-static int fault_detect_read_compare(struct kgsl_device *device)
-{
-	int i, ret = 0;
-	unsigned int ts;
-
-	/* Check to see if the device is idle - if so report no hang */
-	if (_isidle(device) == true)
-		ret = 1;
-
-	for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
-		unsigned int val;
-
-		if (ft_detect_regs[i] == 0)
-			continue;
-		kgsl_regread(device, ft_detect_regs[i], &val);
-		if (val != fault_detect_regs[i])
-			ret = 1;
-		fault_detect_regs[i] = val;
-	}
-
-	ts = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
-	if (ts != fault_detect_ts)
-		ret = 1;
-
-	fault_detect_ts = ts;
-
-	return ret;
-}
-
-/**
- * adreno_dispatcher_get_cmdbatch() - Get a new command from a context queue
- * @drawctxt: Pointer to the adreno draw context
- *
- * Dequeue a new command batch from the context list
- */
-static inline struct kgsl_cmdbatch *adreno_dispatcher_get_cmdbatch(
-		struct adreno_context *drawctxt)
-{
-	struct kgsl_cmdbatch *cmdbatch = NULL;
-
-	mutex_lock(&drawctxt->mutex);
-	if (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) {
-		cmdbatch = drawctxt->cmdqueue[drawctxt->cmdqueue_head];
-
-		/*
-		 * Don't dequeue a cmdbatch that is still waiting for other
-		 * events
-		 */
-		if (kgsl_cmdbatch_sync_pending(cmdbatch)) {
-			cmdbatch = ERR_PTR(-EAGAIN);
-			goto done;
-		}
-
-		drawctxt->cmdqueue_head =
-			CMDQUEUE_NEXT(drawctxt->cmdqueue_head,
-			ADRENO_CONTEXT_CMDQUEUE_SIZE);
-		drawctxt->queued--;
-	}
-
-done:
-	mutex_unlock(&drawctxt->mutex);
-
-	return cmdbatch;
-}
-
-/**
- * adreno_dispatcher_requeue_cmdbatch() - Put a command back on the context
- * queue
- * @drawctxt: Pointer to the adreno draw context
- * @cmdbatch: Pointer to the KGSL cmdbatch to requeue
- *
- * Failure to submit a command to the ringbuffer isn't the fault of the command
- * being submitted so if a failure happens, push it back on the head of the the
- * context queue to be reconsidered again
- */
-static inline void adreno_dispatcher_requeue_cmdbatch(
-		struct adreno_context *drawctxt, struct kgsl_cmdbatch *cmdbatch)
-{
-	unsigned int prev;
-	mutex_lock(&drawctxt->mutex);
-
-	if (kgsl_context_detached(&drawctxt->base) ||
-		drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
-		mutex_unlock(&drawctxt->mutex);
-		return;
-	}
-
-	prev = drawctxt->cmdqueue_head - 1;
-
-	if (prev < 0)
-		prev = ADRENO_CONTEXT_CMDQUEUE_SIZE - 1;
-
-	/*
-	 * The maximum queue size always needs to be one less then the size of
-	 * the ringbuffer queue so there is "room" to put the cmdbatch back in
-	 */
-
-	BUG_ON(prev == drawctxt->cmdqueue_tail);
-
-	drawctxt->cmdqueue[prev] = cmdbatch;
-	drawctxt->queued++;
-
-	/* Reset the command queue head to reflect the newly requeued change */
-	drawctxt->cmdqueue_head = prev;
-	mutex_unlock(&drawctxt->mutex);
-}
-
-/**
- * dispatcher_queue_context() - Queue a context in the dispatcher pending list
- * @dispatcher: Pointer to the adreno dispatcher struct
- * @drawctxt: Pointer to the adreno draw context
- *
- * Add a context to the dispatcher pending list.
- */
-static void  dispatcher_queue_context(struct adreno_device *adreno_dev,
-		struct adreno_context *drawctxt)
-{
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
-	spin_lock(&dispatcher->plist_lock);
-
-	if (plist_node_empty(&drawctxt->pending)) {
-		/* Get a reference to the context while it sits on the list */
-		_kgsl_context_get(&drawctxt->base);
-		trace_dispatch_queue_context(drawctxt);
-		plist_add(&drawctxt->pending, &dispatcher->pending);
-	}
-
-	spin_unlock(&dispatcher->plist_lock);
-}
-
-/**
- * sendcmd() - Send a command batch to the GPU hardware
- * @dispatcher: Pointer to the adreno dispatcher struct
- * @cmdbatch: Pointer to the KGSL cmdbatch being sent
- *
- * Send a KGSL command batch to the GPU hardware
- */
-static int sendcmd(struct adreno_device *adreno_dev,
-	struct kgsl_cmdbatch *cmdbatch)
-{
-	struct kgsl_device *device = &adreno_dev->dev;
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-	int ret;
-
-	dispatcher->inflight++;
-
-	mutex_lock(&device->mutex);
-
-	if (dispatcher->inflight == 1) {
-		/* Time to make the donuts.  Turn on the GPU */
-		ret = kgsl_active_count_get(device);
-		if (ret) {
-			dispatcher->inflight--;
-			mutex_unlock(&device->mutex);
-			return ret;
-		}
-	}
-
-	ret = adreno_ringbuffer_submitcmd(adreno_dev, cmdbatch);
-
-	/*
-	 * On the first command, if the submission was successful, then read the
-	 * fault registers.  If it failed then turn off the GPU. Sad face.
-	 */
-
-	if (dispatcher->inflight == 1) {
-		if (ret == 0)
-			fault_detect_read(device);
-		else
-			kgsl_active_count_put(device);
-	}
-
-	mutex_unlock(&device->mutex);
-
-	if (ret) {
-		dispatcher->inflight--;
-		KGSL_DRV_ERR(device,
-			"Unable to submit command to the ringbuffer\n");
-		return ret;
-	}
-
-	trace_adreno_cmdbatch_submitted(cmdbatch, dispatcher->inflight);
-
-	dispatcher->cmdqueue[dispatcher->tail] = cmdbatch;
-	dispatcher->tail = (dispatcher->tail + 1) %
-		ADRENO_DISPATCH_CMDQUEUE_SIZE;
-
-	/*
-	 * If this is the first command in the pipe then the GPU will
-	 * immediately start executing it so we can start the expiry timeout on
-	 * the command batch here.  Subsequent command batches will have their
-	 * timer started when the previous command batch is retired
-	 */
-	if (dispatcher->inflight == 1) {
-		cmdbatch->expires = jiffies +
-			msecs_to_jiffies(_cmdbatch_timeout);
-		mod_timer(&dispatcher->timer, cmdbatch->expires);
-
-		/* Start the fault detection timer */
-		if (adreno_dev->fast_hang_detect)
-			mod_timer(&dispatcher->fault_timer,
-				jiffies +
-				msecs_to_jiffies(_fault_timer_interval));
-	}
-
-	return 0;
-}
-
-/**
- * dispatcher_context_sendcmds() - Send commands from a context to the GPU
- * @adreno_dev: Pointer to the adreno device struct
- * @drawctxt: Pointer to the adreno context to dispatch commands from
- *
- * Dequeue and send a burst of commands from the specified context to the GPU
- */
-static int dispatcher_context_sendcmds(struct adreno_device *adreno_dev,
-		struct adreno_context *drawctxt)
-{
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-	int count = 0;
-	int requeued = 0;
-
-	/*
-	 * Each context can send a specific number of command batches per cycle
-	 */
-	while ((count < _context_cmdbatch_burst) &&
-		(dispatcher->inflight < _dispatcher_inflight)) {
-		int ret;
-		struct kgsl_cmdbatch *cmdbatch;
-
-		if (dispatcher->state != ADRENO_DISPATCHER_ACTIVE)
-			break;
-
-		if (adreno_gpu_fault(adreno_dev) != 0)
-			break;
-
-		cmdbatch = adreno_dispatcher_get_cmdbatch(drawctxt);
-
-		if (cmdbatch == NULL)
-			break;
-
-		/*
-		 * adreno_context_get_cmdbatch returns -EAGAIN if the current
-		 * cmdbatch has pending sync points so no more to do here.
-		 * When the sync points are satisfied then the context will get
-		 * reqeueued
-		 */
-
-		if (IS_ERR(cmdbatch) && PTR_ERR(cmdbatch) == -EAGAIN) {
-			requeued = 1;
-			break;
-		}
-
-		/*
-		 * If this is a synchronization submission then there are no
-		 * commands to submit.  Discard it and get the next item from
-		 * the queue.  Decrement count so this packet doesn't count
-		 * against the burst for the context
-		 */
-
-		if (cmdbatch->flags & KGSL_CONTEXT_SYNC) {
-			kgsl_cmdbatch_destroy(cmdbatch);
-			continue;
-		}
-
-		ret = sendcmd(adreno_dev, cmdbatch);
-
-		/*
-		 * There are various reasons why we can't submit a command (no
-		 * memory for the commands, full ringbuffer, etc) but none of
-		 * these are actually the current command's fault.  Requeue it
-		 * back on the context and let it come back around again if
-		 * conditions improve
-		 */
-		if (ret) {
-			adreno_dispatcher_requeue_cmdbatch(drawctxt, cmdbatch);
-			requeued = 1;
-			break;
-		}
-		count++;
-	}
-
-	/*
-	 * If the context successfully submitted commands, then
-	 * unconditionally put it back on the queue to be considered the
-	 * next time around. This might seem a little wasteful but it is
-	 * reasonable to think that a busy context will stay busy.
-	 */
-
-	if (count || requeued) {
-		dispatcher_queue_context(adreno_dev, drawctxt);
-
-		/*
-		 * If we submitted something there will be room in the
-		 * context queue so ping the context wait queue on the
-		 * chance that the context is snoozing
-		 */
-
-		wake_up_interruptible_all(&drawctxt->wq);
-	}
-
-	/* Return the number of command batches processed */
-	if (count > 0)
-		return count;
-
-	/*
-	 * If we didn't process anything because of a stall or an error
-	 * return -1 so the issuecmds loop knows that we shouldn't
-	 * keep trying to process it
-	 */
-
-	return requeued ? -1 : 0;
-}
-
-static void plist_move(struct plist_head *old, struct plist_head *new)
-{
-	plist_head_init(new);
-	list_splice_tail(&old->node_list, &new->node_list);
-	plist_head_init(old);
-}
-
-/**
- * _adreno_dispatcher_issuecmds() - Issue commmands from pending contexts
- * @adreno_dev: Pointer to the adreno device struct
- *
- * Issue as many commands as possible (up to inflight) from the pending contexts
- * This function assumes the dispatcher mutex has been locked.
- */
-static int _adreno_dispatcher_issuecmds(struct adreno_device *adreno_dev)
-{
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-	struct plist_head tmp;
-	struct adreno_context *drawctxt, *next;
-
-	/* Leave early if the dispatcher isn't in a happy state */
-	if ((dispatcher->state != ADRENO_DISPATCHER_ACTIVE) ||
-		adreno_gpu_fault(adreno_dev) != 0)
-			return 0;
-
-	/* Copy the current context list to a temporary list */
-	spin_lock(&dispatcher->plist_lock);
-	plist_move(&dispatcher->pending, &tmp);
-	spin_unlock(&dispatcher->plist_lock);
-
-	/* Try to fill the ringbuffer as much as possible */
-	while (dispatcher->inflight < _dispatcher_inflight) {
-
-		/* Stop doing things if the dispatcher is paused or faulted */
-		if ((dispatcher->state != ADRENO_DISPATCHER_ACTIVE) ||
-			adreno_gpu_fault(adreno_dev) != 0)
-			break;
-
-		if (plist_head_empty(&tmp))
-			break;
-
-		/* Get the next entry on the list */
-		drawctxt = plist_first_entry(&tmp, struct adreno_context,
-			pending);
-
-		/* Remove it from the list */
-		plist_del(&drawctxt->pending, &tmp);
-
-		if (kgsl_context_detached(&drawctxt->base) ||
-			drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
-			kgsl_context_put(&drawctxt->base);
-			continue;
-		}
-
-		dispatcher_context_sendcmds(adreno_dev, drawctxt);
-		kgsl_context_put(&drawctxt->base);
-	}
-
-	/* Requeue any remaining contexts for the next go around */
-
-	spin_lock(&dispatcher->plist_lock);
-
-	plist_for_each_entry_safe(drawctxt, next, &tmp, pending) {
-		int prio = drawctxt->pending.prio;
-
-		/* Reset the context node */
-		plist_node_init(&drawctxt->pending, prio);
-
-		/* And put it back in the master list */
-		plist_add(&drawctxt->pending, &dispatcher->pending);
-	}
-
-	spin_unlock(&dispatcher->plist_lock);
-
-	return 0;
-}
-
-/**
- * adreno_dispatcher_issuecmds() - Issue commmands from pending contexts
- * @adreno_dev: Pointer to the adreno device struct
- *
- * Lock the dispatcher and call _adreno_dispatcher_issueibcmds
- */
-int adreno_dispatcher_issuecmds(struct adreno_device *adreno_dev)
-{
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-	int ret;
-
-	mutex_lock(&dispatcher->mutex);
-	ret = _adreno_dispatcher_issuecmds(adreno_dev);
-	mutex_unlock(&dispatcher->mutex);
-
-	return ret;
-}
-
-static int _check_context_queue(struct adreno_context *drawctxt)
-{
-	int ret;
-
-	mutex_lock(&drawctxt->mutex);
-
-	/*
-	 * Wake up if there is room in the context or if the whole thing got
-	 * invalidated while we were asleep
-	 */
-
-	if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
-		ret = 1;
-	else
-		ret = drawctxt->queued < _context_cmdqueue_size ? 1 : 0;
-
-	mutex_unlock(&drawctxt->mutex);
-
-	return ret;
-}
-
-/**
- * get_timestamp() - Return the next timestamp for the context
- * @drawctxt - Pointer to an adreno draw context struct
- * @cmdbatch - Pointer to a command batch
- * @timestamp - Pointer to a timestamp value possibly passed from the user
- *
- * Assign a timestamp based on the settings of the draw context and the command
- * batch.
- */
-static int get_timestamp(struct adreno_context *drawctxt,
-		struct kgsl_cmdbatch *cmdbatch, unsigned int *timestamp)
-{
-	/* Synchronization commands don't get a timestamp */
-	if (cmdbatch->flags & KGSL_CONTEXT_SYNC) {
-		*timestamp = 0;
-		return 0;
-	}
-
-	if (drawctxt->flags & CTXT_FLAGS_USER_GENERATED_TS) {
-		/*
-		 * User specified timestamps need to be greater than the last
-		 * issued timestamp in the context
-		 */
-		if (timestamp_cmp(drawctxt->timestamp, *timestamp) >= 0)
-			return -ERANGE;
-
-		drawctxt->timestamp = *timestamp;
-	} else
-		drawctxt->timestamp++;
-
-	*timestamp = drawctxt->timestamp;
-	return 0;
-}
-
-/**
- * adreno_dispactcher_queue_cmd() - Queue a new command in the context
- * @adreno_dev: Pointer to the adreno device struct
- * @drawctxt: Pointer to the adreno draw context
- * @cmdbatch: Pointer to the command batch being submitted
- * @timestamp: Pointer to the requested timestamp
- *
- * Queue a command in the context - if there isn't any room in the queue, then
- * block until there is
- */
-int adreno_dispatcher_queue_cmd(struct adreno_device *adreno_dev,
-		struct adreno_context *drawctxt, struct kgsl_cmdbatch *cmdbatch,
-		uint32_t *timestamp)
-{
-	int ret;
-
-	mutex_lock(&drawctxt->mutex);
-
-	if (drawctxt->flags & CTXT_FLAGS_BEING_DESTROYED) {
-		mutex_unlock(&drawctxt->mutex);
-		return -EINVAL;
-	}
-
-	/*
-	 * After skipping to the end of the frame we need to force the preamble
-	 * to run (if it exists) regardless of the context state.
-	 */
-
-	if (drawctxt->flags & CTXT_FLAGS_FORCE_PREAMBLE) {
-		set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &cmdbatch->priv);
-		drawctxt->flags &= ~CTXT_FLAGS_FORCE_PREAMBLE;
-	}
-
-	/*
-	 * If we are waiting for the end of frame and it hasn't appeared yet,
-	 * then mark the command batch as skipped.  It will still progress
-	 * through the pipeline but it won't actually send any commands
-	 */
-
-	if (drawctxt->flags & CTXT_FLAGS_SKIP_EOF) {
-		set_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv);
-
-		/*
-		 * If this command batch represents the EOF then clear the way
-		 * for the dispatcher to continue submitting
-		 */
-
-		if (cmdbatch->flags & KGSL_CONTEXT_END_OF_FRAME) {
-			drawctxt->flags &= ~CTXT_FLAGS_SKIP_EOF;
-
-			/*
-			 * Force the preamble on the next command to ensure that
-			 * the state is correct
-			 */
-
-			drawctxt->flags |= CTXT_FLAGS_FORCE_PREAMBLE;
-		}
-	}
-
-	/* Wait for room in the context queue */
-
-	while (drawctxt->queued >= _context_cmdqueue_size) {
-		trace_adreno_drawctxt_sleep(drawctxt);
-		mutex_unlock(&drawctxt->mutex);
-
-		ret = wait_event_interruptible_timeout(drawctxt->wq,
-			_check_context_queue(drawctxt),
-			msecs_to_jiffies(_context_queue_wait));
-
-		mutex_lock(&drawctxt->mutex);
-		trace_adreno_drawctxt_wake(drawctxt);
-
-		if (ret <= 0) {
-			mutex_unlock(&drawctxt->mutex);
-			return (ret == 0) ? -ETIMEDOUT : (int) ret;
-		}
-
-		/*
-		 * Account for the possiblity that the context got invalidated
-		 * while we were sleeping
-		 */
-
-		if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
-			mutex_unlock(&drawctxt->mutex);
-			return -EDEADLK;
-		}
-	}
-
-	ret = get_timestamp(drawctxt, cmdbatch, timestamp);
-	if (ret) {
-		mutex_unlock(&drawctxt->mutex);
-		return ret;
-	}
-
-	cmdbatch->timestamp = *timestamp;
-
-	/*
-	 * Set the fault tolerance policy for the command batch - assuming the
-	 * context hsn't disabled FT use the current device policy
-	 */
-
-	if (drawctxt->flags & CTXT_FLAGS_NO_FAULT_TOLERANCE)
-		set_bit(KGSL_FT_DISABLE, &cmdbatch->fault_policy);
-	else
-		cmdbatch->fault_policy = adreno_dev->ft_policy;
-
-	/* Put the command into the queue */
-	drawctxt->cmdqueue[drawctxt->cmdqueue_tail] = cmdbatch;
-	drawctxt->cmdqueue_tail = (drawctxt->cmdqueue_tail + 1) %
-		ADRENO_CONTEXT_CMDQUEUE_SIZE;
-
-	drawctxt->queued++;
-	trace_adreno_cmdbatch_queued(cmdbatch, drawctxt->queued);
-
-
-	mutex_unlock(&drawctxt->mutex);
-
-	/* Add the context to the dispatcher pending list */
-	dispatcher_queue_context(adreno_dev, drawctxt);
-
-	/*
-	 * Only issue commands if inflight is less than burst -this prevents us
-	 * from sitting around waiting for the mutex on a busy system - the work
-	 * loop will schedule it for us. Inflight is mutex protected but the
-	 * worse that can happen is that it will go to 0 after we check and if
-	 * it goes to 0 it is because the work loop decremented it and the work
-	 * queue will try to schedule new commands anyway.
-	 */
-
-	if (adreno_dev->dispatcher.inflight < _context_cmdbatch_burst)
-		adreno_dispatcher_issuecmds(adreno_dev);
-
-	return 0;
-}
-
-/*
- * If an IB inside of the command batch has a gpuaddr that matches the base
- * passed in then zero the size which effectively skips it when it is submitted
- * in the ringbuffer.
- */
-static void cmdbatch_skip_ib(struct kgsl_cmdbatch *cmdbatch, unsigned int base)
-{
-	int i;
-
-	for (i = 0; i < cmdbatch->ibcount; i++) {
-		if (cmdbatch->ibdesc[i].gpuaddr == base) {
-			cmdbatch->ibdesc[i].sizedwords = 0;
-			return;
-		}
-	}
-}
-
-static void cmdbatch_skip_frame(struct kgsl_cmdbatch *cmdbatch,
-	struct kgsl_cmdbatch **replay, int count)
-{
-	struct adreno_context *drawctxt = ADRENO_CONTEXT(cmdbatch->context);
-	int skip = 1;
-	int i;
-
-	for (i = 0; i < count; i++) {
-
-		/*
-		 * Only operate on command batches that belong to the
-		 * faulting context
-		 */
-
-		if (replay[i]->context->id != cmdbatch->context->id)
-			continue;
-
-		/*
-		 * Skip all the command batches in this context until
-		 * the EOF flag is seen.  If the EOF flag is seen then
-		 * force the preamble for the next command.
-		 */
-
-		if (skip) {
-			set_bit(CMDBATCH_FLAG_SKIP, &replay[i]->priv);
-
-			if (replay[i]->flags & KGSL_CONTEXT_END_OF_FRAME)
-				skip = 0;
-		} else {
-			set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &replay[i]->priv);
-			return;
-		}
-	}
-
-	/*
-	 * If the EOF flag hasn't been seen yet then set the flag in the
-	 * drawctxt to keep looking for it
-	 */
-
-	if (skip && drawctxt)
-		drawctxt->flags |= CTXT_FLAGS_SKIP_EOF;
-
-	/*
-	 * If we did see the EOF flag then force the preamble on for the
-	 * next command issued on this context
-	 */
-
-	if (!skip && drawctxt)
-		drawctxt->flags |= CTXT_FLAGS_FORCE_PREAMBLE;
-}
-
-static void remove_invalidated_cmdbatches(struct kgsl_device *device,
-		struct kgsl_cmdbatch **replay, int count)
-{
-	int i;
-
-	for (i = 0; i < count; i++) {
-		struct kgsl_cmdbatch *cmd = replay[i];
-		struct adreno_context *drawctxt;
-
-		if (cmd == NULL)
-			continue;
-
-		drawctxt = ADRENO_CONTEXT(cmd->context);
-
-		if (kgsl_context_detached(cmd->context) ||
-			drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
-			replay[i] = NULL;
-
-			mutex_lock(&device->mutex);
-			kgsl_cancel_events_timestamp(device, cmd->context,
-				cmd->timestamp);
-			mutex_unlock(&device->mutex);
-
-			kgsl_cmdbatch_destroy(cmd);
-		}
-	}
-}
-
-static char _pidname[TASK_COMM_LEN];
-
-static inline const char *_kgsl_context_comm(struct kgsl_context *context)
-{
-	struct task_struct *task = NULL;
-
-	if (context)
-		task = find_task_by_vpid(context->pid);
-
-	if (task)
-		get_task_comm(_pidname, task);
-	else
-		snprintf(_pidname, TASK_COMM_LEN, "unknown");
-
-	return _pidname;
-}
-
-#define pr_fault(_d, _c, fmt, args...) \
-		dev_err((_d)->dev, "%s[%d]: " fmt, \
-		_kgsl_context_comm((_c)->context), \
-		(_c)->context->pid, ##args)
-
-
-static void adreno_fault_header(struct kgsl_device *device,
-	struct kgsl_cmdbatch *cmdbatch)
-{
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	unsigned int status, base, rptr, wptr, ib1base, ib2base, ib1sz, ib2sz;
-
-	kgsl_regread(device,
-			adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS),
-			&status);
-	kgsl_regread(device,
-		adreno_getreg(adreno_dev, ADRENO_REG_CP_RB_BASE),
-		&base);
-	kgsl_regread(device,
-		adreno_getreg(adreno_dev, ADRENO_REG_CP_RB_RPTR),
-		&rptr);
-	kgsl_regread(device,
-		adreno_getreg(adreno_dev, ADRENO_REG_CP_RB_WPTR),
-		&wptr);
-	kgsl_regread(device,
-		adreno_getreg(adreno_dev, ADRENO_REG_CP_IB1_BASE),
-		&ib1base);
-	kgsl_regread(device,
-		adreno_getreg(adreno_dev, ADRENO_REG_CP_IB1_BUFSZ),
-		&ib1sz);
-	kgsl_regread(device,
-		adreno_getreg(adreno_dev, ADRENO_REG_CP_IB2_BASE),
-		&ib2base);
-	kgsl_regread(device,
-		adreno_getreg(adreno_dev, ADRENO_REG_CP_IB2_BUFSZ),
-		&ib2sz);
-
-	trace_adreno_gpu_fault(cmdbatch->context->id, cmdbatch->timestamp,
-		status, rptr, wptr, ib1base, ib1sz, ib2base, ib2sz);
-
-	pr_fault(device, cmdbatch,
-		"gpu fault ctx %d ts %d status %8.8X rb %4.4x/%4.4x ib1 %8.8x/%4.4x ib2 %8.8x/%4.4x\n",
-		cmdbatch->context->id, cmdbatch->timestamp, status,
-		rptr, wptr, ib1base, ib1sz, ib2base, ib2sz);
-}
-
-static int dispatcher_do_fault(struct kgsl_device *device)
-{
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-	unsigned int ptr;
-	unsigned int reg, base;
-	struct kgsl_cmdbatch **replay = NULL;
-	struct kgsl_cmdbatch *cmdbatch;
-	int ret, i, count = 0;
-	int fault, first = 0;
-	bool pagefault = false;
-	BUG_ON(dispatcher->inflight == 0);
-
-	fault = atomic_xchg(&dispatcher->fault, 0);
-	if (fault == 0)
-		return 0;
-
-	/* Turn off all the timers */
-	del_timer_sync(&dispatcher->timer);
-	del_timer_sync(&dispatcher->fault_timer);
-
-	mutex_lock(&device->mutex);
-
-	cmdbatch = dispatcher->cmdqueue[dispatcher->head];
-
-	trace_adreno_cmdbatch_fault(cmdbatch, fault);
-
-	/*
-	 * If the fault was due to a timeout then stop the CP to ensure we don't
-	 * get activity while we are trying to dump the state of the system
-	 */
-
-	if (fault == ADRENO_TIMEOUT_FAULT) {
-		adreno_readreg(adreno_dev, ADRENO_REG_CP_ME_CNTL, &reg);
-		reg |= (1 << 27) | (1 << 28);
-		adreno_writereg(adreno_dev, ADRENO_REG_CP_ME_CNTL, reg);
-
-		/* Skip the PM dump for a timeout because it confuses people */
-		set_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy);
-	}
-
-	adreno_readreg(adreno_dev, ADRENO_REG_CP_IB1_BASE, &base);
-
-	/*
-	 * Dump the postmortem and snapshot information if this is the first
-	 * detected fault for the oldest active command batch
-	 */
-
-	if (!test_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy)) {
-		adreno_fault_header(device, cmdbatch);
-
-		if (device->pm_dump_enable)
-			kgsl_postmortem_dump(device, 0);
-
-		kgsl_device_snapshot(device, 1);
-	}
-
-	mutex_unlock(&device->mutex);
-
-	/* Allocate memory to store the inflight commands */
-	replay = kzalloc(sizeof(*replay) * dispatcher->inflight, GFP_KERNEL);
-
-	if (replay == NULL) {
-		unsigned int ptr = dispatcher->head;
-
-		while (ptr != dispatcher->tail) {
-			struct kgsl_context *context =
-				dispatcher->cmdqueue[ptr]->context;
-
-			adreno_drawctxt_invalidate(device, context);
-			kgsl_cmdbatch_destroy(dispatcher->cmdqueue[ptr]);
-
-			ptr = CMDQUEUE_NEXT(ptr, ADRENO_DISPATCH_CMDQUEUE_SIZE);
-		}
-
-		/*
-		 * Set the replay count to zero - this will ensure that the
-		 * hardware gets reset but nothing else goes played
-		 */
-
-		count = 0;
-		goto replay;
-	}
-
-	/* Copy the inflight command batches into the temporary storage */
-	ptr = dispatcher->head;
-
-	while (ptr != dispatcher->tail) {
-		replay[count++] = dispatcher->cmdqueue[ptr];
-		ptr = CMDQUEUE_NEXT(ptr, ADRENO_DISPATCH_CMDQUEUE_SIZE);
-	}
-
-	/*
-	 * For the purposes of replay, we assume that the oldest command batch
-	 * that hasn't retired a timestamp is "hung".
-	 */
-
-	cmdbatch = replay[0];
-
-	/*
-	 * If FT is disabled for this cmdbatch invalidate immediately
-	 */
-
-	if (test_bit(KGSL_FT_DISABLE, &cmdbatch->fault_policy) ||
-		test_bit(KGSL_FT_TEMP_DISABLE, &cmdbatch->fault_policy)) {
-		pr_fault(device, cmdbatch, "gpu skipped ctx %d ts %d\n",
-			cmdbatch->context->id, cmdbatch->timestamp);
-
-		adreno_drawctxt_invalidate(device, cmdbatch->context);
-	}
-
-	/*
-	 * Set a flag so we don't print another PM dump if the cmdbatch fails
-	 * again on replay
-	 */
-
-	set_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy);
-
-	/*
-	 * A hardware fault generally means something was deterministically
-	 * wrong with the command batch - no point in trying to replay it
-	 * Clear the replay bit and move on to the next policy level
-	 */
-
-	if (fault == ADRENO_HARD_FAULT)
-		clear_bit(KGSL_FT_REPLAY, &(cmdbatch->fault_policy));
-
-	/*
-	 * A timeout fault means the IB timed out - clear the policy and
-	 * invalidate - this will clear the FT_SKIP_PMDUMP bit but that is okay
-	 * because we won't see this cmdbatch again
-	 */
-
-	if (fault == ADRENO_TIMEOUT_FAULT)
-		bitmap_zero(&cmdbatch->fault_policy, BITS_PER_LONG);
-
-	/*
-	 * If the context had a GPU page fault then it is likely it would fault
-	 * again if replayed
-	 */
-
-	if (test_bit(KGSL_CONTEXT_PAGEFAULT, &cmdbatch->context->priv)) {
-		/* we'll need to resume the mmu later... */
-		pagefault = true;
-		clear_bit(KGSL_FT_REPLAY, &cmdbatch->fault_policy);
-		clear_bit(KGSL_CONTEXT_PAGEFAULT, &cmdbatch->context->priv);
-	}
-
-	/*
-	 * Execute the fault tolerance policy. Each command batch stores the
-	 * current fault policy that was set when it was queued.
-	 * As the options are tried in descending priority
-	 * (REPLAY -> SKIPIBS -> SKIPFRAME -> NOTHING) the bits are cleared
-	 * from the cmdbatch policy so the next thing can be tried if the
-	 * change comes around again
-	 */
-
-	/* Replay the hanging command batch again */
-	if (test_and_clear_bit(KGSL_FT_REPLAY, &cmdbatch->fault_policy)) {
-		trace_adreno_cmdbatch_recovery(cmdbatch, BIT(KGSL_FT_REPLAY));
-		set_bit(KGSL_FT_REPLAY, &cmdbatch->fault_recovery);
-		goto replay;
-	}
-
-	/*
-	 * Skip the last IB1 that was played but replay everything else.
-	 * Note that the last IB1 might not be in the "hung" command batch
-	 * because the CP may have caused a page-fault while it was prefetching
-	 * the next IB1/IB2. walk all outstanding commands and zap the
-	 * supposedly bad IB1 where ever it lurks.
-	 */
-
-	if (test_and_clear_bit(KGSL_FT_SKIPIB, &cmdbatch->fault_policy)) {
-		trace_adreno_cmdbatch_recovery(cmdbatch, BIT(KGSL_FT_SKIPIB));
-		set_bit(KGSL_FT_SKIPIB, &cmdbatch->fault_recovery);
-
-		for (i = 0; i < count; i++) {
-			if (replay[i] != NULL)
-				cmdbatch_skip_ib(replay[i], base);
-		}
-
-		goto replay;
-	}
-
-	if (test_and_clear_bit(KGSL_FT_SKIPFRAME, &cmdbatch->fault_policy)) {
-		trace_adreno_cmdbatch_recovery(cmdbatch,
-			BIT(KGSL_FT_SKIPFRAME));
-		set_bit(KGSL_FT_SKIPFRAME, &cmdbatch->fault_recovery);
-
-		/*
-		 * Skip all the pending command batches for this context until
-		 * the EOF frame is seen
-		 */
-		cmdbatch_skip_frame(cmdbatch, replay, count);
-		goto replay;
-	}
-
-	/* If we get here then all the policies failed */
-
-	pr_fault(device, cmdbatch, "gpu failed ctx %d ts %d\n",
-		cmdbatch->context->id, cmdbatch->timestamp);
-
-	/* Invalidate the context */
-	adreno_drawctxt_invalidate(device, cmdbatch->context);
-
-
-replay:
-	/* Reset the dispatcher queue */
-	dispatcher->inflight = 0;
-	dispatcher->head = dispatcher->tail = 0;
-
-	/* Reset the GPU */
-	mutex_lock(&device->mutex);
-
-	/* resume the MMU if it is stalled */
-	if (pagefault && device->mmu.mmu_ops->mmu_pagefault_resume != NULL)
-		device->mmu.mmu_ops->mmu_pagefault_resume(&device->mmu);
-
-	ret = adreno_reset(device);
-	mutex_unlock(&device->mutex);
-
-	/* If adreno_reset() fails then what hope do we have for the future? */
-	BUG_ON(ret);
-
-	/* Remove any pending command batches that have been invalidated */
-	remove_invalidated_cmdbatches(device, replay, count);
-
-	/* Replay the pending command buffers */
-	for (i = 0; i < count; i++) {
-
-		int ret;
-
-		if (replay[i] == NULL)
-			continue;
-
-		/*
-		 * Force the preamble on the first command (if applicable) to
-		 * avoid any strange stage issues
-		 */
-
-		if (first == 0) {
-			set_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &replay[i]->priv);
-			first = 1;
-		}
-
-		/*
-		 * Force each command batch to wait for idle - this avoids weird
-		 * CP parse issues
-		 */
-
-		set_bit(CMDBATCH_FLAG_WFI, &replay[i]->priv);
-
-		ret = sendcmd(adreno_dev, replay[i]);
-
-		/*
-		 * If sending the command fails, then try to recover by
-		 * invalidating the context
-		 */
-
-		if (ret) {
-			pr_fault(device, replay[i],
-				"gpu reset failed ctx %d ts %d\n",
-				replay[i]->context->id, replay[i]->timestamp);
-
-			adreno_drawctxt_invalidate(device, replay[i]->context);
-			remove_invalidated_cmdbatches(device, &replay[i],
-				count - i);
-		}
-	}
-
-	mutex_lock(&device->mutex);
-	kgsl_active_count_put(device);
-	mutex_unlock(&device->mutex);
-
-	kfree(replay);
-
-	return 1;
-}
-
-static inline int cmdbatch_consumed(struct kgsl_cmdbatch *cmdbatch,
-		unsigned int consumed, unsigned int retired)
-{
-	return ((timestamp_cmp(cmdbatch->timestamp, consumed) >= 0) &&
-		(timestamp_cmp(retired, cmdbatch->timestamp) < 0));
-}
-
-static void _print_recovery(struct kgsl_device *device,
-		struct kgsl_cmdbatch *cmdbatch)
-{
-	static struct {
-		unsigned int mask;
-		const char *str;
-	} flags[] = { ADRENO_FT_TYPES };
-
-	int i, nr = find_first_bit(&cmdbatch->fault_recovery, BITS_PER_LONG);
-	char *result = "unknown";
-
-	for (i = 0; i < ARRAY_SIZE(flags); i++) {
-		if (flags[i].mask == BIT(nr)) {
-			result = (char *) flags[i].str;
-			break;
-		}
-	}
-
-	pr_fault(device, cmdbatch,
-		"gpu %s ctx %d ts %d policy %lX\n",
-		result, cmdbatch->context->id, cmdbatch->timestamp,
-		cmdbatch->fault_recovery);
-}
-
-/**
- * adreno_dispatcher_work() - Master work handler for the dispatcher
- * @work: Pointer to the work struct for the current work queue
- *
- * Process expired commands and send new ones.
- */
-static void adreno_dispatcher_work(struct work_struct *work)
-{
-	struct adreno_dispatcher *dispatcher =
-		container_of(work, struct adreno_dispatcher, work);
-	struct adreno_device *adreno_dev =
-		container_of(dispatcher, struct adreno_device, dispatcher);
-	struct kgsl_device *device = &adreno_dev->dev;
-	int count = 0;
-
-	mutex_lock(&dispatcher->mutex);
-
-	while (dispatcher->head != dispatcher->tail) {
-		uint32_t consumed, retired = 0;
-		struct kgsl_cmdbatch *cmdbatch =
-			dispatcher->cmdqueue[dispatcher->head];
-		struct adreno_context *drawctxt;
-		BUG_ON(cmdbatch == NULL);
-
-		drawctxt = ADRENO_CONTEXT(cmdbatch->context);
-
-		/*
-		 * First try to expire the timestamp. This happens if the
-		 * context is valid and the timestamp expired normally or if the
-		 * context was destroyed before the command batch was finished
-		 * in the GPU.  Either way retire the command batch advance the
-		 * pointers and continue processing the queue
-		 */
-
-		if (!kgsl_context_detached(cmdbatch->context))
-			retired = kgsl_readtimestamp(device, cmdbatch->context,
-				KGSL_TIMESTAMP_RETIRED);
-
-		if (kgsl_context_detached(cmdbatch->context) ||
-			(timestamp_cmp(cmdbatch->timestamp, retired) <= 0)) {
-
-			/*
-			 * If the cmdbatch in question had faulted announce its
-			 * successful completion to the world
-			 */
-
-			if (cmdbatch->fault_recovery != 0)
-				_print_recovery(device, cmdbatch);
-
-			trace_adreno_cmdbatch_retired(cmdbatch,
-				dispatcher->inflight - 1);
-
-			/* Reduce the number of inflight command batches */
-			dispatcher->inflight--;
-
-			/* Zero the old entry*/
-			dispatcher->cmdqueue[dispatcher->head] = NULL;
-
-			/* Advance the buffer head */
-			dispatcher->head = CMDQUEUE_NEXT(dispatcher->head,
-				ADRENO_DISPATCH_CMDQUEUE_SIZE);
-
-			/* Destroy the retired command batch */
-			kgsl_cmdbatch_destroy(cmdbatch);
-
-			/* Update the expire time for the next command batch */
-
-			if (dispatcher->inflight > 0) {
-				cmdbatch =
-					dispatcher->cmdqueue[dispatcher->head];
-				cmdbatch->expires = jiffies +
-					msecs_to_jiffies(_cmdbatch_timeout);
-			}
-
-			count++;
-			continue;
-		}
-
-		/*
-		 * If we got a fault from the interrupt handler, this command
-		 * is to blame.  Invalidate it, reset and replay
-		 */
-
-		if (dispatcher_do_fault(device))
-			goto done;
-
-		/* Get the last consumed timestamp */
-		consumed = kgsl_readtimestamp(device, cmdbatch->context,
-			KGSL_TIMESTAMP_CONSUMED);
-
-		/*
-		 * Break here if fault detection is disabled for the context or
-		 * if the long running IB detection is disaled device wide
-		 * Long running command buffers will be allowed to run to
-		 * completion - but badly behaving command buffers (infinite
-		 * shaders etc) can end up running forever.
-		 */
-
-		if (!adreno_dev->long_ib_detect ||
-			drawctxt->flags & CTXT_FLAGS_NO_FAULT_TOLERANCE)
-			break;
-
-		/*
-		 * The last line of defense is to check if the command batch has
-		 * timed out. If we get this far but the timeout hasn't expired
-		 * yet then the GPU is still ticking away
-		 */
-
-		if (time_is_after_jiffies(cmdbatch->expires))
-			break;
-
-		/* Boom goes the dynamite */
-
-		pr_fault(device, cmdbatch,
-			"gpu timeout ctx %d ts %d\n",
-			cmdbatch->context->id, cmdbatch->timestamp);
-
-		adreno_set_gpu_fault(adreno_dev, ADRENO_TIMEOUT_FAULT);
-
-		dispatcher_do_fault(device);
-		break;
-	}
-
-	/*
-	 * Decrement the active count to 0 - this will allow the system to go
-	 * into suspend even if there are queued command batches
-	 */
-
-	if (count && dispatcher->inflight == 0) {
-		mutex_lock(&device->mutex);
-		kgsl_active_count_put(device);
-		mutex_unlock(&device->mutex);
-	}
-
-	/* Dispatch new commands if we have the room */
-	if (dispatcher->inflight < _dispatcher_inflight)
-		_adreno_dispatcher_issuecmds(adreno_dev);
-
-done:
-	/* Either update the timer for the next command batch or disable it */
-	if (dispatcher->inflight) {
-		struct kgsl_cmdbatch *cmdbatch
-			= dispatcher->cmdqueue[dispatcher->head];
-
-		/* Update the timeout timer for the next command batch */
-		mod_timer(&dispatcher->timer, cmdbatch->expires);
-	} else {
-		del_timer_sync(&dispatcher->timer);
-		del_timer_sync(&dispatcher->fault_timer);
-	}
-
-	/* Before leaving update the pwrscale information */
-	mutex_lock(&device->mutex);
-	kgsl_pwrscale_idle(device);
-	mutex_unlock(&device->mutex);
-
-	mutex_unlock(&dispatcher->mutex);
-}
-
-void adreno_dispatcher_schedule(struct kgsl_device *device)
-{
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
-	queue_work(device->work_queue, &dispatcher->work);
-}
-
-/**
- * adreno_dispatcher_queue_context() - schedule a drawctxt in the dispatcher
- * device: pointer to the KGSL device
- * drawctxt: pointer to the drawctxt to schedule
- *
- * Put a draw context on the dispatcher pending queue and schedule the
- * dispatcher. This is used to reschedule changes that might have been blocked
- * for sync points or other concerns
- */
-void adreno_dispatcher_queue_context(struct kgsl_device *device,
-	struct adreno_context *drawctxt)
-{
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-
-	dispatcher_queue_context(adreno_dev, drawctxt);
-	adreno_dispatcher_schedule(device);
-}
-
-/*
- * This is called on a regular basis while command batches are inflight.  Fault
- * detection registers are read and compared to the existing values - if they
- * changed then the GPU is still running.  If they are the same between
- * subsequent calls then the GPU may have faulted
- */
-
-void adreno_dispatcher_fault_timer(unsigned long data)
-{
-	struct adreno_device *adreno_dev = (struct adreno_device *) data;
-	struct kgsl_device *device = &adreno_dev->dev;
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
-	/* Leave if the user decided to turn off fast hang detection */
-	if (adreno_dev->fast_hang_detect == 0)
-		return;
-
-	if (adreno_gpu_fault(adreno_dev)) {
-		adreno_dispatcher_schedule(device);
-		return;
-	}
-
-	/*
-	 * Read the fault registers - if it returns 0 then they haven't changed
-	 * so mark the dispatcher as faulted and schedule the work loop.
-	 */
-
-	if (!fault_detect_read_compare(device)) {
-		adreno_set_gpu_fault(adreno_dev, ADRENO_SOFT_FAULT);
-		adreno_dispatcher_schedule(device);
-	} else {
-		mod_timer(&dispatcher->fault_timer,
-			jiffies + msecs_to_jiffies(_fault_timer_interval));
-	}
-}
-
-/*
- * This is called when the timer expires - it either means the GPU is hung or
- * the IB is taking too long to execute
- */
-void adreno_dispatcher_timer(unsigned long data)
-{
-	struct adreno_device *adreno_dev = (struct adreno_device *) data;
-	struct kgsl_device *device = &adreno_dev->dev;
-
-	adreno_dispatcher_schedule(device);
-}
-/**
- * adreno_dispatcher_irq_fault() - Trigger a fault in the dispatcher
- * @device: Pointer to the KGSL device
- *
- * Called from an interrupt context this will trigger a fault in the
- * dispatcher for the oldest pending command batch
- */
-void adreno_dispatcher_irq_fault(struct kgsl_device *device)
-{
-	adreno_set_gpu_fault(ADRENO_DEVICE(device), ADRENO_HARD_FAULT);
-	adreno_dispatcher_schedule(device);
-}
-
-/**
- * adreno_dispatcher_pause() - stop the dispatcher
- * @adreno_dev: pointer to the adreno device structure
- *
- * Pause the dispather so it doesn't accept any new commands
- */
-void adreno_dispatcher_pause(struct adreno_device *adreno_dev)
-{
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
-	/*
-	 * This will probably get called while holding other mutexes so don't
-	 * take the dispatcher mutex.  The biggest penalty is that another
-	 * command might be submitted while we are in here but thats okay
-	 * because whoever is waiting for the drain will just have another
-	 * command batch to wait for
-	 */
-
-	dispatcher->state = ADRENO_DISPATCHER_PAUSE;
-}
-
-/**
- * adreno_dispatcher_start() - activate the dispatcher
- * @adreno_dev: pointer to the adreno device structure
- *
- * Set the disaptcher active and start the loop once to get things going
- */
-void adreno_dispatcher_start(struct adreno_device *adreno_dev)
-{
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
-	dispatcher->state = ADRENO_DISPATCHER_ACTIVE;
-
-	/* Schedule the work loop to get things going */
-	adreno_dispatcher_schedule(&adreno_dev->dev);
-}
-
-/**
- * adreno_dispatcher_stop() - stop the dispatcher
- * @adreno_dev: pointer to the adreno device structure
- *
- * Stop the dispatcher and close all the timers
- */
-void adreno_dispatcher_stop(struct adreno_device *adreno_dev)
-{
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
-	del_timer_sync(&dispatcher->timer);
-	del_timer_sync(&dispatcher->fault_timer);
-
-	dispatcher->state = ADRENO_DISPATCHER_PAUSE;
-}
-
-/**
- * adreno_dispatcher_close() - close the dispatcher
- * @adreno_dev: pointer to the adreno device structure
- *
- * Close the dispatcher and free all the oustanding commands and memory
- */
-void adreno_dispatcher_close(struct adreno_device *adreno_dev)
-{
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
-	mutex_lock(&dispatcher->mutex);
-	del_timer_sync(&dispatcher->timer);
-	del_timer_sync(&dispatcher->fault_timer);
-
-	while (dispatcher->head != dispatcher->tail) {
-		kgsl_cmdbatch_destroy(dispatcher->cmdqueue[dispatcher->head]);
-		dispatcher->head = (dispatcher->head + 1)
-			% ADRENO_DISPATCH_CMDQUEUE_SIZE;
-	}
-
-	mutex_unlock(&dispatcher->mutex);
-
-	kobject_put(&dispatcher->kobj);
-}
-
-struct dispatcher_attribute {
-	struct attribute attr;
-	ssize_t (*show)(struct adreno_dispatcher *,
-			struct dispatcher_attribute *, char *);
-	ssize_t (*store)(struct adreno_dispatcher *,
-			struct dispatcher_attribute *, const char *buf,
-			size_t count);
-	unsigned int max;
-	unsigned int *value;
-};
-
-#define DISPATCHER_UINT_ATTR(_name, _mode, _max, _value) \
-	struct dispatcher_attribute dispatcher_attr_##_name =  { \
-		.attr = { .name = __stringify(_name), .mode = _mode }, \
-		.show = _show_uint, \
-		.store = _store_uint, \
-		.max = _max, \
-		.value = &(_value), \
-	}
-
-#define to_dispatcher_attr(_a) \
-	container_of((_a), struct dispatcher_attribute, attr)
-#define to_dispatcher(k) container_of(k, struct adreno_dispatcher, kobj)
-
-static ssize_t _store_uint(struct adreno_dispatcher *dispatcher,
-		struct dispatcher_attribute *attr,
-		const char *buf, size_t size)
-{
-	unsigned long val;
-	int ret = kstrtoul(buf, 0, &val);
-
-	if (ret)
-		return ret;
-
-	if (!val || (attr->max && (val > attr->max)))
-		return -EINVAL;
-
-	*((unsigned int *) attr->value) = val;
-	return size;
-}
-
-static ssize_t _show_uint(struct adreno_dispatcher *dispatcher,
-		struct dispatcher_attribute *attr,
-		char *buf)
-{
-	return snprintf(buf, PAGE_SIZE, "%d\n",
-		*((unsigned int *) attr->value));
-}
-
-static DISPATCHER_UINT_ATTR(inflight, 0644, ADRENO_DISPATCH_CMDQUEUE_SIZE,
-	_dispatcher_inflight);
-/*
- * Our code that "puts back" a command from the context is much cleaner
- * if we are sure that there will always be enough room in the
- * ringbuffer so restrict the maximum size of the context queue to
- * ADRENO_CONTEXT_CMDQUEUE_SIZE - 1
- */
-static DISPATCHER_UINT_ATTR(context_cmdqueue_size, 0644,
-	ADRENO_CONTEXT_CMDQUEUE_SIZE - 1, _context_cmdqueue_size);
-static DISPATCHER_UINT_ATTR(context_burst_count, 0644, 0,
-	_context_cmdbatch_burst);
-static DISPATCHER_UINT_ATTR(cmdbatch_timeout, 0644, 0, _cmdbatch_timeout);
-static DISPATCHER_UINT_ATTR(context_queue_wait, 0644, 0, _context_queue_wait);
-static DISPATCHER_UINT_ATTR(fault_detect_interval, 0644, 0,
-	_fault_timer_interval);
-
-static struct attribute *dispatcher_attrs[] = {
-	&dispatcher_attr_inflight.attr,
-	&dispatcher_attr_context_cmdqueue_size.attr,
-	&dispatcher_attr_context_burst_count.attr,
-	&dispatcher_attr_cmdbatch_timeout.attr,
-	&dispatcher_attr_context_queue_wait.attr,
-	&dispatcher_attr_fault_detect_interval.attr,
-	NULL,
-};
-
-static ssize_t dispatcher_sysfs_show(struct kobject *kobj,
-				   struct attribute *attr, char *buf)
-{
-	struct adreno_dispatcher *dispatcher = to_dispatcher(kobj);
-	struct dispatcher_attribute *pattr = to_dispatcher_attr(attr);
-	ssize_t ret = -EIO;
-
-	if (pattr->show)
-		ret = pattr->show(dispatcher, pattr, buf);
-
-	return ret;
-}
-
-static ssize_t dispatcher_sysfs_store(struct kobject *kobj,
-				    struct attribute *attr,
-				    const char *buf, size_t count)
-{
-	struct adreno_dispatcher *dispatcher = to_dispatcher(kobj);
-	struct dispatcher_attribute *pattr = to_dispatcher_attr(attr);
-	ssize_t ret = -EIO;
-
-	if (pattr->store)
-		ret = pattr->store(dispatcher, pattr, buf, count);
-
-	return ret;
-}
-
-static void dispatcher_sysfs_release(struct kobject *kobj)
-{
-}
-
-static const struct sysfs_ops dispatcher_sysfs_ops = {
-	.show = dispatcher_sysfs_show,
-	.store = dispatcher_sysfs_store
-};
-
-static struct kobj_type ktype_dispatcher = {
-	.sysfs_ops = &dispatcher_sysfs_ops,
-	.default_attrs = dispatcher_attrs,
-	.release = dispatcher_sysfs_release
-};
-
-/**
- * adreno_dispatcher_init() - Initialize the dispatcher
- * @adreno_dev: pointer to the adreno device structure
- *
- * Initialize the dispatcher
- */
-int adreno_dispatcher_init(struct adreno_device *adreno_dev)
-{
-	struct kgsl_device *device = &adreno_dev->dev;
-	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-	int ret;
-
-	memset(dispatcher, 0, sizeof(*dispatcher));
-
-	mutex_init(&dispatcher->mutex);
-
-	setup_timer(&dispatcher->timer, adreno_dispatcher_timer,
-		(unsigned long) adreno_dev);
-
-	setup_timer(&dispatcher->fault_timer, adreno_dispatcher_fault_timer,
-		(unsigned long) adreno_dev);
-
-	INIT_WORK(&dispatcher->work, adreno_dispatcher_work);
-
-	plist_head_init(&dispatcher->pending);
-	spin_lock_init(&dispatcher->plist_lock);
-
-	dispatcher->state = ADRENO_DISPATCHER_ACTIVE;
-
-	ret = kobject_init_and_add(&dispatcher->kobj, &ktype_dispatcher,
-		&device->dev->kobj, "dispatch");
-
-	return ret;
-}
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 907d41f..0af4c12e 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -13,12 +13,10 @@
 
 #include <linux/slab.h>
 #include <linux/msm_kgsl.h>
-#include <linux/sched.h>
 
 #include "kgsl.h"
 #include "kgsl_sharedmem.h"
 #include "adreno.h"
-#include "adreno_trace.h"
 
 #define KGSL_INIT_REFTIMESTAMP		0x7FFFFFFF
 
@@ -134,247 +132,6 @@
 	*incmd = cmd;
 }
 
-static void wait_callback(struct kgsl_device *device, void *priv, u32 id,
-		u32 timestamp, u32 type)
-{
-	struct adreno_context *drawctxt = priv;
-	wake_up_interruptible_all(&drawctxt->waiting);
-}
-
-#define adreno_wait_event_interruptible_timeout(wq, condition, timeout, io)   \
-({                                                                            \
-	long __ret = timeout;                                                 \
-	if (io)                                                               \
-		__wait_io_event_interruptible_timeout(wq, condition, __ret);  \
-	else                                                                  \
-		__wait_event_interruptible_timeout(wq, condition, __ret);     \
-	__ret;                                                                \
-})
-
-#define adreno_wait_event_interruptible(wq, condition, io)                    \
-({                                                                            \
-	long __ret;                                                           \
-	if (io)                                                               \
-		__wait_io_event_interruptible(wq, condition, __ret);          \
-	else                                                                  \
-		__wait_event_interruptible(wq, condition, __ret);             \
-	__ret;                                                                \
-})
-
-static int _check_context_timestamp(struct kgsl_device *device,
-		struct adreno_context *drawctxt, unsigned int timestamp)
-{
-	int ret = 0;
-
-	/* Bail if the drawctxt has been invalidated or destroyed */
-	if (kgsl_context_detached(&drawctxt->base) ||
-		drawctxt->state != ADRENO_CONTEXT_STATE_ACTIVE)
-		return 1;
-
-	mutex_lock(&device->mutex);
-	ret = kgsl_check_timestamp(device, &drawctxt->base, timestamp);
-	mutex_unlock(&device->mutex);
-
-	return ret;
-}
-
-/**
- * adreno_drawctxt_wait() - sleep until a timestamp expires
- * @adreno_dev: pointer to the adreno_device struct
- * @drawctxt: Pointer to the draw context to sleep for
- * @timetamp: Timestamp to wait on
- * @timeout: Number of jiffies to wait (0 for infinite)
- *
- * Register an event to wait for a timestamp on a context and sleep until it
- * has past.  Returns < 0 on error, -ETIMEDOUT if the timeout expires or 0
- * on success
- */
-int adreno_drawctxt_wait(struct adreno_device *adreno_dev,
-		struct kgsl_context *context,
-		uint32_t timestamp, unsigned int timeout)
-{
-	static unsigned int io_cnt;
-	struct kgsl_device *device = &adreno_dev->dev;
-	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
-	struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
-	int ret, io;
-
-	if (kgsl_context_detached(context))
-		return -EINVAL;
-
-	if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
-		return -EDEADLK;
-
-	/* Needs to hold the device mutex */
-	BUG_ON(!mutex_is_locked(&device->mutex));
-
-	trace_adreno_drawctxt_wait_start(context->id, timestamp);
-
-	ret = kgsl_add_event(device, context->id, timestamp,
-		wait_callback, drawctxt, NULL);
-	if (ret)
-		goto done;
-
-	/*
-	 * For proper power accounting sometimes we need to call
-	 * io_wait_interruptible_timeout and sometimes we need to call
-	 * plain old wait_interruptible_timeout. We call the regular
-	 * timeout N times out of 100, where N is a number specified by
-	 * the current power level
-	 */
-
-	io_cnt = (io_cnt + 1) % 100;
-	io = (io_cnt < pwr->pwrlevels[pwr->active_pwrlevel].io_fraction)
-		? 0 : 1;
-
-	mutex_unlock(&device->mutex);
-
-	if (timeout) {
-		ret = (int) adreno_wait_event_interruptible_timeout(
-			drawctxt->waiting,
-			_check_context_timestamp(device, drawctxt, timestamp),
-			msecs_to_jiffies(timeout), io);
-
-		if (ret == 0)
-			ret = -ETIMEDOUT;
-		else if (ret > 0)
-			ret = 0;
-	} else {
-		ret = (int) adreno_wait_event_interruptible(drawctxt->waiting,
-			_check_context_timestamp(device, drawctxt, timestamp),
-				io);
-	}
-
-	mutex_lock(&device->mutex);
-
-	/* -EDEADLK if the context was invalidated while we were waiting */
-	if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
-		ret = -EDEADLK;
-
-
-	/* Return -EINVAL if the context was detached while we were waiting */
-	if (kgsl_context_detached(context))
-		ret = -EINVAL;
-
-done:
-	trace_adreno_drawctxt_wait_done(context->id, timestamp, ret);
-	return ret;
-}
-
-static void global_wait_callback(struct kgsl_device *device, void *priv, u32 id,
-		u32 timestamp, u32 type)
-{
-	struct adreno_context *drawctxt = priv;
-
-	wake_up_interruptible_all(&drawctxt->waiting);
-	kgsl_context_put(&drawctxt->base);
-}
-
-static int _check_global_timestamp(struct kgsl_device *device,
-		unsigned int timestamp)
-{
-	int ret;
-
-	mutex_lock(&device->mutex);
-	ret = kgsl_check_timestamp(device, NULL, timestamp);
-	mutex_unlock(&device->mutex);
-
-	return ret;
-}
-
-int adreno_drawctxt_wait_global(struct adreno_device *adreno_dev,
-		struct kgsl_context *context,
-		uint32_t timestamp, unsigned int timeout)
-{
-	struct kgsl_device *device = &adreno_dev->dev;
-	struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
-	int ret;
-
-	/* Needs to hold the device mutex */
-	BUG_ON(!mutex_is_locked(&device->mutex));
-
-	_kgsl_context_get(context);
-
-	trace_adreno_drawctxt_wait_start(KGSL_MEMSTORE_GLOBAL, timestamp);
-
-	ret = kgsl_add_event(device, KGSL_MEMSTORE_GLOBAL, timestamp,
-		global_wait_callback, drawctxt, NULL);
-	if (ret) {
-		kgsl_context_put(context);
-		goto done;
-	}
-
-	mutex_unlock(&device->mutex);
-
-	if (timeout) {
-		ret = (int) wait_event_interruptible_timeout(drawctxt->waiting,
-			_check_global_timestamp(device, timestamp),
-			msecs_to_jiffies(timeout));
-
-		if (ret == 0)
-			ret = -ETIMEDOUT;
-		else if (ret > 0)
-			ret = 0;
-	} else {
-		ret = (int) wait_event_interruptible(drawctxt->waiting,
-			_check_global_timestamp(device, timestamp));
-	}
-
-	mutex_lock(&device->mutex);
-
-	if (ret)
-		kgsl_cancel_events_timestamp(device, NULL, timestamp);
-
-done:
-	trace_adreno_drawctxt_wait_done(KGSL_MEMSTORE_GLOBAL, timestamp, ret);
-	return ret;
-}
-
-/**
- * adreno_drawctxt_invalidate() - Invalidate an adreno draw context
- * @device: Pointer to the KGSL device structure for the GPU
- * @context: Pointer to the KGSL context structure
- *
- * Invalidate the context and remove all queued commands and cancel any pending
- * waiters
- */
-void adreno_drawctxt_invalidate(struct kgsl_device *device,
-		struct kgsl_context *context)
-{
-	struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
-
-	trace_adreno_drawctxt_invalidate(drawctxt);
-
-	drawctxt->state = ADRENO_CONTEXT_STATE_INVALID;
-
-	/* Clear the pending queue */
-	mutex_lock(&drawctxt->mutex);
-
-	while (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) {
-		struct kgsl_cmdbatch *cmdbatch =
-			drawctxt->cmdqueue[drawctxt->cmdqueue_head];
-
-		drawctxt->cmdqueue_head = (drawctxt->cmdqueue_head + 1) %
-			ADRENO_CONTEXT_CMDQUEUE_SIZE;
-
-		mutex_unlock(&drawctxt->mutex);
-
-		mutex_lock(&device->mutex);
-		kgsl_cancel_events_timestamp(device, context,
-			cmdbatch->timestamp);
-		mutex_unlock(&device->mutex);
-
-		kgsl_cmdbatch_destroy(cmdbatch);
-		mutex_lock(&drawctxt->mutex);
-	}
-
-	mutex_unlock(&drawctxt->mutex);
-
-	/* Give the bad news to everybody waiting around */
-	wake_up_interruptible_all(&drawctxt->waiting);
-	wake_up_interruptible_all(&drawctxt->wq);
-}
-
 /**
  * adreno_drawctxt_create - create a new adreno draw context
  * @dev_priv: the owner of the context
@@ -392,7 +149,6 @@
 	int ret;
 
 	drawctxt = kzalloc(sizeof(struct adreno_context), GFP_KERNEL);
-
 	if (drawctxt == NULL)
 		return ERR_PTR(-ENOMEM);
 
@@ -412,30 +168,22 @@
 		KGSL_CONTEXT_NO_FAULT_TOLERANCE |
 		KGSL_CONTEXT_TYPE_MASK);
 
-	/* Always enable per-context timestamps */
-	*flags |= KGSL_CONTEXT_PER_CONTEXT_TS;
-	drawctxt->flags |= CTXT_FLAGS_PER_CONTEXT_TS;
-
 	if (*flags & KGSL_CONTEXT_PREAMBLE)
 		drawctxt->flags |= CTXT_FLAGS_PREAMBLE;
 
 	if (*flags & KGSL_CONTEXT_NO_GMEM_ALLOC)
 		drawctxt->flags |= CTXT_FLAGS_NOGMEMALLOC;
 
-	if (*flags & KGSL_CONTEXT_USER_GENERATED_TS)
+	if (*flags & KGSL_CONTEXT_PER_CONTEXT_TS)
+		drawctxt->flags |= CTXT_FLAGS_PER_CONTEXT_TS;
+
+	if (*flags & KGSL_CONTEXT_USER_GENERATED_TS) {
+		if (!(*flags & KGSL_CONTEXT_PER_CONTEXT_TS)) {
+			ret = -EINVAL;
+			goto err;
+		}
 		drawctxt->flags |= CTXT_FLAGS_USER_GENERATED_TS;
-
-	mutex_init(&drawctxt->mutex);
-	init_waitqueue_head(&drawctxt->wq);
-	init_waitqueue_head(&drawctxt->waiting);
-
-	/*
-	 * Set up the plist node for the dispatcher.  For now all contexts have
-	 * the same priority, but later the priority will be set at create time
-	 * by the user
-	 */
-
-	plist_node_init(&drawctxt->pending, ADRENO_CONTEXT_DEFAULT_PRIORITY);
+	}
 
 	if (*flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE)
 		drawctxt->flags |= CTXT_FLAGS_NO_FAULT_TOLERANCE;
@@ -448,6 +196,12 @@
 		goto err;
 
 	kgsl_sharedmem_writel(device, &device->memstore,
+			KGSL_MEMSTORE_OFFSET(drawctxt->base.id, ref_wait_ts),
+			KGSL_INIT_REFTIMESTAMP);
+	kgsl_sharedmem_writel(device, &device->memstore,
+			KGSL_MEMSTORE_OFFSET(drawctxt->base.id, ts_cmp_enable),
+			0);
+	kgsl_sharedmem_writel(device, &device->memstore,
 			KGSL_MEMSTORE_OFFSET(drawctxt->base.id, soptimestamp),
 			0);
 	kgsl_sharedmem_writel(device, &device->memstore,
@@ -461,39 +215,22 @@
 }
 
 /**
- * adreno_drawctxt_sched() - Schedule a previously blocked context
- * @device: pointer to a KGSL device
- * @drawctxt: drawctxt to rechedule
- *
- * This function is called by the core when it knows that a previously blocked
- * context has been unblocked.  The default adreno response is to reschedule the
- * context on the dispatcher
- */
-void adreno_drawctxt_sched(struct kgsl_device *device,
-		struct kgsl_context *context)
-{
-	adreno_dispatcher_queue_context(device, ADRENO_CONTEXT(context));
-}
-
-/**
  * adreno_drawctxt_detach(): detach a context from the GPU
  * @context: Generic KGSL context container for the context
  *
  */
-int adreno_drawctxt_detach(struct kgsl_context *context)
+void adreno_drawctxt_detach(struct kgsl_context *context)
 {
 	struct kgsl_device *device;
 	struct adreno_device *adreno_dev;
 	struct adreno_context *drawctxt;
-	int ret;
 
 	if (context == NULL)
-		return 0;
+		return;
 
 	device = context->device;
 	adreno_dev = ADRENO_DEVICE(device);
 	drawctxt = ADRENO_CONTEXT(context);
-
 	/* deactivate context */
 	if (adreno_dev->drawctxt_active == drawctxt) {
 		/* no need to save GMEM or shader, the context is
@@ -509,39 +246,13 @@
 		adreno_drawctxt_switch(adreno_dev, NULL, 0);
 	}
 
-	mutex_lock(&drawctxt->mutex);
-
-	while (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) {
-		struct kgsl_cmdbatch *cmdbatch =
-			drawctxt->cmdqueue[drawctxt->cmdqueue_head];
-
-		drawctxt->cmdqueue_head = (drawctxt->cmdqueue_head + 1) %
-			ADRENO_CONTEXT_CMDQUEUE_SIZE;
-
-		mutex_unlock(&drawctxt->mutex);
-
-		/*
-		 * Don't hold the drawctxt mutex while the cmdbatch is being
-		 * destroyed because the cmdbatch destroy takes the device
-		 * mutex and the world falls in on itself
-		 */
-
-		kgsl_cmdbatch_destroy(cmdbatch);
-		mutex_lock(&drawctxt->mutex);
-	}
-
-	mutex_unlock(&drawctxt->mutex);
-
-	/* Wait for the last global timestamp to pass before continuing */
-	ret = adreno_drawctxt_wait_global(adreno_dev, context,
-		drawctxt->internal_timestamp, 10 * 1000);
+	if (device->state != KGSL_STATE_HUNG)
+		adreno_idle(device);
 
 	adreno_profile_process_results(device);
 
 	kgsl_sharedmem_free(&drawctxt->gpustate);
 	kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);
-
-	return ret;
 }
 
 
@@ -585,12 +296,11 @@
  * Switch the current draw context
  */
 
-int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
+void adreno_drawctxt_switch(struct adreno_device *adreno_dev,
 				struct adreno_context *drawctxt,
 				unsigned int flags)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
-	int ret = 0;
 
 	if (drawctxt) {
 		if (flags & KGSL_CONTEXT_SAVE_GMEM)
@@ -606,24 +316,18 @@
 	if (adreno_dev->drawctxt_active == drawctxt) {
 		if (adreno_dev->gpudev->ctxt_draw_workaround &&
 			adreno_is_a225(adreno_dev))
-				ret = adreno_dev->gpudev->ctxt_draw_workaround(
+				adreno_dev->gpudev->ctxt_draw_workaround(
 					adreno_dev, drawctxt);
-		return ret;
+		return;
 	}
 
-	trace_adreno_drawctxt_switch(adreno_dev->drawctxt_active,
-		drawctxt, flags);
+	KGSL_CTXT_INFO(device, "from %d to %d flags %d\n",
+		adreno_dev->drawctxt_active ?
+		adreno_dev->drawctxt_active->base.id : 0,
+		drawctxt ? drawctxt->base.id : 0, flags);
 
 	/* Save the old context */
-	ret = adreno_dev->gpudev->ctxt_save(adreno_dev,
-		adreno_dev->drawctxt_active);
-
-	if (ret) {
-		KGSL_DRV_ERR(device,
-			"Error in GPU context %d save: %d\n",
-			adreno_dev->drawctxt_active->base.id, ret);
-		return ret;
-	}
+	adreno_dev->gpudev->ctxt_save(adreno_dev, adreno_dev->drawctxt_active);
 
 	/* Put the old instance of the active drawctxt */
 	if (adreno_dev->drawctxt_active) {
@@ -636,14 +340,6 @@
 		_kgsl_context_get(&drawctxt->base);
 
 	/* Set the new context */
-	ret = adreno_dev->gpudev->ctxt_restore(adreno_dev, drawctxt);
-	if (ret) {
-		KGSL_DRV_ERR(device,
-			"Error in GPU context %d restore: %d\n",
-			drawctxt->base.id, ret);
-		return ret;
-	}
-
+	adreno_dev->gpudev->ctxt_restore(adreno_dev, drawctxt);
 	adreno_dev->drawctxt_active = drawctxt;
-	return 0;
 }
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index 5c12676..3088099 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -54,8 +54,6 @@
 #define CTXT_FLAGS_SKIP_EOF             BIT(15)
 /* Context no fault tolerance */
 #define CTXT_FLAGS_NO_FAULT_TOLERANCE  BIT(16)
-/* Force the preamble for the next submission */
-#define CTXT_FLAGS_FORCE_PREAMBLE      BIT(17)
 
 /* Symbolic table for the adreno draw context type */
 #define ADRENO_DRAWCTXT_TYPES \
@@ -71,13 +69,6 @@
 	const char *str;
 };
 
-#define ADRENO_CONTEXT_CMDQUEUE_SIZE 128
-
-#define ADRENO_CONTEXT_DEFAULT_PRIORITY 1
-
-#define ADRENO_CONTEXT_STATE_ACTIVE 0
-#define ADRENO_CONTEXT_STATE_INVALID 1
-
 struct kgsl_device;
 struct adreno_device;
 struct kgsl_device_private;
@@ -108,58 +99,18 @@
 	struct kgsl_memdesc quad_vertices_restore;
 };
 
-/**
- * struct adreno_context - Adreno GPU draw context
- * @id: Unique integer ID of the context
- * @timestamp: Last issued context-specific timestamp
- * @internal_timestamp: Global timestamp of the last issued command
- * @state: Current state of the context
- * @flags: Bitfield controlling behavior of the context
- * @type: Context type (GL, CL, RS)
- * @mutex: Mutex to protect the cmdqueue
- * @pagetable: Pointer to the GPU pagetable for the context
- * @gpustate: Pointer to the GPU scratch memory for context save/restore
- * @reg_restore: Command buffer for restoring context registers
- * @shader_save: Command buffer for saving shaders
- * @shader_restore: Command buffer to restore shaders
- * @context_gmem_shadow: GMEM shadow structure for save/restore
- * @reg_save: A2XX command buffer to save context registers
- * @shader_fixup: A2XX command buffer to "fix" shaders on restore
- * @chicken_restore: A2XX command buffer to "fix" register restore
- * @bin_base_offset: Saved value of the A2XX BIN_BASE_OFFSET register
- * @regconstant_save: A3XX command buffer to save some registers
- * @constant_retore: A3XX command buffer to restore some registers
- * @hslqcontrol_restore: A3XX command buffer to restore HSLSQ registers
- * @save_fixup: A3XX command buffer to "fix" register save
- * @restore_fixup: A3XX cmmand buffer to restore register save fixes
- * @shader_load_commands: A3XX GPU memory descriptor for shader load IB
- * @shader_save_commands: A3XX GPU memory descriptor for shader save IB
- * @constantr_save_commands: A3XX GPU memory descriptor for constant save IB
- * @constant_load_commands: A3XX GPU memory descriptor for constant load IB
- * @cond_execs: A3XX GPU memory descriptor for conditional exec IB
- * @hlsq_restore_commands: A3XX GPU memory descriptor for HLSQ restore IB
- * @cmdqueue: Queue of command batches waiting to be dispatched for this context
- * @cmdqueue_head: Head of the cmdqueue queue
- * @cmdqueue_tail: Tail of the cmdqueue queue
- * @pending: Priority list node for the dispatcher list of pending contexts
- * @wq: Workqueue structure for contexts to sleep pending room in the queue
- * @waiting: Workqueue structure for contexts waiting for a timestamp or event
- * @queued: Number of commands queued in the cmdqueue
- */
 struct adreno_context {
 	struct kgsl_context base;
 	unsigned int ib_gpu_time_used;
 	unsigned int timestamp;
-	unsigned int internal_timestamp;
-	int state;
 	uint32_t flags;
 	unsigned int type;
-	struct mutex mutex;
 	struct kgsl_memdesc gpustate;
 	unsigned int reg_restore[3];
 	unsigned int shader_save[3];
 	unsigned int shader_restore[3];
 
+	/* Information of the GMEM shadow that is created in context create */
 	struct gmem_shadow_t context_gmem_shadow;
 
 	/* A2XX specific items */
@@ -180,44 +131,23 @@
 	struct kgsl_memdesc constant_load_commands[3];
 	struct kgsl_memdesc cond_execs[4];
 	struct kgsl_memdesc hlsqcontrol_restore_commands[1];
-
-	/* Dispatcher */
-	struct kgsl_cmdbatch *cmdqueue[ADRENO_CONTEXT_CMDQUEUE_SIZE];
-	int cmdqueue_head;
-	int cmdqueue_tail;
-
-	struct plist_node pending;
-	wait_queue_head_t wq;
-	wait_queue_head_t waiting;
-
-	int queued;
 };
 
 
 struct kgsl_context *adreno_drawctxt_create(struct kgsl_device_private *,
 			uint32_t *flags);
 
-int adreno_drawctxt_detach(struct kgsl_context *context);
+void adreno_drawctxt_detach(struct kgsl_context *context);
 
 void adreno_drawctxt_destroy(struct kgsl_context *context);
 
-void adreno_drawctxt_sched(struct kgsl_device *device,
-		struct kgsl_context *context);
-
-int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
+void adreno_drawctxt_switch(struct adreno_device *adreno_dev,
 				struct adreno_context *drawctxt,
 				unsigned int flags);
 void adreno_drawctxt_set_bin_base_offset(struct kgsl_device *device,
 					struct kgsl_context *context,
 					unsigned int offset);
 
-int adreno_drawctxt_wait(struct adreno_device *adreno_dev,
-		struct kgsl_context *context,
-		uint32_t timestamp, unsigned int timeout);
-
-void adreno_drawctxt_invalidate(struct kgsl_device *device,
-		struct kgsl_context *context);
-
 /* GPU context switch helper functions */
 
 void build_quad_vtxbuff(struct adreno_context *drawctxt,
diff --git a/drivers/gpu/msm/adreno_pm4types.h b/drivers/gpu/msm/adreno_pm4types.h
index f449870..d1e2b43 100644
--- a/drivers/gpu/msm/adreno_pm4types.h
+++ b/drivers/gpu/msm/adreno_pm4types.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -177,6 +177,8 @@
 /* Load a buffer with pre-fetch enabled */
 #define CP_INDIRECT_BUFFER_PFE 0x3F
 
+#define CP_EXEC_CL 0x31
+
 #define CP_LOADSTATE_DSTOFFSET_SHIFT 0x00000000
 #define CP_LOADSTATE_STATESRC_SHIFT 0x00000010
 #define CP_LOADSTATE_STATEBLOCKID_SHIFT 0x00000013
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 8fb2830..32dbd51 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -22,7 +22,6 @@
 #include "adreno_ringbuffer.h"
 #include "kgsl_cffdump.h"
 #include "kgsl_pwrctrl.h"
-#include "adreno_trace.h"
 
 #include "a2xx_reg.h"
 #include "a3xx_reg.h"
@@ -396,8 +395,8 @@
 
 int adreno_dump(struct kgsl_device *device, int manual)
 {
-	unsigned int cp_ib1_base;
-	unsigned int cp_ib2_base;
+	unsigned int cp_ib1_base, cp_ib1_bufsz;
+	unsigned int cp_ib2_base, cp_ib2_bufsz;
 	phys_addr_t pt_base, cur_pt_base;
 	unsigned int cp_rb_base, cp_rb_ctrl, rb_count;
 	unsigned int cp_rb_wptr, cp_rb_rptr;
@@ -410,6 +409,7 @@
 	unsigned int ts_processed = 0xdeaddead;
 	struct kgsl_context *context;
 	unsigned int context_id;
+	unsigned int rbbm_status;
 
 	static struct ib_list ib_list;
 
@@ -419,10 +419,16 @@
 
 	mb();
 
-	msm_clk_dump_debug_info();
+	if (device->pm_dump_enable) {
+		msm_clk_dump_debug_info();
 
-	if (adreno_dev->gpudev->postmortem_dump)
-		adreno_dev->gpudev->postmortem_dump(adreno_dev);
+		if (adreno_dev->gpudev->postmortem_dump)
+			adreno_dev->gpudev->postmortem_dump(adreno_dev);
+	}
+
+	kgsl_regread(device,
+			adreno_getreg(adreno_dev, ADRENO_REG_RBBM_STATUS),
+			&rbbm_status);
 
 	pt_base = kgsl_mmu_get_current_ptbase(&device->mmu);
 	cur_pt_base = pt_base;
@@ -444,8 +450,26 @@
 		adreno_getreg(adreno_dev, ADRENO_REG_CP_IB1_BASE),
 		&cp_ib1_base);
 	kgsl_regread(device,
+		adreno_getreg(adreno_dev, ADRENO_REG_CP_IB1_BUFSZ),
+		&cp_ib1_bufsz);
+	kgsl_regread(device,
 		adreno_getreg(adreno_dev, ADRENO_REG_CP_IB2_BASE),
 		&cp_ib2_base);
+	kgsl_regread(device,
+		adreno_getreg(adreno_dev, ADRENO_REG_CP_IB2_BUFSZ),
+		&cp_ib2_bufsz);
+
+	/* If postmortem dump is not enabled, dump minimal set and return */
+	if (!device->pm_dump_enable) {
+
+		KGSL_LOG_DUMP(device,
+			"STATUS %08X | IB1:%08X/%08X | IB2: %08X/%08X"
+			" | RPTR: %04X | WPTR: %04X\n",
+			rbbm_status,  cp_ib1_base, cp_ib1_bufsz, cp_ib2_base,
+			cp_ib2_bufsz, cp_rb_rptr, cp_rb_wptr);
+
+		return 0;
+	}
 
 	kgsl_sharedmem_readl(&device->memstore,
 			(unsigned int *) &context_id,
@@ -620,9 +644,5 @@
 error_vfree:
 	vfree(rb_copy);
 end:
-	/* Restart the dispatcher after a manually triggered dump */
-	if (manual)
-		adreno_dispatcher_start(adreno_dev);
-
 	return result;
 }
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 1ad90fd..ceff923 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -67,8 +67,11 @@
 	unsigned long wait_time;
 	unsigned long wait_timeout = msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
 	unsigned long wait_time_part;
+	unsigned int prev_reg_val[FT_DETECT_REGS_COUNT];
 	unsigned int rptr;
 
+	memset(prev_reg_val, 0, sizeof(prev_reg_val));
+
 	/* if wptr ahead, fill the remaining with NOPs */
 	if (wptr_ahead) {
 		/* -1 for header */
@@ -102,13 +105,43 @@
 		if (freecmds == 0 || freecmds > numcmds)
 			break;
 
+		/* Dont wait for timeout, detect hang faster.
+		 */
+		if (time_after(jiffies, wait_time_part)) {
+			wait_time_part = jiffies +
+				msecs_to_jiffies(KGSL_TIMEOUT_PART);
+			if ((adreno_ft_detect(rb->device,
+						prev_reg_val))){
+				KGSL_DRV_ERR(rb->device,
+				"Hang detected while waiting for freespace in"
+				"ringbuffer rptr: 0x%x, wptr: 0x%x\n",
+				rptr, rb->wptr);
+				goto err;
+			}
+		}
+
 		if (time_after(jiffies, wait_time)) {
 			KGSL_DRV_ERR(rb->device,
 			"Timed out while waiting for freespace in ringbuffer "
 			"rptr: 0x%x, wptr: 0x%x\n", rptr, rb->wptr);
-			return -ETIMEDOUT;
+			goto err;
 		}
 
+		continue;
+
+err:
+		if (!adreno_dump_and_exec_ft(rb->device)) {
+			if (context && context->flags & CTXT_FLAGS_GPU_HANG) {
+				KGSL_CTXT_WARN(rb->device,
+				"Context %p caused a gpu hang. Will not accept commands for context %d\n",
+				context, context->base.id);
+				return -EDEADLK;
+			}
+			wait_time = jiffies + wait_timeout;
+		} else {
+			/* GPU is hung and fault tolerance failed */
+			BUG();
+		}
 	}
 	return 0;
 }
@@ -147,8 +180,7 @@
 	if (!ret) {
 		ptr = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
 		rb->wptr += numcmds;
-	} else
-		ptr = ERR_PTR(ret);
+	}
 
 	return ptr;
 }
@@ -315,6 +347,7 @@
 int _ringbuffer_start_common(struct adreno_ringbuffer *rb)
 {
 	int status;
+	/*cp_rb_cntl_u cp_rb_cntl; */
 	union reg_cp_rb_cntl cp_rb_cntl;
 	unsigned int rb_cntl;
 	struct kgsl_device *device = rb->device;
@@ -535,17 +568,18 @@
 
 static int
 adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
-				struct adreno_context *drawctxt,
+				struct adreno_context *context,
 				unsigned int flags, unsigned int *cmds,
-				int sizedwords, uint32_t timestamp)
+				int sizedwords)
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
 	unsigned int *ringcmds;
 	unsigned int total_sizedwords = sizedwords;
 	unsigned int i;
 	unsigned int rcmd_gpu;
-	unsigned int context_id;
+	unsigned int context_id = KGSL_MEMSTORE_GLOBAL;
 	unsigned int gpuaddr = rb->device->memstore.gpuaddr;
+	unsigned int timestamp;
 	bool profile_ready;
 
 	/*
@@ -556,23 +590,19 @@
 	 * the _addcmds call since it is allocating additional ringbuffer
 	 * command space.
 	 */
-	profile_ready = !adreno_is_a2xx(adreno_dev) &&
+	profile_ready = !adreno_is_a2xx(adreno_dev) && context &&
 		adreno_profile_assignments_ready(&adreno_dev->profile) &&
 		!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE);
 
-	/* The global timestamp always needs to be incremented */
-	rb->global_ts++;
-
-	/* If this is a internal IB, use the global timestamp for it */
-	if (!drawctxt || (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
-		timestamp = rb->global_ts;
-		context_id = KGSL_MEMSTORE_GLOBAL;
-	} else {
-		context_id = drawctxt->base.id;
-	}
-
-	if (drawctxt)
-		drawctxt->internal_timestamp = rb->global_ts;
+	/*
+	 * if the context was not created with per context timestamp
+	 * support, we must use the global timestamp since issueibcmds
+	 * will be returning that one, or if an internal issue then
+	 * use global timestamp.
+	 */
+	if ((context && (context->flags & CTXT_FLAGS_PER_CONTEXT_TS)) &&
+		!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE))
+		context_id = context->base.id;
 
 	/* reserve space to temporarily turn off protected mode
 	*  error checking if needed
@@ -583,8 +613,13 @@
 	/* internal ib command identifier for the ringbuffer */
 	total_sizedwords += (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE) ? 2 : 0;
 
-	/* Add two dwords for the CP_INTERRUPT */
-	total_sizedwords += drawctxt ? 2 : 0;
+	/* Add CP_COND_EXEC commands to generate CP_INTERRUPT */
+	total_sizedwords += context ? 13 : 0;
+
+	if ((context) && (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) &&
+		(flags & (KGSL_CMD_FLAGS_INTERNAL_ISSUE |
+		KGSL_CMD_FLAGS_GET_INT)))
+			total_sizedwords += 2;
 
 	if (adreno_is_a3xx(adreno_dev))
 		total_sizedwords += 7;
@@ -592,31 +627,29 @@
 	if (adreno_is_a2xx(adreno_dev))
 		total_sizedwords += 2; /* CP_WAIT_FOR_IDLE */
 
+	total_sizedwords += 2; /* scratchpad ts for fault tolerance */
 	total_sizedwords += 3; /* sop timestamp */
 	total_sizedwords += 4; /* eop timestamp */
 
-	if (adreno_is_a20x(adreno_dev))
-		total_sizedwords += 2; /* CACHE_FLUSH */
-
-	if (drawctxt) {
+	if (KGSL_MEMSTORE_GLOBAL != context_id)
 		total_sizedwords += 3; /* global timestamp without cache
 					* flush for non-zero context */
-	}
 
 	if (adreno_is_a20x(adreno_dev))
 		total_sizedwords += 2; /* CACHE_FLUSH */
 
-	if (flags & KGSL_CMD_FLAGS_WFI)
-		total_sizedwords += 2; /* WFI */
+	if (flags & KGSL_CMD_FLAGS_EOF)
+		total_sizedwords += 2;
 
 	if (profile_ready)
 		total_sizedwords += 6;   /* space for pre_ib and post_ib */
 
-	ringcmds = adreno_ringbuffer_allocspace(rb, drawctxt, total_sizedwords);
+	/* Add space for the power on shader fixup if we need it */
+	if (flags & KGSL_CMD_FLAGS_PWRON_FIXUP)
+		total_sizedwords += 5;
 
-	if (IS_ERR(ringcmds))
-		return PTR_ERR(ringcmds);
-	if (ringcmds == NULL)
+	ringcmds = adreno_ringbuffer_allocspace(rb, context, total_sizedwords);
+	if (!ringcmds)
 		return -ENOSPC;
 
 	rcmd_gpu = rb->buffer_desc.gpuaddr
@@ -631,11 +664,38 @@
 				KGSL_CMD_INTERNAL_IDENTIFIER);
 	}
 
+	if (flags & KGSL_CMD_FLAGS_PWRON_FIXUP) {
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, cp_nop_packet(1));
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+				KGSL_PWRON_FIXUP_IDENTIFIER);
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+			CP_HDR_INDIRECT_BUFFER_PFD);
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+			adreno_dev->pwron_fixup.gpuaddr);
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+			adreno_dev->pwron_fixup_dwords);
+	}
+
 	/* Add any IB required for profiling if it is enabled */
 	if (profile_ready)
-		adreno_profile_preib_processing(rb->device, drawctxt->base.id,
+		adreno_profile_preib_processing(rb->device, context->base.id,
 				&flags, &ringcmds, &rcmd_gpu);
 
+	/* always increment the global timestamp. once. */
+	rb->global_ts++;
+
+	if (KGSL_MEMSTORE_GLOBAL != context_id)
+		timestamp = context->timestamp;
+	else
+		timestamp = rb->global_ts;
+
+	/* scratchpad ts for fault tolerance */
+	GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+		cp_type0_packet(adreno_getreg(adreno_dev,
+			ADRENO_REG_CP_TIMESTAMP), 1));
+	GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+			rb->global_ts);
+
 	/* start-of-pipeline timestamp */
 	GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
 			cp_type3_packet(CP_MEM_WRITE, 2));
@@ -705,7 +765,7 @@
 		KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
 	GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, timestamp);
 
-	if (drawctxt) {
+	if (KGSL_MEMSTORE_GLOBAL != context_id) {
 		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
 			cp_type3_packet(CP_MEM_WRITE, 2));
 		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
@@ -721,13 +781,56 @@
 		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, CACHE_FLUSH);
 	}
 
-	if (drawctxt || (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
+	if (context) {
+		/* Conditional execution based on memory values */
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+			cp_type3_packet(CP_COND_EXEC, 4));
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
+			KGSL_MEMSTORE_OFFSET(
+				context_id, ts_cmp_enable)) >> 2);
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
+			KGSL_MEMSTORE_OFFSET(
+				context_id, ref_wait_ts)) >> 2);
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, timestamp);
+		/* # of conditional command DWORDs */
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 8);
+
+		/* Clear the ts_cmp_enable for the context */
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+			cp_type3_packet(CP_MEM_WRITE, 2));
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, gpuaddr +
+			KGSL_MEMSTORE_OFFSET(
+				context_id, ts_cmp_enable));
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0x0);
+
+		/* Clear the ts_cmp_enable for the global timestamp */
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+			cp_type3_packet(CP_MEM_WRITE, 2));
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, gpuaddr +
+			KGSL_MEMSTORE_OFFSET(
+				KGSL_MEMSTORE_GLOBAL, ts_cmp_enable));
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0x0);
+
+		/* Trigger the interrupt */
 		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
 			cp_type3_packet(CP_INTERRUPT, 1));
 		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
 				CP_INT_CNTL__RB_INT_MASK);
 	}
 
+	/*
+	 * If per context timestamps are enabled and any of the kgsl
+	 * internal commands want INT to be generated trigger the INT
+	*/
+	if ((context) && (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) &&
+		(flags & (KGSL_CMD_FLAGS_INTERNAL_ISSUE |
+		KGSL_CMD_FLAGS_GET_INT))) {
+			GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+				cp_type3_packet(CP_INTERRUPT, 1));
+			GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+				CP_INT_CNTL__RB_INT_MASK);
+	}
+
 	if (adreno_is_a3xx(adreno_dev)) {
 		/* Dummy set-constant to trigger context rollover */
 		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
@@ -737,10 +840,10 @@
 		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0);
 	}
 
-	if (flags & KGSL_CMD_FLAGS_WFI) {
+	if (flags & KGSL_CMD_FLAGS_EOF) {
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, cp_nop_packet(1));
 		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
-			cp_type3_packet(CP_WAIT_FOR_IDLE, 1));
-		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0x00000000);
+				KGSL_END_OF_FRAME_IDENTIFIER);
 	}
 
 	adreno_ringbuffer_submit(rb);
@@ -758,10 +861,14 @@
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
 
+	if (device->state & KGSL_STATE_HUNG)
+		return kgsl_readtimestamp(device, KGSL_MEMSTORE_GLOBAL,
+					KGSL_TIMESTAMP_RETIRED);
+
 	flags |= KGSL_CMD_FLAGS_INTERNAL_ISSUE;
 
 	return adreno_ringbuffer_addcmds(rb, drawctxt, flags, cmds,
-		sizedwords, 0);
+							sizedwords);
 }
 
 static bool _parse_ibs(struct kgsl_device_private *dev_priv, uint gpuaddr,
@@ -954,90 +1061,39 @@
 	return ret;
 }
 
-/**
- * _ringbuffer_verify_ib() - parse an IB and verify that it is correct
- * @dev_priv: Pointer to the process struct
- * @ibdesc: Pointer to the IB descriptor
- *
- * This function only gets called if debugging is enabled  - it walks the IB and
- * does additional level parsing and verification above and beyond what KGSL
- * core does
- */
-static inline bool _ringbuffer_verify_ib(struct kgsl_device_private *dev_priv,
-		struct kgsl_ibdesc *ibdesc)
-{
-	struct kgsl_device *device = dev_priv->device;
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-
-	/* Check that the size of the IBs is under the allowable limit */
-	if (ibdesc->sizedwords == 0 || ibdesc->sizedwords > 0xFFFFF) {
-		KGSL_DRV_ERR(device, "Invalid IB size 0x%X\n",
-				ibdesc->sizedwords);
-		return false;
-	}
-
-	if (unlikely(adreno_dev->ib_check_level >= 1) &&
-		!_parse_ibs(dev_priv, ibdesc->gpuaddr, ibdesc->sizedwords)) {
-		KGSL_DRV_ERR(device, "Could not verify the IBs\n");
-		return false;
-	}
-
-	return true;
-}
-
 int
 adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
 				struct kgsl_context *context,
-				struct kgsl_cmdbatch *cmdbatch,
-				uint32_t *timestamp)
+				struct kgsl_ibdesc *ibdesc,
+				unsigned int numibs,
+				uint32_t *timestamp,
+				unsigned int flags)
 {
 	struct kgsl_device *device = dev_priv->device;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
-	int i, ret;
-
-	if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
-		return -EDEADLK;
-
-	/* Verify the IBs before they get queued */
-
-	for (i = 0; i < cmdbatch->ibcount; i++) {
-		if (!_ringbuffer_verify_ib(dev_priv, &cmdbatch->ibdesc[i]))
-			return -EINVAL;
-	}
-
-	/* Queue the command in the ringbuffer */
-	ret = adreno_dispatcher_queue_cmd(adreno_dev, drawctxt, cmdbatch,
-		timestamp);
-
-	if (ret)
-		KGSL_DRV_ERR(device,
-			"adreno_dispatcher_queue_cmd returned %d\n", ret);
-
-	return ret;
-}
-
-/* adreno_rindbuffer_submitcmd - submit userspace IBs to the GPU */
-int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
-		struct kgsl_cmdbatch *cmdbatch)
-{
-	struct kgsl_device *device = &adreno_dev->dev;
-	struct kgsl_ibdesc *ibdesc;
-	unsigned int numibs;
-	unsigned int *link;
+	unsigned int *link = 0;
 	unsigned int *cmds;
 	unsigned int i;
-	struct kgsl_context *context;
-	struct adreno_context *drawctxt;
+	struct adreno_context *drawctxt = NULL;
 	unsigned int start_index = 0;
-	int flags = KGSL_CMD_FLAGS_NONE;
 	int ret;
 
-	context = cmdbatch->context;
+	if (device->state & KGSL_STATE_HUNG) {
+		ret = -EBUSY;
+		goto done;
+	}
+
+	if (!(adreno_dev->ringbuffer.flags & KGSL_FLAGS_STARTED) ||
+	      context == NULL || ibdesc == 0 || numibs == 0) {
+		ret = -EINVAL;
+		goto done;
+	}
 	drawctxt = ADRENO_CONTEXT(context);
 
-	ibdesc = cmdbatch->ibdesc;
-	numibs = cmdbatch->ibcount;
+	if (drawctxt->flags & CTXT_FLAGS_GPU_HANG) {
+		ret = -EDEADLK;
+		goto done;
+	}
 
 	/* process any profiling results that are available into the log_buf */
 	adreno_profile_process_results(device);
@@ -1046,21 +1102,17 @@
 	commands are stored in the first node of the IB chain. We can skip that
 	if a context switch hasn't occured */
 
-	if ((drawctxt->flags & CTXT_FLAGS_PREAMBLE) &&
-		!test_bit(CMDBATCH_FLAG_FORCE_PREAMBLE, &cmdbatch->priv) &&
-		(adreno_dev->drawctxt_active == drawctxt))
+	if (drawctxt->flags & CTXT_FLAGS_PREAMBLE &&
+		adreno_dev->drawctxt_active == drawctxt)
 		start_index = 1;
 
-	/*
-	 * In skip mode don't issue the draw IBs but keep all the other
-	 * accoutrements of a submision (including the interrupt) to keep
-	 * the accounting sane. Set start_index and numibs to 0 to just
-	 * generate the start and end markers and skip everything else
-	 */
-
-	if (test_bit(CMDBATCH_FLAG_SKIP, &cmdbatch->priv)) {
-		start_index = 0;
-		numibs = 0;
+	if (drawctxt->flags & CTXT_FLAGS_SKIP_EOF) {
+		if (flags & KGSL_CMD_FLAGS_EOF)
+			drawctxt->flags &= ~CTXT_FLAGS_SKIP_EOF;
+		if (start_index)
+			numibs = 1;
+		else
+			numibs = 0;
 	}
 
 	cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 4),
@@ -1081,17 +1133,19 @@
 		*cmds++ = ibdesc[0].sizedwords;
 	}
 	for (i = start_index; i < numibs; i++) {
+		if (unlikely(adreno_dev->ib_check_level >= 1 &&
+		    !_parse_ibs(dev_priv, ibdesc[i].gpuaddr,
+				ibdesc[i].sizedwords))) {
+			ret = -EINVAL;
+			goto done;
+		}
 
-		/*
-		 * Skip 0 sized IBs - these are presumed to have been removed
-		 * from consideration by the FT policy
-		 */
+		if (ibdesc[i].sizedwords == 0) {
+			ret = -EINVAL;
+			goto done;
+		}
 
-		if (ibdesc[i].sizedwords == 0)
-			*cmds++ = cp_nop_packet(2);
-		else
-			*cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
-
+		*cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
 		*cmds++ = ibdesc[i].gpuaddr;
 		*cmds++ = ibdesc[i].sizedwords;
 	}
@@ -1099,47 +1153,257 @@
 	*cmds++ = cp_nop_packet(1);
 	*cmds++ = KGSL_END_OF_IB_IDENTIFIER;
 
-	ret = kgsl_setstate(&device->mmu, context->id,
+	kgsl_setstate(&device->mmu, context->id,
 		      kgsl_mmu_pt_get_flags(device->mmu.hwpagetable,
 					device->id));
 
-	if (ret)
-		goto done;
+	adreno_drawctxt_switch(adreno_dev, drawctxt, flags);
 
-	ret = adreno_drawctxt_switch(adreno_dev, drawctxt, cmdbatch->flags);
+	if (test_and_clear_bit(ADRENO_DEVICE_PWRON, &adreno_dev->priv) &&
+		test_bit(ADRENO_DEVICE_PWRON_FIXUP, &adreno_dev->priv))
+			flags |= KGSL_CMD_FLAGS_PWRON_FIXUP;
 
-	/*
-	 * In the unlikely event of an error in the drawctxt switch,
-	 * treat it like a hang
-	 */
-	if (ret)
-		goto done;
-
-	if (test_bit(CMDBATCH_FLAG_WFI, &cmdbatch->priv))
-		flags = KGSL_CMD_FLAGS_WFI;
+	if (drawctxt->flags & CTXT_FLAGS_USER_GENERATED_TS) {
+		if (timestamp_cmp(drawctxt->timestamp, *timestamp) >= 0) {
+			KGSL_DRV_ERR(device,
+				"Invalid user generated ts <%d:0x%x>, "
+				"less than last issued ts <%d:0x%x>\n",
+				context->id, *timestamp, context->id,
+				drawctxt->timestamp);
+			return -ERANGE;
+		}
+		drawctxt->timestamp = *timestamp;
+	} else
+		drawctxt->timestamp++;
 
 	ret = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
 					drawctxt,
 					flags,
-					&link[0], (cmds - link),
-					cmdbatch->timestamp);
-
-#ifdef CONFIG_MSM_KGSL_CFF_DUMP
+					&link[0], (cmds - link));
 	if (ret)
 		goto done;
+
+	if (drawctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
+		*timestamp = drawctxt->timestamp;
+	else
+		*timestamp = adreno_dev->ringbuffer.global_ts;
+
+#ifdef CONFIG_MSM_KGSL_CFF_DUMP
 	/*
 	 * insert wait for idle after every IB1
 	 * this is conservative but works reliably and is ok
 	 * even for performance simulations
 	 */
-	ret = adreno_idle(device);
+	adreno_idle(device);
 #endif
 
+	/*
+	 * If context hung and recovered then return error so that the
+	 * application may handle it
+	 */
+	if (drawctxt->flags & CTXT_FLAGS_GPU_HANG_FT) {
+		drawctxt->flags &= ~CTXT_FLAGS_GPU_HANG_FT;
+		ret = -EPROTO;
+	} else
+		ret = 0;
+
 done:
-	kgsl_trace_issueibcmds(device, context->id, cmdbatch,
-		cmdbatch->timestamp, cmdbatch->flags, ret,
-		drawctxt->type);
+	device->pwrctrl.irq_last = 0;
+	kgsl_trace_issueibcmds(device, context ? context->id : 0, ibdesc,
+		numibs, *timestamp, flags, ret,
+		drawctxt ? drawctxt->type : 0);
 
 	kfree(link);
 	return ret;
 }
+
+static void _turn_preamble_on_for_ib_seq(struct adreno_ringbuffer *rb,
+				unsigned int rb_rptr)
+{
+	unsigned int temp_rb_rptr = rb_rptr;
+	unsigned int size = rb->buffer_desc.size;
+	unsigned int val[2];
+	int i = 0;
+	bool check = false;
+	bool cmd_start = false;
+
+	/* Go till the start of the ib sequence and turn on preamble */
+	while (temp_rb_rptr / sizeof(unsigned int) != rb->wptr) {
+		kgsl_sharedmem_readl(&rb->buffer_desc, &val[i], temp_rb_rptr);
+		if (check && KGSL_START_OF_IB_IDENTIFIER == val[i]) {
+			/* decrement i */
+			i = (i + 1) % 2;
+			if (val[i] == cp_nop_packet(4)) {
+				temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
+						temp_rb_rptr, size);
+				kgsl_sharedmem_writel(rb->device,
+					&rb->buffer_desc,
+					temp_rb_rptr, cp_nop_packet(1));
+			}
+			KGSL_FT_INFO(rb->device,
+			"Turned preamble on at offset 0x%x\n",
+			temp_rb_rptr / 4);
+			break;
+		}
+		/* If you reach beginning of next command sequence then exit
+		 * First command encountered is the current one so don't break
+		 * on that. */
+		if (KGSL_CMD_IDENTIFIER == val[i]) {
+			if (cmd_start)
+				break;
+			cmd_start = true;
+		}
+
+		i = (i + 1) % 2;
+		if (1 == i)
+			check = true;
+		temp_rb_rptr = adreno_ringbuffer_inc_wrapped(temp_rb_rptr,
+								size);
+	}
+}
+
+void adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
+				struct adreno_ft_data *ft_data)
+{
+	struct kgsl_device *device = rb->device;
+	unsigned int rb_rptr = ft_data->start_of_replay_cmds;
+	unsigned int good_rb_idx = 0, bad_rb_idx = 0, temp_rb_idx = 0;
+	unsigned int last_good_cmd_end_idx = 0, last_bad_cmd_end_idx = 0;
+	unsigned int cmd_start_idx = 0;
+	unsigned int val1 = 0;
+	int copy_rb_contents = 0;
+	unsigned int temp_rb_rptr;
+	struct kgsl_context *k_ctxt;
+	struct adreno_context *a_ctxt;
+	unsigned int size = rb->buffer_desc.size;
+	unsigned int *temp_rb_buffer = ft_data->rb_buffer;
+	int *rb_size = &ft_data->rb_size;
+	unsigned int *bad_rb_buffer = ft_data->bad_rb_buffer;
+	int *bad_rb_size = &ft_data->bad_rb_size;
+	unsigned int *good_rb_buffer = ft_data->good_rb_buffer;
+	int *good_rb_size = &ft_data->good_rb_size;
+
+	/*
+	 * If the start index from where commands need to be copied is invalid
+	 * then no need to save off any commands
+	 */
+	if (0xFFFFFFFF == ft_data->start_of_replay_cmds)
+		return;
+
+	k_ctxt = kgsl_context_get(device, ft_data->context_id);
+
+	if (k_ctxt) {
+		a_ctxt = ADRENO_CONTEXT(k_ctxt);
+		if (a_ctxt->flags & CTXT_FLAGS_PREAMBLE)
+			_turn_preamble_on_for_ib_seq(rb, rb_rptr);
+		kgsl_context_put(k_ctxt);
+	}
+	k_ctxt = NULL;
+
+	/* Walk the rb from the context switch. Omit any commands
+	 * for an invalid context. */
+	while ((rb_rptr / sizeof(unsigned int)) != rb->wptr) {
+		kgsl_sharedmem_readl(&rb->buffer_desc, &val1, rb_rptr);
+
+		if (KGSL_CMD_IDENTIFIER == val1) {
+			/* Start is the NOP dword that comes before
+			 * KGSL_CMD_IDENTIFIER */
+			cmd_start_idx = temp_rb_idx - 1;
+			if ((copy_rb_contents) && (good_rb_idx))
+				last_good_cmd_end_idx = good_rb_idx - 1;
+			if ((!copy_rb_contents) && (bad_rb_idx))
+				last_bad_cmd_end_idx = bad_rb_idx - 1;
+		}
+
+		/* check for context switch indicator */
+		if (val1 == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
+			unsigned int temp_idx, val2;
+			/* increment by 3 to get to the context_id */
+			temp_rb_rptr = rb_rptr + (3 * sizeof(unsigned int)) %
+					size;
+			kgsl_sharedmem_readl(&rb->buffer_desc, &val2,
+						temp_rb_rptr);
+
+			/* if context switches to a context that did not cause
+			 * hang then start saving the rb contents as those
+			 * commands can be executed */
+			k_ctxt = kgsl_context_get(rb->device, val2);
+
+			if (k_ctxt) {
+				a_ctxt = ADRENO_CONTEXT(k_ctxt);
+
+			/* If we are changing to a good context and were not
+			 * copying commands then copy over commands to the good
+			 * context */
+			if (!copy_rb_contents && ((k_ctxt &&
+				!(a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) ||
+				!k_ctxt)) {
+				for (temp_idx = cmd_start_idx;
+					temp_idx < temp_rb_idx;
+					temp_idx++)
+					good_rb_buffer[good_rb_idx++] =
+						temp_rb_buffer[temp_idx];
+				ft_data->last_valid_ctx_id = val2;
+				copy_rb_contents = 1;
+				/* remove the good commands from bad buffer */
+				bad_rb_idx = last_bad_cmd_end_idx;
+			} else if (copy_rb_contents && k_ctxt &&
+				(a_ctxt->flags & CTXT_FLAGS_GPU_HANG)) {
+
+				/* If we are changing back to a bad context
+				 * from good ctxt and were not copying commands
+				 * to bad ctxt then copy over commands to
+				 * the bad context */
+				for (temp_idx = cmd_start_idx;
+					temp_idx < temp_rb_idx;
+					temp_idx++)
+					bad_rb_buffer[bad_rb_idx++] =
+						temp_rb_buffer[temp_idx];
+				/* If we are changing to bad context then
+				 * remove the dwords we copied for this
+				 * sequence from the good buffer */
+				good_rb_idx = last_good_cmd_end_idx;
+				copy_rb_contents = 0;
+			}
+			}
+			kgsl_context_put(k_ctxt);
+		}
+
+		if (copy_rb_contents)
+			good_rb_buffer[good_rb_idx++] = val1;
+		else
+			bad_rb_buffer[bad_rb_idx++] = val1;
+
+		/* Copy both good and bad commands to temp buffer */
+		temp_rb_buffer[temp_rb_idx++] = val1;
+
+		rb_rptr = adreno_ringbuffer_inc_wrapped(rb_rptr, size);
+	}
+	*good_rb_size = good_rb_idx;
+	*bad_rb_size = bad_rb_idx;
+	*rb_size = temp_rb_idx;
+}
+
+void
+adreno_ringbuffer_restore(struct adreno_ringbuffer *rb, unsigned int *rb_buff,
+			int num_rb_contents)
+{
+	int i;
+	unsigned int *ringcmds;
+	unsigned int rcmd_gpu;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
+
+	if (!num_rb_contents)
+		return;
+
+	if (num_rb_contents > (rb->buffer_desc.size - rb->wptr)) {
+		adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_RPTR, 0);
+		BUG_ON(num_rb_contents > rb->buffer_desc.size);
+	}
+	ringcmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
+	rcmd_gpu = rb->buffer_desc.gpuaddr + sizeof(unsigned int) * rb->wptr;
+	for (i = 0; i < num_rb_contents; i++)
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, rb_buff[i]);
+	rb->wptr += num_rb_contents;
+	adreno_ringbuffer_submit(rb);
+}
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index 3aa0101..9634e32 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -27,6 +27,7 @@
 
 struct kgsl_device;
 struct kgsl_device_private;
+struct adreno_ft_data;
 
 #define GSL_RB_MEMPTRS_SCRATCH_COUNT	 8
 struct kgsl_rbmemptrs {
@@ -98,11 +99,10 @@
 
 int adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
 				struct kgsl_context *context,
-				struct kgsl_cmdbatch *cmdbatch,
-				uint32_t *timestamp);
-
-int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
-		struct kgsl_cmdbatch *cmdbatch);
+				struct kgsl_ibdesc *ibdesc,
+				unsigned int numibs,
+				uint32_t *timestamp,
+				unsigned int flags);
 
 int adreno_ringbuffer_init(struct kgsl_device *device);
 
@@ -124,6 +124,13 @@
 
 void kgsl_cp_intrcallback(struct kgsl_device *device);
 
+void adreno_ringbuffer_extract(struct adreno_ringbuffer *rb,
+				struct adreno_ft_data *ft_data);
+
+void
+adreno_ringbuffer_restore(struct adreno_ringbuffer *rb, unsigned int *rb_buff,
+			int num_rb_contents);
+
 unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb,
 						struct adreno_context *context,
 						unsigned int numcmds);
diff --git a/drivers/gpu/msm/adreno_trace.h b/drivers/gpu/msm/adreno_trace.h
deleted file mode 100644
index 6079b61..0000000
--- a/drivers/gpu/msm/adreno_trace.h
+++ /dev/null
@@ -1,270 +0,0 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#if !defined(_ADRENO_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
-#define _ADRENO_TRACE_H
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM kgsl
-#undef TRACE_INCLUDE_PATH
-#define TRACE_INCLUDE_PATH .
-#define TRACE_INCLUDE_FILE adreno_trace
-
-#include <linux/tracepoint.h>
-
-TRACE_EVENT(adreno_cmdbatch_queued,
-	TP_PROTO(struct kgsl_cmdbatch *cmdbatch, unsigned int queued),
-	TP_ARGS(cmdbatch, queued),
-	TP_STRUCT__entry(
-		__field(unsigned int, id)
-		__field(unsigned int, timestamp)
-		__field(unsigned int, queued)
-		__field(unsigned int, flags)
-	),
-	TP_fast_assign(
-		__entry->id = cmdbatch->context->id;
-		__entry->timestamp = cmdbatch->timestamp;
-		__entry->queued = queued;
-		__entry->flags = cmdbatch->flags;
-	),
-	TP_printk(
-		"ctx=%u ts=%u queued=%u flags=%s",
-			__entry->id, __entry->timestamp, __entry->queued,
-			__entry->flags ? __print_flags(__entry->flags, "|",
-				{ KGSL_CONTEXT_SYNC, "SYNC" },
-				{ KGSL_CONTEXT_END_OF_FRAME, "EOF" })
-				: "none"
-	)
-);
-
-DECLARE_EVENT_CLASS(adreno_cmdbatch_template,
-	TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight),
-	TP_ARGS(cmdbatch, inflight),
-	TP_STRUCT__entry(
-		__field(unsigned int, id)
-		__field(unsigned int, timestamp)
-		__field(unsigned int, inflight)
-	),
-	TP_fast_assign(
-		__entry->id = cmdbatch->context->id;
-		__entry->timestamp = cmdbatch->timestamp;
-		__entry->inflight = inflight;
-	),
-	TP_printk(
-		"ctx=%u ts=%u inflight=%u",
-			__entry->id, __entry->timestamp,
-			__entry->inflight
-	)
-);
-
-DEFINE_EVENT(adreno_cmdbatch_template, adreno_cmdbatch_submitted,
-	TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight),
-	TP_ARGS(cmdbatch, inflight)
-);
-
-TRACE_EVENT(adreno_cmdbatch_retired,
-	TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight),
-	TP_ARGS(cmdbatch, inflight),
-	TP_STRUCT__entry(
-		__field(unsigned int, id)
-		__field(unsigned int, timestamp)
-		__field(unsigned int, inflight)
-		__field(unsigned int, recovery)
-	),
-	TP_fast_assign(
-		__entry->id = cmdbatch->context->id;
-		__entry->timestamp = cmdbatch->timestamp;
-		__entry->inflight = inflight;
-		__entry->recovery = cmdbatch->fault_recovery;
-	),
-	TP_printk(
-		"ctx=%u ts=%u inflight=%u recovery=%s",
-			__entry->id, __entry->timestamp,
-			__entry->inflight,
-			__entry->recovery ?
-				__print_flags(__entry->recovery, "|",
-				ADRENO_FT_TYPES) : "none"
-	)
-);
-
-TRACE_EVENT(adreno_cmdbatch_fault,
-	TP_PROTO(struct kgsl_cmdbatch *cmdbatch, unsigned int fault),
-	TP_ARGS(cmdbatch, fault),
-	TP_STRUCT__entry(
-		__field(unsigned int, id)
-		__field(unsigned int, timestamp)
-		__field(unsigned int, fault)
-	),
-	TP_fast_assign(
-		__entry->id = cmdbatch->context->id;
-		__entry->timestamp = cmdbatch->timestamp;
-		__entry->fault = fault;
-	),
-	TP_printk(
-		"ctx=%u ts=%u type=%s",
-			__entry->id, __entry->timestamp,
-			__print_symbolic(__entry->fault,
-				{ 0, "none" },
-				{ ADRENO_SOFT_FAULT, "soft" },
-				{ ADRENO_HARD_FAULT, "hard" },
-				{ ADRENO_TIMEOUT_FAULT, "timeout" })
-	)
-);
-
-TRACE_EVENT(adreno_cmdbatch_recovery,
-	TP_PROTO(struct kgsl_cmdbatch *cmdbatch, unsigned int action),
-	TP_ARGS(cmdbatch, action),
-	TP_STRUCT__entry(
-		__field(unsigned int, id)
-		__field(unsigned int, timestamp)
-		__field(unsigned int, action)
-	),
-	TP_fast_assign(
-		__entry->id = cmdbatch->context->id;
-		__entry->timestamp = cmdbatch->timestamp;
-		__entry->action = action;
-	),
-	TP_printk(
-		"ctx=%u ts=%u action=%s",
-			__entry->id, __entry->timestamp,
-			__print_symbolic(__entry->action, ADRENO_FT_TYPES)
-	)
-);
-
-DECLARE_EVENT_CLASS(adreno_drawctxt_template,
-	TP_PROTO(struct adreno_context *drawctxt),
-	TP_ARGS(drawctxt),
-	TP_STRUCT__entry(
-		__field(unsigned int, id)
-	),
-	TP_fast_assign(
-		__entry->id = drawctxt->base.id;
-	),
-	TP_printk("ctx=%u", __entry->id)
-);
-
-DEFINE_EVENT(adreno_drawctxt_template, adreno_drawctxt_sleep,
-	TP_PROTO(struct adreno_context *drawctxt),
-	TP_ARGS(drawctxt)
-);
-
-DEFINE_EVENT(adreno_drawctxt_template, adreno_drawctxt_wake,
-	TP_PROTO(struct adreno_context *drawctxt),
-	TP_ARGS(drawctxt)
-);
-
-DEFINE_EVENT(adreno_drawctxt_template, dispatch_queue_context,
-	TP_PROTO(struct adreno_context *drawctxt),
-	TP_ARGS(drawctxt)
-);
-
-DEFINE_EVENT(adreno_drawctxt_template, adreno_drawctxt_invalidate,
-	TP_PROTO(struct adreno_context *drawctxt),
-	TP_ARGS(drawctxt)
-);
-
-TRACE_EVENT(adreno_drawctxt_wait_start,
-	TP_PROTO(unsigned int id, unsigned int ts),
-	TP_ARGS(id, ts),
-	TP_STRUCT__entry(
-		__field(unsigned int, id)
-		__field(unsigned int, ts)
-	),
-	TP_fast_assign(
-		__entry->id = id;
-		__entry->ts = ts;
-	),
-	TP_printk(
-		"ctx=%u ts=%u",
-			__entry->id, __entry->ts
-	)
-);
-
-TRACE_EVENT(adreno_drawctxt_wait_done,
-	TP_PROTO(unsigned int id, unsigned int ts, int status),
-	TP_ARGS(id, ts, status),
-	TP_STRUCT__entry(
-		__field(unsigned int, id)
-		__field(unsigned int, ts)
-		__field(int, status)
-	),
-	TP_fast_assign(
-		__entry->id = id;
-		__entry->ts = ts;
-		__entry->status = status;
-	),
-	TP_printk(
-		"ctx=%u ts=%u status=%d",
-			__entry->id, __entry->ts, __entry->status
-	)
-);
-
-TRACE_EVENT(adreno_drawctxt_switch,
-	TP_PROTO(struct adreno_context *oldctx,
-		struct adreno_context *newctx,
-		unsigned int flags),
-	TP_ARGS(oldctx, newctx, flags),
-	TP_STRUCT__entry(
-		__field(unsigned int, oldctx)
-		__field(unsigned int, newctx)
-		__field(unsigned int, flags)
-	),
-	TP_fast_assign(
-		__entry->oldctx = oldctx ? oldctx->base.id : 0;
-		__entry->newctx = newctx ? newctx->base.id : 0;
-	),
-	TP_printk(
-		"oldctx=%u newctx=%u flags=%X",
-			__entry->oldctx, __entry->newctx, flags
-	)
-);
-
-TRACE_EVENT(adreno_gpu_fault,
-	TP_PROTO(unsigned int ctx, unsigned int ts,
-		unsigned int status, unsigned int rptr, unsigned int wptr,
-		unsigned int ib1base, unsigned int ib1size,
-		unsigned int ib2base, unsigned int ib2size),
-	TP_ARGS(ctx, ts, status, rptr, wptr, ib1base, ib1size, ib2base,
-		ib2size),
-	TP_STRUCT__entry(
-		__field(unsigned int, ctx)
-		__field(unsigned int, ts)
-		__field(unsigned int, status)
-		__field(unsigned int, rptr)
-		__field(unsigned int, wptr)
-		__field(unsigned int, ib1base)
-		__field(unsigned int, ib1size)
-		__field(unsigned int, ib2base)
-		__field(unsigned int, ib2size)
-	),
-	TP_fast_assign(
-		__entry->ctx = ctx;
-		__entry->ts = ts;
-		__entry->status = status;
-		__entry->rptr = rptr;
-		__entry->wptr = wptr;
-		__entry->ib1base = ib1base;
-		__entry->ib1size = ib1size;
-		__entry->ib2base = ib2base;
-		__entry->ib2size = ib2size;
-	),
-	TP_printk("ctx=%d ts=%d status=%X RB=%X/%X IB1=%X/%X IB2=%X/%X",
-		__entry->ctx, __entry->ts, __entry->status, __entry->wptr,
-		__entry->rptr, __entry->ib1base, __entry->ib1size,
-		__entry->ib2base, __entry->ib2size)
-);
-
-#endif /* _ADRENO_TRACE_H */
-
-/* This part must be outside protection */
-#include <trace/define_trace.h>
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 35a03de..2781a34 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -14,7 +14,6 @@
 #include <linux/fb.h>
 #include <linux/file.h>
 #include <linux/fs.h>
-#include <linux/list.h>
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
 #include <linux/interrupt.h>
@@ -63,10 +62,59 @@
 static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry);
 
 /**
+ * kgsl_hang_check() - Check for GPU hang
+ * data: KGSL device structure
+ *
+ * This function is called every KGSL_TIMEOUT_PART time when
+ * GPU is active to check for hang. If a hang is detected we
+ * trigger fault tolerance.
+ */
+void kgsl_hang_check(struct work_struct *work)
+{
+	struct kgsl_device *device = container_of(work, struct kgsl_device,
+							hang_check_ws);
+	static unsigned int prev_reg_val[FT_DETECT_REGS_COUNT];
+
+	mutex_lock(&device->mutex);
+
+	if (device->state == KGSL_STATE_ACTIVE) {
+
+		/* Check to see if the GPU is hung */
+		if (adreno_ft_detect(device, prev_reg_val))
+			adreno_dump_and_exec_ft(device);
+
+		mod_timer(&device->hang_timer,
+			(jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
+	}
+
+	mutex_unlock(&device->mutex);
+}
+
+/**
+ * hang_timer() - Hang timer function
+ * data: KGSL device structure
+ *
+ * This function is called when hang timer expires, in this
+ * function we check if GPU is in active state and queue the
+ * work on device workqueue to check for the hang. We restart
+ * the timer after KGSL_TIMEOUT_PART time.
+ */
+void hang_timer(unsigned long data)
+{
+	struct kgsl_device *device = (struct kgsl_device *) data;
+
+	if (device->state == KGSL_STATE_ACTIVE) {
+		/* Have work run in a non-interrupt context. */
+		queue_work(device->work_queue, &device->hang_check_ws);
+	}
+}
+
+/**
  * kgsl_trace_issueibcmds() - Call trace_issueibcmds by proxy
  * device: KGSL device
  * id: ID of the context submitting the command
- * cmdbatch: Pointer to kgsl_cmdbatch describing these commands
+ * ibdesc: Pointer to the list of IB descriptors
+ * numib: Number of IBs in the list
  * timestamp: Timestamp assigned to the command batch
  * flags: Flags sent by the user
  * result: Result of the submission attempt
@@ -76,11 +124,11 @@
  * GPU specific modules.
  */
 void kgsl_trace_issueibcmds(struct kgsl_device *device, int id,
-		struct kgsl_cmdbatch *cmdbatch,
+		struct kgsl_ibdesc *ibdesc, int numibs,
 		unsigned int timestamp, unsigned int flags,
 		int result, unsigned int type)
 {
-	trace_kgsl_issueibcmds(device, id, cmdbatch,
+	trace_kgsl_issueibcmds(device, id, ibdesc, numibs,
 		timestamp, flags, result, type);
 }
 EXPORT_SYMBOL(kgsl_trace_issueibcmds);
@@ -482,8 +530,8 @@
 EXPORT_SYMBOL(kgsl_context_init);
 
 /**
- * kgsl_context_detach() - Release the "master" context reference
- * @context: The context that will be detached
+ * kgsl_context_detach - Release the "master" context reference
+ * @context - The context that will be detached
  *
  * This is called when a context becomes unusable, because userspace
  * has requested for it to be destroyed. The context itself may
@@ -492,12 +540,14 @@
  * detached by checking the KGSL_CONTEXT_DETACHED bit in
  * context->priv.
  */
-int kgsl_context_detach(struct kgsl_context *context)
+void
+kgsl_context_detach(struct kgsl_context *context)
 {
-	int ret;
-
+	struct kgsl_device *device;
 	if (context == NULL)
-		return -EINVAL;
+		return;
+
+	device = context->device;
 
 	/*
 	 * Mark the context as detached to keep others from using
@@ -505,22 +555,19 @@
 	 * we don't try to detach twice.
 	 */
 	if (test_and_set_bit(KGSL_CONTEXT_DETACHED, &context->priv))
-		return -EINVAL;
+		return;
 
-	trace_kgsl_context_detach(context->device, context);
+	trace_kgsl_context_detach(device, context);
 
-	ret = context->device->ftbl->drawctxt_detach(context);
-
+	device->ftbl->drawctxt_detach(context);
 	/*
 	 * Cancel events after the device-specific context is
 	 * detached, to avoid possibly freeing memory while
 	 * it is still in use by the GPU.
 	 */
-	kgsl_context_cancel_events(context->device, context);
+	kgsl_context_cancel_events(device, context);
 
 	kgsl_context_put(context);
-
-	return ret;
 }
 
 void
@@ -532,8 +579,6 @@
 
 	trace_kgsl_context_destroy(device, context);
 
-	BUG_ON(!kgsl_context_detached(context));
-
 	write_lock(&device->context_lock);
 	if (context->id != KGSL_CONTEXT_INVALID) {
 		idr_remove(&device->context_idr, context->id);
@@ -604,11 +649,10 @@
 	policy_saved = device->pwrscale.policy;
 	device->pwrscale.policy = NULL;
 	kgsl_pwrctrl_request_state(device, KGSL_STATE_SUSPEND);
-
-	/* Tell the device to drain the submission queue */
-	device->ftbl->drain(device);
-
-	/* Wait for the active count to hit zero */
+	/*
+	 * Make sure no user process is waiting for a timestamp
+	 * before supending.
+	 */
 	kgsl_active_count_wait(device, 0);
 
 	/*
@@ -619,10 +663,13 @@
 
 	/* Don't let the timer wake us during suspended sleep. */
 	del_timer_sync(&device->idle_timer);
+	del_timer_sync(&device->hang_timer);
 	switch (device->state) {
 		case KGSL_STATE_INIT:
 			break;
 		case KGSL_STATE_ACTIVE:
+			/* Wait for the device to become idle */
+			device->ftbl->idle(device);
 		case KGSL_STATE_NAP:
 		case KGSL_STATE_SLEEP:
 			/* make sure power is on to stop the device */
@@ -948,16 +995,8 @@
 		if (context == NULL)
 			break;
 
-		if (context->dev_priv == dev_priv) {
-			/*
-			 * Hold a reference to the context in case somebody
-			 * tries to put it while we are detaching
-			 */
-
-			_kgsl_context_get(context);
+		if (context->dev_priv == dev_priv)
 			kgsl_context_detach(context);
-			kgsl_context_put(context);
-		}
 
 		next = next + 1;
 	}
@@ -971,7 +1010,6 @@
 
 	result = kgsl_close_device(device);
 	mutex_unlock(&device->mutex);
-
 	kfree(dev_priv);
 
 	kgsl_put_process_private(device, private);
@@ -1004,6 +1042,7 @@
 		 * Make sure the gates are open, so they don't block until
 		 * we start suspend or FT.
 		 */
+		complete_all(&device->ft_gate);
 		complete_all(&device->hwaccess_gate);
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
 		kgsl_active_count_put(device);
@@ -1399,610 +1438,93 @@
 	return result;
 }
 
-/*
- * KGSL command batch management
- * A command batch is a single submission from userland.  The cmdbatch
- * encapsulates everything about the submission : command buffers, flags and
- * sync points.
- *
- * Sync points are events that need to expire before the
- * cmdbatch can be queued to the hardware. For each sync point a
- * kgsl_cmdbatch_sync_event struct is created and added to a list in the
- * cmdbatch. There can be multiple types of events both internal ones (GPU
- * events) and external triggers. As the events expire the struct is deleted
- * from the list. The GPU will submit the command batch as soon as the list
- * goes empty indicating that all the sync points have been met.
- */
-
-/**
- * struct kgsl_cmdbatch_sync_event
- * @type: Syncpoint type
- * @node: Local list node for the cmdbatch sync point list
- * @cmdbatch: Pointer to the cmdbatch that owns the sync event
- * @context: Pointer to the KGSL context that owns the cmdbatch
- * @timestamp: Pending timestamp for the event
- * @handle: Pointer to a sync fence handle
- * @device: Pointer to the KGSL device
- * @lock: Spin lock to protect the sync event list
- */
-struct kgsl_cmdbatch_sync_event {
-	int type;
-	struct list_head node;
-	struct kgsl_cmdbatch *cmdbatch;
-	struct kgsl_context *context;
-	unsigned int timestamp;
-	struct kgsl_sync_fence_waiter *handle;
-	struct kgsl_device *device;
-	spinlock_t lock;
-};
-
-/**
- * kgsl_cmdbatch_destroy_object() - Destroy a cmdbatch object
- * @kref: Pointer to the kref structure for this object
- *
- * Actually destroy a command batch object.  Called from kgsl_cmdbatch_put
- */
-void kgsl_cmdbatch_destroy_object(struct kref *kref)
-{
-	struct kgsl_cmdbatch *cmdbatch = container_of(kref,
-		struct kgsl_cmdbatch, refcount);
-
-	kgsl_context_put(cmdbatch->context);
-	kfree(cmdbatch->ibdesc);
-
-	kfree(cmdbatch);
-}
-EXPORT_SYMBOL(kgsl_cmdbatch_destroy_object);
-
-/*
- * a generic function to retire a pending sync event and (possibly)
- * kick the dispatcher
- */
-static void kgsl_cmdbatch_sync_expire(struct kgsl_device *device,
-	struct kgsl_cmdbatch_sync_event *event)
-{
-	int sched = 0;
-
-	spin_lock(&event->cmdbatch->lock);
-	list_del(&event->node);
-	sched = list_empty(&event->cmdbatch->synclist) ? 1 : 0;
-	spin_unlock(&event->cmdbatch->lock);
-
-	/*
-	 * if this is the last event in the list then tell
-	 * the GPU device that the cmdbatch can be submitted
-	 */
-
-	if (sched && device->ftbl->drawctxt_sched)
-		device->ftbl->drawctxt_sched(device, event->cmdbatch->context);
-}
-
-
-/*
- * This function is called by the GPU event when the sync event timestamp
- * expires
- */
-static void kgsl_cmdbatch_sync_func(struct kgsl_device *device, void *priv,
-		u32 id, u32 timestamp, u32 type)
-{
-	struct kgsl_cmdbatch_sync_event *event = priv;
-
-	kgsl_cmdbatch_sync_expire(device, event);
-
-	kgsl_context_put(event->context);
-	kgsl_cmdbatch_put(event->cmdbatch);
-
-	kfree(event);
-}
-
-/**
- * kgsl_cmdbatch_destroy() - Destroy a cmdbatch structure
- * @cmdbatch: Pointer to the command batch object to destroy
- *
- * Start the process of destroying a command batch.  Cancel any pending events
- * and decrement the refcount.
- */
-void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch)
-{
-	struct kgsl_cmdbatch_sync_event *event, *tmp;
-
-	spin_lock(&cmdbatch->lock);
-
-	/* Delete any pending sync points for this command batch */
-	list_for_each_entry_safe(event, tmp, &cmdbatch->synclist, node) {
-
-		if (event->type == KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP) {
-			/* Cancel the event if it still exists */
-			kgsl_cancel_event(cmdbatch->device, event->context,
-				event->timestamp, kgsl_cmdbatch_sync_func,
-				event);
-		} else if (event->type == KGSL_CMD_SYNCPOINT_TYPE_FENCE) {
-			if (kgsl_sync_fence_async_cancel(event->handle)) {
-				list_del(&event->node);
-				kfree(event);
-				kgsl_cmdbatch_put(cmdbatch);
-			}
-		}
-	}
-
-	spin_unlock(&cmdbatch->lock);
-	kgsl_cmdbatch_put(cmdbatch);
-}
-EXPORT_SYMBOL(kgsl_cmdbatch_destroy);
-
-/*
- * A callback that gets registered with kgsl_sync_fence_async_wait and is fired
- * when a fence is expired
- */
-static void kgsl_cmdbatch_sync_fence_func(void *priv)
-{
-	struct kgsl_cmdbatch_sync_event *event = priv;
-
-	spin_lock(&event->lock);
-	kgsl_cmdbatch_sync_expire(event->device, event);
-	kgsl_cmdbatch_put(event->cmdbatch);
-	spin_unlock(&event->lock);
-	kfree(event);
-}
-
-/* kgsl_cmdbatch_add_sync_fence() - Add a new sync fence syncpoint
- * @device: KGSL device
- * @cmdbatch: KGSL cmdbatch to add the sync point to
- * @priv: Private sructure passed by the user
- *
- * Add a new fence sync syncpoint to the cmdbatch.
- */
-static int kgsl_cmdbatch_add_sync_fence(struct kgsl_device *device,
-		struct kgsl_cmdbatch *cmdbatch, void *priv)
-{
-	struct kgsl_cmd_syncpoint_fence *sync = priv;
-	struct kgsl_cmdbatch_sync_event *event;
-
-	event = kzalloc(sizeof(*event), GFP_KERNEL);
-
-	if (event == NULL)
-		return -ENOMEM;
-
-	kref_get(&cmdbatch->refcount);
-
-	event->type = KGSL_CMD_SYNCPOINT_TYPE_FENCE;
-	event->cmdbatch = cmdbatch;
-	event->device = device;
-	spin_lock_init(&event->lock);
-
-	/*
-	 * Add it to the list first to account for the possiblity that the
-	 * callback will happen immediately after the call to
-	 * kgsl_sync_fence_async_wait
-	 */
-
-	spin_lock(&cmdbatch->lock);
-	list_add(&event->node, &cmdbatch->synclist);
-	spin_unlock(&cmdbatch->lock);
-
-	/*
-	 * There is a distinct race condition that can occur if the fence
-	 * callback is fired before the function has a chance to return.  The
-	 * event struct would be freed before we could write event->handle and
-	 * hilarity ensued.  Protect against this by protecting the call to
-	 * kgsl_sync_fence_async_wait and the kfree in the callback with a lock.
-	 */
-
-	spin_lock(&event->lock);
-
-	event->handle = kgsl_sync_fence_async_wait(sync->fd,
-		kgsl_cmdbatch_sync_fence_func, event);
-
-
-	if (IS_ERR_OR_NULL(event->handle)) {
-		int ret = PTR_ERR(event->handle);
-
-		spin_lock(&cmdbatch->lock);
-		list_del(&event->node);
-		spin_unlock(&cmdbatch->lock);
-
-		kgsl_cmdbatch_put(cmdbatch);
-		spin_unlock(&event->lock);
-		kfree(event);
-
-		return ret;
-	}
-
-	spin_unlock(&event->lock);
-	return 0;
-}
-
-/* kgsl_cmdbatch_add_sync_timestamp() - Add a new sync point for a cmdbatch
- * @device: KGSL device
- * @cmdbatch: KGSL cmdbatch to add the sync point to
- * @priv: Private sructure passed by the user
- *
- * Add a new sync point timestamp event to the cmdbatch.
- */
-static int kgsl_cmdbatch_add_sync_timestamp(struct kgsl_device *device,
-		struct kgsl_cmdbatch *cmdbatch, void *priv)
-{
-	struct kgsl_cmd_syncpoint_timestamp *sync = priv;
-	struct kgsl_context *context = kgsl_context_get(cmdbatch->device,
-		sync->context_id);
-	struct kgsl_cmdbatch_sync_event *event;
-	int ret = -EINVAL;
-
-	if (context == NULL)
-		return -EINVAL;
-
-	/* Sanity check - you can't create a sync point on your own context */
-	if (context == cmdbatch->context) {
-		KGSL_DRV_ERR(device,
-			"Cannot create a sync point on your own context %d\n",
-			context->id);
-		goto done;
-	}
-
-	event = kzalloc(sizeof(*event), GFP_KERNEL);
-	if (event == NULL) {
-		ret = -ENOMEM;
-		goto done;
-	}
-
-	kref_get(&cmdbatch->refcount);
-
-	event->type = KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP;
-	event->cmdbatch = cmdbatch;
-	event->context = context;
-	event->timestamp = sync->timestamp;
-
-	spin_lock(&cmdbatch->lock);
-	list_add(&event->node, &cmdbatch->synclist);
-	spin_unlock(&cmdbatch->lock);
-
-	mutex_lock(&device->mutex);
-	kgsl_active_count_get(device);
-	ret = kgsl_add_event(device, context->id, sync->timestamp,
-		kgsl_cmdbatch_sync_func, event, NULL);
-	kgsl_active_count_put(device);
-	mutex_unlock(&device->mutex);
-
-	if (ret) {
-		spin_lock(&cmdbatch->lock);
-		list_del(&event->node);
-		spin_unlock(&cmdbatch->lock);
-
-		kgsl_cmdbatch_put(cmdbatch);
-		kfree(event);
-	}
-
-done:
-	if (ret)
-		kgsl_context_put(context);
-
-	return ret;
-}
-
-/**
- * kgsl_cmdbatch_add_sync() - Add a sync point to a command batch
- * @device: Pointer to the KGSL device struct for the GPU
- * @cmdbatch: Pointer to the cmdbatch
- * @sync: Pointer to the user-specified struct defining the syncpoint
- *
- * Create a new sync point in the cmdbatch based on the user specified
- * parameters
- */
-static int kgsl_cmdbatch_add_sync(struct kgsl_device *device,
-	struct kgsl_cmdbatch *cmdbatch,
-	struct kgsl_cmd_syncpoint *sync)
-{
-	void *priv;
-	int ret, psize;
-	int (*func)(struct kgsl_device *device, struct kgsl_cmdbatch *cmdbatch,
-			void *priv);
-
-	switch (sync->type) {
-	case KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP:
-		psize = sizeof(struct kgsl_cmd_syncpoint_timestamp);
-		func = kgsl_cmdbatch_add_sync_timestamp;
-		break;
-	case KGSL_CMD_SYNCPOINT_TYPE_FENCE:
-		psize = sizeof(struct kgsl_cmd_syncpoint_fence);
-		func = kgsl_cmdbatch_add_sync_fence;
-		break;
-	default:
-		KGSL_DRV_ERR(device, "Invalid sync type 0x%x\n", sync->type);
-		return -EINVAL;
-	}
-
-	if (sync->size != psize) {
-		KGSL_DRV_ERR(device, "Invalid sync size %d\n", sync->size);
-		return -EINVAL;
-	}
-
-	priv = kzalloc(sync->size, GFP_KERNEL);
-	if (priv == NULL)
-		return -ENOMEM;
-
-	if (copy_from_user(priv, sync->priv, sync->size)) {
-		kfree(priv);
-		return -EFAULT;
-	}
-
-	ret = func(device, cmdbatch, priv);
-	kfree(priv);
-
-	return ret;
-}
-
-/**
- * kgsl_cmdbatch_create() - Create a new cmdbatch structure
- * @device: Pointer to a KGSL device struct
- * @context: Pointer to a KGSL context struct
- * @numibs: Number of indirect buffers to make room for in the cmdbatch
- *
- * Allocate an new cmdbatch structure and add enough room to store the list of
- * indirect buffers
- */
-static struct kgsl_cmdbatch *kgsl_cmdbatch_create(struct kgsl_device *device,
-		struct kgsl_context *context, unsigned int flags,
-		unsigned int numibs)
-{
-	struct kgsl_cmdbatch *cmdbatch = kzalloc(sizeof(*cmdbatch), GFP_KERNEL);
-	if (cmdbatch == NULL)
-		return ERR_PTR(-ENOMEM);
-
-	if (!(flags & KGSL_CONTEXT_SYNC)) {
-		cmdbatch->ibdesc = kzalloc(sizeof(*cmdbatch->ibdesc) * numibs,
-			GFP_KERNEL);
-		if (cmdbatch->ibdesc == NULL) {
-			kfree(cmdbatch);
-			return ERR_PTR(-ENOMEM);
-		}
-	}
-
-	kref_init(&cmdbatch->refcount);
-	INIT_LIST_HEAD(&cmdbatch->synclist);
-	spin_lock_init(&cmdbatch->lock);
-
-	cmdbatch->device = device;
-	cmdbatch->ibcount = (flags & KGSL_CONTEXT_SYNC) ? 0 : numibs;
-	cmdbatch->context = context;
-	cmdbatch->flags = flags & ~KGSL_CONTEXT_SUBMIT_IB_LIST;
-
-	/*
-	 * Increase the reference count on the context so it doesn't disappear
-	 * during the lifetime of this command batch
-	 */
-	_kgsl_context_get(context);
-
-	return cmdbatch;
-}
-
-/**
- * _kgsl_cmdbatch_verify() - Perform a quick sanity check on a command batch
- * @device: Pointer to a KGSL instance that owns the command batch
- * @pagetable: Pointer to the pagetable for the current process
- * @cmdbatch: Number of indirect buffers to make room for in the cmdbatch
- *
- * Do a quick sanity test on the list of indirect buffers in a command batch
- * verifying that the size and GPU address
- */
-static bool _kgsl_cmdbatch_verify(struct kgsl_device_private *dev_priv,
-	struct kgsl_cmdbatch *cmdbatch)
-{
-	int i;
-	struct kgsl_process_private *private = dev_priv->process_priv;
-
-	for (i = 0; i < cmdbatch->ibcount; i++) {
-		if (cmdbatch->ibdesc[i].sizedwords == 0) {
-			KGSL_DRV_ERR(dev_priv->device,
-				"invalid size ctx %d ib(%d) %X/%X\n",
-				cmdbatch->context->id, i,
-				cmdbatch->ibdesc[i].gpuaddr,
-				cmdbatch->ibdesc[i].sizedwords);
-
-			return false;
-		}
-
-		if (!kgsl_mmu_gpuaddr_in_range(private->pagetable,
-			cmdbatch->ibdesc[i].gpuaddr)) {
-			KGSL_DRV_ERR(dev_priv->device,
-				"Invalid address ctx %d ib(%d) %X/%X\n",
-				cmdbatch->context->id, i,
-				cmdbatch->ibdesc[i].gpuaddr,
-				cmdbatch->ibdesc[i].sizedwords);
-
-			return false;
-		}
-	}
-
-	return true;
-}
-
-/**
- * _kgsl_cmdbatch_create_legacy() - Create a cmdbatch from a legacy ioctl struct
- * @device: Pointer to the KGSL device struct for the GPU
- * @context: Pointer to the KGSL context that issued the command batch
- * @param: Pointer to the kgsl_ringbuffer_issueibcmds struct that the user sent
- *
- * Create a command batch from the legacy issueibcmds format.
- */
-static struct kgsl_cmdbatch *_kgsl_cmdbatch_create_legacy(
-		struct kgsl_device *device,
-		struct kgsl_context *context,
-		struct kgsl_ringbuffer_issueibcmds *param)
-{
-	struct kgsl_cmdbatch *cmdbatch =
-		kgsl_cmdbatch_create(device, context, param->flags, 1);
-
-	if (IS_ERR(cmdbatch))
-		return cmdbatch;
-
-	cmdbatch->ibdesc[0].gpuaddr = param->ibdesc_addr;
-	cmdbatch->ibdesc[0].sizedwords = param->numibs;
-	cmdbatch->ibcount = 1;
-	cmdbatch->flags = param->flags;
-
-	return cmdbatch;
-}
-
-/**
- * _kgsl_cmdbatch_create() - Create a cmdbatch from a ioctl struct
- * @device: Pointer to the KGSL device struct for the GPU
- * @context: Pointer to the KGSL context that issued the command batch
- * @flags: Flags passed in from the user command
- * @cmdlist: Pointer to the list of commands from the user
- * @numcmds: Number of commands in the list
- * @synclist: Pointer to the list of syncpoints from the user
- * @numsyncs: Number of syncpoints in the list
- *
- * Create a command batch from the standard issueibcmds format sent by the user.
- */
-static struct kgsl_cmdbatch *_kgsl_cmdbatch_create(struct kgsl_device *device,
-		struct kgsl_context *context,
-		unsigned int flags,
-		unsigned int cmdlist, unsigned int numcmds,
-		unsigned int synclist, unsigned int numsyncs)
-{
-	struct kgsl_cmdbatch *cmdbatch =
-		kgsl_cmdbatch_create(device, context, flags, numcmds);
-	int ret = 0;
-
-	if (IS_ERR(cmdbatch))
-		return cmdbatch;
-
-	if (!(flags & KGSL_CONTEXT_SYNC)) {
-		if (copy_from_user(cmdbatch->ibdesc, (void __user *) cmdlist,
-			sizeof(struct kgsl_ibdesc) * numcmds)) {
-			ret = -EFAULT;
-			goto done;
-		}
-	}
-
-	if (synclist && numsyncs) {
-		struct kgsl_cmd_syncpoint sync;
-		void  __user *uptr = (void __user *) synclist;
-		int i;
-
-		for (i = 0; i < numsyncs; i++) {
-			memset(&sync, 0, sizeof(sync));
-
-			if (copy_from_user(&sync, uptr, sizeof(sync))) {
-				ret = -EFAULT;
-				break;
-			}
-
-			ret = kgsl_cmdbatch_add_sync(device, cmdbatch, &sync);
-
-			if (ret)
-				break;
-
-			uptr += sizeof(sync);
-		}
-	}
-
-done:
-	if (ret) {
-		kgsl_cmdbatch_destroy(cmdbatch);
-		return ERR_PTR(ret);
-	}
-
-	return cmdbatch;
-}
-
 static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
 				      unsigned int cmd, void *data)
 {
+	int result = 0;
+	int i = 0;
 	struct kgsl_ringbuffer_issueibcmds *param = data;
-	struct kgsl_device *device = dev_priv->device;
+	struct kgsl_ibdesc *ibdesc;
 	struct kgsl_context *context;
-	struct kgsl_cmdbatch *cmdbatch;
-	long result = -EINVAL;
 
-	/* The legacy functions don't support synchronization commands */
-	if (param->flags & KGSL_CONTEXT_SYNC)
-		return -EINVAL;
-
-	/* Get the context */
 	context = kgsl_context_get_owner(dev_priv, param->drawctxt_id);
-	if (context == NULL)
+	if (context == NULL) {
+		result = -EINVAL;
 		goto done;
+	}
 
 	if (param->flags & KGSL_CONTEXT_SUBMIT_IB_LIST) {
+		if (!param->numibs) {
+			result = -EINVAL;
+			goto done;
+		}
+
 		/*
-		 * Do a quick sanity check on the number of IBs in the
-		 * submission
+		 * Put a reasonable upper limit on the number of IBs that can be
+		 * submitted
 		 */
 
-		if (param->numibs == 0 || param->numibs > KGSL_MAX_NUMIBS)
+		if (param->numibs > 10000) {
+			result = -EINVAL;
 			goto done;
+		}
 
-		cmdbatch = _kgsl_cmdbatch_create(device, context, param->flags,
-				param->ibdesc_addr, param->numibs, 0, 0);
-	} else
-		cmdbatch = _kgsl_cmdbatch_create_legacy(device, context, param);
+		ibdesc = kzalloc(sizeof(struct kgsl_ibdesc) * param->numibs,
+					GFP_KERNEL);
+		if (!ibdesc) {
+			KGSL_MEM_ERR(dev_priv->device,
+				"kzalloc(%d) failed\n",
+				sizeof(struct kgsl_ibdesc) * param->numibs);
+			result = -ENOMEM;
+			goto done;
+		}
 
-	if (IS_ERR(cmdbatch)) {
-		result = PTR_ERR(cmdbatch);
-		goto done;
+		if (copy_from_user(ibdesc, (void *)param->ibdesc_addr,
+				sizeof(struct kgsl_ibdesc) * param->numibs)) {
+			result = -EFAULT;
+			KGSL_DRV_ERR(dev_priv->device,
+				"copy_from_user failed\n");
+			goto free_ibdesc;
+		}
+	} else {
+		KGSL_DRV_INFO(dev_priv->device,
+			"Using single IB submission mode for ib submission\n");
+		/* If user space driver is still using the old mode of
+		 * submitting single ib then we need to support that as well */
+		ibdesc = kzalloc(sizeof(struct kgsl_ibdesc), GFP_KERNEL);
+		if (!ibdesc) {
+			KGSL_MEM_ERR(dev_priv->device,
+				"kzalloc(%d) failed\n",
+				sizeof(struct kgsl_ibdesc));
+			result = -ENOMEM;
+			goto done;
+		}
+		ibdesc[0].gpuaddr = param->ibdesc_addr;
+		ibdesc[0].sizedwords = param->numibs;
+		param->numibs = 1;
 	}
 
-	/* Run basic sanity checking on the command */
-	if (!_kgsl_cmdbatch_verify(dev_priv, cmdbatch))
-		goto free_cmdbatch;
+	for (i = 0; i < param->numibs; i++) {
+		struct kgsl_pagetable *pt = dev_priv->process_priv->pagetable;
 
-	result = dev_priv->device->ftbl->issueibcmds(dev_priv, context,
-		cmdbatch, &param->timestamp);
-
-free_cmdbatch:
-	if (result)
-		kgsl_cmdbatch_destroy(cmdbatch);
-
-done:
-	kgsl_context_put(context);
-	return result;
-}
-
-static long kgsl_ioctl_submit_commands(struct kgsl_device_private *dev_priv,
-				      unsigned int cmd, void *data)
-{
-	struct kgsl_submit_commands *param = data;
-	struct kgsl_device *device = dev_priv->device;
-	struct kgsl_context *context;
-	struct kgsl_cmdbatch *cmdbatch;
-
-	long result = -EINVAL;
-
-	/* The number of IBs are completely ignored for sync commands */
-	if (!(param->flags & KGSL_CONTEXT_SYNC)) {
-		if (param->numcmds == 0 || param->numcmds > KGSL_MAX_NUMIBS)
-			return -EINVAL;
-	} else if (param->numcmds != 0) {
-		KGSL_DEV_ERR_ONCE(device,
-			"Commands specified with the SYNC flag.  They will be ignored\n");
+		if (!kgsl_mmu_gpuaddr_in_range(pt, ibdesc[i].gpuaddr)) {
+			result = -ERANGE;
+			KGSL_DRV_ERR(dev_priv->device,
+				     "invalid ib base GPU virtual addr %x\n",
+				     ibdesc[i].gpuaddr);
+			goto free_ibdesc;
+		}
 	}
 
-	context = kgsl_context_get_owner(dev_priv, param->context_id);
-	if (context == NULL)
-		return -EINVAL;
+	result = dev_priv->device->ftbl->issueibcmds(dev_priv,
+					     context,
+					     ibdesc,
+					     param->numibs,
+					     &param->timestamp,
+					     param->flags);
 
-	cmdbatch = _kgsl_cmdbatch_create(device, context, param->flags,
-		(unsigned int) param->cmdlist, param->numcmds,
-		(unsigned int) param->synclist, param->numsyncs);
-
-	if (IS_ERR(cmdbatch)) {
-		result = PTR_ERR(cmdbatch);
-		goto done;
-	}
-
-	/* Run basic sanity checking on the command */
-	if (!_kgsl_cmdbatch_verify(dev_priv, cmdbatch))
-		goto free_cmdbatch;
-
-	result = dev_priv->device->ftbl->issueibcmds(dev_priv, context,
-		cmdbatch, &param->timestamp);
-
-free_cmdbatch:
-	if (result)
-		kgsl_cmdbatch_destroy(cmdbatch);
-
+free_ibdesc:
+	kfree(ibdesc);
 done:
 	kgsl_context_put(context);
 	return result;
@@ -2143,11 +1665,14 @@
 {
 	struct kgsl_drawctxt_destroy *param = data;
 	struct kgsl_context *context;
-	long result;
+	long result = -EINVAL;
 
 	context = kgsl_context_get_owner(dev_priv, param->drawctxt_id);
 
-	result = kgsl_context_detach(context);
+	if (context) {
+		kgsl_context_detach(context);
+		result = 0;
+	}
 
 	kgsl_context_put(context);
 	return result;
@@ -3246,7 +2771,7 @@
 } kgsl_ioctl_funcs[] = {
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_GETPROPERTY,
 			kgsl_ioctl_device_getproperty,
-			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+			KGSL_IOCTL_LOCK),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_WAITTIMESTAMP,
 			kgsl_ioctl_device_waittimestamp,
 			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
@@ -3254,9 +2779,8 @@
 			kgsl_ioctl_device_waittimestamp_ctxtid,
 			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS,
-			kgsl_ioctl_rb_issueibcmds, 0),
-	KGSL_IOCTL_FUNC(IOCTL_KGSL_SUBMIT_COMMANDS,
-			kgsl_ioctl_submit_commands, 0),
+			kgsl_ioctl_rb_issueibcmds,
+			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_READTIMESTAMP,
 			kgsl_ioctl_cmdstream_readtimestamp,
 			KGSL_IOCTL_LOCK),
@@ -3265,13 +2789,13 @@
 			KGSL_IOCTL_LOCK),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP,
 			kgsl_ioctl_cmdstream_freememontimestamp,
-			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+			KGSL_IOCTL_LOCK),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_CTXTID,
 			kgsl_ioctl_cmdstream_freememontimestamp_ctxtid,
-			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+			KGSL_IOCTL_LOCK),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_CREATE,
 			kgsl_ioctl_drawctxt_create,
-			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+			KGSL_IOCTL_LOCK),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_DESTROY,
 			kgsl_ioctl_drawctxt_destroy,
 			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
@@ -3291,10 +2815,10 @@
 			kgsl_ioctl_cff_user_event, 0),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_TIMESTAMP_EVENT,
 			kgsl_ioctl_timestamp_event,
-			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+			KGSL_IOCTL_LOCK),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_SETPROPERTY,
 			kgsl_ioctl_device_setproperty,
-			KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+			KGSL_IOCTL_LOCK),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC_ID,
 			kgsl_ioctl_gpumem_alloc_id, 0),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_FREE_ID,
@@ -3938,6 +3462,7 @@
 
 
 	setup_timer(&device->idle_timer, kgsl_timer, (unsigned long) device);
+	setup_timer(&device->hang_timer, hang_timer, (unsigned long) device);
 	status = kgsl_create_device_workqueue(device);
 	if (status)
 		goto error_pwrctrl_close;
@@ -3997,6 +3522,7 @@
 
 		if (device->state == KGSL_STATE_ACTIVE)
 			kgsl_idle(device);
+
 	}
 
 	if (device->pm_dump_enable) {
@@ -4010,12 +3536,13 @@
 			pwr->power_flags, pwr->active_pwrlevel);
 
 		KGSL_LOG_DUMP(device, "POWER: INTERVAL TIMEOUT = %08X ",
-				pwr->interval_timeout);
+			pwr->interval_timeout);
 
 	}
 
 	/* Disable the idle timer so we don't get interrupted */
 	del_timer_sync(&device->idle_timer);
+	del_timer_sync(&device->hang_timer);
 
 	/* Force on the clocks */
 	kgsl_pwrctrl_wake(device);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 2e9d52e..8d390a9 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -78,8 +78,6 @@
 
 #define KGSL_MEMFREE_HIST_SIZE	((int)(PAGE_SIZE * 2))
 
-#define KGSL_MAX_NUMIBS 100000
-
 struct kgsl_memfree_hist_elem {
 	unsigned int pid;
 	unsigned int gpuaddr;
@@ -143,7 +141,6 @@
 
 struct kgsl_pagetable;
 struct kgsl_memdesc;
-struct kgsl_cmdbatch;
 
 struct kgsl_memdesc_ops {
 	int (*vmflags)(struct kgsl_memdesc *);
@@ -208,6 +205,7 @@
 #define MMU_CONFIG 1
 #endif
 
+void kgsl_hang_check(struct work_struct *work);
 void kgsl_mem_entry_destroy(struct kref *kref);
 int kgsl_postmortem_dump(struct kgsl_device *device, int manual);
 
@@ -239,7 +237,7 @@
 		unsigned int value);
 
 void kgsl_trace_issueibcmds(struct kgsl_device *device, int id,
-		struct kgsl_cmdbatch *cmdbatch,
+		struct kgsl_ibdesc *ibdesc, int numibs,
 		unsigned int timestamp, unsigned int flags,
 		int result, unsigned int type);
 
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index 110264b..e623515 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -19,7 +19,6 @@
 #include "kgsl_sharedmem.h"
 
 /*default log levels is error for everything*/
-#define KGSL_LOG_LEVEL_DEFAULT 3
 #define KGSL_LOG_LEVEL_MAX     7
 
 struct dentry *kgsl_debugfs_dir;
@@ -123,6 +122,7 @@
 KGSL_DEBUGFS_LOG(ctxt_log);
 KGSL_DEBUGFS_LOG(mem_log);
 KGSL_DEBUGFS_LOG(pwr_log);
+KGSL_DEBUGFS_LOG(ft_log);
 
 static int memfree_hist_print(struct seq_file *s, void *unused)
 {
@@ -179,12 +179,6 @@
 	if (!device->d_debugfs || IS_ERR(device->d_debugfs))
 		return;
 
-	device->cmd_log = KGSL_LOG_LEVEL_DEFAULT;
-	device->ctxt_log = KGSL_LOG_LEVEL_DEFAULT;
-	device->drv_log = KGSL_LOG_LEVEL_DEFAULT;
-	device->mem_log = KGSL_LOG_LEVEL_DEFAULT;
-	device->pwr_log = KGSL_LOG_LEVEL_DEFAULT;
-
 	debugfs_create_file("log_level_cmd", 0644, device->d_debugfs, device,
 			    &cmd_log_fops);
 	debugfs_create_file("log_level_ctxt", 0644, device->d_debugfs, device,
@@ -197,6 +191,8 @@
 				&pwr_log_fops);
 	debugfs_create_file("memfree_history", 0444, device->d_debugfs, device,
 				&memfree_hist_fops);
+	debugfs_create_file("log_level_ft", 0644, device->d_debugfs, device,
+				&ft_log_fops);
 
 	/* Create postmortem dump control files */
 
@@ -211,7 +207,6 @@
 			    &pm_regs_enabled_fops);
 	debugfs_create_file("ib_enabled", 0644, pm_d_debugfs, device,
 				    &pm_ib_enabled_fops);
-	device->pm_dump_enable = 0;
 	debugfs_create_file("enable", 0644, pm_d_debugfs, device,
 				    &pm_enabled_fops);
 
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index cd9c4f7..09a31c9 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -13,7 +13,6 @@
 #ifndef __KGSL_DEVICE_H
 #define __KGSL_DEVICE_H
 
-#include <linux/slab.h>
 #include <linux/idr.h>
 #include <linux/pm_qos.h>
 #include <linux/sched.h>
@@ -77,7 +76,6 @@
 struct kgsl_context;
 struct kgsl_power_stats;
 struct kgsl_event;
-struct kgsl_cmdbatch;
 
 struct kgsl_functable {
 	/* Mandatory functions - these functions must be implemented
@@ -89,7 +87,7 @@
 	void (*regwrite) (struct kgsl_device *device,
 		unsigned int offsetwords, unsigned int value);
 	int (*idle) (struct kgsl_device *device);
-	bool (*isidle) (struct kgsl_device *device);
+	unsigned int (*isidle) (struct kgsl_device *device);
 	int (*suspend_context) (struct kgsl_device *device);
 	int (*init) (struct kgsl_device *device);
 	int (*start) (struct kgsl_device *device);
@@ -103,8 +101,9 @@
 	unsigned int (*readtimestamp) (struct kgsl_device *device,
 		struct kgsl_context *context, enum kgsl_timestamp_type type);
 	int (*issueibcmds) (struct kgsl_device_private *dev_priv,
-		struct kgsl_context *context, struct kgsl_cmdbatch *cmdbatch,
-		uint32_t *timestamps);
+		struct kgsl_context *context, struct kgsl_ibdesc *ibdesc,
+		unsigned int sizedwords, uint32_t *timestamp,
+		unsigned int flags);
 	int (*setup_pt)(struct kgsl_device *device,
 		struct kgsl_pagetable *pagetable);
 	void (*cleanup_pt)(struct kgsl_device *device,
@@ -116,15 +115,14 @@
 	void * (*snapshot)(struct kgsl_device *device, void *snapshot,
 		int *remain, int hang);
 	irqreturn_t (*irq_handler)(struct kgsl_device *device);
-	int (*drain)(struct kgsl_device *device);
 	/* Optional functions - these functions are not mandatory.  The
 	   driver will check that the function pointer is not NULL before
 	   calling the hook */
-	int (*setstate) (struct kgsl_device *device, unsigned int context_id,
+	void (*setstate) (struct kgsl_device *device, unsigned int context_id,
 			uint32_t flags);
 	struct kgsl_context *(*drawctxt_create) (struct kgsl_device_private *,
 						uint32_t *flags);
-	int (*drawctxt_detach) (struct kgsl_context *context);
+	void (*drawctxt_detach) (struct kgsl_context *context);
 	void (*drawctxt_destroy) (struct kgsl_context *context);
 	long (*ioctl) (struct kgsl_device_private *dev_priv,
 		unsigned int cmd, void *data);
@@ -134,8 +132,6 @@
 	int (*postmortem_dump) (struct kgsl_device *device, int manual);
 	int (*next_event)(struct kgsl_device *device,
 		struct kgsl_event *event);
-	void (*drawctxt_sched)(struct kgsl_device *device,
-		struct kgsl_context *context);
 };
 
 /* MH register values */
@@ -159,56 +155,6 @@
 	unsigned int created;
 };
 
-/**
- * struct kgsl_cmdbatch - KGSl command descriptor
- * @device: KGSL GPU device that the command was created for
- * @context: KGSL context that created the command
- * @timestamp: Timestamp assigned to the command
- * @flags: flags
- * @priv: Internal flags
- * @fault_policy: Internal policy describing how to handle this command in case
- * of a fault
- * @fault_recovery: recovery actions actually tried for this batch
- * @ibcount: Number of IBs in the command list
- * @ibdesc: Pointer to the list of IBs
- * @expires: Point in time when the cmdbatch is considered to be hung
- * @invalid:  non-zero if the dispatcher determines the command and the owning
- * context should be invalidated
- * @refcount: kref structure to maintain the reference count
- * @synclist: List of context/timestamp tuples to wait for before issuing
- *
- * This struture defines an atomic batch of command buffers issued from
- * userspace.
- */
-struct kgsl_cmdbatch {
-	struct kgsl_device *device;
-	struct kgsl_context *context;
-	spinlock_t lock;
-	uint32_t timestamp;
-	uint32_t flags;
-	unsigned long priv;
-	unsigned long fault_policy;
-	unsigned long fault_recovery;
-	uint32_t ibcount;
-	struct kgsl_ibdesc *ibdesc;
-	unsigned long expires;
-	int invalid;
-	struct kref refcount;
-	struct list_head synclist;
-};
-
-/**
- * enum kgsl_cmdbatch_priv - Internal cmdbatch flags
- * @CMDBATCH_FLAG_SKIP - skip the entire command batch
- * @CMDBATCH_FLAG_FORCE_PREAMBLE - Force the preamble on for the cmdbatch
- * @CMDBATCH_FLAG_WFI - Force wait-for-idle for the submission
- */
-
-enum kgsl_cmdbatch_priv {
-	CMDBATCH_FLAG_SKIP = 0,
-	CMDBATCH_FLAG_FORCE_PREAMBLE,
-	CMDBATCH_FLAG_WFI,
-};
 
 struct kgsl_device {
 	struct device *dev;
@@ -244,7 +190,9 @@
 	struct completion hwaccess_gate;
 	const struct kgsl_functable *ftbl;
 	struct work_struct idle_check_ws;
+	struct work_struct hang_check_ws;
 	struct timer_list idle_timer;
+	struct timer_list hang_timer;
 	struct kgsl_pwrctrl pwrctrl;
 	int open_count;
 
@@ -258,6 +206,7 @@
 	wait_queue_head_t active_cnt_wq;
 	struct workqueue_struct *work_queue;
 	struct device *parentdev;
+	struct completion ft_gate;
 	struct dentry *d_debugfs;
 	struct idr context_idr;
 	rwlock_t context_lock;
@@ -284,13 +233,13 @@
 	int drv_log;
 	int mem_log;
 	int pwr_log;
+	int ft_log;
 	int pm_dump_enable;
 	struct kgsl_pwrscale pwrscale;
 	struct kobject pwrscale_kobj;
 	struct work_struct ts_expired_ws;
 	struct list_head events;
 	struct list_head events_pending_list;
-	unsigned int events_last_timestamp;
 	s64 on_time;
 
 	/* Postmortem Control switches */
@@ -305,8 +254,11 @@
 
 #define KGSL_DEVICE_COMMON_INIT(_dev) \
 	.hwaccess_gate = COMPLETION_INITIALIZER((_dev).hwaccess_gate),\
+	.ft_gate = COMPLETION_INITIALIZER((_dev).ft_gate),\
 	.idle_check_ws = __WORK_INITIALIZER((_dev).idle_check_ws,\
 			kgsl_idle_check),\
+	.hang_check_ws = __WORK_INITIALIZER((_dev).hang_check_ws,\
+			kgsl_hang_check),\
 	.ts_expired_ws  = __WORK_INITIALIZER((_dev).ts_expired_ws,\
 			kgsl_process_events),\
 	.context_idr = IDR_INIT((_dev).context_idr),\
@@ -401,9 +353,6 @@
 int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts,
 	kgsl_event_func func, void *priv, void *owner);
 
-void kgsl_cancel_event(struct kgsl_device *device, struct kgsl_context *context,
-		unsigned int timestamp, kgsl_event_func func, void *priv);
-
 static inline void kgsl_process_add_stats(struct kgsl_process_private *priv,
 	unsigned int type, size_t size)
 {
@@ -491,6 +440,8 @@
 	return 0;
 }
 
+
+
 int kgsl_check_timestamp(struct kgsl_device *device,
 		struct kgsl_context *context, unsigned int timestamp);
 
@@ -646,40 +597,4 @@
 {
 	kgsl_signal_event(device, context, timestamp, KGSL_EVENT_CANCELLED);
 }
-
-void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch);
-
-void kgsl_cmdbatch_destroy_object(struct kref *kref);
-
-/**
- * kgsl_cmdbatch_put() - Decrement the refcount for a command batch object
- * @cmdbatch: Pointer to the command batch object
- */
-static inline void kgsl_cmdbatch_put(struct kgsl_cmdbatch *cmdbatch)
-{
-	if (cmdbatch)
-		kref_put(&cmdbatch->refcount, kgsl_cmdbatch_destroy_object);
-}
-
-/**
- * kgsl_cmdbatch_sync_pending() - return true if the cmdbatch is waiting
- * @cmdbatch: Pointer to the command batch object to check
- *
- * Return non-zero if the specified command batch is still waiting for sync
- * point dependencies to be satisfied
- */
-static inline int kgsl_cmdbatch_sync_pending(struct kgsl_cmdbatch *cmdbatch)
-{
-	int ret;
-
-	if (cmdbatch == NULL)
-		return 0;
-
-	spin_lock(&cmdbatch->lock);
-	ret = list_empty(&cmdbatch->synclist) ? 0 : 1;
-	spin_unlock(&cmdbatch->lock);
-
-	return ret;
-}
-
 #endif  /* __KGSL_DEVICE_H */
diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c
index c7ac0ad..9e8f6d0 100644
--- a/drivers/gpu/msm/kgsl_events.c
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -48,8 +48,7 @@
 {
 	int id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL;
 
-	trace_kgsl_fire_event(id, timestamp, type, jiffies - event->created,
-		event->func);
+	trace_kgsl_fire_event(id, timestamp, type, jiffies - event->created);
 
 	if (event->func)
 		event->func(device, event->priv, id, timestamp, type);
@@ -236,7 +235,7 @@
 	 */
 
 	if (timestamp_cmp(cur_ts, ts) >= 0) {
-		trace_kgsl_fire_event(id, cur_ts, ts, 0, func);
+		trace_kgsl_fire_event(id, cur_ts, ts, 0);
 
 		func(device, priv, id, ts, KGSL_EVENT_TIMESTAMP_RETIRED);
 		kgsl_context_put(context);
@@ -253,7 +252,7 @@
 	 * Increase the active count on the device to avoid going into power
 	 * saving modes while events are pending
 	 */
-	ret = kgsl_active_count_get_light(device);
+	ret = kgsl_active_count_get(device);
 	if (ret < 0) {
 		kgsl_context_put(context);
 		kfree(event);
@@ -267,7 +266,7 @@
 	event->owner = owner;
 	event->created = jiffies;
 
-	trace_kgsl_register_event(id, ts, func);
+	trace_kgsl_register_event(id, ts);
 
 	/* Add the event to either the owning context or the global list */
 
@@ -334,11 +333,7 @@
 		void *priv)
 {
 	struct kgsl_event *event;
-	struct list_head *head;
-
-	BUG_ON(!mutex_is_locked(&device->mutex));
-
-	head = _get_list_head(device, context);
+	struct list_head *head = _get_list_head(device, context);
 
 	event = _find_event(device, head, timestamp, func, priv);
 
@@ -405,19 +400,10 @@
 	struct kgsl_context *context, *tmp;
 	uint32_t timestamp;
 
-	/*
-	 * Bail unless the global timestamp has advanced.  We can safely do this
-	 * outside of the mutex for speed
-	 */
-
-	timestamp = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
-	if (timestamp == device->events_last_timestamp)
-		return;
-
 	mutex_lock(&device->mutex);
 
-	device->events_last_timestamp = timestamp;
-
+	/* Process expired global events */
+	timestamp = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
 	_retire_events(device, &device->events, timestamp);
 	_mark_next_event(device, &device->events);
 
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index 2634e4f..68052b1 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -482,17 +482,15 @@
 	return NULL;
 }
 
-static int kgsl_gpummu_default_setstate(struct kgsl_mmu *mmu,
+static void kgsl_gpummu_default_setstate(struct kgsl_mmu *mmu,
 					uint32_t flags)
 {
 	struct kgsl_gpummu_pt *gpummu_pt;
 	if (!kgsl_mmu_enabled())
-		return 0;
+		return;
 
 	if (flags & KGSL_MMUFLAGS_PTUPDATE) {
-		int ret = kgsl_idle(mmu->device);
-		if (ret)
-			return ret;
+		kgsl_idle(mmu->device);
 		gpummu_pt = mmu->hwpagetable->priv;
 		kgsl_regwrite(mmu->device, MH_MMU_PT_BASE,
 			gpummu_pt->base.gpuaddr);
@@ -502,16 +500,12 @@
 		/* Invalidate all and tc */
 		kgsl_regwrite(mmu->device, MH_MMU_INVALIDATE,  0x00000003);
 	}
-
-	return 0;
 }
 
-static int kgsl_gpummu_setstate(struct kgsl_mmu *mmu,
+static void kgsl_gpummu_setstate(struct kgsl_mmu *mmu,
 				struct kgsl_pagetable *pagetable,
 				unsigned int context_id)
 {
-	int ret = 0;
-
 	if (mmu->flags & KGSL_FLAGS_STARTED) {
 		/* page table not current, then setup mmu to use new
 		 *  specified page table
@@ -524,13 +518,10 @@
 			kgsl_mmu_pt_get_flags(pagetable, mmu->device->id);
 
 			/* call device specific set page table */
-			ret = kgsl_setstate(mmu, context_id,
-				KGSL_MMUFLAGS_TLBFLUSH |
+			kgsl_setstate(mmu, context_id, KGSL_MMUFLAGS_TLBFLUSH |
 				KGSL_MMUFLAGS_PTUPDATE);
 		}
 	}
-
-	return ret;
 }
 
 static int kgsl_gpummu_init(struct kgsl_mmu *mmu)
@@ -572,7 +563,6 @@
 
 	struct kgsl_device *device = mmu->device;
 	struct kgsl_gpummu_pt *gpummu_pt;
-	int ret;
 
 	if (mmu->flags & KGSL_FLAGS_STARTED)
 		return 0;
@@ -584,6 +574,9 @@
 	/* setup MMU and sub-client behavior */
 	kgsl_regwrite(device, MH_MMU_CONFIG, mmu->config);
 
+	/* idle device */
+	kgsl_idle(device);
+
 	/* enable axi interrupts */
 	kgsl_regwrite(device, MH_INTERRUPT_MASK,
 			GSL_MMU_INT_MASK | MH_INTERRUPT_MASK__MMU_PAGE_FAULT);
@@ -614,12 +607,10 @@
 	kgsl_regwrite(mmu->device, MH_MMU_VA_RANGE,
 		      (KGSL_PAGETABLE_BASE |
 		      (CONFIG_MSM_KGSL_PAGE_TABLE_SIZE >> 16)));
+	kgsl_setstate(mmu, KGSL_MEMSTORE_GLOBAL, KGSL_MMUFLAGS_TLBFLUSH);
+	mmu->flags |= KGSL_FLAGS_STARTED;
 
-	ret = kgsl_setstate(mmu, KGSL_MEMSTORE_GLOBAL, KGSL_MMUFLAGS_TLBFLUSH);
-	if (!ret)
-		mmu->flags |= KGSL_FLAGS_STARTED;
-
-	return ret;
+	return 0;
 }
 
 static int
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index e296784..ecda5a7 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -423,12 +423,8 @@
 	 * the GPU and trigger a snapshot. To stall the transaction return
 	 * EBUSY error.
 	 */
-	if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE) {
-		/* turn off GPU IRQ so we don't get faults from it too */
-		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
-		adreno_dispatcher_irq_fault(device);
+	if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE)
 		ret = -EBUSY;
-	}
 done:
 	return ret;
 }
@@ -1209,12 +1205,10 @@
 	return 0;
 }
 
-static int kgsl_iommu_setstate(struct kgsl_mmu *mmu,
+static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
 				struct kgsl_pagetable *pagetable,
 				unsigned int context_id)
 {
-	int ret = 0;
-
 	if (mmu->flags & KGSL_FLAGS_STARTED) {
 		/* page table not current, then setup mmu to use new
 		 *  specified page table
@@ -1225,12 +1219,10 @@
 			flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
 							mmu->device->id) |
 							KGSL_MMUFLAGS_TLBFLUSH;
-			ret = kgsl_setstate(mmu, context_id,
+			kgsl_setstate(mmu, context_id,
 				KGSL_MMUFLAGS_PTUPDATE | flags);
 		}
 	}
-
-	return ret;
 }
 
 /*
@@ -1900,40 +1892,31 @@
  * cpu
  * Return - void
  */
-static int kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
+static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
 					uint32_t flags)
 {
 	struct kgsl_iommu *iommu = mmu->priv;
 	int temp;
 	int i;
-	int ret = 0;
 	phys_addr_t pt_base = kgsl_iommu_get_pt_base_addr(mmu,
 						mmu->hwpagetable);
 	phys_addr_t pt_val;
 
-	ret = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
-
-	if (ret) {
+	if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
 		KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
-		return ret;
+		return;
 	}
 
 	/* For v0 SMMU GPU needs to be idle for tlb invalidate as well */
-	if (msm_soc_version_supports_iommu_v0()) {
-		ret = kgsl_idle(mmu->device);
-		if (ret)
-			return ret;
-	}
+	if (msm_soc_version_supports_iommu_v0())
+		kgsl_idle(mmu->device);
 
 	/* Acquire GPU-CPU sync Lock here */
 	_iommu_lock();
 
 	if (flags & KGSL_MMUFLAGS_PTUPDATE) {
-		if (!msm_soc_version_supports_iommu_v0()) {
-			ret = kgsl_idle(mmu->device);
-			if (ret)
-				goto unlock;
-		}
+		if (!msm_soc_version_supports_iommu_v0())
+			kgsl_idle(mmu->device);
 		for (i = 0; i < iommu->unit_count; i++) {
 			/* get the lsb value which should not change when
 			 * changing ttbr0 */
@@ -1994,13 +1977,12 @@
 			}
 		}
 	}
-unlock:
+
 	/* Release GPU-CPU sync Lock here */
 	_iommu_unlock();
 
 	/* Disable smmu clock */
 	kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
-	return ret;
 }
 
 /*
@@ -2057,7 +2039,6 @@
 	.mmu_pagefault_resume = kgsl_iommu_pagefault_resume,
 	.mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
 	.mmu_enable_clk = kgsl_iommu_enable_clk,
-	.mmu_disable_clk = kgsl_iommu_disable_clk,
 	.mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
 	.mmu_get_default_ttbr0 = kgsl_iommu_get_default_ttbr0,
 	.mmu_get_reg_gpuaddr = kgsl_iommu_get_reg_gpuaddr,
diff --git a/drivers/gpu/msm/kgsl_log.h b/drivers/gpu/msm/kgsl_log.h
index 3a32953..a7832e4 100644
--- a/drivers/gpu/msm/kgsl_log.h
+++ b/drivers/gpu/msm/kgsl_log.h
@@ -103,6 +103,15 @@
 #define KGSL_PWR_CRIT(_dev, fmt, args...) \
 KGSL_LOG_CRIT(_dev->dev, _dev->pwr_log, fmt, ##args)
 
+#define KGSL_FT_INFO(_dev, fmt, args...) \
+KGSL_LOG_INFO(_dev->dev, _dev->ft_log, fmt, ##args)
+#define KGSL_FT_WARN(_dev, fmt, args...) \
+KGSL_LOG_WARN(_dev->dev, _dev->ft_log, fmt, ##args)
+#define KGSL_FT_ERR(_dev, fmt, args...) \
+KGSL_LOG_ERR(_dev->dev, _dev->ft_log, fmt, ##args)
+#define KGSL_FT_CRIT(_dev, fmt, args...) \
+KGSL_LOG_CRIT(_dev->dev, _dev->ft_log, fmt, ##args)
+
 /* Core error messages - these are for core KGSL functions that have
    no device associated with them (such as memory) */
 
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 6635a7c..952019f 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -566,7 +566,7 @@
 }
 EXPORT_SYMBOL(kgsl_mmu_putpagetable);
 
-int kgsl_setstate(struct kgsl_mmu *mmu, unsigned int context_id,
+void kgsl_setstate(struct kgsl_mmu *mmu, unsigned int context_id,
 			uint32_t flags)
 {
 	struct kgsl_device *device = mmu->device;
@@ -574,16 +574,14 @@
 
 	if (!(flags & (KGSL_MMUFLAGS_TLBFLUSH | KGSL_MMUFLAGS_PTUPDATE))
 		&& !adreno_is_a2xx(adreno_dev))
-		return 0;
+		return;
 
 	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
-		return 0;
+		return;
 	else if (device->ftbl->setstate)
-		return device->ftbl->setstate(device, context_id, flags);
+		device->ftbl->setstate(device, context_id, flags);
 	else if (mmu->mmu_ops->mmu_device_setstate)
-		return mmu->mmu_ops->mmu_device_setstate(mmu, flags);
-
-	return 0;
+		mmu->mmu_ops->mmu_device_setstate(mmu, flags);
 }
 EXPORT_SYMBOL(kgsl_setstate);
 
@@ -592,6 +590,7 @@
 	struct kgsl_mh *mh = &device->mh;
 	/* force mmu off to for now*/
 	kgsl_regwrite(device, MH_MMU_CONFIG, 0);
+	kgsl_idle(device);
 
 	/* define physical memory range accessible by the core */
 	kgsl_regwrite(device, MH_MMU_MPU_BASE, mh->mpu_base);
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index a30ee3f..faba81e 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -133,10 +133,10 @@
 	int (*mmu_close) (struct kgsl_mmu *mmu);
 	int (*mmu_start) (struct kgsl_mmu *mmu);
 	void (*mmu_stop) (struct kgsl_mmu *mmu);
-	int (*mmu_setstate) (struct kgsl_mmu *mmu,
+	void (*mmu_setstate) (struct kgsl_mmu *mmu,
 		struct kgsl_pagetable *pagetable,
 		unsigned int context_id);
-	int (*mmu_device_setstate) (struct kgsl_mmu *mmu,
+	void (*mmu_device_setstate) (struct kgsl_mmu *mmu,
 					uint32_t flags);
 	void (*mmu_pagefault) (struct kgsl_mmu *mmu);
 	phys_addr_t (*mmu_get_current_ptbase)
@@ -147,8 +147,6 @@
 		(struct kgsl_mmu *mmu, uint32_t ts, bool ts_valid);
 	int (*mmu_enable_clk)
 		(struct kgsl_mmu *mmu, int ctx_id);
-	void (*mmu_disable_clk)
-		(struct kgsl_mmu *mmu);
 	phys_addr_t (*mmu_get_default_ttbr0)(struct kgsl_mmu *mmu,
 				unsigned int unit_id,
 				enum kgsl_iommu_context_id ctx_id);
@@ -233,7 +231,7 @@
 int kgsl_mmu_put_gpuaddr(struct kgsl_pagetable *pagetable,
 		 struct kgsl_memdesc *memdesc);
 unsigned int kgsl_virtaddr_to_physaddr(void *virtaddr);
-int kgsl_setstate(struct kgsl_mmu *mmu, unsigned int context_id,
+void kgsl_setstate(struct kgsl_mmu *mmu, unsigned int context_id,
 			uint32_t flags);
 int kgsl_mmu_get_ptname_from_ptbase(struct kgsl_mmu *mmu,
 					phys_addr_t pt_base);
@@ -262,23 +260,19 @@
 		return 0;
 }
 
-static inline int kgsl_mmu_setstate(struct kgsl_mmu *mmu,
+static inline void kgsl_mmu_setstate(struct kgsl_mmu *mmu,
 			struct kgsl_pagetable *pagetable,
 			unsigned int context_id)
 {
 	if (mmu->mmu_ops && mmu->mmu_ops->mmu_setstate)
-		return mmu->mmu_ops->mmu_setstate(mmu, pagetable, context_id);
-
-	return 0;
+		mmu->mmu_ops->mmu_setstate(mmu, pagetable, context_id);
 }
 
-static inline int kgsl_mmu_device_setstate(struct kgsl_mmu *mmu,
+static inline void kgsl_mmu_device_setstate(struct kgsl_mmu *mmu,
 						uint32_t flags)
 {
 	if (mmu->mmu_ops && mmu->mmu_ops->mmu_device_setstate)
-		return mmu->mmu_ops->mmu_device_setstate(mmu, flags);
-
-	return 0;
+		mmu->mmu_ops->mmu_device_setstate(mmu, flags);
 }
 
 static inline void kgsl_mmu_stop(struct kgsl_mmu *mmu)
@@ -326,12 +320,6 @@
 		return 0;
 }
 
-static inline void kgsl_mmu_disable_clk(struct kgsl_mmu *mmu)
-{
-	if (mmu->mmu_ops && mmu->mmu_ops->mmu_disable_clk)
-		mmu->mmu_ops->mmu_disable_clk(mmu);
-}
-
 static inline void kgsl_mmu_disable_clk_on_ts(struct kgsl_mmu *mmu,
 						unsigned int ts, bool ts_valid)
 {
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 07131f7..6faf0bf 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1215,6 +1215,9 @@
 		} else {
 			device->pwrctrl.irq_last = 0;
 		}
+	} else if (device->state & (KGSL_STATE_HUNG |
+					KGSL_STATE_DUMP_AND_FT)) {
+		kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
 	}
 
 	mutex_unlock(&device->mutex);
@@ -1270,6 +1273,7 @@
 			kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
 			return -EBUSY;
 		}
+		del_timer_sync(&device->hang_timer);
 		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
 		kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_NAP);
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP);
@@ -1339,6 +1343,7 @@
 	case KGSL_STATE_NAP:
 	case KGSL_STATE_SLEEP:
 		del_timer_sync(&device->idle_timer);
+		del_timer_sync(&device->hang_timer);
 		/* make sure power is on to stop the device*/
 		kgsl_pwrctrl_enable(device);
 		device->ftbl->suspend_context(device);
@@ -1430,11 +1435,15 @@
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
 		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
 
+		mod_timer(&device->hang_timer,
+			(jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
 		pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma,
 				device->pwrctrl.pm_qos_latency);
 	case KGSL_STATE_ACTIVE:
 		kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
 		break;
+	case KGSL_STATE_INIT:
+		break;
 	default:
 		KGSL_PWR_WARN(device, "unhandled state %s\n",
 				kgsl_pwrstate_to_str(device->state));
@@ -1497,6 +1506,10 @@
 		return "SLEEP";
 	case KGSL_STATE_SUSPEND:
 		return "SUSPEND";
+	case KGSL_STATE_HUNG:
+		return "HUNG";
+	case KGSL_STATE_DUMP_AND_FT:
+		return "DNR";
 	case KGSL_STATE_SLUMBER:
 		return "SLUMBER";
 	default:
@@ -1526,9 +1539,13 @@
 
 	if ((atomic_read(&device->active_cnt) == 0) &&
 		(device->state != KGSL_STATE_ACTIVE)) {
-		mutex_unlock(&device->mutex);
-		wait_for_completion(&device->hwaccess_gate);
-		mutex_lock(&device->mutex);
+
+		if (device->state != KGSL_STATE_DUMP_AND_FT) {
+			mutex_unlock(&device->mutex);
+			wait_for_completion(&device->hwaccess_gate);
+			wait_for_completion(&device->ft_gate);
+			mutex_lock(&device->mutex);
+		}
 
 		/* Stop the idle timer */
 		del_timer_sync(&device->idle_timer);
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index dc3ad21..b7d7235 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -11,7 +11,6 @@
  *
  */
 
-#include <linux/err.h>
 #include <linux/file.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -282,65 +281,3 @@
 {
 	sync_timeline_destroy(context->timeline);
 }
-
-static void kgsl_sync_callback(struct sync_fence *fence,
-	struct sync_fence_waiter *waiter)
-{
-	struct kgsl_sync_fence_waiter *kwaiter =
-		(struct kgsl_sync_fence_waiter *) waiter;
-	kwaiter->func(kwaiter->priv);
-	sync_fence_put(kwaiter->fence);
-	kfree(kwaiter);
-}
-
-struct kgsl_sync_fence_waiter *kgsl_sync_fence_async_wait(int fd,
-	void (*func)(void *priv), void *priv)
-{
-	struct kgsl_sync_fence_waiter *kwaiter;
-	struct sync_fence *fence;
-	int status;
-
-	fence = sync_fence_fdget(fd);
-	if (fence == NULL)
-		return ERR_PTR(-EINVAL);
-
-	/* create the waiter */
-	kwaiter = kzalloc(sizeof(*kwaiter), GFP_ATOMIC);
-	if (kwaiter == NULL) {
-		sync_fence_put(fence);
-		return ERR_PTR(-ENOMEM);
-	}
-	kwaiter->fence = fence;
-	kwaiter->priv = priv;
-	kwaiter->func = func;
-	sync_fence_waiter_init((struct sync_fence_waiter *) kwaiter,
-		kgsl_sync_callback);
-
-	/* if status then error or signaled */
-	status = sync_fence_wait_async(fence,
-		(struct sync_fence_waiter *) kwaiter);
-	if (status) {
-		kfree(kwaiter);
-		sync_fence_put(fence);
-		if (status < 0)
-			kwaiter = ERR_PTR(status);
-		else
-			kwaiter = NULL;
-	}
-
-	return kwaiter;
-}
-
-int kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_waiter *kwaiter)
-{
-	if (kwaiter == NULL)
-		return 0;
-
-	if (sync_fence_cancel_async(kwaiter->fence,
-		(struct sync_fence_waiter *) kwaiter) == 0) {
-		sync_fence_put(kwaiter->fence);
-		kfree(kwaiter);
-		return 1;
-	}
-	return 0;
-}
diff --git a/drivers/gpu/msm/kgsl_sync.h b/drivers/gpu/msm/kgsl_sync.h
index 275eaf0..63adf06 100644
--- a/drivers/gpu/msm/kgsl_sync.h
+++ b/drivers/gpu/msm/kgsl_sync.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -28,13 +28,6 @@
 	unsigned int timestamp;
 };
 
-struct kgsl_sync_fence_waiter {
-	struct sync_fence_waiter waiter;
-	struct sync_fence *fence;
-	void (*func)(void *priv);
-	void *priv;
-};
-
 #if defined(CONFIG_SYNC)
 struct sync_pt *kgsl_sync_pt_create(struct sync_timeline *timeline,
 	unsigned int timestamp);
@@ -46,9 +39,6 @@
 void kgsl_sync_timeline_signal(struct sync_timeline *timeline,
 	unsigned int timestamp);
 void kgsl_sync_timeline_destroy(struct kgsl_context *context);
-struct kgsl_sync_fence_waiter *kgsl_sync_fence_async_wait(int fd,
-	void (*func)(void *priv), void *priv);
-int kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_waiter *waiter);
 #else
 static inline struct sync_pt
 *kgsl_sync_pt_create(struct sync_timeline *timeline, unsigned int timestamp)
@@ -82,20 +72,6 @@
 static inline void kgsl_sync_timeline_destroy(struct kgsl_context *context)
 {
 }
-
-static inline struct
-kgsl_sync_fence_waiter *kgsl_sync_fence_async_wait(int fd,
-	void (*func)(void *priv), void *priv)
-{
-	return NULL;
-}
-
-static inline int
-kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_waiter *waiter)
-{
-	return 1;
-}
-
 #endif
 
 #endif /* __KGSL_SYNC_H */
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 5f39b8b..f16f2b4 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -37,13 +37,14 @@
 
 	TP_PROTO(struct kgsl_device *device,
 			int drawctxt_id,
-			struct kgsl_cmdbatch *cmdbatch,
+			struct kgsl_ibdesc *ibdesc,
+			int numibs,
 			int timestamp,
 			int flags,
 			int result,
 			unsigned int type),
 
-	TP_ARGS(device, drawctxt_id, cmdbatch, timestamp, flags,
+	TP_ARGS(device, drawctxt_id, ibdesc, numibs, timestamp, flags,
 		result, type),
 
 	TP_STRUCT__entry(
@@ -60,8 +61,8 @@
 	TP_fast_assign(
 		__assign_str(device_name, device->name);
 		__entry->drawctxt_id = drawctxt_id;
-		__entry->ibdesc_addr = cmdbatch->ibdesc[0].gpuaddr;
-		__entry->numibs = cmdbatch->ibcount;
+		__entry->ibdesc_addr = ibdesc[0].gpuaddr;
+		__entry->numibs = numibs;
 		__entry->timestamp = timestamp;
 		__entry->flags = flags;
 		__entry->result = result;
@@ -730,46 +731,42 @@
 );
 
 TRACE_EVENT(kgsl_register_event,
-		TP_PROTO(unsigned int id, unsigned int timestamp, void *func),
-		TP_ARGS(id, timestamp, func),
+		TP_PROTO(unsigned int id, unsigned int timestamp),
+		TP_ARGS(id, timestamp),
 		TP_STRUCT__entry(
 			__field(unsigned int, id)
 			__field(unsigned int, timestamp)
-			__field(void *, func)
 		),
 		TP_fast_assign(
 			__entry->id = id;
 			__entry->timestamp = timestamp;
-			__entry->func = func;
 		),
 		TP_printk(
-			"ctx=%u ts=%u cb=%pF",
-			__entry->id, __entry->timestamp, __entry->func)
+			"ctx=%u ts=%u",
+			__entry->id, __entry->timestamp)
 );
 
 TRACE_EVENT(kgsl_fire_event,
 		TP_PROTO(unsigned int id, unsigned int ts,
-			unsigned int type, unsigned int age, void *func),
-		TP_ARGS(id, ts, type, age, func),
+			unsigned int type, unsigned int age),
+		TP_ARGS(id, ts, type, age),
 		TP_STRUCT__entry(
 			__field(unsigned int, id)
 			__field(unsigned int, ts)
 			__field(unsigned int, type)
 			__field(unsigned int, age)
-			__field(void *, func)
 		),
 		TP_fast_assign(
 			__entry->id = id;
 			__entry->ts = ts;
 			__entry->type = type;
 			__entry->age = age;
-			__entry->func = func;
 		),
 		TP_printk(
-			"ctx=%u ts=%u type=%s age=%u cb=%pF",
+			"ctx=%u ts=%u type=%s age=%u",
 			__entry->id, __entry->ts,
 			__print_symbolic(__entry->type, KGSL_EVENT_TYPES),
-			__entry->age, __entry->func)
+			__entry->age)
 );
 
 TRACE_EVENT(kgsl_active_count,
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 0af57aa..103a751 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -124,6 +124,8 @@
 	| (MMU_CONFIG << MH_MMU_CONFIG__TC_R_CLNT_BEHAVIOR__SHIFT)   \
 	| (MMU_CONFIG << MH_MMU_CONFIG__PA_W_CLNT_BEHAVIOR__SHIFT))
 
+#define KGSL_LOG_LEVEL_DEFAULT 3
+
 static const struct kgsl_functable z180_functable;
 
 static struct z180_device device_2d0 = {
@@ -149,6 +151,13 @@
 		},
 		.iomemname = KGSL_2D0_REG_MEMORY,
 		.ftbl = &z180_functable,
+		.cmd_log = KGSL_LOG_LEVEL_DEFAULT,
+		.ctxt_log = KGSL_LOG_LEVEL_DEFAULT,
+		.drv_log = KGSL_LOG_LEVEL_DEFAULT,
+		.mem_log = KGSL_LOG_LEVEL_DEFAULT,
+		.pwr_log = KGSL_LOG_LEVEL_DEFAULT,
+		.ft_log = KGSL_LOG_LEVEL_DEFAULT,
+		.pm_dump_enable = 0,
 	},
 	.cmdwin_lock = __SPIN_LOCK_INITIALIZER(device_2d1.cmdwin_lock),
 };
@@ -353,13 +362,7 @@
 	return ts_diff < Z180_PACKET_COUNT;
 }
 
-/**
- * z180_idle() - Idle the 2D device
- * @device: Pointer to the KGSL device struct for the Z180
- *
- * wait until the z180 submission queue is idle
- */
-int z180_idle(struct kgsl_device *device)
+static int z180_idle(struct kgsl_device *device)
 {
 	int status = 0;
 	struct z180_device *z180_dev = Z180_DEVICE(device);
@@ -379,8 +382,10 @@
 int
 z180_cmdstream_issueibcmds(struct kgsl_device_private *dev_priv,
 			struct kgsl_context *context,
-			struct kgsl_cmdbatch *cmdbatch,
-			uint32_t *timestamp)
+			struct kgsl_ibdesc *ibdesc,
+			unsigned int numibs,
+			uint32_t *timestamp,
+			unsigned int ctrl)
 {
 	long result = 0;
 	unsigned int ofs        = PACKETSIZE_STATESTREAM * sizeof(unsigned int);
@@ -393,20 +398,6 @@
 	struct kgsl_pagetable *pagetable = dev_priv->process_priv->pagetable;
 	struct z180_device *z180_dev = Z180_DEVICE(device);
 	unsigned int sizedwords;
-	unsigned int numibs;
-	struct kgsl_ibdesc *ibdesc;
-
-	mutex_lock(&device->mutex);
-
-	kgsl_active_count_get(device);
-
-	if (cmdbatch == NULL) {
-		result = EINVAL;
-		goto error;
-	}
-
-	ibdesc = cmdbatch->ibdesc;
-	numibs = cmdbatch->ibcount;
 
 	if (device->state & KGSL_STATE_HUNG) {
 		result = -EINVAL;
@@ -448,7 +439,7 @@
 		context->id, cmd, sizedwords);
 	/* context switch */
 	if ((context->id != (int)z180_dev->ringbuffer.prevctx) ||
-	    (cmdbatch->flags & KGSL_CONTEXT_CTX_SWITCH)) {
+	    (ctrl & KGSL_CONTEXT_CTX_SWITCH)) {
 		KGSL_CMD_INFO(device, "context switch %d -> %d\n",
 			context->id, z180_dev->ringbuffer.prevctx);
 		kgsl_mmu_setstate(&device->mmu, pagetable,
@@ -456,13 +447,10 @@
 		cnt = PACKETSIZE_STATESTREAM;
 		ofs = 0;
 	}
-
-	result = kgsl_setstate(&device->mmu,
+	kgsl_setstate(&device->mmu,
 			KGSL_MEMSTORE_GLOBAL,
 			kgsl_mmu_pt_get_flags(device->mmu.hwpagetable,
 			device->id));
-	if (result < 0)
-		goto error;
 
 	result = wait_event_interruptible_timeout(device->wait_queue,
 				  room_in_rb(z180_dev),
@@ -503,12 +491,9 @@
 	z180_cmdwindow_write(device, ADDR_VGV3_CONTROL, cmd);
 	z180_cmdwindow_write(device, ADDR_VGV3_CONTROL, 0);
 error:
-	kgsl_trace_issueibcmds(device, context->id, cmdbatch,
-		*timestamp, cmdbatch->flags, result, 0);
 
-	kgsl_active_count_put(device);
-
-	mutex_unlock(&device->mutex);
+	kgsl_trace_issueibcmds(device, context->id, ibdesc, numibs,
+		*timestamp, ctrl, result, 0);
 
 	return (int)result;
 }
@@ -619,12 +604,8 @@
 
 static int z180_stop(struct kgsl_device *device)
 {
-	int ret;
-
 	device->ftbl->irqctrl(device, 0);
-	ret = z180_idle(device);
-	if (ret)
-		return ret;
+	z180_idle(device);
 
 	del_timer_sync(&device->idle_timer);
 
@@ -690,7 +671,7 @@
 	return status;
 }
 
-static bool z180_isidle(struct kgsl_device *device)
+static unsigned int z180_isidle(struct kgsl_device *device)
 {
 	struct z180_device *z180_dev = Z180_DEVICE(device);
 
@@ -903,7 +884,7 @@
 	return context;
 }
 
-static int
+static void
 z180_drawctxt_detach(struct kgsl_context *context)
 {
 	struct kgsl_device *device;
@@ -917,13 +898,9 @@
 	if (z180_dev->ringbuffer.prevctx == context->id) {
 		z180_dev->ringbuffer.prevctx = Z180_INVALID_CONTEXT;
 		device->mmu.hwpagetable = device->mmu.defaultpagetable;
-
-		/* Ignore the result - we are going down anyway */
 		kgsl_setstate(&device->mmu, KGSL_MEMSTORE_GLOBAL,
 				KGSL_MMUFLAGS_PTUPDATE);
 	}
-
-	return 0;
 }
 
 static void
@@ -997,7 +974,6 @@
 	.irqctrl = z180_irqctrl,
 	.gpuid = z180_gpuid,
 	.irq_handler = z180_irq_handler,
-	.drain = z180_idle, /* drain == idle for the z180 */
 	/* Optional functions */
 	.drawctxt_create = z180_drawctxt_create,
 	.drawctxt_detach = z180_drawctxt_detach,
diff --git a/drivers/gpu/msm/z180.h b/drivers/gpu/msm/z180.h
index a36e92d..1be0870 100644
--- a/drivers/gpu/msm/z180.h
+++ b/drivers/gpu/msm/z180.h
@@ -45,6 +45,5 @@
 };
 
 int z180_dump(struct kgsl_device *, int);
-int z180_idle(struct kgsl_device *);
 
 #endif /* __Z180_H */
diff --git a/drivers/gpu/msm/z180_postmortem.c b/drivers/gpu/msm/z180_postmortem.c
index bc53c0e..5d929cf 100644
--- a/drivers/gpu/msm/z180_postmortem.c
+++ b/drivers/gpu/msm/z180_postmortem.c
@@ -58,8 +58,6 @@
 	unsigned int i;
 	unsigned int reg_val;
 
-	z180_idle(device);
-
 	KGSL_LOG_DUMP(device, "Z180 Register Dump\n");
 	for (i = 0; i < ARRAY_SIZE(regs_to_dump); i++) {
 		kgsl_regread(device,
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 8b0fcf4..9e0be59 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -131,57 +131,111 @@
 };
 
 static const struct qpnp_vadc_map_pt adcmap_qrd_btm_threshold[] = {
-	{-200,	1672},
-	{-180,	1656},
-	{-160,	1639},
-	{-140,	1620},
-	{-120,	1599},
-	{-100,	1577},
-	{-80,	1553},
-	{-60,	1527},
-	{-40,	1550},
-	{-20,	1471},
-	{0,	1440},
-	{20,	1408},
-	{40,	1374},
-	{60,	1339},
-	{80,	1303},
-	{100,	1266},
-	{120,	1228},
-	{140,	1190},
-	{160,	1150},
-	{180,	1111},
-	{200,	1071},
-	{220,	1032},
-	{240,	992},
-	{260,	953},
-	{280,	915},
-	{300,	877},
-	{320,	841},
-	{340,	805},
-	{360,	770},
-	{380,	736},
-	{400,	704},
-	{420,	673},
-	{440,	643},
-	{460,	614},
-	{480,	587},
-	{500,	561},
-	{520,	536},
-	{540,	513},
-	{560,	491},
-	{580,	470},
-	{600,	450},
-	{620,	431},
-	{640,	414},
-	{660,	397},
-	{680,	382},
-	{700,	367},
-	{720,	353},
-	{740,	340},
-	{760,	328},
-	{780,	317},
-	{800,	306},
+	{-200,	1540},
+	{-180,	1517},
+	{-160,	1492},
+	{-140,	1467},
+	{-120,	1440},
+	{-100,	1412},
+	{-80,	1383},
+	{-60,	1353},
+	{-40,	1323},
+	{-20,	1292},
+	{0,	1260},
+	{20,	1228},
+	{40,	1196},
+	{60,	1163},
+	{80,	1131},
+	{100,	1098},
+	{120,	1066},
+	{140,	1034},
+	{160,	1002},
+	{180,	971},
+	{200,	941},
+	{220,	911},
+	{240,	882},
+	{260,	854},
+	{280,	826},
+	{300,	800},
+	{320,	774},
+	{340,	749},
+	{360,	726},
+	{380,	703},
+	{400,	681},
+	{420,	660},
+	{440,	640},
+	{460,	621},
+	{480,	602},
+	{500,	585},
+	{520,	568},
+	{540,	552},
+	{560,	537},
+	{580,	523},
+	{600,	510},
+	{620,	497},
+	{640,	485},
+	{660,	473},
+	{680,	462},
+	{700,	452},
+	{720,	442},
+	{740,	433},
+	{760,	424},
+	{780,	416},
+	{800,	408},
+};
+
+static const struct qpnp_vadc_map_pt adcmap_qrd_skuaa_btm_threshold[] = {
+	{-200,	1476},
+	{-180,	1450},
+	{-160,	1422},
+	{-140,	1394},
+	{-120,	1365},
+	{-100,	1336},
+	{-80,	1306},
+	{-60,	1276},
+	{-40,	1246},
+	{-20,	1216},
+	{0,	1185},
+	{20,	1155},
+	{40,	1126},
+	{60,	1096},
+	{80,	1068},
+	{100,	1040},
+	{120,	1012},
+	{140,	986},
+	{160,	960},
+	{180,	935},
+	{200,	911},
+	{220,	888},
+	{240,	866},
+	{260,	844},
+	{280,	824},
+	{300,	805},
+	{320,	786},
+	{340,	769},
+	{360,	752},
+	{380,	737},
+	{400,	722},
+	{420,	707},
+	{440,	694},
+	{460,	681},
+	{480,	669},
+	{500,	658},
+	{520,	648},
+	{540,	637},
+	{560,	628},
+	{580,	619},
+	{600,	611},
+	{620,	603},
+	{640,	595},
+	{660,	588},
+	{680,	582},
+	{700,	575},
+	{720,	569},
+	{740,	564},
+	{760,	559},
+	{780,	554},
+	{800,	549},
 };
 
 /* Voltage to temperature */
@@ -539,6 +593,25 @@
 }
 EXPORT_SYMBOL(qpnp_adc_scale_qrd_batt_therm);
 
+int32_t qpnp_adc_scale_qrd_skuaa_batt_therm(struct qpnp_vadc_chip *chip,
+		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)
+{
+	int64_t bat_voltage = 0;
+
+	bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
+			adc_properties, chan_properties);
+
+	return qpnp_adc_map_temp_voltage(
+			adcmap_qrd_skuaa_btm_threshold,
+			ARRAY_SIZE(adcmap_qrd_skuaa_btm_threshold),
+			bat_voltage,
+			&adc_chan_result->physical);
+}
+EXPORT_SYMBOL(qpnp_adc_scale_qrd_skuaa_batt_therm);
+
 int32_t qpnp_adc_scale_therm_pu1(struct qpnp_vadc_chip *chip,
 		int32_t adc_code,
 		const struct qpnp_adc_properties *adc_properties,
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 490a5ce..2d70faa 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -134,7 +134,8 @@
 	bool	ext_rsense;
 	u8	id;
 	u8	sys_gain;
-	u8	revision;
+	u8	revision_dig_major;
+	u8	revision_ana_minor;
 };
 
 struct qpnp_iadc_chip {
@@ -324,60 +325,243 @@
 	return 0;
 }
 
-static int32_t qpnp_iadc_comp(int64_t *result, struct qpnp_iadc_comp comp,
+#define QPNP_IADC_PM8941_3_1_REV2	3
+#define QPNP_IADC_PM8941_3_1_REV3	2
+#define QPNP_IADC_PM8026_1_REV2		1
+#define QPNP_IADC_PM8026_1_REV3		2
+#define QPNP_IADC_PM8026_2_REV2		4
+#define QPNP_IADC_PM8026_2_REV3		2
+#define QPNP_IADC_PM8110_1_REV2		2
+#define QPNP_IADC_PM8110_1_REV3		2
+
+#define QPNP_IADC_REV_ID_8941_3_1	1
+#define QPNP_IADC_REV_ID_8026_1_0	2
+#define QPNP_IADC_REV_ID_8026_2_0	3
+#define QPNP_IADC_REV_ID_8110_1_0	4
+
+static void qpnp_temp_comp_version_check(struct qpnp_iadc_chip *iadc,
+						int32_t *version)
+{
+	if ((iadc->iadc_comp.revision_dig_major ==
+			QPNP_IADC_PM8941_3_1_REV2) &&
+			(iadc->iadc_comp.revision_ana_minor ==
+			QPNP_IADC_PM8941_3_1_REV3))
+		*version = QPNP_IADC_REV_ID_8941_3_1;
+	else if ((iadc->iadc_comp.revision_dig_major ==
+			QPNP_IADC_PM8026_1_REV2) &&
+			(iadc->iadc_comp.revision_ana_minor ==
+			QPNP_IADC_PM8026_1_REV3))
+		*version = QPNP_IADC_REV_ID_8026_1_0;
+	else if ((iadc->iadc_comp.revision_dig_major ==
+			QPNP_IADC_PM8026_2_REV2) &&
+			(iadc->iadc_comp.revision_ana_minor ==
+			QPNP_IADC_PM8026_2_REV3))
+		*version = QPNP_IADC_REV_ID_8026_2_0;
+	else if ((iadc->iadc_comp.revision_dig_major ==
+			QPNP_IADC_PM8110_1_REV2) &&
+			(iadc->iadc_comp.revision_ana_minor ==
+			QPNP_IADC_PM8110_1_REV3))
+		*version = QPNP_IADC_REV_ID_8110_1_0;
+	else
+		*version = -EINVAL;
+
+	return;
+}
+
+#define QPNP_COEFF_1					969000
+#define QPNP_COEFF_2					32
+#define QPNP_COEFF_3_TYPEA				1700000
+#define QPNP_COEFF_3_TYPEB				1000000
+#define QPNP_COEFF_4					100
+#define QPNP_COEFF_5					15
+#define QPNP_COEFF_6					100000
+#define QPNP_COEFF_7					21
+#define QPNP_COEFF_8					100000000
+#define QPNP_COEFF_9					38
+#define QPNP_COEFF_10					40
+#define QPNP_COEFF_11					7
+#define QPNP_COEFF_12					11
+#define QPNP_COEFF_13					37
+#define QPNP_COEFF_14					39
+#define QPNP_COEFF_15					9
+#define QPNP_COEFF_16					11
+#define QPNP_COEFF_17					851200
+#define QPNP_COEFF_18					296500
+#define QPNP_COEFF_19					222400
+#define QPNP_COEFF_20					813800
+#define QPNP_COEFF_21					1059100
+#define QPNP_COEFF_22					5000000
+#define QPNP_COEFF_23					3722500
+#define QPNP_COEFF_24					84
+
+static int32_t qpnp_iadc_comp(int64_t *result, struct qpnp_iadc_chip *iadc,
 							int64_t die_temp)
 {
-	int64_t temp_var = 0, sign_coeff = 0, sys_gain_coeff = 0, old;
+	int64_t temp_var = 0, sys_gain_coeff = 0, old;
+	int32_t coeff_a = 0, coeff_b = 0;
+	int32_t version;
+
+	qpnp_temp_comp_version_check(iadc, &version);
+	if (version == -EINVAL)
+		return 0;
 
 	old = *result;
 	*result = *result * 1000000;
 
-	if (comp.revision == QPNP_IADC_VER_3_1) {
-		/* revision 3.1 */
-		if (comp.sys_gain > 127)
-			sys_gain_coeff = -QPNP_COEFF_6 * (comp.sys_gain - 128);
-		else
-			sys_gain_coeff = QPNP_COEFF_6 * comp.sys_gain;
-	} else if (comp.revision != QPNP_IADC_VER_3_0) {
-		/* unsupported revision, do not compensate */
-		*result = old;
-		return 0;
-	}
+	if (iadc->iadc_comp.sys_gain > 127)
+		sys_gain_coeff = -QPNP_COEFF_6 *
+				(iadc->iadc_comp.sys_gain - 128);
+	else
+		sys_gain_coeff = QPNP_COEFF_6 *
+				iadc->iadc_comp.sys_gain;
 
-	if (!comp.ext_rsense) {
-		/* internal rsense */
-		switch (comp.id) {
-		case COMP_ID_TSMC:
-			temp_var = ((QPNP_COEFF_2 * die_temp) -
-						QPNP_COEFF_3_TYPEB);
-		break;
+	switch (version) {
+	case QPNP_IADC_REV_ID_8941_3_1:
+		switch (iadc->iadc_comp.id) {
 		case COMP_ID_GF:
+			if (!iadc->iadc_comp.ext_rsense) {
+				/* internal rsense */
+				coeff_a = QPNP_COEFF_2;
+				coeff_b = -QPNP_COEFF_3_TYPEA;
+			} else {
+				if (*result < 0) {
+					/* charge */
+					coeff_a = QPNP_COEFF_5;
+					coeff_b = QPNP_COEFF_6;
+				} else {
+					/* discharge */
+					coeff_a = -QPNP_COEFF_7;
+					coeff_b = QPNP_COEFF_6;
+				}
+			}
+			break;
+		case COMP_ID_TSMC:
 		default:
-			temp_var = ((QPNP_COEFF_2 * die_temp) -
-						QPNP_COEFF_3_TYPEA);
-		break;
+			if (!iadc->iadc_comp.ext_rsense) {
+				/* internal rsense */
+				coeff_a = QPNP_COEFF_2;
+				coeff_b = -QPNP_COEFF_3_TYPEB;
+			} else {
+				if (*result < 0) {
+					/* charge */
+					coeff_a = QPNP_COEFF_5;
+					coeff_b = QPNP_COEFF_6;
+				} else {
+					/* discharge */
+					coeff_a = -QPNP_COEFF_7;
+					coeff_b = QPNP_COEFF_6;
+				}
+			}
+			break;
 		}
-		temp_var = div64_s64(temp_var, QPNP_COEFF_4);
-		if (comp.revision == QPNP_IADC_VER_3_0)
-			temp_var = QPNP_COEFF_1 * (1000000 - temp_var);
-		else if (comp.revision == QPNP_IADC_VER_3_1)
-			temp_var = 1000000 * (1000000 - temp_var);
-		*result = div64_s64(*result * 1000000, temp_var);
+		break;
+	case QPNP_IADC_REV_ID_8026_1_0:
+		/* pm8026 rev 1.0 */
+		switch (iadc->iadc_comp.id) {
+		case COMP_ID_GF:
+			if (!iadc->iadc_comp.ext_rsense) {
+				/* internal rsense */
+				if (*result < 0) {
+					/* charge */
+					coeff_a = QPNP_COEFF_9;
+					coeff_b = -QPNP_COEFF_17;
+				} else {
+					coeff_a = QPNP_COEFF_10;
+					coeff_b = QPNP_COEFF_18;
+				}
+			} else {
+				if (*result < 0) {
+					/* charge */
+					coeff_a = -QPNP_COEFF_11;
+					coeff_b = 0;
+				} else {
+					/* discharge */
+					coeff_a = -QPNP_COEFF_17;
+					coeff_b = -QPNP_COEFF_19;
+				}
+			}
+			break;
+		case COMP_ID_TSMC:
+		default:
+			if (!iadc->iadc_comp.ext_rsense) {
+				/* internal rsense */
+				if (*result < 0) {
+					/* charge */
+					coeff_a = QPNP_COEFF_13;
+					coeff_b = -QPNP_COEFF_20;
+				} else {
+					coeff_a = QPNP_COEFF_14;
+					coeff_b = QPNP_COEFF_21;
+				}
+			} else {
+				if (*result < 0) {
+					/* charge */
+					coeff_a = -QPNP_COEFF_15;
+					coeff_b = 0;
+				} else {
+					/* discharge */
+					coeff_a = -QPNP_COEFF_12;
+					coeff_b = -QPNP_COEFF_19;
+				}
+			}
+			break;
+		}
+		break;
+	case QPNP_IADC_REV_ID_8110_1_0:
+		/* pm8110 rev 1.0 */
+		switch (iadc->iadc_comp.id) {
+		case COMP_ID_GF:
+			if (!iadc->iadc_comp.ext_rsense) {
+				/* internal rsense */
+				if (*result < 0) {
+					/* charge */
+					coeff_a = QPNP_COEFF_24;
+					coeff_b = -QPNP_COEFF_22;
+				} else {
+					coeff_a = QPNP_COEFF_24;
+					coeff_b = -QPNP_COEFF_23;
+				}
+			}
+			break;
+		case COMP_ID_SMIC:
+		default:
+			if (!iadc->iadc_comp.ext_rsense) {
+				/* internal rsense */
+				if (*result < 0) {
+					/* charge */
+					coeff_a = QPNP_COEFF_24;
+					coeff_b = -QPNP_COEFF_22;
+				} else {
+					coeff_a = QPNP_COEFF_24;
+					coeff_b = -QPNP_COEFF_23;
+				}
+			}
+			break;
+		}
+		break;
+	default:
+	case QPNP_IADC_REV_ID_8026_2_0:
+		/* pm8026 rev 1.0 */
+		coeff_a = 0;
+		coeff_b = 0;
+		break;
 	}
 
-	sign_coeff = *result < 0 ? QPNP_COEFF_7 : QPNP_COEFF_5;
-	if (comp.ext_rsense) {
-		/* external rsense and current charging */
-		temp_var = div64_s64((-sign_coeff * die_temp) + QPNP_COEFF_8,
-						QPNP_COEFF_4);
-		temp_var = 1000000000 - temp_var;
-		if (comp.revision == QPNP_IADC_VER_3_1) {
-			sys_gain_coeff = (1000000 +
-				div64_s64(sys_gain_coeff, QPNP_COEFF_4));
-			temp_var = div64_s64(temp_var * sys_gain_coeff,
-				1000000000);
-		}
-		*result = div64_s64(*result, temp_var);
+	temp_var = (coeff_a * die_temp) + coeff_b;
+	temp_var = div64_s64(temp_var, QPNP_COEFF_4);
+	temp_var = 1000 * (1000000 - temp_var);
+
+	if (!iadc->iadc_comp.ext_rsense) {
+		/* internal rsense */
+		*result = div64_s64(*result * 1000, temp_var);
+	}
+
+	if (iadc->iadc_comp.ext_rsense) {
+		/* external rsense */
+		sys_gain_coeff = (1000000 +
+			div64_s64(sys_gain_coeff, QPNP_COEFF_4));
+		temp_var = div64_s64(temp_var * sys_gain_coeff, 1000000);
+		*result = div64_s64(*result * 1000, temp_var);
 	}
 	pr_debug("%lld compensated into %lld\n", old, *result);
 
@@ -386,7 +570,7 @@
 
 int32_t qpnp_iadc_comp_result(struct qpnp_iadc_chip *iadc, int64_t *result)
 {
-	return qpnp_iadc_comp(result, iadc->iadc_comp, iadc->die_temp);
+	return qpnp_iadc_comp(result, iadc, iadc->die_temp);
 }
 EXPORT_SYMBOL(qpnp_iadc_comp_result);
 
@@ -401,9 +585,16 @@
 	}
 
 	rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION2,
-						&iadc->iadc_comp.revision);
+					&iadc->iadc_comp.revision_dig_major);
 	if (rc < 0) {
-		pr_err("qpnp adc revision read failed with %d\n", rc);
+		pr_err("qpnp adc revision2 read failed with %d\n", rc);
+		return rc;
+	}
+
+	rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION3,
+					&iadc->iadc_comp.revision_ana_minor);
+	if (rc < 0) {
+		pr_err("qpnp adc revision3 read failed with %d\n", rc);
 		return rc;
 	}
 
@@ -417,9 +608,10 @@
 	if (iadc->external_rsense)
 		iadc->iadc_comp.ext_rsense = true;
 
-	pr_debug("fab id = %u, revision = %u, sys gain = %u, external_rsense = %d\n",
+	pr_debug("fab id = %u, revision_dig_major = %u, revision_ana_minor = %u sys gain = %u, external_rsense = %d\n",
 			iadc->iadc_comp.id,
-			iadc->iadc_comp.revision,
+			iadc->iadc_comp.revision_dig_major,
+			iadc->iadc_comp.revision_ana_minor,
 			iadc->iadc_comp.sys_gain,
 			iadc->iadc_comp.ext_rsense);
 	return rc;
@@ -571,6 +763,7 @@
 	return 0;
 }
 
+#define IADC_IDEAL_RAW_GAIN	3291
 int32_t qpnp_iadc_calibrate_for_trim(struct qpnp_iadc_chip *iadc,
 							bool batfet_closed)
 {
@@ -629,6 +822,12 @@
 		goto fail;
 	}
 
+	if (iadc->iadc_comp.revision_dig_major == QPNP_IADC_PM8026_2_REV2
+		&& iadc->iadc_comp.revision_ana_minor ==
+						QPNP_IADC_PM8026_2_REV3)
+		iadc->adc->calib.gain_raw =
+			iadc->adc->calib.offset_raw + IADC_IDEAL_RAW_GAIN;
+
 	pr_debug("raw gain:0x%x, raw offset:0x%x\n",
 		iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
 
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index c4a2567..e37f75a 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -113,6 +113,8 @@
 	u8				id;
 	struct work_struct		trigger_completion_work;
 	bool				vadc_poll_eoc;
+	u8				revision_ana_minor;
+	u8				revision_dig_major;
 	struct sensor_device_attribute	sens_attr[0];
 };
 
@@ -126,6 +128,7 @@
 	[SCALE_THERM_100K_PULLUP] = {qpnp_adc_scale_therm_pu2},
 	[SCALE_THERM_150K_PULLUP] = {qpnp_adc_scale_therm_pu1},
 	[SCALE_QRD_BATT_THERM] = {qpnp_adc_scale_qrd_batt_therm},
+	[SCALE_QRD_SKUAA_BATT_THERM] = {qpnp_adc_scale_qrd_skuaa_batt_therm},
 };
 
 static int32_t qpnp_vadc_read_reg(struct qpnp_vadc_chip *vadc, int16_t reg,
@@ -493,29 +496,189 @@
 	return 0;
 }
 
-static int32_t qpnp_vbat_sns_comp(int64_t *result, u8 id, int64_t die_temp)
+#define QPNP_VBAT_COEFF_1	3000
+#define QPNP_VBAT_COEFF_2	45810000
+#define QPNP_VBAT_COEFF_3	100000
+#define QPNP_VBAT_COEFF_4	3500
+#define QPNP_VBAT_COEFF_5	80000000
+#define QPNP_VBAT_COEFF_6	4400
+#define QPNP_VBAT_COEFF_7	32200000
+#define QPNP_VBAT_COEFF_8	3880
+#define QPNP_VBAT_COEFF_9	5770
+#define QPNP_VBAT_COEFF_10	3660
+#define QPNP_VBAT_COEFF_11	5320
+#define QPNP_VBAT_COEFF_12	8060000
+#define QPNP_VBAT_COEFF_13	102640000
+#define QPNP_VBAT_COEFF_14	22220000
+#define QPNP_VBAT_COEFF_15	83060000
+
+#define QPNP_VADC_REV_ID_8941_3_1	1
+#define QPNP_VADC_REV_ID_8026_1_0	2
+#define QPNP_VADC_REV_ID_8026_2_0	3
+
+static void qpnp_temp_comp_version_check(struct qpnp_vadc_chip *vadc,
+							int32_t *version)
+{
+	if (vadc->revision_dig_major == 3 &&
+			vadc->revision_ana_minor == 2)
+		*version = QPNP_VADC_REV_ID_8941_3_1;
+	else if (vadc->revision_dig_major == 1 &&
+			vadc->revision_ana_minor == 2)
+		*version = QPNP_VADC_REV_ID_8026_1_0;
+	else if (vadc->revision_dig_major == 2 &&
+			vadc->revision_ana_minor == 2)
+		*version = QPNP_VADC_REV_ID_8026_2_0;
+	else
+		*version = -EINVAL;
+
+	return;
+}
+
+static int32_t qpnp_ocv_comp(int64_t *result,
+			struct qpnp_vadc_chip *vadc, int64_t die_temp)
 {
 	int64_t temp_var = 0;
 	int64_t old = *result;
+	int32_t version;
+
+	qpnp_temp_comp_version_check(vadc, &version);
+	if (version == -EINVAL)
+		return 0;
 
 	if (die_temp < 25000)
 		return 0;
 
-	switch (id) {
-	case COMP_ID_TSMC:
-		temp_var = (((die_temp *
-			(-QPNP_VBAT_SNS_COEFF_1_TYPEB))
-			+ QPNP_VBAT_SNS_COEFF_2_TYPEB));
-	break;
+	if (die_temp > 60000)
+		die_temp = 60000;
+
+	switch (version) {
+	case QPNP_VADC_REV_ID_8941_3_1:
+		switch (vadc->id) {
+		case COMP_ID_TSMC:
+			temp_var = (((die_temp *
+			(-QPNP_VBAT_COEFF_4))
+			+ QPNP_VBAT_COEFF_5));
+			break;
+		default:
+		case COMP_ID_GF:
+			temp_var = (((die_temp *
+			(-QPNP_VBAT_COEFF_1))
+			+ QPNP_VBAT_COEFF_2));
+			break;
+		}
+		break;
+	case QPNP_VADC_REV_ID_8026_1_0:
+		switch (vadc->id) {
+		case COMP_ID_TSMC:
+			temp_var = (((die_temp *
+			(-QPNP_VBAT_COEFF_10))
+			- QPNP_VBAT_COEFF_14));
+			break;
+		default:
+		case COMP_ID_GF:
+			temp_var = (((die_temp *
+			(-QPNP_VBAT_COEFF_8))
+			+ QPNP_VBAT_COEFF_12));
+			break;
+		}
+		break;
+	case QPNP_VADC_REV_ID_8026_2_0:
+		switch (vadc->id) {
+		case COMP_ID_TSMC:
+			temp_var = ((die_temp - 2500) *
+			(-QPNP_VBAT_COEFF_10));
+			break;
+		default:
+		case COMP_ID_GF:
+			temp_var = ((die_temp - 2500) *
+			(-QPNP_VBAT_COEFF_8));
+			break;
+		}
+		break;
 	default:
-	case COMP_ID_GF:
-		temp_var = (((die_temp *
-			(-QPNP_VBAT_SNS_COEFF_1_TYPEA))
-			+ QPNP_VBAT_SNS_COEFF_2_TYPEA));
-	break;
+		temp_var = 0;
+		break;
 	}
 
-	temp_var = div64_s64(temp_var, QPNP_VBAT_SNS_COEFF_3);
+	temp_var = div64_s64(temp_var, QPNP_VBAT_COEFF_3);
+
+	temp_var = 1000000 + temp_var;
+
+	*result = *result * temp_var;
+
+	*result = div64_s64(*result, 1000000);
+	pr_debug("%lld compensated into %lld\n", old, *result);
+
+	return 0;
+}
+
+static int32_t qpnp_vbat_sns_comp(int64_t *result,
+			struct qpnp_vadc_chip *vadc, int64_t die_temp)
+{
+	int64_t temp_var = 0;
+	int64_t old = *result;
+	int32_t version;
+
+	qpnp_temp_comp_version_check(vadc, &version);
+	if (version == -EINVAL)
+		return 0;
+
+	if (die_temp < 25000)
+		return 0;
+
+	/* min(die_temp_c, 60_degC) */
+	if (die_temp > 60000)
+		die_temp = 60000;
+
+	switch (version) {
+	case QPNP_VADC_REV_ID_8941_3_1:
+		switch (vadc->id) {
+		case COMP_ID_TSMC:
+			temp_var = (die_temp *
+			(-QPNP_VBAT_COEFF_1));
+			break;
+		default:
+		case COMP_ID_GF:
+			temp_var = (((die_temp *
+			(-QPNP_VBAT_COEFF_6))
+			+ QPNP_VBAT_COEFF_7));
+			break;
+		}
+		break;
+	case QPNP_VADC_REV_ID_8026_1_0:
+		switch (vadc->id) {
+		case COMP_ID_TSMC:
+			temp_var = (((die_temp *
+			(-QPNP_VBAT_COEFF_11))
+			+ QPNP_VBAT_COEFF_15));
+			break;
+		default:
+		case COMP_ID_GF:
+			temp_var = (((die_temp *
+			(-QPNP_VBAT_COEFF_9))
+			+ QPNP_VBAT_COEFF_13));
+			break;
+		}
+		break;
+	case QPNP_VADC_REV_ID_8026_2_0:
+		switch (vadc->id) {
+		case COMP_ID_TSMC:
+			temp_var = ((die_temp - 2500) *
+			(-QPNP_VBAT_COEFF_11));
+			break;
+		default:
+		case COMP_ID_GF:
+			temp_var = ((die_temp - 2500) *
+			(-QPNP_VBAT_COEFF_9));
+			break;
+		}
+		break;
+	default:
+		temp_var = 0;
+		break;
+	}
+
+	temp_var = div64_s64(temp_var, QPNP_VBAT_COEFF_3);
 
 	temp_var = 1000000 + temp_var;
 
@@ -544,8 +707,7 @@
 		return rc;
 	}
 
-	rc = qpnp_vbat_sns_comp(result, vadc->id,
-					die_temp_result.physical);
+	rc = qpnp_ocv_comp(result, vadc, die_temp_result.physical);
 	if (rc < 0)
 		pr_err("Error with vbat compensation\n");
 
@@ -980,7 +1142,7 @@
 			return rc;
 		}
 
-		rc = qpnp_vbat_sns_comp(&result->physical, vadc->id,
+		rc = qpnp_vbat_sns_comp(&result->physical, vadc,
 						die_temp_result.physical);
 		if (rc < 0)
 			pr_err("Error with vbat compensation\n");
@@ -1233,6 +1395,20 @@
 	}
 	vadc->id = fab_id;
 
+	rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_REVISION2,
+					&vadc->revision_dig_major);
+	if (rc < 0) {
+		pr_err("qpnp adc dig_major rev read failed with %d\n", rc);
+		goto err_setup;
+	}
+
+	rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_REVISION3,
+					&vadc->revision_ana_minor);
+	if (rc < 0) {
+		pr_err("qpnp adc ana_minor rev read failed with %d\n", rc);
+		goto err_setup;
+	}
+
 	rc = qpnp_vadc_warm_rst_configure(vadc);
 	if (rc < 0) {
 		pr_err("Setting perp reset on warm reset failed %d\n", rc);
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index aaa2fc8..716ea0d 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -704,4 +704,14 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called stk3x1x.
 
+config SENSORS_CAPELLA_CM36283
+	tristate "CM36283 proximity and light sensor"
+	depends on I2C
+	default n
+	help
+	  Say Y here to enable the CM36283 Proximity
+	  Sensor with Ambient Light Sensor.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called CM36283.
 endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 445fba0..c927e0e 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -65,3 +65,4 @@
 obj-$(CONFIG_BMP18X_I2C)		+= bmp18x-i2c.o
 obj-$(CONFIG_SENSORS_MMA8X5X)	  	+= mma8x5x.o
 obj-$(CONFIG_SENSORS_STK3X1X)		+= stk3x1x.o
+obj-$(CONFIG_SENSORS_CAPELLA_CM36283)	+= cm36283.o
diff --git a/drivers/input/misc/cm36283.c b/drivers/input/misc/cm36283.c
index 6280013..d850a0e 100644
--- a/drivers/input/misc/cm36283.c
+++ b/drivers/input/misc/cm36283.c
@@ -2,7 +2,9 @@
  *
  * Copyright (C) 2012 Capella Microsystems Inc.
  * Author: Frank Hsieh <pengyueh@gmail.com>
- *                                    
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
  * may be copied, distributed, and modified under those terms.
@@ -27,15 +29,16 @@
 #include <linux/err.h>
 #include <linux/gpio.h>
 #include <linux/miscdevice.h>
-#include <linux/lightsensor.h>
 #include <linux/slab.h>
-#include <asm/uaccess.h>
-#include <asm/mach-types.h>
-#include <linux/cm36283.h>
-#include <linux/capella_cm3602.h>
-#include <asm/setup.h>
+#include <linux/regulator/consumer.h>
 #include <linux/wakelock.h>
 #include <linux/jiffies.h>
+#include <linux/cm36283.h>
+#include <linux/of_gpio.h>
+
+#include <asm/uaccess.h>
+#include <asm/mach-types.h>
+#include <asm/setup.h>
 
 #define D(x...) pr_info(x)
 
@@ -47,7 +50,37 @@
 #define CONTROL_ALS                   0x01
 #define CONTROL_PS                    0x02
 
+/* POWER SUPPLY VOLTAGE RANGE */
+#define CM36283_VDD_MIN_UV	2700000
+#define CM36283_VDD_MAX_UV	3300000
+#define CM36283_VI2C_MIN_UV	1750000
+#define CM36283_VI2C_MAX_UV	1950000
+
+/* cm36283 polling rate in ms */
+#define CM36283_LS_MIN_POLL_DELAY	1
+#define CM36283_LS_MAX_POLL_DELAY	1000
+#define CM36283_LS_DEFAULT_POLL_DELAY	100
+
+#define CM36283_PS_MIN_POLL_DELAY	1
+#define CM36283_PS_MAX_POLL_DELAY	1000
+#define CM36283_PS_DEFAULT_POLL_DELAY	100
+
 static int record_init_fail = 0;
+
+static const int als_range[] = {
+	[CM36283_ALS_IT0] = 6554,
+	[CM36283_ALS_IT1] = 3277,
+	[CM36283_ALS_IT2] = 1638,
+	[CM36283_ALS_IT3] = 819,
+};
+
+static const int als_sense[] = {
+	[CM36283_ALS_IT0] = 10,
+	[CM36283_ALS_IT1] = 20,
+	[CM36283_ALS_IT2] = 40,
+	[CM36283_ALS_IT3] = 80,
+};
+
 static void sensor_irq_do_work(struct work_struct *work);
 static DECLARE_WORK(sensor_irq_work, sensor_irq_do_work);
 
@@ -95,20 +128,30 @@
 
 	uint16_t ls_cmd;
 	uint8_t record_clear_int_fail;
+	bool polling;
+	atomic_t ls_poll_delay;
+	atomic_t ps_poll_delay;
+	struct regulator *vdd;
+	struct regulator *vio;
+	struct delayed_work ldwork;
+	struct delayed_work pdwork;
 };
 struct cm36283_info *lp_info;
 int fLevel=-1;
 static struct mutex als_enable_mutex, als_disable_mutex, als_get_adc_mutex;
 static struct mutex ps_enable_mutex, ps_disable_mutex, ps_get_adc_mutex;
 static struct mutex CM36283_control_mutex;
+static struct mutex wq_lock;
 static int lightsensor_enable(struct cm36283_info *lpi);
 static int lightsensor_disable(struct cm36283_info *lpi);
 static int initial_cm36283(struct cm36283_info *lpi);
 static void psensor_initial_cmd(struct cm36283_info *lpi);
+static int cm36283_power_set(struct cm36283_info *info, bool on);
 
 int32_t als_kadc;
 
-static int control_and_report(struct cm36283_info *lpi, uint8_t mode, uint16_t param);
+static int control_and_report(struct cm36283_info *lpi, uint8_t mode,
+		uint16_t param, int report);
 
 static int I2C_RxData(uint16_t slaveAddr, uint8_t cmd, uint8_t *rxData, int length)
 {
@@ -373,12 +416,91 @@
 {
 	struct cm36283_info *lpi = lp_info;
 	uint16_t intFlag;
-  _cm36283_I2C_Read_Word(lpi->slave_addr, INT_FLAG, &intFlag);
-	control_and_report(lpi, CONTROL_INT_ISR_REPORT, intFlag);  
-	  
+	_cm36283_I2C_Read_Word(lpi->slave_addr, INT_FLAG, &intFlag);
+	control_and_report(lpi, CONTROL_INT_ISR_REPORT, intFlag, 1);
+
 	enable_irq(lpi->irq);
 }
 
+static int get_als_range(void)
+{
+	uint16_t ls_conf;
+	int ret = 0;
+	int index = 0;
+	struct cm36283_info *lpi = lp_info;
+
+	ret = _cm36283_I2C_Read_Word(lpi->slave_addr, ALS_CONF, &ls_conf);
+	if (ret) {
+		dev_err(&lpi->i2c_client->dev, "read ALS_CONF from i2c error. %d\n",
+				ret);
+		return -EIO;
+	}
+
+	index = (ls_conf & 0xC0) >> 0x06;
+	return  als_range[index];
+}
+
+static int get_als_sense(void)
+{
+	uint16_t ls_conf;
+	int ret = 0;
+	int index = 0;
+	struct cm36283_info *lpi = lp_info;
+
+	ret = _cm36283_I2C_Read_Word(lpi->slave_addr, ALS_CONF, &ls_conf);
+	if (ret) {
+		dev_err(&lpi->i2c_client->dev, "read ALS_CONF from i2c error. %d\n",
+				ret);
+		return -EIO;
+	}
+
+	index = (ls_conf & 0xC0) >> 0x06;
+	return  als_sense[index];
+}
+
+static void psensor_delay_work_handler(struct work_struct *work)
+{
+	struct cm36283_info *lpi = lp_info;
+	uint16_t adc_value = 0;
+	int ret;
+
+	mutex_lock(&wq_lock);
+
+	ret = get_ps_adc_value(&adc_value);
+
+	mutex_unlock(&wq_lock);
+
+	if (ret >= 0) {
+		input_report_abs(lpi->ps_input_dev, ABS_DISTANCE,
+				adc_value > lpi->ps_close_thd_set ? 0 : 1);
+		input_sync(lpi->ps_input_dev);
+	}
+	schedule_delayed_work(&lpi->pdwork,
+			msecs_to_jiffies(atomic_read(&lpi->ps_poll_delay)));
+}
+
+static void lsensor_delay_work_handler(struct work_struct *work)
+{
+	struct cm36283_info *lpi = lp_info;
+	uint16_t adc_value = 0;
+	int sense;
+
+	mutex_lock(&wq_lock);
+
+	get_ls_adc_value(&adc_value, 0);
+	sense = get_als_sense();
+
+	mutex_unlock(&wq_lock);
+
+	if (sense > 0) {
+		lpi->current_adc = adc_value;
+		input_report_abs(lpi->ls_input_dev, ABS_MISC, adc_value/sense);
+		input_sync(lpi->ls_input_dev);
+	}
+	schedule_delayed_work(&lpi->ldwork,
+			msecs_to_jiffies(atomic_read(&lpi->ls_poll_delay)));
+}
+
 static irqreturn_t cm36283_irq_handler(int irq, void *data)
 {
 	struct cm36283_info *lpi = data;
@@ -422,33 +544,44 @@
 static int psensor_enable(struct cm36283_info *lpi)
 {
 	int ret = -EIO;
+	unsigned int delay;
 	
 	mutex_lock(&ps_enable_mutex);
 	D("[PS][CM36283] %s\n", __func__);
 
-	if ( lpi->ps_enable ) {
+	if (lpi->ps_enable) {
 		D("[PS][CM36283] %s: already enabled\n", __func__);
 		ret = 0;
-	} else
-  	ret = control_and_report(lpi, CONTROL_PS, 1);
-	
+	} else {
+		ret = control_and_report(lpi, CONTROL_PS, 1, 0);
+	}
+
 	mutex_unlock(&ps_enable_mutex);
+
+	delay = atomic_read(&lpi->ps_poll_delay);
+	if (lpi->polling)
+		schedule_delayed_work(&lpi->pdwork, msecs_to_jiffies(delay));
+
 	return ret;
 }
 
 static int psensor_disable(struct cm36283_info *lpi)
 {
 	int ret = -EIO;
-	
+
+	if (lpi->polling)
+		cancel_delayed_work_sync(&lpi->pdwork);
+
 	mutex_lock(&ps_disable_mutex);
 	D("[PS][CM36283] %s\n", __func__);
 
-	if ( lpi->ps_enable == 0 ) {
+	if (lpi->ps_enable == 0) {
 		D("[PS][CM36283] %s: already disabled\n", __func__);
 		ret = 0;
-	} else
-  	ret = control_and_report(lpi, CONTROL_PS,0);
-	
+	} else {
+		ret = control_and_report(lpi, CONTROL_PS, 0, 0);
+	}
+
 	mutex_unlock(&ps_disable_mutex);
 	return ret;
 }
@@ -572,6 +705,7 @@
 static int lightsensor_enable(struct cm36283_info *lpi)
 {
 	int ret = -EIO;
+	unsigned int delay;
 	
 	mutex_lock(&als_enable_mutex);
 	D("[LS][CM36283] %s\n", __func__);
@@ -579,10 +713,17 @@
 	if (lpi->als_enable) {
 		D("[LS][CM36283] %s: already enabled\n", __func__);
 		ret = 0;
-	} else
-  	ret = control_and_report(lpi, CONTROL_ALS, 1);
+	} else {
+		ret = control_and_report(lpi, CONTROL_ALS, 1, 0);
+	}
 	
 	mutex_unlock(&als_enable_mutex);
+
+	delay = atomic_read(&lpi->ls_poll_delay);
+	if (lpi->polling)
+		schedule_delayed_work(&lpi->ldwork,
+				msecs_to_jiffies(delay));
+
 	return ret;
 }
 
@@ -592,11 +733,15 @@
 	mutex_lock(&als_disable_mutex);
 	D("[LS][CM36283] %s\n", __func__);
 
+	if (lpi->polling)
+		cancel_delayed_work_sync(&lpi->ldwork);
+
 	if ( lpi->als_enable == 0 ) {
 		D("[LS][CM36283] %s: already disabled\n", __func__);
 		ret = 0;
-	} else
-    ret = control_and_report(lpi, CONTROL_ALS, 0);
+	} else {
+		ret = control_and_report(lpi, CONTROL_ALS, 0, 0);
+	}
 	
 	mutex_unlock(&als_disable_mutex);
 	return ret;
@@ -679,13 +824,14 @@
 	uint16_t value;
 	int ret;
 	struct cm36283_info *lpi = lp_info;
-	int intr_val;
-
-	intr_val = gpio_get_value(lpi->intr_pin);
+	int intr_val = -1;
 
 	get_ps_adc_value(&value);
+	if (gpio_is_valid(lpi->intr_pin))
+		intr_val = gpio_get_value(lpi->intr_pin);
 
-	ret = sprintf(buf, "ADC[0x%04X], ENABLE = %d, intr_pin = %d\n", value, lpi->ps_enable, intr_val);
+	ret = snprintf(buf, PAGE_SIZE, "ADC[0x%04X], ENABLE=%d intr_pin=%d\n",
+			value, lpi->ps_enable, intr_val);
 
 	return ret;
 }
@@ -1067,6 +1213,62 @@
 }
 static DEVICE_ATTR(ls_conf, 0664, ls_conf_show, ls_conf_store);
 
+static ssize_t ls_poll_delay_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cm36283_info *lpi = lp_info;
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			atomic_read(&lpi->ls_poll_delay));
+}
+
+static ssize_t ls_poll_delay_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct cm36283_info *lpi = lp_info;
+	unsigned long interval_ms;
+
+	if (kstrtoul(buf, 10, &interval_ms))
+		return -EINVAL;
+
+	if ((interval_ms < CM36283_LS_MIN_POLL_DELAY) ||
+			(interval_ms > CM36283_LS_MAX_POLL_DELAY))
+		return -EINVAL;
+
+	atomic_set(&lpi->ls_poll_delay, (unsigned int) interval_ms);
+	return count;
+}
+
+static DEVICE_ATTR(ls_poll_delay, 0664, ls_poll_delay_show,
+		ls_poll_delay_store);
+
+static ssize_t ps_poll_delay_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct cm36283_info *lpi = lp_info;
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			atomic_read(&lpi->ps_poll_delay));
+}
+
+static ssize_t ps_poll_delay_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct cm36283_info *lpi = lp_info;
+	unsigned long interval_ms;
+
+	if (kstrtoul(buf, 10, &interval_ms))
+		return -EINVAL;
+
+	if ((interval_ms < CM36283_PS_MIN_POLL_DELAY) ||
+			(interval_ms > CM36283_PS_MAX_POLL_DELAY))
+		return -EINVAL;
+
+	atomic_set(&lpi->ps_poll_delay, (unsigned int) interval_ms);
+	return count;
+}
+
+static DEVICE_ATTR(ps_poll_delay, 0664, ps_poll_delay_show,
+		ps_poll_delay_store);
+
 static ssize_t ls_fLevel_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
@@ -1094,6 +1296,7 @@
 static int lightsensor_setup(struct cm36283_info *lpi)
 {
 	int ret;
+	int range;
 
 	lpi->ls_input_dev = input_allocate_device();
 	if (!lpi->ls_input_dev) {
@@ -1104,7 +1307,9 @@
 	}
 	lpi->ls_input_dev->name = "cm36283-ls";
 	set_bit(EV_ABS, lpi->ls_input_dev->evbit);
-	input_set_abs_params(lpi->ls_input_dev, ABS_MISC, 0, 9, 0, 0);
+
+	range = get_als_range();
+	input_set_abs_params(lpi->ls_input_dev, ABS_MISC, 0, range, 0, 0);
 
 	ret = input_register_device(lpi->ls_input_dev);
 	if (ret < 0) {
@@ -1179,13 +1384,8 @@
 	D("[PS][CM36283] %s, INTERRUPT GPIO val = %d\n", __func__, val);
 
 	ret = _cm36283_I2C_Read_Word(lpi->slave_addr, ID_REG, &idReg);
-	if ((ret < 0) || (idReg != 0xC082)) {
-  		if (record_init_fail == 0)
-  			record_init_fail = 1;
-  		return -ENOMEM;/*If devices without cm36283 chip and did not probe driver*/	
-  }
-  
-	return 0;
+
+	return ret;
 }
 
 static int cm36283_setup(struct cm36283_info *lpi)
@@ -1219,14 +1419,15 @@
 	}
 	
 	/*Default disable P sensor and L sensor*/
-  ls_initial_cmd(lpi);
+	ls_initial_cmd(lpi);
 	psensor_initial_cmd(lpi);
 
-	ret = request_any_context_irq(lpi->irq,
-			cm36283_irq_handler,
-			IRQF_TRIGGER_LOW,
-			"cm36283",
-			lpi);
+	if (!lpi->polling)
+		ret = request_any_context_irq(lpi->irq,
+				cm36283_irq_handler,
+				IRQF_TRIGGER_LOW,
+				"cm36283",
+				lpi);
 	if (ret < 0) {
 		pr_err(
 			"[PS][CM36283 error]%s: req_irq(%d) fail for gpio %d (%d)\n",
@@ -1265,6 +1466,78 @@
 }
 #endif
 
+static int cm36283_parse_dt(struct device *dev,
+				struct cm36283_platform_data *pdata)
+{
+	struct device_node *np = dev->of_node;
+	u32	levels[CM36283_LEVELS_SIZE], i;
+	u32 temp_val;
+	int rc;
+
+	rc = of_get_named_gpio_flags(np, "capella,interrupt-gpio",
+			0, NULL);
+	if (rc < 0) {
+		dev_err(dev, "Unable to read interrupt pin number\n");
+		return rc;
+	} else {
+		pdata->intr = rc;
+	}
+
+	rc = of_property_read_u32_array(np, "capella,levels", levels,
+			CM36283_LEVELS_SIZE);
+	if (rc) {
+		dev_err(dev, "Unable to read levels data\n");
+		return rc;
+	} else {
+		for (i = 0; i < CM36283_LEVELS_SIZE; i++)
+			pdata->levels[i] = levels[i];
+	}
+
+	rc = of_property_read_u32(np, "capella,ps_close_thd_set", &temp_val);
+	if (rc) {
+		dev_err(dev, "Unable to read ps_close_thd_set\n");
+		return rc;
+	} else {
+		pdata->ps_close_thd_set = (u8)temp_val;
+	}
+
+	rc = of_property_read_u32(np, "capella,ps_away_thd_set", &temp_val);
+	if (rc) {
+		dev_err(dev, "Unable to read ps_away_thd_set\n");
+		return rc;
+	} else {
+		pdata->ps_away_thd_set = (u8)temp_val;
+	}
+
+	rc = of_property_read_u32(np, "capella,ls_cmd", &temp_val);
+	if (rc) {
+		dev_err(dev, "Unable to read ls_cmd\n");
+		return rc;
+	} else {
+		pdata->ls_cmd = (u16)temp_val;
+	}
+
+	rc = of_property_read_u32(np, "capella,ps_conf1_val", &temp_val);
+	if (rc) {
+		dev_err(dev, "Unable to read ps_conf1_val\n");
+		return rc;
+	} else {
+		pdata->ps_conf1_val = (u16)temp_val;
+	}
+
+	rc = of_property_read_u32(np, "capella,ps_conf3_val", &temp_val);
+	if (rc) {
+		dev_err(dev, "Unable to read ps_conf3_val\n");
+		return rc;
+	} else {
+		pdata->ps_conf3_val = (u16)temp_val;
+	}
+
+	pdata->polling = of_property_read_bool(np, "capella,use-polling");
+
+	return 0;
+}
+
 static int cm36283_probe(struct i2c_client *client,
 	const struct i2c_device_id *id)
 {
@@ -1282,12 +1555,29 @@
 	/*D("[CM36283] %s: client->irq = %d\n", __func__, client->irq);*/
 
 	lpi->i2c_client = client;
-	pdata = client->dev.platform_data;
-	if (!pdata) {
-		pr_err("[PS][CM36283 error]%s: Assign platform_data error!!\n",
-			__func__);
-		ret = -EBUSY;
-		goto err_platform_data_null;
+
+	if (client->dev.of_node) {
+		pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
+		if (!pdata) {
+			dev_err(&client->dev, "Failed to allocate memory for pdata\n");
+			ret = -ENOMEM;
+			goto err_platform_data_null;
+		}
+
+		ret = cm36283_parse_dt(&client->dev, pdata);
+		pdata->slave_addr = client->addr;
+		if (ret) {
+			dev_err(&client->dev, "Failed to get pdata from device tree\n");
+			goto err_parse_dt;
+		}
+	} else {
+		pdata = client->dev.platform_data;
+		if (!pdata) {
+			dev_err(&client->dev, "%s: Assign platform_data error!!\n",
+					__func__);
+			ret = -EBUSY;
+			goto err_platform_data_null;
+		}
 	}
 
 	lpi->irq = client->irq;
@@ -1304,6 +1594,12 @@
 	lpi->ps_close_thd_set = pdata->ps_close_thd_set;	
 	lpi->ps_conf1_val = pdata->ps_conf1_val;
 	lpi->ps_conf3_val = pdata->ps_conf3_val;
+	lpi->polling = pdata->polling;
+	atomic_set(&lpi->ls_poll_delay,
+			(unsigned int) CM36283_LS_DEFAULT_POLL_DELAY);
+	atomic_set(&lpi->ps_poll_delay,
+			(unsigned int) CM36283_PS_DEFAULT_POLL_DELAY);
+
 	
 	lpi->ls_cmd  = pdata->ls_cmd;
 	
@@ -1324,23 +1620,11 @@
 	mutex_init(&als_disable_mutex);
 	mutex_init(&als_get_adc_mutex);
 
-	ret = lightsensor_setup(lpi);
-	if (ret < 0) {
-		pr_err("[LS][CM36283 error]%s: lightsensor_setup error!!\n",
-			__func__);
-		goto err_lightsensor_setup;
-	}
 
 	mutex_init(&ps_enable_mutex);
 	mutex_init(&ps_disable_mutex);
 	mutex_init(&ps_get_adc_mutex);
 
-	ret = psensor_setup(lpi);
-	if (ret < 0) {
-		pr_err("[PS][CM36283 error]%s: psensor_setup error!!\n",
-			__func__);
-		goto err_psensor_setup;
-	}
 
   //SET LUX STEP FACTOR HERE
   // if adc raw value one step = 5/100 = 1/20 = 0.05 lux
@@ -1370,11 +1654,32 @@
 	}
 	wake_lock_init(&(lpi->ps_wake_lock), WAKE_LOCK_SUSPEND, "proximity");
 
+	ret = cm36283_power_set(lpi, true);
+	if (ret < 0) {
+		dev_err(&client->dev, "%s:cm36283 power on error!\n", __func__);
+		goto err_cm36283_power_on;
+	}
+
 	ret = cm36283_setup(lpi);
 	if (ret < 0) {
 		pr_err("[PS_ERR][CM36283 error]%s: cm36283_setup error!\n", __func__);
 		goto err_cm36283_setup;
 	}
+
+	ret = lightsensor_setup(lpi);
+	if (ret < 0) {
+		pr_err("[LS][CM36283 error]%s: lightsensor_setup error!!\n",
+			__func__);
+		goto err_lightsensor_setup;
+	}
+
+	ret = psensor_setup(lpi);
+	if (ret < 0) {
+		pr_err("[PS][CM36283 error]%s: psensor_setup error!!\n",
+			__func__);
+		goto err_psensor_setup;
+	}
+
 	lpi->cm36283_class = class_create(THIS_MODULE, "optical_sensors");
 	if (IS_ERR(lpi->cm36283_class)) {
 		ret = PTR_ERR(lpi->cm36283_class);
@@ -1421,37 +1726,45 @@
 	if (ret)
 		goto err_create_ls_device_file;
 
+	ret = device_create_file(lpi->ls_dev, &dev_attr_ls_poll_delay);
+	if (ret)
+		goto err_create_ls_device_file;
+
 	lpi->ps_dev = device_create(lpi->cm36283_class,
 				NULL, 0, "%s", "proximity");
 	if (unlikely(IS_ERR(lpi->ps_dev))) {
 		ret = PTR_ERR(lpi->ps_dev);
 		lpi->ps_dev = NULL;
-		goto err_create_ls_device_file;
+		goto err_create_ps_device;
 	}
 
 	/* register the attributes */
 	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_adc);
 	if (ret)
-		goto err_create_ps_device;
+		goto err_create_ps_device_file;
 
 	ret = device_create_file(lpi->ps_dev,
 		&dev_attr_ps_parameters);
 	if (ret)
-		goto err_create_ps_device;
+		goto err_create_ps_device_file;
 
 	/* register the attributes */
 	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_conf);
 	if (ret)
-		goto err_create_ps_device;
+		goto err_create_ps_device_file;
 
 	/* register the attributes */
 	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_thd);
 	if (ret)
-		goto err_create_ps_device;
+		goto err_create_ps_device_file;
 
 	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_hw);
 	if (ret)
-		goto err_create_ps_device;
+		goto err_create_ps_device_file;
+
+	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_poll_delay);
+	if (ret)
+		goto err_create_ps_device_file;
 
 #ifdef CONFIG_HAS_EARLYSUSPEND
 	lpi->early_suspend.level =
@@ -1461,47 +1774,59 @@
 	register_early_suspend(&lpi->early_suspend);
 #endif
 
+	mutex_init(&wq_lock);
+	INIT_DELAYED_WORK(&lpi->ldwork, lsensor_delay_work_handler);
+	INIT_DELAYED_WORK(&lpi->pdwork, psensor_delay_work_handler);
 	D("[PS][CM36283] %s: Probe success!\n", __func__);
 
 	return ret;
 
-err_create_ps_device:
+err_create_ps_device_file:
 	device_unregister(lpi->ps_dev);
+err_create_ps_device:
 err_create_ls_device_file:
 	device_unregister(lpi->ls_dev);
 err_create_ls_device:
 	class_destroy(lpi->cm36283_class);
 err_create_class:
-err_cm36283_setup:
-	destroy_workqueue(lpi->lp_wq);
-	wake_lock_destroy(&(lpi->ps_wake_lock));
-
-	input_unregister_device(lpi->ls_input_dev);
-	input_free_device(lpi->ls_input_dev);
+	misc_deregister(&psensor_misc);
 	input_unregister_device(lpi->ps_input_dev);
 	input_free_device(lpi->ps_input_dev);
+err_psensor_setup:
+	misc_deregister(&lightsensor_misc);
+	input_unregister_device(lpi->ls_input_dev);
+	input_free_device(lpi->ls_input_dev);
+err_lightsensor_setup:
+err_cm36283_setup:
+	cm36283_power_set(lpi, false);
+err_cm36283_power_on:
+	wake_lock_destroy(&(lpi->ps_wake_lock));
+	destroy_workqueue(lpi->lp_wq);
 err_create_singlethread_workqueue:
 err_lightsensor_update_table:
-	misc_deregister(&psensor_misc);
-err_psensor_setup:
 	mutex_destroy(&CM36283_control_mutex);
-	mutex_destroy(&ps_enable_mutex);
-	mutex_destroy(&ps_disable_mutex);
-	mutex_destroy(&ps_get_adc_mutex);
-	misc_deregister(&lightsensor_misc);
-err_lightsensor_setup:
 	mutex_destroy(&als_enable_mutex);
 	mutex_destroy(&als_disable_mutex);
 	mutex_destroy(&als_get_adc_mutex);
+	mutex_destroy(&ps_enable_mutex);
+	mutex_destroy(&ps_disable_mutex);
+	mutex_destroy(&ps_get_adc_mutex);
+err_parse_dt:
+	if (client->dev.of_node && (pdata != NULL))
+		devm_kfree(&client->dev, pdata);
 err_platform_data_null:
 	kfree(lpi);
+	dev_err(&client->dev, "%s:error exit! ret = %d\n", __func__, ret);
+
 	return ret;
 }
-   
-static int control_and_report( struct cm36283_info *lpi, uint8_t mode, uint16_t param ) {
-  int ret=0;
+
+static int control_and_report(struct cm36283_info *lpi, uint8_t mode,
+	uint16_t param, int report)
+{
+	int ret = 0;
 	uint16_t adc_value = 0;
-	uint16_t ps_data = 0;	
+	uint16_t ps_data = 0;
 	int level = 0, i, val;
 	
   mutex_lock(&CM36283_control_mutex);
@@ -1566,77 +1891,212 @@
       		  }
       	  }
     	  }
-    
-    	  ret = set_lsensor_range(((i == 0) || (adc_value == 0)) ? 0 :
-    		   	*(lpi->cali_table + (i - 1)) + 1,
-    		    *(lpi->cali_table + i));
-    	  
-        lpi->ls_cmd |= CM36283_ALS_INT_EN;
-    	  
-        ret = _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF, lpi->ls_cmd);  
-    	  
-    		if ((i == 0) || (adc_value == 0))
-    			D("[LS][CM3628] %s: ADC=0x%03X, Level=%d, l_thd equal 0, h_thd = 0x%x \n",
-    				__func__, adc_value, level, *(lpi->cali_table + i));
-    		else
-    			D("[LS][CM3628] %s: ADC=0x%03X, Level=%d, l_thd = 0x%x, h_thd = 0x%x \n",
-    				__func__, adc_value, level, *(lpi->cali_table + (i - 1)) + 1, *(lpi->cali_table + i));
-    		lpi->current_level = level;
-    		lpi->current_adc = adc_value;    
-        input_report_abs(lpi->ls_input_dev, ABS_MISC, level);
-        input_sync(lpi->ls_input_dev);
+	if (!lpi->polling) {
+		ret = set_lsensor_range(((i == 0) ||
+					(adc_value == 0)) ? 0 :
+				*(lpi->cali_table + (i - 1)) + 1,
+				*(lpi->cali_table + i));
+
+		lpi->ls_cmd |= CM36283_ALS_INT_EN;
+	}
+
+	ret = _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF,
+			lpi->ls_cmd);
+
+	if (report) {
+		lpi->current_level = level;
+		lpi->current_adc = adc_value;
+		input_report_abs(lpi->ls_input_dev, ABS_MISC, level);
+		input_sync(lpi->ls_input_dev);
+	}
     }
   }
 
 #define PS_CLOSE 1
 #define PS_AWAY  (1<<1)
 #define PS_CLOSE_AND_AWAY PS_CLOSE+PS_AWAY
+	if (report && (lpi->ps_enable)) {
+		int ps_status = 0;
+		if (mode == CONTROL_PS)
+			ps_status = PS_CLOSE_AND_AWAY;
+		else if (mode == CONTROL_INT_ISR_REPORT) {
+			if (param & INT_FLAG_PS_IF_CLOSE)
+				ps_status |= PS_CLOSE;
+			if (param & INT_FLAG_PS_IF_AWAY)
+				ps_status |= PS_AWAY;
+		}
 
-  if(lpi->ps_enable){
-    int ps_status = 0;
-    if( mode == CONTROL_PS )
-      ps_status = PS_CLOSE_AND_AWAY;   
-    else if(mode == CONTROL_INT_ISR_REPORT ){  
-      if ( param & INT_FLAG_PS_IF_CLOSE )
-        ps_status |= PS_CLOSE;      
-      if ( param & INT_FLAG_PS_IF_AWAY )
-        ps_status |= PS_AWAY;
-    }
-      
-    if (ps_status!=0){
-      switch(ps_status){
-        case PS_CLOSE_AND_AWAY:
-          get_stable_ps_adc_value(&ps_data);
-          val = (ps_data >= lpi->ps_close_thd_set) ? 0 : 1;
-          break;
-        case PS_AWAY:
-          val = 1;
-          break;
-        case PS_CLOSE:
-          val = 0;
-          break;
-        };
-      input_report_abs(lpi->ps_input_dev, ABS_DISTANCE, val);      
-      input_sync(lpi->ps_input_dev);        
-    }
-  }
+		if (ps_status != 0) {
+			switch (ps_status) {
+			case PS_CLOSE_AND_AWAY:
+				get_stable_ps_adc_value(&ps_data);
+				val = (ps_data >= lpi->ps_close_thd_set)
+					? 0 : 1;
+				break;
+			case PS_AWAY:
+				val = 1;
+				break;
+			case PS_CLOSE:
+				val = 0;
+				break;
+			};
+			input_report_abs(lpi->ps_input_dev, ABS_DISTANCE, val);
+			input_sync(lpi->ps_input_dev);
+		}
+	}
 
-  mutex_unlock(&CM36283_control_mutex);
-  return ret;
+	mutex_unlock(&CM36283_control_mutex);
+	return ret;
 }
 
+static int cm36283_power_set(struct cm36283_info *info, bool on)
+{
+	int rc;
+
+	if (on) {
+		info->vdd = regulator_get(&info->i2c_client->dev, "vdd");
+		if (IS_ERR(info->vdd)) {
+			rc = PTR_ERR(info->vdd);
+			dev_err(&info->i2c_client->dev,
+				"Regulator get failed vdd rc=%d\n", rc);
+			goto err_vdd_get;
+		}
+
+		if (regulator_count_voltages(info->vdd) > 0) {
+			rc = regulator_set_voltage(info->vdd,
+					CM36283_VDD_MIN_UV, CM36283_VDD_MAX_UV);
+			if (rc) {
+				dev_err(&info->i2c_client->dev,
+					"Regulator set failed vdd rc=%d\n", rc);
+				goto err_vdd_set_vtg;
+			}
+		}
+
+		info->vio = regulator_get(&info->i2c_client->dev, "vio");
+		if (IS_ERR(info->vio)) {
+			rc = PTR_ERR(info->vio);
+			dev_err(&info->i2c_client->dev,
+				"Regulator get failed vio rc=%d\n", rc);
+			goto err_vio_get;
+		}
+
+		if (regulator_count_voltages(info->vio) > 0) {
+			rc = regulator_set_voltage(info->vio,
+				CM36283_VI2C_MIN_UV, CM36283_VI2C_MAX_UV);
+			if (rc) {
+				dev_err(&info->i2c_client->dev,
+				"Regulator set failed vio rc=%d\n", rc);
+				goto err_vio_set_vtg;
+			}
+		}
+
+		rc = regulator_enable(info->vdd);
+		if (rc) {
+			dev_err(&info->i2c_client->dev,
+				"Regulator vdd enable failed rc=%d\n", rc);
+			goto err_vdd_ena;
+		}
+
+		rc = regulator_enable(info->vio);
+		if (rc) {
+			dev_err(&info->i2c_client->dev,
+				"Regulator vio enable failed rc=%d\n", rc);
+			goto err_vio_ena;
+		}
+
+	} else {
+		rc = regulator_disable(info->vdd);
+		if (rc) {
+			dev_err(&info->i2c_client->dev,
+				"Regulator vdd disable failed rc=%d\n", rc);
+			return rc;
+		}
+		if (regulator_count_voltages(info->vdd) > 0)
+			regulator_set_voltage(info->vdd, 0, CM36283_VDD_MAX_UV);
+
+		regulator_put(info->vdd);
+
+		rc = regulator_disable(info->vio);
+		if (rc) {
+			dev_err(&info->i2c_client->dev,
+				"Regulator vio disable failed rc=%d\n", rc);
+			return rc;
+		}
+		if (regulator_count_voltages(info->vio) > 0)
+			regulator_set_voltage(info->vio, 0,
+					CM36283_VI2C_MAX_UV);
+
+		regulator_put(info->vio);
+	}
+
+	return 0;
+
+err_vio_ena:
+	regulator_disable(info->vdd);
+err_vdd_ena:
+	if (regulator_count_voltages(info->vio) > 0)
+		regulator_set_voltage(info->vio, 0, CM36283_VI2C_MAX_UV);
+err_vio_set_vtg:
+	regulator_put(info->vio);
+err_vio_get:
+	if (regulator_count_voltages(info->vdd) > 0)
+		regulator_set_voltage(info->vdd, 0, CM36283_VDD_MAX_UV);
+err_vdd_set_vtg:
+	regulator_put(info->vdd);
+err_vdd_get:
+	return rc;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int cm36283_suspend(struct device *dev)
+{
+	struct cm36283_info *lpi = lp_info;
+
+	if (lpi->als_enable) {
+		lightsensor_disable(lpi);
+		lpi->als_enable = 1;
+	}
+	cm36283_power_set(lpi, 0);
+
+	return 0;
+}
+
+static int cm36283_resume(struct device *dev)
+{
+	struct cm36283_info *lpi = lp_info;
+
+	cm36283_power_set(lpi, 1);
+
+	if (lpi->als_enable) {
+		cm36283_setup(lpi);
+		lightsensor_setup(lpi);
+		psensor_setup(lpi);
+		lightsensor_enable(lpi);
+	}
+	return 0;
+}
+#endif
+
+static UNIVERSAL_DEV_PM_OPS(cm36283_pm, cm36283_suspend, cm36283_resume, NULL);
 
 static const struct i2c_device_id cm36283_i2c_id[] = {
 	{CM36283_I2C_NAME, 0},
 	{}
 };
 
+static struct of_device_id cm36283_match_table[] = {
+	{ .compatible = "capella,cm36283",},
+	{ },
+};
+
 static struct i2c_driver cm36283_driver = {
 	.id_table = cm36283_i2c_id,
 	.probe = cm36283_probe,
 	.driver = {
 		.name = CM36283_I2C_NAME,
 		.owner = THIS_MODULE,
+		.pm = &cm36283_pm,
+		.of_match_table = cm36283_match_table,
 	},
 };
 
diff --git a/drivers/input/misc/mma8x5x.c b/drivers/input/misc/mma8x5x.c
index 4b78903..8775ab9 100644
--- a/drivers/input/misc/mma8x5x.c
+++ b/drivers/input/misc/mma8x5x.c
@@ -52,6 +52,8 @@
 #define MMA8X5X_STATUS_ZYXDR	0x08
 #define MMA8X5X_BUF_SIZE	7
 
+#define	MMA_SHUTTEDDOWN		(1 << 31)
+
 struct sensor_regulator {
 	struct regulator *vreg;
 	const char *name;
@@ -615,6 +617,9 @@
 	struct mma8x5x_data *pdata = i2c_get_clientdata(client);
 	if (pdata->active == MMA_ACTIVED)
 		mma8x5x_device_stop(client);
+	if (!mma8x5x_config_regulator(client, 0))
+		/* The highest bit sotres the power state */
+		pdata->active |= MMA_SHUTTEDDOWN;
 	return 0;
 }
 
@@ -623,11 +628,33 @@
 	int val = 0;
 	struct i2c_client *client = to_i2c_client(dev);
 	struct mma8x5x_data *pdata = i2c_get_clientdata(client);
+	if (pdata->active & MMA_SHUTTEDDOWN) {
+		if (mma8x5x_config_regulator(client, 1))
+			goto out;
+
+		if (i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, 0))
+			goto out;
+
+		if (i2c_smbus_write_byte_data(client, MMA8X5X_XYZ_DATA_CFG,
+				pdata->mode))
+			goto out;
+
+		/* The BT(boot time) for mma8x5x is 1.55ms according to
+		Freescale mma8450Q document. Document Number:MMA8450Q
+		Rev: 9.1, 04/2012
+		*/
+		usleep_range(1600, 2000);
+		pdata->active &= ~MMA_SHUTTEDDOWN;
+	}
 	if (pdata->active == MMA_ACTIVED) {
 		val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
 		i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, val|0x01);
 	}
+
 	return 0;
+out:
+	dev_err(&client->dev, "%s:failed during resume operation", __func__);
+	return -EIO;
 
 }
 #endif
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index ded2b6e..1537866 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -320,15 +320,19 @@
 		if (sensor->use_poll)
 			schedule_delayed_work(&sensor->input_work,
 				msecs_to_jiffies(sensor->poll_interval));
-		else
+		else {
 			i2c_smbus_write_byte_data(sensor->client,
 					MPU3050_INT_CFG,
 					MPU3050_ACTIVE_LOW |
 					MPU3050_OPEN_DRAIN |
 					MPU3050_RAW_RDY_EN);
+			enable_irq(sensor->client->irq);
+		}
 	} else {
 		if (sensor->use_poll)
 			cancel_delayed_work_sync(&sensor->input_work);
+		else
+			disable_irq(sensor->client->irq);
 		gpio_set_value(sensor->enable_gpio, 0);
 		pm_runtime_put(sensor->dev);
 	}
@@ -448,6 +452,7 @@
 		mpu3050_config_regulator(client, 1);
 		udelay(10);
 		gpio_set_value(sensor->enable_gpio, 1);
+		msleep(60);
 	}
 
 	value = i2c_smbus_read_byte_data(client, MPU3050_PWR_MGM);
@@ -709,7 +714,6 @@
 	}
 
 	mpu3050_set_power_mode(client, 1);
-	msleep(10);
 
 	ret = i2c_smbus_read_byte_data(client, MPU3050_CHIP_ID_REG);
 	if (ret < 0) {
@@ -792,6 +796,7 @@
 				client->irq, error);
 			goto err_pm_set_suspended;
 		}
+		disable_irq(client->irq);
 	}
 
 	error = input_register_device(idev);
@@ -864,6 +869,10 @@
 static int mpu3050_suspend(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
+	struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
+
+	if (!sensor->use_poll)
+		disable_irq(client->irq);
 
 	mpu3050_set_power_mode(client, 0);
 
@@ -879,9 +888,12 @@
 static int mpu3050_resume(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
+	struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
 
 	mpu3050_set_power_mode(client, 1);
-	msleep(100);  /* wait for gyro chip resume */
+
+	if (!sensor->use_poll)
+		enable_irq(client->irq);
 
 	return 0;
 }
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index b43c13e..9b0c5c7 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1008,4 +1008,16 @@
 
 	  If unsure, say N.
 
+config TOUCHSCREEN_GT9XX
+	bool "Goodix touchpanel GT9xx series"
+	depends on I2C
+	help
+	  Say Y here if you have a Goodix GT9xx touchscreen.
+	  Gt9xx controllers are multi touch controllers which can
+	  report 5 touches at a time.
+
+          If unsure, say N.
+
+source "drivers/input/touchscreen/gt9xx/Kconfig"
+
 endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 1f309d8..3acc612 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -82,3 +82,4 @@
 obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4)		+= synaptics_i2c_rmi4.o
 obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV)	+= synaptics_rmi_dev.o
 obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE) 	+= synaptics_fw_update.o
+obj-$(CONFIG_TOUCHSCREEN_GT9XX)		+= gt9xx/
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index b725200..06ca31c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -394,7 +394,7 @@
 	const char *fw_name;
 	bool no_force_update;
 	bool lpm_support;
-	bool regs_enabled;
+	bool dev_sleep;
 
 #if defined(CONFIG_SECURE_TOUCH)
 	atomic_t st_enabled;
@@ -2162,11 +2162,6 @@
 	if (on == false)
 		goto power_off;
 
-	if (data->regs_enabled) {
-		dev_dbg(&data->client->dev, "regs are already enabled\n");
-		return 0;
-	}
-
 	rc = reg_set_optimum_mode_check(data->vcc_ana, MXT_ACTIVE_LOAD_UA);
 	if (rc < 0) {
 		dev_err(&data->client->dev,
@@ -2215,8 +2210,6 @@
 		}
 	}
 
-	data->regs_enabled = true;
-
 	msleep(130);
 
 	return 0;
@@ -2237,12 +2230,6 @@
 	return rc;
 
 power_off:
-
-	if (!data->regs_enabled) {
-		dev_dbg(&data->client->dev, "regs are already disabled\n");
-		return 0;
-	}
-
 	reg_set_optimum_mode_check(data->vcc_ana, 0);
 	regulator_disable(data->vcc_ana);
 	if (data->pdata->digital_pwr_regulator) {
@@ -2254,8 +2241,6 @@
 		regulator_disable(data->vcc_i2c);
 	}
 
-	data->regs_enabled = false;
-
 	msleep(50);
 	return 0;
 }
@@ -2455,6 +2440,11 @@
 	struct input_dev *input_dev = data->input_dev;
 	int error;
 
+	if (data->dev_sleep) {
+		dev_dbg(dev, "Device already in sleep\n");
+		return 0;
+	}
+
 	disable_irq(data->irq);
 
 	mutex_lock(&input_dev->mutex);
@@ -2485,6 +2475,7 @@
 		}
 	}
 
+	data->dev_sleep = true;
 	return 0;
 }
 
@@ -2495,6 +2486,11 @@
 	struct input_dev *input_dev = data->input_dev;
 	int error;
 
+	if (!data->dev_sleep) {
+		dev_dbg(dev, "Device already in resume\n");
+		return 0;
+	}
+
 	/* put regulators back in active power mode */
 	if (data->lpm_support) {
 		error = mxt_regulator_lpm(data, false);
@@ -2538,6 +2534,7 @@
 
 	enable_irq(data->irq);
 
+	data->dev_sleep = false;
 	return 0;
 }
 
@@ -2924,6 +2921,7 @@
 	data->pdata = pdata;
 	data->no_force_update = pdata->no_force_update;
 	data->lpm_support = !pdata->no_lpm_support;
+	data->dev_sleep = false;
 
 	__set_bit(EV_ABS, input_dev->evbit);
 	__set_bit(EV_KEY, input_dev->evbit);
diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
index 83b2aa1..2f9ea10 100644
--- a/drivers/input/touchscreen/ft5x06_ts.c
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -41,22 +41,23 @@
 #define FT_SUSPEND_LEVEL 1
 #endif
 
-#define CFG_MAX_TOUCH_POINTS	5
+#define FT_DRIVER_VERSION	0x02
 
-#define FT_STARTUP_DLY		150
-#define FT_RESET_DLY		20
+#define FT_META_REGS		3
+#define FT_ONE_TCH_LEN		6
+#define FT_TCH_LEN(x)		(FT_META_REGS + FT_ONE_TCH_LEN * x)
 
 #define FT_PRESS		0x7F
 #define FT_MAX_ID		0x0F
-#define FT_TOUCH_STEP		6
 #define FT_TOUCH_X_H_POS	3
 #define FT_TOUCH_X_L_POS	4
 #define FT_TOUCH_Y_H_POS	5
 #define FT_TOUCH_Y_L_POS	6
+#define FT_TD_STATUS		2
 #define FT_TOUCH_EVENT_POS	3
 #define FT_TOUCH_ID_POS		5
-
-#define POINT_READ_BUF	(3 + FT_TOUCH_STEP * CFG_MAX_TOUCH_POINTS)
+#define FT_TOUCH_DOWN		0
+#define FT_TOUCH_CONTACT	2
 
 /*register address*/
 #define FT_REG_DEV_MODE		0x00
@@ -68,6 +69,9 @@
 #define FT_REG_THGROUP		0x80
 #define FT_REG_ECC		0xCC
 #define FT_REG_RESET_FW		0x07
+#define FT_REG_FW_MAJ_VER	0xB1
+#define FT_REG_FW_MIN_VER	0xB2
+#define FT_REG_FW_SUB_MIN_VER	0xB3
 
 /* power register bits*/
 #define FT_PMODE_ACTIVE		0x00
@@ -104,58 +108,14 @@
 #define FT_UPGRADE_AA		0xAA
 #define FT_UPGRADE_55		0x55
 
-/*upgrade config of FT5606*/
-#define FT5606_UPGRADE_AA_DELAY		50
-#define FT5606_UPGRADE_55_DELAY		10
-#define FT5606_UPGRADE_ID_1		0x79
-#define FT5606_UPGRADE_ID_2		0x06
-#define FT5606_UPGRADE_READID_DELAY	100
-#define FT5606_UPGRADE_EARSE_DELAY	2000
-
-/*upgrade config of FT5316*/
-#define FT5316_UPGRADE_AA_DELAY		50
-#define FT5316_UPGRADE_55_DELAY		30
-#define FT5316_UPGRADE_ID_1		0x79
-#define FT5316_UPGRADE_ID_2		0x07
-#define FT5316_UPGRADE_READID_DELAY	1
-#define FT5316_UPGRADE_EARSE_DELAY	1500
-
-/*upgrade config of FT5x06(x=2,3,4)*/
-#define FT5X06_UPGRADE_AA_DELAY		50
-#define FT5X06_UPGRADE_55_DELAY		30
-#define FT5X06_UPGRADE_ID_1		0x79
-#define FT5X06_UPGRADE_ID_2		0x03
-#define FT5X06_UPGRADE_READID_DELAY	1
-#define FT5X06_UPGRADE_EARSE_DELAY	2000
-
-/*upgrade config of FT6208*/
-#define FT6208_UPGRADE_AA_DELAY		60
-#define FT6208_UPGRADE_55_DELAY		10
-#define FT6208_UPGRADE_ID_1		0x79
-#define FT6208_UPGRADE_ID_2		0x05
-#define FT6208_UPGRADE_READID_DELAY	10
-#define FT6208_UPGRADE_EARSE_DELAY	2000
-
-/*upgrade config of FT6x06*/
-#define FT6X06_UPGRADE_AA_DELAY		100
-#define FT6X06_UPGRADE_55_DELAY		30
-#define FT6X06_UPGRADE_ID_1		0x79
-#define FT6X06_UPGRADE_ID_2		0x08
-#define FT6X06_UPGRADE_READID_DELAY	10
-#define FT6X06_UPGRADE_EARSE_DELAY	2000
-
-#define FT_UPGRADE_INFO(x, y)	do { \
-		x->delay_55 = y##_UPGRADE_55_DELAY; \
-		x->delay_aa = y##_UPGRADE_AA_DELAY; \
-		x->upgrade_id_1 = y##_UPGRADE_ID_1; \
-		x->upgrade_id_2 = y##_UPGRADE_ID_2; \
-		x->delay_readid = y##_UPGRADE_READID_DELAY; \
-		x->delay_earse_flash = y##_UPGRADE_EARSE_DELAY; \
-		} while (0)
-
 #define FT_FW_MIN_SIZE		8
 #define FT_FW_MAX_SIZE		32768
-#define FT_FW_FILE_VER(x)	((x)->data[(x)->size - 2])
+
+/* Firmware file is not supporting minor and sub minor so use 0 */
+#define FT_FW_FILE_MAJ_VER(x)	((x)->data[(x)->size - 2])
+#define FT_FW_FILE_MIN_VER(x)	0
+#define FT_FW_FILE_SUB_MIN_VER(x) 0
+
 #define FT_FW_CHECK(x)		\
 	(((x)->data[(x)->size - 8] ^ (x)->data[(x)->size - 6]) == 0xFF \
 	&& (((x)->data[(x)->size - 7] ^ (x)->data[(x)->size - 5]) == 0xFF \
@@ -180,39 +140,29 @@
 #define FT_REG_CAL		0x00
 #define FT_CAL_MASK		0x70
 
-#define FT_INFO_MAX_LEN		200
+#define FT_INFO_MAX_LEN		512
 
-#define FT_STORE_TS_INFO(buf, id, fw_ver) \
+#define FT_STORE_TS_INFO(buf, id, name, max_tch, group_id, fw_vkey_support, \
+			fw_name, fw_maj, fw_min, fw_sub_min) \
 			snprintf(buf, FT_INFO_MAX_LEN, \
 				"controller\t= focaltech\n" \
 				"model\t\t= 0x%x\n" \
-				"fw_ver\t\t= 0x%x\n", id, fw_ver)
+				"name\t\t= %s\n" \
+				"max_touches\t= %d\n" \
+				"drv_ver\t\t= 0x%x\n" \
+				"group_id\t= 0x%x\n" \
+				"fw_vkey_support\t= %s\n" \
+				"fw_name\t\t= %s\n" \
+				"fw_ver\t\t= %d.%d.%d\n", id, name, \
+				max_tch, FT_DRIVER_VERSION, group_id, \
+				fw_vkey_support, fw_name, fw_maj, fw_min, \
+				fw_sub_min)
 
 #define FT_DEBUG_DIR_NAME	"ts_debug"
 
-struct ts_event {
-	u16 x[CFG_MAX_TOUCH_POINTS];	/*x coordinate */
-	u16 y[CFG_MAX_TOUCH_POINTS];	/*y coordinate */
-	/* touch event: 0 -- down; 1-- contact; 2 -- contact */
-	u8 touch_event[CFG_MAX_TOUCH_POINTS];
-	u8 finger_id[CFG_MAX_TOUCH_POINTS];	/*touch ID */
-	u16 pressure;
-	u8 touch_point;
-};
-
-struct upgrade_info {
-	u16 delay_aa;		/*delay of write FT_UPGRADE_AA */
-	u16 delay_55;		/*delay of write FT_UPGRADE_55 */
-	u8 upgrade_id_1;	/*upgrade id 1 */
-	u8 upgrade_id_2;	/*upgrade id 2 */
-	u16 delay_readid;	/*delay of read id */
-	u16 delay_earse_flash; /*delay of earse flash*/
-};
-
 struct ft5x06_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input_dev;
-	struct ts_event event;
 	const struct ft5x06_ts_platform_data *pdata;
 	struct regulator *vdd;
 	struct regulator *vcc_i2c;
@@ -223,6 +173,9 @@
 	u16 addr;
 	bool suspended;
 	char *ts_info;
+	u8 *tch_data;
+	u32 tch_data_len;
+	u8 fw_ver[3];
 #if defined(CONFIG_FB)
 	struct notifier_block fb_notif;
 #elif defined(CONFIG_HAS_EARLYSUSPEND)
@@ -305,88 +258,92 @@
 	return ft5x06_i2c_read(client, &addr, 1, val, 1);
 }
 
-static void ft5x06_report_value(struct ft5x06_ts_data *data)
+static void ft5x06_update_fw_ver(struct ft5x06_ts_data *data)
 {
-	struct ts_event *event = &data->event;
-	int i;
-	int fingerdown = 0;
+	struct i2c_client *client = data->client;
+	u8 reg_addr;
+	int err;
 
-	for (i = 0; i < event->touch_point; i++) {
-		if (event->touch_event[i] == 0 || event->touch_event[i] == 2) {
-			event->pressure = FT_PRESS;
-			fingerdown++;
-		} else {
-			event->pressure = 0;
-		}
+	reg_addr = FT_REG_FW_MAJ_VER;
+	err = ft5x06_i2c_read(client, &reg_addr, 1, &data->fw_ver[0], 1);
+	if (err < 0)
+		dev_err(&client->dev, "fw major version read failed");
 
-		input_mt_slot(data->input_dev, event->finger_id[i]);
-		input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER,
-					!!event->pressure);
+	reg_addr = FT_REG_FW_MIN_VER;
+	err = ft5x06_i2c_read(client, &reg_addr, 1, &data->fw_ver[1], 1);
+	if (err < 0)
+		dev_err(&client->dev, "fw minor version read failed");
 
-		if (event->pressure == FT_PRESS) {
-			input_report_abs(data->input_dev, ABS_MT_POSITION_X,
-					 event->x[i]);
-			input_report_abs(data->input_dev, ABS_MT_POSITION_Y,
-					 event->y[i]);
-			input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR,
-					 event->pressure);
-		}
-	}
+	reg_addr = FT_REG_FW_SUB_MIN_VER;
+	err = ft5x06_i2c_read(client, &reg_addr, 1, &data->fw_ver[2], 1);
+	if (err < 0)
+		dev_err(&client->dev, "fw sub minor version read failed");
 
-	input_report_key(data->input_dev, BTN_TOUCH, !!fingerdown);
-	input_sync(data->input_dev);
-}
-
-static int ft5x06_handle_touchdata(struct ft5x06_ts_data *data)
-{
-	struct ts_event *event = &data->event;
-	int num_points;
-	int ret, i;
-	u8 buf[POINT_READ_BUF] = { 0 };
-	u8 pointid = FT_MAX_ID;
-
-	ret = ft5x06_i2c_read(data->client, buf, 1, buf, POINT_READ_BUF);
-	if (ret < 0) {
-		dev_err(&data->client->dev, "%s read touchdata failed.\n",
-			__func__);
-		return ret;
-	}
-	memset(event, 0, sizeof(struct ts_event));
-
-	event->touch_point = 0;
-	num_points = buf[2] & FT_STATUS_NUM_TP_MASK;
-
-	for (i = 0; i < num_points; i++) {
-		pointid = (buf[FT_TOUCH_ID_POS + FT_TOUCH_STEP * i]) >> 4;
-		if (pointid >= FT_MAX_ID)
-			break;
-		else
-			event->touch_point++;
-		event->x[i] =
-		    (s16) (buf[FT_TOUCH_X_H_POS + FT_TOUCH_STEP * i] & 0x0F) <<
-		    8 | (s16) buf[FT_TOUCH_X_L_POS + FT_TOUCH_STEP * i];
-		event->y[i] =
-		    (s16) (buf[FT_TOUCH_Y_H_POS + FT_TOUCH_STEP * i] & 0x0F) <<
-		    8 | (s16) buf[FT_TOUCH_Y_L_POS + FT_TOUCH_STEP * i];
-		event->touch_event[i] =
-		    buf[FT_TOUCH_EVENT_POS + FT_TOUCH_STEP * i] >> 6;
-		event->finger_id[i] =
-		    (buf[FT_TOUCH_ID_POS + FT_TOUCH_STEP * i]) >> 4;
-	}
-
-	ft5x06_report_value(data);
-
-	return 0;
+	dev_info(&client->dev, "Firmware version = %d.%d.%d\n",
+		data->fw_ver[0], data->fw_ver[1], data->fw_ver[2]);
 }
 
 static irqreturn_t ft5x06_ts_interrupt(int irq, void *dev_id)
 {
 	struct ft5x06_ts_data *data = dev_id;
-	int rc;
+	struct input_dev *ip_dev;
+	int rc, i;
+	u32 id, x, y, pressure, status, num_touches;
+	u8 reg = 0x00, *buf;
+	bool update_input = false;
 
-	rc = ft5x06_handle_touchdata(data);
-	if (rc)
-		pr_err("%s: handling touchdata failed\n", __func__);
+	if (!data) {
+		pr_err("%s: Invalid data\n", __func__);
+		return IRQ_HANDLED;
+	}
+
+	ip_dev = data->input_dev;
+	buf = data->tch_data;
+
+	rc = ft5x06_i2c_read(data->client, &reg, 1,
+			buf, data->tch_data_len);
+	if (rc < 0) {
+		dev_err(&data->client->dev, "%s: read data fail\n", __func__);
+		return IRQ_HANDLED;
+	}
+
+	for (i = 0; i < data->pdata->num_max_touches; i++) {
+		id = (buf[FT_TOUCH_ID_POS + FT_ONE_TCH_LEN * i]) >> 4;
+		if (id >= FT_MAX_ID)
+			break;
+
+		update_input = true;
+
+		x = (buf[FT_TOUCH_X_H_POS + FT_ONE_TCH_LEN * i] & 0x0F) << 8 |
+			(buf[FT_TOUCH_X_L_POS + FT_ONE_TCH_LEN * i]);
+		y = (buf[FT_TOUCH_Y_H_POS + FT_ONE_TCH_LEN * i] & 0x0F) << 8 |
+			(buf[FT_TOUCH_Y_L_POS + FT_ONE_TCH_LEN * i]);
+
+		status = buf[FT_TOUCH_EVENT_POS + FT_ONE_TCH_LEN * i] >> 6;
+
+		num_touches = buf[FT_TD_STATUS] & FT_STATUS_NUM_TP_MASK;
+
+		/* invalid combination */
+		if (!num_touches && !status && !id)
+			break;
+
+		input_mt_slot(ip_dev, id);
+		if (status == FT_TOUCH_DOWN || status == FT_TOUCH_CONTACT) {
+			pressure = FT_PRESS;
+			input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 1);
+			input_report_abs(ip_dev, ABS_MT_POSITION_X, x);
+			input_report_abs(ip_dev, ABS_MT_POSITION_Y, y);
+			input_report_abs(ip_dev, ABS_MT_PRESSURE, pressure);
+		} else {
+			input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 0);
+			input_report_abs(ip_dev, ABS_MT_PRESSURE, 0);
+		}
+	}
+
+	if (update_input) {
+		input_mt_report_pointer_emulation(ip_dev, false);
+		input_sync(ip_dev);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -519,7 +476,7 @@
 	disable_irq(data->client->irq);
 
 	/* release all touches */
-	for (i = 0; i < CFG_MAX_TOUCH_POINTS; i++) {
+	for (i = 0; i < data->pdata->num_max_touches; i++) {
 		input_mt_slot(data->input_dev, i);
 		input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, 0);
 	}
@@ -553,7 +510,7 @@
 pwr_off_fail:
 	if (gpio_is_valid(data->pdata->reset_gpio)) {
 		gpio_set_value_cansleep(data->pdata->reset_gpio, 0);
-		msleep(FT_RESET_DLY);
+		msleep(data->pdata->hard_rst_dly);
 		gpio_set_value_cansleep(data->pdata->reset_gpio, 1);
 	}
 	enable_irq(data->client->irq);
@@ -566,7 +523,7 @@
 	int err;
 
 	if (!data->suspended) {
-		dev_info(dev, "Already in awake state\n");
+		dev_dbg(dev, "Already in awake state\n");
 		return 0;
 	}
 
@@ -586,11 +543,11 @@
 
 	if (gpio_is_valid(data->pdata->reset_gpio)) {
 		gpio_set_value_cansleep(data->pdata->reset_gpio, 0);
-		msleep(FT_RESET_DLY);
+		msleep(data->pdata->hard_rst_dly);
 		gpio_set_value_cansleep(data->pdata->reset_gpio, 1);
 	}
 
-	msleep(FT_STARTUP_DLY);
+	msleep(data->pdata->soft_rst_dly);
 
 	enable_irq(data->client->irq);
 
@@ -649,16 +606,17 @@
 
 static int ft5x06_auto_cal(struct i2c_client *client)
 {
+	struct ft5x06_ts_data *data = i2c_get_clientdata(client);
 	u8 temp = 0, i;
 
 	/* set to factory mode */
-	msleep(2 * FT_STARTUP_DLY);
+	msleep(2 * data->pdata->soft_rst_dly);
 	ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_FACTORYMODE_VALUE);
-	msleep(FT_STARTUP_DLY);
+	msleep(data->pdata->soft_rst_dly);
 
 	/* start calibration */
 	ft5x0x_write_reg(client, FT_DEV_MODE_REG_CAL, FT_CAL_START);
-	msleep(2 * FT_STARTUP_DLY);
+	msleep(2 * data->pdata->soft_rst_dly);
 	for (i = 0; i < FT_CAL_RETRY; i++) {
 		ft5x0x_read_reg(client, FT_REG_CAL, &temp);
 		/*return to normal mode, calibration finish */
@@ -667,36 +625,17 @@
 	}
 
 	/*calibration OK */
-	msleep(2 * FT_STARTUP_DLY);
+	msleep(2 * data->pdata->soft_rst_dly);
 	ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_FACTORYMODE_VALUE);
-	msleep(FT_STARTUP_DLY);
+	msleep(data->pdata->soft_rst_dly);
 
 	/* store calibration data */
 	ft5x0x_write_reg(client, FT_DEV_MODE_REG_CAL, FT_CAL_STORE);
-	msleep(2 * FT_STARTUP_DLY);
+	msleep(2 * data->pdata->soft_rst_dly);
 
 	/* set to normal mode */
 	ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_WORKMODE_VALUE);
-	msleep(2 * FT_STARTUP_DLY);
-
-	return 0;
-}
-
-static int ft5x06_get_upgrade_info(u8 family_id, struct upgrade_info *info)
-{
-	switch (family_id) {
-	case FT5306I_ID:
-		FT_UPGRADE_INFO(info, FT5X06);
-		break;
-	case FT5316_ID:
-		FT_UPGRADE_INFO(info, FT5316);
-		break;
-	case FT6X06_ID:
-		FT_UPGRADE_INFO(info, FT6X06);
-		break;
-	default:
-		return -EINVAL;
-	}
+	msleep(2 * data->pdata->soft_rst_dly);
 
 	return 0;
 }
@@ -705,7 +644,7 @@
 			const u8 *data, u32 data_len)
 {
 	struct ft5x06_ts_data *ts_data = i2c_get_clientdata(client);
-	struct upgrade_info info;
+	struct fw_upgrade_info info = ts_data->pdata->info;
 	u8 reset_reg;
 	u8 w_buf[FT_MAX_WR_BUF] = {0}, r_buf[FT_MAX_RD_BUF] = {0};
 	u8 pkt_buf[FT_FW_PKT_LEN + FT_FW_PKT_META_LEN];
@@ -713,12 +652,6 @@
 	u32 pkt_num, pkt_len;
 	u8 fw_ecc;
 
-	rc = ft5x06_get_upgrade_info(ts_data->family_id, &info);
-	if (rc < 0) {
-		dev_err(&client->dev, "Cannot get upgrade information!\n");
-		return -EINVAL;
-	}
-
 	for (i = 0, j = 0; i < FT_UPGRADE_LOOP; i++) {
 		/* reset - write 0xaa and 0x55 to reset register */
 		if (ts_data->family_id == FT6X06_ID)
@@ -765,7 +698,7 @@
 	/* erase app and panel paramenter area */
 	w_buf[0] = FT_ERASE_APP_REG;
 	ft5x06_i2c_write(client, w_buf, 1);
-	msleep(info.delay_earse_flash);
+	msleep(info.delay_erase_flash);
 
 	w_buf[0] = FT_ERASE_PANEL_REG;
 	ft5x06_i2c_write(client, w_buf, 1);
@@ -840,7 +773,7 @@
 	/* reset */
 	w_buf[0] = FT_REG_RESET_FW;
 	ft5x06_i2c_write(client, w_buf, 1);
-	msleep(FT_STARTUP_DLY);
+	msleep(ts_data->pdata->soft_rst_dly);
 
 	dev_info(&client->dev, "Firmware upgrade successful\n");
 
@@ -852,7 +785,8 @@
 	struct ft5x06_ts_data *data = dev_get_drvdata(dev);
 	const struct firmware *fw = NULL;
 	int rc;
-	u8 val = 0;
+	u8 fw_file_maj, fw_file_min, fw_file_sub_min;
+	bool fw_upgrade = false;
 
 	rc = request_firmware(&fw, data->fw_name, dev);
 	if (rc < 0) {
@@ -867,35 +801,52 @@
 		goto rel_fw;
 	}
 
-	/* check firmware version */
-	rc = ft5x0x_read_reg(data->client, FT_REG_FW_VER, &val);
-	if (rc < 0) {
-		dev_err(dev, "Get firmware version failed\n");
-		goto rel_fw;
-	}
+	fw_file_maj = FT_FW_FILE_MAJ_VER(fw);
+	fw_file_min = FT_FW_FILE_MIN_VER(fw);
+	fw_file_sub_min = FT_FW_FILE_SUB_MIN_VER(fw);
 
-	if (val == FT_FW_FILE_VER(fw) && !force) {
-		dev_err(dev, "No need to update (0x%x)\n", val);
+	dev_info(dev, "Current firmware: %d.%d.%d", data->fw_ver[0],
+				data->fw_ver[1], data->fw_ver[2]);
+	dev_info(dev, "New firmware: %d.%d.%d", fw_file_maj,
+				fw_file_min, fw_file_sub_min);
+
+	if (force) {
+		fw_upgrade = true;
+	} else if (data->fw_ver[0] == fw_file_maj) {
+			if (data->fw_ver[1] < fw_file_min)
+				fw_upgrade = true;
+			else if (data->fw_ver[2] < fw_file_sub_min)
+				fw_upgrade = true;
+			else
+				dev_info(dev, "No need to upgrade\n");
+	} else
+		dev_info(dev, "Firmware versions do not match\n");
+
+	if (!fw_upgrade) {
+		dev_info(dev, "Exiting fw upgrade...\n");
 		rc = -EFAULT;
 		goto rel_fw;
 	}
 
-	dev_info(dev, "upgrade to fw ver 0x%x from 0x%x\n",
-					FT_FW_FILE_VER(fw), val);
-
 	/* start firmware upgrade */
 	if (FT_FW_CHECK(fw)) {
 		rc = ft5x06_fw_upgrade_start(data->client, fw->data, fw->size);
 		if (rc < 0)
-			dev_err(dev, "update failed (%d)\n", rc);
-		else
+			dev_err(dev, "update failed (%d). try later...\n", rc);
+		else if (data->pdata->info.auto_cal)
 			ft5x06_auto_cal(data->client);
 	} else {
 		dev_err(dev, "FW format error\n");
 		rc = -EIO;
 	}
 
-	FT_STORE_TS_INFO(data->ts_info, data->family_id, FT_FW_FILE_VER(fw));
+	ft5x06_update_fw_ver(data);
+
+	FT_STORE_TS_INFO(data->ts_info, data->family_id, data->pdata->name,
+			data->pdata->num_max_touches, data->pdata->group_id,
+			data->pdata->fw_vkey_support ? "yes" : "no",
+			data->pdata->fw_name, data->fw_ver[0],
+			data->fw_ver[1], data->fw_ver[2]);
 rel_fw:
 	release_firmware(fw);
 	return rc;
@@ -923,6 +874,11 @@
 	if (rc != 0)
 		return rc;
 
+	if (data->suspended) {
+		dev_info(dev, "In suspend state, try again later...\n");
+		return size;
+	}
+
 	mutex_lock(&data->input_dev->mutex);
 	if (!data->loading_fw  && val) {
 		data->loading_fw = true;
@@ -1177,6 +1133,13 @@
 	u32 temp_val, num_buttons;
 	u32 button_map[MAX_BUTTONS];
 
+	pdata->name = "focaltech";
+	rc = of_property_read_string(np, "focaltech,name", &pdata->name);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read name\n");
+		return rc;
+	}
+
 	rc = ft5x06_get_dt_coords(dev, "focaltech,panel-coords", pdata);
 	if (rc && (rc != -EINVAL))
 		return rc;
@@ -1201,6 +1164,89 @@
 	if (pdata->irq_gpio < 0)
 		return pdata->irq_gpio;
 
+	pdata->fw_name = "ft_fw.bin";
+	rc = of_property_read_string(np, "focaltech,fw-name", &pdata->fw_name);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read fw name\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(np, "focaltech,group-id", &temp_val);
+	if (!rc)
+		pdata->group_id = temp_val;
+	else
+		return rc;
+
+	rc = of_property_read_u32(np, "focaltech,hard-reset-delay-ms",
+							&temp_val);
+	if (!rc)
+		pdata->hard_rst_dly = temp_val;
+	else
+		return rc;
+
+	rc = of_property_read_u32(np, "focaltech,soft-reset-delay-ms",
+							&temp_val);
+	if (!rc)
+		pdata->soft_rst_dly = temp_val;
+	else
+		return rc;
+
+	rc = of_property_read_u32(np, "focaltech,num-max-touches", &temp_val);
+	if (!rc)
+		pdata->num_max_touches = temp_val;
+	else
+		return rc;
+
+	rc = of_property_read_u32(np, "focaltech,fw-delay-aa-ms", &temp_val);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read fw delay aa\n");
+		return rc;
+	} else if (rc != -EINVAL)
+		pdata->info.delay_aa =  temp_val;
+
+	rc = of_property_read_u32(np, "focaltech,fw-delay-55-ms", &temp_val);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read fw delay 55\n");
+		return rc;
+	} else if (rc != -EINVAL)
+		pdata->info.delay_55 =  temp_val;
+
+	rc = of_property_read_u32(np, "focaltech,fw-upgrade-id1", &temp_val);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read fw upgrade id1\n");
+		return rc;
+	} else if (rc != -EINVAL)
+		pdata->info.upgrade_id_1 =  temp_val;
+
+	rc = of_property_read_u32(np, "focaltech,fw-upgrade-id2", &temp_val);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read fw upgrade id2\n");
+		return rc;
+	} else if (rc != -EINVAL)
+		pdata->info.upgrade_id_2 =  temp_val;
+
+	rc = of_property_read_u32(np, "focaltech,fw-delay-readid-ms",
+							&temp_val);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read fw delay read id\n");
+		return rc;
+	} else if (rc != -EINVAL)
+		pdata->info.delay_readid =  temp_val;
+
+	rc = of_property_read_u32(np, "focaltech,fw-delay-era-flsh-ms",
+							&temp_val);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read fw delay erase flash\n");
+		return rc;
+	} else if (rc != -EINVAL)
+		pdata->info.delay_erase_flash =  temp_val;
+
+	pdata->info.auto_cal = of_property_read_bool(np,
+					"focaltech,fw-auto-cal");
+
+	pdata->fw_vkey_support = of_property_read_bool(np,
+						"focaltech,fw-vkey-support");
+
 	rc = of_property_read_u32(np, "focaltech,family-id", &temp_val);
 	if (!rc)
 		pdata->family_id = temp_val;
@@ -1241,7 +1287,7 @@
 	struct dentry *temp;
 	u8 reg_value;
 	u8 reg_addr;
-	int err;
+	int err, len;
 
 	if (client->dev.of_node) {
 		pdata = devm_kzalloc(&client->dev,
@@ -1252,8 +1298,10 @@
 		}
 
 		err = ft5x06_parse_dt(&client->dev, pdata);
-		if (err)
+		if (err) {
+			dev_err(&client->dev, "DT parsing failed\n");
 			return err;
+		}
 	} else
 		pdata = client->dev.platform_data;
 
@@ -1267,7 +1315,26 @@
 		return -ENODEV;
 	}
 
-	data = kzalloc(sizeof(struct ft5x06_ts_data), GFP_KERNEL);
+	data = devm_kzalloc(&client->dev,
+			sizeof(struct ft5x06_ts_data), GFP_KERNEL);
+	if (!data) {
+		dev_err(&client->dev, "Not enough memory\n");
+		return -ENOMEM;
+	}
+
+	if (pdata->fw_name) {
+		len = strlen(pdata->fw_name);
+		if (len > FT_FW_NAME_MAX_LEN - 1) {
+			dev_err(&client->dev, "Invalid firmware name\n");
+			return -EINVAL;
+		}
+
+		strlcpy(data->fw_name, pdata->fw_name, len + 1);
+	}
+
+	data->tch_data_len = FT_TCH_LEN(pdata->num_max_touches);
+	data->tch_data = devm_kzalloc(&client->dev,
+				data->tch_data_len, GFP_KERNEL);
 	if (!data) {
 		dev_err(&client->dev, "Not enough memory\n");
 		return -ENOMEM;
@@ -1275,9 +1342,8 @@
 
 	input_dev = input_allocate_device();
 	if (!input_dev) {
-		err = -ENOMEM;
 		dev_err(&client->dev, "failed to allocate input device\n");
-		goto free_mem;
+		return -ENOMEM;
 	}
 
 	data->input_dev = input_dev;
@@ -1296,12 +1362,12 @@
 	__set_bit(BTN_TOUCH, input_dev->keybit);
 	__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
 
-	input_mt_init_slots(input_dev, CFG_MAX_TOUCH_POINTS);
+	input_mt_init_slots(input_dev, pdata->num_max_touches);
 	input_set_abs_params(input_dev, ABS_MT_POSITION_X, pdata->x_min,
 			     pdata->x_max, 0, 0);
 	input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->y_min,
 			     pdata->y_max, 0, 0);
-	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, FT_PRESS, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, FT_PRESS, 0, 0);
 
 	err = input_register_device(input_dev);
 	if (err) {
@@ -1364,12 +1430,12 @@
 				"set_direction for reset gpio failed\n");
 			goto free_reset_gpio;
 		}
-		msleep(FT_RESET_DLY);
+		msleep(data->pdata->hard_rst_dly);
 		gpio_set_value_cansleep(data->pdata->reset_gpio, 1);
 	}
 
 	/* make sure CTP already finish startup process */
-	msleep(FT_STARTUP_DLY);
+	msleep(data->pdata->soft_rst_dly);
 
 	/* check the controller id */
 	reg_addr = FT_REG_ID;
@@ -1453,7 +1519,8 @@
 		goto free_debug_dir;
 	}
 
-	data->ts_info = kzalloc(FT_INFO_MAX_LEN, GFP_KERNEL);
+	data->ts_info = devm_kzalloc(&client->dev,
+				FT_INFO_MAX_LEN, GFP_KERNEL);
 	if (!data->ts_info) {
 		dev_err(&client->dev, "Not enough memory\n");
 		goto free_debug_dir;
@@ -1474,14 +1541,13 @@
 
 	dev_dbg(&client->dev, "touch threshold = %d\n", reg_value * 4);
 
-	reg_addr = FT_REG_FW_VER;
-	err = ft5x06_i2c_read(client, &reg_addr, 1, &reg_value, 1);
-	if (err < 0)
-		dev_err(&client->dev, "version read failed");
+	ft5x06_update_fw_ver(data);
 
-	dev_info(&client->dev, "Firmware version = 0x%x\n", reg_value);
-
-	FT_STORE_TS_INFO(data->ts_info, data->family_id, reg_value);
+	FT_STORE_TS_INFO(data->ts_info, data->family_id, data->pdata->name,
+			data->pdata->num_max_touches, data->pdata->group_id,
+			data->pdata->fw_vkey_support ? "yes" : "no",
+			data->pdata->fw_name, data->fw_ver[0],
+			data->fw_ver[1], data->fw_ver[2]);
 
 #if defined(CONFIG_FB)
 	data->fb_notif.notifier_call = fb_notifier_callback;
@@ -1532,8 +1598,6 @@
 	input_dev = NULL;
 free_inputdev:
 	input_free_device(input_dev);
-free_mem:
-	kfree(data);
 	return err;
 }
 
@@ -1571,8 +1635,6 @@
 		ft5x06_power_init(data, false);
 
 	input_unregister_device(data->input_dev);
-	kfree(data->ts_info);
-	kfree(data);
 
 	return 0;
 }
diff --git a/drivers/input/touchscreen/gt9xx/Kconfig b/drivers/input/touchscreen/gt9xx/Kconfig
new file mode 100644
index 0000000..9d36403
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/Kconfig
@@ -0,0 +1,51 @@
+#
+# Goodix GT9xx Touchscreen driver
+#
+
+config GT9XX_TOUCHPANEL_DRIVER
+	tristate "Goodix GT9xx touchpanel driver"
+	depends on TOUCHSCREEN_GT9XX
+	default n
+	help
+	  This is the main file for touchpanel driver for Goodix GT9xx
+	  touchscreens.
+
+	  Say Y here if you have a Goodix GT9xx touchscreen connected
+	  to your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gt9xx_update.
+
+config GT9XX_TOUCHPANEL_UPDATE
+	tristate "Goodix GT9xx touchpanel auto update support"
+	depends on GT9XX_TOUCHPANEL_DRIVER
+	default n
+	help
+	  This enables support for firmware update for Goodix GT9xx
+	  touchscreens.
+
+	  Say Y here if you have a Goodix GT9xx touchscreen connected
+	  to your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gt9xx_update.
+
+config GT9XX_TOUCHPANEL_DEBUG
+	tristate "Goodix GT9xx Tools for debuging"
+	depends on GT9XX_TOUCHPANEL_DRIVER
+	default n
+	help
+	  This is application debug interface support for Goodix GT9xx
+	  touchscreens.
+
+	  Say Y here if you want to have a Android app debug interface
+	  to your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gt9xx_update.
diff --git a/drivers/input/touchscreen/gt9xx/Makefile b/drivers/input/touchscreen/gt9xx/Makefile
new file mode 100644
index 0000000..482d869
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/Makefile
@@ -0,0 +1,8 @@
+#gt915 touchpanel driver
+
+
+obj-$(CONFIG_GT9XX_TOUCHPANEL_DRIVER)	+= gt9xx.o
+#gt915 update file
+obj-$(CONFIG_GT9XX_TOUCHPANEL_UPDATE)	+= gt9xx_update.o
+#debug tool
+obj-$(CONFIG_GT9XX_TOUCHPANEL_DEBUG)	+= goodix_tool.o
diff --git a/drivers/input/touchscreen/gt9xx/goodix_tool.c b/drivers/input/touchscreen/gt9xx/goodix_tool.c
index 3dfe4e1..bdac3fd 100644
--- a/drivers/input/touchscreen/gt9xx/goodix_tool.c
+++ b/drivers/input/touchscreen/gt9xx/goodix_tool.c
@@ -1,615 +1,549 @@
-/* drivers/input/touchscreen/goodix_tool.c

- * 

- * 2010 - 2012 Goodix Technology.

- * 

- * This program is free software; you can redistribute it and/or modify

- * it under the terms of the GNU General Public License as published by

- * the Free Software Foundation; either version 2 of the License, or

- * (at your option) any later version.

- * 

- * This program is distributed in the hope that it will be a reference 

- * to you, when you are integrating the GOODiX's CTP IC into your system, 

- * 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.

- * 

- * Version:1.6

- *        V1.0:2012/05/01,create file.

- *        V1.2:2012/06/08,modify some warning.

- *        V1.4:2012/08/28,modified to support GT9XX

- *        V1.6:new proc name

- */

-

-#include "gt9xx.h"

-

-#define DATA_LENGTH_UINT    512

-#define CMD_HEAD_LENGTH     (sizeof(st_cmd_head) - sizeof(u8*))

-static char procname[20] = {0};

-

-#define UPDATE_FUNCTIONS

-

-#ifdef UPDATE_FUNCTIONS

-extern s32 gup_enter_update_mode(struct i2c_client *client);

-extern void gup_leave_update_mode(void);

-extern s32 gup_update_proc(void *dir);

-#endif

-

-extern void gtp_irq_disable(struct goodix_ts_data *);

-extern void gtp_irq_enable(struct goodix_ts_data *);

-

-#pragma pack(1)

-typedef struct{

-    u8  wr;         //write read flag£¬0:R  1:W  2:PID 3:

-    u8  flag;       //0:no need flag/int 1: need flag  2:need int

-    u8 flag_addr[2];  //flag address

-    u8  flag_val;   //flag val

-    u8  flag_relation;  //flag_val:flag 0:not equal 1:equal 2:> 3:<

-    u16 circle;     //polling cycle 

-    u8  times;      //plling times

-    u8  retry;      //I2C retry times

-    u16 delay;      //delay befor read or after write

-    u16 data_len;   //data length

-    u8  addr_len;   //address length

-    u8  addr[2];    //address

-    u8  res[3];     //reserved

-    u8* data;       //data pointer

-}st_cmd_head;

-#pragma pack()

-st_cmd_head cmd_head;

-

-static struct i2c_client *gt_client = NULL;

-

-static struct proc_dir_entry *goodix_proc_entry;

-

-static s32 goodix_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data);

-static s32 goodix_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data );

-static s32 (*tool_i2c_read)(u8 *, u16);

-static s32 (*tool_i2c_write)(u8 *, u16);

-

-#if GTP_ESD_PROTECT

-extern void gtp_esd_switch(struct i2c_client *, s32);

-#endif

-s32 DATA_LENGTH = 0;

-s8 IC_TYPE[16] = {0};

-

-static void tool_set_proc_name(char * procname)

-{

-    char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", 

-        "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

-    char date[20] = {0};

-    char month[4] = {0};

-    int i = 0, n_month = 1, n_day = 0, n_year = 0;

-    

-    sprintf(date, "%s", __DATE__);

-    

-    //GTP_DEBUG("compile date: %s", date);

-    

-    sscanf(date, "%s %d %d", month, &n_day, &n_year);

-    

-    for (i = 0; i < 12; ++i)

-    {

-        if (!memcmp(months[i], month, 3))

-        {

-            n_month = i+1;

-            break;

-        }

-    }

-    

-    sprintf(procname, "gmnode%04d%02d%02d", n_year, n_month, n_day);    

-    

-    //GTP_DEBUG("procname = %s", procname);

-}

-

-

-static s32 tool_i2c_read_no_extra(u8* buf, u16 len)

-{

-    s32 ret = -1;

-    s32 i = 0;

-    struct i2c_msg msgs[2];

-    

-    msgs[0].flags = !I2C_M_RD;

-    msgs[0].addr  = gt_client->addr;

-    msgs[0].len   = cmd_head.addr_len;

-    msgs[0].buf   = &buf[0];

-    

-    msgs[1].flags = I2C_M_RD;

-    msgs[1].addr  = gt_client->addr;

-    msgs[1].len   = len;

-    msgs[1].buf   = &buf[GTP_ADDR_LENGTH];

-

-    for (i = 0; i < cmd_head.retry; i++)

-    {

-        ret=i2c_transfer(gt_client->adapter, msgs, 2);

-        if (ret > 0)

-        {

-            break;

-        }

-    }

-    return ret;

-}

-

-static s32 tool_i2c_write_no_extra(u8* buf, u16 len)

-{

-    s32 ret = -1;

-    s32 i = 0;

-    struct i2c_msg msg;

-

-    msg.flags = !I2C_M_RD;

-    msg.addr  = gt_client->addr;

-    msg.len   = len;

-    msg.buf   = buf;

-

-    for (i = 0; i < cmd_head.retry; i++)

-    {

-        ret=i2c_transfer(gt_client->adapter, &msg, 1);

-        if (ret > 0)

-        {

-            break;

-        }

-    }

-    return ret;

-}

-

-static s32 tool_i2c_read_with_extra(u8* buf, u16 len)

-{

-    s32 ret = -1;

-    u8 pre[2] = {0x0f, 0xff};

-    u8 end[2] = {0x80, 0x00};

-

-    tool_i2c_write_no_extra(pre, 2);

-    ret = tool_i2c_read_no_extra(buf, len);

-    tool_i2c_write_no_extra(end, 2);

-

-    return ret;

-}

-

-static s32 tool_i2c_write_with_extra(u8* buf, u16 len)

-{

-    s32 ret = -1;

-    u8 pre[2] = {0x0f, 0xff};

-    u8 end[2] = {0x80, 0x00};

-

-    tool_i2c_write_no_extra(pre, 2);

-    ret = tool_i2c_write_no_extra(buf, len);

-    tool_i2c_write_no_extra(end, 2);

-

-    return ret;

-}

-

-static void register_i2c_func(void)

-{

-//    if (!strncmp(IC_TYPE, "GT818", 5) || !strncmp(IC_TYPE, "GT816", 5) 

-//        || !strncmp(IC_TYPE, "GT811", 5) || !strncmp(IC_TYPE, "GT818F", 6) 

-//        || !strncmp(IC_TYPE, "GT827", 5) || !strncmp(IC_TYPE,"GT828", 5)

-//        || !strncmp(IC_TYPE, "GT813", 5))

-    if (strncmp(IC_TYPE, "GT8110", 6) && strncmp(IC_TYPE, "GT8105", 6)

-        && strncmp(IC_TYPE, "GT801", 5) && strncmp(IC_TYPE, "GT800", 5)

-        && strncmp(IC_TYPE, "GT801PLUS", 9) && strncmp(IC_TYPE, "GT811", 5)

-        && strncmp(IC_TYPE, "GTxxx", 5))

-    {

-        tool_i2c_read = tool_i2c_read_with_extra;

-        tool_i2c_write = tool_i2c_write_with_extra;

-        GTP_DEBUG("I2C function: with pre and end cmd!");

-    }

-    else

-    {

-        tool_i2c_read = tool_i2c_read_no_extra;

-        tool_i2c_write = tool_i2c_write_no_extra;

-        GTP_INFO("I2C function: without pre and end cmd!");

-    }

-}

-

-static void unregister_i2c_func(void)

-{

-    tool_i2c_read = NULL;

-    tool_i2c_write = NULL;

-    GTP_INFO("I2C function: unregister i2c transfer function!");

-}

-

-

-s32 init_wr_node(struct i2c_client *client)

-{

-    s32 i;

-

-    gt_client = client;

-    memset(&cmd_head, 0, sizeof(cmd_head));

-    cmd_head.data = NULL;

-

-    i = 5;

-    while ((!cmd_head.data) && i)

-    {

-        cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL);

-        if (NULL != cmd_head.data)

-        {

-            break;

-        }

-        i--;

-    }

-    if (i)

-    {

-        DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH;

-        GTP_INFO("Applied memory size:%d.", DATA_LENGTH);

-    }

-    else

-    {

-        GTP_ERROR("Apply for memory failed.");

-        return FAIL;

-    }

-

-    cmd_head.addr_len = 2;

-    cmd_head.retry = 5;

-

-    register_i2c_func();

-

-    tool_set_proc_name(procname);

-    goodix_proc_entry = create_proc_entry(procname, 0666, NULL);

-    if (goodix_proc_entry == NULL)

-    {

-        GTP_ERROR("Couldn't create proc entry!");

-        return FAIL;

-    }

-    else

-    {

-        GTP_INFO("Create proc entry success!");

-        goodix_proc_entry->write_proc = goodix_tool_write;

-        goodix_proc_entry->read_proc = goodix_tool_read;

-    }

-

-    return SUCCESS;

-}

-

-void uninit_wr_node(void)

-{

-    kfree(cmd_head.data);

-    cmd_head.data = NULL;

-    unregister_i2c_func();

-    remove_proc_entry(procname, NULL);

-}

-

-static u8 relation(u8 src, u8 dst, u8 rlt)

-{

-    u8 ret = 0;

-    

-    switch (rlt)

-    {

-    case 0:

-        ret = (src != dst) ? true : false;

-        break;

-

-    case 1:

-        ret = (src == dst) ? true : false;

-        GTP_DEBUG("equal:src:0x%02x   dst:0x%02x   ret:%d.", src, dst, (s32)ret);

-        break;

-

-    case 2:

-        ret = (src > dst) ? true : false;

-        break;

-

-    case 3:

-        ret = (src < dst) ? true : false;

-        break;

-

-    case 4:

-        ret = (src & dst) ? true : false;

-        break;

-

-    case 5:

-        ret = (!(src | dst)) ? true : false;

-        break;

-

-    default:

-        ret = false;

-        break;    

-    }

-

-    return ret;

-}

-

-/*******************************************************    

-Function:

-    Comfirm function.

-Input:

-  None.

-Output:

-    Return write length.

-********************************************************/

-static u8 comfirm(void)

-{

-    s32 i = 0;

-    u8 buf[32];

-    

-//    memcpy(&buf[GTP_ADDR_LENGTH - cmd_head.addr_len], &cmd_head.flag_addr, cmd_head.addr_len);

-//    memcpy(buf, &cmd_head.flag_addr, cmd_head.addr_len);//Modified by Scott, 2012-02-17

-    memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len);

-   

-    for (i = 0; i < cmd_head.times; i++)

-    {

-        if (tool_i2c_read(buf, 1) <= 0)

-        {

-            GTP_ERROR("Read flag data failed!");

-            return FAIL;

-        }

-        if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val, cmd_head.flag_relation))

-        {

-            GTP_DEBUG("value at flag addr:0x%02x.", buf[GTP_ADDR_LENGTH]);

-            GTP_DEBUG("flag value:0x%02x.", cmd_head.flag_val);

-            break;

-        }

-

-        msleep(cmd_head.circle);

-    }

-

-    if (i >= cmd_head.times)

-    {

-        GTP_ERROR("Didn't get the flag to continue!");

-        return FAIL;

-    }

-

-    return SUCCESS;

-}

-

-/*******************************************************    

-Function:

-    Goodix tool write function.

-Input:

-  standard proc write function param.

-Output:

-    Return write length.

-********************************************************/

-static s32 goodix_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data)

-{

-    s32 ret = 0;

-    GTP_DEBUG_FUNC();

-    GTP_DEBUG_ARRAY((u8*)buff, len);

-    

-    ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);

-    if(ret)

-    {

-        GTP_ERROR("copy_from_user failed.");

-    }

-

-    GTP_DEBUG("wr  :0x%02x.", cmd_head.wr);

-    GTP_DEBUG("flag:0x%02x.", cmd_head.flag);

-    GTP_DEBUG("flag addr:0x%02x%02x.", cmd_head.flag_addr[0], cmd_head.flag_addr[1]);

-    GTP_DEBUG("flag val:0x%02x.", cmd_head.flag_val);

-    GTP_DEBUG("flag rel:0x%02x.", cmd_head.flag_relation);

-    GTP_DEBUG("circle  :%d.", (s32)cmd_head.circle);

-    GTP_DEBUG("times   :%d.", (s32)cmd_head.times);

-    GTP_DEBUG("retry   :%d.", (s32)cmd_head.retry);

-    GTP_DEBUG("delay   :%d.", (s32)cmd_head.delay);

-    GTP_DEBUG("data len:%d.", (s32)cmd_head.data_len);

-    GTP_DEBUG("addr len:%d.", (s32)cmd_head.addr_len);

-    GTP_DEBUG("addr:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]);

-    GTP_DEBUG("len:%d.", (s32)len);

-    GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]);

-    

-    if (1 == cmd_head.wr)

-    {

-      //  copy_from_user(&cmd_head.data[cmd_head.addr_len], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);

-        ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);

-        if(ret)

-        {

-            GTP_ERROR("copy_from_user failed.");

-        }

-        memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len], cmd_head.addr, cmd_head.addr_len);

-

-        GTP_DEBUG_ARRAY(cmd_head.data, cmd_head.data_len + cmd_head.addr_len);

-        GTP_DEBUG_ARRAY((u8*)&buff[CMD_HEAD_LENGTH], cmd_head.data_len);

-

-        if (1 == cmd_head.flag)

-        {

-            if (FAIL == comfirm())

-            {

-                GTP_ERROR("[WRITE]Comfirm fail!");

-                return FAIL;

-            }

-        }

-        else if (2 == cmd_head.flag)

-        {

-            //Need interrupt!

-        }

-        if (tool_i2c_write(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],

-            cmd_head.data_len + cmd_head.addr_len) <= 0)

-        {

-            GTP_ERROR("[WRITE]Write data failed!");

-            return FAIL;

-        }

-

-        GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],cmd_head.data_len + cmd_head.addr_len);

-        if (cmd_head.delay)

-        {

-            msleep(cmd_head.delay);

-        }

-

-        return cmd_head.data_len + CMD_HEAD_LENGTH;

-    }

-    else if (3 == cmd_head.wr)  //Write ic type

-    {

-    ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);

-        if(ret)

-        {

-            GTP_ERROR("copy_from_user failed.");

-        }

-        memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);

-

-        register_i2c_func();

-

-        return cmd_head.data_len + CMD_HEAD_LENGTH;

-    }

-    else if (5 == cmd_head.wr)

-    {

-        //memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);

-

-        return cmd_head.data_len + CMD_HEAD_LENGTH;

-    }

-    else if (7 == cmd_head.wr)//disable irq!

-    {

-        gtp_irq_disable(i2c_get_clientdata(gt_client));

-        

-    #if GTP_ESD_PROTECT

-        gtp_esd_switch(gt_client, SWITCH_OFF);

-    #endif

-        return CMD_HEAD_LENGTH;

-    }

-    else if (9 == cmd_head.wr) //enable irq!

-    {

-        gtp_irq_enable(i2c_get_clientdata(gt_client));

-

-    #if GTP_ESD_PROTECT

-        gtp_esd_switch(gt_client, SWITCH_ON);

-    #endif

-        return CMD_HEAD_LENGTH;

-    }

-    else if(17 == cmd_head.wr)

-    {

-        struct goodix_ts_data *ts = i2c_get_clientdata(gt_client);

-        ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);

-        if(ret)

-        {

-            GTP_DEBUG("copy_from_user failed.");

-        }

-        if(cmd_head.data[GTP_ADDR_LENGTH])

-        {

-            GTP_DEBUG("gtp enter rawdiff.");

-            ts->gtp_rawdiff_mode = true;

-        }

-        else

-        {

-            ts->gtp_rawdiff_mode = false;

-            GTP_DEBUG("gtp leave rawdiff.");

-        }

-        return CMD_HEAD_LENGTH;

-    }

-#ifdef UPDATE_FUNCTIONS

-    else if (11 == cmd_head.wr)//Enter update mode!

-    {

-        if (FAIL == gup_enter_update_mode(gt_client))

-        {

-            return FAIL;

-        }

-    }

-    else if (13 == cmd_head.wr)//Leave update mode!

-    {

-        gup_leave_update_mode();

-    }

-    else if (15 == cmd_head.wr) //Update firmware!

-    {

-        show_len = 0;

-        total_len = 0;

-        memset(cmd_head.data, 0, cmd_head.data_len + 1);

-        memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH], cmd_head.data_len);

-

-        if (FAIL == gup_update_proc((void*)cmd_head.data))

-        {

-            return FAIL;

-        }

-    }

-#endif

-

-    return CMD_HEAD_LENGTH;

-}

-

-/*******************************************************    

-Function:

-    Goodix tool read function.

-Input:

-  standard proc read function param.

-Output:

-    Return read length.

-********************************************************/

-static s32 goodix_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data )

-{

-    GTP_DEBUG_FUNC();

-    

-    if (cmd_head.wr % 2)

-    {

-        return FAIL;

-    }

-    else if (!cmd_head.wr)

-    {

-        u16 len = 0;

-        s16 data_len = 0;

-        u16 loc = 0;

-        

-        if (1 == cmd_head.flag)

-        {

-            if (FAIL == comfirm())

-            {

-                GTP_ERROR("[READ]Comfirm fail!");

-                return FAIL;

-            }

-        }

-        else if (2 == cmd_head.flag)

-        {

-            //Need interrupt!

-        }

-

-        memcpy(cmd_head.data, cmd_head.addr, cmd_head.addr_len);

-

-        GTP_DEBUG("[CMD HEAD DATA] ADDR:0x%02x%02x.", cmd_head.data[0], cmd_head.data[1]);

-        GTP_DEBUG("[CMD HEAD ADDR] ADDR:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]);

-        

-        if (cmd_head.delay)

-        {

-            msleep(cmd_head.delay);

-        }

-        

-        data_len = cmd_head.data_len;

-        while(data_len > 0)

-        {

-            if (data_len > DATA_LENGTH)

-            {

-                len = DATA_LENGTH;

-            }

-            else

-            {

-                len = data_len;

-            }

-            data_len -= DATA_LENGTH;

-

-            if (tool_i2c_read(cmd_head.data, len) <= 0)

-            {

-                GTP_ERROR("[READ]Read data failed!");

-                return FAIL;

-            }

-            memcpy(&page[loc], &cmd_head.data[GTP_ADDR_LENGTH], len);

-            loc += len;

-

-            GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH], len);

-            GTP_DEBUG_ARRAY(page, len);

-        }

-    }

-    else if (2 == cmd_head.wr)

-    {

-    //    memcpy(page, "gt8", cmd_head.data_len);

-       // memcpy(page, "GT818", 5);

-      //  page[5] = 0;

-

-        GTP_DEBUG("Return ic type:%s len:%d.", page, (s32)cmd_head.data_len);

-        return cmd_head.data_len;

-        //return sizeof(IC_TYPE_NAME);

-    }

-    else if (4 == cmd_head.wr)

-    {

-        page[0] = show_len >> 8;

-        page[1] = show_len & 0xff;

-        page[2] = total_len >> 8;

-        page[3] = total_len & 0xff;

-

-        return cmd_head.data_len;

-    }

-    else if (6 == cmd_head.wr)

-    {

-        //Read error code!

-    }

-    else if (8 == cmd_head.wr)  //Read driver version

-    {

-       // memcpy(page, GTP_DRIVER_VERSION, strlen(GTP_DRIVER_VERSION));

-       s32 tmp_len;

-       tmp_len = strlen(GTP_DRIVER_VERSION);

-       memcpy(page, GTP_DRIVER_VERSION, tmp_len);

-       page[tmp_len] = 0;

-    }

-

-    return cmd_head.data_len;

-}

+/* drivers/input/touchscreen/goodix_tool.c
+ *
+ * 2010 - 2012 Goodix Technology.
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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.
+ *
+ * Version:1.6
+ *        V1.0:2012/05/01,create file.
+ *        V1.2:2012/06/08,modify some warning.
+ *        V1.4:2012/08/28,modified to support GT9XX
+ *        V1.6:new proc name
+ */
+
+#include "gt9xx.h"
+
+#define DATA_LENGTH_UINT    512
+#define CMD_HEAD_LENGTH     (sizeof(st_cmd_head) - sizeof(u8 *))
+static char procname[20] = {0};
+
+#define UPDATE_FUNCTIONS
+
+#pragma pack(1)
+struct {
+	u8  wr;		/* write read flag£¬0:R  1:W  2:PID 3: */
+	u8  flag;	/* 0:no need flag/int 1: need flag  2:need int */
+	u8 flag_addr[2];/* flag address */
+	u8  flag_val;	/* flag val */
+	u8  flag_relation; /* flag_val:flag 0:not equal 1:equal 2:> 3:< */
+	u16 circle;	/* polling cycle */
+	u8  times;	/* plling times */
+	u8  retry;	/* I2C retry times */
+	u16 delay;	/* delay befor read or after write */
+	u16 data_len;	/* data length */
+	u8  addr_len;	/* address length */
+	u8  addr[2];	/* address */
+	u8  res[3];	/* reserved */
+	u8  *data;	/* data pointer */
+} st_cmd_head;
+#pragma pack()
+st_cmd_head cmd_head;
+
+static struct i2c_client *gt_client;
+
+static struct proc_dir_entry *goodix_proc_entry;
+
+static s32 goodix_tool_write(struct file *filp, const char __user *buff,
+						unsigned long len, void *data);
+static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
+							int *eof, void *data);
+static s32 (*tool_i2c_read)(u8 *, u16);
+static s32 (*tool_i2c_write)(u8 *, u16);
+
+s32 DATA_LENGTH;
+s8 IC_TYPE[16] = {0};
+
+static void tool_set_proc_name(char *procname)
+{
+	char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May",
+	"Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+	char date[20] = {0};
+	char month[4] = {0};
+	int i = 0, n_month = 1, n_day = 0, n_year = 0;
+	snprintf(date, 20, "%s", __DATE__);
+
+	/* GTP_DEBUG("compile date: %s", date); */
+
+	sscanf(date, "%s %d %d", month, &n_day, &n_year);
+
+	for (i = 0; i < 12; ++i) {
+		if (!memcmp(months[i], month, 3)) {
+			n_month = i+1;
+			break;
+		}
+	}
+
+	snprintf(procname, 20, "gmnode%04d%02d%02d", n_year, n_month, n_day);
+	/* GTP_DEBUG("procname = %s", procname); */
+}
+
+static s32 tool_i2c_read_no_extra(u8 *buf, u16 len)
+{
+	s32 ret = -1;
+	s32 i = 0;
+	struct i2c_msg msgs[2];
+
+	msgs[0].flags = !I2C_M_RD;
+	msgs[0].addr  = gt_client->addr;
+	msgs[0].len   = cmd_head.addr_len;
+	msgs[0].buf   = &buf[0];
+
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].addr  = gt_client->addr;
+	msgs[1].len   = len;
+	msgs[1].buf   = &buf[GTP_ADDR_LENGTH];
+
+	for (i = 0; i < cmd_head.retry; i++) {
+		ret = i2c_transfer(gt_client->adapter, msgs, 2);
+		if (ret > 0)
+			break;
+	}
+
+	return ret;
+}
+
+static s32 tool_i2c_write_no_extra(u8 *buf, u16 len)
+{
+	s32 ret = -1;
+	s32 i = 0;
+	struct i2c_msg msg;
+
+	msg.flags = !I2C_M_RD;
+	msg.addr  = gt_client->addr;
+	msg.len   = len;
+	msg.buf   = buf;
+
+	for (i = 0; i < cmd_head.retry; i++) {
+		ret = i2c_transfer(gt_client->adapter, &msg, 1);
+		if (ret > 0)
+			break;
+		}
+
+	return ret;
+}
+
+static s32 tool_i2c_read_with_extra(u8 *buf, u16 len)
+{
+	s32 ret = -1;
+	u8 pre[2] = {0x0f, 0xff};
+	u8 end[2] = {0x80, 0x00};
+
+	tool_i2c_write_no_extra(pre, 2);
+	ret = tool_i2c_read_no_extra(buf, len);
+	tool_i2c_write_no_extra(end, 2);
+
+	return ret;
+}
+
+static s32 tool_i2c_write_with_extra(u8 *buf, u16 len)
+{
+	s32 ret = -1;
+	u8 pre[2] = {0x0f, 0xff};
+	u8 end[2] = {0x80, 0x00};
+
+	tool_i2c_write_no_extra(pre, 2);
+	ret = tool_i2c_write_no_extra(buf, len);
+	tool_i2c_write_no_extra(end, 2);
+
+	return ret;
+}
+
+static void register_i2c_func(void)
+{
+	/* if (!strncmp(IC_TYPE, "GT818", 5) || !strncmp(IC_TYPE, "GT816", 5)
+	|| !strncmp(IC_TYPE, "GT811", 5) || !strncmp(IC_TYPE, "GT818F", 6)
+	|| !strncmp(IC_TYPE, "GT827", 5) || !strncmp(IC_TYPE,"GT828", 5)
+	|| !strncmp(IC_TYPE, "GT813", 5)) */
+
+	if (strncmp(IC_TYPE, "GT8110", 6) && strncmp(IC_TYPE, "GT8105", 6)
+	&& strncmp(IC_TYPE, "GT801", 5) && strncmp(IC_TYPE, "GT800", 5)
+	&& strncmp(IC_TYPE, "GT801PLUS", 9) && strncmp(IC_TYPE, "GT811", 5)
+	&& strncmp(IC_TYPE, "GTxxx", 5)) {
+		tool_i2c_read = tool_i2c_read_with_extra;
+		tool_i2c_write = tool_i2c_write_with_extra;
+		GTP_DEBUG("I2C function: with pre and end cmd!");
+	} else {
+		tool_i2c_read = tool_i2c_read_no_extra;
+		tool_i2c_write = tool_i2c_write_no_extra;
+		GTP_INFO("I2C function: without pre and end cmd!");
+	}
+}
+
+static void unregister_i2c_func(void)
+{
+	tool_i2c_read = NULL;
+	tool_i2c_write = NULL;
+	GTP_INFO("I2C function: unregister i2c transfer function!");
+}
+
+s32 init_wr_node(struct i2c_client *client)
+{
+	s32 i;
+
+	gt_client = client;
+	memset(&cmd_head, 0, sizeof(cmd_head));
+	cmd_head.data = NULL;
+
+	i = 5;
+	while ((!cmd_head.data) && i) {
+		cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL);
+		if (NULL != cmd_head.data)
+			break;
+		i--;
+	}
+	if (i) {
+		DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH;
+		GTP_INFO("Applied memory size:%d.", DATA_LENGTH);
+	} else {
+		GTP_ERROR("Apply for memory failed.");
+		return FAIL;
+	}
+
+	cmd_head.addr_len = 2;
+	cmd_head.retry = 5;
+
+	register_i2c_func();
+
+	tool_set_proc_name(procname);
+	goodix_proc_entry = create_proc_entry(procname, 0666, NULL);
+	if (goodix_proc_entry == NULL) {
+		GTP_ERROR("Couldn't create proc entry!");
+		return FAIL;
+	} else {
+		GTP_INFO("Create proc entry success!");
+		goodix_proc_entry->write_proc = goodix_tool_write;
+		dix_proc_entry->read_proc = goodix_tool_read;
+	}
+
+	return SUCCESS;
+}
+
+void uninit_wr_node(void)
+{
+	kfree(cmd_head.data);
+	cmd_head.data = NULL;
+	unregister_i2c_func();
+	remove_proc_entry(procname, NULL);
+}
+
+static u8 relation(u8 src, u8 dst, u8 rlt)
+{
+	u8 ret = 0;
+
+	switch (rlt) {
+
+	case 0:
+		ret = (src != dst) ? true : false;
+		break;
+
+	case 1:
+		ret = (src == dst) ? true : false;
+		GTP_DEBUG("equal:src:0x%02x   dst:0x%02x  ret:%d.",
+					src, dst, (s32)ret);
+		break;
+
+	case 2:
+		ret = (src > dst) ? true : false;
+		break;
+
+	case 3:
+		ret = (src < dst) ? true : false;
+		break;
+
+	case 4:
+		ret = (src & dst) ? true : false;
+		break;
+
+	case 5:
+		ret = (!(src | dst)) ? true : false;
+		break;
+
+	default:
+		ret = false;
+		break;
+	}
+
+	return ret;
+}
+
+/*******************************************************
+Function:
+    Comfirm function.
+Input:
+  None.
+Output:
+    Return write length.
+********************************************************/
+static u8 comfirm(void)
+{
+	s32 i = 0;
+	u8 buf[32];
+
+/*    memcpy(&buf[GTP_ADDR_LENGTH - cmd_head.addr_len],
+			&cmd_head.flag_addr, cmd_head.addr_len);
+    memcpy(buf, &cmd_head.flag_addr, cmd_head.addr_len);
+		//Modified by Scott, 2012-02-17 */
+	memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len);
+
+	for (i = 0; i < cmd_head.times; i++) {
+		if (tool_i2c_read(buf, 1) <= 0) {
+			GTP_ERROR("Read flag data failed!");
+			return FAIL;
+		}
+		if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val,
+						cmd_head.flag_relation)) {
+			GTP_DEBUG("value at flag addr:0x%02x.",
+						buf[GTP_ADDR_LENGTH]);
+			GTP_DEBUG("flag value:0x%02x.", cmd_head.flag_val);
+			break;
+		}
+
+		msleep(cmd_head.circle);
+	}
+
+	if (i >= cmd_head.times) {
+		GTP_ERROR("Didn't get the flag to continue!");
+		return FAIL;
+	}
+
+	return SUCCESS;
+}
+
+/********************************************************
+Function:
+    Goodix tool write function.
+nput:
+  standard proc write function param.
+Output:
+    Return write length.
+********************************************************/
+static s32 goodix_tool_write(struct file *filp, const char __user *buff,
+						unsigned long len, void *data)
+{
+	s32 ret = 0;
+	GTP_DEBUG_FUNC();
+	GTP_DEBUG_ARRAY((u8 *)buff, len);
+
+	ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
+	if (ret)
+		GTP_ERROR("copy_from_user failed.");
+
+	GTP_DEBUG("wr  :0x%02x.", cmd_head.wr);
+	GTP_DEBUG("flag:0x%02x.", cmd_head.flag);
+	GTP_DEBUG("flag addr:0x%02x%02x.", cmd_head.flag_addr[0],
+						cmd_head.flag_addr[1]);
+	GTP_DEBUG("flag val:0x%02x.", cmd_head.flag_val);
+	GTP_DEBUG("flag rel:0x%02x.", cmd_head.flag_relation);
+	GTP_DEBUG("circle  :%d.", (s32)cmd_head.circle);
+	GTP_DEBUG("times   :%d.", (s32)cmd_head.times);
+	GTP_DEBUG("retry   :%d.", (s32)cmd_head.retry);
+	GTP_DEBUG("delay   :%d.", (s32)cmd_head.delay);
+	GTP_DEBUG("data len:%d.", (s32)cmd_head.data_len);
+	GTP_DEBUG("addr len:%d.", (s32)cmd_head.addr_len);
+	GTP_DEBUG("addr:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]);
+	GTP_DEBUG("len:%d.", (s32)len);
+	GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]);
+
+	if (cmd_head.wr == 1) {
+		/*  copy_from_user(&cmd_head.data[cmd_head.addr_len],
+				&buff[CMD_HEAD_LENGTH], cmd_head.data_len); */
+		ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
+				&buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+		if (ret)
+			GTP_ERROR("copy_from_user failed.");
+
+		memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
+					cmd_head.addr, cmd_head.addr_len);
+
+		GTP_DEBUG_ARRAY(cmd_head.data,
+				cmd_head.data_len + cmd_head.addr_len);
+		GTP_DEBUG_ARRAY((u8 *)&buff[CMD_HEAD_LENGTH],
+							cmd_head.data_len);
+
+		if (cmd_head.flag == 1) {
+			if (FAIL == comfirm()) {
+				GTP_ERROR("[WRITE]Comfirm fail!");
+				return FAIL;
+			}
+		} else if (cmd_head.flag == 2) {
+			/* Need interrupt! */
+		}
+		if (tool_i2c_write(
+		&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
+		cmd_head.data_len + cmd_head.addr_len) <= 0) {
+			GTP_ERROR("[WRITE]Write data failed!");
+			return FAIL;
+		}
+
+		GTP_DEBUG_ARRAY(
+			&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
+			cmd_head.data_len + cmd_head.addr_len);
+		if (cmd_head.delay)
+			msleep(cmd_head.delay);
+
+		return cmd_head.data_len + CMD_HEAD_LENGTH;
+	} else if (cmd_head.wr == 3) {  /* Write ic type */
+
+		ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH],
+				cmd_head.data_len);
+		if (ret)
+			GTP_ERROR("copy_from_user failed.");
+
+		memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
+
+		register_i2c_func();
+
+		return cmd_head.data_len + CMD_HEAD_LENGTH;
+	} else if (cmd_head.wr == 3) {
+
+		/* memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); */
+
+		return cmd_head.data_len + CMD_HEAD_LENGTH;
+	} else if (cmd_head.wr == 7) { /* disable irq! */
+		gtp_irq_disable(i2c_get_clientdata(gt_client));
+
+		#if GTP_ESD_PROTECT
+		gtp_esd_switch(gt_client, SWITCH_OFF);
+		#endif
+		return CMD_HEAD_LENGTH;
+	} else if (cmd_head.wr == 9) { /* enable irq! */
+		gtp_irq_enable(i2c_get_clientdata(gt_client));
+
+		#if GTP_ESD_PROTECT
+		gtp_esd_switch(gt_client, SWITCH_ON);
+		#endif
+		return CMD_HEAD_LENGTH;
+	} else if (cmd_head.wr == 17) {
+		struct goodix_ts_data *ts = i2c_get_clientdata(gt_client);
+		ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
+				&buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+		if (ret)
+			GTP_DEBUG("copy_from_user failed.");
+		if (cmd_head.data[GTP_ADDR_LENGTH]) {
+			GTP_DEBUG("gtp enter rawdiff.");
+			ts->gtp_rawdiff_mode = true;
+		} else {
+			ts->gtp_rawdiff_mode = false;
+			GTP_DEBUG("gtp leave rawdiff.");
+		}
+		return CMD_HEAD_LENGTH;
+	}
+#ifdef UPDATE_FUNCTIONS
+	else if (cmd_head.wr == 11) { /* Enter update mode! */
+		if (FAIL == gup_enter_update_mode(gt_client))
+			return FAIL;
+	} else if (cmd_head.wr == 13) { /* Leave update mode! */
+		gup_leave_update_mode();
+	} else if (cmd_head.wr == 15) { /* Update firmware! */
+		show_len = 0;
+		total_len = 0;
+		memset(cmd_head.data, 0, cmd_head.data_len + 1);
+		memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH],
+					cmd_head.data_len);
+
+		if (FAIL == gup_update_proc((void *)cmd_head.data))
+			return FAIL;
+	}
+#endif
+
+	return CMD_HEAD_LENGTH;
+}
+
+/*******************************************************
+Function:
+    Goodix tool read function.
+Input:
+  standard proc read function param.
+Output:
+    Return read length.
+********************************************************/
+static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
+							int *eof, void *data)
+{
+	GTP_DEBUG_FUNC();
+
+	if (cmd_head.wr % 2) {
+		return FAIL;
+	} else if (!cmd_head.wr) {
+		u16 len = 0;
+		s16 data_len = 0;
+		u16 loc = 0;
+
+		if (cmd_head.flag == 1) {
+			if (FAIL == comfirm()) {
+				GTP_ERROR("[READ]Comfirm fail!");
+				return FAIL;
+			}
+		} else if (cmd_head.flag == 2) {
+			/* Need interrupt! */
+		}
+
+		memcpy(cmd_head.data, cmd_head.addr, cmd_head.addr_len);
+
+		GTP_DEBUG("[CMD HEAD DATA] ADDR:0x%02x%02x.", cmd_head.data[0],
+							cmd_head.data[1]);
+		GTP_DEBUG("[CMD HEAD ADDR] ADDR:0x%02x%02x.", cmd_head.addr[0],
+							cmd_head.addr[1]);
+
+		if (cmd_head.delay)
+			msleep(cmd_head.delay);
+
+		data_len = cmd_head.data_len;
+		while (data_len > 0) {
+			if (data_len > DATA_LENGTH)
+				len = DATA_LENGTH;
+			else
+				len = data_len;
+
+			data_len -= DATA_LENGTH;
+
+			if (tool_i2c_read(cmd_head.data, len) <= 0) {
+				GTP_ERROR("[READ]Read data failed!");
+				return FAIL;
+			}
+			memcpy(&page[loc], &cmd_head.data[GTP_ADDR_LENGTH],
+									len);
+			loc += len;
+
+			GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH], len);
+			GTP_DEBUG_ARRAY(page, len);
+		}
+	} else if (cmd_head.wr == 2) {
+		/* memcpy(page, "gt8", cmd_head.data_len);
+		memcpy(page, "GT818", 5);
+		page[5] = 0; */
+
+		GTP_DEBUG("Return ic type:%s len:%d.", page,
+						(s32)cmd_head.data_len);
+		return cmd_head.data_len;
+		/* return sizeof(IC_TYPE_NAME); */
+	} else if (cmd_head.wr == 4) {
+		page[0] = show_len >> 8;
+		page[1] = show_len & 0xff;
+		page[2] = total_len >> 8;
+		page[3] = total_len & 0xff;
+
+		return cmd_head.data_len;
+	} else if (6 == cmd_head.wr) {
+		/* Read error code! */
+	} else if (8 == cmd_head.wr) { /*Read driver version */
+		/* memcpy(page, GTP_DRIVER_VERSION,
+				strlen(GTP_DRIVER_VERSION)); */
+		s32 tmp_len;
+		tmp_len = strlen(GTP_DRIVER_VERSION);
+		memcpy(page, GTP_DRIVER_VERSION, tmp_len);
+		page[tmp_len] = 0;
+	}
+
+	return cmd_head.data_len;
+}
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.c b/drivers/input/touchscreen/gt9xx/gt9xx.c
index b1dc08b..33ef141 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.c
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.c
@@ -1,1762 +1,2184 @@
 /* drivers/input/touchscreen/gt9xx.c
- * 
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Linux Foundation chooses to take subject only to the GPLv2 license
+ * terms, and distributes only under these terms.
+ *
  * 2010 - 2013 Goodix Technology.
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be a reference 
- * to you, when you are integrating the GOODiX's CTP IC into your system, 
- * but WITHOUT ANY WARRANTY; without even the implied warranty of 
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
+ *
+ * This program is distributed in the hope that it will be a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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.
- * 
+ *
  * Version: 1.8
  * Authors: andrew@goodix.com, meta@goodix.com
  * Release Date: 2013/04/25
  * Revision record:
- *      V1.0:   
- *          first Release. By Andrew, 2012/08/31 
+ *      V1.0:
+ *          first Release. By Andrew, 2012/08/31
  *      V1.2:
- *          modify gtp_reset_guitar,slot report,tracking_id & 0x0F. By Andrew, 2012/10/15
+ *          modify gtp_reset_guitar,slot report,tracking_id & 0x0F.
+ *                  By Andrew, 2012/10/15
  *      V1.4:
  *          modify gt9xx_update.c. By Andrew, 2012/12/12
- *      V1.6: 
+ *      V1.6:
  *          1. new heartbeat/esd_protect mechanism(add external watchdog)
- *          2. doze mode, sliding wakeup 
- *          3. 3 more cfg_group(GT9 Sensor_ID: 0~5) 
+ *          2. doze mode, sliding wakeup
+ *          3. 3 more cfg_group(GT9 Sensor_ID: 0~5)
  *          3. config length verification
  *          4. names & comments
  *                  By Meta, 2013/03/11
  *      V1.8:
- *          1. pen/stylus identification 
+ *          1. pen/stylus identification
  *          2. read double check & fixed config support
  *          2. new esd & slide wakeup optimization
  *                  By Meta, 2013/06/08
  */
 
-#include <linux/irq.h>
+#include <linux/regulator/consumer.h>
 #include "gt9xx.h"
 
-#if GTP_ICS_SLOT_REPORT
-    #include <linux/input/mt.h>
-#endif
+#include <linux/of_gpio.h>
 
-static const char *goodix_ts_name = "Goodix Capacitive TouchScreen";
-static struct workqueue_struct *goodix_wq;
-struct i2c_client * i2c_connect_client = NULL; 
-u8 config[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH]
-                = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff};
+#include <linux/input/mt.h>
+
+#define GOODIX_DEV_NAME	"Goodix-CTP"
+#define CFG_MAX_TOUCH_POINTS	5
+#define GOODIX_COORDS_ARR_SIZE	4
+#define MAX_BUTTONS		4
+
+/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
+#define GTP_I2C_ADDRESS_HIGH	0x14
+#define GTP_I2C_ADDRESS_LOW	0x5D
+#define CFG_GROUP_LEN(p_cfg_grp)  (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0]))
+
+#define GOODIX_VTG_MIN_UV	2600000
+#define GOODIX_VTG_MAX_UV	3300000
+#define GOODIX_I2C_VTG_MIN_UV	1800000
+#define GOODIX_I2C_VTG_MAX_UV	1800000
+#define GOODIX_VDD_LOAD_MIN_UA	0
+#define GOODIX_VDD_LOAD_MAX_UA	10000
+#define GOODIX_VIO_LOAD_MIN_UA	0
+#define GOODIX_VIO_LOAD_MAX_UA	10000
+
+#define RESET_DELAY_T3_US	200	/* T3: > 100us */
+#define RESET_DELAY_T4		20	/* T4: > 5ms */
+
+#define	PHY_BUF_SIZE		32
+
+#define GTP_MAX_TOUCH		5
+#define GTP_ESD_CHECK_CIRCLE_MS	2000
 
 #if GTP_HAVE_TOUCH_KEY
-    static const u16 touch_key_array[] = GTP_KEY_TAB;
-    #define GTP_MAX_KEY_NUM  (sizeof(touch_key_array)/sizeof(touch_key_array[0]))
-    
+static const u16 touch_key_array[] = {KEY_MENU, KEY_HOMEPAGE, KEY_BACK};
+#define GTP_MAX_KEY_NUM  (sizeof(touch_key_array)/sizeof(touch_key_array[0]))
+
 #if GTP_DEBUG_ON
-    static const int  key_codes[] = {KEY_HOME, KEY_BACK, KEY_MENU, KEY_SEARCH};
-    static const char *key_names[] = {"Key_Home", "Key_Back", "Key_Menu", "Key_Search"};
+static const int  key_codes[] = {
+	KEY_HOME, KEY_BACK, KEY_MENU, KEY_SEARCH
+};
+static const char *const key_names[] = {
+	"Key_Home", "Key_Back", "Key_Menu", "Key_Search"
+};
 #endif
-    
 #endif
 
-static s8 gtp_i2c_test(struct i2c_client *client);
-void gtp_reset_guitar(struct i2c_client *client, s32 ms);
-void gtp_int_sync(s32 ms);
+static void gtp_reset_guitar(struct goodix_ts_data *ts, int ms);
+static void gtp_int_sync(struct goodix_ts_data *ts, int ms);
+static int gtp_i2c_test(struct i2c_client *client);
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+				 unsigned long event, void *data);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
 static void goodix_ts_early_suspend(struct early_suspend *h);
 static void goodix_ts_late_resume(struct early_suspend *h);
 #endif
- 
-#if GTP_CREATE_WR_NODE
-extern s32 init_wr_node(struct i2c_client*);
-extern void uninit_wr_node(void);
-#endif
-
-#if GTP_AUTO_UPDATE
-extern u8 gup_init_update_proc(struct goodix_ts_data *);
-#endif
 
 #if GTP_ESD_PROTECT
 static struct delayed_work gtp_esd_check_work;
-static struct workqueue_struct * gtp_esd_check_workqueue = NULL;
-static void gtp_esd_check_func(struct work_struct *);
-static s32 gtp_init_ext_watchdog(struct i2c_client *client);
-void gtp_esd_switch(struct i2c_client *, s32);
+static struct workqueue_struct *gtp_esd_check_workqueue;
+static void gtp_esd_check_func(struct work_struct *work);
+static int gtp_init_ext_watchdog(struct i2c_client *client);
+struct i2c_client  *i2c_connect_client;
 #endif
 
-
 #if GTP_SLIDE_WAKEUP
-typedef enum
-{
-    DOZE_DISABLED = 0,
-    DOZE_ENABLED = 1,
-    DOZE_WAKEUP = 2,
-}DOZE_T;
-static DOZE_T doze_status = DOZE_DISABLED;
+enum doze_status {
+	DOZE_DISABLED = 0,
+	DOZE_ENABLED = 1,
+	DOZE_WAKEUP = 2,
+};
+static enum doze_status = DOZE_DISABLED;
 static s8 gtp_enter_doze(struct goodix_ts_data *ts);
 #endif
-
-static u8 chip_gt9xxs = 0;  // true if ic is gt9xxs, like gt915s
-u8 grp_cfg_version = 0;
+bool init_done;
+static u8 chip_gt9xxs;  /* true if ic is gt9xxs, like gt915s */
+u8 grp_cfg_version;
 
 /*******************************************************
 Function:
-    Read data from the i2c slave device.
+	Read data from the i2c slave device.
 Input:
-    client:     i2c device.
-    buf[0~1]:   read start address.
-    buf[2~len-1]:   read data buffer.
-    len:    GTP_ADDR_LENGTH + read bytes count
+	client:     i2c device.
+	buf[0~1]:   read start address.
+	buf[2~len-1]:   read data buffer.
+	len:    GTP_ADDR_LENGTH + read bytes count
 Output:
-    numbers of i2c_msgs to transfer: 
-      2: succeed, otherwise: failed
+	numbers of i2c_msgs to transfer:
+		2: succeed, otherwise: failed
 *********************************************************/
-s32 gtp_i2c_read(struct i2c_client *client, u8 *buf, s32 len)
+int gtp_i2c_read(struct i2c_client *client, u8 *buf, int len)
 {
-    struct i2c_msg msgs[2];
-    s32 ret=-1;
-    s32 retries = 0;
+	struct goodix_ts_data *ts = i2c_get_clientdata(client);
+	struct i2c_msg msgs[2];
+	int ret = -EIO;
+	int retries = 0;
 
-    GTP_DEBUG_FUNC();
+	GTP_DEBUG_FUNC();
 
-    msgs[0].flags = !I2C_M_RD;
-    msgs[0].addr  = client->addr;
-    msgs[0].len   = GTP_ADDR_LENGTH;
-    msgs[0].buf   = &buf[0];
-    //msgs[0].scl_rate = 300 * 1000;    // for Rockchip
-    
-    msgs[1].flags = I2C_M_RD;
-    msgs[1].addr  = client->addr;
-    msgs[1].len   = len - GTP_ADDR_LENGTH;
-    msgs[1].buf   = &buf[GTP_ADDR_LENGTH];
-    //msgs[1].scl_rate = 300 * 1000;
+	msgs[0].flags = !I2C_M_RD;
+	msgs[0].addr = client->addr;
+	msgs[0].len = GTP_ADDR_LENGTH;
+	msgs[0].buf = &buf[0];
 
-    while(retries < 5)
-    {
-        ret = i2c_transfer(client->adapter, msgs, 2);
-        if(ret == 2)break;
-        retries++;
-    }
-    if((retries >= 5))
-    {
-    #if GTP_SLIDE_WAKEUP
-        // reset chip would quit doze mode
-        if (DOZE_ENABLED == doze_status)
-        {
-            return ret;
-        }
-    #endif
-        GTP_DEBUG("I2C communication timeout, resetting chip...");
-        gtp_reset_guitar(client, 10);
-    }
-    return ret;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].addr = client->addr;
+	msgs[1].len = len - GTP_ADDR_LENGTH;
+	msgs[1].buf = &buf[GTP_ADDR_LENGTH];
+
+	while (retries < 5) {
+		ret = i2c_transfer(client->adapter, msgs, 2);
+		if (ret == 2)
+			break;
+		retries++;
+	}
+	if (retries >= 5) {
+#if GTP_SLIDE_WAKEUP
+		/* reset chip would quit doze mode */
+		if (DOZE_ENABLED == doze_status)
+			return ret;
+#endif
+		GTP_DEBUG("I2C communication timeout, resetting chip...");
+		if (init_done)
+			gtp_reset_guitar(ts, 10);
+		else
+			dev_warn(&client->dev,
+				"<GTP> gtp_reset_guitar exit init_done=%d:\n",
+				init_done);
+	}
+	return ret;
 }
 
 /*******************************************************
 Function:
-    Write data to the i2c slave device.
+	Write data to the i2c slave device.
 Input:
-    client:     i2c device.
-    buf[0~1]:   write start address.
-    buf[2~len-1]:   data buffer
-    len:    GTP_ADDR_LENGTH + write bytes count
+	client:     i2c device.
+	buf[0~1]:   write start address.
+	buf[2~len-1]:   data buffer
+	len:    GTP_ADDR_LENGTH + write bytes count
 Output:
-    numbers of i2c_msgs to transfer: 
-        1: succeed, otherwise: failed
+	numbers of i2c_msgs to transfer:
+	1: succeed, otherwise: failed
 *********************************************************/
-s32 gtp_i2c_write(struct i2c_client *client,u8 *buf,s32 len)
+int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len)
 {
-    struct i2c_msg msg;
-    s32 ret = -1;
-    s32 retries = 0;
+	struct goodix_ts_data *ts = i2c_get_clientdata(client);
+	struct i2c_msg msg;
+	int ret = -EIO;
+	int retries = 0;
 
-    GTP_DEBUG_FUNC();
+	GTP_DEBUG_FUNC();
 
-    msg.flags = !I2C_M_RD;
-    msg.addr  = client->addr;
-    msg.len   = len;
-    msg.buf   = buf;
-    //msg.scl_rate = 300 * 1000;    // for Rockchip
+	msg.flags = !I2C_M_RD;
+	msg.addr = client->addr;
+	msg.len = len;
+	msg.buf = buf;
 
-    while(retries < 5)
-    {
-        ret = i2c_transfer(client->adapter, &msg, 1);
-        if (ret == 1)break;
-        retries++;
-    }
-    if((retries >= 5))
-    {
-    #if GTP_SLIDE_WAKEUP
-        if (DOZE_ENABLED == doze_status)
-        {
-            return ret;
-        }
-    #endif
-        GTP_DEBUG("I2C communication timeout, resetting chip...");
-        gtp_reset_guitar(client, 10);
-    }
-    return ret;
+	while (retries < 5) {
+		ret = i2c_transfer(client->adapter, &msg, 1);
+		if (ret == 1)
+			break;
+		retries++;
+	}
+	if ((retries >= 5)) {
+#if GTP_SLIDE_WAKEUP
+		if (DOZE_ENABLED == doze_status)
+			return ret;
+#endif
+		GTP_DEBUG("I2C communication timeout, resetting chip...");
+		if (init_done)
+			gtp_reset_guitar(ts, 10);
+		else
+			dev_warn(&client->dev,
+				"<GTP> gtp_reset_guitar exit init_done=%d:\n",
+				init_done);
+	}
+	return ret;
 }
 /*******************************************************
 Function:
-    i2c read twice, compare the results
+	i2c read twice, compare the results
 Input:
-    client:  i2c device
-    addr:    operate address
-    rxbuf:   read data to store, if compare successful
-    len:     bytes to read
+	client:  i2c device
+	addr:    operate address
+	rxbuf:   read data to store, if compare successful
+	len:     bytes to read
 Output:
-    FAIL:    read failed
-    SUCCESS: read successful
+	FAIL:    read failed
+	SUCCESS: read successful
 *********************************************************/
-s32 gtp_i2c_read_dbl_check(struct i2c_client *client, u16 addr, u8 *rxbuf, int len)
+int gtp_i2c_read_dbl_check(struct i2c_client *client,
+			u16 addr, u8 *rxbuf, int len)
 {
-    u8 buf[16] = {0};
-    u8 confirm_buf[16] = {0};
-    u8 retry = 0;
-    
-    while (retry++ < 3)
-    {
-        memset(buf, 0xAA, 16);
-        buf[0] = (u8)(addr >> 8);
-        buf[1] = (u8)(addr & 0xFF);
-        gtp_i2c_read(client, buf, len + 2);
-        
-        memset(confirm_buf, 0xAB, 16);
-        confirm_buf[0] = (u8)(addr >> 8);
-        confirm_buf[1] = (u8)(addr & 0xFF);
-        gtp_i2c_read(client, confirm_buf, len + 2);
-        
-        if (!memcmp(buf, confirm_buf, len+2))
-        {
-            break;
-        }
-    }    
-    if (retry < 3)
-    {
-        memcpy(rxbuf, confirm_buf+2, len);
-        return SUCCESS;
-    }
-    else
-    {
-        GTP_ERROR("i2c read 0x%04X, %d bytes, double check failed!", addr, len);
-        return FAIL;
-    }
+	u8 buf[16] = {0};
+	u8 confirm_buf[16] = {0};
+	u8 retry = 0;
+
+	while (retry++ < 3) {
+		memset(buf, 0xAA, 16);
+		buf[0] = (u8)(addr >> 8);
+		buf[1] = (u8)(addr & 0xFF);
+		gtp_i2c_read(client, buf, len + 2);
+
+		memset(confirm_buf, 0xAB, 16);
+		confirm_buf[0] = (u8)(addr >> 8);
+		confirm_buf[1] = (u8)(addr & 0xFF);
+		gtp_i2c_read(client, confirm_buf, len + 2);
+
+		if (!memcmp(buf, confirm_buf, len + 2))
+			break;
+	}
+	if (retry < 3) {
+		memcpy(rxbuf, confirm_buf + 2, len);
+		return SUCCESS;
+	} else {
+		dev_err(&client->dev,
+			"i2c read 0x%04X, %d bytes, double check failed!",
+			addr, len);
+		return FAIL;
+	}
 }
 
 /*******************************************************
 Function:
-    Send config.
+	Send config data.
 Input:
-    client: i2c device.
+	client: i2c device.
 Output:
-    result of i2c write operation. 
-        1: succeed, otherwise: failed
+	result of i2c write operation.
+	> 0: succeed, otherwise: failed
 *********************************************************/
-s32 gtp_send_cfg(struct i2c_client *client)
+static int gtp_send_cfg(struct goodix_ts_data *ts)
 {
-    s32 ret = 2;
-    
+	int ret;
 #if GTP_DRIVER_SEND_CFG
-    s32 retry = 0;
-    struct goodix_ts_data *ts = i2c_get_clientdata(client);
-    
-    if (ts->fixed_cfg)
-    {
-        GTP_INFO("Ic fixed config, no config sent!");
-        return 2;
-    }
-    GTP_INFO("driver send config");
-    for (retry = 0; retry < 5; retry++)
-    {
-        ret = gtp_i2c_write(client, config , GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH);
-        if (ret > 0)
-        {
-            break;
-        }
-    }
+	int retry = 0;
+
+	if (ts->fixed_cfg) {
+		dev_dbg(&ts->client->dev,
+			"Ic fixed config, no config sent!");
+		ret = 2;
+	} else {
+		for (retry = 0; retry < 5; retry++) {
+			ret = gtp_i2c_write(ts->client,
+				ts->config_data,
+				GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH);
+			if (ret > 0)
+				break;
+		}
+	}
 #endif
 
-    return ret;
+	return ret;
 }
 
 /*******************************************************
 Function:
-    Disable irq function
+	Disable irq function
 Input:
-    ts: goodix i2c_client private data
+	ts: goodix i2c_client private data
 Output:
-    None.
+	None.
 *********************************************************/
 void gtp_irq_disable(struct goodix_ts_data *ts)
 {
-    unsigned long irqflags;
+	unsigned long irqflags;
 
-    GTP_DEBUG_FUNC();
+	GTP_DEBUG_FUNC();
 
-    spin_lock_irqsave(&ts->irq_lock, irqflags);
-    if (!ts->irq_is_disable)
-    {
-        ts->irq_is_disable = 1; 
-        disable_irq_nosync(ts->client->irq);
-    }
-    spin_unlock_irqrestore(&ts->irq_lock, irqflags);
+	spin_lock_irqsave(&ts->irq_lock, irqflags);
+	if (!ts->irq_is_disabled) {
+		ts->irq_is_disabled = true;
+		disable_irq_nosync(ts->client->irq);
+	}
+	spin_unlock_irqrestore(&ts->irq_lock, irqflags);
 }
 
 /*******************************************************
 Function:
-    Enable irq function
+	Enable irq function
 Input:
-    ts: goodix i2c_client private data
+	ts: goodix i2c_client private data
 Output:
-    None.
+	None.
 *********************************************************/
 void gtp_irq_enable(struct goodix_ts_data *ts)
 {
-    unsigned long irqflags = 0;
+	unsigned long irqflags = 0;
 
-    GTP_DEBUG_FUNC();
-    
-    spin_lock_irqsave(&ts->irq_lock, irqflags);
-    if (ts->irq_is_disable) 
-    {
-        enable_irq(ts->client->irq);
-        ts->irq_is_disable = 0; 
-    }
-    spin_unlock_irqrestore(&ts->irq_lock, irqflags);
+	GTP_DEBUG_FUNC();
+
+	spin_lock_irqsave(&ts->irq_lock, irqflags);
+	if (ts->irq_is_disabled) {
+		enable_irq(ts->client->irq);
+		ts->irq_is_disabled = false;
+	}
+	spin_unlock_irqrestore(&ts->irq_lock, irqflags);
 }
 
-
 /*******************************************************
 Function:
-    Report touch point event 
+	Report touch point event
 Input:
-    ts: goodix i2c_client private data
-    id: trackId
-    x:  input x coordinate
-    y:  input y coordinate
-    w:  input pressure
+	ts: goodix i2c_client private data
+	id: trackId
+	x:  input x coordinate
+	y:  input y coordinate
+	w:  input pressure
 Output:
-    None.
+	None.
 *********************************************************/
-static void gtp_touch_down(struct goodix_ts_data* ts,s32 id,s32 x,s32 y,s32 w)
+static void gtp_touch_down(struct goodix_ts_data *ts, int id, int x, int y,
+		int w)
 {
 #if GTP_CHANGE_X2Y
-    GTP_SWAP(x, y);
+	GTP_SWAP(x, y);
 #endif
 
-#if GTP_ICS_SLOT_REPORT
-    input_mt_slot(ts->input_dev, id);
-    input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, id);
-    input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
-    input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
-    input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w);
-    input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
-#else
-    input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
-    input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
-    input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w);
-    input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
-    input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, id);
-    input_mt_sync(ts->input_dev);
-#endif
+	input_mt_slot(ts->input_dev, id);
+	input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
+	input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
+	input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
+	input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w);
+	input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
 
-    GTP_DEBUG("ID:%d, X:%d, Y:%d, W:%d", id, x, y, w);
+	GTP_DEBUG("ID:%d, X:%d, Y:%d, W:%d", id, x, y, w);
 }
 
 /*******************************************************
 Function:
-    Report touch release event
+	Report touch release event
 Input:
-    ts: goodix i2c_client private data
+	ts: goodix i2c_client private data
 Output:
-    None.
+	None.
 *********************************************************/
-static void gtp_touch_up(struct goodix_ts_data* ts, s32 id)
+static void gtp_touch_up(struct goodix_ts_data *ts, int id)
 {
-#if GTP_ICS_SLOT_REPORT
-    input_mt_slot(ts->input_dev, id);
-    input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
-    GTP_DEBUG("Touch id[%2d] release!", id);
-#else
-    input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
-    input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0);
-    input_mt_sync(ts->input_dev);
-#endif
+	input_mt_slot(ts->input_dev, id);
+	input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false);
+	GTP_DEBUG("Touch id[%2d] release!", id);
 }
 
 
+
 /*******************************************************
 Function:
-    Goodix touchscreen work function
+	Goodix touchscreen work function
 Input:
-    work: work struct of goodix_workqueue
+	work: work struct of goodix_workqueue
 Output:
-    None.
+	None.
 *********************************************************/
 static void goodix_ts_work_func(struct work_struct *work)
 {
-    u8  end_cmd[3] = {GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF, 0};
-    u8  point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1]={GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF};
-    u8  touch_num = 0;
-    u8  finger = 0;
-    static u16 pre_touch = 0;
-    static u8 pre_key = 0;
+	u8 end_cmd[3] = { GTP_READ_COOR_ADDR >> 8,
+			GTP_READ_COOR_ADDR & 0xFF, 0};
+	u8 point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1] = {
+			GTP_READ_COOR_ADDR >> 8,
+			GTP_READ_COOR_ADDR & 0xFF};
+	u8 touch_num = 0;
+	u8 finger = 0;
+	static u16 pre_touch;
+	static u8 pre_key;
 #if GTP_WITH_PEN
-    static u8 pre_pen = 0;
+	static u8 pre_pen;
 #endif
-    u8  key_value = 0;
-    u8* coor_data = NULL;
-    s32 input_x = 0;
-    s32 input_y = 0;
-    s32 input_w = 0;
-    s32 id = 0;
-    s32 i  = 0;
-    s32 ret = -1;
-    struct goodix_ts_data *ts = NULL;
+	u8 key_value = 0;
+	u8 *coor_data = NULL;
+	s32 input_x = 0;
+	s32 input_y = 0;
+	s32 input_w = 0;
+	s32 id = 0;
+	s32 i = 0;
+	int ret = -1;
+	struct goodix_ts_data *ts = NULL;
 
 #if GTP_SLIDE_WAKEUP
-    u8 doze_buf[3] = {0x81, 0x4B};
+	u8 doze_buf[3] = {0x81, 0x4B};
 #endif
 
-    GTP_DEBUG_FUNC();
-    ts = container_of(work, struct goodix_ts_data, work);
-    if (ts->enter_update)
-    {
-        return;
-    }
+	GTP_DEBUG_FUNC();
+
+	ts = container_of(work, struct goodix_ts_data, work);
+#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE
+	if (ts->enter_update)
+		return;
+#endif
+
 #if GTP_SLIDE_WAKEUP
-    if (DOZE_ENABLED == doze_status)
-    {               
-        ret = gtp_i2c_read(i2c_connect_client, doze_buf, 3);
-        GTP_DEBUG("0x814B = 0x%02X", doze_buf[2]);
-        if (ret > 0)
-        {               
-            if (doze_buf[2] == 0xAA)
-            {
-                GTP_INFO("Slide(0xAA) To Light up the screen!");
-                doze_status = DOZE_WAKEUP;
-                input_report_key(ts->input_dev, KEY_POWER, 1);
-                input_sync(ts->input_dev);
-                input_report_key(ts->input_dev, KEY_POWER, 0);
-                input_sync(ts->input_dev);
-                // clear 0x814B
-                doze_buf[2] = 0x00;
-                gtp_i2c_write(i2c_connect_client, doze_buf, 3);
-            }
-            else if (doze_buf[2] == 0xBB)
-            {
-                GTP_INFO("Slide(0xBB) To Light up the screen!");
-                doze_status = DOZE_WAKEUP;
-                input_report_key(ts->input_dev, KEY_POWER, 1);
-                input_sync(ts->input_dev);
-                input_report_key(ts->input_dev, KEY_POWER, 0);
-                input_sync(ts->input_dev);
-                // clear 0x814B
-                doze_buf[2] = 0x00;
-                gtp_i2c_write(i2c_connect_client, doze_buf, 3);
-            }
-            else if (0xC0 == (doze_buf[2] & 0xC0))
-            {
-                GTP_INFO("double click to light up the screen!");
-                doze_status = DOZE_WAKEUP;
-                input_report_key(ts->input_dev, KEY_POWER, 1);
-                input_sync(ts->input_dev);
-                input_report_key(ts->input_dev, KEY_POWER, 0);
-                input_sync(ts->input_dev);
-                // clear 0x814B
-                doze_buf[2] = 0x00;
-                gtp_i2c_write(i2c_connect_client, doze_buf, 3);
-            }
-            else
-            {
-                gtp_enter_doze(ts);
-            }
-        }
-        if (ts->use_irq)
-        {
-            gtp_irq_enable(ts);
-        }
-        return;
-    }
+	if (DOZE_ENABLED == doze_status) {
+		ret = gtp_i2c_read(ts->client, doze_buf, 3);
+		GTP_DEBUG("0x814B = 0x%02X", doze_buf[2]);
+		if (ret > 0) {
+			if (doze_buf[2] == 0xAA) {
+				dev_dbg(&ts->client->dev,
+					"Slide(0xAA) To Light up the screen!");
+				doze_status = DOZE_WAKEUP;
+				input_report_key(
+					ts->input_dev, KEY_POWER, 1);
+				input_sync(ts->input_dev);
+				input_report_key(
+					ts->input_dev, KEY_POWER, 0);
+				input_sync(ts->input_dev);
+				/* clear 0x814B */
+				doze_buf[2] = 0x00;
+				gtp_i2c_write(ts->client, doze_buf, 3);
+			} else if (doze_buf[2] == 0xBB) {
+				dev_dbg(&ts->client->dev,
+					"Slide(0xBB) To Light up the screen!");
+				doze_status = DOZE_WAKEUP;
+				input_report_key(ts->input_dev, KEY_POWER, 1);
+				input_sync(ts->input_dev);
+				input_report_key(ts->input_dev, KEY_POWER, 0);
+				input_sync(ts->input_dev);
+				/* clear 0x814B*/
+				doze_buf[2] = 0x00;
+				gtp_i2c_write(ts->client, doze_buf, 3);
+			} else if (0xC0 == (doze_buf[2] & 0xC0)) {
+				dev_dbg(&ts->client->dev,
+					"double click to light up the screen!");
+				doze_status = DOZE_WAKEUP;
+				input_report_key(ts->input_dev, KEY_POWER, 1);
+				input_sync(ts->input_dev);
+				input_report_key(ts->input_dev, KEY_POWER, 0);
+				input_sync(ts->input_dev);
+				/* clear 0x814B */
+				doze_buf[2] = 0x00;
+				gtp_i2c_write(ts->client, doze_buf, 3);
+			} else {
+				gtp_enter_doze(ts);
+			}
+		}
+		if (ts->use_irq)
+			gtp_irq_enable(ts);
+
+		return;
+	}
 #endif
 
-    ret = gtp_i2c_read(ts->client, point_data, 12);
-    if (ret < 0)
-    {
-        GTP_ERROR("I2C transfer error. errno:%d\n ", ret);
-        goto exit_work_func;
-    }
+	ret = gtp_i2c_read(ts->client, point_data, 12);
+	if (ret < 0) {
+		dev_err(&ts->client->dev,
+				"I2C transfer error. errno:%d\n ", ret);
+		goto exit_work_func;
+	}
 
-    finger = point_data[GTP_ADDR_LENGTH];    
-    if((finger & 0x80) == 0)
-    {
-        goto exit_work_func;
-    }
+	finger = point_data[GTP_ADDR_LENGTH];
+	if ((finger & 0x80) == 0)
+		goto exit_work_func;
 
-    touch_num = finger & 0x0f;
-    if (touch_num > GTP_MAX_TOUCH)
-    {
-        goto exit_work_func;
-    }
+	touch_num = finger & 0x0f;
+	if (touch_num > GTP_MAX_TOUCH)
+		goto exit_work_func;
 
-    if (touch_num > 1)
-    {
-        u8 buf[8 * GTP_MAX_TOUCH] = {(GTP_READ_COOR_ADDR + 10) >> 8, (GTP_READ_COOR_ADDR + 10) & 0xff};
+	if (touch_num > 1) {
+		u8 buf[8 * GTP_MAX_TOUCH] = { (GTP_READ_COOR_ADDR + 10) >> 8,
+				(GTP_READ_COOR_ADDR + 10) & 0xff };
 
-        ret = gtp_i2c_read(ts->client, buf, 2 + 8 * (touch_num - 1)); 
-        memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1));
-    }
+		ret = gtp_i2c_read(ts->client, buf,
+				2 + 8 * (touch_num - 1));
+		memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1));
+	}
 
 #if GTP_HAVE_TOUCH_KEY
-    key_value = point_data[3 + 8 * touch_num];
-    
-    if(key_value || pre_key)
-    {
-        for (i = 0; i < GTP_MAX_KEY_NUM; i++)
-        {
-        #if GTP_DEBUG_ON
-            for (ret = 0; ret < 4; ++ret)
-            {
-                if (key_codes[ret] == touch_key_array[i])
-                {
-                    GTP_DEBUG("Key: %s %s", key_names[ret], (key_value & (0x01 << i)) ? "Down" : "Up");
-                    break;
-                }
-            }
-        #endif
-            input_report_key(ts->input_dev, touch_key_array[i], key_value & (0x01<<i));   
-        }
-        touch_num = 0;
-        pre_touch = 0;
-    }
+	key_value = point_data[3 + 8 * touch_num];
+
+	if (key_value || pre_key) {
+		for (i = 0; i < GTP_MAX_KEY_NUM; i++) {
+#if GTP_DEBUG_ON
+			for (ret = 0; ret < 4; ++ret) {
+				if (key_codes[ret] == touch_key_array[i]) {
+					GTP_DEBUG("Key: %s %s",
+						key_names[ret],
+						(key_value & (0x01 << i))
+						? "Down" : "Up");
+					break;
+				}
+			}
 #endif
-    pre_key = key_value;
 
-    GTP_DEBUG("pre_touch:%02x, finger:%02x.", pre_touch, finger);
+			input_report_key(ts->input_dev,
+				touch_key_array[i], key_value & (0x01<<i));
+		}
+		touch_num = 0;
+		pre_touch = 0;
+	}
+#endif
+	pre_key = key_value;
 
-#if GTP_ICS_SLOT_REPORT
+	GTP_DEBUG("pre_touch:%02x, finger:%02x.", pre_touch, finger);
 
 #if GTP_WITH_PEN
-    if (pre_pen && (touch_num == 0))
-    {
-        GTP_DEBUG("Pen touch UP(Slot)!");
-        input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
-        input_mt_slot(ts->input_dev, 5);
-        input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
-        pre_pen = 0;
-    }
+	if (pre_pen && (touch_num == 0)) {
+		GTP_DEBUG("Pen touch UP(Slot)!");
+		input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
+		input_mt_slot(ts->input_dev, 5);
+		input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
+		pre_pen = 0;
+	}
 #endif
-    if (pre_touch || touch_num)
-    {
-        s32 pos = 0;
-        u16 touch_index = 0;
+	if (pre_touch || touch_num) {
+		s32 pos = 0;
+		u16 touch_index = 0;
 
-        coor_data = &point_data[3];
-        
-        if(touch_num)
-        {
-            id = coor_data[pos] & 0x0F;
-        
-        #if GTP_WITH_PEN
-            id = coor_data[pos];
-            if ((id == 128))  
-            {
-                GTP_DEBUG("Pen touch DOWN(Slot)!");
-                input_x  = coor_data[pos + 1] | (coor_data[pos + 2] << 8);
-                input_y  = coor_data[pos + 3] | (coor_data[pos + 4] << 8);
-                input_w  = coor_data[pos + 5] | (coor_data[pos + 6] << 8);
-                
-                input_report_key(ts->input_dev, BTN_TOOL_PEN, 1);
-                input_mt_slot(ts->input_dev, 5);
-                input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 5);
-                input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
-                input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);
-                input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
-                GTP_DEBUG("Pen/Stylus: (%d, %d)[%d]", input_x, input_y, input_w);
-                pre_pen = 1;
-                pre_touch = 0;
-            }    
-        #endif
-        
-            touch_index |= (0x01<<id);
-        }
-        
-        GTP_DEBUG("id = %d,touch_index = 0x%x, pre_touch = 0x%x\n",id, touch_index,pre_touch);
-        for (i = 0; i < GTP_MAX_TOUCH; i++)
-        {
-        #if GTP_WITH_PEN
-            if (pre_pen == 1)
-            {
-                break;
-            }
-        #endif
-        
-            if (touch_index & (0x01<<i))
-            {
-                input_x  = coor_data[pos + 1] | (coor_data[pos + 2] << 8);
-                input_y  = coor_data[pos + 3] | (coor_data[pos + 4] << 8);
-                input_w  = coor_data[pos + 5] | (coor_data[pos + 6] << 8);
+		coor_data = &point_data[3];
+		if (touch_num) {
+			id = coor_data[pos] & 0x0F;
+#if GTP_WITH_PEN
+			id = coor_data[pos];
+			if (id == 128) {
+				GTP_DEBUG("Pen touch DOWN(Slot)!");
+				input_x  = coor_data[pos + 1]
+					| (coor_data[pos + 2] << 8);
+				input_y  = coor_data[pos + 3]
+					| (coor_data[pos + 4] << 8);
+				input_w  = coor_data[pos + 5]
+					| (coor_data[pos + 6] << 8);
 
-                gtp_touch_down(ts, id, input_x, input_y, input_w);
-                pre_touch |= 0x01 << i;
-                
-                pos += 8;
-                id = coor_data[pos] & 0x0F;
-                touch_index |= (0x01<<id);
-            }
-            else
-            {
-                gtp_touch_up(ts, i);
-                pre_touch &= ~(0x01 << i);
-            }
-        }
-    }
-#else
-    input_report_key(ts->input_dev, BTN_TOUCH, (touch_num || key_value));
-    if (touch_num)
-    {
-        for (i = 0; i < touch_num; i++)
-        {
-            coor_data = &point_data[i * 8 + 3];
-
-            id = coor_data[0];      //  & 0x0F;
-            input_x  = coor_data[1] | (coor_data[2] << 8);
-            input_y  = coor_data[3] | (coor_data[4] << 8);
-            input_w  = coor_data[5] | (coor_data[6] << 8);
-        
-        #if GTP_WITH_PEN
-            if (id == 128)
-            {
-                GTP_DEBUG("Pen touch DOWN!");
-                input_report_key(ts->input_dev, BTN_TOOL_PEN, 1);
-                pre_pen = 1;
-                id = 0;   
-            }
-        #endif
-        
-            gtp_touch_down(ts, id, input_x, input_y, input_w);
-        }
-    }
-    else if (pre_touch)
-    {
-    
-    #if GTP_WITH_PEN
-        if (pre_pen == 1)
-        {
-            GTP_DEBUG("Pen touch UP!");
-            input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
-            pre_pen = 0;
-        }
-    #endif
-    
-        GTP_DEBUG("Touch Release!");
-        gtp_touch_up(ts, 0);
-    }
-
-    pre_touch = touch_num;
+				input_report_key(ts->input_dev,
+					BTN_TOOL_PEN, 1);
+				input_mt_slot(ts->input_dev, 5);
+				input_report_abs(ts->input_dev,
+					ABS_MT_TRACKING_ID, 5);
+				input_report_abs(ts->input_dev,
+					ABS_MT_POSITION_X, input_x);
+				input_report_abs(ts->input_dev,
+					ABS_MT_POSITION_Y, input_y);
+				input_report_abs(ts->input_dev,
+					ABS_MT_TOUCH_MAJOR, input_w);
+				GTP_DEBUG("Pen/Stylus: (%d, %d)[%d]",
+					input_x, input_y, input_w);
+				pre_pen = 1;
+				pre_touch = 0;
+			}
 #endif
 
-    input_sync(ts->input_dev);
+			touch_index |= (0x01<<id);
+		}
+
+		GTP_DEBUG("id = %d,touch_index = 0x%x, pre_touch = 0x%x\n",
+			id, touch_index, pre_touch);
+		for (i = 0; i < GTP_MAX_TOUCH; i++) {
+#if GTP_WITH_PEN
+			if (pre_pen == 1)
+				break;
+#endif
+			if (touch_index & (0x01<<i)) {
+				input_x = coor_data[pos + 1] |
+						coor_data[pos + 2] << 8;
+				input_y = coor_data[pos + 3] |
+						coor_data[pos + 4] << 8;
+				input_w = coor_data[pos + 5] |
+						coor_data[pos + 6] << 8;
+
+				gtp_touch_down(ts, id,
+						input_x, input_y, input_w);
+				pre_touch |= 0x01 << i;
+
+				pos += 8;
+				id = coor_data[pos] & 0x0F;
+				touch_index |= (0x01<<id);
+			} else {
+				gtp_touch_up(ts, i);
+				pre_touch &= ~(0x01 << i);
+			}
+		}
+	}
+	input_sync(ts->input_dev);
 
 exit_work_func:
-    if(!ts->gtp_rawdiff_mode)
-    {
-        ret = gtp_i2c_write(ts->client, end_cmd, 3);
-        if (ret < 0)
-        {
-            GTP_INFO("I2C write end_cmd error!");
-        }
-    }
-    if (ts->use_irq)
-    {
-        gtp_irq_enable(ts);
-    }
+	if (!ts->gtp_rawdiff_mode) {
+		ret = gtp_i2c_write(ts->client, end_cmd, 3);
+		if (ret < 0)
+			dev_warn(&ts->client->dev, "I2C write end_cmd error!\n");
+
+	}
+	if (ts->use_irq)
+		gtp_irq_enable(ts);
+
+	return;
 }
 
 /*******************************************************
 Function:
-    Timer interrupt service routine for polling mode.
+	Timer interrupt service routine for polling mode.
 Input:
-    timer: timer struct pointer
+	timer: timer struct pointer
 Output:
-    Timer work mode. 
-        HRTIMER_NORESTART: no restart mode
+	Timer work mode.
+	HRTIMER_NORESTART: no restart mode
 *********************************************************/
 static enum hrtimer_restart goodix_ts_timer_handler(struct hrtimer *timer)
 {
-    struct goodix_ts_data *ts = container_of(timer, struct goodix_ts_data, timer);
+	struct goodix_ts_data
+		*ts = container_of(timer, struct goodix_ts_data, timer);
 
-    GTP_DEBUG_FUNC();
+	GTP_DEBUG_FUNC();
 
-    queue_work(goodix_wq, &ts->work);
-    hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME+6)*1000000), HRTIMER_MODE_REL);
-    return HRTIMER_NORESTART;
+	queue_work(ts->goodix_wq, &ts->work);
+	hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME + 6) * 1000000),
+			HRTIMER_MODE_REL);
+	return HRTIMER_NORESTART;
 }
 
 /*******************************************************
 Function:
-    External interrupt service routine for interrupt mode.
+	External interrupt service routine for interrupt mode.
 Input:
-    irq:  interrupt number.
-    dev_id: private data pointer
+	irq:  interrupt number.
+	dev_id: private data pointer
 Output:
-    Handle Result.
-        IRQ_HANDLED: interrupt handled successfully
+	Handle Result.
+	IRQ_HANDLED: interrupt handled successfully
 *********************************************************/
 static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
 {
-    struct goodix_ts_data *ts = dev_id;
+	struct goodix_ts_data *ts = dev_id;
 
-    GTP_DEBUG_FUNC();
- 
-    gtp_irq_disable(ts);
+	GTP_DEBUG_FUNC();
 
-    queue_work(goodix_wq, &ts->work);
-    
-    return IRQ_HANDLED;
+	gtp_irq_disable(ts);
+
+	queue_work(ts->goodix_wq, &ts->work);
+
+	return IRQ_HANDLED;
 }
 /*******************************************************
 Function:
-    Synchronization.
+	Synchronization.
 Input:
-    ms: synchronization time in millisecond.
+	ms: synchronization time in millisecond.
 Output:
-    None.
+	None.
 *******************************************************/
-void gtp_int_sync(s32 ms)
+void gtp_int_sync(struct goodix_ts_data *ts, int ms)
 {
-    GTP_GPIO_OUTPUT(GTP_INT_PORT, 0);
-    msleep(ms);
-    GTP_GPIO_AS_INT(GTP_INT_PORT);
+	gpio_direction_output(ts->pdata->irq_gpio, 0);
+	msleep(ms);
+	gpio_direction_input(ts->pdata->irq_gpio);
 }
 
 /*******************************************************
 Function:
-    Reset chip.
+	Reset chip.
 Input:
-    ms: reset time in millisecond
+	ms: reset time in millisecond, must >10ms
 Output:
-    None.
+	None.
 *******************************************************/
-void gtp_reset_guitar(struct i2c_client *client, s32 ms)
+static void gtp_reset_guitar(struct goodix_ts_data *ts, int ms)
 {
-    GTP_DEBUG_FUNC();
+	GTP_DEBUG_FUNC();
 
-    GTP_GPIO_OUTPUT(GTP_RST_PORT, 0);   // begin select I2C slave addr
-    msleep(ms);                         // T2: > 10ms
-    // HIGH: 0x28/0x29, LOW: 0xBA/0xBB
-    GTP_GPIO_OUTPUT(GTP_INT_PORT, client->addr == 0x14);
+	/* This reset sequence will selcet I2C slave address */
+	gpio_direction_output(ts->pdata->reset_gpio, 0);
+	msleep(ms);
 
-    msleep(2);                          // T3: > 100us
-    GTP_GPIO_OUTPUT(GTP_RST_PORT, 1);
-    
-    msleep(6);                          // T4: > 5ms
+	if (ts->client->addr == GTP_I2C_ADDRESS_HIGH)
+		gpio_direction_output(ts->pdata->irq_gpio, 1);
+	else
+		gpio_direction_output(ts->pdata->irq_gpio, 0);
 
-    GTP_GPIO_AS_INPUT(GTP_RST_PORT);    // end select I2C slave addr
+	usleep(RESET_DELAY_T3_US);
+	gpio_direction_output(ts->pdata->reset_gpio, 1);
+	msleep(RESET_DELAY_T4);
 
-    gtp_int_sync(50);                  
-    
+	gpio_direction_input(ts->pdata->reset_gpio);
+
+	gtp_int_sync(ts, 50);
+
 #if GTP_ESD_PROTECT
-    gtp_init_ext_watchdog(client);
+	gtp_init_ext_watchdog(ts->client);
 #endif
 }
 
+#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_FB)
 #if GTP_SLIDE_WAKEUP
 /*******************************************************
 Function:
-    Enter doze mode for sliding wakeup.
+	Enter doze mode for sliding wakeup.
 Input:
-    ts: goodix tp private data
+	ts: goodix tp private data
 Output:
-    1: succeed, otherwise failed
+	1: succeed, otherwise failed
 *******************************************************/
 static s8 gtp_enter_doze(struct goodix_ts_data *ts)
 {
-    s8 ret = -1;
-    s8 retry = 0;
-    u8 i2c_control_buf[3] = {(u8)(GTP_REG_SLEEP >> 8), (u8)GTP_REG_SLEEP, 8};
+	int ret = -1;
+	s8 retry = 0;
+	u8 i2c_control_buf[3] = {
+		(u8)(GTP_REG_SLEEP >> 8),
+		(u8)GTP_REG_SLEEP, 8};
 
-    GTP_DEBUG_FUNC();
+	GTP_DEBUG_FUNC();
 
 #if GTP_DBL_CLK_WAKEUP
-    i2c_control_buf[2] = 0x09;
+	i2c_control_buf[2] = 0x09;
 #endif
+	gtp_irq_disable(ts);
 
-    gtp_irq_disable(ts);
-    
-    GTP_DEBUG("entering doze mode...");
-    while(retry++ < 5)
-    {
-        i2c_control_buf[0] = 0x80;
-        i2c_control_buf[1] = 0x46;
-        ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
-        if (ret < 0)
-        {
-            GTP_DEBUG("failed to set doze flag into 0x8046, %d", retry);
-            continue;
-        }
-        i2c_control_buf[0] = 0x80;
-        i2c_control_buf[1] = 0x40;
-        ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
-        if (ret > 0)
-        {
-            doze_status = DOZE_ENABLED;
-            GTP_INFO("GTP has been working in doze mode!");
-            gtp_irq_enable(ts);
-            return ret;
-        }
-        msleep(10);
-    }
-    GTP_ERROR("GTP send doze cmd failed.");
-    gtp_irq_enable(ts);
-    return ret;
+	GTP_DEBUG("entering doze mode...");
+	while (retry++ < 5) {
+		i2c_control_buf[0] = 0x80;
+		i2c_control_buf[1] = 0x46;
+		ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+		if (ret < 0) {
+			GTP_DEBUG(
+				"failed to set doze flag into 0x8046, %d",
+				retry);
+			continue;
+		}
+		i2c_control_buf[0] = 0x80;
+		i2c_control_buf[1] = 0x40;
+		ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+		if (ret > 0) {
+			doze_status = DOZE_ENABLED;
+			dev_dbg(&ts->client->dev,
+				"GTP has been working in doze mode!");
+			gtp_irq_enable(ts);
+			return ret;
+		}
+		msleep(20);
+	}
+	dev_err(&ts->client->dev, "GTP send doze cmd failed.\n");
+	gtp_irq_enable(ts);
+	return ret;
 }
-#else 
-/*******************************************************
-Function:
-    Enter sleep mode.
-Input:
-    ts: private data.
-Output:
-    Executive outcomes.
-       1: succeed, otherwise failed.
-*******************************************************/
-static s8 gtp_enter_sleep(struct goodix_ts_data * ts)
-{
-    s8 ret = -1;
-    s8 retry = 0;
-    u8 i2c_control_buf[3] = {(u8)(GTP_REG_SLEEP >> 8), (u8)GTP_REG_SLEEP, 5};
-
-    GTP_DEBUG_FUNC();
-    
-    GTP_GPIO_OUTPUT(GTP_INT_PORT, 0);
-    msleep(5);
-    
-    while(retry++ < 5)
-    {
-        ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
-        if (ret > 0)
-        {
-            GTP_INFO("GTP enter sleep!");
-            
-            return ret;
-        }
-        msleep(10);
-    }
-    GTP_ERROR("GTP send sleep cmd failed.");
-    return ret;
-}
-#endif 
-/*******************************************************
-Function:
-    Wakeup from sleep.
-Input:
-    ts: private data.
-Output:
-    Executive outcomes.
-        >0: succeed, otherwise: failed.
-*******************************************************/
-static s8 gtp_wakeup_sleep(struct goodix_ts_data * ts)
-{
-    u8 retry = 0;
-    s8 ret = -1;
-    
-    GTP_DEBUG_FUNC();
-    
-#if GTP_POWER_CTRL_SLEEP
-    while(retry++ < 5)
-    {
-        gtp_reset_guitar(ts->client, 20);
-        
-        ret = gtp_send_cfg(ts->client);
-        if (ret < 0)
-        {
-            GTP_INFO("Wakeup sleep send config failed!");
-            continue;
-        }
-        GTP_INFO("GTP wakeup sleep");
-        return 1;
-    }
 #else
-    while(retry++ < 10)
-    {
-    #if GTP_SLIDE_WAKEUP
-        if (DOZE_WAKEUP != doze_status)       // wakeup not by slide 
-        {
-            gtp_reset_guitar(ts->client, 10);
-        }
-        else              // wakeup by slide 
-        {
-            doze_status = DOZE_DISABLED;
-        }
-    #else
-        if (chip_gt9xxs == 1)
-        {
-           gtp_reset_guitar(ts->client, 10);
-        }
-        else
-        {
-            GTP_GPIO_OUTPUT(GTP_INT_PORT, 1);
-            msleep(5);
-        }
-    #endif
-        ret = gtp_i2c_test(ts->client);
-        if (ret > 0)
-        {
-            GTP_INFO("GTP wakeup sleep.");
-            
-        #if (!GTP_SLIDE_WAKEUP)
-            if (chip_gt9xxs == 0)
-            {
-                gtp_int_sync(25);
-                msleep(20);
-            #if GTP_ESD_PROTECT
-                gtp_init_ext_watchdog(ts->client);
-            #endif
-            }
-        #endif
-            return ret;
-        }
-        gtp_reset_guitar(ts->client, 20);
-    }
-#endif
+/*******************************************************
+Function:
+	Enter sleep mode.
+Input:
+	ts: private data.
+Output:
+	Executive outcomes.
+	1: succeed, otherwise failed.
+*******************************************************/
+static s8 gtp_enter_sleep(struct goodix_ts_data  *ts)
+{
+	int ret = -1;
+	s8 retry = 0;
+	u8 i2c_control_buf[3] = {
+		(u8)(GTP_REG_SLEEP >> 8),
+		(u8)GTP_REG_SLEEP, 5};
 
-    GTP_ERROR("GTP wakeup sleep failed.");
-    return ret;
+	GTP_DEBUG_FUNC();
+
+	ret = gpio_direction_output(ts->pdata->irq_gpio, 0);
+	usleep(5000);
+	while (retry++ < 5) {
+		ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+		if (ret > 0) {
+			dev_dbg(&ts->client->dev,
+				"GTP enter sleep!");
+			return ret;
+		}
+		msleep(20);
+	}
+	dev_err(&ts->client->dev, "GTP send sleep cmd failed.\n");
+	return ret;
 }
+#endif
 
 /*******************************************************
 Function:
-    Initialize gtp.
+	Wakeup from sleep.
 Input:
-    ts: goodix private data
+	ts: private data.
 Output:
-    Executive outcomes.
-        0: succeed, otherwise: failed
+	Executive outcomes.
+	>0: succeed, otherwise: failed.
 *******************************************************/
-static s32 gtp_init_panel(struct goodix_ts_data *ts)
+static s8 gtp_wakeup_sleep(struct goodix_ts_data *ts)
 {
-    s32 ret = -1;
+	u8 retry = 0;
+	s8 ret = -1;
+
+	GTP_DEBUG_FUNC();
+
+#if GTP_POWER_CTRL_SLEEP
+	gtp_reset_guitar(ts, 20);
+
+	ret = gtp_send_cfg(ts);
+	if (ret > 0) {
+		dev_dbg(&ts->client->dev,
+			"Wakeup sleep send config success.");
+		return 1;
+	}
+#else
+	while (retry++ < 10) {
+#if GTP_SLIDE_WAKEUP
+		/* wakeup not by slide */
+		if (DOZE_WAKEUP != doze_status)
+			gtp_reset_guitar(ts, 10);
+		else
+			/* wakeup by slide */
+			doze_status = DOZE_DISABLED;
+#else
+		if (chip_gt9xxs == 1) {
+			gtp_reset_guitar(ts, 10);
+		} else {
+			ret = gpio_direction_output(ts->pdata->irq_gpio, 1);
+			usleep(5000);
+		}
+#endif
+		ret = gtp_i2c_test(ts->client);
+		if (ret > 0) {
+			dev_dbg(&ts->client->dev, "GTP wakeup sleep.");
+#if (!GTP_SLIDE_WAKEUP)
+			if (chip_gt9xxs == 0) {
+				gtp_int_sync(ts, 25);
+				msleep(20);
+#if GTP_ESD_PROTECT
+				gtp_init_ext_watchdog(ts->client);
+#endif
+			}
+#endif
+			return ret;
+		}
+		gtp_reset_guitar(ts, 20);
+	}
+#endif
+
+	dev_err(&ts->client->dev, "GTP wakeup sleep failed.\n");
+	return ret;
+}
+#endif /* !CONFIG_HAS_EARLYSUSPEND && !CONFIG_FB*/
+
+/*******************************************************
+Function:
+	Initialize gtp.
+Input:
+	ts: goodix private data
+Output:
+	Executive outcomes.
+	> =0: succeed, otherwise: failed
+*******************************************************/
+static int gtp_init_panel(struct goodix_ts_data *ts)
+{
+	struct i2c_client *client = ts->client;
+	unsigned char *config_data;
+	int ret = -EIO;
 
 #if GTP_DRIVER_SEND_CFG
-    s32 i;
-    u8 check_sum = 0;
-    u8 opr_buf[16];
-    u8 sensor_id = 0;
+	int i;
+	u8 check_sum = 0;
+	u8 opr_buf[16];
+	u8 sensor_id = 0;
 
-    u8 cfg_info_group1[] = CTP_CFG_GROUP1;
-    u8 cfg_info_group2[] = CTP_CFG_GROUP2;
-    u8 cfg_info_group3[] = CTP_CFG_GROUP3;
-    u8 cfg_info_group4[] = CTP_CFG_GROUP4;
-    u8 cfg_info_group5[] = CTP_CFG_GROUP5;
-    u8 cfg_info_group6[] = CTP_CFG_GROUP6;
-    u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2, cfg_info_group3,
-                        cfg_info_group4, cfg_info_group5, cfg_info_group6};
-    u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group1),
-                          CFG_GROUP_LEN(cfg_info_group2),
-                          CFG_GROUP_LEN(cfg_info_group3),
-                          CFG_GROUP_LEN(cfg_info_group4),
-                          CFG_GROUP_LEN(cfg_info_group5),
-                          CFG_GROUP_LEN(cfg_info_group6)};
+	u8 cfg_info_group1[] = CTP_CFG_GROUP1;
+	u8 cfg_info_group2[] = CTP_CFG_GROUP2;
+	u8 cfg_info_group3[] = CTP_CFG_GROUP3;
+	u8 cfg_info_group4[] = CTP_CFG_GROUP4;
+	u8 cfg_info_group5[] = CTP_CFG_GROUP5;
+	u8 cfg_info_group6[] = CTP_CFG_GROUP6;
+	u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2,
+		cfg_info_group3, cfg_info_group4,
+		cfg_info_group5, cfg_info_group6};
 
-    GTP_DEBUG("Config Groups\' Lengths: %d, %d, %d, %d, %d, %d", 
-        cfg_info_len[0], cfg_info_len[1], cfg_info_len[2], cfg_info_len[3],
-        cfg_info_len[4], cfg_info_len[5]);
+	u8 cfg_info_len[] = {CFG_GROUP_LEN(cfg_info_group1),
+		CFG_GROUP_LEN(cfg_info_group2),
+		CFG_GROUP_LEN(cfg_info_group3),
+		CFG_GROUP_LEN(cfg_info_group4),
+		CFG_GROUP_LEN(cfg_info_group5),
+		CFG_GROUP_LEN(cfg_info_group6)};
 
-    ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1);
-    if (SUCCESS == ret) 
-    {
-        if (opr_buf[0] != 0xBE)
-        {
-            ts->fw_error = 1;
-            GTP_ERROR("Firmware error, no config sent!");
-            return -1;
-        }
-    }
+	GTP_DEBUG("Config Groups\' Lengths: %d, %d, %d, %d, %d, %d",
+			cfg_info_len[0], cfg_info_len[1], cfg_info_len[2],
+			cfg_info_len[3], cfg_info_len[4], cfg_info_len[5]);
 
-    if ((!cfg_info_len[1]) && (!cfg_info_len[2]) && 
-        (!cfg_info_len[3]) && (!cfg_info_len[4]) && 
-        (!cfg_info_len[5]))
-    {
-        sensor_id = 0; 
-    }
-    else
-    {
-        ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID, &sensor_id, 1);
-        if (SUCCESS == ret)
-        {
-            if (sensor_id >= 0x06)
-            {
-                GTP_ERROR("Invalid sensor_id(0x%02X), No Config Sent!", sensor_id);
-                return -1;
-            }
-        }
-        else
-        {
-            GTP_ERROR("Failed to get sensor_id, No config sent!");
-            return -1;
-        }
-    }
-    GTP_DEBUG("Sensor_ID: %d", sensor_id);
-    
-    ts->gtp_cfg_len = cfg_info_len[sensor_id];
-    
-    if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH)
-    {
-        GTP_ERROR("Sensor_ID(%d) matches with NULL or INVALID CONFIG GROUP! NO Config Sent! You need to check you header file CFG_GROUP section!", sensor_id);
-        return -1;
-    }
-    
-    ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, &opr_buf[0], 1);
-    
-    if (ret == SUCCESS)
-    {
-        GTP_DEBUG("CFG_GROUP%d Config Version: %d, 0x%02X; IC Config Version: %d, 0x%02X", sensor_id+1, 
-                    send_cfg_buf[sensor_id][0], send_cfg_buf[sensor_id][0], opr_buf[0], opr_buf[0]);
-        
-        if (opr_buf[0] < 90)    
-        {
-            grp_cfg_version = send_cfg_buf[sensor_id][0];       // backup group config version
-            send_cfg_buf[sensor_id][0] = 0x00;
-            ts->fixed_cfg = 0;
-        }
-        else        // treated as fixed config, not send config
-        {
-            GTP_INFO("Ic fixed config with config version(%d, 0x%02X)", opr_buf[0], opr_buf[0]);
-            ts->fixed_cfg = 1;
-        }
-    }
-    else
-    {
-        GTP_ERROR("Failed to get ic config version!No config sent!");
-        return -1;
-    }
-    
-    memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
-    memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id], ts->gtp_cfg_len);
+	ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1);
+	if (SUCCESS == ret) {
+		if (opr_buf[0] != 0xBE) {
+			ts->fw_error = 1;
+			dev_err(&client->dev,
+				"Firmware error, no config sent!");
+			return -EINVAL;
+		}
+	}
+	if ((!cfg_info_len[1]) && (!cfg_info_len[2]) && (!cfg_info_len[3])
+		&& (!cfg_info_len[4]) && (!cfg_info_len[5])) {
+		sensor_id = 0;
+	} else {
+		ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID,
+			&sensor_id, 1);
+		if (SUCCESS == ret) {
+			if (sensor_id >= 0x06) {
+				dev_err(&client->dev,
+					"Invalid sensor_id(0x%02X), No Config Sent!",
+					sensor_id);
+				return -EINVAL;
+			}
+		} else {
+			dev_err(&client->dev,
+				"Failed to get sensor_id, No config sent!");
+			return -EINVAL;
+		}
+	}
+	GTP_DEBUG("Sensor_ID: %d", sensor_id);
+
+	ts->gtp_cfg_len = cfg_info_len[sensor_id];
+
+	if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH) {
+		dev_err(&client->dev,
+				"Sensor_ID(%d) matches with NULL or INVALID CONFIG GROUP! NO Config Sent! You need to check you header file CFG_GROUP section!\n",
+				sensor_id);
+		return -EINVAL;
+	}
+	ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
+		&opr_buf[0], 1);
+
+	if (ret == SUCCESS) {
+		if (opr_buf[0] < 90) {
+			/* backup group config version */
+			grp_cfg_version = send_cfg_buf[sensor_id][0];
+			send_cfg_buf[sensor_id][0] = 0x00;
+			ts->fixed_cfg = 0;
+		} else {
+			/* treated as fixed config, not send config */
+			dev_warn(&client->dev,
+				"Ic fixed config with config version(%d, 0x%02X)",
+				opr_buf[0], opr_buf[0]);
+			ts->fixed_cfg = 1;
+		}
+	} else {
+		dev_err(&client->dev,
+			"Failed to get ic config version!No config sent!");
+		return -EINVAL;
+	}
+
+	if (ts->pdata->gtp_cfg_len) {
+		config_data = ts->pdata->config_data;
+		ts->config_data = ts->pdata->config_data;
+		ts->gtp_cfg_len = ts->pdata->gtp_cfg_len;
+	} else {
+		config_data = devm_kzalloc(&client->dev,
+			GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH,
+				GFP_KERNEL);
+		if (!config_data) {
+			dev_err(&client->dev,
+					"Not enough memory for panel config data\n");
+			return -ENOMEM;
+		}
+
+		ts->config_data = config_data;
+		config_data[0] = GTP_REG_CONFIG_DATA >> 8;
+		config_data[1] = GTP_REG_CONFIG_DATA & 0xff;
+		memset(&config_data[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
+		memcpy(&config_data[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id],
+				ts->gtp_cfg_len);
+	}
 
 #if GTP_CUSTOM_CFG
-    config[RESOLUTION_LOC]     = (u8)GTP_MAX_WIDTH;
-    config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8);
-    config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT;
-    config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8);
-    
-    if (GTP_INT_TRIGGER == 0)  //RISING
-    {
-        config[TRIGGER_LOC] &= 0xfe; 
-    }
-    else if (GTP_INT_TRIGGER == 1)  //FALLING
-    {
-        config[TRIGGER_LOC] |= 0x01;
-    }
-#endif  // GTP_CUSTOM_CFG
-    
-    check_sum = 0;
-    for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
-    {
-        check_sum += config[i];
-    }
-    config[ts->gtp_cfg_len] = (~check_sum) + 1;
-    
-#else // DRIVER NOT SEND CONFIG
-    ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH;
-    ret = gtp_i2c_read(ts->client, config, ts->gtp_cfg_len + GTP_ADDR_LENGTH);
-    if (ret < 0)
-    {
-        GTP_ERROR("Read Config Failed, Using Default Resolution & INT Trigger!");
-        ts->abs_x_max = GTP_MAX_WIDTH;
-        ts->abs_y_max = GTP_MAX_HEIGHT;
-        ts->int_trigger_type = GTP_INT_TRIGGER;
-    }
-#endif // GTP_DRIVER_SEND_CFG
+	config_data[RESOLUTION_LOC] =
+	(unsigned char)(GTP_MAX_WIDTH && 0xFF);
+	config_data[RESOLUTION_LOC + 1] =
+	(unsigned char)(GTP_MAX_WIDTH >> 8);
+	config_data[RESOLUTION_LOC + 2] =
+	(unsigned char)(GTP_MAX_HEIGHT && 0xFF);
+	config_data[RESOLUTION_LOC + 3] =
+	(unsigned char)(GTP_MAX_HEIGHT >> 8);
 
-    GTP_DEBUG_FUNC();
-    if ((ts->abs_x_max == 0) && (ts->abs_y_max == 0))
-    {
-        ts->abs_x_max = (config[RESOLUTION_LOC + 1] << 8) + config[RESOLUTION_LOC];
-        ts->abs_y_max = (config[RESOLUTION_LOC + 3] << 8) + config[RESOLUTION_LOC + 2];
-        ts->int_trigger_type = (config[TRIGGER_LOC]) & 0x03; 
-    }
-    ret = gtp_send_cfg(ts->client);
-    if (ret < 0)
-    {
-        GTP_ERROR("Send config error.");
-    }
-    GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
-        ts->abs_x_max,ts->abs_y_max,ts->int_trigger_type);
+	if (GTP_INT_TRIGGER == 0)
+		config_data[TRIGGER_LOC] &= 0xfe;
+	else if (GTP_INT_TRIGGER == 1)
+		config_data[TRIGGER_LOC] |= 0x01;
+#endif  /* !GTP_CUSTOM_CFG */
 
-    msleep(10);
-    return 0;
+	check_sum = 0;
+	for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
+		check_sum += config_data[i];
+
+	config_data[ts->gtp_cfg_len] = (~check_sum) + 1;
+
+#else /* DRIVER NOT SEND CONFIG */
+	ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH;
+	ret = gtp_i2c_read(ts->client, config_data,
+			ts->gtp_cfg_len + GTP_ADDR_LENGTH);
+	if (ret < 0) {
+		dev_err(&client->dev,
+				"Read Config Failed, Using DEFAULT Resolution & INT Trigger!\n");
+		ts->abs_x_max = GTP_MAX_WIDTH;
+		ts->abs_y_max = GTP_MAX_HEIGHT;
+		ts->int_trigger_type = GTP_INT_TRIGGER;
+	}
+#endif /* !DRIVER NOT SEND CONFIG */
+
+	GTP_DEBUG_FUNC();
+	if ((ts->abs_x_max == 0) && (ts->abs_y_max == 0)) {
+		ts->abs_x_max = (config_data[RESOLUTION_LOC + 1] << 8)
+				+ config_data[RESOLUTION_LOC];
+		ts->abs_y_max = (config_data[RESOLUTION_LOC + 3] << 8)
+				+ config_data[RESOLUTION_LOC + 2];
+		ts->int_trigger_type = (config_data[TRIGGER_LOC]) & 0x03;
+	}
+	ret = gtp_send_cfg(ts);
+	if (ret < 0)
+		dev_err(&client->dev, "%s: Send config error.\n", __func__);
+
+	GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
+			ts->abs_x_max, ts->abs_y_max,
+			ts->int_trigger_type);
+
+	msleep(20);
+	return ret;
 }
 
 /*******************************************************
 Function:
-    Read chip version.
+	Read chip version.
 Input:
-    client:  i2c device
-    version: buffer to keep ic firmware version
+	client:  i2c device
+	version: buffer to keep ic firmware version
 Output:
-    read operation return.
-        2: succeed, otherwise: failed
+	read operation return.
+	2: succeed, otherwise: failed
 *******************************************************/
-s32 gtp_read_version(struct i2c_client *client, u16* version)
+int gtp_read_version(struct i2c_client *client, u16 *version)
 {
-    s32 ret = -1;
-    u8 buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff};
+	int ret = -EIO;
+	u8 buf[8] = { GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff };
 
-    GTP_DEBUG_FUNC();
+	GTP_DEBUG_FUNC();
 
-    ret = gtp_i2c_read(client, buf, sizeof(buf));
-    if (ret < 0)
-    {
-        GTP_ERROR("GTP read version failed");
-        return ret;
-    }
+	ret = gtp_i2c_read(client, buf, sizeof(buf));
+	if (ret < 0) {
+		dev_err(&client->dev, "GTP read version failed.\n");
+		return ret;
+	}
 
-    if (version)
-    {
-        *version = (buf[7] << 8) | buf[6];
-    }
-    
-    if (buf[5] == 0x00)
-    {
-        GTP_INFO("IC Version: %c%c%c_%02x%02x", buf[2], buf[3], buf[4], buf[7], buf[6]);
-    }
-    else
-    {
-        if (buf[5] == 'S' || buf[5] == 's')
-        {
-            chip_gt9xxs = 1;
-        }
-        GTP_INFO("IC Version: %c%c%c%c_%02x%02x", buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]);
-    }
-    return ret;
+	if (version)
+		*version = (buf[7] << 8) | buf[6];
+
+	if (buf[5] == 0x00) {
+		dev_dbg(&client->dev, "IC Version: %c%c%c_%02x%02x\n", buf[2],
+				buf[3], buf[4], buf[7], buf[6]);
+	} else {
+		if (buf[5] == 'S' || buf[5] == 's')
+			chip_gt9xxs = 1;
+		dev_dbg(&client->dev, "IC Version: %c%c%c%c_%02x%02x\n", buf[2],
+				buf[3], buf[4], buf[5], buf[7], buf[6]);
+	}
+	return ret;
 }
 
 /*******************************************************
 Function:
-    I2c test Function.
+	I2c test Function.
 Input:
-    client:i2c client.
+	client:i2c client.
 Output:
-    Executive outcomes.
-        2: succeed, otherwise failed.
+	Executive outcomes.
+	2: succeed, otherwise failed.
 *******************************************************/
-static s8 gtp_i2c_test(struct i2c_client *client)
+static int gtp_i2c_test(struct i2c_client *client)
 {
-    u8 test[3] = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff};
-    u8 retry = 0;
-    s8 ret = -1;
-  
-    GTP_DEBUG_FUNC();
-  
-    while(retry++ < 5)
-    {
-        ret = gtp_i2c_read(client, test, 3);
-        if (ret > 0)
-        {
-            return ret;
-        }
-        GTP_ERROR("GTP i2c test failed time %d.",retry);
-        msleep(10);
-    }
-    return ret;
+	u8 buf[3] = { GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff };
+	int retry = 5;
+	int ret = -EIO;
+
+	GTP_DEBUG_FUNC();
+
+	while (retry--) {
+		ret = gtp_i2c_read(client, buf, 3);
+		if (ret > 0)
+			return ret;
+		dev_err(&client->dev, "GTP i2c test failed time %d.\n", retry);
+		msleep(20);
+	}
+	return ret;
 }
 
 /*******************************************************
 Function:
-    Request gpio(INT & RST) ports.
+	Request gpio(INT & RST) ports.
 Input:
-    ts: private data.
+	ts: private data.
 Output:
-    Executive outcomes.
-        >= 0: succeed, < 0: failed
+	Executive outcomes.
+	= 0: succeed, != 0: failed
 *******************************************************/
-static s8 gtp_request_io_port(struct goodix_ts_data *ts)
+static int gtp_request_io_port(struct goodix_ts_data *ts)
 {
-    s32 ret = 0;
+	struct i2c_client *client = ts->client;
+	struct goodix_ts_platform_data *pdata = ts->pdata;
+	int ret;
+	if (gpio_is_valid(pdata->irq_gpio)) {
+		ret = gpio_request(pdata->irq_gpio, "goodix_ts_irq_gpio");
+		if (ret) {
+			dev_err(&client->dev, "irq gpio request failed\n");
+			goto pwr_off;
+		}
+		ret = gpio_direction_input(pdata->irq_gpio);
+		if (ret) {
+			dev_err(&client->dev,
+					"set_direction for irq gpio failed\n");
+			goto free_irq_gpio;
+		}
+	} else {
+		dev_err(&client->dev, "irq gpio is invalid!\n");
+		ret = -EINVAL;
+		goto free_irq_gpio;
+	}
 
-    ret = GTP_GPIO_REQUEST(GTP_INT_PORT, "GTP_INT_IRQ");
-    if (ret < 0) 
-    {
-        GTP_ERROR("Failed to request GPIO:%d, ERRNO:%d", (s32)GTP_INT_PORT, ret);
-        ret = -ENODEV;
-    }
-    else
-    {
-        GTP_GPIO_AS_INT(GTP_INT_PORT);  
-        ts->client->irq = GTP_INT_IRQ;
-    }
+	if (gpio_is_valid(pdata->reset_gpio)) {
+		ret = gpio_request(pdata->reset_gpio, "goodix_ts__reset_gpio");
+		if (ret) {
+			dev_err(&client->dev, "reset gpio request failed\n");
+			goto free_irq_gpio;
+		}
 
-    ret = GTP_GPIO_REQUEST(GTP_RST_PORT, "GTP_RST_PORT");
-    if (ret < 0) 
-    {
-        GTP_ERROR("Failed to request GPIO:%d, ERRNO:%d",(s32)GTP_RST_PORT,ret);
-        ret = -ENODEV;
-    }
+		ret = gpio_direction_output(pdata->reset_gpio, 0);
+		if (ret) {
+			dev_err(&client->dev,
+					"set_direction for reset gpio failed\n");
+			goto free_reset_gpio;
+		}
+	} else {
+		dev_err(&client->dev, "reset gpio is invalid!\n");
+		ret = -EINVAL;
+		goto free_reset_gpio;
+	}
+	gpio_direction_input(pdata->reset_gpio);
 
-    GTP_GPIO_AS_INPUT(GTP_RST_PORT);
-    gtp_reset_guitar(ts->client, 20);
+	return ret;
 
-    
-    if(ret < 0)
-    {
-        GTP_GPIO_FREE(GTP_RST_PORT);
-        GTP_GPIO_FREE(GTP_INT_PORT);
-    }
-
-    return ret;
+free_reset_gpio:
+	if (gpio_is_valid(pdata->reset_gpio))
+		gpio_free(pdata->reset_gpio);
+free_irq_gpio:
+	if (gpio_is_valid(pdata->irq_gpio))
+		gpio_free(pdata->irq_gpio);
+pwr_off:
+	return ret;
 }
 
 /*******************************************************
 Function:
-    Request interrupt.
+	Request interrupt.
 Input:
-    ts: private data.
+	ts: private data.
 Output:
-    Executive outcomes.
-        0: succeed, -1: failed.
+	Executive outcomes.
+	0: succeed, -1: failed.
 *******************************************************/
-static s8 gtp_request_irq(struct goodix_ts_data *ts)
+static int gtp_request_irq(struct goodix_ts_data *ts)
 {
-    s32 ret = -1;
-    const u8 irq_table[] = GTP_IRQ_TAB;
+	int ret;
+	const u8 irq_table[] = GTP_IRQ_TAB;
 
-    GTP_DEBUG("INT trigger type:%x", ts->int_trigger_type);
+	GTP_DEBUG("INT trigger type:%x, irq=%d", ts->int_trigger_type,
+			ts->client->irq);
 
-    ret  = request_irq(ts->client->irq, 
-                       goodix_ts_irq_handler,
-                       irq_table[ts->int_trigger_type],
-                       ts->client->name,
-                       ts);
-    if (ret)
-    {
-        GTP_ERROR("Request IRQ failed!ERRNO:%d.", ret);
-        GTP_GPIO_AS_INPUT(GTP_INT_PORT);
-        GTP_GPIO_FREE(GTP_INT_PORT);
+	ret = request_irq(ts->client->irq, goodix_ts_irq_handler,
+			irq_table[ts->int_trigger_type],
+			ts->client->name, ts);
+	if (ret) {
+		dev_err(&ts->client->dev, "Request IRQ failed!ERRNO:%d.\n",
+				ret);
+		gpio_direction_input(ts->pdata->irq_gpio);
 
-        hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-        ts->timer.function = goodix_ts_timer_handler;
-        hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
-        return -1;
-    }
-    else 
-    {
-        gtp_irq_disable(ts);
-        ts->use_irq = 1;
-        return 0;
-    }
+		hrtimer_init(&ts->timer, CLOCK_MONOTONIC,
+				HRTIMER_MODE_REL);
+		ts->timer.function = goodix_ts_timer_handler;
+		hrtimer_start(&ts->timer, ktime_set(1, 0),
+				HRTIMER_MODE_REL);
+		ts->use_irq = false;
+		return ret;
+	} else {
+		gtp_irq_disable(ts);
+		ts->use_irq = true;
+		return 0;
+	}
 }
 
 /*******************************************************
 Function:
-    Request input device Function.
+	Request input device Function.
 Input:
-    ts:private data.
+	ts:private data.
 Output:
-    Executive outcomes.
-        0: succeed, otherwise: failed.
+	Executive outcomes.
+	0: succeed, otherwise: failed.
 *******************************************************/
-static s8 gtp_request_input_dev(struct goodix_ts_data *ts)
+static int gtp_request_input_dev(struct goodix_ts_data *ts)
 {
-    s8 ret = -1;
-    s8 phys[32];
+	int ret;
+	char phys[PHY_BUF_SIZE];
 #if GTP_HAVE_TOUCH_KEY
-    u8 index = 0;
-#endif
-  
-    GTP_DEBUG_FUNC();
-  
-    ts->input_dev = input_allocate_device();
-    if (ts->input_dev == NULL)
-    {
-        GTP_ERROR("Failed to allocate input device.");
-        return -ENOMEM;
-    }
-
-    ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
-#if GTP_ICS_SLOT_REPORT
-    __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
-    input_mt_init_slots(ts->input_dev, 10);     // in case of "out of memory"
-#else
-    ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	int index = 0;
 #endif
 
+	GTP_DEBUG_FUNC();
+
+	ts->input_dev = input_allocate_device();
+	if (ts->input_dev == NULL) {
+		dev_err(&ts->client->dev,
+				"Failed to allocate input device.\n");
+		return -ENOMEM;
+	}
+
+	ts->input_dev->evbit[0] =
+		BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
+	set_bit(BTN_TOOL_FINGER, ts->input_dev->keybit);
+	__set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+	input_mt_init_slots(ts->input_dev, 10);/* in case of "out of memory" */
+
 #if GTP_HAVE_TOUCH_KEY
-    for (index = 0; index < GTP_MAX_KEY_NUM; index++)
-    {
-        input_set_capability(ts->input_dev, EV_KEY, touch_key_array[index]);  
-    }
+	for (index = 0; index < GTP_MAX_KEY_NUM; index++) {
+		input_set_capability(ts->input_dev,
+				EV_KEY, touch_key_array[index]);
+	}
 #endif
 
 #if GTP_SLIDE_WAKEUP
-    input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
-#endif 
+	input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
+#endif
 
 #if GTP_WITH_PEN
-    // pen support
-    __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit);
-    __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
-    __set_bit(INPUT_PROP_POINTER, ts->input_dev->propbit);
+	/* pen support */
+	__set_bit(BTN_TOOL_PEN, ts->input_dev->keybit);
+	__set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+	__set_bit(INPUT_PROP_POINTER, ts->input_dev->propbit);
 #endif
 
 #if GTP_CHANGE_X2Y
-    GTP_SWAP(ts->abs_x_max, ts->abs_y_max);
+	GTP_SWAP(ts->abs_x_max, ts->abs_y_max);
 #endif
 
-    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, ts->abs_x_max, 0, 0);
-    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, ts->abs_y_max, 0, 0);
-    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
-    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
-    input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 255, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
+				0, ts->abs_x_max, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,
+				0, ts->abs_y_max, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR,
+				0, 255, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+				0, 255, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID,
+				0, 255, 0, 0);
 
-    sprintf(phys, "input/ts");
-    ts->input_dev->name = goodix_ts_name;
-    ts->input_dev->phys = phys;
-    ts->input_dev->id.bustype = BUS_I2C;
-    ts->input_dev->id.vendor = 0xDEAD;
-    ts->input_dev->id.product = 0xBEEF;
-    ts->input_dev->id.version = 10427;
-    
-    ret = input_register_device(ts->input_dev);
-    if (ret)
-    {
-        GTP_ERROR("Register %s input device failed", ts->input_dev->name);
-        return -ENODEV;
-    }
-    
-#ifdef CONFIG_HAS_EARLYSUSPEND
-    ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
-    ts->early_suspend.suspend = goodix_ts_early_suspend;
-    ts->early_suspend.resume = goodix_ts_late_resume;
-    register_early_suspend(&ts->early_suspend);
-#endif
+	snprintf(phys, PHY_BUF_SIZE, "input/ts");
+	ts->input_dev->name = GOODIX_DEV_NAME;
+	ts->input_dev->phys = phys;
+	ts->input_dev->id.bustype = BUS_I2C;
+	ts->input_dev->id.vendor = 0xDEAD;
+	ts->input_dev->id.product = 0xBEEF;
+	ts->input_dev->id.version = 10427;
 
-    return 0;
+	ret = input_register_device(ts->input_dev);
+	if (ret) {
+		dev_err(&ts->client->dev,
+				"Register %s input device failed.\n",
+				ts->input_dev->name);
+		goto exit_free_inputdev;
+	}
+
+	return 0;
+
+exit_free_inputdev:
+	input_free_device(ts->input_dev);
+	ts->input_dev = NULL;
+	return ret;
+}
+
+static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA)
+{
+	return (regulator_count_voltages(reg) > 0) ?
+		regulator_set_optimum_mode(reg, load_uA) : 0;
+}
+
+/**
+ * goodix_power_on - Turn device power ON
+ * @ts: driver private data
+ *
+ * Returns zero on success, else an error.
+ */
+static int goodix_power_on(struct goodix_ts_data *ts)
+{
+	int ret;
+
+	if (!IS_ERR(ts->avdd)) {
+		ret = reg_set_optimum_mode_check(ts->avdd,
+			GOODIX_VDD_LOAD_MAX_UA);
+		if (ret < 0) {
+			dev_err(&ts->client->dev,
+				"Regulator avdd set_opt failed rc=%d\n", ret);
+			goto err_set_opt_avdd;
+		}
+		ret = regulator_enable(ts->avdd);
+		if (ret) {
+			dev_err(&ts->client->dev,
+				"Regulator avdd enable failed ret=%d\n", ret);
+			goto err_enable_avdd;
+		}
+	}
+
+	if (!IS_ERR(ts->vdd)) {
+		ret = regulator_set_voltage(ts->vdd, GOODIX_VTG_MIN_UV,
+					   GOODIX_VTG_MAX_UV);
+		if (ret) {
+			dev_err(&ts->client->dev,
+				"Regulator set_vtg failed vdd ret=%d\n", ret);
+			goto err_set_vtg_vdd;
+		}
+		ret = reg_set_optimum_mode_check(ts->vdd,
+			GOODIX_VDD_LOAD_MAX_UA);
+		if (ret < 0) {
+			dev_err(&ts->client->dev,
+				"Regulator vdd set_opt failed rc=%d\n", ret);
+			goto err_set_opt_vdd;
+		}
+		ret = regulator_enable(ts->vdd);
+		if (ret) {
+			dev_err(&ts->client->dev,
+				"Regulator vdd enable failed ret=%d\n", ret);
+			goto err_enable_vdd;
+		}
+	}
+
+	if (!IS_ERR(ts->vcc_i2c)) {
+		ret = regulator_set_voltage(ts->vcc_i2c, GOODIX_I2C_VTG_MIN_UV,
+					   GOODIX_I2C_VTG_MAX_UV);
+		if (ret) {
+			dev_err(&ts->client->dev,
+				"Regulator set_vtg failed vcc_i2c ret=%d\n",
+				ret);
+			goto err_set_vtg_vcc_i2c;
+		}
+		ret = reg_set_optimum_mode_check(ts->vcc_i2c,
+			GOODIX_VIO_LOAD_MAX_UA);
+		if (ret < 0) {
+			dev_err(&ts->client->dev,
+				"Regulator vcc_i2c set_opt failed rc=%d\n",
+				ret);
+			goto err_set_opt_vcc_i2c;
+		}
+		ret = regulator_enable(ts->vcc_i2c);
+		if (ret) {
+			dev_err(&ts->client->dev,
+				"Regulator vcc_i2c enable failed ret=%d\n",
+				ret);
+			regulator_disable(ts->vdd);
+			goto err_enable_vcc_i2c;
+			}
+	}
+
+	return 0;
+
+err_enable_vcc_i2c:
+err_set_opt_vcc_i2c:
+	if (!IS_ERR(ts->vcc_i2c))
+		regulator_set_voltage(ts->vcc_i2c, 0, GOODIX_I2C_VTG_MAX_UV);
+err_set_vtg_vcc_i2c:
+	if (!IS_ERR(ts->vdd))
+		regulator_disable(ts->vdd);
+err_enable_vdd:
+err_set_opt_vdd:
+	if (!IS_ERR(ts->vdd))
+		regulator_set_voltage(ts->vdd, 0, GOODIX_VTG_MAX_UV);
+err_set_vtg_vdd:
+	if (!IS_ERR(ts->avdd))
+		regulator_disable(ts->avdd);
+err_enable_avdd:
+err_set_opt_avdd:
+	return ret;
+}
+
+/**
+ * goodix_power_off - Turn device power OFF
+ * @ts: driver private data
+ *
+ * Returns zero on success, else an error.
+ */
+static int goodix_power_off(struct goodix_ts_data *ts)
+{
+	int ret;
+
+	if (!IS_ERR(ts->vcc_i2c)) {
+		ret = regulator_set_voltage(ts->vcc_i2c, 0,
+			GOODIX_I2C_VTG_MAX_UV);
+		if (ret < 0)
+			dev_err(&ts->client->dev,
+				"Regulator vcc_i2c set_vtg failed ret=%d\n",
+				ret);
+		ret = regulator_disable(ts->vcc_i2c);
+		if (ret)
+			dev_err(&ts->client->dev,
+				"Regulator vcc_i2c disable failed ret=%d\n",
+				ret);
+	}
+
+	if (!IS_ERR(ts->vdd)) {
+		ret = regulator_set_voltage(ts->vdd, 0, GOODIX_VTG_MAX_UV);
+		if (ret < 0)
+			dev_err(&ts->client->dev,
+				"Regulator vdd set_vtg failed ret=%d\n", ret);
+		ret = regulator_disable(ts->vdd);
+		if (ret)
+			dev_err(&ts->client->dev,
+				"Regulator vdd disable failed ret=%d\n", ret);
+	}
+
+	if (!IS_ERR(ts->avdd)) {
+		ret = regulator_disable(ts->avdd);
+		if (ret)
+			dev_err(&ts->client->dev,
+				"Regulator avdd disable failed ret=%d\n", ret);
+	}
+
+	return 0;
+}
+
+/**
+ * goodix_power_init - Initialize device power
+ * @ts: driver private data
+ *
+ * Returns zero on success, else an error.
+ */
+static int goodix_power_init(struct goodix_ts_data *ts)
+{
+	int ret;
+
+	ts->avdd = regulator_get(&ts->client->dev, "avdd");
+	if (IS_ERR(ts->avdd)) {
+		ret = PTR_ERR(ts->avdd);
+		dev_info(&ts->client->dev,
+			"Regulator get failed avdd ret=%d\n", ret);
+	}
+
+	ts->vdd = regulator_get(&ts->client->dev, "vdd");
+	if (IS_ERR(ts->vdd)) {
+		ret = PTR_ERR(ts->vdd);
+		dev_info(&ts->client->dev,
+			"Regulator get failed vdd ret=%d\n", ret);
+	}
+
+	ts->vcc_i2c = regulator_get(&ts->client->dev, "vcc-i2c");
+	if (IS_ERR(ts->vcc_i2c)) {
+		ret = PTR_ERR(ts->vcc_i2c);
+		dev_info(&ts->client->dev,
+			"Regulator get failed vcc_i2c ret=%d\n", ret);
+	}
+
+	return 0;
+}
+
+/**
+ * goodix_power_deinit - Deinitialize device power
+ * @ts: driver private data
+ *
+ * Returns zero on success, else an error.
+ */
+static int goodix_power_deinit(struct goodix_ts_data *ts)
+{
+	regulator_put(ts->vdd);
+	regulator_put(ts->vcc_i2c);
+	regulator_put(ts->avdd);
+
+	return 0;
+}
+
+static int goodix_ts_get_dt_coords(struct device *dev, char *name,
+				struct goodix_ts_platform_data *pdata)
+{
+	struct property *prop;
+	struct device_node *np = dev->of_node;
+	int rc;
+	u32 coords[GOODIX_COORDS_ARR_SIZE];
+
+	prop = of_find_property(np, name, NULL);
+	if (!prop)
+		return -EINVAL;
+	if (!prop->value)
+		return -ENODATA;
+
+	rc = of_property_read_u32_array(np, name, coords,
+		GOODIX_COORDS_ARR_SIZE);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read %s\n", name);
+		return rc;
+	}
+
+	if (!strcmp(name, "goodix,panel-coords")) {
+		pdata->panel_minx = coords[0];
+		pdata->panel_miny = coords[1];
+		pdata->panel_maxx = coords[2];
+		pdata->panel_maxy = coords[3];
+	} else if (!strcmp(name, "goodix,display-coords")) {
+		pdata->x_min = coords[0];
+		pdata->y_min = coords[1];
+		pdata->x_max = coords[2];
+		pdata->y_max = coords[3];
+	} else {
+		dev_err(dev, "unsupported property %s\n", name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int goodix_parse_dt(struct device *dev,
+			struct goodix_ts_platform_data *pdata)
+{
+	int rc;
+	struct device_node *np = dev->of_node;
+	struct property *prop;
+	u32 temp_val, num_buttons;
+	u32 button_map[MAX_BUTTONS];
+
+	rc = goodix_ts_get_dt_coords(dev, "goodix,panel-coords", pdata);
+	if (rc && (rc != -EINVAL))
+		return rc;
+
+	rc = goodix_ts_get_dt_coords(dev, "goodix,display-coords", pdata);
+	if (rc)
+		return rc;
+
+	pdata->i2c_pull_up = of_property_read_bool(np,
+						"goodix,i2c-pull-up");
+
+	pdata->no_force_update = of_property_read_bool(np,
+						"goodix,no-force-update");
+	/* reset, irq gpio info */
+	pdata->reset_gpio = of_get_named_gpio_flags(np, "reset-gpios",
+				0, &pdata->reset_gpio_flags);
+	if (pdata->reset_gpio < 0)
+		return pdata->reset_gpio;
+
+	pdata->irq_gpio = of_get_named_gpio_flags(np, "interrupt-gpios",
+				0, &pdata->irq_gpio_flags);
+	if (pdata->irq_gpio < 0)
+		return pdata->irq_gpio;
+
+	rc = of_property_read_u32(np, "goodix,family-id", &temp_val);
+	if (!rc)
+		pdata->family_id = temp_val;
+	else
+		return rc;
+
+	prop = of_find_property(np, "goodix,button-map", NULL);
+	if (prop) {
+		num_buttons = prop->length / sizeof(temp_val);
+		if (num_buttons > MAX_BUTTONS)
+			return -EINVAL;
+
+		rc = of_property_read_u32_array(np,
+			"goodix,button-map", button_map,
+			num_buttons);
+		if (rc) {
+			dev_err(dev, "Unable to read key codes\n");
+			return rc;
+		}
+	}
+
+	prop = of_find_property(np, "goodix,cfg-data", &pdata->gtp_cfg_len);
+	if (prop && prop->value) {
+		pdata->config_data = devm_kzalloc(dev,
+			GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH, GFP_KERNEL);
+		if (!pdata->config_data) {
+			dev_err(dev, "Not enough memory for panel config data\n");
+			return -ENOMEM;
+		}
+
+		pdata->config_data[0] = GTP_REG_CONFIG_DATA >> 8;
+		pdata->config_data[1] = GTP_REG_CONFIG_DATA & 0xff;
+		memset(&pdata->config_data[GTP_ADDR_LENGTH], 0,
+					GTP_CONFIG_MAX_LENGTH);
+		memcpy(&pdata->config_data[GTP_ADDR_LENGTH],
+				prop->value, pdata->gtp_cfg_len);
+	} else {
+		dev_err(dev,
+			"Unable to get configure data, default will be used.\n");
+		pdata->gtp_cfg_len = 0;
+	}
+
+	return 0;
 }
 
 /*******************************************************
 Function:
-    I2c probe.
+	I2c probe.
 Input:
-    client: i2c device struct.
-    id: device id.
+	client: i2c device struct.
+	id: device id.
 Output:
-    Executive outcomes. 
-        0: succeed.
+	Executive outcomes.
+	0: succeed.
 *******************************************************/
-static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
+
+static int goodix_ts_probe(struct i2c_client *client,
+			   const struct i2c_device_id *id)
 {
-    s32 ret = -1;
-    struct goodix_ts_data *ts;
-    u16 version_info;
+	struct goodix_ts_platform_data *pdata;
+	struct goodix_ts_data *ts;
+	u16 version_info;
+	int ret;
 
-    GTP_DEBUG_FUNC();
-    
-    //do NOT remove these logs
-    GTP_INFO("GTP Driver Version: %s", GTP_DRIVER_VERSION);
-    GTP_INFO("GTP Driver Built@%s, %s", __TIME__, __DATE__);
-    GTP_INFO("GTP I2C Address: 0x%02x", client->addr);
+	dev_dbg(&client->dev, "GTP I2C Address: 0x%02x\n", client->addr);
+	if (client->dev.of_node) {
+		pdata = devm_kzalloc(&client->dev,
+			sizeof(struct goodix_ts_platform_data), GFP_KERNEL);
+		if (!pdata) {
+			dev_err(&client->dev,
+				"GTP Failed to allocate memory for pdata\n");
+			return -ENOMEM;
+		}
 
-    i2c_connect_client = client;
-    
-    if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) 
-    {
-        GTP_ERROR("I2C check functionality failed.");
-        return -ENODEV;
-    }
-    ts = kzalloc(sizeof(*ts), GFP_KERNEL);
-    if (ts == NULL)
-    {
-        GTP_ERROR("Alloc GFP_KERNEL memory failed.");
-        return -ENOMEM;
-    }
-   
-    memset(ts, 0, sizeof(*ts));
-    INIT_WORK(&ts->work, goodix_ts_work_func);
-    ts->client = client;
-    spin_lock_init(&ts->irq_lock);          // 2.6.39 later
-    // ts->irq_lock = SPIN_LOCK_UNLOCKED;   // 2.6.39 & before
-    i2c_set_clientdata(client, ts);
-    
-    ts->gtp_rawdiff_mode = 0;
+		ret = goodix_parse_dt(&client->dev, pdata);
+		if (ret)
+			return ret;
+	} else {
+		pdata = client->dev.platform_data;
+	}
 
-    ret = gtp_request_io_port(ts);
-    if (ret < 0)
-    {
-        GTP_ERROR("GTP request IO port failed.");
-        kfree(ts);
-        return ret;
-    }
+	if (!pdata) {
+		dev_err(&client->dev, "GTP invalid pdata\n");
+		return -EINVAL;
+	}
 
-    ret = gtp_i2c_test(client);
-    if (ret < 0)
-    {
-        GTP_ERROR("I2C communication ERROR!");
-    }
+#if GTP_ESD_PROTECT
+	i2c_connect_client = client;
+#endif
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "GTP I2C not supported\n");
+		return -ENODEV;
+	}
+
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	if (!ts) {
+		dev_err(&client->dev, "GTP not enough memory for ts\n");
+		return -ENOMEM;
+	}
+
+	memset(ts, 0, sizeof(*ts));
+	ts->client = client;
+	ts->pdata = pdata;
+	/* For 2.6.39 & later use spin_lock_init(&ts->irq_lock)
+	 * For 2.6.39 & before, use ts->irq_lock = SPIN_LOCK_UNLOCKED
+	 */
+	spin_lock_init(&ts->irq_lock);
+	i2c_set_clientdata(client, ts);
+	ts->gtp_rawdiff_mode = 0;
+
+	ret = goodix_power_init(ts);
+	if (ret) {
+		dev_err(&client->dev, "GTP power init failed\n");
+		goto exit_free_client_data;
+	}
+
+	ret = goodix_power_on(ts);
+	if (ret) {
+		dev_err(&client->dev, "GTP power on failed\n");
+		goto exit_deinit_power;
+	}
+
+	ret = gtp_request_io_port(ts);
+	if (ret) {
+		dev_err(&client->dev, "GTP request IO port failed.\n");
+		goto exit_power_off;
+	}
+
+	gtp_reset_guitar(ts, 20);
+
+	ret = gtp_i2c_test(client);
+	if (ret != 2) {
+		dev_err(&client->dev, "I2C communication ERROR!\n");
+		goto exit_free_io_port;
+	}
 
 #if GTP_AUTO_UPDATE
-    ret = gup_init_update_proc(ts);
-    if (ret < 0)
-    {
-        GTP_ERROR("Create update thread error.");
-    }
+	ret = gup_init_update_proc(ts);
+	if (ret < 0) {
+		dev_err(&client->dev,
+			"GTP Create firmware update thread error.\n");
+		goto exit_free_io_port;
+	}
 #endif
-    
-    ret = gtp_init_panel(ts);
-    if (ret < 0)
-    {
-        GTP_ERROR("GTP init panel failed.");
-        ts->abs_x_max = GTP_MAX_WIDTH;
-        ts->abs_y_max = GTP_MAX_HEIGHT;
-        ts->int_trigger_type = GTP_INT_TRIGGER;
-    }
 
-    ret = gtp_request_input_dev(ts);
-    if (ret < 0)
-    {
-        GTP_ERROR("GTP request input dev failed");
-    }
-    
-    ret = gtp_request_irq(ts); 
-    if (ret < 0)
-    {
-        GTP_INFO("GTP works in polling mode.");
-    }
-    else
-    {
-        GTP_INFO("GTP works in interrupt mode.");
-    }
+	ret = gtp_init_panel(ts);
+	if (ret < 0) {
+		dev_err(&client->dev, "GTP init panel failed.\n");
+		ts->abs_x_max = GTP_MAX_WIDTH;
+		ts->abs_y_max = GTP_MAX_HEIGHT;
+		ts->int_trigger_type = GTP_INT_TRIGGER;
+	}
 
-    ret = gtp_read_version(client, &version_info);
-    if (ret < 0)
-    {
-        GTP_ERROR("Read version failed.");
-    }
-    if (ts->use_irq)
-    {
-        gtp_irq_enable(ts);
-    }
-    
+	ret = gtp_request_input_dev(ts);
+	if (ret) {
+		dev_err(&client->dev, "GTP request input dev failed.\n");
+		goto exit_free_inputdev;
+	}
+
+#if defined(CONFIG_FB)
+	ts->fb_notif.notifier_call = fb_notifier_callback;
+	ret = fb_register_client(&ts->fb_notif);
+	if (ret)
+		dev_err(&ts->client->dev,
+			"Unable to register fb_notifier: %d\n",
+			ret);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+	ts->early_suspend.suspend = goodix_ts_early_suspend;
+	ts->early_suspend.resume = goodix_ts_late_resume;
+	register_early_suspend(&ts->early_suspend);
+#endif
+
+	ts->goodix_wq = create_singlethread_workqueue("goodix_wq");
+	INIT_WORK(&ts->work, goodix_ts_work_func);
+
+	ret = gtp_request_irq(ts);
+	if (ret < 0)
+		dev_info(&client->dev, "GTP works in polling mode.\n");
+	else
+		dev_info(&client->dev, "GTP works in interrupt mode.\n");
+
+	ret = gtp_read_version(client, &version_info);
+	if (ret != 2) {
+		dev_err(&client->dev, "Read version failed.\n");
+		goto exit_free_irq;
+	}
+	if (ts->use_irq)
+		gtp_irq_enable(ts);
+
 #if GTP_CREATE_WR_NODE
-    init_wr_node(client);
+	init_wr_node(client);
 #endif
-    
-#if GTP_ESD_PROTECT
-    gtp_esd_switch(client, SWITCH_ON);
-#endif
-    return 0;
-}
 
+#if GTP_ESD_PROTECT
+	gtp_esd_switch(client, SWITCH_ON);
+#endif
+	init_done = true;
+	return 0;
+exit_free_irq:
+#if defined(CONFIG_FB)
+	if (fb_unregister_client(&ts->fb_notif))
+		dev_err(&client->dev,
+			"Error occurred while unregistering fb_notifier.\n");
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+	unregister_early_suspend(&ts->early_suspend);
+#endif
+	if (ts->use_irq)
+		free_irq(client->irq, ts);
+	else
+		hrtimer_cancel(&ts->timer);
+	cancel_work_sync(&ts->work);
+	flush_workqueue(ts->goodix_wq);
+	destroy_workqueue(ts->goodix_wq);
+
+	input_unregister_device(ts->input_dev);
+	if (ts->input_dev) {
+		input_free_device(ts->input_dev);
+		ts->input_dev = NULL;
+	}
+exit_free_inputdev:
+	kfree(ts->config_data);
+exit_free_io_port:
+	if (gpio_is_valid(pdata->reset_gpio))
+		gpio_free(pdata->reset_gpio);
+	if (gpio_is_valid(pdata->irq_gpio))
+		gpio_free(pdata->irq_gpio);
+exit_power_off:
+	goodix_power_off(ts);
+exit_deinit_power:
+	goodix_power_deinit(ts);
+exit_free_client_data:
+	i2c_set_clientdata(client, NULL);
+	kfree(ts);
+	return ret;
+}
 
 /*******************************************************
 Function:
-    Goodix touchscreen driver release function.
+	Goodix touchscreen driver release function.
 Input:
-    client: i2c device struct.
+	client: i2c device struct.
 Output:
-    Executive outcomes. 0---succeed.
+	Executive outcomes. 0---succeed.
 *******************************************************/
 static int goodix_ts_remove(struct i2c_client *client)
 {
-    struct goodix_ts_data *ts = i2c_get_clientdata(client);
-    
-    GTP_DEBUG_FUNC();
-    
-#ifdef CONFIG_HAS_EARLYSUSPEND
-    unregister_early_suspend(&ts->early_suspend);
+	struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+	GTP_DEBUG_FUNC();
+#if defined(CONFIG_FB)
+	if (fb_unregister_client(&ts->fb_notif))
+		dev_err(&client->dev,
+			"Error occurred while unregistering fb_notifier.\n");
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+	unregister_early_suspend(&ts->early_suspend);
 #endif
 
 #if GTP_CREATE_WR_NODE
-    uninit_wr_node();
+	uninit_wr_node();
 #endif
 
 #if GTP_ESD_PROTECT
-    destroy_workqueue(gtp_esd_check_workqueue);
+	cancel_work_sync(gtp_esd_check_workqueue);
+	flush_workqueue(gtp_esd_check_workqueue);
+	destroy_workqueue(gtp_esd_check_workqueue);
 #endif
 
-    if (ts) 
-    {
-        if (ts->use_irq)
-        {
-            GTP_GPIO_AS_INPUT(GTP_INT_PORT);
-            GTP_GPIO_FREE(GTP_INT_PORT);
-            free_irq(client->irq, ts);
-        }
-        else
-        {
-            hrtimer_cancel(&ts->timer);
-        }
-    }   
-    
-    GTP_INFO("GTP driver removing...");
-    i2c_set_clientdata(client, NULL);
-    input_unregister_device(ts->input_dev);
-    kfree(ts);
+	if (ts) {
+		if (ts->use_irq)
+			free_irq(client->irq, ts);
+		else
+			hrtimer_cancel(&ts->timer);
 
-    return 0;
+		cancel_work_sync(&ts->work);
+		flush_workqueue(ts->goodix_wq);
+		destroy_workqueue(ts->goodix_wq);
+
+		input_unregister_device(ts->input_dev);
+		if (ts->input_dev) {
+			input_free_device(ts->input_dev);
+			ts->input_dev = NULL;
+		}
+		kfree(ts->config_data);
+
+		if (gpio_is_valid(ts->pdata->reset_gpio))
+			gpio_free(ts->pdata->reset_gpio);
+		if (gpio_is_valid(ts->pdata->irq_gpio))
+			gpio_free(ts->pdata->irq_gpio);
+
+		goodix_power_off(ts);
+		goodix_power_deinit(ts);
+		i2c_set_clientdata(client, NULL);
+		kfree(ts);
+	}
+
+	return 0;
 }
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_FB)
 /*******************************************************
 Function:
-    Early suspend function.
+	Early suspend function.
 Input:
-    h: early_suspend struct.
+	h: early_suspend struct.
 Output:
-    None.
+	None.
+*******************************************************/
+static void goodix_ts_suspend(struct goodix_ts_data *ts)
+{
+	int ret = -1, i;
+
+	GTP_DEBUG_FUNC();
+
+#if GTP_ESD_PROTECT
+	ts->gtp_is_suspend = 1;
+	gtp_esd_switch(ts->client, SWITCH_OFF);
+#endif
+
+#if GTP_SLIDE_WAKEUP
+	ret = gtp_enter_doze(ts);
+#else
+	if (ts->use_irq)
+		gtp_irq_disable(ts);
+	else
+		hrtimer_cancel(&ts->timer);
+
+	for (i = 0; i < GTP_MAX_TOUCH; i++)
+		gtp_touch_up(ts, i);
+
+	input_sync(ts->input_dev);
+
+	ret = gtp_enter_sleep(ts);
+#endif
+	if (ret < 0)
+		dev_err(&ts->client->dev, "GTP early suspend failed.\n");
+	/* to avoid waking up while not sleeping,
+	 * delay 48 + 10ms to ensure reliability
+	 */
+	msleep(58);
+}
+
+/*******************************************************
+Function:
+	Late resume function.
+Input:
+	h: early_suspend struct.
+Output:
+	None.
+*******************************************************/
+static void goodix_ts_resume(struct goodix_ts_data *ts)
+{
+	int ret = -1;
+
+	GTP_DEBUG_FUNC();
+
+	ret = gtp_wakeup_sleep(ts);
+
+#if GTP_SLIDE_WAKEUP
+	doze_status = DOZE_DISABLED;
+#endif
+
+	if (ret < 0)
+		dev_err(&ts->client->dev, "GTP resume failed.\n");
+
+	if (ts->use_irq)
+		gtp_irq_enable(ts);
+	else
+		hrtimer_start(&ts->timer,
+			ktime_set(1, 0), HRTIMER_MODE_REL);
+
+#if GTP_ESD_PROTECT
+	ts->gtp_is_suspend = 0;
+	gtp_esd_switch(ts->client, SWITCH_ON);
+#endif
+}
+
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+				 unsigned long event, void *data)
+{
+	struct fb_event *evdata = data;
+	int *blank;
+	struct goodix_ts_data *ts =
+		container_of(self, struct goodix_ts_data, fb_notif);
+
+	if (evdata && evdata->data && event == FB_EVENT_BLANK &&
+			ts && ts->client) {
+		blank = evdata->data;
+		if (*blank == FB_BLANK_UNBLANK)
+			goodix_ts_resume(ts);
+		else if (*blank == FB_BLANK_POWERDOWN)
+			goodix_ts_suspend(ts);
+	}
+
+	return 0;
+}
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+/*******************************************************
+Function:
+	Early suspend function.
+Input:
+	h: early_suspend struct.
+Output:
+	None.
 *******************************************************/
 static void goodix_ts_early_suspend(struct early_suspend *h)
 {
-    struct goodix_ts_data *ts;
-    s8 ret = -1;    
-    ts = container_of(h, struct goodix_ts_data, early_suspend);
-    
-    GTP_DEBUG_FUNC();
+	struct goodix_ts_data *ts;
 
-#if GTP_ESD_PROTECT
-    ts->gtp_is_suspend = 1;
-    gtp_esd_switch(ts->client, SWITCH_OFF);
-#endif
-
-#if GTP_SLIDE_WAKEUP
-    ret = gtp_enter_doze(ts);
-#else
-    if (ts->use_irq)
-    {
-        gtp_irq_disable(ts);
-    }
-    else
-    {
-        hrtimer_cancel(&ts->timer);
-    }
-    ret = gtp_enter_sleep(ts);
-#endif 
-    if (ret < 0)
-    {
-        GTP_ERROR("GTP early suspend failed.");
-    }
-    // to avoid waking up while not sleeping
-    //  delay 48 + 10ms to ensure reliability    
-    msleep(58);   
+	ts = container_of(h, struct goodix_ts_data, early_suspend);
+	goodix_ts_suspend(ts);
+	return;
 }
 
 /*******************************************************
 Function:
-    Late resume function.
+	Late resume function.
 Input:
-    h: early_suspend struct.
+	h: early_suspend struct.
 Output:
-    None.
+	None.
 *******************************************************/
 static void goodix_ts_late_resume(struct early_suspend *h)
 {
-    struct goodix_ts_data *ts;
-    s8 ret = -1;
-    ts = container_of(h, struct goodix_ts_data, early_suspend);
-    
-    GTP_DEBUG_FUNC();
-    
-    ret = gtp_wakeup_sleep(ts);
+	struct goodix_ts_data *ts;
 
-#if GTP_SLIDE_WAKEUP
-    doze_status = DOZE_DISABLED;
-#endif
-
-    if (ret < 0)
-    {
-        GTP_ERROR("GTP later resume failed.");
-    }
-
-    if (ts->use_irq)
-    {
-        gtp_irq_enable(ts);
-    }
-    else
-    {
-        hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
-    }
-
-#if GTP_ESD_PROTECT
-    ts->gtp_is_suspend = 0;
-    gtp_esd_switch(ts->client, SWITCH_ON);
-#endif
+	ts = container_of(h, struct goodix_ts_data, early_suspend);
+	goodix_ts_late_resume(ts);
+	return;
 }
 #endif
+#endif /* !CONFIG_HAS_EARLYSUSPEND && !CONFIG_FB*/
 
 #if GTP_ESD_PROTECT
 /*******************************************************
 Function:
-    switch on & off esd delayed work
+	switch on & off esd delayed work
 Input:
-    client:  i2c device
-    on:      SWITCH_ON / SWITCH_OFF
+	client:  i2c device
+	on:	SWITCH_ON / SWITCH_OFF
 Output:
-    void
+	void
 *********************************************************/
-void gtp_esd_switch(struct i2c_client *client, s32 on)
+void gtp_esd_switch(struct i2c_client *client, int on)
 {
-    struct goodix_ts_data *ts;
-    
-    ts = i2c_get_clientdata(client);
-    if (SWITCH_ON == on)     // switch on esd 
-    {
-        if (!ts->esd_running)
-        {
-            ts->esd_running = 1;
-            GTP_INFO("Esd started");
-            queue_delayed_work(gtp_esd_check_workqueue, &gtp_esd_check_work, GTP_ESD_CHECK_CIRCLE);
-        }
-    }
-    else    // switch off esd
-    {
-        if (ts->esd_running)
-        {
-            ts->esd_running = 0;
-            GTP_INFO("Esd cancelled");
-            cancel_delayed_work_sync(&gtp_esd_check_work);
-        }
-    }
+	struct goodix_ts_data *ts;
+
+	ts = i2c_get_clientdata(client);
+	if (SWITCH_ON == on) {
+		/* switch on esd  */
+		if (!ts->esd_running) {
+			ts->esd_running = 1;
+			dev_dbg(&client->dev, "Esd started\n");
+			queue_delayed_work(gtp_esd_check_workqueue,
+				&gtp_esd_check_work, GTP_ESD_CHECK_CIRCLE);
+		}
+	} else {
+		/* switch off esd */
+		if (ts->esd_running) {
+			ts->esd_running = 0;
+			dev_dbg(&client->dev, "Esd cancelled\n");
+			cancel_delayed_work_sync(&gtp_esd_check_work);
+		}
+	}
 }
 
 /*******************************************************
 Function:
-    Initialize external watchdog for esd protect
+	Initialize external watchdog for esd protect
 Input:
-    client:  i2c device.
+	client:  i2c device.
 Output:
-    result of i2c write operation. 
-        1: succeed, otherwise: failed
+	result of i2c write operation.
+		1: succeed, otherwise: failed
 *********************************************************/
-static s32 gtp_init_ext_watchdog(struct i2c_client *client)
+static int gtp_init_ext_watchdog(struct i2c_client *client)
 {
-    u8 opr_buffer[4] = {0x80, 0x40, 0xAA, 0xAA};
-    
-    struct i2c_msg msg;         // in case of recursively reset by calling gtp_i2c_write
-    s32 ret = -1;
-    s32 retries = 0;
+	/* in case of recursively reset by calling gtp_i2c_write*/
+	struct i2c_msg msg;
+	u8 opr_buffer[4] = {0x80, 0x40, 0xAA, 0xAA};
+	int ret;
+	int retries = 0;
 
-    GTP_DEBUG("Init external watchdog...");
-    GTP_DEBUG_FUNC();
+	GTP_DEBUG("Init external watchdog...");
+	GTP_DEBUG_FUNC();
 
-    msg.flags = !I2C_M_RD;
-    msg.addr  = client->addr;
-    msg.len   = 4;
-    msg.buf   = opr_buffer;
+	msg.flags = !I2C_M_RD;
+	msg.addr  = client->addr;
+	msg.len   = 4;
+	msg.buf   = opr_buffer;
 
-    while(retries < 5)
-    {
-        ret = i2c_transfer(client->adapter, &msg, 1);
-        if (ret == 1)
-        {
-            return 1;
-        }
-        retries++;
-    }
-    if (retries >= 5)
-    {
-        GTP_ERROR("init external watchdog failed!");
-    }
-    return 0;
+	while (retries < 5) {
+		ret = i2c_transfer(client->adapter, &msg, 1);
+		if (ret == 1)
+			return 1;
+		retries++;
+	}
+	if (retries >= 5)
+		dev_err(&client->dev, "init external watchdog failed!");
+	return 0;
 }
 
 /*******************************************************
 Function:
-    Esd protect function.
-    Added external watchdog by meta, 2013/03/07
+	Esd protect function.
+	Added external watchdog by meta, 2013/03/07
 Input:
-    work: delayed work
+	work: delayed work
 Output:
-    None.
+	None.
 *******************************************************/
 static void gtp_esd_check_func(struct work_struct *work)
 {
-    s32 i;
-    s32 ret = -1;
-    struct goodix_ts_data *ts = NULL;
-    u8 test[4] = {0x80, 0x40};
-    
-    GTP_DEBUG_FUNC();
-   
-    ts = i2c_get_clientdata(i2c_connect_client);
+	s32 i;
+	s32 ret = -1;
+	struct goodix_ts_data *ts = NULL;
+	u8 test[4] = {0x80, 0x40};
 
-    if (ts->gtp_is_suspend)
-    {
-        ts->esd_running = 0;
-        GTP_INFO("Esd terminated!");
-        return;
-    }
-    
-    for (i = 0; i < 3; i++)
-    {
-        ret = gtp_i2c_read(ts->client, test, 4);
-        
-        GTP_DEBUG("0x8040 = 0x%02X, 0x8041 = 0x%02X", test[2], test[3]);
-        if ((ret < 0))
-        {
-            // IIC communication problem
-            continue;
-        }
-        else
-        { 
-            if ((test[2] == 0xAA) || (test[3] != 0xAA))
-            {
-                // IC works abnormally..
-                i = 3;
-                break;  
-            }
-            else 
-            {
-                // IC works normally, Write 0x8040 0xAA, feed the dog
-                test[2] = 0xAA; 
-                gtp_i2c_write(ts->client, test, 3);
-                break;
-            }
-        }
-    }
-    if (i >= 3)
-    {
-        GTP_ERROR("IC Working ABNORMALLY, Resetting Guitar...");
-        gtp_reset_guitar(ts->client, 50);
-    }
+	GTP_DEBUG_FUNC();
 
-    if(!ts->gtp_is_suspend)
-    {
-        queue_delayed_work(gtp_esd_check_workqueue, &gtp_esd_check_work, GTP_ESD_CHECK_CIRCLE);
-    }
-    else
-    {
-        GTP_INFO("Esd terminated!");
-        ts->esd_running = 0;
-    }
-    return;
+	ts = i2c_get_clientdata(i2c_connect_client);
+
+	if (ts->gtp_is_suspend) {
+		dev_dbg(&ts->client->dev, "Esd terminated!\n");
+		ts->esd_running = 0;
+		return;
+	}
+#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE
+	if (ts->enter_update)
+		return;
+#endif
+
+	for (i = 0; i < 3; i++) {
+		ret = gtp_i2c_read(ts->client, test, 4);
+
+		GTP_DEBUG("0x8040 = 0x%02X, 0x8041 = 0x%02X", test[2], test[3]);
+		if ((ret < 0)) {
+			/* IC works abnormally..*/
+			continue;
+		} else {
+			if ((test[2] == 0xAA) || (test[3] != 0xAA)) {
+				/* IC works abnormally..*/
+				i = 3;
+				break;
+			} else {
+				/* IC works normally, Write 0x8040 0xAA*/
+				test[2] = 0xAA;
+				gtp_i2c_write(ts->client, test, 3);
+				break;
+			}
+		}
+	}
+	if (i >= 3) {
+		dev_err(&ts->client->dev,
+			"IC Working ABNORMALLY, Resetting Guitar...\n");
+		gtp_reset_guitar(ts, 50);
+	}
+
+	if (!ts->gtp_is_suspend)
+		queue_delayed_work(gtp_esd_check_workqueue,
+			&gtp_esd_check_work, GTP_ESD_CHECK_CIRCLE);
+	else {
+		dev_dbg(&ts->client->dev, "Esd terminated!\n");
+		ts->esd_running = 0;
+	}
+
+	return;
 }
 #endif
 
 static const struct i2c_device_id goodix_ts_id[] = {
-    { GTP_I2C_NAME, 0 },
-    { }
+	{ GTP_I2C_NAME, 0 },
+	{ }
+};
+
+static struct of_device_id goodix_match_table[] = {
+	{ .compatible = "goodix,gt9xx", },
+	{ },
 };
 
 static struct i2c_driver goodix_ts_driver = {
-    .probe      = goodix_ts_probe,
-    .remove     = goodix_ts_remove,
-#ifndef CONFIG_HAS_EARLYSUSPEND
-    .suspend    = goodix_ts_early_suspend,
-    .resume     = goodix_ts_late_resume,
+	.probe      = goodix_ts_probe,
+	.remove     = goodix_ts_remove,
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	.suspend    = goodix_ts_early_suspend,
+	.resume     = goodix_ts_late_resume,
 #endif
-    .id_table   = goodix_ts_id,
-    .driver = {
-        .name     = GTP_I2C_NAME,
-        .owner    = THIS_MODULE,
-    },
+	.id_table   = goodix_ts_id,
+	.driver = {
+		.name     = GTP_I2C_NAME,
+		.owner    = THIS_MODULE,
+		.of_match_table = goodix_match_table,
+	},
 };
 
-/*******************************************************    
+/*******************************************************
 Function:
     Driver Install function.
 Input:
@@ -1766,41 +2188,29 @@
 ********************************************************/
 static int __devinit goodix_ts_init(void)
 {
-    s32 ret;
+	int ret;
 
-    GTP_DEBUG_FUNC();   
-    GTP_INFO("GTP driver installing...");
-    goodix_wq = create_singlethread_workqueue("goodix_wq");
-    if (!goodix_wq)
-    {
-        GTP_ERROR("Creat workqueue failed.");
-        return -ENOMEM;
-    }
+	GTP_DEBUG_FUNC();
 #if GTP_ESD_PROTECT
-    INIT_DELAYED_WORK(&gtp_esd_check_work, gtp_esd_check_func);
-    gtp_esd_check_workqueue = create_workqueue("gtp_esd_check");
+	INIT_DELAYED_WORK(&gtp_esd_check_work, gtp_esd_check_func);
+	gtp_esd_check_workqueue = create_workqueue("gtp_esd_check");
 #endif
-    ret = i2c_add_driver(&goodix_ts_driver);
-    return ret; 
+	ret = i2c_add_driver(&goodix_ts_driver);
+	return ret;
 }
 
-/*******************************************************    
+/*******************************************************
 Function:
-    Driver uninstall function.
+	Driver uninstall function.
 Input:
-    None.
+	None.
 Output:
-    Executive Outcomes. 0---succeed.
+	Executive Outcomes. 0---succeed.
 ********************************************************/
 static void __exit goodix_ts_exit(void)
 {
-    GTP_DEBUG_FUNC();
-    GTP_INFO("GTP driver exited.");
-    i2c_del_driver(&goodix_ts_driver);
-    if (goodix_wq)
-    {
-        destroy_workqueue(goodix_wq);
-    }
+	GTP_DEBUG_FUNC();
+	i2c_del_driver(&goodix_ts_driver);
 }
 
 late_initcall(goodix_ts_init);
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.h b/drivers/input/touchscreen/gt9xx/gt9xx.h
index e375af5..c9b81e7 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.h
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.h
@@ -1,241 +1,280 @@
 /* drivers/input/touchscreen/gt9xx.h
- * 
+ *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Linux Foundation chooses to take subject only to the GPLv2 license
+ * terms, and distributes only under these terms.
+ *
  * 2010 - 2013 Goodix Technology.
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be a reference 
- * to you, when you are integrating the GOODiX's CTP IC into your system, 
- * but WITHOUT ANY WARRANTY; without even the implied warranty of 
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
+ *
+ * This program is distributed in the hope that it will be a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
- * 
+ *
  */
 
 #ifndef _GOODIX_GT9XX_H_
 #define _GOODIX_GT9XX_H_
 
 #include <linux/kernel.h>
-#include <linux/hrtimer.h>
 #include <linux/i2c.h>
+#include <linux/irq.h>
 #include <linux/input.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/proc_fs.h>
-#include <linux/string.h>
-#include <asm/uaccess.h>
-#include <linux/vmalloc.h>
+#include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/io.h>
-#include <mach/gpio.h>
-#include <linux/earlysuspend.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/firmware.h>
+#include <linux/debugfs.h>
 
+#if defined(CONFIG_FB)
+#include <linux/notifier.h>
+#include <linux/fb.h>
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+#include <linux/earlysuspend.h>
+#define GOODIX_SUSPEND_LEVEL 1
+#endif
+
+struct goodix_ts_platform_data {
+	int irq_gpio;
+	u32 irq_gpio_flags;
+	int reset_gpio;
+	u32 reset_gpio_flags;
+	u32 family_id;
+	u32 x_max;
+	u32 y_max;
+	u32 x_min;
+	u32 y_min;
+	u32 panel_minx;
+	u32 panel_miny;
+	u32 panel_maxx;
+	u32 panel_maxy;
+	bool no_force_update;
+	bool i2c_pull_up;
+	int gtp_cfg_len;
+	u8 *config_data;
+};
 struct goodix_ts_data {
-    spinlock_t irq_lock;
-    struct i2c_client *client;
-    struct input_dev  *input_dev;
-    struct hrtimer timer;
-    struct work_struct  work;
-    struct early_suspend early_suspend;
-    s32 irq_is_disable;
-    s32 use_irq;
-    u16 abs_x_max;
-    u16 abs_y_max;
-    u8  max_touch_num;
-    u8  int_trigger_type;
-    u8  green_wake_mode;
-    u8  chip_type;
-    u8  enter_update;
-    u8  gtp_is_suspend;
-    u8  gtp_rawdiff_mode;
-    u8  gtp_cfg_len;
-    u8  fixed_cfg;
-    u8  esd_running;
-    u8  fw_error;
+	spinlock_t irq_lock;
+	struct i2c_client *client;
+	struct input_dev  *input_dev;
+	struct goodix_ts_platform_data *pdata;
+	struct hrtimer timer;
+	struct workqueue_struct *goodix_wq;
+	struct work_struct	work;
+	s32 irq_is_disabled;
+	s32 use_irq;
+	u16 abs_x_max;
+	u16 abs_y_max;
+	u8  max_touch_num;
+	u8  int_trigger_type;
+	u8  green_wake_mode;
+	u8  chip_type;
+	u8 *config_data;
+	u8  enter_update;
+	u8  gtp_is_suspend;
+	u8  gtp_rawdiff_mode;
+	u8  gtp_cfg_len;
+	u8  fixed_cfg;
+	u8  esd_running;
+	u8  fw_error;
+	struct regulator *avdd;
+	struct regulator *vdd;
+	struct regulator *vcc_i2c;
+#if defined(CONFIG_FB)
+	struct notifier_block fb_notif;
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+	struct early_suspend early_suspend;
+#endif
 };
 
 extern u16 show_len;
 extern u16 total_len;
 
-//***************************PART1:ON/OFF define*******************************
-#define GTP_CUSTOM_CFG        0
-#define GTP_CHANGE_X2Y        0
-#define GTP_DRIVER_SEND_CFG   1
-#define GTP_HAVE_TOUCH_KEY    0
-#define GTP_POWER_CTRL_SLEEP  0
-#define GTP_ICS_SLOT_REPORT   0
+/***************************PART1:ON/OFF define*******************************/
+#define GTP_CUSTOM_CFG			0
+#define GTP_CHANGE_X2Y			0
+#define GTP_DRIVER_SEND_CFG		1
+#define GTP_HAVE_TOUCH_KEY		1
+#define GTP_POWER_CTRL_SLEEP	0
 
-#define GTP_AUTO_UPDATE       1     // auto updated by .bin file as default
-#define GTP_HEADER_FW_UPDATE  0     // auto updated by head_fw_array in gt9xx_firmware.h, function together with GTP_AUTO_UPDATE
-                               
-#define GTP_CREATE_WR_NODE    1
-#define GTP_ESD_PROTECT       0
-#define GTP_WITH_PEN          0
+/* auto updated by .bin file as default */
+#define GTP_AUTO_UPDATE			0
+/* auto updated by head_fw_array in gt9xx_firmware.h,
+ * function together with GTP_AUTO_UPDATE */
+#define GTP_HEADER_FW_UPDATE	0
 
-#define GTP_SLIDE_WAKEUP      0
-#define GTP_DBL_CLK_WAKEUP    0     // double-click wakeup, function together with GTP_SLIDE_WAKEUP
+#define GTP_CREATE_WR_NODE		0
+#define GTP_ESD_PROTECT			0
+#define GTP_WITH_PEN			0
 
-#define GTP_DEBUG_ON          1
-#define GTP_DEBUG_ARRAY_ON    0
-#define GTP_DEBUG_FUNC_ON     0
+#define GTP_SLIDE_WAKEUP		0
+/* double-click wakeup, function together with GTP_SLIDE_WAKEUP */
+#define GTP_DBL_CLK_WAKEUP		0
 
-//*************************** PART2:TODO define **********************************
-// STEP_1(REQUIRED): Define Configuration Information Group(s)
-// Sensor_ID Map:
+#define GTP_DEBUG_ON			1
+#define GTP_DEBUG_ARRAY_ON		0
+#define GTP_DEBUG_FUNC_ON		0
+
+/*************************** PART2:TODO define *******************************/
+/* STEP_1(REQUIRED): Define Configuration Information Group(s) */
+/* Sensor_ID Map: */
 /* sensor_opt1 sensor_opt2 Sensor_ID
-    GND         GND         0 
-    VDDIO       GND         1 
-    NC          GND         2 
-    GND         NC/300K     3 
-    VDDIO       NC/300K     4 
-    NC          NC/300K     5 
+ *	GND			GND			0
+ *	VDDIO		GND			1
+ *	NC			GND			2
+ *	GND			NC/300K		3
+ *	VDDIO		NC/300K		4
+ *	NC			NC/300K		5
 */
-// TODO: define your own default or for Sensor_ID == 0 config here. 
-// The predefined one is just a sample config, which is not suitable for your tp in most cases.
+/* Define your own default or for Sensor_ID == 0 config here */
+/* The predefined one is just a sample config,
+ * which is not suitable for your tp in most cases. */
 #define CTP_CFG_GROUP1 {\
-    0x41,0x1C,0x02,0xC0,0x03,0x0A,0x05,0x01,0x01,0x0F,\
-    0x23,0x0F,0x5F,0x41,0x03,0x05,0x00,0x00,0x00,0x00,\
-    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x91,0x00,0x0A,\
-    0x28,0x00,0xB8,0x0B,0x00,0x00,0x00,0x9A,0x03,0x25,\
-    0x00,0x00,0x00,0x00,0x00,0x03,0x64,0x32,0x00,0x00,\
-    0x00,0x32,0x8C,0x94,0x05,0x01,0x05,0x00,0x00,0x96,\
-    0x0C,0x22,0xD8,0x0E,0x23,0x56,0x11,0x25,0xFF,0x13,\
-    0x28,0xA7,0x15,0x2E,0x00,0x00,0x10,0x30,0x48,0x00,\
-    0x56,0x4A,0x3A,0xFF,0xFF,0x16,0x00,0x00,0x00,0x00,\
-    0x00,0x01,0x1B,0x14,0x0D,0x19,0x00,0x00,0x01,0x00,\
-    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
-    0x00,0x00,0x1A,0x18,0x16,0x14,0x12,0x10,0x0E,0x0C,\
-    0x0A,0x08,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\
-    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\
-    0xFF,0xFF,0x1D,0x1E,0x1F,0x20,0x22,0x24,0x28,0x29,\
-    0x0C,0x0A,0x08,0x00,0x02,0x04,0x05,0x06,0x0E,0xFF,\
-    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\
-    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\
-    0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,\
-    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
-    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
-    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
-    0x00,0x00,0x00,0x00,0x00,0x00,0x91,0x01\
-    }
-    
-// TODO: define your config for Sensor_ID == 1 here, if needed
+	0x41, 0x1C, 0x02, 0xC0, 0x03, 0x0A, 0x05, 0x01, 0x01, 0x0F,\
+	0x23, 0x0F, 0x5F, 0x41, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00,\
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x0A,\
+	0x28, 0x00, 0xB8, 0x0B, 0x00, 0x00, 0x00, 0x9A, 0x03, 0x25,\
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x64, 0x32, 0x00, 0x00,\
+	0x00, 0x32, 0x8C, 0x94, 0x05, 0x01, 0x05, 0x00, 0x00, 0x96,\
+	0x0C, 0x22, 0xD8, 0x0E, 0x23, 0x56, 0x11, 0x25, 0xFF, 0x13,\
+	0x28, 0xA7, 0x15, 0x2E, 0x00, 0x00, 0x10, 0x30, 0x48, 0x00,\
+	0x56, 0x4A, 0x3A, 0xFF, 0xFF, 0x16, 0x00, 0x00, 0x00, 0x00,\
+	0x00, 0x01, 0x1B, 0x14, 0x0D, 0x19, 0x00, 0x00, 0x01, 0x00,\
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+	0x00, 0x00, 0x1A, 0x18, 0x16, 0x14, 0x12, 0x10, 0x0E, 0x0C,\
+	0x0A, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\
+	0xFF, 0xFF, 0x1D, 0x1E, 0x1F, 0x20, 0x22, 0x24, 0x28, 0x29,\
+	0x0C, 0x0A, 0x08, 0x00, 0x02, 0x04, 0x05, 0x06, 0x0E, 0xFF,\
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\
+	0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x01\
+	}
+
+/* Define your config for Sensor_ID == 1 here, if needed */
 #define CTP_CFG_GROUP2 {\
-    }
-// TODO: define your config for Sensor_ID == 2 here, if needed
+	}
+
+/* Define your config for Sensor_ID == 2 here, if needed */
 #define CTP_CFG_GROUP3 {\
-    }
+	}
 
-// TODO: define your config for Sensor_ID == 3 here, if needed
+/* Define your config for Sensor_ID == 3 here, if needed */
 #define CTP_CFG_GROUP4 {\
-    }
+	}
 
-// TODO: define your config for Sensor_ID == 4 here, if needed
+/* Define your config for Sensor_ID == 4 here, if needed */
 #define CTP_CFG_GROUP5 {\
-    }
+	}
 
-// TODO: define your config for Sensor_ID == 5 here, if needed
+/* Define your config for Sensor_ID == 5 here, if needed */
 #define CTP_CFG_GROUP6 {\
-    }
+	}
 
-// STEP_2(REQUIRED): Customize your I/O ports & I/O operations
-#define GTP_RST_PORT    S5PV210_GPJ3(6)
-#define GTP_INT_PORT    S5PV210_GPH1(3)
-#define GTP_INT_IRQ     gpio_to_irq(GTP_INT_PORT)
-#define GTP_INT_CFG     S3C_GPIO_SFN(0xF)
+#define GTP_IRQ_TAB		{\
+				IRQ_TYPE_EDGE_RISING,\
+				IRQ_TYPE_EDGE_FALLING,\
+				IRQ_TYPE_LEVEL_LOW,\
+				IRQ_TYPE_LEVEL_HIGH\
+				}
 
-#define GTP_GPIO_AS_INPUT(pin)          do{\
-                                            gpio_direction_input(pin);\
-                                            s3c_gpio_setpull(pin, S3C_GPIO_PULL_NONE);\
-                                        }while(0)
-#define GTP_GPIO_AS_INT(pin)            do{\
-                                            GTP_GPIO_AS_INPUT(pin);\
-                                            s3c_gpio_cfgpin(pin, GTP_INT_CFG);\
-                                        }while(0)
-#define GTP_GPIO_GET_VALUE(pin)         gpio_get_value(pin)
-#define GTP_GPIO_OUTPUT(pin,level)      gpio_direction_output(pin,level)
-#define GTP_GPIO_REQUEST(pin, label)    gpio_request(pin, label)
-#define GTP_GPIO_FREE(pin)              gpio_free(pin)
-#define GTP_IRQ_TAB                     {IRQ_TYPE_EDGE_RISING, IRQ_TYPE_EDGE_FALLING, IRQ_TYPE_LEVEL_LOW, IRQ_TYPE_LEVEL_HIGH}
-
-// STEP_3(optional): Specify your special config info if needed
+/* STEP_3(optional): Specify your special config info if needed */
+#define GTP_IRQ_TAB_RISING	0
+#define GTP_IRQ_TAB_FALLING	1
 #if GTP_CUSTOM_CFG
-  #define GTP_MAX_HEIGHT   800
-  #define GTP_MAX_WIDTH    480
-  #define GTP_INT_TRIGGER  0            // 0: Rising 1: Falling
+#define GTP_MAX_HEIGHT		800
+#define GTP_MAX_WIDTH		480
+#define GTP_INT_TRIGGER		GTP_IRQ_TAB_RISING
 #else
-  #define GTP_MAX_HEIGHT   4096
-  #define GTP_MAX_WIDTH    4096
-  #define GTP_INT_TRIGGER  1
+#define GTP_MAX_HEIGHT		4096
+#define GTP_MAX_WIDTH		4096
+#define GTP_INT_TRIGGER		GTP_IRQ_TAB_FALLING
 #endif
+
 #define GTP_MAX_TOUCH         5
-#define GTP_ESD_CHECK_CIRCLE  2000      // jiffy: ms
+#define GTP_ESD_CHECK_CIRCLE  2000      /* jiffy: ms */
 
-// STEP_4(optional): If keys are available and reported as keys, config your key info here                             
-#if GTP_HAVE_TOUCH_KEY
-    #define GTP_KEY_TAB  {KEY_MENU, KEY_HOME, KEY_BACK}
+/***************************PART3:OTHER define*********************************/
+#define GTP_DRIVER_VERSION		"V1.8<2013/06/08>"
+#define GTP_I2C_NAME			"Goodix-TS"
+#define GTP_POLL_TIME			10     /* jiffy: ms*/
+#define GTP_ADDR_LENGTH			2
+#define GTP_CONFIG_MIN_LENGTH	186
+#define GTP_CONFIG_MAX_LENGTH	240
+#define FAIL					0
+#define SUCCESS					1
+#define SWITCH_OFF				0
+#define SWITCH_ON				1
+
+/* Registers define */
+#define GTP_READ_COOR_ADDR		0x814E
+#define GTP_REG_SLEEP			0x8040
+#define GTP_REG_SENSOR_ID		0x814A
+#define GTP_REG_CONFIG_DATA		0x8047
+#define GTP_REG_VERSION			0x8140
+
+#define RESOLUTION_LOC			3
+#define TRIGGER_LOC				8
+
+#define CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0]))
+/* Log define */
+#define GTP_DEBUG(fmt, arg...)	do {\
+		if (GTP_DEBUG_ON) {\
+			pr_debug("<<-GTP-DEBUG->> [%d]"fmt"\n",\
+				__LINE__, ##arg); } \
+		} while (0)
+
+#define GTP_DEBUG_ARRAY(array, num)    do {\
+		s32 i; \
+		u8 *a = array; \
+		if (GTP_DEBUG_ARRAY_ON) {\
+			pr_debug("<<-GTP-DEBUG-ARRAY->>\n");\
+			for (i = 0; i < (num); i++) { \
+				pr_debug("%02x   ", (a)[i]);\
+				if ((i + 1) % 10 == 0) { \
+					pr_debug("\n");\
+				} \
+			} \
+			pr_debug("\n");\
+		} \
+	} while (0)
+
+#define GTP_DEBUG_FUNC()	do {\
+	if (GTP_DEBUG_FUNC_ON)\
+		pr_debug("<<-GTP-FUNC->> Func:%s@Line:%d\n",\
+					__func__, __LINE__);\
+	} while (0)
+
+#define GTP_SWAP(x, y)		do {\
+					typeof(x) z = x;\
+					x = y;\
+					y = z;\
+				} while (0)
+/*****************************End of Part III********************************/
+
+void gtp_esd_switch(struct i2c_client *client, int on);
+
+#if GTP_CREATE_WR_NODE
+extern s32 init_wr_node(struct i2c_client *client);
+extern void uninit_wr_node(void);
 #endif
 
-//***************************PART3:OTHER define*********************************
-#define GTP_DRIVER_VERSION    "V1.8<2013/06/08>"
-#define GTP_I2C_NAME          "Goodix-TS"
-#define GTP_POLL_TIME         10     // jiffy: ms
-#define GTP_ADDR_LENGTH       2
-#define GTP_CONFIG_MIN_LENGTH 186
-#define GTP_CONFIG_MAX_LENGTH 240
-#define FAIL                  0
-#define SUCCESS               1
-#define SWITCH_OFF            0
-#define SWITCH_ON             1
-
-// Registers define
-#define GTP_READ_COOR_ADDR    0x814E
-#define GTP_REG_SLEEP         0x8040
-#define GTP_REG_SENSOR_ID     0x814A
-#define GTP_REG_CONFIG_DATA   0x8047
-#define GTP_REG_VERSION       0x8140
-
-#define RESOLUTION_LOC        3
-#define TRIGGER_LOC           8
-
-#define CFG_GROUP_LEN(p_cfg_grp)  (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0]))
-// Log define
-#define GTP_INFO(fmt,arg...)           printk("<<-GTP-INFO->> "fmt"\n",##arg)
-#define GTP_ERROR(fmt,arg...)          printk("<<-GTP-ERROR->> "fmt"\n",##arg)
-#define GTP_DEBUG(fmt,arg...)          do{\
-                                         if(GTP_DEBUG_ON)\
-                                         printk("<<-GTP-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
-                                       }while(0)
-#define GTP_DEBUG_ARRAY(array, num)    do{\
-                                         s32 i;\
-                                         u8* a = array;\
-                                         if(GTP_DEBUG_ARRAY_ON)\
-                                         {\
-                                            printk("<<-GTP-DEBUG-ARRAY->>\n");\
-                                            for (i = 0; i < (num); i++)\
-                                            {\
-                                                printk("%02x   ", (a)[i]);\
-                                                if ((i + 1 ) %10 == 0)\
-                                                {\
-                                                    printk("\n");\
-                                                }\
-                                            }\
-                                            printk("\n");\
-                                        }\
-                                       }while(0)
-#define GTP_DEBUG_FUNC()               do{\
-                                         if(GTP_DEBUG_FUNC_ON)\
-                                         printk("<<-GTP-FUNC->> Func:%s@Line:%d\n",__func__,__LINE__);\
-                                       }while(0)
-#define GTP_SWAP(x, y)                 do{\
-                                         typeof(x) z = x;\
-                                         x = y;\
-                                         y = z;\
-                                       }while (0)
-
-//*****************************End of Part III********************************
-
+#if GTP_AUTO_UPDATE
+extern u8 gup_init_update_proc(struct goodix_ts_data *ts);
+#endif
 #endif /* _GOODIX_GT9XX_H_ */
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h b/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h
index 3998bf0..81e3aff 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h
+++ b/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h
@@ -1,6 +1,6 @@
-// make sense only when GTP_HEADER_FW_UPDATE & GTP_AUTO_UPDATE are enabled

-// define your own firmware array here

-const unsigned char header_fw_array[] = 

-{

-    

-};
\ No newline at end of file
+/*
+ * make sense only when GTP_HEADER_FW_UPDATE & GTP_AUTO_UPDATE are enabled
+ * define your own firmware array here
+*/
+const unsigned char header_fw_array[] = {
+};
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx_update.c b/drivers/input/touchscreen/gt9xx/gt9xx_update.c
index f564a6b..cf83154 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx_update.c
+++ b/drivers/input/touchscreen/gt9xx/gt9xx_update.c
@@ -1,21 +1,22 @@
 /* drivers/input/touchscreen/gt9xx_update.c
- * 
+ *
  * 2010 - 2012 Goodix Technology.
- * 
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be a reference 
- * to you, when you are integrating the GOODiX's CTP IC into your system, 
- * but WITHOUT ANY WARRANTY; without even the implied warranty of 
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
+ *
+ * This program is distributed in the hope that it will be a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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.
- * 
+ *
  * Latest Version:1.6
  * Author: andrew@goodix.com
- * Revision Record: 
+ * Revision Record:
  *      V1.0:
  *          first release. By Andrew, 2012/08/31
  *      V1.2:
@@ -25,7 +26,7 @@
  *          2. modify enter_update_mode;
  *          3. add update file cal checksum.
  *                          By Andrew, 2012/12/12
- *      V1.6: 
+ *      V1.6:
  *          1. replace guitar_client with i2c_connect_client;
  *          2. support firmware header array update.
  *                          By Meta, 2013/03/11
@@ -47,8 +48,8 @@
 #define UPDATE_FILE_PATH_2          "/data/_goodix_update_.bin"
 #define UPDATE_FILE_PATH_1          "/sdcard/_goodix_update_.bin"
 
-#define CONFIG_FILE_PATH_1          "/data/_goodix_config_.cfg"     
-#define CONFIG_FILE_PATH_2          "/sdcard/_goodix_config_.cfg"   
+#define CONFIG_FILE_PATH_1          "/data/_goodix_config_.cfg"
+#define CONFIG_FILE_PATH_2          "/sdcard/_goodix_config_.cfg"
 
 #define FW_HEAD_LENGTH               14
 #define FW_SECTION_LENGTH            0x2000
@@ -73,39 +74,27 @@
 #define SUCCESS 1
 
 #pragma pack(1)
-typedef struct 
-{
-    u8  hw_info[4];          //hardware info//
-    u8  pid[8];              //product id   //
-    u16 vid;                 //version id   //
-}st_fw_head;
+struct {
+	u8  hw_info[4];		/* hardware info */
+	u8  pid[8];		/* product id   */
+	u16 vid;		/* version id   */
+} st_fw_head;
 #pragma pack()
 
-typedef struct
-{
-    u8 force_update;
-    u8 fw_flag;
-    struct file *file; 
-    struct file *cfg_file;
-    st_fw_head  ic_fw_msg;
-    mm_segment_t old_fs;
-}st_update_msg;
+struct {
+	u8 force_update;
+	u8 fw_flag;
+	struct file *file;
+	struct file *cfg_file;
+	st_fw_head  ic_fw_msg;
+	mm_segment_t old_fs;
+} st_update_msg;
 
 st_update_msg update_msg;
 u16 show_len;
 u16 total_len;
-u8 got_file_flag = 0;
-u8 searching_file = 0;
-extern u8 config[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH];
-extern void gtp_reset_guitar(struct i2c_client *client, s32 ms);
-extern s32  gtp_send_cfg(struct i2c_client *client);
-extern struct i2c_client * i2c_connect_client;
-extern void gtp_irq_enable(struct goodix_ts_data *ts);
-extern void gtp_irq_disable(struct goodix_ts_data *ts);
-extern s32 gtp_i2c_read_dbl_check(struct i2c_client *, u16, u8 *, int);
-#if GTP_ESD_PROTECT
-extern void gtp_esd_switch(struct i2c_client *, s32);
-#endif
+u8 got_file_flag;
+u8 searching_file;
 /*******************************************************
 Function:
     Read data from the i2c slave device.
@@ -115,37 +104,37 @@
     buf[2~len-1]:   read data buffer.
     len:    GTP_ADDR_LENGTH + read bytes count
 Output:
-    numbers of i2c_msgs to transfer: 
+    numbers of i2c_msgs to transfer:
       2: succeed, otherwise: failed
 *********************************************************/
 s32 gup_i2c_read(struct i2c_client *client, u8 *buf, s32 len)
 {
-    struct i2c_msg msgs[2];
-    s32 ret=-1;
-    s32 retries = 0;
+	struct i2c_msg msgs[2];
+	s32 ret = -1;
+	s32 retries = 0;
 
-    GTP_DEBUG_FUNC();
+	GTP_DEBUG_FUNC();
 
-    msgs[0].flags = !I2C_M_RD;
-    msgs[0].addr  = client->addr;
-    msgs[0].len   = GTP_ADDR_LENGTH;
-    msgs[0].buf   = &buf[0];
-    //msgs[0].scl_rate = 300 * 1000;    // for Rockchip
+	msgs[0].flags = !I2C_M_RD;
+	msgs[0].addr  = client->addr;
+	msgs[0].len   = GTP_ADDR_LENGTH;
+	msgs[0].buf   = &buf[0];
+	/* msgs[0].scl_rate = 300 * 1000;  (for Rockchip) */
 
-    msgs[1].flags = I2C_M_RD;
-    msgs[1].addr  = client->addr;
-    msgs[1].len   = len - GTP_ADDR_LENGTH;
-    msgs[1].buf   = &buf[GTP_ADDR_LENGTH];
-    //msgs[1].scl_rate = 300 * 1000;    
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].addr  = client->addr;
+	msgs[1].len   = len - GTP_ADDR_LENGTH;
+	msgs[1].buf   = &buf[GTP_ADDR_LENGTH];
+	/* msgs[1].scl_rate = 300 * 1000; */
 
-    while(retries < 5)
-    {
-        ret = i2c_transfer(client->adapter, msgs, 2);
-        if(ret == 2)break;
-        retries++;
-    }
+	while (retries < 5) {
+		ret = i2c_transfer(client->adapter, msgs, 2);
+		if (ret == 2)
+			break;
+		retries++;
+	}
 
-    return ret;
+	return ret;
 }
 
 /*******************************************************
@@ -157,1774 +146,1632 @@
     buf[2~len-1]:   data buffer
     len:    GTP_ADDR_LENGTH + write bytes count
 Output:
-    numbers of i2c_msgs to transfer: 
-        1: succeed, otherwise: failed
+    numbers of i2c_msgs to transfer:
+	1: succeed, otherwise: failed
 *********************************************************/
-s32 gup_i2c_write(struct i2c_client *client,u8 *buf,s32 len)
+s32 gup_i2c_write(struct i2c_client *client, u8 *buf, s32 len)
 {
-    struct i2c_msg msg;
-    s32 ret=-1;
-    s32 retries = 0;
+	struct i2c_msg msg;
+	s32 ret = -1;
+	s32 retries = 0;
 
-    GTP_DEBUG_FUNC();
+	GTP_DEBUG_FUNC();
 
-    msg.flags = !I2C_M_RD;
-    msg.addr  = client->addr;
-    msg.len   = len;
-    msg.buf   = buf;
-    //msg.scl_rate = 300 * 1000;    // for Rockchip
+	msg.flags = !I2C_M_RD;
+	msg.addr  = client->addr;
+	msg.len   = len;
+	msg.buf   = buf;
+	/* msg.scl_rate = 300 * 1000;    (for Rockchip) */
 
-    while(retries < 5)
-    {
-        ret = i2c_transfer(client->adapter, &msg, 1);
-        if (ret == 1)break;
-        retries++;
-    }
+	while (retries < 5) {
+		ret = i2c_transfer(client->adapter, &msg, 1);
+		if (ret == 1)
+			break;
+		retries++;
+	}
 
-    return ret;
+	return ret;
 }
 
 static s32 gup_init_panel(struct goodix_ts_data *ts)
 {
-    s32 ret = 0;
-    s32 i = 0;
-    u8 check_sum = 0;
-    u8 opr_buf[16];
-    u8 sensor_id = 0;
+	s32 ret = 0;
+	s32 i = 0;
+	u8 check_sum = 0;
+	u8 opr_buf[16];
+	u8 sensor_id = 0;
 
-    u8 cfg_info_group1[] = CTP_CFG_GROUP1;
-    u8 cfg_info_group2[] = CTP_CFG_GROUP2;
-    u8 cfg_info_group3[] = CTP_CFG_GROUP3;
-    u8 cfg_info_group4[] = CTP_CFG_GROUP4;
-    u8 cfg_info_group5[] = CTP_CFG_GROUP5;
-    u8 cfg_info_group6[] = CTP_CFG_GROUP6;
-    u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2, cfg_info_group3,
-                        cfg_info_group4, cfg_info_group5, cfg_info_group6};
-    u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group1),
-                          CFG_GROUP_LEN(cfg_info_group2),
-                          CFG_GROUP_LEN(cfg_info_group3),
-                          CFG_GROUP_LEN(cfg_info_group4),
-                          CFG_GROUP_LEN(cfg_info_group5),
-                          CFG_GROUP_LEN(cfg_info_group6)};
-                          
-    if ((!cfg_info_len[1]) && (!cfg_info_len[2]) && 
-        (!cfg_info_len[3]) && (!cfg_info_len[4]) && 
-        (!cfg_info_len[5]))
-    {
-        sensor_id = 0; 
-    }
-    else
-    {
-        ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID, &sensor_id, 1);
-        if (SUCCESS == ret)
-        {
-            if (sensor_id >= 0x06)
-            {
-                GTP_ERROR("Invalid sensor_id(0x%02X), No Config Sent!", sensor_id);
-                return -1;
-            }
-        }
-        else
-        {
-            GTP_ERROR("Failed to get sensor_id, No config sent!");
-            return -1;
-        }
-    }
-    
-    GTP_DEBUG("Sensor_ID: %d", sensor_id);
-    
-    ts->gtp_cfg_len = cfg_info_len[sensor_id];
-    
-    if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH)
-    {
-        GTP_ERROR("Sensor_ID(%d) matches with NULL or INVALID CONFIG GROUP! NO Config Sent! You need to check you header file CFG_GROUP section!", sensor_id);
-        return -1;
-    }
-    
-    ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, &opr_buf[0], 1);
-    
-    if (ret == SUCCESS)
-    {
-        GTP_DEBUG("CFG_GROUP%d Config Version: %d, IC Config Version: %d", sensor_id+1, 
-                    send_cfg_buf[sensor_id][0], opr_buf[0]);
-        
-        send_cfg_buf[sensor_id][0] = opr_buf[0];
-        ts->fixed_cfg = 0;
-        /*
-        if (opr_buf[0] < 90)    
-        {
-            grp_cfg_version = send_cfg_buf[sensor_id][0];       // backup group config version
-            send_cfg_buf[sensor_id][0] = 0x00;
-            ts->fixed_cfg = 0;
-        }
-        else        // treated as fixed config, not send config
-        {
-            GTP_INFO("Ic fixed config with config version(%d)", opr_buf[0]);
-            ts->fixed_cfg = 1;
-        }*/
-    }
-    else
-    {
-        GTP_ERROR("Failed to get ic config version!No config sent!");
-        return -1;
-    }
-    
-    memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
-    memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id], ts->gtp_cfg_len);
+	u8 cfg_info_group1[] = CTP_CFG_GROUP1;
+	u8 cfg_info_group2[] = CTP_CFG_GROUP2;
+	u8 cfg_info_group3[] = CTP_CFG_GROUP3;
+	u8 cfg_info_group4[] = CTP_CFG_GROUP4;
+	u8 cfg_info_group5[] = CTP_CFG_GROUP5;
+	u8 cfg_info_group6[] = CTP_CFG_GROUP6;
+	u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2, cfg_info_group3,
+			cfg_info_group4, cfg_info_group5, cfg_info_group6};
+	u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group1),
+			CFG_GROUP_LEN(cfg_info_group2),
+			CFG_GROUP_LEN(cfg_info_group3),
+			CFG_GROUP_LEN(cfg_info_group4),
+			CFG_GROUP_LEN(cfg_info_group5),
+			CFG_GROUP_LEN(cfg_info_group6)};
 
-    GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
-        ts->abs_x_max, ts->abs_y_max, ts->int_trigger_type);
+	if ((!cfg_info_len[1]) && (!cfg_info_len[2]) &&
+	(!cfg_info_len[3]) && (!cfg_info_len[4]) &&
+	(!cfg_info_len[5])) {
+		sensor_id = 0;
+	} else {
+		ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID,
+							&sensor_id, 1);
+		if (SUCCESS == ret) {
+			if (sensor_id >= 0x06) {
+				GTP_ERROR("Invalid sensor_id(0x%02X), " \
+					"No Config Sent!", sensor_id);
+				return -EINVAL;
+			}
+		} else {
+			GTP_ERROR("Failed to get sensor_id, No config sent!");
+			return -EINVAL;
+		}
+	}
 
-    config[RESOLUTION_LOC]     = (u8)GTP_MAX_WIDTH;
-    config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8);
-    config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT;
-    config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8);
-    
-    if (GTP_INT_TRIGGER == 0)  //RISING
-    {
-        config[TRIGGER_LOC] &= 0xfe; 
-    }
-    else if (GTP_INT_TRIGGER == 1)  //FALLING
-    {
-        config[TRIGGER_LOC] |= 0x01;
-    }
-    
-    check_sum = 0;
-    for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
-    {
-        check_sum += config[i];
-    }
-    config[ts->gtp_cfg_len] = (~check_sum) + 1;
+	GTP_DEBUG("Sensor_ID: %d", sensor_id);
 
-    GTP_DEBUG_FUNC();
-    ret = gtp_send_cfg(ts->client);
-    if (ret < 0)
-    {
-        GTP_ERROR("Send config error.");
-    }
+	ts->gtp_cfg_len = cfg_info_len[sensor_id];
 
-    msleep(10);
-    return 0;
+	if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH) {
+		GTP_ERROR("Sensor_ID(%d) matches with NULL or INVALID CONFIG" \
+			" GROUP! NO Config Sent! You need to check you header" \
+			"  file CFG_GROUP section!", sensor_id);
+		return -EINVAL;
+	}
+
+	ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
+					&opr_buf[0], 1);
+
+	if (ret == SUCCESS) {
+		GTP_DEBUG("CFG_GROUP%d Config Version: %d, IC Config Version:" \
+		" %d", sensor_id+1, send_cfg_buf[sensor_id][0],	opr_buf[0]);
+
+		send_cfg_buf[sensor_id][0] = opr_buf[0];
+		ts->fixed_cfg = 0;
+		/*
+		if (opr_buf[0] < 90) {
+			grp_cfg_version = send_cfg_buf[sensor_id][0];
+				*** backup group config version ***
+			send_cfg_buf[sensor_id][0] = 0x00;
+			ts->fixed_cfg = 0;
+		} else { *** treated as fixed config, not send config ***
+			GTP_INFO("Ic fixed config with config version(%d)",
+							opr_buf[0]);
+			ts->fixed_cfg = 1;
+		}*/
+	} else {
+		GTP_ERROR("Failed to get ic config version!No config sent!");
+		return -EINVAL;
+	}
+
+	memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
+	memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id],
+						ts->gtp_cfg_len);
+
+	GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
+	ts->abs_x_max, ts->abs_y_max, ts->int_trigger_type);
+
+	config[RESOLUTION_LOC]     = (u8)GTP_MAX_WIDTH;
+	config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8);
+	config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT;
+	config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8);
+
+	if (GTP_INT_TRIGGER == 0)  /* RISING */
+		config[TRIGGER_LOC] &= 0xfe;
+	else if (GTP_INT_TRIGGER == 1)  /* FALLING */
+		config[TRIGGER_LOC] |= 0x01;
+
+	check_sum = 0;
+	for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
+		check_sum += config[i];
+
+	config[ts->gtp_cfg_len] = (~check_sum) + 1;
+
+	GTP_DEBUG_FUNC();
+	ret = gtp_send_cfg(ts->client);
+	if (ret < 0)
+		GTP_ERROR("Send config error.");
+
+	msleep(20);
+	return 0;
 }
 
 
-static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8* msg, s32 len)
+static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8 *msg, s32 len)
 {
-    s32 i = 0;
+	s32 i = 0;
 
-    msg[0] = (addr >> 8) & 0xff;
-    msg[1] = addr & 0xff;
+	msg[0] = (addr >> 8) & 0xff;
+	msg[1] = addr & 0xff;
 
-    for (i = 0; i < 5; i++)
-    {
-        if (gup_i2c_read(client, msg, GTP_ADDR_LENGTH + len) > 0)
-        {
-            break;
-        }
-    }
+	for (i = 0; i < 5; i++)
+		if (gup_i2c_read(client, msg, GTP_ADDR_LENGTH + len) > 0)
+			break;
 
-    if (i >= 5)
-    {
-        GTP_ERROR("Read data from 0x%02x%02x failed!", msg[0], msg[1]);
-        return FAIL;
-    }
+	if (i >= 5) {
+		GTP_ERROR("Read data from 0x%02x%02x failed!", msg[0], msg[1]);
+		return FAIL;
+	}
 
-    return SUCCESS;
+	return SUCCESS;
 }
 
 static u8 gup_set_ic_msg(struct i2c_client *client, u16 addr, u8 val)
 {
-    s32 i = 0;
-    u8 msg[3];
+	s32 i = 0;
+	u8 msg[3];
 
-    msg[0] = (addr >> 8) & 0xff;
-    msg[1] = addr & 0xff;
-    msg[2] = val;
+	msg[0] = (addr >> 8) & 0xff;
+	msg[1] = addr & 0xff;
+	msg[2] = val;
 
-    for (i = 0; i < 5; i++)
-    {
-        if (gup_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0)
-        {
-            break;
-        }
-    }
+	for (i = 0; i < 5; i++)
+		if (gup_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0)
+			break;
 
-    if (i >= 5)
-    {
-        GTP_ERROR("Set data to 0x%02x%02x failed!", msg[0], msg[1]);
-        return FAIL;
-    }
+	if (i >= 5) {
+		GTP_ERROR("Set data to 0x%02x%02x failed!", msg[0], msg[1]);
+		return FAIL;
+	}
 
-    return SUCCESS;
+	return SUCCESS;
 }
 
 static u8 gup_get_ic_fw_msg(struct i2c_client *client)
 {
-    s32 ret = -1;
-    u8  retry = 0;
-    u8  buf[16];
-    u8  i;
-    
-    // step1:get hardware info
-    ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO, &buf[GTP_ADDR_LENGTH], 4);
-    if (FAIL == ret)
-    {
-        GTP_ERROR("[get_ic_fw_msg]get hw_info failed,exit");
-        return FAIL;
-    }
-     
-    // buf[2~5]: 00 06 90 00
-    // hw_info: 00 90 06 00
-    for(i=0; i<4; i++)
-    {
-        update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i];
-    } 
-    GTP_DEBUG("IC Hardware info:%02x%02x%02x%02x", update_msg.ic_fw_msg.hw_info[0], update_msg.ic_fw_msg.hw_info[1],
-                                                   update_msg.ic_fw_msg.hw_info[2], update_msg.ic_fw_msg.hw_info[3]);
-    // step2:get firmware message
-    for(retry=0; retry<2; retry++)
-    {
-        ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1);
-        if(FAIL == ret)
-        {
-            GTP_ERROR("Read firmware message fail.");
-            return ret;
-        }
-        
-        update_msg.force_update = buf[GTP_ADDR_LENGTH];
-        if((0xBE != update_msg.force_update)&&(!retry))
-        {
-            GTP_INFO("The check sum in ic is error.");
-            GTP_INFO("The IC will be updated by force.");
-            continue;
-        }
-        break;
-    }
-    GTP_DEBUG("IC force update flag:0x%x", update_msg.force_update);
-    
-    // step3:get pid & vid
-    ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID, &buf[GTP_ADDR_LENGTH], 6);
-    if (FAIL == ret)
-    {
-        GTP_ERROR("[get_ic_fw_msg]get pid & vid failed,exit");
-        return FAIL;
-    }
-    
-    memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid));
-    memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4);
-    GTP_DEBUG("IC Product id:%s", update_msg.ic_fw_msg.pid);
-    
-    //GT9XX PID MAPPING
-    /*|-----FLASH-----RAM-----|
-      |------918------918-----|
-      |------968------968-----|
-      |------913------913-----|
-      |------913P-----913P----|
-      |------927------927-----|
-      |------927P-----927P----|
-      |------9110-----9110----|
-      |------9110P----9111----|*/
-    if(update_msg.ic_fw_msg.pid[0] != 0)
-    {
-        if(!memcmp(update_msg.ic_fw_msg.pid, "9111", 4))
-        {
-            GTP_DEBUG("IC Mapping Product id:%s", update_msg.ic_fw_msg.pid);
-            memcpy(update_msg.ic_fw_msg.pid, "9110P", 5);
-        }
-    }
-    
-    update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH+4] + (buf[GTP_ADDR_LENGTH+5]<<8);
-    GTP_DEBUG("IC version id:%04x", update_msg.ic_fw_msg.vid);
-    
-    return SUCCESS;
+	s32 ret = -1;
+	u8  retry = 0;
+	u8  buf[16];
+	u8  i;
+
+	/* step1:get hardware info */
+	ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO,
+					&buf[GTP_ADDR_LENGTH], 4);
+	if (ret == FAIL) {
+		GTP_ERROR("[get_ic_fw_msg]get hw_info failed,exit");
+		return FAIL;
+	}
+
+	/*  buf[2~5]: 00 06 90 00 */
+	/* hw_info: 00 90 06 00 */
+	for (i = 0; i < 4; i++)
+		update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i];
+
+	GTP_DEBUG("IC Hardware info:%02x%02x%02x%02x",
+		update_msg.ic_fw_msg.hw_info[0],
+		update_msg.ic_fw_msg.hw_info[1],
+		update_msg.ic_fw_msg.hw_info[2],
+		update_msg.ic_fw_msg.hw_info[3]);
+
+	/* step2:get firmware message */
+	for (retry = 0; retry < 2; retry++) {
+		ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1);
+		if (ret == FAIL) {
+			GTP_ERROR("Read firmware message fail.");
+			return ret;
+		}
+
+		update_msg.force_update = buf[GTP_ADDR_LENGTH];
+		if ((0xBE != update_msg.force_update) && (!retry)) {
+			GTP_INFO("The check sum in ic is error.");
+			GTP_INFO("The IC will be updated by force.");
+			continue;
+		}
+		break;
+	}
+	GTP_DEBUG("IC force update flag:0x%x", update_msg.force_update);
+
+	/*  step3:get pid & vid */
+	ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID,
+						&buf[GTP_ADDR_LENGTH], 6);
+	if (FAIL == ret) {
+		GTP_ERROR("[get_ic_fw_msg]get pid & vid failed,exit");
+		return FAIL;
+	}
+
+	memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid));
+	memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4);
+	GTP_DEBUG("IC Product id:%s", update_msg.ic_fw_msg.pid);
+
+	/* GT9XX PID MAPPING
+	|-----FLASH-----RAM-----|
+	|------918------918-----|
+	|------968------968-----|
+	|------913------913-----|
+	|------913P-----913P----|
+	|------927------927-----|
+	|------927P-----927P----|
+	|------9110-----9110----|
+	|------9110P----9111----|*/
+	if (update_msg.ic_fw_msg.pid[0] != 0) {
+		if (!memcmp(update_msg.ic_fw_msg.pid, "9111", 4)) {
+			GTP_DEBUG("IC Mapping Product id:%s",
+					update_msg.ic_fw_msg.pid);
+			memcpy(update_msg.ic_fw_msg.pid, "9110P", 5);
+		}
+	}
+
+	update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH + 4] +
+				(buf[GTP_ADDR_LENGTH + 5] << 8);
+	GTP_DEBUG("IC version id:%04x", update_msg.ic_fw_msg.vid);
+
+	return SUCCESS;
 }
 
 s32 gup_enter_update_mode(struct i2c_client *client)
 {
-    s32 ret = -1;
-    s32 retry = 0;
-    u8 rd_buf[3];
-    
-    //step1:RST output low last at least 2ms
-    GTP_GPIO_OUTPUT(GTP_RST_PORT, 0);
-    msleep(2);
-    
-    //step2:select I2C slave addr,INT:0--0xBA;1--0x28.
-    GTP_GPIO_OUTPUT(GTP_INT_PORT, (client->addr == 0x14));
-    msleep(2);
-    
-    //step3:RST output high reset guitar
-    GTP_GPIO_OUTPUT(GTP_RST_PORT, 1);
-    
-    //20121211 modify start
-    msleep(5);
-    while(retry++ < 200)
-    {
-        //step4:Hold ss51 & dsp
-        ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
-        if(ret <= 0)
-        {
-            GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
-            continue;
-        }
-        
-        //step5:Confirm hold
-        ret = gup_get_ic_msg(client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1);
-        if(ret <= 0)
-        {
-            GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
-            continue;
-        }
-        if(0x0C == rd_buf[GTP_ADDR_LENGTH])
-        {
-            GTP_DEBUG("Hold ss51 & dsp confirm SUCCESS");
-            break;
-        }
-        GTP_DEBUG("Hold ss51 & dsp confirm 0x4180 failed,value:%d", rd_buf[GTP_ADDR_LENGTH]);
-    }
-    if(retry >= 200)
-    {
-        GTP_ERROR("Enter update Hold ss51 failed.");
-        return FAIL;
-    }
-    
-    //step6:DSP_CK and DSP_ALU_CK PowerOn
-    ret = gup_set_ic_msg(client, 0x4010, 0x00);
-    
-    //20121211 modify end
-    return ret;
+	s32 ret = -1;
+	s32 retry = 0;
+	u8 rd_buf[3];
+
+	/* step1:RST output low last at least 2ms */
+	GTP_GPIO_OUTPUT(GTP_RST_PORT, 0);
+	msleep(20);
+
+	/* step2:select I2C slave addr,INT:0--0xBA;1--0x28. */
+	GTP_GPIO_OUTPUT(GTP_INT_PORT, (client->addr == 0x14));
+	msleep(20);
+
+	/* step3:RST output high reset guitar */
+	GTP_GPIO_OUTPUT(GTP_RST_PORT, 1);
+
+	/* 20121211 modify start */
+	msleep(20);
+	while (retry++ < 200) {
+		/* step4:Hold ss51 & dsp */
+		ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+		if (ret <= 0) {
+			GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
+			continue;
+		}
+
+		/* step5:Confirm hold */
+		ret = gup_get_ic_msg(client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1);
+		if (ret <= 0) {
+			GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
+			continue;
+		}
+		if (rd_buf[GTP_ADDR_LENGTH] == 0x0C) {
+			GTP_DEBUG("Hold ss51 & dsp confirm SUCCESS");
+			break;
+		}
+		GTP_DEBUG("Hold ss51 & dsp confirm 0x4180 failed,value:%d",
+					rd_buf[GTP_ADDR_LENGTH]);
+	}
+	if (retry >= 200) {
+		GTP_ERROR("Enter update Hold ss51 failed.");
+		return FAIL;
+	}
+
+	/* step6:DSP_CK and DSP_ALU_CK PowerOn */
+	ret = gup_set_ic_msg(client, 0x4010, 0x00);
+
+	/* 20121211 modify end */
+	return ret;
 }
 
 void gup_leave_update_mode(void)
 {
-    GTP_GPIO_AS_INT(GTP_INT_PORT);
-    
-    GTP_DEBUG("[leave_update_mode]reset chip.");
-    gtp_reset_guitar(i2c_connect_client, 20);
+	GTP_GPIO_AS_INT(GTP_INT_PORT);
+
+	GTP_DEBUG("[leave_update_mode]reset chip.");
+	gtp_reset_guitar(i2c_connect_client, 20);
 }
 
-// Get the correct nvram data
-// The correct conditions: 
-//  1. the hardware info is the same
-//  2. the product id is the same
-//  3. the firmware version in update file is greater than the firmware version in ic 
-//      or the check sum in ic is wrong
-/* Update Conditions: 
-    1. Same hardware info
-    2. Same PID
-    3. File PID > IC PID
-   Force Update Conditions:
-    1. Wrong ic firmware checksum
-    2. INVALID IC PID or VID
-    3. IC PID == 91XX || File PID == 91XX
+/*	Get the correct nvram data
+	The correct conditions:
+	1. the hardware info is the same
+	2. the product id is the same
+	3. the firmware version in update file is greater than the firmware
+	version in ic or the check sum in ic is wrong
+
+	Update Conditions:
+	1. Same hardware info
+	2. Same PID
+	3. File PID > IC PID
+
+	Force Update Conditions:
+	1. Wrong ic firmware checksum
+	2. INVALID IC PID or VID
+	3. IC PID == 91XX || File PID == 91XX
 */
 
 static u8 gup_enter_update_judge(st_fw_head *fw_head)
 {
-    u16 u16_tmp;
-    s32 i = 0;
-    
-    u16_tmp = fw_head->vid;
-    fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8);
+	u16 u16_tmp;
+	s32 i = 0;
 
-    GTP_DEBUG("FILE HARDWARE INFO:%02x%02x%02x%02x", fw_head->hw_info[0], fw_head->hw_info[1], fw_head->hw_info[2], fw_head->hw_info[3]);
-    GTP_DEBUG("FILE PID:%s", fw_head->pid);
-    GTP_DEBUG("FILE VID:%04x", fw_head->vid);
+	u16_tmp = fw_head->vid;
+	fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8);
 
-    GTP_DEBUG("IC HARDWARE INFO:%02x%02x%02x%02x", update_msg.ic_fw_msg.hw_info[0], update_msg.ic_fw_msg.hw_info[1],
-                                                   update_msg.ic_fw_msg.hw_info[2], update_msg.ic_fw_msg.hw_info[3]);
-    GTP_DEBUG("IC PID:%s", update_msg.ic_fw_msg.pid);
-    GTP_DEBUG("IC VID:%04x", update_msg.ic_fw_msg.vid);
+	GTP_DEBUG("FILE HARDWARE INFO:%02x%02x%02x%02x", fw_head->hw_info[0],
+		fw_head->hw_info[1], fw_head->hw_info[2], fw_head->hw_info[3]);
+	TP_DEBUG("FILE PID:%s", fw_head->pid);
+	TP_DEBUG("FILE VID:%04x", fw_head->vid);
 
-    //First two conditions
-    if ( !memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info, sizeof(update_msg.ic_fw_msg.hw_info)))
-    {
-        GTP_DEBUG("Get the same hardware info.");
-        if( update_msg.force_update != 0xBE )
-        {
-            GTP_INFO("FW chksum error,need enter update.");
-            return SUCCESS;
-        }
-        
-        // 20130523 start
-        if (strlen(update_msg.ic_fw_msg.pid) < 3)
-        {
-            GTP_INFO("Illegal IC pid, need enter update");
-            return SUCCESS;
-        }
-        else
-        {
-            for (i = 0; i < 3; i++)
-            {
-                if ((update_msg.ic_fw_msg.pid[i] < 0x30) || (update_msg.ic_fw_msg.pid[i] > 0x39))
-                {
-                    GTP_INFO("Illegal IC pid, out of bound, need enter update");
-                    return SUCCESS;
-                }
-            }
-        }
-        // 20130523 end
-        
-        
-        if (( !memcmp(fw_head->pid, update_msg.ic_fw_msg.pid, (strlen(fw_head->pid)<3?3:strlen(fw_head->pid))))||
-            (!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4))||
-            (!memcmp(fw_head->pid, "91XX", 4)))
-        {
-            if(!memcmp(fw_head->pid, "91XX", 4))
-            {
-                GTP_DEBUG("Force none same pid update mode.");
-            }
-            else
-            {
-                GTP_DEBUG("Get the same pid.");
-            }
-            //The third condition
-            if (fw_head->vid > update_msg.ic_fw_msg.vid)
-            {
+	TP_DEBUG("IC HARDWARE INFO:%02x%02x%02x%02x",
+		update_msg.ic_fw_msg.hw_info[0],
+		update_msg.ic_fw_msg.hw_info[1],
+		update_msg.ic_fw_msg.hw_info[2],
+		update_msg.ic_fw_msg.hw_info[3]);
+	TP_DEBUG("IC PID:%s", update_msg.ic_fw_msg.pid);
+	TP_DEBUG("IC VID:%04x", update_msg.ic_fw_msg.vid);
 
-                GTP_INFO("Need enter update.");
-                return SUCCESS;
-            }
-            GTP_ERROR("Don't meet the third condition.");
-            GTP_ERROR("File VID <= Ic VID, update aborted!");
-        }
-        else
-        {
-            GTP_ERROR("File PID != Ic PID, update aborted!");
-        }
-    }
-    else
-    {
-        GTP_ERROR("Different Hardware, update aborted!");
-    }
-    return FAIL;
+	/* First two conditions */
+	if (!memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info,
+			sizeof(update_msg.ic_fw_msg.hw_info))) {
+		GTP_DEBUG("Get the same hardware info.");
+		if (update_msg.force_update != 0xBE) {
+			GTP_INFO("FW chksum error,need enter update.");
+			return SUCCESS;
+		}
+
+		/* 20130523 start */
+		if (strlen(update_msg.ic_fw_msg.pid) < 3) {
+			GTP_INFO("Illegal IC pid, need enter update");
+			return SUCCESS;
+		} else {
+			for (i = 0; i < 3; i++) {
+				if ((update_msg.ic_fw_msg.pid[i] < 0x30) ||
+					(update_msg.ic_fw_msg.pid[i] > 0x39)) {
+					GTP_INFO("Illegal IC pid, out of " \
+					"bound, need enter update");
+					return SUCCESS;
+				}
+			}
+		}
+		/* 20130523 end */
+
+		if ((!memcmp(fw_head->pid, update_msg.ic_fw_msg.pid,
+		(strlen(fw_head->pid) < 3 ? 3 : strlen(fw_head->pid)))) ||
+		(!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4)) ||
+		(!memcmp(fw_head->pid, "91XX", 4))) {
+			if (!memcmp(fw_head->pid, "91XX", 4))
+				GTP_DEBUG("Force none same pid update mode.");
+			else
+				GTP_DEBUG("Get the same pid.");
+
+			/* The third condition */
+			if (fw_head->vid > update_msg.ic_fw_msg.vid) {
+				GTP_INFO("Need enter update.");
+				return SUCCESS;
+			}
+			GTP_ERROR("Don't meet the third condition.");
+			GTP_ERROR("File VID <= Ic VID, update aborted!");
+		} else {
+			GTP_ERROR("File PID != Ic PID, update aborted!");
+		}
+	} else {
+		GTP_ERROR("Different Hardware, update aborted!");
+	}
+
+	return FAIL;
 }
 
 static u8 ascii2hex(u8 a)
 {
-    s8 value = 0;
+	s8 value = 0;
 
-    if(a >= '0' && a <= '9')
-    {
-        value = a - '0';
-    }
-    else if(a >= 'A' && a <= 'F')
-    {
-        value = a - 'A' + 0x0A;
-    }
-    else if(a >= 'a' && a <= 'f')
-    {
-        value = a - 'a' + 0x0A;
-    }
-    else
-    {
-        value = 0xff;
-    }
-    
-    return value;
+	if (a >= '0' && a <= '9')
+		value = a - '0';
+	else if (a >= 'A' && a <= 'F')
+		value = a - 'A' + 0x0A;
+	else if (a >= 'a' && a <= 'f')
+		value = a - 'a' + 0x0A;
+	else
+		value = 0xff;
+
+	return value;
 }
 
 static s8 gup_update_config(struct i2c_client *client)
 {
-    s32 file_len = 0;
-    s32 ret = 0;
-    s32 i = 0;
-    s32 file_cfg_len = 0;
-    s32 chip_cfg_len = 0;
-    s32 count = 0;
-    u8 *buf;
-    u8 *pre_buf;
-    u8 *file_config;
-    //u8 checksum = 0;
-    u8 pid[8];
-    
-    if(NULL == update_msg.cfg_file)
-    {
-        GTP_ERROR("[update_cfg]No need to upgrade config!");
-        return FAIL;
-    }
-    file_len = update_msg.cfg_file->f_op->llseek(update_msg.cfg_file, 0, SEEK_END);
-    
-    ret = gup_get_ic_msg(client, GUP_REG_PID_VID, pid, 6);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[update_cfg]Read product id & version id fail.");
-        return FAIL;
-    }
-    pid[5] = '\0';
-    GTP_DEBUG("update cfg get pid:%s", &pid[GTP_ADDR_LENGTH]);
-    
-    chip_cfg_len = 186;
-    if(!memcmp(&pid[GTP_ADDR_LENGTH], "968", 3) || 
-       !memcmp(&pid[GTP_ADDR_LENGTH], "910", 3) ||
-       !memcmp(&pid[GTP_ADDR_LENGTH], "960", 3))
-    {
-        chip_cfg_len = 228;
-    }
-    GTP_DEBUG("[update_cfg]config file len:%d", file_len);
-    GTP_DEBUG("[update_cfg]need config len:%d",chip_cfg_len);
-    if((file_len+5) < chip_cfg_len*5)
-    {
-        GTP_ERROR("Config length error");
-        return -1;
-    }
-    
-    buf = (u8*)kzalloc(file_len, GFP_KERNEL);
-    pre_buf = (u8*)kzalloc(file_len, GFP_KERNEL);
-    file_config = (u8*)kzalloc(chip_cfg_len + GTP_ADDR_LENGTH, GFP_KERNEL);
-    update_msg.cfg_file->f_op->llseek(update_msg.cfg_file, 0, SEEK_SET);
-    
-    GTP_DEBUG("[update_cfg]Read config from file.");
-    ret = update_msg.cfg_file->f_op->read(update_msg.cfg_file, (char*)pre_buf, file_len, &update_msg.cfg_file->f_pos);
-    if(ret<0)
-    {
-        GTP_ERROR("[update_cfg]Read config file failed.");
-        goto update_cfg_file_failed;
-    }
-    
-    GTP_DEBUG("[update_cfg]Delete illgal charactor.");
-    for(i=0,count=0; i<file_len; i++)
-    {
-        if (pre_buf[i] == ' ' || pre_buf[i] == '\r' || pre_buf[i] == '\n')
-        {
-            continue;
-        }
-        buf[count++] = pre_buf[i];
-    }
-    
-    GTP_DEBUG("[update_cfg]Ascii to hex.");
-    file_config[0] = GTP_REG_CONFIG_DATA >> 8;
-    file_config[1] = GTP_REG_CONFIG_DATA & 0xff;
-    for(i=0,file_cfg_len=GTP_ADDR_LENGTH; i<count; i+=5)
-    {
-        if((buf[i]=='0') && ((buf[i+1]=='x') || (buf[i+1]=='X')))
-        {
-            u8 high,low;
-            high = ascii2hex(buf[i+2]);
-            low = ascii2hex(buf[i+3]);
-            
-            if((high == 0xFF) || (low == 0xFF))
-            {
-                ret = 0;
-                GTP_ERROR("[update_cfg]Illegal config file.");
-                goto update_cfg_file_failed;
-            }
-            file_config[file_cfg_len++] = (high<<4) + low;
-        }
-        else
-        {
-            ret = 0;
-            GTP_ERROR("[update_cfg]Illegal config file.");
-            goto update_cfg_file_failed;
-        }
-    }
-    
-//    //cal checksum
-//    for(i=GTP_ADDR_LENGTH; i<chip_cfg_len; i++)
-//    {
-//        checksum += file_config[i];
-//    }
-//    file_config[chip_cfg_len] = (~checksum) + 1;
-//    file_config[chip_cfg_len+1] = 0x01;
-    
-    GTP_DEBUG("config:");
-    GTP_DEBUG_ARRAY(file_config+2, file_cfg_len);
-    
-    i = 0;
-    while(i++ < 5)
-    {
-        ret = gup_i2c_write(client, file_config, file_cfg_len);
-        if(ret > 0)
-        {
-            GTP_INFO("[update_cfg]Send config SUCCESS.");
-            break;
-        }
-        GTP_ERROR("[update_cfg]Send config i2c error.");
-    }
-    
+	s32 file_len = 0;
+	s32 ret = 0;
+	s32 i = 0;
+	s32 file_cfg_len = 0;
+	s32 chip_cfg_len = 0;
+	s32 count = 0;
+	u8 *buf;
+	u8 *pre_buf;
+	u8 *file_config;
+	/* u8 checksum = 0; */
+	u8 pid[8];
+
+	if (update_msg.cfg_file == NULL) {
+		GTP_ERROR("[update_cfg]No need to upgrade config!");
+		return FAIL;
+	}
+	file_len = update_msg.cfg_file->f_op->llseek(update_msg.cfg_file,
+							0, SEEK_END);
+
+	ret = gup_get_ic_msg(client, GUP_REG_PID_VID, pid, 6);
+	if (ret == FAIL) {
+		GTP_ERROR("[update_cfg]Read product id & version id fail.");
+		return FAIL;
+	}
+	pid[5] = '\0';
+	GTP_DEBUG("update cfg get pid:%s", &pid[GTP_ADDR_LENGTH]);
+
+	chip_cfg_len = 186;
+	if (!memcmp(&pid[GTP_ADDR_LENGTH], "968", 3) ||
+	!memcmp(&pid[GTP_ADDR_LENGTH], "910", 3) ||
+	!memcmp(&pid[GTP_ADDR_LENGTH], "960", 3)) {
+		chip_cfg_len = 228;
+	}
+	GTP_DEBUG("[update_cfg]config file len:%d", file_len);
+	GTP_DEBUG("[update_cfg]need config len:%d", chip_cfg_len);
+	if ((file_len+5) < chip_cfg_len*5) {
+		GTP_ERROR("Config length error");
+		return -EINVAL;
+	}
+
+	buf = kzalloc(file_len, GFP_KERNEL);
+	pre_buf = kzalloc(file_len, GFP_KERNEL);
+	file_config = kzalloc(chip_cfg_len + GTP_ADDR_LENGTH, GFP_KERNEL);
+	update_msg.cfg_file->f_op->llseek(update_msg.cfg_file, 0, SEEK_SET);
+
+	GTP_DEBUG("[update_cfg]Read config from file.");
+	ret = update_msg.cfg_file->f_op->read(update_msg.cfg_file,
+			(char *)pre_buf, file_len, &update_msg.cfg_file->f_pos);
+	if (ret < 0) {
+		GTP_ERROR("[update_cfg]Read config file failed.");
+		goto update_cfg_file_failed;
+	}
+
+	GTP_DEBUG("[update_cfg]Delete illgal charactor.");
+	for (i = 0, count = 0; i < file_len; i++) {
+		if (pre_buf[i] == ' ' || pre_buf[i] == '\r'
+					|| pre_buf[i] == '\n')
+			continue;
+		buf[count++] = pre_buf[i];
+	}
+
+	GTP_DEBUG("[update_cfg]Ascii to hex.");
+	file_config[0] = GTP_REG_CONFIG_DATA >> 8;
+	file_config[1] = GTP_REG_CONFIG_DATA & 0xff;
+	for (i = 0, file_cfg_len = GTP_ADDR_LENGTH; i < count; i + = 5) {
+		if ((buf[i] == '0') && ((buf[i+1] == 'x') ||
+						(buf[i+1] == 'X'))) {
+			u8 high, low;
+			high = ascii2hex(buf[i+2]);
+			low = ascii2hex(buf[i+3]);
+
+			if ((high == 0xFF) || (low == 0xFF)) {
+				ret = 0;
+				GTP_ERROR("[update_cfg]Illegal config file.");
+				goto update_cfg_file_failed;
+			}
+			file_config[file_cfg_len++] = (high<<4) + low;
+		} else {
+			ret = 0;
+			GTP_ERROR("[update_cfg]Illegal config file.");
+			goto update_cfg_file_failed;
+		}
+	}
+
+	/* cal checksum */
+	/* for(i=GTP_ADDR_LENGTH; i<chip_cfg_len; i++)
+		checksum += file_config[i];
+	file_config[chip_cfg_len] = (~checksum) + 1;
+	file_config[chip_cfg_len+1] = 0x01; */
+
+	GTP_DEBUG("config:");
+	GTP_DEBUG_ARRAY(file_config+2, file_cfg_len);
+
+	i = 0;
+	while (i++ < 5) {
+		ret = gup_i2c_write(client, file_config, file_cfg_len);
+		if (ret > 0) {
+			GTP_INFO("[update_cfg]Send config SUCCESS.");
+			break;
+		}
+		GTP_ERROR("[update_cfg]Send config i2c error.");
+	}
+
 update_cfg_file_failed:
-    kfree(pre_buf);
-    kfree(buf);
-    kfree(file_config);
-    return ret;
+	kfree(pre_buf);
+	kfree(buf);
+	kfree(file_config);
+	return ret;
 }
 
 #if GTP_HEADER_FW_UPDATE
 static u8 gup_check_fs_mounted(char *path_name)
 {
-    struct path root_path;
-    struct path path;
-    int err;
-    err = kern_path("/", LOOKUP_FOLLOW, &root_path);
+	struct path root_path;
+	struct path path;
+	int err;
+	err = kern_path("/", LOOKUP_FOLLOW, &root_path);
 
-    if (err)
-    {
-        GTP_DEBUG("\"/\" NOT Mounted: %d", err);
-        return FAIL;
-    }
-    err = kern_path(path_name, LOOKUP_FOLLOW, &path);
+	if (err) {
+		GTP_DEBUG("\"/\" NOT Mounted: %d", err);
+		return FAIL;
+	}
+	err = kern_path(path_name, LOOKUP_FOLLOW, &path);
 
-    if (err)
-    {
-        GTP_DEBUG("/data/ NOT Mounted: %d", err);
-        return FAIL;
-    }
+	if (err) {
+		GTP_DEBUG("/data/ NOT Mounted: %d", err);
+		return FAIL;
+	}
 
-    return SUCCESS;
-    
-    /*
-    if (path.mnt->mnt_sb == root_path.mnt->mnt_sb)
-    {
-        //-- not mounted
-        return FAIL;
-    }
-    else
-    {
-        return SUCCESS;
-    }*/
+	return SUCCESS;
 
+	/* if (path.mnt->mnt_sb == root_path.mnt->mnt_sb)
+		return FAIL;
+	else
+		return SUCCESS; */
 }
 #endif
-static u8 gup_check_update_file(struct i2c_client *client, st_fw_head* fw_head, u8* path)
+
+static u8 gup_check_update_file(struct i2c_client *client, st_fw_head *fw_head,
+								u8 *path)
 {
-    s32 ret = 0;
-    s32 i = 0;
-    s32 fw_checksum = 0;
-    u8 buf[FW_HEAD_LENGTH];
-    
-    if (path)
-    {
-        GTP_DEBUG("Update File path:%s, %d", path, strlen(path));
-        update_msg.file = filp_open(path, O_RDONLY, 0);
+	s32 ret = 0;
+	s32 i = 0;
+	s32 fw_checksum = 0;
+	u8 buf[FW_HEAD_LENGTH];
 
-        if (IS_ERR(update_msg.file))
-        {
-            GTP_ERROR("Open update file(%s) error!", path);
-            return FAIL;
-        }
-    }
-    else
-    {
+	if (path) {
+		GTP_DEBUG("Update File path:%s, %d", path, strlen(path));
+		update_msg.file = file_open(path, O_RDONLY, 0);
+
+		if (IS_ERR(update_msg.file)) {
+			GTP_ERROR("Open update file(%s) error!", path);
+			return FAIL;
+		}
+	} else {
 #if GTP_HEADER_FW_UPDATE
-        for (i = 0; i < (GUP_SEARCH_FILE_TIMES); i++)
-        {
-            GTP_DEBUG("Waiting for /data mounted [%d]", i);
+		for (i = 0; i < (GUP_SEARCH_FILE_TIMES); i++) {
+			GTP_DEBUG("Waiting for /data mounted [%d]", i);
 
-            if (gup_check_fs_mounted("/data") == SUCCESS)
-            {
-                GTP_DEBUG("/data Mounted!");
-                break;
-            }
-            msleep(3000);
-        }
-        if (i >= (GUP_SEARCH_FILE_TIMES))
-        {
-            GTP_ERROR("Wait for /data mounted timeout!");
-            return FAIL;
-        }
-        
-        // update config
-        update_msg.cfg_file = filp_open(CONFIG_FILE_PATH_1, O_RDONLY, 0);
-        if (IS_ERR(update_msg.cfg_file))
-        {
-            GTP_DEBUG("%s is unavailable", CONFIG_FILE_PATH_1);
-        }
-        else
-        {
-            GTP_INFO("Update Config File: %s", CONFIG_FILE_PATH_1);
-            ret = gup_update_config(client);
-            if(ret <= 0)
-            {
-                GTP_ERROR("Update config failed.");
-            }
-            filp_close(update_msg.cfg_file, NULL);
-        }
-        
-        if (sizeof(header_fw_array) < (FW_HEAD_LENGTH+FW_SECTION_LENGTH*4+FW_DSP_ISP_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH))
-        {
-            GTP_ERROR("INVALID header_fw_array, check your gt9xx_firmware.h file!");
-            return FAIL;           
-        }
-        update_msg.file = filp_open(UPDATE_FILE_PATH_2, O_CREAT | O_RDWR, 0666);
-        if ((IS_ERR(update_msg.file)))
-        {
-            GTP_ERROR("Failed to Create file: %s for fw_header!", UPDATE_FILE_PATH_2);
-            return FAIL;
-        }
-        update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
-        update_msg.file->f_op->write(update_msg.file, (char *)header_fw_array, sizeof(header_fw_array), &update_msg.file->f_pos);
-        filp_close(update_msg.file, NULL);
-        update_msg.file = filp_open(UPDATE_FILE_PATH_2, O_RDONLY, 0);
+			if (gup_check_fs_mounted("/data") == SUCCESS) {
+				GTP_DEBUG("/data Mounted!");
+				break;
+			}
+			msleep(3000);
+		}
+		if (i >= (GUP_SEARCH_FILE_TIMES)) {
+			GTP_ERROR("Wait for /data mounted timeout!");
+			return FAIL;
+		}
+
+		/* update config */
+		update_msg.cfg_file = file_open(CONFIG_FILE_PATH_1,
+							O_RDONLY, 0);
+
+		if (IS_ERR(update_msg.cfg_file)) {
+			GTP_DEBUG("%s is unavailable", CONFIG_FILE_PATH_1);
+		} else {
+			GTP_INFO("Update Config File: %s", CONFIG_FILE_PATH_1);
+			ret = gup_update_config(client);
+			if (ret <= 0)
+				GTP_ERROR("Update config failed.");
+			filp_close(update_msg.cfg_file, NULL);
+		}
+
+		if (sizeof(header_fw_array) < (FW_HEAD_LENGTH+FW_SECTION_LENGTH
+		*4 + FW_DSP_ISP_LENGTH+FW_DSP_LENGTH + FW_BOOT_LENGTH)) {
+			GTP_ERROR("INVALID header_fw_array, check your " \
+				"gt9xx_firmware.h file!");
+			return FAIL;
+		}
+		update_msg.file = file_open(UPDATE_FILE_PATH_2, O_CREAT |
+								O_RDWR, 0666);
+		if ((IS_ERR(update_msg.file))) {
+			GTP_ERROR("Failed to Create file: %s for fw_header!",
+							UPDATE_FILE_PATH_2);
+			return FAIL;
+		}
+		update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
+		update_msg.file->f_op->write(update_msg.file,
+			(char *)header_fw_array, sizeof(header_fw_array),
+			&update_msg.file->f_pos);
+		file_close(update_msg.file, NULL);
+		update_msg.file = file_open(UPDATE_FILE_PATH_2, O_RDONLY, 0);
 #else
-        u8 fp_len = max(sizeof(UPDATE_FILE_PATH_1), sizeof(UPDATE_FILE_PATH_2));
-        u8 cfp_len = max(sizeof(CONFIG_FILE_PATH_1), sizeof(CONFIG_FILE_PATH_2));
-        u8 *search_update_path = (u8*)kzalloc(fp_len, GFP_KERNEL);
-        u8 *search_cfg_path = (u8*)kzalloc(cfp_len, GFP_KERNEL);
-        //Begin to search update file,the config file & firmware file must be in the same path,single or double.
-        searching_file = 1;
-        for (i = 0; i < GUP_SEARCH_FILE_TIMES; i++)
-        {
-            if (searching_file == 0)
-            {
-                kfree(search_update_path);
-                kfree(search_cfg_path);
-                GTP_INFO(".bin/.cfg update file search forcely terminated!");
-                return FAIL;
-            }
-            if(i%2)
-            {
-                memcpy(search_update_path, UPDATE_FILE_PATH_1, sizeof(UPDATE_FILE_PATH_1));
-                memcpy(search_cfg_path, CONFIG_FILE_PATH_1, sizeof(CONFIG_FILE_PATH_1));
-            }
-            else
-            {
-                memcpy(search_update_path, UPDATE_FILE_PATH_2, sizeof(UPDATE_FILE_PATH_2));
-                memcpy(search_cfg_path, CONFIG_FILE_PATH_2, sizeof(CONFIG_FILE_PATH_2));
-            }
-            
-            if(!(got_file_flag&0x0F))
-            {
-                update_msg.file = filp_open(search_update_path, O_RDONLY, 0);
-                if(!IS_ERR(update_msg.file))
-                {
-                    GTP_DEBUG("Find the bin file");
-                    got_file_flag |= 0x0F;
-                }
-            }
-            if(!(got_file_flag&0xF0))
-            {
-                update_msg.cfg_file = filp_open(search_cfg_path, O_RDONLY, 0);
-                if(!IS_ERR(update_msg.cfg_file))
-                {
-                    GTP_DEBUG("Find the cfg file");
-                    got_file_flag |= 0xF0;
-                }
-            }
-            
-            if(got_file_flag)
-            {
-                if(got_file_flag == 0xFF)
-                {
-                    break;
-                }
-                else
-                {
-                    i += 4;
-                }
-            }
-            GTP_DEBUG("%3d:Searching %s %s file...", i, (got_file_flag&0x0F)?"":"bin", (got_file_flag&0xF0)?"":"cfg");
-            msleep(3000);
-        }
-        searching_file = 0;
-        kfree(search_update_path);
-        kfree(search_cfg_path);
-        
-        if(!got_file_flag)
-        {
-            GTP_ERROR("Can't find update file.");
-            goto load_failed;
-        }
-        
-        if(got_file_flag&0xF0)
-        {
-            GTP_DEBUG("Got the update config file.");
-            ret = gup_update_config(client);
-            if(ret <= 0)
-            {
-                GTP_ERROR("Update config failed.");
-            }
-            filp_close(update_msg.cfg_file, NULL);
-            msleep(500);                //waiting config to be stored in FLASH.
-        }
-        if(got_file_flag&0x0F)
-        {
-            GTP_DEBUG("Got the update firmware file.");
-        }
-        else
-        {
-            GTP_ERROR("No need to upgrade firmware.");
-            goto load_failed;
-        }
+		u8 fp_len = max(sizeof(UPDATE_FILE_PATH_1),
+						sizeof(UPDATE_FILE_PATH_2));
+		u8 cfp_len = max(sizeof(CONFIG_FILE_PATH_1),
+						sizeof(CONFIG_FILE_PATH_2));
+		u8 *search_update_path = kzalloc(fp_len, GFP_KERNEL);
+		u8 *search_cfg_path = kzalloc(cfp_len, GFP_KERNEL);
+		/* Begin to search update file,the config file & firmware
+			file must be in the same path,single or double. */
+		searching_file = 1;
+		for (i = 0; i < GUP_SEARCH_FILE_TIMES; i++) {
+			if (searching_file == 0) {
+				kfree(search_update_path);
+				kfree(search_cfg_path);
+				GTP_INFO(".bin/.cfg update file search " \
+						"forcely terminated!");
+				return FAIL;
+			}
+			if (i % 2) {
+				memcpy(search_update_path, UPDATE_FILE_PATH_1,
+						sizeof(UPDATE_FILE_PATH_1));
+				memcpy(search_cfg_path, CONFIG_FILE_PATH_1,
+						sizeof(CONFIG_FILE_PATH_1));
+			} else {
+				memcpy(search_update_path, UPDATE_FILE_PATH_2,
+						sizeof(UPDATE_FILE_PATH_2));
+				memcpy(search_cfg_path, CONFIG_FILE_PATH_2,
+						sizeof(CONFIG_FILE_PATH_2));
+			}
+
+			if (!(got_file_flag&0x0F)) {
+				update_msg.file = file_open(search_update_path,
+						O_RDONLY, 0);
+				if (!IS_ERR(update_msg.file)) {
+					GTP_DEBUG("Find the bin file");
+					got_file_flag |= 0x0F;
+				}
+			}
+			if (!(got_file_flag & 0xF0)) {
+				update_msg.cfg_file = file_open(search_cfg_path,
+						O_RDONLY, 0);
+				if (!IS_ERR(update_msg.cfg_file)) {
+					GTP_DEBUG("Find the cfg file");
+					got_file_flag |= 0xF0;
+				}
+			}
+
+			if (got_file_flag) {
+				if (got_file_flag == 0xFF)
+					break;
+				else
+					i += 4;
+			}
+			GTP_DEBUG("%3d:Searching %s %s file...", i,
+			(got_file_flag & 0x0F) ? "" : "bin",
+			(got_file_flag & 0xF0) ? "" : "cfg");
+
+			msleep(3000);
+		}
+
+		searching_file = 0;
+		kfree(search_update_path);
+		kfree(search_cfg_path);
+
+		if (!got_file_flag) {
+			GTP_ERROR("Can't find update file.");
+			goto load_failed;
+		}
+
+		if (got_file_flag & 0xF0) {
+			GTP_DEBUG("Got the update config file.");
+			ret = gup_update_config(client);
+			if (ret <= 0)
+				GTP_ERROR("Update config failed.");
+			filp_close(update_msg.cfg_file, NULL);
+			msleep(500); /* waiting config to be stored in FLASH. */
+		}
+		if (got_file_flag & 0x0F) {
+			GTP_DEBUG("Got the update firmware file.");
+		} else {
+			GTP_ERROR("No need to upgrade firmware.");
+			goto load_failed;
+		}
 #endif
-    }
-    
-    update_msg.old_fs = get_fs();
-    set_fs(KERNEL_DS);
+	}
 
-    update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
-    //update_msg.file->f_pos = 0;
+	update_msg.old_fs = get_fs();
+	set_fs(KERNEL_DS);
 
-    ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, FW_HEAD_LENGTH, &update_msg.file->f_pos);
-    if (ret < 0)
-    {
-        GTP_ERROR("Read firmware head in update file error.");
-        goto load_failed;
-    }
-    memcpy(fw_head, buf, FW_HEAD_LENGTH);
-    
-    //check firmware legality
-    fw_checksum = 0;
-    for(i=0; i<FW_SECTION_LENGTH*4+FW_DSP_ISP_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH; i+=2)
-    {
-        u16 temp;
-        ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, 2, &update_msg.file->f_pos);
-        if (ret < 0)
-        {
-            GTP_ERROR("Read firmware file error.");
-            goto load_failed;
-        }
-        //GTP_DEBUG("BUF[0]:%x", buf[0]);
-        temp = (buf[0]<<8) + buf[1];
-        fw_checksum += temp;
-    }
-    
-    GTP_DEBUG("firmware checksum:%x", fw_checksum&0xFFFF);
-    if(fw_checksum&0xFFFF)
-    {
-        GTP_ERROR("Illegal firmware file.");
-        goto load_failed;    
-    }
-    
-    return SUCCESS;
+	update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
+	/* update_msg.file->f_pos = 0; */
+
+	ret = update_msg.file->f_op->read(update_msg.file, (char *)buf,
+				FW_HEAD_LENGTH, &update_msg.file->f_pos);
+	if (ret < 0) {
+		GTP_ERROR("Read firmware head in update file error.");
+		goto load_failed;
+	}
+	memcpy(fw_head, buf, FW_HEAD_LENGTH);
+
+	/* check firmware legality */
+	fw_checksum = 0;
+	for (i = 0; i < FW_SECTION_LENGTH * 4 + FW_DSP_ISP_LENGTH +
+			FW_DSP_LENGTH + FW_BOOT_LENGTH; i + = 2) {
+		u16 temp;
+		ret = update_msg.file->f_op->read(update_msg.file, (char *)buf,
+						2, &update_msg.file->f_pos);
+		if (ret < 0) {
+			GTP_ERROR("Read firmware file error.");
+			goto load_failed;
+		}
+		/* GTP_DEBUG("BUF[0]:%x", buf[0]); */
+		temp = (buf[0]<<8) + buf[1];
+		fw_checksum += temp;
+	}
+
+	GTP_DEBUG("firmware checksum:%x", fw_checksum&0xFFFF);
+	if (fw_checksum & 0xFFFF) {
+		GTP_ERROR("Illegal firmware file.");
+		goto load_failed;
+	}
+
+	return SUCCESS;
 
 load_failed:
-    set_fs(update_msg.old_fs);
-    return FAIL;
+	set_fs(update_msg.old_fs);
+	return FAIL;
 }
 
 #if 0
-static u8 gup_check_update_header(struct i2c_client *client, st_fw_head* fw_head)
+static u8 gup_check_update_header(struct i2c_client *client,
+			st_fw_head *fw_head)
 {
-    const u8* pos;
-    int i = 0;
-    u8 mask_num = 0;
-    s32 ret = 0;
+	const u8 *pos;
+	int i = 0;
+	u8 mask_num = 0;
+	s32 ret = 0;
 
-    pos = HEADER_UPDATE_DATA;
-      
-    memcpy(fw_head, pos, FW_HEAD_LENGTH);
-    pos += FW_HEAD_LENGTH;
+	pos = HEADER_UPDATE_DATA;
 
-    ret = gup_enter_update_judge(fw_head);
-    if(SUCCESS == ret)
-    {
-        return SUCCESS;
-    }
-    return FAIL;
+	memcpy(fw_head, pos, FW_HEAD_LENGTH);
+	pos += FW_HEAD_LENGTH;
+
+	ret = gup_enter_update_judge(fw_head);
+	if (SUCCESS == ret)
+		return SUCCESS;
+	return FAIL;
 }
 #endif
 
-static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf, u16 start_addr, u16 total_length)
+static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf, u16 start_addr,
+							u16 total_length)
 {
-    s32 ret = 0;
-    u16 burn_addr = start_addr;
-    u16 frame_length = 0;
-    u16 burn_length = 0;
-    u8  wr_buf[PACK_SIZE + GTP_ADDR_LENGTH];
-    u8  rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
-    u8  retry = 0;
-    
-    GTP_DEBUG("Begin burn %dk data to addr 0x%x", (total_length/1024), start_addr);
-    while(burn_length < total_length)
-    {
-        GTP_DEBUG("B/T:%04d/%04d", burn_length, total_length);
-        frame_length = ((total_length - burn_length) > PACK_SIZE) ? PACK_SIZE : (total_length - burn_length);
-        wr_buf[0] = (u8)(burn_addr>>8);
-        rd_buf[0] = wr_buf[0];
-        wr_buf[1] = (u8)burn_addr;
-        rd_buf[1] = wr_buf[1];
-        memcpy(&wr_buf[GTP_ADDR_LENGTH], &burn_buf[burn_length], frame_length);
-        
-        for(retry = 0; retry < MAX_FRAME_CHECK_TIME; retry++)
-        {
-            ret = gup_i2c_write(client, wr_buf, GTP_ADDR_LENGTH + frame_length);
-            if(ret <= 0)
-            {
-                GTP_ERROR("Write frame data i2c error.");
-                continue;
-            }
-            ret = gup_i2c_read(client, rd_buf, GTP_ADDR_LENGTH + frame_length);
-            if(ret <= 0)
-            {
-                GTP_ERROR("Read back frame data i2c error.");
-                continue;
-            }
-            
-            if(memcmp(&wr_buf[GTP_ADDR_LENGTH], &rd_buf[GTP_ADDR_LENGTH], frame_length))
-            {
-                GTP_ERROR("Check frame data fail,not equal.");
-                GTP_DEBUG("write array:");
-                GTP_DEBUG_ARRAY(&wr_buf[GTP_ADDR_LENGTH], frame_length);
-                GTP_DEBUG("read array:");
-                GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length);
-                continue;
-            }
-            else
-            {
-                //GTP_DEBUG("Check frame data success.");
-                break;
-            }
-        }
-        if(retry >= MAX_FRAME_CHECK_TIME)
-        {
-            GTP_ERROR("Burn frame data time out,exit.");
-            return FAIL;
-        }
-        burn_length += frame_length;
-        burn_addr += frame_length;
-    }
-    return SUCCESS;
+	s32 ret = 0;
+	u16 burn_addr = start_addr;
+	u16 frame_length = 0;
+	u16 burn_length = 0;
+	u8  wr_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+	u8  rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+	u8  retry = 0;
+
+	GTP_DEBUG("Begin burn %dk data to addr 0x%x", (total_length/1024),
+								start_addr);
+	while (burn_length < total_length) {
+		GTP_DEBUG("B/T:%04d/%04d", burn_length, total_length);
+		frame_length = ((total_length - burn_length) > PACK_SIZE)
+				? PACK_SIZE : (total_length - burn_length);
+		wr_buf[0] = (u8)(burn_addr>>8);
+		rd_buf[0] = wr_buf[0];
+		wr_buf[1] = (u8)burn_addr;
+		rd_buf[1] = wr_buf[1];
+		memcpy(&wr_buf[GTP_ADDR_LENGTH], &burn_buf[burn_length],
+								frame_length);
+
+		for (retry = 0; retry < MAX_FRAME_CHECK_TIME; retry++) {
+			ret = gup_i2c_write(client, wr_buf,
+					GTP_ADDR_LENGTH + frame_length);
+			if (ret <= 0) {
+				GTP_ERROR("Write frame data i2c error.");
+				continue;
+			}
+			ret = gup_i2c_read(client, rd_buf, GTP_ADDR_LENGTH +
+							frame_length);
+			if (ret <= 0) {
+				GTP_ERROR("Read back frame data i2c error.");
+				continue;
+			}
+
+			if (memcmp(&wr_buf[GTP_ADDR_LENGTH],
+				&rd_buf[GTP_ADDR_LENGTH], frame_length)) {
+				GTP_ERROR("Check frame data fail,not equal.");
+				GTP_DEBUG("write array:");
+				GTP_DEBUG_ARRAY(&wr_buf[GTP_ADDR_LENGTH],
+								frame_length);
+				GTP_DEBUG("read array:");
+				GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH],
+								frame_length);
+				continue;
+			} else {
+				/* GTP_DEBUG("Check frame data success."); */
+				break;
+			}
+		}
+		if (retry >= MAX_FRAME_CHECK_TIME) {
+			GTP_ERROR("Burn frame data time out,exit.");
+			return FAIL;
+		}
+		burn_length += frame_length;
+		burn_addr += frame_length;
+	}
+	return SUCCESS;
 }
 
-static u8 gup_load_section_file(u8* buf, u16 offset, u16 length)
+static u8 gup_load_section_file(u8 *buf, u16 offset, u16 length)
 {
-    s32 ret = 0;
-    
-    if(update_msg.file == NULL)
-    {
-        GTP_ERROR("cannot find update file,load section file fail.");
-        return FAIL;
-    }
-    update_msg.file->f_pos = FW_HEAD_LENGTH + offset;
-    
-    ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, length, &update_msg.file->f_pos);
-    if(ret < 0)
-    {
-        GTP_ERROR("Read update file fail.");
-        return FAIL;
-    }
-    
-    return SUCCESS;
+	s32 ret = 0;
+
+	if (update_msg.file == NULL) {
+		GTP_ERROR("cannot find update file,load section file fail.");
+		return FAIL;
+	}
+	update_msg.file->f_pos = FW_HEAD_LENGTH + offset;
+
+	ret = update_msg.file->f_op->read(update_msg.file, (char *)buf, length,
+						&update_msg.file->f_pos);
+	if (ret < 0) {
+		GTP_ERROR("Read update file fail.");
+		return FAIL;
+	}
+
+	return SUCCESS;
 }
 
-static u8 gup_recall_check(struct i2c_client *client, u8* chk_src, u16 start_rd_addr, u16 chk_length)
+static u8 gup_recall_check(struct i2c_client *client, u8 *chk_src,
+					u16 start_rd_addr, u16 chk_length)
 {
-    u8  rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
-    s32 ret = 0;
-    u16 recall_addr = start_rd_addr;
-    u16 recall_length = 0;
-    u16 frame_length = 0;
+	u8  rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+	s32 ret = 0;
+	u16 recall_addr = start_rd_addr;
+	u16 recall_length = 0;
+	u16 frame_length = 0;
 
-    while(recall_length < chk_length)
-    {
-        frame_length = ((chk_length - recall_length) > PACK_SIZE) ? PACK_SIZE : (chk_length - recall_length);
-        ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length);
-        if(ret <= 0)
-        {
-            GTP_ERROR("recall i2c error,exit");
-            return FAIL;
-        }
-        
-        if(memcmp(&rd_buf[GTP_ADDR_LENGTH], &chk_src[recall_length], frame_length))
-        {
-            GTP_ERROR("Recall frame data fail,not equal.");
-            GTP_DEBUG("chk_src array:");
-            GTP_DEBUG_ARRAY(&chk_src[recall_length], frame_length);
-            GTP_DEBUG("recall array:");
-            GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length);
-            return FAIL;
-        }
-        
-        recall_length += frame_length;
-        recall_addr += frame_length;
-    }
-    GTP_DEBUG("Recall check %dk firmware success.", (chk_length/1024));
-    
-    return SUCCESS;
+	while (recall_length < chk_length) {
+		frame_length = ((chk_length - recall_length) > PACK_SIZE)
+				? PACK_SIZE : (chk_length - recall_length);
+		ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length);
+		if (ret <= 0) {
+			GTP_ERROR("recall i2c error,exit");
+			return FAIL;
+		}
+
+		if (memcmp(&rd_buf[GTP_ADDR_LENGTH], &chk_src[recall_length],
+			frame_length)) {
+			GTP_ERROR("Recall frame data fail,not equal.");
+			GTP_DEBUG("chk_src array:");
+			GTP_DEBUG_ARRAY(&chk_src[recall_length], frame_length);
+			GTP_DEBUG("recall array:");
+			GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length);
+			return FAIL;
+		}
+
+		recall_length += frame_length;
+		recall_addr += frame_length;
+	}
+	GTP_DEBUG("Recall check %dk firmware success.", (chk_length/1024));
+
+	return SUCCESS;
 }
 
-static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section, u16 start_addr, u8 bank_cmd )
+static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section,
+					u16 start_addr, u8 bank_cmdi)
 {
-    s32 ret = 0;
-    u8  rd_buf[5];
-  
-    //step1:hold ss51 & dsp
-    ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_section]hold ss51 & dsp fail.");
-        return FAIL;
-    }
-    
-    //step2:set scramble
-    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_section]set scramble fail.");
-        return FAIL;
-    }
-    
-    //step3:select bank
-    ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_section]select bank %d fail.", (bank_cmd >> 4)&0x0F);
-        return FAIL;
-    }
-    
-    //step4:enable accessing code
-    ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_section]enable accessing code fail.");
-        return FAIL;
-    }
-    
-    //step5:burn 8k fw section
-    ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[burn_fw_section]burn fw_section fail.");
-        return FAIL;
-    }
-    
-    //step6:hold ss51 & release dsp
-    ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_section]hold ss51 & release dsp fail.");
-        return FAIL;
-    }
-    //must delay
-    msleep(1);
-    
-    //step7:send burn cmd to move data to flash from sram
-    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_section]send burn cmd fail.");
-        return FAIL;
-    }
-    GTP_DEBUG("[burn_fw_section]Wait for the burn is complete......");
-    do{
-        ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
-        if(ret <= 0)
-        {
-            GTP_ERROR("[burn_fw_section]Get burn state fail");
-            return FAIL;
-        }
-        msleep(10);
-        //GTP_DEBUG("[burn_fw_section]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]);
-    }while(rd_buf[GTP_ADDR_LENGTH]);
+	s32 ret = 0;
+	u8  rd_buf[5];
 
-    //step8:select bank
-    ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_section]select bank %d fail.", (bank_cmd >> 4)&0x0F);
-        return FAIL;
-    }
-    
-    //step9:enable accessing code
-    ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_section]enable accessing code fail.");
-        return FAIL;
-    }
-    
-    //step10:recall 8k fw section
-    ret = gup_recall_check(client, fw_section, start_addr, FW_SECTION_LENGTH);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[burn_fw_section]recall check 8k firmware fail.");
-        return FAIL;
-    }
-    
-    //step11:disable accessing code
-    ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_section]disable accessing code fail.");
-        return FAIL;
-    }
-    
-    return SUCCESS;
+	/* step1:hold ss51 & dsp */
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_section]hold ss51 & dsp fail.");
+		return FAIL;
+	}
+
+	 /* step2:set scramble */
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_section]set scramble fail.");
+		return FAIL;
+	}
+
+	/* step3:select bank */
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK,
+						(bank_cmd >> 4)&0x0F);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_section]select bank %d fail.",
+					(bank_cmd >> 4)&0x0F);
+		return FAIL;
+	}
+
+	/* step4:enable accessing code */
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_section]enable accessing code fail.");
+		return FAIL;
+	}
+
+	/* step5:burn 8k fw section */
+	ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH);
+	if (ret == FAIL)  {
+		GTP_ERROR("[burn_fw_section]burn fw_section fail.");
+		return FAIL;
+	}
+
+	/* step6:hold ss51 & release dsp */
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_section]hold ss51 & release dsp fail.");
+		return FAIL;
+	}
+	/* must delay */
+	msleep(20);
+
+	/* step7:send burn cmd to move data to flash from sram */
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_section]send burn cmd fail.");
+		return FAIL;
+	}
+	GTP_DEBUG("[burn_fw_section]Wait for the burn is complete......");
+	do {
+		ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+		if (ret <= 0) {
+			GTP_ERROR("[burn_fw_section]Get burn state fail");
+			return FAIL;
+		}
+		msleep(20);
+		/* GTP_DEBUG("[burn_fw_section]Get burn state:%d.",
+						rd_buf[GTP_ADDR_LENGTH]); */
+	} while (rd_buf[GTP_ADDR_LENGTH]);
+
+	/* step8:select bank */
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK,
+							(bank_cmd >> 4)&0x0F);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_section]select bank %d fail.",
+							(bank_cmd >> 4)&0x0F);
+		return FAIL;
+	}
+
+	/* step9:enable accessing code */
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_section]enable accessing code fail.");
+		return FAIL;
+	}
+
+	/* step10:recall 8k fw section */
+	ret = gup_recall_check(client, fw_section, start_addr,
+							FW_SECTION_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_section]recall check 8k firmware fail.");
+		return FAIL;
+	}
+
+	/* step11:disable accessing code */
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_section]disable accessing code fail.");
+		return FAIL;
+	}
+
+	return SUCCESS;
 }
 
 static u8 gup_burn_dsp_isp(struct i2c_client *client)
 {
-    s32 ret = 0;
-    u8* fw_dsp_isp = NULL;
-    u8  retry = 0;
-    
-    GTP_DEBUG("[burn_dsp_isp]Begin burn dsp isp---->>");
-    
-    //step1:alloc memory
-    GTP_DEBUG("[burn_dsp_isp]step1:alloc memory");
-    while(retry++ < 5)
-    {
-        fw_dsp_isp = (u8*)kzalloc(FW_DSP_ISP_LENGTH, GFP_KERNEL);
-        if(fw_dsp_isp == NULL)
-        {
-            continue;
-        }
-        else
-        {
-            GTP_INFO("[burn_dsp_isp]Alloc %dk byte memory success.", (FW_DSP_ISP_LENGTH/1024));
-            break;
-        }
-    }
-    if(retry >= 5)
-    {
-        GTP_ERROR("[burn_dsp_isp]Alloc memory fail,exit.");
-        return FAIL;
-    }
-    
-    //step2:load dsp isp file data
-    GTP_DEBUG("[burn_dsp_isp]step2:load dsp isp file data");
-    ret = gup_load_section_file(fw_dsp_isp, (4*FW_SECTION_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH), FW_DSP_ISP_LENGTH);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[burn_dsp_isp]load firmware dsp_isp fail.");
-        goto exit_burn_dsp_isp;
-    }
-    
-    //step3:disable wdt,clear cache enable
-    GTP_DEBUG("[burn_dsp_isp]step3:disable wdt,clear cache enable");
-    ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_dsp_isp]disable wdt fail.");
-        ret = FAIL;
-        goto exit_burn_dsp_isp;
-    }
-    ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_dsp_isp]clear cache enable fail.");
-        ret = FAIL;
-        goto exit_burn_dsp_isp;
-    }
-    
-    //step4:hold ss51 & dsp
-    GTP_DEBUG("[burn_dsp_isp]step4:hold ss51 & dsp");
-    ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_dsp_isp]hold ss51 & dsp fail.");
-        ret = FAIL;
-        goto exit_burn_dsp_isp;
-    }
-    
-    //step5:set boot from sram
-    GTP_DEBUG("[burn_dsp_isp]step5:set boot from sram");
-    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_dsp_isp]set boot from sram fail.");
-        ret = FAIL;
-        goto exit_burn_dsp_isp;
-    }
-    
-    //step6:software reboot
-    GTP_DEBUG("[burn_dsp_isp]step6:software reboot");
-    ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_dsp_isp]software reboot fail.");
-        ret = FAIL;
-        goto exit_burn_dsp_isp;
-    }
-    
-    //step7:select bank2
-    GTP_DEBUG("[burn_dsp_isp]step7:select bank2");
-    ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_dsp_isp]select bank2 fail.");
-        ret = FAIL;
-        goto exit_burn_dsp_isp;
-    }
-    
-    //step8:enable accessing code
-    GTP_DEBUG("[burn_dsp_isp]step8:enable accessing code");
-    ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_dsp_isp]enable accessing code fail.");
-        ret = FAIL;
-        goto exit_burn_dsp_isp;
-    }
-    
-    //step9:burn 4k dsp_isp
-    GTP_DEBUG("[burn_dsp_isp]step9:burn 4k dsp_isp");
-    ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[burn_dsp_isp]burn dsp_isp fail.");
-        goto exit_burn_dsp_isp;
-    }
-    
-    //step10:set scramble
-    GTP_DEBUG("[burn_dsp_isp]step10:set scramble");
-    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_dsp_isp]set scramble fail.");
-        ret = FAIL;
-        goto exit_burn_dsp_isp;
-    }
-    ret = SUCCESS;
+	s32 ret = 0;
+	u8 *fw_dsp_isp = NULL;
+	u8  retry = 0;
+
+	GTP_DEBUG("[burn_dsp_isp]Begin burn dsp isp---->>");
+
+	/* step1:alloc memory */
+	GTP_DEBUG("[burn_dsp_isp]step1:alloc memory");
+	while (retry++ < 5) {
+		fw_dsp_isp = kzalloc(FW_DSP_ISP_LENGTH, GFP_KERNEL);
+		if (fw_dsp_isp == NULL) {
+			continue;
+		} else {
+			GTP_INFO("[burn_dsp_isp]Alloc %dk byte memory success.",
+					(FW_DSP_ISP_LENGTH/1024));
+			break;
+		}
+	}
+	if (retry >= 5) {
+		GTP_ERROR("[burn_dsp_isp]Alloc memory fail,exit.");
+		return FAIL;
+	}
+
+	/* step2:load dsp isp file data */
+	GTP_DEBUG("[burn_dsp_isp]step2:load dsp isp file data");
+	ret = gup_load_section_file(fw_dsp_isp, (4 * FW_SECTION_LENGTH +
+		FW_DSP_LENGTH + FW_BOOT_LENGTH), FW_DSP_ISP_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_dsp_isp]load firmware dsp_isp fail.");
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step3:disable wdt,clear cache enable */
+	GTP_DEBUG("[burn_dsp_isp]step3:disable wdt,clear cache enable");
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_dsp_isp]disable wdt fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_dsp_isp]clear cache enable fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step4:hold ss51 & dsp */
+	GTP_DEBUG("[burn_dsp_isp]step4:hold ss51 & dsp");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_dsp_isp]hold ss51 & dsp fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step5:set boot from sram */
+	GTP_DEBUG("[burn_dsp_isp]step5:set boot from sram");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_dsp_isp]set boot from sram fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step6:software reboot */
+	GTP_DEBUG("[burn_dsp_isp]step6:software reboot");
+	ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_dsp_isp]software reboot fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step7:select bank2 */
+	GTP_DEBUG("[burn_dsp_isp]step7:select bank2");
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_dsp_isp]select bank2 fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step8:enable accessing code */
+	GTP_DEBUG("[burn_dsp_isp]step8:enable accessing code");
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_dsp_isp]enable accessing code fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step9:burn 4k dsp_isp */
+	GTP_DEBUG("[burn_dsp_isp]step9:burn 4k dsp_isp");
+	ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_dsp_isp]burn dsp_isp fail.");
+		goto exit_burn_dsp_isp;
+	}
+
+	/* step10:set scramble */
+	GTP_DEBUG("[burn_dsp_isp]step10:set scramble");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_dsp_isp]set scramble fail.");
+		ret = FAIL;
+		goto exit_burn_dsp_isp;
+	}
+	ret = SUCCESS;
 
 exit_burn_dsp_isp:
-    kfree(fw_dsp_isp);
-    return ret;
+	kfree(fw_dsp_isp);
+	return ret;
 }
 
 static u8 gup_burn_fw_ss51(struct i2c_client *client)
 {
-    u8* fw_ss51 = NULL;
-    u8  retry = 0;
-    s32 ret = 0;
-    
-    GTP_DEBUG("[burn_fw_ss51]Begin burn ss51 firmware---->>");
-    
-    //step1:alloc memory
-    GTP_DEBUG("[burn_fw_ss51]step1:alloc memory");
-    while(retry++ < 5)
-    {
-        fw_ss51 = (u8*)kzalloc(FW_SECTION_LENGTH, GFP_KERNEL);
-        if(fw_ss51 == NULL)
-        {
-            continue;
-        }
-        else
-        {
-            GTP_INFO("[burn_fw_ss51]Alloc %dk byte memory success.", (FW_SECTION_LENGTH/1024));
-            break;
-        }
-    }
-    if(retry >= 5)
-    {
-        GTP_ERROR("[burn_fw_ss51]Alloc memory fail,exit.");
-        return FAIL;
-    }
-    
-    //step2:load ss51 firmware section 1 file data
-    GTP_DEBUG("[burn_fw_ss51]step2:load ss51 firmware section 1 file data");
-    ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 1 fail.");
-        goto exit_burn_fw_ss51;
-    }
-    
-    //step3:clear control flag
-    GTP_DEBUG("[burn_fw_ss51]step3:clear control flag");
-    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_ss51]clear control flag fail.");
-        ret = FAIL;
-        goto exit_burn_fw_ss51;
-    }
-    
-    //step4:burn ss51 firmware section 1
-    GTP_DEBUG("[burn_fw_ss51]step4:burn ss51 firmware section 1");
-    ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 1 fail.");
-        goto exit_burn_fw_ss51;
-    }
-    
-    //step5:load ss51 firmware section 2 file data
-    GTP_DEBUG("[burn_fw_ss51]step5:load ss51 firmware section 2 file data");
-    ret = gup_load_section_file(fw_ss51, FW_SECTION_LENGTH, FW_SECTION_LENGTH);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 2 fail.");
-        goto exit_burn_fw_ss51;
-    }
-    
-    //step6:burn ss51 firmware section 2
-    GTP_DEBUG("[burn_fw_ss51]step6:burn ss51 firmware section 2");
-    ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 2 fail.");
-        goto exit_burn_fw_ss51;
-    }
-    
-    //step7:load ss51 firmware section 3 file data
-    GTP_DEBUG("[burn_fw_ss51]step7:load ss51 firmware section 3 file data");
-    ret = gup_load_section_file(fw_ss51, 2*FW_SECTION_LENGTH, FW_SECTION_LENGTH);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 3 fail.");
-        goto exit_burn_fw_ss51;
-    }
-    
-    //step8:burn ss51 firmware section 3
-    GTP_DEBUG("[burn_fw_ss51]step8:burn ss51 firmware section 3");
-    ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 3 fail.");
-        goto exit_burn_fw_ss51;
-    }
-    
-    //step9:load ss51 firmware section 4 file data
-    GTP_DEBUG("[burn_fw_ss51]step9:load ss51 firmware section 4 file data");
-    ret = gup_load_section_file(fw_ss51, 3*FW_SECTION_LENGTH, FW_SECTION_LENGTH);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 4 fail.");
-        goto exit_burn_fw_ss51;
-    }
-    
-    //step10:burn ss51 firmware section 4
-    GTP_DEBUG("[burn_fw_ss51]step10:burn ss51 firmware section 4");
-    ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 4 fail.");
-        goto exit_burn_fw_ss51;
-    }
-    
-    ret = SUCCESS;
-    
+	u8 *fw_ss51 = NULL;
+	u8  retry = 0;
+	s32 ret = 0;
+
+	GTP_DEBUG("[burn_fw_ss51]Begin burn ss51 firmware---->>");
+
+	/* step1:alloc memory */
+	GTP_DEBUG("[burn_fw_ss51]step1:alloc memory");
+	while (retry++ < 5) {
+		fw_ss51 = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL);
+		if (fw_ss51 == NULL) {
+			continue;
+		} else {
+			GTP_INFO("[burn_fw_ss51]Alloc %dk byte memory success.",
+						(FW_SECTION_LENGTH/1024));
+			break;
+		}
+	}
+	if (retry >= 5) {
+		GTP_ERROR("[burn_fw_ss51]Alloc memory fail,exit.");
+		return FAIL;
+	}
+
+	/* step2:load ss51 firmware section 1 file data */
+	GTP_DEBUG("[burn_fw_ss51]step2:load ss51 firmware section 1 file data");
+	ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 1 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step3:clear control flag */
+	GTP_DEBUG("[burn_fw_ss51]step3:clear control flag");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_ss51]clear control flag fail.");
+		ret = FAIL;
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step4:burn ss51 firmware section 1 */
+	GTP_DEBUG("[burn_fw_ss51]step4:burn ss51 firmware section 1");
+	ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 1 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step5:load ss51 firmware section 2 file data */
+	GTP_DEBUG("[burn_fw_ss51]step5:load ss51 firmware section 2 file data");
+	ret = gup_load_section_file(fw_ss51, FW_SECTION_LENGTH,
+							FW_SECTION_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 2 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step6:burn ss51 firmware section 2 */
+	GTP_DEBUG("[burn_fw_ss51]step6:burn ss51 firmware section 2");
+	ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 2 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step7:load ss51 firmware section 3 file data */
+	GTP_DEBUG("[burn_fw_ss51]step7:load ss51 firmware section 3 file data");
+	ret = gup_load_section_file(fw_ss51, 2*FW_SECTION_LENGTH,
+							FW_SECTION_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 3 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step8:burn ss51 firmware section 3 */
+	GTP_DEBUG("[burn_fw_ss51]step8:burn ss51 firmware section 3");
+	ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 3 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step9:load ss51 firmware section 4 file data */
+	GTP_DEBUG("[burn_fw_ss51]step9:load ss51 firmware section 4 file data");
+	ret = gup_load_section_file(fw_ss51, 3*FW_SECTION_LENGTH,
+							FW_SECTION_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 4 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	/* step10:burn ss51 firmware section 4 */
+	GTP_DEBUG("[burn_fw_ss51]step10:burn ss51 firmware section 4");
+	ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 4 fail.");
+		goto exit_burn_fw_ss51;
+	}
+
+	ret = SUCCESS;
+
 exit_burn_fw_ss51:
-    kfree(fw_ss51);
-    return ret;
+	kfree(fw_ss51);
+	return ret;
 }
 
 static u8 gup_burn_fw_dsp(struct i2c_client *client)
 {
-    s32 ret = 0;
-    u8* fw_dsp = NULL;
-    u8  retry = 0;
-    u8  rd_buf[5];
-    
-    GTP_DEBUG("[burn_fw_dsp]Begin burn dsp firmware---->>");
-    //step1:alloc memory
-    GTP_DEBUG("[burn_fw_dsp]step1:alloc memory");
-    while(retry++ < 5)
-    {
-        fw_dsp = (u8*)kzalloc(FW_DSP_LENGTH, GFP_KERNEL);
-        if(fw_dsp == NULL)
-        {
-            continue;
-        }
-        else
-        {
-            GTP_INFO("[burn_fw_dsp]Alloc %dk byte memory success.", (FW_SECTION_LENGTH/1024));
-            break;
-        }
-    }
-    if(retry >= 5)
-    {
-        GTP_ERROR("[burn_fw_dsp]Alloc memory fail,exit.");
-        return FAIL;
-    }
-    
-    //step2:load firmware dsp
-    GTP_DEBUG("[burn_fw_dsp]step2:load firmware dsp");
-    ret = gup_load_section_file(fw_dsp, 4*FW_SECTION_LENGTH, FW_DSP_LENGTH);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[burn_fw_dsp]load firmware dsp fail.");
-        goto exit_burn_fw_dsp;
-    }
-    
-    //step3:select bank3
-    GTP_DEBUG("[burn_fw_dsp]step3:select bank3");
-    ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_dsp]select bank3 fail.");
-        ret = FAIL;
-        goto exit_burn_fw_dsp;
-    }
-    
-    //step4:hold ss51 & dsp
-    GTP_DEBUG("[burn_fw_dsp]step4:hold ss51 & dsp");
-    ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_dsp]hold ss51 & dsp fail.");
-        ret = FAIL;
-        goto exit_burn_fw_dsp;
-    }
-    
-    //step5:set scramble
-    GTP_DEBUG("[burn_fw_dsp]step5:set scramble");
-    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_dsp]set scramble fail.");
-        ret = FAIL;
-        goto exit_burn_fw_dsp;
-    }
-    
-    //step6:release ss51 & dsp
-    GTP_DEBUG("[burn_fw_dsp]step6:release ss51 & dsp");
-    ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);                 //20121211
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_dsp]release ss51 & dsp fail.");
-        ret = FAIL;
-        goto exit_burn_fw_dsp;
-    }
-    //must delay
-    msleep(1);
-    
-    //step7:burn 4k dsp firmware
-    GTP_DEBUG("[burn_fw_dsp]step7:burn 4k dsp firmware");
-    ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[burn_fw_dsp]burn fw_section fail.");
-        goto exit_burn_fw_dsp;
-    }
-    
-    //step8:send burn cmd to move data to flash from sram
-    GTP_DEBUG("[burn_fw_dsp]step8:send burn cmd to move data to flash from sram");
-    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_dsp]send burn cmd fail.");
-        goto exit_burn_fw_dsp;
-    }
-    GTP_DEBUG("[burn_fw_dsp]Wait for the burn is complete......");
-    do{
-        ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
-        if(ret <= 0)
-        {
-            GTP_ERROR("[burn_fw_dsp]Get burn state fail");
-            goto exit_burn_fw_dsp;
-        }
-        msleep(10);
-        //GTP_DEBUG("[burn_fw_dsp]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]);
-    }while(rd_buf[GTP_ADDR_LENGTH]);
-    
-    //step9:recall check 4k dsp firmware
-    GTP_DEBUG("[burn_fw_dsp]step9:recall check 4k dsp firmware");
-    ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[burn_fw_dsp]recall check 4k dsp firmware fail.");
-        goto exit_burn_fw_dsp;
-    }
-    
-    ret = SUCCESS;
-    
+	s32 ret = 0;
+	u8 *fw_dsp = NULL;
+	u8  retry = 0;
+	u8  rd_buf[5];
+
+	GTP_DEBUG("[burn_fw_dsp]Begin burn dsp firmware---->>");
+	/* step1:alloc memory */
+	GTP_DEBUG("[burn_fw_dsp]step1:alloc memory");
+	while (retry++ < 5) {
+		fw_dsp = kzalloc(FW_DSP_LENGTH, GFP_KERNEL);
+		if (fw_dsp == NULL) {
+			continue;
+		} else  {
+			GTP_INFO("[burn_fw_dsp]Alloc %dk byte memory success.",
+					(FW_SECTION_LENGTH/1024));
+			break;
+		}
+	}
+	if (retry >= 5) {
+		GTP_ERROR("[burn_fw_dsp]Alloc memory fail,exit.");
+		return FAIL;
+	}
+
+	/* step2:load firmware dsp */
+	GTP_DEBUG("[burn_fw_dsp]step2:load firmware dsp");
+	ret = gup_load_section_file(fw_dsp, 4*FW_SECTION_LENGTH, FW_DSP_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_dsp]load firmware dsp fail.");
+		goto exit_burn_fw_dsp;
+	}
+
+	/* step3:select bank3 */
+	GTP_DEBUG("[burn_fw_dsp]step3:select bank3");
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_dsp]select bank3 fail.");
+		ret = FAIL;
+		goto exit_burn_fw_dsp;
+	}
+
+	/* Step4:hold ss51 & dsp */
+	GTP_DEBUG("[burn_fw_dsp]step4:hold ss51 & dsp");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_dsp]hold ss51 & dsp fail.");
+		ret = FAIL;
+		goto exit_burn_fw_dsp;
+	}
+
+	/* step5:set scramble */
+	GTP_DEBUG("[burn_fw_dsp]step5:set scramble");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_dsp]set scramble fail.");
+		ret = FAIL;
+		goto exit_burn_fw_dsp;
+	}
+
+	/* step6:release ss51 & dsp */
+	GTP_DEBUG("[burn_fw_dsp]step6:release ss51 & dsp");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_dsp]release ss51 & dsp fail.");
+		ret = FAIL;
+		goto exit_burn_fw_dsp;
+	}
+	/* must delay */
+	msleep(20);
+
+	/* step7:burn 4k dsp firmware */
+	GTP_DEBUG("[burn_fw_dsp]step7:burn 4k dsp firmware");
+	ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
+	if (FAIL == ret) {
+		GTP_ERROR("[burn_fw_dsp]burn fw_section fail.");
+		goto exit_burn_fw_dsp;
+	}
+
+	/* step8:send burn cmd to move data to flash from sram */
+	GTP_DEBUG("[burn_fw_dsp]step8:send burn cmd to move data to flash" \
+						"from sram");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_dsp]send burn cmd fail.");
+		goto exit_burn_fw_dsp;
+	}
+	GTP_DEBUG("[burn_fw_dsp]Wait for the burn is complete......");
+	do {
+		ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+		if (ret <= 0) {
+			GTP_ERROR("[burn_fw_dsp]Get burn state fail");
+			goto exit_burn_fw_dsp;
+		}
+		msleep(20);
+		/* GTP_DEBUG("[burn_fw_dsp]Get burn state:%d.",
+						rd_buf[GTP_ADDR_LENGTH]); */
+	} while (rd_buf[GTP_ADDR_LENGTH]);
+
+	/* step9:recall check 4k dsp firmware */
+	GTP_DEBUG("[burn_fw_dsp]step9:recall check 4k dsp firmware");
+	ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_dsp]recall check 4k dsp firmware fail.");
+		goto exit_burn_fw_dsp;
+	}
+
+	ret = SUCCESS;
+
 exit_burn_fw_dsp:
-    kfree(fw_dsp);
-    return ret;
+	kfree(fw_dsp);
+	return ret;
 }
 
 static u8 gup_burn_fw_boot(struct i2c_client *client)
 {
-    s32 ret = 0;
-    u8* fw_boot = NULL;
-    u8  retry = 0;
-    u8  rd_buf[5];
-    
-    GTP_DEBUG("[burn_fw_boot]Begin burn bootloader firmware---->>");
-    
-    //step1:Alloc memory
-    GTP_DEBUG("[burn_fw_boot]step1:Alloc memory");
-    while(retry++ < 5)
-    {
-        fw_boot = (u8*)kzalloc(FW_BOOT_LENGTH, GFP_KERNEL);
-        if(fw_boot == NULL)
-        {
-            continue;
-        }
-        else
-        {
-            GTP_INFO("[burn_fw_boot]Alloc %dk byte memory success.", (FW_BOOT_LENGTH/1024));
-            break;
-        }
-    }
-    if(retry >= 5)
-    {
-        GTP_ERROR("[burn_fw_boot]Alloc memory fail,exit.");
-        return FAIL;
-    }
-    
-    //step2:load firmware bootloader
-    GTP_DEBUG("[burn_fw_boot]step2:load firmware bootloader");
-    ret = gup_load_section_file(fw_boot, (4*FW_SECTION_LENGTH+FW_DSP_LENGTH), FW_BOOT_LENGTH);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[burn_fw_boot]load firmware dsp fail.");
-        goto exit_burn_fw_boot;
-    }
-    
-    //step3:hold ss51 & dsp
-    GTP_DEBUG("[burn_fw_boot]step3:hold ss51 & dsp");
-    ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_boot]hold ss51 & dsp fail.");
-        ret = FAIL;
-        goto exit_burn_fw_boot;
-    }
-    
-    //step4:set scramble
-    GTP_DEBUG("[burn_fw_boot]step4:set scramble");
-    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_boot]set scramble fail.");
-        ret = FAIL;
-        goto exit_burn_fw_boot;
-    }
-    
-    //step5:release ss51 & dsp
-    GTP_DEBUG("[burn_fw_boot]step5:release ss51 & dsp");
-    ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);                 //20121211
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_boot]release ss51 & dsp fail.");
-        ret = FAIL;
-        goto exit_burn_fw_boot;
-    }
-    //must delay
-    msleep(1);
-    
-    //step6:select bank3
-    GTP_DEBUG("[burn_fw_boot]step6:select bank3");
-    ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_boot]select bank3 fail.");
-        ret = FAIL;
-        goto exit_burn_fw_boot;
-    }
-    
-    //step7:burn 2k bootloader firmware
-    GTP_DEBUG("[burn_fw_boot]step7:burn 2k bootloader firmware");
-    ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[burn_fw_boot]burn fw_section fail.");
-        goto exit_burn_fw_boot;
-    }
-    
-    //step7:send burn cmd to move data to flash from sram
-    GTP_DEBUG("[burn_fw_boot]step7:send burn cmd to move data to flash from sram");
-    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_boot]send burn cmd fail.");
-        goto exit_burn_fw_boot;
-    }
-    GTP_DEBUG("[burn_fw_boot]Wait for the burn is complete......");
-    do{
-        ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
-        if(ret <= 0)
-        {
-            GTP_ERROR("[burn_fw_boot]Get burn state fail");
-            goto exit_burn_fw_boot;
-        }
-        msleep(10);
-        //GTP_DEBUG("[burn_fw_boot]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]);
-    }while(rd_buf[GTP_ADDR_LENGTH]);
-    
-    //step8:recall check 2k bootloader firmware
-    GTP_DEBUG("[burn_fw_boot]step8:recall check 2k bootloader firmware");
-    ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[burn_fw_boot]recall check 4k dsp firmware fail.");
-        goto exit_burn_fw_boot;
-    }
-    
-    //step9:enable download DSP code 
-    GTP_DEBUG("[burn_fw_boot]step9:enable download DSP code ");
-    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_boot]enable download DSP code fail.");
-        ret = FAIL;
-        goto exit_burn_fw_boot;
-    }
-    
-    //step10:release ss51 & hold dsp
-    GTP_DEBUG("[burn_fw_boot]step10:release ss51 & hold dsp");
-    ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08);
-    if(ret <= 0)
-    {
-        GTP_ERROR("[burn_fw_boot]release ss51 & hold dsp fail.");
-        ret = FAIL;
-        goto exit_burn_fw_boot;
-    }
-    
-    ret = SUCCESS;
-    
+	s32 ret = 0;
+	u8 *fw_boot = NULL;
+	u8  retry = 0;
+	u8  rd_buf[5];
+
+	GTP_DEBUG("[burn_fw_boot]Begin burn bootloader firmware---->>");
+
+	/* step1:Alloc memory */
+	GTP_DEBUG("[burn_fw_boot]step1:Alloc memory");
+	while (retry++ < 5) {
+		fw_boot = kzalloc(FW_BOOT_LENGTH, GFP_KERNEL);
+		if (fw_boot == NULL) {
+			continue;
+		} else {
+			GTP_INFO("[burn_fw_boot]Alloc %dk byte memory success.",
+						(FW_BOOT_LENGTH/1024));
+			break;
+		}
+	}
+	if (retry >= 5) {
+		GTP_ERROR("[burn_fw_boot]Alloc memory fail,exit.");
+		return FAIL;
+	}
+
+	/* step2:load firmware bootloader */
+	GTP_DEBUG("[burn_fw_boot]step2:load firmware bootloader");
+	ret = gup_load_section_file(fw_boot, (4 * FW_SECTION_LENGTH +
+				FW_DSP_LENGTH), FW_BOOT_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_boot]load firmware dsp fail.");
+		goto exit_burn_fw_boot;
+	}
+
+	/* step3:hold ss51 & dsp */
+	GTP_DEBUG("[burn_fw_boot]step3:hold ss51 & dsp");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_boot]hold ss51 & dsp fail.");
+		ret = FAIL;
+		goto exit_burn_fw_boot;
+	}
+
+	/* step4:set scramble */
+	GTP_DEBUG("[burn_fw_boot]step4:set scramble");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_boot]set scramble fail.");
+		ret = FAIL;
+		goto exit_burn_fw_boot;
+	}
+
+	/* step5:release ss51 & dsp */
+	GTP_DEBUG("[burn_fw_boot]step5:release ss51 & dsp");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_boot]release ss51 & dsp fail.");
+		ret = FAIL;
+		goto exit_burn_fw_boot;
+	}
+	/* must delay */
+	msleep(20);
+
+	/* step6:select bank3 */
+	GTP_DEBUG("[burn_fw_boot]step6:select bank3");
+	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_boot]select bank3 fail.");
+		ret = FAIL;
+		goto exit_burn_fw_boot;
+	}
+
+	/* step7:burn 2k bootloader firmware */
+	GTP_DEBUG("[burn_fw_boot]step7:burn 2k bootloader firmware");
+	ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_boot]burn fw_section fail.");
+		goto exit_burn_fw_boot;
+	}
+
+	/* step7:send burn cmd to move data to flash from sram */
+	GTP_DEBUG("[burn_fw_boot]step7:send burn cmd to move data to" \
+				"flash from sram");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_boot]send burn cmd fail.");
+		goto exit_burn_fw_boot;
+	}
+	GTP_DEBUG("[burn_fw_boot]Wait for the burn is complete......");
+	do {
+		ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+		if (ret <= 0) {
+			GTP_ERROR("[burn_fw_boot]Get burn state fail");
+			goto exit_burn_fw_boot;
+		}
+		msleep(20);
+		/* GTP_DEBUG("[burn_fw_boot]Get burn state:%d.",
+						rd_buf[GTP_ADDR_LENGTH]); */
+	} while (rd_buf[GTP_ADDR_LENGTH]);
+
+	/* step8:recall check 2k bootloader firmware */
+	GTP_DEBUG("[burn_fw_boot]step8:recall check 2k bootloader firmware");
+	ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
+	if (ret == FAIL) {
+		GTP_ERROR("[burn_fw_boot]recall check 4k dsp firmware fail.");
+		goto exit_burn_fw_boot;
+	}
+
+	/* step9:enable download DSP code  */
+	GTP_DEBUG("[burn_fw_boot]step9:enable download DSP code ");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_boot]enable download DSP code fail.");
+		ret = FAIL;
+		goto exit_burn_fw_boot;
+	}
+
+	/* step10:release ss51 & hold dsp */
+	GTP_DEBUG("[burn_fw_boot]step10:release ss51 & hold dsp");
+	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08);
+	if (ret <= 0) {
+		GTP_ERROR("[burn_fw_boot]release ss51 & hold dsp fail.");
+		ret = FAIL;
+		goto exit_burn_fw_boot;
+	}
+
+	ret = SUCCESS;
+
 exit_burn_fw_boot:
-    kfree(fw_boot);
-    return ret;
+	kfree(fw_boot);
+	return ret;
 }
 
 s32 gup_update_proc(void *dir)
 {
-    s32 ret = 0;
-    u8  retry = 0;
-    st_fw_head fw_head;
-    struct goodix_ts_data *ts = NULL;
-    
-    GTP_DEBUG("[update_proc]Begin update ......");
-    
-    show_len = 1;
-    total_len = 100;
-    if(dir == NULL)
-    {
-        msleep(3000);                               //wait main thread to be completed
-    }
-    
-    ts = i2c_get_clientdata(i2c_connect_client);
-    
-    if (searching_file)
-    {
-        searching_file = 0;     // exit .bin update file searching 
-        GTP_INFO("Exiting searching .bin update file...");
-        while ((show_len != 200) && (show_len != 100))     // wait for auto update quitted completely
-        {
-            msleep(100);
-        }
-    }
-    
-    update_msg.file = NULL;
-    ret = gup_check_update_file(i2c_connect_client, &fw_head, (u8*)dir);     //20121211
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[update_proc]check update file fail.");
-        goto file_fail;
-    }
-    
-    //gtp_reset_guitar(i2c_connect_client, 20);
-    ret = gup_get_ic_fw_msg(i2c_connect_client);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[update_proc]get ic message fail.");
-        goto file_fail;
-    }    
-    
-    ret = gup_enter_update_judge(&fw_head);
-    if(FAIL == ret)
-    {
-        GTP_ERROR("[update_proc]Check *.bin file fail.");
-        goto file_fail;
-    }
-    
-    ts->enter_update = 1;        
-    gtp_irq_disable(ts);
+	s32 ret = 0;
+	u8  retry = 0;
+	st_fw_head fw_head;
+	struct goodix_ts_data *ts = NULL;
+
+	GTP_DEBUG("[update_proc]Begin update ......");
+
+	show_len = 1;
+	total_len = 100;
+	if (dir == NULL)
+		/* wait main thread to be completed */
+	msleep(3000);
+
+	ts = i2c_get_clientdata(i2c_connect_client);
+
+	if (searching_file) {
+		/* exit .bin update file searching  */
+		searching_file = 0;
+		GTP_INFO("Exiting searching .bin update file...");
+		/* wait for auto update quitted completely */
+		while ((show_len != 200) && (show_len != 100))
+			msleep(100);
+	}
+
+	update_msg.file = NULL;
+	ret = gup_check_update_file(i2c_connect_client, &fw_head, (u8 *)dir);
+	if (ret == FAIL) {
+		GTP_ERROR("[update_proc]check update file fail.");
+		goto file_fail;
+	}
+
+	/* gtp_reset_guitar(i2c_connect_client, 20); */
+	ret = gup_get_ic_fw_msg(i2c_connect_client);
+	if (ret == FAIL) {
+		GTP_ERROR("[update_proc]get ic message fail.");
+		goto file_fail;
+	}
+
+	ret = gup_enter_update_judge(&fw_head);
+	if (ret == FAIL) {
+		GTP_ERROR("[update_proc]Check *.bin file fail.");
+		goto file_fail;
+	}
+
+	ts->enter_update = 1;
+	gtp_irq_disable(ts);
 #if GTP_ESD_PROTECT
-    gtp_esd_switch(ts->client, SWITCH_OFF);
+	gtp_esd_switch(ts->client, SWITCH_OFF);
 #endif
-    ret = gup_enter_update_mode(i2c_connect_client);
-    if(FAIL == ret)
-    {
-         GTP_ERROR("[update_proc]enter update mode fail.");
-         goto update_fail;
-    }
-    
-    while(retry++ < 5)
-    {
-        show_len = 10;
-        total_len = 100;
-        ret = gup_burn_dsp_isp(i2c_connect_client);
-        if(FAIL == ret)
-        {
-            GTP_ERROR("[update_proc]burn dsp isp fail.");
-            continue;
-        }
-        
-        show_len += 10;
-        ret = gup_burn_fw_ss51(i2c_connect_client);
-        if(FAIL == ret)
-        {
-            GTP_ERROR("[update_proc]burn ss51 firmware fail.");
-            continue;
-        }
-        
-        show_len += 40;
-        ret = gup_burn_fw_dsp(i2c_connect_client);
-        if(FAIL == ret)
-        {
-            GTP_ERROR("[update_proc]burn dsp firmware fail.");
-            continue;
-        }
-        
-        show_len += 20;
-        ret = gup_burn_fw_boot(i2c_connect_client);
-        if(FAIL == ret)
-        {
-            GTP_ERROR("[update_proc]burn bootloader firmware fail.");
-            continue;
-        }
-        show_len += 10;
-        GTP_INFO("[update_proc]UPDATE SUCCESS.");
-        break;
-    }
-    if(retry >= 5)
-    {
-        GTP_ERROR("[update_proc]retry timeout,UPDATE FAIL.");
-        goto update_fail;
-    }
-    
-    GTP_DEBUG("[update_proc]leave update mode.");
-    gup_leave_update_mode();
-    
-    msleep(100);
-//    GTP_DEBUG("[update_proc]send config.");
-//    ret = gtp_send_cfg(i2c_connect_client);
-//    if(ret < 0)
-//    {
-//        GTP_ERROR("[update_proc]send config fail.");
-//    }
-    if (ts->fw_error)
-    {
-        GTP_INFO("firmware error auto update, resent config!");
-        gup_init_panel(ts);
-    }
-    show_len = 100;
-    total_len = 100;
-    ts->enter_update = 0;
-    gtp_irq_enable(ts);
-    
+	ret = gup_enter_update_mode(i2c_connect_client);
+	if (ret == FAIL) {
+		GTP_ERROR("[update_proc]enter update mode fail.");
+		goto update_fail;
+	}
+
+	while (retry++ < 5) {
+		show_len = 10;
+		total_len = 100;
+		ret = gup_burn_dsp_isp(i2c_connect_client);
+		if (ret == FAIL) {
+			GTP_ERROR("[update_proc]burn dsp isp fail.");
+			continue;
+		}
+
+		show_len += 10;
+		ret = gup_burn_fw_ss51(i2c_connect_client);
+		if (ret == FAIL) {
+			GTP_ERROR("[update_proc]burn ss51 firmware fail.");
+			continue;
+		}
+
+		show_len += 40;
+		ret = gup_burn_fw_dsp(i2c_connect_client);
+		if (ret == FAIL) {
+			GTP_ERROR("[update_proc]burn dsp firmware fail.");
+			continue;
+		}
+
+		show_len += 20;
+		ret = gup_burn_fw_boot(i2c_connect_client);
+		if (ret == FAIL) {
+			GTP_ERROR("[update_proc]burn bootloader fw fail.");
+			continue;
+		}
+		show_len += 10;
+		GTP_INFO("[update_proc]UPDATE SUCCESS.");
+		break;
+	}
+	if (retry >= 5) {
+		GTP_ERROR("[update_proc]retry timeout,UPDATE FAIL.");
+		goto update_fail;
+	}
+
+	GTP_DEBUG("[update_proc]leave update mode.");
+	gup_leave_update_mode();
+
+	msleep(100);
+
+	/* GTP_DEBUG("[update_proc]send config.");
+	ret = gtp_send_cfg(i2c_connect_client);
+	if(ret < 0) {
+		GTP_ERROR("[update_proc]send config fail.");
+	} */
+
+	if (ts->fw_error) {
+		GTP_INFO("firmware error auto update, resent config!");
+		gup_init_panel(ts);
+	}
+	show_len = 100;
+	total_len = 100;
+	ts->enter_update = 0;
+	gtp_irq_enable(ts);
+
 #if GTP_ESD_PROTECT
-    gtp_esd_switch(ts->client, SWITCH_ON);
+	gtp_esd_switch(ts->client, SWITCH_ON);
 #endif
-    filp_close(update_msg.file, NULL);
-    return SUCCESS;
-    
+	filp_close(update_msg.file, NULL);
+	return SUCCESS;
+
 update_fail:
-    ts->enter_update = 0;
-    gtp_irq_enable(ts);
-    
+	ts->enter_update = 0;
+	gtp_irq_enable(ts);
+
 #if GTP_ESD_PROTECT
-    gtp_esd_switch(ts->client, SWITCH_ON);
+	gtp_esd_switch(ts->client, SWITCH_ON);
 #endif
 
 file_fail:
-    if(update_msg.file && !IS_ERR(update_msg.file))
-    {
-        filp_close(update_msg.file, NULL);
-    }
-    show_len = 200;
-    total_len = 100;
-    return FAIL;
+	if (update_msg.file && !IS_ERR(update_msg.file))
+		filp_close(update_msg.file, NULL);
+
+	show_len = 200;
+	total_len = 100;
+	return FAIL;
 }
 
 #if GTP_AUTO_UPDATE
 u8 gup_init_update_proc(struct goodix_ts_data *ts)
 {
-    struct task_struct *thread = NULL;
+	struct task_struct *thread = NULL;
 
-    GTP_INFO("Ready to run update thread.");
-    thread = kthread_run(gup_update_proc, (void*)NULL, "guitar_update");
-    if (IS_ERR(thread))
-    {
-        GTP_ERROR("Failed to create update thread.\n");
-        return -1;
-    }
+	GTP_INFO("Ready to run update thread.");
+	thread = kthread_run(gup_update_proc, (void *)NULL, "guitar_update");
+	if (IS_ERR(thread)) {
+		GTP_ERROR("Failed to create update thread.\n");
+		return -EINVAL;
+	}
 
-    return 0;
+	return 0;
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index 2a5fea7..385947f 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -32,14 +32,12 @@
 #define SHOW_PROGRESS
 #define MAX_FIRMWARE_ID_LEN 10
 #define FORCE_UPDATE false
+#define DO_LOCKDOWN false
 #define INSIDE_FIRMWARE_UPDATE
 
 #define FW_IMAGE_OFFSET 0x100
-
-#define BOOTLOADER_ID_OFFSET 0
-#define FLASH_PROPERTIES_OFFSET 2
-#define BLOCK_SIZE_OFFSET 3
-#define FW_BLOCK_COUNT_OFFSET 5
+/* 0 to ignore flash block check to speed up flash time */
+#define CHECK_FLASH_BLOCK_STATUS 1
 
 #define REG_MAP (1 << 0)
 #define UNLOCKED (1 << 1)
@@ -49,9 +47,6 @@
 #define HAS_DISP_CONFIG (1 << 5)
 #define HAS_CTRL1 (1 << 6)
 
-#define BLOCK_NUMBER_OFFSET 0
-#define BLOCK_DATA_OFFSET 2
-
 #define RMI4_INFO_MAX_LEN	200
 
 #define RMI4_STORE_TS_INFO(buf, id, rev, fw_ver) \
@@ -70,6 +65,7 @@
 enum flash_command {
 	CMD_WRITE_FW_BLOCK		= 0x2,
 	CMD_ERASE_ALL			= 0x3,
+	CMD_WRITE_LOCKDOWN_BLOCK	= 0x4,
 	CMD_READ_CONFIG_BLOCK	= 0x5,
 	CMD_WRITE_CONFIG_BLOCK	= 0x6,
 	CMD_ERASE_CONFIG		= 0x7,
@@ -91,6 +87,23 @@
 	OPTION_CONTAIN_BOOTLOADER = 1,
 };
 
+enum flash_offset {
+	OFFSET_BOOTLOADER_ID,
+	OFFSET_FLASH_PROPERTIES,
+	OFFSET_BLOCK_SIZE,
+	OFFSET_FW_BLOCK_COUNT,
+	OFFSET_BLOCK_NUMBER,
+	OFFSET_BLOCK_DATA,
+	OFFSET_FLASH_CONTROL,
+	OFFSET_FLASH_STATUS
+};
+
+enum flash_update_mode {
+	NORMAL = 1,
+	FORCE = 2,
+	LOCKDOWN = 8
+};
+
 #define SLEEP_MODE_NORMAL (0x00)
 #define SLEEP_MODE_SENSOR_SLEEP (0x01)
 #define SLEEP_MODE_RESERVED0 (0x02)
@@ -101,9 +114,7 @@
 #define ERASE_WAIT_MS (5 * 1000)
 #define RESET_WAIT_MS (500)
 
-#define POLLING_MODE 0
-
-#define SLEEP_TIME_US 50
+#define SLEEP_TIME_US 100
 
 static int fwu_wait_for_idle(int timeout_ms);
 
@@ -141,7 +152,8 @@
 	};
 };
 
-struct image_header {
+struct image_content {
+	bool is_contain_build_info;
 	unsigned int checksum;
 	unsigned int image_size;
 	unsigned int config_size;
@@ -152,7 +164,10 @@
 	u16 package_id;
 	u16 package_revision_id;
 	unsigned int firmware_id;
-	bool is_contain_build_info;
+	const unsigned char *firmware_data;
+	const unsigned char *config_data;
+	const unsigned char *lockdown_data;
+	unsigned short lockdown_block_count;
 };
 
 struct pdt_properties {
@@ -194,11 +209,28 @@
 
 struct f34_flash_control {
 	union {
+	/* version 0 */
 		struct {
-			unsigned char command:4;
+			unsigned char command_v0:4;
 			unsigned char status:3;
 			unsigned char program_enabled:1;
 		} __packed;
+	/* version 1 */
+		struct {
+			unsigned char command_v1:6;
+			unsigned char reserved:2;
+		} __packed;
+		unsigned char data[1];
+	};
+};
+
+struct f34_flash_status {
+	union {
+		struct {
+			unsigned char status:6;
+			unsigned char reserved:1;
+			unsigned char program_enabled:1;
+		} __packed;
 		unsigned char data[1];
 	};
 };
@@ -222,6 +254,9 @@
 struct synaptics_rmi4_fwu_handle {
 	bool initialized;
 	bool force_update;
+	bool do_lockdown;
+	bool interrupt_flag;
+	bool polling_mode;
 	char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1];
 	unsigned int image_size;
 	unsigned int data_pos;
@@ -233,31 +268,33 @@
 	unsigned char *read_config_buf;
 	const unsigned char *firmware_data;
 	const unsigned char *config_data;
+	const unsigned char *lockdown_data;
 	unsigned short block_size;
 	unsigned short fw_block_count;
 	unsigned short config_block_count;
+	unsigned short lockdown_block_count;
 	unsigned short perm_config_block_count;
 	unsigned short bl_config_block_count;
 	unsigned short disp_config_block_count;
 	unsigned short config_size;
 	unsigned short config_area;
-	unsigned short addr_f34_flash_control;
 	unsigned short addr_f01_interrupt_register;
+	const unsigned char *data_buffer;
 	struct synaptics_rmi4_fn_desc f01_fd;
 	struct synaptics_rmi4_fn_desc f34_fd;
 	struct synaptics_rmi4_exp_fn_ptr *fn_ptr;
 	struct synaptics_rmi4_data *rmi4_data;
-	struct f34_flash_control flash_control;
 	struct f34_flash_properties flash_properties;
 	struct workqueue_struct *fwu_workqueue;
 	struct delayed_work fwu_work;
-	char firmware_name[NAME_BUFFER_SIZE];
+	char image_name[NAME_BUFFER_SIZE];
+	struct image_content image_content;
 	char *ts_info;
 };
 
 static struct synaptics_rmi4_fwu_handle *fwu;
 
-static struct completion remove_complete;
+DECLARE_COMPLETION(fwu_remove_complete);
 
 static unsigned int extract_uint(const unsigned char *ptr)
 {
@@ -295,42 +332,80 @@
 		pkg_id[3] << 8 | pkg_id[2], build_id);
 }
 
-static void parse_header(struct image_header *header,
-		const unsigned char *fw_image)
+static void parse_header(void)
 {
-	struct image_header_data *data = (struct image_header_data *)fw_image;
-	header->checksum = extract_uint(data->file_checksum);
-	header->bootloader_version = data->bootloader_version;
-	header->image_size = extract_uint(data->firmware_size);
-	header->config_size = extract_uint(data->config_size);
-	memcpy(header->product_id, data->product_id,
+	struct image_content *img = &fwu->image_content;
+	struct image_header_data *data =
+		(struct image_header_data *)fwu->data_buffer;
+	img->checksum = extract_uint(data->file_checksum);
+	img->bootloader_version = data->bootloader_version;
+	img->image_size = extract_uint(data->firmware_size);
+	img->config_size = extract_uint(data->config_size);
+	memcpy(img->product_id, data->product_id,
 		sizeof(data->product_id));
-	header->product_id[sizeof(data->product_id)] = 0;
+	img->product_id[sizeof(data->product_id)] = 0;
 
-	memcpy(header->product_info, data->product_info,
+	img->product_id[sizeof(data->product_info)] = 0;
+	memcpy(img->product_info, data->product_info,
 		sizeof(data->product_info));
 
-	header->is_contain_build_info =
+	img->is_contain_build_info =
 		(data->options_firmware_id == (1 << OPTION_BUILD_INFO));
-	if (header->is_contain_build_info) {
-		header->package_id = (data->pkg_id_rev_msb << 8) |
+
+	if (img->is_contain_build_info) {
+		img->firmware_id = extract_uint(data->firmware_id);
+		img->package_id = (data->pkg_id_rev_msb << 8) |
 				data->pkg_id_lsb;
-		header->package_revision_id = (data->pkg_id_rev_msb << 8) |
+		img->package_revision_id = (data->pkg_id_rev_msb << 8) |
 				data->pkg_id_rev_lsb;
 		dev_info(&fwu->rmi4_data->i2c_client->dev,
 			"%s Package ID %d Rev %d\n", __func__,
-			header->package_id, header->package_revision_id);
+			img->package_id, img->package_revision_id);
 
-		header->firmware_id = extract_uint(data->firmware_id);
+		img->firmware_id = extract_uint(data->firmware_id);
 		dev_info(&fwu->rmi4_data->i2c_client->dev,
 			"%s Firwmare build id %d\n", __func__,
-			header->firmware_id);
+			img->firmware_id);
 	}
 
 	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
 		"Firwmare size %d, config size %d\n",
-		header->image_size,
-		header->config_size);
+		img->image_size,
+		img->config_size);
+
+	/* get UI firmware offset */
+	if (img->image_size)
+		img->firmware_data = fwu->data_buffer + FW_IMAGE_OFFSET;
+	/* get config offset*/
+	if (img->config_size)
+		img->config_data = fwu->data_buffer + FW_IMAGE_OFFSET +
+				img->image_size;
+	/* get lockdown offset*/
+	switch (img->bootloader_version) {
+	case 3:
+	case 4:
+		img->lockdown_block_count = 4;
+		break;
+	case 5:
+	case 6:
+		img->lockdown_block_count = 5;
+		break;
+	default:
+		dev_warn(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Not support lockdown in " \
+			"bootloader version V%d\n",
+			__func__, img->bootloader_version);
+		img->lockdown_data = NULL;
+	}
+
+	img->lockdown_data = fwu->data_buffer +
+				FW_IMAGE_OFFSET -
+				img->lockdown_block_count * fwu->block_size;
+
+	fwu->lockdown_block_count = img->lockdown_block_count;
+	fwu->lockdown_data = img->lockdown_data;
+	fwu->config_data = img->config_data;
+	fwu->firmware_data = img->firmware_data;
 	return;
 }
 
@@ -352,6 +427,62 @@
 	return 0;
 }
 
+static unsigned short fwu_get_address(enum flash_offset type)
+{
+	int offset;
+	unsigned short addr = 0;
+	struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
+
+	switch (type) {
+	case OFFSET_BOOTLOADER_ID:
+		offset = 0;
+		addr = fwu->f34_fd.query_base_addr + offset;
+		break;
+	case OFFSET_FLASH_PROPERTIES:
+		offset = ((fwu->f34_fd.version == 0) ? 2 : 1);
+		addr = fwu->f34_fd.query_base_addr + offset;
+		break;
+	case OFFSET_BLOCK_SIZE:
+		offset = ((fwu->f34_fd.version == 0) ? 3 : 2);
+		addr = fwu->f34_fd.query_base_addr + offset;
+		break;
+	case OFFSET_FW_BLOCK_COUNT:
+		offset = ((fwu->f34_fd.version == 0) ? 5 : 3);
+		addr = fwu->f34_fd.query_base_addr + offset;
+		break;
+	case OFFSET_BLOCK_NUMBER:
+		offset = 0;
+		addr = fwu->f34_fd.data_base_addr + offset;
+		break;
+	case OFFSET_BLOCK_DATA:
+		offset = ((fwu->f34_fd.version == 0) ? 2 : 1);
+		addr = fwu->f34_fd.data_base_addr + offset;
+		break;
+	case OFFSET_FLASH_CONTROL:
+		offset = ((fwu->f34_fd.version == 0) ?
+			2 + (fwu->block_size) : 2);
+		addr = fwu->f34_fd.data_base_addr + offset;
+		break;
+	case OFFSET_FLASH_STATUS:
+		if (fwu->f34_fd.version == 1) {
+			offset = 3;
+			addr = fwu->f34_fd.data_base_addr + offset;
+		} else if (fwu->f34_fd.version == 0) {
+			dev_warn(&i2c_client->dev,
+			"%s: F$34 version 0 does not contain " \
+			"flash status register\n",
+			__func__);
+		}
+		break;
+	default:
+		dev_err(&i2c_client->dev,
+			"%s: Unknown flash offset (%d)\n",
+			__func__, type);
+		break;
+	}
+	return addr;
+}
+
 static int fwu_read_f34_queries(void)
 {
 	int retval;
@@ -360,7 +491,7 @@
 	struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
 
 	retval = fwu->fn_ptr->read(fwu->rmi4_data,
-			fwu->f34_fd.query_base_addr + BOOTLOADER_ID_OFFSET,
+			fwu_get_address(OFFSET_BOOTLOADER_ID),
 			fwu->bootloader_id,
 			sizeof(fwu->bootloader_id));
 	if (retval < 0) {
@@ -371,7 +502,7 @@
 	}
 
 	retval = fwu->fn_ptr->read(fwu->rmi4_data,
-			fwu->f34_fd.query_base_addr + FLASH_PROPERTIES_OFFSET,
+			fwu_get_address(OFFSET_FLASH_PROPERTIES),
 			fwu->flash_properties.data,
 			sizeof(fwu->flash_properties.data));
 	if (retval < 0) {
@@ -397,7 +528,7 @@
 		count += 2;
 
 	retval = fwu->fn_ptr->read(fwu->rmi4_data,
-			fwu->f34_fd.query_base_addr + BLOCK_SIZE_OFFSET,
+			fwu_get_address(OFFSET_BLOCK_SIZE),
 			buf,
 			2);
 	if (retval < 0) {
@@ -410,13 +541,13 @@
 	batohs(&fwu->block_size, &(buf[0]));
 
 	retval = fwu->fn_ptr->read(fwu->rmi4_data,
-			fwu->f34_fd.query_base_addr + FW_BLOCK_COUNT_OFFSET,
+			fwu_get_address(OFFSET_FW_BLOCK_COUNT),
 			buf,
 			count);
 	if (retval < 0) {
 		dev_err(&i2c_client->dev,
-				"%s: Failed to read block count info\n",
-				__func__);
+			"%s: Failed to read block count info\n",
+			__func__);
 		return retval;
 	}
 
@@ -438,9 +569,6 @@
 	if (fwu->flash_properties.has_display_config)
 		batohs(&fwu->disp_config_block_count, &(buf[count]));
 
-	fwu->addr_f34_flash_control = fwu->f34_fd.data_base_addr +
-					BLOCK_DATA_OFFSET +
-					fwu->block_size;
 	return 0;
 }
 
@@ -461,18 +589,36 @@
 	return interrupt_status;
 }
 
-static int fwu_read_f34_flash_status(void)
+static int fwu_read_f34_flash_status(unsigned char *status)
 {
 	int retval;
-	retval = fwu->fn_ptr->read(fwu->rmi4_data,
-			fwu->addr_f34_flash_control,
-			fwu->flash_control.data,
-			sizeof(fwu->flash_control.data));
-	if (retval < 0) {
-		dev_err(&fwu->rmi4_data->i2c_client->dev,
+	struct f34_flash_control flash_control;
+	struct f34_flash_status flash_status;
+
+	if (fwu->f34_fd.version == 1) {
+		retval = fwu->fn_ptr->read(fwu->rmi4_data,
+			fwu_get_address(OFFSET_FLASH_STATUS),
+			flash_status.data,
+			sizeof(flash_status.data));
+		if (retval < 0) {
+			dev_err(&fwu->rmi4_data->i2c_client->dev,
 				"%s: Failed to read flash status\n",
 				__func__);
-		return retval;
+			return -EIO;
+		}
+		*status = flash_status.status;
+	} else {
+		retval = fwu->fn_ptr->read(fwu->rmi4_data,
+			fwu_get_address(OFFSET_FLASH_CONTROL),
+			flash_control.data,
+			sizeof(flash_control.data));
+		if (retval < 0) {
+			dev_err(&fwu->rmi4_data->i2c_client->dev,
+				"%s: Failed to read flash status\n",
+				__func__);
+			return -EIO;
+		}
+		*status = flash_control.status;
 	}
 	return 0;
 }
@@ -492,22 +638,27 @@
 				__func__);
 		return retval;
 	}
+
+	fwu->polling_mode = false;
+
 	return 0;
 }
 
 static int fwu_write_f34_command(unsigned char cmd)
 {
 	int retval;
+	struct f34_flash_control flash_control;
 
-	fwu->flash_control.data[0] = cmd;
+	flash_control.data[0] = cmd;
+	fwu->interrupt_flag = false;
 	retval = fwu->fn_ptr->write(fwu->rmi4_data,
-			fwu->addr_f34_flash_control,
-			fwu->flash_control.data,
-			sizeof(fwu->flash_control.data));
+			fwu_get_address(OFFSET_FLASH_CONTROL),
+			flash_control.data,
+			sizeof(flash_control.data));
 	if (retval < 0) {
 		dev_err(&fwu->rmi4_data->i2c_client->dev,
 				"%s: Failed to write command 0x%02x\n",
-				__func__, fwu->flash_control.data[0]);
+				__func__, flash_control.data[0]);
 		return retval;
 	}
 	return 0;
@@ -518,18 +669,21 @@
 	int count = 0;
 	int timeout_count = ((timeout_ms * 1000) / SLEEP_TIME_US) + 1;
 	do {
-		#if POLLING_MODE
-		fwu_read_f34_flash_status();
-		#endif
-		if (fwu->flash_control.command == 0x00)
+		if (fwu->interrupt_flag)
 			return 0;
-
-		usleep_range(SLEEP_TIME_US, SLEEP_TIME_US + 100);
+		if (fwu->polling_mode)
+			if (fwu->intr_mask & fwu_read_interrupt_status())
+				return 0;
+		usleep_range(SLEEP_TIME_US, SLEEP_TIME_US + 1);
 	} while (count++ < timeout_count);
 
-	fwu_read_f34_flash_status();
-	if (fwu->flash_control.command == 0x00)
+	if (fwu->intr_mask & fwu_read_interrupt_status()) {
+		fwu->polling_mode = true;
+		dev_info(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Switch to polling mode\n",
+			__func__);
 		return 0;
+	}
 
 	dev_err(&fwu->rmi4_data->i2c_client->dev,
 			"%s: Timed out waiting for idle status\n",
@@ -538,7 +692,7 @@
 	return -ETIMEDOUT;
 }
 
-static enum flash_area fwu_go_nogo(struct image_header *header)
+static enum flash_area fwu_go_nogo(void)
 {
 	int retval = 0;
 	int index = 0;
@@ -554,30 +708,53 @@
 	enum flash_area flash_area = NONE;
 	struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
 	struct f01_device_status f01_device_status;
+	struct image_content *img = &fwu->image_content;
 
 	if (fwu->force_update) {
 		flash_area = UI_FIRMWARE;
 		goto exit;
 	}
 
-	if (header->is_contain_build_info) {
+	if (img->is_contain_build_info) {
 		/* if package id does not match, do not update firmware */
 		fwu->fn_ptr->read(fwu->rmi4_data,
 					fwu->f01_fd.query_base_addr + 17,
 					pkg_id,
 					sizeof(pkg_id));
 
-		if (header->package_id != ((pkg_id[1] << 8) | pkg_id[0])) {
+		if (img->package_id != ((pkg_id[1] << 8) | pkg_id[0])) {
 			flash_area = MISMATCH;
 			goto exit;
 		}
-		if (header->package_revision_id !=
+		if (img->package_revision_id !=
 				((pkg_id[3] << 8) | pkg_id[2])) {
 			flash_area = MISMATCH;
 			goto exit;
 		}
 	}
 
+	/* check firmware size */
+	if (fwu->fw_block_count*fwu->block_size != img->image_size) {
+		dev_err(&i2c_client->dev,
+			"%s: firmware size of device (%d) != .img (%d)\n",
+			__func__,
+			fwu->config_block_count * fwu->block_size,
+			img->image_size);
+		flash_area = NONE;
+		goto exit;
+	}
+
+	/* check config size */
+	if (fwu->config_block_count*fwu->block_size != img->config_size) {
+		dev_err(&i2c_client->dev,
+			"%s: config size of device (%d) != .img (%d)\n",
+			__func__,
+			fwu->config_block_count * fwu->block_size,
+			img->config_size);
+		flash_area = NONE;
+		goto exit;
+	}
+
 	retval = fwu_read_f01_device_status(&f01_device_status);
 	if (retval < 0) {
 		flash_area = NONE;
@@ -608,14 +785,21 @@
 	deviceFirmwareID = extract_uint(firmware_id);
 
 	/* .img firmware id */
-	if (header->is_contain_build_info) {
+	if (img->is_contain_build_info) {
 		dev_err(&i2c_client->dev,
 			"%s: Image option contains build info.\n",
 			__func__);
-		imageFirmwareID = header->firmware_id;
+		imageFirmwareID = img->firmware_id;
 	} else {
-		strptr = strnstr(fwu->firmware_name, "PR",
-				sizeof(fwu->firmware_name));
+		if (!fwu->image_name) {
+			dev_info(&i2c_client->dev,
+				"%s: Unknown image file name\n",
+				__func__);
+			flash_area = UI_FIRMWARE;
+			goto exit;
+		}
+		strptr = strnstr(fwu->image_name, "PR",
+				sizeof(fwu->image_name));
 		if (!strptr) {
 			dev_err(&i2c_client->dev,
 				"No valid PR number (PRxxxxxxx)" \
@@ -771,21 +955,41 @@
 		unsigned char command)
 {
 	int retval;
+	unsigned char flash_status;
 	unsigned char block_offset[] = {0, 0};
 	unsigned short block_num;
+	unsigned short addr_block_data = fwu_get_address(OFFSET_BLOCK_DATA);
+	unsigned short addr_block_num = fwu_get_address(OFFSET_BLOCK_NUMBER);
 	struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
 #ifdef SHOW_PROGRESS
-	unsigned int progress = (command == CMD_WRITE_CONFIG_BLOCK) ?
-				10 : 100;
+	unsigned int progress;
+	unsigned char command_str[10];
+	switch (command) {
+	case CMD_WRITE_CONFIG_BLOCK:
+		progress = 10;
+		strlcpy(command_str, "config", 10);
+		break;
+	case CMD_WRITE_FW_BLOCK:
+		progress = 100;
+		strlcpy(command_str, "firmware", 10);
+		break;
+	case CMD_WRITE_LOCKDOWN_BLOCK:
+		progress = 1;
+		strlcpy(command_str, "lockdown", 10);
+		break;
+	default:
+		progress = 1;
+		strlcpy(command_str, "unknown", 10);
+		break;
+	}
 #endif
 
 	dev_dbg(&i2c_client->dev,
 			"%s: Start to update %s blocks\n",
 			__func__,
-			command == CMD_WRITE_CONFIG_BLOCK ?
-			"config" : "firmware");
+			command_str);
 	retval = fwu->fn_ptr->write(fwu->rmi4_data,
-			fwu->f34_fd.data_base_addr + BLOCK_NUMBER_OFFSET,
+			addr_block_num,
 			block_offset,
 			sizeof(block_offset));
 	if (retval < 0) {
@@ -801,12 +1005,11 @@
 			dev_info(&i2c_client->dev,
 					"%s: update %s %3d / %3d\n",
 					__func__,
-					command == CMD_WRITE_CONFIG_BLOCK ?
-					"config" : "firmware",
+					command_str,
 					block_num, block_cnt);
 #endif
 		retval = fwu->fn_ptr->write(fwu->rmi4_data,
-			fwu->f34_fd.data_base_addr + BLOCK_DATA_OFFSET,
+			addr_block_data,
 			block_ptr,
 			fwu->block_size);
 		if (retval < 0) {
@@ -832,21 +1035,28 @@
 			return retval;
 		}
 
-		if (fwu->flash_control.status != 0x00) {
+		#if CHECK_FLASH_BLOCK_STATUS
+		retval = fwu_read_f34_flash_status(&flash_status);
+		if (retval < 0) {
 			dev_err(&i2c_client->dev,
-					"%s: Flash block %d failed, status 0x%02X\n",
-					__func__, block_num, retval);
+					"%s: Failed to read flash status (block %d)\n",
+					__func__, block_num);
 			return retval;
 		}
-
+		if (flash_status != 0x00) {
+			dev_err(&i2c_client->dev,
+				"%s: Flash block %d failed, status 0x%02X\n",
+				__func__, block_num, flash_status);
+			return -EINVAL;
+		}
+		#endif
 		block_ptr += fwu->block_size;
 	}
 #ifdef SHOW_PROGRESS
 	dev_info(&i2c_client->dev,
 			"%s: update %s %3d / %3d\n",
 			__func__,
-			command == CMD_WRITE_CONFIG_BLOCK ?
-			"config" : "firmware",
+			command_str,
 			block_cnt, block_cnt);
 #endif
 	return 0;
@@ -864,6 +1074,12 @@
 		fwu->config_block_count, CMD_WRITE_CONFIG_BLOCK);
 }
 
+static int fwu_write_lockdown_block(void)
+{
+	return fwu_write_blocks((unsigned char *)fwu->lockdown_data,
+		fwu->lockdown_block_count, CMD_WRITE_LOCKDOWN_BLOCK);
+}
+
 static int fwu_write_bootloader_id(void)
 {
 	int retval;
@@ -874,7 +1090,7 @@
 			fwu->bootloader_id[1]);
 
 	retval = fwu->fn_ptr->write(fwu->rmi4_data,
-			fwu->f34_fd.data_base_addr + BLOCK_DATA_OFFSET,
+			fwu_get_address(OFFSET_BLOCK_DATA),
 			fwu->bootloader_id,
 			sizeof(fwu->bootloader_id));
 	if (retval < 0) {
@@ -887,7 +1103,7 @@
 	return 0;
 }
 
-static int fwu_enter_flash_prog(void)
+static int fwu_enter_flash_prog(bool force)
 {
 	int retval;
 	struct f01_device_status f01_device_status;
@@ -961,63 +1177,7 @@
 				__func__);
 		return retval;
 	}
-
-	return retval;
-}
-
-static int fwu_do_reflash(void)
-{
-	int retval;
-
-	retval = fwu_enter_flash_prog();
-	if (retval < 0)
-		return retval;
-
-	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
-			"%s: Entered flash prog mode\n",
-			__func__);
-
-	retval = fwu_write_bootloader_id();
-	if (retval < 0)
-		return retval;
-
-	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
-			"%s: Bootloader ID written\n",
-			__func__);
-
-	retval = fwu_write_f34_command(CMD_ERASE_ALL);
-	if (retval < 0)
-		return retval;
-
-	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
-			"%s: Erase all command written\n",
-			__func__);
-
-	retval = fwu_wait_for_idle(ERASE_WAIT_MS);
-	if (retval < 0)
-		return retval;
-
-	if (fwu->flash_control.status != 0x00) {
-		dev_err(&fwu->rmi4_data->i2c_client->dev,
-				"%s: Erase all command failed, status 0x%02X\n",
-				__func__, retval);
-		return -1;
-	}
-
-	if (fwu->firmware_data) {
-		retval = fwu_write_firmware();
-		if (retval < 0)
-			return retval;
-		pr_notice("%s: Firmware programmed\n", __func__);
-	}
-
-	if (fwu->config_data) {
-		retval = fwu_write_configuration();
-		if (retval < 0)
-			return retval;
-		pr_notice("%s: Configuration programmed\n", __func__);
-	}
-
+	fwu->polling_mode = false;
 	return retval;
 }
 
@@ -1025,7 +1185,7 @@
 {
 	int retval;
 
-	retval = fwu_enter_flash_prog();
+	retval = fwu_enter_flash_prog(false);
 	if (retval < 0)
 		return retval;
 
@@ -1087,42 +1247,38 @@
 static int fwu_start_write_config(void)
 {
 	int retval;
-	struct image_header header;
+	int block_count;
 
 	switch (fwu->config_area) {
 	case UI_CONFIG_AREA:
+		block_count = fwu->config_block_count;
 		break;
 	case PERM_CONFIG_AREA:
 		if (!fwu->flash_properties.has_perm_config)
 			return -EINVAL;
+		block_count = fwu->perm_config_block_count;
 		break;
 	case BL_CONFIG_AREA:
 		if (!fwu->flash_properties.has_bl_config)
 			return -EINVAL;
+		block_count = fwu->bl_config_block_count;
 		break;
 	case DISP_CONFIG_AREA:
 		if (!fwu->flash_properties.has_display_config)
 			return -EINVAL;
+		block_count = fwu->disp_config_block_count;
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	if (fwu->ext_data_source)
-		fwu->config_data = fwu->ext_data_source;
-	else
-		return -EINVAL;
-
-	if (fwu->config_area == UI_CONFIG_AREA) {
-		parse_header(&header, fwu->ext_data_source);
-
-		if (header.config_size) {
-			fwu->config_data = fwu->ext_data_source +
-					FW_IMAGE_OFFSET +
-					header.image_size;
-		} else {
-			return -EINVAL;
-		}
+	if (fwu->image_size == block_count*fwu->block_size) {
+		dev_info(&fwu->rmi4_data->i2c_client->dev,
+				"%s: write config from config file\n",
+				__func__);
+		fwu->config_data = fwu->data_buffer;
+	} else {
+		parse_header();
 	}
 
 	pr_notice("%s: Start of write config process\n", __func__);
@@ -1141,6 +1297,58 @@
 	return retval;
 }
 
+static int fwu_do_write_lockdown(bool reset)
+{
+	int retval;
+
+	pr_notice("%s: Start of lockdown process\n", __func__);
+
+	retval = fwu_enter_flash_prog(false);
+	if (retval < 0)
+		return retval;
+
+	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Entered flash prog mode\n",
+			__func__);
+
+	if (fwu->flash_properties.unlocked == 0) {
+		dev_err(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Device has been locked!\n",
+			__func__);
+		if (reset)
+			goto exit;
+		else
+			return -EINVAL;
+	}
+
+	retval = fwu_write_lockdown_block();
+	if (retval < 0)
+		return retval;
+
+	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+			"%s:Lockdown device\n",
+			__func__);
+
+exit:
+	if (reset)
+		retval = fwu->rmi4_data->reset_device(fwu->rmi4_data);
+	else
+		retval = fwu_enter_flash_prog(true);
+
+	if (retval < 0)
+		return retval;
+
+	pr_notice("%s: End of lockdown process\n", __func__);
+
+	return retval;
+}
+
+static int fwu_start_write_lockdown(void)
+{
+	parse_header();
+	return fwu_do_write_lockdown(true);
+}
+
 static int fwu_do_read_config(void)
 {
 	int retval;
@@ -1149,14 +1357,6 @@
 	unsigned short block_count;
 	unsigned short index = 0;
 
-	retval = fwu_enter_flash_prog();
-	if (retval < 0)
-		goto exit;
-
-	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
-			"%s: Entered flash prog mode\n",
-			__func__);
-
 	switch (fwu->config_area) {
 	case UI_CONFIG_AREA:
 		block_count = fwu->config_block_count;
@@ -1195,7 +1395,7 @@
 	block_offset[1] |= (fwu->config_area << 5);
 
 	retval = fwu->fn_ptr->write(fwu->rmi4_data,
-			fwu->f34_fd.data_base_addr + BLOCK_NUMBER_OFFSET,
+			fwu_get_address(OFFSET_BLOCK_NUMBER),
 			block_offset,
 			sizeof(block_offset));
 	if (retval < 0) {
@@ -1223,7 +1423,7 @@
 		}
 
 		retval = fwu->fn_ptr->read(fwu->rmi4_data,
-				fwu->f34_fd.data_base_addr + BLOCK_DATA_OFFSET,
+				fwu_get_address(OFFSET_BLOCK_DATA),
 				&fwu->read_config_buf[index],
 				fwu->block_size);
 		if (retval < 0) {
@@ -1237,7 +1437,71 @@
 	}
 
 exit:
-	fwu->rmi4_data->reset_device(fwu->rmi4_data);
+	return retval;
+}
+
+static int fwu_do_reflash(void)
+{
+	int retval;
+	unsigned char flash_status;
+
+	if (fwu->do_lockdown) {
+		retval = fwu_do_write_lockdown(false);
+		if (retval < 0)
+			dev_warn(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Skip lockdown process.\n",
+			__func__);
+	}
+	retval = fwu_enter_flash_prog(false);
+	if (retval < 0)
+		return retval;
+	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Entered flash prog mode\n",
+			__func__);
+
+	retval = fwu_write_bootloader_id();
+	if (retval < 0)
+		return retval;
+
+	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Bootloader ID written\n",
+			__func__);
+
+	retval = fwu_write_f34_command(CMD_ERASE_ALL);
+	if (retval < 0)
+		return retval;
+
+	dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Erase all command written\n",
+			__func__);
+
+	retval = fwu_wait_for_idle(ERASE_WAIT_MS);
+	if (retval < 0)
+		return retval;
+
+	retval = fwu_read_f34_flash_status(&flash_status);
+	if (retval < 0)
+		return retval;
+	if (flash_status != 0x00) {
+		dev_err(&fwu->rmi4_data->i2c_client->dev,
+				"%s: Erase all command failed, status 0x%02X\n",
+				__func__, flash_status);
+		return -EINVAL;
+	}
+
+	if (fwu->firmware_data) {
+		retval = fwu_write_firmware();
+		if (retval < 0)
+			return retval;
+		pr_notice("%s: Firmware programmed\n", __func__);
+	}
+
+	if (fwu->config_data) {
+		retval = fwu_write_configuration();
+		if (retval < 0)
+			return retval;
+		pr_notice("%s: Configuration programmed\n", __func__);
+	}
 
 	return retval;
 }
@@ -1245,45 +1509,47 @@
 static int fwu_start_reflash(void)
 {
 	int retval = 0;
-	struct image_header header;
-	const unsigned char *fw_image;
 	const struct firmware *fw_entry = NULL;
 	struct f01_device_status f01_device_status;
 	enum flash_area flash_area;
 
 	pr_notice("%s: Start of reflash process\n", __func__);
 
-	if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) == 0) {
-		dev_err(&fwu->rmi4_data->i2c_client->dev,
-			"Firmware image name not given, skipping update\n");
-		return 0;
-	}
-
-	if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) ==
-		NAME_BUFFER_SIZE) {
-		dev_err(&fwu->rmi4_data->i2c_client->dev,
-			"Firmware image name exceeds max length (%d), " \
-			"skipping update\n", NAME_BUFFER_SIZE);
-		return 0;
-	}
-
 	if (fwu->ext_data_source)
-		fw_image = fwu->ext_data_source;
+		dev_info(&fwu->rmi4_data->i2c_client->dev,
+				"%s Load .img file from commandline.\n",
+				__func__);
 	else {
-		snprintf(fwu->firmware_name, NAME_BUFFER_SIZE, "%s",
+		if (strnlen(fwu->rmi4_data->fw_image_name,
+				NAME_BUFFER_SIZE) == 0) {
+			dev_err(&fwu->rmi4_data->i2c_client->dev,
+				"Firmware image name not given, "\
+				"skipping update\n");
+			return 0;
+		}
+
+		if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) ==
+			NAME_BUFFER_SIZE) {
+			dev_err(&fwu->rmi4_data->i2c_client->dev,
+				"Firmware image name exceeds max length " \
+				"(%d), skipping update\n", NAME_BUFFER_SIZE);
+			return 0;
+		}
+
+		snprintf(fwu->image_name, NAME_BUFFER_SIZE, "%s",
 			fwu->rmi4_data->fw_image_name);
 		dev_info(&fwu->rmi4_data->i2c_client->dev,
 			"%s: Requesting firmware image %s\n",
-			__func__, fwu->firmware_name);
+			__func__, fwu->image_name);
 
 		retval = request_firmware(&fw_entry,
-				fwu->firmware_name,
+				fwu->image_name,
 				&fwu->rmi4_data->i2c_client->dev);
 		if (retval != 0) {
 			dev_err(&fwu->rmi4_data->i2c_client->dev,
 					"%s: Firmware image %s not available\n",
 					__func__,
-					fwu->firmware_name);
+					fwu->image_name);
 			return -EINVAL;
 		}
 
@@ -1291,22 +1557,20 @@
 				"%s: Firmware image size = %d\n",
 				__func__, fw_entry->size);
 
-		fw_image = fw_entry->data;
+		fwu->data_buffer = fw_entry->data;
 	}
 
-	parse_header(&header, fw_image);
+	parse_header();
+	flash_area = fwu_go_nogo();
 
-	if (header.image_size)
-		fwu->firmware_data = fw_image + FW_IMAGE_OFFSET;
-	if (header.config_size) {
-		fwu->config_data = fw_image + FW_IMAGE_OFFSET +
-				header.image_size;
+	if (fwu->rmi4_data->sensor_sleep) {
+		dev_err(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Sensor sleeping\n",
+			__func__);
+		retval = -ENODEV;
+		goto exit;
 	}
-
-	if (fwu->ext_data_source)
-		flash_area = UI_FIRMWARE;
-	else
-		flash_area = fwu_go_nogo(&header);
+	fwu->rmi4_data->stay_awake = true;
 
 	switch (flash_area) {
 	case NONE:
@@ -1326,14 +1590,14 @@
 		dev_err(&fwu->rmi4_data->i2c_client->dev,
 				"%s: Unknown flash area\n",
 				__func__);
+		retval = -EINVAL;
 		goto exit;
 	}
 
-	if (retval < 0) {
+	if (retval < 0)
 		dev_err(&fwu->rmi4_data->i2c_client->dev,
 				"%s: Failed to do reflash\n",
 				__func__);
-	}
 
 	/* reset device */
 	fwu_reset_device();
@@ -1353,8 +1617,6 @@
 		dev_info(&fwu->rmi4_data->i2c_client->dev,
 				"%s: Device is in flash prog mode 0x%02X\n",
 				__func__, f01_device_status.status_code);
-		retval = 0;
-		goto exit;
 	}
 
 exit:
@@ -1362,10 +1624,11 @@
 		release_firmware(fw_entry);
 
 	pr_notice("%s: End of reflash process\n", __func__);
+	fwu->rmi4_data->stay_awake = false;
 	return retval;
 }
 
-int synaptics_fw_updater(unsigned char *fw_data)
+int synaptics_fw_updater(void)
 {
 	int retval;
 
@@ -1383,7 +1646,6 @@
 		return -EBUSY;
 	}
 
-	fwu->ext_data_source = fw_data;
 	fwu->config_area = UI_CONFIG_AREA;
 
 	retval = fwu_start_reflash();
@@ -1421,12 +1683,13 @@
 			(const void *)buf,
 			count);
 
+	fwu->data_buffer = fwu->ext_data_source;
 	fwu->data_pos += count;
 
 	return count;
 }
 
-static ssize_t fwu_sysfs_fw_name_store(struct device *dev,
+static ssize_t fwu_sysfs_image_name_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
@@ -1450,7 +1713,7 @@
 	return count;
 }
 
-static ssize_t fwu_sysfs_fw_name_show(struct device *dev,
+static ssize_t fwu_sysfs_image_name_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
 	if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) > 0)
@@ -1476,9 +1739,11 @@
 		retval = -EINVAL;
 		goto exit;
 	}
+	if (LOCKDOWN)
+		fwu->do_lockdown = true;
 
 	fwu->force_update = true;
-	retval = synaptics_fw_updater(fwu->ext_data_source);
+	retval = synaptics_fw_updater();
 	if (retval < 0) {
 		dev_err(&rmi4_data->i2c_client->dev,
 				"%s: Failed to do reflash\n",
@@ -1491,6 +1756,8 @@
 exit:
 	kfree(fwu->ext_data_source);
 	fwu->ext_data_source = NULL;
+	fwu->force_update = FORCE_UPDATE;
+	fwu->do_lockdown = DO_LOCKDOWN;
 	return retval;
 }
 
@@ -1506,15 +1773,58 @@
 		goto exit;
 	}
 
+	if (input & LOCKDOWN) {
+		fwu->do_lockdown = true;
+		input &= ~LOCKDOWN;
+	}
+
+	if ((input != NORMAL) && (input != FORCE)) {
+		retval = -EINVAL;
+		goto exit;
+	}
+
+	if (input == FORCE)
+		fwu->force_update = true;
+
+	retval = synaptics_fw_updater();
+	if (retval < 0) {
+		dev_err(&rmi4_data->i2c_client->dev,
+				"%s: Failed to do reflash\n",
+				__func__);
+		goto exit;
+	}
+
+	retval = count;
+
+exit:
+	kfree(fwu->ext_data_source);
+	fwu->ext_data_source = NULL;
+	fwu->force_update = FORCE_UPDATE;
+	fwu->do_lockdown = DO_LOCKDOWN;
+	return retval;
+}
+
+static ssize_t fwu_sysfs_write_lockdown_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int retval;
+	unsigned int input;
+	struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+
+	if (sscanf(buf, "%u", &input) != 1) {
+		retval = -EINVAL;
+		goto exit;
+	}
+
 	if (input != 1) {
 		retval = -EINVAL;
 		goto exit;
 	}
 
-	retval = synaptics_fw_updater(fwu->ext_data_source);
+	retval = fwu_start_write_lockdown();
 	if (retval < 0) {
 		dev_err(&rmi4_data->i2c_client->dev,
-				"%s: Failed to do reflash\n",
+				"%s: Failed to write lockdown block\n",
 				__func__);
 		goto exit;
 	}
@@ -1524,6 +1834,8 @@
 exit:
 	kfree(fwu->ext_data_source);
 	fwu->ext_data_source = NULL;
+	fwu->force_update = FORCE_UPDATE;
+	fwu->do_lockdown = DO_LOCKDOWN;
 	return retval;
 }
 
@@ -1714,7 +2026,7 @@
 		unsigned char intr_mask)
 {
 	if (fwu->intr_mask & intr_mask)
-		fwu_read_f34_flash_status();
+		fwu->interrupt_flag = true;
 
 	return;
 }
@@ -1731,8 +2043,8 @@
 
 static struct device_attribute attrs[] = {
 	__ATTR(fw_name, S_IRUGO | S_IWUSR | S_IWGRP,
-			fwu_sysfs_fw_name_show,
-			fwu_sysfs_fw_name_store),
+			fwu_sysfs_image_name_show,
+			fwu_sysfs_image_name_store),
 	__ATTR(force_update_fw, S_IRUGO | S_IWUSR | S_IWGRP,
 			synaptics_rmi4_show_error,
 			fwu_sysfs_force_reflash_store),
@@ -1742,6 +2054,9 @@
 	__ATTR(writeconfig, S_IRUGO | S_IWUSR | S_IWGRP,
 			synaptics_rmi4_show_error,
 			fwu_sysfs_write_config_store),
+	__ATTR(writelockdown, S_IWUGO,
+			synaptics_rmi4_show_error,
+			fwu_sysfs_write_lockdown_store),
 	__ATTR(readconfig, S_IRUGO | S_IWUSR | S_IWGRP,
 			synaptics_rmi4_show_error,
 			fwu_sysfs_read_config_store),
@@ -1851,6 +2166,9 @@
 
 	fwu->initialized = true;
 	fwu->force_update = FORCE_UPDATE;
+	fwu->do_lockdown = DO_LOCKDOWN;
+	fwu->initialized = true;
+	fwu->polling_mode = false;
 
 	retval = sysfs_create_bin_file(&rmi4_data->i2c_client->dev.kobj,
 			&dev_attr_data);
@@ -1900,24 +2218,23 @@
 			msecs_to_jiffies(1000));
 #endif
 
-	init_completion(&remove_complete);
-
 	return 0;
 exit_free_ts_info:
 	debugfs_remove(temp);
 exit_remove_attrs:
-for (attr_count--; attr_count >= 0; attr_count--) {
-	sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
-			&attrs[attr_count].attr);
-}
+	for (attr_count--; attr_count >= 0; attr_count--) {
+		sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
+				&attrs[attr_count].attr);
+	}
 
-sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
+	sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
 
 exit_free_mem:
 	kfree(fwu->fn_ptr);
 
 exit_free_fwu:
 	kfree(fwu);
+	fwu = NULL;
 
 exit:
 	return 0;
@@ -1934,10 +2251,11 @@
 				&attrs[attr_count].attr);
 	}
 
+	kfree(fwu->read_config_buf);
 	kfree(fwu->fn_ptr);
 	kfree(fwu);
 
-	complete(&remove_complete);
+	complete(&fwu_remove_complete);
 
 	return;
 }
@@ -1957,7 +2275,7 @@
 			synaptics_rmi4_fwu_init,
 			synaptics_rmi4_fwu_remove,
 			synaptics_rmi4_fwu_attn);
-	wait_for_completion(&remove_complete);
+	wait_for_completion(&fwu_remove_complete);
 	return;
 }
 
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index ba0be2b..f8ab5f4 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -93,6 +93,8 @@
 #define RMI4_I2C_LPM_LOAD_UA	10
 
 #define RMI4_GPIO_SLEEP_LOW_US 10000
+#define F12_FINGERS_TO_SUPPORT 10
+#define MAX_F11_TOUCH_WIDTH 15
 
 static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
 		unsigned short addr, unsigned char *data,
@@ -168,6 +170,131 @@
 	};
 };
 
+struct synaptics_rmi4_f12_query_5 {
+	union {
+		struct {
+			unsigned char size_of_query6;
+			struct {
+				unsigned char ctrl0_is_present:1;
+				unsigned char ctrl1_is_present:1;
+				unsigned char ctrl2_is_present:1;
+				unsigned char ctrl3_is_present:1;
+				unsigned char ctrl4_is_present:1;
+				unsigned char ctrl5_is_present:1;
+				unsigned char ctrl6_is_present:1;
+				unsigned char ctrl7_is_present:1;
+			} __packed;
+			struct {
+				unsigned char ctrl8_is_present:1;
+				unsigned char ctrl9_is_present:1;
+				unsigned char ctrl10_is_present:1;
+				unsigned char ctrl11_is_present:1;
+				unsigned char ctrl12_is_present:1;
+				unsigned char ctrl13_is_present:1;
+				unsigned char ctrl14_is_present:1;
+				unsigned char ctrl15_is_present:1;
+			} __packed;
+			struct {
+				unsigned char ctrl16_is_present:1;
+				unsigned char ctrl17_is_present:1;
+				unsigned char ctrl18_is_present:1;
+				unsigned char ctrl19_is_present:1;
+				unsigned char ctrl20_is_present:1;
+				unsigned char ctrl21_is_present:1;
+				unsigned char ctrl22_is_present:1;
+				unsigned char ctrl23_is_present:1;
+			} __packed;
+			struct {
+				unsigned char ctrl24_is_present:1;
+				unsigned char ctrl25_is_present:1;
+				unsigned char ctrl26_is_present:1;
+				unsigned char ctrl27_is_present:1;
+				unsigned char ctrl28_is_present:1;
+				unsigned char ctrl29_is_present:1;
+				unsigned char ctrl30_is_present:1;
+				unsigned char ctrl31_is_present:1;
+			} __packed;
+		};
+		unsigned char data[5];
+	};
+};
+
+struct synaptics_rmi4_f12_query_8 {
+	union {
+		struct {
+			unsigned char size_of_query9;
+			struct {
+				unsigned char data0_is_present:1;
+				unsigned char data1_is_present:1;
+				unsigned char data2_is_present:1;
+				unsigned char data3_is_present:1;
+				unsigned char data4_is_present:1;
+				unsigned char data5_is_present:1;
+				unsigned char data6_is_present:1;
+				unsigned char data7_is_present:1;
+			} __packed;
+			struct {
+				unsigned char data8_is_present:1;
+				unsigned char data9_is_present:1;
+				unsigned char data10_is_present:1;
+				unsigned char data11_is_present:1;
+				unsigned char data12_is_present:1;
+				unsigned char data13_is_present:1;
+				unsigned char data14_is_present:1;
+				unsigned char data15_is_present:1;
+			} __packed;
+		};
+		unsigned char data[3];
+	};
+};
+
+struct synaptics_rmi4_f12_ctrl_8 {
+	union {
+		struct {
+			unsigned char max_x_coord_lsb;
+			unsigned char max_x_coord_msb;
+			unsigned char max_y_coord_lsb;
+			unsigned char max_y_coord_msb;
+			unsigned char rx_pitch_lsb;
+			unsigned char rx_pitch_msb;
+			unsigned char tx_pitch_lsb;
+			unsigned char tx_pitch_msb;
+			unsigned char low_rx_clip;
+			unsigned char high_rx_clip;
+			unsigned char low_tx_clip;
+			unsigned char high_tx_clip;
+			unsigned char num_of_rx;
+			unsigned char num_of_tx;
+		};
+		unsigned char data[14];
+	};
+};
+
+struct synaptics_rmi4_f12_ctrl_23 {
+	union {
+		struct {
+			unsigned char obj_type_enable;
+			unsigned char max_reported_objects;
+		};
+		unsigned char data[2];
+	};
+};
+
+struct synaptics_rmi4_f12_finger_data {
+	unsigned char object_type_and_status;
+	unsigned char x_lsb;
+	unsigned char x_msb;
+	unsigned char y_lsb;
+	unsigned char y_msb;
+#ifdef REPORT_2D_Z
+	unsigned char z;
+#endif
+#ifdef REPORT_2D_W
+	unsigned char wx;
+	unsigned char wy;
+#endif
+};
+
 struct synaptics_rmi4_f1a_query {
 	union {
 		struct {
@@ -223,6 +350,13 @@
 	struct synaptics_rmi4_f1a_control button_control;
 };
 
+struct synaptics_rmi4_f12_extra_data {
+	unsigned char data1_offset;
+	unsigned char data15_offset;
+	unsigned char data15_size;
+	unsigned char data15_data[(F12_FINGERS_TO_SUPPORT + 7) / 8];
+};
+
 struct synaptics_rmi4_exp_fn {
 	enum exp_fn fn_type;
 	bool inserted;
@@ -360,8 +494,8 @@
 	retval = synaptics_rmi4_reset_device(rmi4_data);
 	if (retval < 0) {
 		dev_err(dev,
-				"%s: Failed to issue reset command, error = %d\n",
-				__func__, retval);
+			"%s: Failed to issue reset command, error = %d\n",
+			__func__, retval);
 		return retval;
 	}
 
@@ -817,10 +951,7 @@
 	if (!touch_count)
 		input_mt_sync(rmi4_data->input_dev);
 #else
-	/* sync after groups of events */
-	#ifdef KERNEL_ABOVE_3_7
-	input_mt_sync_frame(rmi4_data->input_dev);
-	#endif
+	input_mt_report_pointer_emulation(rmi4_data->input_dev, false);
 #endif
 
 	input_sync(rmi4_data->input_dev);
@@ -828,6 +959,125 @@
 	return touch_count;
 }
 
+ /**
+ * synaptics_rmi4_f12_abs_report()
+ *
+ * Called by synaptics_rmi4_report_touch() when valid Function $12
+ * finger data has been detected.
+ *
+ * This function reads the Function $12 data registers, determines the
+ * status of each finger supported by the Function, processes any
+ * necessary coordinate manipulation, reports the finger data to
+ * the input subsystem, and returns the number of fingers detected.
+ */
+static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data,
+		struct synaptics_rmi4_fn *fhandler)
+{
+	int retval;
+	unsigned char touch_count = 0; /* number of touch points */
+	unsigned char finger;
+	unsigned char fingers_to_process;
+	unsigned char finger_status;
+	unsigned char size_of_2d_data;
+	unsigned short data_addr;
+	int x;
+	int y;
+	int wx;
+	int wy;
+	struct synaptics_rmi4_f12_extra_data *extra_data;
+	struct synaptics_rmi4_f12_finger_data *data;
+	struct synaptics_rmi4_f12_finger_data *finger_data;
+
+	fingers_to_process = fhandler->num_of_data_points;
+	data_addr = fhandler->full_addr.data_base;
+	extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra;
+	size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data);
+
+	retval = synaptics_rmi4_i2c_read(rmi4_data,
+			data_addr + extra_data->data1_offset,
+			(unsigned char *)fhandler->data,
+			fingers_to_process * size_of_2d_data);
+	if (retval < 0)
+		return 0;
+
+	data = (struct synaptics_rmi4_f12_finger_data *)fhandler->data;
+
+	for (finger = 0; finger < fingers_to_process; finger++) {
+		finger_data = data + finger;
+		finger_status = finger_data->object_type_and_status & MASK_2BIT;
+
+		/*
+		 * Each 2-bit finger status field represents the following:
+		 * 00 = finger not present
+		 * 01 = finger present and data accurate
+		 * 10 = finger present but data may be inaccurate
+		 * 11 = reserved
+		 */
+#ifdef TYPE_B_PROTOCOL
+		input_mt_slot(rmi4_data->input_dev, finger);
+		input_mt_report_slot_state(rmi4_data->input_dev,
+				MT_TOOL_FINGER, finger_status != 0);
+#endif
+
+		if (finger_status) {
+			x = (finger_data->x_msb << 8) | (finger_data->x_lsb);
+			y = (finger_data->y_msb << 8) | (finger_data->y_lsb);
+#ifdef REPORT_2D_W
+			wx = finger_data->wx;
+			wy = finger_data->wy;
+#endif
+
+			if (rmi4_data->board->x_flip)
+				x = rmi4_data->sensor_max_x - x;
+			if (rmi4_data->board->y_flip)
+				y = rmi4_data->sensor_max_y - y;
+
+			dev_dbg(&rmi4_data->i2c_client->dev,
+					"%s: Finger %d:\n"
+					"status = 0x%02x\n"
+					"x = %d\n"
+					"y = %d\n"
+					"wx = %d\n"
+					"wy = %d\n",
+					__func__, finger,
+					finger_status,
+					x, y, wx, wy);
+
+			input_report_key(rmi4_data->input_dev,
+					BTN_TOUCH, 1);
+			input_report_key(rmi4_data->input_dev,
+					BTN_TOOL_FINGER, 1);
+			input_report_abs(rmi4_data->input_dev,
+					ABS_MT_POSITION_X, x);
+			input_report_abs(rmi4_data->input_dev,
+					ABS_MT_POSITION_Y, y);
+#ifdef REPORT_2D_W
+			input_report_abs(rmi4_data->input_dev,
+					ABS_MT_TOUCH_MAJOR, max(wx, wy));
+			input_report_abs(rmi4_data->input_dev,
+					ABS_MT_TOUCH_MINOR, min(wx, wy));
+#endif
+#ifndef TYPE_B_PROTOCOL
+			input_mt_sync(rmi4_data->input_dev);
+#endif
+			touch_count++;
+		}
+	}
+
+	input_report_key(rmi4_data->input_dev,
+			BTN_TOUCH, touch_count > 0);
+	input_report_key(rmi4_data->input_dev,
+			BTN_TOOL_FINGER, touch_count > 0);
+#ifndef TYPE_B_PROTOCOL
+	if (!touch_count)
+		input_mt_sync(rmi4_data->input_dev);
+#endif
+	input_mt_report_pointer_emulation(rmi4_data->input_dev, false);
+	input_sync(rmi4_data->input_dev);
+
+	return touch_count;
+}
+
 static void synaptics_rmi4_f1a_report(struct synaptics_rmi4_data *rmi4_data,
 		struct synaptics_rmi4_fn *fhandler)
 {
@@ -955,6 +1205,16 @@
 			rmi4_data->fingers_on_2d = false;
 		break;
 
+	case SYNAPTICS_RMI4_F12:
+		touch_count_2d = synaptics_rmi4_f12_abs_report(rmi4_data,
+				fhandler);
+
+		if (touch_count_2d)
+			rmi4_data->fingers_on_2d = true;
+		else
+			rmi4_data->fingers_on_2d = false;
+		break;
+
 	case SYNAPTICS_RMI4_F1A:
 		synaptics_rmi4_f1a_report(rmi4_data, fhandler);
 		break;
@@ -1045,6 +1305,7 @@
 	return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_OF
 static int synaptics_rmi4_parse_dt(struct device *dev,
 				struct synaptics_rmi4_platform_data *rmi4_pdata)
 {
@@ -1056,6 +1317,10 @@
 
 	rmi4_pdata->i2c_pull_up = of_property_read_bool(np,
 			"synaptics,i2c-pull-up");
+	rmi4_pdata->power_down_enable = of_property_read_bool(np,
+			"synaptics,power-down");
+	rmi4_pdata->disable_gpios = of_property_read_bool(np,
+			"synaptics,disable-gpios");
 	rmi4_pdata->x_flip = of_property_read_bool(np, "synaptics,x-flip");
 	rmi4_pdata->y_flip = of_property_read_bool(np, "synaptics,y-flip");
 
@@ -1123,6 +1388,13 @@
 	}
 	return 0;
 }
+#else
+static inline int synaptics_rmi4_parse_dt(struct device *dev,
+				struct synaptics_rmi4_platform_data *rmi4_pdata)
+{
+	return 0;
+}
+#endif
 
  /**
  * synaptics_rmi4_irq_enable()
@@ -1233,6 +1505,8 @@
 			rmi4_data->sensor_max_x,
 			rmi4_data->sensor_max_y);
 
+	rmi4_data->max_touch_width = MAX_F11_TOUCH_WIDTH;
+
 	fhandler->intr_reg_num = (intr_count + 7) / 8;
 	if (fhandler->intr_reg_num != 0)
 		fhandler->intr_reg_num -= 1;
@@ -1253,6 +1527,212 @@
 	return retval;
 }
 
+static int synaptics_rmi4_f12_set_enables(struct synaptics_rmi4_data *rmi4_data,
+		unsigned short ctrl28)
+{
+	int retval;
+	static unsigned short ctrl_28_address;
+
+	if (ctrl28)
+		ctrl_28_address = ctrl28;
+
+	retval = synaptics_rmi4_i2c_write(rmi4_data,
+			ctrl_28_address,
+			&rmi4_data->report_enable,
+			sizeof(rmi4_data->report_enable));
+	if (retval < 0)
+		return retval;
+
+	return retval;
+}
+
+ /**
+ * synaptics_rmi4_f12_init()
+ *
+ * Called by synaptics_rmi4_query_device().
+ *
+ * This funtion parses information from the Function 12 registers and
+ * determines the number of fingers supported, offset to the data1
+ * register, x and y data ranges, offset to the associated interrupt
+ * status register, interrupt bit mask, and allocates memory resources
+ * for finger data acquisition.
+ */
+static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data,
+		struct synaptics_rmi4_fn *fhandler,
+		struct synaptics_rmi4_fn_desc *fd,
+		unsigned int intr_count)
+{
+	int retval;
+	unsigned char ii;
+	unsigned char intr_offset;
+	unsigned char size_of_2d_data;
+	unsigned char size_of_query8;
+	unsigned char ctrl_8_offset;
+	unsigned char ctrl_23_offset;
+	unsigned char ctrl_28_offset;
+	unsigned char num_of_fingers;
+	struct synaptics_rmi4_f12_extra_data *extra_data;
+	struct synaptics_rmi4_f12_query_5 query_5;
+	struct synaptics_rmi4_f12_query_8 query_8;
+	struct synaptics_rmi4_f12_ctrl_8 ctrl_8;
+	struct synaptics_rmi4_f12_ctrl_23 ctrl_23;
+
+	fhandler->fn_number = fd->fn_number;
+	fhandler->num_of_data_sources = fd->intr_src_count;
+	fhandler->extra = kmalloc(sizeof(*extra_data), GFP_KERNEL);
+	extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra;
+	size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data);
+
+	retval = synaptics_rmi4_i2c_read(rmi4_data,
+			fhandler->full_addr.query_base + 5,
+			query_5.data,
+			sizeof(query_5.data));
+	if (retval < 0)
+		return retval;
+
+	ctrl_8_offset = query_5.ctrl0_is_present +
+			query_5.ctrl1_is_present +
+			query_5.ctrl2_is_present +
+			query_5.ctrl3_is_present +
+			query_5.ctrl4_is_present +
+			query_5.ctrl5_is_present +
+			query_5.ctrl6_is_present +
+			query_5.ctrl7_is_present;
+
+	ctrl_23_offset = ctrl_8_offset +
+			query_5.ctrl8_is_present +
+			query_5.ctrl9_is_present +
+			query_5.ctrl10_is_present +
+			query_5.ctrl11_is_present +
+			query_5.ctrl12_is_present +
+			query_5.ctrl13_is_present +
+			query_5.ctrl14_is_present +
+			query_5.ctrl15_is_present +
+			query_5.ctrl16_is_present +
+			query_5.ctrl17_is_present +
+			query_5.ctrl18_is_present +
+			query_5.ctrl19_is_present +
+			query_5.ctrl20_is_present +
+			query_5.ctrl21_is_present +
+			query_5.ctrl22_is_present;
+
+	ctrl_28_offset = ctrl_23_offset +
+			query_5.ctrl23_is_present +
+			query_5.ctrl24_is_present +
+			query_5.ctrl25_is_present +
+			query_5.ctrl26_is_present +
+			query_5.ctrl27_is_present;
+
+	retval = synaptics_rmi4_i2c_read(rmi4_data,
+			fhandler->full_addr.ctrl_base + ctrl_23_offset,
+			ctrl_23.data,
+			sizeof(ctrl_23.data));
+	if (retval < 0)
+		return retval;
+
+	/* Maximum number of fingers supported */
+	fhandler->num_of_data_points = min(ctrl_23.max_reported_objects,
+			(unsigned char)F12_FINGERS_TO_SUPPORT);
+
+	num_of_fingers = fhandler->num_of_data_points;
+	rmi4_data->num_of_fingers = num_of_fingers;
+
+	retval = synaptics_rmi4_i2c_read(rmi4_data,
+			fhandler->full_addr.query_base + 7,
+			&size_of_query8,
+			sizeof(size_of_query8));
+	if (retval < 0)
+		return retval;
+
+	retval = synaptics_rmi4_i2c_read(rmi4_data,
+			fhandler->full_addr.query_base + 8,
+			query_8.data,
+			size_of_query8);
+	if (retval < 0)
+		return retval;
+
+	/* Determine the presence of the Data0 register */
+	extra_data->data1_offset = query_8.data0_is_present;
+
+	if ((size_of_query8 >= 3) && (query_8.data15_is_present)) {
+		extra_data->data15_offset = query_8.data0_is_present +
+				query_8.data1_is_present +
+				query_8.data2_is_present +
+				query_8.data3_is_present +
+				query_8.data4_is_present +
+				query_8.data5_is_present +
+				query_8.data6_is_present +
+				query_8.data7_is_present +
+				query_8.data8_is_present +
+				query_8.data9_is_present +
+				query_8.data10_is_present +
+				query_8.data11_is_present +
+				query_8.data12_is_present +
+				query_8.data13_is_present +
+				query_8.data14_is_present;
+		extra_data->data15_size = (num_of_fingers + 7) / 8;
+	} else {
+		extra_data->data15_size = 0;
+	}
+
+	rmi4_data->report_enable = RPT_DEFAULT;
+#ifdef REPORT_2D_Z
+	rmi4_data->report_enable |= RPT_Z;
+#endif
+#ifdef REPORT_2D_W
+	rmi4_data->report_enable |= (RPT_WX | RPT_WY);
+#endif
+
+	retval = synaptics_rmi4_f12_set_enables(rmi4_data,
+			fhandler->full_addr.ctrl_base + ctrl_28_offset);
+	if (retval < 0)
+		return retval;
+
+	retval = synaptics_rmi4_i2c_read(rmi4_data,
+			fhandler->full_addr.ctrl_base + ctrl_8_offset,
+			ctrl_8.data,
+			sizeof(ctrl_8.data));
+	if (retval < 0)
+		return retval;
+
+	/* Maximum x and y */
+	rmi4_data->sensor_max_x =
+			((unsigned short)ctrl_8.max_x_coord_lsb << 0) |
+			((unsigned short)ctrl_8.max_x_coord_msb << 8);
+	rmi4_data->sensor_max_y =
+			((unsigned short)ctrl_8.max_y_coord_lsb << 0) |
+			((unsigned short)ctrl_8.max_y_coord_msb << 8);
+	dev_dbg(&rmi4_data->i2c_client->dev,
+			"%s: Function %02x max x = %d max y = %d\n",
+			__func__, fhandler->fn_number,
+			rmi4_data->sensor_max_x,
+			rmi4_data->sensor_max_y);
+
+	rmi4_data->num_of_rx = ctrl_8.num_of_rx;
+	rmi4_data->num_of_tx = ctrl_8.num_of_tx;
+	rmi4_data->max_touch_width = max(rmi4_data->num_of_rx,
+			rmi4_data->num_of_tx);
+
+	fhandler->intr_reg_num = (intr_count + 7) / 8;
+	if (fhandler->intr_reg_num != 0)
+		fhandler->intr_reg_num -= 1;
+
+	/* Set an enable bit for each data source */
+	intr_offset = intr_count % 8;
+	fhandler->intr_mask = 0;
+	for (ii = intr_offset;
+			ii < ((fd->intr_src_count & MASK_3BIT) +
+			intr_offset);
+			ii++)
+		fhandler->intr_mask |= 1 << ii;
+
+	/* Allocate memory for finger data storage space */
+	fhandler->data_size = num_of_fingers * size_of_2d_data;
+	fhandler->data = kmalloc(fhandler->data_size, GFP_KERNEL);
+
+	return retval;
+}
+
 static int synaptics_rmi4_f1a_alloc_mem(struct synaptics_rmi4_data *rmi4_data,
 		struct synaptics_rmi4_fn *fhandler)
 {
@@ -1597,6 +2077,26 @@
 					return retval;
 				break;
 
+			case SYNAPTICS_RMI4_F12:
+				if (rmi_fd.intr_src_count == 0)
+					break;
+
+				retval = synaptics_rmi4_alloc_fh(&fhandler,
+						&rmi_fd, page_number);
+				if (retval < 0) {
+					dev_err(&rmi4_data->i2c_client->dev,
+							"%s: Failed to alloc for F%d\n",
+							__func__,
+							rmi_fd.fn_number);
+					return retval;
+				}
+
+				retval = synaptics_rmi4_f12_init(rmi4_data,
+						fhandler, &rmi_fd, intr_count);
+				if (retval < 0)
+					return retval;
+				break;
+
 			case SYNAPTICS_RMI4_F1A:
 				if (rmi_fd.intr_src_count == 0)
 					break;
@@ -1740,6 +2240,7 @@
 {
 	int retval;
 	struct synaptics_rmi4_fn *fhandler;
+	struct synaptics_rmi4_fn *next_fhandler;
 	struct synaptics_rmi4_device_info *rmi;
 
 	rmi = &(rmi4_data->rmi4_mod_info);
@@ -1753,11 +2254,14 @@
 	}
 
 	if (!list_empty(&rmi->support_fn_list)) {
-		list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+		list_for_each_entry_safe(fhandler, next_fhandler,
+					&rmi->support_fn_list, link) {
 			if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
 				synaptics_rmi4_f1a_kfree(fhandler);
-			else
+			else {
 				kfree(fhandler->data);
+				kfree(fhandler->extra);
+			}
 			kfree(fhandler);
 		}
 	}
@@ -2003,7 +2507,7 @@
 
 error_reg_en_vcc_i2c:
 	if (rmi4_data->board->i2c_pull_up)
-		reg_set_optimum_mode_check(rmi4_data->vdd, 0);
+		reg_set_optimum_mode_check(rmi4_data->vcc_i2c, 0);
 error_reg_opt_i2c:
 	regulator_disable(rmi4_data->vdd);
 error_reg_en_vdd:
@@ -2020,6 +2524,85 @@
 	return 0;
 }
 
+static int synaptics_rmi4_gpio_configure(struct synaptics_rmi4_data *rmi4_data,
+					bool on)
+{
+	int retval = 0;
+
+	if (on) {
+		if (gpio_is_valid(rmi4_data->board->irq_gpio)) {
+			/* configure touchscreen irq gpio */
+			retval = gpio_request(rmi4_data->board->irq_gpio,
+				"rmi4_irq_gpio");
+			if (retval) {
+				dev_err(&rmi4_data->i2c_client->dev,
+					"unable to request gpio [%d]\n",
+					rmi4_data->board->irq_gpio);
+				goto err_irq_gpio_req;
+			}
+			retval = gpio_direction_input(rmi4_data->board->\
+				irq_gpio);
+			if (retval) {
+				dev_err(&rmi4_data->i2c_client->dev,
+					"unable to set direction for gpio " \
+					"[%d]\n", rmi4_data->board->irq_gpio);
+				goto err_irq_gpio_dir;
+			}
+		} else {
+			dev_err(&rmi4_data->i2c_client->dev,
+				"irq gpio not provided\n");
+			goto err_irq_gpio_req;
+		}
+
+		if (gpio_is_valid(rmi4_data->board->reset_gpio)) {
+			/* configure touchscreen reset out gpio */
+			retval = gpio_request(rmi4_data->board->reset_gpio,
+					"rmi4_reset_gpio");
+			if (retval) {
+				dev_err(&rmi4_data->i2c_client->dev,
+					"unable to request gpio [%d]\n",
+					rmi4_data->board->reset_gpio);
+				goto err_irq_gpio_dir;
+			}
+
+			retval = gpio_direction_output(rmi4_data->board->\
+				reset_gpio, 1);
+			if (retval) {
+				dev_err(&rmi4_data->i2c_client->dev,
+					"unable to set direction for gpio " \
+					"[%d]\n", rmi4_data->board->reset_gpio);
+				goto err_reset_gpio_dir;
+			}
+
+			gpio_set_value(rmi4_data->board->reset_gpio, 0);
+			usleep(RMI4_GPIO_SLEEP_LOW_US);
+			gpio_set_value(rmi4_data->board->reset_gpio, 1);
+			msleep(RESET_DELAY);
+		} else
+			synaptics_rmi4_reset_command(rmi4_data);
+
+		return 0;
+	} else {
+		if (rmi4_data->board->disable_gpios) {
+			if (gpio_is_valid(rmi4_data->board->irq_gpio))
+				gpio_free(rmi4_data->board->irq_gpio);
+			if (gpio_is_valid(rmi4_data->board->reset_gpio))
+				gpio_free(rmi4_data->board->reset_gpio);
+		}
+
+		return 0;
+	}
+
+err_reset_gpio_dir:
+	if (gpio_is_valid(rmi4_data->board->reset_gpio))
+		gpio_free(rmi4_data->board->reset_gpio);
+err_irq_gpio_dir:
+	if (gpio_is_valid(rmi4_data->board->irq_gpio))
+		gpio_free(rmi4_data->board->irq_gpio);
+err_irq_gpio_req:
+	return retval;
+}
+
  /**
  * synaptics_rmi4_probe()
  *
@@ -2042,6 +2625,7 @@
 	unsigned char attr_count;
 	struct synaptics_rmi4_f1a_handle *f1a;
 	struct synaptics_rmi4_fn *fhandler;
+	struct synaptics_rmi4_fn *next_fhandler;
 	struct synaptics_rmi4_data *rmi4_data;
 	struct synaptics_rmi4_device_info *rmi;
 	struct synaptics_rmi4_platform_data *platform_data =
@@ -2149,52 +2733,12 @@
 		goto err_power_device;
 	}
 
-	if (gpio_is_valid(platform_data->irq_gpio)) {
-		/* configure touchscreen irq gpio */
-		retval = gpio_request(platform_data->irq_gpio, "rmi4_irq_gpio");
-		if (retval) {
-			dev_err(&client->dev, "unable to request gpio [%d]\n",
-						platform_data->irq_gpio);
-			goto err_irq_gpio_req;
-		}
-		retval = gpio_direction_input(platform_data->irq_gpio);
-		if (retval) {
-			dev_err(&client->dev,
-				"unable to set direction for gpio [%d]\n",
-				platform_data->irq_gpio);
-			goto err_irq_gpio_dir;
-		}
-	} else {
-		dev_err(&client->dev, "irq gpio not provided\n");
-		goto err_irq_gpio_req;
+	retval = synaptics_rmi4_gpio_configure(rmi4_data, true);
+	if (retval < 0) {
+		dev_err(&client->dev, "Failed to configure gpios\n");
+		goto err_gpio_config;
 	}
 
-	if (gpio_is_valid(platform_data->reset_gpio)) {
-		/* configure touchscreen reset out gpio */
-		retval = gpio_request(platform_data->reset_gpio,
-				"rmi4_reset_gpio");
-		if (retval) {
-			dev_err(&client->dev, "unable to request gpio [%d]\n",
-						platform_data->reset_gpio);
-			goto err_irq_gpio_dir;
-		}
-
-		retval = gpio_direction_output(platform_data->reset_gpio, 1);
-		if (retval) {
-			dev_err(&client->dev,
-				"unable to set direction for gpio [%d]\n",
-				platform_data->reset_gpio);
-			goto err_reset_gpio_dir;
-		}
-
-		gpio_set_value(platform_data->reset_gpio, 0);
-		usleep(RMI4_GPIO_SLEEP_LOW_US);
-		gpio_set_value(platform_data->reset_gpio, 1);
-		msleep(RESET_DELAY);
-	} else
-		synaptics_rmi4_reset_command(rmi4_data);
-
-
 	init_waitqueue_head(&rmi4_data->wait);
 	mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex));
 
@@ -2203,7 +2747,7 @@
 		dev_err(&client->dev,
 				"%s: Failed to query device\n",
 				__func__);
-		goto err_reset_gpio_dir;
+		goto err_free_gpios;
 	}
 
 	input_set_abs_params(rmi4_data->input_dev,
@@ -2217,7 +2761,10 @@
 #ifdef REPORT_2D_W
 	input_set_abs_params(rmi4_data->input_dev,
 			ABS_MT_TOUCH_MAJOR, 0,
-			MAX_ABS_MT_TOUCH_MAJOR, 0, 0);
+			rmi4_data->max_touch_width, 0, 0);
+	input_set_abs_params(rmi4_data->input_dev,
+			ABS_MT_TOUCH_MINOR, 0,
+			rmi4_data->max_touch_width, 0, 0);
 #endif
 
 #ifdef TYPE_B_PROTOCOL
@@ -2338,21 +2885,23 @@
 
 err_register_input:
 	if (!list_empty(&rmi->support_fn_list)) {
-		list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+		list_for_each_entry_safe(fhandler, next_fhandler,
+					&rmi->support_fn_list, link) {
 			if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
 				synaptics_rmi4_f1a_kfree(fhandler);
-			else
+			else {
 				kfree(fhandler->data);
+				kfree(fhandler->extra);
+			}
 			kfree(fhandler);
 		}
 	}
-err_reset_gpio_dir:
-	if (gpio_is_valid(platform_data->reset_gpio))
-		gpio_free(platform_data->reset_gpio);
-err_irq_gpio_dir:
-	if (gpio_is_valid(platform_data->irq_gpio))
-		gpio_free(platform_data->irq_gpio);
-err_irq_gpio_req:
+err_free_gpios:
+	if (gpio_is_valid(rmi4_data->board->reset_gpio))
+		gpio_free(rmi4_data->board->reset_gpio);
+	if (gpio_is_valid(rmi4_data->board->irq_gpio))
+		gpio_free(rmi4_data->board->irq_gpio);
+err_gpio_config:
 	synaptics_rmi4_power_on(rmi4_data, false);
 err_power_device:
 	synaptics_rmi4_regulator_configure(rmi4_data, false);
@@ -2379,6 +2928,7 @@
 {
 	unsigned char attr_count;
 	struct synaptics_rmi4_fn *fhandler;
+	struct synaptics_rmi4_fn *next_fhandler;
 	struct synaptics_rmi4_data *rmi4_data = i2c_get_clientdata(client);
 	struct synaptics_rmi4_device_info *rmi;
 
@@ -2402,11 +2952,14 @@
 	input_unregister_device(rmi4_data->input_dev);
 
 	if (!list_empty(&rmi->support_fn_list)) {
-		list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+		list_for_each_entry_safe(fhandler, next_fhandler,
+					&rmi->support_fn_list, link) {
 			if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
 				synaptics_rmi4_f1a_kfree(fhandler);
-			else
+			else {
 				kfree(fhandler->data);
+				kfree(fhandler->extra);
+			}
 			kfree(fhandler);
 		}
 	}
@@ -2549,6 +3102,11 @@
 			container_of(h, struct synaptics_rmi4_data,
 			early_suspend);
 
+	if (rmi4_data->stay_awake)
+		rmi4_data->staying_awake = true;
+	else
+		rmi4_data->staying_awake = false;
+
 	rmi4_data->touch_stopped = true;
 	wake_up(&rmi4_data->wait);
 	synaptics_rmi4_irq_enable(rmi4_data, false);
@@ -2575,6 +3133,9 @@
 			container_of(h, struct synaptics_rmi4_data,
 			early_suspend);
 
+	if (rmi4_data->staying_awake)
+		return;
+
 	if (rmi4_data->full_pm_cycle)
 		synaptics_rmi4_resume(&(rmi4_data->input_dev->dev));
 
@@ -2592,24 +3153,48 @@
 						bool on)
 {
 	int retval;
+	int load_ua;
 
 	if (on == false)
 		goto regulator_hpm;
 
-	retval = reg_set_optimum_mode_check(rmi4_data->vdd, RMI4_LPM_LOAD_UA);
+	if (rmi4_data->board->i2c_pull_up) {
+		load_ua = rmi4_data->board->power_down_enable ?
+			0 : RMI4_I2C_LPM_LOAD_UA;
+		retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
+			load_ua);
+		if (retval < 0) {
+			dev_err(&rmi4_data->i2c_client->dev,
+				"Regulator vcc_i2c set_opt failed " \
+				"rc=%d\n", retval);
+			goto fail_regulator_lpm;
+		}
+
+		if (rmi4_data->board->power_down_enable) {
+			retval = regulator_disable(rmi4_data->vcc_i2c);
+			if (retval) {
+				dev_err(&rmi4_data->i2c_client->dev,
+					"Regulator vcc_i2c disable failed " \
+					"rc=%d\n", retval);
+				goto fail_regulator_lpm;
+			}
+		}
+	}
+
+	load_ua = rmi4_data->board->power_down_enable ? 0 : RMI4_LPM_LOAD_UA;
+	retval = reg_set_optimum_mode_check(rmi4_data->vdd, load_ua);
 	if (retval < 0) {
 		dev_err(&rmi4_data->i2c_client->dev,
-			"Regulator vcc_ana set_opt failed rc=%d\n",
+			"Regulator vdd_ana set_opt failed rc=%d\n",
 			retval);
 		goto fail_regulator_lpm;
 	}
 
-	if (rmi4_data->board->i2c_pull_up) {
-		retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
-			RMI4_I2C_LPM_LOAD_UA);
-		if (retval < 0) {
+	if (rmi4_data->board->power_down_enable) {
+		retval = regulator_disable(rmi4_data->vdd);
+		if (retval) {
 			dev_err(&rmi4_data->i2c_client->dev,
-				"Regulator vcc_i2c set_opt failed rc=%d\n",
+				"Regulator vdd disable failed rc=%d\n",
 				retval);
 			goto fail_regulator_lpm;
 		}
@@ -2628,6 +3213,16 @@
 		goto fail_regulator_hpm;
 	}
 
+	if (rmi4_data->board->power_down_enable) {
+		retval = regulator_enable(rmi4_data->vdd);
+		if (retval) {
+			dev_err(&rmi4_data->i2c_client->dev,
+				"Regulator vdd enable failed rc=%d\n",
+				retval);
+			goto fail_regulator_hpm;
+		}
+	}
+
 	if (rmi4_data->board->i2c_pull_up) {
 		retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
 			RMI4_I2C_LOAD_UA);
@@ -2637,6 +3232,16 @@
 				retval);
 			goto fail_regulator_hpm;
 		}
+
+		if (rmi4_data->board->power_down_enable) {
+			retval = regulator_enable(rmi4_data->vcc_i2c);
+			if (retval) {
+				dev_err(&rmi4_data->i2c_client->dev,
+					"Regulator vcc_i2c enable failed " \
+					"rc=%d\n", retval);
+				goto fail_regulator_hpm;
+			}
+		}
 	}
 
 	return 0;
@@ -2650,10 +3255,13 @@
 	return retval;
 
 fail_regulator_hpm:
-	reg_set_optimum_mode_check(rmi4_data->vdd, RMI4_LPM_LOAD_UA);
-	if (rmi4_data->board->i2c_pull_up)
-		reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
-						RMI4_I2C_LPM_LOAD_UA);
+	load_ua = rmi4_data->board->power_down_enable ? 0 : RMI4_LPM_LOAD_UA;
+	reg_set_optimum_mode_check(rmi4_data->vdd, load_ua);
+	if (rmi4_data->board->i2c_pull_up) {
+		load_ua = rmi4_data->board->power_down_enable ?
+				0 : RMI4_I2C_LPM_LOAD_UA;
+		reg_set_optimum_mode_check(rmi4_data->vcc_i2c, load_ua);
+	}
 	return retval;
 }
 
@@ -2672,6 +3280,12 @@
 	struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
 	int retval;
 
+	if (rmi4_data->stay_awake) {
+		rmi4_data->staying_awake = true;
+		return 0;
+	} else
+		rmi4_data->staying_awake = false;
+
 	if (rmi4_data->suspended) {
 		dev_info(dev, "Already in suspend state\n");
 		return 0;
@@ -2696,6 +3310,13 @@
 		return 0;
 	}
 
+	if (rmi4_data->board->disable_gpios) {
+		retval = synaptics_rmi4_gpio_configure(rmi4_data, false);
+		if (retval < 0) {
+			dev_err(dev, "failed to put gpios in suspend state\n");
+			return retval;
+		}
+	}
 	rmi4_data->suspended = true;
 
 	return 0;
@@ -2716,11 +3337,22 @@
 	struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
 	int retval;
 
+	if (rmi4_data->staying_awake)
+		return 0;
+
 	if (!rmi4_data->suspended) {
 		dev_info(dev, "Already in awake state\n");
 		return 0;
 	}
 
+	if (rmi4_data->board->disable_gpios) {
+		retval = synaptics_rmi4_gpio_configure(rmi4_data, true);
+		if (retval < 0) {
+			dev_err(dev, "failed to put gpios in active state\n");
+			return retval;
+		}
+	}
+
 	retval = synaptics_rmi4_regulator_lpm(rmi4_data, false);
 	if (retval < 0) {
 		dev_err(dev, "failed to enter active power mode\n");
@@ -2731,6 +3363,17 @@
 	rmi4_data->touch_stopped = false;
 	synaptics_rmi4_irq_enable(rmi4_data, true);
 
+	if (rmi4_data->board->power_down_enable ||
+			rmi4_data->board->disable_gpios) {
+		retval = synaptics_rmi4_reset_device(rmi4_data);
+		if (retval < 0) {
+			dev_err(&rmi4_data->i2c_client->dev,
+				"%s: Failed to issue reset command, " \
+				"rc = %d\n", __func__, retval);
+			return retval;
+		}
+	}
+
 	rmi4_data->suspended = false;
 
 	return 0;
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.h b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
index 5f6d6ce..677a2fe 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.h
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
@@ -45,6 +45,7 @@
 
 #define SYNAPTICS_RMI4_F01 (0x01)
 #define SYNAPTICS_RMI4_F11 (0x11)
+#define SYNAPTICS_RMI4_F12 (0x12)
 #define SYNAPTICS_RMI4_F1A (0x1a)
 #define SYNAPTICS_RMI4_F34 (0x34)
 #define SYNAPTICS_RMI4_F54 (0x54)
@@ -69,7 +70,7 @@
 #define MASK_2BIT 0x03
 #define MASK_1BIT 0x01
 
-#define NAME_BUFFER_SIZE 128
+#define NAME_BUFFER_SIZE 256
 
 /*
  * struct synaptics_rmi4_fn_desc - function descriptor fields in PDT
@@ -85,9 +86,12 @@
 	unsigned char cmd_base_addr;
 	unsigned char ctrl_base_addr;
 	unsigned char data_base_addr;
-	unsigned char intr_src_count;
+	unsigned char intr_src_count:3;
+	unsigned char reserved_b3_b4:2;
+	unsigned char version:2;
+	unsigned char reserved_b7:1;
 	unsigned char fn_number;
-};
+} __packed;
 
 /*
  * synaptics_rmi4_fn_full_addr - full 16-bit base addresses
@@ -129,6 +133,7 @@
 	struct list_head link;
 	int data_size;
 	void *data;
+	void *extra;
 };
 
 /*
@@ -214,6 +219,8 @@
 	unsigned char num_of_rx;
 	unsigned char num_of_tx;
 	unsigned char num_of_fingers;
+	unsigned char max_touch_width;
+	unsigned char report_enable;
 	unsigned char intr_mask[MAX_INTR_REGISTERS];
 	unsigned short num_of_intr_regs;
 	unsigned short f01_query_base_addr;
@@ -232,6 +239,8 @@
 	bool fw_updating;
 	bool suspended;
 	wait_queue_head_t wait;
+	bool stay_awake;
+	bool staying_awake;
 	int (*i2c_read)(struct synaptics_rmi4_data *pdata, unsigned short addr,
 			unsigned char *data, unsigned short length);
 	int (*i2c_write)(struct synaptics_rmi4_data *pdata, unsigned short addr,
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index 53c7c30..b9c4cae 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -692,6 +692,7 @@
 	if (ret)
 		goto fail;
 
+	ret = __flush_iotlb_va(domain, va);
 fail:
 	mutex_unlock(&msm_iommu_lock);
 	return ret;
@@ -741,6 +742,7 @@
 	if (ret)
 		goto fail;
 
+	__flush_iotlb(domain);
 fail:
 	mutex_unlock(&msm_iommu_lock);
 	return ret;
diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c
index 78fffb2..474efdf 100644
--- a/drivers/iommu/msm_iommu_sec.c
+++ b/drivers/iommu/msm_iommu_sec.c
@@ -371,7 +371,7 @@
 	map.info.ctx_id = ctx_drvdata->num;
 	map.info.va = va;
 	map.info.size = len;
-	map.flags = 0;
+	map.flags = IOMMU_TLBINVAL_FLAG;
 	flush_va = &pa;
 	flush_pa = virt_to_phys(&pa);
 
@@ -421,7 +421,7 @@
 	map.info.ctx_id = ctx_drvdata->num;
 	map.info.va = va;
 	map.info.size = len;
-	map.flags = 0;
+	map.flags = IOMMU_TLBINVAL_FLAG;
 
 	if (sg->length == len) {
 		pa = get_phys_addr(sg);
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index a1453ae..5a405be 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -95,6 +95,7 @@
 #define FLASH_LED_UNLOCK_SECURE(base)	(base + 0xD0)
 #define FLASH_LED_TORCH(base)		(base + 0xE4)
 #define FLASH_FAULT_DETECT(base)	(base + 0x51)
+#define FLASH_PERIPHERAL_SUBTYPE(base)	(base + 0x05)
 
 #define FLASH_MAX_LEVEL			0x4F
 #define TORCH_MAX_LEVEL			0x0F
@@ -119,13 +120,13 @@
 #define FLASH_ENABLE_MODULE_MASK	0x80
 #define FLASH_DISABLE_ALL		0x00
 #define FLASH_ENABLE_MASK		0xE0
-#define FLASH_ENABLE_LED_0		0x40
-#define FLASH_ENABLE_LED_1		0x20
+#define FLASH_ENABLE_LED_0		0xC0
+#define FLASH_ENABLE_LED_1		0xA0
 #define FLASH_INIT_MASK			0xE0
 #define	FLASH_SELFCHECK_ENABLE		0x80
 
 #define FLASH_STROBE_SW			0xC0
-#define FLASH_STROBE_HW			0xC4
+#define FLASH_STROBE_HW			0x04
 #define FLASH_STROBE_MASK		0xC7
 #define FLASH_LED_0_OUTPUT		0x80
 #define FLASH_LED_1_OUTPUT		0x40
@@ -144,6 +145,9 @@
 #define FLASH_UNLOCK_SECURE		0xA5
 #define FLASH_SECURE_MASK		0xFF
 
+#define FLASH_SUBTYPE_DUAL		0x01
+#define FLASH_SUBTYPE_SINGLE		0x02
+
 #define LED_TRIGGER_DEFAULT		"none"
 
 #define RGB_LED_SRC_SEL(base)		(base + 0x45)
@@ -366,6 +370,7 @@
  *  @trigger_flash - trigger flash
  *  @startup_dly - startup delay for flash
  *  @strobe_type - select between sw and hw strobe
+ *  @peripheral_subtype - module peripheral subtype
  *  @current_addr - address to write for current
  *  @second_addr - address of secondary flash to be written
  *  @safety_timer - enable safety timer or watchdog timer
@@ -385,6 +390,7 @@
 	u8	trigger_flash;
 	u8	startup_dly;
 	u8	strobe_type;
+	u8	peripheral_subtype;
 	u16	current_addr;
 	u16	second_addr;
 	bool	safety_timer;
@@ -720,6 +726,16 @@
 	if (regulator_on && led->flash_cfg->flash_on) {
 		for (i = 0; i < led->num_leds; i++) {
 			if (led_array[i].flash_cfg->flash_reg_get) {
+				rc = qpnp_led_masked_write(led,
+					FLASH_ENABLE_CONTROL(led->base),
+					FLASH_ENABLE_MASK,
+					FLASH_DISABLE_ALL);
+				if (rc) {
+					dev_err(&led->spmi_dev->dev,
+						"Enable reg write failed(%d)\n",
+						rc);
+				}
+
 				rc = regulator_disable(led_array[i].flash_cfg->\
 							flash_boost_reg);
 				if (rc) {
@@ -757,6 +773,13 @@
 
 regulator_turn_off:
 	if (led->flash_cfg->torch_on) {
+		rc = qpnp_led_masked_write(led,	FLASH_ENABLE_CONTROL(led->base),
+				FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Enable reg write failed(%d)\n", rc);
+		}
+
 		rc = regulator_disable(led->flash_cfg->torch_boost_reg);
 		if (rc) {
 			dev_err(&led->spmi_dev->dev,
@@ -780,20 +803,43 @@
 		led->flash_cfg->current_prgm =
 			(val * FLASH_MAX_LEVEL / led->max_current);
 
-	led->flash_cfg->current_prgm =
-		led->flash_cfg->current_prgm >> FLASH_CURRENT_PRGM_SHIFT;
-	if (!led->flash_cfg->current_prgm)
-		led->flash_cfg->current_prgm = FLASH_CURRENT_PRGM_MIN;
-
 	/* Set led current */
 	if (val > 0) {
 		if (led->flash_cfg->torch_enable) {
-			rc = qpnp_torch_regulator_operate(led, true);
-			if (rc) {
-				dev_err(&led->spmi_dev->dev,
+			if (led->flash_cfg->peripheral_subtype ==
+							FLASH_SUBTYPE_DUAL) {
+				rc = qpnp_torch_regulator_operate(led, true);
+				if (rc) {
+					dev_err(&led->spmi_dev->dev,
 					"Torch regulator operate failed(%d)\n",
 					rc);
-				return rc;
+					return rc;
+				}
+			} else if (led->flash_cfg->peripheral_subtype ==
+							FLASH_SUBTYPE_SINGLE) {
+				rc = qpnp_flash_regulator_operate(led, true);
+				if (rc) {
+					dev_err(&led->spmi_dev->dev,
+					"Flash regulator operate failed(%d)\n",
+					rc);
+					goto error_flash_set;
+				}
+
+				/*
+				 * Write 0x80 to MODULE_ENABLE before writing
+				 * 0xE0 in order to avoid a hardware bug caused
+				 * by register value going from 0x00 to 0xE0.
+				 */
+				rc = qpnp_led_masked_write(led,
+					FLASH_ENABLE_CONTROL(led->base),
+					FLASH_ENABLE_MODULE_MASK,
+					FLASH_ENABLE_MODULE);
+				if (rc) {
+					dev_err(&led->spmi_dev->dev,
+						"Enable reg write failed(%d)\n",
+						rc);
+					return rc;
+				}
 			}
 
 			rc = qpnp_led_masked_write(led,
@@ -802,7 +848,7 @@
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Secure reg write failed(%d)\n", rc);
-				goto error_torch_set;
+				goto error_reg_write;
 			}
 
 			rc = qpnp_led_masked_write(led,
@@ -811,7 +857,7 @@
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Torch reg write failed(%d)\n", rc);
-				goto error_torch_set;
+				goto error_reg_write;
 			}
 
 			rc = qpnp_led_masked_write(led,
@@ -821,7 +867,7 @@
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Current reg write failed(%d)\n", rc);
-				goto error_torch_set;
+				goto error_reg_write;
 			}
 
 			rc = qpnp_led_masked_write(led,
@@ -832,7 +878,7 @@
 				dev_err(&led->spmi_dev->dev,
 					"2nd Current reg write failed(%d)\n",
 					rc);
-				goto error_torch_set;
+				goto error_reg_write;
 			}
 
 			qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
@@ -842,16 +888,29 @@
 				dev_err(&led->spmi_dev->dev,
 					"Max current reg write failed(%d)\n",
 					rc);
-				goto error_torch_set;
+				goto error_reg_write;
 			}
 
 			rc = qpnp_led_masked_write(led,
 				FLASH_ENABLE_CONTROL(led->base),
-				FLASH_ENABLE_MASK, FLASH_ENABLE_MODULE);
+				FLASH_ENABLE_MASK,
+				led->flash_cfg->enable_module);
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
-					"Enable reg write failed(%d)\n", rc);
-				goto error_torch_set;
+					"Enable reg write failed(%d)\n",
+					rc);
+				goto error_reg_write;
+			}
+
+			rc = qpnp_led_masked_write(led,
+				FLASH_LED_STROBE_CTRL(led->base),
+				led->flash_cfg->trigger_flash,
+				led->flash_cfg->trigger_flash);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"LED %d strobe reg write failed(%d)\n",
+					led->id, rc);
+				goto error_reg_write;
 			}
 		} else {
 			rc = qpnp_flash_regulator_operate(led, true);
@@ -897,16 +956,19 @@
 				goto error_flash_set;
 			}
 
-			/* Write 0x80 to MODULE_ENABLE before writing 0xE0
-			 * in order to avoid reg value goes from 0x00 to
-			 * 0xE0. This causes a hardware bug.
+			/*
+			 * Write 0x80 to MODULE_ENABLE before writing
+			 * 0xE0 in order to avoid a hardware bug caused
+			 * by register value going from 0x00 to 0xE0.
 			 */
 			rc = qpnp_led_masked_write(led,
 				FLASH_ENABLE_CONTROL(led->base),
-				FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
+				FLASH_ENABLE_MODULE_MASK,
+				FLASH_ENABLE_MODULE);
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
-					"Enable reg write failed(%d)\n", rc);
+					"Enable reg write failed(%d)\n",
+					rc);
 				goto error_flash_set;
 			}
 
@@ -921,57 +983,45 @@
 			}
 
 			rc = qpnp_led_masked_write(led,
-				led->flash_cfg->second_addr,
-				FLASH_CURRENT_MASK,
-				led->flash_cfg->current_prgm);
-			if (rc) {
-				dev_err(&led->spmi_dev->dev,
-					"2nd Current reg write failed(%d)\n",
-					rc);
-				goto error_flash_set;
-			}
-
-			rc = qpnp_led_masked_write(led,
 				FLASH_ENABLE_CONTROL(led->base),
-				FLASH_ENABLE_MASK, FLASH_ENABLE_ALL);
+				led->flash_cfg->enable_module,
+				led->flash_cfg->enable_module);
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Enable reg write failed(%d)\n", rc);
 				goto error_flash_set;
 			}
-		}
 
-		if (!led->flash_cfg->strobe_type) {
-			rc = qpnp_led_masked_write(led,
-				FLASH_LED_STROBE_CTRL(led->base),
-				FLASH_STROBE_MASK, FLASH_STROBE_SW);
-			if (rc) {
-				dev_err(&led->spmi_dev->dev,
+			if (!led->flash_cfg->strobe_type) {
+				rc = qpnp_led_masked_write(led,
+					FLASH_LED_STROBE_CTRL(led->base),
+					led->flash_cfg->trigger_flash,
+					led->flash_cfg->trigger_flash);
+				if (rc) {
+					dev_err(&led->spmi_dev->dev,
 					"LED %d strobe reg write failed(%d)\n",
 					led->id, rc);
-				if (led->flash_cfg->torch_enable)
-					goto error_torch_set;
-				else
 					goto error_flash_set;
-			}
-		} else {
-			rc = qpnp_led_masked_write(led,
-				FLASH_LED_STROBE_CTRL(led->base),
-				FLASH_STROBE_MASK, FLASH_STROBE_HW);
-			if (rc) {
-				dev_err(&led->spmi_dev->dev,
+				}
+			} else {
+				rc = qpnp_led_masked_write(led,
+					FLASH_LED_STROBE_CTRL(led->base),
+					(led->flash_cfg->trigger_flash |
+					FLASH_STROBE_HW),
+					(led->flash_cfg->trigger_flash |
+					FLASH_STROBE_HW));
+				if (rc) {
+					dev_err(&led->spmi_dev->dev,
 					"LED %d strobe reg write failed(%d)\n",
 					led->id, rc);
-				if (led->flash_cfg->torch_enable)
-					goto error_torch_set;
-				else
 					goto error_flash_set;
+				}
 			}
 		}
 	} else {
 		rc = qpnp_led_masked_write(led,
 			FLASH_LED_STROBE_CTRL(led->base),
-			FLASH_STROBE_MASK,
+			led->flash_cfg->trigger_flash,
 			FLASH_DISABLE_ALL);
 		if (rc) {
 			dev_err(&led->spmi_dev->dev,
@@ -982,18 +1032,6 @@
 				goto error_flash_set;
 		}
 
-		rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
-			FLASH_ENABLE_MASK,
-			FLASH_DISABLE_ALL);
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"Enable reg write failed(%d)\n", rc);
-			if (led->flash_cfg->torch_enable)
-				goto error_torch_set;
-			else
-				goto error_flash_set;
-		}
-
 		if (led->flash_cfg->torch_enable) {
 			rc = qpnp_led_masked_write(led,
 				FLASH_LED_UNLOCK_SECURE(led->base),
@@ -1014,14 +1052,40 @@
 				goto error_torch_set;
 			}
 
-			rc = qpnp_torch_regulator_operate(led, false);
-			if (rc) {
-				dev_err(&led->spmi_dev->dev,
-					"Torch regulator operate failed(%d)\n",
-					rc);
-				return rc;
+			if (led->flash_cfg->peripheral_subtype ==
+							FLASH_SUBTYPE_DUAL) {
+				rc = qpnp_torch_regulator_operate(led, false);
+				if (rc) {
+					dev_err(&led->spmi_dev->dev,
+						"Torch regulator operate failed(%d)\n",
+						rc);
+					return rc;
+				}
+			} else if (led->flash_cfg->peripheral_subtype ==
+							FLASH_SUBTYPE_SINGLE) {
+				rc = qpnp_flash_regulator_operate(led, false);
+				if (rc) {
+					dev_err(&led->spmi_dev->dev,
+						"Flash regulator operate failed(%d)\n",
+						rc);
+					return rc;
+				}
 			}
 		} else {
+			rc = qpnp_led_masked_write(led,
+				FLASH_ENABLE_CONTROL(led->base),
+				led->flash_cfg->enable_module &
+				~FLASH_ENABLE_MODULE_MASK,
+				FLASH_DISABLE_ALL);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Enable reg write failed(%d)\n", rc);
+				if (led->flash_cfg->torch_enable)
+					goto error_torch_set;
+				else
+					goto error_flash_set;
+			}
+
 			rc = qpnp_flash_regulator_operate(led, false);
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
@@ -1036,6 +1100,10 @@
 
 	return 0;
 
+error_reg_write:
+	if (led->flash_cfg->peripheral_subtype == FLASH_SUBTYPE_SINGLE)
+		goto error_flash_set;
+
 error_torch_set:
 	error = qpnp_torch_regulator_operate(led, false);
 	if (error) {
@@ -2465,61 +2533,85 @@
 		return -ENOMEM;
 	}
 
-	if (led->id == QPNP_ID_FLASH1_LED0) {
-		led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
-		led->flash_cfg->current_addr = FLASH_LED_0_CURR(led->base);
-		led->flash_cfg->second_addr = FLASH_LED_1_CURR(led->base);
-		led->flash_cfg->trigger_flash = FLASH_LED_0_OUTPUT;
-		if (!*reg_set) {
-			led->flash_cfg->flash_boost_reg =
-				regulator_get(&led->spmi_dev->dev,
-							"flash_boost");
-			if (IS_ERR(led->flash_cfg->flash_boost_reg)) {
-				rc = PTR_ERR(led->flash_cfg->flash_boost_reg);
-				dev_err(&led->spmi_dev->dev,
-					"Regulator get failed(%d)\n", rc);
-				goto error_get_flash_reg;
-			}
-			led->flash_cfg->flash_reg_get = true;
-			*reg_set = true;
-		} else
-			led->flash_cfg->flash_reg_get = false;
-	} else if (led->id == QPNP_ID_FLASH1_LED1) {
-		led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
-		led->flash_cfg->current_addr = FLASH_LED_1_CURR(led->base);
-		led->flash_cfg->second_addr = FLASH_LED_0_CURR(led->base);
-		led->flash_cfg->trigger_flash = FLASH_LED_1_OUTPUT;
-		if (!*reg_set) {
-			led->flash_cfg->flash_boost_reg =
-					regulator_get(&led->spmi_dev->dev,
-								"flash_boost");
-			if (IS_ERR(led->flash_cfg->flash_boost_reg)) {
-				rc = PTR_ERR(led->flash_cfg->flash_boost_reg);
-				dev_err(&led->spmi_dev->dev,
-					"Regulator get failed(%d)\n", rc);
-				goto error_get_flash_reg;
-			}
-			led->flash_cfg->flash_reg_get = true;
-			*reg_set = true;
-		} else
-			led->flash_cfg->flash_reg_get = false;
-	} else {
-		dev_err(&led->spmi_dev->dev, "Unknown flash LED name given\n");
-		return -EINVAL;
+	rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
+			FLASH_PERIPHERAL_SUBTYPE(led->base),
+			&led->flash_cfg->peripheral_subtype, 1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Unable to read from addr=%x, rc(%d)\n",
+			FLASH_PERIPHERAL_SUBTYPE(led->base), rc);
 	}
 
 	led->flash_cfg->torch_enable =
 		of_property_read_bool(node, "qcom,torch-enable");
 
-	if (led->flash_cfg->torch_enable) {
-		led->flash_cfg->torch_boost_reg =
-			regulator_get(&led->spmi_dev->dev, "torch_boost");
-		if (IS_ERR(led->flash_cfg->torch_boost_reg)) {
-			rc = PTR_ERR(led->flash_cfg->torch_boost_reg);
-			dev_err(&led->spmi_dev->dev,
-				"Torch regulator get failed(%d)\n", rc);
-			goto error_get_torch_reg;
+	if (led->id == QPNP_ID_FLASH1_LED0) {
+		led->flash_cfg->enable_module = FLASH_ENABLE_LED_0;
+		led->flash_cfg->current_addr = FLASH_LED_0_CURR(led->base);
+		led->flash_cfg->trigger_flash = FLASH_LED_0_OUTPUT;
+		if (!*reg_set) {
+			led->flash_cfg->flash_boost_reg =
+				regulator_get(&led->spmi_dev->dev,
+							"flash-boost");
+			if (IS_ERR(led->flash_cfg->flash_boost_reg)) {
+				rc = PTR_ERR(led->flash_cfg->flash_boost_reg);
+				dev_err(&led->spmi_dev->dev,
+					"Regulator get failed(%d)\n", rc);
+				goto error_get_flash_reg;
+			}
+			led->flash_cfg->flash_reg_get = true;
+			*reg_set = true;
+		} else
+			led->flash_cfg->flash_reg_get = false;
+
+		if (led->flash_cfg->torch_enable) {
+			led->flash_cfg->second_addr =
+						FLASH_LED_1_CURR(led->base);
 		}
+	} else if (led->id == QPNP_ID_FLASH1_LED1) {
+		led->flash_cfg->enable_module = FLASH_ENABLE_LED_1;
+		led->flash_cfg->current_addr = FLASH_LED_1_CURR(led->base);
+		led->flash_cfg->trigger_flash = FLASH_LED_1_OUTPUT;
+		if (!*reg_set) {
+			led->flash_cfg->flash_boost_reg =
+					regulator_get(&led->spmi_dev->dev,
+								"flash-boost");
+			if (IS_ERR(led->flash_cfg->flash_boost_reg)) {
+				rc = PTR_ERR(led->flash_cfg->flash_boost_reg);
+				dev_err(&led->spmi_dev->dev,
+					"Regulator get failed(%d)\n", rc);
+				goto error_get_flash_reg;
+			}
+			led->flash_cfg->flash_reg_get = true;
+			*reg_set = true;
+		} else
+			led->flash_cfg->flash_reg_get = false;
+
+		if (led->flash_cfg->torch_enable) {
+			led->flash_cfg->second_addr =
+						FLASH_LED_0_CURR(led->base);
+		}
+	} else {
+		dev_err(&led->spmi_dev->dev, "Unknown flash LED name given\n");
+		return -EINVAL;
+	}
+
+	if (led->flash_cfg->torch_enable) {
+		if (of_find_property(of_get_parent(node), "torch-boost-supply",
+									NULL)) {
+			led->flash_cfg->torch_boost_reg =
+				regulator_get(&led->spmi_dev->dev,
+								"torch-boost");
+			if (IS_ERR(led->flash_cfg->torch_boost_reg)) {
+				rc = PTR_ERR(led->flash_cfg->torch_boost_reg);
+				dev_err(&led->spmi_dev->dev,
+					"Torch regulator get failed(%d)\n", rc);
+				goto error_get_torch_reg;
+			}
+			led->flash_cfg->enable_module = FLASH_ENABLE_MODULE;
+		} else
+			led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
+		led->flash_cfg->trigger_flash = FLASH_STROBE_SW;
 	}
 
 	rc = of_property_read_u32(node, "qcom,current", &val);
@@ -3018,7 +3110,7 @@
 			}
 		} else if (strncmp(led_label, "flash", sizeof("flash"))
 				== 0) {
-			if (!of_find_property(node, "flash_boost-supply", NULL))
+			if (!of_find_property(node, "flash-boost-supply", NULL))
 				regulator_probe = true;
 			rc = qpnp_get_config_flash(led, temp, &regulator_probe);
 			if (rc < 0) {
diff --git a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.c b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.c
index 79c533e..de0ed97 100644
--- a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.c
+++ b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.c
@@ -433,7 +433,7 @@
 	}
 }
 
-int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds)
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, uint32_t m_cmds)
 {
 	int is_copy_to_user = -1;
 	uint32_t data;
diff --git a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.h b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.h
index aa6c4aa1..4d08282 100644
--- a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.h
+++ b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_hw.h
@@ -94,7 +94,8 @@
 void msm_gemini_hw_write(struct msm_gemini_hw_cmd *hw_cmd_p);
 int msm_gemini_hw_wait(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
 void msm_gemini_hw_delay(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
-int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds);
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p,
+	uint32_t m_cmds);
 void msm_gemini_io_dump(int size);
 
 #define MSM_GEMINI_PIPELINE_CLK_128MHZ 128 /* 8MP  128MHz */
diff --git a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_sync.c b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_sync.c
index 50c7284..0796b8d 100644
--- a/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_sync.c
+++ b/drivers/media/platform/msm/camera_v1/gemini/msm_gemini_sync.c
@@ -23,6 +23,8 @@
 #include "msm_gemini_platform.h"
 #include "msm_gemini_common.h"
 
+#define UINT32_MAX (0xFFFFFFFFU)
+
 static int release_buf;
 
 /* size is based on 4k page size */
@@ -804,7 +806,7 @@
 	void * __user arg)
 {
 	int is_copy_to_user;
-	int len;
+	uint32_t len;
 	uint32_t m;
 	struct msm_gemini_hw_cmds *hw_cmds_p;
 	struct msm_gemini_hw_cmd *hw_cmd_p;
@@ -814,6 +816,12 @@
 		return -EFAULT;
 	}
 
+	if ((m == 0) || (m > ((UINT32_MAX - sizeof(struct msm_gemini_hw_cmds)) /
+		sizeof(struct msm_gemini_hw_cmd)))) {
+		GMN_PR_ERR("%s:%d] m_cmds out of range\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
 	len = sizeof(struct msm_gemini_hw_cmds) +
 		sizeof(struct msm_gemini_hw_cmd) * (m - 1);
 	hw_cmds_p = kmalloc(len, GFP_KERNEL);
diff --git a/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_sync.c b/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_sync.c
index 9293aad..e6483c1 100644
--- a/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_sync.c
+++ b/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_sync.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -196,6 +196,7 @@
 	int rc = 0;
 
 	MCR_DBG("(%d)%s() Enter\n", __LINE__, __func__);
+	memset(&ctrl_cmd, 0, sizeof(ctrl_cmd));
 	ctrl_cmd.type = (uint32_t)msm_mercury_q_wait(&pmercury_dev->evt_q);
 
 	rc = copy_to_user(arg, &ctrl_cmd, sizeof(ctrl_cmd));
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c
index 96470fd..da6f69f 100644
--- a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c
@@ -426,7 +426,7 @@
 	}
 }
 
-int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds)
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, uint32_t m_cmds)
 {
 	int is_copy_to_user = -1;
 	uint32_t data;
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h
index 84eed72..f4c32a7 100644
--- a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h
@@ -94,7 +94,8 @@
 void msm_gemini_hw_write(struct msm_gemini_hw_cmd *hw_cmd_p);
 int msm_gemini_hw_wait(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
 void msm_gemini_hw_delay(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
-int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds);
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p,
+	uint32_t m_cmds);
 void msm_gemini_io_dump(int size);
 
 #define MSM_GEMINI_PIPELINE_CLK_128MHZ 128 /* 8MP  128MHz */
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c
index 8f84a2c..ebf8d4b 100644
--- a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c
@@ -23,6 +23,8 @@
 #include "msm_gemini_platform.h"
 #include "msm_gemini_common.h"
 
+#define UINT32_MAX (0xFFFFFFFFU)
+
 static int release_buf;
 
 /* size is based on 4k page size */
@@ -808,7 +810,7 @@
 	void * __user arg)
 {
 	int is_copy_to_user;
-	int len;
+	uint32_t len;
 	uint32_t m;
 	struct msm_gemini_hw_cmds *hw_cmds_p;
 	struct msm_gemini_hw_cmd *hw_cmd_p;
@@ -818,6 +820,12 @@
 		return -EFAULT;
 	}
 
+	if ((m == 0) || (m > ((UINT32_MAX - sizeof(struct msm_gemini_hw_cmds)) /
+		sizeof(struct msm_gemini_hw_cmd)))) {
+		GMN_PR_ERR("%s:%d] m_cmds out of range\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
 	len = sizeof(struct msm_gemini_hw_cmds) +
 		sizeof(struct msm_gemini_hw_cmd) * (m - 1);
 	hw_cmds_p = kmalloc(len, GFP_KERNEL);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 2a2656f..2be1f01 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -288,6 +288,10 @@
 		pr_err("%s: Invalid bufq\n", __func__);
 		return rc;
 	}
+	if (!bufq->bufq_handle) {
+		pr_err("%s: Invalid bufq handle\n", __func__);
+		return rc;
+	}
 
 	*buf_info = NULL;
 	spin_lock_irqsave(&bufq->bufq_lock, flags);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 8c42ed2..4aa423f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -49,6 +49,16 @@
 	uint32_t active;
 };
 
+enum msm_isp_pack_fmt {
+	QCOM,
+	MIPI,
+	DPCM6,
+	DPCM8,
+	PLAIN8,
+	PLAIN16,
+	MAX_ISP_PACK_FMT,
+};
+
 enum msm_isp_camif_update_state {
 	NO_UPDATE,
 	ENABLE_CAMIF,
@@ -290,7 +300,7 @@
 	enum msm_vfe_inputmux input_mux;
 	uint32_t width;
 	long pixel_clock;
-	uint32_t input_format;
+	uint32_t input_format;/*V4L2 pix format with bayer pattern*/
 };
 
 enum msm_wm_ub_cfg_type {
@@ -386,10 +396,12 @@
 	struct resource *vfe_irq;
 	struct resource *vfe_mem;
 	struct resource *vfe_vbif_mem;
+	struct resource *tcsr_mem;
 	struct resource *vfe_io;
 	struct resource *vfe_vbif_io;
 	void __iomem *vfe_base;
 	void __iomem *vfe_vbif_base;
+	void __iomem *tcsr_base;
 
 	struct device *iommu_ctx[MAX_IOMMU_CTX];
 
@@ -414,6 +426,7 @@
 	struct msm_vfe_tasklet_queue_cmd
 		tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE];
 
+	uint32_t soc_hw_version;
 	uint32_t vfe_hw_version;
 	struct msm_vfe_hardware_info *hw_info;
 	struct msm_vfe_axi_shared_data axi_data;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index aac973e..a6972e4 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -24,7 +24,7 @@
 
 #define VFE32_BURST_LEN 2
 #define VFE32_UB_SIZE 1024
-#define VFE32_EQUAL_SLICE_UB 204
+#define VFE32_EQUAL_SLICE_UB 198
 #define VFE32_WM_BASE(idx) (0x4C + 0x18 * idx)
 #define VFE32_RDI_BASE(idx) (idx ? 0x734 + 0x4 * (idx - 1) : 0x06FC)
 #define VFE32_XBAR_BASE(idx) (0x40 + 0x4 * (idx / 4))
@@ -149,6 +149,7 @@
 	msm_camera_io_w_mb(0x1CFFFFFF, vfe_dev->vfe_base + 0x20);
 	msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x24);
 	msm_camera_io_w_mb(0x1FFFFFFF, vfe_dev->vfe_base + 0x28);
+
 }
 
 static void msm_vfe32_process_reset_irq(struct vfe_device *vfe_dev,
@@ -483,7 +484,7 @@
 static void msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev,
 	enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
 {
-	int bpp, bpp_reg = 0;
+	int bpp, bpp_reg = 0, pack_fmt = 0, pack_reg = 0;
 	uint32_t io_format_reg;
 	bpp = msm_isp_get_bit_per_pixel(io_format);
 
@@ -498,6 +499,34 @@
 		bpp_reg = 1 << 1;
 		break;
 	}
+
+	if (stream_src == IDEAL_RAW) {
+		pack_fmt = msm_isp_get_pack_format(io_format);
+		switch (pack_fmt) {
+		case QCOM:
+			pack_reg = 0x0;
+			break;
+		case MIPI:
+			pack_reg = 0x1;
+			break;
+		case DPCM6:
+			pack_reg = 0x2;
+			break;
+		case DPCM8:
+			pack_reg = 0x3;
+			break;
+		case PLAIN8:
+			pack_reg = 0x4;
+			break;
+		case PLAIN16:
+			pack_reg = 0x5;
+			break;
+		default:
+			pr_err("%s: invalid pack fmt!\n", __func__);
+			return;
+		}
+	}
+
 	io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x6F8);
 	switch (stream_src) {
 	case PIX_ENCODER:
@@ -508,7 +537,7 @@
 		break;
 	case IDEAL_RAW:
 		io_format_reg &= 0xFFFFFFC8;
-		io_format_reg |= bpp_reg << 4;
+		io_format_reg |= bpp_reg << 4 | pack_reg;
 		break;
 	case RDI_INTF_0:
 	case RDI_INTF_1:
@@ -852,13 +881,13 @@
 	int i;
 	uint32_t ub_offset = VFE32_UB_SIZE;
 	uint32_t ub_size[VFE32_NUM_STATS_TYPE] = {
-		64, /*MSM_ISP_STATS_BG*/
-		64, /*MSM_ISP_STATS_BF*/
-		16, /*MSM_ISP_STATS_AWB*/
-		8,  /*MSM_ISP_STATS_RS*/
+		107, /*MSM_ISP_STATS_BG*/
+		92, /*MSM_ISP_STATS_BF*/
+		2, /*MSM_ISP_STATS_AWB*/
+		7,  /*MSM_ISP_STATS_RS*/
 		16, /*MSM_ISP_STATS_CS*/
-		16, /*MSM_ISP_STATS_IHIST*/
-		16, /*MSM_ISP_STATS_BHIST*/
+		2, /*MSM_ISP_STATS_IHIST*/
+		7, /*MSM_ISP_STATS_BHIST*/
 	};
 
 	for (i = 0; i < VFE32_NUM_STATS_TYPE; i++) {
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 84b95f1..9047c40 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -290,6 +290,14 @@
 		goto vbif_remap_failed;
 	}
 
+	vfe_dev->tcsr_base = ioremap(vfe_dev->tcsr_mem->start,
+		resource_size(vfe_dev->tcsr_mem));
+	if (!vfe_dev->tcsr_base) {
+		rc = -ENOMEM;
+		pr_err("%s: tcsr ioremap failed\n", __func__);
+		goto tcsr_remap_failed;
+	}
+
 	rc = request_irq(vfe_dev->vfe_irq->start, msm_isp_process_irq,
 		IRQF_TRIGGER_RISING, "vfe", vfe_dev);
 	if (rc < 0) {
@@ -298,6 +306,8 @@
 	}
 	return rc;
 irq_req_failed:
+	iounmap(vfe_dev->tcsr_base);
+tcsr_remap_failed:
 	iounmap(vfe_dev->vfe_vbif_base);
 vbif_remap_failed:
 	iounmap(vfe_dev->vfe_base);
@@ -316,6 +326,7 @@
 {
 	free_irq(vfe_dev->vfe_irq->start, vfe_dev);
 	tasklet_kill(&vfe_dev->vfe_tasklet);
+	iounmap(vfe_dev->tcsr_base);
 	iounmap(vfe_dev->vfe_vbif_base);
 	iounmap(vfe_dev->vfe_base);
 	msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info,
@@ -503,15 +514,17 @@
 {
 	*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38);
 	*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C);
-	/*Ignore composite 3 irq which is used for dual VFE only*/
+	/*
+	 * Ignore composite 2/3 irq which is used for dual VFE only
+	 */
 	if (*irq_status0 & 0x6000000)
-		*irq_status0 &= ~(0x10000000);
+		*irq_status0 &= ~(0x18000000);
 	msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x30);
 	msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x34);
 	msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x24);
-	if (*irq_status0 & 0x10000000) {
+	if (*irq_status0 & 0x18000000) {
 		pr_err_ratelimited("%s: Protection triggered\n", __func__);
-		*irq_status0 &= ~(0x10000000);
+		*irq_status0 &= ~(0x18000000);
 	}
 
 	if (*irq_status1 & (1 << 0))
@@ -597,15 +610,29 @@
 	comp_mask &= ~(0x7F << (comp_mask_index * 8));
 	comp_mask |= (axi_data->composite_info[comp_mask_index].
 		stream_composite_mask << (comp_mask_index * 8));
-	if (stream_info->plane_cfg[0].plane_addr_offset)
-		comp_mask |= (axi_data->composite_info[comp_mask_index].
-		stream_composite_mask << 24);
-	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
 
 	irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
 	irq_mask |= 1 << (comp_mask_index + 25);
-	if (stream_info->plane_cfg[0].plane_addr_offset && (comp_mask >> 24))
+
+	/*
+	 * For dual VFE, composite 2/3 interrupt is used to trigger
+	 * microcontroller to update certain VFE registers
+	 */
+	if (stream_info->plane_cfg[0].plane_addr_offset &&
+		stream_info->stream_src == PIX_VIEWFINDER) {
+		comp_mask |= (axi_data->composite_info[comp_mask_index].
+		stream_composite_mask << 16);
+		irq_mask |= BIT(27);
+	}
+
+	if (stream_info->plane_cfg[0].plane_addr_offset &&
+		stream_info->stream_src == PIX_ENCODER) {
+		comp_mask |= (axi_data->composite_info[comp_mask_index].
+		stream_composite_mask << 24);
 		irq_mask |= BIT(28);
+	}
+
+	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
 	msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
 }
 
@@ -618,15 +645,25 @@
 
 	comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40);
 	comp_mask &= ~(0x7F << (comp_mask_index * 8));
-	if (stream_info->plane_cfg[0].plane_addr_offset)
-		comp_mask &= ~(axi_data->composite_info[comp_mask_index].
-		stream_composite_mask << 24);
-	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
 
 	irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
 	irq_mask &= ~(1 << (comp_mask_index + 25));
-	if (stream_info->plane_cfg[0].plane_addr_offset && (comp_mask >> 24))
+
+	if (stream_info->plane_cfg[0].plane_addr_offset &&
+		stream_info->stream_src == PIX_VIEWFINDER) {
+		comp_mask &= ~(axi_data->composite_info[comp_mask_index].
+		stream_composite_mask << 16);
+		irq_mask &= ~BIT(27);
+	}
+
+	if (stream_info->plane_cfg[0].plane_addr_offset &&
+		stream_info->stream_src == PIX_ENCODER) {
+		comp_mask &= ~(axi_data->composite_info[comp_mask_index].
+		stream_composite_mask << 24);
 		irq_mask &= ~BIT(28);
+	}
+
+	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
 	msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
 }
 
@@ -690,8 +727,9 @@
 static void msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev,
 	enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
 {
-	int bpp, bpp_reg = 0;
-	uint32_t io_format_reg;
+	int bpp, bpp_reg = 0, pack_reg = 0;
+	enum msm_isp_pack_fmt pack_fmt = 0;
+	uint32_t io_format_reg; /*io format register bit*/
 	bpp = msm_isp_get_bit_per_pixel(io_format);
 
 	switch (bpp) {
@@ -705,6 +743,35 @@
 		bpp_reg = 1 << 1;
 		break;
 	}
+
+	if (stream_src == IDEAL_RAW) {
+		/*use io_format(v4l2_pix_fmt) to get pack format*/
+		pack_fmt = msm_isp_get_pack_format(io_format);
+		switch (pack_fmt) {
+		case QCOM:
+			pack_reg = 0x0;
+			break;
+		case MIPI:
+			pack_reg = 0x1;
+			break;
+		case DPCM6:
+			pack_reg = 0x2;
+			break;
+		case DPCM8:
+			pack_reg = 0x3;
+			break;
+		case PLAIN8:
+			pack_reg = 0x4;
+			break;
+		case PLAIN16:
+			pack_reg = 0x5;
+			break;
+		default:
+			pr_err("%s: invalid pack fmt!\n", __func__);
+			return;
+		}
+	}
+
 	io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x54);
 	switch (stream_src) {
 	case PIX_ENCODER:
@@ -715,7 +782,7 @@
 		break;
 	case IDEAL_RAW:
 		io_format_reg &= 0xFFFFFFC8;
-		io_format_reg |= bpp_reg << 4;
+		io_format_reg |= bpp_reg << 4 | pack_reg;
 		break;
 	case RDI_INTF_0:
 	case RDI_INTF_1:
@@ -1262,6 +1329,14 @@
 		goto vfe_no_resource;
 	}
 
+	vfe_dev->tcsr_mem = platform_get_resource_byname(vfe_dev->pdev,
+		IORESOURCE_MEM, "tcsr");
+	if (!vfe_dev->tcsr_mem) {
+		pr_err("%s: no mem resource?\n", __func__);
+		rc = -ENODEV;
+		goto vfe_no_resource;
+	}
+
 	vfe_dev->vfe_irq = platform_get_resource_byname(vfe_dev->pdev,
 		IORESOURCE_IRQ, "vfe");
 	if (!vfe_dev->vfe_irq) {
@@ -1300,7 +1375,7 @@
 
 static struct msm_vfe_axi_hardware_info msm_vfe40_axi_hw_info = {
 	.num_wm = 5,
-	.num_comp_mask = 3,
+	.num_comp_mask = 2,
 	.num_rdi = 3,
 	.num_rdi_master = 3,
 	.min_wm_ub = 64,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 5b7658d..f547b0e 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -300,7 +300,16 @@
 	struct msm_vfe_axi_stream *stream_info;
 	enum msm_vfe_axi_state valid_state =
 		(stream_cfg_cmd->cmd == START_STREAM) ? INACTIVE : ACTIVE;
+
+	if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) {
+		return -EINVAL;
+	}
+
 	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])
+		> MAX_NUM_STREAM) {
+			return -EINVAL;
+		}
 		stream_info = &axi_data->stream_info[
 			HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
 		spin_lock_irqsave(&stream_info->lock, flags);
@@ -407,6 +416,7 @@
 		break;
 	}
 
+	sof_event.input_intf = frame_src;
 	sof_event.frame_id = vfe_dev->axi_data.src_info[frame_src].frame_id;
 	sof_event.timestamp = ts->event_time;
 	sof_event.mono_timestamp = ts->buf_time;
@@ -594,9 +604,18 @@
 			stream_info->state == RESUME_PENDING)
 			vfe_dev->hw_info->vfe_ops.axi_ops.
 				enable_wm(vfe_dev, stream_info->wm[i], 1);
-		else
+		else {
 			vfe_dev->hw_info->vfe_ops.axi_ops.
 				enable_wm(vfe_dev, stream_info->wm[i], 0);
+			/* Issue a reg update for Raw Snapshot Case
+			 * since we dont have reg update ack
+			*/
+			if (stream_info->stream_src == CAMIF_RAW ||
+				stream_info->stream_src == IDEAL_RAW) {
+				vfe_dev->hw_info->vfe_ops.core_ops.
+				reg_update(vfe_dev);
+			}
+		}
 	}
 
 	if (stream_info->state == START_PENDING)
@@ -778,6 +797,8 @@
 			 * other ISP hardware is still processing the frame.
 			 */
 			if (rc == 0) {
+				buf_event.input_intf =
+					SRC_TO_INTF(stream_info->stream_src);
 				buf_event.frame_id = frame_id;
 				buf_event.timestamp = ts->buf_time;
 				buf_event.u.buf_done.session_id =
@@ -840,7 +861,16 @@
 	int i;
 	struct msm_vfe_axi_stream *stream_info;
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+
+	if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) {
+		return;
+	}
+
 	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])
+		> MAX_NUM_STREAM) {
+			return;
+		}
 		stream_info =
 			&axi_data->stream_info[
 			HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
@@ -1020,7 +1050,16 @@
 	uint32_t wm_reload_mask = 0x0;
 	struct msm_vfe_axi_stream *stream_info;
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+
+	if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) {
+		return -EINVAL;
+	}
+
 	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])
+		> MAX_NUM_STREAM) {
+			return -EINVAL;
+		}
 		stream_info = &axi_data->stream_info[
 			HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
 		src_state = axi_data->src_info[
@@ -1073,16 +1112,31 @@
 	uint8_t wait_for_complete = 0;
 	struct msm_vfe_axi_stream *stream_info;
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+
+	if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) {
+		return -EINVAL;
+	}
+
 	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])
+		> MAX_NUM_STREAM) {
+			return -EINVAL;
+		}
 		stream_info = &axi_data->stream_info[
 			HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
 
 		stream_info->state = STOP_PENDING;
-		if (stream_info->stream_type == BURST_STREAM &&
-			stream_info->runtime_num_burst_capture == 0) {
-			/*Configure AXI writemasters to stop immediately
-			 *since for burst case, write masters already skip
-			 *all frames.
+		if (stream_info->stream_src == CAMIF_RAW ||
+			stream_info->stream_src == IDEAL_RAW) {
+			/* We dont get reg update IRQ for raw snapshot
+			 * so frame skip cant be ocnfigured
+			*/
+			wait_for_complete = 1;
+		} else if (stream_info->stream_type == BURST_STREAM &&
+				stream_info->runtime_num_burst_capture == 0) {
+			/* Configure AXI writemasters to stop immediately
+			 * since for burst case, write masters already skip
+			 * all frames.
 			 */
 			msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info);
 			stream_info->state = INACTIVE;
@@ -1090,7 +1144,6 @@
 			wait_for_complete = 1;
 		}
 	}
-
 	if (wait_for_complete) {
 		rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
 		if (rc < 0) {
@@ -1158,8 +1211,18 @@
 		return -EBUSY;
 	}
 
+	/*num_stream is uint32 and update_info[] bound by MAX_NUM_STREAM*/
+	if (update_cmd->num_streams > MAX_NUM_STREAM) {
+		return -EINVAL;
+	}
+
 	for (i = 0; i < update_cmd->num_streams; i++) {
 		update_info = &update_cmd->update_info[i];
+		/*check array reference bounds*/
+		if (HANDLE_TO_IDX(update_info->stream_handle)
+		 > MAX_NUM_STREAM) {
+			return -EINVAL;
+		}
 		stream_info = &axi_data->stream_info[
 				HANDLE_TO_IDX(update_info->stream_handle)];
 		if (stream_info->state != ACTIVE &&
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index 33f63b3..b479857 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -23,8 +23,16 @@
 	struct msm_isp_buffer *buf;
 	uint32_t pingpong_bit = 0;
 	uint32_t bufq_handle = stream_info->bufq_handle;
-	uint32_t stats_pingpong_offset =
-		STATS_IDX(stream_info->stream_handle) +
+	uint32_t stats_pingpong_offset;
+
+	if (STATS_IDX(stream_info->stream_handle) >=
+			vfe_dev->hw_info->stats_hw_info->num_stats_type) {
+		pr_err("%s Invalid stats index %d", __func__,
+				STATS_IDX(stream_info->stream_handle));
+		return -EINVAL;
+	}
+
+	stats_pingpong_offset = STATS_IDX(stream_info->stream_handle) +
 		vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset;
 
 	pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1);
@@ -89,6 +97,7 @@
 	buf_event.timestamp = ts->event_time;
 	buf_event.frame_id =
 		vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+	buf_event.input_intf = VFE_PIX_0;
 	pingpong_status = vfe_dev->hw_info->
 		vfe_ops.stats_ops.get_pingpong_status(vfe_dev);
 
@@ -150,10 +159,9 @@
 	stats_idx = vfe_dev->hw_info->vfe_ops.stats_ops.
 		get_stats_idx(stream_req_cmd->stats_type);
 
-	if ((stats_idx > MSM_ISP_STATS_MAX) ||
-		(stats_idx == -EINVAL)) {
-		pr_err("%s: Stats idx Error\n", __func__);
-		return rc;
+	if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
+		pr_err("%s Invalid stats index %d", __func__, stats_idx);
+		return -EINVAL;
 	}
 
 	stream_info = &stats_data->stream_info[stats_idx];
@@ -208,9 +216,10 @@
 	}
 
 	stats_idx = STATS_IDX(stream_req_cmd->stream_handle);
-	if (stats_idx > MSM_ISP_STATS_MAX) {
-		pr_err("%s: Stats idx Error\n", __func__);
-		return rc;
+
+	if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
+		pr_err("%s Invalid stats index %d", __func__, stats_idx);
+		return -EINVAL;
 	}
 
 	stream_info = &stats_data->stream_info[stats_idx];
@@ -241,9 +250,9 @@
 	int stats_idx = STATS_IDX(stream_release_cmd->stream_handle);
 	struct msm_vfe_stats_stream *stream_info = NULL;
 
-	if (stats_idx > MSM_ISP_STATS_MAX) {
-		pr_err("%s: Stats idx Error\n", __func__);
-		return rc;
+	if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
+		pr_err("%s Invalid stats index %d", __func__, stats_idx);
+		return -EINVAL;
 	}
 
 	stream_info = &stats_data->stream_info[stats_idx];
@@ -378,6 +387,12 @@
 	struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
 	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
 		idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
+
+		if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
+			pr_err("%s Invalid stats index %d", __func__, idx);
+			return -EINVAL;
+		}
+
 		stream_info = &stats_data->stream_info[idx];
 		if (stream_info->stream_handle !=
 				stream_cfg_cmd->stream_handle[i]) {
@@ -422,6 +437,12 @@
 	struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
 	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
 		idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
+
+		if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
+			pr_err("%s Invalid stats index %d", __func__, idx);
+			return -EINVAL;
+		}
+
 		stream_info = &stats_data->stream_info[idx];
 		if (stream_info->stream_handle !=
 				stream_cfg_cmd->stream_handle[i]) {
@@ -452,6 +473,12 @@
 
 	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
 		idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
+
+		if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) {
+			pr_err("%s Invalid stats index %d", __func__, idx);
+			return -EINVAL;
+		}
+
 		stream_info = &stats_data->stream_info[idx];
 		msm_isp_deinit_stats_ping_pong_reg(vfe_dev, stream_info);
 	}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index 590b636..b024569 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -27,6 +27,8 @@
 #define MSM_ISP_MIN_AB 300000000
 #define MSM_ISP_MIN_IB 450000000
 
+#define VFE40_8974V2_VERSION 0x1001001A
+
 static struct msm_bus_vectors msm_isp_init_vectors[] = {
 	{
 		.src = MSM_BUS_MASTER_VFE,
@@ -369,7 +371,7 @@
 		break;
 	case VIDIOC_MSM_ISP_SET_SRC_STATE:
 		mutex_lock(&vfe_dev->core_mutex);
-		msm_isp_set_src_state(vfe_dev, arg);
+		rc = msm_isp_set_src_state(vfe_dev, arg);
 		mutex_unlock(&vfe_dev->core_mutex);
 		break;
 	case VIDIOC_MSM_ISP_REQUEST_STATS_STREAM:
@@ -413,7 +415,7 @@
 		if (resource_size(vfe_dev->vfe_mem) <
 			(reg_cfg_cmd->u.rw_info.reg_offset +
 			reg_cfg_cmd->u.rw_info.len)) {
-			pr_err("%s: Invalid length\n", __func__);
+			pr_err("%s: VFE_WRITE: Invalid length\n", __func__);
 			return -EINVAL;
 		}
 		msm_camera_io_memcpy(vfe_dev->vfe_base +
@@ -425,16 +427,37 @@
 	case VFE_WRITE_MB: {
 		uint32_t *data_ptr = cfg_data +
 			reg_cfg_cmd->u.rw_info.cmd_data_offset/4;
+
+		if ((UINT_MAX - sizeof(*data_ptr) <
+					reg_cfg_cmd->u.rw_info.reg_offset) ||
+			(resource_size(vfe_dev->vfe_mem) <
+			reg_cfg_cmd->u.rw_info.reg_offset +
+			sizeof(*data_ptr))) {
+			pr_err("%s: VFE_WRITE_MB: Invalid length\n", __func__);
+			return -EINVAL;
+		}
 		msm_camera_io_w_mb(*data_ptr, vfe_dev->vfe_base +
 			reg_cfg_cmd->u.rw_info.reg_offset);
 		break;
 	}
 	case VFE_CFG_MASK: {
 		uint32_t temp;
+		if (resource_size(vfe_dev->vfe_mem) <
+				reg_cfg_cmd->u.mask_info.reg_offset)
+			return -EINVAL;
 		temp = msm_camera_io_r(vfe_dev->vfe_base +
 			reg_cfg_cmd->u.mask_info.reg_offset);
+
 		temp &= ~reg_cfg_cmd->u.mask_info.mask;
 		temp |= reg_cfg_cmd->u.mask_info.val;
+		if ((UINT_MAX - sizeof(temp) <
+					reg_cfg_cmd->u.mask_info.reg_offset) ||
+			(resource_size(vfe_dev->vfe_mem) <
+			reg_cfg_cmd->u.mask_info.reg_offset +
+			sizeof(temp))) {
+			pr_err("%s: VFE_CFG_MASK: Invalid length\n", __func__);
+			return -EINVAL;
+		}
 		msm_camera_io_w(temp, vfe_dev->vfe_base +
 			reg_cfg_cmd->u.mask_info.reg_offset);
 		break;
@@ -446,8 +469,10 @@
 		uint32_t *hi_tbl_ptr = NULL, *lo_tbl_ptr = NULL;
 		uint32_t hi_val, lo_val, lo_val1;
 		if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) {
-			if (reg_cfg_cmd->u.dmi_info.hi_tbl_offset +
-				reg_cfg_cmd->u.dmi_info.len > cmd_len) {
+			if ((UINT_MAX - reg_cfg_cmd->u.dmi_info.hi_tbl_offset <
+						reg_cfg_cmd->u.dmi_info.len) ||
+				(reg_cfg_cmd->u.dmi_info.hi_tbl_offset +
+				reg_cfg_cmd->u.dmi_info.len > cmd_len)) {
 				pr_err("Invalid Hi Table out of bounds\n");
 				return -EINVAL;
 			}
@@ -531,12 +556,21 @@
 		uint32_t *data_ptr = cfg_data +
 			reg_cfg_cmd->u.rw_info.cmd_data_offset/4;
 		for (i = 0; i < reg_cfg_cmd->u.rw_info.len/4; i++) {
+			if ((data_ptr < cfg_data) ||
+				(UINT_MAX / sizeof(*data_ptr) <
+				 (data_ptr - cfg_data)) ||
+				(sizeof(*data_ptr) * (data_ptr - cfg_data) >
+				 cmd_len))
+				return -EINVAL;
 			*data_ptr++ = msm_camera_io_r(vfe_dev->vfe_base +
 				reg_cfg_cmd->u.rw_info.reg_offset);
 			reg_cfg_cmd->u.rw_info.reg_offset += 4;
 		}
 		break;
 	}
+	case GET_SOC_HW_VER:
+		*cfg_data = vfe_dev->soc_hw_version;
+		break;
 	}
 	return 0;
 }
@@ -548,6 +582,11 @@
 	struct msm_vfe_reg_cfg_cmd *reg_cfg_cmd;
 	uint32_t *cfg_data;
 
+	if (!proc_cmd->num_cfg) {
+		pr_err("%s: Passed num_cfg as 0\n", __func__);
+		return -EINVAL;
+	}
+
 	reg_cfg_cmd = kzalloc(sizeof(struct msm_vfe_reg_cfg_cmd)*
 		proc_cmd->num_cfg, GFP_KERNEL);
 	if (!reg_cfg_cmd) {
@@ -668,6 +707,42 @@
 	return val;
 }
 
+enum msm_isp_pack_fmt msm_isp_get_pack_format(uint32_t output_format)
+{
+	switch (output_format) {
+	case V4L2_PIX_FMT_SBGGR8:
+	case V4L2_PIX_FMT_SGBRG8:
+	case V4L2_PIX_FMT_SGRBG8:
+	case V4L2_PIX_FMT_SRGGB8:
+	case V4L2_PIX_FMT_SBGGR10:
+	case V4L2_PIX_FMT_SGBRG10:
+	case V4L2_PIX_FMT_SGRBG10:
+	case V4L2_PIX_FMT_SRGGB10:
+	case V4L2_PIX_FMT_SBGGR12:
+	case V4L2_PIX_FMT_SGBRG12:
+	case V4L2_PIX_FMT_SGRBG12:
+	case V4L2_PIX_FMT_SRGGB12:
+		return MIPI;
+	case V4L2_PIX_FMT_QBGGR8:
+	case V4L2_PIX_FMT_QGBRG8:
+	case V4L2_PIX_FMT_QGRBG8:
+	case V4L2_PIX_FMT_QRGGB8:
+	case V4L2_PIX_FMT_QBGGR10:
+	case V4L2_PIX_FMT_QGBRG10:
+	case V4L2_PIX_FMT_QGRBG10:
+	case V4L2_PIX_FMT_QRGGB10:
+	case V4L2_PIX_FMT_QBGGR12:
+	case V4L2_PIX_FMT_QGBRG12:
+	case V4L2_PIX_FMT_QGRBG12:
+	case V4L2_PIX_FMT_QRGGB12:
+		return QCOM;
+	default:
+		pr_err("%s: Invalid output format\n", __func__);
+		break;
+	}
+	return -EINVAL;
+}
+
 int msm_isp_get_bit_per_pixel(uint32_t output_format)
 {
 	switch (output_format) {
@@ -727,6 +802,8 @@
 void msm_isp_process_error_info(struct vfe_device *vfe_dev)
 {
 	int i;
+	uint8_t num_stats_type =
+		vfe_dev->hw_info->stats_hw_info->num_stats_type;
 	struct msm_vfe_error_info *error_info = &vfe_dev->error_info;
 	static DEFINE_RATELIMIT_STATE(rs,
 		DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST);
@@ -750,7 +827,7 @@
 				error_info->stream_framedrop_count[i] = 0;
 			}
 		}
-		for (i = 0; i < MSM_ISP_STATS_MAX; i++) {
+		for (i = 0; i < num_stats_type; i++) {
 			if (error_info->stats_framedrop_count[i] != 0 &&
 				__ratelimit(&rs_stats)) {
 				pr_err("%s: Stats stream[%d]: dropped %d frames\n",
@@ -859,11 +936,14 @@
 	}
 }
 
-void msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg)
+int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg)
 {
 	struct msm_vfe_axi_src_state *src_state = arg;
+	if (src_state->input_src >= VFE_SRC_MAX)
+		return -EINVAL;
 	vfe_dev->axi_data.src_info[src_state->input_src].active =
 	src_state->src_active;
+	return 0;
 }
 
 int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
@@ -902,6 +982,15 @@
 
 	vfe_dev->buf_mgr->ops->buf_mgr_init(vfe_dev->buf_mgr, "msm_isp", 28);
 
+	switch (vfe_dev->vfe_hw_version) {
+	case VFE40_8974V2_VERSION:
+		vfe_dev->soc_hw_version = msm_camera_io_r(vfe_dev->tcsr_base);
+		break;
+	default:
+		/* SOC HARDWARE VERSION NOT SUPPORTED */
+		vfe_dev->soc_hw_version = 0x00;
+	}
+
 	memset(&vfe_dev->axi_data, 0, sizeof(struct msm_vfe_axi_shared_data));
 	memset(&vfe_dev->stats_data, 0,
 		sizeof(struct msm_vfe_stats_shared_data));
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
index 34b9859..3364306 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
@@ -63,8 +63,9 @@
 int msm_isp_cal_word_per_line(uint32_t output_format,
 	uint32_t pixel_per_line);
 int msm_isp_get_bit_per_pixel(uint32_t output_format);
+enum msm_isp_pack_fmt msm_isp_get_pack_format(uint32_t output_format);
 irqreturn_t msm_isp_process_irq(int irq_num, void *data);
-void msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg);
+int msm_isp_set_src_state(struct vfe_device *vfe_dev, void *arg);
 void msm_isp_do_tasklet(unsigned long data);
 void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev);
 void msm_isp_process_error_info(struct vfe_device *vfe_dev);
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 14dffa8..2b963a4 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -40,7 +40,7 @@
 #define ISPIF_INTF_CMD_DISABLE_IMMEDIATELY    0x02
 
 #define ISPIF_TIMEOUT_SLEEP_US                1000
-#define ISPIF_TIMEOUT_ALL_US                500000
+#define ISPIF_TIMEOUT_ALL_US               1000000
 
 #undef CDBG
 #ifdef CONFIG_MSMB_CAMERA_DEBUG
@@ -452,6 +452,12 @@
 		rc = -EPERM;
 		return rc;
 	}
+	if (params->num > MAX_PARAM_ENTRIES) {
+		pr_err("%s: invalid param entries %d\n", __func__,
+			params->num);
+		rc = -EINVAL;
+		return rc;
+	}
 
 	for (i = 0; i < params->num; i++) {
 		vfe_intf = params->entries[i].vfe_intf;
@@ -552,6 +558,11 @@
 			pr_err("%s: invalid interface type\n", __func__);
 			return;
 		}
+		if (params->entries[i].num_cids > MAX_CID_CH) {
+			pr_err("%s: out of range of cid_num %d\n",
+				__func__, params->entries[i].num_cids);
+			return;
+		}
 	}
 
 	for (i = 0; i < params->num; i++) {
@@ -607,6 +618,12 @@
 		return rc;
 	}
 
+	if (params->num > MAX_PARAM_ENTRIES) {
+		pr_err("%s: invalid param entries %d\n", __func__,
+			params->num);
+		rc = -EINVAL;
+		return rc;
+	}
 	msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_DISABLE_IMMEDIATELY, params);
 
 	/* after stop the interface we need to unmask the CID enable bits */
@@ -631,6 +648,12 @@
 		rc = -EPERM;
 		return rc;
 	}
+	if (params->num > MAX_PARAM_ENTRIES) {
+		pr_err("%s: invalid param entries %d\n", __func__,
+			params->num);
+		rc = -EINVAL;
+		return rc;
+	}
 
 	msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params);
 
@@ -657,6 +680,13 @@
 		return rc;
 	}
 
+	if (params->num > MAX_PARAM_ENTRIES) {
+		pr_err("%s: invalid param entries %d\n", __func__,
+			params->num);
+		rc = -EINVAL;
+		return rc;
+	}
+
 	for (i = 0; i < params->num; i++) {
 		if (!msm_ispif_is_intf_valid(ispif->csid_version,
 				params->entries[i].vfe_intf)) {
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
index c38771b..0a0fa04 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
@@ -325,7 +325,7 @@
 	}
 }
 
-int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_cmds,
+int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds,
 	uint32_t max_size, void *base)
 {
 	int is_copy_to_user = -1;
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.h b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.h
index 084e36b..4ff4292 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.h
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.h
@@ -96,7 +96,7 @@
 void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *, void *);
 int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *, int, void *);
 void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *, int);
-int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *, int ,
+int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *, uint32_t ,
 	uint32_t , void *);
 void msm_jpeg_hw_region_dump(int size);
 void msm_jpeg_io_dump(void *base, int size);
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
index 2ea4388..80ff9e5 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
@@ -25,6 +25,7 @@
 #define JPEG_REG_SIZE 0x308
 #define JPEG_DEV_CNT 3
 #define JPEG_DEC_ID 2
+#define UINT32_MAX (0xFFFFFFFFU)
 
 inline void msm_jpeg_q_init(char const *name, struct msm_jpeg_q *q_p)
 {
@@ -221,6 +222,7 @@
 		return -EAGAIN;
 	}
 
+	memset(&ctrl_cmd, 0, sizeof(ctrl_cmd));
 	ctrl_cmd.type = buf_p->vbuf.type;
 	kfree(buf_p);
 
@@ -676,7 +678,7 @@
 	void * __user arg)
 {
 	int is_copy_to_user;
-	int len;
+	uint32_t len;
 	uint32_t m;
 	struct msm_jpeg_hw_cmds *hw_cmds_p;
 	struct msm_jpeg_hw_cmd *hw_cmd_p;
@@ -686,6 +688,12 @@
 		return -EFAULT;
 	}
 
+	if ((m == 0) || (m > ((UINT32_MAX - sizeof(struct msm_jpeg_hw_cmds)) /
+		sizeof(struct msm_jpeg_hw_cmd)))) {
+		JPEG_PR_ERR("%s:%d] m_cmds out of range\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
 	len = sizeof(struct msm_jpeg_hw_cmds) +
 		sizeof(struct msm_jpeg_hw_cmd) * (m - 1);
 	hw_cmds_p = kmalloc(len, GFP_KERNEL);
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index 07f3b40..1fd1065 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -402,12 +402,15 @@
 		list, __msm_queue_find_session, &session_id);
 	if (!session)
 		return;
+	mutex_lock(&session->lock);
 
 	cmd_ack = msm_queue_find(&session->command_ack_q,
 		struct msm_command_ack,	list, __msm_queue_find_command_ack_q,
 		&stream_id);
-	if (!cmd_ack)
+	if (!cmd_ack) {
+		mutex_unlock(&session->lock);
 		return;
+	}
 
 	msm_queue_drain(&cmd_ack->command_q, struct msm_command, list);
 
@@ -416,6 +419,7 @@
 	kzfree(cmd_ack);
 	session->command_ack_q.len--;
 	spin_unlock_irqrestore(&(session->command_ack_q.lock), flags);
+	mutex_unlock(&session->lock);
 }
 
 static inline int __msm_sd_close_subdevs(struct msm_sd_subdev *msm_sd,
@@ -468,6 +472,7 @@
 	if ((!session) || !(&session->command_ack_q))
 		return;
 
+	mutex_lock(&session->lock);
 	/* to ensure error handling purpose, it needs to detach all subdevs
 	 * which are being connected to streams */
 	msm_queue_traverse_action(&session->command_ack_q,
@@ -475,6 +480,8 @@
 		__msm_remove_session_cmd_ack_q, NULL);
 
 	msm_queue_drain(&session->command_ack_q, struct msm_command_ack, list);
+
+	mutex_unlock(&session->lock);
 }
 
 int msm_destroy_session(unsigned int session_id)
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 822c0c8..c1f48f5 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -700,7 +700,7 @@
 	msm_cpp_create_buff_queue(cpp_dev, MSM_CPP_MAX_BUFF_QUEUE);
 	if (cpp_dev->is_firmware_loaded == 1) {
 		disable_irq(cpp_dev->irq->start);
-		cpp_load_fw(cpp_dev, NULL);
+		cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin);
 		enable_irq(cpp_dev->irq->start);
 		msm_camera_io_w_mb(0x7C8, cpp_dev->base +
 			MSM_CPP_MICRO_IRQGEN_MASK);
@@ -790,6 +790,7 @@
 		}
 		if (fw)
 			release_firmware(fw);
+		msm_camera_io_w_mb(0x00, cpp_dev->cpp_hw_base + 0xC);
 		msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_OK);
 		msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
 	}
@@ -856,6 +857,7 @@
 	cpp_dev->cpp_open_cnt++;
 	if (cpp_dev->cpp_open_cnt == 1) {
 		cpp_init_hardware(cpp_dev);
+		iommu_attach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
 		cpp_init_mem(cpp_dev);
 		cpp_dev->state = CPP_STATE_IDLE;
 	}
@@ -922,6 +924,7 @@
 			msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C));
 		msm_camera_io_w(0x0, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
 		cpp_deinit_mem(cpp_dev);
+		iommu_detach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
 		cpp_release_hardware(cpp_dev);
 		cpp_dev->state = CPP_STATE_OFF;
 	}
@@ -1318,7 +1321,8 @@
 
 	fw_version_1_2_x = 0;
 	if ((cpp_dev->hw_info.cpp_hw_version == CPP_HW_VERSION_1_1_0) ||
-		(cpp_dev->hw_info.cpp_hw_version == CPP_HW_VERSION_1_1_1))
+		(cpp_dev->hw_info.cpp_hw_version == CPP_HW_VERSION_1_1_1) ||
+		(cpp_dev->hw_info.cpp_hw_version == CPP_HW_VERSION_2_0_0))
 		fw_version_1_2_x = 2;
 
 	for (i = 0; i < num_stripes; i++) {
@@ -1536,6 +1540,10 @@
 		uint32_t identity;
 		struct msm_cpp_buff_queue_info_t *buff_queue_info;
 
+		if ((ioctl_ptr->len == 0) ||
+		    (ioctl_ptr->len > sizeof(uint32_t)))
+			return -EINVAL;
+
 		rc = (copy_from_user(&identity,
 				(void __user *)ioctl_ptr->ioctl_ptr,
 				ioctl_ptr->len) ? -EFAULT : 0);
@@ -1712,6 +1720,7 @@
 	return msm_register_domain(&cpp_fw_layout);
 }
 
+
 static int __devinit cpp_probe(struct platform_device *pdev)
 {
 	struct cpp_device *cpp_dev;
@@ -1826,7 +1835,6 @@
 	cpp_dev->msm_sd.sd.entity.revision = cpp_dev->msm_sd.sd.devnode->num;
 	cpp_dev->state = CPP_STATE_BOOT;
 	cpp_init_hardware(cpp_dev);
-	iommu_attach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
 
 	msm_camera_io_w(0x0, cpp_dev->base +
 					   MSM_CPP_MICRO_IRQGEN_MASK);
@@ -1854,7 +1862,6 @@
 	cpp_timers[1].used = 0;
 	cpp_dev->fw_name_bin = NULL;
 	return rc;
-
 ERROR3:
 	release_mem_region(cpp_dev->mem->start, resource_size(cpp_dev->mem));
 ERROR2:
@@ -1884,7 +1891,6 @@
 		return 0;
 	}
 
-	iommu_detach_device(cpp_dev->domain, cpp_dev->iommu_ctx);
 	msm_sd_unregister(&cpp_dev->msm_sd);
 	release_mem_region(cpp_dev->mem->start, resource_size(cpp_dev->mem));
 	release_mem_region(cpp_dev->vbif_mem->start,
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index 796bede..cf22e6c 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -28,6 +28,7 @@
 **/
 #define CPP_HW_VERSION_1_1_0  0x10010000
 #define CPP_HW_VERSION_1_1_1  0x10010001
+#define CPP_HW_VERSION_2_0_0  0x20000000
 
 #define MAX_ACTIVE_CPP_INSTANCE 8
 #define MAX_CPP_PROCESSING_FRAME 2
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
index d302131..3aaff78 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
@@ -1323,6 +1323,11 @@
 		struct msm_vpe_buff_queue_info_t *buff_queue_info;
 
 		VPE_DBG("VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO\n");
+		if (ioctl_ptr->len != sizeof(uint32_t)) {
+			pr_err("%s:%d Invalid len\n", __func__, __LINE__);
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
 
 		rc = (copy_from_user(&identity,
 				(void __user *)ioctl_ptr->ioctl_ptr,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index 7f4f231..17c5a14 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -41,6 +41,9 @@
 
 /* Max bytes that can be read per CCI read transaction */
 #define CCI_READ_MAX 12
+#define CCI_I2C_READ_MAX_RETRIES 3
+#define CCI_I2C_MAX_READ 8192
+#define CCI_I2C_MAX_WRITE 8192
 
 static struct v4l2_subdev *g_cci_subdev;
 
@@ -87,36 +90,6 @@
 	return;
 }
 
-static int32_t msm_cci_i2c_config_sync_timer(struct v4l2_subdev *sd,
-	struct msm_camera_cci_ctrl *c_ctrl)
-{
-	struct cci_device *cci_dev;
-	cci_dev = v4l2_get_subdevdata(sd);
-	msm_camera_io_w(c_ctrl->cci_info->cid, cci_dev->base +
-		CCI_SET_CID_SYNC_TIMER_0_ADDR + (c_ctrl->cci_info->cid * 0x4));
-	return 0;
-}
-
-static int32_t msm_cci_i2c_set_freq(struct v4l2_subdev *sd,
-	struct msm_camera_cci_ctrl *c_ctrl)
-{
-	struct cci_device *cci_dev;
-	uint32_t val;
-	cci_dev = v4l2_get_subdevdata(sd);
-	val = c_ctrl->cci_info->freq;
-	msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_SCL_CTL_ADDR +
-		c_ctrl->cci_info->cci_i2c_master*0x100);
-	msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_SDA_CTL_0_ADDR +
-		c_ctrl->cci_info->cci_i2c_master*0x100);
-	msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_SDA_CTL_1_ADDR +
-		c_ctrl->cci_info->cci_i2c_master*0x100);
-	msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_SDA_CTL_2_ADDR +
-		c_ctrl->cci_info->cci_i2c_master*0x100);
-	msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_MISC_CTL_ADDR +
-		c_ctrl->cci_info->cci_i2c_master*0x100);
-	return 0;
-}
-
 static void msm_cci_flush_queue(struct cci_device *cci_dev,
 	enum cci_i2c_master_t master)
 {
@@ -213,8 +186,29 @@
 	uint16_t cmd_size = i2c_msg->size;
 	struct msm_camera_i2c_reg_conf *i2c_cmd = i2c_msg->reg_conf_tbl;
 	enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master;
+
+	if (i2c_cmd == NULL) {
+		pr_err("%s:%d Failed line\n", __func__,
+			__LINE__);
+		return -EINVAL;
+	}
+
+	if ((!cmd_size) || (cmd_size > CCI_I2C_MAX_WRITE)) {
+		pr_err("%s:%d Failed line\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
 	CDBG("%s addr type %d data type %d\n", __func__,
 		i2c_msg->addr_type, i2c_msg->data_type);
+
+	if (i2c_msg->addr_type >= MSM_CAMERA_I2C_ADDR_TYPE_MAX) {
+		pr_err("%s failed line %d\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	if (i2c_msg->data_type >= MSM_CAMERA_I2C_DATA_TYPE_MAX) {
+		pr_err("%s failed line %d\n", __func__, __LINE__);
+		return -EINVAL;
+	}
 	/* assume total size within the max queue */
 	while (cmd_size) {
 		CDBG("%s cmd_size %d addr 0x%x data 0x%x", __func__,
@@ -321,6 +315,18 @@
 		goto ERROR;
 	}
 
+	if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) {
+		pr_err("%s:%d More than max retries\n", __func__,
+			__LINE__);
+		goto ERROR;
+	}
+
+	if (read_cfg->data == NULL) {
+		pr_err("%s:%d Data ptr is NULL\n", __func__,
+			__LINE__);
+		goto ERROR;
+	}
+
 	CDBG("%s master %d, queue %d\n", __func__, master, queue);
 	CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__,
 		c_ctrl->cci_info->sid, c_ctrl->cci_info->retries,
@@ -341,6 +347,11 @@
 		goto ERROR;
 	}
 
+	if (read_cfg->addr_type >= MSM_CAMERA_I2C_ADDR_TYPE_MAX) {
+		CDBG("%s failed line %d\n", __func__, __LINE__);
+		goto ERROR;
+	}
+
 	if (read_cfg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR)
 		val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4) |
 			((read_cfg->addr & 0xFF) << 8);
@@ -454,9 +465,14 @@
 		return -EINVAL;
 	}
 
+	if (c_ctrl->cci_info->cci_i2c_master > MASTER_MAX) {
+		pr_err("%s:%d Invalid I2C master addr\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+
 	master = c_ctrl->cci_info->cci_i2c_master;
 	read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg;
-	if (!read_cfg->num_byte) {
+	if ((!read_cfg->num_byte) || (read_cfg->num_byte > CCI_I2C_MAX_READ)) {
 		pr_err("%s:%d read num bytes 0\n", __func__, __LINE__);
 		rc = -EINVAL;
 		goto ERROR;
@@ -494,6 +510,10 @@
 	enum cci_i2c_master_t master;
 	enum cci_i2c_queue_t queue = QUEUE_0;
 	cci_dev = v4l2_get_subdevdata(sd);
+	if (c_ctrl->cci_info->cci_i2c_master > MASTER_MAX) {
+		pr_err("%s:%d Invalid I2C master addr\n", __func__, __LINE__);
+		return -EINVAL;
+	}
 	master = c_ctrl->cci_info->cci_i2c_master;
 	CDBG("%s master %d, queue %d\n", __func__, master, queue);
 	CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__,
@@ -514,6 +534,11 @@
 			__LINE__, rc);
 		goto ERROR;
 	}
+	if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) {
+		pr_err("%s:%d More than max retries\n", __func__,
+			__LINE__);
+		goto ERROR;
+	}
 
 	val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 |
 		c_ctrl->cci_info->retries << 16 |
@@ -533,7 +558,11 @@
 		goto ERROR;
 	}
 
-	msm_cci_data_queue(cci_dev, c_ctrl, queue);
+	rc = msm_cci_data_queue(cci_dev, c_ctrl, queue);
+	if (rc < 0) {
+		CDBG("%s failed line %d\n", __func__, __LINE__);
+		goto ERROR;
+	}
 	val = CCI_I2C_UNLOCK_CMD;
 	CDBG("%s:%d CCI_I2C_UNLOCK_CMD\n", __func__, __LINE__);
 	rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
@@ -622,7 +651,7 @@
 	if (rc < 0) {
 		cci_dev->ref_count--;
 		CDBG("%s: request gpio failed\n", __func__);
-		goto clk_enable_failed;
+		goto request_gpio_failed;
 	}
 
 	rc = msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info,
@@ -647,7 +676,7 @@
 			 __func__, __LINE__);
 		if (rc == 0)
 			rc = -ETIMEDOUT;
-		return rc;
+		goto reset_complete_failed;
 	}
 	msm_cci_set_clk_param(cci_dev);
 	msm_camera_io_w(CCI_IRQ_MASK_0_RMSK,
@@ -658,7 +687,14 @@
 	cci_dev->cci_state = CCI_STATE_ENABLED;
 	return 0;
 
+reset_complete_failed:
+	disable_irq(cci_dev->irq->start);
+	msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info,
+		cci_dev->cci_clk, ARRAY_SIZE(cci_clk_info), 0);
 clk_enable_failed:
+	msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl,
+		cci_dev->cci_gpio_tbl_size, 0);
+request_gpio_failed:
 	return rc;
 }
 
@@ -703,14 +739,6 @@
 	case MSM_CCI_RELEASE:
 		rc = msm_cci_release(sd);
 		break;
-	case MSM_CCI_SET_SID:
-		break;
-	case MSM_CCI_SET_FREQ:
-		rc = msm_cci_i2c_set_freq(sd, cci_ctrl);
-		break;
-	case MSM_CCI_SET_SYNC_CID:
-		rc = msm_cci_i2c_config_sync_timer(sd, cci_ctrl);
-		break;
 	case MSM_CCI_I2C_READ:
 		rc = msm_cci_i2c_read_bytes(sd, cci_ctrl);
 		break;
@@ -809,7 +837,10 @@
 		rc = msm_cci_config(sd, arg);
 		break;
 	case MSM_SD_SHUTDOWN: {
-		return rc;
+		struct msm_camera_cci_ctrl ctrl_cmd;
+		ctrl_cmd.cmd = MSM_CCI_RELEASE;
+		rc = msm_cci_config(sd, &ctrl_cmd);
+		break;
 	}
 	default:
 		rc = -ENOIOCTLCMD;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
index 9aca234..229fdb2 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
@@ -440,7 +440,7 @@
 	case CSID_CFG: {
 		struct msm_camera_csid_params csid_params;
 		struct msm_camera_csid_vc_cfg *vc_cfg = NULL;
-		int32_t i = 0;
+		int8_t i = 0;
 		if (copy_from_user(&csid_params,
 			(void *)cdata->cfg.csid_params,
 			sizeof(struct msm_camera_csid_params))) {
@@ -448,6 +448,13 @@
 			rc = -EFAULT;
 			break;
 		}
+		if (csid_params.lut_params.num_cid < 1 ||
+			csid_params.lut_params.num_cid > 16) {
+			pr_err("%s: %d num_cid outside range\n",
+				 __func__, __LINE__);
+			rc = -EINVAL;
+			break;
+		}
 		for (i = 0; i < csid_params.lut_params.num_cid; i++) {
 			vc_cfg = kzalloc(csid_params.lut_params.num_cid *
 				sizeof(struct msm_camera_csid_vc_cfg),
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
index 21b9cdc..9384a5b 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -124,7 +124,6 @@
 		j++;
 		lane_mask >>= 1;
 	}
-	msleep(20);
 	return rc;
 }
 
@@ -423,7 +422,7 @@
 				__LINE__, csi_lane_params);
 			return -EINVAL;
 		}
-		csi_lane_mask = csi_lane_params->csi_lane_mask;
+		csi_lane_mask = (csi_lane_params->csi_lane_mask & 0x1F);
 
 		CDBG("%s csiphy_params, lane assign %x mask = %x\n",
 			__func__,
@@ -436,7 +435,7 @@
 		csiphy_dev->lane_mask[csiphy_dev->pdev->id] &=
 			~(csi_lane_mask);
 		i = 0;
-		while (csi_lane_mask & 0x1F) {
+		while (csi_lane_mask) {
 			if (csi_lane_mask & 0x1) {
 				msm_camera_io_w(0x0, csiphy_dev->base +
 					MIPI_CSIPHY_LNn_CFG2_ADDR + 0x40*i);
@@ -507,7 +506,7 @@
 				__LINE__, csi_lane_params);
 			return -EINVAL;
 		}
-		csi_lane_mask = csi_lane_params->csi_lane_mask;
+		csi_lane_mask = (csi_lane_params->csi_lane_mask & 0x1F);
 
 		CDBG("%s csiphy_params, lane assign %x mask = %x\n",
 			__func__,
@@ -520,7 +519,7 @@
 		csiphy_dev->lane_mask[csiphy_dev->pdev->id] &=
 			~(csi_lane_mask);
 		i = 0;
-		while (csi_lane_mask & 0x1F) {
+		while (csi_lane_mask) {
 			if (csi_lane_mask & 0x1) {
 				msm_camera_io_w(0x0, csiphy_dev->base +
 					MIPI_CSIPHY_LNn_CFG2_ADDR + 0x40*i);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
index 4ebcfdf..1407f12 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
@@ -98,6 +98,7 @@
 	.i2c_read = msm_camera_cci_i2c_read,
 	.i2c_read_seq = msm_camera_cci_i2c_read_seq,
 	.i2c_write = msm_camera_cci_i2c_write,
+	.i2c_write_seq = msm_camera_cci_i2c_write_seq,
 	.i2c_write_table = msm_camera_cci_i2c_write_table,
 	.i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table,
 	.i2c_write_table_w_microdelay =
@@ -180,7 +181,17 @@
 				return rc;
 			}
 		}
-
+		if (emap[j].pageen.valid_size) {
+			e_ctrl->i2c_client.addr_type = emap[j].pageen.addr_t;
+			rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write(
+				&(e_ctrl->i2c_client), emap[j].pageen.addr,
+				emap[j].pageen.data, emap[j].pageen.data_t);
+				msleep(emap[j].pageen.delay);
+			if (rc < 0) {
+				pr_err("%s: page enable failed\n", __func__);
+				return rc;
+			}
+		}
 		if (emap[j].poll.valid_size) {
 			e_ctrl->i2c_client.addr_type = emap[j].poll.addr_t;
 			rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_poll(
@@ -204,6 +215,16 @@
 			}
 			memptr += emap[j].mem.valid_size;
 		}
+		if (emap[j].pageen.valid_size) {
+			e_ctrl->i2c_client.addr_type = emap[j].pageen.addr_t;
+			rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write(
+				&(e_ctrl->i2c_client), emap[j].pageen.addr,
+				0, emap[j].pageen.data_t);
+			if (rc < 0) {
+				pr_err("%s: page disable failed\n", __func__);
+				return rc;
+			}
+		}
 	}
 	return rc;
 }
@@ -212,7 +233,7 @@
 				       struct device_node *of)
 {
 	int i, rc = 0;
-	char property[12];
+	char property[14];
 	uint32_t count = 6;
 	struct msm_eeprom_board_info *eb = e_ctrl->eboard_info;
 
@@ -240,6 +261,12 @@
 			goto out;
 		}
 
+		snprintf(property, 14, "qcom,pageen%d", i);
+		rc = of_property_read_u32_array(of, property,
+			(uint32_t *) &eb->eeprom_map[i].pageen, count);
+		if (rc < 0)
+			pr_err("%s: pageen not needed\n", __func__);
+
 		snprintf(property, 12, "qcom,poll%d", i);
 		rc = of_property_read_u32_array(of, property,
 			(uint32_t *) &eb->eeprom_map[i].poll, count);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile b/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile
index 4ce7372..62102cb 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile
@@ -2,3 +2,5 @@
 ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
 obj-$(CONFIG_MSMB_CAMERA) += msm_led_flash.o
 obj-$(CONFIG_MSMB_CAMERA) += msm_led_trigger.o
+obj-$(CONFIG_MSMB_CAMERA) += msm_led_i2c_trigger.o
+obj-$(CONFIG_MSMB_CAMERA) += adp1660.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/adp1660.c b/drivers/media/platform/msm/camera_v2/sensor/flash/adp1660.c
new file mode 100644
index 0000000..aad8158
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/adp1660.c
@@ -0,0 +1,182 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/export.h>
+#include "msm_led_flash.h"
+
+#define FLASH_NAME "qcom,led-flash"
+
+/*#define CONFIG_MSMB_CAMERA_DEBUG*/
+#undef CDBG
+#ifdef CONFIG_MSMB_CAMERA_DEBUG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) do { } while (0)
+#endif
+
+static struct msm_led_flash_ctrl_t fctrl;
+static struct i2c_driver adp1660_i2c_driver;
+
+static struct msm_camera_i2c_reg_array adp1660_init_array[] = {
+	{0x01, 0x03},
+	{0x02, 0x0F},
+	{0x09, 0x28},
+};
+
+static struct msm_camera_i2c_reg_array adp1660_off_array[] = {
+	{0x0f, 0x00},
+};
+
+static struct msm_camera_i2c_reg_array adp1660_release_array[] = {
+	{0x0f, 0x00},
+};
+
+static struct msm_camera_i2c_reg_array adp1660_low_array[] = {
+	{0x08, 0x04},
+	{0x06, 0x1E},
+	{0x01, 0xBD},
+	{0x0f, 0x01},
+};
+
+static struct msm_camera_i2c_reg_array adp1660_high_array[] = {
+	{0x02, 0x4F},
+	{0x06, 0x3C},
+	{0x09, 0x28},
+	{0x0f, 0x01},
+	{0x01, 0xBD},
+};
+
+static void __exit msm_flash_adp1660_i2c_remove(void)
+{
+	i2c_del_driver(&adp1660_i2c_driver);
+	return;
+}
+
+static const struct of_device_id adp1660_i2c_trigger_dt_match[] = {
+	{.compatible = "qcom,led-flash"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, adp1660_i2c_trigger_dt_match);
+
+static const struct i2c_device_id flash_i2c_id[] = {
+	{"qcom,led-flash", (kernel_ulong_t)&fctrl},
+	{ }
+};
+
+static const struct i2c_device_id adp1660_i2c_id[] = {
+	{FLASH_NAME, (kernel_ulong_t)&fctrl},
+	{ }
+};
+
+static int msm_flash_adp1660_i2c_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	if (!id) {
+		pr_err("msm_flash_adp1660_i2c_probe: id is NULL");
+		id = adp1660_i2c_id;
+	}
+
+	return msm_flash_i2c_probe(client, id);
+}
+
+static struct i2c_driver adp1660_i2c_driver = {
+	.id_table = adp1660_i2c_id,
+	.probe  = msm_flash_adp1660_i2c_probe,
+	.remove = __exit_p(msm_flash_adp1660_i2c_remove),
+	.driver = {
+		.name = FLASH_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = adp1660_i2c_trigger_dt_match,
+	},
+};
+
+static int __init msm_flash_adp1660_i2c_add_driver(void)
+{
+	CDBG("%s called\n", __func__);
+	return i2c_add_driver(&adp1660_i2c_driver);
+}
+
+static struct msm_camera_i2c_client adp1660_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+};
+
+static struct msm_camera_i2c_reg_setting adp1660_init_setting = {
+	.reg_setting = adp1660_init_array,
+	.size = ARRAY_SIZE(adp1660_init_array),
+	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+	.data_type = MSM_CAMERA_I2C_BYTE_DATA,
+	.delay = 0,
+};
+
+static struct msm_camera_i2c_reg_setting adp1660_off_setting = {
+	.reg_setting = adp1660_off_array,
+	.size = ARRAY_SIZE(adp1660_off_array),
+	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+	.data_type = MSM_CAMERA_I2C_BYTE_DATA,
+	.delay = 0,
+};
+
+static struct msm_camera_i2c_reg_setting adp1660_release_setting = {
+	.reg_setting = adp1660_release_array,
+	.size = ARRAY_SIZE(adp1660_release_array),
+	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+	.data_type = MSM_CAMERA_I2C_BYTE_DATA,
+	.delay = 0,
+};
+
+static struct msm_camera_i2c_reg_setting adp1660_low_setting = {
+	.reg_setting = adp1660_low_array,
+	.size = ARRAY_SIZE(adp1660_low_array),
+	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+	.data_type = MSM_CAMERA_I2C_BYTE_DATA,
+	.delay = 0,
+};
+
+static struct msm_camera_i2c_reg_setting adp1660_high_setting = {
+	.reg_setting = adp1660_high_array,
+	.size = ARRAY_SIZE(adp1660_high_array),
+	.addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+	.data_type = MSM_CAMERA_I2C_BYTE_DATA,
+	.delay = 0,
+};
+
+static struct msm_led_flash_reg_t adp1660_regs = {
+	.init_setting = &adp1660_init_setting,
+	.off_setting = &adp1660_off_setting,
+	.low_setting = &adp1660_low_setting,
+	.high_setting = &adp1660_high_setting,
+	.release_setting = &adp1660_release_setting,
+};
+
+static struct msm_flash_fn_t adp1660_func_tbl = {
+	.flash_get_subdev_id = msm_led_i2c_trigger_get_subdev_id,
+	.flash_led_config = msm_led_i2c_trigger_config,
+	.flash_led_init = msm_flash_led_init,
+	.flash_led_release = msm_flash_led_release,
+	.flash_led_off = msm_flash_led_off,
+	.flash_led_low = msm_flash_led_low,
+	.flash_led_high = msm_flash_led_high,
+};
+
+static struct msm_led_flash_ctrl_t fctrl = {
+	.flash_i2c_client = &adp1660_i2c_client,
+	.reg_setting = &adp1660_regs,
+	.func_tbl = &adp1660_func_tbl,
+};
+
+/*subsys_initcall(msm_flash_i2c_add_driver);*/
+module_init(msm_flash_adp1660_i2c_add_driver);
+module_exit(msm_flash_adp1660_i2c_remove);
+MODULE_DESCRIPTION("adp1660 FLASH");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
index 044fd31..2de17c9 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
@@ -42,6 +42,9 @@
 		return fctrl->func_tbl->flash_get_subdev_id(fctrl, argp);
 	case VIDIOC_MSM_FLASH_LED_DATA_CFG:
 		return fctrl->func_tbl->flash_led_config(fctrl, argp);
+	case MSM_SD_SHUTDOWN:
+		*(int *)argp = MSM_CAMERA_LED_RELEASE;
+		return fctrl->func_tbl->flash_led_config(fctrl, argp);
 	default:
 		pr_err("invalid cmd %d\n", cmd);
 		return -ENOIOCTLCMD;
@@ -87,3 +90,31 @@
 	CDBG("probe success\n");
 	return 0;
 }
+
+int32_t msm_led_i2c_flash_create_v4lsubdev(void *data)
+{
+	struct msm_led_flash_ctrl_t *fctrl =
+		(struct msm_led_flash_ctrl_t *)data;
+	CDBG("Enter\n");
+
+	if (!fctrl) {
+		pr_err("fctrl NULL\n");
+		return -EINVAL;
+	}
+
+	/* Initialize sub device */
+	v4l2_subdev_init(&fctrl->msm_sd.sd, &msm_flash_subdev_ops);
+	v4l2_set_subdevdata(&fctrl->msm_sd.sd, fctrl);
+
+	fctrl->msm_sd.sd.internal_ops = &msm_flash_internal_ops;
+	fctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(fctrl->msm_sd.sd.name, ARRAY_SIZE(fctrl->msm_sd.sd.name),
+		"msm_flash");
+	media_entity_init(&fctrl->msm_sd.sd.entity, 0, NULL, 0);
+	fctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+	fctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_LED_FLASH;
+	msm_sd_register(&fctrl->msm_sd);
+
+	CDBG("probe success\n");
+	return 0;
+}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
index c713c85..9f3a81c 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
@@ -17,6 +17,8 @@
 #include <linux/platform_device.h>
 #include <media/v4l2-subdev.h>
 #include <media/msm_cam_sensor.h>
+#include <mach/camera2.h>
+#include "msm_camera_i2c.h"
 #include "msm_sd.h"
 
 #define MAX_LED_TRIGGERS 3
@@ -33,11 +35,21 @@
 	int32_t (*flash_led_high)(struct msm_led_flash_ctrl_t *);
 };
 
+struct msm_led_flash_reg_t {
+	struct msm_camera_i2c_reg_setting *init_setting;
+	struct msm_camera_i2c_reg_setting *off_setting;
+	struct msm_camera_i2c_reg_setting *release_setting;
+	struct msm_camera_i2c_reg_setting *low_setting;
+	struct msm_camera_i2c_reg_setting *high_setting;
+};
+
 struct msm_led_flash_ctrl_t {
 	struct msm_camera_i2c_client *flash_i2c_client;
 	struct msm_sd_subdev msm_sd;
 	struct platform_device *pdev;
 	struct msm_flash_fn_t *func_tbl;
+	struct msm_camera_sensor_board_info *flashdata;
+	struct msm_led_flash_reg_t *reg_setting;
 	const char *flash_trigger_name[MAX_LED_TRIGGERS];
 	struct led_trigger *flash_trigger[MAX_LED_TRIGGERS];
 	uint32_t flash_op_current[MAX_LED_TRIGGERS];
@@ -46,9 +58,26 @@
 	uint32_t torch_op_current;
 	void *data;
 	uint32_t num_sources;
+	enum msm_camera_device_type_t flash_device_type;
+	uint32_t subdev_id;
 };
 
+int msm_flash_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id);
+
 int32_t msm_led_flash_create_v4lsubdev(struct platform_device *pdev,
 	void *data);
+int32_t msm_led_i2c_flash_create_v4lsubdev(void *data);
 
+int32_t msm_led_i2c_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl,
+	void *arg);
+
+int32_t msm_led_i2c_trigger_config(struct msm_led_flash_ctrl_t *fctrl,
+	void *data);
+
+int msm_flash_led_init(struct msm_led_flash_ctrl_t *fctrl);
+int msm_flash_led_release(struct msm_led_flash_ctrl_t *fctrl);
+int msm_flash_led_off(struct msm_led_flash_ctrl_t *fctrl);
+int msm_flash_led_low(struct msm_led_flash_ctrl_t *fctrl);
+int msm_flash_led_high(struct msm_led_flash_ctrl_t *fctrl);
 #endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_i2c_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_i2c_trigger.c
new file mode 100644
index 0000000..b5afa86
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_i2c_trigger.c
@@ -0,0 +1,538 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <mach/gpiomux.h>
+#include <linux/module.h>
+#include "msm_led_flash.h"
+#include "msm_camera_io_util.h"
+#include "../msm_sensor.h"
+#include "msm_led_flash.h"
+
+#define FLASH_NAME "camera-led-flash"
+
+/*#define CONFIG_MSMB_CAMERA_DEBUG*/
+#undef CDBG
+#ifdef CONFIG_MSMB_CAMERA_DEBUG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) do { } while (0)
+#endif
+
+int32_t msm_led_i2c_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl,
+	void *arg)
+{
+	uint32_t *subdev_id = (uint32_t *)arg;
+	if (!subdev_id) {
+		pr_err("failed\n");
+		return -EINVAL;
+	}
+	*subdev_id = fctrl->subdev_id;
+
+	CDBG("subdev_id %d\n", *subdev_id);
+	return 0;
+}
+
+int32_t msm_led_i2c_trigger_config(struct msm_led_flash_ctrl_t *fctrl,
+	void *data)
+{
+	int rc = 0;
+	struct msm_camera_led_cfg_t *cfg = (struct msm_camera_led_cfg_t *)data;
+	CDBG("called led_state %d\n", cfg->cfgtype);
+
+	if (!fctrl->func_tbl) {
+		pr_err("failed\n");
+		return -EINVAL;
+	}
+	switch (cfg->cfgtype) {
+
+	case MSM_CAMERA_LED_INIT:
+		if (fctrl->func_tbl->flash_led_init)
+			rc = fctrl->func_tbl->flash_led_init(fctrl);
+		break;
+
+	case MSM_CAMERA_LED_RELEASE:
+		if (fctrl->func_tbl->flash_led_release)
+			rc = fctrl->func_tbl->
+				flash_led_release(fctrl);
+		break;
+
+	case MSM_CAMERA_LED_OFF:
+		if (fctrl->func_tbl->flash_led_off)
+			rc = fctrl->func_tbl->flash_led_off(fctrl);
+		break;
+
+	case MSM_CAMERA_LED_LOW:
+		if (fctrl->func_tbl->flash_led_low)
+			rc = fctrl->func_tbl->flash_led_low(fctrl);
+		break;
+
+	case MSM_CAMERA_LED_HIGH:
+		if (fctrl->func_tbl->flash_led_high)
+			rc = fctrl->func_tbl->flash_led_high(fctrl);
+		break;
+	default:
+		rc = -EFAULT;
+		break;
+	}
+	CDBG("flash_set_led_state: return %d\n", rc);
+	return rc;
+}
+
+int msm_flash_led_init(struct msm_led_flash_ctrl_t *fctrl)
+{
+	int rc = 0;
+	struct msm_camera_sensor_board_info *flashdata = NULL;
+	CDBG("%s:%d called\n", __func__, __LINE__);
+
+	flashdata = fctrl->flashdata;
+	if (flashdata->gpio_conf->cam_gpiomux_conf_tbl != NULL) {
+		pr_err("%s:%d mux install\n", __func__, __LINE__);
+		msm_gpiomux_install(
+			(struct msm_gpiomux_config *)
+			flashdata->gpio_conf->cam_gpiomux_conf_tbl,
+			flashdata->gpio_conf->cam_gpiomux_conf_tbl_size);
+	}
+
+	rc = msm_camera_request_gpio_table(
+		flashdata->gpio_conf->cam_gpio_req_tbl,
+		flashdata->gpio_conf->cam_gpio_req_tbl_size, 1);
+	if (rc < 0) {
+		pr_err("%s: request gpio failed\n", __func__);
+		return rc;
+	}
+	msleep(20);
+	gpio_set_value_cansleep(
+		flashdata->gpio_conf->gpio_num_info->gpio_num[0],
+		GPIO_OUT_HIGH);
+
+	if (fctrl->flash_i2c_client && fctrl->reg_setting) {
+		rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table(
+			fctrl->flash_i2c_client,
+			fctrl->reg_setting->init_setting);
+		if (rc < 0)
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+	}
+
+	return rc;
+}
+
+int msm_flash_led_release(struct msm_led_flash_ctrl_t *fctrl)
+{
+	int rc = 0;
+	struct msm_camera_sensor_board_info *flashdata = NULL;
+
+	flashdata = fctrl->flashdata;
+	CDBG("%s:%d called\n", __func__, __LINE__);
+	if (!fctrl) {
+		pr_err("%s:%d fctrl NULL\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	gpio_set_value_cansleep(
+		flashdata->gpio_conf->gpio_num_info->gpio_num[0],
+		GPIO_OUT_LOW);
+	gpio_set_value_cansleep(
+		flashdata->gpio_conf->gpio_num_info->gpio_num[1],
+		GPIO_OUT_LOW);
+	rc = msm_camera_request_gpio_table(
+		flashdata->gpio_conf->cam_gpio_req_tbl,
+		flashdata->gpio_conf->cam_gpio_req_tbl_size, 0);
+	if (rc < 0) {
+		pr_err("%s: request gpio failed\n", __func__);
+		return rc;
+	}
+	return 0;
+}
+
+int msm_flash_led_off(struct msm_led_flash_ctrl_t *fctrl)
+{
+	int rc = 0;
+	struct msm_camera_sensor_board_info *flashdata = NULL;
+
+	flashdata = fctrl->flashdata;
+	CDBG("%s:%d called\n", __func__, __LINE__);
+	if (!fctrl) {
+		pr_err("%s:%d fctrl NULL\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	if (fctrl->flash_i2c_client && fctrl->reg_setting) {
+		rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table(
+			fctrl->flash_i2c_client,
+			fctrl->reg_setting->off_setting);
+		if (rc < 0)
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+	}
+	gpio_set_value_cansleep(
+		flashdata->gpio_conf->gpio_num_info->gpio_num[1],
+		GPIO_OUT_LOW);
+
+	return rc;
+}
+
+int msm_flash_led_low(struct msm_led_flash_ctrl_t *fctrl)
+{
+	int rc = 0;
+	struct msm_camera_sensor_board_info *flashdata = NULL;
+	CDBG("%s:%d called\n", __func__, __LINE__);
+
+	flashdata = fctrl->flashdata;
+	gpio_set_value_cansleep(
+		flashdata->gpio_conf->gpio_num_info->gpio_num[0],
+		GPIO_OUT_HIGH);
+
+	gpio_set_value_cansleep(
+		flashdata->gpio_conf->gpio_num_info->gpio_num[1],
+		GPIO_OUT_HIGH);
+
+
+	if (fctrl->flash_i2c_client && fctrl->reg_setting) {
+		rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table(
+			fctrl->flash_i2c_client,
+			fctrl->reg_setting->low_setting);
+		if (rc < 0)
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+	}
+
+	return rc;
+}
+
+int msm_flash_led_high(struct msm_led_flash_ctrl_t *fctrl)
+{
+	int rc = 0;
+	struct msm_camera_sensor_board_info *flashdata = NULL;
+	CDBG("%s:%d called\n", __func__, __LINE__);
+
+	flashdata = fctrl->flashdata;
+	gpio_set_value_cansleep(
+		flashdata->gpio_conf->gpio_num_info->gpio_num[0],
+		GPIO_OUT_HIGH);
+
+	gpio_set_value_cansleep(
+		flashdata->gpio_conf->gpio_num_info->gpio_num[1],
+		GPIO_OUT_HIGH);
+
+	if (fctrl->flash_i2c_client && fctrl->reg_setting) {
+		rc = fctrl->flash_i2c_client->i2c_func_tbl->i2c_write_table(
+			fctrl->flash_i2c_client,
+			fctrl->reg_setting->high_setting);
+		if (rc < 0)
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+	}
+
+	return rc;
+}
+
+static int32_t msm_flash_init_gpio_pin_tbl(struct device_node *of_node,
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size)
+{
+	int32_t rc = 0;
+	int32_t val = 0;
+
+	gconf->gpio_num_info = kzalloc(sizeof(struct msm_camera_gpio_num_info),
+		GFP_KERNEL);
+	if (!gconf->gpio_num_info) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,gpio-flash-en", &val);
+	if (rc < 0) {
+		pr_err("%s:%d read qcom,gpio-flash-en failed rc %d\n",
+			__func__, __LINE__, rc);
+		goto ERROR;
+	} else if (val >= gpio_array_size) {
+		pr_err("%s:%d qcom,gpio-flash-en invalid %d\n",
+			__func__, __LINE__, val);
+		goto ERROR;
+	}
+	/*index 0 is for qcom,gpio-flash-en */
+	gconf->gpio_num_info->gpio_num[0] =
+		gpio_array[val];
+	CDBG("%s qcom,gpio-flash-en %d\n", __func__,
+		gconf->gpio_num_info->gpio_num[0]);
+
+	rc = of_property_read_u32(of_node, "qcom,gpio-flash-now", &val);
+	if (rc < 0) {
+		pr_err("%s:%d read qcom,gpio-flash-now failed rc %d\n",
+			__func__, __LINE__, rc);
+		goto ERROR;
+	} else if (val >= gpio_array_size) {
+		pr_err("%s:%d qcom,gpio-flash-now invalid %d\n",
+			__func__, __LINE__, val);
+		goto ERROR;
+	}
+	/*index 1 is for qcom,gpio-flash-now */
+	gconf->gpio_num_info->gpio_num[1] =
+		gpio_array[val];
+	CDBG("%s qcom,gpio-flash-now %d\n", __func__,
+		gconf->gpio_num_info->gpio_num[1]);
+
+	return rc;
+
+ERROR:
+	kfree(gconf->gpio_num_info);
+	gconf->gpio_num_info = NULL;
+	return rc;
+}
+
+static int32_t msm_led_get_dt_data(struct device_node *of_node,
+		struct msm_led_flash_ctrl_t *fctrl)
+{
+	int32_t rc = 0, i = 0;
+	struct msm_camera_gpio_conf *gconf = NULL;
+	struct device_node *flash_src_node = NULL;
+	struct msm_camera_sensor_board_info *flashdata = NULL;
+	uint32_t count = 0;
+	uint16_t *gpio_array = NULL;
+	uint16_t gpio_array_size = 0;
+	uint32_t id_info[3];
+
+	CDBG("called\n");
+
+	if (!of_node) {
+		pr_err("of_node NULL\n");
+		return -EINVAL;
+	}
+
+	fctrl->flashdata = kzalloc(sizeof(
+		struct msm_camera_sensor_board_info),
+		GFP_KERNEL);
+	if (!fctrl->flashdata) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	flashdata = fctrl->flashdata;
+
+	flashdata->sensor_init_params = kzalloc(sizeof(
+		struct msm_sensor_init_params), GFP_KERNEL);
+	if (!flashdata->sensor_init_params) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	rc = of_property_read_u32(of_node, "cell-index", &fctrl->subdev_id);
+	if (rc < 0) {
+		pr_err("failed\n");
+		return -EINVAL;
+	}
+
+	CDBG("subdev id %d\n", fctrl->subdev_id);
+
+	rc = of_property_read_string(of_node, "qcom,flash-name",
+		&flashdata->sensor_name);
+	CDBG("%s qcom,flash-name %s, rc %d\n", __func__,
+		flashdata->sensor_name, rc);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto ERROR1;
+	}
+
+	if (of_get_property(of_node, "qcom,flash-source", &count)) {
+		count /= sizeof(uint32_t);
+		CDBG("count %d\n", count);
+		if (count > MAX_LED_TRIGGERS) {
+			pr_err("failed\n");
+			return -EINVAL;
+		}
+		for (i = 0; i < count; i++) {
+			flash_src_node = of_parse_phandle(of_node,
+				"qcom,flash-source", i);
+			if (!flash_src_node) {
+				pr_err("flash_src_node NULL\n");
+				continue;
+			}
+
+			rc = of_property_read_string(flash_src_node,
+				"linux,default-trigger",
+				&fctrl->flash_trigger_name[i]);
+			if (rc < 0) {
+				pr_err("failed\n");
+				of_node_put(flash_src_node);
+				continue;
+			}
+
+			CDBG("default trigger %s\n",
+				 fctrl->flash_trigger_name[i]);
+
+			rc = of_property_read_u32(flash_src_node,
+				"qcom,max-current",
+				&fctrl->flash_op_current[i]);
+			if (rc < 0) {
+				pr_err("failed rc %d\n", rc);
+				of_node_put(flash_src_node);
+				continue;
+			}
+
+			of_node_put(flash_src_node);
+
+			CDBG("max_current[%d] %d\n",
+				i, fctrl->flash_op_current[i]);
+
+			led_trigger_register_simple(
+				fctrl->flash_trigger_name[i],
+				&fctrl->flash_trigger[i]);
+		}
+
+	} else { /*Handle LED Flash Ctrl by GPIO*/
+		flashdata->gpio_conf =
+			 kzalloc(sizeof(struct msm_camera_gpio_conf),
+				 GFP_KERNEL);
+		if (!flashdata->gpio_conf) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			return rc;
+		}
+		gconf = flashdata->gpio_conf;
+
+		gpio_array_size = of_gpio_count(of_node);
+		CDBG("%s gpio count %d\n", __func__, gpio_array_size);
+
+		if (gpio_array_size) {
+			gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size,
+				GFP_KERNEL);
+			if (!gpio_array) {
+				pr_err("%s failed %d\n", __func__, __LINE__);
+				rc = -ENOMEM;
+				goto ERROR4;
+			}
+			for (i = 0; i < gpio_array_size; i++) {
+				gpio_array[i] = of_get_gpio(of_node, i);
+				CDBG("%s gpio_array[%d] = %d\n", __func__, i,
+					gpio_array[i]);
+			}
+
+			rc = msm_sensor_get_dt_gpio_req_tbl(of_node, gconf,
+				gpio_array, gpio_array_size);
+			if (rc < 0) {
+				pr_err("%s failed %d\n", __func__, __LINE__);
+				goto ERROR4;
+			}
+
+			rc = msm_sensor_get_dt_gpio_set_tbl(of_node, gconf,
+				gpio_array, gpio_array_size);
+			if (rc < 0) {
+				pr_err("%s failed %d\n", __func__, __LINE__);
+				goto ERROR5;
+			}
+
+			rc = msm_flash_init_gpio_pin_tbl(of_node, gconf,
+				gpio_array, gpio_array_size);
+			if (rc < 0) {
+				pr_err("%s failed %d\n", __func__, __LINE__);
+				goto ERROR6;
+			}
+		}
+
+		flashdata->slave_info =
+			kzalloc(sizeof(struct msm_camera_slave_info),
+				GFP_KERNEL);
+		if (!flashdata->slave_info) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			goto ERROR8;
+		}
+
+		rc = of_property_read_u32_array(of_node, "qcom,slave-id",
+			id_info, 3);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR9;
+		}
+		fctrl->flashdata->slave_info->sensor_slave_addr = id_info[0];
+		fctrl->flashdata->slave_info->sensor_id_reg_addr = id_info[1];
+		fctrl->flashdata->slave_info->sensor_id = id_info[2];
+
+		kfree(gpio_array);
+		return rc;
+ERROR9:
+		kfree(fctrl->flashdata->slave_info);
+ERROR8:
+		kfree(fctrl->flashdata->gpio_conf->gpio_num_info);
+ERROR6:
+		kfree(gconf->cam_gpio_set_tbl);
+ERROR5:
+		kfree(gconf->cam_gpio_req_tbl);
+ERROR4:
+		kfree(gconf);
+ERROR1:
+		kfree(fctrl->flashdata);
+		kfree(gpio_array);
+	}
+	return rc;
+}
+
+static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = {
+	.i2c_read = msm_camera_qup_i2c_read,
+	.i2c_read_seq = msm_camera_qup_i2c_read_seq,
+	.i2c_write = msm_camera_qup_i2c_write,
+	.i2c_write_table = msm_camera_qup_i2c_write_table,
+	.i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table,
+	.i2c_write_table_w_microdelay =
+		msm_camera_qup_i2c_write_table_w_microdelay,
+};
+
+int msm_flash_i2c_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	int rc = 0;
+	struct msm_led_flash_ctrl_t *fctrl = NULL;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("i2c_check_functionality failed\n");
+		goto probe_failure;
+	}
+
+	fctrl = (struct msm_led_flash_ctrl_t *)(id->driver_data);
+	if (fctrl->flash_i2c_client)
+		fctrl->flash_i2c_client->client = client;
+	/* Set device type as I2C */
+	fctrl->flash_device_type = MSM_CAMERA_I2C_DEVICE;
+
+	/* Assign name for sub device */
+	snprintf(fctrl->msm_sd.sd.name, sizeof(fctrl->msm_sd.sd.name),
+		"%s", id->name);
+
+	rc = msm_led_get_dt_data(client->dev.of_node, fctrl);
+	if (rc < 0) {
+		pr_err("%s failed line %d\n", __func__, __LINE__);
+		return rc;
+	}
+	if (fctrl->flash_i2c_client != NULL) {
+		fctrl->flash_i2c_client->client = client;
+		if (fctrl->flashdata->slave_info->sensor_slave_addr)
+			fctrl->flash_i2c_client->client->addr =
+				fctrl->flashdata->slave_info->
+				sensor_slave_addr;
+	} else {
+		pr_err("%s %s sensor_i2c_client NULL\n",
+			__func__, client->name);
+		rc = -EFAULT;
+		return rc;
+	}
+
+	if (!fctrl->flash_i2c_client->i2c_func_tbl)
+		fctrl->flash_i2c_client->i2c_func_tbl =
+			&msm_sensor_qup_func_tbl;
+
+	rc = msm_led_i2c_flash_create_v4lsubdev(fctrl);
+	CDBG("%s:%d probe success\n", __func__, __LINE__);
+	return 0;
+
+probe_failure:
+	CDBG("%s:%d probe failed\n", __func__, __LINE__);
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/gc0339.c b/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
index cc38b56..8288ad0 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
@@ -33,6 +33,18 @@
 static struct msm_sensor_power_setting gc0339_power_setting[] = {
 
 	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 0,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 0,
+	},
+	{
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VIO,
 		.config_val = 0,
@@ -51,12 +63,6 @@
 		.delay = 0,
 	},
 	{
-		.seq_type = SENSOR_GPIO,
-		.seq_val = SENSOR_GPIO_STANDBY,
-		.config_val = GPIO_OUT_HIGH,
-		.delay = 0,
-	},
-	{
 		.seq_type = SENSOR_CLK,
 		.seq_val = SENSOR_CAM_MCLK,
 		.config_val = 24000000,
@@ -74,18 +80,6 @@
 		.config_val = GPIO_OUT_HIGH,
 		.delay = 1,
 	},
-	{
-		.seq_type = SENSOR_GPIO,
-		.seq_val = SENSOR_GPIO_RESET,
-		.config_val = GPIO_OUT_LOW,
-		.delay = 1,
-	},
-	{
-		.seq_type = SENSOR_GPIO,
-		.seq_val = SENSOR_GPIO_RESET,
-		.config_val = GPIO_OUT_HIGH,
-		.delay = 1,
-	},
 };
 
 static struct v4l2_subdev_info gc0339_subdev_info[] = {
@@ -223,6 +217,12 @@
 			goto power_up_failed;
 		}
 	}
+
+	s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write(
+		s_ctrl->sensor_i2c_client,
+		0xfc,
+		0x10, MSM_CAMERA_I2C_BYTE_DATA);
+
 	if (s_ctrl->func_tbl->sensor_match_id)
 		rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl);
 	else
@@ -254,9 +254,12 @@
 				0);
 			break;
 		case SENSOR_GPIO:
-			gpio_set_value_cansleep(
-				data->gpio_conf->gpio_num_info->gpio_num
-				[power_setting->seq_val], GPIOF_OUT_INIT_LOW);
+			if (data->gpio_conf->gpio_num_info->gpio_num
+				[power_setting->seq_val])
+				gpio_set_value_cansleep(
+					data->gpio_conf->gpio_num_info->gpio_num
+					[power_setting->seq_val],
+					GPIOF_OUT_INIT_LOW);
 			break;
 		case SENSOR_VREG:
 			msm_camera_config_single_vreg(s_ctrl->dev,
@@ -297,6 +300,11 @@
 			s_ctrl->sensor_i2c_client, MSM_CCI_RELEASE);
 	}
 
+	s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write(
+		s_ctrl->sensor_i2c_client,
+		0xfc,
+		0x01, MSM_CAMERA_I2C_BYTE_DATA);
+
 	for (index = (power_setting_array->size - 1); index >= 0; index--) {
 		CDBG("%s index %d\n", __func__, index);
 		power_setting = &power_setting_array->power_setting[index];
@@ -317,9 +325,12 @@
 					SENSOR_GPIO_MAX);
 				continue;
 			}
-			gpio_set_value_cansleep(
-				data->gpio_conf->gpio_num_info->gpio_num
-				[power_setting->seq_val], GPIOF_OUT_INIT_LOW);
+			if (data->gpio_conf->gpio_num_info->gpio_num
+				[power_setting->seq_val])
+				gpio_set_value_cansleep(
+					data->gpio_conf->gpio_num_info->gpio_num
+					[power_setting->seq_val],
+					GPIOF_OUT_INIT_LOW);
 			break;
 		case SENSOR_VREG:
 			if (power_setting->seq_val >= CAM_VREG_MAX) {
@@ -356,10 +367,7 @@
 {
 	int32_t rc = 0;
 	uint16_t chipid = 0;
-	s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write(
-				s_ctrl->sensor_i2c_client,
-				0xfc,
-				0x10, MSM_CAMERA_I2C_BYTE_DATA);
+
 	rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read(
 			s_ctrl->sensor_i2c_client,
 			s_ctrl->sensordata->slave_info->sensor_id_reg_addr,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/hi256.c b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
index de651df..3288e9c 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/hi256.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
@@ -151,7 +151,7 @@
 
 	{0x03, 0x00},
 	{0x10, 0x13},
-	{0x11, 0x93},
+	{0x11, 0x90}, /* no H/V flip */
 	{0x12, 0x00},
 	{0x0b, 0xaa},
 	{0x0c, 0xaa},
@@ -1010,13 +1010,472 @@
 };
 
 static struct msm_camera_i2c_reg_conf hi256_sleep_settings[] = {
+
 	{0x03, 0x00},
 	{0x01, 0xf1},
 	{0x03, 0x02},
 	{0x55, 0x10},
+
 	{0x01, 0xf1},
 	{0x01, 0xf3},
 	{0x01, 0xf1},
+
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_saturation[11][3] = {
+	{
+		{0x03, 0x10},
+		{0x61, 0x1c},
+		{0x62, 0x1c},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0x30},
+		{0x62, 0x30},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0x44},
+		{0x62, 0x44},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0x58},
+		{0x62, 0x58},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0x6c},
+		{0x62, 0x6c},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0x80},
+		{0x62, 0x80},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0x94},
+		{0x62, 0x94},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0xa8},
+		{0x62, 0xa8},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0xbc},
+		{0x62, 0xbc},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0xd0},
+		{0x62, 0xd0},
+	},
+	{
+		{0x03, 0x10},
+		{0x61, 0xe4},
+		{0x62, 0xe4},
+	},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_contrast[11][3] = {
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0x1c},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0x30},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0x44},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0x58},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0x6c},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0x80},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0x94},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0xa8},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0xbc},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0xd0},
+	},
+	{
+		{0x03, 0x10},
+		{0x13, 0x02},
+		{0x48, 0xe4},
+	},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_sharpness[7][9] = {
+	{
+		{0x03, 0x13},
+		{0x20, 0x00},
+		{0x21, 0x00},
+		{0x23, 0x04},
+		{0x24, 0x80},
+		{0x90, 0x00},
+		{0x91, 0x00},
+		{0x94, 0x24},
+		{0x95, 0x65},
+	}, /* SHARPNESS LEVEL 0*/
+	{
+		{0x03, 0x13},
+		{0x20, 0x04},
+		{0x21, 0x03},
+		{0x23, 0x04},
+		{0x24, 0x80},
+		{0x90, 0x08},
+		{0x91, 0x08},
+		{0x94, 0x24},
+		{0x95, 0x65},
+	}, /* SHARPNESS LEVEL 1*/
+	{
+		{0x03, 0x13},
+		{0x20, 0x08},
+		{0x21, 0x07},
+		{0x23, 0x04},
+		{0x24, 0x80},
+		{0x90, 0x32},
+		{0x91, 0x32},
+		{0x94, 0x04},
+		{0x95, 0x0a},
+	}, /* SHARPNESS LEVEL 2*/
+	{
+		{0x03, 0x13},
+		{0x20, 0x15},
+		{0x21, 0x15},
+		{0x23, 0x09},
+		{0x24, 0x11},
+		{0x90, 0x05},
+		{0x91, 0x05},
+		{0x94, 0x10},
+		{0x95, 0x5a},
+	}, /* SHARPNESS LEVEL 3*/
+	{
+		{0x03, 0x13},
+		{0x20, 0x15},
+		{0x21, 0x15},
+		{0x23, 0x04},
+		{0x24, 0x80},
+		{0x90, 0xaf},
+		{0x91, 0xaf},
+		{0x94, 0x24},
+		{0x95, 0x65},
+	}, /* SHARPNESS LEVEL 4*/
+	{
+		{0x03, 0x13},
+		{0x20, 0x20},
+		{0x21, 0x20},
+		{0x23, 0x04},
+		{0x24, 0x80},
+		{0x90, 0xdf},
+		{0x91, 0xdf},
+		{0x94, 0x24},
+		{0x95, 0x65},
+	}, /* SHARPNESS LEVEL 5*/
+	{
+		{0x03, 0x13},
+		{0x20, 0x25},
+		{0x21, 0x25},
+		{0x23, 0x04},
+		{0x24, 0x80},
+		{0x90, 0xff},
+		{0x91, 0xff},
+		{0x94, 0x24},
+		{0x95, 0x65},
+	}, /* SHARPNESS LEVEL 6*/
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_iso[7][3] = {
+	/* auto */
+	{
+		{0x03, 0x20},
+		{0x10, 0x9c},
+		{0xb0, 0x18},
+	},
+	/* auto hjt */
+	{
+		{0x03, 0x20},
+		{0x10, 0x9c},
+		{0xb0, 0x18},
+	},
+	/* iso 100 */
+	{
+		{0x03, 0x20},
+		{0x10, 0x0c},
+		{0xb0, 0x1B},
+	},
+	/* iso 200 */
+	{
+		{0x03, 0x20},
+		{0x10, 0x0c},
+		{0xb0, 0x35},
+	},
+	/* iso 400 */
+	{
+		{0x03, 0x20},
+		{0x10, 0x0c},
+		{0xb0, 0x65},
+	},
+	/* iso 800 */
+	{
+		{0x03, 0x20},
+		{0x10, 0x0c},
+		{0xb0, 0x95},
+	},
+	/* iso 1600 */
+	{
+		{0x03, 0x20},
+		{0x10, 0x0c},
+		{0xb0, 0xd0},
+	},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_exposure_compensation[5][2] = {
+	/* -2 */
+	{
+		{0x03, 0x10},
+		{0x40, 0xa4},
+	},
+	/* -1 */
+	{
+		{0x03, 0x10},
+		{0x40, 0x94},
+	},
+	/* 0 */
+	{
+		{0x03, 0x10},
+		{0x40, 0x80},
+	},
+	/* 1 */
+	{
+		{0x03, 0x10},
+		{0x40, 0x14},
+	},
+	/* 2 */
+	{
+		{0x03, 0x10},
+		{0x40, 0x24},
+	},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_antibanding[][2] = {
+	/* OFF */
+	{
+		{0x03, 0x20},
+		{0x10, 0xcc},
+	},
+	/* 50Hz */
+	{
+		{0x03, 0x20},
+		{0x10, 0x9c},
+	},
+	/* 60Hz */
+	{
+		{0x03, 0x20},
+		{0x10, 0x8c},
+	},
+	/* AUTO */
+	{
+		{0x03, 0x20},
+		{0x10, 0xcc},
+	},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_effect_normal[] = {
+	/* normal: */
+	{0x03, 0x20},
+	{0x28, 0xe7},
+	{0x03, 0x10},
+	{0x11, 0x03},
+	{0x12, 0X30},
+	{0x13, 0x0a},
+	{0x44, 0x80},
+	{0x45, 0x80},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_effect_black_white[] = {
+	/* B&W: */
+	{0x03, 0x20},
+	{0x28, 0xe7},
+	{0x03, 0x10},
+	{0x11, 0x03},
+	{0x12, 0x33},
+	{0x13, 0x02},
+	{0x44, 0x80},
+	{0x45, 0x80},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_effect_negative[] = {
+	/* Negative: */
+	{0x03, 0x20},
+	{0x28, 0xe7},
+	{0x03, 0x10},
+	{0x11, 0x03},
+	{0x12, 0x08},
+	{0x13, 0x0a},
+	{0x14, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_effect_old_movie[] = {
+	/* Sepia(antique): */
+	{0x03, 0x20},
+	{0x28, 0xe7},
+	{0x03, 0x10},
+	{0x11, 0x03},
+	{0x12, 0x33},
+	{0x13, 0x0a},
+	{0x44, 0x25},
+	{0x45, 0xa6},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_effect_solarize[] = {
+	{0x03, 0x20},
+	{0x28, 0xe7},
+	{0x03, 0x10},
+	{0x11, 0x0b},
+	{0x12, 0x00},
+	{0x13, 0x00},
+	{0x14, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_scene_auto[] = {
+	/* <SCENE_auto> */
+	{0x03, 0x20},
+	{0x10, 0x1c},
+	{0x18, 0x38},
+	{0x88, 0x05},
+	{0x89, 0x7e},
+	{0x8a, 0x40},
+	{0x10, 0x9c},
+	{0x18, 0x30},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_scene_portrait[] = {
+	/* <CAMTUNING_SCENE_PORTRAIT> */
+	{0x03, 0x20},
+	{0x10, 0x1c},
+	{0x18, 0x38},
+	{0x88, 0x05},
+	{0x89, 0x7e},
+	{0x8a, 0x40},
+	{0x10, 0x9c},
+	{0x18, 0x30},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_scene_landscape[] = {
+	/* <CAMTUNING_SCENE_LANDSCAPE> */
+	{0x03, 0x20},
+	{0x10, 0x1c},
+	{0x18, 0x38},
+	{0x88, 0x05},
+	{0x89, 0x7e},
+	{0x8a, 0x40},
+	{0x10, 0x9c},
+	{0x18, 0x30},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_scene_night[] = {
+	/* <SCENE_NIGHT> */
+	{0x03, 0x20},
+	{0x10, 0x1c},
+	{0x18, 0x38},
+	{0x88, 0x09},
+	{0x89, 0x27},
+	{0x8a, 0xc0},
+	{0x10, 0x9c},
+	{0x18, 0x30},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_wb_auto[] = {
+	/* Auto: */
+	{0x03, 0x22},
+	{0x11, 0x2e},
+	{0x83, 0x60},
+	{0x84, 0x0a},
+	{0x85, 0x60},
+	{0x86, 0x15},
+	{0x10, 0xfd},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_wb_sunny[] = {
+	/* Sunny: */
+	{0x03, 0x22},
+	{0x11, 0x28},
+	{0x80, 0x33},
+	{0x82, 0x3d},
+	{0x83, 0x2e},
+	{0x84, 0x24},
+	{0x85, 0x43},
+	{0x86, 0x3d},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_wb_cloudy[] = {
+	/* Cloudy: */
+	{0x03, 0x22},
+	{0x11, 0x28},
+	{0x80, 0x49},
+	{0x82, 0x24},
+	{0x83, 0x50},
+	{0x84, 0x45},
+	{0x85, 0x24},
+	{0x86, 0x1E},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_wb_office[] = {
+	/* Office: */
+	{0x03, 0x22},
+	{0x11, 0x28},
+	{0x80, 0x20},
+	{0x82, 0x58},
+	{0x83, 0x27},
+	{0x84, 0x22},
+	{0x85, 0x58},
+	{0x86, 0x52},
+};
+
+static struct msm_camera_i2c_reg_conf HI256_reg_wb_home[] = {
+	/* Home: */
+	{0x03, 0x22},
+	{0x11, 0x28},
+	{0x80, 0x29},
+	{0x82, 0x54},
+	{0x83, 0x2e},
+	{0x84, 0x23},
+	{0x85, 0x58},
+	{0x86, 0x4f},
 };
 
 
@@ -1080,7 +1539,6 @@
 		}
 		table++;
 	}
-
 }
 
 static int32_t hi256_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
@@ -1144,6 +1602,153 @@
 	return rc;
 }
 
+static void hi256_set_stauration(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+	pr_debug("%s %d", __func__, value);
+	hi256_i2c_write_table(s_ctrl, &HI256_reg_saturation[value][0],
+		ARRAY_SIZE(HI256_reg_saturation[value]));
+}
+
+static void hi256_set_contrast(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+	pr_debug("%s %d", __func__, value);
+	hi256_i2c_write_table(s_ctrl, &HI256_reg_contrast[value][0],
+		ARRAY_SIZE(HI256_reg_contrast[value]));
+}
+
+static void hi256_set_sharpness(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+	int val = value / 6;
+	pr_debug("%s %d", __func__, value);
+	hi256_i2c_write_table(s_ctrl, &HI256_reg_sharpness[val][0],
+		ARRAY_SIZE(HI256_reg_sharpness[val]));
+}
+
+
+static void hi256_set_iso(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+	pr_debug("%s %d", __func__, value);
+	hi256_i2c_write_table(s_ctrl, &HI256_reg_iso[value][0],
+		ARRAY_SIZE(HI256_reg_iso[value]));
+}
+
+static void hi256_set_exposure_compensation(struct msm_sensor_ctrl_t *s_ctrl,
+	int value)
+{
+	int val = (value + 12) / 6;
+	pr_debug("%s %d", __func__, val);
+	hi256_i2c_write_table(s_ctrl, &HI256_reg_exposure_compensation[val][0],
+		ARRAY_SIZE(HI256_reg_exposure_compensation[val]));
+}
+
+static void hi256_set_effect(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+	pr_debug("%s %d", __func__, value);
+	switch (value) {
+	case MSM_CAMERA_EFFECT_MODE_OFF: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_normal[0],
+			ARRAY_SIZE(HI256_reg_effect_normal));
+		break;
+	}
+	case MSM_CAMERA_EFFECT_MODE_MONO: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_black_white[0],
+			ARRAY_SIZE(HI256_reg_effect_black_white));
+		break;
+	}
+	case MSM_CAMERA_EFFECT_MODE_NEGATIVE: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_negative[0],
+			ARRAY_SIZE(HI256_reg_effect_negative));
+		break;
+	}
+	case MSM_CAMERA_EFFECT_MODE_SEPIA: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_old_movie[0],
+			ARRAY_SIZE(HI256_reg_effect_old_movie));
+		break;
+	}
+	case MSM_CAMERA_EFFECT_MODE_SOLARIZE: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_solarize[0],
+			ARRAY_SIZE(HI256_reg_effect_solarize));
+		break;
+	}
+	default:
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_effect_normal[0],
+			ARRAY_SIZE(HI256_reg_effect_normal));
+	}
+}
+
+static void hi256_set_antibanding(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+	pr_debug("%s %d", __func__, value);
+	hi256_i2c_write_table(s_ctrl, &HI256_reg_antibanding[value][0],
+		ARRAY_SIZE(HI256_reg_antibanding[value]));
+}
+
+static void hi256_set_scene_mode(struct msm_sensor_ctrl_t *s_ctrl, int value)
+{
+	pr_debug("%s %d", __func__, value);
+	switch (value) {
+	case MSM_CAMERA_SCENE_MODE_OFF: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_auto[0],
+			ARRAY_SIZE(HI256_reg_scene_auto));
+					break;
+	}
+	case MSM_CAMERA_SCENE_MODE_NIGHT: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_night[0],
+			ARRAY_SIZE(HI256_reg_scene_night));
+					break;
+	}
+	case MSM_CAMERA_SCENE_MODE_LANDSCAPE: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_landscape[0],
+			ARRAY_SIZE(HI256_reg_scene_landscape));
+					break;
+	}
+	case MSM_CAMERA_SCENE_MODE_PORTRAIT: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_portrait[0],
+			ARRAY_SIZE(HI256_reg_scene_portrait));
+					break;
+	}
+	default:
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_scene_auto[0],
+			ARRAY_SIZE(HI256_reg_scene_auto));
+	}
+}
+
+static void hi256_set_white_balance_mode(struct msm_sensor_ctrl_t *s_ctrl,
+	int value)
+{
+	pr_debug("%s %d", __func__, value);
+	switch (value) {
+	case MSM_CAMERA_WB_MODE_AUTO: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_auto[0],
+			ARRAY_SIZE(HI256_reg_wb_auto));
+		break;
+	}
+	case MSM_CAMERA_WB_MODE_INCANDESCENT: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_home[0],
+			ARRAY_SIZE(HI256_reg_wb_home));
+		break;
+	}
+	case MSM_CAMERA_WB_MODE_DAYLIGHT: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_sunny[0],
+			ARRAY_SIZE(HI256_reg_wb_sunny));
+					break;
+	}
+	case MSM_CAMERA_WB_MODE_FLUORESCENT: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_office[0],
+			ARRAY_SIZE(HI256_reg_wb_office));
+					break;
+	}
+	case MSM_CAMERA_WB_MODE_CLOUDY_DAYLIGHT: {
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_cloudy[0],
+			ARRAY_SIZE(HI256_reg_wb_cloudy));
+					break;
+	}
+	default:
+		hi256_i2c_write_table(s_ctrl, &HI256_reg_wb_auto[0],
+		ARRAY_SIZE(HI256_reg_wb_auto));
+	}
+}
+
 int32_t hi256_sensor_config(struct msm_sensor_ctrl_t *s_ctrl,
 	void __user *argp)
 {
@@ -1397,6 +2002,117 @@
 		}
 		break;
 	}
+	case CFG_SET_SATURATION: {
+		int32_t sat_lev;
+		if (copy_from_user(&sat_lev, (void *)cdata->cfg.setting,
+			sizeof(int32_t))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: Saturation Value is %d", __func__, sat_lev);
+		hi256_set_stauration(s_ctrl, sat_lev);
+		break;
+	}
+	case CFG_SET_CONTRAST: {
+		int32_t con_lev;
+		if (copy_from_user(&con_lev, (void *)cdata->cfg.setting,
+			sizeof(int32_t))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: Contrast Value is %d", __func__, con_lev);
+		hi256_set_contrast(s_ctrl, con_lev);
+		break;
+	}
+	case CFG_SET_SHARPNESS: {
+		int32_t shp_lev;
+		if (copy_from_user(&shp_lev, (void *)cdata->cfg.setting,
+			sizeof(int32_t))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: Sharpness Value is %d", __func__, shp_lev);
+		hi256_set_sharpness(s_ctrl, shp_lev);
+		break;
+	}
+	case CFG_SET_ISO: {
+		int32_t iso_lev;
+		if (copy_from_user(&iso_lev, (void *)cdata->cfg.setting,
+			sizeof(int32_t))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: ISO Value is %d", __func__, iso_lev);
+		hi256_set_iso(s_ctrl, iso_lev);
+		break;
+	}
+	case CFG_SET_EXPOSURE_COMPENSATION: {
+		int32_t ec_lev;
+		if (copy_from_user(&ec_lev, (void *)cdata->cfg.setting,
+			sizeof(int32_t))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: Exposure compensation Value is %d",
+			__func__, ec_lev);
+		hi256_set_exposure_compensation(s_ctrl, ec_lev);
+		break;
+	}
+	case CFG_SET_EFFECT: {
+		int32_t effect_mode;
+		if (copy_from_user(&effect_mode, (void *)cdata->cfg.setting,
+			sizeof(int32_t))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: Effect mode is %d", __func__, effect_mode);
+		hi256_set_effect(s_ctrl, effect_mode);
+		break;
+	}
+	case CFG_SET_ANTIBANDING: {
+		int32_t antibanding_mode;
+		if (copy_from_user(&antibanding_mode,
+			(void *)cdata->cfg.setting,
+			sizeof(int32_t))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: anti-banding mode is %d", __func__,
+			antibanding_mode);
+		hi256_set_antibanding(s_ctrl, antibanding_mode);
+		break;
+	}
+	case CFG_SET_BESTSHOT_MODE: {
+		int32_t bs_mode;
+		if (copy_from_user(&bs_mode, (void *)cdata->cfg.setting,
+			sizeof(int32_t))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: best shot mode is %d", __func__, bs_mode);
+		hi256_set_scene_mode(s_ctrl, bs_mode);
+		break;
+	}
+	case CFG_SET_WHITE_BALANCE: {
+		int32_t wb_mode;
+		if (copy_from_user(&wb_mode, (void *)cdata->cfg.setting,
+			sizeof(int32_t))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: white balance is %d", __func__, wb_mode);
+		hi256_set_white_balance_mode(s_ctrl, wb_mode);
+		break;
+	}
 	default:
 		rc = -EFAULT;
 		break;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
index 3898bd8..484dd69 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
@@ -111,6 +111,8 @@
 				ps[i].seq_val = SENSOR_GPIO_RESET;
 			else if (!strcmp(seq_name, "sensor_gpio_standby"))
 				ps[i].seq_val = SENSOR_GPIO_STANDBY;
+			else if (!strcmp(seq_name, "sensor_gpio_vdig"))
+				ps[i].seq_val = SENSOR_GPIO_VDIG;
 			else
 				rc = -EILSEQ;
 			break;
@@ -285,6 +287,23 @@
 		return rc;
 	}
 
+	if (of_property_read_bool(of_node, "qcom,gpio-vdig") == true) {
+		rc = of_property_read_u32(of_node, "qcom,gpio-vdig", &val);
+		if (rc < 0) {
+			pr_err("%s:%d read qcom,gpio-reset failed rc %d\n",
+				__func__, __LINE__, rc);
+			goto ERROR;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-reset invalid %d\n",
+				__func__, __LINE__, val);
+			goto ERROR;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG] =
+			gpio_array[val];
+		CDBG("%s qcom,gpio-reset %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG]);
+	}
+
 	if (of_property_read_bool(of_node, "qcom,gpio-reset") == true) {
 		rc = of_property_read_u32(of_node, "qcom,gpio-reset", &val);
 		if (rc < 0) {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
index 6bd7feb..46a0542 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
@@ -544,7 +544,7 @@
 int msm_camera_request_gpio_table(struct gpio *gpio_tbl, uint8_t size,
 	int gpio_en)
 {
-	int rc = 0, i = 0;
+	int rc = 0, i = 0, err = 0;
 
 	if (!gpio_tbl || !size) {
 		pr_err("%s:%d invalid gpio_tbl %p / size %d\n", __func__,
@@ -556,11 +556,19 @@
 			gpio_tbl[i].gpio, gpio_tbl[i].flags);
 	}
 	if (gpio_en) {
-		rc = gpio_request_array(gpio_tbl, size);
-		if (rc < 0) {
-			pr_err("%s:%d camera gpio request failed\n", __func__,
-				__LINE__);
-			return rc;
+		for (i = 0; i < size; i++) {
+			err = gpio_request_one(gpio_tbl[i].gpio,
+				gpio_tbl[i].flags, gpio_tbl[i].label);
+			if (err) {
+				/*
+				* After GPIO request fails, contine to
+				* apply new gpios, outout a error message
+				* for driver bringup debug
+				*/
+				pr_err("%s:%d gpio %d:%s request fails\n",
+					__func__, __LINE__,
+					gpio_tbl[i].gpio, gpio_tbl[i].label);
+			}
 		}
 	} else {
 		gpio_free_array(gpio_tbl, size);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
index adbfbe7..0447159 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -353,7 +353,7 @@
 	return rc;
 }
 
-static int32_t msm_sensor_get_dt_gpio_req_tbl(struct device_node *of_node,
+int32_t msm_sensor_get_dt_gpio_req_tbl(struct device_node *of_node,
 	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
 	uint16_t gpio_array_size)
 {
@@ -437,7 +437,7 @@
 	return rc;
 }
 
-static int32_t msm_sensor_get_dt_gpio_set_tbl(struct device_node *of_node,
+int32_t msm_sensor_get_dt_gpio_set_tbl(struct device_node *of_node,
 	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
 	uint16_t gpio_array_size)
 {
@@ -521,7 +521,7 @@
 	return rc;
 }
 
-static int32_t msm_sensor_init_gpio_pin_tbl(struct device_node *of_node,
+int32_t msm_sensor_init_gpio_pin_tbl(struct device_node *of_node,
 	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
 	uint16_t gpio_array_size)
 {
@@ -967,6 +967,7 @@
 	struct msm_sensor_power_setting_array *power_setting_array = NULL;
 	struct msm_sensor_power_setting *power_setting = NULL;
 	struct msm_camera_sensor_board_info *data = s_ctrl->sensordata;
+	s_ctrl->stop_setting_valid = 0;
 
 	CDBG("%s:%d\n", __func__, __LINE__);
 	power_setting_array = &s_ctrl->power_setting_array;
@@ -1271,9 +1272,8 @@
 	case VIDIOC_MSM_SENSOR_GET_AF_STATUS:
 		return msm_sensor_get_af_status(s_ctrl, argp);
 	case VIDIOC_MSM_SENSOR_RELEASE:
-		msm_sensor_stop_stream(s_ctrl);
-		return 0;
 	case MSM_SD_SHUTDOWN:
+		msm_sensor_stop_stream(s_ctrl);
 		return 0;
 	default:
 		return -ENOIOCTLCMD;
@@ -1342,6 +1342,13 @@
 		s_ctrl->power_setting_array =
 			sensor_slave_info.power_setting_array;
 		power_setting_array = &s_ctrl->power_setting_array;
+
+		if (!power_setting_array->size) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
 		power_setting_array->power_setting = kzalloc(
 			power_setting_array->size *
 			sizeof(struct msm_sensor_power_setting), GFP_KERNEL);
@@ -1403,6 +1410,12 @@
 			break;
 		}
 
+		if (!conf_array.size) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+
 		reg_setting = kzalloc(conf_array.size *
 			(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
 		if (!reg_setting) {
@@ -1492,6 +1505,12 @@
 		CDBG("%s:slave_addr=0x%x, array_size=%d\n", __func__,
 			write_config.slave_addr,
 			write_config.conf_array.size);
+
+		if (!write_config.conf_array.size) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
 		reg_setting = kzalloc(write_config.conf_array.size *
 			(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
 		if (!reg_setting) {
@@ -1565,6 +1584,11 @@
 			break;
 		}
 
+		if (!conf_array.size) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
 		reg_setting = kzalloc(conf_array.size *
 			(sizeof(struct msm_camera_i2c_seq_reg_array)),
 			GFP_KERNEL);
@@ -1655,8 +1679,13 @@
 			break;
 		}
 		s_ctrl->stop_setting_valid = 1;
-
 		reg_setting = stop_setting->reg_setting;
+
+		if (!stop_setting->size) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
 		stop_setting->reg_setting = kzalloc(stop_setting->size *
 			(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
 		if (!stop_setting->reg_setting) {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
index 80a2bd4..a53d448 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
@@ -92,4 +92,15 @@
 
 int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl);
 
+int32_t msm_sensor_get_dt_gpio_req_tbl(struct device_node *of_node,
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size);
+
+int32_t msm_sensor_get_dt_gpio_set_tbl(struct device_node *of_node,
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size);
+
+int32_t msm_sensor_init_gpio_pin_tbl(struct device_node *of_node,
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size);
 #endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov12830.c b/drivers/media/platform/msm/camera_v2/sensor/ov12830.c
index 593892e..fb6d548 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov12830.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov12830.c
@@ -21,73 +21,73 @@
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VIO,
 		.config_val = 0,
-		.delay = 5,
+		.delay = 1,
 	},
 	{
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VANA,
 		.config_val = 0,
-		.delay = 5,
+		.delay = 1,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_VDIG,
 		.config_val = GPIO_OUT_LOW,
-		.delay = 40,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_VDIG,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 40,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VAF,
 		.config_val = 0,
-		.delay = 15,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_STANDBY,
 		.config_val = GPIO_OUT_LOW,
-		.delay = 15,
+		.delay = 1,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_RESET,
 		.config_val = GPIO_OUT_LOW,
-		.delay = 40,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_AF_PWDM,
 		.config_val = GPIO_OUT_LOW,
-		.delay = 40,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_STANDBY,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 40,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_RESET,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 40,
+		.delay = 10,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_AF_PWDM,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 40,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_CLK,
 		.seq_val = SENSOR_CAM_MCLK,
 		.config_val = 24000000,
-		.delay = 5,
+		.delay = 10,
 	},
 	{
 		.seq_type = SENSOR_I2C_MUX,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov5648.c b/drivers/media/platform/msm/camera_v2/sensor/ov5648.c
index 7877fcb..417c7ab 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov5648.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov5648.c
@@ -22,37 +22,37 @@
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VIO,
 		.config_val = 0,
-		.delay = 5,
+		.delay = 0,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_VDIG,
 		.config_val = GPIO_OUT_LOW,
-		.delay = 10,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_VDIG,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 10,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VANA,
 		.config_val = 0,
-		.delay = 10,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_STANDBY,
 		.config_val = GPIO_OUT_LOW,
-		.delay = 30,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_STANDBY,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 30,
+		.delay = 10,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
@@ -64,13 +64,13 @@
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_RESET,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 30,
+		.delay = 10,
 	},
 	{
 		.seq_type = SENSOR_CLK,
 		.seq_val = SENSOR_CAM_MCLK,
 		.config_val = 24000000,
-		.delay = 5,
+		.delay = 10,
 	},
 	{
 		.seq_type = SENSOR_I2C_MUX,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov8825.c b/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
index 3256c5c..e17c94e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
@@ -21,55 +21,55 @@
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VIO,
 		.config_val = 0,
-		.delay = 5,
+		.delay = 1,
 	},
 	{
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VANA,
 		.config_val = 0,
-		.delay = 5,
+		.delay = 1,
 	},
 	{
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VDIG,
 		.config_val = 0,
-		.delay = 5,
+		.delay = 1,
 	},
 	{
 		.seq_type = SENSOR_VREG,
 		.seq_val = CAM_VAF,
 		.config_val = 0,
-		.delay = 15,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_STANDBY,
 		.config_val = GPIO_OUT_LOW,
-		.delay = 15,
+		.delay = 1,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_RESET,
 		.config_val = GPIO_OUT_LOW,
-		.delay = 40,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_STANDBY,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 40,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_RESET,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 40,
+		.delay = 10,
 	},
 	{
 		.seq_type = SENSOR_CLK,
 		.seq_val = SENSOR_CAM_MCLK,
 		.config_val = 24000000,
-		.delay = 5,
+		.delay = 10,
 	},
 	{
 		.seq_type = SENSOR_I2C_MUX,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov9724.c b/drivers/media/platform/msm/camera_v2/sensor/ov9724.c
index 56af02b..99bf03a 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov9724.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov9724.c
@@ -46,7 +46,7 @@
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_RESET,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 30,
+		.delay = 5,
 	},
 	{
 		.seq_type = SENSOR_GPIO,
@@ -58,13 +58,13 @@
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_STANDBY,
 		.config_val = GPIO_OUT_HIGH,
-		.delay = 30,
+		.delay = 10,
 	},
 	{
 		.seq_type = SENSOR_CLK,
 		.seq_val = SENSOR_CAM_MCLK,
 		.config_val = 24000000,
-		.delay = 5,
+		.delay = 10,
 	},
 	{
 		.seq_type = SENSOR_I2C_MUX,
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 02b36f8..1dba2b6 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -32,6 +32,7 @@
 		HFI_H264_PROFILE_CONSTRAINED_BASE,
 	[ilog2(HAL_H264_PROFILE_CONSTRAINED_HIGH)] =
 		HFI_H264_PROFILE_CONSTRAINED_HIGH,
+	[ilog2(HAL_VPX_PROFILE_VERSION_1)] = HFI_VPX_PROFILE_VERSION_1,
 };
 
 static int entropy_mode[] = {
@@ -1160,6 +1161,19 @@
 		pkt->size += sizeof(u32) * 2;
 		break;
 	}
+	case HAL_PARAM_VDEC_CONCEAL_COLOR:
+	{
+		struct hfi_conceal_color *hfi;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR;
+		hfi = (struct hfi_conceal_color *) &pkt->rg_property_data[1];
+		if (hfi)
+			hfi->conceal_color =
+				((struct hfi_conceal_color *) pdata)->
+				conceal_color;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
 	case HAL_CONFIG_VPE_OPERATIONS:
 		break;
 	case HAL_PARAM_VENC_INTRA_REFRESH:
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 653ba46..8350dde 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -78,6 +78,26 @@
 	return vidc_err;
 }
 
+static int sanitize_session_pkt(struct list_head *sessions,
+		struct hal_session *sess, struct mutex *session_lock)
+{
+	struct hal_session *session;
+	int invalid = 1;
+	if (session_lock) {
+		mutex_lock(session_lock);
+		list_for_each_entry(session, sessions, list) {
+			if (session == sess) {
+				invalid = 0;
+				break;
+			}
+		}
+		mutex_unlock(session_lock);
+	}
+	if (invalid)
+		dprintk(VIDC_WARN, "Invalid session from FW: %p\n", sess);
+	return invalid;
+}
+
 static void hfi_process_sess_evt_seq_changed(
 		msm_vidc_callback callback, u32 device_id,
 		struct hfi_msg_event_notify_packet *pkt)
@@ -1115,9 +1135,11 @@
 
 u32 hfi_process_msg_packet(
 		msm_vidc_callback callback, u32 device_id,
-		struct vidc_hal_msg_pkt_hdr *msg_hdr)
+		struct vidc_hal_msg_pkt_hdr *msg_hdr,
+		struct list_head *sessions, struct mutex *session_lock)
 {
 	u32 rc = 0;
+	struct hal_session *sess;
 	if (!callback || !msg_hdr || msg_hdr->size <
 		VIDC_IFACEQ_MIN_PKT_SIZE) {
 		dprintk(VIDC_ERR, "hal_process_msg_packet:bad"
@@ -1126,10 +1148,19 @@
 		return rc;
 	}
 
+#define SANITIZE_SESSION_PKT(msg_pkt) ({ \
+		sess = (struct hal_session *) \
+				(((struct vidc_hal_session_cmd_pkt *) \
+				msg_pkt)->session_id); \
+		if (sanitize_session_pkt(sessions, sess, session_lock)) \
+			break; \
+	})
+
 	dprintk(VIDC_INFO, "Received: 0x%x in ", msg_hdr->packet);
 	rc = (u32) msg_hdr->packet;
 	switch (msg_hdr->packet) {
 	case HFI_MSG_EVENT_NOTIFY:
+		SANITIZE_SESSION_PKT(msg_hdr);
 		hfi_process_event_notify(callback, device_id,
 			(struct hfi_msg_event_notify_packet *) msg_hdr);
 		break;
@@ -1141,6 +1172,7 @@
 	case HFI_MSG_SYS_IDLE:
 		break;
 	case HFI_MSG_SYS_SESSION_INIT_DONE:
+		SANITIZE_SESSION_PKT(msg_hdr);
 		hfi_process_session_init_done(callback, device_id,
 			(struct hfi_msg_sys_session_init_done_packet *)
 					msg_hdr);
@@ -1151,44 +1183,53 @@
 			msg_hdr);
 		break;
 	case HFI_MSG_SYS_SESSION_END_DONE:
+		SANITIZE_SESSION_PKT(msg_hdr);
 		hfi_process_session_end_done(callback, device_id,
 			(struct hfi_msg_sys_session_end_done_packet *)
 					msg_hdr);
 		break;
 	case HFI_MSG_SESSION_LOAD_RESOURCES_DONE:
+		SANITIZE_SESSION_PKT(msg_hdr);
 		hfi_process_session_load_res_done(callback, device_id,
 			(struct hfi_msg_session_load_resources_done_packet *)
 					msg_hdr);
 		break;
 	case HFI_MSG_SESSION_START_DONE:
+		SANITIZE_SESSION_PKT(msg_hdr);
 		hfi_process_session_start_done(callback, device_id,
 			(struct hfi_msg_session_start_done_packet *)
 					msg_hdr);
 		break;
 	case HFI_MSG_SESSION_STOP_DONE:
+		SANITIZE_SESSION_PKT(msg_hdr);
 		hfi_process_session_stop_done(callback, device_id,
 			(struct hfi_msg_session_stop_done_packet *)
 					msg_hdr);
 		break;
 	case HFI_MSG_SESSION_EMPTY_BUFFER_DONE:
+		SANITIZE_SESSION_PKT(msg_hdr);
 		hfi_process_session_etb_done(callback, device_id,
 			(struct hfi_msg_session_empty_buffer_done_packet *)
 					msg_hdr);
 		break;
 	case HFI_MSG_SESSION_FILL_BUFFER_DONE:
+		SANITIZE_SESSION_PKT(msg_hdr);
 		hfi_process_session_ftb_done(callback, device_id, msg_hdr);
 		break;
 	case HFI_MSG_SESSION_FLUSH_DONE:
+		SANITIZE_SESSION_PKT(msg_hdr);
 		hfi_process_session_flush_done(callback, device_id,
 			(struct hfi_msg_session_flush_done_packet *)
 					msg_hdr);
 		break;
 	case HFI_MSG_SESSION_PROPERTY_INFO:
+		SANITIZE_SESSION_PKT(msg_hdr);
 		hfi_process_session_prop_info(callback, device_id,
 			(struct hfi_msg_session_property_info_packet *)
 					msg_hdr);
 		break;
 	case HFI_MSG_SESSION_RELEASE_RESOURCES_DONE:
+		SANITIZE_SESSION_PKT(msg_hdr);
 		hfi_process_session_rel_res_done(callback, device_id,
 			(struct hfi_msg_session_release_resources_done_packet *)
 					msg_hdr);
@@ -1199,18 +1240,21 @@
 			msg_hdr);
 		break;
 	case HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE:
+		SANITIZE_SESSION_PKT(msg_hdr);
 		hfi_process_session_get_seq_hdr_done(
 			callback, device_id, (struct
 			hfi_msg_session_get_sequence_header_done_packet*)
 			msg_hdr);
 		break;
 	case HFI_MSG_SESSION_RELEASE_BUFFERS_DONE:
+		SANITIZE_SESSION_PKT(msg_hdr);
 		hfi_process_session_rel_buf_done(
 			callback, device_id, (struct
 			hfi_msg_session_release_buffers_done_packet*)
 			msg_hdr);
 		break;
 	case HFI_MSG_SYS_SESSION_ABORT_DONE:
+		SANITIZE_SESSION_PKT(msg_hdr);
 		hfi_process_session_abort_done(callback, device_id, (struct
 			hfi_msg_sys_session_abort_done_packet*) msg_hdr);
 		break;
@@ -1218,5 +1262,6 @@
 		dprintk(VIDC_DBG, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
 		break;
 	}
+#undef SANITIZE_SESSION_PKT
 	return rc;
 }
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index cf96ca2..50149dc 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -210,7 +210,8 @@
 fail_nomem:
 	return rc;
 }
-static int msm_v4l2_release_output_buffers(struct msm_v4l2_vid_inst *v4l2_inst)
+static int msm_v4l2_release_buffers(struct msm_v4l2_vid_inst *v4l2_inst,
+				int buffer_type)
 {
 	struct list_head *ptr, *next;
 	struct buffer_info *bi;
@@ -220,7 +221,7 @@
 	int i;
 	list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
 		bi = list_entry(ptr, struct buffer_info, list);
-		if (bi->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		if (bi->type == buffer_type) {
 			buffer_info.type = bi->type;
 			for (i = 0; (i < bi->num_planes)
 				&& (i < VIDEO_MAX_PLANES); i++) {
@@ -266,7 +267,8 @@
 	int i;
 	vidc_inst = get_vidc_inst(filp, NULL);
 	v4l2_inst = get_v4l2_inst(filp, NULL);
-	rc = msm_v4l2_release_output_buffers(v4l2_inst);
+	rc = msm_v4l2_release_buffers(v4l2_inst,
+			V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 	if (rc)
 		dprintk(VIDC_WARN,
 			"Failed in %s for release output buffers\n", __func__);
@@ -339,7 +341,7 @@
 	int rc = 0;
 	v4l2_inst = get_v4l2_inst(file, NULL);
 	if (b->count == 0)
-		rc = msm_v4l2_release_output_buffers(v4l2_inst);
+		rc = msm_v4l2_release_buffers(v4l2_inst, b->type);
 	if (rc)
 		dprintk(VIDC_WARN,
 			"Failed in %s for release output buffers\n", __func__);
@@ -617,7 +619,8 @@
 	int rc = 0;
 	v4l2_inst = get_v4l2_inst(file, NULL);
 	if (dec->cmd == V4L2_DEC_CMD_STOP)
-		rc = msm_v4l2_release_output_buffers(v4l2_inst);
+		rc = msm_v4l2_release_buffers(v4l2_inst,
+				V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 	if (rc)
 		dprintk(VIDC_WARN,
 			"Failed to release dec output buffers: %d\n", rc);
@@ -632,7 +635,8 @@
 	int rc = 0;
 	v4l2_inst = get_v4l2_inst(file, NULL);
 	if (enc->cmd == V4L2_ENC_CMD_STOP)
-		rc = msm_v4l2_release_output_buffers(v4l2_inst);
+		rc = msm_v4l2_release_buffers(v4l2_inst,
+				V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 	if (rc)
 		dprintk(VIDC_WARN,
 			"Failed to release enc output buffers: %d\n", rc);
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 86928f2..73ff9fa 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -22,6 +22,7 @@
 #define MSM_VDEC_DVC_NAME "msm_vdec_8974"
 #define MIN_NUM_OUTPUT_BUFFERS 4
 #define MAX_NUM_OUTPUT_BUFFERS 6
+#define DEFAULT_CONCEAL_COLOR 0x0
 
 enum msm_vdec_ctrl_cluster {
 	MSM_VDEC_CTRL_CLUSTER_MAX = 1 << 0,
@@ -1028,18 +1029,16 @@
 			mutex_unlock(&inst->lock);
 			break;
 		}
-		if (*num_buffers && *num_buffers >
+		if (*num_buffers && *num_buffers >=
 			bufreq->buffer_count_actual) {
 			property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
 			new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
 			new_buf_count.buffer_count_actual = *num_buffers;
 			rc = call_hfi_op(hdev, session_set_property,
 				inst->session, property_id, &new_buf_count);
+		} else {
+			*num_buffers = bufreq->buffer_count_min;
 		}
-		if (bufreq->buffer_count_actual > *num_buffers)
-			*num_buffers =  bufreq->buffer_count_actual;
-		else
-			bufreq->buffer_count_actual = *num_buffers;
 		mutex_unlock(&inst->lock);
 		dprintk(VIDC_DBG, "count =  %d, size = %d, alignment = %d\n",
 				inst->buff_req.buffer[1].buffer_count_actual,
@@ -1129,17 +1128,28 @@
 {
 	struct msm_vidc_inst *inst;
 	int rc = 0;
+	int pdata = DEFAULT_CONCEAL_COLOR;
+	struct hfi_device *hdev;
 	if (!q || !q->drv_priv) {
 		dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
 		return -EINVAL;
 	}
 	inst = q->drv_priv;
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
 	dprintk(VIDC_DBG,
 		"Streamon called on: %d capability\n", q->type);
 	switch (q->type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		if (inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
 			rc = start_streaming(inst);
+		rc = call_hfi_op(hdev, session_set_property,
+			(void *) inst->session,
+			HAL_PARAM_VDEC_CONCEAL_COLOR,
+			(void *) &pdata);
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index cddca74..c1a9ad0 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -87,6 +87,14 @@
 	"High Latency",
 };
 
+static const char *const vp8_profile_level[] = {
+	"Unused",
+	"0.0",
+	"1.0",
+	"2.0",
+	"3.0",
+};
+
 static const char *const mpeg_video_vidc_extradata[] = {
 	"Extradata none",
 	"Extradata MB Quantization",
@@ -125,7 +133,8 @@
 	MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH = 1 << 7,
 	MSM_VENC_CTRL_CLUSTER_BITRATE = 1 << 8,
 	MSM_VENC_CTRL_CLUSTER_TIMING = 1 << 9,
-	MSM_VENC_CTRL_CLUSTER_MAX = 1 << 10,
+	MSM_VENC_CTRL_CLUSTER_VP8_PROFILE_LEVEL = 1 << 10,
+	MSM_VENC_CTRL_CLUSTER_MAX = 1 << 11,
 };
 
 static struct msm_vidc_ctrl msm_venc_ctrls[] = {
@@ -315,7 +324,7 @@
 		.name = "H264 Level",
 		.type = V4L2_CTRL_TYPE_MENU,
 		.minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
-		.maximum = V4L2_MPEG_VIDEO_H264_LEVEL_5_1,
+		.maximum = V4L2_MPEG_VIDEO_H264_LEVEL_5_2,
 		.default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
 		.step = 0,
 		.menu_skip_mask = 0,
@@ -362,6 +371,21 @@
 		.cluster = MSM_VENC_CTRL_CLUSTER_H263_PROFILE_LEVEL,
 	},
 	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+		.name = "VP8 Profile Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1)
+		),
+		.qmenu = vp8_profile_level,
+		.cluster = MSM_VENC_CTRL_CLUSTER_VP8_PROFILE_LEVEL,
+	},
+	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
 		.name = "Rotation",
 		.type = V4L2_CTRL_TYPE_MENU,
@@ -1103,6 +1127,8 @@
 			return HAL_H264_LEVEL_5;
 		case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
 			return HAL_H264_LEVEL_51;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_5_2:
+			return HAL_H264_LEVEL_52;
 		default:
 			goto unknown_value;
 		}
@@ -1171,6 +1197,21 @@
 		default:
 			goto unknown_value;
 		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+		switch (value) {
+		case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0:
+			return HAL_VPX_PROFILE_VERSION_0;
+		case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1:
+			return HAL_VPX_PROFILE_VERSION_1;
+		case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2:
+			return HAL_VPX_PROFILE_VERSION_2;
+		case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3:
+			return HAL_VPX_PROFILE_VERSION_3;
+		case V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED:
+			return HAL_VPX_PROFILE_UNUSED;
+		default:
+			goto unknown_value;
+		}
 	}
 
 unknown_value:
@@ -1477,6 +1518,15 @@
 				ctrl->val);
 		pdata = &profile_level;
 		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+		property_id =
+			HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.profile = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+				ctrl->val);
+		profile_level.level = HAL_VPX_PROFILE_UNUSED;
+		pdata = &profile_level;
+		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
 		property_id =
 			HAL_CONFIG_VPE_OPERATIONS;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index f94b6f1..09f67a2 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -526,8 +526,15 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
-	if (response)
+	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
+		if (response->status) {
+			dprintk(VIDC_ERR,
+				"Load resource response from FW : 0x%x",
+				response->status);
+			msm_comm_generate_session_error(inst);
+		}
+	}
 	else
 		dprintk(VIDC_ERR,
 			"Failed to get valid response for load resource\n");
@@ -817,10 +824,21 @@
 		(u32)fill_buf_done->packet_buffer1);
 	if (vb) {
 		vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
+		vb->v4l2_planes[0].data_offset = fill_buf_done->offset1;
 		vb->v4l2_planes[0].reserved[2] = fill_buf_done->start_x_coord;
 		vb->v4l2_planes[0].reserved[3] = fill_buf_done->start_y_coord;
 		vb->v4l2_planes[0].reserved[4] = fill_buf_done->frame_width;
 		vb->v4l2_planes[0].reserved[5] = fill_buf_done->frame_height;
+		if (vb->v4l2_planes[0].data_offset > vb->v4l2_planes[0].length)
+			dprintk(VIDC_INFO,
+				"fbd:Overflow data_offset = %d; length = %d\n",
+				vb->v4l2_planes[0].data_offset,
+				vb->v4l2_planes[0].length);
+		if (vb->v4l2_planes[0].bytesused > vb->v4l2_planes[0].length)
+			dprintk(VIDC_INFO,
+				"fbd:Overflow bytesused = %d; length = %d\n",
+				vb->v4l2_planes[0].bytesused,
+				vb->v4l2_planes[0].length);
 		if (!(fill_buf_done->flags1 &
 			HAL_BUFFERFLAG_TIMESTAMPINVALID) &&
 			fill_buf_done->filled_len1) {
@@ -873,8 +891,9 @@
 			msm_vidc_debugfs_update(inst,
 				MSM_VIDC_DEBUGFS_EVENT_FBD);
 
-		dprintk(VIDC_DBG, "Filled length = %d; flags %x\n",
+		dprintk(VIDC_DBG, "Filled length = %d; offset = %d; flags %x\n",
 				vb->v4l2_planes[0].bytesused,
+				vb->v4l2_planes[0].data_offset,
 				vb->v4l2_buf.flags);
 		mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
 		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
@@ -901,6 +920,7 @@
 				vb = list_first_entry(&q->vb2_bufq.queued_list,
 					struct vb2_buffer, queued_entry);
 				vb->v4l2_planes[0].bytesused = 0;
+				vb->v4l2_planes[0].data_offset = 0;
 				vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
 				mutex_lock(&q->lock);
 				vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
@@ -932,12 +952,14 @@
 	}
 
 	vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
+	vb->v4l2_planes[0].data_offset = fill_buf_done->offset1;
 
 	vb->v4l2_buf.flags = V4L2_QCOM_BUF_FLAG_CODECCONFIG;
 	vb->v4l2_buf.timestamp = ns_to_timeval(0);
 
-	dprintk(VIDC_DBG, "Filled length = %d; flags %x\n",
+	dprintk(VIDC_DBG, "Filled length = %d; offset = %d; flags %x\n",
 				vb->v4l2_planes[0].bytesused,
+				vb->v4l2_planes[0].data_offset,
 				vb->v4l2_buf.flags);
 	mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
 	vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
@@ -2341,6 +2363,7 @@
 					queued_entry);
 			if (vb) {
 				vb->v4l2_planes[0].bytesused = 0;
+				vb->v4l2_planes[0].data_offset = 0;
 				mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
 				vb2_buffer_done(vb,
 						VB2_BUF_STATE_DONE);
@@ -2358,6 +2381,7 @@
 					queued_entry);
 			if (vb) {
 				vb->v4l2_planes[0].bytesused = 0;
+				vb->v4l2_planes[0].data_offset = 0;
 				mutex_lock(&inst->bufq[OUTPUT_PORT].lock);
 				vb2_buffer_done(vb,
 						VB2_BUF_STATE_DONE);
@@ -2436,6 +2460,7 @@
 					lock = &inst->bufq[CAPTURE_PORT].lock;
 				else
 					lock = &inst->bufq[OUTPUT_PORT].lock;
+				temp->vb->v4l2_planes[0].bytesused = 0;
 				mutex_lock(lock);
 				vb2_buffer_done(temp->vb, VB2_BUF_STATE_DONE);
 				mutex_unlock(lock);
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index bc3b93d..7c99ec3 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -184,7 +184,8 @@
 		if (!rc)
 			hfi_process_msg_packet(device->callback,
 				device->device_id,
-				(struct vidc_hal_msg_pkt_hdr *) packet);
+				(struct vidc_hal_msg_pkt_hdr *) packet,
+				&device->sess_head, &device->session_lock);
 	} while (!rc);
 
 	if (rc != -ENODATA)
@@ -381,7 +382,7 @@
 }
 
 static inline void q6_hfi_add_apr_hdr(struct q6_hfi_device *dev,
-			struct apr_hdr *hdr, u32 pkt_size, u32 opcode)
+			struct apr_hdr *hdr, u32 pkt_size)
 {
 	hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 				APR_HDR_LEN(sizeof(struct apr_hdr)),
@@ -394,7 +395,7 @@
 	hdr->dest_port = 0;
 	hdr->pkt_size  = pkt_size;
 	hdr->token = 0;
-	hdr->opcode = opcode;
+	hdr->opcode = VIDEO_HFI_CMD_ID;
 }
 
 static int q6_hfi_apr_callback(struct apr_client_data *data, void *priv)
@@ -483,6 +484,7 @@
 	}
 
 	INIT_LIST_HEAD(&dev->sess_head);
+	mutex_init(&dev->session_lock);
 
 	if (!dev->event_queue.buffer) {
 		rc = q6_init_event_queue(dev);
@@ -496,7 +498,7 @@
 		goto err_core_init;
 	}
 
-	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr), HFI_CMD_SYS_INIT);
+	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
 
 	rc = create_pkt_cmd_sys_init(&apr.pkt, HFI_VIDEO_ARCH_OX);
 	if (rc) {
@@ -529,22 +531,6 @@
 	return 0;
 }
 
-static int q6_hfi_core_pc_prep(void *device)
-{
-	(void) device;
-
-	/* Q6 does not support core_pc_prep*/
-	return 0;
-}
-
-static int q6_hfi_core_ping(void *device)
-{
-	(void) device;
-
-	/* Q6 does not support cmd_sys_ping */
-	return 0;
-}
-
 static void *q6_hfi_session_init(void *device, u32 session_id,
 	enum hal_domain session_type, enum hal_video_codec codec_type)
 {
@@ -567,8 +553,7 @@
 		new_session->is_decoder = 1;
 	new_session->device = dev;
 
-	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
-				   HFI_CMD_SYS_SESSION_INIT);
+	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
 
 	if (create_pkt_cmd_sys_session_init(&apr.pkt, (u32)new_session,
 					session_type, codec_type)) {
@@ -583,7 +568,9 @@
 		rc = -EBADE;
 		goto err_session_init;
 	}
+	mutex_lock(&dev->session_lock);
 	list_add_tail(&new_session->list, &dev->sess_head);
+	mutex_unlock(&dev->session_lock);
 	return new_session;
 
 err_session_init:
@@ -605,7 +592,7 @@
 	}
 	dev = session->device;
 
-	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr), pkt_type);
+	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
 
 	rc = create_pkt_cmd_session_cmd(&apr.pkt, pkt_type, (u32)session);
 	if (rc) {
@@ -646,7 +633,11 @@
 	sess_close = session;
 	dprintk(VIDC_DBG, "deleted the session: 0x%x",
 			sess_close->session_id);
+	mutex_lock(&((struct q6_hfi_device *)
+			sess_close->device)->session_lock);
 	list_del(&sess_close->list);
+	mutex_unlock(&((struct q6_hfi_device *)
+			sess_close->device)->session_lock);
 	kfree(sess_close);
 	return 0;
 }
@@ -670,8 +661,7 @@
 		return 0;
 	apr = (struct q6_apr_cmd_session_set_buffers_packet *)packet;
 
-	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE,
-			HFI_CMD_SESSION_SET_BUFFERS);
+	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE);
 
 	rc = create_pkt_cmd_session_set_buffers(&apr->pkt,
 			(u32)session, buffer_info);
@@ -713,8 +703,7 @@
 
 	apr = (struct q6_apr_cmd_session_release_buffer_packet *) packet;
 
-	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE,
-					   HFI_CMD_SESSION_RELEASE_BUFFERS);
+	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE);
 
 	rc = create_pkt_cmd_session_release_buffers(&apr->pkt,
 					(u32)session, buffer_info);
@@ -788,8 +777,7 @@
 
 	if (session->is_decoder) {
 		struct q6_apr_cmd_session_empty_buffer_compressed_packet apr;
-		q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
-					   HFI_CMD_SESSION_EMPTY_BUFFER);
+		q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
 
 		rc = create_pkt_cmd_session_etb_decoder(&apr.pkt,
 					(u32)session, input_frame);
@@ -811,8 +799,7 @@
 	} else {
 		struct
 		q6_apr_cmd_session_empty_buffer_uncompressed_plane0_packet apr;
-		q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
-				   HFI_CMD_SESSION_EMPTY_BUFFER);
+		q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
 
 		rc =  create_pkt_cmd_session_etb_encoder(&apr.pkt,
 					(u32)session, input_frame);
@@ -848,8 +835,7 @@
 	}
 	dev = session->device;
 
-	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
-				   HFI_CMD_SESSION_FILL_BUFFER);
+	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
 
 	rc = create_pkt_cmd_session_ftb(&apr.pkt, (u32)session, output_frame);
 	if (rc) {
@@ -886,8 +872,7 @@
 
 	apr = (struct q6_apr_cmd_session_parse_sequence_header_packet *) packet;
 
-	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_SMALL_PKT_SIZE,
-			   HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER);
+	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_SMALL_PKT_SIZE);
 
 	rc = create_pkt_cmd_session_parse_seq_header(&apr->pkt,
 					(u32)session, seq_hdr);
@@ -925,8 +910,7 @@
 
 	apr = (struct q6_apr_cmd_session_get_sequence_header_packet *) packet;
 
-	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_SMALL_PKT_SIZE,
-				   HFI_CMD_SESSION_GET_SEQUENCE_HEADER);
+	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_SMALL_PKT_SIZE);
 
 	rc = create_pkt_cmd_session_get_seq_hdr(&apr->pkt, (u32)session,
 						seq_hdr);
@@ -960,8 +944,7 @@
 	}
 	dev = session->device;
 
-	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
-				   HFI_CMD_SESSION_GET_PROPERTY);
+	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
 
 	rc = create_pkt_cmd_session_get_buf_req(&apr.pkt, (u32)session);
 	if (rc) {
@@ -993,8 +976,7 @@
 	}
 	dev = session->device;
 
-	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
-				   HFI_CMD_SESSION_FLUSH);
+	q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
 
 	rc = create_pkt_cmd_session_flush(&apr.pkt, (u32)session, flush_mode);
 	if (rc) {
@@ -1031,8 +1013,7 @@
 	dev = session->device;
 	dprintk(VIDC_DBG, "in set_prop,with prop id: 0x%x", ptype);
 
-	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE,
-				 HFI_CMD_SESSION_SET_PROPERTY);
+	q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE);
 
 	rc = create_pkt_cmd_session_set_property(&apr->pkt,
 				(u32)session, ptype, pdata);
@@ -1177,28 +1158,6 @@
 	return 0;
 }
 
-static int q6_hfi_scale_clocks(void *dev, int load)
-{
-	(void)dev;
-	(void)load;
-
-	/* Q6 does not support clocks scaling */
-	return 0;
-}
-
-static int q6_hfi_scale_bus(void *dev, int load,
-			enum session_type type, enum mem_type mtype)
-{
-	(void)dev;
-	(void)load;
-	(void)type;
-	(void)mtype;
-
-	/* Q6 does not support bus scaling */
-	return 0;
-
-}
-
 static int q6_hfi_unset_ocmem(void *dev)
 {
 	(void)dev;
@@ -1207,23 +1166,6 @@
 	return -EINVAL;
 }
 
-static int q6_hfi_alloc_ocmem(void *dev, unsigned long size)
-{
-	(void)dev;
-	(void)size;
-
-	/* Q6 does not support ocmem */
-	return 0;
-}
-
-static int q6_hfi_free_ocmem(void *dev)
-{
-	(void)dev;
-
-	/* Q6 does not support ocmem */
-	return 0;
-}
-
 static int q6_hfi_iommu_get_domain_partition(void *dev, u32 flags,
 	u32 buffer_type, int *domain, int *partition)
 {
@@ -1373,14 +1315,6 @@
 	}
 }
 
-static int q6_hfi_get_fw_info(void *dev, enum fw_info info)
-{
-	(void)dev;
-	(void)info;
-
-	return 0;
-}
-
 static int q6_hfi_get_stride_scanline(int color_fmt,
 	int width, int height, int *stride, int *scanlines) {
 	*stride = VENUS_Y_STRIDE(color_fmt, width);
@@ -1392,8 +1326,6 @@
 {
 	hdev->core_init = q6_hfi_core_init;
 	hdev->core_release = q6_hfi_core_release;
-	hdev->core_pc_prep = q6_hfi_core_pc_prep;
-	hdev->core_ping = q6_hfi_core_ping;
 	hdev->session_init = q6_hfi_session_init;
 	hdev->session_end = q6_hfi_session_end;
 	hdev->session_abort = q6_hfi_session_abort;
@@ -1414,15 +1346,10 @@
 	hdev->session_flush = q6_hfi_session_flush;
 	hdev->session_set_property = q6_hfi_session_set_property;
 	hdev->session_get_property = q6_hfi_session_get_property;
-	hdev->scale_clocks = q6_hfi_scale_clocks;
-	hdev->scale_bus = q6_hfi_scale_bus;
 	hdev->unset_ocmem = q6_hfi_unset_ocmem;
-	hdev->alloc_ocmem = q6_hfi_alloc_ocmem;
-	hdev->free_ocmem = q6_hfi_free_ocmem;
 	hdev->iommu_get_domain_partition = q6_hfi_iommu_get_domain_partition;
 	hdev->load_fw = q6_hfi_load_fw;
 	hdev->unload_fw = q6_hfi_unload_fw;
-	hdev->get_fw_info = q6_hfi_get_fw_info;
 	hdev->get_stride_scanline = q6_hfi_get_stride_scanline;
 }
 
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.h b/drivers/media/platform/msm/vidc/q6_hfi.h
index 3dc4607..5f48a51 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.h
+++ b/drivers/media/platform/msm/vidc/q6_hfi.h
@@ -20,6 +20,15 @@
 
 #define Q6_IFACEQ_QUEUE_SIZE (8 * 1024)
 
+/* client to Q6 communication path : forward path */
+#define VIDEO_HFI_CMD_ID  0x00012ECC
+
+/* Q6 to client ACK msg: reverse path*/
+#define VIDEO_HFI_MSG_ID  0x00012ECD
+
+/* Q6 to client event notifications */
+#define VIDEO_HFI_EVT_ID  0x00012ECE
+
 struct q6_resources {
 	struct msm_vidc_fw fw;
 };
@@ -43,6 +52,7 @@
 	struct q6_resources resources;
 	struct msm_vidc_platform_resources *res;
 	void *apr;
+	struct mutex session_lock;
 };
 
 struct q6_apr_cmd_sys_init_packet {
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 5416210..99c51bf 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1045,6 +1045,7 @@
 	INIT_LIST_HEAD(&dev->sess_head);
 	mutex_init(&dev->read_lock);
 	mutex_init(&dev->write_lock);
+	mutex_init(&dev->session_lock);
 	venus_hfi_set_registers(dev);
 
 	if (!dev->hal_client) {
@@ -1484,7 +1485,10 @@
 	else if (session_type == 2)
 		new_session->is_decoder = 1;
 	new_session->device = dev;
+
+	mutex_lock(&dev->session_lock);
 	list_add_tail(&new_session->list, &dev->sess_head);
+	mutex_unlock(&dev->session_lock);
 
 	if (create_pkt_cmd_sys_session_init(&pkt, (u32)new_session,
 			session_type, codec_type)) {
@@ -1554,7 +1558,11 @@
 	sess_close = session;
 	dprintk(VIDC_DBG, "deleted the session: 0x%p",
 			sess_close);
+	mutex_lock(&((struct venus_hfi_device *)
+			sess_close->device)->session_lock);
 	list_del(&sess_close->list);
+	mutex_unlock(&((struct venus_hfi_device *)
+			sess_close->device)->session_lock);
 	kfree(sess_close);
 	return 0;
 }
@@ -1985,7 +1993,8 @@
 		while (!venus_hfi_iface_msgq_read(device, packet)) {
 			rc = hfi_process_msg_packet(device->callback,
 				device->device_id,
-				(struct vidc_hal_msg_pkt_hdr *) packet);
+				(struct vidc_hal_msg_pkt_hdr *) packet,
+				&device->sess_head, &device->session_lock);
 			if (rc == HFI_MSG_EVENT_NOTIFY)
 				venus_hfi_process_msg_event_notify(
 					device, (void *)packet);
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h
index a59a053..44cdf31 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.h
+++ b/drivers/media/platform/msm/vidc/venus_hfi.h
@@ -188,6 +188,7 @@
 	struct mutex read_lock;
 	struct mutex write_lock;
 	struct mutex clock_lock;
+	struct mutex session_lock;
 	msm_vidc_callback callback;
 	struct vidc_mem_addr iface_q_table;
 	struct vidc_mem_addr qdss;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 874738b..5059273 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -832,6 +832,7 @@
 };
 
 u32 hfi_process_msg_packet(msm_vidc_callback callback,
-		u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr);
+		u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr,
+		struct list_head *sessions, struct mutex *session_lock);
 #endif
 
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 010f15d..890a5be 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -176,6 +176,7 @@
 	HAL_PARAM_VENC_MAX_NUM_B_FRAMES,
 	HAL_PARAM_BUFFER_ALLOC_MODE,
 	HAL_PARAM_VDEC_FRAME_ASSEMBLY,
+	HAL_PARAM_VDEC_CONCEAL_COLOR,
 };
 
 enum hal_domain {
@@ -200,7 +201,7 @@
 	HAL_VIDEO_CODEC_VP6      = 0x00000400,
 	HAL_VIDEO_CODEC_VP7      = 0x00000800,
 	HAL_VIDEO_CODEC_VP8      = 0x00001000,
-	HAL_VIDEO_CODEC_HEVC     = 0x00010000,
+	HAL_VIDEO_CODEC_HEVC     = 0x00002000,
 	HAL_UNUSED_CODEC = 0x10000000,
 };
 
@@ -315,6 +316,7 @@
 	HAL_H264_LEVEL_42 = 0x00002000,
 	HAL_H264_LEVEL_5  = 0x00004000,
 	HAL_H264_LEVEL_51 = 0x00008000,
+	HAL_H264_LEVEL_52 = 0x00010000,
 	HAL_UNUSED_H264_LEVEL = 0x10000000,
 };
 
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 0f1e896..de312f4 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -79,7 +79,7 @@
 #define HFI_VIDEO_CODEC_VC1				0x00000100
 #define HFI_VIDEO_CODEC_SPARK				0x00000200
 #define HFI_VIDEO_CODEC_VP8				0x00001000
-#define HFI_VIDEO_CODEC_HEVC				0x00010000
+#define HFI_VIDEO_CODEC_HEVC				0x00002000
 
 #define HFI_H264_PROFILE_BASELINE			0x00000001
 #define HFI_H264_PROFILE_MAIN				0x00000002
@@ -105,6 +105,7 @@
 #define HFI_H264_LEVEL_42					0x00002000
 #define HFI_H264_LEVEL_5					0x00004000
 #define HFI_H264_LEVEL_51					0x00008000
+#define HFI_H264_LEVEL_52                                       0x00010000
 
 #define HFI_H263_PROFILE_BASELINE			0x00000001
 
@@ -435,6 +436,10 @@
 	u32 max_num_b_frames;
 };
 
+struct hfi_conceal_color {
+	u32 conceal_color;
+};
+
 struct hfi_intra_period {
 	u32 pframes;
 	u32 bframes;
diff --git a/drivers/media/platform/msm/wfd/wfd-ioctl.c b/drivers/media/platform/msm/wfd/wfd-ioctl.c
index 58e008d..e3c9b2a 100644
--- a/drivers/media/platform/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/platform/msm/wfd/wfd-ioctl.c
@@ -134,10 +134,18 @@
 
 static void wfd_vidbuf_wait_prepare(struct vb2_queue *q)
 {
+	struct file *priv_data = (struct file *)(q->drv_priv);
+	struct wfd_inst *inst = file_to_inst(priv_data);
+
+	mutex_unlock(&inst->vb2_lock);
 }
 
 static void wfd_vidbuf_wait_finish(struct vb2_queue *q)
 {
+	struct file *priv_data = (struct file *)(q->drv_priv);
+	struct wfd_inst *inst = file_to_inst(priv_data);
+
+	mutex_lock(&inst->vb2_lock);
 }
 
 static unsigned long wfd_enc_addr_to_mdp_addr(struct wfd_inst *inst,
@@ -1026,10 +1034,9 @@
 
 	WFD_MSG_DBG("Waiting to dequeue buffer\n");
 
-	/* XXX: If we switch to non-blocking mode in the future,
-	 * we'll need to lock this with vb2_lock */
-	rc = vb2_dqbuf(&inst->vid_bufq, b, false /* blocking */);
-
+	mutex_lock(&inst->vb2_lock);
+	rc = vb2_dqbuf(&inst->vid_bufq, b, false);
+	mutex_unlock(&inst->vb2_lock);
 	if (rc)
 		WFD_MSG_ERR("Failed to dequeue buffer\n");
 	else
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index de6f1d5..a4cf18e 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -2061,8 +2061,7 @@
 
 	if (radio->fm_st_rsp.station_rsp.stereo_prg)
 		iris_q_event(radio, IRIS_EVT_STEREO);
-
-	if (radio->fm_st_rsp.station_rsp.mute_mode)
+	else if (radio->fm_st_rsp.station_rsp.stereo_prg == 0)
 		iris_q_event(radio, IRIS_EVT_MONO);
 
 	if (radio->fm_st_rsp.station_rsp.rds_sync_status)
@@ -3209,7 +3208,7 @@
 			}
 			break;
 		case FM_TRANS:
-			if (!is_enable_tx_possible(radio) != 0)
+			if (is_enable_tx_possible(radio) != 0)
 				return -EINVAL;
 			radio->mode = FM_TRANS_TURNING_ON;
 			retval = hci_cmd(HCI_FM_ENABLE_TRANS_CMD,
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 3222ea0..4a8d974 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -595,6 +595,8 @@
 	case V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS: return "Intra Refresh AIR MBS";
 	case V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF: return "Intra Refresh AIR REF";
 	case V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS: return "Intra Refresh CIR MBS";
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+		return "VP8 Profile Level";
 
 	/* CAMERA controls */
 	/* Keep the order of the 'case's the same as in videodev2.h! */
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index c99bed1..75a76c0 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -75,11 +75,14 @@
 obj-$(CONFIG_MCP_UCB1200)	+= ucb1x00-core.o
 obj-$(CONFIG_MCP_UCB1200_TS)	+= ucb1x00-ts.o
 
-obj-$(CONFIG_WCD9310_CODEC)       += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
-obj-$(CONFIG_WCD9304_CODEC)       += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
-obj-$(CONFIG_WCD9320_CODEC)       += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
-obj-$(CONFIG_WCD9306_CODEC)       += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
-
+obj-$(CONFIG_WCD9310_CODEC)	+= wcd9xxx-core.o wcd9xxx-irq.o \
+						wcd9xxx-slimslave.o wcd9xxx-core-resource.o
+obj-$(CONFIG_WCD9304_CODEC)	+= wcd9xxx-core.o wcd9xxx-irq.o \
+						wcd9xxx-slimslave.o wcd9xxx-core-resource.o
+obj-$(CONFIG_WCD9320_CODEC)	+= wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o\
+						wcd9xxx-core-resource.o
+obj-$(CONFIG_WCD9306_CODEC)	+= wcd9xxx-core.o wcd9xxx-irq.o\
+						wcd9xxx-slimslave.o wcd9xxx-core-resource.o
 
 ifeq ($(CONFIG_SA1100_ASSABET),y)
 obj-$(CONFIG_MCP_UCB1200)	+= ucb1x00-assabet.o
diff --git a/drivers/mfd/wcd9xxx-core-resource.c b/drivers/mfd/wcd9xxx-core-resource.c
new file mode 100644
index 0000000..1791d72
--- /dev/null
+++ b/drivers/mfd/wcd9xxx-core-resource.c
@@ -0,0 +1,194 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/mfd/wcd9xxx/core-resource.h>
+
+
+static enum wcd9xxx_intf_status wcd9xxx_intf = -1;
+
+int wcd9xxx_core_irq_init(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res)
+{
+	int ret = 0;
+
+	if (wcd9xxx_core_res->irq != 1) {
+		ret = wcd9xxx_irq_init(wcd9xxx_core_res);
+		if (ret)
+			pr_err("IRQ initialization failed\n");
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_core_irq_init);
+
+int wcd9xxx_initialize_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res,
+	unsigned int irq,
+	unsigned int irq_base)
+{
+	wcd9xxx_core_res->irq = irq;
+	wcd9xxx_core_res->irq_base = irq_base;
+
+	return 0;
+}
+EXPORT_SYMBOL(wcd9xxx_initialize_irq);
+
+int wcd9xxx_core_res_init(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res,
+	int num_irqs, int num_irq_regs,
+	int (*codec_read)(struct wcd9xxx_core_resource*, unsigned short),
+	int (*codec_write)(struct wcd9xxx_core_resource*, unsigned short, u8),
+	int (*codec_bulk_read) (struct wcd9xxx_core_resource*, unsigned short,
+							int, u8*))
+{
+	mutex_init(&wcd9xxx_core_res->pm_lock);
+	wcd9xxx_core_res->wlock_holders = 0;
+	wcd9xxx_core_res->pm_state = WCD9XXX_PM_SLEEPABLE;
+	init_waitqueue_head(&wcd9xxx_core_res->pm_wq);
+	pm_qos_add_request(&wcd9xxx_core_res->pm_qos_req,
+				PM_QOS_CPU_DMA_LATENCY,
+				PM_QOS_DEFAULT_VALUE);
+
+	wcd9xxx_core_res->codec_reg_read = codec_read;
+	wcd9xxx_core_res->codec_reg_write = codec_write;
+	wcd9xxx_core_res->codec_bulk_read = codec_bulk_read;
+	wcd9xxx_core_res->num_irqs = num_irqs;
+	wcd9xxx_core_res->num_irq_regs = num_irq_regs;
+
+	pr_info("%s: num_irqs = %d, num_irq_regs = %d\n",
+			__func__, wcd9xxx_core_res->num_irqs,
+			wcd9xxx_core_res->num_irq_regs);
+
+	return 0;
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_init);
+
+void wcd9xxx_core_res_deinit(struct wcd9xxx_core_resource *wcd9xxx_core_res)
+{
+	pm_qos_remove_request(&wcd9xxx_core_res->pm_qos_req);
+	mutex_destroy(&wcd9xxx_core_res->pm_lock);
+	wcd9xxx_core_res->codec_reg_read = NULL;
+	wcd9xxx_core_res->codec_reg_write = NULL;
+	wcd9xxx_core_res->codec_bulk_read = NULL;
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_deinit);
+
+enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(
+		struct wcd9xxx_core_resource *wcd9xxx_core_res,
+		enum wcd9xxx_pm_state o,
+		enum wcd9xxx_pm_state n)
+{
+	enum wcd9xxx_pm_state old;
+	mutex_lock(&wcd9xxx_core_res->pm_lock);
+	old = wcd9xxx_core_res->pm_state;
+	if (old == o)
+		wcd9xxx_core_res->pm_state = n;
+	mutex_unlock(&wcd9xxx_core_res->pm_lock);
+	return old;
+}
+EXPORT_SYMBOL(wcd9xxx_pm_cmpxchg);
+
+int wcd9xxx_core_res_suspend(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res,
+	pm_message_t pmesg)
+{
+	int ret = 0;
+
+	pr_debug("%s: enter\n", __func__);
+	/*
+	 * pm_qos_update_request() can be called after this suspend chain call
+	 * started. thus suspend can be called while lock is being held
+	 */
+	mutex_lock(&wcd9xxx_core_res->pm_lock);
+	if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_SLEEPABLE) {
+		pr_debug("%s: suspending system, state %d, wlock %d\n",
+			 __func__, wcd9xxx_core_res->pm_state,
+			 wcd9xxx_core_res->wlock_holders);
+		wcd9xxx_core_res->pm_state = WCD9XXX_PM_ASLEEP;
+	} else if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_AWAKE) {
+		/*
+		 * unlock to wait for pm_state == WCD9XXX_PM_SLEEPABLE
+		 * then set to WCD9XXX_PM_ASLEEP
+		 */
+		pr_debug("%s: waiting to suspend system, state %d, wlock %d\n",
+			 __func__, wcd9xxx_core_res->pm_state,
+			 wcd9xxx_core_res->wlock_holders);
+		mutex_unlock(&wcd9xxx_core_res->pm_lock);
+		if (!(wait_event_timeout(wcd9xxx_core_res->pm_wq,
+					 wcd9xxx_pm_cmpxchg(wcd9xxx_core_res,
+						  WCD9XXX_PM_SLEEPABLE,
+						  WCD9XXX_PM_ASLEEP) ==
+							WCD9XXX_PM_SLEEPABLE,
+					 HZ))) {
+			pr_debug("%s: suspend failed state %d, wlock %d\n",
+				 __func__, wcd9xxx_core_res->pm_state,
+				 wcd9xxx_core_res->wlock_holders);
+			ret = -EBUSY;
+		} else {
+			pr_debug("%s: done, state %d, wlock %d\n", __func__,
+				 wcd9xxx_core_res->pm_state,
+				 wcd9xxx_core_res->wlock_holders);
+		}
+		mutex_lock(&wcd9xxx_core_res->pm_lock);
+	} else if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_ASLEEP) {
+		pr_warn("%s: system is already suspended, state %d, wlock %dn",
+			__func__, wcd9xxx_core_res->pm_state,
+			wcd9xxx_core_res->wlock_holders);
+	}
+	mutex_unlock(&wcd9xxx_core_res->pm_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_suspend);
+
+int wcd9xxx_core_res_resume(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res)
+{
+	int ret = 0;
+
+	pr_debug("%s: enter\n", __func__);
+	mutex_lock(&wcd9xxx_core_res->pm_lock);
+	if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_ASLEEP) {
+		pr_debug("%s: resuming system, state %d, wlock %d\n", __func__,
+				wcd9xxx_core_res->pm_state,
+				wcd9xxx_core_res->wlock_holders);
+		wcd9xxx_core_res->pm_state = WCD9XXX_PM_SLEEPABLE;
+	} else {
+		pr_warn("%s: system is already awake, state %d wlock %d\n",
+				__func__, wcd9xxx_core_res->pm_state,
+				wcd9xxx_core_res->wlock_holders);
+	}
+	mutex_unlock(&wcd9xxx_core_res->pm_lock);
+	wake_up_all(&wcd9xxx_core_res->pm_wq);
+
+	return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_resume);
+
+enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void)
+{
+	return wcd9xxx_intf;
+}
+EXPORT_SYMBOL(wcd9xxx_get_intf_type);
+
+void wcd9xxx_set_intf_type(enum wcd9xxx_intf_status intf_status)
+{
+	wcd9xxx_intf = intf_status;
+}
+EXPORT_SYMBOL(wcd9xxx_set_intf_type);
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 1eebe61..d718c40 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -19,6 +19,7 @@
 #include <linux/mfd/core.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
 #include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/core-resource.h>
 #include <linux/mfd/wcd9xxx/pdata.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
 
@@ -45,6 +46,9 @@
 #define WCD9XXX_I2C_DIGITAL_1	2
 #define WCD9XXX_I2C_DIGITAL_2	3
 
+#define ONDEMAND_REGULATOR true
+#define STATIC_REGULATOR (!ONDEMAND_REGULATOR)
+
 /* Number of return values needs to be checked for each
  * registration of Slimbus of I2C bus for each codec
  */
@@ -65,7 +69,6 @@
 static struct wcd9xxx_pdata *wcd9xxx_populate_dt_pdata(struct device *dev);
 
 struct wcd9xxx_i2c wcd9xxx_modules[MAX_WCD9XXX_DEVICE];
-static int wcd9xxx_intf = -1;
 
 static int wcd9xxx_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
 		       int bytes, void *dest, bool interface_reg)
@@ -89,7 +92,9 @@
 
 	return 0;
 }
-int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg)
+static int __wcd9xxx_reg_read(
+	struct wcd9xxx *wcd9xxx,
+	unsigned short reg)
 {
 	u8 val;
 	int ret;
@@ -103,7 +108,16 @@
 	else
 		return val;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_reg_read);
+
+int wcd9xxx_reg_read(
+	struct wcd9xxx_core_resource *core_res,
+	unsigned short reg)
+{
+	struct wcd9xxx *wcd9xxx = (struct wcd9xxx *) core_res->parent;
+	return __wcd9xxx_reg_read(wcd9xxx, reg);
+
+}
+EXPORT_SYMBOL(wcd9xxx_reg_read);
 
 static int wcd9xxx_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
 			int bytes, void *src, bool interface_reg)
@@ -122,8 +136,9 @@
 	return wcd9xxx->write_dev(wcd9xxx, reg, bytes, src, interface_reg);
 }
 
-int wcd9xxx_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
-		     u8 val)
+static int __wcd9xxx_reg_write(
+	struct wcd9xxx *wcd9xxx,
+	unsigned short reg, u8 val)
 {
 	int ret;
 
@@ -133,7 +148,15 @@
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_reg_write);
+
+int wcd9xxx_reg_write(
+	struct wcd9xxx_core_resource *core_res,
+	unsigned short reg, u8 val)
+{
+	struct wcd9xxx *wcd9xxx = (struct wcd9xxx *) core_res->parent;
+	return __wcd9xxx_reg_write(wcd9xxx, reg, val);
+}
+EXPORT_SYMBOL(wcd9xxx_reg_write);
 
 static u8 wcd9xxx_pgd_la;
 static u8 wcd9xxx_inf_la;
@@ -152,7 +175,7 @@
 	else
 		return val;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_interface_reg_read);
+EXPORT_SYMBOL(wcd9xxx_interface_reg_read);
 
 int wcd9xxx_interface_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
 		     u8 val)
@@ -165,37 +188,54 @@
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_interface_reg_write);
+EXPORT_SYMBOL(wcd9xxx_interface_reg_write);
 
-int wcd9xxx_bulk_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
-		     int count, u8 *buf)
+static int __wcd9xxx_bulk_read(
+	struct wcd9xxx *wcd9xxx,
+	unsigned short reg,
+	int count, u8 *buf)
 {
 	int ret;
 
 	mutex_lock(&wcd9xxx->io_lock);
-
 	ret = wcd9xxx_read(wcd9xxx, reg, count, buf, false);
-
 	mutex_unlock(&wcd9xxx->io_lock);
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_bulk_read);
 
-int wcd9xxx_bulk_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+int wcd9xxx_bulk_read(
+	struct wcd9xxx_core_resource *core_res,
+	unsigned short reg,
+	int count, u8 *buf)
+{
+	struct wcd9xxx *wcd9xxx =
+			(struct wcd9xxx *) core_res->parent;
+	return __wcd9xxx_bulk_read(wcd9xxx, reg, count, buf);
+}
+EXPORT_SYMBOL(wcd9xxx_bulk_read);
+
+static int __wcd9xxx_bulk_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
 		     int count, u8 *buf)
 {
 	int ret;
 
 	mutex_lock(&wcd9xxx->io_lock);
-
 	ret = wcd9xxx_write(wcd9xxx, reg, count, buf, false);
-
 	mutex_unlock(&wcd9xxx->io_lock);
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_bulk_write);
+
+int wcd9xxx_bulk_write(
+	struct wcd9xxx_core_resource *core_res,
+	unsigned short reg, int count, u8 *buf)
+{
+	struct wcd9xxx *wcd9xxx =
+			(struct wcd9xxx *) core_res->parent;
+	return __wcd9xxx_bulk_write(wcd9xxx, reg, count, buf);
+}
+EXPORT_SYMBOL(wcd9xxx_bulk_write);
 
 static int wcd9xxx_slim_read_device(struct wcd9xxx *wcd9xxx, unsigned short reg,
 				int bytes, void *dest, bool interface)
@@ -334,19 +374,19 @@
 
 static void wcd9xxx_bring_up(struct wcd9xxx *wcd9xxx)
 {
-	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x4);
-	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 0);
+	__wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x4);
+	__wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 0);
 	usleep_range(5000, 5000);
-	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 3);
-	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 3);
+	__wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 3);
+	__wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 3);
 }
 
 static void wcd9xxx_bring_down(struct wcd9xxx *wcd9xxx)
 {
-	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x7);
-	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x6);
-	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0xe);
-	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x8);
+	__wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x7);
+	__wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x6);
+	__wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0xe);
+	__wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x8);
 }
 
 static int wcd9xxx_reset(struct wcd9xxx *wcd9xxx)
@@ -385,13 +425,13 @@
 	int i, rc;
 	const struct wcd9xxx_codec_type *c, *d = NULL;
 
-	rc = wcd9xxx_bulk_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_0,
+	rc = __wcd9xxx_bulk_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_0,
 			       sizeof(wcd9xxx->id_minor),
 			       (u8 *)&wcd9xxx->id_minor);
 	if (rc < 0)
 		goto exit;
 
-	rc = wcd9xxx_bulk_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_2,
+	rc = __wcd9xxx_bulk_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_2,
 			       sizeof(wcd9xxx->id_major),
 			       (u8 *)&wcd9xxx->id_major);
 	if (rc < 0)
@@ -431,7 +471,8 @@
 		if (d->version > -1) {
 			*version = d->version;
 		} else {
-			rc = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_VERSION);
+			rc = __wcd9xxx_reg_read(wcd9xxx,
+							WCD9XXX_A_CHIP_VERSION);
 			if (rc < 0) {
 				d = NULL;
 				goto exit;
@@ -447,24 +488,94 @@
 	return d;
 }
 
+static int wcd9xxx_num_irq_regs(const struct wcd9xxx *wcd9xxx)
+{
+	return (wcd9xxx->codec_type->num_irqs / 8) +
+		((wcd9xxx->codec_type->num_irqs % 8) ? 1 : 0);
+}
+
+/*
+ * Interrupt table for v1 corresponds to newer version
+ * codecs (wcd9304 and wcd9310)
+ */
+static const struct intr_data intr_tbl_v1[] = {
+	{WCD9XXX_IRQ_SLIMBUS, false},
+	{WCD9XXX_IRQ_MBHC_INSERTION, true},
+	{WCD9XXX_IRQ_MBHC_POTENTIAL, true},
+	{WCD9XXX_IRQ_MBHC_RELEASE, true},
+	{WCD9XXX_IRQ_MBHC_PRESS, true},
+	{WCD9XXX_IRQ_MBHC_SHORT_TERM, true},
+	{WCD9XXX_IRQ_MBHC_REMOVAL, true},
+	{WCD9XXX_IRQ_BG_PRECHARGE, false},
+	{WCD9XXX_IRQ_PA1_STARTUP, false},
+	{WCD9XXX_IRQ_PA2_STARTUP, false},
+	{WCD9XXX_IRQ_PA3_STARTUP, false},
+	{WCD9XXX_IRQ_PA4_STARTUP, false},
+	{WCD9XXX_IRQ_PA5_STARTUP, false},
+	{WCD9XXX_IRQ_MICBIAS1_PRECHARGE, false},
+	{WCD9XXX_IRQ_MICBIAS2_PRECHARGE, false},
+	{WCD9XXX_IRQ_MICBIAS3_PRECHARGE, false},
+	{WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, false},
+	{WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, false},
+	{WCD9XXX_IRQ_EAR_PA_OCPL_FAULT, false},
+	{WCD9XXX_IRQ_HPH_L_PA_STARTUP, false},
+	{WCD9XXX_IRQ_HPH_R_PA_STARTUP, false},
+	{WCD9320_IRQ_EAR_PA_STARTUP, false},
+	{WCD9XXX_IRQ_RESERVED_0, false},
+	{WCD9XXX_IRQ_RESERVED_1, false},
+};
+
+/*
+ * Interrupt table for v2 corresponds to newer version
+ * codecs (wcd9320 and wcd9306)
+ */
+static const struct intr_data intr_tbl_v2[] = {
+	{WCD9XXX_IRQ_SLIMBUS, false},
+	{WCD9XXX_IRQ_MBHC_INSERTION, true},
+	{WCD9XXX_IRQ_MBHC_POTENTIAL, true},
+	{WCD9XXX_IRQ_MBHC_RELEASE, true},
+	{WCD9XXX_IRQ_MBHC_PRESS, true},
+	{WCD9XXX_IRQ_MBHC_SHORT_TERM, true},
+	{WCD9XXX_IRQ_MBHC_REMOVAL, true},
+	{WCD9320_IRQ_MBHC_JACK_SWITCH, true},
+	{WCD9306_IRQ_MBHC_JACK_SWITCH, true},
+	{WCD9XXX_IRQ_BG_PRECHARGE, false},
+	{WCD9XXX_IRQ_PA1_STARTUP, false},
+	{WCD9XXX_IRQ_PA2_STARTUP, false},
+	{WCD9XXX_IRQ_PA3_STARTUP, false},
+	{WCD9XXX_IRQ_PA4_STARTUP, false},
+	{WCD9XXX_IRQ_PA5_STARTUP, false},
+	{WCD9XXX_IRQ_MICBIAS1_PRECHARGE, false},
+	{WCD9XXX_IRQ_MICBIAS2_PRECHARGE, false},
+	{WCD9XXX_IRQ_MICBIAS3_PRECHARGE, false},
+	{WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, false},
+	{WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, false},
+	{WCD9XXX_IRQ_EAR_PA_OCPL_FAULT, false},
+	{WCD9XXX_IRQ_HPH_L_PA_STARTUP, false},
+	{WCD9XXX_IRQ_HPH_R_PA_STARTUP, false},
+	{WCD9320_IRQ_EAR_PA_STARTUP, false},
+	{WCD9XXX_IRQ_RESERVED_0, false},
+	{WCD9XXX_IRQ_RESERVED_1, false},
+	{WCD9XXX_IRQ_MAD_AUDIO, false},
+	{WCD9XXX_IRQ_MAD_BEACON, false},
+	{WCD9XXX_IRQ_MAD_ULTRASOUND, false},
+	{WCD9XXX_IRQ_SPEAKER_CLIPPING, false},
+	{WCD9XXX_IRQ_VBAT_MONITOR_ATTACK, false},
+	{WCD9XXX_IRQ_VBAT_MONITOR_RELEASE, false},
+	{WCD9XXX_IRQ_RESERVED_2, false},
+};
+
 static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx)
 {
-	int ret;
+	int ret = 0;
 	u8 version;
 	const struct wcd9xxx_codec_type *found;
+	struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res;
 
 	mutex_init(&wcd9xxx->io_lock);
 	mutex_init(&wcd9xxx->xfer_lock);
 
-	mutex_init(&wcd9xxx->pm_lock);
-	wcd9xxx->wlock_holders = 0;
-	wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
-	init_waitqueue_head(&wcd9xxx->pm_wq);
-	pm_qos_add_request(&wcd9xxx->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
-				PM_QOS_DEFAULT_VALUE);
-
 	dev_set_drvdata(wcd9xxx->dev, wcd9xxx);
-
 	wcd9xxx_bring_up(wcd9xxx);
 
 	found = wcd9xxx_check_codec_type(wcd9xxx, &version);
@@ -476,27 +587,46 @@
 		wcd9xxx->version = version;
 	}
 
-	if (wcd9xxx->irq != -1) {
-		ret = wcd9xxx_irq_init(wcd9xxx);
-		if (ret) {
-			pr_err("IRQ initialization failed\n");
-			goto err;
-		}
+	core_res->parent = wcd9xxx;
+	core_res->dev = wcd9xxx->dev;
+
+	if (wcd9xxx->codec_type->id_major == TABLA_MAJOR
+		|| wcd9xxx->codec_type->id_major == SITAR_MAJOR) {
+		core_res->intr_table = intr_tbl_v1;
+		core_res->intr_table_size = ARRAY_SIZE(intr_tbl_v1);
+	} else {
+		core_res->intr_table = intr_tbl_v2;
+		core_res->intr_table_size = ARRAY_SIZE(intr_tbl_v2);
 	}
 
+	wcd9xxx_core_res_init(&wcd9xxx->core_res,
+				wcd9xxx->codec_type->num_irqs,
+				wcd9xxx_num_irq_regs(wcd9xxx),
+				wcd9xxx_reg_read, wcd9xxx_reg_write,
+				wcd9xxx_bulk_read);
+
+	if (wcd9xxx_core_irq_init(&wcd9xxx->core_res))
+		goto err;
+
 	ret = mfd_add_devices(wcd9xxx->dev, -1, found->dev, found->size,
 			      NULL, 0);
 	if (ret != 0) {
 		dev_err(wcd9xxx->dev, "Failed to add children: %d\n", ret);
 		goto err_irq;
 	}
+
+	ret = device_init_wakeup(wcd9xxx->dev, true);
+	if (ret) {
+		dev_err(wcd9xxx->dev, "Device wakeup init failed: %d\n", ret);
+		goto err_irq;
+	}
+
 	return ret;
 err_irq:
-	wcd9xxx_irq_exit(wcd9xxx);
+	wcd9xxx_irq_exit(&wcd9xxx->core_res);
 err:
 	wcd9xxx_bring_down(wcd9xxx);
-	pm_qos_remove_request(&wcd9xxx->pm_qos_req);
-	mutex_destroy(&wcd9xxx->pm_lock);
+	wcd9xxx_core_res_deinit(&wcd9xxx->core_res);
 	mutex_destroy(&wcd9xxx->io_lock);
 	mutex_destroy(&wcd9xxx->xfer_lock);
 	return ret;
@@ -504,14 +634,14 @@
 
 static void wcd9xxx_device_exit(struct wcd9xxx *wcd9xxx)
 {
-	wcd9xxx_irq_exit(wcd9xxx);
+	device_init_wakeup(wcd9xxx->dev, false);
+	wcd9xxx_irq_exit(&wcd9xxx->core_res);
 	wcd9xxx_bring_down(wcd9xxx);
 	wcd9xxx_free_reset(wcd9xxx);
-	mutex_destroy(&wcd9xxx->pm_lock);
-	pm_qos_remove_request(&wcd9xxx->pm_qos_req);
+	wcd9xxx_core_res_deinit(&wcd9xxx->core_res);
 	mutex_destroy(&wcd9xxx->io_lock);
 	mutex_destroy(&wcd9xxx->xfer_lock);
-	if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+	if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
 		slim_remove_device(wcd9xxx->slim_slave);
 	kfree(wcd9xxx);
 }
@@ -736,13 +866,6 @@
 	kfree(wcd9xxx->supplies);
 }
 
-enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void)
-{
-	return wcd9xxx_intf;
-}
-
-EXPORT_SYMBOL_GPL(wcd9xxx_get_intf_type);
-
 struct wcd9xxx_i2c *get_i2c_wcd9xxx_device_info(u16 reg)
 {
 	u16 mask = 0x0f00;
@@ -894,13 +1017,16 @@
 	int ret = 0;
 	int wcd9xx_index = 0;
 	struct device *dev;
+	int intf_type;
 
-	pr_debug("%s: interface status %d\n", __func__, wcd9xxx_intf);
-	if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+	intf_type = wcd9xxx_get_intf_type();
+
+	pr_debug("%s: interface status %d\n", __func__, intf_type);
+	if (intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
 		dev_dbg(&client->dev, "%s:Codec is detected in slimbus mode\n",
 			__func__);
 		return -ENODEV;
-	} else if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_I2C) {
+	} else if (intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
 		ret = wcd9xxx_i2c_get_client_index(client, &wcd9xx_index);
 		if (ret != 0)
 			dev_err(&client->dev, "%s: I2C set codec I2C\n"
@@ -912,7 +1038,7 @@
 			wcd9xxx_modules[wcd9xx_index].client = client;
 		}
 		return ret;
-	} else if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_PROBING) {
+	} else if (intf_type == WCD9XXX_INTERFACE_TYPE_PROBING) {
 		dev = &client->dev;
 		if (client->dev.of_node) {
 			dev_dbg(&client->dev, "%s:Platform data\n"
@@ -979,10 +1105,9 @@
 		wcd9xxx_modules[wcd9xx_index].client = client;
 		wcd9xxx->read_dev = wcd9xxx_i2c_read;
 		wcd9xxx->write_dev = wcd9xxx_i2c_write;
-		if (!wcd9xxx->dev->of_node) {
-			wcd9xxx->irq = pdata->irq;
-			wcd9xxx->irq_base = pdata->irq_base;
-		}
+		if (!wcd9xxx->dev->of_node)
+			wcd9xxx_initialize_irq(&wcd9xxx->core_res,
+					pdata->irq, pdata->irq_base);
 
 		ret = wcd9xxx_device_init(wcd9xxx);
 		if (ret) {
@@ -998,7 +1123,7 @@
 		if (val != wcd9xxx->codec_type->i2c_chip_status)
 			pr_err("%s: unknown chip status 0x%x\n", __func__, val);
 
-		wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_I2C;
+		wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_I2C);
 
 		return ret;
 	} else
@@ -1195,15 +1320,54 @@
 	return 0;
 }
 
+static int wcd9xxx_process_supplies(struct device *dev,
+		struct wcd9xxx_pdata *pdata, const char *supply_list,
+		int supply_cnt, bool is_ondemand, int index)
+{
+	int idx, ret = 0;
+	const char *name;
+
+	if (supply_cnt == 0) {
+		dev_dbg(dev, "%s: no supplies defined for %s\n", __func__,
+				supply_list);
+		return 0;
+	}
+
+	for (idx = 0; idx < supply_cnt; idx++) {
+		ret = of_property_read_string_index(dev->of_node,
+						    supply_list, idx,
+						    &name);
+		if (ret) {
+			dev_err(dev, "%s: of read string %s idx %d error %d\n",
+				__func__, supply_list, idx, ret);
+			goto err;
+		}
+
+		dev_dbg(dev, "%s: Found cdc supply %s as part of %s\n",
+				__func__, name, supply_list);
+		ret = wcd9xxx_dt_parse_vreg_info(dev,
+					&pdata->regulator[index + idx],
+					name, is_ondemand);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	return ret;
+
+}
+
 static struct wcd9xxx_pdata *wcd9xxx_populate_dt_pdata(struct device *dev)
 {
 	struct wcd9xxx_pdata *pdata;
-	int ret, static_cnt, ond_cnt, idx, i;
-	const char *name = NULL;
+	int ret, static_cnt, ond_cnt, cp_supplies_cnt;
 	u32 mclk_rate = 0;
 	u32 dmic_sample_rate = 0;
 	const char *static_prop_name = "qcom,cdc-static-supplies";
 	const char *ond_prop_name = "qcom,cdc-on-demand-supplies";
+	const char *cp_supplies_name = "qcom,cdc-cp-supplies";
 
 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata) {
@@ -1223,44 +1387,35 @@
 	if (IS_ERR_VALUE(ond_cnt))
 		ond_cnt = 0;
 
-	BUG_ON(static_cnt <= 0 || ond_cnt < 0);
-	if ((static_cnt + ond_cnt) > ARRAY_SIZE(pdata->regulator)) {
+	/* cp-supplies list is an optional property */
+	cp_supplies_cnt = of_property_count_strings(dev->of_node,
+							cp_supplies_name);
+	if (IS_ERR_VALUE(cp_supplies_cnt))
+		cp_supplies_cnt = 0;
+
+	BUG_ON(static_cnt <= 0 || ond_cnt < 0 || cp_supplies_cnt < 0);
+	if ((static_cnt + ond_cnt + cp_supplies_cnt)
+			> ARRAY_SIZE(pdata->regulator)) {
 		dev_err(dev, "%s: Num of supplies %u > max supported %u\n",
 			__func__, static_cnt, ARRAY_SIZE(pdata->regulator));
 		goto err;
 	}
 
-	for (idx = 0; idx < static_cnt; idx++) {
-		ret = of_property_read_string_index(dev->of_node,
-						    static_prop_name, idx,
-						    &name);
-		if (ret) {
-			dev_err(dev, "%s: of read string %s idx %d error %d\n",
-				__func__, static_prop_name, idx, ret);
-			goto err;
-		}
+	ret = wcd9xxx_process_supplies(dev, pdata, static_prop_name,
+				static_cnt, STATIC_REGULATOR, 0);
+	if (ret)
+		goto err;
 
-		dev_dbg(dev, "%s: Found static cdc supply %s\n", __func__,
-			name);
-		ret = wcd9xxx_dt_parse_vreg_info(dev, &pdata->regulator[idx],
-						 name, false);
-		if (ret)
-			goto err;
-	}
+	ret = wcd9xxx_process_supplies(dev, pdata, ond_prop_name,
+				ond_cnt, ONDEMAND_REGULATOR, static_cnt);
+	if (ret)
+		goto err;
 
-	for (i = 0; i < ond_cnt; i++, idx++) {
-		ret = of_property_read_string_index(dev->of_node, ond_prop_name,
-						    i, &name);
-		if (ret)
-			goto err;
-
-		dev_dbg(dev, "%s: Found on-demand cdc supply %s\n", __func__,
-			name);
-		ret = wcd9xxx_dt_parse_vreg_info(dev, &pdata->regulator[idx],
-						 name, true);
-		if (ret)
-			goto err;
-	}
+	ret = wcd9xxx_process_supplies(dev, pdata, cp_supplies_name,
+				cp_supplies_cnt, ONDEMAND_REGULATOR,
+				static_cnt + ond_cnt);
+	if (ret)
+		goto err;
 
 	ret = wcd9xxx_dt_parse_micbias_info(dev, &pdata->micbias);
 	if (ret)
@@ -1351,8 +1506,11 @@
 	struct wcd9xxx *wcd9xxx;
 	struct wcd9xxx_pdata *pdata;
 	int ret = 0;
+	int intf_type;
 
-	if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_I2C) {
+	intf_type = wcd9xxx_get_intf_type();
+
+	if (intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
 		dev_dbg(&slim->dev, "%s:Codec is detected in I2C mode\n",
 			__func__);
 		return -ENODEV;
@@ -1430,10 +1588,9 @@
 	wcd9xxx->write_dev = wcd9xxx_slim_write_device;
 	wcd9xxx_pgd_la = wcd9xxx->slim->laddr;
 	wcd9xxx->slim_slave = &pdata->slimbus_slave_device;
-	if (!wcd9xxx->dev->of_node) {
-		wcd9xxx->irq = pdata->irq;
-		wcd9xxx->irq_base = pdata->irq_base;
-	}
+	if (!wcd9xxx->dev->of_node)
+		wcd9xxx_initialize_irq(&wcd9xxx->core_res,
+					pdata->irq, pdata->irq_base);
 
 	ret = slim_add_device(slim->ctrl, wcd9xxx->slim_slave);
 	if (ret) {
@@ -1451,7 +1608,7 @@
 		goto err_slim_add;
 	}
 	wcd9xxx_inf_la = wcd9xxx->slim_slave->laddr;
-	wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_SLIMBUS;
+	wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_SLIMBUS);
 
 	ret = wcd9xxx_device_init(wcd9xxx);
 	if (ret) {
@@ -1505,29 +1662,10 @@
 	return 0;
 }
 
-static int wcd9xxx_resume(struct wcd9xxx *wcd9xxx)
-{
-	int ret = 0;
-
-	pr_debug("%s: enter\n", __func__);
-	mutex_lock(&wcd9xxx->pm_lock);
-	if (wcd9xxx->pm_state == WCD9XXX_PM_ASLEEP) {
-		pr_debug("%s: resuming system, state %d, wlock %d\n", __func__,
-			 wcd9xxx->pm_state, wcd9xxx->wlock_holders);
-		wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
-	} else {
-		pr_warn("%s: system is already awake, state %d wlock %d\n",
-			__func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
-	}
-	mutex_unlock(&wcd9xxx->pm_lock);
-	wake_up_all(&wcd9xxx->pm_wq);
-
-	return ret;
-}
-
 static int wcd9xxx_device_up(struct wcd9xxx *wcd9xxx)
 {
 	int ret = 0;
+	struct wcd9xxx_core_resource *wcd9xxx_res = &wcd9xxx->core_res;
 
 	if (wcd9xxx->slim_device_bootup) {
 		wcd9xxx->slim_device_bootup = false;
@@ -1538,86 +1676,60 @@
 		pr_err("%s: Resetting Codec failed\n", __func__);
 
 	wcd9xxx_bring_up(wcd9xxx);
-	wcd9xxx->post_reset(wcd9xxx);
+	ret = wcd9xxx_irq_init(wcd9xxx_res);
+	if (ret) {
+		pr_err("%s: wcd9xx_irq_init failed : %d\n", __func__, ret);
+	} else {
+		if (wcd9xxx->post_reset)
+			ret = wcd9xxx->post_reset(wcd9xxx);
+	}
 	return ret;
 }
 
 static int wcd9xxx_slim_device_up(struct slim_device *sldev)
 {
 	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+	dev_dbg(wcd9xxx->dev, "%s: device up\n", __func__);
 	return wcd9xxx_device_up(wcd9xxx);
 }
 
+static int wcd9xxx_slim_device_down(struct slim_device *sldev)
+{
+	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+
+	wcd9xxx_irq_exit(&wcd9xxx->core_res);
+	if (wcd9xxx->dev_down)
+		wcd9xxx->dev_down(wcd9xxx);
+	dev_dbg(wcd9xxx->dev, "%s: device down\n", __func__);
+	return 0;
+}
+
 static int wcd9xxx_slim_resume(struct slim_device *sldev)
 {
 	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
-	return wcd9xxx_resume(wcd9xxx);
+	return wcd9xxx_core_res_resume(&wcd9xxx->core_res);
 }
 
 static int wcd9xxx_i2c_resume(struct i2c_client *i2cdev)
 {
 	struct wcd9xxx *wcd9xxx = dev_get_drvdata(&i2cdev->dev);
 	if (wcd9xxx)
-		return wcd9xxx_resume(wcd9xxx);
+		return wcd9xxx_core_res_resume(&wcd9xxx->core_res);
 	else
 		return 0;
 }
 
-static int wcd9xxx_suspend(struct wcd9xxx *wcd9xxx, pm_message_t pmesg)
-{
-	int ret = 0;
-
-	pr_debug("%s: enter\n", __func__);
-	/*
-	 * pm_qos_update_request() can be called after this suspend chain call
-	 * started. thus suspend can be called while lock is being held
-	 */
-	mutex_lock(&wcd9xxx->pm_lock);
-	if (wcd9xxx->pm_state == WCD9XXX_PM_SLEEPABLE) {
-		pr_debug("%s: suspending system, state %d, wlock %d\n",
-			 __func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
-		wcd9xxx->pm_state = WCD9XXX_PM_ASLEEP;
-	} else if (wcd9xxx->pm_state == WCD9XXX_PM_AWAKE) {
-		/* unlock to wait for pm_state == WCD9XXX_PM_SLEEPABLE
-		 * then set to WCD9XXX_PM_ASLEEP */
-		pr_debug("%s: waiting to suspend system, state %d, wlock %d\n",
-			 __func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
-		mutex_unlock(&wcd9xxx->pm_lock);
-		if (!(wait_event_timeout(wcd9xxx->pm_wq,
-					 wcd9xxx_pm_cmpxchg(wcd9xxx,
-						  WCD9XXX_PM_SLEEPABLE,
-						  WCD9XXX_PM_ASLEEP) ==
-							WCD9XXX_PM_SLEEPABLE,
-					 HZ))) {
-			pr_debug("%s: suspend failed state %d, wlock %d\n",
-				 __func__, wcd9xxx->pm_state,
-				 wcd9xxx->wlock_holders);
-			ret = -EBUSY;
-		} else {
-			pr_debug("%s: done, state %d, wlock %d\n", __func__,
-				 wcd9xxx->pm_state, wcd9xxx->wlock_holders);
-		}
-		mutex_lock(&wcd9xxx->pm_lock);
-	} else if (wcd9xxx->pm_state == WCD9XXX_PM_ASLEEP) {
-		pr_warn("%s: system is already suspended, state %d, wlock %dn",
-			__func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
-	}
-	mutex_unlock(&wcd9xxx->pm_lock);
-
-	return ret;
-}
-
 static int wcd9xxx_slim_suspend(struct slim_device *sldev, pm_message_t pmesg)
 {
 	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
-	return wcd9xxx_suspend(wcd9xxx, pmesg);
+	return wcd9xxx_core_res_suspend(&wcd9xxx->core_res, pmesg);
 }
 
 static int wcd9xxx_i2c_suspend(struct i2c_client *i2cdev, pm_message_t pmesg)
 {
 	struct wcd9xxx *wcd9xxx = dev_get_drvdata(&i2cdev->dev);
 	if (wcd9xxx)
-		return wcd9xxx_suspend(wcd9xxx, pmesg);
+		return wcd9xxx_core_res_suspend(&wcd9xxx->core_res, pmesg);
 	else
 		return 0;
 }
@@ -1704,6 +1816,7 @@
 	.resume = wcd9xxx_slim_resume,
 	.suspend = wcd9xxx_slim_suspend,
 	.device_up = wcd9xxx_slim_device_up,
+	.device_down = wcd9xxx_slim_device_down,
 };
 
 static const struct slim_device_id tapan_slimtest_id[] = {
@@ -1722,6 +1835,7 @@
 	.resume = wcd9xxx_slim_resume,
 	.suspend = wcd9xxx_slim_suspend,
 	.device_up = wcd9xxx_slim_device_up,
+	.device_down = wcd9xxx_slim_device_down,
 };
 
 static struct i2c_device_id wcd9xxx_id_table[] = {
@@ -1771,7 +1885,7 @@
 	int ret[NUM_WCD9XXX_REG_RET];
 	int i = 0;
 
-	wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_PROBING;
+	wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_PROBING);
 
 	ret[0] = slim_driver_register(&tabla_slim_driver);
 	if (ret[0])
@@ -1815,6 +1929,7 @@
 
 static void __exit wcd9xxx_exit(void)
 {
+	wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_PROBING);
 }
 module_exit(wcd9xxx_exit);
 
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 062351d..dc32efd 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -15,10 +15,9 @@
 #include <linux/sched.h>
 #include <linux/irq.h>
 #include <linux/mfd/core.h>
-#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/core-resource.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
 #include <linux/mfd/wcd9xxx/wcd9310_registers.h>
-#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
 #include <linux/delay.h>
 #include <linux/irqdomain.h>
 #include <linux/interrupt.h>
@@ -40,57 +39,76 @@
 };
 #endif
 
-static int virq_to_phyirq(struct wcd9xxx *wcd9xxx, int virq);
-static int phyirq_to_virq(struct wcd9xxx *wcd9xxx, int irq);
-static unsigned int wcd9xxx_irq_get_upstream_irq(struct wcd9xxx *wcd9xxx);
-static void wcd9xxx_irq_put_upstream_irq(struct wcd9xxx *wcd9xxx);
-static int wcd9xxx_map_irq(struct wcd9xxx *wcd9xxx, int irq);
+static int virq_to_phyirq(
+	struct wcd9xxx_core_resource *wcd9xxx_res, int virq);
+static int phyirq_to_virq(
+	struct wcd9xxx_core_resource *wcd9xxx_res, int irq);
+static unsigned int wcd9xxx_irq_get_upstream_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_res);
+static void wcd9xxx_irq_put_upstream_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_res);
+static int wcd9xxx_map_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_res, int irq);
 
 static void wcd9xxx_irq_lock(struct irq_data *data)
 {
-	struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
-	mutex_lock(&wcd9xxx->irq_lock);
+	struct wcd9xxx_core_resource *wcd9xxx_res =
+			irq_data_get_irq_chip_data(data);
+	mutex_lock(&wcd9xxx_res->irq_lock);
 }
 
 static void wcd9xxx_irq_sync_unlock(struct irq_data *data)
 {
-	struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
+	struct wcd9xxx_core_resource *wcd9xxx_res =
+			irq_data_get_irq_chip_data(data);
 	int i;
 
-	if (ARRAY_SIZE(wcd9xxx->irq_masks_cur) > WCD9XXX_NUM_IRQ_REGS ||
-		ARRAY_SIZE(wcd9xxx->irq_masks_cache) > WCD9XXX_NUM_IRQ_REGS) {
+	if ((ARRAY_SIZE(wcd9xxx_res->irq_masks_cur) >
+			WCD9XXX_MAX_IRQ_REGS) ||
+		(ARRAY_SIZE(wcd9xxx_res->irq_masks_cache) >
+			WCD9XXX_MAX_IRQ_REGS)) {
 			pr_err("%s: Array Size out of bound\n", __func__);
 			 return;
 	}
+	if (!wcd9xxx_res->codec_reg_write) {
+		pr_err("%s: Codec reg write callback function not defined\n",
+				__func__);
+		return;
+	}
 
-	for (i = 0; i < ARRAY_SIZE(wcd9xxx->irq_masks_cur); i++) {
+	for (i = 0; i < ARRAY_SIZE(wcd9xxx_res->irq_masks_cur); i++) {
 		/* If there's been a change in the mask write it back
 		 * to the hardware.
 		 */
-		if (wcd9xxx->irq_masks_cur[i] != wcd9xxx->irq_masks_cache[i]) {
-			wcd9xxx->irq_masks_cache[i] = wcd9xxx->irq_masks_cur[i];
-			wcd9xxx_reg_write(wcd9xxx,
+		if (wcd9xxx_res->irq_masks_cur[i] !=
+					wcd9xxx_res->irq_masks_cache[i]) {
+
+			wcd9xxx_res->irq_masks_cache[i] =
+					wcd9xxx_res->irq_masks_cur[i];
+			wcd9xxx_res->codec_reg_write(wcd9xxx_res,
 					  WCD9XXX_A_INTR_MASK0 + i,
-					  wcd9xxx->irq_masks_cur[i]);
+					  wcd9xxx_res->irq_masks_cur[i]);
 		}
 	}
 
-	mutex_unlock(&wcd9xxx->irq_lock);
+	mutex_unlock(&wcd9xxx_res->irq_lock);
 }
 
 static void wcd9xxx_irq_enable(struct irq_data *data)
 {
-	struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
-	int wcd9xxx_irq = virq_to_phyirq(wcd9xxx, data->irq);
-	wcd9xxx->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)] &=
+	struct wcd9xxx_core_resource *wcd9xxx_res =
+			irq_data_get_irq_chip_data(data);
+	int wcd9xxx_irq = virq_to_phyirq(wcd9xxx_res, data->irq);
+	wcd9xxx_res->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)] &=
 		~(BYTE_BIT_MASK(wcd9xxx_irq));
 }
 
 static void wcd9xxx_irq_disable(struct irq_data *data)
 {
-	struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
-	int wcd9xxx_irq = virq_to_phyirq(wcd9xxx, data->irq);
-	wcd9xxx->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)]
+	struct wcd9xxx_core_resource *wcd9xxx_res =
+			irq_data_get_irq_chip_data(data);
+	int wcd9xxx_irq = virq_to_phyirq(wcd9xxx_res, data->irq);
+	wcd9xxx_res->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)]
 		|= BYTE_BIT_MASK(wcd9xxx_irq);
 }
 
@@ -108,21 +126,8 @@
 	.irq_mask = wcd9xxx_irq_mask,
 };
 
-enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(struct wcd9xxx *wcd9xxx,
-		enum wcd9xxx_pm_state o,
-		enum wcd9xxx_pm_state n)
-{
-	enum wcd9xxx_pm_state old;
-	mutex_lock(&wcd9xxx->pm_lock);
-	old = wcd9xxx->pm_state;
-	if (old == o)
-		wcd9xxx->pm_state = n;
-	mutex_unlock(&wcd9xxx->pm_lock);
-	return old;
-}
-EXPORT_SYMBOL_GPL(wcd9xxx_pm_cmpxchg);
-
-bool wcd9xxx_lock_sleep(struct wcd9xxx *wcd9xxx)
+bool wcd9xxx_lock_sleep(
+	struct wcd9xxx_core_resource *wcd9xxx_res)
 {
 	enum wcd9xxx_pm_state os;
 
@@ -138,164 +143,154 @@
 	 * As interrupt line is still active, codec will have another IRQ to
 	 * retry shortly.
 	 */
-	mutex_lock(&wcd9xxx->pm_lock);
-	if (wcd9xxx->wlock_holders++ == 0) {
+	mutex_lock(&wcd9xxx_res->pm_lock);
+	if (wcd9xxx_res->wlock_holders++ == 0) {
 		pr_debug("%s: holding wake lock\n", __func__);
-		pm_qos_update_request(&wcd9xxx->pm_qos_req,
+		pm_qos_update_request(&wcd9xxx_res->pm_qos_req,
 				      msm_cpuidle_get_deep_idle_latency());
 	}
-	mutex_unlock(&wcd9xxx->pm_lock);
-	if (!wait_event_timeout(wcd9xxx->pm_wq,
-			((os = wcd9xxx_pm_cmpxchg(wcd9xxx, WCD9XXX_PM_SLEEPABLE,
-						WCD9XXX_PM_AWAKE)) ==
-						    WCD9XXX_PM_SLEEPABLE ||
-			 (os == WCD9XXX_PM_AWAKE)),
+	mutex_unlock(&wcd9xxx_res->pm_lock);
+	os = wcd9xxx_pm_cmpxchg(wcd9xxx_res,
+					WCD9XXX_PM_SLEEPABLE,
+					WCD9XXX_PM_AWAKE);
+	if (!wait_event_timeout(wcd9xxx_res->pm_wq,
+			(os  == WCD9XXX_PM_SLEEPABLE ||
+			 os == WCD9XXX_PM_AWAKE),
 			msecs_to_jiffies(WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS))) {
 		pr_warn("%s: system didn't resume within %dms, s %d, w %d\n",
 			__func__,
-			WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS, wcd9xxx->pm_state,
-			wcd9xxx->wlock_holders);
-		wcd9xxx_unlock_sleep(wcd9xxx);
+			WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS, wcd9xxx_res->pm_state,
+			wcd9xxx_res->wlock_holders);
+		wcd9xxx_unlock_sleep(wcd9xxx_res);
 		return false;
 	}
-	wake_up_all(&wcd9xxx->pm_wq);
+	wake_up_all(&wcd9xxx_res->pm_wq);
 	return true;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_lock_sleep);
+EXPORT_SYMBOL(wcd9xxx_lock_sleep);
 
-void wcd9xxx_unlock_sleep(struct wcd9xxx *wcd9xxx)
+void wcd9xxx_unlock_sleep(
+	struct wcd9xxx_core_resource *wcd9xxx_res)
 {
-	mutex_lock(&wcd9xxx->pm_lock);
-	if (--wcd9xxx->wlock_holders == 0) {
+	mutex_lock(&wcd9xxx_res->pm_lock);
+	if (--wcd9xxx_res->wlock_holders == 0) {
 		pr_debug("%s: releasing wake lock pm_state %d -> %d\n",
-			 __func__, wcd9xxx->pm_state, WCD9XXX_PM_SLEEPABLE);
+			 __func__, wcd9xxx_res->pm_state, WCD9XXX_PM_SLEEPABLE);
 		/*
 		 * if wcd9xxx_lock_sleep failed, pm_state would be still
 		 * WCD9XXX_PM_ASLEEP, don't overwrite
 		 */
-		if (likely(wcd9xxx->pm_state == WCD9XXX_PM_AWAKE))
-			wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
-		pm_qos_update_request(&wcd9xxx->pm_qos_req,
+		if (likely(wcd9xxx_res->pm_state == WCD9XXX_PM_AWAKE))
+			wcd9xxx_res->pm_state = WCD9XXX_PM_SLEEPABLE;
+		pm_qos_update_request(&wcd9xxx_res->pm_qos_req,
 				PM_QOS_DEFAULT_VALUE);
 	}
-	mutex_unlock(&wcd9xxx->pm_lock);
-	wake_up_all(&wcd9xxx->pm_wq);
+	mutex_unlock(&wcd9xxx_res->pm_lock);
+	wake_up_all(&wcd9xxx_res->pm_wq);
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_unlock_sleep);
+EXPORT_SYMBOL(wcd9xxx_unlock_sleep);
 
-void wcd9xxx_nested_irq_lock(struct wcd9xxx *wcd9xxx)
+void wcd9xxx_nested_irq_lock(struct wcd9xxx_core_resource *wcd9xxx_res)
 {
-	mutex_lock(&wcd9xxx->nested_irq_lock);
+	mutex_lock(&wcd9xxx_res->nested_irq_lock);
 }
 
-void wcd9xxx_nested_irq_unlock(struct wcd9xxx *wcd9xxx)
+void wcd9xxx_nested_irq_unlock(struct wcd9xxx_core_resource *wcd9xxx_res)
 {
-	mutex_unlock(&wcd9xxx->nested_irq_lock);
+	mutex_unlock(&wcd9xxx_res->nested_irq_lock);
 }
 
-static bool wcd9xxx_is_mbhc_irq(struct wcd9xxx *wcd9xxx, int irqbit)
-{
-	if ((irqbit <= WCD9XXX_IRQ_MBHC_INSERTION) &&
-	    (irqbit >= WCD9XXX_IRQ_MBHC_REMOVAL))
-		return true;
-	else if (wcd9xxx->codec_type->id_major == TAIKO_MAJOR &&
-		 irqbit == WCD9320_IRQ_MBHC_JACK_SWITCH)
-		return true;
-	else if (wcd9xxx->codec_type->id_major == TAPAN_MAJOR &&
-		 irqbit == WCD9306_IRQ_MBHC_JACK_SWITCH)
-		return true;
-	else
-		return false;
-}
 
-static void wcd9xxx_irq_dispatch(struct wcd9xxx *wcd9xxx, int irqbit)
+static void wcd9xxx_irq_dispatch(struct wcd9xxx_core_resource *wcd9xxx_res,
+			struct intr_data *irqdata)
 {
-	if (wcd9xxx_is_mbhc_irq(wcd9xxx, irqbit)) {
-		wcd9xxx_nested_irq_lock(wcd9xxx);
-		wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_CLEAR0 +
-					   BIT_BYTE(irqbit),
-				  BYTE_BIT_MASK(irqbit));
-		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
-			wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MODE, 0x02);
-		handle_nested_irq(phyirq_to_virq(wcd9xxx, irqbit));
-		wcd9xxx_nested_irq_unlock(wcd9xxx);
-	} else {
-		wcd9xxx_nested_irq_lock(wcd9xxx);
-		handle_nested_irq(phyirq_to_virq(wcd9xxx, irqbit));
-		wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_CLEAR0 +
-					   BIT_BYTE(irqbit),
-				  BYTE_BIT_MASK(irqbit));
-		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
-			wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MODE, 0x02);
-		wcd9xxx_nested_irq_unlock(wcd9xxx);
+	int irqbit = irqdata->intr_num;
+	if (!wcd9xxx_res->codec_reg_write) {
+		pr_err("%s: codec read/write callback not defined\n",
+			   __func__);
+		return;
 	}
-}
 
-static int wcd9xxx_num_irq_regs(const struct wcd9xxx *wcd9xxx)
-{
-	return (wcd9xxx->codec_type->num_irqs / 8) +
-		((wcd9xxx->codec_type->num_irqs % 8) ? 1 : 0);
+	if (irqdata->clear_first) {
+		wcd9xxx_nested_irq_lock(wcd9xxx_res);
+		wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+				WCD9XXX_A_INTR_CLEAR0 + BIT_BYTE(irqbit),
+				BYTE_BIT_MASK(irqbit));
+
+		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+			wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+						WCD9XXX_A_INTR_MODE, 0x02);
+		handle_nested_irq(phyirq_to_virq(wcd9xxx_res, irqbit));
+		wcd9xxx_nested_irq_unlock(wcd9xxx_res);
+	} else {
+		wcd9xxx_nested_irq_lock(wcd9xxx_res);
+		handle_nested_irq(phyirq_to_virq(wcd9xxx_res, irqbit));
+		wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+				WCD9XXX_A_INTR_CLEAR0 + BIT_BYTE(irqbit),
+				BYTE_BIT_MASK(irqbit));
+		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+			wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+						WCD9XXX_A_INTR_MODE, 0x02);
+
+		wcd9xxx_nested_irq_unlock(wcd9xxx_res);
+	}
 }
 
 static irqreturn_t wcd9xxx_irq_thread(int irq, void *data)
 {
 	int ret;
 	int i;
+	struct intr_data irqdata;
 	char linebuf[128];
-	struct wcd9xxx *wcd9xxx = data;
-	int num_irq_regs = wcd9xxx_num_irq_regs(wcd9xxx);
-	u8 status[num_irq_regs], status1[num_irq_regs];
 	static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 1);
+	struct wcd9xxx_core_resource *wcd9xxx_res = data;
+	int num_irq_regs = wcd9xxx_res->num_irq_regs;
+	u8 status[num_irq_regs], status1[num_irq_regs];
 
-	if (unlikely(wcd9xxx_lock_sleep(wcd9xxx) == false)) {
-		dev_err(wcd9xxx->dev, "Failed to hold suspend\n");
+	if (unlikely(wcd9xxx_lock_sleep(wcd9xxx_res) == false)) {
+		dev_err(wcd9xxx_res->dev, "Failed to hold suspend\n");
 		return IRQ_NONE;
 	}
-	ret = wcd9xxx_bulk_read(wcd9xxx, WCD9XXX_A_INTR_STATUS0,
+
+	if (!wcd9xxx_res->codec_bulk_read) {
+		dev_err(wcd9xxx_res->dev,
+				"%s: Codec Bulk Register read callback not supplied\n",
+			   __func__);
+		goto err_disable_irq;
+	}
+
+	ret = wcd9xxx_res->codec_bulk_read(wcd9xxx_res,
+				WCD9XXX_A_INTR_STATUS0,
 				num_irq_regs, status);
+
 	if (ret < 0) {
-		dev_err(wcd9xxx->dev, "Failed to read interrupt status: %d\n",
-			ret);
-		dev_err(wcd9xxx->dev, "Disable irq %d\n", wcd9xxx->irq);
-		disable_irq_wake(wcd9xxx->irq);
-		disable_irq_nosync(wcd9xxx->irq);
-		wcd9xxx_unlock_sleep(wcd9xxx);
-		return IRQ_NONE;
+		dev_err(wcd9xxx_res->dev,
+				"Failed to read interrupt status: %d\n", ret);
+		goto err_disable_irq;
 	}
 
 	/* Apply masking */
 	for (i = 0; i < num_irq_regs; i++)
-		status[i] &= ~wcd9xxx->irq_masks_cur[i];
+		status[i] &= ~wcd9xxx_res->irq_masks_cur[i];
 
 	memcpy(status1, status, sizeof(status1));
 
 	/* Find out which interrupt was triggered and call that interrupt's
 	 * handler function
-	 */
-	if (status[BIT_BYTE(WCD9XXX_IRQ_SLIMBUS)] &
-	    BYTE_BIT_MASK(WCD9XXX_IRQ_SLIMBUS)) {
-		wcd9xxx_irq_dispatch(wcd9xxx, WCD9XXX_IRQ_SLIMBUS);
-		status1[BIT_BYTE(WCD9XXX_IRQ_SLIMBUS)] &=
-		    ~BYTE_BIT_MASK(WCD9XXX_IRQ_SLIMBUS);
-	}
-
-	/* Since codec has only one hardware irq line which is shared by
+	 *
+	 * Since codec has only one hardware irq line which is shared by
 	 * codec's different internal interrupts, so it's possible master irq
 	 * handler dispatches multiple nested irq handlers after breaking
-	 * order.  Dispatch MBHC interrupts order to follow MBHC state
-	 * machine's order */
-	for (i = WCD9XXX_IRQ_MBHC_INSERTION;
-	     i >= WCD9XXX_IRQ_MBHC_REMOVAL; i--) {
-		if (status[BIT_BYTE(i)] & BYTE_BIT_MASK(i)) {
-			wcd9xxx_irq_dispatch(wcd9xxx, i);
-			status1[BIT_BYTE(i)] &= ~BYTE_BIT_MASK(i);
-		}
-	}
-	for (i = WCD9XXX_IRQ_BG_PRECHARGE; i < wcd9xxx->codec_type->num_irqs;
-	     i++) {
-		if (status[BIT_BYTE(i)] & BYTE_BIT_MASK(i)) {
-			wcd9xxx_irq_dispatch(wcd9xxx, i);
-			status1[BIT_BYTE(i)] &= ~BYTE_BIT_MASK(i);
+	 * order.  Dispatch interrupts in the order that is maintained by
+	 * the interrupt table.
+	 */
+	for (i = 0; i < wcd9xxx_res->intr_table_size; i++) {
+		irqdata = wcd9xxx_res->intr_table[i];
+		if (status[BIT_BYTE(irqdata.intr_num)] &
+			BYTE_BIT_MASK(irqdata.intr_num)) {
+			wcd9xxx_irq_dispatch(wcd9xxx_res, &irqdata);
+			status1[BIT_BYTE(irqdata.intr_num)] &=
+					~BYTE_BIT_MASK(irqdata.intr_num);
 		}
 	}
 
@@ -319,45 +314,58 @@
 		}
 
 		memset(status, 0xff, num_irq_regs);
-		wcd9xxx_bulk_write(wcd9xxx, WCD9XXX_A_INTR_CLEAR0,
+		wcd9xxx_bulk_write(wcd9xxx_res, WCD9XXX_A_INTR_CLEAR0,
 				   num_irq_regs, status);
 		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
-			wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MODE, 0x02);
+			wcd9xxx_reg_write(wcd9xxx_res,
+					WCD9XXX_A_INTR_MODE, 0x02);
 	}
-	wcd9xxx_unlock_sleep(wcd9xxx);
+	wcd9xxx_unlock_sleep(wcd9xxx_res);
 
 	return IRQ_HANDLED;
+
+err_disable_irq:
+		dev_err(wcd9xxx_res->dev,
+				"Disable irq %d\n", wcd9xxx_res->irq);
+
+		disable_irq_wake(wcd9xxx_res->irq);
+		disable_irq_nosync(wcd9xxx_res->irq);
+		wcd9xxx_unlock_sleep(wcd9xxx_res);
+		return IRQ_NONE;
 }
 
-void wcd9xxx_free_irq(struct wcd9xxx *wcd9xxx, int irq, void *data)
+void wcd9xxx_free_irq(struct wcd9xxx_core_resource *wcd9xxx_res,
+			int irq, void *data)
 {
-	free_irq(phyirq_to_virq(wcd9xxx, irq), data);
+	free_irq(phyirq_to_virq(wcd9xxx_res, irq), data);
 }
 
-void wcd9xxx_enable_irq(struct wcd9xxx *wcd9xxx, int irq)
+void wcd9xxx_enable_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq)
 {
-	enable_irq(phyirq_to_virq(wcd9xxx, irq));
+	enable_irq(phyirq_to_virq(wcd9xxx_res, irq));
 }
 
-void wcd9xxx_disable_irq(struct wcd9xxx *wcd9xxx, int irq)
+void wcd9xxx_disable_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq)
 {
-	disable_irq_nosync(phyirq_to_virq(wcd9xxx, irq));
+	disable_irq_nosync(phyirq_to_virq(wcd9xxx_res, irq));
 }
 
-void wcd9xxx_disable_irq_sync(struct wcd9xxx *wcd9xxx, int irq)
+void wcd9xxx_disable_irq_sync(
+			struct wcd9xxx_core_resource *wcd9xxx_res, int irq)
 {
-	disable_irq(phyirq_to_virq(wcd9xxx, irq));
+	disable_irq(phyirq_to_virq(wcd9xxx_res, irq));
 }
 
-static int wcd9xxx_irq_setup_downstream_irq(struct wcd9xxx *wcd9xxx)
+static int wcd9xxx_irq_setup_downstream_irq(
+			struct wcd9xxx_core_resource *wcd9xxx_res)
 {
 	int irq, virq, ret;
 
 	pr_debug("%s: enter\n", __func__);
 
-	for (irq = 0; irq < wcd9xxx->codec_type->num_irqs; irq++) {
+	for (irq = 0; irq < wcd9xxx_res->num_irqs; irq++) {
 		/* Map OF irq */
-		virq = wcd9xxx_map_irq(wcd9xxx, irq);
+		virq = wcd9xxx_map_irq(wcd9xxx_res, irq);
 		pr_debug("%s: irq %d -> %d\n", __func__, irq, virq);
 		if (virq == NO_IRQ) {
 			pr_err("%s, No interrupt specifier for irq %d\n",
@@ -365,14 +373,14 @@
 			return NO_IRQ;
 		}
 
-		ret = irq_set_chip_data(virq, wcd9xxx);
+		ret = irq_set_chip_data(virq, wcd9xxx_res);
 		if (ret) {
 			pr_err("%s: Failed to configure irq %d (%d)\n",
 			       __func__, irq, ret);
 			return ret;
 		}
 
-		if (wcd9xxx->irq_level_high[irq])
+		if (wcd9xxx_res->irq_level_high[irq])
 			irq_set_chip_and_handler(virq, &wcd9xxx_irq_chip,
 						 handle_level_irq);
 		else
@@ -387,91 +395,100 @@
 	return 0;
 }
 
-int wcd9xxx_irq_init(struct wcd9xxx *wcd9xxx)
+int wcd9xxx_irq_init(struct wcd9xxx_core_resource *wcd9xxx_res)
 {
 	int i, ret;
-	u8 irq_level[wcd9xxx_num_irq_regs(wcd9xxx)];
+	u8 irq_level[wcd9xxx_res->num_irq_regs];
 
-	mutex_init(&wcd9xxx->irq_lock);
-	mutex_init(&wcd9xxx->nested_irq_lock);
+	mutex_init(&wcd9xxx_res->irq_lock);
+	mutex_init(&wcd9xxx_res->nested_irq_lock);
 
-	wcd9xxx->irq = wcd9xxx_irq_get_upstream_irq(wcd9xxx);
-	if (!wcd9xxx->irq) {
+	wcd9xxx_res->irq = wcd9xxx_irq_get_upstream_irq(wcd9xxx_res);
+	if (!wcd9xxx_res->irq) {
 		pr_warn("%s: irq driver is not yet initialized\n", __func__);
-		mutex_destroy(&wcd9xxx->irq_lock);
-		mutex_destroy(&wcd9xxx->nested_irq_lock);
+		mutex_destroy(&wcd9xxx_res->irq_lock);
+		mutex_destroy(&wcd9xxx_res->nested_irq_lock);
 		return -EPROBE_DEFER;
 	}
-	pr_debug("%s: probed irq %d\n", __func__, wcd9xxx->irq);
+	pr_debug("%s: probed irq %d\n", __func__, wcd9xxx_res->irq);
 
 	/* Setup downstream IRQs */
-	ret = wcd9xxx_irq_setup_downstream_irq(wcd9xxx);
+	ret = wcd9xxx_irq_setup_downstream_irq(wcd9xxx_res);
 	if (ret) {
 		pr_err("%s: Failed to setup downstream IRQ\n", __func__);
-		wcd9xxx_irq_put_upstream_irq(wcd9xxx);
-		mutex_destroy(&wcd9xxx->irq_lock);
-		mutex_destroy(&wcd9xxx->nested_irq_lock);
+		wcd9xxx_irq_put_upstream_irq(wcd9xxx_res);
+		mutex_destroy(&wcd9xxx_res->irq_lock);
+		mutex_destroy(&wcd9xxx_res->nested_irq_lock);
 		return ret;
 	}
 
 	/* All other wcd9xxx interrupts are edge triggered */
-	wcd9xxx->irq_level_high[0] = true;
+	wcd9xxx_res->irq_level_high[0] = true;
 
 	/* mask all the interrupts */
-	memset(irq_level, 0, wcd9xxx_num_irq_regs(wcd9xxx));
-	for (i = 0; i < wcd9xxx->codec_type->num_irqs; i++) {
-		wcd9xxx->irq_masks_cur[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
-		wcd9xxx->irq_masks_cache[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
+	memset(irq_level, 0, wcd9xxx_res->num_irq_regs);
+	for (i = 0; i < wcd9xxx_res->num_irqs; i++) {
+		wcd9xxx_res->irq_masks_cur[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
+		wcd9xxx_res->irq_masks_cache[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
 		irq_level[BIT_BYTE(i)] |=
-		    wcd9xxx->irq_level_high[i] << (i % BITS_PER_BYTE);
+		    wcd9xxx_res->irq_level_high[i] << (i % BITS_PER_BYTE);
 	}
 
-	for (i = 0; i < wcd9xxx_num_irq_regs(wcd9xxx); i++) {
+	if (!wcd9xxx_res->codec_reg_write) {
+		dev_err(wcd9xxx_res->dev,
+				"%s: Codec Register write callback not defined\n",
+			   __func__);
+		ret = -EINVAL;
+		goto fail_irq_init;
+	}
+
+	for (i = 0; i < wcd9xxx_res->num_irq_regs; i++) {
 		/* Initialize interrupt mask and level registers */
-		wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_LEVEL0 + i,
-				  irq_level[i]);
-		wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MASK0 + i,
-				  wcd9xxx->irq_masks_cur[i]);
+		wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+					WCD9XXX_A_INTR_LEVEL0 + i,
+					irq_level[i]);
+		wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+					WCD9XXX_A_INTR_MASK0 + i,
+					wcd9xxx_res->irq_masks_cur[i]);
 	}
 
-	ret = request_threaded_irq(wcd9xxx->irq, NULL, wcd9xxx_irq_thread,
+	ret = request_threaded_irq(wcd9xxx_res->irq, NULL, wcd9xxx_irq_thread,
 				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
-				   "wcd9xxx", wcd9xxx);
+				   "wcd9xxx", wcd9xxx_res);
 	if (ret != 0)
-		dev_err(wcd9xxx->dev, "Failed to request IRQ %d: %d\n",
-			wcd9xxx->irq, ret);
+		dev_err(wcd9xxx_res->dev, "Failed to request IRQ %d: %d\n",
+			wcd9xxx_res->irq, ret);
 	else {
-		ret = enable_irq_wake(wcd9xxx->irq);
-		if (ret == 0) {
-			ret = device_init_wakeup(wcd9xxx->dev, 1);
-			if (ret) {
-				dev_err(wcd9xxx->dev, "Failed to init device"
-					"wakeup : %d\n", ret);
-				disable_irq_wake(wcd9xxx->irq);
-			}
-		} else
-			dev_err(wcd9xxx->dev, "Failed to set wake interrupt on"
-				" IRQ %d: %d\n", wcd9xxx->irq, ret);
+		ret = enable_irq_wake(wcd9xxx_res->irq);
 		if (ret)
-			free_irq(wcd9xxx->irq, wcd9xxx);
+			dev_err(wcd9xxx_res->dev,
+				"Failed to set wake interrupt on IRQ %d: %d\n",
+				wcd9xxx_res->irq, ret);
+		if (ret)
+			free_irq(wcd9xxx_res->irq, wcd9xxx_res);
 	}
 
-	if (ret) {
-		pr_err("%s: Failed to init wcd9xxx irq\n", __func__);
-		wcd9xxx_irq_put_upstream_irq(wcd9xxx);
-		mutex_destroy(&wcd9xxx->irq_lock);
-		mutex_destroy(&wcd9xxx->nested_irq_lock);
-	}
+	if (ret)
+		goto fail_irq_init;
 
 	return ret;
+
+fail_irq_init:
+	dev_err(wcd9xxx_res->dev,
+			"%s: Failed to init wcd9xxx irq\n", __func__);
+	wcd9xxx_irq_put_upstream_irq(wcd9xxx_res);
+	mutex_destroy(&wcd9xxx_res->irq_lock);
+	mutex_destroy(&wcd9xxx_res->nested_irq_lock);
+	return ret;
 }
 
-int wcd9xxx_request_irq(struct wcd9xxx *wcd9xxx, int irq, irq_handler_t handler,
+int wcd9xxx_request_irq(struct wcd9xxx_core_resource *wcd9xxx_res,
+			int irq, irq_handler_t handler,
 			const char *name, void *data)
 {
 	int virq;
 
-	virq = phyirq_to_virq(wcd9xxx, irq);
+	virq = phyirq_to_virq(wcd9xxx_res, irq);
 
 	/*
 	 * ARM needs us to explicitly flag the IRQ as valid
@@ -487,43 +504,52 @@
 				    name, data);
 }
 
-void wcd9xxx_irq_exit(struct wcd9xxx *wcd9xxx)
+void wcd9xxx_irq_exit(struct wcd9xxx_core_resource *wcd9xxx_res)
 {
-	if (wcd9xxx->irq) {
-		disable_irq_wake(wcd9xxx->irq);
-		free_irq(wcd9xxx->irq, wcd9xxx);
+	dev_dbg(wcd9xxx_res->dev, "%s: Cleaning up irq %d\n", __func__,
+		wcd9xxx_res->irq);
+
+	if (wcd9xxx_res->irq) {
+		disable_irq_wake(wcd9xxx_res->irq);
+		free_irq(wcd9xxx_res->irq, wcd9xxx_res);
 		/* Release parent's of node */
-		wcd9xxx_irq_put_upstream_irq(wcd9xxx);
-		device_init_wakeup(wcd9xxx->dev, 0);
+		wcd9xxx_irq_put_upstream_irq(wcd9xxx_res);
 	}
-	mutex_destroy(&wcd9xxx->irq_lock);
-	mutex_destroy(&wcd9xxx->nested_irq_lock);
+	mutex_destroy(&wcd9xxx_res->irq_lock);
+	mutex_destroy(&wcd9xxx_res->nested_irq_lock);
 }
 
 #ifndef CONFIG_OF
-static int phyirq_to_virq(struct wcd9xxx *wcd9xxx, int offset)
+static int phyirq_to_virq(
+	struct wcd9xxx_core_resource *wcd9xxx_res,
+	int offset)
 {
-	return wcd9xxx->irq_base + offset;
+	return wcd9xxx_res->irq_base + offset;
 }
 
-static int virq_to_phyirq(struct wcd9xxx *wcd9xxx, int virq)
+static int virq_to_phyirq(
+	struct wcd9xxx_core_resource *wcd9xxx_res,
+	int virq)
 {
-	return virq - wcd9xxx->irq_base;
+	return virq - wcd9xxx_res->irq_base;
 }
 
-static unsigned int wcd9xxx_irq_get_upstream_irq(struct wcd9xxx *wcd9xxx)
+static unsigned int wcd9xxx_irq_get_upstream_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_res)
 {
-	return wcd9xxx->irq;
+	return wcd9xxx_res->irq;
 }
 
-static void wcd9xxx_irq_put_upstream_irq(struct wcd9xxx *wcd9xxx)
+static void wcd9xxx_irq_put_upstream_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_res)
 {
 	/* Do nothing */
 }
 
-static int wcd9xxx_map_irq(struct wcd9xxx *wcd9xxx, int irq)
+static int wcd9xxx_map_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_core_res, int irq)
 {
-	return phyirq_to_virq(wcd9xxx, irq);
+	return phyirq_to_virq(wcd9xxx_core_res, irq);
 }
 #else
 int __init wcd9xxx_irq_of_init(struct device_node *node,
@@ -555,12 +581,12 @@
 }
 
 static struct wcd9xxx_irq_drv_data *
-wcd9xxx_get_irq_drv_d(const struct wcd9xxx *wcd9xxx)
+wcd9xxx_get_irq_drv_d(const struct wcd9xxx_core_resource *wcd9xxx_res)
 {
 	struct device_node *pnode;
 	struct irq_domain *domain;
 
-	pnode = of_irq_find_parent(wcd9xxx->dev->of_node);
+	pnode = of_irq_find_parent(wcd9xxx_res->dev->of_node);
 	/* Shouldn't happen */
 	if (unlikely(!pnode))
 		return NULL;
@@ -569,11 +595,11 @@
 	return (struct wcd9xxx_irq_drv_data *)domain->host_data;
 }
 
-static int phyirq_to_virq(struct wcd9xxx *wcd9xxx, int offset)
+static int phyirq_to_virq(struct wcd9xxx_core_resource *wcd9xxx_res, int offset)
 {
 	struct wcd9xxx_irq_drv_data *data;
 
-	data = wcd9xxx_get_irq_drv_d(wcd9xxx);
+	data = wcd9xxx_get_irq_drv_d(wcd9xxx_res);
 	if (!data) {
 		pr_warn("%s: not registered to interrupt controller\n",
 			__func__);
@@ -582,21 +608,22 @@
 	return irq_linear_revmap(data->domain, offset);
 }
 
-static int virq_to_phyirq(struct wcd9xxx *wcd9xxx, int virq)
+static int virq_to_phyirq(struct wcd9xxx_core_resource *wcd9xxx_res, int virq)
 {
 	struct irq_data *irq_data = irq_get_irq_data(virq);
 	return irq_data->hwirq;
 }
 
-static unsigned int wcd9xxx_irq_get_upstream_irq(struct wcd9xxx *wcd9xxx)
+static unsigned int wcd9xxx_irq_get_upstream_irq(
+				struct wcd9xxx_core_resource *wcd9xxx_res)
 {
 	struct wcd9xxx_irq_drv_data *data;
 
 	/* Hold parent's of node */
-	if (!of_node_get(of_irq_find_parent(wcd9xxx->dev->of_node)))
+	if (!of_node_get(of_irq_find_parent(wcd9xxx_res->dev->of_node)))
 		return -EINVAL;
 
-	data = wcd9xxx_get_irq_drv_d(wcd9xxx);
+	data = wcd9xxx_get_irq_drv_d(wcd9xxx_res);
 	if (!data) {
 		pr_err("%s: interrupt controller is not registerd\n", __func__);
 		return 0;
@@ -606,15 +633,16 @@
 	return data->irq;
 }
 
-static void wcd9xxx_irq_put_upstream_irq(struct wcd9xxx *wcd9xxx)
+static void wcd9xxx_irq_put_upstream_irq(
+			struct wcd9xxx_core_resource *wcd9xxx_res)
 {
 	/* Hold parent's of node */
-	of_node_put(of_irq_find_parent(wcd9xxx->dev->of_node));
+	of_node_put(of_irq_find_parent(wcd9xxx_res->dev->of_node));
 }
 
-static int wcd9xxx_map_irq(struct wcd9xxx *wcd9xxx, int irq)
+static int wcd9xxx_map_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq)
 {
-	return of_irq_to_resource(wcd9xxx->dev->of_node, irq, NULL);
+	return of_irq_to_resource(wcd9xxx_res->dev->of_node, irq, NULL);
 }
 
 static int __devinit wcd9xxx_irq_probe(struct platform_device *pdev)
diff --git a/drivers/misc/smsc_hub.c b/drivers/misc/smsc_hub.c
index 41d9ff8..0147e66 100644
--- a/drivers/misc/smsc_hub.c
+++ b/drivers/misc/smsc_hub.c
@@ -21,14 +21,12 @@
 #include <linux/clk.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
-#include <linux/smsc3503.h>
+#include <linux/smsc_hub.h>
 #include <linux/module.h>
 #include <mach/msm_xo.h>
 
-#define SMSC3503_I2C_ADDR 0x08
-#define SMSC_GSBI_I2C_BUS_ID 10
-static const unsigned short normal_i2c[] = {
-SMSC3503_I2C_ADDR, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = {
+0, I2C_CLIENT_END };
 
 struct hsic_hub {
 	struct device *dev;
@@ -111,6 +109,22 @@
 	return i2c_smbus_write_byte_data(client, reg, (ret & ~value));
 }
 
+static int smsc4604_send_connect_cmd(struct i2c_client *client)
+{
+	u8 buf[3];
+
+	buf[0] = 0xAA;
+	buf[1] = 0x55;
+	buf[2] = 0x00;
+
+	if (i2c_master_send(client, buf, 3) != 3) {
+		dev_err(&client->dev, "%s: i2c send failed\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
 static int i2c_hsic_hub_probe(struct i2c_client *client,
 				const struct i2c_device_id *id)
 {
@@ -118,21 +132,37 @@
 				     I2C_FUNC_SMBUS_WORD_DATA))
 		return -EIO;
 
-	/* CONFIG_N bit in SP_ILOCK register has to be set before changing
-	 * other registers to change default configuration of hsic hub.
-	 */
-	hsic_hub_set_bits(client, SMSC3503_SP_ILOCK, CONFIG_N);
+	switch (smsc_hub->pdata->model_id) {
+	case SMSC3503_ID:
+		/*
+		 * CONFIG_N bit in SP_ILOCK register has to be set before
+		 * changing other registers to change default configuration
+		 * of hsic hub.
+		 */
+		hsic_hub_set_bits(client, SMSC3503_SP_ILOCK, CONFIG_N);
 
-	/* Can change default configuartion like VID,PID, strings etc
-	 * by writing new values to hsic hub registers.
-	 */
-	hsic_hub_write_word_data(client, SMSC3503_VENDORID, 0x05C6);
+		/*
+		 * Can change default configuartion like VID,PID,
+		 * strings etc by writing new values to hsic hub registers
+		 */
+		hsic_hub_write_word_data(client, SMSC3503_VENDORID, 0x05C6);
 
-	/* CONFIG_N bit in SP_ILOCK register has to be cleared for new
-	 * values in registers to be effective after writing to
-	 * other registers.
-	 */
-	hsic_hub_clear_bits(client, SMSC3503_SP_ILOCK, CONFIG_N);
+		/*
+		 * CONFIG_N bit in SP_ILOCK register has to be cleared
+		 * for new values in registers to be effective after
+		 * writing to other registers.
+		 */
+		hsic_hub_clear_bits(client, SMSC3503_SP_ILOCK, CONFIG_N);
+		break;
+	case SMSC4604_ID:
+		/*
+		 * SMSC4604 requires an I2C attach command to be issued
+		 * if I2C bus is connected
+		 */
+		return smsc4604_send_connect_cmd(client);
+	default:
+		return -EINVAL;
+	}
 
 	return 0;
 }
@@ -318,6 +348,8 @@
 struct smsc_hub_platform_data *msm_hub_dt_to_pdata(
 				struct platform_device *pdev)
 {
+	int rc;
+	u32 temp_val;
 	struct device_node *node = pdev->dev.of_node;
 	struct smsc_hub_platform_data *pdata;
 
@@ -327,6 +359,14 @@
 		return ERR_PTR(-ENOMEM);
 	}
 
+	rc = of_property_read_u32(node, "smsc,model-id", &temp_val);
+	if (rc) {
+		dev_err(&pdev->dev, "Unable to read smsc,model-id\n");
+		return ERR_PTR(rc);
+	} else {
+		pdata->model_id = temp_val;
+	}
+
 	pdata->hub_reset = of_get_named_gpio(node, "smsc,reset-gpio", 0);
 	if (pdata->hub_reset < 0)
 		return ERR_PTR(pdata->hub_reset);
@@ -399,18 +439,13 @@
 	}
 
 	gpio_direction_output(pdata->hub_reset, 0);
-	/* Hub reset should be asserted for minimum 2microsec
+	/*
+	 * Hub reset should be asserted for minimum 2microsec
 	 * before deasserting.
 	 */
 	udelay(5);
 	gpio_direction_output(pdata->hub_reset, 1);
 
-	ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to add child node, ret=%d\n", ret);
-		goto uninit_gpio;
-	}
-
 	if (!IS_ERR(smsc_hub->hub_vbus_reg)) {
 		ret = regulator_enable(smsc_hub->hub_vbus_reg);
 		if (ret) {
@@ -436,14 +471,39 @@
 	memset(&i2c_info, 0, sizeof(struct i2c_board_info));
 	strlcpy(i2c_info.type, "i2c_hsic_hub", I2C_NAME_SIZE);
 
+	/* 250ms delay is required for SMSC4604 HUB to get I2C up */
+	msleep(250);
+
+	/* Assign I2C slave address per SMSC model */
+	switch (pdata->model_id) {
+	case SMSC3503_ID:
+		normal_i2c[0] = SMSC3503_I2C_ADDR;
+		break;
+	case SMSC4604_ID:
+		normal_i2c[0] = SMSC4604_I2C_ADDR;
+		break;
+	default:
+		dev_err(&pdev->dev, "unsupported SMSC model-id\n");
+		i2c_put_adapter(i2c_adap);
+		i2c_del_driver(&hsic_hub_driver);
+		goto uninit_gpio;
+	}
+
 	smsc_hub->client = i2c_new_probed_device(i2c_adap, &i2c_info,
 						   normal_i2c, NULL);
 	i2c_put_adapter(i2c_adap);
-	if (!smsc_hub->client)
-		dev_err(&pdev->dev, "failed to connect to smsc_hub"
-			 "through I2C\n");
 
 i2c_add_fail:
+	ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to add child node, ret=%d\n", ret);
+		goto uninit_gpio;
+	}
+
+	if (!smsc_hub->client)
+		dev_err(&pdev->dev,
+			"failed to connect to smsc_hub through I2C\n");
+
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index da07947..6ef389c 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1640,6 +1640,13 @@
 		 ext_csd[EXT_CSD_CORRECTLY_PRG_SECTORS_NUM + 2] << 16 |
 		 ext_csd[EXT_CSD_CORRECTLY_PRG_SECTORS_NUM + 3] << 24);
 
+	/*
+	 * skip packed command header (1 sector) included by the counter but not
+	 * actually written to the NAND
+	 */
+	if (correctly_done >= card->ext_csd.data_sector_size)
+		correctly_done -= card->ext_csd.data_sector_size;
+
 	list_for_each_entry(prq, &mq_rq->packed_list, queuelist) {
 		if ((correctly_done - (int)blk_rq_bytes(prq)) < 0) {
 			/* prq is not successfull */
@@ -2993,11 +3000,6 @@
 	return ret;
 }
 
-#define CID_MANFID_SANDISK	0x2
-#define CID_MANFID_TOSHIBA	0x11
-#define CID_MANFID_MICRON	0x13
-#define CID_MANFID_SAMSUNG	0x15
-
 static const struct mmc_fixup blk_fixups[] =
 {
 	MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk,
diff --git a/drivers/mmc/card/mmc_block_test.c b/drivers/mmc/card/mmc_block_test.c
index e9ac2fc..39296ef 100644
--- a/drivers/mmc/card/mmc_block_test.c
+++ b/drivers/mmc/card/mmc_block_test.c
@@ -2867,6 +2867,7 @@
 {
 	int ret = 0;
 	int i;
+	int num_requests = TEST_MAX_REQUESTS / 2;
 
 	td->test_count = 0;
 	mbtd->completed_req_count = 0;
@@ -2876,15 +2877,15 @@
 		     td->wr_rd_next_req_id);
 
 	do {
-		for (i = 0; i < TEST_MAX_REQUESTS; i++) {
+		for (i = 0; i < num_requests; i++) {
 			/*
 			 * since our requests come from a pool containing 128
 			 * requests, we don't want to exhaust this quantity,
-			 * therefore we add up to TEST_MAX_REQUESTS (which
+			 * therefore we add up to num_requests (which
 			 * includes a safety margin) and then call the mmc layer
 			 * to fetch them
 			 */
-			if (td->test_count > TEST_MAX_REQUESTS)
+			if (td->test_count > num_requests)
 				break;
 
 			ret = test_iosched_add_wr_rd_test_req(0, WRITE,
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 507cd5b..8986829 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -264,7 +264,7 @@
 
 	if ((host->caps2 & MMC_CAP2_STOP_REQUEST) &&
 			host->ops->stop_request &&
-			mq->card->ext_csd.hpi)
+			mq->card->ext_csd.hpi_en)
 		blk_urgent_request(mq->queue, mmc_urgent_request);
 
 	memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
@@ -285,7 +285,9 @@
 	if (mmc_can_erase(card))
 		mmc_queue_setup_discard(mq->queue, card);
 
-	if ((mmc_can_sanitize(card) && (host->caps2 & MMC_CAP2_SANITIZE)))
+	/* Don't enable Sanitize if HPI is not supported */
+	if ((mmc_can_sanitize(card) && (host->caps2 & MMC_CAP2_SANITIZE) &&
+	    card->ext_csd.hpi_en))
 		mmc_queue_setup_sanitize(mq->queue);
 
 #ifdef CONFIG_MMC_BLOCK_BOUNCE
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index b140510..eb5d365 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -204,9 +204,11 @@
 
 	if (mmc_use_core_runtime_pm(card->host)) {
 		ret = pm_schedule_suspend(dev, card->idle_timeout);
-		if (ret) {
-			pr_err("%s: %s: pm_schedule_suspend failed: err: %d\n",
-			       mmc_hostname(host), __func__, ret);
+		if ((ret < 0) && (dev->power.runtime_error ||
+				  dev->power.disable_depth > 0)) {
+			pr_err("%s: %s: %s: pm_schedule_suspend failed: err: %d\n",
+			       mmc_hostname(host), __func__, dev_name(dev),
+			       ret);
 			return ret;
 		}
 	}
@@ -397,10 +399,11 @@
 			mmc_card_ddr_mode(card) ? "DDR " : "",
 			type);
 	} else {
-		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
+		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
 			(mmc_card_highspeed(card) ? "high speed " : ""),
+			(mmc_card_hs400(card) ? "HS400 " : ""),
 			(mmc_card_hs200(card) ? "HS200 " : ""),
 			mmc_card_ddr_mode(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 064d5ec..91efb12 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -607,7 +607,7 @@
 	int err = 0;
 	u32 status;
 
-	if (!host->ops->stop_request || !card->ext_csd.hpi) {
+	if (!host->ops->stop_request || !card->ext_csd.hpi_en) {
 		pr_warn("%s: host ops stop_request() or HPI not supported\n",
 				mmc_hostname(host));
 		return -ENOTSUPP;
@@ -731,7 +731,8 @@
 			 * notification before it receives end_io on
 			 * the current
 			 */
-			BUG_ON(pending_is_urgent == true);
+			if (pending_is_urgent)
+				continue; /* wait for done/new/urgent event */
 
 			context_info->is_urgent = false;
 			context_info->is_new_req = false;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 90d9826..e1609cf 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -58,6 +58,17 @@
 		__res & __mask;						\
 	})
 
+static const struct mmc_fixup mmc_fixups[] = {
+	/*
+	 * Certain Hynix eMMC 4.41 cards might get broken when HPI feature
+	 * is used so disable the HPI feature for such buggy cards.
+	 */
+	MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX,
+			      0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5),
+
+	END_FIXUP
+};
+
 /*
  * Given the decoded CSD structure, decode the raw CID to our CID structure.
  */
@@ -263,6 +274,12 @@
 			card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
 		hs_max_dtr = MMC_HS200_MAX_DTR;
 
+	if ((caps2 & MMC_CAP2_HS400_1_8V &&
+			card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) ||
+	    (caps2 & MMC_CAP2_HS400_1_2V &&
+			card_type & EXT_CSD_CARD_TYPE_HS400_1_2V))
+		hs_max_dtr = MMC_HS400_MAX_DTR;
+
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
 	card->ext_csd.card_type = card_type;
 }
@@ -301,6 +318,9 @@
 		goto out;
 	}
 
+	/* fixup device after ext_csd revision field is updated */
+	mmc_fixup_device(card, mmc_fixups);
+
 	card->ext_csd.raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0];
 	card->ext_csd.raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1];
 	card->ext_csd.raw_sectors[2] = ext_csd[EXT_CSD_SEC_CNT + 2];
@@ -465,8 +485,28 @@
 	}
 
 	if (card->ext_csd.rev >= 5) {
-		/* check whether the eMMC card supports BKOPS */
-		if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
+		/* check whether the eMMC card supports HPI */
+		if ((ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) &&
+				!(card->quirks & MMC_QUIRK_BROKEN_HPI)) {
+			card->ext_csd.hpi = 1;
+			if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
+				card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION;
+			else
+				card->ext_csd.hpi_cmd = MMC_SEND_STATUS;
+			/*
+			 * Indicate the maximum timeout to close
+			 * a command interrupted by HPI
+			 */
+			card->ext_csd.out_of_int_time =
+				ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10;
+		}
+
+		/*
+		 * check whether the eMMC card supports BKOPS.
+		 * If HPI is not supported then BKOPs shouldn't be enabled.
+		 */
+		if ((ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) &&
+		    card->ext_csd.hpi) {
 			card->ext_csd.bkops = 1;
 			card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN];
 			card->ext_csd.raw_bkops_status =
@@ -486,21 +526,6 @@
 		pr_info("%s: BKOPS_EN bit = %d\n",
 			mmc_hostname(card->host), card->ext_csd.bkops_en);
 
-		/* check whether the eMMC card supports HPI */
-		if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
-			card->ext_csd.hpi = 1;
-			if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
-				card->ext_csd.hpi_cmd =	MMC_STOP_TRANSMISSION;
-			else
-				card->ext_csd.hpi_cmd = MMC_SEND_STATUS;
-			/*
-			 * Indicate the maximum timeout to close
-			 * a command interrupted by HPI
-			 */
-			card->ext_csd.out_of_int_time =
-				ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10;
-		}
-
 		card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
 		card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION];
 
@@ -719,7 +744,9 @@
 				EXT_CSD_PWR_CL_52_195 :
 				EXT_CSD_PWR_CL_DDR_52_195;
 		else if (host->ios.clock <= 200000000)
-			index = EXT_CSD_PWR_CL_200_195;
+			index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+				EXT_CSD_PWR_CL_200_195 :
+				EXT_CSD_PWR_CL_DDR_200_195;
 		break;
 	case MMC_VDD_27_28:
 	case MMC_VDD_28_29:
@@ -737,7 +764,9 @@
 				EXT_CSD_PWR_CL_52_360 :
 				EXT_CSD_PWR_CL_DDR_52_360;
 		else if (host->ios.clock <= 200000000)
-			index = EXT_CSD_PWR_CL_200_360;
+			index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+				EXT_CSD_PWR_CL_200_360 :
+				EXT_CSD_PWR_CL_DDR_200_360;
 		break;
 	default:
 		pr_warning("%s: Voltage range not supported "
@@ -766,75 +795,385 @@
 }
 
 /*
- * Selects the desired buswidth and switch to the HS200 mode
- * if bus width set without error
+ * Select the correct bus width supported by both host and card
  */
-static int mmc_select_hs200(struct mmc_card *card)
+static int mmc_select_bus_width(struct mmc_card *card, int ddr, u8 *ext_csd)
 {
-	int idx, err = 0;
 	struct mmc_host *host;
-	static unsigned ext_csd_bits[] = {
-		EXT_CSD_BUS_WIDTH_4,
-		EXT_CSD_BUS_WIDTH_8,
+	static unsigned ext_csd_bits[][2] = {
+		{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
+		{ EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
+		{ EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
 	};
 	static unsigned bus_widths[] = {
-		MMC_BUS_WIDTH_4,
 		MMC_BUS_WIDTH_8,
+		MMC_BUS_WIDTH_4,
+		MMC_BUS_WIDTH_1
 	};
-
-	BUG_ON(!card);
+	unsigned idx, bus_width = 0;
+	int err = 0;
 
 	host = card->host;
 
+	if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) ||
+	    !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
+		goto out;
+
+	if (host->caps & MMC_CAP_8_BIT_DATA)
+		idx = 0;
+	else
+		idx = 1;
+
+	for (; idx < ARRAY_SIZE(bus_widths); idx++) {
+		bus_width = bus_widths[idx];
+		if (bus_width == MMC_BUS_WIDTH_1)
+			ddr = 0; /* no DDR for 1-bit width */
+		err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
+					    ext_csd);
+		if (err)
+			pr_warning("%s: power class selection to " \
+				   "bus width %d failed\n",
+				   mmc_hostname(host),
+				   1 << bus_width);
+
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_BUS_WIDTH,
+				 ext_csd_bits[idx][0],
+				 card->ext_csd.generic_cmd6_time);
+		if (!err) {
+			mmc_set_bus_width(host, bus_width);
+
+			/*
+			 * If controller can't handle bus width test,
+			 * compare ext_csd previously read in 1 bit mode
+			 * against ext_csd at new bus width
+			 */
+			if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
+				err = mmc_compare_ext_csds(card, bus_width);
+			else
+				err = mmc_bus_test(card, bus_width);
+			if (!err)
+				break;
+		}
+	}
+
+	if (!err && ddr) {
+		err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
+					    ext_csd);
+		if (err)
+			pr_warning("%s: power class selection to " \
+				   "bus width %d ddr %d failed\n",
+				   mmc_hostname(host),
+				   1 << bus_width, ddr);
+			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+					 EXT_CSD_BUS_WIDTH,
+					 ext_csd_bits[idx][1],
+					 card->ext_csd.generic_cmd6_time);
+	}
+
+out:
+	return err;
+}
+
+/*
+ * Switch to HighSpeed mode and select wide bus if supported
+ */
+static int mmc_select_hs(struct mmc_card *card, u8 *ext_csd)
+{
+	int err = 0;
+	struct mmc_host *host;
+
+	host = card->host;
+
+	if (!(host->caps & MMC_CAP_MMC_HIGHSPEED) ||
+		!(card->ext_csd.card_type & EXT_CSD_CARD_TYPE_52)) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_HS_TIMING, 1,
+				card->ext_csd.generic_cmd6_time);
+
+	if (err && err != -EBADMSG)
+		goto out;
+
+	mmc_card_set_highspeed(card);
+	mmc_set_timing(host, MMC_TIMING_MMC_HS);
+	mmc_set_clock(host, MMC_HIGH_52_MAX_DTR);
+
+	err = mmc_select_bus_width(card, 0, ext_csd);
+
+out:
+	if (err && err != -EOPNOTSUPP)
+		pr_warning("%s: Switch to HighSpeed mode failed (err:%d)\n",
+				mmc_hostname(host), err);
+	return err;
+}
+
+/*
+ * Select the desired buswidth and switch to HighSpeed DDR mode
+ * if bus width set without error
+ */
+static int mmc_select_hsddr(struct mmc_card *card, u8 *ext_csd)
+{
+	int ddr = 0, err = 0;
+	struct mmc_host *host;
+
+	host = card->host;
+
+	if (!(host->caps & MMC_CAP_HSDDR) ||
+		!(card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_52)) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	err = mmc_select_hs(card, ext_csd);
+	if (err)
+		goto out;
+	mmc_card_clr_highspeed(card);
+
+	if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
+		&& ((host->caps & (MMC_CAP_1_8V_DDR |
+		     MMC_CAP_UHS_DDR50))
+			== (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50)))
+			ddr = MMC_1_8V_DDR_MODE;
+	else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
+		&& ((host->caps & (MMC_CAP_1_2V_DDR |
+		     MMC_CAP_UHS_DDR50))
+			== (MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50)))
+			ddr = MMC_1_2V_DDR_MODE;
+
+	err = mmc_select_bus_width(card, ddr, ext_csd);
+	if (err)
+		goto out;
+
+	if (host->ios.bus_width == MMC_BUS_WIDTH_1) {
+		pr_err("%s: failed to switch to wide bus\n",
+			mmc_hostname(host));
+		goto out;
+	}
+
+	/*
+	 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
+	 * signaling.
+	 *
+	 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
+	 *
+	 * 1.8V vccq at 3.3V core voltage (vcc) is not required
+	 * in the JEDEC spec for DDR.
+	 *
+	 * Do not force change in vccq since we are obviously
+	 * working and no change to vccq is needed.
+	 *
+	 * WARNING: eMMC rules are NOT the same as SD DDR
+	 */
+	if (ddr == MMC_1_2V_DDR_MODE) {
+		err = mmc_set_signal_voltage(host,
+			MMC_SIGNAL_VOLTAGE_120, 0);
+		if (err)
+			goto out;
+	}
+	mmc_card_set_ddr_mode(card);
+	mmc_set_timing(host, MMC_TIMING_UHS_DDR50);
+	mmc_set_bus_width(host, host->ios.bus_width);
+
+out:
+	if (err && err != -EOPNOTSUPP)
+		pr_warning("%s: Switch to HighSpeed DDR mode failed (err:%d)\n",
+				mmc_hostname(host), err);
+	return err;
+}
+
+/*
+ * Select the desired buswidth and switch to HS200 mode
+ * if bus width set without error
+ */
+static int mmc_select_hs200(struct mmc_card *card, u8 *ext_csd)
+{
+	int err = 0;
+	struct mmc_host *host;
+
+	host = card->host;
+
+	if (!(host->caps2 & MMC_CAP2_HS200) ||
+		!(card->ext_csd.card_type & EXT_CSD_CARD_TYPE_HS200)) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
 	if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
 	    host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
 		if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0))
 			err = mmc_set_signal_voltage(host,
 						     MMC_SIGNAL_VOLTAGE_180, 0);
-
 	/* If fails try again during next card power cycle */
 	if (err)
-		goto err;
-
-	idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
+		goto out;
 
 	/*
-	 * Unlike SD, MMC cards dont have a configuration register to notify
-	 * supported bus width. So bus test command should be run to identify
-	 * the supported bus width or compare the ext csd values of current
-	 * bus width and ext csd values of 1 bit mode read earlier.
+	 * For devices supporting HS200 mode, the bus width has
+	 * to be set before executing the tuning function. If
+	 * set before tuning, then device will respond with CRC
+	 * errors for responses on CMD line. So for HS200 the
+	 * sequence will be
+	 * 1. set bus width 4bit / 8 bit (1 bit not supported)
+	 * 2. switch to HS200 mode
+	 * 3. set the clock to > 52Mhz <=200MHz and
+	 * 4. execute tuning for HS200
 	 */
-	for (; idx >= 0; idx--) {
+	err = mmc_select_bus_width(card, 0, ext_csd);
+	if (err) {
+		pr_err("%s: select bus width failed\n",
+			mmc_hostname(host));
+		goto out;
+	}
 
-		/*
-		 * Host is capable of 8bit transfer, then switch
-		 * the device to work in 8bit transfer mode. If the
-		 * mmc switch command returns error then switch to
-		 * 4bit transfer mode. On success set the corresponding
-		 * bus width on the host.
-		 */
-		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				 EXT_CSD_BUS_WIDTH,
-				 ext_csd_bits[idx],
-				 card->ext_csd.generic_cmd6_time);
-		if (err)
-			continue;
-
-		mmc_set_bus_width(card->host, bus_widths[idx]);
-
-		if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-			err = mmc_compare_ext_csds(card, bus_widths[idx]);
-		else
-			err = mmc_bus_test(card, bus_widths[idx]);
-		if (!err)
-			break;
+	if (host->ios.bus_width == MMC_BUS_WIDTH_1) {
+		pr_err("%s: failed to switch to wide bus\n",
+			mmc_hostname(host));
+		goto out;
 	}
 
 	/* switch to HS200 mode if bus width set successfully */
-	if (!err)
-		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				 EXT_CSD_HS_TIMING, 2, 0);
-err:
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_HS_TIMING, 2, 0);
+
+	if (err && err != -EBADMSG) {
+		pr_err("%s: HS200 switch failed\n",
+			mmc_hostname(host));
+		goto out;
+	}
+
+	/*
+	 * When HS200 activation is performed as part of HS400 selection
+	 * set the timing appropriately
+	 */
+	if (mmc_card_hs400(card))
+		mmc_set_timing(host, MMC_TIMING_MMC_HS400);
+	else
+		mmc_set_timing(host, MMC_TIMING_MMC_HS200);
+
+	mmc_set_clock(host, MMC_HS200_MAX_DTR);
+
+	if (host->ops->execute_tuning) {
+		mmc_host_clk_hold(host);
+		err = host->ops->execute_tuning(host,
+				MMC_SEND_TUNING_BLOCK_HS200);
+		mmc_host_clk_release(host);
+	}
+	if (err) {
+		pr_warning("%s: tuning execution failed\n",
+			   mmc_hostname(host));
+		goto out;
+	}
+	mmc_card_set_hs200(card);
+
+out:
+	if (err && err != -EOPNOTSUPP)
+		pr_warning("%s: Switch to HS200 mode failed (err:%d)\n",
+				mmc_hostname(host), err);
+	return err;
+}
+
+static int mmc_select_hs400(struct mmc_card *card, u8 *ext_csd)
+{
+	int err = 0;
+	struct mmc_host *host;
+
+	host = card->host;
+
+	if (!(host->caps2 & MMC_CAP2_HS400) ||
+		!(card->ext_csd.card_type & EXT_CSD_CARD_TYPE_HS400)) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	/*
+	 * eMMC5.0 spec doesn't allow switching to HS400 mode from
+	 * HS200 mode directly. Hence follow these steps to switch
+	 * to HS400 mode:
+	 *	Enable HS200 mode
+	 *	Enable HighSpeed mode (The clk should be low enough
+	 *		to enable HighSpeed mode) - HS_TIMING is 0x1
+	 *	Enable DDR mode (Set bus width to 8-bit DDR)
+	 *	Enable HS400 mode (Set HS_TIMING to 0x3 and change
+	 *		frequency to <= 200MHz)
+	 *	Perform tuning if required
+	 */
+	mmc_card_set_hs400(card);
+	err = mmc_select_hs200(card, ext_csd);
+	if (err)
+		goto out;
+	mmc_card_clr_hs200(card);
+
+	if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_HS400_1_2V)
+	    && (host->caps2 & MMC_CAP2_HS400_1_2V))
+		if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0))
+				err = mmc_set_signal_voltage(host,
+						MMC_SIGNAL_VOLTAGE_180, 0);
+	/* If fails try again during next card power cycle */
+	if (err)
+		goto out;
+
+	/*
+	 * Lower the clock and adjust the timing to be able
+	 * to switch to HighSpeed mode
+	 */
+	mmc_set_timing(host, MMC_TIMING_LEGACY);
+	mmc_set_clock(host, MMC_HIGH_26_MAX_DTR);
+
+	err = mmc_select_hs(card, ext_csd);
+	if (err)
+		goto out;
+	mmc_card_clr_highspeed(card);
+
+	/* Switch to 8-bit DDR mode */
+	err = mmc_select_hsddr(card, ext_csd);
+	if (err)
+		goto out;
+	mmc_card_clr_ddr_mode(card);
+
+	/*
+	 * In HS400 mode only DDR 8-bit bus width is allowed.
+	 */
+	if (host->ios.bus_width != MMC_BUS_WIDTH_8) {
+		pr_err("%s: failed to switch to 8-bit bus width\n",
+			mmc_hostname(host));
+		goto out;
+	}
+
+	/* Switch to HS400 mode if bus width set successfully */
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_HS_TIMING, 3, 0);
+	if (err && err != -EBADMSG) {
+		pr_err("%s: Setting HS_TIMING to HS400 failed (err:%d)\n",
+			mmc_hostname(host), err);
+		goto out;
+	}
+
+	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
+	mmc_set_clock(host, MMC_HS400_MAX_DTR);
+
+	if (host->ops->execute_tuning) {
+		mmc_host_clk_hold(host);
+		err = host->ops->execute_tuning(host,
+				MMC_SEND_TUNING_BLOCK_HS400);
+		mmc_host_clk_release(host);
+	}
+	if (err) {
+		pr_err("%s: tuning execution failed (err:%d)\n",
+			   mmc_hostname(host), err);
+		goto out;
+	}
+	mmc_card_set_hs400(card);
+
+out:
+	if (err && err != -EOPNOTSUPP) {
+		pr_warning("%s: Switch to HS400 mode failed (err:%d)\n",
+				mmc_hostname(host), err);
+		mmc_card_clr_hs400(card);
+	}
 	return err;
 }
 
@@ -869,7 +1208,8 @@
 	}
 
 	if (mmc_card_highspeed(card) || mmc_card_hs200(card)
-			|| mmc_card_ddr_mode(card)) {
+			|| mmc_card_ddr_mode(card)
+			|| mmc_card_hs400(card)) {
 		if (*freq > card->ext_csd.hs_max_dtr)
 			*freq = card->ext_csd.hs_max_dtr;
 	} else if (*freq > card->csd.max_dtr) {
@@ -881,7 +1221,8 @@
 
 	mmc_set_clock(host, (unsigned int) (*freq));
 
-	if (mmc_card_hs200(card) && card->host->ops->execute_tuning) {
+	if ((mmc_card_hs400(card) || mmc_card_hs200(card))
+		&& card->host->ops->execute_tuning) {
 		/*
 		 * We try to probe host driver for tuning for any
 		 * frequency, it is host driver responsibility to
@@ -919,6 +1260,35 @@
 }
 
 /*
+ * Activate highest bus speed mode supported by both host and card.
+ * On failure activate the next supported highest bus speed mode.
+ */
+static int mmc_select_bus_speed(struct mmc_card *card, u8 *ext_csd)
+{
+	int err = 0;
+
+	BUG_ON(!card);
+
+	if (!mmc_select_hs400(card, ext_csd))
+		goto out;
+	if (!mmc_select_hs200(card, ext_csd))
+		goto out;
+	if (!mmc_select_hsddr(card, ext_csd))
+		goto out;
+	if (!mmc_select_hs(card, ext_csd))
+		goto out;
+
+	/*
+	 * Select the default speed and wide bus if supported
+	 */
+	mmc_set_clock(card->host, card->csd.max_dtr);
+	err = mmc_select_bus_width(card, 0, ext_csd);
+
+out:
+	return err;
+}
+
+/*
  * Handle the detection and initialisation of a card.
  *
  * In the case of a resume, "oldcard" will contain the card
@@ -928,9 +1298,8 @@
 	struct mmc_card *oldcard)
 {
 	struct mmc_card *card;
-	int err, ddr = 0;
+	int err = 0;
 	u32 cid[4];
-	unsigned int max_dtr;
 	u32 rocr;
 	u8 *ext_csd = NULL;
 
@@ -1132,209 +1501,11 @@
 	}
 
 	/*
-	 * Activate high speed (if supported)
+	 * Activate highest bus speed mode supported by both host and card.
 	 */
-	if (card->ext_csd.hs_max_dtr != 0) {
-		err = 0;
-		if (card->ext_csd.hs_max_dtr > 52000000 &&
-		    host->caps2 & MMC_CAP2_HS200)
-			err = mmc_select_hs200(card);
-		else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_HS_TIMING, 1,
-					 card->ext_csd.generic_cmd6_time);
-
-		if (err && err != -EBADMSG)
-			goto free_card;
-
-		if (err) {
-			pr_warning("%s: switch to highspeed failed\n",
-			       mmc_hostname(card->host));
-			err = 0;
-		} else {
-			if (card->ext_csd.hs_max_dtr > 52000000 &&
-			    host->caps2 & MMC_CAP2_HS200) {
-				mmc_card_set_hs200(card);
-				mmc_set_timing(card->host,
-					       MMC_TIMING_MMC_HS200);
-			} else {
-				mmc_card_set_highspeed(card);
-				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
-			}
-		}
-	}
-
-	/*
-	 * Compute bus speed.
-	 */
-	max_dtr = (unsigned int)-1;
-
-	if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
-		if (max_dtr > card->ext_csd.hs_max_dtr)
-			max_dtr = card->ext_csd.hs_max_dtr;
-	} else if (max_dtr > card->csd.max_dtr) {
-		max_dtr = card->csd.max_dtr;
-	}
-
-	mmc_set_clock(host, max_dtr);
-
-	/*
-	 * Indicate DDR mode (if supported).
-	 */
-	if (mmc_card_highspeed(card)) {
-		if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
-			&& ((host->caps & (MMC_CAP_1_8V_DDR |
-			     MMC_CAP_UHS_DDR50))
-				== (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50)))
-				ddr = MMC_1_8V_DDR_MODE;
-		else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
-			&& ((host->caps & (MMC_CAP_1_2V_DDR |
-			     MMC_CAP_UHS_DDR50))
-				== (MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50)))
-				ddr = MMC_1_2V_DDR_MODE;
-	}
-
-	/*
-	 * Indicate HS200 SDR mode (if supported).
-	 */
-	if (mmc_card_hs200(card)) {
-		u32 ext_csd_bits;
-		u32 bus_width = card->host->ios.bus_width;
-
-		/*
-		 * For devices supporting HS200 mode, the bus width has
-		 * to be set before executing the tuning function. If
-		 * set before tuning, then device will respond with CRC
-		 * errors for responses on CMD line. So for HS200 the
-		 * sequence will be
-		 * 1. set bus width 4bit / 8 bit (1 bit not supported)
-		 * 2. switch to HS200 mode
-		 * 3. set the clock to > 52Mhz <=200MHz and
-		 * 4. execute tuning for HS200
-		 */
-		if ((host->caps2 & MMC_CAP2_HS200) &&
-		    card->host->ops->execute_tuning) {
-			mmc_host_clk_hold(card->host);
-			err = card->host->ops->execute_tuning(card->host,
-				MMC_SEND_TUNING_BLOCK_HS200);
-			mmc_host_clk_release(card->host);
-		}
-		if (err) {
-			pr_warning("%s: tuning execution failed\n",
-				   mmc_hostname(card->host));
-			goto err;
-		}
-
-		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
-				EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-		err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
-		if (err)
-			pr_warning("%s: power class selection to bus width %d"
-				   " failed\n", mmc_hostname(card->host),
-				   1 << bus_width);
-	}
-
-	/*
-	 * Activate wide bus and DDR (if supported).
-	 */
-	if (!mmc_card_hs200(card) &&
-	    (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
-	    (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
-		static unsigned ext_csd_bits[][2] = {
-			{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
-			{ EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
-			{ EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
-		};
-		static unsigned bus_widths[] = {
-			MMC_BUS_WIDTH_8,
-			MMC_BUS_WIDTH_4,
-			MMC_BUS_WIDTH_1
-		};
-		unsigned idx, bus_width = 0;
-
-		if (host->caps & MMC_CAP_8_BIT_DATA)
-			idx = 0;
-		else
-			idx = 1;
-		for (; idx < ARRAY_SIZE(bus_widths); idx++) {
-			bus_width = bus_widths[idx];
-			if (bus_width == MMC_BUS_WIDTH_1)
-				ddr = 0; /* no DDR for 1-bit width */
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
-						    ext_csd);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width);
-
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][0],
-					 card->ext_csd.generic_cmd6_time);
-			if (!err) {
-				mmc_set_bus_width(card->host, bus_width);
-
-				/*
-				 * If controller can't handle bus width test,
-				 * compare ext_csd previously read in 1 bit mode
-				 * against ext_csd at new bus width
-				 */
-				if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-					err = mmc_compare_ext_csds(card,
-						bus_width);
-				else
-					err = mmc_bus_test(card, bus_width);
-				if (!err)
-					break;
-			}
-		}
-
-		if (!err && ddr) {
-			err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
-						    ext_csd);
-			if (err)
-				pr_warning("%s: power class selection to "
-					   "bus width %d ddr %d failed\n",
-					   mmc_hostname(card->host),
-					   1 << bus_width, ddr);
-
-			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-					 EXT_CSD_BUS_WIDTH,
-					 ext_csd_bits[idx][1],
-					 card->ext_csd.generic_cmd6_time);
-		}
-		if (err) {
-			pr_warning("%s: switch to bus width %d ddr %d "
-				"failed\n", mmc_hostname(card->host),
-				1 << bus_width, ddr);
-			goto free_card;
-		} else if (ddr) {
-			/*
-			 * eMMC cards can support 3.3V to 1.2V i/o (vccq)
-			 * signaling.
-			 *
-			 * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
-			 *
-			 * 1.8V vccq at 3.3V core voltage (vcc) is not required
-			 * in the JEDEC spec for DDR.
-			 *
-			 * Do not force change in vccq since we are obviously
-			 * working and no change to vccq is needed.
-			 *
-			 * WARNING: eMMC rules are NOT the same as SD DDR
-			 */
-			if (ddr == MMC_1_2V_DDR_MODE) {
-				err = mmc_set_signal_voltage(host,
-					MMC_SIGNAL_VOLTAGE_120, 0);
-				if (err)
-					goto err;
-			}
-			mmc_card_set_ddr_mode(card);
-			mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
-			mmc_set_bus_width(card->host, bus_width);
-		}
-	}
+	err = mmc_select_bus_speed(card, ext_csd);
+	if (err)
+		goto free_card;
 
 	/*
 	 * Enable HPI feature (if supported)
@@ -1356,9 +1527,10 @@
 	/*
 	 * If cache size is higher than 0, this indicates
 	 * the existence of cache and it can be turned on.
+	 * If HPI is not supported then cache shouldn't be enabled.
 	 */
 	if ((host->caps2 & MMC_CAP2_CACHE_CTRL) &&
-			card->ext_csd.cache_size > 0) {
+	    (card->ext_csd.cache_size > 0) && card->ext_csd.hpi_en) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 				EXT_CSD_CACHE_CTRL, 1,
 				card->ext_csd.generic_cmd6_time);
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 164c418..32e126b 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -598,7 +598,7 @@
 	unsigned int opcode;
 	int err;
 
-	if (!card->ext_csd.hpi) {
+	if (!card->ext_csd.hpi_en) {
 		pr_warning("%s: Card didn't support HPI command\n",
 			   mmc_hostname(card->host));
 		return -EINVAL;
diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c
index 59f0340..4407d91 100644
--- a/drivers/mmc/core/quirks.c
+++ b/drivers/mmc/core/quirks.c
@@ -107,6 +107,8 @@
 		    (f->name == CID_NAME_ANY ||
 		     !strncmp(f->name, card->cid.prod_name,
 			      sizeof(card->cid.prod_name))) &&
+		    (f->ext_csd_rev == EXT_CSD_REV_ANY ||
+		     f->ext_csd_rev == card->ext_csd.rev) &&
 		    (f->cis_vendor == card->cis.vendor ||
 		     f->cis_vendor == (u16) SDIO_ANY_ID) &&
 		    (f->cis_device == card->cis.device ||
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 33dfad2..a7ce6ae 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -45,6 +45,7 @@
 #define SDHCI_VER_100		0x2B
 #define CORE_HC_MODE		0x78
 #define HC_MODE_EN		0x1
+#define FF_CLK_SW_RST_DIS	(1 << 13)
 
 #define CORE_POWER		0x0
 #define CORE_SW_RST		(1 << 7)
@@ -67,20 +68,57 @@
 #define INT_MASK		0xF
 #define MAX_PHASES		16
 
-#define CORE_DLL_LOCK		(1 << 7)
+#define CORE_DLL_CONFIG		0x100
+#define CORE_CMD_DAT_TRACK_SEL	(1 << 0)
 #define CORE_DLL_EN		(1 << 16)
 #define CORE_CDR_EN		(1 << 17)
 #define CORE_CK_OUT_EN		(1 << 18)
 #define CORE_CDR_EXT_EN		(1 << 19)
 #define CORE_DLL_PDN		(1 << 29)
 #define CORE_DLL_RST		(1 << 30)
-#define CORE_DLL_CONFIG		0x100
-#define CORE_DLL_TEST_CTL	0x104
+
 #define CORE_DLL_STATUS		0x108
+#define CORE_DLL_LOCK		(1 << 7)
 
 #define CORE_VENDOR_SPEC	0x10C
 #define CORE_CLK_PWRSAVE	(1 << 1)
+#define CORE_HC_MCLK_SEL_DFLT	(2 << 8)
+#define CORE_HC_MCLK_SEL_HS400	(3 << 8)
+#define CORE_HC_MCLK_SEL_MASK	(3 << 8)
 #define CORE_IO_PAD_PWR_SWITCH	(1 << 16)
+#define CORE_HC_SELECT_IN_EN	(1 << 18)
+#define CORE_HC_SELECT_IN_HS400	(6 << 19)
+#define CORE_HC_SELECT_IN_MASK	(7 << 19)
+
+#define CORE_VENDOR_SPEC_ADMA_ERR_ADDR0	0x114
+#define CORE_VENDOR_SPEC_ADMA_ERR_ADDR1	0x118
+
+#define CORE_CSR_CDC_CTLR_CFG0		0x130
+#define CORE_SW_TRIG_FULL_CALIB		(1 << 16)
+#define CORE_HW_AUTOCAL_ENA		(1 << 17)
+
+#define CORE_CSR_CDC_CTLR_CFG1		0x134
+#define CORE_CSR_CDC_CAL_TIMER_CFG0	0x138
+#define CORE_TIMER_ENA			(1 << 16)
+
+#define CORE_CSR_CDC_CAL_TIMER_CFG1	0x13C
+#define CORE_CSR_CDC_REFCOUNT_CFG	0x140
+#define CORE_CSR_CDC_COARSE_CAL_CFG	0x144
+#define CORE_CDC_OFFSET_CFG		0x14C
+#define CORE_CSR_CDC_DELAY_CFG		0x150
+#define CORE_CDC_SLAVE_DDA_CFG		0x160
+#define CORE_CSR_CDC_STATUS0		0x164
+#define CORE_CALIBRATION_DONE		(1 << 0)
+
+#define CORE_CDC_ERROR_CODE_MASK	0x7000000
+
+#define CORE_CSR_CDC_GEN_CFG		0x178
+#define CORE_CDC_SWITCH_BYPASS_OFF	(1 << 0)
+#define CORE_CDC_SWITCH_RC_EN		(1 << 1)
+
+#define CORE_DDR_200_CFG		0x184
+#define CORE_CDC_T4_DLY_SEL		(1 << 0)
+#define CORE_START_CDC_TRAFFIC		(1 << 6)
 
 #define CORE_MCI_DATA_CTRL	0x2C
 #define CORE_MCI_DPSM_ENABLE	(1 << 0)
@@ -114,6 +152,10 @@
 #define SDHCI_MSM_MAX_SEGMENTS  (1 << 13)
 #define SDHCI_MSM_MMC_CLK_GATE_DELAY	200 /* msecs */
 
+#define CORE_FREQ_100MHZ	(100 * 1000 * 1000)
+
+#define INVALID_TUNING_PHASE	-1
+
 static const u32 tuning_block_64[] = {
 	0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
 	0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
@@ -260,6 +302,8 @@
 	struct clk	 *clk;     /* main SD/MMC bus clock */
 	struct clk	 *pclk;    /* SDHC peripheral bus clock */
 	struct clk	 *bus_clk; /* SDHC bus voter clock */
+	struct clk	 *ff_clk; /* CDC calibration fixed feedback clock */
+	struct clk	 *sleep_clk; /* CDC calibration sleep clock */
 	atomic_t clks_on; /* Set if clocks are enabled */
 	struct sdhci_msm_pltfm_data *pdata;
 	struct mmc_host  *mmc;
@@ -270,6 +314,9 @@
 	struct sdhci_msm_bus_vote msm_bus_vote;
 	struct device_attribute	polling;
 	u32 clk_rate; /* Keeps track of current clock rate that is set */
+	bool tuning_done;
+	bool calibration_done;
+	u8 saved_tuning_phase;
 };
 
 enum vdd_io_level {
@@ -373,8 +420,8 @@
  * Find out the greatest range of consecuitive selected
  * DLL clock output phases that can be used as sampling
  * setting for SD3.0 UHS-I card read operation (in SDR104
- * timing mode) or for eMMC4.5 card read operation (in HS200
- * timing mode).
+ * timing mode) or for eMMC4.5 card read operation (in
+ * HS400/HS200 timing mode).
  * Select the 3/4 of the range and configure the DLL with the
  * selected DLL clock output phase.
  */
@@ -595,6 +642,137 @@
 	return rc;
 }
 
+static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
+{
+	u32 wait_cnt;
+	int ret = 0;
+	int cdc_err = 0;
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+
+	pr_debug("%s: Enter %s\n", mmc_hostname(host->mmc), __func__);
+
+	/*
+	 * Retuning in HS400 (DDR mode) will fail, just reset the
+	 * tuning block and restore the saved tuning phase.
+	 */
+	ret = msm_init_cm_dll(host);
+	if (ret)
+		goto out;
+
+	/* Set the selected phase in delay line hw block */
+	ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase);
+	if (ret)
+		goto out;
+
+	/* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+			| CORE_CMD_DAT_TRACK_SEL),
+			host->ioaddr + CORE_DLL_CONFIG);
+
+	/* Write 0 to CDC_T4_DLY_SEL field in VENDOR_SPEC_DDR200_CFG */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DDR_200_CFG)
+			& ~CORE_CDC_T4_DLY_SEL),
+			host->ioaddr + CORE_DDR_200_CFG);
+
+	/* Write 0 to CDC_SWITCH_BYPASS_OFF field in CORE_CSR_CDC_GEN_CFG */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_CSR_CDC_GEN_CFG)
+			& ~CORE_CDC_SWITCH_BYPASS_OFF),
+			host->ioaddr + CORE_CSR_CDC_GEN_CFG);
+
+	/* Write 1 to CDC_SWITCH_RC_EN field in CORE_CSR_CDC_GEN_CFG */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_CSR_CDC_GEN_CFG)
+			| CORE_CDC_SWITCH_RC_EN),
+			host->ioaddr + CORE_CSR_CDC_GEN_CFG);
+
+	/* Write 0 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DDR_200_CFG)
+			& ~CORE_START_CDC_TRAFFIC),
+			host->ioaddr + CORE_DDR_200_CFG);
+
+	/*
+	 * Perform CDC Register Initialization Sequence
+	 *
+	 * CORE_CSR_CDC_CTLR_CFG0	0x11800EC
+	 * CORE_CSR_CDC_CTLR_CFG1	0x3011111
+	 * CORE_CSR_CDC_CAL_TIMER_CFG0	0x1201000
+	 * CORE_CSR_CDC_CAL_TIMER_CFG1	0x4
+	 * CORE_CSR_CDC_REFCOUNT_CFG	0xCB732020
+	 * CORE_CSR_CDC_COARSE_CAL_CFG	0xB19
+	 * CORE_CSR_CDC_DELAY_CFG	0x3AC
+	 * CORE_CDC_OFFSET_CFG		0x0
+	 * CORE_CDC_SLAVE_DDA_CFG	0x16334
+	 */
+
+	writel_relaxed(0x11800EC, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
+	writel_relaxed(0x3011111, host->ioaddr + CORE_CSR_CDC_CTLR_CFG1);
+	writel_relaxed(0x1201000, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0);
+	writel_relaxed(0x4, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG1);
+	writel_relaxed(0xCB732020, host->ioaddr + CORE_CSR_CDC_REFCOUNT_CFG);
+	writel_relaxed(0xB19, host->ioaddr + CORE_CSR_CDC_COARSE_CAL_CFG);
+	writel_relaxed(0x3AC, host->ioaddr + CORE_CSR_CDC_DELAY_CFG);
+	writel_relaxed(0x0, host->ioaddr + CORE_CDC_OFFSET_CFG);
+	writel_relaxed(0x16334, host->ioaddr + CORE_CDC_SLAVE_DDA_CFG);
+
+	/* CDC HW Calibration */
+
+	/* Write 1 to SW_TRIG_FULL_CALIB field in CORE_CSR_CDC_CTLR_CFG0 */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0)
+			| CORE_SW_TRIG_FULL_CALIB),
+			host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
+
+	/* Write 0 to SW_TRIG_FULL_CALIB field in CORE_CSR_CDC_CTLR_CFG0 */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0)
+			& ~CORE_SW_TRIG_FULL_CALIB),
+			host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
+
+	/* Write 1 to HW_AUTOCAL_ENA field in CORE_CSR_CDC_CTLR_CFG0 */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_CSR_CDC_CTLR_CFG0)
+			| CORE_HW_AUTOCAL_ENA),
+			host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
+
+	/* Write 1 to TIMER_ENA field in CORE_CSR_CDC_CAL_TIMER_CFG0 */
+	writel_relaxed((readl_relaxed(host->ioaddr +
+			CORE_CSR_CDC_CAL_TIMER_CFG0) | CORE_TIMER_ENA),
+			host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG0);
+
+	mb();
+
+	/* Poll on CALIBRATION_DONE field in CORE_CSR_CDC_STATUS0 to be 1 */
+	wait_cnt = 50;
+	while (!(readl_relaxed(host->ioaddr + CORE_CSR_CDC_STATUS0)
+			& CORE_CALIBRATION_DONE)) {
+		/* max. wait for 50us sec for CALIBRATION_DONE bit to be set */
+		if (--wait_cnt == 0) {
+			pr_err("%s: %s: CDC Calibration was not completed\n",
+				mmc_hostname(host->mmc), __func__);
+			ret = -ETIMEDOUT;
+			goto out;
+		}
+		/* wait for 1us before polling again */
+		udelay(1);
+	}
+
+	/* Verify CDC_ERROR_CODE field in CORE_CSR_CDC_STATUS0 is 0 */
+	cdc_err = readl_relaxed(host->ioaddr + CORE_CSR_CDC_STATUS0)
+			& CORE_CDC_ERROR_CODE_MASK;
+	if (cdc_err) {
+		pr_err("%s: %s: CDC Error Code %d\n",
+			mmc_hostname(host->mmc), __func__, cdc_err);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* Write 1 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
+	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DDR_200_CFG)
+			| CORE_START_CDC_TRAFFIC),
+			host->ioaddr + CORE_DDR_200_CFG);
+out:
+	pr_debug("%s: Exit %s, ret:%d\n", mmc_hostname(host->mmc),
+			__func__, ret);
+	return ret;
+}
+
 int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
 {
 	unsigned long flags;
@@ -605,20 +783,36 @@
 	int rc;
 	struct mmc_host *mmc = host->mmc;
 	struct mmc_ios	ios = host->mmc->ios;
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
 
 	/*
-	 * Tuning is required for SDR104 and HS200 cards and if clock frequency
-	 * is greater than 100MHz in these modes.
+	 * Tuning is required for SDR104, HS200 and HS400 cards and
+	 * if clock frequency is greater than 100MHz in these modes.
 	 */
-	if (host->clock <= (100 * 1000 * 1000) ||
-		!(ios.timing == MMC_TIMING_MMC_HS200 ||
-		ios.timing == MMC_TIMING_UHS_SDR104))
+	if (host->clock <= CORE_FREQ_100MHZ ||
+		!((ios.timing == MMC_TIMING_MMC_HS400) ||
+		(ios.timing == MMC_TIMING_MMC_HS200) ||
+		(ios.timing == MMC_TIMING_UHS_SDR104)))
 		return 0;
 
 	pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
+
+	/* CDCLP533 HW calibration is only required for HS400 mode*/
+	if (msm_host->tuning_done && !msm_host->calibration_done &&
+		(mmc->ios.timing == MMC_TIMING_MMC_HS400)) {
+		rc = sdhci_msm_cdclp533_calibration(host);
+		spin_lock_irqsave(&host->lock, flags);
+		if (!rc)
+			msm_host->calibration_done = true;
+		spin_unlock_irqrestore(&host->lock, flags);
+		goto out;
+	}
+
 	spin_lock_irqsave(&host->lock, flags);
 
-	if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
+	if (((opcode == MMC_SEND_TUNING_BLOCK_HS400) ||
+		(opcode == MMC_SEND_TUNING_BLOCK_HS200)) &&
 		(mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
 		tuning_block_pattern = tuning_block_128;
 		size = sizeof(tuning_block_128);
@@ -690,6 +884,7 @@
 		rc = msm_config_cm_dll_phase(host, phase);
 		if (rc)
 			goto kfree;
+		msm_host->saved_tuning_phase = phase;
 		pr_debug("%s: %s: finally setting the tuning phase to %d\n",
 				mmc_hostname(mmc), __func__, phase);
 	} else {
@@ -704,7 +899,11 @@
 kfree:
 	kfree(data_buf);
 out:
-	pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
+	spin_lock_irqsave(&host->lock, flags);
+	if (!rc)
+		msm_host->tuning_done = true;
+	spin_unlock_irqrestore(&host->lock, flags);
+	pr_debug("%s: Exit %s, err(%d)\n", mmc_hostname(mmc), __func__, rc);
 	return rc;
 }
 
@@ -803,7 +1002,7 @@
 		goto out;
 	}
 	sz = *len = *len / sizeof(*arr);
-	if (sz <= 0 || (size > 0 && (sz != size))) {
+	if (sz <= 0 || (size > 0 && (sz > size))) {
 		dev_err(dev, "%s invalid size\n", prop_name);
 		ret = -EINVAL;
 		goto out;
@@ -929,9 +1128,9 @@
 		ret = -ENOMEM;
 		goto out;
 	}
-	pull_data->size = 3; /* array size for clk, cmd, data */
+	pull_data->size = 4; /* array size for clk, cmd, data and rclk */
 
-	/* Allocate on, off configs for clk, cmd, data */
+	/* Allocate on, off configs for clk, cmd, data and rclk */
 	pull = devm_kzalloc(dev, 2 * pull_data->size *\
 			sizeof(struct sdhci_msm_pad_pull), GFP_KERNEL);
 	if (!pull) {
@@ -1214,7 +1413,11 @@
 		if (!name)
 			continue;
 
-		if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
+		if (!strncmp(name, "HS400_1p8v", sizeof("HS400_1p8v")))
+			pdata->caps2 |= MMC_CAP2_HS400_1_8V;
+		else if (!strncmp(name, "HS400_1p2v", sizeof("HS400_1p2v")))
+			pdata->caps2 |= MMC_CAP2_HS400_1_2V;
+		else if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
 			pdata->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
 		else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
 			pdata->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
@@ -2044,6 +2247,22 @@
 				mmc_hostname(host->mmc), __func__, rc);
 			goto disable_pclk;
 		}
+		if (!IS_ERR(msm_host->ff_clk)) {
+			rc = clk_prepare_enable(msm_host->ff_clk);
+			if (rc) {
+				pr_err("%s: %s: failed to enable the ff_clk with error %d\n",
+					mmc_hostname(host->mmc), __func__, rc);
+				goto disable_clk;
+			}
+		}
+		if (!IS_ERR(msm_host->sleep_clk)) {
+			rc = clk_prepare_enable(msm_host->sleep_clk);
+			if (rc) {
+				pr_err("%s: %s: failed to enable the sleep_clk with error %d\n",
+					mmc_hostname(host->mmc), __func__, rc);
+				goto disable_ff_clk;
+			}
+		}
 		mb();
 
 	} else if (!enable && atomic_read(&msm_host->clks_on)) {
@@ -2051,6 +2270,10 @@
 				mmc_hostname(host->mmc));
 		sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
 		mb();
+		if (!IS_ERR_OR_NULL(msm_host->sleep_clk))
+			clk_disable_unprepare(msm_host->sleep_clk);
+		if (!IS_ERR_OR_NULL(msm_host->ff_clk))
+			clk_disable_unprepare(msm_host->ff_clk);
 		clk_disable_unprepare(msm_host->clk);
 		if (!IS_ERR(msm_host->pclk))
 			clk_disable_unprepare(msm_host->pclk);
@@ -2061,6 +2284,12 @@
 	}
 	atomic_set(&msm_host->clks_on, enable);
 	goto out;
+disable_ff_clk:
+	if (!IS_ERR_OR_NULL(msm_host->ff_clk))
+		clk_disable_unprepare(msm_host->ff_clk);
+disable_clk:
+	if (!IS_ERR_OR_NULL(msm_host->clk))
+		clk_disable_unprepare(msm_host->clk);
 disable_pclk:
 	if (!IS_ERR_OR_NULL(msm_host->pclk))
 		clk_disable_unprepare(msm_host->pclk);
@@ -2093,17 +2322,79 @@
 		return;
 
 	sup_clock = sdhci_msm_get_sup_clk_rate(host, clock);
-	if (curr_ios.timing == MMC_TIMING_UHS_DDR50) {
+	if ((curr_ios.timing == MMC_TIMING_UHS_DDR50) ||
+		(curr_ios.timing == MMC_TIMING_MMC_HS400)) {
 		/*
 		 * The SDHC requires internal clock frequency to be double the
 		 * actual clock that will be set for DDR mode. The controller
-		 * uses the faster clock(100MHz) for some of its parts and send
-		 * the actual required clock (50MHz) to the card.
+		 * uses the faster clock(100/400MHz) for some of its parts and
+		 * send the actual required clock (50/200MHz) to the card.
 		 */
 		ddr_clock = clock * 2;
 		sup_clock = sdhci_msm_get_sup_clk_rate(host,
 				ddr_clock);
 	}
+
+	/*
+	 * In general all timing modes are controlled via UHS mode select in
+	 * Host Control2 register. eMMC specific HS200/HS400 doesn't have
+	 * their respective modes defined here, hence we use these values.
+	 *
+	 * HS200 - SDR104 (Since they both are equivalent in functionality)
+	 * HS400 - This involves multiple configurations
+	 *		Initially SDR104 - when tuning is required as HS200
+	 *		Then when switching to DDR @ 400MHz (HS400) we use
+	 *		the vendor specific HC_SELECT_IN to control the mode.
+	 *
+	 * In addition to controlling the modes we also need to select the
+	 * correct input clock for DLL depending on the mode.
+	 *
+	 * HS400 - divided clock (free running MCLK/2)
+	 * All other modes - default (free running MCLK)
+	 */
+	if (curr_ios.timing == MMC_TIMING_MMC_HS400) {
+		/* Select the divided clock (free running MCLK/2) */
+		writel_relaxed(((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
+					& ~CORE_HC_MCLK_SEL_MASK)
+					| CORE_HC_MCLK_SEL_HS400),
+					host->ioaddr + CORE_VENDOR_SPEC);
+		/*
+		 * Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC
+		 * register
+		 */
+		if (msm_host->tuning_done && !msm_host->calibration_done) {
+			/*
+			 * Write 0x6 to HC_SELECT_IN and 1 to HC_SELECT_IN_EN
+			 * field in VENDOR_SPEC_FUNC
+			 */
+			writel_relaxed((readl_relaxed(host->ioaddr + \
+					CORE_VENDOR_SPEC)
+					| CORE_HC_SELECT_IN_HS400
+					| CORE_HC_SELECT_IN_EN),
+					host->ioaddr + CORE_VENDOR_SPEC);
+		}
+	} else {
+		/* Select the default clock (free running MCLK) */
+		writel_relaxed(((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
+					& ~CORE_HC_MCLK_SEL_MASK)
+					| CORE_HC_MCLK_SEL_DFLT),
+					host->ioaddr + CORE_VENDOR_SPEC);
+
+		/*
+		 * Disable HC_SELECT_IN to be able to use the UHS mode select
+		 * configuration from Host Control2 register for all other
+		 * modes.
+		 *
+		 * Write 0 to HC_SELECT_IN and HC_SELECT_IN_EN field
+		 * in VENDOR_SPEC_FUNC
+		 */
+		writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
+				& ~CORE_HC_SELECT_IN_EN
+				& ~CORE_HC_SELECT_IN_MASK),
+				host->ioaddr + CORE_VENDOR_SPEC);
+	}
+	mb();
+
 	if (sup_clock != msm_host->clk_rate) {
 		pr_debug("%s: %s: setting clk rate to %u\n",
 				mmc_hostname(host->mmc), __func__, sup_clock);
@@ -2127,12 +2418,16 @@
 static int sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
 					unsigned int uhs)
 {
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
 	u16 ctrl_2;
 
 	ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 	/* Select Bus Speed Mode for host */
 	ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
-	if (uhs == MMC_TIMING_MMC_HS200)
+	if (uhs == MMC_TIMING_MMC_HS400)
+		ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
+	else if (uhs == MMC_TIMING_MMC_HS200)
 		ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
 	else if (uhs == MMC_TIMING_UHS_SDR12)
 		ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
@@ -2150,11 +2445,36 @@
 	 * provide feedback clock, the mode selection can be any value less
 	 * than 3'b011 in bits [2:0] of HOST CONTROL2 register.
 	 */
-	if (host->clock <= (100 * 1000 * 1000) &&
-			(uhs == MMC_TIMING_MMC_HS200 ||
-			uhs == MMC_TIMING_UHS_SDR104))
-		ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+	if (host->clock <= CORE_FREQ_100MHZ) {
+		if ((uhs == MMC_TIMING_MMC_HS400) ||
+		    (uhs == MMC_TIMING_MMC_HS200) ||
+		    (uhs == MMC_TIMING_UHS_SDR104))
+			ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
 
+		/*
+		 * Make sure DLL is disabled when not required
+		 *
+		 * Write 1 to DLL_RST bit of DLL_CONFIG register
+		 */
+		writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+				| CORE_DLL_RST),
+				host->ioaddr + CORE_DLL_CONFIG);
+
+		/* Write 1 to DLL_PDN bit of DLL_CONFIG register */
+		writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+				| CORE_DLL_PDN),
+				host->ioaddr + CORE_DLL_CONFIG);
+		mb();
+
+		/*
+		 * The DLL needs to be restored and CDCLP533 recalibrated
+		 * when the clock frequency is set back to 400MHz.
+		 */
+		msm_host->calibration_done = false;
+	}
+
+	pr_debug("%s: %s-clock:%u uhs mode:%u ctrl_2:0x%x\n",
+		mmc_hostname(host->mmc), __func__, host->clock, uhs, ctrl_2);
 	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
 
 	return 0;
@@ -2321,9 +2641,27 @@
 	msm_host->clk_rate = sdhci_msm_get_min_clock(host);
 	atomic_set(&msm_host->clks_on, 1);
 
+	/* Setup CDC calibration fixed feedback clock */
+	msm_host->ff_clk = devm_clk_get(&pdev->dev, "cal_clk");
+	if (!IS_ERR(msm_host->ff_clk)) {
+		ret = clk_prepare_enable(msm_host->ff_clk);
+		if (ret)
+			goto clk_disable;
+	}
+
+	/* Setup CDC calibration sleep clock */
+	msm_host->sleep_clk = devm_clk_get(&pdev->dev, "sleep_clk");
+	if (!IS_ERR(msm_host->sleep_clk)) {
+		ret = clk_prepare_enable(msm_host->sleep_clk);
+		if (ret)
+			goto ff_clk_disable;
+	}
+
+	msm_host->saved_tuning_phase = INVALID_TUNING_PHASE;
+
 	ret = sdhci_msm_bus_register(msm_host, pdev);
 	if (ret)
-		goto clk_disable;
+		goto sleep_clk_disable;
 
 	if (msm_host->msm_bus_vote.client_handle)
 		INIT_DELAYED_WORK(&msm_host->msm_bus_vote.vote_work,
@@ -2368,6 +2706,10 @@
 	/* Set HC_MODE_EN bit in HC_MODE register */
 	writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
 
+	/* Set FF_CLK_SW_RST_DIS bit in HC_MODE register */
+	writel_relaxed(readl_relaxed(msm_host->core_mem + CORE_HC_MODE) |
+			FF_CLK_SW_RST_DIS, msm_host->core_mem + CORE_HC_MODE);
+
 	/*
 	 * CORE_SW_RST above may trigger power irq if previous status of PWRCTL
 	 * was either BUS_ON or IO_HIGH_V. So before we enable the power irq
@@ -2554,6 +2896,12 @@
 	if (msm_host->msm_bus_vote.client_handle)
 		sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
 	sdhci_msm_bus_unregister(msm_host);
+sleep_clk_disable:
+	if (!IS_ERR(msm_host->sleep_clk))
+		clk_disable_unprepare(msm_host->sleep_clk);
+ff_clk_disable:
+	if (!IS_ERR(msm_host->ff_clk))
+		clk_disable_unprepare(msm_host->ff_clk);
 clk_disable:
 	if (!IS_ERR(msm_host->clk))
 		clk_disable_unprepare(msm_host->clk);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 578cc14..f9f3802 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1129,6 +1129,7 @@
 
 	/* CMD19 is special in that the Data Present Select should be set */
 	if (cmd->data || cmd->opcode == MMC_SEND_TUNING_BLOCK ||
+	    cmd->opcode == MMC_SEND_TUNING_BLOCK_HS400 ||
 	    cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
 		flags |= SDHCI_CMD_DATA;
 
@@ -1631,7 +1632,8 @@
 		unsigned int clock;
 
 		/* In case of UHS-I modes, set High Speed Enable */
-		if ((ios->timing == MMC_TIMING_MMC_HS200) ||
+		if ((ios->timing == MMC_TIMING_MMC_HS400) ||
+		    (ios->timing == MMC_TIMING_MMC_HS200) ||
 		    (ios->timing == MMC_TIMING_UHS_SDR50) ||
 		    (ios->timing == MMC_TIMING_UHS_SDR104) ||
 		    (ios->timing == MMC_TIMING_UHS_DDR50) ||
@@ -1686,7 +1688,9 @@
 			ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 			/* Select Bus Speed Mode for host */
 			ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
-			if (ios->timing == MMC_TIMING_MMC_HS200)
+			if (ios->timing == MMC_TIMING_MMC_HS400)
+				ctrl_2 |= SDHCI_CTRL_HS_SDR200;
+			else if (ios->timing == MMC_TIMING_MMC_HS200)
 				ctrl_2 |= SDHCI_CTRL_HS_SDR200;
 			else if (ios->timing == MMC_TIMING_UHS_SDR12)
 				ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
@@ -1982,12 +1986,13 @@
 	 * The Host Controller needs tuning only in case of SDR104 mode
 	 * and for SDR50 mode when Use Tuning for SDR50 is set in the
 	 * Capabilities register.
-	 * If the Host Controller supports the HS200 mode then the
+	 * If the Host Controller supports the HS400/HS200 mode then the
 	 * tuning function has to be executed.
 	 */
 	if ((((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) &&
 	    (host->flags & SDHCI_SDR50_NEEDS_TUNING)) ||
-	     (host->flags & SDHCI_HS200_NEEDS_TUNING))
+	     (host->flags & SDHCI_HS200_NEEDS_TUNING) ||
+	     (host->flags & SDHCI_HS400_NEEDS_TUNING))
 		requires_tuning_nonuhs = true;
 
 	if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) ||
@@ -2050,7 +2055,8 @@
 		 * block to the Host Controller. So we set the block size
 		 * to 64 here.
 		 */
-		if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200) {
+		if ((cmd.opcode == MMC_SEND_TUNING_BLOCK_HS400) ||
+		    (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200)) {
 			if (mmc->ios.bus_width == MMC_BUS_WIDTH_8)
 				sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128),
 					     SDHCI_BLOCK_SIZE);
@@ -2451,7 +2457,8 @@
 		host->cmd->error = -EILSEQ;
 
 	if (host->quirks2 & SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING) {
-		if ((host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) ||
+		if ((host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS400) ||
+			(host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) ||
 			(host->cmd->opcode == MMC_SEND_TUNING_BLOCK)) {
 			if (intmask & SDHCI_INT_CRC) {
 				sdhci_reset(host, SDHCI_RESET_CMD);
@@ -2488,7 +2495,8 @@
 	}
 
 	if (host->quirks2 & SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING) {
-		if ((host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) ||
+		if ((host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS400) ||
+			(host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) ||
 			(host->cmd->opcode == MMC_SEND_TUNING_BLOCK)) {
 			if (intmask & SDHCI_INT_CRC) {
 				sdhci_finish_command(host);
@@ -2536,7 +2544,8 @@
 	if (intmask & SDHCI_INT_DATA_AVAIL) {
 		command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND));
 		if (command == MMC_SEND_TUNING_BLOCK ||
-		    command == MMC_SEND_TUNING_BLOCK_HS200) {
+		    command == MMC_SEND_TUNING_BLOCK_HS200 ||
+		    command == MMC_SEND_TUNING_BLOCK_HS400) {
 			host->tuning_done = 1;
 			wake_up(&host->buf_ready_int);
 			return;
@@ -2585,7 +2594,8 @@
 		    (host->quirks2 & SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING)) {
 			command = SDHCI_GET_CMD(sdhci_readw(host,
 							    SDHCI_COMMAND));
-			if ((command != MMC_SEND_TUNING_BLOCK_HS200) &&
+			if ((command != MMC_SEND_TUNING_BLOCK_HS400) &&
+			    (command != MMC_SEND_TUNING_BLOCK_HS200) &&
 			    (command != MMC_SEND_TUNING_BLOCK))
 				pr_msg = true;
 		} else {
@@ -3217,6 +3227,10 @@
 	if (mmc->caps2 & MMC_CAP2_HS200)
 		host->flags |= SDHCI_HS200_NEEDS_TUNING;
 
+	/* Does the host need tuning for HS400? */
+	if (mmc->caps2 & MMC_CAP2_HS400)
+		host->flags |= SDHCI_HS400_NEEDS_TUNING;
+
 	/* Driver Type(s) (A, C, D) supported by the host */
 	if (caps[1] & SDHCI_DRIVER_TYPE_A)
 		mmc->caps |= MMC_CAP_DRIVER_TYPE_A;
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 1262306..aa29748 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -31,6 +31,8 @@
 #include <linux/kthread.h>
 #include <linux/wait.h>
 #include <linux/uaccess.h>
+#include <linux/suspend.h>
+#include <linux/rwsem.h>
 #include <linux/mfd/pm8xxx/misc.h>
 
 #include <mach/msm_smd.h>
@@ -1344,6 +1346,7 @@
 	return;
 }
 
+static DECLARE_RWSEM(wcnss_pm_sem);
 
 static void wcnss_nvbin_dnld(void)
 {
@@ -1359,12 +1362,14 @@
 	const struct firmware *nv = NULL;
 	struct device *dev = &penv->pdev->dev;
 
+	down_read(&wcnss_pm_sem);
+
 	ret = request_firmware(&nv, NVBIN_FILE, dev);
 
 	if (ret || !nv || !nv->data || !nv->size) {
 		pr_err("wcnss: %s: request_firmware failed for %s\n",
 			__func__, NVBIN_FILE);
-		return;
+		goto out;
 	}
 
 	/*
@@ -1457,6 +1462,9 @@
 	/* release firmware */
 	release_firmware(nv);
 
+out:
+	up_read(&wcnss_pm_sem);
+
 	return;
 }
 
@@ -1590,7 +1598,25 @@
 	return;
 }
 
+static int wcnss_pm_notify(struct notifier_block *b,
+			unsigned long event, void *p)
+{
+	switch (event) {
+	case PM_SUSPEND_PREPARE:
+		down_write(&wcnss_pm_sem);
+		break;
 
+	case PM_POST_SUSPEND:
+		up_write(&wcnss_pm_sem);
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block wcnss_pm_notifier = {
+	.notifier_call = wcnss_pm_notify,
+};
 
 static int
 wcnss_trigger_config(struct platform_device *pdev)
@@ -2034,7 +2060,7 @@
 	platform_driver_register(&wcnss_wlan_driver);
 	platform_driver_register(&wcnss_wlan_ctrl_driver);
 	platform_driver_register(&wcnss_ctrl_driver);
-
+	register_pm_notifier(&wcnss_pm_notifier);
 #ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
 	ret = wcnss_prealloc_init();
 	if (ret < 0)
@@ -2049,17 +2075,16 @@
 	if (penv) {
 		if (penv->pil)
 			subsystem_put(penv->pil);
-
-
 		penv = NULL;
 	}
 
-	platform_driver_unregister(&wcnss_ctrl_driver);
-	platform_driver_unregister(&wcnss_wlan_ctrl_driver);
-	platform_driver_unregister(&wcnss_wlan_driver);
 #ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
 	wcnss_prealloc_deinit();
 #endif
+	unregister_pm_notifier(&wcnss_pm_notifier);
+	platform_driver_unregister(&wcnss_ctrl_driver);
+	platform_driver_unregister(&wcnss_wlan_ctrl_driver);
+	platform_driver_unregister(&wcnss_wlan_driver);
 }
 
 module_init(wcnss_wlan_init);
diff --git a/drivers/of/of_batterydata.c b/drivers/of/of_batterydata.c
index 977a1e0..2061408 100644
--- a/drivers/of/of_batterydata.c
+++ b/drivers/of/of_batterydata.c
@@ -155,6 +155,35 @@
 	return 0;
 }
 
+static int of_batterydata_read_batt_id_kohm(const struct device_node *np,
+				const char *propname, struct batt_ids *batt_ids)
+{
+	struct property *prop;
+	const __be32 *data;
+	int num, i, *id_kohm = batt_ids->kohm;
+
+	prop = of_find_property(np, "qcom,batt-id-kohm", NULL);
+	if (!prop) {
+		pr_err("%s: No battery id resistor found\n", np->name);
+		return -EINVAL;
+	} else if (!prop->value) {
+		pr_err("%s: No battery id resistor value found, np->name\n",
+						np->name);
+		return -ENODATA;
+	} else if (prop->length > MAX_BATT_ID_NUM * sizeof(__be32)) {
+		pr_err("%s: Too many battery id resistors\n", np->name);
+		return -EINVAL;
+	}
+
+	num = prop->length/sizeof(__be32);
+	batt_ids->num = num;
+	data = prop->value;
+	for (i = 0; i < num; i++)
+		*id_kohm++ = be32_to_cpup(data++);
+
+	return 0;
+}
+
 #define OF_PROP_READ(property, qpnp_dt_property, node, rc, optional)	\
 do {									\
 	if (rc)								\
@@ -172,6 +201,7 @@
 } while (0)
 
 static int of_batterydata_load_battery_data(struct device_node *node,
+				int best_id_kohm,
 				struct bms_battery_data *batt_data)
 {
 	int rc;
@@ -197,7 +227,6 @@
 			"default-rbatt-mohm", node, rc, false);
 	OF_PROP_READ(batt_data->rbatt_capacitive_mohm,
 			"rbatt-capacitive-mohm", node, rc, false);
-	OF_PROP_READ(batt_data->batt_id_kohm, "batt-id-kohm", node, rc, false);
 	OF_PROP_READ(batt_data->flat_ocv_threshold_uv,
 			"flat-ocv-threshold", node, rc, true);
 	OF_PROP_READ(batt_data->max_voltage_uv,
@@ -205,6 +234,8 @@
 	OF_PROP_READ(batt_data->cutoff_uv, "v-cutoff-uv", node, rc, true);
 	OF_PROP_READ(batt_data->iterm_ua, "chg-term-ua", node, rc, true);
 
+	batt_data->batt_id_kohm = best_id_kohm;
+
 	return rc;
 }
 
@@ -229,8 +260,9 @@
 				int batt_id_uv)
 {
 	struct device_node *node, *best_node;
-	uint32_t id_kohm;
-	int delta, best_delta, batt_id_kohm, rpull_up_kohm, vadc_vdd_uv, rc = 0;
+	struct batt_ids batt_ids;
+	int delta, best_delta, batt_id_kohm, rpull_up_kohm,
+		vadc_vdd_uv, best_id_kohm, i, rc = 0;
 
 	node = batterydata_container_node;
 	OF_PROP_READ(rpull_up_kohm, "rpull-up-kohm", node, rc, false);
@@ -242,18 +274,24 @@
 					rpull_up_kohm, vadc_vdd_uv);
 	best_node = NULL;
 	best_delta = 0;
+	best_id_kohm = 0;
 
 	/*
 	 * Find the battery data with a battery id resistor closest to this one
 	 */
 	for_each_child_of_node(batterydata_container_node, node) {
-		rc = of_property_read_u32(node, "qcom,batt-id-kohm", &id_kohm);
+		rc = of_batterydata_read_batt_id_kohm(node,
+						"qcom,batt-id-kohm",
+						&batt_ids);
 		if (rc)
 			continue;
-		delta = abs((int)id_kohm - batt_id_kohm);
-		if (delta < best_delta || !best_node) {
-			best_node = node;
-			best_delta = delta;
+		for (i = 0; i < batt_ids.num; i++) {
+			delta = abs(batt_ids.kohm[i] - batt_id_kohm);
+			if (delta < best_delta || !best_node) {
+				best_node = node;
+				best_delta = delta;
+				best_id_kohm = batt_ids.kohm[i];
+			}
 		}
 	}
 
@@ -262,7 +300,8 @@
 		return -ENODATA;
 	}
 
-	return of_batterydata_load_battery_data(best_node, batt_data);
+	return of_batterydata_load_battery_data(best_node,
+					best_id_kohm, batt_data);
 }
 
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index 2fdc427..b77c826 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -31,6 +31,8 @@
 #define QPNP_LPG_CHANNEL_BASE	"qpnp-lpg-channel-base"
 #define QPNP_LPG_LUT_BASE	"qpnp-lpg-lut-base"
 
+#define QPNP_PWM_MODE_ONLY_SUB_TYPE	0x0B
+
 /* LPG Control for LPG_PATTERN_CONFIG */
 #define QPNP_RAMP_DIRECTION_SHIFT	4
 #define QPNP_RAMP_DIRECTION_MASK	0x10
@@ -51,10 +53,13 @@
 #define QPNP_SET_PWM_CLK_SUB_TYPE(val, clk, pwm_size) \
 do { \
 	val = (clk + 1) & QPNP_PWM_FREQ_CLK_SELECT_MASK_SUB_TYPE; \
-	val |= ((pwm_size > 6 ? QPNP_PWM_SIZE_9_BIT_SUB_TYPE : 0) << \
-		QPNP_PWM_SIZE_SHIFT_SUB_TYPE) & QPNP_PWM_SIZE_MASK_SUB_TYPE; \
+	val |= (((pwm_size > 6 ? QPNP_PWM_SIZE_9_BIT_SUB_TYPE : 0) << \
+		QPNP_PWM_SIZE_SHIFT_SUB_TYPE) & QPNP_PWM_SIZE_MASK_SUB_TYPE); \
 } while (0)
 
+#define QPNP_GET_PWM_SIZE_SUB_TYPE(reg) ((reg & QPNP_PWM_SIZE_MASK_SUB_TYPE) \
+				>> QPNP_PWM_SIZE_SHIFT_SUB_TYPE)
+
 #define QPNP_PWM_SIZE_SHIFT			4
 #define QPNP_PWM_SIZE_MASK			0x30
 #define QPNP_PWM_FREQ_CLK_SELECT_MASK		0x03
@@ -361,6 +366,9 @@
 #define QPNP_DISABLE_LPG_MODE		qpnp_set_control(0, 0, 0, 0, 1)
 #define QPNP_IS_PWM_CONFIG_SELECTED(val) (val & QPNP_PWM_SRC_SELECT_MASK)
 
+#define QPNP_ENABLE_PWM_MODE_ONLY_SUB_TYPE			0x80
+#define QPNP_DISABLE_PWM_MODE_ONLY_SUB_TYPE			0x0
+#define QPNP_PWM_MODE_ONLY_ENABLE_DISABLE_MASK_SUB_TYPE	0x80
 
 static inline void qpnp_convert_to_lut_flags(int *flags,
 				struct qpnp_lut_config *l_config)
@@ -581,14 +589,16 @@
 	struct qpnp_lpg_chip	*chip = pwm->chip;
 	struct qpnp_pwm_config	*pwm_config = &pwm->pwm_config;
 
-	if (chip->sub_type == 0x0B)
+	if (chip->sub_type == QPNP_PWM_MODE_ONLY_SUB_TYPE) {
 		QPNP_SET_PWM_CLK_SUB_TYPE(val, pwm_config->period.clk,
 				pwm_config->period.pwm_size);
-	else
+		mask = QPNP_PWM_SIZE_MASK_SUB_TYPE |
+				QPNP_PWM_FREQ_CLK_SELECT_MASK_SUB_TYPE;
+	} else {
 		QPNP_SET_PWM_CLK(val, pwm_config->period.clk,
 				pwm_config->period.pwm_size);
-
-	mask = QPNP_PWM_SIZE_MASK | QPNP_PWM_FREQ_CLK_SELECT_MASK;
+		mask = QPNP_PWM_SIZE_MASK | QPNP_PWM_FREQ_CLK_SELECT_MASK;
+	}
 
 	qpnp_lpg_save(&chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK],
 							mask, val);
@@ -612,9 +622,14 @@
 	struct qpnp_lpg_config	*lpg_config = &chip->lpg_config;
 	int rc;
 
-	pwm_size = QPNP_GET_PWM_SIZE(
+	if (chip->sub_type == QPNP_PWM_MODE_ONLY_SUB_TYPE)
+		pwm_size = QPNP_GET_PWM_SIZE_SUB_TYPE(
+			chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK]) ?
+				QPNP_MAX_PWM_BIT_SIZE : QPNP_MIN_PWM_BIT_SIZE;
+	else
+		pwm_size = QPNP_GET_PWM_SIZE(
 			chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK]) +
-			QPNP_MIN_PWM_BIT_SIZE;
+				QPNP_MIN_PWM_BIT_SIZE;
 
 	max_pwm_value = (1 << pwm_size) - 1;
 
@@ -643,13 +658,14 @@
 	if (rc)
 		return rc;
 
-	if (chip->sub_type == 0x0B) {
+	if (chip->sub_type == QPNP_PWM_MODE_ONLY_SUB_TYPE) {
 		value = QPNP_PWM_SYNC_VALUE & QPNP_PWM_SYNC_MASK;
 		rc = spmi_ext_register_writel(chip->spmi_dev->ctrl,
 			chip->spmi_dev->sid,
 			SPMI_LPG_REG_ADDR(lpg_config->base_addr,
 			SPMI_LPG_PWM_SYNC), &value, 1);
 	}
+
 	return rc;
 }
 
@@ -710,6 +726,9 @@
 	struct qpnp_lpg_chip	*chip = pwm->chip;
 	u8			value, mask;
 
+	if (chip->sub_type == QPNP_PWM_MODE_ONLY_SUB_TYPE)
+		return 0;
+
 	value = QPNP_ENABLE_PWM_CONTROL;
 
 	mask = QPNP_EN_PWM_HIGH_MASK | QPNP_EN_PWM_LO_MASK |
@@ -1007,14 +1026,24 @@
 	u8			value, mask;
 	int			rc;
 
-	if (state == QPNP_PWM_ENABLE)
-		value = qpnp_enable_pwm_mode(&pwm->pwm_config);
-	else
-		value = QPNP_DISABLE_PWM_MODE;
+	if (chip->sub_type == QPNP_PWM_MODE_ONLY_SUB_TYPE) {
+		if (state == QPNP_PWM_ENABLE)
+			value = QPNP_ENABLE_PWM_MODE_ONLY_SUB_TYPE;
+		else
+			value = QPNP_DISABLE_PWM_MODE_ONLY_SUB_TYPE;
 
-	mask = QPNP_EN_PWM_HIGH_MASK | QPNP_EN_PWM_LO_MASK |
-		QPNP_EN_PWM_OUTPUT_MASK | QPNP_PWM_SRC_SELECT_MASK |
-					QPNP_PWM_EN_RAMP_GEN_MASK;
+		mask = QPNP_PWM_MODE_ONLY_ENABLE_DISABLE_MASK_SUB_TYPE;
+	} else {
+		if (state == QPNP_PWM_ENABLE)
+			value = qpnp_enable_pwm_mode(&pwm->pwm_config);
+		else
+			value = QPNP_DISABLE_PWM_MODE;
+
+		mask = QPNP_EN_PWM_HIGH_MASK | QPNP_EN_PWM_LO_MASK |
+			QPNP_EN_PWM_OUTPUT_MASK | QPNP_PWM_SRC_SELECT_MASK |
+				QPNP_PWM_EN_RAMP_GEN_MASK;
+	}
+
 
 	rc = qpnp_lpg_save_and_write(value, mask,
 		&pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],
@@ -1164,7 +1193,8 @@
 	spin_lock_irqsave(&pwm->chip->lpg_lock, flags);
 
 	if (QPNP_IS_PWM_CONFIG_SELECTED(
-		chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL])) {
+		chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL]) ||
+			chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED) {
 		rc = qpnp_lpg_configure_pwm_state(pwm, QPNP_PWM_ENABLE);
 	} else if (!(chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED)) {
 			rc = qpnp_lpg_configure_lut_state(pwm, QPNP_LUT_ENABLE);
@@ -1329,7 +1359,8 @@
 
 	if (pwm_config->in_use) {
 		if (QPNP_IS_PWM_CONFIG_SELECTED(
-			chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL])) {
+			chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL]) ||
+				chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED) {
 			rc = qpnp_lpg_configure_pwm_state(pwm,
 						QPNP_PWM_DISABLE);
 		} else if (!(chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED)) {
diff --git a/drivers/platform/msm/qpnp-revid.c b/drivers/platform/msm/qpnp-revid.c
index 9471188..a2876e0 100644
--- a/drivers/platform/msm/qpnp-revid.c
+++ b/drivers/platform/msm/qpnp-revid.c
@@ -13,6 +13,8 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/spmi.h>
+#include <linux/err.h>
+#include <linux/qpnp-revid.h>
 
 #define REVID_REVISION1	0x0
 #define REVID_REVISION2	0x1
@@ -36,6 +38,15 @@
 	"PMD9635",
 };
 
+struct revid_chip {
+	struct list_head	link;
+	struct device_node	*dev_node;
+	struct pmic_revid_data	data;
+};
+
+static LIST_HEAD(revid_chips);
+static DEFINE_MUTEX(revid_chips_lock);
+
 static struct of_device_id qpnp_revid_match_table[] = {
 	{ .compatible = QPNP_REVID_DEV_NAME },
 	{}
@@ -54,6 +65,35 @@
 	return val;
 }
 
+/**
+ * get_revid_data - Return the revision information of PMIC
+ * @dev_node: Pointer to the revid peripheral of the PMIC for which
+ *		revision information is seeked
+ *
+ * CONTEXT: Should be called in non atomic context
+ *
+ * RETURNS: pointer to struct pmic_revid_data filled with the information
+ *		about the PMIC revision
+ */
+struct pmic_revid_data *get_revid_data(struct device_node *dev_node)
+{
+	struct revid_chip *revid_chip;
+
+	if (!dev_node)
+		return ERR_PTR(-EINVAL);
+
+	mutex_lock(&revid_chips_lock);
+	list_for_each_entry(revid_chip, &revid_chips, link) {
+		if (dev_node == revid_chip->dev_node) {
+			mutex_unlock(&revid_chips_lock);
+			return &revid_chip->data;
+		}
+	}
+	mutex_unlock(&revid_chips_lock);
+	return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL(get_revid_data);
+
 #define PM8941_PERIPHERAL_SUBTYPE	0x01
 #define PM8226_PERIPHERAL_SUBTYPE	0x04
 static size_t build_pmic_string(char *buf, size_t n, int sid,
@@ -94,6 +134,7 @@
 	u8 option1, option2, option3, option4;
 	struct resource *resource;
 	char pmic_string[PMIC_STRING_MAXLENGTH] = {'\0'};
+	struct revid_chip *revid_chip;
 
 	resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
 	if (!resource) {
@@ -114,6 +155,23 @@
 	pmic_subtype = qpnp_read_byte(spmi, resource->start + REVID_SUBTYPE);
 	pmic_status = qpnp_read_byte(spmi, resource->start + REVID_STATUS1);
 
+	revid_chip = devm_kzalloc(&spmi->dev, sizeof(struct revid_chip),
+						GFP_KERNEL);
+	if (!revid_chip)
+		return -ENOMEM;
+
+	revid_chip->dev_node = spmi->dev.of_node;
+	revid_chip->data.rev1 = rev1;
+	revid_chip->data.rev2 = rev2;
+	revid_chip->data.rev3 = rev3;
+	revid_chip->data.rev4 = rev4;
+	revid_chip->data.pmic_subtype = pmic_subtype;
+	revid_chip->data.pmic_type = pmic_type;
+
+	mutex_lock(&revid_chips_lock);
+	list_add(&revid_chip->link, &revid_chips);
+	mutex_unlock(&revid_chips_lock);
+
 	option1 = pmic_status & 0x3;
 	option2 = (pmic_status >> 2) & 0x3;
 	option3 = (pmic_status >> 4) & 0x3;
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 73c7e62..639d88c 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -23,6 +23,7 @@
 #include <linux/spmi.h>
 #include <linux/rtc.h>
 #include <linux/delay.h>
+#include <linux/sched.h>
 #include <linux/qpnp/qpnp-adc.h>
 #include <linux/qpnp/power-on.h>
 #include <linux/of_batterydata.h>
@@ -143,6 +144,7 @@
 	bool				bms_psy_registered;
 	struct power_supply		*batt_psy;
 	struct spmi_device		*spmi;
+	wait_queue_head_t		bms_wait_queue;
 	u16				base;
 	u16				iadc_base;
 
@@ -1682,6 +1684,7 @@
 #define SOC_CATCHUP_SEC_PER_PERCENT	60
 #define MAX_CATCHUP_SOC	(SOC_CATCHUP_SEC_MAX / SOC_CATCHUP_SEC_PER_PERCENT)
 #define SOC_CHANGE_PER_SEC		5
+#define REPORT_SOC_WAIT_MS		10000
 static int report_cc_based_soc(struct qpnp_bms_chip *chip)
 {
 	int soc, soc_change;
@@ -1693,6 +1696,18 @@
 	int rc;
 	bool charging, charging_since_last_report;
 
+	rc = wait_event_interruptible_timeout(chip->bms_wait_queue,
+			chip->calculated_soc != -EINVAL,
+			round_jiffies_relative(msecs_to_jiffies
+			(REPORT_SOC_WAIT_MS)));
+
+	if (rc == 0 && chip->calculated_soc == -EINVAL) {
+		pr_debug("calculate soc timed out\n");
+	} else if (rc == -ERESTARTSYS) {
+		pr_err("Wait for SoC interrupted.\n");
+		return rc;
+	}
+
 	rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX1_BATT_THERM, &result);
 
 	if (rc) {
@@ -2300,6 +2315,7 @@
 				params.delta_time_s);
 	}
 	mutex_unlock(&chip->last_soc_mutex);
+	wake_up_interruptible(&chip->bms_wait_queue);
 
 	if (new_calculated_soc != previous_soc && chip->bms_psy_registered) {
 		power_supply_changed(&chip->bms_psy);
@@ -3048,6 +3064,8 @@
 	int status = get_battery_status(chip);
 
 	if (chip->battery_status != status) {
+		pr_debug("status = %d, shadow status = %d\n",
+				status, chip->battery_status);
 		if (status == POWER_SUPPLY_STATUS_CHARGING) {
 			pr_debug("charging started\n");
 			charging_began(chip);
@@ -3310,7 +3328,7 @@
 static int set_battery_data(struct qpnp_bms_chip *chip)
 {
 	int64_t battery_id;
-	int rc;
+	int rc, dt_data = false;
 	struct bms_battery_data *batt_data;
 	struct device_node *node;
 
@@ -3346,6 +3364,10 @@
 			batt_data->rbatt_sf_lut = kzalloc(
 					sizeof(struct sf_lut), GFP_KERNEL);
 
+			batt_data->max_voltage_uv = -1;
+			batt_data->cutoff_uv = -1;
+			batt_data->iterm_ua = -1;
+
 			rc = of_batterydata_read_data(node,
 					batt_data, battery_id);
 			if (rc) {
@@ -3355,6 +3377,8 @@
 				kfree(batt_data->rbatt_sf_lut);
 				kfree(batt_data);
 				batt_data = &palladium_1500_data;
+			} else {
+				dt_data = true;
 			}
 		} else {
 			pr_warn("invalid battid, palladium 1500 assumed batt_id %llx\n",
@@ -3374,11 +3398,11 @@
 	chip->flat_ocv_threshold_uv = batt_data->flat_ocv_threshold_uv;
 
 	/* Override battery properties if specified in the battery profile */
-	if (batt_data->max_voltage_uv >= 0)
+	if (batt_data->max_voltage_uv >= 0 && dt_data)
 		chip->max_voltage_uv = batt_data->max_voltage_uv;
-	if (batt_data->cutoff_uv >= 0)
+	if (batt_data->cutoff_uv >= 0 && dt_data)
 		chip->v_cutoff_uv = batt_data->cutoff_uv;
-	if (batt_data->iterm_ua >= 0)
+	if (batt_data->iterm_ua >= 0 && dt_data)
 		chip->chg_term_ua = batt_data->iterm_ua;
 
 	if (chip->pc_temp_ocv_lut == NULL) {
@@ -3837,6 +3861,7 @@
 	mutex_init(&chip->vbat_monitor_mutex);
 	mutex_init(&chip->soc_invalidation_mutex);
 	mutex_init(&chip->last_soc_mutex);
+	init_waitqueue_head(&chip->bms_wait_queue);
 
 	warm_reset = qpnp_pon_is_warm_reset();
 	rc = warm_reset;
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 7ccd49d..1a79ad5 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -29,6 +29,8 @@
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/machine.h>
 #include <linux/of_batterydata.h>
+#include <linux/qpnp-revid.h>
+#include <linux/android_alarm.h>
 
 /* Interrupt offsets */
 #define INT_RT_STS(base)			(base + 0x10)
@@ -84,7 +86,9 @@
 #define CHGR_STATUS				0x09
 #define CHGR_BAT_IF_VCP				0x42
 #define CHGR_BAT_IF_BATFET_CTRL1		0x90
+#define CHGR_BAT_IF_SPARE			0xDF
 #define CHGR_MISC_BOOT_DONE			0x42
+#define CHGR_BUCK_PSTG_CTRL			0x73
 #define CHGR_BUCK_COMPARATOR_OVRIDE_1		0xEB
 #define CHGR_BUCK_COMPARATOR_OVRIDE_3		0xED
 #define CHGR_BUCK_BCK_VBAT_REG_MODE		0x74
@@ -93,6 +97,7 @@
 #define USB_CHG_GONE_REV_BST			0xED
 #define BUCK_VCHG_OV				0x77
 #define BUCK_TEST_SMBC_MODES			0xE6
+#define BUCK_CTRL_TRIM1				0xF1
 #define SEC_ACCESS				0xD0
 #define BAT_IF_VREF_BAT_THM_CTRL		0x4A
 #define BAT_IF_BPD_CTRL				0x48
@@ -202,9 +207,10 @@
 /* Workaround flags */
 #define CHG_FLAGS_VCP_WA		BIT(0)
 #define BOOST_FLASH_WA			BIT(1)
+#define POWER_STAGE_WA			BIT(2)
 
 struct qpnp_chg_irq {
-	unsigned int		irq;
+	int		irq;
 	unsigned long		disabled;
 };
 
@@ -283,7 +289,6 @@
 	struct qpnp_chg_irq		chg_failed;
 	struct qpnp_chg_irq		chg_vbatdet_lo;
 	struct qpnp_chg_irq		batt_pres;
-	struct qpnp_chg_irq		vchg_loop;
 	struct qpnp_chg_irq		batt_temp_ok;
 	bool				bat_is_cool;
 	bool				bat_is_warm;
@@ -305,6 +310,7 @@
 	int				prev_usb_max_ma;
 	int				set_vddmax_mv;
 	int				delta_vddmax_mv;
+	u8				trim_center;
 	unsigned int			warm_bat_mv;
 	unsigned int			cool_bat_mv;
 	unsigned int			resume_delta_mv;
@@ -331,14 +337,19 @@
 	uint32_t			flags;
 	struct qpnp_adc_tm_btm_param	adc_param;
 	struct work_struct		adc_measure_work;
+	struct work_struct		adc_disable_work;
 	struct delayed_work		arb_stop_work;
 	struct delayed_work		eoc_work;
-	struct wake_lock		eoc_wake_lock;
+	struct work_struct		soc_check_work;
 	struct qpnp_chg_regulator	otg_vreg;
 	struct qpnp_chg_regulator	boost_vreg;
+	struct qpnp_chg_regulator	batfet_vreg;
 	struct qpnp_vadc_chip		*vadc_dev;
 	struct qpnp_adc_tm_chip		*adc_tm_dev;
 	struct mutex			jeita_configure_lock;
+	struct alarm			reduce_power_stage_alarm;
+	struct work_struct		reduce_power_stage_work;
+	bool				power_stage_workaround_running;
 };
 
 
@@ -606,6 +617,24 @@
 	return (dcin_valid_rt_sts & DCIN_VALID_IRQ) ? 1 : 0;
 }
 
+static int
+qpnp_chg_is_ichg_loop_active(struct qpnp_chg_chip *chip)
+{
+	u8 buck_sts;
+	int rc;
+
+	rc = qpnp_chg_read(chip, &buck_sts, INT_RT_STS(chip->buck_base), 1);
+
+	if (rc) {
+		pr_err("spmi read failed: addr=%03X, rc=%d\n",
+				INT_RT_STS(chip->buck_base), rc);
+		return rc;
+	}
+	pr_debug("buck usb sts 0x%x\n", buck_sts);
+
+	return (buck_sts & ICHG_LOOP_IRQ) ? 1 : 0;
+}
+
 #define QPNP_CHG_I_MAX_MIN_100		100
 #define QPNP_CHG_I_MAX_MIN_150		150
 #define QPNP_CHG_I_MAX_MIN_MA		200
@@ -933,15 +962,13 @@
 		pr_err("request ADC error\n");
 }
 
-static irqreturn_t
-qpnp_chg_buck_vchg_loop_irq_handler(int irq, void *_chip)
+static void
+qpnp_bat_if_adc_disable_work(struct work_struct *work)
 {
-	struct qpnp_chg_chip *chip = _chip;
+	struct qpnp_chg_chip *chip = container_of(work,
+				struct qpnp_chg_chip, adc_disable_work);
 
-	if (chip->bat_if_base)
-		power_supply_changed(&chip->batt_psy);
-
-	return IRQ_HANDLED;
+	qpnp_adc_tm_disable_chan_meas(chip->adc_tm_dev, &chip->adc_param);
 }
 
 #define EOC_CHECK_PERIOD_MS	10000
@@ -962,17 +989,20 @@
 	if (!chip->charging_disabled && (chg_sts & FAST_CHG_ON_IRQ)) {
 		schedule_delayed_work(&chip->eoc_work,
 			msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
-		wake_lock(&chip->eoc_wake_lock);
-		qpnp_chg_disable_irq(&chip->chg_vbatdet_lo);
-	} else {
-		qpnp_chg_charge_en(chip, !chip->charging_disabled);
+		pm_stay_awake(chip->dev);
 	}
+	qpnp_chg_disable_irq(&chip->chg_vbatdet_lo);
 
+	pr_debug("psy changed usb_psy\n");
 	power_supply_changed(chip->usb_psy);
-	if (chip->dc_chgpth_base)
+	if (chip->dc_chgpth_base) {
+		pr_debug("psy changed dc_psy\n");
 		power_supply_changed(&chip->dc_psy);
-	if (chip->bat_if_base)
+	}
+	if (chip->bat_if_base) {
+		pr_debug("psy changed batt_psy\n");
 		power_supply_changed(&chip->batt_psy);
+	}
 	return IRQ_HANDLED;
 }
 
@@ -1019,6 +1049,72 @@
 	return IRQ_HANDLED;
 }
 
+#define QPNP_CHG_VDDMAX_MIN		3400
+#define QPNP_CHG_V_MIN_MV		3240
+#define QPNP_CHG_V_MAX_MV		4500
+#define QPNP_CHG_V_STEP_MV		10
+#define QPNP_CHG_BUCK_TRIM1_STEP	10
+#define QPNP_CHG_BUCK_VDD_TRIM_MASK	0xF0
+static int
+qpnp_chg_vddmax_and_trim_set(struct qpnp_chg_chip *chip,
+		int voltage, int trim_mv)
+{
+	int rc, trim_set;
+	u8 vddmax = 0, trim = 0;
+
+	if (voltage < QPNP_CHG_VDDMAX_MIN
+			|| voltage > QPNP_CHG_V_MAX_MV) {
+		pr_err("bad mV=%d asked to set\n", voltage);
+		return -EINVAL;
+	}
+
+	vddmax = (voltage - QPNP_CHG_V_MIN_MV) / QPNP_CHG_V_STEP_MV;
+	rc = qpnp_chg_write(chip, &vddmax, chip->chgr_base + CHGR_VDD_MAX, 1);
+	if (rc) {
+		pr_err("Failed to write vddmax: %d\n", rc);
+		return rc;
+	}
+
+	rc = qpnp_chg_masked_write(chip,
+		chip->buck_base + SEC_ACCESS,
+		0xFF,
+		0xA5, 1);
+	if (rc) {
+		pr_err("failed to write SEC_ACCESS rc=%d\n", rc);
+		return rc;
+	}
+	trim_set = clamp((int)chip->trim_center
+			+ (trim_mv / QPNP_CHG_BUCK_TRIM1_STEP),
+			0, 0xF);
+	trim = (u8)trim_set << 4;
+	rc = qpnp_chg_masked_write(chip,
+		chip->buck_base + BUCK_CTRL_TRIM1,
+		QPNP_CHG_BUCK_VDD_TRIM_MASK,
+		trim, 1);
+	if (rc) {
+		pr_err("Failed to write buck trim1: %d\n", rc);
+		return rc;
+	}
+	pr_debug("voltage=%d+%d setting vddmax: %02x, trim: %02x\n",
+			voltage, trim_mv, vddmax, trim);
+	return 0;
+}
+
+/* JEITA compliance logic */
+static void
+qpnp_chg_set_appropriate_vddmax(struct qpnp_chg_chip *chip)
+{
+	if (chip->bat_is_cool)
+		qpnp_chg_vddmax_and_trim_set(chip, chip->cool_bat_mv,
+				chip->delta_vddmax_mv);
+	else if (chip->bat_is_warm)
+		qpnp_chg_vddmax_and_trim_set(chip, chip->warm_bat_mv,
+				chip->delta_vddmax_mv);
+	else
+		qpnp_chg_vddmax_and_trim_set(chip, chip->max_voltage_mv,
+				chip->delta_vddmax_mv);
+}
+
 #define ENUM_T_STOP_BIT		BIT(0)
 static irqreturn_t
 qpnp_chg_usb_usbin_valid_irq_handler(int irq, void *_chip)
@@ -1038,12 +1134,22 @@
 	if (chip->usb_present ^ usb_present) {
 		chip->usb_present = usb_present;
 		if (!usb_present) {
+			if (!qpnp_chg_is_dc_chg_plugged_in(chip)) {
+				chip->delta_vddmax_mv = 0;
+				qpnp_chg_set_appropriate_vddmax(chip);
+			}
 			qpnp_chg_usb_suspend_enable(chip, 1);
-			chip->chg_done = false;
+			if (!qpnp_chg_is_dc_chg_plugged_in(chip))
+				chip->chg_done = false;
 			chip->prev_usb_max_ma = -EINVAL;
 		} else {
+			if (!qpnp_chg_is_dc_chg_plugged_in(chip)) {
+				chip->delta_vddmax_mv = 0;
+				qpnp_chg_set_appropriate_vddmax(chip);
+			}
 			schedule_delayed_work(&chip->eoc_work,
 				msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
+			schedule_work(&chip->soc_check_work);
 		}
 
 		power_supply_set_present(chip->usb_psy, chip->usb_present);
@@ -1061,6 +1167,7 @@
 	batt_temp_good = qpnp_chg_is_batt_temp_ok(chip);
 	pr_debug("batt-temp triggered: %d\n", batt_temp_good);
 
+	pr_debug("psy changed batt_psy\n");
 	power_supply_changed(&chip->batt_psy);
 	return IRQ_HANDLED;
 }
@@ -1076,17 +1183,18 @@
 
 	if (chip->batt_present ^ batt_present) {
 		chip->batt_present = batt_present;
+		pr_debug("psy changed batt_psy\n");
 		power_supply_changed(&chip->batt_psy);
+		pr_debug("psy changed usb_psy\n");
 		power_supply_changed(chip->usb_psy);
 
-		if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
+		if ((chip->cool_bat_decidegc || chip->warm_bat_decidegc)
 						&& batt_present) {
 			pr_debug("enabling vadc notifications\n");
 			schedule_work(&chip->adc_measure_work);
-		} else if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
+		} else if ((chip->cool_bat_decidegc || chip->warm_bat_decidegc)
 				&& !batt_present) {
-			qpnp_adc_tm_disable_chan_meas(chip->adc_tm_dev,
-					&chip->adc_param);
+			schedule_work(&chip->adc_disable_work);
 			pr_debug("disabling vadc notifications\n");
 		}
 	}
@@ -1105,12 +1213,22 @@
 
 	if (chip->dc_present ^ dc_present) {
 		chip->dc_present = dc_present;
-		if (!dc_present)
+		if (!dc_present && !qpnp_chg_is_usb_chg_plugged_in(chip)) {
+			chip->delta_vddmax_mv = 0;
+			qpnp_chg_set_appropriate_vddmax(chip);
 			chip->chg_done = false;
-		else
+		} else {
+			if (!qpnp_chg_is_usb_chg_plugged_in(chip)) {
+				chip->delta_vddmax_mv = 0;
+				qpnp_chg_set_appropriate_vddmax(chip);
+			}
 			schedule_delayed_work(&chip->eoc_work,
 				msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
+			schedule_work(&chip->soc_check_work);
+		}
+		pr_debug("psy changed dc_psy\n");
 		power_supply_changed(&chip->dc_psy);
+		pr_debug("psy changed batt_psy\n");
 		power_supply_changed(&chip->batt_psy);
 	}
 
@@ -1133,11 +1251,16 @@
 	if (rc)
 		pr_err("Failed to write chg_fail clear bit!\n");
 
-	if (chip->bat_if_base)
+	if (chip->bat_if_base) {
+		pr_debug("psy changed batt_psy\n");
 		power_supply_changed(&chip->batt_psy);
+	}
+	pr_debug("psy changed usb_psy\n");
 	power_supply_changed(chip->usb_psy);
-	if (chip->dc_chgpth_base)
+	if (chip->dc_chgpth_base) {
+		pr_debug("psy changed dc_psy\n");
 		power_supply_changed(&chip->dc_psy);
+	}
 	return IRQ_HANDLED;
 }
 
@@ -1149,8 +1272,10 @@
 	pr_debug("TRKL IRQ triggered\n");
 
 	chip->chg_done = false;
-	if (chip->bat_if_base)
+	if (chip->bat_if_base) {
+		pr_debug("psy changed batt_psy\n");
 		power_supply_changed(&chip->batt_psy);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -1168,21 +1293,31 @@
 
 	pr_debug("FAST_CHG IRQ triggered\n");
 	chip->chg_done = false;
-	if (chip->bat_if_base)
+	if (chip->bat_if_base) {
+		pr_debug("psy changed batt_psy\n");
 		power_supply_changed(&chip->batt_psy);
+	}
+
+	pr_debug("psy changed usb_psy\n");
 	power_supply_changed(chip->usb_psy);
-	if (chip->dc_chgpth_base)
+
+	if (chip->dc_chgpth_base) {
+		pr_debug("psy changed dc_psy\n");
 		power_supply_changed(&chip->dc_psy);
+	}
+
 	if (chip->resuming_charging) {
 		chip->resuming_charging = false;
 		qpnp_chg_set_appropriate_vbatdet(chip);
 	}
 
+	if (!chip->charging_disabled) {
+		schedule_delayed_work(&chip->eoc_work,
+			msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
+		pm_stay_awake(chip->dev);
+	}
+
 	qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
-	if (chgr_sts & FAST_CHG_ON_IRQ)
-		qpnp_chg_enable_irq(&chip->vchg_loop);
-	else
-		qpnp_chg_disable_irq(&chip->vchg_loop);
 
 	return IRQ_HANDLED;
 }
@@ -1534,19 +1669,26 @@
 get_prop_capacity(struct qpnp_chg_chip *chip)
 {
 	union power_supply_propval ret = {0,};
+	int battery_status, charger_in;
 
 	if (chip->use_default_batt_values || !get_prop_batt_present(chip))
 		return DEFAULT_CAPACITY;
 
 	if (chip->bms_psy) {
 		chip->bms_psy->get_property(chip->bms_psy,
-			  POWER_SUPPLY_PROP_CAPACITY, &ret);
-		if (get_prop_batt_status(chip) == POWER_SUPPLY_STATUS_FULL
+				POWER_SUPPLY_PROP_CAPACITY, &ret);
+		battery_status = get_prop_batt_status(chip);
+		charger_in = qpnp_chg_is_usb_chg_plugged_in(chip) ||
+			qpnp_chg_is_dc_chg_plugged_in(chip);
+
+		if (battery_status != POWER_SUPPLY_STATUS_CHARGING
+				&& charger_in
 				&& !chip->resuming_charging
 				&& !chip->charging_disabled
 				&& chip->soc_resume_limit
 				&& ret.intval <= chip->soc_resume_limit) {
-			pr_debug("resuming charging at %d%% soc\n", ret.intval);
+			pr_debug("resuming charging at %d%% soc\n",
+					ret.intval);
 			chip->resuming_charging = true;
 			qpnp_chg_set_appropriate_vbatdet(chip);
 			qpnp_chg_charge_en(chip, !chip->charging_disabled);
@@ -1654,12 +1796,22 @@
 			} else {
 				qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
 			}
+
+			if ((chip->flags & POWER_STAGE_WA)
+			&& ((ret.intval / 1000) > USB_WALL_THRESHOLD_MA)
+			&& !chip->power_stage_workaround_running) {
+				chip->power_stage_workaround_running = true;
+				pr_debug("usb wall chg inserted starting power stage workaround charger_monitor = %d\n",
+						charger_monitor);
+				schedule_work(&chip->reduce_power_stage_work);
+			}
 		}
 		chip->prev_usb_max_ma = ret.intval;
 	}
 
 skip_set_iusb_max:
 	pr_debug("end of power supply changed\n");
+	pr_debug("psy changed batt_psy\n");
 	power_supply_changed(&chip->batt_psy);
 }
 
@@ -1856,9 +2008,6 @@
 			QPNP_CHG_TCHG_MASK, temp, 1);
 }
 
-#define QPNP_CHG_V_MIN_MV	3240
-#define QPNP_CHG_V_MAX_MV	4500
-#define QPNP_CHG_V_STEP_MV	10
 static int
 qpnp_chg_vddsafe_set(struct qpnp_chg_chip *chip, int voltage)
 {
@@ -1875,25 +2024,6 @@
 		chip->chgr_base + CHGR_VDD_SAFE, 1);
 }
 
-#define QPNP_CHG_VDDMAX_MIN	3400
-static int
-qpnp_chg_vddmax_set(struct qpnp_chg_chip *chip, int voltage)
-{
-	u8 temp = 0;
-
-	if (voltage < QPNP_CHG_VDDMAX_MIN
-			|| voltage > QPNP_CHG_V_MAX_MV) {
-		pr_err("bad mV=%d asked to set\n", voltage);
-		return -EINVAL;
-	}
-	chip->set_vddmax_mv = voltage + chip->delta_vddmax_mv;
-
-	temp = (chip->set_vddmax_mv - QPNP_CHG_V_MIN_MV) / QPNP_CHG_V_STEP_MV;
-
-	pr_debug("voltage=%d setting %02x\n", chip->set_vddmax_mv, temp);
-	return qpnp_chg_write(chip, &temp, chip->chgr_base + CHGR_VDD_MAX, 1);
-}
-
 #define BOOST_MIN_UV	4200000
 #define BOOST_MAX_UV	5500000
 #define BOOST_STEP_UV	50000
@@ -1936,18 +2066,6 @@
 	return BOOST_MIN_UV + ((boost_reg - BOOST_MIN) * BOOST_STEP_UV);
 }
 
-/* JEITA compliance logic */
-static void
-qpnp_chg_set_appropriate_vddmax(struct qpnp_chg_chip *chip)
-{
-	if (chip->bat_is_cool)
-		qpnp_chg_vddmax_set(chip, chip->cool_bat_mv);
-	else if (chip->bat_is_warm)
-		qpnp_chg_vddmax_set(chip, chip->warm_bat_mv);
-	else
-		qpnp_chg_vddmax_set(chip, chip->max_voltage_mv);
-}
-
 static void
 qpnp_chg_set_appropriate_battery_current(struct qpnp_chg_chip *chip)
 {
@@ -2206,22 +2324,80 @@
 	.list_voltage		= qpnp_chg_regulator_boost_list_voltage,
 };
 
-#define MIN_DELTA_MV_TO_INCREASE_VDD_MAX	13
-#define MAX_DELTA_VDD_MAX_MV			30
+#define BATFET_LPM_MASK		0xC0
+#define BATFET_LPM		0x40
+#define BATFET_NO_LPM		0x00
+static int
+qpnp_chg_regulator_batfet_enable(struct regulator_dev *rdev)
+{
+	struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+	int rc;
+
+	rc = qpnp_chg_masked_write(chip,
+			chip->bat_if_base + CHGR_BAT_IF_SPARE,
+			BATFET_LPM_MASK, BATFET_NO_LPM, 1);
+	if (rc)
+		pr_err("failed to write to batt_if rc=%d\n", rc);
+	return rc;
+}
+
+static int
+qpnp_chg_regulator_batfet_disable(struct regulator_dev *rdev)
+{
+	struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+	int rc;
+
+	rc = qpnp_chg_masked_write(chip,
+			chip->bat_if_base + CHGR_BAT_IF_SPARE,
+			BATFET_LPM_MASK, BATFET_LPM, 1);
+	if (rc)
+		pr_err("failed to write to batt_if rc=%d\n", rc);
+	return rc;
+}
+
+static int
+qpnp_chg_regulator_batfet_is_enabled(struct regulator_dev *rdev)
+{
+	struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+	int rc;
+	u8 reg;
+
+	rc = qpnp_chg_read(chip, &reg,
+				chip->bat_if_base + CHGR_BAT_IF_SPARE, 1);
+	if (rc) {
+		pr_err("failed to read batt_if rc=%d\n", rc);
+		return rc;
+	}
+
+	if (reg && BATFET_LPM_MASK == BATFET_NO_LPM)
+		return 1;
+
+	return 0;
+}
+
+static struct regulator_ops qpnp_chg_batfet_vreg_ops = {
+	.enable			= qpnp_chg_regulator_batfet_enable,
+	.disable		= qpnp_chg_regulator_batfet_disable,
+	.is_enabled		= qpnp_chg_regulator_batfet_is_enabled,
+};
+
+#define MIN_DELTA_MV_TO_INCREASE_VDD_MAX	8
+#define MAX_DELTA_VDD_MAX_MV			80
+#define VDD_MAX_CENTER_OFFSET			4
 static void
 qpnp_chg_adjust_vddmax(struct qpnp_chg_chip *chip, int vbat_mv)
 {
 	int delta_mv, closest_delta_mv, sign;
 
-	delta_mv = chip->max_voltage_mv - vbat_mv;
+	delta_mv = chip->max_voltage_mv - VDD_MAX_CENTER_OFFSET - vbat_mv;
 	if (delta_mv > 0 && delta_mv < MIN_DELTA_MV_TO_INCREASE_VDD_MAX) {
 		pr_debug("vbat is not low enough to increase vdd\n");
 		return;
 	}
 
 	sign = delta_mv > 0 ? 1 : -1;
-	closest_delta_mv = ((delta_mv + sign * QPNP_CHG_V_STEP_MV / 2)
-			/ QPNP_CHG_V_STEP_MV) * QPNP_CHG_V_STEP_MV;
+	closest_delta_mv = ((delta_mv + sign * QPNP_CHG_BUCK_TRIM1_STEP / 2)
+			/ QPNP_CHG_BUCK_TRIM1_STEP) * QPNP_CHG_BUCK_TRIM1_STEP;
 	pr_debug("max_voltage = %d, vbat_mv = %d, delta_mv = %d, closest = %d\n",
 			chip->max_voltage_mv, vbat_mv,
 			delta_mv, closest_delta_mv);
@@ -2232,6 +2408,7 @@
 }
 
 #define CONSECUTIVE_COUNT	3
+#define VBATDET_MAX_ERR_MV	50
 static void
 qpnp_eoc_work(struct work_struct *work)
 {
@@ -2239,10 +2416,12 @@
 	struct qpnp_chg_chip *chip = container_of(dwork,
 				struct qpnp_chg_chip, eoc_work);
 	static int count;
+	static int vbat_low_count;
 	int ibat_ma, vbat_mv, rc = 0;
 	u8 batt_sts = 0, buck_sts = 0, chg_sts = 0;
+	bool vbat_lower_than_vbatdet;
 
-	wake_lock(&chip->eoc_wake_lock);
+	pm_stay_awake(chip->dev);
 	qpnp_chg_charge_en(chip, !chip->charging_disabled);
 
 	rc = qpnp_chg_read(chip, &batt_sts, INT_RT_STS(chip->bat_if_base), 1);
@@ -2280,11 +2459,24 @@
 		pr_debug("ibat_ma = %d vbat_mv = %d term_current_ma = %d\n",
 				ibat_ma, vbat_mv, chip->term_current);
 
-		if ((!(chg_sts & VBAT_DET_LOW_IRQ)) && (vbat_mv <
-			(chip->max_voltage_mv - chip->resume_delta_mv))) {
-			pr_debug("woke up too early\n");
-			qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
-			goto stop_eoc;
+		vbat_lower_than_vbatdet = !(chg_sts & VBAT_DET_LOW_IRQ);
+		if (vbat_lower_than_vbatdet && vbat_mv <
+				(chip->max_voltage_mv - chip->resume_delta_mv
+				 - VBATDET_MAX_ERR_MV)) {
+			vbat_low_count++;
+			pr_debug("woke up too early vbat_mv = %d, max_mv = %d, resume_mv = %d tolerance_mv = %d low_count = %d\n",
+					vbat_mv, chip->max_voltage_mv,
+					chip->resume_delta_mv,
+					VBATDET_MAX_ERR_MV, vbat_low_count);
+			if (vbat_low_count >= CONSECUTIVE_COUNT) {
+				pr_debug("woke up too early stopping\n");
+				qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
+				goto stop_eoc;
+			} else {
+				goto check_again_later;
+			}
+		} else {
+			vbat_low_count = 0;
 		}
 
 		if (buck_sts & VDD_LOOP_IRQ)
@@ -2302,8 +2494,15 @@
 		} else {
 			if (count == CONSECUTIVE_COUNT) {
 				pr_info("End of Charging\n");
-				qpnp_chg_charge_en(chip, 0);
+				chip->delta_vddmax_mv = 0;
+				qpnp_chg_set_appropriate_vddmax(chip);
 				chip->chg_done = true;
+				qpnp_chg_charge_en(chip, 0);
+				/* sleep for a second before enabling */
+				msleep(2000);
+				qpnp_chg_charge_en(chip,
+						!chip->charging_disabled);
+				pr_debug("psy changed batt_psy\n");
 				power_supply_changed(&chip->batt_psy);
 				qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
 				goto stop_eoc;
@@ -2314,16 +2513,27 @@
 		}
 	} else {
 		pr_debug("not charging\n");
-			goto stop_eoc;
+		goto stop_eoc;
 	}
 
+check_again_later:
 	schedule_delayed_work(&chip->eoc_work,
 		msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
 	return;
 
 stop_eoc:
+	vbat_low_count = 0;
 	count = 0;
-	wake_unlock(&chip->eoc_wake_lock);
+	pm_relax(chip->dev);
+}
+
+static void
+qpnp_chg_soc_check_work(struct work_struct *work)
+{
+	struct qpnp_chg_chip *chip = container_of(work,
+				struct qpnp_chg_chip, soc_check_work);
+
+	get_prop_capacity(chip);
 }
 
 #define HYSTERISIS_DECIDEGC 20
@@ -2475,6 +2685,199 @@
 	return rc;
 }
 
+#define POWER_STAGE_REDUCE_CHECK_PERIOD_SECONDS		20
+#define POWER_STAGE_REDUCE_MAX_VBAT_UV			3900000
+#define POWER_STAGE_REDUCE_MIN_VCHG_UV			4800000
+#define POWER_STAGE_SEL_MASK				0x0F
+#define POWER_STAGE_REDUCED				0x01
+#define POWER_STAGE_DEFAULT				0x0F
+static bool
+qpnp_chg_is_power_stage_reduced(struct qpnp_chg_chip *chip)
+{
+	int rc;
+	u8 reg;
+
+	rc = qpnp_chg_read(chip, &reg,
+				 chip->buck_base + CHGR_BUCK_PSTG_CTRL,
+				 1);
+	if (rc) {
+		pr_err("Error %d reading power stage register\n", rc);
+		return false;
+	}
+
+	if ((reg & POWER_STAGE_SEL_MASK) == POWER_STAGE_DEFAULT)
+		return false;
+
+	return true;
+}
+
+static int
+qpnp_chg_power_stage_set(struct qpnp_chg_chip *chip, bool reduce)
+{
+	int rc;
+	u8 reg = 0xA5;
+
+	rc = qpnp_chg_write(chip, &reg,
+				 chip->buck_base + SEC_ACCESS,
+				 1);
+	if (rc) {
+		pr_err("Error %d writing 0xA5 to buck's 0x%x reg\n",
+				rc, SEC_ACCESS);
+		return rc;
+	}
+
+	reg = POWER_STAGE_DEFAULT;
+	if (reduce)
+		reg = POWER_STAGE_REDUCED;
+	rc = qpnp_chg_write(chip, &reg,
+				 chip->buck_base + CHGR_BUCK_PSTG_CTRL,
+				 1);
+
+	if (rc)
+		pr_err("Error %d writing 0x%x power stage register\n", rc, reg);
+	return rc;
+}
+
+static int
+qpnp_chg_get_vusbin_uv(struct qpnp_chg_chip *chip)
+{
+	int rc = 0;
+	struct qpnp_vadc_result results;
+
+	rc = qpnp_vadc_read(chip->vadc_dev, USBIN, &results);
+	if (rc) {
+		pr_err("Unable to read vbat rc=%d\n", rc);
+		return 0;
+	}
+	return results.physical;
+}
+
+static
+int get_vusb_averaged(struct qpnp_chg_chip *chip, int sample_count)
+{
+	int vusb_uv = 0;
+	int i;
+
+	/* avoid  overflows */
+	if (sample_count > 256)
+		sample_count = 256;
+
+	for (i = 0; i < sample_count; i++)
+		vusb_uv += qpnp_chg_get_vusbin_uv(chip);
+
+	vusb_uv = vusb_uv / sample_count;
+	return vusb_uv;
+}
+
+static
+int get_vbat_averaged(struct qpnp_chg_chip *chip, int sample_count)
+{
+	int vbat_uv = 0;
+	int i;
+
+	/* avoid  overflows */
+	if (sample_count > 256)
+		sample_count = 256;
+
+	for (i = 0; i < sample_count; i++)
+		vbat_uv += get_prop_battery_voltage_now(chip);
+
+	vbat_uv = vbat_uv / sample_count;
+	return vbat_uv;
+}
+
+static void
+qpnp_chg_reduce_power_stage(struct qpnp_chg_chip *chip)
+{
+	struct timespec ts;
+	bool power_stage_reduced_in_hw = qpnp_chg_is_power_stage_reduced(chip);
+	bool reduce_power_stage = false;
+	int vbat_uv = get_vbat_averaged(chip, 16);
+	int vusb_uv = get_vusb_averaged(chip, 16);
+	bool fast_chg =
+		(get_prop_charge_type(chip) == POWER_SUPPLY_CHARGE_TYPE_FAST);
+	static int count_restore_power_stage;
+	static int count_reduce_power_stage;
+	bool vchg_loop = get_prop_vchg_loop(chip);
+	bool ichg_loop = qpnp_chg_is_ichg_loop_active(chip);
+	bool usb_present = qpnp_chg_is_usb_chg_plugged_in(chip);
+	bool usb_ma_above_wall =
+		(qpnp_chg_usb_iusbmax_get(chip) > USB_WALL_THRESHOLD_MA);
+
+	if (fast_chg
+		&& usb_present
+		&& usb_ma_above_wall
+		&& vbat_uv < POWER_STAGE_REDUCE_MAX_VBAT_UV
+		&& vusb_uv > POWER_STAGE_REDUCE_MIN_VCHG_UV)
+		reduce_power_stage = true;
+
+	if ((usb_present && usb_ma_above_wall)
+		&& (vchg_loop || ichg_loop))
+		reduce_power_stage = true;
+
+	if (power_stage_reduced_in_hw && !reduce_power_stage) {
+		count_restore_power_stage++;
+		count_reduce_power_stage = 0;
+	} else if (!power_stage_reduced_in_hw && reduce_power_stage) {
+		count_reduce_power_stage++;
+		count_restore_power_stage = 0;
+	} else if (power_stage_reduced_in_hw == reduce_power_stage) {
+		count_restore_power_stage = 0;
+		count_reduce_power_stage = 0;
+	}
+
+	pr_debug("power_stage_hw = %d reduce_power_stage = %d usb_present = %d usb_ma_above_wall = %d vbat_uv(16) = %d vusb_uv(16) = %d fast_chg = %d , ichg = %d, vchg = %d, restore,reduce = %d, %d\n",
+			power_stage_reduced_in_hw, reduce_power_stage,
+			usb_present, usb_ma_above_wall,
+			vbat_uv, vusb_uv, fast_chg,
+			ichg_loop, vchg_loop,
+			count_restore_power_stage, count_reduce_power_stage);
+
+	if (!power_stage_reduced_in_hw && reduce_power_stage) {
+		if (count_reduce_power_stage >= 2) {
+			qpnp_chg_power_stage_set(chip, true);
+			power_stage_reduced_in_hw = true;
+		}
+	}
+
+	if (power_stage_reduced_in_hw && !reduce_power_stage) {
+		if (count_restore_power_stage >= 6
+				|| (!usb_present || !usb_ma_above_wall)) {
+			qpnp_chg_power_stage_set(chip, false);
+			power_stage_reduced_in_hw = false;
+		}
+	}
+
+	if (usb_present && usb_ma_above_wall) {
+		getnstimeofday(&ts);
+		ts.tv_sec += POWER_STAGE_REDUCE_CHECK_PERIOD_SECONDS;
+		alarm_start_range(&chip->reduce_power_stage_alarm,
+					timespec_to_ktime(ts),
+					timespec_to_ktime(ts));
+	} else {
+		pr_debug("stopping power stage workaround\n");
+		chip->power_stage_workaround_running = false;
+	}
+}
+
+static void
+qpnp_chg_reduce_power_stage_work(struct work_struct *work)
+{
+	struct qpnp_chg_chip *chip = container_of(work,
+				struct qpnp_chg_chip, reduce_power_stage_work);
+
+	qpnp_chg_reduce_power_stage(chip);
+}
+
+static void
+qpnp_chg_reduce_power_stage_callback(struct alarm *alarm)
+{
+	struct qpnp_chg_chip *chip = container_of(alarm, struct qpnp_chg_chip,
+						reduce_power_stage_alarm);
+
+	schedule_work(&chip->reduce_power_stage_work);
+}
+
 static int
 qpnp_dc_power_set_property(struct power_supply *psy,
 				  enum power_supply_property psp,
@@ -2501,6 +2904,7 @@
 		return -EINVAL;
 	}
 
+	pr_debug("psy changed dc_psy\n");
 	power_supply_changed(&chip->dc_psy);
 	return rc;
 }
@@ -2523,8 +2927,17 @@
 		break;
 	case POWER_SUPPLY_PROP_CHARGING_ENABLED:
 		chip->charging_disabled = !(val->intval);
-		qpnp_chg_charge_en(chip, !chip->charging_disabled);
-		qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
+		if (chip->charging_disabled) {
+			/* disable charging */
+			qpnp_chg_charge_en(chip, !chip->charging_disabled);
+			qpnp_chg_force_run_on_batt(chip,
+						chip->charging_disabled);
+		} else {
+			/* enable charging */
+			qpnp_chg_force_run_on_batt(chip,
+					chip->charging_disabled);
+			qpnp_chg_charge_en(chip, !chip->charging_disabled);
+		}
 		break;
 	case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
 		qpnp_batt_system_temp_level_set(chip, val->intval);
@@ -2539,19 +2952,44 @@
 		return -EINVAL;
 	}
 
+	pr_debug("psy changed batt_psy\n");
 	power_supply_changed(&chip->batt_psy);
 	return rc;
 }
 
-static void
+static int
 qpnp_chg_setup_flags(struct qpnp_chg_chip *chip)
 {
 	if (chip->revision > 0 && chip->type == SMBB)
 		chip->flags |= CHG_FLAGS_VCP_WA;
 	if (chip->type == SMBB)
 		chip->flags |= BOOST_FLASH_WA;
-	if (chip->type == SMBBP)
-		chip->flags |= BOOST_FLASH_WA;
+	if (chip->type == SMBBP) {
+		struct device_node *revid_dev_node;
+		struct pmic_revid_data *revid_data;
+
+		chip->flags |=  BOOST_FLASH_WA;
+
+		revid_dev_node = of_parse_phandle(chip->spmi->dev.of_node,
+						"qcom,pmic-revid", 0);
+		if (!revid_dev_node) {
+			pr_err("Missing qcom,pmic-revid property\n");
+			return -EINVAL;
+		}
+		revid_data = get_revid_data(revid_dev_node);
+		if (IS_ERR(revid_data)) {
+			pr_err("Couldnt get revid data rc = %ld\n",
+						PTR_ERR(revid_data));
+			return PTR_ERR(revid_data);
+		}
+
+		if (revid_data->rev4 < PM8226_V2P1_REV4
+			|| ((revid_data->rev4 == PM8226_V2P1_REV4)
+				&& (revid_data->rev3 <= PM8226_V2P1_REV3))) {
+			chip->flags |= POWER_STAGE_WA;
+		}
+	}
+	return 0;
 }
 
 static int
@@ -2648,7 +3086,7 @@
 			rc |= devm_request_irq(chip->dev,
 				chip->chg_vbatdet_lo.irq,
 				qpnp_chg_vbatdet_lo_irq_handler,
-				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+				IRQF_TRIGGER_RISING,
 				"vbat-det-lo", chip);
 			if (rc < 0) {
 				pr_err("Can't request %d vbat-det-lo: %d\n",
@@ -2706,24 +3144,6 @@
 		case SMBB_BUCK_SUBTYPE:
 		case SMBBP_BUCK_SUBTYPE:
 		case SMBCL_BUCK_SUBTYPE:
-			chip->vchg_loop.irq = spmi_get_irq_byname(spmi,
-						spmi_resource, "vchg-loop");
-			if (chip->vchg_loop.irq < 0) {
-				pr_err("Unable to get vchg-loop irq\n");
-				return rc;
-			}
-			rc = devm_request_irq(chip->dev, chip->vchg_loop.irq,
-				qpnp_chg_buck_vchg_loop_irq_handler,
-				IRQF_TRIGGER_RISING,
-				"vchg-loop", chip);
-			if (rc < 0) {
-				pr_err("Can't request %d vchg-loop irq: %d\n",
-						chip->vchg_loop.irq, rc);
-				return rc;
-			}
-
-			enable_irq_wake(chip->vchg_loop.irq);
-			qpnp_chg_disable_irq(&chip->vchg_loop);
 			break;
 
 		case SMBB_USB_CHGPTH_SUBTYPE:
@@ -2829,6 +3249,8 @@
 			return rc;
 		}
 
+		batt_data.max_voltage_uv = -1;
+		batt_data.iterm_ua = -1;
 		rc = of_batterydata_read_data(node,
 				&batt_data, result.physical);
 		if (rc) {
@@ -2867,11 +3289,6 @@
 			pr_debug("failed setting  min_voltage rc=%d\n", rc);
 			return rc;
 		}
-		rc = qpnp_chg_vddmax_set(chip, chip->max_voltage_mv);
-		if (rc) {
-			pr_debug("failed setting max_voltage rc=%d\n", rc);
-			return rc;
-		}
 		rc = qpnp_chg_vddsafe_set(chip, chip->safe_voltage_mv);
 		if (rc) {
 			pr_debug("failed setting safe_voltage rc=%d\n", rc);
@@ -2931,6 +3348,15 @@
 			pr_debug("failed to enable IR drop comp rc=%d\n", rc);
 			return rc;
 		}
+
+		rc = qpnp_chg_read(chip, &chip->trim_center,
+				chip->buck_base + BUCK_CTRL_TRIM1, 1);
+		if (rc) {
+			pr_debug("failed to read trim center rc=%d\n", rc);
+			return rc;
+		}
+		chip->trim_center >>= 4;
+		pr_debug("trim center = %02x\n", chip->trim_center);
 		break;
 	case SMBB_BAT_IF_SUBTYPE:
 	case SMBBP_BAT_IF_SUBTYPE:
@@ -2968,6 +3394,32 @@
 			pr_debug("failed to force on VREF_BAT_THM rc=%d\n", rc);
 			return rc;
 		}
+
+		init_data = of_get_regulator_init_data(chip->dev,
+					       spmi_resource->of_node);
+
+		if (init_data->constraints.name) {
+			rdesc			= &(chip->batfet_vreg.rdesc);
+			rdesc->owner		= THIS_MODULE;
+			rdesc->type		= REGULATOR_VOLTAGE;
+			rdesc->ops		= &qpnp_chg_batfet_vreg_ops;
+			rdesc->name		= init_data->constraints.name;
+
+			init_data->constraints.valid_ops_mask
+				|= REGULATOR_CHANGE_STATUS;
+
+			chip->batfet_vreg.rdev = regulator_register(rdesc,
+					chip->dev, init_data, chip,
+					spmi_resource->of_node);
+			if (IS_ERR(chip->batfet_vreg.rdev)) {
+				rc = PTR_ERR(chip->batfet_vreg.rdev);
+				chip->batfet_vreg.rdev = NULL;
+				if (rc != -EPROBE_DEFER)
+					pr_err("batfet reg failed, rc=%d\n",
+							rc);
+				return rc;
+			}
+		}
 		break;
 	case SMBB_USB_CHGPTH_SUBTYPE:
 	case SMBBP_USB_CHGPTH_SUBTYPE:
@@ -3173,7 +3625,7 @@
 	}
 
 	/* Look up JEITA compliance parameters if cool and warm temp provided */
-	if (chip->cool_bat_decidegc && chip->warm_bat_decidegc) {
+	if (chip->cool_bat_decidegc || chip->warm_bat_decidegc) {
 		chip->adc_tm_dev = qpnp_get_adc_tm(chip->dev, "chg");
 		if (IS_ERR(chip->adc_tm_dev)) {
 			rc = PTR_ERR(chip->adc_tm_dev);
@@ -3265,6 +3717,11 @@
 	}
 
 	mutex_init(&chip->jeita_configure_lock);
+	alarm_init(&chip->reduce_power_stage_alarm, ANDROID_ALARM_RTC_WAKEUP,
+			qpnp_chg_reduce_power_stage_callback);
+	INIT_WORK(&chip->reduce_power_stage_work,
+			qpnp_chg_reduce_power_stage_work);
+
 	/* Get all device tree properties */
 	rc = qpnp_charger_read_dt_props(chip);
 	if (rc)
@@ -3306,11 +3763,11 @@
 				if (rc != -EPROBE_DEFER)
 					pr_err("vadc property missing\n");
 				goto fail_chg_enable;
+			}
 
 			rc = qpnp_chg_load_battery_data(chip);
 			if (rc)
 				goto fail_chg_enable;
-			}
 		}
 	}
 
@@ -3370,16 +3827,6 @@
 				0xff,
 				0x00, 1);
 
-			rc = qpnp_chg_masked_write(chip,
-				chip->buck_base + SEC_ACCESS,
-				0xFF,
-				0xA5, 1);
-
-			rc = qpnp_chg_masked_write(chip,
-				chip->buck_base + BUCK_TEST_SMBC_MODES,
-				0xFF,
-				0x80, 1);
-
 			if (chip->duty_cycle_100p) {
 				rc = qpnp_buck_set_100_duty_cycle_enable(chip,
 						1);
@@ -3477,12 +3924,13 @@
 		}
 		INIT_WORK(&chip->adc_measure_work,
 			qpnp_bat_if_adc_measure_work);
+		INIT_WORK(&chip->adc_disable_work,
+			qpnp_bat_if_adc_disable_work);
 	}
 
-	wake_lock_init(&chip->eoc_wake_lock,
-		WAKE_LOCK_SUSPEND, "qpnp-chg-eoc-lock");
 	INIT_DELAYED_WORK(&chip->eoc_work, qpnp_eoc_work);
 	INIT_DELAYED_WORK(&chip->arb_stop_work, qpnp_arb_stop_work);
+	INIT_WORK(&chip->soc_check_work, qpnp_chg_soc_check_work);
 
 	if (chip->dc_chgpth_base) {
 		chip->dc_psy.name = "qpnp-dc";
@@ -3504,17 +3952,21 @@
 	}
 
 	/* Turn on appropriate workaround flags */
-	qpnp_chg_setup_flags(chip);
+	rc = qpnp_chg_setup_flags(chip);
+	if (rc < 0) {
+		pr_err("failed to setup flags rc=%d\n", rc);
+		goto unregister_dc_psy;
+	}
 
 	if (chip->maxinput_dc_ma && chip->dc_chgpth_base) {
 		rc = qpnp_chg_idcmax_set(chip, chip->maxinput_dc_ma);
 		if (rc) {
 			pr_err("Error setting idcmax property %d\n", rc);
-			goto unregister_batt;
+			goto unregister_dc_psy;
 		}
 	}
 
-	if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
+	if ((chip->cool_bat_decidegc || chip->warm_bat_decidegc)
 							&& chip->bat_if_base) {
 		chip->adc_param.low_temp = chip->cool_bat_decidegc;
 		chip->adc_param.high_temp = chip->warm_bat_decidegc;
@@ -3530,14 +3982,14 @@
 							&chip->adc_param);
 			if (rc) {
 				pr_err("request ADC error %d\n", rc);
-				goto fail_chg_enable;
+				goto unregister_dc_psy;
 			}
 		}
 	}
 	rc = qpnp_chg_bat_if_configure_btc(chip);
 	if (rc) {
 		pr_err("failed to configure btc %d\n", rc);
-		goto unregister_batt;
+		goto unregister_dc_psy;
 	}
 
 	qpnp_chg_charge_en(chip, !chip->charging_disabled);
@@ -3547,11 +3999,11 @@
 	rc = qpnp_chg_request_irqs(chip);
 	if (rc) {
 		pr_err("failed to request interrupts %d\n", rc);
-		goto unregister_batt;
+		goto unregister_dc_psy;
 	}
 
-	qpnp_chg_usb_usbin_valid_irq_handler(USBIN_VALID_IRQ, chip);
-	qpnp_chg_dc_dcin_valid_irq_handler(DCIN_VALID_IRQ, chip);
+	qpnp_chg_usb_usbin_valid_irq_handler(chip->usbin_valid.irq, chip);
+	qpnp_chg_dc_dcin_valid_irq_handler(chip->dcin_valid.irq, chip);
 	power_supply_set_present(chip->usb_psy,
 			qpnp_chg_is_usb_chg_plugged_in(chip));
 
@@ -3569,6 +4021,9 @@
 			get_prop_batt_health(chip));
 	return 0;
 
+unregister_dc_psy:
+	if (chip->dc_chgpth_base)
+		power_supply_unregister(&chip->dc_psy);
 unregister_batt:
 	if (chip->bat_if_base)
 		power_supply_unregister(&chip->batt_psy);
@@ -3585,7 +4040,7 @@
 qpnp_charger_remove(struct spmi_device *spmi)
 {
 	struct qpnp_chg_chip *chip = dev_get_drvdata(&spmi->dev);
-	if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
+	if ((chip->cool_bat_decidegc || chip->warm_bat_decidegc)
 						&& chip->batt_present) {
 		qpnp_adc_tm_disable_chan_meas(chip->adc_tm_dev,
 							&chip->adc_param);
diff --git a/drivers/rtc/alarm.c b/drivers/rtc/alarm.c
index e318ecf..1648cba 100644
--- a/drivers/rtc/alarm.c
+++ b/drivers/rtc/alarm.c
@@ -25,6 +25,7 @@
 
 #include <asm/mach/time.h>
 
+#define ALARM_DELTA 120
 #define ANDROID_ALARM_PRINT_ERROR (1U << 0)
 #define ANDROID_ALARM_PRINT_INIT_STATUS (1U << 1)
 #define ANDROID_ALARM_PRINT_TSET (1U << 2)
@@ -454,7 +455,7 @@
 			rtc_delta.tv_sec, rtc_delta.tv_nsec);
 		if (rtc_current_time + 1 >= rtc_alarm_time) {
 			pr_alarm(SUSPEND, "alarm about to go off\n");
-			memset(&rtc_alarm, 0, sizeof(rtc_alarm));
+			rtc_time_to_tm(0, &rtc_alarm.time);
 			rtc_alarm.enabled = 0;
 			rtc_set_alarm(alarm_rtc_dev, &rtc_alarm);
 
@@ -479,7 +480,7 @@
 
 	pr_alarm(SUSPEND, "alarm_resume(%p)\n", pdev);
 
-	memset(&alarm, 0, sizeof(alarm));
+	rtc_time_to_tm(0, &alarm.time);
 	alarm.enabled = 0;
 	rtc_set_alarm(alarm_rtc_dev, &alarm);
 
@@ -512,6 +513,15 @@
 	rtc_tm_to_time(&rtc_time, &rtc_secs);
 	alarm_delta = wall_time.tv_sec - rtc_secs;
 	alarm_time = power_on_alarm - alarm_delta;
+
+	/*
+	 * Substract ALARM_DELTA from actual alarm time
+	 * to powerup the device before actual alarm
+	 * expiration.
+	 */
+	if ((alarm_time - ALARM_DELTA) > rtc_secs)
+		alarm_time -= ALARM_DELTA;
+
 	if (alarm_time <= rtc_secs)
 		goto disable_alarm;
 
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 2f19863..0c9959c 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -226,6 +226,8 @@
 	u8 *puc;
 	int ret = 0;
 	u8 la = txn->la;
+	u8 txn_mt;
+	u16 txn_mc = txn->mc;
 	u8 wbuf[SLIM_MSGQ_BUF_LEN];
 
 	if (!pm_runtime_enabled(dev->dev) && dev->state == MSM_CTRL_ASLEEP &&
@@ -402,6 +404,14 @@
 		puc[1] += dev->port_b;
 	}
 	dev->err = 0;
+	/*
+	 * If it's a read txn, it may be freed if a response is received by
+	 * received thread before reaching end of this function.
+	 * mc, mt may have changed to convert standard slimbus code/type to
+	 * satellite user-defined message. Reinitialize again
+	 */
+	txn_mc = txn->mc;
+	txn_mt = txn->mt;
 	dev->wr_comp = &tx_sent;
 	ret = msm_send_msg_buf(dev, pbuf, txn->rl,
 			NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_TX_MSG);
@@ -427,7 +437,7 @@
 		void __iomem *ngd = dev->base + NGD_BASE(dev->ctrl.nr,
 							dev->ver);
 		dev_err(dev->dev, "TX failed :MC:0x%x,mt:0x%x, ret:%d, ver:%d",
-				txn->mc, txn->mt, ret, dev->ver);
+				txn_mc, txn_mt, ret, dev->ver);
 		conf = readl_relaxed(ngd);
 		stat = readl_relaxed(ngd + NGD_STATUS);
 		rx_msgq = readl_relaxed(ngd + NGD_RX_MSGQ_CFG);
@@ -438,10 +448,10 @@
 		pr_err("conf:0x%x,stat:0x%x,rxmsgq:0x%x", conf, stat, rx_msgq);
 		pr_err("int_stat:0x%x,int_en:0x%x,int_cll:0x%x", int_stat,
 						int_en, int_clr);
-	} else if (txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
-		(txn->mc == SLIM_USR_MC_CONNECT_SRC ||
-		 txn->mc == SLIM_USR_MC_CONNECT_SINK ||
-		 txn->mc == SLIM_USR_MC_DISCONNECT_PORT)) {
+	} else if (txn_mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
+		(txn_mc == SLIM_USR_MC_CONNECT_SRC ||
+		 txn_mc == SLIM_USR_MC_CONNECT_SINK ||
+		 txn_mc == SLIM_USR_MC_DISCONNECT_PORT)) {
 		int timeout;
 		mutex_unlock(&dev->tx_lock);
 		msm_slim_put_ctrl(dev);
@@ -461,7 +471,7 @@
 	}
 ngd_xfer_err:
 	mutex_unlock(&dev->tx_lock);
-	if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE)
+	if (txn_mc != SLIM_USR_MC_REPORT_SATELLITE)
 		msm_slim_put_ctrl(dev);
 	return ret ? ret : dev->err;
 }
@@ -988,7 +998,6 @@
 		container_of(qmi, struct msm_slim_ctrl, qmi);
 	struct slim_controller *ctrl = &dev->ctrl;
 	struct slim_device *sbdev;
-	int i;
 
 	ngd_slim_enable(dev, false);
 	/* disconnect BAM pipes */
@@ -997,14 +1006,9 @@
 	if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
 		dev->use_tx_msgqs = MSM_MSGQ_DOWN;
 	msm_slim_sps_exit(dev, false);
-	mutex_lock(&ctrl->m_ctrl);
 	/* device up should be called again after SSR */
 	list_for_each_entry(sbdev, &ctrl->devs, dev_list)
-		sbdev->notified = false;
-	/* invalidate logical addresses */
-	for (i = 0; i < ctrl->num_dev; i++)
-		ctrl->addrt[i].valid = false;
-	mutex_unlock(&ctrl->m_ctrl);
+		slim_report_absent(sbdev);
 	pr_info("SLIM ADSP SSR (DOWN) done");
 }
 
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index 201470f..b074289 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -286,20 +286,41 @@
 	.release	= slim_dev_release,
 };
 
-static void slim_report_present(struct work_struct *work)
+static void slim_report(struct work_struct *work)
 {
 	u8 laddr;
-	int ret;
+	int ret, i;
 	struct slim_driver *sbdrv;
 	struct slim_device *sbdev =
 			container_of(work, struct slim_device, wd);
-	if (sbdev->notified || !sbdev->dev.driver)
+	struct slim_controller *ctrl = sbdev->ctrl;
+	if (!sbdev->dev.driver)
+		return;
+	/* check if device-up or down needs to be called */
+	mutex_lock(&ctrl->m_ctrl);
+	/* address no longer valid, means device reported absent */
+	for (i = 0; i < ctrl->num_dev; i++) {
+		if (sbdev->laddr == ctrl->addrt[i].laddr &&
+			ctrl->addrt[i].valid == false &&
+			sbdev->notified)
+			break;
+	}
+	mutex_unlock(&ctrl->m_ctrl);
+	sbdrv = to_slim_driver(sbdev->dev.driver);
+	if (i < ctrl->num_dev) {
+		sbdev->notified = false;
+		if (sbdrv->device_down)
+			sbdrv->device_down(sbdev);
+		return;
+	}
+	if (sbdev->notified)
 		return;
 	ret = slim_get_logical_addr(sbdev, sbdev->e_addr, 6, &laddr);
-	sbdrv = to_slim_driver(sbdev->dev.driver);
-	if (!ret && sbdrv->device_up) {
-		sbdev->notified = true;
-		sbdrv->device_up(sbdev);
+	if (!ret) {
+		if (sbdrv)
+			sbdev->notified = true;
+		if (sbdrv->device_up)
+			sbdrv->device_up(sbdev);
 	}
 }
 
@@ -322,7 +343,7 @@
 	INIT_LIST_HEAD(&sbdev->mark_define);
 	INIT_LIST_HEAD(&sbdev->mark_suspend);
 	INIT_LIST_HEAD(&sbdev->mark_removal);
-	INIT_WORK(&sbdev->wd, slim_report_present);
+	INIT_WORK(&sbdev->wd, slim_report);
 	mutex_lock(&ctrl->m_ctrl);
 	list_add_tail(&sbdev->dev_list, &ctrl->devs);
 	mutex_unlock(&ctrl->m_ctrl);
@@ -604,6 +625,31 @@
 EXPORT_SYMBOL_GPL(slim_add_numbered_controller);
 
 /*
+ * slim_report_absent: Controller calls this function when a device
+ *	reports absent, OR when the device cannot be communicated with
+ * @sbdev: Device that cannot be reached, or sent report absent
+ */
+void slim_report_absent(struct slim_device *sbdev)
+{
+	struct slim_controller *ctrl;
+	int i;
+	if (!sbdev)
+		return;
+	ctrl = sbdev->ctrl;
+	if (!ctrl)
+		return;
+	/* invalidate logical addresses */
+	mutex_lock(&ctrl->m_ctrl);
+	for (i = 0; i < ctrl->num_dev; i++) {
+		if (sbdev->laddr == ctrl->addrt[i].laddr)
+			ctrl->addrt[i].valid = false;
+	}
+	mutex_unlock(&ctrl->m_ctrl);
+	queue_work(ctrl->wq, &sbdev->wd);
+}
+EXPORT_SYMBOL(slim_report_absent);
+
+/*
  * slim_msg_response: Deliver Message response received from a device to the
  *	framework.
  * @ctrl: Controller handle
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 25b4b5e..4512d02 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -2664,7 +2664,6 @@
 struct msm_spi_platform_data * __init msm_spi_dt_to_pdata(
 			struct platform_device *pdev, struct msm_spi *dd)
 {
-	int i;
 	struct msm_spi_platform_data *pdata;
 
 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
@@ -2725,10 +2724,6 @@
 			pdata->use_bam = false;
 		}
 	}
-
-	for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i)
-		dd->cs_gpios[i].valid = (dd->cs_gpios[i].gpio_num >= 0);
-
 	return pdata;
 }
 
@@ -2834,10 +2829,12 @@
 						i + ARRAY_SIZE(spi_rsrcs));
 			dd->cs_gpios[i].gpio_num = resource ?
 							resource->start : -1;
-			dd->cs_gpios[i].valid = 0;
 		}
 	}
 
+	for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i)
+		dd->cs_gpios[i].valid = 0;
+
 	dd->pdata = pdata;
 	resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!resource) {
diff --git a/drivers/spmi/qpnp-int.c b/drivers/spmi/qpnp-int.c
index 03e9021..3e14333 100644
--- a/drivers/spmi/qpnp-int.c
+++ b/drivers/spmi/qpnp-int.c
@@ -591,8 +591,9 @@
 }
 EXPORT_SYMBOL(qpnpint_unregister_controller);
 
-int qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
-		       struct qpnp_irq_spec *spec)
+static int __qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
+		       struct qpnp_irq_spec *spec,
+		       bool show)
 {
 	struct irq_domain *domain;
 	unsigned long hwirq, busno;
@@ -617,12 +618,40 @@
 	domain = chip_lookup[busno]->domain;
 	irq = irq_radix_revmap_lookup(domain, hwirq);
 
-	generic_handle_irq(irq);
+	if (show) {
+		struct irq_desc *desc;
+		const char *name = "null";
+
+		desc = irq_to_desc(irq);
+		if (desc == NULL)
+			name = "stray irq";
+		else if (desc->action && desc->action->name)
+			name = desc->action->name;
+
+		pr_warn("%d triggered [0x%01x, 0x%02x,0x%01x] %s\n",
+				irq, spec->slave, spec->per, spec->irq, name);
+	} else {
+		generic_handle_irq(irq);
+	}
 
 	return 0;
 }
+
+int qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
+		       struct qpnp_irq_spec *spec)
+{
+	return  __qpnpint_handle_irq(spmi_ctrl, spec, false);
+}
+
 EXPORT_SYMBOL(qpnpint_handle_irq);
 
+int qpnpint_show_irq(struct spmi_controller *spmi_ctrl,
+		       struct qpnp_irq_spec *spec)
+{
+	return  __qpnpint_handle_irq(spmi_ctrl, spec, true);
+}
+EXPORT_SYMBOL(qpnpint_show_irq);
+
 int __init qpnpint_of_init(struct device_node *node, struct device_node *parent)
 {
 	struct q_chip_data *chip_d;
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index f85a576..bc328e0 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -24,6 +24,7 @@
 #include <linux/of_spmi.h>
 #include <linux/module.h>
 #include <linux/seq_file.h>
+#include <linux/syscore_ops.h>
 #include <mach/qpnp-int.h>
 #include "spmi-dbgfs.h"
 
@@ -126,9 +127,12 @@
 	u32			mapping_table[SPMI_MAPPING_TABLE_LEN];
 };
 
+static struct spmi_pmic_arb_dev *the_pmic_arb;
+
 static u32 pmic_arb_read(struct spmi_pmic_arb_dev *dev, u32 offset)
 {
 	u32 val = readl_relaxed(dev->base + offset);
+
 	pr_debug("address 0x%p, val 0x%x\n", dev->base + offset, val);
 	return val;
 }
@@ -485,7 +489,7 @@
 }
 
 static irqreturn_t
-periph_interrupt(struct spmi_pmic_arb_dev *pmic_arb, u8 apid)
+periph_interrupt(struct spmi_pmic_arb_dev *pmic_arb, u8 apid, bool show)
 {
 	u16 ppid = get_peripheral_id(pmic_arb, apid);
 	void __iomem *intr = pmic_arb->intr;
@@ -511,10 +515,12 @@
 	/* Read the peripheral specific interrupt bits */
 	status = readl_relaxed(intr + SPMI_PIC_IRQ_STATUS(apid));
 
-	/* Clear the peripheral interrupts */
-	writel_relaxed(status, intr + SPMI_PIC_IRQ_CLEAR(apid));
-	/* Interrupt needs to be cleared/acknowledged before exiting ISR */
-	mb();
+	if (!show) {
+		/* Clear the peripheral interrupts */
+		writel_relaxed(status, intr + SPMI_PIC_IRQ_CLEAR(apid));
+		/* Irq needs to be cleared/acknowledged before exiting ISR */
+		mb();
+	}
 
 	dev_dbg(pmic_arb->dev,
 		"interrupt, apid:0x%x, sid:0x%x, pid:0x%x, intr:0x%x\n",
@@ -528,14 +534,20 @@
 				.per = pid,
 				.irq = i,
 			};
-			qpnpint_handle_irq(&pmic_arb->controller, &irq_spec);
+			if (show)
+				qpnpint_show_irq(&pmic_arb->controller,
+								&irq_spec);
+			else
+				qpnpint_handle_irq(&pmic_arb->controller,
+								&irq_spec);
 		}
 	}
 	return IRQ_HANDLED;
 }
 
 /* Peripheral interrupt handler */
-static irqreturn_t pmic_arb_periph_irq(int irq, void *dev_id)
+static irqreturn_t
+__pmic_arb_periph_irq(int irq, void *dev_id, bool show)
 {
 	struct spmi_pmic_arb_dev *pmic_arb = dev_id;
 	void __iomem *intr = pmic_arb->intr;
@@ -556,7 +568,8 @@
 		for (j = 0; status && j < 32; ++j, status >>= 1) {
 			if (status & 0x1) {
 				u8 id = (i * 32) + j;
-				ret |= periph_interrupt(pmic_arb, id);
+
+				ret |= periph_interrupt(pmic_arb, id, show);
 			}
 		}
 	}
@@ -564,6 +577,22 @@
 	return ret;
 }
 
+static irqreturn_t pmic_arb_periph_irq(int irq, void *dev_id)
+{
+	return __pmic_arb_periph_irq(irq, dev_id, false);
+}
+
+static void spmi_pmic_arb_resume(void)
+{
+	if (qpnpint_show_resume_irq())
+		__pmic_arb_periph_irq(the_pmic_arb->pic_irq,
+						the_pmic_arb, true);
+}
+
+static struct syscore_ops spmi_pmic_arb_syscore_ops = {
+	.resume = spmi_pmic_arb_resume,
+};
+
 /* Callback to register an APID for specific slave/peripheral */
 static int pmic_arb_intr_priv_data(struct spmi_controller *ctrl,
 				struct qpnp_irq_spec *spec, uint32_t *data)
@@ -766,6 +795,9 @@
 	pr_debug("PMIC Arb Version 0x%x\n",
 			pmic_arb_read(pmic_arb, PMIC_ARB_VERSION));
 
+	the_pmic_arb = pmic_arb;
+	register_syscore_ops(&spmi_pmic_arb_syscore_ops);
+
 	return 0;
 
 err_reg_controller:
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 69031dc..613af4e 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -164,7 +164,7 @@
 #define TSENS10_POINT2_BACKUP_MASK	0x3f000000
 
 #define TSENS_8X26_BASE0_MASK		0x1fe000
-#define TSENS0_8X26_POINT1_MASK		0x7f00000
+#define TSENS0_8X26_POINT1_MASK		0x7e00000
 #define TSENS1_8X26_POINT1_MASK		0x3f
 #define TSENS2_8X26_POINT1_MASK		0xfc0
 #define TSENS3_8X26_POINT1_MASK		0x3f000
@@ -174,11 +174,11 @@
 #define TSENS_8X26_TSENS_CAL_SEL	0xe0000000
 #define TSENS_8X26_BASE1_MASK		0xff
 #define TSENS0_8X26_POINT2_MASK		0x3f00
-#define TSENS1_8X26_POINT2_MASK		0xfc00
+#define TSENS1_8X26_POINT2_MASK		0xfc000
 #define TSENS2_8X26_POINT2_MASK		0x3f00000
 #define TSENS3_8X26_POINT2_MASK		0xfc000000
-#define TSENS4_8X26_POINT2_MASK		0xfc000000
-#define TSENS5_8X26_POINT2_MASK		0x3f00000
+#define TSENS4_8X26_POINT2_MASK		0x3f00000
+#define TSENS5_8X26_POINT2_MASK		0xfc000000
 #define TSENS6_8X26_POINT2_MASK		0x7e0000
 
 #define TSENS_8X26_CAL_SEL_SHIFT	29
@@ -664,6 +664,15 @@
 			lower_thr = true;
 		}
 		if (upper_thr || lower_thr) {
+			unsigned long temp;
+			enum thermal_trip_type trip =
+					THERMAL_TRIP_CONFIGURABLE_LOW;
+
+			if (upper_thr)
+				trip = THERMAL_TRIP_CONFIGURABLE_HI;
+			tsens_tz_get_temp(tm->sensor[i].tz_dev, &temp);
+			thermal_sensor_trip(tm->sensor[i].tz_dev, trip, temp);
+
 			/* Notify user space */
 			queue_work(tm->tsens_wq, &tm->sensor[i].work);
 			rc = tsens_get_sw_id_mapping(
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 974cadc..00df613 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -14,9 +14,11 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/kthread.h>
 #include <linux/mutex.h>
 #include <linux/msm_tsens.h>
 #include <linux/workqueue.h>
+#include <linux/completion.h>
 #include <linux/cpu.h>
 #include <linux/cpufreq.h>
 #include <linux/msm_tsens.h>
@@ -29,6 +31,7 @@
 #include <linux/sysfs.h>
 #include <linux/types.h>
 #include <linux/android_alarm.h>
+#include <linux/thermal.h>
 #include <mach/cpufreq.h>
 #include <mach/rpm-regulator.h>
 #include <mach/rpm-regulator-smd.h>
@@ -45,7 +48,10 @@
 static uint32_t wakeup_ms;
 static struct alarm thermal_rtc;
 static struct kobject *tt_kobj;
+static struct kobject *cc_kobj;
 static struct work_struct timer_work;
+static struct task_struct *hotplug_task;
+static struct completion hotplug_notify_complete;
 
 static int enabled;
 static int rails_cnt;
@@ -67,6 +73,14 @@
 static DEFINE_MUTEX(vdd_rstr_mutex);
 static DEFINE_MUTEX(psm_mutex);
 
+struct cpu_info {
+	uint32_t cpu;
+	bool offline;
+	bool user_offline;
+	const char *sensor_type;
+	struct sensor_threshold thresh[2];
+};
+
 struct rail {
 	const char *name;
 	uint32_t freq_req;
@@ -91,6 +105,7 @@
 
 static struct psm_rail *psm_rails;
 static struct rail *rails;
+static struct cpu_info cpus[NR_CPUS];
 
 struct vdd_rstr_enable {
 	struct kobj_attribute ko_attr;
@@ -658,11 +673,67 @@
 	}
 	mutex_unlock(&core_control_mutex);
 }
+/* Call with core_control_mutex locked */
+static int __ref update_offline_cores(int val)
+{
+	int cpu = 0;
+	int ret = 0;
+
+	if (!core_control_enabled)
+		return 0;
+
+	cpus_offlined = msm_thermal_info.core_control_mask & val;
+
+	for_each_possible_cpu(cpu) {
+		if (!(cpus_offlined & BIT(cpu)))
+			continue;
+		if (!cpu_online(cpu))
+			continue;
+		ret = cpu_down(cpu);
+		if (ret)
+			pr_err("%s: Unable to offline cpu%d\n",
+				KBUILD_MODNAME, cpu);
+	}
+	return ret;
+}
+
+static __ref int do_hotplug(void *data)
+{
+	int ret = 0;
+	int cpu = 0;
+	uint32_t mask = 0;
+
+	if (!core_control_enabled)
+		return -EINVAL;
+
+	while (!kthread_should_stop()) {
+		wait_for_completion(&hotplug_notify_complete);
+		INIT_COMPLETION(hotplug_notify_complete);
+		mask = 0;
+
+		mutex_lock(&core_control_mutex);
+		for_each_possible_cpu(cpu) {
+			if (cpus[cpu].offline || cpus[cpu].user_offline)
+				mask |= BIT(cpu);
+		}
+		if (mask != cpus_offlined)
+			update_offline_cores(mask);
+		mutex_unlock(&core_control_mutex);
+		sysfs_notify(cc_kobj, NULL, "cpus_offlined");
+	}
+
+	return ret;
+}
 #else
 static void do_core_control(long temp)
 {
 	return;
 }
+
+static __ref int do_hotplug(void *data)
+{
+	return 0;
+}
 #endif
 
 static int do_vdd_restriction(void)
@@ -848,7 +919,7 @@
 		if (core_control_enabled &&
 			(msm_thermal_info.core_control_mask & BIT(cpu)) &&
 			(cpus_offlined & BIT(cpu))) {
-			pr_info(
+			pr_debug(
 			"%s: Preventing cpu%d from coming online.\n",
 				KBUILD_MODNAME, cpu);
 			return NOTIFY_BAD;
@@ -896,6 +967,112 @@
 			ts.tv_sec, ts.tv_usec);
 }
 
+static int hotplug_notify(enum thermal_trip_type type, int temp, void *data)
+{
+	struct cpu_info *cpu_node = (struct cpu_info *)data;
+
+	pr_info("%s: %s reach temp threshold: %d\n", KBUILD_MODNAME,
+			cpu_node->sensor_type, temp);
+
+	if (!(msm_thermal_info.core_control_mask & BIT(cpu_node->cpu)))
+		return 0;
+	switch (type) {
+	case THERMAL_TRIP_CONFIGURABLE_HI:
+		if (!(cpu_node->offline))
+			cpu_node->offline = 1;
+		break;
+	case THERMAL_TRIP_CONFIGURABLE_LOW:
+		if (cpu_node->offline)
+			cpu_node->offline = 0;
+		break;
+	default:
+		break;
+	}
+	if (hotplug_task)
+		complete(&hotplug_notify_complete);
+	else
+		pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME);
+	return 0;
+}
+/* Adjust cpus offlined bit based on temperature reading. */
+static int hotplug_init_cpu_offlined(void)
+{
+	struct tsens_device tsens_dev;
+	long temp = 0;
+	int cpu = 0;
+
+	mutex_lock(&core_control_mutex);
+	for_each_possible_cpu(cpu) {
+		if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
+			continue;
+		tsens_dev.sensor_num = sensor_get_id(\
+				(char *)cpus[cpu].sensor_type);
+		if (tsens_get_temp(&tsens_dev, &temp)) {
+			pr_err("%s: Unable to read TSENS sensor %d\n",
+				KBUILD_MODNAME, tsens_dev.sensor_num);
+			return -EINVAL;
+		}
+
+		if (temp >= msm_thermal_info.hotplug_temp_degC)
+			cpus[cpu].offline = 1;
+		else if (temp <= (msm_thermal_info.hotplug_temp_degC -
+			msm_thermal_info.hotplug_temp_hysteresis_degC))
+			cpus[cpu].offline = 0;
+	}
+	mutex_unlock(&core_control_mutex);
+
+	if (hotplug_task)
+		complete(&hotplug_notify_complete);
+	else {
+		pr_err("%s: Hotplug task is not initialized\n",
+					KBUILD_MODNAME);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void hotplug_init(void)
+{
+	int cpu = 0;
+
+	if (hotplug_task)
+		return;
+
+	for_each_possible_cpu(cpu) {
+		if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
+			continue;
+		cpus[cpu].cpu = (uint32_t)cpu;
+		cpus[cpu].thresh[0].temp = msm_thermal_info.hotplug_temp_degC;
+		cpus[cpu].thresh[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
+		cpus[cpu].thresh[0].notify = hotplug_notify;
+		cpus[cpu].thresh[0].data = (void *)&cpus[cpu];
+		sensor_set_trip(sensor_get_id((char *)cpus[cpu].sensor_type),
+				&cpus[cpu].thresh[0]);
+
+		cpus[cpu].thresh[1].temp = msm_thermal_info.hotplug_temp_degC -
+				msm_thermal_info.hotplug_temp_hysteresis_degC;
+		cpus[cpu].thresh[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
+		cpus[cpu].thresh[1].notify = hotplug_notify;
+		cpus[cpu].thresh[1].data = (void *)&cpus[cpu];
+		sensor_set_trip(sensor_get_id((char *)cpus[cpu].sensor_type),
+				&cpus[cpu].thresh[1]);
+
+	}
+	init_completion(&hotplug_notify_complete);
+	hotplug_task = kthread_run(do_hotplug, NULL, "msm_thermal:hotplug");
+	if (IS_ERR(hotplug_task)) {
+		pr_err("%s: Failed to create do_hotplug thread\n",
+				KBUILD_MODNAME);
+		return;
+	}
+	/*
+	 * Adjust cpus offlined bit when hotplug intitializes so that the new
+	 * cpus offlined state is based on hotplug threshold range
+	 */
+	if (hotplug_init_cpu_offlined())
+		kthread_stop(hotplug_task);
+}
+
 /*
  * We will reset the cpu frequencies limits here. The core online/offline
  * status will be carried over to the process stopping the msm_thermal, as
@@ -922,9 +1099,10 @@
 	int ret = 0;
 
 	ret = param_set_bool(val, kp);
-	if (!enabled)
+	if (!enabled) {
 		disable_msm_thermal();
-	else
+		hotplug_init();
+	} else
 		pr_info("%s: no action for enabled = %d\n",
 				KBUILD_MODNAME, enabled);
 
@@ -941,37 +1119,6 @@
 module_param_cb(enabled, &module_ops, &enabled, 0644);
 MODULE_PARM_DESC(enabled, "enforce thermal limit on cpu");
 
-
-#ifdef CONFIG_SMP
-/* Call with core_control_mutex locked */
-static int __ref update_offline_cores(int val)
-{
-	int cpu = 0;
-	int ret = 0;
-
-	cpus_offlined = msm_thermal_info.core_control_mask & val;
-	if (!core_control_enabled)
-		return 0;
-
-	for_each_possible_cpu(cpu) {
-		if (!(cpus_offlined & BIT(cpu)))
-			continue;
-		if (!cpu_online(cpu))
-			continue;
-		ret = cpu_down(cpu);
-		if (ret)
-			pr_err("%s: Unable to offline cpu%d\n",
-				KBUILD_MODNAME, cpu);
-	}
-	return ret;
-}
-#else
-static int update_offline_cores(int val)
-{
-	return 0;
-}
-#endif
-
 static ssize_t show_cc_enabled(struct kobject *kobj,
 		struct kobj_attribute *attr, char *buf)
 {
@@ -984,7 +1131,6 @@
 	int ret = 0;
 	int val = 0;
 
-	mutex_lock(&core_control_mutex);
 	ret = kstrtoint(buf, 10, &val);
 	if (ret) {
 		pr_err("%s: Invalid input %s\n", KBUILD_MODNAME, buf);
@@ -998,14 +1144,17 @@
 	if (core_control_enabled) {
 		pr_info("%s: Core control enabled\n", KBUILD_MODNAME);
 		register_cpu_notifier(&msm_thermal_cpu_notifier);
-		update_offline_cores(cpus_offlined);
+		if (hotplug_task)
+			complete(&hotplug_notify_complete);
+		else
+			pr_err("%s: Hotplug task is not initialized\n",
+					KBUILD_MODNAME);
 	} else {
 		pr_info("%s: Core control disabled\n", KBUILD_MODNAME);
 		unregister_cpu_notifier(&msm_thermal_cpu_notifier);
 	}
 
 done_store_cc:
-	mutex_unlock(&core_control_mutex);
 	return count;
 }
 
@@ -1020,6 +1169,7 @@
 {
 	int ret = 0;
 	uint32_t val = 0;
+	int cpu;
 
 	mutex_lock(&core_control_mutex);
 	ret = kstrtouint(buf, 10, &val);
@@ -1034,10 +1184,16 @@
 		goto done_cc;
 	}
 
-	if (cpus_offlined == val)
-		goto done_cc;
+	for_each_possible_cpu(cpu) {
+		if (!(msm_thermal_info.core_control_mask & BIT(cpu)))
+			continue;
+		cpus[cpu].user_offline = !!(val & BIT(cpu));
+	}
 
-	update_offline_cores(val);
+	if (hotplug_task)
+		complete(&hotplug_notify_complete);
+	else
+		pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME);
 done_cc:
 	mutex_unlock(&core_control_mutex);
 	return count;
@@ -1108,7 +1264,6 @@
 static __init int msm_thermal_add_cc_nodes(void)
 {
 	struct kobject *module_kobj = NULL;
-	struct kobject *cc_kobj = NULL;
 	int ret = 0;
 
 	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
@@ -1190,8 +1345,7 @@
 		return -EINVAL;
 
 	enabled = 1;
-	if (num_possible_cpus() > 1)
-		core_control_enabled = 1;
+
 	INIT_DELAYED_WORK(&check_temp_work, check_temp);
 	schedule_delayed_work(&check_temp_work, 0);
 
@@ -1602,12 +1756,76 @@
 	return ret;
 }
 
+static int probe_cc(struct device_node *node, struct msm_thermal_data *data,
+		struct platform_device *pdev)
+{
+	char *key = NULL;
+	int cpu_cnt = 0;
+	int ret = 0;
+	int cpu = 0;
+
+	key = "qcom,core-limit-temp";
+	ret = of_property_read_u32(node, key, &data->core_limit_temp_degC);
+	if (ret)
+		goto read_node_fail;
+
+	key = "qcom,core-temp-hysteresis";
+	ret = of_property_read_u32(node, key, &data->core_temp_hysteresis_degC);
+	if (ret)
+		goto read_node_fail;
+
+	key = "qcom,core-control-mask";
+	ret = of_property_read_u32(node, key, &data->core_control_mask);
+	if (ret)
+		goto read_node_fail;
+
+	key = "qcom,hotplug-temp";
+	ret = of_property_read_u32(node, key, &data->hotplug_temp_degC);
+	if (ret)
+		goto read_node_fail;
+
+	key = "qcom,hotplug-temp-hysteresis";
+	ret = of_property_read_u32(node, key,
+			&data->hotplug_temp_hysteresis_degC);
+	if (ret)
+		goto read_node_fail;
+
+	key = "qcom,cpu-sensors";
+	cpu_cnt = of_property_count_strings(node, key);
+	if (cpu_cnt != num_possible_cpus()) {
+		pr_err("%s: Wrong number of cpu\n", KBUILD_MODNAME);
+		goto read_node_fail;
+	}
+
+	for_each_possible_cpu(cpu) {
+		cpus[cpu].cpu = cpu;
+		cpus[cpu].offline = 0;
+		cpus[cpu].user_offline = 0;
+		ret = of_property_read_string_index(node, key, cpu,
+				&cpus[cpu].sensor_type);
+		if (ret)
+			goto read_node_fail;
+	}
+
+	if (num_possible_cpus() > 1)
+		core_control_enabled = 1;
+
+read_node_fail:
+	if (ret) {
+		dev_info(&pdev->dev,
+			"%s:Failed reading node=%s, key=%s. KTM continues\n",
+			KBUILD_MODNAME, node->full_name, key);
+		core_control_enabled = 0;
+	}
+
+	return ret;
+}
+
 static int __devinit msm_thermal_dev_probe(struct platform_device *pdev)
 {
 	int ret = 0;
 	char *key = NULL;
 	struct device_node *node = pdev->dev.of_node;
-
 	struct msm_thermal_data data;
 
 	memset(&data, 0, sizeof(struct msm_thermal_data));
@@ -1640,15 +1858,7 @@
 	key = "qcom,freq-control-mask";
 	ret = of_property_read_u32(node, key, &data.freq_control_mask);
 
-	key = "qcom,core-limit-temp";
-	ret = of_property_read_u32(node, key, &data.core_limit_temp_degC);
-
-	key = "qcom,core-temp-hysteresis";
-	ret = of_property_read_u32(node, key, &data.core_temp_hysteresis_degC);
-
-	key = "qcom,core-control-mask";
-	ret = of_property_read_u32(node, key, &data.core_control_mask);
-
+	ret = probe_cc(node, &data, pdev);
 	/*
 	 * Probe optional properties below. Call probe_psm before
 	 * probe_vdd_rstr because rpm_regulator_get has to be called
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index 5b78cdd..467d89d 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -1324,15 +1324,6 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t qpnp_adc_tm_isr(int irq, void *data)
-{
-	struct qpnp_adc_tm_chip *chip = data;
-
-	complete(&chip->adc->adc_rslt_completion);
-
-	return IRQ_HANDLED;
-}
-
 static int qpnp_adc_read_temp(struct thermal_zone_device *thermal,
 			     unsigned long *temp)
 {
@@ -1620,17 +1611,6 @@
 		goto fail;
 	}
 
-	rc = devm_request_irq(&spmi->dev, chip->adc->adc_irq_eoc,
-				qpnp_adc_tm_isr, IRQF_TRIGGER_RISING,
-				"qpnp_adc_tm_interrupt", chip);
-	if (rc) {
-		dev_err(&spmi->dev,
-			"failed to request adc irq with error %d\n", rc);
-		goto fail;
-	} else {
-		enable_irq_wake(chip->adc->adc_irq_eoc);
-	}
-
 	rc = devm_request_irq(&spmi->dev, chip->adc->adc_high_thr_irq,
 				qpnp_adc_tm_high_thr_isr,
 		IRQF_TRIGGER_RISING, "qpnp_adc_tm_high_interrupt", chip);
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index fd1a2fc..1cf901e 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -4,6 +4,7 @@
  *  Copyright (C) 2008 Intel Corp
  *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
  *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
+ *  Copyright (c) 2013, The Linux Foundation. All rights reserved.
  *
  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *
@@ -60,6 +61,273 @@
 static LIST_HEAD(thermal_cdev_list);
 static DEFINE_MUTEX(thermal_list_lock);
 
+static LIST_HEAD(sensor_info_list);
+static DEFINE_MUTEX(sensor_list_lock);
+
+static struct sensor_info *get_sensor(uint32_t sensor_id)
+{
+	struct sensor_info *pos, *var;
+
+	list_for_each_entry_safe(pos, var, &sensor_info_list, sensor_list) {
+		if (pos->sensor_id == sensor_id)
+			break;
+	}
+
+	return pos;
+}
+
+int sensor_get_id(char *name)
+{
+	struct sensor_info *pos, *var;
+
+	list_for_each_entry_safe(pos, var, &sensor_info_list, sensor_list) {
+		if (!strcmp(pos->tz->type, name))
+			return pos->sensor_id;
+	}
+
+	return -ENODEV;
+}
+EXPORT_SYMBOL(sensor_get_id);
+
+static void __update_sensor_thresholds(struct sensor_info *sensor)
+{
+	int min = INT_MIN;
+	int max = INT_MAX;
+	struct sensor_threshold *pos, *var;
+	enum thermal_trip_type type;
+	int i;
+	unsigned long curr_temp;
+
+	for (i = 0; ((sensor->max_idx == -1) || (sensor->min_idx == -1)) &&
+		(sensor->tz->ops->get_trip_type) && (i < sensor->tz->trips);
+		i++) {
+		sensor->tz->ops->get_trip_type(sensor->tz, i, &type);
+		if (type == THERMAL_TRIP_CONFIGURABLE_HI)
+			sensor->max_idx = i;
+		if (type == THERMAL_TRIP_CONFIGURABLE_LOW)
+			sensor->min_idx = i;
+	}
+
+	get_cpu();
+	sensor->tz->ops->get_temp(sensor->tz, &curr_temp);
+	list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
+		if ((pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW) &&
+				(pos->temp < (int)curr_temp))
+			if (pos->temp > min)
+				min = pos->temp;
+		if ((pos->trip == THERMAL_TRIP_CONFIGURABLE_HI) &&
+				(pos->temp > (int)curr_temp))
+			if (pos->temp < max)
+				max = pos->temp;
+	}
+	put_cpu();
+
+	if (sensor->tz->ops->set_trip_temp) {
+		if (max != INT_MAX) {
+			sensor->tz->ops->set_trip_temp(sensor->tz,
+				sensor->max_idx, max);
+			sensor->threshold_max = max;
+		}
+		if (min != INT_MIN) {
+			sensor->tz->ops->set_trip_temp(sensor->tz,
+				sensor->min_idx, min);
+			sensor->threshold_min = min;
+		}
+	}
+
+	pr_debug("sensor %d, min: %d, max %d\n", sensor->sensor_id, min, max);
+}
+
+static void sensor_update_work(struct work_struct *work)
+{
+	struct sensor_info *sensor = container_of(work, struct sensor_info,
+						work);
+	mutex_lock(&sensor->lock);
+	__update_sensor_thresholds(sensor);
+	mutex_unlock(&sensor->lock);
+}
+
+/* May be called in an interrupt context.
+ * Do NOT call sensor_set_trip from this function
+ */
+int thermal_sensor_trip(struct thermal_zone_device *tz,
+		enum thermal_trip_type trip, unsigned long temp)
+{
+	struct sensor_threshold *pos, *var;
+	int ret = -ENODEV;
+
+	if (trip != THERMAL_TRIP_CONFIGURABLE_HI &&
+			trip != THERMAL_TRIP_CONFIGURABLE_LOW)
+		return 0;
+
+	if (list_empty(&tz->sensor.threshold_list))
+		return 0;
+
+	list_for_each_entry_safe(pos, var, &tz->sensor.threshold_list, list) {
+		if (pos->trip != trip)
+			continue;
+		if (((trip == THERMAL_TRIP_CONFIGURABLE_LOW) &&
+			(pos->temp <= tz->sensor.threshold_min) &&
+			(pos->temp >= (int) temp)) ||
+			((trip == THERMAL_TRIP_CONFIGURABLE_HI) &&
+				(pos->temp >= tz->sensor.threshold_max) &&
+				(pos->temp <= (int)temp))) {
+			pos->notify(trip, temp, pos->data);
+		}
+	}
+
+	schedule_work(&tz->sensor.work);
+
+	return ret;
+}
+EXPORT_SYMBOL(thermal_sensor_trip);
+
+int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold)
+{
+	struct sensor_threshold *pos, *var;
+	struct sensor_info *sensor = get_sensor(sensor_id);
+
+	if (!sensor)
+		return -ENODEV;
+
+	if (!threshold || !threshold->notify)
+		return -EFAULT;
+
+	mutex_lock(&sensor->lock);
+	list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
+		if (pos == threshold)
+			break;
+	}
+
+	if (pos != threshold) {
+		INIT_LIST_HEAD(&threshold->list);
+		list_add(&threshold->list, &sensor->threshold_list);
+	}
+
+	__update_sensor_thresholds(sensor);
+	mutex_unlock(&sensor->lock);
+
+	return 0;
+
+}
+EXPORT_SYMBOL(sensor_set_trip);
+
+int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold)
+{
+	struct sensor_threshold *pos, *var;
+	struct sensor_info *sensor = get_sensor(sensor_id);
+
+	if (!sensor)
+		return -ENODEV;
+
+	mutex_lock(&sensor->lock);
+	list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
+		if (pos == threshold) {
+			list_del(&pos->list);
+			break;
+		}
+	}
+
+	__update_sensor_thresholds(sensor);
+	mutex_unlock(&sensor->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(sensor_cancel_trip);
+
+static int sensor_get_trip_temp(struct thermal_zone_device *tz,
+		int type, unsigned long *temp)
+{
+	struct sensor_info *sensor = get_sensor(tz->id);
+
+	if (!sensor)
+		return -EFAULT;
+
+	switch (type) {
+	case THERMAL_TRIP_CONFIGURABLE_HI:
+		*temp = tz->sensor.threshold_max;
+		break;
+	case THERMAL_TRIP_CONFIGURABLE_LOW:
+		*temp = tz->sensor.threshold_min;
+		break;
+	default:
+		tz->ops->get_trip_temp(tz, type, temp);
+		break;
+	}
+
+	return 0;
+}
+
+static int tz_notify_trip(enum thermal_trip_type type, int temp, void *data)
+{
+	struct thermal_zone_device *tz = (struct thermal_zone_device *)data;
+
+	pr_debug("sensor %d tripped: type %d temp %d\n",
+			tz->sensor.sensor_id, type, temp);
+
+	return 0;
+}
+
+int sensor_set_trip_temp(struct thermal_zone_device *tz,
+		int trip, long temp)
+{
+	int ret = 0;
+	enum thermal_trip_type type;
+
+	if (!tz->ops->get_trip_type)
+		return -EPERM;
+
+	tz->ops->get_trip_type(tz, trip, &type);
+	switch (type) {
+	case THERMAL_TRIP_CONFIGURABLE_HI:
+		tz->tz_threshold[0].temp = temp;
+		tz->tz_threshold[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
+		tz->tz_threshold[0].notify = tz_notify_trip;
+		tz->tz_threshold[0].data = tz;
+		ret = sensor_set_trip(tz->sensor.sensor_id,
+					&tz->tz_threshold[0]);
+		break;
+	case THERMAL_TRIP_CONFIGURABLE_LOW:
+		tz->tz_threshold[1].temp = temp;
+		tz->tz_threshold[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
+		tz->tz_threshold[1].notify = tz_notify_trip;
+		tz->tz_threshold[1].data = tz;
+		ret = sensor_set_trip(tz->sensor.sensor_id,
+					&tz->tz_threshold[1]);
+		break;
+	default:
+		ret = tz->ops->set_trip_temp(tz, trip, temp);
+		break;
+	}
+
+	return ret;
+}
+
+int sensor_init(struct thermal_zone_device *tz)
+{
+	struct sensor_info *sensor = &tz->sensor;
+
+	sensor->sensor_id = tz->id;
+	sensor->tz = tz;
+	sensor->threshold_min = 0;
+	sensor->threshold_max = INT_MAX;
+	sensor->max_idx = -1;
+	sensor->min_idx = -1;
+	mutex_init(&sensor->lock);
+	INIT_LIST_HEAD(&sensor->sensor_list);
+	INIT_LIST_HEAD(&sensor->threshold_list);
+	INIT_LIST_HEAD(&tz->tz_threshold[0].list);
+	INIT_LIST_HEAD(&tz->tz_threshold[1].list);
+	tz->tz_threshold[0].notify = NULL;
+	tz->tz_threshold[0].data = NULL;
+	tz->tz_threshold[1].notify = NULL;
+	tz->tz_threshold[1].data = NULL;
+	list_add(&sensor->sensor_list, &sensor_info_list);
+	INIT_WORK(&sensor->work, sensor_update_work);
+
+	return 0;
+}
+
 static int get_idr(struct idr *idr, struct mutex *lock, int *id)
 {
 	int err;
@@ -243,7 +511,7 @@
 	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
 		return -EINVAL;
 
-	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
+	ret = sensor_get_trip_temp(tz, trip, &temperature);
 
 	if (ret)
 		return ret;
@@ -268,7 +536,8 @@
 	if (!sscanf(buf, "%ld", &temperature))
 		return -EINVAL;
 
-	ret = tz->ops->set_trip_temp(tz, trip, temperature);
+	ret = sensor_set_trip_temp(tz, trip, temperature);
+
 	if (ret)
 		return ret;
 
@@ -1313,6 +1582,7 @@
 		if (result)
 			break;
 		}
+	sensor_init(tz);
 	mutex_unlock(&thermal_list_lock);
 
 	INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
@@ -1372,6 +1642,10 @@
 				   &trip_point_attrs[count * 2 + 1]);
 	}
 	thermal_remove_hwmon_sysfs(tz);
+	flush_work(&tz->sensor.work);
+	mutex_lock(&thermal_list_lock);
+	list_del(&tz->sensor.sensor_list);
+	mutex_unlock(&thermal_list_lock);
 	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
 	idr_destroy(&tz->idr);
 	mutex_destroy(&tz->lock);
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index d520253..a4a4f28 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -47,6 +47,8 @@
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/wakelock.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
 #include <mach/board.h>
 #include <mach/msm_serial_hs_lite.h>
 #include <mach/msm_bus.h>
@@ -166,12 +168,17 @@
 static inline void msm_hsl_write(struct uart_port *port,
 				 unsigned int val, unsigned int off)
 {
-	iowrite32(val, port->membase + off);
+	__iowmb();
+	__raw_writel_no_log((__force __u32)cpu_to_le32(val),
+		port->membase + off);
 }
 static inline unsigned int msm_hsl_read(struct uart_port *port,
 		     unsigned int off)
 {
-	return ioread32(port->membase + off);
+	unsigned int v = le32_to_cpu((__force __le32)__raw_readl_no_log(
+		port->membase + off));
+	__iormb();
+	return v;
 }
 
 static unsigned int msm_serial_hsl_has_gsbi(struct uart_port *port)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index db6fec9..98c6884 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -111,7 +111,33 @@
 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
 	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
 	reg |= DWC3_GCTL_PRTCAPDIR(mode);
+	/*
+	 * Set this bit so that device attempts three more times at SS, even
+	 * if it failed previously to operate in SS mode.
+	 */
+	reg |= DWC3_GCTL_U2RSTECN;
+	if (mode == DWC3_GCTL_PRTCAP_HOST) {
+		/*
+		 * Allow ITP generated off of ref clk based counter instead
+		 * of UTMI/ULPI clk based counter, when superspeed only is
+		 * active so that UTMI/ULPI PHY can be suspened.
+		 */
+		reg |= DWC3_GCTL_SOFITPSYNC;
+		reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
+		reg |= DWC3_GCTL_PWRDNSCALE(2);
+	} else if (mode == DWC3_GCTL_PRTCAP_DEVICE) {
+		reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
+		reg |= DWC3_GCTL_PWRDNSCALE(2);
+		reg &= ~(DWC3_GCTL_SOFITPSYNC);
+	}
+	reg |= DWC3_GCTL_U2EXIT_LFPS;
 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+	reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+	reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 }
 
 /**
@@ -127,6 +153,9 @@
 	reg |= DWC3_GCTL_CORESOFTRESET;
 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 
+	if (dwc->revision >= DWC3_REVISION_230A)
+		dwc3_notify_event(dwc, DWC3_CONTROLLER_RESET_EVENT);
+
 	/* Assert USB3 PHY reset */
 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
 	reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
@@ -155,6 +184,9 @@
 	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
 	reg &= ~DWC3_GCTL_CORESOFTRESET;
 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+	if (dwc->revision >= DWC3_REVISION_230A)
+		dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT);
 }
 
 /**
@@ -473,6 +505,20 @@
 	dwc3_gadget_restart(dwc);
 }
 
+static void (*notify_event) (struct dwc3 *, unsigned);
+void dwc3_set_notifier(void (*notify)(struct dwc3 *, unsigned))
+{
+	notify_event = notify;
+}
+EXPORT_SYMBOL(dwc3_set_notifier);
+
+void dwc3_notify_event(struct dwc3 *dwc, unsigned event)
+{
+	if (dwc->notify_event)
+		dwc->notify_event(dwc, event);
+}
+EXPORT_SYMBOL(dwc3_notify_event);
+
 #define DWC3_ALIGN_MASK		(16 - 1)
 
 static u64 dwc3_dma_mask = DMA_BIT_MASK(64);
@@ -504,6 +550,7 @@
 	if (!dev->coherent_dma_mask)
 		dev->coherent_dma_mask = DMA_BIT_MASK(64);
 
+	dwc->notify_event = notify_event;
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!res) {
 		dev_err(dev, "missing IRQ\n");
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 2064c13..328f6f4 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -163,7 +163,10 @@
 
 /* Global Configuration Register */
 #define DWC3_GCTL_PWRDNSCALE(n)	((n) << 19)
+#define DWC3_GCTL_PWRDNSCALEMASK (0xFFF80000)
 #define DWC3_GCTL_U2RSTECN	(1 << 16)
+#define DWC3_GCTL_SOFITPSYNC	(1 << 10)
+#define DWC3_GCTL_U2EXIT_LFPS	(1 << 2)
 #define DWC3_GCTL_RAMCLKSEL(x)	(((x) & DWC3_GCTL_CLK_MASK) << 6)
 #define DWC3_GCTL_CLK_BUS	(0)
 #define DWC3_GCTL_CLK_PIPE	(1)
@@ -643,6 +646,9 @@
 	__le64	dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS];
 };
 
+#define DWC3_CONTROLLER_ERROR_EVENT			0
+#define DWC3_CONTROLLER_RESET_EVENT			1
+#define DWC3_CONTROLLER_POST_RESET_EVENT		2
 /**
  * struct dwc3 - representation of our controller
  * @ctrl_req: usb control request which is used for ep0
@@ -771,6 +777,7 @@
 
 	/* Indicate if software connect was issued by the usb_gadget_driver */
 	bool			softconnect;
+	void (*notify_event) (struct dwc3 *, unsigned);
 };
 
 /* -------------------------------------------------------------------------- */
@@ -922,6 +929,9 @@
 void dwc3_post_host_reset_core_init(struct dwc3 *dwc);
 int dwc3_event_buffers_setup(struct dwc3 *dwc);
 
+extern void dwc3_set_notifier(
+		void (*notify) (struct dwc3 *dwc3, unsigned event));
+extern void dwc3_notify_event(struct dwc3 *dwc3, unsigned event);
 extern int dwc3_get_device_id(void);
 extern void dwc3_put_device_id(int id);
 
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
index b156c5f..4901f4b 100644
--- a/drivers/usb/dwc3/debug.h
+++ b/drivers/usb/dwc3/debug.h
@@ -46,6 +46,7 @@
 extern void dbg_setup(u8, const struct usb_ctrlrequest*);
 extern int dwc3_debugfs_init(struct dwc3 *);
 extern void dwc3_debugfs_exit(struct dwc3 *);
+extern void dbg_print_reg(const char *name, int reg);
 #else
 static inline void dbg_event(u8, const char*, int)
 {  }
@@ -57,6 +58,8 @@
 {  }
 static inline void dbg_setup(u8, const struct usb_ctrlrequest*)
 {  }
+static inline void dbg_print_reg(const char *name, int reg)
+{  }
 static inline int dwc3_debugfs_init(struct dwc3 *d)
 {  return 0;  }
 static inline void dwc3_debugfs_exit(struct dwc3 *d)
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index df95646..a2580fc 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -972,6 +972,28 @@
 }
 
 /**
+ * dbg_print_reg: prints a reg value
+ * @name:   reg name
+ * @reg: reg value to be printed
+ */
+void dbg_print_reg(const char *name, int reg)
+{
+	unsigned long flags;
+
+	write_lock_irqsave(&dbg_dwc3_data.lck, flags);
+
+	scnprintf(dbg_dwc3_data.buf[dbg_dwc3_data.idx], DBG_DATA_MSG,
+		  "%s = 0x%08x\n", name, reg);
+
+	dbg_inc(&dbg_dwc3_data.idx);
+
+	write_unlock_irqrestore(&dbg_dwc3_data.lck, flags);
+
+	if (dbg_dwc3_data.tty != 0)
+		pr_notice("%s = 0x%08x\n", name, reg);
+}
+
+/**
  * store_events: configure if events are going to be also printed to console
  *
  */
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index d3ea3be..d7721dc 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -50,6 +50,7 @@
 #include "dwc3_otg.h"
 #include "core.h"
 #include "gadget.h"
+#include "debug.h"
 
 /* ADC threshold values */
 static int adc_low_threshold = 700;
@@ -140,6 +141,7 @@
 #define QSCRATCH_REG_OFFSET	(0x000F8800)
 #define QSCRATCH_CTRL_REG      (QSCRATCH_REG_OFFSET + 0x04)
 #define QSCRATCH_GENERAL_CFG	(QSCRATCH_REG_OFFSET + 0x08)
+#define QSCRATCH_RAM1_REG	(QSCRATCH_REG_OFFSET + 0x0C)
 #define HS_PHY_CTRL_REG		(QSCRATCH_REG_OFFSET + 0x10)
 #define PARAMETER_OVERRIDE_X_REG (QSCRATCH_REG_OFFSET + 0x14)
 #define CHARGING_DET_CTRL_REG	(QSCRATCH_REG_OFFSET + 0x18)
@@ -156,6 +158,8 @@
 #define SS_CR_PROTOCOL_CAP_DATA_REG (QSCRATCH_REG_OFFSET + 0x48)
 #define SS_CR_PROTOCOL_READ_REG     (QSCRATCH_REG_OFFSET + 0x4C)
 #define SS_CR_PROTOCOL_WRITE_REG    (QSCRATCH_REG_OFFSET + 0x50)
+#define PWR_EVNT_IRQ_STAT_REG    (QSCRATCH_REG_OFFSET + 0x58)
+#define PWR_EVNT_IRQ_MASK_REG    (QSCRATCH_REG_OFFSET + 0x5C)
 
 struct dwc3_msm_req_complete {
 	struct list_head list_item;
@@ -223,7 +227,7 @@
 	bool			ext_inuse;
 	enum dwc3_id_state	id_state;
 	unsigned long		lpm_flags;
-#define MDWC3_CORECLK_OFF		BIT(0)
+#define MDWC3_PHY_REF_AND_CORECLK_OFF	BIT(0)
 #define MDWC3_TCXO_SHUTDOWN		BIT(1)
 
 	u32 qscratch_ctl_val;
@@ -410,6 +414,37 @@
 }
 
 /**
+ * Dump all QSCRATCH registers.
+ *
+ */
+static void dwc3_msm_dump_phy_info(struct dwc3_msm *mdwc)
+{
+
+	dbg_print_reg("SSPHY_CTRL_REG", dwc3_msm_read_reg(mdwc->base,
+						SS_PHY_CTRL_REG));
+	dbg_print_reg("HSPHY_CTRL_REG", dwc3_msm_read_reg(mdwc->base,
+						HS_PHY_CTRL_REG));
+	dbg_print_reg("QSCRATCH_CTRL_REG", dwc3_msm_read_reg(mdwc->base,
+						QSCRATCH_CTRL_REG));
+	dbg_print_reg("QSCRATCH_GENERAL_CFG", dwc3_msm_read_reg(mdwc->base,
+						QSCRATCH_GENERAL_CFG));
+	dbg_print_reg("PARAMETER_OVERRIDE_X_REG", dwc3_msm_read_reg(mdwc->base,
+						PARAMETER_OVERRIDE_X_REG));
+	dbg_print_reg("HS_PHY_IRQ_STAT_REG", dwc3_msm_read_reg(mdwc->base,
+						HS_PHY_IRQ_STAT_REG));
+	dbg_print_reg("SS_PHY_PARAM_CTRL_1", dwc3_msm_read_reg(mdwc->base,
+						SS_PHY_PARAM_CTRL_1));
+	dbg_print_reg("SS_PHY_PARAM_CTRL_2", dwc3_msm_read_reg(mdwc->base,
+						SS_PHY_PARAM_CTRL_2));
+	dbg_print_reg("QSCRATCH_RAM1_REG", dwc3_msm_read_reg(mdwc->base,
+						QSCRATCH_RAM1_REG));
+	dbg_print_reg("PWR_EVNT_IRQ_STAT_REG", dwc3_msm_read_reg(mdwc->base,
+						PWR_EVNT_IRQ_STAT_REG));
+	dbg_print_reg("PWR_EVNT_IRQ_MASK_REG", dwc3_msm_read_reg(mdwc->base,
+						PWR_EVNT_IRQ_MASK_REG));
+}
+
+/**
  * Return DBM EP number according to usb endpoint number.
  *
  */
@@ -1381,8 +1416,14 @@
 }
 
 /* Initialize QSCRATCH registers for HSPHY and SSPHY operation */
-static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *mdwc)
+static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *mdwc,
+						unsigned event_status)
 {
+	if (event_status == DWC3_CONTROLLER_POST_RESET_EVENT) {
+		dwc3_msm_ss_phy_reg_init(mdwc);
+		return;
+	}
+
 	/* SSPHY Initialization: Use ref_clk from pads and set its parameters */
 	dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210002);
 	msleep(30);
@@ -1393,7 +1434,7 @@
 	dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210002);
 	usleep_range(2000, 2200);
 	/* Ref clock must be stable now, enable ref clock for HS mode */
-	dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210102);
+	dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x11210102);
 	usleep_range(2000, 2200);
 	/*
 	 * HSPHY Initialization: Enable UTMI clock and clamp enable HVINTs,
@@ -1401,8 +1442,8 @@
 	 */
 	dwc3_msm_write_reg(mdwc->base, HS_PHY_CTRL_REG, 0x5220bb2);
 	usleep_range(2000, 2200);
-	/* Disable (bypass) VBUS and ID filters */
-	dwc3_msm_write_reg(mdwc->base, QSCRATCH_GENERAL_CFG, 0x78);
+	/* Set XHCI_REV bit (2) to 1 - XHCI version 1.0 */
+	dwc3_msm_write_reg(mdwc->base, QSCRATCH_GENERAL_CFG, 0x4);
 	/*
 	 * write HSPHY init value to QSCRATCH reg to set HSPHY parameters like
 	 * VBUS valid threshold, disconnect valid threshold, DC voltage level,
@@ -1415,14 +1456,14 @@
 					PARAMETER_OVERRIDE_X_REG, 0x03FFFFFF,
 					mdwc->hsphy_init_seq & 0x03FFFFFF);
 
-	/* Enable master clock for RAMs to allow BAM to access RAMs when
-	 * RAM clock gating is enabled via DWC3's GCTL. Otherwise, issues
+	/*
+	 * Enable master clock for RAMs to allow BAM to access RAMs when
+	 * RAM clock gating is enabled via DWC3's GCTL. Otherwise issues
 	 * are seen where RAM clocks get turned OFF in SS mode
 	 */
 	dwc3_msm_write_reg(mdwc->base, CGCTL_REG,
 		dwc3_msm_read_reg(mdwc->base, CGCTL_REG) | 0x18);
 
-	dwc3_msm_ss_phy_reg_init(mdwc);
 	/*
 	 * This is required to restore the POR value after userspace
 	 * is done with charger detection.
@@ -1431,6 +1472,31 @@
 		dwc3_msm_read_reg(mdwc->base, QSCRATCH_CTRL_REG);
 }
 
+static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned event)
+{
+	struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
+
+	switch (event) {
+	case DWC3_CONTROLLER_ERROR_EVENT:
+		dev_info(mdwc->dev, "DWC3_CONTROLLER_ERROR_EVENT received\n");
+		dwc3_msm_dump_phy_info(mdwc);
+		break;
+	case DWC3_CONTROLLER_RESET_EVENT:
+		dev_dbg(mdwc->dev, "DWC3_CONTROLLER_RESET_EVENT received\n");
+		dwc3_msm_qscratch_reg_init(mdwc, DWC3_CONTROLLER_RESET_EVENT);
+		break;
+	case DWC3_CONTROLLER_POST_RESET_EVENT:
+		dev_dbg(mdwc->dev,
+				"DWC3_CONTROLLER_POST_RESET_EVENT received\n");
+		dwc3_msm_qscratch_reg_init(mdwc,
+					DWC3_CONTROLLER_POST_RESET_EVENT);
+		break;
+	default:
+		dev_dbg(mdwc->dev, "unknown dwc3 event\n");
+		break;
+	}
+}
+
 static void dwc3_msm_block_reset(struct dwc3_ext_xceiv *xceiv, bool core_reset)
 {
 	struct dwc3_msm *mdwc = container_of(xceiv, struct dwc3_msm, ext_xceiv);
@@ -1447,9 +1513,6 @@
 			return;
 
 		usleep_range(10000, 12000);
-
-		/* Reinitialize QSCRATCH registers after block reset */
-		dwc3_msm_qscratch_reg_init(mdwc);
 	}
 
 	/* Reset the DBM */
@@ -1687,6 +1750,7 @@
 	bool dcp;
 	bool host_bus_suspend;
 	bool host_ss_active;
+	bool host_ss_suspend;
 
 	dev_dbg(mdwc->dev, "%s: entering lpm\n", __func__);
 
@@ -1713,6 +1777,7 @@
 	      (mdwc->charger.chg_type == DWC3_PROPRIETARY_CHARGER) ||
 	      (mdwc->charger.chg_type == DWC3_FLOATED_CHARGER));
 	host_bus_suspend = mdwc->host_mode == 1;
+	host_ss_suspend = host_bus_suspend && host_ss_active;
 
 	if (!dcp && !host_bus_suspend)
 		dwc3_msm_write_reg(mdwc->base, QSCRATCH_CTRL_REG,
@@ -1724,13 +1789,17 @@
 	 * 3. Set TEST_POWERED_DOWN in SS_PHY_CTRL_REG to enable PHY retention
 	 * 4. Disable SSPHY ref clk
 	 */
-	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8), 0x0);
-	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28), 0x0);
-	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26),
+	if (!host_ss_suspend) {
+		dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8),
+									0x0);
+		dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28),
+									0x0);
+		dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26),
 								(1 << 26));
-
+	}
 	usleep_range(1000, 1200);
-	clk_disable_unprepare(mdwc->ref_clk);
+	if (!host_ss_suspend)
+		clk_disable_unprepare(mdwc->ref_clk);
 
 	if (host_bus_suspend) {
 		/* Sequence for host bus suspend case:
@@ -1775,9 +1844,9 @@
 	if (!host_bus_suspend)
 		dwc3_msm_config_gdsc(mdwc, 0);
 
-	if (!host_bus_suspend || !host_ss_active) {
+	if (!host_ss_suspend) {
 		clk_disable_unprepare(mdwc->core_clk);
-		mdwc->lpm_flags |= MDWC3_CORECLK_OFF;
+		mdwc->lpm_flags |= MDWC3_PHY_REF_AND_CORECLK_OFF;
 	}
 	clk_disable_unprepare(mdwc->iface_clk);
 
@@ -1825,6 +1894,7 @@
 	int ret;
 	bool dcp;
 	bool host_bus_suspend;
+	bool resume_from_core_clk_off = false;
 
 	dev_dbg(mdwc->dev, "%s: exiting lpm\n", __func__);
 
@@ -1835,6 +1905,9 @@
 
 	pm_stay_awake(mdwc->dev);
 
+	if (mdwc->lpm_flags & MDWC3_PHY_REF_AND_CORECLK_OFF)
+		resume_from_core_clk_off = true;
+
 	if (mdwc->bus_perf_client) {
 		ret = msm_bus_scale_client_update_request(
 						mdwc->bus_perf_client, 1);
@@ -1873,13 +1946,14 @@
 	if (!host_bus_suspend && !dcp)
 		dwc3_hsusb_config_vddcx(mdwc, 1);
 
-	clk_prepare_enable(mdwc->ref_clk);
+	if (mdwc->lpm_flags & MDWC3_PHY_REF_AND_CORECLK_OFF)
+		clk_prepare_enable(mdwc->ref_clk);
 	usleep_range(1000, 1200);
 
 	clk_prepare_enable(mdwc->iface_clk);
-	if (mdwc->lpm_flags & MDWC3_CORECLK_OFF) {
+	if (mdwc->lpm_flags & MDWC3_PHY_REF_AND_CORECLK_OFF) {
 		clk_prepare_enable(mdwc->core_clk);
-		mdwc->lpm_flags &= ~MDWC3_CORECLK_OFF;
+		mdwc->lpm_flags &= ~MDWC3_PHY_REF_AND_CORECLK_OFF;
 	}
 
 	if (host_bus_suspend) {
@@ -1892,10 +1966,6 @@
 
 		/* Disable DP and DM HV interrupt */
 		dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0x000);
-
-		/* Clear suspend bit in GUSB2PHYCONFIG register */
-		dwc3_msm_write_readback(mdwc->base, DWC3_GUSB2PHYCFG(0),
-								0x40, 0x0);
 	} else {
 		/* Disable HV interrupt */
 		if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
@@ -1919,23 +1989,27 @@
 
 	}
 
-	/* Assert SS PHY RESET */
-	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
+	if (resume_from_core_clk_off) {
+		/* Assert SS PHY RESET */
+		dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
 								(1 << 7));
-	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28),
+		dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28),
 								(1 << 28));
-	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8),
+		dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8),
 								(1 << 8));
-	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26), 0x0);
-	/* 10usec delay required before de-asserting SS PHY RESET */
-	udelay(10);
-	dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7), 0x0);
+		dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26),
+									0x0);
+		/* 10usec delay required before de-asserting SS PHY RESET */
+		udelay(10);
+		dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
+									0x0);
 
-	/*
-	 * Reinitilize SSPHY parameters as SS_PHY RESET will reset
-	 * the internal registers to default values.
-	 */
-	dwc3_msm_ss_phy_reg_init(mdwc);
+		/*
+		 * Reinitilize SSPHY parameters as SS_PHY RESET will reset
+		 * the internal registers to default values.
+		 */
+		dwc3_msm_ss_phy_reg_init(mdwc);
+	}
 	atomic_set(&mdwc->in_lpm, 0);
 
 	/* match disable_irq call from isr */
@@ -2072,7 +2146,7 @@
 
 static struct dentry *dwc3_debugfs_root;
 
-static void dwc3_debugfs_init(struct dwc3_msm *mdwc)
+static void dwc3_msm_debugfs_init(struct dwc3_msm *mdwc)
 {
 	dwc3_debugfs_root = debugfs_create_dir("msm_dwc3", NULL);
 
@@ -2871,8 +2945,6 @@
 	else if (!mdwc->hsphy_init_seq)
 		dev_warn(&pdev->dev, "incorrect hsphyinitseq.Using PORvalue\n");
 
-	dwc3_msm_qscratch_reg_init(mdwc);
-
 	pm_runtime_set_active(mdwc->dev);
 	pm_runtime_enable(mdwc->dev);
 
@@ -2891,7 +2963,7 @@
 		ret = -ENODEV;
 		goto disable_hs_ldo;
 	}
-
+	dwc3_set_notifier(&dwc3_msm_notify_event);
 	/* usb_psy required only for vbus_notifications or charging support */
 	if (mdwc->ext_xceiv.otg_capability ||
 			!mdwc->charger.charging_disabled) {
@@ -2990,7 +3062,7 @@
 
 	device_init_wakeup(mdwc->dev, 1);
 	pm_stay_awake(mdwc->dev);
-	dwc3_debugfs_init(mdwc);
+	dwc3_msm_debugfs_init(mdwc);
 
 	return 0;
 
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index d0d9d34..e912e86 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -56,6 +56,19 @@
 		reg = dwc3_readl(dwc->regs, DWC3_GCTL);
 		reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
 		reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_HOST);
+		/*
+		 * Allow ITP generated off of ref clk based counter instead
+		 * of UTMI/ULPI clk based counter, when superspeed only is
+		 * active so that UTMI/ULPI can be suspened.
+		 */
+		reg |= DWC3_GCTL_SOFITPSYNC;
+		/*
+		 * Set this bit so that device attempts three more times at SS,
+		 * even if it failed previously to operate in SS mode.
+		 */
+		reg |= DWC3_GCTL_U2RSTECN;
+		reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
+		reg |= DWC3_GCTL_PWRDNSCALE(2);
 		dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 	}
 }
@@ -126,6 +139,14 @@
 		reg = dwc3_readl(dwc->regs, DWC3_GCTL);
 		reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
 		reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE);
+		/*
+		 * Set this bit so that device attempts three more times at SS,
+		 * even if it failed previously to operate in SS mode.
+	 */
+		reg |= DWC3_GCTL_U2RSTECN;
+		reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
+		reg |= DWC3_GCTL_PWRDNSCALE(2);
+		reg &= ~(DWC3_GCTL_SOFITPSYNC);
 		dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 	}
 }
@@ -847,7 +868,8 @@
 	 * OCFG[1] - HNPCap = 0
 	 * OCFG[0] - SRPCap = 0
 	 */
-	dwc3_writel(dotg->regs, DWC3_OCFG, 0x4);
+	if (ext_xceiv && !ext_xceiv->otg_capability)
+		dwc3_writel(dotg->regs, DWC3_OCFG, 0x4);
 
 	/*
 	 * OCTL[6] - PeriMode = 1
@@ -859,7 +881,8 @@
 	 * OCTL[0] - HstSetHNPEn = 0
 	 */
 	if (!once) {
-		dwc3_writel(dotg->regs, DWC3_OCTL, 0x40);
+		if (ext_xceiv && !ext_xceiv->otg_capability)
+			dwc3_writel(dotg->regs, DWC3_OCTL, 0x40);
 		once++;
 	}
 
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index acda980..8cf8a6d 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -63,6 +63,9 @@
 MODULE_PARM_DESC(tx_fifo_resize_enable,
 			"Enable allocating Tx fifo for endpoints");
 
+static void dwc3_gadget_usb2_phy_suspend(struct dwc3 *dwc, int suspend);
+static void dwc3_gadget_usb3_phy_suspend(struct dwc3 *dwc, int suspend);
+
 /**
  * dwc3_gadget_set_test_mode - Enables USB2 Test Modes
  * @dwc: pointer to our context structure
@@ -322,6 +325,16 @@
 {
 	u32		timeout = 500;
 	u32		reg;
+	bool hsphy_suspend_enabled;
+	int ret;
+
+	/* Commands to controller will work only if PHY is not suspended */
+	hsphy_suspend_enabled = (dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)) &
+						DWC3_GUSB2PHYCFG_SUSPHY);
+
+	/* Disable suspend of the USB2 PHY */
+	if (hsphy_suspend_enabled)
+		dwc3_gadget_usb2_phy_suspend(dwc, false);
 
 	dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
 	dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
@@ -331,7 +344,8 @@
 		if (!(reg & DWC3_DGCMD_CMDACT)) {
 			dev_vdbg(dwc->dev, "Command Complete --> %d\n",
 					DWC3_DGCMD_STATUS(reg));
-			return 0;
+			ret = 0;
+			break;
 		}
 
 		/*
@@ -339,10 +353,18 @@
 		 * interrupt context.
 		 */
 		timeout--;
-		if (!timeout)
-			return -ETIMEDOUT;
+		if (!timeout) {
+			ret = -ETIMEDOUT;
+			break;
+		}
 		udelay(1);
 	} while (1);
+
+	/* Enable suspend of the USB2 PHY */
+	if (hsphy_suspend_enabled)
+		dwc3_gadget_usb2_phy_suspend(dwc, true);
+
+	return ret;
 }
 
 int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
@@ -351,12 +373,22 @@
 	struct dwc3_ep		*dep = dwc->eps[ep];
 	u32			timeout = 500;
 	u32			reg;
+	bool hsphy_suspend_enabled;
+	int ret;
 
 	dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n",
 			dep->name,
 			dwc3_gadget_ep_cmd_string(cmd), params->param0,
 			params->param1, params->param2);
 
+	/* Commands to controller will work only if PHY is not suspended */
+	hsphy_suspend_enabled = (dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)) &
+						DWC3_GUSB2PHYCFG_SUSPHY);
+
+	/* Disable suspend of the USB2 PHY */
+	if (hsphy_suspend_enabled)
+		dwc3_gadget_usb2_phy_suspend(dwc, false);
+
 	dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
 	dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1);
 	dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2);
@@ -374,9 +406,10 @@
 			 * event. Hence return error in this case.
 			 */
 			if (reg & 0x2000)
-				return -EAGAIN;
+				ret = -EAGAIN;
 			else
-				return 0;
+				ret = 0;
+			break;
 		}
 
 		/*
@@ -384,11 +417,19 @@
 		 * interrupt context.
 		 */
 		timeout--;
-		if (!timeout)
-			return -ETIMEDOUT;
+		if (!timeout) {
+			ret = -ETIMEDOUT;
+			break;
+		}
 
 		udelay(1);
 	} while (1);
+
+	/* Enable suspend of the USB2 PHY */
+	if (hsphy_suspend_enabled)
+		dwc3_gadget_usb2_phy_suspend(dwc, true);
+
+	return ret;
 }
 
 dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
@@ -1677,6 +1718,9 @@
 		reg |= DWC3_DCTL_HIRD_THRES(28);
 
 		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+		dwc3_gadget_usb2_phy_suspend(dwc, true);
+		dwc3_gadget_usb3_phy_suspend(dwc, true);
 	}
 
 	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
@@ -2572,6 +2616,35 @@
 	dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
 }
 
+static void dwc3_dump_reg_info(struct dwc3 *dwc)
+{
+	dbg_event(0xFF, "REGDUMP", 0);
+
+	dbg_print_reg("GUSB3PIPCTL", dwc3_readl(dwc->regs,
+							DWC3_GUSB3PIPECTL(0)));
+	dbg_print_reg("GUSB2PHYCONFIG", dwc3_readl(dwc->regs,
+							DWC3_GUSB2PHYCFG(0)));
+	dbg_print_reg("GCTL", dwc3_readl(dwc->regs, DWC3_GCTL));
+	dbg_print_reg("GUCTL", dwc3_readl(dwc->regs, DWC3_GUCTL));
+	dbg_print_reg("GDBGLTSSM", dwc3_readl(dwc->regs, DWC3_GDBGLTSSM));
+	dbg_print_reg("DCFG", dwc3_readl(dwc->regs, DWC3_DCFG));
+	dbg_print_reg("DCTL", dwc3_readl(dwc->regs, DWC3_DCTL));
+	dbg_print_reg("DEVTEN", dwc3_readl(dwc->regs, DWC3_DEVTEN));
+	dbg_print_reg("DSTS", dwc3_readl(dwc->regs, DWC3_DSTS));
+	dbg_print_reg("DALPENA", dwc3_readl(dwc->regs, DWC3_DALEPENA));
+	dbg_print_reg("DGCMD", dwc3_readl(dwc->regs, DWC3_DGCMD));
+
+	dbg_print_reg("OCFG", dwc3_readl(dwc->regs, DWC3_OCFG));
+	dbg_print_reg("OCTL", dwc3_readl(dwc->regs, DWC3_OCTL));
+	dbg_print_reg("OEVT", dwc3_readl(dwc->regs, DWC3_OEVT));
+	dbg_print_reg("OSTS", dwc3_readl(dwc->regs, DWC3_OSTS));
+
+	dwc3_notify_event(dwc, DWC3_CONTROLLER_ERROR_EVENT);
+
+	panic("DWC3 Erratic error\n");
+
+}
+
 static void dwc3_gadget_interrupt(struct dwc3 *dwc,
 		const struct dwc3_event_devt *event)
 {
@@ -2600,6 +2673,7 @@
 	case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
 		dbg_event(0xFF, "ERROR", 0);
 		dev_vdbg(dwc->dev, "Erratic Error\n");
+		dwc3_dump_reg_info(dwc);
 		break;
 	case DWC3_DEVICE_EVENT_CMD_CMPL:
 		dev_vdbg(dwc->dev, "Command Complete\n");
@@ -2824,8 +2898,8 @@
 
 		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 
-		dwc3_gadget_usb2_phy_suspend(dwc, false);
-		dwc3_gadget_usb3_phy_suspend(dwc, false);
+		dwc3_gadget_usb2_phy_suspend(dwc, true);
+		dwc3_gadget_usb3_phy_suspend(dwc, true);
 	}
 
 	ret = device_register(&dwc->gadget.dev);
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 38b1967..9b38ed3 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -388,22 +388,30 @@
 	}
 }
 
-static void android_enable(struct android_dev *dev)
+static int android_enable(struct android_dev *dev)
 {
 	struct usb_composite_dev *cdev = dev->cdev;
 	struct android_configuration *conf;
+	int err = 0;
 
 	if (WARN_ON(!dev->disable_depth))
-		return;
+		return err;
 
 	if (--dev->disable_depth == 0) {
 
-		list_for_each_entry(conf, &dev->configs, list_item)
-			usb_add_config(cdev, &conf->usb_config,
+		list_for_each_entry(conf, &dev->configs, list_item) {
+			err = usb_add_config(cdev, &conf->usb_config,
 						android_bind_config);
-
+			if (err < 0) {
+				pr_err("%s: usb_add_config failed : err: %d\n",
+						__func__, err);
+				return err;
+			}
+		}
 		usb_gadget_connect(cdev->gadget);
 	}
+
+	return err;
 }
 
 static void android_disable(struct android_dev *dev)
@@ -2130,7 +2138,18 @@
 	list_for_each_entry(f_holder, &conf->enabled_functions, enabled_list) {
 		ret = f_holder->f->bind_config(f_holder->f, c);
 		if (ret) {
-			pr_err("%s: %s failed", __func__, f_holder->f->name);
+			pr_err("%s: %s failed\n", __func__, f_holder->f->name);
+			while (!list_empty(&c->functions)) {
+				struct usb_function		*f;
+
+				f = list_first_entry(&c->functions,
+					struct usb_function, list);
+				list_del(&f->list);
+				if (f->unbind)
+					f->unbind(c, f);
+			}
+			if (c->unbind)
+				c->unbind(c);
 			return ret;
 		}
 	}
@@ -2347,7 +2366,7 @@
 	int enabled = 0;
 	bool audio_enabled = false;
 	static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
-
+	int err = 0;
 
 	if (!cdev)
 		return -ENODEV;
@@ -2382,7 +2401,14 @@
 			}
 		if (audio_enabled)
 			msleep(100);
-		android_enable(dev);
+		err = android_enable(dev);
+		if (err < 0) {
+			pr_err("%s: android_enable failed\n", __func__);
+			dev->connected = 0;
+			dev->enabled = false;
+			mutex_unlock(&dev->mutex);
+			return size;
+		}
 		dev->enabled = true;
 	} else if (!enabled && dev->enabled) {
 		android_disable(dev);
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 27d67e3..e4fb26a 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -824,6 +824,11 @@
 
 	spin_lock_irqsave(&cdev->lock, flags);
 
+	if (WARN_ON(!config->cdev)) {
+		spin_unlock_irqrestore(&cdev->lock, flags);
+		return 0;
+	}
+
 	if (cdev->config == config)
 		reset_config(cdev);
 
@@ -1220,6 +1225,15 @@
 			break;
 		if (w_value && !f->set_alt)
 			break;
+		/*
+		 * We put interfaces in default settings (alt 0)
+		 * upon set config#1. Call set_alt for non-zero
+		 * alternate setting.
+		 */
+		if (!w_value && cdev->config) {
+			value = 0;
+			break;
+		}
 		value = f->set_alt(f, w_index, w_value);
 		if (value == USB_GADGET_DELAYED_STATUS) {
 			DBG(cdev,
diff --git a/drivers/usb/gadget/f_qdss.c b/drivers/usb/gadget/f_qdss.c
index f90967f..3b94dd5 100644
--- a/drivers/usb/gadget/f_qdss.c
+++ b/drivers/usb/gadget/f_qdss.c
@@ -441,6 +441,10 @@
 
 	pr_debug("usb_qdss_disconnect_work\n");
 
+	status = uninit_data(qdss->data);
+	if (status)
+		pr_err("%s: uninit_data error\n", __func__);
+
 	/* notify qdss to cancell all active transfers*/
 	if (qdss->ch.notify) {
 		qdss->ch.notify(qdss->ch.priv, USB_QDSS_DISCONNECT, NULL,
@@ -458,22 +462,22 @@
 {
 	struct f_qdss	*qdss = func_to_qdss(f);
 	unsigned long flags;
-	int status;
 
 	pr_debug("qdss_disable\n");
 
 	spin_lock_irqsave(&qdss->lock, flags);
+	if (!qdss->usb_connected) {
+		spin_unlock_irqrestore(&qdss->lock, flags);
+		return;
+	}
+
 	qdss->usb_connected = 0;
 	spin_unlock_irqrestore(&qdss->lock, flags);
 
 	/*cancell all active xfers*/
 	qdss_eps_disable(f);
 
-	status = uninit_data(qdss->data);
-	if (status)
-		pr_err("%s: uninit_data error\n", __func__);
-
-	schedule_work(&qdss->disconnect_w);
+	queue_work(qdss->wq, &qdss->disconnect_w);
 }
 
 static void usb_qdss_connect_work(struct work_struct *work)
@@ -521,6 +525,7 @@
 	if (gadget->speed != USB_SPEED_SUPER &&
 		gadget->speed != USB_SPEED_HIGH) {
 			pr_err("qdss_st_alt: qdss supportes HS or SS only\n");
+			ret = -EINVAL;
 			goto fail;
 	}
 
@@ -562,7 +567,7 @@
 		qdss->usb_connected = 1;
 
 	if (qdss->usb_connected && ch->app_conn)
-		schedule_work(&qdss->connect_w);
+		queue_work(qdss->wq, &qdss->connect_w);
 
 	return 0;
 fail:
@@ -610,7 +615,13 @@
 			spin_unlock_irqrestore(&d_lock, flags);
 			return -ENOMEM;
 		}
-
+		spin_unlock_irqrestore(&d_lock, flags);
+		qdss->wq = create_singlethread_workqueue(name);
+		if (!qdss->wq) {
+			kfree(qdss);
+			return -ENOMEM;
+		}
+		spin_lock_irqsave(&d_lock, flags);
 		ch = &qdss->ch;
 		ch->name = name;
 		list_add_tail(&ch->list, &usb_qdss_ch_list);
@@ -765,6 +776,13 @@
 			spin_unlock_irqrestore(&d_lock, flags);
 			return ERR_PTR(-ENOMEM);
 		}
+		spin_unlock_irqrestore(&d_lock, flags);
+		qdss->wq = create_singlethread_workqueue(name);
+		if (!qdss->wq) {
+			kfree(qdss);
+			return ERR_PTR(-ENOMEM);
+		}
+		spin_lock_irqsave(&d_lock, flags);
 		ch = &qdss->ch;
 		list_add_tail(&ch->list, &usb_qdss_ch_list);
 	} else {
@@ -781,7 +799,7 @@
 
 	/* the case USB cabel was connected befor qdss called  qdss_open*/
 	if (qdss->usb_connected == 1)
-		schedule_work(&qdss->connect_w);
+		queue_work(qdss->wq, &qdss->connect_w);
 
 	return ch;
 }
@@ -819,7 +837,7 @@
 		_ch = list_entry(act, struct usb_qdss_ch, list);
 		qdss = container_of(_ch, struct f_qdss, ch);
 		spin_lock_irqsave(&d_lock, flags);
-
+		destroy_workqueue(qdss->wq);
 		if (!_ch->priv) {
 			list_del(&_ch->list);
 			kfree(qdss);
diff --git a/drivers/usb/gadget/f_qdss.h b/drivers/usb/gadget/f_qdss.h
index 93b5b1f..dcc80b7 100644
--- a/drivers/usb/gadget/f_qdss.h
+++ b/drivers/usb/gadget/f_qdss.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
 
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -38,6 +38,7 @@
 	unsigned int data_enabled:1;
 	unsigned int ctrl_in_enabled:1;
 	unsigned int ctrl_out_enabled:1;
+	struct workqueue_struct *wq;
 };
 
 #endif
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index f2de17d..5554085 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -25,6 +25,7 @@
 #include "dsi_v2.h"
 #include "dsi_io_v2.h"
 #include "dsi_host_v2.h"
+#include "mdss_debug.h"
 
 #define DSI_POLL_SLEEP_US 1000
 #define DSI_POLL_TIMEOUT_US 16000
@@ -38,7 +39,10 @@
 
 	int irq_no;
 	unsigned char *dsi_base;
+	size_t dsi_reg_size;
 	struct device dis_dev;
+
+	void (*debug_enable_clk)(int on);
 };
 
 static struct dsi_host_v2_private *dsi_host_private;
@@ -320,7 +324,7 @@
 	wmb();
 }
 
-void msm_dsi_set_tx_power_mode(int mode)
+void dsi_set_tx_power_mode(int mode)
 {
 	u32 data;
 	unsigned char *ctrl_base = dsi_host_private->dsi_base;
@@ -877,6 +881,38 @@
 	return 0;
 }
 
+static void msm_dsi_debug_enable_clock(int on)
+{
+	if (dsi_host_private->debug_enable_clk)
+		dsi_host_private->debug_enable_clk(on);
+
+	if (on)
+		msm_dsi_ahb_ctrl(1);
+	else
+		msm_dsi_ahb_ctrl(0);
+}
+
+static int msm_dsi_debug_init(void)
+{
+	int rc;
+
+	if (!mdss_res)
+		return 0;
+
+	dsi_host_private->debug_enable_clk =
+			mdss_res->debug_inf.debug_enable_clock;
+
+	mdss_res->debug_inf.debug_enable_clock = msm_dsi_debug_enable_clock;
+
+
+	rc = mdss_debug_register_base("dsi0",
+				dsi_host_private->dsi_base,
+				dsi_host_private->dsi_reg_size);
+
+	return rc;
+}
+
+
 static int __devinit msm_dsi_probe(struct platform_device *pdev)
 {
 	struct dsi_interface intf;
@@ -897,9 +933,11 @@
 				__func__, __LINE__);
 			return -ENOMEM;
 		} else {
+			dsi_host_private->dsi_reg_size =
+						resource_size(mdss_dsi_mres);
 			dsi_host_private->dsi_base = ioremap(
 						mdss_dsi_mres->start,
-						resource_size(mdss_dsi_mres));
+						dsi_host_private->dsi_reg_size);
 			if (!dsi_host_private->dsi_base) {
 				pr_err("%s:%d unable to remap dsi resources",
 					__func__, __LINE__);
@@ -952,6 +990,8 @@
 	intf.index = 0;
 	intf.private = NULL;
 	dsi_register_interface(&intf);
+
+	msm_dsi_debug_init();
 	pr_debug("%s success\n", __func__);
 	return 0;
 dsi_probe_error:
diff --git a/drivers/video/msm/mdss/dsi_io_v2.c b/drivers/video/msm/mdss/dsi_io_v2.c
index f0ad511..365c32f 100644
--- a/drivers/video/msm/mdss/dsi_io_v2.c
+++ b/drivers/video/msm/mdss/dsi_io_v2.c
@@ -41,19 +41,13 @@
 void msm_dsi_ahb_ctrl(int enable)
 {
 	if (enable) {
-		if (dsi_io_private->msm_dsi_ahb_clk_on) {
-			pr_debug("ahb clks already ON\n");
-			return;
-		}
-		clk_enable(dsi_io_private->dsi_ahb_clk);
-		dsi_io_private->msm_dsi_ahb_clk_on = 1;
+		dsi_io_private->msm_dsi_ahb_clk_on++;
+		if (dsi_io_private->msm_dsi_ahb_clk_on == 1)
+			clk_enable(dsi_io_private->dsi_ahb_clk);
 	} else {
-		if (dsi_io_private->msm_dsi_ahb_clk_on == 0) {
-			pr_debug("ahb clk already OFF\n");
-			return;
-		}
-		clk_disable(dsi_io_private->dsi_ahb_clk);
-		dsi_io_private->msm_dsi_ahb_clk_on = 0;
+		dsi_io_private->msm_dsi_ahb_clk_on--;
+		if (dsi_io_private->msm_dsi_ahb_clk_on == 0)
+			clk_disable(dsi_io_private->dsi_ahb_clk);
 	}
 }
 
diff --git a/drivers/video/msm/mdss/dsi_panel_v2.c b/drivers/video/msm/mdss/dsi_panel_v2.c
index 022d911..b1a4293 100644
--- a/drivers/video/msm/mdss/dsi_panel_v2.c
+++ b/drivers/video/msm/mdss/dsi_panel_v2.c
@@ -143,6 +143,29 @@
 	return 0;
 }
 
+static char led_pwm1[2] = {0x51, 0x0};	/* DTYPE_DCS_WRITE1 */
+static struct dsi_cmd_desc backlight_cmd = {
+	DTYPE_DCS_WRITE1, 1, 0, 0, 1, sizeof(led_pwm1), led_pwm1};
+
+static void dsi_panel_bklt_dcs(struct mdss_panel_data *pdata, int level)
+{
+	struct mipi_panel_info *mipi;
+
+	mipi  = &pdata->panel_info.mipi;
+
+	pr_debug("%s: dcs level=%d\n", __func__, level);
+
+	led_pwm1[1] = (unsigned char)level;
+
+	if (DSI_VIDEO_MODE == mipi->mode) {
+		dsi_set_tx_power_mode(0);
+		dsi_cmds_tx_v2(pdata, &panel_private->dsi_panel_tx_buf,
+					&backlight_cmd,
+					1);
+		dsi_set_tx_power_mode(1);
+	}
+}
+
 void dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
 {
 	if (pdata == NULL) {
@@ -166,13 +189,21 @@
 	if (enable == 2) {
 		dsi_panel_power(1);
 		gpio_request(panel_private->rst_gpio, "panel_reset");
+		gpio_set_value(panel_private->rst_gpio, 1);
 		if (gpio_is_valid(panel_private->disp_en_gpio)) {
 			gpio_request(panel_private->disp_en_gpio,
 					"panel_enable");
+			gpio_set_value(panel_private->disp_en_gpio, 1);
 		}
 		if (gpio_is_valid(panel_private->video_mode_gpio)) {
 			gpio_request(panel_private->video_mode_gpio,
 					"panel_video_mdoe");
+			if (pdata->panel_info.mipi.mode == DSI_VIDEO_MODE)
+				gpio_set_value(panel_private->video_mode_gpio,
+						1);
+			else
+				gpio_set_value(panel_private->video_mode_gpio,
+						0);
 		}
 		if (gpio_is_valid(panel_private->te_gpio))
 			gpio_request(panel_private->te_gpio, "panel_te");
@@ -233,6 +264,10 @@
 			led_trigger_event(bl_led_trigger, bl_level);
 			break;
 
+		case BL_DCS_CMD:
+			dsi_panel_bklt_dcs(pdata, bl_level);
+			break;
+
 		default:
 			pr_err("%s: Unknown bl_ctrl configuration\n",
 				__func__);
@@ -605,8 +640,11 @@
 		led_trigger_register_simple("bkl-trigger", &bl_led_trigger);
 		pr_debug("%s: SUCCESS-> WLED TRIGGER register\n", __func__);
 		*bl_ctrl = BL_WLED;
+	} else if ((bl_ctrl_type) && (!strncmp(bl_ctrl_type,
+				"bl_ctrl_dcs", 11))) {
+		pr_debug("%s: SUCCESS-> DCS COMMAND register\n", __func__);
+		*bl_ctrl = BL_DCS_CMD;
 	}
-
 	rc = of_property_read_u32_array(pdev->dev.of_node,
 		"qcom,mdss-pan-bl-levels", res, 2);
 	panel_data->panel_info.bl_min = (!rc ? res[0] : 0);
@@ -620,6 +658,7 @@
 	const char *pdest;
 	u32 tmp;
 	int rc;
+	bool cont_splash_enabled = false;
 
 	pdest = of_get_property(pdev->dev.of_node,
 				"qcom,mdss-pan-dest", NULL);
@@ -641,6 +680,17 @@
 		"qcom,mdss-pan-underflow-clr", &tmp);
 	panel_data->panel_info.lcdc.underflow_clr = (!rc ? tmp : 0xff);
 
+	cont_splash_enabled = of_property_read_bool(pdev->dev.of_node,
+		"qcom,cont-splash-enabled");
+	if (!cont_splash_enabled) {
+		pr_debug("%s:%d Continuous splash flag not found.\n",
+				__func__, __LINE__);
+		panel_data->panel_info.cont_splash_enabled = 0;
+	} else {
+		pr_debug("%s:%d Continuous splash flag enabled.\n",
+				__func__, __LINE__);
+		panel_data->panel_info.cont_splash_enabled = 1;
+	}
 	return rc;
 }
 
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index 96dd390..73df790 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -235,4 +235,6 @@
 
 int dsi_long_read_resp(struct dsi_buf *rp);
 
+void dsi_set_tx_power_mode(int mode);
+
 #endif /* MDSS_DSI_H */
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index f6f722e..66ad706 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -49,6 +49,7 @@
 #include "mdp3_hwio.h"
 #include "mdp3_ctrl.h"
 #include "mdp3_ppp.h"
+#include "mdss_debug.h"
 
 #define MDP_CORE_HW_VERSION	0x03040310
 struct mdp3_hw_resource *mdp3_res;
@@ -997,14 +998,6 @@
 		return xres * bpp;
 }
 
-void mdp3_fbmem_clear(void)
-{
-	if (mdp3_res->ion_handle && mdp3_res->virt) {
-		pr_debug("mdp3_fbmem_clear\n");
-		memset(mdp3_res->virt, 0, mdp3_res->size);
-	}
-}
-
 static int mdp3_alloc(size_t size, void **virt, unsigned long *phys)
 {
 	int ret = 0;
@@ -1057,76 +1050,16 @@
 	return -ENOMEM;
 }
 
-static int mdp3_fbmem_alloc(struct msm_fb_data_type *mfd)
-{
-	int ret = -ENOMEM, dom;
-	void *virt = NULL;
-	unsigned long phys = 0;
-	size_t size;
-	u32 yres = mfd->fbi->var.yres_virtual;
-
-	size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
-
-	if (mfd->index != 0) {
-		mfd->fbi->screen_base = virt;
-		mfd->fbi->fix.smem_start = phys;
-		mfd->fbi->fix.smem_len = 0;
-		return 0;
-	}
-
-	ret = mdp3_alloc(size, &virt, &phys);
-	if (ret) {
-		pr_err("fail to allocate fb memory\n");
-		return ret;
-	}
-
-	dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
-
-	ret = ion_map_iommu(mdp3_res->ion_client, mdp3_res->ion_handle,
-			dom, 0, SZ_4K, 0, &mfd->iova,
-			(unsigned long *)&size, 0, 0);
-
-	if (ret) {
-		pr_err("%s map IOMMU error\n", __func__);
-		goto ion_map_iommu_err;
-	}
-
-	pr_debug("allocating %u bytes at %p (%lx phys) for fb %d\n",
-			size, virt, phys, mfd->index);
-
-	mfd->fbi->screen_base = virt;
-	mfd->fbi->fix.smem_start = phys;
-	mfd->fbi->fix.smem_len = size;
-	return 0;
-
-ion_map_iommu_err:
-	ion_unmap_kernel(mdp3_res->ion_client, mdp3_res->ion_handle);
-	ion_free(mdp3_res->ion_client, mdp3_res->ion_handle);
-	mdp3_res->ion_handle = NULL;
-	mdp3_res->virt = NULL;
-	mdp3_res->phys = 0;
-	mdp3_res->size = 0;
-	return -ENOMEM;
-}
-
-void mdp3_fbmem_free(struct msm_fb_data_type *mfd)
+void mdp3_free(void)
 {
 	pr_debug("mdp3_fbmem_free\n");
 	if (mdp3_res->ion_handle) {
-		int dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
-
 		ion_unmap_kernel(mdp3_res->ion_client, mdp3_res->ion_handle);
-		ion_unmap_iommu(mdp3_res->ion_client,  mdp3_res->ion_handle,
-				dom, 0);
 		ion_free(mdp3_res->ion_client, mdp3_res->ion_handle);
 		mdp3_res->ion_handle = NULL;
 		mdp3_res->virt = NULL;
 		mdp3_res->phys = 0;
 		mdp3_res->size = 0;
-		mfd->fbi->screen_base = 0;
-		mfd->fbi->fix.smem_start = 0;
-		mfd->fbi->fix.smem_len = 0;
-		mfd->iova = 0;
 	}
 }
 
@@ -1173,6 +1106,11 @@
 	size_t size;
 	int rc;
 
+	if (pdata->panel_info.type != MIPI_VIDEO_PANEL) {
+		pr_debug("cmd mode panel, no need to copy splash image\n");
+		return 0;
+	}
+
 	rgb_size = MDP3_REG_READ(MDP3_REG_DMA_P_SIZE);
 	stride = MDP3_REG_READ(MDP3_REG_DMA_P_IBUF_Y_STRIDE);
 	stride = stride & 0x3FFF;
@@ -1180,7 +1118,7 @@
 
 	height = (rgb_size >> 16) & 0xffff;
 	width  = rgb_size & 0xffff;
-	size = PAGE_ALIGN(height * stride * 2);
+	size = PAGE_ALIGN(height * stride);
 	pr_debug("splash_height=%d splash_width=%d Buffer size=%d\n",
 		height, width, size);
 
@@ -1210,8 +1148,9 @@
 		status = MDP3_REG_READ(MDP3_REG_DSI_VIDEO_EN);
 		rc = status & 0x1;
 	} else {
-		status = MDP3_REG_READ(MDP3_REG_DMA_P_START);
-		rc = status & 01;
+		status = MDP3_REG_READ(MDP3_REG_DMA_P_CONFIG);
+		status &= 0x180000;
+		rc = (status == 0x080000);
 	}
 
 	mdp3_clk_update(MDP3_CLK_AHB, 0);
@@ -1285,17 +1224,62 @@
 			return 0;
 		}
 		rc = mdp3_continuous_splash_on(pdata);
+	} else {
+		if (mdp3_is_display_on(pdata)) {
+			pr_err("lk continuous splash, but kerenl not\n");
+			rc = mdp3_continuous_splash_on(pdata);
+		}
 	}
 	return rc;
 }
 
+static void mdp3_debug_enable_clock(int on)
+{
+	if (on)
+		mdp3_clk_enable(1);
+	else
+		mdp3_clk_enable(0);
+}
+
+static int mdp3_debug_init(struct platform_device *pdev)
+{
+	int rc;
+	struct mdss_data_type *mdata;
+
+	mdata = devm_kzalloc(&pdev->dev, sizeof(*mdata), GFP_KERNEL);
+	if (!mdata)
+		return -ENOMEM;
+
+	mdss_res = mdata;
+
+	mdata->debug_inf.debug_dump_stats = NULL;
+	mdata->debug_inf.debug_enable_clock = mdp3_debug_enable_clock;
+
+	rc = mdss_debugfs_init(mdata);
+	if (rc)
+		return rc;
+
+	rc = mdss_debug_register_base(NULL, mdp3_res->mdp_base ,
+					mdp3_res->mdp_reg_size);
+
+	return rc;
+}
+
+static void mdp3_debug_deinit(struct platform_device *pdev)
+{
+	if (mdss_res) {
+		mdss_debugfs_remove(mdss_res);
+		devm_kfree(&pdev->dev, mdss_res);
+		mdss_res = NULL;
+	}
+}
+
 static int mdp3_probe(struct platform_device *pdev)
 {
 	int rc;
 	static struct msm_mdp_interface mdp3_interface = {
 	.init_fnc = mdp3_init,
 	.fb_mem_get_iommu_domain = mdp3_fb_mem_get_iommu_domain,
-	.fb_mem_alloc_fnc = mdp3_fbmem_alloc,
 	.panel_register_done = mdp3_panel_register_done,
 	.fb_stride = mdp3_fb_stride,
 	};
@@ -1337,6 +1321,12 @@
 		goto probe_done;
 	}
 
+	rc = mdp3_debug_init(pdev);
+	if (rc) {
+		pr_err("unable to initialize mdp debugging\n");
+		goto probe_done;
+	}
+
 	rc = mdss_fb_register_mdp_instance(&mdp3_interface);
 	if (rc)
 		pr_err("unable to register mdp instance\n");
@@ -1350,6 +1340,11 @@
 
 		devm_kfree(&pdev->dev, mdp3_res);
 		mdp3_res = NULL;
+
+		if (mdss_res) {
+			devm_kfree(&pdev->dev, mdss_res);
+			mdss_res = NULL;
+		}
 	}
 
 	return rc;
@@ -1398,6 +1393,7 @@
 	pm_runtime_disable(&pdev->dev);
 	mdp3_bus_scale_unregister();
 	mdp3_clk_remove();
+	mdp3_debug_deinit(pdev);
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 03416c7..bd1c03d 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -155,9 +155,7 @@
 int mdp3_iommu_enable(int client);
 int mdp3_iommu_disable(int client);
 int mdp3_iommu_is_attached(int client);
-void mdp3_fbmem_free(struct msm_fb_data_type *mfd);
-void mdp3_fbmem_clear(void);
-
+void mdp3_free(void);
 
 #define MDP3_REG_WRITE(addr, val) writel_relaxed(val, mdp3_res->mdp_base + addr)
 #define MDP3_REG_READ(addr) readl_relaxed(mdp3_res->mdp_base + addr)
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index f77a2b3..bb53f33 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -88,20 +88,11 @@
 	return bufq->count;
 }
 
-static void mdp3_dispatch_vsync(struct work_struct *work)
-{
-	struct mdp3_session_data *mdp3_session;
-	mdp3_session = container_of(work, struct mdp3_session_data, vsync_work);
-	if (mdp3_session && mdp3_session->mfd)
-		sysfs_notify(&mdp3_session->mfd->fbi->dev->kobj, NULL,
-				"vsync_event");
-}
-
 void vsync_notify_handler(void *arg)
 {
 	struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
 	session->vsync_time = ktime_get();
-	schedule_work(&session->vsync_work);
+	sysfs_notify_dirent(session->vsync_event_sd);
 }
 
 static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable)
@@ -370,6 +361,14 @@
 	struct mdp3_dma_output_config outputConfig;
 	struct mdp3_dma_source sourceConfig;
 	int frame_rate = mfd->panel_info->mipi.frame_rate;
+	int vbp, vfp, vspw;
+	int vtotal, vporch;
+
+	vbp = panel_info->lcdc.v_back_porch;
+	vfp = panel_info->lcdc.v_front_porch;
+	vspw = panel_info->lcdc.v_pulse_width;
+	vporch = vbp + vfp + vspw;
+	vtotal = vporch + panel_info->yres;
 
 	fix = &fbi->fix;
 	var = &fbi->var;
@@ -381,8 +380,9 @@
 	sourceConfig.y = 0;
 	sourceConfig.stride = fix->line_length;
 	sourceConfig.buf = (void *)mfd->iova;
+	sourceConfig.vporch = vporch;
 	sourceConfig.vsync_count =
-		MDP_VSYNC_CLK_RATE / (frame_rate * sourceConfig.width);
+		MDP_VSYNC_CLK_RATE / (frame_rate * vtotal);
 
 	outputConfig.dither_en = 0;
 	outputConfig.out_sel = mdp3_ctrl_get_intf_type(mfd);
@@ -473,11 +473,6 @@
 		goto on_error;
 	}
 
-	mdp3_fbmem_clear();
-
-	if (panel->set_backlight)
-		panel->set_backlight(panel, panel->panel_info.bl_max);
-
 	pr_debug("mdp3_ctrl_on dma start\n");
 	if (mfd->fbi->screen_base) {
 		rc = mdp3_session->dma->start(mdp3_session->dma,
@@ -520,18 +515,16 @@
 
 	mdp3_histogram_stop(mdp3_session, MDP_BLOCK_DMA_P);
 
-	pr_debug("mdp3_ctrl_off turn panel off\n");
-	if (panel->set_backlight)
-		panel->set_backlight(panel, 0);
+	rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
+	if (rc)
+		pr_debug("fail to stop the MDP3 dma\n");
 
 	if (panel->event_handler)
 		rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
 	if (rc)
 		pr_err("fail to turn off the panel\n");
 
-	rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
-	if (rc)
-		pr_err("fail to stop the MDP3 dma\n");
+
 
 	mdp3_irq_deregister();
 
@@ -689,6 +682,7 @@
 		pr_debug("continuous splash screen, IOMMU not attached\n");
 		mdp3_ctrl_off(mfd);
 		mdp3_ctrl_on(mfd);
+		mdp3_free();
 	}
 
 	mutex_lock(&mdp3_session->lock);
@@ -704,9 +698,6 @@
 	if (mdp3_bufq_count(&mdp3_session->bufq_out) > 2) {
 		data = mdp3_bufq_pop(&mdp3_session->bufq_out);
 		mdp3_put_img(data);
-
-		if (mfd->fbi->screen_base)
-			mdp3_fbmem_free(mfd);
 	}
 	mutex_unlock(&mdp3_session->lock);
 
@@ -789,6 +780,64 @@
 	return ret;
 }
 
+int mdp3_validate_start_req(struct mdp_histogram_start_req *req)
+{
+	if (req->frame_cnt >= MDP_HISTOGRAM_FRAME_COUNT_MAX) {
+		pr_err("%s invalid req frame_cnt\n", __func__);
+		return -EINVAL;
+	}
+	if (req->bit_mask >= MDP_HISTOGRAM_BIT_MASK_MAX) {
+		pr_err("%s invalid req bit mask\n", __func__);
+		return -EINVAL;
+	}
+	if (req->block != MDP_BLOCK_DMA_P ||
+		req->num_bins != MDP_HISTOGRAM_BIN_NUM) {
+		pr_err("mdp3_histogram_start invalid request\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int mdp3_validate_scale_config(struct mdp_bl_scale_data *data)
+{
+	if (data->scale > MDP_HISTOGRAM_BL_SCALE_MAX) {
+		pr_err("%s invalid bl_scale\n", __func__);
+		return -EINVAL;
+	}
+	if (data->min_lvl > MDP_HISTOGRAM_BL_LEVEL_MAX) {
+		pr_err("%s invalid bl_min_lvl\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int mdp3_validate_csc_data(struct mdp_csc_cfg_data *data)
+{
+	int i;
+	for (i = 0; i < 9; i++) {
+		if (data->csc_data.csc_mv[i] >=
+				MDP_HISTOGRAM_CSC_MATRIX_MAX)
+			return -EINVAL;
+	}
+	for (i = 0; i < 3; i++) {
+		if (data->csc_data.csc_pre_bv[i] >=
+				MDP_HISTOGRAM_CSC_VECTOR_MAX)
+			return -EINVAL;
+		if (data->csc_data.csc_post_bv[i] >=
+				MDP_HISTOGRAM_CSC_VECTOR_MAX)
+			return -EINVAL;
+	}
+	for (i = 0; i < 6; i++) {
+		if (data->csc_data.csc_pre_lv[i] >=
+				MDP_HISTOGRAM_CSC_VECTOR_MAX)
+			return -EINVAL;
+		if (data->csc_data.csc_post_lv[i] >=
+				MDP_HISTOGRAM_CSC_VECTOR_MAX)
+			return -EINVAL;
+	}
+	return 0;
+}
+
 static int mdp3_histogram_start(struct mdp3_session_data *session,
 					struct mdp_histogram_start_req *req)
 {
@@ -796,11 +845,10 @@
 	struct mdp3_dma_histogram_config histo_config;
 
 	pr_debug("mdp3_histogram_start\n");
-	if (req->block != MDP_BLOCK_DMA_P ||
-		req->num_bins != MDP_HISTOGRAM_BIN_NUM) {
-		pr_err("mdp3_histogram_start invalid request\n");
-		return -EINVAL;
-	}
+
+	ret = mdp3_validate_start_req(req);
+	if (ret)
+		return ret;
 
 	if (!session->dma->histo_op ||
 		!session->dma->config_histo) {
@@ -1000,10 +1048,20 @@
 
 	switch (mdp_pp.op) {
 	case mdp_bl_scale_cfg:
+		ret = mdp3_validate_scale_config(&mdp_pp.data.bl_scale_data);
+		if (ret) {
+			pr_err("%s: invalid scale config\n", __func__);
+			break;
+		}
 		ret = mdp3_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
 						&mdp_pp.data.bl_scale_data);
 		break;
 	case mdp_op_csc_cfg:
+		ret = mdp3_validate_csc_data(&(mdp_pp.data.csc_cfg_data));
+		if (ret) {
+			pr_err("%s: invalid csc data\n", __func__);
+			break;
+		}
 		ret = mdp3_csc_config(mdp3_session,
 						&(mdp_pp.data.csc_cfg_data));
 		break;
@@ -1235,7 +1293,6 @@
 	}
 	memset(mdp3_session, 0, sizeof(struct mdp3_session_data));
 	mutex_init(&mdp3_session->lock);
-	INIT_WORK(&mdp3_session->vsync_work, mdp3_dispatch_vsync);
 	mutex_init(&mdp3_session->histo_lock);
 	mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL);
 	if (!mdp3_session->dma) {
@@ -1261,6 +1318,7 @@
 		goto init_done;
 	}
 
+	mdp3_session->dma->output_config.out_sel = intf_type;
 	mdp3_session->mfd = mfd;
 	mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev);
 	mdp3_session->status = 0;
@@ -1282,6 +1340,14 @@
 		goto init_done;
 	}
 
+	mdp3_session->vsync_event_sd = sysfs_get_dirent(dev->kobj.sd, NULL,
+							"vsync_event");
+	if (!mdp3_session->vsync_event_sd) {
+		pr_err("vsync_event sysfs lookup failed\n");
+		rc = -ENODEV;
+		goto init_done;
+	}
+
 	kobject_uevent(&dev->kobj, KOBJ_ADD);
 	pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
 
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index 9ea1c91..eb32797 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -43,10 +43,10 @@
 	ktime_t vsync_time;
 	struct timer_list vsync_timer;
 	int vsync_period;
+	struct sysfs_dirent *vsync_event_sd;
 	struct mdp_overlay overlay;
 	struct mdp3_buffer_queue bufq_in;
 	struct mdp3_buffer_queue bufq_out;
-	struct work_struct vsync_work;
 	int histo_status;
 	struct mutex histo_lock;
 	int lut_sel;
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 88eedb9..31b9deb 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -18,7 +18,7 @@
 #include "mdp3_hwio.h"
 
 #define DMA_STOP_POLL_SLEEP_US 1000
-#define DMA_STOP_POLL_TIMEOUT_US 16000
+#define DMA_STOP_POLL_TIMEOUT_US 32000
 #define DMA_HISTO_RESET_TIMEOUT_MS 40
 #define DMA_LUT_CONFIG_MASK 0xfffffbe8
 #define DMA_CCS_CONFIG_MASK 0xfffffc17
@@ -247,16 +247,22 @@
 	pr_debug("mdp3_dma_sync_config\n");
 
 	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
-		sync_config = (source_config->height - 1) << 21;
+		int porch = source_config->vporch;
+		int height = source_config->height;
+		int vtotal = height + porch;
+		sync_config = vtotal << 21;
 		sync_config |= source_config->vsync_count;
 		sync_config |= BIT(19);
 		sync_config |= BIT(20);
 
 		MDP3_REG_WRITE(MDP3_REG_SYNC_CONFIG_0 + dma_sel, sync_config);
 		MDP3_REG_WRITE(MDP3_REG_VSYNC_SEL, 0x024);
-		MDP3_REG_WRITE(MDP3_REG_PRIMARY_VSYNC_INIT_VAL + dma_sel, 0);
-		MDP3_REG_WRITE(MDP3_REG_SYNC_THRESH_0 + dma_sel, 0x00100000);
-		MDP3_REG_WRITE(MDP3_REG_PRIMARY_START_P0S + dma_sel, 0x0);
+		MDP3_REG_WRITE(MDP3_REG_PRIMARY_VSYNC_INIT_VAL + dma_sel,
+				height);
+		MDP3_REG_WRITE(MDP3_REG_PRIMARY_RD_PTR_IRQ, 0x5);
+		MDP3_REG_WRITE(MDP3_REG_SYNC_THRESH_0 + dma_sel, (4 << 16 | 2));
+		MDP3_REG_WRITE(MDP3_REG_PRIMARY_START_P0S + dma_sel, porch);
+		MDP3_REG_WRITE(MDP3_REG_TEAR_CHECK_EN, 0x1);
 	}
 	return 0;
 }
@@ -291,7 +297,7 @@
 	 * the default 16 for MDP hang issue workaround
 	 */
 	MDP3_REG_WRITE(MDP3_REG_DMA_P_FETCH_CFG, 0x20);
-	MDP3_REG_WRITE(MDP3_REG_PRIMARY_RD_PTR_IRQ, 0x10);
+
 
 	dma->source_config = *source_config;
 	dma->output_config = *output_config;
@@ -497,7 +503,7 @@
 			struct mdp3_dma_histogram_config *histo_config)
 {
 	unsigned long flag;
-	u32 histo_bit_mask, histo_control;
+	u32 histo_bit_mask = 0, histo_control = 0;
 	u32 histo_isr_mask = MDP3_DMA_P_HIST_INTR_HIST_DONE_BIT |
 			MDP3_DMA_P_HIST_INTR_RESET_DONE_BIT;
 
@@ -530,7 +536,7 @@
 	pr_debug("mdp3_dmap_update\n");
 
 	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
-		cb_type |= MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
+		cb_type = MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
 		if (intf->active)
 			wait_for_completion_killable(&dma->dma_comp);
 	}
@@ -553,7 +559,8 @@
 
 	mdp3_dma_callback_enable(dma, cb_type);
 	pr_debug("mdp3_dmap_update wait for vsync_comp in\n");
-	wait_for_completion_killable(&dma->vsync_comp);
+	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO)
+		wait_for_completion_killable(&dma->vsync_comp);
 	pr_debug("mdp3_dmap_update wait for vsync_comp out\n");
 	return 0;
 }
@@ -565,7 +572,7 @@
 	int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC;
 
 	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
-		cb_type |= MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
+		cb_type = MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
 		if (intf->active)
 			wait_for_completion_killable(&dma->dma_comp);
 	}
@@ -586,7 +593,8 @@
 	spin_unlock_irqrestore(&dma->dma_lock, flag);
 
 	mdp3_dma_callback_enable(dma, cb_type);
-	wait_for_completion_killable(&dma->vsync_comp);
+	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO)
+		wait_for_completion_killable(&dma->vsync_comp);
 	return 0;
 }
 
@@ -631,7 +639,7 @@
 		return ret;
 
 	if (dma->histo_state != MDP3_DMA_HISTO_STATE_READY) {
-		pr_err("mdp3_dmap_histo_get after dma shut down\n");
+		pr_debug("mdp3_dmap_histo_get after dma shut down\n");
 		return -EPERM;
 	}
 
@@ -694,9 +702,6 @@
 	unsigned long flag;
 	int ret;
 
-	if (dma->histo_state == MDP3_DMA_HISTO_STATE_START)
-		return -EINVAL;
-
 	spin_lock_irqsave(&dma->histo_lock, flag);
 
 	init_completion(&dma->histo_comp);
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index e4a28dc..6983e55 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -16,6 +16,12 @@
 
 #include <linux/sched.h>
 
+#define MDP_HISTOGRAM_BL_SCALE_MAX 1024
+#define MDP_HISTOGRAM_BL_LEVEL_MAX 255
+#define MDP_HISTOGRAM_FRAME_COUNT_MAX 0x20
+#define MDP_HISTOGRAM_BIT_MASK_MAX 0x4
+#define MDP_HISTOGRAM_CSC_MATRIX_MAX 0x2000
+#define MDP_HISTOGRAM_CSC_VECTOR_MAX 0x200
 #define MDP_HISTOGRAM_BIN_NUM	32
 #define MDP_LUT_SIZE 256
 
@@ -145,6 +151,7 @@
 	void *buf;
 	int stride;
 	int vsync_count;
+	int vporch;
 };
 
 struct mdp3_dma_output_config {
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index 924ec5a..8e1dd66 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -344,7 +344,7 @@
 int mdp3_ppp_turnon(struct msm_fb_data_type *mfd, int on_off)
 {
 	struct mdss_panel_info *panel_info = mfd->panel_info;
-	int ab = 0, ib = 0;
+	uint64_t ab = 0, ib = 0;
 	int rate = 0;
 
 	if (on_off) {
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 840af17..25a5c9f 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -56,6 +56,12 @@
 	u32 val;
 };
 
+struct mdss_debug_inf {
+	void *debug_data;
+	int (*debug_dump_stats)(void *data, char *buf, int len);
+	void (*debug_enable_clock)(int on);
+};
+
 struct mdss_data_type {
 	u32 mdp_rev;
 	struct clk *mdp_clk[MDSS_MAX_CLK];
@@ -121,7 +127,7 @@
 	struct mdss_iommu_map_type *iommu_map;
 
 	struct early_suspend early_suspend;
-	void *debug_data;
+	struct mdss_debug_inf debug_inf;
 	int current_bus_idx;
 	bool mixer_switched;
 };
diff --git a/drivers/video/msm/mdss/mdss_debug.c b/drivers/video/msm/mdss/mdss_debug.c
index 13fba26..f933c8e 100644
--- a/drivers/video/msm/mdss/mdss_debug.c
+++ b/drivers/video/msm/mdss/mdss_debug.c
@@ -128,11 +128,12 @@
 		const char __user *user_buf, size_t count, loff_t *ppos)
 {
 	struct mdss_debug_base *dbg = file->private_data;
+	struct mdss_data_type *mdata = mdss_res;
 	size_t off;
 	u32 data, cnt;
 	char buf[24];
 
-	if (!dbg)
+	if (!dbg || !mdata)
 		return -ENODEV;
 
 	if (count >= sizeof(buf))
@@ -151,9 +152,13 @@
 	if (off >= dbg->max_offset)
 		return -EFAULT;
 
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	if (mdata->debug_inf.debug_enable_clock)
+		mdata->debug_inf.debug_enable_clock(1);
+
 	writel_relaxed(data, dbg->base + off);
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	if (mdata->debug_inf.debug_enable_clock)
+		mdata->debug_inf.debug_enable_clock(0);
 
 	pr_debug("addr=%x data=%x\n", off, data);
 
@@ -164,9 +169,10 @@
 			char __user *user_buf, size_t count, loff_t *ppos)
 {
 	struct mdss_debug_base *dbg = file->private_data;
+	struct mdss_data_type *mdata = mdss_res;
 	size_t len;
 
-	if (!dbg) {
+	if (!dbg || !mdata) {
 		pr_err("invalid handle\n");
 		return -ENODEV;
 	}
@@ -188,7 +194,9 @@
 		ptr = dbg->base + dbg->off;
 		tot = 0;
 
-		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+		if (mdata->debug_inf.debug_enable_clock)
+			mdata->debug_inf.debug_enable_clock(1);
+
 		for (cnt = dbg->cnt; cnt > 0; cnt -= ROW_BYTES) {
 			hex_dump_to_buffer(ptr, min(cnt, ROW_BYTES),
 					   ROW_BYTES, GROUP_BYTES, dump_buf,
@@ -203,7 +211,8 @@
 			if (tot >= dbg->buf_len)
 				break;
 		}
-		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+		if (mdata->debug_inf.debug_enable_clock)
+			mdata->debug_inf.debug_enable_clock(0);
 
 		dbg->buf_len = tot;
 	}
@@ -246,10 +255,10 @@
 	char dn[80] = "";
 	int prefix_len = 0;
 
-	if (!mdata || !mdata->debug_data)
+	if (!mdata || !mdata->debug_inf.debug_data)
 		return -ENODEV;
 
-	mdd = mdata->debug_data;
+	mdd = mdata->debug_inf.debug_data;
 
 	dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
 	if (!dbg)
@@ -301,33 +310,11 @@
 	return 0;
 }
 
-static int mdss_debug_stat_ctl_dump(struct mdss_mdp_ctl *ctl,
-		char *bp, int len)
-{
-	int tot = 0;
-
-	if (!ctl->ref_cnt)
-		return 0;
-
-	if (ctl->intf_num) {
-		tot = scnprintf(bp, len,
-			"intf%d: play: %08u \tvsync: %08u \tunderrun: %08u\n",
-				ctl->intf_num, ctl->play_cnt,
-				ctl->vsync_cnt, ctl->underrun_cnt);
-	} else {
-		tot = scnprintf(bp, len, "wb: \tmode=%x \tplay: %08u\n",
-				ctl->opmode, ctl->play_cnt);
-	}
-
-	return tot;
-}
-
 static ssize_t mdss_debug_stat_read(struct file *file, char __user *buff,
 		size_t count, loff_t *ppos)
 {
 	struct mdss_data_type *mdata = file->private_data;
-	struct mdss_mdp_pipe *pipe;
-	int i, len, tot;
+	int len, tot;
 	char bp[512];
 
 	if (*ppos)
@@ -337,30 +324,11 @@
 
 	tot = scnprintf(bp, len, "\nmdp:\n");
 
-	for (i = 0; i < mdata->nctl; i++)
-		tot += mdss_debug_stat_ctl_dump(mdata->ctl_off + i,
-				bp + tot, len - tot);
-	tot += scnprintf(bp + tot, len - tot, "\n");
+	if (mdata->debug_inf.debug_dump_stats)
+		tot += mdata->debug_inf.debug_dump_stats(mdata,
+						bp + tot, len - tot);
 
-	for (i = 0; i < mdata->nvig_pipes; i++) {
-		pipe = mdata->vig_pipes + i;
-		tot += scnprintf(bp + tot, len - tot,
-			"VIG%d :   %08u\t", i, pipe->play_cnt);
-	}
-	tot += scnprintf(bp + tot, len - tot, "\n");
 
-	for (i = 0; i < mdata->nrgb_pipes; i++) {
-		pipe = mdata->rgb_pipes + i;
-		tot += scnprintf(bp + tot, len - tot,
-			"RGB%d :   %08u\t", i, pipe->play_cnt);
-	}
-	tot += scnprintf(bp + tot, len - tot, "\n");
-
-	for (i = 0; i < mdata->ndma_pipes; i++) {
-		pipe = mdata->dma_pipes + i;
-		tot += scnprintf(bp + tot, len - tot,
-			"DMA%d :   %08u\t", i, pipe->play_cnt);
-	}
 	tot += scnprintf(bp + tot, len - tot, "\n");
 
 	if (copy_to_user(buff, bp, tot))
@@ -401,7 +369,7 @@
 {
 	struct mdss_debug_data *mdd;
 
-	if (mdata->debug_data) {
+	if (mdata->debug_inf.debug_data) {
 		pr_warn("mdss debugfs already initialized\n");
 		return -EBUSY;
 	}
@@ -424,18 +392,19 @@
 	debugfs_create_file("stat", 0644, mdd->root, mdata, &mdss_stat_fops);
 
 	debugfs_create_u32("min_mdp_clk", 0644, mdd->root,
-		(u32 *)&mdata->min_mdp_clk);
+			(u32 *)&mdata->min_mdp_clk);
 
-	mdata->debug_data = mdd;
+	mdata->debug_inf.debug_data = mdd;
 
 	return 0;
 }
 
 int mdss_debugfs_remove(struct mdss_data_type *mdata)
 {
-	struct mdss_debug_data *mdd = mdata->debug_data;
+	struct mdss_debug_data *mdd = mdata->debug_inf.debug_data;
 
 	mdss_debugfs_cleanup(mdd);
+	mdata->debug_inf.debug_data = NULL;
 
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 9a019f9..9a9a227 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -510,6 +510,12 @@
 	}
 	panel_data->panel_info.yres = (!rc ? tmp : 480);
 
+	rc = of_property_read_u32(np,
+		"qcom,mdss-pan-physical-width-dimension", &tmp);
+	panel_data->panel_info.physical_width = (!rc ? tmp : 0);
+	rc = of_property_read_u32(np,
+		"qcom,mdss-pan-physical-height-dimension", &tmp);
+	panel_data->panel_info.physical_height = (!rc ? tmp : 0);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-h-left-border", &tmp);
 	panel_data->panel_info.lcdc.xres_pad = (!rc ? tmp : 0);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-h-right-border", &tmp);
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 94fced0..a4a2af4 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -322,6 +322,7 @@
 	if (pdata->next)
 		mfd->split_display = true;
 	mfd->mdp = *mdp_instance;
+	INIT_LIST_HEAD(&mfd->proc_list);
 
 	mutex_init(&mfd->lock);
 	mutex_init(&mfd->bl_lock);
@@ -573,9 +574,23 @@
 static void mdss_fb_scale_bl(struct msm_fb_data_type *mfd, u32 *bl_lvl)
 {
 	u32 temp = *bl_lvl;
+
 	pr_debug("input = %d, scale = %d", temp, mfd->bl_scale);
 	if (temp >= mfd->bl_min_lvl) {
-		/* bl_scale is the numerator of scaling fraction (x/1024)*/
+		if (temp > mfd->panel_info->bl_max) {
+			pr_warn("%s: invalid bl level\n",
+				__func__);
+			temp = mfd->panel_info->bl_max;
+		}
+		if (mfd->bl_scale > 1024) {
+			pr_warn("%s: invalid bl scale\n",
+				__func__);
+			mfd->bl_scale = 1024;
+		}
+		/*
+		 * bl_scale is the numerator of
+		 * scaling fraction (x/1024)
+		 */
 		temp = (temp * mfd->bl_scale) / 1024;
 
 		/*if less than minimum level, use min level*/
@@ -1007,6 +1022,10 @@
 		fix->line_length = var->xres * bpp;
 
 	var->yres = panel_info->yres;
+	if (panel_info->physical_width)
+		var->width = panel_info->physical_width;
+	if (panel_info->physical_height)
+		var->height = panel_info->physical_height;
 	var->xres_virtual = var->xres;
 	var->yres_virtual = panel_info->yres * mfd->fb_page;
 	var->bits_per_pixel = bpp * 8;	/* FrameBuffer color depth */
@@ -1083,14 +1102,32 @@
 static int mdss_fb_open(struct fb_info *info, int user)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	struct mdss_fb_proc_info *pinfo = NULL;
 	int result;
+	int pid = current->tgid;
+
+	list_for_each_entry(pinfo, &mfd->proc_list, list) {
+		if (pinfo->pid == pid)
+			break;
+	}
+
+	if ((pinfo == NULL) || (pinfo->pid != pid)) {
+		pinfo = kmalloc(sizeof(*pinfo), GFP_KERNEL);
+		if (!pinfo) {
+			pr_err("unable to alloc process info\n");
+			return -ENOMEM;
+		}
+		pinfo->pid = pid;
+		pinfo->ref_cnt = 0;
+		list_add(&pinfo->list, &mfd->proc_list);
+		pr_debug("new process entry pid=%d\n", pinfo->pid);
+	}
 
 	result = pm_runtime_get_sync(info->dev);
 
 	if (result < 0)
 		pr_err("pm_runtime: fail to wake up\n");
 
-
 	if (!mfd->ref_cnt) {
 		result = mdss_fb_blank_sub(FB_BLANK_UNBLANK, info,
 					   mfd->op_enable);
@@ -1102,6 +1139,7 @@
 		}
 	}
 
+	pinfo->ref_cnt++;
 	mfd->ref_cnt++;
 	return 0;
 }
@@ -1109,7 +1147,9 @@
 static int mdss_fb_release(struct fb_info *info, int user)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	struct mdss_fb_proc_info *pinfo = NULL;
 	int ret = 0;
+	int pid = current->tgid;
 
 	if (!mfd->ref_cnt) {
 		pr_info("try to close unopened fb %d!\n", mfd->index);
@@ -1119,6 +1159,31 @@
 	mdss_fb_pan_idle(mfd);
 	mfd->ref_cnt--;
 
+	list_for_each_entry(pinfo, &mfd->proc_list, list) {
+		if (pinfo->pid == pid)
+			break;
+	}
+
+	if (!pinfo || (pinfo->pid != pid)) {
+		pr_warn("unable to find process info for fb%d pid=%d\n",
+				mfd->index, pid);
+	} else {
+		pr_debug("found process entry pid=%d ref=%d\n",
+				pinfo->pid, pinfo->ref_cnt);
+
+		pinfo->ref_cnt--;
+		if (pinfo->ref_cnt == 0) {
+			if (mfd->mdp.release_fnc) {
+				ret = mfd->mdp.release_fnc(mfd);
+				if (ret)
+					pr_err("error releasing fb%d pid=%d\n",
+						mfd->index, pinfo->pid);
+			}
+			list_del(&pinfo->list);
+			kfree(pinfo);
+		}
+	}
+
 	if (!mfd->ref_cnt) {
 		ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info,
 				       mfd->op_enable);
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 030fd67..65218c0 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -61,6 +61,8 @@
 	int (*init_fnc)(struct msm_fb_data_type *mfd);
 	int (*on_fnc)(struct msm_fb_data_type *mfd);
 	int (*off_fnc)(struct msm_fb_data_type *mfd);
+	/* called to release resources associated to the process */
+	int (*release_fnc)(struct msm_fb_data_type *mfd);
 	int (*kickoff_fnc)(struct msm_fb_data_type *mfd);
 	int (*ioctl_handler)(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
 	void (*dma_fnc)(struct msm_fb_data_type *mfd);
@@ -81,6 +83,12 @@
 					/ (2 * max_bright);\
 					} while (0)
 
+struct mdss_fb_proc_info {
+	int pid;
+	u32 ref_cnt;
+	struct list_head list;
+};
+
 struct msm_fb_data_type {
 	u32 key;
 	u32 index;
@@ -148,6 +156,7 @@
 	u32 is_power_setting;
 
 	u32 dcm_state;
+	struct list_head proc_list;
 };
 
 struct msm_fb_backup_type {
diff --git a/drivers/video/msm/mdss/mdss_hdmi_cec.c b/drivers/video/msm/mdss/mdss_hdmi_cec.c
index 2cf47fc..b74f074 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_cec.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_cec.c
@@ -22,6 +22,7 @@
 
 /* Reference: HDMI 1.4a Specification section 7.1 */
 #define RETRANSMIT_MAX_NUM	5
+#define MAX_OPERAND_SIZE	15
 
 /*
  * Ref. HDMI 1.4a: Supplement-1 CEC Section 6, 7
@@ -30,7 +31,7 @@
 	u8 sender_id;
 	u8 recvr_id;
 	u8 opcode;
-	u8 operand[15];
+	u8 operand[MAX_OPERAND_SIZE];
 	u8 frame_size;
 	u8 retransmit;
 };
@@ -738,6 +739,10 @@
 	}
 	spin_unlock_irqrestore(&cec_ctrl->lock, flags);
 
+	if (msg->frame_size > MAX_OPERAND_SIZE) {
+		DEV_ERR("%s: msg frame too big!\n", __func__);
+		return -EINVAL;
+	}
 	rc = hdmi_cec_msg_send(cec_ctrl, msg);
 	if (rc) {
 		DEV_ERR("%s: hdmi_cec_msg_send failed\n", __func__);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index ad134a0..0fd3655 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -430,7 +430,7 @@
 static ssize_t hdmi_tx_sysfs_wta_vendor_name(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t count)
 {
-	ssize_t ret;
+	ssize_t ret, sz;
 	u8 *s = (u8 *) buf;
 	u8 *d = NULL;
 	struct hdmi_tx_ctrl *hdmi_ctrl =
@@ -445,7 +445,8 @@
 	ret = strnlen(buf, PAGE_SIZE);
 	ret = (ret > 8) ? 8 : ret;
 
-	memset(hdmi_ctrl->spd_vendor_name, 0, 8);
+	sz = sizeof(hdmi_ctrl->spd_vendor_name);
+	memset(hdmi_ctrl->spd_vendor_name, 0, sz);
 	while (*s) {
 		if (*s & 0x60 && *s ^ 0x7f) {
 			*d = *s;
@@ -459,6 +460,7 @@
 
 		d++;
 	}
+	hdmi_ctrl->spd_vendor_name[sz - 1] = 0;
 
 	DEV_DBG("%s: '%s'\n", __func__, hdmi_ctrl->spd_vendor_name);
 
@@ -486,7 +488,7 @@
 static ssize_t hdmi_tx_sysfs_wta_product_description(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t count)
 {
-	ssize_t ret;
+	ssize_t ret, sz;
 	u8 *s = (u8 *) buf;
 	u8 *d = NULL;
 	struct hdmi_tx_ctrl *hdmi_ctrl =
@@ -501,7 +503,8 @@
 	ret = strnlen(buf, PAGE_SIZE);
 	ret = (ret > 16) ? 16 : ret;
 
-	memset(hdmi_ctrl->spd_product_description, 0, 16);
+	sz = sizeof(hdmi_ctrl->spd_product_description);
+	memset(hdmi_ctrl->spd_product_description, 0, sz);
 	while (*s) {
 		if (*s & 0x60 && *s ^ 0x7f) {
 			*d = *s;
@@ -515,6 +518,7 @@
 
 		d++;
 	}
+	hdmi_ctrl->spd_product_description[sz - 1] = 0;
 
 	DEV_DBG("%s: '%s'\n", __func__, hdmi_ctrl->spd_product_description);
 
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 18ee782..fd95582 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -79,8 +79,8 @@
 	bool hdcp_feature_on;
 	u32 present_hdcp;
 
-	u8 spd_vendor_name[8];
-	u8 spd_product_description[16];
+	u8 spd_vendor_name[9];
+	u8 spd_product_description[17];
 
 	struct hdmi_tx_ddc_ctrl ddc_ctrl;
 
diff --git a/drivers/video/msm/mdss/mdss_io_util.c b/drivers/video/msm/mdss/mdss_io_util.c
index c862e78..6a1e7f7c 100644
--- a/drivers/video/msm/mdss/mdss_io_util.c
+++ b/drivers/video/msm/mdss/mdss_io_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -211,7 +211,8 @@
 					in_vreg[i].vreg_name, rc);
 				goto vreg_set_opt_mode_fail;
 			}
-			msleep(in_vreg[i].pre_on_sleep);
+			if (in_vreg[i].pre_on_sleep)
+				msleep(in_vreg[i].pre_on_sleep);
 			rc = regulator_set_optimum_mode(in_vreg[i].vreg,
 				in_vreg[i].enable_load);
 			if (rc < 0) {
@@ -221,7 +222,8 @@
 				goto vreg_set_opt_mode_fail;
 			}
 			rc = regulator_enable(in_vreg[i].vreg);
-			msleep(in_vreg[i].post_on_sleep);
+			if (in_vreg[i].post_on_sleep)
+				msleep(in_vreg[i].post_on_sleep);
 			if (rc < 0) {
 				DEV_ERR("%pS->%s: %s enable failed\n",
 					__builtin_return_address(0), __func__,
@@ -232,11 +234,13 @@
 	} else {
 		for (i = num_vreg-1; i >= 0; i--)
 			if (regulator_is_enabled(in_vreg[i].vreg)) {
-				msleep(in_vreg[i].pre_off_sleep);
+				if (in_vreg[i].pre_off_sleep)
+					msleep(in_vreg[i].pre_off_sleep);
 				regulator_set_optimum_mode(in_vreg[i].vreg,
 					in_vreg[i].disable_load);
 				regulator_disable(in_vreg[i].vreg);
-				msleep(in_vreg[i].post_off_sleep);
+				if (in_vreg[i].post_off_sleep)
+					msleep(in_vreg[i].post_off_sleep);
 			}
 	}
 	return rc;
@@ -246,11 +250,13 @@
 
 vreg_set_opt_mode_fail:
 	for (i--; i >= 0; i--) {
-		msleep(in_vreg[i].pre_off_sleep);
+		if (in_vreg[i].pre_off_sleep)
+			msleep(in_vreg[i].pre_off_sleep);
 		regulator_set_optimum_mode(in_vreg[i].vreg,
 			in_vreg[i].disable_load);
 		regulator_disable(in_vreg[i].vreg);
-		msleep(in_vreg[i].post_off_sleep);
+		if (in_vreg[i].post_off_sleep)
+			msleep(in_vreg[i].post_off_sleep);
 	}
 
 	return rc;
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 0a41ef8..8924298 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -166,9 +166,10 @@
 
 	spin_lock(&mdss_lock);
 	hw = mdss_irq_handlers[hw_ndx];
+	spin_unlock(&mdss_lock);
+
 	if (hw)
 		rc = hw->irq_handler(irq, hw->ptr);
-	spin_unlock(&mdss_lock);
 
 	return rc;
 }
@@ -807,10 +808,75 @@
 	return 0;
 }
 
+static int mdss_debug_stat_ctl_dump(struct mdss_mdp_ctl *ctl,
+		char *bp, int len)
+{
+	int total = 0;
+
+	if (!ctl->ref_cnt)
+		return 0;
+
+	if (ctl->intf_num) {
+		total = scnprintf(bp, len,
+			"intf%d: play: %08u \tvsync: %08u \tunderrun: %08u\n",
+				ctl->intf_num, ctl->play_cnt,
+				ctl->vsync_cnt, ctl->underrun_cnt);
+	} else {
+		total = scnprintf(bp, len, "wb: \tmode=%x \tplay: %08u\n",
+				ctl->opmode, ctl->play_cnt);
+	}
+
+	return total;
+}
+
+static int mdss_debug_dump_stats(void *data, char *buf, int len)
+{
+	struct mdss_data_type *mdata = data;
+	struct mdss_mdp_pipe *pipe;
+	int i, total = 0;
+
+	for (i = 0; i < mdata->nctl; i++)
+		total += mdss_debug_stat_ctl_dump(mdata->ctl_off + i, buf, len);
+
+	total += scnprintf(buf + total, len - total, "\n");
+
+	for (i = 0; i < mdata->nvig_pipes; i++) {
+		pipe = mdata->vig_pipes + i;
+		total += scnprintf(buf + total, len - total,
+			"VIG%d :   %08u\t", i, pipe->play_cnt);
+	}
+	total += scnprintf(buf + total, len - total, "\n");
+
+	for (i = 0; i < mdata->nrgb_pipes; i++) {
+		pipe = mdata->rgb_pipes + i;
+		total += scnprintf(buf + total, len - total,
+			"RGB%d :   %08u\t", i, pipe->play_cnt);
+	}
+	total += scnprintf(buf + total, len - total, "\n");
+
+	for (i = 0; i < mdata->ndma_pipes; i++) {
+		pipe = mdata->dma_pipes + i;
+		total += scnprintf(buf + total, len - total,
+			"DMA%d :   %08u\t", i, pipe->play_cnt);
+	}
+	return total;
+}
+
+static void mdss_debug_enable_clock(int on)
+{
+	if (on)
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	else
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+}
+
 static int mdss_mdp_debug_init(struct mdss_data_type *mdata)
 {
 	int rc;
 
+	mdata->debug_inf.debug_dump_stats = mdss_debug_dump_stats;
+	mdata->debug_inf.debug_enable_clock = mdss_debug_enable_clock;
+
 	rc = mdss_debugfs_init(mdata);
 	if (rc)
 		return rc;
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index aba77e3..70d9107 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -39,6 +39,8 @@
 #define MAX_DOWNSCALE_RATIO	4
 #define MAX_UPSCALE_RATIO	20
 #define MAX_DECIMATION		4
+#define MDP_MIN_VBP		4
+#define MAX_FREE_LIST_SIZE	12
 
 #define C3_ALPHA	3	/* alpha */
 #define C2_R_Cr		2	/* R/Cr */
@@ -314,6 +316,7 @@
 	u32 ftch_id;
 	atomic_t ref_cnt;
 	u32 play_cnt;
+	int pid;
 
 	u32 flags;
 	u32 bwc_mode;
@@ -333,6 +336,7 @@
 	u8 mixer_stage;
 	u8 is_fg;
 	u8 alpha;
+	u8 blend_op;
 	u8 overfetch_disable;
 	u32 transp;
 
@@ -361,8 +365,8 @@
 };
 
 struct mdss_overlay_private {
-	int vsync_pending;
 	ktime_t vsync_time;
+	struct sysfs_dirent *vsync_event_sd;
 	int borderfill_enable;
 	int overlay_play_enable;
 	int hw_refresh;
@@ -375,8 +379,11 @@
 	struct list_head overlay_list;
 	struct list_head pipes_used;
 	struct list_head pipes_cleanup;
-	struct work_struct vsync_work;
+	struct list_head rot_proc_list;
 	bool mixer_swap;
+
+	struct mdss_mdp_data free_list[MAX_FREE_LIST_SIZE];
+	int free_list_size;
 };
 
 struct mdss_mdp_perf_params {
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index d1595b3..176d0df 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -242,6 +242,7 @@
 				       u32 *clk_rate)
 {
 	struct mdss_mdp_pipe *pipe;
+	struct mdss_panel_info *pinfo = NULL;
 	int fps = DEFAULT_FRAME_RATE;
 	u32 v_total;
 	int i;
@@ -252,22 +253,21 @@
 	*clk_rate = 0;
 
 	if (!mixer->rotator_mode) {
-		int is_writeback = false;
 		if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
-			struct mdss_panel_info *pinfo;
 			pinfo = &mixer->ctl->panel_data->panel_info;
 			fps = mdss_panel_get_framerate(pinfo);
 			v_total = mdss_panel_get_vtotal(pinfo);
 
 			if (pinfo->type == WRITEBACK_PANEL)
-				is_writeback = true;
+				pinfo = NULL;
 		} else {
 			v_total = mixer->height;
-
-			is_writeback = true;
 		}
 		*clk_rate = mixer->width * v_total * fps;
-		if (is_writeback) {
+		if (pinfo && pinfo->lcdc.v_back_porch < MDP_MIN_VBP)
+			*clk_rate = MDSS_MDP_CLK_FUDGE_FACTOR(*clk_rate);
+
+		if (!pinfo) {
 			/* perf for bus writeback */
 			*bus_ab_quota = fps * mixer->width * mixer->height * 3;
 			*bus_ab_quota >>= MDSS_MDP_BUS_FACTOR_SHIFT;
@@ -280,11 +280,6 @@
 		pipe = mixer->stage_pipe[i];
 		if (pipe == NULL)
 			continue;
-		if (pipe->is_fg) {
-			ab_total = 0;
-			ib_total = 0;
-			max_clk_rate = 0;
-		}
 
 		if (mdss_mdp_perf_calc_pipe(pipe, &perf))
 			continue;
@@ -520,13 +515,13 @@
 
 	ctl = mdss_mdp_ctl_alloc(mdss_res, mdss_res->nmixers_intf);
 	if (!ctl) {
-		pr_err("unable to allocate wb ctl\n");
+		pr_debug("unable to allocate wb ctl\n");
 		return NULL;
 	}
 
 	mixer = mdss_mdp_mixer_alloc(ctl, MDSS_MDP_MIXER_TYPE_WRITEBACK, false);
 	if (!mixer) {
-		pr_err("unable to allocate wb mixer\n");
+		pr_debug("unable to allocate wb mixer\n");
 		goto error;
 	}
 
@@ -572,6 +567,7 @@
 	struct mdss_mdp_ctl *ctl;
 
 	ctl = mixer->ctl;
+	mixer->rotator_mode = 0;
 
 	pr_debug("destroy ctl=%d mixer=%d\n", ctl->num, mixer->num);
 
@@ -1207,7 +1203,8 @@
 {
 	struct mdss_mdp_pipe *pipe;
 	u32 off, blend_op, blend_stage;
-	u32 mixercfg = 0, blend_color_out = 0, bgalpha = 0;
+	u32 mixercfg = 0, blend_color_out = 0, bg_alpha_enable = 0;
+	u32 fg_alpha = 0, bg_alpha = 0;
 	int stage, secure = 0;
 
 	if (!mixer)
@@ -1227,7 +1224,7 @@
 			mixercfg = 1 << (3 * pipe->num);
 		}
 		if (pipe->src_fmt->alpha_enable)
-			bgalpha = 1;
+			bg_alpha_enable = 1;
 		secure = pipe->flags & MDP_SECURE_OVERLAY_SESSION;
 	}
 
@@ -1244,48 +1241,79 @@
 		blend_stage = stage - MDSS_MDP_STAGE_0;
 		off = MDSS_MDP_REG_LM_BLEND_OFFSET(blend_stage);
 
-		if (pipe->is_fg) {
-			bgalpha = 0;
-			if (!secure)
-				mixercfg = MDSS_MDP_LM_BORDER_COLOR;
+		blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
+			    MDSS_MDP_BLEND_BG_ALPHA_BG_CONST);
+		fg_alpha = pipe->alpha;
+		bg_alpha = 0xFF - pipe->alpha;
+		/* keep fg alpha */
+		blend_color_out |= 1 << (blend_stage + 1);
+
+		switch (pipe->blend_op) {
+		case BLEND_OP_OPAQUE:
 
 			blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
 				    MDSS_MDP_BLEND_BG_ALPHA_BG_CONST);
-			/* keep fg alpha */
-			blend_color_out |= 1 << (blend_stage + 1);
 
-			pr_debug("pnum=%d stg=%d alpha=IS_FG\n", pipe->num,
+			pr_debug("pnum=%d stg=%d op=OPAQUE\n", pipe->num,
 					stage);
-		} else if (pipe->src_fmt->alpha_enable) {
-			bgalpha = 0;
-			blend_op = (MDSS_MDP_BLEND_BG_ALPHA_FG_PIXEL |
-				    MDSS_MDP_BLEND_BG_INV_ALPHA);
-			/* keep fg alpha */
-			blend_color_out |= 1 << (blend_stage + 1);
+			break;
 
-			pr_debug("pnum=%d stg=%d alpha=FG PIXEL\n", pipe->num,
+		case BLEND_OP_PREMULTIPLIED:
+			if (pipe->src_fmt->alpha_enable) {
+				blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
+					    MDSS_MDP_BLEND_BG_ALPHA_FG_PIXEL);
+				if (fg_alpha != 0xff) {
+					bg_alpha = fg_alpha;
+					blend_op |=
+						MDSS_MDP_BLEND_BG_MOD_ALPHA |
+						MDSS_MDP_BLEND_BG_INV_MOD_ALPHA;
+				} else {
+					blend_op |= MDSS_MDP_BLEND_BG_INV_ALPHA;
+				}
+			}
+			pr_debug("pnum=%d stg=%d op=PREMULTIPLIED\n", pipe->num,
 					stage);
-		} else if (bgalpha) {
-			blend_op = (MDSS_MDP_BLEND_BG_ALPHA_BG_PIXEL |
-				    MDSS_MDP_BLEND_FG_ALPHA_BG_PIXEL |
-				    MDSS_MDP_BLEND_FG_INV_ALPHA);
-			/* keep bg alpha */
-			pr_debug("pnum=%d stg=%d alpha=BG_PIXEL\n", pipe->num,
+			break;
+
+		case BLEND_OP_COVERAGE:
+			if (pipe->src_fmt->alpha_enable) {
+				blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_PIXEL |
+					    MDSS_MDP_BLEND_BG_ALPHA_FG_PIXEL);
+				if (fg_alpha != 0xff) {
+					bg_alpha = fg_alpha;
+					blend_op |=
+					       MDSS_MDP_BLEND_FG_MOD_ALPHA |
+					       MDSS_MDP_BLEND_FG_INV_MOD_ALPHA |
+					       MDSS_MDP_BLEND_BG_MOD_ALPHA |
+					       MDSS_MDP_BLEND_BG_INV_MOD_ALPHA;
+				} else {
+					blend_op |= MDSS_MDP_BLEND_BG_INV_ALPHA;
+				}
+			}
+			pr_debug("pnum=%d stg=%d op=COVERAGE\n", pipe->num,
 					stage);
-		} else {
+			break;
+
+		default:
 			blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
 				    MDSS_MDP_BLEND_BG_ALPHA_BG_CONST);
-			pr_debug("pnum=%d stg=%d alpha=CONST\n", pipe->num,
+			pr_debug("pnum=%d stg=%d op=NONE\n", pipe->num,
 					stage);
+			break;
 		}
 
+		if (!pipe->src_fmt->alpha_enable && bg_alpha_enable)
+			blend_color_out = 0;
+
 		mixercfg |= stage << (3 * pipe->num);
 
+		pr_debug("stg=%d op=%x fg_alpha=%x bg_alpha=%x\n", stage,
+					blend_op, fg_alpha, bg_alpha);
 		mdp_mixer_write(mixer, off + MDSS_MDP_REG_LM_OP_MODE, blend_op);
 		mdp_mixer_write(mixer, off + MDSS_MDP_REG_LM_BLEND_FG_ALPHA,
-				   pipe->alpha);
+				   fg_alpha);
 		mdp_mixer_write(mixer, off + MDSS_MDP_REG_LM_BLEND_BG_ALPHA,
-				   0xFF - pipe->alpha);
+				   bg_alpha);
 	}
 
 	if (mixer->cursor_enabled)
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 6fb8883..3f3e51c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -479,9 +479,9 @@
 		mdp_video_write(ctx, MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 1);
 		wmb();
 
-		rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
+		rc = wait_for_completion_timeout(&ctx->vsync_comp,
 				usecs_to_jiffies(VSYNC_TIMEOUT_US));
-		WARN(rc <= 0, "timeout (%d) enabling timegen on ctl=%d\n",
+		WARN(rc == 0, "timeout (%d) enabling timegen on ctl=%d\n",
 				rc, ctl->num);
 
 		ctx->timegen_en = true;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 0a37573..ff977a9 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -345,12 +345,12 @@
 	if (ctx->comp_cnt == 0)
 		return rc;
 
-	rc = wait_for_completion_interruptible_timeout(&ctx->wb_comp,
+	rc = wait_for_completion_timeout(&ctx->wb_comp,
 			KOFF_TIMEOUT);
 	mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
 		NULL, NULL);
 
-	if (rc <= 0) {
+	if (rc == 0) {
 		rc = -ENODEV;
 		WARN(1, "writeback kickoff timed out (%d) ctl=%d\n",
 						rc, ctl->num);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index c4dee86..22d2d2a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -241,6 +241,8 @@
 
 	if (req->id == MSMFB_NEW_REQUEST) {
 		rot = mdss_mdp_rotator_session_alloc();
+		rot->pid = current->tgid;
+		list_add(&rot->list, &mdp5_data->rot_proc_list);
 
 		if (!rot) {
 			pr_err("unable to allocate rotator session\n");
@@ -439,6 +441,7 @@
 		mutex_unlock(&mfd->lock);
 		pipe->mixer = mixer;
 		pipe->mfd = mfd;
+		pipe->pid = current->tgid;
 		pipe->play_cnt = 0;
 	} else {
 		pipe = mdss_mdp_pipe_get(mdp5_data->mdata, req->id);
@@ -491,6 +494,16 @@
 	pipe->is_fg = req->is_fg;
 	pipe->alpha = req->alpha;
 	pipe->transp = req->transp_mask;
+	pipe->blend_op = req->blend_op;
+	if (pipe->blend_op == BLEND_OP_NOT_DEFINED)
+		pipe->blend_op = fmt->alpha_enable ?
+					BLEND_OP_PREMULTIPLIED :
+					BLEND_OP_OPAQUE;
+
+	if (!fmt->alpha_enable && (pipe->blend_op != BLEND_OP_OPAQUE))
+		pr_warn("Unintended blend_op %d on layer with no alpha plane\n",
+			pipe->blend_op);
+
 	pipe->overfetch_disable = fmt->is_yuv &&
 			!(pipe->flags & MDP_SOURCE_ROTATED_90);
 
@@ -686,6 +699,45 @@
 	return 0;
 }
 
+/**
+ * __mdss_mdp_overlay_free_list_purge() - clear free list of buffers
+ * @mfd:	Msm frame buffer data structure for the associated fb
+ *
+ * Frees memory and clears current list of buffers which are pending free
+ */
+static void __mdss_mdp_overlay_free_list_purge(struct msm_fb_data_type *mfd)
+{
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	int i;
+
+	pr_debug("purging fb%d free list\n", mfd->index);
+	for (i = 0; i < mdp5_data->free_list_size; i++)
+		mdss_mdp_overlay_free_buf(&mdp5_data->free_list[i]);
+	mdp5_data->free_list_size = 0;
+}
+
+/**
+ * __mdss_mdp_overlay_free_list_add() - add a buffer to free list
+ * @mfd:	Msm frame buffer data structure for the associated fb
+ */
+static void __mdss_mdp_overlay_free_list_add(struct msm_fb_data_type *mfd,
+		struct mdss_mdp_data *buf)
+{
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	int i;
+
+	/* if holding too many buffers free current list */
+	if (mdp5_data->free_list_size >= MAX_FREE_LIST_SIZE) {
+		pr_warn("max free list size for fb%d, purging\n", mfd->index);
+		__mdss_mdp_overlay_free_list_purge(mfd);
+	}
+
+	BUG_ON(mdp5_data->free_list_size >= MAX_FREE_LIST_SIZE);
+	i = mdp5_data->free_list_size++;
+	mdp5_data->free_list[i] = *buf;
+	memset(buf, 0, sizeof(*buf));
+}
+
 static void mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd)
 {
 	struct mdss_mdp_pipe *pipe, *tmp;
@@ -693,18 +745,20 @@
 	LIST_HEAD(destroy_pipes);
 
 	mutex_lock(&mfd->lock);
+	__mdss_mdp_overlay_free_list_purge(mfd);
+
 	list_for_each_entry_safe(pipe, tmp, &mdp5_data->pipes_cleanup,
 				cleanup_list) {
 		list_move(&pipe->cleanup_list, &destroy_pipes);
 		mdss_mdp_overlay_free_buf(&pipe->back_buf);
-		mdss_mdp_overlay_free_buf(&pipe->front_buf);
+		__mdss_mdp_overlay_free_list_add(mfd, &pipe->front_buf);
 		pipe->mfd = NULL;
 	}
 
 	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
 		if (pipe->back_buf.num_planes) {
 			/* make back buffer active */
-			mdss_mdp_overlay_free_buf(&pipe->front_buf);
+			__mdss_mdp_overlay_free_list_add(mfd, &pipe->front_buf);
 			swap(pipe->back_buf, pipe->front_buf);
 		}
 	}
@@ -892,6 +946,7 @@
 				continue;
 			}
 			mutex_lock(&mfd->lock);
+			pipe->pid = 0;
 			if (!list_empty(&pipe->used_list)) {
 				list_del_init(&pipe->used_list);
 				list_add(&pipe->cleanup_list,
@@ -942,6 +997,10 @@
 		if (rot) {
 			mdss_mdp_overlay_free_buf(&rot->src_buf);
 			mdss_mdp_overlay_free_buf(&rot->dst_buf);
+
+			rot->pid = 0;
+			if (!list_empty(&rot->list))
+				list_del_init(&rot->list);
 			ret = mdss_mdp_rotator_release(rot);
 		}
 	} else {
@@ -954,18 +1013,31 @@
 	return ret;
 }
 
-static int mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd)
+/**
+ * mdss_mdp_overlay_release_all() - release any overlays associated with fb dev
+ * @mfd:	Msm frame buffer structure associated with fb device
+ *
+ * Release any resources allocated by calling process, this can be called
+ * on fb_release to release any overlays/rotator sessions left open.
+ */
+static int __mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd)
 {
 	struct mdss_mdp_pipe *pipe;
+	struct mdss_mdp_rotator_session *rot, *tmp;
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	u32 unset_ndx = 0;
 	int cnt = 0;
+	int pid = current->tgid;
+
+	pr_debug("releasing all resources for fb%d pid=%d\n", mfd->index, pid);
 
 	mutex_lock(&mdp5_data->ov_lock);
 	mutex_lock(&mfd->lock);
 	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
-		unset_ndx |= pipe->ndx;
-		cnt++;
+		if (pipe->pid == pid) {
+			unset_ndx |= pipe->ndx;
+			cnt++;
+		}
 	}
 
 	if (cnt == 0 && !list_empty(&mdp5_data->pipes_cleanup)) {
@@ -985,6 +1057,14 @@
 	if (cnt)
 		mfd->mdp.kickoff_fnc(mfd);
 
+	list_for_each_entry_safe(rot, tmp, &mdp5_data->rot_proc_list, list) {
+		if (rot->pid == pid) {
+			if (!list_empty(&rot->list))
+				list_del_init(&rot->list);
+			mdss_mdp_rotator_release(rot);
+		}
+	}
+
 	return 0;
 }
 
@@ -1341,15 +1421,6 @@
 	mutex_unlock(&mdp5_data->ov_lock);
 }
 
-static void mdss_mdp_overlay_dispatch_vsync(struct work_struct *work)
-{
-	struct mdss_overlay_private *mdp5_data;
-	mdp5_data = container_of(work, struct mdss_overlay_private, vsync_work);
-	if (mdp5_data->ctl && mdp5_data->ctl->mfd)
-		sysfs_notify(&mdp5_data->ctl->mfd->fbi->dev->kobj, NULL,
-				"vsync_event");
-}
-
 /* function is called in irq context should have minimum processing */
 static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl,
 						ktime_t t)
@@ -1366,19 +1437,18 @@
 	pr_debug("vsync on fb%d play_cnt=%d\n", mfd->index, ctl->play_cnt);
 
 	mdp5_data->vsync_time = t;
-	schedule_work(&mdp5_data->vsync_work);
+	sysfs_notify_dirent(mdp5_data->vsync_event_sd);
 }
 
 int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
 {
-	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	int rc;
 
 	if (!ctl)
 		return -ENODEV;
 	if (!ctl->add_vsync_handler || !ctl->remove_vsync_handler)
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
 
 	rc = mutex_lock_interruptible(&ctl->lock);
 	if (rc)
@@ -1387,9 +1457,8 @@
 	if (!ctl->power_on) {
 		pr_debug("fb%d vsync pending first update en=%d\n",
 				mfd->index, en);
-		mdp5_data->vsync_pending = en;
 		mutex_unlock(&ctl->lock);
-		return 0;
+		return -EPERM;
 	}
 
 	pr_debug("fb%d vsync en=%d\n", mfd->index, en);
@@ -2008,11 +2077,7 @@
 	if (IS_ERR_VALUE(rc)) {
 		pr_err("Failed to turn on fb%d\n", mfd->index);
 		mdss_mdp_overlay_off(mfd);
-	} else if (mdp5_data->vsync_pending) {
-		mdp5_data->vsync_pending = 0;
-		mdss_mdp_overlay_vsync_ctrl(mfd, mdp5_data->vsync_pending);
 	}
-
 	return rc;
 }
 
@@ -2021,6 +2086,7 @@
 	int rc;
 	struct mdss_overlay_private *mdp5_data;
 	struct mdss_mdp_mixer *mixer;
+	int need_cleanup;
 
 	if (!mfd)
 		return -ENODEV;
@@ -2048,22 +2114,19 @@
 	if (mixer)
 		mixer->cursor_enabled = 0;
 
-	if (!mfd->ref_cnt) {
-		mdss_mdp_overlay_release_all(mfd);
-	} else {
-		int need_cleanup;
-		mutex_lock(&mfd->lock);
-		need_cleanup = !list_empty(&mdp5_data->pipes_cleanup);
-		mutex_unlock(&mfd->lock);
+	mutex_lock(&mfd->lock);
+	need_cleanup = !list_empty(&mdp5_data->pipes_cleanup);
+	mutex_unlock(&mfd->lock);
 
-		if (need_cleanup) {
-			pr_debug("cleaning up some pipes\n");
-			mdss_mdp_overlay_kickoff(mfd);
-		}
+	if (need_cleanup) {
+		pr_debug("cleaning up pipes on fb%d\n", mfd->index);
+		mdss_mdp_overlay_kickoff(mfd);
 	}
 
 	rc = mdss_mdp_ctl_stop(mdp5_data->ctl);
 	if (rc == 0) {
+		__mdss_mdp_overlay_free_list_purge(mfd);
+
 		if (!mfd->ref_cnt) {
 			mdp5_data->borderfill_enable = false;
 			mdss_mdp_ctl_destroy(mdp5_data->ctl);
@@ -2104,6 +2167,7 @@
 
 	mdp5_interface->on_fnc = mdss_mdp_overlay_on;
 	mdp5_interface->off_fnc = mdss_mdp_overlay_off;
+	mdp5_interface->release_fnc = __mdss_mdp_overlay_release_all;
 	mdp5_interface->do_histogram = NULL;
 	mdp5_interface->cursor_update = mdss_mdp_hw_cursor_update;
 	mdp5_interface->dma_fnc = mdss_mdp_overlay_pan_display;
@@ -2120,7 +2184,7 @@
 
 	INIT_LIST_HEAD(&mdp5_data->pipes_used);
 	INIT_LIST_HEAD(&mdp5_data->pipes_cleanup);
-	INIT_WORK(&mdp5_data->vsync_work, mdss_mdp_overlay_dispatch_vsync);
+	INIT_LIST_HEAD(&mdp5_data->rot_proc_list);
 	mutex_init(&mdp5_data->ov_lock);
 	mdp5_data->hw_refresh = true;
 	mdp5_data->overlay_play_enable = true;
@@ -2143,6 +2207,14 @@
 		goto init_fail;
 	}
 
+	mdp5_data->vsync_event_sd = sysfs_get_dirent(dev->kobj.sd, NULL,
+						     "vsync_event");
+	if (!mdp5_data->vsync_event_sd) {
+		pr_err("vsync_event sysfs lookup failed\n");
+		rc = -ENODEV;
+		goto init_fail;
+	}
+
 	pm_runtime_set_suspended(&mfd->pdev->dev);
 	pm_runtime_enable(&mfd->pdev->dev);
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 6cedd98..95eb381 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -2003,6 +2003,10 @@
 	u32 offset, disp_num, dspp_num = 0;
 	uint16_t *tbl_off;
 	struct mdp_gamut_cfg_data local_cfg;
+	uint16_t *r_tbl[MDP_GAMUT_TABLE_NUM];
+	uint16_t *g_tbl[MDP_GAMUT_TABLE_NUM];
+	uint16_t *b_tbl[MDP_GAMUT_TABLE_NUM];
+
 
 	if (!ctl)
 		return -EINVAL;
@@ -2030,22 +2034,67 @@
 		offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
 			  MDSS_MDP_REG_DSPP_GAMUT_BASE;
 		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			r_tbl[i] = kzalloc(
+				sizeof(uint16_t) * config->tbl_size[i],
+				GFP_KERNEL);
+			if (!r_tbl[i]) {
+				pr_err("%s: alloc failed\n", __func__);
+				goto gamut_config_exit;
+			}
 			for (j = 0; j < config->tbl_size[i]; j++)
-				config->r_tbl[i][j] =
+				r_tbl[i][j] =
 					(u16)MDSS_MDP_REG_READ(offset);
 			offset += 4;
+			ret = copy_to_user(config->r_tbl[i], r_tbl[i],
+				     sizeof(uint16_t) * config->tbl_size[i]);
+			kfree(r_tbl[i]);
+			if (ret) {
+				pr_err("%s: copy tbl to usr failed\n",
+					__func__);
+				goto gamut_config_exit;
+			}
 		}
 		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			g_tbl[i] = kzalloc(
+				sizeof(uint16_t) * config->tbl_size[i],
+				GFP_KERNEL);
+			if (!g_tbl[i]) {
+				pr_err("%s: alloc failed\n", __func__);
+				goto gamut_config_exit;
+			}
 			for (j = 0; j < config->tbl_size[i]; j++)
-				config->g_tbl[i][j] =
+				g_tbl[i][j] =
 					(u16)MDSS_MDP_REG_READ(offset);
 			offset += 4;
+			ret = copy_to_user(config->g_tbl[i], g_tbl[i],
+				     sizeof(uint16_t) * config->tbl_size[i]);
+			kfree(g_tbl[i]);
+			if (ret) {
+				pr_err("%s: copy tbl to usr failed\n",
+					__func__);
+				goto gamut_config_exit;
+			}
 		}
 		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+			b_tbl[i] = kzalloc(
+				sizeof(uint16_t) * config->tbl_size[i],
+				GFP_KERNEL);
+			if (!b_tbl[i]) {
+				pr_err("%s: alloc failed\n", __func__);
+				goto gamut_config_exit;
+			}
 			for (j = 0; j < config->tbl_size[i]; j++)
-				config->b_tbl[i][j] =
+				b_tbl[i][j] =
 					(u16)MDSS_MDP_REG_READ(offset);
 			offset += 4;
+			ret = copy_to_user(config->b_tbl[i], b_tbl[i],
+				     sizeof(uint16_t) * config->tbl_size[i]);
+			kfree(b_tbl[i]);
+			if (ret) {
+				pr_err("%s: copy tbl to usr failed\n",
+					__func__);
+				goto gamut_config_exit;
+			}
 		}
 		*copyback = 1;
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
@@ -3282,7 +3331,7 @@
 	unsigned int ptr;
 	ptr = (unsigned int) addr;
 	/* if request is outside the MDP reg-map or is not aligned 4 */
-	if (ptr == 0x0 || ptr > 0x5138 || ptr % 0x4)
+	if (ptr > 0x5138 || ptr % 0x4)
 		goto end;
 	if (ptr >= 0x100 && ptr <= 0x5138) {
 		/* if ptr is in dspp range */
@@ -3337,7 +3386,8 @@
 				ret = 1;
 		else if (ptr == 0x2234 || ptr == 0x1e34 || ptr == 0x2634)
 				ret = 1;
-	}
+	} else if (ptr == 0x0)
+		ret = 1;
 end:
 	return ret;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index fcd90e1..8381c5b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -74,14 +74,14 @@
 
 	mixer = mdss_mdp_wb_mixer_alloc(1);
 	if (!mixer) {
-		pr_err("wb mixer alloc failed\n");
+		pr_debug("wb mixer alloc failed\n");
 		return NULL;
 	}
 
 	pipe = mdss_mdp_pipe_alloc_dma(mixer);
 	if (!pipe) {
 		mdss_mdp_wb_mixer_destroy(mixer);
-		pr_err("dma pipe allocation failed\n");
+		pr_debug("dma pipe allocation failed\n");
 	}
 
 	return pipe;
@@ -134,6 +134,7 @@
 
 static int mdss_mdp_rotator_pipe_dequeue(struct mdss_mdp_rotator_session *rot)
 {
+	int rc;
 	if (rot->pipe) {
 		pr_debug("reusing existing session=%d\n", rot->pipe->num);
 		mdss_mdp_rotator_busy_wait(rot);
@@ -153,12 +154,19 @@
 					       struct mdss_mdp_rotator_session,
 					       head);
 
-			pr_debug("wait for rotator pipe=%d\n", tmp->pipe->num);
-			mdss_mdp_rotator_busy_wait(tmp);
+			rc = mdss_mdp_rotator_busy_wait(tmp);
+			list_del(&tmp->head);
+			if (rc) {
+				pr_err("no pipe attached to session=%d\n",
+					tmp->session_id);
+				return rc;
+			} else {
+				pr_debug("waited for rotator pipe=%d\n",
+					  tmp->pipe->num);
+			}
 			rot->pipe = tmp->pipe;
 			tmp->pipe = NULL;
 
-			list_del(&tmp->head);
 			list_add_tail(&rot->head, &rotator_queue);
 		} else {
 			pr_err("no available rotator pipes\n");
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.h b/drivers/video/msm/mdss/mdss_mdp_rotator.h
index 43c9e6a..74eeeeb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.h
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.h
@@ -23,6 +23,7 @@
 	u32 session_id;
 	u32 ref_cnt;
 	u32 params_changed;
+	int pid;
 
 	u32 format;
 	u32 flags;
@@ -43,6 +44,7 @@
 	struct mdss_mdp_data dst_buf;
 
 	struct list_head head;
+	struct list_head list;
 	struct mdss_mdp_rotator_session *next;
 };
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 0c74137..72288c2 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -533,11 +533,11 @@
 		goto kickoff_fail;
 	}
 
-	ret = wait_for_completion_interruptible_timeout(&comp, KOFF_TIMEOUT);
-	if (ret <= 0) {
+	ret = wait_for_completion_timeout(&comp, KOFF_TIMEOUT);
+	if (ret == 0)
 		WARN(1, "wfd kick off time out=%d ctl=%d", ret, ctl->num);
+	else
 		ret = 0;
-	}
 
 	if (wb && node) {
 		mutex_lock(&wb->lock);
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index e8a6312..becf455 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -221,6 +221,8 @@
 struct mdss_panel_info {
 	u32 xres;
 	u32 yres;
+	u32 physical_width;
+	u32 physical_height;
 	u32 bpp;
 	u32 type;
 	u32 wait_cycle;
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index c66d50d..a759e86 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -357,14 +357,20 @@
 static int mhl_sii_wait_for_rgnd(struct mhl_tx_ctrl *mhl_ctrl)
 {
 	int timeout;
-	/* let isr handle RGND interrupt */
+
 	pr_debug("%s:%u\n", __func__, __LINE__);
 	INIT_COMPLETION(mhl_ctrl->rgnd_done);
+	/*
+	 * after toggling reset line and enabling disc
+	 * tx can take a while to generate intr
+	 */
 	timeout = wait_for_completion_interruptible_timeout
-		(&mhl_ctrl->rgnd_done, HZ);
+		(&mhl_ctrl->rgnd_done, HZ * 3);
 	if (!timeout) {
-		/* most likely nothing plugged in USB */
-		/* USB HOST connected or already in USB mode */
+		/*
+		 * most likely nothing plugged in USB
+		 * USB HOST connected or already in USB mode
+		 */
 		pr_warn("%s:%u timedout\n", __func__, __LINE__);
 		return -ENODEV;
 	}
@@ -380,9 +386,25 @@
 	struct i2c_client *client = mhl_ctrl->i2c_handle;
 	unsigned long flags;
 
-	enable_irq(client->irq);
+	if (!mhl_ctrl->irq_req_done) {
+		rc = request_threaded_irq(mhl_ctrl->i2c_handle->irq, NULL,
+					  &mhl_tx_isr,
+					  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+					  client->dev.driver->name, mhl_ctrl);
+		if (rc) {
+			pr_err("request_threaded_irq failed, status: %d\n",
+			       rc);
+			return -EINVAL;
+		} else {
+			pr_debug("request_threaded_irq succeeded\n");
+			mhl_ctrl->irq_req_done = true;
+		}
+	} else {
+		enable_irq(client->irq);
+	}
+
 	/* wait for i2c interrupt line to be activated */
-	msleep(300);
+	msleep(100);
 
 	if (id) {
 		/* When MHL cable is disconnected we get a sii8334
@@ -413,8 +435,10 @@
 		/* chipset PR recommends waiting for at least 100 ms
 		 * the chipset needs longer to come out of D3 state.
 		 */
-		msleep(300);
+		msleep(100);
 		mhl_init_reg_settings(mhl_ctrl, true);
+		/* allow tx to enable dev disc after D3 state */
+		msleep(100);
 		rc = mhl_sii_wait_for_rgnd(mhl_ctrl);
 	} else {
 		if (mhl_ctrl->cur_state == POWER_STATE_D3) {
@@ -493,6 +517,10 @@
 	uint8_t i;
 	struct i2c_client *client = mhl_ctrl->i2c_handle;
 
+	/* Read the chip rev ID */
+	mhl_ctrl->chip_rev_id = MHL_SII_PAGE0_RD(0x04);
+	pr_debug("MHL: chip rev ID read=[%x]\n", mhl_ctrl->chip_rev_id);
+
 	/*
 	 * REG_SRST
 	 */
@@ -1428,40 +1456,6 @@
 	return IRQ_HANDLED;
 }
 
-static int mhl_tx_chip_init(struct mhl_tx_ctrl *mhl_ctrl)
-{
-	uint8_t chip_rev_id = 0x00;
-	struct i2c_client *client = mhl_ctrl->i2c_handle;
-	unsigned long flags;
-
-
-	spin_lock_irqsave(&mhl_ctrl->lock, flags);
-	mhl_ctrl->dwnstream_hpd = 0;
-	mhl_ctrl->tx_powered_off = false;
-	spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
-
-	/* Reset the TX chip */
-	mhl_sii_reset_pin(mhl_ctrl, 0);
-	msleep(20);
-	mhl_sii_reset_pin(mhl_ctrl, 1);
-	/* TX PR-guide requires a 100 ms wait here */
-	msleep(100);
-
-	/* Read the chip rev ID */
-	chip_rev_id = MHL_SII_PAGE0_RD(0x04);
-	pr_debug("MHL: chip rev ID read=[%x]\n", chip_rev_id);
-	mhl_ctrl->chip_rev_id = chip_rev_id;
-
-	/*
-	 * Need to disable MHL discovery if
-	 * MHL-USB handshake is implemented
-	 */
-	mhl_init_reg_settings(mhl_ctrl, true);
-	switch_mode(mhl_ctrl, POWER_STATE_D3, true);
-	pr_debug("%s:%u: power_down\n", __func__, __LINE__);
-	mhl_tx_down(mhl_ctrl);
-	return 0;
-}
 
 static int mhl_sii_reg_config(struct i2c_client *client, bool enable)
 {
@@ -1791,30 +1785,12 @@
 		}
 	}
 
-	rc = mhl_tx_chip_init(mhl_ctrl);
-	if (rc) {
-		pr_err("%s: tx chip init failed [%d]\n",
-			__func__, rc);
-		goto failed_probe;
-	}
+	mhl_ctrl->dwnstream_hpd = 0;
+	mhl_ctrl->tx_powered_off = false;
+
 
 	init_completion(&mhl_ctrl->rgnd_done);
 
-	pr_debug("%s: IRQ from GPIO INTR = %d\n",
-		__func__, mhl_ctrl->i2c_handle->irq);
-	pr_debug("%s: Driver name = [%s]\n", __func__,
-		client->dev.driver->name);
-	rc = request_threaded_irq(mhl_ctrl->i2c_handle->irq, NULL,
-				   &mhl_tx_isr,
-				  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-				 client->dev.driver->name, mhl_ctrl);
-	if (rc) {
-		pr_err("request_threaded_irq failed, status: %d\n",
-		       rc);
-		goto failed_probe;
-	} else {
-		pr_debug("request_threaded_irq succeeded\n");
-	}
 
 	mhl_ctrl->mhl_psy.name = "ext-vbus";
 	mhl_ctrl->mhl_psy.type = POWER_SUPPLY_TYPE_USB_DCP;
@@ -1940,15 +1916,21 @@
 #if defined(CONFIG_PM) || defined(CONFIG_PM_SLEEP)
 static int mhl_i2c_suspend_sub(struct i2c_client *client)
 {
-	enable_irq_wake(client->irq);
-	disable_irq(client->irq);
+	struct mhl_tx_ctrl *mhl_ctrl = i2c_get_clientdata(client);
+
+	if (mhl_ctrl->irq_req_done) {
+		enable_irq_wake(client->irq);
+		disable_irq(client->irq);
+	}
 	return 0;
 }
 
 static int mhl_i2c_resume_sub(struct i2c_client *client)
 {
-	disable_irq_wake(client->irq);
-	enable_irq(client->irq);
+	struct mhl_tx_ctrl *mhl_ctrl = i2c_get_clientdata(client);
+
+	if (mhl_ctrl->irq_req_done)
+		disable_irq_wake(client->irq);
 	return 0;
 }
 #endif /* defined(CONFIG_PM) || defined(CONFIG_PM_SLEEP) */
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index f6ca334..f66a034 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -260,6 +260,7 @@
 header-y += msdos_fs.h
 header-y += msg.h
 header-y += msm_adc.h
+header-y += msm_dsps.h
 header-y += msm_ion.h
 header-y += epm_adc.h
 header-y += mtio.h
diff --git a/include/linux/batterydata-lib.h b/include/linux/batterydata-lib.h
index fe2d86f..ff38eb6 100644
--- a/include/linux/batterydata-lib.h
+++ b/include/linux/batterydata-lib.h
@@ -26,6 +26,8 @@
 
 #define MAX_SINGLE_LUT_COLS	20
 
+#define MAX_BATT_ID_NUM		4
+
 struct single_row_lut {
 	int x[MAX_SINGLE_LUT_COLS];
 	int y[MAX_SINGLE_LUT_COLS];
@@ -69,6 +71,11 @@
 	int ocv[PC_TEMP_ROWS][PC_TEMP_COLS];
 };
 
+struct batt_ids {
+	int kohm[MAX_BATT_ID_NUM];
+	int num;
+};
+
 enum battery_type {
 	BATT_UNKNOWN = 0,
 	BATT_PALLADIUM,
@@ -99,7 +106,7 @@
  * @cutoff_uv:		cutoff voltage of the battery
  * @iterm_ua:		termination current of the battery when charging
  *			to 100%
- * @batt_id_kohm:	battery id resistor value
+ * @batt_id_kohm:	the best matched battery id resistor value
  */
 
 struct bms_battery_data {
diff --git a/include/linux/cm36283.h b/include/linux/cm36283.h
index cccd5ee..2872d04 100644
--- a/include/linux/cm36283.h
+++ b/include/linux/cm36283.h
@@ -17,6 +17,8 @@
 #ifndef __LINUX_CM36283_H
 #define __LINUX_CM36283_H
 
+#include <linux/bitops.h>
+
 #define CM36283_I2C_NAME "cm36283"
 
 /* Define Slave Address*/
@@ -102,9 +104,31 @@
 #define INT_FLAG_PS_IF_CLOSE         (1<<9)
 #define INT_FLAG_PS_IF_AWAY          (1<<8)  
 
+#define LS_PWR_ON		BIT(0)
+#define PS_PWR_ON		BIT(1)
+
+#define CAPELLA_CM3602_IOCTL_MAGIC 'c'
+#define CAPELLA_CM3602_IOCTL_GET_ENABLED \
+	_IOR(CAPELLA_CM3602_IOCTL_MAGIC, 1, int *)
+#define CAPELLA_CM3602_IOCTL_ENABLE \
+	_IOW(CAPELLA_CM3602_IOCTL_MAGIC, 2, int *)
+
+#define LIGHTSENSOR_IOCTL_MAGIC 'l'
+#define LIGHTSENSOR_IOCTL_GET_ENABLED _IOR(LIGHTSENSOR_IOCTL_MAGIC, 1, int *)
+#define LIGHTSENSOR_IOCTL_ENABLE _IOW(LIGHTSENSOR_IOCTL_MAGIC, 2, int *)
+
 extern unsigned int ps_kparam1;
 extern unsigned int ps_kparam2;
 
+#define CM36283_LEVELS_SIZE		10
+
+enum {
+	CM36283_ALS_IT0 = 0,
+	CM36283_ALS_IT1,
+	CM36283_ALS_IT2,
+	CM36283_ALS_IT3,
+};
+
 struct cm36283_platform_data {
 	int intr;
 	uint16_t levels[10];
@@ -116,6 +140,7 @@
 	uint16_t ls_cmd;
 	uint16_t ps_conf1_val;
 	uint16_t ps_conf3_val;	
+	bool polling;
 };
 
 #endif
diff --git a/include/linux/input/ft5x06_ts.h b/include/linux/input/ft5x06_ts.h
index af8c332..149133e 100644
--- a/include/linux/input/ft5x06_ts.h
+++ b/include/linux/input/ft5x06_ts.h
@@ -23,7 +23,20 @@
 #define FT5X36_ID		0x14
 #define FT6X06_ID		0x06
 
+struct fw_upgrade_info {
+	bool auto_cal;
+	u16 delay_aa;
+	u16 delay_55;
+	u8 upgrade_id_1;
+	u8 upgrade_id_2;
+	u16 delay_readid;
+	u16 delay_erase_flash;
+};
+
 struct ft5x06_ts_platform_data {
+	struct fw_upgrade_info info;
+	const char *name;
+	const char *fw_name;
 	u32 irqflags;
 	u32 irq_gpio;
 	u32 irq_gpio_flags;
@@ -38,6 +51,11 @@
 	u32 panel_miny;
 	u32 panel_maxx;
 	u32 panel_maxy;
+	u32 group_id;
+	u32 hard_rst_dly;
+	u32 soft_rst_dly;
+	u32 num_max_touches;
+	bool fw_vkey_support;
 	bool no_force_update;
 	bool i2c_pull_up;
 	int (*power_init) (bool);
diff --git a/include/linux/input/synaptics_dsx.h b/include/linux/input/synaptics_dsx.h
index 73016d6..5df022e 100644
--- a/include/linux/input/synaptics_dsx.h
+++ b/include/linux/input/synaptics_dsx.h
@@ -35,8 +35,11 @@
  * struct synaptics_rmi4_platform_data - rmi4 platform data
  * @x_flip: x flip flag
  * @y_flip: y flip flag
+ * @i2c_pull_up: pull up i2c bus with regulator
+ * @power_down_enable: enable complete regulator shutdown in suspend
  * @irq_gpio: attention interrupt gpio
  * @irq_flags: flags used by the irq
+ * @reset_flags: flags used by reset line
  * @reset_gpio: reset gpio
  * @panel_x: panel maximum values on the x
  * @panel_y: panel maximum values on the y
@@ -47,6 +50,8 @@
 	bool x_flip;
 	bool y_flip;
 	bool i2c_pull_up;
+	bool power_down_enable;
+	bool disable_gpios;
 	unsigned irq_gpio;
 	u32 irq_flags;
 	u32 reset_flags;
diff --git a/include/linux/mfd/wcd9xxx/core-resource.h b/include/linux/mfd/wcd9xxx/core-resource.h
new file mode 100644
index 0000000..442496e
--- /dev/null
+++ b/include/linux/mfd/wcd9xxx/core-resource.h
@@ -0,0 +1,137 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MFD_CORE_RESOURCE_H__
+#define __MFD_CORE_RESOURCE_H__
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/pm_qos.h>
+
+#define WCD9XXX_MAX_IRQ_REGS 4
+#define WCD9XXX_MAX_NUM_IRQS (WCD9XXX_MAX_IRQ_REGS * 8)
+
+struct intr_data {
+	int intr_num;
+	bool clear_first;
+};
+
+enum wcd9xxx_pm_state {
+	WCD9XXX_PM_SLEEPABLE,
+	WCD9XXX_PM_AWAKE,
+	WCD9XXX_PM_ASLEEP,
+};
+
+enum wcd9xxx_intf_status {
+	WCD9XXX_INTERFACE_TYPE_PROBING,
+	WCD9XXX_INTERFACE_TYPE_SLIMBUS,
+	WCD9XXX_INTERFACE_TYPE_I2C,
+};
+
+struct wcd9xxx_core_resource {
+	struct mutex irq_lock;
+	struct mutex nested_irq_lock;
+
+	enum wcd9xxx_pm_state pm_state;
+	struct mutex pm_lock;
+	/* pm_wq notifies change of pm_state */
+	wait_queue_head_t pm_wq;
+	struct pm_qos_request pm_qos_req;
+	int wlock_holders;
+
+
+	/* holds the table of interrupts per codec */
+	const struct intr_data *intr_table;
+	int intr_table_size;
+	unsigned int irq_base;
+	unsigned int irq;
+	u8 irq_masks_cur[WCD9XXX_MAX_IRQ_REGS];
+	u8 irq_masks_cache[WCD9XXX_MAX_IRQ_REGS];
+	bool irq_level_high[WCD9XXX_MAX_NUM_IRQS];
+	int num_irqs;
+	int num_irq_regs;
+
+	/* Callback functions to read/write codec registers */
+	int (*codec_reg_read) (struct wcd9xxx_core_resource *,
+				unsigned short);
+	int (*codec_reg_write) (struct wcd9xxx_core_resource *,
+				unsigned short, u8);
+	int (*codec_bulk_read) (struct wcd9xxx_core_resource *,
+				unsigned short, int, u8 *);
+
+	/* Pointer to parent container data structure */
+	void *parent;
+
+	struct device *dev;
+};
+
+extern int wcd9xxx_core_res_init(
+	struct wcd9xxx_core_resource*,
+	int, int,
+	int (*codec_read)(struct wcd9xxx_core_resource *, unsigned short),
+	int (*codec_write)(struct wcd9xxx_core_resource *, unsigned short, u8),
+	int (*codec_bulk_read) (struct wcd9xxx_core_resource *, unsigned short,
+							int, u8 *));
+
+extern void wcd9xxx_core_res_deinit(
+	struct wcd9xxx_core_resource *);
+
+extern int wcd9xxx_core_res_suspend(
+	struct wcd9xxx_core_resource *,
+	pm_message_t);
+
+extern int wcd9xxx_core_res_resume(
+	struct wcd9xxx_core_resource *);
+
+extern int wcd9xxx_core_irq_init(
+	struct wcd9xxx_core_resource*);
+
+extern int wcd9xxx_initialize_irq(
+	struct wcd9xxx_core_resource*,
+	unsigned int,
+	unsigned int);
+
+enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void);
+void wcd9xxx_set_intf_type(enum wcd9xxx_intf_status);
+
+bool wcd9xxx_lock_sleep(struct wcd9xxx_core_resource *);
+void wcd9xxx_unlock_sleep(struct wcd9xxx_core_resource *);
+void wcd9xxx_nested_irq_lock(struct wcd9xxx_core_resource *);
+void wcd9xxx_nested_irq_unlock(struct wcd9xxx_core_resource *);
+enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(
+			struct wcd9xxx_core_resource *,
+			enum wcd9xxx_pm_state,
+			enum wcd9xxx_pm_state);
+
+int wcd9xxx_request_irq(struct wcd9xxx_core_resource *, int,
+			irq_handler_t, const char *, void *);
+
+void wcd9xxx_free_irq(struct wcd9xxx_core_resource *, int, void*);
+void wcd9xxx_enable_irq(struct wcd9xxx_core_resource *, int);
+void wcd9xxx_disable_irq(struct wcd9xxx_core_resource *, int);
+void wcd9xxx_disable_irq_sync(struct wcd9xxx_core_resource *, int);
+int wcd9xxx_reg_read(struct wcd9xxx_core_resource *,
+					 unsigned short);
+int wcd9xxx_reg_write(struct wcd9xxx_core_resource *,
+					  unsigned short, u8);
+int wcd9xxx_bulk_read(struct wcd9xxx_core_resource *,
+					unsigned short, int, u8 *);
+int wcd9xxx_bulk_write(struct wcd9xxx_core_resource*,
+					 unsigned short, int, u8*);
+int wcd9xxx_irq_init(struct wcd9xxx_core_resource *);
+void wcd9xxx_irq_exit(struct wcd9xxx_core_resource *);
+int wcd9xxx_core_res_resume(
+	struct wcd9xxx_core_resource *);
+int wcd9xxx_core_res_suspend(
+	struct wcd9xxx_core_resource *,
+	pm_message_t);
+#endif
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index e688bd9..c2ad2b4 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -14,12 +14,10 @@
 #define __MFD_TABLA_CORE_H__
 
 #include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/pm_qos.h>
 #include <linux/platform_device.h>
 #include <linux/of_irq.h>
+#include <linux/mfd/wcd9xxx/core-resource.h>
 
-#define WCD9XXX_NUM_IRQ_REGS 4
 
 #define WCD9XXX_SLIM_NUM_PORT_REG 3
 #define TABLA_VERSION_1_0	0
@@ -90,6 +88,7 @@
 	WCD9XXX_IRQ_VBAT_MONITOR_ATTACK,
 	WCD9XXX_IRQ_VBAT_MONITOR_RELEASE,
 	WCD9XXX_NUM_IRQS,
+	WCD9XXX_IRQ_RESERVED_2 = WCD9XXX_NUM_IRQS,
 };
 
 enum {
@@ -99,17 +98,6 @@
 	TAPAN_NUM_IRQS = WCD9XXX_NUM_IRQS,
 };
 
-
-#define MAX(X, Y) (((int)X) >= ((int)Y) ? (X) : (Y))
-#define WCD9XXX_MAX_NUM_IRQS (MAX(MAX(TABLA_NUM_IRQS, SITAR_NUM_IRQS), \
-				  TAIKO_NUM_IRQS))
-
-enum wcd9xxx_pm_state {
-	WCD9XXX_PM_SLEEPABLE,
-	WCD9XXX_PM_AWAKE,
-	WCD9XXX_PM_ASLEEP,
-};
-
 /*
  * data structure for Slimbus and I2S channel.
  * Some of fields are only used in smilbus mode
@@ -145,12 +133,6 @@
 	wait_queue_head_t dai_wait;
 };
 
-enum wcd9xxx_intf_status {
-	WCD9XXX_INTERFACE_TYPE_PROBING,
-	WCD9XXX_INTERFACE_TYPE_SLIMBUS,
-	WCD9XXX_INTERFACE_TYPE_I2C,
-};
-
 #define WCD9XXX_CH(xport, xshift) \
 	{.port = xport, .shift = xshift}
 
@@ -178,8 +160,6 @@
 	struct slim_device *slim_slave;
 	struct mutex io_lock;
 	struct mutex xfer_lock;
-	struct mutex irq_lock;
-	struct mutex nested_irq_lock;
 	u8 version;
 
 	int reset_gpio;
@@ -188,6 +168,7 @@
 			int bytes, void *dest, bool interface_reg);
 	int (*write_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
 			int bytes, void *src, bool interface_reg);
+	int (*dev_down)(struct wcd9xxx *wcd9xxx);
 	int (*post_reset)(struct wcd9xxx *wcd9xxx);
 
 	void *ssr_priv;
@@ -196,21 +177,11 @@
 	u32 num_of_supplies;
 	struct regulator_bulk_data *supplies;
 
-	enum wcd9xxx_pm_state pm_state;
-	struct mutex pm_lock;
-	/* pm_wq notifies change of pm_state */
-	wait_queue_head_t pm_wq;
-	struct pm_qos_request pm_qos_req;
-	int wlock_holders;
+	struct wcd9xxx_core_resource core_res;
 
 	u16 id_minor;
 	u16 id_major;
 
-	unsigned int irq_base;
-	unsigned int irq;
-	u8 irq_masks_cur[WCD9XXX_NUM_IRQ_REGS];
-	u8 irq_masks_cache[WCD9XXX_NUM_IRQ_REGS];
-	bool irq_level_high[WCD9XXX_MAX_NUM_IRQS];
 	/* Slimbus or I2S port */
 	u32 num_rx_port;
 	u32 num_tx_port;
@@ -221,36 +192,11 @@
 	const struct wcd9xxx_codec_type *codec_type;
 };
 
-int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
-int wcd9xxx_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
-		u8 val);
 int wcd9xxx_interface_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
 int wcd9xxx_interface_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
 		u8 val);
-int wcd9xxx_bulk_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
-			int count, u8 *buf);
-int wcd9xxx_bulk_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
-			int count, u8 *buf);
-int wcd9xxx_irq_init(struct wcd9xxx *wcd9xxx);
-void wcd9xxx_irq_exit(struct wcd9xxx *wcd9xxx);
 int wcd9xxx_get_logical_addresses(u8 *pgd_la, u8 *inf_la);
-enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void);
 
-bool wcd9xxx_lock_sleep(struct wcd9xxx *wcd9xxx);
-void wcd9xxx_unlock_sleep(struct wcd9xxx *wcd9xxx);
-void wcd9xxx_nested_irq_lock(struct wcd9xxx *wcd9xxx);
-void wcd9xxx_nested_irq_unlock(struct wcd9xxx *wcd9xxx);
-enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(struct wcd9xxx *wcd9xxx,
-				enum wcd9xxx_pm_state o,
-				enum wcd9xxx_pm_state n);
-
-int wcd9xxx_request_irq(struct wcd9xxx *wcd9xxx, int irq,
-			irq_handler_t handler, const char *name, void *data);
-
-void wcd9xxx_free_irq(struct wcd9xxx *wcd9xxx, int irq, void *data);
-void wcd9xxx_enable_irq(struct wcd9xxx *wcd9xxx, int irq);
-void wcd9xxx_disable_irq(struct wcd9xxx *wcd9xxx, int irq);
-void wcd9xxx_disable_irq_sync(struct wcd9xxx *wcd9xxx, int irq);
 #if defined(CONFIG_WCD9310_CODEC) || \
 	defined(CONFIG_WCD9304_CODEC) || \
 	defined(CONFIG_WCD9320_CODEC) || \
@@ -264,4 +210,16 @@
 	return 0;
 }
 #endif	/* CONFIG_OF */
+static inline void wcd9xxx_reg_update(struct wcd9xxx *core,
+				      unsigned short reg,
+				      u8 mask, u8 val)
+{
+	u8 reg_val;
+
+	if (core) {
+		reg_val = wcd9xxx_reg_read(&core->core_res, reg);
+		reg_val = (reg_val & ~mask) | (val & mask);
+		wcd9xxx_reg_write(&core->core_res, reg, reg_val);
+	}
+}
 #endif
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index d1ee11c..71dec42 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -165,6 +165,7 @@
 	bool tx_powered_off;
 	uint8_t dwnstream_hpd;
 	bool mhl_det_discon;
+	bool irq_req_done;
 };
 
 int mhl_i2c_reg_read(struct i2c_client *client,
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 2cb297e..9d15908 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -67,6 +67,7 @@
 #define MMC_HIGH_52_MAX_DTR	52000000
 #define MMC_HIGH_DDR_MAX_DTR	52000000
 #define MMC_HS200_MAX_DTR	200000000
+#define MMC_HS400_MAX_DTR	200000000
 	unsigned int		sectors;
 	unsigned int		card_type;
 	unsigned int		hc_erase_size;		/* In sectors */
@@ -329,6 +330,7 @@
 #define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
 #define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
 #define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
+#define MMC_STATE_HIGHSPEED_400	(1<<9)		/* card is in HS400 mode */
 #define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
 #define MMC_STATE_NEED_BKOPS	(1<<11)		/* card needs to do BKOPS */
 	unsigned int		quirks; 	/* card quirks */
@@ -347,6 +349,8 @@
 #define MMC_QUIRK_SEC_ERASE_TRIM_BROKEN (1<<10)	/* Skip secure for erase/trim */
 						/* byte mode */
 #define MMC_QUIRK_INAND_DATA_TIMEOUT  (1<<8)    /* For incorrect data timeout */
+/* To avoid eMMC device getting broken permanently due to HPI feature */
+#define MMC_QUIRK_BROKEN_HPI (1 << 11)
 
 	unsigned int		erase_size;	/* erase size in sectors */
  	unsigned int		erase_shift;	/* if erase unit is power 2 */
@@ -426,6 +430,8 @@
 
 	/* SDIO-specfic fields. You can use SDIO_ANY_ID here of course */
 	u16 cis_vendor, cis_device;
+	/* for MMC cards */
+	unsigned int ext_csd_rev;
 
 	void (*vendor_fixup)(struct mmc_card *card, int data);
 	int data;
@@ -435,11 +441,19 @@
 #define CID_OEMID_ANY ((unsigned short) -1)
 #define CID_NAME_ANY (NULL)
 
+#define EXT_CSD_REV_ANY (-1u)
+
+#define CID_MANFID_SANDISK	0x2
+#define CID_MANFID_TOSHIBA	0x11
+#define CID_MANFID_MICRON	0x13
+#define CID_MANFID_SAMSUNG	0x15
+#define CID_MANFID_HYNIX	0x90
+
 #define END_FIXUP { 0 }
 
 #define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end,	\
 		   _cis_vendor, _cis_device,				\
-		   _fixup, _data)					\
+		   _fixup, _data, _ext_csd_rev)				\
 	{						   \
 		.name = (_name),			   \
 		.manfid = (_manfid),			   \
@@ -450,23 +464,30 @@
 		.cis_device = (_cis_device),		   \
 		.vendor_fixup = (_fixup),		   \
 		.data = (_data),			   \
+		.ext_csd_rev = (_ext_csd_rev),		   \
 	 }
 
 #define MMC_FIXUP_REV(_name, _manfid, _oemid, _rev_start, _rev_end,	\
-		      _fixup, _data)					\
+		      _fixup, _data, _ext_csd_rev)			\
 	_FIXUP_EXT(_name, _manfid,					\
 		   _oemid, _rev_start, _rev_end,			\
 		   SDIO_ANY_ID, SDIO_ANY_ID,				\
-		   _fixup, _data)					\
+		   _fixup, _data, _ext_csd_rev)				\
 
-#define MMC_FIXUP(_name, _manfid, _oemid, _fixup, _data) \
-	MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data)
+#define MMC_FIXUP(_name, _manfid, _oemid, _fixup, _data)		\
+	MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data,	\
+		      EXT_CSD_REV_ANY)
+
+#define MMC_FIXUP_EXT_CSD_REV(_name, _manfid, _oemid, _fixup, _data,	\
+			      _ext_csd_rev)				\
+	MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data,	\
+		      _ext_csd_rev)
 
 #define SDIO_FIXUP(_vendor, _device, _fixup, _data)			\
 	_FIXUP_EXT(CID_NAME_ANY, CID_MANFID_ANY,			\
 		    CID_OEMID_ANY, 0, -1ull,				\
 		   _vendor, _device,					\
-		   _fixup, _data)					\
+		   _fixup, _data, EXT_CSD_REV_ANY)			\
 
 #define cid_rev(hwrev, fwrev, year, month)	\
 	(((u64) hwrev) << 40 |                  \
@@ -502,6 +523,7 @@
 #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
 #define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
 #define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
+#define mmc_card_hs400(c)	((c)->state & MMC_STATE_HIGHSPEED_400)
 #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
 #define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
 #define mmc_card_uhs(c)		((c)->state & MMC_STATE_ULTRAHIGHSPEED)
@@ -514,9 +536,14 @@
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
 #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
+#define mmc_card_clr_highspeed(c) ((c)->state &= ~MMC_STATE_HIGHSPEED)
 #define mmc_card_set_hs200(c)	((c)->state |= MMC_STATE_HIGHSPEED_200)
+#define mmc_card_clr_hs200(c)	((c)->state &= ~MMC_STATE_HIGHSPEED_200)
+#define mmc_card_set_hs400(c)	((c)->state |= MMC_STATE_HIGHSPEED_400)
+#define mmc_card_clr_hs400(c)	((c)->state &= ~MMC_STATE_HIGHSPEED_400)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
 #define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
+#define mmc_card_clr_ddr_mode(c) ((c)->state &= ~MMC_STATE_HIGHSPEED_DDR)
 #define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index dbafdfc..e1dbd21 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -61,6 +61,7 @@
 #define MMC_TIMING_UHS_SDR104	4
 #define MMC_TIMING_UHS_DDR50	5
 #define MMC_TIMING_MMC_HS200	6
+#define MMC_TIMING_MMC_HS400	7
 
 #define MMC_SDR_MODE		0
 #define MMC_1_2V_DDR_MODE	1
@@ -245,6 +246,7 @@
 						/* DDR mode at 1.8V */
 #define MMC_CAP_1_2V_DDR	(1 << 12)	/* can support */
 						/* DDR mode at 1.2V */
+#define MMC_CAP_HSDDR		(MMC_CAP_1_8V_DDR | MMC_CAP_1_2V_DDR)
 #define MMC_CAP_POWER_OFF_CARD	(1 << 13)	/* Can power off after boot */
 #define MMC_CAP_BUS_WIDTH_TEST	(1 << 14)	/* CMD14/CMD19 bus width ok */
 #define MMC_CAP_UHS_SDR12	(1 << 15)	/* Host supports UHS SDR12 mode */
@@ -295,6 +297,11 @@
 #define MMC_CAP2_CORE_RUNTIME_PM (1 << 19)
 /* Allows Asynchronous SDIO irq while card is in 4-bit mode */
 #define MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE (1 << 20)
+
+#define MMC_CAP2_HS400_1_8V	(1 << 21)        /* can support */
+#define MMC_CAP2_HS400_1_2V	(1 << 22)        /* can support */
+#define MMC_CAP2_HS400		(MMC_CAP2_HS400_1_8V | \
+				 MMC_CAP2_HS400_1_2V)
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
 	int			clk_requests;	/* internal reference counter */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index de145d6..764beec 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -52,6 +52,7 @@
 #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */
 #define MMC_SEND_TUNING_BLOCK    19   /* adtc                    R1  */
 #define MMC_SEND_TUNING_BLOCK_HS200	21	/* adtc R1  */
+#define MMC_SEND_TUNING_BLOCK_HS400	MMC_SEND_TUNING_BLOCK_HS200
 
   /* class 3 */
 #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
@@ -328,6 +329,8 @@
 #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */
 #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */
 #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */
+#define EXT_CSD_PWR_CL_DDR_200_195	253	/* RO */
+#define EXT_CSD_PWR_CL_DDR_200_360	254	/* RO */
 #define EXT_CSD_TAG_UNIT_SIZE		498	/* RO */
 #define EXT_CSD_DATA_TAG_SUPPORT	499	/* RO */
 #define EXT_CSD_MAX_PACKED_WRITES	500	/* RO */
@@ -359,7 +362,7 @@
 
 #define EXT_CSD_CARD_TYPE_26	(1<<0)	/* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_52	(1<<1)	/* Card can run at 52MHz */
-#define EXT_CSD_CARD_TYPE_MASK	0x3F	/* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_MASK	0xFF	/* Mask out reserved bits */
 #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
 					     /* DDR mode @1.8V or 3V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
@@ -369,6 +372,14 @@
 #define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
 #define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
 						/* SDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_HS200		(EXT_CSD_CARD_TYPE_SDR_1_8V  \
+					| EXT_CSD_CARD_TYPE_SDR_1_2V)
+#define EXT_CSD_CARD_TYPE_HS400_1_8V	(1<<6)	/* Card can run at 200MHz */
+							/* DDR mode @1.8V I/O */
+#define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<7)	/* Card can run at 200MHz */
+							/* DDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V  \
+					| EXT_CSD_CARD_TYPE_HS400_1_2V)
 
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 424b1d9..186fff1 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -190,6 +190,7 @@
 #define SDHCI_PV_ENABLED	(1<<8)	/* Preset value enabled */
 #define SDHCI_SDIO_IRQ_ENABLED	(1<<9)	/* SDIO irq enabled */
 #define SDHCI_HS200_NEEDS_TUNING (1<<10)	/* HS200 needs tuning */
+#define SDHCI_HS400_NEEDS_TUNING (1<<11)	/* HS400 needs tuning */
 
 	unsigned int version;	/* SDHCI spec. version */
 
diff --git a/include/linux/msm_dsps.h b/include/linux/msm_dsps.h
index 1f997ba..e3da576 100644
--- a/include/linux/msm_dsps.h
+++ b/include/linux/msm_dsps.h
@@ -1,17 +1,3 @@
-/*
- * Copyright (c) 2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
 #ifndef _DSPS_H_
 #define _DSPS_H_
 
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index f74fcbe..87047d2 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -20,10 +20,7 @@
 #define KGSL_CONTEXT_TRASH_STATE	0x00000020
 #define KGSL_CONTEXT_PER_CONTEXT_TS	0x00000040
 #define KGSL_CONTEXT_USER_GENERATED_TS	0x00000080
-#define KGSL_CONTEXT_END_OF_FRAME	0x00000100
-
 #define KGSL_CONTEXT_NO_FAULT_TOLERANCE 0x00000200
-#define KGSL_CONTEXT_SYNC               0x00000400
 /* bits [12:15] are reserved for future use */
 #define KGSL_CONTEXT_TYPE_MASK          0x01F00000
 #define KGSL_CONTEXT_TYPE_SHIFT         20
@@ -286,7 +283,7 @@
 #define IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID \
 	_IOW(KGSL_IOC_TYPE, 0x7, struct kgsl_device_waittimestamp_ctxtid)
 
-/* DEPRECATED: issue indirect commands to the GPU.
+/* issue indirect commands to the GPU.
  * drawctxt_id must have been created with IOCTL_KGSL_DRAWCTXT_CREATE
  * ibaddr and sizedwords must specify a subset of a buffer created
  * with IOCTL_KGSL_SHAREDMEM_FROM_PMEM
@@ -294,9 +291,6 @@
  * timestamp is a returned counter value which can be passed to
  * other ioctls to determine when the commands have been executed by
  * the GPU.
- *
- * This fucntion is deprecated - consider using IOCTL_KGSL_SUBMIT_COMMANDS
- * instead
  */
 struct kgsl_ringbuffer_issueibcmds {
 	unsigned int drawctxt_id;
@@ -811,77 +805,6 @@
 #define IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK \
 	_IOWR(KGSL_IOC_TYPE, 0x3C, struct kgsl_gpumem_sync_cache_bulk)
 
-/*
- * struct kgsl_cmd_syncpoint_timestamp
- * @context_id: ID of a KGSL context
- * @timestamp: GPU timestamp
- *
- * This structure defines a syncpoint comprising a context/timestamp pair. A
- * list of these may be passed by IOCTL_KGSL_SUBMIT_COMMANDS to define
- * dependencies that must be met before the command can be submitted to the
- * hardware
- */
-struct kgsl_cmd_syncpoint_timestamp {
-	unsigned int context_id;
-	unsigned int timestamp;
-};
-
-#define KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP 0
-
-struct kgsl_cmd_syncpoint_fence {
-	int fd;
-};
-
-#define KGSL_CMD_SYNCPOINT_TYPE_FENCE 1
-
-/**
- * struct kgsl_cmd_syncpoint - Define a sync point for a command batch
- * @type: type of sync point defined here
- * @priv: Pointer to the type specific buffer
- * @size: Size of the type specific buffer
- *
- * This structure contains pointers defining a specific command sync point.
- * The pointer and size should point to a type appropriate structure.
- */
-struct kgsl_cmd_syncpoint {
-	int type;
-	void __user *priv;
-	unsigned int size;
-};
-
-/**
- * struct kgsl_submit_commands - Argument to IOCTL_KGSL_SUBMIT_COMMANDS
- * @context_id: KGSL context ID that owns the commands
- * @flags:
- * @cmdlist: User pointer to a list of kgsl_ibdesc structures
- * @numcmds: Number of commands listed in cmdlist
- * @synclist: User pointer to a list of kgsl_cmd_syncpoint structures
- * @numsyncs: Number of sync points listed in synclist
- * @timestamp: On entry the a user defined timestamp, on exist the timestamp
- * assigned to the command batch
- *
- * This structure specifies a command to send to the GPU hardware.  This is
- * similar to kgsl_issueibcmds expect that it doesn't support the legacy way to
- * submit IB lists and it adds sync points to block the IB until the
- * dependencies are satisified.  This entry point is the new and preferred way
- * to submit commands to the GPU.
- */
-
-struct kgsl_submit_commands {
-	unsigned int context_id;
-	unsigned int flags;
-	struct kgsl_ibdesc __user *cmdlist;
-	unsigned int numcmds;
-	struct kgsl_cmd_syncpoint __user *synclist;
-	unsigned int numsyncs;
-	unsigned int timestamp;
-/* private: reserved for future use */
-	unsigned int __pad[4];
-};
-
-#define IOCTL_KGSL_SUBMIT_COMMANDS \
-	_IOWR(KGSL_IOC_TYPE, 0x3D, struct kgsl_submit_commands)
-
 #ifdef __KERNEL__
 #ifdef CONFIG_MSM_KGSL_DRM
 int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 2455212..73b8014 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -126,6 +126,14 @@
 	MDP_BGR_888,      /* BGR 888 */
 	MDP_Y_CBCR_H2V2_VENUS,
 	MDP_BGRX_8888,   /* BGRX 8888 */
+	MDP_RGBA_8888_TILE,	/* RGBA 8888 in tile format */
+	MDP_ARGB_8888_TILE,	/* ARGB 8888 in tile format */
+	MDP_ABGR_8888_TILE,	/* ABGR 8888 in tile format */
+	MDP_BGRA_8888_TILE,	/* BGRA 8888 in tile format */
+	MDP_RGBX_8888_TILE,	/* RGBX 8888 in tile format */
+	MDP_XRGB_8888_TILE,	/* XRGB 8888 in tile format */
+	MDP_XBGR_8888_TILE,	/* XBGR 8888 in tile format */
+	MDP_BGRX_8888_TILE,	/* BGRX 8888 in tile format */
 	MDP_IMGTYPE_LIMIT,
 	MDP_RGB_BORDERFILL,	/* border fill pipe */
 	MDP_FB_FORMAT = MDP_IMGTYPE2_START,    /* framebuffer format */
@@ -405,6 +413,33 @@
 	struct mdp_hist_lut_data hist_lut_cfg;
 };
 
+/**
+ * enum mdss_mdp_blend_op - Different blend operations set by userspace
+ *
+ * @BLEND_OP_NOT_DEFINED:    No blend operation defined for the layer.
+ * @BLEND_OP_OPAQUE:         Apply a constant blend operation. The layer
+ *                           would appear opaque in case fg plane alpha is
+ *                           0xff.
+ * @BLEND_OP_PREMULTIPLIED:  Apply source over blend rule. Layer already has
+ *                           alpha pre-multiplication done. If fg plane alpha
+ *                           is less than 0xff, apply modulation as well. This
+ *                           operation is intended on layers having alpha
+ *                           channel.
+ * @BLEND_OP_COVERAGE:       Apply source over blend rule. Layer is not alpha
+ *                           pre-multiplied. Apply pre-multiplication. If fg
+ *                           plane alpha is less than 0xff, apply modulation as
+ *                           well.
+ * @BLEND_OP_MAX:            Used to track maximum blend operation possible by
+ *                           mdp.
+ */
+enum mdss_mdp_blend_op {
+	BLEND_OP_NOT_DEFINED = 0,
+	BLEND_OP_OPAQUE,
+	BLEND_OP_PREMULTIPLIED,
+	BLEND_OP_COVERAGE,
+	BLEND_OP_MAX,
+};
+
 struct mdp_overlay {
 	struct msmfb_img src;
 	struct mdp_rect src_rect;
@@ -412,6 +447,7 @@
 	uint32_t z_order;	/* stage number */
 	uint32_t is_fg;		/* control alpha & transp */
 	uint32_t alpha;
+	uint32_t blend_op;
 	uint32_t transp_mask;
 	uint32_t flags;
 	uint32_t id;
diff --git a/include/linux/msm_thermal.h b/include/linux/msm_thermal.h
index 2c1fa11..2ca9900 100644
--- a/include/linux/msm_thermal.h
+++ b/include/linux/msm_thermal.h
@@ -23,6 +23,8 @@
 	uint32_t freq_control_mask;
 	int32_t core_limit_temp_degC;
 	int32_t core_temp_hysteresis_degC;
+	int32_t hotplug_temp_degC;
+	int32_t hotplug_temp_hysteresis_degC;
 	uint32_t core_control_mask;
 	int32_t vdd_rstr_temp_degC;
 	int32_t vdd_rstr_temp_hyst_degC;
diff --git a/include/linux/qpnp-revid.h b/include/linux/qpnp-revid.h
new file mode 100644
index 0000000..3cf9f1c
--- /dev/null
+++ b/include/linux/qpnp-revid.h
@@ -0,0 +1,111 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QPNP_REVID
+#define __QPNP_REVID
+
+#define PM8226_V2P1_REV1	0x00
+#define PM8226_V2P1_REV2	0x00
+#define PM8226_V2P1_REV3	0x01
+#define PM8226_V2P1_REV4	0x02
+#define PM8226_V2P1_TYPE	0x51
+#define PM8226_V2P1_SUBTYPE	0x04
+
+#define PM8226_V2P0_REV1	0x00
+#define PM8226_V2P0_REV2	0x00
+#define PM8226_V2P0_REV3	0x00
+#define PM8226_V2P0_REV4	0x02
+#define PM8226_V2P0_TYPE	0x51
+#define PM8226_V2P0_SUBTYPE	0x04
+
+#define PM8226_V1P0_REV1	0x00
+#define PM8226_V1P0_REV2	0x00
+#define PM8226_V1P0_REV3	0x00
+#define PM8226_V1P0_REV4	0x00
+#define PM8226_V1P0_TYPE	0x51
+#define PM8226_V1P0_SUBTYPE	0x04
+
+#define PM8941_V1P0_REV1	0x00
+#define PM8941_V1P0_REV2	0x00
+#define PM8941_V1P0_REV3	0x00
+#define PM8941_V1P0_REV4	0x01
+#define PM8941_V1P0_TYPE	0x51
+#define PM8941_V1P0_SUBTYPE	0x01
+
+#define PM8941_V2P0_REV1	0x00
+#define PM8941_V2P0_REV2	0x00
+#define PM8941_V2P0_REV3	0x00
+#define PM8941_V2P0_REV4	0x01
+#define PM8941_V2P0_TYPE	0x51
+#define PM8941_V2P0_SUBTYPE	0x01
+
+#define PM8941_V3P0_REV1	0x00
+#define PM8941_V3P0_REV2	0x00
+#define PM8941_V3P0_REV3	0x00
+#define PM8941_V3P0_REV4	0x03
+#define PM8941_V3P0_TYPE	0x51
+#define PM8941_V3P0_SUBTYPE	0x01
+
+#define PM8941_V3P1_REV1	0x00
+#define PM8941_V3P1_REV2	0x00
+#define PM8941_V3P1_REV3	0x01
+#define PM8941_V3P1_REV4	0x03
+#define PM8941_V3P1_TYPE	0x51
+#define PM8941_V3P1_SUBTYPE	0x01
+
+#define PM8110_V1P0_REV1	0x00
+#define PM8110_V1P0_REV2	0x00
+#define PM8110_V1P0_REV3	0x00
+#define PM8110_V1P0_REV4	0x01
+#define PM8110_V1P0_TYPE	0x51
+#define PM8110_V1P0_SUBTYPE	0x05
+
+#define PM8110_V1P1_REV1	0x00
+#define PM8110_V1P1_REV2	0x01
+#define PM8110_V1P1_REV3	0x00
+#define PM8110_V1P1_REV4	0x01
+#define PM8110_V1P1_TYPE	0x51
+#define PM8110_V1P1_SUBTYPE	0x05
+
+#define PM8110_V1P3_REV1	0x00
+#define PM8110_V1P3_REV2	0x03
+#define PM8110_V1P3_REV3	0x00
+#define PM8110_V1P3_REV4	0x01
+#define PM8110_V1P3_TYPE	0x51
+#define PM8110_V1P3_SUBTYPE	0x05
+
+#define PM8110_V2P0_REV1	0x00
+#define PM8110_V2P0_REV2	0x00
+#define PM8110_V2P0_REV3	0x00
+#define PM8110_V2P0_REV4	0x02
+#define PM8110_V2P0_TYPE	0x51
+#define PM8110_V2P0_SUBTYPE	0x05
+
+struct pmic_revid_data {
+	u8	rev1;
+	u8	rev2;
+	u8	rev3;
+	u8	rev4;
+	u8	pmic_type;
+	u8	pmic_subtype;
+};
+
+#ifdef CONFIG_QPNP_REVID
+struct pmic_revid_data *get_revid_data(struct device_node *dev_node);
+#else
+static inline
+struct pmic_revid_data *get_revid_data(struct device_node *dev_node)
+{
+	return NULL;
+}
+#endif
+#endif
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 4f39eaa..13bef66 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -218,6 +218,8 @@
  *				 Uses a mapping table with 150K pullup.
  * %SCALE_QRD_BATT_THERM: Conversion to temperature(decidegC) based on
  *			btm parameters.
+ * %SCALE_QRD_SKUAA_BATT_THERM: Conversion to temperature(decidegC) based on
+ *          btm parametersi for SKUAA.
  * %SCALE_NONE: Do not use this scaling type.
  */
 enum qpnp_adc_scale_fn_type {
@@ -228,6 +230,7 @@
 	SCALE_XOTHERM,
 	SCALE_THERM_150K_PULLUP,
 	SCALE_QRD_BATT_THERM,
+	SCALE_QRD_SKUAA_BATT_THERM,
 	SCALE_NONE,
 };
 
@@ -619,27 +622,6 @@
 	COMP_ID_NUM,
 };
 
-enum qpnp_iadc_rev {
-	QPNP_IADC_VER_3_0 = 0x1,
-	QPNP_IADC_VER_3_1 = 0x3,
-};
-
-#define QPNP_VBAT_SNS_COEFF_1_TYPEA				3000
-#define QPNP_VBAT_SNS_COEFF_2_TYPEA				45810000
-#define QPNP_VBAT_SNS_COEFF_3					100000
-#define QPNP_VBAT_SNS_COEFF_1_TYPEB				3500
-#define QPNP_VBAT_SNS_COEFF_2_TYPEB				80000000
-
-#define QPNP_COEFF_1					969000
-#define QPNP_COEFF_2					34
-#define QPNP_COEFF_3_TYPEA				1700000
-#define QPNP_COEFF_3_TYPEB				1000000
-#define QPNP_COEFF_4					100
-#define QPNP_COEFF_5					15000
-#define QPNP_COEFF_6					100000
-#define QPNP_COEFF_7					21700
-#define QPNP_COEFF_8					100000000
-
 /**
  * struct qpnp_adc_tm_config - Represent ADC Thermal Monitor configuration.
  * @channel: ADC channel for which thermal monitoring is requested.
@@ -1121,6 +1103,23 @@
 			const struct qpnp_vadc_chan_properties *chan_prop,
 			struct qpnp_vadc_result *chan_rslt);
 /**
+ * qpnp_adc_scale_qrd_skuaa_batt_therm() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset. Returns the temperature in decidegC.
+ * @dev:	Structure device for qpnp vadc
+ * @adc_code:	pre-calibrated digital ouput of the ADC.
+ * @adc_prop:	adc properties of the pm8xxx 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_qrd_skuaa_batt_therm(struct qpnp_vadc_chip *dev,
+			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);
+/**
  * qpnp_adc_scale_batt_id() - Scales the pre-calibrated digital output
  *		of an ADC to the ADC reference and compensates for the
  *		gain and offset.
@@ -1366,7 +1365,13 @@
 			struct qpnp_vadc_chip *vadc, 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);
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_qrd_skuaa_batt_therm(
+			struct qpnp_vadc_chip *vadc, 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)
 { return -ENXIO; }
 static inline int32_t qpnp_adc_scale_batt_id(struct qpnp_vadc_chip *vadc,
 			int32_t adc_code,
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index 132135e..cba4394 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -581,6 +581,11 @@
  * @shutdown: Standard shutdown callback used during powerdown/halt.
  * @suspend: Standard suspend callback used during system suspend
  * @resume: Standard resume callback used during system resume
+ * @device_up: This callback is called when the device reports present and
+ *		gets a logical address assigned to it
+ * @device_down: This callback is called when device reports absent, or the
+ *		bus goes down. Device will report present when bus is up and
+ *		device_up callback will be called again when that happens
  * @driver: Slimbus device drivers should initialize name and owner field of
  *	this structure
  * @id_table: List of slimbus devices supported by this driver
@@ -593,6 +598,8 @@
 					pm_message_t pmesg);
 	int				(*resume)(struct slim_device *sldev);
 	int				(*device_up)(struct slim_device *sldev);
+	int				(*device_down)
+						(struct slim_device *sldev);
 
 	struct device_driver		driver;
 	const struct slim_device_id	*id_table;
@@ -1022,6 +1029,13 @@
 				u8 e_len, u8 *laddr, bool valid);
 
 /*
+ * slim_report_absent: Controller calls this function when a device
+ *	reports absent, OR when the device cannot be communicated with
+ * @sbdev: Device that cannot be reached, or that sent report absent
+ */
+void slim_report_absent(struct slim_device *sbdev);
+
+/*
  * slim_msg_response: Deliver Message response received from a device to the
  *	framework.
  * @ctrl: Controller handle
diff --git a/include/linux/smsc3503.h b/include/linux/smsc_hub.h
similarity index 90%
rename from include/linux/smsc3503.h
rename to include/linux/smsc_hub.h
index 1e28a58..9c0afc0 100644
--- a/include/linux/smsc3503.h
+++ b/include/linux/smsc_hub.h
@@ -14,6 +14,12 @@
 #ifndef __LINUX_SMSC3503_H__
 #define __LINUX_SMSC3503_H__
 
+#define SMSC3503_ID	3503
+#define SMSC4604_ID	4604
+#define SMSC3503_I2C_ADDR	0x08
+#define SMSC4604_I2C_ADDR	0x2d
+#define SMSC_GSBI_I2C_BUS_ID	0
+
 /*Serial interface Registers*/
 #define SMSC3503_VENDORID	0x00 /*u16 read*/
 #define SMSC3503_PRODUCTID	0x02 /*u16 read*/
@@ -42,6 +48,7 @@
 #define OCSPINSEL	(1<<5)
 
 struct smsc_hub_platform_data {
+	u32 model_id;
 	int hub_reset;
 	int refclk_gpio;
 	int int_gpio;
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index f740640..1bb3b06 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -97,6 +97,27 @@
 				((long)t-2732+5)/10 : ((long)t-2732-5)/10)
 #define CELSIUS_TO_KELVIN(t)	((t)*10+2732)
 
+struct sensor_threshold {
+	int temp;
+	enum thermal_trip_type trip;
+	int (*notify)(enum thermal_trip_type type, int temp, void *data);
+	void *data;
+	struct list_head list;
+};
+
+struct sensor_info {
+	uint32_t sensor_id;
+	struct thermal_zone_device *tz;
+	int threshold_min;
+	int threshold_max;
+	int max_idx;
+	int min_idx;
+	struct list_head sensor_list;
+	struct list_head threshold_list;
+	struct mutex lock;
+	struct work_struct work;
+};
+
 struct thermal_zone_device {
 	int id;
 	char type[THERMAL_NAME_LENGTH];
@@ -116,6 +137,8 @@
 	struct mutex lock;	/* protect cooling devices list */
 	struct list_head node;
 	struct delayed_work poll_queue;
+	struct sensor_threshold tz_threshold[2];
+	struct sensor_info sensor;
 };
 /* Adding event notification support elements */
 #define THERMAL_GENL_FAMILY_NAME                "thermal_event"
@@ -163,6 +186,12 @@
 		const struct thermal_cooling_device_ops *);
 void thermal_cooling_device_unregister(struct thermal_cooling_device *);
 
+int sensor_get_id(char *name);
+int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold);
+int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold);
+int thermal_sensor_trip(struct thermal_zone_device *tz,
+		enum thermal_trip_type trip, unsigned long temp);
+
 #ifdef CONFIG_NET
 extern int thermal_generate_netlink_event(u32 orig, enum events event);
 #else
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 101325e..38877cc 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1551,6 +1551,7 @@
 	V4L2_MPEG_VIDEO_H264_LEVEL_4_2	= 13,
 	V4L2_MPEG_VIDEO_H264_LEVEL_5_0	= 14,
 	V4L2_MPEG_VIDEO_H264_LEVEL_5_1	= 15,
+	V4L2_MPEG_VIDEO_H264_LEVEL_5_2	= 16,
 };
 #define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA	(V4L2_CID_MPEG_BASE+360)
 #define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA	(V4L2_CID_MPEG_BASE+361)
@@ -1874,6 +1875,16 @@
 	V4L2_MPEG_VIDC_FRAME_ASSEMBLY_ENABLE	= 1,
 };
 
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE+32)
+enum v4l2_mpeg_vidc_video_vp8_profile_level {
+	V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED,
+	V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0,
+	V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1,
+	V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2,
+	V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3,
+};
+
 /*  Camera class control IDs */
 #define V4L2_CID_CAMERA_CLASS_BASE 	(V4L2_CTRL_CLASS_CAMERA | 0x900)
 #define V4L2_CID_CAMERA_CLASS 		(V4L2_CTRL_CLASS_CAMERA | 1)
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index 2805401..540fd2c 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -52,6 +52,7 @@
 	MSM_CAMERA_I2C_BYTE_ADDR = 1,
 	MSM_CAMERA_I2C_WORD_ADDR,
 	MSM_CAMERA_I2C_3B_ADDR,
+	MSM_CAMERA_I2C_ADDR_TYPE_MAX,
 };
 
 enum msm_camera_i2c_data_type {
@@ -62,6 +63,7 @@
 	MSM_CAMERA_I2C_SET_WORD_MASK,
 	MSM_CAMERA_I2C_UNSET_WORD_MASK,
 	MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA,
+	MSM_CAMERA_I2C_DATA_TYPE_MAX,
 };
 
 enum msm_sensor_power_seq_type_t {
@@ -122,6 +124,62 @@
 	SUB_MODULE_MAX,
 };
 
+enum {
+	MSM_CAMERA_EFFECT_MODE_OFF,
+	MSM_CAMERA_EFFECT_MODE_MONO,
+	MSM_CAMERA_EFFECT_MODE_NEGATIVE,
+	MSM_CAMERA_EFFECT_MODE_SOLARIZE,
+	MSM_CAMERA_EFFECT_MODE_SEPIA,
+	MSM_CAMERA_EFFECT_MODE_POSTERIZE,
+	MSM_CAMERA_EFFECT_MODE_WHITEBOARD,
+	MSM_CAMERA_EFFECT_MODE_BLACKBOARD,
+	MSM_CAMERA_EFFECT_MODE_AQUA,
+	MSM_CAMERA_EFFECT_MODE_EMBOSS,
+	MSM_CAMERA_EFFECT_MODE_SKETCH,
+	MSM_CAMERA_EFFECT_MODE_NEON,
+	MSM_CAMERA_EFFECT_MODE_MAX
+};
+
+enum {
+	MSM_CAMERA_WB_MODE_AUTO,
+	MSM_CAMERA_WB_MODE_CUSTOM,
+	MSM_CAMERA_WB_MODE_INCANDESCENT,
+	MSM_CAMERA_WB_MODE_FLUORESCENT,
+	MSM_CAMERA_WB_MODE_WARM_FLUORESCENT,
+	MSM_CAMERA_WB_MODE_DAYLIGHT,
+	MSM_CAMERA_WB_MODE_CLOUDY_DAYLIGHT,
+	MSM_CAMERA_WB_MODE_TWILIGHT,
+	MSM_CAMERA_WB_MODE_SHADE,
+	MSM_CAMERA_WB_MODE_OFF,
+	MSM_CAMERA_WB_MODE_MAX
+};
+
+enum {
+	MSM_CAMERA_SCENE_MODE_OFF,
+	MSM_CAMERA_SCENE_MODE_AUTO,
+	MSM_CAMERA_SCENE_MODE_LANDSCAPE,
+	MSM_CAMERA_SCENE_MODE_SNOW,
+	MSM_CAMERA_SCENE_MODE_BEACH,
+	MSM_CAMERA_SCENE_MODE_SUNSET,
+	MSM_CAMERA_SCENE_MODE_NIGHT,
+	MSM_CAMERA_SCENE_MODE_PORTRAIT,
+	MSM_CAMERA_SCENE_MODE_BACKLIGHT,
+	MSM_CAMERA_SCENE_MODE_SPORTS,
+	MSM_CAMERA_SCENE_MODE_ANTISHAKE,
+	MSM_CAMERA_SCENE_MODE_FLOWERS,
+	MSM_CAMERA_SCENE_MODE_CANDLELIGHT,
+	MSM_CAMERA_SCENE_MODE_FIREWORKS,
+	MSM_CAMERA_SCENE_MODE_PARTY,
+	MSM_CAMERA_SCENE_MODE_NIGHT_PORTRAIT,
+	MSM_CAMERA_SCENE_MODE_THEATRE,
+	MSM_CAMERA_SCENE_MODE_ACTION,
+	MSM_CAMERA_SCENE_MODE_AR,
+	MSM_CAMERA_SCENE_MODE_FACE_PRIORITY,
+	MSM_CAMERA_SCENE_MODE_BARCODE,
+	MSM_CAMERA_SCENE_MODE_HDR,
+	MSM_CAMERA_SCENE_MODE_MAX
+};
+
 enum csid_cfg_type_t {
 	CSID_INIT,
 	CSID_CFG,
@@ -361,6 +419,12 @@
 	CFG_SET_SATURATION,
 	CFG_SET_CONTRAST,
 	CFG_SET_SHARPNESS,
+	CFG_SET_ISO,
+	CFG_SET_EXPOSURE_COMPENSATION,
+	CFG_SET_ANTIBANDING,
+	CFG_SET_BESTSHOT_MODE,
+	CFG_SET_EFFECT,
+	CFG_SET_WHITE_BALANCE,
 	CFG_SET_AUTOFOCUS,
 	CFG_CANCEL_AUTOFOCUS,
 };
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index ec8ec9a..23b19b5 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -225,6 +225,7 @@
 	VFE_READ_DMI_16BIT,
 	VFE_READ_DMI_32BIT,
 	VFE_READ_DMI_64BIT,
+	GET_SOC_HW_VER,
 };
 
 struct msm_vfe_cfg_cmd2 {
@@ -348,17 +349,10 @@
 	struct timeval timestamp;
 	/* Monotonic timestamp since bootup */
 	struct timeval mono_timestamp;
-	/* if pix is a src frame_id is from camif */
+	enum msm_vfe_input_src input_intf;
 	uint32_t frame_id;
 	union {
-		/* START_ACK, STOP_ACK */
-		struct msm_isp_stream_ack stream_ack;
-		/* REG_UPDATE_TRIGGER, bus over flow */
-		enum msm_vfe_input_src input_src;
-		/* stats notify */
 		struct msm_isp_stats_event stats;
-		/* IRQ_VIOLATION, STATS_OVER_FLOW, WM_OVER_FLOW */
-		uint32_t irq_status_mask;
 		struct msm_isp_buf_event buf_done;
 	} u; /* union can have max 52 bytes */
 };
diff --git a/include/media/msmb_ispif.h b/include/media/msmb_ispif.h
index 61dfd52..6417237 100644
--- a/include/media/msmb_ispif.h
+++ b/include/media/msmb_ispif.h
@@ -23,6 +23,7 @@
 	INTF_MAX
 };
 #define MAX_PARAM_ENTRIES (INTF_MAX * 2)
+#define MAX_CID_CH	8
 
 #define PIX0_MASK (1 << PIX0)
 #define PIX1_MASK (1 << PIX1)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index fb2b57a..4ecadd8 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3486,6 +3486,14 @@
 		       struct cfg80211_ft_event_params *ft_event);
 
 
+
+/**
+ * cfg80211_ap_stopped - notify userspace that AP mode stopped
+ * @netdev: network device
+ * @gfp: context flags
+ */
+void cfg80211_ap_stopped(struct net_device *netdev, gfp_t gfp);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 88fcf61..fb58d12 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -82,14 +82,15 @@
 */
 #define ADM_CMD_DEVICE_OPEN_V5                          0x00010326
 
-#define ADM_BIT_SHIFT_DEVICE_PERF_MODE_FLAG                           13
+/* Definition for a low latency stream session. */
+#define ADM_LOW_LATENCY_DEVICE_SESSION			0x2000
+
+/* Definition for a ultra low latency stream session. */
+#define ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION		0x4000
 
 /* Definition for a legacy device session. */
 #define ADM_LEGACY_DEVICE_SESSION                                      0
 
-/* Definition for a low latency stream session. */
-#define ADM_LOW_LATENCY_DEVICE_SESSION                                 1
-
 /* Indicates that endpoint_id_2 is to be ignored.*/
 #define ADM_CMD_COPP_OPEN_END_POINT_ID_2_IGNORE				0xFFFF
 
@@ -3816,11 +3817,12 @@
 #define ASM_STREAM_CMD_OPEN_WRITE_V2       0x00010D8F
 #define ASM_STREAM_CMD_OPEN_WRITE_V3       0x00010DB3
 
-#define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_WRITE                     28
+#define ASM_LOW_LATENCY_STREAM_SESSION				0x10000000
+
+#define ASM_ULTRA_LOW_LATENCY_STREAM_SESSION			0x20000000
 
 #define ASM_LEGACY_STREAM_SESSION                                      0
 
-#define ASM_LOW_LATENCY_STREAM_SESSION                                  1
 
 struct asm_stream_cmd_open_write_v3 {
 	struct apr_hdr			hdr;
diff --git a/include/sound/core.h b/include/sound/core.h
index bc05668..5b9969e 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -134,6 +134,9 @@
 	wait_queue_head_t shutdown_sleep;
 	struct device *dev;		/* device assigned to this card */
 	struct device *card_dev;	/* cardX object for sysfs */
+	int offline;			/* if this sound card is offline */
+	unsigned long offline_change;
+	wait_queue_head_t offline_poll_wait;
 
 #ifdef CONFIG_PM
 	unsigned int power_state;	/* power state */
@@ -295,6 +298,8 @@
 int snd_component_add(struct snd_card *card, const char *component);
 int snd_card_file_add(struct snd_card *card, struct file *file);
 int snd_card_file_remove(struct snd_card *card, struct file *file);
+void snd_card_change_online_state(struct snd_card *card, int online);
+bool snd_card_is_online_state(struct snd_card *card);
 
 #define snd_card_set_dev(card, devptr) ((card)->dev = (devptr))
 
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 7886e84..b1e536d 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -426,6 +426,9 @@
 	struct snd_ac97_bus_ops *ops, int num);
 void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
 
+void snd_soc_card_change_online_state(struct snd_soc_card *soc_card,
+				      int online);
+
 /*
  *Controls
  */
@@ -967,7 +970,6 @@
 	enum snd_soc_pcm_subclass pcm_subclass;
 	struct snd_pcm_ops ops;
 
-	unsigned int complete:1;
 	unsigned int dev_registered:1;
 
 	/* Dynamic PCM BE runtime data */
diff --git a/init/main.c b/init/main.c
index 737ab05..b2fc496 100644
--- a/init/main.c
+++ b/init/main.c
@@ -477,11 +477,6 @@
 	smp_setup_processor_id();
 	debug_objects_early_init();
 
-	/*
-	 * Set up the the initial canary ASAP:
-	 */
-	boot_init_stack_canary();
-
 	cgroup_init_early();
 
 	local_irq_disable();
@@ -496,6 +491,10 @@
 	page_address_init();
 	printk(KERN_NOTICE "%s", linux_banner);
 	setup_arch(&command_line);
+	/*
+	 * Set up the the initial canary ASAP:
+	 */
+	boot_init_stack_canary();
 	mm_init_owner(&init_mm, &init_task);
 	mm_init_cpumask(&init_mm);
 	setup_command_line(command_line);
diff --git a/kernel/power/qos.c b/kernel/power/qos.c
index 6a031e6..bb2dad8 100644
--- a/kernel/power/qos.c
+++ b/kernel/power/qos.c
@@ -237,11 +237,18 @@
  */
 static void pm_qos_work_fn(struct work_struct *work)
 {
+	s32 new_value = PM_QOS_DEFAULT_VALUE;
 	struct pm_qos_request *req = container_of(to_delayed_work(work),
 						  struct pm_qos_request,
 						  work);
 
-	pm_qos_update_request(req, PM_QOS_DEFAULT_VALUE);
+	if (!req || !pm_qos_request_active(req))
+		return;
+
+	if (new_value != req->node.prio)
+		pm_qos_update_target(
+			pm_qos_array[req->pm_qos_class]->constraints,
+			&req->node, PM_QOS_UPDATE_REQ, new_value);
 }
 
 /**
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index d9c4b64..627dab1 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -1670,8 +1670,10 @@
 {
 	struct rq *rq = task_rq(p);
 
-	BUG_ON(rq != this_rq());
-	BUG_ON(p == current);
+	if (WARN_ON(rq != this_rq()) ||
+	    WARN_ON(p == current))
+		return;
+
 	lockdep_assert_held(&rq->lock);
 
 	if (!raw_spin_trylock(&p->pi_lock)) {
@@ -5202,9 +5204,6 @@
 	 */
 	rq->stop = NULL;
 
-	/* Ensure any throttled groups are reachable by pick_next_task */
-	unthrottle_offline_cfs_rqs(rq);
-
 	for ( ; ; ) {
 		/*
 		 * There's this thread running, bail when that's the only
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 5d6ab86..2e98983 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -2060,7 +2060,7 @@
 	hrtimer_cancel(&cfs_b->slack_timer);
 }
 
-void unthrottle_offline_cfs_rqs(struct rq *rq)
+static void unthrottle_offline_cfs_rqs(struct rq *rq)
 {
 	struct cfs_rq *cfs_rq;
 
@@ -2114,7 +2114,7 @@
 	return NULL;
 }
 static inline void destroy_cfs_bandwidth(struct cfs_bandwidth *cfs_b) {}
-void unthrottle_offline_cfs_rqs(struct rq *rq) {}
+static inline void unthrottle_offline_cfs_rqs(struct rq *rq) {}
 
 #endif /* CONFIG_CFS_BANDWIDTH */
 
@@ -5186,6 +5186,9 @@
 static void rq_offline_fair(struct rq *rq)
 {
 	update_sysctl();
+
+	/* Ensure any throttled groups are reachable by pick_next_task */
+	unthrottle_offline_cfs_rqs(rq);
 }
 
 #endif /* CONFIG_SMP */
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 8f32475..be427c5 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -685,6 +685,7 @@
 		 * runtime - in which case borrowing doesn't make sense.
 		 */
 		rt_rq->rt_runtime = RUNTIME_INF;
+		rt_rq->rt_throttled = 0;
 		raw_spin_unlock(&rt_rq->rt_runtime_lock);
 		raw_spin_unlock(&rt_b->rt_runtime_lock);
 	}
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 5370bcb..55f6d9c 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1155,7 +1155,6 @@
 
 extern void init_cfs_rq(struct cfs_rq *cfs_rq);
 extern void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq);
-extern void unthrottle_offline_cfs_rqs(struct rq *rq);
 
 extern void account_cfs_bandwidth_used(int enabled, int was_enabled);
 
diff --git a/lib/spinlock_debug.c b/lib/spinlock_debug.c
index ac516f4..6d22836 100644
--- a/lib/spinlock_debug.c
+++ b/lib/spinlock_debug.c
@@ -108,7 +108,7 @@
 static void __spin_lock_debug(raw_spinlock_t *lock)
 {
 	u64 i;
-	u64 loops = (loops_per_jiffy * HZ) >> 4;
+	u64 loops = (loops_per_jiffy * HZ) >> 1;
 
 	for (i = 0; i < loops; i++) {
 		if (arch_spin_trylock(&lock->raw_lock))
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 90430b7..1604bf2 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -494,8 +494,10 @@
 	}
 	if (ops->fill_info) {
 		data = nla_nest_start(skb, IFLA_INFO_DATA);
-		if (data == NULL)
+		if (data == NULL) {
+			err = -EMSGSIZE;
 			goto err_cancel_link;
+		}
 		err = ops->fill_info(skb, dev);
 		if (err < 0)
 			goto err_cancel_data;
@@ -1059,7 +1061,7 @@
 	rcu_read_lock();
 	cb->seq = net->dev_base_seq;
 
-	if (nlmsg_parse(cb->nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX,
+	if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
 			ifla_policy) >= 0) {
 
 		if (tb[IFLA_EXT_MASK])
@@ -1902,7 +1904,7 @@
 	u32 ext_filter_mask = 0;
 	u16 min_ifinfo_dump_size = 0;
 
-	if (nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX,
+	if (nlmsg_parse(nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
 			ifla_policy) >= 0) {
 		if (tb[IFLA_EXT_MASK])
 			ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
diff --git a/net/core/sock.c b/net/core/sock.c
index b2e14c0..0f8402e 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1600,6 +1600,11 @@
 	gfp_t gfp_mask;
 	long timeo;
 	int err;
+	int npages = (data_len + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+
+	err = -EMSGSIZE;
+	if (npages > MAX_SKB_FRAGS)
+		goto failure;
 
 	gfp_mask = sk->sk_allocation;
 	if (gfp_mask & __GFP_WAIT)
@@ -1618,14 +1623,12 @@
 		if (atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) {
 			skb = alloc_skb(header_len, gfp_mask);
 			if (skb) {
-				int npages;
 				int i;
 
 				/* No pages, we're done... */
 				if (!data_len)
 					break;
 
-				npages = (data_len + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
 				skb->truesize += data_len;
 				skb_shinfo(skb)->nr_frags = npages;
 				for (i = 0; i < npages; i++) {
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
index b9868e1..aa74be4 100644
--- a/net/core/sock_diag.c
+++ b/net/core/sock_diag.c
@@ -126,6 +126,9 @@
 	if (nlmsg_len(nlh) < sizeof(*req))
 		return -EINVAL;
 
+	if (req->sdiag_family >= AF_MAX)
+		return -EINVAL;
+
 	hndl = sock_diag_lock_handler(req->sdiag_family);
 	if (hndl == NULL)
 		err = -ENOENT;
diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c
index 21d66c2..9704f85 100644
--- a/net/netfilter/xt_qtaguid.c
+++ b/net/netfilter/xt_qtaguid.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_qtaguid.h>
+#include <linux/ratelimit.h>
 #include <linux/skbuff.h>
 #include <linux/workqueue.h>
 #include <net/addrconf.h>
@@ -53,25 +54,22 @@
 module_param_named(stats_perms, proc_stats_perms, uint, S_IRUGO | S_IWUSR);
 
 static struct proc_dir_entry *xt_qtaguid_ctrl_file;
-#ifdef CONFIG_ANDROID_PARANOID_NETWORK
+
+/* Everybody can write. But proc_ctrl_write_limited is true by default which
+ * limits what can be controlled. See the can_*() functions.
+ */
 static unsigned int proc_ctrl_perms = S_IRUGO | S_IWUGO;
-#else
-static unsigned int proc_ctrl_perms = S_IRUGO | S_IWUSR;
-#endif
 module_param_named(ctrl_perms, proc_ctrl_perms, uint, S_IRUGO | S_IWUSR);
 
-#ifdef CONFIG_ANDROID_PARANOID_NETWORK
-#include <linux/android_aid.h>
-static gid_t proc_stats_readall_gid = AID_NET_BW_STATS;
-static gid_t proc_ctrl_write_gid = AID_NET_BW_ACCT;
-#else
-/* 0 means, don't limit anybody */
-static gid_t proc_stats_readall_gid;
-static gid_t proc_ctrl_write_gid;
-#endif
-module_param_named(stats_readall_gid, proc_stats_readall_gid, uint,
+/* Limited by default, so the gid of the ctrl and stats proc entries
+ * will limit what can be done. See the can_*() functions.
+ */
+static bool proc_stats_readall_limited = true;
+static bool proc_ctrl_write_limited = true;
+
+module_param_named(stats_readall_limited, proc_stats_readall_limited, bool,
 		   S_IRUGO | S_IWUSR);
-module_param_named(ctrl_write_gid, proc_ctrl_write_gid, uint,
+module_param_named(ctrl_write_limited, proc_ctrl_write_limited, bool,
 		   S_IRUGO | S_IWUSR);
 
 /*
@@ -242,8 +240,9 @@
 static bool can_manipulate_uids(void)
 {
 	/* root pwnd */
-	return unlikely(!current_fsuid()) || unlikely(!proc_ctrl_write_gid)
-		|| in_egroup_p(proc_ctrl_write_gid);
+	return in_egroup_p(xt_qtaguid_ctrl_file->gid)
+		|| unlikely(!current_fsuid()) || unlikely(!proc_ctrl_write_limited)
+		|| unlikely(current_fsuid() == xt_qtaguid_ctrl_file->uid);
 }
 
 static bool can_impersonate_uid(uid_t uid)
@@ -254,9 +253,10 @@
 static bool can_read_other_uid_stats(uid_t uid)
 {
 	/* root pwnd */
-	return unlikely(!current_fsuid()) || uid == current_fsuid()
-		|| unlikely(!proc_stats_readall_gid)
-		|| in_egroup_p(proc_stats_readall_gid);
+	return in_egroup_p(xt_qtaguid_stats_file->gid)
+		|| unlikely(!current_fsuid()) || uid == current_fsuid()
+		|| unlikely(!proc_stats_readall_limited)
+		|| unlikely(current_fsuid() == xt_qtaguid_ctrl_file->uid);
 }
 
 static inline void dc_add_byte_packets(struct data_counters *counters, int set,
@@ -269,24 +269,6 @@
 	counters->bpc[set][direction][ifs_proto].packets += packets;
 }
 
-static inline uint64_t dc_sum_bytes(struct data_counters *counters,
-				    int set,
-				    enum ifs_tx_rx direction)
-{
-	return counters->bpc[set][direction][IFS_TCP].bytes
-		+ counters->bpc[set][direction][IFS_UDP].bytes
-		+ counters->bpc[set][direction][IFS_PROTO_OTHER].bytes;
-}
-
-static inline uint64_t dc_sum_packets(struct data_counters *counters,
-				      int set,
-				      enum ifs_tx_rx direction)
-{
-	return counters->bpc[set][direction][IFS_TCP].packets
-		+ counters->bpc[set][direction][IFS_UDP].packets
-		+ counters->bpc[set][direction][IFS_PROTO_OTHER].packets;
-}
-
 static struct tag_node *tag_node_tree_search(struct rb_root *root, tag_t tag)
 {
 	struct rb_node *node = root->rb_node;
@@ -788,6 +770,53 @@
 	return iface_entry;
 }
 
+/* This is for fmt2 only */
+static int pp_iface_stat_line(bool header, char *outp,
+			      int char_count, struct iface_stat *iface_entry)
+{
+	int len;
+	if (header) {
+		len = snprintf(outp, char_count,
+			       "ifname "
+			       "total_skb_rx_bytes total_skb_rx_packets "
+			       "total_skb_tx_bytes total_skb_tx_packets "
+			       "rx_tcp_bytes rx_tcp_packets "
+			       "rx_udp_bytes rx_udp_packets "
+			       "rx_other_bytes rx_other_packets "
+			       "tx_tcp_bytes tx_tcp_packets "
+			       "tx_udp_bytes tx_udp_packets "
+			       "tx_other_bytes tx_other_packets\n"
+			);
+	} else {
+		struct data_counters *cnts;
+		int cnt_set = 0;   /* We only use one set for the device */
+		cnts = &iface_entry->totals_via_skb;
+		len = snprintf(
+			outp, char_count,
+			"%s "
+			"%llu %llu %llu %llu %llu %llu %llu %llu "
+			"%llu %llu %llu %llu %llu %llu %llu %llu\n",
+			iface_entry->ifname,
+			dc_sum_bytes(cnts, cnt_set, IFS_RX),
+			dc_sum_packets(cnts, cnt_set, IFS_RX),
+			dc_sum_bytes(cnts, cnt_set, IFS_TX),
+			dc_sum_packets(cnts, cnt_set, IFS_TX),
+			cnts->bpc[cnt_set][IFS_RX][IFS_TCP].bytes,
+			cnts->bpc[cnt_set][IFS_RX][IFS_TCP].packets,
+			cnts->bpc[cnt_set][IFS_RX][IFS_UDP].bytes,
+			cnts->bpc[cnt_set][IFS_RX][IFS_UDP].packets,
+			cnts->bpc[cnt_set][IFS_RX][IFS_PROTO_OTHER].bytes,
+			cnts->bpc[cnt_set][IFS_RX][IFS_PROTO_OTHER].packets,
+			cnts->bpc[cnt_set][IFS_TX][IFS_TCP].bytes,
+			cnts->bpc[cnt_set][IFS_TX][IFS_TCP].packets,
+			cnts->bpc[cnt_set][IFS_TX][IFS_UDP].bytes,
+			cnts->bpc[cnt_set][IFS_TX][IFS_UDP].packets,
+			cnts->bpc[cnt_set][IFS_TX][IFS_PROTO_OTHER].bytes,
+			cnts->bpc[cnt_set][IFS_TX][IFS_PROTO_OTHER].packets);
+	}
+	return len;
+}
+
 static int iface_stat_fmt_proc_read(char *page, char **num_items_returned,
 				    off_t items_to_skip, int char_count,
 				    int *eof, void *data)
@@ -817,11 +846,7 @@
 		return 0;
 
 	if (fmt == 2 && item_index++ >= items_to_skip) {
-		len = snprintf(outp, char_count,
-			       "ifname "
-			       "total_skb_rx_bytes total_skb_rx_packets "
-			       "total_skb_tx_bytes total_skb_tx_packets\n"
-			);
+		len = pp_iface_stat_line(true, outp, char_count, NULL);
 		if (len >= char_count) {
 			*outp = '\0';
 			return outp - page;
@@ -866,16 +891,8 @@
 				stats->tx_bytes, stats->tx_packets
 				);
 		} else {
-			len = snprintf(
-				outp, char_count,
-				"%s "
-				"%llu %llu %llu %llu\n",
-				iface_entry->ifname,
-				iface_entry->totals_via_skb[IFS_RX].bytes,
-				iface_entry->totals_via_skb[IFS_RX].packets,
-				iface_entry->totals_via_skb[IFS_TX].bytes,
-				iface_entry->totals_via_skb[IFS_TX].packets
-				);
+			len = pp_iface_stat_line(false, outp, char_count,
+						 iface_entry);
 		}
 		if (len >= char_count) {
 			spin_unlock_bh(&iface_stat_list_lock);
@@ -1092,18 +1109,13 @@
 	spin_lock_bh(&iface_stat_list_lock);
 	entry = get_iface_entry(ifname);
 	if (entry != NULL) {
-		bool activate = !ipv4_is_loopback(ipaddr);
 		IF_DEBUG("qtaguid: iface_stat: create(%s): entry=%p\n",
 			 ifname, entry);
 		iface_check_stats_reset_and_adjust(net_dev, entry);
-		_iface_stat_set_active(entry, net_dev, activate);
+		_iface_stat_set_active(entry, net_dev, true);
 		IF_DEBUG("qtaguid: %s(%s): "
 			 "tracking now %d on ip=%pI4\n", __func__,
-			 entry->ifname, activate, &ipaddr);
-		goto done_unlock_put;
-	} else if (ipv4_is_loopback(ipaddr)) {
-		IF_DEBUG("qtaguid: iface_stat: create(%s): "
-			 "ignore loopback dev. ip=%pI4\n", ifname, &ipaddr);
+			 entry->ifname, true, &ipaddr);
 		goto done_unlock_put;
 	}
 
@@ -1154,19 +1166,13 @@
 	spin_lock_bh(&iface_stat_list_lock);
 	entry = get_iface_entry(ifname);
 	if (entry != NULL) {
-		bool activate = !(addr_type & IPV6_ADDR_LOOPBACK);
 		IF_DEBUG("qtaguid: %s(%s): entry=%p\n", __func__,
 			 ifname, entry);
 		iface_check_stats_reset_and_adjust(net_dev, entry);
-		_iface_stat_set_active(entry, net_dev, activate);
+		_iface_stat_set_active(entry, net_dev, true);
 		IF_DEBUG("qtaguid: %s(%s): "
 			 "tracking now %d on ip=%pI6c\n", __func__,
-			 entry->ifname, activate, &ifa->addr);
-		goto done_unlock_put;
-	} else if (addr_type & IPV6_ADDR_LOOPBACK) {
-		IF_DEBUG("qtaguid: %s(%s): "
-			 "ignore loopback dev. ip=%pI6c\n", __func__,
-			 ifname, &ifa->addr);
+			 entry->ifname, true, &ifa->addr);
 		goto done_unlock_put;
 	}
 
@@ -1305,6 +1311,7 @@
 	const struct net_device *el_dev;
 	enum ifs_tx_rx direction = par->in ? IFS_RX : IFS_TX;
 	int bytes = skb->len;
+	int proto;
 
 	if (!skb->dev) {
 		MT_DEBUG("qtaguid[%d]: no skb->dev\n", par->hooknum);
@@ -1322,15 +1329,15 @@
 	}
 
 	if (unlikely(!el_dev)) {
-		pr_err("qtaguid[%d]: %s(): no par->in/out?!!\n",
-		       par->hooknum, __func__);
+		pr_err_ratelimited("qtaguid[%d]: %s(): no par->in/out?!!\n",
+				   par->hooknum, __func__);
 		BUG();
 	} else if (unlikely(!el_dev->name)) {
-		pr_err("qtaguid[%d]: %s(): no dev->name?!!\n",
-		       par->hooknum, __func__);
+		pr_err_ratelimited("qtaguid[%d]: %s(): no dev->name?!!\n",
+				   par->hooknum, __func__);
 		BUG();
 	} else {
-		int proto = ipx_proto(skb, par);
+		proto = ipx_proto(skb, par);
 		MT_DEBUG("qtaguid[%d]: dev name=%s type=%d fam=%d proto=%d\n",
 			 par->hooknum, el_dev->name, el_dev->type,
 			 par->family, proto);
@@ -1348,8 +1355,8 @@
 	IF_DEBUG("qtaguid: %s(%s): entry=%p\n", __func__,
 		 el_dev->name, entry);
 
-	entry->totals_via_skb[direction].bytes += bytes;
-	entry->totals_via_skb[direction].packets++;
+	data_counters_update(&entry->totals_via_skb, 0, direction, proto,
+			     bytes);
 	spin_unlock_bh(&iface_stat_list_lock);
 }
 
@@ -1412,8 +1419,8 @@
 	iface_entry = get_iface_entry(ifname);
 	if (!iface_entry) {
 		spin_unlock_bh(&iface_stat_list_lock);
-		pr_err("qtaguid: iface_stat: stat_update() %s not found\n",
-		       ifname);
+		pr_err_ratelimited("qtaguid: iface_stat: stat_update() "
+				   "%s not found\n", ifname);
 		return;
 	}
 	spin_unlock_bh(&iface_stat_list_lock);
@@ -1464,6 +1471,8 @@
 		 *  - No {0, uid_tag} stats and no {acc_tag, uid_tag} stats.
 		 */
 		new_tag_stat = create_if_tag_stat(iface_entry, uid_tag);
+		if (!new_tag_stat)
+			goto unlock;
 		uid_tag_counters = &new_tag_stat->counters;
 	} else {
 		uid_tag_counters = &tag_stat_entry->counters;
@@ -1472,6 +1481,8 @@
 	if (acct_tag) {
 		/* Create the child {acct_tag, uid_tag} and hook up parent. */
 		new_tag_stat = create_if_tag_stat(iface_entry, tag);
+		if (!new_tag_stat)
+			goto unlock;
 		new_tag_stat->parent_counters = uid_tag_counters;
 	} else {
 		/*
@@ -1485,6 +1496,7 @@
 		BUG_ON(!new_tag_stat);
 	}
 	tag_stat_update(new_tag_stat, direction, proto, bytes);
+unlock:
 	spin_unlock_bh(&iface_entry->tag_stat_list_lock);
 }
 
@@ -2302,11 +2314,12 @@
 	}
 	CT_DEBUG("qtaguid: ctrl_tag(%s): "
 		 "pid=%u tgid=%u uid=%u euid=%u fsuid=%u "
-		 "in_group=%d in_egroup=%d\n",
+		 "ctrl.gid=%u in_group()=%d in_egroup()=%d\n",
 		 input, current->pid, current->tgid, current_uid(),
 		 current_euid(), current_fsuid(),
-		 in_group_p(proc_ctrl_write_gid),
-		 in_egroup_p(proc_ctrl_write_gid));
+		 xt_qtaguid_ctrl_file->gid,
+		 in_group_p(xt_qtaguid_ctrl_file->gid),
+		 in_egroup_p(xt_qtaguid_ctrl_file->gid));
 	if (argc < 4) {
 		uid = current_fsuid();
 	} else if (!can_impersonate_uid(uid)) {
@@ -2593,14 +2606,16 @@
 	} else {
 		tag_t tag = ppi->ts_entry->tn.tag;
 		uid_t stat_uid = get_uid_from_tag(tag);
-
-		if (!can_read_other_uid_stats(stat_uid)) {
+		/* Detailed tags are not available to everybody */
+		if (get_atag_from_tag(tag)
+		    && !can_read_other_uid_stats(stat_uid)) {
 			CT_DEBUG("qtaguid: stats line: "
 				 "%s 0x%llx %u: insufficient priv "
-				 "from pid=%u tgid=%u uid=%u\n",
+				 "from pid=%u tgid=%u uid=%u stats.gid=%u\n",
 				 ppi->iface_entry->ifname,
 				 get_atag_from_tag(tag), stat_uid,
-				 current->pid, current->tgid, current_fsuid());
+				 current->pid, current->tgid, current_fsuid(),
+				 xt_qtaguid_stats_file->gid);
 			return 0;
 		}
 		if (ppi->item_index++ < ppi->items_to_skip)
@@ -2756,7 +2771,7 @@
 	utd_entry = get_uid_data(current_fsuid(), &utd_entry_found);
 	if (IS_ERR_OR_NULL(utd_entry)) {
 		res = PTR_ERR(utd_entry);
-		goto err;
+		goto err_unlock;
 	}
 
 	/* Look for existing PID based proc_data */
@@ -2798,8 +2813,8 @@
 		rb_erase(&utd_entry->node, &uid_tag_data_tree);
 		kfree(utd_entry);
 	}
+err_unlock:
 	spin_unlock_bh(&uid_tag_data_tree_lock);
-err:
 	return res;
 }
 
diff --git a/net/netfilter/xt_qtaguid_internal.h b/net/netfilter/xt_qtaguid_internal.h
index d79f838..6dc14a9 100644
--- a/net/netfilter/xt_qtaguid_internal.h
+++ b/net/netfilter/xt_qtaguid_internal.h
@@ -179,6 +179,25 @@
 	struct byte_packet_counters bpc[IFS_MAX_COUNTER_SETS][IFS_MAX_DIRECTIONS][IFS_MAX_PROTOS];
 };
 
+static inline uint64_t dc_sum_bytes(struct data_counters *counters,
+				    int set,
+				    enum ifs_tx_rx direction)
+{
+	return counters->bpc[set][direction][IFS_TCP].bytes
+		+ counters->bpc[set][direction][IFS_UDP].bytes
+		+ counters->bpc[set][direction][IFS_PROTO_OTHER].bytes;
+}
+
+static inline uint64_t dc_sum_packets(struct data_counters *counters,
+				      int set,
+				      enum ifs_tx_rx direction)
+{
+	return counters->bpc[set][direction][IFS_TCP].packets
+		+ counters->bpc[set][direction][IFS_UDP].packets
+		+ counters->bpc[set][direction][IFS_PROTO_OTHER].packets;
+}
+
+
 /* Generic X based nodes used as a base for rb_tree ops */
 struct tag_node {
 	struct rb_node node;
@@ -203,7 +222,7 @@
 	struct net_device *net_dev;
 
 	struct byte_packet_counters totals_via_dev[IFS_MAX_DIRECTIONS];
-	struct byte_packet_counters totals_via_skb[IFS_MAX_DIRECTIONS];
+	struct data_counters totals_via_skb;
 	/*
 	 * We keep the last_known, because some devices reset their counters
 	 * just before NETDEV_UP, while some will reset just before
diff --git a/net/netfilter/xt_qtaguid_print.c b/net/netfilter/xt_qtaguid_print.c
index 8cbd8e4..f6a00a3 100644
--- a/net/netfilter/xt_qtaguid_print.c
+++ b/net/netfilter/xt_qtaguid_print.c
@@ -177,9 +177,10 @@
 char *pp_iface_stat(struct iface_stat *is)
 {
 	char *res;
-	if (!is)
+	if (!is) {
 		res = kasprintf(GFP_ATOMIC, "iface_stat@null{}");
-	else
+	} else {
+		struct data_counters *cnts = &is->totals_via_skb;
 		res = kasprintf(GFP_ATOMIC, "iface_stat@%p{"
 				"list=list_head{...}, "
 				"ifname=%s, "
@@ -206,10 +207,10 @@
 				is->totals_via_dev[IFS_RX].packets,
 				is->totals_via_dev[IFS_TX].bytes,
 				is->totals_via_dev[IFS_TX].packets,
-				is->totals_via_skb[IFS_RX].bytes,
-				is->totals_via_skb[IFS_RX].packets,
-				is->totals_via_skb[IFS_TX].bytes,
-				is->totals_via_skb[IFS_TX].packets,
+				dc_sum_bytes(cnts, 0, IFS_RX),
+				dc_sum_packets(cnts, 0, IFS_RX),
+				dc_sum_bytes(cnts, 0, IFS_TX),
+				dc_sum_packets(cnts, 0, IFS_TX),
 				is->last_known_valid,
 				is->last_known[IFS_RX].bytes,
 				is->last_known[IFS_RX].packets,
@@ -218,6 +219,7 @@
 				is->active,
 				is->net_dev,
 				is->proc_ptr);
+	}
 	_bug_on_err_or_null(res);
 	return res;
 }
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
index a2fc3a0..c5861b8 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -1,17 +1,799 @@
-#
-# This file is a placeholder to prevent accidental build breakage if someone
-# enables CONFIG_CFG80211_INTERNAL_REGDB.  Almost no one actually needs to
-# enable that build option.
-#
-# You should be using CRDA instead.  It is even better if you use the CRDA
-# package provided by your distribution, since they will probably keep it
-# up-to-date on your behalf.
-#
-# If you _really_ intend to use CONFIG_CFG80211_INTERNAL_REGDB then you will
-# need to replace this file with one containing appropriately formatted
-# regulatory rules that cover the regulatory domains you will be using.  Your
-# best option is to extract the db.txt file from the wireless-regdb git
-# repository:
-#
-#   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git
-#
+# This is the world regulatory domain
+country 00:
+	(2402 - 2472 @ 40), (3, 20)
+	# Channel 12 - 13.
+	(2457 - 2482 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS
+	# Channel 14. Only JP enables this and for 802.11b only
+	(2474 - 2494 @ 20), (3, 20), PASSIVE-SCAN, NO-IBSS, NO-OFDM
+	# Channel 36 - 48
+	(5170 - 5250 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS
+	# NB: 5260 MHz - 5700 MHz requies DFS
+	# Channel 149 - 165
+	(5735 - 5835 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS
+
+
+country AD:
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country AE:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+
+country AL:
+	(2402 - 2482 @ 20), (N/A, 20)
+
+country AM:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (N/A, 18)
+	(5250 - 5330 @ 20), (N/A, 18), DFS
+
+country AN:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+
+country AR:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country AT: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country AU:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 23)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country AW:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+
+country AZ:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 18)
+	(5250 - 5330 @ 40), (N/A, 18), DFS
+
+country BA: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country BB:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 23)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country BD:
+	(2402 - 2482 @ 40), (N/A, 20)
+
+country BE: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country BG: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 23)
+	(5250 - 5290 @ 40), (N/A, 23), DFS
+	(5490 - 5710 @ 40), (N/A, 30), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country BH:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (N/A, 20)
+	(5250 - 5330 @ 20), (N/A, 20), DFS
+	(5735 - 5835 @ 20), (N/A, 20)
+
+country BL:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 18)
+	(5250 - 5330 @ 40), (N/A, 18), DFS
+
+country BN:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country BO:
+	(2402 - 2482 @ 40), (N/A, 30)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country BR:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country BY:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+
+country BZ:
+	(2402 - 2482 @ 40), (N/A, 30)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country CA:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country CH: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country CL:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5735 - 5835 @ 40), (N/A, 20)
+
+country CN:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+	# 60 gHz band channels 1,4: 28dBm, channels 2,3: 44dBm
+	# ref: http://www.miit.gov.cn/n11293472/n11505629/n11506593/n11960250/n11960606/n11960700/n12330791.files/n12330790.pdf
+	(57240 - 59400 @ 2160), (N/A, 28)
+	(59400 - 63720 @ 2160), (N/A, 44)
+	(63720 - 65880 @ 2160), (N/A, 28)
+
+country CO:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country CR:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (3, 17)
+	(5250 - 5330 @ 20), (3, 23), DFS
+	(5735 - 5835 @ 20), (3, 30)
+
+country CS:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+
+country CY: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+# Data from http://www.ctu.eu/164/download/VOR/VOR-12-08-2005-34.pdf
+# and http://www.ctu.eu/164/download/VOR/VOR-12-05-2007-6-AN.pdf
+# Power at 5250 - 5350 MHz and 5470 - 5725 MHz can be doubled if TPC is
+# implemented.
+country CZ: DFS-ETSI
+	(2400 - 2483.5 @ 40), (N/A, 100 mW)
+	(5150 - 5250 @ 40), (N/A, 200 mW), NO-OUTDOOR
+	(5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS
+	(5470 - 5725 @ 40), (N/A, 500 mW), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+# Data from "Frequenznutzungsplan" (as published in April 2008), downloaded from
+# http://www.bundesnetzagentur.de/cae/servlet/contentblob/38448/publicationFile/2659/Frequenznutzungsplan2008_Id17448pdf.pdf
+# For the 5GHz range also see
+# http://www.bundesnetzagentur.de/cae/servlet/contentblob/38216/publicationFile/6579/WLAN5GHzVfg7_2010_28042010pdf.pdf
+# The values have been reduced by a factor of 2 (3db) for non TPC devices
+# (in other words: devices with TPC can use twice the tx power of this table).
+# Note that the docs do not require TPC for 5150--5250; the reduction to
+# 100mW thus is not strictly required -- however the conservative 100mW
+# limit is used here as the non-interference with radar and satellite
+# apps relies on the attenuation by the building walls only in the
+# absence of DFS; the neighbour countries have 100mW limit here as well.
+
+country DE: DFS-ETSI
+	# entries 279004 and 280006
+	(2400 - 2483.5 @ 40), (N/A, 100 mW)
+	# entry 303005
+	(5150 - 5250 @ 40), (N/A, 100 mW), NO-OUTDOOR
+	# entries 304002 and 305002
+	(5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS
+	# entries 308002, 309001 and 310003
+	(5470 - 5725 @ 40), (N/A, 500 mW), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country DK: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country DO:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country DZ:
+	(2402 - 2482 @ 40), (N/A, 20)
+
+country EC:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (3, 17)
+	(5250 - 5330 @ 20), (3, 23), DFS
+	(5735 - 5835 @ 20), (3, 30)
+
+country EE: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country EG:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (N/A, 20)
+	(5250 - 5330 @ 20), (N/A, 20), DFS
+
+country ES: DFS-ETSI
+	(2400 - 2483.5 @ 40), (N/A, 100 mW)
+	(5150 - 5250 @ 40), (N/A, 100 mW), NO-OUTDOOR
+	(5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS
+	(5470 - 5725 @ 40), (N/A, 500 mW), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country FI: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country FR: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country GE:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 18)
+	(5250 - 5330 @ 40), (N/A, 18), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country GB: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country GD:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country GR: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country GL: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (N/A, 20)
+	(5250 - 5330 @ 20), (N/A, 20), DFS
+	(5490 - 5710 @ 20), (N/A, 27), DFS
+
+country GT:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country GU:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 20), (3, 17)
+	(5250 - 5330 @ 20), (3, 23), DFS
+	(5735 - 5835 @ 20), (3, 30)
+
+country HN:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country HK:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country HR: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country HT:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+
+country HU: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country ID:
+	(2402 - 2482 @ 40), (N/A, 20)
+
+country IE: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country IL:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5150 - 5250 @ 40), (N/A, 200 mW), NO-OUTDOOR
+	(5250 - 5350 @ 40), (N/A, 200 mW), NO-OUTDOOR, DFS
+
+country IN:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5735 - 5835 @ 40), (N/A, 20)
+
+country IS: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country IR:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country IT: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country JM:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country JP:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(2474 - 2494 @ 20), (N/A, 20), NO-OFDM
+	(4910 - 4990 @ 40), (N/A, 23)
+	(5030 - 5090 @ 40), (N/A, 23)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 23), DFS
+
+country JO:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 18)
+
+country KE:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country KH:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+
+country KP:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5330 @ 40), (3, 20)
+	(5160 - 5250 @ 40), (3, 20), DFS
+	(5490 - 5630 @ 40), (3, 30), DFS
+	(5735 - 5815 @ 40), (3, 30)
+
+country KR:
+	(2402 - 2482 @ 20), (N/A, 20)
+	(5170 - 5250 @ 20), (3, 20)
+	(5250 - 5330 @ 20), (3, 20), DFS
+	(5490 - 5630 @ 20), (3, 30), DFS
+	(5735 - 5815 @ 20), (3, 30)
+
+country KW:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+
+country KZ:
+	(2402 - 2482 @ 40), (N/A, 20)
+
+country LB:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country LI: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+
+country LK:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (3, 17)
+	(5250 - 5330 @ 20), (3, 20), DFS
+	(5490 - 5710 @ 20), (3, 20), DFS
+	(5735 - 5835 @ 20), (3, 30)
+
+country LT: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country LU: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country LV: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country MC: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 18)
+	(5250 - 5330 @ 40), (N/A, 18), DFS
+
+country MA:
+	(2402 - 2482 @ 40), (N/A, 20)
+
+country MO:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 23)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country MK: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country MT: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country MY:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 30), DFS
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country MX:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country NL: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20), NO-OUTDOOR
+	(5250 - 5330 @ 40), (N/A, 20), NO-OUTDOOR, DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country NO: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country NP:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country NZ:
+	(2402 - 2482 @ 40), (N/A, 30)
+	(5170 - 5250 @ 20), (3, 23)
+	(5250 - 5330 @ 20), (3, 23), DFS
+	(5735 - 5835 @ 20), (3, 30)
+
+country OM:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country PA:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country PE:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country PG:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country PH:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country PK:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country PL: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country PT: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country PR:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 23), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country QA:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country RO: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+
+# Source:
+# http://www.ratel.rs/upload/documents/Plan_namene/Plan_namene-sl_glasnik.pdf
+country RS:
+	(2400 - 2483.5 @ 40), (N/A, 100 mW)
+	(5150 - 5350 @ 40), (N/A, 200 mW), NO-OUTDOOR
+	(5470 - 5725 @ 20), (3, 1000 mW), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country RU:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 20), (N/A, 30)
+
+country RW:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5835 @ 40), (N/A, 30)
+
+country SA:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (3, 23)
+	(5250 - 5330 @ 20), (3, 23), DFS
+	(5735 - 5835 @ 20), (3, 30)
+
+country SE: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country SG:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5735 - 5835 @ 40), (N/A, 20)
+
+country SI: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country SK: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+	(5490 - 5710 @ 40), (N/A, 27), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country SV:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (3, 17)
+	(5250 - 5330 @ 20), (3, 23), DFS
+	(5735 - 5835 @ 20), (3, 30)
+
+country SY:
+	(2402 - 2482 @ 40), (N/A, 20)
+
+country TW:
+	(2402 - 2472 @ 40), (3, 27)
+	(5270 - 5330 @ 40), (3, 17), DFS
+	(5735 - 5815 @ 40), (3, 30)
+
+country TH:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country TT:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country TN:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (N/A, 20)
+	(5250 - 5330 @ 20), (N/A, 20), DFS
+
+country TR: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (N/A, 20)
+	(5250 - 5330 @ 20), (N/A, 20), DFS
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+ 
+# Source:
+# #914 / 06 Sep 2007: http://www.ucrf.gov.ua/uk/doc/nkrz/1196068874
+# #1174 / 23 Oct 2008: http://www.nkrz.gov.ua/uk/activities/ruling/1225269361
+# (appendix 8)
+# Listed 5GHz range is a lowest common denominator for all related
+# rules in the referenced laws. Such a range is used because of
+# disputable definitions there.
+country UA:
+	(2400 - 2483.5 @ 40), (N/A, 20), NO-OUTDOOR
+	(5150 - 5350 @ 40), (N/A, 20), NO-OUTDOOR
+	# 60 gHz band channels 1-4, ref: Etsi En 302 567
+	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country US: DFS-FCC
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5600 @ 40), (3, 20), DFS
+	(5650 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+	# 60g band
+	# reference: http://cfr.regstoday.com/47cfr15.aspx#47_CFR_15p255
+	# channels 1,2,3, EIRP=40dBm(43dBm peak)
+	(57240 - 63720 @ 2160), (N/A, 40)
+
+country UY:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country UZ:
+	(2402 - 2472 @ 40), (3, 27)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country VE:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5735 - 5815 @ 40), (N/A, 23)
+
+country VN:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (N/A, 20)
+	(5250 - 5330 @ 40), (N/A, 20), DFS
+
+country YE:
+	(2402 - 2482 @ 40), (N/A, 20)
+
+country ZA:
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 40), (3, 17)
+	(5250 - 5330 @ 40), (3, 20), DFS
+	(5490 - 5710 @ 40), (3, 20), DFS
+	(5735 - 5835 @ 40), (3, 30)
+
+country ZW:
+	(2402 - 2482 @ 40), (N/A, 20)
+
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1dee449..7db02f3 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2408,8 +2408,8 @@
 		return -ENOENT;
 
 	err = rdev->ops->stop_ap(&rdev->wiphy, dev);
-	if (!err)
-		wdev->beacon_interval = 0;
+	wdev->beacon_interval = 0;
+
 	return err;
 }
 
@@ -8473,6 +8473,18 @@
 }
 EXPORT_SYMBOL(cfg80211_ft_event);
 
+
+void cfg80211_ap_stopped(struct net_device *netdev, gfp_t gfp)
+{
+	struct wireless_dev *wdev = netdev->ieee80211_ptr;
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+	nl80211_send_mlme_event(rdev, netdev, NULL, 0,
+				NL80211_CMD_STOP_AP, gfp);
+}
+EXPORT_SYMBOL(cfg80211_ap_stopped);
+
+
 /* initialisation/exit functions */
 
 int nl80211_init(void)
diff --git a/sound/core/init.c b/sound/core/init.c
index f300bd3..6559a40 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -55,6 +55,8 @@
 module_param_array(slots, charp, NULL, 0444);
 MODULE_PARM_DESC(slots, "Module names assigned to the slots.");
 
+#define SND_CARD_STATE_MAX_LEN 16
+
 /* return non-zero if the given index is reserved for the given
  * module via slots option
  */
@@ -104,10 +106,40 @@
 	snd_iprintf(buffer, "%s\n", entry->card->id);
 }
 
+static int snd_card_state_read(struct snd_info_entry *entry,
+			       void *file_private_data, struct file *file,
+			       char __user *buf, size_t count, loff_t pos)
+{
+	int len;
+	char buffer[SND_CARD_STATE_MAX_LEN];
+
+	/* make sure offline is updated prior to wake up */
+	rmb();
+	len = snprintf(buffer, sizeof(buffer), "%s\n",
+		       entry->card->offline ? "OFFLINE" : "ONLINE");
+	return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static unsigned int snd_card_state_poll(struct snd_info_entry *entry,
+					void *private_data, struct file *file,
+					poll_table *wait)
+{
+	poll_wait(file, &entry->card->offline_poll_wait, wait);
+	if (xchg(&entry->card->offline_change, 0))
+		return POLLIN | POLLPRI | POLLRDNORM;
+	else
+		return 0;
+}
+
+static struct snd_info_entry_ops snd_card_state_proc_ops = {
+	.read = snd_card_state_read,
+	.poll = snd_card_state_poll,
+};
+
 static inline int init_info_for_card(struct snd_card *card)
 {
 	int err;
-	struct snd_info_entry *entry;
+	struct snd_info_entry *entry, *entry_state;
 
 	if ((err = snd_info_card_register(card)) < 0) {
 		snd_printd("unable to create card info\n");
@@ -123,6 +155,24 @@
 		entry = NULL;
 	}
 	card->proc_id = entry;
+
+	entry_state = snd_info_create_card_entry(card, "state",
+						 card->proc_root);
+	if (entry_state == NULL) {
+		snd_printd("unable to create card entry state\n");
+		card->proc_id = NULL;
+		return err;
+	}
+	entry_state->size = SND_CARD_STATE_MAX_LEN;
+	entry_state->content = SNDRV_INFO_CONTENT_DATA;
+	entry_state->c.ops = &snd_card_state_proc_ops;
+	err = snd_info_register(entry_state);
+	if (err < 0) {
+		snd_printd("unable to register card entry state\n");
+		card->proc_id = NULL;
+		return err;
+	}
+
 	return 0;
 }
 #else /* !CONFIG_PROC_FS */
@@ -216,6 +266,7 @@
 	mutex_init(&card->power_lock);
 	init_waitqueue_head(&card->power_sleep);
 #endif
+	init_waitqueue_head(&card->offline_poll_wait);
 	/* the control interface cannot be accessed from the user space until */
 	/* snd_cards_bitmask and snd_cards are set with snd_card_register */
 	err = snd_ctl_create(card);
@@ -909,6 +960,35 @@
 
 EXPORT_SYMBOL(snd_card_file_remove);
 
+/**
+ * snd_card_change_online_state - mark card's online/offline state
+ * @card: Card to mark
+ * @online: whether online of offline
+ *
+ * Mutes the DAI DAC.
+ */
+void snd_card_change_online_state(struct snd_card *card, int online)
+{
+	snd_printd("snd card %s state change %d -> %d\n",
+		   card->shortname, !card->offline, online);
+	card->offline = !online;
+	/* make sure offline is updated prior to wake up */
+	wmb();
+	xchg(&card->offline_change, 1);
+	wake_up_interruptible(&card->offline_poll_wait);
+}
+EXPORT_SYMBOL(snd_card_change_online_state);
+
+/**
+ * snd_card_is_online_state - return true if card is online state
+ * @card: Card to query
+ */
+bool snd_card_is_online_state(struct snd_card *card)
+{
+	return !card->offline;
+}
+EXPORT_SYMBOL(snd_card_is_online_state);
+
 #ifdef CONFIG_PM
 /**
  *  snd_power_wait - wait until the power-state is changed.
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index c0469e3..56cd5e6 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -165,7 +165,7 @@
 obj-$(CONFIG_SND_SOC_CS8427)	+= snd-soc-cs8427.o
 obj-$(CONFIG_SND_SOC_WCD9320)	+= snd-soc-wcd9320.o
 obj-$(CONFIG_SND_SOC_WCD9306)	+= snd-soc-wcd9306.o wcd9xxx-resmgr.o wcd9xxx-mbhc.o
-obj-$(CONFIG_SND_SOC_MSM8X10_WCD)	+= snd-soc-msm8x10-wcd.o wcd9xxx-resmgr.o
+obj-$(CONFIG_SND_SOC_MSM8X10_WCD)	+= snd-soc-msm8x10-wcd.o wcd9xxx-resmgr.o wcd9xxx-mbhc.o
 obj-$(CONFIG_SND_SOC_WL1273)	+= snd-soc-wl1273.o
 obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
 obj-$(CONFIG_SND_SOC_WM2000)	+= snd-soc-wm2000.o
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 8844b21..bd4f926 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -27,7 +27,6 @@
 #include <linux/i2c.h>
 #include <linux/of_gpio.h>
 #include <linux/regulator/consumer.h>
-#include <linux/mfd/wcd9xxx/core.h>
 #include <linux/mfd/wcd9xxx/pdata.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -52,6 +51,7 @@
 
 #define MSM8X10_WCD_I2S_MASTER_MODE_MASK	0x08
 #define MSM8X10_DINO_CODEC_BASE_ADDR		0xFE043000
+#define MSM8X10_DINO_CODEC_REG_SIZE		0x200
 #define MSM8x10_TLMM_CDC_PULL_CTL			0xFD512050
 #define HELICON_CORE_0_I2C_ADDR				0x0d
 #define HELICON_CORE_1_I2C_ADDR				0x77
@@ -61,6 +61,7 @@
 #define MAX_MSM8X10_WCD_DEVICE	4
 #define CODEC_DT_MAX_PROP_SIZE	40
 #define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH 64
+#define HELICON_MCLK_CLK_9P6MHZ				9600000
 
 enum {
 	MSM8X10_WCD_I2C_TOP_LEVEL = 0,
@@ -125,6 +126,16 @@
 	ON_DEMAND_SUPPLIES_MAX,
 };
 
+/*
+ * The delay list is per codec HW specification.
+ * Please add delay in the list in the future instead
+ * of magic number
+ */
+enum {
+	CODEC_DELAY_1_MS = 1000,
+	CODEC_DELAY_1_1_MS  = 1100,
+};
+
 struct hpf_work {
 	struct msm8x10_wcd_priv *msm8x10_wcd;
 	u32 decimator;
@@ -149,15 +160,14 @@
 	u32 adc_count;
 	u32 rx_bias_count;
 	s32 dmic_1_2_clk_cnt;
-	enum msm8x10_wcd_bandgap_type bandgap_type;
-	bool mclk_enabled;
-	bool clock_active;
-	bool config_mode_active;
-	bool mbhc_polling_active;
 	struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX];
-	struct mutex codec_resource_lock;
 	/* resmgr module */
 	struct wcd9xxx_resmgr resmgr;
+	/* mbhc module */
+	struct wcd9xxx_mbhc mbhc;
+
+	struct delayed_work hs_detect_work;
+	struct wcd9xxx_mbhc_config *mbhc_cfg;
 };
 
 static unsigned short rx_digital_gain_reg[] = {
@@ -211,20 +221,23 @@
 	return rtn;
 }
 
-static int msm8x10_wcd_abh_write_device(u16 reg, u8 *value, u32 bytes)
+static int msm8x10_wcd_abh_write_device(struct msm8x10_wcd *msm8x10_wcd,
+					u16 reg, u8 *value, u32 bytes)
 {
 	u32 temp = ((u32)(*value)) & 0x000000FF;
 	u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
-	iowrite32(temp, ioremap(MSM8X10_DINO_CODEC_BASE_ADDR + offset, 4));
+
+	iowrite32(temp, (msm8x10_wcd->pdino_base+offset));
 	return 0;
 }
 
-static int msm8x10_wcd_abh_read_device(u16 reg, u32 bytes, u8 *value)
+static int msm8x10_wcd_abh_read_device(struct msm8x10_wcd *msm8x10_wcd,
+					u16 reg, u32 bytes, u8 *value)
 {
 	u32 temp;
 	u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
-	temp = ioread32(ioremap(MSM8X10_DINO_CODEC_BASE_ADDR +
-				      offset, 4));
+
+	temp = ioread32((msm8x10_wcd->pdino_base+offset));
 	*value = (u8)temp;
 	return 0;
 }
@@ -330,40 +343,112 @@
 	return msm8x10_wcd_i2c_write_device(reg, src, bytes);
 }
 
-static int msm8x10_wcd_reg_read(struct msm8x10_wcd *msm8x10_wcd,
-				u16 reg, unsigned int *val)
+static unsigned short msm8x10_wcd_mask_reg(unsigned short reg)
+{
+	if (reg >= 0x3C0 && reg <= 0x3DF)
+		reg = reg & 0x00FF;
+	return reg;
+}
+
+static int __msm8x10_wcd_reg_read(struct msm8x10_wcd *msm8x10_wcd,
+				unsigned short reg)
 {
 	int ret = -EINVAL;
 	u8 temp;
 
+	reg = msm8x10_wcd_mask_reg(reg);
+
 	/* check if use I2C interface for Helicon or AHB for Dino */
 	mutex_lock(&msm8x10_wcd->io_lock);
 	if (MSM8X10_WCD_IS_HELICON_REG(reg))
 		ret = msm8x10_wcd_i2c_read(reg, 1, &temp);
 	else if (MSM8X10_WCD_IS_DINO_REG(reg))
-		ret = msm8x10_wcd_abh_read_device(reg, 1, &temp);
+		ret = msm8x10_wcd_abh_read_device(msm8x10_wcd, reg, 1, &temp);
 	mutex_unlock(&msm8x10_wcd->io_lock);
-	*val = temp;
+
+	if (ret < 0) {
+		dev_err(msm8x10_wcd->dev,
+				"%s: codec read failed for reg 0x%x\n",
+				__func__, reg);
+		return ret;
+	} else {
+		dev_dbg(msm8x10_wcd->dev, "Read 0x%02x from 0x%x\n",
+				temp, reg);
+	}
+
+	return temp;
+}
+
+int msm8x10_wcd_reg_read(struct wcd9xxx_core_resource *core_res,
+				unsigned short reg)
+{
+	struct msm8x10_wcd *msm8x10_wcd = core_res->parent;
+	return __msm8x10_wcd_reg_read(msm8x10_wcd, reg);
+}
+EXPORT_SYMBOL(msm8x10_wcd_reg_read);
+
+static int __msm8x10_wcd_bulk_read(struct msm8x10_wcd *msm8x10_wcd,
+		unsigned short reg, int count, u8 *buf)
+{
+	int ret = -EINVAL;
+	mutex_lock(&msm8x10_wcd->io_lock);
+	if (MSM8X10_WCD_IS_HELICON_REG(reg))
+		ret = msm8x10_wcd_i2c_read(reg, count, buf);
+	else if (MSM8X10_WCD_IS_DINO_REG(reg))
+		ret = msm8x10_wcd_abh_read_device(msm8x10_wcd, reg,
+						count, buf);
+	mutex_unlock(&msm8x10_wcd->io_lock);
+
+	if (ret < 0)
+		dev_err(msm8x10_wcd->dev,
+				"%s: codec bulk read failed\n", __func__);
 	return ret;
 }
 
+int msm8x10_wcd_bulk_read(struct wcd9xxx_core_resource *core_res,
+			unsigned short reg, int count, u8 *buf)
+{
+	struct msm8x10_wcd *msm8x10_wcd =
+				(struct msm8x10_wcd *) core_res->parent;
+	return __msm8x10_wcd_bulk_read(msm8x10_wcd, reg, count, buf);
+}
+EXPORT_SYMBOL(msm8x10_wcd_bulk_read);
 
-static int msm8x10_wcd_reg_write(struct msm8x10_wcd *msm8x10_wcd, u16  reg,
-				 u8 val)
+static int __msm8x10_wcd_reg_write(struct msm8x10_wcd *msm8x10_wcd,
+			unsigned short reg, u8 val)
 {
 	int ret = -EINVAL;
 
+	reg = msm8x10_wcd_mask_reg(reg);
+
 	/* check if use I2C interface for Helicon or AHB for Dino */
 	mutex_lock(&msm8x10_wcd->io_lock);
 	if (MSM8X10_WCD_IS_HELICON_REG(reg))
 		ret = msm8x10_wcd_i2c_write(reg, 1, &val);
 	else if (MSM8X10_WCD_IS_DINO_REG(reg))
-		ret = msm8x10_wcd_abh_write_device(reg, &val, 1);
+		ret = msm8x10_wcd_abh_write_device(msm8x10_wcd, reg, &val, 1);
 	mutex_unlock(&msm8x10_wcd->io_lock);
 
+	if (ret < 0)
+		dev_err(msm8x10_wcd->dev,
+				"%s: codec write to reg 0x%x failed\n",
+				__func__, reg);
+	else
+		dev_dbg(msm8x10_wcd->dev,
+				"%s: Codec reg 0x%x written with value 0x%x\n",
+				__func__, reg, val);
+
 	return ret;
 }
 
+int msm8x10_wcd_reg_write(struct wcd9xxx_core_resource *core_res,
+	unsigned short reg, u8 val)
+{
+	struct msm8x10_wcd *msm8x10_wcd = core_res->parent;
+	return __msm8x10_wcd_reg_write(msm8x10_wcd, reg, val);
+}
+EXPORT_SYMBOL(msm8x10_wcd_reg_write);
+
 static bool msm8x10_wcd_is_digital_gain_register(unsigned int reg)
 {
 	bool rtn = false;
@@ -437,7 +522,7 @@
 				reg, ret);
 	}
 
-	return msm8x10_wcd_reg_write(codec->control_data, reg, (u8)value);
+	return __msm8x10_wcd_reg_write(codec->control_data, reg, (u8)value);
 }
 
 static unsigned int msm8x10_wcd_read(struct snd_soc_codec *codec,
@@ -463,7 +548,7 @@
 				reg, ret);
 	}
 
-	ret = msm8x10_wcd_reg_read(codec->control_data, reg, &val);
+	val = __msm8x10_wcd_reg_read(codec->control_data, reg);
 	return val;
 }
 
@@ -1144,13 +1229,8 @@
 	"ZERO", "ADC1", "ADC2", "DMIC1", "DMIC2"
 };
 
-static const char * const anc_mux_text[] = {
-	"ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
-		"RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
-};
-
-static const char * const anc1_fb_mux_text[] = {
-	"ZERO", "EAR_HPH_L", "EAR_LINE_1",
+static const char * const adc2_mux_text[] = {
+	"ZERO", "INP2", "INP3"
 };
 
 static const char * const iir1_inp1_text[] = {
@@ -1208,6 +1288,9 @@
 	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_LO_DAC_CTL, 0, 3,
 	rx_rdac4_text);
 
+static const struct soc_enum adc2_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
+
 static const struct snd_kcontrol_new rx_mix1_inp1_mux =
 	SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
 
@@ -1238,6 +1321,9 @@
 static const struct snd_kcontrol_new rx_dac4_mux =
 	SOC_DAPM_ENUM("RDAC4 MUX Mux", rx_rdac4_enum);
 
+static const struct snd_kcontrol_new tx_adc2_mux =
+	SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
+
 static int msm8x10_wcd_put_dec_enum(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
@@ -1366,7 +1452,8 @@
 
 	if (w->reg == MSM8X10_WCD_A_TX_1_EN)
 		init_bit_shift = 7;
-	else if (w->reg == MSM8X10_WCD_A_TX_2_EN)
+	else if ((w->reg == MSM8X10_WCD_A_TX_2_EN) ||
+		 (w->reg == MSM8X10_WCD_A_TX_3_EN))
 		init_bit_shift = 6;
 	else {
 		dev_err(codec->dev, "%s: Error, invalid adc register\n",
@@ -1379,9 +1466,11 @@
 		msm8x10_wcd_codec_enable_adc_block(codec, 1);
 		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
 				1 << init_bit_shift);
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
+		usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		msm8x10_wcd_codec_enable_adc_block(codec, 0);
@@ -1513,7 +1602,6 @@
 			snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
 		else if (strnstr(w->name, internal3_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
-		snd_soc_update_bits(codec, w->reg, 0x1, 0x0);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		usleep_range(20000, 20100);
@@ -1526,7 +1614,6 @@
 		else if (strnstr(w->name, internal3_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
 
-		snd_soc_update_bits(codec, w->reg, 0x1, 0x1);
 		break;
 	}
 	return 0;
@@ -1778,12 +1865,6 @@
 		/* Let MBHC module know PA turned off */
 		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
 
-		/*
-		 * schedule work is required because at the time HPH PA DAPM
-		 * event callback is called by DAPM framework, CODEC dapm mutex
-		 * would have been locked while snd_soc_jack_report also
-		 * attempts to acquire same lock.
-		 */
 		dev_dbg(codec->dev,
 			"%s: sleep 10 ms after %s PA disable.\n", __func__,
 			w->name);
@@ -1926,9 +2007,14 @@
 	{"DEC2 MUX", "ADC2", "ADC2"},
 	{"DEC2 MUX", NULL, "CDC_CONN"},
 
+	{"ADC2", NULL, "ADC2 MUX"},
+	{"ADC2 MUX", "INP2", "ADC2_INP2"},
+	{"ADC2 MUX", "INP3", "ADC2_INP3"},
+
 	/* ADC Connections */
 	{"ADC1", NULL, "AMIC1"},
-	{"ADC2", NULL, "AMIC2"},
+	{"ADC2_INP2", NULL, "AMIC2"},
+	{"ADC2_INP3", NULL, "AMIC3"},
 
 	{"IIR1", NULL, "IIR1 INP1 MUX"},
 	{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
@@ -1958,88 +2044,6 @@
 		substream->name, substream->stream);
 }
 
-static int msm8x10_wcd_codec_enable_clock_block(struct snd_soc_codec *codec,
-						int enable)
-{
-	if (enable) {
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
-				    0x01, 0x01);
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
-				    0x03, 0x03);
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
-				    0x0f, 0x0d);
-	} else {
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
-				    0x0f, 0x00);
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
-				    0x03, 0x00);
-	}
-	return 0;
-}
-
-static void msm8x10_wcd_codec_enable_audio_mode_bandgap(struct snd_soc_codec
-							*codec)
-{
-	snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
-		0x80);
-	snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x04,
-		0x04);
-	snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x01,
-		0x01);
-	usleep_range(1000, 1000);
-	snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
-		0x00);
-}
-
-static void msm8x10_wcd_codec_enable_bandgap(struct snd_soc_codec *codec,
-	enum msm8x10_wcd_bandgap_type choice)
-{
-	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
-
-	/* TODO lock resources accessed by audio streams and threaded
-	 * interrupt handlers
-	 */
-
-	dev_dbg(codec->dev, "%s, choice is %d, current is %d\n",
-		__func__, choice,
-		msm8x10_wcd->bandgap_type);
-
-	if (msm8x10_wcd->bandgap_type == choice)
-		return;
-
-	if ((msm8x10_wcd->bandgap_type == MSM8X10_WCD_BANDGAP_OFF) &&
-		(choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
-		msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
-	} else if (choice == MSM8X10_WCD_BANDGAP_MBHC_MODE) {
-		/* bandgap mode becomes fast,
-		 * mclk should be off or clk buff source souldn't be VBG
-		 * Let's turn off mclk always */
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
-				    0x2, 0x2);
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
-				    0x80, 0x80);
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
-				    0x4, 0x4);
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
-				    0x01, 0x01);
-		usleep_range(1000, 1000);
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
-				    0x80, 0x00);
-	} else if ((msm8x10_wcd->bandgap_type ==
-		    MSM8X10_WCD_BANDGAP_MBHC_MODE) &&
-		    (choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
-		snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
-		usleep_range(100, 100);
-		msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
-	} else if (choice == MSM8X10_WCD_BANDGAP_OFF) {
-		snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
-	} else {
-		dev_err(codec->dev,
-			"%s: Error, Invalid bandgap settings\n", __func__);
-	}
-	msm8x10_wcd->bandgap_type = choice;
-}
-
 int msm8x10_wcd_mclk_enable(struct snd_soc_codec *codec,
 			    int mclk_enable, bool dapm)
 {
@@ -2047,28 +2051,21 @@
 
 	dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
 		__func__, mclk_enable, dapm);
-	if (dapm)
-		MSM8X10_WCD_ACQUIRE_LOCK(msm8x10_wcd->codec_resource_lock);
+
+	WCD9XXX_BG_CLK_LOCK(&msm8x10_wcd->resmgr);
+
 	if (mclk_enable) {
-		msm8x10_wcd->mclk_enabled = true;
-		msm8x10_wcd_codec_enable_bandgap(codec,
-					   MSM8X10_WCD_BANDGAP_AUDIO_MODE);
-		msm8x10_wcd_codec_enable_clock_block(codec, 1);
+		wcd9xxx_resmgr_get_bandgap(&msm8x10_wcd->resmgr,
+				WCD9XXX_BANDGAP_AUDIO_MODE);
+		wcd9xxx_resmgr_get_clk_block(&msm8x10_wcd->resmgr,
+				WCD9XXX_CLK_MCLK);
 	} else {
-		if (!msm8x10_wcd->mclk_enabled) {
-			if (dapm)
-				MSM8X10_WCD_RELEASE_LOCK(
-				  msm8x10_wcd->codec_resource_lock);
-			dev_err(codec->dev, "Error, MCLK already diabled\n");
-			return -EINVAL;
-		}
-		msm8x10_wcd->mclk_enabled = false;
-		msm8x10_wcd_codec_enable_clock_block(codec, 0);
-		msm8x10_wcd_codec_enable_bandgap(codec,
-						   MSM8X10_WCD_BANDGAP_OFF);
+		wcd9xxx_resmgr_put_clk_block(&msm8x10_wcd->resmgr,
+					WCD9XXX_CLK_MCLK);
+		wcd9xxx_resmgr_put_bandgap(&msm8x10_wcd->resmgr,
+					WCD9XXX_BANDGAP_AUDIO_MODE);
 	}
-	if (dapm)
-		MSM8X10_WCD_RELEASE_LOCK(msm8x10_wcd->codec_resource_lock);
+	WCD9XXX_BG_CLK_UNLOCK(&msm8x10_wcd->resmgr);
 	return 0;
 }
 
@@ -2402,9 +2399,17 @@
 	SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_1_EN, 7, 0,
 		msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_ADC_E("ADC2", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
+	SND_SOC_DAPM_ADC_E("ADC2_INP2", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
 		msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC2_INP3", NULL, MSM8X10_WCD_A_TX_3_EN, 7, 0,
+		msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0,
+		&tx_adc2_mux),
 
 	SND_SOC_DAPM_MICBIAS("MIC BIAS External", MSM8X10_WCD_A_MICB_1_CTL,
 			     7, 0),
@@ -2482,7 +2487,7 @@
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_CFILT_1_VAL, 0x60),
 	/* Enable pulldown to reduce leakage */
-	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x83),
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x82),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_2_EN, 0x32),
@@ -2496,6 +2501,10 @@
 
 	/* Always set TXD_CLK_EN bit to reduce the leakage */
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0x10),
+
+	/* Always disable clock gating for MCLK to mbhc clock gate */
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_ANA_CLK_CTL, 0x20),
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0x10),
 };
 
 static void msm8x10_wcd_update_reg_defaults(struct snd_soc_codec *codec)
@@ -2546,9 +2555,118 @@
 				    msm8x10_wcd_codec_reg_init_val[i].val);
 }
 
-int msm8x10_wcd_hs_detect(struct snd_soc_codec *codec,
-		    struct msm8x10_wcd_mbhc_config *mbhc_cfg)
+static void msm8x10_wcd_enable_mux_bias_block(
+		struct snd_soc_codec *codec)
 {
+	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
+				0x80, 0x00);
+}
+
+static void msm8x10_wcd_put_cfilt_fast_mode(
+	struct snd_soc_codec *codec,
+	struct wcd9xxx_mbhc *mbhc)
+{
+	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
+			0x30, 0x30);
+}
+
+static void msm8x10_wcd_codec_specific_cal_setup(
+	struct snd_soc_codec *codec,
+	struct wcd9xxx_mbhc *mbhc)
+{
+	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+			0x04, 0x04);
+	snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN,
+			0xE0, 0xE0);
+}
+
+static int msm8x10_wcd_get_jack_detect_irq(
+		struct snd_soc_codec *codec)
+{
+	return MSM8X10_WCD_IRQ_MBHC_HS_DET;
+}
+
+static struct wcd9xxx_cfilt_mode msm8x10_wcd_switch_cfilt_mode(
+	struct wcd9xxx_mbhc *mbhc, bool fast)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct wcd9xxx_cfilt_mode cfilt_mode;
+
+	if (fast)
+		cfilt_mode.reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_EN;
+	else
+		cfilt_mode.reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_DSBL;
+
+	cfilt_mode.cur_mode_val =
+		snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x30;
+	cfilt_mode.reg_mask = 0x30;
+	return cfilt_mode;
+}
+
+static void msm8x10_wcd_select_cfilt(struct snd_soc_codec *codec,
+	struct wcd9xxx_mbhc *mbhc)
+{
+	snd_soc_update_bits(codec,
+			mbhc->mbhc_bias_regs.ctl_reg, 0x60, 0x00);
+}
+
+static void msm8x10_wcd_free_irq(struct wcd9xxx_mbhc *mbhc)
+{
+	struct msm8x10_wcd *msm8x10_wcd = mbhc->codec->control_data;
+	struct wcd9xxx_core_resource *core_res =
+			&msm8x10_wcd->wcd9xxx_res;
+	wcd9xxx_free_irq(core_res, MSM8X10_WCD_IRQ_MBHC_HS_DET, mbhc);
+}
+
+enum wcd9xxx_cdc_type msm8x10_wcd_get_cdc_type(void)
+{
+	return WCD9XXX_CDC_TYPE_HELICON;
+}
+
+static void msm8x10_wcd_mbhc_clk_gate(struct snd_soc_codec *codec,
+		bool on)
+{
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL, 0x10, 0x10);
+}
+
+static const struct wcd9xxx_mbhc_cb mbhc_cb = {
+	.enable_mux_bias_block = msm8x10_wcd_enable_mux_bias_block,
+	.cfilt_fast_mode = msm8x10_wcd_put_cfilt_fast_mode,
+	.codec_specific_cal = msm8x10_wcd_codec_specific_cal_setup,
+	.jack_detect_irq = msm8x10_wcd_get_jack_detect_irq,
+	.switch_cfilt_mode = msm8x10_wcd_switch_cfilt_mode,
+	.select_cfilt = msm8x10_wcd_select_cfilt,
+	.free_irq = msm8x10_wcd_free_irq,
+	.get_cdc_type = msm8x10_wcd_get_cdc_type,
+	.enable_clock_gate = msm8x10_wcd_mbhc_clk_gate,
+};
+
+static void delayed_hs_detect_fn(struct work_struct *work)
+{
+	struct delayed_work *delayed_work;
+	struct msm8x10_wcd_priv *wcd_priv;
+
+	delayed_work = to_delayed_work(work);
+	wcd_priv = container_of(delayed_work, struct msm8x10_wcd_priv,
+				hs_detect_work);
+
+	if (!wcd_priv) {
+		pr_err("%s: Invalid private data for codec\n", __func__);
+		return;
+	}
+
+	wcd9xxx_mbhc_start(&wcd_priv->mbhc, wcd_priv->mbhc_cfg);
+}
+
+
+int msm8x10_wcd_hs_detect(struct snd_soc_codec *codec,
+		    struct wcd9xxx_mbhc_config *mbhc_cfg)
+{
+	struct msm8x10_wcd_priv *wcd = snd_soc_codec_get_drvdata(codec);
+
+	wcd->mbhc_cfg = mbhc_cfg;
+	schedule_delayed_work(&wcd->hs_detect_work,
+			msecs_to_jiffies(5000));
 	return 0;
 }
 EXPORT_SYMBOL_GPL(msm8x10_wcd_hs_detect);
@@ -2626,45 +2744,74 @@
 
 static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
 {
-	struct msm8x10_wcd_priv *msm8x10_wcd;
-	int i;
+	struct msm8x10_wcd_priv *msm8x10_wcd_priv;
+	struct msm8x10_wcd *msm8x10_wcd;
+	struct wcd9xxx_core_resource *core_res;
+	int i, ret = 0;
+
 	dev_dbg(codec->dev, "%s()\n", __func__);
 
-	msm8x10_wcd = kzalloc(sizeof(struct msm8x10_wcd_priv), GFP_KERNEL);
-	if (!msm8x10_wcd) {
+	msm8x10_wcd_priv = devm_kzalloc(codec->dev,
+			sizeof(struct msm8x10_wcd_priv), GFP_KERNEL);
+
+	if (!msm8x10_wcd_priv) {
 		dev_err(codec->dev, "Failed to allocate private data\n");
 		return -ENOMEM;
 	}
 
 	for (i = 0 ; i < NUM_DECIMATORS; i++) {
-		tx_hpf_work[i].msm8x10_wcd = msm8x10_wcd;
+		tx_hpf_work[i].msm8x10_wcd = msm8x10_wcd_priv;
 		tx_hpf_work[i].decimator = i + 1;
 		INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
 			tx_hpf_corner_freq_callback);
 	}
 
 	codec->control_data = dev_get_drvdata(codec->dev);
-	snd_soc_codec_set_drvdata(codec, msm8x10_wcd);
-	msm8x10_wcd->codec = codec;
+	snd_soc_codec_set_drvdata(codec, msm8x10_wcd_priv);
+	msm8x10_wcd_priv->codec = codec;
+
+	/* map digital codec registers once */
+	msm8x10_wcd = codec->control_data;
+	msm8x10_wcd->pdino_base = ioremap(MSM8X10_DINO_CODEC_BASE_ADDR,
+					  MSM8X10_DINO_CODEC_REG_SIZE);
+	INIT_DELAYED_WORK(&msm8x10_wcd_priv->hs_detect_work,
+			delayed_hs_detect_fn);
+
+	/* codec resmgr module init */
+	msm8x10_wcd = codec->control_data;
+	core_res = &msm8x10_wcd->wcd9xxx_res;
+	ret = wcd9xxx_resmgr_init(&msm8x10_wcd_priv->resmgr,
+				codec, core_res, NULL, NULL,
+				WCD9XXX_CDC_TYPE_HELICON);
+	if (ret) {
+		dev_err(codec->dev,
+				"%s: wcd9xxx init failed %d\n",
+				__func__, ret);
+		goto exit_probe;
+	}
+
 	msm8x10_wcd_bringup(codec);
 	msm8x10_wcd_codec_init_reg(codec);
 	msm8x10_wcd_update_reg_defaults(codec);
-	msm8x10_wcd->on_demand_list[ON_DEMAND_CP].supply =
+	msm8x10_wcd_priv->on_demand_list[ON_DEMAND_CP].supply =
 				wcd8x10_wcd_codec_find_regulator(
 				codec->control_data,
 				on_demand_supply_name[ON_DEMAND_CP]);
-	atomic_set(&msm8x10_wcd->on_demand_list[ON_DEMAND_CP].ref, 0);
-	msm8x10_wcd->on_demand_list[ON_DEMAND_MICBIAS].supply =
+	atomic_set(&msm8x10_wcd_priv->on_demand_list[ON_DEMAND_CP].ref, 0);
+	msm8x10_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply =
 				wcd8x10_wcd_codec_find_regulator(
 				codec->control_data,
 				on_demand_supply_name[ON_DEMAND_MICBIAS]);
-	atomic_set(&msm8x10_wcd->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
-	msm8x10_wcd->mclk_enabled = false;
-	msm8x10_wcd->bandgap_type = MSM8X10_WCD_BANDGAP_OFF;
-	msm8x10_wcd->clock_active = false;
-	msm8x10_wcd->config_mode_active = false;
-	msm8x10_wcd->mbhc_polling_active = false;
-	mutex_init(&msm8x10_wcd->codec_resource_lock);
+	atomic_set(&msm8x10_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
+
+	ret = wcd9xxx_mbhc_init(&msm8x10_wcd_priv->mbhc,
+				&msm8x10_wcd_priv->resmgr,
+				codec, NULL, &mbhc_cb,
+				HELICON_MCLK_CLK_9P6MHZ, false);
+	if (ret) {
+		pr_err("%s: Failed to initialize mbhc\n", __func__);
+		goto exit_probe;
+	}
 
 	registered_codec = codec;
 	adsp_state_notifier =
@@ -2677,15 +2824,25 @@
 		return -ENOMEM;
 	}
 	return 0;
+
+exit_probe:
+	return ret;
+
 }
 
 static int msm8x10_wcd_codec_remove(struct snd_soc_codec *codec)
 {
-	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
-	msm8x10_wcd->on_demand_list[ON_DEMAND_CP].supply = NULL;
-	atomic_set(&msm8x10_wcd->on_demand_list[ON_DEMAND_CP].ref, 0);
-	msm8x10_wcd->on_demand_list[ON_DEMAND_MICBIAS].supply = NULL;
-	atomic_set(&msm8x10_wcd->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
+	struct msm8x10_wcd_priv *pwcd_priv = snd_soc_codec_get_drvdata(codec);
+	struct msm8x10_wcd *msm8x10_wcd = pwcd_priv->codec->control_data;
+	pwcd_priv->on_demand_list[ON_DEMAND_CP].supply = NULL;
+	atomic_set(&pwcd_priv->on_demand_list[ON_DEMAND_CP].ref, 0);
+	pwcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply = NULL;
+	atomic_set(&pwcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
+
+	/* cleanup resmgr */
+	wcd9xxx_resmgr_deinit(&pwcd_priv->resmgr);
+
+	iounmap(msm8x10_wcd->pdino_base);
 	return 0;
 }
 
@@ -2833,25 +2990,41 @@
 
 static int msm8x10_wcd_pads_config(void)
 {
+	void __iomem *ppull = ioremap(MSM8x10_TLMM_CDC_PULL_CTL, 4);
 	/* Set I2C pads as pull up and rest of pads as no pull */
-	iowrite32(0x03C00000, ioremap(MSM8x10_TLMM_CDC_PULL_CTL, 4));
+	iowrite32(0x03C00000, ppull);
 	usleep_range(100, 200);
+
+	iounmap(ppull);
 	return 0;
 }
 
 
 static int msm8x10_wcd_clk_init(void)
 {
+	void __iomem *pdig1 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR, 4);
+	void __iomem *pdig2 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_M, 4);
+	void __iomem *pdig3 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_N, 4);
+	void __iomem *pdig4 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_D, 4);
+	void __iomem *pdig5 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4);
+	void __iomem *pdig6 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4);
 	/* Div-2 */
-	iowrite32(0x3, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR, 4));
-	iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_M, 4));
-	iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_N, 4));
-	iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_D, 4));
+	iowrite32(0x3, pdig1);
+	iowrite32(0x0, pdig2);
+	iowrite32(0x0, pdig3);
+	iowrite32(0x0, pdig4);
 	/* Digital codec clock enable */
-	iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+	iowrite32(0x1, pdig5);
 	/* Set the update bit to make the settings go through */
-	iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4));
+	iowrite32(0x1, pdig6);
 	usleep_range(100, 200);
+
+	iounmap(pdig1);
+	iounmap(pdig2);
+	iounmap(pdig3);
+	iounmap(pdig4);
+	iounmap(pdig5);
+	iounmap(pdig6);
 	return 0;
 }
 
@@ -2859,13 +3032,38 @@
 {
 	mutex_init(&msm8x10->io_lock);
 	mutex_init(&msm8x10->xfer_lock);
-	mutex_init(&msm8x10->pm_lock);
-	msm8x10->wlock_holders = 0;
 	msm8x10_wcd_pads_config();
 	msm8x10_wcd_clk_init();
 	return 0;
 }
 
+static struct intr_data interrupt_table[] = {
+	{MSM8X10_WCD_IRQ_MBHC_INSERTION, true},
+	{MSM8X10_WCD_IRQ_MBHC_POTENTIAL, true},
+	{MSM8X10_WCD_IRQ_MBHC_RELEASE, true},
+	{MSM8X10_WCD_IRQ_MBHC_PRESS, true},
+	{MSM8X10_WCD_IRQ_MBHC_SHORT_TERM, true},
+	{MSM8X10_WCD_IRQ_MBHC_REMOVAL, true},
+	{MSM8X10_WCD_IRQ_MBHC_HS_DET, true},
+	{MSM8X10_WCD_IRQ_RESERVED_0, false},
+	{MSM8X10_WCD_IRQ_PA_STARTUP, false},
+	{MSM8X10_WCD_IRQ_BG_PRECHARGE, false},
+	{MSM8X10_WCD_IRQ_RESERVED_1, false},
+	{MSM8X10_WCD_IRQ_EAR_PA_OCPL_FAULT, false},
+	{MSM8X10_WCD_IRQ_EAR_PA_STARTUP, false},
+	{MSM8X10_WCD_IRQ_SPKR_PA_OCPL_FAULT, false},
+	{MSM8X10_WCD_IRQ_SPKR_CLIP_FAULT, false},
+	{MSM8X10_WCD_IRQ_RESERVED_2, false},
+	{MSM8X10_WCD_IRQ_HPH_L_PA_STARTUP, false},
+	{MSM8X10_WCD_IRQ_HPH_R_PA_STARTUP, false},
+	{MSM8X10_WCD_IRQ_HPH_PA_OCPL_FAULT, false},
+	{MSM8X10_WCD_IRQ_HPH_PA_OCPR_FAULT, false},
+	{MSM8X10_WCD_IRQ_RESERVED_3, false},
+	{MSM8X10_WCD_IRQ_RESERVED_4, false},
+	{MSM8X10_WCD_IRQ_RESERVED_5, false},
+	{MSM8X10_WCD_IRQ_RESERVED_6, false},
+};
+
 static int __devinit msm8x10_wcd_i2c_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
@@ -2875,6 +3073,7 @@
 	static int device_id;
 	struct device *dev;
 	enum apr_subsys_state q6_state;
+	struct wcd9xxx_core_resource *core_res;
 
 	dev_dbg(&client->dev, "%s(%d):slave addr = 0x%x device_id = %d\n",
 		__func__, __LINE__,  client->addr, device_id);
@@ -2934,8 +3133,8 @@
 	}
 
 	msm8x10->dev = &client->dev;
-	msm8x10->read_dev = msm8x10_wcd_reg_read;
-	msm8x10->write_dev = msm8x10_wcd_reg_write;
+	msm8x10->read_dev = __msm8x10_wcd_reg_read;
+	msm8x10->write_dev = __msm8x10_wcd_reg_write;
 	ret = msm8x10_wcd_init_supplies(msm8x10, pdata);
 	if (ret) {
 		dev_err(&client->dev, "%s: Fail to enable Codec supplies\n",
@@ -2959,15 +3158,37 @@
 		goto err_supplies;
 	}
 	dev_set_drvdata(&client->dev, msm8x10);
+	core_res = &msm8x10->wcd9xxx_res;
+	core_res->parent = msm8x10;
+	core_res->dev = msm8x10->dev;
+	core_res->intr_table = interrupt_table;
+	core_res->intr_table_size = ARRAY_SIZE(interrupt_table);
+
+	wcd9xxx_core_res_init(core_res,
+					MSM8X10_WCD_NUM_IRQS,
+					MSM8X10_WCD_NUM_IRQ_REGS,
+					msm8x10_wcd_reg_read,
+					msm8x10_wcd_reg_write,
+					msm8x10_wcd_bulk_read);
+	if (wcd9xxx_core_irq_init(core_res)) {
+		dev_err(msm8x10->dev,
+				"%s: irq initialization failed\n", __func__);
+	} else {
+		dev_info(msm8x10->dev,
+				"%s: irq initialization passed\n", __func__);
+	}
+
 	ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_msm8x10_wcd,
 				     msm8x10_wcd_i2s_dai,
 				     ARRAY_SIZE(msm8x10_wcd_i2s_dai));
-	if (ret)
+	if (ret) {
 		dev_err(&client->dev,
 			"%s:snd_soc_register_codec failed with error %d\n",
 			__func__, ret);
-	else
+	} else {
+		wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_I2C);
 		goto rtn;
+	}
 
 err_supplies:
 	msm8x10_wcd_disable_supplies(msm8x10, pdata);
@@ -2979,7 +3200,6 @@
 
 static void msm8x10_wcd_device_exit(struct msm8x10_wcd *msm8x10)
 {
-	mutex_destroy(&msm8x10->pm_lock);
 	mutex_destroy(&msm8x10->io_lock);
 	mutex_destroy(&msm8x10->xfer_lock);
 	kfree(msm8x10);
@@ -3023,6 +3243,7 @@
 	int ret;
 
 	pr_debug("%s:\n", __func__);
+	wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_PROBING);
 	ret = i2c_add_driver(&msm8x10_wcd_i2c_driver);
 	if (ret != 0)
 		pr_err("%s: Failed to add msm8x10 wcd I2C driver - error %d\n",
diff --git a/sound/soc/codecs/msm8x10-wcd.h b/sound/soc/codecs/msm8x10-wcd.h
index 8e561cf..5f67cba 100644
--- a/sound/soc/codecs/msm8x10-wcd.h
+++ b/sound/soc/codecs/msm8x10-wcd.h
@@ -168,31 +168,6 @@
 	MSM8X10_WCD_MICBIAS1 = 0,
 };
 
-struct msm8x10_wcd_mbhc_config {
-	struct snd_soc_jack *headset_jack;
-	struct snd_soc_jack *button_jack;
-	bool read_fw_bin;
-	/*
-	 * void* calibration contains:
-	 *  struct msm8x10_wcd_mbhc_general_cfg generic;
-	 *  struct msm8x10_wcd_mbhc_plug_detect_cfg plug_det;
-	 *  struct msm8x10_wcd_mbhc_plug_type_cfg plug_type;
-	 *  struct msm8x10_wcd_mbhc_btn_detect_cfg btn_det;
-	 *  struct msm8x10_wcd_mbhc_imped_detect_cfg imped_det;
-	 * Note: various size depends on btn_det->num_btn
-	 */
-	void *calibration;
-	enum msm8x10_wcd_micbias_num micbias;
-	int (*mclk_cb_fn) (struct snd_soc_codec*, int, bool);
-	unsigned int mclk_rate;
-	unsigned int gpio;
-	unsigned int gpio_irq;
-	int gpio_level_insert;
-	bool detect_extn_cable;
-	/* swap_gnd_mic returns true if extern GND/MIC swap switch toggled */
-	bool (*swap_gnd_mic) (struct snd_soc_codec *);
-};
-
 enum msm8x10_wcd_pm_state {
 	MSM8X10_WCD_PM_SLEEPABLE,
 	MSM8X10_WCD_PM_AWAKE,
@@ -203,39 +178,29 @@
 	struct device *dev;
 	struct mutex io_lock;
 	struct mutex xfer_lock;
-	struct mutex irq_lock;
 	u8 version;
 
 	int reset_gpio;
 	int (*read_dev)(struct msm8x10_wcd *msm8x10,
-			unsigned short reg, unsigned int *val);
+			unsigned short reg);
 	int (*write_dev)(struct msm8x10_wcd *msm8x10,
 			 unsigned short reg, u8 val);
 
 	u32 num_of_supplies;
 	struct regulator_bulk_data *supplies;
 
-	enum msm8x10_wcd_pm_state pm_state;
-	struct mutex pm_lock;
-	/* pm_wq notifies change of pm_state */
-	wait_queue_head_t pm_wq;
-	struct pm_qos_request pm_qos_req;
-	int wlock_holders;
-
 	u8 idbyte[4];
 
-	unsigned int irq_base;
-	unsigned int irq;
-	u8 irq_masks_cur[MSM8X10_WCD_NUM_IRQ_REGS];
-	u8 irq_masks_cache[MSM8X10_WCD_NUM_IRQ_REGS];
-	bool irq_level_high[MSM8X10_WCD_NUM_IRQS];
 	int num_irqs;
 	u32 mclk_rate;
+	char __iomem *pdino_base;
+
+	struct wcd9xxx_core_resource wcd9xxx_res;
 };
 
 extern int msm8x10_wcd_mclk_enable(struct snd_soc_codec *codec, int mclk_enable,
 			     bool dapm);
 extern int msm8x10_wcd_hs_detect(struct snd_soc_codec *codec,
-			   struct msm8x10_wcd_mbhc_config *mbhc_cfg);
+			struct wcd9xxx_mbhc_config *mbhc_cfg);
 
 #endif
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 58ea22d..a68722c 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -3961,8 +3961,10 @@
 {
 	short bias_value;
 	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *core = codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
 	if (noreldetection)
 		sitar_turn_onoff_rel_detection(codec, false);
 
@@ -4103,11 +4105,12 @@
 {
 	int r = 0;
 	struct wcd9xxx *core = dev_get_drvdata(sitar->codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 
 	if (cancel_delayed_work_sync(&sitar->mbhc_btn_dwork)) {
 		/* if scheduled mbhc_btn_dwork is canceled from here,
 		 * we have to unlock from here instead btn_work */
-		wcd9xxx_unlock_sleep(core);
+		wcd9xxx_unlock_sleep(core_res);
 		r = 1;
 	}
 	return r;
@@ -4171,12 +4174,14 @@
 	short bias_value;
 	int dce_mv, sta_mv;
 	struct wcd9xxx *core;
+	struct wcd9xxx_core_resource *core_res;
 
 	pr_debug("%s:\n", __func__);
 
 	delayed_work = to_delayed_work(work);
 	sitar = container_of(delayed_work, struct sitar_priv, mbhc_btn_dwork);
 	core = dev_get_drvdata(sitar->codec->dev->parent);
+	core_res = &core->core_res;
 
 	if (sitar) {
 		if (sitar->mbhc_cfg.button_jack) {
@@ -4198,7 +4203,7 @@
 	}
 
 	pr_debug("%s: leave\n", __func__);
-	wcd9xxx_unlock_sleep(core);
+	wcd9xxx_unlock_sleep(core_res);
 }
 
 
@@ -4212,11 +4217,13 @@
 	u32 dce_wait, sta_wait;
 	u8 *n_cic;
 	void *calibration;
+	struct wcd9xxx *core = codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 
 	sitar = snd_soc_codec_get_drvdata(codec);
 	calibration = sitar->mbhc_cfg.calibration;
 
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
 	sitar_turn_onoff_rel_detection(codec, false);
 
 	/* First compute the DCE / STA wait times
@@ -4707,22 +4714,28 @@
 /* should be called under interrupt context that hold suspend */
 static void sitar_schedule_hs_detect_plug(struct sitar_priv *sitar)
 {
+	struct wcd9xxx *core = sitar->codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
+
 	pr_debug("%s: scheduling sitar_hs_correct_gpio_plug\n", __func__);
 	sitar->hs_detect_work_stop = false;
-	wcd9xxx_lock_sleep(sitar->codec->control_data);
+	wcd9xxx_lock_sleep(core_res);
 	schedule_work(&sitar->hs_correct_plug_work);
 }
 
 /* called under codec_resource_lock acquisition */
 static void sitar_cancel_hs_detect_plug(struct sitar_priv *sitar)
 {
+	struct wcd9xxx *core = sitar->codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
+
 	pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
 	sitar->hs_detect_work_stop = true;
 	wmb();
 	SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
 	if (cancel_work_sync(&sitar->hs_correct_plug_work)) {
 		pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
-		wcd9xxx_unlock_sleep(sitar->codec->control_data);
+		wcd9xxx_unlock_sleep(core_res);
 	}
 	SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
 }
@@ -4737,9 +4750,13 @@
 	short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
 	enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
 	unsigned long timeout;
+	struct wcd9xxx *core;
+	struct wcd9xxx_core_resource *core_res;
 
 	sitar = container_of(work, struct sitar_priv, hs_correct_plug_work);
 	codec = sitar->codec;
+	core = sitar->codec->control_data;
+	core_res = &core->core_res;
 
 	pr_debug("%s: enter\n", __func__);
 	sitar->mbhc_cfg.mclk_cb_fn(codec, 1, false);
@@ -4815,7 +4832,7 @@
 	sitar->mbhc_cfg.mclk_cb_fn(codec, 0, false);
 	pr_debug("%s: leave\n", __func__);
 	/* unlock sleep */
-	wcd9xxx_unlock_sleep(sitar->codec->control_data);
+	wcd9xxx_unlock_sleep(core_res);
 }
 
 /* called under codec_resource_lock acquisition */
@@ -4966,8 +4983,10 @@
 {
 	int r = IRQ_HANDLED;
 	struct snd_soc_codec *codec = data;
+	struct wcd9xxx *core = codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 
-	if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
+	if (unlikely(wcd9xxx_lock_sleep(core_res) == false)) {
 		pr_warn("%s(): Failed to hold suspend\n", __func__);
 		r = IRQ_NONE;
 	} else {
@@ -5181,6 +5200,7 @@
 	short btnmeas[d->n_btn_meas + 1];
 	struct snd_soc_codec *codec = priv->codec;
 	struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 	int n_btn_meas = d->n_btn_meas;
 	u8 mbhc_status = snd_soc_read(codec, SITAR_A_CDC_MBHC_B1_STATUS) & 0x3E;
 
@@ -5271,12 +5291,12 @@
 		}
 		mask = sitar_get_button_mask(btn);
 		priv->buttons_pressed |= mask;
-		wcd9xxx_lock_sleep(core);
+		wcd9xxx_lock_sleep(core_res);
 		if (schedule_delayed_work(&priv->mbhc_btn_dwork,
 					  msecs_to_jiffies(400)) == 0) {
 			WARN(1, "Button pressed twice without release"
 			     "event\n");
-			wcd9xxx_unlock_sleep(core);
+			wcd9xxx_unlock_sleep(core_res);
 		}
 	} else {
 		pr_debug("%s: bogus button press, too short press?\n",
@@ -5386,11 +5406,16 @@
 {
 	struct sitar_priv *sitar = data;
 	struct snd_soc_codec *codec;
+	struct wcd9xxx *core;
+	struct wcd9xxx_core_resource *core_res;
 
 	pr_info("%s: received HPHL OCP irq\n", __func__);
 
 	if (sitar) {
 		codec = sitar->codec;
+		core = codec->control_data;
+		core_res = &core->core_res;
+
 		if ((sitar->hphlocp_cnt < SITAR_OCP_ATTEMPT) &&
 		    (!sitar->hphrocp_cnt)) {
 			pr_info("%s: retry\n", __func__);
@@ -5400,7 +5425,7 @@
 			snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
 					    0x10);
 		} else {
-			wcd9xxx_disable_irq(codec->control_data,
+			wcd9xxx_disable_irq(core_res,
 					    WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
 			sitar->hph_status |= SND_JACK_OC_HPHL;
 			if (sitar->mbhc_cfg.headset_jack)
@@ -5420,11 +5445,16 @@
 {
 	struct sitar_priv *sitar = data;
 	struct snd_soc_codec *codec;
+	struct wcd9xxx *core;
+	struct wcd9xxx_core_resource *core_res;
 
 	pr_info("%s: received HPHR OCP irq\n", __func__);
 
 	if (sitar) {
 		codec = sitar->codec;
+		core = codec->control_data;
+		core_res = &core->core_res;
+
 		if ((sitar->hphrocp_cnt < SITAR_OCP_ATTEMPT) &&
 		    (!sitar->hphlocp_cnt)) {
 			pr_info("%s: retry\n", __func__);
@@ -5434,7 +5464,7 @@
 			snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
 					   0x10);
 		} else {
-			wcd9xxx_disable_irq(codec->control_data,
+			wcd9xxx_disable_irq(core_res,
 					    WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 			sitar->hph_status |= SND_JACK_OC_HPHR;
 			if (sitar->mbhc_cfg.headset_jack)
@@ -5454,10 +5484,12 @@
 {
 	struct sitar_priv *priv = data;
 	struct snd_soc_codec *codec = priv->codec;
+	struct wcd9xxx *core = codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 
 	pr_debug("%s: enter\n", __func__);
 	SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION);
 
 	snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
 
@@ -5847,9 +5879,11 @@
 	int i;
 	u8 sitar_version;
 	void *ptr = NULL;
+	struct wcd9xxx_core_resource *core_res;
 
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
 	core = codec->control_data;
+	core_res = &core->core_res;
 
 	sitar = kzalloc(sizeof(struct sitar_priv), GFP_KERNEL);
 	if (!sitar) {
@@ -5951,7 +5985,7 @@
 	snd_soc_dapm_sync(dapm);
 
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_MBHC_INSERTION,
 		sitar_hs_insert_irq, "Headset insert detect", sitar);
 	if (ret) {
@@ -5959,9 +5993,9 @@
 		       WCD9XXX_IRQ_MBHC_INSERTION);
 		goto err_insert_irq;
 	}
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION);
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_MBHC_REMOVAL,
 		sitar_hs_remove_irq, "Headset remove detect", sitar);
 	if (ret) {
@@ -5970,7 +6004,7 @@
 		goto err_remove_irq;
 	}
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_MBHC_POTENTIAL,
 		sitar_dce_handler, "DC Estimation detect", sitar);
 	if (ret) {
@@ -5979,7 +6013,7 @@
 		goto err_potential_irq;
 	}
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_MBHC_RELEASE,
 				  sitar_release_handler,
 				  "Button Release detect", sitar);
@@ -5989,7 +6023,7 @@
 		goto err_release_irq;
 	}
 
-	ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS,
 				  sitar_slimbus_irq, "SLIMBUS Slave", sitar);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d\n", __func__,
@@ -6002,7 +6036,7 @@
 			SITAR_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
 
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
 				  sitar_hphl_ocp_irq,
 				  "HPH_L OCP detect", sitar);
@@ -6011,10 +6045,10 @@
 		       WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
 		goto err_hphl_ocp_irq;
 	}
-	wcd9xxx_disable_irq(codec->control_data,
+	wcd9xxx_disable_irq(core_res,
 			    WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
 				  sitar_hphr_ocp_irq, "HPH_R OCP detect",
 				  sitar);
@@ -6023,7 +6057,7 @@
 		       WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 		goto err_hphr_ocp_irq;
 	}
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 
 	codec->ignore_pmdown_time = 1;
 
@@ -6034,19 +6068,19 @@
 	return ret;
 
 err_hphr_ocp_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
 			 sitar);
 err_hphl_ocp_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, sitar);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, sitar);
 err_slimbus_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
 err_release_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL,
 			 sitar);
 err_potential_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
 err_remove_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION,
 			 sitar);
 err_insert_irq:
 	kfree(ptr);
@@ -6059,12 +6093,15 @@
 static int sitar_codec_remove(struct snd_soc_codec *codec)
 {
 	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, sitar);
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
+	struct wcd9xxx *core = codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
+
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, sitar);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL,
 			 sitar);
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION,
 			 sitar);
 	SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
 	sitar_codec_disable_clock_block(codec);
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index af2c53e..23696c9 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -24,6 +24,7 @@
 #include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
 #include <linux/mfd/wcd9xxx/wcd9306_registers.h>
 #include <linux/mfd/wcd9xxx/pdata.h>
+#include <linux/regulator/consumer.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -41,6 +42,13 @@
 #define TAPAN_HPH_PA_SETTLE_COMP_ON 3000
 #define TAPAN_HPH_PA_SETTLE_COMP_OFF 13000
 
+#define TAPAN_VDD_CX_OPTIMAL_UA 10000
+#define TAPAN_VDD_CX_SLEEP_UA 2000
+
+static struct regulator *tapan_codec_find_regulator(
+	struct snd_soc_codec *codec,
+	const char *name);
+
 static atomic_t kp_tapan_priv;
 static int spkr_drv_wrnd_param_set(const char *val,
 				   const struct kernel_param *kp);
@@ -58,6 +66,9 @@
 			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
 			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
 
+#define WCD9302_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+
 #define NUM_DECIMATORS 4
 #define NUM_INTERPOLATORS 4
 #define BITS_PER_REG 8
@@ -189,6 +200,12 @@
 	0,	/* AIF1_CAP */
 };
 
+enum {
+	CP_REG_BUCK = 0,
+	CP_REG_BHELPER,
+	CP_REG_MAX,
+};
+
 struct tapan_priv {
 	struct snd_soc_codec *codec;
 	u32 adc_count;
@@ -224,6 +241,9 @@
 
 	/* class h specific data */
 	struct wcd9xxx_clsh_cdc_data clsh_d;
+
+	/* pointers to regulators required for chargepump */
+	struct regulator *cp_regulators[CP_REG_MAX];
 };
 
 static const u32 comp_shift[] = {
@@ -756,20 +776,34 @@
 	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
 	struct wcd9xxx_pdata *pdata = tapan->resmgr.pdata;
 	int i;
+	bool found_regulator = false;
 
 	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+		if (pdata->regulator[i].name == NULL)
+			continue;
+
 		if (!strncmp(pdata->regulator[i].name,
-					 WCD9XXX_SUPPLY_BUCK_NAME,
-					 sizeof(WCD9XXX_SUPPLY_BUCK_NAME))) {
+			     WCD9XXX_SUPPLY_BUCK_NAME,
+			     sizeof(WCD9XXX_SUPPLY_BUCK_NAME))) {
+			found_regulator = true;
 			if ((pdata->regulator[i].min_uV ==
-					WCD9XXX_CDC_BUCK_MV_1P8) ||
-				(pdata->regulator[i].min_uV ==
-					WCD9XXX_CDC_BUCK_MV_2P15))
+			     WCD9XXX_CDC_BUCK_MV_1P8) ||
+			    (pdata->regulator[i].min_uV ==
+			     WCD9XXX_CDC_BUCK_MV_2P15))
 				buck_volt = pdata->regulator[i].min_uV;
 			break;
 		}
 	}
-	pr_debug("%s: S4 voltage requested is %d\n", __func__, buck_volt);
+
+	if (!found_regulator)
+		dev_err(codec->dev,
+			"%s: Failed to find regulator for %s\n",
+			__func__, WCD9XXX_SUPPLY_BUCK_NAME);
+	else
+		dev_dbg(codec->dev,
+			"%s: S4 voltage requested is %d\n",
+			__func__, buck_volt);
+
 	return buck_volt;
 }
 
@@ -948,7 +982,7 @@
 static const struct snd_kcontrol_new class_h_dsm_mux =
 	SOC_DAPM_ENUM("CLASS_H_DSM MUX Mux", class_h_dsm_enum);
 
-static const struct snd_kcontrol_new tapan_snd_controls[] = {
+static const struct snd_kcontrol_new tapan_common_snd_controls[] = {
 
 	SOC_ENUM_EXT("EAR PA Gain", tapan_ear_pa_gain_enum[0],
 		tapan_pa_gain_get, tapan_pa_gain_put),
@@ -970,25 +1004,17 @@
 	SOC_SINGLE_TLV("ADC2 Volume", TAPAN_A_TX_2_EN, 2, 19, 0, analog_gain),
 	SOC_SINGLE_TLV("ADC3 Volume", TAPAN_A_TX_3_EN, 2, 19, 0, analog_gain),
 	SOC_SINGLE_TLV("ADC4 Volume", TAPAN_A_TX_4_EN, 2, 19, 0, analog_gain),
-	SOC_SINGLE_TLV("ADC5 Volume", TAPAN_A_TX_5_EN, 2, 19, 0, analog_gain),
-
 	SOC_SINGLE_S8_TLV("RX1 Digital Volume", TAPAN_A_CDC_RX1_VOL_CTL_B2_CTL,
 		-84, 40, digital_gain),
 	SOC_SINGLE_S8_TLV("RX2 Digital Volume", TAPAN_A_CDC_RX2_VOL_CTL_B2_CTL,
 		-84, 40, digital_gain),
 	SOC_SINGLE_S8_TLV("RX3 Digital Volume", TAPAN_A_CDC_RX3_VOL_CTL_B2_CTL,
 		-84, 40, digital_gain),
-	SOC_SINGLE_S8_TLV("RX4 Digital Volume", TAPAN_A_CDC_RX4_VOL_CTL_B2_CTL,
-		-84, 40, digital_gain),
 
 	SOC_SINGLE_S8_TLV("DEC1 Volume", TAPAN_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
 		digital_gain),
 	SOC_SINGLE_S8_TLV("DEC2 Volume", TAPAN_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
 		digital_gain),
-	SOC_SINGLE_S8_TLV("DEC3 Volume", TAPAN_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
-		digital_gain),
-	SOC_SINGLE_S8_TLV("DEC4 Volume", TAPAN_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
-		digital_gain),
 
 	SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TAPAN_A_CDC_IIR1_GAIN_B1_CTL, -84,
 		40, digital_gain),
@@ -999,10 +1025,6 @@
 	SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TAPAN_A_CDC_IIR1_GAIN_B4_CTL, -84,
 		40, digital_gain),
 
-	SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, tapan_get_anc_slot,
-		tapan_put_anc_slot),
-	SOC_ENUM_EXT("ANC Function", tapan_anc_func_enum, tapan_get_anc_func,
-		tapan_put_anc_func),
 	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
 	SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
 	SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
@@ -1016,12 +1038,10 @@
 	SOC_SINGLE("RX1 HPF Switch", TAPAN_A_CDC_RX1_B5_CTL, 2, 1, 0),
 	SOC_SINGLE("RX2 HPF Switch", TAPAN_A_CDC_RX2_B5_CTL, 2, 1, 0),
 	SOC_SINGLE("RX3 HPF Switch", TAPAN_A_CDC_RX3_B5_CTL, 2, 1, 0),
-	SOC_SINGLE("RX4 HPF Switch", TAPAN_A_CDC_RX4_B5_CTL, 2, 1, 0),
 
 	SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
 	SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
 	SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
-	SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
 
 	SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
 	tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
@@ -1064,6 +1084,23 @@
 	tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
 	SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
 	tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
+};
+
+static const struct snd_kcontrol_new tapan_9306_snd_controls[] = {
+	SOC_SINGLE_TLV("ADC5 Volume", TAPAN_A_TX_5_EN, 2, 19, 0, analog_gain),
+
+	SOC_SINGLE_S8_TLV("RX4 Digital Volume", TAPAN_A_CDC_RX4_VOL_CTL_B2_CTL,
+		-84, 40, digital_gain),
+	SOC_SINGLE_S8_TLV("DEC3 Volume", TAPAN_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
+		digital_gain),
+	SOC_SINGLE_S8_TLV("DEC4 Volume", TAPAN_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
+		digital_gain),
+	SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, tapan_get_anc_slot,
+		tapan_put_anc_slot),
+	SOC_ENUM_EXT("ANC Function", tapan_anc_func_enum, tapan_get_anc_func,
+		tapan_put_anc_func),
+	SOC_SINGLE("RX4 HPF Switch", TAPAN_A_CDC_RX4_B5_CTL, 2, 1, 0),
+	SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
 
 	SOC_SINGLE_EXT("COMP0 Switch", SND_SOC_NOPM, COMPANDER_0, 1, 0,
 		       tapan_get_compander, tapan_set_compander),
@@ -1071,7 +1108,6 @@
 		       tapan_get_compander, tapan_set_compander),
 	SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0,
 		       tapan_get_compander, tapan_set_compander),
-
 };
 
 static const char * const rx_1_2_mix1_text[] = {
@@ -1088,6 +1124,14 @@
 	"ZERO", "SRC1", "SRC2", "IIR1", "IIR2"
 };
 
+static const char * const rx_rdac3_text[] = {
+	"DEM1", "DEM2"
+};
+
+static const char * const rx_rdac4_text[] = {
+	"DEM3", "DEM2"
+};
+
 static const char * const rx_rdac5_text[] = {
 	"DEM4", "DEM3_INV"
 };
@@ -1194,6 +1238,12 @@
 static const struct soc_enum rx4_mix2_inp2_chain_enum =
 	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B3_CTL, 3, 5, rx_mix2_text);
 
+static const struct soc_enum rx_rdac3_enum =
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B2_CTL, 4, 2, rx_rdac3_text);
+
+static const struct soc_enum rx_rdac4_enum =
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_MISC, 1, 2, rx_rdac4_text);
+
 static const struct soc_enum rx_rdac5_enum =
 	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_MISC, 2, 2, rx_rdac5_text);
 
@@ -1283,6 +1333,12 @@
 static const struct snd_kcontrol_new rx4_mix2_inp2_mux =
 	SOC_DAPM_ENUM("RX4 MIX2 INP2 Mux", rx4_mix2_inp2_chain_enum);
 
+static const struct snd_kcontrol_new rx_dac3_mux =
+	SOC_DAPM_ENUM("RDAC3 MUX Mux", rx_rdac3_enum);
+
+static const struct snd_kcontrol_new rx_dac4_mux =
+	SOC_DAPM_ENUM("RDAC4 MUX Mux", rx_rdac4_enum);
+
 static const struct snd_kcontrol_new rx_dac5_mux =
 	SOC_DAPM_ENUM("RDAC5 MUX Mux", rx_rdac5_enum);
 
@@ -2497,90 +2553,24 @@
 	{"SLIM TX2 MUX", NULL, "I2S_CLK"},
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
-	/* SLIMBUS Connections */
-	{"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
-	{"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
-	{"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
-
-	/* SLIM_MIXER("AIF1_CAP Mixer"),*/
-	{"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
-	{"AIF1_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
-	/* SLIM_MIXER("AIF2_CAP Mixer"),*/
-	{"AIF2_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
-	{"AIF2_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
-	/* SLIM_MIXER("AIF3_CAP Mixer"),*/
-	{"AIF3_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
-	{"AIF3_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
-
-	{"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
-	{"SLIM TX1 MUX", "DEC2", "DEC2 MUX"},
+static const struct snd_soc_dapm_route wcd9306_map[] = {
+	{"SLIM TX1 MUX", "RMIX4", "RX4 MIX1"},
+	{"SLIM TX2 MUX", "RMIX4", "RX4 MIX1"},
+	{"SLIM TX3 MUX", "RMIX4", "RX4 MIX1"},
+	{"SLIM TX4 MUX", "RMIX4", "RX4 MIX1"},
+	{"SLIM TX5 MUX", "RMIX4", "RX4 MIX1"},
 	{"SLIM TX1 MUX", "DEC3", "DEC3 MUX"},
 	{"SLIM TX1 MUX", "DEC4", "DEC4 MUX"},
-	{"SLIM TX1 MUX", "RMIX1", "RX1 MIX1"},
-	{"SLIM TX1 MUX", "RMIX2", "RX2 MIX1"},
-	{"SLIM TX1 MUX", "RMIX3", "RX3 MIX1"},
-	{"SLIM TX1 MUX", "RMIX4", "RX4 MIX1"},
-
-	{"SLIM TX2 MUX", "DEC1", "DEC1 MUX"},
-	{"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
 	{"SLIM TX2 MUX", "DEC3", "DEC3 MUX"},
 	{"SLIM TX2 MUX", "DEC4", "DEC4 MUX"},
-	{"SLIM TX2 MUX", "RMIX1", "RX1 MIX1"},
-	{"SLIM TX2 MUX", "RMIX2", "RX2 MIX1"},
-	{"SLIM TX2 MUX", "RMIX3", "RX3 MIX1"},
-	{"SLIM TX2 MUX", "RMIX4", "RX4 MIX1"},
-
 	{"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
-	{"SLIM TX3 MUX", "RMIX1", "RX1 MIX1"},
-	{"SLIM TX3 MUX", "RMIX2", "RX2 MIX1"},
-	{"SLIM TX3 MUX", "RMIX3", "RX3 MIX1"},
-	{"SLIM TX3 MUX", "RMIX4", "RX4 MIX1"},
-
 	{"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
-	{"SLIM TX4 MUX", "RMIX1", "RX1 MIX1"},
-	{"SLIM TX4 MUX", "RMIX2", "RX2 MIX1"},
-	{"SLIM TX4 MUX", "RMIX3", "RX3 MIX1"},
-	{"SLIM TX4 MUX", "RMIX4", "RX4 MIX1"},
-
-	{"SLIM TX5 MUX", "DEC1", "DEC1 MUX"},
-	{"SLIM TX5 MUX", "RMIX1", "RX1 MIX1"},
-	{"SLIM TX5 MUX", "RMIX2", "RX2 MIX1"},
-	{"SLIM TX5 MUX", "RMIX3", "RX3 MIX1"},
-	{"SLIM TX5 MUX", "RMIX4", "RX4 MIX1"},
-
-	/* Earpiece (RX MIX1) */
-	{"EAR", NULL, "EAR PA"},
-	{"EAR PA", NULL, "EAR_PA_MIXER"},
-	{"EAR_PA_MIXER", NULL, "DAC1"},
-	{"DAC1", NULL, "RX_BIAS"},
 
 	{"ANC EAR", NULL, "ANC EAR PA"},
 	{"ANC EAR PA", NULL, "EAR_PA_MIXER"},
 	{"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
 	{"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
 
-	/* Headset (RX MIX1 and RX MIX2) */
-	{"HEADPHONE", NULL, "HPHL"},
-	{"HEADPHONE", NULL, "HPHR"},
-
-	{"HPHL", NULL, "HPHL_PA_MIXER"},
-	{"HPHL_PA_MIXER", NULL, "HPHL DAC"},
-	{"HPHL DAC", NULL, "RX_BIAS"},
-
-	{"HPHR", NULL, "HPHR_PA_MIXER"},
-	{"HPHR_PA_MIXER", NULL, "HPHR DAC"},
-	{"HPHR DAC", NULL, "RX_BIAS"},
-
 	{"ANC HEADPHONE", NULL, "ANC HPHL"},
 	{"ANC HEADPHONE", NULL, "ANC HPHR"},
 
@@ -2608,6 +2598,150 @@
 
 	{"ANC HPHR", NULL, "CDC_CONN"},
 
+	{"RDAC5 MUX", "DEM4", "RX4 MIX2"},
+	{"SPK DAC", "Switch", "RX4 MIX2"},
+
+	{"RX1 MIX2", NULL, "ANC1 MUX"},
+	{"RX2 MIX2", NULL, "ANC2 MUX"},
+
+	{"RX1 MIX1", NULL, "COMP1_CLK"},
+	{"RX2 MIX1", NULL, "COMP1_CLK"},
+	{"RX3 MIX1", NULL, "COMP2_CLK"},
+	{"RX4 MIX1", NULL, "COMP0_CLK"},
+
+	{"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
+	{"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
+	{"RX4 MIX2", NULL, "RX4 MIX1"},
+	{"RX4 MIX2", NULL, "RX4 MIX2 INP1"},
+	{"RX4 MIX2", NULL, "RX4 MIX2 INP2"},
+
+	{"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
+	{"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
+	{"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
+	{"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
+	{"RX4 MIX1 INP1", "RX5", "SLIM RX5"},
+	{"RX4 MIX1 INP1", "IIR1", "IIR1"},
+	{"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
+	{"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
+	{"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
+	{"RX4 MIX1 INP2", "RX5", "SLIM RX5"},
+	{"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
+	{"RX4 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX4 MIX2 INP1", "IIR1", "IIR1"},
+	{"RX4 MIX2 INP2", "IIR1", "IIR1"},
+
+	{"DEC1 MUX", "DMIC3", "DMIC3"},
+	{"DEC1 MUX", "DMIC4", "DMIC4"},
+	{"DEC2 MUX", "DMIC3", "DMIC3"},
+	{"DEC2 MUX", "DMIC4", "DMIC4"},
+
+	{"DEC3 MUX", "ADC1", "ADC1"},
+	{"DEC3 MUX", "ADC2", "ADC2"},
+	{"DEC3 MUX", "ADC3", "ADC3"},
+	{"DEC3 MUX", "ADC4", "ADC4"},
+	{"DEC3 MUX", "ADC5", "ADC5"},
+	{"DEC3 MUX", "DMIC1", "DMIC1"},
+	{"DEC3 MUX", "DMIC2", "DMIC2"},
+	{"DEC3 MUX", "DMIC3", "DMIC3"},
+	{"DEC3 MUX", "DMIC4", "DMIC4"},
+	{"DEC3 MUX", NULL, "CDC_CONN"},
+
+	{"DEC4 MUX", "ADC1", "ADC1"},
+	{"DEC4 MUX", "ADC2", "ADC2"},
+	{"DEC4 MUX", "ADC3", "ADC3"},
+	{"DEC4 MUX", "ADC4", "ADC4"},
+	{"DEC4 MUX", "ADC5", "ADC5"},
+	{"DEC4 MUX", "DMIC1", "DMIC1"},
+	{"DEC4 MUX", "DMIC2", "DMIC2"},
+	{"DEC4 MUX", "DMIC3", "DMIC3"},
+	{"DEC4 MUX", "DMIC4", "DMIC4"},
+	{"DEC4 MUX", NULL, "CDC_CONN"},
+
+	{"ADC5", NULL, "AMIC5"},
+
+	{"AUX_PGA_Left", NULL, "AMIC5"},
+
+	{"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
+	{"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
+
+	{"MIC BIAS3 Internal1", NULL, "LDO_H"},
+	{"MIC BIAS3 Internal2", NULL, "LDO_H"},
+	{"MIC BIAS3 External", NULL, "LDO_H"},
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* SLIMBUS Connections */
+	{"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
+	{"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
+	{"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
+
+	/* SLIM_MIXER("AIF1_CAP Mixer"),*/
+	{"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
+	{"AIF1_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
+	/* SLIM_MIXER("AIF2_CAP Mixer"),*/
+	{"AIF2_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
+	{"AIF2_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
+	/* SLIM_MIXER("AIF3_CAP Mixer"),*/
+	{"AIF3_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
+	{"AIF3_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
+
+	{"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
+	{"SLIM TX1 MUX", "DEC2", "DEC2 MUX"},
+	{"SLIM TX1 MUX", "RMIX1", "RX1 MIX1"},
+	{"SLIM TX1 MUX", "RMIX2", "RX2 MIX1"},
+	{"SLIM TX1 MUX", "RMIX3", "RX3 MIX1"},
+
+	{"SLIM TX2 MUX", "DEC1", "DEC1 MUX"},
+	{"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
+	{"SLIM TX2 MUX", "RMIX1", "RX1 MIX1"},
+	{"SLIM TX2 MUX", "RMIX2", "RX2 MIX1"},
+	{"SLIM TX2 MUX", "RMIX3", "RX3 MIX1"},
+
+	{"SLIM TX3 MUX", "RMIX1", "RX1 MIX1"},
+	{"SLIM TX3 MUX", "RMIX2", "RX2 MIX1"},
+	{"SLIM TX3 MUX", "RMIX3", "RX3 MIX1"},
+
+	{"SLIM TX4 MUX", "RMIX1", "RX1 MIX1"},
+	{"SLIM TX4 MUX", "RMIX2", "RX2 MIX1"},
+	{"SLIM TX4 MUX", "RMIX3", "RX3 MIX1"},
+
+	{"SLIM TX5 MUX", "DEC1", "DEC1 MUX"},
+	{"SLIM TX5 MUX", "RMIX1", "RX1 MIX1"},
+	{"SLIM TX5 MUX", "RMIX2", "RX2 MIX1"},
+	{"SLIM TX5 MUX", "RMIX3", "RX3 MIX1"},
+
+	/* Earpiece (RX MIX1) */
+	{"EAR", NULL, "EAR PA"},
+	{"EAR PA", NULL, "EAR_PA_MIXER"},
+	{"EAR_PA_MIXER", NULL, "DAC1"},
+	{"DAC1", NULL, "RX_BIAS"},
+	{"DAC1", NULL, "CDC_CP_VDD"},
+
+
+	/* Headset (RX MIX1 and RX MIX2) */
+	{"HEADPHONE", NULL, "HPHL"},
+	{"HEADPHONE", NULL, "HPHR"},
+
+	{"HPHL", NULL, "HPHL_PA_MIXER"},
+	{"HPHL_PA_MIXER", NULL, "HPHL DAC"},
+	{"HPHL DAC", NULL, "RX_BIAS"},
+	{"HPHL DAC", NULL, "CDC_CP_VDD"},
+
+	{"HPHR", NULL, "HPHR_PA_MIXER"},
+	{"HPHR_PA_MIXER", NULL, "HPHR DAC"},
+	{"HPHR DAC", NULL, "RX_BIAS"},
+	{"HPHR DAC", NULL, "CDC_CP_VDD"},
+
+
 	{"DAC1", "Switch", "CLASS_H_DSM MUX"},
 	{"HPHL DAC", "Switch", "CLASS_H_DSM MUX"},
 	{"HPHR DAC", NULL, "RX2 CHAIN"},
@@ -2618,34 +2752,28 @@
 
 	{"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
 	{"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
-
 	{"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
 	{"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
 
 	{"LINEOUT1 DAC", NULL, "RX3 MIX1"},
 
 	{"RDAC5 MUX", "DEM3_INV", "RX3 MIX1"},
-	{"RDAC5 MUX", "DEM4", "RX4 MIX2"},
-
 	{"LINEOUT2 DAC", NULL, "RDAC5 MUX"},
 
 	{"SPK PA", NULL, "SPK DAC"},
-	{"SPK DAC", "Switch", "RX4 MIX2"},
 	{"SPK DAC", NULL, "VDD_SPKDRV"},
 
 	{"RX1 CHAIN", NULL, "RX1 MIX2"},
 	{"RX2 CHAIN", NULL, "RX2 MIX2"},
 	{"CLASS_H_DSM MUX", "RX_HPHL", "RX1 CHAIN"},
-	{"RX1 MIX2", NULL, "ANC1 MUX"},
-	{"RX2 MIX2", NULL, "ANC2 MUX"},
 
 	{"LINEOUT1 DAC", NULL, "RX_BIAS"},
 	{"LINEOUT2 DAC", NULL, "RX_BIAS"},
+	{"LINEOUT1 DAC", NULL, "CDC_CP_VDD"},
+	{"LINEOUT2 DAC", NULL, "CDC_CP_VDD"},
 
-	{"RX1 MIX1", NULL, "COMP1_CLK"},
-	{"RX2 MIX1", NULL, "COMP1_CLK"},
-	{"RX3 MIX1", NULL, "COMP2_CLK"},
-	{"RX4 MIX1", NULL, "COMP0_CLK"},
+	{"RDAC3 MUX", "DEM2", "RX2 MIX1"},
+	{"RDAC3 MUX", "DEM1", "RX1 CHAIN"},
 
 	{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
 	{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
@@ -2654,17 +2782,12 @@
 	{"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
 	{"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
 	{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
-	{"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
-	{"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
 	{"RX1 MIX2", NULL, "RX1 MIX1"},
 	{"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
 	{"RX1 MIX2", NULL, "RX1 MIX2 INP2"},
 	{"RX2 MIX2", NULL, "RX2 MIX1"},
 	{"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
 	{"RX2 MIX2", NULL, "RX2 MIX2 INP2"},
-	{"RX4 MIX2", NULL, "RX4 MIX1"},
-	{"RX4 MIX2", NULL, "RX4 MIX2 INP1"},
-	{"RX4 MIX2", NULL, "RX4 MIX2 INP2"},
 
 	/* SLIM_MUX("AIF1_PB", "AIF1 PB"),*/
 	{"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
@@ -2732,25 +2855,11 @@
 	{"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
 	{"RX3 MIX1 INP2", "RX5", "SLIM RX5"},
 	{"RX3 MIX1 INP2", "IIR1", "IIR1"},
-	{"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
-	{"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
-	{"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
-	{"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
-	{"RX4 MIX1 INP1", "RX5", "SLIM RX5"},
-	{"RX4 MIX1 INP1", "IIR1", "IIR1"},
-	{"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
-	{"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
-	{"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
-	{"RX4 MIX1 INP2", "RX5", "SLIM RX5"},
-	{"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
-	{"RX4 MIX1 INP2", "IIR1", "IIR1"},
 
 	{"RX1 MIX2 INP1", "IIR1", "IIR1"},
 	{"RX1 MIX2 INP2", "IIR1", "IIR1"},
 	{"RX2 MIX2 INP1", "IIR1", "IIR1"},
 	{"RX2 MIX2 INP2", "IIR1", "IIR1"},
-	{"RX4 MIX2 INP1", "IIR1", "IIR1"},
-	{"RX4 MIX2 INP2", "IIR1", "IIR1"},
 
 	/* Decimator Inputs */
 	{"DEC1 MUX", "ADC1", "ADC1"},
@@ -2759,8 +2868,6 @@
 	{"DEC1 MUX", "ADC4", "ADC4"},
 	{"DEC1 MUX", "DMIC1", "DMIC1"},
 	{"DEC1 MUX", "DMIC2", "DMIC2"},
-	{"DEC1 MUX", "DMIC3", "DMIC3"},
-	{"DEC1 MUX", "DMIC4", "DMIC4"},
 	{"DEC1 MUX", NULL, "CDC_CONN"},
 
 	{"DEC2 MUX", "ADC1", "ADC1"},
@@ -2769,38 +2876,13 @@
 	{"DEC2 MUX", "ADC4", "ADC4"},
 	{"DEC2 MUX", "DMIC1", "DMIC1"},
 	{"DEC2 MUX", "DMIC2", "DMIC2"},
-	{"DEC2 MUX", "DMIC3", "DMIC3"},
-	{"DEC2 MUX", "DMIC4", "DMIC4"},
 	{"DEC2 MUX", NULL, "CDC_CONN"},
 
-	{"DEC3 MUX", "ADC1", "ADC1"},
-	{"DEC3 MUX", "ADC2", "ADC2"},
-	{"DEC3 MUX", "ADC3", "ADC3"},
-	{"DEC3 MUX", "ADC4", "ADC4"},
-	{"DEC3 MUX", "ADC5", "ADC5"},
-	{"DEC3 MUX", "DMIC1", "DMIC1"},
-	{"DEC3 MUX", "DMIC2", "DMIC2"},
-	{"DEC3 MUX", "DMIC3", "DMIC3"},
-	{"DEC3 MUX", "DMIC4", "DMIC4"},
-	{"DEC3 MUX", NULL, "CDC_CONN"},
-
-	{"DEC4 MUX", "ADC1", "ADC1"},
-	{"DEC4 MUX", "ADC2", "ADC2"},
-	{"DEC4 MUX", "ADC3", "ADC3"},
-	{"DEC4 MUX", "ADC4", "ADC4"},
-	{"DEC4 MUX", "ADC5", "ADC5"},
-	{"DEC4 MUX", "DMIC1", "DMIC1"},
-	{"DEC4 MUX", "DMIC2", "DMIC2"},
-	{"DEC4 MUX", "DMIC3", "DMIC3"},
-	{"DEC4 MUX", "DMIC4", "DMIC4"},
-	{"DEC4 MUX", NULL, "CDC_CONN"},
-
 	/* ADC Connections */
 	{"ADC1", NULL, "AMIC1"},
 	{"ADC2", NULL, "AMIC2"},
 	{"ADC3", NULL, "AMIC3"},
 	{"ADC4", NULL, "AMIC4"},
-	{"ADC5", NULL, "AMIC5"},
 
 	/* AUX PGA Connections */
 	{"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
@@ -2808,13 +2890,10 @@
 	{"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
 	{"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
 	{"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
-	{"AUX_PGA_Left", NULL, "AMIC5"},
 
 	{"IIR1", NULL, "IIR1 INP1 MUX"},
 	{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
 	{"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
-	{"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
-	{"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
 
 	{"MIC BIAS1 Internal1", NULL, "LDO_H"},
 	{"MIC BIAS1 Internal2", NULL, "LDO_H"},
@@ -2823,9 +2902,17 @@
 	{"MIC BIAS2 Internal2", NULL, "LDO_H"},
 	{"MIC BIAS2 Internal3", NULL, "LDO_H"},
 	{"MIC BIAS2 External", NULL, "LDO_H"},
-	{"MIC BIAS3 Internal1", NULL, "LDO_H"},
-	{"MIC BIAS3 Internal2", NULL, "LDO_H"},
-	{"MIC BIAS3 External", NULL, "LDO_H"},
+};
+
+static const struct snd_soc_dapm_route wcd9302_map[] = {
+	{"SPK DAC", "Switch", "RX3 MIX1"},
+
+	{"RDAC4 MUX", "DEM3", "RX3 MIX1"},
+	{"RDAC4 MUX", "DEM2", "RX2 CHAIN"},
+	{"LINEOUT1 DAC", NULL, "RDAC4 MUX"},
+
+	{"RDAC5 MUX", "DEM4", "RX3 MIX1"},
+	{"RDAC5 MUX", "DEM3_INV", "RDAC4 MUX"},
 };
 
 static int tapan_readable(struct snd_soc_codec *ssc, unsigned int reg)
@@ -2896,6 +2983,7 @@
 	unsigned int value)
 {
 	int ret;
+	struct wcd9xxx *wcd9xxx = codec->control_data;
 
 	if (reg == SND_SOC_NOPM)
 		return 0;
@@ -2909,13 +2997,14 @@
 				reg, ret);
 	}
 
-	return wcd9xxx_reg_write(codec->control_data, reg, value);
+	return wcd9xxx_reg_write(&wcd9xxx->core_res, reg, value);
 }
 static unsigned int tapan_read(struct snd_soc_codec *codec,
 				unsigned int reg)
 {
 	unsigned int val;
 	int ret;
+	struct wcd9xxx *wcd9xxx = codec->control_data;
 
 	if (reg == SND_SOC_NOPM)
 		return 0;
@@ -2932,7 +3021,7 @@
 				reg, ret);
 	}
 
-	val = wcd9xxx_reg_read(codec->control_data, reg);
+	val = wcd9xxx_reg_read(&wcd9xxx->core_res, reg);
 	return val;
 }
 
@@ -2964,6 +3053,28 @@
 	}
 }
 
+static void tapan_set_vdd_cx_current(struct snd_soc_codec *codec,
+			int current_uA)
+{
+	struct regulator *cx_regulator;
+	int ret;
+
+	cx_regulator  = tapan_codec_find_regulator(codec,
+				"cdc-vdd-cx");
+
+	if (!cx_regulator) {
+		dev_err(codec->dev, "%s: Regulator %s not defined\n",
+			__func__, "cdc-vdd-cx-supply");
+		return;
+	}
+
+	ret = regulator_set_optimum_mode(cx_regulator, current_uA);
+	if (ret < 0)
+		dev_err(codec->dev,
+			"%s: Failed to set vdd_cx current to %d\n",
+			__func__, current_uA);
+}
+
 int tapan_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
 {
 	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
@@ -2973,6 +3084,7 @@
 
 	WCD9XXX_BG_CLK_LOCK(&tapan->resmgr);
 	if (mclk_enable) {
+		tapan_set_vdd_cx_current(codec, TAPAN_VDD_CX_OPTIMAL_UA);
 		wcd9xxx_resmgr_get_bandgap(&tapan->resmgr,
 					   WCD9XXX_BANDGAP_AUDIO_MODE);
 		wcd9xxx_resmgr_get_clk_block(&tapan->resmgr, WCD9XXX_CLK_MCLK);
@@ -2981,6 +3093,8 @@
 		wcd9xxx_resmgr_put_clk_block(&tapan->resmgr, WCD9XXX_CLK_MCLK);
 		wcd9xxx_resmgr_put_bandgap(&tapan->resmgr,
 					   WCD9XXX_BANDGAP_AUDIO_MODE);
+		/* Set the vdd cx power rail sleep mode current */
+		tapan_set_vdd_cx_current(codec, TAPAN_VDD_CX_SLEEP_UA);
 	}
 	WCD9XXX_BG_CLK_UNLOCK(&tapan->resmgr);
 
@@ -3415,6 +3529,93 @@
 	.get_channel_map = tapan_get_channel_map,
 };
 
+static struct snd_soc_dai_driver tapan9302_dai[] = {
+	{
+		.name = "tapan9302_rx1",
+		.id = AIF1_PB,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.rates = WCD9302_RATES,
+			.formats = TAPAN_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tapan_dai_ops,
+	},
+	{
+		.name = "tapan9302_tx1",
+		.id = AIF1_CAP,
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.rates = WCD9302_RATES,
+			.formats = TAPAN_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &tapan_dai_ops,
+	},
+	{
+		.name = "tapan9302_rx2",
+		.id = AIF2_PB,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.rates = WCD9302_RATES,
+			.formats = TAPAN_FORMATS,
+			.rate_min = 8000,
+			.rate_max = 48000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tapan_dai_ops,
+	},
+	{
+		.name = "tapan9302_tx2",
+		.id = AIF2_CAP,
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.rates = WCD9302_RATES,
+			.formats = TAPAN_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &tapan_dai_ops,
+	},
+	{
+		.name = "tapan9302_tx3",
+		.id = AIF3_CAP,
+		.capture = {
+			.stream_name = "AIF3 Capture",
+			.rates = WCD9302_RATES,
+			.formats = TAPAN_FORMATS,
+			.rate_max = 48000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tapan_dai_ops,
+	},
+	{
+		.name = "tapan9302_rx3",
+		.id = AIF3_PB,
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.rates = WCD9302_RATES,
+			.formats = TAPAN_FORMATS,
+			.rate_min = 8000,
+			.rate_max = 48000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &tapan_dai_ops,
+	},
+};
+
 static struct snd_soc_dai_driver tapan_dai[] = {
 	{
 		.name = "tapan_rx1",
@@ -3766,11 +3967,147 @@
 	return ret;
 }
 
+static int tapan_codec_chargepump_vdd_event(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct tapan_priv *priv = snd_soc_codec_get_drvdata(codec);
+	int ret = 0, i;
+
+	pr_info("%s: event = %d\n", __func__, event);
+
+
+	if (!priv->cp_regulators[CP_REG_BUCK]
+			&& !priv->cp_regulators[CP_REG_BHELPER]) {
+		pr_err("%s: No power supply defined for ChargePump\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		for (i = 0; i < CP_REG_MAX ; i++) {
+			if (!priv->cp_regulators[i])
+				continue;
+
+			ret = regulator_enable(priv->cp_regulators[i]);
+			if (ret) {
+				pr_err("%s: CP Regulator enable failed, index = %d\n",
+						__func__, i);
+				continue;
+			} else {
+				pr_debug("%s: Enabled CP regulator, index %d\n",
+					__func__, i);
+			}
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		for (i = 0; i < CP_REG_MAX; i++) {
+			if (!priv->cp_regulators[i])
+				continue;
+
+			ret = regulator_disable(priv->cp_regulators[i]);
+			if (ret) {
+				pr_err("%s: CP Regulator disable failed, index = %d\n",
+						__func__, i);
+				return ret;
+			} else {
+				pr_debug("%s: Disabled CP regulator %d\n",
+						__func__, i);
+			}
+		}
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget tapan_9306_dapm_widgets[] = {
+	/* RX4 MIX1 mux inputs */
+	SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx4_mix1_inp1_mux),
+	SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx4_mix1_inp2_mux),
+	SND_SOC_DAPM_MUX("RX4 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+		&rx4_mix1_inp2_mux),
+
+	/* RX4 MIX2 mux inputs */
+	SND_SOC_DAPM_MUX("RX4 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+		&rx4_mix2_inp1_mux),
+	SND_SOC_DAPM_MUX("RX4 MIX2 INP2", SND_SOC_NOPM, 0, 0,
+		&rx4_mix2_inp2_mux),
+
+	SND_SOC_DAPM_MIXER("RX4 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER_E("RX4 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
+		0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_MUX_E("DEC3 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
+		&dec3_mux, tapan_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("DEC4 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
+		&dec4_mux, tapan_codec_enable_dec,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY("COMP0_CLK", SND_SOC_NOPM, 0, 0,
+		tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 1, 0,
+		tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 2, 0,
+		tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_INPUT("AMIC5"),
+	SND_SOC_DAPM_ADC_E("ADC5", NULL, TAPAN_A_TX_5_EN, 7, 0,
+		tapan_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
+
+	SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
+	SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
+
+	SND_SOC_DAPM_OUTPUT("ANC HEADPHONE"),
+	SND_SOC_DAPM_PGA_E("ANC HPHL", SND_SOC_NOPM, 5, 0, NULL, 0,
+		tapan_codec_enable_anc_hph,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_E("ANC HPHR", SND_SOC_NOPM, 4, 0, NULL, 0,
+		tapan_codec_enable_anc_hph, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_OUTPUT("ANC EAR"),
+	SND_SOC_DAPM_PGA_E("ANC EAR PA", SND_SOC_NOPM, 0, 0, NULL, 0,
+		tapan_codec_enable_anc_ear,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
+
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TAPAN_A_MICB_3_CTL, 7, 0,
+		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TAPAN_A_MICB_3_CTL, 7, 0,
+		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TAPAN_A_MICB_3_CTL, 7, 0,
+		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
+		tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
+		tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+};
 
 /* Todo: Have seperate dapm widgets for I2S and Slimbus.
  * Might Need to have callbacks registered only for slimbus
  */
-static const struct snd_soc_dapm_widget tapan_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget tapan_common_dapm_widgets[] = {
 
 	SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
 				AIF1_PB, 0, tapan_codec_enable_slimrx,
@@ -3824,14 +4161,6 @@
 	SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
 		&rx3_mix1_inp2_mux),
 
-	/* RX4 MIX1 mux inputs */
-	SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-		&rx4_mix1_inp1_mux),
-	SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-		&rx4_mix1_inp2_mux),
-	SND_SOC_DAPM_MUX("RX4 MIX1 INP3", SND_SOC_NOPM, 0, 0,
-		&rx4_mix1_inp2_mux),
-
 	/* RX1 MIX2 mux inputs */
 	SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
 		&rx1_mix2_inp1_mux),
@@ -3844,16 +4173,8 @@
 	SND_SOC_DAPM_MUX("RX2 MIX2 INP2", SND_SOC_NOPM, 0, 0,
 		&rx2_mix2_inp2_mux),
 
-	/* RX4 MIX2 mux inputs */
-	SND_SOC_DAPM_MUX("RX4 MIX2 INP1", SND_SOC_NOPM, 0, 0,
-		&rx4_mix2_inp1_mux),
-	SND_SOC_DAPM_MUX("RX4 MIX2 INP2", SND_SOC_NOPM, 0, 0,
-		&rx4_mix2_inp2_mux),
-
-
 	SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("RX4 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
 
 	SND_SOC_DAPM_MIXER_E("RX1 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
 		0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
@@ -3864,9 +4185,6 @@
 	SND_SOC_DAPM_MIXER_E("RX3 MIX1", TAPAN_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
 		0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_MIXER_E("RX4 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
-		0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU),
 
 	SND_SOC_DAPM_MIXER("RX1 CHAIN", TAPAN_A_CDC_RX1_B6_CTL, 5, 0,
 						NULL, 0),
@@ -3882,6 +4200,11 @@
 		tapan_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMD),
 
+	/* CDC_CP_VDD */
+	SND_SOC_DAPM_SUPPLY("CDC_CP_VDD", SND_SOC_NOPM, 0, 0,
+		tapan_codec_chargepump_vdd_event, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
 	/*EAR */
 	SND_SOC_DAPM_PGA_E("EAR PA", TAPAN_A_RX_EAR_EN, 4, 0, NULL, 0,
 			tapan_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU |
@@ -3922,6 +4245,13 @@
 	SND_SOC_DAPM_MUX("RDAC5 MUX", SND_SOC_NOPM, 0, 0,
 		&rx_dac5_mux),
 
+	/* LINEOUT1*/
+	SND_SOC_DAPM_MUX("RDAC4 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_dac4_mux),
+
+	SND_SOC_DAPM_MUX("RDAC3 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_dac3_mux),
+
 	SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TAPAN_A_RX_LINE_2_DAC_CTL, 7, 0
 		, tapan_lineout_dac_event,
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
@@ -3984,29 +4314,9 @@
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
 		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_MUX_E("DEC3 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
-		&dec3_mux, tapan_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_MUX_E("DEC4 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
-		&dec4_mux, tapan_codec_enable_dec,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
 	SND_SOC_DAPM_SUPPLY("LDO_H", TAPAN_A_LDO_H_MODE_1, 7, 0,
 		tapan_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
 
-	SND_SOC_DAPM_SUPPLY("COMP0_CLK", SND_SOC_NOPM, 0, 0,
-		tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_PRE_PMD),
-	SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 1, 0,
-		tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_PRE_PMD),
-	SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 2, 0,
-		tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_PRE_PMD),
-
 	SND_SOC_DAPM_INPUT("AMIC1"),
 	SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TAPAN_A_MICB_1_CTL, 7, 0,
 		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
@@ -4035,29 +4345,6 @@
 		tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_INPUT("AMIC5"),
-	SND_SOC_DAPM_ADC_E("ADC5", NULL, TAPAN_A_TX_5_EN, 7, 0,
-		tapan_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
-	SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
-
-	SND_SOC_DAPM_OUTPUT("ANC HEADPHONE"),
-	SND_SOC_DAPM_PGA_E("ANC HPHL", SND_SOC_NOPM, 5, 0, NULL, 0,
-		tapan_codec_enable_anc_hph,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
-		SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_PGA_E("ANC HPHR", SND_SOC_NOPM, 4, 0, NULL, 0,
-		tapan_codec_enable_anc_hph, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
-		SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_OUTPUT("ANC EAR"),
-	SND_SOC_DAPM_PGA_E("ANC EAR PA", SND_SOC_NOPM, 0, 0, NULL, 0,
-		tapan_codec_enable_anc_ear,
-		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
-
 	SND_SOC_DAPM_INPUT("AMIC2"),
 	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TAPAN_A_MICB_2_CTL, 7, 0,
 		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
@@ -4071,15 +4358,6 @@
 	SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TAPAN_A_MICB_2_CTL, 7, 0,
 		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TAPAN_A_MICB_3_CTL, 7, 0,
-		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TAPAN_A_MICB_3_CTL, 7, 0,
-		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TAPAN_A_MICB_3_CTL, 7, 0,
-		tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
 		AIF1_CAP, 0, tapan_codec_enable_slimtx,
@@ -4102,14 +4380,6 @@
 		tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
-		tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
-		tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
-
 	/* Sidetone */
 	SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
 	SND_SOC_DAPM_PGA("IIR1", TAPAN_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
@@ -4553,8 +4823,10 @@
 {
 	int ret = 0;
 	struct snd_soc_codec *codec = tapan->codec;
+	struct wcd9xxx *wcd9xxx = codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res;
 
-	ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS,
 				  tapan_slimbus_irq, "SLIMBUS Slave", tapan);
 	if (ret)
 		pr_err("%s: Failed to request irq %d\n", __func__,
@@ -4568,7 +4840,9 @@
 static void tapan_cleanup_irqs(struct tapan_priv *tapan)
 {
 	struct snd_soc_codec *codec = tapan->codec;
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, tapan);
+	struct wcd9xxx *wcd9xxx = codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res;
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, tapan);
 }
 
 
@@ -4612,6 +4886,8 @@
 
 	cfilt_mode.cur_mode_val =
 		snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x30;
+	cfilt_mode.reg_mask = 0x30;
+
 	return cfilt_mode;
 }
 
@@ -4623,8 +4899,15 @@
 
 static void tapan_free_irq(struct wcd9xxx_mbhc *mbhc)
 {
-	void *cdata = mbhc->codec->control_data;
-	wcd9xxx_free_irq(cdata, WCD9306_IRQ_MBHC_JACK_SWITCH, mbhc);
+	struct wcd9xxx *wcd9xxx = mbhc->codec->control_data;
+	struct wcd9xxx_core_resource *core_res =
+			&wcd9xxx->core_res;
+	wcd9xxx_free_irq(core_res, WCD9306_IRQ_MBHC_JACK_SWITCH, mbhc);
+}
+
+enum wcd9xxx_cdc_type tapan_get_cdc_type(void)
+{
+	return WCD9XXX_CDC_TYPE_TAPAN;
 }
 
 static const struct wcd9xxx_mbhc_cb mbhc_cb = {
@@ -4635,6 +4918,7 @@
 	.switch_cfilt_mode = tapan_codec_switch_cfilt_mode,
 	.select_cfilt = tapan_select_cfilt,
 	.free_irq = tapan_free_irq,
+	.get_cdc_type = tapan_get_cdc_type,
 };
 
 int tapan_hs_detect(struct snd_soc_codec *codec,
@@ -4643,7 +4927,24 @@
 	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
 	return wcd9xxx_mbhc_start(&tapan->mbhc, mbhc_cfg);
 }
-EXPORT_SYMBOL_GPL(tapan_hs_detect);
+EXPORT_SYMBOL(tapan_hs_detect);
+
+void tapan_hs_detect_exit(struct snd_soc_codec *codec)
+{
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+	wcd9xxx_mbhc_stop(&tapan->mbhc);
+}
+EXPORT_SYMBOL(tapan_hs_detect_exit);
+
+static int tapan_device_down(struct wcd9xxx *wcd9xxx)
+{
+	struct snd_soc_codec *codec;
+
+	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
+	snd_soc_card_change_online_state(codec->card, 0);
+
+	return 0;
+}
 
 static int tapan_post_reset_cb(struct wcd9xxx *wcd9xxx)
 {
@@ -4654,8 +4955,10 @@
 
 	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
 	tapan = snd_soc_codec_get_drvdata(codec);
-	mutex_lock(&codec->mutex);
 
+	snd_soc_card_change_online_state(codec->card, 1);
+
+	mutex_lock(&codec->mutex);
 	if (codec->reg_def_copy) {
 		pr_debug("%s: Update ASOC cache", __func__);
 		kfree(codec->reg_cache);
@@ -4695,6 +4998,12 @@
 		pr_err("%s: mbhc init failed %d\n", __func__, ret);
 	else
 		wcd9xxx_mbhc_start(&tapan->mbhc, tapan->mbhc.mbhc_cfg);
+
+	tapan_cleanup_irqs(tapan);
+	ret = tapan_setup_irqs(tapan);
+	if (ret)
+		pr_err("%s: Failed to setup irq: %d\n", __func__, ret);
+
 	mutex_unlock(&codec->mutex);
 	return ret;
 }
@@ -4703,13 +5012,107 @@
 };
 
 static int wcd9xxx_ssr_register(struct wcd9xxx *control,
-		int (*post_reset_cb)(struct wcd9xxx *wcd9xxx), void *priv)
+				int (*device_down_cb)(struct wcd9xxx *wcd9xxx),
+				int (*device_up_cb)(struct wcd9xxx *wcd9xxx),
+				void *priv)
 {
-	control->post_reset = post_reset_cb;
+	control->dev_down = device_down_cb;
+	control->post_reset = device_up_cb;
 	control->ssr_priv = priv;
 	return 0;
 }
 
+static struct regulator *tapan_codec_find_regulator(
+	struct snd_soc_codec *codec,
+	const char *name)
+{
+	int i;
+	struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+
+	for (i = 0; i < core->num_of_supplies; i++) {
+		if (core->supplies[i].supply &&
+			!strcmp(core->supplies[i].supply, name))
+				return core->supplies[i].consumer;
+	}
+	return NULL;
+}
+
+static void tapan_enable_config_rco(struct wcd9xxx *core, bool enable)
+{
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
+
+	if (enable) {
+		/* Enable RC Oscillator */
+		wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_FREQ, 0x10, 0x00);
+		wcd9xxx_reg_write(core_res, WCD9XXX_A_BIAS_OSC_BG_CTL, 0x17);
+		usleep_range(5, 5);
+		wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_FREQ, 0x80, 0x80);
+		wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_TEST, 0x80, 0x80);
+		usleep_range(10, 10);
+		wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_TEST, 0x80, 0x00);
+		usleep_range(20, 20);
+		wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN1, 0x08, 0x08);
+		/* Enable MCLK and wait 1ms till it gets enabled */
+		wcd9xxx_reg_write(core_res, WCD9XXX_A_CLK_BUFF_EN2, 0x02);
+		usleep_range(1000, 1000);
+		/* Enable CLK BUFF and wait for 1.2ms */
+		wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN1, 0x01, 0x01);
+		usleep_range(1000, 1200);
+
+		wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x00);
+		wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x04);
+		wcd9xxx_reg_update(core, WCD9XXX_A_CDC_CLK_MCLK_CTL,
+				   0x01, 0x01);
+		usleep_range(50, 50);
+	} else {
+		wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x00);
+		usleep_range(50, 50);
+		wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x02);
+		wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x00);
+		usleep_range(50, 50);
+	}
+
+}
+
+static bool tapan_check_wcd9306(struct device *cdc_dev, bool sensed)
+{
+	struct wcd9xxx *core = dev_get_drvdata(cdc_dev->parent);
+	u8 reg_val;
+	bool ret = true;
+	unsigned long timeout;
+	bool timedout;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
+
+	if (!core) {
+		dev_err(cdc_dev, "%s: core not initialized\n", __func__);
+		return -EINVAL;
+	}
+
+	tapan_enable_config_rco(core, 1);
+
+	if (sensed == false) {
+		reg_val = wcd9xxx_reg_read(core_res, TAPAN_A_QFUSE_CTL);
+		wcd9xxx_reg_write(core_res, TAPAN_A_QFUSE_CTL,
+					(reg_val | 0x03));
+	}
+
+	timeout = jiffies + HZ;
+	do {
+		if ((wcd9xxx_reg_read(core_res, TAPAN_A_QFUSE_STATUS)))
+			break;
+	} while (!(timedout = time_after(jiffies, timeout)));
+
+	if (wcd9xxx_reg_read(core_res, TAPAN_A_QFUSE_DATA_OUT1) ||
+	    wcd9xxx_reg_read(core_res, TAPAN_A_QFUSE_DATA_OUT2)) {
+		dev_info(cdc_dev, "%s: wcd9302 detected\n", __func__);
+		ret = false;
+	} else
+		dev_info(cdc_dev, "%s: wcd9306 detected\n", __func__);
+
+	tapan_enable_config_rco(core, 0);
+	return ret;
+};
+
 static int tapan_codec_probe(struct snd_soc_codec *codec)
 {
 	struct wcd9xxx *control;
@@ -4720,11 +5123,13 @@
 	int ret = 0;
 	int i, rco_clk_rate;
 	void *ptr = NULL;
+	struct wcd9xxx_core_resource *core_res;
 
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
 	control = codec->control_data;
 
-	wcd9xxx_ssr_register(control, tapan_post_reset_cb, (void *)codec);
+	wcd9xxx_ssr_register(control, tapan_device_down,
+			     tapan_post_reset_cb, (void *)codec);
 
 	dev_info(codec->dev, "%s()\n", __func__);
 
@@ -4744,14 +5149,20 @@
 
 	/* codec resmgr module init */
 	wcd9xxx = codec->control_data;
+	core_res = &wcd9xxx->core_res;
 	pdata = dev_get_platdata(codec->dev->parent);
-	ret = wcd9xxx_resmgr_init(&tapan->resmgr, codec, wcd9xxx, pdata,
-				  &tapan_reg_address);
+	ret = wcd9xxx_resmgr_init(&tapan->resmgr, codec, core_res, pdata,
+				  &tapan_reg_address, WCD9XXX_CDC_TYPE_TAPAN);
 	if (ret) {
 		pr_err("%s: wcd9xxx init failed %d\n", __func__, ret);
 		return ret;
 	}
 
+	tapan->cp_regulators[CP_REG_BUCK] = tapan_codec_find_regulator(codec,
+					WCD9XXX_SUPPLY_BUCK_NAME);
+	tapan->cp_regulators[CP_REG_BHELPER] = tapan_codec_find_regulator(codec,
+					"cdc-vdd-buckhelper");
+
 	tapan->clsh_d.buck_mv = tapan_codec_get_buck_mv(codec);
 	/*
 	 * If 1.8 volts is requested on the vdd_cp line, then
@@ -4822,6 +5233,18 @@
 		}
 	}
 
+	if (tapan_check_wcd9306(codec->dev, false) == true) {
+		snd_soc_add_codec_controls(codec, tapan_9306_snd_controls,
+					   ARRAY_SIZE(tapan_9306_snd_controls));
+		snd_soc_dapm_new_controls(dapm, tapan_9306_dapm_widgets,
+					  ARRAY_SIZE(tapan_9306_dapm_widgets));
+		snd_soc_dapm_add_routes(dapm, wcd9306_map,
+					ARRAY_SIZE(wcd9306_map));
+	} else {
+		snd_soc_dapm_add_routes(dapm, wcd9302_map,
+					ARRAY_SIZE(wcd9302_map));
+	}
+
 	control->num_rx_port = TAPAN_RX_MAX;
 	control->rx_chs = ptr;
 	memcpy(control->rx_chs, tapan_rx_chs, sizeof(tapan_rx_chs));
@@ -4860,6 +5283,7 @@
 static int tapan_codec_remove(struct snd_soc_codec *codec)
 {
 	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+	int index = 0;
 
 	WCD9XXX_BG_CLK_LOCK(&tapan->resmgr);
 	atomic_set(&kp_tapan_priv, 0);
@@ -4876,6 +5300,9 @@
 	/* cleanup resmgr */
 	wcd9xxx_resmgr_deinit(&tapan->resmgr);
 
+	for (index = 0; index < CP_REG_MAX; index++)
+		tapan->cp_regulators[index] = NULL;
+
 	kfree(tapan);
 	return 0;
 }
@@ -4894,10 +5321,10 @@
 	.reg_cache_default = tapan_reset_reg_defaults,
 	.reg_word_size = 1,
 
-	.controls = tapan_snd_controls,
-	.num_controls = ARRAY_SIZE(tapan_snd_controls),
-	.dapm_widgets = tapan_dapm_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(tapan_dapm_widgets),
+	.controls = tapan_common_snd_controls,
+	.num_controls = ARRAY_SIZE(tapan_common_snd_controls),
+	.dapm_widgets = tapan_common_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tapan_common_dapm_widgets),
 	.dapm_routes = audio_map,
 	.num_dapm_routes = ARRAY_SIZE(audio_map),
 };
@@ -4928,12 +5355,35 @@
 static int __devinit tapan_probe(struct platform_device *pdev)
 {
 	int ret = 0;
-	if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
-		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tapan,
-			tapan_dai, ARRAY_SIZE(tapan_dai));
-	else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
-		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tapan,
-			tapan_i2s_dai, ARRAY_SIZE(tapan_i2s_dai));
+	bool is_wcd9306;
+
+	is_wcd9306 = tapan_check_wcd9306(&pdev->dev, false);
+	if (is_wcd9306 < 0) {
+		dev_info(&pdev->dev, "%s: cannot find codec type, default to 9306\n",
+			 __func__);
+		is_wcd9306 = true;
+	}
+
+	if (!is_wcd9306) {
+		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+			ret = snd_soc_register_codec(&pdev->dev,
+				&soc_codec_dev_tapan,
+				tapan9302_dai, ARRAY_SIZE(tapan9302_dai));
+		else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+			ret = snd_soc_register_codec(&pdev->dev,
+				&soc_codec_dev_tapan,
+				tapan_i2s_dai, ARRAY_SIZE(tapan_i2s_dai));
+	} else {
+		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+			ret = snd_soc_register_codec(&pdev->dev,
+				&soc_codec_dev_tapan,
+				tapan_dai, ARRAY_SIZE(tapan_dai));
+		else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+			ret = snd_soc_register_codec(&pdev->dev,
+				&soc_codec_dev_tapan,
+				tapan_i2s_dai, ARRAY_SIZE(tapan_i2s_dai));
+	}
+
 	return ret;
 }
 static int __devexit tapan_remove(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 212924fd..673b634 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -5949,11 +5949,12 @@
 {
 	int r = 0;
 	struct wcd9xxx *core = dev_get_drvdata(tabla->codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 
 	if (cancel_delayed_work_sync(&tabla->mbhc_btn_dwork)) {
 		/* if scheduled mbhc_btn_dwork is canceled from here,
 		* we have to unlock from here instead btn_work */
-		wcd9xxx_unlock_sleep(core);
+		wcd9xxx_unlock_sleep(core_res);
 		r = 1;
 	}
 	return r;
@@ -6332,12 +6333,14 @@
 	short bias_value;
 	int dce_mv, sta_mv;
 	struct wcd9xxx *core;
+	struct wcd9xxx_core_resource *core_res;
 
 	pr_debug("%s:\n", __func__);
 
 	delayed_work = to_delayed_work(work);
 	tabla = container_of(delayed_work, struct tabla_priv, mbhc_btn_dwork);
 	core = dev_get_drvdata(tabla->codec->dev->parent);
+	core_res = &core->core_res;
 
 	if (tabla) {
 		if (tabla->mbhc_cfg.button_jack) {
@@ -6360,7 +6363,7 @@
 	}
 
 	pr_debug("%s: leave\n", __func__);
-	wcd9xxx_unlock_sleep(core);
+	wcd9xxx_unlock_sleep(core_res);
 }
 
 static u16 tabla_get_cfilt_reg(struct snd_soc_codec *codec, u8 cfilt)
@@ -6816,6 +6819,7 @@
 	short btnmeas[d->n_btn_meas + 1];
 	struct snd_soc_codec *codec = priv->codec;
 	struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 	int n_btn_meas = d->n_btn_meas;
 	u8 mbhc_status = snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_STATUS) & 0x3E;
 
@@ -6917,12 +6921,12 @@
 		tabla_mbhc_set_rel_thres(codec, btn_high[btn]);
 		mask = tabla_get_button_mask(btn);
 		priv->buttons_pressed |= mask;
-		wcd9xxx_lock_sleep(core);
+		wcd9xxx_lock_sleep(core_res);
 		if (schedule_delayed_work(&priv->mbhc_btn_dwork,
 					  msecs_to_jiffies(400)) == 0) {
 			WARN(1, "Button pressed twice without release"
 			     "event\n");
-			wcd9xxx_unlock_sleep(core);
+			wcd9xxx_unlock_sleep(core_res);
 		}
 	} else {
 		pr_debug("%s: bogus button press, too short press?\n",
@@ -7248,9 +7252,11 @@
 static void tabla_schedule_hs_detect_plug(struct tabla_priv *tabla,
 	struct work_struct *correct_plug_work)
 {
+	struct wcd9xxx *core = tabla->codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 	pr_debug("%s: scheduling tabla_hs_correct_gpio_plug\n", __func__);
 	tabla->hs_detect_work_stop = false;
-	wcd9xxx_lock_sleep(tabla->codec->control_data);
+	wcd9xxx_lock_sleep(core_res);
 	schedule_work(correct_plug_work);
 }
 
@@ -7258,13 +7264,15 @@
 static void tabla_cancel_hs_detect_plug(struct tabla_priv *tabla,
 		struct work_struct *correct_plug_work)
 {
+	struct wcd9xxx *core = tabla->codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 	pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
 	tabla->hs_detect_work_stop = true;
 	wmb();
 	TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
 	if (cancel_work_sync(correct_plug_work)) {
 		pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
-		wcd9xxx_unlock_sleep(tabla->codec->control_data);
+		wcd9xxx_unlock_sleep(core_res);
 	}
 	TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
 }
@@ -7470,9 +7478,13 @@
 	bool correction = false;
 	enum tabla_mbhc_plug_type plug_type = PLUG_TYPE_INVALID;
 	unsigned long timeout;
+	struct wcd9xxx *core;
+	struct wcd9xxx_core_resource *core_res;
 
 	tabla = container_of(work, struct tabla_priv, hs_correct_plug_work);
 	codec = tabla->codec;
+	core = tabla->codec->control_data;
+	core_res = &core->core_res;
 
 	pr_debug("%s: enter\n", __func__);
 	tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
@@ -7581,7 +7593,7 @@
 	pr_debug("%s: leave current_plug(%d)\n",
 		 __func__, tabla->current_plug);
 	/* unlock sleep */
-	wcd9xxx_unlock_sleep(tabla->codec->control_data);
+	wcd9xxx_unlock_sleep(core_res);
 }
 
 /* called under codec_resource_lock acquisition */
@@ -7738,6 +7750,7 @@
 	int ret;
 	struct snd_soc_codec *codec = priv->codec;
 	struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 
 	/* Cancel possibly running hs_detect_work */
@@ -7766,12 +7779,12 @@
 	} else if (is_mb_trigger && !is_removal) {
 		pr_debug("%s: Waiting for Headphone left trigger\n",
 			__func__);
-		wcd9xxx_lock_sleep(core);
+		wcd9xxx_lock_sleep(core_res);
 		if (schedule_delayed_work(&priv->mbhc_insert_dwork,
 					  usecs_to_jiffies(1000000)) == 0) {
 			pr_err("%s: mbhc_insert_dwork is already scheduled\n",
 			       __func__);
-			wcd9xxx_unlock_sleep(core);
+			wcd9xxx_unlock_sleep(core_res);
 		}
 		tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_HPHL_TRIGGER,
 					     false);
@@ -7781,7 +7794,7 @@
 			pr_debug("%s: Complete plug insertion, Detecting plug "
 				 "type\n", __func__);
 			tabla_codec_detect_plug_type(codec);
-			wcd9xxx_unlock_sleep(core);
+			wcd9xxx_unlock_sleep(core_res);
 		} else {
 			wcd9xxx_enable_irq(codec->control_data,
 					   WCD9XXX_IRQ_MBHC_INSERTION);
@@ -8058,11 +8071,13 @@
 	struct tabla_priv *tabla;
 	struct snd_soc_codec *codec;
 	struct wcd9xxx *tabla_core;
+	struct wcd9xxx_core_resource *core_res;
 
 	dwork = to_delayed_work(work);
 	tabla = container_of(dwork, struct tabla_priv, mbhc_insert_dwork);
 	codec = tabla->codec;
 	tabla_core = dev_get_drvdata(codec->dev->parent);
+	core_res = &tabla_core->core_res;
 
 	pr_debug("%s:\n", __func__);
 
@@ -8073,7 +8088,7 @@
 	wcd9xxx_disable_irq_sync(codec->control_data,
 				 WCD9XXX_IRQ_MBHC_INSERTION);
 	tabla_codec_detect_plug_type(codec);
-	wcd9xxx_unlock_sleep(tabla_core);
+	wcd9xxx_unlock_sleep(core_res);
 }
 
 static void tabla_hs_gpio_handler(struct snd_soc_codec *codec)
@@ -8090,7 +8105,7 @@
 	usleep_range(TABLA_GPIO_IRQ_DEBOUNCE_TIME_US,
 		     TABLA_GPIO_IRQ_DEBOUNCE_TIME_US);
 
-	wcd9xxx_nested_irq_lock(core);
+	wcd9xxx_nested_irq_lock(&core->core_res);
 	TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
 
 	/* cancel pending button press */
@@ -8163,7 +8178,7 @@
 
 	tabla->in_gpio_handler = false;
 	TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
-	wcd9xxx_nested_irq_unlock(core);
+	wcd9xxx_nested_irq_unlock(&core->core_res);
 	pr_debug("%s: leave\n", __func__);
 }
 
@@ -8172,8 +8187,10 @@
 	int r = IRQ_HANDLED;
 	struct snd_soc_codec *codec = data;
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx *core = codec->control_data;
+	struct wcd9xxx_core_resource *core_res = &core->core_res;
 
-	if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
+	if (unlikely(wcd9xxx_lock_sleep(core_res) == false)) {
 		pr_warn("%s: failed to hold suspend\n", __func__);
 		/*
 		 * Give up this IRQ for now and resend this IRQ so IRQ can be
@@ -8186,7 +8203,7 @@
 		r = IRQ_NONE;
 	} else {
 		tabla_hs_gpio_handler(codec);
-		wcd9xxx_unlock_sleep(codec->control_data);
+		wcd9xxx_unlock_sleep(core_res);
 	}
 
 	return r;
@@ -8200,6 +8217,8 @@
 	int retry = 0;
 	enum tabla_mbhc_plug_type plug_type;
 	bool is_headset = false;
+	struct wcd9xxx *core;
+	struct wcd9xxx_core_resource *core_res;
 
 	pr_debug("%s(): Poll Microphone voltage for %d seconds\n",
 			 __func__, TABLA_HS_DETECT_PLUG_TIME_MS / 1000);
@@ -8207,6 +8226,8 @@
 	tabla = container_of(work, struct tabla_priv,
 						 hs_correct_plug_work_nogpio);
 	codec = tabla->codec;
+	core = codec->control_data;
+	core_res = &core->core_res;
 
 	/* Make sure the MBHC mux is connected to MIC Path */
 	snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
@@ -8261,7 +8282,7 @@
 		tabla_codec_cleanup_hs_polling(codec);
 		tabla_codec_enable_hs_detect(codec, 0, 0, false);
 	}
-	wcd9xxx_unlock_sleep(codec->control_data);
+	wcd9xxx_unlock_sleep(core_res);
 }
 
 static int tabla_mbhc_init_and_calibrate(struct tabla_priv *tabla)
@@ -8933,9 +8954,11 @@
 	int ret = 0;
 	int i;
 	void *ptr = NULL;
+	struct wcd9xxx_core_resource *core_res;
 
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
 	control = codec->control_data;
+	core_res = &control->core_res;
 
 	tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
 	if (!tabla) {
@@ -9049,7 +9072,7 @@
 
 	snd_soc_dapm_sync(dapm);
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_MBHC_INSERTION,
 		tabla_hs_insert_irq, "Headset insert detect", tabla);
 	if (ret) {
@@ -9057,9 +9080,9 @@
 		       WCD9XXX_IRQ_MBHC_INSERTION);
 		goto err_insert_irq;
 	}
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION);
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_MBHC_REMOVAL,
 				  tabla_hs_remove_irq,
 				  "Headset remove detect", tabla);
@@ -9069,7 +9092,7 @@
 		goto err_remove_irq;
 	}
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_MBHC_POTENTIAL,
 				  tabla_dce_handler, "DC Estimation detect",
 				  tabla);
@@ -9079,7 +9102,7 @@
 		goto err_potential_irq;
 	}
 
-	ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE,
 				  tabla_release_handler,
 				  "Button Release detect", tabla);
 	if (ret) {
@@ -9088,7 +9111,7 @@
 		goto err_release_irq;
 	}
 
-	ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS,
 				  tabla_slimbus_irq, "SLIMBUS Slave", tabla);
 	if (ret) {
 		pr_err("%s: Failed to request irq %d\n", __func__,
@@ -9097,10 +9120,10 @@
 	}
 
 	for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
-		wcd9xxx_interface_reg_write(codec->control_data,
-			TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
+		wcd9xxx_interface_reg_write(control,
+				TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
 				  tabla_hphl_ocp_irq,
 				  "HPH_L OCP detect", tabla);
@@ -9109,9 +9132,9 @@
 		       WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
 		goto err_hphl_ocp_irq;
 	}
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
 
-	ret = wcd9xxx_request_irq(codec->control_data,
+	ret = wcd9xxx_request_irq(core_res,
 				  WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
 				  tabla_hphr_ocp_irq,
 				  "HPH_R OCP detect", tabla);
@@ -9120,7 +9143,7 @@
 		       WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 		goto err_hphr_ocp_irq;
 	}
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 
 	/*
 	 * Register suspend lock and notifier to resend edge triggered
@@ -9151,19 +9174,19 @@
 	return ret;
 
 err_hphr_ocp_irq:
-	wcd9xxx_free_irq(codec->control_data,
+	wcd9xxx_free_irq(core_res,
 			WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, tabla);
 err_hphl_ocp_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, tabla);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, tabla);
 err_slimbus_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, tabla);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE, tabla);
 err_release_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL,
 			 tabla);
 err_potential_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, tabla);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL, tabla);
 err_remove_irq:
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION,
 			 tabla);
 err_insert_irq:
 err_pdata:
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index c27e085..3621879 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -4051,6 +4051,7 @@
 	unsigned int value)
 {
 	int ret;
+	struct wcd9xxx *wcd9xxx = codec->control_data;
 
 	if (reg == SND_SOC_NOPM)
 		return 0;
@@ -4064,7 +4065,7 @@
 				reg, ret);
 	}
 
-	return wcd9xxx_reg_write(codec->control_data, reg, value);
+	return wcd9xxx_reg_write(&wcd9xxx->core_res, reg, value);
 }
 static unsigned int taiko_read(struct snd_soc_codec *codec,
 				unsigned int reg)
@@ -4072,6 +4073,8 @@
 	unsigned int val;
 	int ret;
 
+	struct wcd9xxx *wcd9xxx = codec->control_data;
+
 	if (reg == SND_SOC_NOPM)
 		return 0;
 
@@ -4087,7 +4090,7 @@
 				reg, ret);
 	}
 
-	val = wcd9xxx_reg_read(codec->control_data, reg);
+	val = wcd9xxx_reg_read(&wcd9xxx->core_res, reg);
 	return val;
 }
 
@@ -6151,8 +6154,11 @@
 {
 	int ret = 0;
 	struct snd_soc_codec *codec = taiko->codec;
+	struct wcd9xxx *wcd9xxx = codec->control_data;
+	struct wcd9xxx_core_resource *core_res =
+				&wcd9xxx->core_res;
 
-	ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS,
 				  taiko_slimbus_irq, "SLIMBUS Slave", taiko);
 	if (ret)
 		pr_err("%s: Failed to request irq %d\n", __func__,
@@ -6166,8 +6172,11 @@
 static void taiko_cleanup_irqs(struct taiko_priv *taiko)
 {
 	struct snd_soc_codec *codec = taiko->codec;
+	struct wcd9xxx *wcd9xxx = codec->control_data;
+	struct wcd9xxx_core_resource *core_res =
+				&wcd9xxx->core_res;
 
-	wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, taiko);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, taiko);
 }
 
 int taiko_hs_detect(struct snd_soc_codec *codec,
@@ -6180,7 +6189,15 @@
 		taiko->mbhc_started = true;
 	return rc;
 }
-EXPORT_SYMBOL_GPL(taiko_hs_detect);
+EXPORT_SYMBOL(taiko_hs_detect);
+
+void taiko_hs_detect_exit(struct snd_soc_codec *codec)
+{
+	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+	wcd9xxx_mbhc_stop(&taiko->mbhc);
+	taiko->mbhc_started = false;
+}
+EXPORT_SYMBOL(taiko_hs_detect_exit);
 
 void taiko_event_register(
 	int (*machine_event_cb)(struct snd_soc_codec *codec,
@@ -6190,7 +6207,7 @@
 	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
 	taiko->machine_codec_event_cb = machine_event_cb;
 }
-EXPORT_SYMBOL_GPL(taiko_event_register);
+EXPORT_SYMBOL(taiko_event_register);
 
 static void taiko_init_slim_slave_cfg(struct snd_soc_codec *codec)
 {
@@ -6212,6 +6229,16 @@
 	pr_debug("%s: slimbus logical address 0x%llx\n", __func__, eaddr);
 }
 
+static int taiko_device_down(struct wcd9xxx *wcd9xxx)
+{
+	struct snd_soc_codec *codec;
+
+	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
+	snd_soc_card_change_online_state(codec->card, 0);
+
+	return 0;
+}
+
 static int taiko_post_reset_cb(struct wcd9xxx *wcd9xxx)
 {
 	int ret = 0;
@@ -6221,8 +6248,10 @@
 
 	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
 	taiko = snd_soc_codec_get_drvdata(codec);
-	mutex_lock(&codec->mutex);
 
+	snd_soc_card_change_online_state(codec->card, 1);
+
+	mutex_lock(&codec->mutex);
 	if (codec->reg_def_copy) {
 		pr_debug("%s: Update ASOC cache", __func__);
 		kfree(codec->reg_cache);
@@ -6256,17 +6285,18 @@
 		ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
 					taiko_enable_mbhc_micbias,
 					NULL, rco_clk_rate, true);
-		if (ret) {
+		if (ret)
 			pr_err("%s: mbhc init failed %d\n", __func__, ret);
-		} else {
-			ret = wcd9xxx_mbhc_start(&taiko->mbhc,
-						 taiko->mbhc.mbhc_cfg);
-			if (!ret)
-				taiko->mbhc_started = true;
-		}
+		else
+			taiko_hs_detect(codec, taiko->mbhc.mbhc_cfg);
 	}
 	taiko->machine_codec_event_cb(codec, WCD9XXX_CODEC_EVENT_CODEC_UP);
 
+	taiko_cleanup_irqs(taiko);
+	ret = taiko_setup_irqs(taiko);
+	if (ret)
+		pr_err("%s: Failed to setup irq: %d\n", __func__, ret);
+
 	mutex_unlock(&codec->mutex);
 	return ret;
 }
@@ -6309,9 +6339,12 @@
 };
 
 static int wcd9xxx_ssr_register(struct wcd9xxx *control,
-		int (*post_reset_cb)(struct wcd9xxx *wcd9xxx), void *priv)
+				int (*device_down_cb)(struct wcd9xxx *wcd9xxx),
+				int (*device_up_cb)(struct wcd9xxx *wcd9xxx),
+				void *priv)
 {
-	control->post_reset = post_reset_cb;
+	control->dev_down = device_down_cb;
+	control->post_reset = device_up_cb;
 	control->ssr_priv = priv;
 	return 0;
 }
@@ -6392,11 +6425,13 @@
 	int i, rco_clk_rate;
 	void *ptr = NULL;
 	struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+	struct wcd9xxx_core_resource *core_res;
 
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
 	control = codec->control_data;
 
-	wcd9xxx_ssr_register(control, taiko_post_reset_cb, (void *)codec);
+	wcd9xxx_ssr_register(control, taiko_device_down,
+			     taiko_post_reset_cb, (void *)codec);
 
 	dev_info(codec->dev, "%s()\n", __func__);
 
@@ -6416,9 +6451,10 @@
 
 	/* codec resmgr module init */
 	wcd9xxx = codec->control_data;
+	core_res = &wcd9xxx->core_res;
 	pdata = dev_get_platdata(codec->dev->parent);
-	ret = wcd9xxx_resmgr_init(&taiko->resmgr, codec, wcd9xxx, pdata,
-				  &taiko_reg_address);
+	ret = wcd9xxx_resmgr_init(&taiko->resmgr, codec, core_res, pdata,
+				  &taiko_reg_address, WCD9XXX_CDC_TYPE_TAIKO);
 	if (ret) {
 		pr_err("%s: wcd9xxx init failed %d\n", __func__, ret);
 		goto err_init;
diff --git a/sound/soc/codecs/wcd9320.h b/sound/soc/codecs/wcd9320.h
index 8f222ad..5ab5200 100644
--- a/sound/soc/codecs/wcd9320.h
+++ b/sound/soc/codecs/wcd9320.h
@@ -146,6 +146,7 @@
 			     bool dapm);
 extern int taiko_hs_detect(struct snd_soc_codec *codec,
 			   struct wcd9xxx_mbhc_config *mbhc_cfg);
+extern void taiko_hs_detect_exit(struct snd_soc_codec *codec);
 extern void *taiko_get_afe_config(struct snd_soc_codec *codec,
 				  enum afe_config_type config_type);
 
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 7820cd0..acb86416 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -20,6 +20,7 @@
 #include <linux/debugfs.h>
 #include <linux/list.h>
 #include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/core-resource.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
 #include <linux/mfd/wcd9xxx/wcd9320_registers.h>
 #include <linux/mfd/wcd9xxx/pdata.h>
@@ -66,6 +67,7 @@
 #define HS_DETECT_PLUG_INERVAL_MS 100
 #define SWCH_REL_DEBOUNCE_TIME_MS 50
 #define SWCH_IRQ_DEBOUNCE_TIME_US 5000
+#define BTN_RELEASE_DEBOUNCE_TIME_MS 25
 
 #define GND_MIC_SWAP_THRESHOLD 2
 #define OCP_ATTEMPT 1
@@ -257,6 +259,17 @@
 	pr_debug("%s: leave\n", __func__);
 }
 
+static int __wcd9xxx_resmgr_get_k_val(struct wcd9xxx_mbhc *mbhc,
+		unsigned int cfilt_mv)
+{
+	if (mbhc->mbhc_cb &&
+			mbhc->mbhc_cb->get_cdc_type() ==
+					WCD9XXX_CDC_TYPE_HELICON)
+		return 0x18;
+
+	return wcd9xxx_resmgr_get_k_val(mbhc->resmgr, cfilt_mv);
+}
+
 /*
  * called under codec_resource_lock acquisition
  * return old status
@@ -290,7 +303,7 @@
 			wcd9xxx_turn_onoff_override(codec, true);
 		/* Adjust threshold if Mic Bias voltage changes */
 		if (d->micb_mv != VDDIO_MICBIAS_MV) {
-			cfilt_k_val = wcd9xxx_resmgr_get_k_val(mbhc->resmgr,
+			cfilt_k_val = __wcd9xxx_resmgr_get_k_val(mbhc,
 							      VDDIO_MICBIAS_MV);
 			usleep_range(10000, 10000);
 			snd_soc_update_bits(codec,
@@ -342,7 +355,7 @@
 		/* Reprogram thresholds */
 		if (d->micb_mv != VDDIO_MICBIAS_MV) {
 			cfilt_k_val =
-			    wcd9xxx_resmgr_get_k_val(mbhc->resmgr,
+			    __wcd9xxx_resmgr_get_k_val(mbhc,
 						     d->micb_mv);
 			snd_soc_update_bits(codec,
 					mbhc->mbhc_bias_regs.cfilt_val,
@@ -452,7 +465,7 @@
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_cal_btn_det_mp);
+EXPORT_SYMBOL(wcd9xxx_mbhc_cal_btn_det_mp);
 
 static void wcd9xxx_calibrate_hs_polling(struct wcd9xxx_mbhc *mbhc)
 {
@@ -487,34 +500,36 @@
 {
 	struct snd_soc_codec *codec = mbhc->codec;
 	struct wcd9xxx_cfilt_mode cfilt_mode;
-	u8 reg_mode_val, cur_mode_val;
 
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->switch_cfilt_mode) {
 		cfilt_mode = mbhc->mbhc_cb->switch_cfilt_mode(mbhc, fast);
-		reg_mode_val = cfilt_mode.reg_mode_val;
-		cur_mode_val = cfilt_mode.cur_mode_val;
 	} else {
 		if (fast)
-			reg_mode_val = WCD9XXX_CFILT_FAST_MODE;
+			cfilt_mode.reg_mode_val = WCD9XXX_CFILT_FAST_MODE;
 		else
-			reg_mode_val = WCD9XXX_CFILT_SLOW_MODE;
+			cfilt_mode.reg_mode_val = WCD9XXX_CFILT_SLOW_MODE;
 
-		cur_mode_val =
+		cfilt_mode.reg_mask = 0x40;
+		cfilt_mode.cur_mode_val =
 		    snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x40;
 	}
-	if (cur_mode_val != reg_mode_val) {
+
+	if (cfilt_mode.cur_mode_val
+			!= cfilt_mode.reg_mode_val) {
 		if (mbhc->polling_active)
 			wcd9xxx_pause_hs_polling(mbhc);
 		snd_soc_update_bits(codec,
 				    mbhc->mbhc_bias_regs.cfilt_ctl,
-				    0x40, reg_mode_val);
+					cfilt_mode.reg_mask,
+					cfilt_mode.reg_mode_val);
 		if (mbhc->polling_active)
 			wcd9xxx_start_hs_polling(mbhc);
 		pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
-			cur_mode_val, reg_mode_val);
+			cfilt_mode.cur_mode_val,
+			cfilt_mode.reg_mode_val);
 	} else {
 		pr_debug("%s: CFILT Value is already %x\n",
-			 __func__, cur_mode_val);
+			 __func__, cfilt_mode.cur_mode_val);
 	}
 }
 
@@ -556,7 +571,7 @@
 			mbhc->hphlocp_cnt = 0;
 		else
 			mbhc->hphrocp_cnt = 0;
-		wcd9xxx_enable_irq(codec->control_data, irq);
+		wcd9xxx_enable_irq(mbhc->resmgr->core_res, irq);
 	}
 }
 
@@ -578,6 +593,18 @@
 	unsigned int cfilt;
 	struct wcd9xxx_pdata *pdata = mbhc->resmgr->pdata;
 
+	if (mbhc->mbhc_cb &&
+			mbhc->mbhc_cb->get_cdc_type() ==
+					WCD9XXX_CDC_TYPE_HELICON) {
+		micbias_regs->mbhc_reg = WCD9XXX_A_MICB_1_MBHC;
+		micbias_regs->int_rbias = WCD9XXX_A_MICB_1_INT_RBIAS;
+		micbias_regs->ctl_reg = WCD9XXX_A_MICB_1_CTL;
+		micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_1_VAL;
+		micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_1_CTL;
+		mbhc->mbhc_data.micb_mv = 1800;
+		return;
+	}
+
 	switch (mbhc->mbhc_cfg->micbias) {
 	case MBHC_MICBIAS1:
 		cfilt = pdata->micbias.bias1_cfilt_sel;
@@ -685,7 +712,7 @@
 	if (r)
 		/* if scheduled mbhc.mbhc_btn_dwork is canceled from here,
 		 * we have to unlock from here instead btn_work */
-		wcd9xxx_unlock_sleep(mbhc->resmgr->core);
+		wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
 	return r;
 }
 
@@ -828,6 +855,7 @@
 		} else if (jack_type == SND_JACK_HEADSET) {
 			mbhc->polling_active = BUTTON_POLLING_SUPPORTED;
 			mbhc->current_plug = PLUG_TYPE_HEADSET;
+			mbhc->update_z = true;
 		} else if (jack_type == SND_JACK_LINEOUT) {
 			mbhc->current_plug = PLUG_TYPE_HIGH_HPH;
 		}
@@ -836,8 +864,10 @@
 			pr_debug("%s: Enabling micbias\n", __func__);
 			mbhc->micbias_enable_cb(mbhc->codec, true);
 		}
+
 		if (mbhc->impedance_detect)
 			wcd9xxx_detect_impedance(mbhc, &mbhc->zl, &mbhc->zr);
+
 		pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
 			 jack_type, mbhc->hph_status);
 		wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
@@ -857,7 +887,7 @@
 	pr_debug("%s: scheduling wcd9xxx_correct_swch_plug\n", __func__);
 	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
 	mbhc->hs_detect_work_stop = false;
-	wcd9xxx_lock_sleep(mbhc->resmgr->core);
+	wcd9xxx_lock_sleep(mbhc->resmgr->core_res);
 	schedule_work(work);
 }
 
@@ -873,7 +903,7 @@
 	if (cancel_work_sync(work)) {
 		pr_debug("%s: correct_plug_swch is canceled\n",
 			 __func__);
-		wcd9xxx_unlock_sleep(mbhc->resmgr->core);
+		wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
 	}
 	WCD9XXX_BCL_LOCK(mbhc->resmgr);
 }
@@ -882,8 +912,8 @@
 {
 	int r;
 	int vddio_k, mb_k;
-	vddio_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, VDDIO_MICBIAS_MV);
-	mb_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, mbhc->mbhc_data.micb_mv);
+	vddio_k = __wcd9xxx_resmgr_get_k_val(mbhc, VDDIO_MICBIAS_MV);
+	mb_k = __wcd9xxx_resmgr_get_k_val(mbhc, mbhc->mbhc_data.micb_mv);
 	if (tovddio)
 		r = v * (vddio_k + 4) / (mb_k + 4);
 	else
@@ -939,7 +969,7 @@
 	short bias_value;
 	struct snd_soc_codec *codec = mbhc->codec;
 
-	wcd9xxx_disable_irq(mbhc->resmgr->core, WCD9XXX_IRQ_MBHC_POTENTIAL);
+	wcd9xxx_disable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
 	if (noreldetection)
 		wcd9xxx_turn_onoff_rel_detection(codec, false);
 
@@ -980,7 +1010,7 @@
 
 	if (noreldetection)
 		wcd9xxx_turn_onoff_rel_detection(codec, true);
-	wcd9xxx_enable_irq(mbhc->resmgr->core, WCD9XXX_IRQ_MBHC_POTENTIAL);
+	wcd9xxx_enable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
 
 	return bias_value;
 }
@@ -1796,12 +1826,12 @@
 	if (snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL) & 0x4) {
 		/* called by interrupt */
 		if (!is_clk_active(codec)) {
-			wcd9xxx_resmgr_enable_config_mode(codec, 1);
+			wcd9xxx_resmgr_enable_config_mode(mbhc->resmgr, 1);
 			snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
 					0x06, 0);
 			usleep_range(generic->t_shutdown_plug_rem,
 					generic->t_shutdown_plug_rem);
-			wcd9xxx_resmgr_enable_config_mode(codec, 0);
+			wcd9xxx_resmgr_enable_config_mode(mbhc->resmgr, 0);
 		} else
 			snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
 					0x06, 0);
@@ -1833,7 +1863,7 @@
 		snd_soc_update_bits(codec, mbhc->resmgr->reg_addr->micb_4_mbhc,
 				    0x3, mbhc->mbhc_cfg->micbias);
 
-	wcd9xxx_enable_irq(mbhc->resmgr->core, WCD9XXX_IRQ_MBHC_INSERTION);
+	wcd9xxx_enable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_INSERTION);
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
 	pr_debug("%s: leave\n", __func__);
 
@@ -2297,7 +2327,7 @@
 
 	pr_debug("%s: enter\n", __func__);
 	WCD9XXX_BCL_LOCK(mbhc->resmgr);
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
+	wcd9xxx_disable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_INSERTION);
 
 	is_mb_trigger = !!(snd_soc_read(codec, mbhc->mbhc_bias_regs.mbhc_reg) &
 			   0x10);
@@ -2343,7 +2373,7 @@
 			    mbhc->buttons_pressed);
 
 	pr_debug("%s: leave\n", __func__);
-	wcd9xxx_unlock_sleep(mbhc->resmgr->core);
+	wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
 }
 
 static void wcd9xxx_mbhc_insert_work(struct work_struct *work)
@@ -2351,12 +2381,12 @@
 	struct delayed_work *dwork;
 	struct wcd9xxx_mbhc *mbhc;
 	struct snd_soc_codec *codec;
-	struct wcd9xxx *core;
+	struct wcd9xxx_core_resource *core_res;
 
 	dwork = to_delayed_work(work);
 	mbhc = container_of(dwork, struct wcd9xxx_mbhc, mbhc_insert_dwork);
 	codec = mbhc->codec;
-	core = mbhc->resmgr->core;
+	core_res = mbhc->resmgr->core_res;
 
 	pr_debug("%s:\n", __func__);
 
@@ -2364,9 +2394,9 @@
 	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
 	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
 	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
-	wcd9xxx_disable_irq_sync(core, WCD9XXX_IRQ_MBHC_INSERTION);
+	wcd9xxx_disable_irq_sync(core_res, WCD9XXX_IRQ_MBHC_INSERTION);
 	wcd9xxx_mbhc_detect_plug_type(mbhc);
-	wcd9xxx_unlock_sleep(core);
+	wcd9xxx_unlock_sleep(core_res);
 }
 
 static bool wcd9xxx_mbhc_fw_validate(const struct firmware *fw)
@@ -2702,7 +2732,7 @@
 	}
 	pr_debug("%s: leave current_plug(%d)\n", __func__, mbhc->current_plug);
 	/* unlock sleep */
-	wcd9xxx_unlock_sleep(mbhc->resmgr->core);
+	wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
 }
 
 static void wcd9xxx_swch_irq_handler(struct wcd9xxx_mbhc *mbhc)
@@ -2797,25 +2827,24 @@
 	struct wcd9xxx_mbhc *mbhc = data;
 
 	pr_debug("%s: enter\n", __func__);
-	if (unlikely(wcd9xxx_lock_sleep(mbhc->resmgr->core) == false)) {
+	if (unlikely(wcd9xxx_lock_sleep(mbhc->resmgr->core_res) == false)) {
 		pr_warn("%s: failed to hold suspend\n", __func__);
 		r = IRQ_NONE;
 	} else {
 		/* Call handler */
 		wcd9xxx_swch_irq_handler(mbhc);
-		wcd9xxx_unlock_sleep(mbhc->resmgr->core);
+		wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
 	}
 
 	pr_debug("%s: leave %d\n", __func__, r);
 	return r;
 }
 
-static int wcd9xxx_is_fake_press(struct wcd9xxx_mbhc *mbhc)
+static int wcd9xxx_is_false_press(struct wcd9xxx_mbhc *mbhc)
 {
-	int i;
 	s16 mb_v;
+	int i = 0;
 	int r = 0;
-	const int dces = NUM_DCE_PLUG_DETECT;
 	const s16 v_ins_hu =
 	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_HU);
 	const s16 v_ins_h =
@@ -2824,9 +2853,16 @@
 	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_HU);
 	const s16 v_b1_h =
 	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
+	const unsigned long timeout =
+	    jiffies + msecs_to_jiffies(BTN_RELEASE_DEBOUNCE_TIME_MS);
 
-	for (i = 0; i < dces; i++) {
-		usleep_range(10000, 10000);
+	while (time_before(jiffies, timeout)) {
+		/*
+		 * This function needs to run measurements just few times during
+		 * release debounce time.  Make 1ms interval to avoid
+		 * unnecessary excessive measurements.
+		 */
+		usleep_range(1000, 1000 + WCD9XXX_USLEEP_RANGE_MARGIN_US);
 		if (i == 0) {
 			mb_v = wcd9xxx_codec_sta_dce(mbhc, 0, true);
 			pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
@@ -2844,6 +2880,7 @@
 				break;
 			}
 		}
+		i++;
 	}
 
 	return r;
@@ -2927,6 +2964,9 @@
 	*sta_z = wcd9xxx_codec_sta_dce(mbhc, 0, false);
 	*dce_z = wcd9xxx_codec_sta_dce(mbhc, 1, false);
 
+	pr_debug("%s: sta_z 0x%x, dce_z 0x%x\n", __func__, *sta_z & 0xFFFF,
+		 *dce_z & 0xFFFF);
+
 	/* Connect override from micbias */
 	snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4, 1 << 4);
 	/* Disable pull down micbias to ground */
@@ -2934,6 +2974,21 @@
 	snd_soc_write(codec, mbhc->mbhc_bias_regs.ctl_reg, reg0);
 }
 
+void wcd9xxx_update_z(struct wcd9xxx_mbhc *mbhc)
+{
+	const u16 sta_z = mbhc->mbhc_data.sta_z;
+	const u16 dce_z = mbhc->mbhc_data.dce_z;
+
+	wcd9xxx_get_z(mbhc, &mbhc->mbhc_data.dce_z, &mbhc->mbhc_data.sta_z);
+	pr_debug("%s: sta_z 0x%x,dce_z 0x%x -> sta_z 0x%x,dce_z 0x%x\n",
+		 __func__, sta_z & 0xFFFF, dce_z & 0xFFFF,
+		 mbhc->mbhc_data.sta_z & 0xFFFF,
+		 mbhc->mbhc_data.dce_z & 0xFFFF);
+
+	wcd9xxx_mbhc_calc_thres(mbhc);
+	wcd9xxx_calibrate_hs_polling(mbhc);
+}
+
 /*
  * wcd9xxx_update_rel_threshold : update mbhc release upper bound threshold
  *				  to ceilmv + buffer
@@ -2979,7 +3034,7 @@
 	short dce[d->n_btn_meas + 1], sta;
 	s32 mv[d->n_btn_meas + 1], mv_s[d->n_btn_meas + 1];
 	struct snd_soc_codec *codec = mbhc->codec;
-	struct wcd9xxx *core = mbhc->resmgr->core;
+	struct wcd9xxx_core_resource *core_res = mbhc->resmgr->core_res;
 	int n_btn_meas = d->n_btn_meas;
 	void *calibration = mbhc->mbhc_cfg->calibration;
 
@@ -3014,6 +3069,9 @@
 	vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
 		 mbhc->mbhc_micbias_switched);
 
+	dce_z = mbhc->mbhc_data.dce_z;
+	sta_z = mbhc->mbhc_data.sta_z;
+
 	/* Measure scaled HW STA */
 	dce[0] = wcd9xxx_read_dce_result(codec);
 	sta = wcd9xxx_read_sta_result(codec);
@@ -3026,7 +3084,10 @@
 		} else {
 			pr_debug("%s: Button is released without resume",
 				 __func__);
-			wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
+			if (mbhc->update_z) {
+				wcd9xxx_update_z(mbhc);
+				mbhc->update_z = false;
+			}
 			stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z,
 						mbhc->mbhc_data.micb_mv);
 			if (vddio)
@@ -3049,7 +3110,10 @@
 	     meas++)
 		dce[meas] = wcd9xxx_codec_sta_dce(mbhc, 1, false);
 
-	wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
+	if (mbhc->update_z) {
+		wcd9xxx_update_z(mbhc);
+		mbhc->update_z = false;
+	}
 
 	stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z,
 					  mbhc->mbhc_data.micb_mv);
@@ -3119,11 +3183,11 @@
 
 		mask = wcd9xxx_get_button_mask(btn);
 		mbhc->buttons_pressed |= mask;
-		wcd9xxx_lock_sleep(core);
+		wcd9xxx_lock_sleep(core_res);
 		if (schedule_delayed_work(&mbhc->mbhc_btn_dwork,
 					  msecs_to_jiffies(400)) == 0) {
 			WARN(1, "Button pressed twice without release event\n");
-			wcd9xxx_unlock_sleep(core);
+			wcd9xxx_unlock_sleep(core_res);
 		}
 	} else {
 		pr_debug("%s: bogus button press, too short press?\n",
@@ -3139,6 +3203,7 @@
 static irqreturn_t wcd9xxx_release_handler(int irq, void *data)
 {
 	int ret;
+	bool waitdebounce = true;
 	struct wcd9xxx_mbhc *mbhc = data;
 
 	pr_debug("%s: enter\n", __func__);
@@ -3153,7 +3218,7 @@
 			wcd9xxx_jack_report(mbhc, &mbhc->button_jack, 0,
 					    mbhc->buttons_pressed);
 		} else {
-			if (wcd9xxx_is_fake_press(mbhc)) {
+			if (wcd9xxx_is_false_press(mbhc)) {
 				pr_debug("%s: Fake button press interrupt\n",
 					 __func__);
 			} else {
@@ -3172,6 +3237,7 @@
 					wcd9xxx_jack_report(mbhc,
 						      &mbhc->button_jack,
 						      0, mbhc->buttons_pressed);
+					waitdebounce = false;
 				}
 			}
 		}
@@ -3181,7 +3247,8 @@
 
 	wcd9xxx_calibrate_hs_polling(mbhc);
 
-	msleep(SWCH_REL_DEBOUNCE_TIME_MS);
+	if (waitdebounce)
+		msleep(SWCH_REL_DEBOUNCE_TIME_MS);
 	wcd9xxx_start_hs_polling(mbhc);
 
 	pr_debug("%s: leave\n", __func__);
@@ -3207,7 +3274,7 @@
 			snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL,
 					    0x10, 0x10);
 		} else {
-			wcd9xxx_disable_irq(codec->control_data,
+			wcd9xxx_disable_irq(mbhc->resmgr->core_res,
 					  WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
 			mbhc->hph_status |= SND_JACK_OC_HPHL;
 			wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
@@ -3237,7 +3304,7 @@
 		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
 				    0x10);
 	} else {
-		wcd9xxx_disable_irq(mbhc->resmgr->core,
+		wcd9xxx_disable_irq(mbhc->resmgr->core_res,
 				    WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 		mbhc->hph_status |= SND_JACK_OC_HPHR;
 		wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
@@ -3318,7 +3385,7 @@
 	struct snd_soc_codec *codec = mbhc->codec;
 
 	pr_debug("%s: enter\n", __func__);
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
+	wcd9xxx_disable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
 	wcd9xxx_turn_onoff_rel_detection(codec, false);
 
 	/* t_dce and t_sta are updated by wcd9xxx_update_mbhc_clk_rate() */
@@ -3449,7 +3516,7 @@
 				    0x80, 0x80);
 	usleep_range(100, 100);
 
-	wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
+	wcd9xxx_enable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
 	wcd9xxx_turn_onoff_rel_detection(codec, true);
 
 	pr_debug("%s: leave\n", __func__);
@@ -3492,9 +3559,14 @@
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78,
 			    btn_det->mbhc_nsc << 3);
 
-	if (mbhc->resmgr->reg_addr->micb_4_mbhc)
-		snd_soc_update_bits(codec, mbhc->resmgr->reg_addr->micb_4_mbhc,
-				    0x03, MBHC_MICBIAS2);
+	if (mbhc->mbhc_cb &&
+			mbhc->mbhc_cb->get_cdc_type() !=
+					WCD9XXX_CDC_TYPE_HELICON) {
+		if (mbhc->resmgr->reg_addr->micb_4_mbhc)
+			snd_soc_update_bits(codec,
+					mbhc->resmgr->reg_addr->micb_4_mbhc,
+					0x03, MBHC_MICBIAS2);
+	}
 
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
 
@@ -3510,8 +3582,8 @@
 static int wcd9xxx_setup_jack_detect_irq(struct wcd9xxx_mbhc *mbhc)
 {
 	int ret = 0;
-	void *core = mbhc->resmgr->core;
 	struct snd_soc_codec *codec = mbhc->codec;
+	void *core_res = mbhc->resmgr->core_res;
 	int jack_irq;
 
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->jack_detect_irq)
@@ -3540,7 +3612,7 @@
 		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_RX_HPH_OCP_CTL,
 				    1 << 1, 1 << 1);
 
-		ret = wcd9xxx_request_irq(core, jack_irq,
+		ret = wcd9xxx_request_irq(core_res, jack_irq,
 					  wcd9xxx_mech_plug_detect_irq,
 					  "Jack Detect",
 					  mbhc);
@@ -3575,9 +3647,9 @@
 	if (!IS_ERR_VALUE(ret)) {
 		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
 				    0x10);
-		wcd9xxx_enable_irq(codec->control_data,
+		wcd9xxx_enable_irq(mbhc->resmgr->core_res,
 				   WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
-		wcd9xxx_enable_irq(codec->control_data,
+		wcd9xxx_enable_irq(mbhc->resmgr->core_res,
 				   WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 
 		/* Initialize mechanical mbhc */
@@ -3798,16 +3870,40 @@
 		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
 		0x40, WCD9XXX_CFILT_FAST_MODE);
 
-	if (!mbhc->mbhc_cfg->read_fw_bin)
+	/*
+	 * If codec has specific clock gating for MBHC,
+	 * remove the clock gate
+	 */
+	if (mbhc->mbhc_cb &&
+			mbhc->mbhc_cb->enable_clock_gate)
+		mbhc->mbhc_cb->enable_clock_gate(mbhc->codec, true);
+
+	if (!mbhc->mbhc_cfg->read_fw_bin ||
+	    (mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_fw)) {
 		rc = wcd9xxx_init_and_calibrate(mbhc);
-	else
-		schedule_delayed_work(&mbhc->mbhc_firmware_dwork,
-				      usecs_to_jiffies(FW_READ_TIMEOUT));
+	} else {
+		if (!mbhc->mbhc_fw)
+			schedule_delayed_work(&mbhc->mbhc_firmware_dwork,
+					     usecs_to_jiffies(FW_READ_TIMEOUT));
+		else
+			pr_debug("%s: Skipping to read mbhc fw, 0x%p\n",
+				 __func__, mbhc->mbhc_fw);
+	}
 
 	pr_debug("%s: leave %d\n", __func__, rc);
 	return rc;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_start);
+EXPORT_SYMBOL(wcd9xxx_mbhc_start);
+
+void wcd9xxx_mbhc_stop(struct wcd9xxx_mbhc *mbhc)
+{
+	if (mbhc->mbhc_fw) {
+		cancel_delayed_work_sync(&mbhc->mbhc_firmware_dwork);
+		release_firmware(mbhc->mbhc_fw);
+		mbhc->mbhc_fw = NULL;
+	}
+}
+EXPORT_SYMBOL(wcd9xxx_mbhc_stop);
 
 static enum wcd9xxx_micbias_num
 wcd9xxx_event_to_micbias(const enum wcd9xxx_notify_event event)
@@ -4374,7 +4470,7 @@
 		      bool impedance_det_en)
 {
 	int ret;
-	void *core;
+	void *core_res;
 
 	pr_debug("%s: enter\n", __func__);
 	memset(&mbhc->mbhc_bias_regs, 0, sizeof(struct mbhc_micbias_regs));
@@ -4441,18 +4537,18 @@
 
 	wcd9xxx_init_debugfs(mbhc);
 
-	core = mbhc->resmgr->core;
-	ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_INSERTION,
+	core_res = mbhc->resmgr->core_res;
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION,
 				  wcd9xxx_hs_insert_irq,
 				  "Headset insert detect", mbhc);
 	if (ret) {
-		pr_err("%s: Failed to request irq %d\n", __func__,
-		       WCD9XXX_IRQ_MBHC_INSERTION);
+		pr_err("%s: Failed to request irq %d, ret = %d\n", __func__,
+		       WCD9XXX_IRQ_MBHC_INSERTION, ret);
 		goto err_insert_irq;
 	}
-	wcd9xxx_disable_irq(core, WCD9XXX_IRQ_MBHC_INSERTION);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION);
 
-	ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_REMOVAL,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL,
 				  wcd9xxx_hs_remove_irq,
 				  "Headset remove detect", mbhc);
 	if (ret) {
@@ -4461,7 +4557,7 @@
 		goto err_remove_irq;
 	}
 
-	ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_POTENTIAL,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL,
 				  wcd9xxx_dce_handler, "DC Estimation detect",
 				  mbhc);
 	if (ret) {
@@ -4470,7 +4566,7 @@
 		goto err_potential_irq;
 	}
 
-	ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_RELEASE,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE,
 				  wcd9xxx_release_handler,
 				  "Button Release detect", mbhc);
 	if (ret) {
@@ -4479,7 +4575,7 @@
 		goto err_release_irq;
 	}
 
-	ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
 				  wcd9xxx_hphl_ocp_irq, "HPH_L OCP detect",
 				  mbhc);
 	if (ret) {
@@ -4487,9 +4583,9 @@
 		       WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
 		goto err_hphl_ocp_irq;
 	}
-	wcd9xxx_disable_irq(core, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
 
-	ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
+	ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
 				  wcd9xxx_hphr_ocp_irq, "HPH_R OCP detect",
 				  mbhc);
 	if (ret) {
@@ -4497,7 +4593,7 @@
 		       WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 		goto err_hphr_ocp_irq;
 	}
-	wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
+	wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 
 	wcd9xxx_regmgr_cond_register(resmgr, 1 << WCD9XXX_COND_HPH_MIC |
 					     1 << WCD9XXX_COND_HPH);
@@ -4506,52 +4602,50 @@
 	return ret;
 
 err_hphr_ocp_irq:
-	wcd9xxx_free_irq(core, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
 err_hphl_ocp_irq:
-	wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
 err_release_irq:
-	wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
 err_potential_irq:
-	wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
 err_remove_irq:
-	wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
 err_insert_irq:
 	wcd9xxx_resmgr_unregister_notifier(mbhc->resmgr, &mbhc->nblock);
 
 	pr_debug("%s: leave ret %d\n", __func__, ret);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_init);
+EXPORT_SYMBOL(wcd9xxx_mbhc_init);
 
 void wcd9xxx_mbhc_deinit(struct wcd9xxx_mbhc *mbhc)
 {
-	void *cdata = mbhc->codec->control_data;
+	struct wcd9xxx_core_resource *core_res =
+				mbhc->resmgr->core_res;
 
 	wcd9xxx_regmgr_cond_deregister(mbhc->resmgr, 1 << WCD9XXX_COND_HPH_MIC |
 						     1 << WCD9XXX_COND_HPH);
 
-	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
-	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
-	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
-	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
 
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->free_irq)
 		mbhc->mbhc_cb->free_irq(mbhc);
 	else
-		wcd9xxx_free_irq(cdata, WCD9320_IRQ_MBHC_JACK_SWITCH,
+		wcd9xxx_free_irq(core_res, WCD9320_IRQ_MBHC_JACK_SWITCH,
 				 mbhc);
 
-	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
-	wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, mbhc);
-
-	if (mbhc->mbhc_fw)
-		release_firmware(mbhc->mbhc_fw);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
+	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, mbhc);
 
 	wcd9xxx_resmgr_unregister_notifier(mbhc->resmgr, &mbhc->nblock);
 
 	wcd9xxx_cleanup_debugfs(mbhc);
 }
-EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_deinit);
+EXPORT_SYMBOL(wcd9xxx_mbhc_deinit);
 
 MODULE_DESCRIPTION("wcd9xxx MBHC module");
 MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 88c911f..3040bc4 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -224,6 +224,7 @@
 struct wcd9xxx_cfilt_mode {
 	u8 reg_mode_val;
 	u8 cur_mode_val;
+	u8 reg_mask;
 };
 
 struct wcd9xxx_mbhc_cb {
@@ -236,6 +237,8 @@
 							bool);
 	void (*select_cfilt) (struct snd_soc_codec *, struct wcd9xxx_mbhc *);
 	void (*free_irq) (struct wcd9xxx_mbhc *);
+	enum wcd9xxx_cdc_type (*get_cdc_type) (void);
+	void (*enable_clock_gate) (struct snd_soc_codec *, bool);
 };
 
 struct wcd9xxx_mbhc {
@@ -306,6 +309,8 @@
 
 	u32 rco_clk_rate;
 
+	bool update_z;
+
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs_poke;
 	struct dentry *debugfs_mbhc;
@@ -369,6 +374,7 @@
 
 int wcd9xxx_mbhc_start(struct wcd9xxx_mbhc *mbhc,
 		       struct wcd9xxx_mbhc_config *mbhc_cfg);
+void wcd9xxx_mbhc_stop(struct wcd9xxx_mbhc *mbhc);
 int wcd9xxx_mbhc_init(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_resmgr *resmgr,
 		      struct snd_soc_codec *codec,
 		      int (*micbias_enable_cb) (struct snd_soc_codec*,  bool),
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 9633cc0..95244c0 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -33,6 +33,7 @@
 #include <linux/kernel.h>
 #include <linux/gpio.h>
 #include "wcd9xxx-resmgr.h"
+#include "msm8x10_wcd_registers.h"
 
 static char wcd9xxx_event_string[][64] = {
 	"WCD9XXX_EVENT_INVALID",
@@ -168,7 +169,9 @@
 	 * mclk should be off or clk buff source souldn't be VBG
 	 * Let's turn off mclk always
 	 */
-	WARN_ON(snd_soc_read(codec, WCD9XXX_A_CLK_BUFF_EN2) & (1 << 2));
+	if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
+		WARN_ON(snd_soc_read(codec, WCD9XXX_A_CLK_BUFF_EN2) & (1 << 2));
+
 	wcd9xxx_enable_bg(resmgr);
 	/* Notify bandgap mode change */
 	wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_POST_BG_MBHC_ON);
@@ -188,11 +191,13 @@
 		wcd9xxx_resmgr_notifier_call(resmgr,
 					     WCD9XXX_EVENT_PRE_MCLK_OFF);
 	/* Disable clock */
-	snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x00);
-	usleep_range(50, 50);
-	snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x02);
-	snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x00);
-	usleep_range(50, 50);
+	if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON) {
+		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x00);
+		usleep_range(50, 50);
+		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x02);
+		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x00);
+		usleep_range(50, 50);
+	}
 	/* Notify */
 	if (resmgr->clk_type == WCD9XXX_CLK_RCO)
 		wcd9xxx_resmgr_notifier_call(resmgr,
@@ -375,8 +380,10 @@
 	}
 }
 
-int wcd9xxx_resmgr_enable_config_mode(struct snd_soc_codec *codec, int enable)
+int wcd9xxx_resmgr_enable_config_mode(struct wcd9xxx_resmgr *resmgr, int enable)
 {
+	struct snd_soc_codec *codec = resmgr->codec;
+
 	pr_debug("%s: enable = %d\n", __func__, enable);
 	if (enable) {
 		snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_FREQ, 0x10, 0);
@@ -388,10 +395,20 @@
 		usleep_range(10, 10);
 		snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_TEST, 0x80, 0);
 		usleep_range(10000, 10000);
-		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x08, 0x08);
+		if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
+			snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
+					0x08, 0x08);
+		else
+			snd_soc_update_bits(codec,
+					MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
+					0x20, 0x20);
 	} else {
 		snd_soc_update_bits(codec, WCD9XXX_A_BIAS_OSC_BG_CTL, 0x1, 0);
 		snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_FREQ, 0x80, 0);
+		if (resmgr->codec_type == WCD9XXX_CDC_TYPE_HELICON)
+			snd_soc_update_bits(codec,
+					MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
+					0x20, 0x00);
 	}
 
 	return 0;
@@ -403,38 +420,60 @@
 	struct snd_soc_codec *codec = resmgr->codec;
 
 	pr_debug("%s: config_mode = %d\n", __func__, config_mode);
+
 	/* transit to RCO requires mclk off */
-	WARN_ON(snd_soc_read(codec, WCD9XXX_A_CLK_BUFF_EN2) & (1 << 2));
+	if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
+		WARN_ON(snd_soc_read(codec, WCD9XXX_A_CLK_BUFF_EN2) & (1 << 2));
+
 	if (config_mode) {
 		/* Notify */
 		wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_RCO_ON);
 		/* enable RCO and switch to it */
-		wcd9xxx_resmgr_enable_config_mode(codec, 1);
-		snd_soc_write(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02);
+		wcd9xxx_resmgr_enable_config_mode(resmgr, 1);
+		if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
+			snd_soc_write(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02);
 		usleep_range(1000, 1000);
 	} else {
 		/* Notify */
 		wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_MCLK_ON);
 		/* switch to MCLK */
-		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x08, 0x00);
+		if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON) {
+			snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
+				0x08, 0x00);
+		} else {
+			snd_soc_update_bits(codec,
+					MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
+					0x03, 0x03);
+			snd_soc_update_bits(codec,
+					MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
+					0x0f, 0x0d);
+		}
 		/* if RCO is enabled, switch from it */
 		if (snd_soc_read(codec, WCD9XXX_A_RC_OSC_FREQ) & 0x80) {
-			snd_soc_write(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02);
-			wcd9xxx_resmgr_enable_config_mode(codec, 0);
+			if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
+				snd_soc_write(codec, WCD9XXX_A_CLK_BUFF_EN2,
+							  0x02);
+			wcd9xxx_resmgr_enable_config_mode(resmgr, 0);
 		}
 		/* clk source to ext clk and clk buff ref to VBG */
-		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x0C, 0x04);
+		if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
+			snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
+				0x0C, 0x04);
 	}
 
-	snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x01, 0x01);
-	/* sleep time required by codec hardware to enable clock buffer */
-	usleep_range(1000, 1200);
-
-	snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x00);
-
-	/* on MCLK */
-	snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x04);
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
+	if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON) {
+		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x01, 0x01);
+		/* sleep required by codec hardware to enable clock buffer */
+		usleep_range(1000, 1200);
+		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x00);
+		/* on MCLK */
+		snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x04);
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_MCLK_CTL,
+				0x01, 0x01);
+	} else {
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
+				0x01, 0x01);
+	}
 	usleep_range(50, 50);
 
 	/* Notify */
@@ -493,7 +532,7 @@
 					       WCD9XXX_A_RC_OSC_FREQ) & 0x80));
 			/* disable clock block */
 			wcd9xxx_disable_clock_block(resmgr);
-			/* switch to RCO */
+			/* switch to MCLK */
 			wcd9xxx_enable_clock_block(resmgr, 0);
 			resmgr->clk_type = WCD9XXX_CLK_MCLK;
 		}
@@ -797,9 +836,10 @@
 
 int wcd9xxx_resmgr_init(struct wcd9xxx_resmgr *resmgr,
 			struct snd_soc_codec *codec,
-			struct wcd9xxx *wcd9xxx,
+			struct wcd9xxx_core_resource *core_res,
 			struct wcd9xxx_pdata *pdata,
-			struct wcd9xxx_reg_address *reg_addr)
+			struct wcd9xxx_reg_address *reg_addr,
+			enum wcd9xxx_cdc_type cdc_type)
 {
 	WARN(ARRAY_SIZE(wcd9xxx_event_string) != WCD9XXX_EVENT_LAST + 1,
 	     "Event string table isn't up to date!, %d != %d\n",
@@ -807,8 +847,9 @@
 
 	resmgr->bandgap_type = WCD9XXX_BANDGAP_OFF;
 	resmgr->codec = codec;
+	resmgr->codec_type = cdc_type;
 	/* This gives access of core handle to lock/unlock suspend */
-	resmgr->core = wcd9xxx;
+	resmgr->core_res = core_res;
 	resmgr->pdata = pdata;
 	resmgr->reg_addr = reg_addr;
 
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
index e6a8f5d..7fb5820 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr.h
@@ -13,6 +13,7 @@
 #define __WCD9XXX_COMMON_H__
 
 #include <linux/notifier.h>
+#include <linux/mfd/wcd9xxx/core-resource.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
 
 enum wcd9xxx_bandgap_type {
@@ -21,6 +22,13 @@
 	WCD9XXX_BANDGAP_MBHC_MODE,
 };
 
+enum wcd9xxx_cdc_type {
+	WCD9XXX_CDC_TYPE_INVALID = 0,
+	WCD9XXX_CDC_TYPE_TAIKO,
+	WCD9XXX_CDC_TYPE_TAPAN,
+	WCD9XXX_CDC_TYPE_HELICON,
+};
+
 enum wcd9xxx_clock_type {
 	WCD9XXX_CLK_OFF,
 	WCD9XXX_CLK_RCO,
@@ -102,7 +110,7 @@
 
 struct wcd9xxx_resmgr {
 	struct snd_soc_codec *codec;
-	struct wcd9xxx *core;
+	struct wcd9xxx_core_resource *core_res;
 
 	u32 rx_bias_count;
 
@@ -146,16 +154,20 @@
 	 */
 	struct mutex codec_resource_lock;
 	struct mutex codec_bg_clk_lock;
+
+	enum wcd9xxx_cdc_type codec_type;
 };
 
 int wcd9xxx_resmgr_init(struct wcd9xxx_resmgr *resmgr,
 			struct snd_soc_codec *codec,
-			struct wcd9xxx *wcd9xxx,
+			struct wcd9xxx_core_resource *core_res,
 			struct wcd9xxx_pdata *pdata,
-			struct wcd9xxx_reg_address *reg_addr);
+			struct wcd9xxx_reg_address *reg_addr,
+			enum wcd9xxx_cdc_type cdc_type);
 void wcd9xxx_resmgr_deinit(struct wcd9xxx_resmgr *resmgr);
 
-int wcd9xxx_resmgr_enable_config_mode(struct snd_soc_codec *codec, int enable);
+int wcd9xxx_resmgr_enable_config_mode(struct wcd9xxx_resmgr *resmgr,
+				int enable);
 
 void wcd9xxx_resmgr_enable_rx_bias(struct wcd9xxx_resmgr *resmgr, u32 enable);
 void wcd9xxx_resmgr_get_clk_block(struct wcd9xxx_resmgr *resmgr,
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 19d717e..55a5e57 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -904,7 +904,7 @@
 };
 
 /* Digital audio interface glue - connects codec <---> CPU */
-static struct snd_soc_dai_link msm8226_dai[] = {
+static struct snd_soc_dai_link msm8226_common_dai[] = {
 	/* FrontEnd DAI Links */
 	{
 		.name = "MSM8226 Media1",
@@ -1289,6 +1289,61 @@
 		.ops = &msm_auxpcm_be_ops,
 		.ignore_suspend = 1
 	},
+	/* Incall Record Uplink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_TX,
+		.stream_name = "Voice Uplink Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.32772",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	/* Incall Record Downlink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_RX,
+		.stream_name = "Voice Downlink Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.32771",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	/* Incall Music BACK END DAI Link */
+	{
+		.name = LPASS_BE_VOICE_PLAYBACK_TX,
+		.stream_name = "Voice Farend Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.32773",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	/* Incall Music 2 BACK END DAI Link */
+	{
+		.name = LPASS_BE_VOICE2_PLAYBACK_TX,
+		.stream_name = "Voice2 Farend Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.32770",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+};
+
+static struct snd_soc_dai_link msm8226_9306_dai[] = {
 	/* Backend DAI Links */
 	{
 		.name = LPASS_BE_SLIMBUS_0_RX,
@@ -1402,64 +1457,142 @@
 		.ops = &msm8226_be_ops,
 		.ignore_suspend = 1,
 	},
-	/* Incall Record Uplink BACK END DAI Link */
+};
+
+static struct snd_soc_dai_link msm8226_9302_dai[] = {
+	/* Backend DAI Links */
 	{
-		.name = LPASS_BE_INCALL_RECORD_TX,
-		.stream_name = "Voice Uplink Capture",
-		.cpu_dai_name = "msm-dai-q6-dev.32772",
+		.name = LPASS_BE_SLIMBUS_0_RX,
+		.stream_name = "Slimbus Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16384",
 		.platform_name = "msm-pcm-routing",
-		.codec_name     = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
+		.codec_name = "tapan_codec",
+		.codec_dai_name	= "tapan9302_rx1",
 		.no_pcm = 1,
-		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+		.init = &msm_audrx_init,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
+		.ignore_pmdown_time = 1, /* dai link has playback support */
 		.ignore_suspend = 1,
 	},
-	/* Incall Record Downlink BACK END DAI Link */
 	{
-		.name = LPASS_BE_INCALL_RECORD_RX,
-		.stream_name = "Voice Downlink Capture",
-		.cpu_dai_name = "msm-dai-q6-dev.32771",
+		.name = LPASS_BE_SLIMBUS_0_TX,
+		.stream_name = "Slimbus Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16385",
 		.platform_name = "msm-pcm-routing",
-		.codec_name     = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
+		.codec_name = "tapan_codec",
+		.codec_dai_name	= "tapan9302_tx1",
 		.no_pcm = 1,
-		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
 		.ignore_suspend = 1,
 	},
-	/* Incall Music BACK END DAI Link */
 	{
-		.name = LPASS_BE_VOICE_PLAYBACK_TX,
-		.stream_name = "Voice Farend Playback",
-		.cpu_dai_name = "msm-dai-q6-dev.32773",
+		.name = LPASS_BE_SLIMBUS_1_RX,
+		.stream_name = "Slimbus1 Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16386",
 		.platform_name = "msm-pcm-routing",
-		.codec_name     = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-rx",
+		.codec_name = "tapan_codec",
+		.codec_dai_name	= "tapan9302_rx1",
 		.no_pcm = 1,
-		.be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
+		/* dai link has playback support */
+		.ignore_pmdown_time = 1,
 		.ignore_suspend = 1,
 	},
-	/* Incall Music 2 BACK END DAI Link */
 	{
-		.name = LPASS_BE_VOICE2_PLAYBACK_TX,
-		.stream_name = "Voice2 Farend Playback",
-		.cpu_dai_name = "msm-dai-q6-dev.32770",
+		.name = LPASS_BE_SLIMBUS_1_TX,
+		.stream_name = "Slimbus1 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16387",
 		.platform_name = "msm-pcm-routing",
-		.codec_name     = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-rx",
+		.codec_name = "tapan_codec",
+		.codec_dai_name	= "tapan9302_tx1",
 		.no_pcm = 1,
-		.be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_3_RX,
+		.stream_name = "Slimbus3 Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16390",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tapan_codec",
+		.codec_dai_name	= "tapan9302_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
+		/* dai link has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_3_TX,
+		.stream_name = "Slimbus3 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16391",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tapan_codec",
+		.codec_dai_name	= "tapan9302_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_4_RX,
+		.stream_name = "Slimbus4 Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16392",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tapan_codec",
+		.codec_dai_name	= "tapan9302_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
+		/* dai link has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_4_TX,
+		.stream_name = "Slimbus4 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16393",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "tapan_codec",
+		.codec_dai_name	= "tapan9302_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
 		.ignore_suspend = 1,
 	},
 };
 
+static struct snd_soc_dai_link msm8226_9306_dai_links[
+				ARRAY_SIZE(msm8226_common_dai) +
+				ARRAY_SIZE(msm8226_9306_dai)];
+
+static struct snd_soc_dai_link msm8226_9302_dai_links[
+				ARRAY_SIZE(msm8226_common_dai) +
+				ARRAY_SIZE(msm8226_9302_dai)];
+
 struct snd_soc_card snd_soc_card_msm8226 = {
 	.name		= "msm8226-tapan-snd-card",
-	.dai_link	= msm8226_dai,
-	.num_links	= ARRAY_SIZE(msm8226_dai),
+	.dai_link	= msm8226_9306_dai_links,
+	.num_links	= ARRAY_SIZE(msm8226_9306_dai_links),
+};
+
+struct snd_soc_card snd_soc_card_9302_msm8226 = {
+	.name		= "msm8226-tapan9302-snd-card",
+	.dai_link	= msm8226_9302_dai_links,
+	.num_links	= ARRAY_SIZE(msm8226_9302_dai_links),
 };
 
 static int msm8226_dtparse_auxpcm(struct platform_device *pdev,
@@ -1534,7 +1667,7 @@
 		ret = gpio_request(pdata->mclk_gpio, "TAPAN_CODEC_PMIC_MCLK");
 		if (ret) {
 			dev_err(card->dev,
-				"%s: Failed to request taiko mclk gpio %d\n",
+				"%s: Failed to request tapan mclk gpio %d\n",
 				__func__, pdata->mclk_gpio);
 			return ret;
 		}
@@ -1580,9 +1713,36 @@
 	return 0;
 }
 
+static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
+{
+
+	struct snd_soc_card *card;
+
+	if (of_property_read_bool(dev->of_node,
+					"qcom,tapan-codec-9302")) {
+		card = &snd_soc_card_9302_msm8226;
+
+		memcpy(msm8226_9302_dai_links, msm8226_common_dai,
+				sizeof(msm8226_common_dai));
+		memcpy(msm8226_9302_dai_links + ARRAY_SIZE(msm8226_common_dai),
+			msm8226_9302_dai, sizeof(msm8226_9302_dai));
+
+	} else {
+
+		card = &snd_soc_card_msm8226;
+
+		memcpy(msm8226_9306_dai_links, msm8226_common_dai,
+				sizeof(msm8226_common_dai));
+		memcpy(msm8226_9306_dai_links + ARRAY_SIZE(msm8226_common_dai),
+			msm8226_9306_dai, sizeof(msm8226_9306_dai));
+	}
+
+	return card;
+}
+
 static __devinit int msm8226_asoc_machine_probe(struct platform_device *pdev)
 {
-	struct snd_soc_card *card = &snd_soc_card_msm8226;
+	struct snd_soc_card *card;
 	struct msm8226_asoc_mach_data *pdata;
 	int ret;
 	const char *auxpcm_pri_gpio_set = NULL;
@@ -1600,14 +1760,7 @@
 		goto err;
 	}
 
-	/* Parse AUXPCM info from DT */
-	ret = msm8226_dtparse_auxpcm(pdev, &pdata->auxpcm_ctrl,
-					msm_auxpcm_gpio_name);
-	if (ret) {
-		dev_err(&pdev->dev,
-		"%s: Auxpcm pin data parse failed\n", __func__);
-		goto err;
-	}
+	card = populate_snd_card_dailinks(&pdev->dev);
 
 	card->dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
@@ -1649,6 +1802,33 @@
 		goto err;
 	}
 
+	ret = msm8226_prepare_codec_mclk(card);
+	if (ret)
+		goto err1;
+
+	mutex_init(&cdc_mclk_mutex);
+
+	mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node,
+					"qcom,headset-jack-type-NO");
+
+	ret = snd_soc_register_card(card);
+	if (ret == -EPROBE_DEFER)
+		goto err;
+	else if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+			ret);
+		goto err;
+	}
+
+	/* Parse AUXPCM info from DT */
+	ret = msm8226_dtparse_auxpcm(pdev, &pdata->auxpcm_ctrl,
+					msm_auxpcm_gpio_name);
+	if (ret) {
+		dev_err(&pdev->dev,
+		"%s: Auxpcm pin data parse failed\n", __func__);
+		goto err;
+	}
+
 	vdd_spkr_gpio = of_get_named_gpio(pdev->dev.of_node,
 				"qcom,cdc-vdd-spkr-gpios", 0);
 	if (vdd_spkr_gpio < 0) {
@@ -1686,22 +1866,8 @@
 		}
 	}
 
-	mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node,
-					"qcom,headset-jack-type-NO");
 	msm8226_setup_hs_jack(pdev, pdata);
 
-	ret = msm8226_prepare_codec_mclk(card);
-	if (ret)
-		goto err_lineout_spkr;
-
-	ret = snd_soc_register_card(card);
-	if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-			ret);
-		goto err_lineout_spkr;
-	}
-	mutex_init(&cdc_mclk_mutex);
-
 	ret = of_property_read_string(pdev->dev.of_node,
 			"qcom,prim-auxpcm-gpio-set", &auxpcm_pri_gpio_set);
 	if (ret) {
@@ -1747,6 +1913,7 @@
 		gpio_free(pdata->mclk_gpio);
 		pdata->mclk_gpio = 0;
 	}
+err1:
 	devm_kfree(&pdev->dev, pdata);
 	return ret;
 }
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 769b8eb..e612eec 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -269,7 +269,9 @@
 static void msm8974_liquid_ext_ult_spk_power_amp_enable(u32 on)
 {
 	if (on) {
-		regulator_enable(ext_spk_amp_regulator);
+		if (regulator_enable(ext_spk_amp_regulator))
+			pr_err("%s: enable failed ext_spk_amp_reg\n",
+				__func__);
 		gpio_direction_output(ext_ult_spk_amp_gpio, 1);
 		/* time takes enable the external power class AB amplifier */
 		usleep_range(EXT_CLASS_AB_EN_DELAY,
@@ -289,7 +291,9 @@
 static void msm8974_liquid_ext_spk_power_amp_enable(u32 on)
 {
 	if (on) {
-		regulator_enable(ext_spk_amp_regulator);
+		if (regulator_enable(ext_spk_amp_regulator))
+			pr_err("%s: enable failed ext_spk_amp_reg\n",
+				__func__);
 		gpio_direction_output(ext_spk_amp_gpio, on);
 		/*time takes enable the external power amplifier*/
 		usleep_range(EXT_CLASS_D_EN_DELAY,
@@ -1625,6 +1629,7 @@
 		pr_err("%s: Failed to register adsp state notifier\n",
 		       __func__);
 		err = -EFAULT;
+		taiko_hs_detect_exit(codec);
 		goto out;
 	}
 
@@ -2659,24 +2664,6 @@
 		return -ENOMEM;
 	}
 
-	/* Parse Primary AUXPCM info from DT */
-	ret = msm8974_dtparse_auxpcm(pdev, &pdata->pri_auxpcm_ctrl,
-					msm_prim_auxpcm_gpio_name);
-	if (ret) {
-		dev_err(&pdev->dev,
-		"%s: Primary Auxpcm pin data parse failed\n", __func__);
-		goto err;
-	}
-
-	/* Parse Secondary AUXPCM info from DT */
-	ret = msm8974_dtparse_auxpcm(pdev, &pdata->sec_auxpcm_ctrl,
-					msm_sec_auxpcm_gpio_name);
-	if (ret) {
-		dev_err(&pdev->dev,
-		"%s: Secondary Auxpcm pin data parse failed\n", __func__);
-		goto err;
-	}
-
 	card->dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
 	snd_soc_card_set_drvdata(card, pdata);
@@ -2717,26 +2704,9 @@
 		goto err;
 	}
 
-	ext_ult_lo_amp_gpio = of_get_named_gpio(pdev->dev.of_node,
-						prop_name_ult_lo_gpio, 0);
-	if (!gpio_is_valid(ext_ult_lo_amp_gpio)) {
-		dev_dbg(&pdev->dev,
-			"Couldn't find %s property in node %s, %d\n",
-			prop_name_ult_lo_gpio, pdev->dev.of_node->full_name,
-			ext_ult_lo_amp_gpio);
-	} else {
-		ret = gpio_request(ext_ult_lo_amp_gpio, "US_AMP_GPIO");
-		if (ret) {
-			dev_err(card->dev,
-				"%s: Failed to request US amp gpio %d\n",
-				__func__, ext_ult_lo_amp_gpio);
-			goto err;
-		}
-	}
-
 	ret = msm8974_prepare_codec_mclk(card);
 	if (ret)
-		goto err1;
+		goto err;
 
 	if (of_property_read_bool(pdev->dev.of_node, "qcom,hdmi-audio-rx")) {
 		dev_info(&pdev->dev, "%s(): hdmi audio support present\n",
@@ -2756,6 +2726,58 @@
 		card->dai_link	= msm8974_common_dai_links;
 		card->num_links	= ARRAY_SIZE(msm8974_common_dai_links);
 	}
+	mutex_init(&cdc_mclk_mutex);
+	atomic_set(&prim_auxpcm_rsc_ref, 0);
+	atomic_set(&sec_auxpcm_rsc_ref, 0);
+	spdev = pdev;
+	ext_spk_amp_regulator = NULL;
+	msm8974_liquid_dock_dev = NULL;
+
+	ret = snd_soc_register_card(card);
+	if (ret == -EPROBE_DEFER)
+		goto err;
+	else if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+			ret);
+		goto err;
+	}
+
+	/* Parse Primary AUXPCM info from DT */
+	ret = msm8974_dtparse_auxpcm(pdev, &pdata->pri_auxpcm_ctrl,
+					msm_prim_auxpcm_gpio_name);
+	if (ret) {
+		dev_err(&pdev->dev,
+		"%s: Primary Auxpcm pin data parse failed\n", __func__);
+		goto err;
+	}
+
+	/* Parse Secondary AUXPCM info from DT */
+	ret = msm8974_dtparse_auxpcm(pdev, &pdata->sec_auxpcm_ctrl,
+					msm_sec_auxpcm_gpio_name);
+	if (ret) {
+		dev_err(&pdev->dev,
+		"%s: Secondary Auxpcm pin data parse failed\n", __func__);
+		goto err;
+	}
+
+
+	ext_ult_lo_amp_gpio = of_get_named_gpio(pdev->dev.of_node,
+						prop_name_ult_lo_gpio, 0);
+	if (!gpio_is_valid(ext_ult_lo_amp_gpio)) {
+		dev_dbg(&pdev->dev,
+			"Couldn't find %s property in node %s, %d\n",
+			prop_name_ult_lo_gpio, pdev->dev.of_node->full_name,
+			ext_ult_lo_amp_gpio);
+	} else {
+		ret = gpio_request(ext_ult_lo_amp_gpio, "US_AMP_GPIO");
+		if (ret) {
+			dev_err(card->dev,
+				"%s: Failed to request US amp gpio %d\n",
+				__func__, ext_ult_lo_amp_gpio);
+			goto err;
+		}
+	}
+
 
 	pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
 				"qcom,us-euro-gpios", 0);
@@ -2774,20 +2796,6 @@
 		dev_err(&pdev->dev, "msm8974_prepare_us_euro failed (%d)\n",
 			ret);
 
-	mutex_init(&cdc_mclk_mutex);
-	atomic_set(&prim_auxpcm_rsc_ref, 0);
-	atomic_set(&sec_auxpcm_rsc_ref, 0);
-	spdev = pdev;
-	ext_spk_amp_regulator = NULL;
-	msm8974_liquid_dock_dev = NULL;
-
-	ret = snd_soc_register_card(card);
-	if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-			ret);
-		goto err1;
-	}
-
 	ret = of_property_read_string(pdev->dev.of_node,
 			"qcom,prim-auxpcm-gpio-set", &auxpcm_pri_gpio_set);
 	if (ret) {
@@ -2820,7 +2828,8 @@
 	return 0;
 
 err1:
-	gpio_free(ext_ult_lo_amp_gpio);
+	if (ext_ult_lo_amp_gpio >= 0)
+		gpio_free(ext_ult_lo_amp_gpio);
 	ext_ult_lo_amp_gpio = -1;
 err:
 	if (pdata->mclk_gpio > 0) {
@@ -2835,6 +2844,7 @@
 		gpio_free(pdata->us_euro_gpio);
 		pdata->us_euro_gpio = 0;
 	}
+	mutex_destroy(&cdc_mclk_mutex);
 	devm_kfree(&pdev->dev, pdata);
 	return ret;
 }
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 9150751..bc36aae 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -39,15 +39,40 @@
 #define EXT_CLASS_D_DIS_DELAY 3000
 #define EXT_CLASS_D_DELAY_DELTA 2000
 
+#define CDC_EXT_CLK_RATE 9600000
+#define WCD9XXX_MBHC_DEF_BUTTONS 8
+#define WCD9XXX_MBHC_DEF_RLOADS 5
 
 static int msm_btsco_rate = BTSCO_RATE_8KHZ;
 static int msm_btsco_ch = 1;
 
 static int msm_proxy_rx_ch = 2;
-static struct snd_soc_jack hs_jack;
 static struct platform_device *spdev;
 static int ext_spk_amp_gpio = -1;
 
+/* pointers for digital codec register mappings */
+static void __iomem *pcbcr;
+static void __iomem *prcgr;
+
+static int msm_sec_mi2s_rx_ch = 1;
+static int msm_pri_mi2s_tx_ch = 1;
+
+static void *def_msm8x10_wcd_mbhc_cal(void);
+static int msm8x10_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+					bool dapm);
+static struct wcd9xxx_mbhc_config mbhc_cfg = {
+	.read_fw_bin = false,
+	.calibration = NULL,
+	.micbias = MBHC_MICBIAS1,
+	.mclk_cb_fn = msm8x10_enable_codec_ext_clk,
+	.mclk_rate = CDC_EXT_CLK_RATE,
+	.gpio = 0,
+	.gpio_irq = 0,
+	.gpio_level_insert = 0,
+	.detect_extn_cable = false,
+	.insert_detect = true,
+	.swap_gnd_mic = NULL,
+};
 
 /*
  * There is limitation for the clock root selection from
@@ -160,10 +185,9 @@
 
 static int msm_config_mclk(u16 port_id, struct afe_digital_clk_cfg *cfg)
 {
-	iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+	iowrite32(0x1, pcbcr);
 	/* Set the update bit to make the settings go through */
-	iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4));
-
+	iowrite32(0x1, prcgr);
 	return 0;
 
 }
@@ -180,10 +204,43 @@
 	return 0;
 }
 
+static int msm_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s(): channel:%d\n", __func__, msm_pri_mi2s_tx_ch);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_sec_mi2s_rx_ch;
+
+	return 0;
+}
+
+static int msm_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s(), channel:%d\n", __func__, msm_pri_mi2s_tx_ch);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_pri_mi2s_tx_ch;
+
+	return 0;
+}
+
+
 static const char *const btsco_rate_text[] = {"8000", "16000"};
 static const struct soc_enum msm_btsco_enum[] = {
 	SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
 };
+static const char *const sec_mi2s_rx_ch_text[] = {"One", "Two"};
+static const char *const pri_mi2s_tx_ch_text[] = {"One", "Two"};
 
 static int msm_btsco_rate_get(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
@@ -213,6 +270,43 @@
 	return 0;
 }
 
+static int msm_sec_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_sec_mi2s_rx_ch  = %d\n", __func__,
+		 msm_sec_mi2s_rx_ch);
+	ucontrol->value.integer.value[0] = msm_sec_mi2s_rx_ch - 1;
+	return 0;
+}
+
+static int msm_sec_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_sec_mi2s_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_sec_mi2s_rx_ch = %d\n", __func__,
+		 msm_sec_mi2s_rx_ch);
+	return 1;
+}
+
+static int msm_pri_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_pri_mi2s_tx_ch  = %d\n", __func__,
+		 msm_pri_mi2s_tx_ch);
+	ucontrol->value.integer.value[0] = msm_pri_mi2s_tx_ch - 1;
+	return 0;
+}
+
+static int msm_pri_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_pri_mi2s_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_pri_mi2s_tx_ch = %d\n", __func__, msm_pri_mi2s_tx_ch);
+	return 1;
+}
+
 static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 					struct snd_pcm_hw_params *params)
 {
@@ -351,9 +445,18 @@
 	return ret;
 }
 
+static const struct soc_enum msm_snd_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, sec_mi2s_rx_ch_text),
+	SOC_ENUM_SINGLE_EXT(2, pri_mi2s_tx_ch_text),
+};
+
 static const struct snd_kcontrol_new msm_snd_controls[] = {
 	SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
 		     msm_btsco_rate_get, msm_btsco_rate_put),
+	SOC_ENUM_EXT("MI2S_RX Channels", msm_snd_enum[0],
+			msm_sec_mi2s_rx_ch_get, msm_sec_mi2s_rx_ch_put),
+	SOC_ENUM_EXT("MI2S_TX Channels", msm_snd_enum[1],
+			msm_pri_mi2s_tx_ch_get, msm_pri_mi2s_tx_ch_put),
 };
 
 static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
@@ -366,6 +469,19 @@
 
 	pr_debug("%s(),dev_name%s\n", __func__, dev_name(cpu_dai->dev));
 	msm8x10_ext_spk_power_amp_init();
+
+	mbhc_cfg.calibration = def_msm8x10_wcd_mbhc_cal();
+	if (mbhc_cfg.calibration) {
+		ret = msm8x10_wcd_hs_detect(codec, &mbhc_cfg);
+		if (ret) {
+			pr_err("%s: msm8x10_wcd_hs_detect failed\n", __func__);
+			goto exit;
+		}
+	} else {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
 	snd_soc_dapm_new_controls(dapm, msm8x10_dapm_widgets,
 				ARRAY_SIZE(msm8x10_dapm_widgets));
 
@@ -377,15 +493,92 @@
 	if (ret < 0)
 		return ret;
 
-	ret = snd_soc_jack_new(codec, "Headset Jack",
-			SND_JACK_HEADSET, &hs_jack);
-	if (ret) {
-		pr_err("%s: Failed to create headset jack\n", __func__);
-	}
+exit:
+	if (gpio_is_valid(ext_spk_amp_gpio))
+		gpio_free(ext_spk_amp_gpio);
 
 	return ret;
 }
 
+static void *def_msm8x10_wcd_mbhc_cal(void)
+{
+	void *msm8x10_wcd_cal;
+	struct wcd9xxx_mbhc_btn_detect_cfg *btn_cfg;
+	u16 *btn_low, *btn_high;
+	u8 *n_ready, *n_cic, *gain;
+
+	msm8x10_wcd_cal = kzalloc(WCD9XXX_MBHC_CAL_SIZE(
+						WCD9XXX_MBHC_DEF_BUTTONS,
+						WCD9XXX_MBHC_DEF_RLOADS),
+					GFP_KERNEL);
+	if (!msm8x10_wcd_cal) {
+		pr_err("%s: out of memory\n", __func__);
+		return NULL;
+	}
+
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_GENERAL_PTR(msm8x10_wcd_cal)->X) = (Y))
+	S(t_ldoh, 100);
+	S(t_bg_fast_settle, 100);
+	S(t_shutdown_plug_rem, 255);
+	S(mbhc_nsa, 2);
+	S(mbhc_navg, 128);
+#undef S
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_PLUG_DET_PTR(msm8x10_wcd_cal)->X) = (Y))
+	S(mic_current, MSM8X10_WCD_PID_MIC_5_UA);
+	S(hph_current, MSM8X10_WCD_PID_MIC_5_UA);
+	S(t_mic_pid, 100);
+	S(t_ins_complete, 250);
+	S(t_ins_retry, 200);
+#undef S
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(msm8x10_wcd_cal)->X) = (Y))
+	S(v_no_mic, 30);
+	S(v_hs_max, 1650);
+#undef S
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_BTN_DET_PTR(msm8x10_wcd_cal)->X) = (Y))
+	S(c[0], 62);
+	S(c[1], 124);
+	S(nc, 1);
+	S(n_meas, 5);
+	S(mbhc_nsc, 10);
+	S(n_btn_meas, 1);
+	S(n_btn_con, 2);
+	S(num_btn, WCD9XXX_MBHC_DEF_BUTTONS);
+	S(v_btn_press_delta_sta, 100);
+	S(v_btn_press_delta_cic, 50);
+#undef S
+	btn_cfg = WCD9XXX_MBHC_CAL_BTN_DET_PTR(msm8x10_wcd_cal);
+	btn_low = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_V_BTN_LOW);
+	btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg,
+					       MBHC_BTN_DET_V_BTN_HIGH);
+	btn_low[0] = -50;
+	btn_high[0] = 10;
+	btn_low[1] = 11;
+	btn_high[1] = 52;
+	btn_low[2] = 53;
+	btn_high[2] = 94;
+	btn_low[3] = 95;
+	btn_high[3] = 133;
+	btn_low[4] = 134;
+	btn_high[4] = 171;
+	btn_low[5] = 172;
+	btn_high[5] = 208;
+	btn_low[6] = 209;
+	btn_high[6] = 244;
+	btn_low[7] = 245;
+	btn_high[7] = 330;
+	n_ready = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_READY);
+	n_ready[0] = 80;
+	n_ready[1] = 68;
+	n_cic = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_CIC);
+	n_cic[0] = 60;
+	n_cic[1] = 47;
+	gain = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_GAIN);
+	gain[0] = 11;
+	gain[1] = 14;
+
+	return msm8x10_wcd_cal;
+}
+
 static int msm_proxy_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 					struct snd_pcm_hw_params *params)
 {
@@ -635,7 +828,7 @@
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
 		.init = &msm_audrx_init,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.be_hw_params_fixup = msm_rx_be_hw_params_fixup,
 		.ops = &msm8x10_mi2s_be_ops,
 		.ignore_suspend = 1,
 	},
@@ -648,7 +841,7 @@
 		.codec_dai_name = "msm8x10_wcd_i2s_tx1",
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.be_hw_params_fixup = msm_tx_be_hw_params_fixup,
 		.ops = &msm8x10_mi2s_be_ops,
 		.ignore_suspend = 1,
 	},
@@ -801,16 +994,38 @@
 	if (ret)
 		goto err;
 
+	mutex_init(&cdc_mclk_mutex);
+	pcbcr = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4);
+	if (!pcbcr) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+	prcgr = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4);
+	if (!prcgr) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+	atomic_set(&mclk_rsc_ref, 0);
+	mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node,
+						"qcom,headset-jack-type-NC");
+
 	spdev = pdev;
+
 	ret = snd_soc_register_card(card);
-	if (ret) {
+	if (ret == -EPROBE_DEFER)
+		goto err1;
+	else if (ret) {
 		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
 			ret);
-		goto err;
+		goto err1;
 	}
-	mutex_init(&cdc_mclk_mutex);
-	atomic_set(&mclk_rsc_ref, 0);
 	return 0;
+err1:
+	mutex_destroy(&cdc_mclk_mutex);
+	if (pcbcr)
+		iounmap(pcbcr);
+	if (prcgr)
+		iounmap(prcgr);
 err:
 	return ret;
 }
@@ -823,6 +1038,9 @@
 		gpio_free(ext_spk_amp_gpio);
 	snd_soc_unregister_card(card);
 	mutex_destroy(&cdc_mclk_mutex);
+
+	iounmap(pcbcr);
+	iounmap(prcgr);
 	return 0;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index de60430..62fe6d2 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -371,8 +371,12 @@
 		msm_send_eq_values(fedai_id);
 	topology = get_topology(path_type);
 	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
-		if (test_bit(fedai_id, &msm_bedais[i].fe_sessions) && perf_mode)
-			set_bit(fedai_id, &msm_bedais[i].perf_mode);
+		if (test_bit(fedai_id, &msm_bedais[i].fe_sessions)) {
+			if (perf_mode)
+				set_bit(fedai_id, &msm_bedais[i].perf_mode);
+			else
+				clear_bit(fedai_id, &msm_bedais[i].perf_mode);
+		}
 		if (!is_be_dai_extproc(i) &&
 		   (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
 		   (msm_bedais[i].active) &&
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index b1f968d..d99812f 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -522,7 +522,6 @@
 				/* Should only come here if there is an APR */
 				/* error or malformed APR packet. Otherwise */
 				/* response will be returned as */
-				/* ADM_CMDRSP_SHARED_MEM_MAP_REGIONS */
 				if (payload[1] != 0) {
 					pr_err("%s: ADM map error, resuming\n",
 						__func__);
@@ -967,11 +966,9 @@
 		open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
 		open.flags = 0x00;
 		if (perf_mode) {
-			open.flags |= ADM_LOW_LATENCY_DEVICE_SESSION <<
-				ADM_BIT_SHIFT_DEVICE_PERF_MODE_FLAG;
+			open.flags |= ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION;
 		} else {
-			open.flags |= ADM_LEGACY_DEVICE_SESSION <<
-				ADM_BIT_SHIFT_DEVICE_PERF_MODE_FLAG;
+			open.flags |= ADM_LEGACY_DEVICE_SESSION;
 		}
 
 		open.mode_of_operation = path;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 6a34470..1abc47d 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1504,11 +1504,9 @@
 	open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
 	open.mode_flags = 0x00;
 	if (ac->perf_mode)
-		open.mode_flags |= (ASM_LOW_LATENCY_STREAM_SESSION <<
-				ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_WRITE);
+		open.mode_flags |= ASM_ULTRA_LOW_LATENCY_STREAM_SESSION;
 	else
-		open.mode_flags |= (ASM_LEGACY_STREAM_SESSION <<
-				ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_WRITE);
+		open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
 
 	/* source endpoint : matrix */
 	open.sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 60dd522..c863497 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -1890,20 +1890,20 @@
 	if (!common.apr_q6_cvs) {
 		pr_err("%s: apr_cvs is NULL\n", __func__);
 
-		ret = -EINVAL;
+		ret = -EPERM;
 		goto done;
 	}
 
 	if (!common.cal_mem_handle) {
-		pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+		pr_err("%s: Cal mem handle is NULL\n", __func__);
+		ret = -EPERM;
 		goto done;
 	}
 
 	get_vocstrm_cal(&cal_block);
 	if (cal_block.cal_size == 0) {
 		pr_err("%s: CVS cal size is 0\n", __func__);
-
+		ret = -EPERM;
 		goto done;
 	}
 
@@ -1932,7 +1932,7 @@
 	ret = apr_send_pkt(common.apr_q6_cvs, (uint32_t *) &cvs_reg_cal_cmd);
 	if (ret < 0) {
 		pr_err("%s: Error %d registering CVS cal\n", __func__, ret);
-
+		ret = -EINVAL;
 		goto done;
 	}
 	ret = wait_event_timeout(v->cvs_wait,
@@ -1940,7 +1940,7 @@
 				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: Command timeout\n", __func__);
-
+		ret = -EINVAL;
 		goto done;
 	}
 
@@ -1965,19 +1965,22 @@
 	if (!common.apr_q6_cvs) {
 		pr_err("%s: apr_cvs is NULL\n", __func__);
 
-		ret = -EINVAL;
+		ret = -EPERM;
 		goto done;
 	}
 
 	if (!common.cal_mem_handle) {
-		pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+		pr_err("%s: Cal mem handle is NULL\n", __func__);
+		ret = -EPERM;
 		goto done;
 	}
 
 	get_vocstrm_cal(&cal_block);
-	if (cal_block.cal_size == 0)
+	if (cal_block.cal_size == 0) {
+		pr_err("%s: CVS cal size is 0\n", __func__);
+		ret = -EPERM;
 		goto done;
+	}
 
 	cvs_dereg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -1994,7 +1997,7 @@
 	ret = apr_send_pkt(common.apr_q6_cvs, (uint32_t *) &cvs_dereg_cal_cmd);
 	if (ret < 0) {
 		pr_err("%s: Error %d de-registering CVS cal\n", __func__, ret);
-
+		ret = -EINVAL;
 		goto done;
 	}
 	ret = wait_event_timeout(v->cvs_wait,
@@ -2002,7 +2005,7 @@
 				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: Command  timeout\n", __func__);
-
+		ret = -EINVAL;
 		goto done;
 	}
 
@@ -2028,20 +2031,20 @@
 	if (!common.apr_q6_cvp) {
 		pr_err("%s: apr_cvp is NULL\n", __func__);
 
-		ret = -EINVAL;
+		ret = -EPERM;
 		goto done;
 	}
 
 	if (!common.cal_mem_handle) {
-		pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+		pr_err("%s: Cal mem handle is NULL\n", __func__);
+		ret = -EPERM;
 		goto done;
 	}
 
 	get_vocproc_dev_cfg_cal(&cal_block);
 	if (cal_block.cal_size == 0) {
 		pr_err("%s: CVP cal size is 0\n", __func__);
-
+		ret = -EPERM;
 		goto done;
 	}
 
@@ -2066,7 +2069,7 @@
 	if (ret < 0) {
 		pr_err("%s: Error %d registering CVP dev cfg cal\n",
 		       __func__, ret);
-
+		ret = -EINVAL;
 		goto done;
 	}
 	ret = wait_event_timeout(v->cvp_wait,
@@ -2074,7 +2077,7 @@
 				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: Command timeout\n", __func__);
-
+		ret = -EINVAL;
 		goto done;
 	}
 
@@ -2099,19 +2102,22 @@
 	if (!common.apr_q6_cvp) {
 		pr_err("%s: apr_cvp is NULL\n", __func__);
 
-		ret = -EINVAL;
+		ret = -EPERM;
 		goto done;
 	}
 
 	if (!common.cal_mem_handle) {
-		pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+		pr_err("%s: Cal mem handle is NULL\n", __func__);
+		ret = -EPERM;
 		goto done;
 	}
 
 	get_vocproc_dev_cfg_cal(&cal_block);
-	if (cal_block.cal_size == 0)
+	if (cal_block.cal_size == 0) {
+		pr_err("%s: CVP cal size is 0\n", __func__);
+		ret = -EPERM;
 		goto done;
+	}
 
 	cvp_dereg_dev_cfg_cmd.hdr.hdr_field =
 				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -2131,7 +2137,7 @@
 	if (ret < 0) {
 		pr_err("%s: Error %d de-registering CVP dev cfg cal\n",
 		       __func__, ret);
-
+		ret = -EINVAL;
 		goto done;
 	}
 	ret = wait_event_timeout(v->cvp_wait,
@@ -2139,7 +2145,7 @@
 				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: Command timeout\n", __func__);
-
+		ret = -EINVAL;
 		goto done;
 	}
 
@@ -2164,20 +2170,20 @@
 	if (!common.apr_q6_cvp) {
 		pr_err("%s: apr_cvp is NULL\n", __func__);
 
-		ret = -EINVAL;
+		ret = -EPERM;
 		goto done;
 	}
 
 	if (!common.cal_mem_handle) {
-		pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+		pr_err("%s: Cal mem handle is NULL\n", __func__);
+		ret = -EPERM;
 		goto done;
 	}
 
 	get_vocproc_cal(&cal_block);
 	if (cal_block.cal_size == 0) {
 		pr_err("%s: CVP cal size is 0\n", __func__);
-
+		ret = -EPERM;
 		goto done;
 	}
 
@@ -2206,7 +2212,7 @@
 	ret = apr_send_pkt(common.apr_q6_cvp, (uint32_t *) &cvp_reg_cal_cmd);
 	if (ret < 0) {
 		pr_err("%s: Error %d registering CVP cal\n", __func__, ret);
-
+		ret = -EINVAL;
 		goto done;
 	}
 	ret = wait_event_timeout(v->cvp_wait,
@@ -2214,7 +2220,7 @@
 				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: Command timeout\n", __func__);
-
+		ret = -EINVAL;
 		goto done;
 	}
 
@@ -2239,19 +2245,22 @@
 	if (!common.apr_q6_cvp) {
 		pr_err("%s: apr_cvp is NULL.\n", __func__);
 
-		ret = -EINVAL;
+		ret = -EPERM;
 		goto done;
 	}
 
 	if (!common.cal_mem_handle) {
-		pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+		pr_err("%s: Cal mem handle is NULL\n", __func__);
+		ret = -EPERM;
 		goto done;
 	}
 
 	get_vocproc_cal(&cal_block);
-	if (cal_block.cal_size == 0)
+	if (cal_block.cal_size == 0) {
+		pr_err("%s: CVP vol cal size is 0\n", __func__);
+		ret = -EPERM;
 		goto done;
+	}
 
 	cvp_dereg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -2268,7 +2277,7 @@
 	ret = apr_send_pkt(common.apr_q6_cvp, (uint32_t *) &cvp_dereg_cal_cmd);
 	if (ret < 0) {
 		pr_err("%s: Error %d de-registering CVP cal\n", __func__, ret);
-
+		ret = -EINVAL;
 		goto done;
 	}
 	ret = wait_event_timeout(v->cvp_wait,
@@ -2276,7 +2285,7 @@
 				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: Command timeout\n", __func__);
-
+		ret = -EINVAL;
 		goto done;
 	}
 
@@ -2301,20 +2310,20 @@
 	if (!common.apr_q6_cvp) {
 		pr_err("%s: apr_cvp is NULL\n", __func__);
 
-		ret = -EINVAL;
+		ret = -EPERM;
 		goto done;
 	}
 
 	if (!common.cal_mem_handle) {
-		pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+		pr_err("%s: Cal mem handle is NULL\n", __func__);
+		ret = -EPERM;
 		goto done;
 	}
 
 	get_vocvol_cal(&cal_block);
 	if (cal_block.cal_size == 0) {
 		pr_err("%s: CVP vol cal size is 0\n", __func__);
-
+		ret = -EPERM;
 		goto done;
 	}
 
@@ -2346,7 +2355,7 @@
 			   (uint32_t *) &cvp_reg_vol_cal_cmd);
 	if (ret < 0) {
 		pr_err("%s: Error %d registering CVP vol cal\n", __func__, ret);
-
+		ret = -EINVAL;
 		goto done;
 	}
 	ret = wait_event_timeout(v->cvp_wait,
@@ -2354,7 +2363,7 @@
 				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: Command timeout\n", __func__);
-
+		ret = -EINVAL;
 		goto done;
 	}
 
@@ -2379,19 +2388,22 @@
 	if (!common.apr_q6_cvp) {
 		pr_err("%s: apr_cvp is NULL\n", __func__);
 
-		ret = -EINVAL;
+		ret = -EPERM;
 		goto done;
 	}
 
 	if (!common.cal_mem_handle) {
-		pr_debug("%s: Cal mem handle is NULL\n", __func__);
-
+		pr_err("%s: Cal mem handle is NULL\n", __func__);
+		ret = -EPERM;
 		goto done;
 	}
 
 	get_vocvol_cal(&cal_block);
-	if (cal_block.cal_size == 0)
+	if (cal_block.cal_size == 0) {
+		pr_err("%s: CVP vol cal size is 0\n", __func__);
+		ret = -EPERM;
 		goto done;
+	}
 
 	cvp_dereg_vol_cal_cmd.hdr.hdr_field =
 			APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -2411,7 +2423,7 @@
 	if (ret < 0) {
 		pr_err("%s: Error %d de-registering CVP vol cal\n",
 		       __func__, ret);
-
+		ret = -EINVAL;
 		goto done;
 	}
 	ret = wait_event_timeout(v->cvp_wait,
@@ -2419,7 +2431,7 @@
 				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: Command timeout\n", __func__);
-
+		ret = -EINVAL;
 		goto done;
 	}
 
@@ -2430,6 +2442,7 @@
 int voc_register_vocproc_vol_table(void)
 {
 	int			result = 0;
+	int			result2 = 0;
 	int			i;
 	struct voice_data	*v = NULL;
 	pr_debug("%s\n", __func__);
@@ -2440,17 +2453,17 @@
 
 		mutex_lock(&v->lock);
 		if (is_voc_state_active(v->voc_state)) {
-			result = voice_send_cvp_register_vol_cal_cmd(v);
-			if (result) {
+			result2 = voice_send_cvp_register_vol_cal_cmd(v);
+			if (result2 < 0) {
 				pr_err("%s: Failed to register vocvol table for session 0x%x!\n",
 					__func__, v->session_id);
-				mutex_unlock(&v->lock);
-				goto done;
+				result = result2;
+				/* Still try to register other sessions */
 			}
 		}
 		mutex_unlock(&v->lock);
 	}
-done:
+
 	mutex_unlock(&common.common_lock);
 	return result;
 }
@@ -2458,6 +2471,7 @@
 int voc_deregister_vocproc_vol_table(void)
 {
 	int			result = 0;
+	int			success = 0;
 	int			i;
 	struct voice_data	*v = NULL;
 	pr_debug("%s\n", __func__);
@@ -2469,17 +2483,25 @@
 		mutex_lock(&v->lock);
 		if (is_voc_state_active(v->voc_state)) {
 			result = voice_send_cvp_deregister_vol_cal_cmd(v);
-			if (result) {
+			if (result < 0) {
 				pr_err("%s: Failed to deregister vocvol table for session 0x%x!\n",
 					__func__, v->session_id);
 				mutex_unlock(&v->lock);
+				mutex_unlock(&common.common_lock);
+				if (success) {
+					pr_err("%s: Try to re-register all deregistered sessions!\n",
+						__func__);
+					voc_register_vocproc_vol_table();
+				}
 				goto done;
+			} else {
+				success = 1;
 			}
 		}
 		mutex_unlock(&v->lock);
 	}
-done:
 	mutex_unlock(&common.common_lock);
+done:
 	return result;
 }
 
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 79016b5..de98feb 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -55,7 +55,6 @@
 #endif
 
 static DEFINE_MUTEX(client_mutex);
-static LIST_HEAD(card_list);
 static LIST_HEAD(dai_list);
 static LIST_HEAD(platform_list);
 static LIST_HEAD(codec_list);
@@ -850,15 +849,9 @@
 	struct snd_soc_dai *codec_dai, *cpu_dai;
 	const char *platform_name;
 
-	if (rtd->complete)
-		return 1;
 	dev_dbg(card->dev, "binding %s at idx %d\n", dai_link->name, num);
 
-	/* do we already have the CPU DAI for this link ? */
-	if (rtd->cpu_dai) {
-		goto find_codec;
-	}
-	/* no, then find CPU DAI from registered DAIs*/
+	/* Find CPU DAI from registered DAIs*/
 	list_for_each_entry(cpu_dai, &dai_list, list) {
 		if (dai_link->cpu_dai_of_node) {
 			if (cpu_dai->dev->of_node != dai_link->cpu_dai_of_node)
@@ -869,15 +862,13 @@
 		}
 
 		rtd->cpu_dai = cpu_dai;
-		goto find_codec;
 	}
-	dev_dbg(card->dev, "CPU DAI %s not registered\n",
-			dai_link->cpu_dai_name);
 
-find_codec:
-	/* do we already have the CODEC for this link ? */
-	if (rtd->codec) {
-		goto find_platform;
+	if (!rtd->cpu_dai) {
+		dev_dbg(card->dev, "CPU DAI %s not registered\n",
+			dai_link->cpu_dai_name);
+		return -EPROBE_DEFER;
+
 	}
 
 	/* no, then find CODEC from registered CODECs*/
@@ -902,21 +893,21 @@
 					dai_link->codec_dai_name)) {
 
 				rtd->codec_dai = codec_dai;
-				goto find_platform;
 			}
 		}
-		dev_dbg(card->dev, "CODEC DAI %s not registered\n",
+		if (!rtd->codec_dai) {
+			dev_dbg(card->dev, "CODEC DAI %s not registered\n",
 				dai_link->codec_dai_name);
+			return -EPROBE_DEFER;
+		}
 
-		goto find_platform;
 	}
-	dev_dbg(card->dev, "CODEC %s not registered\n",
-			dai_link->codec_name);
 
-find_platform:
-	/* do we need a platform? */
-	if (rtd->platform)
-		goto out;
+	if (!rtd->codec) {
+		dev_dbg(card->dev, "CODEC %s not registered\n",
+			dai_link->codec_name);
+		return -EPROBE_DEFER;
+	}
 
 	/* if there's no platform we match on the empty platform */
 	platform_name = dai_link->platform_name;
@@ -935,20 +926,17 @@
 		}
 
 		rtd->platform = platform;
-		goto out;
 	}
-
-	dev_dbg(card->dev, "platform %s not registered\n",
+	if (!rtd->platform) {
+		dev_dbg(card->dev, "platform %s not registered\n",
 			dai_link->platform_name);
+
+		return -EPROBE_DEFER;
+	}
+	card->num_rtd++;
+
 	return 0;
 
-out:
-	/* mark rtd as complete if we found all 4 of our client devices */
-	if (rtd->codec && rtd->codec_dai && rtd->platform && rtd->cpu_dai) {
-		rtd->complete = 1;
-		card->num_rtd++;
-	}
-	return 1;
 }
 
 static void soc_remove_codec(struct snd_soc_codec *codec)
@@ -1399,6 +1387,20 @@
 }
 #endif
 
+static int soc_check_aux_dev(struct snd_soc_card *card, int num)
+{
+	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
+	struct snd_soc_codec *codec;
+
+	/* find CODEC from registered CODECs*/
+	list_for_each_entry(codec, &codec_list, list) {
+		if (!strcmp(codec->name, aux_dev->codec_name))
+			return 0;
+	}
+
+	return -EPROBE_DEFER;
+}
+
 static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
 {
 	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
@@ -1419,7 +1421,7 @@
 	}
 	/* codec not found */
 	dev_err(card->dev, "asoc: codec %s not found", aux_dev->codec_name);
-	goto out;
+	return -EPROBE_DEFER;
 
 found:
 	ret = soc_probe_codec(card, codec);
@@ -1559,7 +1561,7 @@
 }
 
 
-static void snd_soc_instantiate_card(struct snd_soc_card *card)
+static int snd_soc_instantiate_card(struct snd_soc_card *card)
 {
 	struct snd_soc_codec *codec;
 	struct snd_soc_codec_conf *codec_conf;
@@ -1569,19 +1571,19 @@
 
 	mutex_lock(&card->mutex);
 
-	if (card->instantiated) {
-		mutex_unlock(&card->mutex);
-		return;
-	}
 
 	/* bind DAIs */
-	for (i = 0; i < card->num_links; i++)
-		soc_bind_dai_link(card, i);
+	for (i = 0; i < card->num_links; i++) {
+		ret = soc_bind_dai_link(card, i);
+		if (ret != 0)
+			goto base_error;
+	}
 
-	/* bind completed ? */
-	if (card->num_rtd != card->num_links) {
-		mutex_unlock(&card->mutex);
-		return;
+	/* check aux_devs too */
+	for (i = 0; i < card->num_aux_devs; i++) {
+		ret = soc_check_aux_dev(card, i);
+		if (ret != 0)
+			goto base_error;
 	}
 
 	/* initialize the register cache for each available codec */
@@ -1601,10 +1603,8 @@
 			}
 		}
 		ret = snd_soc_init_codec_cache(codec, compress_type);
-		if (ret < 0) {
-			mutex_unlock(&card->mutex);
-			return;
-		}
+		if (ret < 0)
+			goto base_error;
 	}
 
 	/* card bind complete so register a sound card */
@@ -1613,8 +1613,7 @@
 	if (ret < 0) {
 		printk(KERN_ERR "asoc: can't create sound card for card %s\n",
 			card->name);
-		mutex_unlock(&card->mutex);
-		return;
+		goto base_error;
 	}
 	card->snd_card->dev = card->dev;
 
@@ -1751,7 +1750,7 @@
 	card->instantiated = 1;
 	snd_soc_dapm_sync(&card->dapm);
 	mutex_unlock(&card->mutex);
-	return;
+	return 0;
 
 probe_aux_dev_err:
 	for (i = 0; i < card->num_aux_devs; i++)
@@ -1765,19 +1764,9 @@
 		card->remove(card);
 
 	snd_card_free(card->snd_card);
-
+base_error:
 	mutex_unlock(&card->mutex);
-}
-
-/*
- * Attempt to initialise any uninitialised cards.  Must be called with
- * client_mutex.
- */
-static void snd_soc_instantiate_cards(void)
-{
-	struct snd_soc_card *card;
-	list_for_each_entry(card, &card_list, list)
-		snd_soc_instantiate_card(card);
+	return ret;
 }
 
 /* probes a new socdev */
@@ -2035,6 +2024,10 @@
 {
 	unsigned int ret;
 
+	if (unlikely(!snd_card_is_online_state(codec->card->snd_card))) {
+		dev_err(codec->dev, "read 0x%02x while offline\n", reg);
+		return -ENODEV;
+	}
 	ret = codec->read(codec, reg);
 	dev_dbg(codec->dev, "read %x => %x\n", reg, ret);
 	trace_snd_soc_reg_read(codec, reg, ret);
@@ -2046,6 +2039,10 @@
 unsigned int snd_soc_write(struct snd_soc_codec *codec,
 			   unsigned int reg, unsigned int val)
 {
+	if (unlikely(!snd_card_is_online_state(codec->card->snd_card))) {
+		dev_err(codec->dev, "write 0x%02x while offline\n", reg);
+		return -ENODEV;
+	}
 	dev_dbg(codec->dev, "write %x = %x\n", reg, val);
 	trace_snd_soc_reg_write(codec, reg, val);
 	return codec->write(codec, reg, val);
@@ -3233,12 +3230,10 @@
 	mutex_init(&card->dpcm_mutex);
 	mutex_init(&card->dapm_power_mutex);
 
-	mutex_lock(&client_mutex);
-	list_add(&card->list, &card_list);
-	snd_soc_instantiate_cards();
-	mutex_unlock(&client_mutex);
+	ret = snd_soc_instantiate_card(card);
+	if (ret != 0)
+		soc_cleanup_card_debugfs(card);
 
-	dev_dbg(card->dev, "Registered card '%s'\n", card->name);
 
 	return ret;
 }
@@ -3254,9 +3249,6 @@
 {
 	if (card->instantiated)
 		soc_cleanup_card_resources(card);
-	mutex_lock(&client_mutex);
-	list_del(&card->list);
-	mutex_unlock(&client_mutex);
 	dev_dbg(card->dev, "Unregistered card '%s'\n", card->name);
 
 	return 0;
@@ -3352,7 +3344,6 @@
 
 	mutex_lock(&client_mutex);
 	list_add(&dai->list, &dai_list);
-	snd_soc_instantiate_cards();
 	mutex_unlock(&client_mutex);
 
 	pr_debug("Registered DAI '%s'\n", dai->name);
@@ -3434,9 +3425,6 @@
 		pr_debug("Registered DAI '%s'\n", dai->name);
 	}
 
-	mutex_lock(&client_mutex);
-	snd_soc_instantiate_cards();
-	mutex_unlock(&client_mutex);
 	return 0;
 
 err:
@@ -3493,7 +3481,6 @@
 
 	mutex_lock(&client_mutex);
 	list_add(&platform->list, &platform_list);
-	snd_soc_instantiate_cards();
 	mutex_unlock(&client_mutex);
 
 	pr_debug("Registered platform '%s'\n", platform->name);
@@ -3562,6 +3549,17 @@
 }
 
 /**
+ * snd_soc_card_change_online_state - Mark if soc card is online/offline
+ *
+ * @soc_card : soc_card to mark
+ */
+void snd_soc_card_change_online_state(struct snd_soc_card *soc_card, int online)
+{
+	snd_card_change_online_state(soc_card->snd_card, online);
+}
+EXPORT_SYMBOL(snd_soc_card_change_online_state);
+
+/**
  * snd_soc_register_codec - Register a codec with the ASoC core
  *
  * @codec: codec to register
@@ -3651,7 +3649,6 @@
 
 	mutex_lock(&client_mutex);
 	list_add(&codec->list, &codec_list);
-	snd_soc_instantiate_cards();
 	mutex_unlock(&client_mutex);
 
 	pr_debug("Registered codec '%s'\n", codec->name);