Merge "[SCSI] ufs: use devres functions for ufshcd"
diff --git a/AndroidKernel.mk b/AndroidKernel.mk
index 3684a3f..d97d3c3 100644
--- a/AndroidKernel.mk
+++ b/AndroidKernel.mk
@@ -5,7 +5,11 @@
 
 KERNEL_OUT := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ
 KERNEL_CONFIG := $(KERNEL_OUT)/.config
+ifeq ($(TARGET_KERNEL_APPEND_DTB), true)
+TARGET_PREBUILT_INT_KERNEL := $(KERNEL_OUT)/arch/arm/boot/zImage-dtb
+else
 TARGET_PREBUILT_INT_KERNEL := $(KERNEL_OUT)/arch/arm/boot/zImage
+endif
 KERNEL_HEADERS_INSTALL := $(KERNEL_OUT)/usr
 KERNEL_MODULES_INSTALL := system
 KERNEL_MODULES_OUT := $(TARGET_OUT)/lib/modules
diff --git a/Documentation/devicetree/bindings/dma/sps/sps.txt b/Documentation/devicetree/bindings/dma/sps/sps.txt
index a979c56..26102c8 100644
--- a/Documentation/devicetree/bindings/dma/sps/sps.txt
+++ b/Documentation/devicetree/bindings/dma/sps/sps.txt
@@ -7,7 +7,11 @@
   - compatible: should be "qcom,msm_sps"
 
 Optional properties:
-  - reg: offset and size of the register set in the memory map
+  - reg: offset and size for the memory mapping, including maps for
+    BAM DMA BAM, BAM DMA peripheral, pipe memory and reserved memory.
+  - reg-names: indicates various resources passed to driver (via reg
+    property) by name. "reg-names" examples are "bam_mem", "core_mem"
+    , "pipe_mem" and "res_mem".
   - interrupts: IRQ line
   - qcom,device-type: specify the device configuration of BAM DMA and
     pipe memory. Can be one of
diff --git a/Documentation/devicetree/bindings/input/misc/stk-stk3x1x.txt b/Documentation/devicetree/bindings/input/misc/stk-stk3x1x.txt
new file mode 100644
index 0000000..aa50140
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/misc/stk-stk3x1x.txt
@@ -0,0 +1,46 @@
+Sensortek stk301x, stk321x and stk331x ambient light/proximity 3-in-1 sensor
+
+Required properties:
+
+ - compatible		: Should be "stk,stk3x1x".
+ - reg					: i2c slave address of the device.
+ - interrupt-parent	: Parent of interrupt.
+ - interrupts		: Sensor will issue interrupt when preset condition is met,
+				typically when proximity sensor detect a change on near/far state.
+ - vdd-supply		: Main power supply to power sensor.
+ - vio-supply		: Power supply required to pullup I2C bus.
+ - stk,irq-gpio	: irq gpio which is to provide interrupts to host, same as
+				"interrupts" node.
+ - stk,transmittance : Transmittance rate of glass above the ambient light
+				detection window. The value may not be equal to real transmittance
+				but just a relative value.
+ - stk,state-reg	: The default setting of state register.
+ - stk,psctrl-reg	: The default setting for proximity sensor.
+ - stk,alsctrl-reg	: The default setting for ambient light sensor.
+ - stk,ledctrl-reg	: The default setting for IR LED.
+ - stk,wait-reg	: The default setting for wait time.
+ - stk,ps-thdh	: High threshold for proximity sensor, sensor will report
+				"near" if the proximity sensor reading is larger or equal to this
+				value.
+ - stk,ps-thdl	: Low threshold for proximity sensor, sensor will report
+				"far" if the proximity sensor reading is larger than this value.
+
+Example:
+	i2c@f9925000 {
+		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 = <500>;
+			stk,state-reg = <0x00>;
+			stk,psctrl-reg = <0x71>;
+			stk,alsctrl-reg = <0x38>;
+			stk,ledctrl-reg = <0xFF>;
+			stk,wait-reg = <0x07>;
+			stk,ps-thdh = <1700>;
+			stk,ps-thdl = <1500>;
+		};
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index b60760e..9524360 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -47,6 +47,7 @@
 - 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
 
 RGB Led is a tri-colored led, Red, Blue & Green.
 
@@ -222,6 +223,7 @@
 			compatible = "qcom,leds-qpnp";
 			status = "okay";
 			flash_boost-supply = <&pm8941_chg_boost>;
+			torch_boost-supply = <&pm8941_boost>;
 			qcom,flash_0 {
 				qcom,max-current = <1000>;
 				qcom,default-state = "off";
diff --git a/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
index 72b32be..d848baf 100644
--- a/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
@@ -13,6 +13,10 @@
 - qcom,flash-source : Should contain array of phandles to flash source nodes.
     - pm8941_flash0 pm8941_flash1
 
+Optional properties:
+-qcom,torch-source : Should contain phandle to torch source node.
+    -pm8941_torch
+
 Example:
 
 qcom,camera-led-flash {
@@ -20,4 +24,5 @@
 	compatible = "qcom,camera-led-flash";
 	qcom,flash-type = <1>;
 	qcom,flash-source = <&pm8941_flash0 &pm8941_flash1>;
+	qcom,torch-source = <&pm8941_torch>;
 };
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index b8156c3..c60441f 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -49,6 +49,7 @@
 Required properties:
 - compatible : should be manufacturer name followed by sensor name
     - "qcom,s5k3l1yx"
+    - "qcom,imx135"
     - "shinetech,gc0339"
     - "shinetech,hi256"
     - "shinetech,s5k4e1"
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index a3a3807..527c50c 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -42,6 +42,7 @@
 samsung	Samsung Semiconductor
 sbs	Smart Battery System
 schindler	Schindler
+stk	Sensortek Technology Corporation.(formerly Sitronix Technology Co., Ltd.)
 shinetech	Shine Tech Corporation, Ltd.
 sil	Silicon Image
 simtek
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8226e43..69b2cd2 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -2015,6 +2015,21 @@
 	help
 	  Include support for flattened device tree machine descriptions.
 
+config BUILD_ARM_APPENDED_DTB_IMAGE
+	bool "Build a concatenated zImage/dtb by default"
+	depends on OF
+	help
+	  Enabling this option will cause a concatenated zImage and list of
+	  DTBs to be built by default (instead of a standalone zImage.)
+	  The image will built in arch/arm/boot/zImage-dtb
+
+config BUILD_ARM_APPENDED_DTB_IMAGE_NAMES
+	string "Default dtb names"
+	depends on BUILD_ARM_APPENDED_DTB_IMAGE
+	help
+	  Space separated list of names of dtbs to append when
+	  building a concatenated zImage-dtb.
+
 # Compressed boot loader in ROM.  Yes, we really want to ask about
 # TEXT and BSS so we preserve their values in the config files.
 config ZBOOT_ROM_TEXT
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 2f2603f..d43e69bf 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -261,6 +261,8 @@
 # Default target when executing plain make
 ifeq ($(CONFIG_XIP_KERNEL),y)
 KBUILD_IMAGE := xipImage
+else ifeq ($(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE),y)
+KBUILD_IMAGE := zImage-dtb
 else
 KBUILD_IMAGE := zImage
 endif
@@ -292,6 +294,9 @@
 dtbs: scripts
 	$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
 
+zImage-dtb: vmlinux scripts
+	$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
+
 # We use MRPROPER_FILES and CLEAN_FILES now
 archclean:
 	$(Q)$(MAKE) $(clean)=$(boot)
@@ -306,7 +311,7 @@
   echo  '  Image         - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
   echo  '* xipImage      - XIP kernel image, if configured (arch/$(ARCH)/boot/xipImage)'
   echo  '  uImage        - U-Boot wrapped zImage'
-  echo  '  bootpImage    - Combined zImage and initial RAM disk' 
+  echo  '  bootpImage    - Combined zImage and initial RAM disk'
   echo  '                  (supply initrd image via make variable INITRD=<path>)'
   echo  '* dtbs          - Build device tree blobs for enabled boards'
   echo  '  install       - Install uncompressed kernel'
diff --git a/arch/arm/boot/.gitignore b/arch/arm/boot/.gitignore
index 3c79f85..ad7a025 100644
--- a/arch/arm/boot/.gitignore
+++ b/arch/arm/boot/.gitignore
@@ -4,3 +4,4 @@
 bootpImage
 uImage
 *.dtb
+zImage-dtb
\ No newline at end of file
diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
index c877087..bc8ee6c 100644
--- a/arch/arm/boot/Makefile
+++ b/arch/arm/boot/Makefile
@@ -27,6 +27,14 @@
 
 targets := Image zImage xipImage bootpImage uImage
 
+DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE_NAMES))
+ifneq ($(DTB_NAMES),)
+DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES))
+else
+DTB_LIST := $(dtb-y)
+endif
+DTB_OBJS := $(addprefix $(obj)/,$(DTB_LIST))
+
 ifeq ($(CONFIG_XIP_KERNEL),y)
 
 $(obj)/xipImage: vmlinux FORCE
@@ -55,15 +63,19 @@
 	$(call if_changed,objcopy)
 	@echo '  Kernel: $@ is ready'
 
+$(obj)/zImage-dtb:	$(obj)/zImage $(DTB_OBJS) FORCE
+	$(call if_changed,cat)
+	@echo '  Kernel: $@ is ready'
+
 endif
 
-targets += $(dtb-y)
+targets += $(DTB_LIST)
 
 # Rule to build device tree blobs
 $(obj)/%.dtb: $(src)/dts/%.dts FORCE
 	$(call if_changed_dep,dtc)
 
-$(obj)/dtbs: $(addprefix $(obj)/, $(dtb-y))
+$(obj)/dtbs: $(DTB_OBJS)
 
 clean-files := *.dtb
 
diff --git a/arch/arm/boot/dts/apq8026-v1-mtp.dts b/arch/arm/boot/dts/apq8026-v1-mtp.dts
index b89c676..7900ddf 100644
--- a/arch/arm/boot/dts/apq8026-v1-mtp.dts
+++ b/arch/arm/boot/dts/apq8026-v1-mtp.dts
@@ -20,3 +20,10 @@
 	compatible = "qcom,apq8026-mtp", "qcom,apq8026", "qcom,mtp";
 	qcom,msm-id = <199 8 0>;
 };
+
+&cci {
+	/* Rotate rear camera to 0 degrees */
+	qcom,camera@6f {
+	qcom,mount-angle = <0>;
+	};
+};
diff --git a/arch/arm/boot/dts/apq8084-coresight.dtsi b/arch/arm/boot/dts/apq8084-coresight.dtsi
index 6cd238a..22c260f 100644
--- a/arch/arm/boot/dts/apq8084-coresight.dtsi
+++ b/arch/arm/boot/dts/apq8084-coresight.dtsi
@@ -348,4 +348,29 @@
 		coresight-name = "coresight-cti-cpu3";
 		coresight-nr-inports = <0>;
 	};
+
+	hwevent: hwevent@fd828018 {
+		compatible = "qcom,coresight-hwevent";
+		reg = <0xfd828018 0x80>,
+		      <0xf9011080 0x80>,
+		      <0xfd4ab160 0x80>,
+		      <0xfc401600 0x80>;
+		reg-names = "mmss-mux", "apcs-mux", "ppss-mux", "gcc-mux";
+
+		coresight-id = <29>;
+		coresight-name = "coresight-hwevent";
+		coresight-nr-inports = <0>;
+
+		qcom,hwevent-clks = "core_mmss_clk";
+	};
+
+	fuse: fuse@fc4be024 {
+		compatible = "arm,coresight-fuse";
+		reg = <0xfc4be024 0x8>;
+		reg-names = "fuse-base";
+
+		coresight-id = <30>;
+		coresight-name = "coresight-fuse";
+		coresight-nr-inports = <0>;
+	};
 };
diff --git a/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
new file mode 100644
index 0000000..5b7cc79
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
@@ -0,0 +1,275 @@
+/* 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.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
+&soc {
+	qcom,mdss_dsi_nt35521_720p_video {
+		compatible = "qcom,mdss-dsi-panel";
+		status = "disable";
+		qcom,mdss-dsi-panel-name = "nt35521 720p video mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <720>;
+		qcom,mdss-dsi-panel-height = <1280>;
+		qcom,mdss-dsi-h-front-porch = <44>;
+		qcom,mdss-dsi-h-back-porch = <55>;
+		qcom,mdss-dsi-h-pulse-width = <11>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <15>;
+		qcom,mdss-dsi-v-front-porch = <14>;
+		qcom,mdss-dsi-v-pulse-width = <1>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = <0>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-pixel-packing = <0>;
+		qcom,mdss-dsi-on-command = [29 01 00 00 00 00 06 F0 55 AA 52 08 00
+				29 01 00 00 00 00 03 B1 68 21
+				23 01 00 00 00 00 02 B5 C8
+				29 01 00 00 00 00 02 B6 0F
+				29 01 00 00 00 00 05 B8 00 00 0A 00
+				23 01 00 00 00 00 02 B9 00
+				23 01 00 00 00 00 02 BA 02
+				29 01 00 00 00 00 03 BB 63 63
+				29 01 00 00 00 00 03 BC 00 00
+				29 01 00 00 00 00 06 BD 02 7F 0D 0B 00
+				29 01 00 00 00 00 11 CC 41 36 87 54 46 65 10 12 14 10 12 14 40 08 15 05
+				23 01 00 00 00 00 02 D0 00
+				29 01 00 00 00 00 11 D1 00 04 08 0C 10 14 18 1C 20 24 28 2C 30 34 38 3C
+				23 01 00 00 00 00 02 D3 00
+				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 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
+				29 01 00 00 00 00 0B E8 F3 D9 CC CD B3 A6 99 99 99 95
+				29 01 00 00 00 00 03 E9 00 04
+				23 01 00 00 00 00 02 EA 00
+				29 01 00 00 00 00 05 EE 87 78 00 00
+				29 01 00 00 00 00 03 EF 07 FF
+				29 01 00 00 00 00 06 F0 55 AA 52 08 01
+				29 01 00 00 00 00 03 B0 0D 0D
+				29 01 00 00 00 00 03 B1 0D 0D
+				29 01 00 00 00 00 03 B3 2D 2D
+				29 01 00 00 00 00 03 B4 19 19
+				29 01 00 00 00 00 03 B5 06 06
+				29 01 00 00 00 00 03 B6 05 05
+				29 01 00 00 00 00 03 B7 05 05
+				29 01 00 00 00 00 03 B8 05 05
+				29 01 00 00 00 00 03 B9 44 44
+				29 01 00 00 00 00 03 BA 36 36
+				29 01 00 00 00 00 03 BC 50 00
+				29 01 00 00 00 00 03 BD 50 00
+				23 01 00 00 00 00 02 BE 39
+				23 01 00 00 00 00 02 BF 39
+				23 01 00 00 00 00 02 C0 0C
+				23 01 00 00 00 00 02 C1 00
+				29 01 00 00 00 00 03 C2 19 19
+				29 01 00 00 00 00 03 C3 0A 0A
+				29 01 00 00 00 00 03 C4 23 23
+				29 01 00 00 00 00 04 C7 00 80 00
+				29 01 00 00 00 00 07 C9 00 00 00 00 00 00
+				23 01 00 00 00 00 02 CA 01
+				29 01 00 00 00 00 03 CB 0B 53
+				23 01 00 00 00 00 02 CC 00
+				29 01 00 00 00 00 04 CD 0B 52 53
+				23 01 00 00 00 00 02 CE 44
+				29 01 00 00 00 00 04 CF 00 50 50
+				29 01 00 00 00 00 03 D0 50 50
+				29 01 00 00 00 00 03 D1 50 50
+				23 01 00 00 00 00 02 D2 39
+				23 01 00 00 00 00 02 D3 39
+				29 01 00 00 00 00 06 F0 55 AA 52 08 02
+				29 01 00 00 00 00 11 B0 00 AC 00 BA 00 D9 00 ED 01 01 01 1E 01 3A 01 62
+				29 01 00 00 00 00 11 B1 01 85 01 B8 01 E4 02 27 02 5B 02 5D 02 8C 02 BE
+				29 01 00 00 00 00 11 B2 02 DF 03 0C 03 2A 03 51 03 6D 03 8D 03 A4 03 BE
+				29 01 00 00 00 00 05 B3 03 CC 03 CC
+				29 01 00 00 00 00 11 B4 00 AC 00 BA 00 D9 00 ED 01 01 01 1E 01 3A 01 62
+				29 01 00 00 00 00 11 B5 01 85 01 B8 01 E4 02 27 02 5B 02 5D 02 8C 02 BE
+				29 01 00 00 00 00 11 B6 02 DF 03 0C 03 2A 03 51 03 6D 03 8D 03 A4 03 BE
+				29 01 00 00 00 00 05 B7 03 CC 03 CC
+				29 01 00 00 00 00 11 B8 00 AC 00 BA 00 D9 00 ED 01 01 01 1E 01 3A 01 62
+				29 01 00 00 00 00 11 B9 01 85 01 B8 01 E4 02 27 02 5B 02 5D 02 8C 02 BE
+				29 01 00 00 00 00 11 BA 02 DF 03 0C 03 2A 03 51 03 6D 03 8D 03 A4 03 BE
+				29 01 00 00 00 00 05 BB 03 CC 03 CC
+				29 01 00 00 00 00 11 BC 00 AC 00 BA 00 D9 00 ED 01 01 01 1E 01 3A 01 62
+				29 01 00 00 00 00 11 BD 01 85 01 B8 01 E4 02 27 02 5B 02 5D 02 8C 02 BE
+				29 01 00 00 00 00 11 BE 02 DF 03 0C 03 2A 03 51 03 6D 03 8D 03 A4 03 BE
+				29 01 00 00 00 00 05 BF 03 CC 03 CC
+				29 01 00 00 00 00 11 C0 00 AC 00 BA 00 D9 00 ED 01 01 01 1E 01 3A 01 62
+				29 01 00 00 00 00 11 C1 01 85 01 B8 01 E4 02 27 02 5B 02 5D 02 8C 02 BE
+				29 01 00 00 00 00 11 C2 02 DF 03 0C 03 2A 03 51 03 6D 03 8D 03 A4 03 BE
+				29 01 00 00 00 00 05 C3 03 CC 03 CC
+				29 01 00 00 00 00 11 C4 00 AC 00 BA 00 D9 00 ED 01 01 01 1E 01 3A 01 62
+				29 01 00 00 00 00 11 C5 01 85 01 B8 01 E4 02 27 02 5B 02 5D 02 8C 02 BE
+				29 01 00 00 00 00 11 C6 02 DF 03 0C 03 2A 03 51 03 6D 03 8D 03 A4 03 BE
+				29 01 00 00 00 00 05 C7 03 CC 03 CC
+				23 01 00 00 00 00 02 EE 00
+				29 01 00 00 00 00 06 F0 55 AA 52 08 03
+				29 01 00 00 00 00 03 B0 00 00
+				29 01 00 00 00 00 03 B1 00 00
+				29 01 00 00 00 00 06 B2 03 00 00 00 00
+				29 01 00 00 00 00 06 B3 03 00 00 00 00
+				29 01 00 00 00 00 06 B4 03 00 00 00 00
+				29 01 00 00 00 00 06 B5 03 00 00 00 00
+				29 01 00 00 00 00 06 B6 03 00 00 00 00
+				29 01 00 00 00 00 06 B7 03 00 00 00 00
+				29 01 00 00 00 00 06 B8 03 00 00 00 00
+				29 01 00 00 00 00 06 B9 03 00 00 00 00
+				29 01 00 00 00 00 06 BA 35 10 00 00 00
+				29 01 00 00 00 00 06 BB 35 10 00 00 00
+				29 01 00 00 00 00 06 BC 35 10 00 00 00
+				29 01 00 00 00 00 06 BD 35 10 00 00 00
+				29 01 00 00 00 00 05 C0 00 34 00 00
+				29 01 00 00 00 00 05 C1 00 34 00 00
+				29 01 00 00 00 00 05 C2 00 34 00 00
+				29 01 00 00 00 00 05 C3 00 34 00 00
+				23 01 00 00 00 00 02 C4 40
+				23 01 00 00 00 00 02 C5 40
+				23 01 00 00 00 00 02 C6 40
+				23 01 00 00 00 00 02 C7 40
+				23 01 00 00 00 00 02 EF 00
+				29 01 00 00 00 00 06 F0 55 AA 52 08 05
+				29 01 00 00 00 00 03 B0 1B 10
+				29 01 00 00 00 00 03 B1 1B 10
+				29 01 00 00 00 00 03 B2 1B 10
+				29 01 00 00 00 00 03 B3 1B 10
+				29 01 00 00 00 00 03 B4 1B 10
+				29 01 00 00 00 00 03 B5 1B 10
+				29 01 00 00 00 00 03 B6 1B 10
+				29 01 00 00 00 00 03 B7 1B 10
+				23 01 00 00 00 00 02 B8 00
+				23 01 00 00 00 00 02 B9 00
+				23 01 00 00 00 00 02 BA 00
+				23 01 00 00 00 00 02 BB 00
+				23 01 00 00 00 00 02 BC 00
+				29 01 00 00 00 00 06 BD 03 03 03 00 01
+				23 01 00 00 00 00 02 C0 03
+				23 01 00 00 00 00 02 C1 05
+				23 01 00 00 00 00 02 C2 03
+				23 01 00 00 00 00 02 C3 05
+				23 01 00 00 00 00 02 C4 80
+				23 01 00 00 00 00 02 C5 A2
+				23 01 00 00 00 00 02 C6 80
+				23 01 00 00 00 00 02 C7 A2
+				29 01 00 00 00 00 03 C8 01 20
+				29 01 00 00 00 00 03 C9 00 20
+				29 01 00 00 00 00 03 CA 01 00
+				29 01 00 00 00 00 03 CB 00 00
+				29 01 00 00 00 00 04 CC 00 00 01
+				29 01 00 00 00 00 04 CD 00 00 01
+				29 01 00 00 00 00 04 CE 00 00 01
+				29 01 00 00 00 00 04 CF 00 00 01
+				23 01 00 00 00 00 02 D0 00
+				29 01 00 00 00 00 06 D1 03 00 00 07 10
+				29 01 00 00 00 00 06 D2 13 00 00 07 11
+				29 01 00 00 00 00 06 D3 23 00 00 07 10
+				29 01 00 00 00 00 06 D4 33 00 00 07 11
+				23 01 00 00 00 00 02 E5 06
+				23 01 00 00 00 00 02 E6 06
+				23 01 00 00 00 00 02 E7 06
+				23 01 00 00 00 00 02 E8 06
+				23 01 00 00 00 00 02 E9 06
+				23 01 00 00 00 00 02 EA 06
+				23 01 00 00 00 00 02 EB 06
+				23 01 00 00 00 00 02 EC 06
+				23 01 00 00 00 00 02 ED 31
+				29 01 00 00 00 00 06 F0 55 AA 52 08 06
+				29 01 00 00 00 00 03 B0 10 11
+				29 01 00 00 00 00 03 B1 12 13
+				29 01 00 00 00 00 03 B2 08 00
+				29 01 00 00 00 00 03 B3 2D 2D
+				29 01 00 00 00 00 03 B4 2D 34
+				29 01 00 00 00 00 03 B5 34 2D
+				29 01 00 00 00 00 03 B6 2D 34
+				29 01 00 00 00 00 03 B7 34 34
+				29 01 00 00 00 00 03 B8 02 0A
+				29 01 00 00 00 00 03 B9 00 08
+				29 01 00 00 00 00 03 BA 09 01
+				29 01 00 00 00 00 03 BB 0B 03
+				29 01 00 00 00 00 03 BC 34 34
+				29 01 00 00 00 00 03 BD 34 2D
+				29 01 00 00 00 00 03 BE 2D 34
+				29 01 00 00 00 00 03 BF 34 2D
+				29 01 00 00 00 00 03 C0 2D 2D
+				29 01 00 00 00 00 03 C1 01 09
+				29 01 00 00 00 00 03 C2 19 18
+				29 01 00 00 00 00 03 C3 17 16
+				29 01 00 00 00 00 03 C4 19 18
+				29 01 00 00 00 00 03 C5 17 16
+				29 01 00 00 00 00 03 C6 01 09
+				29 01 00 00 00 00 03 C7 2D 2D
+				29 01 00 00 00 00 03 C8 2D 34
+				29 01 00 00 00 00 03 C9 34 2D
+				29 01 00 00 00 00 03 CA 2D 34
+				29 01 00 00 00 00 03 CB 34 34
+				29 01 00 00 00 00 03 CC 0B 03
+				29 01 00 00 00 00 03 CD 09 01
+				29 01 00 00 00 00 03 CE 00 08
+				29 01 00 00 00 00 03 CF 02 0A
+				29 01 00 00 00 00 03 D0 34 34
+				29 01 00 00 00 00 03 D1 34 2D
+				29 01 00 00 00 00 03 D2 2D 34
+				29 01 00 00 00 00 03 D3 34 2D
+				29 01 00 00 00 00 03 D4 2D 2D
+				29 01 00 00 00 00 03 D5 08 00
+				29 01 00 00 00 00 03 D6 10 11
+				29 01 00 00 00 00 03 D7 12 13
+				29 01 00 00 00 00 06 D8 55 55 55 55 55
+				29 01 00 00 00 00 06 D9 55 55 55 55 55
+				29 01 00 00 00 00 03 E5 34 34
+				29 01 00 00 00 00 03 E6 34 34
+				23 01 00 00 00 00 02 E7 05
+				29 01 00 00 00 00 06 F0 55 AA 52 00 00
+				05 01 00 00 32 00 02 11 00
+				05 01 00 00 96 00 02 29 00
+				29 01 00 00 00 00 06 F0 55 AA 52 08 01
+				29 01 00 00 00 00 06 F0 55 AA 52 00 00
+				29 01 00 00 00 00 02 53 2C];
+		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
+					05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <1>;
+		qcom,mdss-dsi-traffic-mode = <2>;
+		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings = [93 1F 17 00 2F 2E 1C 21 26 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x20>;
+		qcom,mdss-dsi-t-clk-pre = <0x2D>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <255>;
+		qcom,mdss-dsi-dma-trigger = <4>;
+		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs";
+
+	};
+};
diff --git a/arch/arm/boot/dts/mpq8092-rumi.dts b/arch/arm/boot/dts/mpq8092-rumi.dts
index 1abaf55..3ba2fbc 100644
--- a/arch/arm/boot/dts/mpq8092-rumi.dts
+++ b/arch/arm/boot/dts/mpq8092-rumi.dts
@@ -18,7 +18,7 @@
 / {
 	model = "Qualcomm MPQ8092 RUMI";
 	compatible = "qcom,mpq8092-rumi", "qcom,mpq8092", "qcom,rumi";
-	qcom,msm-id = <146 16 0>;
+	qcom,msm-id = <146 15 0>;
 };
 
 &soc {
diff --git a/arch/arm/boot/dts/mpq8092-sim.dts b/arch/arm/boot/dts/mpq8092-sim.dts
index 676ef3b..2384a45 100644
--- a/arch/arm/boot/dts/mpq8092-sim.dts
+++ b/arch/arm/boot/dts/mpq8092-sim.dts
@@ -17,7 +17,7 @@
 / {
 	model = "Qualcomm MPQ8092 Simulator";
 	compatible = "qcom,mpq8092-sim", "qcom,mpq8092", "qcom,sim";
-	qcom,msm-id = <126 16 0>;
+	qcom,msm-id = <146 16 0>;
 };
 
 &soc {
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index 2f67f3e..9a37316 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -229,6 +229,15 @@
 		qcom,current-limit = <800>;
 	};
 
+	qcom,sps@f9980000 {
+		compatible = "qcom,msm_sps";
+		reg = <0xf9984000 0x15000>,
+		      <0xf9999000 0xb000>;
+		reg-names = "bam_mem", "core_mem";
+		interrupts = <0 94 0>;
+		qcom,pipe-attr-ee;
+	};
+
 	sata: sata@fc580000 {
 		compatible = "qcom,msm-ahci";
 		reg = <0xfc580000 0x17c>;
@@ -308,5 +317,9 @@
 	status = "ok";
 };
 
+&gdsc_vcap {
+	status = "ok";
+};
+
 /include/ "msm-pma8084.dtsi"
 /include/ "mpq8092-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msm-gdsc.dtsi b/arch/arm/boot/dts/msm-gdsc.dtsi
index 495f65a..2f732a4 100644
--- a/arch/arm/boot/dts/msm-gdsc.dtsi
+++ b/arch/arm/boot/dts/msm-gdsc.dtsi
@@ -109,4 +109,11 @@
 		reg = <0xfc401ec0 0x4>;
 		status = "disabled";
 	};
+
+	gdsc_vcap: qcom,gdsc@fd8c1804 {
+		compatible = "qcom,gdsc";
+		regulator-name = "gdsc_vcap";
+		reg = <0xfd8c1804 0x4>;
+		status = "disabled";
+	};
 };
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 12af463..0c2b02b 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -1252,6 +1252,7 @@
 		reg = <0xd300 0x100>;
 		label = "flash";
 		flash_boost-supply = <&pm8941_chg_boost>;
+		torch_boost-supply = <&pm8941_boost>;
 	};
 
 	qcom,leds@d400 {
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
index d4b605b..f807814 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
@@ -68,6 +68,47 @@
 		qcom,cci-master = <0>;
 	};
 
+    qcom,camera@20 {
+		compatible = "qcom,imx135";
+		reg = <0x20>;
+		qcom,slave-id = <0x20 0x0016 0x0135>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <90>;
+		qcom,sensor-name = "imx135";
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vana-supply = <&pm8226_l19>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		cam_vaf-supply = <&pm8226_l15>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+				     "cam_vaf";
+		qcom,cam-vreg-type = <0 1 0 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		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,gpio-set-tbl-num = <1 1>;
+		qcom,gpio-set-tbl-flags = <0 2>;
+		qcom,gpio-set-tbl-delay = <1000 30000>;
+		qcom,csi-lane-assign = <0x4320>;
+		qcom,csi-lane-mask = <0x1F>;
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+	        qcom,sensor-type = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
 	qcom,camera@6d {
 		compatible = "qcom,ov9724";
 		reg = <0x6d>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
index 53860ac..56e8a09 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
@@ -38,7 +38,7 @@
 		qcom,csid-sd-index = <0>;
 		qcom,actuator-src = <&actuator0>;
 		qcom,led-flash-src = <&led_flash0>;
-		qcom,mount-angle = <0>;
+		qcom,mount-angle = <90>;
 		qcom,sensor-name = "ov8825";
 		cam_vdig-supply = <&pm8226_l5>;
 		cam_vana-supply = <&pm8226_l19>;
diff --git a/arch/arm/boot/dts/msm8226-sim.dts b/arch/arm/boot/dts/msm8226-sim.dts
index 2405646..1da94b3 100644
--- a/arch/arm/boot/dts/msm8226-sim.dts
+++ b/arch/arm/boot/dts/msm8226-sim.dts
@@ -12,7 +12,6 @@
 
 /dts-v1/;
 /include/ "msm8226.dtsi"
-/include/ "msm8226-camera.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226 Simulator";
diff --git a/arch/arm/boot/dts/msm8226-v1-mtp.dts b/arch/arm/boot/dts/msm8226-v1-mtp.dts
index b1d46b1..6f03dca 100644
--- a/arch/arm/boot/dts/msm8226-v1-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-v1-mtp.dts
@@ -23,3 +23,10 @@
 		      <198 8 0>,
 		      <205 8 0>;
 };
+
+&cci {
+	/* Rotate rear camera to 0 degrees */
+	qcom,camera@6f {
+	qcom,mount-angle = <0>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
index 936f87f..3e0e4e4 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
@@ -13,7 +13,7 @@
 /dts-v1/;
 /include/ "msm8226-v1.dtsi"
 /include/ "msm8226-qrd.dtsi"
-/include/ "dsi-panel-nt35590-720p-video.dtsi"
+/include/ "dsi-panel-nt35521-720p-video.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226 QRD";
@@ -26,9 +26,9 @@
 };
 
 &soc {
-	qcom,mdss_dsi_nt35590_720p_video {
+	qcom,mdss_dsi_nt35521_720p_video {
 		status = "ok";
-		qcom,mdss-pan-bl-ctrl = "bl_ctrl_dcs";
+		qcom,cont-splash-enabled;
 	};
 
 	sound {
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
index b34fb94..0a4657d 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
@@ -13,7 +13,7 @@
 /dts-v1/;
 /include/ "msm8226-v2.dtsi"
 /include/ "msm8226-qrd.dtsi"
-/include/ "dsi-panel-nt35590-720p-video.dtsi"
+/include/ "dsi-panel-nt35521-720p-video.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226v2 QRD";
@@ -27,9 +27,9 @@
 };
 
 &soc {
-	qcom,mdss_dsi_nt35590_720p_video {
+	qcom,mdss_dsi_nt35521_720p_video {
 		status = "ok";
-		qcom,mdss-pan-bl-ctrl = "bl_ctrl_dcs";
+		qcom,cont-splash-enabled;
 	};
 
 	sound {
diff --git a/arch/arm/boot/dts/msm8226-v2.dtsi b/arch/arm/boot/dts/msm8226-v2.dtsi
index 1dab78a..2b3b7c2 100644
--- a/arch/arm/boot/dts/msm8226-v2.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2.dtsi
@@ -17,7 +17,6 @@
  */
 
 /include/ "msm8226.dtsi"
-/include/ "msm8226-camera.dtsi"
 
 &pm8226_l3 {
 	regulator-min-microvolt = <750000>;
diff --git a/arch/arm/boot/dts/msm8926.dtsi b/arch/arm/boot/dts/msm8926.dtsi
index f46b714..013da90a 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -17,7 +17,6 @@
  */
 
 /include/ "msm8226.dtsi"
-/include/ "msm8226-camera.dtsi"
 
 / {
 	model = "Qualcomm MSM 8926";
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index fa57244..9badf6d 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -271,11 +271,11 @@
 			qcom,default-state = "on";
 			qcom,max-current = <25>;
 			qcom,ctrl-delay-us = <0>;
-			qcom,boost-curr-lim = <3>;
+			qcom,boost-curr-lim = <5>;
 			qcom,cp-sel = <0>;
 			qcom,switch-freq = <11>;
 			qcom,ovp-val = <2>;
-			qcom,num-strings = <1>;
+			qcom,num-strings = <3>;
 			qcom,id = <0>;
 		};
 	};
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index 3d20f7c..9c2509a 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -269,11 +269,11 @@
 			qcom,default-state = "on";
 			qcom,max-current = <25>;
 			qcom,ctrl-delay-us = <0>;
-			qcom,boost-curr-lim = <3>;
+			qcom,boost-curr-lim = <5>;
 			qcom,cp-sel = <0>;
 			qcom,switch-freq = <11>;
 			qcom,ovp-val = <2>;
-			qcom,num-strings = <1>;
+			qcom,num-strings = <3>;
 			qcom,id = <0>;
 		};
 	};
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index c1a8792..6955597 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -210,11 +210,11 @@
 			qcom,default-state = "on";
 			qcom,max-current = <25>;
 			qcom,ctrl-delay-us = <0>;
-			qcom,boost-curr-lim = <3>;
+			qcom,boost-curr-lim = <5>;
 			qcom,cp-sel = <0>;
 			qcom,switch-freq = <11>;
 			qcom,ovp-val = <2>;
-			qcom,num-strings = <1>;
+			qcom,num-strings = <3>;
 			qcom,id = <0>;
 		};
 	};
diff --git a/arch/arm/boot/dts/msmsamarium-regulator.dtsi b/arch/arm/boot/dts/msmsamarium-regulator.dtsi
new file mode 100644
index 0000000..ae4dc8d
--- /dev/null
+++ b/arch/arm/boot/dts/msmsamarium-regulator.dtsi
@@ -0,0 +1,374 @@
+/*
+ * 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.
+ */
+
+/* QPNP controlled regulators: */
+
+&spmi_bus {
+	qcom,pma8084@1 {
+		pma8084_s1: regulator@1400 {
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		/* PMA8084 S2 + S12 = 2 phase VDD_CX supply */
+		pma8084_s2: regulator@1700 {
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		pma8084_s3: regulator@1a00 {
+			regulator-min-microvolt = <1300000>;
+			regulator-max-microvolt = <1300000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		pma8084_s4: regulator@1d00 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		/* Output of PMA8084 S5 and L25 is tied together. */
+		pma8084_s5: regulator@2000 {
+			regulator-min-microvolt = <2150000>;
+			regulator-max-microvolt = <2150000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_s6: regulator@2300 {
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_s7: regulator@2600 {
+			regulator-min-microvolt = <815000>;
+			regulator-max-microvolt = <900000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_s8: regulator@2900 {
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1100000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		pma8084_s9: regulator@2c00 {
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1100000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		pma8084_s10: regulator@2f00 {
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1100000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		pma8084_s11: regulator@3200 {
+			regulator-min-microvolt = <500000>;
+			regulator-max-microvolt = <1100000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		pma8084_l1: regulator@4000 {
+			parent-supply = <&pma8084_s3>;
+			regulator-min-microvolt = <1225000>;
+			regulator-max-microvolt = <1225000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <10000>;
+			status = "okay";
+		};
+
+		pma8084_l2: regulator@4100 {
+			parent-supply = <&pma8084_s3>;
+			regulator-min-microvolt = <1175000>;
+			regulator-max-microvolt = <1175000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l3: regulator@4200 {
+			parent-supply = <&pma8084_s3>;
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l4: regulator@4300 {
+			parent-supply = <&pma8084_s3>;
+			regulator-min-microvolt = <1225000>;
+			regulator-max-microvolt = <1225000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l6: regulator@4500 {
+			parent-supply = <&pma8084_s5>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l8: regulator@4700 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l9: regulator@4800 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l10: regulator@4900 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l11: regulator@4a00 {
+			parent-supply = <&pma8084_s3>;
+			regulator-min-microvolt = <1300000>;
+			regulator-max-microvolt = <1300000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l12: regulator@4b00 {
+			parent-supply = <&pma8084_s5>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l13: regulator@4c00 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l14: regulator@4d00 {
+			parent-supply = <&pma8084_s5>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l15: regulator@4e00 {
+			parent-supply = <&pma8084_s5>;
+			regulator-min-microvolt = <2050000>;
+			regulator-max-microvolt = <2050000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l16: regulator@4f00 {
+			regulator-min-microvolt = <2700000>;
+			regulator-max-microvolt = <2700000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l17: regulator@5000 {
+			regulator-min-microvolt = <2850000>;
+			regulator-max-microvolt = <2850000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l18: regulator@5100 {
+			regulator-min-microvolt = <2850000>;
+			regulator-max-microvolt = <2850000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l19: regulator@5200 {
+			regulator-min-microvolt = <2900000>;
+			regulator-max-microvolt = <2900000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l20: regulator@5300 {
+			regulator-min-microvolt = <2950000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l21: regulator@5400 {
+			regulator-min-microvolt = <2950000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l22: regulator@5500 {
+			regulator-min-microvolt = <3000000>;
+			regulator-max-microvolt = <3000000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l23: regulator@5600 {
+			regulator-min-microvolt = <2850000>;
+			regulator-max-microvolt = <2850000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l24: regulator@5700 {
+			regulator-min-microvolt = <3075000>;
+			regulator-max-microvolt = <3075000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l26: regulator@5900 {
+			parent-supply = <&pma8084_s5>;
+			regulator-min-microvolt = <2050000>;
+			regulator-max-microvolt = <2050000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l27: regulator@5a00 {
+			parent-supply = <&pma8084_s3>;
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_lvs1: regulator@8000 {
+			parent-supply = <&pma8084_s4>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_lvs2: regulator@8100 {
+			parent-supply = <&pma8084_s4>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_lvs3: regulator@8200 {
+			parent-supply = <&pma8084_s4>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_lvs4: regulator@8300 {
+			parent-supply = <&pma8084_s4>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_mvs1: regulator@8400 {
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+	};
+};
+
+&soc {
+	pma8084_s2_corner: s2_corner_vreg {
+		compatible = "qcom,stub-regulator";
+		regulator-name = "8084_s2_corner";
+		regulator-min-microvolt = <1>;
+		regulator-max-microvolt = <7>;
+		qcom,hpm-min-load = <100000>;
+		qcom,consumer-supplies = "vdd_dig", "";
+	};
+};
diff --git a/arch/arm/boot/dts/msmsamarium.dtsi b/arch/arm/boot/dts/msmsamarium.dtsi
index 20954f9..a492561 100644
--- a/arch/arm/boot/dts/msmsamarium.dtsi
+++ b/arch/arm/boot/dts/msmsamarium.dtsi
@@ -242,6 +242,19 @@
 		cell-index = <0>;
 		qcom,not-wakeup;     /* Needed until MPM is fully configured. */
 	};
+
+	tsens: tsens@fc4a8000 {
+		compatible = "qcom,msm-tsens";
+		reg = <0xfc4a8000 0x2000>,
+		      <0xfc4bc000 0x1000>;
+		reg-names = "tsens_physical", "tsens_eeprom_physical";
+		interrupts = <0 184 0>;
+		qcom,sensors = <11>;
+		qcom,slope = <3200 3200 3200 3200 3200 3200 3200 3200 3200
+				3200 3200>;
+		qcom,calib-mode = "fuse_map1";
+	};
 };
 
 /include/ "msm-pma8084.dtsi"
+/include/ "msmsamarium-regulator.dtsi"
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index 4315d3f..f4ad0c4 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -402,9 +402,11 @@
 CONFIG_CRYPTO_DEV_QCEDEV=m
 CONFIG_CRC_CCITT=y
 CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_FUSE=y
 CONFIG_CORESIGHT_TMC=y
 CONFIG_CORESIGHT_FUNNEL=y
 CONFIG_CORESIGHT_REPLICATOR=y
 CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
 CONFIG_CORESIGHT_ETM=y
 CONFIG_USB_BAM=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 0db08db..b9d37b8 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -391,3 +391,4 @@
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
 CONFIG_SENSORS_STK3X1X=y
 CONFIG_SENSORS_MMA8X5X=y
+CONFIG_LOGCAT_SIZE=64
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index f2f6558..7901e93 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -480,3 +480,4 @@
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCEDEV=y
 CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
+CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 71742a5..8520f23 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -514,3 +514,4 @@
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCEDEV=y
 CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
+CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c
index ad9dfb2..bb97140 100644
--- a/arch/arm/kernel/sched_clock.c
+++ b/arch/arm/kernel/sched_clock.c
@@ -68,7 +68,9 @@
 		smp_rmb();
 	} while (epoch_cyc != cd.epoch_cyc_copy);
 
-	return epoch_ns + cyc_to_ns((cyc - epoch_cyc) & mask, cd.mult, cd.shift);
+	cyc = read_sched_clock();
+	cyc = (cyc - epoch_cyc) & sched_clock_mask;
+	return epoch_ns + cyc_to_ns(cyc, cd.mult, cd.shift);
 }
 
 /*
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index cd71104..e4a647f 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -24,7 +24,7 @@
 
 obj-y += acpuclock.o
 obj-$(CONFIG_HW_PERF_EVENTS) += perf_trace_counters.o
-obj-$(CONFIG_ARCH_MSM_KRAIT) += acpuclock-krait.o
+obj-$(CONFIG_ARCH_MSM_KRAIT) += acpuclock-krait.o clock-krait.o
 ifdef CONFIG_ARCH_MSM_KRAIT
 obj-$(CONFIG_DEBUG_FS) += acpuclock-krait-debug.o
 endif
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 1460f94..820bcf9 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -1583,6 +1583,12 @@
 {
 	int ret = 0;
 
+	if (in_global_reset) {
+		DMUX_LOG_KERR("%s: modem timeout: already in SSR\n",
+			__func__);
+		return 1;
+	}
+
 	DMUX_LOG_KERR("%s: modem timeout: BAM DMUX disabled for SSR\n",
 								__func__);
 	in_global_reset = 1;
@@ -1755,11 +1761,15 @@
 	unsigned long flags;
 	unsigned long time_remaining;
 
-	time_remaining = wait_for_completion_timeout(&shutdown_completion,
-			msecs_to_jiffies(SHUTDOWN_TIMEOUT_MS));
-	if (time_remaining == 0) {
-		pr_err("%s: shutdown completion timed out\n", __func__);
-		ssrestart_check();
+	if (!in_global_reset) {
+		time_remaining = wait_for_completion_timeout(
+				&shutdown_completion,
+				msecs_to_jiffies(SHUTDOWN_TIMEOUT_MS));
+		if (time_remaining == 0) {
+			DMUX_LOG_KERR("%s: shutdown completion timed out\n",
+					__func__);
+			ssrestart_check();
+		}
 	}
 
 	bam_connection_is_active = 0;
@@ -2226,6 +2236,11 @@
 {
 	static unsigned int clear_bit; /* 0 = set the bit, else clear bit */
 
+	if (in_global_reset) {
+		BAM_DMUX_LOG("%s: skipped due to SSR\n", __func__);
+		return;
+	}
+
 	BAM_DMUX_LOG("%s: apps ack %d->%d\n", __func__,
 			clear_bit & 0x1, ~clear_bit & 0x1);
 	smsm_change_state(SMSM_APPS_STATE,
diff --git a/arch/arm/mach-msm/board-samarium.c b/arch/arm/mach-msm/board-samarium.c
index 6133983..52a947b 100644
--- a/arch/arm/mach-msm/board-samarium.c
+++ b/arch/arm/mach-msm/board-samarium.c
@@ -16,6 +16,7 @@
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/memory.h>
+#include <linux/msm_tsens.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach/map.h>
 #include <asm/mach/arch.h>
@@ -35,6 +36,10 @@
 #include "modem_notifier.h"
 
 static struct clk_lookup msm_clocks_dummy[] = {
+	CLK_DUMMY("xo",                CXO_CLK, "fc880000.qcom,mss", OFF),
+	CLK_DUMMY("bus_clk",   MSS_BIMC_Q6_CLK, "fc880000.qcom,mss", OFF),
+	CLK_DUMMY("iface_clk", MSS_CFG_AHB_CLK, "fc880000.qcom,mss", OFF),
+	CLK_DUMMY("mem_clk",  BOOT_ROM_AHB_CLK, "fc880000.qcom,mss", OFF),
 	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "f991f000.serial", OFF),
 	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "f991f000.serial", OFF),
 	CLK_DUMMY("core_clk",	SDC1_CLK,	"msm_sdcc.1", OFF),
@@ -109,6 +114,7 @@
 	msm_init_modem_notifier_list();
 	msm_smd_init();
 	msm_clock_init(&msm_dummy_clock_init_data);
+	tsens_tm_init_driver();
 }
 
 static void __init msmsamarium_map_io(void)
diff --git a/arch/arm/mach-msm/clock-8084.c b/arch/arm/mach-msm/clock-8084.c
index ffd33a8..939a637 100644
--- a/arch/arm/mach-msm/clock-8084.c
+++ b/arch/arm/mach-msm/clock-8084.c
@@ -415,6 +415,7 @@
 	CLK_DUMMY("core_clk", qdss_clk.c, "fc342000.cti", OFF),
 	CLK_DUMMY("core_clk", qdss_clk.c, "fc343000.cti", OFF),
 	CLK_DUMMY("core_clk", qdss_clk.c, "fc344000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fd828018.hwevent", OFF),
 
 	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc326000.tmc", OFF),
 	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc324000.replicator", OFF),
@@ -444,6 +445,13 @@
 	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc342000.cti", OFF),
 	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc343000.cti", OFF),
 	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc344000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fd828018.hwevent", OFF),
+
+	CLK_DUMMY("core_mmss_clk", mmss_misc_ahb_clk.c, "fd828018.hwevent",
+		  OFF),
+
+	CLK_DUMMY("iface_clk", gcc_prng_ahb_clk.c,
+					"f9bff000.qcom,msm-rng", OFF),
 };
 
 struct clock_init_data msm8084_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 383af54..8a79687 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -3389,11 +3389,13 @@
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6d.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6a.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "20.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6f.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "90.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6d.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6a.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "20.qcom,camera"),
 
 	/* eeprom clocks */
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6c.qcom,eeprom"),
diff --git a/arch/arm/mach-msm/clock-krait.c b/arch/arm/mach-msm/clock-krait.c
new file mode 100644
index 0000000..b96ba62
--- /dev/null
+++ b/arch/arm/mach-msm/clock-krait.c
@@ -0,0 +1,521 @@
+/*
+ * 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/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+
+#include <linux/clk.h>
+#include <mach/clk-provider.h>
+#include <mach/clk.h>
+#include <mach/clock-generic.h>
+#include <mach/msm-krait-l2-accessors.h>
+#include "clock-krait.h"
+#include "avs.h"
+
+static DEFINE_SPINLOCK(kpss_clock_reg_lock);
+
+static void __kpss_mux_set_sel(struct mux_clk *mux, int sel)
+{
+	unsigned long flags;
+	u32 regval;
+
+	spin_lock_irqsave(&kpss_clock_reg_lock, flags);
+	regval = get_l2_indirect_reg(mux->offset);
+	regval &= ~(mux->mask << mux->shift);
+	regval |= (sel & mux->mask) << mux->shift;
+	set_l2_indirect_reg(mux->offset, regval);
+	spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
+
+	/* Wait for switch to complete. */
+	mb();
+	udelay(1);
+}
+static int kpss_mux_set_sel(struct mux_clk *mux, int sel)
+{
+	mux->en_mask = sel;
+	if (mux->c.count)
+		__kpss_mux_set_sel(mux, sel);
+	return 0;
+}
+
+static int kpss_mux_get_sel(struct mux_clk *mux)
+{
+	u32 sel;
+
+	sel = get_l2_indirect_reg(mux->offset);
+	sel >>= mux->shift;
+	sel &= mux->mask;
+	mux->en_mask = sel;
+
+	return sel;
+}
+
+static int kpss_mux_enable(struct mux_clk *mux)
+{
+	__kpss_mux_set_sel(mux, mux->en_mask);
+	return 0;
+}
+
+static void kpss_mux_disable(struct mux_clk *mux)
+{
+	__kpss_mux_set_sel(mux, mux->safe_sel);
+}
+
+struct clk_mux_ops clk_mux_ops_kpss = {
+	.enable = kpss_mux_enable,
+	.disable = kpss_mux_disable,
+	.set_mux_sel = kpss_mux_set_sel,
+	.get_mux_sel = kpss_mux_get_sel,
+};
+
+/*
+ * The divider can divide by 2, 4, 6 and 8. But we only really need div-2. So
+ * force it to div-2 during handoff and treat it like a fixed div-2 clock.
+ */
+static int kpss_div2_get_div(struct div_clk *div)
+{
+	unsigned long flags;
+	u32 regval;
+	int val;
+
+	spin_lock_irqsave(&kpss_clock_reg_lock, flags);
+	regval = get_l2_indirect_reg(div->offset);
+	val = (regval >> div->shift) && div->mask;
+	regval &= ~(div->mask << div->shift);
+	set_l2_indirect_reg(div->offset, regval);
+	spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
+
+	val = (val + 1) * 2;
+	WARN(val != 2, "Divider %s was configured to div-%d instead of 2!\n",
+		div->c.dbg_name, val);
+
+	return 2;
+}
+
+struct clk_div_ops clk_div_ops_kpss_div2 = {
+	.get_div = kpss_div2_get_div,
+};
+
+#define LOCK_BIT	BIT(16)
+
+/* Initialize a HFPLL at a given rate and enable it. */
+static void __hfpll_clk_init_once(struct clk *c)
+{
+	struct hfpll_clk *h = to_hfpll_clk(c);
+	struct hfpll_data const *hd = h->d;
+
+	if (likely(h->init_done))
+		return;
+
+	/* Configure PLL parameters for integer mode. */
+	writel_relaxed(hd->config_val, h->base + hd->config_offset);
+	writel_relaxed(0, h->base + hd->m_offset);
+	writel_relaxed(1, h->base + hd->n_offset);
+
+	if (hd->user_offset) {
+		u32 regval = hd->user_val;
+		unsigned long rate;
+
+		rate = readl_relaxed(h->base + hd->l_offset) * h->src_rate;
+
+		/* Pick the right VCO. */
+		if (rate > hd->low_vco_max_rate)
+			regval |= hd->user_vco_mask;
+		writel_relaxed(regval, h->base + hd->user_offset);
+	}
+
+	if (hd->droop_offset)
+		writel_relaxed(hd->droop_val, h->base + hd->droop_offset);
+
+	h->init_done = true;
+}
+
+/* Enable an already-configured HFPLL. */
+static int hfpll_clk_enable(struct clk *c)
+{
+	struct hfpll_clk *h = to_hfpll_clk(c);
+	struct hfpll_data const *hd = h->d;
+
+	if (!h->base)
+		return -ENODEV;
+
+	__hfpll_clk_init_once(c);
+
+	/* Disable PLL bypass mode. */
+	writel_relaxed(0x2, h->base + hd->mode_offset);
+
+	/*
+	 * H/W requires a 5us delay between disabling the bypass and
+	 * de-asserting the reset. Delay 10us just to be safe.
+	 */
+	mb();
+	udelay(10);
+
+	/* De-assert active-low PLL reset. */
+	writel_relaxed(0x6, h->base + hd->mode_offset);
+
+	/* Wait for PLL to lock. */
+	if (hd->status_offset) {
+		while (!(readl_relaxed(h->base + hd->status_offset) & LOCK_BIT))
+			;
+	} else {
+		mb();
+		udelay(60);
+	}
+
+	/* Enable PLL output. */
+	writel_relaxed(0x7, h->base + hd->mode_offset);
+
+	/* Make sure the enable is done before returning. */
+	mb();
+
+	return 0;
+}
+
+static void hfpll_clk_disable(struct clk *c)
+{
+	struct hfpll_clk *h = to_hfpll_clk(c);
+	struct hfpll_data const *hd = h->d;
+
+	/*
+	 * Disable the PLL output, disable test mode, enable the bypass mode,
+	 * and assert the reset.
+	 */
+	writel_relaxed(0, h->base + hd->mode_offset);
+}
+
+static long hfpll_clk_round_rate(struct clk *c, unsigned long rate)
+{
+	struct hfpll_clk *h = to_hfpll_clk(c);
+	struct hfpll_data const *hd = h->d;
+	unsigned long rrate;
+
+	if (!h->src_rate)
+		return 0;
+
+	rate = max(rate, hd->min_rate);
+	rate = min(rate, hd->max_rate);
+
+	rrate = DIV_ROUND_UP(rate, h->src_rate) * h->src_rate;
+	if (rrate > hd->max_rate)
+		rrate -= h->src_rate;
+
+	return rrate;
+}
+
+/*
+ * For optimization reasons, assumes no downstream clocks are actively using
+ * it.
+ */
+static int hfpll_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	struct hfpll_clk *h = to_hfpll_clk(c);
+	struct hfpll_data const *hd = h->d;
+	unsigned long flags;
+	u32 l_val;
+
+	if (!h->base)
+		return -ENODEV;
+
+	if (rate != hfpll_clk_round_rate(c, rate))
+		return -EINVAL;
+
+	l_val = rate / h->src_rate;
+
+	spin_lock_irqsave(&c->lock, flags);
+
+	if (c->count)
+		hfpll_clk_disable(c);
+
+	/* Pick the right VCO. */
+	if (hd->user_offset) {
+		u32 regval;
+		regval = readl_relaxed(h->base + hd->user_offset);
+		if (rate <= hd->low_vco_max_rate)
+			regval &= ~hd->user_vco_mask;
+		else
+			regval |= hd->user_vco_mask;
+		writel_relaxed(regval, h->base  + hd->user_offset);
+	}
+
+	writel_relaxed(l_val, h->base + hd->l_offset);
+
+	if (c->count)
+		hfpll_clk_enable(c);
+
+	spin_unlock_irqrestore(&c->lock, flags);
+
+	return 0;
+}
+
+static enum handoff hfpll_clk_handoff(struct clk *c)
+{
+	struct hfpll_clk *h = to_hfpll_clk(c);
+	struct hfpll_data const *hd = h->d;
+	u32 l_val, mode;
+
+	if (!hd)
+		return HANDOFF_DISABLED_CLK;
+
+	if (!h->base)
+		return HANDOFF_DISABLED_CLK;
+
+	/* Assume parent rate doesn't change and cache it. */
+	h->src_rate = clk_get_rate(c->parent);
+	l_val = readl_relaxed(h->base + hd->l_offset);
+	c->rate = l_val * h->src_rate;
+
+	mode = readl_relaxed(h->base + hd->mode_offset) & 0x7;
+	if (mode != 0x7) {
+		__hfpll_clk_init_once(c);
+		return HANDOFF_DISABLED_CLK;
+	}
+
+	if (hd->status_offset &&
+		!(readl_relaxed(h->base + hd->status_offset) & LOCK_BIT)) {
+		WARN(1, "HFPLL %s is ON, but not locked!\n", c->dbg_name);
+		hfpll_clk_disable(c);
+		__hfpll_clk_init_once(c);
+		return HANDOFF_DISABLED_CLK;
+	}
+
+	WARN(c->rate < hd->min_rate || c->rate > hd->max_rate,
+		"HFPLL %s rate %lu outside spec!\n", c->dbg_name, c->rate);
+
+	return HANDOFF_ENABLED_CLK;
+}
+
+struct clk_ops clk_ops_hfpll = {
+	.enable = hfpll_clk_enable,
+	.disable = hfpll_clk_disable,
+	.round_rate = hfpll_clk_round_rate,
+	.set_rate = hfpll_clk_set_rate,
+	.handoff = hfpll_clk_handoff,
+};
+
+struct cpu_hwcg_action {
+	bool read;
+	bool enable;
+};
+
+static void cpu_hwcg_rw(void *info)
+{
+	struct cpu_hwcg_action *action = info;
+
+	u32 val;
+	asm volatile ("mrc p15, 7, %[cpmr0], c15, c0, 5\n\t"
+			: [cpmr0]"=r" (val));
+
+	if (action->read) {
+		action->enable = !(val & BIT(0));
+		return;
+	}
+
+	if (action->enable)
+		val &= ~BIT(0);
+	else
+		val |= BIT(0);
+
+	asm volatile ("mcr p15, 7, %[cpmr0], c15, c0, 5\n\t"
+			: : [cpmr0]"r" (val));
+}
+
+static void kpss_cpu_enable_hwcg(struct clk *c)
+{
+	struct kpss_core_clk *cpu = to_kpss_core_clk(c);
+	struct cpu_hwcg_action action = { .enable = true };
+
+	smp_call_function_single(cpu->id, cpu_hwcg_rw, &action, 1);
+}
+
+static void kpss_cpu_disable_hwcg(struct clk *c)
+{
+	struct kpss_core_clk *cpu = to_kpss_core_clk(c);
+	struct cpu_hwcg_action action = { .enable = false };
+
+	smp_call_function_single(cpu->id, cpu_hwcg_rw, &action, 1);
+}
+
+static int kpss_cpu_in_hwcg_mode(struct clk *c)
+{
+	struct kpss_core_clk *cpu = to_kpss_core_clk(c);
+	struct cpu_hwcg_action action = { .read = true };
+
+	smp_call_function_single(cpu->id, cpu_hwcg_rw, &action, 1);
+	return action.enable;
+}
+
+static enum handoff kpss_cpu_handoff(struct clk *c)
+{
+	struct kpss_core_clk *cpu = to_kpss_core_clk(c);
+
+	c->rate = clk_get_rate(c->parent);
+
+	/*
+	 * Don't unnecessarily turn on the parents for an offline CPU and
+	 * then have them turned off at late init.
+	 */
+	return (cpu_online(cpu->id) ?
+		HANDOFF_ENABLED_CLK : HANDOFF_DISABLED_CLK);
+}
+
+u32 find_dscr(struct avs_data *t, unsigned long rate)
+{
+	int i;
+
+	if (!t)
+		return 0;
+
+	for (i = 0; i < t->num; i++) {
+		if (t->rate[i] == rate)
+			return t->dscr[i];
+	}
+
+	return 0;
+}
+
+static int kpss_cpu_pre_set_rate(struct clk *c, unsigned long new_rate)
+{
+	struct kpss_core_clk *cpu = to_kpss_core_clk(c);
+	u32 dscr = find_dscr(cpu->avs_tbl, c->rate);
+
+	if (!c->prepare_count)
+		return -ENODEV;
+
+	if (dscr)
+		AVS_DISABLE(cpu->id);
+	return 0;
+}
+
+static long kpss_core_round_rate(struct clk *c, unsigned long rate)
+{
+	if (c->fmax && c->num_fmax)
+		rate = min(rate, c->fmax[c->num_fmax-1]);
+
+	return clk_round_rate(c->parent, rate);
+}
+
+static int kpss_core_set_rate(struct clk *c, unsigned long rate)
+{
+	if (!c->prepare_count)
+		return -ENODEV;
+
+	return clk_set_rate(c->parent, rate);
+}
+
+static void kpss_cpu_post_set_rate(struct clk *c, unsigned long old_rate)
+{
+	struct kpss_core_clk *cpu = to_kpss_core_clk(c);
+	u32 dscr = find_dscr(cpu->avs_tbl, c->rate);
+
+	/*
+	 * FIXME: If AVS enable/disable needs to be done in the
+	 * enable/disable op to correctly handle power collapse, then might
+	 * need to grab the spinlock here.
+	 */
+	if (dscr)
+		AVS_ENABLE(cpu->id, dscr);
+}
+
+static unsigned long kpss_core_get_rate(struct clk *c)
+{
+	return clk_get_rate(c->parent);
+}
+
+static long kpss_core_list_rate(struct clk *c, unsigned n)
+{
+	if (!c->fmax || c->num_fmax <= n)
+		return -ENXIO;
+
+	return c->fmax[n];
+}
+
+struct clk_ops clk_ops_kpss_cpu = {
+	.enable_hwcg = kpss_cpu_enable_hwcg,
+	.disable_hwcg = kpss_cpu_disable_hwcg,
+	.in_hwcg_mode = kpss_cpu_in_hwcg_mode,
+	.pre_set_rate = kpss_cpu_pre_set_rate,
+	.round_rate = kpss_core_round_rate,
+	.set_rate = kpss_core_set_rate,
+	.post_set_rate = kpss_cpu_post_set_rate,
+	.get_rate = kpss_core_get_rate,
+	.list_rate = kpss_core_list_rate,
+	.handoff = kpss_cpu_handoff,
+};
+
+#define SLPDLY_SHIFT		10
+#define SLPDLY_MASK		0x3
+static void kpss_l2_enable_hwcg(struct clk *c)
+{
+	struct kpss_core_clk *l2 = to_kpss_core_clk(c);
+	u32 regval;
+	unsigned long flags;
+
+	spin_lock_irqsave(&kpss_clock_reg_lock, flags);
+	regval = get_l2_indirect_reg(l2->cp15_iaddr);
+	regval &= ~(SLPDLY_MASK << SLPDLY_SHIFT);
+	regval |= l2->l2_slp_delay;
+	set_l2_indirect_reg(l2->cp15_iaddr, regval);
+	spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
+}
+
+static void kpss_l2_disable_hwcg(struct clk *c)
+{
+	struct kpss_core_clk *l2 = to_kpss_core_clk(c);
+	u32 regval;
+	unsigned long flags;
+
+	/*
+	 * NOTE: Should not be called when HW clock gating is already
+	 * disabled.
+	 */
+	spin_lock_irqsave(&kpss_clock_reg_lock, flags);
+	regval = get_l2_indirect_reg(l2->cp15_iaddr);
+	l2->l2_slp_delay = regval & (SLPDLY_MASK << SLPDLY_SHIFT);
+	regval |= (SLPDLY_MASK << SLPDLY_SHIFT);
+	set_l2_indirect_reg(l2->cp15_iaddr, regval);
+	spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
+}
+
+static int kpss_l2_in_hwcg_mode(struct clk *c)
+{
+	struct kpss_core_clk *l2 = to_kpss_core_clk(c);
+	u32 regval;
+
+	regval = get_l2_indirect_reg(l2->cp15_iaddr);
+	regval >>= SLPDLY_SHIFT;
+	regval &= SLPDLY_MASK;
+	return (regval != SLPDLY_MASK);
+}
+
+static enum handoff kpss_l2_handoff(struct clk *c)
+{
+	c->rate = clk_get_rate(c->parent);
+	return HANDOFF_ENABLED_CLK;
+}
+
+struct clk_ops clk_ops_kpss_l2 = {
+	.enable_hwcg = kpss_l2_enable_hwcg,
+	.disable_hwcg = kpss_l2_disable_hwcg,
+	.in_hwcg_mode = kpss_l2_in_hwcg_mode,
+	.round_rate = kpss_core_round_rate,
+	.set_rate = kpss_core_set_rate,
+	.get_rate = kpss_core_get_rate,
+	.list_rate = kpss_core_list_rate,
+	.handoff = kpss_l2_handoff,
+};
diff --git a/arch/arm/mach-msm/clock-krait.h b/arch/arm/mach-msm/clock-krait.h
new file mode 100644
index 0000000..2691a8c
--- /dev/null
+++ b/arch/arm/mach-msm/clock-krait.h
@@ -0,0 +1,99 @@
+/*
+ * 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 __ARCH_ARM_MACH_MSM_CLOCK_KRAIT_H
+#define __ARCH_ARM_MACH_MSM_CLOCK_KRAIT_H
+
+#include <mach/clk-provider.h>
+#include <mach/clock-generic.h>
+
+extern struct clk_mux_ops clk_mux_ops_kpss;
+extern struct clk_div_ops clk_div_ops_kpss_div2;
+
+#define DEFINE_KPSS_DIV2_CLK(clk_name, _parent, _offset) \
+static struct div_clk clk_name = {		\
+	.div = 2,				\
+	.min_div = 2,				\
+	.max_div = 2,				\
+	.ops = &clk_div_ops_kpss_div2,		\
+	.offset = _offset,			\
+	.mask = 0x3,				\
+	.shift = 6,				\
+	.c = {					\
+		.parent = _parent,		\
+		.dbg_name = #clk_name,		\
+		.ops = &clk_ops_div,		\
+		.flags = CLKFLAG_NO_RATE_CACHE,	\
+		CLK_INIT(clk_name.c),		\
+	}					\
+}
+
+struct hfpll_data {
+	const u32 mode_offset;
+	const u32 l_offset;
+	const u32 m_offset;
+	const u32 n_offset;
+	const u32 user_offset;
+	const u32 droop_offset;
+	const u32 config_offset;
+	const u32 status_offset;
+
+	const u32 droop_val;
+	const u32 config_val;
+	const u32 user_val;
+	const u32 user_vco_mask;
+	unsigned long low_vco_max_rate;
+
+	unsigned long min_rate;
+	unsigned long max_rate;
+};
+
+struct hfpll_clk {
+	void  * __iomem base;
+	struct hfpll_data const *d;
+	unsigned long	src_rate;
+	int		init_done;
+
+	struct clk	c;
+};
+
+static inline struct hfpll_clk *to_hfpll_clk(struct clk *c)
+{
+	return container_of(c, struct hfpll_clk, c);
+}
+
+extern struct clk_ops clk_ops_hfpll;
+
+struct avs_data {
+	unsigned long	*rate;
+	u32		*dscr;
+	int		num;
+};
+
+struct kpss_core_clk {
+	int		id;
+	u32		cp15_iaddr;
+	u32		l2_slp_delay;
+	struct avs_data	*avs_tbl;
+	struct clk	c;
+};
+
+static inline struct kpss_core_clk *to_kpss_core_clk(struct clk *c)
+{
+	return container_of(c, struct kpss_core_clk, c);
+}
+
+extern struct clk_ops clk_ops_kpss_cpu;
+extern struct clk_ops clk_ops_kpss_l2;
+
+#endif
diff --git a/arch/arm/mach-msm/clock-krypton.c b/arch/arm/mach-msm/clock-krypton.c
index 0b615cc..176dc32 100644
--- a/arch/arm/mach-msm/clock-krypton.c
+++ b/arch/arm/mach-msm/clock-krypton.c
@@ -18,12 +18,12 @@
 #include <linux/spinlock.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
-#include <linux/iopoll.h>
 #include <linux/regulator/consumer.h>
+#include <linux/iopoll.h>
 
+#include <mach/clk.h>
 #include <mach/rpm-regulator-smd.h>
 #include <mach/socinfo.h>
-#include <mach/rpm-smd.h>
 
 #include "clock-local2.h"
 #include "clock-pll.h"
@@ -31,97 +31,2051 @@
 #include "clock-voter.h"
 #include "clock.h"
 
-static struct clk_lookup msm_clocks_dummy[] = {
-	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "f991f000.serial", OFF),
-	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "f991f000.serial", OFF),
-	CLK_DUMMY("core_clk",	SPI_CLK,	"f9928000.spi",  OFF),
-	CLK_DUMMY("iface_clk",	SPI_P_CLK,	"f9928000.spi",  OFF),
-
-	CLK_DUMMY("bus_clk", cnoc_msmbus_clk.c, "msm_config_noc", OFF),
-	CLK_DUMMY("bus_a_clk", cnoc_msmbus_a_clk.c, "msm_config_noc", OFF),
-	CLK_DUMMY("bus_clk", snoc_msmbus_clk.c, "msm_sys_noc", OFF),
-	CLK_DUMMY("bus_a_clk", snoc_msmbus_a_clk.c, "msm_sys_noc", OFF),
-	CLK_DUMMY("bus_clk", pnoc_msmbus_clk.c, "msm_periph_noc", OFF),
-	CLK_DUMMY("bus_a_clk", pnoc_msmbus_a_clk.c, "msm_periph_noc", OFF),
-	CLK_DUMMY("mem_clk", bimc_msmbus_clk.c, "msm_bimc", OFF),
-	CLK_DUMMY("mem_a_clk", bimc_msmbus_a_clk.c, "msm_bimc", OFF),
-	CLK_DUMMY("mem_clk", bimc_acpu_a_clk.c, "", OFF),
-	CLK_DUMMY("dfab_clk",	DFAB_CLK,	"msm_sps", OFF),
-	CLK_DUMMY("dma_bam_pclk",	DMA_BAM_P_CLK,	"msm_sps", OFF),
-
-	CLK_DUMMY("clktype", gcc_imem_axi_clk         , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_imem_cfg_ahb_clk     , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_mss_cfg_ahb_clk      , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_mss_q6_bimc_axi_clk  , "drivername", OFF),
-	CLK_DUMMY("mem_clk", gcc_usb30_master_clk     , "drivername", OFF),
-	CLK_DUMMY("sleep_clk", gcc_usb30_sleep_clk    , "drivername", OFF),
-	CLK_DUMMY("utmi_clk", gcc_usb30_mock_utmi_clk , "drivername", OFF),
-	CLK_DUMMY("iface_clk", gcc_usb_hsic_ahb_clk   , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_usb_hsic_system_clk , "drivername", OFF),
-	CLK_DUMMY("phyclk", gcc_usb_hsic_clk         , "drivername", OFF),
-	CLK_DUMMY("cal_clk", gcc_usb_hsic_io_cal_clk  , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_usb_hs_system_clk   , "drivername", OFF),
-	CLK_DUMMY("iface_clk", gcc_usb_hs_ahb_clk     , "drivername", OFF),
-	CLK_DUMMY("sleep_a_clk", gcc_usb2a_phy_sleep_clk  , "drivername", OFF),
-	CLK_DUMMY("sleep_b_clk", gcc_usb2b_phy_sleep_clk  , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_sdcc2_apps_clk      , "drivername", OFF),
-	CLK_DUMMY("iface_clk", gcc_sdcc2_ahb_clk      , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_sdcc3_apps_clk      , "drivername", OFF),
-	CLK_DUMMY("iface_clk", gcc_sdcc3_ahb_clk      , "drivername", OFF),
-	CLK_DUMMY("core_clk", sdcc3_apps_clk_src      , "drivername", OFF),
-	CLK_DUMMY("iface_clk", gcc_blsp1_ahb_clk      , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup1_spi_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup1_i2c_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_uart1_apps_clk , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup2_spi_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup2_i2c_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_uart2_apps_clk , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup3_spi_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup3_i2c_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_uart3_apps_clk , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup4_spi_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup4_i2c_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_uart4_apps_clk , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup5_spi_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup5_i2c_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_uart5_apps_clk , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup6_spi_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_qup6_i2c_apps_clk, "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_blsp1_uart6_apps_clk , "drivername", OFF),
-	CLK_DUMMY("core_clk", blsp1_uart6_apps_clk_src , "drivername", OFF),
-	CLK_DUMMY("iface_clk", gcc_pdm_ahb_clk        , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_pdm2_clk            , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_prng_ahb_clk        , "drivername", OFF),
-	CLK_DUMMY("dma_bam_pclk", gcc_bam_dma_ahb_clk , "drivername", OFF),
-	CLK_DUMMY("mem_clk", gcc_boot_rom_ahb_clk     , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_ce1_clk             , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_ce1_axi_clk         , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_ce1_ahb_clk         , "drivername", OFF),
-	CLK_DUMMY("core_clk_src", ce1_clk_src         , "drivername", OFF),
-	CLK_DUMMY("bus_clk", gcc_lpass_q6_axi_clk     , "drivername", OFF),
-	CLK_DUMMY("clktype", pcie_pipe_clk            , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_gp1_clk              , "drivername", OFF),
-	CLK_DUMMY("clktype", gp1_clk_src              , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_gp2_clk              , "drivername", OFF),
-	CLK_DUMMY("clktype", gp2_clk_src              , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_gp3_clk              , "drivername", OFF),
-	CLK_DUMMY("clktype", gp3_clk_src              , "drivername", OFF),
-	CLK_DUMMY("core_clk", gcc_ipa_clk             , "drivername", OFF),
-	CLK_DUMMY("iface_clk", gcc_ipa_cnoc_clk       , "drivername", OFF),
-	CLK_DUMMY("inactivity_clk", gcc_ipa_sleep_clk , "drivername", OFF),
-	CLK_DUMMY("core_clk_src", ipa_clk_src         , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_dcs_clk              , "drivername", OFF),
-	CLK_DUMMY("clktype", dcs_clk_src              , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_pcie_cfg_ahb_clk     , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_pcie_pipe_clk        , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_pcie_axi_clk         , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_pcie_sleep_clk       , "drivername", OFF),
-	CLK_DUMMY("clktype", gcc_pcie_axi_mstr_clk    , "drivername", OFF),
-	CLK_DUMMY("clktype", pcie_pipe_clk_src        , "drivername", OFF),
-	CLK_DUMMY("clktype", pcie_aux_clk_src         , "drivername", OFF),
+enum {
+	GCC_BASE,
+	LPASS_BASE,
+	APCS_GLB_BASE,
+	APCS_GCC_BASE,
+	APCS_ACC_BASE,
+	N_BASES,
 };
 
+static void __iomem *virt_bases[N_BASES];
+
+#define GCC_REG_BASE(x) (void __iomem *)(virt_bases[GCC_BASE] + (x))
+#define APCS_GCC_BASE(x) (void __iomem *)(virt_bases[APCS_GCC_BASE] + (x))
+
+/* Mux source select values */
+#define xo_source_val	0
+#define gpll0_source_val 1
+#define gpll1_source_val 4
+#define gnd_source_val	5
+
+#define usb3_pipe_clk_source_val	2
+#define pcie_pipe_clk_source_val	2
+
+/* Prevent a divider of -1 */
+#define FIXDIV(div) (div ? (2 * (div) - 1) : (0))
+
+#define F(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(FIXDIV(div))) \
+			| BVAL(10, 8, s##_source_val), \
+	}
+
+#define F_EXT_SRC(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(FIXDIV(div))) \
+			| BVAL(10, 8, s##_source_val), \
+	}
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
+#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+		[VDD_DIG_##l3] = (f3),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
+
+enum vdd_dig_levels {
+	VDD_DIG_NONE,
+	VDD_DIG_LOW,
+	VDD_DIG_NOMINAL,
+	VDD_DIG_HIGH,
+	VDD_DIG_NUM
+};
+
+static int vdd_corner[] = {
+	RPM_REGULATOR_CORNER_NONE,		/* VDD_DIG_NONE */
+	RPM_REGULATOR_CORNER_SVS_SOC,		/* VDD_DIG_LOW */
+	RPM_REGULATOR_CORNER_NORMAL,		/* VDD_DIG_NOMINAL */
+	RPM_REGULATOR_CORNER_SUPER_TURBO,	/* VDD_DIG_HIGH */
+};
+
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
+
+#define RPM_MISC_CLK_TYPE	0x306b6c63
+#define RPM_BUS_CLK_TYPE	0x316b6c63
+#define RPM_MEM_CLK_TYPE	0x326b6c63
+#define RPM_QPIC_CLK_TYPE	0x63697071
+
+#define RPM_SMD_KEY_ENABLE	0x62616E45
+
+#define CXO_ID			0x0
+#define QDSS_ID			0x1
+
+#define PNOC_ID		0x0
+#define SNOC_ID		0x1
+#define CNOC_ID		0x2
+
+#define BIMC_ID		0x0
+#define QPIC_ID		0x0
+
+#define D0_ID		 1
+#define D1_ID		 2
+#define A0_ID		 3
+#define A1_ID		 4
+#define A2_ID		 5
+
+#define APCS_CLK_DIAG                                      (0x001C)
+#define GPLL0_MODE                                         (0x0000)
+#define GPLL1_MODE                                         (0x0040)
+#define SYS_NOC_USB3_AXI_CBCR                              (0x0108)
+#define MSS_CFG_AHB_CBCR                                   (0x0280)
+#define MSS_Q6_BIMC_AXI_CBCR                               (0x0284)
+#define USB_30_BCR                                         (0x03C0)
+#define USB30_MASTER_CBCR                                  (0x03C8)
+#define USB30_SLEEP_CBCR                                   (0x03CC)
+#define USB30_MOCK_UTMI_CBCR                               (0x03D0)
+#define USB30_MASTER_CMD_RCGR                              (0x03D4)
+#define USB30_MOCK_UTMI_CMD_RCGR                           (0x03E8)
+#define USB3_PIPE_CBCR                                     (0x1B90)
+#define USB3_AUX_CBCR                                      (0x1B94)
+#define USB3_PIPE_CMD_RCGR                                 (0x1B98)
+#define USB3_AUX_CMD_RCGR                                  (0x1BC0)
+#define USB_HS_HSIC_BCR                                    (0x0400)
+#define USB_HSIC_AHB_CBCR                                  (0x0408)
+#define USB_HSIC_SYSTEM_CMD_RCGR                           (0x041C)
+#define USB_HSIC_SYSTEM_CBCR                               (0x040C)
+#define USB_HSIC_CMD_RCGR                                  (0x0440)
+#define USB_HSIC_CBCR                                      (0x0410)
+#define USB_HSIC_IO_CAL_CMD_RCGR                           (0x0458)
+#define USB_HSIC_IO_CAL_CBCR                               (0x0414)
+#define USB_HSIC_IO_CAL_SLEEP_CBCR                         (0x0418)
+#define USB_HSIC_XCVR_FS_CMD_RCGR                          (0x0424)
+#define USB_HSIC_XCVR_FS_CBCR                              (0x042C)
+#define USB_HS_BCR                                         (0x0480)
+#define USB_HS_SYSTEM_CBCR                                 (0x0484)
+#define USB_HS_AHB_CBCR                                    (0x0488)
+#define USB_HS_SYSTEM_CMD_RCGR                             (0x0490)
+#define SDCC2_APPS_CMD_RCGR                                (0x0510)
+#define SDCC2_APPS_CBCR                                    (0x0504)
+#define SDCC2_AHB_CBCR                                     (0x0508)
+#define SDCC3_APPS_CMD_RCGR                                (0x0550)
+#define SDCC3_APPS_CBCR                                    (0x0544)
+#define SDCC3_AHB_CBCR                                     (0x0548)
+#define BLSP1_AHB_CBCR                                     (0x05C4)
+#define BLSP1_QUP1_SPI_APPS_CBCR                           (0x0644)
+#define BLSP1_QUP1_I2C_APPS_CBCR                           (0x0648)
+#define BLSP1_QUP1_I2C_APPS_CMD_RCGR                       (0x0660)
+#define BLSP1_QUP2_I2C_APPS_CMD_RCGR                       (0x06E0)
+#define BLSP1_QUP3_I2C_APPS_CMD_RCGR                       (0x0760)
+#define BLSP1_QUP4_I2C_APPS_CMD_RCGR                       (0x07E0)
+#define BLSP1_QUP5_I2C_APPS_CMD_RCGR                       (0x0860)
+#define BLSP1_QUP6_I2C_APPS_CMD_RCGR                       (0x08E0)
+#define BLSP1_QUP1_SPI_APPS_CMD_RCGR                       (0x064C)
+#define BLSP1_UART1_APPS_CBCR                              (0x0684)
+#define BLSP1_UART1_APPS_CMD_RCGR                          (0x068C)
+#define BLSP1_QUP2_SPI_APPS_CBCR                           (0x06C4)
+#define BLSP1_QUP2_I2C_APPS_CBCR                           (0x06C8)
+#define BLSP1_QUP2_SPI_APPS_CMD_RCGR                       (0x06CC)
+#define BLSP1_UART2_APPS_CBCR                              (0x0704)
+#define BLSP1_UART2_APPS_CMD_RCGR                          (0x070C)
+#define BLSP1_QUP3_SPI_APPS_CBCR                           (0x0744)
+#define BLSP1_QUP3_I2C_APPS_CBCR                           (0x0748)
+#define BLSP1_QUP3_SPI_APPS_CMD_RCGR                       (0x074C)
+#define BLSP1_UART3_APPS_CBCR                              (0x0784)
+#define BLSP1_UART3_APPS_CMD_RCGR                          (0x078C)
+#define BLSP1_QUP4_SPI_APPS_CBCR                           (0x07C4)
+#define BLSP1_QUP4_I2C_APPS_CBCR                           (0x07C8)
+#define BLSP1_QUP4_SPI_APPS_CMD_RCGR                       (0x07CC)
+#define BLSP1_UART4_APPS_CBCR                              (0x0804)
+#define BLSP1_UART4_APPS_CMD_RCGR                          (0x080C)
+#define BLSP1_QUP5_SPI_APPS_CBCR                           (0x0844)
+#define BLSP1_QUP5_I2C_APPS_CBCR                           (0x0848)
+#define BLSP1_QUP5_SPI_APPS_CMD_RCGR                       (0x084C)
+#define BLSP1_UART5_APPS_CBCR                              (0x0884)
+#define BLSP1_UART5_APPS_CMD_RCGR                          (0x088C)
+#define BLSP1_QUP6_SPI_APPS_CBCR                           (0x08C4)
+#define BLSP1_QUP6_I2C_APPS_CBCR                           (0x08C8)
+#define BLSP1_QUP6_SPI_APPS_CMD_RCGR                       (0x08CC)
+#define BLSP1_UART6_APPS_CBCR                              (0x0904)
+#define BLSP1_UART6_APPS_CMD_RCGR                          (0x090C)
+#define PDM_AHB_CBCR                                       (0x0CC4)
+#define PDM2_CBCR                                          (0x0CCC)
+#define PDM2_CMD_RCGR                                      (0x0CD0)
+#define PRNG_AHB_CBCR                                      (0x0D04)
+#define BAM_DMA_AHB_CBCR                                   (0x0D44)
+#define BAM_DMA_INACTIVITY_TIMERS_CBCR                     (0x0D48)
+#define BOOT_ROM_AHB_CBCR                                  (0x0E04)
+#define RPM_MISC                                           (0x0F24)
+#define CE1_CMD_RCGR                                       (0x1050)
+#define CE1_CBCR                                           (0x1044)
+#define CE1_AXI_CBCR                                       (0x1048)
+#define CE1_AHB_CBCR                                       (0x104C)
+#define GCC_XO_DIV4_CBCR                                   (0x10C8)
+#define LPASS_Q6_AXI_CBCR                                  (0x11C0)
+#define APCS_GPLL_ENA_VOTE                                 (0x1480)
+#define APCS_CLOCK_BRANCH_ENA_VOTE                         (0x1484)
+#define GCC_DEBUG_CLK_CTL                                  (0x1880)
+#define CLOCK_FRQ_MEASURE_CTL                              (0x1884)
+#define CLOCK_FRQ_MEASURE_STATUS                           (0x1888)
+#define PLLTEST_PAD_CFG                                    (0x188C)
+#define PCIE_CFG_AHB_CBCR                                  (0x1C04)
+#define PCIE_PIPE_CBCR                                     (0x1C08)
+#define PCIE_AXI_CBCR                                      (0x1C0C)
+#define PCIE_SLEEP_CBCR                                    (0x1C10)
+#define PCIE_AXI_MSTR_CBCR                                 (0x1C2C)
+#define PCIE_PIPE_CMD_RCGR                                 (0x1C14)
+#define PCIE_AUX_CMD_RCGR                                  (0x1E00)
+#define Q6SS_AHB_LFABIF_CBCR                               (0x22000)
+#define Q6SS_AHBM_CBCR                                     (0x22004)
+
+DEFINE_CLK_RPM_SMD_BRANCH(xo, xo_a_clk, RPM_MISC_CLK_TYPE, CXO_ID, 19200000);
+
+static unsigned int soft_vote_gpll0;
+
+static struct pll_vote_clk gpll0 = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_MODE,
+	.status_mask = BIT(31),
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.rate = 600000000,
+		.parent = &xo.c,
+		.dbg_name = "gpll0",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0.c),
+	},
+};
+
+/* Don't vote for xo if using this clock to allow xo shutdown */
+static struct pll_vote_clk gpll0_ao = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_MODE,
+	.status_mask = BIT(31),
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.rate = 600000000,
+		.dbg_name = "gpll0_ao",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0_ao.c),
+	},
+};
+
+static struct pll_vote_clk gpll1 = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(1),
+	.status_reg = (void __iomem *)GPLL1_MODE,
+	.status_mask = BIT(31),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.rate = 480000000,
+		.parent = &xo.c,
+		.dbg_name = "gpll1",
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(gpll1.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb30_master_clk[] = {
+	F( 125000000,      gpll0,    1,    5,    24),
+	F_END
+};
+
+static struct rcg_clk usb30_master_clk_src = {
+	.cmd_rcgr_reg = USB30_MASTER_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_usb30_master_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb30_master_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOW, 125000000),
+		CLK_INIT(usb30_master_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_qup1_6_i2c_apps_clk[] = {
+	F(  19200000,         xo,    1,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup1_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP1_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup1_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(blsp1_qup1_i2c_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_qup1_6_spi_apps_clk[] = {
+	F(    960000,         xo,   10,    1,     2),
+	F(   4800000,         xo,    4,    0,     0),
+	F(   9600000,         xo,    2,    0,     0),
+	F(  15000000,      gpll0,   10,    1,     4),
+	F(  19200000,         xo,    1,    0,     0),
+	F(  25000000,      gpll0,   12,    1,     2),
+	F(  50000000,      gpll0,   12,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup1_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP1_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup1_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup1_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup2_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP2_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup2_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(blsp1_qup2_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup2_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP2_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup2_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup2_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup3_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP3_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup3_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(blsp1_qup3_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup3_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP3_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup3_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup3_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup4_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP4_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup4_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(blsp1_qup4_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup4_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP4_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup4_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup4_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup5_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP5_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup5_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(blsp1_qup5_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup5_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP5_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup5_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup5_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup6_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP6_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup6_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(blsp1_qup6_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup6_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP6_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup6_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup6_spi_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_uart1_6_apps_clk[] = {
+	F(   3686400,      gpll0,    1,   96, 15625),
+	F(   7372800,      gpll0,    1,  192, 15625),
+	F(  14745600,      gpll0,    1,  384, 15625),
+	F(  16000000,      gpll0,    5,    2,    15),
+	F(  19200000,         xo,    1,    0,     0),
+	F(  24000000,      gpll0,    5,    1,     5),
+	F(  32000000,      gpll0,    1,    4,    75),
+	F(  40000000,      gpll0,   15,    0,     0),
+	F(  46400000,      gpll0,    1,   29,   375),
+	F(  48000000,      gpll0, 12.5,    0,     0),
+	F(  51200000,      gpll0,    1,   32,   375),
+	F(  56000000,      gpll0,    1,    7,    75),
+	F(  58982400,      gpll0,    1, 1536, 15625),
+	F(  60000000,      gpll0,   10,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_uart1_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart2_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart2_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart3_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART3_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart3_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart3_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart4_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART4_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart4_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart4_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart5_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART5_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart5_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart5_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart6_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART6_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart6_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart6_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_ce1_clk[] = {
+	F(  50000000,      gpll0,   12,    0,     0),
+	F(  85710000,      gpll0,    7,    0,     0),
+	F( 100000000,      gpll0,    6,    0,     0),
+	F( 171430000,      gpll0,  3.5,    0,     0),
+	F( 200000000,      gpll0,    3,    0,     0),
+	F_END
+};
+
+static struct rcg_clk ce1_clk_src = {
+	.cmd_rcgr_reg = CE1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_ce1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "ce1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 85710000, NOMINAL, 171430000, HIGH,
+			200000000),
+		CLK_INIT(ce1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_pcie_sleep_clk[] = {
+	F(   1000000,         xo,    1,    5,    96),
+	F_END
+};
+
+static struct rcg_clk pcie_aux_clk_src = {
+	.cmd_rcgr_reg = PCIE_AUX_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_pcie_sleep_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "pcie_aux_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOW, 1000000),
+		CLK_INIT(pcie_aux_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_pcie_pipe_clk[] = {
+	F_EXT_SRC(  62500000, pcie_pipe_clk,    2,    0,     0),
+	F_EXT_SRC( 125000000, pcie_pipe_clk,    1,    0,     0),
+	F_END
+};
+
+static struct rcg_clk pcie_pipe_clk_src = {
+	.cmd_rcgr_reg = PCIE_PIPE_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_pcie_pipe_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "pcie_pipe_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 62500000, NOMINAL, 125000000),
+		CLK_INIT(pcie_pipe_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_pdm2_clk[] = {
+	F(  60000000,      gpll0,   10,    0,     0),
+	F_END
+};
+
+static struct rcg_clk pdm2_clk_src = {
+	.cmd_rcgr_reg = PDM2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_pdm2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "pdm2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 60000000),
+		CLK_INIT(pdm2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_sdcc2_3_apps_clk[] = {
+	F(    144000,         xo,   16,    3,    25),
+	F(    400000,         xo,   12,    1,     4),
+	F(  20000000,      gpll0,   15,    1,     2),
+	F(  25000000,      gpll0,   12,    1,     2),
+	F(  50000000,      gpll0,   12,    0,     0),
+	F( 100000000,      gpll0,    6,    0,     0),
+	F( 200000000,      gpll0,    3,    0,     0),
+	F_END
+};
+
+static struct rcg_clk sdcc2_apps_clk_src = {
+	.cmd_rcgr_reg = SDCC2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc2_3_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(sdcc2_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk sdcc3_apps_clk_src = {
+	.cmd_rcgr_reg = SDCC3_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc2_3_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc3_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 100000000),
+		CLK_INIT(sdcc3_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb3_aux_clk[] = {
+	F(   1000000,         xo,    1,    5,    96),
+	F_END
+};
+
+static struct rcg_clk usb3_aux_clk_src = {
+	.cmd_rcgr_reg = USB3_AUX_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_usb3_aux_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb3_aux_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOW, 1000000),
+		CLK_INIT(usb3_aux_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb3_pipe_clk[] = {
+	F_EXT_SRC( 125000000, usb3_pipe_clk,    1,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb3_pipe_clk_src = {
+	.cmd_rcgr_reg = USB3_PIPE_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb3_pipe_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb3_pipe_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 125000000),
+		CLK_INIT(usb3_pipe_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb30_mock_utmi_clk[] = {
+	F(  60000000,      gpll0,   10,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb30_mock_utmi_clk_src = {
+	.cmd_rcgr_reg = USB30_MOCK_UTMI_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb30_mock_utmi_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb30_mock_utmi_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 60000000),
+		CLK_INIT(usb30_mock_utmi_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hs_system_clk[] = {
+	F(  60000000,      gpll0,   10,    0,     0),
+	F(  75000000,      gpll0,    8,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb_hs_system_clk_src = {
+	.cmd_rcgr_reg = USB_HS_SYSTEM_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hs_system_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hs_system_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 60000000, NOMINAL, 75000000),
+		CLK_INIT(usb_hs_system_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hsic_clk[] = {
+	F( 480000000,      gpll1,    1,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_clk_src = {
+	.cmd_rcgr_reg = USB_HSIC_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hsic_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hsic_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 480000000),
+		CLK_INIT(usb_hsic_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hsic_io_cal_clk[] = {
+	F(   9600000,         xo,    2,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_io_cal_clk_src = {
+	.cmd_rcgr_reg = USB_HSIC_IO_CAL_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hsic_io_cal_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hsic_io_cal_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 9600000),
+		CLK_INIT(usb_hsic_io_cal_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hsic_system_clk[] = {
+	F(  60000000,      gpll0,   10,    0,     0),
+	F(  75000000,      gpll0,    8,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_system_clk_src = {
+	.cmd_rcgr_reg = USB_HSIC_SYSTEM_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hsic_system_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hsic_system_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 60000000, NOMINAL, 75000000),
+		CLK_INIT(usb_hsic_system_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hsic_xcvr_fs_clk[] = {
+	F(  60000000,      gpll0,   10,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb_hsic_xcvr_fs_clk_src = {
+	.cmd_rcgr_reg = USB_HSIC_XCVR_FS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hsic_xcvr_fs_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hsic_xcvr_fs_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 60000000),
+		CLK_INIT(usb_hsic_xcvr_fs_clk_src.c),
+	},
+};
+
+DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_ID, NULL);
+
+DEFINE_CLK_RPM_SMD(cnoc_clk, cnoc_a_clk, RPM_BUS_CLK_TYPE, CNOC_ID, NULL);
+
+DEFINE_CLK_RPM_SMD(pnoc_clk, pnoc_a_clk, RPM_BUS_CLK_TYPE, PNOC_ID, NULL);
+
+DEFINE_CLK_RPM_SMD_QDSS(qdss_clk, qdss_a_clk, RPM_MISC_CLK_TYPE, QDSS_ID);
+
+DEFINE_CLK_RPM_SMD(qpic_clk, qpic_a_clk, RPM_QPIC_CLK_TYPE, QPIC_ID, NULL);
+
+DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_ID, NULL);
+
+static struct local_vote_clk gcc_bam_dma_ahb_clk = {
+	.cbcr_reg = BAM_DMA_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(12),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_bam_dma_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_bam_dma_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_bam_dma_inactivity_timers_clk = {
+	.cbcr_reg = BAM_DMA_INACTIVITY_TIMERS_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_bam_dma_inactivity_timers_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_bam_dma_inactivity_timers_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_blsp1_ahb_clk = {
+	.cbcr_reg = BLSP1_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(17),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_blsp1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_i2c_apps_clk",
+		.parent = &blsp1_qup1_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_spi_apps_clk",
+		.parent = &blsp1_qup1_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_i2c_apps_clk",
+		.parent = &blsp1_qup2_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_spi_apps_clk",
+		.parent = &blsp1_qup2_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_i2c_apps_clk",
+		.parent = &blsp1_qup3_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_spi_apps_clk",
+		.parent = &blsp1_qup3_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_i2c_apps_clk",
+		.parent = &blsp1_qup4_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_spi_apps_clk",
+		.parent = &blsp1_qup4_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup5_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP5_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup5_i2c_apps_clk",
+		.parent = &blsp1_qup5_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup5_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup5_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP5_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup5_spi_apps_clk",
+		.parent = &blsp1_qup5_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup5_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup6_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP6_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup6_i2c_apps_clk",
+		.parent = &blsp1_qup6_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup6_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup6_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP6_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup6_spi_apps_clk",
+		.parent = &blsp1_qup6_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup6_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart1_apps_clk = {
+	.cbcr_reg = BLSP1_UART1_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart1_apps_clk",
+		.parent = &blsp1_uart1_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart2_apps_clk = {
+	.cbcr_reg = BLSP1_UART2_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart2_apps_clk",
+		.parent = &blsp1_uart2_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart2_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart3_apps_clk = {
+	.cbcr_reg = BLSP1_UART3_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart3_apps_clk",
+		.parent = &blsp1_uart3_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart3_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart4_apps_clk = {
+	.cbcr_reg = BLSP1_UART4_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart4_apps_clk",
+		.parent = &blsp1_uart4_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart4_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart5_apps_clk = {
+	.cbcr_reg = BLSP1_UART5_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart5_apps_clk",
+		.parent = &blsp1_uart5_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart5_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart6_apps_clk = {
+	.cbcr_reg = BLSP1_UART6_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart6_apps_clk",
+		.parent = &blsp1_uart6_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart6_apps_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_boot_rom_ahb_clk = {
+	.cbcr_reg = BOOT_ROM_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(10),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_boot_rom_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_boot_rom_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce1_ahb_clk = {
+	.cbcr_reg = CE1_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(3),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce1_axi_clk = {
+	.cbcr_reg = CE1_AXI_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(4),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_axi_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_axi_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce1_clk = {
+	.cbcr_reg = CE1_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(5),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_lpass_q6_axi_clk = {
+	.cbcr_reg = LPASS_Q6_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_lpass_q6_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_lpass_q6_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_cfg_ahb_clk = {
+	.cbcr_reg = MSS_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mss_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_cfg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_q6_bimc_axi_clk = {
+	.cbcr_reg = MSS_Q6_BIMC_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mss_q6_bimc_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_q6_bimc_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pcie_axi_clk = {
+	.cbcr_reg = PCIE_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pcie_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pcie_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pcie_axi_mstr_clk = {
+	.cbcr_reg = PCIE_AXI_MSTR_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pcie_axi_mstr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pcie_axi_mstr_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pcie_cfg_ahb_clk = {
+	.cbcr_reg = PCIE_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pcie_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pcie_cfg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pcie_pipe_clk = {
+	.cbcr_reg = PCIE_PIPE_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pcie_pipe_clk",
+		.parent = &pcie_pipe_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pcie_pipe_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pcie_sleep_clk = {
+	.cbcr_reg = PCIE_SLEEP_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pcie_sleep_clk",
+		.parent = &pcie_aux_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pcie_sleep_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm2_clk = {
+	.cbcr_reg = PDM2_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pdm2_clk",
+		.parent = &pdm2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm_ahb_clk = {
+	.cbcr_reg = PDM_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pdm_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_prng_ahb_clk = {
+	.cbcr_reg = PRNG_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(13),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_prng_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_prng_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc2_ahb_clk = {
+	.cbcr_reg = SDCC2_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc2_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc2_apps_clk = {
+	.cbcr_reg = SDCC2_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc2_apps_clk",
+		.parent = &sdcc2_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc3_ahb_clk = {
+	.cbcr_reg = SDCC3_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc3_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc3_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc3_apps_clk = {
+	.cbcr_reg = SDCC3_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc3_apps_clk",
+		.parent = &sdcc3_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc3_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sys_noc_usb3_axi_clk = {
+	.cbcr_reg = SYS_NOC_USB3_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sys_noc_usb3_axi_clk",
+		.parent = &usb30_master_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sys_noc_usb3_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb3_aux_clk = {
+	.cbcr_reg = USB3_AUX_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb3_aux_clk",
+		.parent = &usb3_aux_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb3_aux_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb3_pipe_clk = {
+	.cbcr_reg = USB3_PIPE_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb3_pipe_clk",
+		.parent = &usb3_pipe_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb3_pipe_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb30_master_clk = {
+	.cbcr_reg = USB30_MASTER_CBCR,
+	.bcr_reg = USB_30_BCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb30_master_clk",
+		.parent = &usb30_master_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb30_master_clk.c),
+		.depends = &gcc_sys_noc_usb3_axi_clk.c,
+	},
+};
+
+static struct branch_clk gcc_usb30_mock_utmi_clk = {
+	.cbcr_reg = USB30_MOCK_UTMI_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb30_mock_utmi_clk",
+		.parent = &usb30_mock_utmi_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb30_mock_utmi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb30_sleep_clk = {
+	.cbcr_reg = USB30_SLEEP_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb30_sleep_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb30_sleep_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_ahb_clk = {
+	.cbcr_reg = USB_HS_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_system_clk = {
+	.cbcr_reg = USB_HS_SYSTEM_CBCR,
+	.has_sibling = 0,
+	.bcr_reg = USB_HS_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_system_clk",
+		.parent = &usb_hs_system_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_system_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_ahb_clk = {
+	.cbcr_reg = USB_HSIC_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_clk = {
+	.cbcr_reg = USB_HSIC_CBCR,
+	.has_sibling = 0,
+	.bcr_reg = USB_HS_HSIC_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_clk",
+		.parent = &usb_hsic_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_io_cal_clk = {
+	.cbcr_reg = USB_HSIC_IO_CAL_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_io_cal_clk",
+		.parent = &usb_hsic_io_cal_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_io_cal_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_io_cal_sleep_clk = {
+	.cbcr_reg = USB_HSIC_IO_CAL_SLEEP_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_io_cal_sleep_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_io_cal_sleep_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_system_clk = {
+	.cbcr_reg = USB_HSIC_SYSTEM_CBCR,
+	.has_sibling = 0,
+	.bcr_reg = USB_HS_HSIC_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_system_clk",
+		.parent = &usb_hsic_system_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_system_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hsic_xcvr_fs_clk = {
+	.cbcr_reg = USB_HSIC_XCVR_FS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hsic_xcvr_fs_clk",
+		.parent = &usb_hsic_xcvr_fs_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hsic_xcvr_fs_clk.c),
+	},
+};
+
+static struct branch_clk q6ss_ahb_lfabif_clk = {
+	.cbcr_reg = Q6SS_AHB_LFABIF_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "q6ss_ahb_lfabif_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(q6ss_ahb_lfabif_clk.c),
+	},
+};
+
+static struct branch_clk q6ss_ahbm_clk = {
+	.cbcr_reg = Q6SS_AHBM_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "q6ss_ahbm_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(q6ss_ahbm_clk.c),
+	},
+};
+
+static DEFINE_CLK_VOTER(pnoc_msmbus_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_clk, &snoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_msmbus_clk, &cnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_msmbus_a_clk, &pnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_a_clk, &snoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_msmbus_a_clk, &cnoc_a_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(bimc_msmbus_clk, &bimc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(pnoc_sdcc2_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_sdcc3_clk, &pnoc_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, LONG_MAX);
+
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_lpass_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_mss_clk, &xo.c);
+
+static DEFINE_CLK_MEASURE(a7_m_clk);
+
+#ifdef CONFIG_DEBUG_FS
+
+struct measure_mux_entry {
+	struct clk *c;
+	int base;
+	u32 debug_mux;
+};
+
+struct measure_mux_entry measure_mux[] = {
+	{&gcc_mss_cfg_ahb_clk.c,               GCC_BASE, 0x0030},
+	{&gcc_mss_q6_bimc_axi_clk.c,           GCC_BASE, 0x0031},
+	{&gcc_usb30_master_clk.c,              GCC_BASE, 0x0050},
+	{&gcc_usb30_sleep_clk.c,               GCC_BASE, 0x0051},
+	{&gcc_usb30_mock_utmi_clk.c,           GCC_BASE, 0x0052},
+	{&gcc_usb3_pipe_clk.c,                 GCC_BASE, 0x0054},
+	{&gcc_usb3_aux_clk.c,                  GCC_BASE, 0x0055},
+	{&gcc_usb_hsic_ahb_clk.c,              GCC_BASE, 0x0058},
+	{&gcc_usb_hsic_system_clk.c,           GCC_BASE, 0x0059},
+	{&gcc_usb_hsic_clk.c,                  GCC_BASE, 0x005a},
+	{&gcc_usb_hsic_io_cal_clk.c,           GCC_BASE, 0x005b},
+	{&gcc_usb_hsic_io_cal_sleep_clk.c,     GCC_BASE, 0x005c},
+	{&gcc_usb_hsic_xcvr_fs_clk.c,          GCC_BASE, 0x005d},
+	{&gcc_usb_hs_system_clk.c,             GCC_BASE, 0x0060},
+	{&gcc_usb_hs_ahb_clk.c,                GCC_BASE, 0x0061},
+	{&gcc_sdcc2_apps_clk.c,                GCC_BASE, 0x0070},
+	{&gcc_sdcc2_ahb_clk.c,                 GCC_BASE, 0x0071},
+	{&gcc_sdcc3_apps_clk.c,                GCC_BASE, 0x0078},
+	{&gcc_sdcc3_ahb_clk.c,                 GCC_BASE, 0x0079},
+	{&gcc_blsp1_ahb_clk.c,                 GCC_BASE, 0x0088},
+	{&gcc_blsp1_qup1_spi_apps_clk.c,       GCC_BASE, 0x008a},
+	{&gcc_blsp1_qup1_i2c_apps_clk.c,       GCC_BASE, 0x008b},
+	{&gcc_blsp1_uart1_apps_clk.c,          GCC_BASE, 0x008c},
+	{&gcc_blsp1_qup2_spi_apps_clk.c,       GCC_BASE, 0x008e},
+	{&gcc_blsp1_qup2_i2c_apps_clk.c,       GCC_BASE, 0x0090},
+	{&gcc_blsp1_uart2_apps_clk.c,          GCC_BASE, 0x0091},
+	{&gcc_blsp1_qup3_spi_apps_clk.c,       GCC_BASE, 0x0093},
+	{&gcc_blsp1_qup3_i2c_apps_clk.c,       GCC_BASE, 0x0094},
+	{&gcc_blsp1_uart3_apps_clk.c,          GCC_BASE, 0x0095},
+	{&gcc_blsp1_qup4_spi_apps_clk.c,       GCC_BASE, 0x0098},
+	{&gcc_blsp1_qup4_i2c_apps_clk.c,       GCC_BASE, 0x0099},
+	{&gcc_blsp1_uart4_apps_clk.c,          GCC_BASE, 0x009a},
+	{&gcc_blsp1_qup5_spi_apps_clk.c,       GCC_BASE, 0x009c},
+	{&gcc_blsp1_qup5_i2c_apps_clk.c,       GCC_BASE, 0x009d},
+	{&gcc_blsp1_uart5_apps_clk.c,          GCC_BASE, 0x009e},
+	{&gcc_blsp1_qup6_spi_apps_clk.c,       GCC_BASE, 0x00a1},
+	{&gcc_blsp1_qup6_i2c_apps_clk.c,       GCC_BASE, 0x00a2},
+	{&gcc_blsp1_uart6_apps_clk.c,          GCC_BASE, 0x00a3},
+	{&gcc_pdm_ahb_clk.c,                   GCC_BASE, 0x00d0},
+	{&gcc_pdm2_clk.c,                      GCC_BASE, 0x00d2},
+	{&gcc_prng_ahb_clk.c,                  GCC_BASE, 0x00d8},
+	{&gcc_bam_dma_ahb_clk.c,               GCC_BASE, 0x00e0},
+	{&gcc_bam_dma_inactivity_timers_clk.c, GCC_BASE, 0x00e1},
+	{&gcc_boot_rom_ahb_clk.c,              GCC_BASE, 0x00f8},
+	{&gcc_ce1_clk.c,                       GCC_BASE, 0x0138},
+	{&gcc_ce1_axi_clk.c,                   GCC_BASE, 0x0139},
+	{&gcc_ce1_ahb_clk.c,                   GCC_BASE, 0x013a},
+	{&gcc_lpass_q6_axi_clk.c,              GCC_BASE, 0x0160},
+	{&gcc_pcie_cfg_ahb_clk.c,              GCC_BASE, 0x01f0},
+	{&gcc_pcie_pipe_clk.c,                 GCC_BASE, 0x01f1},
+	{&gcc_pcie_axi_clk.c,                  GCC_BASE, 0x01f2},
+	{&gcc_pcie_sleep_clk.c,                GCC_BASE, 0x01f3},
+	{&gcc_pcie_axi_mstr_clk.c,             GCC_BASE, 0x01f4},
+
+	{&bimc_clk.c,                          GCC_BASE, 0x0155},
+	{&cnoc_clk.c,                          GCC_BASE, 0x0008},
+	{&pnoc_clk.c,                          GCC_BASE, 0x0010},
+	{&snoc_clk.c,                          GCC_BASE, 0x0000},
+
+	{&q6ss_ahbm_clk.c,                   LPASS_BASE, 0x001d},
+	{&q6ss_ahb_lfabif_clk.c,             LPASS_BASE, 0x001e},
+
+	{&a7_m_clk,			  APCS_GCC_BASE,    0x3},
+	{&dummy_clk,				N_BASES, 0x0000},
+};
+
+static int measure_clk_set_parent(struct clk *c, struct clk *parent)
+{
+	struct measure_clk *clk = to_measure_clk(c);
+	unsigned long flags;
+	u32 regval, clk_sel, i;
+
+	if (!parent)
+		return -EINVAL;
+
+	for (i = 0; i < (ARRAY_SIZE(measure_mux) - 1); i++)
+		if (measure_mux[i].c == parent)
+			break;
+
+	if (measure_mux[i].c == &dummy_clk)
+		return -EINVAL;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	/*
+	 * Program the test vector, measurement period (sample_ticks)
+	 * and scaling multiplier.
+	 */
+	clk->sample_ticks = 0x10000;
+	clk->multiplier = 1;
+
+	writel_relaxed(0, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+
+	switch (measure_mux[i].base) {
+
+	case GCC_BASE:
+		clk_sel = measure_mux[i].debug_mux;
+		break;
+
+	case APCS_GCC_BASE:
+		clk_sel = 0x16A;
+		regval = BVAL(5, 3, measure_mux[i].debug_mux);
+		writel_relaxed(regval, APCS_GCC_BASE(APCS_CLK_DIAG));
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Set debug mux clock index */
+	regval = BVAL(9, 0, clk_sel);
+	writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+
+	/* Activate debug clock output */
+	regval |= BIT(16);
+	writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+
+	/* Make sure test vector is set before starting measurements. */
+	mb();
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	return 0;
+}
+
+/* Sample clock for 'ticks' reference clock ticks. */
+static u32 run_measurement(unsigned ticks)
+{
+	/* Stop counters and set the XO4 counter start value. */
+	writel_relaxed(ticks, GCC_REG_BASE(CLOCK_FRQ_MEASURE_CTL));
+
+	/* Wait for timer to become ready. */
+	while ((readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS)) &
+			BIT(25)) != 0)
+		cpu_relax();
+
+	/* Run measurement and wait for completion. */
+	writel_relaxed(BIT(20)|ticks, GCC_REG_BASE(CLOCK_FRQ_MEASURE_CTL));
+	while ((readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS)) &
+			BIT(25)) == 0)
+		cpu_relax();
+
+	/* Return measured ticks. */
+	return readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS)) &
+				BM(24, 0);
+}
+
+/*
+ * Perform a hardware rate measurement for a given clock.
+ * FOR DEBUG USE ONLY: Measurements take ~15 ms!
+ */
+static unsigned long measure_clk_get_rate(struct clk *c)
+{
+	unsigned long flags;
+	u32 gcc_xo4_reg_backup;
+	u64 raw_count_short, raw_count_full;
+	struct measure_clk *clk = to_measure_clk(c);
+	unsigned ret;
+
+	ret = clk_prepare_enable(&xo.c);
+	if (ret) {
+		pr_warning("CXO clock failed to enable. Can't measure\n");
+		return 0;
+	}
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+
+	/* Enable CXO/4 and RINGOSC branch. */
+	gcc_xo4_reg_backup = readl_relaxed(GCC_REG_BASE(GCC_XO_DIV4_CBCR));
+	writel_relaxed(0x1, GCC_REG_BASE(GCC_XO_DIV4_CBCR));
+
+	/*
+	 * The ring oscillator counter will not reset if the measured clock
+	 * is not running.  To detect this, run a short measurement before
+	 * the full measurement.  If the raw results of the two are the same
+	 * then the clock must be off.
+	 */
+
+	/* Run a short measurement. (~1 ms) */
+	raw_count_short = run_measurement(0x1000);
+	/* Run a full measurement. (~14 ms) */
+	raw_count_full = run_measurement(clk->sample_ticks);
+
+	writel_relaxed(gcc_xo4_reg_backup, GCC_REG_BASE(GCC_XO_DIV4_CBCR));
+
+	/* Return 0 if the clock is off. */
+	if (raw_count_full == raw_count_short) {
+		ret = 0;
+	} else {
+		/* Compute rate in Hz. */
+		raw_count_full = ((raw_count_full * 10) + 15) * 4800000;
+		do_div(raw_count_full, ((clk->sample_ticks * 10) + 35));
+		ret = (raw_count_full * clk->multiplier);
+	}
+
+	writel_relaxed(0x51A00, GCC_REG_BASE(PLLTEST_PAD_CFG));
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	clk_disable_unprepare(&xo.c);
+
+	return ret;
+}
+#else /* !CONFIG_DEBUG_FS */
+static int measure_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	return -EINVAL;
+}
+
+static unsigned long measure_clk_get_rate(struct clk *clk)
+{
+	return 0;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static struct clk_ops clk_ops_measure = {
+	.set_parent = measure_clk_set_parent,
+	.get_rate = measure_clk_get_rate,
+};
+
+static struct measure_clk measure_clk = {
+	.c = {
+		.dbg_name = "measure_clk",
+		.ops = &clk_ops_measure,
+		CLK_INIT(measure_clk.c),
+	},
+	.multiplier = 1,
+};
+
+static struct clk_lookup msm_clocks_krypton[] = {
+	CLK_LOOKUP("xo",	xo.c,	""),
+	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
+
+	/* PLLS */
+	CLK_LOOKUP("",	gpll0.c,	""),
+	CLK_LOOKUP("",	gpll1.c,	""),
+	CLK_LOOKUP("",  gpll0_ao.c,     ""),
+
+	/* PIL-LPASS */
+	CLK_LOOKUP("xo",          cxo_pil_lpass_clk.c, "fe200000.qcom,lpass"),
+	CLK_LOOKUP("bus_clk",  gcc_lpass_q6_axi_clk.c, "fe200000.qcom,lpass"),
+	CLK_LOOKUP("core_clk",    cxo_pil_lpass_clk.c, "fe200000.qcom,lpass"),
+	CLK_LOOKUP("iface_clk", q6ss_ahb_lfabif_clk.c, "fe200000.qcom,lpass"),
+	CLK_LOOKUP("reg_clk",         q6ss_ahbm_clk.c, "fe200000.qcom,lpass"),
+
+	/* PIL-MODEM */
+	CLK_LOOKUP("xo",              cxo_pil_mss_clk.c, "fc880000.qcom,mss"),
+	CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "fc880000.qcom,mss"),
+	CLK_LOOKUP("iface_clk",   gcc_mss_cfg_ahb_clk.c, "fc880000.qcom,mss"),
+	CLK_LOOKUP("mem_clk",    gcc_boot_rom_ahb_clk.c, "fc880000.qcom,mss"),
+
+	/* SPS */
+	CLK_LOOKUP("dma_bam_pclk", gcc_bam_dma_ahb_clk.c, "msm_sps"),
+	CLK_LOOKUP("inactivity_clk", gcc_bam_dma_inactivity_timers_clk.c,
+								"msm_sps"),
+	CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "msm_sps"),
+
+
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991f000.serial"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart3_apps_clk.c, "f991f000.serial"),
+
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9928000.spi"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup6_spi_apps_clk.c, "f9928000.spi"),
+
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9925000.i2c"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, "f9925000.i2c"),
+
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991d000.uart"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart1_apps_clk.c, "f991d000.uart"),
+
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup3_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup4_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup4_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup5_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup5_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup6_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup6_spi_apps_clk.c, ""),
+
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart2_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart4_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart5_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart6_apps_clk.c, ""),
+
+	CLK_LOOKUP("iface_clk", gcc_prng_ahb_clk.c, "f9bff000.qcom,msm-rng"),
+
+	CLK_LOOKUP("core_clk", gcc_pdm2_clk.c, ""),
+	CLK_LOOKUP("iface_clk", gcc_pdm_ahb_clk.c, ""),
+
+	CLK_LOOKUP("iface_clk", gcc_sdcc2_ahb_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("core_clk", gcc_sdcc2_apps_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("bus_clk",  pnoc_sdcc2_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("iface_clk", gcc_sdcc3_ahb_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("core_clk", gcc_sdcc3_apps_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("bus_clk", pnoc_sdcc3_clk.c, "msm_sdcc.3"),
+
+	CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c,     "f9a55000.usb"),
+	CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c,   "f9a55000.usb"),
+	CLK_LOOKUP("iface_clk", gcc_usb_hsic_ahb_clk.c,	  "msm_hsic_host"),
+	CLK_LOOKUP("phy_clk", gcc_usb_hsic_clk.c,	  "msm_hsic_host"),
+	CLK_LOOKUP("cal_clk", gcc_usb_hsic_io_cal_clk.c,  "msm_hsic_host"),
+	CLK_LOOKUP("core_clk", gcc_usb_hsic_system_clk.c, "msm_hsic_host"),
+	CLK_LOOKUP("alt_core_clk", gcc_usb_hsic_xcvr_fs_clk.c, ""),
+	CLK_LOOKUP("inactivity_clk", gcc_usb_hsic_io_cal_sleep_clk.c,
+							"msm_hsic_host"),
+
+	CLK_LOOKUP("core_clk", gcc_ce1_clk.c, "fd400000.qcom,qcedev"),
+	CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "fd400000.qcom,qcedev"),
+	CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "fd400000.qcom,qcedev"),
+	CLK_LOOKUP("core_clk_src", ce1_clk_src.c, "fd400000.qcom,qcedev"),
+
+	CLK_LOOKUP("core_clk", gcc_ce1_clk.c, "fd400000.qcom,qcrypto"),
+	CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "fd400000.qcom,qcrypto"),
+	CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "fd400000.qcom,qcrypto"),
+	CLK_LOOKUP("core_clk_src", ce1_clk_src.c, "fd400000.qcom,qcrypto"),
+
+	/* RPM and voter clocks */
+	CLK_LOOKUP("bus_clk", snoc_clk.c, ""),
+	CLK_LOOKUP("bus_clk", pnoc_clk.c, ""),
+	CLK_LOOKUP("bus_clk", cnoc_clk.c, ""),
+	CLK_LOOKUP("mem_clk", bimc_clk.c, ""),
+	CLK_LOOKUP("bus_clk", snoc_a_clk.c, ""),
+	CLK_LOOKUP("bus_clk", pnoc_a_clk.c, ""),
+	CLK_LOOKUP("bus_clk", cnoc_a_clk.c, ""),
+	CLK_LOOKUP("mem_clk", bimc_a_clk.c, ""),
+
+	CLK_LOOKUP("bus_clk",	cnoc_msmbus_clk.c,	"msm_config_noc"),
+	CLK_LOOKUP("bus_a_clk",	cnoc_msmbus_a_clk.c,	"msm_config_noc"),
+	CLK_LOOKUP("bus_clk",	snoc_msmbus_clk.c,	"msm_sys_noc"),
+	CLK_LOOKUP("bus_a_clk",	snoc_msmbus_a_clk.c,	"msm_sys_noc"),
+	CLK_LOOKUP("bus_clk",	pnoc_msmbus_clk.c,	"msm_periph_noc"),
+	CLK_LOOKUP("bus_a_clk",	pnoc_msmbus_a_clk.c,	"msm_periph_noc"),
+	CLK_LOOKUP("mem_clk",	bimc_msmbus_clk.c,	"msm_bimc"),
+	CLK_LOOKUP("mem_a_clk",	bimc_msmbus_a_clk.c,	"msm_bimc"),
+
+	CLK_LOOKUP("a7_m_clk", a7_m_clk, ""),
+
+	/* CoreSight clocks */
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc322000.tmc"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc318000.tpiu"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc31c000.replicator"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc307000.tmc"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc31b000.funnel"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc319000.funnel"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc31a000.funnel"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc321000.stm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc332000.etm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc332000.jtagmm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc308000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc309000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30a000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30b000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30c000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30d000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30e000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc30f000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc310000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fc333000.cti"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "f9011038.hwevent"),
+
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31c000.replicator"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc307000.tmc"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31b000.funnel"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc319000.funnel"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31a000.funnel"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc321000.stm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc332000.etm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc332000.jtagmm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc308000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc309000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30a000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30b000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30c000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30d000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30e000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30f000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc310000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc333000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "f9011038.hwevent"),
+
+	/* Misc rcgs without clients */
+	CLK_LOOKUP("",	usb30_master_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup1_i2c_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup1_spi_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup2_i2c_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup2_spi_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup3_i2c_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup3_spi_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup4_i2c_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup4_spi_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup5_i2c_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup5_spi_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup6_i2c_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_qup6_spi_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_uart1_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_uart2_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_uart3_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_uart4_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_uart5_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	blsp1_uart6_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	pcie_aux_clk_src.c,	""),
+	CLK_LOOKUP("",	pcie_pipe_clk_src.c,	""),
+	CLK_LOOKUP("",	pdm2_clk_src.c,	""),
+	CLK_LOOKUP("",	sdcc2_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	sdcc3_apps_clk_src.c,	""),
+	CLK_LOOKUP("",	usb3_aux_clk_src.c,	""),
+	CLK_LOOKUP("",	usb3_pipe_clk_src.c,	""),
+	CLK_LOOKUP("",	usb30_mock_utmi_clk_src.c,	""),
+	CLK_LOOKUP("",	usb_hs_system_clk_src.c,	""),
+	CLK_LOOKUP("",	usb_hsic_clk_src.c,	""),
+	CLK_LOOKUP("",	usb_hsic_io_cal_clk_src.c,	""),
+	CLK_LOOKUP("",	usb_hsic_system_clk_src.c,	""),
+	CLK_LOOKUP("",	usb_hsic_xcvr_fs_clk_src.c,	""),
+
+	CLK_LOOKUP("",	gcc_pcie_axi_clk.c,	""),
+	CLK_LOOKUP("",	gcc_pcie_axi_mstr_clk.c,	""),
+	CLK_LOOKUP("",	gcc_pcie_cfg_ahb_clk.c,	""),
+	CLK_LOOKUP("",	gcc_pcie_pipe_clk.c,	""),
+	CLK_LOOKUP("",	gcc_pcie_sleep_clk.c,	""),
+	CLK_LOOKUP("",	gcc_sys_noc_usb3_axi_clk.c,	""),
+	CLK_LOOKUP("",	gcc_usb3_aux_clk.c,	""),
+	CLK_LOOKUP("",	gcc_usb3_pipe_clk.c,	""),
+	CLK_LOOKUP("",	gcc_usb30_master_clk.c,	""),
+	CLK_LOOKUP("",	gcc_usb30_mock_utmi_clk.c,	""),
+	CLK_LOOKUP("",	gcc_usb30_sleep_clk.c,	""),
+};
+
+static void __init reg_init(void)
+{
+	u32 regval;
+
+	/* Vote for GPLL0 to turn on. Needed by acpuclock. */
+	regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+	regval |= BIT(0);
+	writel_relaxed(regval, GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+}
+
+static void __init msmkrypton_clock_post_init(void)
+{
+	/*
+	 * Hold an active set vote for CXO; this is because CXO is expected
+	 * to remain on whenever CPUs aren't power collapsed.
+	 */
+	clk_prepare_enable(&xo_a_clk.c);
+}
+
+#define GCC_CC_PHYS		0xFC400000
+#define GCC_CC_SIZE		SZ_8K
+
+#define LPASS_CC_PHYS		0xFE000000
+#define LPASS_CC_SIZE		SZ_256K
+
+#define APCS_GLB_PHYS		0xF9010000
+#define APCS_GLB_SIZE		0x38
+
+#define APCS_GCC_PHYS		0xF9011000
+#define APCS_GCC_SIZE		0x1C
+
+#define APCS_ACC_PHYS		0xF9008000
+#define APCS_ACC_SIZE		0x40
+
+static void __init msmkrypton_clock_pre_init(void)
+{
+	virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
+	if (!virt_bases[GCC_BASE])
+		panic("clock-krypton: Unable to ioremap GCC memory!");
+
+	virt_bases[LPASS_BASE] = ioremap(LPASS_CC_PHYS, LPASS_CC_SIZE);
+	if (!virt_bases[LPASS_BASE])
+		panic("clock-8226: Unable to ioremap LPASS_CC memory!");
+
+	virt_bases[APCS_GLB_BASE] = ioremap(APCS_GLB_PHYS, APCS_GLB_SIZE);
+	if (!virt_bases[APCS_GLB_BASE])
+		panic("clock-krypton: Unable to ioremap APCS_GLB memory!");
+
+	virt_bases[APCS_GCC_BASE] = ioremap(APCS_GCC_PHYS, APCS_GCC_SIZE);
+	if (!virt_bases[APCS_GCC_BASE])
+		panic("clock-krypton: Unable to ioremap APCS_GCC memory!");
+
+	virt_bases[APCS_ACC_BASE] = ioremap(APCS_ACC_PHYS, APCS_ACC_SIZE);
+	if (!virt_bases[APCS_ACC_BASE])
+		panic("clock-krypton: Unable to ioremap APCS_PLL memory!");
+
+	vdd_dig.regulator[0] = regulator_get(NULL, "vdd_dig");
+	if (IS_ERR(vdd_dig.regulator[0]))
+		panic("clock-krypton: Unable to get the vdd_dig regulator!");
+
+	enable_rpm_scaling();
+
+	reg_init();
+}
+
 struct clock_init_data msmkrypton_clock_init_data __initdata = {
-	.table = msm_clocks_dummy,
-	.size = ARRAY_SIZE(msm_clocks_dummy),
+	.table = msm_clocks_krypton,
+	.size = ARRAY_SIZE(msm_clocks_krypton),
+	.pre_init = msmkrypton_clock_pre_init,
+	.post_init = msmkrypton_clock_post_init,
 };
diff --git a/arch/arm/mach-msm/include/mach/qseecomi.h b/arch/arm/mach-msm/include/mach/qseecomi.h
index a4021d4..688dea0 100644
--- a/arch/arm/mach-msm/include/mach/qseecomi.h
+++ b/arch/arm/mach-msm/include/mach/qseecomi.h
@@ -46,8 +46,12 @@
 	QSEOS_UNLOAD_SERV_IMAGE_COMMAND,
 	QSEOS_APP_REGION_NOTIFICATION,
 	QSEOS_REGISTER_LOG_BUF_COMMAND,
-	QSEE_RPMB_PROVISION_KEY_COMMAND,
-	QSEE_RPMB_ERASE_COMMAND,
+	QSEOS_RPMB_PROVISION_KEY_COMMAND,
+	QSEOS_RPMB_ERASE_COMMAND,
+	QSEOS_GENERATE_KEY  = 0x11,
+	QSEOS_DELETE_KEY,
+	QSEOS_MAX_KEY_COUNT,
+	QSEOS_SET_KEY,
 	QSEOS_CMD_MAX     = 0xEFFFFFFF
 };
 
@@ -57,15 +61,6 @@
 	QSEOS_RESULT_FAILURE  = 0xFFFFFFFF
 };
 
-/* Key Management requests */
-enum qseecom_qceos_key_gen_cmd_id {
-	QSEOS_GENERATE_KEY  = 0x11,
-	QSEOS_DELETE_KEY,
-	QSEOS_MAX_KEY_COUNT,
-	QSEOS_SET_KEY,
-	QSEOS_KEY_CMD_MAX   = 0xEFFFFFFF
-};
-
 enum qseecom_pipe_type {
 	QSEOS_PIPE_ENC = 0x1,
 	QSEOS_PIPE_ENC_XTS = 0x2,
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 64986d0..863a2d7 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -98,6 +98,7 @@
 #define IPC_ROUTER_LOG_EVENT_ERROR      0x00
 #define IPC_ROUTER_LOG_EVENT_TX         0x01
 #define IPC_ROUTER_LOG_EVENT_RX         0x02
+#define IPC_ROUTER_DUMMY_DEST_NODE	0xFFFFFFFF
 
 static LIST_HEAD(control_ports);
 static DECLARE_RWSEM(control_ports_lock_lha5);
@@ -926,7 +927,8 @@
 
 static int msm_ipc_router_send_control_msg(
 		struct msm_ipc_router_xprt_info *xprt_info,
-		union rr_control_msg *msg)
+		union rr_control_msg *msg,
+		uint32_t dst_node_id)
 {
 	struct rr_packet *pkt;
 	struct sk_buff *ipc_rtr_pkt;
@@ -986,7 +988,10 @@
 	hdr->src_port_id = IPC_ROUTER_ADDRESS;
 	hdr->confirm_rx = 0;
 	hdr->size = sizeof(*msg);
-	hdr->dst_node_id = xprt_info->remote_node_id;
+	if (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)
+		hdr->dst_node_id = dst_node_id;
+	else
+		hdr->dst_node_id = xprt_info->remote_node_id;
 	hdr->dst_port_id = IPC_ROUTER_ADDRESS;
 	skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
 	pkt->pkt_fragment_q = pkt_fragment_q;
@@ -1031,7 +1036,7 @@
 				ctl.srv.port_id =
 					server_port->server_addr.port_id;
 				msm_ipc_router_send_control_msg(xprt_info,
-								&ctl);
+					&ctl, IPC_ROUTER_DUMMY_DEST_NODE);
 			}
 		}
 	}
@@ -1132,7 +1137,8 @@
 
 	down_read(&xprt_info_list_lock_lha5);
 	list_for_each_entry(xprt_info, &xprt_info_list, list) {
-		msm_ipc_router_send_control_msg(xprt_info, ctl);
+		msm_ipc_router_send_control_msg(xprt_info, ctl,
+					IPC_ROUTER_DUMMY_DEST_NODE);
 	}
 	up_read(&xprt_info_list_lock_lha5);
 
@@ -1150,7 +1156,8 @@
 	down_read(&xprt_info_list_lock_lha5);
 	list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
 		if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
-			msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
+			msm_ipc_router_send_control_msg(fwd_xprt_info, ctl,
+						IPC_ROUTER_DUMMY_DEST_NODE);
 	}
 	up_read(&xprt_info_list_lock_lha5);
 
@@ -1252,7 +1259,8 @@
 		list_for_each_entry(tmp_xprt_info, &xprt_info_list, list) {
 			if (tmp_xprt_info != xprt_info)
 				continue;
-			msm_ipc_router_send_control_msg(tmp_xprt_info, &msg);
+			msm_ipc_router_send_control_msg(tmp_xprt_info, &msg,
+						IPC_ROUTER_DUMMY_DEST_NODE);
 			break;
 		}
 		up_read(&xprt_info_list_lock_lha5);
@@ -1498,7 +1506,8 @@
 	/* Send a reply HELLO message */
 	memset(&ctl, 0, sizeof(ctl));
 	ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
-	rc = msm_ipc_router_send_control_msg(xprt_info, &ctl);
+	rc = msm_ipc_router_send_control_msg(xprt_info, &ctl,
+						IPC_ROUTER_DUMMY_DEST_NODE);
 	if (rc < 0) {
 		pr_err("%s: Error sending reply HELLO message\n", __func__);
 		return rc;
@@ -1751,7 +1760,6 @@
 	struct msm_ipc_port *port_ptr;
 	struct sk_buff *head_skb;
 	struct msm_ipc_router_remote_port *rport_ptr;
-	uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
 
 	struct msm_ipc_router_xprt_info *xprt_info =
 		container_of(work,
@@ -1814,10 +1822,6 @@
 #endif
 #endif
 
-		resume_tx = hdr->confirm_rx;
-		resume_tx_node_id = hdr->dst_node_id;
-		resume_tx_port_id = hdr->dst_port_id;
-
 		down_read(&local_ports_lock_lha2);
 		port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
 		if (!port_ptr) {
@@ -1825,7 +1829,7 @@
 				hdr->dst_port_id);
 			up_read(&local_ports_lock_lha2);
 			release_pkt(pkt);
-			goto process_done;
+			return;
 		}
 
 		down_read(&routing_table_lock_lha3);
@@ -1841,26 +1845,13 @@
 					hdr->src_port_id);
 				up_read(&routing_table_lock_lha3);
 				up_read(&local_ports_lock_lha2);
-				goto process_done;
+				release_pkt(pkt);
+				return;
 			}
 		}
 		up_read(&routing_table_lock_lha3);
 		post_pkt_to_port(port_ptr, pkt, 0);
 		up_read(&local_ports_lock_lha2);
-
-process_done:
-		if (resume_tx) {
-			union rr_control_msg msg;
-			memset(&msg, 0, sizeof(msg));
-			msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
-			msg.cli.node_id = resume_tx_node_id;
-			msg.cli.port_id = resume_tx_port_id;
-
-			RR("x RESUME_TX id=%d:%08x\n",
-			   msg.cli.node_id, msg.cli.port_id);
-			msm_ipc_router_send_control_msg(xprt_info, &msg);
-		}
-
 	}
 	return;
 
@@ -2239,11 +2230,56 @@
 	return 0;
 }
 
+/**
+ * msm_ipc_router_send_resume_tx() - Send Resume_Tx message
+ * @data: Pointer to received data packet that has confirm_rx bit set
+ *
+ * @return: On success, number of bytes transferred is returned, else
+ *	    standard linux error code is returned.
+ *
+ * This function sends the Resume_Tx event to the remote node that
+ * sent the data with confirm_rx field set. In case of a multi-hop
+ * scenario also, this function makes sure that the destination node_id
+ * to which the resume_tx event should reach is right.
+ */
+static int msm_ipc_router_send_resume_tx(void *data)
+{
+	union rr_control_msg msg;
+	struct rr_header *hdr = (struct rr_header *)data;
+	struct msm_ipc_routing_table_entry *rt_entry;
+	int ret;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
+	msg.cli.node_id = hdr->dst_node_id;
+	msg.cli.port_id = hdr->dst_port_id;
+	down_read(&routing_table_lock_lha3);
+	rt_entry = lookup_routing_table(hdr->src_node_id);
+	if (!rt_entry) {
+		pr_err("%s: %d Node is not present",
+				__func__, hdr->src_node_id);
+		up_read(&routing_table_lock_lha3);
+		return -ENODEV;
+	}
+	RR("x RESUME_TX id=%d:%08x\n",
+			msg.cli.node_id, msg.cli.port_id);
+	ret = msm_ipc_router_send_control_msg(rt_entry->xprt_info, &msg,
+						hdr->src_node_id);
+	up_read(&routing_table_lock_lha3);
+	if (ret < 0)
+		pr_err("%s: Send Resume_Tx Failed SRC_NODE: %d SRC_PORT: %d DEST_NODE: %d",
+			__func__, hdr->dst_node_id, hdr->dst_port_id,
+			hdr->src_node_id);
+
+	return ret;
+}
+
 int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
 			struct sk_buff_head **data,
 			size_t buf_len)
 {
 	struct rr_packet *pkt;
+	struct sk_buff *head_skb;
 	int ret;
 
 	if (!port_ptr || !data)
@@ -2265,8 +2301,15 @@
 		wake_unlock(&port_ptr->port_rx_wake_lock);
 	*data = pkt->pkt_fragment_q;
 	ret = pkt->length;
-	kfree(pkt);
 	mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
+	kfree(pkt);
+	head_skb = skb_peek(*data);
+	if (!head_skb) {
+		pr_err("%s: Socket Buffer not found", __func__);
+		return -EFAULT;
+	}
+	if (((struct rr_header *)(head_skb->data))->confirm_rx)
+		msm_ipc_router_send_resume_tx((void *)(head_skb->data));
 
 	return ret;
 }
diff --git a/drivers/coresight/coresight-csr.c b/drivers/coresight/coresight-csr.c
index 6efab5b..16338a9 100644
--- a/drivers/coresight/coresight-csr.c
+++ b/drivers/coresight/coresight-csr.c
@@ -136,7 +136,7 @@
 }
 EXPORT_SYMBOL(msm_qdss_csr_disable_flush);
 
-int coresight_csr_hwctrl_set(phys_addr_t addr, uint32_t val)
+int coresight_csr_hwctrl_set(uint64_t addr, uint32_t val)
 {
 	struct csr_drvdata *drvdata = csrdrvdata;
 	int ret = 0;
diff --git a/drivers/coresight/coresight-cti.c b/drivers/coresight/coresight-cti.c
index d139583..2a06f0a 100644
--- a/drivers/coresight/coresight-cti.c
+++ b/drivers/coresight/coresight-cti.c
@@ -387,11 +387,77 @@
 }
 static DEVICE_ATTR(unmap_trigout, S_IWUSR, NULL, cti_store_unmap_trigout);
 
+static ssize_t cti_show_trigin(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long trig, ch;
+	uint32_t ctien;
+	ssize_t size = 0;
+
+	for (trig = 0; trig < CTI_MAX_TRIGGERS; trig++) {
+		ctien = cti_readl(drvdata, CTIINEN(trig));
+		for (ch = 0; ch < CTI_MAX_CHANNELS; ch++) {
+			if (ctien & (1 << ch)) {
+				/* Ensure we do not write more than PAGE_SIZE
+				 * bytes of data including \n character and null
+				 * terminator
+				 */
+				size += scnprintf(&buf[size], PAGE_SIZE - size -
+						  1, " %#lx %#lx,", trig, ch);
+				if (size >= PAGE_SIZE - 2) {
+					dev_err(dev, "show buffer full\n");
+					goto err;
+				}
+
+			}
+		}
+	}
+err:
+	size += scnprintf(&buf[size], 2, "\n");
+	return size;
+}
+static DEVICE_ATTR(show_trigin, S_IRUGO, cti_show_trigin, NULL);
+
+static ssize_t cti_show_trigout(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long trig, ch;
+	uint32_t ctien;
+	ssize_t size = 0;
+
+	for (trig = 0; trig < CTI_MAX_TRIGGERS; trig++) {
+		ctien = cti_readl(drvdata, CTIOUTEN(trig));
+		for (ch = 0; ch < CTI_MAX_CHANNELS; ch++) {
+			if (ctien & (1 << ch)) {
+				/* Ensure we do not write more than PAGE_SIZE
+				 * bytes of data including \n character and null
+				 * terminator
+				 */
+				size += scnprintf(&buf[size], PAGE_SIZE - size -
+						  1, " %#lx %#lx,", trig, ch);
+				if (size >= PAGE_SIZE - 2) {
+					dev_err(dev, "show buffer full\n");
+					goto err;
+				}
+
+			}
+		}
+	}
+err:
+	size += scnprintf(&buf[size], 2, "\n");
+	return size;
+}
+static DEVICE_ATTR(show_trigout, S_IRUGO, cti_show_trigout, NULL);
+
 static struct attribute *cti_attrs[] = {
 	&dev_attr_map_trigin.attr,
 	&dev_attr_map_trigout.attr,
 	&dev_attr_unmap_trigin.attr,
 	&dev_attr_unmap_trigout.attr,
+	&dev_attr_show_trigin.attr,
+	&dev_attr_show_trigout.attr,
 	NULL,
 };
 
diff --git a/drivers/coresight/coresight-hwevent.c b/drivers/coresight/coresight-hwevent.c
index 269d56e..4f75bcd 100644
--- a/drivers/coresight/coresight-hwevent.c
+++ b/drivers/coresight/coresight-hwevent.c
@@ -130,11 +130,11 @@
 {
 	struct hwevent_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	void *hwereg;
-	phys_addr_t addr;
-	uint32_t val;
+	unsigned long long addr;
+	unsigned long val;
 	int ret, i;
 
-	if (sscanf(buf, "%x %x", &addr, &val) != 2)
+	if (sscanf(buf, "%llx %lx", &addr, &val) != 2)
 		return -EINVAL;
 
 	mutex_lock(&drvdata->mutex);
@@ -153,7 +153,7 @@
 					      drvdata->hmux[i].end -
 					      drvdata->hmux[i].start);
 			if (!hwereg) {
-				dev_err(dev, "unable to map address 0x%x\n",
+				dev_err(dev, "unable to map address 0x%llx\n",
 					addr);
 				ret = -ENOMEM;
 				goto err;
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
index 3ad1f34..fae1232 100644
--- a/drivers/coresight/coresight-priv.h
+++ b/drivers/coresight/coresight-priv.h
@@ -47,13 +47,13 @@
 extern void msm_qdss_csr_enable_bam_to_usb(void);
 extern void msm_qdss_csr_disable_bam_to_usb(void);
 extern void msm_qdss_csr_disable_flush(void);
-extern int coresight_csr_hwctrl_set(phys_addr_t addr, uint32_t val);
+extern int coresight_csr_hwctrl_set(uint64_t addr, uint32_t val);
 extern void coresight_csr_set_byte_cntr(uint32_t);
 #else
 static inline void msm_qdss_csr_enable_bam_to_usb(void) {}
 static inline void msm_qdss_csr_disable_bam_to_usb(void) {}
 static inline void msm_qdss_csr_disable_flush(void) {}
-static inline int coresight_csr_hwctrl_set(phys_addr_t addr,
+static inline int coresight_csr_hwctrl_set(uint64_t addr,
 					   uint32_t val) { return -ENOSYS; }
 static inline void coresight_csr_set_byte_cntr(uint32_t val) {}
 #endif
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index a052bd3..aaa2fc8 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -692,4 +692,16 @@
 	default "0"
 	help
 	  this provide the sensor position setting , value is between 0~7
+
+config SENSORS_STK3X1X
+	tristate "STK3X1X device driver"
+	depends on I2C
+	default n
+	help
+	  Say Y here you want to enable for the sitronix stk3x1x
+	  light and proximity sensors driver.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called stk3x1x.
+
 endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 4f29e05..445fba0 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -64,3 +64,4 @@
 obj-$(CONFIG_BMP18X)			+= bmp18x-core.o
 obj-$(CONFIG_BMP18X_I2C)		+= bmp18x-i2c.o
 obj-$(CONFIG_SENSORS_MMA8X5X)	  	+= mma8x5x.o
+obj-$(CONFIG_SENSORS_STK3X1X)		+= stk3x1x.o
diff --git a/drivers/input/misc/stk3x1x.c b/drivers/input/misc/stk3x1x.c
index 6e6b9ea..61f3530 100644
--- a/drivers/input/misc/stk3x1x.c
+++ b/drivers/input/misc/stk3x1x.c
@@ -43,6 +43,10 @@
 #include <linux/gpio.h>
 #include <linux/fs.h>
 #include <linux/uaccess.h>
+#include <linux/regulator/consumer.h>
+#ifdef CONFIG_OF
+#include <linux/of_gpio.h>
+#endif
 #ifdef CONFIG_HAS_EARLYSUSPEND
 #include <linux/earlysuspend.h>
 #endif
@@ -169,6 +173,12 @@
 #define ALS_NAME "lightsensor-level"
 #define PS_NAME "proximity"
 
+/* POWER SUPPLY VOLTAGE RANGE */
+#define STK3X1X_VDD_MIN_UV	2000000
+#define STK3X1X_VDD_MAX_UV	3300000
+#define STK3X1X_VIO_MIN_UV	1750000
+#define STK3X1X_VIO_MAX_UV	1950000
+
 struct stk3x1x_data {
 	struct i2c_client *client;
 #if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS))
@@ -205,6 +215,9 @@
     struct work_struct stk_als_work;
 	struct workqueue_struct *stk_als_wq;
 #endif
+	struct regulator *vdd;
+	struct regulator *vio;
+	bool power_enabled;
 };
 
 #if( !defined(CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD))
@@ -1412,15 +1425,14 @@
 	return size;
 }
 
-
 static struct device_attribute als_enable_attribute = __ATTR(enable,0664,stk_als_enable_show,stk_als_enable_store);
 static struct device_attribute als_lux_attribute = __ATTR(lux,0664,stk_als_lux_show,stk_als_lux_store);
 static struct device_attribute als_code_attribute = __ATTR(code, 0444, stk_als_code_show, NULL);
 static struct device_attribute als_transmittance_attribute = __ATTR(transmittance,0664,stk_als_transmittance_show,stk_als_transmittance_store);
-static struct device_attribute als_poll_delay_attribute = __ATTR(delay,0664,stk_als_delay_show,stk_als_delay_store);
+static struct device_attribute als_poll_delay_attribute =
+	__ATTR(poll_delay, 0664, stk_als_delay_show, stk_als_delay_store);
 static struct device_attribute als_ir_code_attribute = __ATTR(ircode,0444,stk_als_ir_code_show,NULL);
 
-
 static struct attribute *stk_als_attrs [] =
 {
 	&als_enable_attribute.attr,
@@ -1433,7 +1445,6 @@
 };
 
 static struct attribute_group stk_als_attribute_group = {
-	.name = "driver",
 	.attrs = stk_als_attrs,
 };
 
@@ -1465,7 +1476,6 @@
 };
 
 static struct attribute_group stk_ps_attribute_group = {
-	.name = "driver",
 	.attrs = stk_ps_attrs,
 };
 
@@ -1793,6 +1803,205 @@
 }
 #endif	//#ifdef CONFIG_HAS_EARLYSUSPEND
 
+static int stk3x1x_power_on(struct stk3x1x_data *data, bool on)
+{
+	int ret = 0;
+
+	if (!on && data->power_enabled) {
+		ret = regulator_disable(data->vdd);
+		if (ret) {
+			dev_err(&data->client->dev,
+				"Regulator vdd disable failed ret=%d\n", ret);
+			return ret;
+		}
+
+		ret = regulator_disable(data->vio);
+		if (ret) {
+			dev_err(&data->client->dev,
+				"Regulator vio disable failed ret=%d\n", ret);
+			regulator_enable(data->vdd);
+		}
+	} else if (on && !data->power_enabled) {
+
+		ret = regulator_enable(data->vdd);
+		if (ret) {
+			dev_err(&data->client->dev,
+				"Regulator vdd enable failed ret=%d\n", ret);
+			return ret;
+		}
+
+		ret = regulator_enable(data->vio);
+		if (ret) {
+			dev_err(&data->client->dev,
+				"Regulator vio enable failed ret=%d\n", ret);
+			regulator_disable(data->vdd);
+		}
+	} else {
+		dev_warn(&data->client->dev,
+				"Power on=%d. enabled=%d\n",
+				on, data->power_enabled);
+	}
+
+	return ret;
+}
+
+static int stk3x1x_power_init(struct stk3x1x_data *data, bool on)
+{
+	int ret;
+
+	if (!on) {
+		if (regulator_count_voltages(data->vdd) > 0)
+			regulator_set_voltage(data->vdd,
+					0, STK3X1X_VDD_MAX_UV);
+
+		regulator_put(data->vdd);
+
+		if (regulator_count_voltages(data->vio) > 0)
+			regulator_set_voltage(data->vio,
+					0, STK3X1X_VIO_MAX_UV);
+
+		regulator_put(data->vio);
+	} else {
+		data->vdd = regulator_get(&data->client->dev, "vdd");
+		if (IS_ERR(data->vdd)) {
+			ret = PTR_ERR(data->vdd);
+			dev_err(&data->client->dev,
+				"Regulator get failed vdd ret=%d\n", ret);
+			return ret;
+		}
+
+		if (regulator_count_voltages(data->vdd) > 0) {
+			ret = regulator_set_voltage(data->vdd,
+					STK3X1X_VDD_MIN_UV,
+					STK3X1X_VDD_MAX_UV);
+			if (ret) {
+				dev_err(&data->client->dev,
+					"Regulator set failed vdd ret=%d\n",
+					ret);
+				goto reg_vdd_put;
+			}
+		}
+
+		data->vio = regulator_get(&data->client->dev, "vio");
+		if (IS_ERR(data->vio)) {
+			ret = PTR_ERR(data->vio);
+			dev_err(&data->client->dev,
+				"Regulator get failed vio ret=%d\n", ret);
+			goto reg_vdd_set;
+		}
+
+		if (regulator_count_voltages(data->vio) > 0) {
+			ret = regulator_set_voltage(data->vio,
+					STK3X1X_VIO_MIN_UV,
+					STK3X1X_VIO_MAX_UV);
+			if (ret) {
+				dev_err(&data->client->dev,
+				"Regulator set failed vio ret=%d\n", ret);
+				goto reg_vio_put;
+			}
+		}
+	}
+
+	return 0;
+
+reg_vio_put:
+	regulator_put(data->vio);
+reg_vdd_set:
+	if (regulator_count_voltages(data->vdd) > 0)
+		regulator_set_voltage(data->vdd, 0, STK3X1X_VDD_MAX_UV);
+reg_vdd_put:
+	regulator_put(data->vdd);
+	return ret;
+}
+
+#ifdef CONFIG_OF
+static int stk3x1x_parse_dt(struct device *dev,
+			struct stk3x1x_platform_data *pdata)
+{
+	int rc;
+	struct device_node *np = dev->of_node;
+	u32 temp_val;
+
+	pdata->int_pin = of_get_named_gpio_flags(np, "stk,irq-gpio",
+				0, &pdata->int_flags);
+	if (pdata->int_pin < 0) {
+		dev_err(dev, "Unable to read irq-gpio\n");
+		return pdata->int_pin;
+	}
+
+	rc = of_property_read_u32(np, "stk,transmittance", &temp_val);
+	if (!rc)
+		pdata->transmittance = temp_val;
+	else {
+		dev_err(dev, "Unable to read transmittance\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(np, "stk,state-reg", &temp_val);
+	if (!rc)
+		pdata->state_reg = temp_val;
+	else {
+		dev_err(dev, "Unable to read state-reg\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(np, "stk,psctrl-reg", &temp_val);
+	if (!rc)
+		pdata->psctrl_reg = (u8)temp_val;
+	else {
+		dev_err(dev, "Unable to read psctrl-reg\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(np, "stk,alsctrl-reg", &temp_val);
+	if (!rc)
+		pdata->alsctrl_reg = (u8)temp_val;
+	else {
+		dev_err(dev, "Unable to read alsctrl-reg\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(np, "stk,ledctrl-reg", &temp_val);
+	if (!rc)
+		pdata->ledctrl_reg = (u8)temp_val;
+	else {
+		dev_err(dev, "Unable to read ledctrl-reg\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(np, "stk,wait-reg", &temp_val);
+	if (!rc)
+		pdata->wait_reg = (u8)temp_val;
+	else {
+		dev_err(dev, "Unable to read wait-reg\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(np, "stk,ps-thdh", &temp_val);
+	if (!rc)
+		pdata->ps_thd_h = (u16)temp_val;
+	else {
+		dev_err(dev, "Unable to read ps-thdh\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(np, "stk,ps-thdl", &temp_val);
+	if (!rc)
+		pdata->ps_thd_l = (u16)temp_val;
+	else {
+		dev_err(dev, "Unable to read ps-thdl\n");
+		return rc;
+	}
+
+	return 0;
+}
+#else
+static int stk3x1x_parse_dt(struct device *dev,
+			struct stk3x1x_platform_data *pdata)
+{
+	return -ENODEV;
+}
+#endif /* !CONFIG_OF */
 
 static int stk3x1x_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
@@ -1827,20 +2036,33 @@
 #ifdef STK_POLL_PS
 	wake_lock_init(&ps_data->ps_nosuspend_wl,WAKE_LOCK_SUSPEND, "stk_nosuspend_wakelock");
 #endif
-	if(client->dev.platform_data != NULL)
-	{
-		plat_data = client->dev.platform_data;
-		ps_data->als_transmittance = plat_data->transmittance;
-		ps_data->int_pin = plat_data->int_pin;
-		if(ps_data->als_transmittance == 0)
-		{
-			printk(KERN_ERR "%s: Please set als_transmittance in platform data\n", __func__);
-			goto err_als_input_allocate;
+	if (client->dev.of_node) {
+		plat_data = devm_kzalloc(&client->dev,
+			sizeof(struct stk3x1x_platform_data), GFP_KERNEL);
+		if (!plat_data) {
+			dev_err(&client->dev, "Failed to allocate memory\n");
+			return -ENOMEM;
 		}
+
+		err = stk3x1x_parse_dt(&client->dev, plat_data);
+		dev_err(&client->dev,
+			"%s: stk3x1x_parse_dt ret=%d\n", __func__, err);
+		if (err)
+			return err;
+	} else
+		plat_data = client->dev.platform_data;
+
+	if (!plat_data) {
+		dev_err(&client->dev,
+			"%s: no stk3x1x platform data!\n", __func__);
+		goto err_als_input_allocate;
 	}
-	else
-	{
-		printk(KERN_ERR "%s: no stk3x1x platform data!\n", __func__);
+	ps_data->als_transmittance = plat_data->transmittance;
+	ps_data->int_pin = plat_data->int_pin;
+
+	if (ps_data->als_transmittance == 0) {
+		dev_err(&client->dev,
+			"%s: Please set als_transmittance\n", __func__);
 		goto err_als_input_allocate;
 	}
 
@@ -1913,6 +2135,14 @@
 		goto err_stk3x1x_setup_irq;
 #endif
 
+	err = stk3x1x_power_init(ps_data, true);
+	if (err)
+		goto err_power_init;
+
+	err = stk3x1x_power_on(ps_data, true);
+	if (err)
+		goto err_power_on;
+
 	err = stk3x1x_init_all_setting(client, plat_data);
 	if(err < 0)
 		goto err_init_all_setting;
@@ -1926,6 +2156,10 @@
 	return 0;
 
 err_init_all_setting:
+	stk3x1x_power_on(ps_data, false);
+err_power_on:
+	stk3x1x_power_init(ps_data, false);
+err_power_init:
 #ifndef STK_POLL_PS
 	free_irq(ps_data->irq, ps_data);
 	gpio_free(plat_data->int_pin);
@@ -2001,11 +2235,17 @@
 };
 MODULE_DEVICE_TABLE(i2c, stk_ps_id);
 
+static struct of_device_id stk_match_table[] = {
+	{ .compatible = "stk,stk3x1x", },
+	{ },
+};
+
 static struct i2c_driver stk_ps_driver =
 {
     .driver = {
         .name = DEVICE_NAME,
 		.owner = THIS_MODULE,
+		.of_match_table = stk_match_table,
     },
     .probe = stk3x1x_probe,
     .remove = stk3x1x_remove,
diff --git a/drivers/input/touchscreen/gt9xx/goodix_tool.c b/drivers/input/touchscreen/gt9xx/goodix_tool.c
new file mode 100644
index 0000000..3dfe4e1
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/goodix_tool.c
@@ -0,0 +1,615 @@
+/* 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;

+}

diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.c b/drivers/input/touchscreen/gt9xx/gt9xx.c
new file mode 100644
index 0000000..b1dc08b
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.c
@@ -0,0 +1,1810 @@
+/* drivers/input/touchscreen/gt9xx.c
+ * 
+ * 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 
+ * 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.2:
+ *          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: 
+ *          1. new heartbeat/esd_protect mechanism(add external watchdog)
+ *          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 
+ *          2. read double check & fixed config support
+ *          2. new esd & slide wakeup optimization
+ *                  By Meta, 2013/06/08
+ */
+
+#include <linux/irq.h>
+#include "gt9xx.h"
+
+#if GTP_ICS_SLOT_REPORT
+    #include <linux/input/mt.h>
+#endif
+
+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};
+
+#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]))
+    
+#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"};
+#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);
+
+#ifdef 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);
+#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;
+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;
+
+/*******************************************************
+Function:
+    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
+Output:
+    numbers of i2c_msgs to transfer: 
+      2: succeed, otherwise: failed
+*********************************************************/
+s32 gtp_i2c_read(struct i2c_client *client, u8 *buf, s32 len)
+{
+    struct i2c_msg msgs[2];
+    s32 ret=-1;
+    s32 retries = 0;
+
+    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;
+
+    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;
+}
+
+/*******************************************************
+Function:
+    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
+Output:
+    numbers of i2c_msgs to transfer: 
+        1: succeed, otherwise: failed
+*********************************************************/
+s32 gtp_i2c_write(struct i2c_client *client,u8 *buf,s32 len)
+{
+    struct i2c_msg msg;
+    s32 ret = -1;
+    s32 retries = 0;
+
+    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
+
+    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;
+}
+/*******************************************************
+Function:
+    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
+Output:
+    FAIL:    read failed
+    SUCCESS: read successful
+*********************************************************/
+s32 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;
+    }
+}
+
+/*******************************************************
+Function:
+    Send config.
+Input:
+    client: i2c device.
+Output:
+    result of i2c write operation. 
+        1: succeed, otherwise: failed
+*********************************************************/
+s32 gtp_send_cfg(struct i2c_client *client)
+{
+    s32 ret = 2;
+    
+#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;
+        }
+    }
+#endif
+
+    return ret;
+}
+
+/*******************************************************
+Function:
+    Disable irq function
+Input:
+    ts: goodix i2c_client private data
+Output:
+    None.
+*********************************************************/
+void gtp_irq_disable(struct goodix_ts_data *ts)
+{
+    unsigned long irqflags;
+
+    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);
+}
+
+/*******************************************************
+Function:
+    Enable irq function
+Input:
+    ts: goodix i2c_client private data
+Output:
+    None.
+*********************************************************/
+void gtp_irq_enable(struct goodix_ts_data *ts)
+{
+    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);
+}
+
+
+/*******************************************************
+Function:
+    Report touch point event 
+Input:
+    ts: goodix i2c_client private data
+    id: trackId
+    x:  input x coordinate
+    y:  input y coordinate
+    w:  input pressure
+Output:
+    None.
+*********************************************************/
+static void gtp_touch_down(struct goodix_ts_data* ts,s32 id,s32 x,s32 y,s32 w)
+{
+#if GTP_CHANGE_X2Y
+    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
+
+    GTP_DEBUG("ID:%d, X:%d, Y:%d, W:%d", id, x, y, w);
+}
+
+/*******************************************************
+Function:
+    Report touch release event
+Input:
+    ts: goodix i2c_client private data
+Output:
+    None.
+*********************************************************/
+static void gtp_touch_up(struct goodix_ts_data* ts, s32 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
+}
+
+
+/*******************************************************
+Function:
+    Goodix touchscreen work function
+Input:
+    work: work struct of goodix_workqueue
+Output:
+    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;
+#if GTP_WITH_PEN
+    static u8 pre_pen = 0;
+#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;
+
+#if GTP_SLIDE_WAKEUP
+    u8 doze_buf[3] = {0x81, 0x4B};
+#endif
+
+    GTP_DEBUG_FUNC();
+    ts = container_of(work, struct goodix_ts_data, work);
+    if (ts->enter_update)
+    {
+        return;
+    }
+#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;
+    }
+#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;
+    }
+
+    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;
+    }
+
+    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));
+    }
+
+#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;
+    }
+#endif
+    pre_key = key_value;
+
+    GTP_DEBUG("pre_touch:%02x, finger:%02x.", pre_touch, finger);
+
+#if GTP_ICS_SLOT_REPORT
+
+#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;
+    }
+#endif
+    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);
+
+                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;
+#endif
+
+    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);
+    }
+}
+
+/*******************************************************
+Function:
+    Timer interrupt service routine for polling mode.
+Input:
+    timer: timer struct pointer
+Output:
+    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);
+
+    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;
+}
+
+/*******************************************************
+Function:
+    External interrupt service routine for interrupt mode.
+Input:
+    irq:  interrupt number.
+    dev_id: private data pointer
+Output:
+    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;
+
+    GTP_DEBUG_FUNC();
+ 
+    gtp_irq_disable(ts);
+
+    queue_work(goodix_wq, &ts->work);
+    
+    return IRQ_HANDLED;
+}
+/*******************************************************
+Function:
+    Synchronization.
+Input:
+    ms: synchronization time in millisecond.
+Output:
+    None.
+*******************************************************/
+void gtp_int_sync(s32 ms)
+{
+    GTP_GPIO_OUTPUT(GTP_INT_PORT, 0);
+    msleep(ms);
+    GTP_GPIO_AS_INT(GTP_INT_PORT);
+}
+
+/*******************************************************
+Function:
+    Reset chip.
+Input:
+    ms: reset time in millisecond
+Output:
+    None.
+*******************************************************/
+void gtp_reset_guitar(struct i2c_client *client, s32 ms)
+{
+    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);
+
+    msleep(2);                          // T3: > 100us
+    GTP_GPIO_OUTPUT(GTP_RST_PORT, 1);
+    
+    msleep(6);                          // T4: > 5ms
+
+    GTP_GPIO_AS_INPUT(GTP_RST_PORT);    // end select I2C slave addr
+
+    gtp_int_sync(50);                  
+    
+#if GTP_ESD_PROTECT
+    gtp_init_ext_watchdog(client);
+#endif
+}
+
+#if GTP_SLIDE_WAKEUP
+/*******************************************************
+Function:
+    Enter doze mode for sliding wakeup.
+Input:
+    ts: goodix tp private data
+Output:
+    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};
+
+    GTP_DEBUG_FUNC();
+
+#if GTP_DBL_CLK_WAKEUP
+    i2c_control_buf[2] = 0x09;
+#endif
+
+    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;
+}
+#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
+
+    GTP_ERROR("GTP wakeup sleep failed.");
+    return ret;
+}
+
+/*******************************************************
+Function:
+    Initialize gtp.
+Input:
+    ts: goodix private data
+Output:
+    Executive outcomes.
+        0: succeed, otherwise: failed
+*******************************************************/
+static s32 gtp_init_panel(struct goodix_ts_data *ts)
+{
+    s32 ret = -1;
+
+#if GTP_DRIVER_SEND_CFG
+    s32 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)};
+
+    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]);
+
+    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;
+        }
+    }
+
+    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);
+
+#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
+
+    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);
+
+    msleep(10);
+    return 0;
+}
+
+/*******************************************************
+Function:
+    Read chip version.
+Input:
+    client:  i2c device
+    version: buffer to keep ic firmware version
+Output:
+    read operation return.
+        2: succeed, otherwise: failed
+*******************************************************/
+s32 gtp_read_version(struct i2c_client *client, u16* version)
+{
+    s32 ret = -1;
+    u8 buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff};
+
+    GTP_DEBUG_FUNC();
+
+    ret = gtp_i2c_read(client, buf, sizeof(buf));
+    if (ret < 0)
+    {
+        GTP_ERROR("GTP read version failed");
+        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;
+}
+
+/*******************************************************
+Function:
+    I2c test Function.
+Input:
+    client:i2c client.
+Output:
+    Executive outcomes.
+        2: succeed, otherwise failed.
+*******************************************************/
+static s8 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;
+}
+
+/*******************************************************
+Function:
+    Request gpio(INT & RST) ports.
+Input:
+    ts: private data.
+Output:
+    Executive outcomes.
+        >= 0: succeed, < 0: failed
+*******************************************************/
+static s8 gtp_request_io_port(struct goodix_ts_data *ts)
+{
+    s32 ret = 0;
+
+    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;
+    }
+
+    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;
+    }
+
+    GTP_GPIO_AS_INPUT(GTP_RST_PORT);
+    gtp_reset_guitar(ts->client, 20);
+
+    
+    if(ret < 0)
+    {
+        GTP_GPIO_FREE(GTP_RST_PORT);
+        GTP_GPIO_FREE(GTP_INT_PORT);
+    }
+
+    return ret;
+}
+
+/*******************************************************
+Function:
+    Request interrupt.
+Input:
+    ts: private data.
+Output:
+    Executive outcomes.
+        0: succeed, -1: failed.
+*******************************************************/
+static s8 gtp_request_irq(struct goodix_ts_data *ts)
+{
+    s32 ret = -1;
+    const u8 irq_table[] = GTP_IRQ_TAB;
+
+    GTP_DEBUG("INT trigger type:%x", ts->int_trigger_type);
+
+    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);
+
+        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;
+    }
+}
+
+/*******************************************************
+Function:
+    Request input device Function.
+Input:
+    ts:private data.
+Output:
+    Executive outcomes.
+        0: succeed, otherwise: failed.
+*******************************************************/
+static s8 gtp_request_input_dev(struct goodix_ts_data *ts)
+{
+    s8 ret = -1;
+    s8 phys[32];
+#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);
+#endif
+
+#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]);  
+    }
+#endif
+
+#if GTP_SLIDE_WAKEUP
+    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);
+#endif
+
+#if GTP_CHANGE_X2Y
+    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);
+
+    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
+
+    return 0;
+}
+
+/*******************************************************
+Function:
+    I2c probe.
+Input:
+    client: i2c device struct.
+    id: device id.
+Output:
+    Executive outcomes. 
+        0: succeed.
+*******************************************************/
+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;
+
+    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);
+
+    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 = gtp_request_io_port(ts);
+    if (ret < 0)
+    {
+        GTP_ERROR("GTP request IO port failed.");
+        kfree(ts);
+        return ret;
+    }
+
+    ret = gtp_i2c_test(client);
+    if (ret < 0)
+    {
+        GTP_ERROR("I2C communication ERROR!");
+    }
+
+#if GTP_AUTO_UPDATE
+    ret = gup_init_update_proc(ts);
+    if (ret < 0)
+    {
+        GTP_ERROR("Create update thread error.");
+    }
+#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_read_version(client, &version_info);
+    if (ret < 0)
+    {
+        GTP_ERROR("Read version failed.");
+    }
+    if (ts->use_irq)
+    {
+        gtp_irq_enable(ts);
+    }
+    
+#if GTP_CREATE_WR_NODE
+    init_wr_node(client);
+#endif
+    
+#if GTP_ESD_PROTECT
+    gtp_esd_switch(client, SWITCH_ON);
+#endif
+    return 0;
+}
+
+
+/*******************************************************
+Function:
+    Goodix touchscreen driver release function.
+Input:
+    client: i2c device struct.
+Output:
+    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);
+#endif
+
+#if GTP_CREATE_WR_NODE
+    uninit_wr_node();
+#endif
+
+#if GTP_ESD_PROTECT
+    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);
+
+    return 0;
+}
+
+#ifdef 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();
+
+#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);   
+}
+
+/*******************************************************
+Function:
+    Late resume function.
+Input:
+    h: early_suspend struct.
+Output:
+    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);
+
+#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
+}
+#endif
+
+#if GTP_ESD_PROTECT
+/*******************************************************
+Function:
+    switch on & off esd delayed work
+Input:
+    client:  i2c device
+    on:      SWITCH_ON / SWITCH_OFF
+Output:
+    void
+*********************************************************/
+void gtp_esd_switch(struct i2c_client *client, s32 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);
+        }
+    }
+}
+
+/*******************************************************
+Function:
+    Initialize external watchdog for esd protect
+Input:
+    client:  i2c device.
+Output:
+    result of i2c write operation. 
+        1: succeed, otherwise: failed
+*********************************************************/
+static s32 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;
+
+    GTP_DEBUG("Init external watchdog...");
+    GTP_DEBUG_FUNC();
+
+    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;
+}
+
+/*******************************************************
+Function:
+    Esd protect function.
+    Added external watchdog by meta, 2013/03/07
+Input:
+    work: delayed work
+Output:
+    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);
+
+    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);
+    }
+
+    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;
+}
+#endif
+
+static const struct i2c_device_id goodix_ts_id[] = {
+    { GTP_I2C_NAME, 0 },
+    { }
+};
+
+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,
+#endif
+    .id_table   = goodix_ts_id,
+    .driver = {
+        .name     = GTP_I2C_NAME,
+        .owner    = THIS_MODULE,
+    },
+};
+
+/*******************************************************    
+Function:
+    Driver Install function.
+Input:
+    None.
+Output:
+    Executive Outcomes. 0---succeed.
+********************************************************/
+static int __devinit goodix_ts_init(void)
+{
+    s32 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;
+    }
+#if GTP_ESD_PROTECT
+    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; 
+}
+
+/*******************************************************    
+Function:
+    Driver uninstall function.
+Input:
+    None.
+Output:
+    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);
+    }
+}
+
+late_initcall(goodix_ts_init);
+module_exit(goodix_ts_exit);
+
+MODULE_DESCRIPTION("GTP Series Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.h b/drivers/input/touchscreen/gt9xx/gt9xx.h
new file mode 100644
index 0000000..e375af5
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.h
@@ -0,0 +1,241 @@
+/* drivers/input/touchscreen/gt9xx.h
+ * 
+ * 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 
+ * 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/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/interrupt.h>
+#include <linux/io.h>
+#include <mach/gpio.h>
+#include <linux/earlysuspend.h>
+
+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;
+};
+
+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
+
+#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
+
+#define GTP_SLIDE_WAKEUP      0
+#define GTP_DBL_CLK_WAKEUP    0     // double-click wakeup, function together with GTP_SLIDE_WAKEUP
+
+#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 
+*/
+// 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 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
+#define CTP_CFG_GROUP2 {\
+    }
+// TODO: 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 CTP_CFG_GROUP4 {\
+    }
+
+// TODO: 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 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_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
+#if GTP_CUSTOM_CFG
+  #define GTP_MAX_HEIGHT   800
+  #define GTP_MAX_WIDTH    480
+  #define GTP_INT_TRIGGER  0            // 0: Rising 1: Falling
+#else
+  #define GTP_MAX_HEIGHT   4096
+  #define GTP_MAX_WIDTH    4096
+  #define GTP_INT_TRIGGER  1
+#endif
+#define GTP_MAX_TOUCH         5
+#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}
+#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********************************
+
+#endif /* _GOODIX_GT9XX_H_ */
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h b/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h
new file mode 100644
index 0000000..3998bf0
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h
@@ -0,0 +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
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx_update.c b/drivers/input/touchscreen/gt9xx/gt9xx_update.c
new file mode 100644
index 0000000..f564a6b
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/gt9xx_update.c
@@ -0,0 +1,1930 @@
+/* drivers/input/touchscreen/gt9xx_update.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.
+ * 
+ * Latest Version:1.6
+ * Author: andrew@goodix.com
+ * Revision Record: 
+ *      V1.0:
+ *          first release. By Andrew, 2012/08/31
+ *      V1.2:
+ *          add force update,GT9110P pid map. By Andrew, 2012/10/15
+ *      V1.4:
+ *          1. add config auto update function;
+ *          2. modify enter_update_mode;
+ *          3. add update file cal checksum.
+ *                          By Andrew, 2012/12/12
+ *      V1.6: 
+ *          1. replace guitar_client with i2c_connect_client;
+ *          2. support firmware header array update.
+ *                          By Meta, 2013/03/11
+ */
+#include <linux/kthread.h>
+#include "gt9xx.h"
+
+#if GTP_HEADER_FW_UPDATE
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include "gt9xx_firmware.h"
+#endif
+
+#define GUP_REG_HW_INFO             0x4220
+#define GUP_REG_FW_MSG              0x41E4
+#define GUP_REG_PID_VID             0x8140
+
+#define GUP_SEARCH_FILE_TIMES       50
+#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 FW_HEAD_LENGTH               14
+#define FW_SECTION_LENGTH            0x2000
+#define FW_DSP_ISP_LENGTH            0x1000
+#define FW_DSP_LENGTH                0x1000
+#define FW_BOOT_LENGTH               0x800
+
+#define PACK_SIZE                    256
+#define MAX_FRAME_CHECK_TIME         5
+
+#define _bRW_MISCTL__SRAM_BANK       0x4048
+#define _bRW_MISCTL__MEM_CD_EN       0x4049
+#define _bRW_MISCTL__CACHE_EN        0x404B
+#define _bRW_MISCTL__TMR0_EN         0x40B0
+#define _rRW_MISCTL__SWRST_B0_       0x4180
+#define _bWO_MISCTL__CPU_SWRST_PULSE 0x4184
+#define _rRW_MISCTL__BOOTCTL_B0_     0x4190
+#define _rRW_MISCTL__BOOT_OPT_B0_    0x4218
+#define _rRW_MISCTL__BOOT_CTL_       0x5094
+
+#define FAIL    0
+#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;
+#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;
+
+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
+/*******************************************************
+Function:
+    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
+Output:
+    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;
+
+    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;    
+
+    while(retries < 5)
+    {
+        ret = i2c_transfer(client->adapter, msgs, 2);
+        if(ret == 2)break;
+        retries++;
+    }
+
+    return ret;
+}
+
+/*******************************************************
+Function:
+    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
+Output:
+    numbers of i2c_msgs to transfer: 
+        1: succeed, otherwise: failed
+*********************************************************/
+s32 gup_i2c_write(struct i2c_client *client,u8 *buf,s32 len)
+{
+    struct i2c_msg msg;
+    s32 ret=-1;
+    s32 retries = 0;
+
+    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
+
+    while(retries < 5)
+    {
+        ret = i2c_transfer(client->adapter, &msg, 1);
+        if (ret == 1)break;
+        retries++;
+    }
+
+    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;
+
+    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);
+
+    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(10);
+    return 0;
+}
+
+
+static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8* msg, s32 len)
+{
+    s32 i = 0;
+
+    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;
+        }
+    }
+
+    if (i >= 5)
+    {
+        GTP_ERROR("Read data from 0x%02x%02x failed!", msg[0], msg[1]);
+        return FAIL;
+    }
+
+    return SUCCESS;
+}
+
+static u8 gup_set_ic_msg(struct i2c_client *client, u16 addr, u8 val)
+{
+    s32 i = 0;
+    u8 msg[3];
+
+    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;
+        }
+    }
+
+    if (i >= 5)
+    {
+        GTP_ERROR("Set data to 0x%02x%02x failed!", msg[0], msg[1]);
+        return FAIL;
+    }
+
+    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 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;
+}
+
+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);
+}
+
+// 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);
+
+    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);
+
+    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);
+
+    //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;
+
+    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.");
+    }
+    
+update_cfg_file_failed:
+    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);
+
+    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;
+    }
+
+    return SUCCESS;
+    
+    /*
+    if (path.mnt->mnt_sb == root_path.mnt->mnt_sb)
+    {
+        //-- not mounted
+        return FAIL;
+    }
+    else
+    {
+        return SUCCESS;
+    }*/
+
+}
+#endif
+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);
+
+        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);
+
+            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);
+#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;
+        }
+#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;
+
+    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;
+}
+
+#if 0
+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;
+
+    pos = HEADER_UPDATE_DATA;
+      
+    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)
+{
+    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)
+{
+    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)
+{
+    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;
+}
+
+static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section, u16 start_addr, u8 bank_cmd )
+{
+    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]);
+
+    //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;
+}
+
+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;
+
+exit_burn_dsp_isp:
+    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;
+    
+exit_burn_fw_ss51:
+    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;
+    
+exit_burn_fw_dsp:
+    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;
+    
+exit_burn_fw_boot:
+    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);
+#if GTP_ESD_PROTECT
+    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);
+    
+#if GTP_ESD_PROTECT
+    gtp_esd_switch(ts->client, SWITCH_ON);
+#endif
+    filp_close(update_msg.file, NULL);
+    return SUCCESS;
+    
+update_fail:
+    ts->enter_update = 0;
+    gtp_irq_enable(ts);
+    
+#if GTP_ESD_PROTECT
+    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 GTP_AUTO_UPDATE
+u8 gup_init_update_proc(struct goodix_ts_data *ts)
+{
+    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;
+    }
+
+    return 0;
+}
+#endif
\ No newline at end of file
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index b896f65..a1453ae 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -372,7 +372,9 @@
  *  @torch_enable - enable flash LED torch mode
  *  @flash_reg_get - flash regulator attached or not
  *  @flash_on - flash status, on or off
+ *  @torch_on - torch status, on or off
  *  @flash_boost_reg - boost regulator for flash
+ *  @torch_boost_reg - boost regulator for torch
  */
 struct flash_config_data {
 	u8	current_prgm;
@@ -389,7 +391,9 @@
 	bool	torch_enable;
 	bool	flash_reg_get;
 	bool	flash_on;
+	bool	torch_on;
 	struct regulator *flash_boost_reg;
+	struct regulator *torch_boost_reg;
 };
 
 /**
@@ -733,9 +737,40 @@
 	return 0;
 }
 
-static int qpnp_flash_set(struct qpnp_led_data *led)
+static int qpnp_torch_regulator_operate(struct qpnp_led_data *led, bool on)
 {
 	int rc;
+
+	if (!on)
+		goto regulator_turn_off;
+
+	if (!led->flash_cfg->torch_on) {
+		rc = regulator_enable(led->flash_cfg->torch_boost_reg);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Regulator enable failed(%d)\n", rc);
+				return rc;
+		}
+		led->flash_cfg->torch_on = true;
+	}
+	return 0;
+
+regulator_turn_off:
+	if (led->flash_cfg->torch_on) {
+		rc = regulator_disable(led->flash_cfg->torch_boost_reg);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Regulator disable failed(%d)\n", rc);
+			return rc;
+		}
+		led->flash_cfg->torch_on = false;
+	}
+	return 0;
+}
+
+static int qpnp_flash_set(struct qpnp_led_data *led)
+{
+	int rc, error;
 	int val = led->cdev.brightness;
 
 	if (led->flash_cfg->torch_enable)
@@ -753,13 +788,21 @@
 	/* 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,
+					"Torch regulator operate failed(%d)\n",
+					rc);
+				return rc;
+			}
+
 			rc = qpnp_led_masked_write(led,
 				FLASH_LED_UNLOCK_SECURE(led->base),
 				FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Secure reg write failed(%d)\n", rc);
-				return rc;
+				goto error_torch_set;
 			}
 
 			rc = qpnp_led_masked_write(led,
@@ -768,7 +811,7 @@
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Torch reg write failed(%d)\n", rc);
-				return rc;
+				goto error_torch_set;
 			}
 
 			rc = qpnp_led_masked_write(led,
@@ -778,7 +821,7 @@
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Current reg write failed(%d)\n", rc);
-				return rc;
+				goto error_torch_set;
 			}
 
 			rc = qpnp_led_masked_write(led,
@@ -789,7 +832,7 @@
 				dev_err(&led->spmi_dev->dev,
 					"2nd Current reg write failed(%d)\n",
 					rc);
-				return rc;
+				goto error_torch_set;
 			}
 
 			qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
@@ -799,16 +842,16 @@
 				dev_err(&led->spmi_dev->dev,
 					"Max current reg write failed(%d)\n",
 					rc);
-				return rc;
+				goto error_torch_set;
 			}
 
 			rc = qpnp_led_masked_write(led,
 				FLASH_ENABLE_CONTROL(led->base),
-				FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
+				FLASH_ENABLE_MASK, FLASH_ENABLE_MODULE);
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Enable reg write failed(%d)\n", rc);
-				return rc;
+				goto error_torch_set;
 			}
 		} else {
 			rc = qpnp_flash_regulator_operate(led, true);
@@ -816,7 +859,7 @@
 				dev_err(&led->spmi_dev->dev,
 					"Flash regulator operate failed(%d)\n",
 					rc);
-				return rc;
+				goto error_flash_set;
 			}
 
 			/* Set flash safety timer */
@@ -828,7 +871,7 @@
 				dev_err(&led->spmi_dev->dev,
 					"Safety timer reg write failed(%d)\n",
 					rc);
-				return rc;
+				goto error_flash_set;
 			}
 
 			/* Set max current */
@@ -839,7 +882,7 @@
 				dev_err(&led->spmi_dev->dev,
 					"Max current reg write failed(%d)\n",
 					rc);
-				return rc;
+				goto error_flash_set;
 			}
 
 			/* Set clamp current */
@@ -851,7 +894,7 @@
 				dev_err(&led->spmi_dev->dev,
 					"Clamp current reg write failed(%d)\n",
 					rc);
-				return rc;
+				goto error_flash_set;
 			}
 
 			/* Write 0x80 to MODULE_ENABLE before writing 0xE0
@@ -864,7 +907,7 @@
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Enable reg write failed(%d)\n", rc);
-				return rc;
+				goto error_flash_set;
 			}
 
 			rc = qpnp_led_masked_write(led,
@@ -874,7 +917,7 @@
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Current reg write failed(%d)\n", rc);
-				return rc;
+				goto error_flash_set;
 			}
 
 			rc = qpnp_led_masked_write(led,
@@ -885,7 +928,7 @@
 				dev_err(&led->spmi_dev->dev,
 					"2nd Current reg write failed(%d)\n",
 					rc);
-				return rc;
+				goto error_flash_set;
 			}
 
 			rc = qpnp_led_masked_write(led,
@@ -894,7 +937,7 @@
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Enable reg write failed(%d)\n", rc);
-				return rc;
+				goto error_flash_set;
 			}
 		}
 
@@ -906,7 +949,10 @@
 				dev_err(&led->spmi_dev->dev,
 					"LED %d strobe reg write failed(%d)\n",
 					led->id, rc);
-				return rc;
+				if (led->flash_cfg->torch_enable)
+					goto error_torch_set;
+				else
+					goto error_flash_set;
 			}
 		} else {
 			rc = qpnp_led_masked_write(led,
@@ -916,10 +962,38 @@
 				dev_err(&led->spmi_dev->dev,
 					"LED %d strobe reg write failed(%d)\n",
 					led->id, rc);
-				return 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_DISABLE_ALL);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"LED %d flash write failed(%d)\n", led->id, rc);
+			if (led->flash_cfg->torch_enable)
+				goto error_torch_set;
+			else
+				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),
@@ -927,7 +1001,7 @@
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Secure reg write failed(%d)\n", rc);
-				return rc;
+				goto error_torch_set;
 			}
 
 			rc = qpnp_led_masked_write(led,
@@ -937,40 +1011,48 @@
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Torch reg write failed(%d)\n", rc);
+				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;
 			}
-		}
-
-		rc = qpnp_led_masked_write(led,
-			FLASH_LED_STROBE_CTRL(led->base),
-			FLASH_STROBE_MASK,
-			FLASH_DISABLE_ALL);
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"LED %d flash write failed(%d)\n", led->id, rc);
-			return rc;
-		}
-
-		rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
-			FLASH_ENABLE_MASK,
-			FLASH_DISABLE_ALL);
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"Enable reg write failed(%d)\n", rc);
-			return rc;
-		}
-
-		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_flash_regulator_operate(led, false);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Flash regulator operate failed(%d)\n",
+					rc);
+				return rc;
+			}
 		}
 	}
 
 	qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
 
 	return 0;
+
+error_torch_set:
+	error = qpnp_torch_regulator_operate(led, false);
+	if (error) {
+		dev_err(&led->spmi_dev->dev,
+			"Torch regulator operate failed(%d)\n", rc);
+		return error;
+	}
+	return rc;
+
+error_flash_set:
+	error = qpnp_flash_regulator_operate(led, false);
+	if (error) {
+		dev_err(&led->spmi_dev->dev,
+			"Flash regulator operate failed(%d)\n", rc);
+		return error;
+	}
+	return rc;
 }
 
 static int qpnp_kpdbl_set(struct qpnp_led_data *led)
@@ -1997,6 +2079,18 @@
 		return rc;
 	}
 
+	/* Disable flash LED module */
+	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);
+		return rc;
+	}
+
+	if (led->flash_cfg->torch_enable)
+		return 0;
+
 	/* Set headroom */
 	rc = qpnp_led_masked_write(led, FLASH_HEADROOM(led->base),
 		FLASH_HEADROOM_MASK, led->flash_cfg->headroom);
@@ -2056,15 +2150,6 @@
 		return rc;
 	}
 
-	/* Disable flash LED module */
-	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);
-		return rc;
-	}
-
 	led->flash_cfg->strobe_type = 0;
 
 	/* dump flash registers */
@@ -2393,7 +2478,7 @@
 				rc = PTR_ERR(led->flash_cfg->flash_boost_reg);
 				dev_err(&led->spmi_dev->dev,
 					"Regulator get failed(%d)\n", rc);
-				return rc;
+				goto error_get_flash_reg;
 			}
 			led->flash_cfg->flash_reg_get = true;
 			*reg_set = true;
@@ -2412,7 +2497,7 @@
 				rc = PTR_ERR(led->flash_cfg->flash_boost_reg);
 				dev_err(&led->spmi_dev->dev,
 					"Regulator get failed(%d)\n", rc);
-				return rc;
+				goto error_get_flash_reg;
 			}
 			led->flash_cfg->flash_reg_get = true;
 			*reg_set = true;
@@ -2426,16 +2511,32 @@
 	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;
+		}
+	}
+
 	rc = of_property_read_u32(node, "qcom,current", &val);
 	if (!rc) {
-		if (led->flash_cfg->torch_enable)
+		if (led->flash_cfg->torch_enable) {
 			led->flash_cfg->current_prgm = (val *
 				TORCH_MAX_LEVEL / led->max_current);
+			return 0;
+		}
 		else
 			led->flash_cfg->current_prgm = (val *
 				FLASH_MAX_LEVEL / led->max_current);
 	} else
-		return -EINVAL;
+		if (led->flash_cfg->torch_enable)
+			goto error_get_torch_reg;
+		else
+			goto error_get_flash_reg;
 
 	rc = of_property_read_u32(node, "qcom,headroom", &val);
 	if (!rc)
@@ -2443,7 +2544,7 @@
 	else if (rc == -EINVAL)
 		led->flash_cfg->headroom = HEADROOM_500mV;
 	else
-		return rc;
+		goto error_get_flash_reg;
 
 	rc = of_property_read_u32(node, "qcom,duration", &val);
 	if (!rc)
@@ -2451,7 +2552,7 @@
 	else if (rc == -EINVAL)
 		led->flash_cfg->duration = FLASH_DURATION_200ms;
 	else
-		return rc;
+		goto error_get_flash_reg;
 
 	rc = of_property_read_u32(node, "qcom,clamp-curr", &val);
 	if (!rc)
@@ -2460,7 +2561,7 @@
 	else if (rc == -EINVAL)
 		led->flash_cfg->clamp_curr = FLASH_CLAMP_200mA;
 	else
-		return rc;
+		goto error_get_flash_reg;
 
 	rc = of_property_read_u32(node, "qcom,startup-dly", &val);
 	if (!rc)
@@ -2468,12 +2569,20 @@
 	else if (rc == -EINVAL)
 		led->flash_cfg->startup_dly = DELAY_128us;
 	else
-		return rc;
+		goto error_get_flash_reg;
 
 	led->flash_cfg->safety_timer =
 		of_property_read_bool(node, "qcom,safety-timer");
 
 	return 0;
+
+error_get_torch_reg:
+	regulator_put(led->flash_cfg->torch_boost_reg);
+
+error_get_flash_reg:
+	regulator_put(led->flash_cfg->flash_boost_reg);
+	return rc;
+
 }
 
 static int __devinit qpnp_get_config_pwm(struct pwm_config_data *pwm_cfg,
@@ -3065,6 +3174,9 @@
 			if (led_array[i].flash_cfg->flash_reg_get)
 				regulator_put(led_array[i].flash_cfg-> \
 							flash_boost_reg);
+			if (led_array[i].flash_cfg->torch_enable)
+				regulator_put(led_array[i].flash_cfg->\
+							torch_boost_reg);
 			sysfs_remove_group(&led_array[i].cdev.dev->kobj,
 							&led_attr_group);
 			break;
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index c70e151..0313161 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -353,6 +353,7 @@
 
 set_fmt_fail:
 	kzfree(sp->vb2_q.drv_priv);
+	sp->vb2_q.drv_priv = NULL;
 	return rc;
 }
 
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 aa6f034..2ea4388 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
@@ -501,7 +501,8 @@
 		(int) buf_cmd.vaddr, buf_cmd.y_len);
 
 	buf_p->y_buffer_addr    = msm_jpeg_platform_v2p(pgmn_dev, buf_cmd.fd,
-		buf_cmd.y_len + buf_cmd.cbcr_len + buf_cmd.pln2_len,
+		buf_cmd.y_len + buf_cmd.cbcr_len +
+		buf_cmd.pln2_len + buf_cmd.offset,
 		&buf_p->file, &buf_p->handle, pgmn_dev->domain_num) +
 		buf_cmd.offset + buf_cmd.y_off;
 	buf_p->y_len          = buf_cmd.y_len;
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 4fa3085..7f4f231 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
@@ -292,7 +292,7 @@
 static int32_t msm_cci_i2c_read(struct v4l2_subdev *sd,
 	struct msm_camera_cci_ctrl *c_ctrl)
 {
-	uint32_t rc = 0;
+	int32_t rc = 0;
 	uint32_t val = 0;
 	int32_t read_words = 0, exp_words = 0;
 	int32_t index = 0, first_byte = 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 ac697fb..c713c85 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
@@ -19,7 +19,7 @@
 #include <media/msm_cam_sensor.h>
 #include "msm_sd.h"
 
-#define MAX_LED_TRIGGERS 2
+#define MAX_LED_TRIGGERS 3
 
 struct msm_led_flash_ctrl_t;
 
@@ -38,10 +38,14 @@
 	struct msm_sd_subdev msm_sd;
 	struct platform_device *pdev;
 	struct msm_flash_fn_t *func_tbl;
-	const char *led_trigger_name[MAX_LED_TRIGGERS];
-	struct led_trigger *led_trigger[MAX_LED_TRIGGERS];
-	uint32_t op_current[MAX_LED_TRIGGERS];
+	const char *flash_trigger_name[MAX_LED_TRIGGERS];
+	struct led_trigger *flash_trigger[MAX_LED_TRIGGERS];
+	uint32_t flash_op_current[MAX_LED_TRIGGERS];
+	const char *torch_trigger_name;
+	struct led_trigger *torch_trigger;
+	uint32_t torch_op_current;
 	void *data;
+	uint32_t num_sources;
 };
 
 int32_t msm_led_flash_create_v4lsubdev(struct platform_device *pdev,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
index c6f1f72..1b0ec44 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
@@ -46,29 +46,45 @@
 {
 	int rc = 0;
 	struct msm_camera_led_cfg_t *cfg = (struct msm_camera_led_cfg_t *)data;
+	uint32_t i;
 	CDBG("called led_state %d\n", cfg->cfgtype);
 
-	if (!fctrl->led_trigger[0]) {
+	if (!fctrl) {
 		pr_err("failed\n");
 		return -EINVAL;
 	}
+
 	switch (cfg->cfgtype) {
 	case MSM_CAMERA_LED_OFF:
-		led_trigger_event(fctrl->led_trigger[0], 0);
+		for (i = 0; i < fctrl->num_sources; i++)
+			if (fctrl->flash_trigger[i])
+				led_trigger_event(fctrl->flash_trigger[i], 0);
+		if (fctrl->torch_trigger)
+			led_trigger_event(fctrl->torch_trigger, 0);
 		break;
 
 	case MSM_CAMERA_LED_LOW:
-		led_trigger_event(fctrl->led_trigger[0],
-			fctrl->op_current[0] / 2);
+		if (fctrl->torch_trigger)
+			led_trigger_event(fctrl->torch_trigger,
+				fctrl->torch_op_current);
 		break;
 
 	case MSM_CAMERA_LED_HIGH:
-		led_trigger_event(fctrl->led_trigger[0], fctrl->op_current[0]);
+		if (fctrl->torch_trigger)
+			led_trigger_event(fctrl->torch_trigger, 0);
+		for (i = 0; i < fctrl->num_sources; i++)
+			if (fctrl->flash_trigger[i])
+				led_trigger_event(fctrl->flash_trigger[i],
+					fctrl->flash_op_current[i]);
 		break;
 
 	case MSM_CAMERA_LED_INIT:
 	case MSM_CAMERA_LED_RELEASE:
-		led_trigger_event(fctrl->led_trigger[0], 0);
+		for (i = 0; i < fctrl->num_sources; i++)
+			if (fctrl->flash_trigger[i])
+				led_trigger_event(fctrl->flash_trigger[i], 0);
+		if (fctrl->torch_trigger)
+			led_trigger_event(fctrl->torch_trigger, 0);
 		break;
 
 	default:
@@ -109,6 +125,7 @@
 	}
 
 	fctrl.pdev = pdev;
+	fctrl.num_sources = 0;
 
 	rc = of_property_read_u32(of_node, "cell-index", &pdev->id);
 	if (rc < 0) {
@@ -124,6 +141,7 @@
 			pr_err("failed\n");
 			return -EINVAL;
 		}
+		fctrl.num_sources = count;
 		for (i = 0; i < count; i++) {
 			flash_src_node = of_parse_phandle(of_node,
 				"qcom,flash-source", i);
@@ -134,17 +152,18 @@
 
 			rc = of_property_read_string(flash_src_node,
 				"linux,default-trigger",
-				&fctrl.led_trigger_name[i]);
+				&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.led_trigger_name[i]);
+			CDBG("default trigger %s\n",
+				fctrl.flash_trigger_name[i]);
 
 			rc = of_property_read_u32(flash_src_node,
-				"qcom,current", &fctrl.op_current[i]);
+				"qcom,current", &fctrl.flash_op_current[i]);
 			if (rc < 0) {
 				pr_err("failed rc %d\n", rc);
 				of_node_put(flash_src_node);
@@ -153,10 +172,41 @@
 
 			of_node_put(flash_src_node);
 
-			CDBG("max_current[%d] %d\n", i, fctrl.op_current[i]);
+			CDBG("max_current[%d] %d\n",
+				i, fctrl.flash_op_current[i]);
 
-			led_trigger_register_simple(fctrl.led_trigger_name[i],
-				&fctrl.led_trigger[i]);
+			led_trigger_register_simple(fctrl.flash_trigger_name[i],
+				&fctrl.flash_trigger[i]);
+		}
+
+		/* Torch source */
+		flash_src_node = of_parse_phandle(of_node, "qcom,torch-source",
+			0);
+		if (flash_src_node) {
+			rc = of_property_read_string(flash_src_node,
+				"linux,default-trigger",
+				&fctrl.torch_trigger_name);
+			if (rc < 0) {
+				pr_err("failed\n");
+			} else {
+				CDBG("default trigger %s\n",
+					fctrl.torch_trigger_name);
+
+				rc = of_property_read_u32(flash_src_node,
+					"qcom,current",
+					&fctrl.torch_op_current);
+				if (rc < 0) {
+					pr_err("failed rc %d\n", rc);
+				} else {
+					CDBG("torch max_current %d\n",
+						fctrl.torch_op_current);
+
+					led_trigger_register_simple(
+						fctrl.torch_trigger_name,
+						&fctrl.torch_trigger);
+				}
+			}
+			of_node_put(flash_src_node);
 		}
 	}
 	rc = msm_led_flash_create_v4lsubdev(pdev, &fctrl);
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 7897068..cddca74 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -683,6 +683,18 @@
 		.qmenu = perf_level,
 		.step = 0,
 	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB,
+		.name = "Intra Refresh CIR MBS",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = MAX_INTRA_REFRESH_MBS,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
+	}
 };
 
 #define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
@@ -1641,8 +1653,8 @@
 		air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
 		cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
 
-		property_id =
-			HAL_PARAM_VENC_INTRA_REFRESH;
+		property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
 		intra_refresh.air_mbs = ctrl->val;
 		intra_refresh.mode = ir_mode->val;
 		intra_refresh.air_ref = air_ref->val;
@@ -1658,8 +1670,8 @@
 		air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
 		cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
 
-		property_id =
-			HAL_PARAM_VENC_INTRA_REFRESH;
+		property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
 		intra_refresh.air_ref = ctrl->val;
 		intra_refresh.air_mbs = air_mbs->val;
 		intra_refresh.mode = ir_mode->val;
@@ -1676,8 +1688,7 @@
 		air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
 		air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
 
-		property_id =
-			HAL_PARAM_VENC_INTRA_REFRESH;
+		property_id = HAL_PARAM_VENC_INTRA_REFRESH;
 
 		intra_refresh.cir_mbs = ctrl->val;
 		intra_refresh.air_mbs = air_mbs->val;
@@ -1687,6 +1698,22 @@
 		pdata = &intra_refresh;
 		break;
 	}
+	case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: {
+		struct v4l2_ctrl *air_mbs, *air_ref;
+
+		air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+		air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+
+		property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
+		intra_refresh.cir_mbs = ctrl->val;
+		intra_refresh.air_mbs = air_mbs->val;
+		intra_refresh.air_ref = air_ref->val;
+		intra_refresh.mode = HAL_INTRA_REFRESH_CYCLIC;
+
+		pdata = &intra_refresh;
+		break;
+	}
 	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
 		property_id =
 			HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index b9eb8f9..de6f1d5 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -126,6 +126,11 @@
 		struct rds_grp_data rds_buf);
 static void hci_ev_ert(struct iris_device *radio);
 static int update_spur_table(struct iris_device *radio);
+static int initialise_recv(struct iris_device *radio);
+static int initialise_trans(struct iris_device *radio);
+static int is_enable_rx_possible(struct iris_device *radio);
+static int is_enable_tx_possible(struct iris_device *radio);
+
 static struct v4l2_queryctrl iris_v4l2_queryctrl[] = {
 	{
 	.id	= V4L2_CID_AUDIO_VOLUME,
@@ -1633,13 +1638,16 @@
 	__u8 status = *((__u8 *) skb->data);
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
 
-	if (status)
-		return;
-	if ((radio->mode != FM_CALIB) && (radio->mode != FM_OFF))
+	if ((radio->mode == FM_TURNING_OFF) && (status == 0)) {
 		iris_q_event(radio, IRIS_EVT_RADIO_DISABLED);
-	radio->mode = FM_OFF;
-
-	radio_hci_req_complete(hdev, status);
+		radio_hci_req_complete(hdev, status);
+		radio->mode = FM_OFF;
+	} else if (radio->mode == FM_CALIB) {
+		radio_hci_req_complete(hdev, status);
+	} else if ((radio->mode == FM_RECV) || (radio->mode == FM_TRANS)) {
+		iris_q_event(radio, IRIS_EVT_RADIO_DISABLED);
+		radio->mode = FM_OFF;
+	}
 }
 
 static void hci_cc_conf_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
@@ -1673,11 +1681,18 @@
 	struct hci_fm_conf_rsp  *rsp = (void *)skb->data;
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
 
-	if (rsp->status)
+	if (rsp->status) {
+		radio_hci_req_complete(hdev, rsp->status);
 		return;
-	if (radio->mode != FM_CALIB)
-		iris_q_event(radio, IRIS_EVT_RADIO_READY);
+	}
 
+	if (radio->mode == FM_RECV_TURNING_ON) {
+		radio->mode = FM_RECV;
+		iris_q_event(radio, IRIS_EVT_RADIO_READY);
+	} else if (radio->mode == FM_TRANS_TURNING_ON) {
+		radio->mode = FM_TRANS;
+		iris_q_event(radio, IRIS_EVT_RADIO_READY);
+	}
 	radio_hci_req_complete(hdev, rsp->status);
 }
 
@@ -2695,7 +2710,9 @@
 			radio->fm_hdev);
 	if (retval < 0)
 		FMDERR("Disable Failed after calibration %d", retval);
-	radio->mode = FM_TURNING_OFF;
+	else
+		radio->mode = FM_OFF;
+
 	return retval;
 }
 static int iris_vidioc_g_ctrl(struct file *file, void *priv,
@@ -3177,82 +3194,60 @@
 	case V4L2_CID_PRIVATE_IRIS_STATE:
 		switch (ctrl->value) {
 		case FM_RECV:
+			if (is_enable_rx_possible(radio) != 0)
+				return -EINVAL;
+			radio->mode = FM_RECV_TURNING_ON;
 			retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
 							 radio->fm_hdev);
 			if (retval < 0) {
 				FMDERR("Error while enabling RECV FM"
 							" %d\n", retval);
+				radio->mode = FM_OFF;
 				return retval;
+			} else {
+				initialise_recv(radio);
 			}
-			radio->mode = FM_RECV;
-			radio->mute_mode.soft_mute = CTRL_ON;
-			retval = hci_set_fm_mute_mode(
-						&radio->mute_mode,
-							radio->fm_hdev);
-			if (retval < 0) {
-				FMDERR("Failed to enable Smute\n");
-				return retval;
-			}
-			radio->stereo_mode.stereo_mode = CTRL_OFF;
-			radio->stereo_mode.sig_blend = CTRL_ON;
-			radio->stereo_mode.intf_blend = CTRL_ON;
-			radio->stereo_mode.most_switch = CTRL_ON;
-			retval = hci_set_fm_stereo_mode(
-						&radio->stereo_mode,
-							radio->fm_hdev);
-			if (retval < 0) {
-				FMDERR("Failed to set stereo mode\n");
-				return retval;
-			}
-			radio->event_mask = SIG_LEVEL_INTR |
-						RDS_SYNC_INTR | AUDIO_CTRL_INTR;
-			retval = hci_conf_event_mask(&radio->event_mask,
-							radio->fm_hdev);
-			if (retval < 0) {
-				FMDERR("Enable Async events failed");
-				return retval;
-			}
-			retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
-						radio->fm_hdev);
-			if (retval < 0)
-				FMDERR("Failed to get the Recv Config\n");
 			break;
 		case FM_TRANS:
+			if (!is_enable_tx_possible(radio) != 0)
+				return -EINVAL;
+			radio->mode = FM_TRANS_TURNING_ON;
 			retval = hci_cmd(HCI_FM_ENABLE_TRANS_CMD,
 							 radio->fm_hdev);
 			if (retval < 0) {
 				FMDERR("Error while enabling TRANS FM"
 							" %d\n", retval);
+				radio->mode = FM_OFF;
 				return retval;
+			} else {
+				initialise_trans(radio);
 			}
-			radio->mode = FM_TRANS;
-			retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
-			if (retval < 0)
-				FMDERR("get frequency failed %d\n", retval);
 			break;
 		case FM_OFF:
 			radio->spur_table_size = 0;
 			switch (radio->mode) {
 			case FM_RECV:
+				radio->mode = FM_TURNING_OFF;
 				retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
 						radio->fm_hdev);
 				if (retval < 0) {
 					FMDERR("Err on disable recv FM"
 						   " %d\n", retval);
+					radio->mode = FM_RECV;
 					return retval;
 				}
-				radio->mode = FM_TURNING_OFF;
 				break;
 			case FM_TRANS:
+				radio->mode = FM_TURNING_OFF;
 				retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
 						radio->fm_hdev);
 
 				if (retval < 0) {
 					FMDERR("Err disabling trans FM"
 						" %d\n", retval);
+					radio->mode = FM_TRANS;
 					return retval;
 				}
-				radio->mode = FM_TURNING_OFF;
 				break;
 			default:
 				retval = -EINVAL;
@@ -4132,6 +4127,73 @@
 	return 0;
 }
 
+static int initialise_recv(struct iris_device *radio)
+{
+	int retval;
+
+	radio->mute_mode.soft_mute = CTRL_ON;
+	retval = hci_set_fm_mute_mode(&radio->mute_mode,
+					radio->fm_hdev);
+
+	if (retval < 0) {
+		FMDERR("Failed to enable Smute\n");
+		return retval;
+	}
+
+	radio->stereo_mode.stereo_mode = CTRL_OFF;
+	radio->stereo_mode.sig_blend = CTRL_ON;
+	radio->stereo_mode.intf_blend = CTRL_ON;
+	radio->stereo_mode.most_switch = CTRL_ON;
+	retval = hci_set_fm_stereo_mode(&radio->stereo_mode,
+						radio->fm_hdev);
+
+	if (retval < 0) {
+		FMDERR("Failed to set stereo mode\n");
+		return retval;
+	}
+
+	radio->event_mask = SIG_LEVEL_INTR | RDS_SYNC_INTR | AUDIO_CTRL_INTR;
+	retval = hci_conf_event_mask(&radio->event_mask, radio->fm_hdev);
+	if (retval < 0) {
+		FMDERR("Enable Async events failed");
+		return retval;
+	}
+
+	retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD, radio->fm_hdev);
+	if (retval < 0)
+		FMDERR("Failed to get the Recv Config\n");
+	return retval;
+}
+
+static int initialise_trans(struct iris_device *radio)
+{
+
+	int retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
+	if (retval < 0)
+		FMDERR("get frequency failed %d\n", retval);
+
+	return retval;
+}
+
+static int is_enable_rx_possible(struct iris_device *radio)
+{
+	int retval = 1;
+
+	if (radio->mode == FM_OFF || radio->mode == FM_RECV)
+		retval = 0;
+
+	return retval;
+}
+
+static int is_enable_tx_possible(struct iris_device *radio)
+{
+	int retval = 1;
+
+	if (radio->mode == FM_OFF || radio->mode == FM_TRANS)
+		retval = 0;
+
+	return retval;
+}
 
 static const struct v4l2_ioctl_ops iris_ioctl_ops = {
 	.vidioc_querycap              = iris_vidioc_querycap,
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 3d0abce..1eebe61 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -470,7 +470,7 @@
 	found = wcd9xxx_check_codec_type(wcd9xxx, &version);
 	if (!found) {
 		ret = -ENODEV;
-		goto err_irq;
+		goto err;
 	} else {
 		wcd9xxx->codec_type = found;
 		wcd9xxx->version = version;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index b750602..0987b6b 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -890,8 +890,8 @@
 	data->type = QSEECOM_SECURE_SERVICE;
 
 	switch (req.cmd_id) {
-	case QSEE_RPMB_PROVISION_KEY_COMMAND:
-	case QSEE_RPMB_ERASE_COMMAND:
+	case QSEOS_RPMB_PROVISION_KEY_COMMAND:
+	case QSEOS_RPMB_ERASE_COMMAND:
 		if (__qseecom_process_rpmb_svc_cmd(data, &req,
 				&send_svc_ireq))
 			return -EINVAL;
diff --git a/drivers/net/ethernet/msm/msm_rmnet_bam.c b/drivers/net/ethernet/msm/msm_rmnet_bam.c
index 3f3d76a..44f86dd 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_bam.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_bam.c
@@ -62,8 +62,9 @@
 
 #define DEVICE_ID_INVALID   -1
 
-#define DEVICE_INACTIVE      0
+#define DEVICE_INACTIVE      2
 #define DEVICE_ACTIVE        1
+#define DEVICE_UNINITIALIZED 0
 
 #define HEADROOM_FOR_BAM   8 /* for mux header */
 #define HEADROOM_FOR_QOS    8
@@ -394,7 +395,7 @@
 
 	DBG0("[%s] __rmnet_open()\n", dev->name);
 
-	if (!p->device_up) {
+	if (p->device_up == DEVICE_UNINITIALIZED) {
 		r = msm_bam_dmux_open(p->ch_id, dev, bam_notify);
 
 		if (r < 0) {
@@ -436,7 +437,7 @@
 	struct rmnet_private *p = netdev_priv(dev);
 	int rc = 0;
 
-	if (p->device_up) {
+	if (p->device_up == DEVICE_ACTIVE) {
 		/* do not close rmnet port once up,  this causes
 		   remote side to hang if tried to open again */
 		p->device_up = DEVICE_INACTIVE;
@@ -906,6 +907,7 @@
 		p->ch_id = n;
 		p->waiting_for_ul_skb = NULL;
 		p->in_reset = 0;
+		p->device_up = DEVICE_UNINITIALIZED;
 		spin_lock_init(&p->lock);
 		spin_lock_init(&p->tx_queue_lock);
 #ifdef CONFIG_MSM_RMNET_DEBUG
@@ -971,6 +973,7 @@
 		p->ch_id = n+BAM_DMUX_DATA_REV_RMNET_0;
 		p->waiting_for_ul_skb = NULL;
 		p->in_reset = 0;
+		p->device_up = DEVICE_UNINITIALIZED;
 		spin_lock_init(&p->lock);
 		spin_lock_init(&p->tx_queue_lock);
 
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 657fc2f..1262306 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -81,9 +81,16 @@
 
 #define PRONTO_PMU_SPARE_OFFSET       0x1088
 
-#define PRONTO_PMU_GDSCR_OFFSET       0x0024
-#define PRONTO_PMU_GDSCR_SW_COLLAPSE  BIT(0)
-#define PRONTO_PMU_GDSCR_HW_CTRL      BIT(1)
+#define PRONTO_PMU_COM_GDSCR_OFFSET       0x0024
+#define PRONTO_PMU_COM_GDSCR_SW_COLLAPSE  BIT(0)
+#define PRONTO_PMU_COM_GDSCR_HW_CTRL      BIT(1)
+
+#define PRONTO_PMU_WLAN_BCR_OFFSET         0x0050
+#define PRONTO_PMU_WLAN_BCR_BLK_ARES       BIT(0)
+
+#define PRONTO_PMU_WLAN_GDSCR_OFFSET       0x0054
+#define PRONTO_PMU_WLAN_GDSCR_SW_COLLAPSE  BIT(0)
+
 
 #define PRONTO_PMU_CBCR_OFFSET        0x0008
 #define PRONTO_PMU_CBCR_CLK_EN        BIT(0)
@@ -118,6 +125,9 @@
 #define MSM_PRONTO_PLL_BASE				0xfb21b1c0
 #define PRONTO_PLL_STATUS_OFFSET		0x1c
 
+#define MSM_PRONTO_TXP_PHY_ABORT        0xfb080488
+#define MSM_PRONTO_BRDG_ERR_SRC         0xfb080fb0
+
 #define WCNSS_DEF_WLAN_RX_BUFF_COUNT		1024
 
 #define WCNSS_CTRL_CHANNEL			"WCNSS_CTRL"
@@ -296,6 +306,8 @@
 	void __iomem *pronto_ccpu_base;
 	void __iomem *pronto_saw2_base;
 	void __iomem *pronto_pll_base;
+	void __iomem *wlan_tx_phy_aborts;
+	void __iomem *wlan_brdg_err_source;
 	void __iomem *fiq_reg;
 	int	ssr_boot;
 	int	nv_downloaded;
@@ -435,14 +447,14 @@
 void wcnss_pronto_log_debug_regs(void)
 {
 	void __iomem *reg_addr, *tst_addr, *tst_ctrl_addr;
-	u32 reg = 0;
+	u32 reg = 0, reg2 = 0;
 
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SPARE_OFFSET;
 	reg = readl_relaxed(reg_addr);
 	pr_info_ratelimited("%s:  PRONTO_PMU_SPARE %08x\n", __func__, reg);
 
-	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_GDSCR_OFFSET;
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_GDSCR_OFFSET;
 	reg = readl_relaxed(reg_addr);
 	reg >>= 31;
 
@@ -451,7 +463,8 @@
 				__func__);
 		return;
 	}
-	reg &= ~(PRONTO_PMU_GDSCR_SW_COLLAPSE | PRONTO_PMU_GDSCR_HW_CTRL);
+	reg &= ~(PRONTO_PMU_COM_GDSCR_SW_COLLAPSE
+			| PRONTO_PMU_COM_GDSCR_HW_CTRL);
 	writel_relaxed(reg, reg_addr);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CBCR_OFFSET;
@@ -557,6 +570,26 @@
 	reg = readl_relaxed(tst_addr);
 	pr_info_ratelimited("%s:  CTRL SEL CFG1 testbus %08x\n", __func__, reg);
 
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WLAN_BCR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WLAN_GDSCR_OFFSET;
+	reg2 = readl_relaxed(reg_addr);
+
+	if ((reg & PRONTO_PMU_WLAN_BCR_BLK_ARES) ||
+			(reg2 & PRONTO_PMU_WLAN_GDSCR_SW_COLLAPSE)) {
+		pr_info_ratelimited("%s:  Cannot log, wlan domain is power collapsed\n",
+				__func__);
+		return;
+	}
+
+	reg = readl_relaxed(penv->wlan_tx_phy_aborts);
+	pr_info_ratelimited("%s: WLAN_TX_PHY_ABORTS %08x\n", __func__, reg);
+
+	reg = readl_relaxed(penv->wlan_brdg_err_source);
+	pr_info_ratelimited("%s: WLAN_BRDG_ERR_SOURCE %08x\n", __func__, reg);
+
 }
 EXPORT_SYMBOL(wcnss_pronto_log_debug_regs);
 
@@ -1716,6 +1749,21 @@
 			goto fail_ioremap6;
 		}
 
+		penv->wlan_tx_phy_aborts =  ioremap(MSM_PRONTO_TXP_PHY_ABORT,
+					SZ_8);
+		if (!penv->wlan_tx_phy_aborts) {
+			ret = -ENOMEM;
+			pr_err("%s: ioremap wlan TX PHY failed\n", __func__);
+			goto fail_ioremap7;
+		}
+		penv->wlan_brdg_err_source =  ioremap(MSM_PRONTO_BRDG_ERR_SRC,
+							SZ_8);
+		if (!penv->wlan_brdg_err_source) {
+			ret = -ENOMEM;
+			pr_err("%s: ioremap wlan BRDG ERR failed\n", __func__);
+			goto fail_ioremap8;
+		}
+
 	}
 
 	/* trigger initialization of the WCNSS */
@@ -1732,6 +1780,12 @@
 fail_pil:
 	if (penv->riva_ccu_base)
 		iounmap(penv->riva_ccu_base);
+	if (penv->wlan_brdg_err_source)
+		iounmap(penv->wlan_brdg_err_source);
+fail_ioremap8:
+	if (penv->wlan_tx_phy_aborts)
+		iounmap(penv->wlan_tx_phy_aborts);
+fail_ioremap7:
 	if (penv->pronto_pll_base)
 		iounmap(penv->pronto_pll_base);
 fail_ioremap6:
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
index e832716..87c7c30 100644
--- a/drivers/nfc/nfc-nci.c
+++ b/drivers/nfc/nfc-nci.c
@@ -49,6 +49,7 @@
 #define MAX_QCA_REG		(116)
 
 static int nfc_i2c_write(struct i2c_client *client, u8 *buf, int len);
+static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr);
 
 struct qca199x_dev {
 	wait_queue_head_t read_wq;
@@ -167,6 +168,8 @@
 		count = MAX_BUFFER_SIZE;
 
 	mutex_lock(&qca199x_dev->read_mutex);
+	memset(tmp, 0, sizeof(tmp));
+	memset(len, 0, sizeof(len));
 	dmode = device_mode.handle_flavour;
 	/* FTM-RAW-I2C RD/WR MODE - Special Case */
 	if ((dmode == UNSOLICITED_FTM_RAW_MODE) ||
@@ -199,20 +202,25 @@
 	/* NORMAL NCI Behaviour */
 	/* Read the header */
 	ret = i2c_master_recv(qca199x_dev->client, len, PAYLOAD_HEADER_LENGTH);
-	if (ret != PAYLOAD_HEADER_LENGTH)
+	if (ret != PAYLOAD_HEADER_LENGTH) {
+		total = 0;
 		goto err;
+	}
 	length = len[PAYLOAD_HEADER_LENGTH - 1];
-
+	if (length == 0)
+		total = 0;
 	/** make sure full packet fits in the buffer **/
 	if ((length > 0) && ((length + PAYLOAD_HEADER_LENGTH) <= count)) {
 		/* Read the packet */
 		ret = i2c_master_recv(qca199x_dev->client, tmp, (length +
 			PAYLOAD_HEADER_LENGTH));
-		if (ret < 0)
+		if (ret < 0) {
+			total = 0;
 			goto err;
+		}
 		total = (length + PAYLOAD_HEADER_LENGTH);
 	}
-	mutex_unlock(&qca199x_dev->read_mutex);
+
 	if (total > 0) {
 		if ((total > count) || copy_to_user(buf, tmp, total)) {
 			dev_err(&qca199x_dev->client->dev,
@@ -221,6 +229,7 @@
 			total = -EFAULT;
 		}
 	}
+	mutex_unlock(&qca199x_dev->read_mutex);
 err:
 	if (ret < 0)
 		mutex_unlock(&qca199x_dev->read_mutex);
@@ -375,6 +384,7 @@
 			goto err_req;
 		}
 		gpio_set_value(qca199x_dev->dis_gpio, 0);
+		msleep(20);
 	} else if (arg == 1) {
 		gpio_set_value(qca199x_dev->dis_gpio, 0);
 		r = gpio_direction_output(qca199x_dev->dis_gpio, 1);
@@ -385,12 +395,20 @@
 			goto err_req;
 		}
 		gpio_set_value(qca199x_dev->dis_gpio, 1);
+		usleep(1000);
 	} else if (arg == 2) {
-		msleep(20);
+		r = nfcc_initialise(qca199x_dev->client, 0xE);
+		if (r) {
+			dev_err(&qca199x_dev->client->dev,
+					"nfc-nci probe: request nfcc initialise failed\n");
+			goto err_req;
+		}
 	} else if (arg == 3) {
 		msleep(20);
 	} else if (arg == 4) {
+		mutex_lock(&qca199x_dev->read_mutex);
 		nfcc_wake(NFCC_WAKE, filp);
+		mutex_unlock(&qca199x_dev->read_mutex);
 	} else if (arg == 5) {
 		nfcc_wake(NFCC_SLEEP, filp);
 	} else {
@@ -568,7 +586,7 @@
 	return r;
 }
 
-int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr)
+static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr)
 {
 	int r = 0;
 	unsigned char raw_1p8_CONTROL_011[]	= {0x11, XTAL_CLOCK};
@@ -764,9 +782,9 @@
 		dev_err(&client->dev, "dis gpio not provided\n");
 		goto err_irq;
 	}
-	gpio_set_value(qca199x_dev->dis_gpio, 1);
+	gpio_set_value(platform_data->dis_gpio, 1);/* HPD */
 	msleep(20);
-	gpio_set_value(qca199x_dev->dis_gpio, 0);
+	gpio_set_value(platform_data->dis_gpio, 0);/* ULPM */
 
 	nfc_clk  = clk_get(&client->dev, "ref_clk");
 
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 6ccfd29..4f10cf8 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -81,6 +81,7 @@
 
 u32 d_type;
 bool enhd_pipe;
+bool imem;
 
 static void sps_device_de_init(void);
 
@@ -2430,13 +2431,16 @@
 
 	resource = platform_get_resource(pdev, IORESOURCE_MEM, 2);
 	if (resource) {
+		imem = true;
 		sps->pipemem_phys_base = resource->start;
 		sps->pipemem_size = resource_size(resource);
 		SPS_DBG("sps:pipemem.base=0x%x,size=0x%x.",
 			sps->pipemem_phys_base,
 			sps->pipemem_size);
-	} else
+	} else {
+		imem = false;
 		SPS_DBG("sps:No pipe memory on this target.\n");
+	}
 
 	resource  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (resource) {
diff --git a/drivers/platform/msm/sps/sps_mem.c b/drivers/platform/msm/sps/sps_mem.c
index faa1618..34a2001 100644
--- a/drivers/platform/msm/sps/sps_mem.c
+++ b/drivers/platform/msm/sps/sps_mem.c
@@ -109,7 +109,7 @@
 	/* 2^8=128. The desc-fifo and data-fifo minimal allocation. */
 	int min_alloc_order = 8;
 
-	if ((d_type == 0) || (d_type == 2)) {
+	if ((d_type == 0) || (d_type == 2) || imem) {
 		iomem_phys = pipemem_phys_base;
 		iomem_size = pipemem_size;
 
@@ -136,7 +136,7 @@
 		return -ENOMEM;
 	}
 
-	if ((d_type == 0) || (d_type == 2)) {
+	if ((d_type == 0) || (d_type == 2) || imem) {
 		res = gen_pool_add(pool, (u32) iomem_virt, iomem_size, nid);
 		if (res)
 			return res;
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index f65fef7..353ece6 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -50,6 +50,7 @@
 
 extern u32 d_type;
 extern bool enhd_pipe;
+extern bool imem;
 
 #ifdef CONFIG_DEBUG_FS
 extern u8 debugfs_record_enabled;
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 408681c..8bb4f90 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -162,6 +162,11 @@
 	struct work_struct finish_suspend_work;
 };
 
+struct usb_bam_hsic_host_info {
+	struct device *dev;
+	bool in_lpm;
+};
+
 static spinlock_t usb_bam_ipa_handshake_info_lock;
 static struct usb_bam_ipa_handshake_info info;
 static spinlock_t usb_bam_peer_handshake_info_lock;
@@ -169,8 +174,7 @@
 static spinlock_t usb_bam_lock; /* Protect ctx and usb_bam_connections */
 static struct usb_bam_pipe_connect *usb_bam_connections;
 static struct usb_bam_ctx_type ctx;
-
-static struct device *hsic_host_dev;
+static struct usb_bam_hsic_host_info hsic_host_info;
 
 static int __usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
 	void *param, bool trigger_cb_per_pipe);
@@ -184,15 +188,16 @@
 		pr_debug("%s: Getting hsic device %x\n", __func__,
 			(int)dev);
 		pm_runtime_get(dev);
-	} else if (hsic_host_dev) {
+	} else if (hsic_host_info.dev) {
 		pr_debug("%s: Putting hsic device %x\n", __func__,
-			(int)hsic_host_dev);
+			(int)hsic_host_info.dev);
 		/* Just free previous device*/
 		info.in_lpm[HSIC_BAM] = true;
-		pm_runtime_put(hsic_host_dev);
+		pm_runtime_put(hsic_host_info.dev);
 	}
 
-	hsic_host_dev = dev;
+	hsic_host_info.dev = dev;
+	hsic_host_info.in_lpm = false;
 }
 
 static int get_bam_type_from_core_name(const char *name)
@@ -847,18 +852,24 @@
 	return;
 }
 
+/**
+ * usb_bam_resume_hsic_host: vote for hsic host core resume.
+ * In addition also resume all hsic pipes that are connected to
+ * the ipa peer bam.
+ *
+ * NOTE: This function should be called in a context that hold
+ *	 usb_bam_lock.
+ */
 static void usb_bam_resume_hsic_host(void)
 {
 	int i;
 	struct usb_bam_pipe_connect *pipe_iter;
 
-	spin_lock(&usb_bam_lock);
-
 	/* Exit from "full suspend" in case of hsic host */
-	if (hsic_host_dev && info.in_lpm[HSIC_BAM]) {
+	if (hsic_host_info.dev && info.in_lpm[HSIC_BAM]) {
 		pr_debug("%s: Getting hsic device %x\n", __func__,
-			(int)hsic_host_dev);
-		pm_runtime_get(hsic_host_dev);
+			(int)hsic_host_info.dev);
+		pm_runtime_get(hsic_host_info.dev);
 		info.in_lpm[HSIC_BAM] = false;
 
 		for (i = 0; i < ctx.max_connections; i++) {
@@ -873,8 +884,6 @@
 			}
 		}
 	}
-
-	spin_unlock(&usb_bam_lock);
 }
 
 static int cons_request_resource(enum usb_bam cur_bam)
@@ -905,16 +914,26 @@
 
 		break;
 	case HSIC_BAM:
+		/*
+		 * Vote for hsic resume, however the core
+		 * resume may not be completed yet or on the other hand
+		 * hsic core might already be resumed, due to a vote
+		 * by other driver, in this case we will just renew our
+		 * vote here.
+		 */
+		usb_bam_resume_hsic_host();
 
-			usb_bam_resume_hsic_host();
+		/*
+		 * Return sucess if there are pipes connected
+		 * and hsic core is actually not in lpm.
+		 * If in lpm, grant will occur on resume
+		 * finish (see msm_bam_hsic_notify_on_resume)
+		 */
+		if (ctx.pipes_enabled_per_bam[cur_bam] &&
+		    !hsic_host_info.in_lpm) {
+			ret = 0;
+		}
 
-			/*
-			 * Return sucess if there are pipes connected
-			 * and not in lpm
-			 */
-			if (ctx.pipes_enabled_per_bam[cur_bam] &&
-			    !info.in_lpm[cur_bam])
-				ret = 0;
 		break;
 	case SSUSB_BAM:
 	default:
@@ -926,6 +945,7 @@
 
 	if (ret == -EINPROGRESS)
 		pr_debug("%s: EINPROGRESS on cons_request", __func__);
+
 	return ret;
 }
 
@@ -968,10 +988,10 @@
 		 * Allow to go to lpm for now. Actual state will be checked
 		 * in msm_bam_hsic_lpm_ok() just before going to lpm.
 		 */
-		if (hsic_host_dev && !info.in_lpm[HSIC_BAM]) {
+		if (hsic_host_info.dev && !info.in_lpm[HSIC_BAM]) {
 			pr_debug("%s: Putting hsic device %x\n", __func__,
-			(int)hsic_host_dev);
-			pm_runtime_put(hsic_host_dev);
+			(int)hsic_host_info.dev);
+			pm_runtime_put(hsic_host_info.dev);
 			info.in_lpm[HSIC_BAM] = true;
 		}
 	}
@@ -1315,6 +1335,8 @@
 
 void msm_bam_wait_for_hsic_prod_granted(void)
 {
+	spin_lock(&usb_bam_lock);
+
 	ctx.is_bam_inactivity[HSIC_BAM] = false;
 
 	/* Get back to resume state including wakeup ipa */
@@ -1322,10 +1344,19 @@
 
 	/* Ensure getting the producer resource */
 	wait_for_prod_granted(HSIC_BAM);
+
+	spin_unlock(&usb_bam_lock);
 }
 
 void msm_bam_hsic_notify_on_resume(void)
 {
+	spin_lock(&usb_bam_lock);
+
+	hsic_host_info.in_lpm = false;
+
+	/* HSIC resume completed. Notify CONS grant if CONS was requested */
+	notify_usb_connected(HSIC_BAM);
+
 	/*
 	 * This function is called to notify the usb bam driver
 	 * that the hsic core and hsic bam hw are fully resumed
@@ -1334,6 +1365,8 @@
 	 */
 	if (ctx.inactivity_timer_ms[HSIC_BAM])
 		usb_bam_set_inactivity_timer(HSIC_BAM);
+
+	spin_unlock(&usb_bam_lock);
 }
 
 bool msm_bam_hsic_lpm_ok(void)
@@ -1341,7 +1374,7 @@
 	int i;
 	struct usb_bam_pipe_connect *pipe_iter;
 
-	if (hsic_host_dev) {
+	if (hsic_host_info.dev) {
 
 		pr_debug("%s: Starting hsic full suspend sequence\n",
 			__func__);
@@ -1363,7 +1396,7 @@
 
 			/* HSIC host will go now to lpm */
 			pr_debug("%s: vote for suspend hsic %x\n",
-				__func__, (int)hsic_host_dev);
+				__func__, (int)hsic_host_info.dev);
 
 			for (i = 0; i < ctx.max_connections; i++) {
 				pipe_iter =
@@ -1379,6 +1412,8 @@
 				}
 			}
 
+			hsic_host_info.in_lpm = true;
+
 			spin_unlock(&usb_bam_lock);
 			return true;
 		}
@@ -1392,7 +1427,7 @@
 				info.cur_cons_state[HSIC_BAM],
 				info.cur_prod_state[HSIC_BAM],
 				info.in_lpm[HSIC_BAM]);
-			pm_runtime_get(hsic_host_dev);
+			pm_runtime_get(hsic_host_info.dev);
 			info.in_lpm[HSIC_BAM] = false;
 			spin_unlock(&usb_bam_lock);
 		} else
@@ -1469,11 +1504,11 @@
 		sps_device_reset(ctx.h_bam[cur_bam]);
 
 		/* On re-connect assume out from lpm for HSIC BAM */
-		if (cur_bam == HSIC_BAM && hsic_host_dev &&
+		if (cur_bam == HSIC_BAM && hsic_host_info.dev &&
 		    info.in_lpm[HSIC_BAM]) {
 			pr_debug("%s: Getting hsic device %x\n",
-					__func__, (int)hsic_host_dev);
-			pm_runtime_get(hsic_host_dev);
+					__func__, (int)hsic_host_info.dev);
+			pm_runtime_get(hsic_host_info.dev);
 		}
 
 		/* On re-connect assume out from lpm for all BAMs */
@@ -1583,8 +1618,10 @@
 		 * until we complete releasing the hsic consumer and producer
 		 * resources against the ipa resource manager.
 		 */
+		spin_lock(&usb_bam_lock);
 		if (pipe_connect->bam_type == HSIC_BAM)
 			usb_bam_resume_hsic_host();
+		spin_unlock(&usb_bam_lock);
 
 		/* Notify about wakeup / activity of the bam */
 		if (event_info->callback)
@@ -1660,12 +1697,12 @@
 		 * If consumer is up, we will wait to the release consumer
 		 * notification.
 		 */
-		if (hsic_host_dev &&
+		if (hsic_host_info.dev &&
 		    info.cur_cons_state[HSIC_BAM] ==
 		    IPA_RM_RESOURCE_RELEASED && !info.in_lpm[HSIC_BAM]) {
 			pr_debug("%s: Putting hsic device %x\n", __func__,
-			(int)hsic_host_dev);
-			pm_runtime_put(hsic_host_dev);
+			(int)hsic_host_info.dev);
+			pm_runtime_put(hsic_host_info.dev);
 			info.in_lpm[HSIC_BAM] = true;
 		}
 
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 0883312..7f77b75 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -102,6 +102,7 @@
 #define BAT_IF_BTC_CTRL				0x49
 #define USB_OCP_THR				0x52
 #define USB_OCP_CLR				0x53
+#define BAT_IF_TEMP_STATUS			0x09
 
 #define REG_OFFSET_PERP_SUBTYPE			0x05
 
@@ -1442,7 +1443,7 @@
 get_prop_batt_status(struct qpnp_chg_chip *chip)
 {
 	int rc;
-	u8 chgr_sts;
+	u8 chgr_sts, bat_if_sts;
 
 	if ((qpnp_chg_is_usb_chg_plugged_in(chip) ||
 		qpnp_chg_is_dc_chg_plugged_in(chip)) && chip->chg_done) {
@@ -1455,9 +1456,15 @@
 		return POWER_SUPPLY_CHARGE_TYPE_NONE;
 	}
 
-	if (chgr_sts & TRKL_CHG_ON_IRQ)
+	rc = qpnp_chg_read(chip, &bat_if_sts, INT_RT_STS(chip->bat_if_base), 1);
+	if (rc) {
+		pr_err("failed to read bat_if sts %d\n", rc);
+		return POWER_SUPPLY_CHARGE_TYPE_NONE;
+	}
+
+	if (chgr_sts & TRKL_CHG_ON_IRQ && bat_if_sts & BAT_FET_ON_IRQ)
 		return POWER_SUPPLY_STATUS_CHARGING;
-	if (chgr_sts & FAST_CHG_ON_IRQ)
+	if (chgr_sts & FAST_CHG_ON_IRQ && bat_if_sts & BAT_FET_ON_IRQ)
 		return POWER_SUPPLY_STATUS_CHARGING;
 
 	return POWER_SUPPLY_STATUS_DISCHARGING;
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index 43d17c2..b46bbaf 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -25,6 +25,14 @@
 	tristate "Android log driver"
 	default n
 
+config LOGCAT_SIZE
+	int "Adjust android log buffer sizes"
+	default 256
+	depends on ANDROID_LOGGER
+	help
+	  Set logger buffer size. Enter a number greater than zero.
+	  Any value less than 256 is recommended. Reduce value to save kernel static memory size.
+
 config ANDROID_PERSISTENT_RAM
 	bool
 	depends on HAVE_MEMBLOCK
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
index e1e886c..267a8ec 100644
--- a/drivers/staging/android/logger.c
+++ b/drivers/staging/android/logger.c
@@ -29,6 +29,10 @@
 
 #include <asm/ioctls.h>
 
+#ifndef CONFIG_LOGCAT_SIZE
+#define CONFIG_LOGCAT_SIZE 256
+#endif
+
 /*
  * struct logger_log - represents a specific log, such as 'main' or 'radio'
  *
@@ -728,10 +732,10 @@
 	.size = SIZE, \
 };
 
-DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 64*1024)
-DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 64*1024)
-DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 64*1024)
-DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, 64*1024)
+DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, CONFIG_LOGCAT_SIZE*1024)
+DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, CONFIG_LOGCAT_SIZE*1024)
+DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, CONFIG_LOGCAT_SIZE*1024)
+DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, CONFIG_LOGCAT_SIZE*1024)
 
 static struct logger_log *get_log_from_minor(int minor)
 {
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 974cadc..8c3b291 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -37,7 +37,8 @@
 #define MAX_RAILS 5
 
 static struct msm_thermal_data msm_thermal_info;
-static uint32_t limited_max_freq = MSM_CPUFREQ_NO_LIMIT;
+static uint32_t limited_max_freq = UINT_MAX;
+static uint32_t limited_min_freq;
 static struct delayed_work check_temp_work;
 static bool core_control_enabled;
 static uint32_t cpus_offlined;
@@ -139,6 +140,25 @@
 
 #define PSM_REG_MODE_FROM_ATTRIBS(attr) \
 	(container_of(attr, struct psm_rail, mode_attr));
+
+static int  msm_thermal_cpufreq_callback(struct notifier_block *nfb,
+		unsigned long event, void *data)
+{
+	struct cpufreq_policy *policy = data;
+
+	switch (event) {
+	case CPUFREQ_INCOMPATIBLE:
+		cpufreq_verify_within_limits(policy, limited_min_freq,
+				limited_max_freq);
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block msm_thermal_cpufreq_notifier = {
+	.notifier_call = msm_thermal_cpufreq_callback,
+};
+
 /* If freq table exists, then we can send freq request */
 static int check_freq_table(void)
 {
@@ -159,37 +179,26 @@
 {
 	int cpu = 0;
 	int ret = 0;
-	struct cpufreq_policy *policy = NULL;
 
 	if (!freq_table_get) {
 		ret = check_freq_table();
 		if (ret) {
-			pr_err("%s:Fail to get freq table\n", __func__);
+			pr_err("%s:Fail to get freq table\n", KBUILD_MODNAME);
 			return ret;
 		}
 	}
 	/* If min is larger than allowed max */
-	if (min != MSM_CPUFREQ_NO_LIMIT &&
-			min > table[limit_idx_high].frequency)
-		min = table[limit_idx_high].frequency;
+	min = min(min, table[limit_idx_high].frequency);
 
-	for_each_possible_cpu(cpu) {
-		ret = msm_cpufreq_set_freq_limits(cpu, min, limited_max_freq);
-		if (ret) {
-			pr_err("%s:Fail to set limits for cpu%d\n",
-					__func__, cpu);
-			return ret;
-		}
+	limited_min_freq = min;
 
-		if (cpu_online(cpu)) {
-			policy = cpufreq_cpu_get(cpu);
-			if (!policy)
-				continue;
-			cpufreq_driver_target(policy, policy->cur,
-					CPUFREQ_RELATION_L);
-			cpufreq_cpu_put(policy);
-		}
+	get_online_cpus();
+	for_each_online_cpu(cpu) {
+		if (cpufreq_update_policy(cpu))
+			pr_info("%s: Unable to update policy for cpu:%d\n",
+				KBUILD_MODNAME, cpu);
 	}
+	put_online_cpus();
 
 	return ret;
 }
@@ -584,26 +593,19 @@
 {
 	int ret = 0;
 
-	ret = msm_cpufreq_set_freq_limits(cpu, MSM_CPUFREQ_NO_LIMIT, max_freq);
-	if (ret)
-		return ret;
-
-	limited_max_freq = max_freq;
-	if (max_freq != MSM_CPUFREQ_NO_LIMIT)
+	if (max_freq != UINT_MAX)
 		pr_info("%s: Limiting cpu%d max frequency to %d\n",
 				KBUILD_MODNAME, cpu, max_freq);
 	else
 		pr_info("%s: Max frequency reset for cpu%d\n",
 				KBUILD_MODNAME, cpu);
-
-	if (cpu_online(cpu)) {
-		struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
-		if (!policy)
-			return ret;
-		ret = cpufreq_driver_target(policy, policy->cur,
-				CPUFREQ_RELATION_H);
-		cpufreq_cpu_put(policy);
+	get_online_cpus();
+	for_each_online_cpu(cpu) {
+		if (cpufreq_update_policy(cpu))
+			pr_info("%s: Unable to update policy for cpu:%d\n",
+				KBUILD_MODNAME, cpu);
 	}
+	put_online_cpus();
 
 	return ret;
 }
@@ -764,7 +766,6 @@
 
 static void __ref do_freq_control(long temp)
 {
-	int ret = 0;
 	int cpu = 0;
 	uint32_t max_freq = limited_max_freq;
 
@@ -784,7 +785,7 @@
 		limit_idx += msm_thermal_info.freq_step;
 		if (limit_idx >= limit_idx_high) {
 			limit_idx = limit_idx_high;
-			max_freq = MSM_CPUFREQ_NO_LIMIT;
+			max_freq = UINT_MAX;
 		} else
 			max_freq = table[limit_idx].frequency;
 	}
@@ -792,17 +793,13 @@
 	if (max_freq == limited_max_freq)
 		return;
 
+	limited_max_freq = max_freq;
 	/* Update new limits */
 	for_each_possible_cpu(cpu) {
 		if (!(msm_thermal_info.freq_control_mask & BIT(cpu)))
 			continue;
-		ret = update_cpu_max_freq(cpu, max_freq);
-		if (ret)
-			pr_debug(
-			"%s: Unable to limit cpu%d max freq to %d\n",
-					KBUILD_MODNAME, cpu, max_freq);
+		update_cpu_max_freq(cpu, max_freq);
 	}
-
 }
 
 static void __ref check_temp(struct work_struct *work)
@@ -909,12 +906,17 @@
 	cancel_delayed_work(&check_temp_work);
 	flush_scheduled_work();
 
-	if (limited_max_freq == MSM_CPUFREQ_NO_LIMIT)
+	if (limited_max_freq == UINT_MAX)
 		return;
 
-	for_each_possible_cpu(cpu) {
-		update_cpu_max_freq(cpu, MSM_CPUFREQ_NO_LIMIT);
+	limited_max_freq = UINT_MAX;
+	get_online_cpus();
+	for_each_online_cpu(cpu) {
+		if (cpufreq_update_policy(cpu))
+			pr_info("%s: Unable to update policy for cpu:%d\n",
+				KBUILD_MODNAME, cpu);
 	}
+	put_online_cpus();
 }
 
 static int __ref set_enabled(const char *val, const struct kernel_param *kp)
@@ -926,7 +928,7 @@
 		disable_msm_thermal();
 	else
 		pr_info("%s: no action for enabled = %d\n",
-				KBUILD_MODNAME, enabled);
+			KBUILD_MODNAME, enabled);
 
 	pr_info("%s: enabled = %d\n", KBUILD_MODNAME, enabled);
 
@@ -1190,6 +1192,11 @@
 		return -EINVAL;
 
 	enabled = 1;
+	ret = cpufreq_register_notifier(&msm_thermal_cpufreq_notifier,
+			CPUFREQ_POLICY_NOTIFIER);
+	if (ret)
+		pr_err("%s: cannot register cpufreq notifier\n",
+			KBUILD_MODNAME);
 	if (num_possible_cpus() > 1)
 		core_control_enabled = 1;
 	INIT_DELAYED_WORK(&check_temp_work, check_temp);
@@ -1505,7 +1512,7 @@
 		key = "qcom,freq-req";
 		rails[i].freq_req = of_property_read_bool(child_node, key);
 		if (rails[i].freq_req)
-			rails[i].min_level = MSM_CPUFREQ_NO_LIMIT;
+			rails[i].min_level = 0;
 		else {
 			key = "qcom,min-level";
 			ret = of_property_read_u32(child_node, key,
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index d1b911a..bccc504 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -626,6 +626,7 @@
 		struct usb_function *f)
 {
 	struct diag_context *ctxt = func_to_diag(f);
+	unsigned long flags;
 
 	if (gadget_is_superspeed(c->cdev->gadget))
 		usb_free_descriptors(f->ss_descriptors);
@@ -643,7 +644,9 @@
 		ctxt->ch->priv_usb = NULL;
 	list_del(&ctxt->list_item);
 	/* Free any pending USB requests from last session */
+	spin_lock_irqsave(&ctxt->lock, flags);
 	free_reqs(ctxt);
+	spin_unlock_irqrestore(&ctxt->lock, flags);
 	kfree(ctxt);
 }
 
diff --git a/include/linux/stk3x1x.h b/include/linux/stk3x1x.h
index 33625bd..d9d2cf6 100644
--- a/include/linux/stk3x1x.h
+++ b/include/linux/stk3x1x.h
@@ -23,6 +23,7 @@
 	uint16_t ps_thd_l;
 	int int_pin;
 	uint32_t transmittance;
+	uint32_t int_flags;
 };
 
 #endif /* __STK3X1X_H__ */
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index 419e055..d28a8c0 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -627,7 +627,9 @@
 	FM_TRANS,
 	FM_RESET,
 	FM_CALIB,
-	FM_TURNING_OFF
+	FM_TURNING_OFF,
+	FM_RECV_TURNING_ON,
+	FM_TRANS_TURNING_ON,
 };
 
 enum emphasis_type {
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 0be6f11..b1dd350 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -266,6 +266,12 @@
 quiet_cmd_dtc = DTC     $@
 cmd_dtc = $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 $(DTC_FLAGS) -d $(depfile) $<
 
+# cat
+# ---------------------------------------------------------------------------
+# Concatentate multiple files together
+quiet_cmd_cat = CAT     $@
+cmd_cat = (cat $(filter-out FORCE,$^) > $@) || (rm -f $@; false)
+
 # Bzip2
 # ---------------------------------------------------------------------------
 
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 46b0a91..8844b21 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -1157,6 +1157,16 @@
 	"ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3"
 };
 
+/*
+  * There is only one bit to select RX2 (0) or RX3 (1) so add 'ZERO' won't
+  * cause any issue to select the right input, but it eliminates that lineout
+  * is powered-up when HPH is enabled if the 'ZERO" is used in the disable
+  * sequence for lineout.
+  */
+static const char * const rx_rdac4_text[] = {
+	"ZERO", "RX3", "RX2"
+};
+
 static const struct soc_enum rx_mix1_inp1_chain_enum =
 	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL, 0, 6, rx_mix1_text);
 
@@ -1194,6 +1204,10 @@
 	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_EQ1_B1_CTL, 0, 6,
 	iir1_inp1_text);
 
+static const struct soc_enum rx_rdac4_enum  =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_LO_DAC_CTL, 0, 3,
+	rx_rdac4_text);
+
 static const struct snd_kcontrol_new rx_mix1_inp1_mux =
 	SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
 
@@ -1221,6 +1235,9 @@
 static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
 	SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
 
+static const struct snd_kcontrol_new rx_dac4_mux =
+	SOC_DAPM_ENUM("RDAC4 MUX Mux", rx_rdac4_enum);
+
 static int msm8x10_wcd_put_dec_enum(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
@@ -1312,6 +1329,10 @@
 	SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
 };
 
+static const struct snd_kcontrol_new spkr_switch[] = {
+	SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_SPKR_DRV_DAC_CTL, 2, 1, 0)
+};
+
 static void msm8x10_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
 					 int enable)
 {
@@ -1791,13 +1812,6 @@
 	return 0;
 }
 
-static int msm8x10_wcd_spk_dac_event(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	dev_dbg(w->codec->dev, "%s %s %d\n", __func__, w->name, event);
-	return 0;
-}
-
 static const struct snd_soc_dapm_route audio_map[] = {
 	{"RX_I2S_CLK", NULL, "CDC_CONN"},
 	{"I2S RX1", NULL, "RX_I2S_CLK"},
@@ -1837,11 +1851,15 @@
 
 	{"LINEOUT PA", NULL, "CP"},
 	{"LINEOUT PA", NULL, "LINEOUT DAC"},
+	{"LINEOUT DAC", NULL, "RDAC4 MUX"},
+
+	{"RDAC4 MUX", "RX2", "RX2 CHAIN"},
+	{"RDAC4 MUX", "RX3", "RX3 CHAIN"},
 
 	{"CP", NULL, "CP_REGULATOR"},
 	{"CP", NULL, "RX_BIAS"},
 	{"SPK PA", NULL, "SPK DAC"},
-	{"SPK DAC", NULL, "RX3 CHAIN"},
+	{"SPK DAC", "Switch", "RX3 CHAIN"},
 
 	{"RX1 CHAIN", NULL, "RX1 CLK"},
 	{"RX2 CHAIN", NULL, "RX2 CLK"},
@@ -2270,6 +2288,9 @@
 		msm8x10_wcd_hphr_dac_event,
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
+	SND_SOC_DAPM_MIXER("SPK DAC", SND_SOC_NOPM, 0, 0,
+		spkr_switch, ARRAY_SIZE(spkr_switch)),
+
 	/* Speaker */
 	SND_SOC_DAPM_OUTPUT("LINEOUT"),
 	SND_SOC_DAPM_OUTPUT("SPK_OUT"),
@@ -2289,10 +2310,6 @@
 		msm8x10_wcd_lineout_dac_event,
 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_DAC_E("SPK DAC", NULL, SND_SOC_NOPM, 0, 0,
-			   msm8x10_wcd_spk_dac_event,
-			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
 	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),
 
@@ -2340,6 +2357,8 @@
 		&rx1_mix2_inp1_mux),
 	SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
 		&rx2_mix2_inp1_mux),
+	SND_SOC_DAPM_MUX("RDAC4 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_dac4_mux),
 
 	SND_SOC_DAPM_SUPPLY("MICBIAS_REGULATOR", SND_SOC_NOPM,
 		ON_DEMAND_MICBIAS, 0,
@@ -2512,6 +2531,8 @@
 	/* config DMIC clk to CLK_MODE_1 (3.2Mhz@9.6Mhz mclk) */
 	{MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x22},
 
+	/* Disable REF_EN for MSM8X10_WCD_A_SPKR_DRV_DAC_CTL */
+	{MSM8X10_WCD_A_SPKR_DRV_DAC_CTL, 0x04, 0x00},
 };
 
 static void msm8x10_wcd_codec_init_reg(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index ff190cd..af2c53e 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -4589,7 +4589,7 @@
 					   struct wcd9xxx_mbhc *mbhc)
 {
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
-			    0x0C, 0x04);
+			    0x04, 0x04);
 	snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0xE0, 0xE0);
 }
 
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 6fc8e13..7820cd0 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -33,6 +33,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/kernel.h>
 #include <linux/gpio.h>
+#include <linux/input.h>
 #include "wcd9320.h"
 #include "wcd9306.h"
 #include "wcd9xxx-mbhc.h"
@@ -90,6 +91,22 @@
 #define WCD9XXX_MEAS_DELTA_MAX_MV 50
 #define WCD9XXX_MEAS_INVALD_RANGE_LOW_MV 20
 #define WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV 80
+
+/*
+ * Invalid voltage range for the detection
+ * of plug type with current source
+ */
+#define WCD9XXX_CS_MEAS_INVALD_RANGE_LOW_MV 110
+#define WCD9XXX_CS_MEAS_INVALD_RANGE_HIGH_MV 265
+
+/*
+ * Threshold used to detect euro headset
+ * with current source
+ */
+#define WCD9XXX_CS_GM_SWAP_THRES_MIN_MV 10
+#define WCD9XXX_CS_GM_SWAP_THRES_MAX_MV 40
+
+#define WCD9XXX_MBHC_NSC_CS 9
 #define WCD9XXX_GM_SWAP_THRES_MIN_MV 150
 #define WCD9XXX_GM_SWAP_THRES_MAX_MV 650
 #define WCD9XXX_THRESHOLD_MIC_THRESHOLD 200
@@ -101,6 +118,11 @@
 
 #define WCD9XXX_IRQ_MBHC_JACK_SWITCH_DEFAULT 28
 
+#define WCD9XXX_V_CS_HS_MAX 500
+#define WCD9XXX_V_CS_NO_MIC 5
+#define WCD9XXX_MB_MEAS_DELTA_MAX_MV 80
+#define WCD9XXX_CS_MEAS_DELTA_MAX_MV 10
+
 static bool detect_use_vddio_switch = true;
 
 struct wcd9xxx_mbhc_detect {
@@ -110,6 +132,7 @@
 	bool swap_gnd;
 	bool vddio;
 	bool hwvalue;
+	bool mic_bias;
 	/* internal purpose from here */
 	bool _above_no_mic;
 	bool _below_v_hs_max;
@@ -969,7 +992,7 @@
 }
 
 static s32 __wcd9xxx_codec_sta_dce_v(struct wcd9xxx_mbhc *mbhc, s8 dce,
-				     u16 bias_value, s16 z)
+				     u16 bias_value, s16 z, u32 micb_mv)
 {
 	s16 value, mb;
 	s32 mv;
@@ -977,10 +1000,10 @@
 	value = bias_value;
 	if (dce) {
 		mb = (mbhc->mbhc_data.dce_mb);
-		mv = (value - z) * (s32)mbhc->mbhc_data.micb_mv / (mb - z);
+		mv = (value - z) * (s32)micb_mv / (mb - z);
 	} else {
 		mb = (mbhc->mbhc_data.sta_mb);
-		mv = (value - z) * (s32)mbhc->mbhc_data.micb_mv / (mb - z);
+		mv = (value - z) * (s32)micb_mv / (mb - z);
 	}
 
 	return mv;
@@ -991,11 +1014,13 @@
 {
 	s16 z;
 	z = dce ? (s16)mbhc->mbhc_data.dce_z : (s16)mbhc->mbhc_data.sta_z;
-	return __wcd9xxx_codec_sta_dce_v(mbhc, dce, bias_value, z);
+	return __wcd9xxx_codec_sta_dce_v(mbhc, dce, bias_value, z,
+					 mbhc->mbhc_data.micb_mv);
 }
 
 /* called only from interrupt which is under codec_resource_lock acquisition */
-static short wcd9xxx_mbhc_setup_hs_polling(struct wcd9xxx_mbhc *mbhc)
+static short wcd9xxx_mbhc_setup_hs_polling(struct wcd9xxx_mbhc *mbhc,
+					   bool is_cs_enable)
 {
 	struct snd_soc_codec *codec = mbhc->codec;
 	short bias_value;
@@ -1047,7 +1072,8 @@
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
 
-	wcd9xxx_calibrate_hs_polling(mbhc);
+	if (!is_cs_enable)
+		wcd9xxx_calibrate_hs_polling(mbhc);
 
 	/* don't flip override */
 	bias_value = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true);
@@ -1143,6 +1169,158 @@
 	return status;
 }
 
+static enum wcd9xxx_mbhc_plug_type
+wcd9xxx_cs_find_plug_type(struct wcd9xxx_mbhc *mbhc,
+			  struct wcd9xxx_mbhc_detect *dt, const int size,
+			  bool highhph,
+			  unsigned long event_state)
+{
+	int i;
+	int vdce, mb_mv;
+	int ch, sz, delta_thr;
+	int minv = 0, maxv = INT_MIN;
+	struct wcd9xxx_mbhc_detect *d = dt;
+	struct wcd9xxx_mbhc_detect *dprev = d, *dmicbias = NULL, *dgnd = NULL;
+	enum wcd9xxx_mbhc_plug_type type = PLUG_TYPE_INVALID;
+
+	const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
+	    WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
+	s16 hs_max, no_mic, dce_z;
+
+	pr_debug("%s: enter\n", __func__);
+	pr_debug("%s: event_state 0x%lx\n", __func__, event_state);
+
+	sz = size - 1;
+	for (i = 0, d = dt, ch = 0; i < sz; i++, d++) {
+		if (d->mic_bias) {
+			dce_z = mbhc->mbhc_data.dce_z;
+			mb_mv = mbhc->mbhc_data.micb_mv;
+			hs_max = plug_type->v_hs_max;
+			no_mic = plug_type->v_no_mic;
+		} else {
+			dce_z = mbhc->mbhc_data.dce_nsc_cs_z;
+			mb_mv = VDDIO_MICBIAS_MV;
+			hs_max = WCD9XXX_V_CS_HS_MAX;
+			no_mic = WCD9XXX_V_CS_NO_MIC;
+		}
+
+		vdce = __wcd9xxx_codec_sta_dce_v(mbhc, true, d->dce,
+						 dce_z, (u32)mb_mv);
+
+		d->_vdces = vdce;
+		if (d->_vdces < no_mic)
+			d->_type = PLUG_TYPE_HEADPHONE;
+		else if (d->_vdces >= hs_max)
+			d->_type = PLUG_TYPE_HIGH_HPH;
+		else
+			d->_type = PLUG_TYPE_HEADSET;
+
+		pr_debug("%s: DCE #%d, %04x, V %04d(%04d), HPHL %d TYPE %d\n",
+			 __func__, i, d->dce, vdce, d->_vdces,
+			 d->hphl_status & 0x01,
+			 d->_type);
+
+		ch += d->hphl_status & 0x01;
+		if (!d->swap_gnd && !d->mic_bias) {
+			if (maxv < d->_vdces)
+				maxv = d->_vdces;
+			if (!minv || minv > d->_vdces)
+				minv = d->_vdces;
+		}
+		if ((!d->mic_bias &&
+		    (d->_vdces >= WCD9XXX_CS_MEAS_INVALD_RANGE_LOW_MV &&
+		     d->_vdces <= WCD9XXX_CS_MEAS_INVALD_RANGE_HIGH_MV)) ||
+		    (d->mic_bias &&
+		    (d->_vdces >= WCD9XXX_MEAS_INVALD_RANGE_LOW_MV &&
+		     d->_vdces <= WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV))) {
+			pr_debug("%s: within invalid range\n", __func__);
+			type = PLUG_TYPE_INVALID;
+			goto exit;
+		}
+	}
+
+	if (event_state & (1 << MBHC_EVENT_PA_HPHL)) {
+		pr_debug("%s: HPHL PA was ON\n", __func__);
+	} else if (ch != sz && ch > 0) {
+		pr_debug("%s: Invalid, inconsistent HPHL\n", __func__);
+		type = PLUG_TYPE_INVALID;
+		goto exit;
+	}
+
+	delta_thr = highhph ? WCD9XXX_MB_MEAS_DELTA_MAX_MV :
+			      WCD9XXX_CS_MEAS_DELTA_MAX_MV;
+
+	for (i = 0, d = dt; i < sz; i++, d++) {
+		if ((i > 0) && !d->mic_bias && !d->swap_gnd &&
+		    (d->_type != dprev->_type)) {
+			pr_debug("%s: Invalid, inconsistent types\n", __func__);
+			type = PLUG_TYPE_INVALID;
+			goto exit;
+		}
+
+		if (!d->swap_gnd && !d->mic_bias &&
+		    (abs(minv - d->_vdces) > delta_thr ||
+		     abs(maxv - d->_vdces) > delta_thr)) {
+			pr_debug("%s: Invalid, delta %dmv, %dmv and %dmv\n",
+				 __func__, d->_vdces, minv, maxv);
+			type = PLUG_TYPE_INVALID;
+			goto exit;
+		} else if (d->swap_gnd) {
+			dgnd = d;
+		}
+
+		if (!d->mic_bias && !d->swap_gnd)
+			dprev = d;
+		else if (d->mic_bias)
+			dmicbias = d;
+	}
+	if (dgnd && dt->_type != PLUG_TYPE_HEADSET &&
+	    dt->_type != dgnd->_type) {
+		pr_debug("%s: Invalid, inconsistent types\n", __func__);
+		type = PLUG_TYPE_INVALID;
+		goto exit;
+	}
+
+	type = dt->_type;
+	if (dmicbias) {
+		if (dmicbias->_type == PLUG_TYPE_HEADSET &&
+		    (dt->_type == PLUG_TYPE_HIGH_HPH ||
+		     dt->_type == PLUG_TYPE_HEADSET)) {
+			type = PLUG_TYPE_HEADSET;
+			if (dt->_type == PLUG_TYPE_HIGH_HPH) {
+				pr_debug("%s: Headset with threshold on MIC detected\n",
+					 __func__);
+				if (mbhc->mbhc_cfg->micbias_enable_flags &
+				 (1 << MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET))
+					mbhc->micbias_enable = true;
+			}
+		}
+	}
+
+	if (!(event_state & (1UL << MBHC_EVENT_PA_HPHL))) {
+		if (((type == PLUG_TYPE_HEADSET ||
+		      type == PLUG_TYPE_HEADPHONE) && ch != sz)) {
+			pr_debug("%s: Invalid, not fully inserted, TYPE %d\n",
+				 __func__, type);
+			type = PLUG_TYPE_INVALID;
+		}
+	}
+	if (type == PLUG_TYPE_HEADSET && dgnd && !dgnd->mic_bias) {
+		if ((dgnd->_vdces + WCD9XXX_CS_GM_SWAP_THRES_MIN_MV <
+		     minv) &&
+		    (dgnd->_vdces + WCD9XXX_CS_GM_SWAP_THRES_MAX_MV >
+		     maxv))
+			type = PLUG_TYPE_GND_MIC_SWAP;
+		else if (dgnd->_type != PLUG_TYPE_HEADSET) {
+			pr_debug("%s: Invalid, inconsistent types\n", __func__);
+			type = PLUG_TYPE_INVALID;
+		}
+	}
+exit:
+	pr_debug("%s: Plug type %d detected\n", __func__, type);
+	return type;
+}
+
 /*
  * wcd9xxx_find_plug_type : Find out and return the best plug type with given
  *			    list of wcd9xxx_mbhc_detect structure.
@@ -1328,6 +1506,112 @@
 	return 0;
 }
 
+void wcd9xxx_turn_onoff_current_source(struct wcd9xxx_mbhc *mbhc, bool on,
+				       bool highhph)
+{
+
+	struct snd_soc_codec *codec;
+	struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
+	const struct wcd9xxx_mbhc_plug_detect_cfg *plug_det =
+	    WCD9XXX_MBHC_CAL_PLUG_DET_PTR(mbhc->mbhc_cfg->calibration);
+
+	btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
+	codec = mbhc->codec;
+
+	if (on) {
+		pr_debug("%s: enabling current source\n", __func__);
+		/* Nsc to 9 */
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+				    0x78, 0x48);
+		/* pull down diode bit to 0 */
+		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
+				    0x01, 0x00);
+		/*
+		 * Keep the low power insertion/removal
+		 * detection (reg 0x3DD) disabled
+		 */
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL,
+				    0x01, 0x00);
+		/*
+		 * Enable the Mic Bias current source
+		 * Write bits[6:5] of register MICB_2_MBHC to 0x3 (V_20_UA)
+		 * Write bit[7] of register MICB_2_MBHC to 1
+		 * (INS_DET_ISRC_EN__ENABLE)
+		 * MICB_2_MBHC__SCHT_TRIG_EN to 1
+		 */
+		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
+				    0xF0, 0xF0);
+		/* Disconnect MBHC Override from MicBias and LDOH */
+		snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 0x10, 0x00);
+	} else {
+		pr_debug("%s: disabling current source\n", __func__);
+		/* Connect MBHC Override from MicBias and LDOH */
+		snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 0x10, 0x10);
+		/* INS_DET_ISRC_CTL to acdb value */
+		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
+				    0x60, plug_det->mic_current << 5);
+		if (!highhph) {
+			/* INS_DET_ISRC_EN__ENABLE to 0 */
+			snd_soc_update_bits(codec,
+					    mbhc->mbhc_bias_regs.mbhc_reg,
+					    0x80, 0x00);
+			/* MICB_2_MBHC__SCHT_TRIG_EN  to 0 */
+			snd_soc_update_bits(codec,
+					    mbhc->mbhc_bias_regs.mbhc_reg,
+					    0x10, 0x00);
+		}
+		/* Nsc to acdb value */
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78,
+				    btn_det->mbhc_nsc << 3);
+	}
+}
+
+static enum wcd9xxx_mbhc_plug_type
+wcd9xxx_codec_cs_get_plug_type(struct wcd9xxx_mbhc *mbhc, bool highhph)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct wcd9xxx_mbhc_detect rt[NUM_DCE_PLUG_INS_DETECT];
+	enum wcd9xxx_mbhc_plug_type type = PLUG_TYPE_INVALID;
+	int i;
+
+	pr_debug("%s: enter\n", __func__);
+	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
+
+	BUG_ON(NUM_DCE_PLUG_INS_DETECT < 4);
+
+	rt[0].swap_gnd = false;
+	rt[0].vddio = false;
+	rt[0].hwvalue = true;
+	rt[0].hphl_status = wcd9xxx_hphl_status(mbhc);
+	rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc, true);
+	rt[0].mic_bias = false;
+
+	for (i = 1; i < NUM_DCE_PLUG_INS_DETECT - 1; i++) {
+		rt[i].swap_gnd = (i == NUM_DCE_PLUG_INS_DETECT - 3);
+		rt[i].mic_bias = ((i == NUM_DCE_PLUG_INS_DETECT - 4) &&
+				   highhph);
+		rt[i].hphl_status = wcd9xxx_hphl_status(mbhc);
+		if (rt[i].swap_gnd)
+			wcd9xxx_codec_hphr_gnd_switch(codec, true);
+
+		if (rt[i].mic_bias)
+			wcd9xxx_turn_onoff_current_source(mbhc, false, false);
+
+		rt[i].dce = __wcd9xxx_codec_sta_dce(mbhc, 1, !highhph, true);
+		if (rt[i].mic_bias)
+			wcd9xxx_turn_onoff_current_source(mbhc, true, false);
+		if (rt[i].swap_gnd)
+			wcd9xxx_codec_hphr_gnd_switch(codec, false);
+	}
+
+	type = wcd9xxx_cs_find_plug_type(mbhc, rt, ARRAY_SIZE(rt), highhph,
+					 mbhc->event_state);
+
+	pr_debug("%s: plug_type:%d\n", __func__, type);
+
+	return type;
+}
+
 static enum wcd9xxx_mbhc_plug_type
 wcd9xxx_codec_get_plug_type(struct wcd9xxx_mbhc *mbhc, bool highhph)
 {
@@ -1364,7 +1648,7 @@
 	(void) wcd9xxx_pull_down_micbias(mbhc,
 					 WCD9XXX_MICBIAS_PULLDOWN_SETTLE_US);
 	rt[0].hphl_status = wcd9xxx_hphl_status(mbhc);
-	rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc);
+	rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc, false);
 	rt[0].swap_gnd = false;
 	rt[0].vddio = false;
 	rt[0].hwvalue = true;
@@ -1634,14 +1918,23 @@
 {
 	enum wcd9xxx_mbhc_plug_type plug_type;
 	struct snd_soc_codec *codec = mbhc->codec;
+	bool current_source_enable;
 
 	pr_debug("%s: enter\n", __func__);
 
 	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
+	current_source_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
+				  (1 << MBHC_CS_ENABLE_INSERTION)) != 0);
 
-	wcd9xxx_turn_onoff_override(codec, true);
-	plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
-	wcd9xxx_turn_onoff_override(codec, false);
+	if (current_source_enable) {
+		wcd9xxx_turn_onoff_current_source(mbhc, true, false);
+		plug_type = wcd9xxx_codec_cs_get_plug_type(mbhc, false);
+		wcd9xxx_turn_onoff_current_source(mbhc, false, false);
+	} else {
+		wcd9xxx_turn_onoff_override(codec, true);
+		plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
+		wcd9xxx_turn_onoff_override(codec, false);
+	}
 
 	if (wcd9xxx_swch_level_remove(mbhc)) {
 		pr_debug("%s: Switch level is low when determining plug\n",
@@ -1671,26 +1964,9 @@
 /* called under codec_resource_lock acquisition */
 static void wcd9xxx_mbhc_detect_plug_type(struct wcd9xxx_mbhc *mbhc)
 {
-	struct snd_soc_codec *codec = mbhc->codec;
-	const struct wcd9xxx_mbhc_plug_detect_cfg *plug_det =
-		WCD9XXX_MBHC_CAL_PLUG_DET_PTR(mbhc->mbhc_cfg->calibration);
-
 	pr_debug("%s: enter\n", __func__);
 	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
 
-	/*
-	 * Turn on the override,
-	 * wcd9xxx_mbhc_setup_hs_polling requires override on
-	 */
-	wcd9xxx_turn_onoff_override(codec, true);
-	if (plug_det->t_ins_complete > 20)
-		msleep(plug_det->t_ins_complete);
-	else
-		usleep_range(plug_det->t_ins_complete * 1000,
-			     plug_det->t_ins_complete * 1000);
-	/* Turn off the override */
-	wcd9xxx_turn_onoff_override(codec, false);
-
 	if (wcd9xxx_swch_level_remove(mbhc))
 		pr_debug("%s: Switch level low when determining plug\n",
 			 __func__);
@@ -1739,14 +2015,21 @@
 	}
 }
 
-static bool is_valid_mic_voltage(struct wcd9xxx_mbhc *mbhc, s32 mic_mv)
+static bool is_valid_mic_voltage(struct wcd9xxx_mbhc *mbhc, s32 mic_mv,
+				 bool cs_enable)
 {
 	const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
 	    WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
 	const s16 v_hs_max = wcd9xxx_get_current_v_hs_max(mbhc);
 
-	return (!(mic_mv > 10 && mic_mv < 80) && (mic_mv > plug_type->v_no_mic)
-		&& (mic_mv < v_hs_max)) ? true : false;
+	if (cs_enable)
+		return ((mic_mv > WCD9XXX_V_CS_NO_MIC) &&
+			 (mic_mv < WCD9XXX_V_CS_HS_MAX)) ? true : false;
+	else
+		return (!(mic_mv > WCD9XXX_MEAS_INVALD_RANGE_LOW_MV &&
+			  mic_mv < WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV) &&
+			(mic_mv > plug_type->v_no_mic) &&
+			(mic_mv < v_hs_max)) ? true : false;
 }
 
 /*
@@ -1761,6 +2044,13 @@
 	s32 mic_mv[NUM_DCE_PLUG_DETECT];
 	short mb_v[NUM_DCE_PLUG_DETECT];
 	unsigned long retry = 0, timeout;
+	bool cs_enable;
+
+	cs_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
+		      (1 << MBHC_CS_ENABLE_REMOVAL)) != 0);
+
+	if (cs_enable)
+		wcd9xxx_turn_onoff_current_source(mbhc, true, false);
 
 	timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
 	while (!(timedout = time_after(jiffies, timeout))) {
@@ -1780,11 +2070,28 @@
 			break;
 		}
 
-		for (i = 0; i < NUM_DCE_PLUG_DETECT; i++) {
-			mb_v[i] = wcd9xxx_codec_sta_dce(mbhc, 1,  true);
-			mic_mv[i] = wcd9xxx_codec_sta_dce_v(mbhc, 1 , mb_v[i]);
-			pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
-				 __func__, retry, mic_mv[i], mb_v[i]);
+		if (cs_enable) {
+			for (i = 0; i < NUM_DCE_PLUG_DETECT; i++) {
+				mb_v[i] = __wcd9xxx_codec_sta_dce(mbhc, 1,
+								  true, true);
+				mic_mv[i] = __wcd9xxx_codec_sta_dce_v(mbhc,
+								      true,
+								      mb_v[i],
+						mbhc->mbhc_data.dce_nsc_cs_z,
+						(u32)VDDIO_MICBIAS_MV);
+				pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
+					 __func__, retry, mic_mv[i], mb_v[i]);
+			}
+		} else {
+			for (i = 0; i < NUM_DCE_PLUG_DETECT; i++) {
+				mb_v[i] = wcd9xxx_codec_sta_dce(mbhc, 1,
+								true);
+				mic_mv[i] = wcd9xxx_codec_sta_dce_v(mbhc, 1,
+								mb_v[i]);
+				pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
+					 __func__, retry, mic_mv[i],
+								mb_v[i]);
+			}
 		}
 
 		if (wcd9xxx_swch_level_remove(mbhc)) {
@@ -1799,7 +2106,7 @@
 		}
 
 		for (i = 0; i < NUM_DCE_PLUG_DETECT; i++)
-			if (!is_valid_mic_voltage(mbhc, mic_mv[i]))
+			if (!is_valid_mic_voltage(mbhc, mic_mv[i], cs_enable))
 				break;
 
 		if (i == NUM_DCE_PLUG_DETECT) {
@@ -1810,6 +2117,9 @@
 		}
 	}
 
+	if (cs_enable)
+		wcd9xxx_turn_onoff_current_source(mbhc, false, false);
+
 	if (timedout)
 		pr_debug("%s: Microphone did not settle in %d seconds\n",
 			 __func__, HS_DETECT_PLUG_TIME_MS);
@@ -1828,12 +2138,15 @@
 /* called only from interrupt which is under codec_resource_lock acquisition */
 static void wcd9xxx_hs_remove_irq_noswch(struct wcd9xxx_mbhc *mbhc)
 {
-	s16 dce;
+	s16 dce, dcez;
 	unsigned long timeout;
 	bool removed = true;
 	struct snd_soc_codec *codec = mbhc->codec;
 	const struct wcd9xxx_mbhc_general_cfg *generic =
 		WCD9XXX_MBHC_CAL_GENERAL_PTR(mbhc->mbhc_cfg->calibration);
+	bool cs_enable;
+	s16 cur_v_ins_h;
+	u32 mb_mv;
 
 	pr_debug("%s: enter\n", __func__);
 	if (mbhc->current_plug != PLUG_TYPE_HEADSET) {
@@ -1847,13 +2160,32 @@
 	usleep_range(generic->t_shutdown_plug_rem,
 		     generic->t_shutdown_plug_rem);
 
+	cs_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
+		      (1 << MBHC_CS_ENABLE_REMOVAL)) != 0);
+	if (cs_enable)
+		wcd9xxx_turn_onoff_current_source(mbhc, true, false);
+
 	timeout = jiffies + msecs_to_jiffies(FAKE_REMOVAL_MIN_PERIOD_MS);
 	do {
-		dce = wcd9xxx_codec_sta_dce(mbhc, 1,  true);
+		if (cs_enable) {
+			dce = __wcd9xxx_codec_sta_dce(mbhc, 1,  true, true);
+			dcez = mbhc->mbhc_data.dce_nsc_cs_z;
+			mb_mv = VDDIO_MICBIAS_MV;
+		} else {
+			dce = wcd9xxx_codec_sta_dce(mbhc, 1,  true);
+			dcez = mbhc->mbhc_data.dce_z;
+			mb_mv = mbhc->mbhc_data.micb_mv;
+		}
+
 		pr_debug("%s: DCE 0x%x,%d\n", __func__, dce,
-			 wcd9xxx_codec_sta_dce_v(mbhc, 1, dce));
-		if (dce <
-		    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H)) {
+			  __wcd9xxx_codec_sta_dce_v(mbhc, true, dce,
+						    dcez, mb_mv));
+
+		cur_v_ins_h = cs_enable ? (s16) mbhc->mbhc_data.v_cs_ins_h :
+					  (wcd9xxx_get_current_v(mbhc,
+					   WCD9XXX_CURRENT_V_INS_H));
+
+		if (dce < cur_v_ins_h) {
 			removed = false;
 			break;
 		}
@@ -1861,6 +2193,9 @@
 	pr_debug("%s: headset %sactually removed\n", __func__,
 		  removed ? "" : "not ");
 
+	if (cs_enable)
+		wcd9xxx_turn_onoff_current_source(mbhc, false, false);
+
 	if (removed) {
 		if (mbhc->mbhc_cfg->detect_extn_cable) {
 			if (!wcd9xxx_swch_level_remove(mbhc)) {
@@ -2069,22 +2404,29 @@
 }
 
 static u16 wcd9xxx_codec_v_sta_dce(struct wcd9xxx_mbhc *mbhc,
-				   enum meas_type dce, s16 vin_mv)
+				   enum meas_type dce, s16 vin_mv,
+				   bool cs_enable)
 {
 	s16 diff, zero;
 	u32 mb_mv, in;
 	u16 value;
+	s16 dce_z;
 
 	mb_mv = mbhc->mbhc_data.micb_mv;
+	dce_z = mbhc->mbhc_data.dce_z;
 
 	if (mb_mv == 0) {
 		pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
 		return -EINVAL;
 	}
+	if (cs_enable) {
+		mb_mv = VDDIO_MICBIAS_MV;
+		dce_z = mbhc->mbhc_data.dce_nsc_cs_z;
+	}
 
 	if (dce) {
-		diff = (mbhc->mbhc_data.dce_mb) - (mbhc->mbhc_data.dce_z);
-		zero = (mbhc->mbhc_data.dce_z);
+		diff = (mbhc->mbhc_data.dce_mb) - (dce_z);
+		zero = (dce_z);
 	} else {
 		diff = (mbhc->mbhc_data.sta_mb) - (mbhc->mbhc_data.sta_z);
 		zero = (mbhc->mbhc_data.sta_z);
@@ -2111,9 +2453,9 @@
 	plug_type = WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
 
 	mbhc->mbhc_data.v_ins_hu[MBHC_V_IDX_CFILT] =
-	    wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_hs_max);
+	    wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_hs_max, false);
 	mbhc->mbhc_data.v_ins_h[MBHC_V_IDX_CFILT] =
-	    wcd9xxx_codec_v_sta_dce(mbhc, DCE, plug_type->v_hs_max);
+	    wcd9xxx_codec_v_sta_dce(mbhc, DCE, plug_type->v_hs_max, false);
 
 	mbhc->mbhc_data.v_inval_ins_low = FAKE_INS_LOW;
 	mbhc->mbhc_data.v_inval_ins_high = FAKE_INS_HIGH;
@@ -2122,9 +2464,9 @@
 		adj_v_hs_max = scale_v_micb_vddio(mbhc, plug_type->v_hs_max,
 						  true);
 		mbhc->mbhc_data.v_ins_hu[MBHC_V_IDX_VDDIO] =
-		    wcd9xxx_codec_v_sta_dce(mbhc, STA, adj_v_hs_max);
+		    wcd9xxx_codec_v_sta_dce(mbhc, STA, adj_v_hs_max, false);
 		mbhc->mbhc_data.v_ins_h[MBHC_V_IDX_VDDIO] =
-		    wcd9xxx_codec_v_sta_dce(mbhc, DCE, adj_v_hs_max);
+		    wcd9xxx_codec_v_sta_dce(mbhc, DCE, adj_v_hs_max, false);
 		mbhc->mbhc_data.v_inval_ins_low =
 		    scale_v_micb_vddio(mbhc, mbhc->mbhc_data.v_inval_ins_low,
 				       false);
@@ -2132,6 +2474,11 @@
 		    scale_v_micb_vddio(mbhc, mbhc->mbhc_data.v_inval_ins_high,
 				       false);
 	}
+	mbhc->mbhc_data.v_cs_ins_h = wcd9xxx_codec_v_sta_dce(mbhc, DCE,
+							WCD9XXX_V_CS_HS_MAX,
+							true);
+	pr_debug("%s: v_ins_h for current source: 0x%x\n", __func__,
+		  mbhc->mbhc_data.v_cs_ins_h);
 
 	btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_det,
 					       MBHC_BTN_DET_V_BTN_HIGH);
@@ -2146,13 +2493,17 @@
 	    scale_v_micb_vddio(mbhc, btn_mv_dce[MBHC_V_IDX_CFILT], true);
 
 	mbhc->mbhc_data.v_b1_hu[MBHC_V_IDX_CFILT] =
-	    wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_CFILT]);
+	    wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_CFILT],
+				    false);
 	mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_CFILT] =
-	    wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_CFILT]);
+	    wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_CFILT],
+				    false);
 	mbhc->mbhc_data.v_b1_hu[MBHC_V_IDX_VDDIO] =
-	    wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_VDDIO]);
+	    wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_VDDIO],
+				    false);
 	mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_VDDIO] =
-	    wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_VDDIO]);
+	    wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_VDDIO],
+				    false);
 
 	mbhc->mbhc_data.v_brh[MBHC_V_IDX_CFILT] =
 	    mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_CFILT];
@@ -2162,7 +2513,7 @@
 	mbhc->mbhc_data.v_brl = BUTTON_MIN;
 
 	mbhc->mbhc_data.v_no_mic =
-	    wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_no_mic);
+	    wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_no_mic, false);
 	pr_debug("%s: leave\n", __func__);
 }
 
@@ -2176,6 +2527,16 @@
 	 mbhc->mbhc_cfg->mclk_cb_fn(mbhc->codec, on, false);
 }
 
+/*
+ * Mic Bias Enable Decision
+ * Return true if high_hph_cnt is a power of 2 (!= 2)
+ * otherwise return false
+ */
+static bool wcd9xxx_mbhc_enable_mb_decision(int high_hph_cnt)
+{
+	return (high_hph_cnt > 2) && !(high_hph_cnt & (high_hph_cnt - 1));
+}
+
 static void wcd9xxx_correct_swch_plug(struct work_struct *work)
 {
 	struct wcd9xxx_mbhc *mbhc;
@@ -2183,13 +2544,17 @@
 	enum wcd9xxx_mbhc_plug_type plug_type = PLUG_TYPE_INVALID;
 	unsigned long timeout;
 	int retry = 0, pt_gnd_mic_swap_cnt = 0;
+	int highhph_cnt = 0;
 	bool correction = false;
-	bool wrk_complete = true;
+	bool current_source_enable;
+	bool wrk_complete = true, highhph = false;
 
 	pr_debug("%s: enter\n", __func__);
 
 	mbhc = container_of(work, struct wcd9xxx_mbhc, correct_plug_swch);
 	codec = mbhc->codec;
+	current_source_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
+				  (1 << MBHC_CS_ENABLE_POLLING)) != 0);
 
 	wcd9xxx_onoff_ext_mclk(mbhc, true);
 
@@ -2203,7 +2568,11 @@
 	 * DAPM doesn't use any MBHC block as this work only runs with
 	 * headphone detection.
 	 */
-	wcd9xxx_turn_onoff_override(codec, true);
+	if (current_source_enable)
+		wcd9xxx_turn_onoff_current_source(mbhc, true,
+						  false);
+	else
+		wcd9xxx_turn_onoff_override(codec, true);
 
 	timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
 	while (!time_after(jiffies, timeout)) {
@@ -2224,11 +2593,20 @@
 
 		/* can race with removal interrupt */
 		WCD9XXX_BCL_LOCK(mbhc->resmgr);
-		plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
+		if (current_source_enable)
+			plug_type = wcd9xxx_codec_cs_get_plug_type(mbhc,
+								   highhph);
+		else
+			plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
 		WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
 
 		pr_debug("%s: attempt(%d) current_plug(%d) new_plug(%d)\n",
 			 __func__, retry, mbhc->current_plug, plug_type);
+
+		highhph_cnt = (plug_type == PLUG_TYPE_HIGH_HPH) ?
+					(highhph_cnt + 1) :
+					0;
+		highhph = wcd9xxx_mbhc_enable_mb_decision(highhph_cnt);
 		if (plug_type == PLUG_TYPE_INVALID) {
 			pr_debug("Invalid plug in attempt # %d\n", retry);
 			if (!mbhc->mbhc_cfg->detect_extn_cable &&
@@ -2274,8 +2652,12 @@
 				pt_gnd_mic_swap_cnt = 0;
 
 			WCD9XXX_BCL_LOCK(mbhc->resmgr);
-			/* Turn off override */
-			wcd9xxx_turn_onoff_override(codec, false);
+			/* Turn off override/current source */
+			if (current_source_enable)
+				wcd9xxx_turn_onoff_current_source(mbhc, false,
+								  false);
+			else
+				wcd9xxx_turn_onoff_override(codec, false);
 			/*
 			 * The valid plug also includes PLUG_TYPE_GND_MIC_SWAP
 			 */
@@ -2288,15 +2670,19 @@
 		}
 	}
 
-	if (plug_type == PLUG_TYPE_HIGH_HPH) {
+	highhph = false;
+	if (wrk_complete && plug_type == PLUG_TYPE_HIGH_HPH) {
 		pr_debug("%s: polling is done, still HPH, so enabling MIC trigger\n",
 			 __func__);
 		WCD9XXX_BCL_LOCK(mbhc->resmgr);
 		wcd9xxx_find_plug_and_report(mbhc, plug_type);
+		highhph = true;
 		WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
 	}
-	/* Turn off override */
-	if (!correction)
+
+	if (!correction && current_source_enable)
+		wcd9xxx_turn_onoff_current_source(mbhc, false, highhph);
+	else if (!correction)
 		wcd9xxx_turn_onoff_override(codec, false);
 
 	wcd9xxx_onoff_ext_mclk(mbhc, false);
@@ -2565,11 +2951,11 @@
 	pr_debug("%s: reprogram vb1hu/vbrh to %dmv\n", __func__, mv);
 
 	/* update LSB first so mbhc hardware block doesn't see too low value */
-	v_b1_hu = wcd9xxx_codec_v_sta_dce(mbhc, STA, mv);
+	v_b1_hu = wcd9xxx_codec_v_sta_dce(mbhc, STA, mv, false);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu & 0xFF);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
 		      (v_b1_hu >> 8) & 0xFF);
-	v_brh = wcd9xxx_codec_v_sta_dce(mbhc, DCE, mv);
+	v_brh = wcd9xxx_codec_v_sta_dce(mbhc, DCE, mv, false);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh & 0xFF);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
 		      (v_brh >> 8) & 0xFF);
@@ -2641,14 +3027,15 @@
 			pr_debug("%s: Button is released without resume",
 				 __func__);
 			wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
-			stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z);
+			stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z,
+						mbhc->mbhc_data.micb_mv);
 			if (vddio)
 				stamv_s = scale_v_micb_vddio(mbhc, stamv,
 							     false);
 			else
 				stamv_s = stamv;
 			mv[0] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[0],
-							  dce_z);
+					  dce_z, mbhc->mbhc_data.micb_mv);
 			mv_s[0] = vddio ? scale_v_micb_vddio(mbhc, mv[0],
 							     false) : mv[0];
 			btn = wcd9xxx_determine_button(mbhc, mv_s[0]);
@@ -2664,7 +3051,8 @@
 
 	wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
 
-	stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z);
+	stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z,
+					  mbhc->mbhc_data.micb_mv);
 	if (vddio)
 		stamv_s = scale_v_micb_vddio(mbhc, stamv, false);
 	else
@@ -2673,7 +3061,8 @@
 		 sta & 0xFFFF, stamv, stamv_s);
 
 	/* determine pressed button */
-	mv[0] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[0], dce_z);
+	mv[0] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[0], dce_z,
+					  mbhc->mbhc_data.micb_mv);
 	mv_s[0] = vddio ? scale_v_micb_vddio(mbhc, mv[0], false) : mv[0];
 	btnmeas[0] = wcd9xxx_determine_button(mbhc, mv_s[0]);
 	pr_debug("%s: Meas HW - DCE 0x%x,%d,%d button %d\n", __func__,
@@ -2682,7 +3071,8 @@
 		btn = btnmeas[0];
 	for (meas = 1; (n_btn_meas && d->n_btn_meas &&
 			(meas < (d->n_btn_meas + 1))); meas++) {
-		mv[meas] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[meas], dce_z);
+		mv[meas] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[meas], dce_z,
+						     mbhc->mbhc_data.micb_mv);
 		mv_s[meas] = vddio ? scale_v_micb_vddio(mbhc, mv[meas], false) :
 				     mv[meas];
 		btnmeas[meas] = wcd9xxx_determine_button(mbhc, mv_s[meas]);
@@ -2924,7 +3314,7 @@
 static void wcd9xxx_mbhc_cal(struct wcd9xxx_mbhc *mbhc)
 {
 	u8 cfilt_mode;
-	u16 reg0, reg1;
+	u16 reg0, reg1, reg2;
 	struct snd_soc_codec *codec = mbhc->codec;
 
 	pr_debug("%s: enter\n", __func__);
@@ -2987,10 +3377,26 @@
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
 	mbhc->mbhc_data.dce_z = __wcd9xxx_codec_sta_dce(mbhc, 1, true, false);
+
+	/* compute dce_z for current source */
+	reg2 = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL);
+	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78,
+			    WCD9XXX_MBHC_NSC_CS << 3);
+
+	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
+	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
+	mbhc->mbhc_data.dce_nsc_cs_z = __wcd9xxx_codec_sta_dce(mbhc, 1, true,
+							       false);
+	pr_debug("%s: dce_z with nsc cs: 0x%x\n", __func__,
+						 mbhc->mbhc_data.dce_nsc_cs_z);
+
+	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, reg2);
+
 	/* STA measurement for 0 voltage */
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
 	mbhc->mbhc_data.sta_z = __wcd9xxx_codec_sta_dce(mbhc, 0, true, false);
+
 	/* Restore registers */
 	snd_soc_write(codec, mbhc->mbhc_bias_regs.ctl_reg, reg0);
 	snd_soc_write(codec, WCD9XXX_A_MAD_ANA_CTRL, reg1);
@@ -4009,6 +4415,15 @@
 			return ret;
 		}
 
+		ret = snd_jack_set_key(mbhc->button_jack.jack,
+				       SND_JACK_BTN_0,
+				       KEY_MEDIA);
+		if (ret) {
+			pr_err("%s: Failed to set code for btn-0\n",
+				__func__);
+			return ret;
+		}
+
 		INIT_DELAYED_WORK(&mbhc->mbhc_firmware_dwork,
 				  wcd9xxx_mbhc_fw_read);
 		INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd9xxx_btn_lpress_fn);
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 0599ccb..88c911f 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -43,6 +43,7 @@
 /* Data used by MBHC */
 struct mbhc_internal_cal_data {
 	u16 dce_z;
+	u16 dce_nsc_cs_z;
 	u16 dce_mb;
 	u16 sta_z;
 	u16 sta_mb;
@@ -59,6 +60,7 @@
 	u16 v_no_mic;
 	s16 v_inval_ins_low;
 	s16 v_inval_ins_high;
+	u16 v_cs_ins_h;
 };
 
 enum wcd9xxx_mbhc_plug_type {
@@ -83,6 +85,12 @@
 	MBHC_MICBIAS_ENABLE_REGULAR_HEADSET,
 };
 
+enum wcd9xx_mbhc_cs_enable_bits {
+	MBHC_CS_ENABLE_POLLING,
+	MBHC_CS_ENABLE_INSERTION,
+	MBHC_CS_ENABLE_REMOVAL,
+};
+
 enum wcd9xxx_mbhc_state {
 	MBHC_STATE_NONE = -1,
 	MBHC_STATE_POTENTIAL,
@@ -210,6 +218,7 @@
 	unsigned long micbias_enable_flags;
 	/* swap_gnd_mic returns true if extern GND/MIC swap switch toggled */
 	bool (*swap_gnd_mic) (struct snd_soc_codec *);
+	unsigned long cs_enable_flags;
 };
 
 struct wcd9xxx_cfilt_mode {
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index d3ba3d5..19d717e 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -83,6 +83,9 @@
 	.micbias_enable_flags = 1 << MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET,
 	.insert_detect = true,
 	.swap_gnd_mic = NULL,
+	.cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING |
+			    1 << MBHC_CS_ENABLE_INSERTION |
+			    1 << MBHC_CS_ENABLE_REMOVAL),
 };
 
 struct msm_auxpcm_gpio {
@@ -788,7 +791,7 @@
 	S(c[1], 124);
 	S(nc, 1);
 	S(n_meas, 5);
-	S(mbhc_nsc, 11);
+	S(mbhc_nsc, 10);
 	S(n_btn_meas, 1);
 	S(n_btn_con, 2);
 	S(num_btn, WCD9XXX_MBHC_DEF_BUTTONS);
@@ -1146,6 +1149,22 @@
 		.ignore_pmdown_time = 1,
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA9,
 	},
+	{
+		.name = "VoLTE",
+		.stream_name = "VoLTE",
+		.cpu_dai_name   = "VoLTE",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_VOLTE,
+	},
 	/* Backend BT/FM DAI Links */
 	{
 		.name = LPASS_BE_INT_BT_SCO_RX,
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index b28f0f49..769b8eb 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -133,6 +133,9 @@
 	.micbias_enable_flags = 1 << MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET,
 	.insert_detect = true,
 	.swap_gnd_mic = NULL,
+	.cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING |
+			    1 << MBHC_CS_ENABLE_INSERTION |
+			    1 << MBHC_CS_ENABLE_REMOVAL),
 };
 
 struct msm_auxpcm_gpio {
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 340d3db..9150751 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -180,6 +180,39 @@
 	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 int msm_btsco_rate_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_btsco_rate  = %d", __func__, msm_btsco_rate);
+
+	ucontrol->value.integer.value[0] = msm_btsco_rate;
+	return 0;
+}
+
+static int msm_btsco_rate_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 8000:
+		msm_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	case 16000:
+		msm_btsco_rate = BTSCO_RATE_16KHZ;
+		break;
+	default:
+		msm_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	}
+
+	pr_debug("%s: msm_btsco_rate = %d\n", __func__, msm_btsco_rate);
+	return 0;
+}
+
 static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 					struct snd_pcm_hw_params *params)
 {
@@ -318,6 +351,11 @@
 	return ret;
 }
 
+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),
+};
+
 static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
 {
 
@@ -334,6 +372,11 @@
 	snd_soc_dapm_enable_pin(dapm, "Lineout amp");
 	snd_soc_dapm_sync(dapm);
 
+	ret = snd_soc_add_codec_controls(codec, msm_snd_controls,
+					 ARRAY_SIZE(msm_snd_controls));
+	if (ret < 0)
+		return ret;
+
 	ret = snd_soc_jack_new(codec, "Headset Jack",
 			SND_JACK_HEADSET, &hs_jack);
 	if (ret) {
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.h b/sound/soc/msm/qdsp6v2/audio_acdb.h
index 1685894..d9c1210 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.h
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.h
@@ -19,7 +19,6 @@
 enum {
 	RX_CAL,
 	TX_CAL,
-	AANC_TX_CAL,
 	MAX_AUDPROC_TYPES
 };
 
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
index 58ea36d..113d85f 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
@@ -223,7 +223,7 @@
 					DOLBY_PARAM_VEN_LENGTH)
 
 #define DOLBY_PARAM_INT_ENDP_LENGTH		1
-#define DOLBY_PARAM_PAYLOAD_SIZE		4
+#define DOLBY_PARAM_PAYLOAD_SIZE		3
 #define DOLBY_MAX_LENGTH_INDIVIDUAL_PARAM	329
 
 #define DOLBY_NUM_ENDP_DEPENDENT_PARAMS		1
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index df0fa6a..b1f968d 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -35,6 +35,16 @@
 #define INVALID_COPP_ID 0xFF
 #define ADM_GET_PARAMETER_LENGTH 350
 
+
+enum {
+	ADM_RX_AUDPROC_CAL,
+	ADM_TX_AUDPROC_CAL,
+	ADM_RX_AUDVOL_CAL,
+	ADM_TX_AUDVOL_CAL,
+	ADM_CUSTOM_TOP_CAL,
+	ADM_MAX_CAL_TYPES
+};
+
 struct adm_ctl {
 	void *apr;
 	atomic_t copp_id[AFE_MAX_PORTS];
@@ -48,10 +58,7 @@
 	struct acdb_cal_block mem_addr_audproc[MAX_AUDPROC_TYPES];
 	struct acdb_cal_block mem_addr_audvol[MAX_AUDPROC_TYPES];
 
-/* 0 - (MAX_AUDPROC_TYPES -1):				audproc handles */
-/* (MAX_AUDPROC_TYPES -1) - (2 * MAX_AUDPROC_TYPES -1):	audvol handles */
-/* + 1 for custom ADM topology */
-	atomic_t mem_map_cal_handles[(2 * MAX_AUDPROC_TYPES) + 1];
+	atomic_t mem_map_cal_handles[ADM_MAX_CAL_TYPES];
 	atomic_t mem_map_cal_index;
 
 	int set_custom_topology;
@@ -626,7 +633,7 @@
 
 	if (this_adm.set_custom_topology) {
 		/* specific index 4 for adm topology memory */
-		atomic_set(&this_adm.mem_map_cal_index, 4);
+		atomic_set(&this_adm.mem_map_cal_index, ADM_CUSTOM_TOP_CAL);
 
 		/* Only call this once */
 		this_adm.set_custom_topology = 0;
@@ -656,7 +663,8 @@
 	adm_top.hdr.opcode = ADM_CMD_ADD_TOPOLOGIES;
 	adm_top.payload_addr_lsw = cal_block.cal_paddr;
 	adm_top.payload_addr_msw = 0;
-	adm_top.mem_map_handle = atomic_read(&this_adm.mem_map_cal_handles[4]);
+	adm_top.mem_map_handle =
+		atomic_read(&this_adm.mem_map_cal_handles[ADM_CUSTOM_TOP_CAL]);
 	adm_top.payload_size = cal_block.cal_size;
 
 	atomic_set(&this_adm.copp_stat[index], 0);
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 1810770..6dfe5b3 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -25,6 +25,14 @@
 
 #include "audio_acdb.h"
 
+enum {
+	AFE_RX_CAL,
+	AFE_TX_CAL,
+	AFE_AANC_TX_CAL,
+	MAX_AFE_CAL_TYPES
+};
+
+
 struct afe_ctl {
 	void *apr;
 	atomic_t state;
@@ -39,8 +47,8 @@
 	void *rx_private_data;
 	uint32_t mmap_handle;
 
-	struct acdb_cal_block afe_cal_addr[MAX_AUDPROC_TYPES];
-	atomic_t mem_map_cal_handles[MAX_AUDPROC_TYPES];
+	struct acdb_cal_block afe_cal_addr[MAX_AFE_CAL_TYPES];
+	atomic_t mem_map_cal_handles[MAX_AFE_CAL_TYPES];
 	atomic_t mem_map_cal_index;
 	u16 dtmf_gen_rx_portid;
 	struct afe_spkr_prot_calib_get_resp calib_data;
@@ -94,7 +102,7 @@
 		pr_debug("q6afe: reset event = %d %d apr[%p]\n",
 			data->reset_event, data->reset_proc, this_afe.apr);
 
-		for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
+		for (i = 0; i < MAX_AFE_CAL_TYPES; i++) {
 			this_afe.afe_cal_addr[i].cal_paddr = 0;
 			this_afe.afe_cal_addr[i].cal_size = 0;
 		}
@@ -384,7 +392,7 @@
 	u32 handle;
 
 	pr_debug("%s: path %d\n", __func__, path);
-	if (path == AANC_TX_CAL) {
+	if (path == AFE_AANC_TX_CAL) {
 		get_aanc_cal(&cal_block);
 	} else {
 		get_afe_cal(path, &cal_block);
@@ -600,10 +608,10 @@
 
 	if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX) {
 		afe_send_cal_spkr_prot_tx(port_id);
-		afe_send_cal_block(TX_CAL, port_id);
+		afe_send_cal_block(AFE_TX_CAL, port_id);
 	} else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX) {
 		afe_send_cal_spkr_prot_rx(port_id);
-		afe_send_cal_block(RX_CAL, port_id);
+		afe_send_cal_block(AFE_RX_CAL, port_id);
 	}
 }
 
@@ -1149,7 +1157,7 @@
 			__func__, ret);
 		goto fail_cmd;
 	}
-	afe_send_cal_block(AANC_TX_CAL, tx_port_id);
+	afe_send_cal_block(AFE_AANC_TX_CAL, tx_port_id);
 
 fail_cmd:
 	return ret;
diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c
index c5483ee..aec048e 100644
--- a/sound/soc/msm/qdsp6v2/q6lsm.c
+++ b/sound/soc/msm/qdsp6v2/q6lsm.c
@@ -735,7 +735,7 @@
 	int rc = -EINVAL;
 
 	if (!client)
-		goto fail;
+		return rc;
 
 	mutex_lock(&client->cmd_lock);
 	if (!client->sound_model.data) {
@@ -744,7 +744,6 @@
 		if (IS_ERR_OR_NULL(client->sound_model.client)) {
 			pr_err("%s: ION create client for AUDIO failed\n",
 			       __func__);
-			mutex_unlock(&client->cmd_lock);
 			goto fail;
 		}
 		client->sound_model.handle =
@@ -753,7 +752,6 @@
 		if (IS_ERR_OR_NULL(client->sound_model.handle)) {
 			pr_err("%s: ION memory allocation for AUDIO failed\n",
 			       __func__);
-			mutex_unlock(&client->cmd_lock);
 			goto fail;
 		}
 
@@ -764,7 +762,6 @@
 		if (rc) {
 			pr_err("%s: ION get physical mem failed, rc%d\n",
 			       __func__, rc);
-			mutex_unlock(&client->cmd_lock);
 			goto fail;
 		}
 
@@ -773,7 +770,6 @@
 				   client->sound_model.handle);
 		if (IS_ERR_OR_NULL(client->sound_model.data)) {
 			pr_err("%s: ION memory mapping failed\n", __func__);
-			mutex_unlock(&client->cmd_lock);
 			goto fail;
 		}
 		memset(client->sound_model.data, 0, len);
@@ -789,11 +785,13 @@
 				      &client->sound_model.mem_map_handle);
 	if (rc < 0) {
 		pr_err("%s:CMD Memory_map_regions failed\n", __func__);
-		goto fail;
+		goto exit;
 	}
 
 	return 0;
 fail:
+	mutex_unlock(&client->cmd_lock);
+exit:
 	q6lsm_snd_model_buf_free(client);
 	return rc;
 }