Merge "usb: dwc3: gadget: Do not restart usb upon end transfer cmd timeout"
diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs
index db7aab1..b8d0a30 100644
--- a/Documentation/ABI/testing/sysfs-fs-f2fs
+++ b/Documentation/ABI/testing/sysfs-fs-f2fs
@@ -192,3 +192,14 @@
 Contact:	"Sheng Yong" <shengyong1@huawei.com>
 Description:
 		 Controls readahead inode block in readdir.
+
+What:		/sys/fs/f2fs/<disk>/extension_list
+Date:		Feburary 2018
+Contact:	"Chao Yu" <yuchao0@huawei.com>
+Description:
+		 Used to control configure extension list:
+		 - Query: cat /sys/fs/f2fs/<disk>/extension_list
+		 - Add: echo '[h/c]extension' > /sys/fs/f2fs/<disk>/extension_list
+		 - Del: echo '[h/c]!extension' > /sys/fs/f2fs/<disk>/extension_list
+		 - [h] means add/del hot file extension
+		 - [c] means add/del cold file extension
diff --git a/Documentation/device-mapper/verity.txt b/Documentation/device-mapper/verity.txt
index 89fd8f9..b3d2e4a 100644
--- a/Documentation/device-mapper/verity.txt
+++ b/Documentation/device-mapper/verity.txt
@@ -109,6 +109,17 @@
     This is the offset, in <data_block_size> blocks, from the start of the
     FEC device to the beginning of the encoding data.
 
+check_at_most_once
+    Verify data blocks only the first time they are read from the data device,
+    rather than every time.  This reduces the overhead of dm-verity so that it
+    can be used on systems that are memory and/or CPU constrained.  However, it
+    provides a reduced level of security because only offline tampering of the
+    data device's content will be detected, not online tampering.
+
+    Hash blocks are still verified each time they are read from the hash device,
+    since verification of hash blocks is less performance critical than data
+    blocks, and a hash block will not be verified any more after all the data
+    blocks it covers have been verified anyway.
 
 Theory of operation
 ===================
diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt
index bda03f0..3a96610 100644
--- a/Documentation/devicetree/bindings/arm/coresight.txt
+++ b/Documentation/devicetree/bindings/arm/coresight.txt
@@ -1,222 +1,12 @@
 * CoreSight Components:
 
 CoreSight components are compliant with the ARM CoreSight architecture
-specification and can be connected in various topologies to suite a particular
-SoCs tracing needs. These trace components can generally be classified as sinks,
-links and sources. Trace data produced by one or more sources flows through the
-intermediate links connecting the source to the currently selected sink. Each
-CoreSight component device should use these properties to describe its hardware
-characteristcs.
-
-Required properties:
-
-- compatible : name of the component used for driver matching, should be one of
-	the following:
-	"arm,coresight-tmc" for coresight tmc-etr or tmc-etf device,
-	"arm,coresight-tpiu" for coresight tpiu device,
-	"qcom,coresight-replicator" for coresight replicator device,
-	"arm,coresight-funnel" for coresight funnel devices,
-	"qcom,coresight-tpda" for coresight tpda device,
-	"qcom,coresight-tpdm" for coresight tpdm device,
-	"qcom,coresight-dbgui" for coresight dbgui device
-	"arm,coresight-stm" for coresight stm trace device,
-	"arm,coresight-etm" for coresight etm trace devices,
-	"arm,coresight-etmv4" for coresight etmv4 trace devices,
-	"qcom,coresight-csr" for coresight csr device,
-	"arm,coresight-cti" for coresight cti devices,
-	"qcom,coresight-hwevent" for coresight hardware event devices
-	"arm,coresight-fuse" for coresight fuse v1 device,
-	"arm,coresight-fuse-v2" for coresight fuse v2 device,
-	"arm,coresight-fuse-v3" for coresight fuse v3 device,
-	"qcom,coresight-remote-etm" for coresight remote processor etm trace device,
-	"qcom,coresight-qpdi" for coresight qpdi device
-- reg : physical base address and length of the register set(s) of the component.
-	Not required for the following compatible string:
-	- "qcom,coresight-remote-etm"
-- reg-names : names corresponding to each reg property value.
-	Not required for the following compatible string:
-	- "qcom,coresight-remote-etm"
-	The reg-names that need to be used with corresponding compatible string
-	for a coresight device are:
-	- for coresight tmc-etr or tmc-etf device:
-		compatible : should be "arm,coresight-tmc"
-		reg-names  : should be:
-			"tmc-base" - physical base address of tmc configuration
-				registers
-			"bam-base" - physical base address of tmc-etr bam registers
-	- for coresight tpiu device:
-		compatible : should be "arm,coresight-tpiu"
-		reg-names  : should be:
-			"tpiu-base" - physical base address of tpiu registers
-	- for coresight replicator device
-		compatible : should be "qcom,coresight-replicator"
-		reg-names  : should be:
-			"replicator-base" - physical base address of replicator
-				registers
-	- for coresight funnel devices
-		compatible : should be "arm,coresight-funnel"
-		reg-names  : should be:
-			"funnel-base" - physical base address of funnel registers
-	- for coresight tpda trace device
-		compatible : should be "qcom,coresight-tpda"
-		reg-names  : should be:
-			"tpda-base" - physical base address of tpda registers
-	- for coresight tpdm trace device
-		compatible : should be "qcom,coresight-tpdm"
-		reg-names  : should be:
-			"tpdm-base" - physical base address of tpdm registers
-	- for coresight dbgui device:
-		compatible : should be "qcom,coresight-dbgui"
-		reg-names  : should be:
-			"dbgui-base" - physical base address of dbgui registers
-	- for coresight stm trace device
-		compatible : should be "arm,coresight-stm"
-		reg-names  : should be:
-			"stm-base" - physical base address of stm configuration
-				registers
-			"stm-data-base" - physical base address of stm data registers
-	- for coresight etm trace devices
-		compatible : should be "arm,coresight-etm"
-		reg-names  : should be:
-			"etm-base" - physical base address of etm registers
-	- for coresight etmv4 trace devices
-		compatible : should be "arm,coresight-etmv4"
-		reg-names  : should be:
-			"etm-base" - physical base address of etmv4 registers
-	- for coresight csr device:
-		compatible : should be "qcom,coresight-csr"
-		reg-names  : should be:
-			"csr-base" - physical base address of csr registers
-	- for coresight cti devices:
-		compatible : should be "arm,coresight-cti"
-		reg-names  : should be:
-			"cti<num>-base" - physical base address of cti registers
-	- for coresight hardware event devices:
-		compatible : should be "qcom,coresight-hwevent"
-		reg-names  : should be:
-			"<ss-mux>" - physical base address of hardware event mux
-				control registers where <ss-mux> is subsystem mux it
-				represents
-	- for coresight fuse device:
-		compatible : should be "arm,coresight-fuse"
-		reg-names  : should be:
-			"fuse-base" - physical base address of fuse registers
-			"nidnt-fuse-base" - physical base address of nidnt fuse registers
-			"qpdi-fuse-base" - physical base address of qpdi fuse registers
-	- for coresight qpdi device:
-		compatible : should be "qcom,coresight-qpdi"
-		reg-names  : should be:
-			"qpdi-base" - physical base address of qpdi registers
-- coresight-id : unique integer identifier for the component
-- coresight-name : unique descriptive name of the component
-- coresight-nr-inports : number of input ports on the component
-
-Optional properties:
-
-- coresight-outports : list of output port numbers of this component
-- coresight-child-list : list of phandles pointing to the children of this
-			 component
-- coresight-child-ports : list of input port numbers of the children
-- coresight-default-sink : represents the default compile time CoreSight sink
-- coresight-ctis : list of ctis that this component interacts with
-- qcom,cti-save : boolean, indicating cti context needs to be saved and restored
-- qcom,cti-hwclk : boolean, indicating support of hardware clock to access cti
-		   registers to be saved and restored
-- qcom,cti-gpio-trigin : cti trigger input driven by gpio
-- qcom,cti-gpio-trigout : cti trigger output sent to gpio
-- qcom,pc-save : program counter save implemented
-- qcom,blk-size : block size for tmc-etr to usb transfers
-- qcom,memory-size : size of coherent memory to be allocated for tmc-etr buffer
-- qcom,round-robin : indicates if per core etms are allowed round-robin access
-		     by the funnel
-- qcom,write-64bit : only 64bit data writes supported by stm
-- qcom,data-barrier : barrier required for every stm data write to channel space
-- <supply-name>-supply: phandle to the regulator device tree node. The required
-			<supply-name> is "vdd" for SD card and "vdd-io" for SD
-			I/O supply. Used for tpiu component
-- qcom,<supply>-voltage-level : specifies voltage level for vdd supply. Should
-				be specified in pairs (min, max) with units
-				being uV. Here <supply> can be "vdd" for SD card
-				vdd supply or "vdd-io" for SD I/O vdd supply.
-- qcom,<supply>-current-level : specifies current load levels for vdd supply.
-				Should be specified in pairs (lpm, hpm) with
-				units being uA. Here <supply> can be "vdd" for
-				SD card vdd supply or "vdd-io" for SD I/O vdd
-				supply.
-- qcom,hwevent-clks : list of clocks required by hardware event driver
-- qcom,hwevent-regs : list of regulators required by hardware event driver
-- qcom,byte-cntr-absent : specifies if the byte counter feature is absent on
-			  the device. Only relevant in case of tmc-etr device.
-- interrupts : <a b c> where a is 0 or 1 depending on if the interrupt is
-		spi/ppi, b is the interrupt number and c is the mask,
-- interrupt-names : a list of strings that map in order to the list of
-		    interrupts specified in the 'interrupts' property.
-- qcom,sg-enable : indicates whether scatter gather feature is supported for TMC
-		   ETR configuration.
-- qcom,force-reg-dump : boolean, indicate whether TMC register need to be dumped.
-			Used for TMC component
-- qcom,nidntsw : boolean, indicating NIDnT software debug or trace support
-		 present. Used for tpiu component
-- qcom,nidnthw : boolean, indicating NIDnT hardware sensing support present.
-		 Used for tpiu component
-  qcom,nidntsw and qcom,nidnthw are mutually exclusive properties, either of
-  these may specified for tpiu component
-- qcom,nidnt-swduart : boolean, indicating NIDnT swd uart support present. Used
-		       for tpiu component
-- qcom,nidnt-swdtrc : boolean, indicating NIDnT swd trace support present. Used
-		      for tpiu component
-- qcom,nidnt-jtag : boolean, indicating NIDnT jtag debug support present. Used
-		    for tpiu component
-- qcom,nidnt-spmi : boolean, indicating NIDnT spmi debug support present. Used
-		    for tpiu component
-- nidnt-gpio : specifies gpio for NIDnT hardware detection
-- nidnt-gpio-polarity : specifies gpio polarity for NIDnT hardware detection
-- pinctrl-names : names corresponding to the numbered pinctrl. The allowed
-		  names are subset of the following: cti-trigin-pctrl,
-		  cti-trigout-pctrl. Used for cti component
-- pinctrl-<n>: list of pinctrl phandles for the different pinctrl states. Refer
-	       to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt".
-- qcom,funnel-save-restore : boolean, indicating funnel port needs to be disabled
-			     for the ETM whose CPU is being powered down. The port
-			     state is restored when CPU is powered up. Used for
-			     funnel component.
-- qcom,tmc-flush-powerdown : boolean, indicating trace data needs to be flushed before
-			     powering down CPU. Used for TMC component.
-- qcom,bc-elem-size : specifies the BC element size supported by each monitor
-		      connected to the aggregator on each port. Should be specified
-		      in pairs (port, bc element size).
-- qcom,tc-elem-size : specifies the TC element size supported by each monitor
-		      connected to the aggregator on each port. Should be specified
-		      in pairs (port, tc element size).
-- qcom,dsb-elem-size : specifies the DSB element size supported by each monitor
-		       connected to the aggregator on each port. Should be specified
-		       in pairs (port, dsb element size).
-- qcom,cmb-elem-size : specifies the CMB element size supported by each monitor
-		       connected to the aggregator on each port. Should be specified
-		       in pairs (port, cmb element size).
-- qcom,clk-enable: specifies whether additional clock bit needs to be set for
-		   M4M TPDM.
-- qcom,tpda-atid : specifies the ATID for TPDA.
-- qcom,inst-id : QMI instance id for remote ETMs.
-- qcom,noovrflw-enable : boolean, indicating whether no overflow bit needs to be
-			 set in ETM stall control register.
-- coresight-cti-cpu : cpu phandle for cpu cti, required when qcom,cti-save is true
-- coresight-etm-cpu : specifies phandle for the cpu associated with the ETM device
-- qcom,dbgui-addr-offset : indicates the offset of dbgui address registers
-- qcom,dbgui-data-offset : indicates the offset of dbgui data registers
-- qcom,dbgui-size : indicates the size of dbgui address and data registers
-- qcom,pmic-carddetect-gpio : indicates the hotplug capabilities of the qpdi driver
-- qcom,cpuss-debug-cgc: debug clock gating phandle for etm
-	reg : the clock gating register for each cluster
-	cluster : indicate the cluster number
-
-coresight-outports, coresight-child-list and coresight-child-ports lists will
-be of the same length and will have a one to one correspondence among the
-elements at the same list index.
-
-coresight-default-sink must be specified for one of the sink devices that is
-intended to be made the default sink. Other sink devices must not have this
-specified. Not specifying this property on any of the sinks is invalid.
+specification and can be connected in various topologies to suit a particular
+SoCs tracing needs. These trace components can generally be classified as
+sinks, links and sources. Trace data produced by one or more sources flows
+through the intermediate links connecting the source to the currently selected
+sink. Each CoreSight component device should use these properties to describe
+its hardware characteristcs.
 
 * Required properties for all components *except* non-configurable replicators:
 
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-workarounds.txt b/Documentation/devicetree/bindings/arm/msm/lpm-workarounds.txt
deleted file mode 100644
index 0304035..0000000
--- a/Documentation/devicetree/bindings/arm/msm/lpm-workarounds.txt
+++ /dev/null
@@ -1,55 +0,0 @@
-* LPM Workarounds
-
-The required properties are:
-
-- compatible: "qcom,lpm-workarounds"
-
-The optional properties are:
-- reg: The physical address and the size of the l1_l2_gcc and l2_pwr_sts
-	regitsters of performance cluster.
-
-- reg-names: "l2_pwr_sts" - string to identify l2_pwr_sts physical address.
-	     "l1_l2_gcc" - string to identify l1_l2_gcc physical address.
-
-- qcom,lpm-wa-cx-turbo-unvote: Indicates the workaround to unvote CX turbo
-	vote when system is coming out of rpm assisted power collaspe.
-	lpm-cx-supply is required if this is present.
-
-- lpm-cx-supply:  will hold handle for CX regulator supply which is used
-	to unvote.
-
-- qcom,lpm-wa-skip-l2-spm: Due to a hardware bug on 8939 and 8909, secure
-	world needs to disable and enable L2 SPM to get the proper context
-	in secure watchdog bite cases. With this workaround there is a race
-	in programming L2 SPM between HLOS and secure world. This leads to
-	stability issues. To avoid this program L2 SPM only in secure world
-	based on the L2 mode flag passed. Set lpm-wa-skip-l2-spm node if this
-	is required.
-
-- qcom,lpm-wa-dynamic-clock-gating: Due to a hardware bug on 8952, L1/L2 dynamic
-	clock gating needs to be enabled by software for performance cluster
-	cores and L2. Set lpm-wa-dynamic-clock-gating node if this workaround is
-	required.
-
-- qcom,cpu-offline-mask: Dynamic clock gating should be enabled when cluster is
-	in L2 PC. Each bit of cpu-offline-mask lists the cpu no. to hotplug by KTM
-	driver.
-
-- qcom,non-boot-cpu-index: will hold index of non boot cluster cpu.
-
-- qcom,l1-l2-gcc-secure: indicates L1/L2 clock enabling register is secure.
-
-Example:
-
-qcom,lpm-workarounds {
-	compatible = "qcom,lpm-workarounds";
-	reg = <0x0B011018 0x4>,
-	      <0x0B011088 0x4>;
-	reg-names = "l2-pwr-sts", "l1-l2-gcc";
-	lpm-cx-supply = <&pm8916_s2_corner>;
-	qcom,lpm-wa-cx-turbo-unvote;
-	qcom,lpm-wa-skip-l2-spm;
-	qcom,lpm-wa-dynamic-clock-gating;
-	qcom,cpu-offline-mask = "0xF";
-	qcom,non-boot-cpu-index = <4>;
-}
diff --git a/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt
index 2b7b3fa..606da38 100644
--- a/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt
+++ b/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt
@@ -1,11 +1,14 @@
-* Amlogic Meson8b Clock and Reset Unit
+* Amlogic Meson8, Meson8b and Meson8m2 Clock and Reset Unit
 
-The Amlogic Meson8b clock controller generates and supplies clock to various
-controllers within the SoC.
+The Amlogic Meson8 / Meson8b / Meson8m2 clock controller generates and
+supplies clock to various controllers within the SoC.
 
 Required Properties:
 
-- compatible: should be "amlogic,meson8b-clkc"
+- compatible: must be one of:
+	- "amlogic,meson8-clkc" for Meson8 (S802) SoCs
+	- "amlogic,meson8b-clkc" for Meson8 (S805) SoCs
+	- "amlogic,meson8m2-clkc" for Meson8m2 (S812) SoCs
 - reg: it must be composed by two tuples:
 	0) physical base address of the xtal register and length of memory
 	   mapped region.
diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
index 4f7ae75..bda9d6f 100644
--- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
+++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
@@ -47,10 +47,13 @@
   Documentation/devicetree/bindings/media/video-interfaces.txt. The
   first port should be the input endpoint, the second one the output
 
-  The output should have two endpoints. The first is the block
-  connected to the TCON channel 0 (usually a panel or a bridge), the
-  second the block connected to the TCON channel 1 (usually the TV
-  encoder)
+  The output may have multiple endpoints. The TCON has two channels,
+  usually with the first channel being used for the panels interfaces
+  (RGB, LVDS, etc.), and the second being used for the outputs that
+  require another controller (TV Encoder, HDMI, etc.). The endpoints
+  will take an extra property, allwinner,tcon-channel, to specify the
+  channel the endpoint is associated to. If that property is not
+  present, the endpoint number will be used as the channel number.
 
 On SoCs other than the A33, there is one more clock required:
    - 'tcon-ch1': The clock driving the TCON channel 1
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
index d9d3470..432c482 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
@@ -10,6 +10,7 @@
 Required properties:
 - compatible : should be "qcom,qpnp-vadc" for Voltage ADC device driver and
 		"qcom,qpnp-vadc-hc" for VADC_HC voltage ADC device driver.
+		should include "qcom,qpnp-adc-hc-pm5" for PMIC5.
 - reg : offset and length of the PMIC Aribter register map.
 - address-cells : Must be one.
 - size-cells : Must be zero.
diff --git a/Documentation/devicetree/bindings/iio/imu/invn-icm20602.txt b/Documentation/devicetree/bindings/iio/imu/invn-icm20602.txt
new file mode 100644
index 0000000..27c304e
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/imu/invn-icm20602.txt
@@ -0,0 +1,28 @@
+The ICM20602 sensor is 6-axis gyroscope+accelerometer combo
+device which is made by InvenSense Inc.
+
+Required properties:
+
+ - compatible	: Should be "invensense,icm20602".
+ - reg	: the I2C address which depends on the AD0 pin.
+ - interrupt-parent	: should be the phandle for the interrupt controller
+ - interrupts	: interrupt mapping for GPIO IRQ
+
+Optional properties:
+ - invensense,icm20602-gpio:  the irq gpio. This is not used if
+ using SMD to trigger. this is needed only if using the
+ device IRQ to trigger. Only using SMD to trigger can
+ support 8K sample rate.
+
+Example:
+	icm20602-i2c@068 {
+		compatible = "invensense,icm20602";
+		reg = <0x68>;
+		interrupt-parent = <&msm_gpio>;
+		interrupts = <13 0>;
+		invensense,icm20602-gpio = <&msm_gpio 13 0x0>;
+		pinctrl-names = "imu_active","imu_suspend";
+		pinctrl-0 = <&imu_int_active>;
+		pinctrl-1 = <&imu_int_suspend>;
+		status = "okay";
+	};
diff --git a/Documentation/devicetree/bindings/input/misc/stmvl53l0x.txt b/Documentation/devicetree/bindings/input/misc/stmvl53l0x.txt
new file mode 100644
index 0000000..bf10122
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/misc/stmvl53l0x.txt
@@ -0,0 +1,36 @@
+STM VL53L0X Time-of-Flight ranging and gesture detection sensor driver
+
+Description:
+
+The VL53L0X is a new generation Time-of-Flight
+(ToF) laser-ranging module housed in the
+smallest package on the market today, providing
+accurate distance measurement whatever the
+target reflectances unlike conventional
+technologies. It can measure absolute distances
+up to 2m, setting a new benchmark in ranging
+performance levels, opening the door to various
+new applications.
+The VL53L0X integrates a leading-edge SPAD
+array (Single Photon Avalanche Diodes) and
+embeds ST’s second generation FlightSenseTM
+patented technology.
+The VL53L0X’s 940 nm VCSEL emitter (Vertical
+Cavity Surface-Emitting Laser), is totally invisible
+to the human eye, coupled with internal physical
+infrared filters, it enables longer ranging
+distances, higher immunity to ambient light, and
+better robustness to cover glass optical crosstalk.
+
+Required properties:
+
+ - compatible		: Should be "st,stmvl53l0".
+ - reg			: i2c slave address of the device.
+
+Example:
+	i2c@f9925000 {
+		vl53l0x@52 {
+			compatible = "st,stmvl53l0";
+			reg = <0x52>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/input/touchscreen/himax.txt b/Documentation/devicetree/bindings/input/touchscreen/himax.txt
index 258ffec..b54c859 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/himax.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/himax.txt
@@ -3,3 +3,20 @@
 Required properties:
 
  - compatible			: Should be "himax,hxcommon"
+ - reg					: i2c slave address of the device.
+ - interrupt-parent		: parent of interrupt.
+ - himax,irq-gpio       : irq gpio.
+ - himax,reset-gpio		: reset gpio.
+ - vdd-supply			: Power supply needed to power up the device.
+ - avdd-supply			: Power source required to power up i2c bus.
+ - himax,panel-coords 	: panel coordinates for the chip in pixels.
+						  It is a four tuple consisting of min x,
+						  min y, max x and max y values.
+ - himax,display-coords : display coordinates in pixels. It is a four
+						  tuple consisting of min x, min y, max x and
+						  max y values
+
+Optional properties:
+ - himax,3v3-gpio		: gpio acting as 3.3 v supply.
+ - report_type			: Multi-touch protocol type. Default 0.
+						  0 for protocol A, 1 for protocol B.
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index 78aa1d7..4839df4 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -77,6 +77,21 @@
 - qcom,tz-device-id : A string indicating the device ID for this SMMU known
 		  to TZ.  See msm_tz_smmu.c for a full list of mappings.
 
+- qcom,enable-static-cb:
+		A boolean indicating that the SMMU global register space,
+		as well as some context banks, are managed by secure software
+		and may not be modified by HLOS.
+
+- qcom,static-ns-cbs:
+		A list of u32.
+		When qcom,enable-static-cb is selected, indicates which
+		iommu context banks may be used by HLOS.
+
+- qcom,hibernation-support:
+		A boolean, indicates that hibernation should be supported and
+		all secure usecases should be disabled, since they cannot be
+		restored properly.
+
 - qcom,skip-init : Disable resetting configuration for all context banks
                   during device reset.  This is useful for targets where
                   some context banks are dedicated to other execution
diff --git a/Documentation/devicetree/bindings/mcd/mcd.txt b/Documentation/devicetree/bindings/mcd/mcd.txt
deleted file mode 100644
index 4077ee2..0000000
--- a/Documentation/devicetree/bindings/mcd/mcd.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-* MCD (MobiCore Driver)
-
-t-base is an operating system running in the secure world (TrustZone).
-The t-base implementation consists of several components in the
-secure world and the non-secure world (kernel and user space). The
-MobiCore driver communicates with the t-base operating system that
-exists in TrustZone.
-
-Required properties:
-  - compatible: Should be "qcom,mcd"
-  - qcom,ce-hw-instance: should contain crypto HW instance
-  - qcom,ce-device: Device number
-  - clocks: Array of <clock_controller_phandle clock_reference> listing
-            all the clocks that are accesed by this subsystem.
-  - qcom,ce-opp-freq: indicates the CE operating frequency in Hz, changes from target to target.
-
-Example:
-	mcd {
-		compatible = "qcom,mcd";
-		qcom,ce-hw-instance = <0>;
-		qcom,ce-device = <0>;
-		clocks = <&clock_gcc clk_crypto_clk_src>,
-			 <&clock_gcc clk_gcc_crypto_clk>,
-			 <&clock_gcc clk_gcc_crypto_ahb_clk>,
-			 <&clock_gcc clk_gcc_crypto_axi_clk>;
-		clock-names = "core_clk_src", "core_clk",
-				"iface_clk", "bus_clk";
-		qcom,ce-opp-freq = <100000000>;
-	};
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt
index caf297b..c28d4eb8 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt
@@ -35,6 +35,15 @@
 - ti,palmas-enable-dvfs2: Enable DVFS2. Configure pins for DVFS2 mode.
 	Selection primary or secondary function associated to GPADC_START
 	and SYSEN2 pin/pad for DVFS2 interface
+- ti,palmas-override-powerhold: This is applicable for PMICs for which
+	GPIO7 is configured in POWERHOLD mode which has higher priority
+	over DEV_ON bit and keeps the PMIC supplies on even after the DEV_ON
+	bit is turned off. This property enables driver to over ride the
+	POWERHOLD value to GPIO7 so as to turn off the PMIC in power off
+	scenarios. So for GPIO7 if ti,palmas-override-powerhold is set
+	then the GPIO_7 field should never be muxed to anything else.
+	It should be set to POWERHOLD by default and only in case of
+	power off scenarios the driver will over ride the mux value.
 
 This binding uses the following generic properties as defined in
 pinctrl-bindings.txt:
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
index efa67f5..afeb65d 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
@@ -191,6 +191,77 @@
 		    temperature specific configuration as applied. If not
 		    specified, the default value is 0 degree centigrade.
 
+- qcom,cl-disable
+	Usage:      optional
+	Value type: <empty>
+	Definition: A boolean property to disable the battery capacity
+		    learning when charging.
+
+- qcom,cl-feedback-on
+	Usage:      optional
+	Value type: <empty>
+	Definition: A boolean property to feedback the learned capacity into
+		    the capacity lerning algorithm. This has to be used only if the
+		    property "qcom,cl-disable" is not specified.
+
+- qcom,cl-max-start-soc
+	Usage:      optional
+	Value type: <u32>
+	Definition: Battery SOC has to be below or equal to this value at the
+		    start of a charge cycle to start the capacity learning.
+		    If this is not specified, then the default value used
+		    will be 15. Unit is in percentage.
+
+- qcom,cl-min-start-soc
+	Usage:      optional
+	Value type: <u32>
+	Definition: Battery SOC has to be above or equal to this value at the
+		    start of a charge cycle to start the capacity learning.
+		    If this is not specified, then the default value used
+		    will be 10. Unit is in percentage.
+
+- qcom,cl-min-temp
+	Usage:      optional
+	Value type: <u32>
+	Definition: Lower limit of battery temperature to start the capacity
+		    learning. If this is not specified, then the default value
+		    used will be 150 (15 C). Unit is in decidegC.
+
+- qcom,cl-max-temp
+	Usage:      optional
+	Value type: <u32>
+	Definition: Upper limit of battery temperature to start the capacity
+		    learning. If this is not specified, then the default value
+		    used will be 500 (50 C). Unit is in decidegC.
+
+- qcom,cl-max-increment
+	Usage:      optional
+	Value type: <u32>
+	Definition: Maximum capacity increment allowed per capacity learning
+		    cycle. If this is not specified, then the default value
+		    used will be 5 (0.5%). Unit is in decipercentage.
+
+- qcom,cl-max-decrement
+	Usage:      optional
+	Value type: <u32>
+	Definition: Maximum capacity decrement allowed per capacity learning
+		    cycle. If this is not specified, then the default value
+		    used will be 100 (10%). Unit is in decipercentage.
+
+- qcom,cl-min-limit
+	Usage:      optional
+	Value type: <u32>
+	Definition: Minimum limit that the capacity cannot go below in a
+		    capacity learning cycle. If this is not specified, then
+		    the default value is 0. Unit is in decipercentage.
+
+- qcom,cl-max-limit
+	Usage:      optional
+	Value type: <u32>
+	Definition: Maximum limit that the capacity cannot go above in a
+		    capacity learning cycle. If this is not specified, then
+		    the default value is 0. Unit is in decipercentage.
+
 ==========================================================
 Second Level Nodes - Peripherals managed by QGAUGE driver
 ==========================================================
diff --git a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt
index 846bd22..b02d759 100644
--- a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt
@@ -241,6 +241,15 @@
 		    time in order to allow hardware closed-loop CPR voltage
 		    change requests to reach the PMIC regulator.
 
+- qcom,cpr-thread-has-always-vote-en
+	Usage:      optional; only meaningful for CPR4 controller
+	Value type: <empty>
+	Definition: Boolean value which indicates that the CPR controller should
+		    be configured to keep thread vote always enabled. This
+		    configuration allows the CPR controller to not consider
+		    MID/DN recommendations from other thread when all sensors
+		    mapped to a thread collapsed.
+
 =================================================
 Second Level Nodes - CPR Threads for a Controller
 =================================================
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 7b8ae6f..1e4d2c1 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -434,6 +434,9 @@
 Required properties:
 
  - compatible :                            "qcom,wcd-dsp-glink"
+ - qcom,msm-codec-glink-edge:              Name of the glink edge which is used
+                                           for IPC.
+                                           If no name is set, it defaults to "wdsp"
 
 * msm_ext_disp_audio_codec_rx
 
@@ -722,6 +725,7 @@
 
 	wcd_dsp_glink {
 		compatible = "qcom,wcd-dsp-glink";
+		qcom,msm-codec-glink-edge = "bg";
 	};
 
 	msm_ext_disp_audio_codec_rx {
@@ -1180,6 +1184,18 @@
 				When clock rate is set to zero,
 				then external clock is assumed.
 
+ - qcom,msm-cpudai-tdm-afe-ebit-unsupported: Notify if ebit
+				setting is needed.When this is
+				set, along with clock rate as
+				zero, then afe is not configured
+				for clock.
+
+ - qcom,msm-cpudai-tdm-sec-port-enable: For chipsets with the
+				limitation where we need to enable
+				both RX and TX AFE ports, this flag
+				is used to enable TX/RX port for
+				RX/TX streams.
+
  - qcom,msm-cpudai-tdm-clk-internal: Clock Source.
 				0 - EBIT clock from clk tree
 				1 - IBIT clock from clk tree
diff --git a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
index 97b71a7..d3f765c 100644
--- a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
+++ b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
@@ -13,6 +13,7 @@
 Required properties:
 - compatible : should be "qcom,qpnp-adc-tm-hc" for thermal ADC driver using
 	       refreshed BTM peripheral.
+	       should include "qcom,qpnp-adc-tm-hc-pm5" for PMIC5.
 - reg : offset and length of the PMIC Aribter register map.
 - address-cells : Must be one.
 - size-cells : Must be zero.
diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt
index e7fb61e..e85f9e1 100644
--- a/Documentation/filesystems/f2fs.txt
+++ b/Documentation/filesystems/f2fs.txt
@@ -171,6 +171,23 @@
 offprjjquota           Turn off project journelled quota.
 quota                  Enable plain user disk quota accounting.
 noquota                Disable all plain disk quota option.
+whint_mode=%s          Control which write hints are passed down to block
+                       layer. This supports "off", "user-based", and
+                       "fs-based".  In "off" mode (default), f2fs does not pass
+                       down hints. In "user-based" mode, f2fs tries to pass
+                       down hints given by users. And in "fs-based" mode, f2fs
+                       passes down hints with its policy.
+alloc_mode=%s          Adjust block allocation policy, which supports "reuse"
+                       and "default".
+fsync_mode=%s          Control the policy of fsync. Currently supports "posix"
+                       and "strict". In "posix" mode, which is default, fsync
+                       will follow POSIX semantics and does a light operation
+                       to improve the filesystem performance. In "strict" mode,
+                       fsync will be heavy and behaves in line with xfs, ext4
+                       and btrfs, where xfstest generic/342 will pass, but the
+                       performance will regress.
+test_dummy_encryption  Enable dummy encryption, which provides a fake fscrypt
+                       context. The fake fscrypt context is used by xfstests.
 
 ================================================================================
 DEBUGFS ENTRIES
diff --git a/Makefile b/Makefile
index 41cc032..bf5ea11 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 4
 PATCHLEVEL = 9
-SUBLEVEL = 92
+SUBLEVEL = 96
 EXTRAVERSION =
 NAME = Roaring Lionus
 
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 04b1c06..54e93a0 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -574,6 +574,7 @@
        select PINCTRL
        select ARCH_WANT_KMAP_ATOMIC_FLUSH
        select SND_SOC_COMPRESS
+       select SND_HWDEP
        help
          Support for Qualcomm MSM/QSD based systems.  This runs on the
          apps processor of the MSM/QSD and depends on a shared memory
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index a6d5794..f66f377 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -13,6 +13,10 @@
 # Ensure linker flags are correct
 LDFLAGS		:=
 
+ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
+export DTC_FLAGS := -@
+endif
+
 LDFLAGS_vmlinux	:=-p --no-undefined -X --pic-veneer
 ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
 LDFLAGS_vmlinux	+= --be8
diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
index 2fa123e..52e8c50 100644
--- a/arch/arm/boot/Makefile
+++ b/arch/arm/boot/Makefile
@@ -34,10 +34,10 @@
 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)/dts/,$(DTB_LIST))
+else
+DTB_OBJS := $(shell find $(obj)/dts/ -name \*.dtb)
+endif
 
 ifeq ($(CONFIG_XIP_KERNEL),y)
 
diff --git a/arch/arm/boot/dts/am335x-pepper.dts b/arch/arm/boot/dts/am335x-pepper.dts
index 42b62f5..30e2f87 100644
--- a/arch/arm/boot/dts/am335x-pepper.dts
+++ b/arch/arm/boot/dts/am335x-pepper.dts
@@ -139,7 +139,7 @@
 &audio_codec {
 	status = "okay";
 
-	reset-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>;
+	gpio-reset = <&gpio1 16 GPIO_ACTIVE_LOW>;
 	AVDD-supply = <&ldo3_reg>;
 	IOVDD-supply = <&ldo3_reg>;
 	DRVDD-supply = <&ldo3_reg>;
diff --git a/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi
index 6df7829..78bee26 100644
--- a/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi
+++ b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi
@@ -204,6 +204,7 @@
 		interrupt-controller;
 
 		ti,system-power-controller;
+		ti,palmas-override-powerhold;
 
 		tps659038_pmic {
 			compatible = "ti,tps659038-pmic";
diff --git a/arch/arm/boot/dts/am57xx-idk-common.dtsi b/arch/arm/boot/dts/am57xx-idk-common.dtsi
index db858ff..1cc6272 100644
--- a/arch/arm/boot/dts/am57xx-idk-common.dtsi
+++ b/arch/arm/boot/dts/am57xx-idk-common.dtsi
@@ -57,6 +57,7 @@
 		#interrupt-cells = <2>;
 		interrupt-controller;
 		ti,system-power-controller;
+		ti,palmas-override-powerhold;
 
 		tps659038_pmic {
 			compatible = "ti,tps659038-pmic";
diff --git a/arch/arm/boot/dts/at91sam9g25.dtsi b/arch/arm/boot/dts/at91sam9g25.dtsi
index a7da0dd..0898213 100644
--- a/arch/arm/boot/dts/at91sam9g25.dtsi
+++ b/arch/arm/boot/dts/at91sam9g25.dtsi
@@ -21,7 +21,7 @@
 				atmel,mux-mask = <
 				      /*    A         B          C     */
 				       0xffffffff 0xffe0399f 0xc000001c  /* pioA */
-				       0x0007ffff 0x8000fe3f 0x00000000  /* pioB */
+				       0x0007ffff 0x00047e3f 0x00000000  /* pioB */
 				       0x80000000 0x07c0ffff 0xb83fffff  /* pioC */
 				       0x003fffff 0x003f8000 0x00000000  /* pioD */
 				      >;
diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts
index 132f2be..56311fd 100644
--- a/arch/arm/boot/dts/dra7-evm.dts
+++ b/arch/arm/boot/dts/dra7-evm.dts
@@ -398,6 +398,8 @@
 	tps659038: tps659038@58 {
 		compatible = "ti,tps659038";
 		reg = <0x58>;
+		ti,palmas-override-powerhold;
+		ti,system-power-controller;
 
 		tps659038_pmic {
 			compatible = "ti,tps659038-pmic";
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index f7357d9..64de33d 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -640,7 +640,7 @@
 			power-domains = <&pd_gsc>;
 			clocks = <&clock CLK_GSCL0>;
 			clock-names = "gscl";
-			iommu = <&sysmmu_gsc0>;
+			iommus = <&sysmmu_gsc0>;
 		};
 
 		gsc_1:  gsc@13e10000 {
@@ -650,7 +650,7 @@
 			power-domains = <&pd_gsc>;
 			clocks = <&clock CLK_GSCL1>;
 			clock-names = "gscl";
-			iommu = <&sysmmu_gsc1>;
+			iommus = <&sysmmu_gsc1>;
 		};
 
 		gsc_2:  gsc@13e20000 {
@@ -660,7 +660,7 @@
 			power-domains = <&pd_gsc>;
 			clocks = <&clock CLK_GSCL2>;
 			clock-names = "gscl";
-			iommu = <&sysmmu_gsc2>;
+			iommus = <&sysmmu_gsc2>;
 		};
 
 		gsc_3:  gsc@13e30000 {
@@ -670,7 +670,7 @@
 			power-domains = <&pd_gsc>;
 			clocks = <&clock CLK_GSCL3>;
 			clock-names = "gscl";
-			iommu = <&sysmmu_gsc3>;
+			iommus = <&sysmmu_gsc3>;
 		};
 
 		hdmi: hdmi@14530000 {
diff --git a/arch/arm/boot/dts/imx53-qsrb.dts b/arch/arm/boot/dts/imx53-qsrb.dts
index 96d7eed..036c9bd 100644
--- a/arch/arm/boot/dts/imx53-qsrb.dts
+++ b/arch/arm/boot/dts/imx53-qsrb.dts
@@ -23,7 +23,7 @@
 	imx53-qsrb {
 		pinctrl_pmic: pmicgrp {
 			fsl,pins = <
-				MX53_PAD_CSI0_DAT5__GPIO5_23	0x1e4 /* IRQ */
+				MX53_PAD_CSI0_DAT5__GPIO5_23	0x1c4 /* IRQ */
 			>;
 		};
 	};
diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
index 2b9c2be..47c9554 100644
--- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
@@ -88,6 +88,7 @@
 		clocks = <&clks IMX6QDL_CLK_CKO>;
 		VDDA-supply = <&reg_2p5v>;
 		VDDIO-supply = <&reg_3p3v>;
+		lrclk-strength = <3>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index 368e219..825f6ea 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -146,7 +146,7 @@
 		};
 
 		esdhc: esdhc@1560000 {
-			compatible = "fsl,esdhc";
+			compatible = "fsl,ls1021a-esdhc", "fsl,esdhc";
 			reg = <0x0 0x1560000 0x0 0x10000>;
 			interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
 			clock-frequency = <0>;
diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts
index 6003b29..4d448f1 100644
--- a/arch/arm/boot/dts/omap3-n900.dts
+++ b/arch/arm/boot/dts/omap3-n900.dts
@@ -510,7 +510,7 @@
 	tlv320aic3x: tlv320aic3x@18 {
 		compatible = "ti,tlv320aic3x";
 		reg = <0x18>;
-		reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; /* 60 */
+		gpio-reset = <&gpio2 28 GPIO_ACTIVE_HIGH>; /* 60 */
 		ai3x-gpio-func = <
 			0 /* AIC3X_GPIO1_FUNC_DISABLED */
 			5 /* AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT */
@@ -527,7 +527,7 @@
 	tlv320aic3x_aux: tlv320aic3x@19 {
 		compatible = "ti,tlv320aic3x";
 		reg = <0x19>;
-		reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; /* 60 */
+		gpio-reset = <&gpio2 28 GPIO_ACTIVE_HIGH>; /* 60 */
 
 		AVDD-supply = <&vmmc2>;
 		DRVDD-supply = <&vmmc2>;
diff --git a/arch/arm/boot/dts/qcom-ipq4019.dtsi b/arch/arm/boot/dts/qcom-ipq4019.dtsi
index b7a24af..4b7d972 100644
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -154,10 +154,10 @@
 
 		i2c_0: i2c@78b7000 {
 			compatible = "qcom,i2c-qup-v2.2.1";
-			reg = <0x78b7000 0x6000>;
+			reg = <0x78b7000 0x600>;
 			interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&gcc GCC_BLSP1_AHB_CLK>,
-				 <&gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>;
+				 <&gcc GCC_BLSP1_QUP1_I2C_APPS_CLK>;
 			clock-names = "iface", "core";
 			#address-cells = <1>;
 			#size-cells = <0>;
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
index 4642d0d..e6af69d 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -21,14 +21,18 @@
 	mdm9607-ttp.dtb
 
 targets += dtbs
-targets += $(addprefix ../, $(dtb-y))
-
-$(obj)/../%.dtb: $(src)/%.dts FORCE
-	$(call if_changed_dep,dtc)
 
 include $(srctree)/arch/arm64/boot/dts/qcom/Makefile
-$(obj)/../%.dtb: $(src)/../../../../arm64/boot/dts/qcom/%.dts FORCE
+$(obj)/%.dtb: $(src)/../../../../arm64/boot/dts/qcom/%.dts FORCE
 	$(call if_changed_dep,dtc)
 
-dtbs: $(addprefix $(obj)/../,$(dtb-y))
+ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
+$(obj)/%.dtbo:$(src)/../../../../arm64/boot/dts/qcom/%.dts FORCE
+	$(call if_changed_dep,dtc)
+	$(call if_changed,dtbo_verify)
+
+dtbs: $(addprefix $(obj)/,$(dtb-y)) $(addprefix $(obj)/,$(dtbo-y))
+else
+dtbs: $(addprefix $(obj)/,$(dtb-y))
+endif
 clean-files := *.dtb
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dtsi
index dafd0b8..1428f37 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dtsi
@@ -18,7 +18,8 @@
 
 &usb {
 	status = "okay";
-	extcon = <&vbus_detect>;
+	qcom,connector-type-uAB;
+	extcon = <0>, <0>, <0>, <&vbus_detect>;
 };
 
 &pcie_ep {
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dtsi
index 6c5f3c3..d7c0d13 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dtsi
@@ -18,7 +18,8 @@
 
 &usb {
 	status = "okay";
-	extcon = <&vbus_detect>;
+	qcom,connector-type-uAB;
+	extcon = <0>, <0>, <0>, <&vbus_detect>;
 };
 
 &pcie_ep {
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi
index 77fc533..505f242 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi
@@ -98,4 +98,9 @@
 		reg = <0xC300000 0x1000>, <0xC370004 0x4>;
 		reg-names = "phys_addr_base", "offset_addr";
 	};
+
+	qcom,rpmh-master-stats@b211200 {
+		compatible = "qcom,rpmh-master-stats-v1";
+		reg = <0xb211200 0x60>;
+	};
 };
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index ec5b61e..50bbebf 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -19,6 +19,8 @@
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 #include <dt-bindings/clock/qcom,aop-qmp.h>
 
+#define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024))
+
 / {
 	model = "Qualcomm Technologies, Inc. SDX POORWILLS";
 	compatible = "qcom,sdxpoorwills";
@@ -218,6 +220,31 @@
 				< 1497600 >;
 	};
 
+	cpubw: qcom,cpubw {
+		compatible = "qcom,devbw";
+		governor = "cpufreq";
+		qcom,src-dst-ports = <1 512>;
+		qcom,active-only;
+		qcom,bw-tbl =
+			< MHZ_TO_MBPS(200, 2) >, /*   381 MB/s */
+			< MHZ_TO_MBPS(470, 2) >, /*   896 MB/s */
+			< MHZ_TO_MBPS(547, 2) >, /*  1043 MB/s */
+			< MHZ_TO_MBPS(691, 2) >, /*  1317 MB/s */
+			< MHZ_TO_MBPS(806, 2) >, /*  1537 MB/s */
+			< MHZ_TO_MBPS(940, 2) >, /*  1792 MB/s */
+			< MHZ_TO_MBPS(1383, 2) >; /* 2637 MB/s */
+	};
+
+	devfreq_compute: qcom,devfreq-compute {
+		compatible = "qcom,arm-cpu-mon";
+		qcom,cpulist = <&CPU0>;
+		qcom,target-dev = <&cpubw>;
+		qcom,core-dev-table =
+				<  153600 MHZ_TO_MBPS(200, 2) >,
+				<  576000 MHZ_TO_MBPS(691, 2) >,
+				< 1497600 MHZ_TO_MBPS(1383, 2)>;
+	};
+
 	clock_gcc: qcom,gcc@100000 {
 		compatible = "qcom,gcc-sdxpoorwills", "syscon";
 		reg = <0x100000 0x1f0000>;
@@ -809,7 +836,7 @@
 		memory-region = <&dump_mem>;
 
 		rpmh_dump {
-			qcom,dump-size = <0x2000000>;
+			qcom,dump-size = <0x300000>;
 			qcom,dump-id = <0xec>;
 		};
 
@@ -1039,7 +1066,6 @@
 
 		ipa_smmu_ap: ipa_smmu_ap {
 			compatible = "qcom,ipa-smmu-ap-cb";
-			qcom,smmu-s1-bypass;
 			iommus = <&apps_smmu 0x5E0 0x0>;
 			qcom,iova-mapping = <0x20000000 0x40000000>;
 			qcom,additional-mapping =
@@ -1050,7 +1076,6 @@
 
 		ipa_smmu_wlan: ipa_smmu_wlan {
 			compatible = "qcom,ipa-smmu-wlan-cb";
-			qcom,smmu-s1-bypass;
 			iommus = <&apps_smmu 0x5E1 0x0>;
 			qcom,additional-mapping =
 				/* ipa-uc ram */
@@ -1059,7 +1084,6 @@
 
 		ipa_smmu_uc: ipa_smmu_uc {
 			compatible = "qcom,ipa-smmu-uc-cb";
-			qcom,smmu-s1-bypass;
 			iommus = <&apps_smmu 0x5E2 0x0>;
 			qcom,iova-mapping = <0x40000000 0x20000000>;
 		};
@@ -1078,6 +1102,12 @@
 		#mbox-cells = <1>;
 	};
 
+	aop-msg-client {
+		compatible = "qcom,debugfs-qmp-client";
+		mboxes = <&qmp_aop 0>;
+		mbox-names = "aop";
+	};
+
 	vbus_detect: qcom,pmd-vbus-det {
 		compatible = "qcom,pmd-vbus-det";
 		interrupt-parent = <&spmi_bus>;
@@ -1255,13 +1285,14 @@
 			"rx-ch0-intr", "rx-ch1-intr",
 			"rx-ch2-intr", "rx-ch3-intr";
 		qcom,msm-bus,name = "emac";
-		qcom,msm-bus,num-cases = <3>;
+		qcom,msm-bus,num-cases = <4>;
 		qcom,msm-bus,num-paths = <2>;
 		qcom,msm-bus,vectors-KBps =
+			<98 512 0 0>, <1 781 0 0>,  /* No vote */
 			<98 512 1250 0>, <1 781 0 40000>,  /* 10Mbps vote */
 			<98 512 12500 0>, <1 781 0 40000>,  /* 100Mbps vote */
 			<98 512 125000 0>, <1 781 0 40000>; /* 1000Mbps vote */
-		qcom,bus-vector-names = "10", "100", "1000";
+		qcom,bus-vector-names = "0", "10", "100", "1000";
 		clocks = <&clock_gcc GCC_ETH_AXI_CLK>,
 			<&clock_gcc GCC_ETH_PTP_CLK>,
 			<&clock_gcc GCC_ETH_RGMII_CLK>,
@@ -1281,7 +1312,6 @@
 
 		emac_emb_smmu: emac_emb_smmu {
 			compatible = "qcom,emac-smmu-embedded";
-			qcom,smmu-s1-bypass;
 			iommus = <&apps_smmu 0x220 0xf>;
 			qcom,iova-mapping = <0x80000000 0x40000000>;
 		};
diff --git a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
index 7885075..1788e18 100644
--- a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
+++ b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
@@ -266,7 +266,9 @@
 	lcd0_pins: lcd0 {
 		groups = "lcd0_data24_0", "lcd0_lclk_1", "lcd0_sync";
 		function = "lcd0";
+	};
 
+	lcd0_mux {
 		/* DBGMD/LCDC0/FSIA MUX */
 		gpio-hog;
 		gpios = <176 0>;
diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi
index 9e6bf0e..2679dc8 100644
--- a/arch/arm/boot/dts/rk322x.dtsi
+++ b/arch/arm/boot/dts/rk322x.dtsi
@@ -617,9 +617,9 @@
 						<0 12 RK_FUNC_1 &pcfg_pull_none>,
 						<0 13 RK_FUNC_1 &pcfg_pull_none>,
 						<0 14 RK_FUNC_1 &pcfg_pull_none>,
-						<1 2 RK_FUNC_1 &pcfg_pull_none>,
-						<1 4 RK_FUNC_1 &pcfg_pull_none>,
-						<1 5 RK_FUNC_1 &pcfg_pull_none>;
+						<1 2 RK_FUNC_2 &pcfg_pull_none>,
+						<1 4 RK_FUNC_2 &pcfg_pull_none>,
+						<1 5 RK_FUNC_2 &pcfg_pull_none>;
 			};
 		};
 
diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi
index 65e725f..de0e189 100644
--- a/arch/arm/boot/dts/sama5d4.dtsi
+++ b/arch/arm/boot/dts/sama5d4.dtsi
@@ -1362,7 +1362,7 @@
 			pinctrl@fc06a000 {
 				#address-cells = <1>;
 				#size-cells = <1>;
-				compatible = "atmel,at91sam9x5-pinctrl", "atmel,at91rm9200-pinctrl", "simple-bus";
+				compatible = "atmel,sama5d3-pinctrl", "atmel,at91sam9x5-pinctrl", "simple-bus";
 				ranges = <0xfc068000 0xfc068000 0x100
 					  0xfc06a000 0xfc06a000 0x4000>;
 				/* WARNING: revisit as pin spec has changed */
diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig
index 6f3cee4..9f5001f 100644
--- a/arch/arm/configs/msm8909-perf_defconfig
+++ b/arch/arm/configs/msm8909-perf_defconfig
@@ -259,7 +259,9 @@
 CONFIG_PPP_ASYNC=y
 CONFIG_PPP_SYNC_TTY=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
-CONFIG_CLD_LL_CORE=y
+CONFIG_CNSS=y
+CONFIG_CNSS_SDIO=y
+CONFIG_CLD_HL_SDIO_CORE=y
 CONFIG_INPUT_EVDEV=y
 CONFIG_KEYBOARD_GPIO=y
 CONFIG_INPUT_JOYSTICK=y
@@ -423,8 +425,10 @@
 CONFIG_MSM_EVENT_TIMER=y
 CONFIG_QTI_RPM_STATS_LOG=y
 CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_CNSS_CRYPTO=y
 CONFIG_PWM=y
 CONFIG_PWM_QPNP=y
+CONFIG_QTI_MPM=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
 CONFIG_SENSORS_SSC=y
diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig
index f57e45d..c8087ad 100644
--- a/arch/arm/configs/msm8909_defconfig
+++ b/arch/arm/configs/msm8909_defconfig
@@ -253,7 +253,9 @@
 CONFIG_PPP_ASYNC=y
 CONFIG_PPP_SYNC_TTY=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
-CONFIG_CLD_LL_CORE=y
+CONFIG_CNSS=y
+CONFIG_CNSS_SDIO=y
+CONFIG_CLD_HL_SDIO_CORE=y
 CONFIG_INPUT_EVDEV=y
 CONFIG_KEYBOARD_GPIO=y
 CONFIG_INPUT_JOYSTICK=y
@@ -418,8 +420,10 @@
 CONFIG_MSM_EVENT_TIMER=y
 CONFIG_QTI_RPM_STATS_LOG=y
 CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_CNSS_CRYPTO=y
 CONFIG_PWM=y
 CONFIG_PWM_QPNP=y
+CONFIG_QTI_MPM=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
 CONFIG_SENSORS_SSC=y
diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig
index 9b55740..5a56d63 100644
--- a/arch/arm/configs/msm8909w-perf_defconfig
+++ b/arch/arm/configs/msm8909w-perf_defconfig
@@ -1,9 +1,13 @@
+# CONFIG_FHANDLE is not set
 CONFIG_AUDIT=y
 # CONFIG_AUDITSYSCALL is not set
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_IRQ_TIME_ACCOUNTING=y
 CONFIG_SCHED_WALT=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
 CONFIG_RCU_EXPERT=y
 CONFIG_RCU_FAST_NO_HZ=y
 CONFIG_RCU_NOCB_CPU=y
@@ -30,7 +34,7 @@
 CONFIG_EMBEDDED=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=y
-CONFIG_CC_STACKPROTECTOR_STRONG=y
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
@@ -132,6 +136,7 @@
 CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
 CONFIG_NETFILTER_XT_MATCH_SOCKET=y
 CONFIG_NETFILTER_XT_MATCH_STATE=y
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -213,6 +218,7 @@
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_HDCP_QSEECOM=y
 CONFIG_QSEECOM=y
+CONFIG_UID_SYS_STATS=y
 CONFIG_MEMORY_STATE_TIME=y
 CONFIG_QPNP_MISC=y
 CONFIG_SCSI=y
@@ -259,6 +265,8 @@
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_QPNP_POWER_ON=y
 CONFIG_INPUT_UINPUT=y
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
 CONFIG_SERIAL_MSM_HS=y
 CONFIG_SERIAL_MSM_SMD=y
 CONFIG_DIAG_CHAR=y
@@ -310,6 +318,8 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_VIDC_3X_V4L2=y
+CONFIG_MSM_VIDC_3X_GOVERNORS=y
 CONFIG_QCOM_KGSL=y
 CONFIG_FB=y
 CONFIG_FB_VIRTUAL=y
@@ -354,9 +364,12 @@
 CONFIG_USB_CONFIGFS_EEM=y
 CONFIG_USB_CONFIGFS_MASS_STORAGE=y
 CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MTP=y
+CONFIG_USB_CONFIGFS_F_PTP=y
 CONFIG_USB_CONFIGFS_F_ACC=y
 CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
 CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
 CONFIG_USB_CONFIGFS_F_HID=y
 CONFIG_USB_CONFIGFS_F_DIAG=y
 CONFIG_USB_CONFIGFS_F_CDEV=y
@@ -498,6 +511,7 @@
 CONFIG_CRYPTO_ANSI_CPRNG=y
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_QCRYPTO=y
 CONFIG_CRYPTO_DEV_QCEDEV=y
 CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
 CONFIG_CRYPTO_DEV_QCOM_ICE=y
diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig
index bb6bc88..af47269 100644
--- a/arch/arm/configs/msm8909w_defconfig
+++ b/arch/arm/configs/msm8909w_defconfig
@@ -1,3 +1,4 @@
+# CONFIG_FHANDLE is not set
 CONFIG_AUDIT=y
 # CONFIG_AUDITSYSCALL is not set
 CONFIG_NO_HZ=y
@@ -34,7 +35,7 @@
 CONFIG_EMBEDDED=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=y
-CONFIG_CC_STACKPROTECTOR_STRONG=y
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
@@ -141,6 +142,7 @@
 CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
 CONFIG_NETFILTER_XT_MATCH_SOCKET=y
 CONFIG_NETFILTER_XT_MATCH_STATE=y
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -269,6 +271,8 @@
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_QPNP_POWER_ON=y
 CONFIG_INPUT_UINPUT=y
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
 CONFIG_SERIAL_MSM=y
 CONFIG_SERIAL_MSM_CONSOLE=y
 CONFIG_SERIAL_MSM_HS=y
@@ -322,6 +326,8 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_VIDC_3X_V4L2=y
+CONFIG_MSM_VIDC_3X_GOVERNORS=y
 CONFIG_QCOM_KGSL=y
 CONFIG_FB=y
 CONFIG_FB_VIRTUAL=y
@@ -375,6 +381,7 @@
 CONFIG_USB_CONFIGFS_F_ACC=y
 CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
 CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
 CONFIG_USB_CONFIGFS_F_HID=y
 CONFIG_USB_CONFIGFS_F_DIAG=y
 CONFIG_USB_CONFIGFS_F_CDEV=y
diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig
index 5a6de0f..b113ebd 100644
--- a/arch/arm/configs/msm8937-perf_defconfig
+++ b/arch/arm/configs/msm8937-perf_defconfig
@@ -17,7 +17,6 @@
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
 CONFIG_CGROUP_FREEZER=y
-CONFIG_CPUSETS=y
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_CGROUP_SCHEDTUNE=y
 CONFIG_RT_GROUP_SCHED=y
@@ -223,6 +222,8 @@
 CONFIG_RMNET_DATA_FC=y
 CONFIG_RMNET_DATA_DEBUG_PKT=y
 CONFIG_BT=y
+# CONFIG_BT_BREDR is not set
+# CONFIG_BT_LE is not set
 CONFIG_MSM_BT_POWER=y
 CONFIG_CFG80211=y
 CONFIG_CFG80211_INTERNAL_REGDB=y
@@ -241,7 +242,6 @@
 CONFIG_HDCP_QSEECOM=y
 CONFIG_QSEECOM=y
 CONFIG_UID_SYS_STATS=y
-CONFIG_MEMORY_STATE_TIME=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_SG=y
@@ -253,10 +253,8 @@
 CONFIG_SCSI_UFSHCD_PLATFORM=y
 CONFIG_SCSI_UFS_QCOM=y
 CONFIG_SCSI_UFS_QCOM_ICE=y
-CONFIG_SCSI_UFSHCD_CMD_LOGGING=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_DM=y
-CONFIG_DM_DEBUG=y
 CONFIG_DM_CRYPT=y
 CONFIG_DM_REQ_CRYPT=y
 CONFIG_DM_UEVENT=y
@@ -308,6 +306,8 @@
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_JOYSTICK=y
 CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_FT5X06=y
+CONFIG_TOUCHSCREEN_GEN_VKEYS=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_HBTP_INPUT=y
 CONFIG_INPUT_QPNP_POWER_ON=y
@@ -339,7 +339,6 @@
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_QPNP_PIN=y
-CONFIG_GPIO_QPNP_PIN_DEBUG=y
 CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_QCOM=y
 CONFIG_QCOM_DLOAD_MODE=y
@@ -409,7 +408,6 @@
 CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y
 CONFIG_MSMB_JPEG=y
 CONFIG_MSM_FD=y
-CONFIG_MSM_JPEGDMA=y
 CONFIG_MSM_VIDC_3X_V4L2=y
 CONFIG_MSM_VIDC_3X_GOVERNORS=y
 CONFIG_RADIO_IRIS=y
@@ -422,7 +420,7 @@
 CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
 CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_DYNAMIC_MINORS=y
@@ -483,11 +481,12 @@
 CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
+# CONFIG_PWRSEQ_EMMC is not set
+# CONFIG_PWRSEQ_SIMPLE is not set
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_CLKGATE=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
-CONFIG_MMC_TEST=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_SDHCI_MSM=y
@@ -581,6 +580,8 @@
 CONFIG_MSM_TZ_LOG=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_SECURITY=y
+CONFIG_F2FS_FS=y
+CONFIG_F2FS_FS_SECURITY=y
 CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 CONFIG_QFMT_V2=y
@@ -588,8 +589,6 @@
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
-CONFIG_ECRYPT_FS=y
-CONFIG_ECRYPT_FS_MESSAGING=y
 CONFIG_SDCARD_FS=y
 # CONFIG_NETWORK_FILESYSTEMS is not set
 CONFIG_NLS_CODEPAGE_437=y
diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig
index 858b506..1cccfd3 100644
--- a/arch/arm/configs/msm8937_defconfig
+++ b/arch/arm/configs/msm8937_defconfig
@@ -18,7 +18,6 @@
 CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
 CONFIG_CGROUP_DEBUG=y
 CONFIG_CGROUP_FREEZER=y
-CONFIG_CPUSETS=y
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_CGROUP_SCHEDTUNE=y
 CONFIG_RT_GROUP_SCHED=y
@@ -228,6 +227,8 @@
 CONFIG_RMNET_DATA_FC=y
 CONFIG_RMNET_DATA_DEBUG_PKT=y
 CONFIG_BT=y
+# CONFIG_BT_BREDR is not set
+# CONFIG_BT_LE is not set
 CONFIG_MSM_BT_POWER=y
 CONFIG_CFG80211=y
 CONFIG_CFG80211_INTERNAL_REGDB=y
@@ -246,7 +247,6 @@
 CONFIG_HDCP_QSEECOM=y
 CONFIG_QSEECOM=y
 CONFIG_UID_SYS_STATS=y
-CONFIG_MEMORY_STATE_TIME=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_SG=y
@@ -258,10 +258,8 @@
 CONFIG_SCSI_UFSHCD_PLATFORM=y
 CONFIG_SCSI_UFS_QCOM=y
 CONFIG_SCSI_UFS_QCOM_ICE=y
-CONFIG_SCSI_UFSHCD_CMD_LOGGING=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_DM=y
-CONFIG_DM_DEBUG=y
 CONFIG_DM_CRYPT=y
 CONFIG_DM_REQ_CRYPT=y
 CONFIG_DM_UEVENT=y
@@ -313,6 +311,8 @@
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_JOYSTICK=y
 CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_FT5X06=y
+CONFIG_TOUCHSCREEN_GEN_VKEYS=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_HBTP_INPUT=y
 CONFIG_INPUT_QPNP_POWER_ON=y
@@ -346,7 +346,6 @@
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_QPNP_PIN=y
-CONFIG_GPIO_QPNP_PIN_DEBUG=y
 CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_QCOM=y
 CONFIG_QCOM_DLOAD_MODE=y
@@ -416,7 +415,6 @@
 CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y
 CONFIG_MSMB_JPEG=y
 CONFIG_MSM_FD=y
-CONFIG_MSM_JPEGDMA=y
 CONFIG_MSM_VIDC_3X_V4L2=y
 CONFIG_MSM_VIDC_3X_GOVERNORS=y
 CONFIG_RADIO_IRIS=y
@@ -430,7 +428,7 @@
 CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
 CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_DYNAMIC_MINORS=y
@@ -491,12 +489,13 @@
 CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
+# CONFIG_PWRSEQ_EMMC is not set
+# CONFIG_PWRSEQ_SIMPLE is not set
 CONFIG_MMC_RING_BUFFER=y
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_CLKGATE=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
-CONFIG_MMC_TEST=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_SDHCI_MSM=y
@@ -597,6 +596,8 @@
 CONFIG_MSM_TZ_LOG=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_SECURITY=y
+CONFIG_F2FS_FS=y
+CONFIG_F2FS_FS_SECURITY=y
 CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 CONFIG_QFMT_V2=y
@@ -604,8 +605,6 @@
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
-CONFIG_ECRYPT_FS=y
-CONFIG_ECRYPT_FS_MESSAGING=y
 CONFIG_SDCARD_FS=y
 # CONFIG_NETWORK_FILESYSTEMS is not set
 CONFIG_NLS_CODEPAGE_437=y
diff --git a/arch/arm/configs/msm8953-batcam-perf_defconfig b/arch/arm/configs/msm8953-batcam-perf_defconfig
new file mode 100644
index 0000000..1610d29
--- /dev/null
+++ b/arch/arm/configs/msm8953-batcam-perf_defconfig
@@ -0,0 +1,271 @@
+CONFIG_LOCALVERSION="-perf"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SCHED_WALT=y
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_ALL=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHEDTUNE=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_CGROUP_BPF=y
+# CONFIG_UTS_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_SCHED_TUNE=y
+CONFIG_DEFAULT_USE_ENERGY_AWARE=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_BPF_SYSCALL=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_CC_STACKPROTECTOR_STRONG=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_MSM8953=y
+# CONFIG_VDSO is not set
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_VMSPLIT_3G_OPT=y
+CONFIG_NR_CPUS=8
+CONFIG_ARM_PSCI=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_CMA=y
+CONFIG_CMA_DEBUGFS=y
+CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_SECCOMP=y
+CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
+CONFIG_IMG_DTB=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_BOOST=y
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_CPU_FREQ_MSM=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_KERNEL_MODE_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HIBERNATION=y
+CONFIG_HIBERNATION_IMAGE_REUSE=y
+CONFIG_PM_STD_PARTITION="/dev/mmcblk0p49"
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_NET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_DMA_CMA=y
+CONFIG_QSEECOM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_NETDEVICES=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_QPNP_POWER_ON=y
+CONFIG_INPUT_UINPUT=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM_SMD=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
+CONFIG_MSM_SMD_PKT=y
+CONFIG_MSM_ADSPRPC=y
+CONFIG_MSM_RDBG=m
+CONFIG_I2C_CHARDEV=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
+CONFIG_PINCTRL_MSM8953=y
+CONFIG_PINCTRL_MSM8917=y
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_QPNP_FG=y
+CONFIG_SMB135X_CHARGER=y
+CONFIG_QPNP_SMB5=y
+CONFIG_QPNP_SMBCHARGER=y
+CONFIG_QPNP_TYPEC=y
+CONFIG_QPNP_QG=y
+CONFIG_MSM_APM=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_THERMAL_TSENS=y
+CONFIG_MSM_BCL_PERIPHERAL_CTL=y
+CONFIG_QTI_THERMAL_LIMITS_DCVS=y
+CONFIG_MFD_SPMI_PMIC=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_PROXY_CONSUMER=y
+CONFIG_REGULATOR_CPR=y
+CONFIG_REGULATOR_CPR4_APSS=y
+CONFIG_REGULATOR_CPRH_KBSS=y
+CONFIG_REGULATOR_MEM_ACC=y
+CONFIG_REGULATOR_MSM_GFX_LDO=y
+CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_QPNP_LCDB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_RPM_SMD=y
+CONFIG_REGULATOR_SPM=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
+CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_SOC=y
+CONFIG_UHID=y
+CONFIG_MMC=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_CQ_HCI=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_QTI_TRI_LED=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_QPNP_FLASH=y
+CONFIG_LEDS_QPNP_FLASH_V2=y
+CONFIG_LEDS_QPNP_WLED=y
+CONFIG_LEDS_QPNP_HAPTICS=y
+CONFIG_LEDS_QPNP_VIBRATOR_LDO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_EDAC=y
+CONFIG_EDAC_MM_EDAC=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_DMADEVICES=y
+CONFIG_QCOM_SPS_DMA=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_IPA=y
+CONFIG_RNDIS_IPA=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_COINCELL=y
+CONFIG_QPNP_REVID=y
+CONFIG_MSM_MDSS_PLL=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MAILBOX=y
+CONFIG_ARM_SMMU=y
+CONFIG_QCOM_LAZY_MAPPING=y
+CONFIG_QCOM_RUN_QUEUE_STATS=y
+CONFIG_MSM_SPM=y
+CONFIG_MSM_L2_SPM=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_MSM_RPM_SMD=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_QCOM_SECURE_BUFFER=y
+CONFIG_QCOM_EARLY_RANDOM=y
+CONFIG_MSM_SMEM=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_DEBUG=y
+CONFIG_MSM_TZ_SMMU=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_SSR_GENERIC=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_ICNSS=y
+CONFIG_MSM_PERFORMANCE=y
+CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_PM=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
+CONFIG_QCOM_BIMC_BWMON=y
+CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
+CONFIG_SPDM_SCM=y
+CONFIG_DEVFREQ_SPDM=y
+CONFIG_PWM=y
+CONFIG_PWM_QPNP=y
+CONFIG_PWM_QTI_LPG=y
+CONFIG_QTI_MPM=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_SENSORS_SSC=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_QFMT_V2=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_ECRYPT_FS=y
+CONFIG_ECRYPT_FS_MESSAGING=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF4=y
+CONFIG_FRAME_WARN=2048
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_STACKTRACE=y
+# CONFIG_FTRACE is not set
+CONFIG_SECURITY=y
+CONFIG_HARDENED_USERCOPY=y
+CONFIG_CRYPTO_USER_API_HASH=m
+CONFIG_ARM_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM_NEON=y
+CONFIG_CRYPTO_SHA2_ARM_CE=y
+CONFIG_CRYPTO_AES_ARM_BS=y
+CONFIG_CRYPTO_AES_ARM_CE=y
+CONFIG_QMI_ENCDEC=y
diff --git a/arch/arm/configs/msm8953-batcam_defconfig b/arch/arm/configs/msm8953-batcam_defconfig
new file mode 100644
index 0000000..1ba9d96
--- /dev/null
+++ b/arch/arm/configs/msm8953-batcam_defconfig
@@ -0,0 +1,272 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SCHED_WALT=y
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_ALL=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHEDTUNE=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_CGROUP_BPF=y
+# CONFIG_UTS_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_SCHED_TUNE=y
+CONFIG_DEFAULT_USE_ENERGY_AWARE=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_BPF_SYSCALL=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_CC_STACKPROTECTOR_STRONG=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_MSM8953=y
+# CONFIG_VDSO is not set
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_VMSPLIT_3G_OPT=y
+CONFIG_NR_CPUS=8
+CONFIG_ARM_PSCI=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_CMA=y
+CONFIG_CMA_DEBUGFS=y
+CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_SECCOMP=y
+CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
+CONFIG_IMG_DTB=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_BOOST=y
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_CPU_FREQ_MSM=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_KERNEL_MODE_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HIBERNATION=y
+CONFIG_HIBERNATION_IMAGE_REUSE=y
+CONFIG_PM_STD_PARTITION="/dev/mmcblk0p49"
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_NET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_DMA_CMA=y
+CONFIG_QSEECOM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_NETDEVICES=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_QPNP_POWER_ON=y
+CONFIG_INPUT_UINPUT=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_SERIAL_MSM_SMD=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
+CONFIG_MSM_SMD_PKT=y
+CONFIG_MSM_ADSPRPC=y
+CONFIG_MSM_RDBG=m
+CONFIG_I2C_CHARDEV=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
+CONFIG_PINCTRL_MSM8953=y
+CONFIG_PINCTRL_MSM8917=y
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_QPNP_FG=y
+CONFIG_SMB135X_CHARGER=y
+CONFIG_QPNP_SMB5=y
+CONFIG_QPNP_SMBCHARGER=y
+CONFIG_QPNP_TYPEC=y
+CONFIG_QPNP_QG=y
+CONFIG_MSM_APM=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_THERMAL_TSENS=y
+CONFIG_MSM_BCL_PERIPHERAL_CTL=y
+CONFIG_QTI_THERMAL_LIMITS_DCVS=y
+CONFIG_MFD_SPMI_PMIC=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_PROXY_CONSUMER=y
+CONFIG_REGULATOR_CPR=y
+CONFIG_REGULATOR_CPR4_APSS=y
+CONFIG_REGULATOR_CPRH_KBSS=y
+CONFIG_REGULATOR_MEM_ACC=y
+CONFIG_REGULATOR_MSM_GFX_LDO=y
+CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_QPNP_LCDB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_RPM_SMD=y
+CONFIG_REGULATOR_SPM=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
+CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_SOC=y
+CONFIG_UHID=y
+CONFIG_MMC=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_CQ_HCI=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_QTI_TRI_LED=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_QPNP_FLASH=y
+CONFIG_LEDS_QPNP_FLASH_V2=y
+CONFIG_LEDS_QPNP_WLED=y
+CONFIG_LEDS_QPNP_HAPTICS=y
+CONFIG_LEDS_QPNP_VIBRATOR_LDO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_EDAC=y
+CONFIG_EDAC_MM_EDAC=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_DMADEVICES=y
+CONFIG_QCOM_SPS_DMA=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_IPA=y
+CONFIG_RNDIS_IPA=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_COINCELL=y
+CONFIG_QPNP_REVID=y
+CONFIG_MSM_MDSS_PLL=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MAILBOX=y
+CONFIG_ARM_SMMU=y
+CONFIG_QCOM_LAZY_MAPPING=y
+CONFIG_QCOM_RUN_QUEUE_STATS=y
+CONFIG_MSM_SPM=y
+CONFIG_MSM_L2_SPM=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_MSM_RPM_SMD=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_QCOM_SECURE_BUFFER=y
+CONFIG_QCOM_EARLY_RANDOM=y
+CONFIG_MSM_SMEM=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_DEBUG=y
+CONFIG_MSM_TZ_SMMU=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_SSR_GENERIC=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_ICNSS=y
+CONFIG_MSM_PERFORMANCE=y
+CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_PM=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
+CONFIG_QCOM_BIMC_BWMON=y
+CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
+CONFIG_SPDM_SCM=y
+CONFIG_DEVFREQ_SPDM=y
+CONFIG_PWM=y
+CONFIG_PWM_QPNP=y
+CONFIG_PWM_QTI_LPG=y
+CONFIG_QTI_MPM=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_SENSORS_SSC=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_QFMT_V2=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_ECRYPT_FS=y
+CONFIG_ECRYPT_FS_MESSAGING=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF4=y
+CONFIG_FRAME_WARN=2048
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_STACKTRACE=y
+# CONFIG_FTRACE is not set
+CONFIG_SECURITY=y
+CONFIG_HARDENED_USERCOPY=y
+CONFIG_CRYPTO_USER_API_HASH=m
+CONFIG_ARM_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM_NEON=y
+CONFIG_CRYPTO_SHA2_ARM_CE=y
+CONFIG_CRYPTO_AES_ARM_BS=y
+CONFIG_CRYPTO_AES_ARM_CE=y
+CONFIG_QMI_ENCDEC=y
diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig
index 2ba24d9..aa557b0 100644
--- a/arch/arm/configs/msm8953-perf_defconfig
+++ b/arch/arm/configs/msm8953-perf_defconfig
@@ -307,6 +307,10 @@
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_FT5X06=y
 CONFIG_TOUCHSCREEN_GEN_VKEYS=y
+CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y
+CONFIG_TOUCHSCREEN_HIMAX_I2C=y
+CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y
+CONFIG_HMX_DB=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_HBTP_INPUT=y
 CONFIG_INPUT_QPNP_POWER_ON=y
@@ -352,11 +356,19 @@
 CONFIG_MSM_APM=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_THERMAL=y
+CONFIG_THERMAL_WRITABLE_TRIPS=y
+CONFIG_THERMAL_GOV_USER_SPACE=y
+CONFIG_THERMAL_GOV_LOW_LIMITS=y
+CONFIG_CPU_THERMAL=y
+CONFIG_DEVFREQ_THERMAL=y
 CONFIG_THERMAL_QPNP=y
 CONFIG_THERMAL_QPNP_ADC_TM=y
 CONFIG_THERMAL_TSENS=y
-CONFIG_MSM_BCL_PERIPHERAL_CTL=y
-CONFIG_QTI_THERMAL_LIMITS_DCVS=y
+CONFIG_QTI_VIRTUAL_SENSOR=y
+CONFIG_QTI_QMI_COOLING_DEVICE=y
+CONFIG_REGULATOR_COOLING_DEVICE=y
+CONFIG_QTI_BCL_PMIC5=y
+CONFIG_QTI_BCL_SOC_DRIVER=y
 CONFIG_MFD_SPMI_PMIC=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig
index 8299018..f38341d 100644
--- a/arch/arm/configs/msm8953_defconfig
+++ b/arch/arm/configs/msm8953_defconfig
@@ -312,6 +312,10 @@
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_FT5X06=y
 CONFIG_TOUCHSCREEN_GEN_VKEYS=y
+CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y
+CONFIG_TOUCHSCREEN_HIMAX_I2C=y
+CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y
+CONFIG_HMX_DB=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_HBTP_INPUT=y
 CONFIG_INPUT_QPNP_POWER_ON=y
@@ -359,11 +363,19 @@
 CONFIG_MSM_APM=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_THERMAL=y
+CONFIG_THERMAL_WRITABLE_TRIPS=y
+CONFIG_THERMAL_GOV_USER_SPACE=y
+CONFIG_THERMAL_GOV_LOW_LIMITS=y
+CONFIG_CPU_THERMAL=y
+CONFIG_DEVFREQ_THERMAL=y
 CONFIG_THERMAL_QPNP=y
 CONFIG_THERMAL_QPNP_ADC_TM=y
 CONFIG_THERMAL_TSENS=y
-CONFIG_MSM_BCL_PERIPHERAL_CTL=y
-CONFIG_QTI_THERMAL_LIMITS_DCVS=y
+CONFIG_QTI_VIRTUAL_SENSOR=y
+CONFIG_QTI_QMI_COOLING_DEVICE=y
+CONFIG_REGULATOR_COOLING_DEVICE=y
+CONFIG_QTI_BCL_PMIC5=y
+CONFIG_QTI_BCL_SOC_DRIVER=y
 CONFIG_MFD_SPMI_PMIC=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig
index 04affb1..14c2a7c 100644
--- a/arch/arm/configs/sdxpoorwills-perf_defconfig
+++ b/arch/arm/configs/sdxpoorwills-perf_defconfig
@@ -222,6 +222,7 @@
 CONFIG_INPUT_GPIO=m
 CONFIG_SERIO_LIBPS2=y
 # CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM=y
 CONFIG_SERIAL_MSM_HS=y
 CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
@@ -381,6 +382,9 @@
 CONFIG_QTI_RPM_STATS_LOG=y
 CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
 CONFIG_QMP_DEBUGFS_CLIENT=y
+CONFIG_ARM_MEMLAT_MON=y
+CONFIG_DEVFREQ_GOV_MEMLAT=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
 CONFIG_EXTCON_QCOM_SPMI_MISC=y
 CONFIG_IIO=y
 CONFIG_PWM=y
@@ -399,6 +403,7 @@
 CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_INFO=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_PANIC_ON_RECURSIVE_FAULT=y
 CONFIG_PANIC_TIMEOUT=5
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_SCHEDSTATS=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index 4232b47..b259dc7 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -386,6 +386,8 @@
 CONFIG_QTI_RPM_STATS_LOG=y
 CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
 CONFIG_QMP_DEBUGFS_CLIENT=y
+CONFIG_ARM_MEMLAT_MON=y
+CONFIG_DEVFREQ_GOV_MEMLAT=y
 CONFIG_QCOM_DEVFREQ_DEVBW=y
 CONFIG_EXTCON_QCOM_SPMI_MISC=y
 CONFIG_IIO=y
@@ -411,6 +413,7 @@
 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_PANIC_ON_RECURSIVE_FAULT=y
 CONFIG_PANIC_TIMEOUT=5
 CONFIG_SCHEDSTATS=y
 CONFIG_DEBUG_SPINLOCK=y
diff --git a/arch/arm/include/asm/dma-contiguous.h b/arch/arm/include/asm/dma-contiguous.h
index 4f8e9e5..2dbb8c6 100644
--- a/arch/arm/include/asm/dma-contiguous.h
+++ b/arch/arm/include/asm/dma-contiguous.h
@@ -1,14 +1,25 @@
+/*
+ * Copyright (c) 2016-2018, 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 ASMARM_DMA_CONTIGUOUS_H
 #define ASMARM_DMA_CONTIGUOUS_H
 
 #ifdef __KERNEL__
-#ifdef CONFIG_DMA_CMA
 
 #include <linux/types.h>
 
 void dma_contiguous_early_fixup(phys_addr_t base, unsigned long size);
 
 #endif
-#endif
 
 #endif
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index d5423ab..9fe1043 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -318,4 +318,10 @@
 	return -ENXIO;
 }
 
+static inline bool kvm_arm_harden_branch_predictor(void)
+{
+	/* No way to detect it yet, pretend it is not there. */
+	return false;
+}
+
 #endif /* __ARM_KVM_HOST_H__ */
diff --git a/arch/arm/include/asm/kvm_psci.h b/arch/arm/include/asm/kvm_psci.h
deleted file mode 100644
index 6bda945..0000000
--- a/arch/arm/include/asm/kvm_psci.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2012 - ARM Ltd
- * Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __ARM_KVM_PSCI_H__
-#define __ARM_KVM_PSCI_H__
-
-#define KVM_ARM_PSCI_0_1	1
-#define KVM_ARM_PSCI_0_2	2
-
-int kvm_psci_version(struct kvm_vcpu *vcpu);
-int kvm_psci_call(struct kvm_vcpu *vcpu);
-
-#endif /* __ARM_KVM_PSCI_H__ */
diff --git a/arch/arm/include/asm/xen/events.h b/arch/arm/include/asm/xen/events.h
index 71e473d..620dc75 100644
--- a/arch/arm/include/asm/xen/events.h
+++ b/arch/arm/include/asm/xen/events.h
@@ -16,7 +16,7 @@
 	return raw_irqs_disabled_flags(regs->ARM_cpsr);
 }
 
-#define xchg_xen_ulong(ptr, val) atomic64_xchg(container_of((ptr),	\
+#define xchg_xen_ulong(ptr, val) atomic64_xchg(container_of((long long*)(ptr),\
 							    atomic64_t,	\
 							    counter), (val))
 
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 4f9e2b5..5b6cb33 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -1066,8 +1066,6 @@
 {
 	unsigned long config_base = 0;
 
-	if (attr->exclude_idle)
-		return -EPERM;
 	if (attr->exclude_user)
 		config_base |= ARMV7_EXCLUDE_USER;
 	if (attr->exclude_kernel)
@@ -1184,11 +1182,68 @@
 	*nb_cnt += 1;
 }
 
-static int armv7_probe_num_events(struct arm_pmu *arm_pmu)
+static void armv7_pmu_idle_update(struct arm_pmu *cpu_pmu)
 {
-	return smp_call_function_any(&arm_pmu->supported_cpus,
+	struct pmu_hw_events *hw_events;
+	struct perf_event *event;
+	int idx;
+
+	if (!cpu_pmu)
+		return;
+
+	hw_events = this_cpu_ptr(cpu_pmu->hw_events);
+	if (!hw_events)
+		return;
+
+	for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
+		event = hw_events->events[idx];
+
+		if (!event || !event->attr.exclude_idle ||
+			event->state != PERF_EVENT_STATE_ACTIVE)
+			continue;
+
+		cpu_pmu->pmu.read(event);
+	}
+}
+
+struct armv7_pmu_idle_nb {
+	struct arm_pmu *cpu_pmu;
+	struct notifier_block perf_cpu_idle_nb;
+};
+
+static int armv7_pmu_idle_notifier(struct notifier_block *nb,
+				unsigned long action, void *data)
+{
+	struct armv7_pmu_idle_nb *pmu_idle_nb = container_of(nb,
+				struct armv7_pmu_idle_nb, perf_cpu_idle_nb);
+
+	if (action == IDLE_START)
+		armv7_pmu_idle_update(pmu_idle_nb->cpu_pmu);
+
+	return NOTIFY_OK;
+}
+
+static int armv7_probe_pmu(struct arm_pmu *arm_pmu)
+{
+	int ret;
+	struct armv7_pmu_idle_nb *pmu_idle_nb;
+
+	pmu_idle_nb = devm_kzalloc(&arm_pmu->plat_device->dev,
+				sizeof(*pmu_idle_nb), GFP_KERNEL);
+	if (!pmu_idle_nb)
+		return -ENOMEM;
+
+	ret = smp_call_function_any(&arm_pmu->supported_cpus,
 				     armv7_read_num_pmnc_events,
 				     &arm_pmu->num_events, 1);
+	if (ret)
+		return ret;
+
+	pmu_idle_nb->cpu_pmu = arm_pmu;
+	pmu_idle_nb->perf_cpu_idle_nb.notifier_call = armv7_pmu_idle_notifier;
+	idle_notifier_register(&pmu_idle_nb->perf_cpu_idle_nb);
+
+	return 0;
 }
 
 static int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1200,7 +1255,7 @@
 		&armv7_pmuv1_events_attr_group;
 	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
 		&armv7_pmu_format_attr_group;
-	return armv7_probe_num_events(cpu_pmu);
+	return armv7_probe_pmu(cpu_pmu);
 }
 
 static int armv7_a9_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1212,7 +1267,7 @@
 		&armv7_pmuv1_events_attr_group;
 	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
 		&armv7_pmu_format_attr_group;
-	return armv7_probe_num_events(cpu_pmu);
+	return armv7_probe_pmu(cpu_pmu);
 }
 
 static int armv7_a5_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1224,7 +1279,7 @@
 		&armv7_pmuv1_events_attr_group;
 	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
 		&armv7_pmu_format_attr_group;
-	return armv7_probe_num_events(cpu_pmu);
+	return armv7_probe_pmu(cpu_pmu);
 }
 
 static int armv7_a15_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1237,7 +1292,7 @@
 		&armv7_pmuv2_events_attr_group;
 	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
 		&armv7_pmu_format_attr_group;
-	return armv7_probe_num_events(cpu_pmu);
+	return armv7_probe_pmu(cpu_pmu);
 }
 
 static int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1250,7 +1305,7 @@
 		&armv7_pmuv2_events_attr_group;
 	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
 		&armv7_pmu_format_attr_group;
-	return armv7_probe_num_events(cpu_pmu);
+	return armv7_probe_pmu(cpu_pmu);
 }
 
 static int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1263,7 +1318,7 @@
 		&armv7_pmuv2_events_attr_group;
 	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
 		&armv7_pmu_format_attr_group;
-	return armv7_probe_num_events(cpu_pmu);
+	return armv7_probe_pmu(cpu_pmu);
 }
 
 static int armv7_a17_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1660,7 +1715,7 @@
 	cpu_pmu->disable	= krait_pmu_disable_event;
 	cpu_pmu->get_event_idx	= krait_pmu_get_event_idx;
 	cpu_pmu->clear_event_idx = krait_pmu_clear_event_idx;
-	return armv7_probe_num_events(cpu_pmu);
+	return armv7_probe_pmu(cpu_pmu);
 }
 
 /*
@@ -1983,7 +2038,7 @@
 	cpu_pmu->disable	= scorpion_pmu_disable_event;
 	cpu_pmu->get_event_idx	= scorpion_pmu_get_event_idx;
 	cpu_pmu->clear_event_idx = scorpion_pmu_clear_event_idx;
-	return armv7_probe_num_events(cpu_pmu);
+	return armv7_probe_pmu(cpu_pmu);
 }
 
 static int scorpion_mp_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1996,7 +2051,7 @@
 	cpu_pmu->disable	= scorpion_pmu_disable_event;
 	cpu_pmu->get_event_idx	= scorpion_pmu_get_event_idx;
 	cpu_pmu->clear_event_idx = scorpion_pmu_clear_event_idx;
-	return armv7_probe_num_events(cpu_pmu);
+	return armv7_probe_pmu(cpu_pmu);
 }
 
 static const struct of_device_id armv7_pmu_of_device_ids[] = {
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index c6324b5..38ad8b9 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -129,13 +129,13 @@
 		for (j = 0; j < 8; j++) {
 			u32	data;
 			if (probe_kernel_address(p, data)) {
-				printk(" ********");
+				pr_cont(" ********");
 			} else {
-				printk(" %08x", data);
+				pr_cont(" %08x", data);
 			}
 			++p;
 		}
-		printk("\n");
+		pr_cont("\n");
 	}
 }
 
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index ab509d6..a03a99a 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -672,6 +672,8 @@
 
 	if ((unsigned)ipinr < NR_IPI)
 		trace_ipi_exit_rcuidle(ipi_types[ipinr]);
+
+	per_cpu(pending_ipi, cpu) = false;
 	set_irq_regs(old_regs);
 }
 
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index c38bfbe..ef6595c 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -29,6 +29,7 @@
 #include <linux/kvm.h>
 #include <trace/events/kvm.h>
 #include <kvm/arm_pmu.h>
+#include <kvm/arm_psci.h>
 
 #define CREATE_TRACE_POINTS
 #include "trace.h"
@@ -44,7 +45,6 @@
 #include <asm/kvm_mmu.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_coproc.h>
-#include <asm/kvm_psci.h>
 #include <asm/sections.h>
 
 #ifdef REQUIRES_VIRT
@@ -1088,7 +1088,7 @@
 	pgd_ptr = kvm_mmu_get_httbr();
 	stack_page = __this_cpu_read(kvm_arm_hyp_stack_page);
 	hyp_stack_ptr = stack_page + PAGE_SIZE;
-	vector_ptr = (unsigned long)kvm_ksym_ref(__kvm_hyp_vector);
+	vector_ptr = (unsigned long)kvm_get_hyp_vector();
 
 	__cpu_init_hyp_mode(pgd_ptr, hyp_stack_ptr, vector_ptr);
 	__cpu_init_stage2();
@@ -1345,6 +1345,13 @@
 		goto out_err;
 	}
 
+
+	err = kvm_map_vectors();
+	if (err) {
+		kvm_err("Cannot map vectors\n");
+		goto out_err;
+	}
+
 	/*
 	 * Map the Hyp stack pages
 	 */
diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index 4e57ebc..de1aedc 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -21,7 +21,7 @@
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_coproc.h>
 #include <asm/kvm_mmu.h>
-#include <asm/kvm_psci.h>
+#include <kvm/arm_psci.h>
 #include <trace/events/kvm.h>
 
 #include "trace.h"
@@ -36,7 +36,7 @@
 		      kvm_vcpu_hvc_get_imm(vcpu));
 	vcpu->stat.hvc_exit_stat++;
 
-	ret = kvm_psci_call(vcpu);
+	ret = kvm_hvc_call_handler(vcpu);
 	if (ret < 0) {
 		vcpu_set_reg(vcpu, 0, ~0UL);
 		return 1;
diff --git a/arch/arm/kvm/hyp/switch.c b/arch/arm/kvm/hyp/switch.c
index 624a510..ebd2dd4 100644
--- a/arch/arm/kvm/hyp/switch.c
+++ b/arch/arm/kvm/hyp/switch.c
@@ -237,8 +237,10 @@
 
 		vcpu = (struct kvm_vcpu *)read_sysreg(HTPIDR);
 		host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+		__timer_save_state(vcpu);
 		__deactivate_traps(vcpu);
 		__deactivate_vm(vcpu);
+		__banked_restore_state(host_ctxt);
 		__sysreg_restore_state(host_ctxt);
 	}
 
diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c
index a08d7a9..3d96225 100644
--- a/arch/arm/kvm/psci.c
+++ b/arch/arm/kvm/psci.c
@@ -15,16 +15,16 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/arm-smccc.h>
 #include <linux/preempt.h>
 #include <linux/kvm_host.h>
 #include <linux/wait.h>
 
 #include <asm/cputype.h>
 #include <asm/kvm_emulate.h>
-#include <asm/kvm_psci.h>
 #include <asm/kvm_host.h>
 
-#include <uapi/linux/psci.h>
+#include <kvm/arm_psci.h>
 
 /*
  * This is an implementation of the Power State Coordination Interface
@@ -33,6 +33,38 @@
 
 #define AFFINITY_MASK(level)	~((0x1UL << ((level) * MPIDR_LEVEL_BITS)) - 1)
 
+static u32 smccc_get_function(struct kvm_vcpu *vcpu)
+{
+	return vcpu_get_reg(vcpu, 0);
+}
+
+static unsigned long smccc_get_arg1(struct kvm_vcpu *vcpu)
+{
+	return vcpu_get_reg(vcpu, 1);
+}
+
+static unsigned long smccc_get_arg2(struct kvm_vcpu *vcpu)
+{
+	return vcpu_get_reg(vcpu, 2);
+}
+
+static unsigned long smccc_get_arg3(struct kvm_vcpu *vcpu)
+{
+	return vcpu_get_reg(vcpu, 3);
+}
+
+static void smccc_set_retval(struct kvm_vcpu *vcpu,
+			     unsigned long a0,
+			     unsigned long a1,
+			     unsigned long a2,
+			     unsigned long a3)
+{
+	vcpu_set_reg(vcpu, 0, a0);
+	vcpu_set_reg(vcpu, 1, a1);
+	vcpu_set_reg(vcpu, 2, a2);
+	vcpu_set_reg(vcpu, 3, a3);
+}
+
 static unsigned long psci_affinity_mask(unsigned long affinity_level)
 {
 	if (affinity_level <= 3)
@@ -75,7 +107,7 @@
 	unsigned long context_id;
 	phys_addr_t target_pc;
 
-	cpu_id = vcpu_get_reg(source_vcpu, 1) & MPIDR_HWID_BITMASK;
+	cpu_id = smccc_get_arg1(source_vcpu) & MPIDR_HWID_BITMASK;
 	if (vcpu_mode_is_32bit(source_vcpu))
 		cpu_id &= ~((u32) 0);
 
@@ -88,14 +120,14 @@
 	if (!vcpu)
 		return PSCI_RET_INVALID_PARAMS;
 	if (!vcpu->arch.power_off) {
-		if (kvm_psci_version(source_vcpu) != KVM_ARM_PSCI_0_1)
+		if (kvm_psci_version(source_vcpu, kvm) != KVM_ARM_PSCI_0_1)
 			return PSCI_RET_ALREADY_ON;
 		else
 			return PSCI_RET_INVALID_PARAMS;
 	}
 
-	target_pc = vcpu_get_reg(source_vcpu, 2);
-	context_id = vcpu_get_reg(source_vcpu, 3);
+	target_pc = smccc_get_arg2(source_vcpu);
+	context_id = smccc_get_arg3(source_vcpu);
 
 	kvm_reset_vcpu(vcpu);
 
@@ -114,7 +146,7 @@
 	 * NOTE: We always update r0 (or x0) because for PSCI v0.1
 	 * the general puspose registers are undefined upon CPU_ON.
 	 */
-	vcpu_set_reg(vcpu, 0, context_id);
+	smccc_set_retval(vcpu, context_id, 0, 0, 0);
 	vcpu->arch.power_off = false;
 	smp_mb();		/* Make sure the above is visible */
 
@@ -134,8 +166,8 @@
 	struct kvm *kvm = vcpu->kvm;
 	struct kvm_vcpu *tmp;
 
-	target_affinity = vcpu_get_reg(vcpu, 1);
-	lowest_affinity_level = vcpu_get_reg(vcpu, 2);
+	target_affinity = smccc_get_arg1(vcpu);
+	lowest_affinity_level = smccc_get_arg2(vcpu);
 
 	/* Determine target affinity mask */
 	target_affinity_mask = psci_affinity_mask(lowest_affinity_level);
@@ -198,18 +230,10 @@
 	kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_RESET);
 }
 
-int kvm_psci_version(struct kvm_vcpu *vcpu)
-{
-	if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
-		return KVM_ARM_PSCI_0_2;
-
-	return KVM_ARM_PSCI_0_1;
-}
-
 static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
-	unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
+	unsigned long psci_fn = smccc_get_function(vcpu);
 	unsigned long val;
 	int ret = 1;
 
@@ -219,7 +243,7 @@
 		 * Bits[31:16] = Major Version = 0
 		 * Bits[15:0] = Minor Version = 2
 		 */
-		val = 2;
+		val = KVM_ARM_PSCI_0_2;
 		break;
 	case PSCI_0_2_FN_CPU_SUSPEND:
 	case PSCI_0_2_FN64_CPU_SUSPEND:
@@ -276,14 +300,56 @@
 		break;
 	}
 
-	vcpu_set_reg(vcpu, 0, val);
+	smccc_set_retval(vcpu, val, 0, 0, 0);
+	return ret;
+}
+
+static int kvm_psci_1_0_call(struct kvm_vcpu *vcpu)
+{
+	u32 psci_fn = smccc_get_function(vcpu);
+	u32 feature;
+	unsigned long val;
+	int ret = 1;
+
+	switch(psci_fn) {
+	case PSCI_0_2_FN_PSCI_VERSION:
+		val = KVM_ARM_PSCI_1_0;
+		break;
+	case PSCI_1_0_FN_PSCI_FEATURES:
+		feature = smccc_get_arg1(vcpu);
+		switch(feature) {
+		case PSCI_0_2_FN_PSCI_VERSION:
+		case PSCI_0_2_FN_CPU_SUSPEND:
+		case PSCI_0_2_FN64_CPU_SUSPEND:
+		case PSCI_0_2_FN_CPU_OFF:
+		case PSCI_0_2_FN_CPU_ON:
+		case PSCI_0_2_FN64_CPU_ON:
+		case PSCI_0_2_FN_AFFINITY_INFO:
+		case PSCI_0_2_FN64_AFFINITY_INFO:
+		case PSCI_0_2_FN_MIGRATE_INFO_TYPE:
+		case PSCI_0_2_FN_SYSTEM_OFF:
+		case PSCI_0_2_FN_SYSTEM_RESET:
+		case PSCI_1_0_FN_PSCI_FEATURES:
+		case ARM_SMCCC_VERSION_FUNC_ID:
+			val = 0;
+			break;
+		default:
+			val = PSCI_RET_NOT_SUPPORTED;
+			break;
+		}
+		break;
+	default:
+		return kvm_psci_0_2_call(vcpu);
+	}
+
+	smccc_set_retval(vcpu, val, 0, 0, 0);
 	return ret;
 }
 
 static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
-	unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
+	unsigned long psci_fn = smccc_get_function(vcpu);
 	unsigned long val;
 
 	switch (psci_fn) {
@@ -301,7 +367,7 @@
 		break;
 	}
 
-	vcpu_set_reg(vcpu, 0, val);
+	smccc_set_retval(vcpu, val, 0, 0, 0);
 	return 1;
 }
 
@@ -319,9 +385,11 @@
  * Errors:
  * -EINVAL: Unrecognized PSCI function
  */
-int kvm_psci_call(struct kvm_vcpu *vcpu)
+static int kvm_psci_call(struct kvm_vcpu *vcpu)
 {
-	switch (kvm_psci_version(vcpu)) {
+	switch (kvm_psci_version(vcpu, vcpu->kvm)) {
+	case KVM_ARM_PSCI_1_0:
+		return kvm_psci_1_0_call(vcpu);
 	case KVM_ARM_PSCI_0_2:
 		return kvm_psci_0_2_call(vcpu);
 	case KVM_ARM_PSCI_0_1:
@@ -330,3 +398,30 @@
 		return -EINVAL;
 	};
 }
+
+int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
+{
+	u32 func_id = smccc_get_function(vcpu);
+	u32 val = PSCI_RET_NOT_SUPPORTED;
+	u32 feature;
+
+	switch (func_id) {
+	case ARM_SMCCC_VERSION_FUNC_ID:
+		val = ARM_SMCCC_VERSION_1_1;
+		break;
+	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
+		feature = smccc_get_arg1(vcpu);
+		switch(feature) {
+		case ARM_SMCCC_ARCH_WORKAROUND_1:
+			if (kvm_arm_harden_branch_predictor())
+				val = 0;
+			break;
+		}
+		break;
+	default:
+		return kvm_psci_call(vcpu);
+	}
+
+	smccc_set_retval(vcpu, val, 0, 0, 0);
+	return 1;
+}
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index add3771..9a22d40 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -821,6 +821,8 @@
 	.resource	= da8xx_rproc_resources,
 };
 
+static bool rproc_mem_inited __initdata;
+
 #if IS_ENABLED(CONFIG_DA8XX_REMOTEPROC)
 
 static phys_addr_t rproc_base __initdata;
@@ -859,6 +861,8 @@
 	ret = dma_declare_contiguous(&da8xx_dsp.dev, rproc_size, rproc_base, 0);
 	if (ret)
 		pr_err("%s: dma_declare_contiguous failed %d\n", __func__, ret);
+	else
+		rproc_mem_inited = true;
 }
 
 #else
@@ -873,6 +877,12 @@
 {
 	int ret;
 
+	if (!rproc_mem_inited) {
+		pr_warn("%s: memory not reserved for DSP, not registering DSP device\n",
+			__func__);
+		return -ENOMEM;
+	}
+
 	ret = platform_device_register(&da8xx_dsp);
 	if (ret)
 		pr_err("%s: can't register DSP device: %d\n", __func__, ret);
diff --git a/arch/arm/mach-imx/cpu.c b/arch/arm/mach-imx/cpu.c
index b3347d3..94906ed 100644
--- a/arch/arm/mach-imx/cpu.c
+++ b/arch/arm/mach-imx/cpu.c
@@ -131,6 +131,9 @@
 	case MXC_CPU_IMX6UL:
 		soc_id = "i.MX6UL";
 		break;
+	case MXC_CPU_IMX6ULL:
+		soc_id = "i.MX6ULL";
+		break;
 	case MXC_CPU_IMX7D:
 		soc_id = "i.MX7D";
 		break;
diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h
index 34f2ff6..e00d626 100644
--- a/arch/arm/mach-imx/mxc.h
+++ b/arch/arm/mach-imx/mxc.h
@@ -39,6 +39,7 @@
 #define MXC_CPU_IMX6SX		0x62
 #define MXC_CPU_IMX6Q		0x63
 #define MXC_CPU_IMX6UL		0x64
+#define MXC_CPU_IMX6ULL		0x65
 #define MXC_CPU_IMX7D		0x72
 
 #define IMX_DDR_TYPE_LPDDR2		1
@@ -73,6 +74,11 @@
 	return __mxc_cpu_type == MXC_CPU_IMX6UL;
 }
 
+static inline bool cpu_is_imx6ull(void)
+{
+	return __mxc_cpu_type == MXC_CPU_IMX6ULL;
+}
+
 static inline bool cpu_is_imx6q(void)
 {
 	return __mxc_cpu_type == MXC_CPU_IMX6Q;
diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig
index 1ab1fbb..b055b60 100644
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -65,6 +65,17 @@
 	select HAVE_CLK_PREPARE
 	select COMMON_CLK_MSM
 
+config ARCH_MSM8953_BOOT_ORDERING
+	bool "Enable support for MSM8953 device boot ordering"
+	default n
+	help
+	  Populate devices from devicetree at late_init, after
+	  drivers for all platform devices have been registered.
+	  This causes devices to be probed in the order they are
+	  listed in devicetree. Thus it is possible to have
+	  greater control over the probe ordering such that
+	  overall boot time can be reduced.
+
 config ARCH_MSM8937
 	bool "Enable support for MSM8937"
 	select CPU_V7
diff --git a/arch/arm/mach-qcom/board-msm8953.c b/arch/arm/mach-qcom/board-msm8953.c
index 04b0bcc..de4538f 100644
--- a/arch/arm/mach-qcom/board-msm8953.c
+++ b/arch/arm/mach-qcom/board-msm8953.c
@@ -14,6 +14,7 @@
 #include "board-dt.h"
 #include <asm/mach/map.h>
 #include <asm/mach/arch.h>
+#include <linux/of_platform.h>
 
 static const char *msm8953_dt_match[] __initconst = {
 	"qcom,msm8953",
@@ -23,9 +24,25 @@
 
 static void __init msm8953_init(void)
 {
+	if (IS_ENABLED(CONFIG_ARCH_MSM8953_BOOT_ORDERING))
+		return;
 	board_dt_populate(NULL);
 }
 
+#ifdef CONFIG_ARCH_MSM8953_BOOT_ORDERING
+static int __init msm8953_dt_populate(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+
+	/* Explicitly parent the /soc devices to the root node to preserve
+	 * the kernel ABI (sysfs structure, etc) until userspace is updated
+	 */
+	of_platform_populate(of_find_node_by_path("/soc"),
+			     of_default_bus_match_table, NULL, NULL);
+}
+late_initcall(msm8953_dt_populate);
+#endif
+
 DT_MACHINE_START(MSM8953_DT,
 	"Qualcomm Technologies, Inc. MSM8953 (Flattened Device Tree)")
 	.init_machine		= msm8953_init,
diff --git a/arch/arm/mach-qcom/board-sdm429.c b/arch/arm/mach-qcom/board-sdm429.c
index c648eaf..6bdf0f4 100644
--- a/arch/arm/mach-qcom/board-sdm429.c
+++ b/arch/arm/mach-qcom/board-sdm429.c
@@ -17,6 +17,7 @@
 
 static const char *sdm429_dt_match[] __initconst = {
 	"qcom,sdm429",
+	"qcom,sda429",
 	NULL
 };
 
diff --git a/arch/arm/mach-qcom/board-sdm439.c b/arch/arm/mach-qcom/board-sdm439.c
index 312f3a5..7b9aa0f 100644
--- a/arch/arm/mach-qcom/board-sdm439.c
+++ b/arch/arm/mach-qcom/board-sdm439.c
@@ -17,6 +17,7 @@
 
 static const char *sdm439_dt_match[] __initconst = {
 	"qcom,sdm439",
+	"qcom,sda439",
 	NULL
 };
 
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index da0b33d..5629d75 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -648,7 +648,7 @@
  */
 static int vfp_dying_cpu(unsigned int cpu)
 {
-	vfp_force_reload(cpu, current_thread_info());
+	vfp_current_hw_state[cpu] = NULL;
 	return 0;
 }
 
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 1b135e5..9c01a31 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -825,6 +825,18 @@
 
 	  If unsure, say Y.
 
+config PSCI_BP_HARDENING
+	depends on HARDEN_BRANCH_PREDICTOR
+	bool "Use PSCI get version to enable branch predictor hardening"
+	help
+	  If the mitigation for branch prediction is supported using psci
+	  get version by the firmware then enable this option. Some older
+	  versions of firmwares may not be using new SMCCC convention in
+	  such cases use psci get version method to enable hardening for
+	  branch prediction attacks.
+
+	  If unsure, say N.
+
 menuconfig ARMV8_DEPRECATED
 	bool "Emulate deprecated/obsolete ARMv8 instructions"
 	depends on COMPAT
diff --git a/arch/arm64/boot/dts/qcom/8909w-pm660.dtsi b/arch/arm64/boot/dts/qcom/8909w-pm660.dtsi
index 3947406..c8330bd 100644
--- a/arch/arm64/boot/dts/qcom/8909w-pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/8909w-pm660.dtsi
@@ -79,6 +79,31 @@
 	};
 };
 
+&msm_gpio {
+	/delete-node/ mpu6050_int_pin;
+	/delete-node/ apds99xx_int_pin;
+	/delete-node/ ak8963_int_pin;
+
+	pmx_mdss {
+		mdss_dsi_active: mdss_dsi_active {
+			mux {
+				pins = "gpio25", "gpio37", "gpio59";
+			};
+			config {
+				pins = "gpio25", "gpio37", "gpio59";
+			};
+		};
+		mdss_dsi_suspend: mdss_dsi_suspend {
+			mux {
+				pins = "gpio25", "gpio37", "gpio59";
+			};
+			config {
+				pins = "gpio25", "gpio37", "gpio59";
+			};
+		};
+	};
+};
+
 &i2c_3 {
 	qcom,actuator@0 {
 		/delete-property/ cam_vaf-supply;
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 31d4b0d..98238d9 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -308,7 +308,8 @@
 
 dtbo-$(CONFIG_ARCH_SDM439) += sdm439-mtp-overlay.dtbo \
 	sdm439-cdp-overlay.dtbo \
-	sdm439-qrd-overlay.dtbo
+	sdm439-qrd-overlay.dtbo \
+	sdm439-external-codec-mtp-overlay.dtbo
 
 dtbo-$(CONFIG_ARCH_SDM429) += sdm429-mtp-overlay.dtbo \
 	sdm429-cdp-overlay.dtbo \
@@ -368,14 +369,19 @@
 	sdm632-pm8004.dtb
 
 sdm439-mtp-overlay.dtbo-base := sdm439.dtb \
+	sda439.dtb \
 	msm8937-interposer-sdm439.dtb
 sdm439-cdp-overlay.dtbo-base := sdm439.dtb \
+	sda439.dtb \
 	msm8937-interposer-sdm439.dtb
 sdm439-qrd-overlay.dtbo-base := sdm439.dtb \
 	msm8937-interposer-sdm439.dtb
+sdm439-external-codec-mtp-overlay.dtbo-base := sdm439.dtb
 sdm429-mtp-overlay.dtbo-base := sdm429.dtb \
+	sda429.dtb \
 	msm8937-interposer-sdm429.dtb
 sdm429-cdp-overlay.dtbo-base := sdm429.dtb \
+	sda429.dtb \
 	msm8937-interposer-sdm429.dtb
 sdm429-qrd-overlay.dtbo-base := sdm429.dtb \
 	msm8937-interposer-sdm429.dtb
@@ -398,6 +404,10 @@
 	apq8053-iot-mtp.dtb \
 	apq8053-lite-dragon-v1.0.dtb \
 	apq8053-lite-dragon-v2.0.dtb \
+	apq8053-lite-lenovo-v1.0.dtb \
+	apq8053-lite-lenovo-v1.1.dtb \
+	apq8053-lite-harman-v1.0.dtb \
+	apq8053-lite-lge-v1.0.dtb \
 	msm8953-pmi8940-cdp.dtb \
 	msm8953-pmi8940-mtp.dtb \
 	msm8953-pmi8937-cdp.dtb \
@@ -414,14 +424,29 @@
 	msm8937-interposer-sdm429-mtp.dtb
 
 dtb-$(CONFIG_ARCH_MSM8917) += msm8917-pmi8950-mtp.dtb \
+	msm8917-pmi8950-cdp.dtb \
+	msm8917-pmi8950-rcm.dtb \
+	msm8917-pmi8950-ext-codec-cdp.dtb \
+	msm8917-pmi8950-cdp-mirror-lake-touch.dtb \
+	apq8017-pmi8950-cdp-wcd-rome.dtb \
+	apq8017-pmi8950-mtp.dtb \
+	apq8017-pmi8950-cdp.dtb \
 	msm8917-pmi8937-qrd-sku5.dtb \
+	msm8917-pmi8937-mtp.dtb \
+	msm8917-pmi8937-cdp.dtb \
+	msm8917-pmi8937-rcm.dtb \
+	apq8017-pmi8937-mtp.dtb \
+	apq8017-pmi8937-cdp.dtb \
+	apq8017-pmi8937-cdp-wcd-rome.dtb \
 	msm8917-pmi8940-mtp.dtb \
-	msm8917-pmi8937-mtp.dtb
+	msm8917-pmi8940-cdp.dtb \
+	msm8917-pmi8940-rcm.dtb
 
 dtb-$(CONFIG_ARCH_MSM8909) += msm8909w-bg-wtp-v2.dtb \
 	apq8009w-bg-wtp-v2.dtb \
 	apq8009w-bg-alpha.dtb \
 	apq8009-mtp-wcd9326-refboard.dtb \
+	apq8009-robot-som-refboard.dtb \
 	apq8009-dragon.dtb
 
 dtb-$(CONFIG_ARCH_SDM450) += sdm450-rcm.dtb \
@@ -459,7 +484,8 @@
 	sdm439-cdp.dtb \
 	sdm439-qrd.dtb \
 	sda439-mtp.dtb \
-	sda439-cdp.dtb
+	sda439-cdp.dtb \
+	sdm439-external-codec-mtp.dtb
 
 dtb-$(CONFIG_ARCH_SDM429) += sdm429-mtp.dtb \
 	sdm429-cdp.dtb \
diff --git a/arch/arm64/boot/dts/qcom/apq8009-dragon.dts b/arch/arm64/boot/dts/qcom/apq8009-dragon.dts
index 6b3aea0..12a4363 100644
--- a/arch/arm64/boot/dts/qcom/apq8009-dragon.dts
+++ b/arch/arm64/boot/dts/qcom/apq8009-dragon.dts
@@ -66,6 +66,11 @@
 	mdss_mdp: qcom,mdss_mdp@1a00000 {
 		status = "disabled";
 	};
+
+	bluetooth: bt_qca9379 {
+		compatible = "qca,qca9379";
+		qca,bt-reset-gpio = <&msm_gpio 47 0>; /* BT_EN */
+	};
 };
 
 &sdhc_2 {
@@ -133,3 +138,7 @@
 &pm8916_bms {
 	status = "ok";
 };
+
+&blsp1_uart2_hs {
+	status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts b/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts
new file mode 100644
index 0000000..958f7c8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8909-mtp.dtsi"
+#include "8909-pm8916.dtsi"
+#include "msm8909-pm8916-mtp.dtsi"
+#include "apq8009-audio-external_codec.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. APQ8009 Robot SOM refboard";
+	compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp";
+	qcom,msm-id = <265 2>;
+	qcom,board-id = <8 0x15>;
+};
+
+&soc {
+	ext-codec {
+		qcom,msm-mbhc-hphl-swh = <0>;
+		qcom,audio-routing =
+			"AIF4 VI", "MCLK",
+			"RX_BIAS", "MCLK",
+			"MADINPUT", "MCLK",
+			"AMIC2", "MIC BIAS2",
+			"MIC BIAS2", "Headset Mic",
+			"DMIC0", "MIC BIAS1",
+			"MIC BIAS1", "Digital Mic0",
+			"DMIC1", "MIC BIAS1",
+			"MIC BIAS1", "Digital Mic1",
+			"DMIC2", "MIC BIAS3",
+			"MIC BIAS3", "Digital Mic2",
+			"DMIC3", "MIC BIAS3",
+			"MIC BIAS3", "Digital Mic3",
+			"SpkrLeft IN", "SPK1 OUT",
+			"SpkrRight IN", "SPK2 OUT";
+	};
+
+	sound-9335 {
+		status = "disabled";
+	};
+
+	i2c@78b8000 {
+		wcd9xxx_codec@d {
+		  status = "disabled";
+		};
+	};
+
+	vph_pwr_vreg: vph_pwr_vreg {
+		compatible = "regulator-fixed";
+		status = "ok";
+		regulator-name = "vph_pwr";
+		regulator-always-on;
+	};
+
+	mdss_mdp: qcom,mdss_mdp@1a00000 {
+		status = "disabled";
+	};
+
+	bluetooth: bt_qca9379 {
+		compatible = "qca,qca9379";
+		qca,bt-reset-gpio = <&msm_gpio 47 0>; /* BT_EN */
+	};
+	cnss_sdio: qcom,cnss_sdio {
+		compatible = "qcom,cnss_sdio";
+		subsys-name = "AR6320";
+		/**
+		 * There is no vdd-wlan on board and this is not for DSRC.
+		 * IO and XTAL share the same vreg.
+		 */
+		vdd-wlan-io-supply = <&pm8916_l5>;
+		qcom,cap-tsf-gpio = <&msm_gpio 42 1>;
+		qcom,wlan-ramdump-dynamic = <0x200000>;
+		qcom,msm-bus,name = "msm-cnss";
+		qcom,msm-bus,num-cases = <4>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<79 512 0 0>,             /* No vote */
+			<79 512 6250 200000>,     /* 50 Mbps */
+			<79 512 25000 200000>,    /* 200 Mbps */
+			<79 512 2048000 4096000>; /* MAX */
+	};
+};
+
+&wcnss {
+	status = "disabled";
+};
+
+&msm_gpio {
+	sdc2_wlan_gpio_on: sdc2_wlan_gpio_on {
+		mux {
+			pins = "gpio43";
+			function = "gpio";
+		};
+		config {
+			pins = "gpio43";
+			drive-strength = <10>;
+			bias-pull-up;
+			output-high;
+		};
+	};
+
+	sdc2_wlan_gpio_off: sdc2_wlan_gpio_off {
+		mux {
+			pins = "gpio43";
+			function = "gpio";
+		};
+		config {
+			pins = "gpio43";
+			drive-strength = <2>;
+			bias-disable;
+			output-low;
+		};
+	};
+};
+
+&sdhc_2 {
+	/delete-property/cd-gpios;
+	#address-cells = <0>;
+	interrupt-parent = <&sdhc_2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+		1 &intc 0 221 0
+		2 &msm_gpio 38 0>;
+	interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq";
+
+	qcom,vdd-voltage-level = <1800000 2950000>;
+	qcom,vdd-current-level = <15000 400000>;
+
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <200 50000>;
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on
+	&sdc2_wlan_gpio_on>;
+	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off
+	&sdc2_wlan_gpio_off>;
+	qcom,nonremovable;
+	qcom,core_3_0v_support;
+	status = "ok";
+};
+
+&usb_otg {
+	interrupts = <0 134 0>,<0 140 0>,<0 136 0>;
+	interrupt-names = "core_irq", "async_irq", "phy_irq";
+	qcom,hsusb-otg-mode = <3>;
+	qcom,switch-vbus-w-id;
+	vbus_otg-supply = <&vph_pwr_vreg>;
+	extcon = <&pm8916_chg>;
+};
+
+&external_image_mem {
+	reg = <0x0 0x87a00000 0x0 0x0600000>;
+};
+
+&modem_adsp_mem {
+	reg = <0x0 0x88000000 0x0 0x01e00000>;
+};
+
+&peripheral_mem {
+	reg = <0x0 0x89e00000 0x0 0x0700000>;
+};
+
+&pm8916_chg {
+	status = "ok";
+};
+
+&pm8916_bms {
+	status = "ok";
+};
+
+&blsp1_uart2_hs {
+	status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts b/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts
index 89e1b76..1fe7b15 100644
--- a/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts
+++ b/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts
@@ -300,4 +300,5 @@
 &mdss_dsi0 {
 	qcom,dsi-pref-prim-pan = <&dsi_auo_390p_cmd>;
 	qcom,platform-bklight-en-gpio = <&msm_gpio 52 0>;
+	qcom,platform-enable-gpio = <&msm_gpio 59 0>;
 };
diff --git a/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts
index 9fb6626..8113670 100644
--- a/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts
+++ b/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts
@@ -317,4 +317,5 @@
 &mdss_dsi0 {
 	qcom,dsi-pref-prim-pan = <&dsi_auo_390p_cmd>;
 	qcom,platform-bklight-en-gpio = <&msm_gpio 52 0>;
+	qcom,platform-enable-gpio = <&msm_gpio 59 0>;
 };
diff --git a/arch/arm64/boot/dts/qcom/apq8017-audio.dtsi b/arch/arm64/boot/dts/qcom/apq8017-audio.dtsi
new file mode 100644
index 0000000..56f69ad
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017-audio.dtsi
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2017-2018, 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.
+ */
+
+&wsa881x_211 {
+	qcom,spkr-sd-n-gpio = <&tlmm 92 0>;
+};
+
+&wsa881x_212 {
+	qcom,spkr-sd-n-gpio = <&tlmm 92 0>;
+};
+
+&wsa881x_213 {
+	qcom,spkr-sd-n-gpio = <&tlmm 92 0>;
+};
+
+&wsa881x_214 {
+	qcom,spkr-sd-n-gpio = <&tlmm 92 0>;
+};
+
+&pm8937_gpios {
+	gpio@c000 {
+		status = "ok";
+		qcom,mode = <1>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <0>;
+		qcom,src-sel = <2>;
+		qcom,master-en = <1>;
+		qcom,out-strength = <2>;
+	};
+
+	gpio@c600 {
+		status = "ok";
+		qcom,mode = <1>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <0>;
+		qcom,src-sel = <0>;
+		qcom,master-en = <1>;
+		qcom,out-strength = <2>;
+	};
+};
+
+&slim_msm {
+	status = "okay";
+};
+
+&wcd9xxx_intc {
+	status = "okay";
+};
+
+&clock_audio {
+	status = "okay";
+};
+
+&wcd9335 {
+	status = "okay";
+	cdc-vdd-mic-bias-supply = <&pm8937_l9>;
+	qcom,cdc-vdd-mic-bias-voltage = <3300000 3300000>;
+	qcom,cdc-vdd-mic-bias-current = <15000>;
+};
+
+&wcd_rst_gpio {
+	status = "okay";
+};
+
+&ext_codec {
+	status = "okay";
+	qcom,msm-mbhc-hphl-swh = <1>;
+	qcom,msm-mbhc-gnd-swh = <1>;
+	qcom,tdm-audio-intf;
+	qcom,afe-rxtx-lb;
+	reg = <0xc051000 0x4>,
+		<0xc051004 0x4>,
+		<0xc055000 0x4>,
+		<0xc052000 0x4>,
+		<0x0c056000 0x4>,
+		<0x0c054000 0x4>,
+		<0x0c053000 0x4>;
+	reg-names = "csr_gp_io_mux_mic_ctl",
+		"csr_gp_io_mux_spkr_ctl",
+		"csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel",
+		"csr_gp_io_mux_quin_ctl",
+		"csr_gp_io_lpaif_qui_pcm_sec_mode_muxsel",
+		"csr_gp_io_mux_mic_ext_clk_ctl",
+		"csr_gp_io_mux_sec_tlmm_ctl";
+	qcom,audio-routing =
+		"AIF4 VI", "MCLK",
+		"AIF4 VI", "MICBIAS_REGULATOR",
+		"RX_BIAS", "MCLK",
+		"BRIDGE RX OUT", "MCLK",
+		"BRIDGE TX IN", "MCLK",
+		"MADINPUT", "MCLK",
+		"AIF4 MAD", "MICBIAS_REGULATOR",
+		"AMIC1", "MIC BIAS3",
+		"MIC BIAS3", "Handset Mic",
+		"AMIC2", "MIC BIAS2",
+		"MIC BIAS2", "Headset Mic",
+		"AMIC3", "MIC BIAS3",
+		"MIC BIAS3", "Secondary Mic",
+		"AMIC4", "MIC BIAS3",
+		"MIC BIAS3", "Analog Mic4",
+		"AMIC5", "MIC BIAS4",
+		"MIC BIAS4", "Analog Mic7",
+		"AMIC6", "MIC BIAS4",
+		"MIC BIAS4", "Analog Mic6",
+		"DMIC0", "MIC BIAS1",
+		"MIC BIAS1", "Digital Mic0",
+		"DMIC1", "MIC BIAS1",
+		"MIC BIAS1", "Digital Mic1",
+		"DMIC2", "MIC BIAS3",
+		"MIC BIAS3", "Digital Mic2",
+		"DMIC3", "MIC BIAS3",
+		"MIC BIAS3", "Digital Mic3",
+		"DMIC4", "MIC BIAS4",
+		"MIC BIAS4", "Digital Mic4",
+		"DMIC5", "MIC BIAS4",
+		"MIC BIAS4", "Digital Mic5",
+		"MIC BIAS3", "MICBIAS_REGULATOR",
+		"MIC BIAS4", "MICBIAS_REGULATOR",
+		"SpkrLeft IN", "SPK1 OUT",
+		"SpkrRight IN", "SPK2 OUT";
+	asoc-cpu = <&dai_pri_auxpcm>,
+		<&dai_mi2s2>, <&dai_mi2s3>, <&dai_mi2s5>,
+		<&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+		<&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
+		<&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>,
+		<&afe_pcm_rx>, <&afe_pcm_tx>,
+		<&afe_proxy_rx>, <&afe_proxy_tx>,
+		<&incall_record_rx>, <&incall_record_tx>,
+		<&incall_music_rx>, <&incall_music_2_rx>,
+		<&sb_5_rx>,  <&bt_sco_rx>,
+		<&bt_sco_tx>, <&int_fm_rx>, <&int_fm_tx>,
+		<&sb_6_rx>, <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+		<&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, <&afe_loopback_tx>;
+	asoc-cpu-names = "msm-dai-q6-auxpcm.1",
+			"msm-dai-q6-mi2s.2",
+			"msm-dai-q6-mi2s.3", "msm-dai-q6-mi2s.5",
+			"msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+			"msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+			"msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389",
+			"msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+			"msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+			"msm-dai-q6-dev.16395", "msm-dai-q6-dev.224",
+			"msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+			"msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+			"msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+			"msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394",
+			"msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
+			"msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293",
+			"msm-dai-q6-dev.16396", "msm-dai-q6-tdm.36864",
+			"msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36880",
+			"msm-dai-q6-tdm.36881", "msm-dai-q6-dev.24577";
+	qcom,msm-gpios =
+		"quin_i2s",
+		"us_eu_gpio",
+		"quat_i2s";
+	qcom,pinctrl-names =
+		"all_off",
+		"quin_i2s_act",
+		"us_eu_gpio_act",
+		"quin_i2s_us_eu_gpio_act",
+		"quat_i2s_act",
+		"quat_i2s_quin_i2s_act",
+		"quat_i2s_us_eu_gpio_act",
+		"quat_i2s_us_eu_gpio_quin_i2s_act";
+	pinctrl-names =
+		"all_off",
+		"quin_i2s_act",
+		"us_eu_gpio_act",
+		"quin_i2s_us_eu_gpio_act",
+		"quat_i2s_act",
+		"quat_i2s_quin_i2s_act",
+		"quat_i2s_us_eu_gpio_act",
+		"quat_i2s_us_eu_gpio_quin_i2s_act";
+
+	pinctrl-0 = <&pri_tlmm_ws_sus
+		&cross_conn_det_sus &pri_mi2s_sd0_sleep
+		&pri_mi2s_sck_sleep &pri_mi2s_sd1_sleep
+		&sec_mi2s_ws_sleep &sec_mi2s_sck_sleep
+		&sec_mi2s_sd1_sleep &sec_mi2s_sd0_sleep>;
+	pinctrl-1 = <&pri_tlmm_ws_act
+		&cross_conn_det_sus &pri_mi2s_sd0_active
+		&pri_mi2s_sck_active &pri_mi2s_sd1_active
+		&sec_mi2s_ws_sleep &sec_mi2s_sck_sleep
+		&sec_mi2s_sd1_sleep &sec_mi2s_sd0_sleep>;
+	pinctrl-2 = <&pri_tlmm_ws_sus
+		&cross_conn_det_act &pri_mi2s_sd0_sleep
+		&pri_mi2s_sck_sleep &pri_mi2s_sd1_sleep
+		&sec_mi2s_ws_sleep &sec_mi2s_sck_sleep
+		&sec_mi2s_sd1_sleep &sec_mi2s_sd0_sleep>;
+	pinctrl-3 = <&pri_tlmm_ws_act
+		&cross_conn_det_act &pri_mi2s_sd0_active
+		&pri_mi2s_sck_active &pri_mi2s_sd1_active
+		&sec_mi2s_ws_sleep &sec_mi2s_sck_sleep
+		&sec_mi2s_sd1_sleep &sec_mi2s_sd0_sleep>;
+	pinctrl-4 = <&pri_tlmm_ws_sus
+		&cross_conn_det_sus &pri_mi2s_sd0_sleep
+		&pri_mi2s_sck_sleep &pri_mi2s_sd1_sleep
+		&sec_mi2s_ws_active &sec_mi2s_sck_active
+		&sec_mi2s_sd1_active &sec_mi2s_sd0_active>;
+	pinctrl-5 = <&pri_tlmm_ws_act
+		&cross_conn_det_sus &pri_mi2s_sd0_active
+		&pri_mi2s_sck_active &pri_mi2s_sd1_active
+		&sec_mi2s_ws_active &sec_mi2s_sck_active
+		&sec_mi2s_sd1_active &sec_mi2s_sd0_active>;
+	pinctrl-6 = <&pri_tlmm_ws_sus
+		&cross_conn_det_act &pri_mi2s_sd0_sleep
+		&pri_mi2s_sck_sleep &pri_mi2s_sd1_sleep
+		&sec_mi2s_ws_active &sec_mi2s_sck_active
+		&sec_mi2s_sd1_active &sec_mi2s_sd0_active>;
+	pinctrl-7 = <&pri_tlmm_ws_act
+		&cross_conn_det_act &pri_mi2s_sd0_active
+		&pri_mi2s_sck_active &pri_mi2s_sd1_active
+		&sec_mi2s_ws_active &sec_mi2s_sck_active
+		&sec_mi2s_sd1_active &sec_mi2s_sd0_active>;
+};
+
+&int_codec {
+	status = "disabled";
+};
+
+&wsa881x_i2c_f {
+	status = "disabled";
+};
+
+&wsa881x_i2c_45 {
+	status = "disabled";
+};
+
+&soc {
+	qcom,msm-dai-tdm-pri-rx {
+		compatible = "qcom,msm-dai-tdm";
+		qcom,msm-cpudai-tdm-group-id = <37120>;
+		qcom,msm-cpudai-tdm-group-num-ports = <1>;
+		qcom,msm-cpudai-tdm-group-port-id = <36864>;
+		qcom,msm-cpudai-tdm-clk-rate = <12288000>;
+		qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>;
+		dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36864>;
+			qcom,msm-cpudai-tdm-sync-mode = <0>;
+			qcom,msm-cpudai-tdm-sync-src = <1>;
+			qcom,msm-cpudai-tdm-data-out = <0>;
+			qcom,msm-cpudai-tdm-invert-sync = <0>;
+			qcom,msm-cpudai-tdm-data-delay = <1>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+	};
+
+	qcom,msm-dai-tdm-pri-tx {
+		compatible = "qcom,msm-dai-tdm";
+		qcom,msm-cpudai-tdm-group-id = <37121>;
+		qcom,msm-cpudai-tdm-group-num-ports = <1>;
+		qcom,msm-cpudai-tdm-group-port-id = <36865>;
+		qcom,msm-cpudai-tdm-clk-rate = <12288000>;
+		qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>;
+		dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36865>;
+			qcom,msm-cpudai-tdm-sync-mode = <0>;
+			qcom,msm-cpudai-tdm-sync-src = <1>;
+			qcom,msm-cpudai-tdm-data-out = <0>;
+			qcom,msm-cpudai-tdm-invert-sync = <0>;
+			qcom,msm-cpudai-tdm-data-delay = <1>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+	};
+
+	qcom,msm-dai-tdm-sec-rx {
+		compatible = "qcom,msm-dai-tdm";
+		qcom,msm-cpudai-tdm-group-id = <37136>;
+		qcom,msm-cpudai-tdm-group-num-ports = <1>;
+		qcom,msm-cpudai-tdm-group-port-id = <36880>;
+		qcom,msm-cpudai-tdm-clk-rate = <12288000>;
+		qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>;
+		dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36880>;
+			qcom,msm-cpudai-tdm-sync-mode = <0>;
+			qcom,msm-cpudai-tdm-sync-src = <1>;
+			qcom,msm-cpudai-tdm-data-out = <0>;
+			qcom,msm-cpudai-tdm-invert-sync = <0>;
+			qcom,msm-cpudai-tdm-data-delay = <1>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+	};
+
+	qcom,msm-dai-tdm-sec-tx {
+		compatible = "qcom,msm-dai-tdm";
+		qcom,msm-cpudai-tdm-group-id = <37137>;
+		qcom,msm-cpudai-tdm-group-num-ports = <1>;
+		qcom,msm-cpudai-tdm-group-port-id = <36881>;
+		qcom,msm-cpudai-tdm-clk-rate = <12288000>;
+		qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>;
+		dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 {
+			compatible = "qcom,msm-dai-q6-tdm";
+			qcom,msm-cpudai-tdm-dev-id = <36881>;
+			qcom,msm-cpudai-tdm-sync-mode = <0>;
+			qcom,msm-cpudai-tdm-sync-src = <1>;
+			qcom,msm-cpudai-tdm-data-out = <0>;
+			qcom,msm-cpudai-tdm-invert-sync = <0>;
+			qcom,msm-cpudai-tdm-data-delay = <1>;
+			qcom,msm-cpudai-tdm-data-align = <0>;
+		};
+	};
+};
+
+&dai_pri_auxpcm {
+	qcom,msm-cpudai-afe-clk-ver = <2>;
+};
+
+&tlmm {
+	tlmm_gpio_key {
+		gpio_key_active: gpio_key_active {
+			mux {
+				pins = "gpio91", "gpio127", "gpio128";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio91", "gpio127", "gpio128";
+			};
+		};
+
+		gpio_key_suspend: gpio_key_suspend {
+			mux {
+				pins = "gpio91", "gpio127", "gpio128";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio91", "gpio127", "gpio128";
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp-wcd-rome.dts b/arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp-wcd-rome.dts
new file mode 100644
index 0000000..19c24f8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp-wcd-rome.dts
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "apq8017.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8937.dtsi"
+#include "apq8017-rome.dtsi"
+#include "apq8017-audio.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. APQ8017-PMI8937 CDP \
+						with WCD codec/Rome card";
+	compatible = "qcom,apq8017-cdp", "qcom,apq8017", "qcom,cdp";
+	qcom,board-id= <1 2>;
+	qcom,pmic-id = <0x10019 0x020037 0x0 0x0>;
+};
+
+&blsp1_uart1 {
+	status = "ok";
+};
+
+&sdhc_2 {
+	/* device core power supply */
+	/delete-property/vdd-supply;
+	/delete-property/qcom,vdd-voltage-level;
+	/delete-property/qcom,vdd-current-level;
+
+	/* device communication power supply */
+	vdd-io-supply = <&pm8937_l5>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <200 325000>;
+
+	qcom,core_3_0v_support;
+	qcom,nonremovable;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on
+			&sdc2_wlan_gpio_active>;
+	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off
+			&sdc2_wlan_gpio_sleep>;
+
+	#address-cells = <0>;
+	interrupt-parent = <&sdhc_2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+		1 &intc 0 221 0
+		2 &tlmm 124 0x4>;
+	interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq";
+
+	/delete-property/cd-gpios;
+	/delete-property/qcom,devfreq,freq-table;
+
+	status = "ok";
+
+};
+
+&mdss_fb0 {
+	/delete-node/ qcom,cont-splash-memory;
+};
+
+/delete-node/ &cont_splash_mem;
+
+&soc {
+	gpio_keys {
+		/delete-node/ home;
+	};
+};
+
+&modem_mem {
+	reg = <0x0 0x86800000 0x0 0x1500000>;
+};
+
+&adsp_fw_mem {
+	reg = <0x0 0x87d00000 0x0 0x1100000>;
+};
+
+&wcnss_fw_mem {
+	reg = <0x0 0x88e00000 0x0 0x700000>;
+};
+
+&secure_mem {
+	status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp.dts b/arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp.dts
new file mode 100644
index 0000000..6faa413
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp.dts
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "apq8017.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8937.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. APQ8017-PMI8937 CDP";
+	compatible = "qcom,apq8017-cdp", "qcom,apq8017", "qcom,cdp";
+	qcom,board-id= <1 0>;
+	qcom,pmic-id = <0x10019 0x020037 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8937-mtp.dts b/arch/arm64/boot/dts/qcom/apq8017-pmi8937-mtp.dts
new file mode 100644
index 0000000..01305e6
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8937-mtp.dts
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "apq8017.dtsi"
+#include "msm8917-mtp.dtsi"
+#include "msm8917-pmi8937.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. APQ8017-PMI8937 MTP";
+	compatible = "qcom,apq8017-mtp", "qcom,apq8017", "qcom,mtp";
+	qcom,board-id= <8 0>;
+	qcom,pmic-id = <0x10019 0x020037 0x0 0x0>;
+};
+
+&blsp1_uart1 {
+	status = "ok";
+};
+
+&vendor {
+	mtp_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "batterydata-itech-3000mah.dtsi"
+		#include "batterydata-ascent-3450mAh.dtsi"
+	};
+};
+
+&qpnp_fg {
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&qpnp_smbcharger {
+	qcom,battery-data = <&mtp_batterydata>;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dts b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dts
new file mode 100644
index 0000000..8ddb1fc
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dts
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "apq8017.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8950.dtsi"
+#include "apq8017-rome.dtsi"
+#include "apq8017-audio.dtsi"
+#include "apq8017-pmi8950-cdp-wcd-rome.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. APQ8017-PMI8950 CDP \
+						with WCD codec/Rome card";
+	compatible = "qcom,apq8017-cdp", "qcom,apq8017", "qcom,cdp";
+	qcom,board-id= <1 2>;
+	qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+};
+
+&blsp1_uart1 {
+	status = "ok";
+};
+
+&wcd9335 {
+	qcom,cdc-mic-unmute-delay = <50>;
+};
+
+&sdhc_2 {
+	/* device core power supply */
+	/delete-property/vdd-supply;
+	/delete-property/qcom,vdd-voltage-level;
+	/delete-property/qcom,vdd-current-level;
+
+	/* device communication power supply */
+	vdd-io-supply = <&pm8937_l5>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <200 325000>;
+
+	qcom,core_3_0v_support;
+	qcom,nonremovable;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on
+			&sdc2_wlan_gpio_active>;
+	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off
+			&sdc2_wlan_gpio_sleep>;
+
+	#address-cells = <0>;
+	interrupt-parent = <&sdhc_2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+		1 &intc 0 221 0
+		2 &tlmm 124 0x4>;
+	interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq";
+
+	/delete-property/cd-gpios;
+	/delete-property/qcom,devfreq,freq-table;
+
+	status = "ok";
+
+};
+
+&mdss_fb0 {
+	/delete-node/ qcom,cont-splash-memory;
+};
+
+/delete-node/ &cont_splash_mem;
+
+&soc {
+	gpio_keys {
+		/delete-node/ home;
+	};
+};
+
+&usb_otg {
+	vbus_otg-supply = <0>;
+	qcom,vbus-low-as-hostmode;
+};
+
+&i2c_4 {
+	usb2533@2c {
+		status = "ok";
+	};
+};
+
+&i2c_2 {
+	/* DSI_TO_HDMI I2C configuration */
+	adv7533@39 {
+		compatible = "adv7533";
+		reg = <0x39>;
+		instance_id = <0>;
+		adi,video-mode = <3>; /* 3 = 1080p */
+		adi,main-addr = <0x39>;
+		adi,cec-dsi-addr = <0x3C>;
+		adi,enable-audio;
+		adi,irq-gpio = <&tlmm 0x29 0x2002>;
+		adi,power-down-gpio = <&tlmm 0x7D 0x0>;
+		adi,switch-gpio = <&pm8937_gpios 0x8 0x1>;
+		pinctrl-names = "pmx_adv7533_active",
+					"pmx_adv7533_suspend";
+		pinctrl-0 = <&adv7533_int_active>;
+		pinctrl-1 = <&adv7533_int_suspend>;
+	};
+
+	pericom-type-c@1d {
+		status = "disabled";
+	};
+};
+
+&mdss_dsi {
+	hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_adv7533_1080p>;
+	qcom,platform-intf-mux-gpio = <&tlmm 115 0>;
+	status = "ok";
+	qcom,bridge-index = <0>;
+	qcom,pluggable;
+};
+
+&dsi_adv7533_1080p {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
+
+&modem_mem {
+	reg = <0x0 0x86800000 0x0 0x1500000>;
+};
+
+&adsp_fw_mem {
+	reg = <0x0 0x87d00000 0x0 0x1100000>;
+};
+
+&wcnss_fw_mem {
+	reg = <0x0 0x88e00000 0x0 0x700000>;
+};
+
+&other_ext_mem {
+	reg = <0x0 0x84f00000 0x0 0x1900000>;
+};
+
+&qcom_seecom {
+	reg = <0x84f00000 0x1400000>;
+};
+
+&secure_mem {
+	status = "disabled";
+};
+
+/* Warning, SPI6 & I2C6 cannot be enabled at the same time due to pin usage. */
+&spi_6 {
+	status = "disabled";
+};
+
+&i2c_6 {
+	status = "ok";
+	qcom,clk-freq-out = <100000>;
+
+	/* TI591XX LED Drivers */
+	tlc59116@60 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "ti,tlc59116";
+		reg = <0x60>;
+		out0@0 {
+			label = "ledsec1_g";
+			reg = <0x0>;
+		};
+		out1@1 {
+			label = "ledsec1_r";
+			reg = <0x1>;
+		};
+		out2@2 {
+			label = "ledsec1_b";
+			reg = <0x2>;
+		};
+		out3@3 {
+			label = "ledsec2_g";
+			reg = <0x3>;
+		};
+		out4@4 {
+			label = "ledsec2_r";
+			reg = <0x4>;
+		};
+		out5@5 {
+			label = "ledsec2_b";
+			reg = <0x5>;
+		};
+		out6@6 {
+			label = "ledsec3_g";
+			reg = <0x6>;
+		};
+		out7@7 {
+			label = "ledsec3_r";
+			reg = <0x7>;
+		};
+		out8@8 {
+			label = "ledsec3_b";
+			reg = <0x8>;
+		};
+		out9@9 {
+			label = "ledsec4_g";
+			reg = <0x9>;
+		};
+		out10@10 {
+			label = "ledsec4_r";
+			reg = <0xa>;
+		};
+		out11@11 {
+			label = "ledsec4_b";
+			reg = <0xb>;
+		};
+		out12@12 {
+			label = "ledsec5_g";
+			reg = <0xc>;
+		};
+		out13@13 {
+			label = "ledsec5_r";
+			reg = <0xd>;
+		};
+		out14@14 {
+			label = "ledsec5_b";
+			reg = <0xe>;
+		};
+	};
+
+	tlc59116@61 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "ti,tlc59116";
+		reg = <0x61>;
+		out0@0 {
+			label = "ledsec6_g";
+			reg = <0x0>;
+		};
+		out1@1 {
+			label = "ledsec6_r";
+			reg = <0x1>;
+		};
+		out2@2 {
+			label = "ledsec6_b";
+			reg = <0x2>;
+		};
+		out3@3 {
+			label = "ledsec7_g";
+			reg = <0x3>;
+		};
+		out4@4 {
+			label = "ledsec7_r";
+			reg = <0x4>;
+		};
+		out5@5 {
+			label = "ledsec7_b";
+			reg = <0x5>;
+		};
+		out6@6 {
+			label = "ledsec8_g";
+			reg = <0x6>;
+		};
+		out7@7 {
+			label = "ledsec8_r";
+			reg = <0x7>;
+		};
+		out8@8 {
+			label = "ledsec8_b";
+			reg = <0x8>;
+		};
+		out9@9 {
+			label = "ledsec9_g";
+			reg = <0x9>;
+		};
+		out10@10 {
+			label = "ledsec9_r";
+			reg = <0xa>;
+		};
+		out11@11 {
+			label = "ledsec9_b";
+			reg = <0xb>;
+		};
+	};
+};
+
+&soc {
+	pinctrl@1000000 {
+		i2c6{
+			tlc59116_reset: tlc59116_reset {
+				config {
+					pins = "gpio20";
+					drive-strength = <16>;
+					bias-pull-up;
+				};
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dtsi b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dtsi
new file mode 100644
index 0000000..3337add
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dtsi
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2017-2018, 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.
+ */
+
+/ {
+	model = "Qualcomm Technologies, Inc. APQ8017-PMI8950 CDP \
+						with WCD codec/Rome card";
+	compatible = "qcom,apq8017-cdp", "qcom,apq8017", "qcom,cdp";
+	qcom,board-id= <1 2>;
+	qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+
+	aliases {
+		i2c6 = &i2c_6;
+	};
+};
+
+&soc {
+	i2c_6: i2c@7af6000 { /* BLSP2 QUP2 */
+		compatible = "qcom,i2c-msm-v2";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "qup_phys_addr";
+		reg = <0x7af6000 0x600>;
+		interrupt-names = "qup_irq";
+		interrupts = <0 300 0>;
+		qcom,clk-freq-out = <400000>;
+		qcom,clk-freq-in  = <19200000>;
+		clock-names = "iface_clk", "core_clk";
+		clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>,
+			<&clock_gcc clk_gcc_blsp2_qup2_i2c_apps_clk>;
+
+		pinctrl-names = "i2c_active", "i2c_sleep";
+		pinctrl-0 = <&i2c_6_active>;
+		pinctrl-1 = <&i2c_6_sleep>;
+		qcom,noise-rjct-scl = <0>;
+		qcom,noise-rjct-sda = <0>;
+		qcom,master-id = <84>;
+		dmas = <&dma_blsp2 6 64 0x20000020 0x20>,
+			<&dma_blsp2 7 32 0x20000020 0x20>;
+		dma-names = "tx", "rx";
+		status = "disabled";
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp.dts b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp.dts
new file mode 100644
index 0000000..5c8ef83
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp.dts
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "apq8017.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8950.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. APQ8017-PMI8950 CDP";
+	compatible = "qcom,apq8017-cdp", "qcom,apq8017", "qcom,cdp";
+	qcom,board-id= <1 0>;
+	qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+};
+
+&mdss_fb0 {
+	/delete-node/ qcom,cont-splash-memory;
+};
+
+/delete-node/ &cont_splash_mem;
diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8950-mtp.dts b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-mtp.dts
new file mode 100644
index 0000000..b5b7667
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-mtp.dts
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "apq8017.dtsi"
+#include "msm8917-mtp.dtsi"
+#include "msm8917-pmi8950.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. APQ8017-PMI8950 MTP";
+	compatible = "qcom,apq8017-mtp", "qcom,apq8017", "qcom,mtp";
+	qcom,board-id= <8 0>;
+	qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+};
+
+&blsp1_uart1 {
+	status = "ok";
+};
+
+&vendor {
+	mtp_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "batterydata-itech-3000mah.dtsi"
+		#include "batterydata-ascent-3450mAh.dtsi"
+	};
+};
+
+&qpnp_fg {
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&qpnp_smbcharger {
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&i2c_2 {
+	/* DSI_TO_HDMI I2C configuration */
+	adv7533@39 {
+		compatible = "adv7533";
+		reg = <0x39>;
+		instance_id = <0>;
+		adi,video-mode = <3>; /* 3 = 1080p */
+		adi,main-addr = <0x39>;
+		adi,cec-dsi-addr = <0x3C>;
+		adi,enable-audio;
+		adi,irq-gpio = <&tlmm 0x29 0x2002>;
+		adi,power-down-gpio = <&tlmm 0x7D 0x0>;
+		adi,switch-gpio = <&pm8937_gpios 0x8 0x1>;
+		pinctrl-names = "pmx_adv7533_active",
+					"pmx_adv7533_suspend";
+		pinctrl-0 = <&adv7533_int_active>;
+		pinctrl-1 = <&adv7533_int_suspend>;
+	};
+};
+
+&mdss_dsi {
+	hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_adv7533_1080p>;
+	qcom,platform-intf-mux-gpio = <&tlmm 115 0>;
+	status = "ok";
+	qcom,bridge-index = <0>;
+	qcom,pluggable;
+};
+
+&dsi_adv7533_1080p {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8017-rome.dtsi b/arch/arm64/boot/dts/qcom/apq8017-rome.dtsi
new file mode 100644
index 0000000..7dfa952
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017-rome.dtsi
@@ -0,0 +1,33 @@
+/*
+ * copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	qcom,cnss_sdio {
+		compatible = "qcom,cnss_sdio";
+		qcom,wlan-ramdump-dynamic = <0x200000>;
+		subsys-name = "AR6320";
+		qcom,cap-tsf-gpio = <&tlmm 126 1>;
+	};
+};
+
+&pm8937_gpios {
+	gpio@c100 { /* GPIO 2 - Rome Sleep Clock */
+		qcom,mode = <1>;		/* Digital output */
+		qcom,vin-sel = <3>;		/* VIN 3 */
+		qcom,src-sel = <2>;		/* Function 2 */
+		qcom,out-strength = <2>;	/* Medium */
+		qcom,pull = <4>;
+		qcom,master-en = <1>;		/* Enable GPIO */
+		status = "okay";
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8017.dtsi b/arch/arm64/boot/dts/qcom/apq8017.dtsi
new file mode 100644
index 0000000..fecc7ce8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017.dtsi
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015-2018, 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 "msm8917.dtsi"
+/ {
+	model = "Qualcomm Technologies, Inc. APQ8017";
+	compatible = "qcom,apq8017";
+	qcom,msm-id = <307 0x0>;
+};
+
+&tlmm {
+	pmx_adv7533_int: pmx_adv7533_int {
+		adv7533_int_active: adv7533_int_active {
+			mux {
+				pins = "gpio41";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio41";
+				function = "gpio";
+				drive-strength = <16>;
+				bias-pull-up; /* pull up */
+			};
+		};
+
+		adv7533_int_suspend: adv7533_int_suspend {
+			mux {
+				pins = "gpio41";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio41";
+				drive-strength = <16>;
+				bias-disable;
+			};
+		};
+	};
+};
+
+&mdss_dsi_active {
+	mux {
+		pins = "gpio60", "gpio98", "gpio115", "gpio133";
+		function = "gpio";
+	};
+
+	config {
+		pins = "gpio60", "gpio98", "gpio115", "gpio133";
+		drive-strength = <8>; /* 8 mA */
+		bias-disable = <0>; /* no pull */
+		output-high;
+	};
+};
+
+&mdss_dsi_suspend {
+	mux {
+		pins = "gpio60", "gpio98", "gpio115", "gpio133";
+		function = "gpio";
+	};
+
+	config {
+		pins = "gpio60", "gpio98", "gpio115", "gpio133";
+		drive-strength = <2>; /* 2 mA */
+		bias-pull-down; /* pull down */
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts b/arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts
index 8f7e326..9f0edda 100644
--- a/arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts
@@ -26,3 +26,63 @@
 	qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
 };
 
+&int_codec {
+	status = "disabled";
+};
+
+&wsa881x_i2c_f {
+	status = "disabled";
+};
+
+&wsa881x_i2c_45 {
+	status = "disabled";
+};
+
+&cdc_pri_mi2s_gpios {
+	status = "disabled";
+};
+
+&wsa881x_analog_vi_gpio {
+	status = "disabled";
+};
+
+&wsa881x_analog_clk_gpio {
+	status = "disabled";
+};
+
+&wsa881x_analog_reset_gpio {
+	status = "disabled";
+};
+
+&cdc_comp_gpios {
+	status = "disabled";
+};
+
+&slim_msm {
+	status = "okay";
+};
+
+&dai_slim {
+	status = "okay";
+};
+
+&wcd9xxx_intc {
+	status = "okay";
+};
+
+&clock_audio {
+	status = "okay";
+};
+
+&wcd9335 {
+	status = "okay";
+};
+
+&wcd_rst_gpio {
+	status = "okay";
+};
+
+&ext_codec {
+	qcom,model = "msm8953-tasha-snd-card";
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dts
index d7836e5..55d8b7b 100644
--- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dts
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dts
@@ -13,7 +13,6 @@
 
 /dts-v1/;
 
-#include "apq8053-lite.dtsi"
 #include "apq8053-lite-dragon-v2.0.dtsi"
 
 / {
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dtsi
index 947af4d..bb40018 100644
--- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dtsi
@@ -12,68 +12,25 @@
  */
 
 #include "apq8053-lite-dragon.dtsi"
-#include "msm8953-mdss-panels.dtsi"
-
-&i2c_3 {
-	status = "okay";
-	himax_ts@48 {
-		compatible = "himax,hxcommon";
-		reg = <0x48>;
-		interrupt-parent = <&tlmm>;
-		interrupts = <65 0x2>;
-		vdd-supply = <&pm8953_l10>;
-		avdd-supply = <&pm8953_l5>;
-		pinctrl-names = "pmx_ts_active","pmx_ts_suspend",
-					"pmx_ts_release";
-		pinctrl-0 = <&ts_int_active &ts_reset_active>;
-		pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
-		pinctrl-2 = <&ts_release>;
-		himax,panel-coords = <0 800 0 1280>;
-		himax,display-coords = <0 800 0 1280>;
-		himax,irq-gpio = <&tlmm 65 0x2008>;
-		report_type = <1>;
-	};
-};
-
-&mdss_mdp {
-	qcom,mdss-pref-prim-intf = "dsi";
-};
-
-&mdss_dsi {
-	hw-config = "single_dsi";
-};
 
 &mdss_dsi0 {
-	qcom,dsi-pref-prim-pan = <&dsi_boyi_hx83100a_800p_video>;
-	pinctrl-names = "mdss_default", "mdss_sleep";
 	pinctrl-0 = <&mdss_dsi_active &mdss_te_active &mdss_dsi_gpio>;
 	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend &mdss_dsi_gpio>;
-
-	vdd-supply = <&pm8953_l10>;
-	vddio-supply = <&pm8953_l6>;
-	lab-supply = <&lab_regulator>;
-	ibb-supply = <&ibb_regulator>;
-
-	qcom,platform-te-gpio = <&tlmm 24 0>;
-	qcom,platform-reset-gpio = <&tlmm 61 0>;
-	qcom,platform-bklight-en-gpio = <&tlmm 100 0>;
-};
-
-&mdss_dsi1 {
-	status = "disabled";
-};
-
-&labibb {
-	status = "okay";
-	qpnp,qpnp-labibb-mode = "lcd";
-};
-
-&wled {
-	qcom,cons-sync-write-delay-us = <1000>;
-	qcom,led-strings-list = [00 01 02 03];
 };
 
 &pm8953_l4 {
 	status = "okay";
 	regulator-always-on;
 };
+
+&camera0 {
+	qcom,mount-angle = <90>;
+};
+
+&camera1 {
+	qcom,mount-angle = <90>;
+};
+
+&camera2{
+	qcom,mount-angle = <90>;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi
index 5e3ddce..bd48f09 100644
--- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi
@@ -11,6 +11,7 @@
  * GNU General Public License for more details.
  */
 
+#include "apq8053-lite.dtsi"
 #include "msm8953-pinctrl.dtsi"
 #include "apq8053-camera-sensor-dragon.dtsi"
 #include "pmi8950.dtsi"
@@ -185,39 +186,22 @@
 
 &i2c_3 {
 	status = "okay";
-	focaltech@38 {
-		compatible = "focaltech,5x06";
-		reg = <0x38>;
+	himax_ts@48 {
+		compatible = "himax,hxcommon";
+		reg = <0x48>;
 		interrupt-parent = <&tlmm>;
 		interrupts = <65 0x2>;
 		vdd-supply = <&pm8953_l10>;
-		vcc_i2c-supply = <&pm8953_l5>;
-		/* pins used by touchscreen */
+		avdd-supply = <&pm8953_l5>;
 		pinctrl-names = "pmx_ts_active","pmx_ts_suspend",
-			"pmx_ts_release";
+					"pmx_ts_release";
 		pinctrl-0 = <&ts_int_active &ts_reset_active>;
 		pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
 		pinctrl-2 = <&ts_release>;
-		focaltech,name = "ft5606";
-		focaltech,family-id = <0x08>;
-		focaltech,reset-gpio = <&tlmm 64 0x0>;
-		focaltech,irq-gpio = <&tlmm 65 0x2008>;
-		focaltech,display-coords = <0 0 1919 1199>;
-		focaltech,panel-coords = <0 0 1919 1199>;
-		focaltech,no-force-update;
-		focaltech,i2c-pull-up;
-		focaltech,group-id = <1>;
-		focaltech,hard-reset-delay-ms = <20>;
-		focaltech,soft-reset-delay-ms = <200>;
-		focaltech,num-max-touches = <5>;
-		focaltech,fw-delay-aa-ms = <30>;
-		focaltech,fw-delay-55-ms = <30>;
-		focaltech,fw-upgrade-id1 = <0x79>;
-		focaltech,fw-upgrade-id2 = <0x08>;
-		focaltech,fw-delay-readid-ms = <10>;
-		focaltech,fw-delay-era-flsh-ms = <2000>;
-		focaltech,fw-auto-cal;
-		focaltech,resume-in-workqueue;
+		himax,panel-coords = <0 800 0 1280>;
+		himax,display-coords = <0 800 0 1280>;
+		himax,irq-gpio = <&tlmm 65 0x2008>;
+		report_type = <1>;
 	};
 };
 
@@ -229,6 +213,71 @@
 	status = "disabled";
 };
 
+#include "msm8953-mdss-panels.dtsi"
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+	hw-config = "single_dsi";
+};
+
+&mdss_dsi_active {
+	mux {
+		pins = "gpio61", "gpio100";
+		function = "gpio";
+	};
+
+	config {
+		pins = "gpio61", "gpio100";
+		drive-strength = <8>;
+		bias-disable = <0>;
+		output-high;
+	};
+};
+
+&mdss_dsi_suspend {
+	mux {
+		pins = "gpio61", "gpio100";
+		function = "gpio";
+	};
+
+	config {
+		pins = "gpio61", "gpio100";
+		drive-strength = <2>;
+		bias-pull-down;
+	};
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_boyi_hx83100a_800p_video>;
+	pinctrl-names = "mdss_default", "mdss_sleep";
+	pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+	vdd-supply = <&pm8953_l10>;
+	vddio-supply = <&pm8953_l6>;
+	lab-supply = <&lab_regulator>;
+	ibb-supply = <&ibb_regulator>;
+
+	qcom,platform-te-gpio = <&tlmm 24 0>;
+	qcom,platform-reset-gpio = <&tlmm 61 0>;
+	qcom,platform-bklight-en-gpio = <&tlmm 100 0>;
+};
+
+&mdss_dsi1 {
+	status = "disabled";
+};
+
+&labibb {
+	status = "okay";
+	qpnp,qpnp-labibb-mode = "lcd";
+};
+
+&wled {
+	qcom,cons-sync-write-delay-us = <1000>;
+	qcom,led-strings-list = [00 01 02 03];
+};
 &blsp1_uart0 {
 	status = "ok";
 	pinctrl-names = "default";
@@ -270,7 +319,7 @@
 			pins = "gpio75";
 			drive-strength = <10>;
 			bias-pull-up;
-			output-high;
+			output-low;
 		};
 	};
 	sdc2_wlan_gpio_off: sdc2_wlan_gpio_off {
@@ -290,6 +339,7 @@
 &sdhc_2 {
 	/* device communication power supply */
 	vdd-io-supply = <&pm8953_l12>;
+	qcom,vdd-io-always-on;
 	qcom,vdd-io-voltage-level = <1800000 1800000>;
 	qcom,vdd-io-current-level = <200 22000>;
 
@@ -301,7 +351,7 @@
 	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off
 		 &sdc2_wlan_gpio_off>;
 
-	qcom,clk-rates = <400000 20000000 25000000 50000000>;
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000>;
 	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
 
 	status = "ok";
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dts
new file mode 100644
index 0000000..203b6b8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "apq8053-lite-harman-v1.0.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. APQ8053 Lite Harman v1.0 Board";
+	compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053",
+			"qcom,dragonboard";
+	qcom,board-id= <0x01020020 0>;
+};
+
+&blsp2_uart0 {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dtsi
new file mode 100644
index 0000000..5cf8ac0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dtsi
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2017-2018, 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 "apq8053-lite-dragon.dtsi"
+
+&pm8953_l4 {
+	status = "okay";
+	regulator-always-on;
+};
+
+&pm8953_l10 {
+	status = "okay";
+	regulator-min-microvolt = <3000000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-always-on;
+};
+
+&pm8953_l2 {
+	status = "okay";
+	regulator-always-on;
+};
+
+&pm8953_l17 {
+	status = "okay";
+	regulator-always-on;
+};
+
+&pm8953_l22 {
+	status = "okay";
+	regulator-always-on;
+};
+
+&i2c_3 {
+	status = "okay";
+	/delete-node/ himax_ts@48;
+	focaltech_ts@38 {
+		compatible = "focaltech,fts";
+		reg = <0x38>;
+		interrupt-parent = <&tlmm>;
+		interrupts = <65 0x2>;
+		vdd-supply = <&pm8953_l10>;
+		avdd-supply = <&pm8953_l6>;
+		pinctrl-names = "pmx_ts_active","pmx_ts_suspend",
+					"pmx_ts_release";
+		pinctrl-0 = <&ts_int_active &ts_reset_active>;
+		pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
+		pinctrl-2 = <&ts_release>;
+		focaltech,display-coords = <0 0 800 1280>;
+		focaltech,reset-gpio = <&tlmm 64 0x0>;
+		focaltech,irq-gpio = <&tlmm 65 0x2>;
+		focaltech,max-touch-number = <5>;
+		report_type = <1>;
+	};
+};
+
+&wled {
+	qcom,led-strings-list = [00 01 02];
+};
+
+&camera0 {
+	qcom,mount-angle = <90>;
+};
+
+&camera1 {
+	qcom,mount-angle = <90>;
+};
+
+&camera2{
+	qcom,mount-angle = <90>;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dts
new file mode 100644
index 0000000..325accf
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "apq8053-lite-lenovo-v1.0.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. APQ8053 Lite Lenovo v1.0 Board";
+	compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053",
+			"qcom,dragonboard";
+	qcom,board-id= <0x01010020 0>;
+};
+
+&blsp2_uart0 {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dtsi
new file mode 100644
index 0000000..4d9c40c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dtsi
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017-2018, 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 "apq8053-lite-dragon.dtsi"
+
+&mdss_dsi0 {
+	qcom,ext_vdd-gpio = <&tlmm 100 0>;
+	qcom,platform-bklight-en-gpio = <&tlmm 95 0>;
+
+	qcom,platform-lane-config = [00 00 ff 0f
+				00 00 ff 0f
+				00 00 ff 0f
+				00 00 ff 0f
+				00 00 ff 8f];
+};
+
+&eeprom0 {
+	gpios = <&tlmm 26 0>,
+		<&tlmm 40 0>,
+		<&tlmm 118 0>,
+		<&tlmm 119 0>,
+		<&tlmm 39 0>;
+	qcom,gpio-vdig = <3>;
+	qcom,gpio-vana = <4>;
+	qcom,gpio-req-tbl-num = <0 1 2 3 4>;
+	qcom,gpio-req-tbl-flags = <1 0 0 0 0>;
+	qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+			"CAM_RESET0",
+			"CAM_VDIG",
+			"CAM_VANA",
+			"CAM_STANDBY0";
+};
+
+&camera0 {
+	qcom,mount-angle = <270>;
+	gpios = <&tlmm 26 0>,
+		<&tlmm 40 0>,
+		<&tlmm 39 0>,
+		<&tlmm 118 0>,
+		<&tlmm 119 0>;
+	qcom,gpio-vdig = <3>;
+	qcom,gpio-vana = <4>;
+	qcom,gpio-req-tbl-num = <0 1 2 3 4>;
+	qcom,gpio-req-tbl-flags = <1 0 0 0 0>;
+	qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+			"CAM_RESET0",
+			"CAM_STANDBY0",
+			"CAM_VDIG",
+			"CAM_VANA";
+};
+
+&camera1 {
+	qcom,mount-angle = <270>;
+};
+
+&camera2{
+	qcom,mount-angle = <270>;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dts
new file mode 100644
index 0000000..0c7b557
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "apq8053-lite-lenovo-v1.1.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. APQ8053 Lite Lenovo v1.1 Board";
+	compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053",
+			"qcom,dragonboard";
+	qcom,board-id= <0x01010120 0>;
+};
+
+&blsp2_uart0 {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dtsi
new file mode 100644
index 0000000..396fd55
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dtsi
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017-2018, 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 "apq8053-lite-dragon.dtsi"
+
+&i2c_3 {
+	status = "okay";
+	/delete-node/ himax_ts@48;
+};
+
+&eeprom0 {
+	gpios = <&tlmm 26 0>,
+		<&tlmm 40 0>,
+		<&tlmm 118 0>,
+		<&tlmm 119 0>,
+		<&tlmm 39 0>;
+	qcom,gpio-vdig = <3>;
+	qcom,gpio-vana = <4>;
+	qcom,gpio-req-tbl-num = <0 1 2 3 4>;
+	qcom,gpio-req-tbl-flags = <1 0 0 0 0>;
+	qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+			"CAM_RESET0",
+			"CAM_VDIG",
+			"CAM_VANA",
+			"CAM_STANDBY0";
+};
+
+&camera0 {
+	qcom,mount-angle = <270>;
+	gpios = <&tlmm 26 0>,
+		<&tlmm 40 0>,
+		<&tlmm 39 0>,
+		<&tlmm 118 0>,
+		<&tlmm 119 0>;
+	qcom,gpio-vdig = <3>;
+	qcom,gpio-vana = <4>;
+	qcom,gpio-req-tbl-num = <0 1 2 3 4>;
+	qcom,gpio-req-tbl-flags = <1 0 0 0 0>;
+	qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+			"CAM_RESET0",
+			"CAM_STANDBY0",
+			"CAM_VDIG",
+			"CAM_VANA";
+};
+
+&camera1 {
+	qcom,mount-angle = <270>;
+};
+
+&camera2{
+	qcom,mount-angle = <270>;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dts
new file mode 100644
index 0000000..70952dc
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "apq8053-lite-lge-v1.0.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. APQ8053 Lite LGE v1.0 Board";
+	compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053",
+			"qcom,dragonboard";
+	qcom,board-id= <0x01030020 0>;
+};
+
+&blsp2_uart0 {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dtsi
new file mode 100644
index 0000000..db0331e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dtsi
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017-2018, 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 "apq8053-lite-dragon.dtsi"
+
+&wled {
+	qcom,fs-curr-ua = <17500>;
+};
+
+&camera0 {
+	qcom,mount-angle = <180>;
+};
+
+&camera1 {
+	qcom,mount-angle = <180>;
+};
+
+&camera2 {
+	qcom,mount-angle = <180>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm670.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm670.dtsi
index ab088b8..707875b 100644
--- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm670.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -27,14 +27,14 @@
 		vdd-supply = <&gpu_cx_gdsc>;
 		interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>,
 				<GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 364 IRQ_TYPE_EDGE_RISING>,
-				<GIC_SPI 365 IRQ_TYPE_EDGE_RISING>,
-				<GIC_SPI 366 IRQ_TYPE_EDGE_RISING>,
-				<GIC_SPI 367 IRQ_TYPE_EDGE_RISING>,
-				<GIC_SPI 368 IRQ_TYPE_EDGE_RISING>,
-				<GIC_SPI 369 IRQ_TYPE_EDGE_RISING>,
-				<GIC_SPI 370 IRQ_TYPE_EDGE_RISING>,
-				<GIC_SPI 371 IRQ_TYPE_EDGE_RISING>;
+				<GIC_SPI 364 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 365 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 366 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 367 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 368 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 369 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
 		clock-names = "gcc_gpu_memnoc_gfx_clk";
 		clocks = <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>;
 		attach-impl-defs =
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
index e4fe2e3..0ac9c2a 100644
--- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -27,14 +27,14 @@
 		vdd-supply = <&gpu_cx_gdsc>;
 		interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>,
 				<GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>,
-				<GIC_SPI 364 IRQ_TYPE_EDGE_RISING>,
-				<GIC_SPI 365 IRQ_TYPE_EDGE_RISING>,
-				<GIC_SPI 366 IRQ_TYPE_EDGE_RISING>,
-				<GIC_SPI 367 IRQ_TYPE_EDGE_RISING>,
-				<GIC_SPI 368 IRQ_TYPE_EDGE_RISING>,
-				<GIC_SPI 369 IRQ_TYPE_EDGE_RISING>,
-				<GIC_SPI 370 IRQ_TYPE_EDGE_RISING>,
-				<GIC_SPI 371 IRQ_TYPE_EDGE_RISING>;
+				<GIC_SPI 364 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 365 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 366 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 367 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 368 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 369 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>;
 		clock-names =	"gcc_gpu_memnoc_gfx_clk";
 		clocks = <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>;
 		attach-impl-defs =
diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass-msm8909.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass-msm8909.dtsi
new file mode 100644
index 0000000..fe9094f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass-msm8909.dtsi
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	pcm0: qcom,msm-pcm {
+		compatible = "qcom,msm-pcm-dsp";
+		qcom,msm-pcm-dsp-id = <0>;
+	};
+
+	routing: qcom,msm-pcm-routing {
+		compatible = "qcom,msm-pcm-routing";
+	};
+
+	compr: qcom,msm-compr-dsp {
+		compatible = "qcom,msm-compr-dsp";
+	};
+
+	pcm1: qcom,msm-pcm-low-latency {
+		compatible = "qcom,msm-pcm-dsp";
+		qcom,msm-pcm-dsp-id = <1>;
+		qcom,msm-pcm-low-latency;
+		qcom,latency-level = "regular";
+	};
+
+	pcm2: qcom,msm-ultra-low-latency {
+		compatible = "qcom,msm-pcm-dsp";
+		qcom,msm-pcm-dsp-id = <2>;
+		qcom,msm-pcm-low-latency;
+		qcom,latency-level = "ultra";
+	};
+
+	compress: qcom,msm-compress-dsp {
+		compatible = "qcom,msm-compress-dsp";
+	};
+
+	voip: qcom,msm-voip-dsp {
+		compatible = "qcom,msm-voip-dsp";
+	};
+
+	voice: qcom,msm-pcm-voice {
+		compatible = "qcom,msm-pcm-voice";
+		qcom,destroy-cvd;
+	};
+
+	stub_codec: qcom,msm-stub-codec {
+		compatible = "qcom,msm-stub-codec";
+	};
+
+	qcom,msm-dai-fe {
+		compatible = "qcom,msm-dai-fe";
+	};
+
+	afe: qcom,msm-pcm-afe {
+		compatible = "qcom,msm-pcm-afe";
+	};
+
+	loopback: qcom,msm-pcm-loopback {
+		compatible = "qcom,msm-pcm-loopback";
+	};
+
+	lsm: qcom,msm-lsm-client {
+		compatible = "qcom,msm-lsm-client";
+	};
+
+	qcom,msm-dai-q6 {
+		compatible = "qcom,msm-dai-q6";
+		bt_sco_rx: qcom,msm-dai-q6-bt-sco-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <12288>;
+		};
+
+		bt_sco_tx: qcom,msm-dai-q6-bt-sco-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <12289>;
+		};
+
+		int_fm_rx: qcom,msm-dai-q6-int-fm-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <12292>;
+		};
+
+		int_fm_tx: qcom,msm-dai-q6-int-fm-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <12293>;
+		};
+
+		afe_pcm_rx: qcom,msm-dai-q6-be-afe-pcm-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <224>;
+		};
+
+		afe_pcm_tx: qcom,msm-dai-q6-be-afe-pcm-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <225>;
+		};
+
+		afe_proxy_rx: qcom,msm-dai-q6-afe-proxy-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <241>;
+		};
+
+		afe_proxy_tx: qcom,msm-dai-q6-afe-proxy-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <240>;
+		};
+
+		incall_record_rx: qcom,msm-dai-q6-incall-record-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32771>;
+		};
+
+		incall_record_tx: qcom,msm-dai-q6-incall-record-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32772>;
+		};
+
+		incall_music_rx: qcom,msm-dai-q6-incall-music-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32773>;
+		};
+
+		incall_music_2_rx: qcom,msm-dai-q6-incall-music-2-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32770>;
+		};
+
+		usb_audio_rx: qcom,msm-dai-q6-usb-audio-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <28672>;
+		};
+
+		usb_audio_tx: qcom,msm-dai-q6-usb-audio-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <28673>;
+		};
+	};
+
+	hostless: qcom,msm-pcm-hostless {
+		compatible = "qcom,msm-pcm-hostless";
+	};
+
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-audio-bg_codec.dtsi b/arch/arm64/boot/dts/qcom/msm8909-audio-bg_codec.dtsi
index f2cea32..fa6498e 100644
--- a/arch/arm64/boot/dts/qcom/msm8909-audio-bg_codec.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8909-audio-bg_codec.dtsi
@@ -9,8 +9,15 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
+#include "msm-audio-lpass-msm8909.dtsi"
 
 &soc {
+	qcom,msm-audio-apr {
+		compatible = "qcom,msm-audio-apr";
+		msm_audio_apr_dummy {
+			compatible = "qcom,msm-audio-apr-dummy";
+		};
+	};
 	audio_codec_bg: sound {
 		status = "disabled";
 		compatible = "qcom,msm-bg-audio-codec";
@@ -28,6 +35,8 @@
 		qcom,msm-ext-pa = "primary";
 		qcom,tdm-audio-intf;
 		qcom,msm-afe-clk-ver = <1>;
+		qcom,split-a2dp;
+		qcom,pri-mi2s-gpios = <&cdc_dmic_gpios>;
 		asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
 				<&loopback>, <&compress>, <&hostless>,
 				<&afe>, <&lsm>, <&routing>, <&lpa>,
@@ -69,7 +78,12 @@
 		asoc-codec = <&stub_codec>;
 		asoc-codec-names = "msm-stub-codec.1";
 	};
-
+	cdc_dmic_gpios: cdc_dmic_pinctrl {
+		compatible = "qcom,msm-cdc-pinctrl";
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>;
+		pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>;
+	};
 	pri_tdm_rx: qcom,msm-dai-tdm-pri-rx {
 		compatible = "qcom,msm-dai-tdm";
 		qcom,msm-cpudai-tdm-group-id = <37120>;
@@ -77,49 +91,32 @@
 		qcom,msm-cpudai-tdm-group-port-id = <36864 36866 36868 36870>;
 		qcom,msm-cpudai-tdm-clk-rate = <0>;
 		qcom,msm-cpudai-tdm-afe-ebit-unsupported;
+		qcom,msm-cpudai-tdm-clk-internal = <0>;
+		qcom,msm-cpudai-tdm-sync-mode = <0>;
+		qcom,msm-cpudai-tdm-sync-src = <0>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <0>;
+		qcom,msm-cpudai-tdm-data-delay = <0>;
 		qcom,msm-cpudai-tdm-sec-port-enable;
 		qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>;
-		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>;
-		pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>;
 		dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 {
 			compatible = "qcom,msm-dai-q6-tdm";
 			qcom,msm-cpudai-tdm-dev-id = <36864>;
-			qcom,msm-cpudai-tdm-sync-mode = <0>;
-			qcom,msm-cpudai-tdm-sync-src = <0>;
-			qcom,msm-cpudai-tdm-data-out = <0>;
-			qcom,msm-cpudai-tdm-invert-sync = <0>;
-			qcom,msm-cpudai-tdm-data-delay = <0>;
 			qcom,msm-cpudai-tdm-data-align = <0>;
 		};
 		dai_pri_tdm_rx_1: qcom,msm-dai-q6-tdm-pri-rx-1 {
 			compatible = "qcom,msm-dai-q6-tdm";
 			qcom,msm-cpudai-tdm-dev-id = <36866>;
-			qcom,msm-cpudai-tdm-sync-mode = <0>;
-			qcom,msm-cpudai-tdm-sync-src = <0>;
-			qcom,msm-cpudai-tdm-data-out = <0>;
-			qcom,msm-cpudai-tdm-invert-sync = <0>;
-			qcom,msm-cpudai-tdm-data-delay = <0>;
 			qcom,msm-cpudai-tdm-data-align = <0>;
 		};
 		dai_pri_tdm_rx_2: qcom,msm-dai-q6-tdm-pri-rx-2 {
 			compatible = "qcom,msm-dai-q6-tdm";
 			qcom,msm-cpudai-tdm-dev-id = <36868>;
-			qcom,msm-cpudai-tdm-sync-mode = <0>;
-			qcom,msm-cpudai-tdm-sync-src = <0>;
-			qcom,msm-cpudai-tdm-data-out = <0>;
-			qcom,msm-cpudai-tdm-invert-sync = <0>;
-			qcom,msm-cpudai-tdm-data-delay = <0>;
 			qcom,msm-cpudai-tdm-data-align = <0>;
 		};
 		dai_pri_tdm_rx_3: qcom,msm-dai-q6-tdm-pri-rx-3 {
 			compatible = "qcom,msm-dai-q6-tdm";
 			qcom,msm-cpudai-tdm-dev-id = <36870>;
-			qcom,msm-cpudai-tdm-sync-mode = <0>;
-			qcom,msm-cpudai-tdm-sync-src = <0>;
-			qcom,msm-cpudai-tdm-data-out = <0>;
-			qcom,msm-cpudai-tdm-invert-sync = <0>;
-			qcom,msm-cpudai-tdm-data-delay = <0>;
 			qcom,msm-cpudai-tdm-data-align = <0>;
 		};
 	};
@@ -131,49 +128,32 @@
 		qcom,msm-cpudai-tdm-group-port-id = <36865 36867 36869 36871>;
 		qcom,msm-cpudai-tdm-clk-rate = <0>;
 		qcom,msm-cpudai-tdm-afe-ebit-unsupported;
+		qcom,msm-cpudai-tdm-clk-internal = <0>;
+		qcom,msm-cpudai-tdm-sync-mode = <0>;
+		qcom,msm-cpudai-tdm-sync-src = <0>;
+		qcom,msm-cpudai-tdm-data-out = <0>;
+		qcom,msm-cpudai-tdm-invert-sync = <0>;
+		qcom,msm-cpudai-tdm-data-delay = <0>;
 		qcom,msm-cpudai-tdm-sec-port-enable;
 		qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>;
-		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>;
-		pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>;
 		dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 {
 			compatible = "qcom,msm-dai-q6-tdm";
 			qcom,msm-cpudai-tdm-dev-id = <36865>;
-			qcom,msm-cpudai-tdm-sync-mode = <0>;
-			qcom,msm-cpudai-tdm-sync-src = <0>;
-			qcom,msm-cpudai-tdm-data-out = <0>;
-			qcom,msm-cpudai-tdm-invert-sync = <0>;
-			qcom,msm-cpudai-tdm-data-delay = <0>;
 			qcom,msm-cpudai-tdm-data-align = <0>;
 		};
 		dai_pri_tdm_tx_1: qcom,msm-dai-q6-tdm-pri-tx-1 {
 			compatible = "qcom,msm-dai-q6-tdm";
 			qcom,msm-cpudai-tdm-dev-id = <36867>;
-			qcom,msm-cpudai-tdm-sync-mode = <0>;
-			qcom,msm-cpudai-tdm-sync-src = <0>;
-			qcom,msm-cpudai-tdm-data-out = <0>;
-			qcom,msm-cpudai-tdm-invert-sync = <0>;
-			qcom,msm-cpudai-tdm-data-delay = <0>;
 			qcom,msm-cpudai-tdm-data-align = <0>;
 		};
 		dai_pri_tdm_tx_2: qcom,msm-dai-q6-tdm-pri-tx-2 {
 			compatible = "qcom,msm-dai-q6-tdm";
 			qcom,msm-cpudai-tdm-dev-id = <36869>;
-			qcom,msm-cpudai-tdm-sync-mode = <0>;
-			qcom,msm-cpudai-tdm-sync-src = <0>;
-			qcom,msm-cpudai-tdm-data-out = <0>;
-			qcom,msm-cpudai-tdm-invert-sync = <0>;
-			qcom,msm-cpudai-tdm-data-delay = <0>;
 			qcom,msm-cpudai-tdm-data-align = <0>;
 		};
 		dai_pri_tdm_tx_3: qcom,msm-dai-q6-tdm-pri-tx-3 {
 			compatible = "qcom,msm-dai-q6-tdm";
 			qcom,msm-cpudai-tdm-dev-id = <36871>;
-			qcom,msm-cpudai-tdm-sync-mode = <0>;
-			qcom,msm-cpudai-tdm-sync-src = <0>;
-			qcom,msm-cpudai-tdm-data-out = <0>;
-			qcom,msm-cpudai-tdm-invert-sync = <0>;
-			qcom,msm-cpudai-tdm-data-delay = <0>;
 			qcom,msm-cpudai-tdm-data-align = <0>;
 		};
 	};
@@ -187,6 +167,7 @@
 		status = "disabled";
 		compatible = "qcom,bg-codec";
 		qcom,subsys-name = "modem";
+		qcom,bg-speaker-connected;
 		qcom,bg-glink {
 			compatible = "qcom,bg-cdc-glink";
 			qcom,msm-glink-channels = <4>;
diff --git a/arch/arm64/boot/dts/qcom/msm8909-coresight.dtsi b/arch/arm64/boot/dts/qcom/msm8909-coresight.dtsi
index 4e7d6f8..9d35b06 100644
--- a/arch/arm64/boot/dts/qcom/msm8909-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8909-coresight.dtsi
@@ -1,413 +1,694 @@
-/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2015-2018, 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
+ * it under the terms of the GNU General Public License version 2 an
  * 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  * GNU General Public License for more details.
  */
 
 &soc {
 	tmc_etr: tmc@826000 {
-		compatible = "arm,coresight-tmc";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b961>;
+
 		reg = <0x826000 0x1000>,
 		      <0x884000 0x15000>;
 		reg-names = "tmc-base", "bam-base";
+
 		interrupts = <0 166 0>;
 		interrupt-names = "byte-cntr-irq";
 
-		qcom,memory-size = <0x100000>;
-		qcom,sg-enable;
+		arm,buffer-size = <0x100000>;
+		arm,sg-enable;
 
-		coresight-id = <0>;
 		coresight-name = "coresight-tmc-etr";
-		coresight-nr-inports = <1>;
 		coresight-ctis = <&cti0 &cti8>;
-		clocks = <&clock_rpm clk_qdss_clk>,
-			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-	};
-
-	tpiu: tpiu@820000 {
-		compatible = "arm,coresight-tpiu";
-		reg = <0x820000 0x1000>,
-		      <0x1100000 0xb0000>;
-		reg-names = "tpiu-base", "nidnt-base";
-
-		coresight-id = <1>;
-		coresight-name = "coresight-tpiu";
-		coresight-nr-inports = <1>;
-
-		qcom,nidnthw;
-		qcom,nidnt-swduart;
-		qcom,nidnt-swdtrc;
-		qcom,nidnt-jtag;
-		qcom,nidnt-spmi;
-		nidnt-gpio = <38>;
-		nidnt-gpio-polarity = <1>;
-
-		interrupts = <0 82 0>;
-		interrupt-names = "nidnt-irq";
-
-		vdd-supply = <&pm8909_l11>;
-		qcom,vdd-voltage-level = <2950000 2950000>;
-		qcom,vdd-current-level = <15000 400000>;
-
-		vdd-io-supply = <&pm8909_l12>;
-		qcom,vdd-io-voltage-level = <2950000 2950000>;
-		qcom,vdd-io-current-level = <200 50000>;
+		coresight-csr = <&csr>;
 
 		clocks = <&clock_rpm clk_qdss_clk>,
 			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-	};
-
-	replicator: replicator@824000 {
-		compatible = "qcom,coresight-replicator";
-		reg = <0x824000 0x1000>;
-		reg-names = "replicator-base";
-
-		coresight-id = <2>;
-		coresight-name = "coresight-replicator";
-		coresight-nr-inports = <1>;
-		coresight-outports = <0 1>;
-		coresight-child-list = <&tmc_etr &tpiu>;
-		coresight-child-ports = <0 0>;
-		clocks = <&clock_rpm clk_qdss_clk>,
-			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
+		clock-names = "apb_pclk";
+		port {
+			tmc_etr_in_replicator: endpoint {
+				slave-mode;
+				remote-endpoint = <&replicator_out_tmc_etr>;
+			};
+		};
 	};
 
 	tmc_etf: tmc@825000 {
-		compatible = "arm,coresight-tmc";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b961>;
+
 		reg = <0x825000 0x1000>;
 		reg-names = "tmc-base";
 
-		coresight-id = <3>;
 		coresight-name = "coresight-tmc-etf";
-		coresight-nr-inports = <1>;
-		coresight-outports = <0>;
-		coresight-child-list = <&replicator>;
-		coresight-child-ports = <0>;
-		coresight-default-sink;
+
+		arm,default-sink;
 		coresight-ctis = <&cti0 &cti8>;
+		coresight-csr = <&csr>;
 
 		clocks = <&clock_rpm clk_qdss_clk>,
 			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				tmc_etf_out_replicator:endpoint {
+					remote-endpoint =
+						<&replicator_in_tmc_etf>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				tmc_etf_in_funnel_in0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_in0_out_tmc_etf>;
+				};
+			};
+		};
+	};
+
+	replicator: replicator@824000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b909>;
+
+		reg = <0x824000 0x1000>;
+		reg-names = "replicator-base";
+
+		coresight-name = "coresight-replicator";
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				replicator_out_tmc_etr: endpoint {
+					remote-endpoint =
+						<&tmc_etr_in_replicator>;
+				};
+			};
+			port@1 {
+				reg = <0>;
+				replicator_in_tmc_etf: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tmc_etf_out_replicator>;
+				};
+			};
+		};
 	};
 
 	funnel_in0: funnel@821000 {
-		compatible = "arm,coresight-funnel";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
 		reg = <0x821000 0x1000>;
 		reg-names = "funnel-base";
 
-		coresight-id = <4>;
 		coresight-name = "coresight-funnel-in0";
-		coresight-nr-inports = <8>;
-		coresight-outports = <0>;
-		coresight-child-list = <&tmc_etf>;
-		coresight-child-ports = <0>;
+
 		clocks = <&clock_rpm clk_qdss_clk>,
 			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			port@0 {
+				funnel_in0_out_tmc_etf: endpoint {
+					remote-endpoint =
+						<&tmc_etf_in_funnel_in0>;
+				};
+			};
+			port@1 {
+				reg = <7>;
+				funnel_in0_in_stm: endpoint {
+					slave-mode;
+					remote-endpoint = <&stm_out_funnel_in0>;
+				};
+			};
+
+			port@2 {
+				reg = <3>;
+				funnel_in0_in_funnel_center: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_center_out_funnel_in0>;
+				};
+			};
+
+			port@3 {
+				reg = <4>;
+				funnel_in0_in_funnel_right: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_right_out_funnel_in0>;
+				};
+			};
+
+			port@4 {
+
+				reg = <0>;
+				funnel_in0_in_rpm_etm0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&rpm_etm0_out_funnel_center>;
+				};
+			};
+
+			port@5 {
+				reg = <1>;
+				funnel_in0_in_modem_etm0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&modem_etm0_out_funnel_right>;
+				};
+			};
+		};
 	};
 
-	funnel_in2: funnel@869000 {
-		compatible = "arm,coresight-funnel";
+	funnel_center: funnel@869000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
 		reg = <0x869000 0x1000>;
 		reg-names = "funnel-base";
 
-		coresight-id = <5>;
-		coresight-name = "coresight-funnel-in2";
-		coresight-nr-inports = <8>;
-		coresight-outports = <0>;
-		coresight-child-list = <&funnel_in0>;
-		coresight-child-ports = <6>;
+		coresight-name = "coresight-funnel-center";
+
 		clocks = <&clock_rpm clk_qdss_clk>,
 			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				funnel_center_out_funnel_in0: endpoint {
+					remote-endpoint =
+						<&funnel_in0_in_funnel_center>;
+				};
+			};
+
+			port@2 {
+				reg = <2>;
+				funnel_center_in_dbgui: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&dbgui_out_funnel_center>;
+				};
+			};
+		};
 	};
 
-	funnel_in3: funnel@868000 {
-		compatible = "arm,coresight-funnel";
+	funnel_right: funnel@868000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
 		reg = <0x868000 0x1000>;
 		reg-names = "funnel-base";
 
-		coresight-id = <6>;
-		coresight-name = "coresight-funnel-in3";
-		coresight-nr-inports = <2>;
-		coresight-outports = <0>;
-		coresight-child-list = <&funnel_in2>;
-		coresight-child-ports = <7>;
+		coresight-name = "coresight-funnel-right";
+
 		clocks = <&clock_rpm clk_qdss_clk>,
 			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				funnel_right_out_funnel_in0: endpoint {
+					remote-endpoint =
+						<&funnel_in0_in_funnel_right>;
+				};
+			};
+
+			port@2 {
+				reg = <2>;
+				funnel_right_in_funnel_apss: endpoint {
+					slave-mode;
+					remote-endpoint =
+					       <&funnel_apss_out_funnel_right>;
+				};
+			};
+
+			port@3 {
+				reg = <0>;
+				funnel_right_in_wcn_etm0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&wcn_etm0_out_funnel_mm>;
+				};
+			};
+		};
 	};
 
-	cti0: cti@810000 {
-		compatible = "arm,coresight-cti";
-		reg = <0x810000 0x1000>;
-		reg-names = "cti-base";
+	funnel_apss: funnel@855000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
 
-		coresight-id = <7>;
-		coresight-name = "coresight-cti0";
-		coresight-nr-inports = <0>;
+		reg = <0x855000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-apss";
+
 		clocks = <&clock_rpm clk_qdss_clk>,
 			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				funnel_apss_out_funnel_right: endpoint {
+					remote-endpoint =
+						<&funnel_right_in_funnel_apss>;
+				};
+			};
+
+			port@1 {
+				reg = <4>;
+				funnel_apss0_in_etm0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&etm0_out_funnel_apss0>;
+				};
+			};
+
+			port@2 {
+				reg = <5>;
+				funnel_apss0_in_etm1: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&etm1_out_funnel_apss0>;
+				};
+			};
+
+			port@3 {
+				reg = <6>;
+				funnel_apss0_in_etm2: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&etm2_out_funnel_apss0>;
+					};
+			};
+
+			port@4 {
+				reg = <7>;
+				funnel_apss0_in_etm3: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&etm3_out_funnel_apss0>;
+				};
+			};
+
+		};
+
 	};
 
-	cti1: cti@811000 {
-		compatible = "arm,coresight-cti";
-		reg = <0x811000 0x1000>;
-		reg-names = "cti-base";
+	tpiu: tpiu@820000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b912>;
+		coresight-name = "coresight-tpiu";
 
-		coresight-id = <8>;
-		coresight-name = "coresight-cti1";
-		coresight-nr-inports = <0>;
+		reg = <0x820000 0x1000>,
+		      <0x1100000 0xb0000>;
+		reg-names = "tpiu-base", "nidnt-base";
 		clocks = <&clock_rpm clk_qdss_clk>,
 			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
+		clock-names = "apb_pclk";
 	};
 
-	cti2: cti@812000 {
-		compatible = "arm,coresight-cti";
-		reg = <0x812000 0x1000>;
-		reg-names = "cti-base";
+	etm0: etm@84c000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b955>;
 
-		coresight-id = <9>;
-		coresight-name = "coresight-cti2";
-		coresight-nr-inports = <0>;
+		reg = <0x84c000 0x1000>;
+		cpu = <&CPU0>;
+		coresight-name = "coresight-etm0";
+
 		clocks = <&clock_rpm clk_qdss_clk>,
 			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
+		clock-names = "apb_pclk";
+
+		port {
+			etm0_out_funnel_apss0: endpoint {
+				remote-endpoint = <&funnel_apss0_in_etm0>;
+			};
+		};
 	};
 
-	cti3: cti@813000 {
-		compatible = "arm,coresight-cti";
-		reg = <0x813000 0x1000>;
-		reg-names = "cti-base";
+	etm1: etm@84d000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b955>;
 
-		coresight-id = <10>;
-		coresight-name = "coresight-cti3";
-		coresight-nr-inports = <0>;
+		reg = <0x84d000 0x1000>;
+		cpu = <&CPU1>;
+		coresight-name = "coresight-etm1";
+
 		clocks = <&clock_rpm clk_qdss_clk>,
 			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
+		clock-names = "apb_pclk";
+
+		port {
+			etm1_out_funnel_apss0: endpoint {
+				remote-endpoint = <&funnel_apss0_in_etm1>;
+			};
+		};
 	};
 
-	cti4: cti@814000 {
-		compatible = "arm,coresight-cti";
-		reg = <0x814000 0x1000>;
-		reg-names = "cti-base";
+	etm2: etm@84e000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b955>;
 
-		coresight-id = <11>;
-		coresight-name = "coresight-cti4";
-		coresight-nr-inports = <0>;
+		reg = <0x84e000 0x1000>;
+		cpu = <&CPU2>;
+		coresight-name = "coresight-etm2";
+
 		clocks = <&clock_rpm clk_qdss_clk>,
 			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
+		clock-names = "apb_pclk";
+
+		port {
+			etm2_out_funnel_apss0: endpoint {
+				remote-endpoint = <&funnel_apss0_in_etm2>;
+			};
+		};
 	};
 
-	cti5: cti@815000 {
-		compatible = "arm,coresight-cti";
-		reg = <0x815000 0x1000>;
-		reg-names = "cti-base";
+	etm3: etm@84f000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b955>;
 
-		coresight-id = <12>;
-		coresight-name = "coresight-cti5";
-		coresight-nr-inports = <0>;
-		clocks = <&clock_rpm clk_qdss_clk>,
-			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-	};
-
-	cti6: cti@816000 {
-		compatible = "arm,coresight-cti";
-		reg = <0x816000 0x1000>;
-		reg-names = "cti-base";
-
-		coresight-id = <13>;
-		coresight-name = "coresight-cti6";
-		coresight-nr-inports = <0>;
-		clocks = <&clock_rpm clk_qdss_clk>,
-			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-
-		qcom,cti-gpio-trigout = <2>;
-		pinctrl-names = "cti-trigout-pctrl";
-		pinctrl-0 = <&trigout_a0>;
-	};
-
-	cti7: cti@817000 {
-		compatible = "arm,coresight-cti";
-		reg = <0x817000 0x1000>;
-		reg-names = "cti-base";
-
-		coresight-id = <14>;
-		coresight-name = "coresight-cti7";
-		coresight-nr-inports = <0>;
-		clocks = <&clock_rpm clk_qdss_clk>,
-			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-	};
-
-	cti8: cti@818000 {
-		compatible = "arm,coresight-cti";
-		reg = <0x818000 0x1000>;
-		reg-names = "cti-base";
-
-		coresight-id = <15>;
-		coresight-name = "coresight-cti8";
-		coresight-nr-inports = <0>;
-		clocks = <&clock_rpm clk_qdss_clk>,
-			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-	};
-
-	cti_cpu0: cti@851000 {
-		compatible = "arm,coresight-cti";
-		reg = <0x851000 0x1000>;
-		reg-names = "cti-base";
-
-		coresight-id = <16>;
-		coresight-name = "coresight-cti-cpu0";
-		coresight-nr-inports = <0>;
-		coresight-cti-cpu = <&CPU0>;
-
-		qcom,cti-save;
+		reg = <0x84f000 0x1000>;
+		coresight-name = "coresight-etm3";
+		cpu = <&CPU3>;
 
 		clocks = <&clock_rpm clk_qdss_clk>,
 			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-	};
+		clock-names = "apb_pclk";
 
-	cti_cpu1: cti@852000 {
-		compatible = "arm,coresight-cti";
-		reg = <0x852000 0x1000>;
-		reg-names = "cti-base";
-
-		coresight-id = <17>;
-		coresight-name = "coresight-cti-cpu1";
-		coresight-nr-inports = <0>;
-		coresight-cti-cpu = <&CPU1>;
-
-		qcom,cti-save;
-
-		clocks = <&clock_rpm clk_qdss_clk>,
-			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-	};
-
-	cti_cpu2: cti@853000 {
-		compatible = "arm,coresight-cti";
-		reg = <0x853000 0x1000>;
-		reg-names = "cti-base";
-
-		coresight-id = <18>;
-		coresight-name = "coresight-cti-cpu2";
-		coresight-nr-inports = <0>;
-		coresight-cti-cpu = <&CPU2>;
-
-		qcom,cti-save;
-
-		clocks = <&clock_rpm clk_qdss_clk>,
-			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-	};
-
-	cti_cpu3: cti@854000 {
-		compatible = "arm,coresight-cti";
-		reg = <0x854000 0x1000>;
-		reg-names = "cti-base";
-
-		coresight-id = <19>;
-		coresight-name = "coresight-cti-cpu3";
-		coresight-nr-inports = <0>;
-		coresight-cti-cpu = <&CPU3>;
-
-		qcom,cti-save;
-
-		clocks = <&clock_rpm clk_qdss_clk>,
-			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-	};
-
-	cti_rpm_cpu0: cti@83c000 {
-		compatible = "arm,coresight-cti";
-		reg = <0x83c000 0x1000>;
-		reg-names = "cti-base";
-
-		coresight-id = <20>;
-		coresight-name = "coresight-cti-rpm-cpu0";
-		coresight-nr-inports = <0>;
-
-		clocks = <&clock_rpm clk_qdss_clk>,
-			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-	};
-
-	cti_modem_cpu0: cti@838000 {
-		compatible = "arm,coresight-cti";
-		reg = <0x838000 0x1000>;
-		reg-names = "cti-base";
-
-		coresight-id = <21>;
-		coresight-name = "coresight-cti-modem-cpu0";
-		coresight-nr-inports = <0>;
-
-		clocks = <&clock_rpm clk_qdss_clk>,
-			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-	};
-
-	cti_wcn_cpu0: cti@835000 {
-		compatible = "arm,coresight-cti";
-		reg = <0x835000 0x1000>;
-		reg-names = "cti-base";
-
-		coresight-id = <22>;
-		coresight-name = "coresight-cti-wcn-cpu0";
-		coresight-nr-inports = <0>;
-
-		clocks = <&clock_rpm clk_qdss_clk>,
-			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-	};
-
-	cti_video_cpu0: cti@830000 {
-		compatible = "arm,coresight-cti";
-		reg = <0x830000 0x1000>;
-		reg-names = "cti-base";
-
-		coresight-id = <23>;
-		coresight-name = "coresight-cti-video-cpu0";
-		coresight-nr-inports = <0>;
-
-		clocks = <&clock_rpm clk_qdss_clk>,
-			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
+		port {
+			etm3_out_funnel_apss0: endpoint {
+				remote-endpoint = <&funnel_apss0_in_etm3>;
+			};
+		};
 	};
 
 	stm: stm@802000 {
-		compatible = "arm,coresight-stm";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b962>;
+
 		reg = <0x802000 0x1000>,
 		      <0x9280000 0x180000>;
-		reg-names = "stm-base", "stm-data-base";
+		reg-names = "stm-base", "stm-stimulus-base";
 
-		coresight-id = <24>;
 		coresight-name = "coresight-stm";
-		coresight-nr-inports = <0>;
-		coresight-outports = <0>;
-		coresight-child-list = <&funnel_in0>;
-		coresight-child-ports = <7>;
+
 		clocks = <&clock_rpm clk_qdss_clk>,
 			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
+		clock-names = "apb_pclk";
+
+		port {
+			stm_out_funnel_in0: endpoint {
+				remote-endpoint = <&funnel_in0_in_stm>;
+			};
+		};
+	};
+
+	cti0: cti@810000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x810000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti0";
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti1: cti@811000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x811000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti1";
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti2: cti@812000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x812000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti2";
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti3: cti@813000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x813000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti3";
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti4: cti@814000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x814000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti4";
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti5: cti@815000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x815000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti5";
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti6: cti@816000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x816000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti6";
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti7: cti@817000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x817000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti7";
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti8: cti@818000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x818000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti8";
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_cpu0: cti@851000{
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x851000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-cpu0";
+		cpu = <&CPU0>;
+		qcom,cti-save;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_cpu1: cti@852000{
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x852000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-cpu1";
+		cpu = <&CPU1>;
+		qcom,cti-save;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_cpu2: cti@853000{
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x853000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-cpu2";
+		cpu = <&CPU2>;
+		qcom,cti-save;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_cpu3: cti@854000{
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x854000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-cpu3";
+		cpu = <&CPU3>;
+		qcom,cti-save;
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_modem_cpu0: cti@838000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x838000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-modem-cpu0";
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	/* Venus CTI */
+	cti_video_cpu0: cti@830000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x830000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-video-cpu0";
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	/* Pronto CTI */
+	cti_wcn_cpu0: cti@835000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x835000 0x1000>;
+		reg-names = "cti-base";
+		coresight-name = "coresight-cti-wcn-cpu0";
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	wcn_etm0 {
+		compatible = "qcom,coresight-remote-etm";
+		coresight-name = "coresight-wcn-etm0";
+		qcom,inst-id = <3>;
+
+		port {
+			wcn_etm0_out_funnel_mm: endpoint {
+				remote-endpoint = <&funnel_right_in_wcn_etm0>;
+			};
+		};
+	};
+
+	/* MSS_SCL */
+	modem_etm0 {
+		compatible = "qcom,coresight-remote-etm";
+		coresight-name = "coresight-modem-etm0";
+		qcom,inst-id = <11>;
+
+		port {
+			modem_etm0_out_funnel_right: endpoint {
+				remote-endpoint = <&funnel_in0_in_modem_etm0>;
+			};
+		};
+	};
+
+	rpm_etm0 {
+		compatible = "qcom,coresight-remote-etm";
+		coresight-name = "coresight-rpm-etm0";
+		qcom,inst-id = <4>;
+
+		port {
+			rpm_etm0_out_funnel_center: endpoint {
+				remote-endpoint = <&funnel_in0_in_rpm_etm0>;
+			};
+		};
 	};
 
 	csr: csr@801000 {
@@ -415,209 +696,52 @@
 		reg = <0x801000 0x1000>;
 		reg-names = "csr-base";
 
-		coresight-id = <25>;
 		coresight-name = "coresight-csr";
-		coresight-nr-inports = <0>;
 
+		qcom,usb-bam-support;
+		qcom,hwctrl-set-support;
+		qcom,set-byte-cntr-support;
 		qcom,blk-size = <1>;
-		clocks = <&clock_rpm clk_qdss_clk>,
-			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-	};
-
-	funnel_apss: funnel@855000 {
-		compatible = "arm,coresight-funnel";
-		reg = <0x855000 0x1000>;
-		reg-names = "funnel-base";
-
-		coresight-id = <26>;
-		coresight-name = "coresight-funnel-apss";
-		coresight-nr-inports = <4>;
-		coresight-outports = <0>;
-		coresight-child-list = <&funnel_in0>;
-		coresight-child-ports = <4>;
-
-		clocks = <&clock_rpm clk_qdss_clk>,
-			<&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-	};
-
-	etm0: etm@84c000 {
-		compatible = "arm,coresight-etm";
-		reg = <0x84c000 0x1000>;
-		reg-names = "etm-base";
-
-		coresight-id = <27>;
-		coresight-name = "coresight-etm0";
-		coresight-nr-inports = <0>;
-		coresight-outports = <0>;
-		coresight-child-list = <&funnel_apss>;
-		coresight-child-ports = <0>;
-		coresight-etm-cpu = <&CPU0>;
-
-		clocks = <&clock_rpm clk_qdss_clk>,
-			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-	};
-
-	etm1: etm@84d000 {
-		compatible = "arm,coresight-etm";
-		reg = <0x84d000 0x1000>;
-		reg-names = "etm-base";
-
-		coresight-id = <28>;
-		coresight-name = "coresight-etm1";
-		coresight-nr-inports = <0>;
-		coresight-outports = <0>;
-		coresight-child-list = <&funnel_apss>;
-		coresight-child-ports = <1>;
-		coresight-etm-cpu = <&CPU1>;
-
-		clocks = <&clock_rpm clk_qdss_clk>,
-			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-	};
-
-	etm2: etm@84e000 {
-		compatible = "arm,coresight-etm";
-		reg = <0x84e000 0x1000>;
-		reg-names = "etm-base";
-
-		coresight-id = <29>;
-		coresight-name = "coresight-etm2";
-		coresight-nr-inports = <0>;
-		coresight-outports = <0>;
-		coresight-child-list = <&funnel_apss>;
-		coresight-child-ports = <2>;
-		coresight-etm-cpu = <&CPU2>;
-
-		clocks = <&clock_rpm clk_qdss_clk>,
-			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-	};
-
-	etm3: etm@84f000 {
-		compatible = "arm,coresight-etm";
-		reg = <0x84f000 0x1000>;
-		reg-names = "etm-base";
-
-		coresight-id = <30>;
-		coresight-name = "coresight-etm3";
-		coresight-nr-inports = <0>;
-		coresight-outports = <0>;
-		coresight-child-list = <&funnel_apss>;
-		coresight-child-ports = <3>;
-		coresight-etm-cpu = <&CPU3>;
-
-		clocks = <&clock_rpm clk_qdss_clk>,
-			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-	};
-
-	hwevent: hwevent@86c000 {
-		compatible = "qcom,coresight-hwevent";
-		reg = <0x86c000 0x108>,
-		      <0x86cfb0 0x4>,
-		      <0x78c5010 0x4>,
-		      <0x7885010 0x4>;
-		reg-names = "wrapper-mux", "wrapper-lockaccess", "usbbam-mux",
-				"blsp-mux";
-		coresight-id = <31>;
-		coresight-name = "coresight-hwevent";
-		coresight-nr-inports = <0>;
-
-		clocks = <&clock_rpm clk_qdss_clk>,
-			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
-	};
-
-	rpm_etm0 {
-		compatible = "qcom,coresight-remote-etm";
-
-		coresight-id = <32>;
-		coresight-name = "coresight-rpm-etm0";
-		coresight-nr-inports = <0>;
-		coresight-outports = <0>;
-		coresight-child-list = <&funnel_in0>;
-		coresight-child-ports = <0>;
-
-		qcom,inst-id = <4>;
-	};
-
-	wcn_etm0 {
-		compatible = "qcom,coresight-remote-etm";
-
-		coresight-id = <33>;
-		coresight-name = "coresight-wcn-etm0";
-		coresight-nr-inports = <0>;
-		coresight-outports = <0>;
-		coresight-child-list = <&funnel_in3>;
-		coresight-child-ports = <0>;
-
-		qcom,inst-id = <3>;
-	};
-
-	modem_etm0 {
-		compatible = "qcom,coresight-remote-etm";
-
-		coresight-id = <34>;
-		coresight-name = "coresight-modem-etm0";
-		coresight-nr-inports = <0>;
-		coresight-outports = <0>;
-		coresight-child-list = <&funnel_in0>;
-		coresight-child-ports = <2>;
-
-		qcom,inst-id = <2>;
-	};
-
-	fuse: fuse@5e01c {
-		compatible = "arm,coresight-fuse-v2";
-		reg = <0x5e01c 0x8>,
-		      <0x58040 0x4>,
-		      <0x5e00c 0x4>;
-		reg-names = "fuse-base", "nidnt-fuse-base", "qpdi-fuse-base";
-
-		coresight-id = <35>;
-		coresight-name = "coresight-fuse";
-		coresight-nr-inports = <0>;
-	};
-
-	qpdi: qpdi@1941000 {
-		compatible = "qcom,coresight-qpdi";
-		reg = <0x1941000 0x4>;
-		reg-names = "qpdi-base";
-
-		coresight-id = <36>;
-		coresight-name = "coresight-qpdi";
-		coresight-nr-inports = <0>;
-
-		vdd-supply = <&pm8909_l11>;
-		qcom,vdd-voltage-level = <2800000 2950000>;
-		qcom,vdd-current-level = <15000 400000>;
-
-		vdd-io-supply = <&pm8909_l12>;
-		qcom,vdd-io-voltage-level = <1800000 2950000>;
-		qcom,vdd-io-current-level = <200 50000>;
 	};
 
 	dbgui: dbgui@86d000 {
 		compatible = "qcom,coresight-dbgui";
 		reg = <0x86d000 0x1000>;
 		reg-names = "dbgui-base";
-
-		coresight-id = <37>;
 		coresight-name = "coresight-dbgui";
-		coresight-nr-inports = <0>;
-		coresight-outports = <0>;
-		coresight-child-list = <&funnel_in2>;
-		coresight-child-ports = <2>;
 
 		qcom,dbgui-addr-offset = <0x30>;
-		qcom,dbgui-data-offset = <0xB0>;
-		qcom,dbgui-size = <32>;
+		qcom,dbgui-data-offset = <0x130>;
+		qcom,dbgui-size = <64>;
 
 		clocks = <&clock_rpm clk_qdss_clk>,
 			 <&clock_rpm clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
+		clock-names = "apb_pclk";
+
+		port {
+			dbgui_out_funnel_center: endpoint {
+				remote-endpoint = <&funnel_center_in_dbgui>;
+			};
+		};
 	};
+
+	hwevent: hwevent@86c000 {
+		compatible = "qcom,coresight-hwevent";
+
+		reg = <0x86c000 0x108>,
+		      <0x86cfb0 0x4>,
+		      <0x78c5010 0x4>,
+		      <0x7885010 0x4>;
+
+		reg-names = "center-wrapper-mux", "center-wrapper-lockaccess",
+				"right-wrapper-mux", "right-wrapper-lockaccess";
+
+		coresight-csr = <&csr>;
+		coresight-name = "coresight-hwevent";
+
+		clocks = <&clock_rpm clk_qdss_clk>,
+			 <&clock_rpm clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8909-ion.dtsi b/arch/arm64/boot/dts/qcom/msm8909-ion.dtsi
index 858429b..cd21e6e 100644
--- a/arch/arm64/boot/dts/qcom/msm8909-ion.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8909-ion.dtsi
@@ -33,12 +33,6 @@
 			qcom,ion-heap-type = "DMA";
 		};
 
-		modem_heap: qcom,ion-heap@26 { /* MODEM HEAP */
-			reg = <26>;
-			memory-region = <&modem_adsp_mem>;
-			qcom,ion-heap-type = "DMA";
-		};
-
 		qcom,ion-heap@19 { /* QSEECOM TA HEAP */
 			reg = <19>;
 			memory-region = <&qseecom_ta_mem>;
diff --git a/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi
index 18fc575..e2fbc9e 100644
--- a/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi
@@ -410,27 +410,3 @@
 		};
 	};
 };
-
-/* CoreSight */
-&tpiu {
-	pinctrl-names = "sdcard", "trace", "swduart",
-			"swdtrc", "jtag", "spmi";
-	/* NIDnT */
-	pinctrl-0 = <&qdsd_clk_sdcard &qdsd_cmd_sdcard
-		     &qdsd_data0_sdcard &qdsd_data1_sdcard
-		     &qdsd_data2_sdcard &qdsd_data3_sdcard>;
-	pinctrl-1 = <&qdsd_clk_trace &qdsd_cmd_trace
-		     &qdsd_data0_trace &qdsd_data1_trace
-		     &qdsd_data2_trace &qdsd_data3_trace>;
-	pinctrl-2 = <&qdsd_cmd_swduart &qdsd_data0_swduart
-		     &qdsd_data1_swduart &qdsd_data2_swduart
-		     &qdsd_data3_swduart>;
-	pinctrl-3 = <&qdsd_clk_swdtrc &qdsd_cmd_swdtrc
-		     &qdsd_data0_swdtrc &qdsd_data1_swdtrc
-		     &qdsd_data2_swdtrc &qdsd_data3_swdtrc>;
-	pinctrl-4 = <&qdsd_cmd_jtag &qdsd_data0_jtag
-		     &qdsd_data1_jtag &qdsd_data2_jtag
-		     &qdsd_data3_jtag>;
-	pinctrl-5 = <&qdsd_clk_spmi &qdsd_cmd_spmi
-		     &qdsd_data0_spmi &qdsd_data3_spmi>;
-};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-vidc.dtsi b/arch/arm64/boot/dts/qcom/msm8909-vidc.dtsi
new file mode 100644
index 0000000..5eeaa21
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-vidc.dtsi
@@ -0,0 +1,163 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	qcom,vidc@1d00000 {
+		compatible = "qcom,msm-vidc";
+		reg = <0x01d00000 0xff000>;
+		interrupts = <0 44 0>;
+		qcom,hfi-version = "3xx";
+		venus-supply = <&gdsc_venus>;
+		venus-core0-supply = <&gdsc_venus_core0>;
+		clocks = <&clock_gcc clk_gcc_venus0_vcodec0_clk>,
+			<&clock_gcc clk_gcc_venus0_core0_vcodec0_clk>,
+			<&clock_gcc clk_gcc_venus0_ahb_clk>,
+			<&clock_gcc clk_gcc_venus0_axi_clk>;
+		clock-names = "core_clk", "core0_clk", "iface_clk", "bus_clk";
+		qcom,clock-configs = <0x1 0x0 0x0 0x0>;
+		qcom,sw-power-collapse;
+		qcom,slave-side-cp;
+		qcom,hfi = "venus";
+		qcom,reg-presets = <0xe0020 0x05555556>,
+			<0xe0024 0x05555556>,
+			<0x80124 0x00000003>;
+		qcom,qdss-presets = <0x826000 0x1000>,
+			<0x827000 0x1000>,
+			<0x822000 0x1000>,
+			<0x803000 0x1000>,
+			<0x9180000 0x1000>,
+			<0x9181000 0x1000>;
+		qcom,max-hw-load = <244800>; /* 1080p@30 + 720p@30 */
+		qcom,firmware-name = "venus";
+		qcom,allowed-clock-rates = <307200000 266670000 133330000>;
+		qcom,clock-freq-tbl {
+			qcom,profile-enc {
+				qcom,codec-mask = <0x55555555>;
+				qcom,cycles-per-mb = <2316>;
+				qcom,low-power-mode-factor = <32768>;
+			};
+			qcom,profile-dec {
+				qcom,codec-mask = <0xf3ffffff>;
+				qcom,cycles-per-mb = <788>;
+			};
+			qcom,profile-hevcdec {
+				qcom,codec-mask = <0x0c000000>;
+				qcom,cycles-per-mb = <1015>;
+			};
+		};
+
+		/* MMUs */
+		non_secure_cb {
+			compatible = "qcom,msm-vidc,context-bank";
+			label = "venus_ns";
+			iommus = <&apps_iommu 0x800 0x00>,
+				<&apps_iommu 0x807 0x00>,
+				<&apps_iommu 0x808 0x27>,
+				<&apps_iommu 0x811 0x0>;
+			buffer-types = <0xfff>;
+			virtual-addr-pool = <0x5dc00000 0x8f000000>;
+		};
+
+		secure_bitstream_cb {
+			compatible = "qcom,msm-vidc,context-bank";
+			label = "venus_sec_bitstream";
+			iommus = <&apps_iommu 0x90c 0x20>;
+			buffer-types = <0x241>;
+			virtual-addr-pool = <0x4b000000 0x12c00000>;
+			qcom,secure-context-bank;
+		};
+
+		secure_pixel_cb {
+			compatible = "qcom,msm-vidc,context-bank";
+			label = "venus_sec_pixel";
+			iommus = <&apps_iommu 0x900 0x00>,
+				<&apps_iommu 0x909 0x20>,
+				<&apps_iommu 0x90a 0x00>,
+				<&apps_iommu 0x90b 0x20>,
+				<&apps_iommu 0x90e 0x00>;
+			buffer-types = <0x106>;
+			virtual-addr-pool = <0x25800000 0x25800000>;
+			qcom,secure-context-bank;
+		};
+
+		secure_non_pixel_cb {
+			compatible = "qcom,msm-vidc,context-bank";
+			label = "venus_sec_non_pixel";
+			iommus = <&apps_iommu 0x9c0 0x00>,
+				<&apps_iommu 0x907 0x00>,
+				<&apps_iommu 0x908 0x20>,
+				<&apps_iommu 0x90d 0x20>,
+				<&apps_iommu 0x90f 0x00>;
+			buffer-types = <0x480>;
+			virtual-addr-pool = <0x1000000 0x24800000>;
+			qcom,secure-context-bank;
+		};
+
+		/* Buses */
+		venus_bus_ddr {
+			compatible = "qcom,msm-vidc,bus";
+			label = "venus-ddr";
+			qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+			qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+			qcom,bus-governor = "venus-ddr-gov";
+			qcom,bus-range-kbps = <1000 917000>;
+		};
+
+		arm9_bus_ddr {
+			compatible = "qcom,msm-vidc,bus";
+			label = "venus-arm9-ddr";
+			qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+			qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+			qcom,bus-governor = "performance";
+			qcom,bus-range-kbps = <1 1>;
+		};
+	};
+
+	venus-ddr-gov {
+		compatible = "qcom,msm-vidc,governor,table";
+		name = "venus-ddr-gov";
+		status = "ok";
+		qcom,bus-freq-table {
+			qcom,profile-enc {
+				qcom,codec-mask = <0x55555555>;
+				qcom,load-busfreq-tbl =
+					<244800 841000>,   /* 1080p30E   */
+					<216000 740000>,   /* 720p60E    */
+					<194400 680000>,   /* FWVGA120E  */
+					<144000 496000>,   /* VGA120E    */
+					<108000 370000>,   /* 720p30E    */
+					<97200  340000>,   /* FWVGA60E   */
+					<48600  170000>,   /* FWVGA30E   */
+					<72000  248000>,   /* VGA60E     */
+					<36000  124000>,   /* VGA30E     */
+					<18000  70000>,    /* QVGA60E    */
+					<9000   35000>,    /* QVGA30E    */
+					<0      0>;
+			};
+			qcom,profile-dec {
+				qcom,codec-mask = <0xffffffff>;
+				qcom,load-busfreq-tbl =
+					<244800 605000>,   /* 1080p30D   */
+					<216000 540000>,   /* 720p60D    */
+					<194400 484000>,   /* FWVGA120D  */
+					<144000 360000>,   /* VGA120D    */
+					<108000 270000>,   /* 720p30D    */
+					<97200  242000>,   /* FWVGA60D   */
+					<48600  121000>,   /* FWVGA30D   */
+					<72000  180000>,   /* VGA60D     */
+					<36000  90000>,    /* VGA30D     */
+					<18000  45000>,    /* HVGA30D    */
+					<0      0>;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909.dtsi b/arch/arm64/boot/dts/qcom/msm8909.dtsi
index a6d42f1..a72fdbf 100644
--- a/arch/arm64/boot/dts/qcom/msm8909.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8909.dtsi
@@ -239,6 +239,7 @@
 #include "msm8909-gpu.dtsi"
 #include "msm8909-coresight.dtsi"
 #include "msm8909-bus.dtsi"
+#include "msm8909-vidc.dtsi"
 #include "msm8909-mdss.dtsi"
 #include "msm8909-mdss-pll.dtsi"
 
@@ -1947,19 +1948,6 @@
 		memory-region = <&modem_adsp_mem>;
 	};
 
-	mcd {
-		compatible = "qcom,mcd";
-		qcom,ce-hw-instance = <0>;
-		qcom,ce-device = <0>;
-		clocks = <&clock_gcc clk_crypto_clk_src>,
-			 <&clock_gcc clk_gcc_crypto_clk>,
-			 <&clock_gcc clk_gcc_crypto_ahb_clk>,
-			 <&clock_gcc clk_gcc_crypto_axi_clk>;
-		clock-names = "core_clk_src", "core_clk",
-				"iface_clk", "bus_clk";
-		qcom,ce-opp-freq = <100000000>;
-	};
-
 	cpu0_slp_sts: cpu-sleep-status@b088008 {
 		reg = <0xb088008 0x100>;
 		qcom,sleep-status-mask= <0x80000>;
diff --git a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts
index 8149eb2..9dd80f0 100644
--- a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts
+++ b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts
@@ -320,4 +320,5 @@
 &mdss_dsi0 {
 	qcom,dsi-pref-prim-pan = <&dsi_auo_390p_cmd>;
 	qcom,platform-bklight-en-gpio = <&msm_gpio 52 0>;
+	qcom,platform-enable-gpio = <&msm_gpio 59 0>;
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8917-audio-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-audio-cdp.dtsi
new file mode 100644
index 0000000..465859a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-audio-cdp.dtsi
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015-2016, 2018, 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.
+ */
+
+&int_codec {
+	status = "okay";
+	qcom,msm-hs-micbias-type = "external";
+
+	asoc-wsa-codec-names = "wsa881x-i2c-codec.2-000f";
+	asoc-wsa-codec-prefixes = "SpkrMono";
+
+	msm-vdd-wsa-switch-supply = <&pm8937_l13>;
+	qcom,msm-vdd-wsa-switch-voltage = <3075000>;
+	qcom,msm-vdd-wsa-switch-current = <5000>;
+};
+
+&wsa881x_i2c_f {
+	status = "okay";
+};
+
+&wsa881x_i2c_45 {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-cdp-mirror-lake-touch.dtsi b/arch/arm64/boot/dts/qcom/msm8917-cdp-mirror-lake-touch.dtsi
new file mode 100644
index 0000000..d6d85fa
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-cdp-mirror-lake-touch.dtsi
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2017-2018, 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 "msm8917-pinctrl.dtsi"
+/* #include "msm8917-camera-sensor-cdp.dtsi"*/
+
+&soc {
+	gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+		pinctrl-names = "tlmm_gpio_key_active", "tlmm_gpio_key_suspend";
+		pinctrl-0 = <&gpio_key_active>;
+		pinctrl-1 = <&gpio_key_suspend>;
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&tlmm 128 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			debounce-interval = <15>;
+		};
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&tlmm 127 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&tlmm 91 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			debounce-interval = <15>;
+		};
+
+		home {
+			label = "home";
+			gpios = <&tlmm 86 0x1>;
+			linux,input-type = <1>;
+			linux,code = <102>;
+			debounce-interval = <15>;
+		};
+	};
+
+	hbtp {
+		compatible = "qcom,hbtp-input";
+		vcc_ana-supply = <&pm8937_l10>;
+		vcc_dig-supply = <&pm8937_l5>;
+		qcom,afe-load = <50000>;
+		qcom,afe-vtg-min = <2850000>;
+		qcom,afe-vtg-max = <2850000>;
+		qcom,dig-load = <15000>;
+		qcom,dig-vtg-min = <1800000>;
+		qcom,dig-vtg-max = <1800000>;
+	};
+
+	usb_detect {
+		compatible = "qcom,gpio-usbdetect";
+		interrupt-names = "vbus_det_irq";
+		interrupt-parent = <&tlmm>;
+		interrupts = <130 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb_mode_select>;
+		qcom,gpio-mode-sel = <&tlmm 130 0>;
+		qcom,notify-host-mode;
+		status = "disabled";
+	};
+};
+
+&flash_led {
+	compatible = "qcom,qpnp-flash-led";
+	reg = <0xd300 0x100>;
+	pinctrl-names = "flash_led_enable","flash_led_disable";
+	pinctrl-0 = <&rear_flash_led_enable>;
+	pinctrl-1 = <&rear_flash_led_disable>;
+	qcom,follow-otst2-rb-disabled;
+};
+
+&wled {
+	qcom,cons-sync-write-delay-us = <1000>;
+};
+
+&pmi_haptic{
+	qcom,actuator-type = "lra";
+	qcom,wave-play-rate-us = <4165>;
+	qcom,lra-auto-res-mode = "qwd";
+	qcom,lra-high-z = "opt1";
+	qcom,lra-res-cal-period = <0>;
+};
+
+&blsp1_uart2 {
+	status = "ok";
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart_console_active>;
+};
+
+#include "msm8937-mdss-panels.dtsi"
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+	hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_truly_720_vid>;
+	pinctrl-names = "mdss_default", "mdss_sleep";
+	pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+	qcom,platform-te-gpio = <&tlmm 24 0>;
+	qcom,platform-reset-gpio = <&tlmm 60 0>;
+	qcom,platform-bklight-en-gpio = <&tlmm 98 0>;
+};
+
+&dsi_truly_720_vid {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-pan-enable-dynamic-fps;
+	qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
+};
+
+&dsi_truly_720_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,ulps-enabled;
+	qcom,partial-update-enabled;
+	qcom,panel-roi-alignment = <2 2 2 2 2 2>;
+};
+
+&tlmm {
+	tlmm_gpio_key {
+		gpio_key_active: gpio_key_active {
+			mux {
+				pins = "gpio86", "gpio91", "gpio127", "gpio128";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio86", "gpio91", "gpio127", "gpio128";
+			};
+		};
+
+		gpio_key_suspend: gpio_key_suspend {
+			mux {
+				pins = "gpio86", "gpio91", "gpio127", "gpio128";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio86", "gpio91", "gpio127", "gpio128";
+			};
+		};
+	};
+};
+
+&sdhc_1 {
+	/* device core power supply */
+	vdd-supply = <&pm8937_l8>;
+	qcom,vdd-voltage-level = <2900000 2900000>;
+	qcom,vdd-current-level = <200 570000>;
+
+	/* device communication power supply */
+	vdd-io-supply = <&pm8937_l5>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <200 325000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on  &sdc1_rclk_on>;
+	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000
+								384000000>;
+	qcom,nonremovable;
+	qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+	status = "ok";
+};
+
+&sdhc_2 {
+	/* device core power supply */
+	vdd-supply = <&pm8937_l11>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <15000 800000>;
+
+	/* device communication power supply */
+	vdd-io-supply = <&pm8937_l12>;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <200 22000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+
+	#address-cells = <0>;
+	interrupt-parent = <&sdhc_2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+		1 &intc 0 221 0
+		2 &tlmm 67 0>;
+	interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+	cd-gpios = <&tlmm 67 0x1>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+								200000000>;
+	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+	status = "ok";
+};
+
+&i2c_3 {
+	status = "okay";
+	synaptics@22 {
+		compatible = "synaptics,dsx";
+		reg = <0x22>;
+		interrupt-parent = <&tlmm>;
+		interrupts = <65 0x2008>;
+		avdd-supply = <&pm8937_l10>;
+		vdd-supply = <&pm8937_l5>;
+		synaptics,vdd-voltage = <1880000 1880000>;
+		synaptics,avdd-voltage = <3008000 3008000>;
+		synaptics,vdd-current = <40000>;
+		synaptics,avdd-current = <20000>;
+		pinctrl-names = "pmx_ts_active","pmx_ts_suspend";
+		pinctrl-0 = <&ts_int_active &ts_reset_active>;
+		pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
+		synaptics,display-coords = <0 0 719 1439>;
+		synaptics,panel-coords  = <0 0 719 1439>;
+		synaptics,reset-gpio = <&tlmm 64 0x00>;
+		synaptics,irq-gpio = <&tlmm 65 0x2008>;
+		synaptics,disable-gpios;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi
new file mode 100644
index 0000000..fde4847
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2015-2018, 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 "msm8917-pinctrl.dtsi"
+/* #include "msm8917-camera-sensor-cdp.dtsi"*/
+
+&soc {
+	gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+		pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend";
+		pinctrl-0 = <&gpio_key_active>;
+		pinctrl-1 = <&gpio_key_suspend>;
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&tlmm 128 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			debounce-interval = <15>;
+		};
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&tlmm 127 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&tlmm 91 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			debounce-interval = <15>;
+		};
+
+		home {
+			label = "home";
+			gpios = <&tlmm 86 0x1>;
+			linux,input-type = <1>;
+			linux,code = <102>;
+			debounce-interval = <15>;
+		};
+	};
+
+	hbtp {
+		compatible = "qcom,hbtp-input";
+		vcc_ana-supply = <&pm8937_l10>;
+		vcc_dig-supply = <&pm8937_l5>;
+		qcom,afe-load = <50000>;
+		qcom,afe-vtg-min = <2850000>;
+		qcom,afe-vtg-max = <2850000>;
+		qcom,dig-load = <15000>;
+		qcom,dig-vtg-min = <1800000>;
+		qcom,dig-vtg-max = <1800000>;
+	};
+
+	usb_detect {
+		compatible = "qcom,gpio-usbdetect";
+		interrupt-names = "vbus_det_irq";
+		interrupt-parent = <&tlmm>;
+		interrupts = <130 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb_mode_select>;
+		qcom,gpio-mode-sel = <&tlmm 130 0>;
+		qcom,notify-host-mode;
+		status = "disabled";
+	};
+};
+
+&blsp1_uart2 {
+	status = "ok";
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart_console_active>;
+};
+
+#include "msm8937-mdss-panels.dtsi"
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+	hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_truly_720_vid>;
+	pinctrl-names = "mdss_default", "mdss_sleep";
+	pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+	qcom,platform-te-gpio = <&tlmm 24 0>;
+	qcom,platform-reset-gpio = <&tlmm 60 0>;
+	qcom,platform-bklight-en-gpio = <&tlmm 98 0>;
+};
+
+&dsi_truly_720_vid {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-pan-enable-dynamic-fps;
+	qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
+};
+
+&dsi_truly_720_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,ulps-enabled;
+	qcom,partial-update-enabled;
+	qcom,panel-roi-alignment = <2 2 2 2 2 2>;
+};
+
+&tlmm {
+	tlmm_gpio_key {
+		gpio_key_active: gpio_key_active {
+			mux {
+				pins = "gpio86", "gpio91", "gpio127", "gpio128";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio86", "gpio91", "gpio127", "gpio128";
+			};
+		};
+
+		gpio_key_suspend: gpio_key_suspend {
+			mux {
+				pins = "gpio86", "gpio91", "gpio127", "gpio128";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio86", "gpio91", "gpio127", "gpio128";
+			};
+		};
+	};
+};
+
+&sdhc_1 {
+	/* device core power supply */
+	vdd-supply = <&pm8937_l8>;
+	qcom,vdd-voltage-level = <2900000 2900000>;
+	qcom,vdd-current-level = <200 570000>;
+
+	/* device communication power supply */
+	vdd-io-supply = <&pm8937_l5>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <200 325000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on  &sdc1_rclk_on>;
+	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000
+								384000000>;
+	qcom,nonremovable;
+	qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+	status = "ok";
+};
+
+&sdhc_2 {
+	/* device core power supply */
+	vdd-supply = <&pm8937_l11>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <15000 800000>;
+
+	/* device communication power supply */
+	vdd-io-supply = <&pm8937_l12>;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <200 22000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+
+	#address-cells = <0>;
+	interrupt-parent = <&sdhc_2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+		1 &intc 0 221 0
+		2 &tlmm 67 0>;
+	interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+	cd-gpios = <&tlmm 67 0x1>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+								200000000>;
+	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+	status = "ok";
+};
+
diff --git a/arch/arm64/boot/dts/qcom/msm8917-coresight.dtsi b/arch/arm64/boot/dts/qcom/msm8917-coresight.dtsi
new file mode 100644
index 0000000..87303c5
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-coresight.dtsi
@@ -0,0 +1,1039 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	tmc_etr: tmc@6028000 {
+		compatible = "arm,primecell";
+		reg = <0x6028000 0x1000>,
+		      <0x6044000 0x15000>;
+		reg-names = "tmc-base", "bam-base";
+
+		interrupts = <0 166 0>;
+		interrupt-names = "byte-cntr-irq";
+
+		arm,buffer-size = <0x100000>;
+		arm,sg-enable;
+		qcom,force-reg-dump;
+
+		coresight-name = "coresight-tmc-etr";
+		coresight-csr = <&csr>;
+		coresight-ctis = <&cti0 &cti8>;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			tmc_etr_in_replicator: endpoint {
+				slave-mode;
+				remote-endpoint = <&replicator_out_tmc_etr>;
+			};
+		};
+	};
+
+	replicator: replicator@6026000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b909>;
+
+		reg = <0x6026000 0x1000>;
+		reg-names = "replicator-base";
+
+		coresight-name = "coresight-replicator";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				replicator_out_tmc_etr: endpoint {
+					remote-endpoint =
+						<&tmc_etr_in_replicator>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				replicator_in_tmc_etf: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tmc_etf_out_replicator>;
+				};
+			};
+		};
+	};
+
+	tmc_etf: tmc@6027000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b961>;
+
+		reg = <0x6027000 0x1000>;
+		reg-names = "tmc-base";
+
+		coresight-name = "coresight-tmc-etf";
+		coresight-csr = <&csr>;
+
+		arm,default-sink;
+		qcom,force-reg-dump;
+
+		coresight-ctis = <&cti0 &cti8>;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		 ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				tmc_etf_out_replicator:endpoint {
+					remote-endpoint =
+						<&replicator_in_tmc_etf>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				tmc_etf_in_funnel_in0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_in0_out_tmc_etf>;
+				};
+			};
+		};
+	};
+
+	funnel_in0: funnel@6021000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6021000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-in0";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		 ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				funnel_in0_out_tmc_etf: endpoint {
+					remote-endpoint =
+						<&tmc_etf_in_funnel_in0>;
+				};
+			};
+
+			port@1 {
+				reg = <7>;
+				funnel_in0_in_stm: endpoint {
+					slave-mode;
+					remote-endpoint = <&stm_out_funnel_in0>;
+				};
+			};
+
+			port@2 {
+				reg = <6>;
+				funnel_in0_in_tpda: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpda_out_funnel_in0>;
+				};
+			};
+
+			port@3 {
+				reg = <3>;
+				funnel_in0_in_funnel_center: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_center_out_funnel_in0>;
+				};
+			};
+
+			port@4 {
+				reg = <4>;
+				funnel_in0_in_funnel_right: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_right_out_funnel_in0>;
+				};
+			};
+
+			port@5 {
+				reg = <5>;
+				funnel_in0_in_funnel_mm: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_mm_out_funnel_in0>;
+				};
+			};
+		};
+	};
+
+	funnel_mm: funnel@6130000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6130000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-mm";
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				funnel_mm_out_funnel_in0: endpoint {
+					remote-endpoint =
+						<&funnel_in0_in_funnel_mm>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				funnel_mm_in_wcn_etm0: endpoint {
+					slave-mode;
+					remote-endpoint =
+					<&wcn_etm0_out_funnel_mm>;
+				};
+			};
+
+			port@2 {
+				reg = <4>;
+				funnel_mm_in_funnel_cam: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_cam_out_funnel_mm>;
+				};
+			};
+
+			port@3 {
+				reg = <5>;
+				funnel_mm_in_audio_etm0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&audio_etm0_out_funnel_mm>;
+				};
+			};
+		};
+	};
+
+	funnel_center: funnel@6100000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6100000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-center";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				funnel_center_out_funnel_in0: endpoint {
+					remote-endpoint =
+						<&funnel_in0_in_funnel_center>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				funnel_center_in_rpm_etm0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&rpm_etm0_out_funnel_center>;
+				};
+			};
+
+			port@2 {
+				reg = <2>;
+				funnel_center_in_dbgui: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&dbgui_out_funnel_center>;
+				};
+			};
+		};
+	};
+
+	funnel_right: funnel@6120000 {
+		compatible = "arm,primecell";
+
+		reg = <0x6120000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-right";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				funnel_right_out_funnel_in0: endpoint {
+					remote-endpoint =
+						<&funnel_in0_in_funnel_right>;
+				};
+			};
+
+			port@1 {
+				reg = <1>;
+				funnel_right_in_modem_etm0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&modem_etm0_out_funnel_right>;
+				};
+			};
+
+			port@2 {
+				reg = <2>;
+				funnel_right_in_funnel_apss: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_apss_out_funnel_right>;
+				};
+			};
+		};
+	};
+
+	funnel_cam: funnel@6132000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6132000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-cam";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		 port {
+			funnel_cam_out_funnel_mm: endpoint {
+				remote-endpoint = <&funnel_mm_in_funnel_cam>;
+			};
+		};
+	};
+
+	funnel_apss: funnel@61a1000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x61a1000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-apss";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				funnel_apss_out_funnel_right: endpoint {
+					remote-endpoint =
+						<&funnel_right_in_funnel_apss>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				funnel_apss0_in_etm0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&etm0_out_funnel_apss0>;
+				};
+			};
+
+			port@2 {
+				reg = <1>;
+				funnel_apss0_in_etm1: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&etm1_out_funnel_apss0>;
+				};
+			};
+
+			port@3 {
+				reg = <2>;
+				funnel_apss0_in_etm2: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&etm2_out_funnel_apss0>;
+				};
+			};
+
+			port@4 {
+				reg = <3>;
+				funnel_apss0_in_etm3: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&etm3_out_funnel_apss0>;
+				};
+			};
+		};
+	};
+
+	etm0: etm@61bc000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x000bb95d>;
+
+		reg = <0x61bc000 0x1000>;
+		cpu = <&CPU0>;
+		reg-names = "etm-base";
+
+		coresight-name = "coresight-etm0";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+		port {
+			etm0_out_funnel_apss0: endpoint {
+				remote-endpoint = <&funnel_apss0_in_etm0>;
+			};
+		};
+	};
+
+	etm1: etm@61bd000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x000bb95d>;
+
+		reg = <0x61bd000 0x1000>;
+		cpu = <&CPU1>;
+		coresight-name = "coresight-etm1";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			etm1_out_funnel_apss0: endpoint {
+				remote-endpoint = <&funnel_apss0_in_etm1>;
+			};
+		};
+	};
+
+	etm2: etm@61be000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x000bb95d>;
+
+		reg = <0x61be000 0x1000>;
+		cpu = <&CPU2>;
+		coresight-name = "coresight-etm2";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			etm2_out_funnel_apss0: endpoint {
+				remote-endpoint = <&funnel_apss0_in_etm2>;
+			};
+		};
+	};
+
+	etm3: etm@61bf000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x000bb95d>;
+
+		reg = <0x61bf000 0x1000>;
+		cpu = <&CPU3>;
+		coresight-name = "coresight-etm3";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			etm3_out_funnel_apss0: endpoint {
+				remote-endpoint = <&funnel_apss0_in_etm3>;
+			};
+		};
+	};
+
+	stm: stm@6002000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b962>;
+
+		reg = <0x6002000 0x1000>,
+		      <0x9280000 0x180000>;
+		reg-names = "stm-base", "stm-data-base";
+
+		coresight-name = "coresight-stm";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			stm_out_funnel_in0: endpoint {
+				remote-endpoint = <&funnel_in0_in_stm>;
+			};
+		};
+	};
+
+	cti0: cti@6010000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6010000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti0";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti1: cti@6011000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6011000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti1";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti2: cti@6012000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6012000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti2";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti3: cti@6013000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6013000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti3";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti4: cti@6014000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6014000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti4";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti5: cti@6015000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6015000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti5";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti6: cti@6016000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6016000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti6";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti7: cti@6017000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6017000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti7";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti8: cti@6018000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6018000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti8";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti9: cti@6019000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6019000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti9";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti10: cti@601a000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x601a000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti10";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti11: cti@601b000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x601b000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti11";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti12: cti@601c000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x601c000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti12";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti13: cti@601d000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x601d000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti13";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti14: cti@601e000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x601e000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti14";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti15: cti@601f000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x601f000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti15";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_cpu0: cti@61b8000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x61b8000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-cpu0";
+		cpu = <&CPU0>;
+		qcom,cti-save;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_cpu1: cti@61b9000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x61b9000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-cpu1";
+		cpu = <&CPU1>;
+		qcom,cti-save;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_cpu2: cti@61ba000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x61ba000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-cpu2";
+		cpu = <&CPU2>;
+		qcom,cti-save;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_cpu3: cti@61bb000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x61bb000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-cpu3";
+		cpu = <&CPU3>;
+		qcom,cti-save;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_modem_cpu0: cti@6124000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6124000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-modem-cpu0";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	/* Proto CTI */
+	cti_wcn_cpu0: cti@6139000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6139000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-wcn-cpu0";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	/* Venus CTI */
+	cti_video_cpu0: cti@6134000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x6134000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-video-cpu0";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	/* LPASS CTI */
+	cti_audio_cpu0: cti@613c000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x613c000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-audio-cpu0";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	/* RPM CTI */
+	cti_rpm_cpu0: cti@610c000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+
+		reg = <0x610c000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-rpm-cpu0";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	/* Proto ETM */
+	wcn_etm0 {
+		compatible = "qcom,coresight-remote-etm";
+		coresight-name = "coresight-wcn-etm0";
+		qcom,inst-id = <3>;
+
+		port {
+			wcn_etm0_out_funnel_mm: endpoint {
+				remote-endpoint = <&funnel_mm_in_wcn_etm0>;
+			};
+		};
+	};
+
+	rpm_etm0 {
+		compatible = "qcom,coresight-remote-etm";
+		coresight-name = "coresight-rpm-etm0";
+		qcom,inst-id = <4>;
+
+		port {
+			rpm_etm0_out_funnel_center: endpoint {
+				remote-endpoint = <&funnel_center_in_rpm_etm0>;
+			};
+		};
+	};
+
+	/* LPASS ETM */
+	audio_etm0 {
+		compatible = "qcom,coresight-remote-etm";
+		coresight-name = "coresight-audio-etm0";
+		qcom,inst-id = <5>;
+
+		port {
+			audio_etm0_out_funnel_mm: endpoint {
+				remote-endpoint = <&funnel_mm_in_audio_etm0>;
+			};
+		};
+	};
+
+	modem_etm0 {
+		compatible = "qcom,coresight-remote-etm";
+		coresight-name = "coresight-modem-etm0";
+		qcom,inst-id = <11>;
+
+		port {
+			modem_etm0_out_funnel_right: endpoint {
+				remote-endpoint = <&funnel_right_in_modem_etm0>;
+			};
+		};
+	};
+
+	csr: csr@6001000 {
+		compatible = "qcom,coresight-csr";
+		reg = <0x6001000 0x1000>;
+		reg-names = "csr-base";
+
+		coresight-name = "coresight-csr";
+
+		qcom,usb-bam-support;
+		qcom,hwctrl-set-support;
+		qcom,set-byte-cntr-support;
+
+		qcom,blk-size = <1>;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+
+	dbgui: dbgui@6108000 {
+		compatible = "qcom,coresight-dbgui";
+		reg = <0x6108000 0x1000>;
+		reg-names = "dbgui-base";
+
+		coresight-name = "coresight-dbgui";
+
+		qcom,dbgui-addr-offset = <0x30>;
+		qcom,dbgui-data-offset = <0x130>;
+		qcom,dbgui-size = <32>;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			dbgui_out_funnel_center: endpoint {
+				remote-endpoint = <&funnel_center_in_dbgui>;
+			};
+		};
+	};
+
+	tpda: tpda@6003000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b969>;
+
+		reg = <0x6003000 0x1000>;
+		reg-names = "tpda-base";
+
+		coresight-name = "coresight-tpda";
+
+		qcom,tpda-atid = <64>;
+		qcom,cmb-elem-size = <0 32>;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				tpda_out_funnel_in0: endpoint {
+					remote-endpoint = <&funnel_in0_in_tpda>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				tpda_in_tpdm_dcc: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_dcc_out_tpda>;
+				};
+			};
+		};
+	};
+
+	tpdm_dcc: tpdm@6110000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
+
+		reg = <0x6110000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-dcc";
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+
+		port {
+			tpdm_dcc_out_tpda: endpoint {
+				remote-endpoint = <&tpda_in_tpdm_dcc>;
+			};
+		};
+	};
+
+	hwevent: hwevent@6101000 {
+		compatible = "qcom,coresight-hwevent";
+		reg = <0x6101000 0x148>,
+		      <0x6101fb0 0x4>,
+		      <0x6121000 0x148>,
+		      <0x6121fb0 0x4>,
+		      <0x6131000 0x148>,
+		      <0x6131fb0 0x4>,
+		      <0x78c5010 0x4>,
+		      <0x7885010 0x4>;
+		reg-names = "center-wrapper-mux", "center-wrapper-lockaccess",
+			    "right-wrapper-mux", "right-wrapper-lockaccess",
+			    "mm-wrapper-mux", "mm-wrapper-lockaccess",
+			    "usbbam-mux", "blsp-mux";
+
+		coresight-name = "coresight-hwevent";
+		coresight-csr = <&csr>;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "apb_pclk";
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-cpu.dtsi b/arch/arm64/boot/dts/qcom/msm8917-cpu.dtsi
index 792d5d1..5a242db 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-cpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917-cpu.dtsi
@@ -117,3 +117,46 @@
 
 	};
 };
+
+&soc {
+	cpuss_dump {
+		compatible = "qcom,cpuss-dump";
+		qcom,l2_dump1 {
+			/* L2 cache dump for A53 cluster */
+			qcom,dump-node = <&L2_1>;
+			qcom,dump-id = <0xC1>;
+		};
+		qcom,l1_i_cache100 {
+			qcom,dump-node = <&L1_I_100>;
+			qcom,dump-id = <0x60>;
+		};
+		qcom,l1_i_cache101 {
+			qcom,dump-node = <&L1_I_101>;
+			qcom,dump-id = <0x61>;
+		};
+		qcom,l1_i_cache102 {
+			qcom,dump-node = <&L1_I_102>;
+			qcom,dump-id = <0x62>;
+		};
+		qcom,l1_i_cache103 {
+			qcom,dump-node = <&L1_I_103>;
+			qcom,dump-id = <0x63>;
+		};
+		qcom,l1_d_cache100 {
+			qcom,dump-node = <&L1_D_100>;
+			qcom,dump-id = <0x80>;
+		};
+		qcom,l1_d_cache101 {
+			qcom,dump-node = <&L1_D_101>;
+			qcom,dump-id = <0x81>;
+		};
+		qcom,l1_d_cache102 {
+			qcom,dump-node = <&L1_D_102>;
+			qcom,dump-id = <0x82>;
+		};
+		qcom,l1_d_cache103 {
+			qcom,dump-node = <&L1_D_103>;
+			qcom,dump-id = <0x83>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi
index 800ea1c..164b781 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi
@@ -68,6 +68,20 @@
 	status = "ok";
 };
 
+&soc {
+	hbtp {
+		compatible = "qcom,hbtp-input";
+		vcc_ana-supply = <&pm8937_l10>;
+		vcc_dig-supply = <&pm8937_l5>;
+		qcom,afe-load = <50000>;
+		qcom,afe-vtg-min = <2850000>;
+		qcom,afe-vtg-max = <2850000>;
+		qcom,dig-load = <15000>;
+		qcom,dig-vtg-min = <1800000>;
+		qcom,dig-vtg-max = <1800000>;
+	};
+};
+
 #include "msm8937-mdss-panels.dtsi"
 
 &mdss_mdp {
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pm.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pm.dtsi
index 6200b4e..575d1b5 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-pm.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917-pm.dtsi
@@ -125,7 +125,211 @@
 		};
 	};
 
+	qcom,mpm@601d0 {
+		compatible = "qcom,mpm-v2";
+		reg = <0x601d0 0x1000>, /* MSM_RPM_MPM_BASE 4K */
+		      <0xb011008 0x4>;
+		reg-names = "vmpm", "ipc";
+		interrupts = <0 171 1>;
+		clocks = <&clock_gcc clk_xo_lpm_clk>;
+		clock-names = "xo";
+		qcom,ipc-bit-offset = <1>;
+		qcom,gic-parent = <&intc>;
+		qcom,gic-map = <2 216>, /* tsens_upper_lower_int */
+			<49 172>, /* usb1_hs_async_wakeup_irq */
+			<58 166>, /* usb_hs_irq */
+			<53 104>, /* mdss_irq */
+			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+			<0xff 18>,  /* APC_qgicQTmrSecPhysIrptReq */
+			<0xff 19>,  /* APC_qgicQTmrNonSecPhysIrptReq */
+			<0xff 20>,  /* qgicQTmrVirtIrptReq */
+			<0xff 35>,  /* WDT_barkInt */
+			<0xff 39>,  /* arch_mem_timer */
+			<0xff 40>,  /* qtmr_phy_irq[0] */
+			<0xff 47>,  /* rbif_irq[0] */
+			<0xff 56>,  /* q6_wdog_expired_irq */
+			<0xff 57>,  /* mss_to_apps_irq(0) */
+			<0xff 58>,  /* mss_to_apps_irq(1) */
+			<0xff 59>,  /* mss_to_apps_irq(2) */
+			<0xff 60>,  /* mss_to_apps_irq(3) */
+			<0xff 61>,  /* mss_a2_bam_irq */
+			<0xff 65>,  /* o_gc_sys_irq[0] */
+			<0xff 69>,  /* vbif_irpt */
+			<0xff 73>,  /* smmu_intr_bus[1] */
+			<0xff 74>,  /* smmu_bus_intr[2] */
+			<0xff 75>,  /* smmu_bus_intr[3] */
+			<0xff 76>,  /* venus_irq */
+			<0xff 78>,  /* smmu_bus_intr[5] */
+			<0xff 79>,  /* smmu_bus_intr[6] */
+			<0xff 85>,  /* smmu_bus_intr[31] */
+			<0xff 86>,  /* smmu_bus_intr[32] */
+			<0xff 90>,  /* smmu_bus_intr[33] */
+			<0xff 92>,  /* smmu_bus_intr[34] */
+			<0xff 93>,  /* smmu_bus_intr[35] */
+			<0xff 97>,  /* smmu_bus_intr[10] */
+			<0xff 102>, /* smmu_bus_intr[14] */
+			<0xff 108>, /* smmu_bus_intr[36] */
+			<0xff 109>, /* smmu_bus_intr[37] */
+			<0xff 112>, /* smmu_bus_intr[38] */
+			<0xff 114>, /* qdsd_intr_out */
+			<0xff 126>, /* smmu_bus_intr[39] */
+			<0xff 128>, /* blsp1_peripheral_irq[3] */
+			<0xff 129>, /* blsp1_peripheral_irq[4] */
+			<0xff 131>, /* qup_irq */
+			<0xff 136>, /* smmu_bus_intr[43] */
+			<0xff 137>, /* smmu_intr_bus[44] */
+			<0xff 138>, /* smmu_intr_bus[45] */
+			<0xff 140>, /* uart_dm_intr */
+			<0xff 141>, /* smmu_bus_intr[46] */
+			<0xff 142>, /* smmu_bus_intr[47] */
+			<0xff 143>, /* smmu_bus_intr[48] */
+			<0xff 144>, /* smmu_bus_intr[49] */
+			<0xff 145>, /* smmu_bus_intr[50] */
+			<0xff 146>, /* smmu_bus_intr[51] */
+			<0xff 147>, /* smmu_bus_intr[52] */
+			<0xff 148>, /* smmu_bus_intr[53] */
+			<0xff 149>, /* smmu_bus_intr[54] */
+			<0xff 150>, /* smmu_bus_intr[55] */
+			<0xff 151>, /* smmu_bus_intr[56] */
+			<0xff 152>, /* smmu_bus_intr[57] */
+			<0xff 153>, /* smmu_bus_intr[58] */
+			<0xff 155>, /* sdc1_irq(0) */
+			<0xff 157>, /* sdc2_irq(0) */
+			<0xff 167>, /* bam_irq(0) */
+			<0xff 170>, /* sdc1_pwr_cmd_irq */
+			<0xff 173>, /* o_wcss_apss_smd_hi */
+			<0xff 174>, /* o_wcss_apss_smd_med */
+			<0xff 175>, /* o_wcss_apss_smd_low */
+			<0xff 176>, /* o_wcss_apss_smsm_irq */
+			<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
+			<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
+			<0xff 179>, /* o_wcss_apss_asic_intr */
+			<0xff 181>, /* o_wcss_apss_wdog_bite_and_reset_rdy */
+			<0xff 188>, /* lpass_irq_out_apcs(0) */
+			<0xff 189>, /* lpass_irq_out_apcs(1) */
+			<0xff 190>, /* lpass_irq_out_apcs(2) */
+			<0xff 191>, /* lpass_irq_out_apcs(3) */
+			<0xff 192>, /* lpass_irq_out_apcs(4) */
+			<0xff 193>, /* lpass_irq_out_apcs(5) */
+			<0xff 194>, /* lpass_irq_out_apcs(6) */
+			<0xff 195>, /* lpass_irq_out_apcs(7) */
+			<0xff 196>, /* lpass_irq_out_apcs(8) */
+			<0xff 197>, /* lpass_irq_out_apcs(9) */
+			<0xff 198>, /* coresight-tmc-etr interrupt */
+			<0xff 200>, /* rpm_ipc(4) */
+			<0xff 201>, /* rpm_ipc(5) */
+			<0xff 202>, /* rpm_ipc(6) */
+			<0xff 203>, /* rpm_ipc(7) */
+			<0xff 204>, /* rpm_ipc(24) */
+			<0xff 205>, /* rpm_ipc(25) */
+			<0xff 206>, /* rpm_ipc(26) */
+			<0xff 207>, /* rpm_ipc(27) */
+			<0xff 215>, /* o_bimc_intr[0] */
+			<0xff 224>, /* SPDM interrupt */
+			<0xff 239>, /* crypto_bam_irq[1]*/
+			<0xff 240>, /* summary_irq_kpss */
+			<0xff 253>, /* sdcc_pwr_cmd_irq */
+			<0xff 260>, /* ipa_irq[0] */
+			<0xff 261>, /* ipa_irq[2] */
+			<0xff 262>, /* ipa_bam_irq[0] */
+			<0xff 263>, /* ipa_bam_irq[2] */
+			<0xff 269>, /* rpm_wdog_expired_irq */
+			<0xff 270>, /* blsp1_bam_irq[0] */
+			<0xff 272>, /* smmu_intr_bus[17] */
+			<0xff 273>, /* smmu_bus_intr[18] */
+			<0xff 274>, /* smmu_bus_intr[19] */
+			<0xff 275>, /* rpm_ipc(30) */
+			<0xff 276>, /* rpm_ipc(31) */
+			<0xff 277>, /* smmu_intr_bus[20] */
+			<0xff 285>, /* smmu_bus_intr[28] */
+			<0xff 286>, /* smmu_bus_intr[29] */
+			<0xff 287>, /* smmu_bus_intr[30] */
+			<0xff 321>, /* q6ss_irq_out(4) */
+			<0xff 322>, /* q6ss_irq_out(5) */
+			<0xff 323>, /* q6ss_irq_out(6) */
+			<0xff 325>, /* q6ss_wdog_exp_irq */
+			<0xff 344>; /* sdcc1ice */
+
+		qcom,gpio-parent = <&tlmm>;
+		qcom,gpio-map = <3  38 >,
+			<4  1 >,
+			<5  5 >,
+			<6  9 >,
+			<8  37>,
+			<9  36>,
+			<10  13>,
+			<11  35>,
+			<12  17>,
+			<13  21>,
+			<14  54>,
+			<15  34>,
+			<16  31>,
+			<17  58>,
+			<18  28>,
+			<19  42>,
+			<20  25>,
+			<21  12>,
+			<22  43>,
+			<23  44>,
+			<24  45>,
+			<25  46>,
+			<26  48>,
+			<27  65>,
+			<28  93>,
+			<29  97>,
+			<30  63>,
+			<31  70>,
+			<32  71>,
+			<33  72>,
+			<34  81>,
+			<35  126>,
+			<36  90>,
+			<37  128>,
+			<38  91>,
+			<39  41>,
+			<40  127>,
+			<41  86>,
+			<50  67>,
+			<51  73>,
+			<52  74>,
+			<53  62>,
+			<54  124>,
+			<55  61>,
+			<56  130>,
+			<57  59>,
+			<59  50>;
+	};
+
 	qcom,cpu-sleep-status {
 		compatible = "qcom,cpu-sleep-status";
 	};
+
+	qcom,rpm-log@29dc00 {
+		compatible = "qcom,rpm-log";
+		reg = <0x29dc00 0x4000>;
+		qcom,rpm-addr-phys = <0x200000>;
+		qcom,offset-version = <4>;
+		qcom,offset-page-buffer-addr = <36>;
+		qcom,offset-log-len = <40>;
+		qcom,offset-log-len-mask = <44>;
+		qcom,offset-page-indices = <56>;
+	};
+
+	qcom,rpm-stats@29dba0 {
+		compatible = "qcom,rpm-stats";
+		reg = <0x200000 0x1000>,
+		      <0x290014 0x4>,
+		      <0x29001c 0x4>;
+		reg-names = "phys_addr_base", "offset_addr",
+						"heap_phys_addrbase";
+		qcom,sleep-stats-version = <2>;
+	};
+
+	qcom,rpm-master-stats@60150 {
+		compatible = "qcom,rpm-master-stats";
+		reg = <0x60150 0x5000>;
+		qcom,masters = "APSS", "MPSS", "PRONTO", "TZ", "LPASS";
+		qcom,master-stats-version = <2>;
+		qcom,master-offset = <4096>;
+	};
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8937-cdp.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8937-cdp.dts
new file mode 100644
index 0000000..9d8a2eb
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8937-cdp.dts
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8917.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8937.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8917-PMI8937 CDP";
+	compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp";
+	qcom,board-id= <1 0>;
+	qcom,pmic-id = <0x10019 0x020037 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8937-rcm.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8937-rcm.dts
new file mode 100644
index 0000000..c7fe115
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8937-rcm.dts
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8917.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8937.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8917-PMI8937 RCM";
+	compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp";
+	qcom,board-id= <21 0>;
+	qcom,pmic-id = <0x10019 0x020037 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8940-cdp.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8940-cdp.dts
new file mode 100644
index 0000000..9785a4f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8940-cdp.dts
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8917.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8940.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8917-PMI8940 CDP";
+	compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp";
+	qcom,board-id = <1 0>;
+	qcom,pmic-id = <0x10019 0x020040 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8940-rcm.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8940-rcm.dts
new file mode 100644
index 0000000..2cab716
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8940-rcm.dts
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8917.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8940.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8917-PMI8940 RCM";
+	compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp";
+	qcom,board-id = <21 0>;
+	qcom,pmic-id = <0x10019 0x020040 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dts
new file mode 100644
index 0000000..ea6b24a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8917.dtsi"
+#include "msm8917-pmi8950-cdp-mirror-lake-touch.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8917-PMI8950 CDP ML Touch";
+	compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp";
+	qcom,board-id = <1 4>;
+	qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dtsi
new file mode 100644
index 0000000..4701101
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dtsi
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2017-2018, 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 "pmi8950.dtsi"
+#include "msm8917-cdp-mirror-lake-touch.dtsi"
+#include "msm8917-audio-cdp.dtsi"
+
+&soc {
+	led_flash0: qcom,camera-flash {
+		cell-index = <0>;
+		compatible = "qcom,camera-flash";
+		qcom,flash-type = <1>;
+		qcom,flash-source = <&pmi8950_flash0 &pmi8950_flash1>;
+		qcom,torch-source = <&pmi8950_torch0 &pmi8950_torch1>;
+		qcom,switch-source = <&pmi8950_switch>;
+	};
+
+	bluetooth: bt_qca6174 {
+		compatible = "qca,qca6174";
+		qca,bt-reset-gpio = <&tlmm 129 0>; /* BT_EN */
+	};
+};
+
+&qpnp_smbcharger {
+	/delete-property/ dpdm-supply;
+};
+
+&pm8937_gpios {
+	gpio@c400 {
+		qcom,mode = <0>;
+		qcom,output-type = <0>;
+		qcom,pull = <0>;
+		qcom,vin-sel = <2>;
+		qcom,out-strength = <3>;
+		qcom,src-sel = <0>;
+		qcom,master-en = <1>;
+		status = "okay";
+	};
+};
+
+&i2c_5 { /* BLSP2 QUP1 */
+	nq@28 {
+		compatible = "qcom,nq-nci";
+		reg = <0x28>;
+		qcom,nq-irq = <&tlmm 17 0x00>;
+		qcom,nq-ven = <&tlmm 16 0x00>;
+		qcom,nq-firm = <&tlmm 130 0x00>;
+		qcom,nq-clkreq = <&pm8937_gpios 5 0x00>;
+		interrupt-parent = <&tlmm>;
+		qcom,clk-src = "BBCLK2";
+		interrupts = <17 0>;
+		interrupt-names = "nfc_irq";
+		pinctrl-names = "nfc_active", "nfc_suspend";
+		pinctrl-0 = <&nfc_int_active &nfc_disable_active>;
+		pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>;
+		clocks = <&clock_gcc clk_bb_clk2_pin>;
+		clock-names = "ref_clk";
+	};
+};
+
+&mdss_dsi0 {
+	lab-supply = <&lab_regulator>;
+	ibb-supply = <&ibb_regulator>;
+};
+
+&labibb {
+	status = "ok";
+	qpnp,qpnp-labibb-mode = "lcd";
+};
+
+&ibb_regulator {
+	qcom,qpnp-ibb-discharge-resistor = <32>;
+};
+
+&dsi_panel_pwr_supply {
+	qcom,panel-supply-entry@2 {
+		reg = <2>;
+		qcom,supply-name = "lab";
+		qcom,supply-min-voltage = <4600000>;
+		qcom,supply-max-voltage = <6000000>;
+		qcom,supply-enable-load = <100000>;
+		qcom,supply-disable-load = <100>;
+	};
+
+	qcom,panel-supply-entry@3 {
+		reg = <3>;
+		qcom,supply-name = "ibb";
+		qcom,supply-min-voltage = <4600000>;
+		qcom,supply-max-voltage = <6000000>;
+		qcom,supply-enable-load = <100000>;
+		qcom,supply-disable-load = <100>;
+		qcom,supply-post-on-sleep = <20>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp.dts
new file mode 100644
index 0000000..a32e2b3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp.dts
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8917.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8950.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8917-PMI8950 CDP";
+	compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp";
+	qcom,board-id= <1 0>;
+	qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-ext-codec-cdp.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-ext-codec-cdp.dts
new file mode 100644
index 0000000..91c4f3a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-ext-codec-cdp.dts
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8917.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8950.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8917 External Audio Codec CDP";
+	compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp";
+	qcom,board-id= <1 1>;
+	qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+};
+
+&pm8937_gpios {
+	gpio@c000 {
+		status = "ok";
+		qcom,mode = <1>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <0>;
+		qcom,src-sel = <2>;
+		qcom,master-en = <1>;
+		qcom,out-strength = <2>;
+	};
+
+	gpio@c600 {
+		status = "ok";
+		qcom,mode = <1>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <0>;
+		qcom,src-sel = <0>;
+		qcom,master-en = <1>;
+		qcom,out-strength = <2>;
+	};
+};
+
+&slim_msm {
+	status = "okay";
+};
+
+&wcd9xxx_intc {
+	status = "okay";
+};
+
+&clock_audio {
+	status = "okay";
+};
+
+&wcd9335 {
+	status = "okay";
+};
+
+&wcd_rst_gpio {
+	status = "okay";
+};
+
+&ext_codec {
+	status = "okay";
+};
+
+&int_codec {
+	status = "disabled";
+};
+
+&wsa881x_i2c_f {
+	status = "disabled";
+};
+
+&wsa881x_i2c_45 {
+	status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dts
index 3fe60a3..5b458b2 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dts
@@ -14,7 +14,8 @@
 /dts-v1/;
 
 #include "msm8917.dtsi"
-#include "msm8917-pmi8950-mtp.dtsi"
+#include "msm8917-mtp.dtsi"
+#include "msm8917-pmi8950.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8917-PMI8950 MTP";
@@ -22,3 +23,23 @@
 	qcom,board-id= <8 0>;
 	qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
 };
+
+&blsp1_uart1 {
+	status = "ok";
+};
+
+&vendor {
+	mtp_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "batterydata-itech-3000mah.dtsi"
+		#include "batterydata-ascent-3450mAh.dtsi"
+	};
+};
+
+&qpnp_fg {
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&qpnp_smbcharger {
+	qcom,battery-data = <&mtp_batterydata>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-rcm.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-rcm.dts
new file mode 100644
index 0000000..a91bea1
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-rcm.dts
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8917.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8950.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8917-PMI8950 RCM";
+	compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp";
+	qcom,board-id= <21 0>;
+	qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pmi8950.dtsi
new file mode 100644
index 0000000..9543133
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950.dtsi
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018 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 "pmi8950.dtsi"
+
+&qpnp_smbcharger {
+	qcom,chg-led-sw-controls;
+	qcom,chg-led-support;
+	/delete-property/ dpdm-supply;
+};
+
+&usb_otg {
+	extcon = <&qpnp_smbcharger>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi b/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi
index f897b59..fae258d0 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi
@@ -78,6 +78,12 @@
 };
 
 &soc {
+	int_codec: sound {
+		status = "okay";
+		qcom,msm-mbhc-hphl-swh = <1>;
+		qcom,msm-hs-micbias-type = "internal";
+	};
+
 	gpio_keys {
 		compatible = "gpio-keys";
 		input-name = "gpio-keys";
diff --git a/arch/arm64/boot/dts/qcom/msm8917.dtsi b/arch/arm64/boot/dts/qcom/msm8917.dtsi
index dbdd9d9..a285110 100644
--- a/arch/arm64/boot/dts/qcom/msm8917.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917.dtsi
@@ -161,6 +161,7 @@
 #include "msm8917-pm.dtsi"
 #include "msm8917-ion.dtsi"
 #include "msm8917-smp2p.dtsi"
+#include "msm8917-coresight.dtsi"
 #include "msm8917-bus.dtsi"
 #include "msm8917-mdss.dtsi"
 #include "msm8917-mdss-pll.dtsi"
@@ -183,6 +184,18 @@
 			<0x0b002000 0x1000>;
 	};
 
+	dcc: dcc@b3000 {
+		compatible = "qcom,dcc";
+		reg = <0xb3000 0x1000>,
+			<0xb4000 0x2000>;
+		reg-names = "dcc-base", "dcc-ram-base";
+
+		clocks = <&clock_gcc clk_gcc_dcc_clk>;
+		clock-names = "apb_pclk";
+
+		qcom,save-reg;
+	};
+
 	wakegic: wake-gic {
 		compatible = "qcom,mpm-gic", "qcom,mpm-gic-msm8937";
 		interrupts = <GIC_SPI 171 IRQ_TYPE_EDGE_RISING>;
@@ -482,6 +495,23 @@
 		#clock-cells = <1>;
 	};
 
+	msm_cpufreq: qcom,msm-cpufreq {
+		compatible = "qcom,msm-cpufreq";
+		clock-names = "cpu0_clk", "cpu1_clk", "cpu2_clk",
+				"cpu3_clk";
+		clocks = <&clock_cpu clk_a53_bc_clk>,
+			 <&clock_cpu clk_a53_bc_clk>,
+			 <&clock_cpu clk_a53_bc_clk>,
+			 <&clock_cpu clk_a53_bc_clk>;
+
+		qcom,cpufreq-table =
+			 <  960000 >,
+			 < 1094400 >,
+			 < 1248000 >,
+			 < 1401000 >,
+			 < 1497600 >;
+	};
+
 	i2c_2: i2c@78b6000 { /* BLSP1 QUP2 */
 		compatible = "qcom,i2c-msm-v2";
 		#address-cells = <1>;
@@ -713,6 +743,24 @@
 		qcom,target-dev = <&cpubw>;
 	};
 
+	devfreq-cpufreq {
+		cpubw-cpufreq {
+		target-dev = <&cpubw>;
+		cpu-to-dev-map =
+			<  998400  4248 >,
+			< 1094400  4541 >,
+			< 1497600  5645 >;
+		};
+
+		mincpubw-cpufreq {
+			target-dev = <&mincpubw>;
+			cpu-to-dev-map =
+				<  998400 2270 >,
+				< 1094400 4248 >,
+				< 1497600 4248 >;
+		};
+	};
+
 	qcom,wdt@b017000 {
 		compatible = "qcom,msm-watchdog";
 		reg = <0xb017000 0x1000>;
@@ -724,6 +772,32 @@
 		qcom,wakeup-enable;
 	};
 
+	qcom,memshare {
+		compatible = "qcom,memshare";
+
+		qcom,client_1 {
+			compatible = "qcom,memshare-peripheral";
+			qcom,peripheral-size = <0x200000>;
+			qcom,client-id = <0>;
+			qcom,allocate-boot-time;
+			label = "modem";
+		};
+
+		qcom,client_2 {
+			compatible = "qcom,memshare-peripheral";
+			qcom,peripheral-size = <0x300000>;
+			qcom,client-id = <2>;
+			label = "modem";
+		};
+
+		mem_client_3_size: qcom,client_3 {
+			compatible = "qcom,memshare-peripheral";
+			qcom,peripheral-size = <0x0>;
+			qcom,client-id = <1>;
+			label = "modem";
+		};
+	};
+
 	spmi_bus: qcom,spmi@200f000 {
 		compatible = "qcom,spmi-pmic-arb";
 		reg = <0x200f000 0x1000>,
@@ -782,6 +856,64 @@
 
 	};
 
+	 jtag_fuse: jtagfuse@a601c {
+		compatible = "qcom,jtag-fuse-v2";
+		reg = <0xa601c 0x8>;
+		reg-names = "fuse-base";
+	};
+
+	jtag_mm0: jtagmm@61bc000 {
+		compatible = "qcom,jtagv8-mm";
+		reg = <0x61bc000 0x1000>,
+			<0x61b0000 0x1000>;
+		reg-names = "etm-base", "debug-base";
+
+		qcom,coresight-jtagmm-cpu = <&CPU0>;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	jtag_mm1: jtagmm@61bd000 {
+		compatible = "qcom,jtagv8-mm";
+		reg = <0x61bd000 0x1000>,
+			<0x61b2000 0x1000>;
+		reg-names = "etm-base", "debug-base";
+
+		qcom,coresight-jtagmm-cpu = <&CPU1>;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			<&clock_gcc clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	jtag_mm2: jtagmm@61be000 {
+		compatible = "qcom,jtagv8-mm";
+		reg = <0x61be000 0x1000>,
+			<0x61b4000 0x1000>;
+		reg-names = "etm-base", "debug-base";
+
+		qcom,coresight-jtagmm-cpu = <&CPU2>;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			<&clock_gcc clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	jtag_mm3: jtagmm@61bf000 {
+		compatible = "qcom,jtagv8-mm";
+		reg = <0x61bf000 0x1000>,
+			<0x61b6000 0x1000>;
+		reg-names = "etm-base", "debug-base";
+
+		qcom,coresight-jtagmm-cpu = <&CPU3>;
+
+		clocks = <&clock_gcc clk_qdss_clk>,
+			 <&clock_gcc clk_qdss_a_clk>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
 	qcom,ipc-spinlock@1905000 {
 		compatible = "qcom,ipc-spinlock-sfpb";
 		reg = <0x1905000 0x8000>;
@@ -1141,6 +1273,10 @@
 		qcom,ce-opp-freq = <100000000>;
 	};
 
+	qcom,iris-fm {
+		compatible = "qcom,iris_fm";
+	};
+
 	qcom,mss@4080000 {
 		compatible = "qcom,pil-q6v55-mss";
 		reg = <0x04080000 0x100>,
@@ -1423,6 +1559,86 @@
 		status = "disabled";
 	};
 
+	qcom,wcnss-wlan@a000000 {
+		compatible = "qcom,wcnss_wlan";
+		reg = <0xa000000 0x280000>,
+		      <0xb011008 0x4>,
+		      <0xa21b000 0x3000>,
+		      <0x3204000 0x100>,
+		      <0x3200800 0x200>,
+		      <0xa100400 0x200>,
+		      <0xa205050 0x200>,
+		      <0xa219000 0x20>,
+		      <0xa080488 0x8>,
+		      <0xa080fb0 0x8>,
+		      <0xa08040c 0x8>,
+		      <0xa0120a8 0x8>,
+		      <0xa012448 0x8>,
+		      <0xa080c00 0x1>;
+
+		reg-names = "wcnss_mmio", "wcnss_fiq",
+			    "pronto_phy_base", "riva_phy_base",
+			    "riva_ccu_base", "pronto_a2xb_base",
+			    "pronto_ccpu_base", "pronto_saw2_base",
+			    "wlan_tx_phy_aborts","wlan_brdg_err_source",
+			    "wlan_tx_status", "alarms_txctl",
+			    "alarms_tactl", "pronto_mcu_base";
+
+		interrupts = <0 145 0 0 146 0>;
+		interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+
+		qcom,pronto-vddmx-supply = <&pm8937_l3_level_ao>;
+		qcom,pronto-vddcx-supply = <&pm8937_s2_level>;
+		qcom,pronto-vddpx-supply = <&pm8937_l5>;
+		qcom,iris-vddxo-supply   = <&pm8937_l7>;
+		qcom,iris-vddrfa-supply  = <&pm8937_l19>;
+		qcom,iris-vddpa-supply   = <&pm8937_l9>;
+		qcom,iris-vdddig-supply  = <&pm8937_l5>;
+
+		qcom,iris-vddxo-voltage-level = <1800000 0 1800000>;
+		qcom,iris-vddrfa-voltage-level = <1300000 0 1300000>;
+		qcom,iris-vddpa-voltage-level = <3300000 0 3300000>;
+		qcom,iris-vdddig-voltage-level = <1800000 0 1800000>;
+
+		qcom,vddmx-voltage-level = <RPM_SMD_REGULATOR_LEVEL_TURBO
+				       RPM_SMD_REGULATOR_LEVEL_NONE
+				       RPM_SMD_REGULATOR_LEVEL_TURBO>;
+		qcom,vddcx-voltage-level = <RPM_SMD_REGULATOR_LEVEL_NOM
+				       RPM_SMD_REGULATOR_LEVEL_NONE
+				       RPM_SMD_REGULATOR_LEVEL_TURBO>;
+		qcom,vddpx-voltage-level = <1800000 0 1800000>;
+
+		qcom,iris-vddxo-current = <10000>;
+		qcom,iris-vddrfa-current = <100000>;
+		qcom,iris-vddpa-current = <515000>;
+		qcom,iris-vdddig-current = <10000>;
+
+		qcom,pronto-vddmx-current = <0>;
+		qcom,pronto-vddcx-current = <0>;
+		qcom,pronto-vddpx-current = <0>;
+
+		pinctrl-names = "wcnss_default", "wcnss_sleep",
+				"wcnss_gpio_default";
+		pinctrl-0 = <&wcnss_default>;
+		pinctrl-1 = <&wcnss_sleep>;
+		pinctrl-2 = <&wcnss_gpio_default>;
+
+		gpios = <&tlmm 76 0>, <&tlmm 77 0>, <&tlmm 78 0>,
+			<&tlmm 79 0>, <&tlmm 80 0>;
+
+		clocks = <&clock_gcc clk_xo_wlan_clk>,
+			 <&clock_gcc clk_rf_clk2>,
+			 <&clock_debug clk_gcc_debug_mux_8937>,
+			 <&clock_gcc clk_wcnss_m_clk>;
+
+		clock-names = "xo", "rf_clk", "measure", "wcnss_debug";
+
+		qcom,has-autodetect-xo;
+		qcom,is-pronto-v3;
+		qcom,has-pronto-hw;
+		qcom,has-vsys-adc-channel;
+		qcom,wcnss-adc_tm = <&pm8937_adc_tm>;
+	};
 };
 
 #include "pm8937-rpm-regulator.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/msm8937-audio.dtsi b/arch/arm64/boot/dts/qcom/msm8937-audio.dtsi
index 2e4d38e..ffc266f 100644
--- a/arch/arm64/boot/dts/qcom/msm8937-audio.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937-audio.dtsi
@@ -240,16 +240,23 @@
 			"SpkrRight IN", "SPK2 OUT";
 
 		qcom,tasha-mclk-clk-freq = <9600000>;
+		qcom,cdc-us-euro-gpios = <&tlmm 63 0>;
+		qcom,msm-mbhc-hphl-swh = <0>;
+		qcom,msm-mbhc-gnd-swh = <0>;
+		qcom,cdc-us-eu-gpios = <&cdc_us_euro_sw>;
+		qcom,quin-mi2s-gpios = <&cdc_quin_mi2s_gpios>;
 
 		asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
 				<&loopback>, <&compress>, <&hostless>,
-				<&afe>, <&lsm>, <&routing>;
+				<&afe>, <&lsm>, <&routing>, <&cpe>,
+				<&pcm_noirq>;
 		asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
 				"msm-pcm-dsp.2", "msm-voip-dsp",
 				"msm-pcm-voice", "msm-pcm-loopback",
 				"msm-compress-dsp", "msm-pcm-hostless",
 				"msm-pcm-afe", "msm-lsm-client",
-				"msm-pcm-routing";
+				"msm-pcm-routing", "msm-cpe-lsm",
+				"msm-pcm-dsp-noirq";
 
 		asoc-cpu = <&dai_pri_auxpcm>,
 				<&dai_mi2s2>, <&dai_mi2s3>, <&dai_mi2s5>,
@@ -281,9 +288,6 @@
 
 		asoc-codec = <&stub_codec>, <&hdmi_dba>;
 		asoc-codec-names = "msm-stub-codec.1", "msm-hdmi-dba-codec-rx";
-		qcom,cdc-us-euro-gpios = <&tlmm 63 0>;
-		qcom,msm-mbhc-hphl-swh = <0>;
-		qcom,msm-mbhc-gnd-swh = <0>;
 
 		qcom,wsa-max-devs = <2>;
 		qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>,
@@ -292,11 +296,19 @@
 				"SpkrLeft", "SpkrRight";
 	};
 
+	cpe: qcom,msm-cpe-lsm {
+		compatible = "qcom,msm-cpe-lsm";
+	};
+
 	wcd9xxx_intc: wcd9xxx-irq {
 		status = "disabled";
+		compatible = "qcom,wcd9xxx-irq";
+		interrupt-controller;
+		#interrupt-cells = <1>;
 		interrupt-parent = <&tlmm>;
-		interrupts = <73 0>;
 		qcom,gpio-connect = <&tlmm 73 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&wcd_intr_default>;
 	};
 
 	clock_audio: audio_ext_clk {
@@ -306,28 +318,61 @@
 		qcom,node_has_rpm_clock;
 		#clock-cells = <1>;
 		qcom,audio-ref-clk-gpio = <&pm8937_gpios 1 0>;
-		qcom,lpass-mclk-id = "pri_mclk";
 		clocks = <&clock_gcc clk_div_clk2>;
 		pinctrl-0 = <&cdc_mclk2_sleep>;
 		pinctrl-1 = <&cdc_mclk2_active>;
 	};
 
-	wcd_rst_gpio: wcd_gpio_ctrl {
+	wcd_rst_gpio: msm_cdc_pinctrl {
 		status = "disabled";
-		qcom,cdc-rst-n-gpio = <&tlmm 68 0>;
+		compatible = "qcom,msm-cdc-pinctrl";
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&cdc_reset_active>;
+		pinctrl-1 = <&cdc_reset_sleep>;
 	};
 };
 
 &slim_msm {
 	status = "disabled";
+
+	dai_slim: msm_dai_slim {
+		status = "disabled";
+		compatible = "qcom,msm-dai-slim";
+		elemental-addr = [ff ff ff fe 17 02];
+	};
+
 	wcd9335: tasha_codec {
 		status = "disabled";
 		compatible = "qcom,tasha-slim-pgd";
+		elemental-addr = [00 01 A0 01 17 02];
+
+		qcom,cdc-slim-ifd = "tasha-slim-ifd";
+		qcom,cdc-slim-ifd-elemental-addr = [00 00 A0 01 17 02];
+
+		interrupt-parent = <&wcd9xxx_intc>;
+		interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+				17 18 19 20 21 22 23 24 25 26 27 28 29 30>;
+
+		qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>;
+
 		clock-names = "wcd_clk", "wcd_native_clk";
 		clocks = <&clock_audio clk_audio_pmi_clk>,
 			<&clock_audio clk_audio_ap_clk2>;
 
-		qcom,cdc-reset-gpio = <&tlmm 68 0>;
+		qcom,cdc-static-supplies =
+				"cdc-vdd-buck",
+				"cdc-buck-sido",
+				"cdc-vdd-tx-h",
+				"cdc-vdd-rx-h",
+				"cdc-vdd-px";
+		qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias";
+		qcom,cdc-micbias1-mv = <1800>;
+		qcom,cdc-micbias2-mv = <1800>;
+		qcom,cdc-micbias3-mv = <1800>;
+		qcom,cdc-micbias4-mv = <1800>;
+
+		qcom,cdc-dmic-sample-rate = <2400000>;
+		qcom,cdc-mclk-clk-rate = <9600000>;
 
 		cdc-vdd-buck-supply = <&eldo2_pm8937>;
 		qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
@@ -355,18 +400,6 @@
 	};
 };
 
-&pm8937_gpios {
-	gpio@c000 {
-		status = "ok";
-		qcom,mode = <1>;
-		qcom,pull = <5>;
-		qcom,vin-sel = <0>;
-		qcom,src-sel = <2>;
-		qcom,master-en = <1>;
-		qcom,out-strength = <2>;
-	};
-};
-
 &pm8937_1 {
 	pmic_analog_codec: analog-codec@f000 {
 		status = "okay";
diff --git a/arch/arm64/boot/dts/qcom/msm8937.dtsi b/arch/arm64/boot/dts/qcom/msm8937.dtsi
index 9ef154a..66c7e7c 100644
--- a/arch/arm64/boot/dts/qcom/msm8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937.dtsi
@@ -30,6 +30,11 @@
 	firmware: firmware {
 		android {
 			compatible = "android,firmware";
+			vbmeta {
+				compatible = "android,vbmeta";
+				parts = "vbmeta,boot,system,vendor,dtbo,recovery";
+			};
+
 			fstab {
 				compatible = "android,fstab";
 				vendor {
@@ -37,7 +42,7 @@
 					dev = "/dev/block/platform/soc/7824900.sdhci/by-name/vendor";
 					type = "ext4";
 					mnt_flags = "ro,barrier=1,discard";
-					fsmgr_flags = "wait";
+					fsmgr_flags = "wait,avb";
 					status = "ok";
 				};
 				system {
@@ -45,7 +50,7 @@
 					dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system";
 					type = "ext4";
 					mnt_flags = "ro,barrier=1,discard";
-					fsmgr_flags = "wait";
+					fsmgr_flags = "wait,avb";
 					status = "ok";
 				};
 
@@ -423,6 +428,7 @@
 			<0x00a6018 0x00004>;
 		reg-names = "cc_base", "apcs_c1_base",
 				"apcs_c0_base", "efuse";
+		qcom,gfx3d_clk_src-opp-store-vcorner = <&msm_gpu>;
 		vdd_dig-supply = <&pm8937_s2_level>;
 		vdd_sr2_dig-supply = <&pm8937_s2_level_ao>;
 		vdd_sr2_pll-supply = <&pm8937_l7_ao>;
diff --git a/arch/arm64/boot/dts/qcom/msm8953-iot-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-iot-mtp.dts
index 39c76cc..c3d4cc5 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-iot-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-iot-mtp.dts
@@ -25,3 +25,18 @@
 	qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
 };
 
+&kgsl_smmu {
+	qcom,hibernation-support;
+	qcom,static-ns-cbs = <0>;
+	/delete-property/ qcom,skip-init;
+};
+
+&apps_iommu {
+	qcom,hibernation-support;
+	qcom,static-ns-cbs =
+			<15 16 17 18 19>,
+			<20 21 22 23 24 25 26 27 28 29 30>,
+			<31>;
+
+	/delete-property/ qcom,skip-init;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi
index cd0afec..67fd75f 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi
@@ -17,6 +17,7 @@
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
 #include <dt-bindings/clock/msm-clocks-8953.h>
+#include <dt-bindings/msm/msm-bus-ids.h>
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8953";
@@ -68,7 +69,7 @@
 
 		modem_mem: modem_region@0 {
 			compatible = "removed-dma-pool";
-			no-map-fixup;
+			no-map;
 			reg = <0x0 0x86c00000 0x0 0x6a00000>;
 		};
 
@@ -168,7 +169,18 @@
 		spi3 = &spi_3;
 	};
 
-	soc: soc { };
+	soc: soc {
+		/*
+		 * The ordering of these devices is important to boot time
+		 * for iot projects.
+		 */
+		smem: qcom,smem@86300000 {};
+		rpm_bus: qcom,rpm-smd {};
+		clock_gcc: qcom,gcc@1800000 {};
+		ad_hoc_bus: ad-hoc-bus@580000 {};
+		tlmm: pinctrl@1000000 {};
+		sdhc_1: sdhci@7824900 {};
+	};
 
 };
 
diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi
index 48bda61..0b1a50a 100644
--- a/arch/arm64/boot/dts/qcom/pmi632.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi
@@ -35,7 +35,8 @@
 		};
 
 		pmi632_vadc: vadc@3100 {
-			compatible = "qcom,qpnp-vadc-hc";
+			compatible = "qcom,qpnp-vadc-hc",
+				"qcom,qpnp-adc-hc-pm5";
 			reg = <0x3100 0x100>;
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -43,8 +44,6 @@
 			interrupt-names = "eoc-int-en-set";
 			qcom,adc-vdd-reference = <1875>;
 			qcom,adc-full-scale-code = <0x70e4>;
-			pinctrl-names = "default";
-			pinctrl-0 = <&quiet_therm_default &smb_therm_default>;
 
 			chan@0 {
 				label = "ref_gnd";
@@ -252,7 +251,8 @@
 		};
 
 		pmi632_adc_tm: vadc@3500 {
-			compatible = "qcom,qpnp-adc-tm-hc";
+			compatible = "qcom,qpnp-adc-tm-hc",
+				"qcom,qpnp-adc-tm-hc-pm5";
 			reg = <0x3500 0x100>;
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -303,21 +303,6 @@
 			gpio-controller;
 			#gpio-cells = <2>;
 			qcom,gpios-disallowed = <1>;
-
-			quiet_therm {
-				quiet_therm_default: quiet_therm_default {
-					pins = "gpio3";
-					bias-high-impedance;
-				};
-			};
-
-			smb_therm {
-				smb_therm_default: smb_therm_default {
-					pins = "gpio4";
-					bias-high-impedance;
-				};
-			};
-
 		};
 
 		pmi632_charger: qcom,qpnp-smb5 {
@@ -329,6 +314,7 @@
 			qcom,pmic-revid = <&pmi632_revid>;
 			dpdm-supply = <&qusb_phy>;
 			qcom,auto-recharge-soc = <98>;
+			qcom,chg-vadc = <&pmi632_vadc>;
 
 			qcom,thermal-mitigation
 				= <3000000 2500000 2000000 1500000
@@ -478,6 +464,7 @@
 						"ilim1-s1",
 						"ilim2-s2",
 						"vreg-ok";
+				qcom,flash-disable-soc = <10>;
 			};
 
 			smb5_vbus: qcom,smb5-vbus {
diff --git a/arch/arm64/boot/dts/qcom/qcs605.dtsi b/arch/arm64/boot/dts/qcom/qcs605.dtsi
index 1e1d82c..747593f 100644
--- a/arch/arm64/boot/dts/qcom/qcs605.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs605.dtsi
@@ -19,39 +19,39 @@
 };
 
 &pil_modem_mem {
-	reg = <0 0x8b000000 0 0x3e00000>;
+	reg = <0 0x8b000000 0 0x3100000>;
 };
 
 &pil_video_mem {
-	reg = <0 0x8ee00000 0 0x500000>;
+	reg = <0 0x8e100000 0 0x500000>;
 };
 
 &wlan_msa_mem {
-	reg = <0 0x8f300000 0 0x100000>;
+	reg = <0 0x8e600000 0 0x100000>;
 };
 
 &pil_cdsp_mem {
-	reg = <0 0x8f400000 0 0x800000>;
+	reg = <0 0x8e700000 0 0x800000>;
 };
 
 &pil_mba_mem {
-	reg = <0 0x8fc00000 0 0x200000>;
+	reg = <0 0x8ef00000 0 0x200000>;
 };
 
 &pil_adsp_mem {
-	reg = <0 0x8fe00000 0 0x1e00000>;
+	reg = <0 0x8f100000 0 0x1e00000>;
 };
 
 &pil_ipa_fw_mem {
-	reg = <0 0x91c00000 0 0x10000>;
+	reg = <0 0x90f00000 0 0x10000>;
 };
 
 &pil_ipa_gsi_mem {
-	reg = <0 0x91c10000 0 0x5000>;
+	reg = <0 0x90f10000 0 0x5000>;
 };
 
 &pil_gpu_mem {
-	reg = <0 0x91c15000 0 0x2000>;
+	reg = <0 0x90f15000 0 0x2000>;
 };
 
 &adsp_mem {
@@ -66,6 +66,10 @@
 	status = "disabled";
 };
 
+&dump_mem {
+	size = <0 0x800000>;
+};
+
 &soc {
 	qcom,rmnet-ipa {
 		status = "disabled";
@@ -76,6 +80,12 @@
 	status = "disabled";
 };
 
+&mem_dump {
+	rpmh {
+		qcom,dump-size = <0x400000>;
+	};
+};
+
 &thermal_zones {
 	lmh-dcvs-00 {
 		trips {
diff --git a/arch/arm64/boot/dts/qcom/sda429.dts b/arch/arm64/boot/dts/qcom/sda429.dts
new file mode 100644
index 0000000..6a26f23
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda429.dts
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sda429.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDA429 CDP";
+	compatible = "qcom,sda429-cdp", "qcom,sda429", "qcom,cdp";
+	qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+	qcom.pmic-name = "PMI632";
+};
diff --git a/arch/arm64/boot/dts/qcom/sda439.dts b/arch/arm64/boot/dts/qcom/sda439.dts
new file mode 100644
index 0000000..a124c75
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda439.dts
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sda439.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDA439";
+	compatible = "qcom,sda439";
+	qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+	qcom.pmic-name = "PMI632";
+};
diff --git a/arch/arm64/boot/dts/qcom/sda450-pmi632-mtp-s3.dts b/arch/arm64/boot/dts/qcom/sda450-pmi632-mtp-s3.dts
index c907977..f20c2ba 100644
--- a/arch/arm64/boot/dts/qcom/sda450-pmi632-mtp-s3.dts
+++ b/arch/arm64/boot/dts/qcom/sda450-pmi632-mtp-s3.dts
@@ -14,8 +14,8 @@
 /dts-v1/;
 
 #include "sda450.dtsi"
-#include "sdm450-pmi632-mtp-s3.dtsi"
 #include "sdm450-pmi632.dtsi"
+#include "sdm450-pmi632-mtp-s3.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDA450 + PMI632 MTP S3";
diff --git a/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi b/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi
index 0b678a8..c4b4a50 100644
--- a/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi
+++ b/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi
@@ -32,7 +32,6 @@
 			/* MDM PON conrol*/
 			pins = "gpio10";
 			function = "normal";
-			output-low;
 			power-source = <0>;
 		};
 	};
diff --git a/arch/arm64/boot/dts/qcom/sda845-svr.dtsi b/arch/arm64/boot/dts/qcom/sda845-svr.dtsi
index ce62781..ed2ad69 100644
--- a/arch/arm64/boot/dts/qcom/sda845-svr.dtsi
+++ b/arch/arm64/boot/dts/qcom/sda845-svr.dtsi
@@ -14,9 +14,12 @@
 #include "sdm845-pinctrl-overlay.dtsi"
 #include "sda845-svr-pinctrl-overlay.dtsi"
 #include "sdm845-camera-sensor-svr.dtsi"
-#include "smb1355.dtsi"
 #include <dt-bindings/clock/mdss-10nm-pll-clk.h>
 
+&qupv3_se10_i2c {
+#include "smb1355.dtsi"
+};
+
 &vendor {
 	bluetooth: bt_wcn3990 {
 		compatible = "qca,wcn3990";
diff --git a/arch/arm64/boot/dts/qcom/sdm429-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-cdp-overlay.dts
index 93a9ae9..c55c2a5 100644
--- a/arch/arm64/boot/dts/qcom/sdm429-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm429-cdp-overlay.dts
@@ -22,5 +22,4 @@
 / {
 	model = "CDP";
 	qcom,board-id = <1 3>;
-	qcom,msm-id = <354 0x0>;
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm429-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-mtp-overlay.dts
index 3a339da..7735b35 100644
--- a/arch/arm64/boot/dts/qcom/sdm429-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm429-mtp-overlay.dts
@@ -22,5 +22,4 @@
 / {
 	model = "MTP";
 	qcom,board-id = <8 2>;
-	qcom,msm-id = <354 0x0>;
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm429-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-qrd-overlay.dts
index 8abccb7..fae68c9 100644
--- a/arch/arm64/boot/dts/qcom/sdm429-qrd-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm429-qrd-overlay.dts
@@ -22,5 +22,4 @@
 / {
 	model = "QRD";
 	qcom,board-id = <0xb 3>;
-	qcom,msm-id = <354 0x0>;
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm429-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm429-qrd.dtsi
index 7116662..dde9c56 100644
--- a/arch/arm64/boot/dts/qcom/sdm429-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm429-qrd.dtsi
@@ -12,3 +12,7 @@
  */
 
 #include "sdm439-qrd.dtsi"
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_hx8399c_hd_vid>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi
index 24e9905..19df054 100644
--- a/arch/arm64/boot/dts/qcom/sdm429.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi
@@ -207,3 +207,9 @@
 		"byte1_src";
 	#clock-cells = <1>;
 };
+
+/* GPU overrides */
+&msm_gpu {
+	/* Update GPU chip ID*/
+	qcom,chipid = <0x05000400>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi
index f6751d2..a6b2371 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi
@@ -15,6 +15,7 @@
 	int_codec: sound {
 		qcom,model = "sdm439-snd-card-mtp";
 		qcom,msm-hs-micbias-type = "internal";
+		qcom,msm-micbias2-ext-cap;
 
 		asoc-codec = <&stub_codec>, <&msm_digital_codec>,
 				<&pmic_analog_codec>;
@@ -24,6 +25,65 @@
 		qcom,msm-vdd-wsa-switch-voltage = <1800000>;
 		qcom,msm-vdd-wsa-switch-current = <10000>;
 	};
+
+	clock_audio_native: audio_ext_clk_native {
+		status = "disabled";
+		compatible = "qcom,audio-ref-clk";
+		#clock-cells = <1>;
+		qcom,codec-mclk-clk-freq = <11289600>;
+		qcom,audio-ref-clk-gpio = <&tlmm 66 0>;
+		qcom,lpass-mclk-id = "pri_mclk";
+		pinctrl-names = "sleep", "active";
+		pinctrl-0 = <&cdc_mclk2_sleep>;
+		pinctrl-1 = <&cdc_mclk2_active>;
+	};
+};
+
+
+&clock_audio {
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&tasha_mclk_default>;
+	pinctrl-1 = <&tasha_mclk_default>;
+	qcom,audio-ref-clk-gpio = <&pm8953_gpios 1 0>;
+};
+
+&wcd9335 {
+	cdc-vdd-buck-supply = <&dbu1>;
+	qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+	qcom,cdc-vdd-buck-current = <650000>;
+
+	cdc-buck-sido-supply = <&dbu1>;
+	qcom,cdc-buck-sido-voltage = <1800000 1800000>;
+	qcom,cdc-buck-sido-current = <150000>;
+
+	cdc-vdd-tx-h-supply = <&dbu1>;
+	qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+	qcom,cdc-vdd-tx-h-current = <25000>;
+
+	cdc-vdd-rx-h-supply = <&dbu1>;
+	qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+	qcom,cdc-vdd-rx-h-current = <25000>;
+
+	cdc-vdd-px-supply = <&dbu1>;
+	qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+	qcom,cdc-vdd-px-current = <10000>;
+
+	cdc-vdd-mic-bias-supply = <&pm8953_l13>;
+	qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
+	qcom,cdc-vdd-mic-bias-current = <15000>;
+};
+
+&pm8953_gpios {
+	tasha_mclk {
+		tasha_mclk_default: tasha_mclk_default{
+			pins = "gpio1";
+			function = "func1";
+			qcom,drive-strength = <2>;
+			power-source = <0>;
+			bias-disable;
+			output-low;
+		};
+	};
 };
 
 &pm8953_1 {
@@ -76,7 +136,7 @@
 		qcom,cdc-vdd-pa-current = <260000>;
 
 		cdc-vdd-mic-bias-supply = <&pm8953_l13>;
-		qcom,cdc-vdd-mic-bias-voltage = <3125000 3125000>;
+		qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
 		qcom,cdc-vdd-mic-bias-current = <5000>;
 
 		qcom,cdc-mclk-clk-rate = <9600000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm439-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm439-cdp-overlay.dts
index 6d6f99b..5e86672 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm439-cdp-overlay.dts
@@ -22,5 +22,4 @@
 / {
 	model = "CDP";
 	qcom,board-id = <1 2>;
-	qcom,msm-id = <353 0x0>;
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi
index 08745cd..fd66f4b 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi
@@ -150,6 +150,30 @@
 	};
 };
 
+&cdc_pdm_lines_2_act {
+	mux {
+		pins = "gpio70", "gpio71", "gpio72";
+		function = "cdc_pdm0";
+	};
+
+	config {
+		pins = "gpio70", "gpio71", "gpio72";
+		drive-strength = <16>;
+	};
+};
+
+&cdc_pdm_lines_act {
+	mux {
+		pins = "gpio69", "gpio73", "gpio74";
+		function = "cdc_pdm0";
+	};
+
+	config {
+		pins = "gpio69", "gpio73", "gpio74";
+		drive-strength = <16>;
+	};
+};
+
 &pm8953_pwm {
 	status = "ok";
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm439-ext-audio-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-ext-audio-mtp.dtsi
new file mode 100644
index 0000000..a74fb75
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-ext-audio-mtp.dtsi
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+&int_codec {
+	status = "disabled";
+};
+
+&wsa881x_i2c_f {
+	status = "disabled";
+};
+
+&wsa881x_i2c_45 {
+	status = "disabled";
+};
+
+&cdc_pri_mi2s_gpios {
+	status = "disabled";
+};
+
+&wsa881x_analog_vi_gpio {
+	status = "disabled";
+};
+
+&wsa881x_analog_clk_gpio {
+	status = "disabled";
+};
+
+&wsa881x_analog_reset_gpio {
+	status = "disabled";
+};
+
+&slim_msm {
+	status = "okay";
+};
+
+&dai_slim {
+	status = "okay";
+};
+
+&wcd9xxx_intc {
+	status = "okay";
+};
+
+&clock_audio {
+	status = "okay";
+};
+
+&wcd9335 {
+	status = "okay";
+};
+
+&cdc_us_euro_sw {
+	status = "okay";
+};
+
+&cdc_quin_mi2s_gpios {
+	status = "okay";
+};
+
+&wcd_rst_gpio {
+	status = "okay";
+};
+
+&ext_codec {
+	status = "okay";
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp-overlay.dts
new file mode 100644
index 0000000..468f514
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp-overlay.dts
@@ -0,0 +1,28 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clock/msm-clocks-8953.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm439-mtp.dtsi"
+#include "sdm439-external-codec.dtsi"
+
+/ {
+	model = "MTP";
+	qcom,board-id = <8 3>;
+	qcom,msm-id = <353 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp.dts
new file mode 100644
index 0000000..e2a86bb
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp.dts
@@ -0,0 +1,25 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm439.dtsi"
+#include "sdm439-mtp.dtsi"
+#include "sdm439-external-codec.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM439 Audio Codec MTP";
+	compatible = "qcom,sdm439-mtp", "qcom,sdm439", "qcom,mtp";
+	qcom,board-id = <8 3>;
+	qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-external-codec.dtsi b/arch/arm64/boot/dts/qcom/sdm439-external-codec.dtsi
new file mode 100644
index 0000000..83864ef
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-external-codec.dtsi
@@ -0,0 +1,12 @@
+/* Copyright (c) 2018, 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 "sdm439-ext-audio-mtp.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm439-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm439-mtp-overlay.dts
index df8a0d7..8b6c6fb 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm439-mtp-overlay.dts
@@ -22,5 +22,4 @@
 / {
 	model = "MTP";
 	qcom,board-id = <8 1>;
-	qcom,msm-id = <353 0x0>;
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi
index 29e0d72..9aa6d58 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi
@@ -215,3 +215,60 @@
 	qcom,mdss-dsi-bl-pmic-bank-select = <0>;
 	qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
 };
+
+&i2c_2 {
+#include "smb1355.dtsi"
+};
+
+&pmi632_gpios {
+	smb_en {
+		smb_en_default: smb_en_default {
+			pins = "gpio2";
+			function = "func1";
+			output-enable;
+		};
+	};
+};
+
+&tlmm {
+	smb_int_default: smb_int_default {
+		mux {
+			pins = "gpio59";
+			function = "gpio";
+		};
+		config {
+			pins = "gpio59";
+			drive-strength = <2>;
+			bias-pull-up;
+			input-enable;
+		};
+	};
+};
+
+&smb1355_0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&smb_int_default
+			&smb_en_default>;
+	interrupt-parent = <&tlmm>;
+	interrupts = <59 IRQ_TYPE_LEVEL_LOW>;
+	smb1355_charger_0: qcom,smb1355-charger@1000 {
+		status ="ok";
+		/delete-property/ io-channels;
+		/delete-property/ io-channels-names;
+		qcom,parallel-mode = <1>;
+	};
+};
+
+&smb1355_1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&smb_int_default
+			&smb_en_default>;
+	interrupt-parent = <&tlmm>;
+	interrupts = <59 IRQ_TYPE_LEVEL_LOW>;
+	smb1355_charger_1: qcom,smb1355-charger@1000 {
+		status ="ok";
+		/delete-property/ io-channels;
+		/delete-property/ io-channels-names;
+		qcom,parallel-mode = <1>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi b/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi
index bc2ba9f..68bf1d2 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi
@@ -43,6 +43,27 @@
 	qcom,battery-data = <&mtp_batterydata>;
 };
 
+&pmi632_vadc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&quiet_therm_default &smb_therm_default>;
+};
+
+&pmi632_gpios {
+	quiet_therm {
+		quiet_therm_default: quiet_therm_default {
+			pins = "gpio3";
+			bias-high-impedance;
+		};
+	};
+
+	smb_therm {
+		smb_therm_default: smb_therm_default {
+			pins = "gpio4";
+			bias-high-impedance;
+		};
+	};
+};
+
 &pm8953_typec {
 	status = "disabled";
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm439-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm439-qrd-overlay.dts
index ac059c4d..ed6b2ad 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-qrd-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm439-qrd-overlay.dts
@@ -22,5 +22,4 @@
 / {
 	model = "QRD";
 	qcom,board-id = <0xb 2>;
-	qcom,msm-id = <353 0x0>;
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi
index 18714ce..df85d95 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi
@@ -51,6 +51,11 @@
 	qcom,msm-mbhc-hphl-swh = <1>;
 	qcom,msm-mbhc-gnd-swh = <0>;
 	qcom,msm-hs-micbias-type = "external";
+	/delete-property/ qcom,quin-mi2s-gpios;
+};
+
+&cdc_quin_mi2s_gpios {
+	status = "disabled";
 };
 
 &wsa881x_i2c_f {
@@ -297,3 +302,70 @@
 	qcom,mdss-dsi-pan-fps-update =
 		"dfps_immediate_porch_mode_vfp";
 };
+
+&dsi_hx8399c_hd_vid {
+	/delete-property/ qcom,mdss-dsi-panel-timings;
+	qcom,mdss-dsi-panel-timings-phy-12nm = [08 06 0a 02 00 04 02 08];
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+	qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+	qcom,mdss-dsi-bl-pmic-bank-select = <0>;
+	qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
+};
+
+&i2c_2 {
+#include "smb1355.dtsi"
+};
+
+&pmi632_gpios {
+	smb_en {
+		smb_en_default: smb_en_default {
+			pins = "gpio2";
+			function = "func1";
+			output-enable;
+		};
+	};
+};
+
+&tlmm {
+	smb_int_default: smb_int_default {
+		mux {
+			pins = "gpio59";
+			function = "gpio";
+		};
+		config {
+			pins = "gpio59";
+			drive-strength = <2>;
+			bias-pull-up;
+			input-enable;
+		};
+	};
+};
+
+&smb1355_0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&smb_int_default
+			&smb_en_default>;
+	interrupt-parent = <&tlmm>;
+	interrupts = <59 IRQ_TYPE_LEVEL_LOW>;
+	smb1355_charger_0: qcom,smb1355-charger@1000 {
+		status ="ok";
+		/delete-property/ io-channels;
+		/delete-property/ io-channels-names;
+		qcom,parallel-mode = <1>;
+	};
+};
+
+&smb1355_1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&smb_int_default
+			&smb_en_default>;
+	interrupt-parent = <&tlmm>;
+	interrupts = <59 IRQ_TYPE_LEVEL_LOW>;
+	smb1355_charger_1: qcom,smb1355-charger@1000 {
+		status ="ok";
+		/delete-property/ io-channels;
+		/delete-property/ io-channels-names;
+		qcom,parallel-mode = <1>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi
index f325925..e2f2dea 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi
@@ -468,5 +468,26 @@
 		qcom,cpr-quot-adjust-scaling-factor-max = <0 1400 1400>;
 		qcom,cpr-voltage-scaling-factor-max = <0 2000 2000>;
 		qcom,cpr-scaled-init-voltage-as-ceiling;
+
+		qcom,cpr-fuse-version-map =
+			/* <Speed-bin pvs-version cpr-rev ... ... ...> */
+			<(-1)    (-1)   ( 0)   (-1)    (-1)    (-1)>,
+			<(-1)    (-1)   (-1)   (-1)    (-1)    (-1)>;
+
+		qcom,cpr-quotient-adjustment =
+			<66    77      66>, /* SVSP_30mV, NOM_35mV, TUR_30mV */
+			<0      0       0>;
+
+		qcom,cpr-voltage-ceiling-override =
+			<(-1) (-1) 795000 795000 835000 910000 910000>;
+
+		qcom,cpr-enable;
+	};
+
+	dbu1: dbu1 {
+		compatible = "regulator-fixed";
+		regulator-name = "dbu1";
+		startup-delay-us = <0>;
+		enable-active-high;
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm439.dtsi b/arch/arm64/boot/dts/qcom/sdm439.dtsi
index 2df468f..0e4f666 100644
--- a/arch/arm64/boot/dts/qcom/sdm439.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm439.dtsi
@@ -14,6 +14,7 @@
 #include "msm8937.dtsi"
 #include "sdm439-pm8953.dtsi"
 #include "sdm439-pmi632.dtsi"
+#include "sdm439-audio.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM439";
diff --git a/arch/arm64/boot/dts/qcom/sdm450-cdp-s2-overlay.dts b/arch/arm64/boot/dts/qcom/sdm450-cdp-s2-overlay.dts
index e12ad51..97c9389 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-cdp-s2-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-cdp-s2-overlay.dts
@@ -18,7 +18,6 @@
 
 / {
 	model = "CDP S2";
-	compatible = "qcom,cdp";
 	qcom,board-id = <1 2>;
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm450-mtp-s3-overlay.dts b/arch/arm64/boot/dts/qcom/sdm450-mtp-s3-overlay.dts
index ae522a5..3dd7200 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-mtp-s3-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-mtp-s3-overlay.dts
@@ -18,7 +18,6 @@
 
 / {
 	model = "MTP S3";
-	compatible = "qcom,mtp";
 	qcom,board-id = <8 3>;
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dts
index b9aadc1..b73b49a 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dts
@@ -14,8 +14,8 @@
 /dts-v1/;
 
 #include "sdm450.dtsi"
-#include "sdm450-pmi632-mtp-s3.dtsi"
 #include "sdm450-pmi632.dtsi"
+#include "sdm450-pmi632-mtp-s3.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM450 + PMI632 MTP S3";
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi
index 64d9e64..265a86d 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi
@@ -46,3 +46,60 @@
 	qcom,mdss-dsi-bl-pmic-bank-select = <0>;
 	qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
 };
+
+&i2c_2 {
+#include "smb1355.dtsi"
+};
+
+&pmi632_gpios {
+	smb_en {
+		smb_en_default: smb_en_default {
+			pins = "gpio2";
+			function = "func1";
+			output-enable;
+		};
+	};
+};
+
+&tlmm {
+	smb_int_default: smb_int_default {
+		mux {
+			pins = "gpio59";
+			function = "gpio";
+		};
+		config {
+			pins = "gpio59";
+			drive-strength = <2>;
+			bias-pull-up;
+			input-enable;
+		};
+	};
+};
+
+&smb1355_0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&smb_int_default
+			&smb_en_default>;
+	interrupt-parent = <&tlmm>;
+	interrupts = <59 IRQ_TYPE_LEVEL_LOW>;
+	smb1355_charger_0: qcom,smb1355-charger@1000 {
+		status ="ok";
+		/delete-property/ io-channels;
+		/delete-property/ io-channels-names;
+		qcom,parallel-mode = <1>;
+	};
+};
+
+&smb1355_1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&smb_int_default
+			&smb_en_default>;
+	interrupt-parent = <&tlmm>;
+	interrupts = <59 IRQ_TYPE_LEVEL_LOW>;
+	smb1355_charger_1: qcom,smb1355-charger@1000 {
+		status ="ok";
+		/delete-property/ io-channels;
+		/delete-property/ io-channels-names;
+		qcom,parallel-mode = <1>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi b/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi
index 5c127bc..e09d637 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi
@@ -41,6 +41,27 @@
 	};
 };
 
+&pmi632_vadc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&quiet_therm_default &smb_therm_default>;
+};
+
+&pmi632_gpios {
+	quiet_therm {
+		quiet_therm_default: quiet_therm_default {
+			pins = "gpio3";
+			bias-high-impedance;
+		};
+	};
+
+	smb_therm {
+		smb_therm_default: smb_therm_default {
+			pins = "gpio4";
+			bias-high-impedance;
+		};
+	};
+};
+
 &pmi632_qg {
 	qcom,battery-data = <&mtp_batterydata>;
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4-overlay.dts b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4-overlay.dts
index 558c3c6..e8dca18 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4-overlay.dts
@@ -18,7 +18,6 @@
 
 / {
 	model = "QRD SKU4";
-	compatible = "qcom,qrd";
 	qcom,board-id = <0xb 1>;
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
index 386bd71..c5eff7b4 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
@@ -177,3 +177,59 @@
 	};
 };
 
+&i2c_2 {
+#include "smb1355.dtsi"
+};
+
+&pmi632_gpios {
+	smb_en {
+		smb_en_default: smb_en_default {
+			pins = "gpio2";
+			function = "func1";
+			output-enable;
+		};
+	};
+};
+
+&tlmm {
+	smb_int_default: smb_int_default {
+		mux {
+			pins = "gpio59";
+			function = "gpio";
+		};
+		config {
+			pins = "gpio59";
+			drive-strength = <2>;
+			bias-pull-up;
+			input-enable;
+		};
+	};
+};
+
+&smb1355_0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&smb_int_default
+			&smb_en_default>;
+	interrupt-parent = <&tlmm>;
+	interrupts = <59 IRQ_TYPE_LEVEL_LOW>;
+	smb1355_charger_0: qcom,smb1355-charger@1000 {
+		status ="ok";
+		/delete-property/ io-channels;
+		/delete-property/ io-channels-names;
+		qcom,parallel-mode = <1>;
+	};
+};
+
+&smb1355_1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&smb_int_default
+			&smb_en_default>;
+	interrupt-parent = <&tlmm>;
+	interrupts = <59 IRQ_TYPE_LEVEL_LOW>;
+	smb1355_charger_1: qcom,smb1355-charger@1000 {
+		status ="ok";
+		/delete-property/ io-channels;
+		/delete-property/ io-channels-names;
+		qcom,parallel-mode = <1>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi b/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi
index de1bd1f..c37750a 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi
@@ -258,7 +258,7 @@
 			busy-cost-data = <
 				633600	722
 				902400	1287
-				1036800	1739
+				1094400	1739
 				1401600	2819
 				1555200	3532
 				1804800	5038
@@ -287,7 +287,7 @@
 			busy-cost-data = <
 				633600	68
 				902400	103
-				1036800	132
+				1094400	132
 				1401600	193
 				1555200	233
 				1804800	292
diff --git a/arch/arm64/boot/dts/qcom/sdm632-ext-audio-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm632-ext-audio-mtp.dtsi
new file mode 100644
index 0000000..b34e3d8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-ext-audio-mtp.dtsi
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+&int_codec {
+	status = "disabled";
+};
+
+&pmic_analog_codec {
+	status = "disabled";
+};
+
+&wsa881x_i2c_f {
+	status = "disabled";
+};
+
+&wsa881x_i2c_45 {
+	status = "disabled";
+};
+
+&cdc_pri_mi2s_gpios {
+	status = "disabled";
+};
+
+&wsa881x_analog_vi_gpio {
+	status = "disabled";
+};
+
+&wsa881x_analog_clk_gpio {
+	status = "disabled";
+};
+
+&wsa881x_analog_reset_gpio {
+	status = "disabled";
+};
+
+&cdc_comp_gpios {
+	status = "disabled";
+};
+
+&slim_msm {
+	status = "okay";
+};
+
+&dai_slim {
+	status = "okay";
+};
+
+&wcd9xxx_intc {
+	status = "okay";
+};
+
+&clock_audio {
+	status = "okay";
+};
+
+&wcd9335 {
+	status = "okay";
+
+	dc-vdd-buck-supply = <&dbu3>;
+	qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+	qcom,cdc-vdd-buck-current = <650000>;
+
+	cdc-buck-sido-supply = <&dbu3>;
+	qcom,cdc-buck-sido-voltage = <1800000 1800000>;
+	qcom,cdc-buck-sido-current = <150000>;
+
+	cdc-vdd-tx-h-supply = <&dbu3>;
+	qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+	qcom,cdc-vdd-tx-h-current = <25000>;
+
+	cdc-vdd-rx-h-supply = <&dbu3>;
+	qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+	qcom,cdc-vdd-rx-h-current = <25000>;
+
+	cdc-vdd-px-supply = <&dbu3>;
+	qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+	qcom,cdc-vdd-px-current = <10000>;
+};
+
+&cdc_us_euro_sw {
+	status = "okay";
+};
+
+&cdc_quin_mi2s_gpios {
+	status = "okay";
+};
+
+&wcd_rst_gpio {
+	status = "okay";
+};
+
+&ext_codec {
+	qcom,model = "msm8953-tasha-snd-card";
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-cdp-s3-overlay.dts b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-cdp-s3-overlay.dts
index eb5afbd..c3e0ba9 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-cdp-s3-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-cdp-s3-overlay.dts
@@ -18,7 +18,6 @@
 
 / {
 	model = "Ext Codec CDP S3";
-	compatible = "qcom,cdp";
 	qcom,board-id = <1 3>;
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4-overlay.dts b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4-overlay.dts
index 5656fd0..63b51ab 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4-overlay.dts
@@ -18,7 +18,6 @@
 
 / {
 	model = "Ext Codec MTP S4";
-	compatible = "qcom,mtp";
 	qcom,board-id = <8 4>;
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4.dtsi b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4.dtsi
index d8326ff..fd1eb3d 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4.dtsi
@@ -12,4 +12,5 @@
  */
 
 #include "sdm450-pmi632-mtp-s3.dtsi"
+#include "sdm632-ext-audio-mtp.dtsi"
 
diff --git a/arch/arm64/boot/dts/qcom/sdm632-mtp-s3.dts b/arch/arm64/boot/dts/qcom/sdm632-mtp-s3.dts
index 3662cf3..1dd1163 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-mtp-s3.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-mtp-s3.dts
@@ -14,8 +14,8 @@
 /dts-v1/;
 
 #include "sdm632.dtsi"
-#include "sdm450-pmi632-mtp-s3.dtsi"
 #include "sdm450-pmi632.dtsi"
+#include "sdm450-pmi632-mtp-s3.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM632 + PMI632 MTP S3";
diff --git a/arch/arm64/boot/dts/qcom/sdm632-pm8004-mtp-s3.dts b/arch/arm64/boot/dts/qcom/sdm632-pm8004-mtp-s3.dts
index d2a9cf1..aea6bff 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-pm8004-mtp-s3.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-pm8004-mtp-s3.dts
@@ -14,8 +14,8 @@
 /dts-v1/;
 
 #include "sdm632.dtsi"
-#include "sdm450-pmi632-mtp-s3.dtsi"
 #include "sdm450-pmi632.dtsi"
+#include "sdm450-pmi632-mtp-s3.dtsi"
 #include "sdm632-pm8004.dtsi"
 
 / {
diff --git a/arch/arm64/boot/dts/qcom/sdm632-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm632-qrd-overlay.dts
index e6217e5..4b7f6b2 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-qrd-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-qrd-overlay.dts
@@ -18,7 +18,6 @@
 
 / {
 	model = "QRD";
-	compatible = "qcom,qrd";
 	qcom,board-id = <0xb 3>;
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm632-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm632-qrd.dtsi
index 09077c42..cefc078 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm632-qrd.dtsi
@@ -12,3 +12,9 @@
  */
 
 #include "sdm450-qrd-sku4.dtsi"
+
+&ssphy {
+	fpc-redrive-supply = <&pm8953_l6>;
+	qcom,redrive-voltage-level = <0 1800000 1900000>;
+	qcom,redrive-load = <105000>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-rcm.dts b/arch/arm64/boot/dts/qcom/sdm632-rcm.dts
index 68f0ea0..fe7ab38 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-rcm.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-rcm.dts
@@ -24,3 +24,32 @@
 	qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
 };
 
+&soc {
+	gpio_keys {
+		/delete-node/home;
+	};
+};
+
+&tlmm {
+	tlmm_gpio_key {
+		gpio_key_active: gpio_key_active {
+			mux {
+				pins = "gpio85", "gpio86", "gpio87";
+			};
+
+			config {
+				pins = "gpio85", "gpio86", "gpio87";
+			};
+		};
+
+		gpio_key_suspend: gpio_key_suspend {
+			mux {
+				pins = "gpio85", "gpio86", "gpio87";
+			};
+
+			config {
+				pins = "gpio85", "gpio86", "gpio87";
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi
index b5373a2..33ac930 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi
@@ -114,6 +114,8 @@
 		qcom,cpr-count-repeat = <14>;
 		qcom,cpr-down-error-step-limit = <1>;
 		qcom,cpr-up-error-step-limit = <1>;
+		qcom,cpr-reset-step-quot-loop-en;
+		qcom,cpr-thread-has-always-vote-en;
 
 		qcom,apm-ctrl = <&apc_apm>;
 		qcom,apm-threshold-voltage = <875000>;
@@ -131,10 +133,13 @@
 			"APCS_ALIAS0_APM_CTLER_STATUS",
 			"APCS0_CPR_CORE_ADJ_MODE_REG";
 
+		qcom,cpr-enable;
+		qcom,cpr-hw-closed-loop;
+
 		thread@0 {
 			qcom,cpr-thread-id = <0>;
 			qcom,cpr-consecutive-up = <0>;
-			qcom,cpr-consecutive-down = <2>;
+			qcom,cpr-consecutive-down = <0>;
 			qcom,cpr-up-threshold = <2>;
 			qcom,cpr-down-threshold = <1>;
 
@@ -143,10 +148,10 @@
 				regulator-min-microvolt = <1>;
 				regulator-max-microvolt = <7>;
 
-				qcom,cpr-fuse-corners = <5>;
+				qcom,cpr-fuse-corners = <4>;
 				qcom,cpr-fuse-combos = <64>;
 				qcom,cpr-corners = <7>;
-				qcom,cpr-corner-fmax-map = <1 2 3 4 7>;
+				qcom,cpr-corner-fmax-map = <1 3 4 7>;
 
 				qcom,cpr-voltage-ceiling =
 					<720000  790000 865000 865000 920000
@@ -156,6 +161,10 @@
 					<500000  500000 500000 500000 500000
 					 500000  500000>;
 
+				qcom,cpr-floor-to-ceiling-max-range =
+					<50000  50000 50000 50000 50000
+					 50000  50000>;
+
 				qcom,mem-acc-voltage = <1 1 2 2 2 2 3>;
 
 				qcom,corner-frequencies =
@@ -171,44 +180,55 @@
 				      <3600 3600 3830 2430 2520 2700 1790 1760
 				       1970 1880 2110 2010 2510 4900 4370 4780>,
 				      <3600 3600 3830 2430 2520 2700 1790 1760
-				       1970 1880 2110 2010 2510 4900 4370 4780>,
-				      <3600 3600 3830 2430 2520 2700 1790 1760
 				       1970 1880 2110 2010 2510 4900 4370 4780>;
 
 				qcom,allow-voltage-interpolation;
 				qcom,allow-quotient-interpolation;
 				qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+
+				qcom,cpr-open-loop-voltage-fuse-adjustment =
+					< 0       0      0 10000>;
+
+				qcom,cpr-closed-loop-voltage-fuse-adjustment =
+					<(-10000) 0      0 10000>;
 			};
 		};
 
 		thread@1 {
 			qcom,cpr-thread-id = <1>;
 			qcom,cpr-consecutive-up = <0>;
-			qcom,cpr-consecutive-down = <2>;
+			qcom,cpr-consecutive-down = <0>;
 			qcom,cpr-up-threshold = <2>;
 			qcom,cpr-down-threshold = <1>;
 
 			apc1_perfcl_vreg: regulator {
 				regulator-name = "apc1_perfcl_corner";
 				regulator-min-microvolt = <1>;
-				regulator-max-microvolt = <5>;
+				regulator-max-microvolt = <7>;
 
-				qcom,cpr-fuse-corners = <3>;
+				qcom,cpr-fuse-corners = <4>;
 				qcom,cpr-fuse-combos = <64>;
-				qcom,cpr-corners = <5>;
-				qcom,cpr-corner-fmax-map = <1 2 5>;
+				qcom,cpr-corners = <7>;
+				qcom,cpr-corner-fmax-map = <1 3 4 7>;
 
 				qcom,cpr-voltage-ceiling =
-					<865000 865000 920000 990000 1065000>;
+					<720000 790000 865000 865000 920000
+					 990000 1065000>;
 
 				qcom,cpr-voltage-floor =
-					<500000  500000 500000 500000 500000>;
+					<500000 500000 500000 500000 500000
+					 500000 500000>;
 
-				qcom,mem-acc-voltage = <2 2 2 2 3>;
+				qcom,cpr-floor-to-ceiling-max-range =
+					<50000  50000 50000 50000 50000
+					 50000  50000>;
+
+				qcom,mem-acc-voltage = <1 1 2 2 2 2 3>;
 
 				qcom,corner-frequencies =
-					<1094400000 1401600000 1555200000
-					 1804800000 2016000000>;
+					<633600000   902400000 1094400000
+					 1401600000 1555200000 1804800000
+					 2016000000>;
 
 				qcom,cpr-ro-scaling-factor =
 				      <3600 3600 3830 2430 2520 2700 1790 1760
@@ -216,11 +236,175 @@
 				      <3600 3600 3830 2430 2520 2700 1790 1760
 				       1970 1880 2110 2010 2510 4900 4370 4780>,
 				      <3600 3600 3830 2430 2520 2700 1790 1760
+				       1970 1880 2110 2010 2510 4900 4370 4780>,
+				      <3600 3600 3830 2430 2520 2700 1790 1760
 				       1970 1880 2110 2010 2510 4900 4370 4780>;
 
 				qcom,allow-voltage-interpolation;
 				qcom,allow-quotient-interpolation;
 				qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+
+				qcom,cpr-open-loop-voltage-fuse-adjustment =
+					/* Speed bin 0; CPR rev 0..7 */
+					< 30000      0  10000 20000>,
+					< 30000      0  10000 20000>,
+					<     0      0  10000 20000>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 1; CPR rev 0..7 */
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 2; CPR rev 0..7 */
+					< 30000      0  10000 20000>,
+					< 30000      0  10000 20000>,
+					<     0      0  10000 20000>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 3; CPR rev 0..7 */
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 4; CPR rev 0..7 */
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 5; CPR rev 0..7 */
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 6; CPR rev 0..7 */
+					< 30000      0  10000 20000>,
+					< 30000      0  10000 20000>,
+					<     0      0  10000 20000>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 7; CPR rev 0..7 */
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>;
+
+				qcom,cpr-closed-loop-voltage-fuse-adjustment =
+					/* Speed bin 0; CPR rev 0..7 */
+					< 30000      0      0     0>,
+					< 30000      0      0     0>,
+					<(-10000)    0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 1; CPR rev 0..7 */
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 2; CPR rev 0..7 */
+					< 30000      0      0     0>,
+					< 30000      0      0     0>,
+					<(-10000)    0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 3; CPR rev 0..7 */
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 4; CPR rev 0..7 */
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 5; CPR rev 0..7 */
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 6; CPR rev 0..7 */
+					< 30000      0      0     0>,
+					< 30000      0      0     0>,
+					<(-10000)    0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 7; CPR rev 0..7 */
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>;
 			};
 		};
 	};
@@ -267,4 +451,11 @@
 		mem-acc-supply = <&gfx_mem_acc>;
 		qcom,mem-acc-corner-map = <1 1 1 2 2 2 2>;
 	};
+
+	dbu3: dbu3 {
+		compatible = "regulator-fixed";
+		regulator-name = "dbu3";
+		startup-delay-us = <0>;
+		enable-active-high;
+	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm632.dtsi b/arch/arm64/boot/dts/qcom/sdm632.dtsi
index 69cb36f..67efe0f 100644
--- a/arch/arm64/boot/dts/qcom/sdm632.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm632.dtsi
@@ -40,6 +40,17 @@
 
 &clock_gcc_gfx {
 	compatible = "qcom,gcc-gfx-sdm632";
+	qcom,gfxfreq-corner =
+		 <         0   0 >,
+		 < 133330000   1 >,  /* Min SVS   */
+		 < 216000000   2 >,  /* Low SVS   */
+		 < 320000000   3 >,  /* SVS       */
+		 < 400000000   4 >,  /* SVS Plus  */
+		 < 510000000   5 >,  /* NOM       */
+		 < 560000000   6 >,  /* Nom Plus  */
+		 < 650000000   7 >,  /* Turbo     */
+		 < 700000000   7 >,  /* Turbo     */
+		 < 725000000   7 >;  /* Turbo     */
 };
 
 &thermal_zones {
@@ -824,10 +835,12 @@
 		<  1804800000 7>;
 	qcom,speed0-bin-v0-c1 =
 		<          0 0>,
-		<  1094400000 1>,
-		<  1401600000 2>,
-		<  1555200000 3>,
-		<  1804800000 4>;
+		<   633600000 1>,
+		<   902400000 2>,
+		<  1094400000 3>,
+		<  1401600000 4>,
+		<  1555200000 5>,
+		<  1804800000 6>;
 	qcom,speed0-bin-v0-cci =
 		<          0 0>,
 		<  307200000 1>,
@@ -848,10 +861,12 @@
 		<  1804800000 7>;
 	qcom,speed6-bin-v0-c1 =
 		<          0 0>,
-		<  1094400000 1>,
-		<  1401600000 2>,
-		<  1555200000 3>,
-		<  1804800000 4>;
+		<   633600000 1>,
+		<   902400000 2>,
+		<  1094400000 3>,
+		<  1401600000 4>,
+		<  1555200000 5>,
+		<  1804800000 6>;
 	qcom,speed6-bin-v0-cci =
 		<          0 0>,
 		<  307200000 1>,
@@ -872,11 +887,13 @@
 		<  1804800000 7>;
 	qcom,speed2-bin-v0-c1 =
 		<          0 0>,
-		<  1094400000 1>,
-		<  1401600000 2>,
-		<  1555200000 3>,
-		<  1804800000 4>,
-		<  2016000000 5>;
+		<   633600000 1>,
+		<   902400000 2>,
+		<  1094400000 3>,
+		<  1401600000 4>,
+		<  1555200000 5>,
+		<  1804800000 6>,
+		<  2016000000 7>;
 	qcom,speed2-bin-v0-cci =
 		<          0 0>,
 		<  307200000 1>,
@@ -914,6 +931,8 @@
 			< 1804800 >;
 
 		qcom,cpufreq-table-4 =
+			<  633600 >,
+			<  902400 >,
 			< 1094400 >,
 			< 1401600 >,
 			< 1555200 >,
@@ -961,6 +980,8 @@
 				< 1536000 768000>,      /* NOM+  */
 				< 1670400 787200>;      /* TURBO */
 			cpu-to-dev-map-4 =
+				<  633600 307200>,      /* SVS   */
+				<  902400 403200>,
 				< 1094400 499200>,	/* SVS   */
 				< 1401600 691200>,      /* NOM   */
 				< 1555200 768000>,      /* NOM+  */
diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
index bd88087..da4d27d 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -143,7 +143,7 @@
 
 		cam_snapshot {
 			label = "cam_snapshot";
-			gpios = <&tlmm 91 0>;
+			gpios = <&tlmm 91 GPIO_ACTIVE_LOW>;
 			linux,input-type = <1>;
 			linux,code = <766>;
 			gpio-key,wakeup;
@@ -153,7 +153,7 @@
 
 		cam_focus {
 			label = "cam_focus";
-			gpios = <&tlmm 92 0>;
+			gpios = <&tlmm 92 GPIO_ACTIVE_HIGH>;
 			linux,input-type = <1>;
 			linux,code = <528>;
 			gpio-key,wakeup;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
index cc55127..dbc3651 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
@@ -14,7 +14,10 @@
 #include "sdm670-pmic-overlay.dtsi"
 #include "sdm670-sde-display.dtsi"
 #include "sdm670-camera-sensor-mtp.dtsi"
+
+&qupv3_se10_i2c {
 #include "smb1355.dtsi"
+};
 
 &ufsphy_mem {
 	compatible = "qcom,ufs-phy-qmp-v3";
@@ -202,7 +205,7 @@
 
 		cam_snapshot {
 			label = "cam_snapshot";
-			gpios = <&tlmm 91 0>;
+			gpios = <&tlmm 91 GPIO_ACTIVE_LOW>;
 			linux,input-type = <1>;
 			linux,code = <766>;
 			gpio-key,wakeup;
@@ -212,7 +215,7 @@
 
 		cam_focus {
 			label = "cam_focus";
-			gpios = <&tlmm 92 0>;
+			gpios = <&tlmm 92 GPIO_ACTIVE_HIGH>;
 			linux,input-type = <1>;
 			linux,code = <528>;
 			gpio-key,wakeup;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
index bdcd039..8ed821a 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
@@ -134,7 +134,9 @@
 				#size-cells = <0>;
 				qcom,psci-mode-shift = <0>;
 				qcom,psci-mode-mask = <0xf>;
-				qcom,disable-prediction;
+				qcom,ref-stddev = <100>;
+				qcom,tmr-add = <100>;
+				qcom,ref-premature-cnt = <3>;
 				qcom,cpu = <&CPU6 &CPU7>;
 
 				qcom,pm-cpu-level@0 { /* C1 */
diff --git a/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
index 43f1465..3b8b375 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
@@ -14,9 +14,12 @@
 #include "sdm670-camera-sensor-qrd.dtsi"
 #include "sdm670-pmic-overlay.dtsi"
 #include "sdm670-audio-overlay.dtsi"
-#include "smb1355.dtsi"
 #include "sdm670-sde-display.dtsi"
 
+&qupv3_se10_i2c {
+#include "smb1355.dtsi"
+};
+
 &qupv3_se9_2uart {
 	status = "disabled";
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 3ca33b2..4b39207 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -1096,7 +1096,7 @@
 
 	clock_debug: qcom,cc-debug {
 		compatible = "qcom,debugcc-sdm845";
-		qcom,cc-count = <5>;
+		qcom,cc-count = <6>;
 		qcom,gcc = <&clock_gcc>;
 		qcom,videocc = <&clock_videocc>;
 		qcom,camcc = <&clock_camcc>;
@@ -1389,7 +1389,7 @@
 		};
 	};
 
-	mem_dump {
+	mem_dump: mem_dump {
 		compatible = "qcom,mem-dump";
 		memory-region = <&dump_mem>;
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
index 9903d19..0c37bf1 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
@@ -36,6 +36,7 @@
 		qcom,dwc-usb3-msm-tx-fifo-size = <21288>;
 		qcom,num-gsi-evt-buffs = <0x3>;
 		qcom,use-pdc-interrupts;
+		qcom,pm-qos-latency = <44>;
 		extcon = <0>, <0>, <&eud>, <0>, <0>;
 
 		clocks = <&clock_gcc GCC_USB30_PRIM_MASTER_CLK>,
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
index 349c4c0..812a313 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
@@ -14,7 +14,10 @@
 #include "sdm845-pmic-overlay.dtsi"
 #include "sdm845-pinctrl-overlay.dtsi"
 #include "sdm845-camera-sensor-mtp.dtsi"
+
+&qupv3_se10_i2c {
 #include "smb1355.dtsi"
+};
 
 &vendor {
 	bluetooth: bt_wcn3990 {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index 6034b6d..f5a979c 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -13,9 +13,12 @@
 #include "sdm845-pmic-overlay.dtsi"
 #include "sdm845-pinctrl-overlay.dtsi"
 #include "sdm845-camera-sensor-qrd.dtsi"
-#include "smb1355.dtsi"
 #include <dt-bindings/gpio/gpio.h>
 
+&qupv3_se10_i2c {
+#include "smb1355.dtsi"
+};
+
 &vendor {
 	bluetooth: bt_wcn3990 {
 		compatible = "qca,wcn3990";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
index a5c6ab5..b2b0000 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
@@ -18,7 +18,10 @@
 
 #include "sdm845-pmic-overlay.dtsi"
 #include "sdm845-pinctrl-overlay.dtsi"
+
+&qupv3_se10_i2c {
 #include "smb1355.dtsi"
+};
 
 &vendor {
 	bluetooth: bt_wcn3990 {
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 22b4b90..e9a913f 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -1276,7 +1276,7 @@
 
 	clock_debug: qcom,cc-debug@100000 {
 		compatible = "qcom,debugcc-sdm845";
-		qcom,cc-count = <5>;
+		qcom,cc-count = <6>;
 		qcom,gcc = <&clock_gcc>;
 		qcom,videocc = <&clock_videocc>;
 		qcom,camcc = <&clock_camcc>;
diff --git a/arch/arm64/boot/dts/qcom/smb1355.dtsi b/arch/arm64/boot/dts/qcom/smb1355.dtsi
index 3412b25d..5939440 100644
--- a/arch/arm64/boot/dts/qcom/smb1355.dtsi
+++ b/arch/arm64/boot/dts/qcom/smb1355.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -12,98 +12,96 @@
 
 #include <dt-bindings/interrupt-controller/irq.h>
 
-&qupv3_se10_i2c {
-	smb1355_0: qcom,smb1355@8 {
-		compatible = "qcom,i2c-pmic";
-		reg = <0x8>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		interrupt-parent = <&spmi_bus>;
-		interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>;
-		interrupt_names = "smb1355_0";
-		interrupt-controller;
-		#interrupt-cells = <3>;
-		qcom,periph-map = <0x10 0x12 0x13 0x16>;
+smb1355_0: qcom,smb1355@8 {
+	compatible = "qcom,i2c-pmic";
+	reg = <0x8>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	interrupt-parent = <&spmi_bus>;
+	interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>;
+	interrupt_names = "smb1355_0";
+	interrupt-controller;
+	#interrupt-cells = <3>;
+	qcom,periph-map = <0x10 0x12 0x13 0x16>;
 
-		smb1355_revid_0: qcom,revid@100 {
-			compatible = "qcom,qpnp-revid";
-			reg = <0x100 0x100>;
-		};
-
-		smb1355_charger_0: qcom,smb1355-charger@1000 {
-			compatible = "qcom,smb1355";
-			qcom,pmic-revid = <&smb1355_revid_0>;
-			reg = <0x1000 0x700>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			interrupt-parent = <&smb1355_0>;
-			status = "disabled";
-
-			io-channels = <&pmi8998_rradc 2>,
-				      <&pmi8998_rradc 12>;
-			io-channel-names = "charger_temp",
-					   "charger_temp_max";
-
-			qcom,chgr@1000 {
-				reg = <0x1000 0x100>;
-				interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>;
-				interrupt-names = "chg-state-change";
-			};
-
-			qcom,chgr-misc@1600 {
-				reg = <0x1600 0x100>;
-				interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>,
-					     <0x16 0x6 IRQ_TYPE_EDGE_RISING>;
-				interrupt-names = "wdog-bark",
-						  "temperature-change";
-			};
-		};
+	smb1355_revid_0: qcom,revid@100 {
+		compatible = "qcom,qpnp-revid";
+		reg = <0x100 0x100>;
 	};
 
-	smb1355_1: qcom,smb1355@c {
-		compatible = "qcom,i2c-pmic";
-		reg = <0xc>;
+	smb1355_charger_0: qcom,smb1355-charger@1000 {
+		compatible = "qcom,smb1355";
+		qcom,pmic-revid = <&smb1355_revid_0>;
+		reg = <0x1000 0x700>;
 		#address-cells = <1>;
-		#size-cells = <0>;
-		interrupt-parent = <&spmi_bus>;
-		interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>;
-		interrupt_names = "smb1355_1";
-		interrupt-controller;
-		#interrupt-cells = <3>;
-		qcom,periph-map = <0x10 0x12 0x13 0x16>;
+		#size-cells = <1>;
+		interrupt-parent = <&smb1355_0>;
+		status = "disabled";
 
-		smb1355_revid_1: qcom,revid@100 {
-			compatible = "qcom,qpnp-revid";
-			reg = <0x100 0x100>;
+		io-channels = <&pmi8998_rradc 2>,
+			      <&pmi8998_rradc 12>;
+		io-channel-names = "charger_temp",
+				   "charger_temp_max";
+
+		qcom,chgr@1000 {
+			reg = <0x1000 0x100>;
+			interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "chg-state-change";
 		};
 
-		smb1355_charger_1: qcom,smb1355-charger@1000 {
-			compatible = "qcom,smb1355";
-			qcom,pmic-revid = <&smb1355_revid_1>;
-			reg = <0x1000 0x700>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			interrupt-parent = <&smb1355_1>;
-			status = "disabled";
+		qcom,chgr-misc@1600 {
+			reg = <0x1600 0x100>;
+			interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+				     <0x16 0x6 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "wdog-bark",
+					  "temperature-change";
+		};
+	};
+};
 
-			io-channels = <&pmi8998_rradc 2>,
-				      <&pmi8998_rradc 12>;
-			io-channel-names = "charger_temp",
-					   "charger_temp_max";
+smb1355_1: qcom,smb1355@c {
+	compatible = "qcom,i2c-pmic";
+	reg = <0xc>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	interrupt-parent = <&spmi_bus>;
+	interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>;
+	interrupt_names = "smb1355_1";
+	interrupt-controller;
+	#interrupt-cells = <3>;
+	qcom,periph-map = <0x10 0x12 0x13 0x16>;
 
-			qcom,chgr@1000 {
-				reg = <0x1000 0x100>;
-				interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>;
-				interrupt-names = "chg-state-change";
-			};
+	smb1355_revid_1: qcom,revid@100 {
+		compatible = "qcom,qpnp-revid";
+		reg = <0x100 0x100>;
+	};
 
-			qcom,chgr-misc@1600 {
-				reg = <0x1600 0x100>;
-				interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>,
-					     <0x16 0x6 IRQ_TYPE_EDGE_RISING>;
-				interrupt-names = "wdog-bark",
-						  "temperature-change";
-			};
+	smb1355_charger_1: qcom,smb1355-charger@1000 {
+		compatible = "qcom,smb1355";
+		qcom,pmic-revid = <&smb1355_revid_1>;
+		reg = <0x1000 0x700>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		interrupt-parent = <&smb1355_1>;
+		status = "disabled";
+
+		io-channels = <&pmi8998_rradc 2>,
+			      <&pmi8998_rradc 12>;
+		io-channel-names = "charger_temp",
+				   "charger_temp_max";
+
+		qcom,chgr@1000 {
+			reg = <0x1000 0x100>;
+			interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "chg-state-change";
+		};
+
+		qcom,chgr-misc@1600 {
+			reg = <0x1600 0x100>;
+			interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+				     <0x16 0x6 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "wdog-bark",
+					  "temperature-change";
 		};
 	};
 };
diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig
index 4c6b6a1..11eb070 100644
--- a/arch/arm64/configs/msm8937-perf_defconfig
+++ b/arch/arm64/configs/msm8937-perf_defconfig
@@ -18,7 +18,6 @@
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
 CONFIG_CGROUP_FREEZER=y
-CONFIG_CPUSETS=y
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_CGROUP_SCHEDTUNE=y
 CONFIG_RT_GROUP_SCHED=y
@@ -68,7 +67,6 @@
 CONFIG_ZSMALLOC=y
 CONFIG_PROCESS_RECLAIM=y
 CONFIG_SECCOMP=y
-CONFIG_HARDEN_BRANCH_PREDICTOR=y
 CONFIG_ARMV8_DEPRECATED=y
 CONFIG_SWP_EMULATION=y
 CONFIG_CP15_BARRIER_EMULATION=y
@@ -148,6 +146,7 @@
 CONFIG_NETFILTER_XT_TARGET_TRACE=y
 CONFIG_NETFILTER_XT_TARGET_SECMARK=y
 CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_BPF=y
 CONFIG_NETFILTER_XT_MATCH_COMMENT=y
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
@@ -224,6 +223,8 @@
 CONFIG_RMNET_DATA_FC=y
 CONFIG_RMNET_DATA_DEBUG_PKT=y
 CONFIG_BT=y
+# CONFIG_BT_BREDR is not set
+# CONFIG_BT_LE is not set
 CONFIG_MSM_BT_POWER=y
 CONFIG_CFG80211=y
 CONFIG_CFG80211_INTERNAL_REGDB=y
@@ -242,7 +243,6 @@
 CONFIG_HDCP_QSEECOM=y
 CONFIG_QSEECOM=y
 CONFIG_UID_SYS_STATS=y
-CONFIG_MEMORY_STATE_TIME=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_SG=y
@@ -254,10 +254,8 @@
 CONFIG_SCSI_UFSHCD_PLATFORM=y
 CONFIG_SCSI_UFS_QCOM=y
 CONFIG_SCSI_UFS_QCOM_ICE=y
-CONFIG_SCSI_UFSHCD_CMD_LOGGING=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_DM=y
-CONFIG_DM_DEBUG=y
 CONFIG_DM_CRYPT=y
 CONFIG_DM_REQ_CRYPT=y
 CONFIG_DM_UEVENT=y
@@ -341,12 +339,12 @@
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_QPNP_PIN=y
-CONFIG_GPIO_QPNP_PIN_DEBUG=y
 CONFIG_POWER_RESET_QCOM=y
 CONFIG_QCOM_DLOAD_MODE=y
 CONFIG_POWER_RESET_SYSCON=y
 CONFIG_QPNP_FG=y
 CONFIG_SMB135X_CHARGER=y
+CONFIG_SMB1355_SLAVE_CHARGER=y
 CONFIG_SMB1351_USB_CHARGER=y
 CONFIG_QPNP_SMB5=y
 CONFIG_QPNP_SMBCHARGER=y
@@ -368,6 +366,7 @@
 CONFIG_REGULATOR_COOLING_DEVICE=y
 CONFIG_QTI_BCL_PMIC5=y
 CONFIG_QTI_BCL_SOC_DRIVER=y
+CONFIG_MFD_I2C_PMIC=y
 CONFIG_MFD_SPMI_PMIC=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -414,7 +413,6 @@
 CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y
 CONFIG_MSMB_JPEG=y
 CONFIG_MSM_FD=y
-CONFIG_MSM_JPEGDMA=y
 CONFIG_MSM_VIDC_3X_V4L2=y
 CONFIG_MSM_VIDC_3X_GOVERNORS=y
 CONFIG_MSM_SDE_ROTATOR=y
@@ -428,7 +426,7 @@
 CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
 CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_DYNAMIC_MINORS=y
@@ -489,11 +487,12 @@
 CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
+# CONFIG_PWRSEQ_EMMC is not set
+# CONFIG_PWRSEQ_SIMPLE is not set
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_CLKGATE=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
-CONFIG_MMC_TEST=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_SDHCI_MSM=y
@@ -578,6 +577,7 @@
 CONFIG_QCOM_DEVFREQ_DEVBW=y
 CONFIG_SPDM_SCM=y
 CONFIG_DEVFREQ_SPDM=y
+CONFIG_IIO=y
 CONFIG_PWM=y
 CONFIG_PWM_QPNP=y
 CONFIG_PWM_QTI_LPG=y
@@ -589,6 +589,8 @@
 CONFIG_MSM_TZ_LOG=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_SECURITY=y
+CONFIG_F2FS_FS=y
+CONFIG_F2FS_FS_SECURITY=y
 CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 CONFIG_QFMT_V2=y
@@ -596,8 +598,6 @@
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_ECRYPT_FS=y
-CONFIG_ECRYPT_FS_MESSAGING=y
 CONFIG_SDCARD_FS=y
 # CONFIG_NETWORK_FILESYSTEMS is not set
 CONFIG_NLS_CODEPAGE_437=y
diff --git a/arch/arm64/configs/msm8937_defconfig b/arch/arm64/configs/msm8937_defconfig
index 11bd200..3b73b06c 100644
--- a/arch/arm64/configs/msm8937_defconfig
+++ b/arch/arm64/configs/msm8937_defconfig
@@ -19,7 +19,6 @@
 CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
 CONFIG_CGROUP_DEBUG=y
 CONFIG_CGROUP_FREEZER=y
-CONFIG_CPUSETS=y
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_CGROUP_SCHEDTUNE=y
 CONFIG_RT_GROUP_SCHED=y
@@ -71,7 +70,6 @@
 CONFIG_ZSMALLOC=y
 CONFIG_PROCESS_RECLAIM=y
 CONFIG_SECCOMP=y
-CONFIG_HARDEN_BRANCH_PREDICTOR=y
 CONFIG_ARMV8_DEPRECATED=y
 CONFIG_SWP_EMULATION=y
 CONFIG_CP15_BARRIER_EMULATION=y
@@ -152,6 +150,7 @@
 CONFIG_NETFILTER_XT_TARGET_TRACE=y
 CONFIG_NETFILTER_XT_TARGET_SECMARK=y
 CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_BPF=y
 CONFIG_NETFILTER_XT_MATCH_COMMENT=y
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
@@ -230,6 +229,8 @@
 CONFIG_RMNET_DATA_FC=y
 CONFIG_RMNET_DATA_DEBUG_PKT=y
 CONFIG_BT=y
+# CONFIG_BT_BREDR is not set
+# CONFIG_BT_LE is not set
 CONFIG_MSM_BT_POWER=y
 CONFIG_CFG80211=y
 CONFIG_CFG80211_INTERNAL_REGDB=y
@@ -248,7 +249,6 @@
 CONFIG_HDCP_QSEECOM=y
 CONFIG_QSEECOM=y
 CONFIG_UID_SYS_STATS=y
-CONFIG_MEMORY_STATE_TIME=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_SG=y
@@ -260,10 +260,8 @@
 CONFIG_SCSI_UFSHCD_PLATFORM=y
 CONFIG_SCSI_UFS_QCOM=y
 CONFIG_SCSI_UFS_QCOM_ICE=y
-CONFIG_SCSI_UFSHCD_CMD_LOGGING=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_DM=y
-CONFIG_DM_DEBUG=y
 CONFIG_DM_CRYPT=y
 CONFIG_DM_REQ_CRYPT=y
 CONFIG_DM_UEVENT=y
@@ -349,12 +347,12 @@
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_QPNP_PIN=y
-CONFIG_GPIO_QPNP_PIN_DEBUG=y
 CONFIG_POWER_RESET_QCOM=y
 CONFIG_QCOM_DLOAD_MODE=y
 CONFIG_POWER_RESET_SYSCON=y
 CONFIG_QPNP_FG=y
 CONFIG_SMB135X_CHARGER=y
+CONFIG_SMB1355_SLAVE_CHARGER=y
 CONFIG_SMB1351_USB_CHARGER=y
 CONFIG_QPNP_SMB5=y
 CONFIG_QPNP_SMBCHARGER=y
@@ -376,6 +374,7 @@
 CONFIG_REGULATOR_COOLING_DEVICE=y
 CONFIG_QTI_BCL_PMIC5=y
 CONFIG_QTI_BCL_SOC_DRIVER=y
+CONFIG_MFD_I2C_PMIC=y
 CONFIG_MFD_SPMI_PMIC=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -422,7 +421,6 @@
 CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y
 CONFIG_MSMB_JPEG=y
 CONFIG_MSM_FD=y
-CONFIG_MSM_JPEGDMA=y
 CONFIG_MSM_VIDC_3X_V4L2=y
 CONFIG_MSM_VIDC_3X_GOVERNORS=y
 CONFIG_MSM_SDE_ROTATOR=y
@@ -437,7 +435,7 @@
 CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
 CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_DYNAMIC_MINORS=y
@@ -498,12 +496,13 @@
 CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
+# CONFIG_PWRSEQ_EMMC is not set
+# CONFIG_PWRSEQ_SIMPLE is not set
 CONFIG_MMC_RING_BUFFER=y
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_CLKGATE=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
-CONFIG_MMC_TEST=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_SDHCI_MSM=y
@@ -596,6 +595,7 @@
 CONFIG_QCOM_DEVFREQ_DEVBW=y
 CONFIG_SPDM_SCM=y
 CONFIG_DEVFREQ_SPDM=y
+CONFIG_IIO=y
 CONFIG_PWM=y
 CONFIG_PWM_QPNP=y
 CONFIG_PWM_QTI_LPG=y
@@ -607,6 +607,8 @@
 CONFIG_MSM_TZ_LOG=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_SECURITY=y
+CONFIG_F2FS_FS=y
+CONFIG_F2FS_FS_SECURITY=y
 CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 CONFIG_QFMT_V2=y
@@ -615,8 +617,6 @@
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_ECRYPT_FS=y
-CONFIG_ECRYPT_FS_MESSAGING=y
 CONFIG_SDCARD_FS=y
 # CONFIG_NETWORK_FILESYSTEMS is not set
 CONFIG_NLS_CODEPAGE_437=y
diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig
index 7d64ca7..f0ced73 100644
--- a/arch/arm64/configs/msm8953-perf_defconfig
+++ b/arch/arm64/configs/msm8953-perf_defconfig
@@ -67,6 +67,7 @@
 CONFIG_PROCESS_RECLAIM=y
 CONFIG_SECCOMP=y
 CONFIG_HARDEN_BRANCH_PREDICTOR=y
+CONFIG_PSCI_BP_HARDENING=y
 CONFIG_ARMV8_DEPRECATED=y
 CONFIG_SWP_EMULATION=y
 CONFIG_CP15_BARRIER_EMULATION=y
@@ -344,6 +345,7 @@
 CONFIG_POWER_RESET_SYSCON=y
 CONFIG_QPNP_FG=y
 CONFIG_SMB135X_CHARGER=y
+CONFIG_SMB1355_SLAVE_CHARGER=y
 CONFIG_SMB1351_USB_CHARGER=y
 CONFIG_QPNP_SMB5=y
 CONFIG_QPNP_SMBCHARGER=y
@@ -365,6 +367,7 @@
 CONFIG_REGULATOR_COOLING_DEVICE=y
 CONFIG_QTI_BCL_PMIC5=y
 CONFIG_QTI_BCL_SOC_DRIVER=y
+CONFIG_MFD_I2C_PMIC=y
 CONFIG_MFD_SPMI_PMIC=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -584,6 +587,7 @@
 CONFIG_QCOM_DEVFREQ_DEVBW=y
 CONFIG_SPDM_SCM=y
 CONFIG_DEVFREQ_SPDM=y
+CONFIG_IIO=y
 CONFIG_PWM=y
 CONFIG_PWM_QPNP=y
 CONFIG_PWM_QTI_LPG=y
diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig
index de329bd..733ac69 100644
--- a/arch/arm64/configs/msm8953_defconfig
+++ b/arch/arm64/configs/msm8953_defconfig
@@ -70,6 +70,7 @@
 CONFIG_PROCESS_RECLAIM=y
 CONFIG_SECCOMP=y
 CONFIG_HARDEN_BRANCH_PREDICTOR=y
+CONFIG_PSCI_BP_HARDENING=y
 CONFIG_ARMV8_DEPRECATED=y
 CONFIG_SWP_EMULATION=y
 CONFIG_CP15_BARRIER_EMULATION=y
@@ -353,6 +354,7 @@
 CONFIG_POWER_RESET_SYSCON=y
 CONFIG_QPNP_FG=y
 CONFIG_SMB135X_CHARGER=y
+CONFIG_SMB1355_SLAVE_CHARGER=y
 CONFIG_SMB1351_USB_CHARGER=y
 CONFIG_QPNP_SMB5=y
 CONFIG_QPNP_SMBCHARGER=y
@@ -374,6 +376,7 @@
 CONFIG_REGULATOR_COOLING_DEVICE=y
 CONFIG_QTI_BCL_PMIC5=y
 CONFIG_QTI_BCL_SOC_DRIVER=y
+CONFIG_MFD_I2C_PMIC=y
 CONFIG_MFD_SPMI_PMIC=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -604,6 +607,7 @@
 CONFIG_QCOM_DEVFREQ_DEVBW=y
 CONFIG_SPDM_SCM=y
 CONFIG_DEVFREQ_SPDM=y
+CONFIG_IIO=y
 CONFIG_PWM=y
 CONFIG_PWM_QPNP=y
 CONFIG_PWM_QTI_LPG=y
diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig
index 93f7621..8e7c369 100644
--- a/arch/arm64/configs/sdm670-perf_defconfig
+++ b/arch/arm64/configs/sdm670-perf_defconfig
@@ -67,6 +67,7 @@
 CONFIG_PROCESS_RECLAIM=y
 CONFIG_SECCOMP=y
 CONFIG_HARDEN_BRANCH_PREDICTOR=y
+CONFIG_PSCI_BP_HARDENING=y
 CONFIG_ARMV8_DEPRECATED=y
 CONFIG_SWP_EMULATION=y
 CONFIG_CP15_BARRIER_EMULATION=y
@@ -238,6 +239,7 @@
 CONFIG_IPC_ROUTER=y
 CONFIG_IPC_ROUTER_SECURITY=y
 CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_AQT_REGMAP=y
 CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y
 CONFIG_DMA_CMA=y
 CONFIG_ZRAM=y
@@ -286,6 +288,7 @@
 CONFIG_PPPOPNS=y
 CONFIG_PPP_ASYNC=y
 CONFIG_PPP_SYNC_TTY=y
+CONFIG_USB_LAN78XX=y
 CONFIG_USB_USBNET=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
 CONFIG_CLD_LL_CORE=y
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index 3e8d865..5fb8fdb 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -72,6 +72,7 @@
 CONFIG_PROCESS_RECLAIM=y
 CONFIG_SECCOMP=y
 CONFIG_HARDEN_BRANCH_PREDICTOR=y
+CONFIG_PSCI_BP_HARDENING=y
 CONFIG_ARMV8_DEPRECATED=y
 CONFIG_SWP_EMULATION=y
 CONFIG_CP15_BARRIER_EMULATION=y
@@ -293,6 +294,7 @@
 CONFIG_PPPOPNS=y
 CONFIG_PPP_ASYNC=y
 CONFIG_PPP_SYNC_TTY=y
+CONFIG_USB_LAN78XX=y
 CONFIG_USB_USBNET=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
 CONFIG_CLD_LL_CORE=y
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index 55f45ae..fe5b5b5 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -65,6 +65,7 @@
 CONFIG_BALANCE_ANON_FILE_RECLAIM=y
 CONFIG_SECCOMP=y
 CONFIG_HARDEN_BRANCH_PREDICTOR=y
+CONFIG_PSCI_BP_HARDENING=y
 CONFIG_ARMV8_DEPRECATED=y
 CONFIG_SWP_EMULATION=y
 CONFIG_CP15_BARRIER_EMULATION=y
@@ -568,9 +569,7 @@
 CONFIG_ANDROID_BINDER_IPC=y
 CONFIG_SENSORS_SSC=y
 CONFIG_MSM_TZ_LOG=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_SECURITY=y
 CONFIG_EXT4_ENCRYPTION=y
 CONFIG_F2FS_FS=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index b890dee..666f350 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -69,6 +69,7 @@
 CONFIG_BALANCE_ANON_FILE_RECLAIM=y
 CONFIG_SECCOMP=y
 CONFIG_HARDEN_BRANCH_PREDICTOR=y
+CONFIG_PSCI_BP_HARDENING=y
 CONFIG_ARMV8_DEPRECATED=y
 CONFIG_SWP_EMULATION=y
 CONFIG_CP15_BARRIER_EMULATION=y
@@ -589,9 +590,7 @@
 CONFIG_ANDROID_BINDER_IPC=y
 CONFIG_SENSORS_SSC=y
 CONFIG_MSM_TZ_LOG=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_SECURITY=y
 CONFIG_EXT4_ENCRYPTION=y
 CONFIG_F2FS_FS=y
diff --git a/arch/arm64/crypto/sha256-core.S b/arch/arm64/crypto/sha256-core.S
new file mode 100644
index 0000000..3ce82cc
--- /dev/null
+++ b/arch/arm64/crypto/sha256-core.S
@@ -0,0 +1,2061 @@
+// Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
+//
+// Licensed under the OpenSSL license (the "License").  You may not use
+// this file except in compliance with the License.  You can obtain a copy
+// in the file LICENSE in the source distribution or at
+// https://www.openssl.org/source/license.html
+
+// ====================================================================
+// Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+// project. The module is, however, dual licensed under OpenSSL and
+// CRYPTOGAMS licenses depending on where you obtain it. For further
+// details see http://www.openssl.org/~appro/cryptogams/.
+//
+// Permission to use under GPLv2 terms is granted.
+// ====================================================================
+//
+// SHA256/512 for ARMv8.
+//
+// Performance in cycles per processed byte and improvement coefficient
+// over code generated with "default" compiler:
+//
+//		SHA256-hw	SHA256(*)	SHA512
+// Apple A7	1.97		10.5 (+33%)	6.73 (-1%(**))
+// Cortex-A53	2.38		15.5 (+115%)	10.0 (+150%(***))
+// Cortex-A57	2.31		11.6 (+86%)	7.51 (+260%(***))
+// Denver	2.01		10.5 (+26%)	6.70 (+8%)
+// X-Gene			20.0 (+100%)	12.8 (+300%(***))
+// Mongoose	2.36		13.0 (+50%)	8.36 (+33%)
+//
+// (*)	Software SHA256 results are of lesser relevance, presented
+//	mostly for informational purposes.
+// (**)	The result is a trade-off: it's possible to improve it by
+//	10% (or by 1 cycle per round), but at the cost of 20% loss
+//	on Cortex-A53 (or by 4 cycles per round).
+// (***)	Super-impressive coefficients over gcc-generated code are
+//	indication of some compiler "pathology", most notably code
+//	generated with -mgeneral-regs-only is significanty faster
+//	and the gap is only 40-90%.
+//
+// October 2016.
+//
+// Originally it was reckoned that it makes no sense to implement NEON
+// version of SHA256 for 64-bit processors. This is because performance
+// improvement on most wide-spread Cortex-A5x processors was observed
+// to be marginal, same on Cortex-A53 and ~10% on A57. But then it was
+// observed that 32-bit NEON SHA256 performs significantly better than
+// 64-bit scalar version on *some* of the more recent processors. As
+// result 64-bit NEON version of SHA256 was added to provide best
+// all-round performance. For example it executes ~30% faster on X-Gene
+// and Mongoose. [For reference, NEON version of SHA512 is bound to
+// deliver much less improvement, likely *negative* on Cortex-A5x.
+// Which is why NEON support is limited to SHA256.]
+
+#ifndef	__KERNEL__
+# include "arm_arch.h"
+#endif
+
+.text
+
+.extern	OPENSSL_armcap_P
+.globl	sha256_block_data_order
+.type	sha256_block_data_order,%function
+.align	6
+sha256_block_data_order:
+#ifndef	__KERNEL__
+# ifdef	__ILP32__
+	ldrsw	x16,.LOPENSSL_armcap_P
+# else
+	ldr	x16,.LOPENSSL_armcap_P
+# endif
+	adr	x17,.LOPENSSL_armcap_P
+	add	x16,x16,x17
+	ldr	w16,[x16]
+	tst	w16,#ARMV8_SHA256
+	b.ne	.Lv8_entry
+	tst	w16,#ARMV7_NEON
+	b.ne	.Lneon_entry
+#endif
+	stp	x29,x30,[sp,#-128]!
+	add	x29,sp,#0
+
+	stp	x19,x20,[sp,#16]
+	stp	x21,x22,[sp,#32]
+	stp	x23,x24,[sp,#48]
+	stp	x25,x26,[sp,#64]
+	stp	x27,x28,[sp,#80]
+	sub	sp,sp,#4*4
+
+	ldp	w20,w21,[x0]				// load context
+	ldp	w22,w23,[x0,#2*4]
+	ldp	w24,w25,[x0,#4*4]
+	add	x2,x1,x2,lsl#6	// end of input
+	ldp	w26,w27,[x0,#6*4]
+	adr	x30,.LK256
+	stp	x0,x2,[x29,#96]
+
+.Loop:
+	ldp	w3,w4,[x1],#2*4
+	ldr	w19,[x30],#4			// *K++
+	eor	w28,w21,w22				// magic seed
+	str	x1,[x29,#112]
+#ifndef	__AARCH64EB__
+	rev	w3,w3			// 0
+#endif
+	ror	w16,w24,#6
+	add	w27,w27,w19			// h+=K[i]
+	eor	w6,w24,w24,ror#14
+	and	w17,w25,w24
+	bic	w19,w26,w24
+	add	w27,w27,w3			// h+=X[i]
+	orr	w17,w17,w19			// Ch(e,f,g)
+	eor	w19,w20,w21			// a^b, b^c in next round
+	eor	w16,w16,w6,ror#11	// Sigma1(e)
+	ror	w6,w20,#2
+	add	w27,w27,w17			// h+=Ch(e,f,g)
+	eor	w17,w20,w20,ror#9
+	add	w27,w27,w16			// h+=Sigma1(e)
+	and	w28,w28,w19			// (b^c)&=(a^b)
+	add	w23,w23,w27			// d+=h
+	eor	w28,w28,w21			// Maj(a,b,c)
+	eor	w17,w6,w17,ror#13	// Sigma0(a)
+	add	w27,w27,w28			// h+=Maj(a,b,c)
+	ldr	w28,[x30],#4		// *K++, w19 in next round
+	//add	w27,w27,w17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	w4,w4			// 1
+#endif
+	ldp	w5,w6,[x1],#2*4
+	add	w27,w27,w17			// h+=Sigma0(a)
+	ror	w16,w23,#6
+	add	w26,w26,w28			// h+=K[i]
+	eor	w7,w23,w23,ror#14
+	and	w17,w24,w23
+	bic	w28,w25,w23
+	add	w26,w26,w4			// h+=X[i]
+	orr	w17,w17,w28			// Ch(e,f,g)
+	eor	w28,w27,w20			// a^b, b^c in next round
+	eor	w16,w16,w7,ror#11	// Sigma1(e)
+	ror	w7,w27,#2
+	add	w26,w26,w17			// h+=Ch(e,f,g)
+	eor	w17,w27,w27,ror#9
+	add	w26,w26,w16			// h+=Sigma1(e)
+	and	w19,w19,w28			// (b^c)&=(a^b)
+	add	w22,w22,w26			// d+=h
+	eor	w19,w19,w20			// Maj(a,b,c)
+	eor	w17,w7,w17,ror#13	// Sigma0(a)
+	add	w26,w26,w19			// h+=Maj(a,b,c)
+	ldr	w19,[x30],#4		// *K++, w28 in next round
+	//add	w26,w26,w17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	w5,w5			// 2
+#endif
+	add	w26,w26,w17			// h+=Sigma0(a)
+	ror	w16,w22,#6
+	add	w25,w25,w19			// h+=K[i]
+	eor	w8,w22,w22,ror#14
+	and	w17,w23,w22
+	bic	w19,w24,w22
+	add	w25,w25,w5			// h+=X[i]
+	orr	w17,w17,w19			// Ch(e,f,g)
+	eor	w19,w26,w27			// a^b, b^c in next round
+	eor	w16,w16,w8,ror#11	// Sigma1(e)
+	ror	w8,w26,#2
+	add	w25,w25,w17			// h+=Ch(e,f,g)
+	eor	w17,w26,w26,ror#9
+	add	w25,w25,w16			// h+=Sigma1(e)
+	and	w28,w28,w19			// (b^c)&=(a^b)
+	add	w21,w21,w25			// d+=h
+	eor	w28,w28,w27			// Maj(a,b,c)
+	eor	w17,w8,w17,ror#13	// Sigma0(a)
+	add	w25,w25,w28			// h+=Maj(a,b,c)
+	ldr	w28,[x30],#4		// *K++, w19 in next round
+	//add	w25,w25,w17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	w6,w6			// 3
+#endif
+	ldp	w7,w8,[x1],#2*4
+	add	w25,w25,w17			// h+=Sigma0(a)
+	ror	w16,w21,#6
+	add	w24,w24,w28			// h+=K[i]
+	eor	w9,w21,w21,ror#14
+	and	w17,w22,w21
+	bic	w28,w23,w21
+	add	w24,w24,w6			// h+=X[i]
+	orr	w17,w17,w28			// Ch(e,f,g)
+	eor	w28,w25,w26			// a^b, b^c in next round
+	eor	w16,w16,w9,ror#11	// Sigma1(e)
+	ror	w9,w25,#2
+	add	w24,w24,w17			// h+=Ch(e,f,g)
+	eor	w17,w25,w25,ror#9
+	add	w24,w24,w16			// h+=Sigma1(e)
+	and	w19,w19,w28			// (b^c)&=(a^b)
+	add	w20,w20,w24			// d+=h
+	eor	w19,w19,w26			// Maj(a,b,c)
+	eor	w17,w9,w17,ror#13	// Sigma0(a)
+	add	w24,w24,w19			// h+=Maj(a,b,c)
+	ldr	w19,[x30],#4		// *K++, w28 in next round
+	//add	w24,w24,w17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	w7,w7			// 4
+#endif
+	add	w24,w24,w17			// h+=Sigma0(a)
+	ror	w16,w20,#6
+	add	w23,w23,w19			// h+=K[i]
+	eor	w10,w20,w20,ror#14
+	and	w17,w21,w20
+	bic	w19,w22,w20
+	add	w23,w23,w7			// h+=X[i]
+	orr	w17,w17,w19			// Ch(e,f,g)
+	eor	w19,w24,w25			// a^b, b^c in next round
+	eor	w16,w16,w10,ror#11	// Sigma1(e)
+	ror	w10,w24,#2
+	add	w23,w23,w17			// h+=Ch(e,f,g)
+	eor	w17,w24,w24,ror#9
+	add	w23,w23,w16			// h+=Sigma1(e)
+	and	w28,w28,w19			// (b^c)&=(a^b)
+	add	w27,w27,w23			// d+=h
+	eor	w28,w28,w25			// Maj(a,b,c)
+	eor	w17,w10,w17,ror#13	// Sigma0(a)
+	add	w23,w23,w28			// h+=Maj(a,b,c)
+	ldr	w28,[x30],#4		// *K++, w19 in next round
+	//add	w23,w23,w17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	w8,w8			// 5
+#endif
+	ldp	w9,w10,[x1],#2*4
+	add	w23,w23,w17			// h+=Sigma0(a)
+	ror	w16,w27,#6
+	add	w22,w22,w28			// h+=K[i]
+	eor	w11,w27,w27,ror#14
+	and	w17,w20,w27
+	bic	w28,w21,w27
+	add	w22,w22,w8			// h+=X[i]
+	orr	w17,w17,w28			// Ch(e,f,g)
+	eor	w28,w23,w24			// a^b, b^c in next round
+	eor	w16,w16,w11,ror#11	// Sigma1(e)
+	ror	w11,w23,#2
+	add	w22,w22,w17			// h+=Ch(e,f,g)
+	eor	w17,w23,w23,ror#9
+	add	w22,w22,w16			// h+=Sigma1(e)
+	and	w19,w19,w28			// (b^c)&=(a^b)
+	add	w26,w26,w22			// d+=h
+	eor	w19,w19,w24			// Maj(a,b,c)
+	eor	w17,w11,w17,ror#13	// Sigma0(a)
+	add	w22,w22,w19			// h+=Maj(a,b,c)
+	ldr	w19,[x30],#4		// *K++, w28 in next round
+	//add	w22,w22,w17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	w9,w9			// 6
+#endif
+	add	w22,w22,w17			// h+=Sigma0(a)
+	ror	w16,w26,#6
+	add	w21,w21,w19			// h+=K[i]
+	eor	w12,w26,w26,ror#14
+	and	w17,w27,w26
+	bic	w19,w20,w26
+	add	w21,w21,w9			// h+=X[i]
+	orr	w17,w17,w19			// Ch(e,f,g)
+	eor	w19,w22,w23			// a^b, b^c in next round
+	eor	w16,w16,w12,ror#11	// Sigma1(e)
+	ror	w12,w22,#2
+	add	w21,w21,w17			// h+=Ch(e,f,g)
+	eor	w17,w22,w22,ror#9
+	add	w21,w21,w16			// h+=Sigma1(e)
+	and	w28,w28,w19			// (b^c)&=(a^b)
+	add	w25,w25,w21			// d+=h
+	eor	w28,w28,w23			// Maj(a,b,c)
+	eor	w17,w12,w17,ror#13	// Sigma0(a)
+	add	w21,w21,w28			// h+=Maj(a,b,c)
+	ldr	w28,[x30],#4		// *K++, w19 in next round
+	//add	w21,w21,w17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	w10,w10			// 7
+#endif
+	ldp	w11,w12,[x1],#2*4
+	add	w21,w21,w17			// h+=Sigma0(a)
+	ror	w16,w25,#6
+	add	w20,w20,w28			// h+=K[i]
+	eor	w13,w25,w25,ror#14
+	and	w17,w26,w25
+	bic	w28,w27,w25
+	add	w20,w20,w10			// h+=X[i]
+	orr	w17,w17,w28			// Ch(e,f,g)
+	eor	w28,w21,w22			// a^b, b^c in next round
+	eor	w16,w16,w13,ror#11	// Sigma1(e)
+	ror	w13,w21,#2
+	add	w20,w20,w17			// h+=Ch(e,f,g)
+	eor	w17,w21,w21,ror#9
+	add	w20,w20,w16			// h+=Sigma1(e)
+	and	w19,w19,w28			// (b^c)&=(a^b)
+	add	w24,w24,w20			// d+=h
+	eor	w19,w19,w22			// Maj(a,b,c)
+	eor	w17,w13,w17,ror#13	// Sigma0(a)
+	add	w20,w20,w19			// h+=Maj(a,b,c)
+	ldr	w19,[x30],#4		// *K++, w28 in next round
+	//add	w20,w20,w17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	w11,w11			// 8
+#endif
+	add	w20,w20,w17			// h+=Sigma0(a)
+	ror	w16,w24,#6
+	add	w27,w27,w19			// h+=K[i]
+	eor	w14,w24,w24,ror#14
+	and	w17,w25,w24
+	bic	w19,w26,w24
+	add	w27,w27,w11			// h+=X[i]
+	orr	w17,w17,w19			// Ch(e,f,g)
+	eor	w19,w20,w21			// a^b, b^c in next round
+	eor	w16,w16,w14,ror#11	// Sigma1(e)
+	ror	w14,w20,#2
+	add	w27,w27,w17			// h+=Ch(e,f,g)
+	eor	w17,w20,w20,ror#9
+	add	w27,w27,w16			// h+=Sigma1(e)
+	and	w28,w28,w19			// (b^c)&=(a^b)
+	add	w23,w23,w27			// d+=h
+	eor	w28,w28,w21			// Maj(a,b,c)
+	eor	w17,w14,w17,ror#13	// Sigma0(a)
+	add	w27,w27,w28			// h+=Maj(a,b,c)
+	ldr	w28,[x30],#4		// *K++, w19 in next round
+	//add	w27,w27,w17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	w12,w12			// 9
+#endif
+	ldp	w13,w14,[x1],#2*4
+	add	w27,w27,w17			// h+=Sigma0(a)
+	ror	w16,w23,#6
+	add	w26,w26,w28			// h+=K[i]
+	eor	w15,w23,w23,ror#14
+	and	w17,w24,w23
+	bic	w28,w25,w23
+	add	w26,w26,w12			// h+=X[i]
+	orr	w17,w17,w28			// Ch(e,f,g)
+	eor	w28,w27,w20			// a^b, b^c in next round
+	eor	w16,w16,w15,ror#11	// Sigma1(e)
+	ror	w15,w27,#2
+	add	w26,w26,w17			// h+=Ch(e,f,g)
+	eor	w17,w27,w27,ror#9
+	add	w26,w26,w16			// h+=Sigma1(e)
+	and	w19,w19,w28			// (b^c)&=(a^b)
+	add	w22,w22,w26			// d+=h
+	eor	w19,w19,w20			// Maj(a,b,c)
+	eor	w17,w15,w17,ror#13	// Sigma0(a)
+	add	w26,w26,w19			// h+=Maj(a,b,c)
+	ldr	w19,[x30],#4		// *K++, w28 in next round
+	//add	w26,w26,w17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	w13,w13			// 10
+#endif
+	add	w26,w26,w17			// h+=Sigma0(a)
+	ror	w16,w22,#6
+	add	w25,w25,w19			// h+=K[i]
+	eor	w0,w22,w22,ror#14
+	and	w17,w23,w22
+	bic	w19,w24,w22
+	add	w25,w25,w13			// h+=X[i]
+	orr	w17,w17,w19			// Ch(e,f,g)
+	eor	w19,w26,w27			// a^b, b^c in next round
+	eor	w16,w16,w0,ror#11	// Sigma1(e)
+	ror	w0,w26,#2
+	add	w25,w25,w17			// h+=Ch(e,f,g)
+	eor	w17,w26,w26,ror#9
+	add	w25,w25,w16			// h+=Sigma1(e)
+	and	w28,w28,w19			// (b^c)&=(a^b)
+	add	w21,w21,w25			// d+=h
+	eor	w28,w28,w27			// Maj(a,b,c)
+	eor	w17,w0,w17,ror#13	// Sigma0(a)
+	add	w25,w25,w28			// h+=Maj(a,b,c)
+	ldr	w28,[x30],#4		// *K++, w19 in next round
+	//add	w25,w25,w17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	w14,w14			// 11
+#endif
+	ldp	w15,w0,[x1],#2*4
+	add	w25,w25,w17			// h+=Sigma0(a)
+	str	w6,[sp,#12]
+	ror	w16,w21,#6
+	add	w24,w24,w28			// h+=K[i]
+	eor	w6,w21,w21,ror#14
+	and	w17,w22,w21
+	bic	w28,w23,w21
+	add	w24,w24,w14			// h+=X[i]
+	orr	w17,w17,w28			// Ch(e,f,g)
+	eor	w28,w25,w26			// a^b, b^c in next round
+	eor	w16,w16,w6,ror#11	// Sigma1(e)
+	ror	w6,w25,#2
+	add	w24,w24,w17			// h+=Ch(e,f,g)
+	eor	w17,w25,w25,ror#9
+	add	w24,w24,w16			// h+=Sigma1(e)
+	and	w19,w19,w28			// (b^c)&=(a^b)
+	add	w20,w20,w24			// d+=h
+	eor	w19,w19,w26			// Maj(a,b,c)
+	eor	w17,w6,w17,ror#13	// Sigma0(a)
+	add	w24,w24,w19			// h+=Maj(a,b,c)
+	ldr	w19,[x30],#4		// *K++, w28 in next round
+	//add	w24,w24,w17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	w15,w15			// 12
+#endif
+	add	w24,w24,w17			// h+=Sigma0(a)
+	str	w7,[sp,#0]
+	ror	w16,w20,#6
+	add	w23,w23,w19			// h+=K[i]
+	eor	w7,w20,w20,ror#14
+	and	w17,w21,w20
+	bic	w19,w22,w20
+	add	w23,w23,w15			// h+=X[i]
+	orr	w17,w17,w19			// Ch(e,f,g)
+	eor	w19,w24,w25			// a^b, b^c in next round
+	eor	w16,w16,w7,ror#11	// Sigma1(e)
+	ror	w7,w24,#2
+	add	w23,w23,w17			// h+=Ch(e,f,g)
+	eor	w17,w24,w24,ror#9
+	add	w23,w23,w16			// h+=Sigma1(e)
+	and	w28,w28,w19			// (b^c)&=(a^b)
+	add	w27,w27,w23			// d+=h
+	eor	w28,w28,w25			// Maj(a,b,c)
+	eor	w17,w7,w17,ror#13	// Sigma0(a)
+	add	w23,w23,w28			// h+=Maj(a,b,c)
+	ldr	w28,[x30],#4		// *K++, w19 in next round
+	//add	w23,w23,w17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	w0,w0			// 13
+#endif
+	ldp	w1,w2,[x1]
+	add	w23,w23,w17			// h+=Sigma0(a)
+	str	w8,[sp,#4]
+	ror	w16,w27,#6
+	add	w22,w22,w28			// h+=K[i]
+	eor	w8,w27,w27,ror#14
+	and	w17,w20,w27
+	bic	w28,w21,w27
+	add	w22,w22,w0			// h+=X[i]
+	orr	w17,w17,w28			// Ch(e,f,g)
+	eor	w28,w23,w24			// a^b, b^c in next round
+	eor	w16,w16,w8,ror#11	// Sigma1(e)
+	ror	w8,w23,#2
+	add	w22,w22,w17			// h+=Ch(e,f,g)
+	eor	w17,w23,w23,ror#9
+	add	w22,w22,w16			// h+=Sigma1(e)
+	and	w19,w19,w28			// (b^c)&=(a^b)
+	add	w26,w26,w22			// d+=h
+	eor	w19,w19,w24			// Maj(a,b,c)
+	eor	w17,w8,w17,ror#13	// Sigma0(a)
+	add	w22,w22,w19			// h+=Maj(a,b,c)
+	ldr	w19,[x30],#4		// *K++, w28 in next round
+	//add	w22,w22,w17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	w1,w1			// 14
+#endif
+	ldr	w6,[sp,#12]
+	add	w22,w22,w17			// h+=Sigma0(a)
+	str	w9,[sp,#8]
+	ror	w16,w26,#6
+	add	w21,w21,w19			// h+=K[i]
+	eor	w9,w26,w26,ror#14
+	and	w17,w27,w26
+	bic	w19,w20,w26
+	add	w21,w21,w1			// h+=X[i]
+	orr	w17,w17,w19			// Ch(e,f,g)
+	eor	w19,w22,w23			// a^b, b^c in next round
+	eor	w16,w16,w9,ror#11	// Sigma1(e)
+	ror	w9,w22,#2
+	add	w21,w21,w17			// h+=Ch(e,f,g)
+	eor	w17,w22,w22,ror#9
+	add	w21,w21,w16			// h+=Sigma1(e)
+	and	w28,w28,w19			// (b^c)&=(a^b)
+	add	w25,w25,w21			// d+=h
+	eor	w28,w28,w23			// Maj(a,b,c)
+	eor	w17,w9,w17,ror#13	// Sigma0(a)
+	add	w21,w21,w28			// h+=Maj(a,b,c)
+	ldr	w28,[x30],#4		// *K++, w19 in next round
+	//add	w21,w21,w17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	w2,w2			// 15
+#endif
+	ldr	w7,[sp,#0]
+	add	w21,w21,w17			// h+=Sigma0(a)
+	str	w10,[sp,#12]
+	ror	w16,w25,#6
+	add	w20,w20,w28			// h+=K[i]
+	ror	w9,w4,#7
+	and	w17,w26,w25
+	ror	w8,w1,#17
+	bic	w28,w27,w25
+	ror	w10,w21,#2
+	add	w20,w20,w2			// h+=X[i]
+	eor	w16,w16,w25,ror#11
+	eor	w9,w9,w4,ror#18
+	orr	w17,w17,w28			// Ch(e,f,g)
+	eor	w28,w21,w22			// a^b, b^c in next round
+	eor	w16,w16,w25,ror#25	// Sigma1(e)
+	eor	w10,w10,w21,ror#13
+	add	w20,w20,w17			// h+=Ch(e,f,g)
+	and	w19,w19,w28			// (b^c)&=(a^b)
+	eor	w8,w8,w1,ror#19
+	eor	w9,w9,w4,lsr#3	// sigma0(X[i+1])
+	add	w20,w20,w16			// h+=Sigma1(e)
+	eor	w19,w19,w22			// Maj(a,b,c)
+	eor	w17,w10,w21,ror#22	// Sigma0(a)
+	eor	w8,w8,w1,lsr#10	// sigma1(X[i+14])
+	add	w3,w3,w12
+	add	w24,w24,w20			// d+=h
+	add	w20,w20,w19			// h+=Maj(a,b,c)
+	ldr	w19,[x30],#4		// *K++, w28 in next round
+	add	w3,w3,w9
+	add	w20,w20,w17			// h+=Sigma0(a)
+	add	w3,w3,w8
+.Loop_16_xx:
+	ldr	w8,[sp,#4]
+	str	w11,[sp,#0]
+	ror	w16,w24,#6
+	add	w27,w27,w19			// h+=K[i]
+	ror	w10,w5,#7
+	and	w17,w25,w24
+	ror	w9,w2,#17
+	bic	w19,w26,w24
+	ror	w11,w20,#2
+	add	w27,w27,w3			// h+=X[i]
+	eor	w16,w16,w24,ror#11
+	eor	w10,w10,w5,ror#18
+	orr	w17,w17,w19			// Ch(e,f,g)
+	eor	w19,w20,w21			// a^b, b^c in next round
+	eor	w16,w16,w24,ror#25	// Sigma1(e)
+	eor	w11,w11,w20,ror#13
+	add	w27,w27,w17			// h+=Ch(e,f,g)
+	and	w28,w28,w19			// (b^c)&=(a^b)
+	eor	w9,w9,w2,ror#19
+	eor	w10,w10,w5,lsr#3	// sigma0(X[i+1])
+	add	w27,w27,w16			// h+=Sigma1(e)
+	eor	w28,w28,w21			// Maj(a,b,c)
+	eor	w17,w11,w20,ror#22	// Sigma0(a)
+	eor	w9,w9,w2,lsr#10	// sigma1(X[i+14])
+	add	w4,w4,w13
+	add	w23,w23,w27			// d+=h
+	add	w27,w27,w28			// h+=Maj(a,b,c)
+	ldr	w28,[x30],#4		// *K++, w19 in next round
+	add	w4,w4,w10
+	add	w27,w27,w17			// h+=Sigma0(a)
+	add	w4,w4,w9
+	ldr	w9,[sp,#8]
+	str	w12,[sp,#4]
+	ror	w16,w23,#6
+	add	w26,w26,w28			// h+=K[i]
+	ror	w11,w6,#7
+	and	w17,w24,w23
+	ror	w10,w3,#17
+	bic	w28,w25,w23
+	ror	w12,w27,#2
+	add	w26,w26,w4			// h+=X[i]
+	eor	w16,w16,w23,ror#11
+	eor	w11,w11,w6,ror#18
+	orr	w17,w17,w28			// Ch(e,f,g)
+	eor	w28,w27,w20			// a^b, b^c in next round
+	eor	w16,w16,w23,ror#25	// Sigma1(e)
+	eor	w12,w12,w27,ror#13
+	add	w26,w26,w17			// h+=Ch(e,f,g)
+	and	w19,w19,w28			// (b^c)&=(a^b)
+	eor	w10,w10,w3,ror#19
+	eor	w11,w11,w6,lsr#3	// sigma0(X[i+1])
+	add	w26,w26,w16			// h+=Sigma1(e)
+	eor	w19,w19,w20			// Maj(a,b,c)
+	eor	w17,w12,w27,ror#22	// Sigma0(a)
+	eor	w10,w10,w3,lsr#10	// sigma1(X[i+14])
+	add	w5,w5,w14
+	add	w22,w22,w26			// d+=h
+	add	w26,w26,w19			// h+=Maj(a,b,c)
+	ldr	w19,[x30],#4		// *K++, w28 in next round
+	add	w5,w5,w11
+	add	w26,w26,w17			// h+=Sigma0(a)
+	add	w5,w5,w10
+	ldr	w10,[sp,#12]
+	str	w13,[sp,#8]
+	ror	w16,w22,#6
+	add	w25,w25,w19			// h+=K[i]
+	ror	w12,w7,#7
+	and	w17,w23,w22
+	ror	w11,w4,#17
+	bic	w19,w24,w22
+	ror	w13,w26,#2
+	add	w25,w25,w5			// h+=X[i]
+	eor	w16,w16,w22,ror#11
+	eor	w12,w12,w7,ror#18
+	orr	w17,w17,w19			// Ch(e,f,g)
+	eor	w19,w26,w27			// a^b, b^c in next round
+	eor	w16,w16,w22,ror#25	// Sigma1(e)
+	eor	w13,w13,w26,ror#13
+	add	w25,w25,w17			// h+=Ch(e,f,g)
+	and	w28,w28,w19			// (b^c)&=(a^b)
+	eor	w11,w11,w4,ror#19
+	eor	w12,w12,w7,lsr#3	// sigma0(X[i+1])
+	add	w25,w25,w16			// h+=Sigma1(e)
+	eor	w28,w28,w27			// Maj(a,b,c)
+	eor	w17,w13,w26,ror#22	// Sigma0(a)
+	eor	w11,w11,w4,lsr#10	// sigma1(X[i+14])
+	add	w6,w6,w15
+	add	w21,w21,w25			// d+=h
+	add	w25,w25,w28			// h+=Maj(a,b,c)
+	ldr	w28,[x30],#4		// *K++, w19 in next round
+	add	w6,w6,w12
+	add	w25,w25,w17			// h+=Sigma0(a)
+	add	w6,w6,w11
+	ldr	w11,[sp,#0]
+	str	w14,[sp,#12]
+	ror	w16,w21,#6
+	add	w24,w24,w28			// h+=K[i]
+	ror	w13,w8,#7
+	and	w17,w22,w21
+	ror	w12,w5,#17
+	bic	w28,w23,w21
+	ror	w14,w25,#2
+	add	w24,w24,w6			// h+=X[i]
+	eor	w16,w16,w21,ror#11
+	eor	w13,w13,w8,ror#18
+	orr	w17,w17,w28			// Ch(e,f,g)
+	eor	w28,w25,w26			// a^b, b^c in next round
+	eor	w16,w16,w21,ror#25	// Sigma1(e)
+	eor	w14,w14,w25,ror#13
+	add	w24,w24,w17			// h+=Ch(e,f,g)
+	and	w19,w19,w28			// (b^c)&=(a^b)
+	eor	w12,w12,w5,ror#19
+	eor	w13,w13,w8,lsr#3	// sigma0(X[i+1])
+	add	w24,w24,w16			// h+=Sigma1(e)
+	eor	w19,w19,w26			// Maj(a,b,c)
+	eor	w17,w14,w25,ror#22	// Sigma0(a)
+	eor	w12,w12,w5,lsr#10	// sigma1(X[i+14])
+	add	w7,w7,w0
+	add	w20,w20,w24			// d+=h
+	add	w24,w24,w19			// h+=Maj(a,b,c)
+	ldr	w19,[x30],#4		// *K++, w28 in next round
+	add	w7,w7,w13
+	add	w24,w24,w17			// h+=Sigma0(a)
+	add	w7,w7,w12
+	ldr	w12,[sp,#4]
+	str	w15,[sp,#0]
+	ror	w16,w20,#6
+	add	w23,w23,w19			// h+=K[i]
+	ror	w14,w9,#7
+	and	w17,w21,w20
+	ror	w13,w6,#17
+	bic	w19,w22,w20
+	ror	w15,w24,#2
+	add	w23,w23,w7			// h+=X[i]
+	eor	w16,w16,w20,ror#11
+	eor	w14,w14,w9,ror#18
+	orr	w17,w17,w19			// Ch(e,f,g)
+	eor	w19,w24,w25			// a^b, b^c in next round
+	eor	w16,w16,w20,ror#25	// Sigma1(e)
+	eor	w15,w15,w24,ror#13
+	add	w23,w23,w17			// h+=Ch(e,f,g)
+	and	w28,w28,w19			// (b^c)&=(a^b)
+	eor	w13,w13,w6,ror#19
+	eor	w14,w14,w9,lsr#3	// sigma0(X[i+1])
+	add	w23,w23,w16			// h+=Sigma1(e)
+	eor	w28,w28,w25			// Maj(a,b,c)
+	eor	w17,w15,w24,ror#22	// Sigma0(a)
+	eor	w13,w13,w6,lsr#10	// sigma1(X[i+14])
+	add	w8,w8,w1
+	add	w27,w27,w23			// d+=h
+	add	w23,w23,w28			// h+=Maj(a,b,c)
+	ldr	w28,[x30],#4		// *K++, w19 in next round
+	add	w8,w8,w14
+	add	w23,w23,w17			// h+=Sigma0(a)
+	add	w8,w8,w13
+	ldr	w13,[sp,#8]
+	str	w0,[sp,#4]
+	ror	w16,w27,#6
+	add	w22,w22,w28			// h+=K[i]
+	ror	w15,w10,#7
+	and	w17,w20,w27
+	ror	w14,w7,#17
+	bic	w28,w21,w27
+	ror	w0,w23,#2
+	add	w22,w22,w8			// h+=X[i]
+	eor	w16,w16,w27,ror#11
+	eor	w15,w15,w10,ror#18
+	orr	w17,w17,w28			// Ch(e,f,g)
+	eor	w28,w23,w24			// a^b, b^c in next round
+	eor	w16,w16,w27,ror#25	// Sigma1(e)
+	eor	w0,w0,w23,ror#13
+	add	w22,w22,w17			// h+=Ch(e,f,g)
+	and	w19,w19,w28			// (b^c)&=(a^b)
+	eor	w14,w14,w7,ror#19
+	eor	w15,w15,w10,lsr#3	// sigma0(X[i+1])
+	add	w22,w22,w16			// h+=Sigma1(e)
+	eor	w19,w19,w24			// Maj(a,b,c)
+	eor	w17,w0,w23,ror#22	// Sigma0(a)
+	eor	w14,w14,w7,lsr#10	// sigma1(X[i+14])
+	add	w9,w9,w2
+	add	w26,w26,w22			// d+=h
+	add	w22,w22,w19			// h+=Maj(a,b,c)
+	ldr	w19,[x30],#4		// *K++, w28 in next round
+	add	w9,w9,w15
+	add	w22,w22,w17			// h+=Sigma0(a)
+	add	w9,w9,w14
+	ldr	w14,[sp,#12]
+	str	w1,[sp,#8]
+	ror	w16,w26,#6
+	add	w21,w21,w19			// h+=K[i]
+	ror	w0,w11,#7
+	and	w17,w27,w26
+	ror	w15,w8,#17
+	bic	w19,w20,w26
+	ror	w1,w22,#2
+	add	w21,w21,w9			// h+=X[i]
+	eor	w16,w16,w26,ror#11
+	eor	w0,w0,w11,ror#18
+	orr	w17,w17,w19			// Ch(e,f,g)
+	eor	w19,w22,w23			// a^b, b^c in next round
+	eor	w16,w16,w26,ror#25	// Sigma1(e)
+	eor	w1,w1,w22,ror#13
+	add	w21,w21,w17			// h+=Ch(e,f,g)
+	and	w28,w28,w19			// (b^c)&=(a^b)
+	eor	w15,w15,w8,ror#19
+	eor	w0,w0,w11,lsr#3	// sigma0(X[i+1])
+	add	w21,w21,w16			// h+=Sigma1(e)
+	eor	w28,w28,w23			// Maj(a,b,c)
+	eor	w17,w1,w22,ror#22	// Sigma0(a)
+	eor	w15,w15,w8,lsr#10	// sigma1(X[i+14])
+	add	w10,w10,w3
+	add	w25,w25,w21			// d+=h
+	add	w21,w21,w28			// h+=Maj(a,b,c)
+	ldr	w28,[x30],#4		// *K++, w19 in next round
+	add	w10,w10,w0
+	add	w21,w21,w17			// h+=Sigma0(a)
+	add	w10,w10,w15
+	ldr	w15,[sp,#0]
+	str	w2,[sp,#12]
+	ror	w16,w25,#6
+	add	w20,w20,w28			// h+=K[i]
+	ror	w1,w12,#7
+	and	w17,w26,w25
+	ror	w0,w9,#17
+	bic	w28,w27,w25
+	ror	w2,w21,#2
+	add	w20,w20,w10			// h+=X[i]
+	eor	w16,w16,w25,ror#11
+	eor	w1,w1,w12,ror#18
+	orr	w17,w17,w28			// Ch(e,f,g)
+	eor	w28,w21,w22			// a^b, b^c in next round
+	eor	w16,w16,w25,ror#25	// Sigma1(e)
+	eor	w2,w2,w21,ror#13
+	add	w20,w20,w17			// h+=Ch(e,f,g)
+	and	w19,w19,w28			// (b^c)&=(a^b)
+	eor	w0,w0,w9,ror#19
+	eor	w1,w1,w12,lsr#3	// sigma0(X[i+1])
+	add	w20,w20,w16			// h+=Sigma1(e)
+	eor	w19,w19,w22			// Maj(a,b,c)
+	eor	w17,w2,w21,ror#22	// Sigma0(a)
+	eor	w0,w0,w9,lsr#10	// sigma1(X[i+14])
+	add	w11,w11,w4
+	add	w24,w24,w20			// d+=h
+	add	w20,w20,w19			// h+=Maj(a,b,c)
+	ldr	w19,[x30],#4		// *K++, w28 in next round
+	add	w11,w11,w1
+	add	w20,w20,w17			// h+=Sigma0(a)
+	add	w11,w11,w0
+	ldr	w0,[sp,#4]
+	str	w3,[sp,#0]
+	ror	w16,w24,#6
+	add	w27,w27,w19			// h+=K[i]
+	ror	w2,w13,#7
+	and	w17,w25,w24
+	ror	w1,w10,#17
+	bic	w19,w26,w24
+	ror	w3,w20,#2
+	add	w27,w27,w11			// h+=X[i]
+	eor	w16,w16,w24,ror#11
+	eor	w2,w2,w13,ror#18
+	orr	w17,w17,w19			// Ch(e,f,g)
+	eor	w19,w20,w21			// a^b, b^c in next round
+	eor	w16,w16,w24,ror#25	// Sigma1(e)
+	eor	w3,w3,w20,ror#13
+	add	w27,w27,w17			// h+=Ch(e,f,g)
+	and	w28,w28,w19			// (b^c)&=(a^b)
+	eor	w1,w1,w10,ror#19
+	eor	w2,w2,w13,lsr#3	// sigma0(X[i+1])
+	add	w27,w27,w16			// h+=Sigma1(e)
+	eor	w28,w28,w21			// Maj(a,b,c)
+	eor	w17,w3,w20,ror#22	// Sigma0(a)
+	eor	w1,w1,w10,lsr#10	// sigma1(X[i+14])
+	add	w12,w12,w5
+	add	w23,w23,w27			// d+=h
+	add	w27,w27,w28			// h+=Maj(a,b,c)
+	ldr	w28,[x30],#4		// *K++, w19 in next round
+	add	w12,w12,w2
+	add	w27,w27,w17			// h+=Sigma0(a)
+	add	w12,w12,w1
+	ldr	w1,[sp,#8]
+	str	w4,[sp,#4]
+	ror	w16,w23,#6
+	add	w26,w26,w28			// h+=K[i]
+	ror	w3,w14,#7
+	and	w17,w24,w23
+	ror	w2,w11,#17
+	bic	w28,w25,w23
+	ror	w4,w27,#2
+	add	w26,w26,w12			// h+=X[i]
+	eor	w16,w16,w23,ror#11
+	eor	w3,w3,w14,ror#18
+	orr	w17,w17,w28			// Ch(e,f,g)
+	eor	w28,w27,w20			// a^b, b^c in next round
+	eor	w16,w16,w23,ror#25	// Sigma1(e)
+	eor	w4,w4,w27,ror#13
+	add	w26,w26,w17			// h+=Ch(e,f,g)
+	and	w19,w19,w28			// (b^c)&=(a^b)
+	eor	w2,w2,w11,ror#19
+	eor	w3,w3,w14,lsr#3	// sigma0(X[i+1])
+	add	w26,w26,w16			// h+=Sigma1(e)
+	eor	w19,w19,w20			// Maj(a,b,c)
+	eor	w17,w4,w27,ror#22	// Sigma0(a)
+	eor	w2,w2,w11,lsr#10	// sigma1(X[i+14])
+	add	w13,w13,w6
+	add	w22,w22,w26			// d+=h
+	add	w26,w26,w19			// h+=Maj(a,b,c)
+	ldr	w19,[x30],#4		// *K++, w28 in next round
+	add	w13,w13,w3
+	add	w26,w26,w17			// h+=Sigma0(a)
+	add	w13,w13,w2
+	ldr	w2,[sp,#12]
+	str	w5,[sp,#8]
+	ror	w16,w22,#6
+	add	w25,w25,w19			// h+=K[i]
+	ror	w4,w15,#7
+	and	w17,w23,w22
+	ror	w3,w12,#17
+	bic	w19,w24,w22
+	ror	w5,w26,#2
+	add	w25,w25,w13			// h+=X[i]
+	eor	w16,w16,w22,ror#11
+	eor	w4,w4,w15,ror#18
+	orr	w17,w17,w19			// Ch(e,f,g)
+	eor	w19,w26,w27			// a^b, b^c in next round
+	eor	w16,w16,w22,ror#25	// Sigma1(e)
+	eor	w5,w5,w26,ror#13
+	add	w25,w25,w17			// h+=Ch(e,f,g)
+	and	w28,w28,w19			// (b^c)&=(a^b)
+	eor	w3,w3,w12,ror#19
+	eor	w4,w4,w15,lsr#3	// sigma0(X[i+1])
+	add	w25,w25,w16			// h+=Sigma1(e)
+	eor	w28,w28,w27			// Maj(a,b,c)
+	eor	w17,w5,w26,ror#22	// Sigma0(a)
+	eor	w3,w3,w12,lsr#10	// sigma1(X[i+14])
+	add	w14,w14,w7
+	add	w21,w21,w25			// d+=h
+	add	w25,w25,w28			// h+=Maj(a,b,c)
+	ldr	w28,[x30],#4		// *K++, w19 in next round
+	add	w14,w14,w4
+	add	w25,w25,w17			// h+=Sigma0(a)
+	add	w14,w14,w3
+	ldr	w3,[sp,#0]
+	str	w6,[sp,#12]
+	ror	w16,w21,#6
+	add	w24,w24,w28			// h+=K[i]
+	ror	w5,w0,#7
+	and	w17,w22,w21
+	ror	w4,w13,#17
+	bic	w28,w23,w21
+	ror	w6,w25,#2
+	add	w24,w24,w14			// h+=X[i]
+	eor	w16,w16,w21,ror#11
+	eor	w5,w5,w0,ror#18
+	orr	w17,w17,w28			// Ch(e,f,g)
+	eor	w28,w25,w26			// a^b, b^c in next round
+	eor	w16,w16,w21,ror#25	// Sigma1(e)
+	eor	w6,w6,w25,ror#13
+	add	w24,w24,w17			// h+=Ch(e,f,g)
+	and	w19,w19,w28			// (b^c)&=(a^b)
+	eor	w4,w4,w13,ror#19
+	eor	w5,w5,w0,lsr#3	// sigma0(X[i+1])
+	add	w24,w24,w16			// h+=Sigma1(e)
+	eor	w19,w19,w26			// Maj(a,b,c)
+	eor	w17,w6,w25,ror#22	// Sigma0(a)
+	eor	w4,w4,w13,lsr#10	// sigma1(X[i+14])
+	add	w15,w15,w8
+	add	w20,w20,w24			// d+=h
+	add	w24,w24,w19			// h+=Maj(a,b,c)
+	ldr	w19,[x30],#4		// *K++, w28 in next round
+	add	w15,w15,w5
+	add	w24,w24,w17			// h+=Sigma0(a)
+	add	w15,w15,w4
+	ldr	w4,[sp,#4]
+	str	w7,[sp,#0]
+	ror	w16,w20,#6
+	add	w23,w23,w19			// h+=K[i]
+	ror	w6,w1,#7
+	and	w17,w21,w20
+	ror	w5,w14,#17
+	bic	w19,w22,w20
+	ror	w7,w24,#2
+	add	w23,w23,w15			// h+=X[i]
+	eor	w16,w16,w20,ror#11
+	eor	w6,w6,w1,ror#18
+	orr	w17,w17,w19			// Ch(e,f,g)
+	eor	w19,w24,w25			// a^b, b^c in next round
+	eor	w16,w16,w20,ror#25	// Sigma1(e)
+	eor	w7,w7,w24,ror#13
+	add	w23,w23,w17			// h+=Ch(e,f,g)
+	and	w28,w28,w19			// (b^c)&=(a^b)
+	eor	w5,w5,w14,ror#19
+	eor	w6,w6,w1,lsr#3	// sigma0(X[i+1])
+	add	w23,w23,w16			// h+=Sigma1(e)
+	eor	w28,w28,w25			// Maj(a,b,c)
+	eor	w17,w7,w24,ror#22	// Sigma0(a)
+	eor	w5,w5,w14,lsr#10	// sigma1(X[i+14])
+	add	w0,w0,w9
+	add	w27,w27,w23			// d+=h
+	add	w23,w23,w28			// h+=Maj(a,b,c)
+	ldr	w28,[x30],#4		// *K++, w19 in next round
+	add	w0,w0,w6
+	add	w23,w23,w17			// h+=Sigma0(a)
+	add	w0,w0,w5
+	ldr	w5,[sp,#8]
+	str	w8,[sp,#4]
+	ror	w16,w27,#6
+	add	w22,w22,w28			// h+=K[i]
+	ror	w7,w2,#7
+	and	w17,w20,w27
+	ror	w6,w15,#17
+	bic	w28,w21,w27
+	ror	w8,w23,#2
+	add	w22,w22,w0			// h+=X[i]
+	eor	w16,w16,w27,ror#11
+	eor	w7,w7,w2,ror#18
+	orr	w17,w17,w28			// Ch(e,f,g)
+	eor	w28,w23,w24			// a^b, b^c in next round
+	eor	w16,w16,w27,ror#25	// Sigma1(e)
+	eor	w8,w8,w23,ror#13
+	add	w22,w22,w17			// h+=Ch(e,f,g)
+	and	w19,w19,w28			// (b^c)&=(a^b)
+	eor	w6,w6,w15,ror#19
+	eor	w7,w7,w2,lsr#3	// sigma0(X[i+1])
+	add	w22,w22,w16			// h+=Sigma1(e)
+	eor	w19,w19,w24			// Maj(a,b,c)
+	eor	w17,w8,w23,ror#22	// Sigma0(a)
+	eor	w6,w6,w15,lsr#10	// sigma1(X[i+14])
+	add	w1,w1,w10
+	add	w26,w26,w22			// d+=h
+	add	w22,w22,w19			// h+=Maj(a,b,c)
+	ldr	w19,[x30],#4		// *K++, w28 in next round
+	add	w1,w1,w7
+	add	w22,w22,w17			// h+=Sigma0(a)
+	add	w1,w1,w6
+	ldr	w6,[sp,#12]
+	str	w9,[sp,#8]
+	ror	w16,w26,#6
+	add	w21,w21,w19			// h+=K[i]
+	ror	w8,w3,#7
+	and	w17,w27,w26
+	ror	w7,w0,#17
+	bic	w19,w20,w26
+	ror	w9,w22,#2
+	add	w21,w21,w1			// h+=X[i]
+	eor	w16,w16,w26,ror#11
+	eor	w8,w8,w3,ror#18
+	orr	w17,w17,w19			// Ch(e,f,g)
+	eor	w19,w22,w23			// a^b, b^c in next round
+	eor	w16,w16,w26,ror#25	// Sigma1(e)
+	eor	w9,w9,w22,ror#13
+	add	w21,w21,w17			// h+=Ch(e,f,g)
+	and	w28,w28,w19			// (b^c)&=(a^b)
+	eor	w7,w7,w0,ror#19
+	eor	w8,w8,w3,lsr#3	// sigma0(X[i+1])
+	add	w21,w21,w16			// h+=Sigma1(e)
+	eor	w28,w28,w23			// Maj(a,b,c)
+	eor	w17,w9,w22,ror#22	// Sigma0(a)
+	eor	w7,w7,w0,lsr#10	// sigma1(X[i+14])
+	add	w2,w2,w11
+	add	w25,w25,w21			// d+=h
+	add	w21,w21,w28			// h+=Maj(a,b,c)
+	ldr	w28,[x30],#4		// *K++, w19 in next round
+	add	w2,w2,w8
+	add	w21,w21,w17			// h+=Sigma0(a)
+	add	w2,w2,w7
+	ldr	w7,[sp,#0]
+	str	w10,[sp,#12]
+	ror	w16,w25,#6
+	add	w20,w20,w28			// h+=K[i]
+	ror	w9,w4,#7
+	and	w17,w26,w25
+	ror	w8,w1,#17
+	bic	w28,w27,w25
+	ror	w10,w21,#2
+	add	w20,w20,w2			// h+=X[i]
+	eor	w16,w16,w25,ror#11
+	eor	w9,w9,w4,ror#18
+	orr	w17,w17,w28			// Ch(e,f,g)
+	eor	w28,w21,w22			// a^b, b^c in next round
+	eor	w16,w16,w25,ror#25	// Sigma1(e)
+	eor	w10,w10,w21,ror#13
+	add	w20,w20,w17			// h+=Ch(e,f,g)
+	and	w19,w19,w28			// (b^c)&=(a^b)
+	eor	w8,w8,w1,ror#19
+	eor	w9,w9,w4,lsr#3	// sigma0(X[i+1])
+	add	w20,w20,w16			// h+=Sigma1(e)
+	eor	w19,w19,w22			// Maj(a,b,c)
+	eor	w17,w10,w21,ror#22	// Sigma0(a)
+	eor	w8,w8,w1,lsr#10	// sigma1(X[i+14])
+	add	w3,w3,w12
+	add	w24,w24,w20			// d+=h
+	add	w20,w20,w19			// h+=Maj(a,b,c)
+	ldr	w19,[x30],#4		// *K++, w28 in next round
+	add	w3,w3,w9
+	add	w20,w20,w17			// h+=Sigma0(a)
+	add	w3,w3,w8
+	cbnz	w19,.Loop_16_xx
+
+	ldp	x0,x2,[x29,#96]
+	ldr	x1,[x29,#112]
+	sub	x30,x30,#260		// rewind
+
+	ldp	w3,w4,[x0]
+	ldp	w5,w6,[x0,#2*4]
+	add	x1,x1,#14*4			// advance input pointer
+	ldp	w7,w8,[x0,#4*4]
+	add	w20,w20,w3
+	ldp	w9,w10,[x0,#6*4]
+	add	w21,w21,w4
+	add	w22,w22,w5
+	add	w23,w23,w6
+	stp	w20,w21,[x0]
+	add	w24,w24,w7
+	add	w25,w25,w8
+	stp	w22,w23,[x0,#2*4]
+	add	w26,w26,w9
+	add	w27,w27,w10
+	cmp	x1,x2
+	stp	w24,w25,[x0,#4*4]
+	stp	w26,w27,[x0,#6*4]
+	b.ne	.Loop
+
+	ldp	x19,x20,[x29,#16]
+	add	sp,sp,#4*4
+	ldp	x21,x22,[x29,#32]
+	ldp	x23,x24,[x29,#48]
+	ldp	x25,x26,[x29,#64]
+	ldp	x27,x28,[x29,#80]
+	ldp	x29,x30,[sp],#128
+	ret
+.size	sha256_block_data_order,.-sha256_block_data_order
+
+.align	6
+.type	.LK256,%object
+.LK256:
+	.long	0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
+	.long	0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
+	.long	0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
+	.long	0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
+	.long	0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
+	.long	0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
+	.long	0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
+	.long	0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
+	.long	0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
+	.long	0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
+	.long	0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
+	.long	0xd192e819,0xd6990624,0xf40e3585,0x106aa070
+	.long	0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
+	.long	0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
+	.long	0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
+	.long	0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
+	.long	0	//terminator
+.size	.LK256,.-.LK256
+#ifndef	__KERNEL__
+.align	3
+.LOPENSSL_armcap_P:
+# ifdef	__ILP32__
+	.long	OPENSSL_armcap_P-.
+# else
+	.quad	OPENSSL_armcap_P-.
+# endif
+#endif
+.asciz	"SHA256 block transform for ARMv8, CRYPTOGAMS by <appro@openssl.org>"
+.align	2
+#ifndef	__KERNEL__
+.type	sha256_block_armv8,%function
+.align	6
+sha256_block_armv8:
+.Lv8_entry:
+	stp		x29,x30,[sp,#-16]!
+	add		x29,sp,#0
+
+	ld1		{v0.4s,v1.4s},[x0]
+	adr		x3,.LK256
+
+.Loop_hw:
+	ld1		{v4.16b-v7.16b},[x1],#64
+	sub		x2,x2,#1
+	ld1		{v16.4s},[x3],#16
+	rev32		v4.16b,v4.16b
+	rev32		v5.16b,v5.16b
+	rev32		v6.16b,v6.16b
+	rev32		v7.16b,v7.16b
+	orr		v18.16b,v0.16b,v0.16b		// offload
+	orr		v19.16b,v1.16b,v1.16b
+	ld1		{v17.4s},[x3],#16
+	add		v16.4s,v16.4s,v4.4s
+	.inst	0x5e2828a4	//sha256su0 v4.16b,v5.16b
+	orr		v2.16b,v0.16b,v0.16b
+	.inst	0x5e104020	//sha256h v0.16b,v1.16b,v16.4s
+	.inst	0x5e105041	//sha256h2 v1.16b,v2.16b,v16.4s
+	.inst	0x5e0760c4	//sha256su1 v4.16b,v6.16b,v7.16b
+	ld1		{v16.4s},[x3],#16
+	add		v17.4s,v17.4s,v5.4s
+	.inst	0x5e2828c5	//sha256su0 v5.16b,v6.16b
+	orr		v2.16b,v0.16b,v0.16b
+	.inst	0x5e114020	//sha256h v0.16b,v1.16b,v17.4s
+	.inst	0x5e115041	//sha256h2 v1.16b,v2.16b,v17.4s
+	.inst	0x5e0460e5	//sha256su1 v5.16b,v7.16b,v4.16b
+	ld1		{v17.4s},[x3],#16
+	add		v16.4s,v16.4s,v6.4s
+	.inst	0x5e2828e6	//sha256su0 v6.16b,v7.16b
+	orr		v2.16b,v0.16b,v0.16b
+	.inst	0x5e104020	//sha256h v0.16b,v1.16b,v16.4s
+	.inst	0x5e105041	//sha256h2 v1.16b,v2.16b,v16.4s
+	.inst	0x5e056086	//sha256su1 v6.16b,v4.16b,v5.16b
+	ld1		{v16.4s},[x3],#16
+	add		v17.4s,v17.4s,v7.4s
+	.inst	0x5e282887	//sha256su0 v7.16b,v4.16b
+	orr		v2.16b,v0.16b,v0.16b
+	.inst	0x5e114020	//sha256h v0.16b,v1.16b,v17.4s
+	.inst	0x5e115041	//sha256h2 v1.16b,v2.16b,v17.4s
+	.inst	0x5e0660a7	//sha256su1 v7.16b,v5.16b,v6.16b
+	ld1		{v17.4s},[x3],#16
+	add		v16.4s,v16.4s,v4.4s
+	.inst	0x5e2828a4	//sha256su0 v4.16b,v5.16b
+	orr		v2.16b,v0.16b,v0.16b
+	.inst	0x5e104020	//sha256h v0.16b,v1.16b,v16.4s
+	.inst	0x5e105041	//sha256h2 v1.16b,v2.16b,v16.4s
+	.inst	0x5e0760c4	//sha256su1 v4.16b,v6.16b,v7.16b
+	ld1		{v16.4s},[x3],#16
+	add		v17.4s,v17.4s,v5.4s
+	.inst	0x5e2828c5	//sha256su0 v5.16b,v6.16b
+	orr		v2.16b,v0.16b,v0.16b
+	.inst	0x5e114020	//sha256h v0.16b,v1.16b,v17.4s
+	.inst	0x5e115041	//sha256h2 v1.16b,v2.16b,v17.4s
+	.inst	0x5e0460e5	//sha256su1 v5.16b,v7.16b,v4.16b
+	ld1		{v17.4s},[x3],#16
+	add		v16.4s,v16.4s,v6.4s
+	.inst	0x5e2828e6	//sha256su0 v6.16b,v7.16b
+	orr		v2.16b,v0.16b,v0.16b
+	.inst	0x5e104020	//sha256h v0.16b,v1.16b,v16.4s
+	.inst	0x5e105041	//sha256h2 v1.16b,v2.16b,v16.4s
+	.inst	0x5e056086	//sha256su1 v6.16b,v4.16b,v5.16b
+	ld1		{v16.4s},[x3],#16
+	add		v17.4s,v17.4s,v7.4s
+	.inst	0x5e282887	//sha256su0 v7.16b,v4.16b
+	orr		v2.16b,v0.16b,v0.16b
+	.inst	0x5e114020	//sha256h v0.16b,v1.16b,v17.4s
+	.inst	0x5e115041	//sha256h2 v1.16b,v2.16b,v17.4s
+	.inst	0x5e0660a7	//sha256su1 v7.16b,v5.16b,v6.16b
+	ld1		{v17.4s},[x3],#16
+	add		v16.4s,v16.4s,v4.4s
+	.inst	0x5e2828a4	//sha256su0 v4.16b,v5.16b
+	orr		v2.16b,v0.16b,v0.16b
+	.inst	0x5e104020	//sha256h v0.16b,v1.16b,v16.4s
+	.inst	0x5e105041	//sha256h2 v1.16b,v2.16b,v16.4s
+	.inst	0x5e0760c4	//sha256su1 v4.16b,v6.16b,v7.16b
+	ld1		{v16.4s},[x3],#16
+	add		v17.4s,v17.4s,v5.4s
+	.inst	0x5e2828c5	//sha256su0 v5.16b,v6.16b
+	orr		v2.16b,v0.16b,v0.16b
+	.inst	0x5e114020	//sha256h v0.16b,v1.16b,v17.4s
+	.inst	0x5e115041	//sha256h2 v1.16b,v2.16b,v17.4s
+	.inst	0x5e0460e5	//sha256su1 v5.16b,v7.16b,v4.16b
+	ld1		{v17.4s},[x3],#16
+	add		v16.4s,v16.4s,v6.4s
+	.inst	0x5e2828e6	//sha256su0 v6.16b,v7.16b
+	orr		v2.16b,v0.16b,v0.16b
+	.inst	0x5e104020	//sha256h v0.16b,v1.16b,v16.4s
+	.inst	0x5e105041	//sha256h2 v1.16b,v2.16b,v16.4s
+	.inst	0x5e056086	//sha256su1 v6.16b,v4.16b,v5.16b
+	ld1		{v16.4s},[x3],#16
+	add		v17.4s,v17.4s,v7.4s
+	.inst	0x5e282887	//sha256su0 v7.16b,v4.16b
+	orr		v2.16b,v0.16b,v0.16b
+	.inst	0x5e114020	//sha256h v0.16b,v1.16b,v17.4s
+	.inst	0x5e115041	//sha256h2 v1.16b,v2.16b,v17.4s
+	.inst	0x5e0660a7	//sha256su1 v7.16b,v5.16b,v6.16b
+	ld1		{v17.4s},[x3],#16
+	add		v16.4s,v16.4s,v4.4s
+	orr		v2.16b,v0.16b,v0.16b
+	.inst	0x5e104020	//sha256h v0.16b,v1.16b,v16.4s
+	.inst	0x5e105041	//sha256h2 v1.16b,v2.16b,v16.4s
+
+	ld1		{v16.4s},[x3],#16
+	add		v17.4s,v17.4s,v5.4s
+	orr		v2.16b,v0.16b,v0.16b
+	.inst	0x5e114020	//sha256h v0.16b,v1.16b,v17.4s
+	.inst	0x5e115041	//sha256h2 v1.16b,v2.16b,v17.4s
+
+	ld1		{v17.4s},[x3]
+	add		v16.4s,v16.4s,v6.4s
+	sub		x3,x3,#64*4-16	// rewind
+	orr		v2.16b,v0.16b,v0.16b
+	.inst	0x5e104020	//sha256h v0.16b,v1.16b,v16.4s
+	.inst	0x5e105041	//sha256h2 v1.16b,v2.16b,v16.4s
+
+	add		v17.4s,v17.4s,v7.4s
+	orr		v2.16b,v0.16b,v0.16b
+	.inst	0x5e114020	//sha256h v0.16b,v1.16b,v17.4s
+	.inst	0x5e115041	//sha256h2 v1.16b,v2.16b,v17.4s
+
+	add		v0.4s,v0.4s,v18.4s
+	add		v1.4s,v1.4s,v19.4s
+
+	cbnz		x2,.Loop_hw
+
+	st1		{v0.4s,v1.4s},[x0]
+
+	ldr		x29,[sp],#16
+	ret
+.size	sha256_block_armv8,.-sha256_block_armv8
+#endif
+#ifdef	__KERNEL__
+.globl	sha256_block_neon
+#endif
+.type	sha256_block_neon,%function
+.align	4
+sha256_block_neon:
+.Lneon_entry:
+	stp	x29, x30, [sp, #-16]!
+	mov	x29, sp
+	sub	sp,sp,#16*4
+
+	adr	x16,.LK256
+	add	x2,x1,x2,lsl#6	// len to point at the end of inp
+
+	ld1	{v0.16b},[x1], #16
+	ld1	{v1.16b},[x1], #16
+	ld1	{v2.16b},[x1], #16
+	ld1	{v3.16b},[x1], #16
+	ld1	{v4.4s},[x16], #16
+	ld1	{v5.4s},[x16], #16
+	ld1	{v6.4s},[x16], #16
+	ld1	{v7.4s},[x16], #16
+	rev32	v0.16b,v0.16b		// yes, even on
+	rev32	v1.16b,v1.16b		// big-endian
+	rev32	v2.16b,v2.16b
+	rev32	v3.16b,v3.16b
+	mov	x17,sp
+	add	v4.4s,v4.4s,v0.4s
+	add	v5.4s,v5.4s,v1.4s
+	add	v6.4s,v6.4s,v2.4s
+	st1	{v4.4s-v5.4s},[x17], #32
+	add	v7.4s,v7.4s,v3.4s
+	st1	{v6.4s-v7.4s},[x17]
+	sub	x17,x17,#32
+
+	ldp	w3,w4,[x0]
+	ldp	w5,w6,[x0,#8]
+	ldp	w7,w8,[x0,#16]
+	ldp	w9,w10,[x0,#24]
+	ldr	w12,[sp,#0]
+	mov	w13,wzr
+	eor	w14,w4,w5
+	mov	w15,wzr
+	b	.L_00_48
+
+.align	4
+.L_00_48:
+	ext	v4.16b,v0.16b,v1.16b,#4
+	add	w10,w10,w12
+	add	w3,w3,w15
+	and	w12,w8,w7
+	bic	w15,w9,w7
+	ext	v7.16b,v2.16b,v3.16b,#4
+	eor	w11,w7,w7,ror#5
+	add	w3,w3,w13
+	mov	d19,v3.d[1]
+	orr	w12,w12,w15
+	eor	w11,w11,w7,ror#19
+	ushr	v6.4s,v4.4s,#7
+	eor	w15,w3,w3,ror#11
+	ushr	v5.4s,v4.4s,#3
+	add	w10,w10,w12
+	add	v0.4s,v0.4s,v7.4s
+	ror	w11,w11,#6
+	sli	v6.4s,v4.4s,#25
+	eor	w13,w3,w4
+	eor	w15,w15,w3,ror#20
+	ushr	v7.4s,v4.4s,#18
+	add	w10,w10,w11
+	ldr	w12,[sp,#4]
+	and	w14,w14,w13
+	eor	v5.16b,v5.16b,v6.16b
+	ror	w15,w15,#2
+	add	w6,w6,w10
+	sli	v7.4s,v4.4s,#14
+	eor	w14,w14,w4
+	ushr	v16.4s,v19.4s,#17
+	add	w9,w9,w12
+	add	w10,w10,w15
+	and	w12,w7,w6
+	eor	v5.16b,v5.16b,v7.16b
+	bic	w15,w8,w6
+	eor	w11,w6,w6,ror#5
+	sli	v16.4s,v19.4s,#15
+	add	w10,w10,w14
+	orr	w12,w12,w15
+	ushr	v17.4s,v19.4s,#10
+	eor	w11,w11,w6,ror#19
+	eor	w15,w10,w10,ror#11
+	ushr	v7.4s,v19.4s,#19
+	add	w9,w9,w12
+	ror	w11,w11,#6
+	add	v0.4s,v0.4s,v5.4s
+	eor	w14,w10,w3
+	eor	w15,w15,w10,ror#20
+	sli	v7.4s,v19.4s,#13
+	add	w9,w9,w11
+	ldr	w12,[sp,#8]
+	and	w13,w13,w14
+	eor	v17.16b,v17.16b,v16.16b
+	ror	w15,w15,#2
+	add	w5,w5,w9
+	eor	w13,w13,w3
+	eor	v17.16b,v17.16b,v7.16b
+	add	w8,w8,w12
+	add	w9,w9,w15
+	and	w12,w6,w5
+	add	v0.4s,v0.4s,v17.4s
+	bic	w15,w7,w5
+	eor	w11,w5,w5,ror#5
+	add	w9,w9,w13
+	ushr	v18.4s,v0.4s,#17
+	orr	w12,w12,w15
+	ushr	v19.4s,v0.4s,#10
+	eor	w11,w11,w5,ror#19
+	eor	w15,w9,w9,ror#11
+	sli	v18.4s,v0.4s,#15
+	add	w8,w8,w12
+	ushr	v17.4s,v0.4s,#19
+	ror	w11,w11,#6
+	eor	w13,w9,w10
+	eor	v19.16b,v19.16b,v18.16b
+	eor	w15,w15,w9,ror#20
+	add	w8,w8,w11
+	sli	v17.4s,v0.4s,#13
+	ldr	w12,[sp,#12]
+	and	w14,w14,w13
+	ror	w15,w15,#2
+	ld1	{v4.4s},[x16], #16
+	add	w4,w4,w8
+	eor	v19.16b,v19.16b,v17.16b
+	eor	w14,w14,w10
+	eor	v17.16b,v17.16b,v17.16b
+	add	w7,w7,w12
+	add	w8,w8,w15
+	and	w12,w5,w4
+	mov	v17.d[1],v19.d[0]
+	bic	w15,w6,w4
+	eor	w11,w4,w4,ror#5
+	add	w8,w8,w14
+	add	v0.4s,v0.4s,v17.4s
+	orr	w12,w12,w15
+	eor	w11,w11,w4,ror#19
+	eor	w15,w8,w8,ror#11
+	add	v4.4s,v4.4s,v0.4s
+	add	w7,w7,w12
+	ror	w11,w11,#6
+	eor	w14,w8,w9
+	eor	w15,w15,w8,ror#20
+	add	w7,w7,w11
+	ldr	w12,[sp,#16]
+	and	w13,w13,w14
+	ror	w15,w15,#2
+	add	w3,w3,w7
+	eor	w13,w13,w9
+	st1	{v4.4s},[x17], #16
+	ext	v4.16b,v1.16b,v2.16b,#4
+	add	w6,w6,w12
+	add	w7,w7,w15
+	and	w12,w4,w3
+	bic	w15,w5,w3
+	ext	v7.16b,v3.16b,v0.16b,#4
+	eor	w11,w3,w3,ror#5
+	add	w7,w7,w13
+	mov	d19,v0.d[1]
+	orr	w12,w12,w15
+	eor	w11,w11,w3,ror#19
+	ushr	v6.4s,v4.4s,#7
+	eor	w15,w7,w7,ror#11
+	ushr	v5.4s,v4.4s,#3
+	add	w6,w6,w12
+	add	v1.4s,v1.4s,v7.4s
+	ror	w11,w11,#6
+	sli	v6.4s,v4.4s,#25
+	eor	w13,w7,w8
+	eor	w15,w15,w7,ror#20
+	ushr	v7.4s,v4.4s,#18
+	add	w6,w6,w11
+	ldr	w12,[sp,#20]
+	and	w14,w14,w13
+	eor	v5.16b,v5.16b,v6.16b
+	ror	w15,w15,#2
+	add	w10,w10,w6
+	sli	v7.4s,v4.4s,#14
+	eor	w14,w14,w8
+	ushr	v16.4s,v19.4s,#17
+	add	w5,w5,w12
+	add	w6,w6,w15
+	and	w12,w3,w10
+	eor	v5.16b,v5.16b,v7.16b
+	bic	w15,w4,w10
+	eor	w11,w10,w10,ror#5
+	sli	v16.4s,v19.4s,#15
+	add	w6,w6,w14
+	orr	w12,w12,w15
+	ushr	v17.4s,v19.4s,#10
+	eor	w11,w11,w10,ror#19
+	eor	w15,w6,w6,ror#11
+	ushr	v7.4s,v19.4s,#19
+	add	w5,w5,w12
+	ror	w11,w11,#6
+	add	v1.4s,v1.4s,v5.4s
+	eor	w14,w6,w7
+	eor	w15,w15,w6,ror#20
+	sli	v7.4s,v19.4s,#13
+	add	w5,w5,w11
+	ldr	w12,[sp,#24]
+	and	w13,w13,w14
+	eor	v17.16b,v17.16b,v16.16b
+	ror	w15,w15,#2
+	add	w9,w9,w5
+	eor	w13,w13,w7
+	eor	v17.16b,v17.16b,v7.16b
+	add	w4,w4,w12
+	add	w5,w5,w15
+	and	w12,w10,w9
+	add	v1.4s,v1.4s,v17.4s
+	bic	w15,w3,w9
+	eor	w11,w9,w9,ror#5
+	add	w5,w5,w13
+	ushr	v18.4s,v1.4s,#17
+	orr	w12,w12,w15
+	ushr	v19.4s,v1.4s,#10
+	eor	w11,w11,w9,ror#19
+	eor	w15,w5,w5,ror#11
+	sli	v18.4s,v1.4s,#15
+	add	w4,w4,w12
+	ushr	v17.4s,v1.4s,#19
+	ror	w11,w11,#6
+	eor	w13,w5,w6
+	eor	v19.16b,v19.16b,v18.16b
+	eor	w15,w15,w5,ror#20
+	add	w4,w4,w11
+	sli	v17.4s,v1.4s,#13
+	ldr	w12,[sp,#28]
+	and	w14,w14,w13
+	ror	w15,w15,#2
+	ld1	{v4.4s},[x16], #16
+	add	w8,w8,w4
+	eor	v19.16b,v19.16b,v17.16b
+	eor	w14,w14,w6
+	eor	v17.16b,v17.16b,v17.16b
+	add	w3,w3,w12
+	add	w4,w4,w15
+	and	w12,w9,w8
+	mov	v17.d[1],v19.d[0]
+	bic	w15,w10,w8
+	eor	w11,w8,w8,ror#5
+	add	w4,w4,w14
+	add	v1.4s,v1.4s,v17.4s
+	orr	w12,w12,w15
+	eor	w11,w11,w8,ror#19
+	eor	w15,w4,w4,ror#11
+	add	v4.4s,v4.4s,v1.4s
+	add	w3,w3,w12
+	ror	w11,w11,#6
+	eor	w14,w4,w5
+	eor	w15,w15,w4,ror#20
+	add	w3,w3,w11
+	ldr	w12,[sp,#32]
+	and	w13,w13,w14
+	ror	w15,w15,#2
+	add	w7,w7,w3
+	eor	w13,w13,w5
+	st1	{v4.4s},[x17], #16
+	ext	v4.16b,v2.16b,v3.16b,#4
+	add	w10,w10,w12
+	add	w3,w3,w15
+	and	w12,w8,w7
+	bic	w15,w9,w7
+	ext	v7.16b,v0.16b,v1.16b,#4
+	eor	w11,w7,w7,ror#5
+	add	w3,w3,w13
+	mov	d19,v1.d[1]
+	orr	w12,w12,w15
+	eor	w11,w11,w7,ror#19
+	ushr	v6.4s,v4.4s,#7
+	eor	w15,w3,w3,ror#11
+	ushr	v5.4s,v4.4s,#3
+	add	w10,w10,w12
+	add	v2.4s,v2.4s,v7.4s
+	ror	w11,w11,#6
+	sli	v6.4s,v4.4s,#25
+	eor	w13,w3,w4
+	eor	w15,w15,w3,ror#20
+	ushr	v7.4s,v4.4s,#18
+	add	w10,w10,w11
+	ldr	w12,[sp,#36]
+	and	w14,w14,w13
+	eor	v5.16b,v5.16b,v6.16b
+	ror	w15,w15,#2
+	add	w6,w6,w10
+	sli	v7.4s,v4.4s,#14
+	eor	w14,w14,w4
+	ushr	v16.4s,v19.4s,#17
+	add	w9,w9,w12
+	add	w10,w10,w15
+	and	w12,w7,w6
+	eor	v5.16b,v5.16b,v7.16b
+	bic	w15,w8,w6
+	eor	w11,w6,w6,ror#5
+	sli	v16.4s,v19.4s,#15
+	add	w10,w10,w14
+	orr	w12,w12,w15
+	ushr	v17.4s,v19.4s,#10
+	eor	w11,w11,w6,ror#19
+	eor	w15,w10,w10,ror#11
+	ushr	v7.4s,v19.4s,#19
+	add	w9,w9,w12
+	ror	w11,w11,#6
+	add	v2.4s,v2.4s,v5.4s
+	eor	w14,w10,w3
+	eor	w15,w15,w10,ror#20
+	sli	v7.4s,v19.4s,#13
+	add	w9,w9,w11
+	ldr	w12,[sp,#40]
+	and	w13,w13,w14
+	eor	v17.16b,v17.16b,v16.16b
+	ror	w15,w15,#2
+	add	w5,w5,w9
+	eor	w13,w13,w3
+	eor	v17.16b,v17.16b,v7.16b
+	add	w8,w8,w12
+	add	w9,w9,w15
+	and	w12,w6,w5
+	add	v2.4s,v2.4s,v17.4s
+	bic	w15,w7,w5
+	eor	w11,w5,w5,ror#5
+	add	w9,w9,w13
+	ushr	v18.4s,v2.4s,#17
+	orr	w12,w12,w15
+	ushr	v19.4s,v2.4s,#10
+	eor	w11,w11,w5,ror#19
+	eor	w15,w9,w9,ror#11
+	sli	v18.4s,v2.4s,#15
+	add	w8,w8,w12
+	ushr	v17.4s,v2.4s,#19
+	ror	w11,w11,#6
+	eor	w13,w9,w10
+	eor	v19.16b,v19.16b,v18.16b
+	eor	w15,w15,w9,ror#20
+	add	w8,w8,w11
+	sli	v17.4s,v2.4s,#13
+	ldr	w12,[sp,#44]
+	and	w14,w14,w13
+	ror	w15,w15,#2
+	ld1	{v4.4s},[x16], #16
+	add	w4,w4,w8
+	eor	v19.16b,v19.16b,v17.16b
+	eor	w14,w14,w10
+	eor	v17.16b,v17.16b,v17.16b
+	add	w7,w7,w12
+	add	w8,w8,w15
+	and	w12,w5,w4
+	mov	v17.d[1],v19.d[0]
+	bic	w15,w6,w4
+	eor	w11,w4,w4,ror#5
+	add	w8,w8,w14
+	add	v2.4s,v2.4s,v17.4s
+	orr	w12,w12,w15
+	eor	w11,w11,w4,ror#19
+	eor	w15,w8,w8,ror#11
+	add	v4.4s,v4.4s,v2.4s
+	add	w7,w7,w12
+	ror	w11,w11,#6
+	eor	w14,w8,w9
+	eor	w15,w15,w8,ror#20
+	add	w7,w7,w11
+	ldr	w12,[sp,#48]
+	and	w13,w13,w14
+	ror	w15,w15,#2
+	add	w3,w3,w7
+	eor	w13,w13,w9
+	st1	{v4.4s},[x17], #16
+	ext	v4.16b,v3.16b,v0.16b,#4
+	add	w6,w6,w12
+	add	w7,w7,w15
+	and	w12,w4,w3
+	bic	w15,w5,w3
+	ext	v7.16b,v1.16b,v2.16b,#4
+	eor	w11,w3,w3,ror#5
+	add	w7,w7,w13
+	mov	d19,v2.d[1]
+	orr	w12,w12,w15
+	eor	w11,w11,w3,ror#19
+	ushr	v6.4s,v4.4s,#7
+	eor	w15,w7,w7,ror#11
+	ushr	v5.4s,v4.4s,#3
+	add	w6,w6,w12
+	add	v3.4s,v3.4s,v7.4s
+	ror	w11,w11,#6
+	sli	v6.4s,v4.4s,#25
+	eor	w13,w7,w8
+	eor	w15,w15,w7,ror#20
+	ushr	v7.4s,v4.4s,#18
+	add	w6,w6,w11
+	ldr	w12,[sp,#52]
+	and	w14,w14,w13
+	eor	v5.16b,v5.16b,v6.16b
+	ror	w15,w15,#2
+	add	w10,w10,w6
+	sli	v7.4s,v4.4s,#14
+	eor	w14,w14,w8
+	ushr	v16.4s,v19.4s,#17
+	add	w5,w5,w12
+	add	w6,w6,w15
+	and	w12,w3,w10
+	eor	v5.16b,v5.16b,v7.16b
+	bic	w15,w4,w10
+	eor	w11,w10,w10,ror#5
+	sli	v16.4s,v19.4s,#15
+	add	w6,w6,w14
+	orr	w12,w12,w15
+	ushr	v17.4s,v19.4s,#10
+	eor	w11,w11,w10,ror#19
+	eor	w15,w6,w6,ror#11
+	ushr	v7.4s,v19.4s,#19
+	add	w5,w5,w12
+	ror	w11,w11,#6
+	add	v3.4s,v3.4s,v5.4s
+	eor	w14,w6,w7
+	eor	w15,w15,w6,ror#20
+	sli	v7.4s,v19.4s,#13
+	add	w5,w5,w11
+	ldr	w12,[sp,#56]
+	and	w13,w13,w14
+	eor	v17.16b,v17.16b,v16.16b
+	ror	w15,w15,#2
+	add	w9,w9,w5
+	eor	w13,w13,w7
+	eor	v17.16b,v17.16b,v7.16b
+	add	w4,w4,w12
+	add	w5,w5,w15
+	and	w12,w10,w9
+	add	v3.4s,v3.4s,v17.4s
+	bic	w15,w3,w9
+	eor	w11,w9,w9,ror#5
+	add	w5,w5,w13
+	ushr	v18.4s,v3.4s,#17
+	orr	w12,w12,w15
+	ushr	v19.4s,v3.4s,#10
+	eor	w11,w11,w9,ror#19
+	eor	w15,w5,w5,ror#11
+	sli	v18.4s,v3.4s,#15
+	add	w4,w4,w12
+	ushr	v17.4s,v3.4s,#19
+	ror	w11,w11,#6
+	eor	w13,w5,w6
+	eor	v19.16b,v19.16b,v18.16b
+	eor	w15,w15,w5,ror#20
+	add	w4,w4,w11
+	sli	v17.4s,v3.4s,#13
+	ldr	w12,[sp,#60]
+	and	w14,w14,w13
+	ror	w15,w15,#2
+	ld1	{v4.4s},[x16], #16
+	add	w8,w8,w4
+	eor	v19.16b,v19.16b,v17.16b
+	eor	w14,w14,w6
+	eor	v17.16b,v17.16b,v17.16b
+	add	w3,w3,w12
+	add	w4,w4,w15
+	and	w12,w9,w8
+	mov	v17.d[1],v19.d[0]
+	bic	w15,w10,w8
+	eor	w11,w8,w8,ror#5
+	add	w4,w4,w14
+	add	v3.4s,v3.4s,v17.4s
+	orr	w12,w12,w15
+	eor	w11,w11,w8,ror#19
+	eor	w15,w4,w4,ror#11
+	add	v4.4s,v4.4s,v3.4s
+	add	w3,w3,w12
+	ror	w11,w11,#6
+	eor	w14,w4,w5
+	eor	w15,w15,w4,ror#20
+	add	w3,w3,w11
+	ldr	w12,[x16]
+	and	w13,w13,w14
+	ror	w15,w15,#2
+	add	w7,w7,w3
+	eor	w13,w13,w5
+	st1	{v4.4s},[x17], #16
+	cmp	w12,#0				// check for K256 terminator
+	ldr	w12,[sp,#0]
+	sub	x17,x17,#64
+	bne	.L_00_48
+
+	sub	x16,x16,#256		// rewind x16
+	cmp	x1,x2
+	mov	x17, #64
+	csel	x17, x17, xzr, eq
+	sub	x1,x1,x17			// avoid SEGV
+	mov	x17,sp
+	add	w10,w10,w12
+	add	w3,w3,w15
+	and	w12,w8,w7
+	ld1	{v0.16b},[x1],#16
+	bic	w15,w9,w7
+	eor	w11,w7,w7,ror#5
+	ld1	{v4.4s},[x16],#16
+	add	w3,w3,w13
+	orr	w12,w12,w15
+	eor	w11,w11,w7,ror#19
+	eor	w15,w3,w3,ror#11
+	rev32	v0.16b,v0.16b
+	add	w10,w10,w12
+	ror	w11,w11,#6
+	eor	w13,w3,w4
+	eor	w15,w15,w3,ror#20
+	add	v4.4s,v4.4s,v0.4s
+	add	w10,w10,w11
+	ldr	w12,[sp,#4]
+	and	w14,w14,w13
+	ror	w15,w15,#2
+	add	w6,w6,w10
+	eor	w14,w14,w4
+	add	w9,w9,w12
+	add	w10,w10,w15
+	and	w12,w7,w6
+	bic	w15,w8,w6
+	eor	w11,w6,w6,ror#5
+	add	w10,w10,w14
+	orr	w12,w12,w15
+	eor	w11,w11,w6,ror#19
+	eor	w15,w10,w10,ror#11
+	add	w9,w9,w12
+	ror	w11,w11,#6
+	eor	w14,w10,w3
+	eor	w15,w15,w10,ror#20
+	add	w9,w9,w11
+	ldr	w12,[sp,#8]
+	and	w13,w13,w14
+	ror	w15,w15,#2
+	add	w5,w5,w9
+	eor	w13,w13,w3
+	add	w8,w8,w12
+	add	w9,w9,w15
+	and	w12,w6,w5
+	bic	w15,w7,w5
+	eor	w11,w5,w5,ror#5
+	add	w9,w9,w13
+	orr	w12,w12,w15
+	eor	w11,w11,w5,ror#19
+	eor	w15,w9,w9,ror#11
+	add	w8,w8,w12
+	ror	w11,w11,#6
+	eor	w13,w9,w10
+	eor	w15,w15,w9,ror#20
+	add	w8,w8,w11
+	ldr	w12,[sp,#12]
+	and	w14,w14,w13
+	ror	w15,w15,#2
+	add	w4,w4,w8
+	eor	w14,w14,w10
+	add	w7,w7,w12
+	add	w8,w8,w15
+	and	w12,w5,w4
+	bic	w15,w6,w4
+	eor	w11,w4,w4,ror#5
+	add	w8,w8,w14
+	orr	w12,w12,w15
+	eor	w11,w11,w4,ror#19
+	eor	w15,w8,w8,ror#11
+	add	w7,w7,w12
+	ror	w11,w11,#6
+	eor	w14,w8,w9
+	eor	w15,w15,w8,ror#20
+	add	w7,w7,w11
+	ldr	w12,[sp,#16]
+	and	w13,w13,w14
+	ror	w15,w15,#2
+	add	w3,w3,w7
+	eor	w13,w13,w9
+	st1	{v4.4s},[x17], #16
+	add	w6,w6,w12
+	add	w7,w7,w15
+	and	w12,w4,w3
+	ld1	{v1.16b},[x1],#16
+	bic	w15,w5,w3
+	eor	w11,w3,w3,ror#5
+	ld1	{v4.4s},[x16],#16
+	add	w7,w7,w13
+	orr	w12,w12,w15
+	eor	w11,w11,w3,ror#19
+	eor	w15,w7,w7,ror#11
+	rev32	v1.16b,v1.16b
+	add	w6,w6,w12
+	ror	w11,w11,#6
+	eor	w13,w7,w8
+	eor	w15,w15,w7,ror#20
+	add	v4.4s,v4.4s,v1.4s
+	add	w6,w6,w11
+	ldr	w12,[sp,#20]
+	and	w14,w14,w13
+	ror	w15,w15,#2
+	add	w10,w10,w6
+	eor	w14,w14,w8
+	add	w5,w5,w12
+	add	w6,w6,w15
+	and	w12,w3,w10
+	bic	w15,w4,w10
+	eor	w11,w10,w10,ror#5
+	add	w6,w6,w14
+	orr	w12,w12,w15
+	eor	w11,w11,w10,ror#19
+	eor	w15,w6,w6,ror#11
+	add	w5,w5,w12
+	ror	w11,w11,#6
+	eor	w14,w6,w7
+	eor	w15,w15,w6,ror#20
+	add	w5,w5,w11
+	ldr	w12,[sp,#24]
+	and	w13,w13,w14
+	ror	w15,w15,#2
+	add	w9,w9,w5
+	eor	w13,w13,w7
+	add	w4,w4,w12
+	add	w5,w5,w15
+	and	w12,w10,w9
+	bic	w15,w3,w9
+	eor	w11,w9,w9,ror#5
+	add	w5,w5,w13
+	orr	w12,w12,w15
+	eor	w11,w11,w9,ror#19
+	eor	w15,w5,w5,ror#11
+	add	w4,w4,w12
+	ror	w11,w11,#6
+	eor	w13,w5,w6
+	eor	w15,w15,w5,ror#20
+	add	w4,w4,w11
+	ldr	w12,[sp,#28]
+	and	w14,w14,w13
+	ror	w15,w15,#2
+	add	w8,w8,w4
+	eor	w14,w14,w6
+	add	w3,w3,w12
+	add	w4,w4,w15
+	and	w12,w9,w8
+	bic	w15,w10,w8
+	eor	w11,w8,w8,ror#5
+	add	w4,w4,w14
+	orr	w12,w12,w15
+	eor	w11,w11,w8,ror#19
+	eor	w15,w4,w4,ror#11
+	add	w3,w3,w12
+	ror	w11,w11,#6
+	eor	w14,w4,w5
+	eor	w15,w15,w4,ror#20
+	add	w3,w3,w11
+	ldr	w12,[sp,#32]
+	and	w13,w13,w14
+	ror	w15,w15,#2
+	add	w7,w7,w3
+	eor	w13,w13,w5
+	st1	{v4.4s},[x17], #16
+	add	w10,w10,w12
+	add	w3,w3,w15
+	and	w12,w8,w7
+	ld1	{v2.16b},[x1],#16
+	bic	w15,w9,w7
+	eor	w11,w7,w7,ror#5
+	ld1	{v4.4s},[x16],#16
+	add	w3,w3,w13
+	orr	w12,w12,w15
+	eor	w11,w11,w7,ror#19
+	eor	w15,w3,w3,ror#11
+	rev32	v2.16b,v2.16b
+	add	w10,w10,w12
+	ror	w11,w11,#6
+	eor	w13,w3,w4
+	eor	w15,w15,w3,ror#20
+	add	v4.4s,v4.4s,v2.4s
+	add	w10,w10,w11
+	ldr	w12,[sp,#36]
+	and	w14,w14,w13
+	ror	w15,w15,#2
+	add	w6,w6,w10
+	eor	w14,w14,w4
+	add	w9,w9,w12
+	add	w10,w10,w15
+	and	w12,w7,w6
+	bic	w15,w8,w6
+	eor	w11,w6,w6,ror#5
+	add	w10,w10,w14
+	orr	w12,w12,w15
+	eor	w11,w11,w6,ror#19
+	eor	w15,w10,w10,ror#11
+	add	w9,w9,w12
+	ror	w11,w11,#6
+	eor	w14,w10,w3
+	eor	w15,w15,w10,ror#20
+	add	w9,w9,w11
+	ldr	w12,[sp,#40]
+	and	w13,w13,w14
+	ror	w15,w15,#2
+	add	w5,w5,w9
+	eor	w13,w13,w3
+	add	w8,w8,w12
+	add	w9,w9,w15
+	and	w12,w6,w5
+	bic	w15,w7,w5
+	eor	w11,w5,w5,ror#5
+	add	w9,w9,w13
+	orr	w12,w12,w15
+	eor	w11,w11,w5,ror#19
+	eor	w15,w9,w9,ror#11
+	add	w8,w8,w12
+	ror	w11,w11,#6
+	eor	w13,w9,w10
+	eor	w15,w15,w9,ror#20
+	add	w8,w8,w11
+	ldr	w12,[sp,#44]
+	and	w14,w14,w13
+	ror	w15,w15,#2
+	add	w4,w4,w8
+	eor	w14,w14,w10
+	add	w7,w7,w12
+	add	w8,w8,w15
+	and	w12,w5,w4
+	bic	w15,w6,w4
+	eor	w11,w4,w4,ror#5
+	add	w8,w8,w14
+	orr	w12,w12,w15
+	eor	w11,w11,w4,ror#19
+	eor	w15,w8,w8,ror#11
+	add	w7,w7,w12
+	ror	w11,w11,#6
+	eor	w14,w8,w9
+	eor	w15,w15,w8,ror#20
+	add	w7,w7,w11
+	ldr	w12,[sp,#48]
+	and	w13,w13,w14
+	ror	w15,w15,#2
+	add	w3,w3,w7
+	eor	w13,w13,w9
+	st1	{v4.4s},[x17], #16
+	add	w6,w6,w12
+	add	w7,w7,w15
+	and	w12,w4,w3
+	ld1	{v3.16b},[x1],#16
+	bic	w15,w5,w3
+	eor	w11,w3,w3,ror#5
+	ld1	{v4.4s},[x16],#16
+	add	w7,w7,w13
+	orr	w12,w12,w15
+	eor	w11,w11,w3,ror#19
+	eor	w15,w7,w7,ror#11
+	rev32	v3.16b,v3.16b
+	add	w6,w6,w12
+	ror	w11,w11,#6
+	eor	w13,w7,w8
+	eor	w15,w15,w7,ror#20
+	add	v4.4s,v4.4s,v3.4s
+	add	w6,w6,w11
+	ldr	w12,[sp,#52]
+	and	w14,w14,w13
+	ror	w15,w15,#2
+	add	w10,w10,w6
+	eor	w14,w14,w8
+	add	w5,w5,w12
+	add	w6,w6,w15
+	and	w12,w3,w10
+	bic	w15,w4,w10
+	eor	w11,w10,w10,ror#5
+	add	w6,w6,w14
+	orr	w12,w12,w15
+	eor	w11,w11,w10,ror#19
+	eor	w15,w6,w6,ror#11
+	add	w5,w5,w12
+	ror	w11,w11,#6
+	eor	w14,w6,w7
+	eor	w15,w15,w6,ror#20
+	add	w5,w5,w11
+	ldr	w12,[sp,#56]
+	and	w13,w13,w14
+	ror	w15,w15,#2
+	add	w9,w9,w5
+	eor	w13,w13,w7
+	add	w4,w4,w12
+	add	w5,w5,w15
+	and	w12,w10,w9
+	bic	w15,w3,w9
+	eor	w11,w9,w9,ror#5
+	add	w5,w5,w13
+	orr	w12,w12,w15
+	eor	w11,w11,w9,ror#19
+	eor	w15,w5,w5,ror#11
+	add	w4,w4,w12
+	ror	w11,w11,#6
+	eor	w13,w5,w6
+	eor	w15,w15,w5,ror#20
+	add	w4,w4,w11
+	ldr	w12,[sp,#60]
+	and	w14,w14,w13
+	ror	w15,w15,#2
+	add	w8,w8,w4
+	eor	w14,w14,w6
+	add	w3,w3,w12
+	add	w4,w4,w15
+	and	w12,w9,w8
+	bic	w15,w10,w8
+	eor	w11,w8,w8,ror#5
+	add	w4,w4,w14
+	orr	w12,w12,w15
+	eor	w11,w11,w8,ror#19
+	eor	w15,w4,w4,ror#11
+	add	w3,w3,w12
+	ror	w11,w11,#6
+	eor	w14,w4,w5
+	eor	w15,w15,w4,ror#20
+	add	w3,w3,w11
+	and	w13,w13,w14
+	ror	w15,w15,#2
+	add	w7,w7,w3
+	eor	w13,w13,w5
+	st1	{v4.4s},[x17], #16
+	add	w3,w3,w15			// h+=Sigma0(a) from the past
+	ldp	w11,w12,[x0,#0]
+	add	w3,w3,w13			// h+=Maj(a,b,c) from the past
+	ldp	w13,w14,[x0,#8]
+	add	w3,w3,w11			// accumulate
+	add	w4,w4,w12
+	ldp	w11,w12,[x0,#16]
+	add	w5,w5,w13
+	add	w6,w6,w14
+	ldp	w13,w14,[x0,#24]
+	add	w7,w7,w11
+	add	w8,w8,w12
+	 ldr	w12,[sp,#0]
+	stp	w3,w4,[x0,#0]
+	add	w9,w9,w13
+	 mov	w13,wzr
+	stp	w5,w6,[x0,#8]
+	add	w10,w10,w14
+	stp	w7,w8,[x0,#16]
+	 eor	w14,w4,w5
+	stp	w9,w10,[x0,#24]
+	 mov	w15,wzr
+	 mov	x17,sp
+	b.ne	.L_00_48
+
+	ldr	x29,[x29]
+	add	sp,sp,#16*4+16
+	ret
+.size	sha256_block_neon,.-sha256_block_neon
+#ifndef	__KERNEL__
+.comm	OPENSSL_armcap_P,4,4
+#endif
diff --git a/arch/arm64/crypto/sha512-core.S b/arch/arm64/crypto/sha512-core.S
new file mode 100644
index 0000000..bd0f59f
--- /dev/null
+++ b/arch/arm64/crypto/sha512-core.S
@@ -0,0 +1,1085 @@
+// Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
+//
+// Licensed under the OpenSSL license (the "License").  You may not use
+// this file except in compliance with the License.  You can obtain a copy
+// in the file LICENSE in the source distribution or at
+// https://www.openssl.org/source/license.html
+
+// ====================================================================
+// Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+// project. The module is, however, dual licensed under OpenSSL and
+// CRYPTOGAMS licenses depending on where you obtain it. For further
+// details see http://www.openssl.org/~appro/cryptogams/.
+//
+// Permission to use under GPLv2 terms is granted.
+// ====================================================================
+//
+// SHA256/512 for ARMv8.
+//
+// Performance in cycles per processed byte and improvement coefficient
+// over code generated with "default" compiler:
+//
+//		SHA256-hw	SHA256(*)	SHA512
+// Apple A7	1.97		10.5 (+33%)	6.73 (-1%(**))
+// Cortex-A53	2.38		15.5 (+115%)	10.0 (+150%(***))
+// Cortex-A57	2.31		11.6 (+86%)	7.51 (+260%(***))
+// Denver	2.01		10.5 (+26%)	6.70 (+8%)
+// X-Gene			20.0 (+100%)	12.8 (+300%(***))
+// Mongoose	2.36		13.0 (+50%)	8.36 (+33%)
+//
+// (*)	Software SHA256 results are of lesser relevance, presented
+//	mostly for informational purposes.
+// (**)	The result is a trade-off: it's possible to improve it by
+//	10% (or by 1 cycle per round), but at the cost of 20% loss
+//	on Cortex-A53 (or by 4 cycles per round).
+// (***)	Super-impressive coefficients over gcc-generated code are
+//	indication of some compiler "pathology", most notably code
+//	generated with -mgeneral-regs-only is significanty faster
+//	and the gap is only 40-90%.
+//
+// October 2016.
+//
+// Originally it was reckoned that it makes no sense to implement NEON
+// version of SHA256 for 64-bit processors. This is because performance
+// improvement on most wide-spread Cortex-A5x processors was observed
+// to be marginal, same on Cortex-A53 and ~10% on A57. But then it was
+// observed that 32-bit NEON SHA256 performs significantly better than
+// 64-bit scalar version on *some* of the more recent processors. As
+// result 64-bit NEON version of SHA256 was added to provide best
+// all-round performance. For example it executes ~30% faster on X-Gene
+// and Mongoose. [For reference, NEON version of SHA512 is bound to
+// deliver much less improvement, likely *negative* on Cortex-A5x.
+// Which is why NEON support is limited to SHA256.]
+
+#ifndef	__KERNEL__
+# include "arm_arch.h"
+#endif
+
+.text
+
+.extern	OPENSSL_armcap_P
+.globl	sha512_block_data_order
+.type	sha512_block_data_order,%function
+.align	6
+sha512_block_data_order:
+	stp	x29,x30,[sp,#-128]!
+	add	x29,sp,#0
+
+	stp	x19,x20,[sp,#16]
+	stp	x21,x22,[sp,#32]
+	stp	x23,x24,[sp,#48]
+	stp	x25,x26,[sp,#64]
+	stp	x27,x28,[sp,#80]
+	sub	sp,sp,#4*8
+
+	ldp	x20,x21,[x0]				// load context
+	ldp	x22,x23,[x0,#2*8]
+	ldp	x24,x25,[x0,#4*8]
+	add	x2,x1,x2,lsl#7	// end of input
+	ldp	x26,x27,[x0,#6*8]
+	adr	x30,.LK512
+	stp	x0,x2,[x29,#96]
+
+.Loop:
+	ldp	x3,x4,[x1],#2*8
+	ldr	x19,[x30],#8			// *K++
+	eor	x28,x21,x22				// magic seed
+	str	x1,[x29,#112]
+#ifndef	__AARCH64EB__
+	rev	x3,x3			// 0
+#endif
+	ror	x16,x24,#14
+	add	x27,x27,x19			// h+=K[i]
+	eor	x6,x24,x24,ror#23
+	and	x17,x25,x24
+	bic	x19,x26,x24
+	add	x27,x27,x3			// h+=X[i]
+	orr	x17,x17,x19			// Ch(e,f,g)
+	eor	x19,x20,x21			// a^b, b^c in next round
+	eor	x16,x16,x6,ror#18	// Sigma1(e)
+	ror	x6,x20,#28
+	add	x27,x27,x17			// h+=Ch(e,f,g)
+	eor	x17,x20,x20,ror#5
+	add	x27,x27,x16			// h+=Sigma1(e)
+	and	x28,x28,x19			// (b^c)&=(a^b)
+	add	x23,x23,x27			// d+=h
+	eor	x28,x28,x21			// Maj(a,b,c)
+	eor	x17,x6,x17,ror#34	// Sigma0(a)
+	add	x27,x27,x28			// h+=Maj(a,b,c)
+	ldr	x28,[x30],#8		// *K++, x19 in next round
+	//add	x27,x27,x17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	x4,x4			// 1
+#endif
+	ldp	x5,x6,[x1],#2*8
+	add	x27,x27,x17			// h+=Sigma0(a)
+	ror	x16,x23,#14
+	add	x26,x26,x28			// h+=K[i]
+	eor	x7,x23,x23,ror#23
+	and	x17,x24,x23
+	bic	x28,x25,x23
+	add	x26,x26,x4			// h+=X[i]
+	orr	x17,x17,x28			// Ch(e,f,g)
+	eor	x28,x27,x20			// a^b, b^c in next round
+	eor	x16,x16,x7,ror#18	// Sigma1(e)
+	ror	x7,x27,#28
+	add	x26,x26,x17			// h+=Ch(e,f,g)
+	eor	x17,x27,x27,ror#5
+	add	x26,x26,x16			// h+=Sigma1(e)
+	and	x19,x19,x28			// (b^c)&=(a^b)
+	add	x22,x22,x26			// d+=h
+	eor	x19,x19,x20			// Maj(a,b,c)
+	eor	x17,x7,x17,ror#34	// Sigma0(a)
+	add	x26,x26,x19			// h+=Maj(a,b,c)
+	ldr	x19,[x30],#8		// *K++, x28 in next round
+	//add	x26,x26,x17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	x5,x5			// 2
+#endif
+	add	x26,x26,x17			// h+=Sigma0(a)
+	ror	x16,x22,#14
+	add	x25,x25,x19			// h+=K[i]
+	eor	x8,x22,x22,ror#23
+	and	x17,x23,x22
+	bic	x19,x24,x22
+	add	x25,x25,x5			// h+=X[i]
+	orr	x17,x17,x19			// Ch(e,f,g)
+	eor	x19,x26,x27			// a^b, b^c in next round
+	eor	x16,x16,x8,ror#18	// Sigma1(e)
+	ror	x8,x26,#28
+	add	x25,x25,x17			// h+=Ch(e,f,g)
+	eor	x17,x26,x26,ror#5
+	add	x25,x25,x16			// h+=Sigma1(e)
+	and	x28,x28,x19			// (b^c)&=(a^b)
+	add	x21,x21,x25			// d+=h
+	eor	x28,x28,x27			// Maj(a,b,c)
+	eor	x17,x8,x17,ror#34	// Sigma0(a)
+	add	x25,x25,x28			// h+=Maj(a,b,c)
+	ldr	x28,[x30],#8		// *K++, x19 in next round
+	//add	x25,x25,x17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	x6,x6			// 3
+#endif
+	ldp	x7,x8,[x1],#2*8
+	add	x25,x25,x17			// h+=Sigma0(a)
+	ror	x16,x21,#14
+	add	x24,x24,x28			// h+=K[i]
+	eor	x9,x21,x21,ror#23
+	and	x17,x22,x21
+	bic	x28,x23,x21
+	add	x24,x24,x6			// h+=X[i]
+	orr	x17,x17,x28			// Ch(e,f,g)
+	eor	x28,x25,x26			// a^b, b^c in next round
+	eor	x16,x16,x9,ror#18	// Sigma1(e)
+	ror	x9,x25,#28
+	add	x24,x24,x17			// h+=Ch(e,f,g)
+	eor	x17,x25,x25,ror#5
+	add	x24,x24,x16			// h+=Sigma1(e)
+	and	x19,x19,x28			// (b^c)&=(a^b)
+	add	x20,x20,x24			// d+=h
+	eor	x19,x19,x26			// Maj(a,b,c)
+	eor	x17,x9,x17,ror#34	// Sigma0(a)
+	add	x24,x24,x19			// h+=Maj(a,b,c)
+	ldr	x19,[x30],#8		// *K++, x28 in next round
+	//add	x24,x24,x17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	x7,x7			// 4
+#endif
+	add	x24,x24,x17			// h+=Sigma0(a)
+	ror	x16,x20,#14
+	add	x23,x23,x19			// h+=K[i]
+	eor	x10,x20,x20,ror#23
+	and	x17,x21,x20
+	bic	x19,x22,x20
+	add	x23,x23,x7			// h+=X[i]
+	orr	x17,x17,x19			// Ch(e,f,g)
+	eor	x19,x24,x25			// a^b, b^c in next round
+	eor	x16,x16,x10,ror#18	// Sigma1(e)
+	ror	x10,x24,#28
+	add	x23,x23,x17			// h+=Ch(e,f,g)
+	eor	x17,x24,x24,ror#5
+	add	x23,x23,x16			// h+=Sigma1(e)
+	and	x28,x28,x19			// (b^c)&=(a^b)
+	add	x27,x27,x23			// d+=h
+	eor	x28,x28,x25			// Maj(a,b,c)
+	eor	x17,x10,x17,ror#34	// Sigma0(a)
+	add	x23,x23,x28			// h+=Maj(a,b,c)
+	ldr	x28,[x30],#8		// *K++, x19 in next round
+	//add	x23,x23,x17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	x8,x8			// 5
+#endif
+	ldp	x9,x10,[x1],#2*8
+	add	x23,x23,x17			// h+=Sigma0(a)
+	ror	x16,x27,#14
+	add	x22,x22,x28			// h+=K[i]
+	eor	x11,x27,x27,ror#23
+	and	x17,x20,x27
+	bic	x28,x21,x27
+	add	x22,x22,x8			// h+=X[i]
+	orr	x17,x17,x28			// Ch(e,f,g)
+	eor	x28,x23,x24			// a^b, b^c in next round
+	eor	x16,x16,x11,ror#18	// Sigma1(e)
+	ror	x11,x23,#28
+	add	x22,x22,x17			// h+=Ch(e,f,g)
+	eor	x17,x23,x23,ror#5
+	add	x22,x22,x16			// h+=Sigma1(e)
+	and	x19,x19,x28			// (b^c)&=(a^b)
+	add	x26,x26,x22			// d+=h
+	eor	x19,x19,x24			// Maj(a,b,c)
+	eor	x17,x11,x17,ror#34	// Sigma0(a)
+	add	x22,x22,x19			// h+=Maj(a,b,c)
+	ldr	x19,[x30],#8		// *K++, x28 in next round
+	//add	x22,x22,x17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	x9,x9			// 6
+#endif
+	add	x22,x22,x17			// h+=Sigma0(a)
+	ror	x16,x26,#14
+	add	x21,x21,x19			// h+=K[i]
+	eor	x12,x26,x26,ror#23
+	and	x17,x27,x26
+	bic	x19,x20,x26
+	add	x21,x21,x9			// h+=X[i]
+	orr	x17,x17,x19			// Ch(e,f,g)
+	eor	x19,x22,x23			// a^b, b^c in next round
+	eor	x16,x16,x12,ror#18	// Sigma1(e)
+	ror	x12,x22,#28
+	add	x21,x21,x17			// h+=Ch(e,f,g)
+	eor	x17,x22,x22,ror#5
+	add	x21,x21,x16			// h+=Sigma1(e)
+	and	x28,x28,x19			// (b^c)&=(a^b)
+	add	x25,x25,x21			// d+=h
+	eor	x28,x28,x23			// Maj(a,b,c)
+	eor	x17,x12,x17,ror#34	// Sigma0(a)
+	add	x21,x21,x28			// h+=Maj(a,b,c)
+	ldr	x28,[x30],#8		// *K++, x19 in next round
+	//add	x21,x21,x17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	x10,x10			// 7
+#endif
+	ldp	x11,x12,[x1],#2*8
+	add	x21,x21,x17			// h+=Sigma0(a)
+	ror	x16,x25,#14
+	add	x20,x20,x28			// h+=K[i]
+	eor	x13,x25,x25,ror#23
+	and	x17,x26,x25
+	bic	x28,x27,x25
+	add	x20,x20,x10			// h+=X[i]
+	orr	x17,x17,x28			// Ch(e,f,g)
+	eor	x28,x21,x22			// a^b, b^c in next round
+	eor	x16,x16,x13,ror#18	// Sigma1(e)
+	ror	x13,x21,#28
+	add	x20,x20,x17			// h+=Ch(e,f,g)
+	eor	x17,x21,x21,ror#5
+	add	x20,x20,x16			// h+=Sigma1(e)
+	and	x19,x19,x28			// (b^c)&=(a^b)
+	add	x24,x24,x20			// d+=h
+	eor	x19,x19,x22			// Maj(a,b,c)
+	eor	x17,x13,x17,ror#34	// Sigma0(a)
+	add	x20,x20,x19			// h+=Maj(a,b,c)
+	ldr	x19,[x30],#8		// *K++, x28 in next round
+	//add	x20,x20,x17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	x11,x11			// 8
+#endif
+	add	x20,x20,x17			// h+=Sigma0(a)
+	ror	x16,x24,#14
+	add	x27,x27,x19			// h+=K[i]
+	eor	x14,x24,x24,ror#23
+	and	x17,x25,x24
+	bic	x19,x26,x24
+	add	x27,x27,x11			// h+=X[i]
+	orr	x17,x17,x19			// Ch(e,f,g)
+	eor	x19,x20,x21			// a^b, b^c in next round
+	eor	x16,x16,x14,ror#18	// Sigma1(e)
+	ror	x14,x20,#28
+	add	x27,x27,x17			// h+=Ch(e,f,g)
+	eor	x17,x20,x20,ror#5
+	add	x27,x27,x16			// h+=Sigma1(e)
+	and	x28,x28,x19			// (b^c)&=(a^b)
+	add	x23,x23,x27			// d+=h
+	eor	x28,x28,x21			// Maj(a,b,c)
+	eor	x17,x14,x17,ror#34	// Sigma0(a)
+	add	x27,x27,x28			// h+=Maj(a,b,c)
+	ldr	x28,[x30],#8		// *K++, x19 in next round
+	//add	x27,x27,x17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	x12,x12			// 9
+#endif
+	ldp	x13,x14,[x1],#2*8
+	add	x27,x27,x17			// h+=Sigma0(a)
+	ror	x16,x23,#14
+	add	x26,x26,x28			// h+=K[i]
+	eor	x15,x23,x23,ror#23
+	and	x17,x24,x23
+	bic	x28,x25,x23
+	add	x26,x26,x12			// h+=X[i]
+	orr	x17,x17,x28			// Ch(e,f,g)
+	eor	x28,x27,x20			// a^b, b^c in next round
+	eor	x16,x16,x15,ror#18	// Sigma1(e)
+	ror	x15,x27,#28
+	add	x26,x26,x17			// h+=Ch(e,f,g)
+	eor	x17,x27,x27,ror#5
+	add	x26,x26,x16			// h+=Sigma1(e)
+	and	x19,x19,x28			// (b^c)&=(a^b)
+	add	x22,x22,x26			// d+=h
+	eor	x19,x19,x20			// Maj(a,b,c)
+	eor	x17,x15,x17,ror#34	// Sigma0(a)
+	add	x26,x26,x19			// h+=Maj(a,b,c)
+	ldr	x19,[x30],#8		// *K++, x28 in next round
+	//add	x26,x26,x17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	x13,x13			// 10
+#endif
+	add	x26,x26,x17			// h+=Sigma0(a)
+	ror	x16,x22,#14
+	add	x25,x25,x19			// h+=K[i]
+	eor	x0,x22,x22,ror#23
+	and	x17,x23,x22
+	bic	x19,x24,x22
+	add	x25,x25,x13			// h+=X[i]
+	orr	x17,x17,x19			// Ch(e,f,g)
+	eor	x19,x26,x27			// a^b, b^c in next round
+	eor	x16,x16,x0,ror#18	// Sigma1(e)
+	ror	x0,x26,#28
+	add	x25,x25,x17			// h+=Ch(e,f,g)
+	eor	x17,x26,x26,ror#5
+	add	x25,x25,x16			// h+=Sigma1(e)
+	and	x28,x28,x19			// (b^c)&=(a^b)
+	add	x21,x21,x25			// d+=h
+	eor	x28,x28,x27			// Maj(a,b,c)
+	eor	x17,x0,x17,ror#34	// Sigma0(a)
+	add	x25,x25,x28			// h+=Maj(a,b,c)
+	ldr	x28,[x30],#8		// *K++, x19 in next round
+	//add	x25,x25,x17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	x14,x14			// 11
+#endif
+	ldp	x15,x0,[x1],#2*8
+	add	x25,x25,x17			// h+=Sigma0(a)
+	str	x6,[sp,#24]
+	ror	x16,x21,#14
+	add	x24,x24,x28			// h+=K[i]
+	eor	x6,x21,x21,ror#23
+	and	x17,x22,x21
+	bic	x28,x23,x21
+	add	x24,x24,x14			// h+=X[i]
+	orr	x17,x17,x28			// Ch(e,f,g)
+	eor	x28,x25,x26			// a^b, b^c in next round
+	eor	x16,x16,x6,ror#18	// Sigma1(e)
+	ror	x6,x25,#28
+	add	x24,x24,x17			// h+=Ch(e,f,g)
+	eor	x17,x25,x25,ror#5
+	add	x24,x24,x16			// h+=Sigma1(e)
+	and	x19,x19,x28			// (b^c)&=(a^b)
+	add	x20,x20,x24			// d+=h
+	eor	x19,x19,x26			// Maj(a,b,c)
+	eor	x17,x6,x17,ror#34	// Sigma0(a)
+	add	x24,x24,x19			// h+=Maj(a,b,c)
+	ldr	x19,[x30],#8		// *K++, x28 in next round
+	//add	x24,x24,x17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	x15,x15			// 12
+#endif
+	add	x24,x24,x17			// h+=Sigma0(a)
+	str	x7,[sp,#0]
+	ror	x16,x20,#14
+	add	x23,x23,x19			// h+=K[i]
+	eor	x7,x20,x20,ror#23
+	and	x17,x21,x20
+	bic	x19,x22,x20
+	add	x23,x23,x15			// h+=X[i]
+	orr	x17,x17,x19			// Ch(e,f,g)
+	eor	x19,x24,x25			// a^b, b^c in next round
+	eor	x16,x16,x7,ror#18	// Sigma1(e)
+	ror	x7,x24,#28
+	add	x23,x23,x17			// h+=Ch(e,f,g)
+	eor	x17,x24,x24,ror#5
+	add	x23,x23,x16			// h+=Sigma1(e)
+	and	x28,x28,x19			// (b^c)&=(a^b)
+	add	x27,x27,x23			// d+=h
+	eor	x28,x28,x25			// Maj(a,b,c)
+	eor	x17,x7,x17,ror#34	// Sigma0(a)
+	add	x23,x23,x28			// h+=Maj(a,b,c)
+	ldr	x28,[x30],#8		// *K++, x19 in next round
+	//add	x23,x23,x17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	x0,x0			// 13
+#endif
+	ldp	x1,x2,[x1]
+	add	x23,x23,x17			// h+=Sigma0(a)
+	str	x8,[sp,#8]
+	ror	x16,x27,#14
+	add	x22,x22,x28			// h+=K[i]
+	eor	x8,x27,x27,ror#23
+	and	x17,x20,x27
+	bic	x28,x21,x27
+	add	x22,x22,x0			// h+=X[i]
+	orr	x17,x17,x28			// Ch(e,f,g)
+	eor	x28,x23,x24			// a^b, b^c in next round
+	eor	x16,x16,x8,ror#18	// Sigma1(e)
+	ror	x8,x23,#28
+	add	x22,x22,x17			// h+=Ch(e,f,g)
+	eor	x17,x23,x23,ror#5
+	add	x22,x22,x16			// h+=Sigma1(e)
+	and	x19,x19,x28			// (b^c)&=(a^b)
+	add	x26,x26,x22			// d+=h
+	eor	x19,x19,x24			// Maj(a,b,c)
+	eor	x17,x8,x17,ror#34	// Sigma0(a)
+	add	x22,x22,x19			// h+=Maj(a,b,c)
+	ldr	x19,[x30],#8		// *K++, x28 in next round
+	//add	x22,x22,x17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	x1,x1			// 14
+#endif
+	ldr	x6,[sp,#24]
+	add	x22,x22,x17			// h+=Sigma0(a)
+	str	x9,[sp,#16]
+	ror	x16,x26,#14
+	add	x21,x21,x19			// h+=K[i]
+	eor	x9,x26,x26,ror#23
+	and	x17,x27,x26
+	bic	x19,x20,x26
+	add	x21,x21,x1			// h+=X[i]
+	orr	x17,x17,x19			// Ch(e,f,g)
+	eor	x19,x22,x23			// a^b, b^c in next round
+	eor	x16,x16,x9,ror#18	// Sigma1(e)
+	ror	x9,x22,#28
+	add	x21,x21,x17			// h+=Ch(e,f,g)
+	eor	x17,x22,x22,ror#5
+	add	x21,x21,x16			// h+=Sigma1(e)
+	and	x28,x28,x19			// (b^c)&=(a^b)
+	add	x25,x25,x21			// d+=h
+	eor	x28,x28,x23			// Maj(a,b,c)
+	eor	x17,x9,x17,ror#34	// Sigma0(a)
+	add	x21,x21,x28			// h+=Maj(a,b,c)
+	ldr	x28,[x30],#8		// *K++, x19 in next round
+	//add	x21,x21,x17			// h+=Sigma0(a)
+#ifndef	__AARCH64EB__
+	rev	x2,x2			// 15
+#endif
+	ldr	x7,[sp,#0]
+	add	x21,x21,x17			// h+=Sigma0(a)
+	str	x10,[sp,#24]
+	ror	x16,x25,#14
+	add	x20,x20,x28			// h+=K[i]
+	ror	x9,x4,#1
+	and	x17,x26,x25
+	ror	x8,x1,#19
+	bic	x28,x27,x25
+	ror	x10,x21,#28
+	add	x20,x20,x2			// h+=X[i]
+	eor	x16,x16,x25,ror#18
+	eor	x9,x9,x4,ror#8
+	orr	x17,x17,x28			// Ch(e,f,g)
+	eor	x28,x21,x22			// a^b, b^c in next round
+	eor	x16,x16,x25,ror#41	// Sigma1(e)
+	eor	x10,x10,x21,ror#34
+	add	x20,x20,x17			// h+=Ch(e,f,g)
+	and	x19,x19,x28			// (b^c)&=(a^b)
+	eor	x8,x8,x1,ror#61
+	eor	x9,x9,x4,lsr#7	// sigma0(X[i+1])
+	add	x20,x20,x16			// h+=Sigma1(e)
+	eor	x19,x19,x22			// Maj(a,b,c)
+	eor	x17,x10,x21,ror#39	// Sigma0(a)
+	eor	x8,x8,x1,lsr#6	// sigma1(X[i+14])
+	add	x3,x3,x12
+	add	x24,x24,x20			// d+=h
+	add	x20,x20,x19			// h+=Maj(a,b,c)
+	ldr	x19,[x30],#8		// *K++, x28 in next round
+	add	x3,x3,x9
+	add	x20,x20,x17			// h+=Sigma0(a)
+	add	x3,x3,x8
+.Loop_16_xx:
+	ldr	x8,[sp,#8]
+	str	x11,[sp,#0]
+	ror	x16,x24,#14
+	add	x27,x27,x19			// h+=K[i]
+	ror	x10,x5,#1
+	and	x17,x25,x24
+	ror	x9,x2,#19
+	bic	x19,x26,x24
+	ror	x11,x20,#28
+	add	x27,x27,x3			// h+=X[i]
+	eor	x16,x16,x24,ror#18
+	eor	x10,x10,x5,ror#8
+	orr	x17,x17,x19			// Ch(e,f,g)
+	eor	x19,x20,x21			// a^b, b^c in next round
+	eor	x16,x16,x24,ror#41	// Sigma1(e)
+	eor	x11,x11,x20,ror#34
+	add	x27,x27,x17			// h+=Ch(e,f,g)
+	and	x28,x28,x19			// (b^c)&=(a^b)
+	eor	x9,x9,x2,ror#61
+	eor	x10,x10,x5,lsr#7	// sigma0(X[i+1])
+	add	x27,x27,x16			// h+=Sigma1(e)
+	eor	x28,x28,x21			// Maj(a,b,c)
+	eor	x17,x11,x20,ror#39	// Sigma0(a)
+	eor	x9,x9,x2,lsr#6	// sigma1(X[i+14])
+	add	x4,x4,x13
+	add	x23,x23,x27			// d+=h
+	add	x27,x27,x28			// h+=Maj(a,b,c)
+	ldr	x28,[x30],#8		// *K++, x19 in next round
+	add	x4,x4,x10
+	add	x27,x27,x17			// h+=Sigma0(a)
+	add	x4,x4,x9
+	ldr	x9,[sp,#16]
+	str	x12,[sp,#8]
+	ror	x16,x23,#14
+	add	x26,x26,x28			// h+=K[i]
+	ror	x11,x6,#1
+	and	x17,x24,x23
+	ror	x10,x3,#19
+	bic	x28,x25,x23
+	ror	x12,x27,#28
+	add	x26,x26,x4			// h+=X[i]
+	eor	x16,x16,x23,ror#18
+	eor	x11,x11,x6,ror#8
+	orr	x17,x17,x28			// Ch(e,f,g)
+	eor	x28,x27,x20			// a^b, b^c in next round
+	eor	x16,x16,x23,ror#41	// Sigma1(e)
+	eor	x12,x12,x27,ror#34
+	add	x26,x26,x17			// h+=Ch(e,f,g)
+	and	x19,x19,x28			// (b^c)&=(a^b)
+	eor	x10,x10,x3,ror#61
+	eor	x11,x11,x6,lsr#7	// sigma0(X[i+1])
+	add	x26,x26,x16			// h+=Sigma1(e)
+	eor	x19,x19,x20			// Maj(a,b,c)
+	eor	x17,x12,x27,ror#39	// Sigma0(a)
+	eor	x10,x10,x3,lsr#6	// sigma1(X[i+14])
+	add	x5,x5,x14
+	add	x22,x22,x26			// d+=h
+	add	x26,x26,x19			// h+=Maj(a,b,c)
+	ldr	x19,[x30],#8		// *K++, x28 in next round
+	add	x5,x5,x11
+	add	x26,x26,x17			// h+=Sigma0(a)
+	add	x5,x5,x10
+	ldr	x10,[sp,#24]
+	str	x13,[sp,#16]
+	ror	x16,x22,#14
+	add	x25,x25,x19			// h+=K[i]
+	ror	x12,x7,#1
+	and	x17,x23,x22
+	ror	x11,x4,#19
+	bic	x19,x24,x22
+	ror	x13,x26,#28
+	add	x25,x25,x5			// h+=X[i]
+	eor	x16,x16,x22,ror#18
+	eor	x12,x12,x7,ror#8
+	orr	x17,x17,x19			// Ch(e,f,g)
+	eor	x19,x26,x27			// a^b, b^c in next round
+	eor	x16,x16,x22,ror#41	// Sigma1(e)
+	eor	x13,x13,x26,ror#34
+	add	x25,x25,x17			// h+=Ch(e,f,g)
+	and	x28,x28,x19			// (b^c)&=(a^b)
+	eor	x11,x11,x4,ror#61
+	eor	x12,x12,x7,lsr#7	// sigma0(X[i+1])
+	add	x25,x25,x16			// h+=Sigma1(e)
+	eor	x28,x28,x27			// Maj(a,b,c)
+	eor	x17,x13,x26,ror#39	// Sigma0(a)
+	eor	x11,x11,x4,lsr#6	// sigma1(X[i+14])
+	add	x6,x6,x15
+	add	x21,x21,x25			// d+=h
+	add	x25,x25,x28			// h+=Maj(a,b,c)
+	ldr	x28,[x30],#8		// *K++, x19 in next round
+	add	x6,x6,x12
+	add	x25,x25,x17			// h+=Sigma0(a)
+	add	x6,x6,x11
+	ldr	x11,[sp,#0]
+	str	x14,[sp,#24]
+	ror	x16,x21,#14
+	add	x24,x24,x28			// h+=K[i]
+	ror	x13,x8,#1
+	and	x17,x22,x21
+	ror	x12,x5,#19
+	bic	x28,x23,x21
+	ror	x14,x25,#28
+	add	x24,x24,x6			// h+=X[i]
+	eor	x16,x16,x21,ror#18
+	eor	x13,x13,x8,ror#8
+	orr	x17,x17,x28			// Ch(e,f,g)
+	eor	x28,x25,x26			// a^b, b^c in next round
+	eor	x16,x16,x21,ror#41	// Sigma1(e)
+	eor	x14,x14,x25,ror#34
+	add	x24,x24,x17			// h+=Ch(e,f,g)
+	and	x19,x19,x28			// (b^c)&=(a^b)
+	eor	x12,x12,x5,ror#61
+	eor	x13,x13,x8,lsr#7	// sigma0(X[i+1])
+	add	x24,x24,x16			// h+=Sigma1(e)
+	eor	x19,x19,x26			// Maj(a,b,c)
+	eor	x17,x14,x25,ror#39	// Sigma0(a)
+	eor	x12,x12,x5,lsr#6	// sigma1(X[i+14])
+	add	x7,x7,x0
+	add	x20,x20,x24			// d+=h
+	add	x24,x24,x19			// h+=Maj(a,b,c)
+	ldr	x19,[x30],#8		// *K++, x28 in next round
+	add	x7,x7,x13
+	add	x24,x24,x17			// h+=Sigma0(a)
+	add	x7,x7,x12
+	ldr	x12,[sp,#8]
+	str	x15,[sp,#0]
+	ror	x16,x20,#14
+	add	x23,x23,x19			// h+=K[i]
+	ror	x14,x9,#1
+	and	x17,x21,x20
+	ror	x13,x6,#19
+	bic	x19,x22,x20
+	ror	x15,x24,#28
+	add	x23,x23,x7			// h+=X[i]
+	eor	x16,x16,x20,ror#18
+	eor	x14,x14,x9,ror#8
+	orr	x17,x17,x19			// Ch(e,f,g)
+	eor	x19,x24,x25			// a^b, b^c in next round
+	eor	x16,x16,x20,ror#41	// Sigma1(e)
+	eor	x15,x15,x24,ror#34
+	add	x23,x23,x17			// h+=Ch(e,f,g)
+	and	x28,x28,x19			// (b^c)&=(a^b)
+	eor	x13,x13,x6,ror#61
+	eor	x14,x14,x9,lsr#7	// sigma0(X[i+1])
+	add	x23,x23,x16			// h+=Sigma1(e)
+	eor	x28,x28,x25			// Maj(a,b,c)
+	eor	x17,x15,x24,ror#39	// Sigma0(a)
+	eor	x13,x13,x6,lsr#6	// sigma1(X[i+14])
+	add	x8,x8,x1
+	add	x27,x27,x23			// d+=h
+	add	x23,x23,x28			// h+=Maj(a,b,c)
+	ldr	x28,[x30],#8		// *K++, x19 in next round
+	add	x8,x8,x14
+	add	x23,x23,x17			// h+=Sigma0(a)
+	add	x8,x8,x13
+	ldr	x13,[sp,#16]
+	str	x0,[sp,#8]
+	ror	x16,x27,#14
+	add	x22,x22,x28			// h+=K[i]
+	ror	x15,x10,#1
+	and	x17,x20,x27
+	ror	x14,x7,#19
+	bic	x28,x21,x27
+	ror	x0,x23,#28
+	add	x22,x22,x8			// h+=X[i]
+	eor	x16,x16,x27,ror#18
+	eor	x15,x15,x10,ror#8
+	orr	x17,x17,x28			// Ch(e,f,g)
+	eor	x28,x23,x24			// a^b, b^c in next round
+	eor	x16,x16,x27,ror#41	// Sigma1(e)
+	eor	x0,x0,x23,ror#34
+	add	x22,x22,x17			// h+=Ch(e,f,g)
+	and	x19,x19,x28			// (b^c)&=(a^b)
+	eor	x14,x14,x7,ror#61
+	eor	x15,x15,x10,lsr#7	// sigma0(X[i+1])
+	add	x22,x22,x16			// h+=Sigma1(e)
+	eor	x19,x19,x24			// Maj(a,b,c)
+	eor	x17,x0,x23,ror#39	// Sigma0(a)
+	eor	x14,x14,x7,lsr#6	// sigma1(X[i+14])
+	add	x9,x9,x2
+	add	x26,x26,x22			// d+=h
+	add	x22,x22,x19			// h+=Maj(a,b,c)
+	ldr	x19,[x30],#8		// *K++, x28 in next round
+	add	x9,x9,x15
+	add	x22,x22,x17			// h+=Sigma0(a)
+	add	x9,x9,x14
+	ldr	x14,[sp,#24]
+	str	x1,[sp,#16]
+	ror	x16,x26,#14
+	add	x21,x21,x19			// h+=K[i]
+	ror	x0,x11,#1
+	and	x17,x27,x26
+	ror	x15,x8,#19
+	bic	x19,x20,x26
+	ror	x1,x22,#28
+	add	x21,x21,x9			// h+=X[i]
+	eor	x16,x16,x26,ror#18
+	eor	x0,x0,x11,ror#8
+	orr	x17,x17,x19			// Ch(e,f,g)
+	eor	x19,x22,x23			// a^b, b^c in next round
+	eor	x16,x16,x26,ror#41	// Sigma1(e)
+	eor	x1,x1,x22,ror#34
+	add	x21,x21,x17			// h+=Ch(e,f,g)
+	and	x28,x28,x19			// (b^c)&=(a^b)
+	eor	x15,x15,x8,ror#61
+	eor	x0,x0,x11,lsr#7	// sigma0(X[i+1])
+	add	x21,x21,x16			// h+=Sigma1(e)
+	eor	x28,x28,x23			// Maj(a,b,c)
+	eor	x17,x1,x22,ror#39	// Sigma0(a)
+	eor	x15,x15,x8,lsr#6	// sigma1(X[i+14])
+	add	x10,x10,x3
+	add	x25,x25,x21			// d+=h
+	add	x21,x21,x28			// h+=Maj(a,b,c)
+	ldr	x28,[x30],#8		// *K++, x19 in next round
+	add	x10,x10,x0
+	add	x21,x21,x17			// h+=Sigma0(a)
+	add	x10,x10,x15
+	ldr	x15,[sp,#0]
+	str	x2,[sp,#24]
+	ror	x16,x25,#14
+	add	x20,x20,x28			// h+=K[i]
+	ror	x1,x12,#1
+	and	x17,x26,x25
+	ror	x0,x9,#19
+	bic	x28,x27,x25
+	ror	x2,x21,#28
+	add	x20,x20,x10			// h+=X[i]
+	eor	x16,x16,x25,ror#18
+	eor	x1,x1,x12,ror#8
+	orr	x17,x17,x28			// Ch(e,f,g)
+	eor	x28,x21,x22			// a^b, b^c in next round
+	eor	x16,x16,x25,ror#41	// Sigma1(e)
+	eor	x2,x2,x21,ror#34
+	add	x20,x20,x17			// h+=Ch(e,f,g)
+	and	x19,x19,x28			// (b^c)&=(a^b)
+	eor	x0,x0,x9,ror#61
+	eor	x1,x1,x12,lsr#7	// sigma0(X[i+1])
+	add	x20,x20,x16			// h+=Sigma1(e)
+	eor	x19,x19,x22			// Maj(a,b,c)
+	eor	x17,x2,x21,ror#39	// Sigma0(a)
+	eor	x0,x0,x9,lsr#6	// sigma1(X[i+14])
+	add	x11,x11,x4
+	add	x24,x24,x20			// d+=h
+	add	x20,x20,x19			// h+=Maj(a,b,c)
+	ldr	x19,[x30],#8		// *K++, x28 in next round
+	add	x11,x11,x1
+	add	x20,x20,x17			// h+=Sigma0(a)
+	add	x11,x11,x0
+	ldr	x0,[sp,#8]
+	str	x3,[sp,#0]
+	ror	x16,x24,#14
+	add	x27,x27,x19			// h+=K[i]
+	ror	x2,x13,#1
+	and	x17,x25,x24
+	ror	x1,x10,#19
+	bic	x19,x26,x24
+	ror	x3,x20,#28
+	add	x27,x27,x11			// h+=X[i]
+	eor	x16,x16,x24,ror#18
+	eor	x2,x2,x13,ror#8
+	orr	x17,x17,x19			// Ch(e,f,g)
+	eor	x19,x20,x21			// a^b, b^c in next round
+	eor	x16,x16,x24,ror#41	// Sigma1(e)
+	eor	x3,x3,x20,ror#34
+	add	x27,x27,x17			// h+=Ch(e,f,g)
+	and	x28,x28,x19			// (b^c)&=(a^b)
+	eor	x1,x1,x10,ror#61
+	eor	x2,x2,x13,lsr#7	// sigma0(X[i+1])
+	add	x27,x27,x16			// h+=Sigma1(e)
+	eor	x28,x28,x21			// Maj(a,b,c)
+	eor	x17,x3,x20,ror#39	// Sigma0(a)
+	eor	x1,x1,x10,lsr#6	// sigma1(X[i+14])
+	add	x12,x12,x5
+	add	x23,x23,x27			// d+=h
+	add	x27,x27,x28			// h+=Maj(a,b,c)
+	ldr	x28,[x30],#8		// *K++, x19 in next round
+	add	x12,x12,x2
+	add	x27,x27,x17			// h+=Sigma0(a)
+	add	x12,x12,x1
+	ldr	x1,[sp,#16]
+	str	x4,[sp,#8]
+	ror	x16,x23,#14
+	add	x26,x26,x28			// h+=K[i]
+	ror	x3,x14,#1
+	and	x17,x24,x23
+	ror	x2,x11,#19
+	bic	x28,x25,x23
+	ror	x4,x27,#28
+	add	x26,x26,x12			// h+=X[i]
+	eor	x16,x16,x23,ror#18
+	eor	x3,x3,x14,ror#8
+	orr	x17,x17,x28			// Ch(e,f,g)
+	eor	x28,x27,x20			// a^b, b^c in next round
+	eor	x16,x16,x23,ror#41	// Sigma1(e)
+	eor	x4,x4,x27,ror#34
+	add	x26,x26,x17			// h+=Ch(e,f,g)
+	and	x19,x19,x28			// (b^c)&=(a^b)
+	eor	x2,x2,x11,ror#61
+	eor	x3,x3,x14,lsr#7	// sigma0(X[i+1])
+	add	x26,x26,x16			// h+=Sigma1(e)
+	eor	x19,x19,x20			// Maj(a,b,c)
+	eor	x17,x4,x27,ror#39	// Sigma0(a)
+	eor	x2,x2,x11,lsr#6	// sigma1(X[i+14])
+	add	x13,x13,x6
+	add	x22,x22,x26			// d+=h
+	add	x26,x26,x19			// h+=Maj(a,b,c)
+	ldr	x19,[x30],#8		// *K++, x28 in next round
+	add	x13,x13,x3
+	add	x26,x26,x17			// h+=Sigma0(a)
+	add	x13,x13,x2
+	ldr	x2,[sp,#24]
+	str	x5,[sp,#16]
+	ror	x16,x22,#14
+	add	x25,x25,x19			// h+=K[i]
+	ror	x4,x15,#1
+	and	x17,x23,x22
+	ror	x3,x12,#19
+	bic	x19,x24,x22
+	ror	x5,x26,#28
+	add	x25,x25,x13			// h+=X[i]
+	eor	x16,x16,x22,ror#18
+	eor	x4,x4,x15,ror#8
+	orr	x17,x17,x19			// Ch(e,f,g)
+	eor	x19,x26,x27			// a^b, b^c in next round
+	eor	x16,x16,x22,ror#41	// Sigma1(e)
+	eor	x5,x5,x26,ror#34
+	add	x25,x25,x17			// h+=Ch(e,f,g)
+	and	x28,x28,x19			// (b^c)&=(a^b)
+	eor	x3,x3,x12,ror#61
+	eor	x4,x4,x15,lsr#7	// sigma0(X[i+1])
+	add	x25,x25,x16			// h+=Sigma1(e)
+	eor	x28,x28,x27			// Maj(a,b,c)
+	eor	x17,x5,x26,ror#39	// Sigma0(a)
+	eor	x3,x3,x12,lsr#6	// sigma1(X[i+14])
+	add	x14,x14,x7
+	add	x21,x21,x25			// d+=h
+	add	x25,x25,x28			// h+=Maj(a,b,c)
+	ldr	x28,[x30],#8		// *K++, x19 in next round
+	add	x14,x14,x4
+	add	x25,x25,x17			// h+=Sigma0(a)
+	add	x14,x14,x3
+	ldr	x3,[sp,#0]
+	str	x6,[sp,#24]
+	ror	x16,x21,#14
+	add	x24,x24,x28			// h+=K[i]
+	ror	x5,x0,#1
+	and	x17,x22,x21
+	ror	x4,x13,#19
+	bic	x28,x23,x21
+	ror	x6,x25,#28
+	add	x24,x24,x14			// h+=X[i]
+	eor	x16,x16,x21,ror#18
+	eor	x5,x5,x0,ror#8
+	orr	x17,x17,x28			// Ch(e,f,g)
+	eor	x28,x25,x26			// a^b, b^c in next round
+	eor	x16,x16,x21,ror#41	// Sigma1(e)
+	eor	x6,x6,x25,ror#34
+	add	x24,x24,x17			// h+=Ch(e,f,g)
+	and	x19,x19,x28			// (b^c)&=(a^b)
+	eor	x4,x4,x13,ror#61
+	eor	x5,x5,x0,lsr#7	// sigma0(X[i+1])
+	add	x24,x24,x16			// h+=Sigma1(e)
+	eor	x19,x19,x26			// Maj(a,b,c)
+	eor	x17,x6,x25,ror#39	// Sigma0(a)
+	eor	x4,x4,x13,lsr#6	// sigma1(X[i+14])
+	add	x15,x15,x8
+	add	x20,x20,x24			// d+=h
+	add	x24,x24,x19			// h+=Maj(a,b,c)
+	ldr	x19,[x30],#8		// *K++, x28 in next round
+	add	x15,x15,x5
+	add	x24,x24,x17			// h+=Sigma0(a)
+	add	x15,x15,x4
+	ldr	x4,[sp,#8]
+	str	x7,[sp,#0]
+	ror	x16,x20,#14
+	add	x23,x23,x19			// h+=K[i]
+	ror	x6,x1,#1
+	and	x17,x21,x20
+	ror	x5,x14,#19
+	bic	x19,x22,x20
+	ror	x7,x24,#28
+	add	x23,x23,x15			// h+=X[i]
+	eor	x16,x16,x20,ror#18
+	eor	x6,x6,x1,ror#8
+	orr	x17,x17,x19			// Ch(e,f,g)
+	eor	x19,x24,x25			// a^b, b^c in next round
+	eor	x16,x16,x20,ror#41	// Sigma1(e)
+	eor	x7,x7,x24,ror#34
+	add	x23,x23,x17			// h+=Ch(e,f,g)
+	and	x28,x28,x19			// (b^c)&=(a^b)
+	eor	x5,x5,x14,ror#61
+	eor	x6,x6,x1,lsr#7	// sigma0(X[i+1])
+	add	x23,x23,x16			// h+=Sigma1(e)
+	eor	x28,x28,x25			// Maj(a,b,c)
+	eor	x17,x7,x24,ror#39	// Sigma0(a)
+	eor	x5,x5,x14,lsr#6	// sigma1(X[i+14])
+	add	x0,x0,x9
+	add	x27,x27,x23			// d+=h
+	add	x23,x23,x28			// h+=Maj(a,b,c)
+	ldr	x28,[x30],#8		// *K++, x19 in next round
+	add	x0,x0,x6
+	add	x23,x23,x17			// h+=Sigma0(a)
+	add	x0,x0,x5
+	ldr	x5,[sp,#16]
+	str	x8,[sp,#8]
+	ror	x16,x27,#14
+	add	x22,x22,x28			// h+=K[i]
+	ror	x7,x2,#1
+	and	x17,x20,x27
+	ror	x6,x15,#19
+	bic	x28,x21,x27
+	ror	x8,x23,#28
+	add	x22,x22,x0			// h+=X[i]
+	eor	x16,x16,x27,ror#18
+	eor	x7,x7,x2,ror#8
+	orr	x17,x17,x28			// Ch(e,f,g)
+	eor	x28,x23,x24			// a^b, b^c in next round
+	eor	x16,x16,x27,ror#41	// Sigma1(e)
+	eor	x8,x8,x23,ror#34
+	add	x22,x22,x17			// h+=Ch(e,f,g)
+	and	x19,x19,x28			// (b^c)&=(a^b)
+	eor	x6,x6,x15,ror#61
+	eor	x7,x7,x2,lsr#7	// sigma0(X[i+1])
+	add	x22,x22,x16			// h+=Sigma1(e)
+	eor	x19,x19,x24			// Maj(a,b,c)
+	eor	x17,x8,x23,ror#39	// Sigma0(a)
+	eor	x6,x6,x15,lsr#6	// sigma1(X[i+14])
+	add	x1,x1,x10
+	add	x26,x26,x22			// d+=h
+	add	x22,x22,x19			// h+=Maj(a,b,c)
+	ldr	x19,[x30],#8		// *K++, x28 in next round
+	add	x1,x1,x7
+	add	x22,x22,x17			// h+=Sigma0(a)
+	add	x1,x1,x6
+	ldr	x6,[sp,#24]
+	str	x9,[sp,#16]
+	ror	x16,x26,#14
+	add	x21,x21,x19			// h+=K[i]
+	ror	x8,x3,#1
+	and	x17,x27,x26
+	ror	x7,x0,#19
+	bic	x19,x20,x26
+	ror	x9,x22,#28
+	add	x21,x21,x1			// h+=X[i]
+	eor	x16,x16,x26,ror#18
+	eor	x8,x8,x3,ror#8
+	orr	x17,x17,x19			// Ch(e,f,g)
+	eor	x19,x22,x23			// a^b, b^c in next round
+	eor	x16,x16,x26,ror#41	// Sigma1(e)
+	eor	x9,x9,x22,ror#34
+	add	x21,x21,x17			// h+=Ch(e,f,g)
+	and	x28,x28,x19			// (b^c)&=(a^b)
+	eor	x7,x7,x0,ror#61
+	eor	x8,x8,x3,lsr#7	// sigma0(X[i+1])
+	add	x21,x21,x16			// h+=Sigma1(e)
+	eor	x28,x28,x23			// Maj(a,b,c)
+	eor	x17,x9,x22,ror#39	// Sigma0(a)
+	eor	x7,x7,x0,lsr#6	// sigma1(X[i+14])
+	add	x2,x2,x11
+	add	x25,x25,x21			// d+=h
+	add	x21,x21,x28			// h+=Maj(a,b,c)
+	ldr	x28,[x30],#8		// *K++, x19 in next round
+	add	x2,x2,x8
+	add	x21,x21,x17			// h+=Sigma0(a)
+	add	x2,x2,x7
+	ldr	x7,[sp,#0]
+	str	x10,[sp,#24]
+	ror	x16,x25,#14
+	add	x20,x20,x28			// h+=K[i]
+	ror	x9,x4,#1
+	and	x17,x26,x25
+	ror	x8,x1,#19
+	bic	x28,x27,x25
+	ror	x10,x21,#28
+	add	x20,x20,x2			// h+=X[i]
+	eor	x16,x16,x25,ror#18
+	eor	x9,x9,x4,ror#8
+	orr	x17,x17,x28			// Ch(e,f,g)
+	eor	x28,x21,x22			// a^b, b^c in next round
+	eor	x16,x16,x25,ror#41	// Sigma1(e)
+	eor	x10,x10,x21,ror#34
+	add	x20,x20,x17			// h+=Ch(e,f,g)
+	and	x19,x19,x28			// (b^c)&=(a^b)
+	eor	x8,x8,x1,ror#61
+	eor	x9,x9,x4,lsr#7	// sigma0(X[i+1])
+	add	x20,x20,x16			// h+=Sigma1(e)
+	eor	x19,x19,x22			// Maj(a,b,c)
+	eor	x17,x10,x21,ror#39	// Sigma0(a)
+	eor	x8,x8,x1,lsr#6	// sigma1(X[i+14])
+	add	x3,x3,x12
+	add	x24,x24,x20			// d+=h
+	add	x20,x20,x19			// h+=Maj(a,b,c)
+	ldr	x19,[x30],#8		// *K++, x28 in next round
+	add	x3,x3,x9
+	add	x20,x20,x17			// h+=Sigma0(a)
+	add	x3,x3,x8
+	cbnz	x19,.Loop_16_xx
+
+	ldp	x0,x2,[x29,#96]
+	ldr	x1,[x29,#112]
+	sub	x30,x30,#648		// rewind
+
+	ldp	x3,x4,[x0]
+	ldp	x5,x6,[x0,#2*8]
+	add	x1,x1,#14*8			// advance input pointer
+	ldp	x7,x8,[x0,#4*8]
+	add	x20,x20,x3
+	ldp	x9,x10,[x0,#6*8]
+	add	x21,x21,x4
+	add	x22,x22,x5
+	add	x23,x23,x6
+	stp	x20,x21,[x0]
+	add	x24,x24,x7
+	add	x25,x25,x8
+	stp	x22,x23,[x0,#2*8]
+	add	x26,x26,x9
+	add	x27,x27,x10
+	cmp	x1,x2
+	stp	x24,x25,[x0,#4*8]
+	stp	x26,x27,[x0,#6*8]
+	b.ne	.Loop
+
+	ldp	x19,x20,[x29,#16]
+	add	sp,sp,#4*8
+	ldp	x21,x22,[x29,#32]
+	ldp	x23,x24,[x29,#48]
+	ldp	x25,x26,[x29,#64]
+	ldp	x27,x28,[x29,#80]
+	ldp	x29,x30,[sp],#128
+	ret
+.size	sha512_block_data_order,.-sha512_block_data_order
+
+.align	6
+.type	.LK512,%object
+.LK512:
+	.quad	0x428a2f98d728ae22,0x7137449123ef65cd
+	.quad	0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc
+	.quad	0x3956c25bf348b538,0x59f111f1b605d019
+	.quad	0x923f82a4af194f9b,0xab1c5ed5da6d8118
+	.quad	0xd807aa98a3030242,0x12835b0145706fbe
+	.quad	0x243185be4ee4b28c,0x550c7dc3d5ffb4e2
+	.quad	0x72be5d74f27b896f,0x80deb1fe3b1696b1
+	.quad	0x9bdc06a725c71235,0xc19bf174cf692694
+	.quad	0xe49b69c19ef14ad2,0xefbe4786384f25e3
+	.quad	0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65
+	.quad	0x2de92c6f592b0275,0x4a7484aa6ea6e483
+	.quad	0x5cb0a9dcbd41fbd4,0x76f988da831153b5
+	.quad	0x983e5152ee66dfab,0xa831c66d2db43210
+	.quad	0xb00327c898fb213f,0xbf597fc7beef0ee4
+	.quad	0xc6e00bf33da88fc2,0xd5a79147930aa725
+	.quad	0x06ca6351e003826f,0x142929670a0e6e70
+	.quad	0x27b70a8546d22ffc,0x2e1b21385c26c926
+	.quad	0x4d2c6dfc5ac42aed,0x53380d139d95b3df
+	.quad	0x650a73548baf63de,0x766a0abb3c77b2a8
+	.quad	0x81c2c92e47edaee6,0x92722c851482353b
+	.quad	0xa2bfe8a14cf10364,0xa81a664bbc423001
+	.quad	0xc24b8b70d0f89791,0xc76c51a30654be30
+	.quad	0xd192e819d6ef5218,0xd69906245565a910
+	.quad	0xf40e35855771202a,0x106aa07032bbd1b8
+	.quad	0x19a4c116b8d2d0c8,0x1e376c085141ab53
+	.quad	0x2748774cdf8eeb99,0x34b0bcb5e19b48a8
+	.quad	0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb
+	.quad	0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3
+	.quad	0x748f82ee5defb2fc,0x78a5636f43172f60
+	.quad	0x84c87814a1f0ab72,0x8cc702081a6439ec
+	.quad	0x90befffa23631e28,0xa4506cebde82bde9
+	.quad	0xbef9a3f7b2c67915,0xc67178f2e372532b
+	.quad	0xca273eceea26619c,0xd186b8c721c0c207
+	.quad	0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178
+	.quad	0x06f067aa72176fba,0x0a637dc5a2c898a6
+	.quad	0x113f9804bef90dae,0x1b710b35131c471b
+	.quad	0x28db77f523047d84,0x32caab7b40c72493
+	.quad	0x3c9ebe0a15c9bebc,0x431d67c49c100d4c
+	.quad	0x4cc5d4becb3e42b6,0x597f299cfc657e2a
+	.quad	0x5fcb6fab3ad6faec,0x6c44198c4a475817
+	.quad	0	// terminator
+.size	.LK512,.-.LK512
+#ifndef	__KERNEL__
+.align	3
+.LOPENSSL_armcap_P:
+# ifdef	__ILP32__
+	.long	OPENSSL_armcap_P-.
+# else
+	.quad	OPENSSL_armcap_P-.
+# endif
+#endif
+.asciz	"SHA512 block transform for ARMv8, CRYPTOGAMS by <appro@openssl.org>"
+.align	2
+#ifndef	__KERNEL__
+.comm	OPENSSL_armcap_P,4,4
+#endif
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 88a4d1e..c7749d8 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -109,6 +109,24 @@
 	.endm
 
 /*
+ * Value prediction barrier
+ */
+	.macro	csdb
+	hint	#20
+	.endm
+
+/*
+ * Sanitise a 64-bit bounded index wrt speculation, returning zero if out
+ * of bounds.
+ */
+	.macro	mask_nospec64, idx, limit, tmp
+	sub	\tmp, \idx, \limit
+	bic	\tmp, \tmp, \idx
+	and	\idx, \idx, \tmp, asr #63
+	csdb
+	.endm
+
+/*
  * NOP sequence
  */
 	.macro	nops, num
@@ -492,4 +510,8 @@
 .Ldone\@:
 	.endm
 
+	.macro	pte_to_phys, phys, pte
+	and	\phys, \pte, #(((1 << (48 - PAGE_SHIFT)) - 1) << PAGE_SHIFT)
+	.endm
+
 #endif	/* __ASM_ASSEMBLER_H */
diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
index 0fe7e43..0b0755c 100644
--- a/arch/arm64/include/asm/barrier.h
+++ b/arch/arm64/include/asm/barrier.h
@@ -31,6 +31,8 @@
 #define dmb(opt)	asm volatile("dmb " #opt : : : "memory")
 #define dsb(opt)	asm volatile("dsb " #opt : : : "memory")
 
+#define csdb()		asm volatile("hint #20" : : : "memory")
+
 #define mb()		dsb(sy)
 #define rmb()		dsb(ld)
 #define wmb()		dsb(st)
@@ -38,6 +40,27 @@
 #define dma_rmb()	dmb(oshld)
 #define dma_wmb()	dmb(oshst)
 
+/*
+ * Generate a mask for array_index__nospec() that is ~0UL when 0 <= idx < sz
+ * and 0 otherwise.
+ */
+#define array_index_mask_nospec array_index_mask_nospec
+static inline unsigned long array_index_mask_nospec(unsigned long idx,
+						    unsigned long sz)
+{
+	unsigned long mask;
+
+	asm volatile(
+	"	cmp	%1, %2\n"
+	"	sbc	%0, xzr, xzr\n"
+	: "=r" (mask)
+	: "r" (idx), "Ir" (sz)
+	: "cc");
+
+	csdb();
+	return mask;
+}
+
 #define __smp_mb()	dmb(ish)
 #define __smp_rmb()	dmb(ishld)
 #define __smp_wmb()	dmb(ishst)
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index 847bfe6..9a6b81a 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -92,6 +92,7 @@
 
 #define CAVIUM_CPU_PART_THUNDERX	0x0A1
 #define CAVIUM_CPU_PART_THUNDERX_81XX	0x0A2
+#define CAVIUM_CPU_PART_THUNDERX2	0x0AF
 
 #define BRCM_CPU_PART_VULCAN		0x516
 
@@ -107,6 +108,8 @@
 #define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
 #define MIDR_KRYO2XX_GOLD \
 	MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, ARM_CPU_PART_KRYO2XX_GOLD)
+#define MIDR_CAVIUM_THUNDERX2 MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX2)
+#define MIDR_BRCM_VULCAN MIDR_CPU_MODEL(ARM_CPU_IMP_BRCM, BRCM_CPU_PART_VULCAN)
 
 #ifndef __ASSEMBLY__
 
diff --git a/arch/arm64/include/asm/dma-contiguous.h b/arch/arm64/include/asm/dma-contiguous.h
index f7e2c32..50f70a8 100644
--- a/arch/arm64/include/asm/dma-contiguous.h
+++ b/arch/arm64/include/asm/dma-contiguous.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013,2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013,2017-2018 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
@@ -15,7 +15,6 @@
 #define _ASM_DMA_CONTIGUOUS_H
 
 #ifdef __KERNEL__
-#ifdef CONFIG_DMA_CMA
 
 #include <linux/types.h>
 
@@ -23,5 +22,3 @@
 
 #endif
 #endif
-
-#endif
diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h
index 85c4a89..c5bc52e 100644
--- a/arch/arm64/include/asm/futex.h
+++ b/arch/arm64/include/asm/futex.h
@@ -48,16 +48,17 @@
 } while (0)
 
 static inline int
-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
+futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *_uaddr)
 {
 	int op = (encoded_op >> 28) & 7;
 	int cmp = (encoded_op >> 24) & 15;
-	int oparg = (encoded_op << 8) >> 20;
-	int cmparg = (encoded_op << 20) >> 20;
+	int oparg = (int)(encoded_op << 8) >> 20;
+	int cmparg = (int)(encoded_op << 20) >> 20;
 	int oldval = 0, ret, tmp;
+	u32 __user *uaddr = __uaccess_mask_ptr(_uaddr);
 
 	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
-		oparg = 1 << oparg;
+		oparg = 1U << (oparg & 0x1f);
 
 	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
 		return -EFAULT;
@@ -106,15 +107,17 @@
 }
 
 static inline int
-futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *_uaddr,
 			      u32 oldval, u32 newval)
 {
 	int ret = 0;
 	u32 val, tmp;
+	u32 __user *uaddr;
 
-	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+	if (!access_ok(VERIFY_WRITE, _uaddr, sizeof(u32)))
 		return -EFAULT;
 
+	uaddr = __uaccess_mask_ptr(_uaddr);
 	uaccess_enable();
 	asm volatile("// futex_atomic_cmpxchg_inatomic\n"
 "	prfm	pstl1strm, %2\n"
diff --git a/arch/arm64/include/asm/kernel-pgtable.h b/arch/arm64/include/asm/kernel-pgtable.h
index 77a27af..7803343 100644
--- a/arch/arm64/include/asm/kernel-pgtable.h
+++ b/arch/arm64/include/asm/kernel-pgtable.h
@@ -78,16 +78,8 @@
 /*
  * Initial memory map attributes.
  */
-#define _SWAPPER_PTE_FLAGS	(PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
-#define _SWAPPER_PMD_FLAGS	(PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
-
-#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
-#define SWAPPER_PTE_FLAGS	(_SWAPPER_PTE_FLAGS | PTE_NG)
-#define SWAPPER_PMD_FLAGS	(_SWAPPER_PMD_FLAGS | PMD_SECT_NG)
-#else
-#define SWAPPER_PTE_FLAGS	_SWAPPER_PTE_FLAGS
-#define SWAPPER_PMD_FLAGS	_SWAPPER_PMD_FLAGS
-#endif
+#define SWAPPER_PTE_FLAGS	(PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
+#define SWAPPER_PMD_FLAGS	(PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
 
 #if ARM64_SWAPPER_USES_SECTION_MAPS
 #define SWAPPER_MM_MMUFLAGS	(PMD_ATTRINDX(MT_NORMAL) | SWAPPER_PMD_FLAGS)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index e505038..37d56e8 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -393,4 +393,9 @@
 		  "PARange is %d bits, unsupported configuration!", parange);
 }
 
+static inline bool kvm_arm_harden_branch_predictor(void)
+{
+	return cpus_have_cap(ARM64_HARDEN_BRANCH_PREDICTOR);
+}
+
 #endif /* __ARM64_KVM_HOST_H__ */
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 35ea9c1..36d2aba 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -325,7 +325,7 @@
 		vect = __bp_harden_hyp_vecs_start +
 		       data->hyp_vectors_slot * SZ_2K;
 
-		if (!has_vhe())
+		if (!cpus_have_cap(ARM64_HAS_VIRT_HOST_EXTN))
 			vect = lm_alias(vect);
 	}
 
diff --git a/arch/arm64/include/asm/kvm_psci.h b/arch/arm64/include/asm/kvm_psci.h
deleted file mode 100644
index bc39e55..0000000
--- a/arch/arm64/include/asm/kvm_psci.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2012,2013 - ARM Ltd
- * Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __ARM64_KVM_PSCI_H__
-#define __ARM64_KVM_PSCI_H__
-
-#define KVM_ARM_PSCI_0_1	1
-#define KVM_ARM_PSCI_0_2	2
-
-int kvm_psci_version(struct kvm_vcpu *vcpu);
-int kvm_psci_call(struct kvm_vcpu *vcpu);
-
-#endif /* __ARM64_KVM_PSCI_H__ */
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index 8fe5ffc..708028e 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -61,12 +61,12 @@
  * KIMAGE_VADDR - the virtual address of the start of the kernel image
  * VA_BITS - the maximum number of bits for virtual addresses.
  * VA_START - the first kernel virtual address.
- * TASK_SIZE - the maximum size of a user space task.
- * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area.
  */
 #define VA_BITS			(CONFIG_ARM64_VA_BITS)
-#define VA_START		(UL(0xffffffffffffffff) << VA_BITS)
-#define PAGE_OFFSET		(UL(0xffffffffffffffff) << (VA_BITS - 1))
+#define VA_START		(UL(0xffffffffffffffff) - \
+	(UL(1) << VA_BITS) + 1)
+#define PAGE_OFFSET		(UL(0xffffffffffffffff) - \
+	(UL(1) << (VA_BITS - 1)) + 1)
 #define KIMAGE_VADDR		(MODULES_END)
 #define MODULES_END		(MODULES_VADDR + MODULES_VSIZE)
 #define MODULES_VADDR		(VA_START + KASAN_SHADOW_SIZE)
@@ -75,19 +75,6 @@
 #define PCI_IO_END		(VMEMMAP_START - SZ_2M)
 #define PCI_IO_START		(PCI_IO_END - PCI_IO_SIZE)
 #define FIXADDR_TOP		(PCI_IO_START - SZ_2M)
-#define TASK_SIZE_64		(UL(1) << VA_BITS)
-
-#ifdef CONFIG_COMPAT
-#define TASK_SIZE_32		UL(0x100000000)
-#define TASK_SIZE		(test_thread_flag(TIF_32BIT) ? \
-				TASK_SIZE_32 : TASK_SIZE_64)
-#define TASK_SIZE_OF(tsk)	(test_tsk_thread_flag(tsk, TIF_32BIT) ? \
-				TASK_SIZE_32 : TASK_SIZE_64)
-#else
-#define TASK_SIZE		TASK_SIZE_64
-#endif /* CONFIG_COMPAT */
-
-#define TASK_UNMAPPED_BASE	(PAGE_ALIGN(TASK_SIZE / 4))
 
 #define KERNEL_START      _text
 #define KERNEL_END        _end
diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h
index f543df3..24c780d 100644
--- a/arch/arm64/include/asm/mmu.h
+++ b/arch/arm64/include/asm/mmu.h
@@ -21,7 +21,7 @@
 
 #ifndef __ASSEMBLY__
 
-#include <asm/percpu.h>
+#include <linux/percpu.h>
 
 typedef struct {
 	atomic64_t	id;
@@ -55,7 +55,7 @@
 
 static inline struct bp_hardening_data *arm64_get_bp_hardening_data(void)
 {
-	return raw_cpu_ptr(&bp_hardening_data);
+	return this_cpu_ptr(&bp_hardening_data);
 }
 
 static inline void arm64_apply_bp_hardening(void)
diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h
index 84b5283..f705d96 100644
--- a/arch/arm64/include/asm/pgtable-prot.h
+++ b/arch/arm64/include/asm/pgtable-prot.h
@@ -37,13 +37,11 @@
 #define _PROT_DEFAULT		(PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
 #define _PROT_SECT_DEFAULT	(PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
 
-#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
-#define PROT_DEFAULT		(_PROT_DEFAULT | PTE_NG)
-#define PROT_SECT_DEFAULT	(_PROT_SECT_DEFAULT | PMD_SECT_NG)
-#else
-#define PROT_DEFAULT		_PROT_DEFAULT
-#define PROT_SECT_DEFAULT	_PROT_SECT_DEFAULT
-#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
+#define PTE_MAYBE_NG		(arm64_kernel_unmapped_at_el0() ? PTE_NG : 0)
+#define PMD_MAYBE_NG		(arm64_kernel_unmapped_at_el0() ? PMD_SECT_NG : 0)
+
+#define PROT_DEFAULT		(_PROT_DEFAULT | PTE_MAYBE_NG)
+#define PROT_SECT_DEFAULT	(_PROT_SECT_DEFAULT | PMD_MAYBE_NG)
 
 #define PROT_DEVICE_nGnRnE	(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRnE))
 #define PROT_DEVICE_nGnRE	(PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRE))
@@ -55,22 +53,22 @@
 #define PROT_SECT_NORMAL	(PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL))
 #define PROT_SECT_NORMAL_EXEC	(PROT_SECT_DEFAULT | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL))
 
-#define _PAGE_DEFAULT		(PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL))
-#define _HYP_PAGE_DEFAULT	(_PAGE_DEFAULT & ~PTE_NG)
+#define _PAGE_DEFAULT		(_PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL))
+#define _HYP_PAGE_DEFAULT	_PAGE_DEFAULT
 
-#define PAGE_KERNEL		__pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE)
-#define PAGE_KERNEL_RO		__pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
-#define PAGE_KERNEL_ROX		__pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
-#define PAGE_KERNEL_EXEC	__pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE)
-#define PAGE_KERNEL_EXEC_CONT	__pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_CONT)
+#define PAGE_KERNEL		__pgprot(PROT_NORMAL)
+#define PAGE_KERNEL_RO		__pgprot((PROT_NORMAL & ~PTE_WRITE) | PTE_RDONLY)
+#define PAGE_KERNEL_ROX		__pgprot((PROT_NORMAL & ~(PTE_WRITE | PTE_PXN)) | PTE_RDONLY)
+#define PAGE_KERNEL_EXEC	__pgprot(PROT_NORMAL & ~PTE_PXN)
+#define PAGE_KERNEL_EXEC_CONT	__pgprot((PROT_NORMAL & ~PTE_PXN) | PTE_CONT)
 
 #define PAGE_HYP		__pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_HYP_XN)
 #define PAGE_HYP_EXEC		__pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY)
 #define PAGE_HYP_RO		__pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY | PTE_HYP_XN)
 #define PAGE_HYP_DEVICE		__pgprot(PROT_DEVICE_nGnRE | PTE_HYP)
 
-#define PAGE_S2			__pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY)
-#define PAGE_S2_DEVICE		__pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_UXN)
+#define PAGE_S2			__pgprot(_PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY)
+#define PAGE_S2_DEVICE		__pgprot(_PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_UXN)
 
 #define PAGE_NONE		__pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_NG | PTE_PXN | PTE_UXN)
 #define PAGE_SHARED		__pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE)
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index a4af9f0..d8039a1 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -19,6 +19,13 @@
 #ifndef __ASM_PROCESSOR_H
 #define __ASM_PROCESSOR_H
 
+#define TASK_SIZE_64		(UL(1) << VA_BITS)
+
+#define KERNEL_DS	UL(-1)
+#define USER_DS		(TASK_SIZE_64 - 1)
+
+#ifndef __ASSEMBLY__
+
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
@@ -37,6 +44,22 @@
 #include <asm/ptrace.h>
 #include <asm/types.h>
 
+/*
+ * TASK_SIZE - the maximum size of a user space task.
+ * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area.
+ */
+#ifdef CONFIG_COMPAT
+#define TASK_SIZE_32		UL(0x100000000)
+#define TASK_SIZE		(test_thread_flag(TIF_32BIT) ? \
+				TASK_SIZE_32 : TASK_SIZE_64)
+#define TASK_SIZE_OF(tsk)	(test_tsk_thread_flag(tsk, TIF_32BIT) ? \
+				TASK_SIZE_32 : TASK_SIZE_64)
+#else
+#define TASK_SIZE		TASK_SIZE_64
+#endif /* CONFIG_COMPAT */
+
+#define TASK_UNMAPPED_BASE	(PAGE_ALIGN(TASK_SIZE / 4))
+
 #define STACK_TOP_MAX		TASK_SIZE_64
 #ifdef CONFIG_COMPAT
 #define AARCH32_VECTORS_BASE	0xffff0000
@@ -195,4 +218,5 @@
 int cpu_enable_uao(void *__unused);
 int cpu_enable_cache_maint_trap(void *__unused);
 
+#endif /* __ASSEMBLY__ */
 #endif /* __ASM_PROCESSOR_H */
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 9311547..6c35d21 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -35,6 +35,7 @@
 
 #include <asm/cpufeature.h>
 #include <asm/kernel-pgtable.h>
+#include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/errno.h>
 #include <asm/memory.h>
@@ -65,10 +66,7 @@
 
 extern int fixup_exception(struct pt_regs *regs);
 
-#define KERNEL_DS	(-1UL)
 #define get_ds()	(KERNEL_DS)
-
-#define USER_DS		TASK_SIZE_64
 #define get_fs()	(current_thread_info()->addr_limit)
 
 static inline void set_fs(mm_segment_t fs)
@@ -76,6 +74,13 @@
 	current_thread_info()->addr_limit = fs;
 
 	/*
+	 * Prevent a mispredicted conditional call to set_fs from forwarding
+	 * the wrong address limit to access_ok under speculation.
+	 */
+	dsb(nsh);
+	isb();
+
+	/*
 	 * Enable/disable UAO so that copy_to_user() etc can access
 	 * kernel memory with the unprivileged instructions.
 	 */
@@ -93,22 +98,32 @@
  * Returns 1 if the range is valid, 0 otherwise.
  *
  * This is equivalent to the following test:
- * (u65)addr + (u65)size <= current->addr_limit
- *
- * This needs 65-bit arithmetic.
+ * (u65)addr + (u65)size <= (u65)current->addr_limit + 1
  */
-#define __range_ok(addr, size)						\
-({									\
-	unsigned long __addr = (unsigned long __force)(addr);		\
-	unsigned long flag, roksum;					\
-	__chk_user_ptr(addr);						\
-	asm("adds %1, %1, %3; ccmp %1, %4, #2, cc; cset %0, ls"		\
-		: "=&r" (flag), "=&r" (roksum)				\
-		: "1" (__addr), "Ir" (size),				\
-		  "r" (current_thread_info()->addr_limit)		\
-		: "cc");						\
-	flag;								\
-})
+static inline unsigned long __range_ok(unsigned long addr, unsigned long size)
+{
+	unsigned long limit = current_thread_info()->addr_limit;
+
+	__chk_user_ptr(addr);
+	asm volatile(
+	// A + B <= C + 1 for all A,B,C, in four easy steps:
+	// 1: X = A + B; X' = X % 2^64
+	"	adds	%0, %0, %2\n"
+	// 2: Set C = 0 if X > 2^64, to guarantee X' > C in step 4
+	"	csel	%1, xzr, %1, hi\n"
+	// 3: Set X' = ~0 if X >= 2^64. For X == 2^64, this decrements X'
+	//    to compensate for the carry flag being set in step 4. For
+	//    X > 2^64, X' merely has to remain nonzero, which it does.
+	"	csinv	%0, %0, xzr, cc\n"
+	// 4: For X < 2^64, this gives us X' - C - 1 <= 0, where the -1
+	//    comes from the carry in being clear. Otherwise, we are
+	//    testing X' - C == 0, subject to the previous adjustments.
+	"	sbcs	xzr, %0, %1\n"
+	"	cset	%0, ls\n"
+	: "+r" (addr), "+r" (limit) : "Ir" (size) : "cc");
+
+	return addr;
+}
 
 /*
  * When dealing with data aborts, watchpoints, or instruction traps we may end
@@ -117,7 +132,7 @@
  */
 #define untagged_addr(addr)		sign_extend64(addr, 55)
 
-#define access_ok(type, addr, size)	__range_ok(addr, size)
+#define access_ok(type, addr, size)	__range_ok((unsigned long)(addr), size)
 #define user_addr_max			get_fs
 
 #define _ASM_EXTABLE(from, to)						\
@@ -236,6 +251,26 @@
 }
 
 /*
+ * Sanitise a uaccess pointer such that it becomes NULL if above the
+ * current addr_limit.
+ */
+#define uaccess_mask_ptr(ptr) (__typeof__(ptr))__uaccess_mask_ptr(ptr)
+static inline void __user *__uaccess_mask_ptr(const void __user *ptr)
+{
+	void __user *safe_ptr;
+
+	asm volatile(
+	"	bics	xzr, %1, %2\n"
+	"	csel	%0, %1, xzr, eq\n"
+	: "=&r" (safe_ptr)
+	: "r" (ptr), "r" (current_thread_info()->addr_limit)
+	: "cc");
+
+	csdb();
+	return safe_ptr;
+}
+
+/*
  * The "__xxx" versions of the user access functions do not verify the address
  * space - it must have been done previously with a separate "access_ok()"
  * call.
@@ -287,29 +322,34 @@
 	(x) = (__force __typeof__(*(ptr)))__gu_val;			\
 } while (0)
 
-#define __get_user(x, ptr)						\
+#define __get_user_check(x, ptr, err)					\
 ({									\
-	int __gu_err = 0;						\
-	__get_user_err((x), (ptr), __gu_err);				\
-	__gu_err;							\
+	__typeof__(*(ptr)) __user *__p = (ptr);				\
+	might_fault();							\
+	if (access_ok(VERIFY_READ, __p, sizeof(*__p))) {		\
+		__p = uaccess_mask_ptr(__p);				\
+		__get_user_err((x), __p, (err));			\
+	} else {							\
+		(x) = 0; (err) = -EFAULT;				\
+	}								\
 })
 
 #define __get_user_error(x, ptr, err)					\
 ({									\
-	__get_user_err((x), (ptr), (err));				\
+	__get_user_check((x), (ptr), (err));				\
 	(void)0;							\
 })
 
+#define __get_user(x, ptr)						\
+({									\
+	int __gu_err = 0;						\
+	__get_user_check((x), (ptr), __gu_err);				\
+	__gu_err;							\
+})
+
 #define __get_user_unaligned __get_user
 
-#define get_user(x, ptr)						\
-({									\
-	__typeof__(*(ptr)) __user *__p = (ptr);				\
-	might_fault();							\
-	access_ok(VERIFY_READ, __p, sizeof(*__p)) ?			\
-		__get_user((x), __p) :					\
-		((x) = 0, -EFAULT);					\
-})
+#define get_user	__get_user
 
 #define __put_user_asm(instr, alt_instr, reg, x, addr, err, feature)	\
 	asm volatile(							\
@@ -353,47 +393,51 @@
 	uaccess_disable_not_uao();					\
 } while (0)
 
-#define __put_user(x, ptr)						\
+#define __put_user_check(x, ptr, err)					\
 ({									\
-	int __pu_err = 0;						\
-	__put_user_err((x), (ptr), __pu_err);				\
-	__pu_err;							\
+	__typeof__(*(ptr)) __user *__p = (ptr);				\
+	might_fault();							\
+	if (access_ok(VERIFY_WRITE, __p, sizeof(*__p))) {		\
+		__p = uaccess_mask_ptr(__p);				\
+		__put_user_err((x), __p, (err));			\
+	} else	{							\
+		(err) = -EFAULT;					\
+	}								\
 })
 
 #define __put_user_error(x, ptr, err)					\
 ({									\
-	__put_user_err((x), (ptr), (err));				\
+	__put_user_check((x), (ptr), (err));				\
 	(void)0;							\
 })
 
+#define __put_user(x, ptr)						\
+({									\
+	int __pu_err = 0;						\
+	__put_user_check((x), (ptr), __pu_err);				\
+	__pu_err;							\
+})
+
 #define __put_user_unaligned __put_user
 
-#define put_user(x, ptr)						\
-({									\
-	__typeof__(*(ptr)) __user *__p = (ptr);				\
-	might_fault();							\
-	access_ok(VERIFY_WRITE, __p, sizeof(*__p)) ?			\
-		__put_user((x), __p) :					\
-		-EFAULT;						\
-})
+#define put_user	__put_user
 
 extern unsigned long __must_check __arch_copy_from_user(void *to, const void __user *from, unsigned long n);
 extern unsigned long __must_check __arch_copy_to_user(void __user *to, const void *from, unsigned long n);
-extern unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n);
-extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n);
+extern unsigned long __must_check __arch_copy_in_user(void __user *to, const void __user *from, unsigned long n);
 
 static inline unsigned long __must_check __copy_from_user(void *to, const void __user *from, unsigned long n)
 {
 	kasan_check_write(to, n);
 	check_object_size(to, n, false);
-	return __arch_copy_from_user(to, from, n);
+	return __arch_copy_from_user(to, __uaccess_mask_ptr(from), n);
 }
 
 static inline unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n)
 {
 	kasan_check_read(from, n);
 	check_object_size(from, n, true);
-	return __arch_copy_to_user(to, from, n);
+	return __arch_copy_to_user(__uaccess_mask_ptr(to), from, n);
 }
 
 static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n)
@@ -421,22 +465,25 @@
 	return n;
 }
 
-static inline unsigned long __must_check copy_in_user(void __user *to, const void __user *from, unsigned long n)
+static inline unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n)
 {
 	if (access_ok(VERIFY_READ, from, n) && access_ok(VERIFY_WRITE, to, n))
-		n = __copy_in_user(to, from, n);
+		n = __arch_copy_in_user(__uaccess_mask_ptr(to), __uaccess_mask_ptr(from), n);
 	return n;
 }
+#define copy_in_user __copy_in_user
 
 #define __copy_to_user_inatomic __copy_to_user
 #define __copy_from_user_inatomic __copy_from_user
 
-static inline unsigned long __must_check clear_user(void __user *to, unsigned long n)
+extern unsigned long __must_check __arch_clear_user(void __user *to, unsigned long n);
+static inline unsigned long __must_check __clear_user(void __user *to, unsigned long n)
 {
 	if (access_ok(VERIFY_WRITE, to, n))
-		n = __clear_user(to, n);
+		n = __arch_clear_user(__uaccess_mask_ptr(to), n);
 	return n;
 }
+#define clear_user	__clear_user
 
 extern long strncpy_from_user(char *dest, const char __user *src, long count);
 
diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c
index dd918d0..ca1cf2d 100644
--- a/arch/arm64/kernel/arm64ksyms.c
+++ b/arch/arm64/kernel/arm64ksyms.c
@@ -38,8 +38,8 @@
 	/* user mem (segment) */
 EXPORT_SYMBOL(__arch_copy_from_user);
 EXPORT_SYMBOL(__arch_copy_to_user);
-EXPORT_SYMBOL(__clear_user);
-EXPORT_SYMBOL(__copy_in_user);
+EXPORT_SYMBOL(__arch_clear_user);
+EXPORT_SYMBOL(__arch_copy_in_user);
 
 	/* physical memory */
 EXPORT_SYMBOL(memstart_addr);
diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
index dec95bd..746a203 100644
--- a/arch/arm64/kernel/bpi.S
+++ b/arch/arm64/kernel/bpi.S
@@ -17,6 +17,7 @@
  */
 
 #include <linux/linkage.h>
+#include <linux/arm-smccc.h>
 
 .macro ventry target
 	.rept 31
@@ -53,6 +54,7 @@
 	vectors __kvm_hyp_vector
 	.endr
 ENTRY(__bp_harden_hyp_vecs_end)
+
 ENTRY(__psci_hyp_bp_inval_start)
 	sub	sp, sp, #(8 * 18)
 	stp	x16, x17, [sp, #(16 * 0)]
@@ -77,3 +79,23 @@
 	ldp	x0, x1, [sp, #(16 * 8)]
 	add	sp, sp, #(8 * 18)
 ENTRY(__psci_hyp_bp_inval_end)
+
+.macro smccc_workaround_1 inst
+	sub	sp, sp, #(8 * 4)
+	stp	x2, x3, [sp, #(8 * 0)]
+	stp	x0, x1, [sp, #(8 * 2)]
+	mov	w0, #ARM_SMCCC_ARCH_WORKAROUND_1
+	\inst	#0
+	ldp	x2, x3, [sp, #(8 * 0)]
+	ldp	x0, x1, [sp, #(8 * 2)]
+	add	sp, sp, #(8 * 4)
+.endm
+
+ENTRY(__smccc_workaround_1_smc_start)
+	smccc_workaround_1	smc
+ENTRY(__smccc_workaround_1_smc_end)
+
+ENTRY(__smccc_workaround_1_hvc_start)
+	smccc_workaround_1	hvc
+ENTRY(__smccc_workaround_1_hvc_end)
+.#endif
diff --git a/arch/arm64/kernel/cpu-reset.S b/arch/arm64/kernel/cpu-reset.S
index 65f42d2..f736a6f 100644
--- a/arch/arm64/kernel/cpu-reset.S
+++ b/arch/arm64/kernel/cpu-reset.S
@@ -16,7 +16,7 @@
 #include <asm/virt.h>
 
 .text
-.pushsection    .idmap.text, "ax"
+.pushsection    .idmap.text, "awx"
 
 /*
  * __cpu_soft_restart(el2_switch, entry, arg0, arg1, arg2) - Helper for
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 7c8e185..49e548f 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -54,11 +54,15 @@
 
 #ifdef CONFIG_KVM
 extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
+extern char __smccc_workaround_1_smc_start[];
+extern char __smccc_workaround_1_smc_end[];
+extern char __smccc_workaround_1_hvc_start[];
+extern char __smccc_workaround_1_hvc_end[];
 
 static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
 				const char *hyp_vecs_end)
 {
-	void *dst = lm_alias(__bp_harden_hyp_vecs_start + slot * SZ_2K);
+	void *dst = __bp_harden_hyp_vecs_start + slot * SZ_2K;
 	int i;
 
 	for (i = 0; i < SZ_2K; i += 0x80)
@@ -98,6 +102,10 @@
 #else
 #define __psci_hyp_bp_inval_start	NULL
 #define __psci_hyp_bp_inval_end		NULL
+#define __smccc_workaround_1_smc_start		NULL
+#define __smccc_workaround_1_smc_end		NULL
+#define __smccc_workaround_1_hvc_start		NULL
+#define __smccc_workaround_1_hvc_end		NULL
 
 static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
 				      const char *hyp_vecs_start,
@@ -124,8 +132,11 @@
 	__install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
 }
 
+#include <uapi/linux/psci.h>
+#include <linux/arm-smccc.h>
 #include <linux/psci.h>
 
+#ifdef CONFIG_PSCI_BP_HARDENING
 static int enable_psci_bp_hardening(void *data)
 {
 	const struct arm64_cpu_capabilities *entry = data;
@@ -135,6 +146,59 @@
 				       (bp_hardening_cb_t)psci_ops.get_version,
 				       __psci_hyp_bp_inval_start,
 				       __psci_hyp_bp_inval_end);
+	return 0;
+}
+#endif
+
+static void call_smc_arch_workaround_1(void)
+{
+	arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
+}
+
+static void call_hvc_arch_workaround_1(void)
+{
+	arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
+}
+
+static int enable_smccc_arch_workaround_1(void *data)
+{
+	const struct arm64_cpu_capabilities *entry = data;
+	bp_hardening_cb_t cb;
+	void *smccc_start, *smccc_end;
+	struct arm_smccc_res res;
+
+	if (!entry->matches(entry, SCOPE_LOCAL_CPU))
+		return 0;
+
+	if (psci_ops.smccc_version == SMCCC_VERSION_1_0)
+		return 0;
+
+	switch (psci_ops.conduit) {
+	case PSCI_CONDUIT_HVC:
+		arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+				  ARM_SMCCC_ARCH_WORKAROUND_1, &res);
+		if (res.a0)
+			return 0;
+		cb = call_hvc_arch_workaround_1;
+		smccc_start = __smccc_workaround_1_hvc_start;
+		smccc_end = __smccc_workaround_1_hvc_end;
+		break;
+
+	case PSCI_CONDUIT_SMC:
+		arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+				  ARM_SMCCC_ARCH_WORKAROUND_1, &res);
+		if (res.a0)
+			return 0;
+		cb = call_smc_arch_workaround_1;
+		smccc_start = __smccc_workaround_1_smc_start;
+		smccc_end = __smccc_workaround_1_smc_end;
+		break;
+
+	default:
+		return 0;
+	}
+
+	install_bp_hardening_cb(entry, cb, smccc_start, smccc_end);
 
 	return 0;
 }
@@ -238,32 +302,50 @@
 	{
 		.capability = ARM64_HARDEN_BRANCH_PREDICTOR,
 		MIDR_ALL_VERSIONS(MIDR_CORTEX_A57),
-		.enable = enable_psci_bp_hardening,
+		.enable = enable_smccc_arch_workaround_1,
 	},
 	{
 		.capability = ARM64_HARDEN_BRANCH_PREDICTOR,
 		MIDR_ALL_VERSIONS(MIDR_CORTEX_A72),
-		.enable = enable_psci_bp_hardening,
+		.enable = enable_smccc_arch_workaround_1,
 	},
 	{
 		.capability = ARM64_HARDEN_BRANCH_PREDICTOR,
 		MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
-		.enable = enable_psci_bp_hardening,
+		.enable = enable_smccc_arch_workaround_1,
 	},
 	{
 		.capability = ARM64_HARDEN_BRANCH_PREDICTOR,
 		MIDR_ALL_VERSIONS(MIDR_CORTEX_A75),
-		.enable = enable_psci_bp_hardening,
+		.enable = enable_smccc_arch_workaround_1,
 	},
 	{
 		.capability = ARM64_HARDEN_BRANCH_PREDICTOR,
 		MIDR_ALL_VERSIONS(MIDR_KRYO3G),
+#ifdef CONFIG_PSCI_BP_HARDENING
 		.enable = enable_psci_bp_hardening,
+#else
+		.enable = enable_smccc_arch_workaround_1,
+#endif
 	},
 	{
 		.capability = ARM64_HARDEN_BRANCH_PREDICTOR,
 		MIDR_ALL_VERSIONS(MIDR_KRYO2XX_GOLD),
+#ifdef CONFIG_PSCI_BP_HARDENING
 		.enable = enable_psci_bp_hardening,
+#else
+		.enable = enable_smccc_arch_workaround_1,
+#endif
+	},
+	{
+		.capability = ARM64_HARDEN_BRANCH_PREDICTOR,
+		MIDR_ALL_VERSIONS(MIDR_BRCM_VULCAN),
+		.enable = enable_smccc_arch_workaround_1,
+	},
+	{
+		.capability = ARM64_HARDEN_BRANCH_PREDICTOR,
+		MIDR_ALL_VERSIONS(MIDR_CAVIUM_THUNDERX2),
+		.enable = enable_smccc_arch_workaround_1,
 	},
 #endif
 	{
@@ -279,15 +361,18 @@
 {
 	const struct arm64_cpu_capabilities *caps = arm64_errata;
 
-	for (; caps->matches; caps++)
-		if (!cpus_have_cap(caps->capability) &&
-			caps->matches(caps, SCOPE_LOCAL_CPU)) {
+	for (; caps->matches; caps++) {
+		if (cpus_have_cap(caps->capability)) {
+			if (caps->enable)
+				caps->enable((void *)caps);
+		} else if (caps->matches(caps, SCOPE_LOCAL_CPU)) {
 			pr_crit("CPU%d: Requires work around for %s, not detected"
 					" at boot time\n",
 				smp_processor_id(),
 				caps->desc ? : "an erratum");
 			cpu_die_early();
 		}
+	}
 }
 
 void update_cpu_errata_workarounds(void)
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 5cf4c64..675bf45 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -95,12 +95,13 @@
 };
 
 static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
-	ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0),
+	ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV3_SHIFT, 4, 0),
+	ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV2_SHIFT, 4, 0),
+	ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 24, 0),
 	ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 4, 0),
 	ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_GIC_SHIFT, 4, 0),
 	S_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI),
 	S_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_FP_SHIFT, 4, ID_AA64PFR0_FP_NI),
-	ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV3_SHIFT, 4, 0),
 	/* Linux doesn't care about the EL3 */
 	ARM64_FTR_BITS(FTR_NONSTRICT, FTR_EXACT, ID_AA64PFR0_EL3_SHIFT, 4, 0),
 	ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_EL2_SHIFT, 4, 0),
@@ -753,12 +754,23 @@
 static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry,
 				int __unused)
 {
+	char const *str = "command line option";
 	u64 pfr0 = read_system_reg(SYS_ID_AA64PFR0_EL1);
 
-	/* Forced on command line? */
+	/*
+	 * For reasons that aren't entirely clear, enabling KPTI on Cavium
+	 * ThunderX leads to apparent I-cache corruption of kernel text, which
+	 * ends as well as you might imagine. Don't even try.
+	 */
+	if (cpus_have_cap(ARM64_WORKAROUND_CAVIUM_27456)) {
+		str = "ARM64_WORKAROUND_CAVIUM_27456";
+		__kpti_forced = -1;
+	}
+
+	/* Forced? */
 	if (__kpti_forced) {
-		pr_info_once("kernel page table isolation forced %s by command line option\n",
-			     __kpti_forced > 0 ? "ON" : "OFF");
+		pr_info_once("kernel page table isolation forced %s by %s\n",
+			     __kpti_forced > 0 ? "ON" : "OFF", str);
 		return __kpti_forced > 0;
 	}
 
@@ -766,11 +778,42 @@
 	if (IS_ENABLED(CONFIG_RANDOMIZE_BASE))
 		return true;
 
+	/* Don't force KPTI for CPUs that are not vulnerable */
+	switch (read_cpuid_id() & MIDR_CPU_MODEL_MASK) {
+	case MIDR_CAVIUM_THUNDERX2:
+	case MIDR_BRCM_VULCAN:
+		return false;
+	}
+
 	/* Defer to CPU feature registers */
 	return !cpuid_feature_extract_unsigned_field(pfr0,
 						     ID_AA64PFR0_CSV3_SHIFT);
 }
 
+static int __nocfi kpti_install_ng_mappings(void *__unused)
+{
+	typedef void (kpti_remap_fn)(int, int, phys_addr_t);
+	extern kpti_remap_fn idmap_kpti_install_ng_mappings;
+	kpti_remap_fn *remap_fn;
+
+	static bool kpti_applied = false;
+	int cpu = smp_processor_id();
+
+	if (kpti_applied)
+		return 0;
+
+	remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings);
+
+	cpu_install_idmap();
+	remap_fn(cpu, num_online_cpus(), __pa_symbol(swapper_pg_dir));
+	cpu_uninstall_idmap();
+
+	if (!cpu)
+		kpti_applied = true;
+
+	return 0;
+}
+
 static int __init parse_kpti(char *str)
 {
 	bool enabled;
@@ -874,6 +917,7 @@
 		.capability = ARM64_UNMAP_KERNEL_AT_EL0,
 		.def_scope = SCOPE_SYSTEM,
 		.matches = unmap_kernel_at_el0,
+		.enable = kpti_install_ng_mappings,
 	},
 #endif
 	{},
@@ -969,6 +1013,25 @@
 			cap_set_elf_hwcap(hwcaps);
 }
 
+/*
+ * Check if the current CPU has a given feature capability.
+ * Should be called from non-preemptible context.
+ */
+static bool __this_cpu_has_cap(const struct arm64_cpu_capabilities *cap_array,
+			       unsigned int cap)
+{
+	const struct arm64_cpu_capabilities *caps;
+
+	if (WARN_ON(preemptible()))
+		return false;
+
+	for (caps = cap_array; caps->matches; caps++)
+		if (caps->capability == cap &&
+		    caps->matches(caps, SCOPE_LOCAL_CPU))
+			return true;
+	return false;
+}
+
 void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
 			    const char *info)
 {
@@ -1037,8 +1100,9 @@
 }
 
 static void
-verify_local_cpu_features(const struct arm64_cpu_capabilities *caps)
+verify_local_cpu_features(const struct arm64_cpu_capabilities *caps_list)
 {
+	const struct arm64_cpu_capabilities *caps = caps_list;
 	for (; caps->matches; caps++) {
 		if (!cpus_have_cap(caps->capability))
 			continue;
@@ -1046,7 +1110,7 @@
 		 * If the new CPU misses an advertised feature, we cannot proceed
 		 * further, park the cpu.
 		 */
-		if (!caps->matches(caps, SCOPE_LOCAL_CPU)) {
+		if (!__this_cpu_has_cap(caps_list, caps->capability)) {
 			pr_crit("CPU%d: missing feature: %s\n",
 					smp_processor_id(), caps->desc);
 			cpu_die_early();
@@ -1099,22 +1163,12 @@
 	enable_cpu_capabilities(arm64_features);
 }
 
-/*
- * Check if the current CPU has a given feature capability.
- * Should be called from non-preemptible context.
- */
+extern const struct arm64_cpu_capabilities arm64_errata[];
+
 bool this_cpu_has_cap(unsigned int cap)
 {
-	const struct arm64_cpu_capabilities *caps;
-
-	if (WARN_ON(preemptible()))
-		return false;
-
-	for (caps = arm64_features; caps->desc; caps++)
-		if (caps->capability == cap && caps->matches)
-			return caps->matches(caps, SCOPE_LOCAL_CPU);
-
-	return false;
+	return (__this_cpu_has_cap(arm64_features, cap) ||
+		__this_cpu_has_cap(arm64_errata, cap));
 }
 
 void __init setup_cpu_features(void)
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index f8ba35d..7613ed1 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -30,11 +30,13 @@
 #include <asm/irq.h>
 #include <asm/memory.h>
 #include <asm/mmu.h>
+#include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/thread_info.h>
 #include <asm/uaccess.h>
 #include <asm/asm-uaccess.h>
 #include <asm/unistd.h>
+#include <asm/kernel-pgtable.h>
 
 /*
  * Context tracking subsystem.  Used to instrument transitions
@@ -125,10 +127,10 @@
 	.else
 	add	x21, sp, #S_FRAME_SIZE
 	get_thread_info tsk
-	/* Save the task's original addr_limit and set USER_DS (TASK_SIZE_64) */
+	/* Save the task's original addr_limit and set USER_DS */
 	ldr	x20, [tsk, #TSK_TI_ADDR_LIMIT]
 	str	x20, [sp, #S_ORIG_ADDR_LIMIT]
-	mov	x20, #TASK_SIZE_64
+	mov	x20, #USER_DS
 	str	x20, [tsk, #TSK_TI_ADDR_LIMIT]
 	/* No need to reset PSTATE.UAO, hardware's already set it to 0 for us */
 	.endif /* \el == 0 */
@@ -668,8 +670,7 @@
 	 * Instruction abort handling
 	 */
 	mrs	x26, far_el1
-	// enable interrupts before calling the main handler
-	enable_dbg_and_irq
+	msr     daifclr, #(8 | 4 | 1)
 #ifdef CONFIG_TRACE_IRQFLAGS
 	bl	trace_hardirqs_off
 #endif
@@ -704,8 +705,10 @@
 	 * Stack or PC alignment exception handling
 	 */
 	mrs	x26, far_el1
-	// enable interrupts before calling the main handler
-	enable_dbg_and_irq
+	enable_dbg
+#ifdef CONFIG_TRACE_IRQFLAGS
+	bl	trace_hardirqs_off
+#endif
 	ct_user_exit
 	mov	x0, x26
 	mov	x1, x25
@@ -764,6 +767,11 @@
 #endif
 
 	ct_user_exit
+#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
+	tbz	x22, #55, 1f
+	bl	do_el0_irq_bp_hardening
+1:
+#endif
 	irq_handler
 
 #ifdef CONFIG_TRACE_IRQFLAGS
@@ -876,6 +884,7 @@
 	b.ne	__sys_trace
 	cmp     scno, sc_nr                     // check upper syscall limit
 	b.hs	ni_sys
+	mask_nospec64 scno, sc_nr, x19	// enforce bounds for syscall number
 	ldr	x16, [stbl, scno, lsl #3]	// address in the syscall table
 	blr	x16				// call sys_* routine
 	b	ret_fast_syscall
@@ -953,16 +962,9 @@
 	orr	\tmp, \tmp, #USER_ASID_FLAG
 	msr	ttbr1_el1, \tmp
 	/*
-	 * We avoid running the post_ttbr_update_workaround here because the
-	 * user and kernel ASIDs don't have conflicting mappings, so any
-	 * "blessing" as described in:
-	 *
-	 *   http://lkml.kernel.org/r/56BB848A.6060603@caviumnetworks.com
-	 *
-	 * will not hurt correctness. Whilst this may partially defeat the
-	 * point of using split ASIDs in the first place, it avoids
-	 * the hit of invalidating the entire I-cache on every return to
-	 * userspace.
+	 * We avoid running the post_ttbr_update_workaround here because
+	 * it's only needed by Cavium ThunderX, which requires KPTI to be
+	 * disabled.
 	 */
 	.endm
 
@@ -972,6 +974,11 @@
 	.if	\regsize == 64
 	msr	tpidrro_el0, x30	// Restored in kernel_ventry
 	.endif
+	/*
+	 * Defend against branch aliasing attacks by pushing a dummy
+	 * entry onto the return stack and using a RET instruction to
+	 * enter the full-fat kernel vectors.
+	 */
 	bl	2f
 	b	.
 2:
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index c186586..d479185 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -474,7 +474,7 @@
  * end early head section, begin head code that is also used for
  * hotplug and needs to have the same protections as the text region
  */
-	.section ".idmap.text","ax"
+	.section ".idmap.text","awx"
 
 ENTRY(kimage_vaddr)
 	.quad		_text - TEXT_OFFSET
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
index 409abc4..1b3eb67 100644
--- a/arch/arm64/kernel/pci.c
+++ b/arch/arm64/kernel/pci.c
@@ -175,8 +175,10 @@
 		return NULL;
 
 	root_ops = kzalloc_node(sizeof(*root_ops), GFP_KERNEL, node);
-	if (!root_ops)
+	if (!root_ops) {
+		kfree(ri);
 		return NULL;
+	}
 
 	ri->cfg = pci_acpi_setup_ecam_mapping(root);
 	if (!ri->cfg) {
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 52710f1..e0b731e 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -869,15 +869,23 @@
 {
 	unsigned long config_base = 0;
 
-	if (is_kernel_in_hyp_mode() &&
-	    attr->exclude_kernel != attr->exclude_hv)
-		return -EINVAL;
+	/*
+	 * If we're running in hyp mode, then we *are* the hypervisor.
+	 * Therefore we ignore exclude_hv in this configuration, since
+	 * there's no hypervisor to sample anyway. This is consistent
+	 * with other architectures (x86 and Power).
+	 */
+	if (is_kernel_in_hyp_mode()) {
+		if (!attr->exclude_kernel)
+			config_base |= ARMV8_PMU_INCLUDE_EL2;
+	} else {
+		if (attr->exclude_kernel)
+			config_base |= ARMV8_PMU_EXCLUDE_EL1;
+		if (!attr->exclude_hv)
+			config_base |= ARMV8_PMU_INCLUDE_EL2;
+	}
 	if (attr->exclude_user)
 		config_base |= ARMV8_PMU_EXCLUDE_EL0;
-	if (!is_kernel_in_hyp_mode() && attr->exclude_kernel)
-		config_base |= ARMV8_PMU_EXCLUDE_EL1;
-	if (!attr->exclude_hv)
-		config_base |= ARMV8_PMU_INCLUDE_EL2;
 
 	/*
 	 * Install the filter into config_base as this is used to
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index ee0ea17..08ca9dc 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -213,7 +213,7 @@
 		for (j = 0; j < 8; j++) {
 			u32	data;
 			if (probe_kernel_address(p, data)) {
-				printk(" ********");
+				pr_cont(" ********");
 			} else {
 				pr_cont(" %08x", data);
 			}
diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S
index df67652..5a4fbcc 100644
--- a/arch/arm64/kernel/sleep.S
+++ b/arch/arm64/kernel/sleep.S
@@ -95,7 +95,7 @@
 	ret
 ENDPROC(__cpu_suspend_enter)
 
-	.pushsection ".idmap.text", "ax"
+	.pushsection ".idmap.text", "awx"
 ENTRY(cpu_resume)
 	bl	el2_setup		// if in EL2 drop to EL1 cleanly
 	bl	__cpu_setup
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 2e6e9e9..efe43c5 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -22,12 +22,15 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 
+#include <kvm/arm_psci.h>
+
 #include <asm/esr.h>
 #include <asm/kvm_asm.h>
 #include <asm/kvm_coproc.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_mmu.h>
-#include <asm/kvm_psci.h>
+#include <asm/debug-monitors.h>
+#include <asm/traps.h>
 
 #define CREATE_TRACE_POINTS
 #include "trace.h"
@@ -42,7 +45,7 @@
 			    kvm_vcpu_hvc_get_imm(vcpu));
 	vcpu->stat.hvc_exit_stat++;
 
-	ret = kvm_psci_call(vcpu);
+	ret = kvm_hvc_call_handler(vcpu);
 	if (ret < 0) {
 		vcpu_set_reg(vcpu, 0, ~0UL);
 		return 1;
@@ -53,7 +56,16 @@
 
 static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
+	/*
+	 * "If an SMC instruction executed at Non-secure EL1 is
+	 * trapped to EL2 because HCR_EL2.TSC is 1, the exception is a
+	 * Trap exception, not a Secure Monitor Call exception [...]"
+	 *
+	 * We need to advance the PC after the trap, as it would
+	 * otherwise return to the same address...
+	 */
 	vcpu_set_reg(vcpu, 0, ~0UL);
+	kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
 	return 1;
 }
 
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index 4e92399..4e9d50c 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -15,6 +15,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/arm-smccc.h>
 #include <linux/linkage.h>
 
 #include <asm/alternative.h>
@@ -79,10 +80,11 @@
 	lsr	x0, x1, #ESR_ELx_EC_SHIFT
 
 	cmp	x0, #ESR_ELx_EC_HVC64
+	ccmp	x0, #ESR_ELx_EC_HVC32, #4, ne
 	b.ne	el1_trap
 
-	mrs	x1, vttbr_el2		// If vttbr is valid, the 64bit guest
-	cbnz	x1, el1_trap		// called HVC
+	mrs	x1, vttbr_el2		// If vttbr is valid, the guest
+	cbnz	x1, el1_hvc_guest	// called HVC
 
 	/* Here, we're pretty sure the host called HVC. */
 	ldp	x0, x1, [sp], #16
@@ -101,6 +103,20 @@
 
 2:	eret
 
+el1_hvc_guest:
+	/*
+	 * Fastest possible path for ARM_SMCCC_ARCH_WORKAROUND_1.
+	 * The workaround has already been applied on the host,
+	 * so let's quickly get back to the guest. We don't bother
+	 * restoring x1, as it can be clobbered anyway.
+	 */
+	ldr	x1, [sp]				// Guest's x0
+	eor	w1, w1, #ARM_SMCCC_ARCH_WORKAROUND_1
+	cbnz	w1, el1_trap
+	mov	x0, x1
+	add	sp, sp, #16
+	eret
+
 el1_trap:
 	/*
 	 * x0: ESR_EC
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 3eab6ac..849ee8a 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -19,6 +19,8 @@
 #include <linux/jump_label.h>
 #include <uapi/linux/psci.h>
 
+#include <kvm/arm_psci.h>
+
 #include <asm/kvm_asm.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
@@ -311,14 +313,16 @@
 
 	if (exit_code == ARM_EXCEPTION_TRAP &&
 	    (kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC64 ||
-	     kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC32) &&
-	    vcpu_get_reg(vcpu, 0) == PSCI_0_2_FN_PSCI_VERSION) {
-		u64 val = PSCI_RET_NOT_SUPPORTED;
-		if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
-			val = 2;
+	     kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC32)) {
+		u32 val = vcpu_get_reg(vcpu, 0);
 
-		vcpu_set_reg(vcpu, 0, val);
-		goto again;
+		if (val == PSCI_0_2_FN_PSCI_VERSION) {
+			val = kvm_psci_version(vcpu, kern_hyp_va(vcpu->kvm));
+			if (unlikely(val == KVM_ARM_PSCI_0_1))
+				val = PSCI_RET_NOT_SUPPORTED;
+			vcpu_set_reg(vcpu, 0, val);
+			goto again;
+		}
 	}
 
 	if (static_branch_unlikely(&vgic_v2_cpuif_trap) &&
@@ -417,6 +421,7 @@
 
 		vcpu = (struct kvm_vcpu *)read_sysreg(tpidr_el2);
 		host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+		__timer_save_state(vcpu);
 		__deactivate_traps(vcpu);
 		__deactivate_vm(vcpu);
 		__sysreg_restore_host_state(host_ctxt);
diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S
index 07c7ad9..b581e16 100644
--- a/arch/arm64/lib/clear_user.S
+++ b/arch/arm64/lib/clear_user.S
@@ -21,7 +21,7 @@
 
 	.text
 
-/* Prototype: int __clear_user(void *addr, size_t sz)
+/* Prototype: int __arch_clear_user(void *addr, size_t sz)
  * Purpose  : clear some user memory
  * Params   : addr - user memory address to clear
  *          : sz   - number of bytes to clear
@@ -29,7 +29,7 @@
  *
  * Alignment fixed up by hardware.
  */
-ENTRY(__clear_user)
+ENTRY(__arch_clear_user)
 	uaccess_enable_not_uao x2, x3, x4
 	mov	x2, x1			// save the size for fixup return
 	subs	x1, x1, #8
@@ -52,7 +52,7 @@
 5:	mov	x0, #0
 	uaccess_disable_not_uao x2, x3
 	ret
-ENDPROC(__clear_user)
+ENDPROC(__arch_clear_user)
 
 	.section .fixup,"ax"
 	.align	2
diff --git a/arch/arm64/lib/copy_in_user.S b/arch/arm64/lib/copy_in_user.S
index e8bfaf1..800779e 100644
--- a/arch/arm64/lib/copy_in_user.S
+++ b/arch/arm64/lib/copy_in_user.S
@@ -64,14 +64,14 @@
 	.endm
 
 end	.req	x5
-ENTRY(__copy_in_user)
+ENTRY(__arch_copy_in_user)
 	uaccess_enable_not_uao x3, x4, x5
 	add	end, x0, x2
 #include "copy_template.S"
 	uaccess_disable_not_uao x3, x4
 	mov	x0, #0
 	ret
-ENDPROC(__copy_in_user)
+ENDPROC(__arch_copy_in_user)
 
 	.section .fixup,"ax"
 	.align	2
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 2b8950e..6befc9c 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -343,7 +343,7 @@
 		mm_flags |= FAULT_FLAG_WRITE;
 	}
 
-	if (addr < USER_DS && is_permission_fault(esr, regs)) {
+	if (addr < TASK_SIZE && is_permission_fault(esr, regs)) {
 		/* regs->orig_addr_limit may be 0 if we entered from EL0 */
 		if (regs->orig_addr_limit == KERNEL_DS)
 			die("Accessing user space memory with fs=KERNEL_DS", regs, esr);
@@ -618,6 +618,12 @@
 	arm64_notify_die("", regs, &info, esr);
 }
 
+asmlinkage void __exception do_el0_irq_bp_hardening(void)
+{
+	/* PC has already been checked in entry.S */
+	arm64_apply_bp_hardening();
+}
+
 asmlinkage void __exception do_el0_ia_bp_hardening(unsigned long addr,
 						   unsigned int esr,
 						   struct pt_regs *regs)
@@ -644,6 +650,12 @@
 	struct siginfo info;
 	struct task_struct *tsk = current;
 
+	if (user_mode(regs)) {
+		if (instruction_pointer(regs) > TASK_SIZE)
+			arm64_apply_bp_hardening();
+		local_irq_enable();
+	}
+
 	if (show_unhandled_signals && unhandled_signal(tsk, SIGBUS))
 		pr_info_ratelimited("%s[%d]: %s exception: pc=%p sp=%p\n",
 				    tsk->comm, task_pid_nr(tsk),
@@ -703,6 +715,9 @@
 	if (interrupts_enabled(regs))
 		trace_hardirqs_off();
 
+	if (user_mode(regs) && instruction_pointer(regs) > TASK_SIZE)
+		arm64_apply_bp_hardening();
+
 	if (!inf->fn(addr, esr, regs)) {
 		rv = 1;
 	} else {
diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c
index 01c1717..caf75ab 100644
--- a/arch/arm64/mm/mmap.c
+++ b/arch/arm64/mm/mmap.c
@@ -18,6 +18,7 @@
 
 #include <linux/elf.h>
 #include <linux/fs.h>
+#include <linux/memblock.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/export.h>
@@ -102,12 +103,18 @@
  */
 int valid_phys_addr_range(phys_addr_t addr, size_t size)
 {
-	if (addr < PHYS_OFFSET)
-		return 0;
-	if (addr + size > __pa(high_memory - 1) + 1)
-		return 0;
-
-	return 1;
+	/*
+	 * Check whether addr is covered by a memory region without the
+	 * MEMBLOCK_NOMAP attribute, and whether that region covers the
+	 * entire range. In theory, this could lead to false negatives
+	 * if the range is covered by distinct but adjacent memory regions
+	 * that only differ in other attributes. However, few of such
+	 * attributes have been defined, and it is debatable whether it
+	 * follows that /dev/mem read() calls should be able traverse
+	 * such boundaries.
+	 */
+	return memblock_is_region_memory(addr, size) &&
+	       memblock_is_map_memory(addr);
 }
 
 /*
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index e7bf3c3..6e989eb 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -466,7 +466,7 @@
 {
 	extern char __entry_tramp_text_start[];
 
-	pgprot_t prot = PAGE_KERNEL_EXEC;
+	pgprot_t prot = rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC;
 	phys_addr_t pa_start = __pa_symbol(__entry_tramp_text_start);
 
 	/* The trampoline is always mapped and can therefore be global */
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index 2e69a14..3a9af60 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -132,7 +132,7 @@
  *
  * x0: Address of context pointer
  */
-	.pushsection ".idmap.text", "ax"
+	.pushsection ".idmap.text", "awx"
 ENTRY(cpu_do_resume)
 	ldp	x2, x3, [x0]
 	ldp	x4, x5, [x0, #16]
@@ -197,7 +197,17 @@
 	b	post_ttbr_update_workaround	// Back to C code...
 ENDPROC(cpu_do_switch_mm)
 
-	.pushsection ".idmap.text", "ax"
+	.pushsection ".idmap.text", "awx"
+
+.macro	__idmap_cpu_set_reserved_ttbr1, tmp1, tmp2
+	adrp	\tmp1, empty_zero_page
+	msr	ttbr1_el1, \tmp1
+	isb
+	tlbi	vmalle1
+	dsb	nsh
+	isb
+.endm
+
 /*
  * void idmap_cpu_replace_ttbr1(phys_addr_t new_pgd)
  *
@@ -208,13 +218,7 @@
 	mrs	x2, daif
 	msr	daifset, #0xf
 
-	adrp	x1, empty_zero_page
-	msr	ttbr1_el1, x1
-	isb
-
-	tlbi	vmalle1
-	dsb	nsh
-	isb
+	__idmap_cpu_set_reserved_ttbr1 x1, x3
 
 	msr	ttbr1_el1, x0
 	isb
@@ -225,13 +229,196 @@
 ENDPROC(idmap_cpu_replace_ttbr1)
 	.popsection
 
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+	.pushsection ".idmap.text", "awx"
+
+	.macro	__idmap_kpti_get_pgtable_ent, type
+	dc	cvac, cur_\()\type\()p		// Ensure any existing dirty
+	dmb	sy				// lines are written back before
+	ldr	\type, [cur_\()\type\()p]	// loading the entry
+	tbz	\type, #0, next_\()\type	// Skip invalid entries
+	.endm
+
+	.macro __idmap_kpti_put_pgtable_ent_ng, type
+	orr	\type, \type, #PTE_NG		// Same bit for blocks and pages
+	str	\type, [cur_\()\type\()p]	// Update the entry and ensure it
+	dc	civac, cur_\()\type\()p		// is visible to all CPUs.
+	.endm
+
+/*
+ * void __kpti_install_ng_mappings(int cpu, int num_cpus, phys_addr_t swapper)
+ *
+ * Called exactly once from stop_machine context by each CPU found during boot.
+ */
+__idmap_kpti_flag:
+	.long	1
+ENTRY(idmap_kpti_install_ng_mappings)
+	cpu		.req	w0
+	num_cpus	.req	w1
+	swapper_pa	.req	x2
+	swapper_ttb	.req	x3
+	flag_ptr	.req	x4
+	cur_pgdp	.req	x5
+	end_pgdp	.req	x6
+	pgd		.req	x7
+	cur_pudp	.req	x8
+	end_pudp	.req	x9
+	pud		.req	x10
+	cur_pmdp	.req	x11
+	end_pmdp	.req	x12
+	pmd		.req	x13
+	cur_ptep	.req	x14
+	end_ptep	.req	x15
+	pte		.req	x16
+
+	mrs	swapper_ttb, ttbr1_el1
+	adr	flag_ptr, __idmap_kpti_flag
+
+	cbnz	cpu, __idmap_kpti_secondary
+
+	/* We're the boot CPU. Wait for the others to catch up */
+	sevl
+1:	wfe
+	ldaxr	w18, [flag_ptr]
+	eor	w18, w18, num_cpus
+	cbnz	w18, 1b
+
+	/* We need to walk swapper, so turn off the MMU. */
+	mrs	x18, sctlr_el1
+	bic	x18, x18, #SCTLR_ELx_M
+	msr	sctlr_el1, x18
+	isb
+
+	/* Everybody is enjoying the idmap, so we can rewrite swapper. */
+	/* PGD */
+	mov	cur_pgdp, swapper_pa
+	add	end_pgdp, cur_pgdp, #(PTRS_PER_PGD * 8)
+do_pgd:	__idmap_kpti_get_pgtable_ent	pgd
+	tbnz	pgd, #1, walk_puds
+	__idmap_kpti_put_pgtable_ent_ng	pgd
+next_pgd:
+	add	cur_pgdp, cur_pgdp, #8
+	cmp	cur_pgdp, end_pgdp
+	b.ne	do_pgd
+
+	/* Publish the updated tables and nuke all the TLBs */
+	dsb	sy
+	tlbi	vmalle1is
+	dsb	ish
+	isb
+
+	/* We're done: fire up the MMU again */
+	mrs	x18, sctlr_el1
+	orr	x18, x18, #SCTLR_ELx_M
+	msr	sctlr_el1, x18
+	isb
+
+	/* Set the flag to zero to indicate that we're all done */
+	str	wzr, [flag_ptr]
+	ret
+
+	/* PUD */
+walk_puds:
+	.if CONFIG_PGTABLE_LEVELS > 3
+	pte_to_phys	cur_pudp, pgd
+	add	end_pudp, cur_pudp, #(PTRS_PER_PUD * 8)
+do_pud:	__idmap_kpti_get_pgtable_ent	pud
+	tbnz	pud, #1, walk_pmds
+	__idmap_kpti_put_pgtable_ent_ng	pud
+next_pud:
+	add	cur_pudp, cur_pudp, 8
+	cmp	cur_pudp, end_pudp
+	b.ne	do_pud
+	b	next_pgd
+	.else /* CONFIG_PGTABLE_LEVELS <= 3 */
+	mov	pud, pgd
+	b	walk_pmds
+next_pud:
+	b	next_pgd
+	.endif
+
+	/* PMD */
+walk_pmds:
+	.if CONFIG_PGTABLE_LEVELS > 2
+	pte_to_phys	cur_pmdp, pud
+	add	end_pmdp, cur_pmdp, #(PTRS_PER_PMD * 8)
+do_pmd:	__idmap_kpti_get_pgtable_ent	pmd
+	tbnz	pmd, #1, walk_ptes
+	__idmap_kpti_put_pgtable_ent_ng	pmd
+next_pmd:
+	add	cur_pmdp, cur_pmdp, #8
+	cmp	cur_pmdp, end_pmdp
+	b.ne	do_pmd
+	b	next_pud
+	.else /* CONFIG_PGTABLE_LEVELS <= 2 */
+	mov	pmd, pud
+	b	walk_ptes
+next_pmd:
+	b	next_pud
+	.endif
+
+	/* PTE */
+walk_ptes:
+	pte_to_phys	cur_ptep, pmd
+	add	end_ptep, cur_ptep, #(PTRS_PER_PTE * 8)
+do_pte:	__idmap_kpti_get_pgtable_ent	pte
+	__idmap_kpti_put_pgtable_ent_ng	pte
+next_pte:
+	add	cur_ptep, cur_ptep, #8
+	cmp	cur_ptep, end_ptep
+	b.ne	do_pte
+	b	next_pmd
+
+	/* Secondary CPUs end up here */
+__idmap_kpti_secondary:
+	/* Uninstall swapper before surgery begins */
+	__idmap_cpu_set_reserved_ttbr1 x18, x17
+
+	/* Increment the flag to let the boot CPU we're ready */
+1:	ldxr	w18, [flag_ptr]
+	add	w18, w18, #1
+	stxr	w17, w18, [flag_ptr]
+	cbnz	w17, 1b
+
+	/* Wait for the boot CPU to finish messing around with swapper */
+	sevl
+1:	wfe
+	ldxr	w18, [flag_ptr]
+	cbnz	w18, 1b
+
+	/* All done, act like nothing happened */
+	msr	ttbr1_el1, swapper_ttb
+	isb
+	ret
+
+	.unreq	cpu
+	.unreq	num_cpus
+	.unreq	swapper_pa
+	.unreq	swapper_ttb
+	.unreq	flag_ptr
+	.unreq	cur_pgdp
+	.unreq	end_pgdp
+	.unreq	pgd
+	.unreq	cur_pudp
+	.unreq	end_pudp
+	.unreq	pud
+	.unreq	cur_pmdp
+	.unreq	end_pmdp
+	.unreq	pmd
+	.unreq	cur_ptep
+	.unreq	end_ptep
+	.unreq	pte
+ENDPROC(idmap_kpti_install_ng_mappings)
+	.popsection
+#endif
+
 /*
  *	__cpu_setup
  *
  *	Initialise the processor for turning the MMU on.  Return in x0 the
  *	value of the SCTLR_EL1 register.
  */
-	.pushsection ".idmap.text", "ax"
+	.pushsection ".idmap.text", "awx"
 ENTRY(__cpu_setup)
 	tlbi	vmalle1				// Invalidate local TLB
 	dsb	nsh
diff --git a/arch/frv/include/asm/timex.h b/arch/frv/include/asm/timex.h
index a89bdde..139093f 100644
--- a/arch/frv/include/asm/timex.h
+++ b/arch/frv/include/asm/timex.h
@@ -16,5 +16,11 @@
 #define vxtime_lock()		do {} while (0)
 #define vxtime_unlock()		do {} while (0)
 
+/* This attribute is used in include/linux/jiffies.h alongside with
+ * __cacheline_aligned_in_smp. It is assumed that __cacheline_aligned_in_smp
+ * for frv does not contain another section specification.
+ */
+#define __jiffy_arch_data	__attribute__((__section__(".data")))
+
 #endif
 
diff --git a/arch/mips/include/asm/kprobes.h b/arch/mips/include/asm/kprobes.h
index daba1f9..174aedc 100644
--- a/arch/mips/include/asm/kprobes.h
+++ b/arch/mips/include/asm/kprobes.h
@@ -40,7 +40,8 @@
 
 #define flush_insn_slot(p)						\
 do {									\
-	flush_icache_range((unsigned long)p->addr,			\
+	if (p->addr)							\
+		flush_icache_range((unsigned long)p->addr,		\
 			   (unsigned long)p->addr +			\
 			   (MAX_INSN_SIZE * sizeof(kprobe_opcode_t)));	\
 } while (0)
diff --git a/arch/mips/include/asm/pgtable-32.h b/arch/mips/include/asm/pgtable-32.h
index d21f3da..c0be540 100644
--- a/arch/mips/include/asm/pgtable-32.h
+++ b/arch/mips/include/asm/pgtable-32.h
@@ -18,6 +18,10 @@
 
 #include <asm-generic/pgtable-nopmd.h>
 
+#ifdef CONFIG_HIGHMEM
+#include <asm/highmem.h>
+#endif
+
 extern int temp_tlb_entry;
 
 /*
@@ -61,7 +65,8 @@
 
 #define VMALLOC_START	  MAP_BASE
 
-#define PKMAP_BASE		(0xfe000000UL)
+#define PKMAP_END	((FIXADDR_START) & ~((LAST_PKMAP << PAGE_SHIFT)-1))
+#define PKMAP_BASE	(PKMAP_END - PAGE_SIZE * LAST_PKMAP)
 
 #ifdef CONFIG_HIGHMEM
 # define VMALLOC_END	(PKMAP_BASE-2*PAGE_SIZE)
diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h
index 89fa5c0b..c92f4c2 100644
--- a/arch/mips/include/asm/uaccess.h
+++ b/arch/mips/include/asm/uaccess.h
@@ -1257,6 +1257,13 @@
 {
 	__kernel_size_t res;
 
+#ifdef CONFIG_CPU_MICROMIPS
+/* micromips memset / bzero also clobbers t7 & t8 */
+#define bzero_clobbers "$4", "$5", "$6", __UA_t0, __UA_t1, "$15", "$24", "$31"
+#else
+#define bzero_clobbers "$4", "$5", "$6", __UA_t0, __UA_t1, "$31"
+#endif /* CONFIG_CPU_MICROMIPS */
+
 	if (eva_kernel_access()) {
 		__asm__ __volatile__(
 			"move\t$4, %1\n\t"
@@ -1266,7 +1273,7 @@
 			"move\t%0, $6"
 			: "=r" (res)
 			: "r" (addr), "r" (size)
-			: "$4", "$5", "$6", __UA_t0, __UA_t1, "$31");
+			: bzero_clobbers);
 	} else {
 		might_fault();
 		__asm__ __volatile__(
@@ -1277,7 +1284,7 @@
 			"move\t%0, $6"
 			: "=r" (res)
 			: "r" (addr), "r" (size)
-			: "$4", "$5", "$6", __UA_t0, __UA_t1, "$31");
+			: bzero_clobbers);
 	}
 
 	return res;
diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S
index 18a1ccd..2b1bf93 100644
--- a/arch/mips/lib/memset.S
+++ b/arch/mips/lib/memset.S
@@ -218,7 +218,7 @@
 1:	PTR_ADDIU	a0, 1			/* fill bytewise */
 	R10KCBARRIER(0(ra))
 	bne		t1, a0, 1b
-	sb		a1, -1(a0)
+	 EX(sb, a1, -1(a0), .Lsmall_fixup\@)
 
 2:	jr		ra			/* done */
 	move		a2, zero
@@ -251,13 +251,18 @@
 	PTR_L		t0, TI_TASK($28)
 	andi		a2, STORMASK
 	LONG_L		t0, THREAD_BUADDR(t0)
-	LONG_ADDU	a2, t1
+	LONG_ADDU	a2, a0
 	jr		ra
 	LONG_SUBU	a2, t0
 
 .Llast_fixup\@:
 	jr		ra
-	andi		v1, a2, STORMASK
+	 nop
+
+.Lsmall_fixup\@:
+	PTR_SUBU	a2, t1, a0
+	jr		ra
+	 PTR_ADDIU	a2, 1
 
 	.endm
 
diff --git a/arch/mips/mm/pgtable-32.c b/arch/mips/mm/pgtable-32.c
index adc6911..b19a3c5 100644
--- a/arch/mips/mm/pgtable-32.c
+++ b/arch/mips/mm/pgtable-32.c
@@ -51,15 +51,15 @@
 	/*
 	 * Fixed mappings:
 	 */
-	vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
-	fixrange_init(vaddr, vaddr + FIXADDR_SIZE, pgd_base);
+	vaddr = __fix_to_virt(__end_of_fixed_addresses - 1);
+	fixrange_init(vaddr & PMD_MASK, vaddr + FIXADDR_SIZE, pgd_base);
 
 #ifdef CONFIG_HIGHMEM
 	/*
 	 * Permanent kmaps:
 	 */
 	vaddr = PKMAP_BASE;
-	fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);
+	fixrange_init(vaddr & PMD_MASK, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);
 
 	pgd = swapper_pg_dir + __pgd_offset(vaddr);
 	pud = pud_offset(pgd, vaddr);
diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c
index 700e2d2..2e68ca1 100644
--- a/arch/parisc/kernel/drivers.c
+++ b/arch/parisc/kernel/drivers.c
@@ -648,6 +648,10 @@
 					(modpath->mod == PCI_FUNC(devfn)));
 	}
 
+	/* index might be out of bounds for bc[] */
+	if (index >= 6)
+		return 0;
+
 	id = PCI_SLOT(pdev->devfn) | (PCI_FUNC(pdev->devfn) << 5);
 	return (modpath->bc[index] == id);
 }
diff --git a/arch/powerpc/include/asm/barrier.h b/arch/powerpc/include/asm/barrier.h
index c0deafc..798ab37 100644
--- a/arch/powerpc/include/asm/barrier.h
+++ b/arch/powerpc/include/asm/barrier.h
@@ -34,7 +34,8 @@
 #define rmb()  __asm__ __volatile__ ("sync" : : : "memory")
 #define wmb()  __asm__ __volatile__ ("sync" : : : "memory")
 
-#ifdef __SUBARCH_HAS_LWSYNC
+/* The sub-arch has lwsync */
+#if defined(__powerpc64__) || defined(CONFIG_PPC_E500MC)
 #    define SMPWMB      LWSYNC
 #else
 #    define SMPWMB      eieio
diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h
index cd4ffd8..bb9073a 100644
--- a/arch/powerpc/include/asm/module.h
+++ b/arch/powerpc/include/asm/module.h
@@ -14,6 +14,10 @@
 #include <asm-generic/module.h>
 
 
+#ifdef CC_USING_MPROFILE_KERNEL
+#define MODULE_ARCH_VERMAGIC	"mprofile-kernel"
+#endif
+
 #ifndef __powerpc64__
 /*
  * Thanks to Paul M for explaining this.
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index e958b70..9e5e0d9 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -21,6 +21,9 @@
 /* We calculate number of sg entries based on PAGE_SIZE */
 #define SG_ENTRIES_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct opal_sg_entry))
 
+/* Default time to sleep or delay between OPAL_BUSY/OPAL_BUSY_EVENT loops */
+#define OPAL_BUSY_DELAY_MS	10
+
 /* /sys/firmware/opal */
 extern struct kobject *opal_kobj;
 
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index 56398e7..71c6988 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -132,7 +132,19 @@
 #define virt_to_pfn(kaddr)	(__pa(kaddr) >> PAGE_SHIFT)
 #define virt_to_page(kaddr)	pfn_to_page(virt_to_pfn(kaddr))
 #define pfn_to_kaddr(pfn)	__va((pfn) << PAGE_SHIFT)
+
+#ifdef CONFIG_PPC_BOOK3S_64
+/*
+ * On hash the vmalloc and other regions alias to the kernel region when passed
+ * through __pa(), which virt_to_pfn() uses. That means virt_addr_valid() can
+ * return true for some vmalloc addresses, which is incorrect. So explicitly
+ * check that the address is in the kernel region.
+ */
+#define virt_addr_valid(kaddr) (REGION_ID(kaddr) == KERNEL_REGION_ID && \
+				pfn_valid(virt_to_pfn(kaddr)))
+#else
 #define virt_addr_valid(kaddr)	pfn_valid(virt_to_pfn(kaddr))
+#endif
 
 /*
  * On Book-E parts we need __va to parse the device tree and we can't
diff --git a/arch/powerpc/include/asm/synch.h b/arch/powerpc/include/asm/synch.h
index 78efe8d..30f2d6d 100644
--- a/arch/powerpc/include/asm/synch.h
+++ b/arch/powerpc/include/asm/synch.h
@@ -5,10 +5,6 @@
 #include <linux/stringify.h>
 #include <asm/feature-fixups.h>
 
-#if defined(__powerpc64__) || defined(CONFIG_PPC_E500MC)
-#define __SUBARCH_HAS_LWSYNC
-#endif
-
 #ifndef __ASSEMBLY__
 extern unsigned int __start___lwsync_fixup, __stop___lwsync_fixup;
 extern void do_lwsync_fixups(unsigned long value, void *fixup_start,
diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c
index de7d091..1abd8dd 100644
--- a/arch/powerpc/kernel/eeh_pe.c
+++ b/arch/powerpc/kernel/eeh_pe.c
@@ -795,7 +795,8 @@
 	eeh_ops->write_config(pdn, 15*4, 4, edev->config_space[15]);
 
 	/* PCI Command: 0x4 */
-	eeh_ops->write_config(pdn, PCI_COMMAND, 4, edev->config_space[1]);
+	eeh_ops->write_config(pdn, PCI_COMMAND, 4, edev->config_space[1] |
+			      PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
 
 	/* Check the PCIe link is ready */
 	eeh_bridge_check_link(edev);
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 7614d1d..94b5dfb 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -723,7 +723,7 @@
 	ld	r3, PACA_EXSLB+EX_DAR(r13)
 	std	r3, _DAR(r1)
 	beq	cr6, 2f
-	li	r10, 0x480		/* fix trap number for I-SLB miss */
+	li	r10, 0x481		/* fix trap number for I-SLB miss */
 	std	r10, _TRAP(r1)
 2:	bl	save_nvgprs
 	addi	r3, r1, STACK_FRAME_OVERHEAD
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 028a22b..ad713f7 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -372,6 +372,14 @@
 	 */
 	WARN_ON(!arch_irqs_disabled());
 
+	/*
+	 * Interrupts must always be hard disabled before irq_happened is
+	 * modified (to prevent lost update in case of interrupt between
+	 * load and store).
+	 */
+	__hard_irq_disable();
+	local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
+
 	/* Indicate in the PACA that we have an interrupt to replay */
 	local_paca->irq_happened |= PACA_IRQ_EE;
 }
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index f1d7e99..ab7b661 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -719,12 +719,20 @@
 static void start_cpu_decrementer(void)
 {
 #if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
+	unsigned int tcr;
+
 	/* Clear any pending timer interrupts */
 	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
 
-	/* Enable decrementer interrupt */
-	mtspr(SPRN_TCR, TCR_DIE);
-#endif /* defined(CONFIG_BOOKE) || defined(CONFIG_40x) */
+	tcr = mfspr(SPRN_TCR);
+	/*
+	 * The watchdog may have already been enabled by u-boot. So leave
+	 * TRC[WP] (Watchdog Period) alone.
+	 */
+	tcr &= TCR_WP_MASK;	/* Clear all bits except for TCR[WP] */
+	tcr |= TCR_DIE;		/* Enable decrementer */
+	mtspr(SPRN_TCR, tcr);
+#endif
 }
 
 void __init generic_calibrate_decr(void)
diff --git a/arch/powerpc/kvm/book3s_pr_papr.c b/arch/powerpc/kvm/book3s_pr_papr.c
index 02176fd..286a3b0 100644
--- a/arch/powerpc/kvm/book3s_pr_papr.c
+++ b/arch/powerpc/kvm/book3s_pr_papr.c
@@ -50,7 +50,9 @@
 	pteg_addr = get_pteg_addr(vcpu, pte_index);
 
 	mutex_lock(&vcpu->kvm->arch.hpt_mutex);
-	copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg));
+	ret = H_FUNCTION;
+	if (copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg)))
+		goto done;
 	hpte = pteg;
 
 	ret = H_PTEG_FULL;
@@ -71,7 +73,9 @@
 	hpte[0] = cpu_to_be64(kvmppc_get_gpr(vcpu, 6));
 	hpte[1] = cpu_to_be64(kvmppc_get_gpr(vcpu, 7));
 	pteg_addr += i * HPTE_SIZE;
-	copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE);
+	ret = H_FUNCTION;
+	if (copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE))
+		goto done;
 	kvmppc_set_gpr(vcpu, 4, pte_index | i);
 	ret = H_SUCCESS;
 
@@ -93,7 +97,9 @@
 
 	pteg = get_pteg_addr(vcpu, pte_index);
 	mutex_lock(&vcpu->kvm->arch.hpt_mutex);
-	copy_from_user(pte, (void __user *)pteg, sizeof(pte));
+	ret = H_FUNCTION;
+	if (copy_from_user(pte, (void __user *)pteg, sizeof(pte)))
+		goto done;
 	pte[0] = be64_to_cpu((__force __be64)pte[0]);
 	pte[1] = be64_to_cpu((__force __be64)pte[1]);
 
@@ -103,7 +109,9 @@
 	    ((flags & H_ANDCOND) && (pte[0] & avpn) != 0))
 		goto done;
 
-	copy_to_user((void __user *)pteg, &v, sizeof(v));
+	ret = H_FUNCTION;
+	if (copy_to_user((void __user *)pteg, &v, sizeof(v)))
+		goto done;
 
 	rb = compute_tlbie_rb(pte[0], pte[1], pte_index);
 	vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
@@ -171,7 +179,10 @@
 		}
 
 		pteg = get_pteg_addr(vcpu, tsh & H_BULK_REMOVE_PTEX);
-		copy_from_user(pte, (void __user *)pteg, sizeof(pte));
+		if (copy_from_user(pte, (void __user *)pteg, sizeof(pte))) {
+			ret = H_FUNCTION;
+			break;
+		}
 		pte[0] = be64_to_cpu((__force __be64)pte[0]);
 		pte[1] = be64_to_cpu((__force __be64)pte[1]);
 
@@ -184,7 +195,10 @@
 			tsh |= H_BULK_REMOVE_NOT_FOUND;
 		} else {
 			/* Splat the pteg in (userland) hpt */
-			copy_to_user((void __user *)pteg, &v, sizeof(v));
+			if (copy_to_user((void __user *)pteg, &v, sizeof(v))) {
+				ret = H_FUNCTION;
+				break;
+			}
 
 			rb = compute_tlbie_rb(pte[0], pte[1],
 					      tsh & H_BULK_REMOVE_PTEX);
@@ -211,7 +225,9 @@
 
 	pteg = get_pteg_addr(vcpu, pte_index);
 	mutex_lock(&vcpu->kvm->arch.hpt_mutex);
-	copy_from_user(pte, (void __user *)pteg, sizeof(pte));
+	ret = H_FUNCTION;
+	if (copy_from_user(pte, (void __user *)pteg, sizeof(pte)))
+		goto done;
 	pte[0] = be64_to_cpu((__force __be64)pte[0]);
 	pte[1] = be64_to_cpu((__force __be64)pte[1]);
 
@@ -234,7 +250,9 @@
 	vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
 	pte[0] = (__force u64)cpu_to_be64(pte[0]);
 	pte[1] = (__force u64)cpu_to_be64(pte[1]);
-	copy_to_user((void __user *)pteg, pte, sizeof(pte));
+	ret = H_FUNCTION;
+	if (copy_to_user((void __user *)pteg, pte, sizeof(pte)))
+		goto done;
 	ret = H_SUCCESS;
 
  done:
diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
index e86bfa1..46c8338 100644
--- a/arch/powerpc/lib/feature-fixups.c
+++ b/arch/powerpc/lib/feature-fixups.c
@@ -55,7 +55,7 @@
 		unsigned int *target = (unsigned int *)branch_target(src);
 
 		/* Branch within the section doesn't need translating */
-		if (target < alt_start || target >= alt_end) {
+		if (target < alt_start || target > alt_end) {
 			instr = translate_branch(dest, src);
 			if (!instr)
 				return 1;
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c
index 85c85eb..b4abf9d 100644
--- a/arch/powerpc/platforms/cell/spufs/coredump.c
+++ b/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -175,6 +175,8 @@
 	skip = roundup(cprm->pos - total + sz, 4) - cprm->pos;
 	if (!dump_skip(cprm, skip))
 		goto Eio;
+
+	rc = 0;
 out:
 	free_page((unsigned long)buf);
 	return rc;
diff --git a/arch/powerpc/platforms/powernv/opal-nvram.c b/arch/powerpc/platforms/powernv/opal-nvram.c
index 9db4398..1bceb95 100644
--- a/arch/powerpc/platforms/powernv/opal-nvram.c
+++ b/arch/powerpc/platforms/powernv/opal-nvram.c
@@ -11,6 +11,7 @@
 
 #define DEBUG
 
+#include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/of.h>
@@ -56,9 +57,17 @@
 
 	while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
 		rc = opal_write_nvram(__pa(buf), count, off);
-		if (rc == OPAL_BUSY_EVENT)
+		if (rc == OPAL_BUSY_EVENT) {
+			msleep(OPAL_BUSY_DELAY_MS);
 			opal_poll_events(NULL);
+		} else if (rc == OPAL_BUSY) {
+			msleep(OPAL_BUSY_DELAY_MS);
+		}
 	}
+
+	if (rc)
+		return -EIO;
+
 	*index += count;
 	return count;
 }
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c
index 3e828b2..2842f9d 100644
--- a/arch/powerpc/sysdev/mpc8xx_pic.c
+++ b/arch/powerpc/sysdev/mpc8xx_pic.c
@@ -79,7 +79,7 @@
 	irq = in_be32(&siu_reg->sc_sivec) >> 26;
 
 	if (irq == PIC_VEC_SPURRIOUS)
-		irq = 0;
+		return 0;
 
         return irq_linear_revmap(mpc8xx_pic_host, irq);
 
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index 09bccb2..2a17123 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -318,7 +318,7 @@
 
 	if (sb->s_root)
 		hypfs_delete_tree(sb->s_root);
-	if (sb_info->update_file)
+	if (sb_info && sb_info->update_file)
 		hypfs_remove(sb_info->update_file);
 	kfree(sb->s_fs_info);
 	sb->s_fs_info = NULL;
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 295bfb7..39127b6 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -798,6 +798,7 @@
 	/* copy and convert to ebcdic */
 	memcpy(ipb->hdr.loadparm, buf, lp_len);
 	ASCEBC(ipb->hdr.loadparm, LOADPARM_LEN);
+	ipb->hdr.flags |= DIAG308_FLAGS_LP_VALID;
 	return len;
 }
 
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index 3667d20..115bda2 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -31,8 +31,14 @@
 {
 	. = 0x00000000;
 	.text : {
-	_text = .;		/* Text and read-only data */
+		/* Text and read-only data */
 		HEAD_TEXT
+		/*
+		 * E.g. perf doesn't like symbols starting at address zero,
+		 * therefore skip the initial PSW and channel program located
+		 * at address zero and let _text start at 0x200.
+		 */
+	_text = 0x200;
 		TEXT_TEXT
 		SCHED_TEXT
 		CPUIDLE_TEXT
diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c
index 59d5038..9cc600b 100644
--- a/arch/sparc/kernel/ldc.c
+++ b/arch/sparc/kernel/ldc.c
@@ -1733,9 +1733,14 @@
 
 		lp->rcv_nxt = p->seqid;
 
+		/*
+		 * If this is a control-only packet, there is nothing
+		 * else to do but advance the rx queue since the packet
+		 * was already processed above.
+		 */
 		if (!(p->type & LDC_DATA)) {
 			new = rx_advance(lp, new);
-			goto no_data;
+			break;
 		}
 		if (p->stype & (LDC_ACK | LDC_NACK)) {
 			err = data_ack_nack(lp, p);
diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
index 2db18cb..c019709 100644
--- a/arch/um/os-Linux/file.c
+++ b/arch/um/os-Linux/file.c
@@ -12,6 +12,7 @@
 #include <sys/mount.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
+#include <sys/sysmacros.h>
 #include <sys/un.h>
 #include <sys/types.h>
 #include <os.h>
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index a86d7cc..bf0acb8 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -16,6 +16,7 @@
 #include <os.h>
 #include <sysdep/mcontext.h>
 #include <um_malloc.h>
+#include <sys/ucontext.h>
 
 void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = {
 	[SIGTRAP]	= relay_signal,
@@ -159,7 +160,7 @@
 
 static void hard_handler(int sig, siginfo_t *si, void *p)
 {
-	struct ucontext *uc = p;
+	ucontext_t *uc = p;
 	mcontext_t *mc = &uc->uc_mcontext;
 	unsigned long pending = 1UL << sig;
 
diff --git a/arch/x86/boot/compressed/error.h b/arch/x86/boot/compressed/error.h
index 2e59dac..d732e60 100644
--- a/arch/x86/boot/compressed/error.h
+++ b/arch/x86/boot/compressed/error.h
@@ -1,7 +1,9 @@
 #ifndef BOOT_COMPRESSED_ERROR_H
 #define BOOT_COMPRESSED_ERROR_H
 
+#include <linux/compiler.h>
+
 void warn(char *m);
-void error(char *m);
+void error(char *m) __noreturn;
 
 #endif /* BOOT_COMPRESSED_ERROR_H */
diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig
new file mode 100644
index 0000000..43c9575
--- /dev/null
+++ b/arch/x86/configs/x86_64_cuttlefish_defconfig
@@ -0,0 +1,454 @@
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_FHANDLE is not set
+# CONFIG_USELIB is not set
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_CGROUP_BPF=y
+CONFIG_NAMESPACES=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_LZ4 is not set
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_PCSPKR_PLATFORM is not set
+CONFIG_BPF_SYSCALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_JUMP_LABEL=y
+CONFIG_CC_STACKPROTECTOR_STRONG=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_SMP=y
+CONFIG_HYPERVISOR_GUEST=y
+CONFIG_PARAVIRT=y
+CONFIG_PARAVIRT_SPINLOCKS=y
+CONFIG_MCORE2=y
+CONFIG_PROCESSOR_SELECT=y
+# CONFIG_CPU_SUP_CENTAUR is not set
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT=y
+# CONFIG_MICROCODE is not set
+CONFIG_X86_MSR=y
+CONFIG_X86_CPUID=y
+CONFIG_KSM=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+CONFIG_TRANSPARENT_HUGEPAGE=y
+# CONFIG_MTRR is not set
+CONFIG_HZ_100=y
+CONFIG_KEXEC=y
+CONFIG_CRASH_DUMP=y
+CONFIG_PHYSICAL_START=0x200000
+CONFIG_RANDOMIZE_BASE=y
+CONFIG_PHYSICAL_ALIGN=0x1000000
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0 reboot=p"
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_PM_DEBUG=y
+CONFIG_ACPI_PROCFS_POWER=y
+# CONFIG_ACPI_FAN is not set
+# CONFIG_ACPI_THERMAL is not set
+# CONFIG_X86_PM_TIMER is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_X86_ACPI_CPUFREQ=y
+# CONFIG_X86_ACPI_CPUFREQ_CPB is not set
+CONFIG_PCI_MMCONFIG=y
+CONFIG_PCI_MSI=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_BINFMT_MISC=y
+CONFIG_IA32_EMULATION=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_TCP_CONG_ADVANCED=y
+# CONFIG_TCP_CONG_BIC is not set
+# CONFIG_TCP_CONG_WESTWOOD is not set
+# CONFIG_TCP_CONG_HTCP is not set
+CONFIG_TCP_MD5SIG=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_NETLABEL=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_IPV6HEADER=y
+CONFIG_IP6_NF_MATCH_RPFILTER=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_CFG80211=y
+CONFIG_MAC80211=y
+CONFIG_RFKILL=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEBUG_DEVRES=y
+CONFIG_OF=y
+CONFIG_OF_UNITTEST=y
+# CONFIG_PNP_DEBUG_MESSAGES is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_VIRTIO_BLK=y
+CONFIG_UID_SYS_STATS=y
+CONFIG_MEMORY_STATE_TIME=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_SPI_ATTRS=y
+CONFIG_SCSI_VIRTIO=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_MIRROR=y
+CONFIG_DM_ZERO=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_NETDEVICES=y
+CONFIG_NETCONSOLE=y
+CONFIG_NETCONSOLE_DYNAMIC=y
+CONFIG_TUN=y
+CONFIG_VIRTIO_NET=y
+# CONFIG_ETHERNET is not set
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_USB_USBNET=y
+# CONFIG_USB_NET_AX8817X is not set
+# CONFIG_USB_NET_AX88179_178A is not set
+# CONFIG_USB_NET_CDCETHER is not set
+# CONFIG_USB_NET_CDC_NCM is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+# CONFIG_USB_NET_ZAURUS is not set
+# CONFIG_WLAN_VENDOR_ADMTEK is not set
+# CONFIG_WLAN_VENDOR_ATH is not set
+# CONFIG_WLAN_VENDOR_ATMEL is not set
+# CONFIG_WLAN_VENDOR_BROADCOM is not set
+# CONFIG_WLAN_VENDOR_CISCO is not set
+# CONFIG_WLAN_VENDOR_INTEL is not set
+# CONFIG_WLAN_VENDOR_INTERSIL is not set
+# CONFIG_WLAN_VENDOR_MARVELL is not set
+# CONFIG_WLAN_VENDOR_MEDIATEK is not set
+# CONFIG_WLAN_VENDOR_RALINK is not set
+# CONFIG_WLAN_VENDOR_REALTEK is not set
+# CONFIG_WLAN_VENDOR_RSI is not set
+# CONFIG_WLAN_VENDOR_ST is not set
+# CONFIG_WLAN_VENDOR_TI is not set
+# CONFIG_WLAN_VENDOR_ZYDAS is not set
+CONFIG_MAC80211_HWSIM=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYRESET=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_XPAD=y
+CONFIG_JOYSTICK_XPAD_FF=y
+CONFIG_JOYSTICK_XPAD_LEDS=y
+CONFIG_INPUT_TABLET=y
+CONFIG_TABLET_USB_ACECAD=y
+CONFIG_TABLET_USB_AIPTEK=y
+CONFIG_TABLET_USB_GTCO=y
+CONFIG_TABLET_USB_HANWANG=y
+CONFIG_TABLET_USB_KBTAB=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_KEYCHORD=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=48
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_INTEL is not set
+# CONFIG_HW_RANDOM_AMD is not set
+# CONFIG_HW_RANDOM_VIA is not set
+CONFIG_HW_RANDOM_VIRTIO=y
+CONFIG_HPET=y
+# CONFIG_HPET_MMAP_DEFAULT is not set
+# CONFIG_DEVPORT is not set
+# CONFIG_ACPI_I2C_OPREGION is not set
+# CONFIG_I2C_COMPAT is not set
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_PTP_1588_CLOCK=y
+# CONFIG_HWMON is not set
+# CONFIG_X86_PKG_TEMP_THERMAL is not set
+CONFIG_WATCHDOG=y
+CONFIG_SOFT_WATCHDOG=y
+CONFIG_MEDIA_SUPPORT=y
+# CONFIG_DVB_TUNER_DIB0070 is not set
+# CONFIG_DVB_TUNER_DIB0090 is not set
+# CONFIG_VGA_ARB is not set
+CONFIG_DRM=y
+# CONFIG_DRM_FBDEV_EMULATION is not set
+CONFIG_DRM_VIRTIO_GPU=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_HIDRAW=y
+CONFIG_UHID=y
+# CONFIG_HID_GENERIC is not set
+CONFIG_HID_A4TECH=y
+CONFIG_HID_ACRUX=y
+CONFIG_HID_ACRUX_FF=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_PRODIKEYS=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_DRAGONRISE=y
+CONFIG_DRAGONRISE_FF=y
+CONFIG_HID_EMS_FF=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_HOLTEK=y
+CONFIG_HID_KEYTOUCH=y
+CONFIG_HID_KYE=y
+CONFIG_HID_UCLOGIC=y
+CONFIG_HID_WALTOP=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LCPOWER=y
+CONFIG_HID_LOGITECH=y
+CONFIG_HID_LOGITECH_DJ=y
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_LOGIG940_FF=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_ORTEK=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_PANTHERLORD_FF=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_PICOLCD=y
+CONFIG_HID_PRIMAX=y
+CONFIG_HID_ROCCAT=y
+CONFIG_HID_SAITEK=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SPEEDLINK=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+CONFIG_GREENASIA_FF=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_SMARTJOYPLUS_FF=y
+CONFIG_HID_TIVO=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_HID_WACOM=y
+CONFIG_HID_WIIMOTE=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_HID_ZYDACRON=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_DUMMY_HCD=y
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_ACC=y
+CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_HCTOSYS is not set
+CONFIG_SW_SYNC=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_BALLOON=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_VSOC=y
+CONFIG_ION=y
+# CONFIG_X86_PLATFORM_DEVICES is not set
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+# CONFIG_FIRMWARE_MEMMAP is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+CONFIG_QFMT_V2=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_HUGETLBFS=y
+CONFIG_SDCARD_FS=y
+CONFIG_PSTORE=y
+CONFIG_PSTORE_CONSOLE=y
+CONFIG_PSTORE_RAM=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_PANIC_TIMEOUT=5
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_IO_DELAY_NONE=y
+CONFIG_DEBUG_BOOT_PARAMS=y
+CONFIG_OPTIMIZE_INLINING=y
+CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_PATH=y
+CONFIG_HARDENED_USERCOPY=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
diff --git a/arch/x86/crypto/cast5_avx_glue.c b/arch/x86/crypto/cast5_avx_glue.c
index 8648158..f8fe11d 100644
--- a/arch/x86/crypto/cast5_avx_glue.c
+++ b/arch/x86/crypto/cast5_avx_glue.c
@@ -66,8 +66,6 @@
 	void (*fn)(struct cast5_ctx *ctx, u8 *dst, const u8 *src);
 	int err;
 
-	fn = (enc) ? cast5_ecb_enc_16way : cast5_ecb_dec_16way;
-
 	err = blkcipher_walk_virt(desc, walk);
 	desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
@@ -79,6 +77,7 @@
 
 		/* Process multi-block batch */
 		if (nbytes >= bsize * CAST5_PARALLEL_BLOCKS) {
+			fn = (enc) ? cast5_ecb_enc_16way : cast5_ecb_dec_16way;
 			do {
 				fn(ctx, wdst, wsrc);
 
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c
index b8d3f1b..91c48cd 100644
--- a/arch/x86/kernel/kprobes/core.c
+++ b/arch/x86/kernel/kprobes/core.c
@@ -51,6 +51,7 @@
 #include <linux/ftrace.h>
 #include <linux/frame.h>
 #include <linux/kasan.h>
+#include <linux/moduleloader.h>
 
 #include <asm/text-patching.h>
 #include <asm/cacheflush.h>
@@ -405,6 +406,14 @@
 	return length;
 }
 
+/* Recover page to RW mode before releasing it */
+void free_insn_page(void *page)
+{
+	set_memory_nx((unsigned long)page & PAGE_MASK, 1);
+	set_memory_rw((unsigned long)page & PAGE_MASK, 1);
+	module_memfree(page);
+}
+
 static int arch_copy_kprobe(struct kprobe *p)
 {
 	int ret;
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index d07a9390..bbfb03ec 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -366,6 +366,8 @@
 		tsc_clocksource_reliable = 1;
 	if (!strncmp(str, "noirqtime", 9))
 		no_sched_irq_time = 1;
+	if (!strcmp(str, "unstable"))
+		mark_tsc_unstable("boot parameter");
 	return 1;
 }
 
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index b24b3c6..5c3d416f 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -1363,8 +1363,10 @@
 
 static void cancel_hv_tscdeadline(struct kvm_lapic *apic)
 {
+	preempt_disable();
 	kvm_x86_ops->cancel_hv_timer(apic->vcpu);
 	apic->lapic_timer.hv_timer_in_use = false;
+	preempt_enable();
 }
 
 void kvm_lapic_expired_hv_timer(struct kvm_vcpu *vcpu)
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 8c99f2f..aaa93b4 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -1879,6 +1879,7 @@
 		 */
 		if (var->unusable)
 			var->db = 0;
+		/* This is symmetric with svm_set_segment() */
 		var->dpl = to_svm(vcpu)->vmcb->save.cpl;
 		break;
 	}
@@ -2024,18 +2025,14 @@
 	s->base = var->base;
 	s->limit = var->limit;
 	s->selector = var->selector;
-	if (var->unusable)
-		s->attrib = 0;
-	else {
-		s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK);
-		s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT;
-		s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT;
-		s->attrib |= (var->present & 1) << SVM_SELECTOR_P_SHIFT;
-		s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT;
-		s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT;
-		s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT;
-		s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT;
-	}
+	s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK);
+	s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT;
+	s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT;
+	s->attrib |= ((var->present & 1) && !var->unusable) << SVM_SELECTOR_P_SHIFT;
+	s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT;
+	s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT;
+	s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT;
+	s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT;
 
 	/*
 	 * This is always accurate, except if SYSRET returned to a segment
@@ -2044,7 +2041,8 @@
 	 * would entail passing the CPL to userspace and back.
 	 */
 	if (seg == VCPU_SREG_SS)
-		svm->vmcb->save.cpl = (s->attrib >> SVM_SELECTOR_DPL_SHIFT) & 3;
+		/* This is symmetric with svm_get_segment() */
+		svm->vmcb->save.cpl = (var->dpl & 3);
 
 	mark_dirty(svm->vmcb, VMCB_SEG);
 }
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 9c51710..ff2030f 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -7924,11 +7924,13 @@
 {
 	unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
 	int cr = exit_qualification & 15;
-	int reg = (exit_qualification >> 8) & 15;
-	unsigned long val = kvm_register_readl(vcpu, reg);
+	int reg;
+	unsigned long val;
 
 	switch ((exit_qualification >> 4) & 3) {
 	case 0: /* mov to cr */
+		reg = (exit_qualification >> 8) & 15;
+		val = kvm_register_readl(vcpu, reg);
 		switch (cr) {
 		case 0:
 			if (vmcs12->cr0_guest_host_mask &
@@ -7983,6 +7985,7 @@
 		 * lmsw can change bits 1..3 of cr0, and only set bit 0 of
 		 * cr0. Other attempted changes are ignored, with no exit.
 		 */
+		val = (exit_qualification >> LMSW_SOURCE_DATA_SHIFT) & 0x0f;
 		if (vmcs12->cr0_guest_host_mask & 0xe &
 		    (val ^ vmcs12->cr0_read_shadow))
 			return true;
@@ -10660,8 +10663,7 @@
 		vmcs12->guest_pdptr3 = vmcs_read64(GUEST_PDPTR3);
 	}
 
-	if (nested_cpu_has_ept(vmcs12))
-		vmcs12->guest_linear_address = vmcs_readl(GUEST_LINEAR_ADDRESS);
+	vmcs12->guest_linear_address = vmcs_readl(GUEST_LINEAR_ADDRESS);
 
 	if (nested_cpu_has_vid(vmcs12))
 		vmcs12->guest_intr_status = vmcs_read16(GUEST_INTR_STATUS);
diff --git a/arch/x86/lib/csum-copy_64.S b/arch/x86/lib/csum-copy_64.S
index 7e48807..45a53df 100644
--- a/arch/x86/lib/csum-copy_64.S
+++ b/arch/x86/lib/csum-copy_64.S
@@ -55,7 +55,7 @@
 	movq  %r12, 3*8(%rsp)
 	movq  %r14, 4*8(%rsp)
 	movq  %r13, 5*8(%rsp)
-	movq  %rbp, 6*8(%rsp)
+	movq  %r15, 6*8(%rsp)
 
 	movq  %r8, (%rsp)
 	movq  %r9, 1*8(%rsp)
@@ -74,7 +74,7 @@
 	/* main loop. clear in 64 byte blocks */
 	/* r9: zero, r8: temp2, rbx: temp1, rax: sum, rcx: saved length */
 	/* r11:	temp3, rdx: temp4, r12 loopcnt */
-	/* r10:	temp5, rbp: temp6, r14 temp7, r13 temp8 */
+	/* r10:	temp5, r15: temp6, r14 temp7, r13 temp8 */
 	.p2align 4
 .Lloop:
 	source
@@ -89,7 +89,7 @@
 	source
 	movq  32(%rdi), %r10
 	source
-	movq  40(%rdi), %rbp
+	movq  40(%rdi), %r15
 	source
 	movq  48(%rdi), %r14
 	source
@@ -103,7 +103,7 @@
 	adcq  %r11, %rax
 	adcq  %rdx, %rax
 	adcq  %r10, %rax
-	adcq  %rbp, %rax
+	adcq  %r15, %rax
 	adcq  %r14, %rax
 	adcq  %r13, %rax
 
@@ -121,7 +121,7 @@
 	dest
 	movq %r10, 32(%rsi)
 	dest
-	movq %rbp, 40(%rsi)
+	movq %r15, 40(%rsi)
 	dest
 	movq %r14, 48(%rsi)
 	dest
@@ -203,7 +203,7 @@
 	movq 3*8(%rsp), %r12
 	movq 4*8(%rsp), %r14
 	movq 5*8(%rsp), %r13
-	movq 6*8(%rsp), %rbp
+	movq 6*8(%rsp), %r15
 	addq $7*8, %rsp
 	ret
 
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 274dfc4..a0e85f2 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -832,9 +832,11 @@
 
 	/*
 	 * We don't do virtual mode, since we don't do runtime services, on
-	 * non-native EFI
+	 * non-native EFI. With efi=old_map, we don't do runtime services in
+	 * kexec kernel because in the initial boot something else might
+	 * have been mapped at these virtual addresses.
 	 */
-	if (!efi_is_native()) {
+	if (!efi_is_native() || efi_enabled(EFI_OLD_MEMMAP)) {
 		efi_memmap_unmap();
 		clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
 		return;
diff --git a/arch/x86/um/stub_segv.c b/arch/x86/um/stub_segv.c
index 1518d28..27361cb 100644
--- a/arch/x86/um/stub_segv.c
+++ b/arch/x86/um/stub_segv.c
@@ -6,11 +6,12 @@
 #include <sysdep/stub.h>
 #include <sysdep/faultinfo.h>
 #include <sysdep/mcontext.h>
+#include <sys/ucontext.h>
 
 void __attribute__ ((__section__ (".__syscall_stub")))
 stub_segv_handler(int sig, siginfo_t *info, void *p)
 {
-	struct ucontext *uc = p;
+	ucontext_t *uc = p;
 
 	GET_FAULTINFO_FROM_MC(*((struct faultinfo *) STUB_DATA),
 			      &uc->uc_mcontext);
diff --git a/block/bio-integrity.c b/block/bio-integrity.c
index 63f72f0..80dedde 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -175,6 +175,9 @@
 	if (!bio_is_rw(bio))
 		return false;
 
+	if (!bio_sectors(bio))
+		return false;
+
 	/* Already protected? */
 	if (bio_integrity(bio))
 		return false;
diff --git a/block/bio.c b/block/bio.c
index 07f287b..4f93345 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -42,9 +42,9 @@
  * break badly! cannot be bigger than what you can fit into an
  * unsigned short
  */
-#define BV(x) { .nr_vecs = x, .name = "biovec-"__stringify(x) }
+#define BV(x, n) { .nr_vecs = x, .name = "biovec-"#n }
 static struct biovec_slab bvec_slabs[BVEC_POOL_NR] __read_mostly = {
-	BV(1), BV(4), BV(16), BV(64), BV(128), BV(BIO_MAX_PAGES),
+	BV(1, 1), BV(4, 4), BV(16, 16), BV(64, 64), BV(128, 128), BV(BIO_MAX_PAGES, max),
 };
 #undef BV
 
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 8c74712..0668b66 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -1265,13 +1265,13 @@
 
 	blk_queue_bounce(q, &bio);
 
+	blk_queue_split(q, &bio, q->bio_split);
+
 	if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
 		bio_io_error(bio);
 		return BLK_QC_T_NONE;
 	}
 
-	blk_queue_split(q, &bio, q->bio_split);
-
 	if (!is_flush_fua && !blk_queue_nomerges(q) &&
 	    blk_attempt_plug_merge(q, bio, &request_count, &same_queue_rq))
 		return BLK_QC_T_NONE;
@@ -1592,7 +1592,8 @@
 {
 	unsigned flush_start_tag = set->queue_depth;
 
-	blk_mq_tag_idle(hctx);
+	if (blk_mq_hw_queue_mapped(hctx))
+		blk_mq_tag_idle(hctx);
 
 	if (set->ops->exit_request)
 		set->ops->exit_request(set->driver_data,
@@ -1907,6 +1908,9 @@
 	struct blk_mq_hw_ctx **hctxs = q->queue_hw_ctx;
 
 	blk_mq_sysfs_unregister(q);
+
+	/* protect against switching io scheduler  */
+	mutex_lock(&q->sysfs_lock);
 	for (i = 0; i < set->nr_hw_queues; i++) {
 		int node;
 
@@ -1956,6 +1960,7 @@
 		}
 	}
 	q->nr_hw_queues = i;
+	mutex_unlock(&q->sysfs_lock);
 	blk_mq_sysfs_register(q);
 }
 
@@ -2014,15 +2019,15 @@
 
 	blk_mq_init_cpu_queues(q, set->nr_hw_queues);
 
-	mutex_lock(&all_q_mutex);
 	get_online_cpus();
+	mutex_lock(&all_q_mutex);
 
 	list_add_tail(&q->all_q_node, &all_q_list);
 	blk_mq_add_queue_tag_set(set, q);
 	blk_mq_map_swqueue(q, cpu_online_mask);
 
-	put_online_cpus();
 	mutex_unlock(&all_q_mutex);
+	put_online_cpus();
 
 	return q;
 
diff --git a/block/partition-generic.c b/block/partition-generic.c
index a2437c0..298c05f 100644
--- a/block/partition-generic.c
+++ b/block/partition-generic.c
@@ -321,8 +321,10 @@
 
 	if (info) {
 		struct partition_meta_info *pinfo = alloc_part_info(disk);
-		if (!pinfo)
+		if (!pinfo) {
+			err = -ENOMEM;
 			goto out_free_stats;
+		}
 		memcpy(pinfo, info, sizeof(*info));
 		p->info = pinfo;
 	}
diff --git a/block/partitions/msdos.c b/block/partitions/msdos.c
index 5610cd5..7d8d50c 100644
--- a/block/partitions/msdos.c
+++ b/block/partitions/msdos.c
@@ -300,7 +300,9 @@
 			continue;
 		bsd_start = le32_to_cpu(p->p_offset);
 		bsd_size = le32_to_cpu(p->p_size);
-		if (memcmp(flavour, "bsd\0", 4) == 0)
+		/* FreeBSD has relative offset if C partition offset is zero */
+		if (memcmp(flavour, "bsd\0", 4) == 0 &&
+		    le32_to_cpu(l->d_partitions[2].p_offset) == 0)
 			bsd_start += offset;
 		if (offset == bsd_start && size == bsd_size)
 			/* full parent partition, we have it already */
diff --git a/build.config.cuttlefish.x86_64 b/build.config.cuttlefish.x86_64
new file mode 100644
index 0000000..5a96563
--- /dev/null
+++ b/build.config.cuttlefish.x86_64
@@ -0,0 +1,15 @@
+ARCH=x86_64
+BRANCH=android-4.9
+CLANG_TRIPLE=x86_64-linux-gnu-
+CROSS_COMPILE=x86_64-linux-androidkernel-
+DEFCONFIG=x86_64_cuttlefish_defconfig
+EXTRA_CMDS=''
+KERNEL_DIR=common
+POST_DEFCONFIG_CMDS="check_defconfig"
+CLANG_PREBUILT_BIN=prebuilts/clang/host/linux-x86/clang-4630689/bin
+LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin
+FILES="
+arch/x86/boot/bzImage
+vmlinux
+System.map
+"
diff --git a/crypto/ahash.c b/crypto/ahash.c
index 14402ef..90d73a2 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -91,13 +91,14 @@
 
 	if (nbytes && walk->offset & alignmask && !err) {
 		walk->offset = ALIGN(walk->offset, alignmask + 1);
-		walk->data += walk->offset;
-
 		nbytes = min(nbytes,
 			     ((unsigned int)(PAGE_SIZE)) - walk->offset);
 		walk->entrylen -= nbytes;
 
-		return nbytes;
+		if (nbytes) {
+			walk->data += walk->offset;
+			return nbytes;
+		}
 	}
 
 	if (walk->flags & CRYPTO_ALG_ASYNC)
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index 029f705..ce2df8c 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -102,6 +102,7 @@
 		}
 	}
 
+	ret = -ENOMEM;
 	cert->pub->key = kmemdup(ctx->key, ctx->key_size, GFP_KERNEL);
 	if (!cert->pub->key)
 		goto error_decode;
diff --git a/crypto/async_tx/async_pq.c b/crypto/async_tx/async_pq.c
index f83de99..56bd612 100644
--- a/crypto/async_tx/async_pq.c
+++ b/crypto/async_tx/async_pq.c
@@ -62,9 +62,6 @@
 	dma_addr_t dma_dest[2];
 	int src_off = 0;
 
-	if (submit->flags & ASYNC_TX_FENCE)
-		dma_flags |= DMA_PREP_FENCE;
-
 	while (src_cnt > 0) {
 		submit->flags = flags_orig;
 		pq_src_cnt = min(src_cnt, dma_maxpq(dma, dma_flags));
@@ -83,6 +80,8 @@
 			if (cb_fn_orig)
 				dma_flags |= DMA_PREP_INTERRUPT;
 		}
+		if (submit->flags & ASYNC_TX_FENCE)
+			dma_flags |= DMA_PREP_FENCE;
 
 		/* Drivers force forward progress in case they can not provide
 		 * a descriptor
diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c
index c5557d0..94e04c9 100644
--- a/drivers/acpi/acpi_video.c
+++ b/drivers/acpi/acpi_video.c
@@ -87,8 +87,8 @@
 static bool device_id_scheme = false;
 module_param(device_id_scheme, bool, 0444);
 
-static bool only_lcd = false;
-module_param(only_lcd, bool, 0444);
+static int only_lcd = -1;
+module_param(only_lcd, int, 0444);
 
 static int register_count;
 static DEFINE_MUTEX(register_count_mutex);
@@ -2082,6 +2082,16 @@
 		goto leave;
 	}
 
+	/*
+	 * We're seeing a lot of bogus backlight interfaces on newer machines
+	 * without a LCD such as desktops, servers and HDMI sticks. Checking
+	 * the lcd flag fixes this, so enable this on any machines which are
+	 * win8 ready (where we also prefer the native backlight driver, so
+	 * normally the acpi_video code should not register there anyways).
+	 */
+	if (only_lcd == -1)
+		only_lcd = acpi_osi_is_win8();
+
 	dmi_check_system(video_dmi_table);
 
 	ret = acpi_bus_register_driver(&acpi_video_bus);
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c
index 9179e9a..35a2d9e 100644
--- a/drivers/acpi/acpica/evxfevnt.c
+++ b/drivers/acpi/acpica/evxfevnt.c
@@ -180,6 +180,12 @@
 
 	ACPI_FUNCTION_TRACE(acpi_enable_event);
 
+	/* If Hardware Reduced flag is set, there are no fixed events */
+
+	if (acpi_gbl_reduced_hardware) {
+		return_ACPI_STATUS(AE_OK);
+	}
+
 	/* Decode the Fixed Event */
 
 	if (event > ACPI_EVENT_MAX) {
@@ -237,6 +243,12 @@
 
 	ACPI_FUNCTION_TRACE(acpi_disable_event);
 
+	/* If Hardware Reduced flag is set, there are no fixed events */
+
+	if (acpi_gbl_reduced_hardware) {
+		return_ACPI_STATUS(AE_OK);
+	}
+
 	/* Decode the Fixed Event */
 
 	if (event > ACPI_EVENT_MAX) {
@@ -290,6 +302,12 @@
 
 	ACPI_FUNCTION_TRACE(acpi_clear_event);
 
+	/* If Hardware Reduced flag is set, there are no fixed events */
+
+	if (acpi_gbl_reduced_hardware) {
+		return_ACPI_STATUS(AE_OK);
+	}
+
 	/* Decode the Fixed Event */
 
 	if (event > ACPI_EVENT_MAX) {
diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c
index db0e903..ac2e8df 100644
--- a/drivers/acpi/acpica/psobject.c
+++ b/drivers/acpi/acpica/psobject.c
@@ -121,6 +121,9 @@
 			     (u32)(aml_offset +
 				   sizeof(struct acpi_table_header)));
 
+			ACPI_ERROR((AE_INFO,
+				    "Aborting disassembly, AML byte code is corrupt"));
+
 			/* Dump the context surrounding the invalid opcode */
 
 			acpi_ut_dump_buffer(((u8 *)walk_state->parser_state.
@@ -129,6 +132,14 @@
 					     sizeof(struct acpi_table_header) -
 					     16));
 			acpi_os_printf(" */\n");
+
+			/*
+			 * Just abort the disassembly, cannot continue because the
+			 * parser is essentially lost. The disassembler can then
+			 * randomly fail because an ill-constructed parse tree
+			 * can result.
+			 */
+			return_ACPI_STATUS(AE_AML_BAD_OPCODE);
 #endif
 		}
 
@@ -293,6 +304,9 @@
 	if (status == AE_CTRL_PARSE_CONTINUE) {
 		return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
 	}
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
 
 	/* Create Op structure and append to parent's argument list */
 
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index b4a2c31..7b665aa 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1518,7 +1518,7 @@
 	}
 
 	acpi_handle_info(ec->handle,
-			 "GPE=0x%lx, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n",
+			 "GPE=0x%x, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n",
 			 ec->gpe, ec->command_addr, ec->data_addr);
 	return ret;
 }
diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c
index 6c7dd7a..dd70d6c 100644
--- a/drivers/acpi/ec_sys.c
+++ b/drivers/acpi/ec_sys.c
@@ -128,7 +128,7 @@
 		return -ENOMEM;
 	}
 
-	if (!debugfs_create_x32("gpe", 0444, dev_dir, (u32 *)&first_ec->gpe))
+	if (!debugfs_create_x32("gpe", 0444, dev_dir, &first_ec->gpe))
 		goto error;
 	if (!debugfs_create_bool("use_global_lock", 0444, dev_dir,
 				 &first_ec->global_lock))
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 08b3ca0..b012e94 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -158,7 +158,7 @@
    -------------------------------------------------------------------------- */
 struct acpi_ec {
 	acpi_handle handle;
-	unsigned long gpe;
+	u32 gpe;
 	unsigned long command_addr;
 	unsigned long data_addr;
 	bool global_lock;
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index b1815b2..3874eec 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -967,8 +967,11 @@
 	if (nd_desc) {
 		struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
 
+		mutex_lock(&acpi_desc->init_mutex);
 		rc = sprintf(buf, "%d%s", acpi_desc->scrub_count,
-				(work_busy(&acpi_desc->work)) ? "+\n" : "\n");
+				work_busy(&acpi_desc->work)
+				&& !acpi_desc->cancel ? "+\n" : "\n");
+		mutex_unlock(&acpi_desc->init_mutex);
 	}
 	device_unlock(dev);
 	return rc;
@@ -2547,15 +2550,21 @@
 static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc)
 {
 	struct nfit_spa *nfit_spa;
-	int rc;
 
-	list_for_each_entry(nfit_spa, &acpi_desc->spas, list)
-		if (nfit_spa_type(nfit_spa->spa) == NFIT_SPA_DCR) {
-			/* BLK regions don't need to wait for ars results */
-			rc = acpi_nfit_register_region(acpi_desc, nfit_spa);
-			if (rc)
-				return rc;
-		}
+	list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+		int rc, type = nfit_spa_type(nfit_spa->spa);
+
+		/* PMEM and VMEM will be registered by the ARS workqueue */
+		if (type == NFIT_SPA_PM || type == NFIT_SPA_VOLATILE)
+			continue;
+		/* BLK apertures belong to BLK region registration below */
+		if (type == NFIT_SPA_BDW)
+			continue;
+		/* BLK regions don't need to wait for ARS results */
+		rc = acpi_nfit_register_region(acpi_desc, nfit_spa);
+		if (rc)
+			return rc;
+	}
 
 	queue_work(nfit_wq, &acpi_desc->work);
 	return 0;
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index 02ded25..cdc4737 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -214,6 +214,15 @@
 		},
 	},
 	{
+	 /* https://bugzilla.redhat.com/show_bug.cgi?id=1557060 */
+	 .callback = video_detect_force_video,
+	 .ident = "SAMSUNG 670Z5E",
+	 .matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+		DMI_MATCH(DMI_PRODUCT_NAME, "670Z5E"),
+		},
+	},
+	{
 	 /* https://bugzilla.redhat.com/show_bug.cgi?id=1094948 */
 	 .callback = video_detect_force_video,
 	 .ident = "SAMSUNG 730U3E/740U3E",
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index aaa761b..cd2eab6 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -514,8 +514,9 @@
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq <= 0) {
-		dev_err(dev, "no irq\n");
-		return -EINVAL;
+		if (irq != -EPROBE_DEFER)
+			dev_err(dev, "no irq\n");
+		return irq;
 	}
 
 	hpriv->irq = irq;
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 3331ed8..f74f3ca 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -1736,7 +1736,7 @@
 		return -EINVAL;
 	if (val_len % map->format.val_bytes)
 		return -EINVAL;
-	if (map->max_raw_write && map->max_raw_write > val_len)
+	if (map->max_raw_write && map->max_raw_write < val_len)
 		return -E2BIG;
 
 	map->lock(map->lock_arg);
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 68bfcef..ff1c4d7 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -612,6 +612,9 @@
  */
 static int loop_flush(struct loop_device *lo)
 {
+	/* loop not yet configured, no running thread, nothing to flush */
+	if (lo->lo_state != Lo_bound)
+		return 0;
 	return loop_switch(lo, NULL);
 }
 
@@ -1107,11 +1110,15 @@
 	if (info->lo_encrypt_type) {
 		unsigned int type = info->lo_encrypt_type;
 
-		if (type >= MAX_LO_CRYPT)
-			return -EINVAL;
+		if (type >= MAX_LO_CRYPT) {
+			err = -EINVAL;
+			goto exit;
+		}
 		xfer = xfer_funcs[type];
-		if (xfer == NULL)
-			return -EINVAL;
+		if (xfer == NULL) {
+			err = -EINVAL;
+			goto exit;
+		}
 	} else
 		xfer = NULL;
 
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index b86273f..3cfd879 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -169,25 +169,6 @@
 	return false; /* device present */
 }
 
-/* we have to use runtime tag to setup command header */
-static void mtip_init_cmd_header(struct request *rq)
-{
-	struct driver_data *dd = rq->q->queuedata;
-	struct mtip_cmd *cmd = blk_mq_rq_to_pdu(rq);
-	u32 host_cap_64 = readl(dd->mmio + HOST_CAP) & HOST_CAP_64;
-
-	/* Point the command headers at the command tables. */
-	cmd->command_header = dd->port->command_list +
-				(sizeof(struct mtip_cmd_hdr) * rq->tag);
-	cmd->command_header_dma = dd->port->command_list_dma +
-				(sizeof(struct mtip_cmd_hdr) * rq->tag);
-
-	if (host_cap_64)
-		cmd->command_header->ctbau = __force_bit2int cpu_to_le32((cmd->command_dma >> 16) >> 16);
-
-	cmd->command_header->ctba = __force_bit2int cpu_to_le32(cmd->command_dma & 0xFFFFFFFF);
-}
-
 static struct mtip_cmd *mtip_get_int_command(struct driver_data *dd)
 {
 	struct request *rq;
@@ -199,9 +180,6 @@
 	if (IS_ERR(rq))
 		return NULL;
 
-	/* Internal cmd isn't submitted via .queue_rq */
-	mtip_init_cmd_header(rq);
-
 	return blk_mq_rq_to_pdu(rq);
 }
 
@@ -3833,8 +3811,6 @@
 	struct request *rq = bd->rq;
 	int ret;
 
-	mtip_init_cmd_header(rq);
-
 	if (unlikely(mtip_check_unal_depth(hctx, rq)))
 		return BLK_MQ_RQ_QUEUE_BUSY;
 
@@ -3866,6 +3842,7 @@
 {
 	struct driver_data *dd = data;
 	struct mtip_cmd *cmd = blk_mq_rq_to_pdu(rq);
+	u32 host_cap_64 = readl(dd->mmio + HOST_CAP) & HOST_CAP_64;
 
 	/*
 	 * For flush requests, request_idx starts at the end of the
@@ -3882,6 +3859,17 @@
 
 	memset(cmd->command, 0, CMD_DMA_ALLOC_SZ);
 
+	/* Point the command headers at the command tables. */
+	cmd->command_header = dd->port->command_list +
+				(sizeof(struct mtip_cmd_hdr) * request_idx);
+	cmd->command_header_dma = dd->port->command_list_dma +
+				(sizeof(struct mtip_cmd_hdr) * request_idx);
+
+	if (host_cap_64)
+		cmd->command_header->ctbau = __force_bit2int cpu_to_le32((cmd->command_dma >> 16) >> 16);
+
+	cmd->command_header->ctba = __force_bit2int cpu_to_le32(cmd->command_dma & 0xFFFFFFFF);
+
 	sg_init_table(cmd->sg, MTIP_MAX_SG);
 	return 0;
 }
diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c
index f927756..7f7c942 100644
--- a/drivers/bluetooth/bluetooth-power.c
+++ b/drivers/bluetooth/bluetooth-power.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2010, 2013-2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-2010, 2013-2018 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
@@ -43,6 +43,7 @@
 static const struct of_device_id bt_power_match_table[] = {
 	{	.compatible = "qca,ar3002" },
 	{	.compatible = "qca,qca6174" },
+	{	.compatible = "qca,qca9379" },
 	{	.compatible = "qca,wcn3990" },
 	{}
 };
diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index 72fe0a5..017c37b 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Broadcom Corporation
+ * Copyright (C) 2014-2017 Broadcom
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -37,8 +37,6 @@
 #define  ARB_ERR_CAP_CLEAR		(1 << 0)
 #define  ARB_ERR_CAP_STATUS_TIMEOUT	(1 << 12)
 #define  ARB_ERR_CAP_STATUS_TEA		(1 << 11)
-#define  ARB_ERR_CAP_STATUS_BS_SHIFT	(1 << 2)
-#define  ARB_ERR_CAP_STATUS_BS_MASK	0x3c
 #define  ARB_ERR_CAP_STATUS_WRITE	(1 << 1)
 #define  ARB_ERR_CAP_STATUS_VALID	(1 << 0)
 
@@ -47,7 +45,6 @@
 	ARB_ERR_CAP_CLR,
 	ARB_ERR_CAP_HI_ADDR,
 	ARB_ERR_CAP_ADDR,
-	ARB_ERR_CAP_DATA,
 	ARB_ERR_CAP_STATUS,
 	ARB_ERR_CAP_MASTER,
 };
@@ -57,7 +54,6 @@
 	[ARB_ERR_CAP_CLR]	= 0x0c4,
 	[ARB_ERR_CAP_HI_ADDR]	= -1,
 	[ARB_ERR_CAP_ADDR]	= 0x0c8,
-	[ARB_ERR_CAP_DATA]	= 0x0cc,
 	[ARB_ERR_CAP_STATUS]	= 0x0d0,
 	[ARB_ERR_CAP_MASTER]	= -1,
 };
@@ -67,7 +63,6 @@
 	[ARB_ERR_CAP_CLR]	= 0x0c8,
 	[ARB_ERR_CAP_HI_ADDR]	= -1,
 	[ARB_ERR_CAP_ADDR]	= 0x0cc,
-	[ARB_ERR_CAP_DATA]	= 0x0d0,
 	[ARB_ERR_CAP_STATUS]	= 0x0d4,
 	[ARB_ERR_CAP_MASTER]	= 0x0d8,
 };
@@ -77,7 +72,6 @@
 	[ARB_ERR_CAP_CLR]	= 0x168,
 	[ARB_ERR_CAP_HI_ADDR]	= -1,
 	[ARB_ERR_CAP_ADDR]	= 0x16c,
-	[ARB_ERR_CAP_DATA]	= 0x170,
 	[ARB_ERR_CAP_STATUS]	= 0x174,
 	[ARB_ERR_CAP_MASTER]	= 0x178,
 };
@@ -87,7 +81,6 @@
 	[ARB_ERR_CAP_CLR]	= 0x7e4,
 	[ARB_ERR_CAP_HI_ADDR]	= 0x7e8,
 	[ARB_ERR_CAP_ADDR]	= 0x7ec,
-	[ARB_ERR_CAP_DATA]	= 0x7f0,
 	[ARB_ERR_CAP_STATUS]	= 0x7f4,
 	[ARB_ERR_CAP_MASTER]	= 0x7f8,
 };
@@ -109,9 +102,13 @@
 {
 	int offset = gdev->gisb_offsets[reg];
 
-	/* return 1 if the hardware doesn't have ARB_ERR_CAP_MASTER */
-	if (offset == -1)
-		return 1;
+	if (offset < 0) {
+		/* return 1 if the hardware doesn't have ARB_ERR_CAP_MASTER */
+		if (reg == ARB_ERR_CAP_MASTER)
+			return 1;
+		else
+			return 0;
+	}
 
 	if (gdev->big_endian)
 		return ioread32be(gdev->base + offset);
@@ -119,6 +116,16 @@
 		return ioread32(gdev->base + offset);
 }
 
+static u64 gisb_read_address(struct brcmstb_gisb_arb_device *gdev)
+{
+	u64 value;
+
+	value = gisb_read(gdev, ARB_ERR_CAP_ADDR);
+	value |= (u64)gisb_read(gdev, ARB_ERR_CAP_HI_ADDR) << 32;
+
+	return value;
+}
+
 static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg)
 {
 	int offset = gdev->gisb_offsets[reg];
@@ -127,9 +134,9 @@
 		return;
 
 	if (gdev->big_endian)
-		iowrite32be(val, gdev->base + reg);
+		iowrite32be(val, gdev->base + offset);
 	else
-		iowrite32(val, gdev->base + reg);
+		iowrite32(val, gdev->base + offset);
 }
 
 static ssize_t gisb_arb_get_timeout(struct device *dev,
@@ -185,7 +192,7 @@
 					const char *reason)
 {
 	u32 cap_status;
-	unsigned long arb_addr;
+	u64 arb_addr;
 	u32 master;
 	const char *m_name;
 	char m_fmt[11];
@@ -197,10 +204,7 @@
 		return 1;
 
 	/* Read the address and master */
-	arb_addr = gisb_read(gdev, ARB_ERR_CAP_ADDR) & 0xffffffff;
-#if (IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT))
-	arb_addr |= (u64)gisb_read(gdev, ARB_ERR_CAP_HI_ADDR) << 32;
-#endif
+	arb_addr = gisb_read_address(gdev);
 	master = gisb_read(gdev, ARB_ERR_CAP_MASTER);
 
 	m_name = brcmstb_gisb_master_to_str(gdev, master);
@@ -209,7 +213,7 @@
 		m_name = m_fmt;
 	}
 
-	pr_crit("%s: %s at 0x%lx [%c %s], core: %s\n",
+	pr_crit("%s: %s at 0x%llx [%c %s], core: %s\n",
 		__func__, reason, arb_addr,
 		cap_status & ARB_ERR_CAP_STATUS_WRITE ? 'W' : 'R',
 		cap_status & ARB_ERR_CAP_STATUS_TIMEOUT ? "timeout" : "",
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index b7d56a9..c20dd2e 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -2189,9 +2189,12 @@
 		if (driver->time_sync_enabled)
 			diag_send_time_sync_update(peripheral);
 		mutex_lock(&driver->md_session_lock);
-		diag_send_msg_mask_update(peripheral, ALL_SSID, ALL_SSID);
-		diag_send_log_mask_update(peripheral, ALL_EQUIP_ID);
-		diag_send_event_mask_update(peripheral);
+		if (driver->set_mask_cmd) {
+			diag_send_msg_mask_update(peripheral,
+				ALL_SSID, ALL_SSID);
+			diag_send_log_mask_update(peripheral, ALL_EQUIP_ID);
+			diag_send_event_mask_update(peripheral);
+		}
 		mutex_unlock(&driver->md_session_lock);
 		diag_send_real_time_update(peripheral,
 				driver->real_time_mode[DIAG_LOCAL_PROC]);
@@ -2228,6 +2231,7 @@
 			break;
 		case DIAG_CMD_OP_SET_LOG_MASK:
 			hdlr = diag_cmd_set_log_mask;
+			driver->set_mask_cmd = 1;
 			break;
 		case DIAG_CMD_OP_GET_LOG_MASK:
 			hdlr = diag_cmd_get_log_mask;
@@ -2247,17 +2251,21 @@
 			break;
 		case DIAG_CMD_OP_SET_MSG_MASK:
 			hdlr = diag_cmd_set_msg_mask;
+			driver->set_mask_cmd = 1;
 			break;
 		case DIAG_CMD_OP_SET_ALL_MSG_MASK:
 			hdlr = diag_cmd_set_all_msg_mask;
+			driver->set_mask_cmd = 1;
 			break;
 		}
 	} else if (*buf == DIAG_CMD_GET_EVENT_MASK) {
 		hdlr = diag_cmd_get_event_mask;
 	} else if (*buf == DIAG_CMD_SET_EVENT_MASK) {
 		hdlr = diag_cmd_update_event_mask;
+		driver->set_mask_cmd = 1;
 	} else if (*buf == DIAG_CMD_EVENT_TOGGLE) {
 		hdlr = diag_cmd_toggle_events;
+		driver->set_mask_cmd = 1;
 	}
 
 	if (hdlr)
diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c
index ce0c7bb..55b1b49 100644
--- a/drivers/char/diag/diag_memorydevice.c
+++ b/drivers/char/diag/diag_memorydevice.c
@@ -384,7 +384,7 @@
 	int i, j;
 	struct diag_md_info *ch = NULL;
 
-	for (i = 0; i < NUM_DIAG_MD_DEV; i++) {
+	for (i = 0; i < DIAG_MD_LOCAL_LAST; i++) {
 		ch = &diag_md[i];
 		ch->num_tbl_entries = diag_mempools[ch->mempool].poolsize;
 		ch->tbl = kzalloc(ch->num_tbl_entries *
@@ -408,12 +408,53 @@
 	return -ENOMEM;
 }
 
+int diag_md_mdm_init(void)
+{
+	int i, j;
+	struct diag_md_info *ch = NULL;
+
+	for (i = DIAG_MD_BRIDGE_BASE; i < NUM_DIAG_MD_DEV; i++) {
+		ch = &diag_md[i];
+		ch->num_tbl_entries = diag_mempools[ch->mempool].poolsize;
+		ch->tbl = kcalloc(ch->num_tbl_entries, sizeof(*ch->tbl),
+				GFP_KERNEL);
+		if (!ch->tbl)
+			goto fail;
+
+		for (j = 0; j < ch->num_tbl_entries; j++) {
+			ch->tbl[j].buf = NULL;
+			ch->tbl[j].len = 0;
+			ch->tbl[j].ctx = 0;
+		}
+		spin_lock_init(&(ch->lock));
+	}
+
+	return 0;
+
+fail:
+	diag_md_mdm_exit();
+	return -ENOMEM;
+}
+
 void diag_md_exit(void)
 {
 	int i;
 	struct diag_md_info *ch = NULL;
 
-	for (i = 0; i < NUM_DIAG_MD_DEV; i++) {
+	for (i = 0; i < DIAG_MD_LOCAL_LAST; i++) {
+		ch = &diag_md[i];
+		kfree(ch->tbl);
+		ch->num_tbl_entries = 0;
+		ch->ops = NULL;
+	}
+}
+
+void diag_md_mdm_exit(void)
+{
+	int i;
+	struct diag_md_info *ch = NULL;
+
+	for (i = DIAG_MD_BRIDGE_BASE; i < NUM_DIAG_MD_DEV; i++) {
 		ch = &diag_md[i];
 		kfree(ch->tbl);
 		ch->num_tbl_entries = 0;
diff --git a/drivers/char/diag/diag_memorydevice.h b/drivers/char/diag/diag_memorydevice.h
index 35a1ee3..9b4aa39 100644
--- a/drivers/char/diag/diag_memorydevice.h
+++ b/drivers/char/diag/diag_memorydevice.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 2018 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
@@ -46,7 +46,9 @@
 extern struct diag_md_info diag_md[NUM_DIAG_MD_DEV];
 
 int diag_md_init(void);
+int diag_md_mdm_init(void);
 void diag_md_exit(void);
+void diag_md_mdm_exit(void);
 void diag_md_open_all(void);
 void diag_md_close_all(void);
 int diag_md_register(int id, int ctx, struct diag_mux_ops *ops);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index fc18776..9bbfb82 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -673,6 +673,7 @@
 	struct diag_mask_info *log_mask;
 	struct diag_mask_info *event_mask;
 	struct diag_mask_info *build_time_mask;
+	uint8_t set_mask_cmd;
 	uint8_t msg_mask_tbl_count;
 	uint8_t bt_msg_mask_tbl_count;
 	uint16_t event_mask_size;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 0d3389a..54a4d98 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -969,6 +969,7 @@
 			poolsize_mdm_dci_write);
 	diagmem_setsize(POOL_TYPE_QSC_MUX, itemsize_qsc_usb,
 			poolsize_qsc_usb);
+	diag_md_mdm_init();
 	driver->hdlc_encode_buf = kzalloc(DIAG_MAX_HDLC_BUF_SIZE, GFP_KERNEL);
 	if (!driver->hdlc_encode_buf)
 		return -ENOMEM;
diff --git a/drivers/char/diag/diagfwd_mhi.c b/drivers/char/diag/diagfwd_mhi.c
index f8c3fde..6f41868 100644
--- a/drivers/char/diag/diagfwd_mhi.c
+++ b/drivers/char/diag/diagfwd_mhi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, 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
@@ -434,9 +434,10 @@
 	do {
 		if (!(atomic_read(&(read_ch->opened))))
 			break;
-
+		spin_lock_irqsave(&read_ch->lock, flags);
 		buf = diagmem_alloc(driver, DIAG_MDM_BUF_SIZE,
 				    mhi_info->mempool);
+		spin_unlock_irqrestore(&read_ch->lock, flags);
 		if (!buf)
 			break;
 
@@ -743,4 +744,3 @@
 			diagmem_exit(driver, mhi_info->mempool);
 	}
 }
-
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index 510fc10..f11c1c7 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -409,6 +409,7 @@
 	msg = ipmi_alloc_smi_msg();
 	if (!msg) {
 		ssif_info->ssif_state = SSIF_NORMAL;
+		ipmi_ssif_unlock_cond(ssif_info, flags);
 		return;
 	}
 
@@ -431,6 +432,7 @@
 	msg = ipmi_alloc_smi_msg();
 	if (!msg) {
 		ssif_info->ssif_state = SSIF_NORMAL;
+		ipmi_ssif_unlock_cond(ssif_info, flags);
 		return;
 	}
 
diff --git a/drivers/char/random.c b/drivers/char/random.c
index ee737ef..8a167a6 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -434,8 +434,9 @@
  * its value (from 0->1->2).
  */
 static int crng_init = 0;
-#define crng_ready() (likely(crng_init > 0))
+#define crng_ready() (likely(crng_init > 1))
 static int crng_init_cnt = 0;
+static unsigned long crng_global_init_time = 0;
 #define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE)
 static void _extract_crng(struct crng_state *crng,
 			  __u8 out[CHACHA20_BLOCK_SIZE]);
@@ -741,7 +742,7 @@
 
 static int credit_entropy_bits_safe(struct entropy_store *r, int nbits)
 {
-	const int nbits_max = (int)(~0U >> (ENTROPY_SHIFT + 1));
+	const int nbits_max = r->poolinfo->poolwords * 32;
 
 	if (nbits < 0)
 		return -EINVAL;
@@ -800,7 +801,7 @@
 
 	if (!spin_trylock_irqsave(&primary_crng.lock, flags))
 		return 0;
-	if (crng_ready()) {
+	if (crng_init != 0) {
 		spin_unlock_irqrestore(&primary_crng.lock, flags);
 		return 0;
 	}
@@ -836,7 +837,7 @@
 		_crng_backtrack_protect(&primary_crng, buf.block,
 					CHACHA20_KEY_SIZE);
 	}
-	spin_lock_irqsave(&primary_crng.lock, flags);
+	spin_lock_irqsave(&crng->lock, flags);
 	for (i = 0; i < 8; i++) {
 		unsigned long	rv;
 		if (!arch_get_random_seed_long(&rv) &&
@@ -852,7 +853,7 @@
 		wake_up_interruptible(&crng_init_wait);
 		pr_notice("random: crng init done\n");
 	}
-	spin_unlock_irqrestore(&primary_crng.lock, flags);
+	spin_unlock_irqrestore(&crng->lock, flags);
 }
 
 static inline void maybe_reseed_primary_crng(void)
@@ -872,8 +873,9 @@
 {
 	unsigned long v, flags;
 
-	if (crng_init > 1 &&
-	    time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL))
+	if (crng_ready() &&
+	    (time_after(crng_global_init_time, crng->init_time) ||
+	     time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL)))
 		crng_reseed(crng, crng == &primary_crng ? &input_pool : NULL);
 	spin_lock_irqsave(&crng->lock, flags);
 	if (arch_get_random_long(&v))
@@ -1115,12 +1117,16 @@
 static __u32 get_reg(struct fast_pool *f, struct pt_regs *regs)
 {
 	__u32 *ptr = (__u32 *) regs;
+	unsigned int idx;
 
 	if (regs == NULL)
 		return 0;
-	if (f->reg_idx >= sizeof(struct pt_regs) / sizeof(__u32))
-		f->reg_idx = 0;
-	return *(ptr + f->reg_idx++);
+	idx = READ_ONCE(f->reg_idx);
+	if (idx >= sizeof(struct pt_regs) / sizeof(__u32))
+		idx = 0;
+	ptr += idx++;
+	WRITE_ONCE(f->reg_idx, idx);
+	return *ptr;
 }
 
 void add_interrupt_randomness(int irq, int irq_flags)
@@ -1149,7 +1155,7 @@
 	fast_mix(fast_pool);
 	add_interrupt_bench(cycles);
 
-	if (!crng_ready()) {
+	if (unlikely(crng_init == 0)) {
 		if ((fast_pool->count >= 64) &&
 		    crng_fast_load((char *) fast_pool->pool,
 				   sizeof(fast_pool->pool))) {
@@ -1664,6 +1670,7 @@
 	init_std_data(&input_pool);
 	init_std_data(&blocking_pool);
 	crng_initialize(&primary_crng);
+	crng_global_init_time = jiffies;
 
 #ifdef CONFIG_NUMA
 	pool = kcalloc(nr_node_ids, sizeof(*pool), GFP_KERNEL|__GFP_NOFAIL);
@@ -1850,6 +1857,14 @@
 		input_pool.entropy_count = 0;
 		blocking_pool.entropy_count = 0;
 		return 0;
+	case RNDRESEEDCRNG:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (crng_init < 2)
+			return -ENODATA;
+		crng_reseed(&primary_crng, NULL);
+		crng_global_init_time = jiffies - 1;
+		return 0;
 	default:
 		return -EINVAL;
 	}
@@ -2143,7 +2158,7 @@
 {
 	struct entropy_store *poolp = &input_pool;
 
-	if (!crng_ready()) {
+	if (unlikely(crng_init == 0)) {
 		crng_fast_load(buffer, count);
 		return;
 	}
diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c
index 4e1cd5a..07c8f70 100644
--- a/drivers/clk/at91/clk-generated.c
+++ b/drivers/clk/at91/clk-generated.c
@@ -260,13 +260,13 @@
 	gck->lock = lock;
 	gck->range = *range;
 
+	clk_generated_startup(gck);
 	hw = &gck->hw;
 	ret = clk_hw_register(NULL, &gck->hw);
 	if (ret) {
 		kfree(gck);
 		hw = ERR_PTR(ret);
-	} else
-		clk_generated_startup(gck);
+	}
 
 	return hw;
 }
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index abdc149..73aab6e 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -545,9 +545,7 @@
 	const struct bcm2835_pll_data *data = pll->data;
 
 	spin_lock(&cprman->regs_lock);
-	cprman_write(cprman, data->cm_ctrl_reg,
-		     cprman_read(cprman, data->cm_ctrl_reg) |
-		     CM_PLL_ANARST);
+	cprman_write(cprman, data->cm_ctrl_reg, CM_PLL_ANARST);
 	cprman_write(cprman, data->a2w_ctrl_reg,
 		     cprman_read(cprman, data->a2w_ctrl_reg) |
 		     A2W_PLL_CTRL_PWRDN);
@@ -583,6 +581,10 @@
 		cpu_relax();
 	}
 
+	cprman_write(cprman, data->a2w_ctrl_reg,
+		     cprman_read(cprman, data->a2w_ctrl_reg) |
+		     A2W_PLL_CTRL_PRST_DISABLE);
+
 	return 0;
 }
 
diff --git a/drivers/clk/clk-conf.c b/drivers/clk/clk-conf.c
index 674785d..f0290092 100644
--- a/drivers/clk/clk-conf.c
+++ b/drivers/clk/clk-conf.c
@@ -106,7 +106,7 @@
 
 			rc = clk_set_rate(clk, rate);
 			if (rc < 0)
-				pr_err("clk: couldn't set %s clk rate to %d (%d), current rate: %ld\n",
+				pr_err("clk: couldn't set %s clk rate to %u (%d), current rate: %lu\n",
 				       __clk_get_name(clk), rate, rc,
 				       clk_get_rate(clk));
 			clk_put(clk);
diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c
index 96d37175..8ad458b 100644
--- a/drivers/clk/clk-scpi.c
+++ b/drivers/clk/clk-scpi.c
@@ -71,15 +71,15 @@
 };
 
 /* find closest match to given frequency in OPP table */
-static int __scpi_dvfs_round_rate(struct scpi_clk *clk, unsigned long rate)
+static long __scpi_dvfs_round_rate(struct scpi_clk *clk, unsigned long rate)
 {
 	int idx;
-	u32 fmin = 0, fmax = ~0, ftmp;
+	unsigned long fmin = 0, fmax = ~0, ftmp;
 	const struct scpi_opp *opp = clk->info->opps;
 
 	for (idx = 0; idx < clk->info->count; idx++, opp++) {
 		ftmp = opp->freq;
-		if (ftmp >= (u32)rate) {
+		if (ftmp >= rate) {
 			if (ftmp <= fmax)
 				fmax = ftmp;
 			break;
diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index 2f29ee1..5588f75 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -7,9 +7,9 @@
 	bool
 	depends on COMMON_CLK_AMLOGIC
 	help
-	  Support for the clock controller on AmLogic S805 devices, aka
-	  meson8b. Say Y if you want peripherals and CPU frequency scaling to
-	  work.
+	  Support for the clock controller on AmLogic S802 (Meson8),
+	  S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you
+	  want peripherals and CPU frequency scaling to work.
 
 config COMMON_CLK_GXBB
 	bool
diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c
index 3f1be46..70567958 100644
--- a/drivers/clk/meson/meson8b.c
+++ b/drivers/clk/meson/meson8b.c
@@ -1,5 +1,6 @@
 /*
- * AmLogic S805 / Meson8b Clock Controller Driver
+ * AmLogic S802 (Meson8) / S805 (Meson8b) / S812 (Meson8m2) Clock Controller
+ * Driver
  *
  * Copyright (c) 2015 Endless Mobile, Inc.
  * Author: Carlo Caione <carlo@endlessm.com>
@@ -661,7 +662,9 @@
 }
 
 static const struct of_device_id meson8b_clkc_match_table[] = {
+	{ .compatible = "amlogic,meson8-clkc" },
 	{ .compatible = "amlogic,meson8b-clkc" },
+	{ .compatible = "amlogic,meson8m2-clkc" },
 	{ }
 };
 
diff --git a/drivers/clk/msm/clock-gcc-8953.c b/drivers/clk/msm/clock-gcc-8953.c
index 57adebf..0e8665c 100644
--- a/drivers/clk/msm/clock-gcc-8953.c
+++ b/drivers/clk/msm/clock-gcc-8953.c
@@ -411,6 +411,27 @@
 	F_END
 };
 
+static struct clk_freq_tbl ftbl_gfx3d_clk_src_sdm632[] = {
+	F_MM(  19200000, FIXED_CLK_SRC,                  xo,    1,    0,     0),
+	F_MM(  50000000, FIXED_CLK_SRC,  gpll0_main_div2_mm,    8,    0,     0),
+	F_MM(  80000000, FIXED_CLK_SRC,  gpll0_main_div2_mm,    5,    0,     0),
+	F_MM( 100000000, FIXED_CLK_SRC,  gpll0_main_div2_mm,    4,    0,     0),
+	F_MM( 133330000, FIXED_CLK_SRC,  gpll0_main_div2_mm,    3,    0,     0),
+	F_MM( 160000000, FIXED_CLK_SRC,  gpll0_main_div2_mm,  2.5,    0,     0),
+	F_MM( 200000000, FIXED_CLK_SRC,  gpll0_main_div2_mm,    2,    0,     0),
+	F_MM( 216000000, FIXED_CLK_SRC, gpll6_main_div2_gfx,  2.5,    0,     0),
+	F_MM( 266670000, FIXED_CLK_SRC,               gpll0,    3,    0,     0),
+	F_MM( 320000000, FIXED_CLK_SRC,               gpll0,  2.5,    0,     0),
+	F_MM( 400000000, FIXED_CLK_SRC,               gpll0,    2,    0,     0),
+	F_MM( 460800000, FIXED_CLK_SRC,       gpll4_out_aux,  2.5,    0,     0),
+	F_MM( 510000000,    1020000000,               gpll3,    1,    0,     0),
+	F_MM( 560000000,    1120000000,               gpll3,    1,    0,     0),
+	F_MM( 650000000,    1300000000,               gpll3,    1,    0,     0),
+	F_MM( 700000000,    1400000000,               gpll3,    1,    0,     0),
+	F_MM( 725000000,    1450000000,               gpll3,    1,    0,     0),
+
+	F_END
+};
 static struct rcg_clk gfx3d_clk_src = {
 	.cmd_rcgr_reg = GFX3D_CMD_RCGR,
 	.set_rate = set_rate_hid,
@@ -4104,6 +4125,11 @@
 	if (compat_bin)
 		gfx3d_clk_src.freq_tbl = ftbl_gfx3d_clk_src_sdm450;
 
+	compat_bin = of_device_is_compatible(pdev->dev.of_node,
+							"qcom,gcc-gfx-sdm632");
+	if (compat_bin)
+		gfx3d_clk_src.freq_tbl = ftbl_gfx3d_clk_src_sdm632;
+
 	ret = of_get_fmax_vdd_class(pdev, &gcc_oxili_gfx3d_clk.c,
 					"qcom,gfxfreq-corner");
 	if (ret) {
diff --git a/drivers/clk/mvebu/armada-38x.c b/drivers/clk/mvebu/armada-38x.c
index 8bccf4e..9ff4ea6 100644
--- a/drivers/clk/mvebu/armada-38x.c
+++ b/drivers/clk/mvebu/armada-38x.c
@@ -46,10 +46,11 @@
 }
 
 static const u32 armada_38x_cpu_frequencies[] __initconst = {
-	0, 0, 0, 0,
-	1066 * 1000 * 1000, 0, 0, 0,
+	666 * 1000 * 1000,  0, 800 * 1000 * 1000, 0,
+	1066 * 1000 * 1000, 0, 1200 * 1000 * 1000, 0,
 	1332 * 1000 * 1000, 0, 0, 0,
-	1600 * 1000 * 1000,
+	1600 * 1000 * 1000, 0, 0, 0,
+	1866 * 1000 * 1000, 0, 0, 2000 * 1000 * 1000,
 };
 
 static u32 __init armada_38x_get_cpu_freq(void __iomem *sar)
@@ -75,11 +76,11 @@
 };
 
 static const int armada_38x_cpu_l2_ratios[32][2] __initconst = {
-	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+	{1, 2}, {0, 1}, {1, 2}, {0, 1},
+	{1, 2}, {0, 1}, {1, 2}, {0, 1},
 	{1, 2}, {0, 1}, {0, 1}, {0, 1},
 	{1, 2}, {0, 1}, {0, 1}, {0, 1},
-	{1, 2}, {0, 1}, {0, 1}, {0, 1},
-	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+	{1, 2}, {0, 1}, {0, 1}, {1, 2},
 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
@@ -90,7 +91,7 @@
 	{1, 2}, {0, 1}, {0, 1}, {0, 1},
 	{1, 2}, {0, 1}, {0, 1}, {0, 1},
 	{1, 2}, {0, 1}, {0, 1}, {0, 1},
-	{0, 1}, {0, 1}, {0, 1}, {0, 1},
+	{1, 2}, {0, 1}, {0, 1}, {7, 15},
 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index aaf2324..f759978 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013, 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -185,6 +185,7 @@
 extern const struct clk_ops clk_pixel_ops;
 extern const struct clk_ops clk_gfx3d_ops;
 extern const struct clk_ops clk_dp_ops;
+extern const struct clk_ops clk_esc_ops;
 
 extern int clk_rcg2_get_dfs_clock_rate(struct clk_rcg2 *clk,
 				struct device *dev, u8 rcg_flags);
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 35bcf5a..057f0e1 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013, 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -246,12 +246,14 @@
 clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
 {
 	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+	const struct freq_tbl *f_curr;
 	u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask;
 
 	if (rcg->flags & DFS_ENABLE_RCG)
 		return rcg->current_freq;
 
-	if (rcg->enable_safe_config && !clk_hw_is_prepared(hw)) {
+	if (rcg->enable_safe_config && (!clk_hw_is_prepared(hw)
+				|| !clk_hw_is_enabled(hw))) {
 		if (!rcg->current_freq)
 			rcg->current_freq = cxo_f.freq;
 		return rcg->current_freq;
@@ -271,9 +273,17 @@
 		mode >>= CFG_MODE_SHIFT;
 	}
 
-	mask = BIT(rcg->hid_width) - 1;
-	hid_div = cfg >> CFG_SRC_DIV_SHIFT;
-	hid_div &= mask;
+	if (rcg->enable_safe_config) {
+		f_curr = qcom_find_freq(rcg->freq_tbl, rcg->current_freq);
+		if (!f_curr)
+			return -EINVAL;
+
+		hid_div = f_curr->pre_div;
+	} else {
+		mask = BIT(rcg->hid_width) - 1;
+		hid_div = cfg >> CFG_SRC_DIV_SHIFT;
+		hid_div &= mask;
+	}
 
 	return clk_rcg2_calc_rate(parent_rate, m, n, mode, hid_div);
 }
@@ -1181,6 +1191,76 @@
 };
 EXPORT_SYMBOL_GPL(clk_gfx3d_ops);
 
+static int clk_esc_determine_rate(struct clk_hw *hw,
+				    struct clk_rate_request *req)
+{
+	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+	unsigned long parent_rate, div;
+	u32 mask = BIT(rcg->hid_width) - 1;
+	struct clk_hw *p;
+	unsigned long rate = req->rate;
+
+	if (rate == 0)
+		return -EINVAL;
+
+	p = req->best_parent_hw;
+	req->best_parent_rate = parent_rate = clk_hw_round_rate(p, rate);
+
+	div = ((2 * parent_rate) / rate) - 1;
+	div = min_t(u32, div, mask);
+
+	req->rate = clk_rcg2_calc_rate(parent_rate, 0, 0, 0, div);
+
+	return 0;
+}
+
+static int clk_esc_set_rate(struct clk_hw *hw, unsigned long rate,
+			 unsigned long parent_rate)
+{
+	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+	struct freq_tbl f = { 0 };
+	unsigned long div;
+	int i, num_parents = clk_hw_get_num_parents(hw);
+	u32 mask = BIT(rcg->hid_width) - 1;
+	u32 cfg;
+
+	div = ((2 * parent_rate) / rate) - 1;
+	div = min_t(u32, div, mask);
+
+	f.pre_div = div;
+
+	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
+	cfg &= CFG_SRC_SEL_MASK;
+	cfg >>= CFG_SRC_SEL_SHIFT;
+
+	for (i = 0; i < num_parents; i++) {
+		if (cfg == rcg->parent_map[i].cfg) {
+			f.src = rcg->parent_map[i].src;
+			return clk_rcg2_configure(rcg, &f);
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int clk_esc_set_rate_and_parent(struct clk_hw *hw,
+		unsigned long rate, unsigned long parent_rate, u8 index)
+{
+	return clk_esc_set_rate(hw, rate, parent_rate);
+}
+
+const struct clk_ops clk_esc_ops = {
+	.is_enabled = clk_rcg2_is_enabled,
+	.get_parent = clk_rcg2_get_parent,
+	.set_parent = clk_rcg2_set_parent,
+	.recalc_rate = clk_rcg2_recalc_rate,
+	.determine_rate = clk_esc_determine_rate,
+	.set_rate = clk_esc_set_rate,
+	.set_rate_and_parent = clk_esc_set_rate_and_parent,
+	.list_registers = clk_rcg2_list_registers,
+};
+EXPORT_SYMBOL(clk_esc_ops);
+
 /* Common APIs to be used for DFS based RCGR */
 static u8 clk_parent_index_pre_div_and_mode(struct clk_hw *hw, u32 offset,
 		u32 *mode, u32 *pre_div)
diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c
index d4f27d7..0c49fa4 100644
--- a/drivers/clk/qcom/dispcc-sdm845.c
+++ b/drivers/clk/qcom/dispcc-sdm845.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -328,13 +328,12 @@
 	.mnd_width = 0,
 	.hid_width = 5,
 	.parent_map = disp_cc_parent_map_0,
-	.freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src,
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "disp_cc_mdss_esc0_clk_src",
 		.parent_names = disp_cc_parent_names_0,
 		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_rcg2_ops,
+		.ops = &clk_esc_ops,
 		VDD_CX_FMAX_MAP1(
 			MIN, 19200000),
 	},
@@ -345,13 +344,12 @@
 	.mnd_width = 0,
 	.hid_width = 5,
 	.parent_map = disp_cc_parent_map_0,
-	.freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src,
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "disp_cc_mdss_esc1_clk_src",
 		.parent_names = disp_cc_parent_names_0,
 		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_rcg2_ops,
+		.ops = &clk_esc_ops,
 		VDD_CX_FMAX_MAP1(
 			MIN, 19200000),
 	},
diff --git a/drivers/clk/renesas/clk-rcar-gen2.c b/drivers/clk/renesas/clk-rcar-gen2.c
index 00e6aba..c55d5fe 100644
--- a/drivers/clk/renesas/clk-rcar-gen2.c
+++ b/drivers/clk/renesas/clk-rcar-gen2.c
@@ -271,11 +271,14 @@
 	unsigned int extal_div;
 	unsigned int pll1_mult;
 	unsigned int pll3_mult;
+	unsigned int pll0_mult;		/* For R-Car V2H and E2 only */
 };
 
 static const struct cpg_pll_config cpg_pll_configs[8] __initconst = {
-	{ 1, 208, 106 }, { 1, 208,  88 }, { 1, 156,  80 }, { 1, 156,  66 },
-	{ 2, 240, 122 }, { 2, 240, 102 }, { 2, 208, 106 }, { 2, 208,  88 },
+	{ 1, 208, 106, 200 }, { 1, 208,  88, 200 },
+	{ 1, 156,  80, 150 }, { 1, 156,  66, 150 },
+	{ 2, 240, 122, 230 }, { 2, 240, 102, 230 },
+	{ 2, 208, 106, 200 }, { 2, 208,  88, 200 },
 };
 
 /* SDHI divisors */
@@ -297,6 +300,12 @@
 
 static u32 cpg_mode __initdata;
 
+static const char * const pll0_mult_match[] = {
+	"renesas,r8a7792-cpg-clocks",
+	"renesas,r8a7794-cpg-clocks",
+	NULL
+};
+
 static struct clk * __init
 rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
 			     const struct cpg_pll_config *config,
@@ -317,9 +326,15 @@
 		 * clock implementation and we currently have no need to change
 		 * the multiplier value.
 		 */
-		u32 value = clk_readl(cpg->reg + CPG_PLL0CR);
+		if (of_device_compatible_match(np, pll0_mult_match)) {
+			/* R-Car V2H and E2 do not have PLL0CR */
+			mult = config->pll0_mult;
+			div = 3;
+		} else {
+			u32 value = clk_readl(cpg->reg + CPG_PLL0CR);
+			mult = ((value >> 24) & ((1 << 7) - 1)) + 1;
+		}
 		parent_name = "main";
-		mult = ((value >> 24) & ((1 << 7) - 1)) + 1;
 	} else if (!strcmp(name, "pll1")) {
 		parent_name = "main";
 		mult = config->pll1_mult / 2;
diff --git a/drivers/clk/renesas/clk-sh73a0.c b/drivers/clk/renesas/clk-sh73a0.c
index eea38f6..3892346 100644
--- a/drivers/clk/renesas/clk-sh73a0.c
+++ b/drivers/clk/renesas/clk-sh73a0.c
@@ -46,7 +46,7 @@
 	unsigned int shift;
 };
 
-static struct div4_clk div4_clks[] = {
+static const struct div4_clk div4_clks[] = {
 	{ "zg", "pll0", CPG_FRQCRA, 16 },
 	{ "m3", "pll1", CPG_FRQCRA, 12 },
 	{ "b",  "pll1", CPG_FRQCRA,  8 },
@@ -79,7 +79,7 @@
 {
 	const struct clk_div_table *table = NULL;
 	unsigned int shift, reg, width;
-	const char *parent_name;
+	const char *parent_name = NULL;
 	unsigned int mult = 1;
 	unsigned int div = 1;
 
@@ -135,7 +135,7 @@
 		shift = 24;
 		width = 5;
 	} else {
-		struct div4_clk *c;
+		const struct div4_clk *c;
 
 		for (c = div4_clks; c->name; c++) {
 			if (!strcmp(name, c->name)) {
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 597aa57..379080c 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -45,6 +45,15 @@
 
 	  If in doubt, say N.
 
+config CPU_FREQ_TIMES
+       bool "CPU frequency time-in-state statistics"
+       default y
+       help
+         This driver exports CPU time-in-state information through procfs file
+         system.
+
+         If in doubt, say N.
+
 choice
 	prompt "Default CPUFreq governor"
 	default CPU_FREQ_DEFAULT_GOV_USERSPACE if ARM_SA1100_CPUFREQ || ARM_SA1110_CPUFREQ
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index bf98b28..ba9f9405 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -4,7 +4,10 @@
 # CPUfreq stats
 obj-$(CONFIG_CPU_FREQ_STAT)             += cpufreq_stats.o
 
-# CPUfreq governors 
+# CPUfreq times
+obj-$(CONFIG_CPU_FREQ_TIMES)		+= cpufreq_times.o
+
+# CPUfreq governors
 obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE)	+= cpufreq_performance.o
 obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE)	+= cpufreq_powersave.o
 obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE)	+= cpufreq_userspace.o
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 8059ef9..d82ce73 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -19,6 +19,7 @@
 
 #include <linux/cpu.h>
 #include <linux/cpufreq.h>
+#include <linux/cpufreq_times.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/init.h>
@@ -444,6 +445,7 @@
 			 (unsigned long)freqs->new, (unsigned long)freqs->cpu);
 		trace_cpu_frequency(freqs->new, freqs->cpu);
 		cpufreq_stats_record_transition(policy, freqs->new);
+		cpufreq_times_record_transition(freqs);
 		srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
 				CPUFREQ_POSTCHANGE, freqs);
 		if (likely(policy) && likely(policy->cpu == freqs->cpu))
@@ -1373,6 +1375,7 @@
 			goto out_exit_policy;
 
 		cpufreq_stats_create_table(policy);
+		cpufreq_times_create_policy(policy);
 		blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
 				CPUFREQ_CREATE_POLICY, policy);
 
diff --git a/drivers/cpufreq/cpufreq_times.c b/drivers/cpufreq/cpufreq_times.c
new file mode 100644
index 0000000..6254f45
--- /dev/null
+++ b/drivers/cpufreq/cpufreq_times.c
@@ -0,0 +1,461 @@
+/* drivers/cpufreq/cpufreq_times.c
+ *
+ * Copyright (C) 2018 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/cpufreq.h>
+#include <linux/cpufreq_times.h>
+#include <linux/cputime.h>
+#include <linux/hashtable.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/threads.h>
+
+#define UID_HASH_BITS 10
+
+static DECLARE_HASHTABLE(uid_hash_table, UID_HASH_BITS);
+
+static DEFINE_SPINLOCK(task_time_in_state_lock); /* task->time_in_state */
+static DEFINE_SPINLOCK(uid_lock); /* uid_hash_table */
+
+struct uid_entry {
+	uid_t uid;
+	unsigned int max_state;
+	struct hlist_node hash;
+	struct rcu_head rcu;
+	u64 time_in_state[0];
+};
+
+/**
+ * struct cpu_freqs - per-cpu frequency information
+ * @offset: start of these freqs' stats in task time_in_state array
+ * @max_state: number of entries in freq_table
+ * @last_index: index in freq_table of last frequency switched to
+ * @freq_table: list of available frequencies
+ */
+struct cpu_freqs {
+	unsigned int offset;
+	unsigned int max_state;
+	unsigned int last_index;
+	unsigned int freq_table[0];
+};
+
+static struct cpu_freqs *all_freqs[NR_CPUS];
+
+static unsigned int next_offset;
+
+
+/* Caller must hold rcu_read_lock() */
+static struct uid_entry *find_uid_entry_rcu(uid_t uid)
+{
+	struct uid_entry *uid_entry;
+
+	hash_for_each_possible_rcu(uid_hash_table, uid_entry, hash, uid) {
+		if (uid_entry->uid == uid)
+			return uid_entry;
+	}
+	return NULL;
+}
+
+/* Caller must hold uid lock */
+static struct uid_entry *find_uid_entry_locked(uid_t uid)
+{
+	struct uid_entry *uid_entry;
+
+	hash_for_each_possible(uid_hash_table, uid_entry, hash, uid) {
+		if (uid_entry->uid == uid)
+			return uid_entry;
+	}
+	return NULL;
+}
+
+/* Caller must hold uid lock */
+static struct uid_entry *find_or_register_uid_locked(uid_t uid)
+{
+	struct uid_entry *uid_entry, *temp;
+	unsigned int max_state = READ_ONCE(next_offset);
+	size_t alloc_size = sizeof(*uid_entry) + max_state *
+		sizeof(uid_entry->time_in_state[0]);
+
+	uid_entry = find_uid_entry_locked(uid);
+	if (uid_entry) {
+		if (uid_entry->max_state == max_state)
+			return uid_entry;
+		/* uid_entry->time_in_state is too small to track all freqs, so
+		 * expand it.
+		 */
+		temp = __krealloc(uid_entry, alloc_size, GFP_ATOMIC);
+		if (!temp)
+			return uid_entry;
+		temp->max_state = max_state;
+		memset(temp->time_in_state + uid_entry->max_state, 0,
+		       (max_state - uid_entry->max_state) *
+		       sizeof(uid_entry->time_in_state[0]));
+		if (temp != uid_entry) {
+			hlist_replace_rcu(&uid_entry->hash, &temp->hash);
+			kfree_rcu(uid_entry, rcu);
+		}
+		return temp;
+	}
+
+	uid_entry = kzalloc(alloc_size, GFP_ATOMIC);
+	if (!uid_entry)
+		return NULL;
+
+	uid_entry->uid = uid;
+	uid_entry->max_state = max_state;
+
+	hash_add_rcu(uid_hash_table, &uid_entry->hash, uid);
+
+	return uid_entry;
+}
+
+static bool freq_index_invalid(unsigned int index)
+{
+	unsigned int cpu;
+	struct cpu_freqs *freqs;
+
+	for_each_possible_cpu(cpu) {
+		freqs = all_freqs[cpu];
+		if (!freqs || index < freqs->offset ||
+		    freqs->offset + freqs->max_state <= index)
+			continue;
+		return freqs->freq_table[index - freqs->offset] ==
+			CPUFREQ_ENTRY_INVALID;
+	}
+	return true;
+}
+
+static int single_uid_time_in_state_show(struct seq_file *m, void *ptr)
+{
+	struct uid_entry *uid_entry;
+	unsigned int i;
+	u64 time;
+	uid_t uid = from_kuid_munged(current_user_ns(), *(kuid_t *)m->private);
+
+	if (uid == overflowuid)
+		return -EINVAL;
+
+	rcu_read_lock();
+
+	uid_entry = find_uid_entry_rcu(uid);
+	if (!uid_entry) {
+		rcu_read_unlock();
+		return 0;
+	}
+
+	for (i = 0; i < uid_entry->max_state; ++i) {
+		if (freq_index_invalid(i))
+			continue;
+		time = cputime_to_clock_t(uid_entry->time_in_state[i]);
+		seq_write(m, &time, sizeof(time));
+	}
+
+	rcu_read_unlock();
+
+	return 0;
+}
+
+static void *uid_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	if (*pos >= HASH_SIZE(uid_hash_table))
+		return NULL;
+
+	return &uid_hash_table[*pos];
+}
+
+static void *uid_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	(*pos)++;
+
+	if (*pos >= HASH_SIZE(uid_hash_table))
+		return NULL;
+
+	return &uid_hash_table[*pos];
+}
+
+static void uid_seq_stop(struct seq_file *seq, void *v) { }
+
+static int uid_time_in_state_seq_show(struct seq_file *m, void *v)
+{
+	struct uid_entry *uid_entry;
+	struct cpu_freqs *freqs, *last_freqs = NULL;
+	int i, cpu;
+
+	if (v == uid_hash_table) {
+		seq_puts(m, "uid:");
+		for_each_possible_cpu(cpu) {
+			freqs = all_freqs[cpu];
+			if (!freqs || freqs == last_freqs)
+				continue;
+			last_freqs = freqs;
+			for (i = 0; i < freqs->max_state; i++) {
+				if (freqs->freq_table[i] ==
+				    CPUFREQ_ENTRY_INVALID)
+					continue;
+				seq_printf(m, " %d", freqs->freq_table[i]);
+			}
+		}
+		seq_putc(m, '\n');
+	}
+
+	rcu_read_lock();
+
+	hlist_for_each_entry_rcu(uid_entry, (struct hlist_head *)v, hash) {
+		if (uid_entry->max_state)
+			seq_printf(m, "%d:", uid_entry->uid);
+		for (i = 0; i < uid_entry->max_state; ++i) {
+			if (freq_index_invalid(i))
+				continue;
+			seq_printf(m, " %lu", (unsigned long)cputime_to_clock_t(
+					   uid_entry->time_in_state[i]));
+		}
+		if (uid_entry->max_state)
+			seq_putc(m, '\n');
+	}
+
+	rcu_read_unlock();
+	return 0;
+}
+
+void cpufreq_task_times_init(struct task_struct *p)
+{
+	void *temp;
+	unsigned long flags;
+	unsigned int max_state;
+
+	spin_lock_irqsave(&task_time_in_state_lock, flags);
+	p->time_in_state = NULL;
+	spin_unlock_irqrestore(&task_time_in_state_lock, flags);
+	p->max_state = 0;
+
+	max_state = READ_ONCE(next_offset);
+
+	/* We use one array to avoid multiple allocs per task */
+	temp = kcalloc(max_state, sizeof(p->time_in_state[0]), GFP_ATOMIC);
+	if (!temp)
+		return;
+
+	spin_lock_irqsave(&task_time_in_state_lock, flags);
+	p->time_in_state = temp;
+	spin_unlock_irqrestore(&task_time_in_state_lock, flags);
+	p->max_state = max_state;
+}
+
+/* Caller must hold task_time_in_state_lock */
+static int cpufreq_task_times_realloc_locked(struct task_struct *p)
+{
+	void *temp;
+	unsigned int max_state = READ_ONCE(next_offset);
+
+	temp = krealloc(p->time_in_state, max_state * sizeof(u64), GFP_ATOMIC);
+	if (!temp)
+		return -ENOMEM;
+	p->time_in_state = temp;
+	memset(p->time_in_state + p->max_state, 0,
+	       (max_state - p->max_state) * sizeof(u64));
+	p->max_state = max_state;
+	return 0;
+}
+
+void cpufreq_task_times_exit(struct task_struct *p)
+{
+	unsigned long flags;
+	void *temp;
+
+	if (!p->time_in_state)
+		return;
+
+	spin_lock_irqsave(&task_time_in_state_lock, flags);
+	temp = p->time_in_state;
+	p->time_in_state = NULL;
+	spin_unlock_irqrestore(&task_time_in_state_lock, flags);
+	kfree(temp);
+}
+
+int proc_time_in_state_show(struct seq_file *m, struct pid_namespace *ns,
+	struct pid *pid, struct task_struct *p)
+{
+	unsigned int cpu, i;
+	cputime_t cputime;
+	unsigned long flags;
+	struct cpu_freqs *freqs;
+	struct cpu_freqs *last_freqs = NULL;
+
+	spin_lock_irqsave(&task_time_in_state_lock, flags);
+	for_each_possible_cpu(cpu) {
+		freqs = all_freqs[cpu];
+		if (!freqs || freqs == last_freqs)
+			continue;
+		last_freqs = freqs;
+
+		seq_printf(m, "cpu%u\n", cpu);
+		for (i = 0; i < freqs->max_state; i++) {
+			if (freqs->freq_table[i] == CPUFREQ_ENTRY_INVALID)
+				continue;
+			cputime = 0;
+			if (freqs->offset + i < p->max_state &&
+			    p->time_in_state)
+				cputime = p->time_in_state[freqs->offset + i];
+			seq_printf(m, "%u %lu\n", freqs->freq_table[i],
+				   (unsigned long)cputime_to_clock_t(cputime));
+		}
+	}
+	spin_unlock_irqrestore(&task_time_in_state_lock, flags);
+	return 0;
+}
+
+void cpufreq_acct_update_power(struct task_struct *p, cputime_t cputime)
+{
+	unsigned long flags;
+	unsigned int state;
+	struct uid_entry *uid_entry;
+	struct cpu_freqs *freqs = all_freqs[task_cpu(p)];
+	uid_t uid = from_kuid_munged(current_user_ns(), task_uid(p));
+
+	if (!freqs || p->flags & PF_EXITING)
+		return;
+
+	state = freqs->offset + READ_ONCE(freqs->last_index);
+
+	spin_lock_irqsave(&task_time_in_state_lock, flags);
+	if ((state < p->max_state || !cpufreq_task_times_realloc_locked(p)) &&
+	    p->time_in_state)
+		p->time_in_state[state] += cputime;
+	spin_unlock_irqrestore(&task_time_in_state_lock, flags);
+
+	spin_lock_irqsave(&uid_lock, flags);
+	uid_entry = find_or_register_uid_locked(uid);
+	if (uid_entry && state < uid_entry->max_state)
+		uid_entry->time_in_state[state] += cputime;
+	spin_unlock_irqrestore(&uid_lock, flags);
+}
+
+void cpufreq_times_create_policy(struct cpufreq_policy *policy)
+{
+	int cpu, index;
+	unsigned int count = 0;
+	struct cpufreq_frequency_table *pos, *table;
+	struct cpu_freqs *freqs;
+	void *tmp;
+
+	if (all_freqs[policy->cpu])
+		return;
+
+	table = policy->freq_table;
+	if (!table)
+		return;
+
+	cpufreq_for_each_entry(pos, table)
+		count++;
+
+	tmp =  kzalloc(sizeof(*freqs) + sizeof(freqs->freq_table[0]) * count,
+		       GFP_KERNEL);
+	if (!tmp)
+		return;
+
+	freqs = tmp;
+	freqs->max_state = count;
+
+	index = cpufreq_frequency_table_get_index(policy, policy->cur);
+	if (index >= 0)
+		WRITE_ONCE(freqs->last_index, index);
+
+	cpufreq_for_each_entry(pos, table)
+		freqs->freq_table[pos - table] = pos->frequency;
+
+	freqs->offset = next_offset;
+	WRITE_ONCE(next_offset, freqs->offset + count);
+	for_each_cpu(cpu, policy->related_cpus)
+		all_freqs[cpu] = freqs;
+}
+
+void cpufreq_task_times_remove_uids(uid_t uid_start, uid_t uid_end)
+{
+	struct uid_entry *uid_entry;
+	struct hlist_node *tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&uid_lock, flags);
+
+	for (; uid_start <= uid_end; uid_start++) {
+		hash_for_each_possible_safe(uid_hash_table, uid_entry, tmp,
+			hash, uid_start) {
+			if (uid_start == uid_entry->uid) {
+				hash_del_rcu(&uid_entry->hash);
+				kfree_rcu(uid_entry, rcu);
+			}
+		}
+	}
+
+	spin_unlock_irqrestore(&uid_lock, flags);
+}
+
+void cpufreq_times_record_transition(struct cpufreq_freqs *freq)
+{
+	int index;
+	struct cpu_freqs *freqs = all_freqs[freq->cpu];
+	struct cpufreq_policy *policy;
+
+	if (!freqs)
+		return;
+
+	policy = cpufreq_cpu_get(freq->cpu);
+	if (!policy)
+		return;
+
+	index = cpufreq_frequency_table_get_index(policy, freq->new);
+	if (index >= 0)
+		WRITE_ONCE(freqs->last_index, index);
+
+	cpufreq_cpu_put(policy);
+}
+
+static const struct seq_operations uid_time_in_state_seq_ops = {
+	.start = uid_seq_start,
+	.next = uid_seq_next,
+	.stop = uid_seq_stop,
+	.show = uid_time_in_state_seq_show,
+};
+
+static int uid_time_in_state_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &uid_time_in_state_seq_ops);
+}
+
+int single_uid_time_in_state_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, single_uid_time_in_state_show,
+			&(inode->i_uid));
+}
+
+static const struct file_operations uid_time_in_state_fops = {
+	.open		= uid_time_in_state_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
+static int __init cpufreq_times_init(void)
+{
+	proc_create_data("uid_time_in_state", 0444, NULL,
+			 &uid_time_in_state_fops, NULL);
+
+	return 0;
+}
+
+early_initcall(cpufreq_times_init);
diff --git a/drivers/cpuidle/dt_idle_states.c b/drivers/cpuidle/dt_idle_states.c
index a5c111b..ea11a33 100644
--- a/drivers/cpuidle/dt_idle_states.c
+++ b/drivers/cpuidle/dt_idle_states.c
@@ -174,8 +174,10 @@
 		if (!state_node)
 			break;
 
-		if (!of_device_is_available(state_node))
+		if (!of_device_is_available(state_node)) {
+			of_node_put(state_node);
 			continue;
+		}
 
 		if (!idle_state_valid(state_node, i, cpumask)) {
 			pr_warn("%s idle state not valid, bailing out\n",
diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c
index fe3ef48..7a653c6 100644
--- a/drivers/cpuidle/lpm-levels-of.c
+++ b/drivers/cpuidle/lpm-levels-of.c
@@ -708,7 +708,7 @@
 
 static int parse_cpu_levels(struct device_node *node, struct lpm_cluster *c)
 {
-	int ret, i;
+	int ret;
 	char *key;
 	struct lpm_cpu *cpu;
 
@@ -724,12 +724,12 @@
 	key = "qcom,psci-mode-shift";
 	ret = of_property_read_u32(node, key, &cpu->psci_mode_shift);
 	if (ret)
-		goto failed_parse_params;
+		goto failed;
 
 	key = "qcom,psci-mode-mask";
 	ret = of_property_read_u32(node, key, &cpu->psci_mode_mask);
 	if (ret)
-		goto failed_parse_params;
+		goto failed;
 
 	key = "qcom,disable-prediction";
 	cpu->lpm_prediction = !(of_property_read_bool(node, key));
@@ -757,20 +757,14 @@
 	key = "parse_cpu";
 	ret = parse_cpu(node, cpu);
 	if (ret)
-		goto failed_parse_cpu;
+		goto failed;
 
 	cpumask_or(&c->child_cpus, &c->child_cpus, &cpu->related_cpus);
 	list_add(&cpu->list, &c->cpu);
 
 	return ret;
 
-failed_parse_cpu:
-	for (i = 0; i < cpu->nlevels; i++) {
-		kfree(cpu->levels[i].name);
-		cpu->levels[i].name = NULL;
-	}
-
-failed_parse_params:
+failed:
 	pr_err("Failed to read key: %s node: %s\n", key, node->name);
 	return ret;
 }
@@ -785,15 +779,8 @@
 		free_cluster_node(cl);
 	};
 
-	list_for_each_entry_safe(cpu, n, &cluster->cpu, list) {
-		int i;
-
+	list_for_each_entry_safe(cpu, n, &cluster->cpu, list)
 		list_del(&cpu->list);
-		for (i = 0; i < cpu->nlevels; i++) {
-			kfree(cpu->levels[i].name);
-			cpu->levels[i].name = NULL;
-		}
-	}
 }
 
 /*
@@ -886,7 +873,6 @@
 		list_del(&c->list);
 	free_cluster_node(c);
 failed_parse_params:
-	c->parent = NULL;
 	pr_err("Failed parse params\n");
 	return NULL;
 }
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index 9ae640d..9694225 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -1783,12 +1783,10 @@
 #endif
 
 	rc = platform_driver_register(&lpm_driver);
-	if (rc) {
-		pr_info("Error registering %s\n", lpm_driver.driver.name);
-		goto fail;
-	}
+	if (rc)
+		pr_info("Error registering %s rc=%d\n", lpm_driver.driver.name,
+									rc);
 
-fail:
 	return rc;
 }
 late_initcall(lpm_levels_module_init);
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index d0b16e5..d8305dd 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -750,7 +750,10 @@
 	if (final)
 		new_len = DIV_ROUND_UP(new_len, bs) * bs;
 	else
-		new_len = new_len / bs * bs;
+		new_len = (new_len - 1) / bs * bs;
+
+	if (nbytes != new_len)
+		list_ok = false;
 
 	while (nbytes > 0 && sg_tmp) {
 		n++;
@@ -846,6 +849,8 @@
 			xmit_len = DIV_ROUND_UP(xmit_len, bs) * bs;
 		else
 			xmit_len = xmit_len / bs * bs;
+	} else if (!final) {
+		xmit_len -= bs;
 	}
 
 	hash_later = rctx->total - xmit_len;
@@ -873,14 +878,21 @@
 	}
 
 	if (hash_later) {
-		if (req->nbytes) {
-			scatterwalk_map_and_copy(rctx->buffer, req->src,
-						 req->nbytes - hash_later,
-						 hash_later, 0);
-		} else {
+		int offset = 0;
+
+		if (hash_later > req->nbytes) {
 			memcpy(rctx->buffer, rctx->buffer + xmit_len,
-			       hash_later);
+			       hash_later - req->nbytes);
+			offset = hash_later - req->nbytes;
 		}
+
+		if (req->nbytes) {
+			scatterwalk_map_and_copy(rctx->buffer + offset,
+						 req->src,
+						 offset + req->nbytes -
+						 hash_later, hash_later, 0);
+		}
+
 		rctx->bufcnt = hash_later;
 	} else {
 		rctx->bufcnt = 0;
@@ -1130,7 +1142,7 @@
 	ctx = ahash_request_ctx(req);
 
 	err = omap_sham_prepare_request(req, ctx->op == OP_UPDATE);
-	if (err)
+	if (err || !ctx->total)
 		goto err1;
 
 	dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n",
@@ -1189,11 +1201,10 @@
 	if (!req->nbytes)
 		return 0;
 
-	if (ctx->total + req->nbytes < ctx->buflen) {
+	if (ctx->bufcnt + req->nbytes <= ctx->buflen) {
 		scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, req->src,
 					 0, req->nbytes, 0);
 		ctx->bufcnt += req->nbytes;
-		ctx->total += req->nbytes;
 		return 0;
 	}
 
diff --git a/drivers/devfreq/arm-memlat-mon.c b/drivers/devfreq/arm-memlat-mon.c
index 1dca479..81f7c16 100644
--- a/drivers/devfreq/arm-memlat-mon.c
+++ b/drivers/devfreq/arm-memlat-mon.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, 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
@@ -82,7 +82,7 @@
 {
 	ktime_t ts;
 	unsigned int diff;
-	unsigned long freq = 0;
+	uint64_t freq = 0;
 
 	ts = ktime_get();
 	diff = ktime_to_us(ktime_sub(ts, cpustats->prev_ts));
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 3357aaf..2298de2 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -969,7 +969,8 @@
 	if (df->governor == governor) {
 		ret = 0;
 		goto out;
-	} else if (df->governor->immutable || governor->immutable) {
+	} else if ((df->governor && df->governor->immutable) ||
+					governor->immutable) {
 		ret = -EINVAL;
 		goto out;
 	}
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index b7d7f2d..ee7b48d 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -1473,10 +1473,10 @@
 	for (retry = 0; retry < AT_XDMAC_RESIDUE_MAX_RETRIES; retry++) {
 		check_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
 		rmb();
-		initd = !!(at_xdmac_chan_read(atchan, AT_XDMAC_CC) & AT_XDMAC_CC_INITD);
-		rmb();
 		cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC);
 		rmb();
+		initd = !!(at_xdmac_chan_read(atchan, AT_XDMAC_CC) & AT_XDMAC_CC_INITD);
+		rmb();
 		cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
 		rmb();
 
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 21726a2..b9c2972 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -1755,19 +1755,26 @@
 	if (IS_ERR(sdma->clk_ahb))
 		return PTR_ERR(sdma->clk_ahb);
 
-	clk_prepare(sdma->clk_ipg);
-	clk_prepare(sdma->clk_ahb);
+	ret = clk_prepare(sdma->clk_ipg);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare(sdma->clk_ahb);
+	if (ret)
+		goto err_clk;
 
 	ret = devm_request_irq(&pdev->dev, irq, sdma_int_handler, 0, "sdma",
 			       sdma);
 	if (ret)
-		return ret;
+		goto err_irq;
 
 	sdma->irq = irq;
 
 	sdma->script_addrs = kzalloc(sizeof(*sdma->script_addrs), GFP_KERNEL);
-	if (!sdma->script_addrs)
-		return -ENOMEM;
+	if (!sdma->script_addrs) {
+		ret = -ENOMEM;
+		goto err_irq;
+	}
 
 	/* initially no scripts available */
 	saddr_arr = (s32 *)sdma->script_addrs;
@@ -1882,6 +1889,10 @@
 	dma_async_device_unregister(&sdma->dma_device);
 err_init:
 	kfree(sdma->script_addrs);
+err_irq:
+	clk_unprepare(sdma->clk_ahb);
+err_clk:
+	clk_unprepare(sdma->clk_ipg);
 	return ret;
 }
 
@@ -1893,6 +1904,8 @@
 	devm_free_irq(&pdev->dev, sdma->irq, sdma);
 	dma_async_device_unregister(&sdma->dma_device);
 	kfree(sdma->script_addrs);
+	clk_unprepare(sdma->clk_ahb);
+	clk_unprepare(sdma->clk_ipg);
 	/* Kill the tasklet */
 	for (i = 0; i < MAX_DMA_CHANNELS; i++) {
 		struct sdma_channel *sdmac = &sdma->channel[i];
diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c
index cb9b857..61c19b8 100644
--- a/drivers/edac/mv64x60_edac.c
+++ b/drivers/edac/mv64x60_edac.c
@@ -759,7 +759,7 @@
 		/* Non-ECC RAM? */
 		printk(KERN_WARNING "%s: No ECC DIMMs discovered\n", __func__);
 		res = -ENODEV;
-		goto err2;
+		goto err;
 	}
 
 	edac_dbg(3, "init mci\n");
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index 3d50bae..1f81e63 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -59,7 +59,10 @@
 	return cpu == resident_cpu;
 }
 
-struct psci_operations psci_ops;
+struct psci_operations psci_ops = {
+	.conduit = PSCI_CONDUIT_NONE,
+	.smccc_version = SMCCC_VERSION_1_0,
+};
 
 typedef unsigned long (psci_fn)(unsigned long, unsigned long,
 				unsigned long, unsigned long);
@@ -210,6 +213,22 @@
 			      0, 0, 0);
 }
 
+static void set_conduit(enum psci_conduit conduit)
+{
+	switch (conduit) {
+	case PSCI_CONDUIT_HVC:
+		invoke_psci_fn = __invoke_psci_fn_hvc;
+		break;
+	case PSCI_CONDUIT_SMC:
+		invoke_psci_fn = __invoke_psci_fn_smc;
+		break;
+	default:
+		WARN(1, "Unexpected PSCI conduit %d\n", conduit);
+	}
+
+	psci_ops.conduit = conduit;
+}
+
 static int get_set_conduit_method(struct device_node *np)
 {
 	const char *method;
@@ -222,9 +241,9 @@
 	}
 
 	if (!strcmp("hvc", method)) {
-		invoke_psci_fn = __invoke_psci_fn_hvc;
+		set_conduit(PSCI_CONDUIT_HVC);
 	} else if (!strcmp("smc", method)) {
-		invoke_psci_fn = __invoke_psci_fn_smc;
+		set_conduit(PSCI_CONDUIT_SMC);
 	} else {
 		pr_warn("invalid \"method\" property: %s\n", method);
 		return -EINVAL;
@@ -495,6 +514,31 @@
 	pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid);
 }
 
+static void __init psci_init_smccc(void)
+{
+	u32 ver = ARM_SMCCC_VERSION_1_0;
+	int feature;
+
+	feature = psci_features(ARM_SMCCC_VERSION_FUNC_ID);
+
+	if (feature != PSCI_RET_NOT_SUPPORTED) {
+		u32 ret;
+		ret = invoke_psci_fn(ARM_SMCCC_VERSION_FUNC_ID, 0, 0, 0);
+		if (ret == ARM_SMCCC_VERSION_1_1) {
+			psci_ops.smccc_version = SMCCC_VERSION_1_1;
+			ver = ret;
+		}
+	}
+
+	/*
+	 * Conveniently, the SMCCC and PSCI versions are encoded the
+	 * same way. No, this isn't accidental.
+	 */
+	pr_info("SMC Calling Convention v%d.%d\n",
+		PSCI_VERSION_MAJOR(ver), PSCI_VERSION_MINOR(ver));
+
+}
+
 static void __init psci_0_2_set_functions(void)
 {
 	pr_info("Using standard PSCI v0.2 function IDs\n");
@@ -543,6 +587,7 @@
 	psci_init_migrate();
 
 	if (PSCI_VERSION_MAJOR(ver) >= 1) {
+		psci_init_smccc();
 		psci_init_cpu_suspend();
 		psci_init_system_suspend();
 	}
@@ -656,9 +701,9 @@
 	pr_info("probing for conduit method from ACPI.\n");
 
 	if (acpi_psci_use_hvc())
-		invoke_psci_fn = __invoke_psci_fn_hvc;
+		set_conduit(PSCI_CONDUIT_HVC);
 	else
-		invoke_psci_fn = __invoke_psci_fn_smc;
+		set_conduit(PSCI_CONDUIT_SMC);
 
 	return psci_probe();
 }
diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c
index 7c446d1..1d87b07 100644
--- a/drivers/gpio/gpio-crystalcove.c
+++ b/drivers/gpio/gpio-crystalcove.c
@@ -90,8 +90,18 @@
 {
 	int reg;
 
-	if (gpio == 94)
-		return GPIOPANELCTL;
+	if (gpio >= CRYSTALCOVE_GPIO_NUM) {
+		/*
+		 * Virtual GPIO called from ACPI, for now we only support
+		 * the panel ctl.
+		 */
+		switch (gpio) {
+		case 0x5e:
+			return GPIOPANELCTL;
+		default:
+			return -EOPNOTSUPP;
+		}
+	}
 
 	if (reg_type == CTRL_IN) {
 		if (gpio < 8)
@@ -130,36 +140,36 @@
 static int crystalcove_gpio_dir_in(struct gpio_chip *chip, unsigned gpio)
 {
 	struct crystalcove_gpio *cg = gpiochip_get_data(chip);
+	int reg = to_reg(gpio, CTRL_OUT);
 
-	if (gpio > CRYSTALCOVE_VGPIO_NUM)
+	if (reg < 0)
 		return 0;
 
-	return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT),
-			    CTLO_INPUT_SET);
+	return regmap_write(cg->regmap, reg, CTLO_INPUT_SET);
 }
 
 static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned gpio,
 				    int value)
 {
 	struct crystalcove_gpio *cg = gpiochip_get_data(chip);
+	int reg = to_reg(gpio, CTRL_OUT);
 
-	if (gpio > CRYSTALCOVE_VGPIO_NUM)
+	if (reg < 0)
 		return 0;
 
-	return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT),
-			    CTLO_OUTPUT_SET | value);
+	return regmap_write(cg->regmap, reg, CTLO_OUTPUT_SET | value);
 }
 
 static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned gpio)
 {
 	struct crystalcove_gpio *cg = gpiochip_get_data(chip);
-	int ret;
 	unsigned int val;
+	int ret, reg = to_reg(gpio, CTRL_IN);
 
-	if (gpio > CRYSTALCOVE_VGPIO_NUM)
+	if (reg < 0)
 		return 0;
 
-	ret = regmap_read(cg->regmap, to_reg(gpio, CTRL_IN), &val);
+	ret = regmap_read(cg->regmap, reg, &val);
 	if (ret)
 		return ret;
 
@@ -170,14 +180,15 @@
 				 unsigned gpio, int value)
 {
 	struct crystalcove_gpio *cg = gpiochip_get_data(chip);
+	int reg = to_reg(gpio, CTRL_OUT);
 
-	if (gpio > CRYSTALCOVE_VGPIO_NUM)
+	if (reg < 0)
 		return;
 
 	if (value)
-		regmap_update_bits(cg->regmap, to_reg(gpio, CTRL_OUT), 1, 1);
+		regmap_update_bits(cg->regmap, reg, 1, 1);
 	else
-		regmap_update_bits(cg->regmap, to_reg(gpio, CTRL_OUT), 1, 0);
+		regmap_update_bits(cg->regmap, reg, 1, 0);
 }
 
 static int crystalcove_irq_type(struct irq_data *data, unsigned type)
@@ -185,6 +196,9 @@
 	struct crystalcove_gpio *cg =
 		gpiochip_get_data(irq_data_get_irq_chip_data(data));
 
+	if (data->hwirq >= CRYSTALCOVE_GPIO_NUM)
+		return 0;
+
 	switch (type) {
 	case IRQ_TYPE_NONE:
 		cg->intcnt_value = CTLI_INTCNT_DIS;
@@ -235,8 +249,10 @@
 	struct crystalcove_gpio *cg =
 		gpiochip_get_data(irq_data_get_irq_chip_data(data));
 
-	cg->set_irq_mask = false;
-	cg->update |= UPDATE_IRQ_MASK;
+	if (data->hwirq < CRYSTALCOVE_GPIO_NUM) {
+		cg->set_irq_mask = false;
+		cg->update |= UPDATE_IRQ_MASK;
+	}
 }
 
 static void crystalcove_irq_mask(struct irq_data *data)
@@ -244,8 +260,10 @@
 	struct crystalcove_gpio *cg =
 		gpiochip_get_data(irq_data_get_irq_chip_data(data));
 
-	cg->set_irq_mask = true;
-	cg->update |= UPDATE_IRQ_MASK;
+	if (data->hwirq < CRYSTALCOVE_GPIO_NUM) {
+		cg->set_irq_mask = true;
+		cg->update |= UPDATE_IRQ_MASK;
+	}
 }
 
 static struct irq_chip crystalcove_irqchip = {
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f3c3680..4f54ff4 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -3231,7 +3231,8 @@
 		return desc;
 	}
 
-	status = gpiod_request(desc, con_id);
+	/* If a connection label was passed use that, else use the device name as label */
+	status = gpiod_request(desc, con_id ? con_id : dev_name(dev));
 	if (status < 0)
 		return ERR_PTR(status);
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
index 0e8f897..0217f5d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
@@ -569,6 +569,7 @@
 	{ 0x1002, 0x6900, 0x1002, 0x0124, AMDGPU_PX_QUIRK_FORCE_ATPX },
 	{ 0x1002, 0x6900, 0x1028, 0x0812, AMDGPU_PX_QUIRK_FORCE_ATPX },
 	{ 0x1002, 0x6900, 0x1028, 0x0813, AMDGPU_PX_QUIRK_FORCE_ATPX },
+	{ 0x1002, 0x67DF, 0x1028, 0x0774, AMDGPU_PX_QUIRK_FORCE_ATPX },
 	{ 0, 0, 0, 0, 0 },
 };
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
index c02db01f6..fe011c7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
@@ -201,8 +201,10 @@
 	for (i = 0; i < list->num_entries; i++) {
 		unsigned priority = list->array[i].priority;
 
-		list_add_tail(&list->array[i].tv.head,
-			      &bucket[priority]);
+		if (!list->array[i].robj->parent)
+			list_add_tail(&list->array[i].tv.head,
+				      &bucket[priority]);
+
 		list->array[i].user_pages = NULL;
 	}
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index cb505f6..c801624 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -519,7 +519,7 @@
 	INIT_LIST_HEAD(&duplicates);
 	amdgpu_vm_get_pd_bo(&fpriv->vm, &p->validated, &p->vm_pd);
 
-	if (p->uf_entry.robj)
+	if (p->uf_entry.robj && !p->uf_entry.robj->parent)
 		list_add(&p->uf_entry.tv.head, &p->validated);
 
 	if (need_mmap_lock)
diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c
index 002862b..3fa8320 100644
--- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c
+++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c
@@ -6449,9 +6449,9 @@
 {
 	u32 lane_width;
 	u32 new_lane_width =
-		(amdgpu_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT;
+		((amdgpu_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
 	u32 current_lane_width =
-		(amdgpu_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT;
+		((amdgpu_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
 
 	if (new_lane_width != current_lane_width) {
 		amdgpu_set_pcie_lanes(adev, new_lane_width);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
index ef7c8de..171480b 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
@@ -317,7 +317,8 @@
 
 	/* init process apertures*/
 	process->is_32bit_user_mode = in_compat_syscall();
-	if (kfd_init_apertures(process) != 0)
+	err = kfd_init_apertures(process);
+	if (err != 0)
 		goto err_init_apretures;
 
 	return process;
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 5e73dfa..bfe98b5 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -772,8 +772,6 @@
 	catalog = dp_catalog_get_priv(ctrl);
 	io_data = catalog->io.dp_link;
 
-	misc_val = dp_read(catalog, io_data, DP_MISC1_MISC0);
-	misc_val |= cc;
 	misc_val |= (tb << 5);
 	misc_val |= BIT(0); /* Configure clock to synchronous mode */
 
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
index d083e72..a457070 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
@@ -214,6 +214,7 @@
 	phy->ops.ulps_ops.is_lanes_in_ulps =
 		dsi_phy_hw_v3_0_is_lanes_in_ulps;
 	phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v3_0;
+	phy->ops.clamp_ctrl = dsi_phy_hw_v3_0_clamp_ctrl;
 	phy->ops.phy_lane_reset = dsi_phy_hw_v3_0_lane_reset;
 	phy->ops.toggle_resync_fifo = dsi_phy_hw_v3_0_toggle_resync_fifo;
 }
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
index 0e2db430..144ccd9 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
@@ -102,6 +102,7 @@
 bool dsi_phy_hw_v3_0_is_lanes_in_ulps(u32 lanes, u32 ulps_lanes);
 int dsi_phy_hw_timing_val_v3_0(struct dsi_phy_per_lane_cfgs *timing_cfg,
 		u32 *timing_val, u32 size);
+void dsi_phy_hw_v3_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable);
 int dsi_phy_hw_v3_0_lane_reset(struct dsi_phy_hw *phy);
 void dsi_phy_hw_v3_0_toggle_resync_fifo(struct dsi_phy_hw *phy);
 
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
index d89760e..bdc60d2 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
@@ -43,6 +43,13 @@
 	DSI_LINK_CLK_MAX,
 };
 
+enum dsi_link_clk_op_type {
+	DSI_LINK_CLK_SET_RATE = BIT(0),
+	DSI_LINK_CLK_PREPARE = BIT(1),
+	DSI_LINK_CLK_ENABLE = BIT(2),
+	DSI_LINK_CLK_START = BIT(0) | BIT(1) | BIT(2),
+};
+
 enum dsi_clk_type {
 	DSI_CORE_CLK = BIT(0),
 	DSI_LINK_CLK = BIT(1),
@@ -50,6 +57,12 @@
 	DSI_CLKS_MAX = BIT(2),
 };
 
+enum dsi_lclk_type {
+	DSI_LINK_NONE = 0,
+	DSI_LINK_LP_CLK = BIT(0),
+	DSI_LINK_HS_CLK = BIT(1),
+};
+
 struct dsi_clk_ctrl_info {
 	enum dsi_clk_type clk_type;
 	enum dsi_clk_state clk_state;
@@ -82,23 +95,29 @@
 };
 
 /**
- * struct dsi_link_clk_info - Link clock information for DSI hardware.
- * @byte_clk:        Handle to DSI byte clock.
- * @pixel_clk:       Handle to DSI pixel clock.
- * @esc_clk:         Handle to DSI escape clock.
+ * struct dsi_link_hs_clk_info - Set of high speed link clocks for DSI HW
+ * @byte_clk:        Handle to DSI byte_clk.
+ * @pixel_clk:       Handle to DSI pixel_clk.
  * @byte_intf_clk:   Handle to DSI byte intf. clock.
  */
-struct dsi_link_clk_info {
+struct dsi_link_hs_clk_info {
 	struct clk *byte_clk;
 	struct clk *pixel_clk;
-	struct clk *esc_clk;
 	struct clk *byte_intf_clk;
 };
 
 /**
+ * struct dsi_link_lp_clk_info - Set of low power link clocks for DSI HW.
+ * @esc_clk:         Handle to DSI escape clock.
+ */
+struct dsi_link_lp_clk_info {
+	struct clk *esc_clk;
+};
+
+/**
  * struct link_clk_freq - Clock frequency information for Link clocks
- * @byte_clk_rate:   Frequency of DSI byte clock in KHz.
- * @pixel_clk_rate:  Frequency of DSI pixel clock in KHz.
+ * @byte_clk_rate:   Frequency of DSI byte_clk in KHz.
+ * @pixel_clk_rate:  Frequency of DSI pixel_clk in KHz.
  * @esc_clk_rate:    Frequency of DSI escape clock in KHz.
  */
 struct link_clk_freq {
@@ -111,48 +130,56 @@
  * typedef *pre_clockoff_cb() - Callback before clock is turned off
  * @priv: private data pointer.
  * @clk_type: clock which is being turned off.
+ * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
  * @new_state: next state for the clock.
  *
  * @return: error code.
  */
 typedef int (*pre_clockoff_cb)(void *priv,
 			       enum dsi_clk_type clk_type,
+			       enum dsi_lclk_type l_type,
 			       enum dsi_clk_state new_state);
 
 /**
  * typedef *post_clockoff_cb() - Callback after clock is turned off
  * @priv: private data pointer.
  * @clk_type: clock which was turned off.
+ * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
  * @curr_state: current state for the clock.
  *
  * @return: error code.
  */
 typedef int (*post_clockoff_cb)(void *priv,
 				enum dsi_clk_type clk_type,
+				enum dsi_lclk_type l_type,
 				enum dsi_clk_state curr_state);
 
 /**
  * typedef *post_clockon_cb() - Callback after clock is turned on
  * @priv: private data pointer.
  * @clk_type: clock which was turned on.
+ * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
  * @curr_state: current state for the clock.
  *
  * @return: error code.
  */
 typedef int (*post_clockon_cb)(void *priv,
 			       enum dsi_clk_type clk_type,
+			       enum dsi_lclk_type l_type,
 			       enum dsi_clk_state curr_state);
 
 /**
  * typedef *pre_clockon_cb() - Callback before clock is turned on
  * @priv: private data pointer.
  * @clk_type: clock which is being turned on.
+ * @l_type: specifies if the clock is HS or LP type.Valid only for link clocks.
  * @new_state: next state for the clock.
  *
  * @return: error code.
  */
 typedef int (*pre_clockon_cb)(void *priv,
 			      enum dsi_clk_type clk_type,
+			      enum dsi_lclk_type l_type,
 			      enum dsi_clk_state new_state);
 
 
@@ -160,7 +187,8 @@
  * struct dsi_clk_info - clock information for DSI hardware.
  * @name:                    client name.
  * @c_clks[MAX_DSI_CTRL]     array of core clock configurations
- * @l_clks[MAX_DSI_CTRL]     array of link clock configurations
+ * @l_lp_clks[MAX_DSI_CTRL]  array of low power(esc) clock configurations
+ * @l_hs_clks[MAX_DSI_CTRL]  array of high speed clock configurations
  * @bus_handle[MAX_DSI_CTRL] array of bus handles
  * @ctrl_index[MAX_DSI_CTRL] array of DSI controller indexes mapped
  *                           to core and link clock configurations
@@ -175,7 +203,8 @@
 struct dsi_clk_info {
 	char name[MAX_STRING_LEN];
 	struct dsi_core_clk_info c_clks[MAX_DSI_CTRL];
-	struct dsi_link_clk_info l_clks[MAX_DSI_CTRL];
+	struct dsi_link_lp_clk_info l_lp_clks[MAX_DSI_CTRL];
+	struct dsi_link_hs_clk_info l_hs_clks[MAX_DSI_CTRL];
 	u32 bus_handle[MAX_DSI_CTRL];
 	u32 ctrl_index[MAX_DSI_CTRL];
 	pre_clockoff_cb pre_clkoff_cb;
@@ -189,8 +218,8 @@
 
 /**
  * struct dsi_clk_link_set - Pair of clock handles to describe link clocks
- * @byte_clk:     Handle to DSi byte clock.
- * @pixel_clk:    Handle to DSI pixel clock.
+ * @byte_clk:     Handle to DSi byte_clk.
+ * @pixel_clk:    Handle to DSI pixel_clk.
  */
 struct dsi_clk_link_set {
 	struct clk *byte_clk;
@@ -263,10 +292,10 @@
 
 
 /**
- * dsi_clk_set_pixel_clk_rate() - set frequency for pixel clock
+ * dsi_clk_set_pixel_clk_rate() - set frequency for pixel_clk
  * @client:       DSI clock client pointer.
- * @pixel_clk: Pixel clock rate in Hz.
- * @index:      Index of the DSI controller.
+ * @pixel_clk:    Pixel_clk rate in Hz.
+ * @index:        Index of the DSI controller.
  * return: error code in case of failure or 0 for success.
  */
 int dsi_clk_set_pixel_clk_rate(void *client, u64 pixel_clk, u32 index);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
index 434d383..2e3828e 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
@@ -24,7 +24,8 @@
 };
 
 struct dsi_link_clks {
-	struct dsi_link_clk_info clks;
+	struct dsi_link_hs_clk_info hs_clks;
+	struct dsi_link_lp_clk_info lp_clks;
 	struct link_clk_freq freq;
 };
 
@@ -124,7 +125,7 @@
 	struct dsi_clk_mngr *mngr;
 
 	mngr = c->mngr;
-	rc = clk_set_rate(mngr->link_clks[index].clks.pixel_clk, pixel_clk);
+	rc = clk_set_rate(mngr->link_clks[index].hs_clks.pixel_clk, pixel_clk);
 	if (rc)
 		pr_err("failed to set clk rate for pixel clk, rc=%d\n", rc);
 	else
@@ -147,7 +148,7 @@
 	struct dsi_clk_mngr *mngr;
 
 	mngr = c->mngr;
-	rc = clk_set_rate(mngr->link_clks[index].clks.byte_clk, byte_clk);
+	rc = clk_set_rate(mngr->link_clks[index].hs_clks.byte_clk, byte_clk);
 	if (rc)
 		pr_err("failed to set clk rate for byte clk, rc=%d\n", rc);
 	else
@@ -285,38 +286,39 @@
 	return rc;
 }
 
-static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks, int index)
+static int dsi_link_hs_clk_set_rate(struct dsi_link_hs_clk_info *link_hs_clks,
+		int index)
 {
 	int rc = 0;
 	struct dsi_clk_mngr *mngr;
+	struct dsi_link_clks *l_clks;
 
 	if (index >= MAX_DSI_CTRL) {
 		pr_err("Invalid DSI ctrl index\n");
 		return -EINVAL;
 	}
 
+	l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks);
 	mngr = container_of(l_clks, struct dsi_clk_mngr, link_clks[index]);
-	if (mngr->is_cont_splash_enabled)
-		return 0;
+
 	/*
 	 * In an ideal world, cont_splash_enabled should not be required inside
 	 * the clock manager. But, in the current driver cont_splash_enabled
 	 * flag is set inside mdp driver and there is no interface event
 	 * associated with this flag setting.
 	 */
-	rc = clk_set_rate(l_clks->clks.esc_clk, l_clks->freq.esc_clk_rate);
-	if (rc) {
-		pr_err("clk_set_rate failed for esc_clk rc = %d\n", rc);
-		goto error;
-	}
+	if (mngr->is_cont_splash_enabled)
+		return 0;
 
-	rc = clk_set_rate(l_clks->clks.byte_clk, l_clks->freq.byte_clk_rate);
+	rc = clk_set_rate(link_hs_clks->byte_clk,
+		l_clks->freq.byte_clk_rate);
 	if (rc) {
 		pr_err("clk_set_rate failed for byte_clk rc = %d\n", rc);
 		goto error;
 	}
 
-	rc = clk_set_rate(l_clks->clks.pixel_clk, l_clks->freq.pix_clk_rate);
+	rc = clk_set_rate(link_hs_clks->pixel_clk,
+		l_clks->freq.pix_clk_rate);
 	if (rc) {
 		pr_err("clk_set_rate failed for pixel_clk rc = %d\n", rc);
 		goto error;
@@ -327,8 +329,8 @@
 	 * For DPHY: byte_intf_clk_rate = byte_clk_rate / 2
 	 * todo: this needs to be revisited when support for CPHY is added
 	 */
-	if (l_clks->clks.byte_intf_clk) {
-		rc = clk_set_rate(l_clks->clks.byte_intf_clk,
+	if (link_hs_clks->byte_intf_clk) {
+		rc = clk_set_rate(link_hs_clks->byte_intf_clk,
 			(l_clks->freq.byte_clk_rate / 2));
 		if (rc) {
 			pr_err("set_rate failed for byte_intf_clk rc = %d\n",
@@ -340,30 +342,24 @@
 	return rc;
 }
 
-static int dsi_link_clk_prepare(struct dsi_link_clks *l_clks)
+static int dsi_link_hs_clk_prepare(struct dsi_link_hs_clk_info *link_hs_clks)
 {
 	int rc = 0;
 
-	rc = clk_prepare(l_clks->clks.esc_clk);
-	if (rc) {
-		pr_err("Failed to prepare dsi esc clk, rc=%d\n", rc);
-		goto esc_clk_err;
-	}
-
-	rc = clk_prepare(l_clks->clks.byte_clk);
+	rc = clk_prepare(link_hs_clks->byte_clk);
 	if (rc) {
 		pr_err("Failed to prepare dsi byte clk, rc=%d\n", rc);
 		goto byte_clk_err;
 	}
 
-	rc = clk_prepare(l_clks->clks.pixel_clk);
+	rc = clk_prepare(link_hs_clks->pixel_clk);
 	if (rc) {
 		pr_err("Failed to prepare dsi pixel clk, rc=%d\n", rc);
 		goto pixel_clk_err;
 	}
 
-	if (l_clks->clks.byte_intf_clk) {
-		rc = clk_prepare(l_clks->clks.byte_intf_clk);
+	if (link_hs_clks->byte_intf_clk) {
+		rc = clk_prepare(link_hs_clks->byte_intf_clk);
 		if (rc) {
 			pr_err("Failed to prepare dsi byte intf clk, rc=%d\n",
 				rc);
@@ -374,48 +370,39 @@
 	return rc;
 
 byte_intf_clk_err:
-	clk_unprepare(l_clks->clks.pixel_clk);
+	clk_unprepare(link_hs_clks->pixel_clk);
 pixel_clk_err:
-	clk_unprepare(l_clks->clks.byte_clk);
+	clk_unprepare(link_hs_clks->byte_clk);
 byte_clk_err:
-	clk_unprepare(l_clks->clks.esc_clk);
-esc_clk_err:
 	return rc;
 }
 
-static void dsi_link_clk_unprepare(struct dsi_link_clks *l_clks)
+static void dsi_link_hs_clk_unprepare(struct dsi_link_hs_clk_info *link_hs_clks)
 {
-	if (l_clks->clks.byte_intf_clk)
-		clk_unprepare(l_clks->clks.byte_intf_clk);
-	clk_unprepare(l_clks->clks.pixel_clk);
-	clk_unprepare(l_clks->clks.byte_clk);
-	clk_unprepare(l_clks->clks.esc_clk);
+	if (link_hs_clks->byte_intf_clk)
+		clk_unprepare(link_hs_clks->byte_intf_clk);
+	clk_unprepare(link_hs_clks->pixel_clk);
+	clk_unprepare(link_hs_clks->byte_clk);
 }
 
-static int dsi_link_clk_enable(struct dsi_link_clks *l_clks)
+static int dsi_link_hs_clk_enable(struct dsi_link_hs_clk_info *link_hs_clks)
 {
 	int rc = 0;
 
-	rc = clk_enable(l_clks->clks.esc_clk);
-	if (rc) {
-		pr_err("Failed to enable dsi esc clk, rc=%d\n", rc);
-		goto esc_clk_err;
-	}
-
-	rc = clk_enable(l_clks->clks.byte_clk);
+	rc = clk_enable(link_hs_clks->byte_clk);
 	if (rc) {
 		pr_err("Failed to enable dsi byte clk, rc=%d\n", rc);
 		goto byte_clk_err;
 	}
 
-	rc = clk_enable(l_clks->clks.pixel_clk);
+	rc = clk_enable(link_hs_clks->pixel_clk);
 	if (rc) {
 		pr_err("Failed to enable dsi pixel clk, rc=%d\n", rc);
 		goto pixel_clk_err;
 	}
 
-	if (l_clks->clks.byte_intf_clk) {
-		rc = clk_enable(l_clks->clks.byte_intf_clk);
+	if (link_hs_clks->byte_intf_clk) {
+		rc = clk_enable(link_hs_clks->byte_intf_clk);
 		if (rc) {
 			pr_err("Failed to enable dsi byte intf clk, rc=%d\n",
 				rc);
@@ -426,28 +413,26 @@
 	return rc;
 
 byte_intf_clk_err:
-	clk_disable(l_clks->clks.pixel_clk);
+	clk_disable(link_hs_clks->pixel_clk);
 pixel_clk_err:
-	clk_disable(l_clks->clks.byte_clk);
+	clk_disable(link_hs_clks->byte_clk);
 byte_clk_err:
-	clk_disable(l_clks->clks.esc_clk);
-esc_clk_err:
 	return rc;
 }
 
-static void dsi_link_clk_disable(struct dsi_link_clks *l_clks)
+static void dsi_link_hs_clk_disable(struct dsi_link_hs_clk_info *link_hs_clks)
 {
-	if (l_clks->clks.byte_intf_clk)
-		clk_disable(l_clks->clks.byte_intf_clk);
-	clk_disable(l_clks->clks.esc_clk);
-	clk_disable(l_clks->clks.pixel_clk);
-	clk_disable(l_clks->clks.byte_clk);
+	if (link_hs_clks->byte_intf_clk)
+		clk_disable(link_hs_clks->byte_intf_clk);
+	clk_disable(link_hs_clks->pixel_clk);
+	clk_disable(link_hs_clks->byte_clk);
 }
 
 /**
  * dsi_link_clk_start() - enable dsi link clocks
  */
-static int dsi_link_clk_start(struct dsi_link_clks *clks, int index)
+static int dsi_link_hs_clk_start(struct dsi_link_hs_clk_info *link_hs_clks,
+	enum dsi_link_clk_op_type op_type, int index)
 {
 	int rc = 0;
 
@@ -456,28 +441,34 @@
 		return -EINVAL;
 	}
 
-	rc = dsi_link_clk_set_rate(clks, index);
-	if (rc) {
-		pr_err("failed to set clk rates, rc = %d\n", rc);
-		goto error;
+	if (op_type & DSI_LINK_CLK_SET_RATE) {
+		rc = dsi_link_hs_clk_set_rate(link_hs_clks, index);
+		if (rc) {
+			pr_err("failed to set HS clk rates, rc = %d\n", rc);
+			goto error;
+		}
 	}
 
-	rc = dsi_link_clk_prepare(clks);
-	if (rc) {
-		pr_err("failed to prepare link clks, rc = %d\n", rc);
-		goto error;
+	if (op_type & DSI_LINK_CLK_PREPARE) {
+		rc = dsi_link_hs_clk_prepare(link_hs_clks);
+		if (rc) {
+			pr_err("failed to prepare link HS clks, rc = %d\n", rc);
+			goto error;
+		}
 	}
 
-	rc = dsi_link_clk_enable(clks);
-	if (rc) {
-		pr_err("failed to enable link clks, rc = %d\n", rc);
-		goto error_unprepare;
+	if (op_type & DSI_LINK_CLK_ENABLE) {
+		rc = dsi_link_hs_clk_enable(link_hs_clks);
+		if (rc) {
+			pr_err("failed to enable link HS clks, rc = %d\n", rc);
+			goto error_unprepare;
+		}
 	}
 
-	pr_debug("Link clocks are enabled\n");
+	pr_debug("HS Link clocks are enabled\n");
 	return rc;
 error_unprepare:
-	dsi_link_clk_unprepare(clks);
+	dsi_link_hs_clk_unprepare(link_hs_clks);
 error:
 	return rc;
 }
@@ -485,13 +476,69 @@
 /**
  * dsi_link_clk_stop() - Stop DSI link clocks.
  */
-int dsi_link_clk_stop(struct dsi_link_clks *clks)
+static int dsi_link_hs_clk_stop(struct dsi_link_hs_clk_info *link_hs_clks)
 {
-	dsi_link_clk_disable(clks);
-	dsi_link_clk_unprepare(clks);
+	struct dsi_link_clks *l_clks;
 
-	pr_debug("Link clocks disabled\n");
+	l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks);
 
+	dsi_link_hs_clk_disable(link_hs_clks);
+	dsi_link_hs_clk_unprepare(link_hs_clks);
+
+	pr_debug("HS Link clocks disabled\n");
+
+	return 0;
+}
+
+static int dsi_link_lp_clk_start(struct dsi_link_lp_clk_info *link_lp_clks)
+{
+	int rc = 0;
+	struct dsi_clk_mngr *mngr;
+	struct dsi_link_clks *l_clks;
+
+	l_clks = container_of(link_lp_clks, struct dsi_link_clks, lp_clks);
+
+	mngr = container_of(l_clks, struct dsi_clk_mngr, link_clks[0]);
+	if (!mngr)
+		return -EINVAL;
+	/*
+	 * In an ideal world, cont_splash_enabled should not be required inside
+	 * the clock manager. But, in the current driver cont_splash_enabled
+	 * flag is set inside mdp driver and there is no interface event
+	 * associated with this flag setting. Also, set rate for clock need not
+	 * be called for every enable call. It should be done only once when
+	 * coming out of suspend.
+	 */
+	if (mngr->is_cont_splash_enabled)
+		goto prepare;
+
+	rc = clk_set_rate(link_lp_clks->esc_clk, l_clks->freq.esc_clk_rate);
+	if (rc) {
+		pr_err("clk_set_rate failed for esc_clk rc = %d\n", rc);
+		goto error;
+	}
+
+prepare:
+	rc = clk_prepare_enable(link_lp_clks->esc_clk);
+	if (rc) {
+		pr_err("Failed to enable dsi esc clk\n");
+		clk_unprepare(l_clks->lp_clks.esc_clk);
+	}
+error:
+	pr_debug("LP Link clocks are enabled\n");
+	return rc;
+}
+
+static int dsi_link_lp_clk_stop(
+	struct dsi_link_lp_clk_info *link_lp_clks)
+{
+	struct dsi_link_clks *l_clks;
+
+	l_clks = container_of(link_lp_clks, struct dsi_link_clks, lp_clks);
+
+	clk_disable_unprepare(l_clks->lp_clks.esc_clk);
+
+	pr_debug("LP Link clocks are disabled\n");
 	return 0;
 }
 
@@ -556,7 +603,7 @@
 }
 
 static int dsi_display_link_clk_enable(struct dsi_link_clks *clks,
-	u32 ctrl_count, u32 master_ndx)
+	enum dsi_lclk_type l_type, u32 ctrl_count, u32 master_ndx)
 {
 	int rc = 0;
 	int i;
@@ -570,27 +617,56 @@
 
 	m_clks = &clks[master_ndx];
 
-	rc = dsi_link_clk_start(m_clks, master_ndx);
-	if (rc) {
-		pr_err("failed to turn on master clocks, rc=%d\n", rc);
-		goto error;
+	if (l_type & DSI_LINK_LP_CLK) {
+		rc = dsi_link_lp_clk_start(&m_clks->lp_clks);
+		if (rc) {
+			pr_err("failed to turn on master lp link clocks, rc=%d\n",
+				rc);
+			goto error;
+		}
 	}
 
-	/* Turn on rest of the core clocks */
+	if (l_type & DSI_LINK_HS_CLK) {
+		rc = dsi_link_hs_clk_start(&m_clks->hs_clks,
+			DSI_LINK_CLK_START, master_ndx);
+		if (rc) {
+			pr_err("failed to turn on master hs link clocks, rc=%d\n",
+				rc);
+			goto error;
+		}
+	}
+
 	for (i = 0; i < ctrl_count; i++) {
 		clk = &clks[i];
 		if (!clk || (clk == m_clks))
 			continue;
 
-		rc = dsi_link_clk_start(clk, i);
-		if (rc) {
-			pr_err("failed to turn on clocks, rc=%d\n", rc);
-			goto error_disable_master;
+		if (l_type & DSI_LINK_LP_CLK) {
+			rc = dsi_link_lp_clk_start(&clk->lp_clks);
+			if (rc) {
+				pr_err("failed to turn on lp link clocks, rc=%d\n",
+					rc);
+				goto error_disable_master;
+			}
+		}
+
+		if (l_type & DSI_LINK_HS_CLK) {
+			rc = dsi_link_hs_clk_start(&clk->hs_clks,
+				DSI_LINK_CLK_START, i);
+			if (rc) {
+				pr_err("failed to turn on hs link clocks, rc=%d\n",
+					rc);
+				goto error_disable_master;
+			}
 		}
 	}
 	return rc;
+
 error_disable_master:
-	(void)dsi_link_clk_stop(m_clks);
+	if (l_type == DSI_LINK_LP_CLK)
+		(void)dsi_link_lp_clk_stop(&m_clks->lp_clks);
+	else if (l_type == DSI_LINK_HS_CLK)
+		(void)dsi_link_hs_clk_stop(&m_clks->hs_clks);
 error:
 	return rc;
 }
@@ -646,7 +722,7 @@
 }
 
 static int dsi_display_link_clk_disable(struct dsi_link_clks *clks,
-	u32 ctrl_count, u32 master_ndx)
+	enum dsi_lclk_type l_type, u32 ctrl_count, u32 master_ndx)
 {
 	int rc = 0;
 	int i;
@@ -667,15 +743,100 @@
 		if (!clk || (clk == m_clks))
 			continue;
 
-		rc = dsi_link_clk_stop(clk);
-		if (rc)
-			pr_err("failed to turn off clocks, rc=%d\n", rc);
+		if (l_type & DSI_LINK_LP_CLK) {
+			rc = dsi_link_lp_clk_stop(&clk->lp_clks);
+			if (rc)
+				pr_err("failed to turn off lp link clocks, rc=%d\n",
+					rc);
+		}
+
+		if (l_type & DSI_LINK_HS_CLK) {
+			rc = dsi_link_hs_clk_stop(&clk->hs_clks);
+			if (rc)
+				pr_err("failed to turn off hs link clocks, rc=%d\n",
+					rc);
+		}
 	}
 
-	rc = dsi_link_clk_stop(m_clks);
-	if (rc)
-		pr_err("failed to turn off master clocks, rc=%d\n", rc);
+	if (l_type & DSI_LINK_LP_CLK) {
+		rc = dsi_link_lp_clk_stop(&m_clks->lp_clks);
+		if (rc)
+			pr_err("failed to turn off master lp link clocks, rc=%d\n",
+				rc);
+	}
 
+	if (l_type & DSI_LINK_HS_CLK) {
+		rc = dsi_link_hs_clk_stop(&m_clks->hs_clks);
+		if (rc)
+			pr_err("failed to turn off master hs link clocks, rc=%d\n",
+				rc);
+	}
+
+	return rc;
+}
+
+static int dsi_clk_update_link_clk_state(struct dsi_link_clks *l_clks,
+	enum dsi_lclk_type l_type, u32 l_state, bool enable)
+{
+	int rc = 0;
+	struct dsi_clk_mngr *mngr;
+
+	mngr = container_of(l_clks, struct dsi_clk_mngr, link_clks[0]);
+	if (!mngr)
+		return -EINVAL;
+
+	if (enable) {
+		if (mngr->pre_clkon_cb) {
+			rc = mngr->pre_clkon_cb(mngr->priv_data, DSI_LINK_CLK,
+				l_type, l_state);
+			if (rc) {
+				pr_err("pre link clk on cb failed for type %d\n",
+					l_type);
+				goto error;
+			}
+		}
+		rc = dsi_display_link_clk_enable(l_clks, l_type,
+				mngr->dsi_ctrl_count, mngr->master_ndx);
+		if (rc) {
+			pr_err("failed to start link clk type %d rc=%d\n",
+				l_type, rc);
+			goto error;
+		}
+
+		if (mngr->post_clkon_cb) {
+			rc = mngr->post_clkon_cb(mngr->priv_data, DSI_LINK_CLK,
+				l_type, l_state);
+			if (rc) {
+				pr_err("post link clk on cb failed for type %d\n",
+					l_type);
+				goto error;
+			}
+		}
+	} else {
+		if (mngr->pre_clkoff_cb) {
+			rc = mngr->pre_clkoff_cb(mngr->priv_data,
+				DSI_LINK_CLK, l_type, l_state);
+			if (rc)
+				pr_err("pre link clk off cb failed\n");
+		}
+
+		rc = dsi_display_link_clk_disable(l_clks, l_type,
+			mngr->dsi_ctrl_count, mngr->master_ndx);
+		if (rc) {
+			pr_err("failed to stop link clk type %d, rc = %d\n",
+			       l_type, rc);
+			goto error;
+		}
+
+		if (mngr->post_clkoff_cb) {
+			rc = mngr->post_clkoff_cb(mngr->priv_data,
+				DSI_LINK_CLK, l_type, l_state);
+			if (rc)
+				pr_err("post link clk off cb failed\n");
+		}
+	}
+
+error:
 	return rc;
 }
 
@@ -710,6 +871,7 @@
 		if (mngr->core_clk_state == DSI_CLK_OFF) {
 			rc = mngr->pre_clkon_cb(mngr->priv_data,
 						DSI_CORE_CLK,
+						DSI_LINK_NONE,
 						DSI_CLK_ON);
 			if (rc) {
 				pr_err("failed to turn on MDP FS rc= %d\n", rc);
@@ -726,6 +888,7 @@
 		if (mngr->post_clkon_cb) {
 			rc = mngr->post_clkon_cb(mngr->priv_data,
 						 DSI_CORE_CLK,
+						 DSI_LINK_NONE,
 						 DSI_CLK_ON);
 			if (rc)
 				pr_err("post clk on cb failed, rc = %d\n", rc);
@@ -735,25 +898,15 @@
 
 	if (l_clks) {
 		if (l_state == DSI_CLK_ON) {
-			if (mngr->pre_clkon_cb) {
-				rc = mngr->pre_clkon_cb(mngr->priv_data,
-					DSI_LINK_CLK, l_state);
-				if (rc)
-					pr_err("pre link clk on cb failed\n");
-			}
-			rc = dsi_display_link_clk_enable(l_clks,
-					mngr->dsi_ctrl_count, mngr->master_ndx);
-			if (rc) {
-				pr_err("failed to start link clk rc= %d\n", rc);
+			rc = dsi_clk_update_link_clk_state(l_clks,
+				DSI_LINK_LP_CLK, l_state, true);
+			if (rc)
 				goto error;
-			}
-			if (mngr->post_clkon_cb) {
-				rc = mngr->post_clkon_cb(mngr->priv_data,
-							DSI_LINK_CLK,
-							l_state);
-				if (rc)
-					pr_err("post link clk on cb failed\n");
-			}
+
+			rc = dsi_clk_update_link_clk_state(l_clks,
+				DSI_LINK_HS_CLK, l_state, true);
+			if (rc)
+				goto error;
 		} else {
 			/*
 			 * Two conditions that need to be checked for Link
@@ -784,36 +937,26 @@
 				}
 
 				rc = dsi_display_link_clk_enable(l_clks,
+					(DSI_LINK_LP_CLK & DSI_LINK_HS_CLK),
 					mngr->dsi_ctrl_count, mngr->master_ndx);
 				if (rc) {
-					pr_err("Link clks did not start\n");
+					pr_err("LP Link clks did not start\n");
 					goto error;
 				}
 				l_c_on = true;
 				pr_debug("ECG: core and Link_on\n");
 			}
 
-			if (mngr->pre_clkoff_cb) {
-				rc = mngr->pre_clkoff_cb(mngr->priv_data,
-					DSI_LINK_CLK, l_state);
-				if (rc)
-					pr_err("pre link clk off cb failed\n");
-			}
-
-			rc = dsi_display_link_clk_disable(l_clks,
-				mngr->dsi_ctrl_count, mngr->master_ndx);
-			if (rc) {
-				pr_err("failed to stop link clk, rc = %d\n",
-				       rc);
+			rc = dsi_clk_update_link_clk_state(l_clks,
+				DSI_LINK_HS_CLK, l_state, false);
+			if (rc)
 				goto error;
-			}
 
-			if (mngr->post_clkoff_cb) {
-				rc = mngr->post_clkoff_cb(mngr->priv_data,
-					DSI_LINK_CLK, l_state);
-				if (rc)
-					pr_err("post link clk off cb failed\n");
-			}
+			rc = dsi_clk_update_link_clk_state(l_clks,
+				DSI_LINK_LP_CLK, l_state, false);
+			if (rc)
+				goto error;
+
 			/*
 			 * This check is to save unnecessary clock state
 			 * change when going from EARLY_GATE to OFF. In the
@@ -872,6 +1015,7 @@
 		if (mngr->pre_clkoff_cb) {
 			rc = mngr->pre_clkoff_cb(mngr->priv_data,
 						 DSI_CORE_CLK,
+						 DSI_LINK_NONE,
 						 c_state);
 			if (rc)
 				pr_err("pre core clk off cb failed\n");
@@ -888,6 +1032,7 @@
 			if (mngr->post_clkoff_cb) {
 				rc = mngr->post_clkoff_cb(mngr->priv_data,
 						DSI_CORE_CLK,
+						DSI_LINK_NONE,
 						DSI_CLK_OFF);
 				if (rc)
 					pr_err("post clkoff cb fail, rc = %d\n",
@@ -1095,7 +1240,8 @@
 	}
 
 	rc = dsi_display_link_clk_disable(l_clks,
-		mngr->dsi_ctrl_count, mngr->master_ndx);
+			(DSI_LINK_LP_CLK | DSI_LINK_HS_CLK),
+			mngr->dsi_ctrl_count, mngr->master_ndx);
 	if (rc) {
 		pr_err("%s, failed to stop link clk, rc = %d\n",
 			__func__, rc);
@@ -1103,7 +1249,8 @@
 	}
 
 	rc = dsi_display_link_clk_enable(l_clks,
-		mngr->dsi_ctrl_count, mngr->master_ndx);
+			(DSI_LINK_LP_CLK | DSI_LINK_HS_CLK),
+			mngr->dsi_ctrl_count, mngr->master_ndx);
 	if (rc) {
 		pr_err("%s, failed to start link clk rc= %d\n",
 			__func__, rc);
@@ -1267,8 +1414,10 @@
 	for (i = 0; i < mngr->dsi_ctrl_count; i++) {
 		memcpy(&mngr->core_clks[i].clks, &info->c_clks[i],
 			sizeof(struct dsi_core_clk_info));
-		memcpy(&mngr->link_clks[i].clks, &info->l_clks[i],
-			sizeof(struct dsi_link_clk_info));
+		memcpy(&mngr->link_clks[i].hs_clks, &info->l_hs_clks[i],
+			sizeof(struct dsi_link_hs_clk_info));
+		memcpy(&mngr->link_clks[i].lp_clks, &info->l_lp_clks[i],
+			sizeof(struct dsi_link_lp_clk_info));
 		mngr->core_clks[i].bus_handle = info->bus_handle[i];
 		mngr->ctrl_index[i] = info->ctrl_index[i];
 	}
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index c7c640f5..32bc3eb 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -498,7 +498,8 @@
 static int dsi_ctrl_clocks_deinit(struct dsi_ctrl *ctrl)
 {
 	struct dsi_core_clk_info *core = &ctrl->clk_info.core_clks;
-	struct dsi_link_clk_info *link = &ctrl->clk_info.link_clks;
+	struct dsi_link_lp_clk_info *lp_link = &ctrl->clk_info.lp_link_clks;
+	struct dsi_link_hs_clk_info *hs_link = &ctrl->clk_info.hs_link_clks;
 	struct dsi_clk_link_set *rcg = &ctrl->clk_info.rcg_clks;
 
 	if (core->mdp_core_clk)
@@ -514,16 +515,17 @@
 
 	memset(core, 0x0, sizeof(*core));
 
-	if (link->byte_clk)
-		devm_clk_put(&ctrl->pdev->dev, link->byte_clk);
-	if (link->pixel_clk)
-		devm_clk_put(&ctrl->pdev->dev, link->pixel_clk);
-	if (link->esc_clk)
-		devm_clk_put(&ctrl->pdev->dev, link->esc_clk);
-	if (link->byte_intf_clk)
-		devm_clk_put(&ctrl->pdev->dev, link->byte_intf_clk);
+	if (hs_link->byte_clk)
+		devm_clk_put(&ctrl->pdev->dev, hs_link->byte_clk);
+	if (hs_link->pixel_clk)
+		devm_clk_put(&ctrl->pdev->dev, hs_link->pixel_clk);
+	if (lp_link->esc_clk)
+		devm_clk_put(&ctrl->pdev->dev, lp_link->esc_clk);
+	if (hs_link->byte_intf_clk)
+		devm_clk_put(&ctrl->pdev->dev, hs_link->byte_intf_clk);
 
-	memset(link, 0x0, sizeof(*link));
+	memset(hs_link, 0x0, sizeof(*hs_link));
+	memset(lp_link, 0x0, sizeof(*lp_link));
 
 	if (rcg->byte_clk)
 		devm_clk_put(&ctrl->pdev->dev, rcg->byte_clk);
@@ -540,7 +542,8 @@
 {
 	int rc = 0;
 	struct dsi_core_clk_info *core = &ctrl->clk_info.core_clks;
-	struct dsi_link_clk_info *link = &ctrl->clk_info.link_clks;
+	struct dsi_link_lp_clk_info *lp_link = &ctrl->clk_info.lp_link_clks;
+	struct dsi_link_hs_clk_info *hs_link = &ctrl->clk_info.hs_link_clks;
 	struct dsi_clk_link_set *rcg = &ctrl->clk_info.rcg_clks;
 
 	core->mdp_core_clk = devm_clk_get(&pdev->dev, "mdp_core_clk");
@@ -573,30 +576,30 @@
 		pr_debug("can't get mnoc clock, rc=%d\n", rc);
 	}
 
-	link->byte_clk = devm_clk_get(&pdev->dev, "byte_clk");
-	if (IS_ERR(link->byte_clk)) {
-		rc = PTR_ERR(link->byte_clk);
+	hs_link->byte_clk = devm_clk_get(&pdev->dev, "byte_clk");
+	if (IS_ERR(hs_link->byte_clk)) {
+		rc = PTR_ERR(hs_link->byte_clk);
 		pr_err("failed to get byte_clk, rc=%d\n", rc);
 		goto fail;
 	}
 
-	link->pixel_clk = devm_clk_get(&pdev->dev, "pixel_clk");
-	if (IS_ERR(link->pixel_clk)) {
-		rc = PTR_ERR(link->pixel_clk);
+	hs_link->pixel_clk = devm_clk_get(&pdev->dev, "pixel_clk");
+	if (IS_ERR(hs_link->pixel_clk)) {
+		rc = PTR_ERR(hs_link->pixel_clk);
 		pr_err("failed to get pixel_clk, rc=%d\n", rc);
 		goto fail;
 	}
 
-	link->esc_clk = devm_clk_get(&pdev->dev, "esc_clk");
-	if (IS_ERR(link->esc_clk)) {
-		rc = PTR_ERR(link->esc_clk);
+	lp_link->esc_clk = devm_clk_get(&pdev->dev, "esc_clk");
+	if (IS_ERR(lp_link->esc_clk)) {
+		rc = PTR_ERR(lp_link->esc_clk);
 		pr_err("failed to get esc_clk, rc=%d\n", rc);
 		goto fail;
 	}
 
-	link->byte_intf_clk = devm_clk_get(&pdev->dev, "byte_intf_clk");
-	if (IS_ERR(link->byte_intf_clk)) {
-		link->byte_intf_clk = NULL;
+	hs_link->byte_intf_clk = devm_clk_get(&pdev->dev, "byte_intf_clk");
+	if (IS_ERR(hs_link->byte_intf_clk)) {
+		hs_link->byte_intf_clk = NULL;
 		pr_debug("can't find byte intf clk, rc=%d\n", rc);
 	}
 
@@ -1338,9 +1341,6 @@
 	u32 dlen, diff, rlen = msg->rx_len;
 	unsigned char *buff;
 	char cmd;
-	struct dsi_cmd_desc *of_cmd;
-
-	of_cmd = container_of(msg, struct dsi_cmd_desc, msg);
 
 	if (msg->rx_len <= 2) {
 		short_resp = true;
@@ -1378,9 +1378,9 @@
 		 * wait before reading rdbk_data register, if any delay is
 		 * required after sending the read command.
 		 */
-		if (of_cmd && of_cmd->post_wait_ms)
-			usleep_range(of_cmd->post_wait_ms * 1000,
-				     ((of_cmd->post_wait_ms * 1000) + 10));
+		if (msg->wait_ms)
+			usleep_range(msg->wait_ms * 1000,
+				     ((msg->wait_ms * 1000) + 10));
 
 		dlen = dsi_ctrl->hw.ops.get_cmd_read_data(&dsi_ctrl->hw,
 					buff, total_bytes_read,
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
index e08ef99..b059fc5 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
@@ -100,7 +100,8 @@
 /**
  * struct dsi_ctrl_clk_info - clock information for DSI controller
  * @core_clks:          Core clocks needed to access DSI controller registers.
- * @link_clks:          Link clocks required to transmit data over DSI link.
+ * @hs_link_clks:       Clocks required to transmit high speed data over DSI
+ * @lp_link_clks:       Clocks required to perform low power ops over DSI
  * @rcg_clks:           Root clock generation clocks generated in MMSS_CC. The
  *			output of the PLL is set as parent for these root
  *			clocks. These clocks are specific to controller
@@ -114,7 +115,8 @@
 struct dsi_ctrl_clk_info {
 	/* Clocks parsed from DT */
 	struct dsi_core_clk_info core_clks;
-	struct dsi_link_clk_info link_clks;
+	struct dsi_link_hs_clk_info hs_link_clks;
+	struct dsi_link_lp_clk_info lp_link_clks;
 	struct dsi_clk_link_set rcg_clks;
 
 	/* Clocks set by DSI Manager */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index adcec15..7194f1a 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -559,9 +559,6 @@
 	if (dsi_ctrl_validate_host_state(ctrl->ctrl))
 		return 1;
 
-	/* acquire panel_lock to make sure no commands are in progress */
-	dsi_panel_acquire_panel_lock(panel);
-
 	config = &(panel->esd_config);
 	lenp = config->status_valid_params ?: config->status_cmds_rlen;
 	count = config->status_cmd.count;
@@ -580,7 +577,7 @@
 		rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, &cmds[i].msg, flags);
 		if (rc <= 0) {
 			pr_err("rx cmd transfer failed rc=%d\n", rc);
-			goto error;
+			return rc;
 		}
 
 		memcpy(config->return_buf + start,
@@ -588,9 +585,6 @@
 		start += lenp[i];
 	}
 
-error:
-	/* release panel_lock */
-	dsi_panel_release_panel_lock(panel);
 	return rc;
 }
 
@@ -709,15 +703,16 @@
 	u32 status_mode;
 	int rc = 0x1;
 
-	if (dsi_display == NULL)
+	if (!dsi_display || !dsi_display->panel)
 		return -EINVAL;
 
-	mutex_lock(&dsi_display->display_lock);
-
 	panel = dsi_display->panel;
+
+	dsi_panel_acquire_panel_lock(panel);
+
 	if (!panel->panel_initialized) {
 		pr_debug("Panel not initialized\n");
-		mutex_unlock(&dsi_display->display_lock);
+		dsi_panel_release_panel_lock(panel);
 		return rc;
 	}
 
@@ -742,7 +737,7 @@
 
 	dsi_display_clk_ctrl(dsi_display->dsi_clk_handle,
 		DSI_ALL_CLKS, DSI_CLK_OFF);
-	mutex_unlock(&dsi_display->display_lock);
+	dsi_panel_release_panel_lock(panel);
 
 	return rc;
 }
@@ -758,7 +753,7 @@
 	cmd->msg.channel = cmd_buf[2];
 	cmd->msg.flags = cmd_buf[3];
 	cmd->msg.ctrl = 0;
-	cmd->post_wait_ms = cmd_buf[4];
+	cmd->post_wait_ms = cmd->msg.wait_ms = cmd_buf[4];
 	cmd->msg.tx_len = ((cmd_buf[5] << 8) | (cmd_buf[6]));
 
 	if (cmd->msg.tx_len > payload_len) {
@@ -1582,9 +1577,19 @@
 	m_ctrl = &display->ctrl[display->cmd_master_idx];
 	ulps_enabled = display->ulps_enabled;
 
+	/*
+	 * Clamp control can be either through the DSI controller or
+	 * the DSI PHY depending on hardware variation
+	 */
 	rc = dsi_ctrl_set_clamp_state(m_ctrl->ctrl, enable, ulps_enabled);
 	if (rc) {
-		pr_err("DSI Clamp state change(%d) failed\n", enable);
+		pr_err("DSI ctrl clamp state change(%d) failed\n", enable);
+		return rc;
+	}
+
+	rc = dsi_phy_set_clamp_state(m_ctrl->phy, enable);
+	if (rc) {
+		pr_err("DSI phy clamp state change(%d) failed\n", enable);
 		return rc;
 	}
 
@@ -1598,7 +1603,18 @@
 			pr_err("DSI Clamp state change(%d) failed\n", enable);
 			return rc;
 		}
+
+		rc = dsi_phy_set_clamp_state(ctrl->phy, enable);
+		if (rc) {
+			pr_err("DSI phy clamp state change(%d) failed\n",
+				enable);
+			return rc;
+		}
+
+		pr_debug("Clamps %s for ctrl%d\n",
+			enable ? "enabled" : "disabled", i);
 	}
+
 	display->clamp_enabled = enable;
 	return 0;
 }
@@ -3003,12 +3019,14 @@
 
 int dsi_pre_clkoff_cb(void *priv,
 			   enum dsi_clk_type clk,
+			   enum dsi_lclk_type l_type,
 			   enum dsi_clk_state new_state)
 {
 	int rc = 0;
 	struct dsi_display *display = priv;
 
-	if ((clk & DSI_LINK_CLK) && (new_state == DSI_CLK_OFF)) {
+	if ((clk & DSI_LINK_CLK) && (new_state == DSI_CLK_OFF) &&
+		(l_type && DSI_LINK_LP_CLK)) {
 		/*
 		 * If ULPS feature is enabled, enter ULPS first.
 		 * However, when blanking the panel, we should enter ULPS
@@ -3060,13 +3078,14 @@
 
 int dsi_post_clkon_cb(void *priv,
 			   enum dsi_clk_type clk,
+			   enum dsi_lclk_type l_type,
 			   enum dsi_clk_state curr_state)
 {
 	int rc = 0;
 	struct dsi_display *display = priv;
 	bool mmss_clamp = false;
 
-	if (clk & DSI_CORE_CLK) {
+	if ((clk & DSI_LINK_CLK) && (l_type & DSI_LINK_LP_CLK)) {
 		mmss_clamp = display->clamp_enabled;
 		/*
 		 * controller setup is needed if coming out of idle
@@ -3075,6 +3094,13 @@
 		if (mmss_clamp)
 			dsi_display_ctrl_setup(display);
 
+		/*
+		 * Phy setup is needed if coming out of idle
+		 * power collapse with clamps enabled.
+		 */
+		if (display->phy_idle_power_off || mmss_clamp)
+			dsi_display_phy_idle_on(display, mmss_clamp);
+
 		if (display->ulps_enabled && mmss_clamp) {
 			/*
 			 * ULPS Entry Request. This is needed if the lanes were
@@ -3113,17 +3139,11 @@
 			goto error;
 		}
 
-		/*
-		 * Phy setup is needed if coming out of idle
-		 * power collapse with clamps enabled.
-		 */
-		if (display->phy_idle_power_off || mmss_clamp)
-			dsi_display_phy_idle_on(display, mmss_clamp);
-
 		/* enable dsi to serve irqs */
 		dsi_display_ctrl_irq_update(display, true);
 	}
-	if (clk & DSI_LINK_CLK) {
+
+	if ((clk & DSI_LINK_CLK) && (l_type & DSI_LINK_HS_CLK)) {
 		/*
 		 * Toggle the resync FIFO everytime clock changes, except
 		 * when cont-splash screen transition is going on.
@@ -3148,6 +3168,7 @@
 
 int dsi_post_clkoff_cb(void *priv,
 			    enum dsi_clk_type clk_type,
+			    enum dsi_lclk_type l_type,
 			    enum dsi_clk_state curr_state)
 {
 	int rc = 0;
@@ -3175,6 +3196,7 @@
 
 int dsi_pre_clkon_cb(void *priv,
 			  enum dsi_clk_type clk_type,
+			  enum dsi_lclk_type l_type,
 			  enum dsi_clk_state new_state)
 {
 	int rc = 0;
@@ -4391,10 +4413,16 @@
 			goto error_ctrl_deinit;
 		}
 
-		memcpy(&info.c_clks[i], &display_ctrl->ctrl->clk_info.core_clks,
-			sizeof(struct dsi_core_clk_info));
-		memcpy(&info.l_clks[i], &display_ctrl->ctrl->clk_info.link_clks,
-			sizeof(struct dsi_link_clk_info));
+		memcpy(&info.c_clks[i],
+				(&display_ctrl->ctrl->clk_info.core_clks),
+				sizeof(struct dsi_core_clk_info));
+		memcpy(&info.l_hs_clks[i],
+				(&display_ctrl->ctrl->clk_info.hs_link_clks),
+				sizeof(struct dsi_link_hs_clk_info));
+		memcpy(&info.l_lp_clks[i],
+				(&display_ctrl->ctrl->clk_info.lp_link_clks),
+				sizeof(struct dsi_link_lp_clk_info));
+
 		info.c_clks[i].phandle = &priv->phandle;
 		info.bus_handle[i] =
 			display_ctrl->ctrl->axi_bus_info.bus_handle;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
index 6b1c029..5612016 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -497,12 +497,14 @@
  * dsi_pre_clkoff_cb() - Callback before clock is turned off
  * @priv: private data pointer.
  * @clk_type: clock which is being turned on.
+ * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
  * @new_state: next state for the clock.
  *
  * @return: error code.
  */
 int dsi_pre_clkoff_cb(void *priv, enum dsi_clk_type clk_type,
-	enum dsi_clk_state new_state);
+		enum dsi_lclk_type l_type,
+		enum dsi_clk_state new_state);
 
 /**
  * dsi_display_update_pps() - update PPS buffer.
@@ -519,35 +521,40 @@
  * dsi_post_clkoff_cb() - Callback after clock is turned off
  * @priv: private data pointer.
  * @clk_type: clock which is being turned on.
+ * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
  * @curr_state: current state for the clock.
  *
  * @return: error code.
  */
 int dsi_post_clkoff_cb(void *priv, enum dsi_clk_type clk_type,
-	enum dsi_clk_state curr_state);
+		enum dsi_lclk_type l_type,
+		enum dsi_clk_state curr_state);
 
 /**
  * dsi_post_clkon_cb() - Callback after clock is turned on
  * @priv: private data pointer.
  * @clk_type: clock which is being turned on.
+ * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
  * @curr_state: current state for the clock.
  *
  * @return: error code.
  */
 int dsi_post_clkon_cb(void *priv, enum dsi_clk_type clk_type,
-	enum dsi_clk_state curr_state);
-
+		enum dsi_lclk_type l_type,
+		enum dsi_clk_state curr_state);
 
 /**
  * dsi_pre_clkon_cb() - Callback before clock is turned on
  * @priv: private data pointer.
  * @clk_type: clock which is being turned on.
+ * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
  * @new_state: next state for the clock.
  *
  * @return: error code.
  */
 int dsi_pre_clkon_cb(void *priv, enum dsi_clk_type clk_type,
-	enum dsi_clk_state new_state);
+		enum dsi_lclk_type l_type,
+		enum dsi_clk_state new_state);
 
 /**
  * dsi_display_unprepare() - power off display hardware.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
index 5b47865..6b5bfb4 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
@@ -186,6 +186,7 @@
 {
 	int rc = 0;
 	struct dsi_bridge *c_bridge = to_dsi_bridge(bridge);
+	struct dsi_display *display;
 
 	if (!bridge) {
 		pr_err("Invalid params\n");
@@ -197,11 +198,15 @@
 		pr_debug("[%d] seamless enable\n", c_bridge->id);
 		return;
 	}
+	display = c_bridge->display;
 
-	rc = dsi_display_post_enable(c_bridge->display);
+	rc = dsi_display_post_enable(display);
 	if (rc)
 		pr_err("[%d] DSI display post enabled failed, rc=%d\n",
 		       c_bridge->id, rc);
+
+	if (display && display->drm_conn)
+		sde_connector_helper_bridge_enable(display->drm_conn);
 }
 
 static void dsi_bridge_disable(struct drm_bridge *bridge)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index 79df631..cb9c1fa 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -1536,7 +1536,7 @@
 		cmd[i].msg.channel = data[2];
 		cmd[i].msg.flags |= (data[3] == 1 ? MIPI_DSI_MSG_REQ_ACK : 0);
 		cmd[i].msg.ctrl = 0;
-		cmd[i].post_wait_ms = data[4];
+		cmd[i].post_wait_ms = cmd[i].msg.wait_ms = data[4];
 		cmd[i].msg.tx_len = ((data[5] << 8) | (data[6]));
 
 		size = cmd[i].msg.tx_len * sizeof(u8);
@@ -1771,6 +1771,9 @@
 
 	panel->sync_broadcast_en = of_property_read_bool(of_node,
 			"qcom,cmd-sync-wait-broadcast");
+
+	panel->lp11_init = of_property_read_bool(of_node,
+			"qcom,mdss-dsi-lp11-init");
 	return 0;
 }
 
@@ -3511,6 +3514,7 @@
 	set->cmds[0].msg.tx_buf = caset;
 	set->cmds[0].msg.rx_len = 0;
 	set->cmds[0].msg.rx_buf = 0;
+	set->cmds[0].msg.wait_ms = 0;
 	set->cmds[0].last_command = 0;
 	set->cmds[0].post_wait_ms = 0;
 
@@ -3522,6 +3526,7 @@
 	set->cmds[1].msg.tx_buf = paset;
 	set->cmds[1].msg.rx_len = 0;
 	set->cmds[1].msg.rx_buf = 0;
+	set->cmds[1].msg.wait_ms = 0;
 	set->cmds[1].last_command = 1;
 	set->cmds[1].post_wait_ms = 0;
 
@@ -3746,14 +3751,6 @@
 		goto error;
 	}
 
-	if (panel->lp11_init) {
-		rc = dsi_panel_power_off(panel);
-		if (rc) {
-			pr_err("[%s] panel power_Off failed, rc=%d\n",
-			       panel->name, rc);
-			goto error;
-		}
-	}
 error:
 	mutex_unlock(&panel->panel_lock);
 	return rc;
@@ -3773,13 +3770,11 @@
 
 	mutex_lock(&panel->panel_lock);
 
-	if (!panel->lp11_init) {
-		rc = dsi_panel_power_off(panel);
-		if (rc) {
-			pr_err("[%s] panel power_Off failed, rc=%d\n",
-			       panel->name, rc);
-			goto error;
-		}
+	rc = dsi_panel_power_off(panel);
+	if (rc) {
+		pr_err("[%s] panel power_Off failed, rc=%d\n",
+		       panel->name, rc);
+		goto error;
 	}
 error:
 	mutex_unlock(&panel->panel_lock);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
index 6a7a84c..2e2d0d8 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
@@ -902,6 +902,26 @@
 }
 
 /**
+ * dsi_phy_set_clamp_state() - configure clamps for DSI lanes
+ * @phy:        DSI PHY handle.
+ * @enable:     boolean to specify clamp enable/disable.
+ *
+ * Return: error code.
+ */
+int dsi_phy_set_clamp_state(struct msm_dsi_phy *phy, bool enable)
+{
+	if (!phy)
+		return -EINVAL;
+
+	pr_debug("[%s] enable=%d\n", phy->name, enable);
+
+	if (phy->hw.ops.clamp_ctrl)
+		phy->hw.ops.clamp_ctrl(&phy->hw, enable);
+
+	return 0;
+}
+
+/**
  * dsi_phy_idle_ctrl() - enable/disable DSI PHY during idle screen
  * @phy:          DSI PHY handle
  * @enable:       boolean to specify PHY enable/disable.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
index 56d5ee3..4163411 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
@@ -218,6 +218,15 @@
 int dsi_phy_idle_ctrl(struct msm_dsi_phy *phy, bool enable);
 
 /**
+ * dsi_phy_set_clamp_state() - configure clamps for DSI lanes
+ * @phy:        DSI PHY handle.
+ * @enable:     boolean to specify clamp enable/disable.
+ *
+ * Return: error code.
+ */
+int dsi_phy_set_clamp_state(struct msm_dsi_phy *phy, bool enable);
+
+/**
  * dsi_phy_set_clk_freq() - set DSI PHY clock frequency setting
  * @phy:          DSI PHY handle
  * @clk_freq:     link clock frequency
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h
index e31899d4..d24a613 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h
@@ -234,6 +234,14 @@
 				u32 *timing, u32 size);
 
 	/**
+	 * clamp_ctrl() - configure clamps for DSI lanes
+	 * @phy:        DSI PHY handle.
+	 * @enable:     boolean to specify clamp enable/disable.
+	 * Return:    error code.
+	 */
+	void (*clamp_ctrl)(struct dsi_phy_hw *phy, bool enable);
+
+	/**
 	 * phy_lane_reset() - Reset dsi phy lanes in case of error.
 	 * @phy:      Pointer to DSI PHY hardware object.
 	 * Return:    error code.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
index b078231..5015806 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
@@ -196,10 +196,31 @@
 		DSI_W32(phy, DSIPHY_LNX_OFFSET_BOT_CTRL(i), 0x0);
 		DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(i), tx_dctrl[i]);
 	}
+}
 
-	/* Toggle BIT 0 to release freeze I/0 */
-	DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(3), 0x05);
-	DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(3), 0x04);
+void dsi_phy_hw_v3_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable)
+{
+	u32 reg;
+
+	pr_debug("enable=%s\n", enable ? "true" : "false");
+
+	/*
+	 * DSI PHY lane clamps, also referred to as PHY FreezeIO is
+	 * enalbed by default as part of the initialization sequnce.
+	 * This would get triggered anytime the chip FreezeIO is asserted.
+	 */
+	if (enable)
+		return;
+
+	/*
+	 * Toggle BIT 0 to exlplictly release PHY freeze I/0 to disable
+	 * the clamps.
+	 */
+	reg = DSI_R32(phy, DSIPHY_LNX_TX_DCTRL(3));
+	DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(3), reg | BIT(0));
+	wmb(); /* Ensure that the freezeio bit is toggled */
+	DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(3), reg & ~BIT(0));
+	wmb(); /* Ensure that the freezeio bit is toggled */
 }
 
 /**
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 19df8be..0697db8 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -947,6 +947,14 @@
 	struct msm_kms *kms = priv->kms;
 	int i;
 
+	/* check for splash status before triggering cleanup
+	 * if we end up here with splash status ON i.e before first
+	 * commit then ignore the last close call
+	 */
+	if (kms && kms->funcs && kms->funcs->check_for_splash
+		&& kms->funcs->check_for_splash(kms))
+		return;
+
 	/*
 	 * clean up vblank disable immediately as this is the last close.
 	 */
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index ce4197b..fcdddb3 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -155,6 +155,7 @@
 	CRTC_PROP_SECURITY_LEVEL,
 	CRTC_PROP_IDLE_TIMEOUT,
 	CRTC_PROP_DEST_SCALER,
+	CRTC_PROP_CAPTURE_OUTPUT,
 
 	CRTC_PROP_ENABLE_SUI_ENHANCEMENT,
 
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index db9e7ee..e99ff9c 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
@@ -106,6 +106,8 @@
 			unsigned int domain);
 	/* handle continuous splash  */
 	int (*cont_splash_config)(struct msm_kms *kms);
+	/* check for continuous splash status */
+	bool (*check_for_splash)(struct msm_kms *kms);
 };
 
 struct msm_kms {
diff --git a/drivers/gpu/drm/msm/sde/sde_ad4.h b/drivers/gpu/drm/msm/sde/sde_ad4.h
index bf08360..b254d7d 100644
--- a/drivers/gpu/drm/msm/sde/sde_ad4.h
+++ b/drivers/gpu/drm/msm/sde/sde_ad4.h
@@ -52,6 +52,7 @@
 	AD_IPC_SUSPEND,
 	AD_IPC_RESUME,
 	AD_IPC_RESET,
+	AD_VSYNC_UPDATE,
 	AD_PROPMAX,
 };
 
diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.c b/drivers/gpu/drm/msm/sde/sde_color_processing.c
index 0f55b19..47ff024 100644
--- a/drivers/gpu/drm/msm/sde/sde_color_processing.c
+++ b/drivers/gpu/drm/msm/sde/sde_color_processing.c
@@ -88,6 +88,7 @@
 		enum ad_property ad_prop);
 
 static void sde_cp_notify_hist_event(struct drm_crtc *crtc_drm, void *arg);
+static void sde_cp_update_ad_vsync_prop(struct sde_crtc *sde_crtc, u32 val);
 
 #define setup_dspp_prop_install_funcs(func) \
 do { \
@@ -138,6 +139,7 @@
 	SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS,
 	SDE_CP_CRTC_DSPP_AD_BACKLIGHT,
 	SDE_CP_CRTC_DSPP_AD_STRENGTH,
+	SDE_CP_CRTC_DSPP_AD_VSYNC_COUNT,
 	SDE_CP_CRTC_DSPP_MAX,
 	/* DSPP features end */
 
@@ -407,6 +409,7 @@
 	if (IS_ERR(sde_crtc->hist_blob))
 		sde_crtc->hist_blob = NULL;
 
+	sde_crtc->ad_vsync_count = 0;
 	mutex_init(&sde_crtc->crtc_cp_lock);
 	INIT_LIST_HEAD(&sde_crtc->active_list);
 	INIT_LIST_HEAD(&sde_crtc->dirty_list);
@@ -789,6 +792,9 @@
 			ad_cfg.prop = AD_MODE;
 			ad_cfg.hw_cfg = &hw_cfg;
 			hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
+			sde_crtc->ad_vsync_count = 0;
+			sde_cp_update_ad_vsync_prop(sde_crtc,
+					sde_crtc->ad_vsync_count);
 			break;
 		case SDE_CP_CRTC_DSPP_AD_INIT:
 			if (!hw_dspp || !hw_dspp->ops.setup_ad) {
@@ -798,6 +804,9 @@
 			ad_cfg.prop = AD_INIT;
 			ad_cfg.hw_cfg = &hw_cfg;
 			hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
+			sde_crtc->ad_vsync_count = 0;
+			sde_cp_update_ad_vsync_prop(sde_crtc,
+					sde_crtc->ad_vsync_count);
 			break;
 		case SDE_CP_CRTC_DSPP_AD_CFG:
 			if (!hw_dspp || !hw_dspp->ops.setup_ad) {
@@ -807,6 +816,9 @@
 			ad_cfg.prop = AD_CFG;
 			ad_cfg.hw_cfg = &hw_cfg;
 			hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
+			sde_crtc->ad_vsync_count = 0;
+			sde_cp_update_ad_vsync_prop(sde_crtc,
+					sde_crtc->ad_vsync_count);
 			break;
 		case SDE_CP_CRTC_DSPP_AD_INPUT:
 			if (!hw_dspp || !hw_dspp->ops.setup_ad) {
@@ -816,6 +828,9 @@
 			ad_cfg.prop = AD_INPUT;
 			ad_cfg.hw_cfg = &hw_cfg;
 			hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
+			sde_crtc->ad_vsync_count = 0;
+			sde_cp_update_ad_vsync_prop(sde_crtc,
+					sde_crtc->ad_vsync_count);
 			break;
 		case SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS:
 			if (!hw_dspp || !hw_dspp->ops.setup_ad) {
@@ -825,6 +840,9 @@
 			ad_cfg.prop = AD_ASSERTIVE;
 			ad_cfg.hw_cfg = &hw_cfg;
 			hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
+			sde_crtc->ad_vsync_count = 0;
+			sde_cp_update_ad_vsync_prop(sde_crtc,
+					sde_crtc->ad_vsync_count);
 			break;
 		case SDE_CP_CRTC_DSPP_AD_BACKLIGHT:
 			if (!hw_dspp || !hw_dspp->ops.setup_ad) {
@@ -834,6 +852,9 @@
 			ad_cfg.prop = AD_BACKLIGHT;
 			ad_cfg.hw_cfg = &hw_cfg;
 			hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
+			sde_crtc->ad_vsync_count = 0;
+			sde_cp_update_ad_vsync_prop(sde_crtc,
+					sde_crtc->ad_vsync_count);
 			break;
 		case SDE_CP_CRTC_DSPP_AD_STRENGTH:
 			if (!hw_dspp || !hw_dspp->ops.setup_ad) {
@@ -843,6 +864,9 @@
 			ad_cfg.prop = AD_STRENGTH;
 			ad_cfg.hw_cfg = &hw_cfg;
 			hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
+			sde_crtc->ad_vsync_count = 0;
+			sde_cp_update_ad_vsync_prop(sde_crtc,
+					sde_crtc->ad_vsync_count);
 			break;
 		default:
 			ret = -EINVAL;
@@ -924,10 +948,15 @@
 			DRM_DEBUG_DRIVER("Dirty list is empty\n");
 			goto exit;
 		}
-		sde_cp_ad_set_prop(sde_crtc, AD_IPC_RESET);
 		set_dspp_flush = true;
 	}
 
+	if (!list_empty(&sde_crtc->ad_active)) {
+		sde_cp_ad_set_prop(sde_crtc, AD_IPC_RESET);
+		sde_cp_ad_set_prop(sde_crtc, AD_VSYNC_UPDATE);
+		sde_cp_update_ad_vsync_prop(sde_crtc, sde_crtc->ad_vsync_count);
+	}
+
 	list_for_each_entry_safe(prop_node, n, &sde_crtc->dirty_list,
 				dirty_list) {
 		sde_dspp_feature = crtc_feature_map[prop_node->feature];
@@ -1449,6 +1478,9 @@
 				"SDE_DSPP_AD_V4_BACKLIGHT",
 			SDE_CP_CRTC_DSPP_AD_BACKLIGHT, 0, (BIT(16) - 1),
 			0);
+		sde_cp_crtc_install_range_property(crtc,
+			"SDE_DSPP_AD_V4_VSYNC_COUNT",
+			SDE_CP_CRTC_DSPP_AD_VSYNC_COUNT, 0, U32_MAX, 0);
 		break;
 	default:
 		DRM_ERROR("version %d not supported\n", version);
@@ -1867,6 +1899,11 @@
 		hw_cfg.displayh = num_mixers * hw_lm->cfg.out_width;
 		hw_cfg.displayv = hw_lm->cfg.out_height;
 		hw_cfg.mixer_info = hw_lm;
+
+		if (ad_prop == AD_VSYNC_UPDATE) {
+			hw_cfg.payload = &sde_crtc->ad_vsync_count;
+			hw_cfg.len = sizeof(sde_crtc->ad_vsync_count);
+		}
 		ad_cfg.prop = ad_prop;
 		ad_cfg.hw_cfg = &hw_cfg;
 		ret = hw_dspp->ops.validate_ad(hw_dspp, (u32 *)&ad_prop);
@@ -2118,3 +2155,35 @@
 exit:
 	return ret;
 }
+
+void sde_cp_update_ad_vsync_count(struct drm_crtc *crtc, u32 val)
+{
+	struct sde_crtc *sde_crtc;
+
+	if (!crtc) {
+		DRM_ERROR("invalid crtc %pK\n", crtc);
+		return;
+	}
+
+	sde_crtc = to_sde_crtc(crtc);
+	if (!sde_crtc) {
+		DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
+		return;
+	}
+
+	sde_crtc->ad_vsync_count = val;
+	sde_cp_update_ad_vsync_prop(sde_crtc, val);
+}
+
+static void sde_cp_update_ad_vsync_prop(struct sde_crtc *sde_crtc, u32 val)
+{
+	struct sde_cp_node *prop_node = NULL;
+
+	list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
+		if (prop_node->feature == SDE_CP_CRTC_DSPP_AD_VSYNC_COUNT) {
+			prop_node->prop_val = val;
+			pr_debug("AD vsync count updated to %d\n", val);
+			return;
+		}
+	}
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.h b/drivers/gpu/drm/msm/sde/sde_color_processing.h
index 7eb1738..620db26 100644
--- a/drivers/gpu/drm/msm/sde/sde_color_processing.h
+++ b/drivers/gpu/drm/msm/sde/sde_color_processing.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -146,4 +146,11 @@
  */
 int sde_cp_hist_interrupt(struct drm_crtc *crtc_drm, bool en,
 	struct sde_irq_callback *hist_irq);
+
+/**
+ * sde_cp_update_ad_vsync_count: Api to update AD vsync count
+ * @crtc: Pointer to crtc.
+ * @val: vsync count value
+ */
+void sde_cp_update_ad_vsync_count(struct drm_crtc *crtc, u32 val);
 #endif /*_SDE_COLOR_PROCESSING_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index d2f8d12..07d1ad7 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -623,6 +623,7 @@
 void sde_connector_helper_bridge_disable(struct drm_connector *connector)
 {
 	int rc;
+	struct sde_connector *c_conn = NULL;
 
 	if (!connector)
 		return;
@@ -633,6 +634,34 @@
 				connector->base.id, rc);
 		SDE_EVT32(connector->base.id, SDE_EVTLOG_ERROR);
 	}
+
+	/* Disable ESD thread */
+	sde_connector_schedule_status_work(connector, false);
+
+	c_conn = to_sde_connector(connector);
+	if (c_conn->panel_dead) {
+		c_conn->bl_device->props.power = FB_BLANK_POWERDOWN;
+		c_conn->bl_device->props.state |= BL_CORE_FBBLANK;
+		backlight_update_status(c_conn->bl_device);
+	}
+}
+
+void sde_connector_helper_bridge_enable(struct drm_connector *connector)
+{
+	struct sde_connector *c_conn = NULL;
+
+	if (!connector)
+		return;
+
+	c_conn = to_sde_connector(connector);
+
+	/* Special handling for ESD recovery case */
+	if (c_conn->panel_dead) {
+		c_conn->bl_device->props.power = FB_BLANK_UNBLANK;
+		c_conn->bl_device->props.state &= ~BL_CORE_FBBLANK;
+		backlight_update_status(c_conn->bl_device);
+		c_conn->panel_dead = false;
+	}
 }
 
 int sde_connector_clk_ctrl(struct drm_connector *connector, bool enable)
@@ -1207,7 +1236,7 @@
 }
 
 void sde_connector_complete_commit(struct drm_connector *connector,
-		ktime_t ts)
+		ktime_t ts, enum sde_fence_event fence_event)
 {
 	if (!connector) {
 		SDE_ERROR("invalid connector\n");
@@ -1215,7 +1244,8 @@
 	}
 
 	/* signal connector's retire fence */
-	sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, false);
+	sde_fence_signal(&to_sde_connector(connector)->retire_fence,
+			ts, fence_event);
 }
 
 void sde_connector_commit_reset(struct drm_connector *connector, ktime_t ts)
@@ -1226,7 +1256,8 @@
 	}
 
 	/* signal connector's retire fence */
-	sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, true);
+	sde_fence_signal(&to_sde_connector(connector)->retire_fence,
+			ts, SDE_FENCE_RESET_TIMELINE);
 }
 
 static void sde_connector_update_hdr_props(struct drm_connector *connector)
@@ -1734,15 +1765,15 @@
 static void _sde_connector_report_panel_dead(struct sde_connector *conn)
 {
 	struct drm_event event;
-	bool panel_dead = true;
 
 	if (!conn)
 		return;
 
+	conn->panel_dead = true;
 	event.type = DRM_EVENT_PANEL_DEAD;
 	event.length = sizeof(bool);
 	msm_mode_object_event_notify(&conn->base.base,
-		conn->base.dev, &event, (u8 *)&panel_dead);
+		conn->base.dev, &event, (u8 *)&conn->panel_dead);
 	sde_encoder_display_failure_notification(conn->encoder);
 	SDE_EVT32(SDE_EVTLOG_ERROR);
 	SDE_ERROR("esd check failed report PANEL_DEAD conn_id: %d enc_id: %d\n",
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index c6f348e..51dc92d 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -324,6 +324,8 @@
  * @status_work: work object to perform status checks
  * @force_panel_dead: variable to trigger forced ESD recovery
  * @esd_status_interval: variable to change ESD check interval in millisec
+ * @panel_dead: Flag to indicate if panel has gone bad
+ * @esd_status_check: Flag to indicate if ESD thread is scheduled or not
  * @bl_scale_dirty: Flag to indicate PP BL scale value(s) is changed
  * @bl_scale: BL scale value for ABA feature
  * @bl_scale_ad: BL scale value for AD feature
@@ -365,7 +367,7 @@
 	struct delayed_work status_work;
 	u32 force_panel_dead;
 	u32 esd_status_interval;
-
+	bool panel_dead;
 	bool esd_status_check;
 
 	bool bl_scale_dirty;
@@ -583,8 +585,10 @@
  * sde_connector_complete_commit - signal completion of current commit
  * @connector: Pointer to drm connector object
  * @ts: timestamp to be updated in the fence signalling
+ * @fence_event: enum value to indicate nature of fence event
  */
-void sde_connector_complete_commit(struct drm_connector *connector, ktime_t ts);
+void sde_connector_complete_commit(struct drm_connector *connector,
+		ktime_t ts, enum sde_fence_event fence_event);
 
 /**
  * sde_connector_commit_reset - reset the completion signal
@@ -763,6 +767,12 @@
 void sde_connector_helper_bridge_disable(struct drm_connector *connector);
 
 /**
+ * sde_connector_helper_bridge_enable - helper function for drm bridge enable
+ * @connector: Pointer to DRM connector object
+ */
+void sde_connector_helper_bridge_enable(struct drm_connector *connector);
+
+/**
  * sde_connector_get_panel_vfp - helper to get panel vfp
  * @connector: pointer to drm connector
  * @h_active: panel width
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 7daab2a..cefa513 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -936,7 +936,9 @@
 	struct sde_crtc *sde_crtc;
 	struct sde_crtc_state *crtc_state;
 	struct sde_rect *crtc_roi;
-	int i, num_attached_conns = 0;
+	struct msm_mode_info mode_info;
+	int i = 0;
+	int rc;
 	bool is_crtc_roi_dirty;
 	bool is_any_conn_roi_dirty;
 
@@ -958,13 +960,14 @@
 		if (!conn_state || conn_state->crtc != crtc)
 			continue;
 
-		if (num_attached_conns) {
-			SDE_ERROR(
-				"crtc%d: unsupported: roi on crtc w/ >1 connectors\n",
-					DRMID(crtc));
+		rc = sde_connector_get_mode_info(conn_state, &mode_info);
+		if (rc) {
+			SDE_ERROR("failed to get mode info\n");
 			return -EINVAL;
 		}
-		++num_attached_conns;
+
+		if (!mode_info.roi_caps.enabled)
+			continue;
 
 		sde_conn = to_sde_connector(conn_state->connector);
 		sde_conn_state = to_sde_connector_state(conn_state);
@@ -1285,13 +1288,6 @@
 	sde_crtc = to_sde_crtc(crtc);
 	sde_crtc_state = to_sde_crtc_state(state);
 
-	if (hweight_long(state->connector_mask) != 1) {
-		SDE_ERROR("invalid connector count(%d) for crtc: %d\n",
-			(int)hweight_long(state->connector_mask),
-			crtc->base.id);
-		return -EINVAL;
-	}
-
 	/*
 	 * check connector array cached at modeset time since incoming atomic
 	 * state may not include any connectors if they aren't modified
@@ -1307,42 +1303,41 @@
 			SDE_ERROR("failed to get mode info\n");
 			return -EINVAL;
 		}
-		break;
-	}
 
-	if (!mode_info.roi_caps.enabled)
-		return 0;
+		if (!mode_info.roi_caps.enabled)
+			continue;
 
-	if (sde_crtc_state->user_roi_list.num_rects >
-					mode_info.roi_caps.num_roi) {
-		SDE_ERROR("roi count is more than supported limit, %d > %d\n",
-				sde_crtc_state->user_roi_list.num_rects,
-				mode_info.roi_caps.num_roi);
-		return -E2BIG;
-	}
+		if (sde_crtc_state->user_roi_list.num_rects >
+				mode_info.roi_caps.num_roi) {
+			SDE_ERROR("roi count is exceeding limit, %d > %d\n",
+					sde_crtc_state->user_roi_list.num_rects,
+					mode_info.roi_caps.num_roi);
+			return -E2BIG;
+		}
 
-	rc = _sde_crtc_set_crtc_roi(crtc, state);
-	if (rc)
-		return rc;
+		rc = _sde_crtc_set_crtc_roi(crtc, state);
+		if (rc)
+			return rc;
 
-	rc = _sde_crtc_check_autorefresh(crtc, state);
-	if (rc)
-		return rc;
+		rc = _sde_crtc_check_autorefresh(crtc, state);
+		if (rc)
+			return rc;
 
-	for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
-		rc = _sde_crtc_set_lm_roi(crtc, state, lm_idx);
+		for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
+			rc = _sde_crtc_set_lm_roi(crtc, state, lm_idx);
+			if (rc)
+				return rc;
+		}
+
+		rc = _sde_crtc_check_rois_centered_and_symmetric(crtc, state);
+		if (rc)
+			return rc;
+
+		rc = _sde_crtc_check_planes_within_crtc_roi(crtc, state);
 		if (rc)
 			return rc;
 	}
 
-	rc = _sde_crtc_check_rois_centered_and_symmetric(crtc, state);
-	if (rc)
-		return rc;
-
-	rc = _sde_crtc_check_planes_within_crtc_roi(crtc, state);
-	if (rc)
-		return rc;
-
 	return 0;
 }
 
@@ -2116,15 +2111,62 @@
 	}
 }
 
+static void sde_crtc_frame_event_cb(void *data, u32 event)
+{
+	struct drm_crtc *crtc = (struct drm_crtc *)data;
+	struct sde_crtc *sde_crtc;
+	struct msm_drm_private *priv;
+	struct sde_crtc_frame_event *fevent;
+	struct sde_crtc_frame_event_cb_data *cb_data;
+	unsigned long flags;
+	u32 crtc_id;
+
+	cb_data = (struct sde_crtc_frame_event_cb_data *)data;
+	if (!data) {
+		SDE_ERROR("invalid parameters\n");
+		return;
+	}
+
+	crtc = cb_data->crtc;
+	if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
+		SDE_ERROR("invalid parameters\n");
+		return;
+	}
+	sde_crtc = to_sde_crtc(crtc);
+	priv = crtc->dev->dev_private;
+	crtc_id = drm_crtc_index(crtc);
+
+	SDE_DEBUG("crtc%d\n", crtc->base.id);
+	SDE_EVT32_VERBOSE(DRMID(crtc), event);
+
+	spin_lock_irqsave(&sde_crtc->spin_lock, flags);
+	fevent = list_first_entry_or_null(&sde_crtc->frame_event_list,
+			struct sde_crtc_frame_event, list);
+	if (fevent)
+		list_del_init(&fevent->list);
+	spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
+
+	if (!fevent) {
+		SDE_ERROR("crtc%d event %d overflow\n",
+				crtc->base.id, event);
+		SDE_EVT32(DRMID(crtc), event);
+		return;
+	}
+
+	fevent->event = event;
+	fevent->crtc = crtc;
+	fevent->connector = cb_data->connector;
+	fevent->ts = ktime_get();
+	kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work);
+}
+
 void sde_crtc_prepare_commit(struct drm_crtc *crtc,
 		struct drm_crtc_state *old_state)
 {
 	struct sde_crtc *sde_crtc;
 	struct sde_crtc_state *cstate;
 	struct drm_connector *conn;
-	struct sde_crtc_retire_event *retire_event = NULL;
-	unsigned long flags;
-	int i;
+	struct drm_encoder *encoder;
 
 	if (!crtc || !crtc->state) {
 		SDE_ERROR("invalid crtc\n");
@@ -2141,31 +2183,17 @@
 	drm_for_each_connector(conn, crtc->dev)
 		if (conn->state && conn->state->crtc == crtc &&
 				cstate->num_connectors < MAX_CONNECTORS) {
+			encoder = conn->state->best_encoder;
+			if (encoder)
+				sde_encoder_register_frame_event_callback(
+						encoder,
+						sde_crtc_frame_event_cb,
+						crtc);
+
 			cstate->connectors[cstate->num_connectors++] = conn;
 			sde_connector_prepare_fence(conn);
 		}
 
-	for (i = 0; i < SDE_CRTC_FRAME_EVENT_SIZE; i++) {
-		retire_event = &sde_crtc->retire_events[i];
-		if (list_empty(&retire_event->list))
-			break;
-		retire_event = NULL;
-	}
-
-	if (retire_event) {
-		retire_event->num_connectors = cstate->num_connectors;
-		for (i = 0; i < cstate->num_connectors; i++)
-			retire_event->connectors[i] = cstate->connectors[i];
-
-		spin_lock_irqsave(&sde_crtc->spin_lock, flags);
-		list_add_tail(&retire_event->list,
-						&sde_crtc->retire_event_list);
-		spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
-	} else {
-		SDE_ERROR("crtc%d retire event overflow\n", crtc->base.id);
-		SDE_EVT32(DRMID(crtc), SDE_EVTLOG_ERROR);
-	}
-
 	/* prepare main output fence */
 	sde_fence_prepare(&sde_crtc->output_fence);
 }
@@ -2216,9 +2244,16 @@
 		return INTF_MODE_NONE;
 	}
 
-	drm_for_each_encoder(encoder, crtc->dev)
-		if (encoder->crtc == crtc)
-			return sde_encoder_get_intf_mode(encoder);
+	drm_for_each_encoder(encoder, crtc->dev) {
+		if (encoder->crtc != crtc)
+			continue;
+
+		/* continue if copy encoder is encountered */
+		if (sde_encoder_in_clone_mode(encoder))
+			continue;
+
+		return sde_encoder_get_intf_mode(encoder);
+	}
 
 	return INTF_MODE_NONE;
 }
@@ -2243,38 +2278,16 @@
 	SDE_EVT32_VERBOSE(DRMID(crtc));
 }
 
-static void _sde_crtc_retire_event(struct drm_crtc *crtc, ktime_t ts)
+static void _sde_crtc_retire_event(struct drm_connector *connector,
+		ktime_t ts, bool is_error)
 {
-	struct sde_crtc_retire_event *retire_event;
-	struct sde_crtc *sde_crtc;
-	unsigned long flags;
-	int i;
-
-	if (!crtc) {
+	if (!connector) {
 		SDE_ERROR("invalid param\n");
 		return;
 	}
 
-	sde_crtc = to_sde_crtc(crtc);
-	spin_lock_irqsave(&sde_crtc->spin_lock, flags);
-	retire_event = list_first_entry_or_null(&sde_crtc->retire_event_list,
-				struct sde_crtc_retire_event, list);
-	if (retire_event)
-		list_del_init(&retire_event->list);
-	spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
-
-	if (!retire_event) {
-		SDE_ERROR("crtc%d retire event without kickoff\n",
-								crtc->base.id);
-		SDE_EVT32(DRMID(crtc), SDE_EVTLOG_ERROR);
-		return;
-	}
-
 	SDE_ATRACE_BEGIN("signal_retire_fence");
-	for (i = 0; (i < retire_event->num_connectors) &&
-					retire_event->connectors[i]; ++i)
-		sde_connector_complete_commit(
-					retire_event->connectors[i], ts);
+	sde_connector_complete_commit(connector, ts, is_error);
 	SDE_ATRACE_END("signal_retire_fence");
 }
 
@@ -2287,6 +2300,7 @@
 	struct sde_kms *sde_kms;
 	unsigned long flags;
 	bool frame_done = false;
+	bool in_clone_mode = false;
 
 	if (!work) {
 		SDE_ERROR("invalid work handle\n");
@@ -2315,10 +2329,11 @@
 
 	SDE_EVT32_VERBOSE(DRMID(crtc), fevent->event, SDE_EVTLOG_FUNC_ENTRY);
 
-	if (fevent->event & (SDE_ENCODER_FRAME_EVENT_DONE
-				| SDE_ENCODER_FRAME_EVENT_ERROR
-				| SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)) {
+	in_clone_mode = sde_encoder_in_clone_mode(fevent->connector->encoder);
 
+	if (!in_clone_mode && (fevent->event & (SDE_ENCODER_FRAME_EVENT_ERROR
+					| SDE_ENCODER_FRAME_EVENT_PANEL_DEAD
+					| SDE_ENCODER_FRAME_EVENT_DONE))) {
 		if (atomic_read(&sde_crtc->frame_pending) < 1) {
 			/* this should not happen */
 			SDE_ERROR("crtc%d ts:%lld invalid frame_pending:%d\n",
@@ -2347,13 +2362,17 @@
 
 	if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE) {
 		SDE_ATRACE_BEGIN("signal_release_fence");
-		sde_fence_signal(&sde_crtc->output_fence, fevent->ts, false);
+		sde_fence_signal(&sde_crtc->output_fence, fevent->ts,
+				(fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR)
+				? SDE_FENCE_SIGNAL_ERROR : SDE_FENCE_SIGNAL);
 		SDE_ATRACE_END("signal_release_fence");
 	}
 
 	if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE)
 		/* this api should be called without spin_lock */
-		_sde_crtc_retire_event(crtc, fevent->ts);
+		_sde_crtc_retire_event(fevent->connector, fevent->ts,
+				(fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR)
+				? SDE_FENCE_SIGNAL_ERROR : SDE_FENCE_SIGNAL);
 
 	if (fevent->event & SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)
 		SDE_ERROR("crtc%d ts:%lld received panel dead event\n",
@@ -2368,46 +2387,6 @@
 	SDE_ATRACE_END("crtc_frame_event");
 }
 
-static void sde_crtc_frame_event_cb(void *data, u32 event)
-{
-	struct drm_crtc *crtc = (struct drm_crtc *)data;
-	struct sde_crtc *sde_crtc;
-	struct msm_drm_private *priv;
-	struct sde_crtc_frame_event *fevent;
-	unsigned long flags;
-	u32 crtc_id;
-
-	if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
-		SDE_ERROR("invalid parameters\n");
-		return;
-	}
-	sde_crtc = to_sde_crtc(crtc);
-	priv = crtc->dev->dev_private;
-	crtc_id = drm_crtc_index(crtc);
-
-	SDE_DEBUG("crtc%d\n", crtc->base.id);
-	SDE_EVT32_VERBOSE(DRMID(crtc), event);
-
-	spin_lock_irqsave(&sde_crtc->spin_lock, flags);
-	fevent = list_first_entry_or_null(&sde_crtc->frame_event_list,
-			struct sde_crtc_frame_event, list);
-	if (fevent)
-		list_del_init(&fevent->list);
-	spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
-
-	if (!fevent) {
-		SDE_ERROR("crtc%d event %d overflow\n",
-				crtc->base.id, event);
-		SDE_EVT32(DRMID(crtc), event);
-		return;
-	}
-
-	fevent->event = event;
-	fevent->crtc = crtc;
-	fevent->ts = ktime_get();
-	kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work);
-}
-
 void sde_crtc_complete_commit(struct drm_crtc *crtc,
 		struct drm_crtc_state *old_state)
 {
@@ -2440,6 +2419,23 @@
 }
 
 /**
+ * _sde_crtc_clear_dim_layers_v1 - clear all dim layer settings
+ * @cstate:      Pointer to sde crtc state
+ */
+static void _sde_crtc_clear_dim_layers_v1(struct sde_crtc_state *cstate)
+{
+	u32 i;
+
+	if (!cstate)
+		return;
+
+	for (i = 0; i < cstate->num_dim_layers; i++)
+		memset(&cstate->dim_layer[i], 0, sizeof(cstate->dim_layer[i]));
+
+	cstate->num_dim_layers = 0;
+}
+
+/**
  * _sde_crtc_set_dim_layer_v1 - copy dim layer settings from userspace
  * @cstate:      Pointer to sde crtc state
  * @user_ptr:    User ptr for sde_drm_dim_layer_v1 struct
@@ -2459,6 +2455,8 @@
 	dim_layer = cstate->dim_layer;
 
 	if (!usr_ptr) {
+		/* usr_ptr is null when setting the default property value */
+		_sde_crtc_clear_dim_layers_v1(cstate);
 		SDE_DEBUG("dim_layer data removed\n");
 		return;
 	}
@@ -2958,6 +2956,10 @@
 		if (enc->crtc != crtc)
 			continue;
 
+		/* avoid overwriting mixers info from a copy encoder */
+		if (sde_encoder_in_clone_mode(enc))
+			continue;
+
 		_sde_crtc_setup_mixer_for_encoder(crtc, enc);
 	}
 
@@ -4125,6 +4127,7 @@
 	event.type = DRM_EVENT_CRTC_POWER;
 	event.length = sizeof(u32);
 	sde_cp_crtc_suspend(crtc);
+	sde_cp_update_ad_vsync_count(crtc, 0);
 	power_on = 0;
 	msm_mode_object_event_notify(&crtc->base, crtc->dev, &event,
 			(u8 *)&power_on);
@@ -4191,7 +4194,8 @@
 	 * reset the fence timeline if crtc will not be enabled for this commit
 	 */
 	if (!crtc->state->active || !crtc->state->enable) {
-		sde_fence_signal(&sde_crtc->output_fence, ktime_get(), true);
+		sde_fence_signal(&sde_crtc->output_fence,
+				ktime_get(), SDE_FENCE_RESET_TIMELINE);
 		for (i = 0; i < cstate->num_connectors; ++i)
 			sde_connector_commit_reset(cstate->connectors[i],
 					ktime_get());
@@ -4256,7 +4260,7 @@
 		if (encoder->crtc != crtc)
 			continue;
 		sde_encoder_register_frame_event_callback(encoder,
-				sde_crtc_frame_event_cb, (void *)crtc);
+				sde_crtc_frame_event_cb, crtc);
 	}
 
 	if (!sde_crtc->enabled && !sde_crtc->suspend &&
@@ -4915,6 +4919,11 @@
 		{SDE_DRM_SEC_ONLY, "sec_only"},
 	};
 
+	static const struct drm_prop_enum_list e_cwb_data_points[] = {
+		{CAPTURE_MIXER_OUT, "capture_mixer_out"},
+		{CAPTURE_DSPP_OUT, "capture_pp_out"},
+	};
+
 	SDE_DEBUG("\n");
 
 	if (!crtc || !catalog) {
@@ -4994,6 +5003,12 @@
 		"enable_sui_enhancement", 0, 0, U64_MAX, 0,
 		CRTC_PROP_ENABLE_SUI_ENHANCEMENT);
 
+	if (catalog->has_cwb_support)
+		msm_property_install_enum(&sde_crtc->property_info,
+				"capture_mode", 0, 0, e_cwb_data_points,
+				ARRAY_SIZE(e_cwb_data_points),
+				CRTC_PROP_CAPTURE_OUTPUT);
+
 	msm_property_install_blob(&sde_crtc->property_info, "capabilities",
 		DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO);
 
@@ -5867,10 +5882,6 @@
 		list_add_tail(&sde_crtc->event_cache[i].list,
 				&sde_crtc->event_free_list);
 
-	INIT_LIST_HEAD(&sde_crtc->retire_event_list);
-	for (i = 0; i < ARRAY_SIZE(sde_crtc->retire_events); i++)
-		INIT_LIST_HEAD(&sde_crtc->retire_events[i].list);
-
 	return rc;
 }
 
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 64f3821..53b8df9 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -31,7 +31,8 @@
 #define SDE_CRTC_NAME_SIZE	12
 
 /* define the maximum number of in-flight frame events */
-#define SDE_CRTC_FRAME_EVENT_SIZE	4
+/* Expand it to 2x for handling atleast 2 connectors safely */
+#define SDE_CRTC_FRAME_EVENT_SIZE	(4 * 2)
 
 /**
  * enum sde_crtc_client_type: crtc client type
@@ -48,6 +49,16 @@
 };
 
 /**
+ * enum sde_crtc_output_capture_point
+ * @MIXER_OUT : capture mixer output
+ * @DSPP_OUT : capture output of dspp
+ */
+enum sde_crtc_output_capture_point {
+	CAPTURE_MIXER_OUT,
+	CAPTURE_DSPP_OUT
+};
+
+/**
  * @connectors    : Currently associated drm connectors for retire event
  * @num_connectors: Number of associated drm connectors for retire event
  * @list:	event list
@@ -81,9 +92,20 @@
 };
 
 /**
+ * struct sde_crtc_frame_event_cb_data : info of drm objects of a frame event
+ * @crtc:       pointer to drm crtc object registered for frame event
+ * @connector:  pointer to drm connector which is source of frame event
+ */
+struct sde_crtc_frame_event_cb_data {
+	 struct drm_crtc *crtc;
+	 struct drm_connector *connector;
+};
+
+/**
  * struct sde_crtc_frame_event: stores crtc frame event for crtc processing
  * @work:	base work structure
  * @crtc:	Pointer to crtc handling this event
+ * @connector:  pointer to drm connector which is source of frame event
  * @list:	event list
  * @ts:		timestamp at queue entry
  * @event:	event identifier
@@ -91,6 +113,7 @@
 struct sde_crtc_frame_event {
 	struct kthread_work work;
 	struct drm_crtc *crtc;
+	struct drm_connector *connector;
 	struct list_head list;
 	ktime_t ts;
 	u32 event;
@@ -155,13 +178,12 @@
  * @dirty_list    : list of color processing features are dirty
  * @ad_dirty: list containing ad properties that are dirty
  * @ad_active: list containing ad properties that are active
+ * @ad_vsync_count : count of vblank since last reset for AD
  * @crtc_lock     : crtc lock around create, destroy and access.
  * @frame_pending : Whether or not an update is pending
  * @frame_events  : static allocation of in-flight frame events
  * @frame_event_list : available frame event list
  * @spin_lock     : spin lock for frame event, transaction status, etc...
- * @retire_events  : static allocation of retire fence connector
- * @retire_event_list : available retire fence connector list
  * @frame_done_comp    : for frame_event_done synchronization
  * @event_thread  : Pointer to event handler thread
  * @event_worker  : Event worker queue
@@ -224,6 +246,7 @@
 	struct list_head ad_dirty;
 	struct list_head ad_active;
 	struct list_head user_event_list;
+	u32 ad_vsync_count;
 
 	struct mutex crtc_lock;
 	struct mutex crtc_cp_lock;
@@ -232,8 +255,6 @@
 	struct sde_crtc_frame_event frame_events[SDE_CRTC_FRAME_EVENT_SIZE];
 	struct list_head frame_event_list;
 	spinlock_t spin_lock;
-	struct sde_crtc_retire_event retire_events[SDE_CRTC_FRAME_EVENT_SIZE];
-	struct list_head retire_event_list;
 	struct completion frame_done_comp;
 
 	/* for handling internal event thread */
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index bea6693..2ce8b2e 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -80,6 +80,11 @@
 /* Maximum number of VSYNC wait attempts for RSC state transition */
 #define MAX_RSC_WAIT	5
 
+#define TOPOLOGY_DUALPIPE_MERGE_MODE(x) \
+		(((x) == SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE) || \
+		((x) == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE) || \
+		((x) == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC))
+
 /**
  * enum sde_enc_rc_events - events for resource control state machine
  * @SDE_ENC_RC_EVENT_KICKOFF:
@@ -215,6 +220,7 @@
 struct sde_encoder_virt {
 	struct drm_encoder base;
 	spinlock_t enc_spinlock;
+	struct mutex vblank_ctl_lock;
 	uint32_t bus_scaling_client;
 
 	uint32_t display_num_of_h_tiles;
@@ -234,7 +240,7 @@
 	struct mutex enc_lock;
 	DECLARE_BITMAP(frame_busy_mask, MAX_PHYS_ENCODERS_PER_VIRTUAL);
 	void (*crtc_frame_event_cb)(void *, u32 event);
-	void *crtc_frame_event_cb_data;
+	struct sde_crtc_frame_event_cb_data crtc_frame_event_cb_data;
 
 	struct timer_list vsync_event_timer;
 
@@ -416,6 +422,14 @@
 	return false;
 }
 
+int sde_encoder_in_clone_mode(struct drm_encoder *drm_enc)
+{
+	struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
+
+	return sde_enc && sde_enc->cur_master &&
+		sde_enc->cur_master->in_clone_mode;
+}
+
 static inline int _sde_encoder_power_enable(struct sde_encoder_virt *sde_enc,
 								bool enable)
 {
@@ -1586,11 +1600,16 @@
 	 * only primary command mode panel can request CMD state.
 	 * all other panels/displays can request for VID state including
 	 * secondary command mode panel.
+	 * Clone mode encoder can request CLK STATE only.
 	 */
-	rsc_state = enable ?
-		(((disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) &&
-		  disp_info->is_primary) ? SDE_RSC_CMD_STATE :
-		SDE_RSC_VID_STATE) : SDE_RSC_IDLE_STATE;
+	if (sde_encoder_in_clone_mode(drm_enc))
+		rsc_state = enable ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE;
+	else
+		rsc_state = enable ?
+			(((disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE)
+			  && disp_info->is_primary) ? SDE_RSC_CMD_STATE :
+			 SDE_RSC_VID_STATE) : SDE_RSC_IDLE_STATE;
+
 	prefill_lines = config ? mode_info.prefill_lines +
 		config->inline_rotate_prefill : mode_info.prefill_lines;
 
@@ -2301,10 +2320,17 @@
 			_sde_encoder_resource_control_rsc_update(drm_enc, true);
 			_sde_encoder_resource_control_helper(drm_enc, true);
 
+			/*
+			 * In some cases, commit comes with slight delay
+			 * (> 80 ms)after early wake up, prevent clock switch
+			 * off to avoid jank in next update. So, increase the
+			 * command mode idle timeout sufficiently to prevent
+			 * such case.
+			 */
 			kthread_mod_delayed_work(&disp_thread->worker,
-						&sde_enc->delayed_off_work,
-						msecs_to_jiffies(
-						IDLE_POWERCOLLAPSE_DURATION));
+					&sde_enc->delayed_off_work,
+					msecs_to_jiffies(
+					IDLE_POWERCOLLAPSE_IN_EARLY_WAKEUP));
 
 			sde_enc->rc_state = SDE_ENC_RC_STATE_ON;
 		}
@@ -2648,7 +2674,6 @@
 	struct sde_encoder_virt *sde_enc = NULL;
 	struct msm_drm_private *priv;
 	struct sde_kms *sde_kms;
-	struct drm_connector *drm_conn = NULL;
 	enum sde_intf_mode intf_mode;
 	int i = 0;
 
@@ -2677,10 +2702,6 @@
 
 	SDE_EVT32(DRMID(drm_enc));
 
-	/* Disable ESD thread */
-	drm_conn = sde_enc->cur_master->connector;
-	sde_connector_schedule_status_work(drm_conn, false);
-
 	/* wait for idle */
 	sde_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE);
 
@@ -2838,8 +2859,8 @@
 }
 
 void sde_encoder_register_frame_event_callback(struct drm_encoder *drm_enc,
-		void (*frame_event_cb)(void *, u32 event),
-		void *frame_event_cb_data)
+			void (*frame_event_cb)(void *, u32 event),
+			struct drm_crtc *crtc)
 {
 	struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
 	unsigned long lock_flags;
@@ -2856,7 +2877,7 @@
 
 	spin_lock_irqsave(&sde_enc->enc_spinlock, lock_flags);
 	sde_enc->crtc_frame_event_cb = frame_event_cb;
-	sde_enc->crtc_frame_event_cb_data = frame_event_cb_data;
+	sde_enc->crtc_frame_event_cb_data.crtc = crtc;
 	spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags);
 }
 
@@ -2867,6 +2888,9 @@
 	struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
 	unsigned int i;
 
+	sde_enc->crtc_frame_event_cb_data.connector =
+				sde_enc->cur_master->connector;
+
 	if (event & (SDE_ENCODER_FRAME_EVENT_DONE
 			| SDE_ENCODER_FRAME_EVENT_ERROR
 			| SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)) {
@@ -2895,13 +2919,13 @@
 
 			if (sde_enc->crtc_frame_event_cb)
 				sde_enc->crtc_frame_event_cb(
-					sde_enc->crtc_frame_event_cb_data,
+					&sde_enc->crtc_frame_event_cb_data,
 					event);
 		}
 	} else {
 		if (sde_enc->crtc_frame_event_cb)
 			sde_enc->crtc_frame_event_cb(
-				sde_enc->crtc_frame_event_cb_data, event);
+				&sde_enc->crtc_frame_event_cb_data, event);
 	}
 }
 
@@ -3010,6 +3034,10 @@
 		return;
 	}
 
+	/* avoid ctrl start for encoder in clone mode */
+	if (phys->in_clone_mode)
+		return;
+
 	ctl = phys->hw_ctl;
 	if (phys->split_role == ENC_ROLE_SKIP) {
 		SDE_DEBUG_ENC(to_sde_encoder_virt(phys->parent),
@@ -3402,13 +3430,14 @@
 static void _sde_encoder_setup_dither(struct sde_encoder_phys *phys)
 {
 	void *dither_cfg;
-	int ret = 0, rc;
+	int ret = 0, rc, i = 0;
 	size_t len = 0;
 	enum sde_rm_topology_name topology;
 	struct drm_encoder *drm_enc;
 	struct msm_mode_info mode_info;
 	struct msm_display_dsc_info *dsc = NULL;
 	struct sde_encoder_virt *sde_enc;
+	struct sde_hw_pingpong *hw_pp;
 
 	if (!phys || !phys->connector || !phys->hw_pp ||
 			!phys->hw_pp->ops.setup_dither || !phys->parent)
@@ -3431,12 +3460,24 @@
 	/* disable dither for 10 bpp or 10bpc dsc config */
 	if (dsc->bpp == 10 || dsc->bpc == 10) {
 		phys->hw_pp->ops.setup_dither(phys->hw_pp, NULL, 0);
+		return;
+	}
+
+	ret = sde_connector_get_dither_cfg(phys->connector,
+			phys->connector->state, &dither_cfg, &len);
+	if (ret)
+		return;
+
+	if (TOPOLOGY_DUALPIPE_MERGE_MODE(topology)) {
+		for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
+			hw_pp = sde_enc->hw_pp[i];
+			if (hw_pp) {
+				phys->hw_pp->ops.setup_dither(hw_pp, dither_cfg,
+								len);
+			}
+		}
 	} else {
-		ret = sde_connector_get_dither_cfg(phys->connector,
-				phys->connector->state, &dither_cfg, &len);
-		if (!ret)
-			phys->hw_pp->ops.setup_dither(phys->hw_pp,
-				dither_cfg, len);
+		phys->hw_pp->ops.setup_dither(phys->hw_pp, dither_cfg, len);
 	}
 }
 
@@ -4388,6 +4429,7 @@
 	phys_params.parent = &sde_enc->base;
 	phys_params.parent_ops = parent_ops;
 	phys_params.enc_spinlock = &sde_enc->enc_spinlock;
+	phys_params.vblank_ctl_lock = &sde_enc->vblank_ctl_lock;
 
 	SDE_DEBUG("\n");
 
@@ -4530,6 +4572,7 @@
 
 	sde_enc->cur_master = NULL;
 	spin_lock_init(&sde_enc->enc_spinlock);
+	mutex_init(&sde_enc->vblank_ctl_lock);
 	drm_enc = &sde_enc->base;
 	drm_encoder_init(dev, drm_enc, &sde_encoder_funcs, drm_enc_mode, NULL);
 	drm_encoder_helper_add(drm_enc, &sde_encoder_helper_funcs);
@@ -4858,10 +4901,14 @@
 	SDE_EVT32_VERBOSE(DRMID(enc));
 
 	disp_thread = &priv->disp_thread[sde_enc->crtc->index];
-
-	kthread_queue_work(&disp_thread->worker,
-				&sde_enc->esd_trigger_work);
-	kthread_flush_work(&sde_enc->esd_trigger_work);
+	if (current->tgid == disp_thread->thread->tgid) {
+		sde_encoder_resource_control(&sde_enc->base,
+					     SDE_ENC_RC_EVENT_KICKOFF);
+	} else {
+		kthread_queue_work(&disp_thread->worker,
+				   &sde_enc->esd_trigger_work);
+		kthread_flush_work(&sde_enc->esd_trigger_work);
+	}
 	/**
 	 * panel may stop generating te signal (vsync) during esd failure. rsc
 	 * hardware may hang without vsync. Avoid rsc hang by generating the
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h
index 0e8e9dd..42b9e58 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.h
@@ -31,6 +31,7 @@
 #define SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE	BIT(4)
 
 #define IDLE_POWERCOLLAPSE_DURATION	(66 - 16/2)
+#define IDLE_POWERCOLLAPSE_IN_EARLY_WAKEUP (200 - 16/2)
 
 /**
  * Encoder functions and data types
@@ -97,10 +98,10 @@
  *	will be called after the request is complete, or other events.
  * @encoder:	encoder pointer
  * @cb:		callback pointer, provide NULL to deregister
- * @data:	user data provided to callback
+ * @crtc:	pointer to drm_crtc object interested in frame events
  */
 void sde_encoder_register_frame_event_callback(struct drm_encoder *encoder,
-		void (*cb)(void *, u32), void *data);
+		void (*cb)(void *, u32), struct drm_crtc *crtc);
 
 /**
  * sde_encoder_get_rsc_client - gets the rsc client state for primary
@@ -242,14 +243,18 @@
  * esd timeout or other display failure notification. This event flows from
  * dsi, sde_connector to sde_encoder.
  *
- * This api must not be called from crtc_commit (display) thread because it
- * requests the flush work on same thread. It is called from esd check thread
- * based on current design.
- *
  *      TODO: manage the event at sde_kms level for forward processing.
  * @drm_enc:    Pointer to drm encoder structure
  * @Return:     true if successful in updating the encoder structure
  */
 int sde_encoder_display_failure_notification(struct drm_encoder *enc);
 
+/**
+ * sde_encoder_in_clone_mode - checks if underlying phys encoder is in clone
+ *	mode or independent display mode. ref@ WB in Concurrent writeback mode.
+ * @drm_enc:    Pointer to drm encoder structure
+ * @Return:     true if successful in updating the encoder structure
+ */
+int sde_encoder_in_clone_mode(struct drm_encoder *enc);
+
 #endif /* __SDE_ENCODER_H__ */
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index 9557d41..4e9430e 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
@@ -194,6 +194,9 @@
  * @INTR_IDX_PINGPONG: Pingpong done unterrupt for cmd mode panel
  * @INTR_IDX_UNDERRUN: Underrun unterrupt for video and cmd mode panel
  * @INTR_IDX_RDPTR:    Readpointer done unterrupt for cmd mode panel
+ * @INTR_IDX_WB_DONE:  Writeback done interrupt for WB
+ * @INTR_IDX_PP2_OVFL: Pingpong overflow interrupt on PP2 for Concurrent WB
+ * @INTR_IDX_PP2_OVFL: Pingpong overflow interrupt on PP3 for Concurrent WB
  * @INTR_IDX_AUTOREFRESH_DONE:  Autorefresh done for cmd mode panel meaning
  *                              autorefresh has triggered a double buffer flip
  */
@@ -204,6 +207,9 @@
 	INTR_IDX_CTL_START,
 	INTR_IDX_RDPTR,
 	INTR_IDX_AUTOREFRESH_DONE,
+	INTR_IDX_WB_DONE,
+	INTR_IDX_PP2_OVFL,
+	INTR_IDX_PP3_OVFL,
 	INTR_IDX_MAX,
 };
 
@@ -263,6 +269,7 @@
  * @irq:			IRQ tracking structures
  * @cont_splash_single_flush	Variable to check if single flush is enabled.
  * @cont_splash_settings	Variable to store continuous splash settings.
+ * @in_clone_mode		Indicates if encoder is in clone mode ref@CWB
  * @vfp_cached:			cached vertical front porch to be used for
  *				programming ROT and MDP fetch start
  */
@@ -284,6 +291,7 @@
 	enum msm_display_compression_type comp_type;
 	spinlock_t *enc_spinlock;
 	enum sde_enc_enable_state enable_state;
+	struct mutex *vblank_ctl_lock;
 	atomic_t vblank_refcount;
 	atomic_t vsync_cnt;
 	atomic_t underrun_cnt;
@@ -294,6 +302,7 @@
 	struct sde_encoder_irq irq[INTR_IDX_MAX];
 	u32 cont_splash_single_flush;
 	bool cont_splash_settings;
+	bool in_clone_mode;
 	int vfp_cached;
 };
 
@@ -367,7 +376,6 @@
  *	writeback specific operations
  * @base:		Baseclass physical encoder structure
  * @hw_wb:		Hardware interface to the wb registers
- * @irq_idx:		IRQ interface lookup index
  * @wbdone_timeout:	Timeout value for writeback done in msec
  * @bypass_irqreg:	Bypass irq register/unregister if non-zero
  * @wbdone_complete:	for wbdone irq synchronization
@@ -391,8 +399,6 @@
 struct sde_encoder_phys_wb {
 	struct sde_encoder_phys base;
 	struct sde_hw_wb *hw_wb;
-	int irq_idx;
-	struct sde_irq_callback irq_cb;
 	u32 wbdone_timeout;
 	u32 bypass_irqreg;
 	struct completion wbdone_complete;
@@ -434,6 +440,7 @@
 	enum sde_wb wb_idx;
 	enum msm_display_compression_type comp_type;
 	spinlock_t *enc_spinlock;
+	struct mutex *vblank_ctl_lock;
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index 828d771..f06ceb7 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -680,6 +680,7 @@
 		return -EINVAL;
 	}
 
+	mutex_lock(phys_enc->vblank_ctl_lock);
 	refcount = atomic_read(&phys_enc->vblank_refcount);
 
 	/* Slave encoders don't report vblank */
@@ -713,6 +714,7 @@
 				enable, refcount, SDE_EVTLOG_ERROR);
 	}
 
+	mutex_unlock(phys_enc->vblank_ctl_lock);
 	return ret;
 }
 
@@ -1398,6 +1400,7 @@
 	phys_enc->split_role = p->split_role;
 	phys_enc->intf_mode = INTF_MODE_CMD;
 	phys_enc->enc_spinlock = p->enc_spinlock;
+	phys_enc->vblank_ctl_lock = p->vblank_ctl_lock;
 	cmd_enc->stream_sel = 0;
 	phys_enc->enable_state = SDE_ENC_DISABLED;
 	phys_enc->comp_type = p->comp_type;
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 862a8b3..d363d62 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -625,6 +625,7 @@
 		return -EINVAL;
 	}
 
+	mutex_lock(phys_enc->vblank_ctl_lock);
 	refcount = atomic_read(&phys_enc->vblank_refcount);
 	vid_enc = to_sde_encoder_phys_vid(phys_enc);
 
@@ -645,11 +646,17 @@
 	SDE_EVT32(DRMID(phys_enc->parent), enable,
 			atomic_read(&phys_enc->vblank_refcount));
 
-	if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1)
+	if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1) {
 		ret = sde_encoder_helper_register_irq(phys_enc, INTR_IDX_VSYNC);
-	else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0)
+		if (ret)
+			atomic_dec_return(&phys_enc->vblank_refcount);
+	} else if (!enable &&
+			atomic_dec_return(&phys_enc->vblank_refcount) == 0) {
 		ret = sde_encoder_helper_unregister_irq(phys_enc,
 				INTR_IDX_VSYNC);
+		if (ret)
+			atomic_inc_return(&phys_enc->vblank_refcount);
+	}
 
 end:
 	if (ret) {
@@ -660,6 +667,7 @@
 				vid_enc->hw_intf->idx - INTF_0,
 				enable, refcount, SDE_EVTLOG_ERROR);
 	}
+	mutex_unlock(phys_enc->vblank_ctl_lock);
 	return ret;
 }
 
@@ -1233,6 +1241,7 @@
 	phys_enc->split_role = p->split_role;
 	phys_enc->intf_mode = INTF_MODE_VIDEO;
 	phys_enc->enc_spinlock = p->enc_spinlock;
+	phys_enc->vblank_ctl_lock = p->vblank_ctl_lock;
 	phys_enc->comp_type = p->comp_type;
 	for (i = 0; i < INTR_IDX_MAX; i++) {
 		irq = &phys_enc->irq[i];
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
index 9a90075..bad608d 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018 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
@@ -32,6 +32,7 @@
 
 #define TO_S15D16(_x_)	((_x_) << 7)
 
+#define MULTIPLE_CONN_DETECTED(x) (x > 1)
 /**
  * sde_rgb2yuv_601l - rgb to yuv color space conversion matrix
  *
@@ -398,6 +399,31 @@
 	}
 }
 
+static void _sde_encoder_phys_wb_setup_cwb(struct sde_encoder_phys *phys_enc,
+					bool enable)
+{
+	struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
+	struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
+	struct sde_hw_intf_cfg *intf_cfg = &wb_enc->intf_cfg;
+	struct sde_hw_ctl *hw_ctl = phys_enc->hw_ctl;
+	struct sde_crtc *crtc = to_sde_crtc(wb_enc->crtc);
+
+	if (!phys_enc->in_clone_mode) {
+		SDE_DEBUG("not in CWB mode. early return\n");
+		return;
+	}
+
+	memset(intf_cfg, 0, sizeof(struct sde_hw_intf_cfg));
+	intf_cfg->intf = SDE_NONE;
+	intf_cfg->wb = hw_wb->idx;
+
+	hw_ctl = crtc->mixers[0].hw_ctl;
+	if (hw_ctl && hw_ctl->ops.update_wb_cfg) {
+		hw_ctl->ops.update_wb_cfg(hw_ctl, intf_cfg, enable);
+		SDE_DEBUG("in CWB mode adding WB for CTL_%d\n",
+				hw_ctl->idx - CTL_0);
+	}
+}
 /**
  * sde_encoder_phys_wb_setup_cdp - setup chroma down prefetch block
  * @phys_enc:	Pointer to physical encoder
@@ -408,8 +434,12 @@
 	struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
 	struct sde_hw_intf_cfg *intf_cfg = &wb_enc->intf_cfg;
 
-	memset(intf_cfg, 0, sizeof(struct sde_hw_intf_cfg));
+	if (phys_enc->in_clone_mode) {
+		SDE_DEBUG("in CWB mode. early return\n");
+		return;
+	}
 
+	memset(intf_cfg, 0, sizeof(struct sde_hw_intf_cfg));
 	intf_cfg->intf = SDE_NONE;
 	intf_cfg->wb = hw_wb->idx;
 	intf_cfg->mode_3d = sde_encoder_helper_get_3d_blend_mode(phys_enc);
@@ -417,6 +447,98 @@
 	if (phys_enc->hw_ctl && phys_enc->hw_ctl->ops.setup_intf_cfg)
 		phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl,
 				intf_cfg);
+
+}
+
+static void _sde_enc_phys_wb_detect_cwb(struct sde_encoder_phys *phys_enc,
+		struct drm_crtc_state *crtc_state)
+{
+	struct drm_connector *conn;
+	struct drm_connector_state *conn_state;
+	struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
+	const struct sde_wb_cfg *wb_cfg = wb_enc->hw_wb->caps;
+	int conn_count = 0;
+
+	phys_enc->in_clone_mode = false;
+
+	/* Check if WB has CWB support */
+	if (!(wb_cfg->features & SDE_WB_HAS_CWB))
+		return;
+
+	/* Count the number of connectors on the given crtc */
+	drm_for_each_connector(conn, crtc_state->crtc->dev) {
+		conn_state =
+			drm_atomic_get_connector_state(crtc_state->state, conn);
+		if ((conn->state && conn->state->crtc == crtc_state->crtc) ||
+				(conn_state &&
+				 conn_state->crtc == crtc_state->crtc))
+			conn_count++;
+	}
+
+
+	/* Enable clone mode If crtc has multiple connectors & one is WB */
+	if (MULTIPLE_CONN_DETECTED(conn_count))
+		phys_enc->in_clone_mode = true;
+
+	SDE_DEBUG("detect CWB - status:%d\n", phys_enc->in_clone_mode);
+}
+
+static int _sde_enc_phys_wb_validate_cwb(struct sde_encoder_phys *phys_enc,
+			struct drm_crtc_state *crtc_state,
+			 struct drm_connector_state *conn_state)
+{
+	struct sde_crtc_state *cstate = to_sde_crtc_state(crtc_state);
+	struct sde_rect wb_roi = {0,};
+	int data_pt;
+	int ds_outw = 0;
+	int ds_outh = 0;
+	int ds_in_use = false;
+	int i = 0;
+	int ret = 0;
+
+	if (!phys_enc->in_clone_mode) {
+		SDE_DEBUG("not in CWB mode. early return\n");
+		goto exit;
+	}
+
+	ret = sde_wb_connector_state_get_output_roi(conn_state, &wb_roi);
+	if (ret) {
+		SDE_ERROR("failed to get roi %d\n", ret);
+		goto exit;
+	}
+
+	data_pt = sde_crtc_get_property(cstate, CRTC_PROP_CAPTURE_OUTPUT);
+
+	/* compute cumulative ds output dimensions if in use */
+	for (i = 0; i < cstate->num_ds; i++)
+		if (cstate->ds_cfg[i].scl3_cfg.enable) {
+			ds_in_use = true;
+			ds_outw += cstate->ds_cfg[i].scl3_cfg.dst_width;
+			ds_outh += cstate->ds_cfg[i].scl3_cfg.dst_height;
+		}
+
+	/* if ds in use check wb roi against ds output dimensions */
+	if ((data_pt == CAPTURE_DSPP_OUT) &&  ds_in_use &&
+			((wb_roi.w != ds_outw) || (wb_roi.h != ds_outh))) {
+		SDE_ERROR("invalid wb roi with dest scalar [%dx%d vs %dx%d]\n",
+				wb_roi.w, wb_roi.h, ds_outw, ds_outh);
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	/* validate conn roi against pu rect */
+	if (!sde_kms_rect_is_null(&cstate->crtc_roi)) {
+		if (wb_roi.w != cstate->crtc_roi.w ||
+				wb_roi.h != cstate->crtc_roi.h) {
+			SDE_ERROR("invalid wb roi with pu [%dx%d vs %dx%d]\n",
+					wb_roi.w, wb_roi.h, cstate->crtc_roi.w,
+					 cstate->crtc_roi.h);
+			ret = -EINVAL;
+			goto exit;
+		}
+	}
+exit:
+	return ret;
 }
 
 /**
@@ -453,6 +575,8 @@
 		return -EINVAL;
 	}
 
+	_sde_enc_phys_wb_detect_cwb(phys_enc, crtc_state);
+
 	memset(&wb_roi, 0, sizeof(struct sde_rect));
 
 	rc = sde_wb_connector_state_get_output_roi(conn_state, &wb_roi);
@@ -542,7 +666,62 @@
 		}
 	}
 
-	return 0;
+	rc = _sde_enc_phys_wb_validate_cwb(phys_enc, crtc_state, conn_state);
+	if (rc) {
+		SDE_ERROR("failed in cwb validation %d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static void _sde_encoder_phys_wb_update_cwb_flush(
+		struct sde_encoder_phys *phys_enc)
+{
+	struct sde_encoder_phys_wb *wb_enc;
+	struct sde_hw_wb *hw_wb;
+	struct sde_hw_ctl *hw_ctl;
+	struct sde_hw_cdm *hw_cdm;
+	struct sde_crtc *crtc;
+	struct sde_crtc_state *crtc_state;
+	u32 flush_mask = 0;
+	int capture_point = 0;
+
+	if (!phys_enc->in_clone_mode) {
+		SDE_DEBUG("not in CWB mode. early return\n");
+		return;
+	}
+
+	wb_enc = to_sde_encoder_phys_wb(phys_enc);
+	crtc = to_sde_crtc(wb_enc->crtc);
+	crtc_state = to_sde_crtc_state(wb_enc->crtc->state);
+
+	hw_wb = wb_enc->hw_wb;
+	hw_cdm = phys_enc->hw_cdm;
+
+	/* In CWB mode, program actual source master sde_hw_ctl from crtc */
+	hw_ctl = crtc->mixers[0].hw_ctl;
+	if (!hw_ctl) {
+		SDE_DEBUG("[wb:%d] no ctl assigned for CWB\n",
+				hw_wb->idx - WB_0);
+		return;
+	}
+
+	capture_point  = sde_crtc_get_property(crtc_state,
+			CRTC_PROP_CAPTURE_OUTPUT);
+
+	phys_enc->hw_mdptop->ops.set_cwb_ppb_cntl(phys_enc->hw_mdptop,
+			crtc->num_mixers == CRTC_DUAL_MIXERS,
+			capture_point == CAPTURE_DSPP_OUT);
+
+	if (hw_ctl->ops.get_bitmask_wb)
+		hw_ctl->ops.get_bitmask_wb(hw_ctl, &flush_mask, hw_wb->idx);
+
+	if (hw_ctl->ops.get_bitmask_cdm && hw_cdm)
+		hw_ctl->ops.get_bitmask_cdm(hw_ctl, &flush_mask, hw_cdm->idx);
+
+	if (hw_ctl->ops.update_pending_flush)
+		hw_ctl->ops.update_pending_flush(hw_ctl, flush_mask);
 }
 
 /**
@@ -551,7 +730,7 @@
  */
 static void _sde_encoder_phys_wb_update_flush(struct sde_encoder_phys *phys_enc)
 {
-	struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
+	struct sde_encoder_phys_wb *wb_enc;
 	struct sde_hw_wb *hw_wb;
 	struct sde_hw_ctl *hw_ctl;
 	struct sde_hw_cdm *hw_cdm;
@@ -560,12 +739,18 @@
 	if (!phys_enc)
 		return;
 
+	wb_enc = to_sde_encoder_phys_wb(phys_enc);
 	hw_wb = wb_enc->hw_wb;
-	hw_ctl = phys_enc->hw_ctl;
 	hw_cdm = phys_enc->hw_cdm;
+	hw_ctl = phys_enc->hw_ctl;
 
 	SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
 
+	if (phys_enc->in_clone_mode) {
+		SDE_DEBUG("in CWB mode. early return\n");
+		return;
+	}
+
 	if (!hw_ctl) {
 		SDE_DEBUG("[wb:%d] no ctl assigned\n", hw_wb->idx - WB_0);
 		return;
@@ -659,54 +844,28 @@
 	sde_encoder_phys_wb_setup_fb(phys_enc, fb, wb_roi);
 
 	sde_encoder_phys_wb_setup_cdp(phys_enc);
+
+	_sde_encoder_phys_wb_setup_cwb(phys_enc, true);
 }
 
-/**
- * sde_encoder_phys_wb_unregister_irq - unregister writeback interrupt handler
- * @phys_enc:	Pointer to physical encoder
- */
-static int sde_encoder_phys_wb_unregister_irq(
-		struct sde_encoder_phys *phys_enc)
-{
-	struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
-	struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
-
-	if (wb_enc->bypass_irqreg)
-		return 0;
-
-	sde_core_irq_disable(phys_enc->sde_kms, &wb_enc->irq_idx, 1);
-	sde_core_irq_unregister_callback(phys_enc->sde_kms, wb_enc->irq_idx,
-			&wb_enc->irq_cb);
-
-	SDE_DEBUG("un-register IRQ for wb %d, irq_idx=%d\n",
-			hw_wb->idx - WB_0,
-			wb_enc->irq_idx);
-
-	return 0;
-}
-
-/**
- * sde_encoder_phys_wb_done_irq - writeback interrupt handler
- * @arg:	Pointer to writeback encoder
- * @irq_idx:	interrupt index
- */
-static void sde_encoder_phys_wb_done_irq(void *arg, int irq_idx)
+static void _sde_encoder_phys_wb_frame_done_helper(void *arg, bool frame_error)
 {
 	struct sde_encoder_phys_wb *wb_enc = arg;
 	struct sde_encoder_phys *phys_enc = &wb_enc->base;
 	struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
-	u32 event = 0;
+	u32 event = frame_error ? SDE_ENCODER_FRAME_EVENT_ERROR : 0;
 
-	SDE_DEBUG("[wb:%d,%u]\n", hw_wb->idx - WB_0,
-			wb_enc->frame_count);
+	event |= SDE_ENCODER_FRAME_EVENT_DONE |
+		SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE;
+
+	SDE_DEBUG("[wb:%d,%u]\n", hw_wb->idx - WB_0, wb_enc->frame_count);
 
 	/* don't notify upper layer for internal commit */
 	if (phys_enc->enable_state == SDE_ENC_DISABLING)
 		goto complete;
 
-	event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE
-			| SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE
-			| SDE_ENCODER_FRAME_EVENT_DONE;
+	if (!phys_enc->in_clone_mode)
+		event |= SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE;
 
 	atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0);
 	if (phys_enc->parent_ops.handle_frame_done)
@@ -724,58 +883,60 @@
 }
 
 /**
- * sde_encoder_phys_wb_register_irq - register writeback interrupt handler
- * @phys_enc:	Pointer to physical encoder
+ * sde_encoder_phys_wb_done_irq - Pingpong overflow interrupt handler for CWB
+ * @arg:	Pointer to writeback encoder
+ * @irq_idx:	interrupt index
  */
-static int sde_encoder_phys_wb_register_irq(struct sde_encoder_phys *phys_enc)
+static void sde_encoder_phys_cwb_ovflow(void *arg, int irq_idx)
 {
-	struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
-	struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
-	struct sde_irq_callback *irq_cb = &wb_enc->irq_cb;
-	enum sde_intr_type intr_type;
-	int ret = 0;
+	_sde_encoder_phys_wb_frame_done_helper(arg, true);
+}
+
+/**
+ * sde_encoder_phys_wb_done_irq - writeback interrupt handler
+ * @arg:	Pointer to writeback encoder
+ * @irq_idx:	interrupt index
+ */
+static void sde_encoder_phys_wb_done_irq(void *arg, int irq_idx)
+{
+	_sde_encoder_phys_wb_frame_done_helper(arg, false);
+}
+
+/**
+ * sde_encoder_phys_wb_irq_ctrl - irq control of WB
+ * @phys:	Pointer to physical encoder
+ * @enable:	indicates enable or disable interrupts
+ */
+static void sde_encoder_phys_wb_irq_ctrl(
+		struct sde_encoder_phys *phys, bool enable)
+{
+
+	struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys);
+	int index = 0;
+
+	if (!wb_enc)
+		return;
 
 	if (wb_enc->bypass_irqreg)
-		return 0;
+		return;
 
-	intr_type = sde_encoder_phys_wb_get_intr_type(hw_wb);
-	wb_enc->irq_idx = sde_core_irq_idx_lookup(phys_enc->sde_kms,
-			intr_type, hw_wb->idx);
-	if (wb_enc->irq_idx < 0) {
-		SDE_ERROR(
-			"failed to lookup IRQ index for WB_DONE with wb=%d\n",
-			hw_wb->idx - WB_0);
-		return -EINVAL;
+	if (enable) {
+		sde_encoder_helper_register_irq(phys, INTR_IDX_WB_DONE);
+		if (phys->in_clone_mode) {
+			for (index = 0; index < CRTC_DUAL_MIXERS; index++)
+				sde_encoder_helper_register_irq(phys,
+						index ? INTR_IDX_PP3_OVFL
+						: INTR_IDX_PP2_OVFL);
+		}
+	} else {
+		sde_encoder_helper_unregister_irq(phys, INTR_IDX_WB_DONE);
+		if (phys->in_clone_mode) {
+			for (index = 0; index < CRTC_DUAL_MIXERS; index++)
+				sde_encoder_helper_unregister_irq(phys,
+						index ? INTR_IDX_PP3_OVFL
+						: INTR_IDX_PP2_OVFL);
+		}
 	}
-
-	irq_cb->func = sde_encoder_phys_wb_done_irq;
-	irq_cb->arg = wb_enc;
-	ret = sde_core_irq_register_callback(phys_enc->sde_kms,
-			wb_enc->irq_idx, irq_cb);
-	if (ret) {
-		SDE_ERROR("failed to register IRQ callback WB_DONE\n");
-		return ret;
-	}
-
-	ret = sde_core_irq_enable(phys_enc->sde_kms, &wb_enc->irq_idx, 1);
-	if (ret) {
-		SDE_ERROR(
-			"failed to enable IRQ for WB_DONE, wb %d, irq_idx=%d\n",
-				hw_wb->idx - WB_0,
-				wb_enc->irq_idx);
-		wb_enc->irq_idx = -EINVAL;
-
-		/* Unregister callback on IRQ enable failure */
-		sde_core_irq_unregister_callback(phys_enc->sde_kms,
-				wb_enc->irq_idx, irq_cb);
-		return ret;
-	}
-
-	SDE_DEBUG("registered IRQ for wb %d, irq_idx=%d\n",
-			hw_wb->idx - WB_0,
-			wb_enc->irq_idx);
-
-	return ret;
 }
 
 /**
@@ -846,6 +1007,7 @@
 	u32 irq_status, event = 0;
 	u64 wb_time = 0;
 	int rc = 0;
+	int irq_idx = phys_enc->irq[INTR_IDX_WB_DONE].irq_idx;
 	u32 timeout = max_t(u32, wb_enc->wbdone_timeout, KICKOFF_TIMEOUT_MS);
 
 	/* Return EWOULDBLOCK since we know the wait isn't necessary */
@@ -860,7 +1022,7 @@
 	/* signal completion if commit with no framebuffer */
 	if (!wb_enc->wb_fb) {
 		SDE_DEBUG("no output framebuffer\n");
-		sde_encoder_phys_wb_done_irq(wb_enc, wb_enc->irq_idx);
+		_sde_encoder_phys_wb_frame_done_helper(wb_enc, false);
 	}
 
 	ret = wait_for_completion_timeout(&wb_enc->wbdone_complete,
@@ -870,11 +1032,11 @@
 		SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc),
 				wb_enc->frame_count);
 		irq_status = sde_core_irq_read(phys_enc->sde_kms,
-				wb_enc->irq_idx, true);
+				irq_idx, true);
 		if (irq_status) {
 			SDE_DEBUG("wb:%d done but irq not triggered\n",
 					WBID(wb_enc));
-			sde_encoder_phys_wb_done_irq(wb_enc, wb_enc->irq_idx);
+			_sde_encoder_phys_wb_frame_done_helper(wb_enc, false);
 		} else {
 			SDE_ERROR("wb:%d kickoff timed out\n",
 					WBID(wb_enc));
@@ -891,8 +1053,6 @@
 		}
 	}
 
-	sde_encoder_phys_wb_unregister_irq(phys_enc);
-
 	if (!rc)
 		wb_enc->end_time = ktime_get();
 
@@ -937,19 +1097,12 @@
 		struct sde_encoder_kickoff_params *params)
 {
 	struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
-	int ret;
 
 	SDE_DEBUG("[wb:%d,%u]\n", wb_enc->hw_wb->idx - WB_0,
 			wb_enc->kickoff_count);
 
 	reinit_completion(&wb_enc->wbdone_complete);
 
-	ret = sde_encoder_phys_wb_register_irq(phys_enc);
-	if (ret) {
-		SDE_ERROR("failed to register irq %d\n", ret);
-		return ret;
-	}
-
 	wb_enc->kickoff_count++;
 
 	/* set OT limit & enable traffic shaper */
@@ -957,6 +1110,8 @@
 
 	_sde_encoder_phys_wb_update_flush(phys_enc);
 
+	_sde_encoder_phys_wb_update_cwb_flush(phys_enc);
+
 	/* vote for iommu/clk/bus */
 	wb_enc->start_time = ktime_get();
 
@@ -977,6 +1132,15 @@
 		return;
 	}
 
+	/*
+	 * Bail out iff in CWB mode. In case of CWB, primary control-path
+	 * which is actually driving would trigger the flush
+	 */
+	if (phys_enc->in_clone_mode) {
+		SDE_DEBUG("in CWB mode. early return\n");
+		return;
+	}
+
 	SDE_DEBUG("[wb:%d]\n", wb_enc->hw_wb->idx - WB_0);
 
 	/* clear pending flush if commit with no framebuffer */
@@ -1183,6 +1347,13 @@
 		goto exit;
 	}
 
+	/* avoid reset frame for CWB */
+	if (phys_enc->in_clone_mode) {
+		_sde_encoder_phys_wb_setup_cwb(phys_enc, false);
+		phys_enc->in_clone_mode = false;
+		goto exit;
+	}
+
 	/* reset h/w before final flush */
 	if (phys_enc->hw_ctl->ops.clear_pending_flush)
 		phys_enc->hw_ctl->ops.clear_pending_flush(phys_enc->hw_ctl);
@@ -1320,6 +1491,7 @@
 	ops->trigger_flush = sde_encoder_phys_wb_trigger_flush;
 	ops->trigger_start = sde_encoder_helper_trigger_start;
 	ops->hw_reset = sde_encoder_helper_hw_reset;
+	ops->irq_control = sde_encoder_phys_wb_irq_ctrl;
 }
 
 /**
@@ -1332,6 +1504,7 @@
 	struct sde_encoder_phys *phys_enc;
 	struct sde_encoder_phys_wb *wb_enc;
 	struct sde_hw_mdp *hw_mdp;
+	struct sde_encoder_irq *irq;
 	int ret = 0;
 
 	SDE_DEBUG("\n");
@@ -1348,7 +1521,6 @@
 		ret = -ENOMEM;
 		goto fail_alloc;
 	}
-	wb_enc->irq_idx = -EINVAL;
 	wb_enc->wbdone_timeout = KICKOFF_TIMEOUT_MS;
 	init_completion(&wb_enc->wbdone_complete);
 
@@ -1410,8 +1582,38 @@
 	phys_enc->intf_mode = INTF_MODE_WB_LINE;
 	phys_enc->intf_idx = p->intf_idx;
 	phys_enc->enc_spinlock = p->enc_spinlock;
+	phys_enc->vblank_ctl_lock = p->vblank_ctl_lock;
 	atomic_set(&phys_enc->pending_retire_fence_cnt, 0);
-	INIT_LIST_HEAD(&wb_enc->irq_cb.list);
+
+	irq = &phys_enc->irq[INTR_IDX_WB_DONE];
+	INIT_LIST_HEAD(&irq->cb.list);
+	irq->name = "wb_done";
+	irq->hw_idx =  wb_enc->hw_wb->idx;
+	irq->irq_idx = -1;
+	irq->intr_type = sde_encoder_phys_wb_get_intr_type(wb_enc->hw_wb);
+	irq->intr_idx = INTR_IDX_WB_DONE;
+	irq->cb.arg = wb_enc;
+	irq->cb.func = sde_encoder_phys_wb_done_irq;
+
+	irq = &phys_enc->irq[INTR_IDX_PP2_OVFL];
+	INIT_LIST_HEAD(&irq->cb.list);
+	irq->name = "pp2_overflow";
+	irq->hw_idx = CWB_2;
+	irq->irq_idx = -1;
+	irq->intr_type = SDE_IRQ_TYPE_CWB_OVERFLOW;
+	irq->intr_idx = INTR_IDX_PP2_OVFL;
+	irq->cb.arg = wb_enc;
+	irq->cb.func = sde_encoder_phys_cwb_ovflow;
+
+	irq = &phys_enc->irq[INTR_IDX_PP3_OVFL];
+	INIT_LIST_HEAD(&irq->cb.list);
+	irq->name = "pp3_overflow";
+	irq->hw_idx = CWB_3;
+	irq->irq_idx = -1;
+	irq->intr_type = SDE_IRQ_TYPE_CWB_OVERFLOW;
+	irq->intr_idx = INTR_IDX_PP3_OVFL;
+	irq->cb.arg = wb_enc;
+	irq->cb.func = sde_encoder_phys_cwb_ovflow;
 
 	/* create internal buffer for disable logic */
 	if (_sde_encoder_phys_wb_init_internal_fb(wb_enc,
diff --git a/drivers/gpu/drm/msm/sde/sde_fence.c b/drivers/gpu/drm/msm/sde/sde_fence.c
index 686c640..1f30a5c 100644
--- a/drivers/gpu/drm/msm/sde/sde_fence.c
+++ b/drivers/gpu/drm/msm/sde/sde_fence.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -278,7 +278,8 @@
 	}
 }
 
-static void _sde_fence_trigger(struct sde_fence_context *ctx, ktime_t ts)
+static void _sde_fence_trigger(struct sde_fence_context *ctx,
+		ktime_t ts, bool error)
 {
 	unsigned long flags;
 	struct sde_fence *fc, *next;
@@ -300,6 +301,7 @@
 
 	list_for_each_entry_safe(fc, next, &local_list_head, fence_list) {
 		spin_lock_irqsave(&ctx->lock, flags);
+		fc->base.error = error ? -EBUSY : 0;
 		fc->base.timestamp = ts;
 		is_signaled = fence_is_signaled_locked(&fc->base);
 		spin_unlock_irqrestore(&ctx->lock, flags);
@@ -351,7 +353,7 @@
 
 	if (fd >= 0) {
 		rc = 0;
-		_sde_fence_trigger(ctx, ktime_get());
+		_sde_fence_trigger(ctx, ktime_get(), false);
 	} else {
 		rc = fd;
 	}
@@ -360,7 +362,7 @@
 }
 
 void sde_fence_signal(struct sde_fence_context *ctx, ktime_t ts,
-							bool reset_timeline)
+		enum sde_fence_event fence_event)
 {
 	unsigned long flags;
 
@@ -370,7 +372,7 @@
 	}
 
 	spin_lock_irqsave(&ctx->lock, flags);
-	if (reset_timeline) {
+	if (fence_event == SDE_FENCE_RESET_TIMELINE) {
 		if ((int)(ctx->done_count - ctx->commit_count) < 0) {
 			SDE_ERROR(
 				"timeline reset attempt! done count:%d commit:%d\n",
@@ -378,7 +380,7 @@
 			ctx->done_count = ctx->commit_count;
 			SDE_EVT32(ctx->drm_id, ctx->done_count,
 				ctx->commit_count, ktime_to_us(ts),
-				reset_timeline, SDE_EVTLOG_FATAL);
+				fence_event, SDE_EVTLOG_FATAL);
 		} else {
 			spin_unlock_irqrestore(&ctx->lock, flags);
 			return;
@@ -391,7 +393,7 @@
 		SDE_ERROR("extra signal attempt! done count:%d commit:%d\n",
 					ctx->done_count, ctx->commit_count);
 		SDE_EVT32(ctx->drm_id, ctx->done_count, ctx->commit_count,
-			ktime_to_us(ts), reset_timeline, SDE_EVTLOG_FATAL);
+			ktime_to_us(ts), fence_event, SDE_EVTLOG_FATAL);
 		spin_unlock_irqrestore(&ctx->lock, flags);
 		return;
 	}
@@ -400,7 +402,7 @@
 	SDE_EVT32(ctx->drm_id, ctx->done_count, ctx->commit_count,
 			ktime_to_us(ts));
 
-	_sde_fence_trigger(ctx, ts);
+	_sde_fence_trigger(ctx, ts, (fence_event == SDE_FENCE_SIGNAL_ERROR));
 }
 
 void sde_fence_timeline_status(struct sde_fence_context *ctx,
diff --git a/drivers/gpu/drm/msm/sde/sde_fence.h b/drivers/gpu/drm/msm/sde/sde_fence.h
index 29d2ec7..7891be4 100644
--- a/drivers/gpu/drm/msm/sde/sde_fence.h
+++ b/drivers/gpu/drm/msm/sde/sde_fence.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -47,6 +47,18 @@
 	char name[SDE_FENCE_NAME_SIZE];
 };
 
+/**
+ * enum sde_fence_event - sde fence event as hint fence operation
+ * @SDE_FENCE_SIGNAL: Signal the fence cleanly with current timeline
+ * @SDE_FENCE_RESET_TIMELINE: Reset timeline of the fence context
+ * @SDE_FENCE_SIGNAL: Signal the fence but indicate error throughfence status
+ */
+enum sde_fence_event {
+	SDE_FENCE_SIGNAL,
+	SDE_FENCE_RESET_TIMELINE,
+	SDE_FENCE_SIGNAL_ERROR
+};
+
 #if IS_ENABLED(CONFIG_SYNC_FILE)
 /**
  * sde_sync_get - Query sync fence object from a file handle
@@ -128,10 +140,10 @@
  * sde_fence_signal - advance fence timeline to signal outstanding fences
  * @fence: Pointer fence container
  * @ts: fence timestamp
- * @reset_timeline: reset the fence timeline to done count equal to commit count
+ * @fence_event: fence event to indicate nature of fence signal.
  */
 void sde_fence_signal(struct sde_fence_context *fence, ktime_t ts,
-		bool reset_timeline);
+		enum sde_fence_event fence_event);
 
 /**
  * sde_fence_timeline_status - prints fence timeline status
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ad4.c b/drivers/gpu/drm/msm/sde/sde_hw_ad4.c
index 66445da..e60defd 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ad4.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ad4.c
@@ -109,6 +109,9 @@
 static int ad4_cfg_ipc_reset(struct sde_hw_dspp *dspp,
 		struct sde_ad_hw_cfg *cfg);
 
+static int ad4_vsync_update(struct sde_hw_dspp *dspp,
+		struct sde_ad_hw_cfg *cfg);
+
 static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = {
 	[ad4_state_idle][AD_MODE] = ad4_mode_setup_common,
 	[ad4_state_idle][AD_INIT] = ad4_init_setup_idle,
@@ -121,6 +124,7 @@
 	[ad4_state_idle][AD_IPC_SUSPEND] = ad4_no_op_setup,
 	[ad4_state_idle][AD_IPC_RESUME] = ad4_no_op_setup,
 	[ad4_state_idle][AD_IPC_RESET] = ad4_no_op_setup,
+	[ad4_state_idle][AD_VSYNC_UPDATE] = ad4_no_op_setup,
 
 	[ad4_state_startup][AD_MODE] = ad4_mode_setup_common,
 	[ad4_state_startup][AD_INIT] = ad4_init_setup,
@@ -133,6 +137,7 @@
 	[ad4_state_startup][AD_STRENGTH] = ad4_no_op_setup,
 	[ad4_state_startup][AD_IPC_RESUME] = ad4_no_op_setup,
 	[ad4_state_startup][AD_IPC_RESET] = ad4_ipc_reset_setup_startup,
+	[ad4_state_startup][AD_VSYNC_UPDATE] = ad4_vsync_update,
 
 	[ad4_state_run][AD_MODE] = ad4_mode_setup_common,
 	[ad4_state_run][AD_INIT] = ad4_init_setup_run,
@@ -145,6 +150,7 @@
 	[ad4_state_run][AD_IPC_SUSPEND] = ad4_ipc_suspend_setup_run,
 	[ad4_state_run][AD_IPC_RESUME] = ad4_no_op_setup,
 	[ad4_state_run][AD_IPC_RESET] = ad4_setup_debug,
+	[ad4_state_run][AD_VSYNC_UPDATE] = ad4_vsync_update,
 
 	[ad4_state_ipcs][AD_MODE] = ad4_no_op_setup,
 	[ad4_state_ipcs][AD_INIT] = ad4_no_op_setup,
@@ -157,6 +163,7 @@
 	[ad4_state_ipcs][AD_IPC_SUSPEND] = ad4_no_op_setup,
 	[ad4_state_ipcs][AD_IPC_RESUME] = ad4_ipc_resume_setup_ipcs,
 	[ad4_state_ipcs][AD_IPC_RESET] = ad4_no_op_setup,
+	[ad4_state_ipcs][AD_VSYNC_UPDATE] = ad4_no_op_setup,
 
 	[ad4_state_ipcr][AD_MODE] = ad4_mode_setup_common,
 	[ad4_state_ipcr][AD_INIT] = ad4_init_setup_ipcr,
@@ -169,6 +176,7 @@
 	[ad4_state_ipcr][AD_IPC_SUSPEND] = ad4_ipc_suspend_setup_ipcr,
 	[ad4_state_ipcr][AD_IPC_RESUME] = ad4_no_op_setup,
 	[ad4_state_ipcr][AD_IPC_RESET] = ad4_ipc_reset_setup_ipcr,
+	[ad4_state_ipcr][AD_VSYNC_UPDATE] = ad4_no_op_setup,
 
 	[ad4_state_manual][AD_MODE] = ad4_mode_setup_common,
 	[ad4_state_manual][AD_INIT] = ad4_init_setup,
@@ -181,6 +189,7 @@
 	[ad4_state_manual][AD_IPC_SUSPEND] = ad4_no_op_setup,
 	[ad4_state_manual][AD_IPC_RESUME] = ad4_no_op_setup,
 	[ad4_state_manual][AD_IPC_RESET] = ad4_setup_debug_manual,
+	[ad4_state_manual][AD_VSYNC_UPDATE] = ad4_no_op_setup,
 };
 
 struct ad4_info {
@@ -201,6 +210,7 @@
 	u32 irdx_control_0;
 	u32 tf_ctrl;
 	u32 vc_control_0;
+	u32 frame_pushes;
 };
 
 static struct ad4_info info[DSPP_MAX] = {
@@ -905,6 +915,8 @@
 	val = (ad_cfg->cfg_param_046 & (BIT(16) - 1));
 	SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
 
+	info[dspp->idx].frame_pushes = ad_cfg->cfg_param_047;
+
 	return 0;
 }
 
@@ -1546,3 +1558,25 @@
 		ad4_mode_setup(dspp, info[dspp->idx].mode);
 	return 0;
 }
+
+static int ad4_vsync_update(struct sde_hw_dspp *dspp,
+		struct sde_ad_hw_cfg *cfg)
+{
+	u32 *count;
+	struct sde_hw_mixer *hw_lm;
+
+	if (cfg->hw_cfg->len != sizeof(u32) || !cfg->hw_cfg->payload) {
+		DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n",
+			sizeof(u32), cfg->hw_cfg->len, cfg->hw_cfg->payload);
+		return -EINVAL;
+	}
+
+	count = (u32 *)(cfg->hw_cfg->payload);
+	hw_lm = cfg->hw_cfg->mixer_info;
+
+	if (hw_lm && !hw_lm->cfg.right_mixer &&
+		(*count < info[dspp->idx].frame_pushes))
+		(*count)++;
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index eacafe6..475f8d0 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -1694,6 +1694,9 @@
 
 		set_bit(SDE_WB_XY_ROI_OFFSET, &wb->features);
 
+		if (sde_cfg->has_cwb_support)
+			set_bit(SDE_WB_HAS_CWB, &wb->features);
+
 		for (j = 0; j < sde_cfg->mdp_count; j++) {
 			sde_cfg->mdp[j].clk_ctrls[wb->clk_ctrl].reg_off =
 				PROP_BITVALUE_ACCESS(prop_value,
@@ -3248,6 +3251,7 @@
 	} else if (IS_SDM845_TARGET(hw_rev)) {
 		/* update sdm845 target here */
 		sde_cfg->has_wb_ubwc = true;
+		sde_cfg->has_cwb_support = true;
 		sde_cfg->perf.min_prefill_lines = 24;
 		sde_cfg->vbif_qos_nlvl = 8;
 		sde_cfg->ts_prefill_rev = 2;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index 963b48f..65919e9 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -261,6 +261,7 @@
  * @SDE_WB_QOS,             Writeback supports QoS control, danger/safe/creq
  * @SDE_WB_QOS_8LVL,        Writeback supports 8-level QoS control
  * @SDE_WB_CDP              Writeback supports client driven prefetch
+ * @SDE_WB_HAS_CWB          Writeback block supports concurrent writeback
  * @SDE_WB_MAX              maximum value
  */
 enum {
@@ -279,6 +280,7 @@
 	SDE_WB_QOS,
 	SDE_WB_QOS_8LVL,
 	SDE_WB_CDP,
+	SDE_WB_HAS_CWB,
 	SDE_WB_MAX
 };
 
@@ -922,6 +924,7 @@
  * @has_src_split      source split feature status
  * @has_cdp            Client driven prefetch feature status
  * @has_wb_ubwc        UBWC feature supported on WB
+ * @has_cwb_support    indicates if device supports primary capture through CWB
  * @ubwc_version       UBWC feature version (0x0 for not supported)
  * @has_sbuf           indicate if stream buffer is available
  * @sbuf_headroom      stream buffer headroom in lines
@@ -959,6 +962,7 @@
 	bool has_cdp;
 	bool has_dim_layer;
 	bool has_wb_ubwc;
+	bool has_cwb_support;
 	u32 ubwc_version;
 	bool has_sbuf;
 	u32 sbuf_headroom;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
index 303d96e..2146611 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -576,6 +576,23 @@
 	SDE_REG_WRITE(c, CTL_TOP, intf_cfg);
 }
 
+static void sde_hw_ctl_update_wb_cfg(struct sde_hw_ctl *ctx,
+		struct sde_hw_intf_cfg *cfg, bool enable) {
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	u32 intf_cfg = 0;
+
+	if (!cfg->wb)
+		return;
+
+	intf_cfg = SDE_REG_READ(c, CTL_TOP);
+	if (enable)
+		intf_cfg |= (cfg->wb & 0x3) + 2;
+	else
+		intf_cfg &= ~((cfg->wb & 0x3) + 2);
+
+	SDE_REG_WRITE(c, CTL_TOP, intf_cfg);
+}
+
 static inline u32 sde_hw_ctl_read_ctl_top(struct sde_hw_ctl *ctx)
 {
 	struct sde_hw_blk_reg_map *c;
@@ -638,6 +655,7 @@
 	ops->read_ctl_top = sde_hw_ctl_read_ctl_top;
 	ops->read_ctl_layers = sde_hw_ctl_read_ctl_layers;
 	ops->setup_intf_cfg = sde_hw_ctl_intf_cfg;
+	ops->update_wb_cfg = sde_hw_ctl_update_wb_cfg;
 	ops->reset = sde_hw_ctl_reset_control;
 	ops->get_reset = sde_hw_ctl_get_reset_status;
 	ops->hard_reset = sde_hw_ctl_hard_reset;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
index 9eb31f1..75631dd8 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -150,6 +150,15 @@
 	void (*setup_intf_cfg)(struct sde_hw_ctl *ctx,
 		struct sde_hw_intf_cfg *cfg);
 
+	/**
+	 * Update the interface selection with input WB config
+	 * @ctx       : ctl path ctx pointer
+	 * @cfg       : pointer to input wb config
+	 * @enable    : set if true, clear otherwise
+	 */
+	void (*update_wb_cfg)(struct sde_hw_ctl *ctx,
+		struct sde_hw_intf_cfg *cfg, bool enable);
+
 	int (*reset)(struct sde_hw_ctl *c);
 
 	/**
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.c b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
index 4e677c2..97a3ea4 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_lm.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -179,7 +179,7 @@
 	u32 reset = BIT(16), val;
 
 	reset = ~reset;
-	for (i = SDE_STAGE_0; i < sblk->maxblendstages; i++) {
+	for (i = SDE_STAGE_0; i <= sblk->maxblendstages; i++) {
 		stage_off = _stage_offset(ctx, i);
 		if (WARN_ON(stage_off < 0))
 			return;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
index 8022f23..9b4e03d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
@@ -570,7 +570,8 @@
 /**
  * struct sde_splash_data - Struct contains details of continuous splash
  *	memory region and initial pipeline configuration.
- * @smmu_handoff_pending:boolean to notify handoff from splash memory to smmu
+ * @resource_handoff_pending: boolean to notify boot up resource handoff
+ *			is pending.
  * @splash_base:	Base address of continuous splash region reserved
  *                      by bootloader
  * @splash_size:	Size of continuous splash region
@@ -585,7 +586,7 @@
  * @single_flush_en: Stores if the single flush is enabled.
  */
 struct sde_splash_data {
-	bool smmu_handoff_pending;
+	bool resource_handoff_pending;
 	unsigned long splash_base;
 	u32 splash_size;
 	struct ctl_top top[CTL_MAX - CTL_0];
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.c b/drivers/gpu/drm/msm/sde/sde_hw_top.c
index 8b89ebb..cf646bd 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.c
@@ -376,6 +376,18 @@
 	SDE_REG_WRITE(c, HDMI_DP_CORE_SELECT, 0x1);
 }
 
+static void sde_hw_program_cwb_ppb_ctrl(struct sde_hw_mdp *mdp,
+		bool dual, bool dspp_out)
+{
+	u32 value = dspp_out ? 0x4 : 0x0;
+
+	SDE_REG_WRITE(&mdp->hw, PPB2_CNTL, value);
+	if (dual) {
+		value |= 0x1;
+		SDE_REG_WRITE(&mdp->hw, PPB3_CNTL, value);
+	}
+}
+
 static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops,
 		unsigned long cap)
 {
@@ -385,6 +397,7 @@
 	ops->setup_clk_force_ctrl = sde_hw_setup_clk_force_ctrl;
 	ops->get_danger_status = sde_hw_get_danger_status;
 	ops->setup_vsync_source = sde_hw_setup_vsync_source;
+	ops->set_cwb_ppb_cntl = sde_hw_program_cwb_ppb_ctrl;
 	ops->get_safe_status = sde_hw_get_safe_status;
 	ops->get_split_flush_status = sde_hw_get_split_flush;
 	ops->setup_dce = sde_hw_setup_dce;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.h b/drivers/gpu/drm/msm/sde/sde_hw_top.h
index 950a62c..210ea53 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.h
@@ -194,6 +194,15 @@
 	 * @mdp: mdp top context driver
 	 */
 	void (*intf_audio_select)(struct sde_hw_mdp *mdp);
+
+	/**
+	 * set_cwb_ppb_cntl - select the data point for CWB
+	 * @mdp: mdp top context driver
+	 * @dual: indicates if dual pipe line needs to be programmed
+	 * @dspp_out : true if dspp output required. LM is default tap point
+	 */
+	void (*set_cwb_ppb_cntl)(struct sde_hw_mdp *mdp,
+			bool dual, bool dspp_out);
 };
 
 struct sde_hw_mdp {
diff --git a/drivers/gpu/drm/msm/sde/sde_hwio.h b/drivers/gpu/drm/msm/sde/sde_hwio.h
index cc020d9..a592223 100644
--- a/drivers/gpu/drm/msm/sde/sde_hwio.h
+++ b/drivers/gpu/drm/msm/sde/sde_hwio.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -40,6 +40,8 @@
 #define PPB0_CONFIG                     0x334
 #define PPB1_CNTL                       0x338
 #define PPB1_CONFIG                     0x33C
+#define PPB2_CNTL                       0x370
+#define PPB3_CNTL                       0x374
 #define HW_EVENTS_CTL                   0x37C
 #define CLK_CTRL3                       0x3A8
 #define CLK_STATUS3                     0x3AC
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 33bdec9..b0a52a7 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -936,9 +936,6 @@
 		}
 	}
 
-	if (sde_kms->splash_data.smmu_handoff_pending)
-		sde_kms->splash_data.smmu_handoff_pending = false;
-
 	/*
 	 * NOTE: for secure use cases we want to apply the new HW
 	 * configuration only after completing preparation for secure
@@ -972,6 +969,62 @@
 	}
 }
 
+static void _sde_kms_release_splash_resource(struct sde_kms *sde_kms,
+		struct drm_atomic_state *old_state)
+{
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *crtc_state;
+	bool primary_crtc_active = false;
+	struct msm_drm_private *priv;
+	int i, rc = 0;
+
+	priv = sde_kms->dev->dev_private;
+
+	if (!sde_kms->splash_data.resource_handoff_pending)
+		return;
+
+	SDE_EVT32(SDE_EVTLOG_FUNC_CASE1);
+	for_each_crtc_in_state(old_state, crtc, crtc_state, i) {
+		if (crtc->state->active)
+			primary_crtc_active = true;
+		SDE_EVT32(crtc->base.id, crtc->state->active);
+	}
+
+	if (!primary_crtc_active) {
+		SDE_EVT32(SDE_EVTLOG_FUNC_CASE2);
+		return;
+	}
+
+	sde_kms->splash_data.resource_handoff_pending = false;
+
+	if (sde_kms->splash_data.cont_splash_en) {
+		SDE_DEBUG("disabling cont_splash feature\n");
+		sde_kms->splash_data.cont_splash_en = false;
+
+		for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++)
+			sde_power_data_bus_set_quota(&priv->phandle,
+				sde_kms->core_client,
+				SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT, i,
+				SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA,
+				SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA);
+
+		sde_power_resource_enable(&priv->phandle, sde_kms->core_client,
+			false);
+	}
+
+	if (sde_kms->splash_data.splash_base) {
+		_sde_kms_splash_smmu_unmap(sde_kms);
+
+		rc = _sde_kms_release_splash_buffer(
+			sde_kms->splash_data.splash_base,
+			sde_kms->splash_data.splash_size);
+		if (rc)
+			pr_err("failed to release splash memory\n");
+		sde_kms->splash_data.splash_base = 0;
+		sde_kms->splash_data.splash_size = 0;
+	}
+}
+
 static void sde_kms_complete_commit(struct msm_kms *kms,
 		struct drm_atomic_state *old_state)
 {
@@ -1019,39 +1072,9 @@
 
 	sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
 
+	_sde_kms_release_splash_resource(sde_kms, old_state);
+
 	SDE_EVT32_VERBOSE(SDE_EVTLOG_FUNC_EXIT);
-
-	if (sde_kms->splash_data.cont_splash_en) {
-		/* Releasing splash resources as we have first frame update */
-		rc = _sde_kms_splash_smmu_unmap(sde_kms);
-		SDE_DEBUG("Disabling cont_splash feature\n");
-		sde_kms->splash_data.cont_splash_en = false;
-
-		for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++)
-			sde_power_data_bus_set_quota(&priv->phandle,
-				sde_kms->core_client,
-				SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT, i,
-				SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA,
-				SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA);
-
-		sde_power_resource_enable(&priv->phandle,
-				sde_kms->core_client, false);
-		SDE_DEBUG("removing Vote for MDP Resources\n");
-	}
-
-	/*
-	 * Even for continuous splash disabled cases we have to release
-	 * splash memory reservation back to system after first frame update.
-	 */
-	if (sde_kms->splash_data.splash_base) {
-		rc = _sde_kms_release_splash_buffer(
-				sde_kms->splash_data.splash_base,
-				sde_kms->splash_data.splash_size);
-		if (rc)
-			pr_err("Failed to release splash memory\n");
-		sde_kms->splash_data.splash_base = 0;
-		sde_kms->splash_data.splash_size = 0;
-	}
 }
 
 static void sde_kms_wait_for_commit_done(struct msm_kms *kms,
@@ -2704,6 +2727,19 @@
 	return rc;
 }
 
+static bool sde_kms_check_for_splash(struct msm_kms *kms)
+{
+	struct sde_kms *sde_kms;
+
+	if (!kms) {
+		SDE_ERROR("invalid kms\n");
+		return false;
+	}
+
+	sde_kms = to_sde_kms(kms);
+	return sde_kms->splash_data.cont_splash_en;
+}
+
 static int sde_kms_pm_suspend(struct device *dev)
 {
 	struct drm_device *ddev;
@@ -2904,6 +2940,7 @@
 	.register_events = _sde_kms_register_events,
 	.get_address_space = _sde_kms_get_address_space,
 	.postopen = _sde_kms_post_open,
+	.check_for_splash = sde_kms_check_for_splash,
 };
 
 /* the caller api needs to turn on clock before calling it */
@@ -2956,8 +2993,7 @@
 		 * address. To facilitate this requirement we need to have a
 		 * one to one mapping on SMMU until we have our first frame.
 		 */
-		if ((i == MSM_SMMU_DOMAIN_UNSECURE) &&
-			sde_kms->splash_data.smmu_handoff_pending) {
+		if (i == MSM_SMMU_DOMAIN_UNSECURE) {
 			ret = mmu->funcs->set_attribute(mmu,
 				DOMAIN_ATTR_EARLY_MAP,
 				&early_map);
@@ -2986,27 +3022,27 @@
 		}
 		aspace->domain_attached = true;
 		early_map = 0;
+
 		/* Mapping splash memory block */
 		if ((i == MSM_SMMU_DOMAIN_UNSECURE) &&
-			sde_kms->splash_data.smmu_handoff_pending) {
+				sde_kms->splash_data.splash_base) {
 			ret = _sde_kms_splash_smmu_map(sde_kms->dev, mmu,
 					&sde_kms->splash_data);
 			if (ret) {
 				SDE_ERROR("failed to map ret:%d\n", ret);
 				goto fail;
 			}
-			/*
-			 * Turning off early map after generating one to one
-			 * mapping for splash address space.
-			 */
-			ret = mmu->funcs->set_attribute(mmu,
-				DOMAIN_ATTR_EARLY_MAP,
-				&early_map);
-			if (ret) {
-				SDE_ERROR("failed to set map att ret:%d\n",
-									ret);
-				goto early_map_fail;
-			}
+		}
+
+		/*
+		 * Turning off early map after generating one to one
+		 * mapping for splash address space.
+		 */
+		ret = mmu->funcs->set_attribute(mmu, DOMAIN_ATTR_EARLY_MAP,
+			&early_map);
+		if (ret) {
+			SDE_ERROR("failed to set map att ret:%d\n", ret);
+			goto early_map_fail;
 		}
 	}
 
@@ -3285,12 +3321,7 @@
 					&sde_kms->splash_data,
 					sde_kms->catalog);
 
-	/*
-	 * SMMU handoff is necessary for continuous splash enabled
-	 * scenario.
-	 */
-	if (sde_kms->splash_data.cont_splash_en)
-		sde_kms->splash_data.smmu_handoff_pending = true;
+	sde_kms->splash_data.resource_handoff_pending = true;
 
 	/* Initialize reg dma block which is a singleton */
 	rc = sde_reg_dma_init(sde_kms->reg_dma, sde_kms->catalog,
diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c
index 505dee0db..ca91651 100644
--- a/drivers/gpu/drm/omapdrm/omap_gem.c
+++ b/drivers/gpu/drm/omapdrm/omap_gem.c
@@ -195,7 +195,7 @@
 	size_t size = PAGE_SIZE * n;
 	loff_t off = mmap_offset(obj) +
 			(entry->obj_pgoff << PAGE_SHIFT);
-	const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE);
+	const int m = DIV_ROUND_UP(omap_obj->width << fmt, PAGE_SIZE);
 
 	if (m > 1) {
 		int i;
@@ -442,7 +442,7 @@
 	 * into account in some of the math, so figure out virtual stride
 	 * in pages
 	 */
-	const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE);
+	const int m = DIV_ROUND_UP(omap_obj->width << fmt, PAGE_SIZE);
 
 	/* We don't use vmf->pgoff since that has the fake offset: */
 	pgoff = ((unsigned long)vmf->virtual_address -
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index 41b72ce..83e1345 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -238,9 +238,10 @@
 	 * may be slow
 	 * See https://bugs.freedesktop.org/show_bug.cgi?id=88758
 	 */
-
+#ifndef CONFIG_COMPILE_TEST
 #warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \
 	 thanks to write-combining
+#endif
 
 	if (bo->flags & RADEON_GEM_GTT_WC)
 		DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for "
diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c
index 574ab00..b82ef5e 100644
--- a/drivers/gpu/drm/radeon/si_dpm.c
+++ b/drivers/gpu/drm/radeon/si_dpm.c
@@ -5969,9 +5969,9 @@
 {
 	u32 lane_width;
 	u32 new_lane_width =
-		(radeon_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT;
+		((radeon_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
 	u32 current_lane_width =
-		(radeon_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT;
+		((radeon_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
 
 	if (new_lane_width != current_lane_width) {
 		radeon_set_pcie_lanes(rdev, new_lane_width);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 6e3c4ac..32d87c6 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -1386,6 +1386,9 @@
 	usleep_range(10, 20);
 	reset_control_deassert(ahb_rst);
 
+	VOP_INTR_SET_TYPE(vop, clear, INTR_MASK, 1);
+	VOP_INTR_SET_TYPE(vop, enable, INTR_MASK, 0);
+
 	memcpy(vop->regsbak, vop->regs, vop->len);
 
 	for (i = 0; i < vop_data->table_size; i++)
@@ -1541,17 +1544,9 @@
 
 	mutex_init(&vop->vsync_mutex);
 
-	ret = devm_request_irq(dev, vop->irq, vop_isr,
-			       IRQF_SHARED, dev_name(dev), vop);
-	if (ret)
-		return ret;
-
-	/* IRQ is initially disabled; it gets enabled in power_on */
-	disable_irq(vop->irq);
-
 	ret = vop_create_crtc(vop);
 	if (ret)
-		goto err_enable_irq;
+		return ret;
 
 	pm_runtime_enable(&pdev->dev);
 
@@ -1561,13 +1556,19 @@
 		goto err_disable_pm_runtime;
 	}
 
+	ret = devm_request_irq(dev, vop->irq, vop_isr,
+			       IRQF_SHARED, dev_name(dev), vop);
+	if (ret)
+		goto err_disable_pm_runtime;
+
+	/* IRQ is initially disabled; it gets enabled in power_on */
+	disable_irq(vop->irq);
+
 	return 0;
 
 err_disable_pm_runtime:
 	pm_runtime_disable(&pdev->dev);
 	vop_destroy_crtc(vop);
-err_enable_irq:
-	enable_irq(vop->irq); /* To balance out the disable_irq above */
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 9e77fc0..aad2f4a 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -212,6 +212,11 @@
 	.unbind	= sun4i_drv_unbind,
 };
 
+static bool sun4i_drv_node_is_connector(struct device_node *node)
+{
+	return of_device_is_compatible(node, "hdmi-connector");
+}
+
 static bool sun4i_drv_node_is_frontend(struct device_node *node)
 {
 	return of_device_is_compatible(node, "allwinner,sun5i-a13-display-frontend") ||
@@ -252,6 +257,13 @@
 	    !of_device_is_available(node))
 		return 0;
 
+	/*
+	 * The connectors will be the last nodes in our pipeline, we
+	 * can just bail out.
+	 */
+	if (sun4i_drv_node_is_connector(node))
+		return 0;
+
 	if (!sun4i_drv_node_is_frontend(node)) {
 		/* Add current component */
 		DRM_DEBUG_DRIVER("Adding component %s\n",
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index ab30169..b608cd4 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -110,8 +110,8 @@
 					    &handle);
 
 		if (ret) {
-			state->bo_count = i - 1;
-			goto err;
+			state->bo_count = i;
+			goto err_delete_handle;
 		}
 		bo_state[i].handle = handle;
 		bo_state[i].paddr = vc4_bo->base.paddr;
@@ -123,13 +123,16 @@
 			 state->bo_count * sizeof(*bo_state)))
 		ret = -EFAULT;
 
-	kfree(bo_state);
+err_delete_handle:
+	if (ret) {
+		for (i = 0; i < state->bo_count; i++)
+			drm_gem_handle_delete(file_priv, bo_state[i].handle);
+	}
 
 err_free:
-
 	vc4_free_hang_state(dev, kernel_state);
+	kfree(bo_state);
 
-err:
 	return ret;
 }
 
diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h
index f7e9eb3..614b1c7 100644
--- a/drivers/gpu/msm/adreno-gpulist.h
+++ b/drivers/gpu/msm/adreno-gpulist.h
@@ -207,9 +207,11 @@
 		.major = 0,
 		.minor = 4,
 		.patchid = ANY_ID,
-		.features = ADRENO_PREEMPTION | ADRENO_64BIT,
+		.features = ADRENO_PREEMPTION | ADRENO_64BIT |
+			ADRENO_CONTENT_PROTECTION | ADRENO_CPZ_RETENTION,
 		.pm4fw_name = "a530_pm4.fw",
 		.pfpfw_name = "a530_pfp.fw",
+		.zap_name = "a506_zap",
 		.gpudev = &adreno_a5xx_gpudev,
 		.gmem_size = (SZ_128K + SZ_8K),
 		.num_protected_regs = 0x20,
@@ -221,9 +223,11 @@
 		.major = 0,
 		.minor = 5,
 		.patchid = ANY_ID,
-		.features = ADRENO_PREEMPTION | ADRENO_64BIT,
+		.features = ADRENO_PREEMPTION | ADRENO_64BIT |
+			ADRENO_CONTENT_PROTECTION | ADRENO_CPZ_RETENTION,
 		.pm4fw_name = "a530_pm4.fw",
 		.pfpfw_name = "a530_pfp.fw",
+		.zap_name = "a506_zap",
 		.gpudev = &adreno_a5xx_gpudev,
 		.gmem_size = (SZ_128K + SZ_8K),
 		.num_protected_regs = 0x20,
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 44ecb0b..8e21958 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -1808,7 +1808,7 @@
 		return ret;
 	}
 	adreno_readreg(adreno_dev, ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI, &val);
-	if (val != *perfctr_pwr_hi) {
+	if (val > *perfctr_pwr_hi) {
 		*perfctr_pwr_hi = val;
 		ret = true;
 	}
@@ -1823,14 +1823,17 @@
 	unsigned int ret = 0;
 	bool overflow = true;
 	static unsigned int perfctr_pwr_hi;
+	unsigned int prev_perfctr_pwr_hi = 0;
 
 	/* Read the value */
 	kgsl_regread(device, reg, &val);
 
 	if (adreno_is_a5xx(adreno_dev) && reg == adreno_getreg
-		(adreno_dev, ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO))
+		(adreno_dev, ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO)) {
+		prev_perfctr_pwr_hi = perfctr_pwr_hi;
 		overflow = is_power_counter_overflow(adreno_dev, reg,
 				*counter, &perfctr_pwr_hi);
+	}
 
 	/* Return 0 for the first read */
 	if (*counter != 0) {
@@ -1843,9 +1846,12 @@
 			 * Since KGSL got abnormal value from the counter,
 			 * We will drop the value from being accumulated.
 			 */
-			pr_warn_once("KGSL: Abnormal value :0x%x (0x%x) from perf counter : 0x%x\n",
-					val, *counter, reg);
-			return 0;
+			KGSL_DRV_ERR_RATELIMIT(device,
+				"Abnormal value:0x%llx (0x%llx) from perf counter : 0x%x\n",
+				val | ((uint64_t)perfctr_pwr_hi << 32),
+				*counter |
+					((uint64_t)prev_perfctr_pwr_hi << 32),
+				reg);
 		}
 	}
 
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index 7ddb6fe..876b7c9 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -2226,6 +2226,13 @@
 				upper_32_bits(gpuaddr));
 
 	/*
+	 * Do not invoke to load zap shader if MMU does
+	 * not support secure mode.
+	 */
+	if (!device->mmu.secured)
+		return 0;
+
+	/*
 	 * Resume call to write the zap shader base address into the
 	 * appropriate register,
 	 * skip if retention is supported for the CPZ register
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index f2c18b7..37330cb 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -853,6 +853,13 @@
 	kgsl_regwrite(device, A6XX_CP_SQE_INSTR_BASE_HI,
 				upper_32_bits(gpuaddr));
 
+	/*
+	 * Do not invoke to load zap shader if MMU does
+	 * not support secure mode.
+	 */
+	if (!device->mmu.secured)
+		return 0;
+
 	/* Load the zap shader firmware through PIL if its available */
 	if (adreno_dev->gpucore->zap_name && !adreno_dev->zap_loaded) {
 		/*
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index b8c282d..a634d98 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -208,8 +208,8 @@
 	if (!kgsl_state_is_awake(KGSL_DEVICE(adreno_dev)))
 		goto ret;
 
-	if (adreno_rb_empty(adreno_dev->cur_rb))
-		goto ret;
+	if (!adreno_rb_empty(adreno_dev->cur_rb))
+		return false;
 
 	/* only check rbbm status to determine if GPU is idle */
 	adreno_readreg(adreno_dev, ADRENO_REG_RBBM_STATUS, &reg_rbbm_status);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 2e84bad..14653ea 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -110,27 +110,25 @@
 		id++, entry = idr_get_next(&priv->mem_idr, &id)) {
 
 		int egl_surface_count = 0, egl_image_count = 0;
-		struct kgsl_memdesc *m;
+		struct kgsl_memdesc *m = &entry->memdesc;
 
-		if (kgsl_mem_entry_get(entry) == 0)
+		if ((kgsl_memdesc_usermem_type(m) != KGSL_MEM_ENTRY_ION) ||
+			entry->pending_free || (kgsl_mem_entry_get(entry) == 0))
 			continue;
 		spin_unlock(&priv->mem_lock);
 
-		m = &entry->memdesc;
-		if (kgsl_memdesc_usermem_type(m) == KGSL_MEM_ENTRY_ION) {
-			kgsl_get_egl_counts(entry, &egl_surface_count,
-					&egl_image_count);
+		kgsl_get_egl_counts(entry, &egl_surface_count,
+				&egl_image_count);
 
-			if (kgsl_memdesc_get_memtype(m) ==
-						KGSL_MEMTYPE_EGL_SURFACE)
-				imported_mem += m->size;
-			else if (egl_surface_count == 0) {
-				uint64_t size = m->size;
+		if (kgsl_memdesc_get_memtype(m) ==
+				KGSL_MEMTYPE_EGL_SURFACE)
+			imported_mem += m->size;
+		else if (egl_surface_count == 0) {
+			uint64_t size = m->size;
 
-				do_div(size, (egl_image_count ?
-							egl_image_count : 1));
-				imported_mem += size;
-			}
+			do_div(size, (egl_image_count ?
+					egl_image_count : 1));
+			imported_mem += size;
 		}
 
 		kgsl_mem_entry_put(entry);
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index ac7d2c6..aea6267 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1370,7 +1370,7 @@
 	 * of implement() working on 8 byte chunks
 	 */
 
-	int len = hid_report_len(report) + 7;
+	u32 len = hid_report_len(report) + 7;
 
 	return kmalloc(len, flags);
 }
@@ -1435,7 +1435,7 @@
 {
 	char *buf;
 	int ret;
-	int len;
+	u32 len;
 
 	buf = hid_alloc_report_buf(report, GFP_KERNEL);
 	if (!buf)
@@ -1461,14 +1461,14 @@
 }
 EXPORT_SYMBOL_GPL(__hid_request);
 
-int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
 		int interrupt)
 {
 	struct hid_report_enum *report_enum = hid->report_enum + type;
 	struct hid_report *report;
 	struct hid_driver *hdrv;
 	unsigned int a;
-	int rsize, csize = size;
+	u32 rsize, csize = size;
 	u8 *cdata = data;
 	int ret = 0;
 
@@ -1526,7 +1526,7 @@
  *
  * This is data entry for lower layers.
  */
-int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt)
+int hid_input_report(struct hid_device *hid, int type, u8 *data, u32 size, int interrupt)
 {
 	struct hid_report_enum *report_enum;
 	struct hid_driver *hdrv;
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 40233315..5ff6dd8 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -1279,7 +1279,8 @@
 					      led_work);
 	struct hid_field *field;
 	struct hid_report *report;
-	int len, ret;
+	int ret;
+	u32 len;
 	__u8 *buf;
 
 	field = hidinput_get_led_field(hid);
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 89e9032..fba655d 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -315,7 +315,8 @@
 static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
 {
 	struct mt_device *td = hid_get_drvdata(hdev);
-	int ret, size = hid_report_len(report);
+	int ret;
+	u32 size = hid_report_len(report);
 	u8 *buf;
 
 	/*
@@ -919,7 +920,7 @@
 	struct hid_report_enum *re;
 	struct mt_class *cls = &td->mtclass;
 	char *buf;
-	int report_len;
+	u32 report_len;
 
 	if (td->inputmode < 0)
 		return;
diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c
index be89bcb..276d12d 100644
--- a/drivers/hid/hid-rmi.c
+++ b/drivers/hid/hid-rmi.c
@@ -110,8 +110,8 @@
 	u8 *writeReport;
 	u8 *readReport;
 
-	int input_report_size;
-	int output_report_size;
+	u32 input_report_size;
+	u32 output_report_size;
 
 	unsigned long flags;
 
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index b0bb99a..1b1dccd 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -1056,7 +1056,6 @@
 	u8 battery_charging;
 	u8 battery_capacity;
 	u8 led_state[MAX_LEDS];
-	u8 resume_led_state[MAX_LEDS];
 	u8 led_delay_on[MAX_LEDS];
 	u8 led_delay_off[MAX_LEDS];
 	u8 led_count;
@@ -1793,6 +1792,7 @@
 		led->name = name;
 		led->brightness = sc->led_state[n];
 		led->max_brightness = max_brightness[n];
+		led->flags = LED_CORE_SUSPENDRESUME;
 		led->brightness_get = sony_led_get_brightness;
 		led->brightness_set = sony_led_set_brightness;
 
@@ -2509,47 +2509,32 @@
 
 static int sony_suspend(struct hid_device *hdev, pm_message_t message)
 {
-	/*
-	 * On suspend save the current LED state,
-	 * stop running force-feedback and blank the LEDS.
-	 */
-	if (SONY_LED_SUPPORT || SONY_FF_SUPPORT) {
+#ifdef CONFIG_SONY_FF
+
+	/* On suspend stop any running force-feedback events */
+	if (SONY_FF_SUPPORT) {
 		struct sony_sc *sc = hid_get_drvdata(hdev);
 
-#ifdef CONFIG_SONY_FF
 		sc->left = sc->right = 0;
-#endif
-
-		memcpy(sc->resume_led_state, sc->led_state,
-			sizeof(sc->resume_led_state));
-		memset(sc->led_state, 0, sizeof(sc->led_state));
-
 		sony_send_output_report(sc);
 	}
 
+#endif
 	return 0;
 }
 
 static int sony_resume(struct hid_device *hdev)
 {
-	/* Restore the state of controller LEDs on resume */
-	if (SONY_LED_SUPPORT) {
-		struct sony_sc *sc = hid_get_drvdata(hdev);
+	struct sony_sc *sc = hid_get_drvdata(hdev);
 
-		memcpy(sc->led_state, sc->resume_led_state,
-			sizeof(sc->led_state));
-
-		/*
-		 * The Sixaxis and navigation controllers on USB need to be
-		 * reinitialized on resume or they won't behave properly.
-		 */
-		if ((sc->quirks & SIXAXIS_CONTROLLER_USB) ||
-			(sc->quirks & NAVIGATION_CONTROLLER_USB)) {
-			sixaxis_set_operational_usb(sc->hdev);
-			sc->defer_initialization = 1;
-		}
-
-		sony_set_leds(sc);
+	/*
+	 * The Sixaxis and navigation controllers on USB need to be
+	 * reinitialized on resume or they won't behave properly.
+	 */
+	if ((sc->quirks & SIXAXIS_CONTROLLER_USB) ||
+		(sc->quirks & NAVIGATION_CONTROLLER_USB)) {
+		sixaxis_set_operational_usb(sc->hdev);
+		sc->defer_initialization = 1;
 	}
 
 	return 0;
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index f0e2757..216f033 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -192,6 +192,11 @@
 	int ret = 0, len;
 	unsigned char report_number;
 
+	if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
+		ret = -ENODEV;
+		goto out;
+	}
+
 	dev = hidraw_table[minor]->hid;
 
 	if (!dev->ll_driver->raw_request) {
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index 865e7c2..2548c5d 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -142,10 +142,10 @@
 						   * register of the HID
 						   * descriptor. */
 	unsigned int		bufsize;	/* i2c buffer size */
-	char			*inbuf;		/* Input buffer */
-	char			*rawbuf;	/* Raw Input buffer */
-	char			*cmdbuf;	/* Command buffer */
-	char			*argsbuf;	/* Command arguments buffer */
+	u8			*inbuf;		/* Input buffer */
+	u8			*rawbuf;	/* Raw Input buffer */
+	u8			*cmdbuf;	/* Command buffer */
+	u8			*argsbuf;	/* Command arguments buffer */
 
 	unsigned long		flags;		/* device flags */
 	unsigned long		quirks;		/* Various quirks */
@@ -451,7 +451,8 @@
 
 static void i2c_hid_get_input(struct i2c_hid *ihid)
 {
-	int ret, ret_size;
+	int ret;
+	u32 ret_size;
 	int size = le16_to_cpu(ihid->hdesc.wMaxInputLength);
 
 	if (size > ihid->bufsize)
@@ -476,7 +477,7 @@
 		return;
 	}
 
-	if (ret_size > size) {
+	if ((ret_size > size) || (ret_size <= 2)) {
 		dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n",
 			__func__, size, ret_size);
 		return;
@@ -968,6 +969,15 @@
 	return ret < 0 && ret != -ENXIO ? ret : 0;
 }
 
+static void i2c_hid_acpi_fix_up_power(struct device *dev)
+{
+	acpi_handle handle = ACPI_HANDLE(dev);
+	struct acpi_device *adev;
+
+	if (handle && acpi_bus_get_device(handle, &adev) == 0)
+		acpi_device_fix_up_power(adev);
+}
+
 static const struct acpi_device_id i2c_hid_acpi_match[] = {
 	{"ACPI0C50", 0 },
 	{"PNP0C50", 0 },
@@ -980,6 +990,8 @@
 {
 	return -ENODEV;
 }
+
+static inline void i2c_hid_acpi_fix_up_power(struct device *dev) {}
 #endif
 
 #ifdef CONFIG_OF
@@ -1082,6 +1094,8 @@
 	if (ret < 0)
 		goto err;
 
+	i2c_hid_acpi_fix_up_power(&client->dev);
+
 	pm_runtime_get_noresume(&client->dev);
 	pm_runtime_set_active(&client->dev);
 	pm_runtime_enable(&client->dev);
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 7a4d39c..e8b90b5 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -351,7 +351,7 @@
 	u8 *rep_data;
 	struct hid_report *r;
 	struct hid_report_enum *re;
-	int length;
+	u32 length;
 	int error = -ENOMEM, limit = 0;
 
 	if (wacom_wac->mode_report < 0)
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index d8bc4b9..9360cdc 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -70,7 +70,7 @@
 	/* PCIE */
 	{ .dev_type = HV_PCIE,
 	  HV_PCIE_GUID,
-	  .perf_device = true,
+	  .perf_device = false,
 	},
 
 	/* Synthetic Frame Buffer */
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index b24f1d3..ac63e56 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -94,18 +94,20 @@
 
 struct ina2xx_config {
 	u16 config_default;
-	int calibration_factor;
+	int calibration_value;
 	int registers;
 	int shunt_div;
 	int bus_voltage_shift;
 	int bus_voltage_lsb;	/* uV */
-	int power_lsb;		/* uW */
+	int power_lsb_factor;
 };
 
 struct ina2xx_data {
 	const struct ina2xx_config *config;
 
 	long rshunt;
+	long current_lsb_uA;
+	long power_lsb_uW;
 	struct mutex config_lock;
 	struct regmap *regmap;
 
@@ -115,21 +117,21 @@
 static const struct ina2xx_config ina2xx_config[] = {
 	[ina219] = {
 		.config_default = INA219_CONFIG_DEFAULT,
-		.calibration_factor = 40960000,
+		.calibration_value = 4096,
 		.registers = INA219_REGISTERS,
 		.shunt_div = 100,
 		.bus_voltage_shift = 3,
 		.bus_voltage_lsb = 4000,
-		.power_lsb = 20000,
+		.power_lsb_factor = 20,
 	},
 	[ina226] = {
 		.config_default = INA226_CONFIG_DEFAULT,
-		.calibration_factor = 5120000,
+		.calibration_value = 2048,
 		.registers = INA226_REGISTERS,
 		.shunt_div = 400,
 		.bus_voltage_shift = 0,
 		.bus_voltage_lsb = 1250,
-		.power_lsb = 25000,
+		.power_lsb_factor = 25,
 	},
 };
 
@@ -168,12 +170,16 @@
 	return INA226_SHIFT_AVG(avg_bits);
 }
 
+/*
+ * Calibration register is set to the best value, which eliminates
+ * truncation errors on calculating current register in hardware.
+ * According to datasheet (eq. 3) the best values are 2048 for
+ * ina226 and 4096 for ina219. They are hardcoded as calibration_value.
+ */
 static int ina2xx_calibrate(struct ina2xx_data *data)
 {
-	u16 val = DIV_ROUND_CLOSEST(data->config->calibration_factor,
-				    data->rshunt);
-
-	return regmap_write(data->regmap, INA2XX_CALIBRATION, val);
+	return regmap_write(data->regmap, INA2XX_CALIBRATION,
+			    data->config->calibration_value);
 }
 
 /*
@@ -186,10 +192,6 @@
 	if (ret < 0)
 		return ret;
 
-	/*
-	 * Set current LSB to 1mA, shunt is in uOhms
-	 * (equation 13 in datasheet).
-	 */
 	return ina2xx_calibrate(data);
 }
 
@@ -267,15 +269,15 @@
 		val = DIV_ROUND_CLOSEST(val, 1000);
 		break;
 	case INA2XX_POWER:
-		val = regval * data->config->power_lsb;
+		val = regval * data->power_lsb_uW;
 		break;
 	case INA2XX_CURRENT:
-		/* signed register, LSB=1mA (selected), in mA */
-		val = (s16)regval;
+		/* signed register, result in mA */
+		val = regval * data->current_lsb_uA;
+		val = DIV_ROUND_CLOSEST(val, 1000);
 		break;
 	case INA2XX_CALIBRATION:
-		val = DIV_ROUND_CLOSEST(data->config->calibration_factor,
-					regval);
+		val = regval;
 		break;
 	default:
 		/* programmer goofed */
@@ -303,9 +305,32 @@
 			ina2xx_get_value(data, attr->index, regval));
 }
 
-static ssize_t ina2xx_set_shunt(struct device *dev,
-				struct device_attribute *da,
-				const char *buf, size_t count)
+/*
+ * In order to keep calibration register value fixed, the product
+ * of current_lsb and shunt_resistor should also be fixed and equal
+ * to shunt_voltage_lsb = 1 / shunt_div multiplied by 10^9 in order
+ * to keep the scale.
+ */
+static int ina2xx_set_shunt(struct ina2xx_data *data, long val)
+{
+	unsigned int dividend = DIV_ROUND_CLOSEST(1000000000,
+						  data->config->shunt_div);
+	if (val <= 0 || val > dividend)
+		return -EINVAL;
+
+	mutex_lock(&data->config_lock);
+	data->rshunt = val;
+	data->current_lsb_uA = DIV_ROUND_CLOSEST(dividend, val);
+	data->power_lsb_uW = data->config->power_lsb_factor *
+			     data->current_lsb_uA;
+	mutex_unlock(&data->config_lock);
+
+	return 0;
+}
+
+static ssize_t ina2xx_store_shunt(struct device *dev,
+				  struct device_attribute *da,
+				  const char *buf, size_t count)
 {
 	unsigned long val;
 	int status;
@@ -315,18 +340,9 @@
 	if (status < 0)
 		return status;
 
-	if (val == 0 ||
-	    /* Values greater than the calibration factor make no sense. */
-	    val > data->config->calibration_factor)
-		return -EINVAL;
-
-	mutex_lock(&data->config_lock);
-	data->rshunt = val;
-	status = ina2xx_calibrate(data);
-	mutex_unlock(&data->config_lock);
+	status = ina2xx_set_shunt(data, val);
 	if (status < 0)
 		return status;
-
 	return count;
 }
 
@@ -386,7 +402,7 @@
 
 /* shunt resistance */
 static SENSOR_DEVICE_ATTR(shunt_resistor, S_IRUGO | S_IWUSR,
-			  ina2xx_show_value, ina2xx_set_shunt,
+			  ina2xx_show_value, ina2xx_store_shunt,
 			  INA2XX_CALIBRATION);
 
 /* update interval (ina226 only) */
@@ -431,6 +447,7 @@
 
 	/* set the device type */
 	data->config = &ina2xx_config[id->driver_data];
+	mutex_init(&data->config_lock);
 
 	if (of_property_read_u32(dev->of_node, "shunt-resistor", &val) < 0) {
 		struct ina2xx_platform_data *pdata = dev_get_platdata(dev);
@@ -441,10 +458,7 @@
 			val = INA2XX_RSHUNT_DEFAULT;
 	}
 
-	if (val <= 0 || val > data->config->calibration_factor)
-		return -ENODEV;
-
-	data->rshunt = val;
+	ina2xx_set_shunt(data, val);
 
 	ina2xx_regmap_config.max_register = data->config->registers;
 
@@ -460,8 +474,6 @@
 		return -ENODEV;
 	}
 
-	mutex_init(&data->config_lock);
-
 	data->groups[group++] = &ina2xx_group;
 	if (id->driver_data == ina226)
 		data->groups[group++] = &ina226_group;
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index f396c76..b900f76 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -2495,6 +2495,12 @@
 		}
 	}
 
+	if (of_device_is_compatible(node, "qcom,qpnp-adc-hc-pm5") ||
+		of_device_is_compatible(node, "qcom,qpnp-adc-tm-hc-pm5"))
+		adc_prop->is_pmic_5 = true;
+	else
+		adc_prop->is_pmic_5 = false;
+
 	for_each_child_of_node(node, child) {
 		int channel_num, scaling = 0, post_scaling = 0;
 		int fast_avg_setup, calib_type = 0, rc, hw_settle_time = 0;
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index ed5222e..7e6af65 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -35,8 +35,6 @@
 #include <linux/power_supply.h>
 #include <linux/thermal.h>
 
-#define QPNP_VADC_HC_VREF_CODE	0x4000
-
 /* QPNP VADC register definition */
 #define QPNP_VADC_REVISION1				0x0
 #define QPNP_VADC_REVISION2				0x1
@@ -508,7 +506,7 @@
 		goto fail_unlock;
 	}
 
-	if (vadc->adc->adc_prop->full_scale_code == QPNP_VADC_HC_VREF_CODE) {
+	if (!vadc->adc->adc_prop->is_pmic_5) {
 		if (!vadc->vadc_init_calib) {
 			rc = qpnp_vadc_calib_device(vadc);
 			if (rc) {
@@ -2595,6 +2593,8 @@
 	},
 	{	.compatible = "qcom,qpnp-vadc-hc",
 	},
+	{	.compatible = "qcom,qpnp-adc-hc-pm5",
+	},
 	{}
 };
 
diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c
index f57ad2e..3bbcc95 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2012, 2016, 2018, The Linux Foundation. All rights reserved.
  *
  * Description: CoreSight Program Flow Trace driver
  *
@@ -39,6 +39,7 @@
 
 #include "coresight-etm.h"
 #include "coresight-etm-perf.h"
+#include "coresight-priv.h"
 
 /*
  * Not really modular but using module_param is the easiest way to
@@ -711,6 +712,10 @@
 
 	CS_UNLOCK(drvdata->base);
 
+	/* check the state of the fuse */
+	if (!coresight_authstatus_enabled(drvdata->base))
+		goto out;
+
 	/* First dummy read */
 	(void)etm_readl(drvdata, ETMPDSR);
 	/* Provide power to ETM: ETMPDCR[3] == 1 */
@@ -742,6 +747,7 @@
 
 	etm_set_pwrdwn(drvdata);
 	etm_clr_pwrup(drvdata);
+out:
 	CS_LOCK(drvdata->base);
 }
 
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index a4bf109..5db74f0 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014, 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -38,6 +38,7 @@
 
 #include "coresight-etm4x.h"
 #include "coresight-etm-perf.h"
+#include "coresight-priv.h"
 
 static int boot_enable;
 module_param_named(boot_enable, boot_enable, int, 0444);
@@ -436,6 +437,9 @@
 
 	CS_UNLOCK(drvdata->base);
 
+	if (!coresight_authstatus_enabled(drvdata->base))
+		goto out;
+
 	/* find all capabilities of the tracing unit */
 	etmidr0 = readl_relaxed(drvdata->base + TRCIDR0);
 
@@ -582,6 +586,8 @@
 	drvdata->nrseqstate = BMVAL(etmidr5, 25, 27);
 	/* NUMCNTR, bits[30:28] number of counters available for tracing */
 	drvdata->nr_cntr = BMVAL(etmidr5, 28, 30);
+
+out:
 	CS_LOCK(drvdata->base);
 }
 
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 87d9162..287f901 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -733,6 +733,13 @@
 		ret = tmc_etr_bam_init(adev, drvdata);
 		if (ret)
 			goto out;
+		/*
+		 * ETR configuration uses a 40-bit AXI master in place of
+		 * the embedded SRAM of ETB/ETF.
+		 */
+		ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
+		if (ret)
+			goto out;
 	} else {
 		desc.type = CORESIGHT_DEV_TYPE_LINKSINK;
 		desc.ops = &tmc_etf_cs_ops;
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c
index 1cf60f3..85a16b1 100644
--- a/drivers/hwtracing/coresight/coresight.c
+++ b/drivers/hwtracing/coresight/coresight.c
@@ -589,6 +589,9 @@
 	int ret = 0;
 	struct coresight_device *sink;
 	struct list_head *path;
+	enum coresight_dev_subtype_source subtype;
+
+	subtype = csdev->subtype.source_subtype;
 
 	mutex_lock(&coresight_mutex);
 
@@ -596,8 +599,16 @@
 	if (ret)
 		goto out;
 
-	if (csdev->enable)
+	if (csdev->enable) {
+		/*
+		 * There could be multiple applications driving the software
+		 * source. So keep the refcount for each such user when the
+		 * source is already enabled.
+		 */
+		if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
+			atomic_inc(csdev->refcnt);
 		goto out;
+	}
 
 	/*
 	 * Search for a valid sink for this session but don't reset the
diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c
index c6a90b4..91b10af 100644
--- a/drivers/i2c/muxes/i2c-mux-reg.c
+++ b/drivers/i2c/muxes/i2c-mux-reg.c
@@ -196,20 +196,25 @@
 		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 		mux->data.reg_size = resource_size(res);
 		mux->data.reg = devm_ioremap_resource(&pdev->dev, res);
-		if (IS_ERR(mux->data.reg))
-			return PTR_ERR(mux->data.reg);
+		if (IS_ERR(mux->data.reg)) {
+			ret = PTR_ERR(mux->data.reg);
+			goto err_put_parent;
+		}
 	}
 
 	if (mux->data.reg_size != 4 && mux->data.reg_size != 2 &&
 	    mux->data.reg_size != 1) {
 		dev_err(&pdev->dev, "Invalid register size\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err_put_parent;
 	}
 
 	muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, 0, 0,
 			     i2c_mux_reg_select, NULL);
-	if (!muxc)
-		return -ENOMEM;
+	if (!muxc) {
+		ret = -ENOMEM;
+		goto err_put_parent;
+	}
 	muxc->priv = mux;
 
 	platform_set_drvdata(pdev, muxc);
@@ -235,6 +240,8 @@
 
 add_adapter_failed:
 	i2c_mux_del_adapters(muxc);
+err_put_parent:
+	i2c_put_adapter(parent);
 
 	return ret;
 }
diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c
index 678e8c7..fec696e 100644
--- a/drivers/iio/adc/hi8435.c
+++ b/drivers/iio/adc/hi8435.c
@@ -121,10 +121,21 @@
 				     enum iio_event_direction dir, int state)
 {
 	struct hi8435_priv *priv = iio_priv(idev);
+	int ret;
+	u32 tmp;
 
-	priv->event_scan_mask &= ~BIT(chan->channel);
-	if (state)
+	if (state) {
+		ret = hi8435_readl(priv, HI8435_SO31_0_REG, &tmp);
+		if (ret < 0)
+			return ret;
+		if (tmp & BIT(chan->channel))
+			priv->event_prev_val |= BIT(chan->channel);
+		else
+			priv->event_prev_val &= ~BIT(chan->channel);
+
 		priv->event_scan_mask |= BIT(chan->channel);
+	} else
+		priv->event_scan_mask &= ~BIT(chan->channel);
 
 	return 0;
 }
@@ -442,13 +453,15 @@
 	priv->spi = spi;
 
 	reset_gpio = devm_gpiod_get(&spi->dev, NULL, GPIOD_OUT_LOW);
-	if (IS_ERR(reset_gpio)) {
-		/* chip s/w reset if h/w reset failed */
+	if (!IS_ERR(reset_gpio)) {
+		/* need >=100ns low pulse to reset chip */
+		gpiod_set_raw_value_cansleep(reset_gpio, 0);
+		udelay(1);
+		gpiod_set_raw_value_cansleep(reset_gpio, 1);
+	} else {
+		/* s/w reset chip if h/w reset is not available */
 		hi8435_writeb(priv, HI8435_CTRL_REG, HI8435_CTRL_SRST);
 		hi8435_writeb(priv, HI8435_CTRL_REG, 0);
-	} else {
-		udelay(5);
-		gpiod_set_value(reset_gpio, 1);
 	}
 
 	spi_set_drvdata(spi, idev);
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 1f1ad41..0a8b763 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -39,6 +39,7 @@
 	  be called kmx61.
 
 source "drivers/iio/imu/inv_mpu6050/Kconfig"
+source "drivers/iio/imu/inv_icm20602/Kconfig"
 
 endmenu
 
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index c71bcd3..fab6a5e 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -15,5 +15,6 @@
 
 obj-y += bmi160/
 obj-y += inv_mpu6050/
+obj-y += inv_icm20602/
 
 obj-$(CONFIG_KMX61) += kmx61.o
diff --git a/drivers/iio/imu/inv_icm20602/Kconfig b/drivers/iio/imu/inv_icm20602/Kconfig
new file mode 100644
index 0000000..fa88689
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20602/Kconfig
@@ -0,0 +1,14 @@
+#
+# inv-icm20602 drivers for Invensense MPU devices and combos
+#
+config INV_ICM20602_IIO
+	tristate "Invensense ICM20602 devices"
+	depends on I2C && SYSFS
+	select IIO_BUFFER
+	select IIO_BUFFER_CB
+	select IIO_TRIGGERED_BUFFER
+	help
+	  This driver supports the Invensense ICM20602 devices.
+	  It is a gyroscope/accelerometer combo device.
+	  This driver can be built as a module. The module will be called
+	  inv-icm20602.
diff --git a/drivers/iio/imu/inv_icm20602/Makefile b/drivers/iio/imu/inv_icm20602/Makefile
new file mode 100644
index 0000000..d60c10a
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20602/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for Invensense icm20602 device.
+#
+
+obj-$(CONFIG_INV_ICM20602_IIO) += inv-icm20602.o
+inv-icm20602-objs := inv_icm20602_core.o inv_icm20602_ring.o inv_icm20602_trigger.o inv_icm20602_bsp.o
diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c
new file mode 100644
index 0000000..bfff285
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c
@@ -0,0 +1,932 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/kfifo.h>
+#include <linux/poll.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include "inv_icm20602_bsp.h"
+#include "inv_icm20602_iio.h"
+
+#define icm20602_init_reg_addr(head, tail, reg_map) { \
+			enum inv_icm20602_reg_addr i;\
+			for (i = head; i <= tail; i++) {\
+				reg_map->address = i;\
+				reg_map->reg_u.reg = 0x0;\
+				reg_map++;\
+			} \
+}
+
+#define icm20602_write_reg_simple(st, register) \
+		icm20602_write_reg(st, \
+		register.address, \
+		register.reg_u.reg)
+
+static struct inv_icm20602_reg_map reg_set_20602;
+
+int icm20602_init_reg_map(void)
+{
+	struct struct_XG_OFFS_TC_H *reg_map = &(reg_set_20602.XG_OFFS_TC_H);
+
+	icm20602_init_reg_addr(ADDR_XG_OFFS_TC_H,
+			ADDR_XG_OFFS_TC_L, reg_map);
+
+	icm20602_init_reg_addr(ADDR_YG_OFFS_TC_H,
+			ADDR_YG_OFFS_TC_L, reg_map);
+
+	icm20602_init_reg_addr(ADDR_ZG_OFFS_TC_H,
+			ADDR_ZG_OFFS_TC_L, reg_map);
+
+	icm20602_init_reg_addr(ADDR_SELF_TEST_X_ACCEL,
+			ADDR_SELF_TEST_Z_ACCEL, reg_map);
+
+	icm20602_init_reg_addr(ADDR_XG_OFFS_USRH,
+			ADDR_LP_MODE_CFG, reg_map);
+
+	icm20602_init_reg_addr(ADDR_ACCEL_WOM_X_THR,
+			ADDR_FIFO_EN, reg_map);
+
+	icm20602_init_reg_addr(ADDR_FSYNC_INT,
+			ADDR_GYRO_ZOUT_L, reg_map);
+
+	icm20602_init_reg_addr(ADDR_SELF_TEST_X_GYRO,
+			ADDR_SELF_TEST_Z_GYRO, reg_map);
+
+	icm20602_init_reg_addr(ADDR_FIFO_WM_TH1,
+			ADDR_FIFO_WM_TH2, reg_map);
+
+	icm20602_init_reg_addr(ADDR_SIGNAL_PATH_RESET,
+			ADDR_PWR_MGMT_2, reg_map);
+
+	icm20602_init_reg_addr(ADDR_I2C_IF,
+			ADDR_I2C_IF, reg_map);
+
+	icm20602_init_reg_addr(ADDR_FIFO_COUNTH,
+			ADDR_XA_OFFSET_L, reg_map);
+
+	icm20602_init_reg_addr(ADDR_YA_OFFSET_H,
+			ADDR_YA_OFFSET_L, reg_map);
+
+	icm20602_init_reg_addr(ADDR_ZA_OFFSET_H,
+			ADDR_ZA_OFFSET_L, reg_map);
+
+	return MPU_SUCCESS;
+}
+
+#define W_FLG	0
+#define R_FLG	1
+int icm20602_bulk_read(struct inv_icm20602_state *st,
+			int reg, char *buf, int size)
+{
+	int result = MPU_SUCCESS;
+	char tx_buf[2] = {0x0, 0x0};
+	int tmp_size = size;
+	int tmp_buf = buf;
+	struct i2c_msg msg[2];
+
+	if (!st || !buf)
+		return -MPU_FAIL;
+
+	if (st->interface == ICM20602_SPI) {
+		tx_buf[0] = ICM20602_READ_REG(reg);
+		result = spi_write_then_read(st->spi, &tx_buf[0],
+			1, tmp_buf, size);
+		if (result) {
+			pr_err("mpu read reg %u failed, rc %d\n",
+				reg, result);
+			result = -MPU_READ_FAIL;
+		}
+	} else {
+		result = size;
+		while (tmp_size > 0) {
+#ifdef ICM20602_I2C_SMBUS
+			result += i2c_smbus_read_i2c_block_data(st->client,
+				reg, (tmp_size < 32)?tmp_size:32, tmp_buf);
+			tmp_size -= 32;
+			tmp_buf += tmp_size;
+#else
+			tx_buf[0] = reg;
+			msg[0].addr = st->client->addr;
+			msg[0].flags = W_FLG;
+			msg[0].len = 1;
+			msg[0].buf = tx_buf;
+
+			msg[1].addr = st->client->addr;
+			msg[1].flags = I2C_M_RD;
+			msg[1].len = (tmp_size < 32)?tmp_size:32;
+			msg[1].buf = tmp_buf;
+			i2c_transfer(st->client->adapter, msg, ARRAY_SIZE(msg));
+			tmp_size -= 32;
+			tmp_buf += tmp_size;
+#endif
+		}
+	}
+
+	return result;
+}
+
+static int icm20602_write_reg(struct inv_icm20602_state *st,
+			 uint8_t reg, uint8_t val)
+{
+	int result = MPU_SUCCESS;
+	char txbuf[2] = {0x0, 0x0};
+	struct i2c_msg msg[1];
+
+	if (st->interface == ICM20602_SPI) {
+		txbuf[0] = ICM20602_WRITE_REG(reg);
+		txbuf[1] = val;
+		result = spi_write_then_read(st->spi, &txbuf[0], 2, NULL, 0);
+		if (result) {
+			pr_err("mpu write reg %u failed, rc %d\n",
+						reg, val);
+			result = -MPU_READ_FAIL;
+		}
+	} else if (st->interface == ICM20602_I2C) {
+#ifdef ICM20602_I2C_SMBUS
+		result = i2c_smbus_write_i2c_block_data(st->client,
+						reg, 1, &val);
+#else
+		txbuf[0] = reg;
+		txbuf[1] = val;
+		msg[0].addr = st->client->addr;
+		msg[0].flags = I2C_M_IGNORE_NAK;
+		msg[0].len = 2;
+		msg[0].buf = txbuf;
+
+		i2c_transfer(st->client->adapter, msg, ARRAY_SIZE(msg));
+#endif
+	}
+
+	return result;
+}
+
+static int icm20602_read_reg(struct inv_icm20602_state *st,
+				uint8_t reg, uint8_t *val)
+{
+	int result = MPU_SUCCESS;
+	char txbuf[1] = {0x0};
+	char rxbuf[1] = {0x0};
+	struct i2c_msg msg[2];
+
+	if (st->interface == ICM20602_SPI) {
+		txbuf[0] = ICM20602_READ_REG(reg);
+		result = spi_write_then_read(st->spi,
+						&txbuf[0], 1, rxbuf, 1);
+		if (result) {
+			pr_err("mpu read reg %u failed, rc %d\n",
+						reg, result);
+			result = -MPU_READ_FAIL;
+		}
+	} else if (st->interface == ICM20602_I2C) {
+#ifdef ICM20602_I2C_SMBUS
+		result = i2c_smbus_read_i2c_block_data(st->client,
+						reg, 1, rxbuf);
+		if (result != 1) {
+			pr_err("mpu read reg %u failed, rc %d\n",
+						reg, result);
+			result = -MPU_READ_FAIL;
+		}
+#else
+		txbuf[0] = reg;
+		msg[0].addr = st->client->addr;
+		msg[0].flags = W_FLG;
+		msg[0].len = 1;
+		msg[0].buf = txbuf;
+
+		msg[1].addr = st->client->addr;
+		msg[1].flags = I2C_M_RD;
+		msg[1].len = 1;
+		msg[1].buf = rxbuf;
+
+		i2c_transfer(st->client->adapter, msg, ARRAY_SIZE(msg));
+#endif
+	}
+	*val = rxbuf[0];
+
+	return result;
+}
+
+#define combine_8_to_16(upper, lower) ((upper << 8) | lower)
+
+int icm20602_read_raw(struct inv_icm20602_state *st,
+		struct struct_icm20602_real_data *real_data, uint32_t type)
+{
+	struct struct_icm20602_raw_data raw_data;
+
+	if (type & ACCEL != 0) {
+		icm20602_read_reg(st,
+			reg_set_20602.ACCEL_XOUT_H.address,
+			&raw_data.ACCEL_XOUT_H);
+		icm20602_read_reg(st,
+			reg_set_20602.ACCEL_XOUT_L.address,
+			&raw_data.ACCEL_XOUT_L);
+		real_data->ACCEL_XOUT =
+			combine_8_to_16(raw_data.ACCEL_XOUT_H,
+			raw_data.ACCEL_XOUT_L);
+
+		icm20602_read_reg(st,
+			reg_set_20602.ACCEL_YOUT_H.address,
+			&raw_data.ACCEL_YOUT_H);
+		icm20602_read_reg(st,
+			reg_set_20602.ACCEL_YOUT_L.address,
+			&raw_data.ACCEL_YOUT_L);
+		real_data->ACCEL_YOUT =
+			combine_8_to_16(raw_data.ACCEL_YOUT_H,
+			raw_data.ACCEL_YOUT_L);
+
+		icm20602_read_reg(st,
+			reg_set_20602.ACCEL_ZOUT_H.address,
+			&raw_data.ACCEL_ZOUT_H);
+		icm20602_read_reg(st,
+			reg_set_20602.ACCEL_ZOUT_L.address,
+			&raw_data.ACCEL_ZOUT_L);
+		real_data->ACCEL_ZOUT =
+			combine_8_to_16(raw_data.ACCEL_ZOUT_H,
+			raw_data.ACCEL_ZOUT_L);
+	}
+
+	if (type & GYRO != 0) {
+		icm20602_read_reg(st,
+			reg_set_20602.GYRO_XOUT_H.address,
+			&raw_data.GYRO_XOUT_H);
+		icm20602_read_reg(st,
+			reg_set_20602.GYRO_XOUT_L.address,
+			&raw_data.GYRO_XOUT_L);
+		real_data->GYRO_XOUT =
+			combine_8_to_16(raw_data.GYRO_XOUT_H,
+			raw_data.GYRO_XOUT_L);
+
+		icm20602_read_reg(st,
+			reg_set_20602.GYRO_YOUT_H.address,
+			&raw_data.GYRO_YOUT_H);
+		icm20602_read_reg(st,
+			reg_set_20602.GYRO_YOUT_L.address,
+			&raw_data.GYRO_YOUT_L);
+		real_data->GYRO_YOUT =
+			combine_8_to_16(raw_data.GYRO_YOUT_H,
+			raw_data.GYRO_YOUT_L);
+
+		icm20602_read_reg(st,
+			reg_set_20602.GYRO_ZOUT_H.address,
+			&raw_data.GYRO_ZOUT_H);
+		icm20602_read_reg(st,
+			reg_set_20602.GYRO_ZOUT_L.address,
+			&raw_data.GYRO_ZOUT_L);
+		real_data->GYRO_ZOUT =
+			combine_8_to_16(raw_data.GYRO_ZOUT_H,
+			raw_data.GYRO_ZOUT_L);
+	}
+
+	return MPU_SUCCESS;
+}
+
+int icm20602_read_fifo(struct inv_icm20602_state *st,
+					void *buf, const int size)
+{
+	return icm20602_bulk_read(st,
+		reg_set_20602.FIFO_R_W.address, buf, size);
+}
+
+int icm20602_start_fifo(struct inv_icm20602_state *st)
+{
+	struct icm20602_user_config *config = NULL;
+
+	config = st->config;
+
+	/* enable fifo */
+	if (config->fifo_enabled) {
+		reg_set_20602.USER_CTRL.reg_u.REG.FIFO_EN = 0x1;
+		if (icm20602_write_reg_simple(st,
+						reg_set_20602.USER_CTRL)) {
+			pr_err("icm20602 start fifo failed\n");
+			return -MPU_FAIL;
+		}
+
+		/* enable interrupt, need to test */
+		reg_set_20602.INT_ENABLE.reg_u.REG.FIFO_OFLOW_EN = 0x1;
+		reg_set_20602.INT_ENABLE.reg_u.REG.DATA_RDY_INT_EN = 0x0;
+		if (icm20602_write_reg_simple(st,
+						reg_set_20602.INT_ENABLE)) {
+			pr_err("icm20602 set FIFO_OFLOW_EN failed\n");
+			return -MPU_FAIL;
+		}
+	}
+
+	return MPU_SUCCESS;
+}
+
+static int icm20602_stop_fifo(struct inv_icm20602_state *st)
+{
+	struct icm20602_user_config *config = NULL;
+
+	config = st->config;
+	/* disable fifo */
+	if (config->fifo_enabled) {
+		reg_set_20602.USER_CTRL.reg_u.REG.FIFO_EN = 0x0;
+		reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x1;
+		if (icm20602_write_reg_simple(st,
+				reg_set_20602.USER_CTRL)) {
+			reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0;
+			pr_err("icm20602 stop fifo failed\n");
+			return -MPU_FAIL;
+		}
+		reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0;
+	}
+
+	return MPU_SUCCESS;
+}
+
+static int icm20602_config_waterlevel(struct inv_icm20602_state *st)
+{
+	struct icm20602_user_config *config = NULL;
+	uint8_t val = 0;
+
+	config = st->config;
+	if (config->fifo_enabled != true)
+		return MPU_SUCCESS;
+	/* config waterlevel as the fps need */
+	config->fifo_waterlevel = (config->user_fps_in_ms /
+				(1000 / config->gyro_accel_sample_rate))
+				*ICM20602_PACKAGE_SIZE;
+
+	if (config->fifo_waterlevel > 1023 ||
+		config->fifo_waterlevel/50 >
+		(1023-config->fifo_waterlevel)/ICM20602_PACKAGE_SIZE) {
+		pr_err("set fifo_waterlevel failed %d\n",
+					config->fifo_waterlevel);
+		return MPU_FAIL;
+	}
+	reg_set_20602.FIFO_WM_TH1.reg_u.reg =
+				(config->fifo_waterlevel & 0xff00) >> 8;
+	reg_set_20602.FIFO_WM_TH2.reg_u.reg =
+				(config->fifo_waterlevel & 0x00ff);
+
+	icm20602_write_reg_simple(st, reg_set_20602.FIFO_WM_TH1);
+	icm20602_write_reg_simple(st, reg_set_20602.FIFO_WM_TH2);
+	icm20602_read_reg(st, reg_set_20602.FIFO_WM_TH1.address, &val);
+	icm20602_read_reg(st, reg_set_20602.FIFO_WM_TH2.address, &val);
+
+	return MPU_SUCCESS;
+}
+
+static int icm20602_read_ST_code(struct inv_icm20602_state *st)
+{
+	struct icm20602_user_config *config = NULL;
+	int result = 0;
+
+	config = st->config;
+	result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_X_ACCEL.address,
+		&(config->acc_self_test.X));
+	result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_Y_ACCEL.address,
+		&(config->acc_self_test.Y));
+	result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_Z_ACCEL.address,
+		&(config->acc_self_test.Z));
+
+	result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_X_GYRO.address,
+		&(config->gyro_self_test.X));
+	result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_Y_GYRO.address,
+		&(config->gyro_self_test.Y));
+	result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_Z_GYRO.address,
+		&(config->gyro_self_test.Z));
+
+	return result;
+}
+
+static int icm20602_set_self_test(struct inv_icm20602_state *st)
+{
+	uint8_t raw_data[6] = {0, 0, 0, 0, 0, 0};
+	uint8_t selfTest[6];
+	float factory_trim[6];
+	int result = 0;
+	int ii;
+
+	reg_set_20602.SMPLRT_DIV.reg_u.REG.SMPLRT_DIV = 0;
+	result |= icm20602_write_reg_simple(st, reg_set_20602.SMPLRT_DIV);
+
+	reg_set_20602.CONFIG.reg_u.REG.DLFP_CFG = INV_ICM20602_GYRO_LFP_92HZ;
+	result |= icm20602_write_reg_simple(st, reg_set_20602.CONFIG);
+
+	reg_set_20602.GYRO_CONFIG.reg_u.REG.FCHOICE_B = 0x0;
+	reg_set_20602.GYRO_CONFIG.reg_u.REG.FS_SEL = ICM20602_GYRO_FSR_250DPS;
+	result |= icm20602_write_reg_simple(st, reg_set_20602.GYRO_CONFIG);
+
+	reg_set_20602.ACCEL_CONFIG2.reg_u.REG.A_DLPF_CFG = ICM20602_ACCLFP_99;
+	reg_set_20602.ACCEL_CONFIG2.reg_u.REG.ACCEL_FCHOICE_B = 0X0;
+	result |= icm20602_write_reg_simple(st, reg_set_20602.ACCEL_CONFIG2);
+
+	reg_set_20602.ACCEL_CONFIG.reg_u.REG.ACCEL_FS_SEL = ICM20602_ACC_FSR_2G;
+	result |= icm20602_write_reg_simple(st, reg_set_20602.ACCEL_CONFIG);
+
+	//icm20602_read_ST_code(st);
+
+	return 0;
+}
+
+static int icm20602_do_test_acc(struct inv_icm20602_state *st,
+	struct X_Y_Z *acc, struct X_Y_Z *acc_st)
+{
+	struct struct_icm20602_real_data *real_data =
+		kmalloc(sizeof(struct inv_icm20602_state), GFP_ATOMIC);
+	struct icm20602_user_config *config = st->config;
+	int i, j;
+
+	for (i = 0; i < SELFTEST_COUNT; i++) {
+		icm20602_read_raw(st, real_data, ACCEL);
+		acc->X += real_data->ACCEL_XOUT;
+		acc->Y += real_data->ACCEL_YOUT;
+		acc->Z += real_data->ACCEL_ZOUT;
+		usleep_range(1000, 1001);
+	}
+	acc->X /= SELFTEST_COUNT;
+	acc->X *= ST_PRECISION;
+
+	acc->Y /= SELFTEST_COUNT;
+	acc->Y *= ST_PRECISION;
+
+	acc->Z /= SELFTEST_COUNT;
+	acc->Z *= ST_PRECISION;
+
+	reg_set_20602.ACCEL_CONFIG.reg_u.REG.XG_ST = 0x1;
+	reg_set_20602.ACCEL_CONFIG.reg_u.REG.YG_ST = 0x1;
+	reg_set_20602.ACCEL_CONFIG.reg_u.REG.ZG_ST = 0x1;
+	icm20602_write_reg_simple(st, reg_set_20602.ACCEL_CONFIG);
+
+	for (i = 0; i < SELFTEST_COUNT; i++) {
+		icm20602_read_raw(st, real_data, ACCEL);
+		acc_st->X += real_data->ACCEL_XOUT;
+		acc_st->Y += real_data->ACCEL_YOUT;
+		acc_st->Z += real_data->ACCEL_ZOUT;
+		usleep_range(1000, 1001);
+	}
+	acc_st->X /= SELFTEST_COUNT;
+	acc_st->X *= ST_PRECISION;
+
+	acc_st->Y /= SELFTEST_COUNT;
+	acc_st->Y *= ST_PRECISION;
+
+	acc_st->Z /= SELFTEST_COUNT;
+	acc_st->Z *= ST_PRECISION;
+
+	return MPU_SUCCESS;
+}
+
+static int icm20602_do_test_gyro(struct inv_icm20602_state *st,
+	struct X_Y_Z *gyro, struct X_Y_Z *gyro_st)
+{
+	struct struct_icm20602_real_data *real_data =
+		kmalloc(sizeof(struct inv_icm20602_state), GFP_ATOMIC);
+	int i, j;
+
+	for (i = 0; i < SELFTEST_COUNT; i++) {
+		icm20602_read_raw(st, real_data, GYRO);
+		gyro->X += real_data->GYRO_XOUT;
+		gyro->Y += real_data->GYRO_YOUT;
+		gyro->Z += real_data->GYRO_ZOUT;
+		usleep_range(1000, 1001);
+	}
+	gyro->X /= SELFTEST_COUNT;
+	gyro->X *= ST_PRECISION;
+
+	gyro->Y /= SELFTEST_COUNT;
+	gyro->Y *= ST_PRECISION;
+
+	gyro->Z /= SELFTEST_COUNT;
+	gyro->Z *= ST_PRECISION;
+
+	reg_set_20602.GYRO_CONFIG.reg_u.REG.XG_ST = 0x1;
+	reg_set_20602.GYRO_CONFIG.reg_u.REG.YG_ST = 0x1;
+	reg_set_20602.GYRO_CONFIG.reg_u.REG.ZG_ST = 0x1;
+	icm20602_write_reg_simple(st, reg_set_20602.GYRO_CONFIG);
+
+	for (i = 0; i < SELFTEST_COUNT; i++) {
+		icm20602_read_raw(st, real_data, ACCEL);
+		gyro_st->X += real_data->GYRO_XOUT;
+		gyro_st->Y += real_data->GYRO_YOUT;
+		gyro_st->Z += real_data->GYRO_ZOUT;
+		usleep_range(1000, 1001);
+	}
+	gyro_st->X /= SELFTEST_COUNT;
+	gyro_st->X *= ST_PRECISION;
+
+	gyro_st->Y /= SELFTEST_COUNT;
+	gyro_st->Y *= ST_PRECISION;
+
+	gyro_st->Z /= SELFTEST_COUNT;
+	gyro_st->Z *= ST_PRECISION;
+
+	return MPU_SUCCESS;
+}
+
+static bool icm20602_check_acc_selftest(struct inv_icm20602_state *st,
+	struct X_Y_Z *acc, struct X_Y_Z *acc_st)
+{
+	struct X_Y_Z acc_ST_code, st_otp, st_shift_cust;
+	bool otp_value_zero = false, test_result = true;
+
+	acc_ST_code.X = st->config->acc_self_test.X;
+	acc_ST_code.Y = st->config->acc_self_test.Y;
+	acc_ST_code.Z = st->config->acc_self_test.Z;
+
+	st_otp.X = (st_otp.X != 0) ? mpu_st_tb[acc_ST_code.X - 1] : 0;
+	st_otp.Y = (st_otp.Y != 0) ? mpu_st_tb[acc_ST_code.Y - 1] : 0;
+	st_otp.Z = (st_otp.Z != 0) ? mpu_st_tb[acc_ST_code.Z - 1] : 0;
+
+	if (st_otp.X & st_otp.Y & st_otp.Z == 0)
+		otp_value_zero = true;
+
+	st_shift_cust.X = acc_st->X - acc->X;
+	st_shift_cust.Y = acc_st->X - acc->Y;
+	st_shift_cust.Z = acc_st->X - acc->Z;
+	if (!otp_value_zero) {
+		if (
+		st_shift_cust.X <
+		(st_otp.X * ST_PRECISION * ACC_ST_SHIFT_MIN / 100) ||
+		st_shift_cust.Y <
+		(st_otp.Y * ST_PRECISION * ACC_ST_SHIFT_MIN / 100) ||
+		st_shift_cust.Z <
+		(st_otp.Z * ST_PRECISION * ACC_ST_SHIFT_MIN / 100) ||
+
+		st_shift_cust.X >
+		(st_otp.X * ST_PRECISION * ACC_ST_SHIFT_MAX / 100) ||
+		st_shift_cust.Y >
+		(st_otp.Y * ST_PRECISION * ACC_ST_SHIFT_MAX / 100) ||
+		st_shift_cust.Z >
+		(st_otp.Z * ST_PRECISION * ACC_ST_SHIFT_MAX / 100)
+		) {
+			test_result = false;
+		}
+	} else {
+		if (
+		abs(st_shift_cust.X) <
+		(ACC_ST_AL_MIN * 16384 / 1000 * ST_PRECISION) ||
+		abs(st_shift_cust.Y) <
+		(ACC_ST_AL_MIN * 16384 / 1000 * ST_PRECISION) ||
+		abs(st_shift_cust.Z) <
+		(ACC_ST_AL_MIN * 16384 / 1000 * ST_PRECISION)  ||
+
+		abs(st_shift_cust.X) >
+		(ACC_ST_AL_MAX * 16384 / 1000 * ST_PRECISION) ||
+		abs(st_shift_cust.Y) >
+		(ACC_ST_AL_MAX * 16384 / 1000 * ST_PRECISION) ||
+		abs(st_shift_cust.Z) >
+		(ACC_ST_AL_MAX * 16384 / 1000 * ST_PRECISION)
+		) {
+			test_result = false;
+		}
+	}
+
+	return test_result;
+}
+
+static int icm20602_check_gyro_selftest(struct inv_icm20602_state *st,
+	struct X_Y_Z *gyro, struct X_Y_Z *gyro_st)
+{
+	struct X_Y_Z gyro_ST_code, st_otp, st_shift_cust;
+	bool otp_value_zero = false, test_result = true;
+
+	gyro_ST_code.X = st->config->gyro_self_test.X;
+	gyro_ST_code.Y = st->config->gyro_self_test.Y;
+	gyro_ST_code.Z = st->config->gyro_self_test.Z;
+
+	st_otp.X = (st_otp.X != 0) ? mpu_st_tb[gyro_ST_code.X - 1] : 0;
+	st_otp.Y = (st_otp.Y != 0) ? mpu_st_tb[gyro_ST_code.Y - 1] : 0;
+	st_otp.Z = (st_otp.Z != 0) ? mpu_st_tb[gyro_ST_code.Z - 1] : 0;
+
+	if (st_otp.X & st_otp.Y & st_otp.Z == 0)
+		otp_value_zero = true;
+
+	st_shift_cust.X = gyro_st->X - gyro->X;
+	st_shift_cust.Y = gyro_st->X - gyro->Y;
+	st_shift_cust.Z = gyro_st->X - gyro->Z;
+	if (!otp_value_zero) {
+		if (
+		st_shift_cust.X <
+		(st_otp.X * ST_PRECISION * GYRO_ST_SHIFT / 100) ||
+		st_shift_cust.Y <
+		(st_otp.Y * ST_PRECISION * GYRO_ST_SHIFT / 100) ||
+		st_shift_cust.Z <
+		(st_otp.Z * ST_PRECISION * GYRO_ST_SHIFT / 100)
+		) {
+			test_result = false;
+		}
+	} else {
+		if (
+		abs(st_shift_cust.X) <
+		(GYRO_ST_AL * 32768 / 250 * ST_PRECISION) ||
+		abs(st_shift_cust.Y) <
+		(GYRO_ST_AL * 32768 / 250 * ST_PRECISION) ||
+		abs(st_shift_cust.Z) <
+		(GYRO_ST_AL * 32768 / 250 * ST_PRECISION)
+		) {
+			test_result = false;
+		}
+	}
+
+	if (test_result == true) {
+		/* Self Test Pass/Fail Criteria C */
+		if (
+		abs(st_shift_cust.X) >
+		GYRO_OFFSET_MAX * 32768 / 250 * ST_PRECISION ||
+		abs(st_shift_cust.Y) >
+		GYRO_OFFSET_MAX * 32768 / 250 * ST_PRECISION ||
+		abs(st_shift_cust.Z) >
+		GYRO_OFFSET_MAX * 32768 / 250 * ST_PRECISION
+		) {
+			test_result = false;
+		}
+	}
+
+	return test_result;
+}
+
+bool icm20602_self_test(struct inv_icm20602_state *st)
+{
+	struct X_Y_Z acc, acc_st;
+	struct X_Y_Z gyro, gyro_st;
+	bool test_result = true;
+
+	icm20602_set_self_test(st);
+	icm20602_do_test_acc(st, &acc, &acc_st);
+	icm20602_do_test_gyro(st, &gyro, &gyro_st);
+	test_result = icm20602_check_acc_selftest(st, &acc, &acc_st);
+	test_result = icm20602_check_gyro_selftest(st, &gyro, &gyro_st);
+
+	return test_result;
+}
+
+static int icm20602_config_fifo(struct inv_icm20602_state *st)
+{
+	struct icm20602_user_config *config = NULL;
+
+	config = st->config;
+	if (config->fifo_enabled != true)
+		return MPU_SUCCESS;
+
+	/*
+	 * Set CONFIG.USER_SET_BIT = 0, No reason as datasheet said
+	 */
+	reg_set_20602.CONFIG.reg_u.REG.USER_SET_BIT = 0x0;
+	/*
+	 * Set CONFIG.FIFO_MODE = 1,
+	 * i.e. when FIFO is full, additional writes will
+	 * not be written to FIFO
+	 */
+	reg_set_20602.CONFIG.reg_u.REG.FIFO_MODE = 0x1;
+	if (icm20602_write_reg_simple(st, reg_set_20602.CONFIG))
+		return -MPU_FAIL;
+
+	/* reset fifo */
+	reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x1;
+	if (icm20602_write_reg_simple(st, reg_set_20602.USER_CTRL)) {
+		reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0;
+		return -MPU_FAIL;
+	}
+	reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0;
+
+	/* Enable FIFO on specified sensors */
+	reg_set_20602.FIFO_EN.reg_u.REG.GYRO_FIFO_EN = 0x1;
+	reg_set_20602.FIFO_EN.reg_u.REG.ACCEL_FIFO_EN = 0x1;
+	if (icm20602_write_reg_simple(st, reg_set_20602.FIFO_EN))
+		return -MPU_FAIL;
+
+	if (icm20602_config_waterlevel(st))
+		return -MPU_FAIL;
+
+	if (icm20602_start_fifo(st))
+		return -MPU_FAIL;
+
+	return MPU_SUCCESS;
+}
+
+static int icm20602_initialize_gyro(struct inv_icm20602_state *st)
+{
+	struct icm20602_user_config *config = NULL;
+	int result = MPU_SUCCESS;
+	int sample_rate;
+	uint8_t fchoice_b;
+
+	if (st == NULL)
+		return -MPU_FAIL;
+
+	/*
+	 * ICM20602 supports gyro sampling rate up to 32KHz
+	 * when fchoice_b != 0x00
+	 * In our driver, we supports up to 8KHz
+	 * thus always set fchoice_b to 0x00;
+	 */
+	config = st->config;
+	/*
+	 * SAPLRT_DIV in ICM20602_REG_SMPLRT_DIV is only used for 1kHz internal
+	 * sampling, i.e. fchoice_b in ICM20602_REG_GYRO_CONFIG is 00
+	 * and 0 < dlpf_cfg in ICM20602_REG_CONFIG < 7
+	 * SAMPLE_RATE=Internal_Sample_Rate / (1 + SMPLRT_DIV)
+	 */
+	if (config->gyro_accel_sample_rate <= ICM20602_SAMPLE_RATE_1000HZ)
+		reg_set_20602.SMPLRT_DIV.reg_u.reg =
+		ICM20602_INTERNAL_SAMPLE_RATE_HZ /
+		config->gyro_accel_sample_rate - 1;
+
+	result = icm20602_write_reg_simple(st, reg_set_20602.SMPLRT_DIV);
+
+	/* Set gyro&temperature(combine) LPF */
+	reg_set_20602.CONFIG.reg_u.REG.DLFP_CFG = config->gyro_lpf;
+	result |= icm20602_write_reg_simple(st, reg_set_20602.CONFIG);
+
+	/* Set gyro full scale range */
+	reg_set_20602.GYRO_CONFIG.reg_u.REG.FCHOICE_B = 0x0;
+	reg_set_20602.GYRO_CONFIG.reg_u.REG.FS_SEL = config->gyro_fsr;
+	result |= icm20602_write_reg_simple(st, reg_set_20602.GYRO_CONFIG);
+
+	/* Set Accel full scale range */
+	reg_set_20602.ACCEL_CONFIG.reg_u.REG.ACCEL_FS_SEL = config->acc_fsr;
+	result |= icm20602_write_reg_simple(st, reg_set_20602.ACCEL_CONFIG);
+
+	/*
+	 * Set accel LPF
+	 * Support accel sample rate up to 1KHz
+	 * thus set accel_fchoice_b to 0x00
+	 * The actual accel sample rate is 1KHz/(1+SMPLRT_DIV)
+	 */
+	reg_set_20602.ACCEL_CONFIG2.reg_u.REG.ACCEL_FCHOICE_B = 0x0;
+	reg_set_20602.ACCEL_CONFIG2.reg_u.REG.A_DLPF_CFG = config->acc_lpf;
+	result |= icm20602_write_reg_simple(st,
+				reg_set_20602.ACCEL_CONFIG2);
+
+	if (result) {
+		pr_err("icm20602 init gyro and accel failed\n");
+		return -MPU_FAIL;
+	}
+
+	return result;
+}
+
+int icm20602_set_power_itg(struct inv_icm20602_state *st, bool power_on)
+{
+	int result = MPU_SUCCESS;
+
+	if (power_on) {
+		reg_set_20602.PWR_MGMT_1.reg_u.reg = 0;
+		result = icm20602_write_reg_simple(st,
+					reg_set_20602.PWR_MGMT_1);
+	} else {
+		reg_set_20602.PWR_MGMT_1.reg_u.REG.SLEEP = 0x1;
+		result = icm20602_write_reg_simple(st,
+					reg_set_20602.PWR_MGMT_1);
+	}
+	if (result) {
+		pr_err("set power failed power %d  err %d\n",
+					power_on, result);
+		return result;
+	}
+
+	if (power_on)
+		msleep(30);
+
+	return result;
+}
+
+int icm20602_init_device(struct inv_icm20602_state *st)
+{
+	int result = MPU_SUCCESS;
+	struct icm20602_user_config *config = NULL;
+	int package_count;
+
+	config = st->config;
+	if (st == NULL || st->config == NULL) {
+		pr_err("icm20602 validate config failed\n");
+		return -MPU_FAIL;
+	}
+
+	/* turn on gyro and accel */
+	reg_set_20602.PWR_MGMT_2.reg_u.reg = 0x0;
+	result |= icm20602_write_reg_simple(st, reg_set_20602.PWR_MGMT_2);
+	msleep(30);
+
+	/* disable INT */
+	reg_set_20602.INT_ENABLE.reg_u.reg = 0x0;
+	result |= icm20602_write_reg_simple(st, reg_set_20602.INT_ENABLE);
+
+	/* disbale FIFO */
+	reg_set_20602.FIFO_EN.reg_u.reg = 0x0;
+	result |= icm20602_write_reg_simple(st, reg_set_20602.FIFO_EN);
+
+	/* reset FIFO */
+	reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x1;
+	result |= icm20602_write_reg_simple(st, reg_set_20602.USER_CTRL);
+	reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0;
+	msleep(30);
+
+	/* init gyro and accel */
+	if (icm20602_initialize_gyro(st)) {
+		pr_err("icm20602 init device failed\n");
+		return -MPU_FAIL;
+	}
+
+	/* if FIFO enable, config FIFO */
+	if (config->fifo_enabled) {
+		if (icm20602_config_fifo(st)) {
+			pr_err("icm20602 init config fifo failed\n");
+			return -MPU_FAIL;
+		}
+	} else {
+		/* enable interrupt */
+		reg_set_20602.INT_ENABLE.reg_u.REG.DATA_RDY_INT_EN = 0x0;
+		if (icm20602_write_reg_simple(st,
+				reg_set_20602.INT_ENABLE)) {
+			pr_err("icm20602 set raw rdy failed\n");
+			return -MPU_FAIL;
+		}
+	}
+
+	/* buffer malloc */
+	package_count = config->fifo_waterlevel / ICM20602_PACKAGE_SIZE;
+
+	st->buf = kzalloc(sizeof(config->fifo_waterlevel * 2), GFP_ATOMIC);
+	if (!st->buf)
+		return -ENOMEM;
+
+	st->data_push = kcalloc(package_count,
+		sizeof(struct struct_icm20602_data), GFP_ATOMIC);
+	if (!st->data_push)
+		return -ENOMEM;
+
+	return result;
+}
+
+void icm20602_rw_test(struct inv_icm20602_state *st)
+{
+	uint8_t val = 0;
+
+	reg_set_20602.PWR_MGMT_2.reg_u.REG.STBY_ZG = 0x1;
+	icm20602_write_reg_simple(st, reg_set_20602.PWR_MGMT_2);
+	reg_set_20602.CONFIG.reg_u.REG.FIFO_MODE = 0x1;
+	icm20602_write_reg_simple(st, reg_set_20602.CONFIG);
+
+	icm20602_read_reg(st, reg_set_20602.PWR_MGMT_2.address, &val);
+	icm20602_read_reg(st, reg_set_20602.CONFIG.address, &val);
+
+}
+
+int icm20602_detect(struct inv_icm20602_state *st)
+{
+	int result = MPU_SUCCESS;
+	uint8_t retry = 0, val = 0;
+	uint8_t usr_ctrl = 0;
+
+	pr_debug("icm20602_detect\n");
+	/* reset to make sure previous state are not there */
+	reg_set_20602.PWR_MGMT_1.reg_u.REG.DEVICE_RESET = 0x1;
+	result = icm20602_write_reg_simple(st, reg_set_20602.PWR_MGMT_1);
+	if (result) {
+		pr_err("mpu write reg 0x%x value 0x%x failed\n",
+		reg_set_20602.PWR_MGMT_1.reg_u.reg,
+		reg_set_20602.PWR_MGMT_1.reg_u.REG.DEVICE_RESET);
+		return result;
+	}
+	reg_set_20602.PWR_MGMT_1.reg_u.REG.DEVICE_RESET = 0x0;
+
+	/* the power up delay */
+	msleep(30);
+
+	/* out of sleep */
+	result = icm20602_set_power_itg(st, true);
+	if (result)
+		return result;
+	/* get who am i register */
+	while (retry < 10) {
+		/* get version (expecting 0x12 for the icm20602) */
+		icm20602_read_reg(st, reg_set_20602.WHO_AM_I.address, &val);
+		if (val == ICM20602_WHO_AM_I)
+			break;
+		retry++;
+	}
+
+	if (val != ICM20602_WHO_AM_I) {
+		pr_err("detect mpu failed,whoami reg 0x%x\n", val);
+		result = -MPU_FAIL;
+	} else {
+		pr_debug("detect mpu ok,whoami reg 0x%x\n", val);
+	}
+	icm20602_rw_test(st);
+
+	return result;
+}
diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.h b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.h
new file mode 100644
index 0000000..9c4dbd0
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.h
@@ -0,0 +1,978 @@
+/*
+ * Copyright (c) 2018 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.
+ */
+
+/* register high bit=1 for read */
+#define ICM20602_READ_REG(reg) (reg | 0x80)
+
+/* register high bit=0 for write */
+#define ICM20602_WRITE_REG(reg) (reg & (~0x80))
+#define ICM20602_WHO_AM_I 0x12
+#define ICM20602_INTERNAL_SAMPLE_RATE_HZ 1000
+
+#define SELFTEST_COUNT 200
+#define ST_PRECISION 1000
+#define ACC_ST_SHIFT_MAX	150
+#define ACC_ST_SHIFT_MIN	50
+#define ACC_ST_AL_MIN		225
+#define ACC_ST_AL_MAX		675
+#define GYRO_ST_SHIFT	50
+#define GYRO_ST_AL		60
+#define GYRO_OFFSET_MAX	20
+
+static const uint16_t mpu_st_tb[256] = {
+	2620, 2646, 2672, 2699, 2726, 2753, 2781, 2808,
+	2837, 2865, 2894, 2923, 2952, 2981, 3011, 3041,
+	3072, 3102, 3133, 3165, 3196, 3228, 3261, 3293,
+	3326, 3359, 3393, 3427, 3461, 3496, 3531, 3566,
+	3602, 3638, 3674, 3711, 3748, 3786, 3823, 3862,
+	3900, 3939, 3979, 4019, 4059, 4099, 4140, 4182,
+	4224, 4266, 4308, 4352, 4395, 4439, 4483, 4528,
+	4574, 4619, 4665, 4712, 4759, 4807, 4855, 4903,
+	4953, 5002, 5052, 5103, 5154, 5205, 5257, 5310,
+	5363, 5417, 5471, 5525, 5581, 5636, 5693, 5750,
+	5807, 5865, 5924, 5983, 6043, 6104, 6165, 6226,
+	6289, 6351, 6415, 6479, 6544, 6609, 6675, 6742,
+	6810, 6878, 6946, 7016, 7086, 7157, 7229, 7301,
+	7374, 7448, 7522, 7597, 7673, 7750, 7828, 7906,
+	7985, 8065, 8145, 8227, 8309, 8392, 8476, 8561,
+	8647, 8733, 8820, 8909, 8998, 9088, 9178, 9270,
+	9363, 9457, 9551, 9647, 9743, 9841, 9939, 10038,
+	10139, 10240, 10343, 10446, 10550, 10656, 10763, 10870,
+	10979, 11089, 11200, 11312, 11425, 11539, 11654, 11771,
+	11889, 12008, 12128, 12249, 12371, 12495, 12620, 12746,
+	12874, 13002, 13132, 13264, 13396, 13530, 13666, 13802,
+	13940, 14080, 14221, 14363, 14506, 14652, 14798, 14946,
+	15096, 15247, 15399, 15553, 15709, 15866, 16024, 16184,
+	16346, 16510, 16675, 16842, 17010, 17180, 17352, 17526,
+	17701, 17878, 18057, 18237, 18420, 18604, 18790, 18978,
+	19167, 19359, 19553, 19748, 19946, 20145, 20347, 20550,
+	20756, 20963, 21173, 21385, 21598, 21814, 22033, 22253,
+	22475, 22700, 22927, 23156, 23388, 23622, 23858, 24097,
+	24338, 24581, 24827, 25075, 25326, 25579, 25835, 26093,
+	26354, 26618, 26884, 27153, 27424, 27699, 27976, 28255,
+	28538, 28823, 29112, 29403, 29697, 29994, 30294, 30597,
+	30903, 31212, 31524, 31839, 32157, 32479, 32804
+};
+
+enum inv_icm20602_reg_addr {
+	ADDR_XG_OFFS_TC_H = 0x04,
+	ADDR_XG_OFFS_TC_L,
+	ADDR_YG_OFFS_TC_H = 0x07,
+	ADDR_YG_OFFS_TC_L,
+	ADDR_ZG_OFFS_TC_H = 0x0A,
+	ADDR_ZG_OFFS_TC_L,
+
+	ADDR_SELF_TEST_X_ACCEL = 0x0D,
+	ADDR_SELF_TEST_Y_ACCEL,
+	ADDR_SELF_TEST_Z_ACCEL,
+
+	ADDR_XG_OFFS_USRH = 0x13,
+	ADDR_XG_OFFS_USRL,
+	ADDR_YG_OFFS_USRH,
+	ADDR_YG_OFFS_USRL,
+	ADDR_ZG_OFFS_USRH,
+	ADDR_ZG_OFFS_USRL,
+
+	ADDR_SMPLRT_DIV,
+	ADDR_CONFIG,
+
+	ADDR_GYRO_CONFIG,
+
+	ADDR_ACCEL_CONFIG,
+	ADDR_ACCEL_CONFIG2,
+
+	ADDR_LP_MODE_CFG,
+
+	ADDR_ACCEL_WOM_X_THR = 0x20,
+	ADDR_ACCEL_WOM_Y_THR,
+	ADDR_ACCEL_WOM_Z_THR,
+	ADDR_FIFO_EN,
+
+	ADDR_FSYNC_INT = 0x36,
+	ADDR_INT_PIN_CFG,
+	ADDR_INT_ENABLE,
+	ADDR_FIFO_WM_INT_STATUS,
+	ADDR_INT_STATUS,
+
+	ADDR_ACCEL_XOUT_H,
+	ADDR_ACCEL_XOUT_L,
+	ADDR_ACCEL_YOUT_H,
+	ADDR_ACCEL_YOUT_L,
+	ADDR_ACCEL_ZOUT_H,
+	ADDR_ACCEL_ZOUT_L,
+
+	ADDR_TEMP_OUT_H,
+	ADDR_TEMP_OUT_L,
+
+	ADDR_GYRO_XOUT_H,
+	ADDR_GYRO_XOUT_L,
+	ADDR_GYRO_YOUT_H,
+	ADDR_GYRO_YOUT_L,
+	ADDR_GYRO_ZOUT_H,
+	ADDR_GYRO_ZOUT_L,
+
+	ADDR_SELF_TEST_X_GYRO = 0x50,
+	ADDR_SELF_TEST_Y_GYRO,
+	ADDR_SELF_TEST_Z_GYRO,
+
+	ADDR_FIFO_WM_TH1 = 0x60,
+	ADDR_FIFO_WM_TH2,
+
+	ADDR_SIGNAL_PATH_RESET = 0x68,
+	ADDR_ACCEL_INTEL_CTRL,
+	ADDR_USER_CTRL,
+
+	ADDR_PWR_MGMT_1,
+	ADDR_PWR_MGMT_2,
+
+	ADDR_I2C_IF = 0x70,
+
+	ADDR_FIFO_COUNTH = 0x72,
+	ADDR_FIFO_COUNTL,
+	ADDR_FIFO_R_W,
+
+	ADDR_WHO_AM_I,
+
+	ADDR_XA_OFFSET_H,
+	ADDR_XA_OFFSET_L,
+	ADDR_YA_OFFSET_H = 0x7A,
+	ADDR_YA_OFFSET_L,
+	ADDR_ZA_OFFSET_H = 0x7D,
+	ADDR_ZA_OFFSET_L
+};
+
+struct struct_XG_OFFS_TC_H {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 REG_XG_OFFS_TC_H :2;
+			u8 REG_XG_OFFS_LP	:6;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_XG_OFFS_TC_L {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 REG_XG_OFFS_TC_L	:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_YG_OFFS_TC_H {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 REG_YG_OFFS_TC_H	:2;
+			u8 REG_YG_OFFS_LP	:6;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_YG_OFFS_TC_L {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 REG_YG_OFFS_TC_L :8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_ZG_OFFS_TC_H {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 REG_ZG_OFFS_TC_H :2;
+			u8 REG_ZG_OFFS_LP	:6;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_ZG_OFFS_TC_L {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 REG_ZG_OFFS_TC_L :8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_SELF_TEST_X_ACCEL {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 XA_ST_DATA	:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_SELF_TEST_Y_ACCEL {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 YA_ST_DATA	:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_SELF_TEST_Z_ACCEL {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 ZA_ST_DATA	:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_XG_OFFS_USRH {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 X_OFFS_USR	:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_XG_OFFS_USRL {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 X_OFFS_USR	:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_YG_OFFS_USRH {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 Y_OFFS_USR	:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_YG_OFFS_USRL {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 Y_OFFS_USR	:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_ZG_OFFS_USRH {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 Z_OFFS_USR	:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_ZG_OFFS_USRL {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 Z_OFFS_USR	:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_SMPLRT_DIV {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 SMPLRT_DIV	:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_CONFIG {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 DLFP_CFG		:3;
+			u8 EXT_SYNC_SET	:3;
+			u8 FIFO_MODE	:1;
+			u8 USER_SET_BIT	:1;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_GYRO_CONFIG {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 FCHOICE_B	:2;
+			u8 RESERVE0		:1;
+			u8 FS_SEL		:2;
+			u8 ZG_ST		:1;
+			u8 YG_ST		:1;
+			u8 XG_ST		:1;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_ACCEL_CONFIG {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 RESERVE0			:3;
+			u8 ACCEL_FS_SEL		:2;
+			u8 ZG_ST			:1;
+			u8 YG_ST			:1;
+			u8 XG_ST			:1;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_ACCEL_CONFIG2 {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 A_DLPF_CFG		:3;
+			u8 ACCEL_FCHOICE_B	:1;
+			u8 DEC2_CFG			:2;
+			u8 RESERVE0			:2;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_LP_MODE_CFG {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 RESERVE0			:4;
+			u8 G_AVGCFG			:3;
+			u8 GYRO_CYCLE		:1;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_ACCEL_WOM_X_THR {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 WOM_X_TH			:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+
+struct struct_ACCEL_WOM_Y_THR {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 WOM_Y_TH			:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_ACCEL_WOM_Z_THR {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 WOM_Z_TH			:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_FIFO_EN {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 RESERVE1			:3;
+			u8 ACCEL_FIFO_EN	:1;
+			u8 GYRO_FIFO_EN		:1;
+			u8 RESERVE0			:3;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_FSYNC_INT {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 RESERVE0			:7;
+			u8 FSYNC_INT		:1;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_INT_PIN_CFG {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 RESERVE0			:2;
+			u8 FSYNC_INT_MODE_EN:1;
+			u8 FSYNC_INT_LEVEL	:1;
+			u8 INT_RD_CLEAR		:1;
+			u8 LATCH_INT_EN		:1;
+			u8 INT_OPEN			:1;
+			u8 INT_LEVEL		:1;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_INT_ENABLE {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 DATA_RDY_INT_EN	:1;
+			u8 RESERVE0			:1;
+			u8 GDRIVE_INT_EN	:1;
+			u8 FSYNC_INT_EN		:1;
+			u8 FIFO_OFLOW_EN	:1;
+			u8 WOM_Z_INT_EN		:1;
+			u8 WOM_Y_INT_EN		:1;
+			u8 WOM_X_INT_EN		:1;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_FIFO_WM_INT_STATUS {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 RESERVE1			:6;
+			u8 FIFO_WM_INT		:1;
+			u8 RESERVE0			:1;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_INT_STATUS {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 DATA_RDY_INT		:1;
+			u8 RESERVE1			:1;
+			u8 GDRIVE_INT		:1;
+			u8 RESERVE0			:1;
+			u8 FIFO_OFLOW_INT	:1;
+			u8 WOM_Z_INT		:1;
+			u8 WOM_Y_INT		:1;
+			u8 WOM_X_INT		:1;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_ACCEL_XOUT_H {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 ACCEL_XOUT		:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_ACCEL_XOUT_L {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 ACCEL_XOUT		:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_ACCEL_YOUT_H {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 ACCEL_YOUT		:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_ACCEL_YOUT_L {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 ACCEL_YOUT		:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_ACCEL_ZOUT_H {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 ACCEL_ZOUT		:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_ACCEL_ZOUT_L {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 ACCEL_ZOUT		:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_TEMP_OUT_H {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 TEMP_OUT			:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_TEMP_OUT_L {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 TEMP_OUT			:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_GYRO_XOUT_H {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 GYRO_XOUT		:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_GYRO_XOUT_L {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 GYRO_XOUT		:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_GYRO_YOUT_H {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 GYRO_YOUT		:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_GYRO_YOUT_L {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 GYRO_YOUT		:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_GYRO_ZOUT_H {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 GYRO_ZOUT		:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_GYRO_ZOUT_L {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 GYRO_ZOUT		:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_SELF_TEST_X_GYRO {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 XG_ST_DATA		:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_SELF_TEST_Y_GYRO {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 YG_ST_DATA		:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_SELF_TEST_Z_GYRO {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 ZG_ST_DATA		:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_FIFO_WM_TH1 {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 RESERVE0			:6;
+			u8 FIFO_WM_TH		:2;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_FIFO_WM_TH2 {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 FIFO_WM_TH		:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_SIGNAL_PATH_RESET {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 TEMP_RST			:1;
+			u8 ACCEL_RST		:1;
+			u8 FIFO_WM_TH		:6;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_ACCEL_INTEL_CTRL {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 WOM_TH_MODE		:1;
+			u8 OUTPUT_LIMIT		:1;
+			u8 RESERVE0			:4;
+			u8 ACCEL_INTEL_MODE	:1;
+			u8 ACCEL_INTEL_EN	:1;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_USER_CTRL {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 SIG_COND_RST		:1;
+			u8 RESERVE2			:1;
+			u8 FIFO_RST			:1;
+			u8 RESERVE1			:3;
+			u8 FIFO_EN			:1;
+			u8 RESERVE0			:1;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_PWR_MGMT_1 {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 CLKSEL			:3;
+			u8 TEMP_DIS			:1;
+			u8 GYRO_STANDBY		:1;
+			u8 CYCLE			:1;
+			u8 SLEEP			:1;
+			u8 DEVICE_RESET		:1;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_PWR_MGMT_2 {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 STBY_ZG			:1;
+			u8 STBY_YG			:1;
+			u8 STBY_XG			:1;
+			u8 STBY_ZA			:1;
+			u8 STBY_YA			:1;
+			u8 STBY_XA			:1;
+			u8 RESERVE0			:2;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_I2C_IF {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 RESERVE1			:6;
+			u8 I2C_IF_DIS		:1;
+			u8 RESERVE0			:1;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_FIFO_COUNTH {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 FIFO_COUNT		:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_FIFO_COUNTL {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 FIFO_COUNT		:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_FIFO_R_W {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 FIFO_DATA		:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_WHO_AM_I {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 WHOAMI			:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_XA_OFFSET_H {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 XA_OFFS			:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_XA_OFFSET_L {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 XA_OFFS			:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_YA_OFFSET_H {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 YA_OFFS			:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_YA_OFFSET_L {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 YA_OFFS			:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_ZA_OFFSET_H {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 ZA_OFFS			:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+struct struct_ZA_OFFSET_L {
+	enum inv_icm20602_reg_addr address;
+	union {
+		struct {
+			u8 ZA_OFFS			:8;
+		} REG;
+		u8 reg;
+	} reg_u;
+};
+
+/*
+ *  struct inv_icm20602_reg_map - Notable registers.
+ *  @sample_rate_div:	Divider applied to gyro output rate.
+ *  @lpf:		Configures internal low pass filter.
+ *  @user_ctrl:		Enables/resets the FIFO.
+ *  @fifo_en:		Determines which data will appear in FIFO.
+ *  @gyro_config:	gyro config register.
+ *  @accl_config:	accel config register
+ *  @fifo_count_h:	Upper byte of FIFO count.
+ *  @fifo_r_w:		FIFO register.
+ *  @raw_gyro:		Address of first gyro register.
+ *  @raw_accl:		Address of first accel register.
+ *  @temperature:	temperature register
+ *  @int_enable:	Interrupt enable register.
+ *  @pwr_mgmt_1:	Controls chip's power state and clock source.
+ *  @pwr_mgmt_2:	Controls power state of individual sensors.
+ */
+struct inv_icm20602_reg_map {
+	struct struct_XG_OFFS_TC_H XG_OFFS_TC_H;
+	struct struct_XG_OFFS_TC_L XG_OFFS_TC_L;
+	struct struct_YG_OFFS_TC_H YG_OFFS_TC_H;
+	struct struct_YG_OFFS_TC_L YG_OFFS_TC_L;
+	struct struct_ZG_OFFS_TC_H ZG_OFFS_TC_H;
+	struct struct_ZG_OFFS_TC_L ZG_OFFS_TC_L;
+
+	struct struct_SELF_TEST_X_ACCEL SELF_TEST_X_ACCEL;
+	struct struct_SELF_TEST_Y_ACCEL SELF_TEST_Y_ACCEL;
+	struct struct_SELF_TEST_Z_ACCEL SELF_TEST_Z_ACCEL;
+
+	struct struct_XG_OFFS_USRH XG_OFFS_USRH;
+	struct struct_XG_OFFS_USRL XG_OFFS_USRL;
+	struct struct_YG_OFFS_USRH YG_OFFS_USRH;
+	struct struct_YG_OFFS_USRL YG_OFFS_USRL;
+	struct struct_ZG_OFFS_USRH ZG_OFFS_USRH;
+	struct struct_ZG_OFFS_USRL ZG_OFFS_USRL;
+
+	struct struct_SMPLRT_DIV SMPLRT_DIV;
+	struct struct_CONFIG CONFIG;
+
+	struct struct_GYRO_CONFIG GYRO_CONFIG;
+
+	struct struct_ACCEL_CONFIG ACCEL_CONFIG;
+	struct struct_ACCEL_CONFIG2 ACCEL_CONFIG2;
+
+	struct struct_LP_MODE_CFG LP_MODE_CFG;
+
+	struct struct_ACCEL_WOM_X_THR ACCEL_WOM_X_THR;
+	struct struct_ACCEL_WOM_Y_THR ACCEL_WOM_Y_THR;
+	struct struct_ACCEL_WOM_Z_THR ACCEL_WOM_Z_THR;
+
+	struct struct_FIFO_EN FIFO_EN;
+	struct struct_FSYNC_INT FSYNC_INT;
+	struct struct_INT_PIN_CFG INT_PIN_CFG;
+	struct struct_INT_ENABLE INT_ENABLE;
+	struct struct_FIFO_WM_INT_STATUS FIFO_WM_INT_STATUS;
+	struct struct_INT_STATUS INT_STATUS;
+
+	struct struct_ACCEL_XOUT_H ACCEL_XOUT_H;
+	struct struct_ACCEL_XOUT_L ACCEL_XOUT_L;
+	struct struct_ACCEL_YOUT_H ACCEL_YOUT_H;
+	struct struct_ACCEL_YOUT_L ACCEL_YOUT_L;
+	struct struct_ACCEL_ZOUT_H ACCEL_ZOUT_H;
+	struct struct_ACCEL_ZOUT_L ACCEL_ZOUT_L;
+
+	struct struct_TEMP_OUT_H TEMP_OUT_H;
+	struct struct_TEMP_OUT_L TEMP_OUT_L;
+
+	struct struct_GYRO_XOUT_H GYRO_XOUT_H;
+	struct struct_GYRO_XOUT_L GYRO_XOUT_L;
+	struct struct_GYRO_YOUT_H GYRO_YOUT_H;
+	struct struct_GYRO_YOUT_L GYRO_YOUT_L;
+	struct struct_GYRO_ZOUT_H GYRO_ZOUT_H;
+	struct struct_GYRO_ZOUT_L GYRO_ZOUT_L;
+
+	struct struct_SELF_TEST_X_GYRO SELF_TEST_X_GYRO;
+	struct struct_SELF_TEST_Y_GYRO SELF_TEST_Y_GYRO;
+	struct struct_SELF_TEST_Z_GYRO SELF_TEST_Z_GYRO;
+	struct struct_FIFO_WM_TH1 FIFO_WM_TH1;
+	struct struct_FIFO_WM_TH2 FIFO_WM_TH2;
+	struct struct_SIGNAL_PATH_RESET SIGNAL_PATH_RESET;
+	struct struct_ACCEL_INTEL_CTRL ACCEL_INTEL_CTRL;
+	struct struct_USER_CTRL USER_CTRL;
+
+	struct struct_PWR_MGMT_1 PWR_MGMT_1;
+	struct struct_PWR_MGMT_2 PWR_MGMT_2;
+
+	struct struct_I2C_IF I2C_IF;
+
+	struct struct_FIFO_COUNTH FIFO_COUNTH;
+	struct struct_FIFO_COUNTL FIFO_COUNTL;
+	struct struct_FIFO_R_W FIFO_R_W;
+
+	struct struct_WHO_AM_I WHO_AM_I;
+
+	struct struct_XA_OFFSET_H XA_OFFSET_H;
+	struct struct_XA_OFFSET_L XA_OFFSET_L;
+	struct struct_YA_OFFSET_H YA_OFFSET_H;
+	struct struct_YA_OFFSET_L YA_OFFSET_L;
+	struct struct_ZA_OFFSET_H ZA_OFFSET_H;
+	struct struct_ZA_OFFSET_L ZA_OFFSET_L;
+};
+
+
diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c
new file mode 100644
index 0000000..0f7fc92
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Copyright (C) 2012 Invensense, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/kfifo.h>
+#include <linux/spinlock.h>
+#include <linux/spi/spi.h>
+#include <linux/i2c.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include "inv_icm20602_iio.h"
+
+/* Attribute of icm20602 device init show */
+static ssize_t inv_icm20602_init_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	return 0;
+}
+
+static void inv_icm20602_def_config(struct inv_icm20602_state *st)
+{
+	struct icm20602_user_config *config = st->config;
+
+	config->user_fps_in_ms = 10;
+	config->gyro_lpf = INV_ICM20602_GYRO_LFP_92HZ;
+	config->gyro_fsr = ICM20602_GYRO_FSR_1000DPS;
+	config->acc_lpf = ICM20602_ACCLFP_99;
+	config->acc_fsr = ICM20602_ACC_FSR_4G;
+	config->gyro_accel_sample_rate = ICM20602_SAMPLE_RATE_100HZ;
+	config->fifo_enabled = true;
+
+}
+
+static void inv_icm20602_load_config(struct inv_icm20602_state *st)
+{
+	struct icm20602_user_config *config = st->config;
+
+	if (config->user_fps_in_ms == 0)
+		inv_icm20602_def_config(st);
+	config->fifo_enabled = true;
+
+}
+
+static ssize_t inv_icm20602_init_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int result = MPU_SUCCESS;
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct inv_icm20602_state *st = iio_priv(indio_dev);
+
+	inv_icm20602_load_config(st);
+	result |= icm20602_detect(st);
+	result |= icm20602_init_device(st);
+	icm20602_start_fifo(st);
+	if (result)
+		return result;
+
+	return count;
+}
+
+static IIO_DEVICE_ATTR(
+						inv_icm20602_init,
+						0644,
+						inv_icm20602_init_show,
+						inv_icm20602_init_store,
+						0);
+
+/* Attribute of gyro lpf base on the enum inv_icm20602_gyro_temp_lpf_e */
+static ssize_t inv_gyro_lpf_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	return 0;
+}
+
+static ssize_t inv_gyro_lpf_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct inv_icm20602_state *st = iio_priv(indio_dev);
+	struct icm20602_user_config *config = st->config;
+	int gyro_lpf;
+
+	if (kstrtoint(buf, 10, &gyro_lpf))
+		return -EINVAL;
+	if (gyro_lpf > INV_ICM20602_GYRO_LFP_NUM)
+		return -EINVAL;
+	config->gyro_lpf = gyro_lpf;
+	return count;
+}
+static IIO_DEVICE_ATTR(
+						inv_icm20602_gyro_lpf,
+						0644,
+						inv_gyro_lpf_show,
+						inv_gyro_lpf_store,
+						0);
+
+/* Attribute of gyro fsr base on enum inv_icm20602_gyro_temp_lpf_e */
+static ssize_t inv_gyro_fsr_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	return 0;
+}
+
+static ssize_t inv_gyro_fsr_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct inv_icm20602_state *st = iio_priv(indio_dev);
+	struct icm20602_user_config *config = st->config;
+	int gyro_fsr;
+
+	if (kstrtoint(buf, 10, &gyro_fsr))
+		return -EINVAL;
+	if (gyro_fsr > ICM20602_GYRO_FSR_NUM)
+		return -EINVAL;
+
+	config->gyro_fsr = gyro_fsr;
+	return count;
+}
+
+static IIO_DEVICE_ATTR(
+						inv_icm20602_gyro_fsr,
+						0644,
+						inv_gyro_fsr_show,
+						inv_gyro_fsr_store,
+						0);
+
+/* Attribute of gyro_self_test */
+static ssize_t inv_gyro_self_test_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return 0;
+}
+
+static ssize_t inv_gyro_self_test_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	return 0;
+}
+static IIO_DEVICE_ATTR(
+						inv_icm20602_gyro_self_test,
+						0644,
+						inv_gyro_self_test_show,
+						inv_gyro_self_test_store,
+						0);
+
+/* Attribute of gyro fsr base on enum inv_icm20602_acc_fsr_e */
+static ssize_t inv_gyro_acc_fsr_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return 0;
+}
+
+static ssize_t inv_gyro_acc_fsr_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct inv_icm20602_state *st = iio_priv(indio_dev);
+	struct icm20602_user_config *config = st->config;
+	int acc_fsr;
+
+	if (kstrtoint(buf, 10, &acc_fsr))
+		return -EINVAL;
+	if (acc_fsr > ICM20602_ACC_FSR_NUM)
+		return -EINVAL;
+
+	config->acc_fsr = acc_fsr;
+	return count;
+}
+static IIO_DEVICE_ATTR(
+						inv_icm20602_acc_fsr,
+						0644,
+						inv_gyro_acc_fsr_show,
+						inv_gyro_acc_fsr_store,
+						0);
+
+/* Attribute of gyro fsr base on enum inv_icm20602_acc_lpf_e */
+static ssize_t inv_gyro_acc_lpf_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return 0;
+}
+
+static ssize_t inv_gyro_acc_lpf_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct inv_icm20602_state *st = iio_priv(indio_dev);
+	struct icm20602_user_config *config = st->config;
+	int acc_lpf;
+
+	if (kstrtoint(buf, 10, &acc_lpf))
+		return -EINVAL;
+	if (acc_lpf > ICM20602_ACCLPF_NUM)
+		return -EINVAL;
+
+	config->acc_fsr = acc_lpf;
+	return count;
+}
+static IIO_DEVICE_ATTR(
+						inv_icm20602_acc_lpf,
+						0644,
+						inv_gyro_acc_lpf_show,
+						inv_gyro_acc_lpf_store,
+						0);
+
+/* Attribute of acc_self_test */
+static ssize_t inv_acc_self_test_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return 0;
+}
+
+static ssize_t inv_acc_self_test_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	return 0;
+}
+static IIO_DEVICE_ATTR(
+						inv_icm20602_acc_self_test,
+						0644,
+						inv_acc_self_test_show,
+						inv_acc_self_test_store,
+						0);
+
+/* Attribute of user_fps_in_ms */
+static ssize_t inv_user_fps_in_ms_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return 0;
+}
+
+static ssize_t inv_user_fps_in_ms_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct inv_icm20602_state *st = iio_priv(indio_dev);
+	struct icm20602_user_config *config = st->config;
+	int user_fps_in_ms;
+
+	if (kstrtoint(buf, 10, &user_fps_in_ms))
+		return -EINVAL;
+	if (user_fps_in_ms < 10)
+		return -EINVAL;
+
+	config->user_fps_in_ms = user_fps_in_ms;
+	return count;
+}
+static IIO_DEVICE_ATTR(
+						inv_user_fps_in_ms,
+						0644,
+						inv_user_fps_in_ms_show,
+						inv_user_fps_in_ms_store,
+						0);
+
+/* Attribute of gyro_accel_sample_rate */
+static ssize_t inv_sampling_frequency_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return 0;
+}
+
+static ssize_t inv_sampling_frequency_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	return 0;
+}
+static IIO_DEV_ATTR_SAMP_FREQ(
+						0644,
+						inv_sampling_frequency_show,
+						inv_sampling_frequency_store);
+
+static struct attribute *inv_icm20602_attributes[] = {
+	&iio_dev_attr_inv_icm20602_init.dev_attr.attr,
+
+	&iio_dev_attr_inv_icm20602_gyro_self_test.dev_attr.attr,
+	&iio_dev_attr_inv_icm20602_gyro_fsr.dev_attr.attr,
+	&iio_dev_attr_inv_icm20602_gyro_lpf.dev_attr.attr,
+
+	&iio_dev_attr_inv_icm20602_acc_self_test.dev_attr.attr,
+	&iio_dev_attr_inv_icm20602_acc_fsr.dev_attr.attr,
+	&iio_dev_attr_inv_icm20602_acc_lpf.dev_attr.attr,
+
+	&iio_dev_attr_sampling_frequency.dev_attr.attr,
+
+	&iio_dev_attr_inv_user_fps_in_ms.dev_attr.attr,
+	NULL,
+};
+
+#define INV_ICM20602_CHAN(_type, _channel2, _index)                    \
+{                                                             \
+	.type = _type,                                        \
+	.modified = 1,                                        \
+	.channel2 = _channel2,                                \
+	.info_mask_shared_by_type =  BIT(IIO_CHAN_INFO_SCALE), \
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),         \
+	.scan_index = _index,                                 \
+	.scan_type = {                                        \
+			.sign = 's',                          \
+			.realbits = 16,                       \
+			.storagebits = 16,                    \
+			.shift = 0,                          \
+			.endianness = IIO_BE,                 \
+	},                                       \
+}
+
+static const struct iio_chan_spec inv_icm20602_channels[] = {
+	IIO_CHAN_SOFT_TIMESTAMP(INV_ICM20602_SCAN_TIMESTAMP),
+
+	{
+		.type = IIO_TEMP,
+		.info_mask_separate =  BIT(IIO_CHAN_INFO_RAW)
+				| BIT(IIO_CHAN_INFO_OFFSET)
+				| BIT(IIO_CHAN_INFO_SCALE),
+		.scan_index = INV_ICM20602_SCAN_TEMP,
+		.channel2 = IIO_MOD_X,
+		.scan_type = {
+				.sign = 's',
+				.realbits = 16,
+				.storagebits = 16,
+				.shift = 0,
+				.endianness = IIO_BE,
+			     },
+	},
+	INV_ICM20602_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_ICM20602_SCAN_GYRO_X),
+	INV_ICM20602_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_ICM20602_SCAN_GYRO_Y),
+	INV_ICM20602_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_ICM20602_SCAN_GYRO_Z),
+
+	INV_ICM20602_CHAN(IIO_ACCEL, IIO_MOD_X, INV_ICM20602_SCAN_ACCL_X),
+	INV_ICM20602_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_ICM20602_SCAN_ACCL_Y),
+	INV_ICM20602_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_ICM20602_SCAN_ACCL_Z),
+};
+
+static const struct attribute_group inv_icm20602_attribute_group = {
+	.attrs = inv_icm20602_attributes,
+};
+
+static const struct iio_info icm20602_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = NULL,
+	.write_raw = NULL,
+	.attrs = &inv_icm20602_attribute_group,
+	.validate_trigger = inv_icm20602_validate_trigger,
+};
+
+static int of_populate_icm20602_dt(struct inv_icm20602_state *st)
+{
+	int result = MPU_SUCCESS;
+
+	/* use client device irq */
+	st->gpio = of_get_named_gpio(st->client->dev.of_node,
+			"invensense,icm20602-gpio", 0);
+	result = gpio_is_valid(st->gpio);
+	if (!result) {
+		pr_err("gpio_is_valid %d failed\n", st->gpio);
+		return -MPU_FAIL;
+	}
+
+	result = gpio_request(st->gpio, "icm20602-irq");
+	if (result) {
+		pr_err("gpio_request failed\n");
+		return -MPU_FAIL;
+	}
+
+	result = gpio_direction_input(st->gpio);
+	if (result) {
+		pr_err("gpio_direction_input failed\n");
+		return -MPU_FAIL;
+	}
+
+	st->client->irq = gpio_to_irq(st->gpio);
+	if (st->client->irq < 0) {
+		pr_err("gpio_to_irq failed\n");
+		return -MPU_FAIL;
+	}
+
+	return MPU_SUCCESS;
+}
+
+/*
+ *  inv_icm20602_probe() - probe function.
+ *  @client:          i2c client.
+ *  @id:              i2c device id.
+ *
+ *  Returns 0 on success, a negative error code otherwise.
+ *  The I2C address of the ICM-20602 is 0x68 or 0x69
+ *  depending upon the value driven on AD0 pin.
+ */
+static int inv_icm20602_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	struct inv_icm20602_state *st;
+	struct iio_dev *indio_dev;
+	int result = MPU_SUCCESS;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
+	if (indio_dev == NULL) {
+		result =  -ENOMEM;
+		goto out_remove_trigger;
+	}
+	st = iio_priv(indio_dev);
+	st->client = client;
+	st->interface = ICM20602_I2C;
+
+	pr_debug("i2c address is %x\n", client->addr);
+	result = of_populate_icm20602_dt(st);
+	if (result)
+		return result;
+
+	st->config = kzalloc(sizeof(struct icm20602_user_config), GFP_ATOMIC);
+	if (st->config == NULL)
+		return -ENOMEM;
+
+	icm20602_init_reg_map();
+
+	i2c_set_clientdata(client, indio_dev);
+
+	dev_set_drvdata(&client->dev, indio_dev);
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->name = ICM20602_DEV_NAME;
+	indio_dev->channels = inv_icm20602_channels;
+	indio_dev->num_channels = ARRAY_SIZE(inv_icm20602_channels);
+
+	indio_dev->info = &icm20602_info;
+	indio_dev->modes = INDIO_BUFFER_TRIGGERED;
+	result = iio_triggered_buffer_setup(indio_dev,
+		inv_icm20602_irq_handler, inv_icm20602_read_fifo_fn, NULL);
+	if (result) {
+		dev_err(&st->client->dev, " configure buffer fail %d\n",
+				result);
+		goto out_remove_trigger;
+	}
+
+	result = inv_icm20602_probe_trigger(indio_dev);
+	if (result) {
+		dev_err(&st->client->dev, "trigger probe fail %d\n", result);
+		goto out_unreg_ring;
+	}
+
+	INIT_KFIFO(st->timestamps);
+	spin_lock_init(&st->time_stamp_lock);
+	result = iio_device_register(indio_dev);
+	if (result) {
+		dev_err(&st->client->dev, "IIO register fail %d\n", result);
+		goto out_remove_trigger;
+	}
+
+	return 0;
+
+out_remove_trigger:
+	inv_icm20602_remove_trigger(st);
+out_unreg_ring:
+	iio_triggered_buffer_cleanup(indio_dev);
+out_free:
+	iio_device_free(indio_dev);
+	gpio_free(st->gpio);
+
+	return 0;
+}
+
+static int inv_icm20602_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct inv_icm20602_state *st = iio_priv(indio_dev);
+
+	gpio_free(st->gpio);
+	iio_device_unregister(indio_dev);
+	inv_icm20602_remove_trigger(st);
+	iio_triggered_buffer_cleanup(indio_dev);
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static int inv_icm20602_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int inv_icm20602_resume(struct device *dev)
+{
+	return 0;
+}
+
+static const struct dev_pm_ops icm20602_pm_ops = {
+	.resume		=	inv_icm20602_resume,
+	.suspend	=	inv_icm20602_suspend,
+};
+
+static const struct of_device_id icm20602_match_table[] = {
+	{.compatible = "invensense,icm20602"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, icm20602_match_table);
+
+static const struct i2c_device_id inv_icm20602_id[] = {
+	{"icm20602", 0},
+	{}
+};
+
+static struct i2c_driver icm20602_i2c_driver = {
+	.probe		=	inv_icm20602_probe,
+	.remove		=	inv_icm20602_remove,
+	.id_table	=	inv_icm20602_id,
+	.driver = {
+		.owner	=	THIS_MODULE,
+		.name	=	"inv-icm20602",
+		.of_match_table = icm20602_match_table,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+		.pm = &icm20602_pm_ops,
+	},
+};
+
+static int __init inv_icm20602_init(void)
+{
+	return i2c_add_driver(&icm20602_i2c_driver);
+}
+module_init(inv_icm20602_init);
+
+static void __exit inv_icm20602_exit(void)
+{
+	i2c_del_driver(&icm20602_i2c_driver);
+}
+module_exit(inv_icm20602_exit);
+
+MODULE_DESCRIPTION("icm20602 IMU driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h b/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h
new file mode 100644
index 0000000..943fc1e
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Copyright (C) 2012 Invensense, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _INV_ICM20602_IIO_H_
+#define _INV_ICM20602_IIO_H_
+
+#include <linux/i2c.h>
+#include <linux/kfifo.h>
+#include <linux/spinlock.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/platform_data/invensense_mpu6050.h>
+
+/*
+ * it uses sensor irq to trigger
+ * if set INV20602_DEVICE_IRQ_TRIGGER as 1,
+ * otherwise use SMD IRQ to trigger
+ */
+#define INV20602_DEVICE_IRQ_TRIGGER    0
+
+#if INV20602_DEVICE_IRQ_TRIGGER
+#define INV20602_SMD_IRQ_TRIGGER    0
+#else
+#define INV20602_SMD_IRQ_TRIGGER    1
+#endif
+
+#define INV_ICM20602_TIME_STAMP_TOR           5
+#define ICM20602_PACKAGE_SIZE 14
+
+/* device enum */
+enum inv_devices {
+	INV_ICM20602,
+	INV_NUM_PARTS,
+};
+
+enum _mpu_err {
+	MPU_SUCCESS = 0,
+	MPU_FAIL = 1,
+	MPU_READ_FAIL = 2,
+	MPU_WRITE_FAIL = 3,
+};
+
+/* Gyro Full Scale Range Enum */
+enum inv_icm20602_gyro_fsr_e {
+	ICM20602_GYRO_FSR_250DPS = 0,
+	ICM20602_GYRO_FSR_500DPS,
+	ICM20602_GYRO_FSR_1000DPS,
+	ICM20602_GYRO_FSR_2000DPS,
+	ICM20602_GYRO_FSR_NUM,
+};
+
+/* Accelerometor Full Scale Range Enum */
+enum inv_icm20602_acc_fsr_e {
+	ICM20602_ACC_FSR_2G = 0,
+	ICM20602_ACC_FSR_4G,
+	ICM20602_ACC_FSR_8G,
+	ICM20602_ACC_FSR_16G,
+	ICM20602_ACC_FSR_NUM,
+};
+
+/* scan element definition */
+enum inv_icm20602_scan {
+	INV_ICM20602_SCAN_ACCL_X,
+	INV_ICM20602_SCAN_ACCL_Y,
+	INV_ICM20602_SCAN_ACCL_Z,
+	INV_ICM20602_SCAN_GYRO_X,
+	INV_ICM20602_SCAN_GYRO_Y,
+	INV_ICM20602_SCAN_GYRO_Z,
+	INV_ICM20602_SCAN_TEMP,
+	INV_ICM20602_SCAN_TIMESTAMP,
+};
+
+/* this is for CONFIGURATION reg bit[2:0] DLFP_CFG */
+enum inv_icm20602_gyro_temp_lpf_e {
+	INV_ICM20602_GLFP_250HZ = 0,  /* 8KHz */
+	INV_ICM20602_GYRO_LFP_176HZ,      /* 1KHz */
+	INV_ICM20602_GYRO_LFP_92HZ,
+	INV_ICM20602_GYRO_LFP_41HZ,
+	INV_ICM20602_GYRO_LFP_20HZ,
+	INV_ICM20602_GYRO_LFP_10HZ,
+	INV_ICM20602_GYRO_LFP_5HZ,
+	INV_ICM20602_GYRO_LFP_NUM,
+};
+
+enum inv_icm20602_gyro_sample_rate_e {
+	ICM20602_SAMPLE_RATE_100HZ = 100,
+	ICM20602_SAMPLE_RATE_200HZ = 200,
+	ICM20602_SAMPLE_RATE_500HZ = 500,
+	ICM20602_SAMPLE_RATE_1000HZ = 1000,
+};
+
+/* this is for ACCEL CONFIGURATION 2 reg */
+enum inv_icm20602_acc_lpf_e {
+	ICM20602_ACCLFP_218 = 1,
+	ICM20602_ACCLFP_99,
+	ICM20602_ACCLFP_44,
+	ICM20602_ACCLFP_21,
+	ICM20602_ACCLFP_10,
+	ICM20602_ACCLFP_5,
+	ICM20602_ACCLFP_420_NOLPF,
+	ICM20602_ACCLPF_NUM = 7,
+};
+
+/* IIO attribute address */
+enum INV_ICM20602_IIO_ATTR_ADDR {
+	ATTR_ICM20602_GYRO_MATRIX,
+	ATTR_ICM20602_ACCL_MATRIX,
+};
+
+/* this is for GYRO CONFIGURATION reg */
+enum inv_icm20602_fs_e {
+	INV_ICM20602_FS_250DPS = 0,
+	INV_ICM20602_FS_500DPS,
+	INV_ICM20602_FS_1000DPS,
+	INV_ICM20602_FS_2000DPS,
+	NUM_ICM20602_FS,
+};
+
+enum inv_icm20602_clock_sel_e {
+	INV_ICM20602_CLK_INTERNAL = 0,
+	INV_ICM20602_CLK_PLL,
+	INV_NUM_CLK,
+};
+
+enum inv_icm20602_spi_freq {
+	MPU_SPI_FREQUENCY_1MHZ = 960000UL,
+	MPU_SPI_FREQUENCY_5MHZ = 4800000UL,
+	MPU_SPI_FREQUENCY_8MHZ = 8000000UL,
+	MPU_SPI_FREQUENCY_10MHZ = 10000000UL,
+	MPU_SPI_FREQUENCY_15MHZ = 15000000UL,
+	MPU_SPI_FREQUENCY_20MHZ = 20000000UL,
+};
+
+#define MPU_SPI_BUF_LEN   512
+#define	ICM20602_DEV_NAME	"icm20602_iio"
+
+struct inv_icm20602_platform_data {
+	__s8 orientation[9];
+};
+
+struct X_Y_Z {
+	u8 X;
+	u8 Y;
+	u8 Z;
+};
+
+enum RAW_TYPE {
+	ACCEL = 1,
+	GYRO  = 2,
+	TEMP  = 4,
+};
+
+struct icm20602_user_config {
+	enum inv_icm20602_gyro_temp_lpf_e gyro_lpf;
+	enum inv_icm20602_gyro_fsr_e gyro_fsr;
+	struct X_Y_Z gyro_self_test;
+
+	enum inv_icm20602_acc_lpf_e	acc_lpf;
+	enum inv_icm20602_acc_fsr_e	acc_fsr;
+	struct X_Y_Z acc_self_test;
+
+	uint32_t gyro_accel_sample_rate;
+	uint32_t user_fps_in_ms;
+
+	bool fifo_enabled;
+	uint32_t fifo_waterlevel;
+	struct X_Y_Z wake_on_motion;
+};
+
+enum inv_icm20602_interface {
+	ICM20602_I2C = 0,
+	ICM20602_SPI
+};
+
+/*
+ *  struct inv_icm20602_state - Driver state variables.
+ *  @TIMESTAMP_FIFO_SIZE: fifo size for timestamp.
+ *  @trig:              IIO trigger.
+ *  @chip_config:	Cached attribute information.
+ *  @reg:		Map of important registers.
+ *  @hw:		Other hardware-specific information.
+ *  @chip_type:		chip type.
+ *  @time_stamp_lock:	spin lock to time stamp.
+ *  @spi: spi devices
+ *  @plat_data:		platform data.
+ *  @timestamps:        kfifo queue to store time stamp.
+ */
+struct inv_icm20602_state {
+#define TIMESTAMP_FIFO_SIZE 32
+	enum inv_icm20602_interface interface;
+	struct iio_trigger  *trig;
+	const struct inv_icm20602_reg_map *reg;
+	struct icm20602_user_config *config;
+	spinlock_t time_stamp_lock;
+	struct spi_device *spi;
+	struct i2c_client *client;
+	u8 fifo_packet_size;
+	int fifo_cnt_threshold;
+	char *buf;
+	struct struct_icm20602_data *data_push;
+	enum inv_devices chip_type;
+	int gpio;
+	DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE);
+};
+
+struct struct_icm20602_raw_data {
+	u8 ACCEL_XOUT_H;
+	u8 ACCEL_XOUT_L;
+
+	u8 ACCEL_YOUT_H;
+	u8 ACCEL_YOUT_L;
+
+	u8 ACCEL_ZOUT_H;
+	u8 ACCEL_ZOUT_L;
+
+	u8 TEMP_OUT_H;
+	u8 TEMP_OUT_L;
+
+	u8 GYRO_XOUT_H;
+	u8 GYRO_XOUT_L;
+
+	u8 GYRO_YOUT_H;
+	u8 GYRO_YOUT_L;
+
+	u8 GYRO_ZOUT_H;
+	u8 GYRO_ZOUT_L;
+};
+
+struct struct_icm20602_real_data {
+	u16 ACCEL_XOUT;
+	u16 ACCEL_YOUT;
+	u16 ACCEL_ZOUT;
+
+	u16 GYRO_XOUT;
+	u16 GYRO_YOUT;
+	u16 GYRO_ZOUT;
+
+	u16 TEMP_OUT;
+};
+
+struct struct_icm20602_data {
+	s64 timestamps;
+	struct struct_icm20602_raw_data raw_data;
+	struct struct_icm20602_real_data real_data;
+};
+
+extern struct iio_trigger *inv_trig;
+irqreturn_t inv_icm20602_irq_handler(int irq, void *p);
+irqreturn_t inv_icm20602_read_fifo_fn(int irq, void *p);
+int inv_icm20602_reset_fifo(struct iio_dev *indio_dev);
+
+int inv_icm20602_probe_trigger(struct iio_dev *indio_dev);
+void inv_icm20602_remove_trigger(struct inv_icm20602_state *st);
+int inv_icm20602_validate_trigger(struct iio_dev *indio_dev,
+				struct iio_trigger *trig);
+
+int icm20602_read_raw(struct inv_icm20602_state *st,
+		struct struct_icm20602_real_data *real_data, uint32_t type);
+int icm20602_init_reg_map(void);
+int icm20602_init_device(struct inv_icm20602_state *st);
+int icm20602_detect(struct inv_icm20602_state *st);
+int icm20602_read_fifo(struct inv_icm20602_state *st,
+	void *buf, const int size);
+int icm20602_start_fifo(struct inv_icm20602_state *st);
+#endif
diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_ring.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_ring.c
new file mode 100644
index 0000000..b0f93be
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_ring.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Copyright (C) 2012 Invensense, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/kfifo.h>
+#include <linux/poll.h>
+#include <linux/spi/spi.h>
+#include "inv_icm20602_iio.h"
+#include <linux/i2c.h>
+
+#define combine_8_to_16(upper, lower)  ((_upper << 8) | _lower)
+
+static void inv_clear_kfifo(struct inv_icm20602_state *st)
+{
+	unsigned long flags;
+
+	/* Take the spin lock sem to avoid interrupt kick in */
+	spin_lock_irqsave(&st->time_stamp_lock, flags);
+	kfifo_reset(&st->timestamps);
+	spin_unlock_irqrestore(&st->time_stamp_lock, flags);
+}
+
+int inv_icm20602_reset_fifo(struct iio_dev *indio_dev)
+{
+	int result;
+	//u8 d;
+	//struct inv_icm20602_state  *st = iio_priv(indio_dev);
+
+	return result;
+}
+
+/*
+ * inv_icm20602_irq_handler() - Cache a timestamp at each data ready interrupt.
+ */
+irqreturn_t inv_icm20602_irq_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct inv_icm20602_state *st = iio_priv(indio_dev);
+	s64 timestamp;
+
+	timestamp = iio_get_time_ns(indio_dev);
+
+	kfifo_in_spinlocked(&st->timestamps, &timestamp, 1,
+				&st->time_stamp_lock);
+
+	return IRQ_WAKE_THREAD;
+}
+
+static int inv_icm20602_read_data(struct iio_dev *indio_dev)
+{
+	int result = MPU_SUCCESS;
+	struct inv_icm20602_state *st = iio_priv(indio_dev);
+	struct icm20602_user_config *config = st->config;
+	int package_count;
+	//char *buf = st->buf;
+	//struct struct_icm20602_data *data_push = st->data_push;
+	s64 timestamp;
+	int i;
+
+	if (!st)
+		return -MPU_FAIL;
+	package_count = config->fifo_waterlevel / ICM20602_PACKAGE_SIZE;
+	mutex_lock(&indio_dev->mlock);
+	if (config->fifo_enabled) {
+		result = icm20602_read_fifo(st,
+				st->buf, config->fifo_waterlevel);
+		if (result != config->fifo_waterlevel) {
+			pr_err("icm20602 read fifo failed, result = %d\n",
+				result);
+			goto flush_fifo;
+		}
+
+		for (i = 0; i < package_count; i++) {
+			memcpy((char *)(&st->data_push[i].raw_data),
+				st->buf, ICM20602_PACKAGE_SIZE);
+			result = kfifo_out(&st->timestamps,
+				&timestamp, 1);
+			/* when there is no timestamp, put it as 0 */
+			if (result == 0)
+				timestamp = 0;
+			st->data_push[i].timestamps = timestamp;
+			iio_push_to_buffers(indio_dev, st->data_push+i);
+			st->buf += ICM20602_PACKAGE_SIZE;
+		}
+	}
+//end_session:
+	mutex_unlock(&indio_dev->mlock);
+	iio_trigger_notify_done(indio_dev->trig);
+	return MPU_SUCCESS;
+
+flush_fifo:
+	/* Flush HW and SW FIFOs. */
+	inv_clear_kfifo(st);
+	inv_icm20602_reset_fifo(indio_dev);
+	mutex_unlock(&indio_dev->mlock);
+	iio_trigger_notify_done(indio_dev->trig);
+	return MPU_SUCCESS;
+}
+
+/*
+ * inv_icm20602_read_fifo() - Transfer data from hardware FIFO to KFIFO.
+ */
+irqreturn_t inv_icm20602_read_fifo_fn(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+
+	inv_icm20602_read_data(indio_dev);
+	return IRQ_HANDLED;
+}
diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_trigger.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_trigger.c
new file mode 100644
index 0000000..f05a631
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_trigger.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Copyright (C) 2012 Invensense, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/spi/spi.h>
+#include <linux/sched/rt.h>
+#include <linux/delay.h>
+#include "inv_icm20602_iio.h"
+#include <linux/i2c.h>
+
+static const struct iio_trigger_ops inv_icm20602_trigger_ops = {
+	.owner = THIS_MODULE,
+};
+
+int inv_icm20602_validate_trigger(struct iio_dev *indio_dev,
+					struct iio_trigger *trig)
+{
+	struct inv_icm20602_state *st = iio_priv(indio_dev);
+
+	if (st->trig != trig)
+		return -EINVAL;
+
+	return 0;
+}
+
+int inv_icm20602_probe_trigger(struct iio_dev *indio_dev)
+{
+	int ret;
+	struct inv_icm20602_state *st = iio_priv(indio_dev);
+
+	st->trig = iio_trigger_alloc("%s-dev%d",
+					indio_dev->name,
+					indio_dev->id);
+	if (st->trig == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	ret = request_irq(st->client->irq, &iio_trigger_generic_data_rdy_poll,
+				IRQF_TRIGGER_RISING,
+				"inv_icm20602",
+				st->trig);
+	if (ret) {
+		pr_err("request_irq failed\n");
+		goto error_free_trig;
+	}
+	st->trig->dev.parent = &st->client->dev;
+	st->trig->ops = &inv_icm20602_trigger_ops;
+	iio_trigger_set_drvdata(st->trig, indio_dev);
+	ret = iio_trigger_register(st->trig);
+	if (ret) {
+		pr_err("iio_trigger_register failed\n");
+		goto error_free_irq;
+	}
+	indio_dev->trig = st->trig;
+
+	return 0;
+
+error_free_irq:
+	free_irq(st->client->irq, st->trig);
+error_free_trig:
+	iio_trigger_free(st->trig);
+error_ret:
+	return ret;
+}
+
+void inv_icm20602_remove_trigger(struct inv_icm20602_state *st)
+{
+	iio_trigger_unregister(st->trig);
+	free_irq(st->client->irq, st->trig);
+	iio_trigger_free(st->trig);
+}
diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c
index 7de0f39..d23cf77 100644
--- a/drivers/iio/light/rpr0521.c
+++ b/drivers/iio/light/rpr0521.c
@@ -510,13 +510,26 @@
 
 	ret = pm_runtime_set_active(&client->dev);
 	if (ret < 0)
-		return ret;
+		goto err_poweroff;
 
 	pm_runtime_enable(&client->dev);
 	pm_runtime_set_autosuspend_delay(&client->dev, RPR0521_SLEEP_DELAY_MS);
 	pm_runtime_use_autosuspend(&client->dev);
 
-	return iio_device_register(indio_dev);
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto err_pm_disable;
+
+	return 0;
+
+err_pm_disable:
+	pm_runtime_disable(&client->dev);
+	pm_runtime_set_suspended(&client->dev);
+	pm_runtime_put_noidle(&client->dev);
+err_poweroff:
+	rpr0521_poweroff(data);
+
+	return ret;
 }
 
 static int rpr0521_remove(struct i2c_client *client)
diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c
index 6325e7d..f3cb4dc 100644
--- a/drivers/iio/magnetometer/st_magn_spi.c
+++ b/drivers/iio/magnetometer/st_magn_spi.c
@@ -48,8 +48,6 @@
 }
 
 static const struct spi_device_id st_magn_id_table[] = {
-	{ LSM303DLHC_MAGN_DEV_NAME },
-	{ LSM303DLM_MAGN_DEV_NAME },
 	{ LIS3MDL_MAGN_DEV_NAME },
 	{ LSM303AGR_MAGN_DEV_NAME },
 	{},
diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c
index 19d2eb4..2a4a62e 100644
--- a/drivers/iio/pressure/zpa2326.c
+++ b/drivers/iio/pressure/zpa2326.c
@@ -871,12 +871,13 @@
 {
 	int          ret;
 	unsigned int val;
+	long     timeout;
 
 	zpa2326_dbg(indio_dev, "waiting for one shot completion interrupt");
 
-	ret = wait_for_completion_interruptible_timeout(
+	timeout = wait_for_completion_interruptible_timeout(
 		&private->data_ready, ZPA2326_CONVERSION_JIFFIES);
-	if (ret > 0)
+	if (timeout > 0)
 		/*
 		 * Interrupt handler completed before timeout: return operation
 		 * status.
@@ -886,13 +887,16 @@
 	/* Clear all interrupts just to be sure. */
 	regmap_read(private->regmap, ZPA2326_INT_SOURCE_REG, &val);
 
-	if (!ret)
+	if (!timeout) {
 		/* Timed out. */
+		zpa2326_warn(indio_dev, "no one shot interrupt occurred (%ld)",
+			     timeout);
 		ret = -ETIME;
-
-	if (ret != -ERESTARTSYS)
-		zpa2326_warn(indio_dev, "no one shot interrupt occurred (%d)",
-			     ret);
+	} else if (timeout < 0) {
+		zpa2326_warn(indio_dev,
+			     "wait for one shot interrupt cancelled");
+		ret = -ERESTARTSYS;
+	}
 
 	return ret;
 }
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index fb4ce03..978b8d9 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -209,6 +209,22 @@
 }
 EXPORT_SYMBOL(rdma_addr_size);
 
+int rdma_addr_size_in6(struct sockaddr_in6 *addr)
+{
+	int ret = rdma_addr_size((struct sockaddr *) addr);
+
+	return ret <= sizeof(*addr) ? ret : 0;
+}
+EXPORT_SYMBOL(rdma_addr_size_in6);
+
+int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr)
+{
+	int ret = rdma_addr_size((struct sockaddr *) addr);
+
+	return ret <= sizeof(*addr) ? ret : 0;
+}
+EXPORT_SYMBOL(rdma_addr_size_kss);
+
 static struct rdma_addr_client self;
 
 void rdma_addr_register_client(struct rdma_addr_client *client)
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 017a09c..cb79d17 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -132,7 +132,7 @@
 	ctx = idr_find(&ctx_idr, id);
 	if (!ctx)
 		ctx = ERR_PTR(-ENOENT);
-	else if (ctx->file != file)
+	else if (ctx->file != file || !ctx->cm_id)
 		ctx = ERR_PTR(-EINVAL);
 	return ctx;
 }
@@ -454,6 +454,7 @@
 	struct rdma_ucm_create_id cmd;
 	struct rdma_ucm_create_id_resp resp;
 	struct ucma_context *ctx;
+	struct rdma_cm_id *cm_id;
 	enum ib_qp_type qp_type;
 	int ret;
 
@@ -474,10 +475,10 @@
 		return -ENOMEM;
 
 	ctx->uid = cmd.uid;
-	ctx->cm_id = rdma_create_id(current->nsproxy->net_ns,
-				    ucma_event_handler, ctx, cmd.ps, qp_type);
-	if (IS_ERR(ctx->cm_id)) {
-		ret = PTR_ERR(ctx->cm_id);
+	cm_id = rdma_create_id(current->nsproxy->net_ns,
+			       ucma_event_handler, ctx, cmd.ps, qp_type);
+	if (IS_ERR(cm_id)) {
+		ret = PTR_ERR(cm_id);
 		goto err1;
 	}
 
@@ -487,14 +488,19 @@
 		ret = -EFAULT;
 		goto err2;
 	}
+
+	ctx->cm_id = cm_id;
 	return 0;
 
 err2:
-	rdma_destroy_id(ctx->cm_id);
+	rdma_destroy_id(cm_id);
 err1:
 	mutex_lock(&mut);
 	idr_remove(&ctx_idr, ctx->id);
 	mutex_unlock(&mut);
+	mutex_lock(&file->mut);
+	list_del(&ctx->list);
+	mutex_unlock(&file->mut);
 	kfree(ctx);
 	return ret;
 }
@@ -624,6 +630,9 @@
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
 
+	if (!rdma_addr_size_in6(&cmd.addr))
+		return -EINVAL;
+
 	ctx = ucma_get_ctx(file, cmd.id);
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
@@ -637,22 +646,21 @@
 			 int in_len, int out_len)
 {
 	struct rdma_ucm_bind cmd;
-	struct sockaddr *addr;
 	struct ucma_context *ctx;
 	int ret;
 
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
 
-	addr = (struct sockaddr *) &cmd.addr;
-	if (cmd.reserved || !cmd.addr_size || (cmd.addr_size != rdma_addr_size(addr)))
+	if (cmd.reserved || !cmd.addr_size ||
+	    cmd.addr_size != rdma_addr_size_kss(&cmd.addr))
 		return -EINVAL;
 
 	ctx = ucma_get_ctx(file, cmd.id);
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
-	ret = rdma_bind_addr(ctx->cm_id, addr);
+	ret = rdma_bind_addr(ctx->cm_id, (struct sockaddr *) &cmd.addr);
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -668,13 +676,16 @@
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
 
+	if (!rdma_addr_size_in6(&cmd.src_addr) ||
+	    !rdma_addr_size_in6(&cmd.dst_addr))
+		return -EINVAL;
+
 	ctx = ucma_get_ctx(file, cmd.id);
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
 	ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
-				(struct sockaddr *) &cmd.dst_addr,
-				cmd.timeout_ms);
+				(struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms);
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -684,24 +695,23 @@
 				 int in_len, int out_len)
 {
 	struct rdma_ucm_resolve_addr cmd;
-	struct sockaddr *src, *dst;
 	struct ucma_context *ctx;
 	int ret;
 
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
 
-	src = (struct sockaddr *) &cmd.src_addr;
-	dst = (struct sockaddr *) &cmd.dst_addr;
-	if (cmd.reserved || (cmd.src_size && (cmd.src_size != rdma_addr_size(src))) ||
-	    !cmd.dst_size || (cmd.dst_size != rdma_addr_size(dst)))
+	if (cmd.reserved ||
+	    (cmd.src_size && (cmd.src_size != rdma_addr_size_kss(&cmd.src_addr))) ||
+	    !cmd.dst_size || (cmd.dst_size != rdma_addr_size_kss(&cmd.dst_addr)))
 		return -EINVAL;
 
 	ctx = ucma_get_ctx(file, cmd.id);
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
-	ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms);
+	ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
+				(struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms);
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -1146,6 +1156,11 @@
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
+	if (!ctx->cm_id->device) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	resp.qp_attr_mask = 0;
 	memset(&qp_attr, 0, sizeof qp_attr);
 	qp_attr.qp_state = cmd.qp_state;
@@ -1216,6 +1231,9 @@
 	if (!optlen)
 		return -EINVAL;
 
+	if (!ctx->cm_id->device)
+		return -EINVAL;
+
 	memset(&sa_path, 0, sizeof(sa_path));
 
 	ib_sa_unpack_path(path_data->path_rec, &sa_path);
@@ -1302,7 +1320,7 @@
 {
 	struct rdma_ucm_notify cmd;
 	struct ucma_context *ctx;
-	int ret;
+	int ret = -EINVAL;
 
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
@@ -1311,7 +1329,9 @@
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
-	ret = rdma_notify(ctx->cm_id, (enum ib_event_type) cmd.event);
+	if (ctx->cm_id->device)
+		ret = rdma_notify(ctx->cm_id, (enum ib_event_type)cmd.event);
+
 	ucma_put_ctx(ctx);
 	return ret;
 }
@@ -1397,7 +1417,7 @@
 	join_cmd.response = cmd.response;
 	join_cmd.uid = cmd.uid;
 	join_cmd.id = cmd.id;
-	join_cmd.addr_size = rdma_addr_size((struct sockaddr *) &cmd.addr);
+	join_cmd.addr_size = rdma_addr_size_in6(&cmd.addr);
 	if (!join_cmd.addr_size)
 		return -EINVAL;
 
@@ -1416,7 +1436,7 @@
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
 
-	if (!rdma_addr_size((struct sockaddr *)&cmd.addr))
+	if (!rdma_addr_size_kss(&cmd.addr))
 		return -EINVAL;
 
 	return ucma_process_join(file, &cmd, out_len);
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 6512a55..dd18b74 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -488,6 +488,7 @@
 
 	ep = *((struct c4iw_ep **)(skb->cb + 2 * sizeof(void *)));
 	release_ep_resources(ep);
+	kfree_skb(skb);
 	return 0;
 }
 
@@ -498,6 +499,7 @@
 	ep = *((struct c4iw_ep **)(skb->cb + 2 * sizeof(void *)));
 	c4iw_put_ep(&ep->parent_ep->com);
 	release_ep_resources(ep);
+	kfree_skb(skb);
 	return 0;
 }
 
@@ -569,11 +571,13 @@
 
 	PDBG("%s rdev %p\n", __func__, rdev);
 	req->cmd = CPL_ABORT_NO_RST;
+	skb_get(skb);
 	ret = c4iw_ofld_send(rdev, skb);
 	if (ret) {
 		__state_set(&ep->com, DEAD);
 		queue_arp_failure_cpl(ep, skb, FAKE_CPL_PUT_EP_SAFE);
-	}
+	} else
+		kfree_skb(skb);
 }
 
 static int send_flowc(struct c4iw_ep *ep)
diff --git a/drivers/infiniband/hw/hfi1/sysfs.c b/drivers/infiniband/hw/hfi1/sysfs.c
index 919a547..621b60a 100644
--- a/drivers/infiniband/hw/hfi1/sysfs.c
+++ b/drivers/infiniband/hw/hfi1/sysfs.c
@@ -196,7 +196,8 @@
 };
 
 static struct attribute *port_cc_default_attributes[] = {
-	&cc_prescan_attr.attr
+	&cc_prescan_attr.attr,
+	NULL
 };
 
 static struct kobj_type port_cc_ktype = {
diff --git a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c
index 2c4b4d0..3b973cb 100644
--- a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c
+++ b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c
@@ -3644,8 +3644,10 @@
 		hmc_info->hmc_obj[I40IW_HMC_IW_APBVT_ENTRY].cnt = 1;
 		hmc_info->hmc_obj[I40IW_HMC_IW_MR].cnt = mrwanted;
 
-		hmc_info->hmc_obj[I40IW_HMC_IW_XF].cnt = I40IW_MAX_WQ_ENTRIES * qpwanted;
-		hmc_info->hmc_obj[I40IW_HMC_IW_Q1].cnt = 4 * I40IW_MAX_IRD_SIZE * qpwanted;
+		hmc_info->hmc_obj[I40IW_HMC_IW_XF].cnt =
+			roundup_pow_of_two(I40IW_MAX_WQ_ENTRIES * qpwanted);
+		hmc_info->hmc_obj[I40IW_HMC_IW_Q1].cnt =
+			roundup_pow_of_two(2 * I40IW_MAX_IRD_SIZE * qpwanted);
 		hmc_info->hmc_obj[I40IW_HMC_IW_XFFL].cnt =
 			hmc_info->hmc_obj[I40IW_HMC_IW_XF].cnt / hmc_fpm_misc->xf_block_size;
 		hmc_info->hmc_obj[I40IW_HMC_IW_Q1FL].cnt =
diff --git a/drivers/infiniband/hw/i40iw/i40iw_d.h b/drivers/infiniband/hw/i40iw/i40iw_d.h
index d1328a6..8ce599e 100644
--- a/drivers/infiniband/hw/i40iw/i40iw_d.h
+++ b/drivers/infiniband/hw/i40iw/i40iw_d.h
@@ -86,6 +86,7 @@
 #define RDMA_OPCODE_MASK        0x0f
 #define RDMA_READ_REQ_OPCODE    1
 #define Q2_BAD_FRAME_OFFSET     72
+#define Q2_FPSN_OFFSET          64
 #define CQE_MAJOR_DRV           0x8000
 
 #define I40IW_TERM_SENT 0x01
diff --git a/drivers/infiniband/hw/i40iw/i40iw_puda.c b/drivers/infiniband/hw/i40iw/i40iw_puda.c
index c62d354..3ed4914 100644
--- a/drivers/infiniband/hw/i40iw/i40iw_puda.c
+++ b/drivers/infiniband/hw/i40iw/i40iw_puda.c
@@ -1320,7 +1320,7 @@
 	u32 *hw_host_ctx = (u32 *)qp->hw_host_ctx;
 	u32 rcv_wnd = hw_host_ctx[23];
 	/* first partial seq # in q2 */
-	u32 fps = qp->q2_buf[16];
+	u32 fps = *(u32 *)(qp->q2_buf + Q2_FPSN_OFFSET);
 	struct list_head *rxlist = &pfpdu->rxlist;
 	struct list_head *plist;
 
diff --git a/drivers/infiniband/sw/rdmavt/cq.c b/drivers/infiniband/sw/rdmavt/cq.c
index 6d9904a..29dc527 100644
--- a/drivers/infiniband/sw/rdmavt/cq.c
+++ b/drivers/infiniband/sw/rdmavt/cq.c
@@ -197,7 +197,7 @@
 		return ERR_PTR(-EINVAL);
 
 	/* Allocate the completion queue structure. */
-	cq = kzalloc(sizeof(*cq), GFP_KERNEL);
+	cq = kzalloc_node(sizeof(*cq), GFP_KERNEL, rdi->dparms.node);
 	if (!cq)
 		return ERR_PTR(-ENOMEM);
 
@@ -213,7 +213,9 @@
 		sz += sizeof(struct ib_uverbs_wc) * (entries + 1);
 	else
 		sz += sizeof(struct ib_wc) * (entries + 1);
-	wc = vmalloc_user(sz);
+	wc = udata ?
+		vmalloc_user(sz) :
+		vzalloc_node(sz, rdi->dparms.node);
 	if (!wc) {
 		ret = ERR_PTR(-ENOMEM);
 		goto bail_cq;
@@ -368,7 +370,9 @@
 		sz += sizeof(struct ib_uverbs_wc) * (cqe + 1);
 	else
 		sz += sizeof(struct ib_wc) * (cqe + 1);
-	wc = vmalloc_user(sz);
+	wc = udata ?
+		vmalloc_user(sz) :
+		vzalloc_node(sz, rdi->dparms.node);
 	if (!wc)
 		return -ENOMEM;
 
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c
index 59f37f4..ced416f 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.c
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.c
@@ -747,9 +747,8 @@
 		memcpy(wqe->dma.sge, ibwr->sg_list,
 		       num_sge * sizeof(struct ib_sge));
 
-	wqe->iova		= (mask & WR_ATOMIC_MASK) ?
-					atomic_wr(ibwr)->remote_addr :
-					rdma_wr(ibwr)->remote_addr;
+	wqe->iova = mask & WR_ATOMIC_MASK ? atomic_wr(ibwr)->remote_addr :
+		mask & WR_READ_OR_WRITE_MASK ? rdma_wr(ibwr)->remote_addr : 0;
 	wqe->mask		= mask;
 	wqe->dma.length		= length;
 	wqe->dma.resid		= length;
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 84f9185..463ea59 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -2626,9 +2626,11 @@
 		ret = FAST_IO_FAIL;
 	else
 		ret = FAILED;
-	srp_free_req(ch, req, scmnd, 0);
-	scmnd->result = DID_ABORT << 16;
-	scmnd->scsi_done(scmnd);
+	if (ret == SUCCESS) {
+		srp_free_req(ch, req, scmnd, 0);
+		scmnd->result = DID_ABORT << 16;
+		scmnd->scsi_done(scmnd);
+	}
 
 	return ret;
 }
@@ -3395,12 +3397,10 @@
 				      num_online_nodes());
 		const int ch_end = ((node_idx + 1) * target->ch_count /
 				    num_online_nodes());
-		const int cv_start = (node_idx * ibdev->num_comp_vectors /
-				      num_online_nodes() + target->comp_vector)
-				     % ibdev->num_comp_vectors;
-		const int cv_end = ((node_idx + 1) * ibdev->num_comp_vectors /
-				    num_online_nodes() + target->comp_vector)
-				   % ibdev->num_comp_vectors;
+		const int cv_start = node_idx * ibdev->num_comp_vectors /
+				     num_online_nodes();
+		const int cv_end = (node_idx + 1) * ibdev->num_comp_vectors /
+				   num_online_nodes();
 		int cpu_idx = 0;
 
 		for_each_online_cpu(cpu) {
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index 7cf468a..9888c9b 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -2292,12 +2292,8 @@
 	}
 	spin_unlock_irqrestore(&ioctx->spinlock, flags);
 
-	if (unlikely(transport_check_aborted_status(&ioctx->cmd, false)
-		     || WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT))) {
-		atomic_inc(&ch->req_lim_delta);
-		srpt_abort_cmd(ioctx);
+	if (unlikely(WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT)))
 		return;
-	}
 
 	/* For read commands, transfer the data to the initiator. */
 	if (ioctx->cmd.data_direction == DMA_FROM_DEVICE &&
@@ -2670,7 +2666,8 @@
 	struct srpt_rdma_ch *ch = ioctx->ch;
 	unsigned long flags;
 
-	WARN_ON(ioctx->state != SRPT_STATE_DONE);
+	WARN_ON_ONCE(ioctx->state != SRPT_STATE_DONE &&
+		     !(ioctx->cmd.transport_state & CMD_T_ABORTED));
 
 	if (ioctx->n_rw_ctx) {
 		srpt_free_rw_ctxs(ch, ioctx);
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 3026c06..f8a987a 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -398,6 +398,18 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called keychord.
 
+
+config STMVL53L0X
+        tristate "STM VL53L0X Ranging Sensor"
+        depends on I2C
+        help
+	  Say Y here if you want to enable the key chord driver
+          This is a Time-of-Flight (ToF) laser-ranging sensor, provide
+	  the distance from obstacle.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called vl5310x.
+
 config INPUT_KEYSPAN_REMOTE
 	tristate "Keyspan DMR USB remote control"
 	depends on USB_ARCH_HAS_HCD
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index c3af7c2..149273c 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -82,3 +82,5 @@
 obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND)	+= xen-kbdfront.o
 obj-$(CONFIG_INPUT_YEALINK)		+= yealink.o
 obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR)	+= ideapad_slidebar.o
+obj-$(CONFIG_INPUT_PIXART_OTS_PAT9125_SWITCH)	+= ots_pat9125/
+obj-$(CONFIG_STMVL53L0X)	+= vl53l0x/
diff --git a/drivers/input/misc/vl53l0x/Makefile b/drivers/input/misc/vl53l0x/Makefile
new file mode 100644
index 0000000..af00414
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/Makefile
@@ -0,0 +1,20 @@
+#
+# Makefile for the vl53L0X drivers.
+#
+
+# Each configuration option enables a list of files.
+FEATURE_USE_CCI := false
+#FEATURE_USE_CCI := true
+
+ifeq ($(FEATURE_USE_CCI), true)
+ccflags-y	+= -Idrivers/input/misc/vl53l0x/inc -DCAMERA_CCI
+else
+ccflags-y	+= -Idrivers/input/misc/vl53l0x/inc -DSTM_TEST
+endif
+
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
+obj-$(CONFIG_STMVL53L0X)			+= stmvl53l0x.o
+stmvl53l0x-objs				:= stmvl53l0x_module.o stmvl53l0x_module-i2c.o stmvl53l0x_module-cci.o src/vl53l0x_api_calibration.o src/vl53l0x_api_core.o src/vl53l0x_api_ranging.o src/vl53l0x_api_strings.o src/vl53l0x_api.o src/vl53l0x_platform.o src/vl53l0x_i2c_platform.o src/vl53l0x_port_i2c.o
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api.h
new file mode 100644
index 0000000..a0e0e79
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api.h
@@ -0,0 +1,1943 @@
+/*
+ *  vl53l0x_api.h - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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 _VL_API_H_
+#define _VL_API_H_
+
+#include "vl53l0x_api_strings.h"
+#include "vl53l0x_def.h"
+#include "vl53l0x_platform.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifdef _MSC_VER
+#   ifdef VL_API_EXPORTS
+#       define VL_API  __declspec(dllexport)
+#   else
+#       define VL_API
+#   endif
+#else
+#   define VL_API
+#endif
+
+/** @defgroup VL_cut11_group VL53L0X cut1.1 Function Definition
+ *  @brief    VL53L0X cut1.1 Function Definition
+ *  @{
+ */
+
+/** @defgroup VL_general_group VL53L0X General Functions
+ *  @brief    General functions and definitions
+ *  @{
+ */
+
+/**
+ * @brief Return the VL53L0X PAL Implementation Version
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param   pVersion              Pointer to current PAL Implementation Version
+ * @return  VL_ERROR_NONE     Success
+ * @return  "Other error code"    See ::int8_t
+ */
+VL_API int8_t VL_GetVersion(struct VL_Version_t *pVersion);
+
+/**
+ * @brief Return the PAL Specification Version used for the current
+ * implementation.
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param   pPalSpecVersion       Pointer to current PAL Specification Version
+ * @return  VL_ERROR_NONE        Success
+ * @return  "Other error code"    See ::int8_t
+ */
+VL_API int8_t VL_GetPalSpecVersion(
+	struct VL_Version_t *pPalSpecVersion);
+
+/**
+ * @brief Reads the Product Revision for a for given Device
+ * This function can be used to distinguish cut1.0 from cut1.1.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                 Device Handle
+ * @param   pProductRevisionMajor  Pointer to Product Revision Major
+ * for a given Device
+ * @param   pProductRevisionMinor  Pointer to Product Revision Minor
+ * for a given Device
+ * @return  VL_ERROR_NONE      Success
+ * @return  "Other error code"  See ::int8_t
+ */
+VL_API int8_t VL_GetProductRevision(struct vl_data *Dev,
+	uint8_t *pProductRevisionMajor, uint8_t *pProductRevisionMinor);
+
+/**
+ * @brief Reads the Device information for given Device
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                 Device Handle
+ * @param   pVL_DeviceInfo  Pointer to current device info for a given
+ *  Device
+ * @return  VL_ERROR_NONE   Success
+ * @return  "Other error code"  See ::int8_t
+ */
+VL_API int8_t VL_GetDeviceInfo(struct vl_data *Dev,
+	struct VL_DeviceInfo_t *pVL_DeviceInfo);
+
+/**
+ * @brief Read current status of the error register for the selected device
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                   Device Handle
+ * @param   pDeviceErrorStatus    Pointer to current error code of the device
+ * @return  VL_ERROR_NONE     Success
+ * @return  "Other error code"    See ::int8_t
+ */
+VL_API int8_t VL_GetDeviceErrorStatus(struct vl_data *Dev,
+	uint8_t *pDeviceErrorStatus);
+
+/**
+ * @brief Human readable Range Status string for a given RangeStatus
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param   RangeStatus         The RangeStatus code as stored on
+ * @a struct VL_RangingMeasurementData_t
+ * @param   pRangeStatusString  The returned RangeStatus string.
+ * @return  VL_ERROR_NONE   Success
+ * @return  "Other error code"  See ::int8_t
+ */
+VL_API int8_t VL_GetRangeStatusString(uint8_t RangeStatus,
+	char *pRangeStatusString);
+
+/**
+ * @brief Human readable error string for a given Error Code
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param   ErrorCode           The error code as stored on ::uint8_t
+ * @param   pDeviceErrorString  The error string corresponding to the ErrorCode
+ * @return  VL_ERROR_NONE   Success
+ * @return  "Other error code"  See ::int8_t
+ */
+VL_API int8_t VL_GetDeviceErrorString(
+	uint8_t ErrorCode, char *pDeviceErrorString);
+
+/**
+ * @brief Human readable error string for current PAL error status
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param   PalErrorCode       The error code as stored on @a int8_t
+ * @param   pPalErrorString    The error string corresponding to the
+ * PalErrorCode
+ * @return  VL_ERROR_NONE  Success
+ * @return  "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetPalErrorString(int8_t PalErrorCode,
+	char *pPalErrorString);
+
+/**
+ * @brief Human readable PAL State string
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param   PalStateCode          The State code as stored on @a uint8_t
+ * @param   pPalStateString       The State string corresponding to the
+ * PalStateCode
+ * @return  VL_ERROR_NONE     Success
+ * @return  "Other error code"    See ::int8_t
+ */
+VL_API int8_t VL_GetPalStateString(uint8_t PalStateCode,
+	char *pPalStateString);
+
+/**
+ * @brief Reads the internal state of the PAL for a given Device
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param   Dev                   Device Handle
+ * @param   pPalState             Pointer to current state of the PAL for a
+ * given Device
+ * @return  VL_ERROR_NONE     Success
+ * @return  "Other error code"    See ::int8_t
+ */
+VL_API int8_t VL_GetPalState(struct vl_data *Dev,
+	uint8_t *pPalState);
+
+/**
+ * @brief Set the power mode for a given Device
+ * The power mode can be Standby or Idle. Different level of both Standby and
+ * Idle can exists.
+ * This function should not be used when device is in Ranging state.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                   Device Handle
+ * @param   PowerMode             The value of the power mode to set.
+ * see ::uint8_t
+ *                                Valid values are:
+ *                                VL_POWERMODE_STANDBY_LEVEL1,
+ *                                VL_POWERMODE_IDLE_LEVEL1
+ * @return  VL_ERROR_NONE                  Success
+ * @return  VL_ERROR_MODE_NOT_SUPPORTED    This error occurs when PowerMode
+ * is not in the supported list
+ * @return  "Other error code"    See ::int8_t
+ */
+VL_API int8_t VL_SetPowerMode(struct vl_data *Dev,
+	uint8_t PowerMode);
+
+/**
+ * @brief Get the power mode for a given Device
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                   Device Handle
+ * @param   pPowerMode            Pointer to the current value of the power
+ * mode. see ::uint8_t
+ *                                Valid values are:
+ *                                VL_POWERMODE_STANDBY_LEVEL1,
+ *                                VL_POWERMODE_IDLE_LEVEL1
+ * @return  VL_ERROR_NONE     Success
+ * @return  "Other error code"    See ::int8_t
+ */
+VL_API int8_t VL_GetPowerMode(struct vl_data *Dev,
+	uint8_t *pPowerMode);
+
+/**
+ * Set or over-hide part to part calibration offset
+ * \sa VL_DataInit()   VL_GetOffsetCalibrationDataMicroMeter()
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                                Device Handle
+ * @param   OffsetCalibrationDataMicroMeter    Offset (microns)
+ * @return  VL_ERROR_NONE                  Success
+ * @return  "Other error code"                 See ::int8_t
+ */
+VL_API int8_t VL_SetOffsetCalibrationDataMicroMeter(
+	struct vl_data *Dev, int32_t OffsetCalibrationDataMicroMeter);
+
+/**
+ * @brief Get part to part calibration offset
+ *
+ * @par Function Description
+ * Should only be used after a successful call to @a VL_DataInit to backup
+ * device NVM value
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                                Device Handle
+ * @param   pOffsetCalibrationDataMicroMeter   Return part to part
+ * calibration offset from device (microns)
+ * @return  VL_ERROR_NONE                  Success
+ * @return  "Other error code"                 See ::int8_t
+ */
+VL_API int8_t VL_GetOffsetCalibrationDataMicroMeter(
+	struct vl_data *Dev, int32_t *pOffsetCalibrationDataMicroMeter);
+
+/**
+ * Set the linearity corrective gain
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                                Device Handle
+ * @param   LinearityCorrectiveGain            Linearity corrective
+ * gain in x1000
+ * if value is 1000 then no modification is applied.
+ * @return  VL_ERROR_NONE                  Success
+ * @return  "Other error code"                 See ::int8_t
+ */
+VL_API int8_t VL_SetLinearityCorrectiveGain(struct vl_data *Dev,
+	int16_t LinearityCorrectiveGain);
+
+/**
+ * @brief Get the linearity corrective gain
+ *
+ * @par Function Description
+ * Should only be used after a successful call to @a VL_DataInit to backup
+ * device NVM value
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                                Device Handle
+ * @param   pLinearityCorrectiveGain           Pointer to the linearity
+ * corrective gain in x1000
+ * if value is 1000 then no modification is applied.
+ * @return  VL_ERROR_NONE                  Success
+ * @return  "Other error code"                 See ::int8_t
+ */
+VL_API int8_t VL_GetLinearityCorrectiveGain(struct vl_data *Dev,
+	uint16_t *pLinearityCorrectiveGain);
+
+/**
+ * Set Group parameter Hold state
+ *
+ * @par Function Description
+ * Set or remove device internal group parameter hold
+ *
+ * @note This function is not Implemented
+ *
+ * @param   Dev      Device Handle
+ * @param   GroupParamHold   Group parameter Hold state to be set (on/off)
+ * @return  VL_ERROR_NOT_IMPLEMENTED        Not implemented
+ */
+VL_API int8_t VL_SetGroupParamHold(struct vl_data *Dev,
+	uint8_t GroupParamHold);
+
+/**
+ * @brief Get the maximal distance for actual setup
+ * @par Function Description
+ * Device must be initialized through @a VL_SetParameters() prior calling
+ * this function.
+ *
+ * Any range value more than the value returned is to be considered as
+ * "no target detected" or
+ * "no target in detectable range"\n
+ * @warning The maximal distance depends on the setup
+ *
+ * @note This function is not Implemented
+ *
+ * @param   Dev      Device Handle
+ * @param   pUpperLimitMilliMeter   The maximal range limit for actual setup
+ * (in millimeter)
+ * @return  VL_ERROR_NOT_IMPLEMENTED        Not implemented
+ */
+VL_API int8_t VL_GetUpperLimitMilliMeter(struct vl_data *Dev,
+	uint16_t *pUpperLimitMilliMeter);
+
+
+/**
+ * @brief Get the Total Signal Rate
+ * @par Function Description
+ * This function will return the Total Signal Rate after a good ranging is done.
+ *
+ * @note This function access to Device
+ *
+ * @param   Dev      Device Handle
+ * @param   pTotalSignalRate   Total Signal Rate value in Mega count per second
+ * @return  VL_ERROR_NONE     Success
+ * @return  "Other error code"    See ::int8_t
+ */
+int8_t VL_GetTotalSignalRate(struct vl_data *Dev,
+	unsigned int *pTotalSignalRate);
+
+/** @} VL_general_group */
+
+/** @defgroup VL_init_group VL53L0X Init Functions
+ *  @brief    VL53L0X Init Functions
+ *  @{
+ */
+
+/**
+ * @brief Set new device address
+ *
+ * After completion the device will answer to the new address programmed.
+ * This function should be called when several devices are used in parallel
+ * before start programming the sensor.
+ * When a single device us used, there is no need to call this function.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                   Device Handle
+ * @param   DeviceAddress         The new Device address
+ * @return  VL_ERROR_NONE     Success
+ * @return  "Other error code"    See ::int8_t
+ */
+VL_API int8_t VL_SetDeviceAddress(struct vl_data *Dev,
+	uint8_t DeviceAddress);
+
+/**
+ *
+ * @brief One time device initialization
+ *
+ * To be called once and only once after device is brought out of reset
+ * (Chip enable) and booted see @a VL_WaitDeviceBooted()
+ *
+ * @par Function Description
+ * When not used after a fresh device "power up" or reset, it may return
+ * @a #VL_ERROR_CALIBRATION_WARNING meaning wrong calibration data
+ * may have been fetched from device that can result in ranging offset error\n
+ * If application cannot execute device reset or need to run VL_DataInit
+ * multiple time then it  must ensure proper offset calibration saving and
+ * restore on its own by using @a VL_GetOffsetCalibrationData() on first
+ * power up and then @a VL_SetOffsetCalibrationData() in all subsequent
+ * init.
+ * This function will change the uint8_t from VL_STATE_POWERDOWN to
+ * VL_STATE_WAIT_STATICINIT.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                   Device Handle
+ * @return  VL_ERROR_NONE     Success
+ * @return  "Other error code"    See ::int8_t
+ */
+VL_API int8_t VL_DataInit(struct vl_data *Dev);
+
+/**
+ * @brief Set the tuning settings pointer
+ *
+ * This function is used to specify the Tuning settings buffer to be used
+ * for a given device. The buffer contains all the necessary data to permit
+ * the API to write tuning settings.
+ * This function permit to force the usage of either external or internal
+ * tuning settings.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                             Device Handle
+ * @param   pTuningSettingBuffer            Pointer to tuning settings buffer.
+ * @param   UseInternalTuningSettings       Use internal tuning settings value.
+ * @return  VL_ERROR_NONE     Success
+ * @return  "Other error code"    See ::int8_t
+ */
+VL_API int8_t VL_SetTuningSettingBuffer(struct vl_data *Dev,
+	uint8_t *pTuningSettingBuffer, uint8_t UseInternalTuningSettings);
+
+/**
+ * @brief Get the tuning settings pointer and the internal external switch
+ * value.
+ *
+ * This function is used to get the Tuning settings buffer pointer and the
+ * value.
+ * of the switch to select either external or internal tuning settings.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                        Device Handle
+ * @param   ppTuningSettingBuffer      Pointer to tuning settings buffer.
+ * @param   pUseInternalTuningSettings Pointer to store Use internal tuning
+ *                                     settings value.
+ * @return  VL_ERROR_NONE          Success
+ * @return  "Other error code"         See ::int8_t
+ */
+VL_API int8_t VL_GetTuningSettingBuffer(struct vl_data *Dev,
+	uint8_t **ppTuningSettingBuffer, uint8_t *pUseInternalTuningSettings);
+
+/**
+ * @brief Do basic device init (and eventually patch loading)
+ * This function will change the uint8_t from
+ * VL_STATE_WAIT_STATICINIT to VL_STATE_IDLE.
+ * In this stage all default setting will be applied.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                   Device Handle
+ * @return  VL_ERROR_NONE     Success
+ * @return  "Other error code"    See ::int8_t
+ */
+VL_API int8_t VL_StaticInit(struct vl_data *Dev);
+
+/**
+ * @brief Wait for device booted after chip enable (hardware standby)
+ * This function can be run only when uint8_t is VL_STATE_POWERDOWN.
+ *
+ * @note This function is not Implemented
+ *
+ * @param   Dev      Device Handle
+ * @return  VL_ERROR_NOT_IMPLEMENTED Not implemented
+ *
+ */
+VL_API int8_t VL_WaitDeviceBooted(struct vl_data *Dev);
+
+/**
+ * @brief Do an hard reset or soft reset (depending on implementation) of the
+ * device \nAfter call of this function, device must be in same state as right
+ * after a power-up sequence.This function will change the uint8_t to
+ * VL_STATE_POWERDOWN.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                   Device Handle
+ * @return  VL_ERROR_NONE     Success
+ * @return  "Other error code"    See ::int8_t
+ */
+VL_API int8_t VL_ResetDevice(struct vl_data *Dev);
+
+/** @} VL_init_group */
+
+/** @defgroup VL_parameters_group VL53L0X Parameters Functions
+ *  @brief    Functions used to prepare and setup the device
+ *  @{
+ */
+
+/**
+ * @brief  Prepare device for operation
+ * @par Function Description
+ * Update device with provided parameters
+ * @li Then start ranging operation.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                   Device Handle
+ * @param   pDeviceParameters     Pointer to store current device parameters.
+ * @return  VL_ERROR_NONE     Success
+ * @return  "Other error code"    See ::int8_t
+ */
+VL_API int8_t VL_SetDeviceParameters(struct vl_data *Dev,
+	const struct VL_DeviceParameters_t *pDeviceParameters);
+
+/**
+ * @brief  Retrieve current device parameters
+ * @par Function Description
+ * Get actual parameters of the device
+ * @li Then start ranging operation.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                   Device Handle
+ * @param   pDeviceParameters     Pointer to store current device parameters.
+ * @return  VL_ERROR_NONE     Success
+ * @return  "Other error code"    See ::int8_t
+ */
+VL_API int8_t VL_GetDeviceParameters(struct vl_data *Dev,
+	struct VL_DeviceParameters_t *pDeviceParameters);
+
+/**
+ * @brief  Set a new device mode
+ * @par Function Description
+ * Set device to a new mode (ranging, histogram ...)
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param   Dev                   Device Handle
+ * @param   DeviceMode            New device mode to apply
+ *                                Valid values are:
+ *                                VL_DEVICEMODE_SINGLE_RANGING
+ *                                VL_DEVICEMODE_CONTINUOUS_RANGING
+ *                                VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING
+ *                                VL_DEVICEMODE_SINGLE_HISTOGRAM
+ *                                VL_HISTOGRAMMODE_REFERENCE_ONLY
+ *                                VL_HISTOGRAMMODE_RETURN_ONLY
+ *                                VL_HISTOGRAMMODE_BOTH
+ *
+ *
+ * @return  VL_ERROR_NONE               Success
+ * @return  VL_ERROR_MODE_NOT_SUPPORTED This error occurs when DeviceMode is
+ *                                          not in the supported list
+ */
+VL_API int8_t VL_SetDeviceMode(struct vl_data *Dev,
+	uint8_t DeviceMode);
+
+/**
+ * @brief  Get current new device mode
+ * @par Function Description
+ * Get actual mode of the device(ranging, histogram ...)
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param   Dev                   Device Handle
+ * @param   pDeviceMode           Pointer to current apply mode value
+ *                                Valid values are:
+ *                                VL_DEVICEMODE_SINGLE_RANGING
+ *                                VL_DEVICEMODE_CONTINUOUS_RANGING
+ *                                VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING
+ *                                VL_DEVICEMODE_SINGLE_HISTOGRAM
+ *                                VL_HISTOGRAMMODE_REFERENCE_ONLY
+ *                                VL_HISTOGRAMMODE_RETURN_ONLY
+ *                                VL_HISTOGRAMMODE_BOTH
+ *
+ * @return  VL_ERROR_NONE                   Success
+ * @return  VL_ERROR_MODE_NOT_SUPPORTED     This error occurs when
+ * DeviceMode is not in the supported list
+ */
+VL_API int8_t VL_GetDeviceMode(struct vl_data *Dev,
+	uint8_t *pDeviceMode);
+
+/**
+ * @brief  Sets the resolution of range measurements.
+ * @par Function Description
+ * Set resolution of range measurements to either 0.25mm if
+ * fraction enabled or 1mm if not enabled.
+ *
+ * @note This function Accesses the device
+ *
+ * @param   Dev               Device Handle
+ * @param   Enable            Enable high resolution
+ *
+ * @return  VL_ERROR_NONE               Success
+ * @return  "Other error code"              See ::int8_t
+ */
+VL_API int8_t VL_SetRangeFractionEnable(struct vl_data *Dev,
+	uint8_t Enable);
+
+/**
+ * @brief  Gets the fraction enable parameter indicating the resolution of
+ * range measurements.
+ *
+ * @par Function Description
+ * Gets the fraction enable state, which translates to the resolution of
+ * range measurements as follows :Enabled:=0.25mm resolution,
+ * Not Enabled:=1mm resolution.
+ *
+ * @note This function Accesses the device
+ *
+ * @param   Dev       Device Handle
+ * @param   pEnable   Output Parameter reporting the fraction enable state.
+ *
+ * @return  VL_ERROR_NONE                   Success
+ * @return  "Other error code"                  See ::int8_t
+ */
+VL_API int8_t VL_GetFractionEnable(struct vl_data *Dev,
+	uint8_t *pEnable);
+
+/**
+ * @brief  Set a new Histogram mode
+ * @par Function Description
+ * Set device to a new Histogram mode
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param   Dev                   Device Handle
+ * @param   HistogramMode         New device mode to apply
+ *                                Valid values are:
+ *                                VL_HISTOGRAMMODE_DISABLED
+ *                                struct vl_data *ICEMODE_SINGLE_HISTOGRAM
+ *                                VL_HISTOGRAMMODE_REFERENCE_ONLY
+ *                                VL_HISTOGRAMMODE_RETURN_ONLY
+ *                                VL_HISTOGRAMMODE_BOTH
+ *
+ * @return  VL_ERROR_NONE                   Success
+ * @return  VL_ERROR_MODE_NOT_SUPPORTED     This error occurs when
+ * HistogramMode is not in the supported list
+ * @return  "Other error code"    See ::int8_t
+ */
+VL_API int8_t VL_SetHistogramMode(struct vl_data *Dev,
+	uint8_t HistogramMode);
+
+/**
+ * @brief  Get current new device mode
+ * @par Function Description
+ * Get current Histogram mode of a Device
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param   Dev                   Device Handle
+ * @param   pHistogramMode        Pointer to current Histogram Mode value
+ *                                Valid values are:
+ *                                VL_HISTOGRAMMODE_DISABLED
+ *                                struct vl_data *ICEMODE_SINGLE_HISTOGRAM
+ *                                VL_HISTOGRAMMODE_REFERENCE_ONLY
+ *                                VL_HISTOGRAMMODE_RETURN_ONLY
+ *                                VL_HISTOGRAMMODE_BOTH
+ * @return  VL_ERROR_NONE     Success
+ * @return  "Other error code"    See ::int8_t
+ */
+VL_API int8_t VL_GetHistogramMode(struct vl_data *Dev,
+	uint8_t *pHistogramMode);
+
+/**
+ * @brief Set Ranging Timing Budget in microseconds
+ *
+ * @par Function Description
+ * Defines the maximum time allowed by the user to the device to run a
+ * full ranging sequence for the current mode (ranging, histogram, ASL ...)
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                                Device Handle
+ * @param MeasurementTimingBudgetMicroSeconds  Max measurement time in
+ * microseconds.
+ *                                   Valid values are:
+ *                                   >= 17000 microsecs when wraparound enabled
+ *                                   >= 12000 microsecs when wraparound disabled
+ * @return  VL_ERROR_NONE             Success
+ * @return  VL_ERROR_INVALID_PARAMS   This error is returned if
+ MeasurementTimingBudgetMicroSeconds out of range
+ * @return  "Other error code"            See ::int8_t
+ */
+VL_API int8_t VL_SetMeasurementTimingBudgetMicroSeconds(
+	struct vl_data *Dev, uint32_t MeasurementTimingBudgetMicroSeconds);
+
+/**
+ * @brief Get Ranging Timing Budget in microseconds
+ *
+ * @par Function Description
+ * Returns the programmed the maximum time allowed by the user to the
+ * device to run a full ranging sequence for the current mode
+ * (ranging, histogram, ASL ...)
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                                    Device Handle
+ * @param   pMeasurementTimingBudgetMicroSeconds   Max measurement time in
+ * microseconds.
+ *                                   Valid values are:
+ *                                   >= 17000 microsecs when wraparound enabled
+ *                                   >= 12000 microsecs when wraparound disabled
+ * @return  VL_ERROR_NONE                      Success
+ * @return  "Other error code"                     See ::int8_t
+ */
+VL_API int8_t VL_GetMeasurementTimingBudgetMicroSeconds(
+	struct vl_data *Dev, uint32_t *pMeasurementTimingBudgetMicroSeconds);
+
+/**
+ * @brief Gets the VCSEL pulse period.
+ *
+ * @par Function Description
+ * This function retrieves the VCSEL pulse period for the given period type.
+ *
+ * @note This function Accesses the device
+ *
+ * @param   Dev                      Device Handle
+ * @param   VcselPeriodType          VCSEL period identifier (pre-range|final).
+ * @param   pVCSELPulsePeriod        Pointer to VCSEL period value.
+ * @return  VL_ERROR_NONE        Success
+ * @return  VL_ERROR_INVALID_PARAMS  Error VcselPeriodType parameter not
+ *                                       supported.
+ * @return  "Other error code"           See ::int8_t
+ */
+VL_API int8_t VL_GetVcselPulsePeriod(struct vl_data *Dev,
+	uint8_t VcselPeriodType, uint8_t *pVCSELPulsePeriod);
+
+/**
+ * @brief Sets the VCSEL pulse period.
+ *
+ * @par Function Description
+ * This function retrieves the VCSEL pulse period for the given period type.
+ *
+ * @note This function Accesses the device
+ *
+ * @param   Dev                       Device Handle
+ * @param   VcselPeriodType	      VCSEL period identifier (pre-range|final).
+ * @param   VCSELPulsePeriod          VCSEL period value
+ * @return  VL_ERROR_NONE            Success
+ * @return  VL_ERROR_INVALID_PARAMS  Error VcselPeriodType parameter not
+ *                                       supported.
+ * @return  "Other error code"           See ::int8_t
+ */
+VL_API int8_t VL_SetVcselPulsePeriod(struct vl_data *Dev,
+	uint8_t VcselPeriodType, uint8_t VCSELPulsePeriod);
+
+/**
+ * @brief Sets the (on/off) state of a requested sequence step.
+ *
+ * @par Function Description
+ * This function enables/disables a requested sequence step.
+ *
+ * @note This function Accesses the device
+ *
+ * @param   Dev                          Device Handle
+ * @param   SequenceStepId	         Sequence step identifier.
+ * @param   SequenceStepEnabled          Demanded state {0=Off,1=On}
+ *                                       is enabled.
+ * @return  VL_ERROR_NONE            Success
+ * @return  VL_ERROR_INVALID_PARAMS  Error SequenceStepId parameter not
+ *                                       supported.
+ * @return  "Other error code"           See ::int8_t
+ */
+VL_API int8_t VL_SetSequenceStepEnable(struct vl_data *Dev,
+	uint8_t SequenceStepId, uint8_t SequenceStepEnabled);
+
+/**
+ * @brief Gets the (on/off) state of a requested sequence step.
+ *
+ * @par Function Description
+ * This function retrieves the state of a requested sequence step, i.e. on/off.
+ *
+ * @note This function Accesses the device
+ *
+ * @param   Dev                    Device Handle
+ * @param   SequenceStepId         Sequence step identifier.
+ * @param   pSequenceStepEnabled   Out parameter reporting if the sequence step
+ *                                 is enabled {0=Off,1=On}.
+ * @return  VL_ERROR_NONE            Success
+ * @return  VL_ERROR_INVALID_PARAMS  Error SequenceStepId parameter not
+ *                                       supported.
+ * @return  "Other error code"           See ::int8_t
+ */
+VL_API int8_t VL_GetSequenceStepEnable(struct vl_data *Dev,
+	uint8_t SequenceStepId, uint8_t *pSequenceStepEnabled);
+
+/**
+ * @brief Gets the (on/off) state of all sequence steps.
+ *
+ * @par Function Description
+ * This function retrieves the state of all sequence step in the scheduler.
+ *
+ * @note This function Accesses the device
+ *
+ * @param   Dev                          Device Handle
+ * @param   pSchedulerSequenceSteps      Pointer to struct containing result.
+ * @return  VL_ERROR_NONE            Success
+ * @return  "Other error code"           See ::int8_t
+ */
+VL_API int8_t VL_GetSequenceStepEnables(struct vl_data *Dev,
+	struct VL_SchedulerSequenceSteps_t *pSchedulerSequenceSteps);
+
+/**
+ * @brief Sets the timeout of a requested sequence step.
+ *
+ * @par Function Description
+ * This function sets the timeout of a requested sequence step.
+ *
+ * @note This function Accesses the device
+ *
+ * @param   Dev                          Device Handle
+ * @param   SequenceStepId               Sequence step identifier.
+ * @param   TimeOutMilliSecs             Demanded timeout
+ * @return  VL_ERROR_NONE            Success
+ * @return  VL_ERROR_INVALID_PARAMS  Error SequenceStepId parameter not
+ *                                       supported.
+ * @return  "Other error code"           See ::int8_t
+ */
+VL_API int8_t VL_SetSequenceStepTimeout(struct vl_data *Dev,
+	uint8_t SequenceStepId, unsigned int TimeOutMilliSecs);
+
+/**
+ * @brief Gets the timeout of a requested sequence step.
+ *
+ * @par Function Description
+ * This function retrieves the timeout of a requested sequence step.
+ *
+ * @note This function Accesses the device
+ *
+ * @param   Dev                          Device Handle
+ * @param   SequenceStepId               Sequence step identifier.
+ * @param   pTimeOutMilliSecs            Timeout value.
+ * @return  VL_ERROR_NONE            Success
+ * @return  VL_ERROR_INVALID_PARAMS  Error SequenceStepId parameter not
+ *                                       supported.
+ * @return  "Other error code"           See ::int8_t
+ */
+VL_API int8_t VL_GetSequenceStepTimeout(struct vl_data *Dev,
+	uint8_t SequenceStepId,
+	unsigned int *pTimeOutMilliSecs);
+
+/**
+ * @brief Gets number of sequence steps managed by the API.
+ *
+ * @par Function Description
+ * This function retrieves the number of sequence steps currently managed
+ * by the API
+ *
+ * @note This function Accesses the device
+ *
+ * @param   Dev                          Device Handle
+ * @param   pNumberOfSequenceSteps       Out parameter reporting the number of
+ *                                       sequence steps.
+ * @return  VL_ERROR_NONE            Success
+ * @return  "Other error code"           See ::int8_t
+ */
+VL_API int8_t VL_GetNumberOfSequenceSteps(struct vl_data *Dev,
+	uint8_t *pNumberOfSequenceSteps);
+
+/**
+ * @brief Gets the name of a given sequence step.
+ *
+ * @par Function Description
+ * This function retrieves the name of sequence steps corresponding to
+ * SequenceStepId.
+ *
+ * @note This function doesn't Accesses the device
+ *
+ * @param   SequenceStepId               Sequence step identifier.
+ * @param   pSequenceStepsString         Pointer to Info string
+ *
+ * @return  VL_ERROR_NONE            Success
+ * @return  "Other error code"           See ::int8_t
+ */
+VL_API int8_t VL_GetSequenceStepsInfo(
+	uint8_t SequenceStepId, char *pSequenceStepsString);
+
+/**
+ * Program continuous mode Inter-Measurement period in milliseconds
+ *
+ * @par Function Description
+ * When trying to set too short time return  INVALID_PARAMS minimal value
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                                  Device Handle
+ * @param   InterMeasurementPeriodMilliSeconds   Inter-Measurement Period in ms.
+ * @return  VL_ERROR_NONE                    Success
+ * @return  "Other error code"                   See ::int8_t
+ */
+VL_API int8_t VL_SetInterMeasurementPeriodMilliSeconds(
+	struct vl_data *Dev, uint32_t InterMeasurementPeriodMilliSeconds);
+
+/**
+ * Get continuous mode Inter-Measurement period in milliseconds
+ *
+ * @par Function Description
+ * When trying to set too short time return  INVALID_PARAMS minimal value
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                                  Device Handle
+ * @param   pInterMeasurementPeriodMilliSeconds  Pointer to programmed
+ *  Inter-Measurement Period in milliseconds.
+ * @return  VL_ERROR_NONE                    Success
+ * @return  "Other error code"                   See ::int8_t
+ */
+VL_API int8_t VL_GetInterMeasurementPeriodMilliSeconds(
+	struct vl_data *Dev, uint32_t *pInterMeasurementPeriodMilliSeconds);
+
+/**
+ * @brief Enable/Disable Cross talk compensation feature
+ *
+ * @note This function is not Implemented.
+ * Enable/Disable Cross Talk by set to zero the Cross Talk value
+ * by using @a VL_SetXTalkCompensationRateMegaCps().
+ *
+ * @param   Dev                       Device Handle
+ * @param   XTalkCompensationEnable   Cross talk compensation
+ *  to be set 0=disabled else = enabled
+ * @return  VL_ERROR_NOT_IMPLEMENTED   Not implemented
+ */
+VL_API int8_t VL_SetXTalkCompensationEnable(struct vl_data *Dev,
+	uint8_t XTalkCompensationEnable);
+
+/**
+ * @brief Get Cross talk compensation rate
+ *
+ * @note This function is not Implemented.
+ * Enable/Disable Cross Talk by set to zero the Cross Talk value by
+ * using @a VL_SetXTalkCompensationRateMegaCps().
+ *
+ * @param   Dev                        Device Handle
+ * @param   pXTalkCompensationEnable   Pointer to the Cross talk compensation
+ *  state 0=disabled or 1 = enabled
+ * @return  VL_ERROR_NOT_IMPLEMENTED   Not implemented
+ */
+VL_API int8_t VL_GetXTalkCompensationEnable(struct vl_data *Dev,
+	uint8_t *pXTalkCompensationEnable);
+
+/**
+ * @brief Set Cross talk compensation rate
+ *
+ * @par Function Description
+ * Set Cross talk compensation rate.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                            Device Handle
+ * @param   XTalkCompensationRateMegaCps   Compensation rate in
+ *  Mega counts per second (16.16 fix point) see datasheet for details
+ * @return  VL_ERROR_NONE              Success
+ * @return  "Other error code"             See ::int8_t
+ */
+VL_API int8_t VL_SetXTalkCompensationRateMegaCps(
+	struct vl_data *Dev, unsigned int XTalkCompensationRateMegaCps);
+
+/**
+ * @brief Get Cross talk compensation rate
+ *
+ * @par Function Description
+ * Get Cross talk compensation rate.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                            Device Handle
+ * @param   pXTalkCompensationRateMegaCps  Pointer to Compensation rate
+ in Mega counts per second (16.16 fix point) see datasheet for details
+ * @return  VL_ERROR_NONE              Success
+ * @return  "Other error code"             See ::int8_t
+ */
+VL_API int8_t VL_GetXTalkCompensationRateMegaCps(
+	struct vl_data *Dev, unsigned int *pXTalkCompensationRateMegaCps);
+
+/**
+ * @brief Set Reference Calibration Parameters
+ *
+ * @par Function Description
+ * Set Reference Calibration Parameters.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                            Device Handle
+ * @param   VhvSettings                    Parameter for VHV
+ * @param   PhaseCal                       Parameter for PhaseCal
+ * @return  VL_ERROR_NONE              Success
+ * @return  "Other error code"             See ::int8_t
+ */
+VL_API int8_t VL_SetRefCalibration(struct vl_data *Dev,
+	uint8_t VhvSettings, uint8_t PhaseCal);
+
+/**
+ * @brief Get Reference Calibration Parameters
+ *
+ * @par Function Description
+ * Get Reference Calibration Parameters.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                            Device Handle
+ * @param   pVhvSettings                   Pointer to VHV parameter
+ * @param   pPhaseCal                      Pointer to PhaseCal Parameter
+ * @return  VL_ERROR_NONE              Success
+ * @return  "Other error code"             See ::int8_t
+ */
+VL_API int8_t VL_GetRefCalibration(struct vl_data *Dev,
+	uint8_t *pVhvSettings, uint8_t *pPhaseCal);
+
+/**
+ * @brief  Get the number of the check limit managed by a given Device
+ *
+ * @par Function Description
+ * This function give the number of the check limit managed by the Device
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param   pNumberOfLimitCheck           Pointer to the number of check limit.
+ * @return  VL_ERROR_NONE             Success
+ * @return  "Other error code"            See ::int8_t
+ */
+VL_API int8_t VL_GetNumberOfLimitCheck(
+	uint16_t *pNumberOfLimitCheck);
+
+/**
+ * @brief  Return a description string for a given limit check number
+ *
+ * @par Function Description
+ * This function returns a description string for a given limit check number.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param   Dev                           Device Handle
+ * @param   LimitCheckId                  Limit Check ID
+ (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ).
+ * @param   pLimitCheckString             Pointer to the
+ description string of the given check limit.
+ * @return  VL_ERROR_NONE             Success
+ * @return  VL_ERROR_INVALID_PARAMS   This error is
+ returned when LimitCheckId value is out of range.
+ * @return  "Other error code"            See ::int8_t
+ */
+VL_API int8_t VL_GetLimitCheckInfo(struct vl_data *Dev,
+	uint16_t LimitCheckId, char *pLimitCheckString);
+
+/**
+ * @brief  Return a the Status of the specified check limit
+ *
+ * @par Function Description
+ * This function returns the Status of the specified check limit.
+ * The value indicate if the check is fail or not.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param   Dev                           Device Handle
+ * @param   LimitCheckId                  Limit Check ID
+ (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ).
+ * @param   pLimitCheckStatus             Pointer to the
+ Limit Check Status of the given check limit.
+ * LimitCheckStatus :
+ * 0 the check is not fail
+ * 1 the check if fail or not enabled
+ *
+ * @return  VL_ERROR_NONE             Success
+ * @return  VL_ERROR_INVALID_PARAMS   This error is
+ returned when LimitCheckId value is out of range.
+ * @return  "Other error code"            See ::int8_t
+ */
+VL_API int8_t VL_GetLimitCheckStatus(struct vl_data *Dev,
+	uint16_t LimitCheckId, uint8_t *pLimitCheckStatus);
+
+/**
+ * @brief  Enable/Disable a specific limit check
+ *
+ * @par Function Description
+ * This function Enable/Disable a specific limit check.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param   Dev                           Device Handle
+ * @param   LimitCheckId                  Limit Check ID
+ *  (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ).
+ * @param   LimitCheckEnable              if 1 the check limit
+ *  corresponding to LimitCheckId is Enabled
+ *                                        if 0 the check limit
+ *  corresponding to LimitCheckId is disabled
+ * @return  VL_ERROR_NONE             Success
+ * @return  VL_ERROR_INVALID_PARAMS   This error is returned
+ *  when LimitCheckId value is out of range.
+ * @return  "Other error code"            See ::int8_t
+ */
+VL_API int8_t VL_SetLimitCheckEnable(struct vl_data *Dev,
+	uint16_t LimitCheckId, uint8_t LimitCheckEnable);
+
+/**
+ * @brief  Get specific limit check enable state
+ *
+ * @par Function Description
+ * This function get the enable state of a specific limit check.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                           Device Handle
+ * @param   LimitCheckId                  Limit Check ID
+ *  (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ).
+ * @param   pLimitCheckEnable             Pointer to the check limit enable
+ * value.
+ *  if 1 the check limit
+ *        corresponding to LimitCheckId is Enabled
+ *  if 0 the check limit
+ *        corresponding to LimitCheckId is disabled
+ * @return  VL_ERROR_NONE             Success
+ * @return  VL_ERROR_INVALID_PARAMS   This error is returned
+ *  when LimitCheckId value is out of range.
+ * @return  "Other error code"            See ::int8_t
+ */
+VL_API int8_t VL_GetLimitCheckEnable(struct vl_data *Dev,
+	uint16_t LimitCheckId, uint8_t *pLimitCheckEnable);
+
+/**
+ * @brief  Set a specific limit check value
+ *
+ * @par Function Description
+ * This function set a specific limit check value.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                           Device Handle
+ * @param   LimitCheckId                  Limit Check ID
+ *  (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ).
+ * @param   LimitCheckValue               Limit check Value for a given
+ * LimitCheckId
+ * @return  VL_ERROR_NONE             Success
+ * @return  VL_ERROR_INVALID_PARAMS   This error is returned when either
+ *  LimitCheckId or LimitCheckValue value is out of range.
+ * @return  "Other error code"            See ::int8_t
+ */
+VL_API int8_t VL_SetLimitCheckValue(struct vl_data *Dev,
+	uint16_t LimitCheckId, unsigned int LimitCheckValue);
+
+/**
+ * @brief  Get a specific limit check value
+ *
+ * @par Function Description
+ * This function get a specific limit check value from device then it updates
+ * internal values and check enables.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                           Device Handle
+ * @param   LimitCheckId                  Limit Check ID
+ *  (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ).
+ * @param   pLimitCheckValue              Pointer to Limit
+ *  check Value for a given LimitCheckId.
+ * @return  VL_ERROR_NONE             Success
+ * @return  VL_ERROR_INVALID_PARAMS   This error is returned
+ *  when LimitCheckId value is out of range.
+ * @return  "Other error code"            See ::int8_t
+ */
+VL_API int8_t VL_GetLimitCheckValue(struct vl_data *Dev,
+	uint16_t LimitCheckId, unsigned int *pLimitCheckValue);
+
+/**
+ * @brief  Get the current value of the signal used for the limit check
+ *
+ * @par Function Description
+ * This function get a the current value of the signal used for the limit check.
+ * To obtain the latest value you should run a ranging before.
+ * The value reported is linked to the limit check identified with the
+ * LimitCheckId.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                           Device Handle
+ * @param   LimitCheckId                  Limit Check ID
+ *  (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ).
+ * @param   pLimitCheckCurrent            Pointer to current Value for a
+ * given LimitCheckId.
+ * @return  VL_ERROR_NONE             Success
+ * @return  VL_ERROR_INVALID_PARAMS   This error is returned when
+ * LimitCheckId value is out of range.
+ * @return  "Other error code"            See ::int8_t
+ */
+VL_API int8_t VL_GetLimitCheckCurrent(struct vl_data *Dev,
+	uint16_t LimitCheckId, unsigned int *pLimitCheckCurrent);
+
+/**
+ * @brief  Enable (or disable) Wrap around Check
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                    Device Handle
+ * @param   WrapAroundCheckEnable  Wrap around Check to be set
+ *                                 0=disabled, other = enabled
+ * @return  VL_ERROR_NONE      Success
+ * @return  "Other error code"     See ::int8_t
+ */
+VL_API int8_t VL_SetWrapAroundCheckEnable(struct vl_data *Dev,
+		uint8_t WrapAroundCheckEnable);
+
+/**
+ * @brief  Get setup of Wrap around Check
+ *
+ * @par Function Description
+ * This function get the wrapAround check enable parameters
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                     Device Handle
+ * @param   pWrapAroundCheckEnable  Pointer to the Wrap around Check state
+ *                                  0=disabled or 1 = enabled
+ * @return  VL_ERROR_NONE       Success
+ * @return  "Other error code"      See ::int8_t
+ */
+VL_API int8_t VL_GetWrapAroundCheckEnable(struct vl_data *Dev,
+		uint8_t *pWrapAroundCheckEnable);
+
+/**
+ * @brief   Set Dmax Calibration Parameters for a given device
+ * When one of the parameter is zero, this function will get parameter
+ * from NVM.
+ * @note This function doesn't Access to the device
+ *
+ * @param   Dev                    Device Handle
+ * @param   RangeMilliMeter        Calibration Distance
+ * @param   SignalRateRtnMegaCps   Signal rate return read at CalDistance
+ * @return  VL_ERROR_NONE      Success
+ * @return  "Other error code"     See ::int8_t
+ */
+VL_API int8_t VL_SetDmaxCalParameters(struct vl_data *Dev,
+		uint16_t RangeMilliMeter, unsigned int SignalRateRtnMegaCps);
+
+/**
+ * @brief  Get Dmax Calibration Parameters for a given device
+ *
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                     Device Handle
+ * @param   pRangeMilliMeter        Pointer to Calibration Distance
+ * @param   pSignalRateRtnMegaCps   Pointer to Signal rate return
+ * @return  VL_ERROR_NONE       Success
+ * @return  "Other error code"      See ::int8_t
+ */
+VL_API int8_t VL_GetDmaxCalParameters(struct vl_data *Dev,
+	uint16_t *pRangeMilliMeter, unsigned int *pSignalRateRtnMegaCps);
+
+/** @} VL_parameters_group */
+
+/** @defgroup VL_measurement_group VL53L0X Measurement Functions
+ *  @brief    Functions used for the measurements
+ *  @{
+ */
+
+/**
+ * @brief Single shot measurement.
+ *
+ * @par Function Description
+ * Perform simple measurement sequence (Start measure, Wait measure to end,
+ * and returns when measurement is done).
+ * Once function returns, user can get valid data by calling
+ * VL_GetRangingMeasurement or VL_GetHistogramMeasurement
+ * depending on defined measurement mode
+ * User should Clear the interrupt in case this are enabled by using the
+ * function VL_ClearInterruptMask().
+ *
+ * @warning This function is a blocking function
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                  Device Handle
+ * @return  VL_ERROR_NONE    Success
+ * @return  "Other error code"   See ::int8_t
+ */
+VL_API int8_t VL_PerformSingleMeasurement(struct vl_data *Dev);
+
+/**
+ * @brief Perform Reference Calibration
+ *
+ * @details Perform a reference calibration of the Device.
+ * This function should be run from time to time before doing
+ * a ranging measurement.
+ * This function will launch a special ranging measurement, so
+ * if interrupt are enable an interrupt will be done.
+ * This function will clear the interrupt generated automatically.
+ *
+ * @warning This function is a blocking function
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                  Device Handle
+ * @param   pVhvSettings         Pointer to vhv settings parameter.
+ * @param   pPhaseCal            Pointer to PhaseCal parameter.
+ * @return  VL_ERROR_NONE    Success
+ * @return  "Other error code"   See ::int8_t
+ */
+VL_API int8_t VL_PerformRefCalibration(struct vl_data *Dev,
+	uint8_t *pVhvSettings, uint8_t *pPhaseCal);
+
+/**
+ * @brief Perform XTalk Measurement
+ *
+ * @details Measures the current cross talk from glass in front
+ * of the sensor.
+ * This functions performs a histogram measurement and uses the results
+ * to measure the crosstalk. For the function to be successful, there
+ * must be no target in front of the sensor.
+ *
+ * @warning This function is a blocking function
+ *
+ * @warning This function is not supported when the final range
+ * vcsel clock period is set below 10 PCLKS.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                  Device Handle
+ * @param   TimeoutMs            Histogram measurement duration.
+ * @param   pXtalkPerSpad        Output parameter containing the crosstalk
+ * measurement result, in MCPS/Spad. Format fixpoint 16:16.
+ * @param   pAmbientTooHigh      Output parameter which indicate that
+ * pXtalkPerSpad is not good if the Ambient is too high.
+ * @return  VL_ERROR_NONE    Success
+ * @return  VL_ERROR_INVALID_PARAMS vcsel clock period not supported
+ * for this operation. Must not be less than 10PCLKS.
+ * @return  "Other error code"   See ::int8_t
+ */
+VL_API int8_t VL_PerformXTalkMeasurement(struct vl_data *Dev,
+	uint32_t TimeoutMs, unsigned int *pXtalkPerSpad,
+	uint8_t *pAmbientTooHigh);
+
+/**
+ * @brief Perform XTalk Calibration
+ *
+ * @details Perform a XTalk calibration of the Device.
+ * This function will launch a ranging measurement, if interrupts
+ * are enabled an interrupt will be done.
+ * This function will clear the interrupt generated automatically.
+ * This function will program a new value for the XTalk compensation
+ * and it will enable the cross talk before exit.
+ * This function will disable the VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD.
+ *
+ * @warning This function is a blocking function
+ *
+ * @note This function Access to the device
+ *
+ * @note This function change the device mode to
+ * struct vl_data *ICEMODE_SINGLE_RANGING
+ *
+ * @param   Dev                  Device Handle
+ * @param   XTalkCalDistance     XTalkCalDistance value used for the XTalk
+ * computation.
+ * @param   pXTalkCompensationRateMegaCps  Pointer to new
+ * XTalkCompensation value.
+ * @return  VL_ERROR_NONE    Success
+ * @return  "Other error code"   See ::int8_t
+ */
+VL_API int8_t VL_PerformXTalkCalibration(struct vl_data *Dev,
+	unsigned int XTalkCalDistance,
+	unsigned int *pXTalkCompensationRateMegaCps);
+
+/**
+ * @brief Perform Offset Calibration
+ *
+ * @details Perform a Offset calibration of the Device.
+ * This function will launch a ranging measurement, if interrupts are
+ * enabled an interrupt will be done.
+ * This function will clear the interrupt generated automatically.
+ * This function will program a new value for the Offset calibration value
+ * This function will disable the VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD.
+ *
+ * @warning This function is a blocking function
+ *
+ * @note This function Access to the device
+ *
+ * @note This function does not change the device mode.
+ *
+ * @param   Dev                  Device Handle
+ * @param   CalDistanceMilliMeter     Calibration distance value used for the
+ * offset compensation.
+ * @param   pOffsetMicroMeter  Pointer to new Offset value computed by the
+ * function.
+ *
+ * @return  VL_ERROR_NONE    Success
+ * @return  "Other error code"   See ::int8_t
+ */
+VL_API int8_t VL_PerformOffsetCalibration(struct vl_data *Dev,
+	unsigned int CalDistanceMilliMeter, int32_t *pOffsetMicroMeter);
+
+/**
+ * @brief Start device measurement
+ *
+ * @details Started measurement will depend on device parameters set through
+ * @a VL_SetParameters()
+ * This is a non-blocking function.
+ * This function will change the uint8_t from VL_STATE_IDLE to
+ * VL_STATE_RUNNING.
+ *
+ * @note This function Access to the device
+ *
+
+ * @param   Dev                  Device Handle
+ * @return  VL_ERROR_NONE                  Success
+ * @return  VL_ERROR_MODE_NOT_SUPPORTED    This error occurs when
+ * DeviceMode programmed with @a VL_SetDeviceMode is not in the supported
+ * list:
+ *	Supported mode are:
+ *	struct vl_data *ICEMODE_SINGLE_RANGING,
+ *	struct vl_data *ICEMODE_CONTINUOUS_RANGING,
+ *	struct vl_data *ICEMODE_CONTINUOUS_TIMED_RANGING
+ * @return  VL_ERROR_TIME_OUT    Time out on start measurement
+ * @return  "Other error code"   See ::int8_t
+ */
+VL_API int8_t VL_StartMeasurement(struct vl_data *Dev);
+
+/**
+ * @brief Stop device measurement
+ *
+ * @details Will set the device in standby mode at end of current measurement\n
+ *          Not necessary in single mode as device shall return automatically
+ *          in standby mode at end of measurement.
+ *          This function will change the uint8_t from
+ *          VL_STATE_RUNNING to VL_STATE_IDLE.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                  Device Handle
+ * @return  VL_ERROR_NONE    Success
+ * @return  "Other error code"   See ::int8_t
+ */
+VL_API int8_t VL_StopMeasurement(struct vl_data *Dev);
+
+/**
+ * @brief Return Measurement Data Ready
+ *
+ * @par Function Description
+ * This function indicate that a measurement data is ready.
+ * This function check if interrupt mode is used then check is done accordingly.
+ * If perform function clear the interrupt, this function will not work,
+ * like in case of @a VL_PerformSingleRangingMeasurement().
+ * The previous function is blocking function, VL_GetMeasurementDataReady
+ * is used for non-blocking capture.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                    Device Handle
+ * @param   pMeasurementDataReady  Pointer to Measurement Data Ready.
+ *  0=data not ready, 1 = data ready
+ * @return  VL_ERROR_NONE      Success
+ * @return  "Other error code"     See ::int8_t
+ */
+VL_API int8_t VL_GetMeasurementDataReady(struct vl_data *Dev,
+	uint8_t *pMeasurementDataReady);
+
+/**
+ * @brief Wait for device ready for a new measurement command.
+ * Blocking function.
+ *
+ * @note This function is not Implemented
+ *
+ * @param   Dev      Device Handle
+ * @param   MaxLoop    Max Number of polling loop (timeout).
+ * @return  VL_ERROR_NOT_IMPLEMENTED   Not implemented
+ */
+VL_API int8_t VL_WaitDeviceReadyForNewMeasurement(
+	struct vl_data *Dev, uint32_t MaxLoop);
+
+/**
+ * @brief Retrieve the Reference Signal after a measurements
+ *
+ * @par Function Description
+ * Get Reference Signal from last successful Ranging measurement
+ * This function return a valid value after that you call the
+ * @a VL_GetRangingMeasurementData().
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                      Device Handle
+ * @param   pMeasurementRefSignal    Pointer to the Ref Signal to fill up.
+ * @return  VL_ERROR_NONE        Success
+ * @return  "Other error code"       See ::int8_t
+ */
+VL_API int8_t VL_GetMeasurementRefSignal(struct vl_data *Dev,
+	unsigned int *pMeasurementRefSignal);
+
+/**
+ * @brief Retrieve the measurements from device for a given setup
+ *
+ * @par Function Description
+ * Get data from last successful Ranging measurement
+ * @warning USER should take care about  @a VL_GetNumberOfROIZones()
+ * before get data.
+ * PAL will fill a NumberOfROIZones times the corresponding data
+ * structure used in the measurement function.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                      Device Handle
+ * @param   pRangingMeasurementData  Pointer to the data structure to fill up.
+ * @return  VL_ERROR_NONE        Success
+ * @return  "Other error code"       See ::int8_t
+ */
+VL_API int8_t VL_GetRangingMeasurementData(struct vl_data *Dev,
+	struct VL_RangingMeasurementData_t *pRangingMeasurementData);
+
+/**
+ * @brief Retrieve the measurements from device for a given setup
+ *
+ * @par Function Description
+ * Get data from last successful Histogram measurement
+ * @warning USER should take care about  @a VL_GetNumberOfROIZones()
+ * before get data.
+ * PAL will fill a NumberOfROIZones times the corresponding data structure
+ * used in the measurement function.
+ *
+ * @note This function is not Implemented
+ *
+ * @param   Dev                         Device Handle
+ * @param   pHistogramMeasurementData   Pointer to the histogram data structure.
+ * @return  VL_ERROR_NOT_IMPLEMENTED   Not implemented
+ */
+VL_API int8_t VL_GetHistogramMeasurementData(struct vl_data *Dev,
+	struct VL_HistogramMeasurementData_t *pHistogramMeasurementData);
+
+/**
+ * @brief Performs a single ranging measurement and retrieve the ranging
+ * measurement data
+ *
+ * @par Function Description
+ * This function will change the device mode to
+ * struct vl_data *ICEMODE_SINGLE_RANGING with @a VL_SetDeviceMode(),
+ * It performs measurement with @a VL_PerformSingleMeasurement()
+ * It get data from last successful Ranging measurement with
+ * @a VL_GetRangingMeasurementData.
+ * Finally it clear the interrupt with @a VL_ClearInterruptMask().
+ *
+ * @note This function Access to the device
+ *
+ * @note This function change the device mode to
+ * struct vl_data *ICEMODE_SINGLE_RANGING
+ *
+ * @param   Dev                       Device Handle
+ * @param   pRangingMeasurementData   Pointer to the data structure to fill up.
+ * @return  VL_ERROR_NONE         Success
+ * @return  "Other error code"        See ::int8_t
+ */
+VL_API int8_t VL_PerformSingleRangingMeasurement(
+	struct vl_data *Dev,
+	struct VL_RangingMeasurementData_t *pRangingMeasurementData);
+
+/**
+ * @brief Performs a single histogram measurement and retrieve the histogram
+ * measurement data
+ *   Is equivalent to VL_PerformSingleMeasurement +
+ *   VL_GetHistogramMeasurementData
+ *
+ * @par Function Description
+ * Get data from last successful Ranging measurement.
+ * This function will clear the interrupt in case of these are enabled.
+ *
+ * @note This function is not Implemented
+ *
+ * @param   Dev                        Device Handle
+ * @param   pHistogramMeasurementData  Pointer to the data structure to fill up.
+ * @return  VL_ERROR_NOT_IMPLEMENTED   Not implemented
+ */
+VL_API int8_t VL_PerformSingleHistogramMeasurement(
+	struct vl_data *Dev,
+	struct VL_HistogramMeasurementData_t *pHistogramMeasurementData);
+
+/**
+ * @brief Set the number of ROI Zones to be used for a specific Device
+ *
+ * @par Function Description
+ * Set the number of ROI Zones to be used for a specific Device.
+ * The programmed value should be less than the max number of ROI Zones given
+ * with @a VL_GetMaxNumberOfROIZones().
+ * This version of API manage only one zone.
+ *
+ * @param   Dev                           Device Handle
+ * @param   NumberOfROIZones              Number of ROI Zones to be used for a
+ *  specific Device.
+ * @return  VL_ERROR_NONE             Success
+ * @return  VL_ERROR_INVALID_PARAMS   This error is returned if
+ * NumberOfROIZones != 1
+ */
+VL_API int8_t VL_SetNumberOfROIZones(struct vl_data *Dev,
+	uint8_t NumberOfROIZones);
+
+/**
+ * @brief Get the number of ROI Zones managed by the Device
+ *
+ * @par Function Description
+ * Get number of ROI Zones managed by the Device
+ * USER should take care about  @a VL_GetNumberOfROIZones()
+ * before get data after a perform measurement.
+ * PAL will fill a NumberOfROIZones times the corresponding data
+ * structure used in the measurement function.
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param   Dev                   Device Handle
+ * @param   pNumberOfROIZones     Pointer to the Number of ROI Zones value.
+ * @return  VL_ERROR_NONE     Success
+ */
+VL_API int8_t VL_GetNumberOfROIZones(struct vl_data *Dev,
+	uint8_t *pNumberOfROIZones);
+
+/**
+ * @brief Get the Maximum number of ROI Zones managed by the Device
+ *
+ * @par Function Description
+ * Get Maximum number of ROI Zones managed by the Device.
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param   Dev                    Device Handle
+ * @param   pMaxNumberOfROIZones   Pointer to the Maximum Number
+ *  of ROI Zones value.
+ * @return  VL_ERROR_NONE      Success
+ */
+VL_API int8_t VL_GetMaxNumberOfROIZones(struct vl_data *Dev,
+	uint8_t *pMaxNumberOfROIZones);
+
+/** @} VL_measurement_group */
+
+/** @defgroup VL_interrupt_group VL53L0X Interrupt Functions
+ *  @brief    Functions used for interrupt managements
+ *  @{
+ */
+
+/**
+ * @brief Set the configuration of GPIO pin for a given device
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                   Device Handle
+ * @param   Pin                   ID of the GPIO Pin
+ * @param   Functionality         Select Pin functionality.
+ *  Refer to ::uint8_t
+ * @param   DeviceMode            Device Mode associated to the Gpio.
+ * @param   Polarity              Set interrupt polarity. Active high
+ *   or active low see ::uint8_t
+ * @return  VL_ERROR_NONE                            Success
+ * @return  VL_ERROR_GPIO_NOT_EXISTING               Only Pin=0 is accepted.
+ * @return  VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED    This error occurs
+ * when Functionality programmed is not in the supported list:
+ *                             Supported value are:
+ *                             VL_GPIOFUNCTIONALITY_OFF,
+ *                             VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW,
+ *                             VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH,
+ VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT,
+ *                               VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY
+ * @return  "Other error code"    See ::int8_t
+ */
+VL_API int8_t VL_SetGpioConfig(struct vl_data *Dev, uint8_t Pin,
+	uint8_t DeviceMode, uint8_t Functionality,
+	uint8_t Polarity);
+
+/**
+ * @brief Get current configuration for GPIO pin for a given device
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                   Device Handle
+ * @param   Pin                   ID of the GPIO Pin
+ * @param   pDeviceMode           Pointer to Device Mode associated to the Gpio.
+ * @param   pFunctionality        Pointer to Pin functionality.
+ *  Refer to ::uint8_t
+ * @param   pPolarity             Pointer to interrupt polarity.
+ *  Active high or active low see ::uint8_t
+ * @return  VL_ERROR_NONE                            Success
+ * @return  VL_ERROR_GPIO_NOT_EXISTING               Only Pin=0 is accepted.
+ * @return  VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED   This error occurs
+ * when Functionality programmed is not in the supported list:
+ *                      Supported value are:
+ *                      VL_GPIOFUNCTIONALITY_OFF,
+ *                      VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW,
+ *                      VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH,
+ *                      VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT,
+ *                      VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY
+ * @return  "Other error code"    See ::int8_t
+ */
+VL_API int8_t VL_GetGpioConfig(struct vl_data *Dev, uint8_t Pin,
+	uint8_t *pDeviceMode,
+	uint8_t *pFunctionality,
+	uint8_t *pPolarity);
+
+/**
+ * @brief Set low and high Interrupt thresholds for a given mode
+ * (ranging, ALS, ...) for a given device
+ *
+ * @par Function Description
+ * Set low and high Interrupt thresholds for a given mode (ranging, ALS, ...)
+ * for a given device
+ *
+ * @note This function Access to the device
+ *
+ * @note DeviceMode is ignored for the current device
+ *
+ * @param   Dev              Device Handle
+ * @param   DeviceMode       Device Mode for which change thresholds
+ * @param   ThresholdLow     Low threshold (mm, lux ..., depending on the mode)
+ * @param   ThresholdHigh    High threshold (mm, lux ..., depending on the mode)
+ * @return  VL_ERROR_NONE    Success
+ * @return  "Other error code"   See ::int8_t
+ */
+VL_API int8_t VL_SetInterruptThresholds(struct vl_data *Dev,
+	uint8_t DeviceMode, unsigned int ThresholdLow,
+	unsigned int ThresholdHigh);
+
+/**
+ * @brief  Get high and low Interrupt thresholds for a given mode
+ *  (ranging, ALS, ...) for a given device
+ *
+ * @par Function Description
+ * Get high and low Interrupt thresholds for a given mode (ranging, ALS, ...)
+ * for a given device
+ *
+ * @note This function Access to the device
+ *
+ * @note DeviceMode is ignored for the current device
+ *
+ * @param   Dev              Device Handle
+ * @param   DeviceMode       Device Mode from which read thresholds
+ * @param   pThresholdLow    Low threshold (mm, lux ..., depending on the mode)
+ * @param   pThresholdHigh   High threshold (mm, lux ..., depending on the mode)
+ * @return  VL_ERROR_NONE   Success
+ * @return  "Other error code"  See ::int8_t
+ */
+VL_API int8_t VL_GetInterruptThresholds(struct vl_data *Dev,
+	uint8_t DeviceMode, unsigned int *pThresholdLow,
+	unsigned int *pThresholdHigh);
+
+/**
+ * @brief Return device stop completion status
+ *
+ * @par Function Description
+ * Returns stop completiob status.
+ * User shall call this function after a stop command
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                    Device Handle
+ * @param   pStopStatus            Pointer to status variable to update
+ * @return  VL_ERROR_NONE      Success
+ * @return  "Other error code"     See ::int8_t
+ */
+VL_API int8_t VL_GetStopCompletedStatus(struct vl_data *Dev,
+	uint32_t *pStopStatus);
+
+
+/**
+ * @brief Clear given system interrupt condition
+ *
+ * @par Function Description
+ * Clear given interrupt(s).
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                  Device Handle
+ * @param   InterruptMask        Mask of interrupts to clear
+ * @return  VL_ERROR_NONE    Success
+ * @return  VL_ERROR_INTERRUPT_NOT_CLEARED    Cannot clear interrupts
+ *
+ * @return  "Other error code"   See ::int8_t
+ */
+VL_API int8_t VL_ClearInterruptMask(struct vl_data *Dev,
+	uint32_t InterruptMask);
+
+/**
+ * @brief Return device interrupt status
+ *
+ * @par Function Description
+ * Returns currently raised interrupts by the device.
+ * User shall be able to activate/deactivate interrupts through
+ * @a VL_SetGpioConfig()
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                    Device Handle
+ * @param   pInterruptMaskStatus   Pointer to status variable to update
+ * @return  VL_ERROR_NONE      Success
+ * @return  "Other error code"     See ::int8_t
+ */
+VL_API int8_t VL_GetInterruptMaskStatus(struct vl_data *Dev,
+	uint32_t *pInterruptMaskStatus);
+
+/**
+ * @brief Configure ranging interrupt reported to system
+ *
+ * @note This function is not Implemented
+ *
+ * @param   Dev                  Device Handle
+ * @param   InterruptMask         Mask of interrupt to Enable/disable
+ *  (0:interrupt disabled or 1: interrupt enabled)
+ * @return  VL_ERROR_NOT_IMPLEMENTED   Not implemented
+ */
+VL_API int8_t VL_EnableInterruptMask(struct vl_data *Dev,
+	uint32_t InterruptMask);
+
+/** @} VL_interrupt_group */
+
+/** @defgroup VL_SPADfunctions_group VL53L0X SPAD Functions
+ *  @brief    Functions used for SPAD managements
+ *  @{
+ */
+
+/**
+ * @brief  Set the SPAD Ambient Damper Threshold value
+ *
+ * @par Function Description
+ * This function set the SPAD Ambient Damper Threshold value
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                           Device Handle
+ * @param   SpadAmbientDamperThreshold    SPAD Ambient Damper Threshold value
+ * @return  VL_ERROR_NONE             Success
+ * @return  "Other error code"            See ::int8_t
+ */
+VL_API int8_t VL_SetSpadAmbientDamperThreshold(struct vl_data *Dev,
+	uint16_t SpadAmbientDamperThreshold);
+
+/**
+ * @brief  Get the current SPAD Ambient Damper Threshold value
+ *
+ * @par Function Description
+ * This function get the SPAD Ambient Damper Threshold value
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                           Device Handle
+ * @param   pSpadAmbientDamperThreshold   Pointer to programmed
+ *                                        SPAD Ambient Damper Threshold value
+ * @return  VL_ERROR_NONE             Success
+ * @return  "Other error code"            See ::int8_t
+ */
+VL_API int8_t VL_GetSpadAmbientDamperThreshold(struct vl_data *Dev,
+	uint16_t *pSpadAmbientDamperThreshold);
+
+/**
+ * @brief  Set the SPAD Ambient Damper Factor value
+ *
+ * @par Function Description
+ * This function set the SPAD Ambient Damper Factor value
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                           Device Handle
+ * @param   SpadAmbientDamperFactor       SPAD Ambient Damper Factor value
+ * @return  VL_ERROR_NONE             Success
+ * @return  "Other error code"            See ::int8_t
+ */
+VL_API int8_t VL_SetSpadAmbientDamperFactor(struct vl_data *Dev,
+	uint16_t SpadAmbientDamperFactor);
+
+/**
+ * @brief  Get the current SPAD Ambient Damper Factor value
+ *
+ * @par Function Description
+ * This function get the SPAD Ambient Damper Factor value
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                           Device Handle
+ * @param   pSpadAmbientDamperFactor      Pointer to programmed SPAD Ambient
+ * Damper Factor value
+ * @return  VL_ERROR_NONE             Success
+ * @return  "Other error code"            See ::int8_t
+ */
+VL_API int8_t VL_GetSpadAmbientDamperFactor(struct vl_data *Dev,
+	uint16_t *pSpadAmbientDamperFactor);
+
+/**
+ * @brief Performs Reference Spad Management
+ *
+ * @par Function Description
+ * The reference SPAD initialization procedure determines the minimum amount
+ * of reference spads to be enables to achieve a target reference signal rate
+ * and should be performed once during initialization.
+ *
+ * @note This function Access to the device
+ *
+ * @note This function change the device mode to
+ * struct vl_data *ICEMODE_SINGLE_RANGING
+ *
+ * @param   Dev                          Device Handle
+ * @param   refSpadCount                 Reports ref Spad Count
+ * @param   isApertureSpads              Reports if spads are of type
+ *                                       aperture or non-aperture.
+ *                                       1:=aperture, 0:=Non-Aperture
+ * @return  VL_ERROR_NONE            Success
+ * @return  VL_ERROR_REF_SPAD_INIT   Error in the Ref Spad procedure.
+ * @return  "Other error code"           See ::int8_t
+ */
+VL_API int8_t VL_PerformRefSpadManagement(struct vl_data *Dev,
+	uint32_t *refSpadCount, uint8_t *isApertureSpads);
+
+/**
+ * @brief Applies Reference SPAD configuration
+ *
+ * @par Function Description
+ * This function applies a given number of reference spads, identified as
+ * either Aperture or Non-Aperture.
+ * The requested spad count and type are stored within the device specific
+ * parameters data for access by the host.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                          Device Handle
+ * @param   refSpadCount                 Number of ref spads.
+ * @param   isApertureSpads              Defines if spads are of type
+ *                                       aperture or non-aperture.
+ *                                       1:=aperture, 0:=Non-Aperture
+ * @return  VL_ERROR_NONE            Success
+ * @return  VL_ERROR_REF_SPAD_INIT   Error in the in the reference
+ *                                       spad configuration.
+ * @return  "Other error code"           See ::int8_t
+ */
+VL_API int8_t VL_SetReferenceSpads(struct vl_data *Dev,
+	uint32_t refSpadCount, uint8_t isApertureSpads);
+
+/**
+ * @brief Retrieves SPAD configuration
+ *
+ * @par Function Description
+ * This function retrieves the current number of applied reference spads
+ * and also their type : Aperture or Non-Aperture.
+ *
+ * @note This function Access to the device
+ *
+ * @param   Dev                          Device Handle
+ * @param   refSpadCount                 Number ref Spad Count
+ * @param   isApertureSpads              Reports if spads are of type
+ *                                       aperture or non-aperture.
+ *                                       1:=aperture, 0:=Non-Aperture
+ * @return  VL_ERROR_NONE            Success
+ * @return  VL_ERROR_REF_SPAD_INIT   Error in the in the reference
+ *                                       spad configuration.
+ * @return  "Other error code"           See ::int8_t
+ */
+VL_API int8_t VL_GetReferenceSpads(struct vl_data *Dev,
+	uint32_t *refSpadCount, uint8_t *isApertureSpads);
+
+/** @} VL_SPADfunctions_group */
+
+/** @} VL_cut11_group */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL_API_H_ */
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api_calibration.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_calibration.h
new file mode 100644
index 0000000..5964e0b
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_calibration.h
@@ -0,0 +1,75 @@
+/*
+ *  vl53l0x_api_calibration.h - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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 _VL_API_CALIBRATION_H_
+#define _VL_API_CALIBRATION_H_
+
+#include "vl53l0x_def.h"
+#include "vl53l0x_platform.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int8_t VL_perform_xtalk_calibration(struct vl_data *Dev,
+		unsigned int XTalkCalDistance,
+		unsigned int *pXTalkCompensationRateMegaCps);
+
+int8_t VL_perform_offset_calibration(struct vl_data *Dev,
+		unsigned int CalDistanceMilliMeter,
+		int32_t *pOffsetMicroMeter);
+
+int8_t VL_set_offset_calibration_data_micro_meter(struct vl_data *Dev,
+		int32_t OffsetCalibrationDataMicroMeter);
+
+int8_t VL_get_offset_calibration_data_micro_meter(struct vl_data *Dev,
+		int32_t *pOffsetCalibrationDataMicroMeter);
+
+int8_t VL_apply_offset_adjustment(struct vl_data *Dev);
+
+int8_t VL_perform_ref_spad_management(struct vl_data *Dev,
+		uint32_t *refSpadCount, uint8_t *isApertureSpads);
+
+int8_t VL_set_reference_spads(struct vl_data *Dev,
+		uint32_t count, uint8_t isApertureSpads);
+
+int8_t VL_get_reference_spads(struct vl_data *Dev,
+		uint32_t *pSpadCount, uint8_t *pIsApertureSpads);
+
+int8_t VL_perform_phase_calibration(struct vl_data *Dev,
+	uint8_t *pPhaseCal, const uint8_t get_data_enable,
+	const uint8_t restore_config);
+
+int8_t VL_perform_ref_calibration(struct vl_data *Dev,
+	uint8_t *pVhvSettings, uint8_t *pPhaseCal, uint8_t get_data_enable);
+
+int8_t VL_set_ref_calibration(struct vl_data *Dev,
+		uint8_t VhvSettings, uint8_t PhaseCal);
+
+int8_t VL_get_ref_calibration(struct vl_data *Dev,
+		uint8_t *pVhvSettings, uint8_t *pPhaseCal);
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL_API_CALIBRATION_H_ */
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api_core.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_core.h
new file mode 100644
index 0000000..ac368cf
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_core.h
@@ -0,0 +1,98 @@
+/*
+ *  vl53l0x_api_core.h - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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 _VL_API_CORE_H_
+#define _VL_API_CORE_H_
+
+#include "vl53l0x_def.h"
+#include "vl53l0x_platform.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+int8_t VL_reverse_bytes(uint8_t *data, uint32_t size);
+
+int8_t VL_measurement_poll_for_completion(struct vl_data *Dev);
+
+uint8_t VL_encode_vcsel_period(uint8_t vcsel_period_pclks);
+
+uint8_t VL_decode_vcsel_period(uint8_t vcsel_period_reg);
+
+uint32_t VL_isqrt(uint32_t num);
+
+uint32_t VL_quadrature_sum(uint32_t a, uint32_t b);
+
+int8_t VL_get_info_from_device(struct vl_data *Dev, uint8_t option);
+
+int8_t VL_set_vcsel_pulse_period(struct vl_data *Dev,
+	uint8_t VcselPeriodType, uint8_t VCSELPulsePeriodPCLK);
+
+int8_t VL_get_vcsel_pulse_period(struct vl_data *Dev,
+	uint8_t VcselPeriodType, uint8_t *pVCSELPulsePeriodPCLK);
+
+uint32_t VL_decode_timeout(uint16_t encoded_timeout);
+
+int8_t get_sequence_step_timeout(struct vl_data *Dev,
+			uint8_t SequenceStepId,
+			uint32_t *pTimeOutMicroSecs);
+
+int8_t set_sequence_step_timeout(struct vl_data *Dev,
+			uint8_t SequenceStepId,
+			uint32_t TimeOutMicroSecs);
+
+int8_t VL_set_measurement_timing_budget_micro_seconds(
+	struct vl_data *Dev, uint32_t MeasurementTimingBudgetMicroSeconds);
+
+int8_t VL_get_measurement_timing_budget_micro_seconds(
+	struct vl_data *Dev, uint32_t *pMeasurementTimingBudgetMicroSeconds);
+
+int8_t VL_load_tuning_settings(struct vl_data *Dev,
+		uint8_t *pTuningSettingBuffer);
+
+int8_t VL_calc_sigma_estimate(struct vl_data *Dev,
+		struct VL_RangingMeasurementData_t *pRangingMeasurementData,
+		unsigned int *pSigmaEstimate, uint32_t *pDmax_mm);
+
+int8_t VL_get_total_xtalk_rate(struct vl_data *Dev,
+	struct VL_RangingMeasurementData_t *pRangingMeasurementData,
+	unsigned int *ptotal_xtalk_rate_mcps);
+
+int8_t VL_get_total_signal_rate(struct vl_data *Dev,
+	struct VL_RangingMeasurementData_t *pRangingMeasurementData,
+	unsigned int *ptotal_signal_rate_mcps);
+
+int8_t VL_get_pal_range_status(struct vl_data *Dev,
+		 uint8_t DeviceRangeStatus,
+		 unsigned int SignalRate,
+		 uint16_t EffectiveSpadRtnCount,
+		 struct VL_RangingMeasurementData_t *pRangingMeasurementData,
+		 uint8_t *pPalRangeStatus);
+
+uint32_t VL_calc_timeout_mclks(struct vl_data *Dev,
+	uint32_t timeout_period_us, uint8_t vcsel_period_pclks);
+
+uint16_t VL_encode_timeout(uint32_t timeout_macro_clks);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL_API_CORE_H_ */
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api_ranging.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_ranging.h
new file mode 100644
index 0000000..e6b48fc
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_ranging.h
@@ -0,0 +1,37 @@
+/*
+ *  vl53l0x_api_ranging.h - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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 _VL_API_RANGING_H_
+#define _VL_API_RANGING_H_
+
+#include "vl53l0x_def.h"
+#include "vl53l0x_platform.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL_API_RANGING_H_ */
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api_strings.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_strings.h
new file mode 100644
index 0000000..78a2dcd
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_strings.h
@@ -0,0 +1,268 @@
+/*
+ *  vl53l0x_api_strings.h - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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 VL_API_STRINGS_H_
+#define VL_API_STRINGS_H_
+
+#include "vl53l0x_def.h"
+#include "vl53l0x_platform.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+int8_t VL_get_device_info(struct vl_data *Dev,
+			struct VL_DeviceInfo_t *pVL_DeviceInfo);
+
+int8_t VL_get_device_error_string(uint8_t ErrorCode,
+		char *pDeviceErrorString);
+
+int8_t VL_get_range_status_string(uint8_t RangeStatus,
+		char *pRangeStatusString);
+
+int8_t VL_get_pal_error_string(int8_t PalErrorCode,
+		char *pPalErrorString);
+
+int8_t VL_get_pal_state_string(uint8_t PalStateCode,
+		char *pPalStateString);
+
+int8_t VL_get_sequence_steps_info(
+		uint8_t SequenceStepId,
+		char *pSequenceStepsString);
+
+int8_t VL_get_limit_check_info(struct vl_data *Dev,
+	uint16_t LimitCheckId, char *pLimitCheckString);
+
+
+#ifdef USE_EMPTY_STRING
+	#define  VL_STRING_DEVICE_INFO_NAME                             ""
+	#define  VL_STRING_DEVICE_INFO_NAME_TS0                         ""
+	#define  VL_STRING_DEVICE_INFO_NAME_TS1                         ""
+	#define  VL_STRING_DEVICE_INFO_NAME_TS2                         ""
+	#define  VL_STRING_DEVICE_INFO_NAME_ES1                         ""
+	#define  VL_STRING_DEVICE_INFO_TYPE                             ""
+
+	/* PAL ERROR strings */
+	#define  VL_STRING_ERROR_NONE                                   ""
+	#define  VL_STRING_ERROR_CALIBRATION_WARNING                    ""
+	#define  VL_STRING_ERROR_MIN_CLIPPED                            ""
+	#define  VL_STRING_ERROR_UNDEFINED                              ""
+	#define  VL_STRING_ERROR_INVALID_PARAMS                         ""
+	#define  VL_STRING_ERROR_NOT_SUPPORTED                          ""
+	#define  VL_STRING_ERROR_RANGE_ERROR                            ""
+	#define  VL_STRING_ERROR_TIME_OUT                               ""
+	#define  VL_STRING_ERROR_MODE_NOT_SUPPORTED                     ""
+	#define  VL_STRING_ERROR_BUFFER_TOO_SMALL                       ""
+	#define  VL_STRING_ERROR_GPIO_NOT_EXISTING                      ""
+	#define  VL_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED       ""
+	#define  VL_STRING_ERROR_CONTROL_INTERFACE                      ""
+	#define  VL_STRING_ERROR_INVALID_COMMAND                        ""
+	#define  VL_STRING_ERROR_DIVISION_BY_ZERO                       ""
+	#define  VL_STRING_ERROR_REF_SPAD_INIT                          ""
+	#define  VL_STRING_ERROR_NOT_IMPLEMENTED                        ""
+
+	#define  VL_STRING_UNKNOWN_ERROR_CODE                            ""
+
+
+
+	/* Range Status */
+	#define  VL_STRING_RANGESTATUS_NONE                             ""
+	#define  VL_STRING_RANGESTATUS_RANGEVALID                       ""
+	#define  VL_STRING_RANGESTATUS_SIGMA                            ""
+	#define  VL_STRING_RANGESTATUS_SIGNAL                           ""
+	#define  VL_STRING_RANGESTATUS_MINRANGE                         ""
+	#define  VL_STRING_RANGESTATUS_PHASE                            ""
+	#define  VL_STRING_RANGESTATUS_HW                               ""
+
+
+	/* Range Status */
+	#define  VL_STRING_STATE_POWERDOWN                              ""
+	#define  VL_STRING_STATE_WAIT_STATICINIT                        ""
+	#define  VL_STRING_STATE_STANDBY                                ""
+	#define  VL_STRING_STATE_IDLE                                   ""
+	#define  VL_STRING_STATE_RUNNING                                ""
+	#define  VL_STRING_STATE_UNKNOWN                                ""
+	#define  VL_STRING_STATE_ERROR                                  ""
+
+
+	/* Device Specific */
+	#define  VL_STRING_DEVICEERROR_NONE                             ""
+	#define  VL_STRING_DEVICEERROR_VCSELCONTINUITYTESTFAILURE       ""
+	#define  VL_STRING_DEVICEERROR_VCSELWATCHDOGTESTFAILURE         ""
+	#define  VL_STRING_DEVICEERROR_NOVHVVALUEFOUND                  ""
+	#define  VL_STRING_DEVICEERROR_MSRCNOTARGET                     ""
+	#define  VL_STRING_DEVICEERROR_SNRCHECK                         ""
+	#define  VL_STRING_DEVICEERROR_RANGEPHASECHECK                  ""
+	#define  VL_STRING_DEVICEERROR_SIGMATHRESHOLDCHECK              ""
+	#define  VL_STRING_DEVICEERROR_TCC                              ""
+	#define  VL_STRING_DEVICEERROR_PHASECONSISTENCY                 ""
+	#define  VL_STRING_DEVICEERROR_MINCLIP                          ""
+	#define  VL_STRING_DEVICEERROR_RANGECOMPLETE                    ""
+	#define  VL_STRING_DEVICEERROR_ALGOUNDERFLOW                    ""
+	#define  VL_STRING_DEVICEERROR_ALGOOVERFLOW                     ""
+	#define  VL_STRING_DEVICEERROR_RANGEIGNORETHRESHOLD             ""
+	#define  VL_STRING_DEVICEERROR_UNKNOWN                          ""
+
+	/* Check Enable */
+	#define  VL_STRING_CHECKENABLE_SIGMA_FINAL_RANGE                ""
+	#define  VL_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE          ""
+	#define  VL_STRING_CHECKENABLE_SIGNAL_REF_CLIP                  ""
+	#define  VL_STRING_CHECKENABLE_RANGE_IGNORE_THRESHOLD           ""
+
+	/* Sequence Step */
+	#define  VL_STRING_SEQUENCESTEP_TCC                             ""
+	#define  VL_STRING_SEQUENCESTEP_DSS                             ""
+	#define  VL_STRING_SEQUENCESTEP_MSRC                            ""
+	#define  VL_STRING_SEQUENCESTEP_PRE_RANGE                       ""
+	#define  VL_STRING_SEQUENCESTEP_FINAL_RANGE                     ""
+#else
+	#define  VL_STRING_DEVICE_INFO_NAME          "VL53L0X cut1.0"
+	#define  VL_STRING_DEVICE_INFO_NAME_TS0      "VL53L0X TS0"
+	#define  VL_STRING_DEVICE_INFO_NAME_TS1      "VL53L0X TS1"
+	#define  VL_STRING_DEVICE_INFO_NAME_TS2      "VL53L0X TS2"
+	#define  VL_STRING_DEVICE_INFO_NAME_ES1      "VL53L0X ES1 or later"
+	#define  VL_STRING_DEVICE_INFO_TYPE          "VL53L0X"
+
+	/* PAL ERROR strings */
+	#define  VL_STRING_ERROR_NONE \
+			"No Error"
+	#define  VL_STRING_ERROR_CALIBRATION_WARNING \
+			"Calibration Warning Error"
+	#define  VL_STRING_ERROR_MIN_CLIPPED \
+			"Min clipped error"
+	#define  VL_STRING_ERROR_UNDEFINED \
+			"Undefined error"
+	#define  VL_STRING_ERROR_INVALID_PARAMS \
+			"Invalid parameters error"
+	#define  VL_STRING_ERROR_NOT_SUPPORTED \
+			"Not supported error"
+	#define  VL_STRING_ERROR_RANGE_ERROR \
+			"Range error"
+	#define  VL_STRING_ERROR_TIME_OUT \
+			"Time out error"
+	#define  VL_STRING_ERROR_MODE_NOT_SUPPORTED \
+			"Mode not supported error"
+	#define  VL_STRING_ERROR_BUFFER_TOO_SMALL \
+			"Buffer too small"
+	#define  VL_STRING_ERROR_GPIO_NOT_EXISTING \
+			"GPIO not existing"
+	#define  VL_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED \
+			"GPIO funct not supported"
+	#define  VL_STRING_ERROR_INTERRUPT_NOT_CLEARED \
+			"Interrupt not Cleared"
+	#define  VL_STRING_ERROR_CONTROL_INTERFACE \
+			"Control Interface Error"
+	#define  VL_STRING_ERROR_INVALID_COMMAND \
+			"Invalid Command Error"
+	#define  VL_STRING_ERROR_DIVISION_BY_ZERO \
+			"Division by zero Error"
+	#define  VL_STRING_ERROR_REF_SPAD_INIT \
+			"Reference Spad Init Error"
+	#define  VL_STRING_ERROR_NOT_IMPLEMENTED \
+			"Not implemented error"
+
+	#define  VL_STRING_UNKNOWN_ERROR_CODE \
+			"Unknown Error Code"
+
+
+
+	/* Range Status */
+	#define  VL_STRING_RANGESTATUS_NONE                 "No Update"
+	#define  VL_STRING_RANGESTATUS_RANGEVALID           "Range Valid"
+	#define  VL_STRING_RANGESTATUS_SIGMA                "Sigma Fail"
+	#define  VL_STRING_RANGESTATUS_SIGNAL               "Signal Fail"
+	#define  VL_STRING_RANGESTATUS_MINRANGE          "Min Range Fail"
+	#define  VL_STRING_RANGESTATUS_PHASE                "Phase Fail"
+	#define  VL_STRING_RANGESTATUS_HW                   "Hardware Fail"
+
+
+	/* Range Status */
+	#define  VL_STRING_STATE_POWERDOWN               "POWERDOWN State"
+	#define  VL_STRING_STATE_WAIT_STATICINIT \
+			"Wait for staticinit State"
+	#define  VL_STRING_STATE_STANDBY                 "STANDBY State"
+	#define  VL_STRING_STATE_IDLE                    "IDLE State"
+	#define  VL_STRING_STATE_RUNNING                 "RUNNING State"
+	#define  VL_STRING_STATE_UNKNOWN                 "UNKNOWN State"
+	#define  VL_STRING_STATE_ERROR                   "ERROR State"
+
+
+	/* Device Specific */
+	#define  VL_STRING_DEVICEERROR_NONE                   "No Update"
+	#define  VL_STRING_DEVICEERROR_VCSELCONTINUITYTESTFAILURE \
+			"VCSEL Continuity Test Failure"
+	#define  VL_STRING_DEVICEERROR_VCSELWATCHDOGTESTFAILURE \
+			"VCSEL Watchdog Test Failure"
+	#define  VL_STRING_DEVICEERROR_NOVHVVALUEFOUND \
+			"No VHV Value found"
+	#define  VL_STRING_DEVICEERROR_MSRCNOTARGET \
+			"MSRC No Target Error"
+	#define  VL_STRING_DEVICEERROR_SNRCHECK \
+			"SNR Check Exit"
+	#define  VL_STRING_DEVICEERROR_RANGEPHASECHECK \
+			"Range Phase Check Error"
+	#define  VL_STRING_DEVICEERROR_SIGMATHRESHOLDCHECK \
+			"Sigma Threshold Check Error"
+	#define  VL_STRING_DEVICEERROR_TCC \
+			"TCC Error"
+	#define  VL_STRING_DEVICEERROR_PHASECONSISTENCY \
+			"Phase Consistency Error"
+	#define  VL_STRING_DEVICEERROR_MINCLIP \
+			"Min Clip Error"
+	#define  VL_STRING_DEVICEERROR_RANGECOMPLETE \
+			"Range Complete"
+	#define  VL_STRING_DEVICEERROR_ALGOUNDERFLOW \
+			"Range Algo Underflow Error"
+	#define  VL_STRING_DEVICEERROR_ALGOOVERFLOW \
+			"Range Algo Overlow Error"
+	#define  VL_STRING_DEVICEERROR_RANGEIGNORETHRESHOLD \
+			"Range Ignore Threshold Error"
+	#define  VL_STRING_DEVICEERROR_UNKNOWN \
+			"Unknown error code"
+
+	/* Check Enable */
+	#define  VL_STRING_CHECKENABLE_SIGMA_FINAL_RANGE \
+			"SIGMA FINAL RANGE"
+	#define  VL_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE \
+			"SIGNAL RATE FINAL RANGE"
+	#define  VL_STRING_CHECKENABLE_SIGNAL_REF_CLIP \
+			"SIGNAL REF CLIP"
+	#define  VL_STRING_CHECKENABLE_RANGE_IGNORE_THRESHOLD \
+			"RANGE IGNORE THRESHOLD"
+	#define  VL_STRING_CHECKENABLE_SIGNAL_RATE_MSRC \
+			"SIGNAL RATE MSRC"
+	#define  VL_STRING_CHECKENABLE_SIGNAL_RATE_PRE_RANGE \
+			"SIGNAL RATE PRE RANGE"
+
+	/* Sequence Step */
+	#define  VL_STRING_SEQUENCESTEP_TCC                   "TCC"
+	#define  VL_STRING_SEQUENCESTEP_DSS                   "DSS"
+	#define  VL_STRING_SEQUENCESTEP_MSRC                  "MSRC"
+	#define  VL_STRING_SEQUENCESTEP_PRE_RANGE             "PRE RANGE"
+	#define  VL_STRING_SEQUENCESTEP_FINAL_RANGE           "FINAL RANGE"
+#endif /* USE_EMPTY_STRING */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_def.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_def.h
new file mode 100644
index 0000000..50495a0
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_def.h
@@ -0,0 +1,619 @@
+/*
+ *  vl53l0x_def.h - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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.
+ */
+
+/**
+ * @file VL_def.h
+ *
+ * @brief Type definitions for VL53L0X API.
+ *
+ */
+
+
+#ifndef _VL_DEF_H_
+#define _VL_DEF_H_
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup VL_globaldefine_group VL53L0X Defines
+ *	@brief	  VL53L0X Defines
+ *	@{
+ */
+
+
+/** PAL SPECIFICATION major version */
+#define VL53L0X10_SPECIFICATION_VER_MAJOR   1
+/** PAL SPECIFICATION minor version */
+#define VL53L0X10_SPECIFICATION_VER_MINOR   2
+/** PAL SPECIFICATION sub version */
+#define VL53L0X10_SPECIFICATION_VER_SUB	   7
+/** PAL SPECIFICATION sub version */
+#define VL53L0X10_SPECIFICATION_VER_REVISION 1440
+
+/** VL53L0X PAL IMPLEMENTATION major version */
+#define VL53L0X10_IMPLEMENTATION_VER_MAJOR	1
+/** VL53L0X PAL IMPLEMENTATION minor version */
+#define VL53L0X10_IMPLEMENTATION_VER_MINOR	0
+/** VL53L0X PAL IMPLEMENTATION sub version */
+#define VL53L0X10_IMPLEMENTATION_VER_SUB		9
+/** VL53L0X PAL IMPLEMENTATION sub version */
+#define VL53L0X10_IMPLEMENTATION_VER_REVISION	3673
+
+/** PAL SPECIFICATION major version */
+#define VL_SPECIFICATION_VER_MAJOR	 1
+/** PAL SPECIFICATION minor version */
+#define VL_SPECIFICATION_VER_MINOR	 2
+/** PAL SPECIFICATION sub version */
+#define VL_SPECIFICATION_VER_SUB	 7
+/** PAL SPECIFICATION sub version */
+#define VL_SPECIFICATION_VER_REVISION 1440
+
+/** VL53L0X PAL IMPLEMENTATION major version */
+#define VL_IMPLEMENTATION_VER_MAJOR	  1
+/** VL53L0X PAL IMPLEMENTATION minor version */
+#define VL_IMPLEMENTATION_VER_MINOR	  0
+/** VL53L0X PAL IMPLEMENTATION sub version */
+#define VL_IMPLEMENTATION_VER_SUB	  2
+/** VL53L0X PAL IMPLEMENTATION sub version */
+#define VL_IMPLEMENTATION_VER_REVISION	  4823
+#define VL_DEFAULT_MAX_LOOP 2000
+#define VL_MAX_STRING_LENGTH 32
+
+
+#include "vl53l0x_device.h"
+#include "vl53l0x_types.h"
+
+
+/****************************************
+ * PRIVATE define do not edit
+ ****************************************/
+
+/** @brief Defines the parameters of the Get Version Functions
+ */
+struct VL_Version_t {
+	uint32_t	 revision; /*!< revision number */
+	uint8_t		 major;	   /*!< major number */
+	uint8_t		 minor;	   /*!< minor number */
+	uint8_t		 build;	   /*!< build number */
+};
+
+
+/** @brief Defines the parameters of the Get Device Info Functions
+ */
+struct VL_DeviceInfo_t {
+	char Name[VL_MAX_STRING_LENGTH];
+		/*!< Name of the Device e.g. Left_Distance */
+	char Type[VL_MAX_STRING_LENGTH];
+		/*!< Type of the Device e.g VL53L0X */
+	char ProductId[VL_MAX_STRING_LENGTH];
+		/*!< Product Identifier String	*/
+	uint8_t ProductType;
+		/*!< Product Type, VL53L0X = 1, VL53L1 = 2 */
+	uint8_t ProductRevisionMajor;
+		/*!< Product revision major */
+	uint8_t ProductRevisionMinor;
+		/*!< Product revision minor */
+};
+
+
+/** @defgroup VL_define_Error_group Error and Warning code returned by API
+ *	The following DEFINE are used to identify the PAL ERROR
+ *	@{
+ */
+
+#define VL_ERROR_NONE		((int8_t)	0)
+#define VL_ERROR_CALIBRATION_WARNING	((int8_t) -1)
+	/*!< Warning invalid calibration data may be in used*/
+		/*\a VL_InitData()*/
+		/*\a VL_GetOffsetCalibrationData*/
+		/*\a VL_SetOffsetCalibrationData */
+#define VL_ERROR_MIN_CLIPPED			((int8_t) -2)
+	/*!< Warning parameter passed was clipped to min before to be applied */
+
+#define VL_ERROR_UNDEFINED				((int8_t) -3)
+	/*!< Unqualified error */
+#define VL_ERROR_INVALID_PARAMS			((int8_t) -4)
+	/*!< Parameter passed is invalid or out of range */
+#define VL_ERROR_NOT_SUPPORTED			((int8_t) -5)
+	/*!< Function is not supported in current mode or configuration */
+#define VL_ERROR_RANGE_ERROR			((int8_t) -6)
+	/*!< Device report a ranging error interrupt status */
+#define VL_ERROR_TIME_OUT				((int8_t) -7)
+	/*!< Aborted due to time out */
+#define VL_ERROR_MODE_NOT_SUPPORTED		((int8_t) -8)
+	/*!< Asked mode is not supported by the device */
+#define VL_ERROR_BUFFER_TOO_SMALL			((int8_t) -9)
+	/*!< ... */
+#define VL_ERROR_GPIO_NOT_EXISTING			((int8_t) -10)
+	/*!< User tried to setup a non-existing GPIO pin */
+#define VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED  ((int8_t) -11)
+	/*!< unsupported GPIO functionality */
+#define VL_ERROR_INTERRUPT_NOT_CLEARED		((int8_t) -12)
+	/*!< Error during interrupt clear */
+#define VL_ERROR_CONTROL_INTERFACE			((int8_t) -20)
+	/*!< error reported from IO functions */
+#define VL_ERROR_INVALID_COMMAND			((int8_t) -30)
+	/*!< The command is not allowed in the current device state*/
+	/* *	(power down) */
+#define VL_ERROR_DIVISION_BY_ZERO			((int8_t) -40)
+	/*!< In the function a division by zero occurs */
+#define VL_ERROR_REF_SPAD_INIT			((int8_t) -50)
+	/*!< Error during reference SPAD initialization */
+#define VL_ERROR_NOT_IMPLEMENTED			((int8_t) -99)
+	/*!< Tells requested functionality has not been implemented yet or*/
+	/* * not compatible with the device */
+/** @} VL_define_Error_group */
+
+
+/** @defgroup VL_define_DeviceModes_group Defines Device modes
+ *	Defines all possible modes for the device
+ *	@{
+ */
+
+#define VL_DEVICEMODE_SINGLE_RANGING	((uint8_t)  0)
+#define VL_DEVICEMODE_CONTINUOUS_RANGING	((uint8_t)  1)
+#define VL_DEVICEMODE_SINGLE_HISTOGRAM	((uint8_t)  2)
+#define VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING ((uint8_t) 3)
+#define VL_DEVICEMODE_SINGLE_ALS		((uint8_t) 10)
+#define VL_DEVICEMODE_GPIO_DRIVE		((uint8_t) 20)
+#define VL_DEVICEMODE_GPIO_OSC		((uint8_t) 21)
+	/* ... Modes to be added depending on device */
+/** @} VL_define_DeviceModes_group */
+
+
+
+/** @defgroup VL_define_HistogramModes_group Defines Histogram modes
+ *	Defines all possible Histogram modes for the device
+ *	@{
+ */
+
+#define VL_HISTOGRAMMODE_DISABLED		((uint8_t) 0)
+	/*!< Histogram Disabled */
+#define VL_HISTOGRAMMODE_REFERENCE_ONLY	((uint8_t) 1)
+	/*!< Histogram Reference array only */
+#define VL_HISTOGRAMMODE_RETURN_ONLY	((uint8_t) 2)
+	/*!< Histogram Return array only */
+#define VL_HISTOGRAMMODE_BOTH		((uint8_t) 3)
+	/*!< Histogram both Reference and Return Arrays */
+	/* ... Modes to be added depending on device */
+/** @} VL_define_HistogramModes_group */
+
+
+/** @defgroup VL_define_PowerModes_group List of available Power Modes
+ *	List of available Power Modes
+ *	@{
+ */
+
+#define VL_POWERMODE_STANDBY_LEVEL1 ((uint8_t) 0)
+	/*!< Standby level 1 */
+#define VL_POWERMODE_STANDBY_LEVEL2 ((uint8_t) 1)
+	/*!< Standby level 2 */
+#define VL_POWERMODE_IDLE_LEVEL1	((uint8_t) 2)
+	/*!< Idle level 1 */
+#define VL_POWERMODE_IDLE_LEVEL2	((uint8_t) 3)
+	/*!< Idle level 2 */
+
+/** @} VL_define_PowerModes_group */
+
+
+/** @brief Defines all parameters for the device
+ */
+struct VL_DeviceParameters_t {
+	uint8_t DeviceMode;
+	/*!< Defines type of measurement to be done for the next measure */
+	uint8_t HistogramMode;
+	/*!< Defines type of histogram measurement to be done for the next*/
+	/* *	measure */
+	uint32_t MeasurementTimingBudgetMicroSeconds;
+	/*!< Defines the allowed total time for a single measurement */
+	uint32_t InterMeasurementPeriodMilliSeconds;
+	/*!< Defines time between two consecutive measurements (between two*/
+	/* *	measurement starts). If set to 0 means back-to-back mode */
+	uint8_t XTalkCompensationEnable;
+	/*!< Tells if Crosstalk compensation shall be enable or not	 */
+	uint16_t XTalkCompensationRangeMilliMeter;
+	/*!< CrossTalk compensation range in millimeter	 */
+	unsigned int XTalkCompensationRateMegaCps;
+	/*!< CrossTalk compensation rate in Mega counts per seconds.*/
+	/* *	Expressed in 16.16 fixed point format.	*/
+	int32_t RangeOffsetMicroMeters;
+	/*!< Range offset adjustment (mm).	*/
+
+	uint8_t LimitChecksEnable[VL_CHECKENABLE_NUMBER_OF_CHECKS];
+	/*!< This Array store all the Limit Check enable for this device. */
+	uint8_t LimitChecksStatus[VL_CHECKENABLE_NUMBER_OF_CHECKS];
+	/*!< This Array store all the Status of the check linked to last*/
+	/** measurement. */
+	unsigned int LimitChecksValue[VL_CHECKENABLE_NUMBER_OF_CHECKS];
+	/*!< This Array store all the Limit Check value for this device */
+
+	uint8_t WrapAroundCheckEnable;
+	/*!< Tells if Wrap Around Check shall be enable or not */
+};
+
+
+/** @defgroup VL_define_State_group Defines the current status
+ *	of the device Defines the current status of the device
+ *	@{
+ */
+
+#define VL_STATE_POWERDOWN		 ((uint8_t)  0)
+	/*!< Device is in HW reset	*/
+#define VL_STATE_WAIT_STATICINIT ((uint8_t)  1)
+	/*!< Device is initialized and wait for static initialization  */
+#define VL_STATE_STANDBY		 ((uint8_t)  2)
+	/*!< Device is in Low power Standby mode   */
+#define VL_STATE_IDLE			 ((uint8_t)  3)
+	/*!< Device has been initialized and ready to do measurements  */
+#define VL_STATE_RUNNING		 ((uint8_t)  4)
+	/*!< Device is performing measurement */
+#define VL_STATE_UNKNOWN		 ((uint8_t)  98)
+	/*!< Device is in unknown state and need to be rebooted	 */
+#define VL_STATE_ERROR			 ((uint8_t)  99)
+	/*!< Device is in error state and need to be rebooted  */
+
+/** @} VL_define_State_group */
+
+
+/** @brief Structure containing the Dmax computation parameters and data
+ */
+struct VL_DMaxData_t {
+	int32_t AmbTuningWindowFactor_K;
+		/*!<  internal algo tuning (*1000) */
+	int32_t RetSignalAt0mm;
+		/*!< intermediate dmax computation value caching */
+};
+
+/**
+ * @struct VL_RangeData_t
+ * @brief Range measurement data.
+ */
+struct VL_RangingMeasurementData_t {
+	uint32_t TimeStamp;		/*!< 32-bit time stamp. */
+	uint32_t MeasurementTimeUsec;
+		/*!< Give the Measurement time needed by the device to do the */
+		/** measurement.*/
+
+
+	uint16_t RangeMilliMeter;	/*!< range distance in millimeter. */
+
+	uint16_t RangeDMaxMilliMeter;
+		/*!< Tells what is the maximum detection distance of */
+		/* the device */
+		/* * in current setup and environment conditions (Filled when */
+		/* *	applicable) */
+
+	unsigned int SignalRateRtnMegaCps;
+		/*!< Return signal rate (MCPS)\n these is a 16.16 fix point */
+		/* *	value, which is effectively a measure of target */
+		/* *	 reflectance.*/
+	unsigned int AmbientRateRtnMegaCps;
+		/*!< Return ambient rate (MCPS)\n these is a 16.16 fix point */
+		/* *	value, which is effectively a measure of the ambien */
+		/* *	t light.*/
+
+	uint16_t EffectiveSpadRtnCount;
+		/*!< Return the effective SPAD count for the return signal. */
+		/* *	To obtain Real value it should be divided by 256 */
+
+	uint8_t ZoneId;
+		/*!< Denotes which zone and range scheduler stage the range */
+		/* *	data relates to. */
+	uint8_t RangeFractionalPart;
+		/*!< Fractional part of range distance. Final value is a */
+		/* *	FixPoint168 value. */
+	uint8_t RangeStatus;
+		/*!< Range Status for the current measurement. This is device */
+		/* *	dependent. Value = 0 means value is valid. */
+		/* *	See \ref RangeStatusPage */
+};
+
+
+#define VL_HISTOGRAM_BUFFER_SIZE 24
+
+/**
+ * @struct VL_HistogramData_t
+ * @brief Histogram measurement data.
+ */
+struct VL_HistogramMeasurementData_t {
+	/* Histogram Measurement data */
+	uint32_t HistogramData[VL_HISTOGRAM_BUFFER_SIZE];
+	/*!< Histogram data */
+	uint8_t HistogramType; /*!< Indicate the types of histogram data : */
+	/*Return only, Reference only, both Return and Reference */
+	uint8_t FirstBin; /*!< First Bin value */
+	uint8_t BufferSize; /*!< Buffer Size - Set by the user.*/
+	uint8_t NumberOfBins;
+	/*!< Number of bins filled by the histogram measurement */
+
+	uint8_t ErrorStatus;
+	/*!< Error status of the current measurement. \n */
+	/* see @a ::uint8_t @a VL_GetStatusErrorString() */
+};
+
+#define VL_REF_SPAD_BUFFER_SIZE 6
+
+/**
+ * @struct VL_SpadData_t
+ * @brief Spad Configuration Data.
+ */
+struct VL_SpadData_t {
+	uint8_t RefSpadEnables[VL_REF_SPAD_BUFFER_SIZE];
+	/*!< Reference Spad Enables */
+	uint8_t RefGoodSpadMap[VL_REF_SPAD_BUFFER_SIZE];
+	/*!< Reference Spad Good Spad Map */
+};
+
+struct VL_DeviceSpecificParameters_t {
+	unsigned int OscFrequencyMHz; /* Frequency used */
+
+	uint16_t LastEncodedTimeout;
+	/* last encoded Time out used for timing budget*/
+
+	uint8_t Pin0GpioFunctionality;
+	/* store the functionality of the GPIO: pin0 */
+
+	uint32_t FinalRangeTimeoutMicroSecs;
+	 /*!< Execution time of the final range*/
+	uint8_t FinalRangeVcselPulsePeriod;
+	 /*!< Vcsel pulse period (pll clocks) for the final range measurement*/
+	uint32_t PreRangeTimeoutMicroSecs;
+	 /*!< Execution time of the final range*/
+	uint8_t PreRangeVcselPulsePeriod;
+	 /*!< Vcsel pulse period (pll clocks) for the pre-range measurement*/
+
+	uint16_t SigmaEstRefArray;
+	 /*!< Reference array sigma value in 1/100th of [mm] e.g. 100 = 1mm */
+	uint16_t SigmaEstEffPulseWidth;
+	 /*!< Effective Pulse width for sigma estimate in 1/100th */
+	 /* * of ns e.g. 900 = 9.0ns */
+	uint16_t SigmaEstEffAmbWidth;
+	 /*!< Effective Ambient width for sigma estimate in 1/100th of ns */
+	 /* * e.g. 500 = 5.0ns */
+
+
+	uint8_t ReadDataFromDeviceDone; /* Indicate if read from device has */
+	/*been done (==1) or not (==0) */
+	uint8_t ModuleId; /* Module ID */
+	uint8_t Revision; /* test Revision */
+	char ProductId[VL_MAX_STRING_LENGTH];
+		/* Product Identifier String  */
+	uint8_t ReferenceSpadCount; /* used for ref spad management */
+	uint8_t ReferenceSpadType;	/* used for ref spad management */
+	uint8_t RefSpadsInitialised; /* reports if ref spads are initialised. */
+	uint32_t PartUIDUpper; /*!< Unique Part ID Upper */
+	uint32_t PartUIDLower; /*!< Unique Part ID Lower */
+	unsigned int SignalRateMeasFixed400mm; /*!< Peek Signal rate at 400 mm*/
+
+};
+
+/**
+ * @struct VL_DevData_t
+ *
+ * @brief VL53L0X PAL device ST private data structure \n
+ * End user should never access any of these field directly
+ *
+ * These must never access directly but only via macro
+ */
+struct VL_DevData_t {
+	struct VL_DMaxData_t DMaxData;
+	/*!< Dmax Data */
+	int32_t	 Part2PartOffsetNVMMicroMeter;
+	/*!< backed up NVM value */
+	int32_t	 Part2PartOffsetAdjustmentNVMMicroMeter;
+	/*!< backed up NVM value representing additional offset adjustment */
+	struct VL_DeviceParameters_t CurrentParameters;
+	/*!< Current Device Parameter */
+	struct VL_RangingMeasurementData_t LastRangeMeasure;
+	/*!< Ranging Data */
+	struct VL_HistogramMeasurementData_t LastHistogramMeasure;
+	/*!< Histogram Data */
+	struct VL_DeviceSpecificParameters_t DeviceSpecificParameters;
+	/*!< Parameters specific to the device */
+	struct VL_SpadData_t SpadData;
+	/*!< Spad Data */
+	uint8_t SequenceConfig;
+	/*!< Internal value for the sequence config */
+	uint8_t RangeFractionalEnable;
+	/*!< Enable/Disable fractional part of ranging data */
+	uint8_t PalState;
+	/*!< Current state of the PAL for this device */
+	uint8_t PowerMode;
+	/*!< Current Power Mode	 */
+	uint16_t SigmaEstRefArray;
+	/*!< Reference array sigma value in 1/100th of [mm] e.g. 100 = 1mm */
+	uint16_t SigmaEstEffPulseWidth;
+	/*!< Effective Pulse width for sigma estimate in 1/100th */
+	/* of ns e.g. 900 = 9.0ns */
+	uint16_t SigmaEstEffAmbWidth;
+	/*!< Effective Ambient width for sigma estimate in 1/100th of ns */
+	/* * e.g. 500 = 5.0ns */
+	uint8_t StopVariable;
+	/*!< StopVariable used during the stop sequence */
+	uint16_t targetRefRate;
+	/*!< Target Ambient Rate for Ref spad management */
+	unsigned int SigmaEstimate;
+	/*!< Sigma Estimate - based on ambient & VCSEL rates and */
+	/** signal_total_events */
+	unsigned int SignalEstimate;
+	/*!< Signal Estimate - based on ambient & VCSEL rates and cross talk */
+	unsigned int LastSignalRefMcps;
+	/*!< Latest Signal ref in Mcps */
+	uint8_t *pTuningSettingsPointer;
+	/*!< Pointer for Tuning Settings table */
+	uint8_t UseInternalTuningSettings;
+	/*!< Indicate if we use	 Tuning Settings table */
+	uint16_t LinearityCorrectiveGain;
+	/*!< Linearity Corrective Gain value in x1000 */
+	uint16_t DmaxCalRangeMilliMeter;
+	/*!< Dmax Calibration Range millimeter */
+	unsigned int DmaxCalSignalRateRtnMegaCps;
+	/*!< Dmax Calibration Signal Rate Return MegaCps */
+
+};
+
+
+/** @defgroup VL_define_InterruptPolarity_group Defines the Polarity
+ * of the Interrupt
+ *	Defines the Polarity of the Interrupt
+ *	@{
+ */
+
+#define VL_INTERRUPTPOLARITY_LOW	   ((uint8_t)	0)
+/*!< Set active low polarity best setup for falling edge. */
+#define VL_INTERRUPTPOLARITY_HIGH	   ((uint8_t)	1)
+/*!< Set active high polarity best setup for rising edge. */
+
+/** @} VL_define_InterruptPolarity_group */
+
+
+/** @defgroup VL_define_VcselPeriod_group Vcsel Period Defines
+ *	Defines the range measurement for which to access the vcsel period.
+ *	@{
+ */
+
+#define VL_VCSEL_PERIOD_PRE_RANGE	((uint8_t) 0)
+/*!<Identifies the pre-range vcsel period. */
+#define VL_VCSEL_PERIOD_FINAL_RANGE ((uint8_t) 1)
+/*!<Identifies the final range vcsel period. */
+
+/** @} VL_define_VcselPeriod_group */
+
+/** @defgroup VL_define_SchedulerSequence_group Defines the steps
+ * carried out by the scheduler during a range measurement.
+ *	@{
+ *	Defines the states of all the steps in the scheduler
+ *	i.e. enabled/disabled.
+ */
+struct VL_SchedulerSequenceSteps_t {
+	uint8_t		 TccOn;	   /*!<Reports if Target Centre Check On  */
+	uint8_t		 MsrcOn;	   /*!<Reports if MSRC On  */
+	uint8_t		 DssOn;		   /*!<Reports if DSS On  */
+	uint8_t		 PreRangeOn;   /*!<Reports if Pre-Range On	*/
+	uint8_t		 FinalRangeOn; /*!<Reports if Final-Range On  */
+};
+
+/** @} VL_define_SchedulerSequence_group */
+
+/** @defgroup VL_define_SequenceStepId_group Defines the Polarity
+ *	of the Interrupt
+ *	Defines the the sequence steps performed during ranging..
+ *	@{
+ */
+
+#define	 VL_SEQUENCESTEP_TCC		 ((uint8_t) 0)
+/*!<Target CentreCheck identifier. */
+#define	 VL_SEQUENCESTEP_DSS		 ((uint8_t) 1)
+/*!<Dynamic Spad Selection function Identifier. */
+#define	 VL_SEQUENCESTEP_MSRC		 ((uint8_t) 2)
+/*!<Minimum Signal Rate Check function Identifier. */
+#define	 VL_SEQUENCESTEP_PRE_RANGE	 ((uint8_t) 3)
+/*!<Pre-Range check Identifier. */
+#define	 VL_SEQUENCESTEP_FINAL_RANGE ((uint8_t) 4)
+/*!<Final Range Check Identifier. */
+
+#define	 VL_SEQUENCESTEP_NUMBER_OF_CHECKS			 5
+/*!<Number of Sequence Step Managed by the API. */
+
+/** @} VL_define_SequenceStepId_group */
+
+
+/* MACRO Definitions */
+/** @defgroup VL_define_GeneralMacro_group General Macro Defines
+ *	General Macro Defines
+ *	@{
+ */
+
+/* Defines */
+#define VL_SETPARAMETERFIELD(Dev, field, value) \
+	PALDevDataSet(Dev, CurrentParameters.field, value)
+
+#define VL_GETPARAMETERFIELD(Dev, field, variable) \
+	(variable = PALDevDataGet(Dev, CurrentParameters).field)
+
+
+#define VL_SETARRAYPARAMETERFIELD(Dev, field, index, value) \
+	PALDevDataSet(Dev, CurrentParameters.field[index], value)
+
+#define VL_GETARRAYPARAMETERFIELD(Dev, field, index, variable) \
+	(variable = PALDevDataGet(Dev, CurrentParameters).field[index])
+
+
+#define VL_SETDEVICESPECIFICPARAMETER(Dev, field, value) \
+		PALDevDataSet(Dev, DeviceSpecificParameters.field, value)
+
+#define VL_GETDEVICESPECIFICPARAMETER(Dev, field) \
+		PALDevDataGet(Dev, DeviceSpecificParameters).field
+
+
+#define VL_FIXPOINT1616TOFIXPOINT97(Value) \
+	(uint16_t)((Value>>9)&0xFFFF)
+#define VL_FIXPOINT97TOFIXPOINT1616(Value) \
+	(unsigned int)(Value<<9)
+
+#define VL_FIXPOINT1616TOFIXPOINT88(Value) \
+	(uint16_t)((Value>>8)&0xFFFF)
+#define VL_FIXPOINT88TOFIXPOINT1616(Value) \
+	(unsigned int)(Value<<8)
+
+#define VL_FIXPOINT1616TOFIXPOINT412(Value) \
+	(uint16_t)((Value>>4)&0xFFFF)
+#define VL_FIXPOINT412TOFIXPOINT1616(Value) \
+	(unsigned int)(Value<<4)
+
+#define VL_FIXPOINT1616TOFIXPOINT313(Value) \
+	(uint16_t)((Value>>3)&0xFFFF)
+#define VL_FIXPOINT313TOFIXPOINT1616(Value) \
+	(unsigned int)(Value<<3)
+
+#define VL_FIXPOINT1616TOFIXPOINT08(Value) \
+	(uint8_t)((Value>>8)&0x00FF)
+#define VL_FIXPOINT08TOFIXPOINT1616(Value) \
+	(unsigned int)(Value<<8)
+
+#define VL_FIXPOINT1616TOFIXPOINT53(Value) \
+	(uint8_t)((Value>>13)&0x00FF)
+#define VL_FIXPOINT53TOFIXPOINT1616(Value) \
+	(unsigned int)(Value<<13)
+
+#define VL_FIXPOINT1616TOFIXPOINT102(Value) \
+	(uint16_t)((Value>>14)&0x0FFF)
+#define VL_FIXPOINT102TOFIXPOINT1616(Value) \
+	(unsigned int)(Value<<12)
+
+#define VL_MAKEUINT16(lsb, msb) (uint16_t)((((uint16_t)msb)<<8) + \
+		(uint16_t)lsb)
+
+/** @} VL_define_GeneralMacro_group */
+
+/** @} VL_globaldefine_group */
+
+
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _VL_DEF_H_ */
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_device.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_device.h
new file mode 100644
index 0000000..b296ff8
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_device.h
@@ -0,0 +1,246 @@
+/*
+ *  vl53l0x_device.h - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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.
+ */
+
+/**
+ * Device specific defines. To be adapted by implementer for the targeted
+ * device.
+ */
+
+#ifndef _VL_DEVICE_H_
+#define _VL_DEVICE_H_
+
+#include "vl53l0x_types.h"
+
+
+/** @defgroup VL_DevSpecDefines_group VL53L0X cut1.1
+ *  Device Specific Defines
+ *  @brief VL53L0X cut1.1 Device Specific Defines
+ *  @{
+ */
+
+
+/** @defgroup uint8_t_group Device Error
+ *  @brief Device Error code
+ *
+ *  This enum is Device specific it should be updated in the implementation
+ *  Use @a VL_GetStatusErrorString() to get the string.
+ *  It is related to Status Register of the Device.
+ *  @{
+ */
+
+#define VL_DEVICEERROR_NONE                     ((uint8_t) 0)
+	/*!< 0  NoError  */
+#define VL_DEVICEERROR_VCSELCONTINUITYTESTFAILURE ((uint8_t) 1)
+#define VL_DEVICEERROR_VCSELWATCHDOGTESTFAILURE ((uint8_t) 2)
+#define VL_DEVICEERROR_NOVHVVALUEFOUND         ((uint8_t) 3)
+#define VL_DEVICEERROR_MSRCNOTARGET            ((uint8_t) 4)
+#define VL_DEVICEERROR_SNRCHECK                ((uint8_t) 5)
+#define VL_DEVICEERROR_RANGEPHASECHECK         ((uint8_t) 6)
+#define VL_DEVICEERROR_SIGMATHRESHOLDCHECK     ((uint8_t) 7)
+#define VL_DEVICEERROR_TCC                     ((uint8_t) 8)
+#define VL_DEVICEERROR_PHASECONSISTENCY        ((uint8_t) 9)
+#define VL_DEVICEERROR_MINCLIP                 ((uint8_t) 10)
+#define VL_DEVICEERROR_RANGECOMPLETE           ((uint8_t) 11)
+#define VL_DEVICEERROR_ALGOUNDERFLOW           ((uint8_t) 12)
+#define VL_DEVICEERROR_ALGOOVERFLOW            ((uint8_t) 13)
+#define VL_DEVICEERROR_RANGEIGNORETHRESHOLD    ((uint8_t) 14)
+
+/** @} end of uint8_t_group */
+
+
+/** @defgroup VL_CheckEnable_group Check Enable list
+ *  @brief Check Enable code
+ *
+ *  Define used to specify the LimitCheckId.
+ *  Use @a VL_GetLimitCheckInfo() to get the string.
+ *  @{
+ */
+
+#define VL_CHECKENABLE_SIGMA_FINAL_RANGE           0
+#define VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE     1
+#define VL_CHECKENABLE_SIGNAL_REF_CLIP             2
+#define VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD      3
+#define VL_CHECKENABLE_SIGNAL_RATE_MSRC            4
+#define VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE       5
+
+#define VL_CHECKENABLE_NUMBER_OF_CHECKS            6
+
+/** @}  end of VL_CheckEnable_group */
+
+
+/** @defgroup uint8_t_group Gpio Functionality
+ *  @brief Defines the different functionalities for the device GPIO(s)
+ *  @{
+ */
+
+#define VL_GPIOFUNCTIONALITY_OFF                     \
+	((uint8_t)  0) /*!< NO Interrupt  */
+#define VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW   \
+	((uint8_t)  1) /*!< Level Low (value < thresh_low) */
+#define VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH   \
+	((uint8_t)  2)/*!< Level High (value > thresh_high)*/
+#define VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT    \
+	((uint8_t)  3)
+	/*!< Out Of Window (value < thresh_low OR value > thresh_high)  */
+#define VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY        \
+	((uint8_t)  4) /*!< New Sample Ready  */
+
+/** @} end of uint8_t_group */
+
+
+/* Device register map */
+
+/** @defgroup VL_DefineRegisters_group Define Registers
+ *  @brief List of all the defined registers
+ *  @{
+ */
+#define VL_REG_SYSRANGE_START                        0x000
+	/** mask existing bit in #VL_REG_SYSRANGE_START*/
+	#define VL_REG_SYSRANGE_MODE_MASK          0x0F
+	/** bit 0 in #VL_REG_SYSRANGE_START write 1 toggle state in */
+	/* continuous mode and arm next shot in single shot mode */
+	#define VL_REG_SYSRANGE_MODE_START_STOP    0x01
+	/** bit 1 write 0 in #VL_REG_SYSRANGE_START set single shot mode */
+	#define VL_REG_SYSRANGE_MODE_SINGLESHOT    0x00
+	/** bit 1 write 1 in #VL_REG_SYSRANGE_START set back-to-back */
+	/*  operation mode */
+	#define VL_REG_SYSRANGE_MODE_BACKTOBACK    0x02
+	/** bit 2 write 1 in #VL_REG_SYSRANGE_START set timed operation */
+	/* *  mode */
+	#define VL_REG_SYSRANGE_MODE_TIMED         0x04
+	/** bit 3 write 1 in #VL_REG_SYSRANGE_START set histogram operation */
+	/* *  mode */
+	#define VL_REG_SYSRANGE_MODE_HISTOGRAM     0x08
+
+
+#define VL_REG_SYSTEM_THRESH_HIGH               0x000C
+#define VL_REG_SYSTEM_THRESH_LOW                0x000E
+
+
+#define VL_REG_SYSTEM_SEQUENCE_CONFIG		0x0001
+#define VL_REG_SYSTEM_RANGE_CONFIG			0x0009
+#define VL_REG_SYSTEM_INTERMEASUREMENT_PERIOD	0x0004
+
+
+#define VL_REG_SYSTEM_INTERRUPT_CONFIG_GPIO               0x000A
+	#define VL_REG_SYSTEM_INTERRUPT_GPIO_DISABLED	0x00
+	#define VL_REG_SYSTEM_INTERRUPT_GPIO_LEVEL_LOW	0x01
+	#define VL_REG_SYSTEM_INTERRUPT_GPIO_LEVEL_HIGH	0x02
+	#define VL_REG_SYSTEM_INTERRUPT_GPIO_OUT_OF_WINDOW	0x03
+	#define VL_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY	0x04
+
+#define VL_REG_GPIO_HV_MUX_ACTIVE_HIGH          0x0084
+
+
+#define VL_REG_SYSTEM_INTERRUPT_CLEAR           0x000B
+
+/* Result registers */
+#define VL_REG_RESULT_INTERRUPT_STATUS          0x0013
+#define VL_REG_RESULT_RANGE_STATUS              0x0014
+
+#define VL_REG_RESULT_CORE_PAGE  1
+#define VL_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_RTN   0x00BC
+#define VL_REG_RESULT_CORE_RANGING_TOTAL_EVENTS_RTN    0x00C0
+#define VL_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_REF   0x00D0
+#define VL_REG_RESULT_CORE_RANGING_TOTAL_EVENTS_REF    0x00D4
+#define VL_REG_RESULT_PEAK_SIGNAL_RATE_REF             0x00B6
+
+/* Algo register */
+
+#define VL_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM       0x0028
+
+#define VL_REG_I2C_SLAVE_DEVICE_ADDRESS                0x008a
+
+/* Check Limit registers */
+#define VL_REG_MSRC_CONFIG_CONTROL                     0x0060
+
+#define VL_REG_PRE_RANGE_CONFIG_MIN_SNR                      0X0027
+#define VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW              0x0056
+#define VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH             0x0057
+#define VL_REG_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT            0x0064
+
+#define VL_REG_FINAL_RANGE_CONFIG_MIN_SNR                    0X0067
+#define VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW            0x0047
+#define VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH           0x0048
+#define VL_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT   0x0044
+
+
+#define VL_REG_PRE_RANGE_CONFIG_SIGMA_THRESH_HI              0X0061
+#define VL_REG_PRE_RANGE_CONFIG_SIGMA_THRESH_LO              0X0062
+
+/* PRE RANGE registers */
+#define VL_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD                 0x0050
+#define VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI            0x0051
+#define VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_LO            0x0052
+
+#define VL_REG_SYSTEM_HISTOGRAM_BIN                          0x0081
+#define VL_REG_HISTOGRAM_CONFIG_INITIAL_PHASE_SELECT         0x0033
+#define VL_REG_HISTOGRAM_CONFIG_READOUT_CTRL                 0x0055
+
+#define VL_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD               0x0070
+#define VL_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI          0x0071
+#define VL_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_LO          0x0072
+#define VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS         0x0020
+
+#define VL_REG_MSRC_CONFIG_TIMEOUT_MACROP                    0x0046
+
+
+#define VL_REG_SOFT_RESET_GO2_SOFT_RESET_N	                 0x00bf
+#define VL_REG_IDENTIFICATION_MODEL_ID                       0x00c0
+#define VL_REG_IDENTIFICATION_REVISION_ID                    0x00c2
+
+#define VL_REG_OSC_CALIBRATE_VAL                             0x00f8
+
+
+#define VL_SIGMA_ESTIMATE_MAX_VALUE                          65535
+/* equivalent to a range sigma of 655.35mm */
+
+#define VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH          0x032
+#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0   0x0B0
+#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_1   0x0B1
+#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_2   0x0B2
+#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_3   0x0B3
+#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_4   0x0B4
+#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_5   0x0B5
+
+#define VL_REG_GLOBAL_CONFIG_REF_EN_START_SELECT   0xB6
+#define VL_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD 0x4E /* 0x14E */
+#define VL_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET    0x4F /* 0x14F */
+#define VL_REG_POWER_MANAGEMENT_GO1_POWER_FORCE    0x80
+
+/*
+ * Speed of light in um per 1E-10 Seconds
+ */
+
+#define VL_SPEED_OF_LIGHT_IN_AIR 2997
+
+#define VL_REG_VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV     0x0089
+
+#define VL_REG_ALGO_PHASECAL_LIM                         0x0030 /* 0x130 */
+#define VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT              0x0030
+
+/** @} VL_DefineRegisters_group */
+
+/** @} VL_DevSpecDefines_group */
+
+
+#endif
+
+/* _VL_DEVICE_H_ */
+
+
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_i2c_platform.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_i2c_platform.h
new file mode 100644
index 0000000..3cd5d69
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_i2c_platform.h
@@ -0,0 +1,397 @@
+/*
+ *  vl53l0x_i2c_platform.h - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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.
+ */
+
+/**
+ * @file   VL_i2c_platform.h
+ * @brief  Function prototype definitions for EWOK Platform layer.
+ *
+ */
+
+
+#ifndef _VL_I2C_PLATFORM_H_
+#define _VL_I2C_PLATFORM_H_
+
+#include "vl53l0x_def.h"
+
+
+/** Maximum buffer size to be used in i2c */
+#define VL_MAX_I2C_XFER_SIZE   64
+
+/**
+ *  @brief Typedef defining .\n
+ * The developer should modify this to suit the platform being deployed.
+ *
+ */
+
+/**
+ * @brief Typedef defining 8 bit unsigned char type.\n
+ * The developer should modify this to suit the platform being deployed.
+ *
+ */
+#define	   I2C                0x01
+#define	   SPI                0x00
+
+#define    COMMS_BUFFER_SIZE    64
+/*MUST be the same size as the SV task buffer */
+
+#define    BYTES_PER_WORD        2
+#define    BYTES_PER_DWORD       4
+
+#define    VL_MAX_STRING_LENGTH_PLT       256
+
+/**
+ * @brief  Initialise platform comms.
+ *
+ * @param  comms_type      - selects between I2C and SPI
+ * @param  comms_speed_khz - unsigned short containing the I2C speed in kHz
+ *
+ * @return status - status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_comms_initialise(uint8_t  comms_type,
+			uint16_t comms_speed_khz);
+
+/**
+ * @brief  Close platform comms.
+ *
+ * @return status - status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_comms_close(void);
+
+/**
+ * @brief  Cycle Power to Device
+ *
+ * @return status - status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_cycle_power(void);
+
+int32_t VL_set_page(struct vl_data *dev, uint8_t page_data);
+
+/**
+ * @brief Writes the supplied byte buffer to the device
+ *
+ * Wrapper for SystemVerilog Write Multi task
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint8_t *spad_enables;
+ *
+ * int status = VL_write_multi(RET_SPAD_EN_0, spad_enables, 36);
+ *
+ * @endcode
+ *
+ * @param  address - uint8_t device address value
+ * @param  index - uint8_t register index value
+ * @param  pdata - pointer to uint8_t buffer containing the data to be written
+ * @param  count - number of bytes in the supplied byte buffer
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_write_multi(struct vl_data *dev, uint8_t index, uint8_t  *pdata,
+		int32_t count);
+
+
+/**
+ * @brief  Reads the requested number of bytes from the device
+ *
+ * Wrapper for SystemVerilog Read Multi task
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint8_t buffer[COMMS_BUFFER_SIZE];
+ *
+ * int status = status  = VL_read_multi(DEVICE_ID, buffer, 2)
+ *
+ * @endcode
+ *
+ * @param  address - uint8_t device address value
+ * @param  index - uint8_t register index value
+ * @param  pdata - pointer to the uint8_t buffer to store read data
+ * @param  count - number of uint8_t's to read
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_read_multi(struct vl_data *dev,  uint8_t index, uint8_t  *pdata,
+		int32_t count);
+
+
+/**
+ * @brief  Writes a single byte to the device
+ *
+ * Wrapper for SystemVerilog Write Byte task
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint8_t page_number = MAIN_SELECT_PAGE;
+ *
+ * int status = VL_write_byte(PAGE_SELECT, page_number);
+ *
+ * @endcode
+ *
+ * @param  address - uint8_t device address value
+ * @param  index - uint8_t register index value
+ * @param  data  - uint8_t data value to write
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_write_byte(struct vl_data *dev,  uint8_t index, uint8_t   data);
+
+
+/**
+ * @brief  Writes a single word (16-bit unsigned) to the device
+ *
+ * Manages the big-endian nature of the device (first byte written is the
+ * MS byte).
+ * Uses SystemVerilog Write Multi task.
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint16_t nvm_ctrl_pulse_width = 0x0004;
+ *
+ * int status = VL_write_word(NVM_CTRL__PULSE_WIDTH_MSB,
+ * nvm_ctrl_pulse_width);
+ *
+ * @endcode
+ *
+ * @param  address - uint8_t device address value
+ * @param  index - uint8_t register index value
+ * @param  data  - uin16_t data value write
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_write_word(struct vl_data *dev,  uint8_t index, uint16_t  data);
+
+
+/**
+ * @brief  Writes a single dword (32-bit unsigned) to the device
+ *
+ * Manages the big-endian nature of the device (first byte written is the
+ * MS byte).
+ * Uses SystemVerilog Write Multi task.
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint32_t nvm_data = 0x0004;
+ *
+ * int status = VL_write_dword(NVM_CTRL__DATAIN_MMM, nvm_data);
+ *
+ * @endcode
+ *
+ * @param  address - uint8_t device address value
+ * @param  index - uint8_t register index value
+ * @param  data  - uint32_t data value to write
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_write_dword(struct vl_data *dev, uint8_t index, uint32_t  data);
+
+
+
+/**
+ * @brief  Reads a single byte from the device
+ *
+ * Uses SystemVerilog Read Byte task.
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint8_t device_status = 0;
+ *
+ * int status = VL_read_byte(STATUS, &device_status);
+ *
+ * @endcode
+ *
+ * @param  address - uint8_t device address value
+ * @param  index  - uint8_t register index value
+ * @param  pdata  - pointer to uint8_t data value
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_read_byte(struct vl_data *dev,  uint8_t index, uint8_t  *pdata);
+
+
+/**
+ * @brief  Reads a single word (16-bit unsigned) from the device
+ *
+ * Manages the big-endian nature of the device (first byte read is the MS byte).
+ * Uses SystemVerilog Read Multi task.
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint16_t timeout = 0;
+ *
+ * int status = VL_read_word(TIMEOUT_OVERALL_PERIODS_MSB, &timeout);
+ *
+ * @endcode
+ *
+ * @param  address - uint8_t device address value
+ * @param  index  - uint8_t register index value
+ * @param  pdata  - pointer to uint16_t data value
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_read_word(struct vl_data *dev,  uint8_t index, uint16_t *pdata);
+
+
+/**
+ * @brief  Reads a single dword (32-bit unsigned) from the device
+ *
+ * Manages the big-endian nature of the device (first byte read is the MS byte).
+ * Uses SystemVerilog Read Multi task.
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint32_t range_1 = 0;
+ *
+ * int status = VL_read_dword(RANGE_1_MMM, &range_1);
+ *
+ * @endcode
+ *
+ * @param  address - uint8_t device address value
+ * @param  index - uint8_t register index value
+ * @param  pdata - pointer to uint32_t data value
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_read_dword(struct vl_data *dev, uint8_t index, uint32_t *pdata);
+
+
+/**
+ * @brief  Implements a programmable wait in us
+ *
+ * Wrapper for SystemVerilog Wait in micro seconds task
+ *
+ * @param  wait_us - integer wait in micro seconds
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_platform_wait_us(int32_t wait_us);
+
+
+/**
+ * @brief  Implements a programmable wait in ms
+ *
+ * Wrapper for SystemVerilog Wait in milli seconds task
+ *
+ * @param  wait_ms - integer wait in milli seconds
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_wait_ms(int32_t wait_ms);
+
+
+/**
+ * @brief Set GPIO value
+ *
+ * @param  level  - input  level - either 0 or 1
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_set_gpio(uint8_t  level);
+
+
+/**
+ * @brief Get GPIO value
+ *
+ * @param  plevel - uint8_t pointer to store GPIO level (0 or 1)
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_get_gpio(uint8_t *plevel);
+
+/**
+ * @brief Release force on GPIO
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_release_gpio(void);
+
+
+/**
+ * @brief Get the frequency of the timer used for ranging results time stamps
+ *
+ * @param[out] ptimer_freq_hz : pointer for timer frequency
+ *
+ * @return status : 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_get_timer_frequency(int32_t *ptimer_freq_hz);
+
+/**
+ * @brief Get the timer value in units of timer_freq_hz
+ * (see VL_get_timestamp_frequency())
+ *
+ * @param[out] ptimer_count : pointer for timer count value
+ *
+ * @return status : 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_get_timer_value(int32_t *ptimer_count);
+int VL_I2CWrite(struct vl_data *dev, uint8_t *buff, uint8_t len);
+int VL_I2CRead(struct vl_data *dev, uint8_t *buff, uint8_t len);
+
+#endif /* _VL_I2C_PLATFORM_H_ */
+
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_interrupt_threshold_settings.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_interrupt_threshold_settings.h
new file mode 100644
index 0000000..ecfc994
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_interrupt_threshold_settings.h
@@ -0,0 +1,183 @@
+/*
+ *  vl53l0x_interrupt_threshold_settings.h - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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 _VL_INTERRUPT_THRESHOLD_SETTINGS_H_
+#define _VL_INTERRUPT_THRESHOLD_SETTINGS_H_
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+uint8_t InterruptThresholdSettings[] = {
+
+	/* Start of Interrupt Threshold Settings */
+	0x1, 0xff, 0x00,
+	0x1, 0x80, 0x01,
+	0x1, 0xff, 0x01,
+	0x1, 0x00, 0x00,
+	0x1, 0xff, 0x01,
+	0x1, 0x4f, 0x02,
+	0x1, 0xFF, 0x0E,
+	0x1, 0x00, 0x03,
+	0x1, 0x01, 0x84,
+	0x1, 0x02, 0x0A,
+	0x1, 0x03, 0x03,
+	0x1, 0x04, 0x08,
+	0x1, 0x05, 0xC8,
+	0x1, 0x06, 0x03,
+	0x1, 0x07, 0x8D,
+	0x1, 0x08, 0x08,
+	0x1, 0x09, 0xC6,
+	0x1, 0x0A, 0x01,
+	0x1, 0x0B, 0x02,
+	0x1, 0x0C, 0x00,
+	0x1, 0x0D, 0xD5,
+	0x1, 0x0E, 0x18,
+	0x1, 0x0F, 0x12,
+	0x1, 0x10, 0x01,
+	0x1, 0x11, 0x82,
+	0x1, 0x12, 0x00,
+	0x1, 0x13, 0xD5,
+	0x1, 0x14, 0x18,
+	0x1, 0x15, 0x13,
+	0x1, 0x16, 0x03,
+	0x1, 0x17, 0x86,
+	0x1, 0x18, 0x0A,
+	0x1, 0x19, 0x09,
+	0x1, 0x1A, 0x08,
+	0x1, 0x1B, 0xC2,
+	0x1, 0x1C, 0x03,
+	0x1, 0x1D, 0x8F,
+	0x1, 0x1E, 0x0A,
+	0x1, 0x1F, 0x06,
+	0x1, 0x20, 0x01,
+	0x1, 0x21, 0x02,
+	0x1, 0x22, 0x00,
+	0x1, 0x23, 0xD5,
+	0x1, 0x24, 0x18,
+	0x1, 0x25, 0x22,
+	0x1, 0x26, 0x01,
+	0x1, 0x27, 0x82,
+	0x1, 0x28, 0x00,
+	0x1, 0x29, 0xD5,
+	0x1, 0x2A, 0x18,
+	0x1, 0x2B, 0x0B,
+	0x1, 0x2C, 0x28,
+	0x1, 0x2D, 0x78,
+	0x1, 0x2E, 0x28,
+	0x1, 0x2F, 0x91,
+	0x1, 0x30, 0x00,
+	0x1, 0x31, 0x0B,
+	0x1, 0x32, 0x00,
+	0x1, 0x33, 0x0B,
+	0x1, 0x34, 0x00,
+	0x1, 0x35, 0xA1,
+	0x1, 0x36, 0x00,
+	0x1, 0x37, 0xA0,
+	0x1, 0x38, 0x00,
+	0x1, 0x39, 0x04,
+	0x1, 0x3A, 0x28,
+	0x1, 0x3B, 0x30,
+	0x1, 0x3C, 0x0C,
+	0x1, 0x3D, 0x04,
+	0x1, 0x3E, 0x0F,
+	0x1, 0x3F, 0x79,
+	0x1, 0x40, 0x28,
+	0x1, 0x41, 0x1E,
+	0x1, 0x42, 0x2F,
+	0x1, 0x43, 0x87,
+	0x1, 0x44, 0x00,
+	0x1, 0x45, 0x0B,
+	0x1, 0x46, 0x00,
+	0x1, 0x47, 0x0B,
+	0x1, 0x48, 0x00,
+	0x1, 0x49, 0xA7,
+	0x1, 0x4A, 0x00,
+	0x1, 0x4B, 0xA6,
+	0x1, 0x4C, 0x00,
+	0x1, 0x4D, 0x04,
+	0x1, 0x4E, 0x01,
+	0x1, 0x4F, 0x00,
+	0x1, 0x50, 0x00,
+	0x1, 0x51, 0x80,
+	0x1, 0x52, 0x09,
+	0x1, 0x53, 0x08,
+	0x1, 0x54, 0x01,
+	0x1, 0x55, 0x00,
+	0x1, 0x56, 0x0F,
+	0x1, 0x57, 0x79,
+	0x1, 0x58, 0x09,
+	0x1, 0x59, 0x05,
+	0x1, 0x5A, 0x00,
+	0x1, 0x5B, 0x60,
+	0x1, 0x5C, 0x05,
+	0x1, 0x5D, 0xD1,
+	0x1, 0x5E, 0x0C,
+	0x1, 0x5F, 0x3C,
+	0x1, 0x60, 0x00,
+	0x1, 0x61, 0xD0,
+	0x1, 0x62, 0x0B,
+	0x1, 0x63, 0x03,
+	0x1, 0x64, 0x28,
+	0x1, 0x65, 0x10,
+	0x1, 0x66, 0x2A,
+	0x1, 0x67, 0x39,
+	0x1, 0x68, 0x0B,
+	0x1, 0x69, 0x02,
+	0x1, 0x6A, 0x28,
+	0x1, 0x6B, 0x10,
+	0x1, 0x6C, 0x2A,
+	0x1, 0x6D, 0x61,
+	0x1, 0x6E, 0x0C,
+	0x1, 0x6F, 0x00,
+	0x1, 0x70, 0x0F,
+	0x1, 0x71, 0x79,
+	0x1, 0x72, 0x00,
+	0x1, 0x73, 0x0B,
+	0x1, 0x74, 0x00,
+	0x1, 0x75, 0x0B,
+	0x1, 0x76, 0x00,
+	0x1, 0x77, 0xA1,
+	0x1, 0x78, 0x00,
+	0x1, 0x79, 0xA0,
+	0x1, 0x7A, 0x00,
+	0x1, 0x7B, 0x04,
+	0x1, 0xFF, 0x04,
+	0x1, 0x79, 0x1D,
+	0x1, 0x7B, 0x27,
+	0x1, 0x96, 0x0E,
+	0x1, 0x97, 0xFE,
+	0x1, 0x98, 0x03,
+	0x1, 0x99, 0xEF,
+	0x1, 0x9A, 0x02,
+	0x1, 0x9B, 0x44,
+	0x1, 0x73, 0x07,
+	0x1, 0x70, 0x01,
+	0x1, 0xff, 0x01,
+	0x1, 0x00, 0x01,
+	0x1, 0xff, 0x00,
+	0x00, 0x00, 0x00
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL_INTERRUPT_THRESHOLD_SETTINGS_H_ */
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_platform.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_platform.h
new file mode 100644
index 0000000..d896fe8
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_platform.h
@@ -0,0 +1,213 @@
+/*
+ *  vl53l0x_platform.h - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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 _VL_PLATFORM_H_
+#define _VL_PLATFORM_H_
+
+#include <linux/delay.h>
+#include "vl53l0x_def.h"
+#include "vl53l0x_platform_log.h"
+
+#include "stmvl53l0x-i2c.h"
+#include "stmvl53l0x-cci.h"
+#include "stmvl53l0x.h"
+
+/**
+ * @file vl53l0x_platform.h
+ *
+ * @brief All end user OS/platform/application porting
+ */
+
+/**
+ * @defgroup VL_platform_group VL53L0 Platform Functions
+ * @brief    VL53L0 Platform Functions
+ *  @{
+ */
+
+/**
+ * @def PALDevDataGet
+ * @brief Get ST private structure @a struct VL_DevData_t data access
+ *
+ * @param Dev       Device Handle
+ * @param field     ST structure field name
+ * It maybe used and as real data "ref" not just as "get" for sub-structure item
+ * like PALDevDataGet(FilterData.field)[i] or
+ * PALDevDataGet(FilterData.MeasurementIndex)++
+ */
+#define PALDevDataGet(Dev, field) (Dev->Data.field)
+
+/**
+ * @def PALDevDataSet(Dev, field, data)
+ * @brief  Set ST private structure @a struct VL_DevData_t data field
+ * @param Dev       Device Handle
+ * @param field     ST structure field na*me
+ * @param data      Data to be set
+ */
+#define PALDevDataSet(Dev, field, data) ((Dev->Data.field) = (data))
+
+
+/**
+ * @defgroup VL_registerAccess_group PAL Register Access Functions
+ * @brief    PAL Register Access Functions
+ *  @{
+ */
+
+/**
+ * Lock comms interface to serialize all commands to a shared I2C interface
+ * for a specific device
+ * @param   Dev       Device Handle
+ * @return  VL_ERROR_NONE        Success
+ * @return  "Other error code"    See ::int8_t
+ */
+int8_t VL_LockSequenceAccess(struct vl_data *Dev);
+
+/**
+ * Unlock comms interface to serialize all commands to a shared I2C interface
+ * for a specific device
+ * @param   Dev       Device Handle
+ * @return  VL_ERROR_NONE        Success
+ * @return  "Other error code"    See ::int8_t
+ */
+int8_t VL_UnlockSequenceAccess(struct vl_data *Dev);
+
+
+/**
+ * Writes the supplied byte buffer to the device
+ * @param   Dev       Device Handle
+ * @param   index     The register index
+ * @param   pdata     Pointer to uint8_t buffer containing the data
+ * to be written
+ * @param   count     Number of bytes in the supplied byte buffer
+ * @return  VL_ERROR_NONE        Success
+ * @return  "Other error code"    See ::int8_t
+ */
+int8_t VL_WriteMulti(struct vl_data *Dev, uint8_t index,
+		uint8_t *pdata, uint32_t count);
+
+/**
+ * Reads the requested number of bytes from the device
+ * @param   Dev       Device Handle
+ * @param   index     The register index
+ * @param   pdata     Pointer to the uint8_t buffer to store read data
+ * @param   count     Number of uint8_t's to read
+ * @return  VL_ERROR_NONE        Success
+ * @return  "Other error code"    See ::int8_t
+ */
+int8_t VL_ReadMulti(struct vl_data *Dev, uint8_t index,
+		uint8_t *pdata, uint32_t count);
+
+/**
+ * Write single byte register
+ * @param   Dev       Device Handle
+ * @param   index     The register index
+ * @param   data      8 bit register data
+ * @return  VL_ERROR_NONE        Success
+ * @return  "Other error code"    See ::int8_t
+ */
+int8_t VL_WrByte(struct vl_data *Dev, uint8_t index, uint8_t data);
+
+/**
+ * Write word register
+ * @param   Dev       Device Handle
+ * @param   index     The register index
+ * @param   data      16 bit register data
+ * @return  VL_ERROR_NONE        Success
+ * @return  "Other error code"    See ::int8_t
+ */
+int8_t VL_WrWord(struct vl_data *Dev, uint8_t index, uint16_t data);
+
+/**
+ * Write double word (4 byte) register
+ * @param   Dev       Device Handle
+ * @param   index     The register index
+ * @param   data      32 bit register data
+ * @return  VL_ERROR_NONE        Success
+ * @return  "Other error code"    See ::int8_t
+ */
+int8_t VL_WrDWord(struct vl_data *Dev, uint8_t index, uint32_t data);
+
+/**
+ * Read single byte register
+ * @param   Dev       Device Handle
+ * @param   index     The register index
+ * @param   data      pointer to 8 bit data
+ * @return  VL_ERROR_NONE        Success
+ * @return  "Other error code"    See ::int8_t
+ */
+int8_t VL_RdByte(struct vl_data *Dev, uint8_t index, uint8_t *data);
+
+/**
+ * Read word (2byte) register
+ * @param   Dev       Device Handle
+ * @param   index     The register index
+ * @param   data      pointer to 16 bit data
+ * @return  VL_ERROR_NONE        Success
+ * @return  "Other error code"    See ::int8_t
+ */
+int8_t VL_RdWord(struct vl_data *Dev, uint8_t index, uint16_t *data);
+
+/**
+ * Read dword (4byte) register
+ * @param   Dev       Device Handle
+ * @param   index     The register index
+ * @param   data      pointer to 32 bit data
+ * @return  VL_ERROR_NONE        Success
+ * @return  "Other error code"    See ::int8_t
+ */
+int8_t VL_RdDWord(struct vl_data *Dev, uint8_t index, uint32_t *data);
+
+/**
+ * Threat safe Update (read/modify/write) single byte register
+ *
+ * Final_reg = (Initial_reg & and_data) |or_data
+ *
+ * @param   Dev        Device Handle
+ * @param   index      The register index
+ * @param   AndData    8 bit and data
+ * @param   OrData     8 bit or data
+ * @return  VL_ERROR_NONE        Success
+ * @return  "Other error code"    See ::int8_t
+ */
+int8_t VL_UpdateByte(struct vl_data *Dev, uint8_t index,
+		uint8_t AndData, uint8_t OrData);
+
+/** @} end of VL_registerAccess_group */
+
+
+/**
+ * @brief execute delay in all polling API call
+ *
+ * A typical multi-thread or RTOs implementation is to sleep the task for
+ * some 5ms (with 100Hz max rate faster polling is not needed)
+ * if nothing specific is need you can define it as an empty/void macro
+ * @code
+ * #define VL_PollingDelay(...) (void)0
+ * @endcode
+ * @param Dev       Device Handle
+ * @return  VL_ERROR_NONE        Success
+ * @return  "Other error code"    See ::int8_t
+ */
+int8_t VL_PollingDelay(struct vl_data *Dev);
+/* usually best implemented as a real function */
+
+/** @} end of VL_platform_group */
+
+#endif  /* _VL_PLATFORM_H_ */
+
+
+
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_platform_log.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_platform_log.h
new file mode 100644
index 0000000..a8f22c5
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_platform_log.h
@@ -0,0 +1,99 @@
+/*
+ *  vl53l0x_platform_log.h - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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 _VL_PLATFORM_LOG_H_
+#define _VL_PLATFORM_LOG_H_
+
+#include <linux/string.h>
+/* LOG Functions */
+
+
+/**
+ * @file vl53l0x_platform_log.h
+ *
+ * @brief platform log function definition
+ */
+
+/* #define VL_LOG_ENABLE */
+
+enum {
+	TRACE_LEVEL_NONE,
+	TRACE_LEVEL_ERRORS,
+	TRACE_LEVEL_WARNING,
+	TRACE_LEVEL_INFO,
+	TRACE_LEVEL_DEBUG,
+	TRACE_LEVEL_ALL,
+	TRACE_LEVEL_IGNORE
+};
+
+enum {
+	TRACE_FUNCTION_NONE = 0,
+	TRACE_FUNCTION_I2C  = 1,
+	TRACE_FUNCTION_ALL  = 0x7fffffff /* all bits except sign */
+};
+
+enum {
+	TRACE_MODULE_NONE              = 0x0,
+	TRACE_MODULE_API               = 0x1,
+	TRACE_MODULE_PLATFORM          = 0x2,
+	TRACE_MODULE_ALL               = 0x7fffffff /* all bits except sign */
+};
+
+
+#ifdef VL_LOG_ENABLE
+
+#include <linux/module.h>
+
+
+extern uint32_t _trace_level;
+
+
+
+int32_t VL_trace_config(char *filename, uint32_t modules,
+			uint32_t level, uint32_t functions);
+
+#define trace_print_module_function(...)
+
+#define LOG_GET_TIME()	0
+#define _LOG_FUNCTION_START(module, fmt, ...) \
+		dbg("beg %s start @%d\t" fmt "\n", \
+		__func__, LOG_GET_TIME(), ##__VA_ARGS__)
+
+#define _LOG_FUNCTION_END(module, status, ...)\
+		dbg("end %s start @%d Status %d\n", \
+		 __func__, LOG_GET_TIME(), (int)status)
+
+#define _LOG_FUNCTION_END_FMT(module, status, fmt, ...)\
+		dbg("End %s @%d %d\t"fmt"\n", \
+		__func__, LOG_GET_TIME(), (int)status, ##__VA_ARGS__)
+
+
+#else /* VL_LOG_ENABLE no logging */
+	#define VL_ErrLog(...) (void)0
+	#define _LOG_FUNCTION_START(module, fmt, ...) (void)0
+	#define _LOG_FUNCTION_END(module, status, ...) (void)0
+	#define _LOG_FUNCTION_END_FMT(module, status, fmt, ...) (void)0
+#endif /* else */
+
+#define VL_COPYSTRING(str, ...) strlcpy(str, ##__VA_ARGS__, sizeof(str))
+
+
+#endif  /* _VL_PLATFORM_LOG_H_ */
+
+
+
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_tuning.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_tuning.h
new file mode 100644
index 0000000..ba2998a
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_tuning.h
@@ -0,0 +1,135 @@
+/*
+ *  vl53l0x_tuning.h - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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 _VL_TUNING_H_
+#define _VL_TUNING_H_
+
+#include "vl53l0x_def.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+uint8_t DefaultTuningSettings[] = {
+
+	/* update 02/11/2015_v36 */
+	0x01, 0xFF, 0x01,
+	0x01, 0x00, 0x00,
+
+	0x01, 0xFF, 0x00,
+	0x01, 0x09, 0x00,
+	0x01, 0x10, 0x00,
+	0x01, 0x11, 0x00,
+
+	0x01, 0x24, 0x01,
+	0x01, 0x25, 0xff,
+	0x01, 0x75, 0x00,
+
+	0x01, 0xFF, 0x01,
+	0x01, 0x4e, 0x2c,
+	0x01, 0x48, 0x00,
+	0x01, 0x30, 0x20,
+
+	0x01, 0xFF, 0x00,
+	0x01, 0x30, 0x09, /* mja changed from 0x64. */
+	0x01, 0x54, 0x00,
+	0x01, 0x31, 0x04,
+	0x01, 0x32, 0x03,
+	0x01, 0x40, 0x83,
+	0x01, 0x46, 0x25,
+	0x01, 0x60, 0x00,
+	0x01, 0x27, 0x00,
+	0x01, 0x50, 0x06,
+	0x01, 0x51, 0x00,
+	0x01, 0x52, 0x96,
+	0x01, 0x56, 0x08,
+	0x01, 0x57, 0x30,
+	0x01, 0x61, 0x00,
+	0x01, 0x62, 0x00,
+	0x01, 0x64, 0x00,
+	0x01, 0x65, 0x00,
+	0x01, 0x66, 0xa0,
+
+	0x01, 0xFF, 0x01,
+	0x01, 0x22, 0x32,
+	0x01, 0x47, 0x14,
+	0x01, 0x49, 0xff,
+	0x01, 0x4a, 0x00,
+
+	0x01, 0xFF, 0x00,
+	0x01, 0x7a, 0x0a,
+	0x01, 0x7b, 0x00,
+	0x01, 0x78, 0x21,
+
+	0x01, 0xFF, 0x01,
+	0x01, 0x23, 0x34,
+	0x01, 0x42, 0x00,
+	0x01, 0x44, 0xff,
+	0x01, 0x45, 0x26,
+	0x01, 0x46, 0x05,
+	0x01, 0x40, 0x40,
+	0x01, 0x0E, 0x06,
+	0x01, 0x20, 0x1a,
+	0x01, 0x43, 0x40,
+
+	0x01, 0xFF, 0x00,
+	0x01, 0x34, 0x03,
+	0x01, 0x35, 0x44,
+
+	0x01, 0xFF, 0x01,
+	0x01, 0x31, 0x04,
+	0x01, 0x4b, 0x09,
+	0x01, 0x4c, 0x05,
+	0x01, 0x4d, 0x04,
+
+
+	0x01, 0xFF, 0x00,
+	0x01, 0x44, 0x00,
+	0x01, 0x45, 0x20,
+	0x01, 0x47, 0x08,
+	0x01, 0x48, 0x28,
+	0x01, 0x67, 0x00,
+	0x01, 0x70, 0x04,
+	0x01, 0x71, 0x01,
+	0x01, 0x72, 0xfe,
+	0x01, 0x76, 0x00,
+	0x01, 0x77, 0x00,
+
+	0x01, 0xFF, 0x01,
+	0x01, 0x0d, 0x01,
+
+	0x01, 0xFF, 0x00,
+	0x01, 0x80, 0x01,
+	0x01, 0x01, 0xF8,
+
+	0x01, 0xFF, 0x01,
+	0x01, 0x8e, 0x01,
+	0x01, 0x00, 0x01,
+	0x01, 0xFF, 0x00,
+	0x01, 0x80, 0x00,
+
+	0x00, 0x00, 0x00
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL_TUNING_H_ */
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_types.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_types.h
new file mode 100644
index 0000000..be40e83
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_types.h
@@ -0,0 +1,54 @@
+/*
+ *  vl53l0x_types.h - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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 VL_TYPES_H_
+#define VL_TYPES_H_
+
+#include <linux/types.h>
+
+#ifndef NULL
+#error "TODO review  NULL definition or add required include "
+#define NULL 0
+#endif
+
+#if !defined(STDINT_H) &&  !defined(_GCC_STDINT_H) \
+	&& !defined(_STDINT_H) && !defined(_LINUX_TYPES_H)
+
+#pragma message(
+"Review type definition of STDINT define for your platform and add to above")
+
+/*
+ *  target platform do not provide stdint or use a different #define than above
+ *  to avoid seeing the message below addapt the #define list above or implement
+ *  all type and delete these pragma
+ */
+
+unsigned int uint32_t;
+int int32_t;
+
+unsigned short uint16_t;
+short int16_t;
+
+unsigned char uint8_t;
+
+signed char int8_t;
+
+
+#endif /* _STDINT_H */
+
+#endif /* VL_TYPES_H_ */
diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api.c
new file mode 100644
index 0000000..888947f
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api.c
@@ -0,0 +1,3096 @@
+/*
+ *  vl53l0x_api.c - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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 "vl53l0x_api.h"
+#include "vl53l0x_tuning.h"
+#include "vl53l0x_interrupt_threshold_settings.h"
+#include "vl53l0x_api_core.h"
+#include "vl53l0x_api_calibration.h"
+#include "vl53l0x_api_strings.h"
+
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
+#define LOG_FUNCTION_START(fmt, ...) \
+	_LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+	_LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
+	_LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
+
+#ifdef VL_LOG_ENABLE
+#define trace_print(level, ...) trace_print_module_function(TRACE_MODULE_API, \
+	level, TRACE_FUNCTION_NONE, ##__VA_ARGS__)
+#endif
+
+/* Group PAL General Functions */
+
+int8_t VL_GetVersion(struct VL_Version_t *pVersion)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	pVersion->major = VL_IMPLEMENTATION_VER_MAJOR;
+	pVersion->minor = VL_IMPLEMENTATION_VER_MINOR;
+	pVersion->build = VL_IMPLEMENTATION_VER_SUB;
+
+	pVersion->revision = VL_IMPLEMENTATION_VER_REVISION;
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetPalSpecVersion(struct VL_Version_t *pPalSpecVersion)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	pPalSpecVersion->major = VL_SPECIFICATION_VER_MAJOR;
+	pPalSpecVersion->minor = VL_SPECIFICATION_VER_MINOR;
+	pPalSpecVersion->build = VL_SPECIFICATION_VER_SUB;
+
+	pPalSpecVersion->revision = VL_SPECIFICATION_VER_REVISION;
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetProductRevision(struct vl_data *Dev,
+	uint8_t *pProductRevisionMajor, uint8_t *pProductRevisionMinor)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t revision_id;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_RdByte(Dev, VL_REG_IDENTIFICATION_REVISION_ID,
+		&revision_id);
+	*pProductRevisionMajor = 1;
+	*pProductRevisionMinor = (revision_id & 0xF0) >> 4;
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+
+}
+
+int8_t VL_GetDeviceInfo(struct vl_data *Dev,
+	struct VL_DeviceInfo_t *pVL_DeviceInfo)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_get_device_info(Dev, pVL_DeviceInfo);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetDeviceErrorStatus(struct vl_data *Dev,
+	uint8_t *pDeviceErrorStatus)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t RangeStatus;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_RdByte(Dev, VL_REG_RESULT_RANGE_STATUS,
+		&RangeStatus);
+
+	*pDeviceErrorStatus = (uint8_t)((RangeStatus & 0x78) >> 3);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+
+int8_t VL_GetDeviceErrorString(uint8_t ErrorCode,
+	char *pDeviceErrorString)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_get_device_error_string(ErrorCode, pDeviceErrorString);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetRangeStatusString(uint8_t RangeStatus,
+	char *pRangeStatusString)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_get_range_status_string(RangeStatus,
+		pRangeStatusString);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetPalErrorString(int8_t PalErrorCode,
+	char *pPalErrorString)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_get_pal_error_string(PalErrorCode, pPalErrorString);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetPalStateString(uint8_t PalStateCode,
+	char *pPalStateString)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_get_pal_state_string(PalStateCode, pPalStateString);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetPalState(struct vl_data *Dev, uint8_t *pPalState)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	*pPalState = PALDevDataGet(Dev, PalState);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetPowerMode(struct vl_data *Dev,
+	uint8_t PowerMode)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	/* Only level1 of Power mode exists */
+	if ((PowerMode != VL_POWERMODE_STANDBY_LEVEL1)
+		&& (PowerMode != VL_POWERMODE_IDLE_LEVEL1)) {
+		Status = VL_ERROR_MODE_NOT_SUPPORTED;
+	} else if (PowerMode == VL_POWERMODE_STANDBY_LEVEL1) {
+		/* set the standby level1 of power mode */
+		Status = VL_WrByte(Dev, 0x80, 0x00);
+		if (Status == VL_ERROR_NONE) {
+			/* Set PAL State to standby */
+			PALDevDataSet(Dev, PalState, VL_STATE_STANDBY);
+			PALDevDataSet(Dev, PowerMode,
+				VL_POWERMODE_STANDBY_LEVEL1);
+		}
+
+	} else {
+		/* VL_POWERMODE_IDLE_LEVEL1 */
+		Status = VL_WrByte(Dev, 0x80, 0x00);
+		if (Status == VL_ERROR_NONE)
+			Status = VL_StaticInit(Dev);
+
+		if (Status == VL_ERROR_NONE)
+			PALDevDataSet(Dev, PowerMode,
+				VL_POWERMODE_IDLE_LEVEL1);
+
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetPowerMode(struct vl_data *Dev,
+	uint8_t *pPowerMode)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t Byte;
+
+	LOG_FUNCTION_START("");
+
+	/* Only level1 of Power mode exists */
+	Status = VL_RdByte(Dev, 0x80, &Byte);
+
+	if (Status == VL_ERROR_NONE) {
+		if (Byte == 1) {
+			PALDevDataSet(Dev, PowerMode,
+				VL_POWERMODE_IDLE_LEVEL1);
+		} else {
+			PALDevDataSet(Dev, PowerMode,
+				VL_POWERMODE_STANDBY_LEVEL1);
+		}
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetOffsetCalibrationDataMicroMeter(struct vl_data *Dev,
+	int32_t OffsetCalibrationDataMicroMeter)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_set_offset_calibration_data_micro_meter(Dev,
+		OffsetCalibrationDataMicroMeter);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetOffsetCalibrationDataMicroMeter(struct vl_data *Dev,
+	int32_t *pOffsetCalibrationDataMicroMeter)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_get_offset_calibration_data_micro_meter(Dev,
+		pOffsetCalibrationDataMicroMeter);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetLinearityCorrectiveGain(struct vl_data *Dev,
+	int16_t LinearityCorrectiveGain)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	if ((LinearityCorrectiveGain < 0) || (LinearityCorrectiveGain > 1000))
+		Status = VL_ERROR_INVALID_PARAMS;
+	else {
+		PALDevDataSet(Dev, LinearityCorrectiveGain,
+			LinearityCorrectiveGain);
+
+		if (LinearityCorrectiveGain != 1000) {
+			/* Disable FW Xtalk */
+			Status = VL_WrWord(Dev,
+			VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS, 0);
+		}
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetLinearityCorrectiveGain(struct vl_data *Dev,
+	uint16_t *pLinearityCorrectiveGain)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	*pLinearityCorrectiveGain = PALDevDataGet(Dev, LinearityCorrectiveGain);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetGroupParamHold(struct vl_data *Dev, uint8_t GroupParamHold)
+{
+	int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+	LOG_FUNCTION_START("");
+
+	/* not implemented on VL53L0X */
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetUpperLimitMilliMeter(struct vl_data *Dev,
+	uint16_t *pUpperLimitMilliMeter)
+{
+	int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+	LOG_FUNCTION_START("");
+
+	/* not implemented on VL53L0X */
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetTotalSignalRate(struct vl_data *Dev,
+	unsigned int *pTotalSignalRate)
+{
+	int8_t Status = VL_ERROR_NONE;
+	struct VL_RangingMeasurementData_t LastRangeDataBuffer;
+
+	LOG_FUNCTION_START("");
+
+	LastRangeDataBuffer = PALDevDataGet(Dev, LastRangeMeasure);
+
+	Status = VL_get_total_signal_rate(
+		Dev, &LastRangeDataBuffer, pTotalSignalRate);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+/* End Group PAL General Functions */
+
+/* Group PAL Init Functions */
+int8_t VL_SetDeviceAddress(struct vl_data *Dev, uint8_t DeviceAddress)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_WrByte(Dev, VL_REG_I2C_SLAVE_DEVICE_ADDRESS,
+		DeviceAddress / 2);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_DataInit(struct vl_data *Dev)
+{
+	int8_t Status = VL_ERROR_NONE;
+	struct VL_DeviceParameters_t CurrentParameters;
+	int i;
+	uint8_t StopVariable;
+
+	LOG_FUNCTION_START("");
+
+	/* by default the I2C is running at 1V8 if you want to change it you */
+	/* need to include this define at compilation level. */
+#ifdef USE_I2C_2V8
+	Status = VL_UpdateByte(Dev,
+		VL_REG_VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV,
+		0xFE,
+		0x01);
+#endif
+
+	/* Set I2C standard mode */
+	if (Status == VL_ERROR_NONE)
+		Status = VL_WrByte(Dev, 0x88, 0x00);
+
+	VL_SETDEVICESPECIFICPARAMETER(Dev, ReadDataFromDeviceDone, 0);
+
+#ifdef USE_IQC_STATION
+	if (Status == VL_ERROR_NONE)
+		Status = VL_apply_offset_adjustment(Dev);
+#endif
+
+	/* Default value is 1000 for Linearity Corrective Gain */
+	PALDevDataSet(Dev, LinearityCorrectiveGain, 1000);
+
+	/* Dmax default Parameter */
+	PALDevDataSet(Dev, DmaxCalRangeMilliMeter, 400);
+	PALDevDataSet(Dev, DmaxCalSignalRateRtnMegaCps,
+		(unsigned int)((0x00016B85))); /* 1.42 No Cover Glass*/
+
+	/* Set Default static parameters */
+	/* *set first temporary values 9.44MHz * 65536 = 618660 */
+	VL_SETDEVICESPECIFICPARAMETER(Dev, OscFrequencyMHz, 618660);
+
+	/* Set Default XTalkCompensationRateMegaCps to 0  */
+	VL_SETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps, 0);
+
+	/* Get default parameters */
+	Status = VL_GetDeviceParameters(Dev, &CurrentParameters);
+	if (Status == VL_ERROR_NONE) {
+		/* initialize PAL values */
+		CurrentParameters.DeviceMode = VL_DEVICEMODE_SINGLE_RANGING;
+		CurrentParameters.HistogramMode = VL_HISTOGRAMMODE_DISABLED;
+		PALDevDataSet(Dev, CurrentParameters, CurrentParameters);
+	}
+
+	/* Sigma estimator variable */
+	PALDevDataSet(Dev, SigmaEstRefArray, 100);
+	PALDevDataSet(Dev, SigmaEstEffPulseWidth, 900);
+	PALDevDataSet(Dev, SigmaEstEffAmbWidth, 500);
+	PALDevDataSet(Dev, targetRefRate, 0x0A00); /* 20 MCPS in 9:7 format */
+
+	/* Use internal default settings */
+	PALDevDataSet(Dev, UseInternalTuningSettings, 1);
+
+	Status |= VL_WrByte(Dev, 0x80, 0x01);
+	Status |= VL_WrByte(Dev, 0xFF, 0x01);
+	Status |= VL_WrByte(Dev, 0x00, 0x00);
+	Status |= VL_RdByte(Dev, 0x91, &StopVariable);
+	PALDevDataSet(Dev, StopVariable, StopVariable);
+	Status |= VL_WrByte(Dev, 0x00, 0x01);
+	Status |= VL_WrByte(Dev, 0xFF, 0x00);
+	Status |= VL_WrByte(Dev, 0x80, 0x00);
+
+	/* Enable all check */
+	for (i = 0; i < VL_CHECKENABLE_NUMBER_OF_CHECKS; i++) {
+		if (Status == VL_ERROR_NONE)
+			Status |= VL_SetLimitCheckEnable(Dev, i, 1);
+		else
+			break;
+
+	}
+
+	/* Disable the following checks */
+	if (Status == VL_ERROR_NONE)
+		Status = VL_SetLimitCheckEnable(Dev,
+			VL_CHECKENABLE_SIGNAL_REF_CLIP, 0);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_SetLimitCheckEnable(Dev,
+			VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_SetLimitCheckEnable(Dev,
+			VL_CHECKENABLE_SIGNAL_RATE_MSRC, 0);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_SetLimitCheckEnable(Dev,
+			VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE, 0);
+
+	/* Limit default values */
+	if (Status == VL_ERROR_NONE) {
+		Status = VL_SetLimitCheckValue(Dev,
+			VL_CHECKENABLE_SIGMA_FINAL_RANGE,
+				(unsigned int)(18 * 65536));
+	}
+	if (Status == VL_ERROR_NONE) {
+		Status = VL_SetLimitCheckValue(Dev,
+			VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+				(unsigned int)(25 * 65536 / 100));
+				/* 0.25 * 65536 */
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		Status = VL_SetLimitCheckValue(Dev,
+			VL_CHECKENABLE_SIGNAL_REF_CLIP,
+				(unsigned int)(35 * 65536));
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		Status = VL_SetLimitCheckValue(Dev,
+			VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+				(unsigned int)(0 * 65536));
+	}
+
+	if (Status == VL_ERROR_NONE) {
+
+		PALDevDataSet(Dev, SequenceConfig, 0xFF);
+		Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG,
+			0xFF);
+
+		/* Set PAL state to tell that we are waiting for call to */
+		/* * VL_StaticInit */
+		PALDevDataSet(Dev, PalState, VL_STATE_WAIT_STATICINIT);
+	}
+
+	if (Status == VL_ERROR_NONE)
+		VL_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 0);
+
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetTuningSettingBuffer(struct vl_data *Dev,
+	uint8_t *pTuningSettingBuffer, uint8_t UseInternalTuningSettings)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	if (UseInternalTuningSettings == 1) {
+		/* Force use internal settings */
+		PALDevDataSet(Dev, UseInternalTuningSettings, 1);
+	} else {
+
+		/* check that the first byte is not 0 */
+		if (*pTuningSettingBuffer != 0) {
+			PALDevDataSet(Dev, pTuningSettingsPointer,
+				pTuningSettingBuffer);
+			PALDevDataSet(Dev, UseInternalTuningSettings, 0);
+
+		} else {
+			Status = VL_ERROR_INVALID_PARAMS;
+		}
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetTuningSettingBuffer(struct vl_data *Dev,
+	uint8_t **ppTuningSettingBuffer, uint8_t *pUseInternalTuningSettings)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	*ppTuningSettingBuffer = PALDevDataGet(Dev, pTuningSettingsPointer);
+	*pUseInternalTuningSettings = PALDevDataGet(Dev,
+		UseInternalTuningSettings);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_StaticInit(struct vl_data *Dev)
+{
+	int8_t Status = VL_ERROR_NONE;
+	struct VL_DeviceParameters_t CurrentParameters = {0};
+	uint8_t *pTuningSettingBuffer;
+	uint16_t tempword = 0;
+	uint8_t tempbyte = 0;
+	uint8_t UseInternalTuningSettings = 0;
+	uint32_t count = 0;
+	uint8_t isApertureSpads = 0;
+	uint32_t refSpadCount = 0;
+	uint8_t ApertureSpads = 0;
+	uint8_t vcselPulsePeriodPCLK;
+	uint32_t seqTimeoutMicroSecs;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_get_info_from_device(Dev, 1);
+
+	/* set the ref spad from NVM */
+	count	= (uint32_t)VL_GETDEVICESPECIFICPARAMETER(Dev,
+		ReferenceSpadCount);
+	ApertureSpads = VL_GETDEVICESPECIFICPARAMETER(Dev,
+		ReferenceSpadType);
+
+	/* NVM value invalid */
+	if ((ApertureSpads > 1) ||
+		((ApertureSpads == 1) && (count > 32)) ||
+		((ApertureSpads == 0) && (count > 12)))
+		Status = VL_perform_ref_spad_management(Dev, &refSpadCount,
+			&isApertureSpads);
+	else
+		Status = VL_set_reference_spads(Dev, count, ApertureSpads);
+
+
+	/* Initialize tuning settings buffer to prevent compiler warning. */
+	pTuningSettingBuffer = DefaultTuningSettings;
+
+	if (Status == VL_ERROR_NONE) {
+		UseInternalTuningSettings = PALDevDataGet(Dev,
+			UseInternalTuningSettings);
+
+		if (UseInternalTuningSettings == 0)
+			pTuningSettingBuffer = PALDevDataGet(Dev,
+				pTuningSettingsPointer);
+		else
+			pTuningSettingBuffer = DefaultTuningSettings;
+
+	}
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_load_tuning_settings(Dev,
+			pTuningSettingBuffer);
+
+
+	/* Set interrupt config to new sample ready */
+	if (Status == VL_ERROR_NONE) {
+		Status = VL_SetGpioConfig(Dev, 0, 0,
+		VL_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY,
+		VL_INTERRUPTPOLARITY_LOW);
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		Status = VL_WrByte(Dev, 0xFF, 0x01);
+		Status |= VL_RdWord(Dev, 0x84, &tempword);
+		Status |= VL_WrByte(Dev, 0xFF, 0x00);
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		VL_SETDEVICESPECIFICPARAMETER(Dev, OscFrequencyMHz,
+			VL_FIXPOINT412TOFIXPOINT1616(tempword));
+	}
+
+	/* After static init, some device parameters may be changed, */
+	/* * so update them */
+	if (Status == VL_ERROR_NONE)
+		Status = VL_GetDeviceParameters(Dev, &CurrentParameters);
+
+
+	if (Status == VL_ERROR_NONE) {
+		Status = VL_GetFractionEnable(Dev, &tempbyte);
+		if (Status == VL_ERROR_NONE)
+			PALDevDataSet(Dev, RangeFractionalEnable, tempbyte);
+
+	}
+
+	if (Status == VL_ERROR_NONE)
+		PALDevDataSet(Dev, CurrentParameters, CurrentParameters);
+
+
+	/* read the sequence config and save it */
+	if (Status == VL_ERROR_NONE) {
+		Status = VL_RdByte(Dev,
+		VL_REG_SYSTEM_SEQUENCE_CONFIG, &tempbyte);
+		if (Status == VL_ERROR_NONE)
+			PALDevDataSet(Dev, SequenceConfig, tempbyte);
+
+	}
+
+	/* Disable MSRC and TCC by default */
+	if (Status == VL_ERROR_NONE)
+		Status = VL_SetSequenceStepEnable(Dev,
+					VL_SEQUENCESTEP_TCC, 0);
+
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_SetSequenceStepEnable(Dev,
+		VL_SEQUENCESTEP_MSRC, 0);
+
+
+	/* Set PAL State to standby */
+	if (Status == VL_ERROR_NONE)
+		PALDevDataSet(Dev, PalState, VL_STATE_IDLE);
+
+
+
+	/* Store pre-range vcsel period */
+	if (Status == VL_ERROR_NONE) {
+		Status = VL_GetVcselPulsePeriod(
+			Dev,
+			VL_VCSEL_PERIOD_PRE_RANGE,
+			&vcselPulsePeriodPCLK);
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		VL_SETDEVICESPECIFICPARAMETER(
+		Dev, PreRangeVcselPulsePeriod,
+		vcselPulsePeriodPCLK);
+	}
+
+	/* Store final-range vcsel period */
+	if (Status == VL_ERROR_NONE) {
+		Status = VL_GetVcselPulsePeriod(
+			Dev,
+			VL_VCSEL_PERIOD_FINAL_RANGE,
+			&vcselPulsePeriodPCLK);
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		VL_SETDEVICESPECIFICPARAMETER(
+		Dev, FinalRangeVcselPulsePeriod,
+		vcselPulsePeriodPCLK);
+	}
+
+	/* Store pre-range timeout */
+	if (Status == VL_ERROR_NONE) {
+		Status = get_sequence_step_timeout(
+			Dev,
+			VL_SEQUENCESTEP_PRE_RANGE,
+			&seqTimeoutMicroSecs);
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		VL_SETDEVICESPECIFICPARAMETER(
+			Dev,
+			PreRangeTimeoutMicroSecs,
+			seqTimeoutMicroSecs);
+	}
+
+	/* Store final-range timeout */
+	if (Status == VL_ERROR_NONE) {
+		Status = get_sequence_step_timeout(
+			Dev,
+			VL_SEQUENCESTEP_FINAL_RANGE,
+			&seqTimeoutMicroSecs);
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		VL_SETDEVICESPECIFICPARAMETER(
+			Dev,
+			FinalRangeTimeoutMicroSecs,
+			seqTimeoutMicroSecs);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_WaitDeviceBooted(struct vl_data *Dev)
+{
+	int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+	LOG_FUNCTION_START("");
+
+	/* not implemented on VL53L0X */
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_ResetDevice(struct vl_data *Dev)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t Byte;
+
+	LOG_FUNCTION_START("");
+
+	/* Set reset bit */
+	Status = VL_WrByte(Dev, VL_REG_SOFT_RESET_GO2_SOFT_RESET_N,
+		0x00);
+
+	/* Wait for some time */
+	if (Status == VL_ERROR_NONE) {
+		do {
+			Status = VL_RdByte(Dev,
+			VL_REG_IDENTIFICATION_MODEL_ID, &Byte);
+		} while (Byte != 0x00);
+	}
+
+	VL_PollingDelay(Dev);
+
+	/* Release reset */
+	Status = VL_WrByte(Dev, VL_REG_SOFT_RESET_GO2_SOFT_RESET_N,
+		0x01);
+
+	/* Wait until correct boot-up of the device */
+	if (Status == VL_ERROR_NONE) {
+		do {
+			Status = VL_RdByte(Dev,
+			VL_REG_IDENTIFICATION_MODEL_ID, &Byte);
+		} while (Byte == 0x00);
+	}
+
+	VL_PollingDelay(Dev);
+
+	/* Set PAL State to VL_STATE_POWERDOWN */
+	if (Status == VL_ERROR_NONE)
+		PALDevDataSet(Dev, PalState, VL_STATE_POWERDOWN);
+
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+/* End Group PAL Init Functions */
+
+/* Group PAL Parameters Functions */
+int8_t VL_SetDeviceParameters(struct vl_data *Dev,
+	const struct VL_DeviceParameters_t *pDeviceParameters)
+{
+	int8_t Status = VL_ERROR_NONE;
+	int i;
+
+	LOG_FUNCTION_START("");
+	Status = VL_SetDeviceMode(Dev, pDeviceParameters->DeviceMode);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_SetInterMeasurementPeriodMilliSeconds(Dev,
+			pDeviceParameters->InterMeasurementPeriodMilliSeconds);
+
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_SetXTalkCompensationRateMegaCps(Dev,
+			pDeviceParameters->XTalkCompensationRateMegaCps);
+
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_SetOffsetCalibrationDataMicroMeter(Dev,
+			pDeviceParameters->RangeOffsetMicroMeters);
+
+
+	for (i = 0; i < VL_CHECKENABLE_NUMBER_OF_CHECKS; i++) {
+		if (Status == VL_ERROR_NONE)
+			Status |= VL_SetLimitCheckEnable(Dev, i,
+				pDeviceParameters->LimitChecksEnable[i]);
+		else
+			break;
+
+		if (Status == VL_ERROR_NONE)
+			Status |= VL_SetLimitCheckValue(Dev, i,
+				pDeviceParameters->LimitChecksValue[i]);
+		else
+			break;
+
+	}
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_SetWrapAroundCheckEnable(Dev,
+			pDeviceParameters->WrapAroundCheckEnable);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_SetMeasurementTimingBudgetMicroSeconds(Dev,
+			pDeviceParameters->MeasurementTimingBudgetMicroSeconds);
+
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetDeviceParameters(struct vl_data *Dev,
+	struct VL_DeviceParameters_t *pDeviceParameters)
+{
+	int8_t Status = VL_ERROR_NONE;
+	int i;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_GetDeviceMode(Dev, &(pDeviceParameters->DeviceMode));
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_GetInterMeasurementPeriodMilliSeconds(Dev,
+		&(pDeviceParameters->InterMeasurementPeriodMilliSeconds));
+
+
+	if (Status == VL_ERROR_NONE)
+		pDeviceParameters->XTalkCompensationEnable = 0;
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_GetXTalkCompensationRateMegaCps(Dev,
+			&(pDeviceParameters->XTalkCompensationRateMegaCps));
+
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_GetOffsetCalibrationDataMicroMeter(Dev,
+			&(pDeviceParameters->RangeOffsetMicroMeters));
+
+
+	if (Status == VL_ERROR_NONE) {
+		for (i = 0; i < VL_CHECKENABLE_NUMBER_OF_CHECKS; i++) {
+			/* get first the values, then the enables.
+			 * VL_GetLimitCheckValue will modify the enable
+			 * flags
+			 */
+			if (Status == VL_ERROR_NONE) {
+				Status |= VL_GetLimitCheckValue(Dev, i,
+				&(pDeviceParameters->LimitChecksValue[i]));
+			} else {
+				break;
+			}
+			if (Status == VL_ERROR_NONE) {
+				Status |= VL_GetLimitCheckEnable(Dev, i,
+				&(pDeviceParameters->LimitChecksEnable[i]));
+			} else {
+				break;
+			}
+		}
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		Status = VL_GetWrapAroundCheckEnable(Dev,
+			&(pDeviceParameters->WrapAroundCheckEnable));
+	}
+
+	/* Need to be done at the end as it uses VCSELPulsePeriod */
+	if (Status == VL_ERROR_NONE) {
+		Status = VL_GetMeasurementTimingBudgetMicroSeconds(Dev,
+		&(pDeviceParameters->MeasurementTimingBudgetMicroSeconds));
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetDeviceMode(struct vl_data *Dev,
+	uint8_t DeviceMode)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("%d", (int)DeviceMode);
+
+	switch (DeviceMode) {
+	case VL_DEVICEMODE_SINGLE_RANGING:
+	case VL_DEVICEMODE_CONTINUOUS_RANGING:
+	case VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING:
+	case VL_DEVICEMODE_GPIO_DRIVE:
+	case VL_DEVICEMODE_GPIO_OSC:
+		/* Supported modes */
+		VL_SETPARAMETERFIELD(Dev, DeviceMode, DeviceMode);
+		break;
+	default:
+		/* Unsupported mode */
+		Status = VL_ERROR_MODE_NOT_SUPPORTED;
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetDeviceMode(struct vl_data *Dev,
+	uint8_t *pDeviceMode)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	VL_GETPARAMETERFIELD(Dev, DeviceMode, *pDeviceMode);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetRangeFractionEnable(struct vl_data *Dev,	uint8_t Enable)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("%d", (int)Enable);
+
+	Status = VL_WrByte(Dev, VL_REG_SYSTEM_RANGE_CONFIG, Enable);
+
+	if (Status == VL_ERROR_NONE)
+		PALDevDataSet(Dev, RangeFractionalEnable, Enable);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetFractionEnable(struct vl_data *Dev, uint8_t *pEnabled)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_RdByte(Dev, VL_REG_SYSTEM_RANGE_CONFIG, pEnabled);
+
+	if (Status == VL_ERROR_NONE)
+		*pEnabled = (*pEnabled & 1);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetHistogramMode(struct vl_data *Dev,
+	uint8_t HistogramMode)
+{
+	int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+	LOG_FUNCTION_START("");
+
+	/* not implemented on VL53L0X */
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetHistogramMode(struct vl_data *Dev,
+	uint8_t *pHistogramMode)
+{
+	int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+	LOG_FUNCTION_START("");
+
+	/* not implemented on VL53L0X */
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetMeasurementTimingBudgetMicroSeconds(struct vl_data *Dev,
+	uint32_t MeasurementTimingBudgetMicroSeconds)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_set_measurement_timing_budget_micro_seconds(Dev,
+		MeasurementTimingBudgetMicroSeconds);
+
+	LOG_FUNCTION_END(Status);
+
+	return Status;
+}
+
+int8_t VL_GetMeasurementTimingBudgetMicroSeconds(struct vl_data *Dev,
+	uint32_t *pMeasurementTimingBudgetMicroSeconds)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_get_measurement_timing_budget_micro_seconds(Dev,
+		pMeasurementTimingBudgetMicroSeconds);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetVcselPulsePeriod(struct vl_data *Dev,
+	uint8_t VcselPeriodType, uint8_t VCSELPulsePeriodPCLK)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_set_vcsel_pulse_period(Dev, VcselPeriodType,
+		VCSELPulsePeriodPCLK);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetVcselPulsePeriod(struct vl_data *Dev,
+	uint8_t VcselPeriodType, uint8_t *pVCSELPulsePeriodPCLK)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_get_vcsel_pulse_period(Dev, VcselPeriodType,
+		pVCSELPulsePeriodPCLK);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetSequenceStepEnable(struct vl_data *Dev,
+	uint8_t SequenceStepId, uint8_t SequenceStepEnabled)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t SequenceConfig = 0;
+	uint8_t SequenceConfigNew = 0;
+	uint32_t MeasurementTimingBudgetMicroSeconds;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG,
+		&SequenceConfig);
+
+	SequenceConfigNew = SequenceConfig;
+
+	if (Status == VL_ERROR_NONE) {
+		if (SequenceStepEnabled == 1) {
+
+			/* Enable requested sequence step
+			 */
+			switch (SequenceStepId) {
+			case VL_SEQUENCESTEP_TCC:
+				SequenceConfigNew |= 0x10;
+				break;
+			case VL_SEQUENCESTEP_DSS:
+				SequenceConfigNew |= 0x28;
+				break;
+			case VL_SEQUENCESTEP_MSRC:
+				SequenceConfigNew |= 0x04;
+				break;
+			case VL_SEQUENCESTEP_PRE_RANGE:
+				SequenceConfigNew |= 0x40;
+				break;
+			case VL_SEQUENCESTEP_FINAL_RANGE:
+				SequenceConfigNew |= 0x80;
+				break;
+			default:
+				Status = VL_ERROR_INVALID_PARAMS;
+			}
+		} else {
+			/* Disable requested sequence step
+			 */
+			switch (SequenceStepId) {
+			case VL_SEQUENCESTEP_TCC:
+				SequenceConfigNew &= 0xef;
+				break;
+			case VL_SEQUENCESTEP_DSS:
+				SequenceConfigNew &= 0xd7;
+				break;
+			case VL_SEQUENCESTEP_MSRC:
+				SequenceConfigNew &= 0xfb;
+				break;
+			case VL_SEQUENCESTEP_PRE_RANGE:
+				SequenceConfigNew &= 0xbf;
+				break;
+			case VL_SEQUENCESTEP_FINAL_RANGE:
+				SequenceConfigNew &= 0x7f;
+				break;
+			default:
+				Status = VL_ERROR_INVALID_PARAMS;
+			}
+		}
+	}
+
+	if (SequenceConfigNew != SequenceConfig) {
+		/* Apply New Setting */
+		if (Status == VL_ERROR_NONE) {
+			Status = VL_WrByte(Dev,
+			VL_REG_SYSTEM_SEQUENCE_CONFIG, SequenceConfigNew);
+		}
+		if (Status == VL_ERROR_NONE)
+			PALDevDataSet(Dev, SequenceConfig, SequenceConfigNew);
+
+
+		/* Recalculate timing budget */
+		if (Status == VL_ERROR_NONE) {
+			VL_GETPARAMETERFIELD(Dev,
+				MeasurementTimingBudgetMicroSeconds,
+				MeasurementTimingBudgetMicroSeconds);
+
+			VL_SetMeasurementTimingBudgetMicroSeconds(Dev,
+				MeasurementTimingBudgetMicroSeconds);
+		}
+	}
+
+	LOG_FUNCTION_END(Status);
+
+	return Status;
+}
+
+int8_t sequence_step_enabled(struct vl_data *Dev,
+	uint8_t SequenceStepId, uint8_t SequenceConfig,
+	uint8_t *pSequenceStepEnabled)
+{
+	int8_t Status = VL_ERROR_NONE;
+	*pSequenceStepEnabled = 0;
+
+	LOG_FUNCTION_START("");
+
+	switch (SequenceStepId) {
+	case VL_SEQUENCESTEP_TCC:
+		*pSequenceStepEnabled = (SequenceConfig & 0x10) >> 4;
+		break;
+	case VL_SEQUENCESTEP_DSS:
+		*pSequenceStepEnabled = (SequenceConfig & 0x08) >> 3;
+		break;
+	case VL_SEQUENCESTEP_MSRC:
+		*pSequenceStepEnabled = (SequenceConfig & 0x04) >> 2;
+		break;
+	case VL_SEQUENCESTEP_PRE_RANGE:
+		*pSequenceStepEnabled = (SequenceConfig & 0x40) >> 6;
+		break;
+	case VL_SEQUENCESTEP_FINAL_RANGE:
+		*pSequenceStepEnabled = (SequenceConfig & 0x80) >> 7;
+		break;
+	default:
+		Status = VL_ERROR_INVALID_PARAMS;
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetSequenceStepEnable(struct vl_data *Dev,
+	uint8_t SequenceStepId, uint8_t *pSequenceStepEnabled)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t SequenceConfig = 0;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG,
+		&SequenceConfig);
+
+	if (Status == VL_ERROR_NONE) {
+		Status = sequence_step_enabled(Dev, SequenceStepId,
+			SequenceConfig, pSequenceStepEnabled);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetSequenceStepEnables(struct vl_data *Dev,
+	struct VL_SchedulerSequenceSteps_t *pSchedulerSequenceSteps)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t SequenceConfig = 0;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG,
+		&SequenceConfig);
+
+	if (Status == VL_ERROR_NONE) {
+		Status = sequence_step_enabled(Dev,
+		VL_SEQUENCESTEP_TCC, SequenceConfig,
+			&pSchedulerSequenceSteps->TccOn);
+	}
+	if (Status == VL_ERROR_NONE) {
+		Status = sequence_step_enabled(Dev,
+		VL_SEQUENCESTEP_DSS, SequenceConfig,
+			&pSchedulerSequenceSteps->DssOn);
+	}
+	if (Status == VL_ERROR_NONE) {
+		Status = sequence_step_enabled(Dev,
+		VL_SEQUENCESTEP_MSRC, SequenceConfig,
+			&pSchedulerSequenceSteps->MsrcOn);
+	}
+	if (Status == VL_ERROR_NONE) {
+		Status = sequence_step_enabled(Dev,
+		VL_SEQUENCESTEP_PRE_RANGE, SequenceConfig,
+			&pSchedulerSequenceSteps->PreRangeOn);
+	}
+	if (Status == VL_ERROR_NONE) {
+		Status = sequence_step_enabled(Dev,
+		VL_SEQUENCESTEP_FINAL_RANGE, SequenceConfig,
+			&pSchedulerSequenceSteps->FinalRangeOn);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetNumberOfSequenceSteps(struct vl_data *Dev,
+	uint8_t *pNumberOfSequenceSteps)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	*pNumberOfSequenceSteps = VL_SEQUENCESTEP_NUMBER_OF_CHECKS;
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetSequenceStepsInfo(
+	uint8_t SequenceStepId, char *pSequenceStepsString)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_get_sequence_steps_info(
+			SequenceStepId,
+			pSequenceStepsString);
+
+	LOG_FUNCTION_END(Status);
+
+	return Status;
+}
+
+int8_t VL_SetSequenceStepTimeout(struct vl_data *Dev,
+	uint8_t SequenceStepId, unsigned int TimeOutMilliSecs)
+{
+	int8_t Status = VL_ERROR_NONE;
+	int8_t Status1 = VL_ERROR_NONE;
+	uint32_t TimeoutMicroSeconds = ((TimeOutMilliSecs * 1000) + 0x8000)
+		>> 16;
+	uint32_t MeasurementTimingBudgetMicroSeconds;
+	unsigned int OldTimeOutMicroSeconds;
+
+	LOG_FUNCTION_START("");
+
+	/* Read back the current value in case we need to revert back to this.
+	 */
+	Status = get_sequence_step_timeout(Dev, SequenceStepId,
+		&OldTimeOutMicroSeconds);
+
+	if (Status == VL_ERROR_NONE) {
+		Status = set_sequence_step_timeout(Dev, SequenceStepId,
+			TimeoutMicroSeconds);
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		VL_GETPARAMETERFIELD(Dev,
+			MeasurementTimingBudgetMicroSeconds,
+			MeasurementTimingBudgetMicroSeconds);
+
+		/* At this point we don't know if the requested */
+		/* value is valid, */
+		/* therefore proceed to update the entire timing budget and */
+		/* if this fails, revert back to the previous value. */
+		Status = VL_SetMeasurementTimingBudgetMicroSeconds(Dev,
+			MeasurementTimingBudgetMicroSeconds);
+
+		if (Status != VL_ERROR_NONE) {
+			Status1 = set_sequence_step_timeout(Dev, SequenceStepId,
+				OldTimeOutMicroSeconds);
+
+			if (Status1 == VL_ERROR_NONE) {
+				Status1 =
+				VL_SetMeasurementTimingBudgetMicroSeconds(
+					Dev,
+					MeasurementTimingBudgetMicroSeconds);
+			}
+
+			Status = Status1;
+		}
+	}
+
+	LOG_FUNCTION_END(Status);
+
+	return Status;
+}
+
+int8_t VL_GetSequenceStepTimeout(struct vl_data *Dev,
+	uint8_t SequenceStepId,
+	unsigned int *pTimeOutMilliSecs)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint32_t TimeoutMicroSeconds;
+
+	LOG_FUNCTION_START("");
+
+	Status = get_sequence_step_timeout(Dev, SequenceStepId,
+		&TimeoutMicroSeconds);
+	if (Status == VL_ERROR_NONE) {
+		TimeoutMicroSeconds <<= 8;
+		*pTimeOutMilliSecs = (TimeoutMicroSeconds + 500)/1000;
+		*pTimeOutMilliSecs <<= 8;
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetInterMeasurementPeriodMilliSeconds(struct vl_data *Dev,
+	uint32_t InterMeasurementPeriodMilliSeconds)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint16_t osc_calibrate_val;
+	uint32_t IMPeriodMilliSeconds;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_RdWord(Dev, VL_REG_OSC_CALIBRATE_VAL,
+		&osc_calibrate_val);
+
+	if (Status == VL_ERROR_NONE) {
+		if (osc_calibrate_val != 0) {
+			IMPeriodMilliSeconds =
+				InterMeasurementPeriodMilliSeconds
+					* osc_calibrate_val;
+		} else {
+			IMPeriodMilliSeconds =
+				InterMeasurementPeriodMilliSeconds;
+		}
+		Status = VL_WrDWord(Dev,
+		VL_REG_SYSTEM_INTERMEASUREMENT_PERIOD,
+			IMPeriodMilliSeconds);
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		VL_SETPARAMETERFIELD(Dev,
+			InterMeasurementPeriodMilliSeconds,
+			InterMeasurementPeriodMilliSeconds);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetInterMeasurementPeriodMilliSeconds(struct vl_data *Dev,
+	uint32_t *pInterMeasurementPeriodMilliSeconds)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint16_t osc_calibrate_val;
+	uint32_t IMPeriodMilliSeconds;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_RdWord(Dev, VL_REG_OSC_CALIBRATE_VAL,
+		&osc_calibrate_val);
+
+	if (Status == VL_ERROR_NONE) {
+		Status = VL_RdDWord(Dev,
+		VL_REG_SYSTEM_INTERMEASUREMENT_PERIOD,
+			&IMPeriodMilliSeconds);
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		if (osc_calibrate_val != 0) {
+			*pInterMeasurementPeriodMilliSeconds =
+				IMPeriodMilliSeconds / osc_calibrate_val;
+		}
+		VL_SETPARAMETERFIELD(Dev,
+			InterMeasurementPeriodMilliSeconds,
+			*pInterMeasurementPeriodMilliSeconds);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetXTalkCompensationEnable(struct vl_data *Dev,
+	uint8_t XTalkCompensationEnable)
+{
+	int8_t Status = VL_ERROR_NONE;
+	unsigned int TempFix1616;
+	uint16_t LinearityCorrectiveGain;
+
+	LOG_FUNCTION_START("");
+
+	LinearityCorrectiveGain = PALDevDataGet(Dev, LinearityCorrectiveGain);
+
+	if ((XTalkCompensationEnable == 0)
+		|| (LinearityCorrectiveGain != 1000)) {
+		TempFix1616 = 0;
+	} else {
+		VL_GETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps,
+			TempFix1616);
+	}
+
+	/* the following register has a format 3.13 */
+	Status = VL_WrWord(Dev,
+	VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS,
+		VL_FIXPOINT1616TOFIXPOINT313(TempFix1616));
+
+	if (Status == VL_ERROR_NONE) {
+		if (XTalkCompensationEnable == 0) {
+			VL_SETPARAMETERFIELD(Dev, XTalkCompensationEnable,
+				0);
+		} else {
+			VL_SETPARAMETERFIELD(Dev, XTalkCompensationEnable,
+				1);
+		}
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetXTalkCompensationEnable(struct vl_data *Dev,
+	uint8_t *pXTalkCompensationEnable)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t Temp8;
+
+	LOG_FUNCTION_START("");
+
+	VL_GETPARAMETERFIELD(Dev, XTalkCompensationEnable, Temp8);
+	*pXTalkCompensationEnable = Temp8;
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetXTalkCompensationRateMegaCps(struct vl_data *Dev,
+	unsigned int XTalkCompensationRateMegaCps)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t Temp8;
+	uint16_t LinearityCorrectiveGain;
+	uint16_t data;
+
+	LOG_FUNCTION_START("");
+
+	VL_GETPARAMETERFIELD(Dev, XTalkCompensationEnable, Temp8);
+	LinearityCorrectiveGain = PALDevDataGet(Dev, LinearityCorrectiveGain);
+
+	if (Temp8 == 0) { /* disabled write only internal value */
+		VL_SETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps,
+			XTalkCompensationRateMegaCps);
+	} else {
+		/* the following register has a format 3.13 */
+		if (LinearityCorrectiveGain == 1000) {
+			data = VL_FIXPOINT1616TOFIXPOINT313(
+				XTalkCompensationRateMegaCps);
+		} else {
+			data = 0;
+		}
+
+		Status = VL_WrWord(Dev,
+		VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS, data);
+
+		if (Status == VL_ERROR_NONE) {
+			VL_SETPARAMETERFIELD(Dev,
+				XTalkCompensationRateMegaCps,
+				XTalkCompensationRateMegaCps);
+		}
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetXTalkCompensationRateMegaCps(struct vl_data *Dev,
+	unsigned int *pXTalkCompensationRateMegaCps)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint16_t Value;
+	unsigned int TempFix1616;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_RdWord(Dev,
+	VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS, (uint16_t *)&Value);
+	if (Status == VL_ERROR_NONE) {
+		if (Value == 0) {
+			/* the Xtalk is disabled return value from memory */
+			VL_GETPARAMETERFIELD(Dev,
+				XTalkCompensationRateMegaCps, TempFix1616);
+			*pXTalkCompensationRateMegaCps = TempFix1616;
+			VL_SETPARAMETERFIELD(Dev, XTalkCompensationEnable,
+				0);
+		} else {
+			TempFix1616 = VL_FIXPOINT313TOFIXPOINT1616(Value);
+			*pXTalkCompensationRateMegaCps = TempFix1616;
+			VL_SETPARAMETERFIELD(Dev,
+				XTalkCompensationRateMegaCps, TempFix1616);
+			VL_SETPARAMETERFIELD(Dev, XTalkCompensationEnable,
+				1);
+		}
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetRefCalibration(struct vl_data *Dev, uint8_t VhvSettings,
+	uint8_t PhaseCal)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_set_ref_calibration(Dev, VhvSettings, PhaseCal);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetRefCalibration(struct vl_data *Dev, uint8_t *pVhvSettings,
+	uint8_t *pPhaseCal)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_get_ref_calibration(Dev, pVhvSettings, pPhaseCal);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+/*
+ * CHECK LIMIT FUNCTIONS
+ */
+
+int8_t VL_GetNumberOfLimitCheck(uint16_t *pNumberOfLimitCheck)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	*pNumberOfLimitCheck = VL_CHECKENABLE_NUMBER_OF_CHECKS;
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetLimitCheckInfo(struct vl_data *Dev, uint16_t LimitCheckId,
+	char *pLimitCheckString)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_get_limit_check_info(Dev, LimitCheckId,
+		pLimitCheckString);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetLimitCheckStatus(struct vl_data *Dev,
+	uint16_t LimitCheckId, uint8_t *pLimitCheckStatus)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t Temp8;
+
+	LOG_FUNCTION_START("");
+
+	if (LimitCheckId >= VL_CHECKENABLE_NUMBER_OF_CHECKS) {
+		Status = VL_ERROR_INVALID_PARAMS;
+	} else {
+
+		VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
+			LimitCheckId, Temp8);
+
+		*pLimitCheckStatus = Temp8;
+
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetLimitCheckEnable(struct vl_data *Dev,
+	uint16_t LimitCheckId, uint8_t LimitCheckEnable)
+{
+	int8_t Status = VL_ERROR_NONE;
+	unsigned int TempFix1616 = 0;
+	uint8_t LimitCheckEnableInt = 0;
+	uint8_t LimitCheckDisable = 0;
+	uint8_t Temp8;
+
+	LOG_FUNCTION_START("");
+
+	if (LimitCheckId >= VL_CHECKENABLE_NUMBER_OF_CHECKS) {
+		Status = VL_ERROR_INVALID_PARAMS;
+	} else {
+		if (LimitCheckEnable == 0) {
+			TempFix1616 = 0;
+			LimitCheckEnableInt = 0;
+			LimitCheckDisable = 1;
+
+		} else {
+			VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+				LimitCheckId, TempFix1616);
+			LimitCheckDisable = 0;
+			/* this to be sure to have either 0 or 1 */
+			LimitCheckEnableInt = 1;
+		}
+
+		switch (LimitCheckId) {
+
+		case VL_CHECKENABLE_SIGMA_FINAL_RANGE:
+			/* internal computation: */
+			VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+				VL_CHECKENABLE_SIGMA_FINAL_RANGE,
+				LimitCheckEnableInt);
+
+			break;
+
+		case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
+
+			Status = VL_WrWord(Dev,
+			VL_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT,
+				VL_FIXPOINT1616TOFIXPOINT97(TempFix1616));
+
+			break;
+
+		case VL_CHECKENABLE_SIGNAL_REF_CLIP:
+
+			/* internal computation: */
+			VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+				VL_CHECKENABLE_SIGNAL_REF_CLIP,
+				LimitCheckEnableInt);
+
+			break;
+
+		case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD:
+
+			/* internal computation: */
+			VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+				VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+				LimitCheckEnableInt);
+
+			break;
+
+		case VL_CHECKENABLE_SIGNAL_RATE_MSRC:
+
+			Temp8 = (uint8_t)(LimitCheckDisable << 1);
+			Status = VL_UpdateByte(Dev,
+				VL_REG_MSRC_CONFIG_CONTROL,
+				0xFE, Temp8);
+
+			break;
+
+		case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE:
+
+			Temp8 = (uint8_t)(LimitCheckDisable << 4);
+			Status = VL_UpdateByte(Dev,
+				VL_REG_MSRC_CONFIG_CONTROL,
+				0xEF, Temp8);
+
+			break;
+
+
+		default:
+			Status = VL_ERROR_INVALID_PARAMS;
+
+		}
+
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		if (LimitCheckEnable == 0) {
+			VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+				LimitCheckId, 0);
+		} else {
+			VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+				LimitCheckId, 1);
+		}
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetLimitCheckEnable(struct vl_data *Dev,
+	uint16_t LimitCheckId, uint8_t *pLimitCheckEnable)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t Temp8;
+
+	LOG_FUNCTION_START("");
+
+	if (LimitCheckId >= VL_CHECKENABLE_NUMBER_OF_CHECKS) {
+		Status = VL_ERROR_INVALID_PARAMS;
+		*pLimitCheckEnable = 0;
+	} else {
+		VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+			LimitCheckId, Temp8);
+		*pLimitCheckEnable = Temp8;
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetLimitCheckValue(struct vl_data *Dev, uint16_t LimitCheckId,
+	unsigned int LimitCheckValue)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t Temp8;
+
+	LOG_FUNCTION_START("");
+
+	VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, LimitCheckId,
+		Temp8);
+
+	if (Temp8 == 0) { /* disabled write only internal value */
+		VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+			LimitCheckId, LimitCheckValue);
+	} else {
+
+		switch (LimitCheckId) {
+
+		case VL_CHECKENABLE_SIGMA_FINAL_RANGE:
+			/* internal computation: */
+			VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+				VL_CHECKENABLE_SIGMA_FINAL_RANGE,
+				LimitCheckValue);
+			break;
+
+		case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
+
+			Status = VL_WrWord(Dev,
+			VL_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT,
+				VL_FIXPOINT1616TOFIXPOINT97(
+					LimitCheckValue));
+
+			break;
+
+		case VL_CHECKENABLE_SIGNAL_REF_CLIP:
+
+			/* internal computation: */
+			VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+				VL_CHECKENABLE_SIGNAL_REF_CLIP,
+				LimitCheckValue);
+
+			break;
+
+		case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD:
+
+			/* internal computation: */
+			VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+				VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+				LimitCheckValue);
+
+			break;
+
+		case VL_CHECKENABLE_SIGNAL_RATE_MSRC:
+		case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE:
+
+			Status = VL_WrWord(Dev,
+				VL_REG_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT,
+				VL_FIXPOINT1616TOFIXPOINT97(
+					LimitCheckValue));
+
+			break;
+
+		default:
+			Status = VL_ERROR_INVALID_PARAMS;
+
+		}
+
+		if (Status == VL_ERROR_NONE) {
+			VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+				LimitCheckId, LimitCheckValue);
+		}
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetLimitCheckValue(struct vl_data *Dev, uint16_t LimitCheckId,
+	unsigned int *pLimitCheckValue)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t EnableZeroValue = 0;
+	uint16_t Temp16;
+	unsigned int TempFix1616;
+
+	LOG_FUNCTION_START("");
+
+	switch (LimitCheckId) {
+
+	case VL_CHECKENABLE_SIGMA_FINAL_RANGE:
+		/* internal computation: */
+		VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+			VL_CHECKENABLE_SIGMA_FINAL_RANGE, TempFix1616);
+		EnableZeroValue = 0;
+		break;
+
+	case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
+		Status = VL_RdWord(Dev,
+		VL_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT,
+			&Temp16);
+		if (Status == VL_ERROR_NONE)
+			TempFix1616 = VL_FIXPOINT97TOFIXPOINT1616(Temp16);
+
+
+		EnableZeroValue = 1;
+		break;
+
+	case VL_CHECKENABLE_SIGNAL_REF_CLIP:
+		/* internal computation: */
+		VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+			VL_CHECKENABLE_SIGNAL_REF_CLIP, TempFix1616);
+		EnableZeroValue = 0;
+		break;
+
+	case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD:
+		/* internal computation: */
+		VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+		    VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, TempFix1616);
+		EnableZeroValue = 0;
+		break;
+
+	case VL_CHECKENABLE_SIGNAL_RATE_MSRC:
+	case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE:
+		Status = VL_RdWord(Dev,
+			VL_REG_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT,
+			&Temp16);
+		if (Status == VL_ERROR_NONE)
+			TempFix1616 = VL_FIXPOINT97TOFIXPOINT1616(Temp16);
+
+
+		EnableZeroValue = 0;
+		break;
+
+	default:
+		Status = VL_ERROR_INVALID_PARAMS;
+
+	}
+
+	if (Status == VL_ERROR_NONE) {
+
+		if (EnableZeroValue == 1) {
+
+			if (TempFix1616 == 0) {
+				/* disabled: return value from memory */
+				VL_GETARRAYPARAMETERFIELD(Dev,
+					LimitChecksValue, LimitCheckId,
+					TempFix1616);
+				*pLimitCheckValue = TempFix1616;
+				VL_SETARRAYPARAMETERFIELD(Dev,
+					LimitChecksEnable, LimitCheckId, 0);
+			} else {
+				*pLimitCheckValue = TempFix1616;
+				VL_SETARRAYPARAMETERFIELD(Dev,
+					LimitChecksValue, LimitCheckId,
+					TempFix1616);
+				VL_SETARRAYPARAMETERFIELD(Dev,
+					LimitChecksEnable, LimitCheckId, 1);
+			}
+		} else {
+			*pLimitCheckValue = TempFix1616;
+		}
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+
+}
+
+int8_t VL_GetLimitCheckCurrent(struct vl_data *Dev,
+	uint16_t LimitCheckId, unsigned int *pLimitCheckCurrent)
+{
+	int8_t Status = VL_ERROR_NONE;
+	struct VL_RangingMeasurementData_t LastRangeDataBuffer;
+
+	LOG_FUNCTION_START("");
+
+	if (LimitCheckId >= VL_CHECKENABLE_NUMBER_OF_CHECKS) {
+		Status = VL_ERROR_INVALID_PARAMS;
+	} else {
+		switch (LimitCheckId) {
+		case VL_CHECKENABLE_SIGMA_FINAL_RANGE:
+			/* Need to run a ranging to have the latest values */
+			*pLimitCheckCurrent = PALDevDataGet(Dev, SigmaEstimate);
+
+			break;
+
+		case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
+			/* Need to run a ranging to have the latest values */
+			LastRangeDataBuffer = PALDevDataGet(Dev,
+				LastRangeMeasure);
+			*pLimitCheckCurrent =
+				LastRangeDataBuffer.SignalRateRtnMegaCps;
+
+			break;
+
+		case VL_CHECKENABLE_SIGNAL_REF_CLIP:
+			/* Need to run a ranging to have the latest values */
+			*pLimitCheckCurrent = PALDevDataGet(Dev,
+				LastSignalRefMcps);
+
+			break;
+
+		case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD:
+			/* Need to run a ranging to have the latest values */
+			LastRangeDataBuffer = PALDevDataGet(Dev,
+				LastRangeMeasure);
+			*pLimitCheckCurrent =
+				LastRangeDataBuffer.SignalRateRtnMegaCps;
+
+			break;
+
+		case VL_CHECKENABLE_SIGNAL_RATE_MSRC:
+			/* Need to run a ranging to have the latest values */
+			LastRangeDataBuffer = PALDevDataGet(Dev,
+				LastRangeMeasure);
+			*pLimitCheckCurrent =
+				LastRangeDataBuffer.SignalRateRtnMegaCps;
+
+			break;
+
+		case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE:
+			/* Need to run a ranging to have the latest values */
+			LastRangeDataBuffer = PALDevDataGet(Dev,
+				LastRangeMeasure);
+			*pLimitCheckCurrent =
+				LastRangeDataBuffer.SignalRateRtnMegaCps;
+
+			break;
+
+		default:
+			Status = VL_ERROR_INVALID_PARAMS;
+		}
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+
+}
+
+/*
+ * WRAPAROUND Check
+ */
+int8_t VL_SetWrapAroundCheckEnable(struct vl_data *Dev,
+	uint8_t WrapAroundCheckEnable)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t Byte;
+	uint8_t WrapAroundCheckEnableInt;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, &Byte);
+	if (WrapAroundCheckEnable == 0) {
+		/* Disable wraparound */
+		Byte = Byte & 0x7F;
+		WrapAroundCheckEnableInt = 0;
+	} else {
+		/*Enable wraparound */
+		Byte = Byte | 0x80;
+		WrapAroundCheckEnableInt = 1;
+	}
+
+	Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, Byte);
+
+	if (Status == VL_ERROR_NONE) {
+		PALDevDataSet(Dev, SequenceConfig, Byte);
+		VL_SETPARAMETERFIELD(Dev, WrapAroundCheckEnable,
+			WrapAroundCheckEnableInt);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetWrapAroundCheckEnable(struct vl_data *Dev,
+	uint8_t *pWrapAroundCheckEnable)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t data;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, &data);
+	if (Status == VL_ERROR_NONE) {
+		PALDevDataSet(Dev, SequenceConfig, data);
+		if (data & (0x01 << 7))
+			*pWrapAroundCheckEnable = 0x01;
+		else
+			*pWrapAroundCheckEnable = 0x00;
+	}
+	if (Status == VL_ERROR_NONE) {
+		VL_SETPARAMETERFIELD(Dev, WrapAroundCheckEnable,
+			*pWrapAroundCheckEnable);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetDmaxCalParameters(struct vl_data *Dev,
+	uint16_t RangeMilliMeter, unsigned int SignalRateRtnMegaCps)
+{
+	int8_t Status = VL_ERROR_NONE;
+	unsigned int SignalRateRtnMegaCpsTemp = 0;
+
+	LOG_FUNCTION_START("");
+
+	/* Check if one of input parameter is zero, in that case the */
+	/* value are get from NVM */
+	if ((RangeMilliMeter == 0) || (SignalRateRtnMegaCps == 0)) {
+		/* NVM parameters */
+		/* Run VL_get_info_from_device wit option 4 to get */
+		/* signal rate at 400 mm if the value have been already */
+		/* get this function will return with no access to device */
+		VL_get_info_from_device(Dev, 4);
+
+		SignalRateRtnMegaCpsTemp = VL_GETDEVICESPECIFICPARAMETER(
+			Dev, SignalRateMeasFixed400mm);
+
+		PALDevDataSet(Dev, DmaxCalRangeMilliMeter, 400);
+		PALDevDataSet(Dev, DmaxCalSignalRateRtnMegaCps,
+			SignalRateRtnMegaCpsTemp);
+	} else {
+		/* User parameters */
+		PALDevDataSet(Dev, DmaxCalRangeMilliMeter, RangeMilliMeter);
+		PALDevDataSet(Dev, DmaxCalSignalRateRtnMegaCps,
+			SignalRateRtnMegaCps);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetDmaxCalParameters(struct vl_data *Dev,
+	uint16_t *pRangeMilliMeter, unsigned int *pSignalRateRtnMegaCps)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	*pRangeMilliMeter = PALDevDataGet(Dev, DmaxCalRangeMilliMeter);
+	*pSignalRateRtnMegaCps = PALDevDataGet(Dev,
+		DmaxCalSignalRateRtnMegaCps);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+/* End Group PAL Parameters Functions */
+
+/* Group PAL Measurement Functions */
+int8_t VL_PerformSingleMeasurement(struct vl_data *Dev)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t DeviceMode;
+
+	LOG_FUNCTION_START("");
+
+	/* Get Current DeviceMode */
+	Status = VL_GetDeviceMode(Dev, &DeviceMode);
+
+	/* Start immediately to run a single ranging measurement in case of */
+	/* single ranging or single histogram */
+	if (Status == VL_ERROR_NONE
+		&& DeviceMode == VL_DEVICEMODE_SINGLE_RANGING)
+		Status = VL_StartMeasurement(Dev);
+
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_measurement_poll_for_completion(Dev);
+
+
+	/* Change PAL State in case of single ranging or single histogram */
+	if (Status == VL_ERROR_NONE
+		&& DeviceMode == VL_DEVICEMODE_SINGLE_RANGING)
+		PALDevDataSet(Dev, PalState, VL_STATE_IDLE);
+
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_PerformSingleHistogramMeasurement(struct vl_data *Dev,
+	struct VL_HistogramMeasurementData_t *pHistogramMeasurementData)
+{
+	int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+	LOG_FUNCTION_START("");
+
+	/* not implemented on VL53L0X */
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_PerformRefCalibration(struct vl_data *Dev,
+	uint8_t *pVhvSettings, uint8_t *pPhaseCal)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_perform_ref_calibration(Dev, pVhvSettings,
+		pPhaseCal, 1);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_PerformXTalkMeasurement(struct vl_data *Dev,
+	uint32_t TimeoutMs, unsigned int *pXtalkPerSpad,
+	uint8_t *pAmbientTooHigh)
+{
+	int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+	LOG_FUNCTION_START("");
+
+	/* not implemented on VL53L0X */
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_PerformXTalkCalibration(struct vl_data *Dev,
+	unsigned int XTalkCalDistance,
+	unsigned int *pXTalkCompensationRateMegaCps)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_perform_xtalk_calibration(Dev, XTalkCalDistance,
+		pXTalkCompensationRateMegaCps);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_PerformOffsetCalibration(struct vl_data *Dev,
+	unsigned int CalDistanceMilliMeter, int32_t *pOffsetMicroMeter)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_perform_offset_calibration(Dev, CalDistanceMilliMeter,
+		pOffsetMicroMeter);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_CheckAndLoadInterruptSettings(struct vl_data *Dev,
+	uint8_t StartNotStopFlag)
+{
+	uint8_t InterruptConfig;
+	unsigned int ThresholdLow;
+	unsigned int ThresholdHigh;
+	int8_t Status = VL_ERROR_NONE;
+
+	InterruptConfig = VL_GETDEVICESPECIFICPARAMETER(Dev,
+		Pin0GpioFunctionality);
+
+	if ((InterruptConfig ==
+		VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW) ||
+		(InterruptConfig ==
+		VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH) ||
+		(InterruptConfig ==
+		VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT)) {
+
+		Status = VL_GetInterruptThresholds(Dev,
+			VL_DEVICEMODE_CONTINUOUS_RANGING,
+			&ThresholdLow, &ThresholdHigh);
+
+		if (((ThresholdLow > 255*65536) ||
+			(ThresholdHigh > 255*65536)) &&
+			(Status == VL_ERROR_NONE)) {
+
+			if (StartNotStopFlag != 0) {
+				Status = VL_load_tuning_settings(Dev,
+					InterruptThresholdSettings);
+			} else {
+				Status |= VL_WrByte(Dev, 0xFF, 0x04);
+				Status |= VL_WrByte(Dev, 0x70, 0x00);
+				Status |= VL_WrByte(Dev, 0xFF, 0x00);
+				Status |= VL_WrByte(Dev, 0x80, 0x00);
+			}
+
+		}
+
+
+	}
+
+	return Status;
+
+}
+
+
+int8_t VL_StartMeasurement(struct vl_data *Dev)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t DeviceMode;
+	uint8_t Byte;
+	uint8_t StartStopByte = VL_REG_SYSRANGE_MODE_START_STOP;
+	uint32_t LoopNb;
+
+	LOG_FUNCTION_START("");
+
+	/* Get Current DeviceMode */
+	VL_GetDeviceMode(Dev, &DeviceMode);
+
+	Status = VL_WrByte(Dev, 0x80, 0x01);
+	Status = VL_WrByte(Dev, 0xFF, 0x01);
+	Status = VL_WrByte(Dev, 0x00, 0x00);
+	Status = VL_WrByte(Dev, 0x91, PALDevDataGet(Dev, StopVariable));
+	Status = VL_WrByte(Dev, 0x00, 0x01);
+	Status = VL_WrByte(Dev, 0xFF, 0x00);
+	Status = VL_WrByte(Dev, 0x80, 0x00);
+
+	switch (DeviceMode) {
+	case VL_DEVICEMODE_SINGLE_RANGING:
+		Status = VL_WrByte(Dev, VL_REG_SYSRANGE_START, 0x01);
+
+		Byte = StartStopByte;
+		if (Status == VL_ERROR_NONE) {
+			/* Wait until start bit has been cleared */
+			LoopNb = 0;
+			do {
+				if (LoopNb > 0)
+					Status = VL_RdByte(Dev,
+					VL_REG_SYSRANGE_START, &Byte);
+				LoopNb = LoopNb + 1;
+			} while (((Byte & StartStopByte) == StartStopByte)
+				&& (Status == VL_ERROR_NONE)
+				&& (LoopNb < VL_DEFAULT_MAX_LOOP));
+
+			if (LoopNb >= VL_DEFAULT_MAX_LOOP)
+				Status = VL_ERROR_TIME_OUT;
+
+		}
+
+		break;
+	case VL_DEVICEMODE_CONTINUOUS_RANGING:
+		/* Back-to-back mode */
+
+		/* Check if need to apply interrupt settings */
+		if (Status == VL_ERROR_NONE)
+			Status = VL_CheckAndLoadInterruptSettings(Dev, 1);
+
+		Status = VL_WrByte(Dev,
+		VL_REG_SYSRANGE_START,
+		VL_REG_SYSRANGE_MODE_BACKTOBACK);
+		if (Status == VL_ERROR_NONE) {
+			/* Set PAL State to Running */
+			PALDevDataSet(Dev, PalState, VL_STATE_RUNNING);
+		}
+		break;
+	case VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING:
+		/* Continuous mode */
+		/* Check if need to apply interrupt settings */
+		if (Status == VL_ERROR_NONE)
+			Status = VL_CheckAndLoadInterruptSettings(Dev, 1);
+
+		Status = VL_WrByte(Dev,
+		VL_REG_SYSRANGE_START,
+		VL_REG_SYSRANGE_MODE_TIMED);
+
+		if (Status == VL_ERROR_NONE) {
+			/* Set PAL State to Running */
+			PALDevDataSet(Dev, PalState, VL_STATE_RUNNING);
+		}
+		break;
+	default:
+		/* Selected mode not supported */
+		Status = VL_ERROR_MODE_NOT_SUPPORTED;
+	}
+
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_StopMeasurement(struct vl_data *Dev)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_WrByte(Dev, VL_REG_SYSRANGE_START,
+	VL_REG_SYSRANGE_MODE_SINGLESHOT);
+
+	Status = VL_WrByte(Dev, 0xFF, 0x01);
+	Status = VL_WrByte(Dev, 0x00, 0x00);
+	Status = VL_WrByte(Dev, 0x91, 0x00);
+	Status = VL_WrByte(Dev, 0x00, 0x01);
+	Status = VL_WrByte(Dev, 0xFF, 0x00);
+
+	if (Status == VL_ERROR_NONE) {
+		/* Set PAL State to Idle */
+		PALDevDataSet(Dev, PalState, VL_STATE_IDLE);
+	}
+
+	/* Check if need to apply interrupt settings */
+	if (Status == VL_ERROR_NONE)
+		Status = VL_CheckAndLoadInterruptSettings(Dev, 0);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetMeasurementDataReady(struct vl_data *Dev,
+	uint8_t *pMeasurementDataReady)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t SysRangeStatusRegister;
+	uint8_t InterruptConfig;
+	uint32_t InterruptMask;
+
+	LOG_FUNCTION_START("");
+
+	InterruptConfig = VL_GETDEVICESPECIFICPARAMETER(Dev,
+		Pin0GpioFunctionality);
+
+	if (InterruptConfig ==
+		VL_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY) {
+		Status = VL_GetInterruptMaskStatus(Dev, &InterruptMask);
+		if (InterruptMask ==
+		VL_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY)
+			*pMeasurementDataReady = 1;
+		else
+			*pMeasurementDataReady = 0;
+	} else {
+		Status = VL_RdByte(Dev, VL_REG_RESULT_RANGE_STATUS,
+			&SysRangeStatusRegister);
+		if (Status == VL_ERROR_NONE) {
+			if (SysRangeStatusRegister & 0x01)
+				*pMeasurementDataReady = 1;
+			else
+				*pMeasurementDataReady = 0;
+		}
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_WaitDeviceReadyForNewMeasurement(struct vl_data *Dev,
+	uint32_t MaxLoop)
+{
+	int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+	LOG_FUNCTION_START("");
+
+	/* not implemented for VL53L0X */
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+
+int8_t VL_GetRangingMeasurementData(struct vl_data *Dev,
+	struct VL_RangingMeasurementData_t *pRangingMeasurementData)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t DeviceRangeStatus;
+	uint8_t RangeFractionalEnable;
+	uint8_t PalRangeStatus;
+	uint8_t XTalkCompensationEnable;
+	uint16_t AmbientRate;
+	unsigned int SignalRate;
+	uint16_t XTalkCompensationRateMegaCps;
+	uint16_t EffectiveSpadRtnCount;
+	uint16_t tmpuint16;
+	uint16_t XtalkRangeMilliMeter;
+	uint16_t LinearityCorrectiveGain;
+	uint8_t localBuffer[12];
+	struct VL_RangingMeasurementData_t LastRangeDataBuffer;
+
+	LOG_FUNCTION_START("");
+
+	/*
+	 * use multi read even if some registers are not useful, result will
+	 * be more efficient
+	 * start reading at 0x14 dec20
+	 * end reading at 0x21 dec33 total 14 bytes to read
+	 */
+	Status = VL_ReadMulti(Dev, 0x14, localBuffer, 12);
+
+	if (Status == VL_ERROR_NONE) {
+
+		pRangingMeasurementData->ZoneId = 0; /* Only one zone */
+		pRangingMeasurementData->TimeStamp = 0; /* Not Implemented */
+
+		tmpuint16 = VL_MAKEUINT16(localBuffer[11],
+			localBuffer[10]);
+		/* cut1.1 if SYSTEM__RANGE_CONFIG if 1 range is 2bits fractional
+		 *(format 11.2) else no fractional
+		 */
+
+		pRangingMeasurementData->MeasurementTimeUsec = 0;
+
+		SignalRate = VL_FIXPOINT97TOFIXPOINT1616(
+			VL_MAKEUINT16(localBuffer[7], localBuffer[6]));
+		/* peak_signal_count_rate_rtn_mcps */
+		pRangingMeasurementData->SignalRateRtnMegaCps = SignalRate;
+
+		AmbientRate = VL_MAKEUINT16(localBuffer[9],
+			localBuffer[8]);
+		pRangingMeasurementData->AmbientRateRtnMegaCps =
+			VL_FIXPOINT97TOFIXPOINT1616(AmbientRate);
+
+		EffectiveSpadRtnCount = VL_MAKEUINT16(localBuffer[3],
+			localBuffer[2]);
+		/* EffectiveSpadRtnCount is 8.8 format */
+		pRangingMeasurementData->EffectiveSpadRtnCount =
+			EffectiveSpadRtnCount;
+
+		DeviceRangeStatus = localBuffer[0];
+
+		/* Get Linearity Corrective Gain */
+		LinearityCorrectiveGain = PALDevDataGet(Dev,
+			LinearityCorrectiveGain);
+
+		/* Get ranging configuration */
+		RangeFractionalEnable = PALDevDataGet(Dev,
+			RangeFractionalEnable);
+
+		if (LinearityCorrectiveGain != 1000) {
+
+			tmpuint16 = (uint16_t)((LinearityCorrectiveGain
+				* tmpuint16 + 500) / 1000);
+
+			/* Implement Xtalk */
+			VL_GETPARAMETERFIELD(Dev,
+				XTalkCompensationRateMegaCps,
+				XTalkCompensationRateMegaCps);
+			VL_GETPARAMETERFIELD(Dev, XTalkCompensationEnable,
+				XTalkCompensationEnable);
+
+			if (XTalkCompensationEnable) {
+
+				if ((SignalRate
+					- ((XTalkCompensationRateMegaCps
+					* EffectiveSpadRtnCount) >> 8))
+					<= 0) {
+					if (RangeFractionalEnable)
+						XtalkRangeMilliMeter = 8888;
+					else
+						XtalkRangeMilliMeter = 8888
+							<< 2;
+				} else {
+					XtalkRangeMilliMeter =
+					(tmpuint16 * SignalRate)
+						/ (SignalRate
+						- ((XTalkCompensationRateMegaCps
+						* EffectiveSpadRtnCount)
+						>> 8));
+				}
+
+				tmpuint16 = XtalkRangeMilliMeter;
+			}
+
+		}
+
+		if (RangeFractionalEnable) {
+			pRangingMeasurementData->RangeMilliMeter =
+				(uint16_t)((tmpuint16) >> 2);
+			pRangingMeasurementData->RangeFractionalPart =
+				(uint8_t)((tmpuint16 & 0x03) << 6);
+		} else {
+			pRangingMeasurementData->RangeMilliMeter = tmpuint16;
+			pRangingMeasurementData->RangeFractionalPart = 0;
+		}
+
+		/*
+		 * For a standard definition of RangeStatus, this should
+		 * return 0 in case of good result after a ranging
+		 * The range status depends on the device so call a device
+		 * specific function to obtain the right Status.
+		 */
+		Status |= VL_get_pal_range_status(Dev, DeviceRangeStatus,
+			SignalRate, EffectiveSpadRtnCount,
+			pRangingMeasurementData, &PalRangeStatus);
+
+		if (Status == VL_ERROR_NONE)
+			pRangingMeasurementData->RangeStatus = PalRangeStatus;
+
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		/* Copy last read data into Dev buffer */
+		LastRangeDataBuffer = PALDevDataGet(Dev, LastRangeMeasure);
+
+		LastRangeDataBuffer.RangeMilliMeter =
+			pRangingMeasurementData->RangeMilliMeter;
+		LastRangeDataBuffer.RangeFractionalPart =
+			pRangingMeasurementData->RangeFractionalPart;
+		LastRangeDataBuffer.RangeDMaxMilliMeter =
+			pRangingMeasurementData->RangeDMaxMilliMeter;
+		LastRangeDataBuffer.MeasurementTimeUsec =
+			pRangingMeasurementData->MeasurementTimeUsec;
+		LastRangeDataBuffer.SignalRateRtnMegaCps =
+			pRangingMeasurementData->SignalRateRtnMegaCps;
+		LastRangeDataBuffer.AmbientRateRtnMegaCps =
+			pRangingMeasurementData->AmbientRateRtnMegaCps;
+		LastRangeDataBuffer.EffectiveSpadRtnCount =
+			pRangingMeasurementData->EffectiveSpadRtnCount;
+		LastRangeDataBuffer.RangeStatus =
+			pRangingMeasurementData->RangeStatus;
+
+		PALDevDataSet(Dev, LastRangeMeasure, LastRangeDataBuffer);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetMeasurementRefSignal(struct vl_data *Dev,
+	unsigned int *pMeasurementRefSignal)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t SignalRefClipLimitCheckEnable = 0;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_GetLimitCheckEnable(Dev,
+			VL_CHECKENABLE_SIGNAL_REF_CLIP,
+			&SignalRefClipLimitCheckEnable);
+	if (SignalRefClipLimitCheckEnable != 0)
+		*pMeasurementRefSignal = PALDevDataGet(Dev, LastSignalRefMcps);
+	else
+		Status = VL_ERROR_INVALID_COMMAND;
+	LOG_FUNCTION_END(Status);
+
+	return Status;
+}
+
+int8_t VL_GetHistogramMeasurementData(struct vl_data *Dev,
+	struct VL_HistogramMeasurementData_t *pHistogramMeasurementData)
+{
+	int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+	LOG_FUNCTION_START("");
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_PerformSingleRangingMeasurement(struct vl_data *Dev,
+	struct VL_RangingMeasurementData_t *pRangingMeasurementData)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	/* This function will do a complete single ranging */
+	/* Here we fix the mode! */
+	Status = VL_SetDeviceMode(Dev, VL_DEVICEMODE_SINGLE_RANGING);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_PerformSingleMeasurement(Dev);
+
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_GetRangingMeasurementData(Dev,
+			pRangingMeasurementData);
+
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_ClearInterruptMask(Dev, 0);
+
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetNumberOfROIZones(struct vl_data *Dev,
+	uint8_t NumberOfROIZones)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	if (NumberOfROIZones != 1)
+		Status = VL_ERROR_INVALID_PARAMS;
+
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetNumberOfROIZones(struct vl_data *Dev,
+	uint8_t *pNumberOfROIZones)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	*pNumberOfROIZones = 1;
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetMaxNumberOfROIZones(struct vl_data *Dev,
+	uint8_t *pMaxNumberOfROIZones)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	*pMaxNumberOfROIZones = 1;
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+/* End Group PAL Measurement Functions */
+
+int8_t VL_SetGpioConfig(struct vl_data *Dev, uint8_t Pin,
+	uint8_t DeviceMode, uint8_t Functionality,
+	uint8_t Polarity)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t data;
+
+	LOG_FUNCTION_START("");
+
+	if (Pin != 0) {
+		Status = VL_ERROR_GPIO_NOT_EXISTING;
+	} else if (DeviceMode == VL_DEVICEMODE_GPIO_DRIVE) {
+		if (Polarity == VL_INTERRUPTPOLARITY_LOW)
+			data = 0x10;
+		else
+			data = 1;
+
+		Status = VL_WrByte(Dev,
+		VL_REG_GPIO_HV_MUX_ACTIVE_HIGH, data);
+
+	} else if (DeviceMode == VL_DEVICEMODE_GPIO_OSC) {
+
+		Status |= VL_WrByte(Dev, 0xff, 0x01);
+		Status |= VL_WrByte(Dev, 0x00, 0x00);
+
+		Status |= VL_WrByte(Dev, 0xff, 0x00);
+		Status |= VL_WrByte(Dev, 0x80, 0x01);
+		Status |= VL_WrByte(Dev, 0x85, 0x02);
+
+		Status |= VL_WrByte(Dev, 0xff, 0x04);
+		Status |= VL_WrByte(Dev, 0xcd, 0x00);
+		Status |= VL_WrByte(Dev, 0xcc, 0x11);
+
+		Status |= VL_WrByte(Dev, 0xff, 0x07);
+		Status |= VL_WrByte(Dev, 0xbe, 0x00);
+
+		Status |= VL_WrByte(Dev, 0xff, 0x06);
+		Status |= VL_WrByte(Dev, 0xcc, 0x09);
+
+		Status |= VL_WrByte(Dev, 0xff, 0x00);
+		Status |= VL_WrByte(Dev, 0xff, 0x01);
+		Status |= VL_WrByte(Dev, 0x00, 0x00);
+
+	} else {
+
+		if (Status == VL_ERROR_NONE) {
+			switch (Functionality) {
+			case VL_GPIOFUNCTIONALITY_OFF:
+				data = 0x00;
+				break;
+			case VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW:
+				data = 0x01;
+				break;
+			case VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH:
+				data = 0x02;
+				break;
+			case VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT:
+				data = 0x03;
+				break;
+			case VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY:
+				data = 0x04;
+				break;
+			default:
+				Status =
+				VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED;
+			}
+		}
+
+		if (Status == VL_ERROR_NONE)
+			Status = VL_WrByte(Dev,
+			VL_REG_SYSTEM_INTERRUPT_CONFIG_GPIO, data);
+
+		if (Status == VL_ERROR_NONE) {
+			if (Polarity == VL_INTERRUPTPOLARITY_LOW)
+				data = 0;
+			else
+				data = (uint8_t)(1 << 4);
+
+			Status = VL_UpdateByte(Dev,
+			VL_REG_GPIO_HV_MUX_ACTIVE_HIGH, 0xEF, data);
+		}
+
+		if (Status == VL_ERROR_NONE)
+			VL_SETDEVICESPECIFICPARAMETER(Dev,
+				Pin0GpioFunctionality, Functionality);
+
+		if (Status == VL_ERROR_NONE)
+			Status = VL_ClearInterruptMask(Dev, 0);
+
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetGpioConfig(struct vl_data *Dev, uint8_t Pin,
+	uint8_t *pDeviceMode,
+	uint8_t *pFunctionality,
+	uint8_t *pPolarity)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t GpioFunctionality;
+	uint8_t data;
+
+	LOG_FUNCTION_START("");
+
+	/* pDeviceMode not managed by Ewok it return the current mode */
+
+	Status = VL_GetDeviceMode(Dev, pDeviceMode);
+
+	if (Status == VL_ERROR_NONE) {
+		if (Pin != 0) {
+			Status = VL_ERROR_GPIO_NOT_EXISTING;
+		} else {
+			Status = VL_RdByte(Dev,
+			VL_REG_SYSTEM_INTERRUPT_CONFIG_GPIO, &data);
+		}
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		switch (data & 0x07) {
+		case 0x00:
+			GpioFunctionality = VL_GPIOFUNCTIONALITY_OFF;
+			break;
+		case 0x01:
+			GpioFunctionality =
+			VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW;
+			break;
+		case 0x02:
+			GpioFunctionality =
+			VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH;
+			break;
+		case 0x03:
+			GpioFunctionality =
+			VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT;
+			break;
+		case 0x04:
+			GpioFunctionality =
+			VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY;
+			break;
+		default:
+			Status = VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED;
+		}
+	}
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_RdByte(Dev,
+			VL_REG_GPIO_HV_MUX_ACTIVE_HIGH, &data);
+
+	if (Status == VL_ERROR_NONE) {
+		if ((data & (uint8_t)(1 << 4)) == 0)
+			*pPolarity = VL_INTERRUPTPOLARITY_LOW;
+		else
+			*pPolarity = VL_INTERRUPTPOLARITY_HIGH;
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		*pFunctionality = GpioFunctionality;
+		VL_SETDEVICESPECIFICPARAMETER(Dev, Pin0GpioFunctionality,
+			GpioFunctionality);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetInterruptThresholds(struct vl_data *Dev,
+	uint8_t DeviceMode, unsigned int ThresholdLow,
+	unsigned int ThresholdHigh)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint16_t Threshold16;
+
+	LOG_FUNCTION_START("");
+
+	/* no dependency on DeviceMode for Ewok */
+	/* Need to divide by 2 because the FW will apply a x2 */
+	Threshold16 = (uint16_t)((ThresholdLow >> 17) & 0x00fff);
+	Status = VL_WrWord(Dev, VL_REG_SYSTEM_THRESH_LOW,
+		Threshold16);
+
+	if (Status == VL_ERROR_NONE) {
+		/* Need to divide by 2 because the FW will apply a x2 */
+		Threshold16 = (uint16_t)((ThresholdHigh >> 17) & 0x00fff);
+		Status = VL_WrWord(Dev, VL_REG_SYSTEM_THRESH_HIGH,
+			Threshold16);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetInterruptThresholds(struct vl_data *Dev,
+	uint8_t DeviceMode, unsigned int *pThresholdLow,
+	unsigned int *pThresholdHigh)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint16_t Threshold16;
+
+	LOG_FUNCTION_START("");
+
+	/* no dependency on DeviceMode for Ewok */
+
+	Status = VL_RdWord(Dev, VL_REG_SYSTEM_THRESH_LOW,
+		&Threshold16);
+	/* Need to multiply by 2 because the FW will apply a x2 */
+	*pThresholdLow = (unsigned int)((0x00fff & Threshold16) << 17);
+
+	if (Status == VL_ERROR_NONE) {
+		Status = VL_RdWord(Dev, VL_REG_SYSTEM_THRESH_HIGH,
+			&Threshold16);
+		/* Need to multiply by 2 because the FW will apply a x2 */
+		*pThresholdHigh =
+			(unsigned int)((0x00fff & Threshold16) << 17);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetStopCompletedStatus(struct vl_data *Dev,
+	uint32_t *pStopStatus)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t Byte = 0;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_WrByte(Dev, 0xFF, 0x01);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_RdByte(Dev, 0x04, &Byte);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_WrByte(Dev, 0xFF, 0x0);
+
+	*pStopStatus = Byte;
+
+	if (Byte == 0) {
+		Status = VL_WrByte(Dev, 0x80, 0x01);
+		Status = VL_WrByte(Dev, 0xFF, 0x01);
+		Status = VL_WrByte(Dev, 0x00, 0x00);
+		Status = VL_WrByte(Dev, 0x91,
+			PALDevDataGet(Dev, StopVariable));
+		Status = VL_WrByte(Dev, 0x00, 0x01);
+		Status = VL_WrByte(Dev, 0xFF, 0x00);
+		Status = VL_WrByte(Dev, 0x80, 0x00);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+/* Group PAL Interrupt Functions */
+int8_t VL_ClearInterruptMask(struct vl_data *Dev,
+	uint32_t InterruptMask)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t LoopCount;
+	uint8_t Byte;
+
+	LOG_FUNCTION_START("");
+
+	/* clear bit 0 range interrupt, bit 1 error interrupt */
+	LoopCount = 0;
+	do {
+		Status = VL_WrByte(Dev,
+			VL_REG_SYSTEM_INTERRUPT_CLEAR, 0x01);
+		Status |= VL_WrByte(Dev,
+			VL_REG_SYSTEM_INTERRUPT_CLEAR, 0x00);
+		Status |= VL_RdByte(Dev,
+			VL_REG_RESULT_INTERRUPT_STATUS, &Byte);
+		LoopCount++;
+	} while (((Byte & 0x07) != 0x00)
+			&& (LoopCount < 3)
+			&& (Status == VL_ERROR_NONE));
+
+
+	if (LoopCount >= 3)
+		Status = VL_ERROR_INTERRUPT_NOT_CLEARED;
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetInterruptMaskStatus(struct vl_data *Dev,
+	uint32_t *pInterruptMaskStatus)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t Byte;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_RdByte(Dev, VL_REG_RESULT_INTERRUPT_STATUS,
+		&Byte);
+	*pInterruptMaskStatus = Byte & 0x07;
+
+	if (Byte & 0x18)
+		Status = VL_ERROR_RANGE_ERROR;
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_EnableInterruptMask(struct vl_data *Dev,
+	uint32_t InterruptMask)
+{
+	int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+	LOG_FUNCTION_START("");
+
+	/* not implemented for VL53L0X */
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+/* End Group PAL Interrupt Functions */
+
+/* Group SPAD functions */
+
+int8_t VL_SetSpadAmbientDamperThreshold(struct vl_data *Dev,
+	uint16_t SpadAmbientDamperThreshold)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_WrByte(Dev, 0xFF, 0x01);
+	Status |= VL_WrWord(Dev, 0x40, SpadAmbientDamperThreshold);
+	Status |= VL_WrByte(Dev, 0xFF, 0x00);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetSpadAmbientDamperThreshold(struct vl_data *Dev,
+	uint16_t *pSpadAmbientDamperThreshold)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_WrByte(Dev, 0xFF, 0x01);
+	Status |= VL_RdWord(Dev, 0x40, pSpadAmbientDamperThreshold);
+	Status |= VL_WrByte(Dev, 0xFF, 0x00);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_SetSpadAmbientDamperFactor(struct vl_data *Dev,
+	uint16_t SpadAmbientDamperFactor)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t Byte;
+
+	LOG_FUNCTION_START("");
+
+	Byte = (uint8_t)(SpadAmbientDamperFactor & 0x00FF);
+
+	Status = VL_WrByte(Dev, 0xFF, 0x01);
+	Status |= VL_WrByte(Dev, 0x42, Byte);
+	Status |= VL_WrByte(Dev, 0xFF, 0x00);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_GetSpadAmbientDamperFactor(struct vl_data *Dev,
+	uint16_t *pSpadAmbientDamperFactor)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t Byte;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_WrByte(Dev, 0xFF, 0x01);
+	Status |= VL_RdByte(Dev, 0x42, &Byte);
+	Status |= VL_WrByte(Dev, 0xFF, 0x00);
+	*pSpadAmbientDamperFactor = (uint16_t)Byte;
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+/* END Group SPAD functions */
+
+/*****************************************************************************
+ * Internal functions
+ *****************************************************************************/
+
+int8_t VL_SetReferenceSpads(struct vl_data *Dev, uint32_t count,
+	uint8_t isApertureSpads)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_set_reference_spads(Dev, count, isApertureSpads);
+
+	LOG_FUNCTION_END(Status);
+
+	return Status;
+}
+
+int8_t VL_GetReferenceSpads(struct vl_data *Dev, uint32_t *pSpadCount,
+	uint8_t *pIsApertureSpads)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_get_reference_spads(Dev, pSpadCount, pIsApertureSpads);
+
+	LOG_FUNCTION_END(Status);
+
+	return Status;
+}
+
+int8_t VL_PerformRefSpadManagement(struct vl_data *Dev,
+	uint32_t *refSpadCount, uint8_t *isApertureSpads)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_perform_ref_spad_management(Dev, refSpadCount,
+		isApertureSpads);
+
+	LOG_FUNCTION_END(Status);
+
+	return Status;
+}
diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api_calibration.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api_calibration.c
new file mode 100644
index 0000000..08b5ce2
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api_calibration.c
@@ -0,0 +1,1266 @@
+/*
+ *  vl53l0x_api_calibration.c - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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 "vl53l0x_api.h"
+#include "vl53l0x_api_core.h"
+#include "vl53l0x_api_calibration.h"
+
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
+
+#define LOG_FUNCTION_START(fmt, ...) \
+	_LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+	_LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
+	_LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
+
+#define REF_ARRAY_SPAD_0  0
+#define REF_ARRAY_SPAD_5  5
+#define REF_ARRAY_SPAD_10 10
+
+uint32_t refArrayQuadrants[4] = {REF_ARRAY_SPAD_10, REF_ARRAY_SPAD_5,
+		REF_ARRAY_SPAD_0, REF_ARRAY_SPAD_5 };
+
+int8_t VL_perform_xtalk_calibration(struct vl_data *Dev,
+			unsigned int XTalkCalDistance,
+			unsigned int *pXTalkCompensationRateMegaCps)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint16_t sum_ranging = 0;
+	uint16_t sum_spads = 0;
+	unsigned int sum_signalRate = 0;
+	unsigned int total_count = 0;
+	uint8_t xtalk_meas = 0;
+	struct VL_RangingMeasurementData_t RangingMeasurementData;
+	unsigned int xTalkStoredMeanSignalRate;
+	unsigned int xTalkStoredMeanRange;
+	unsigned int xTalkStoredMeanRtnSpads;
+	uint32_t signalXTalkTotalPerSpad;
+	uint32_t xTalkStoredMeanRtnSpadsAsInt;
+	uint32_t xTalkCalDistanceAsInt;
+	unsigned int XTalkCompensationRateMegaCps;
+
+	if (XTalkCalDistance <= 0)
+		Status = VL_ERROR_INVALID_PARAMS;
+
+	/* Disable the XTalk compensation */
+	if (Status == VL_ERROR_NONE)
+		Status = VL_SetXTalkCompensationEnable(Dev, 0);
+
+	/* Disable the RIT */
+	if (Status == VL_ERROR_NONE) {
+		Status = VL_SetLimitCheckEnable(Dev,
+				VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0);
+	}
+
+	/* Perform 50 measurements and compute the averages */
+	if (Status == VL_ERROR_NONE) {
+		sum_ranging = 0;
+		sum_spads = 0;
+		sum_signalRate = 0;
+		total_count = 0;
+		for (xtalk_meas = 0; xtalk_meas < 50; xtalk_meas++) {
+			Status = VL_PerformSingleRangingMeasurement(Dev,
+				&RangingMeasurementData);
+
+			if (Status != VL_ERROR_NONE)
+				break;
+
+			/* The range is valid when RangeStatus = 0 */
+			if (RangingMeasurementData.RangeStatus == 0) {
+				sum_ranging = sum_ranging +
+					RangingMeasurementData.RangeMilliMeter;
+				sum_signalRate = sum_signalRate +
+				RangingMeasurementData.SignalRateRtnMegaCps;
+				sum_spads = sum_spads +
+				RangingMeasurementData.EffectiveSpadRtnCount
+					/ 256;
+				total_count = total_count + 1;
+			}
+		}
+
+		/* no valid values found */
+		if (total_count == 0)
+			Status = VL_ERROR_RANGE_ERROR;
+
+	}
+
+
+	if (Status == VL_ERROR_NONE) {
+		/* unsigned int / uint16_t = unsigned int */
+		xTalkStoredMeanSignalRate = sum_signalRate / total_count;
+		xTalkStoredMeanRange = (unsigned int)((uint32_t)(
+			sum_ranging << 16) / total_count);
+		xTalkStoredMeanRtnSpads = (unsigned int)((uint32_t)(
+			sum_spads << 16) / total_count);
+
+		/* Round Mean Spads to Whole Number.
+		 * Typically the calculated mean SPAD count is a whole number
+		 * or very close to a whole
+		 * number, therefore any truncation will not result in a
+		 * significant loss in accuracy.
+		 * Also, for a grey target at a typical distance of around
+		 * 400mm, around 220 SPADs will
+		 * be enabled, therefore, any truncation will result in a loss
+		 * of accuracy of less than
+		 * 0.5%.
+		 */
+		xTalkStoredMeanRtnSpadsAsInt = (xTalkStoredMeanRtnSpads +
+			0x8000) >> 16;
+
+		/* Round Cal Distance to Whole Number. */
+		/* Note that the cal distance is in mm, */
+		/* therefore no resolution is lost.*/
+		 xTalkCalDistanceAsInt = (XTalkCalDistance + 0x8000) >> 16;
+
+		if (xTalkStoredMeanRtnSpadsAsInt == 0 ||
+		   xTalkCalDistanceAsInt == 0 ||
+		   xTalkStoredMeanRange >= XTalkCalDistance) {
+			XTalkCompensationRateMegaCps = 0;
+		} else {
+			/* Round Cal Distance to Whole Number. */
+			/* Note that the cal distance is in mm, therefore no */
+			/* resolution is lost.*/
+			xTalkCalDistanceAsInt = (XTalkCalDistance +
+				0x8000) >> 16;
+
+			/* Apply division by mean spad count early in the */
+			/* calculation to keep the numbers small. */
+			/* This ensures we can maintain a 32bit calculation. */
+			/* Fixed1616 / int := Fixed1616 */
+			signalXTalkTotalPerSpad = (xTalkStoredMeanSignalRate) /
+				xTalkStoredMeanRtnSpadsAsInt;
+
+			/* Complete the calculation for total Signal */
+			/* XTalk per SPAD */
+			/* Fixed1616 * (Fixed1616 - Fixed1616/int) := */
+			/* (2^16 * Fixed1616) */
+
+			signalXTalkTotalPerSpad *= ((1 << 16) -
+				(xTalkStoredMeanRange / xTalkCalDistanceAsInt));
+
+			/* Round from 2^16 * Fixed1616, to Fixed1616. */
+			XTalkCompensationRateMegaCps = (signalXTalkTotalPerSpad
+				+ 0x8000) >> 16;
+		}
+
+		*pXTalkCompensationRateMegaCps = XTalkCompensationRateMegaCps;
+
+		/* Enable the XTalk compensation */
+		if (Status == VL_ERROR_NONE)
+			Status = VL_SetXTalkCompensationEnable(Dev, 1);
+
+		/* Enable the XTalk compensation */
+		if (Status == VL_ERROR_NONE)
+			Status = VL_SetXTalkCompensationRateMegaCps(Dev,
+					XTalkCompensationRateMegaCps);
+
+	}
+
+	return Status;
+}
+
+int8_t VL_perform_offset_calibration(struct vl_data *Dev,
+			unsigned int CalDistanceMilliMeter,
+			int32_t *pOffsetMicroMeter)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint16_t sum_ranging = 0;
+	unsigned int total_count = 0;
+	struct VL_RangingMeasurementData_t RangingMeasurementData;
+	unsigned int StoredMeanRange;
+	uint32_t StoredMeanRangeAsInt;
+	uint32_t CalDistanceAsInt_mm;
+	uint8_t SequenceStepEnabled;
+	int meas = 0;
+
+	if (CalDistanceMilliMeter <= 0)
+		Status = VL_ERROR_INVALID_PARAMS;
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_SetOffsetCalibrationDataMicroMeter(Dev, 0);
+
+
+	/* Get the value of the TCC */
+	if (Status == VL_ERROR_NONE)
+		Status = VL_GetSequenceStepEnable(Dev,
+				VL_SEQUENCESTEP_TCC, &SequenceStepEnabled);
+
+
+	/* Disable the TCC */
+	if (Status == VL_ERROR_NONE)
+		Status = VL_SetSequenceStepEnable(Dev,
+				VL_SEQUENCESTEP_TCC, 0);
+
+
+	/* Disable the RIT */
+	if (Status == VL_ERROR_NONE)
+		Status = VL_SetLimitCheckEnable(Dev,
+				VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0);
+
+	/* Perform 50 measurements and compute the averages */
+	if (Status == VL_ERROR_NONE) {
+		sum_ranging = 0;
+		total_count = 0;
+		for (meas = 0; meas < 50; meas++) {
+			Status = VL_PerformSingleRangingMeasurement(Dev,
+					&RangingMeasurementData);
+
+			if (Status != VL_ERROR_NONE)
+				break;
+
+			/* The range is valid when RangeStatus = 0 */
+			if (RangingMeasurementData.RangeStatus == 0) {
+				sum_ranging = sum_ranging +
+					RangingMeasurementData.RangeMilliMeter;
+				total_count = total_count + 1;
+			}
+		}
+
+		/* no valid values found */
+		if (total_count == 0)
+			Status = VL_ERROR_RANGE_ERROR;
+	}
+
+
+	if (Status == VL_ERROR_NONE) {
+		/* unsigned int / uint16_t = unsigned int */
+		StoredMeanRange = (unsigned int)((uint32_t)(sum_ranging << 16)
+			/ total_count);
+
+		StoredMeanRangeAsInt = (StoredMeanRange + 0x8000) >> 16;
+
+		/* Round Cal Distance to Whole Number. */
+		/* Note that the cal distance is in mm, */
+		/* therefore no resolution is lost.*/
+		 CalDistanceAsInt_mm = (CalDistanceMilliMeter + 0x8000) >> 16;
+
+		 *pOffsetMicroMeter = (CalDistanceAsInt_mm -
+				 StoredMeanRangeAsInt) * 1000;
+
+		/* Apply the calculated offset */
+		if (Status == VL_ERROR_NONE) {
+			VL_SETPARAMETERFIELD(Dev, RangeOffsetMicroMeters,
+					*pOffsetMicroMeter);
+			Status = VL_SetOffsetCalibrationDataMicroMeter(Dev,
+					*pOffsetMicroMeter);
+		}
+
+	}
+
+	/* Restore the TCC */
+	if (Status == VL_ERROR_NONE) {
+		if (SequenceStepEnabled != 0)
+			Status = VL_SetSequenceStepEnable(Dev,
+					VL_SEQUENCESTEP_TCC, 1);
+	}
+
+	return Status;
+}
+
+
+int8_t VL_set_offset_calibration_data_micro_meter(struct vl_data *Dev,
+		int32_t OffsetCalibrationDataMicroMeter)
+{
+	int8_t Status = VL_ERROR_NONE;
+	int32_t cMaxOffsetMicroMeter = 511000;
+	int32_t cMinOffsetMicroMeter = -512000;
+	int16_t cOffsetRange = 4096;
+	uint32_t encodedOffsetVal;
+
+	LOG_FUNCTION_START("");
+
+	if (OffsetCalibrationDataMicroMeter > cMaxOffsetMicroMeter)
+		OffsetCalibrationDataMicroMeter = cMaxOffsetMicroMeter;
+	else if (OffsetCalibrationDataMicroMeter < cMinOffsetMicroMeter)
+		OffsetCalibrationDataMicroMeter = cMinOffsetMicroMeter;
+
+	/* The offset register is 10.2 format and units are mm
+	 * therefore conversion is applied by a division of
+	 * 250.
+	 */
+	if (OffsetCalibrationDataMicroMeter >= 0) {
+		encodedOffsetVal =
+			OffsetCalibrationDataMicroMeter/250;
+	} else {
+		encodedOffsetVal =
+			cOffsetRange +
+			OffsetCalibrationDataMicroMeter/250;
+	}
+
+	Status = VL_WrWord(Dev,
+		VL_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM,
+		encodedOffsetVal);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_get_offset_calibration_data_micro_meter(struct vl_data *Dev,
+		int32_t *pOffsetCalibrationDataMicroMeter)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint16_t RangeOffsetRegister;
+	int16_t cMaxOffset = 2047;
+	int16_t cOffsetRange = 4096;
+
+	/* Note that offset has 10.2 format */
+
+	Status = VL_RdWord(Dev,
+				VL_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM,
+				&RangeOffsetRegister);
+
+	if (Status == VL_ERROR_NONE) {
+		RangeOffsetRegister = (RangeOffsetRegister & 0x0fff);
+
+		/* Apply 12 bit 2's compliment conversion */
+		if (RangeOffsetRegister > cMaxOffset)
+			*pOffsetCalibrationDataMicroMeter =
+				(int16_t)(RangeOffsetRegister - cOffsetRange)
+					* 250;
+		else
+			*pOffsetCalibrationDataMicroMeter =
+				(int16_t)RangeOffsetRegister * 250;
+
+	}
+
+	return Status;
+}
+
+
+int8_t VL_apply_offset_adjustment(struct vl_data *Dev)
+{
+	int8_t Status = VL_ERROR_NONE;
+	int32_t CorrectedOffsetMicroMeters;
+	int32_t CurrentOffsetMicroMeters;
+
+	/* if we run on this function we can read all the NVM info */
+	/* used by the API */
+	Status = VL_get_info_from_device(Dev, 7);
+
+	/* Read back current device offset */
+	if (Status == VL_ERROR_NONE) {
+		Status = VL_GetOffsetCalibrationDataMicroMeter(Dev,
+					&CurrentOffsetMicroMeters);
+	}
+
+	/* Apply Offset Adjustment derived from 400mm measurements */
+	if (Status == VL_ERROR_NONE) {
+
+		/* Store initial device offset */
+		PALDevDataSet(Dev, Part2PartOffsetNVMMicroMeter,
+			CurrentOffsetMicroMeters);
+
+		CorrectedOffsetMicroMeters = CurrentOffsetMicroMeters +
+			(int32_t)PALDevDataGet(Dev,
+				Part2PartOffsetAdjustmentNVMMicroMeter);
+
+		Status = VL_SetOffsetCalibrationDataMicroMeter(Dev,
+					CorrectedOffsetMicroMeters);
+
+		/* store current, adjusted offset */
+		if (Status == VL_ERROR_NONE) {
+			VL_SETPARAMETERFIELD(Dev, RangeOffsetMicroMeters,
+					CorrectedOffsetMicroMeters);
+		}
+	}
+
+	return Status;
+}
+
+void get_next_good_spad(uint8_t goodSpadArray[], uint32_t size,
+			uint32_t curr, int32_t *next)
+{
+	uint32_t startIndex;
+	uint32_t fineOffset;
+	uint32_t cSpadsPerByte = 8;
+	uint32_t coarseIndex;
+	uint32_t fineIndex;
+	uint8_t dataByte;
+	uint8_t success = 0;
+
+	/*
+	 * Starting with the current good spad, loop through the array to find
+	 * the next. i.e. the next bit set in the sequence.
+	 *
+	 * The coarse index is the byte index of the array and the fine index is
+	 * the index of the bit within each byte.
+	 */
+
+	*next = -1;
+
+	startIndex = curr / cSpadsPerByte;
+	fineOffset = curr % cSpadsPerByte;
+
+	for (coarseIndex = startIndex; ((coarseIndex < size) && !success);
+				coarseIndex++) {
+		fineIndex = 0;
+		dataByte = goodSpadArray[coarseIndex];
+
+		if (coarseIndex == startIndex) {
+			/* locate the bit position of the provided current */
+			/* spad bit before iterating */
+			dataByte >>= fineOffset;
+			fineIndex = fineOffset;
+		}
+
+		while (fineIndex < cSpadsPerByte) {
+			if ((dataByte & 0x1) == 1) {
+				success = 1;
+				*next = coarseIndex * cSpadsPerByte + fineIndex;
+				break;
+			}
+			dataByte >>= 1;
+			fineIndex++;
+		}
+	}
+}
+
+
+uint8_t is_aperture(uint32_t spadIndex)
+{
+	/*
+	 * This function reports if a given spad index is an aperture SPAD by
+	 * deriving the quadrant.
+	 */
+	uint32_t quadrant;
+	uint8_t isAperture = 1;
+
+	quadrant = spadIndex >> 6;
+	if (refArrayQuadrants[quadrant] == REF_ARRAY_SPAD_0)
+		isAperture = 0;
+
+	return isAperture;
+}
+
+
+int8_t enable_spad_bit(uint8_t spadArray[], uint32_t size,
+	uint32_t spadIndex)
+{
+	int8_t status = VL_ERROR_NONE;
+	uint32_t cSpadsPerByte = 8;
+	uint32_t coarseIndex;
+	uint32_t fineIndex;
+
+	coarseIndex = spadIndex / cSpadsPerByte;
+	fineIndex = spadIndex % cSpadsPerByte;
+	if (coarseIndex >= size)
+		status = VL_ERROR_REF_SPAD_INIT;
+	else
+		spadArray[coarseIndex] |= (1 << fineIndex);
+
+	return status;
+}
+
+int8_t count_enabled_spads(uint8_t spadArray[],
+		uint32_t byteCount, uint32_t maxSpads,
+		uint32_t *pTotalSpadsEnabled, uint8_t *pIsAperture)
+{
+	int8_t status = VL_ERROR_NONE;
+	uint32_t cSpadsPerByte = 8;
+	uint32_t lastByte;
+	uint32_t lastBit;
+	uint32_t byteIndex = 0;
+	uint32_t bitIndex = 0;
+	uint8_t tempByte;
+	uint8_t spadTypeIdentified = 0;
+
+	/* The entire array will not be used for spads, therefore the last
+	 * byte and last bit is determined from the max spads value.
+	 */
+
+	lastByte = maxSpads / cSpadsPerByte;
+	lastBit = maxSpads % cSpadsPerByte;
+
+	/* Check that the max spads value does not exceed the array bounds. */
+	if (lastByte >= byteCount)
+		status = VL_ERROR_REF_SPAD_INIT;
+
+	*pTotalSpadsEnabled = 0;
+
+	/* Count the bits enabled in the whole bytes */
+	for (byteIndex = 0; byteIndex <= (lastByte - 1); byteIndex++) {
+		tempByte = spadArray[byteIndex];
+
+		for (bitIndex = 0; bitIndex <= cSpadsPerByte; bitIndex++) {
+			if ((tempByte & 0x01) == 1) {
+				(*pTotalSpadsEnabled)++;
+				if (!spadTypeIdentified) {
+					*pIsAperture = 1;
+					if ((byteIndex < 2) && (bitIndex < 4))
+						*pIsAperture = 0;
+						spadTypeIdentified = 1;
+				}
+			}
+			tempByte >>= 1;
+		}
+	}
+
+	/* Count the number of bits enabled in the last byte accounting
+	 * for the fact that not all bits in the byte may be used.
+	 */
+	tempByte = spadArray[lastByte];
+
+	for (bitIndex = 0; bitIndex <= lastBit; bitIndex++) {
+		if ((tempByte & 0x01) == 1)
+			(*pTotalSpadsEnabled)++;
+	}
+
+	return status;
+}
+
+int8_t set_ref_spad_map(struct vl_data *Dev, uint8_t *refSpadArray)
+{
+	int8_t status = VL_WriteMulti(Dev,
+				VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0,
+				refSpadArray, 6);
+	return status;
+}
+
+int8_t get_ref_spad_map(struct vl_data *Dev, uint8_t *refSpadArray)
+{
+	int8_t status = VL_ReadMulti(Dev,
+				VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0,
+				refSpadArray,
+				6);
+	return status;
+}
+
+int8_t enable_ref_spads(struct vl_data *Dev,
+				uint8_t apertureSpads,
+				uint8_t goodSpadArray[],
+				uint8_t spadArray[],
+				uint32_t size,
+				uint32_t start,
+				uint32_t offset,
+				uint32_t spadCount,
+				uint32_t *lastSpad)
+{
+	int8_t status = VL_ERROR_NONE;
+	uint32_t index;
+	uint32_t i;
+	int32_t nextGoodSpad = offset;
+	uint32_t currentSpad;
+	uint8_t checkSpadArray[6];
+
+	/*
+	 * This function takes in a spad array which may or may not have SPADS
+	 * already enabled and appends from a given offset a requested number
+	 * of new SPAD enables. The 'good spad map' is applied to
+	 * determine the next SPADs to enable.
+	 *
+	 * This function applies to only aperture or only non-aperture spads.
+	 * Checks are performed to ensure this.
+	 */
+
+	currentSpad = offset;
+	for (index = 0; index < spadCount; index++) {
+		get_next_good_spad(goodSpadArray, size, currentSpad,
+			&nextGoodSpad);
+
+		if (nextGoodSpad == -1) {
+			status = VL_ERROR_REF_SPAD_INIT;
+			break;
+		}
+
+		/* Confirm that the next good SPAD is non-aperture */
+		if (is_aperture(start + nextGoodSpad) != apertureSpads) {
+			/* if we can't get the required number of good aperture
+			 * spads from the current quadrant then this is an error
+			 */
+			status = VL_ERROR_REF_SPAD_INIT;
+			break;
+		}
+		currentSpad = (uint32_t)nextGoodSpad;
+		enable_spad_bit(spadArray, size, currentSpad);
+		currentSpad++;
+	}
+	*lastSpad = currentSpad;
+
+	if (status == VL_ERROR_NONE)
+		status = set_ref_spad_map(Dev, spadArray);
+
+
+	if (status == VL_ERROR_NONE) {
+		status = get_ref_spad_map(Dev, checkSpadArray);
+
+		i = 0;
+
+		/* Compare spad maps. If not equal report error. */
+		while (i < size) {
+			if (spadArray[i] != checkSpadArray[i]) {
+				status = VL_ERROR_REF_SPAD_INIT;
+				break;
+			}
+			i++;
+		}
+	}
+	return status;
+}
+
+
+int8_t perform_ref_signal_measurement(struct vl_data *Dev,
+		uint16_t *refSignalRate)
+{
+	int8_t status = VL_ERROR_NONE;
+	struct VL_RangingMeasurementData_t rangingMeasurementData;
+
+	uint8_t SequenceConfig = 0;
+
+	/* store the value of the sequence config,
+	 * this will be reset before the end of the function
+	 */
+
+	SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
+
+	/*
+	 * This function performs a reference signal rate measurement.
+	 */
+	if (status == VL_ERROR_NONE)
+		status = VL_WrByte(Dev,
+			VL_REG_SYSTEM_SEQUENCE_CONFIG, 0xC0);
+
+	if (status == VL_ERROR_NONE)
+		status = VL_PerformSingleRangingMeasurement(Dev,
+				&rangingMeasurementData);
+
+	if (status == VL_ERROR_NONE)
+		status = VL_WrByte(Dev, 0xFF, 0x01);
+
+	if (status == VL_ERROR_NONE)
+		status = VL_RdWord(Dev,
+			VL_REG_RESULT_PEAK_SIGNAL_RATE_REF,
+			refSignalRate);
+
+	if (status == VL_ERROR_NONE)
+		status = VL_WrByte(Dev, 0xFF, 0x00);
+
+	if (status == VL_ERROR_NONE) {
+		/* restore the previous Sequence Config */
+		status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG,
+				SequenceConfig);
+		if (status == VL_ERROR_NONE)
+			PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
+	}
+
+	return status;
+}
+
+int8_t VL_perform_ref_spad_management(struct vl_data *Dev,
+				uint32_t *refSpadCount,
+				uint8_t *isApertureSpads)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t lastSpadArray[6];
+	uint8_t startSelect = 0xB4;
+	uint32_t minimumSpadCount = 3;
+	uint32_t maxSpadCount = 44;
+	uint32_t currentSpadIndex = 0;
+	uint32_t lastSpadIndex = 0;
+	int32_t nextGoodSpad = 0;
+	uint16_t targetRefRate = 0x0A00; /* 20 MCPS in 9:7 format */
+	uint16_t peakSignalRateRef;
+	uint32_t needAptSpads = 0;
+	uint32_t index = 0;
+	uint32_t spadArraySize = 6;
+	uint32_t signalRateDiff = 0;
+	uint32_t lastSignalRateDiff = 0;
+	uint8_t complete = 0;
+	uint8_t VhvSettings = 0;
+	uint8_t PhaseCal = 0;
+	uint32_t refSpadCount_int = 0;
+	uint8_t	 isApertureSpads_int = 0;
+
+	/*
+	 * The reference SPAD initialization procedure determines the minimum
+	 * amount of reference spads to be enables to achieve a target reference
+	 * signal rate and should be performed once during initialization.
+	 *
+	 * Either aperture or non-aperture spads are applied but never both.
+	 * Firstly non-aperture spads are set, beginning with 5 spads, and
+	 * increased one spad at a time until the closest measurement to the
+	 * target rate is achieved.
+	 *
+	 * If the target rate is exceeded when 5 non-aperture spads are enabled,
+	 * initialization is performed instead with aperture spads.
+	 *
+	 * When setting spads, a 'Good Spad Map' is applied.
+	 *
+	 * This procedure operates within a SPAD window of interest of a maximum
+	 * 44 spads.
+	 * The start point is currently fixed to 180, which lies towards the end
+	 * of the non-aperture quadrant and runs in to the adjacent aperture
+	 * quadrant.
+	 */
+
+
+	targetRefRate = PALDevDataGet(Dev, targetRefRate);
+
+	/*
+	 * Initialize Spad arrays.
+	 * Currently the good spad map is initialised to 'All good'.
+	 * This is a short term implementation. The good spad map will be
+	 * provided as an input.
+	 * Note that there are 6 bytes. Only the first 44 bits will be used to
+	 * represent spads.
+	 */
+	for (index = 0; index < spadArraySize; index++)
+		Dev->Data.SpadData.RefSpadEnables[index] = 0;
+
+
+	Status = VL_WrByte(Dev, 0xFF, 0x01);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_WrByte(Dev,
+			VL_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_WrByte(Dev,
+			VL_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_WrByte(Dev, 0xFF, 0x00);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_WrByte(Dev,
+			VL_REG_GLOBAL_CONFIG_REF_EN_START_SELECT,
+			startSelect);
+
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_WrByte(Dev,
+			VL_REG_POWER_MANAGEMENT_GO1_POWER_FORCE, 0);
+
+	/* Perform ref calibration */
+	if (Status == VL_ERROR_NONE)
+		Status = VL_perform_ref_calibration(Dev, &VhvSettings,
+			&PhaseCal, 0);
+
+	if (Status == VL_ERROR_NONE) {
+		/* Enable Minimum NON-APERTURE Spads */
+		currentSpadIndex = 0;
+		lastSpadIndex = currentSpadIndex;
+		needAptSpads = 0;
+		Status = enable_ref_spads(Dev,
+					needAptSpads,
+					Dev->Data.SpadData.RefGoodSpadMap,
+					Dev->Data.SpadData.RefSpadEnables,
+					spadArraySize,
+					startSelect,
+					currentSpadIndex,
+					minimumSpadCount,
+					&lastSpadIndex);
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		currentSpadIndex = lastSpadIndex;
+
+		Status = perform_ref_signal_measurement(Dev,
+			&peakSignalRateRef);
+		if ((Status == VL_ERROR_NONE) &&
+			(peakSignalRateRef > targetRefRate)) {
+			/* Signal rate measurement too high, */
+			/* switch to APERTURE SPADs */
+
+			for (index = 0; index < spadArraySize; index++)
+				Dev->Data.SpadData.RefSpadEnables[index] = 0;
+
+
+			/* Increment to the first APERTURE spad */
+			while ((is_aperture(startSelect + currentSpadIndex)
+				== 0) && (currentSpadIndex < maxSpadCount)) {
+				currentSpadIndex++;
+			}
+
+			needAptSpads = 1;
+
+			Status = enable_ref_spads(Dev,
+					needAptSpads,
+					Dev->Data.SpadData.RefGoodSpadMap,
+					Dev->Data.SpadData.RefSpadEnables,
+					spadArraySize,
+					startSelect,
+					currentSpadIndex,
+					minimumSpadCount,
+					&lastSpadIndex);
+
+			if (Status == VL_ERROR_NONE) {
+				currentSpadIndex = lastSpadIndex;
+				Status = perform_ref_signal_measurement(Dev,
+						&peakSignalRateRef);
+
+				if ((Status == VL_ERROR_NONE) &&
+					(peakSignalRateRef > targetRefRate)) {
+					/* Signal rate still too high after
+					 * setting the minimum number of
+					 * APERTURE spads. Can do no more
+					 * therefore set the min number of
+					 * aperture spads as the result.
+					 */
+					isApertureSpads_int = 1;
+					refSpadCount_int = minimumSpadCount;
+				}
+			}
+		} else {
+			needAptSpads = 0;
+		}
+	}
+
+	if ((Status == VL_ERROR_NONE) &&
+		(peakSignalRateRef < targetRefRate)) {
+		/* At this point, the minimum number of either aperture
+		 * or non-aperture spads have been set. Proceed to add
+		 * spads and perform measurements until the target
+		 * reference is reached.
+		 */
+		isApertureSpads_int = needAptSpads;
+		refSpadCount_int	= minimumSpadCount;
+
+		memcpy(lastSpadArray, Dev->Data.SpadData.RefSpadEnables,
+				spadArraySize);
+		lastSignalRateDiff = abs(peakSignalRateRef -
+			targetRefRate);
+		complete = 0;
+
+		while (!complete) {
+			get_next_good_spad(
+				Dev->Data.SpadData.RefGoodSpadMap,
+				spadArraySize, currentSpadIndex,
+				&nextGoodSpad);
+
+			if (nextGoodSpad == -1) {
+				Status = VL_ERROR_REF_SPAD_INIT;
+				break;
+			}
+
+			/* Cannot combine Aperture and Non-Aperture spads, so
+			 * ensure the current spad is of the correct type.
+			 */
+			if (is_aperture((uint32_t)startSelect + nextGoodSpad) !=
+					needAptSpads) {
+				/* At this point we have enabled the maximum
+				 * number of Aperture spads.
+				 */
+				complete = 1;
+				break;
+			}
+
+			(refSpadCount_int)++;
+
+			currentSpadIndex = nextGoodSpad;
+			Status = enable_spad_bit(
+					Dev->Data.SpadData.RefSpadEnables,
+					spadArraySize, currentSpadIndex);
+
+			if (Status == VL_ERROR_NONE) {
+				currentSpadIndex++;
+				/* Proceed to apply the additional spad and */
+				/* perform measurement. */
+				Status = set_ref_spad_map(Dev,
+					Dev->Data.SpadData.RefSpadEnables);
+			}
+
+			if (Status != VL_ERROR_NONE)
+				break;
+
+			Status = perform_ref_signal_measurement(Dev,
+					&peakSignalRateRef);
+
+			if (Status != VL_ERROR_NONE)
+				break;
+
+			signalRateDiff = abs(peakSignalRateRef - targetRefRate);
+
+			if (peakSignalRateRef > targetRefRate) {
+				/* Select the spad map that provides the */
+				/* measurement closest to the target rate, */
+				/* either above or below it. */
+
+				if (signalRateDiff > lastSignalRateDiff) {
+				/* Previous spad map produced a closer */
+				/* measurement, so choose this. */
+					Status = set_ref_spad_map(Dev,
+							lastSpadArray);
+					memcpy(
+					Dev->Data.SpadData.RefSpadEnables,
+					lastSpadArray, spadArraySize);
+
+					(refSpadCount_int)--;
+				}
+				complete = 1;
+			} else {
+				/* Continue to add spads */
+				lastSignalRateDiff = signalRateDiff;
+				memcpy(lastSpadArray,
+					Dev->Data.SpadData.RefSpadEnables,
+					spadArraySize);
+			}
+
+		} /* while */
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		*refSpadCount = refSpadCount_int;
+		*isApertureSpads = isApertureSpads_int;
+
+		VL_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 1);
+		VL_SETDEVICESPECIFICPARAMETER(Dev,
+			ReferenceSpadCount, (uint8_t)(*refSpadCount));
+		VL_SETDEVICESPECIFICPARAMETER(Dev,
+			ReferenceSpadType, *isApertureSpads);
+	}
+
+	return Status;
+}
+
+int8_t VL_set_reference_spads(struct vl_data *Dev,
+				 uint32_t count, uint8_t isApertureSpads)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint32_t currentSpadIndex = 0;
+	uint8_t startSelect = 0xB4;
+	uint32_t spadArraySize = 6;
+	uint32_t maxSpadCount = 44;
+	uint32_t lastSpadIndex;
+	uint32_t index;
+
+	/*
+	 * This function applies a requested number of reference spads, either
+	 * aperture or
+	 * non-aperture, as requested.
+	 * The good spad map will be applied.
+	 */
+
+	Status = VL_WrByte(Dev, 0xFF, 0x01);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_WrByte(Dev,
+			VL_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_WrByte(Dev,
+			VL_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_WrByte(Dev, 0xFF, 0x00);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_WrByte(Dev,
+			VL_REG_GLOBAL_CONFIG_REF_EN_START_SELECT,
+			startSelect);
+
+	for (index = 0; index < spadArraySize; index++)
+		Dev->Data.SpadData.RefSpadEnables[index] = 0;
+
+	if (isApertureSpads) {
+		/* Increment to the first APERTURE spad */
+		while ((is_aperture(startSelect + currentSpadIndex) == 0) &&
+			  (currentSpadIndex < maxSpadCount)) {
+			currentSpadIndex++;
+		}
+	}
+	Status = enable_ref_spads(Dev,
+				isApertureSpads,
+				Dev->Data.SpadData.RefGoodSpadMap,
+				Dev->Data.SpadData.RefSpadEnables,
+				spadArraySize,
+				startSelect,
+				currentSpadIndex,
+				count,
+				&lastSpadIndex);
+
+	if (Status == VL_ERROR_NONE) {
+		VL_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 1);
+		VL_SETDEVICESPECIFICPARAMETER(Dev,
+			ReferenceSpadCount, (uint8_t)(count));
+		VL_SETDEVICESPECIFICPARAMETER(Dev,
+			ReferenceSpadType, isApertureSpads);
+	}
+
+	return Status;
+}
+
+int8_t VL_get_reference_spads(struct vl_data *Dev,
+			uint32_t *pSpadCount, uint8_t *pIsApertureSpads)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t refSpadsInitialised;
+	uint8_t refSpadArray[6];
+	uint32_t cMaxSpadCount = 44;
+	uint32_t cSpadArraySize = 6;
+	uint32_t spadsEnabled;
+	uint8_t isApertureSpads = 0;
+
+	refSpadsInitialised = VL_GETDEVICESPECIFICPARAMETER(Dev,
+					RefSpadsInitialised);
+
+	if (refSpadsInitialised == 1) {
+
+		*pSpadCount = (uint32_t)VL_GETDEVICESPECIFICPARAMETER(Dev,
+			ReferenceSpadCount);
+		*pIsApertureSpads = VL_GETDEVICESPECIFICPARAMETER(Dev,
+			ReferenceSpadType);
+	} else {
+
+		/* obtain spad info from device.*/
+		Status = get_ref_spad_map(Dev, refSpadArray);
+
+		if (Status == VL_ERROR_NONE) {
+			/* count enabled spads within spad map array and
+			 * determine if Aperture or Non-Aperture.
+			 */
+			Status = count_enabled_spads(refSpadArray,
+							cSpadArraySize,
+							cMaxSpadCount,
+							&spadsEnabled,
+							&isApertureSpads);
+
+			if (Status == VL_ERROR_NONE) {
+
+				*pSpadCount = spadsEnabled;
+				*pIsApertureSpads = isApertureSpads;
+
+				VL_SETDEVICESPECIFICPARAMETER(Dev,
+					RefSpadsInitialised, 1);
+				VL_SETDEVICESPECIFICPARAMETER(Dev,
+					ReferenceSpadCount,
+					(uint8_t)spadsEnabled);
+				VL_SETDEVICESPECIFICPARAMETER(Dev,
+					ReferenceSpadType, isApertureSpads);
+			}
+		}
+	}
+
+	return Status;
+}
+
+
+int8_t VL_perform_single_ref_calibration(struct vl_data *Dev,
+		uint8_t vhv_init_byte)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_WrByte(Dev, VL_REG_SYSRANGE_START,
+				VL_REG_SYSRANGE_MODE_START_STOP |
+				vhv_init_byte);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_measurement_poll_for_completion(Dev);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_ClearInterruptMask(Dev, 0);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_WrByte(Dev, VL_REG_SYSRANGE_START, 0x00);
+
+	return Status;
+}
+
+
+int8_t VL_ref_calibration_io(struct vl_data *Dev,
+	uint8_t read_not_write, uint8_t VhvSettings, uint8_t PhaseCal,
+	uint8_t *pVhvSettings, uint8_t *pPhaseCal,
+	const uint8_t vhv_enable, const uint8_t phase_enable)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t PhaseCalint = 0;
+
+	/* Read VHV from device */
+	Status |= VL_WrByte(Dev, 0xFF, 0x01);
+	Status |= VL_WrByte(Dev, 0x00, 0x00);
+	Status |= VL_WrByte(Dev, 0xFF, 0x00);
+
+	if (read_not_write) {
+		if (vhv_enable)
+			Status |= VL_RdByte(Dev, 0xCB, pVhvSettings);
+		if (phase_enable)
+			Status |= VL_RdByte(Dev, 0xEE, &PhaseCalint);
+	} else {
+		if (vhv_enable)
+			Status |= VL_WrByte(Dev, 0xCB, VhvSettings);
+		if (phase_enable)
+			Status |= VL_UpdateByte(Dev, 0xEE, 0x80, PhaseCal);
+	}
+
+	Status |= VL_WrByte(Dev, 0xFF, 0x01);
+	Status |= VL_WrByte(Dev, 0x00, 0x01);
+	Status |= VL_WrByte(Dev, 0xFF, 0x00);
+
+	*pPhaseCal = (uint8_t)(PhaseCalint&0xEF);
+
+	return Status;
+}
+
+
+int8_t VL_perform_vhv_calibration(struct vl_data *Dev,
+	uint8_t *pVhvSettings, const uint8_t get_data_enable,
+	const uint8_t restore_config)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t SequenceConfig = 0;
+	uint8_t VhvSettings = 0;
+	uint8_t PhaseCal = 0;
+	uint8_t PhaseCalInt = 0;
+
+	/* store the value of the sequence config,
+	 * this will be reset before the end of the function
+	 */
+
+	if (restore_config)
+		SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
+
+	/* Run VHV */
+	Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, 0x01);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_perform_single_ref_calibration(Dev, 0x40);
+
+	/* Read VHV from device */
+	if ((Status == VL_ERROR_NONE) && (get_data_enable == 1)) {
+		Status = VL_ref_calibration_io(Dev, 1,
+			VhvSettings, PhaseCal, /* Not used here */
+			pVhvSettings, &PhaseCalInt,
+			1, 0);
+	} else
+		*pVhvSettings = 0;
+
+
+	if ((Status == VL_ERROR_NONE) && restore_config) {
+		/* restore the previous Sequence Config */
+		Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG,
+				SequenceConfig);
+		if (Status == VL_ERROR_NONE)
+			PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
+
+	}
+
+	return Status;
+}
+
+int8_t VL_perform_phase_calibration(struct vl_data *Dev,
+	uint8_t *pPhaseCal, const uint8_t get_data_enable,
+	const uint8_t restore_config)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t SequenceConfig = 0;
+	uint8_t VhvSettings = 0;
+	uint8_t PhaseCal = 0;
+	uint8_t VhvSettingsint;
+
+	/* store the value of the sequence config,
+	 * this will be reset before the end of the function
+	 */
+
+	if (restore_config)
+		SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
+
+	/* Run PhaseCal */
+	Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, 0x02);
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_perform_single_ref_calibration(Dev, 0x0);
+
+	/* Read PhaseCal from device */
+	if ((Status == VL_ERROR_NONE) && (get_data_enable == 1)) {
+		Status = VL_ref_calibration_io(Dev, 1,
+			VhvSettings, PhaseCal, /* Not used here */
+			&VhvSettingsint, pPhaseCal,
+			0, 1);
+	} else
+		*pPhaseCal = 0;
+
+
+	if ((Status == VL_ERROR_NONE) && restore_config) {
+		/* restore the previous Sequence Config */
+		Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG,
+				SequenceConfig);
+		if (Status == VL_ERROR_NONE)
+			PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
+
+	}
+
+	return Status;
+}
+
+int8_t VL_perform_ref_calibration(struct vl_data *Dev,
+	uint8_t *pVhvSettings, uint8_t *pPhaseCal, uint8_t get_data_enable)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t SequenceConfig = 0;
+
+	/* store the value of the sequence config,
+	 * this will be reset before the end of the function
+	 */
+
+	SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
+
+	/* In the following function we don't save the config to optimize */
+	/* writes on device. Config is saved and restored only once. */
+	Status = VL_perform_vhv_calibration(
+			Dev, pVhvSettings, get_data_enable, 0);
+
+
+	if (Status == VL_ERROR_NONE)
+		Status = VL_perform_phase_calibration(
+			Dev, pPhaseCal, get_data_enable, 0);
+
+
+	if (Status == VL_ERROR_NONE) {
+		/* restore the previous Sequence Config */
+		Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG,
+				SequenceConfig);
+		if (Status == VL_ERROR_NONE)
+			PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
+
+	}
+
+	return Status;
+}
+
+int8_t VL_set_ref_calibration(struct vl_data *Dev,
+		uint8_t VhvSettings, uint8_t PhaseCal)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t pVhvSettings;
+	uint8_t pPhaseCal;
+
+	Status = VL_ref_calibration_io(Dev, 0,
+		VhvSettings, PhaseCal,
+		&pVhvSettings, &pPhaseCal,
+		1, 1);
+
+	return Status;
+}
+
+int8_t VL_get_ref_calibration(struct vl_data *Dev,
+		uint8_t *pVhvSettings, uint8_t *pPhaseCal)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t VhvSettings = 0;
+	uint8_t PhaseCal = 0;
+
+	Status = VL_ref_calibration_io(Dev, 1,
+		VhvSettings, PhaseCal,
+		pVhvSettings, pPhaseCal,
+		1, 1);
+
+	return Status;
+}
diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api_core.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api_core.c
new file mode 100644
index 0000000..ceb3585
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api_core.c
@@ -0,0 +1,2220 @@
+/*
+ *  vl53l0x_api_core.c - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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 "vl53l0x_api.h"
+#include "vl53l0x_api_core.h"
+#include "vl53l0x_api_calibration.h"
+
+
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
+#define LOG_FUNCTION_START(fmt, ...) \
+	_LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+	_LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
+	_LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
+
+int8_t VL_reverse_bytes(uint8_t *data, uint32_t size)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t tempData;
+	uint32_t mirrorIndex;
+	uint32_t middle = size/2;
+	uint32_t index;
+
+	for (index = 0; index < middle; index++) {
+		mirrorIndex		 = size - index - 1;
+		tempData		 = data[index];
+		data[index]		 = data[mirrorIndex];
+		data[mirrorIndex] = tempData;
+	}
+	return Status;
+}
+
+int8_t VL_measurement_poll_for_completion(struct vl_data *Dev)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t NewDataReady = 0;
+	uint32_t LoopNb;
+
+	LOG_FUNCTION_START("");
+
+	LoopNb = 0;
+
+	do {
+		Status = VL_GetMeasurementDataReady(Dev, &NewDataReady);
+		if (Status != 0)
+			break; /* the error is set */
+
+		if (NewDataReady == 1)
+			break; /* done note that status == 0 */
+
+		LoopNb++;
+		if (LoopNb >= VL_DEFAULT_MAX_LOOP) {
+			Status = VL_ERROR_TIME_OUT;
+			break;
+		}
+
+		VL_PollingDelay(Dev);
+	} while (1);
+
+	LOG_FUNCTION_END(Status);
+
+	return Status;
+}
+
+
+uint8_t VL_decode_vcsel_period(uint8_t vcsel_period_reg)
+{
+	/*!
+	 * Converts the encoded VCSEL period register value into the real
+	 * period in PLL clocks
+	 */
+
+	uint8_t vcsel_period_pclks = 0;
+
+	vcsel_period_pclks = (vcsel_period_reg + 1) << 1;
+
+	return vcsel_period_pclks;
+}
+
+uint8_t VL_encode_vcsel_period(uint8_t vcsel_period_pclks)
+{
+	/*!
+	 * Converts the encoded VCSEL period register value into the real period
+	 * in PLL clocks
+	 */
+
+	uint8_t vcsel_period_reg = 0;
+
+	vcsel_period_reg = (vcsel_period_pclks >> 1) - 1;
+
+	return vcsel_period_reg;
+}
+
+
+uint32_t VL_isqrt(uint32_t num)
+{
+	/*
+	 * Implements an integer square root
+	 *
+	 * From: http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
+	 */
+
+	uint32_t  res = 0;
+	uint32_t  bit = 1 << 30;
+	/* The second-to-top bit is set: */
+	/* 1 << 14 for 16-bits, 1 << 30 for 32 bits */
+
+	 /* "bit" starts at the highest power of four <= the argument. */
+	while (bit > num)
+		bit >>= 2;
+
+
+	while (bit != 0) {
+		if (num >= res + bit) {
+			num -= res + bit;
+			res = (res >> 1) + bit;
+		} else
+			res >>= 1;
+
+		bit >>= 2;
+	}
+
+	return res;
+}
+
+
+uint32_t VL_quadrature_sum(uint32_t a, uint32_t b)
+{
+	/*
+	 * Implements a quadrature sum
+	 *
+	 * rea = sqrt(a^2 + b^2)
+	 *
+	 * Trap overflow case max input value is 65535 (16-bit value)
+	 * as internal calc are 32-bit wide
+	 *
+	 * If overflow then seta output to maximum
+	 */
+	uint32_t  res = 0;
+
+	if (a > 65535 || b > 65535)
+		res = 65535;
+	else
+		res = VL_isqrt(a * a + b * b);
+
+	return res;
+}
+
+
+int8_t VL_device_read_strobe(struct vl_data *Dev)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t strobe;
+	uint32_t LoopNb;
+
+	LOG_FUNCTION_START("");
+
+	Status |= VL_WrByte(Dev, 0x83, 0x00);
+
+	/* polling use timeout to avoid deadlock*/
+	if (Status == VL_ERROR_NONE) {
+		LoopNb = 0;
+		do {
+			Status = VL_RdByte(Dev, 0x83, &strobe);
+			if ((strobe != 0x00) || Status != VL_ERROR_NONE)
+				break;
+				LoopNb = LoopNb + 1;
+		} while (LoopNb < VL_DEFAULT_MAX_LOOP);
+
+		if (LoopNb >= VL_DEFAULT_MAX_LOOP)
+			Status = VL_ERROR_TIME_OUT;
+
+	}
+
+	Status |= VL_WrByte(Dev, 0x83, 0x01);
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+
+}
+
+int8_t VL_get_info_from_device(struct vl_data *Dev, uint8_t option)
+{
+
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t byte;
+	uint32_t TmpDWord;
+	uint8_t ModuleId;
+	uint8_t Revision;
+	uint8_t ReferenceSpadCount = 0;
+	uint8_t ReferenceSpadType = 0;
+	uint32_t PartUIDUpper = 0;
+	uint32_t PartUIDLower = 0;
+	uint32_t OffsetFixed1104_mm = 0;
+	int16_t OffsetMicroMeters = 0;
+	uint32_t DistMeasTgtFixed1104_mm = 400 << 4;
+	uint32_t DistMeasFixed1104_400_mm = 0;
+	uint32_t SignalRateMeasFixed1104_400_mm = 0;
+	char ProductId[19];
+	char *ProductId_tmp;
+	uint8_t ReadDataFromDeviceDone;
+	unsigned int SignalRateMeasFixed400mmFix = 0;
+	uint8_t NvmRefGoodSpadMap[VL_REF_SPAD_BUFFER_SIZE];
+	int i;
+
+
+	LOG_FUNCTION_START("");
+
+	ReadDataFromDeviceDone = VL_GETDEVICESPECIFICPARAMETER(Dev,
+			ReadDataFromDeviceDone);
+
+	/* This access is done only once after that a GetDeviceInfo or */
+	/* datainit is done*/
+	if (ReadDataFromDeviceDone != 7) {
+
+		Status |= VL_WrByte(Dev, 0x80, 0x01);
+		Status |= VL_WrByte(Dev, 0xFF, 0x01);
+		Status |= VL_WrByte(Dev, 0x00, 0x00);
+
+		Status |= VL_WrByte(Dev, 0xFF, 0x06);
+		Status |= VL_RdByte(Dev, 0x83, &byte);
+		Status |= VL_WrByte(Dev, 0x83, byte|4);
+		Status |= VL_WrByte(Dev, 0xFF, 0x07);
+		Status |= VL_WrByte(Dev, 0x81, 0x01);
+
+		Status |= VL_PollingDelay(Dev);
+
+		Status |= VL_WrByte(Dev, 0x80, 0x01);
+
+		if (((option & 1) == 1) &&
+			((ReadDataFromDeviceDone & 1) == 0)) {
+			Status |= VL_WrByte(Dev, 0x94, 0x6b);
+			Status |= VL_device_read_strobe(Dev);
+			Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+			ReferenceSpadCount = (uint8_t)((TmpDWord >> 8) & 0x07f);
+			ReferenceSpadType  = (uint8_t)((TmpDWord >> 15) & 0x01);
+
+			Status |= VL_WrByte(Dev, 0x94, 0x24);
+			Status |= VL_device_read_strobe(Dev);
+			Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+
+			NvmRefGoodSpadMap[0] = (uint8_t)((TmpDWord >> 24)
+				& 0xff);
+			NvmRefGoodSpadMap[1] = (uint8_t)((TmpDWord >> 16)
+				& 0xff);
+			NvmRefGoodSpadMap[2] = (uint8_t)((TmpDWord >> 8)
+				& 0xff);
+			NvmRefGoodSpadMap[3] = (uint8_t)(TmpDWord & 0xff);
+
+			Status |= VL_WrByte(Dev, 0x94, 0x25);
+			Status |= VL_device_read_strobe(Dev);
+			Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+			NvmRefGoodSpadMap[4] = (uint8_t)((TmpDWord >> 24)
+				& 0xff);
+			NvmRefGoodSpadMap[5] = (uint8_t)((TmpDWord >> 16)
+				& 0xff);
+		}
+
+		if (((option & 2) == 2) &&
+			((ReadDataFromDeviceDone & 2) == 0)) {
+
+			Status |= VL_WrByte(Dev, 0x94, 0x02);
+			Status |= VL_device_read_strobe(Dev);
+			Status |= VL_RdByte(Dev, 0x90, &ModuleId);
+
+			Status |= VL_WrByte(Dev, 0x94, 0x7B);
+			Status |= VL_device_read_strobe(Dev);
+			Status |= VL_RdByte(Dev, 0x90, &Revision);
+
+			Status |= VL_WrByte(Dev, 0x94, 0x77);
+			Status |= VL_device_read_strobe(Dev);
+			Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+			ProductId[0] = (char)((TmpDWord >> 25) & 0x07f);
+			ProductId[1] = (char)((TmpDWord >> 18) & 0x07f);
+			ProductId[2] = (char)((TmpDWord >> 11) & 0x07f);
+			ProductId[3] = (char)((TmpDWord >> 4) & 0x07f);
+
+			byte = (uint8_t)((TmpDWord & 0x00f) << 3);
+
+			Status |= VL_WrByte(Dev, 0x94, 0x78);
+			Status |= VL_device_read_strobe(Dev);
+			Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+			ProductId[4] = (char)(byte +
+					((TmpDWord >> 29) & 0x07f));
+			ProductId[5] = (char)((TmpDWord >> 22) & 0x07f);
+			ProductId[6] = (char)((TmpDWord >> 15) & 0x07f);
+			ProductId[7] = (char)((TmpDWord >> 8) & 0x07f);
+			ProductId[8] = (char)((TmpDWord >> 1) & 0x07f);
+
+			byte = (uint8_t)((TmpDWord & 0x001) << 6);
+
+			Status |= VL_WrByte(Dev, 0x94, 0x79);
+
+			Status |= VL_device_read_strobe(Dev);
+
+			Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+			ProductId[9] = (char)(byte +
+					((TmpDWord >> 26) & 0x07f));
+			ProductId[10] = (char)((TmpDWord >> 19) & 0x07f);
+			ProductId[11] = (char)((TmpDWord >> 12) & 0x07f);
+			ProductId[12] = (char)((TmpDWord >> 5) & 0x07f);
+
+			byte = (uint8_t)((TmpDWord & 0x01f) << 2);
+
+			Status |= VL_WrByte(Dev, 0x94, 0x7A);
+
+			Status |= VL_device_read_strobe(Dev);
+
+			Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+			ProductId[13] = (char)(byte +
+					((TmpDWord >> 30) & 0x07f));
+			ProductId[14] = (char)((TmpDWord >> 23) & 0x07f);
+			ProductId[15] = (char)((TmpDWord >> 16) & 0x07f);
+			ProductId[16] = (char)((TmpDWord >> 9) & 0x07f);
+			ProductId[17] = (char)((TmpDWord >> 2) & 0x07f);
+			ProductId[18] = '\0';
+
+		}
+
+		if (((option & 4) == 4) &&
+			((ReadDataFromDeviceDone & 4) == 0)) {
+
+			Status |= VL_WrByte(Dev, 0x94, 0x7B);
+			Status |= VL_device_read_strobe(Dev);
+			Status |= VL_RdDWord(Dev, 0x90, &PartUIDUpper);
+
+			Status |= VL_WrByte(Dev, 0x94, 0x7C);
+			Status |= VL_device_read_strobe(Dev);
+			Status |= VL_RdDWord(Dev, 0x90, &PartUIDLower);
+
+			Status |= VL_WrByte(Dev, 0x94, 0x73);
+			Status |= VL_device_read_strobe(Dev);
+			Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+			SignalRateMeasFixed1104_400_mm = (TmpDWord &
+				0x0000000ff) << 8;
+
+			Status |= VL_WrByte(Dev, 0x94, 0x74);
+			Status |= VL_device_read_strobe(Dev);
+			Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+			SignalRateMeasFixed1104_400_mm |= ((TmpDWord &
+				0xff000000) >> 24);
+
+			Status |= VL_WrByte(Dev, 0x94, 0x75);
+			Status |= VL_device_read_strobe(Dev);
+			Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+			DistMeasFixed1104_400_mm = (TmpDWord & 0x0000000ff)
+							<< 8;
+
+			Status |= VL_WrByte(Dev, 0x94, 0x76);
+			Status |= VL_device_read_strobe(Dev);
+			Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+			DistMeasFixed1104_400_mm |= ((TmpDWord & 0xff000000)
+							>> 24);
+		}
+
+		Status |= VL_WrByte(Dev, 0x81, 0x00);
+		Status |= VL_WrByte(Dev, 0xFF, 0x06);
+		Status |= VL_RdByte(Dev, 0x83, &byte);
+		Status |= VL_WrByte(Dev, 0x83, byte&0xfb);
+		Status |= VL_WrByte(Dev, 0xFF, 0x01);
+		Status |= VL_WrByte(Dev, 0x00, 0x01);
+
+		Status |= VL_WrByte(Dev, 0xFF, 0x00);
+		Status |= VL_WrByte(Dev, 0x80, 0x00);
+	}
+
+	if ((Status == VL_ERROR_NONE) &&
+		(ReadDataFromDeviceDone != 7)) {
+		/* Assign to variable if status is ok */
+		if (((option & 1) == 1) &&
+			((ReadDataFromDeviceDone & 1) == 0)) {
+			VL_SETDEVICESPECIFICPARAMETER(Dev,
+				ReferenceSpadCount, ReferenceSpadCount);
+
+			VL_SETDEVICESPECIFICPARAMETER(Dev,
+				ReferenceSpadType, ReferenceSpadType);
+
+			for (i = 0; i < VL_REF_SPAD_BUFFER_SIZE; i++) {
+				Dev->Data.SpadData.RefGoodSpadMap[i] =
+					NvmRefGoodSpadMap[i];
+			}
+		}
+
+		if (((option & 2) == 2) &&
+			((ReadDataFromDeviceDone & 2) == 0)) {
+			VL_SETDEVICESPECIFICPARAMETER(Dev,
+					ModuleId, ModuleId);
+
+			VL_SETDEVICESPECIFICPARAMETER(Dev,
+					Revision, Revision);
+
+			ProductId_tmp = VL_GETDEVICESPECIFICPARAMETER(Dev,
+					ProductId);
+			VL_COPYSTRING(ProductId_tmp, ProductId);
+
+		}
+
+		if (((option & 4) == 4) &&
+			((ReadDataFromDeviceDone & 4) == 0)) {
+			VL_SETDEVICESPECIFICPARAMETER(Dev,
+						PartUIDUpper, PartUIDUpper);
+
+			VL_SETDEVICESPECIFICPARAMETER(Dev,
+						PartUIDLower, PartUIDLower);
+
+			SignalRateMeasFixed400mmFix =
+				VL_FIXPOINT97TOFIXPOINT1616(
+					SignalRateMeasFixed1104_400_mm);
+
+			VL_SETDEVICESPECIFICPARAMETER(Dev,
+				SignalRateMeasFixed400mm,
+				SignalRateMeasFixed400mmFix);
+
+			OffsetMicroMeters = 0;
+			if (DistMeasFixed1104_400_mm != 0) {
+				OffsetFixed1104_mm = DistMeasFixed1104_400_mm -
+				DistMeasTgtFixed1104_mm;
+				OffsetMicroMeters = (OffsetFixed1104_mm
+				* 1000) >> 4;
+				OffsetMicroMeters *= -1;
+			}
+
+			PALDevDataSet(Dev,
+				Part2PartOffsetAdjustmentNVMMicroMeter,
+				OffsetMicroMeters);
+		}
+		byte = (uint8_t)(ReadDataFromDeviceDone|option);
+		VL_SETDEVICESPECIFICPARAMETER(Dev, ReadDataFromDeviceDone,
+				byte);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+
+uint32_t VL_calc_macro_period_ps(struct vl_data *Dev,
+	uint8_t vcsel_period_pclks)
+{
+	uint64_t PLL_period_ps;
+	uint32_t macro_period_vclks;
+	uint32_t macro_period_ps;
+
+	LOG_FUNCTION_START("");
+
+	/* The above calculation will produce rounding errors, */
+	/* therefore set fixed value */
+	PLL_period_ps = 1655;
+
+	macro_period_vclks = 2304;
+	macro_period_ps = (uint32_t)(macro_period_vclks
+			* vcsel_period_pclks * PLL_period_ps);
+
+	LOG_FUNCTION_END("");
+	return macro_period_ps;
+}
+
+uint16_t VL_encode_timeout(uint32_t timeout_macro_clks)
+{
+	/*!
+	 * Encode timeout in macro periods in (LSByte * 2^MSByte) + 1 format
+	 */
+
+	uint16_t encoded_timeout = 0;
+	uint32_t ls_byte = 0;
+	uint16_t ms_byte = 0;
+
+	if (timeout_macro_clks > 0) {
+		ls_byte = timeout_macro_clks - 1;
+
+		while ((ls_byte & 0xFFFFFF00) > 0) {
+			ls_byte = ls_byte >> 1;
+			ms_byte++;
+		}
+
+		encoded_timeout = (ms_byte << 8)
+				+ (uint16_t) (ls_byte & 0x000000FF);
+	}
+
+	return encoded_timeout;
+
+}
+
+uint32_t VL_decode_timeout(uint16_t encoded_timeout)
+{
+	/*!
+	 * Decode 16-bit timeout register value - format (LSByte * 2^MSByte) + 1
+	 */
+
+	uint32_t timeout_macro_clks = 0;
+
+	timeout_macro_clks = ((uint32_t) (encoded_timeout & 0x00FF)
+			<< (uint32_t) ((encoded_timeout & 0xFF00) >> 8)) + 1;
+
+	return timeout_macro_clks;
+}
+
+
+/* To convert ms into register value */
+uint32_t VL_calc_timeout_mclks(struct vl_data *Dev,
+		uint32_t timeout_period_us,
+		uint8_t vcsel_period_pclks)
+{
+	uint32_t macro_period_ps;
+	uint32_t macro_period_ns;
+	uint32_t timeout_period_mclks = 0;
+
+	macro_period_ps = VL_calc_macro_period_ps(Dev, vcsel_period_pclks);
+	macro_period_ns = (macro_period_ps + 500) / 1000;
+
+	timeout_period_mclks =
+		(uint32_t) (((timeout_period_us * 1000)
+		+ (macro_period_ns / 2)) / macro_period_ns);
+
+	return timeout_period_mclks;
+}
+
+/* To convert register value into us */
+uint32_t VL_calc_timeout_us(struct vl_data *Dev,
+		uint16_t timeout_period_mclks,
+		uint8_t vcsel_period_pclks)
+{
+	uint32_t macro_period_ps;
+	uint32_t macro_period_ns;
+	uint32_t actual_timeout_period_us = 0;
+
+	macro_period_ps = VL_calc_macro_period_ps(Dev, vcsel_period_pclks);
+	macro_period_ns = (macro_period_ps + 500) / 1000;
+
+	actual_timeout_period_us =
+		((timeout_period_mclks * macro_period_ns) + 500) / 1000;
+
+	return actual_timeout_period_us;
+}
+
+
+int8_t get_sequence_step_timeout(struct vl_data *Dev,
+				uint8_t SequenceStepId,
+				uint32_t *pTimeOutMicroSecs)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t CurrentVCSELPulsePeriodPClk;
+	uint8_t EncodedTimeOutByte = 0;
+	uint32_t TimeoutMicroSeconds = 0;
+	uint16_t PreRangeEncodedTimeOut = 0;
+	uint16_t MsrcTimeOutMClks;
+	uint16_t PreRangeTimeOutMClks;
+	uint16_t FinalRangeTimeOutMClks = 0;
+	uint16_t FinalRangeEncodedTimeOut;
+	struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps;
+
+	if ((SequenceStepId == VL_SEQUENCESTEP_TCC)	 ||
+		(SequenceStepId == VL_SEQUENCESTEP_DSS)	 ||
+		(SequenceStepId == VL_SEQUENCESTEP_MSRC)) {
+
+		Status = VL_GetVcselPulsePeriod(Dev,
+					VL_VCSEL_PERIOD_PRE_RANGE,
+					&CurrentVCSELPulsePeriodPClk);
+		if (Status == VL_ERROR_NONE) {
+			Status = VL_RdByte(Dev,
+					VL_REG_MSRC_CONFIG_TIMEOUT_MACROP,
+					&EncodedTimeOutByte);
+		}
+		MsrcTimeOutMClks = VL_decode_timeout(EncodedTimeOutByte);
+
+		TimeoutMicroSeconds = VL_calc_timeout_us(Dev,
+						MsrcTimeOutMClks,
+						CurrentVCSELPulsePeriodPClk);
+	} else if (SequenceStepId == VL_SEQUENCESTEP_PRE_RANGE) {
+		/* Retrieve PRE-RANGE VCSEL Period */
+		Status = VL_GetVcselPulsePeriod(Dev,
+						VL_VCSEL_PERIOD_PRE_RANGE,
+						&CurrentVCSELPulsePeriodPClk);
+
+		/* Retrieve PRE-RANGE Timeout in Macro periods (MCLKS) */
+		if (Status == VL_ERROR_NONE) {
+
+			/* Retrieve PRE-RANGE VCSEL Period */
+			Status = VL_GetVcselPulsePeriod(Dev,
+					VL_VCSEL_PERIOD_PRE_RANGE,
+					&CurrentVCSELPulsePeriodPClk);
+
+			if (Status == VL_ERROR_NONE) {
+				Status = VL_RdWord(Dev,
+				VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
+				&PreRangeEncodedTimeOut);
+			}
+
+			PreRangeTimeOutMClks = VL_decode_timeout(
+					PreRangeEncodedTimeOut);
+
+			TimeoutMicroSeconds = VL_calc_timeout_us(Dev,
+					PreRangeTimeOutMClks,
+					CurrentVCSELPulsePeriodPClk);
+		}
+	} else if (SequenceStepId == VL_SEQUENCESTEP_FINAL_RANGE) {
+
+		VL_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps);
+		PreRangeTimeOutMClks = 0;
+
+		if (SchedulerSequenceSteps.PreRangeOn) {
+			/* Retrieve PRE-RANGE VCSEL Period */
+			Status = VL_GetVcselPulsePeriod(Dev,
+				VL_VCSEL_PERIOD_PRE_RANGE,
+				&CurrentVCSELPulsePeriodPClk);
+
+			/* Retrieve PRE-RANGE Timeout in Macro periods */
+			/* (MCLKS) */
+			if (Status == VL_ERROR_NONE) {
+				Status = VL_RdWord(Dev,
+				VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
+				&PreRangeEncodedTimeOut);
+				PreRangeTimeOutMClks = VL_decode_timeout(
+						PreRangeEncodedTimeOut);
+			}
+		}
+
+		if (Status == VL_ERROR_NONE) {
+			/* Retrieve FINAL-RANGE VCSEL Period */
+			Status = VL_GetVcselPulsePeriod(Dev,
+					VL_VCSEL_PERIOD_FINAL_RANGE,
+					&CurrentVCSELPulsePeriodPClk);
+		}
+
+		/* Retrieve FINAL-RANGE Timeout in Macro periods (MCLKS) */
+		if (Status == VL_ERROR_NONE) {
+			Status = VL_RdWord(Dev,
+			    VL_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI,
+				&FinalRangeEncodedTimeOut);
+			FinalRangeTimeOutMClks = VL_decode_timeout(
+					FinalRangeEncodedTimeOut);
+		}
+
+		FinalRangeTimeOutMClks -= PreRangeTimeOutMClks;
+		TimeoutMicroSeconds = VL_calc_timeout_us(Dev,
+						FinalRangeTimeOutMClks,
+						CurrentVCSELPulsePeriodPClk);
+	}
+
+	*pTimeOutMicroSecs = TimeoutMicroSeconds;
+
+	return Status;
+}
+
+
+int8_t set_sequence_step_timeout(struct vl_data *Dev,
+					uint8_t SequenceStepId,
+					uint32_t TimeOutMicroSecs)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t CurrentVCSELPulsePeriodPClk;
+	uint8_t MsrcEncodedTimeOut;
+	uint16_t PreRangeEncodedTimeOut;
+	uint16_t PreRangeTimeOutMClks;
+	uint16_t MsrcRangeTimeOutMClks;
+	uint32_t FinalRangeTimeOutMClks;
+	uint16_t FinalRangeEncodedTimeOut;
+	struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps;
+
+	if ((SequenceStepId == VL_SEQUENCESTEP_TCC)	 ||
+		(SequenceStepId == VL_SEQUENCESTEP_DSS)	 ||
+		(SequenceStepId == VL_SEQUENCESTEP_MSRC)) {
+
+		Status = VL_GetVcselPulsePeriod(Dev,
+					VL_VCSEL_PERIOD_PRE_RANGE,
+					&CurrentVCSELPulsePeriodPClk);
+
+		if (Status == VL_ERROR_NONE) {
+			MsrcRangeTimeOutMClks = VL_calc_timeout_mclks(Dev,
+					TimeOutMicroSecs,
+					(uint8_t)CurrentVCSELPulsePeriodPClk);
+
+			if (MsrcRangeTimeOutMClks > 256)
+				MsrcEncodedTimeOut = 255;
+			else
+				MsrcEncodedTimeOut =
+					(uint8_t)MsrcRangeTimeOutMClks - 1;
+
+			VL_SETDEVICESPECIFICPARAMETER(Dev,
+				LastEncodedTimeout,
+				MsrcEncodedTimeOut);
+		}
+
+		if (Status == VL_ERROR_NONE) {
+			Status = VL_WrByte(Dev,
+				VL_REG_MSRC_CONFIG_TIMEOUT_MACROP,
+				MsrcEncodedTimeOut);
+		}
+	} else {
+
+		if (SequenceStepId == VL_SEQUENCESTEP_PRE_RANGE) {
+
+			if (Status == VL_ERROR_NONE) {
+				Status = VL_GetVcselPulsePeriod(Dev,
+						VL_VCSEL_PERIOD_PRE_RANGE,
+						&CurrentVCSELPulsePeriodPClk);
+				PreRangeTimeOutMClks =
+					VL_calc_timeout_mclks(Dev,
+					TimeOutMicroSecs,
+					(uint8_t)CurrentVCSELPulsePeriodPClk);
+				PreRangeEncodedTimeOut = VL_encode_timeout(
+					PreRangeTimeOutMClks);
+
+				VL_SETDEVICESPECIFICPARAMETER(Dev,
+					LastEncodedTimeout,
+					PreRangeEncodedTimeOut);
+			}
+
+			if (Status == VL_ERROR_NONE) {
+				Status = VL_WrWord(Dev,
+				VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
+				PreRangeEncodedTimeOut);
+			}
+
+			if (Status == VL_ERROR_NONE) {
+				VL_SETDEVICESPECIFICPARAMETER(
+					Dev,
+					PreRangeTimeoutMicroSecs,
+					TimeOutMicroSecs);
+			}
+		} else if (SequenceStepId == VL_SEQUENCESTEP_FINAL_RANGE) {
+
+			/* For the final range timeout, the pre-range timeout
+			 * must be added. To do this both final and pre-range
+			 * timeouts must be expressed in macro periods MClks
+			 * because they have different vcsel periods.
+			 */
+
+			VL_GetSequenceStepEnables(Dev,
+					&SchedulerSequenceSteps);
+			PreRangeTimeOutMClks = 0;
+			if (SchedulerSequenceSteps.PreRangeOn) {
+
+				/* Retrieve PRE-RANGE VCSEL Period */
+				Status = VL_GetVcselPulsePeriod(Dev,
+					VL_VCSEL_PERIOD_PRE_RANGE,
+					&CurrentVCSELPulsePeriodPClk);
+
+				/* Retrieve PRE-RANGE Timeout in Macro */
+				/* periods (MCLKS) */
+				if (Status == VL_ERROR_NONE) {
+					Status = VL_RdWord(Dev, 0x51,
+						&PreRangeEncodedTimeOut);
+					PreRangeTimeOutMClks =
+						VL_decode_timeout(
+							PreRangeEncodedTimeOut);
+				}
+			}
+
+			/* Calculate FINAL RANGE Timeout in Macro Periods */
+			/* (MCLKS) and add PRE-RANGE value */
+			if (Status == VL_ERROR_NONE) {
+
+				Status = VL_GetVcselPulsePeriod(Dev,
+					VL_VCSEL_PERIOD_FINAL_RANGE,
+					&CurrentVCSELPulsePeriodPClk);
+			}
+			if (Status == VL_ERROR_NONE) {
+
+				FinalRangeTimeOutMClks =
+					VL_calc_timeout_mclks(Dev,
+					TimeOutMicroSecs,
+					(uint8_t) CurrentVCSELPulsePeriodPClk);
+
+				FinalRangeTimeOutMClks += PreRangeTimeOutMClks;
+
+				FinalRangeEncodedTimeOut =
+				VL_encode_timeout(FinalRangeTimeOutMClks);
+
+				if (Status == VL_ERROR_NONE) {
+					Status = VL_WrWord(Dev, 0x71,
+					FinalRangeEncodedTimeOut);
+				}
+
+				if (Status == VL_ERROR_NONE) {
+					VL_SETDEVICESPECIFICPARAMETER(
+						Dev,
+						FinalRangeTimeoutMicroSecs,
+						TimeOutMicroSecs);
+				}
+			}
+		} else
+			Status = VL_ERROR_INVALID_PARAMS;
+
+	}
+	return Status;
+}
+
+int8_t VL_set_vcsel_pulse_period(struct vl_data *Dev,
+	uint8_t VcselPeriodType, uint8_t VCSELPulsePeriodPCLK)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t vcsel_period_reg;
+	uint8_t MinPreVcselPeriodPCLK = 12;
+	uint8_t MaxPreVcselPeriodPCLK = 18;
+	uint8_t MinFinalVcselPeriodPCLK = 8;
+	uint8_t MaxFinalVcselPeriodPCLK = 14;
+	uint32_t MeasurementTimingBudgetMicroSeconds;
+	uint32_t FinalRangeTimeoutMicroSeconds;
+	uint32_t PreRangeTimeoutMicroSeconds;
+	uint32_t MsrcTimeoutMicroSeconds;
+	uint8_t PhaseCalInt = 0;
+
+	/* Check if valid clock period requested */
+
+	if ((VCSELPulsePeriodPCLK % 2) != 0) {
+		/* Value must be an even number */
+		Status = VL_ERROR_INVALID_PARAMS;
+	} else if (VcselPeriodType == VL_VCSEL_PERIOD_PRE_RANGE &&
+		(VCSELPulsePeriodPCLK < MinPreVcselPeriodPCLK ||
+		VCSELPulsePeriodPCLK > MaxPreVcselPeriodPCLK)) {
+		Status = VL_ERROR_INVALID_PARAMS;
+	} else if (VcselPeriodType == VL_VCSEL_PERIOD_FINAL_RANGE &&
+		(VCSELPulsePeriodPCLK < MinFinalVcselPeriodPCLK ||
+		 VCSELPulsePeriodPCLK > MaxFinalVcselPeriodPCLK)) {
+
+		Status = VL_ERROR_INVALID_PARAMS;
+	}
+
+	/* Apply specific settings for the requested clock period */
+
+	if (Status != VL_ERROR_NONE)
+		return Status;
+
+
+	if (VcselPeriodType == VL_VCSEL_PERIOD_PRE_RANGE) {
+
+		/* Set phase check limits */
+		if (VCSELPulsePeriodPCLK == 12) {
+
+			Status = VL_WrByte(Dev,
+				VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
+				0x18);
+			Status = VL_WrByte(Dev,
+				VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
+				0x08);
+		} else if (VCSELPulsePeriodPCLK == 14) {
+
+			Status = VL_WrByte(Dev,
+				VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
+				0x30);
+			Status = VL_WrByte(Dev,
+				VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
+				0x08);
+		} else if (VCSELPulsePeriodPCLK == 16) {
+
+			Status = VL_WrByte(Dev,
+				VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
+				0x40);
+			Status = VL_WrByte(Dev,
+				VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
+				0x08);
+		} else if (VCSELPulsePeriodPCLK == 18) {
+
+			Status = VL_WrByte(Dev,
+				VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
+				0x50);
+			Status = VL_WrByte(Dev,
+				VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
+				0x08);
+		}
+	} else if (VcselPeriodType == VL_VCSEL_PERIOD_FINAL_RANGE) {
+
+		if (VCSELPulsePeriodPCLK == 8) {
+
+			Status = VL_WrByte(Dev,
+				VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
+				0x10);
+			Status = VL_WrByte(Dev,
+				VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
+				0x08);
+
+			Status |= VL_WrByte(Dev,
+				VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x02);
+			Status |= VL_WrByte(Dev,
+				VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x0C);
+
+			Status |= VL_WrByte(Dev, 0xff, 0x01);
+			Status |= VL_WrByte(Dev,
+				VL_REG_ALGO_PHASECAL_LIM,
+				0x30);
+			Status |= VL_WrByte(Dev, 0xff, 0x00);
+		} else if (VCSELPulsePeriodPCLK == 10) {
+
+			Status = VL_WrByte(Dev,
+				VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
+				0x28);
+			Status = VL_WrByte(Dev,
+				VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
+				0x08);
+
+			Status |= VL_WrByte(Dev,
+				VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
+			Status |= VL_WrByte(Dev,
+				VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x09);
+
+			Status |= VL_WrByte(Dev, 0xff, 0x01);
+			Status |= VL_WrByte(Dev,
+				VL_REG_ALGO_PHASECAL_LIM,
+				0x20);
+			Status |= VL_WrByte(Dev, 0xff, 0x00);
+		} else if (VCSELPulsePeriodPCLK == 12) {
+
+			Status = VL_WrByte(Dev,
+				VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
+				0x38);
+			Status = VL_WrByte(Dev,
+				VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
+				0x08);
+
+			Status |= VL_WrByte(Dev,
+				VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
+			Status |= VL_WrByte(Dev,
+				VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x08);
+
+			Status |= VL_WrByte(Dev, 0xff, 0x01);
+			Status |= VL_WrByte(Dev,
+				VL_REG_ALGO_PHASECAL_LIM,
+				0x20);
+			Status |= VL_WrByte(Dev, 0xff, 0x00);
+		} else if (VCSELPulsePeriodPCLK == 14) {
+
+			Status = VL_WrByte(Dev,
+				VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
+				0x048);
+			Status = VL_WrByte(Dev,
+				VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
+				0x08);
+
+			Status |= VL_WrByte(Dev,
+				VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
+			Status |= VL_WrByte(Dev,
+				VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x07);
+
+			Status |= VL_WrByte(Dev, 0xff, 0x01);
+			Status |= VL_WrByte(Dev,
+				VL_REG_ALGO_PHASECAL_LIM,
+				0x20);
+			Status |= VL_WrByte(Dev, 0xff, 0x00);
+		}
+	}
+
+
+	/* Re-calculate and apply timeouts, in macro periods */
+
+	if (Status == VL_ERROR_NONE) {
+		vcsel_period_reg = VL_encode_vcsel_period((uint8_t)
+			VCSELPulsePeriodPCLK);
+
+	/* When the VCSEL period for the pre or final range is changed, */
+	/* the corresponding timeout must be read from the device using */
+	/* the current VCSEL period, then the new VCSEL period can be */
+	/* applied. The timeout then must be written back to the device */
+	/* using the new VCSEL period. */
+	/* For the MSRC timeout, the same applies - this timeout being */
+	/* dependent on the pre-range vcsel period. */
+		switch (VcselPeriodType) {
+		case VL_VCSEL_PERIOD_PRE_RANGE:
+			Status = get_sequence_step_timeout(Dev,
+				VL_SEQUENCESTEP_PRE_RANGE,
+				&PreRangeTimeoutMicroSeconds);
+
+			if (Status == VL_ERROR_NONE)
+				Status = get_sequence_step_timeout(Dev,
+					VL_SEQUENCESTEP_MSRC,
+					&MsrcTimeoutMicroSeconds);
+
+			if (Status == VL_ERROR_NONE)
+				Status = VL_WrByte(Dev,
+				VL_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD,
+					vcsel_period_reg);
+
+
+			if (Status == VL_ERROR_NONE)
+				Status = set_sequence_step_timeout(Dev,
+					VL_SEQUENCESTEP_PRE_RANGE,
+					PreRangeTimeoutMicroSeconds);
+
+
+			if (Status == VL_ERROR_NONE)
+				Status = set_sequence_step_timeout(Dev,
+					VL_SEQUENCESTEP_MSRC,
+					MsrcTimeoutMicroSeconds);
+
+			VL_SETDEVICESPECIFICPARAMETER(
+				Dev,
+				PreRangeVcselPulsePeriod,
+				VCSELPulsePeriodPCLK);
+			break;
+		case VL_VCSEL_PERIOD_FINAL_RANGE:
+			Status = get_sequence_step_timeout(Dev,
+				VL_SEQUENCESTEP_FINAL_RANGE,
+				&FinalRangeTimeoutMicroSeconds);
+
+			if (Status == VL_ERROR_NONE)
+				Status = VL_WrByte(Dev,
+				VL_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD,
+					vcsel_period_reg);
+
+
+			if (Status == VL_ERROR_NONE)
+				Status = set_sequence_step_timeout(Dev,
+					VL_SEQUENCESTEP_FINAL_RANGE,
+					FinalRangeTimeoutMicroSeconds);
+
+			VL_SETDEVICESPECIFICPARAMETER(
+				Dev,
+				FinalRangeVcselPulsePeriod,
+				VCSELPulsePeriodPCLK);
+			break;
+		default:
+			Status = VL_ERROR_INVALID_PARAMS;
+		}
+	}
+
+	/* Finally, the timing budget must be re-applied */
+	if (Status == VL_ERROR_NONE) {
+		VL_GETPARAMETERFIELD(Dev,
+			MeasurementTimingBudgetMicroSeconds,
+			MeasurementTimingBudgetMicroSeconds);
+
+		Status = VL_SetMeasurementTimingBudgetMicroSeconds(Dev,
+				MeasurementTimingBudgetMicroSeconds);
+	}
+
+	/* Perform the phase calibration. This is needed after changing on */
+	/* vcsel period. */
+	/* get_data_enable = 0, restore_config = 1 */
+	if (Status == VL_ERROR_NONE)
+		Status = VL_perform_phase_calibration(
+			Dev, &PhaseCalInt, 0, 1);
+
+	return Status;
+}
+
+int8_t VL_get_vcsel_pulse_period(struct vl_data *Dev,
+	uint8_t VcselPeriodType, uint8_t *pVCSELPulsePeriodPCLK)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t vcsel_period_reg;
+
+	switch (VcselPeriodType) {
+	case VL_VCSEL_PERIOD_PRE_RANGE:
+		Status = VL_RdByte(Dev,
+			VL_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD,
+			&vcsel_period_reg);
+	break;
+	case VL_VCSEL_PERIOD_FINAL_RANGE:
+		Status = VL_RdByte(Dev,
+			VL_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD,
+			&vcsel_period_reg);
+	break;
+	default:
+		Status = VL_ERROR_INVALID_PARAMS;
+	}
+
+	if (Status == VL_ERROR_NONE)
+		*pVCSELPulsePeriodPCLK =
+			VL_decode_vcsel_period(vcsel_period_reg);
+
+	return Status;
+}
+
+
+
+int8_t VL_set_measurement_timing_budget_micro_seconds(
+	struct vl_data *Dev, uint32_t MeasurementTimingBudgetMicroSeconds)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint32_t FinalRangeTimingBudgetMicroSeconds;
+	struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps;
+	uint32_t MsrcDccTccTimeoutMicroSeconds	= 2000;
+	uint32_t StartOverheadMicroSeconds		= 1910;
+	uint32_t EndOverheadMicroSeconds		= 960;
+	uint32_t MsrcOverheadMicroSeconds		= 660;
+	uint32_t TccOverheadMicroSeconds		= 590;
+	uint32_t DssOverheadMicroSeconds		= 690;
+	uint32_t PreRangeOverheadMicroSeconds	= 660;
+	uint32_t FinalRangeOverheadMicroSeconds = 550;
+	uint32_t PreRangeTimeoutMicroSeconds	= 0;
+	uint32_t cMinTimingBudgetMicroSeconds	= 20000;
+	uint32_t SubTimeout = 0;
+
+	LOG_FUNCTION_START("");
+
+	if (MeasurementTimingBudgetMicroSeconds
+			< cMinTimingBudgetMicroSeconds) {
+		Status = VL_ERROR_INVALID_PARAMS;
+		return Status;
+	}
+
+	FinalRangeTimingBudgetMicroSeconds =
+		MeasurementTimingBudgetMicroSeconds -
+		(StartOverheadMicroSeconds + EndOverheadMicroSeconds);
+
+	Status = VL_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps);
+
+	if (Status == VL_ERROR_NONE &&
+		(SchedulerSequenceSteps.TccOn  ||
+		SchedulerSequenceSteps.MsrcOn ||
+		SchedulerSequenceSteps.DssOn)) {
+
+		/* TCC, MSRC and DSS all share the same timeout */
+		Status = get_sequence_step_timeout(Dev,
+					VL_SEQUENCESTEP_MSRC,
+					&MsrcDccTccTimeoutMicroSeconds);
+
+		/* Subtract the TCC, MSRC and DSS timeouts if they are */
+		/* enabled. */
+
+		if (Status != VL_ERROR_NONE)
+			return Status;
+
+		/* TCC */
+		if (SchedulerSequenceSteps.TccOn) {
+
+			SubTimeout = MsrcDccTccTimeoutMicroSeconds
+				+ TccOverheadMicroSeconds;
+
+			if (SubTimeout <
+				FinalRangeTimingBudgetMicroSeconds) {
+				FinalRangeTimingBudgetMicroSeconds -=
+							SubTimeout;
+			} else {
+				/* Requested timeout too big. */
+				Status = VL_ERROR_INVALID_PARAMS;
+			}
+		}
+
+		if (Status != VL_ERROR_NONE) {
+			LOG_FUNCTION_END(Status);
+			return Status;
+		}
+
+		/* DSS */
+		if (SchedulerSequenceSteps.DssOn) {
+
+			SubTimeout = 2 * (MsrcDccTccTimeoutMicroSeconds +
+				DssOverheadMicroSeconds);
+
+			if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) {
+				FinalRangeTimingBudgetMicroSeconds
+							-= SubTimeout;
+			} else {
+				/* Requested timeout too big. */
+				Status = VL_ERROR_INVALID_PARAMS;
+			}
+		} else if (SchedulerSequenceSteps.MsrcOn) {
+			/* MSRC */
+			SubTimeout = MsrcDccTccTimeoutMicroSeconds +
+						MsrcOverheadMicroSeconds;
+
+			if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) {
+				FinalRangeTimingBudgetMicroSeconds
+							-= SubTimeout;
+			} else {
+				/* Requested timeout too big. */
+				Status = VL_ERROR_INVALID_PARAMS;
+			}
+		}
+
+	}
+
+	if (Status != VL_ERROR_NONE) {
+		LOG_FUNCTION_END(Status);
+		return Status;
+	}
+
+	if (SchedulerSequenceSteps.PreRangeOn) {
+
+		/* Subtract the Pre-range timeout if enabled. */
+
+		Status = get_sequence_step_timeout(Dev,
+				VL_SEQUENCESTEP_PRE_RANGE,
+				&PreRangeTimeoutMicroSeconds);
+
+		SubTimeout = PreRangeTimeoutMicroSeconds +
+				PreRangeOverheadMicroSeconds;
+
+		if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) {
+			FinalRangeTimingBudgetMicroSeconds -= SubTimeout;
+		} else {
+			/* Requested timeout too big. */
+			Status = VL_ERROR_INVALID_PARAMS;
+		}
+	}
+
+
+	if (Status == VL_ERROR_NONE &&
+		SchedulerSequenceSteps.FinalRangeOn) {
+
+		FinalRangeTimingBudgetMicroSeconds -=
+				FinalRangeOverheadMicroSeconds;
+
+		/* Final Range Timeout
+		 * Note that the final range timeout is determined by the timing
+		 * budget and the sum of all other timeouts within the sequence.
+		 * If there is no room for the final range timeout,then an error
+		 * will be set. Otherwise the remaining time will be applied to
+		 * the final range.
+		 */
+		Status = set_sequence_step_timeout(Dev,
+			VL_SEQUENCESTEP_FINAL_RANGE,
+			FinalRangeTimingBudgetMicroSeconds);
+
+		VL_SETPARAMETERFIELD(Dev,
+			MeasurementTimingBudgetMicroSeconds,
+			MeasurementTimingBudgetMicroSeconds);
+	}
+
+	LOG_FUNCTION_END(Status);
+
+	return Status;
+}
+
+int8_t VL_get_measurement_timing_budget_micro_seconds(
+	struct vl_data *Dev, uint32_t *pMeasurementTimingBudgetMicroSeconds)
+{
+	int8_t Status = VL_ERROR_NONE;
+	struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps;
+	uint32_t FinalRangeTimeoutMicroSeconds;
+	uint32_t MsrcDccTccTimeoutMicroSeconds	= 2000;
+	uint32_t StartOverheadMicroSeconds		= 1910;
+	uint32_t EndOverheadMicroSeconds		= 960;
+	uint32_t MsrcOverheadMicroSeconds		= 660;
+	uint32_t TccOverheadMicroSeconds		= 590;
+	uint32_t DssOverheadMicroSeconds		= 690;
+	uint32_t PreRangeOverheadMicroSeconds	= 660;
+	uint32_t FinalRangeOverheadMicroSeconds = 550;
+	uint32_t PreRangeTimeoutMicroSeconds	= 0;
+
+	LOG_FUNCTION_START("");
+
+	/* Start and end overhead times always present */
+	*pMeasurementTimingBudgetMicroSeconds
+		= StartOverheadMicroSeconds + EndOverheadMicroSeconds;
+
+	Status = VL_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps);
+
+	if (Status != VL_ERROR_NONE) {
+		LOG_FUNCTION_END(Status);
+		return Status;
+	}
+
+
+	if (SchedulerSequenceSteps.TccOn  ||
+		SchedulerSequenceSteps.MsrcOn ||
+		SchedulerSequenceSteps.DssOn) {
+
+		Status = get_sequence_step_timeout(Dev,
+				VL_SEQUENCESTEP_MSRC,
+				&MsrcDccTccTimeoutMicroSeconds);
+
+		if (Status == VL_ERROR_NONE) {
+			if (SchedulerSequenceSteps.TccOn) {
+				*pMeasurementTimingBudgetMicroSeconds +=
+					MsrcDccTccTimeoutMicroSeconds +
+					TccOverheadMicroSeconds;
+			}
+
+			if (SchedulerSequenceSteps.DssOn) {
+				*pMeasurementTimingBudgetMicroSeconds +=
+				2 * (MsrcDccTccTimeoutMicroSeconds +
+					DssOverheadMicroSeconds);
+			} else if (SchedulerSequenceSteps.MsrcOn) {
+				*pMeasurementTimingBudgetMicroSeconds +=
+					MsrcDccTccTimeoutMicroSeconds +
+					MsrcOverheadMicroSeconds;
+			}
+		}
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		if (SchedulerSequenceSteps.PreRangeOn) {
+			Status = get_sequence_step_timeout(Dev,
+				VL_SEQUENCESTEP_PRE_RANGE,
+				&PreRangeTimeoutMicroSeconds);
+			*pMeasurementTimingBudgetMicroSeconds +=
+				PreRangeTimeoutMicroSeconds +
+				PreRangeOverheadMicroSeconds;
+		}
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		if (SchedulerSequenceSteps.FinalRangeOn) {
+			Status = get_sequence_step_timeout(Dev,
+					VL_SEQUENCESTEP_FINAL_RANGE,
+					&FinalRangeTimeoutMicroSeconds);
+			*pMeasurementTimingBudgetMicroSeconds +=
+				(FinalRangeTimeoutMicroSeconds +
+				FinalRangeOverheadMicroSeconds);
+		}
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		VL_SETPARAMETERFIELD(Dev,
+			MeasurementTimingBudgetMicroSeconds,
+			*pMeasurementTimingBudgetMicroSeconds);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+
+
+int8_t VL_load_tuning_settings(struct vl_data *Dev,
+		uint8_t *pTuningSettingBuffer)
+{
+	int8_t Status = VL_ERROR_NONE;
+	int i;
+	int Index;
+	uint8_t msb;
+	uint8_t lsb;
+	uint8_t SelectParam;
+	uint8_t NumberOfWrites;
+	uint8_t Address;
+	uint8_t localBuffer[4]; /* max */
+	uint16_t Temp16;
+
+	LOG_FUNCTION_START("");
+
+	Index = 0;
+
+	while ((*(pTuningSettingBuffer + Index) != 0) &&
+			(Status == VL_ERROR_NONE)) {
+		NumberOfWrites = *(pTuningSettingBuffer + Index);
+		Index++;
+		if (NumberOfWrites == 0xFF) {
+			/* internal parameters */
+			SelectParam = *(pTuningSettingBuffer + Index);
+			Index++;
+			switch (SelectParam) {
+			case 0: /* uint16_t SigmaEstRefArray -> 2 bytes */
+				msb = *(pTuningSettingBuffer + Index);
+				Index++;
+				lsb = *(pTuningSettingBuffer + Index);
+				Index++;
+				Temp16 = VL_MAKEUINT16(lsb, msb);
+				PALDevDataSet(Dev, SigmaEstRefArray, Temp16);
+				break;
+			case 1: /* uint16_t SigmaEstEffPulseWidth -> 2 bytes */
+				msb = *(pTuningSettingBuffer + Index);
+				Index++;
+				lsb = *(pTuningSettingBuffer + Index);
+				Index++;
+				Temp16 = VL_MAKEUINT16(lsb, msb);
+				PALDevDataSet(Dev, SigmaEstEffPulseWidth,
+					Temp16);
+				break;
+			case 2: /* uint16_t SigmaEstEffAmbWidth -> 2 bytes */
+				msb = *(pTuningSettingBuffer + Index);
+				Index++;
+				lsb = *(pTuningSettingBuffer + Index);
+				Index++;
+				Temp16 = VL_MAKEUINT16(lsb, msb);
+				PALDevDataSet(Dev, SigmaEstEffAmbWidth, Temp16);
+				break;
+			case 3: /* uint16_t targetRefRate -> 2 bytes */
+				msb = *(pTuningSettingBuffer + Index);
+				Index++;
+				lsb = *(pTuningSettingBuffer + Index);
+				Index++;
+				Temp16 = VL_MAKEUINT16(lsb, msb);
+				PALDevDataSet(Dev, targetRefRate, Temp16);
+				break;
+			default: /* invalid parameter */
+				Status = VL_ERROR_INVALID_PARAMS;
+			}
+
+		} else if (NumberOfWrites <= 4) {
+			Address = *(pTuningSettingBuffer + Index);
+			Index++;
+
+			for (i = 0; i < NumberOfWrites; i++) {
+				localBuffer[i] = *(pTuningSettingBuffer +
+							Index);
+				Index++;
+			}
+
+			Status = VL_WriteMulti(Dev, Address, localBuffer,
+					NumberOfWrites);
+
+		} else {
+			Status = VL_ERROR_INVALID_PARAMS;
+		}
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_get_total_xtalk_rate(struct vl_data *Dev,
+	struct VL_RangingMeasurementData_t *pRangingMeasurementData,
+	unsigned int *ptotal_xtalk_rate_mcps)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	uint8_t xtalkCompEnable;
+	unsigned int totalXtalkMegaCps;
+	unsigned int xtalkPerSpadMegaCps;
+
+	*ptotal_xtalk_rate_mcps = 0;
+
+	Status = VL_GetXTalkCompensationEnable(Dev, &xtalkCompEnable);
+	if (Status == VL_ERROR_NONE) {
+
+		if (xtalkCompEnable) {
+
+			VL_GETPARAMETERFIELD(
+				Dev,
+				XTalkCompensationRateMegaCps,
+				xtalkPerSpadMegaCps);
+
+			/* FixPoint1616 * FixPoint 8:8 = FixPoint0824 */
+			totalXtalkMegaCps =
+				pRangingMeasurementData->EffectiveSpadRtnCount *
+				xtalkPerSpadMegaCps;
+
+			/* FixPoint0824 >> 8 = FixPoint1616 */
+			*ptotal_xtalk_rate_mcps =
+				(totalXtalkMegaCps + 0x80) >> 8;
+		}
+	}
+
+	return Status;
+}
+
+int8_t VL_get_total_signal_rate(struct vl_data *Dev,
+	struct VL_RangingMeasurementData_t *pRangingMeasurementData,
+	unsigned int *ptotal_signal_rate_mcps)
+{
+	int8_t Status = VL_ERROR_NONE;
+	unsigned int totalXtalkMegaCps;
+
+	LOG_FUNCTION_START("");
+
+	*ptotal_signal_rate_mcps =
+		pRangingMeasurementData->SignalRateRtnMegaCps;
+
+	Status = VL_get_total_xtalk_rate(
+		Dev, pRangingMeasurementData, &totalXtalkMegaCps);
+
+	if (Status == VL_ERROR_NONE)
+		*ptotal_signal_rate_mcps += totalXtalkMegaCps;
+
+	return Status;
+}
+
+int8_t VL_calc_dmax(
+	struct vl_data *Dev,
+	unsigned int totalSignalRate_mcps,
+	unsigned int totalCorrSignalRate_mcps,
+	unsigned int pwMult,
+	uint32_t sigmaEstimateP1,
+	unsigned int sigmaEstimateP2,
+	uint32_t peakVcselDuration_us,
+	uint32_t *pdmax_mm)
+{
+	const uint32_t cSigmaLimit		= 18;
+	const unsigned int cSignalLimit	= 0x4000; /* 0.25 */
+	const unsigned int cSigmaEstRef	= 0x00000042; /* 0.001 */
+	const uint32_t cAmbEffWidthSigmaEst_ns = 6;
+	const uint32_t cAmbEffWidthDMax_ns	   = 7;
+	uint32_t dmaxCalRange_mm;
+	unsigned int dmaxCalSignalRateRtn_mcps;
+	unsigned int minSignalNeeded;
+	unsigned int minSignalNeeded_p1;
+	unsigned int minSignalNeeded_p2;
+	unsigned int minSignalNeeded_p3;
+	unsigned int minSignalNeeded_p4;
+	unsigned int sigmaLimitTmp;
+	unsigned int sigmaEstSqTmp;
+	unsigned int signalLimitTmp;
+	unsigned int SignalAt0mm;
+	unsigned int dmaxDark;
+	unsigned int dmaxAmbient;
+	unsigned int dmaxDarkTmp;
+	unsigned int sigmaEstP2Tmp;
+	uint32_t signalRateTemp_mcps;
+
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	dmaxCalRange_mm =
+		PALDevDataGet(Dev, DmaxCalRangeMilliMeter);
+
+	dmaxCalSignalRateRtn_mcps =
+		PALDevDataGet(Dev, DmaxCalSignalRateRtnMegaCps);
+
+	/* uint32 * FixPoint1616 = FixPoint1616 */
+	SignalAt0mm = dmaxCalRange_mm * dmaxCalSignalRateRtn_mcps;
+
+	/* FixPoint1616 >> 8 = FixPoint2408 */
+	SignalAt0mm = (SignalAt0mm + 0x80) >> 8;
+	SignalAt0mm *= dmaxCalRange_mm;
+
+	minSignalNeeded_p1 = 0;
+	if (totalCorrSignalRate_mcps > 0) {
+
+		/* Shift by 10 bits to increase resolution prior to the */
+		/* division */
+		signalRateTemp_mcps = totalSignalRate_mcps << 10;
+
+		/* Add rounding value prior to division */
+		minSignalNeeded_p1 = signalRateTemp_mcps +
+			(totalCorrSignalRate_mcps/2);
+
+		/* FixPoint0626/FixPoint1616 = FixPoint2210 */
+		minSignalNeeded_p1 /= totalCorrSignalRate_mcps;
+
+		/* Apply a factored version of the speed of light. */
+		/* Correction to be applied at the end */
+		minSignalNeeded_p1 *= 3;
+
+		/* FixPoint2210 * FixPoint2210 = FixPoint1220 */
+		minSignalNeeded_p1 *= minSignalNeeded_p1;
+
+		/* FixPoint1220 >> 16 = FixPoint2804 */
+		minSignalNeeded_p1 = (minSignalNeeded_p1 + 0x8000) >> 16;
+	}
+
+	minSignalNeeded_p2 = pwMult * sigmaEstimateP1;
+
+	/* FixPoint1616 >> 16 =	 uint32 */
+	minSignalNeeded_p2 = (minSignalNeeded_p2 + 0x8000) >> 16;
+
+	/* uint32 * uint32	=  uint32 */
+	minSignalNeeded_p2 *= minSignalNeeded_p2;
+
+	/* Check sigmaEstimateP2
+	 * If this value is too high there is not enough signal rate
+	 * to calculate dmax value so set a suitable value to ensure
+	 * a very small dmax.
+	 */
+	sigmaEstP2Tmp = (sigmaEstimateP2 + 0x8000) >> 16;
+	sigmaEstP2Tmp = (sigmaEstP2Tmp + cAmbEffWidthSigmaEst_ns/2)/
+		cAmbEffWidthSigmaEst_ns;
+	sigmaEstP2Tmp *= cAmbEffWidthDMax_ns;
+
+	if (sigmaEstP2Tmp > 0xffff) {
+		minSignalNeeded_p3 = 0xfff00000;
+	} else {
+
+		/* DMAX uses a different ambient width from sigma, so apply
+		 * correction.
+		 * Perform division before multiplication to prevent overflow.
+		 */
+		sigmaEstimateP2 = (sigmaEstimateP2 + cAmbEffWidthSigmaEst_ns/2)/
+			cAmbEffWidthSigmaEst_ns;
+		sigmaEstimateP2 *= cAmbEffWidthDMax_ns;
+
+		/* FixPoint1616 >> 16 = uint32 */
+		minSignalNeeded_p3 = (sigmaEstimateP2 + 0x8000) >> 16;
+
+		minSignalNeeded_p3 *= minSignalNeeded_p3;
+
+	}
+
+	/* FixPoint1814 / uint32 = FixPoint1814 */
+	sigmaLimitTmp = ((cSigmaLimit << 14) + 500) / 1000;
+
+	/* FixPoint1814 * FixPoint1814 = FixPoint3628 := FixPoint0428 */
+	sigmaLimitTmp *= sigmaLimitTmp;
+
+	/* FixPoint1616 * FixPoint1616 = FixPoint3232 */
+	sigmaEstSqTmp = cSigmaEstRef * cSigmaEstRef;
+
+	/* FixPoint3232 >> 4 = FixPoint0428 */
+	sigmaEstSqTmp = (sigmaEstSqTmp + 0x08) >> 4;
+
+	/* FixPoint0428 - FixPoint0428	= FixPoint0428 */
+	sigmaLimitTmp -=  sigmaEstSqTmp;
+
+	/* uint32_t * FixPoint0428 = FixPoint0428 */
+	minSignalNeeded_p4 = 4 * 12 * sigmaLimitTmp;
+
+	/* FixPoint0428 >> 14 = FixPoint1814 */
+	minSignalNeeded_p4 = (minSignalNeeded_p4 + 0x2000) >> 14;
+
+	/* uint32 + uint32 = uint32 */
+	minSignalNeeded = (minSignalNeeded_p2 + minSignalNeeded_p3);
+
+	/* uint32 / uint32 = uint32 */
+	minSignalNeeded += (peakVcselDuration_us/2);
+	minSignalNeeded /= peakVcselDuration_us;
+
+	/* uint32 << 14 = FixPoint1814 */
+	minSignalNeeded <<= 14;
+
+	/* FixPoint1814 / FixPoint1814 = uint32 */
+	minSignalNeeded += (minSignalNeeded_p4/2);
+	minSignalNeeded /= minSignalNeeded_p4;
+
+	/* FixPoint3200 * FixPoint2804 := FixPoint2804*/
+	minSignalNeeded *= minSignalNeeded_p1;
+
+	/* Apply correction by dividing by 1000000.
+	 * This assumes 10E16 on the numerator of the equation
+	 * and 10E-22 on the denominator.
+	 * We do this because 32bit fix point calculation can't
+	 * handle the larger and smaller elements of this equation,
+	 * i.e. speed of light and pulse widths.
+	 */
+	minSignalNeeded = (minSignalNeeded + 500) / 1000;
+	minSignalNeeded <<= 4;
+
+	minSignalNeeded = (minSignalNeeded + 500) / 1000;
+
+	/* FixPoint1616 >> 8 = FixPoint2408 */
+	signalLimitTmp = (cSignalLimit + 0x80) >> 8;
+
+	/* FixPoint2408/FixPoint2408 = uint32 */
+	if (signalLimitTmp != 0)
+		dmaxDarkTmp = (SignalAt0mm + (signalLimitTmp / 2))
+			/ signalLimitTmp;
+	else
+		dmaxDarkTmp = 0;
+
+	dmaxDark = VL_isqrt(dmaxDarkTmp);
+
+	/* FixPoint2408/FixPoint2408 = uint32 */
+	if (minSignalNeeded != 0)
+		dmaxAmbient = (SignalAt0mm + minSignalNeeded/2)
+			/ minSignalNeeded;
+	else
+		dmaxAmbient = 0;
+
+	dmaxAmbient = VL_isqrt(dmaxAmbient);
+
+	*pdmax_mm = dmaxDark;
+	if (dmaxDark > dmaxAmbient)
+		*pdmax_mm = dmaxAmbient;
+
+	LOG_FUNCTION_END(Status);
+
+	return Status;
+}
+
+
+int8_t VL_calc_sigma_estimate(struct vl_data *Dev,
+	struct VL_RangingMeasurementData_t *pRangingMeasurementData,
+	unsigned int *pSigmaEstimate,
+	uint32_t *pDmax_mm)
+{
+	/* Expressed in 100ths of a ns, i.e. centi-ns */
+	const uint32_t cPulseEffectiveWidth_centi_ns   = 800;
+	/* Expressed in 100ths of a ns, i.e. centi-ns */
+	const uint32_t cAmbientEffectiveWidth_centi_ns = 600;
+	/* 25ms */
+	const unsigned int cDfltFinalRangeIntegrationTimeMilliSecs =
+		0x00190000;
+	const uint32_t cVcselPulseWidth_ps	= 4700; /* pico secs */
+	const unsigned int cSigmaEstMax	= 0x028F87AE;
+	const unsigned int cSigmaEstRtnMax	= 0xF000;
+	const unsigned int cAmbToSignalRatioMax = 0xF0000000/
+		cAmbientEffectiveWidth_centi_ns;
+	/* Time Of Flight per mm (6.6 pico secs) */
+	const unsigned int cTOF_per_mm_ps		= 0x0006999A;
+	const uint32_t c16BitRoundingParam		= 0x00008000;
+	const unsigned int cMaxXTalk_kcps		= 0x00320000;
+	const uint32_t cPllPeriod_ps			= 1655;
+
+	uint32_t vcselTotalEventsRtn;
+	uint32_t finalRangeTimeoutMicroSecs;
+	uint32_t preRangeTimeoutMicroSecs;
+	uint32_t finalRangeIntegrationTimeMilliSecs;
+	unsigned int sigmaEstimateP1;
+	unsigned int sigmaEstimateP2;
+	unsigned int sigmaEstimateP3;
+	unsigned int deltaT_ps;
+	unsigned int pwMult;
+	unsigned int sigmaEstRtn;
+	unsigned int sigmaEstimate;
+	unsigned int xTalkCorrection;
+	unsigned int ambientRate_kcps;
+	unsigned int peakSignalRate_kcps;
+	unsigned int xTalkCompRate_mcps;
+	uint32_t xTalkCompRate_kcps;
+	int8_t Status = VL_ERROR_NONE;
+	unsigned int diff1_mcps;
+	unsigned int diff2_mcps;
+	unsigned int sqr1;
+	unsigned int sqr2;
+	unsigned int sqrSum;
+	unsigned int sqrtResult_centi_ns;
+	unsigned int sqrtResult;
+	unsigned int totalSignalRate_mcps;
+	unsigned int correctedSignalRate_mcps;
+	unsigned int sigmaEstRef;
+	uint32_t vcselWidth;
+	uint32_t finalRangeMacroPCLKS;
+	uint32_t preRangeMacroPCLKS;
+	uint32_t peakVcselDuration_us;
+	uint8_t finalRangeVcselPCLKS;
+	uint8_t preRangeVcselPCLKS;
+	/*! \addtogroup calc_sigma_estimate
+	 * @{
+	 *
+	 * Estimates the range sigma
+	 */
+
+	LOG_FUNCTION_START("");
+
+	VL_GETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps,
+			xTalkCompRate_mcps);
+
+	/*
+	 * We work in kcps rather than mcps as this helps keep within the
+	 * confines of the 32 Fix1616 type.
+	 */
+
+	ambientRate_kcps =
+		(pRangingMeasurementData->AmbientRateRtnMegaCps * 1000) >> 16;
+
+	correctedSignalRate_mcps =
+		pRangingMeasurementData->SignalRateRtnMegaCps;
+
+
+	Status = VL_get_total_signal_rate(
+		Dev, pRangingMeasurementData, &totalSignalRate_mcps);
+	Status = VL_get_total_xtalk_rate(
+		Dev, pRangingMeasurementData, &xTalkCompRate_mcps);
+
+
+	/* Signal rate measurement provided by device is the
+	 * peak signal rate, not average.
+	 */
+	peakSignalRate_kcps = (totalSignalRate_mcps * 1000);
+	peakSignalRate_kcps = (peakSignalRate_kcps + 0x8000) >> 16;
+
+	xTalkCompRate_kcps = xTalkCompRate_mcps * 1000;
+
+	if (xTalkCompRate_kcps > cMaxXTalk_kcps)
+		xTalkCompRate_kcps = cMaxXTalk_kcps;
+
+	if (Status == VL_ERROR_NONE) {
+
+		/* Calculate final range macro periods */
+		finalRangeTimeoutMicroSecs = VL_GETDEVICESPECIFICPARAMETER(
+			Dev, FinalRangeTimeoutMicroSecs);
+
+		finalRangeVcselPCLKS = VL_GETDEVICESPECIFICPARAMETER(
+			Dev, FinalRangeVcselPulsePeriod);
+
+		finalRangeMacroPCLKS = VL_calc_timeout_mclks(
+			Dev, finalRangeTimeoutMicroSecs, finalRangeVcselPCLKS);
+
+		/* Calculate pre-range macro periods */
+		preRangeTimeoutMicroSecs = VL_GETDEVICESPECIFICPARAMETER(
+			Dev, PreRangeTimeoutMicroSecs);
+
+		preRangeVcselPCLKS = VL_GETDEVICESPECIFICPARAMETER(
+			Dev, PreRangeVcselPulsePeriod);
+
+		preRangeMacroPCLKS = VL_calc_timeout_mclks(
+			Dev, preRangeTimeoutMicroSecs, preRangeVcselPCLKS);
+
+		vcselWidth = 3;
+		if (finalRangeVcselPCLKS == 8)
+			vcselWidth = 2;
+
+
+		peakVcselDuration_us = vcselWidth * 2048 *
+			(preRangeMacroPCLKS + finalRangeMacroPCLKS);
+		peakVcselDuration_us = (peakVcselDuration_us + 500)/1000;
+		peakVcselDuration_us *= cPllPeriod_ps;
+		peakVcselDuration_us = (peakVcselDuration_us + 500)/1000;
+
+		/* Fix1616 >> 8 = Fix2408 */
+		totalSignalRate_mcps = (totalSignalRate_mcps + 0x80) >> 8;
+
+		/* Fix2408 * uint32 = Fix2408 */
+		vcselTotalEventsRtn = totalSignalRate_mcps *
+			peakVcselDuration_us;
+
+		/* Fix2408 >> 8 = uint32 */
+		vcselTotalEventsRtn = (vcselTotalEventsRtn + 0x80) >> 8;
+
+		/* Fix2408 << 8 = Fix1616 = */
+		totalSignalRate_mcps <<= 8;
+	}
+
+	if (Status != VL_ERROR_NONE) {
+		LOG_FUNCTION_END(Status);
+		return Status;
+	}
+
+	if (peakSignalRate_kcps == 0) {
+		*pSigmaEstimate = cSigmaEstMax;
+		PALDevDataSet(Dev, SigmaEstimate, cSigmaEstMax);
+		*pDmax_mm = 0;
+	} else {
+		if (vcselTotalEventsRtn < 1)
+			vcselTotalEventsRtn = 1;
+
+		sigmaEstimateP1 = cPulseEffectiveWidth_centi_ns;
+
+		/* ((FixPoint1616 << 16)* uint32)/uint32 = FixPoint1616 */
+		sigmaEstimateP2 = (ambientRate_kcps << 16)/peakSignalRate_kcps;
+		if (sigmaEstimateP2 > cAmbToSignalRatioMax) {
+			/* Clip to prevent overflow. Will ensure safe */
+			/* max result. */
+			sigmaEstimateP2 = cAmbToSignalRatioMax;
+		}
+		sigmaEstimateP2 *= cAmbientEffectiveWidth_centi_ns;
+
+		sigmaEstimateP3 = 2 * VL_isqrt(vcselTotalEventsRtn * 12);
+
+		/* uint32 * FixPoint1616 = FixPoint1616 */
+		deltaT_ps = pRangingMeasurementData->RangeMilliMeter *
+					cTOF_per_mm_ps;
+
+		/* vcselRate - xtalkCompRate */
+		/* (uint32 << 16) - FixPoint1616 = FixPoint1616. */
+		/* Divide result by 1000 to convert to mcps. */
+		/* 500 is added to ensure rounding when integer division */
+		/* truncates. */
+		diff1_mcps = (((peakSignalRate_kcps << 16) -
+			2 * xTalkCompRate_kcps) + 500)/1000;
+
+		/* vcselRate + xtalkCompRate */
+		diff2_mcps = ((peakSignalRate_kcps << 16) + 500)/1000;
+
+		/* Shift by 8 bits to increase resolution prior to the */
+		/* division */
+		diff1_mcps <<= 8;
+
+		/* FixPoint0824/FixPoint1616 = FixPoint2408 */
+		xTalkCorrection	 = abs(diff1_mcps/diff2_mcps);
+
+		/* FixPoint2408 << 8 = FixPoint1616 */
+		xTalkCorrection <<= 8;
+
+		if (pRangingMeasurementData->RangeStatus != 0) {
+			pwMult = 1 << 16;
+		} else {
+			/* FixPoint1616/uint32 = FixPoint1616 *i */
+			/* smaller than 1.0f */
+			pwMult = deltaT_ps/cVcselPulseWidth_ps;
+
+		/* FixPoint1616 * FixPoint1616 = FixPoint3232, however both */
+		/* values are small enough such that32 bits will not be */
+		/* exceeded. */
+			pwMult *= ((1 << 16) - xTalkCorrection);
+
+			/* (FixPoint3232 >> 16) = FixPoint1616 */
+			pwMult =  (pwMult + c16BitRoundingParam) >> 16;
+
+			/* FixPoint1616 + FixPoint1616 = FixPoint1616 */
+			pwMult += (1 << 16);
+
+		/* At this point the value will be 1.xx, */
+		/* therefore if we square */
+		/* the value this will exceed 32 bits. */
+		/* To address this perform */
+		/* a single shift to the right before the multiplication. */
+			pwMult >>= 1;
+			/* FixPoint1715 * FixPoint1715 = FixPoint3430 */
+			pwMult = pwMult * pwMult;
+
+			/* (FixPoint3430 >> 14) = Fix1616 */
+			pwMult >>= 14;
+		}
+
+		/* FixPoint1616 * uint32 = FixPoint1616 */
+		sqr1 = pwMult * sigmaEstimateP1;
+
+		/* (FixPoint1616 >> 16) = FixPoint3200 */
+		sqr1 = (sqr1 + 0x8000) >> 16;
+
+		/* FixPoint3200 * FixPoint3200 = FixPoint6400 */
+		sqr1 *= sqr1;
+
+		sqr2 = sigmaEstimateP2;
+
+		/* (FixPoint1616 >> 16) = FixPoint3200 */
+		sqr2 = (sqr2 + 0x8000) >> 16;
+
+		/* FixPoint3200 * FixPoint3200 = FixPoint6400 */
+		sqr2 *= sqr2;
+
+		/* FixPoint64000 + FixPoint6400 = FixPoint6400 */
+		sqrSum = sqr1 + sqr2;
+
+		/* SQRT(FixPoin6400) = FixPoint3200 */
+		sqrtResult_centi_ns = VL_isqrt(sqrSum);
+
+		/* (FixPoint3200 << 16) = FixPoint1616 */
+		sqrtResult_centi_ns <<= 16;
+
+		/*
+		 * Note that the Speed Of Light is expressed in um per 1E-10
+		 * seconds (2997) Therefore to get mm/ns we have to divide by
+		 * 10000
+		 */
+		sigmaEstRtn = (((sqrtResult_centi_ns+50)/100) /
+				sigmaEstimateP3);
+		sigmaEstRtn		 *= VL_SPEED_OF_LIGHT_IN_AIR;
+
+		/* Add 5000 before dividing by 10000 to ensure rounding. */
+		sigmaEstRtn		 += 5000;
+		sigmaEstRtn		 /= 10000;
+
+		if (sigmaEstRtn > cSigmaEstRtnMax) {
+			/* Clip to prevent overflow. Will ensure safe */
+			/* max result. */
+			sigmaEstRtn = cSigmaEstRtnMax;
+		}
+		finalRangeIntegrationTimeMilliSecs =
+		    (finalRangeTimeoutMicroSecs +
+			preRangeTimeoutMicroSecs + 500)/1000;
+
+		/* sigmaEstRef = 1mm * 25ms/final range integration time */
+		/* (inc pre-range) sqrt(FixPoint1616/int) = FixPoint2408) */
+		sigmaEstRef =
+			VL_isqrt((cDfltFinalRangeIntegrationTimeMilliSecs +
+				finalRangeIntegrationTimeMilliSecs/2)/
+				finalRangeIntegrationTimeMilliSecs);
+
+		/* FixPoint2408 << 8 = FixPoint1616 */
+		sigmaEstRef <<= 8;
+		sigmaEstRef = (sigmaEstRef + 500)/1000;
+
+		/* FixPoint1616 * FixPoint1616 = FixPoint3232 */
+		sqr1 = sigmaEstRtn * sigmaEstRtn;
+		/* FixPoint1616 * FixPoint1616 = FixPoint3232 */
+		sqr2 = sigmaEstRef * sigmaEstRef;
+
+		/* sqrt(FixPoint3232) = FixPoint1616 */
+		sqrtResult = VL_isqrt((sqr1 + sqr2));
+		/* Note that the Shift by 4 bits increases */
+		/*resolution prior to */
+		/* the sqrt, therefore the result must be */
+		/* shifted by 2 bits to */
+		/* the right to revert back to the FixPoint1616 format. */
+
+		sigmaEstimate	 = 1000 * sqrtResult;
+
+		if ((peakSignalRate_kcps < 1) || (vcselTotalEventsRtn < 1) ||
+			(sigmaEstimate > cSigmaEstMax)) {
+			sigmaEstimate = cSigmaEstMax;
+		}
+
+		*pSigmaEstimate = (uint32_t)(sigmaEstimate);
+		PALDevDataSet(Dev, SigmaEstimate, *pSigmaEstimate);
+		Status = VL_calc_dmax(
+			Dev,
+			totalSignalRate_mcps,
+			correctedSignalRate_mcps,
+			pwMult,
+			sigmaEstimateP1,
+			sigmaEstimateP2,
+			peakVcselDuration_us,
+			pDmax_mm);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_get_pal_range_status(struct vl_data *Dev,
+		uint8_t DeviceRangeStatus,
+		unsigned int SignalRate,
+		uint16_t EffectiveSpadRtnCount,
+		struct VL_RangingMeasurementData_t *pRangingMeasurementData,
+		uint8_t *pPalRangeStatus)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t NoneFlag;
+	uint8_t SigmaLimitflag = 0;
+	uint8_t SignalRefClipflag = 0;
+	uint8_t RangeIgnoreThresholdflag = 0;
+	uint8_t SigmaLimitCheckEnable = 0;
+	uint8_t SignalRateFinalRangeLimitCheckEnable = 0;
+	uint8_t SignalRefClipLimitCheckEnable = 0;
+	uint8_t RangeIgnoreThresholdLimitCheckEnable = 0;
+	unsigned int SigmaEstimate;
+	unsigned int SigmaLimitValue;
+	unsigned int SignalRefClipValue;
+	unsigned int RangeIgnoreThresholdValue;
+	unsigned int SignalRatePerSpad;
+	uint8_t DeviceRangeStatusInternal = 0;
+	uint16_t tmpWord = 0;
+	uint8_t Temp8;
+	uint32_t Dmax_mm = 0;
+	unsigned int LastSignalRefMcps;
+
+	LOG_FUNCTION_START("");
+
+
+	/*
+	 * VL53L0X has a good ranging when the value of the
+	 * DeviceRangeStatus = 11. This function will replace the value 0 with
+	 * the value 11 in the DeviceRangeStatus.
+	 * In addition, the SigmaEstimator is not included in the VL53L0X
+	 * DeviceRangeStatus, this will be added in the PalRangeStatus.
+	 */
+
+	DeviceRangeStatusInternal = ((DeviceRangeStatus & 0x78) >> 3);
+
+	if (DeviceRangeStatusInternal == 0 ||
+		DeviceRangeStatusInternal == 5 ||
+		DeviceRangeStatusInternal == 7 ||
+		DeviceRangeStatusInternal == 12 ||
+		DeviceRangeStatusInternal == 13 ||
+		DeviceRangeStatusInternal == 14 ||
+		DeviceRangeStatusInternal == 15
+			) {
+		NoneFlag = 1;
+	} else {
+		NoneFlag = 0;
+	}
+
+	/*
+	 * Check if Sigma limit is enabled, if yes then do comparison with limit
+	 * value and put the result back into pPalRangeStatus.
+	 */
+	if (Status == VL_ERROR_NONE)
+		Status =  VL_GetLimitCheckEnable(Dev,
+			VL_CHECKENABLE_SIGMA_FINAL_RANGE,
+			&SigmaLimitCheckEnable);
+
+	if ((SigmaLimitCheckEnable != 0) && (Status == VL_ERROR_NONE)) {
+		/* compute the Sigma and check with limit */
+		Status = VL_calc_sigma_estimate(
+			Dev,
+			pRangingMeasurementData,
+			&SigmaEstimate,
+			&Dmax_mm);
+		if (Status == VL_ERROR_NONE)
+			pRangingMeasurementData->RangeDMaxMilliMeter = Dmax_mm;
+
+		if (Status == VL_ERROR_NONE) {
+			Status = VL_GetLimitCheckValue(Dev,
+				VL_CHECKENABLE_SIGMA_FINAL_RANGE,
+				&SigmaLimitValue);
+
+			if ((SigmaLimitValue > 0) &&
+				(SigmaEstimate > SigmaLimitValue))
+				/* Limit Fail */
+				SigmaLimitflag = 1;
+		}
+	}
+
+	/* Check if Signal ref clip limit is enabled, */
+	/* if yes then do comparison */
+	/* with limit value and put the result back into pPalRangeStatus. */
+	if (Status == VL_ERROR_NONE)
+		Status =  VL_GetLimitCheckEnable(Dev,
+				VL_CHECKENABLE_SIGNAL_REF_CLIP,
+				&SignalRefClipLimitCheckEnable);
+
+	if ((SignalRefClipLimitCheckEnable != 0) &&
+			(Status == VL_ERROR_NONE)) {
+
+		Status = VL_GetLimitCheckValue(Dev,
+				VL_CHECKENABLE_SIGNAL_REF_CLIP,
+				&SignalRefClipValue);
+
+		/* Read LastSignalRefMcps from device */
+		if (Status == VL_ERROR_NONE)
+			Status = VL_WrByte(Dev, 0xFF, 0x01);
+
+		if (Status == VL_ERROR_NONE)
+			Status = VL_RdWord(Dev,
+				VL_REG_RESULT_PEAK_SIGNAL_RATE_REF,
+				&tmpWord);
+
+		if (Status == VL_ERROR_NONE)
+			Status = VL_WrByte(Dev, 0xFF, 0x00);
+
+		LastSignalRefMcps = VL_FIXPOINT97TOFIXPOINT1616(tmpWord);
+		PALDevDataSet(Dev, LastSignalRefMcps, LastSignalRefMcps);
+
+		if ((SignalRefClipValue > 0) &&
+				(LastSignalRefMcps > SignalRefClipValue)) {
+			/* Limit Fail */
+			SignalRefClipflag = 1;
+		}
+	}
+
+	/*
+	 * Check if Signal ref clip limit is enabled, if yes then do comparison
+	 * with limit value and put the result back into pPalRangeStatus.
+	 * EffectiveSpadRtnCount has a format 8.8
+	 * If (Return signal rate < (1.5 x Xtalk x number of Spads)) : FAIL
+	 */
+	if (Status == VL_ERROR_NONE)
+		Status =  VL_GetLimitCheckEnable(Dev,
+				VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+				&RangeIgnoreThresholdLimitCheckEnable);
+
+	if ((RangeIgnoreThresholdLimitCheckEnable != 0) &&
+			(Status == VL_ERROR_NONE)) {
+
+		/* Compute the signal rate per spad */
+		if (EffectiveSpadRtnCount == 0) {
+			SignalRatePerSpad = 0;
+		} else {
+			SignalRatePerSpad = (unsigned int)((256 * SignalRate)
+				/ EffectiveSpadRtnCount);
+		}
+
+		Status = VL_GetLimitCheckValue(Dev,
+				VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+				&RangeIgnoreThresholdValue);
+
+		if ((RangeIgnoreThresholdValue > 0) &&
+			(SignalRatePerSpad < RangeIgnoreThresholdValue)) {
+			/* Limit Fail add 2^6 to range status */
+			RangeIgnoreThresholdflag = 1;
+		}
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		if (NoneFlag == 1) {
+			*pPalRangeStatus = 255;	 /* NONE */
+		} else if (DeviceRangeStatusInternal == 1 ||
+					DeviceRangeStatusInternal == 2 ||
+					DeviceRangeStatusInternal == 3) {
+			*pPalRangeStatus = 5; /* HW fail */
+		} else if (DeviceRangeStatusInternal == 6 ||
+					DeviceRangeStatusInternal == 9) {
+			*pPalRangeStatus = 4;  /* Phase fail */
+		} else if (DeviceRangeStatusInternal == 8 ||
+					DeviceRangeStatusInternal == 10 ||
+					SignalRefClipflag == 1) {
+			*pPalRangeStatus = 3;  /* Min range */
+		} else if (DeviceRangeStatusInternal == 4 ||
+					RangeIgnoreThresholdflag == 1) {
+			*pPalRangeStatus = 2;  /* Signal Fail */
+		} else if (SigmaLimitflag == 1) {
+			*pPalRangeStatus = 1;  /* Sigma	 Fail */
+		} else {
+			*pPalRangeStatus = 0; /* Range Valid */
+		}
+	}
+
+	/* DMAX only relevant during range error */
+	if (*pPalRangeStatus == 0)
+		pRangingMeasurementData->RangeDMaxMilliMeter = 0;
+
+	/* fill the Limit Check Status */
+
+	Status =  VL_GetLimitCheckEnable(Dev,
+			VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+			&SignalRateFinalRangeLimitCheckEnable);
+
+	if (Status == VL_ERROR_NONE) {
+		if ((SigmaLimitCheckEnable == 0) || (SigmaLimitflag == 1))
+			Temp8 = 1;
+		else
+			Temp8 = 0;
+		VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
+				VL_CHECKENABLE_SIGMA_FINAL_RANGE, Temp8);
+
+		if ((DeviceRangeStatusInternal == 4) ||
+				(SignalRateFinalRangeLimitCheckEnable == 0))
+			Temp8 = 1;
+		else
+			Temp8 = 0;
+		VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
+				VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+				Temp8);
+
+		if ((SignalRefClipLimitCheckEnable == 0) ||
+					(SignalRefClipflag == 1))
+			Temp8 = 1;
+		else
+			Temp8 = 0;
+
+		VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
+				VL_CHECKENABLE_SIGNAL_REF_CLIP, Temp8);
+
+		if ((RangeIgnoreThresholdLimitCheckEnable == 0) ||
+				(RangeIgnoreThresholdflag == 1))
+			Temp8 = 1;
+		else
+			Temp8 = 0;
+
+		VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
+				VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+				Temp8);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+
+}
diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api_ranging.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api_ranging.c
new file mode 100644
index 0000000..a1f4683
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api_ranging.c
@@ -0,0 +1,32 @@
+/*
+ *  vl53l0x_api_ranging.c - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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 "vl53l0x_api.h"
+#include "vl53l0x_api_core.h"
+
+
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
+#define LOG_FUNCTION_START(fmt, ...) \
+	_LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+	_LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
+	_LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
+
diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api_strings.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api_strings.c
new file mode 100644
index 0000000..71fec10
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api_strings.c
@@ -0,0 +1,455 @@
+/*
+ *  vl53l0x_api_strings.c - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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 "vl53l0x_api.h"
+#include "vl53l0x_api_core.h"
+#include "vl53l0x_api_strings.h"
+
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
+
+#define LOG_FUNCTION_START(fmt, ...) \
+	_LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+	_LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
+	_LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
+
+
+int8_t VL_check_part_used(struct vl_data *Dev,
+		uint8_t *Revision,
+		struct VL_DeviceInfo_t *pVL_DeviceInfo)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t ModuleIdInt;
+	char *ProductId_tmp;
+
+	LOG_FUNCTION_START("");
+
+	Status = VL_get_info_from_device(Dev, 2);
+
+	if (Status == VL_ERROR_NONE) {
+		ModuleIdInt = VL_GETDEVICESPECIFICPARAMETER(Dev, ModuleId);
+
+	if (ModuleIdInt == 0) {
+		*Revision = 0;
+		VL_COPYSTRING(pVL_DeviceInfo->ProductId, "");
+	} else {
+		*Revision = VL_GETDEVICESPECIFICPARAMETER(Dev, Revision);
+		ProductId_tmp = VL_GETDEVICESPECIFICPARAMETER(Dev,
+			ProductId);
+		VL_COPYSTRING(pVL_DeviceInfo->ProductId,
+			ProductId_tmp);
+	}
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+
+int8_t VL_get_device_info(struct vl_data *Dev,
+				struct VL_DeviceInfo_t *pVL_DeviceInfo)
+{
+	int8_t Status = VL_ERROR_NONE;
+	uint8_t revision_id;
+	uint8_t Revision;
+
+	Status = VL_check_part_used(Dev, &Revision, pVL_DeviceInfo);
+
+	if (Status == VL_ERROR_NONE) {
+		if (Revision == 0) {
+			VL_COPYSTRING(pVL_DeviceInfo->Name,
+					VL_STRING_DEVICE_INFO_NAME_TS0);
+		} else if ((Revision <= 34) && (Revision != 32)) {
+			VL_COPYSTRING(pVL_DeviceInfo->Name,
+					VL_STRING_DEVICE_INFO_NAME_TS1);
+		} else if (Revision < 39) {
+			VL_COPYSTRING(pVL_DeviceInfo->Name,
+					VL_STRING_DEVICE_INFO_NAME_TS2);
+		} else {
+			VL_COPYSTRING(pVL_DeviceInfo->Name,
+					VL_STRING_DEVICE_INFO_NAME_ES1);
+		}
+
+		VL_COPYSTRING(pVL_DeviceInfo->Type,
+				VL_STRING_DEVICE_INFO_TYPE);
+
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		Status = VL_RdByte(Dev,
+			VL_REG_IDENTIFICATION_MODEL_ID,
+			&pVL_DeviceInfo->ProductType);
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		Status = VL_RdByte(Dev,
+			VL_REG_IDENTIFICATION_REVISION_ID,
+				&revision_id);
+		pVL_DeviceInfo->ProductRevisionMajor = 1;
+		pVL_DeviceInfo->ProductRevisionMinor =
+					(revision_id & 0xF0) >> 4;
+	}
+
+	return Status;
+}
+
+
+int8_t VL_get_device_error_string(uint8_t ErrorCode,
+		char *pDeviceErrorString)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	switch (ErrorCode) {
+	case VL_DEVICEERROR_NONE:
+		VL_COPYSTRING(pDeviceErrorString,
+			VL_STRING_DEVICEERROR_NONE);
+	break;
+	case VL_DEVICEERROR_VCSELCONTINUITYTESTFAILURE:
+		VL_COPYSTRING(pDeviceErrorString,
+			VL_STRING_DEVICEERROR_VCSELCONTINUITYTESTFAILURE);
+	break;
+	case VL_DEVICEERROR_VCSELWATCHDOGTESTFAILURE:
+		VL_COPYSTRING(pDeviceErrorString,
+			VL_STRING_DEVICEERROR_VCSELWATCHDOGTESTFAILURE);
+	break;
+	case VL_DEVICEERROR_NOVHVVALUEFOUND:
+		VL_COPYSTRING(pDeviceErrorString,
+			VL_STRING_DEVICEERROR_NOVHVVALUEFOUND);
+	break;
+	case VL_DEVICEERROR_MSRCNOTARGET:
+		VL_COPYSTRING(pDeviceErrorString,
+			VL_STRING_DEVICEERROR_MSRCNOTARGET);
+	break;
+	case VL_DEVICEERROR_SNRCHECK:
+		VL_COPYSTRING(pDeviceErrorString,
+			VL_STRING_DEVICEERROR_SNRCHECK);
+	break;
+	case VL_DEVICEERROR_RANGEPHASECHECK:
+		VL_COPYSTRING(pDeviceErrorString,
+			VL_STRING_DEVICEERROR_RANGEPHASECHECK);
+	break;
+	case VL_DEVICEERROR_SIGMATHRESHOLDCHECK:
+		VL_COPYSTRING(pDeviceErrorString,
+			VL_STRING_DEVICEERROR_SIGMATHRESHOLDCHECK);
+	break;
+	case VL_DEVICEERROR_TCC:
+		VL_COPYSTRING(pDeviceErrorString,
+			VL_STRING_DEVICEERROR_TCC);
+	break;
+	case VL_DEVICEERROR_PHASECONSISTENCY:
+		VL_COPYSTRING(pDeviceErrorString,
+			VL_STRING_DEVICEERROR_PHASECONSISTENCY);
+	break;
+	case VL_DEVICEERROR_MINCLIP:
+		VL_COPYSTRING(pDeviceErrorString,
+			VL_STRING_DEVICEERROR_MINCLIP);
+	break;
+	case VL_DEVICEERROR_RANGECOMPLETE:
+		VL_COPYSTRING(pDeviceErrorString,
+			VL_STRING_DEVICEERROR_RANGECOMPLETE);
+	break;
+	case VL_DEVICEERROR_ALGOUNDERFLOW:
+		VL_COPYSTRING(pDeviceErrorString,
+			VL_STRING_DEVICEERROR_ALGOUNDERFLOW);
+	break;
+	case VL_DEVICEERROR_ALGOOVERFLOW:
+		VL_COPYSTRING(pDeviceErrorString,
+			VL_STRING_DEVICEERROR_ALGOOVERFLOW);
+	break;
+	case VL_DEVICEERROR_RANGEIGNORETHRESHOLD:
+		VL_COPYSTRING(pDeviceErrorString,
+			VL_STRING_DEVICEERROR_RANGEIGNORETHRESHOLD);
+	break;
+
+	default:
+		VL_COPYSTRING(pDeviceErrorString,
+			VL_STRING_UNKNOWN_ERROR_CODE);
+
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_get_range_status_string(uint8_t RangeStatus,
+		char *pRangeStatusString)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	switch (RangeStatus) {
+	case 0:
+		VL_COPYSTRING(pRangeStatusString,
+			VL_STRING_RANGESTATUS_RANGEVALID);
+	break;
+	case 1:
+		VL_COPYSTRING(pRangeStatusString,
+			VL_STRING_RANGESTATUS_SIGMA);
+	break;
+	case 2:
+		VL_COPYSTRING(pRangeStatusString,
+			VL_STRING_RANGESTATUS_SIGNAL);
+	break;
+	case 3:
+		VL_COPYSTRING(pRangeStatusString,
+			VL_STRING_RANGESTATUS_MINRANGE);
+	break;
+	case 4:
+		VL_COPYSTRING(pRangeStatusString,
+			VL_STRING_RANGESTATUS_PHASE);
+	break;
+	case 5:
+		VL_COPYSTRING(pRangeStatusString,
+			VL_STRING_RANGESTATUS_HW);
+	break;
+
+	default: /**/
+		VL_COPYSTRING(pRangeStatusString,
+				VL_STRING_RANGESTATUS_NONE);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_get_pal_error_string(int8_t PalErrorCode,
+		char *pPalErrorString)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	switch (PalErrorCode) {
+	case VL_ERROR_NONE:
+		VL_COPYSTRING(pPalErrorString,
+			VL_STRING_ERROR_NONE);
+	break;
+	case VL_ERROR_CALIBRATION_WARNING:
+		VL_COPYSTRING(pPalErrorString,
+			VL_STRING_ERROR_CALIBRATION_WARNING);
+	break;
+	case VL_ERROR_MIN_CLIPPED:
+		VL_COPYSTRING(pPalErrorString,
+			VL_STRING_ERROR_MIN_CLIPPED);
+	break;
+	case VL_ERROR_UNDEFINED:
+		VL_COPYSTRING(pPalErrorString,
+			VL_STRING_ERROR_UNDEFINED);
+	break;
+	case VL_ERROR_INVALID_PARAMS:
+		VL_COPYSTRING(pPalErrorString,
+			VL_STRING_ERROR_INVALID_PARAMS);
+	break;
+	case VL_ERROR_NOT_SUPPORTED:
+		VL_COPYSTRING(pPalErrorString,
+			VL_STRING_ERROR_NOT_SUPPORTED);
+	break;
+	case VL_ERROR_INTERRUPT_NOT_CLEARED:
+		VL_COPYSTRING(pPalErrorString,
+			VL_STRING_ERROR_INTERRUPT_NOT_CLEARED);
+	break;
+	case VL_ERROR_RANGE_ERROR:
+		VL_COPYSTRING(pPalErrorString,
+			VL_STRING_ERROR_RANGE_ERROR);
+	break;
+	case VL_ERROR_TIME_OUT:
+		VL_COPYSTRING(pPalErrorString,
+			VL_STRING_ERROR_TIME_OUT);
+	break;
+	case VL_ERROR_MODE_NOT_SUPPORTED:
+		VL_COPYSTRING(pPalErrorString,
+			VL_STRING_ERROR_MODE_NOT_SUPPORTED);
+	break;
+	case VL_ERROR_BUFFER_TOO_SMALL:
+		VL_COPYSTRING(pPalErrorString,
+			VL_STRING_ERROR_BUFFER_TOO_SMALL);
+	break;
+	case VL_ERROR_GPIO_NOT_EXISTING:
+		VL_COPYSTRING(pPalErrorString,
+			VL_STRING_ERROR_GPIO_NOT_EXISTING);
+	break;
+	case VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED:
+		VL_COPYSTRING(pPalErrorString,
+			VL_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED);
+	break;
+	case VL_ERROR_CONTROL_INTERFACE:
+		VL_COPYSTRING(pPalErrorString,
+			VL_STRING_ERROR_CONTROL_INTERFACE);
+	break;
+	case VL_ERROR_INVALID_COMMAND:
+		VL_COPYSTRING(pPalErrorString,
+			VL_STRING_ERROR_INVALID_COMMAND);
+	break;
+	case VL_ERROR_DIVISION_BY_ZERO:
+		VL_COPYSTRING(pPalErrorString,
+			VL_STRING_ERROR_DIVISION_BY_ZERO);
+	break;
+	case VL_ERROR_REF_SPAD_INIT:
+		VL_COPYSTRING(pPalErrorString,
+			VL_STRING_ERROR_REF_SPAD_INIT);
+	break;
+	case VL_ERROR_NOT_IMPLEMENTED:
+		VL_COPYSTRING(pPalErrorString,
+			VL_STRING_ERROR_NOT_IMPLEMENTED);
+	break;
+
+	default:
+		VL_COPYSTRING(pPalErrorString,
+				VL_STRING_UNKNOWN_ERROR_CODE);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_get_pal_state_string(uint8_t PalStateCode,
+		char *pPalStateString)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	switch (PalStateCode) {
+	case VL_STATE_POWERDOWN:
+		VL_COPYSTRING(pPalStateString,
+			VL_STRING_STATE_POWERDOWN);
+	break;
+	case VL_STATE_WAIT_STATICINIT:
+		VL_COPYSTRING(pPalStateString,
+			VL_STRING_STATE_WAIT_STATICINIT);
+	break;
+	case VL_STATE_STANDBY:
+		VL_COPYSTRING(pPalStateString,
+			VL_STRING_STATE_STANDBY);
+	break;
+	case VL_STATE_IDLE:
+		VL_COPYSTRING(pPalStateString,
+			VL_STRING_STATE_IDLE);
+	break;
+	case VL_STATE_RUNNING:
+		VL_COPYSTRING(pPalStateString,
+			VL_STRING_STATE_RUNNING);
+	break;
+	case VL_STATE_UNKNOWN:
+		VL_COPYSTRING(pPalStateString,
+			VL_STRING_STATE_UNKNOWN);
+	break;
+	case VL_STATE_ERROR:
+		VL_COPYSTRING(pPalStateString,
+			VL_STRING_STATE_ERROR);
+	break;
+
+	default:
+		VL_COPYSTRING(pPalStateString,
+			VL_STRING_STATE_UNKNOWN);
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
+
+int8_t VL_get_sequence_steps_info(
+		uint8_t SequenceStepId,
+		char *pSequenceStepsString)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	switch (SequenceStepId) {
+	case VL_SEQUENCESTEP_TCC:
+		VL_COPYSTRING(pSequenceStepsString,
+			VL_STRING_SEQUENCESTEP_TCC);
+	break;
+	case VL_SEQUENCESTEP_DSS:
+		VL_COPYSTRING(pSequenceStepsString,
+			VL_STRING_SEQUENCESTEP_DSS);
+	break;
+	case VL_SEQUENCESTEP_MSRC:
+		VL_COPYSTRING(pSequenceStepsString,
+			VL_STRING_SEQUENCESTEP_MSRC);
+	break;
+	case VL_SEQUENCESTEP_PRE_RANGE:
+		VL_COPYSTRING(pSequenceStepsString,
+			VL_STRING_SEQUENCESTEP_PRE_RANGE);
+	break;
+	case VL_SEQUENCESTEP_FINAL_RANGE:
+		VL_COPYSTRING(pSequenceStepsString,
+			VL_STRING_SEQUENCESTEP_FINAL_RANGE);
+	break;
+
+	default:
+		Status = VL_ERROR_INVALID_PARAMS;
+	}
+
+	LOG_FUNCTION_END(Status);
+
+	return Status;
+}
+
+
+int8_t VL_get_limit_check_info(struct vl_data *Dev,
+	uint16_t LimitCheckId, char *pLimitCheckString)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+
+	switch (LimitCheckId) {
+	case VL_CHECKENABLE_SIGMA_FINAL_RANGE:
+		VL_COPYSTRING(pLimitCheckString,
+			VL_STRING_CHECKENABLE_SIGMA_FINAL_RANGE);
+	break;
+	case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
+		VL_COPYSTRING(pLimitCheckString,
+			VL_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE);
+	break;
+	case VL_CHECKENABLE_SIGNAL_REF_CLIP:
+		VL_COPYSTRING(pLimitCheckString,
+			VL_STRING_CHECKENABLE_SIGNAL_REF_CLIP);
+	break;
+	case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD:
+		VL_COPYSTRING(pLimitCheckString,
+			VL_STRING_CHECKENABLE_RANGE_IGNORE_THRESHOLD);
+	break;
+
+	case VL_CHECKENABLE_SIGNAL_RATE_MSRC:
+		VL_COPYSTRING(pLimitCheckString,
+			VL_STRING_CHECKENABLE_SIGNAL_RATE_MSRC);
+	break;
+
+	case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE:
+		VL_COPYSTRING(pLimitCheckString,
+			VL_STRING_CHECKENABLE_SIGNAL_RATE_PRE_RANGE);
+	break;
+
+	default:
+		VL_COPYSTRING(pLimitCheckString,
+			VL_STRING_UNKNOWN_ERROR_CODE);
+
+	}
+
+	LOG_FUNCTION_END(Status);
+	return Status;
+}
diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_i2c_platform.c b/drivers/input/misc/vl53l0x/src/vl53l0x_i2c_platform.c
new file mode 100644
index 0000000..edc4b5c
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/src/vl53l0x_i2c_platform.c
@@ -0,0 +1,384 @@
+/*
+ *  vl53l0x_i2c_platform.c - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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.
+ */
+
+/*!
+ * \file   VL_platform.c
+ * \brief  Code function definitions for EWOK Platform Layer
+ *
+ */
+
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include "stmvl53l0x-i2c.h"
+#include "stmvl53l0x-cci.h"
+
+#include "vl53l0x_platform.h"
+#include "vl53l0x_i2c_platform.h"
+#include "vl53l0x_def.h"
+
+#include "vl53l0x_platform_log.h"
+
+#ifdef VL_LOG_ENABLE
+#define trace_print(level, ...) \
+	trace_print_module_function(TRACE_MODULE_PLATFORM, level,\
+	TRACE_FUNCTION_NONE, ##__VA_ARGS__)
+#define trace_i2c(...) \
+	trace_print_module_function(TRACE_MODULE_NONE, \
+	TRACE_LEVEL_NONE, TRACE_FUNCTION_I2C, ##__VA_ARGS__)
+#endif
+
+/**
+ * @def I2C_BUFFER_CONFIG
+ *
+ * @brief Configure Device register I2C access
+ *
+ * @li 0 : one GLOBAL buffer \n
+ *   Use one global buffer of MAX_I2C_XFER_SIZE byte in data space \n
+ *   This solution is not multi-Device compliant nor multi-thread cpu safe \n
+ *   It can be the best option for small 8/16 bit MCU without stack and limited
+ *   ram  (STM8s, 80C51 ...)
+ *
+ * @li 1 : ON_STACK/local \n
+ *   Use local variable (on stack) buffer \n
+ *   This solution is multi-thread with use of i2c resource lock or mutex see
+ *   VL6180x_GetI2CAccess() \n
+ *
+ * @li 2 : User defined \n
+ *    Per Device potentially dynamic allocated. Requires VL6180x_GetI2cBuffer()
+ *    to be implemented.
+ * @ingroup Configuration
+ */
+#define I2C_BUFFER_CONFIG 1
+
+#if I2C_BUFFER_CONFIG == 0
+    /* GLOBAL config buffer */
+	uint8_t i2c_global_buffer[VL_MAX_I2C_XFER_SIZE];
+
+    #define DECL_I2C_BUFFER
+    #define VL_GetLocalBuffer(Dev, n_byte)  i2c_global_buffer
+
+#elif I2C_BUFFER_CONFIG == 1
+    /* ON STACK */
+	uint8_t LocBuffer[VL_MAX_I2C_XFER_SIZE];
+    #define VL_GetLocalBuffer(Dev, n_byte)  LocBuffer
+#elif I2C_BUFFER_CONFIG == 2
+    /* user define buffer type declare DECL_I2C_BUFFER  as access  via */
+    /* VL_GetLocalBuffer */
+    #define DECL_I2C_BUFFER
+#else
+#error "invalid I2C_BUFFER_CONFIG "
+#endif
+
+
+#define VL_I2C_USER_VAR         /* none but could be for a flag var to */
+	/* get/pass to mutex interruptible  return flags and try again */
+#define VL_GetI2CAccess(Dev)    /* todo mutex acquire */
+#define VL_DoneI2CAcces(Dev)    /* todo mutex release */
+
+
+char  debug_string[VL_MAX_STRING_LENGTH_PLT];
+
+
+#define MIN_COMMS_VERSION_MAJOR     1
+#define MIN_COMMS_VERSION_MINOR     8
+#define MIN_COMMS_VERSION_BUILD     1
+#define MIN_COMMS_VERSION_REVISION  0
+
+#define STATUS_OK              0x00
+#define STATUS_FAIL            0x01
+
+bool _check_min_version(void)
+{
+	bool min_version_comms_dll = false;
+
+	min_version_comms_dll = true;
+
+	return min_version_comms_dll;
+}
+
+int32_t VL_comms_initialise(uint8_t comms_type, uint16_t comms_speed_khz)
+{
+	int32_t status   = STATUS_OK;
+
+	return status;
+}
+
+int32_t VL_comms_close(void)
+{
+	int32_t status = STATUS_OK;
+
+
+	return status;
+}
+
+int32_t VL_set_page(struct vl_data *dev, uint8_t page_data)
+{
+	int32_t status = STATUS_OK;
+	uint16_t page_index = 0xFF;
+	uint8_t *buffer;
+
+	buffer =  VL_GetLocalBuffer(dev, 3);
+	buffer[0] = page_index >> 8;
+	buffer[1] = page_index & 0xff;
+	buffer[2] = page_data;
+
+	status = VL_I2CWrite(dev, buffer, (uint8_t) 3);
+	return status;
+}
+
+int32_t VL_write_multi(struct vl_data *dev, uint8_t index, uint8_t *pdata,
+			int32_t count)
+{
+	int32_t status = STATUS_OK;
+	uint8_t *buffer;
+
+#ifdef VL_LOG_ENABLE
+	int32_t i = 0;
+	char value_as_str[VL_MAX_STRING_LENGTH_PLT];
+	char *pvalue_as_str;
+
+	pvalue_as_str =  value_as_str;
+
+	for (i = 0 ; i < count ; i++) {
+		snprintf(pvalue_as_str, sizeof(pvalue_as_str),
+			"%02X", *(pdata + i));
+
+		pvalue_as_str += 2;
+	}
+	trace_i2c("Write reg : 0x%04X, Val : 0x%s\n", index, value_as_str);
+#endif
+	if ((count + 1) > VL_MAX_I2C_XFER_SIZE)
+		return STATUS_FAIL;
+	buffer =  VL_GetLocalBuffer(dev, (count+1));
+	buffer[0] = index;
+	memcpy(&buffer[1], pdata, count);
+	status = VL_I2CWrite(dev, buffer, (count+1));
+
+	return status;
+}
+
+int32_t VL_read_multi(struct vl_data *dev, uint8_t index, uint8_t *pdata,
+			int32_t count)
+{
+	int32_t status = STATUS_OK;
+	uint8_t *buffer;
+
+#ifdef VL_LOG_ENABLE
+	int32_t      i = 0;
+	char   value_as_str[VL_MAX_STRING_LENGTH_PLT];
+	char *pvalue_as_str;
+#endif
+
+	if ((count + 1) > VL_MAX_I2C_XFER_SIZE)
+		return STATUS_FAIL;
+
+	buffer =  VL_GetLocalBuffer(dev, 1);
+	buffer[0] = index;
+	status = VL_I2CWrite(dev, (uint8_t *)buffer, (uint8_t)1);
+	if (!status) {
+		pdata[0] = index;
+		status = VL_I2CRead(dev, pdata, count);
+	}
+
+#ifdef VL_LOG_ENABLE
+	pvalue_as_str =  value_as_str;
+
+	for (i = 0 ; i < count ; i++) {
+		snprintf(pvalue_as_str, sizeof(value_as_str),
+			"%02X", *(pdata+i));
+		pvalue_as_str += 2;
+	}
+
+	trace_i2c("Read  reg : 0x%04X, Val : 0x%s\n", index, value_as_str);
+#endif
+
+	return status;
+}
+
+
+int32_t VL_write_byte(struct vl_data *dev, uint8_t index, uint8_t data)
+{
+	int32_t status = STATUS_OK;
+	const int32_t cbyte_count = 1;
+
+	status = VL_write_multi(dev, index, &data, cbyte_count);
+
+	return status;
+
+}
+
+
+int32_t VL_write_word(struct vl_data *dev, uint8_t index, uint16_t data)
+{
+	int32_t status = STATUS_OK;
+
+	uint8_t  buffer[BYTES_PER_WORD];
+
+	/* Split 16-bit word into MS and LS uint8_t */
+	buffer[0] = (uint8_t)(data >> 8);
+	buffer[1] = (uint8_t)(data &  0x00FF);
+
+	status = VL_write_multi(dev, index, buffer, BYTES_PER_WORD);
+
+	return status;
+
+}
+
+
+int32_t VL_write_dword(struct vl_data *dev, uint8_t index, uint32_t data)
+{
+	int32_t status = STATUS_OK;
+	uint8_t  buffer[BYTES_PER_DWORD];
+
+	/* Split 32-bit word into MS ... LS bytes */
+	buffer[0] = (uint8_t) (data >> 24);
+	buffer[1] = (uint8_t)((data &  0x00FF0000) >> 16);
+	buffer[2] = (uint8_t)((data &  0x0000FF00) >> 8);
+	buffer[3] = (uint8_t) (data &  0x000000FF);
+
+	status = VL_write_multi(dev, index, buffer, BYTES_PER_DWORD);
+
+	return status;
+
+}
+
+
+int32_t VL_read_byte(struct vl_data *dev, uint8_t index, uint8_t *pdata)
+{
+	int32_t status = STATUS_OK;
+	int32_t cbyte_count = 1;
+
+	status = VL_read_multi(dev, index, pdata, cbyte_count);
+
+	return status;
+
+}
+
+
+int32_t VL_read_word(struct vl_data *dev, uint8_t index, uint16_t *pdata)
+{
+	int32_t  status = STATUS_OK;
+	uint8_t  buffer[BYTES_PER_WORD];
+
+	status = VL_read_multi(dev, index, buffer, BYTES_PER_WORD);
+	*pdata = ((uint16_t)buffer[0]<<8) + (uint16_t)buffer[1];
+
+	return status;
+
+}
+
+int32_t VL_read_dword(struct vl_data *dev, uint8_t index, uint32_t *pdata)
+{
+	int32_t status = STATUS_OK;
+	uint8_t  buffer[BYTES_PER_DWORD];
+
+	status = VL_read_multi(dev, index, buffer, BYTES_PER_DWORD);
+	*pdata = ((uint32_t)buffer[0]<<24) + ((uint32_t)buffer[1]<<16) +
+			((uint32_t)buffer[2]<<8) + (uint32_t)buffer[3];
+
+	return status;
+
+}
+
+int32_t VL_platform_wait_us(int32_t wait_us)
+{
+	int32_t status = STATUS_OK;
+
+	msleep((wait_us/1000));
+
+#ifdef VL_LOG_ENABLE
+	trace_i2c("Wait us : %6d\n", wait_us);
+#endif
+
+	return status;
+
+}
+
+
+int32_t VL_wait_ms(int32_t wait_ms)
+{
+	int32_t status = STATUS_OK;
+
+	msleep(wait_ms);
+
+#ifdef VL_LOG_ENABLE
+	trace_i2c("Wait ms : %6d\n", wait_ms);
+#endif
+
+	return status;
+
+}
+
+
+int32_t VL_set_gpio(uint8_t level)
+{
+	int32_t status = STATUS_OK;
+#ifdef VL_LOG_ENABLE
+	trace_i2c("// Set GPIO = %d;\n", level);
+#endif
+
+	return status;
+
+}
+
+
+int32_t VL_get_gpio(uint8_t *plevel)
+{
+	int32_t status = STATUS_OK;
+#ifdef VL_LOG_ENABLE
+	trace_i2c("// Get GPIO = %d;\n", *plevel);
+#endif
+	return status;
+}
+
+
+int32_t VL_release_gpio(void)
+{
+	int32_t status = STATUS_OK;
+#ifdef VL_LOG_ENABLE
+	trace_i2c("// Releasing force on GPIO\n");
+#endif
+	return status;
+
+}
+
+int32_t VL_cycle_power(void)
+{
+	int32_t status = STATUS_OK;
+#ifdef VL_LOG_ENABLE
+	trace_i2c("// cycle sensor power\n");
+#endif
+
+	return status;
+}
+
+
+int32_t VL_get_timer_frequency(int32_t *ptimer_freq_hz)
+{
+	*ptimer_freq_hz = 0;
+	return STATUS_FAIL;
+}
+
+
+int32_t VL_get_timer_value(int32_t *ptimer_count)
+{
+	*ptimer_count = 0;
+	return STATUS_FAIL;
+}
diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_platform.c b/drivers/input/misc/vl53l0x/src/vl53l0x_platform.c
new file mode 100644
index 0000000..79df3db
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/src/vl53l0x_platform.c
@@ -0,0 +1,232 @@
+/*
+ *  vl53l0x_platform.c - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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.
+ */
+
+/**
+ * @file VL_i2c.c
+ *
+ * Copyright (C) 2014 ST MicroElectronics
+ *
+ * provide variable word size byte/Word/dword VL6180x register access via i2c
+ *
+ */
+#include "vl53l0x_platform.h"
+#include "vl53l0x_i2c_platform.h"
+#include "vl53l0x_api.h"
+
+#define LOG_FUNCTION_START(fmt, ...) \
+		_LOG_FUNCTION_START(TRACE_MODULE_PLATFORM, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+		_LOG_FUNCTION_END(TRACE_MODULE_PLATFORM, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...)\
+		_LOG_FUNCTION_END_FMT(TRACE_MODULE_PLATFORM, status,\
+		fmt, ##__VA_ARGS__)
+
+
+
+int8_t VL_LockSequenceAccess(struct vl_data *Dev)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	return Status;
+}
+
+int8_t VL_UnlockSequenceAccess(struct vl_data *Dev)
+{
+	int8_t Status = VL_ERROR_NONE;
+
+	return Status;
+}
+
+/* the ranging_sensor_comms.dll will take care of the page selection */
+int8_t VL_WriteMulti(struct vl_data *Dev, uint8_t index,
+				uint8_t *pdata, uint32_t count)
+{
+
+	int8_t Status = VL_ERROR_NONE;
+	int32_t status_int = 0;
+	uint8_t deviceAddress;
+
+	if (count >= VL_MAX_I2C_XFER_SIZE)
+		Status = VL_ERROR_INVALID_PARAMS;
+
+
+	deviceAddress = Dev->I2cDevAddr;
+
+	status_int = VL_write_multi(Dev, index, pdata, count);
+
+	if (status_int != 0)
+		Status = VL_ERROR_CONTROL_INTERFACE;
+
+	return Status;
+}
+
+/* the ranging_sensor_comms.dll will take care of the page selection */
+int8_t VL_ReadMulti(struct vl_data *Dev, uint8_t index,
+				uint8_t *pdata, uint32_t count)
+{
+	int8_t Status = VL_ERROR_NONE;
+	int32_t status_int;
+	uint8_t deviceAddress;
+
+	if (count >= VL_MAX_I2C_XFER_SIZE)
+		Status = VL_ERROR_INVALID_PARAMS;
+
+
+	deviceAddress = Dev->I2cDevAddr;
+
+	status_int = VL_read_multi(Dev, index, pdata, count);
+
+	if (status_int != 0)
+		Status = VL_ERROR_CONTROL_INTERFACE;
+
+	return Status;
+}
+
+
+int8_t VL_WrByte(struct vl_data *Dev, uint8_t index, uint8_t data)
+{
+	int8_t Status = VL_ERROR_NONE;
+	int32_t status_int;
+	uint8_t deviceAddress;
+
+	deviceAddress = Dev->I2cDevAddr;
+
+	status_int = VL_write_byte(Dev, index, data);
+
+	if (status_int != 0)
+		Status = VL_ERROR_CONTROL_INTERFACE;
+
+	return Status;
+}
+
+int8_t VL_WrWord(struct vl_data *Dev, uint8_t index, uint16_t data)
+{
+	int8_t Status = VL_ERROR_NONE;
+	int32_t status_int;
+	uint8_t deviceAddress;
+
+	deviceAddress = Dev->I2cDevAddr;
+
+	status_int = VL_write_word(Dev, index, data);
+
+	if (status_int != 0)
+		Status = VL_ERROR_CONTROL_INTERFACE;
+
+	return Status;
+}
+
+int8_t VL_WrDWord(struct vl_data *Dev, uint8_t index, uint32_t data)
+{
+	int8_t Status = VL_ERROR_NONE;
+	int32_t status_int;
+	uint8_t deviceAddress;
+
+	deviceAddress = Dev->I2cDevAddr;
+
+	status_int = VL_write_dword(Dev, index, data);
+
+	if (status_int != 0)
+		Status = VL_ERROR_CONTROL_INTERFACE;
+
+	return Status;
+}
+
+int8_t VL_UpdateByte(struct vl_data *Dev, uint8_t index,
+				uint8_t AndData, uint8_t OrData)
+{
+	int8_t Status = VL_ERROR_NONE;
+	int32_t status_int;
+	uint8_t deviceAddress;
+	uint8_t data;
+
+	deviceAddress = Dev->I2cDevAddr;
+
+	status_int = VL_read_byte(Dev, index, &data);
+
+	if (status_int != 0)
+		Status = VL_ERROR_CONTROL_INTERFACE;
+
+	if (Status == VL_ERROR_NONE) {
+		data = (data & AndData) | OrData;
+		status_int = VL_write_byte(Dev, index, data);
+
+		if (status_int != 0)
+			Status = VL_ERROR_CONTROL_INTERFACE;
+	}
+
+	return Status;
+}
+
+int8_t VL_RdByte(struct vl_data *Dev, uint8_t index, uint8_t *data)
+{
+	int8_t Status = VL_ERROR_NONE;
+	int32_t status_int;
+	uint8_t deviceAddress;
+
+	deviceAddress = Dev->I2cDevAddr;
+
+	status_int = VL_read_byte(Dev, index, data);
+
+	if (status_int != 0)
+		Status = VL_ERROR_CONTROL_INTERFACE;
+
+	return Status;
+}
+
+int8_t VL_RdWord(struct vl_data *Dev, uint8_t index, uint16_t *data)
+{
+	int8_t Status = VL_ERROR_NONE;
+	int32_t status_int;
+	uint8_t deviceAddress;
+
+	deviceAddress = Dev->I2cDevAddr;
+
+	status_int = VL_read_word(Dev, index, data);
+
+	if (status_int != 0)
+		Status = VL_ERROR_CONTROL_INTERFACE;
+
+	return Status;
+}
+
+int8_t  VL_RdDWord(struct vl_data *Dev, uint8_t index, uint32_t *data)
+{
+	int8_t Status = VL_ERROR_NONE;
+	int32_t status_int;
+	uint8_t deviceAddress;
+
+	deviceAddress = Dev->I2cDevAddr;
+
+	status_int = VL_read_dword(Dev, index, data);
+
+	if (status_int != 0)
+		Status = VL_ERROR_CONTROL_INTERFACE;
+
+	return Status;
+}
+
+#define VL_POLLINGDELAY_LOOPNB  250
+int8_t VL_PollingDelay(struct vl_data *Dev)
+{
+	int8_t status = VL_ERROR_NONE;
+
+	LOG_FUNCTION_START("");
+	usleep_range(1000, 1001);
+	LOG_FUNCTION_END(status);
+	return status;
+}
diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_port_i2c.c b/drivers/input/misc/vl53l0x/src/vl53l0x_port_i2c.c
new file mode 100644
index 0000000..9e14f79
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/src/vl53l0x_port_i2c.c
@@ -0,0 +1,168 @@
+/*
+ *  vl53l0x_port_i2c.c - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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/i2c.h>
+#include <linux/module.h>
+#include "stmvl53l0x-i2c.h"
+#include "stmvl53l0x-cci.h"
+#include "vl53l0x_platform.h"
+#include "vl53l0x_i2c_platform.h"
+#include "stmvl53l0x.h"
+
+#define I2C_M_WR			0x00
+#define STATUS_OK			0x00
+#define STATUS_FAIL			(-1)
+/** int  VL_I2CWrite(VL_Dev_t dev, void *buff, uint8_t len);
+ * @brief       Write data buffer to VL53L0 device via i2c
+ * @param dev   The device to write to
+ * @param buff  The data buffer
+ * @param len   The length of the transaction in byte
+ * @return      0 on success
+ */
+int VL_I2CWrite(struct vl_data *dev, uint8_t *buff, uint8_t len)
+{
+
+
+	int err = 0;
+
+	if (dev->bus_type == CCI_BUS) {
+#ifdef CAMERA_CCI
+		uint16_t index;
+		struct cci_data *cci_client_obj =
+			(struct cci_data *)dev->client_object;
+		struct msm_camera_i2c_client *client = cci_client_obj->client;
+
+		index = buff[0];
+		/*dbg("%s: index: %d len: %d\n", __func__, index, len); */
+
+		if (len == 2) {
+			uint8_t data;
+
+			data = buff[1];
+			/* for byte access */
+			err = client->i2c_func_tbl->i2c_write(client, index,
+					data, MSM_CAMERA_I2C_BYTE_DATA);
+			if (err < 0) {
+				dbg("%s:%d failed status=%d\n",
+					__func__, __LINE__, err);
+				return err;
+			}
+		} else if (len == 3) {
+			uint16_t data;
+
+			data = ((uint16_t)buff[1] << 8) | (uint16_t)buff[2];
+			err = client->i2c_func_tbl->i2c_write(client, index,
+					data, MSM_CAMERA_I2C_WORD_DATA);
+			if (err < 0) {
+				dbg("%s:%d failed status=%d\n",
+					__func__, __LINE__, err);
+				return err;
+			}
+		} else if (len >= 5) {
+			err = client->i2c_func_tbl->i2c_write_seq(client,
+					index, &buff[1], (len-1));
+			if (err < 0) {
+				dbg("%s:%d failed status=%d\n",
+					__func__, __LINE__, err);
+				return err;
+			}
+
+		}
+#endif
+#ifndef CAMERA_CCI
+	} else {
+		struct i2c_msg msg[1];
+		struct i2c_data *i2c_client_obj =
+					(struct i2c_data *)dev->client_object;
+		struct i2c_client *client =
+				(struct i2c_client *)i2c_client_obj->client;
+
+		msg[0].addr = client->addr;
+		msg[0].flags = I2C_M_WR;
+		msg[0].buf = buff;
+		msg[0].len = len;
+
+		err = i2c_transfer(client->adapter, msg, 1);
+		/* return the actual messages transfer */
+		if (err != 1) {
+			dbg("%s: i2c_transfer err:%d, addr:0x%x, reg:0x%x\n",
+				__func__, err, client->addr,
+				(buff[0] << 8 | buff[1]));
+			return STATUS_FAIL;
+		}
+#endif
+	}
+
+	return 0;
+}
+
+
+/** int VL_I2CRead(VL_Dev_t dev, void *buff, uint8_t len);
+ * @brief       Read data buffer from VL53L0 device via i2c
+ * @param dev   The device to read from
+ * @param buff  The data buffer to fill
+ * @param len   The length of the transaction in byte
+ * @return      transaction status
+ */
+int VL_I2CRead(struct vl_data *dev, uint8_t *buff, uint8_t len)
+{
+
+	int err = 0;
+
+	if (dev->bus_type == CCI_BUS) {
+#ifdef CAMERA_CCI
+		uint16_t index;
+		struct cci_data *cci_client_obj =
+				(struct cci_data *)dev->client_object;
+		struct msm_camera_i2c_client *client = cci_client_obj->client;
+
+		index = buff[0];
+		/* dbg("%s: index: %d\n", __func__, index); */
+		err = client->i2c_func_tbl->i2c_read_seq(client,
+							index, buff, len);
+		if (err < 0) {
+			dbg("%s:%d failed status=%d\n",
+					__func__, __LINE__, err);
+			return err;
+		}
+#endif
+	} else {
+#ifndef CAMERA_CCI
+		struct i2c_msg msg[1];
+		struct i2c_data *i2c_client_obj =
+					(struct i2c_data *)dev->client_object;
+		struct i2c_client *client =
+				(struct i2c_client *) i2c_client_obj->client;
+
+		msg[0].addr = client->addr;
+		msg[0].flags = I2C_M_RD|client->flags;
+		msg[0].buf = buff;
+		msg[0].len = len;
+
+		err = i2c_transfer(client->adapter, &msg[0], 1);
+		/* return the actual message transfer */
+		if (err != 1) {
+			dbg("%s: Read i2c_transfer err:%d, addr:0x%x\n",
+				__func__, err, client->addr);
+			return STATUS_FAIL;
+		}
+#endif
+	}
+
+	return 0;
+}
diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x-cci.h b/drivers/input/misc/vl53l0x/stmvl53l0x-cci.h
new file mode 100644
index 0000000..5476ef9
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/stmvl53l0x-cci.h
@@ -0,0 +1,57 @@
+/*
+ *  stmvl53l0x-cci.h - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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 STMVL_CCI_H
+#define STMVL_CCI_H
+#include <linux/types.h>
+
+#ifdef CAMERA_CCI
+#include <soc/qcom/camera2.h>
+#include "msm_camera_i2c.h"
+#include "msm_camera_dt_util.h"
+#include "msm_camera_io_util.h"
+#include "msm_cci.h"
+
+#define	MSM_TOF_MAX_VREGS (10)
+
+struct msm_tof_vreg {
+	struct camera_vreg_t *cam_vreg;
+	void *data[MSM_TOF_MAX_VREGS];
+	int num_vreg;
+};
+
+struct cci_data {
+	struct msm_camera_i2c_client g_client;
+	struct msm_camera_i2c_client *client;
+	struct platform_device *pdev;
+	enum msm_camera_device_type_t device_type;
+	enum cci_i2c_master_t cci_master;
+	struct msm_tof_vreg vreg_cfg;
+	struct msm_sd_subdev msm_sd;
+	struct v4l2_subdev sdev;
+	struct v4l2_subdev_ops *subdev_ops;
+	char subdev_initialized;
+	uint32_t subdev_id;
+	uint8_t power_up;
+};
+int stmvl53l0x_init_cci(void);
+void stmvl53l0x_exit_cci(void *cci_object);
+int stmvl53l0x_power_down_cci(void *cci_object);
+int stmvl53l0x_power_up_cci(void *cci_object, unsigned int *preset_flag);
+#endif /* CAMERA_CCI */
+#endif /* STMVL_CCI_H */
diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x-i2c.h b/drivers/input/misc/vl53l0x/stmvl53l0x-i2c.h
new file mode 100644
index 0000000..68f7d37
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/stmvl53l0x-i2c.h
@@ -0,0 +1,35 @@
+/*
+ *  stmvl53l0x-i2c.h - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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 STMVL_I2C_H
+#define STMVL_I2C_H
+#include <linux/types.h>
+
+#ifndef CAMERA_CCI
+struct i2c_data {
+	struct i2c_client *client;
+	struct regulator *vana;
+	uint8_t power_up;
+};
+int stmvl53l0x_init_i2c(void);
+void stmvl53l0x_exit_i2c(void *i2c_object);
+int stmvl53l0x_power_up_i2c(void *i2c_object, unsigned int *preset_flag);
+int stmvl53l0x_power_down_i2c(void *i2c_object);
+
+#endif /* NOT CAMERA_CCI */
+#endif /* STMVL_I2C_H */
diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x.h b/drivers/input/misc/vl53l0x/stmvl53l0x.h
new file mode 100644
index 0000000..1f15278
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/stmvl53l0x.h
@@ -0,0 +1,186 @@
+/*
+ *  stmvl53l0x.h - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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 STMVL_H
+#define STMVL_H
+
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/miscdevice.h>
+#include <linux/wait.h>
+
+
+#define STMVL_DRV_NAME	"stmvl53l0"
+#define STMVL_SLAVE_ADDR	(0x52>>1)
+
+#define DRIVER_VERSION		"1.0.5"
+#define I2C_M_WR			0x00
+/* #define INT_POLLING_DELAY	20 */
+
+/* if don't want to have output from dbg, comment out #DEBUG macro */
+#ifdef DEBUG
+#define dbg(fmt, ...)	\
+	printk(fmt, ##__VA_ARGS__)
+#else
+#define dbg(fmt, ...)
+#endif
+
+#define err(fmt, ...) \
+	printk(fmt, ##__VA_ARGS__)
+
+#define VL_VDD_MIN      2600000
+#define VL_VDD_MAX      3000000
+
+enum init_mode_e {
+	NORMAL_MODE = 0,
+	OFFSETCALIB_MODE = 1,
+	XTALKCALIB_MODE = 2,
+};
+
+enum parameter_name_e {
+	OFFSET_PAR = 0,
+	XTALKRATE_PAR = 1,
+	XTALKENABLE_PAR = 2,
+	GPIOFUNC_PAR = 3,
+	LOWTHRESH_PAR = 4,
+	HIGHTHRESH_PAR = 5,
+	DEVICEMODE_PAR = 6,
+	INTERMEASUREMENT_PAR = 7,
+	REFERENCESPADS_PAR = 8,
+	REFCALIBRATION_PAR = 9,
+};
+
+enum {
+	CCI_BUS = 0,
+	I2C_BUS = 1,
+};
+
+/*
+ *  IOCTL register data structs
+ */
+struct stmvl53l0x_register {
+	uint32_t is_read; /*1: read 0: write*/
+	uint32_t reg_index;
+	uint32_t reg_bytes;
+	uint32_t reg_data;
+	int32_t status;
+};
+
+/*
+ *  IOCTL parameter structs
+ */
+struct stmvl53l0x_parameter {
+	uint32_t is_read; /*1: Get 0: Set*/
+	enum parameter_name_e name;
+	int32_t value;
+	int32_t value2;
+	int32_t status;
+};
+
+/*
+ *  driver data structs
+ */
+struct vl_data {
+
+	struct VL_DevData_t Data; /* !<embed ST VL53L0 Dev data as "dev_data" */
+	uint8_t   I2cDevAddr;	/* !< i2c device address user specific field */
+	uint8_t   comms_type;	/* !< Type of comms : */
+				/* VL_COMMS_I2C or VL_COMMS_SPI */
+	uint16_t  comms_speed_khz;	/*!< Comms speed [kHz] : */
+					/*typically 400kHz for I2C */
+	uint8_t   bus_type;		/* CCI_BUS; I2C_BUS */
+
+	void *client_object; /* cci or i2c client */
+
+	struct mutex update_lock;
+	struct delayed_work	dwork;		/* for PS  work handler */
+	struct input_dev *input_dev_ps;
+	struct kobject *range_kobj;
+
+	const char *dev_name;
+	/* function pointer */
+
+	/* misc device */
+	struct miscdevice miscdev;
+
+	int irq;
+	unsigned int reset;
+
+	/* control flag from HAL */
+	unsigned int enable_ps_sensor;
+
+	/* PS parameters */
+	unsigned int ps_data;			/* to store PS data */
+
+	/* Calibration parameters */
+	unsigned int offsetCalDistance;
+	unsigned int xtalkCalDistance;
+
+
+	/* Range Data */
+	struct VL_RangingMeasurementData_t rangeData;
+
+	/* Device parameters */
+	uint8_t			deviceMode;
+	uint32_t				interMeasurems;
+	uint8_t gpio_function;
+	uint8_t gpio_polarity;
+	unsigned int low_threshold;
+	unsigned int high_threshold;
+
+	/* delay time in miniseconds*/
+	uint8_t delay_ms;
+
+	/* Timing Budget */
+	uint32_t	timingBudget;
+	/* Use this threshold to force restart ranging */
+	uint32_t	noInterruptCount;
+	/* Use this flag to use long ranging*/
+	int			  useLongRange;
+
+	/* Polling thread */
+	struct task_struct *poll_thread;
+	/* Wait Queue on which the poll thread blocks */
+	wait_queue_head_t poll_thread_wq;
+
+	/* Recent interrupt status */
+	uint32_t		interruptStatus;
+
+	struct mutex work_mutex;
+
+	/* Debug */
+	unsigned int enableDebug;
+	uint8_t interrupt_received;
+};
+
+/*
+ *  function pointer structs
+ */
+struct stmvl53l0x_module_fn_t {
+	int (*init)(void);
+	void (*deinit)(void *);
+	int (*power_up)(void *, unsigned int *);
+	int (*power_down)(void *);
+};
+
+
+
+int stmvl53l0x_setup(struct vl_data *data);
+
+#endif /* STMVL_H */
diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x_module-cci.c b/drivers/input/misc/vl53l0x/stmvl53l0x_module-cci.c
new file mode 100644
index 0000000..39b802f
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/stmvl53l0x_module-cci.c
@@ -0,0 +1,411 @@
+/*
+ *  stmvl53l0x_module-cci.c - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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/uaccess.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+/*
+ * power specific includes
+ */
+#include <linux/pwm.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/clk.h>
+#include <linux/of_gpio.h>
+/*
+ * API includes
+ */
+#include "vl53l0x_api.h"
+#include "vl53l0x_def.h"
+#include "vl53l0x_platform.h"
+#include "stmvl53l0x-cci.h"
+#include "stmvl53l0x-i2c.h"
+#include "stmvl53l0x.h"
+
+#ifdef CAMERA_CCI
+/*
+ * Global data
+ */
+static struct v4l2_file_operations msm_tof_v4l2_subdev_fops;
+static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = {
+	.i2c_read = msm_camera_cci_i2c_read,
+	.i2c_read_seq = msm_camera_cci_i2c_read_seq,
+	.i2c_write = msm_camera_cci_i2c_write,
+	.i2c_write_seq = msm_camera_cci_i2c_write_seq,
+	.i2c_write_table = msm_camera_cci_i2c_write_table,
+	.i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table,
+	.i2c_write_table_w_microdelay =
+		msm_camera_cci_i2c_write_table_w_microdelay,
+	.i2c_util = msm_sensor_cci_i2c_util,
+	.i2c_poll =  msm_camera_cci_i2c_poll,
+};
+static int stmvl53l0x_get_dt_data(struct device *dev, struct cci_data *data);
+
+/*
+ * QCOM specific functions
+ */
+static int stmvl53l0x_get_dt_data(struct device *dev, struct cci_data *data)
+{
+	int rc = 0;
+
+	dbg("Enter\n");
+
+	if (dev->of_node) {
+		struct device_node *of_node = dev->of_node;
+		struct msm_tof_vreg *vreg_cfg;
+
+		if (!of_node) {
+			err("failed %d\n", __LINE__);
+			return -EINVAL;
+		}
+
+		rc = of_property_read_u32(of_node,
+				"cell-index", &data->pdev->id);
+		if (rc < 0) {
+			err("failed %d\n", __LINE__);
+			return rc;
+		}
+		dbg("cell-index: %d\n", data->pdev->id);
+		rc = of_property_read_u32(of_node, "qcom,cci-master",
+				&data->cci_master);
+		if (rc < 0) {
+			err("failed %d\n", __LINE__);
+			/* Set default master 0 */
+			data->cci_master = MASTER_0;
+			rc = 0;
+		}
+		dbg("cci_master: %d\n", data->cci_master);
+		if (of_find_property(of_node, "qcom,cam-vreg-name", NULL)) {
+			vreg_cfg = &data->vreg_cfg;
+			rc = msm_camera_get_dt_vreg_data(of_node,
+				&vreg_cfg->cam_vreg, &vreg_cfg->num_vreg);
+			if (rc < 0) {
+				err("failed %d\n", __LINE__);
+				return rc;
+			}
+		}
+		dbg("vreg-name: %s min_volt: %d max_volt: %d",
+			vreg_cfg->cam_vreg->reg_name,
+			vreg_cfg->cam_vreg->min_voltage,
+			vreg_cfg->cam_vreg->max_voltage);
+	}
+	dbg("End rc =%d\n", rc);
+
+	return rc;
+}
+
+static int32_t stmvl53l0x_vreg_control(struct cci_data *data, int config)
+{
+	int rc = 0, i, cnt;
+	struct msm_tof_vreg *vreg_cfg;
+
+	dbg("Enter\n");
+
+	vreg_cfg = &data->vreg_cfg;
+	cnt = vreg_cfg->num_vreg;
+	dbg("num_vreg: %d\n", cnt);
+	if (!cnt) {
+		err("failed %d\n", __LINE__);
+		return 0;
+	}
+
+	if (cnt >= MSM_TOF_MAX_VREGS) {
+		err("failed %d cnt %d\n", __LINE__, cnt);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < cnt; i++) {
+		rc = msm_camera_config_single_vreg(&(data->pdev->dev),
+				&vreg_cfg->cam_vreg[i],
+				(struct regulator **)&vreg_cfg->data[i],
+				config);
+	}
+
+	dbg("EXIT rc =%d\n", rc);
+	return rc;
+}
+
+
+static int msm_tof_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	return 0;
+}
+
+
+static const struct v4l2_subdev_internal_ops msm_tof_internal_ops = {
+	.close = msm_tof_close,
+};
+
+static long msm_tof_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	dbg("Subdev_ioctl not handled\n");
+	return 0;
+}
+
+static int32_t msm_tof_power(struct v4l2_subdev *sd, int on)
+{
+	dbg("TOF power called\n");
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops msm_tof_subdev_core_ops = {
+	.ioctl = msm_tof_subdev_ioctl,
+	.s_power = msm_tof_power,
+};
+
+static struct v4l2_subdev_ops msm_tof_subdev_ops = {
+	.core = &msm_tof_subdev_core_ops,
+};
+
+static int stmvl53l0x_cci_init(struct cci_data *data)
+{
+	int rc = 0;
+	struct msm_camera_cci_client *cci_client = data->client->cci_client;
+
+	if (data->subdev_initialized == FALSE) {
+		data->client->i2c_func_tbl = &msm_sensor_cci_func_tbl;
+		data->client->cci_client =
+			kzalloc(sizeof(struct msm_camera_cci_client),
+			GFP_KERNEL);
+		if (!data->client->cci_client) {
+			err("%d, failed no memory\n", __LINE__);
+			return -ENOMEM;
+		}
+		cci_client = data->client->cci_client;
+		cci_client->cci_subdev = msm_cci_get_subdev();
+		cci_client->cci_i2c_master = data->cci_master;
+		v4l2_subdev_init(&data->msm_sd.sd, data->subdev_ops);
+		v4l2_set_subdevdata(&data->msm_sd.sd, data);
+		data->msm_sd.sd.internal_ops = &msm_tof_internal_ops;
+		data->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+		snprintf(data->msm_sd.sd.name, ARRAY_SIZE(data->msm_sd.sd.name),
+			"msm_tof");
+		media_entity_init(&data->msm_sd.sd.entity, 0, NULL, 0);
+		data->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+		data->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_TOF;
+		data->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2;
+		msm_sd_register(&data->msm_sd);
+		msm_tof_v4l2_subdev_fops = v4l2_subdev_fops;
+		data->msm_sd.sd.devnode->fops = &msm_tof_v4l2_subdev_fops;
+		data->subdev_initialized = TRUE;
+	}
+
+	cci_client->sid = 0x29;
+	cci_client->retries = 3;
+	cci_client->id_map = 0;
+	cci_client->cci_i2c_master = data->cci_master;
+	rc = data->client->i2c_func_tbl->i2c_util(data->client, MSM_CCI_INIT);
+	if (rc < 0) {
+		err("%d: CCI Init failed\n", __LINE__);
+		return rc;
+	}
+	dbg("CCI Init Succeeded\n");
+
+	data->client->addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+
+	return 0;
+}
+
+static int32_t stmvl53l0x_platform_probe(struct platform_device *pdev)
+{
+	struct vl_data *vl53l0x_data = NULL;
+	struct cci_data *cci_object = NULL;
+	int32_t rc = 0;
+
+	dbg("Enter\n");
+
+	if (!pdev->dev.of_node) {
+		err("of_node NULL\n");
+		return -EINVAL;
+	}
+
+	vl53l0x_data = kzalloc(sizeof(struct vl_data), GFP_KERNEL);
+	if (!vl53l0x_data) {
+		rc = -ENOMEM;
+		return rc;
+	}
+	if (vl53l0x_data) {
+		vl53l0x_data->client_object =
+			kzalloc(sizeof(struct cci_data), GFP_KERNEL);
+		cci_object = (struct cci_data *)vl53l0x_data->client_object;
+	}
+	cci_object->client =
+		(struct msm_camera_i2c_client *)&cci_object->g_client;
+
+	/* setup bus type */
+	vl53l0x_data->bus_type = CCI_BUS;
+
+	/* Set platform device handle */
+	cci_object->subdev_ops = &msm_tof_subdev_ops;
+	cci_object->pdev = pdev;
+	rc = stmvl53l0x_get_dt_data(&pdev->dev, cci_object);
+	if (rc < 0) {
+		err("%d, failed rc %d\n", __LINE__, rc);
+		return rc;
+	}
+	cci_object->subdev_id = pdev->id;
+
+	/* Set device type as platform device */
+	cci_object->device_type = MSM_CAMERA_PLATFORM_DEVICE;
+	cci_object->subdev_initialized = FALSE;
+
+	/* setup device name */
+	vl53l0x_data->dev_name = dev_name(&pdev->dev);
+
+	/* setup device data */
+	dev_set_drvdata(&pdev->dev, vl53l0x_data);
+
+	/* setup other stuff */
+	rc = stmvl53l0x_setup(vl53l0x_data);
+
+	/* init default value */
+	cci_object->power_up = 0;
+
+	dbg("End\n");
+
+	return rc;
+
+}
+
+static int32_t stmvl53l0x_platform_remove(struct platform_device *pdev)
+{
+	struct vl_data *vl53l0x_data = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	kfree(vl53l0x_data->client_object);
+	kfree(vl53l0x_data);
+
+	return 0;
+}
+
+static const struct of_device_id st_stmvl53l0x_dt_match[] = {
+	{ .compatible = "st,stmvl53l0", },
+	{ },
+};
+
+static struct platform_driver stmvl53l0x_platform_driver = {
+	.probe = stmvl53l0x_platform_probe,
+	.remove = stmvl53l0x_platform_remove,
+	.driver = {
+		.name = STMVL_DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = st_stmvl53l0x_dt_match,
+	},
+};
+
+int stmvl53l0x_power_up_cci(void *cci_object, unsigned int *preset_flag)
+{
+	int ret = 0;
+	struct cci_data *data = (struct cci_data *)cci_object;
+
+	dbg("Enter");
+
+	/* need to init cci first */
+	ret = stmvl53l0x_cci_init(data);
+	if (ret) {
+		err("stmvl53l0x_cci_init failed %d\n", __LINE__);
+		return ret;
+	}
+	/* actual power up */
+	if (data && data->device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+		ret = stmvl53l0x_vreg_control(data, 1);
+		if (ret < 0) {
+			err("stmvl53l0x_vreg_control failed %d\n",
+				__LINE__);
+			return ret;
+		}
+	}
+	data->power_up = 1;
+	*preset_flag = 1;
+	dbg("End\n");
+
+	return ret;
+}
+
+int stmvl53l0x_power_down_cci(void *cci_object)
+{
+	int ret = 0;
+	struct cci_data *data = (struct cci_data *)cci_object;
+
+	dbg("Enter\n");
+	if (data->power_up) {
+		/* need to release cci first */
+		ret = data->client->i2c_func_tbl->i2c_util(data->client,
+				MSM_CCI_RELEASE);
+		if (ret < 0)
+			err("CCI Release failed rc %d\n", ret);
+
+		/* actual power down */
+		if (data->device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+			ret = stmvl53l0x_vreg_control(data, 0);
+			if (ret < 0) {
+				err(
+					"stmvl53l0x_vreg_control failed %d\n",
+					__LINE__);
+				return ret;
+			}
+		}
+	}
+	data->power_up = 0;
+	dbg("End\n");
+	return ret;
+}
+
+int stmvl53l0x_init_cci(void)
+{
+	int ret = 0;
+
+	dbg("Enter\n");
+
+	/* register as a platform device */
+	ret = platform_driver_register(&stmvl53l0x_platform_driver);
+	if (ret)
+		err("%d, error ret:%d\n", __LINE__, ret);
+
+	dbg("End\n");
+
+	return ret;
+}
+
+void stmvl53l0x_exit_cci(void *cci_object)
+{
+	struct cci_data *data = (struct cci_data *)cci_object;
+
+	dbg("Enter\n");
+
+	if (data && data->client->cci_client)
+		kfree(data->client->cci_client);
+
+	dbg("End\n");
+}
+#endif /* end of CAMERA_CCI */
diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x_module-i2c.c b/drivers/input/misc/vl53l0x/stmvl53l0x_module-i2c.c
new file mode 100644
index 0000000..7e0cc15
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/stmvl53l0x_module-i2c.c
@@ -0,0 +1,246 @@
+/*
+ *  stmvl53l0x_module-i2c.c - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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/uaccess.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+/*
+ * power specific includes
+ */
+#include <linux/pwm.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/clk.h>
+#include <linux/of_gpio.h>
+/*
+ * API includes
+ */
+#include "vl53l0x_api.h"
+#include "vl53l0x_def.h"
+#include "vl53l0x_platform.h"
+#include "stmvl53l0x-i2c.h"
+#include "stmvl53l0x-cci.h"
+#include "stmvl53l0x.h"
+#ifndef CAMERA_CCI
+
+/*
+ * Global data
+ */
+static int stmvl53l0x_parse_vdd(struct device *dev, struct i2c_data *data);
+
+/*
+ * QCOM specific functions
+ */
+static int stmvl53l0x_parse_vdd(struct device *dev, struct i2c_data *data)
+{
+	int ret = 0;
+
+	dbg("Enter\n");
+
+	if (dev->of_node) {
+		data->vana = regulator_get(dev, "vdd");
+		if (IS_ERR(data->vana)) {
+			err("vdd supply is not provided\n");
+			ret = -1;
+		}
+	}
+	dbg("End\n");
+
+	return ret;
+}
+
+static int stmvl53l0x_probe(struct i2c_client *client,
+				   const struct i2c_device_id *id)
+{
+	int rc = 0;
+	struct vl_data *vl53l0x_data = NULL;
+	struct i2c_data *i2c_object = NULL;
+
+	dbg("Enter\n");
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
+		rc = -EIO;
+		return rc;
+	}
+
+	vl53l0x_data = kzalloc(sizeof(struct vl_data), GFP_KERNEL);
+	if (!vl53l0x_data) {
+		rc = -ENOMEM;
+		return rc;
+	}
+	if (vl53l0x_data) {
+		vl53l0x_data->client_object =
+			kzalloc(sizeof(struct i2c_data), GFP_KERNEL);
+		i2c_object = (struct i2c_data *)vl53l0x_data->client_object;
+	}
+	i2c_object->client = client;
+
+	/* setup bus type */
+	vl53l0x_data->bus_type = I2C_BUS;
+
+	/* setup regulator */
+	stmvl53l0x_parse_vdd(&i2c_object->client->dev, i2c_object);
+
+	/* setup device name */
+	vl53l0x_data->dev_name = dev_name(&client->dev);
+
+	/* setup device data */
+	dev_set_drvdata(&client->dev, vl53l0x_data);
+
+	/* setup client data */
+	i2c_set_clientdata(client, vl53l0x_data);
+
+	/* setup other stuff */
+	rc = stmvl53l0x_setup(vl53l0x_data);
+
+	/* init default value */
+	i2c_object->power_up = 0;
+
+	dbg("End\n");
+	return rc;
+}
+
+static int stmvl53l0x_remove(struct i2c_client *client)
+{
+	struct vl_data *data = i2c_get_clientdata(client);
+
+	dbg("Enter\n");
+
+	/* Power down the device */
+	stmvl53l0x_power_down_i2c(data->client_object);
+	kfree(data->client_object);
+	kfree(data);
+	dbg("End\n");
+	return 0;
+}
+
+static const struct i2c_device_id stmvl53l0x_id[] = {
+	{ STMVL_DRV_NAME, 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, stmvl53l0x_id);
+
+static const struct of_device_id st_stmvl53l0x_dt_match[] = {
+	{ .compatible = "st,stmvl53l0", },
+	{ },
+};
+
+static struct i2c_driver stmvl53l0x_driver = {
+	.driver = {
+		.name	= STMVL_DRV_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = st_stmvl53l0x_dt_match,
+	},
+	.probe	= stmvl53l0x_probe,
+	.remove	= stmvl53l0x_remove,
+	.id_table = stmvl53l0x_id,
+
+};
+
+int stmvl53l0x_power_up_i2c(void *i2c_object, unsigned int *preset_flag)
+{
+	int ret = 0;
+#ifndef STM_TEST
+	struct i2c_data *data = (struct i2c_data *)i2c_object;
+#endif
+
+	dbg("Enter\n");
+
+	/* actual power on */
+#ifndef STM_TEST
+	ret = regulator_set_voltage(data->vana,
+		VL_VDD_MIN, VL_VDD_MAX);
+	if (ret < 0) {
+		err("set_vol(%p) fail %d\n", data->vana, ret);
+		return ret;
+	}
+	ret = regulator_enable(data->vana);
+	usleep_range(3000, 3001);
+	if (ret < 0) {
+		err("reg enable(%p) failed.rc=%d\n",
+			data->vana, ret);
+		return ret;
+	}
+	data->power_up = 1;
+	*preset_flag = 1;
+#endif
+
+	dbg("End\n");
+	return ret;
+}
+
+int stmvl53l0x_power_down_i2c(void *i2c_object)
+{
+	int ret = 0;
+#ifndef STM_TEST
+	struct i2c_data *data = (struct i2c_data *)i2c_object;
+#endif
+
+	dbg("Enter\n");
+#ifndef STM_TEST
+	msleep(30);
+	ret = regulator_disable(data->vana);
+	if (ret < 0)
+		err("reg disable(%p) failed.rc=%d\n",
+			data->vana, ret);
+
+	data->power_up = 0;
+#endif
+
+	dbg("End\n");
+	return ret;
+}
+
+int stmvl53l0x_init_i2c(void)
+{
+	int ret = 0;
+
+	dbg("Enter\n");
+
+	/* register as a i2c client device */
+	ret = i2c_add_driver(&stmvl53l0x_driver);
+	if (ret)
+		err("%d erro ret:%d\n", __LINE__, ret);
+
+	dbg("End with rc:%d\n", ret);
+
+	return ret;
+}
+
+void stmvl53l0x_exit_i2c(void *i2c_object)
+{
+	dbg("Enter\n");
+	i2c_del_driver(&stmvl53l0x_driver);
+
+	dbg("End\n");
+}
+
+#endif /* end of NOT CAMERA_CCI */
diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x_module.c b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c
new file mode 100644
index 0000000..ece245f
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c
@@ -0,0 +1,1893 @@
+/*
+ *  stmvl53l0x_module.c - Linux kernel modules for
+ *  STM VL53L0 FlightSense TOF sensor
+ *
+ *  Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *  Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be 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/uaccess.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+#include <linux/kobject.h>
+#include <linux/kthread.h>
+/*
+ * API includes
+ */
+#include "vl53l0x_api.h"
+
+#define IRQ_NUM	   59
+#ifdef DEBUG_TIME_LOG
+struct timeval start_tv, stop_tv;
+#endif
+
+/*
+ * Global data
+ */
+
+#ifdef CAMERA_CCI
+static struct stmvl53l0x_module_fn_t stmvl53l0x_module_func_tbl = {
+	.init = stmvl53l0x_init_cci,
+	.deinit = stmvl53l0x_exit_cci,
+	.power_up = stmvl53l0x_power_up_cci,
+	.power_down = stmvl53l0x_power_down_cci,
+};
+#else
+static struct stmvl53l0x_module_fn_t stmvl53l0x_module_func_tbl = {
+	.init = stmvl53l0x_init_i2c,
+	.deinit = stmvl53l0x_exit_i2c,
+	.power_up = stmvl53l0x_power_up_i2c,
+	.power_down = stmvl53l0x_power_down_i2c,
+};
+#endif
+struct stmvl53l0x_module_fn_t *pmodule_func_tbl;
+struct stmvl53l0x_api_fn_t {
+	int8_t (*GetVersion)(struct VL_Version_t *pVersion);
+	int8_t (*GetPalSpecVersion)(struct VL_Version_t *pPalSpecVersion);
+
+	int8_t (*GetProductRevision)(struct vl_data *Dev,
+					uint8_t *pProductRevisionMajor,
+					uint8_t *pProductRevisionMinor);
+	int8_t (*GetDeviceInfo)(struct vl_data *Dev,
+				struct VL_DeviceInfo_t *pVL_DeviceInfo);
+	int8_t (*GetDeviceErrorStatus)(struct vl_data *Dev,
+				uint8_t *pDeviceErrorStatus);
+	int8_t (*GetRangeStatusString)(uint8_t RangeStatus,
+				char *pRangeStatusString);
+	int8_t (*GetDeviceErrorString)(uint8_t ErrorCode,
+				char *pDeviceErrorString);
+	int8_t (*GetPalErrorString)(int8_t PalErrorCode,
+				char *pPalErrorString);
+	int8_t (*GetPalStateString)(uint8_t PalStateCode,
+				char *pPalStateString);
+	int8_t (*GetPalState)(struct vl_data *Dev, uint8_t *pPalState);
+	int8_t (*SetPowerMode)(struct vl_data *Dev,
+				uint8_t PowerMode);
+	int8_t (*GetPowerMode)(struct vl_data *Dev,
+				uint8_t *pPowerMode);
+	int8_t (*SetOffsetCalibrationDataMicroMeter)(struct vl_data *Dev,
+				int32_t OffsetCalibrationDataMicroMeter);
+	int8_t (*GetOffsetCalibrationDataMicroMeter)(struct vl_data *Dev,
+				int32_t *pOffsetCalibrationDataMicroMeter);
+	int8_t (*SetLinearityCorrectiveGain)(struct vl_data *Dev,
+				int16_t LinearityCorrectiveGain);
+	int8_t (*GetLinearityCorrectiveGain)(struct vl_data *Dev,
+				uint16_t *pLinearityCorrectiveGain);
+	int8_t (*SetGroupParamHold)(struct vl_data *Dev,
+				uint8_t GroupParamHold);
+	int8_t (*GetUpperLimitMilliMeter)(struct vl_data *Dev,
+				uint16_t *pUpperLimitMilliMeter);
+	int8_t (*SetDeviceAddress)(struct vl_data *Dev,
+				uint8_t DeviceAddress);
+	int8_t (*DataInit)(struct vl_data *Dev);
+	int8_t (*SetTuningSettingBuffer)(struct vl_data *Dev,
+				uint8_t *pTuningSettingBuffer,
+				uint8_t UseInternalTuningSettings);
+	int8_t (*GetTuningSettingBuffer)(struct vl_data *Dev,
+				uint8_t **pTuningSettingBuffer,
+				uint8_t *pUseInternalTuningSettings);
+	int8_t (*StaticInit)(struct vl_data *Dev);
+	int8_t (*WaitDeviceBooted)(struct vl_data *Dev);
+	int8_t (*ResetDevice)(struct vl_data *Dev);
+	int8_t (*SetDeviceParameters)(struct vl_data *Dev,
+			const struct VL_DeviceParameters_t *pDeviceParameters);
+	int8_t (*GetDeviceParameters)(struct vl_data *Dev,
+			struct VL_DeviceParameters_t *pDeviceParameters);
+	int8_t (*SetDeviceMode)(struct vl_data *Dev,
+			uint8_t DeviceMode);
+	int8_t (*GetDeviceMode)(struct vl_data *Dev,
+			uint8_t *pDeviceMode);
+	int8_t (*SetHistogramMode)(struct vl_data *Dev,
+			uint8_t HistogramMode);
+	int8_t (*GetHistogramMode)(struct vl_data *Dev,
+			uint8_t *pHistogramMode);
+	int8_t (*SetMeasurementTimingBudgetMicroSeconds)(struct vl_data *Dev,
+			uint32_t  MeasurementTimingBudgetMicroSeconds);
+	int8_t (*GetMeasurementTimingBudgetMicroSeconds)(
+			struct vl_data *Dev,
+			uint32_t *pMeasurementTimingBudgetMicroSeconds);
+	int8_t (*GetVcselPulsePeriod)(struct vl_data *Dev,
+			uint8_t VcselPeriodType,
+			uint8_t	*pVCSELPulsePeriod);
+	int8_t (*SetVcselPulsePeriod)(struct vl_data *Dev,
+			uint8_t VcselPeriodType,
+			uint8_t VCSELPulsePeriod);
+	int8_t (*SetSequenceStepEnable)(struct vl_data *Dev,
+			uint8_t SequenceStepId,
+			uint8_t SequenceStepEnabled);
+	int8_t (*GetSequenceStepEnable)(struct vl_data *Dev,
+			uint8_t SequenceStepId,
+			uint8_t *pSequenceStepEnabled);
+	int8_t (*GetSequenceStepEnables)(struct vl_data *Dev,
+		struct VL_SchedulerSequenceSteps_t *pSchedulerSequenceSteps);
+	int8_t (*SetSequenceStepTimeout)(struct vl_data *Dev,
+			uint8_t SequenceStepId,
+			unsigned int TimeOutMilliSecs);
+	int8_t (*GetSequenceStepTimeout)(struct vl_data *Dev,
+			uint8_t SequenceStepId,
+			unsigned int *pTimeOutMilliSecs);
+	int8_t (*GetNumberOfSequenceSteps)(struct vl_data *Dev,
+			uint8_t *pNumberOfSequenceSteps);
+	int8_t (*GetSequenceStepsInfo)(
+			uint8_t SequenceStepId,
+			char *pSequenceStepsString);
+	int8_t (*SetInterMeasurementPeriodMilliSeconds)(
+			struct vl_data *Dev,
+			uint32_t InterMeasurementPeriodMilliSeconds);
+	int8_t (*GetInterMeasurementPeriodMilliSeconds)(
+			struct vl_data *Dev,
+			uint32_t *pInterMeasurementPeriodMilliSeconds);
+	int8_t (*SetXTalkCompensationEnable)(struct vl_data *Dev,
+			uint8_t XTalkCompensationEnable);
+	int8_t (*GetXTalkCompensationEnable)(struct vl_data *Dev,
+			uint8_t *pXTalkCompensationEnable);
+	int8_t (*SetXTalkCompensationRateMegaCps)(
+			struct vl_data *Dev,
+			unsigned int XTalkCompensationRateMegaCps);
+	int8_t (*GetXTalkCompensationRateMegaCps)(
+			struct vl_data *Dev,
+			unsigned int *pXTalkCompensationRateMegaCps);
+	int8_t (*GetNumberOfLimitCheck)(
+			uint16_t *pNumberOfLimitCheck);
+	int8_t (*GetLimitCheckInfo)(struct vl_data *Dev,
+			uint16_t LimitCheckId, char *pLimitCheckString);
+	int8_t (*SetLimitCheckEnable)(struct vl_data *Dev,
+			uint16_t LimitCheckId,
+			uint8_t LimitCheckEnable);
+	int8_t (*GetLimitCheckEnable)(struct vl_data *Dev,
+			uint16_t LimitCheckId, uint8_t *pLimitCheckEnable);
+	int8_t (*SetLimitCheckValue)(struct vl_data *Dev,
+			uint16_t LimitCheckId,
+			unsigned int LimitCheckValue);
+	int8_t (*GetLimitCheckValue)(struct vl_data *Dev,
+			uint16_t LimitCheckId,
+			unsigned int *pLimitCheckValue);
+	int8_t (*GetLimitCheckCurrent)(struct vl_data *Dev,
+		uint16_t LimitCheckId, unsigned int *pLimitCheckCurrent);
+	int8_t (*SetWrapAroundCheckEnable)(struct vl_data *Dev,
+			uint8_t WrapAroundCheckEnable);
+	int8_t (*GetWrapAroundCheckEnable)(struct vl_data *Dev,
+			uint8_t *pWrapAroundCheckEnable);
+	int8_t (*PerformSingleMeasurement)(struct vl_data *Dev);
+	int8_t (*PerformRefCalibration)(struct vl_data *Dev,
+			uint8_t *pVhvSettings, uint8_t *pPhaseCal);
+	int8_t (*SetRefCalibration)(struct vl_data *Dev,
+			uint8_t VhvSettings, uint8_t PhaseCal);
+	int8_t (*GetRefCalibration)(struct vl_data *Dev,
+			uint8_t *pVhvSettings, uint8_t *pPhaseCal);
+	int8_t (*PerformXTalkCalibration)(struct vl_data *Dev,
+			unsigned int XTalkCalDistance,
+			unsigned int *pXTalkCompensationRateMegaCps);
+	int8_t (*PerformOffsetCalibration)(struct vl_data *Dev,
+			unsigned int CalDistanceMilliMeter,
+			int32_t *pOffsetMicroMeter);
+	int8_t (*StartMeasurement)(struct vl_data *Dev);
+	int8_t (*StopMeasurement)(struct vl_data *Dev);
+	int8_t (*GetMeasurementDataReady)(struct vl_data *Dev,
+			uint8_t *pMeasurementDataReady);
+	int8_t (*WaitDeviceReadyForNewMeasurement)(struct vl_data *Dev,
+			uint32_t MaxLoop);
+	int8_t (*GetRangingMeasurementData)(struct vl_data *Dev,
+	struct VL_RangingMeasurementData_t *pRangingMeasurementData);
+	int8_t (*GetHistogramMeasurementData)(struct vl_data *Dev,
+	struct VL_HistogramMeasurementData_t *pHistogramMeasurementData);
+	int8_t (*PerformSingleRangingMeasurement)(struct vl_data *Dev,
+	struct VL_RangingMeasurementData_t *pRangingMeasurementData);
+	int8_t (*PerformSingleHistogramMeasurement)(struct vl_data *Dev,
+	struct VL_HistogramMeasurementData_t *pHistogramMeasurementData);
+	int8_t (*SetNumberOfROIZones)(struct vl_data *Dev,
+			uint8_t NumberOfROIZones);
+	int8_t (*GetNumberOfROIZones)(struct vl_data *Dev,
+			uint8_t *pNumberOfROIZones);
+	int8_t (*GetMaxNumberOfROIZones)(struct vl_data *Dev,
+			uint8_t *pMaxNumberOfROIZones);
+	int8_t (*SetGpioConfig)(struct vl_data *Dev,
+			uint8_t Pin,
+			uint8_t DeviceMode,
+			uint8_t Functionality,
+			uint8_t Polarity);
+	int8_t (*GetGpioConfig)(struct vl_data *Dev,
+			uint8_t Pin,
+			uint8_t *pDeviceMode,
+			uint8_t *pFunctionality,
+			uint8_t *pPolarity);
+	int8_t (*SetInterruptThresholds)(struct vl_data *Dev,
+			uint8_t DeviceMode,
+			unsigned int ThresholdLow,
+			unsigned int ThresholdHigh);
+	int8_t (*GetInterruptThresholds)(struct vl_data *Dev,
+			uint8_t DeviceMode,
+			unsigned int *pThresholdLow,
+			unsigned int *pThresholdHigh);
+	int8_t (*ClearInterruptMask)(struct vl_data *Dev,
+			uint32_t InterruptMask);
+	int8_t (*GetInterruptMaskStatus)(struct vl_data *Dev,
+			uint32_t *pInterruptMaskStatus);
+	int8_t (*EnableInterruptMask)(struct vl_data *Dev,
+		uint32_t InterruptMask);
+	int8_t (*SetSpadAmbientDamperThreshold)(struct vl_data *Dev,
+			uint16_t SpadAmbientDamperThreshold);
+	int8_t (*GetSpadAmbientDamperThreshold)(struct vl_data *Dev,
+			uint16_t *pSpadAmbientDamperThreshold);
+	int8_t (*SetSpadAmbientDamperFactor)(struct vl_data *Dev,
+			uint16_t SpadAmbientDamperFactor);
+	int8_t (*GetSpadAmbientDamperFactor)(struct vl_data *Dev,
+			uint16_t *pSpadAmbientDamperFactor);
+	int8_t (*PerformRefSpadManagement)(struct vl_data *Dev,
+			uint32_t *refSpadCount, uint8_t *isApertureSpads);
+	int8_t (*SetReferenceSpads)(struct vl_data *Dev,
+			uint32_t count, uint8_t isApertureSpads);
+	int8_t (*GetReferenceSpads)(struct vl_data *Dev,
+			uint32_t *pSpadCount, uint8_t *pIsApertureSpads);
+};
+
+static struct stmvl53l0x_api_fn_t stmvl53l0x_api_func_tbl = {
+	.GetVersion = VL_GetVersion,
+	.GetPalSpecVersion = VL_GetPalSpecVersion,
+	.GetProductRevision = VL_GetProductRevision,
+	.GetDeviceInfo = VL_GetDeviceInfo,
+	.GetDeviceErrorStatus = VL_GetDeviceErrorStatus,
+	.GetRangeStatusString = VL_GetRangeStatusString,
+	.GetDeviceErrorString = VL_GetDeviceErrorString,
+	.GetPalErrorString = VL_GetPalErrorString,
+	.GetPalState = VL_GetPalState,
+	.SetPowerMode = VL_SetPowerMode,
+	.GetPowerMode = VL_GetPowerMode,
+	.SetOffsetCalibrationDataMicroMeter =
+		VL_SetOffsetCalibrationDataMicroMeter,
+	.SetLinearityCorrectiveGain =
+		VL_SetLinearityCorrectiveGain,
+	.GetLinearityCorrectiveGain =
+		VL_GetLinearityCorrectiveGain,
+	.GetOffsetCalibrationDataMicroMeter =
+		VL_GetOffsetCalibrationDataMicroMeter,
+	.SetGroupParamHold = VL_SetGroupParamHold,
+	.GetUpperLimitMilliMeter = VL_GetUpperLimitMilliMeter,
+	.SetDeviceAddress = VL_SetDeviceAddress,
+	.DataInit = VL_DataInit,
+	.SetTuningSettingBuffer = VL_SetTuningSettingBuffer,
+	.GetTuningSettingBuffer = VL_GetTuningSettingBuffer,
+	.StaticInit = VL_StaticInit,
+	.WaitDeviceBooted = VL_WaitDeviceBooted,
+	.ResetDevice = VL_ResetDevice,
+	.SetDeviceParameters = VL_SetDeviceParameters,
+	.SetDeviceMode = VL_SetDeviceMode,
+	.GetDeviceMode = VL_GetDeviceMode,
+	.SetHistogramMode = VL_SetHistogramMode,
+	.GetHistogramMode = VL_GetHistogramMode,
+	.SetMeasurementTimingBudgetMicroSeconds =
+		VL_SetMeasurementTimingBudgetMicroSeconds,
+	.GetMeasurementTimingBudgetMicroSeconds =
+		VL_GetMeasurementTimingBudgetMicroSeconds,
+	.GetVcselPulsePeriod = VL_GetVcselPulsePeriod,
+	.SetVcselPulsePeriod = VL_SetVcselPulsePeriod,
+	.SetSequenceStepEnable = VL_SetSequenceStepEnable,
+	.GetSequenceStepEnable = VL_GetSequenceStepEnable,
+	.GetSequenceStepEnables = VL_GetSequenceStepEnables,
+	.SetSequenceStepTimeout = VL_SetSequenceStepTimeout,
+	.GetSequenceStepTimeout = VL_GetSequenceStepTimeout,
+	.GetNumberOfSequenceSteps = VL_GetNumberOfSequenceSteps,
+	.GetSequenceStepsInfo = VL_GetSequenceStepsInfo,
+	.SetInterMeasurementPeriodMilliSeconds =
+		VL_SetInterMeasurementPeriodMilliSeconds,
+	.GetInterMeasurementPeriodMilliSeconds =
+		VL_GetInterMeasurementPeriodMilliSeconds,
+	.SetXTalkCompensationEnable = VL_SetXTalkCompensationEnable,
+	.GetXTalkCompensationEnable = VL_GetXTalkCompensationEnable,
+	.SetXTalkCompensationRateMegaCps =
+		VL_SetXTalkCompensationRateMegaCps,
+	.GetXTalkCompensationRateMegaCps =
+		VL_GetXTalkCompensationRateMegaCps,
+	.GetNumberOfLimitCheck = VL_GetNumberOfLimitCheck,
+	.GetLimitCheckInfo = VL_GetLimitCheckInfo,
+	.SetLimitCheckEnable = VL_SetLimitCheckEnable,
+	.GetLimitCheckEnable = VL_GetLimitCheckEnable,
+	.SetLimitCheckValue = VL_SetLimitCheckValue,
+	.GetLimitCheckValue = VL_GetLimitCheckValue,
+	.GetLimitCheckCurrent = VL_GetLimitCheckCurrent,
+	.SetWrapAroundCheckEnable = VL_SetWrapAroundCheckEnable,
+	.GetWrapAroundCheckEnable = VL_GetWrapAroundCheckEnable,
+	.PerformSingleMeasurement = VL_PerformSingleMeasurement,
+	.PerformRefCalibration = VL_PerformRefCalibration,
+	.SetRefCalibration = VL_SetRefCalibration,
+	.GetRefCalibration = VL_GetRefCalibration,
+	.PerformXTalkCalibration = VL_PerformXTalkCalibration,
+	.PerformOffsetCalibration = VL_PerformOffsetCalibration,
+	.StartMeasurement = VL_StartMeasurement,
+	.StopMeasurement = VL_StopMeasurement,
+	.GetMeasurementDataReady = VL_GetMeasurementDataReady,
+	.WaitDeviceReadyForNewMeasurement =
+		VL_WaitDeviceReadyForNewMeasurement,
+	.GetRangingMeasurementData = VL_GetRangingMeasurementData,
+	.GetHistogramMeasurementData = VL_GetHistogramMeasurementData,
+	.PerformSingleRangingMeasurement =
+		VL_PerformSingleRangingMeasurement,
+	.PerformSingleHistogramMeasurement =
+		VL_PerformSingleHistogramMeasurement,
+	.SetNumberOfROIZones = VL_SetNumberOfROIZones,
+	.GetNumberOfROIZones = VL_GetNumberOfROIZones,
+	.GetMaxNumberOfROIZones = VL_GetMaxNumberOfROIZones,
+	.SetGpioConfig = VL_SetGpioConfig,
+	.GetGpioConfig = VL_GetGpioConfig,
+	.SetInterruptThresholds = VL_SetInterruptThresholds,
+	.GetInterruptThresholds = VL_GetInterruptThresholds,
+	.ClearInterruptMask = VL_ClearInterruptMask,
+	.GetInterruptMaskStatus = VL_GetInterruptMaskStatus,
+	.EnableInterruptMask = VL_EnableInterruptMask,
+	.SetSpadAmbientDamperThreshold = VL_SetSpadAmbientDamperThreshold,
+	.GetSpadAmbientDamperThreshold = VL_GetSpadAmbientDamperThreshold,
+	.SetSpadAmbientDamperFactor = VL_SetSpadAmbientDamperFactor,
+	.GetSpadAmbientDamperFactor = VL_GetSpadAmbientDamperFactor,
+	.PerformRefSpadManagement = VL_PerformRefSpadManagement,
+	.SetReferenceSpads = VL_SetReferenceSpads,
+	.GetReferenceSpads = VL_GetReferenceSpads,
+
+};
+struct stmvl53l0x_api_fn_t *papi_func_tbl;
+
+/*
+ * IOCTL definitions
+ */
+#define VL_IOCTL_INIT			_IO('p', 0x01)
+#define VL_IOCTL_XTALKCALB		_IOW('p', 0x02, unsigned int)
+#define VL_IOCTL_OFFCALB		_IOW('p', 0x03, unsigned int)
+#define VL_IOCTL_STOP			_IO('p', 0x05)
+#define VL_IOCTL_SETXTALK		_IOW('p', 0x06, unsigned int)
+#define VL_IOCTL_SETOFFSET		_IOW('p', 0x07, int8_t)
+#define VL_IOCTL_GETDATAS \
+			_IOR('p', 0x0b, struct VL_RangingMeasurementData_t)
+#define VL_IOCTL_REGISTER \
+			_IOWR('p', 0x0c, struct stmvl53l0x_register)
+#define VL_IOCTL_PARAMETER \
+			_IOWR('p', 0x0d, struct stmvl53l0x_parameter)
+
+static long stmvl53l0x_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg);
+/*static int stmvl53l0x_flush(struct file *file, fl_owner_t id);*/
+static int stmvl53l0x_open(struct inode *inode, struct file *file);
+static int stmvl53l0x_init_client(struct vl_data *data);
+static int stmvl53l0x_start(struct vl_data *data, uint8_t scaling,
+			enum init_mode_e mode);
+static int stmvl53l0x_stop(struct vl_data *data);
+
+#ifdef DEBUG_TIME_LOG
+static void stmvl53l0x_DebugTimeGet(struct timeval *ptv)
+{
+	do_gettimeofday(ptv);
+}
+
+static void stmvl53l0x_DebugTimeDuration(struct timeval *pstart_tv,
+			struct timeval *pstop_tv)
+{
+	long total_sec, total_msec;
+
+	total_sec = pstop_tv->tv_sec - pstart_tv->tv_sec;
+	total_msec = (pstop_tv->tv_usec - pstart_tv->tv_usec)/1000;
+	total_msec += total_sec * 1000;
+	dbg("elapsedTime:%ld\n", total_msec);
+}
+#endif
+
+static void stmvl53l0x_setupAPIFunctions(void)
+{
+
+	/*cut 1.1*/
+	err("to setup API cut 1.1\n");
+	papi_func_tbl->GetVersion = VL_GetVersion;
+	papi_func_tbl->GetPalSpecVersion = VL_GetPalSpecVersion;
+	papi_func_tbl->GetProductRevision = VL_GetProductRevision;
+	papi_func_tbl->GetDeviceInfo = VL_GetDeviceInfo;
+	papi_func_tbl->GetDeviceErrorStatus = VL_GetDeviceErrorStatus;
+	papi_func_tbl->GetRangeStatusString = VL_GetRangeStatusString;
+	papi_func_tbl->GetDeviceErrorString = VL_GetDeviceErrorString;
+	papi_func_tbl->GetPalErrorString = VL_GetPalErrorString;
+	papi_func_tbl->GetPalState = VL_GetPalState;
+	papi_func_tbl->SetPowerMode = VL_SetPowerMode;
+	papi_func_tbl->GetPowerMode = VL_GetPowerMode;
+	papi_func_tbl->SetOffsetCalibrationDataMicroMeter =
+		VL_SetOffsetCalibrationDataMicroMeter;
+	papi_func_tbl->GetOffsetCalibrationDataMicroMeter =
+		VL_GetOffsetCalibrationDataMicroMeter;
+	papi_func_tbl->SetLinearityCorrectiveGain =
+		VL_SetLinearityCorrectiveGain;
+	papi_func_tbl->GetLinearityCorrectiveGain =
+		VL_GetLinearityCorrectiveGain;
+	papi_func_tbl->SetGroupParamHold = VL_SetGroupParamHold;
+	papi_func_tbl->GetUpperLimitMilliMeter =
+		VL_GetUpperLimitMilliMeter;
+	papi_func_tbl->SetDeviceAddress = VL_SetDeviceAddress;
+	papi_func_tbl->DataInit = VL_DataInit;
+	papi_func_tbl->SetTuningSettingBuffer = VL_SetTuningSettingBuffer;
+	papi_func_tbl->GetTuningSettingBuffer = VL_GetTuningSettingBuffer;
+	papi_func_tbl->StaticInit = VL_StaticInit;
+	papi_func_tbl->WaitDeviceBooted = VL_WaitDeviceBooted;
+	papi_func_tbl->ResetDevice = VL_ResetDevice;
+	papi_func_tbl->SetDeviceParameters = VL_SetDeviceParameters;
+	papi_func_tbl->SetDeviceMode = VL_SetDeviceMode;
+	papi_func_tbl->GetDeviceMode = VL_GetDeviceMode;
+	papi_func_tbl->SetHistogramMode = VL_SetHistogramMode;
+	papi_func_tbl->GetHistogramMode = VL_GetHistogramMode;
+	papi_func_tbl->SetMeasurementTimingBudgetMicroSeconds =
+		VL_SetMeasurementTimingBudgetMicroSeconds;
+	papi_func_tbl->GetMeasurementTimingBudgetMicroSeconds =
+		VL_GetMeasurementTimingBudgetMicroSeconds;
+	papi_func_tbl->GetVcselPulsePeriod = VL_GetVcselPulsePeriod;
+	papi_func_tbl->SetVcselPulsePeriod = VL_SetVcselPulsePeriod;
+	papi_func_tbl->SetSequenceStepEnable = VL_SetSequenceStepEnable;
+	papi_func_tbl->GetSequenceStepEnable = VL_GetSequenceStepEnable;
+	papi_func_tbl->GetSequenceStepEnables = VL_GetSequenceStepEnables;
+	papi_func_tbl->SetSequenceStepTimeout = VL_SetSequenceStepTimeout;
+	papi_func_tbl->GetSequenceStepTimeout = VL_GetSequenceStepTimeout;
+	papi_func_tbl->GetNumberOfSequenceSteps =
+		VL_GetNumberOfSequenceSteps;
+	papi_func_tbl->GetSequenceStepsInfo = VL_GetSequenceStepsInfo;
+	papi_func_tbl->SetInterMeasurementPeriodMilliSeconds =
+		VL_SetInterMeasurementPeriodMilliSeconds;
+	papi_func_tbl->GetInterMeasurementPeriodMilliSeconds =
+		VL_GetInterMeasurementPeriodMilliSeconds;
+	papi_func_tbl->SetXTalkCompensationEnable =
+		VL_SetXTalkCompensationEnable;
+	papi_func_tbl->GetXTalkCompensationEnable =
+		VL_GetXTalkCompensationEnable;
+	papi_func_tbl->SetXTalkCompensationRateMegaCps =
+		VL_SetXTalkCompensationRateMegaCps;
+	papi_func_tbl->GetXTalkCompensationRateMegaCps =
+		VL_GetXTalkCompensationRateMegaCps;
+	papi_func_tbl->GetNumberOfLimitCheck = VL_GetNumberOfLimitCheck;
+	papi_func_tbl->GetLimitCheckInfo = VL_GetLimitCheckInfo;
+	papi_func_tbl->SetLimitCheckEnable = VL_SetLimitCheckEnable;
+	papi_func_tbl->GetLimitCheckEnable = VL_GetLimitCheckEnable;
+	papi_func_tbl->SetLimitCheckValue = VL_SetLimitCheckValue;
+	papi_func_tbl->GetLimitCheckValue = VL_GetLimitCheckValue;
+	papi_func_tbl->GetLimitCheckCurrent = VL_GetLimitCheckCurrent;
+	papi_func_tbl->SetWrapAroundCheckEnable =
+		VL_SetWrapAroundCheckEnable;
+	papi_func_tbl->GetWrapAroundCheckEnable =
+		VL_GetWrapAroundCheckEnable;
+	papi_func_tbl->PerformSingleMeasurement =
+		VL_PerformSingleMeasurement;
+	papi_func_tbl->PerformRefCalibration = VL_PerformRefCalibration;
+	papi_func_tbl->SetRefCalibration = VL_SetRefCalibration;
+	papi_func_tbl->GetRefCalibration = VL_GetRefCalibration;
+	papi_func_tbl->PerformXTalkCalibration =
+		VL_PerformXTalkCalibration;
+	papi_func_tbl->PerformOffsetCalibration =
+		VL_PerformOffsetCalibration;
+	papi_func_tbl->StartMeasurement = VL_StartMeasurement;
+	papi_func_tbl->StopMeasurement = VL_StopMeasurement;
+	papi_func_tbl->GetMeasurementDataReady =
+		VL_GetMeasurementDataReady;
+	papi_func_tbl->WaitDeviceReadyForNewMeasurement =
+		VL_WaitDeviceReadyForNewMeasurement;
+	papi_func_tbl->GetRangingMeasurementData =
+		VL_GetRangingMeasurementData;
+	papi_func_tbl->GetHistogramMeasurementData =
+		VL_GetHistogramMeasurementData;
+	papi_func_tbl->PerformSingleRangingMeasurement =
+		VL_PerformSingleRangingMeasurement;
+	papi_func_tbl->PerformSingleHistogramMeasurement =
+		VL_PerformSingleHistogramMeasurement;
+	papi_func_tbl->SetNumberOfROIZones = VL_SetNumberOfROIZones;
+	papi_func_tbl->GetNumberOfROIZones = VL_GetNumberOfROIZones;
+	papi_func_tbl->GetMaxNumberOfROIZones = VL_GetMaxNumberOfROIZones;
+	papi_func_tbl->SetGpioConfig = VL_SetGpioConfig;
+	papi_func_tbl->GetGpioConfig = VL_GetGpioConfig;
+	papi_func_tbl->SetInterruptThresholds = VL_SetInterruptThresholds;
+	papi_func_tbl->GetInterruptThresholds = VL_GetInterruptThresholds;
+	papi_func_tbl->ClearInterruptMask = VL_ClearInterruptMask;
+	papi_func_tbl->GetInterruptMaskStatus = VL_GetInterruptMaskStatus;
+	papi_func_tbl->EnableInterruptMask = VL_EnableInterruptMask;
+	papi_func_tbl->SetSpadAmbientDamperThreshold =
+		VL_SetSpadAmbientDamperThreshold;
+	papi_func_tbl->GetSpadAmbientDamperThreshold =
+		VL_GetSpadAmbientDamperThreshold;
+	papi_func_tbl->SetSpadAmbientDamperFactor =
+		VL_SetSpadAmbientDamperFactor;
+	papi_func_tbl->GetSpadAmbientDamperFactor =
+		VL_GetSpadAmbientDamperFactor;
+	papi_func_tbl->PerformRefSpadManagement =
+		VL_PerformRefSpadManagement;
+	papi_func_tbl->SetReferenceSpads = VL_SetReferenceSpads;
+	papi_func_tbl->GetReferenceSpads = VL_GetReferenceSpads;
+
+}
+
+static void stmvl53l0x_ps_read_measurement(struct vl_data *data)
+{
+	struct timeval tv;
+	struct vl_data *vl53l0x_dev = data;
+	int8_t Status = VL_ERROR_NONE;
+	unsigned int LimitCheckCurrent;
+
+	do_gettimeofday(&tv);
+
+	data->ps_data = data->rangeData.RangeMilliMeter;
+	input_report_abs(data->input_dev_ps, ABS_DISTANCE,
+		(int)(data->ps_data + 5) / 10);
+	input_report_abs(data->input_dev_ps, ABS_HAT0X, tv.tv_sec);
+	input_report_abs(data->input_dev_ps, ABS_HAT0Y, tv.tv_usec);
+	input_report_abs(data->input_dev_ps, ABS_HAT1X,
+		data->rangeData.RangeMilliMeter);
+	input_report_abs(data->input_dev_ps, ABS_HAT1Y,
+		data->rangeData.RangeStatus);
+	input_report_abs(data->input_dev_ps, ABS_HAT2X,
+		data->rangeData.SignalRateRtnMegaCps);
+	input_report_abs(data->input_dev_ps, ABS_HAT2Y,
+		data->rangeData.AmbientRateRtnMegaCps);
+	input_report_abs(data->input_dev_ps, ABS_HAT3X,
+		data->rangeData.MeasurementTimeUsec);
+	input_report_abs(data->input_dev_ps, ABS_HAT3Y,
+		data->rangeData.RangeDMaxMilliMeter);
+	Status = papi_func_tbl->GetLimitCheckCurrent(vl53l0x_dev,
+		VL_CHECKENABLE_SIGMA_FINAL_RANGE,
+		&LimitCheckCurrent);
+	if (Status == VL_ERROR_NONE) {
+		input_report_abs(data->input_dev_ps, ABS_WHEEL,
+				LimitCheckCurrent);
+	}
+	input_report_abs(data->input_dev_ps, ABS_PRESSURE,
+		data->rangeData.EffectiveSpadRtnCount);
+	input_sync(data->input_dev_ps);
+
+	if (data->enableDebug)
+		err("range:%d, RtnRateMcps:%d,err:0x%x\n",
+		data->rangeData.RangeMilliMeter,
+			data->rangeData.SignalRateRtnMegaCps,
+			data->rangeData.RangeStatus);
+		err("Dmax:%d,rtnambr:%d,time:%d,Spad:%d,SigmaLimit:%d\n",
+			data->rangeData.RangeDMaxMilliMeter,
+			data->rangeData.AmbientRateRtnMegaCps,
+			data->rangeData.MeasurementTimeUsec,
+			data->rangeData.EffectiveSpadRtnCount,
+			LimitCheckCurrent);
+
+
+}
+
+static void stmvl53l0x_cancel_handler(struct vl_data *data)
+{
+	unsigned long flags;
+	bool ret;
+
+	spin_lock_irqsave(&data->update_lock.wait_lock, flags);
+	/*
+	 * If work is already scheduled then subsequent schedules will not
+	 * change the scheduled time that's why we have to cancel it first.
+	 */
+	ret = cancel_delayed_work(&data->dwork);
+	if (ret == 0)
+		err("cancel_delayed_work return FALSE\n");
+
+	spin_unlock_irqrestore(&data->update_lock.wait_lock, flags);
+
+}
+
+void stmvl53l0x_schedule_handler(struct vl_data *data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&data->update_lock.wait_lock, flags);
+	/*
+	 * If work is already scheduled then subsequent schedules will not
+	 * change the scheduled time that's why we have to cancel it first.
+	 */
+	cancel_delayed_work(&data->dwork);
+	schedule_delayed_work(&data->dwork, 0);
+	spin_unlock_irqrestore(&data->update_lock.wait_lock, flags);
+
+}
+
+/* Flag used to exit the thread when kthread_stop() is invoked */
+static int poll_thread_exit;
+int stmvl53l0x_poll_thread(void *data)
+{
+	struct vl_data *vl53l0x_dev = data;
+	int8_t Status = VL_ERROR_NONE;
+	uint32_t sleep_time = 0;
+	uint32_t interruptStatus = 0;
+
+	dbg("Starting Polling thread\n");
+
+	while (!kthread_should_stop()) {
+		/* Check if enable_ps_sensor is true or */
+		/* exit request is made. If not block */
+		wait_event(vl53l0x_dev->poll_thread_wq,
+			(vl53l0x_dev->enable_ps_sensor || poll_thread_exit));
+		if (poll_thread_exit) {
+			dbg("Exiting the poll thread\n");
+			break;
+		}
+
+		mutex_lock(&vl53l0x_dev->work_mutex);
+
+		sleep_time = vl53l0x_dev->delay_ms;
+		Status = VL_GetInterruptMaskStatus(vl53l0x_dev,
+			&interruptStatus);
+		if (Status == VL_ERROR_NONE &&
+			interruptStatus &&
+			interruptStatus != vl53l0x_dev->interruptStatus) {
+			vl53l0x_dev->interruptStatus = interruptStatus;
+			vl53l0x_dev->noInterruptCount = 0;
+			stmvl53l0x_schedule_handler(vl53l0x_dev);
+
+		} else {
+			vl53l0x_dev->noInterruptCount++;
+		}
+
+	/* Force Clear interrupt mask and restart if no interrupt */
+	/* after twice the timingBudget */
+	if ((vl53l0x_dev->noInterruptCount * vl53l0x_dev->delay_ms) >
+	(vl53l0x_dev->timingBudget * 2)) {
+		dbg("No interrupt after (%u) msec(TimingBudget = %u)\n",
+		(vl53l0x_dev->noInterruptCount * vl53l0x_dev->delay_ms),
+			vl53l0x_dev->timingBudget);
+		Status = papi_func_tbl->ClearInterruptMask(vl53l0x_dev, 0);
+		if (vl53l0x_dev->deviceMode ==
+			VL_DEVICEMODE_SINGLE_RANGING) {
+			Status = papi_func_tbl->StartMeasurement(vl53l0x_dev);
+			if (Status != VL_ERROR_NONE)
+				dbg("Status = %d\n", Status);
+			}
+		}
+
+		mutex_unlock(&vl53l0x_dev->work_mutex);
+
+		msleep(sleep_time);
+	}
+
+	return 0;
+}
+
+/* work handler */
+static void stmvl53l0x_work_handler(struct work_struct *work)
+{
+	struct vl_data *data = container_of(work,
+	struct vl_data,	dwork.work);
+
+	struct vl_data *vl53l0x_dev = data;
+
+	int8_t Status = VL_ERROR_NONE;
+
+	mutex_lock(&data->work_mutex);
+	/* dbg("Enter\n"); */
+
+
+	if (vl53l0x_dev->enable_ps_sensor == 1) {
+#ifdef DEBUG_TIME_LOG
+		stmvl53l0x_DebugTimeGet(&stop_tv);
+		stmvl53l0x_DebugTimeDuration(&start_tv, &stop_tv);
+#endif
+		/* ISR has scheduled this function */
+		if (vl53l0x_dev->interrupt_received == 1) {
+			Status = papi_func_tbl->GetInterruptMaskStatus(
+			vl53l0x_dev, &vl53l0x_dev->interruptStatus);
+			if (Status != VL_ERROR_NONE) {
+				dbg("%s(%d) : Status = %d\n",
+				__func__, __LINE__, Status);
+			}
+			vl53l0x_dev->interrupt_received = 0;
+		}
+		if (data->enableDebug)
+			dbg("interruptStatus:0x%x, interrupt_received:%d\n",
+			vl53l0x_dev->interruptStatus,
+				vl53l0x_dev->interrupt_received);
+
+		if (vl53l0x_dev->interruptStatus ==
+			vl53l0x_dev->gpio_function) {
+			Status = papi_func_tbl->ClearInterruptMask(vl53l0x_dev,
+				0);
+			if (Status != VL_ERROR_NONE) {
+				dbg("%s(%d) : Status = %d\n",
+					__func__, __LINE__, Status);
+			} else {
+				Status =
+				papi_func_tbl->GetRangingMeasurementData(
+					vl53l0x_dev, &(data->rangeData));
+				/* to push the measurement */
+				if (Status == VL_ERROR_NONE)
+					stmvl53l0x_ps_read_measurement(data);
+				else
+					dbg("%s(%d) : Status = %d\n",
+						__func__, __LINE__, Status);
+
+				dbg("Measured range:%d\n",
+				data->rangeData.RangeMilliMeter);
+
+				if (data->enableDebug)
+					dbg("Measured range:%d\n",
+					data->rangeData.RangeMilliMeter);
+
+				if (data->deviceMode ==
+					VL_DEVICEMODE_SINGLE_RANGING)
+					Status =
+					papi_func_tbl->StartMeasurement(
+					vl53l0x_dev);
+			}
+		}
+#ifdef DEBUG_TIME_LOG
+		stmvl53l0x_DebugTimeGet(&start_tv);
+#endif
+
+		}
+
+
+	vl53l0x_dev->interruptStatus = 0;
+
+	mutex_unlock(&data->work_mutex);
+
+}
+
+
+/*
+ * SysFS support
+ */
+static ssize_t stmvl53l0x_show_enable_ps_sensor(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct vl_data *data = dev_get_drvdata(dev);
+
+	return snprintf(buf, 5, "%d\n", data->enable_ps_sensor);
+}
+
+static ssize_t stmvl53l0x_store_enable_ps_sensor(struct device *dev,
+				struct device_attribute *attr, const char *buf,
+				size_t count)
+{
+	struct vl_data *data = dev_get_drvdata(dev);
+
+	unsigned int val;
+
+	kstrtoint(buf, 10, &val);
+	if ((val != 0) && (val != 1)) {
+		err("store unvalid value=%ld\n", val);
+		return count;
+	}
+	mutex_lock(&data->work_mutex);
+	dbg("Enter, enable_ps_sensor flag:%d\n",
+		data->enable_ps_sensor);
+	dbg("enable ps senosr ( %ld)\n", val);
+
+	if (val == 1) {
+		/* turn on tof sensor */
+		if (data->enable_ps_sensor == 0) {
+			/* to start */
+			stmvl53l0x_start(data, 3, NORMAL_MODE);
+		} else {
+			err("Already enabled. Skip !");
+		}
+	} else {
+		/* turn off tof sensor */
+		if (data->enable_ps_sensor == 1) {
+			data->enable_ps_sensor = 0;
+			/* to stop */
+			stmvl53l0x_stop(data);
+		}
+	}
+	dbg("End\n");
+	mutex_unlock(&data->work_mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(enable_ps_sensor, 0664/*S_IWUGO | S_IRUGO*/,
+				   stmvl53l0x_show_enable_ps_sensor,
+					stmvl53l0x_store_enable_ps_sensor);
+
+static ssize_t stmvl53l0x_show_enable_debug(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct vl_data *data = dev_get_drvdata(dev);
+
+	return snprintf(buf, 5, "%d\n", data->enableDebug);
+}
+
+/* for debug */
+static ssize_t stmvl53l0x_store_enable_debug(struct device *dev,
+					struct device_attribute *attr, const
+					char *buf, size_t count)
+{
+	struct vl_data *data = dev_get_drvdata(dev);
+	int on;
+
+	kstrtoint(buf, 10, &on);
+	if ((on != 0) &&  (on != 1)) {
+		err("set debug=%ld\n", on);
+		return count;
+	}
+	data->enableDebug = on;
+
+	return count;
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(enable_debug, 0660/*S_IWUSR | S_IRUGO*/,
+				   stmvl53l0x_show_enable_debug,
+					stmvl53l0x_store_enable_debug);
+
+static ssize_t stmvl53l0x_show_set_delay_ms(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct vl_data *data = dev_get_drvdata(dev);
+
+	return snprintf(buf, 5, "%d\n", data->delay_ms);
+}
+
+/* for work handler scheduler time */
+static ssize_t stmvl53l0x_store_set_delay_ms(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct vl_data *data = dev_get_drvdata(dev);
+	int delay_ms;
+
+	kstrtoint(buf, 10, &delay_ms);
+	if (delay_ms == 0) {
+		err("set delay_ms=%ld\n", delay_ms);
+		return count;
+	}
+	mutex_lock(&data->work_mutex);
+	data->delay_ms = delay_ms;
+	mutex_unlock(&data->work_mutex);
+
+	return count;
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(set_delay_ms, 0660/*S_IWUGO | S_IRUGO*/,
+				   stmvl53l0x_show_set_delay_ms,
+					stmvl53l0x_store_set_delay_ms);
+
+/* Timing Budget */
+static ssize_t stmvl53l0x_show_timing_budget(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct vl_data *data = dev_get_drvdata(dev);
+
+	return snprintf(buf, 10, "%d\n", data->timingBudget);
+}
+
+static ssize_t stmvl53l0x_store_set_timing_budget(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct vl_data *data = dev_get_drvdata(dev);
+	int timingBudget;
+
+	kstrtoint(buf, 10, &timingBudget);
+	if (timingBudget == 0) {
+		err("set timingBudget=%ld\n", timingBudget);
+		return count;
+	}
+	mutex_lock(&data->work_mutex);
+	data->timingBudget = timingBudget;
+	mutex_unlock(&data->work_mutex);
+
+	return count;
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(set_timing_budget, 0660/*S_IWUGO | S_IRUGO*/,
+				   stmvl53l0x_show_timing_budget,
+					stmvl53l0x_store_set_timing_budget);
+
+
+/* Long Range  */
+static ssize_t stmvl53l0x_show_long_range(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct vl_data *data = dev_get_drvdata(dev);
+
+	return snprintf(buf, 5, "%d\n", data->useLongRange);
+}
+
+static ssize_t stmvl53l0x_store_set_long_range(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct vl_data *data = dev_get_drvdata(dev);
+	int useLongRange;
+
+	kstrtoint(buf, 10, &useLongRange);
+	if ((useLongRange != 0) &&  (useLongRange != 1)) {
+		err("set useLongRange=%ld\n", useLongRange);
+		return count;
+	}
+
+	mutex_lock(&data->work_mutex);
+	data->useLongRange = useLongRange;
+	if (useLongRange)
+		data->timingBudget = 26000;
+	else
+		data->timingBudget = 200000;
+
+	mutex_unlock(&data->work_mutex);
+
+	return count;
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(set_long_range, 0660/*S_IWUGO | S_IRUGO*/,
+				   stmvl53l0x_show_long_range,
+					stmvl53l0x_store_set_long_range);
+
+static ssize_t stmvl53l0x_show_meter(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct vl_data *data = dev_get_drvdata(dev);
+	struct VL_RangingMeasurementData_t Measure;
+
+	papi_func_tbl->PerformSingleRangingMeasurement(data, &Measure);
+	dbg("Measure = %d\n", Measure.RangeMilliMeter);
+	return snprintf(buf, 4, "%d\n", Measure.RangeMilliMeter);
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(show_meter, 0660/*S_IWUGO | S_IRUGO*/,
+				   stmvl53l0x_show_meter,
+				   NULL);
+
+static ssize_t stmvl53l0x_show_xtalk(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct vl_data *data = dev_get_drvdata(dev);
+	struct VL_RangingMeasurementData_t Measure;
+
+	dbg("Measure = %d\n", Measure.RangeMilliMeter);
+	return snprintf(buf, 4, "%d\n", Measure.RangeMilliMeter);
+}
+
+static ssize_t stmvl53l0x_set_xtalk(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct vl_data *data = dev_get_drvdata(dev);
+	unsigned int targetDistance;
+
+	kstrtoint(buf, 10, &targetDistance);
+	data->xtalkCalDistance = targetDistance;
+	stmvl53l0x_start(data, 3, XTALKCALIB_MODE);
+	return count;
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(xtalk_cal, 0660/*S_IWUGO | S_IRUGO*/,
+				   stmvl53l0x_show_xtalk,
+				   stmvl53l0x_set_xtalk);
+
+static ssize_t stmvl53l0x_show_offset(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct vl_data *data = dev_get_drvdata(dev);
+	struct VL_RangingMeasurementData_t Measure;
+
+	papi_func_tbl->PerformSingleRangingMeasurement(data, &Measure);
+	dbg("Measure = %d\n", Measure.RangeMilliMeter);
+	return snprintf(buf, 4, "%d\n", Measure.RangeMilliMeter);
+}
+
+static ssize_t stmvl53l0x_set_offset(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct vl_data *data = dev_get_drvdata(dev);
+	unsigned int targetDistance;
+
+	kstrtoint(buf, 10, &targetDistance);
+	data->offsetCalDistance = targetDistance;
+	stmvl53l0x_start(data, 3, OFFSETCALIB_MODE);
+	return count;
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(offset_cal, 0660/*S_IWUGO | S_IRUGO*/,
+				   stmvl53l0x_show_offset,
+				   stmvl53l0x_set_offset);
+
+static struct attribute *stmvl53l0x_attributes[] = {
+	&dev_attr_enable_ps_sensor.attr,
+	&dev_attr_enable_debug.attr,
+	&dev_attr_set_delay_ms.attr,
+	&dev_attr_set_timing_budget.attr,
+	&dev_attr_set_long_range.attr,
+	&dev_attr_show_meter.attr,
+	&dev_attr_xtalk_cal.attr,
+	&dev_attr_offset_cal.attr,
+	NULL,
+};
+
+
+static const struct attribute_group stmvl53l0x_attr_group = {
+	.attrs = stmvl53l0x_attributes,
+};
+
+/*
+ * misc device file operation functions
+ */
+static int stmvl53l0x_ioctl_handler(struct file *file,
+			unsigned int cmd, unsigned long arg,
+			void __user *p)
+{
+	int rc = 0;
+	unsigned int xtalkint = 0;
+	unsigned int targetDistance = 0;
+	int8_t offsetint = 0;
+	struct vl_data *data =
+			container_of(file->private_data,
+				struct vl_data, miscdev);
+	struct stmvl53l0x_register reg;
+	struct stmvl53l0x_parameter parameter;
+	struct vl_data *vl53l0x_dev = data;
+	uint8_t deviceMode;
+	uint8_t page_num = 0;
+
+	if (!data)
+		return -EINVAL;
+
+	dbg("Enter enable_ps_sensor:%d\n", data->enable_ps_sensor);
+	switch (cmd) {
+	/* enable */
+	case VL_IOCTL_INIT:
+		dbg("VL_IOCTL_INIT\n");
+		/* turn on tof sensor only if it's not enabled by other */
+		/* client */
+		if (data->enable_ps_sensor == 0) {
+			/* to start */
+			stmvl53l0x_start(data, 3, NORMAL_MODE);
+		} else
+			rc = -EINVAL;
+		break;
+	/* crosstalk calibration */
+	case VL_IOCTL_XTALKCALB:
+		dbg("VL_IOCTL_XTALKCALB\n");
+		data->xtalkCalDistance = 100;
+		if (copy_from_user(&targetDistance, (unsigned int *)p,
+			sizeof(unsigned int))) {
+			err("%d, fail\n", __LINE__);
+			return -EFAULT;
+		}
+		data->xtalkCalDistance = targetDistance;
+
+		/* turn on tof sensor only if it's not enabled by other */
+		/* client */
+		if (data->enable_ps_sensor == 0) {
+			/* to start */
+			stmvl53l0x_start(data, 3, XTALKCALIB_MODE);
+		} else
+			rc = -EINVAL;
+		break;
+	/* set up Xtalk value */
+	case VL_IOCTL_SETXTALK:
+		dbg("VL_IOCTL_SETXTALK\n");
+		if (copy_from_user(&xtalkint, (unsigned int *)p,
+			sizeof(unsigned int))) {
+			err("%d, fail\n", __LINE__);
+			return -EFAULT;
+		}
+		dbg("SETXTALK as 0x%x\n", xtalkint);
+/* later
+ *	SetXTalkCompensationRate(vl53l0x_dev, xtalkint);
+ */
+		break;
+	/* offset calibration */
+	case VL_IOCTL_OFFCALB:
+		dbg("VL_IOCTL_OFFCALB\n");
+		data->offsetCalDistance = 50;
+		if (copy_from_user(&targetDistance, (unsigned int *)p,
+			sizeof(unsigned int))) {
+			err("%d, fail\n", __LINE__);
+			return -EFAULT;
+		}
+		data->offsetCalDistance = targetDistance;
+		if (data->enable_ps_sensor == 0) {
+			/* to start */
+			stmvl53l0x_start(data, 3, OFFSETCALIB_MODE);
+		} else
+			rc = -EINVAL;
+		break;
+	/* set up offset value */
+	case VL_IOCTL_SETOFFSET:
+		dbg("VL_IOCTL_SETOFFSET\n");
+		if (copy_from_user(&offsetint, (int8_t *)p, sizeof(int8_t))) {
+			err("%d, fail\n", __LINE__);
+			return -EFAULT;
+		}
+		dbg("SETOFFSET as %d\n", offsetint);
+	/* later SetOffsetCalibrationData(vl53l0x_dev, offsetint); */
+		break;
+	/* disable */
+	case VL_IOCTL_STOP:
+		dbg("VL_IOCTL_STOP\n");
+		/* turn off tof sensor only if it's enabled by other client */
+		if (data->enable_ps_sensor == 1) {
+			data->enable_ps_sensor = 0;
+			/* to stop */
+			stmvl53l0x_stop(data);
+		}
+		break;
+	/* Get all range data */
+	case VL_IOCTL_GETDATAS:
+		dbg("VL_IOCTL_GETDATAS\n");
+		if (copy_to_user((struct VL_RangingMeasurementData_t *)p,
+			&(data->rangeData),
+			sizeof(struct VL_RangingMeasurementData_t))) {
+			err("%d, fail\n", __LINE__);
+			return -EFAULT;
+		}
+		break;
+	/* Register tool */
+	case VL_IOCTL_REGISTER:
+		dbg("VL_IOCTL_REGISTER\n");
+		if (copy_from_user(&reg, (struct stmvl53l0x_register *)p,
+			sizeof(struct stmvl53l0x_register))) {
+			err("%d, fail\n", __LINE__);
+			return -EFAULT;
+		}
+		reg.status = 0;
+		page_num = (uint8_t)((reg.reg_index & 0x0000ff00) >> 8);
+		dbg(
+"VL_IOCTL_REGISTER,	page number:%d\n", page_num);
+		if (page_num != 0)
+			reg.status = VL_WrByte(vl53l0x_dev,
+				0xFF, page_num);
+
+		switch (reg.reg_bytes) {
+		case(4):
+			if (reg.is_read)
+				reg.status = VL_RdDWord(vl53l0x_dev,
+					(uint8_t)reg.reg_index,
+					&reg.reg_data);
+			else
+				reg.status = VL_WrDWord(vl53l0x_dev,
+					(uint8_t)reg.reg_index,
+					reg.reg_data);
+			break;
+		case(2):
+			if (reg.is_read)
+				reg.status = VL_RdWord(vl53l0x_dev,
+					(uint8_t)reg.reg_index,
+					(uint16_t *)&reg.reg_data);
+			else
+				reg.status = VL_WrWord(vl53l0x_dev,
+					(uint8_t)reg.reg_index,
+					(uint16_t)reg.reg_data);
+			break;
+		case(1):
+			if (reg.is_read)
+				reg.status = VL_RdByte(vl53l0x_dev,
+					(uint8_t)reg.reg_index,
+					(uint8_t *)&reg.reg_data);
+			else
+				reg.status = VL_WrByte(vl53l0x_dev,
+					(uint8_t)reg.reg_index,
+					(uint8_t)reg.reg_data);
+			break;
+		default:
+			reg.status = -1;
+
+		}
+		if (page_num != 0)
+			reg.status = VL_WrByte(vl53l0x_dev, 0xFF, 0);
+
+
+		if (copy_to_user((struct stmvl53l0x_register *)p, &reg,
+				sizeof(struct stmvl53l0x_register))) {
+			err("%d, fail\n", __LINE__);
+			return -EFAULT;
+		}
+		break;
+	/* parameter access */
+	case VL_IOCTL_PARAMETER:
+		dbg("VL_IOCTL_PARAMETER\n");
+		if (copy_from_user(&parameter, (struct stmvl53l0x_parameter *)p,
+				sizeof(struct stmvl53l0x_parameter))) {
+			err("%d, fail\n", __LINE__);
+			return -EFAULT;
+		}
+		parameter.status = 0;
+		if (data->enableDebug)
+			dbg("VL_IOCTL_PARAMETER Name = %d\n",
+				parameter.name);
+		switch (parameter.name) {
+		case (OFFSET_PAR):
+			if (parameter.is_read)
+				parameter.status =
+			papi_func_tbl->GetOffsetCalibrationDataMicroMeter(
+						vl53l0x_dev, &parameter.value);
+			else
+				parameter.status =
+			papi_func_tbl->SetOffsetCalibrationDataMicroMeter(
+				vl53l0x_dev, parameter.value);
+			dbg("get parameter value as %d\n",
+				parameter.value);
+			break;
+
+		case (REFERENCESPADS_PAR):
+			if (parameter.is_read) {
+				parameter.status =
+				papi_func_tbl->GetReferenceSpads(vl53l0x_dev,
+					(uint32_t *)&(parameter.value),
+					(uint8_t *)&(parameter.value2));
+				if (data->enableDebug)
+					dbg("Get RefSpad: Count:%u, Type:%u\n",
+				parameter.value, (uint8_t)parameter.value2);
+			} else {
+				if (data->enableDebug)
+					dbg("Set RefSpad: Count:%u, Type:%u\n",
+				parameter.value, (uint8_t)parameter.value2);
+
+				parameter.status =
+					papi_func_tbl->SetReferenceSpads(
+					vl53l0x_dev,
+					(uint32_t)(parameter.value),
+					(uint8_t)(parameter.value2));
+			}
+			break;
+
+		case (REFCALIBRATION_PAR):
+			if (parameter.is_read) {
+				parameter.status =
+				papi_func_tbl->GetRefCalibration(vl53l0x_dev,
+				(uint8_t *)&(parameter.value),
+				(uint8_t *)&(parameter.value2));
+				if (data->enableDebug)
+					dbg("Get Ref: Vhv:%u, PhaseCal:%u\n",
+					(uint8_t)parameter.value,
+					(uint8_t)parameter.value2);
+			} else {
+				if (data->enableDebug)
+					dbg("Set Ref: Vhv:%u, PhaseCal:%u\n",
+					(uint8_t)parameter.value,
+					(uint8_t)parameter.value2);
+				parameter.status =
+					papi_func_tbl->SetRefCalibration(
+					vl53l0x_dev, (uint8_t)(parameter.value),
+					(uint8_t)(parameter.value2));
+			}
+			break;
+		case (XTALKRATE_PAR):
+			if (parameter.is_read)
+				parameter.status =
+				papi_func_tbl->GetXTalkCompensationRateMegaCps(
+						vl53l0x_dev, (unsigned int *)
+						&parameter.value);
+			else
+				parameter.status =
+				papi_func_tbl->SetXTalkCompensationRateMegaCps(
+						vl53l0x_dev,
+						(unsigned int)
+							parameter.value);
+
+			break;
+		case (XTALKENABLE_PAR):
+			if (parameter.is_read)
+				parameter.status =
+				papi_func_tbl->GetXTalkCompensationEnable(
+						vl53l0x_dev,
+						(uint8_t *) &parameter.value);
+			else
+				parameter.status =
+				papi_func_tbl->SetXTalkCompensationEnable(
+						vl53l0x_dev,
+						(uint8_t) parameter.value);
+			break;
+		case (GPIOFUNC_PAR):
+			if (parameter.is_read) {
+				parameter.status =
+				papi_func_tbl->GetGpioConfig(vl53l0x_dev, 0,
+						&deviceMode,
+						&data->gpio_function,
+						&data->gpio_polarity);
+				parameter.value = data->gpio_function;
+			} else {
+				data->gpio_function = parameter.value;
+				parameter.status =
+				papi_func_tbl->SetGpioConfig(vl53l0x_dev, 0, 0,
+						data->gpio_function,
+						data->gpio_polarity);
+			}
+			break;
+		case (LOWTHRESH_PAR):
+			if (parameter.is_read) {
+				parameter.status =
+				papi_func_tbl->GetInterruptThresholds(
+				vl53l0x_dev, 0, &(data->low_threshold),
+				&(data->high_threshold));
+				parameter.value = data->low_threshold >> 16;
+			} else {
+				data->low_threshold = parameter.value << 16;
+				parameter.status =
+				papi_func_tbl->SetInterruptThresholds(
+				vl53l0x_dev, 0, data->low_threshold,
+				data->high_threshold);
+			}
+			break;
+		case (HIGHTHRESH_PAR):
+			if (parameter.is_read) {
+				parameter.status =
+				papi_func_tbl->GetInterruptThresholds(
+				vl53l0x_dev, 0, &(data->low_threshold),
+				&(data->high_threshold));
+				parameter.value = data->high_threshold >> 16;
+			} else {
+				data->high_threshold = parameter.value << 16;
+				parameter.status =
+				papi_func_tbl->SetInterruptThresholds(
+				vl53l0x_dev, 0, data->low_threshold,
+				data->high_threshold);
+			}
+			break;
+		case (DEVICEMODE_PAR):
+			if (parameter.is_read) {
+				parameter.status =
+					papi_func_tbl->GetDeviceMode(
+					vl53l0x_dev,
+					(uint8_t *)&
+					(parameter.value));
+			} else {
+				parameter.status =
+					papi_func_tbl->SetDeviceMode(
+					vl53l0x_dev,
+					(uint8_t)(parameter.value));
+					data->deviceMode =
+					(uint8_t)(parameter.value);
+			}
+			break;
+
+
+
+		case (INTERMEASUREMENT_PAR):
+			if (parameter.is_read) {
+				parameter.status =
+			papi_func_tbl->GetInterMeasurementPeriodMilliSeconds(
+				vl53l0x_dev, (uint32_t *)&(parameter.value));
+			} else {
+				parameter.status =
+			papi_func_tbl->SetInterMeasurementPeriodMilliSeconds(
+				vl53l0x_dev, (uint32_t)(parameter.value));
+				data->interMeasurems = parameter.value;
+			}
+			break;
+
+		}
+
+		if (copy_to_user((struct stmvl53l0x_parameter *)p, &parameter,
+				sizeof(struct stmvl53l0x_parameter))) {
+			err("%d, fail\n", __LINE__);
+			return -EFAULT;
+		}
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static int stmvl53l0x_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int stmvl53l0x_flush(struct file *file, fl_owner_t id)
+{
+	struct vl_data *data = container_of(file->private_data,
+					struct vl_data, miscdev);
+	(void) file;
+	(void) id;
+
+	if (data) {
+		if (data->enable_ps_sensor == 1) {
+			/* turn off tof sensor if it's enabled */
+			data->enable_ps_sensor = 0;
+			/* to stop */
+			stmvl53l0x_stop(data);
+		}
+	}
+	return 0;
+}
+
+static long stmvl53l0x_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	long ret;
+	struct vl_data *data =
+			container_of(file->private_data,
+					struct vl_data, miscdev);
+	mutex_lock(&data->work_mutex);
+	ret = stmvl53l0x_ioctl_handler(file, cmd, arg, (void __user *)arg);
+	mutex_unlock(&data->work_mutex);
+
+	return ret;
+}
+
+/*
+ * Initialization function
+ */
+static int stmvl53l0x_init_client(struct vl_data *data)
+{
+
+	int8_t Status = VL_ERROR_NONE;
+	struct VL_DeviceInfo_t DeviceInfo;
+	struct vl_data *vl53l0x_dev = data;
+
+	uint32_t refSpadCount;
+	uint8_t isApertureSpads;
+	uint8_t VhvSettings;
+	uint8_t PhaseCal;
+
+	dbg("Enter\n");
+
+	vl53l0x_dev->I2cDevAddr      = 0x52;
+	vl53l0x_dev->comms_type      =  1;
+	vl53l0x_dev->comms_speed_khz =  400;
+
+	/* Setup API functions based on revision */
+	stmvl53l0x_setupAPIFunctions();
+
+	if (Status == VL_ERROR_NONE && data->reset) {
+		dbg("Call of VL_DataInit\n");
+		/* Data initialization */
+		Status = papi_func_tbl->DataInit(vl53l0x_dev);
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		dbg("VL_GetDeviceInfo:\n");
+		Status = papi_func_tbl->GetDeviceInfo(vl53l0x_dev, &DeviceInfo);
+		if (Status == VL_ERROR_NONE) {
+			dbg("Device Name : %s\n", DeviceInfo.Name);
+			dbg("Device Type : %s\n", DeviceInfo.Type);
+			dbg("Device ID : %s\n", DeviceInfo.ProductId);
+			dbg("Product type: %d\n", DeviceInfo.ProductType);
+			dbg("ProductRevisionMajor : %d\n",
+				DeviceInfo.ProductRevisionMajor);
+			dbg("ProductRevisionMinor : %d\n",
+				DeviceInfo.ProductRevisionMinor);
+		}
+	}
+
+	if (Status == VL_ERROR_NONE) {
+		dbg("Call of VL_StaticInit\n");
+		Status = papi_func_tbl->StaticInit(vl53l0x_dev);
+		/* Device Initialization */
+	}
+
+	if (Status == VL_ERROR_NONE && data->reset) {
+		if (papi_func_tbl->PerformRefCalibration != NULL) {
+			dbg("Call of VL_PerformRefCalibration\n");
+			Status = papi_func_tbl->PerformRefCalibration(
+				vl53l0x_dev, &VhvSettings, &PhaseCal);
+				/* Ref calibration */
+		}
+	}
+
+	if (Status == VL_ERROR_NONE && data->reset) {
+		if (papi_func_tbl->PerformRefSpadManagement != NULL) {
+			dbg("Call of VL_PerformRefSpadManagement\n");
+			Status = papi_func_tbl->PerformRefSpadManagement(
+				vl53l0x_dev, &refSpadCount, &isApertureSpads);
+				/* Ref Spad Management */
+		}
+		data->reset = 0;
+		/* needed, even the function is NULL */
+	}
+
+	if (Status == VL_ERROR_NONE) {
+
+		dbg("Call of VL_SetDeviceMode\n");
+		Status = papi_func_tbl->SetDeviceMode(vl53l0x_dev,
+					VL_DEVICEMODE_SINGLE_RANGING);
+		/* Setup in	single ranging mode */
+	}
+	if (Status == VL_ERROR_NONE)
+		Status = papi_func_tbl->SetWrapAroundCheckEnable(
+			vl53l0x_dev, 1);
+
+	dbg("End\n");
+
+	return 0;
+}
+
+static int stmvl53l0x_start(struct vl_data *data, uint8_t scaling,
+	enum init_mode_e mode)
+{
+	int rc = 0;
+	struct vl_data *vl53l0x_dev = data;
+	int8_t Status = VL_ERROR_NONE;
+
+	dbg("Enter\n");
+
+	/* Power up */
+	rc = pmodule_func_tbl->power_up(data->client_object, &data->reset);
+	if (rc) {
+		err("%d,error rc %d\n", __LINE__, rc);
+		return rc;
+	}
+	/* init */
+	rc = stmvl53l0x_init_client(data);
+	if (rc) {
+		err("%d, error rc %d\n", __LINE__, rc);
+		pmodule_func_tbl->power_down(data->client_object);
+		return -EINVAL;
+	}
+
+	/* check mode */
+	if (mode != NORMAL_MODE)
+		papi_func_tbl->SetXTalkCompensationEnable(vl53l0x_dev, 1);
+
+	if (mode == OFFSETCALIB_MODE) {
+		/*VL_SetOffsetCalibrationDataMicroMeter(vl53l0x_dev, 0);*/
+		unsigned int OffsetMicroMeter;
+
+		papi_func_tbl->PerformOffsetCalibration(vl53l0x_dev,
+			(data->offsetCalDistance<<16),
+			&OffsetMicroMeter);
+		dbg("Offset calibration:%u\n", OffsetMicroMeter);
+		return rc;
+	} else if (mode == XTALKCALIB_MODE) {
+		unsigned int XTalkCompensationRateMegaCps;
+		/*caltarget distance : 100mm and convert to */
+		/* fixed point 16 16 format */
+		papi_func_tbl->PerformXTalkCalibration(vl53l0x_dev,
+			(data->xtalkCalDistance<<16),
+			&XTalkCompensationRateMegaCps);
+		dbg("Xtalk calibration:%u\n", XTalkCompensationRateMegaCps);
+		return rc;
+	}
+	/* set up device parameters */
+	data->gpio_polarity = VL_INTERRUPTPOLARITY_LOW;
+
+	/* Following two calls are made from IOCTL as well */
+	papi_func_tbl->SetGpioConfig(vl53l0x_dev, 0, 0,
+		data->gpio_function,
+		VL_INTERRUPTPOLARITY_LOW);
+
+	papi_func_tbl->SetInterruptThresholds(vl53l0x_dev, 0,
+		data->low_threshold, data->high_threshold);
+
+	if (data->deviceMode == VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING) {
+		papi_func_tbl->SetInterMeasurementPeriodMilliSeconds(
+			vl53l0x_dev, data->interMeasurems);
+	}
+
+	dbg("DeviceMode:0x%x, interMeasurems:%d==\n", data->deviceMode,
+			data->interMeasurems);
+	papi_func_tbl->SetDeviceMode(vl53l0x_dev,
+			data->deviceMode);
+	papi_func_tbl->ClearInterruptMask(vl53l0x_dev,
+							0);
+
+	if (vl53l0x_dev->useLongRange) {
+		dbg("Configure Long Ranging\n");
+		Status = papi_func_tbl->SetLimitCheckValue(vl53l0x_dev,
+			VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+			(unsigned int)(65536/10)); /* 0.1 * 65536 */
+		if (Status == VL_ERROR_NONE) {
+			Status = papi_func_tbl->SetLimitCheckValue(vl53l0x_dev,
+				VL_CHECKENABLE_SIGMA_FINAL_RANGE,
+				(unsigned int)(60*65536));
+		} else {
+			dbg("SIGNAL_RATE_FINAL_RANGE failed err = %d\n",
+				Status);
+		}
+
+		if (Status == VL_ERROR_NONE) {
+			dbg("Set Timing Budget = %u\n",
+				vl53l0x_dev->timingBudget);
+			Status =
+			papi_func_tbl->SetMeasurementTimingBudgetMicroSeconds(
+				vl53l0x_dev, vl53l0x_dev->timingBudget);
+		} else {
+			dbg("SetLimitCheckValue failed err =%d\n",
+				Status);
+		}
+
+		if (Status == VL_ERROR_NONE) {
+			Status = papi_func_tbl->SetVcselPulsePeriod(vl53l0x_dev,
+				VL_VCSEL_PERIOD_PRE_RANGE, 18);
+		} else {
+			dbg("SetMeasurementTimingBudget failed err = %d\n",
+				Status);
+		}
+
+		if (Status == VL_ERROR_NONE) {
+			Status = papi_func_tbl->SetVcselPulsePeriod(vl53l0x_dev,
+				VL_VCSEL_PERIOD_FINAL_RANGE, 14);
+		} else {
+			dbg("SetVcselPulsePeriod(PRE, 18) failed err = %d\n",
+				Status);
+		}
+
+		if (Status != VL_ERROR_NONE) {
+			dbg("SetVcselPulsePeriod(FINAL, 14) failed err = %d\n",
+				Status);
+		}
+	} else {
+		dbg("Configure High Accuracy\n");
+		Status = papi_func_tbl->SetLimitCheckValue(vl53l0x_dev,
+			VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+			(unsigned int)(25 * 65536 / 100)); /* 0.25 * 65536 */
+		if (Status == VL_ERROR_NONE) {
+			Status = papi_func_tbl->SetLimitCheckValue(vl53l0x_dev,
+				VL_CHECKENABLE_SIGMA_FINAL_RANGE,
+				(unsigned int)(18*65536));
+		} else {
+			dbg("SIGNAL_RATE_FINAL_RANGE failed err = %d\n",
+				Status);
+		}
+
+		if (Status == VL_ERROR_NONE) {
+			dbg("Set Timing Budget = %u\n",
+				vl53l0x_dev->timingBudget);
+			Status =
+			papi_func_tbl->SetMeasurementTimingBudgetMicroSeconds(
+				vl53l0x_dev, vl53l0x_dev->timingBudget);
+		} else {
+			dbg("SetLimitCheckValue failed err = %d\n",
+				Status);
+		}
+
+		if (Status == VL_ERROR_NONE) {
+			Status = papi_func_tbl->SetVcselPulsePeriod(vl53l0x_dev,
+				VL_VCSEL_PERIOD_PRE_RANGE, 14);
+		} else {
+			dbg("SetMeasurementTimingBudget failed err = %d\n",
+				Status);
+		}
+
+		if (Status == VL_ERROR_NONE) {
+			Status = papi_func_tbl->SetVcselPulsePeriod(vl53l0x_dev,
+				VL_VCSEL_PERIOD_FINAL_RANGE, 10);
+		} else {
+			dbg("SetVcselPulsePeriod failed err = %d\n",
+				Status);
+		}
+
+		if (Status != VL_ERROR_NONE) {
+			dbg("SetVcselPulsePeriod failed err = %d\n",
+				Status);
+		}
+
+	}
+
+	/* start the ranging */
+	papi_func_tbl->StartMeasurement(vl53l0x_dev);
+	data->enable_ps_sensor = 1;
+
+
+	dbg("End\n");
+
+	return rc;
+}
+
+static int stmvl53l0x_stop(struct vl_data *data)
+{
+	int rc = 0;
+	struct vl_data *vl53l0x_dev = data;
+
+	dbg("Enter\n");
+
+	/* stop - if continuous mode */
+	if (data->deviceMode == VL_DEVICEMODE_CONTINUOUS_RANGING ||
+		data->deviceMode == VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING)
+		papi_func_tbl->StopMeasurement(vl53l0x_dev);
+
+	/* clean interrupt */
+	papi_func_tbl->ClearInterruptMask(vl53l0x_dev, 0);
+
+	/* cancel work handler */
+	stmvl53l0x_cancel_handler(data);
+	/* power down */
+	rc = pmodule_func_tbl->power_down(data->client_object);
+	if (rc) {
+		err("%d, error rc %d\n", __LINE__, rc);
+		return rc;
+	}
+	dbg("End\n");
+
+	return rc;
+}
+
+/*
+ * I2C init/probing/exit functions
+ */
+static const struct file_operations stmvl53l0x_ranging_fops = {
+	.owner =			THIS_MODULE,
+	.unlocked_ioctl =	stmvl53l0x_ioctl,
+	.open =				stmvl53l0x_open,
+	.flush =			stmvl53l0x_flush,
+};
+
+int stmvl53l0x_setup(struct vl_data *data)
+{
+	int rc = 0;
+
+	dbg("Enter\n");
+
+	/* init mutex */
+	mutex_init(&data->update_lock);
+	mutex_init(&data->work_mutex);
+
+	init_waitqueue_head(&data->poll_thread_wq);
+
+	data->poll_thread = kthread_run(&stmvl53l0x_poll_thread,
+				(void *)data, "STM-VL53L0");
+	if (data->poll_thread == NULL) {
+		dbg("%s(%d) - Failed to create Polling thread\n",
+			__func__, __LINE__);
+		goto exit_free_irq;
+	}
+
+	/* init work handler */
+	INIT_DELAYED_WORK(&data->dwork, stmvl53l0x_work_handler);
+
+	/* Register to Input Device */
+	data->input_dev_ps = input_allocate_device();
+	if (!data->input_dev_ps) {
+		rc = -ENOMEM;
+		err("%d error:%d\n", __LINE__, rc);
+
+		goto exit_free_irq;
+	}
+	set_bit(EV_ABS, data->input_dev_ps->evbit);
+	/* range in cm*/
+	input_set_abs_params(data->input_dev_ps, ABS_DISTANCE, 0, 76, 0, 0);
+	/* tv_sec */
+	input_set_abs_params(data->input_dev_ps, ABS_HAT0X, 0, 0xffffffff,
+		0, 0);
+	/* tv_usec */
+	input_set_abs_params(data->input_dev_ps, ABS_HAT0Y, 0, 0xffffffff,
+		0, 0);
+	/* range in_mm */
+	input_set_abs_params(data->input_dev_ps, ABS_HAT1X, 0, 765, 0, 0);
+	/* error code change maximum to 0xff for more flexibility */
+	input_set_abs_params(data->input_dev_ps, ABS_HAT1Y, 0, 0xff, 0, 0);
+	/* rtnRate */
+	input_set_abs_params(data->input_dev_ps, ABS_HAT2X, 0, 0xffffffff,
+		0, 0);
+	/* rtn_amb_rate */
+	input_set_abs_params(data->input_dev_ps, ABS_HAT2Y, 0, 0xffffffff,
+		0, 0);
+	/* rtn_conv_time */
+	input_set_abs_params(data->input_dev_ps, ABS_HAT3X, 0, 0xffffffff,
+		0, 0);
+	/* dmax */
+	input_set_abs_params(data->input_dev_ps, ABS_HAT3Y, 0, 0xffffffff,
+		0, 0);
+
+	input_set_abs_params(data->input_dev_ps, ABS_PRESSURE, 0, 0xffffffff,
+		0, 0);
+
+	input_set_abs_params(data->input_dev_ps, ABS_WHEEL, 0, 0xffffffff,
+		0, 0);
+
+	data->input_dev_ps->name = "STM VL53L0 proximity sensor";
+
+	rc = input_register_device(data->input_dev_ps);
+	if (rc) {
+		rc = -ENOMEM;
+		err("%d error:%d\n", __LINE__, rc);
+		goto exit_free_dev_ps;
+	}
+	/* setup drv data */
+	input_set_drvdata(data->input_dev_ps, data);
+
+	/* Register sysfs hooks */
+	data->range_kobj = kobject_create_and_add("range", kernel_kobj);
+	if (!data->range_kobj) {
+		rc = -ENOMEM;
+		err("%d error:%d\n", __LINE__, rc);
+		goto exit_unregister_dev_ps;
+	}
+	rc = sysfs_create_group(&data->input_dev_ps->dev.kobj,
+			&stmvl53l0x_attr_group);
+	if (rc) {
+		rc = -ENOMEM;
+		err("%d error:%d\n", __LINE__, rc);
+		goto exit_unregister_dev_ps_1;
+	}
+	/* init default device parameter value */
+	data->enable_ps_sensor = 0;
+	data->reset = 1;
+	data->delay_ms = 30;	/* delay time to 30ms */
+	data->enableDebug = 0;
+	data->gpio_polarity = VL_INTERRUPTPOLARITY_LOW;
+	data->gpio_function = VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY;
+	data->low_threshold = 60;
+	data->high_threshold = 200;
+	data->deviceMode = VL_DEVICEMODE_SINGLE_RANGING;
+	data->interMeasurems = 30;
+	data->timingBudget = 26000;
+	data->useLongRange = 1;
+
+	dbg("support ver. %s enabled\n", DRIVER_VERSION);
+	dbg("End");
+
+	return 0;
+exit_unregister_dev_ps_1:
+	kobject_put(data->range_kobj);
+exit_unregister_dev_ps:
+	input_unregister_device(data->input_dev_ps);
+exit_free_dev_ps:
+	input_free_device(data->input_dev_ps);
+exit_free_irq:
+	kfree(data);
+	return rc;
+}
+
+static int __init stmvl53l0x_init(void)
+{
+	int ret = -1;
+
+	dbg("Enter\n");
+
+	/* assign function table */
+	pmodule_func_tbl = &stmvl53l0x_module_func_tbl;
+	papi_func_tbl = &stmvl53l0x_api_func_tbl;
+
+	/* client specific init function */
+	ret = pmodule_func_tbl->init();
+
+	if (ret)
+		err("%d failed with %d\n", __LINE__, ret);
+
+	dbg("End\n");
+
+	return ret;
+}
+
+static void __exit stmvl53l0x_exit(void)
+{
+	dbg("Enter\n");
+
+	dbg("End\n");
+}
+
+MODULE_DESCRIPTION("ST FlightSense Time-of-Flight sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(stmvl53l0x_init);
+module_exit(stmvl53l0x_exit);
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index af83d2e..a8a96def 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -2538,13 +2538,31 @@
 }
 
 static int alps_update_dual_info_ss4_v2(unsigned char otp[][4],
-				       struct alps_data *priv)
+					struct alps_data *priv,
+					struct psmouse *psmouse)
 {
 	bool is_dual = false;
+	int reg_val = 0;
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
 
-	if (IS_SS4PLUS_DEV(priv->dev_id))
+	if (IS_SS4PLUS_DEV(priv->dev_id)) {
 		is_dual = (otp[0][0] >> 4) & 0x01;
 
+		if (!is_dual) {
+			/* For support TrackStick of Thinkpad L/E series */
+			if (alps_exit_command_mode(psmouse) == 0 &&
+				alps_enter_command_mode(psmouse) == 0) {
+				reg_val = alps_command_mode_read_reg(psmouse,
+									0xD7);
+			}
+			alps_exit_command_mode(psmouse);
+			ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
+
+			if (reg_val == 0x0C || reg_val == 0x1D)
+				is_dual = true;
+		}
+	}
+
 	if (is_dual)
 		priv->flags |= ALPS_DUALPOINT |
 					ALPS_DUALPOINT_WITH_PRESSURE;
@@ -2567,7 +2585,7 @@
 
 	alps_update_btn_info_ss4_v2(otp, priv);
 
-	alps_update_dual_info_ss4_v2(otp, priv);
+	alps_update_dual_info_ss4_v2(otp, priv, psmouse);
 
 	return 0;
 }
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index c9d491b..3851d57 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -1082,6 +1082,13 @@
 		return error;
 	}
 
+	/* Make sure there is something at this address */
+	error = i2c_smbus_read_byte(client);
+	if (error < 0) {
+		dev_dbg(&client->dev, "nothing at this address: %d\n", error);
+		return -ENXIO;
+	}
+
 	/* Initialize the touchpad. */
 	error = elan_initialize(data);
 	if (error)
diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c
index a679e56..765879d 100644
--- a/drivers/input/mouse/elan_i2c_i2c.c
+++ b/drivers/input/mouse/elan_i2c_i2c.c
@@ -557,7 +557,14 @@
 	long ret;
 	int error;
 	int len;
-	u8 buffer[ETP_I2C_INF_LENGTH];
+	u8 buffer[ETP_I2C_REPORT_LEN];
+
+	len = i2c_master_recv(client, buffer, ETP_I2C_REPORT_LEN);
+	if (len != ETP_I2C_REPORT_LEN) {
+		error = len < 0 ? len : -EIO;
+		dev_warn(dev, "failed to read I2C data after FW WDT reset: %d (%d)\n",
+			error, len);
+	}
 
 	reinit_completion(completion);
 	enable_irq(client->irq);
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 59603a5..c519c0b 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1711,6 +1711,17 @@
 			     etd->samples[0], etd->samples[1], etd->samples[2]);
 	}
 
+	if (etd->samples[1] == 0x74 && etd->hw_version == 0x03) {
+		/*
+		 * This module has a bug which makes absolute mode
+		 * unusable, so let's abort so we'll be using standard
+		 * PS/2 protocol.
+		 */
+		psmouse_info(psmouse,
+			     "absolute mode broken, forcing standard PS/2 protocol\n");
+		goto init_fail;
+	}
+
 	if (elantech_set_absolute_mode(psmouse)) {
 		psmouse_err(psmouse,
 			    "failed to put touchpad into absolute mode.\n");
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index b604564..30328e5 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -15,6 +15,7 @@
 #define MOUSEDEV_MINORS		31
 #define MOUSEDEV_MIX		63
 
+#include <linux/bitops.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/poll.h>
@@ -103,7 +104,7 @@
 	spinlock_t packet_lock;
 	int pos_x, pos_y;
 
-	signed char ps2[6];
+	u8 ps2[6];
 	unsigned char ready, buffer, bufsiz;
 	unsigned char imexseq, impsseq;
 	enum mousedev_emul mode;
@@ -291,11 +292,10 @@
 		}
 
 		client->pos_x += packet->dx;
-		client->pos_x = client->pos_x < 0 ?
-			0 : (client->pos_x >= xres ? xres : client->pos_x);
+		client->pos_x = clamp_val(client->pos_x, 0, xres);
+
 		client->pos_y += packet->dy;
-		client->pos_y = client->pos_y < 0 ?
-			0 : (client->pos_y >= yres ? yres : client->pos_y);
+		client->pos_y = clamp_val(client->pos_y, 0, yres);
 
 		p->dx += packet->dx;
 		p->dy += packet->dy;
@@ -571,44 +571,50 @@
 	return error;
 }
 
-static inline int mousedev_limit_delta(int delta, int limit)
-{
-	return delta > limit ? limit : (delta < -limit ? -limit : delta);
-}
-
-static void mousedev_packet(struct mousedev_client *client,
-			    signed char *ps2_data)
+static void mousedev_packet(struct mousedev_client *client, u8 *ps2_data)
 {
 	struct mousedev_motion *p = &client->packets[client->tail];
+	s8 dx, dy, dz;
 
-	ps2_data[0] = 0x08 |
-		((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
-	ps2_data[1] = mousedev_limit_delta(p->dx, 127);
-	ps2_data[2] = mousedev_limit_delta(p->dy, 127);
-	p->dx -= ps2_data[1];
-	p->dy -= ps2_data[2];
+	dx = clamp_val(p->dx, -127, 127);
+	p->dx -= dx;
+
+	dy = clamp_val(p->dy, -127, 127);
+	p->dy -= dy;
+
+	ps2_data[0] = BIT(3);
+	ps2_data[0] |= ((dx & BIT(7)) >> 3) | ((dy & BIT(7)) >> 2);
+	ps2_data[0] |= p->buttons & 0x07;
+	ps2_data[1] = dx;
+	ps2_data[2] = dy;
 
 	switch (client->mode) {
 	case MOUSEDEV_EMUL_EXPS:
-		ps2_data[3] = mousedev_limit_delta(p->dz, 7);
-		p->dz -= ps2_data[3];
-		ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
+		dz = clamp_val(p->dz, -7, 7);
+		p->dz -= dz;
+
+		ps2_data[3] = (dz & 0x0f) | ((p->buttons & 0x18) << 1);
 		client->bufsiz = 4;
 		break;
 
 	case MOUSEDEV_EMUL_IMPS:
-		ps2_data[0] |=
-			((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
-		ps2_data[3] = mousedev_limit_delta(p->dz, 127);
-		p->dz -= ps2_data[3];
+		dz = clamp_val(p->dz, -127, 127);
+		p->dz -= dz;
+
+		ps2_data[0] |= ((p->buttons & 0x10) >> 3) |
+			       ((p->buttons & 0x08) >> 1);
+		ps2_data[3] = dz;
+
 		client->bufsiz = 4;
 		break;
 
 	case MOUSEDEV_EMUL_PS2:
 	default:
-		ps2_data[0] |=
-			((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
 		p->dz = 0;
+
+		ps2_data[0] |= ((p->buttons & 0x10) >> 3) |
+			       ((p->buttons & 0x08) >> 1);
+
 		client->bufsiz = 3;
 		break;
 	}
@@ -714,7 +720,7 @@
 {
 	struct mousedev_client *client = file->private_data;
 	struct mousedev *mousedev = client->mousedev;
-	signed char data[sizeof(client->ps2)];
+	u8 data[sizeof(client->ps2)];
 	int retval = 0;
 
 	if (!client->ready && !client->buffer && mousedev->exist &&
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index d1051e3..e484ea2 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -530,6 +530,20 @@
 	{ }
 };
 
+static const struct dmi_system_id i8042_dmi_forcemux_table[] __initconst = {
+	{
+		/*
+		 * Sony Vaio VGN-CS series require MUX or the touch sensor
+		 * buttons will disturb touchpad operation
+		 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "VGN-CS"),
+		},
+	},
+	{ }
+};
+
 /*
  * On some Asus laptops, just running self tests cause problems.
  */
@@ -693,6 +707,13 @@
 		},
 	},
 	{
+		/* Lenovo ThinkPad L460 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L460"),
+		},
+	},
+	{
 		/* Clevo P650RS, 650RP6, Sager NP8152-S, and others */
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
@@ -1223,6 +1244,9 @@
 	if (dmi_check_system(i8042_dmi_nomux_table))
 		i8042_nomux = true;
 
+	if (dmi_check_system(i8042_dmi_forcemux_table))
+		i8042_nomux = false;
+
 	if (dmi_check_system(i8042_dmi_notimeout_table))
 		i8042_notimeout = true;
 
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 25791c2..6c4156a 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1279,4 +1279,16 @@
 
 	  If unsure, say N.
 
+config TOUCHSCREEN_HIMAX_CHIPSET
+	bool "Himax touchpanel CHIPSET"
+	depends on I2C
+	help
+	  Say Y here if you have a Himax CHIPSET touchscreen.
+	  HIMAX controllers are multi touch controllers which can
+	  report 10 touches at a time.
+
+	  If unsure, say N.
+
+source "drivers/input/touchscreen/hxchipset/Kconfig"
+
 endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 34e8823..a5952ca 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -104,3 +104,4 @@
 obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50)	+= colibri-vf50-ts.o
 obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023)	+= rohm_bu21023.o
 obj-$(CONFIG_TOUCHSCREEN_FTS)		+= focaltech_touch/
+obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET)	+= hxchipset/
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index 240b16f..5907fdd 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -778,8 +778,10 @@
 	int error;
 
 	/* We need gpio pins to suspend/resume */
-	if (!ts->gpiod_int || !ts->gpiod_rst)
+	if (!ts->gpiod_int || !ts->gpiod_rst) {
+		disable_irq(client->irq);
 		return 0;
+	}
 
 	wait_for_completion(&ts->firmware_loading_complete);
 
@@ -819,8 +821,10 @@
 	struct goodix_ts_data *ts = i2c_get_clientdata(client);
 	int error;
 
-	if (!ts->gpiod_int || !ts->gpiod_rst)
+	if (!ts->gpiod_int || !ts->gpiod_rst) {
+		enable_irq(client->irq);
 		return 0;
+	}
 
 	/*
 	 * Exit sleep mode by outputting HIGH level to INT pin
diff --git a/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i b/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i
diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_124.i b/drivers/input/touchscreen/hxchipset/HX_CRC_124.i
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/HX_CRC_124.i
diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_128.i b/drivers/input/touchscreen/hxchipset/HX_CRC_128.i
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/HX_CRC_128.i
diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_60.i b/drivers/input/touchscreen/hxchipset/HX_CRC_60.i
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/HX_CRC_60.i
diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_64.i b/drivers/input/touchscreen/hxchipset/HX_CRC_64.i
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/HX_CRC_64.i
diff --git a/drivers/input/touchscreen/hxchipset/Kconfig b/drivers/input/touchscreen/hxchipset/Kconfig
new file mode 100644
index 0000000..ebf3aa4
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/Kconfig
@@ -0,0 +1,21 @@
+#
+# Himax Touchscreen driver configuration
+#
+
+config TOUCHSCREEN_HIMAX_I2C
+        tristate "HIMAX chipset i2c touchscreen"
+		depends on TOUCHSCREEN_HIMAX_CHIPSET
+		help
+		This enables support for HIMAX CHIPSET over I2C based touchscreens.
+
+config TOUCHSCREEN_HIMAX_DEBUG
+        tristate "HIMAX debug function"
+		depends on TOUCHSCREEN_HIMAX_I2C
+		help
+		This enables support for HIMAX debug function.
+
+config HMX_DB
+	tristate "HIMAX driver test over Dragon Board"
+	depends on TOUCHSCREEN_HIMAX_I2C
+	help
+	  This enables support for HIMAX driver test over Dragon Board.
diff --git a/drivers/input/touchscreen/hxchipset/Makefile b/drivers/input/touchscreen/hxchipset/Makefile
new file mode 100644
index 0000000..509d491
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/Makefile
@@ -0,0 +1,3 @@
+# Makefile for the Himax touchscreen drivers.
+
+obj-$(CONFIG_TOUCHSCREEN_HIMAX_I2C)   	+= himax_platform.o himax_ic.o himax_common.o himax_debug.o
diff --git a/drivers/input/touchscreen/hxchipset/himax_common.c b/drivers/input/touchscreen/hxchipset/himax_common.c
new file mode 100644
index 0000000..417b0c0
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/himax_common.c
@@ -0,0 +1,1936 @@
+/* Himax Android Driver Sample Code for Himax chipset
+*
+* Copyright (C) 2015 Himax Corporation.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+*/
+
+#include "himax_common.h"
+#include "himax_ic.h"
+
+#define SUPPORT_FINGER_DATA_CHECKSUM 0x0F
+#define TS_WAKE_LOCK_TIMEOUT		(2 * HZ)
+#define FRAME_COUNT 5
+
+#if defined(HX_AUTO_UPDATE_FW)
+	static unsigned char i_CTPM_FW[]=
+	{
+		#include "HX83100_Amber_0901_030B.i"
+	};
+#endif
+
+#ifdef HX_ESD_WORKAROUND
+	extern void HX_report_ESD_event(void);
+	unsigned char ESD_00_counter = 0;
+	unsigned char ESD_00_Flag = 0;
+#endif
+
+//static int		tpd_keys_local[HX_KEY_MAX_COUNT] = HX_KEY_ARRAY; // for Virtual key array
+
+struct himax_ts_data *private_ts;
+struct himax_ic_data* ic_data;
+
+static int		HX_TOUCH_INFO_POINT_CNT;
+
+#ifdef HX_AUTO_UPDATE_FW
+extern unsigned long	FW_VER_MAJ_FLASH_ADDR;
+extern unsigned long 	FW_VER_MIN_FLASH_ADDR;
+extern unsigned long 	CFG_VER_MAJ_FLASH_ADDR;
+extern unsigned long 	CFG_VER_MIN_FLASH_ADDR;
+#endif
+extern unsigned long 	FW_VER_MAJ_FLASH_LENG;
+extern unsigned long 	FW_VER_MIN_FLASH_LENG;
+extern unsigned long 	CFG_VER_MAJ_FLASH_LENG;
+extern unsigned long 	CFG_VER_MIN_FLASH_LENG;
+extern unsigned char	IC_TYPE;
+extern unsigned char	IC_CHECKSUM;
+
+#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG)
+extern int himax_touch_proc_init(void);
+extern void himax_touch_proc_deinit(void);
+//PROC-START
+#ifdef HX_TP_PROC_FLASH_DUMP
+extern void	himax_ts_flash_func(void);
+extern void setFlashBuffer(void);
+extern bool getFlashDumpGoing(void);
+extern uint8_t getSysOperation(void);
+extern void setSysOperation(uint8_t operation);
+#endif
+
+#ifdef HX_TP_PROC_HITOUCH
+extern bool hitouch_is_connect;
+#endif
+
+#ifdef HX_TP_PROC_DIAG
+	extern int touch_monitor_stop_flag;
+	extern int touch_monitor_stop_limit;
+	extern void	himax_ts_diag_func(void);
+	extern int16_t *getMutualBuffer(void);
+	extern int16_t *getMutualNewBuffer(void);
+	extern int16_t *getMutualOldBuffer(void);
+	extern int16_t *getSelfBuffer(void);
+	extern uint8_t getXChannel(void);
+	extern uint8_t getYChannel(void);
+	extern uint8_t getDiagCommand(void);
+	extern void setXChannel(uint8_t x);
+	extern void setYChannel(uint8_t y);
+	extern void setMutualBuffer(void);
+	extern void setMutualNewBuffer(void);
+	extern void setMutualOldBuffer(void);
+	extern uint8_t	coordinate_dump_enable;
+	extern struct file	*coordinate_fn;
+	extern uint8_t diag_coor[128];
+#ifdef HX_TP_PROC_2T2R
+	extern int16_t *getMutualBuffer_2(void);
+	extern uint8_t getXChannel_2(void);
+	extern uint8_t getYChannel_2(void);
+	extern void setXChannel_2(uint8_t x);
+	extern void setYChannel_2(uint8_t y);
+	extern void setMutualBuffer_2(void);
+#endif
+#endif
+//PROC-END
+#endif
+
+extern int himax_parse_dt(struct himax_ts_data *ts,
+				struct himax_i2c_platform_data *pdata);
+extern int himax_ts_pinctrl_init(struct himax_ts_data *ts);
+
+static uint8_t 	vk_press;
+static uint8_t 	AA_press;
+static uint8_t 	EN_NoiseFilter;
+static uint8_t	Last_EN_NoiseFilter;
+static int	hx_point_num;																	// for himax_ts_work_func use
+static int	p_point_num	= 0xFFFF;
+static int	tpd_key;
+static int	tpd_key_old;
+static int	probe_fail_flag;
+static bool	config_load;
+static struct himax_config *config_selected;
+
+//static int iref_number = 11;
+//static bool iref_found = false;    
+
+#ifdef HX_USB_DETECT2
+extern bool USB_Flag;
+#endif
+
+#if defined(CONFIG_FB)
+int fb_notifier_callback(struct notifier_block *self,
+				 unsigned long event, void *data);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+static void himax_ts_early_suspend(struct early_suspend *h);
+static void himax_ts_late_resume(struct early_suspend *h);
+#endif
+
+int himax_input_register(struct himax_ts_data *ts)
+{
+	int ret;
+	ts->input_dev = input_allocate_device();
+	if (ts->input_dev == NULL) {
+		ret = -ENOMEM;
+		E("%s: Failed to allocate input device\n", __func__);
+		return ret;
+	}
+	ts->input_dev->name = "himax-touchscreen";
+
+	set_bit(EV_SYN, ts->input_dev->evbit);
+	set_bit(EV_ABS, ts->input_dev->evbit);
+	set_bit(EV_KEY, ts->input_dev->evbit);
+
+	set_bit(KEY_BACK, ts->input_dev->keybit);
+	set_bit(KEY_HOME, ts->input_dev->keybit);
+	set_bit(KEY_MENU, ts->input_dev->keybit);
+	set_bit(KEY_SEARCH, ts->input_dev->keybit);
+#if defined(HX_SMART_WAKEUP)
+	set_bit(KEY_POWER, ts->input_dev->keybit);
+	set_bit(KEY_CUST_01, ts->input_dev->keybit);
+	set_bit(KEY_CUST_02, ts->input_dev->keybit);
+	set_bit(KEY_CUST_03, ts->input_dev->keybit);
+	set_bit(KEY_CUST_04, ts->input_dev->keybit);
+	set_bit(KEY_CUST_05, ts->input_dev->keybit);
+	set_bit(KEY_CUST_06, ts->input_dev->keybit);
+	set_bit(KEY_CUST_07, ts->input_dev->keybit);
+	set_bit(KEY_CUST_08, ts->input_dev->keybit);
+	set_bit(KEY_CUST_09, ts->input_dev->keybit);
+	set_bit(KEY_CUST_10, ts->input_dev->keybit);
+	set_bit(KEY_CUST_11, ts->input_dev->keybit);
+	set_bit(KEY_CUST_12, ts->input_dev->keybit);
+	set_bit(KEY_CUST_13, ts->input_dev->keybit);
+	set_bit(KEY_CUST_14, ts->input_dev->keybit);
+	set_bit(KEY_CUST_15, ts->input_dev->keybit);
+#endif
+	set_bit(BTN_TOUCH, ts->input_dev->keybit);
+
+	set_bit(KEY_F10, ts->input_dev->keybit);
+
+	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+
+	if (ts->protocol_type == PROTOCOL_TYPE_A) {
+		//ts->input_dev->mtsize = ts->nFinger_support;
+		input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID,
+		0, 3, 0, 0);
+	} else {/* PROTOCOL_TYPE_B */
+		set_bit(MT_TOOL_FINGER, ts->input_dev->keybit);
+		input_mt_init_slots(ts->input_dev, ts->nFinger_support,0);
+	}
+
+	I("input_set_abs_params: mix_x %d, max_x %d, min_y %d, max_y %d\n",
+		ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max);
+
+	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_x_fuzz, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,ts->pdata->abs_y_min, ts->pdata->abs_y_max, ts->pdata->abs_y_fuzz, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE,ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR,ts->pdata->abs_width_min, ts->pdata->abs_width_max, ts->pdata->abs_pressure_fuzz, 0);
+
+//	input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE, 0, ((ts->pdata->abs_pressure_max << 16) | ts->pdata->abs_width_max), 0, 0);
+//	input_set_abs_params(ts->input_dev, ABS_MT_POSITION, 0, (BIT(31) | (ts->pdata->abs_x_max << 16) | ts->pdata->abs_y_max), 0, 0);
+
+	return input_register_device(ts->input_dev);
+}
+
+static void calcDataSize(uint8_t finger_num)
+{
+	struct himax_ts_data *ts_data = private_ts;
+	ts_data->coord_data_size = 4 * finger_num;
+	ts_data->area_data_size = ((finger_num / 4) + (finger_num % 4 ? 1 : 0)) * 4;
+	ts_data->raw_data_frame_size = 128 - ts_data->coord_data_size - ts_data->area_data_size - 4 - 4 - 1;
+	ts_data->raw_data_nframes  = ((uint32_t)ts_data->x_channel * ts_data->y_channel +
+																					ts_data->x_channel + ts_data->y_channel) / ts_data->raw_data_frame_size +
+															(((uint32_t)ts_data->x_channel * ts_data->y_channel +
+		  																		ts_data->x_channel + ts_data->y_channel) % ts_data->raw_data_frame_size)? 1 : 0;
+	I("%s: coord_data_size: %d, area_data_size:%d, raw_data_frame_size:%d, raw_data_nframes:%d", __func__, ts_data->coord_data_size, ts_data->area_data_size, ts_data->raw_data_frame_size, ts_data->raw_data_nframes);
+}
+
+static void calculate_point_number(void)
+{
+	HX_TOUCH_INFO_POINT_CNT = ic_data->HX_MAX_PT * 4 ;
+
+	if ( (ic_data->HX_MAX_PT % 4) == 0)
+		HX_TOUCH_INFO_POINT_CNT += (ic_data->HX_MAX_PT / 4) * 4 ;
+	else
+		HX_TOUCH_INFO_POINT_CNT += ((ic_data->HX_MAX_PT / 4) +1) * 4 ;
+}
+
+#if 0
+static int himax_read_Sensor_ID(struct i2c_client *client)
+{	
+	uint8_t val_high[1], val_low[1], ID0=0, ID1=0;
+	char data[3];
+	const int normalRetry = 10;
+	int sensor_id;
+	
+	data[0] = 0x56; data[1] = 0x02; data[2] = 0x02;/*ID pin PULL High*/
+	i2c_himax_master_write(client, &data[0],3,normalRetry);
+	usleep_range(1000, 2000);
+
+	//read id pin high
+	i2c_himax_read(client, 0x57, val_high, 1, normalRetry);
+
+	data[0] = 0x56; data[1] = 0x01; data[2] = 0x01;/*ID pin PULL Low*/
+	i2c_himax_master_write(client, &data[0],3,normalRetry);
+	usleep_range(1000, 2000);
+
+	//read id pin low
+	i2c_himax_read(client, 0x57, val_low, 1, normalRetry);
+
+	if((val_high[0] & 0x01) ==0)
+		ID0=0x02;/*GND*/
+	else if((val_low[0] & 0x01) ==0)
+		ID0=0x01;/*Floating*/
+	else
+		ID0=0x04;/*VCC*/
+	
+	if((val_high[0] & 0x02) ==0)
+		ID1=0x02;/*GND*/
+	else if((val_low[0] & 0x02) ==0)
+		ID1=0x01;/*Floating*/
+	else
+		ID1=0x04;/*VCC*/
+	if((ID0==0x04)&&(ID1!=0x04))
+		{
+			data[0] = 0x56; data[1] = 0x02; data[2] = 0x01;/*ID pin PULL High,Low*/
+			i2c_himax_master_write(client, &data[0],3,normalRetry);
+			usleep_range(1000, 2000);
+
+		}
+	else if((ID0!=0x04)&&(ID1==0x04))
+		{
+			data[0] = 0x56; data[1] = 0x01; data[2] = 0x02;/*ID pin PULL Low,High*/
+			i2c_himax_master_write(client, &data[0],3,normalRetry);
+			usleep_range(1000, 2000);
+
+		}
+	else if((ID0==0x04)&&(ID1==0x04))
+		{
+			data[0] = 0x56; data[1] = 0x02; data[2] = 0x02;/*ID pin PULL High,High*/
+			i2c_himax_master_write(client, &data[0],3,normalRetry);
+			usleep_range(1000, 2000);
+
+		}
+	sensor_id=(ID1<<4)|ID0;
+
+	data[0] = 0xE4; data[1] = sensor_id;
+	i2c_himax_master_write(client, &data[0],2,normalRetry);/*Write to MCU*/
+	usleep_range(1000, 2000);
+
+	return sensor_id;
+
+}
+#endif
+static void himax_power_on_initCMD(struct i2c_client *client)
+{
+	I("%s:\n", __func__);
+
+	himax_touch_information(client);
+
+    //himax_sense_on(private_ts->client, 0x01);//1=Flash, 0=SRAM
+}
+
+#ifdef HX_AUTO_UPDATE_FW
+static int i_update_FW(void)
+{
+	int upgrade_times = 0;
+	unsigned char* ImageBuffer = i_CTPM_FW;
+	int fullFileLength = sizeof(i_CTPM_FW);
+	int i_FW_VER = 0, i_CFG_VER = 0;
+	uint8_t ret = -1, result = 0;
+//	uint8_t tmp_addr[4];
+//	uint8_t tmp_data[4];
+	int CRC_from_FW = 0;
+	int CRC_Check_result = 0;
+
+	i_FW_VER = i_CTPM_FW[FW_VER_MAJ_FLASH_ADDR]<<8 |i_CTPM_FW[FW_VER_MIN_FLASH_ADDR];
+	i_CFG_VER = i_CTPM_FW[CFG_VER_MAJ_FLASH_ADDR]<<8 |i_CTPM_FW[CFG_VER_MIN_FLASH_ADDR];
+
+	I("%s: i_fullFileLength = %d\n", __func__,fullFileLength);
+
+	himax_sense_off(private_ts->client);
+	msleep(500);
+
+	CRC_from_FW = himax_check_CRC(private_ts->client,fw_image_64k);
+	CRC_Check_result = Calculate_CRC_with_AP(ImageBuffer, CRC_from_FW,fw_image_64k);
+	I("%s: Check sum result = %d\n", __func__,CRC_Check_result);
+	//I("%s: ic_data->vendor_fw_ver = %X, i_FW_VER = %X,\n", __func__,ic_data->vendor_fw_ver, i_FW_VER);
+	//I("%s: ic_data->vendor_config_ver = %X, i_CFG_VER = %X,\n", __func__,ic_data->vendor_config_ver, i_CFG_VER);
+	
+	if ((CRC_Check_result == 0)|| ( ic_data->vendor_fw_ver < i_FW_VER ) || ( ic_data->vendor_config_ver < i_CFG_VER ))
+		{
+			himax_int_enable(private_ts->client->irq,0);
+update_retry:
+			if(fullFileLength == FW_SIZE_60k){
+				ret = fts_ctpm_fw_upgrade_with_sys_fs_60k(private_ts->client,ImageBuffer,fullFileLength,false);
+			}else if (fullFileLength == FW_SIZE_64k){
+				ret = fts_ctpm_fw_upgrade_with_sys_fs_64k(private_ts->client,ImageBuffer,fullFileLength,false);
+			}else if (fullFileLength == FW_SIZE_124k){
+				ret = fts_ctpm_fw_upgrade_with_sys_fs_124k(private_ts->client,ImageBuffer,fullFileLength,false);
+			}else if (fullFileLength == FW_SIZE_128k){
+				ret = fts_ctpm_fw_upgrade_with_sys_fs_128k(private_ts->client,ImageBuffer,fullFileLength,false);
+			}
+			if(ret == 0){
+				upgrade_times++;
+				E("%s: TP upgrade error, upgrade_times = %d\n", __func__, upgrade_times);
+				if(upgrade_times < 3)
+					goto update_retry;
+				else
+				{
+					himax_sense_on(private_ts->client, 0x01);
+					msleep(120);
+#ifdef HX_ESD_WORKAROUND
+					HX_ESD_RESET_ACTIVATE = 1;
+#endif
+					result = -1;//upgrade fail
+				}
+			}
+			else if(ret == 1){
+/*
+				// 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver)
+				tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20;
+				tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01;
+				himax_register_write(private_ts->client, tmp_addr, 1, tmp_data);
+
+				// 2. Write driver initial code condition
+				//	  write value from AHB I2C : 0x8001_C603 = 0x000000FF
+				tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xC6; tmp_addr[0] = 0x03;
+				tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xFF;
+				himax_register_write(private_ts->client, tmp_addr, 1, tmp_data);
+
+				// 1. Set DDREG_Req = 0 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver)
+				tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20;
+				tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+				himax_register_write(private_ts->client, tmp_addr, 1, tmp_data);
+*/
+				himax_sense_on(private_ts->client, 0x01);
+				msleep(120);
+#ifdef HX_ESD_WORKAROUND
+				HX_ESD_RESET_ACTIVATE = 1;
+#endif
+
+				ic_data->vendor_fw_ver = i_FW_VER;
+				ic_data->vendor_config_ver = i_CFG_VER;
+				result = 1;//upgrade success
+				I("%s: TP upgrade OK\n", __func__);
+			}
+
+				himax_int_enable(private_ts->client->irq,1);
+			return result;
+		}
+	else
+		{
+			himax_sense_on(private_ts->client, 0x01);
+			return 0;//NO upgrade
+		}
+}
+#endif 
+
+#ifdef HX_RST_PIN_FUNC
+void himax_HW_reset(uint8_t loadconfig,uint8_t int_off)
+{
+	struct himax_ts_data *ts = private_ts;
+	int ret = 0;
+
+	return;
+	if (ts->rst_gpio) {
+		if(int_off)
+			{
+				if (ts->use_irq)
+					himax_int_enable(private_ts->client->irq,0);
+				else {
+					hrtimer_cancel(&ts->timer);
+					ret = cancel_work_sync(&ts->work);
+				}
+			}
+
+		I("%s: Now reset the Touch chip.\n", __func__);
+
+		himax_rst_gpio_set(ts->rst_gpio, 0);
+		msleep(20);
+		himax_rst_gpio_set(ts->rst_gpio, 1);
+		msleep(20);
+
+		if(loadconfig)
+			himax_loadSensorConfig(private_ts->client,private_ts->pdata);
+
+		if(int_off)
+			{
+				if (ts->use_irq)
+					himax_int_enable(private_ts->client->irq,1);
+				else
+					hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+			}
+	}
+}
+#endif
+
+int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_data *pdata)
+{
+
+	if (!client) {
+		E("%s: Necessary parameters client are null!\n", __func__);
+		return -EINVAL;
+	}
+
+	if(config_load == false)
+		{
+			config_selected = kzalloc(sizeof(*config_selected), GFP_KERNEL);
+			if (config_selected == NULL) {
+				E("%s: alloc config_selected fail!\n", __func__);
+				return -ENOMEM;
+			}
+		}
+
+		himax_power_on_initCMD(client);
+
+		himax_int_enable(client->irq,0);
+		himax_read_FW_ver(client);
+#ifdef HX_RST_PIN_FUNC
+	himax_HW_reset(true,false);
+#endif
+	himax_int_enable(client->irq,1);
+		I("FW_VER : %X \n",ic_data->vendor_fw_ver);
+
+		ic_data->vendor_sensor_id=0x2602;
+		I("sensor_id=%x.\n",ic_data->vendor_sensor_id);
+
+	himax_sense_on(private_ts->client, 0x01);//1=Flash, 0=SRAM
+	msleep(120);
+#ifdef HX_ESD_WORKAROUND
+	HX_ESD_RESET_ACTIVATE = 1;
+#endif
+	I("%s: initialization complete\n", __func__);
+
+	return 1;
+}
+
+#ifdef HX_ESD_WORKAROUND
+void ESD_HW_REST(void)
+{
+	I("START_Himax TP: ESD - Reset\n");	
+	
+	HX_report_ESD_event();
+	ESD_00_counter = 0;
+	ESD_00_Flag = 0;
+	/*************************************/
+		if (private_ts->protocol_type == PROTOCOL_TYPE_A)
+		input_mt_sync(private_ts->input_dev);
+		input_report_key(private_ts->input_dev, BTN_TOUCH, 0);
+		input_sync(private_ts->input_dev);
+		/*************************************/
+
+	I("END_Himax TP: ESD - Reset\n");
+}
+#endif
+#ifdef HX_HIGH_SENSE
+void himax_set_HSEN_func(struct i2c_client *client,uint8_t HSEN_enable)
+{
+	uint8_t tmp_data[4];
+
+	if(HSEN_enable)
+	{
+		I(" %s in", __func__);
+		HSEN_bit_retry:
+		himax_set_HSEN_enable(client,HSEN_enable);
+		msleep(20);
+		himax_get_HSEN_enable(client,tmp_data);
+		I("%s: Read HSEN bit data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__
+			,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]);
+		if(tmp_data[0]!= 0x01)
+			{
+				I("%s: retry HSEN bit write data[0]=%x  \n",__func__,tmp_data[0]);
+				goto HSEN_bit_retry;
+			}
+	}
+}
+
+static void himax_HSEN_func(struct work_struct *work)
+{
+	struct himax_ts_data *ts = container_of(work, struct himax_ts_data,
+							hsen_work.work);
+
+	himax_set_HSEN_func(ts->client, ts->HSEN_enable);
+}
+
+#endif
+
+#ifdef HX_SMART_WAKEUP
+#ifdef HX_GESTURE_TRACK
+static void gest_pt_log_coordinate(int rx, int tx)
+{
+	//driver report x y with range 0 - 255 , we scale it up to x/y pixel
+	gest_pt_x[gest_pt_cnt] = rx*(ic_data->HX_X_RES)/255;
+	gest_pt_y[gest_pt_cnt] = tx*(ic_data->HX_Y_RES)/255;
+}
+#endif
+static int himax_parse_wake_event(struct himax_ts_data *ts)
+{
+	uint8_t buf[64];
+	unsigned char check_sum_cal = 0;
+#ifdef HX_GESTURE_TRACK
+	int tmp_max_x=0x00,tmp_min_x=0xFFFF,tmp_max_y=0x00,tmp_min_y=0xFFFF;
+	int gest_len;
+#endif
+	int i=0, check_FC = 0, gesture_flag = 0;
+
+	himax_burst_enable(ts->client, 0);
+	himax_read_event_stack(ts->client,buf,56);
+
+	for(i=0;i<GEST_PTLG_ID_LEN;i++)
+	{
+		if (check_FC==0)
+		{
+			if((buf[0]!=0x00)&&((buf[0]<=0x0F)||(buf[0]==0x80)))
+			{
+				check_FC = 1;
+				gesture_flag = buf[i];
+			}
+			else
+			{
+				check_FC = 0;
+				I("ID START at %x , value = %x skip the event\n", i, buf[i]);
+				break;
+			}
+		}
+		else
+		{
+			if(buf[i]!=gesture_flag)
+			{
+				check_FC = 0;
+				I("ID NOT the same %x != %x So STOP parse event\n", buf[i], gesture_flag);
+				break;
+			}
+		}
+
+		I("0x%2.2X ", buf[i]);
+		if (i % 8 == 7)
+				I("\n");
+	}
+	I("Himax gesture_flag= %x\n",gesture_flag );
+	I("Himax check_FC is %d\n", check_FC);
+
+	if (check_FC == 0)
+		return 0;
+	if(buf[GEST_PTLG_ID_LEN] != GEST_PTLG_HDR_ID1 ||
+			buf[GEST_PTLG_ID_LEN+1] != GEST_PTLG_HDR_ID2)
+		return 0;
+	for(i=0;i<(GEST_PTLG_ID_LEN+GEST_PTLG_HDR_LEN);i++)
+	{
+		I("P[%x]=0x%2.2X \n", i, buf[i]);
+		I("checksum=0x%2.2X \n", check_sum_cal);
+		check_sum_cal += buf[i];
+	}
+	if ((check_sum_cal != 0x00) )
+	{
+		I(" %s : check_sum_cal: 0x%02X\n",__func__ ,check_sum_cal);
+		return 0;
+	}
+#ifdef HX_GESTURE_TRACK
+	if(buf[GEST_PTLG_ID_LEN] == GEST_PTLG_HDR_ID1 &&
+			buf[GEST_PTLG_ID_LEN+1] == GEST_PTLG_HDR_ID2)
+	{
+		gest_len = buf[GEST_PTLG_ID_LEN+2];
+
+		I("gest_len = %d ",gest_len);
+
+		i = 0;
+		gest_pt_cnt = 0;
+		I("gest doornidate start \n %s",__func__);
+		while(i<(gest_len+1)/2)
+		{
+			gest_pt_log_coordinate(buf[GEST_PTLG_ID_LEN+4+i*2],buf[GEST_PTLG_ID_LEN+4+i*2+1]);
+			i++;
+
+			I("gest_pt_x[%d]=%d \n",gest_pt_cnt,gest_pt_x[gest_pt_cnt]);
+			I("gest_pt_y[%d]=%d \n",gest_pt_cnt,gest_pt_y[gest_pt_cnt]);
+
+			gest_pt_cnt +=1;
+		}
+		if(gest_pt_cnt)
+			{
+				for(i=0; i<gest_pt_cnt; i++)
+					{
+						if(tmp_max_x<gest_pt_x[i])
+							tmp_max_x=gest_pt_x[i];
+						if(tmp_min_x>gest_pt_x[i])
+							tmp_min_x=gest_pt_x[i];
+						if(tmp_max_y<gest_pt_y[i])
+							tmp_max_y=gest_pt_y[i];
+						if(tmp_min_y>gest_pt_y[i])
+							tmp_min_y=gest_pt_y[i];
+					}
+				I("gest_point x_min= %d, x_max= %d, y_min= %d, y_max= %d\n",tmp_min_x,tmp_max_x,tmp_min_y,tmp_max_y);
+				gest_start_x=gest_pt_x[0];
+				gn_gesture_coor[0] = gest_start_x;
+				gest_start_y=gest_pt_y[0];
+				gn_gesture_coor[1] = gest_start_y;
+				gest_end_x=gest_pt_x[gest_pt_cnt-1];
+				gn_gesture_coor[2] = gest_end_x;
+				gest_end_y=gest_pt_y[gest_pt_cnt-1];
+				gn_gesture_coor[3] = gest_end_y;
+				gest_width = tmp_max_x - tmp_min_x;
+				gn_gesture_coor[4] = gest_width;
+				gest_height = tmp_max_y - tmp_min_y;
+				gn_gesture_coor[5] = gest_height;
+				gest_mid_x = (tmp_max_x + tmp_min_x)/2;
+				gn_gesture_coor[6] = gest_mid_x;
+				gest_mid_y = (tmp_max_y + tmp_min_y)/2;
+				gn_gesture_coor[7] = gest_mid_y;
+				gn_gesture_coor[8] = gest_mid_x;//gest_up_x
+				gn_gesture_coor[9] = gest_mid_y-gest_height/2;//gest_up_y
+				gn_gesture_coor[10] = gest_mid_x;//gest_down_x
+				gn_gesture_coor[11] = gest_mid_y+gest_height/2;	//gest_down_y
+				gn_gesture_coor[12] = gest_mid_x-gest_width/2;	//gest_left_x
+				gn_gesture_coor[13] = gest_mid_y;	//gest_left_y
+				gn_gesture_coor[14] = gest_mid_x+gest_width/2;	//gest_right_x
+				gn_gesture_coor[15] = gest_mid_y; //gest_right_y
+
+			}
+
+	}
+#endif
+	if(gesture_flag != 0x80)
+	{
+		if(!ts->gesture_cust_en[gesture_flag])
+			{
+				I("%s NOT report customer key \n ",__func__);
+				return 0;//NOT report customer key
+			}
+	}
+	else
+	{
+		if(!ts->gesture_cust_en[0])
+			{
+				I("%s NOT report report double click \n",__func__);
+				return 0;//NOT report power key
+			}
+	}
+
+	if(gesture_flag == 0x80)
+		return EV_GESTURE_PWR;
+	else
+		return gesture_flag;
+}
+
+void himax_wake_check_func(void)
+{
+	int ret_event = 0, KEY_EVENT = 0;
+
+	ret_event = himax_parse_wake_event(private_ts);
+	switch (ret_event) {
+		case EV_GESTURE_PWR:
+			KEY_EVENT = KEY_POWER;
+		break;
+		case EV_GESTURE_01:
+			KEY_EVENT = KEY_CUST_01;
+		break;
+		case EV_GESTURE_02:
+			KEY_EVENT = KEY_CUST_02;
+		break;
+		case EV_GESTURE_03:
+			KEY_EVENT = KEY_CUST_03;
+		break;
+		case EV_GESTURE_04:
+			KEY_EVENT = KEY_CUST_04;
+		break;
+		case EV_GESTURE_05:
+			KEY_EVENT = KEY_CUST_05;
+		break;
+		case EV_GESTURE_06:
+			KEY_EVENT = KEY_CUST_06;
+		break;
+		case EV_GESTURE_07:
+			KEY_EVENT = KEY_CUST_07;
+		break;
+		case EV_GESTURE_08:
+			KEY_EVENT = KEY_CUST_08;
+		break;
+		case EV_GESTURE_09:
+			KEY_EVENT = KEY_CUST_09;
+		break;
+		case EV_GESTURE_10:
+			KEY_EVENT = KEY_CUST_10;
+		break;
+		case EV_GESTURE_11:
+			KEY_EVENT = KEY_CUST_11;
+		break;
+		case EV_GESTURE_12:
+			KEY_EVENT = KEY_CUST_12;
+		break;
+		case EV_GESTURE_13:
+			KEY_EVENT = KEY_CUST_13;
+		break;
+		case EV_GESTURE_14:
+			KEY_EVENT = KEY_CUST_14;
+		break;
+		case EV_GESTURE_15:
+			KEY_EVENT = KEY_CUST_15;
+		break;
+	}
+	if(ret_event)
+		{
+			I(" %s SMART WAKEUP KEY event %x press\n",__func__,KEY_EVENT);
+			input_report_key(private_ts->input_dev, KEY_EVENT, 1);
+			input_sync(private_ts->input_dev);
+			//msleep(100);
+			I(" %s SMART WAKEUP KEY event %x release\n",__func__,KEY_EVENT);
+			input_report_key(private_ts->input_dev, KEY_EVENT, 0);
+			input_sync(private_ts->input_dev);
+			FAKE_POWER_KEY_SEND=true;
+#ifdef HX_GESTURE_TRACK
+			I("gest_start_x= %d, gest_start_y= %d, gest_end_x= %d, gest_end_y= %d\n",gest_start_x,gest_start_y,
+			gest_end_x,gest_end_y);
+			I("gest_width= %d, gest_height= %d, gest_mid_x= %d, gest_mid_y= %d\n",gest_width,gest_height,
+			gest_mid_x,gest_mid_y);
+			I("gest_up_x= %d, gest_up_y= %d, gest_down_x= %d, gest_down_y= %d\n",gn_gesture_coor[8],gn_gesture_coor[9],
+			gn_gesture_coor[10],gn_gesture_coor[11]);
+			I("gest_left_x= %d, gest_left_y= %d, gest_right_x= %d, gest_right_y= %d\n",gn_gesture_coor[12],gn_gesture_coor[13],
+			gn_gesture_coor[14],gn_gesture_coor[15]);
+#endif
+		}
+}
+
+#endif
+static void himax_ts_button_func(int tp_key_index,struct himax_ts_data *ts)
+{
+	uint16_t x_position = 0, y_position = 0;
+if ( tp_key_index != 0x00)
+	{
+		I("virtual key index =%x\n",tp_key_index);
+		if ( tp_key_index == 0x01) {
+			vk_press = 1;
+			I("back key pressed\n");
+				if (ts->pdata->virtual_key)
+				{
+					if (ts->button[0].index) {
+						x_position = (ts->button[0].x_range_min + ts->button[0].x_range_max) / 2;
+						y_position = (ts->button[0].y_range_min + ts->button[0].y_range_max) / 2;
+					}
+					if (ts->protocol_type == PROTOCOL_TYPE_A) {
+						input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0);
+						input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+							100);
+						input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
+							100);
+						input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
+							100);
+						input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
+							x_position);
+						input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
+							y_position);
+						input_mt_sync(ts->input_dev);
+					} else if (ts->protocol_type == PROTOCOL_TYPE_B) {
+						input_mt_slot(ts->input_dev, 0);
+						input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER,
+						1);
+						input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+							100);
+						input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
+							100);
+						input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
+							100);
+						input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
+							x_position);
+						input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
+							y_position);
+					}
+				}
+				else
+					input_report_key(ts->input_dev, KEY_BACK, 1);
+		}
+		else if ( tp_key_index == 0x02) {
+			vk_press = 1;
+			I("home key pressed\n");
+				if (ts->pdata->virtual_key)
+				{
+					if (ts->button[1].index) {
+						x_position = (ts->button[1].x_range_min + ts->button[1].x_range_max) / 2;
+						y_position = (ts->button[1].y_range_min + ts->button[1].y_range_max) / 2;
+					}
+						if (ts->protocol_type == PROTOCOL_TYPE_A) {
+						input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0);
+						input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+							100);
+						input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
+							100);
+						input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
+							100);
+						input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
+							x_position);
+						input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
+							y_position);
+						input_mt_sync(ts->input_dev);
+					} else if (ts->protocol_type == PROTOCOL_TYPE_B) {
+						input_mt_slot(ts->input_dev, 0);
+						input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER,
+						1);
+						input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+							100);
+						input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
+							100);
+						input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
+							100);
+						input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
+							x_position);
+						input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
+							y_position);
+					}
+				}
+				else
+					input_report_key(ts->input_dev, KEY_HOME, 1);
+		}
+		else if ( tp_key_index == 0x04) {
+			vk_press = 1;
+			I("APP_switch key pressed\n");
+				if (ts->pdata->virtual_key)
+				{
+					if (ts->button[2].index) {
+						x_position = (ts->button[2].x_range_min + ts->button[2].x_range_max) / 2;
+						y_position = (ts->button[2].y_range_min + ts->button[2].y_range_max) / 2;
+					}
+						if (ts->protocol_type == PROTOCOL_TYPE_A) {
+						input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0);
+						input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+							100);
+						input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
+							100);
+						input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
+							100);
+						input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
+							x_position);
+						input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
+							y_position);
+						input_mt_sync(ts->input_dev);
+					} else if (ts->protocol_type == PROTOCOL_TYPE_B) {
+						input_mt_slot(ts->input_dev, 0);
+						input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER,
+						1);
+						input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+							100);
+						input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
+							100);
+						input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
+							100);
+						input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
+							x_position);
+						input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
+							y_position);
+					}
+				}
+				else
+					input_report_key(ts->input_dev, KEY_F10, 1);	
+		}
+		input_sync(ts->input_dev);
+	}
+else/*tp_key_index =0x00*/
+	{
+		I("virtual key released\n");
+		vk_press = 0;
+		if (ts->protocol_type == PROTOCOL_TYPE_A) {
+			input_mt_sync(ts->input_dev);
+		}
+		else if (ts->protocol_type == PROTOCOL_TYPE_B) {
+			input_mt_slot(ts->input_dev, 0);
+			input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0);
+		}
+		input_report_key(ts->input_dev, KEY_BACK, 0);
+		input_report_key(ts->input_dev, KEY_HOME, 0);
+		input_report_key(ts->input_dev, KEY_F10, 0);
+	input_sync(ts->input_dev);
+	}
+}
+
+void himax_ts_work(struct himax_ts_data *ts)
+{
+	int ret = 0;
+	uint8_t  finger_num, hw_reset_check[2];
+	uint8_t buf[128];
+	uint8_t finger_on = 0;
+	int32_t loop_i;
+	uint16_t check_sum_cal = 0;
+	int raw_cnt_max ;
+	int raw_cnt_rmd ;
+	int hx_touch_info_size;
+	uint8_t coordInfoSize = ts->coord_data_size + ts->area_data_size + 4;
+
+#ifdef HX_TP_PROC_DIAG
+	int16_t *mutual_data;
+	int16_t *self_data;
+	uint8_t diag_cmd;
+	int  	i;
+	int 	mul_num;
+	int 	self_num;
+	int RawDataLen = 0;
+	//coordinate dump start
+	char coordinate_char[15+(ic_data->HX_MAX_PT+5)*2*5+2];
+	//coordinate dump end
+#endif
+
+	memset(buf, 0x00, sizeof(buf));
+	memset(hw_reset_check, 0x00, sizeof(hw_reset_check));
+
+	raw_cnt_max = ic_data->HX_MAX_PT/4;
+	raw_cnt_rmd = ic_data->HX_MAX_PT%4;
+	
+#if defined(HX_USB_DETECT2)
+	himax_cable_detect_func();
+#endif
+
+	if (raw_cnt_rmd != 0x00) //more than 4 fingers
+	{
+		RawDataLen = cal_data_len(raw_cnt_rmd, ic_data->HX_MAX_PT, raw_cnt_max);
+		hx_touch_info_size = (ic_data->HX_MAX_PT+raw_cnt_max+2)*4;
+	}
+	else //less than 4 fingers
+	{
+		RawDataLen = cal_data_len(raw_cnt_rmd, ic_data->HX_MAX_PT, raw_cnt_max);
+		hx_touch_info_size = (ic_data->HX_MAX_PT+raw_cnt_max+1)*4;
+	}
+
+#ifdef HX_TP_PROC_DIAG
+	diag_cmd = getDiagCommand();
+	if( diag_cmd ){
+		ret = read_event_stack(ts->client, buf, 128);
+	}
+	else{
+		if(touch_monitor_stop_flag != 0){
+			ret = read_event_stack(ts->client, buf, 128);
+			touch_monitor_stop_flag-- ;
+		}
+		else{
+			ret = read_event_stack(ts->client, buf, hx_touch_info_size);
+		}
+	}
+
+	if (!ret)
+#else
+	if(!read_event_stack(ts->client, buf, hx_touch_info_size))
+#endif		
+	{
+		E("%s: can't read data from chip!\n", __func__);
+		goto err_workqueue_out;
+	}
+	post_read_event_stack(ts->client);
+#ifdef HX_ESD_WORKAROUND
+	for(i = 0; i < hx_touch_info_size; i++)
+	{
+		if(buf[i] == 0xED)/*case 1 ESD recovery flow*/
+		{
+			check_sum_cal = 1;
+
+		}else if(buf[i] == 0x00)
+		{
+			ESD_00_Flag = 1;
+		}
+		else
+		{
+			check_sum_cal = 0;
+			ESD_00_counter = 0;
+	    ESD_00_Flag = 0;
+			i = hx_touch_info_size;
+			break;
+		}		
+	}
+	if (ESD_00_Flag == 1){
+		ESD_00_counter ++;
+	}
+	if (ESD_00_counter > 1){
+		check_sum_cal = 2;
+	}
+	
+	 if (check_sum_cal == 2 && HX_ESD_RESET_ACTIVATE == 0)
+	 {
+	  I("[HIMAX TP MSG]: ESD event checked - ALL Zero.\n");
+	  ESD_HW_REST();
+	  return;
+	 }
+	 
+	if (check_sum_cal == 1 && HX_ESD_RESET_ACTIVATE == 0)
+	{
+		I("[HIMAX TP MSG]: ESD event checked - ALL 0xED.\n");
+		ESD_HW_REST();
+		return;
+	}
+	else if (HX_ESD_RESET_ACTIVATE)
+	{
+#ifdef HX_SMART_WAKEUP
+		queue_delayed_work(ts->himax_smwp_wq, &ts->smwp_work, msecs_to_jiffies(50));
+#endif
+#ifdef HX_HIGH_SENSE
+		queue_delayed_work(ts->himax_hsen_wq, &ts->hsen_work, msecs_to_jiffies(50));
+#endif
+		HX_ESD_RESET_ACTIVATE = 0;/*drop 1st interrupts after chip reset*/
+		I("[HIMAX TP MSG]:%s: Back from reset, ready to serve.\n", __func__);
+	}
+#endif
+	for (loop_i = 0, check_sum_cal = 0; loop_i < hx_touch_info_size; loop_i++)
+		check_sum_cal += buf[loop_i];
+	
+	if ((check_sum_cal % 0x100 != 0) )
+	{
+		I("[HIMAX TP MSG] checksum fail : check_sum_cal: 0x%02X\n", check_sum_cal);
+		return;
+	}
+
+	if (ts->debug_log_level & BIT(0)) {
+		I("%s: raw data:\n", __func__);
+		for (loop_i = 0; loop_i < hx_touch_info_size; loop_i++) {
+			I("P %d = 0x%2.2X ", loop_i, buf[loop_i]);
+			if (loop_i % 8 == 7)
+				I("\n");
+		}
+	}
+
+	//touch monitor raw data fetch
+#ifdef HX_TP_PROC_DIAG
+	diag_cmd = getDiagCommand();
+	if (diag_cmd >= 1 && diag_cmd <= 6)
+	{
+		//Check 124th byte CRC
+		if(!diag_check_sum(hx_touch_info_size, buf))
+		{
+			goto bypass_checksum_failed_packet;
+		}
+#ifdef HX_TP_PROC_2T2R
+		if(Is_2T2R && diag_cmd == 4)
+		{
+			mutual_data = getMutualBuffer_2();
+			self_data 	= getSelfBuffer();
+
+			// initiallize the block number of mutual and self
+			mul_num = getXChannel_2() * getYChannel_2();
+
+#ifdef HX_EN_SEL_BUTTON
+			self_num = getXChannel_2() + getYChannel_2() + ic_data->HX_BT_NUM;
+#else
+			self_num = getXChannel_2() + getYChannel_2();
+#endif
+		}
+		else
+#endif			
+		{
+			mutual_data = getMutualBuffer();
+			self_data 	= getSelfBuffer();
+
+			// initiallize the block number of mutual and self
+			mul_num = getXChannel() * getYChannel();
+
+#ifdef HX_EN_SEL_BUTTON
+			self_num = getXChannel() + getYChannel() + ic_data->HX_BT_NUM;
+#else
+			self_num = getXChannel() + getYChannel();
+#endif
+		}
+
+		diag_parse_raw_data(hx_touch_info_size, RawDataLen, mul_num, self_num, buf, diag_cmd, mutual_data,	self_data);
+
+	}
+	else if (diag_cmd == 7)
+	{
+		memcpy(&(diag_coor[0]), &buf[0], 128);
+	}
+	//coordinate dump start
+	if (coordinate_dump_enable == 1)
+	{
+		for(i=0; i<(15 + (ic_data->HX_MAX_PT+5)*2*5); i++)
+		{
+			coordinate_char[i] = 0x20;
+		}
+		coordinate_char[15 + (ic_data->HX_MAX_PT+5)*2*5] = 0xD;
+		coordinate_char[15 + (ic_data->HX_MAX_PT+5)*2*5 + 1] = 0xA;
+	}
+	//coordinate dump end
+bypass_checksum_failed_packet:
+#endif
+		EN_NoiseFilter = (buf[HX_TOUCH_INFO_POINT_CNT+2]>>3);
+		//I("EN_NoiseFilter=%d\n",EN_NoiseFilter);
+		EN_NoiseFilter = EN_NoiseFilter & 0x01;
+		//I("EN_NoiseFilter2=%d\n",EN_NoiseFilter);
+
+#if defined(HX_EN_SEL_BUTTON) || defined(HX_EN_MUT_BUTTON)
+		tpd_key = (buf[HX_TOUCH_INFO_POINT_CNT+2]>>4);
+		if (tpd_key == 0x0F)/*All (VK+AA)leave*/
+		{
+			tpd_key = 0x00;
+		}
+		//I("[DEBUG] tpd_key:  %x\r\n", tpd_key);
+#else
+		tpd_key = 0x00;
+#endif
+
+		p_point_num = hx_point_num;
+
+		if (buf[HX_TOUCH_INFO_POINT_CNT] == 0xff)
+			hx_point_num = 0;
+		else
+			hx_point_num= buf[HX_TOUCH_INFO_POINT_CNT] & 0x0f;
+
+		// Touch Point information
+		if (hx_point_num != 0 ) {
+			if(vk_press == 0x00)
+				{
+					uint16_t old_finger = ts->pre_finger_mask;
+					ts->pre_finger_mask = 0;
+					finger_num = buf[coordInfoSize - 4] & 0x0F;
+					finger_on = 1;
+					AA_press = 1;
+					for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) {
+							int base = loop_i * 4;
+							int x = buf[base] << 8 | buf[base + 1];
+							int y = (buf[base + 2] << 8 | buf[base + 3]);
+							int w = buf[(ts->nFinger_support * 4) + loop_i];
+						if(x >= 0 && x <= ts->pdata->abs_x_max && y >= 0 && y <= ts->pdata->abs_y_max){
+							finger_num--;
+
+							if ((ts->debug_log_level & BIT(3)) > 0)
+							{
+								if (old_finger >> loop_i == 0)
+								{
+									if (ts->useScreenRes)
+									{
+										I("status: Screen:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n",
+										loop_i+1, x * ts->widthFactor >> SHIFTBITS,
+										y * ts->heightFactor >> SHIFTBITS, w, EN_NoiseFilter);
+									}
+									else
+									{
+										I("status: Raw:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n",
+										loop_i+1, x, y, w, EN_NoiseFilter);
+									}
+								}
+							}
+
+							if (ts->protocol_type == PROTOCOL_TYPE_B)
+							{
+								input_mt_slot(ts->input_dev, loop_i);
+							}
+
+							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_PRESSURE, w);
+							input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
+							input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
+							
+							if (ts->protocol_type == PROTOCOL_TYPE_A)
+							{
+								input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, loop_i);
+								input_mt_sync(ts->input_dev);
+							}
+							else
+							{
+								ts->last_slot = loop_i;
+								input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 1);
+							}
+
+							if (!ts->first_pressed)
+							{
+								ts->first_pressed = 1;
+								I("S1@%d, %d\n", x, y);
+							}
+
+							ts->pre_finger_data[loop_i][0] = x;
+							ts->pre_finger_data[loop_i][1] = y;
+
+
+							if (ts->debug_log_level & BIT(1))
+								I("Finger %d=> X:%d, Y:%d W:%d, Z:%d, F:%d, N:%d\n",
+									loop_i + 1, x, y, w, w, loop_i + 1, EN_NoiseFilter);
+										
+							ts->pre_finger_mask = ts->pre_finger_mask + (1 << loop_i);
+											
+						} else {
+							if (ts->protocol_type == PROTOCOL_TYPE_B)
+							{
+								input_mt_slot(ts->input_dev, loop_i);
+								input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0);
+							}
+
+							if (loop_i == 0 && ts->first_pressed == 1)
+							{
+								ts->first_pressed = 2;
+								I("E1@%d, %d\n",
+								ts->pre_finger_data[0][0] , ts->pre_finger_data[0][1]);
+							}
+							if ((ts->debug_log_level & BIT(3)) > 0)
+							{
+								if (old_finger >> loop_i == 1)
+								{
+									if (ts->useScreenRes)
+									{
+										I("status: Screen:F:%02d Up, X:%d, Y:%d, N:%d\n",
+										loop_i+1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS,
+										ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter);
+									}
+									else
+									{
+										I("status: Raw:F:%02d Up, X:%d, Y:%d, N:%d\n",
+										loop_i+1, ts->pre_finger_data[loop_i][0],
+										ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter);
+									}
+								}
+							}
+						}
+					}
+
+				}else if ((tpd_key_old != 0x00)&&(tpd_key == 0x00)) {
+					//temp_x[0] = 0xFFFF;
+					//temp_y[0] = 0xFFFF;
+					//temp_x[1] = 0xFFFF;
+					//temp_y[1] = 0xFFFF;
+					himax_ts_button_func(tpd_key,ts);
+					finger_on = 0;
+				}
+			input_report_key(ts->input_dev, BTN_TOUCH, finger_on);
+			input_sync(ts->input_dev);
+		} else if (hx_point_num == 0){
+			if(AA_press)
+				{
+				// leave event
+				finger_on = 0;
+				AA_press = 0;
+				if (ts->protocol_type == PROTOCOL_TYPE_A)
+					input_mt_sync(ts->input_dev);
+
+				for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) {
+						if (((ts->pre_finger_mask >> loop_i) & 1) == 1) {
+							if (ts->protocol_type == PROTOCOL_TYPE_B) {
+								input_mt_slot(ts->input_dev, loop_i);
+								input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0);
+							}
+						}
+					}
+				if (ts->pre_finger_mask > 0) {
+					for (loop_i = 0; loop_i < ts->nFinger_support && (ts->debug_log_level & BIT(3)) > 0; loop_i++) {
+						if (((ts->pre_finger_mask >> loop_i) & 1) == 1) {
+							if (ts->useScreenRes) {
+								I("status:%X, Screen:F:%02d Up, X:%d, Y:%d, N:%d\n", 0, loop_i+1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS,
+									ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter);
+							} else {
+								I("status:%X, Raw:F:%02d Up, X:%d, Y:%d, N:%d\n",0, loop_i+1, ts->pre_finger_data[loop_i][0],ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter);
+							}
+						}
+					}
+					ts->pre_finger_mask = 0;
+				}
+
+				if (ts->first_pressed == 1) {
+					ts->first_pressed = 2;
+					I("E1@%d, %d\n",ts->pre_finger_data[0][0] , ts->pre_finger_data[0][1]);
+				}
+
+				if (ts->debug_log_level & BIT(1))
+					I("All Finger leave\n");
+
+			}
+			else if (tpd_key != 0x00) {
+				himax_ts_button_func(tpd_key,ts);
+				finger_on = 1;
+			}
+			else if ((tpd_key_old != 0x00)&&(tpd_key == 0x00)) {
+				himax_ts_button_func(tpd_key,ts);
+				finger_on = 0;
+			}
+			input_report_key(ts->input_dev, BTN_TOUCH, finger_on);
+			input_sync(ts->input_dev);
+		}
+		tpd_key_old = tpd_key;
+		Last_EN_NoiseFilter = EN_NoiseFilter;
+
+workqueue_out:
+	return;
+
+err_workqueue_out:
+	I("%s: Now reset the Touch chip.\n", __func__);
+
+#ifdef HX_RST_PIN_FUNC
+	himax_HW_reset(true,false);
+#endif
+
+	goto workqueue_out;
+}
+enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer)
+{
+	struct himax_ts_data *ts;
+
+	ts = container_of(timer, struct himax_ts_data, timer);
+	queue_work(ts->himax_wq, &ts->work);
+	hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL);
+	return HRTIMER_NORESTART;
+}
+
+#if defined(HX_USB_DETECT)
+static void himax_cable_tp_status_handler_func(int connect_status)
+{
+	struct himax_ts_data *ts;
+	I("Touch: cable change to %d\n", connect_status);
+	ts = private_ts;
+	if (ts->cable_config) {
+		if (!atomic_read(&ts->suspend_mode)) {
+			if ((!!connect_status) != ts->usb_connected) {
+				if (!!connect_status) {
+					ts->cable_config[1] = 0x01;
+					ts->usb_connected = 0x01;
+				} else {
+					ts->cable_config[1] = 0x00;
+					ts->usb_connected = 0x00;
+				}
+
+				i2c_himax_master_write(ts->client, ts->cable_config,
+					sizeof(ts->cable_config), HIMAX_I2C_RETRY_TIMES);
+
+				I("%s: Cable status change: 0x%2.2X\n", __func__, ts->cable_config[1]);
+			} else
+				I("%s: Cable status is the same as previous one, ignore.\n", __func__);
+		} else {
+			if (connect_status)
+				ts->usb_connected = 0x01;
+			else
+				ts->usb_connected = 0x00;
+			I("%s: Cable status remembered: 0x%2.2X\n", __func__, ts->usb_connected);
+		}
+	}
+}
+
+static struct t_cable_status_notifier himax_cable_status_handler = {
+	.name = "usb_tp_connected",
+	.func = himax_cable_tp_status_handler_func,
+};
+
+#endif
+
+#if defined(HX_USB_DETECT2)
+void himax_cable_detect_func(void)
+{
+	uint8_t tmp_addr[4];
+	uint8_t tmp_data[128];
+	struct himax_ts_data *ts;
+	u32 connect_status = 0;
+
+	connect_status = USB_Flag;//upmu_is_chr_det();
+	ts = private_ts;
+	//I("Touch: cable status=%d, cable_config=%p, usb_connected=%d \n", connect_status,ts->cable_config, ts->usb_connected);
+	if (ts->cable_config) {
+		if ((!!connect_status) != ts->usb_connected) {
+			//notify USB plug/unplug
+			// 0x9008_8060 ==> 0x0000_0000/0001
+			tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x60;
+			tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00;
+			
+			if (!!connect_status) {
+				tmp_data[0] = 0x01;
+				ts->usb_connected = 0x01;
+			} else {
+				tmp_data[0] = 0x00;
+				ts->usb_connected = 0x00;
+			}
+
+			himax_flash_write_burst(ts->client, tmp_addr, tmp_data);
+
+			I("%s: Cable status change: 0x%2.2X\n", __func__, ts->usb_connected);
+			}
+		//else
+			//I("%s: Cable status is the same as previous one, ignore.\n", __func__);
+	}
+}
+#endif
+
+#ifdef CONFIG_FB
+int himax_fb_register(struct himax_ts_data *ts)
+{
+	int ret = 0;
+
+	I(" %s in", __func__);
+	ts->fb_notif.notifier_call = fb_notifier_callback;
+	ret = fb_register_client(&ts->fb_notif);
+	if (ret)
+		E(" Unable to register fb_notifier: %d\n", ret);
+
+	return ret;
+}
+#endif
+
+#ifdef HX_SMART_WAKEUP
+void himax_set_SMWP_func(struct i2c_client *client,uint8_t SMWP_enable)
+{
+	uint8_t tmp_data[4];
+
+	if(SMWP_enable)
+	{
+		SMWP_bit_retry:
+		himax_set_SMWP_enable(client, SMWP_enable);
+		msleep(20);
+		himax_get_SMWP_enable(client,tmp_data);
+		I("%s: Read SMWP bit data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__
+			,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]);
+		if(tmp_data[0]!= 0x01)
+			{
+				I("%s: retry SMWP bit write data[0]=%x  \n",__func__,tmp_data[0]);
+				goto SMWP_bit_retry;
+			}
+	}
+}
+
+static void himax_SMWP_work(struct work_struct *work)
+{
+	struct himax_ts_data *ts = container_of(work, struct himax_ts_data,
+							smwp_work.work);
+	I(" %s in", __func__);
+
+	himax_set_SMWP_func(ts->client,ts->SMWP_enable);
+
+}
+#endif
+
+#ifdef  HX_TP_PROC_FLASH_DUMP
+static void himax_ts_flash_work_func(struct work_struct *work)
+{
+	himax_ts_flash_func();
+}
+#endif
+
+#ifdef  HX_TP_PROC_DIAG
+static void himax_ts_diag_work_func(struct work_struct *work)
+{
+	himax_ts_diag_func();
+}
+#endif
+
+void himax_ts_init(struct himax_ts_data *ts)
+{
+	int ret = 0, err = 0;
+	struct himax_i2c_platform_data *pdata;
+	struct i2c_client *client;
+
+	client = ts->client;
+	pdata = ts->pdata;
+
+	I("%s: Start.\n", __func__);
+
+	/* Set pinctrl in active state */
+	if (ts->ts_pinctrl) {
+		ret = pinctrl_select_state(ts->ts_pinctrl,
+					ts->pinctrl_state_active);
+		if (ret < 0) {
+			E("Failed to set pin in active state %d",ret);
+		}
+	}
+
+	himax_burst_enable(client, 0);
+
+	//Get Himax IC Type / FW information / Calculate the point number
+	if (himax_check_chip_version(ts->client) == false) {
+		E("Himax chip doesn NOT EXIST");
+		goto err_ic_package_failed;
+	}
+	if (himax_ic_package_check(ts->client) == false) {
+		E("Himax chip doesn NOT EXIST");
+		goto err_ic_package_failed;
+	}
+
+	if (pdata->virtual_key)
+		ts->button = pdata->virtual_key;
+#ifdef  HX_TP_PROC_FLASH_DUMP
+	ts->flash_wq = create_singlethread_workqueue("himax_flash_wq");
+	if (!ts->flash_wq)
+	{
+		E("%s: create flash workqueue failed\n", __func__);
+		err = -ENOMEM;
+		goto err_create_wq_failed;
+	}
+
+	INIT_WORK(&ts->flash_work, himax_ts_flash_work_func);
+
+	setSysOperation(0);
+	setFlashBuffer();
+#endif
+
+#ifdef  HX_TP_PROC_DIAG
+	ts->himax_diag_wq = create_singlethread_workqueue("himax_diag");
+	if (!ts->himax_diag_wq)
+	{
+		E("%s: create diag workqueue failed\n", __func__);
+		err = -ENOMEM;
+		goto err_create_wq_failed;
+	}
+	INIT_DELAYED_WORK(&ts->himax_diag_delay_wrok, himax_ts_diag_work_func);
+#endif
+
+himax_read_FW_ver(client);
+
+#ifdef HX_AUTO_UPDATE_FW
+	I(" %s in", __func__);
+	if(i_update_FW() == false)
+		I("NOT Have new FW=NOT UPDATE=\n");
+	else
+		I("Have new FW=UPDATE=\n");
+#endif
+
+	//Himax Power On and Load Config
+	if (himax_loadSensorConfig(client, pdata) < 0) {
+		E("%s: Load Sesnsor configuration failed, unload driver.\n", __func__);
+		goto err_detect_failed;
+	}
+
+	calculate_point_number();
+#ifdef HX_TP_PROC_DIAG
+	setXChannel(ic_data->HX_RX_NUM); // X channel
+	setYChannel(ic_data->HX_TX_NUM); // Y channel
+
+	setMutualBuffer();
+	setMutualNewBuffer();
+	setMutualOldBuffer();
+	if (getMutualBuffer() == NULL) {
+		E("%s: mutual buffer allocate fail failed\n", __func__);
+		return;
+	}
+#ifdef HX_TP_PROC_2T2R
+	if(Is_2T2R){
+		setXChannel_2(ic_data->HX_RX_NUM_2); // X channel
+		setYChannel_2(ic_data->HX_TX_NUM_2); // Y channel
+
+		setMutualBuffer_2();
+
+		if (getMutualBuffer_2() == NULL) {
+			E("%s: mutual buffer 2 allocate fail failed\n", __func__);
+			return;
+		}
+	}
+#endif
+#endif
+#ifdef CONFIG_OF
+	ts->power = pdata->power;
+#endif
+	ts->pdata = pdata;
+
+	ts->x_channel = ic_data->HX_RX_NUM;
+	ts->y_channel = ic_data->HX_TX_NUM;
+	ts->nFinger_support = ic_data->HX_MAX_PT;
+	//calculate the i2c data size
+	calcDataSize(ts->nFinger_support);
+	I("%s: calcDataSize complete\n", __func__);
+#ifdef CONFIG_OF
+	ts->pdata->abs_pressure_min = 0;
+	ts->pdata->abs_pressure_max = 200;
+	ts->pdata->abs_width_min = 0;
+	ts->pdata->abs_width_max = 200;
+	pdata->cable_config[0] = 0x90;
+	pdata->cable_config[1] = 0x00;
+#endif
+	ts->suspended = false;
+#if defined(HX_USB_DETECT)||defined(HX_USB_DETECT2)
+	ts->usb_connected = 0x00;
+	ts->cable_config = pdata->cable_config;
+#endif
+	ts->protocol_type = pdata->protocol_type;
+	I("%s: Use Protocol Type %c\n", __func__,
+	ts->protocol_type == PROTOCOL_TYPE_A ? 'A' : 'B');
+
+	ret = himax_input_register(ts);
+	if (ret) {
+		E("%s: Unable to register %s input device\n",
+			__func__, ts->input_dev->name);
+		goto err_input_register_device_failed;
+	}
+#ifdef HX_SMART_WAKEUP
+	ts->SMWP_enable=0;
+	wake_lock_init(&ts->ts_SMWP_wake_lock, WAKE_LOCK_SUSPEND, HIMAX_common_NAME);
+
+	ts->himax_smwp_wq = create_singlethread_workqueue("HMX_SMWP_WORK");
+	if (!ts->himax_smwp_wq) {
+		E(" allocate himax_smwp_wq failed\n");
+		err = -ENOMEM;
+		goto err_smwp_wq_failed;
+	}
+	INIT_DELAYED_WORK(&ts->smwp_work, himax_SMWP_work);
+#endif
+#ifdef HX_HIGH_SENSE
+	ts->HSEN_enable=0;
+	ts->himax_hsen_wq = create_singlethread_workqueue("HMX_HSEN_WORK");
+	if (!ts->himax_hsen_wq) {
+		E(" allocate himax_hsen_wq failed\n");
+		err = -ENOMEM;
+		goto err_hsen_wq_failed;
+	}
+	INIT_DELAYED_WORK(&ts->hsen_work, himax_HSEN_func);
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG)
+	himax_touch_proc_init();
+#endif
+
+#if defined(HX_USB_DETECT)
+	if (ts->cable_config)
+		cable_detect_register_notifier(&himax_cable_status_handler);
+#endif
+
+	err = himax_ts_register_interrupt(ts->client);
+	if (err)
+		goto err_register_interrupt_failed;
+	return;
+
+err_register_interrupt_failed:
+#ifdef HX_HIGH_SENSE
+err_hsen_wq_failed:
+#endif
+#ifdef HX_SMART_WAKEUP
+err_smwp_wq_failed:
+	wake_lock_destroy(&ts->ts_SMWP_wake_lock);
+#endif
+err_input_register_device_failed:
+	input_free_device(ts->input_dev);
+err_detect_failed:
+#ifdef  HX_TP_PROC_FLASH_DUMP
+err_create_wq_failed:
+#endif
+err_ic_package_failed:
+
+return;
+}
+
+int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	int err = 0;
+	struct himax_ts_data *ts;
+	struct himax_i2c_platform_data *pdata;
+
+	//Check I2C functionality
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		E("%s: i2c check functionality error\n", __func__);
+		err = -ENODEV;
+		goto err_check_functionality_failed;
+	}
+
+	ts = kzalloc(sizeof(struct himax_ts_data), GFP_KERNEL);
+	if (ts == NULL) {
+		E("%s: allocate himax_ts_data failed\n", __func__);
+		err = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+
+	i2c_set_clientdata(client, ts);
+	ts->client = client;
+	ts->dev = &client->dev;
+
+	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+	if (pdata == NULL) { /*Allocate Platform data space*/
+		err = -ENOMEM;
+			goto err_dt_platform_data_fail;
+	}
+
+	ic_data = kzalloc(sizeof(*ic_data), GFP_KERNEL);
+	if (ic_data == NULL) { /*Allocate IC data space*/
+		err = -ENOMEM;
+			goto err_dt_ic_data_fail;
+	}
+
+#ifdef CONFIG_OF
+	if (client->dev.of_node) { /*DeviceTree Init Platform_data*/
+		err = himax_parse_dt(ts, pdata);
+		if (err < 0) {
+			I(" pdata is NULL for DT\n");
+			goto err_alloc_dt_pdata_failed;
+		}
+	}
+#endif
+
+#ifdef HX_RST_PIN_FUNC
+	ts->rst_gpio = pdata->gpio_reset;
+#endif
+
+himax_gpio_power_config(ts->client, pdata);
+
+	err = himax_ts_pinctrl_init(ts);
+	if (err || ts->ts_pinctrl == NULL) {
+		E(" Pinctrl init failed\n");
+	}
+
+#ifndef CONFIG_OF
+	if (pdata->power) {
+		err = pdata->power(1);
+		if (err < 0) {
+			E("%s: power on failed\n", __func__);
+			goto err_power_failed;
+		}
+	}
+#endif
+	ts->pdata = pdata;
+	private_ts = ts;
+
+	mutex_init(&ts->fb_mutex);
+	/* ts initialization is deferred till FB_UNBLACK event;
+	 * probe is considered pending till then.*/
+	ts->probe_done = false;
+#ifdef CONFIG_FB
+	err = himax_fb_register(ts);
+	if (err) {
+		E("Falied to register fb notifier\n");
+		err = -ENOMEM;
+		goto err_fb_notif_wq_create;
+	}
+#endif
+
+    return 0;
+
+#ifdef CONFIG_FB
+err_fb_notif_wq_create:
+#endif
+#ifdef CONFIG_OF
+err_alloc_dt_pdata_failed:
+#else
+err_power_failed:
+err_get_platform_data_fail:
+#endif
+	if (ts->ts_pinctrl) {
+		if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) {
+			devm_pinctrl_put(ts->ts_pinctrl);
+			ts->ts_pinctrl = NULL;
+		} else {
+			err = pinctrl_select_state(ts->ts_pinctrl,
+					ts->pinctrl_state_release);
+			if (err)
+				E("failed to select relase pinctrl state %d\n",
+					err);
+		}
+	}
+	kfree(ic_data);
+
+err_dt_ic_data_fail:
+	kfree(pdata);
+
+err_dt_platform_data_fail:
+	kfree(ts);
+
+err_alloc_data_failed:
+
+err_check_functionality_failed:
+	probe_fail_flag = 1;
+	return err;
+
+}
+
+int himax_chip_common_remove(struct i2c_client *client)
+{
+	struct himax_ts_data *ts = i2c_get_clientdata(client);
+	int ret;
+#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG)
+	himax_touch_proc_deinit();
+#endif
+#ifdef CONFIG_FB
+	if (fb_unregister_client(&ts->fb_notif))
+		dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n");
+#endif
+
+	if (!ts->use_irq)
+		hrtimer_cancel(&ts->timer);
+
+	destroy_workqueue(ts->himax_wq);
+
+	if (ts->protocol_type == PROTOCOL_TYPE_B)
+		input_mt_destroy_slots(ts->input_dev);
+
+	input_unregister_device(ts->input_dev);
+
+	if (ts->ts_pinctrl) {
+		if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) {
+			devm_pinctrl_put(ts->ts_pinctrl);
+			ts->ts_pinctrl = NULL;
+		} else {
+			ret = pinctrl_select_state(ts->ts_pinctrl,
+					ts->pinctrl_state_release);
+			if (ret)
+				E("failed to select relase pinctrl state %d\n",
+					ret);
+		}
+	}
+#ifdef HX_SMART_WAKEUP
+		wake_lock_destroy(&ts->ts_SMWP_wake_lock);
+#endif
+	kfree(ts);
+
+	return 0;
+
+}
+
+int himax_chip_common_suspend(struct himax_ts_data *ts)
+{
+	int ret;
+
+	if(ts->suspended)
+	{
+		I("%s: Already suspended. Skipped. \n", __func__);
+		return 0;
+	}
+	else
+	{
+		ts->suspended = true;
+		I("%s: enter \n", __func__);
+	}
+
+#ifdef HX_TP_PROC_FLASH_DUMP
+	if (getFlashDumpGoing())
+	{
+		I("[himax] %s: Flash dump is going, reject suspend\n",__func__);
+		return 0;
+	}
+#endif
+#ifdef HX_TP_PROC_HITOUCH
+	if(hitouch_is_connect)
+	{
+		I("[himax] %s: Hitouch connect, reject suspend\n",__func__);
+		return 0;
+	}
+#endif
+#ifdef HX_SMART_WAKEUP
+	if(ts->SMWP_enable)
+	{
+		atomic_set(&ts->suspend_mode, 1);
+		ts->pre_finger_mask = 0;
+		FAKE_POWER_KEY_SEND=false;
+		I("[himax] %s: SMART_WAKEUP enable, reject suspend\n",__func__);
+		return 0;
+	}
+#endif
+#ifdef HX_ESD_WORKAROUND
+	ESD_00_counter = 0;
+	ESD_00_Flag = 0;
+#endif
+	if (!ts->use_irq) {
+		ret = cancel_work_sync(&ts->work);
+		if (ret)
+			himax_int_enable(ts->client->irq,1);
+	}
+
+	//ts->first_pressed = 0;
+	atomic_set(&ts->suspend_mode, 1);
+	ts->pre_finger_mask = 0;
+
+	if (ts->ts_pinctrl) {
+		ret = pinctrl_select_state(ts->ts_pinctrl,
+				ts->pinctrl_state_suspend);
+		if (ret < 0) {
+			E("Failed to get idle pinctrl state %d\n", ret);
+		}
+	}
+
+	if (ts->pdata->powerOff3V3 && ts->pdata->power)
+		ts->pdata->power(0);
+
+	return 0;
+}
+
+int himax_chip_common_resume(struct himax_ts_data *ts)
+{
+	int retval;
+
+	I("%s: enter \n", __func__);
+
+	if (ts->pdata->powerOff3V3 && ts->pdata->power)
+		ts->pdata->power(1);
+		
+		
+		/*************************************/
+		if (ts->protocol_type == PROTOCOL_TYPE_A)
+		input_mt_sync(ts->input_dev);
+		input_report_key(ts->input_dev, BTN_TOUCH, 0);
+		input_sync(ts->input_dev);
+		/*************************************/
+		
+		
+	if (ts->ts_pinctrl) {
+		retval = pinctrl_select_state(ts->ts_pinctrl,
+				ts->pinctrl_state_active);
+		if (retval < 0) {
+			E("Cannot get default pinctrl state %d\n", retval);
+			goto err_pinctrl_select_resume;
+		}
+	}
+
+	atomic_set(&ts->suspend_mode, 0);
+
+	himax_int_enable(ts->client->irq,1);
+
+	ts->suspended = false;
+#if defined(HX_USB_DETECT2)
+	ts->usb_connected = 0x00;
+	himax_cable_detect_func();
+#endif
+#ifdef HX_SMART_WAKEUP
+	queue_delayed_work(ts->himax_smwp_wq, &ts->smwp_work, msecs_to_jiffies(1000));
+#endif
+#ifdef HX_HIGH_SENSE
+	queue_delayed_work(ts->himax_hsen_wq, &ts->hsen_work, msecs_to_jiffies(1000));
+#endif
+	return 0;
+err_pinctrl_select_resume:
+	if (ts->pdata->powerOff3V3 && ts->pdata->power)
+		ts->pdata->power(0);
+	return retval;
+}
+
diff --git a/drivers/input/touchscreen/hxchipset/himax_common.h b/drivers/input/touchscreen/hxchipset/himax_common.h
new file mode 100644
index 0000000..27ce9aa
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/himax_common.h
@@ -0,0 +1,395 @@
+/* Himax Android Driver Sample Code for Himax chipset
+*
+* Copyright (C) 2015 Himax Corporation.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+*/
+
+#ifndef HIMAX_COMMON_H
+#define HIMAX_COMMON_H
+
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/async.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/input/mt.h>
+#include <linux/firmware.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include "himax_platform.h"
+
+#if defined(CONFIG_FB)
+#include <linux/notifier.h>
+#include <linux/fb.h>
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+#include <linux/earlysuspend.h>
+#endif
+
+#ifdef CONFIG_OF
+#include <linux/of_gpio.h>
+#endif
+#define HIMAX_DRIVER_VER "0.2.4.0"
+
+#define FLASH_DUMP_FILE "/data/user/Flash_Dump.bin"
+#define DIAG_COORDINATE_FILE "/sdcard/Coordinate_Dump.csv"
+
+#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG)
+
+#define HX_TP_PROC_DIAG
+#define HX_TP_PROC_REGISTER
+#define HX_TP_PROC_DEBUG
+#define HX_TP_PROC_FLASH_DUMP
+#define HX_TP_PROC_SELF_TEST
+#define HX_TP_PROC_RESET
+#define HX_TP_PROC_SENSE_ON_OFF
+//#define HX_TP_PROC_2T2R
+
+int himax_touch_proc_init(void);
+void himax_touch_proc_deinit(void);
+#endif
+
+//===========Himax Option function=============
+//#define HX_RST_PIN_FUNC
+//#define HX_AUTO_UPDATE_FW
+//#define HX_HIGH_SENSE
+//#define HX_SMART_WAKEUP
+//#define HX_USB_DETECT
+//#define HX_ESD_WORKAROUND
+//#define HX_USB_DETECT2
+
+//#define HX_EN_SEL_BUTTON		       // Support Self Virtual key		,default is close
+#define HX_EN_MUT_BUTTON		    // Support Mutual Virtual Key	,default is close
+
+#define HX_KEY_MAX_COUNT             4			
+#define DEFAULT_RETRY_CNT            3
+
+#define HX_VKEY_0   KEY_BACK
+#define HX_VKEY_1   KEY_HOME
+#define HX_VKEY_2   KEY_RESERVED
+#define HX_VKEY_3   KEY_RESERVED
+#define HX_KEY_ARRAY    {HX_VKEY_0, HX_VKEY_1, HX_VKEY_2, HX_VKEY_3}
+
+#define SHIFTBITS 5
+//#define FLASH_SIZE 131072
+#define  FW_SIZE_60k 	61440
+#define  FW_SIZE_64k 	65536
+#define  FW_SIZE_124k 	126976
+#define  FW_SIZE_128k 	131072
+
+struct himax_ic_data {
+	int vendor_fw_ver;
+	int vendor_config_ver;
+	int vendor_sensor_id;
+	int		HX_RX_NUM;
+	int		HX_TX_NUM;
+	int		HX_BT_NUM;
+	int		HX_X_RES;
+	int		HX_Y_RES;
+	int		HX_MAX_PT;
+	bool	HX_XY_REVERSE;
+	bool	HX_INT_IS_EDGE;
+#ifdef HX_TP_PROC_2T2R
+	int HX_RX_NUM_2;
+	int HX_TX_NUM_2;
+#endif
+};
+
+struct himax_virtual_key {
+	int index;
+	int keycode;
+	int x_range_min;
+	int x_range_max;
+	int y_range_min;
+	int y_range_max;
+};
+
+struct himax_config {
+	uint8_t  default_cfg;
+	uint8_t  sensor_id;
+	uint8_t  fw_ver;
+	uint16_t length;
+	uint32_t tw_x_min;
+	uint32_t tw_x_max;
+	uint32_t tw_y_min;
+	uint32_t tw_y_max;
+	uint32_t pl_x_min;
+	uint32_t pl_x_max;
+	uint32_t pl_y_min;
+	uint32_t pl_y_max;
+	uint8_t c1[11];
+	uint8_t c2[11];
+	uint8_t c3[11];
+	uint8_t c4[11];
+	uint8_t c5[11];
+	uint8_t c6[11];
+	uint8_t c7[11];
+	uint8_t c8[11];
+	uint8_t c9[11];
+	uint8_t c10[11];
+	uint8_t c11[11];
+	uint8_t c12[11];
+	uint8_t c13[11];
+	uint8_t c14[11];
+	uint8_t c15[11];
+	uint8_t c16[11];
+	uint8_t c17[11];
+	uint8_t c18[17];
+	uint8_t c19[15];
+	uint8_t c20[5];
+	uint8_t c21[11];
+	uint8_t c22[4];
+	uint8_t c23[3];
+	uint8_t c24[3];
+	uint8_t c25[4];
+	uint8_t c26[2];
+	uint8_t c27[2];
+	uint8_t c28[2];
+	uint8_t c29[2];
+	uint8_t c30[2];
+	uint8_t c31[2];
+	uint8_t c32[2];
+	uint8_t c33[2];
+	uint8_t c34[2];
+	uint8_t c35[3];
+	uint8_t c36[5];
+	uint8_t c37[5];
+	uint8_t c38[9];
+	uint8_t c39[14];
+	uint8_t c40[159];
+	uint8_t c41[99];
+};
+
+struct himax_ts_data {
+	bool suspended;
+	bool probe_done;
+	struct mutex fb_mutex;
+	atomic_t suspend_mode;
+	uint8_t x_channel;
+	uint8_t y_channel;
+	uint8_t useScreenRes;
+	uint8_t diag_command;
+	
+	uint8_t protocol_type;
+	uint8_t first_pressed;
+	uint8_t coord_data_size;
+	uint8_t area_data_size;
+	uint8_t raw_data_frame_size;
+	uint8_t raw_data_nframes;
+	uint8_t nFinger_support;
+	uint8_t irq_enabled;
+	uint8_t diag_self[50];
+	
+	uint16_t finger_pressed;
+	uint16_t last_slot;
+	uint16_t pre_finger_mask;
+
+	uint32_t debug_log_level;
+	uint32_t widthFactor;
+	uint32_t heightFactor;
+	uint32_t tw_x_min;
+	uint32_t tw_x_max;
+	uint32_t tw_y_min;
+	uint32_t tw_y_max;
+	uint32_t pl_x_min;
+	uint32_t pl_x_max;
+	uint32_t pl_y_min;
+	uint32_t pl_y_max;
+	
+	int use_irq;
+	int (*power)(int on);
+	int pre_finger_data[10][2];
+	
+	struct device *dev;
+	struct workqueue_struct *himax_wq;
+	struct work_struct work;
+	struct input_dev *input_dev;
+	struct hrtimer timer;
+	struct i2c_client *client;
+	struct himax_i2c_platform_data *pdata;	
+	struct himax_virtual_key *button;
+	
+#if defined(CONFIG_FB)
+	struct notifier_block fb_notif;
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+	struct early_suspend early_suspend;
+#endif
+
+#ifdef HX_TP_PROC_FLASH_DUMP
+	struct workqueue_struct 			*flash_wq;
+	struct work_struct 					flash_work;
+#endif
+
+#ifdef HX_RST_PIN_FUNC
+	int rst_gpio;
+#endif
+
+#ifdef HX_TP_PROC_DIAG
+	struct workqueue_struct *himax_diag_wq;
+	struct delayed_work himax_diag_delay_wrok;
+#endif
+#ifdef HX_SMART_WAKEUP
+	uint8_t SMWP_enable;
+	uint8_t gesture_cust_en[16];
+	struct wake_lock ts_SMWP_wake_lock;
+	struct workqueue_struct *himax_smwp_wq;
+	struct delayed_work smwp_work;
+#endif
+
+#ifdef HX_HIGH_SENSE
+	uint8_t HSEN_enable;
+	struct workqueue_struct *himax_hsen_wq;
+	struct delayed_work hsen_work;
+#endif
+
+#if defined(HX_USB_DETECT)||defined(HX_USB_DETECT2)
+	uint8_t usb_connected;
+	uint8_t *cable_config;
+#endif
+
+	/* pinctrl data */
+	struct pinctrl *ts_pinctrl;
+	struct pinctrl_state *pinctrl_state_active;
+	struct pinctrl_state *pinctrl_state_suspend;
+	struct pinctrl_state *pinctrl_state_release;
+};
+
+#define HX_CMD_NOP					 0x00	
+#define HX_CMD_SETMICROOFF			 0x35	
+#define HX_CMD_SETROMRDY			 0x36	
+#define HX_CMD_TSSLPIN				 0x80	
+#define HX_CMD_TSSLPOUT 			 0x81	
+#define HX_CMD_TSSOFF				 0x82	
+#define HX_CMD_TSSON				 0x83	
+#define HX_CMD_ROE					 0x85	
+#define HX_CMD_RAE					 0x86	
+#define HX_CMD_RLE					 0x87	
+#define HX_CMD_CLRES				 0x88	
+#define HX_CMD_TSSWRESET			 0x9E	
+#define HX_CMD_SETDEEPSTB			 0xD7	
+#define HX_CMD_SET_CACHE_FUN		 0xDD	
+#define HX_CMD_SETIDLE				 0xF2	
+#define HX_CMD_SETIDLEDELAY 		 0xF3	
+#define HX_CMD_SELFTEST_BUFFER		 0x8D	
+#define HX_CMD_MANUALMODE			 0x42
+#define HX_CMD_FLASH_ENABLE 		 0x43
+#define HX_CMD_FLASH_SET_ADDRESS	 0x44
+#define HX_CMD_FLASH_WRITE_REGISTER  0x45
+#define HX_CMD_FLASH_SET_COMMAND	 0x47
+#define HX_CMD_FLASH_WRITE_BUFFER	 0x48
+#define HX_CMD_FLASH_PAGE_ERASE 	 0x4D
+#define HX_CMD_FLASH_SECTOR_ERASE	 0x4E
+#define HX_CMD_CB					 0xCB
+#define HX_CMD_EA					 0xEA
+#define HX_CMD_4A					 0x4A
+#define HX_CMD_4F					 0x4F
+#define HX_CMD_B9					 0xB9
+#define HX_CMD_76					 0x76
+
+enum input_protocol_type {
+	PROTOCOL_TYPE_A	= 0x00,
+	PROTOCOL_TYPE_B	= 0x01,
+};
+
+#ifdef HX_HIGH_SENSE
+void himax_set_HSEN_func(struct i2c_client *client,uint8_t HSEN_enable);
+#endif
+
+#ifdef HX_SMART_WAKEUP
+#define GEST_PTLG_ID_LEN	(4)
+#define GEST_PTLG_HDR_LEN	(4)
+#define GEST_PTLG_HDR_ID1	(0xCC)
+#define GEST_PTLG_HDR_ID2	(0x44)
+#define GEST_PT_MAX_NUM 	(128)
+
+#ifdef HX_GESTURE_TRACK
+static int gest_pt_cnt;
+static int gest_pt_x[GEST_PT_MAX_NUM];
+static int gest_pt_y[GEST_PT_MAX_NUM];
+static int gest_start_x,gest_start_y,gest_end_x,gest_end_y;
+static int gest_width,gest_height,gest_mid_x,gest_mid_y;
+static int gn_gesture_coor[16];
+#endif
+
+void himax_set_SMWP_func(struct i2c_client *client,uint8_t SMWP_enable);
+extern bool FAKE_POWER_KEY_SEND;
+
+	enum gesture_event_type {
+		EV_GESTURE_01 = 0x01,
+		EV_GESTURE_02,
+		EV_GESTURE_03,
+		EV_GESTURE_04,
+		EV_GESTURE_05,
+		EV_GESTURE_06,
+		EV_GESTURE_07,
+		EV_GESTURE_08,
+		EV_GESTURE_09,
+		EV_GESTURE_10,
+		EV_GESTURE_11,
+		EV_GESTURE_12,
+		EV_GESTURE_13,
+		EV_GESTURE_14,
+		EV_GESTURE_15,
+		EV_GESTURE_PWR = 0x80,
+	};
+
+#define KEY_CUST_01 251
+#define KEY_CUST_02 252
+#define KEY_CUST_03 253
+#define KEY_CUST_04 254
+#define KEY_CUST_05 255
+#define KEY_CUST_06 256
+#define KEY_CUST_07 257
+#define KEY_CUST_08 258
+#define KEY_CUST_09 259
+#define KEY_CUST_10 260
+#define KEY_CUST_11 261
+#define KEY_CUST_12 262
+#define KEY_CUST_13 263
+#define KEY_CUST_14 264
+#define KEY_CUST_15 265
+#endif
+
+#ifdef HX_ESD_WORKAROUND
+	extern	u8 HX_ESD_RESET_ACTIVATE;
+#endif
+
+extern int irq_enable_count;
+
+#ifdef QCT
+irqreturn_t himax_ts_thread(int irq, void *ptr);
+int himax_input_register(struct himax_ts_data *ts);
+#endif
+
+extern int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_id *id);
+extern int himax_chip_common_remove(struct i2c_client *client);
+extern int himax_chip_common_suspend(struct himax_ts_data *ts);
+extern int himax_chip_common_resume(struct himax_ts_data *ts);
+int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_data *pdata);
+
+#ifdef HX_USB_DETECT2
+//extern kal_bool upmu_is_chr_det(void);
+void himax_cable_detect_func(void);
+#endif
+
+#endif
+
diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.c b/drivers/input/touchscreen/hxchipset/himax_debug.c
new file mode 100644
index 0000000..f8bee11
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/himax_debug.c
@@ -0,0 +1,2329 @@
+/* Himax Android Driver Sample Code for Himax chipset
+*
+* Copyright (C) 2015 Himax Corporation.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+*/
+
+#include "himax_debug.h"
+#include "himax_ic.h"
+
+//struct himax_debug_data* debug_data;
+
+extern struct himax_ic_data* ic_data;
+extern struct himax_ts_data *private_ts;
+extern unsigned char	IC_TYPE;
+extern unsigned char	IC_CHECKSUM;
+extern int himax_input_register(struct himax_ts_data *ts);
+#ifdef QCT
+extern irqreturn_t himax_ts_thread(int irq, void *ptr);
+#endif
+#ifdef MTK
+#ifdef CONFIG_OF_TOUCH
+extern irqreturn_t tpd_eint_interrupt_handler(int irq, void *desc);
+#else
+extern void tpd_eint_interrupt_handler(void);
+#endif
+#endif
+
+#ifdef HX_TP_PROC_DIAG
+#ifdef HX_TP_PROC_2T2R
+int	HX_RX_NUM_2			= 0;
+int	HX_TX_NUM_2			= 0;
+#endif
+int	touch_monitor_stop_flag		= 0;
+int	touch_monitor_stop_limit	= 5;
+uint8_t	g_diag_arr_num			= 0;
+#endif
+
+#ifdef HX_ESD_WORKAROUND
+u8 HX_ESD_RESET_ACTIVATE;
+#endif
+
+#ifdef HX_SMART_WAKEUP
+bool FAKE_POWER_KEY_SEND;
+#endif
+
+//=============================================================================================================
+//
+//	Segment : Himax PROC Debug Function
+//
+//=============================================================================================================
+#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG)
+
+static ssize_t himax_vendor_read(struct file *file, char *buf,
+	size_t len, loff_t *pos)
+{
+	ssize_t ret = 0;
+	char *temp_buf;
+
+	if(!HX_PROC_SEND_FLAG)
+	{
+		temp_buf = kzalloc(len, GFP_KERNEL);
+		if (!temp_buf) {
+			HX_PROC_SEND_FLAG=0;
+			return ret;
+		}
+
+		ret += snprintf(temp_buf, len, "%s_FW:%#x_CFG:%#x_SensorId:%#x\n", HIMAX_common_NAME,
+		ic_data->vendor_fw_ver, ic_data->vendor_config_ver, ic_data->vendor_sensor_id);
+		HX_PROC_SEND_FLAG=1;
+
+		if (copy_to_user(buf, temp_buf, len))
+		{
+			I("%s,here:%d\n", __func__, __LINE__);
+		}
+
+		kfree(temp_buf);
+	}
+	else
+		HX_PROC_SEND_FLAG=0;
+
+	return ret;
+}
+
+static const struct file_operations himax_proc_vendor_ops =
+{
+	.owner = THIS_MODULE,
+	.read = himax_vendor_read,
+};
+
+static ssize_t himax_attn_read(struct file *file, char *buf,
+	size_t len, loff_t *pos)
+{
+	ssize_t ret = 0;
+	struct himax_ts_data *ts_data;
+	char *temp_buf;
+
+	ts_data = private_ts;
+
+	if (!HX_PROC_SEND_FLAG) {
+		temp_buf = kzalloc(len, GFP_KERNEL);
+		if (!temp_buf) {
+			HX_PROC_SEND_FLAG=0;
+			return ret;
+		}
+		ret += snprintf(temp_buf, len, "attn = %x\n", himax_int_gpio_read(ts_data->pdata->gpio_irq));
+
+		if (copy_to_user(buf, temp_buf, len))
+		{
+			I("%s,here:%d\n", __func__, __LINE__);
+		}
+
+		kfree(temp_buf);
+		HX_PROC_SEND_FLAG = 1;
+	}
+	else
+		HX_PROC_SEND_FLAG=0;
+
+	return ret;
+}
+
+
+static const struct file_operations himax_proc_attn_ops =
+{
+	.owner = THIS_MODULE,
+	.read = himax_attn_read,
+};
+
+static ssize_t himax_int_en_read(struct file *file, char *buf,
+	size_t len, loff_t *pos)
+{
+	struct himax_ts_data *ts = private_ts;
+	size_t ret = 0;
+	char *temp_buf;
+
+	if (!HX_PROC_SEND_FLAG) {
+		temp_buf = kzalloc(len, GFP_KERNEL);
+		if (!temp_buf) {
+			HX_PROC_SEND_FLAG=0;
+			return ret;
+		}
+		ret += snprintf(temp_buf, len, "%d ", ts->irq_enabled);
+		ret += snprintf(temp_buf+ret, len-ret, "\n");
+
+		if (copy_to_user(buf, temp_buf, len))
+		{
+			I("%s,here:%d\n", __func__, __LINE__);
+		}
+
+		kfree(temp_buf);
+		HX_PROC_SEND_FLAG = 1;
+	}
+	else
+		HX_PROC_SEND_FLAG=0;
+	return ret;
+}
+
+static ssize_t himax_int_en_write(struct file *file, const char *buff,
+	size_t len, loff_t *pos)
+{
+	struct himax_ts_data *ts = private_ts;
+	char buf_tmp[12]= {0};
+	int value, ret=0;
+
+	if (len >= 12)
+	{
+		I("%s: no command exceeds 12 chars.\n", __func__);
+		return -EFAULT;
+	}
+	if (copy_from_user(buf_tmp, buff, len))
+	{
+		return -EFAULT;
+	}
+
+	if (buf_tmp[0] == '0')
+		value = false;
+	else if (buf_tmp[0] == '1')
+		value = true;
+	else
+		return -EINVAL;
+
+	if (value) {
+		if(ic_data->HX_INT_IS_EDGE)
+		{
+#ifdef MTK
+#ifdef CONFIG_OF_TOUCH
+			himax_int_enable(ts->client->irq,1);
+#else
+			//mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_TYPE);
+			//mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN);
+			mt_eint_registration(ts->client->irq, EINTF_TRIGGER_FALLING, tpd_eint_interrupt_handler, 1);
+#endif
+#endif
+#ifdef QCT
+			ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread,
+					IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ts->client->name, ts);
+#endif
+		}
+		else
+		{
+#ifdef MTK
+#ifdef CONFIG_OF_TOUCH
+			himax_int_enable(ts->client->irq,1);
+#else
+			//mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_TYPE);
+			//mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN);
+			mt_eint_registration(ts->client->irq, EINTF_TRIGGER_LOW, tpd_eint_interrupt_handler, 1);
+#endif
+#endif
+#ifdef QCT
+			ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread,
+					IRQF_TRIGGER_LOW | IRQF_ONESHOT, ts->client->name, ts);
+#endif
+		}
+		if (ret == 0) {
+			ts->irq_enabled = 1;
+			irq_enable_count = 1;
+		}
+	} else {
+		himax_int_enable(ts->client->irq,0);
+		free_irq(ts->client->irq, ts);
+		ts->irq_enabled = 0;
+	}
+
+	return len;
+}
+
+static const struct file_operations himax_proc_int_en_ops =
+{
+	.owner = THIS_MODULE,
+	.read = himax_int_en_read,
+	.write = himax_int_en_write,
+};
+
+static ssize_t himax_layout_read(struct file *file, char *buf,
+	size_t len, loff_t *pos)
+{
+	struct himax_ts_data *ts = private_ts;
+	size_t ret = 0;
+	char *temp_buf;
+
+	if (!HX_PROC_SEND_FLAG) {
+		temp_buf = kzalloc(len, GFP_KERNEL);
+		if (!temp_buf) {
+			HX_PROC_SEND_FLAG=0;
+			return ret;
+		}
+		ret += snprintf(temp_buf, len,  "%d ", ts->pdata->abs_x_min);
+		ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_x_max);
+		ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_y_min);
+		ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_y_max);
+		ret += snprintf(temp_buf+ret, len-ret, "\n");
+
+		if (copy_to_user(buf, temp_buf, len))
+		{
+			I("%s,here:%d\n", __func__, __LINE__);
+		}
+
+		kfree(temp_buf);
+		HX_PROC_SEND_FLAG = 1;
+	}
+	else
+		HX_PROC_SEND_FLAG=0;
+
+	return ret;
+}
+
+static ssize_t himax_layout_write(struct file *file, const char *buff,
+	size_t len, loff_t *pos)
+{
+	struct himax_ts_data *ts = private_ts;
+	char buf_tmp[5];
+	int i = 0, j = 0, k = 0, ret;
+	unsigned long value;
+	int layout[4] = {0};
+	char buf[80] = {0};
+
+	if (len >= 80)
+	{
+		I("%s: no command exceeds 80 chars.\n", __func__);
+		return -EFAULT;
+	}
+	if (copy_from_user(buf, buff, len))
+	{
+		return -EFAULT;
+	}
+
+	for (i = 0; i < 20; i++) {
+		if (buf[i] == ',' || buf[i] == '\n') {
+			memset(buf_tmp, 0x0, sizeof(buf_tmp));
+			if (i - j <= 5)
+				memcpy(buf_tmp, buf + j, i - j);
+			else {
+				I("buffer size is over 5 char\n");
+				return len;
+			}
+			j = i + 1;
+			if (k < 4) {
+				ret = kstrtoul(buf_tmp, 10, &value);
+				layout[k++] = value;
+			}
+		}
+	}
+	if (k == 4) {
+		ts->pdata->abs_x_min=layout[0];
+		ts->pdata->abs_x_max=layout[1];
+		ts->pdata->abs_y_min=layout[2];
+		ts->pdata->abs_y_max=layout[3];
+		I("%d, %d, %d, %d\n",ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max);
+		input_unregister_device(ts->input_dev);
+		himax_input_register(ts);
+	} else
+		I("ERR@%d, %d, %d, %d\n",ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max);
+	return len;
+}
+
+static const struct file_operations himax_proc_layout_ops =
+{
+	.owner = THIS_MODULE,
+	.read = himax_layout_read,
+	.write = himax_layout_write,
+};
+
+static ssize_t himax_debug_level_read(struct file *file, char *buf,
+	size_t len, loff_t *pos)
+{
+	struct himax_ts_data *ts_data;
+	size_t ret = 0;
+	char *temp_buf;
+	ts_data = private_ts;
+
+	if (!HX_PROC_SEND_FLAG) {
+		temp_buf = kzalloc(len, GFP_KERNEL);
+		if (!temp_buf) {
+			HX_PROC_SEND_FLAG=0;
+			return ret;
+		}
+		ret += snprintf(temp_buf, len, "%d\n", ts_data->debug_log_level);
+
+		if (copy_to_user(buf, temp_buf, len))
+		{
+			I("%s,here:%d\n", __func__, __LINE__);
+		}
+
+		kfree(temp_buf);
+		HX_PROC_SEND_FLAG = 1;
+	}
+	else
+		HX_PROC_SEND_FLAG=0;
+
+	return ret;
+}
+
+static ssize_t himax_debug_level_write(struct file *file, const char *buff,
+	size_t len, loff_t *pos)
+{
+	struct himax_ts_data *ts;
+	char buf_tmp[11];
+	int i;
+	ts = private_ts;
+
+	if (len >= 12)
+	{
+		I("%s: no command exceeds 12 chars.\n", __func__);
+		return -EFAULT;
+	}
+	if (copy_from_user(buf_tmp, buff, len))
+	{
+		return -EFAULT;
+	}
+
+	ts->debug_log_level = 0;
+	for(i=0; i<len-1; i++)
+	{
+		if( buf_tmp[i]>='0' && buf_tmp[i]<='9' )
+			ts->debug_log_level |= (buf_tmp[i]-'0');
+		else if( buf_tmp[i]>='A' && buf_tmp[i]<='F' )
+			ts->debug_log_level |= (buf_tmp[i]-'A'+10);
+		else if( buf_tmp[i]>='a' && buf_tmp[i]<='f' )
+			ts->debug_log_level |= (buf_tmp[i]-'a'+10);
+
+		if(i!=len-2)
+			ts->debug_log_level <<= 4;
+	}
+
+	if (ts->debug_log_level & BIT(3)) {
+		if (ts->pdata->screenWidth > 0 && ts->pdata->screenHeight > 0 &&
+		 (ts->pdata->abs_x_max - ts->pdata->abs_x_min) > 0 &&
+		 (ts->pdata->abs_y_max - ts->pdata->abs_y_min) > 0) {
+			ts->widthFactor = (ts->pdata->screenWidth << SHIFTBITS)/(ts->pdata->abs_x_max - ts->pdata->abs_x_min);
+			ts->heightFactor = (ts->pdata->screenHeight << SHIFTBITS)/(ts->pdata->abs_y_max - ts->pdata->abs_y_min);
+			if (ts->widthFactor > 0 && ts->heightFactor > 0)
+				ts->useScreenRes = 1;
+			else {
+				ts->heightFactor = 0;
+				ts->widthFactor = 0;
+				ts->useScreenRes = 0;
+			}
+		} else
+			I("Enable finger debug with raw position mode!\n");
+	} else {
+		ts->useScreenRes = 0;
+		ts->widthFactor = 0;
+		ts->heightFactor = 0;
+	}
+
+	return len;
+}
+
+static const struct file_operations himax_proc_debug_level_ops =
+{
+	.owner = THIS_MODULE,
+	.read = himax_debug_level_read,
+	.write = himax_debug_level_write,
+};
+
+#ifdef HX_TP_PROC_REGISTER
+static ssize_t himax_proc_register_read(struct file *file, char *buf,
+	size_t len, loff_t *pos)
+{
+	int ret = 0;
+	uint16_t loop_i;
+	uint8_t data[128];
+	char *temp_buf;
+
+	memset(data, 0x00, sizeof(data));
+
+	I("himax_register_show: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]);
+	if(!HX_PROC_SEND_FLAG)
+	{
+		temp_buf = kzalloc(len, GFP_KERNEL);
+		if (!temp_buf) {
+			HX_PROC_SEND_FLAG=0;
+			return ret;
+		}
+		himax_register_read(private_ts->client, register_command, 1, data);
+
+		ret += snprintf(temp_buf, len, "command:  %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]);
+
+		for (loop_i = 0; loop_i < 128; loop_i++) {
+			ret += snprintf(temp_buf+ret, len-ret, "0x%2.2X ", data[loop_i]);
+			if ((loop_i % 16) == 15)
+				ret += snprintf(temp_buf+ret, len-ret, "\n");
+		}
+		ret += snprintf(temp_buf+ret, len-ret, "\n");
+		HX_PROC_SEND_FLAG=1;
+
+		if (copy_to_user(buf, temp_buf, len))
+		{
+			I("%s,here:%d\n", __func__, __LINE__);
+		}
+
+		kfree(temp_buf);
+	}
+	else
+		HX_PROC_SEND_FLAG=0;
+	return ret;
+}
+
+static ssize_t himax_proc_register_write(struct file *file, const char *buff,
+	size_t len, loff_t *pos)
+{
+	char buf_tmp[16], length = 0;
+	unsigned long result    = 0;
+	uint8_t loop_i          = 0;
+	uint16_t base           = 5;
+	uint8_t write_da[128];
+	char buf[80] = {0};
+
+	if (len >= 80)
+	{
+		I("%s: no command exceeds 80 chars.\n", __func__);
+		return -EFAULT;
+	}
+	if (copy_from_user(buf, buff, len))
+	{
+		return -EFAULT;
+	}
+
+	memset(buf_tmp, 0x0, sizeof(buf_tmp));
+	memset(write_da, 0x0, sizeof(write_da));
+
+	I("himax %s \n",buf);
+
+	if ((buf[0] == 'r' || buf[0] == 'w') && buf[1] == ':') {
+
+		if (buf[2] == 'x') {
+			memcpy(buf_tmp, buf + 3, 8);
+			if (!kstrtoul(buf_tmp, 16, &result))
+				{
+					register_command[0] = (uint8_t)result;
+					register_command[1] = (uint8_t)(result >> 8);
+					register_command[2] = (uint8_t)(result >> 16);
+					register_command[3] = (uint8_t)(result >> 24);
+				}
+			base = 11;
+			I("CMD: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]);
+
+			for (loop_i = 0; loop_i < 128 && (base+10)<80; loop_i++) {
+				if (buf[base] == '\n') {
+					if (buf[0] == 'w') {
+						himax_register_write(private_ts->client, register_command, 1, write_da);
+						I("CMD: %x, %x, %x, %x, len=%d\n", write_da[0], write_da[1],write_da[2],write_da[3],length);
+					}
+					I("\n");
+					return len;
+				}
+				if (buf[base + 1] == 'x') {
+					buf_tmp[10] = '\n';
+					buf_tmp[11] = '\0';
+					memcpy(buf_tmp, buf + base + 2, 8);
+					if (!kstrtoul(buf_tmp, 16, &result)) {
+						write_da[loop_i] = (uint8_t)result;
+						write_da[loop_i+1] = (uint8_t)(result >> 8);
+						write_da[loop_i+2] = (uint8_t)(result >> 16);
+						write_da[loop_i+3] = (uint8_t)(result >> 24);
+					}
+					length+=4;
+				}
+				base += 10;
+			}
+		}
+	}
+	return len;
+}
+
+static const struct file_operations himax_proc_register_ops =
+{
+	.owner = THIS_MODULE,
+	.read = himax_proc_register_read,
+	.write = himax_proc_register_write,
+};
+#endif
+
+#ifdef HX_TP_PROC_DIAG
+int16_t *getMutualBuffer(void)
+{
+	return diag_mutual;
+}
+int16_t *getMutualNewBuffer(void)
+{
+	return diag_mutual_new;
+}
+int16_t *getMutualOldBuffer(void)
+{
+	return diag_mutual_old;
+}
+int16_t *getSelfBuffer(void)
+{
+	return &diag_self[0];
+}
+uint8_t getXChannel(void)
+{
+	return x_channel;
+}
+uint8_t getYChannel(void)
+{
+	return y_channel;
+}
+uint8_t getDiagCommand(void)
+{
+	return diag_command;
+}
+void setXChannel(uint8_t x)
+{
+	x_channel = x;
+}
+void setYChannel(uint8_t y)
+{
+	y_channel = y;
+}
+void setMutualBuffer(void)
+{
+	diag_mutual = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL);
+}
+void setMutualNewBuffer(void)
+{
+	diag_mutual_new = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL);
+}
+void setMutualOldBuffer(void)
+{
+	diag_mutual_old = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL);
+}
+
+#ifdef HX_TP_PROC_2T2R
+int16_t *getMutualBuffer_2(void)
+{
+	return diag_mutual_2;
+}
+uint8_t getXChannel_2(void)
+{
+	return x_channel_2;
+}
+uint8_t getYChannel_2(void)
+{
+	return y_channel_2;
+}
+void setXChannel_2(uint8_t x)
+{
+	x_channel_2 = x;
+}
+void setYChannel_2(uint8_t y)
+{
+	y_channel_2 = y;
+}
+void setMutualBuffer_2(void)
+{
+	diag_mutual_2 = kzalloc(x_channel_2 * y_channel_2 * sizeof(int16_t), GFP_KERNEL);
+}
+#endif
+
+static ssize_t himax_diag_arrange_write(struct file *file, const char *buff,
+	size_t len, loff_t *pos)
+{
+	//struct himax_ts_data *ts = private_ts;
+	char buf[80] = {0};
+
+	if (len >= 80)
+	{
+		I("%s: no command exceeds 80 chars.\n", __func__);
+		return -EFAULT;
+	}
+	if (copy_from_user(buf, buff, len))
+	{
+		return -EFAULT;
+	}
+
+	g_diag_arr_num = buf[0] - '0';
+	I("%s: g_diag_arr_num = %d \n", __func__,g_diag_arr_num);
+
+	return len;
+}
+
+static const struct file_operations himax_proc_diag_arrange_ops =
+{
+	.owner = THIS_MODULE,
+	.write = himax_diag_arrange_write,
+};
+
+static void himax_diag_arrange_print(struct seq_file *s, int i, int j, int transpose)
+{
+	if(transpose)
+		seq_printf(s, "%6d", diag_mutual[ j + i*x_channel]);
+	else
+		seq_printf(s, "%6d", diag_mutual[ i + j*x_channel]);
+}
+
+static void himax_diag_arrange_inloop(struct seq_file *s, int in_init,bool transpose, int j)
+{
+	int i;
+	int in_max = 0;
+
+	if(transpose)
+		in_max = y_channel;
+	else
+		in_max = x_channel;
+
+	if (in_init > 0)
+	{
+		for(i = in_init-1;i >= 0;i--)
+		{
+			himax_diag_arrange_print(s, i, j, transpose);
+		}
+	}
+	else
+	{
+		for (i = 0; i < in_max; i++)
+		{
+			himax_diag_arrange_print(s, i, j, transpose);
+		}
+	}
+}
+
+static void himax_diag_arrange_outloop(struct seq_file *s, int transpose, int out_init, int in_init)
+{
+	int j;
+	int out_max = 0;
+
+	if(transpose)
+		out_max = x_channel;
+	else
+		out_max = y_channel;
+
+	if(out_init > 0)
+	{
+		for(j = out_init-1;j >= 0;j--)
+		{
+			himax_diag_arrange_inloop(s, in_init, transpose, j);
+			seq_printf(s, " %5d\n", diag_self[j]);
+		}
+	}
+	else
+	{
+		for(j = 0;j < out_max;j++)
+		{
+			himax_diag_arrange_inloop(s, in_init, transpose, j);
+			seq_printf(s, " %5d\n", diag_self[j]);
+		}
+	}
+}
+
+static void himax_diag_arrange(struct seq_file *s)
+{
+	int bit2,bit1,bit0;
+	int i;
+
+	bit2 = g_diag_arr_num >> 2;
+	bit1 = g_diag_arr_num >> 1 & 0x1;
+	bit0 = g_diag_arr_num & 0x1;
+
+	if (g_diag_arr_num < 4)
+	{
+		himax_diag_arrange_outloop(s, bit2, bit1 * y_channel, bit0 * x_channel);
+		for (i = y_channel; i < x_channel + y_channel; i++) {
+			seq_printf(s, "%6d", diag_self[i]);
+		}
+	}
+	else
+	{
+		himax_diag_arrange_outloop(s, bit2, bit1 * x_channel, bit0 * y_channel);
+		for (i = x_channel; i < x_channel + y_channel; i++) {
+			seq_printf(s, "%6d", diag_self[i]);
+		}
+	}
+}
+
+static void *himax_diag_seq_start(struct seq_file *s, loff_t *pos)
+{
+	if (*pos>=1) return NULL;
+	return (void *)((unsigned long) *pos+1);
+}
+
+static void *himax_diag_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+	return NULL;
+}
+static void himax_diag_seq_stop(struct seq_file *s, void *v)
+{
+}
+static int himax_diag_seq_read(struct seq_file *s, void *v)
+{
+	size_t count = 0;
+	int32_t loop_i;//,loop_j
+	uint16_t mutual_num, self_num, width;
+
+#ifdef HX_TP_PROC_2T2R
+	if(Is_2T2R && diag_command == 4)
+	{
+		mutual_num	= x_channel_2 * y_channel_2;
+		self_num	= x_channel_2 + y_channel_2; //don't add KEY_COUNT
+		width		= x_channel_2;
+		seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_channel_2, y_channel_2);
+	}
+	else
+#endif
+	{
+		mutual_num	= x_channel * y_channel;
+		self_num	= x_channel + y_channel; //don't add KEY_COUNT
+		width		= x_channel;
+		seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_channel, y_channel);
+	}
+
+	// start to show out the raw data in adb shell
+	if (diag_command >= 1 && diag_command <= 6) {
+		if (diag_command <= 3) {
+			himax_diag_arrange(s);
+			seq_printf(s, "\n\n");
+#ifdef HX_EN_SEL_BUTTON
+			seq_printf(s, "\n");
+			for (loop_i = 0; loop_i < HX_BT_NUM; loop_i++)
+					seq_printf(s, "%6d", diag_self[HX_RX_NUM + HX_TX_NUM + loop_i]);
+#endif
+#ifdef HX_TP_PROC_2T2R
+		}else if(Is_2T2R && diag_command == 4 ) {
+			for (loop_i = 0; loop_i < mutual_num; loop_i++) {
+				seq_printf(s, "%4d", diag_mutual_2[loop_i]);
+				if ((loop_i % width) == (width - 1))
+					seq_printf(s, " %6d\n", diag_self[width + loop_i/width]);
+			}
+			seq_printf(s, "\n");
+			for (loop_i = 0; loop_i < width; loop_i++) {
+				seq_printf(s, "%6d", diag_self[loop_i]);
+				if (((loop_i) % width) == (width - 1))
+					seq_printf(s, "\n");
+			}
+#ifdef HX_EN_SEL_BUTTON
+			seq_printf(s, "\n");
+			for (loop_i = 0; loop_i < HX_BT_NUM; loop_i++)
+				seq_printf(s, "%4d", diag_self[HX_RX_NUM_2 + HX_TX_NUM_2 + loop_i]);
+#endif
+#endif
+		} else if (diag_command > 4) {
+			for (loop_i = 0; loop_i < self_num; loop_i++) {
+				seq_printf(s, "%4d", diag_self[loop_i]);
+				if (((loop_i - mutual_num) % width) == (width - 1))
+					seq_printf(s, "\n");
+			}
+		} else {
+			for (loop_i = 0; loop_i < mutual_num; loop_i++) {
+				seq_printf(s, "%4d", diag_mutual[loop_i]);
+				if ((loop_i % width) == (width - 1))
+					seq_printf(s, "\n");
+			}
+		}
+		seq_printf(s, "ChannelEnd");
+		seq_printf(s, "\n");
+	} else if (diag_command == 7) {
+		for (loop_i = 0; loop_i < 128 ;loop_i++) {
+			if ((loop_i % 16) == 0)
+				seq_printf(s, "LineStart:");
+				seq_printf(s, "%4d", diag_coor[loop_i]);
+			if ((loop_i % 16) == 15)
+				seq_printf(s, "\n");
+		}
+	} else if (diag_command == 9 || diag_command == 91 || diag_command == 92){
+		himax_diag_arrange(s);
+		seq_printf(s, "\n");
+	}
+
+	return count;
+}
+static const struct seq_operations himax_diag_seq_ops =
+{
+	.start	= himax_diag_seq_start,
+	.next	= himax_diag_seq_next,
+	.stop	= himax_diag_seq_stop,
+	.show	= himax_diag_seq_read,
+};
+static int himax_diag_proc_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &himax_diag_seq_ops);
+};
+bool DSRAM_Flag;
+
+//DSRAM thread
+void himax_ts_diag_func(void)
+{
+	int i=0, j=0;
+	unsigned int index = 0;
+	int total_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM * 2;
+	uint8_t  info_data[total_size];
+	int16_t *mutual_data     = NULL;
+	int16_t *mutual_data_new = NULL;
+	int16_t *mutual_data_old = NULL;
+	int16_t new_data;
+
+	himax_burst_enable(private_ts->client, 1);
+	if(diag_command == 9 || diag_command == 91)
+	{
+		mutual_data = getMutualBuffer();
+	}else if(diag_command == 92){
+		mutual_data = getMutualBuffer();
+		mutual_data_new = getMutualNewBuffer();
+		mutual_data_old = getMutualOldBuffer();
+	}
+	himax_get_DSRAM_data(private_ts->client, info_data);
+
+	index = 0;
+	for (i = 0; i < ic_data->HX_TX_NUM; i++)
+	{
+		for (j = 0; j < ic_data->HX_RX_NUM; j++)
+		{
+			new_data = (short)(info_data[index + 1] << 8 | info_data[index]);
+			if(diag_command == 9){
+				mutual_data[i*ic_data->HX_RX_NUM+j] = new_data;
+			}else if(diag_command == 91){ //Keep max data for 100 frame
+				if(mutual_data[i * ic_data->HX_RX_NUM + j] < new_data)
+				mutual_data[i * ic_data->HX_RX_NUM + j] = new_data;
+			}else if(diag_command == 92){ //Cal data for [N]-[N-1] frame
+				mutual_data_new[i * ic_data->HX_RX_NUM + j] = new_data;
+				mutual_data[i * ic_data->HX_RX_NUM + j] = mutual_data_new[i * ic_data->HX_RX_NUM + j] - mutual_data_old[i * ic_data->HX_RX_NUM + j];
+			}
+			index += 2;
+		}
+	}
+	if(diag_command == 92){
+		memcpy(mutual_data_old,mutual_data_new,x_channel * y_channel * sizeof(int16_t)); //copy N data to N-1 array
+	}
+	diag_max_cnt++;
+	if(diag_command == 9 || diag_command == 92){
+		queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 1/10*HZ);
+	}else if(diag_command == 91){
+		if(diag_max_cnt > 100) //count for 100 frame
+		{
+			//Clear DSRAM flag
+			DSRAM_Flag = false;
+
+			//Enable ISR
+			himax_int_enable(private_ts->client->irq,1);
+
+			//=====================================
+			// test result command : 0x8002_0324 ==> 0x00
+			//=====================================
+			himax_diag_register_set(private_ts->client, 0x00);
+		}else{
+			queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 1/10*HZ);
+		}
+	}
+}
+
+static ssize_t himax_diag_write(struct file *filp, const char __user *buff, size_t len, loff_t *data)
+{
+	char messages[80] = {0};
+
+	uint8_t command[2] = {0x00, 0x00};
+	uint8_t receive[1];
+
+	memset(receive, 0x00, sizeof(receive));
+
+	if (len >= 80)
+	{
+		I("%s: no command exceeds 80 chars.\n", __func__);
+		return -EFAULT;
+	}
+	if (copy_from_user(messages, buff, len))
+	{
+		return -EFAULT;
+	}
+	if (messages[1] == 0x0A){
+		diag_command =messages[0] - '0';
+	}else{
+		diag_command =(messages[0] - '0')*10 + (messages[1] - '0');
+	}
+
+	I("[Himax]diag_command=0x%x\n",diag_command);
+	if (diag_command < 0x04){
+		if(DSRAM_Flag)
+		{
+			//1. Clear DSRAM flag
+			DSRAM_Flag = false;
+
+			//2. Stop DSRAM thread
+			cancel_delayed_work_sync(&private_ts->himax_diag_delay_wrok);
+
+			//3. Enable ISR
+			himax_int_enable(private_ts->client->irq,1);
+		}
+		command[0] = diag_command;
+		himax_diag_register_set(private_ts->client, command[0]);
+	}
+	//coordinate dump start
+	else if (diag_command == 0x08)	{
+		E("%s: coordinate_dump_file_create error\n", __func__);
+	}
+	else if (diag_command == 0x09 || diag_command == 91 || diag_command == 92){
+		diag_max_cnt = 0;
+		memset(diag_mutual, 0x00, x_channel * y_channel * sizeof(int16_t)); //Set data 0 everytime
+
+		//1. Disable ISR
+		himax_int_enable(private_ts->client->irq,0);
+
+		//2. Start DSRAM thread
+		//himax_diag_register_set(private_ts->client, 0x0A);
+
+		queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 2*HZ/100);
+
+		I("%s: Start get raw data in DSRAM\n", __func__);
+
+		//3. Set DSRAM flag
+		DSRAM_Flag = true;
+	}else{
+		command[0] = 0x00;
+		himax_diag_register_set(private_ts->client, command[0]);
+		E("[Himax]Diag command error!diag_command=0x%x\n",diag_command);
+	}
+	return len;
+}
+
+static const struct file_operations himax_proc_diag_ops =
+{
+	.owner = THIS_MODULE,
+	.open = himax_diag_proc_open,
+	.read = seq_read,
+	.write = himax_diag_write,
+};
+#endif
+
+#ifdef HX_TP_PROC_RESET
+static ssize_t himax_reset_write(struct file *file, const char *buff,
+	size_t len, loff_t *pos)
+{
+	char buf_tmp[12];
+
+	if (len >= 12)
+	{
+		I("%s: no command exceeds 12 chars.\n", __func__);
+		return -EFAULT;
+	}
+	if (copy_from_user(buf_tmp, buff, len))
+	{
+		return -EFAULT;
+	}
+	//if (buf_tmp[0] == '1')
+	//	ESD_HW_REST();
+
+	return len;
+}
+
+static const struct file_operations himax_proc_reset_ops =
+{
+	.owner = THIS_MODULE,
+	.write = himax_reset_write,
+};
+#endif
+
+#ifdef HX_TP_PROC_DEBUG
+static ssize_t himax_debug_read(struct file *file, char *buf,
+	size_t len, loff_t *pos)
+{
+	size_t count = 0;
+	char *temp_buf;
+
+	if(!HX_PROC_SEND_FLAG)
+	{
+		temp_buf = kzalloc(len, GFP_KERNEL);
+		if (!temp_buf){
+			HX_PROC_SEND_FLAG=0;
+			return count;
+		}
+
+		if (debug_level_cmd == 't')
+		{
+			if (fw_update_complete)
+				count += snprintf(temp_buf+count, len-count, "FW Update Complete ");
+			else
+			{
+				count += snprintf(temp_buf+count, len-count, "FW Update Fail ");
+			}
+		}
+		else if (debug_level_cmd == 'h')
+		{
+			if (handshaking_result == 0)
+			{
+				count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (MCU Running)\n", handshaking_result);
+			}
+			else if (handshaking_result == 1)
+			{
+				count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (MCU Stop)\n", handshaking_result);
+			}
+			else if (handshaking_result == 2)
+			{
+				count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (I2C Error)\n", handshaking_result);
+			}
+			else
+			{
+				count += snprintf(temp_buf+count, len-count, "Handshaking Result = error\n");
+			}
+		}
+		else if (debug_level_cmd == 'v')
+		{
+			count += snprintf(temp_buf+count, len-count, "FW_VER = ");
+			count += snprintf(temp_buf+count, len-count, "0x%2.2X\n", ic_data->vendor_fw_ver);
+			count += snprintf(temp_buf+count, len-count, "CONFIG_VER = ");
+			count += snprintf(temp_buf+count, len-count, "0x%2.2X\n", ic_data->vendor_config_ver);
+			count += snprintf(temp_buf+count, len-count, "\n");
+		}
+		else if (debug_level_cmd == 'd')
+		{
+			count += snprintf(temp_buf+count, len-count, "Himax Touch IC Information :\n");
+			if (IC_TYPE == HX_85XX_D_SERIES_PWON)
+			{
+				count += snprintf(temp_buf+count, len-count, "IC Type : D\n");
+			}
+			else if (IC_TYPE == HX_85XX_E_SERIES_PWON)
+			{
+				count += snprintf(temp_buf+count, len-count, "IC Type : E\n");
+			}
+			else if (IC_TYPE == HX_85XX_ES_SERIES_PWON)
+			{
+				count += snprintf(temp_buf+count, len-count, "IC Type : ES\n");
+			}
+			else if (IC_TYPE == HX_85XX_F_SERIES_PWON)
+			{
+				count += snprintf(temp_buf+count, len-count, "IC Type : F\n");
+			}
+			else
+			{
+				count += snprintf(temp_buf+count, len-count, "IC Type error.\n");
+			}
+
+			if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_SW)
+			{
+				count += snprintf(temp_buf+count, len-count, "IC Checksum : SW\n");
+			}
+			else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_HW)
+			{
+				count += snprintf(temp_buf+count, len-count, "IC Checksum : HW\n");
+			}
+			else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_CRC)
+			{
+				count += snprintf(temp_buf+count, len-count, "IC Checksum : CRC\n");
+			}
+			else
+			{
+				count += snprintf(temp_buf+count, len-count, "IC Checksum error.\n");
+			}
+
+			if (ic_data->HX_INT_IS_EDGE)
+			{
+				count += snprintf(temp_buf+count, len-count, "Interrupt : EDGE TIRGGER\n");
+			}
+			else
+			{
+				count += snprintf(temp_buf+count, len-count, "Interrupt : LEVEL TRIGGER\n");
+			}
+
+			count += snprintf(temp_buf+count, len-count, "RX Num : %d\n", ic_data->HX_RX_NUM);
+			count += snprintf(temp_buf+count, len-count, "TX Num : %d\n", ic_data->HX_TX_NUM);
+			count += snprintf(temp_buf+count, len-count, "BT Num : %d\n", ic_data->HX_BT_NUM);
+			count += snprintf(temp_buf+count, len-count, "X Resolution : %d\n", ic_data->HX_X_RES);
+			count += snprintf(temp_buf+count, len-count, "Y Resolution : %d\n", ic_data->HX_Y_RES);
+			count += snprintf(temp_buf+count, len-count, "Max Point : %d\n", ic_data->HX_MAX_PT);
+			count += snprintf(temp_buf+count, len-count, "XY reverse : %d\n", ic_data->HX_XY_REVERSE);
+	#ifdef HX_TP_PROC_2T2R
+			if(Is_2T2R)
+			{
+				count += snprintf(temp_buf+count, len-count, "2T2R panel\n");
+				count += snprintf(temp_buf+count, len-count, "RX Num_2 : %d\n", HX_RX_NUM_2);
+				count += snprintf(temp_buf+count, len-count, "TX Num_2 : %d\n", HX_TX_NUM_2);
+			}
+	#endif
+		}
+		else if (debug_level_cmd == 'i')
+		{
+			count += snprintf(temp_buf+count, len-count, "Himax Touch Driver Version:\n");
+			count += snprintf(temp_buf+count, len-count, "%s\n", HIMAX_DRIVER_VER);
+		}
+		if (copy_to_user(buf, temp_buf, len))
+		{
+			I("%s,here:%d\n", __func__, __LINE__);
+		}
+
+		kfree(temp_buf);
+		HX_PROC_SEND_FLAG=1;
+	}
+	else
+		HX_PROC_SEND_FLAG=0;
+	return count;
+}
+
+static ssize_t himax_debug_write(struct file *file, const char *buff,
+	size_t len, loff_t *pos)
+{
+	const struct firmware *fw = NULL;
+	unsigned char *fw_data = NULL;
+	char fileName[128];
+	char buf[80] = {0};
+	int result;
+
+	if (len >= 80)
+	{
+		I("%s: no command exceeds 80 chars.\n", __func__);
+		return -EFAULT;
+	}
+	if (copy_from_user(buf, buff, len))
+	{
+		return -EFAULT;
+	}
+
+	if ( buf[0] == 'h') //handshaking
+	{
+		debug_level_cmd = buf[0];
+
+		himax_int_enable(private_ts->client->irq,0);
+
+		handshaking_result = himax_hand_shaking(private_ts->client); //0:Running, 1:Stop, 2:I2C Fail
+
+		himax_int_enable(private_ts->client->irq,1);
+
+		return len;
+	}
+
+	else if ( buf[0] == 'v') //firmware version
+	{
+		debug_level_cmd = buf[0];
+		himax_int_enable(private_ts->client->irq,0);
+#ifdef HX_RST_PIN_FUNC
+		himax_HW_reset(false,false);
+#endif
+		himax_read_FW_ver(private_ts->client);
+		//himax_check_chip_version();
+#ifdef HX_RST_PIN_FUNC
+	himax_HW_reset(true,false);
+#endif
+	himax_int_enable(private_ts->client->irq,1);
+		return len;
+	}
+
+	else if ( buf[0] == 'd') //ic information
+	{
+		debug_level_cmd = buf[0];
+		return len;
+	}
+
+	else if ( buf[0] == 'i') //driver version
+	{
+		debug_level_cmd = buf[0];
+		return len;
+	}
+
+	else if (buf[0] == 't')
+	{
+
+		himax_int_enable(private_ts->client->irq,0);
+
+		debug_level_cmd 		= buf[0];
+		fw_update_complete		= false;
+
+		memset(fileName, 0, 128);
+		// parse the file name
+		snprintf(fileName, len-4, "%s", &buf[4]);
+		I("%s: upgrade from file(%s) start!\n", __func__, fileName);
+		// open file
+		result = request_firmware(&fw, fileName, private_ts->dev);
+		if (result) {
+			E("%s: open firmware file failed\n", __func__);
+			goto firmware_upgrade_done;
+			//return len;
+		}
+
+		I("%s: FW len %d\n", __func__, fw->size);
+		fw_data = (unsigned char *)fw->data;
+
+		I("%s: FW image,len %d: %02X, %02X, %02X, %02X\n", __func__, result, upgrade_fw[0], upgrade_fw[1], upgrade_fw[2], upgrade_fw[3]);
+
+		if (fw_data != NULL)
+		{
+			// start to upgrade
+			himax_int_enable(private_ts->client->irq,0);
+
+			if ((buf[1] == '6') && (buf[2] == '0'))
+			{
+				if (fts_ctpm_fw_upgrade_with_sys_fs_60k(private_ts->client,upgrade_fw, result, false) == 0)
+				{
+					E("%s: TP upgrade error, line: %d\n", __func__, __LINE__);
+					fw_update_complete = false;
+				}
+				else
+				{
+					I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__);
+					fw_update_complete = true;
+				}
+			}
+			else if ((buf[1] == '6') && (buf[2] == '4'))
+			{
+				if (fts_ctpm_fw_upgrade_with_sys_fs_64k(private_ts->client,upgrade_fw, result, false) == 0)
+				{
+					E("%s: TP upgrade error, line: %d\n", __func__, __LINE__);
+					fw_update_complete = false;
+				}
+				else
+				{
+					I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__);
+					fw_update_complete = true;
+				}
+			}
+			else if ((buf[1] == '2') && (buf[2] == '4'))
+			{
+				if (fts_ctpm_fw_upgrade_with_sys_fs_124k(private_ts->client,upgrade_fw, result, false) == 0)
+				{
+					E("%s: TP upgrade error, line: %d\n", __func__, __LINE__);
+					fw_update_complete = false;
+				}
+				else
+				{
+					I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__);
+					fw_update_complete = true;
+				}
+			}
+			else if ((buf[1] == '2') && (buf[2] == '8'))
+			{
+				if (fts_ctpm_fw_upgrade_with_sys_fs_128k(private_ts->client,upgrade_fw, result, false) == 0)
+				{
+					E("%s: TP upgrade error, line: %d\n", __func__, __LINE__);
+					fw_update_complete = false;
+				}
+				else
+				{
+					I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__);
+					fw_update_complete = true;
+				}
+			}
+			else
+			{
+				E("%s: Flash command fail: %d\n", __func__, __LINE__);
+				fw_update_complete = false;
+			}
+			release_firmware(fw);
+			goto firmware_upgrade_done;
+			//return count;
+		}
+	}
+
+	firmware_upgrade_done:
+
+#ifdef HX_RST_PIN_FUNC
+	himax_HW_reset(true,false);
+#endif
+
+	himax_sense_on(private_ts->client, 0x01);
+	msleep(120);
+#ifdef HX_ESD_WORKAROUND
+	HX_ESD_RESET_ACTIVATE = 1;
+#endif
+	himax_int_enable(private_ts->client->irq,1);
+
+	//todo himax_chip->tp_firmware_upgrade_proceed = 0;
+	//todo himax_chip->suspend_state = 0;
+	//todo enable_irq(himax_chip->irq);
+	return len;
+}
+
+static const struct file_operations himax_proc_debug_ops =
+{
+	.owner = THIS_MODULE,
+	.read = himax_debug_read,
+	.write = himax_debug_write,
+};
+
+#endif
+
+#ifdef HX_TP_PROC_FLASH_DUMP
+
+static uint8_t getFlashCommand(void)
+{
+	return flash_command;
+}
+
+static uint8_t getFlashDumpProgress(void)
+{
+	return flash_progress;
+}
+
+static uint8_t getFlashDumpComplete(void)
+{
+	return flash_dump_complete;
+}
+
+static uint8_t getFlashDumpFail(void)
+{
+	return flash_dump_fail;
+}
+
+uint8_t getSysOperation(void)
+{
+	return sys_operation;
+}
+
+static uint8_t getFlashReadStep(void)
+{
+	return flash_read_step;
+}
+/*
+static uint8_t getFlashDumpSector(void)
+{
+	return flash_dump_sector;
+}
+
+static uint8_t getFlashDumpPage(void)
+{
+	return flash_dump_page;
+}
+*/
+bool getFlashDumpGoing(void)
+{
+	return flash_dump_going;
+}
+
+void setFlashBuffer(void)
+{
+	flash_buffer = kzalloc(Flash_Size * sizeof(uint8_t), GFP_KERNEL);
+	if (flash_buffer)
+		memset(flash_buffer,0x00,Flash_Size);
+}
+
+void setSysOperation(uint8_t operation)
+{
+	sys_operation = operation;
+}
+
+static void setFlashDumpProgress(uint8_t progress)
+{
+	flash_progress = progress;
+	//I("setFlashDumpProgress : progress = %d ,flash_progress = %d \n",progress,flash_progress);
+}
+
+static void setFlashDumpComplete(uint8_t status)
+{
+	flash_dump_complete = status;
+}
+
+static void setFlashDumpFail(uint8_t fail)
+{
+	flash_dump_fail = fail;
+}
+
+static void setFlashCommand(uint8_t command)
+{
+	flash_command = command;
+}
+
+static void setFlashReadStep(uint8_t step)
+{
+	flash_read_step = step;
+}
+
+static void setFlashDumpSector(uint8_t sector)
+{
+	flash_dump_sector = sector;
+}
+
+static void setFlashDumpPage(uint8_t page)
+{
+	flash_dump_page = page;
+}
+
+static void setFlashDumpGoing(bool going)
+{
+	flash_dump_going = going;
+}
+
+static ssize_t himax_proc_flash_read(struct file *file, char *buf,
+	size_t len, loff_t *pos)
+{
+	int ret = 0;
+	int loop_i;
+	uint8_t local_flash_read_step=0;
+	uint8_t local_flash_complete = 0;
+	uint8_t local_flash_progress = 0;
+	uint8_t local_flash_command = 0;
+	uint8_t local_flash_fail = 0;
+	char *temp_buf;
+	local_flash_complete = getFlashDumpComplete();
+	local_flash_progress = getFlashDumpProgress();
+	local_flash_command = getFlashCommand();
+	local_flash_fail = getFlashDumpFail();
+
+	I("flash_progress = %d \n",local_flash_progress);
+	if(!HX_PROC_SEND_FLAG)
+	{
+		temp_buf = kzalloc(len, GFP_KERNEL);
+		if (!temp_buf) {
+			HX_PROC_SEND_FLAG=0;
+			return ret;
+		}
+
+		if (local_flash_fail)
+		{
+			ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Fail \n");
+			ret += snprintf(temp_buf+ret, len-ret, "FlashEnd");
+			ret += snprintf(temp_buf+ret, len-ret, "\n");
+
+			if (copy_to_user(buf, temp_buf, len))
+			{
+				I("%s,here:%d\n", __func__, __LINE__);
+			}
+
+			kfree(temp_buf);
+			HX_PROC_SEND_FLAG = 1;
+			return ret;
+		}
+
+		if (!local_flash_complete)
+		{
+			ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Ongoing:0x%2.2x \n",flash_progress);
+			ret += snprintf(temp_buf+ret, len-ret, "FlashEnd");
+			ret += snprintf(temp_buf+ret, len-ret, "\n");
+
+			if (copy_to_user(buf, temp_buf, len))
+			{
+				I("%s,here:%d\n", __func__, __LINE__);
+			}
+
+			kfree(temp_buf);
+			HX_PROC_SEND_FLAG = 1;
+			return ret;
+		}
+
+		if (local_flash_command == 1 && local_flash_complete)
+		{
+			ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Complete \n");
+			ret += snprintf(temp_buf+ret, len-ret, "FlashEnd");
+			ret += snprintf(temp_buf+ret, len-ret, "\n");
+
+			if (copy_to_user(buf, temp_buf, len))
+			{
+				I("%s,here:%d\n", __func__, __LINE__);
+			}
+
+			kfree(temp_buf);
+			HX_PROC_SEND_FLAG = 1;
+			return ret;
+		}
+
+		if (local_flash_command == 3 && local_flash_complete)
+		{
+			ret += snprintf(temp_buf+ret, len-ret, "FlashStart: \n");
+			for(loop_i = 0; loop_i < 128; loop_i++)
+			{
+				ret += snprintf(temp_buf+ret, len-ret, "x%2.2x", flash_buffer[loop_i]);
+				if ((loop_i % 16) == 15)
+				{
+					ret += snprintf(temp_buf+ret, len-ret, "\n");
+				}
+			}
+			ret += snprintf(temp_buf+ret, len-ret, "FlashEnd");
+			ret += snprintf(temp_buf+ret, len-ret, "\n");
+
+			if (copy_to_user(buf, temp_buf, len))
+			{
+				I("%s,here:%d\n", __func__, __LINE__);
+			}
+
+			kfree(temp_buf);
+			HX_PROC_SEND_FLAG = 1;
+			return ret;
+		}
+
+		//flash command == 0 , report the data
+		local_flash_read_step = getFlashReadStep();
+
+		ret += snprintf(temp_buf+ret, len-ret, "FlashStart:%2.2x \n",local_flash_read_step);
+
+		for (loop_i = 0; loop_i < 1024; loop_i++)
+		{
+			ret += snprintf(temp_buf+ret, len-ret, "x%2.2X", flash_buffer[local_flash_read_step*1024 + loop_i]);
+
+			if ((loop_i % 16) == 15)
+			{
+				ret += snprintf(temp_buf+ret, len-ret, "\n");
+			}
+		}
+
+		ret += snprintf(temp_buf+ret, len-ret, "FlashEnd");
+		ret += snprintf(temp_buf+ret, len-ret, "\n");
+		if (copy_to_user(buf, temp_buf, len))
+		{
+			I("%s,here:%d\n", __func__, __LINE__);
+		}
+
+		kfree(temp_buf);
+		HX_PROC_SEND_FLAG = 1;
+	}
+	else
+		HX_PROC_SEND_FLAG=0;
+	return ret;
+}
+
+static ssize_t himax_proc_flash_write(struct file *file, const char *buff,
+	size_t len, loff_t *pos)
+{
+	char buf_tmp[6];
+	unsigned long result = 0;
+	uint8_t loop_i = 0;
+	int base = 0;
+	char buf[80] = {0};
+
+	if (len >= 80)
+	{
+		I("%s: no command exceeds 80 chars.\n", __func__);
+		return -EFAULT;
+	}
+	if (copy_from_user(buf, buff, len))
+	{
+		return -EFAULT;
+	}
+	memset(buf_tmp, 0x0, sizeof(buf_tmp));
+
+	I("%s: buf[0] = %s\n", __func__, buf);
+
+	if (getSysOperation() == 1)
+	{
+		E("%s: PROC is busy , return!\n", __func__);
+		return len;
+	}
+
+	if (buf[0] == '0')
+	{
+		setFlashCommand(0);
+		if (buf[1] == ':' && buf[2] == 'x')
+		{
+			memcpy(buf_tmp, buf + 3, 2);
+			I("%s: read_Step = %s\n", __func__, buf_tmp);
+			if (!kstrtoul(buf_tmp, 16, &result))
+			{
+				I("%s: read_Step = %lu \n", __func__, result);
+				setFlashReadStep(result);
+			}
+		}
+	}
+	else if (buf[0] == '1')// 1_60,1_64,1_24,1_28 for flash size 60k,64k,124k,128k
+	{
+		setSysOperation(1);
+		setFlashCommand(1);
+		setFlashDumpProgress(0);
+		setFlashDumpComplete(0);
+		setFlashDumpFail(0);
+		if ((buf[1] == '_' ) && (buf[2] == '6' )){
+			if (buf[3] == '0'){
+				Flash_Size = FW_SIZE_60k;
+			}else if (buf[3] == '4'){
+				Flash_Size = FW_SIZE_64k;
+			}
+		}else if ((buf[1] == '_' ) && (buf[2] == '2' )){
+			if (buf[3] == '4'){
+				Flash_Size = FW_SIZE_124k;
+			}else if (buf[3] == '8'){
+				Flash_Size = FW_SIZE_128k;
+			}
+		}
+		queue_work(private_ts->flash_wq, &private_ts->flash_work);
+	}
+	else if (buf[0] == '2') // 2_60,2_64,2_24,2_28 for flash size 60k,64k,124k,128k
+	{
+		setSysOperation(1);
+		setFlashCommand(2);
+		setFlashDumpProgress(0);
+		setFlashDumpComplete(0);
+		setFlashDumpFail(0);
+		if ((buf[1] == '_' ) && (buf[2] == '6' )){
+			if (buf[3] == '0'){
+				Flash_Size = FW_SIZE_60k;
+			}else if (buf[3] == '4'){
+				Flash_Size = FW_SIZE_64k;
+			}
+		}else if ((buf[1] == '_' ) && (buf[2] == '2' )){
+			if (buf[3] == '4'){
+				Flash_Size = FW_SIZE_124k;
+			}else if (buf[3] == '8'){
+				Flash_Size = FW_SIZE_128k;
+			}
+		}
+		queue_work(private_ts->flash_wq, &private_ts->flash_work);
+	}
+	else if (buf[0] == '3')
+	{
+		setSysOperation(1);
+		setFlashCommand(3);
+		setFlashDumpProgress(0);
+		setFlashDumpComplete(0);
+		setFlashDumpFail(0);
+
+		memcpy(buf_tmp, buf + 3, 2);
+		if (!kstrtoul(buf_tmp, 16, &result))
+		{
+			setFlashDumpSector(result);
+		}
+
+		memcpy(buf_tmp, buf + 7, 2);
+		if (!kstrtoul(buf_tmp, 16, &result))
+		{
+			setFlashDumpPage(result);
+		}
+
+		queue_work(private_ts->flash_wq, &private_ts->flash_work);
+	}
+	else if (buf[0] == '4')
+	{
+		I("%s: command 4 enter.\n", __func__);
+		setSysOperation(1);
+		setFlashCommand(4);
+		setFlashDumpProgress(0);
+		setFlashDumpComplete(0);
+		setFlashDumpFail(0);
+
+		memcpy(buf_tmp, buf + 3, 2);
+		if (!kstrtoul(buf_tmp, 16, &result))
+		{
+			setFlashDumpSector(result);
+		}
+		else
+		{
+			E("%s: command 4 , sector error.\n", __func__);
+			return len;
+		}
+
+		memcpy(buf_tmp, buf + 7, 2);
+		if (!kstrtoul(buf_tmp, 16, &result))
+		{
+			setFlashDumpPage(result);
+		}
+		else
+		{
+			E("%s: command 4 , page error.\n", __func__);
+			return len;
+		}
+
+		base = 11;
+
+		I("=========Himax flash page buffer start=========\n");
+		for(loop_i=0;loop_i<128 && base<80;loop_i++)
+		{
+			memcpy(buf_tmp, buf + base, 2);
+			if (!kstrtoul(buf_tmp, 16, &result))
+			{
+				flash_buffer[loop_i] = result;
+				I("%d ",flash_buffer[loop_i]);
+				if (loop_i % 16 == 15)
+				{
+					I("\n");
+				}
+			}
+			base += 3;
+		}
+		I("=========Himax flash page buffer end=========\n");
+
+		queue_work(private_ts->flash_wq, &private_ts->flash_work);
+	}
+	return len;
+}
+
+static const struct file_operations himax_proc_flash_ops =
+{
+	.owner = THIS_MODULE,
+	.read = himax_proc_flash_read,
+	.write = himax_proc_flash_write,
+};
+
+void himax_ts_flash_func(void)
+{
+	uint8_t local_flash_command = 0;
+
+	himax_int_enable(private_ts->client->irq,0);
+	setFlashDumpGoing(true);
+
+	//sector = getFlashDumpSector();
+	//page = getFlashDumpPage();
+
+	local_flash_command = getFlashCommand();
+
+	msleep(100);
+
+	I("%s: local_flash_command = %d enter.\n", __func__,local_flash_command);
+
+	if ((local_flash_command == 1 || local_flash_command == 2)|| (local_flash_command==0x0F))
+	{
+		himax_flash_dump_func(private_ts->client, local_flash_command,Flash_Size, flash_buffer);
+	}
+
+	I("Complete~~~~~~~~~~~~~~~~~~~~~~~\n");
+
+	if (local_flash_command == 2)
+	{
+		E("Flash dump failed\n");
+	}
+
+	himax_int_enable(private_ts->client->irq,1);
+	setFlashDumpGoing(false);
+
+	setFlashDumpComplete(1);
+	setSysOperation(0);
+	return;
+
+/*	Flash_Dump_i2c_transfer_error:
+
+	himax_int_enable(private_ts->client->irq,1);
+	setFlashDumpGoing(false);
+	setFlashDumpComplete(0);
+	setFlashDumpFail(1);
+	setSysOperation(0);
+	return;
+*/
+}
+
+#endif
+
+#ifdef HX_TP_PROC_SELF_TEST
+static ssize_t himax_self_test_read(struct file *file, char *buf,
+	size_t len, loff_t *pos)
+{
+	int val=0x00;
+	int ret = 0;
+	char *temp_buf;
+
+	I("%s: enter, %d \n", __func__, __LINE__);
+	if(!HX_PROC_SEND_FLAG)
+	{
+		temp_buf = kzalloc(len, GFP_KERNEL);
+		if (!temp_buf) {
+			HX_PROC_SEND_FLAG=0;
+			return ret;
+		}
+		himax_int_enable(private_ts->client->irq,0);//disable irq
+		val = himax_chip_self_test(private_ts->client);
+#ifdef HX_ESD_WORKAROUND
+		HX_ESD_RESET_ACTIVATE = 1;
+#endif
+		himax_int_enable(private_ts->client->irq,1);//enable irq
+
+		if (val == 0x01) {
+			ret += snprintf(temp_buf+ret, len-ret, "Self_Test Pass\n");
+		} else {
+			ret += snprintf(temp_buf+ret, len-ret, "Self_Test Fail\n");
+		}
+
+		if (copy_to_user(buf, temp_buf, len))
+		{
+			I("%s,here:%d\n", __func__, __LINE__);
+		}
+
+		kfree(temp_buf);
+		HX_PROC_SEND_FLAG = 1;
+	}
+	else
+		HX_PROC_SEND_FLAG=0;
+	return ret;
+}
+
+/*
+static ssize_t himax_chip_self_test_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t count)
+{
+	char buf_tmp[2];
+	unsigned long result = 0;
+
+	memset(buf_tmp, 0x0, sizeof(buf_tmp));
+	memcpy(buf_tmp, buf, 2);
+	if(!kstrtoul(buf_tmp, 16, &result))
+		{
+			sel_type = (uint8_t)result;
+		}
+	I("sel_type = %x \r\n", sel_type);
+	return count;
+}
+*/
+
+static const struct file_operations himax_proc_self_test_ops =
+{
+	.owner = THIS_MODULE,
+	.read = himax_self_test_read,
+};
+#endif
+
+#ifdef HX_TP_PROC_SENSE_ON_OFF
+static ssize_t himax_sense_on_off_write(struct file *file, const char *buff,
+	size_t len, loff_t *pos)
+{
+	char buf[80] = {0};
+
+	if (len >= 80)
+	{
+		I("%s: no command exceeds 80 chars.\n", __func__);
+		return -EFAULT;
+	}
+	if (copy_from_user(buf, buff, len))
+	{
+		return -EFAULT;
+	}
+
+	if(buf[0] == '0')
+	{
+		himax_sense_off(private_ts->client);
+		I("Sense off \n");
+	}
+	else if(buf[0] == '1')
+	{
+		if(buf[1] == '1'){
+			himax_sense_on(private_ts->client, 0x01);
+			I("Sense on re-map off, run flash \n");
+		}else if(buf[1] == '0'){
+			himax_sense_on(private_ts->client, 0x00);
+			I("Sense on re-map on, run sram \n");
+		}else{
+			I("Do nothing \n");
+		}
+	}
+	else
+	{
+		I("Do nothing \n");
+	}
+	return len;
+}
+
+static const struct file_operations himax_proc_sense_on_off_ops =
+{
+	.owner = THIS_MODULE,
+	.write = himax_sense_on_off_write,
+};
+#endif
+
+#ifdef HX_HIGH_SENSE
+static ssize_t himax_HSEN_read(struct file *file, char *buf,
+	size_t len, loff_t *pos)
+{
+	struct himax_ts_data *ts = private_ts;
+	size_t count = 0;
+	char *temp_buf;
+
+	if(!HX_PROC_SEND_FLAG)
+	{
+		temp_buf = kzalloc(len, GFP_KERNEL);
+		if (!temp_buf) {
+			HX_PROC_SEND_FLAG=0;
+			return count;
+		}
+		count = snprintf(temp_buf, len, "%d\n", ts->HSEN_enable);
+		HX_PROC_SEND_FLAG=1;
+
+		if (copy_to_user(buf, temp_buf, len))
+		{
+			I("%s,here:%d\n", __func__, __LINE__);
+		}
+
+		kfree(temp_buf);
+	}
+	else
+		HX_PROC_SEND_FLAG=0;
+	return count;
+}
+
+static ssize_t himax_HSEN_write(struct file *file, const char *buff,
+	size_t len, loff_t *pos)
+{
+	struct himax_ts_data *ts = private_ts;
+	char buf[80] = {0};
+
+
+	if (len >= 80)
+	{
+		I("%s: no command exceeds 80 chars.\n", __func__);
+		return -EFAULT;
+	}
+	if (copy_from_user(buf, buff, len))
+	{
+		return -EFAULT;
+	}
+
+	if (buf[0] == '0'){
+		ts->HSEN_enable = 0;
+	}
+	else if (buf[0] == '1'){
+		ts->HSEN_enable = 1;
+	}
+	else
+		return -EINVAL;
+
+	himax_set_HSEN_func(ts->client, ts->HSEN_enable);
+
+	I("%s: HSEN_enable = %d.\n", __func__, ts->HSEN_enable);
+
+	return len;
+}
+
+static const struct file_operations himax_proc_HSEN_ops =
+{
+	.owner = THIS_MODULE,
+	.read = himax_HSEN_read,
+	.write = himax_HSEN_write,
+};
+#endif
+
+#ifdef HX_SMART_WAKEUP
+static ssize_t himax_SMWP_read(struct file *file, char *buf,
+	size_t len, loff_t *pos)
+{
+	size_t count = 0;
+	struct himax_ts_data *ts = private_ts;
+	char *temp_buf;
+
+	if(!HX_PROC_SEND_FLAG)
+	{
+		temp_buf = kzalloc(len, GFP_KERNEL);
+		if (!temp_buf) {
+			HX_PROC_SEND_FLAG=0;
+			return count;
+		}
+		count = snprintf(temp_buf, len, "%d\n", ts->SMWP_enable);
+
+		if (copy_to_user(buf, temp_buf, len))
+		{
+			I("%s,here:%d\n", __func__, __LINE__);
+		}
+
+		kfree(temp_buf);
+		HX_PROC_SEND_FLAG=1;
+	}
+	else
+		HX_PROC_SEND_FLAG=0;
+
+	return count;
+}
+
+static ssize_t himax_SMWP_write(struct file *file, const char *buff,
+	size_t len, loff_t *pos)
+{
+	struct himax_ts_data *ts = private_ts;
+	char buf[80] = {0};
+
+	if (len >= 80)
+	{
+		I("%s: no command exceeds 80 chars.\n", __func__);
+		return -EFAULT;
+	}
+	if (copy_from_user(buf, buff, len))
+	{
+		return -EFAULT;
+	}
+
+
+	if (buf[0] == '0')
+	{
+		ts->SMWP_enable = 0;
+	}
+	else if (buf[0] == '1')
+	{
+		ts->SMWP_enable = 1;
+	}
+	else
+		return -EINVAL;
+
+	himax_set_SMWP_func(ts->client, ts->SMWP_enable);
+	HX_SMWP_EN = ts->SMWP_enable;
+	I("%s: SMART_WAKEUP_enable = %d.\n", __func__, HX_SMWP_EN);
+
+	return len;
+}
+
+static const struct file_operations himax_proc_SMWP_ops =
+{
+	.owner = THIS_MODULE,
+	.read = himax_SMWP_read,
+	.write = himax_SMWP_write,
+};
+
+static ssize_t himax_GESTURE_read(struct file *file, char *buf,
+	size_t len, loff_t *pos)
+{
+	struct himax_ts_data *ts = private_ts;
+	int i =0;
+	int ret = 0;
+	char *temp_buf;
+
+	if(!HX_PROC_SEND_FLAG)
+	{
+		temp_buf = kzalloc(len, GFP_KERNEL);
+		if (!temp_buf) {
+			HX_PROC_SEND_FLAG=0;
+			return ret;
+		}
+		for(i=0;i<16;i++)
+			ret += snprintf(temp_buf+ret, len-ret, "ges_en[%d]=%d\n", i, ts->gesture_cust_en[i]);
+		HX_PROC_SEND_FLAG = 1;
+		if (copy_to_user(buf, temp_buf, len))
+		{
+			I("%s,here:%d\n", __func__, __LINE__);
+		}
+
+		kfree(temp_buf);
+		HX_PROC_SEND_FLAG = 1;
+	}
+	else
+	{
+		HX_PROC_SEND_FLAG = 0;
+		ret = 0;
+	}
+	return ret;
+}
+
+static ssize_t himax_GESTURE_write(struct file *file, const char *buff,
+	size_t len, loff_t *pos)
+{
+	struct himax_ts_data *ts = private_ts;
+	int i =0;
+	char buf[80] = {0};
+
+	if (len >= 80)
+	{
+		I("%s: no command exceeds 80 chars.\n", __func__);
+		return -EFAULT;
+	}
+	if (copy_from_user(buf, buff, len))
+	{
+		return -EFAULT;
+	}
+
+	I("himax_GESTURE_store= %s \n",buf);
+	for (i=0;i<16;i++)
+	{
+		if (buf[i] == '0')
+			ts->gesture_cust_en[i]= 0;
+		else if (buf[i] == '1')
+			ts->gesture_cust_en[i]= 1;
+		else
+			ts->gesture_cust_en[i]= 0;
+		I("gesture en[%d]=%d \n", i, ts->gesture_cust_en[i]);
+	}
+	return len;
+}
+
+static const struct file_operations himax_proc_Gesture_ops =
+{
+	.owner = THIS_MODULE,
+	.read = himax_GESTURE_read,
+	.write = himax_GESTURE_write,
+};
+#endif
+
+int himax_touch_proc_init(void)
+{
+	himax_touch_proc_dir = proc_mkdir( HIMAX_PROC_TOUCH_FOLDER, NULL);
+	if (himax_touch_proc_dir == NULL)
+	{
+		E(" %s: himax_touch_proc_dir file create failed!\n", __func__);
+		return -ENOMEM;
+	}
+
+	himax_proc_debug_level_file = proc_create(HIMAX_PROC_DEBUG_LEVEL_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_level_ops);
+	if (himax_proc_debug_level_file == NULL)
+	{
+		E(" %s: proc debug_level file create failed!\n", __func__);
+		goto fail_1;
+	}
+
+	himax_proc_vendor_file = proc_create(HIMAX_PROC_VENDOR_FILE, (S_IRUGO),himax_touch_proc_dir, &himax_proc_vendor_ops);
+	if(himax_proc_vendor_file == NULL)
+	{
+		E(" %s: proc vendor file create failed!\n", __func__);
+		goto fail_2;
+	}
+
+	himax_proc_attn_file = proc_create(HIMAX_PROC_ATTN_FILE, (S_IRUGO),himax_touch_proc_dir, &himax_proc_attn_ops);
+	if(himax_proc_attn_file == NULL)
+	{
+		E(" %s: proc attn file create failed!\n", __func__);
+		goto fail_3;
+	}
+
+	himax_proc_int_en_file = proc_create(HIMAX_PROC_INT_EN_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_int_en_ops);
+	if(himax_proc_int_en_file == NULL)
+	{
+		E(" %s: proc int en file create failed!\n", __func__);
+		goto fail_4;
+	}
+
+	himax_proc_layout_file = proc_create(HIMAX_PROC_LAYOUT_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_layout_ops);
+	if(himax_proc_layout_file == NULL)
+	{
+		E(" %s: proc layout file create failed!\n", __func__);
+		goto fail_5;
+	}
+
+#ifdef HX_TP_PROC_RESET
+	himax_proc_reset_file = proc_create(HIMAX_PROC_RESET_FILE, (S_IWUSR), himax_touch_proc_dir, &himax_proc_reset_ops);
+	if(himax_proc_reset_file == NULL)
+	{
+		E(" %s: proc reset file create failed!\n", __func__);
+		goto fail_6;
+	}
+#endif
+
+#ifdef HX_TP_PROC_DIAG
+	himax_proc_diag_file = proc_create(HIMAX_PROC_DIAG_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_diag_ops);
+	if(himax_proc_diag_file == NULL)
+	{
+		E(" %s: proc diag file create failed!\n", __func__);
+		goto fail_7;
+	}
+	himax_proc_diag_arrange_file = proc_create(HIMAX_PROC_DIAG_ARR_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_diag_arrange_ops);
+	if(himax_proc_diag_arrange_file == NULL)
+	{
+		E(" %s: proc diag file create failed!\n", __func__);
+		goto fail_7_1;
+	}
+#endif
+
+#ifdef HX_TP_PROC_REGISTER
+	himax_proc_register_file = proc_create(HIMAX_PROC_REGISTER_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_register_ops);
+	if(himax_proc_register_file == NULL)
+	{
+		E(" %s: proc register file create failed!\n", __func__);
+		goto fail_8;
+	}
+#endif
+
+#ifdef HX_TP_PROC_DEBUG
+	himax_proc_debug_file = proc_create(HIMAX_PROC_DEBUG_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_ops);
+	if(himax_proc_debug_file == NULL)
+	{
+		E(" %s: proc debug file create failed!\n", __func__);
+		goto fail_9;
+	}
+#endif
+
+#ifdef HX_TP_PROC_FLASH_DUMP
+	himax_proc_flash_dump_file = proc_create(HIMAX_PROC_FLASH_DUMP_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_flash_ops);
+	if(himax_proc_flash_dump_file == NULL)
+	{
+		E(" %s: proc flash dump file create failed!\n", __func__);
+		goto fail_10;
+	}
+#endif
+
+#ifdef HX_TP_PROC_SELF_TEST
+	himax_proc_self_test_file = proc_create(HIMAX_PROC_SELF_TEST_FILE, (S_IRUGO), himax_touch_proc_dir, &himax_proc_self_test_ops);
+	if(himax_proc_self_test_file == NULL)
+	{
+		E(" %s: proc self_test file create failed!\n", __func__);
+		goto fail_11;
+	}
+#endif
+
+#ifdef HX_HIGH_SENSE
+	himax_proc_HSEN_file = proc_create(HIMAX_PROC_HSEN_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_HSEN_ops);
+	if(himax_proc_HSEN_file == NULL)
+	{
+		E(" %s: proc HSEN file create failed!\n", __func__);
+		goto fail_12;
+	}
+#endif
+
+#ifdef HX_SMART_WAKEUP
+	himax_proc_SMWP_file = proc_create(HIMAX_PROC_SMWP_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_SMWP_ops);
+	if(himax_proc_SMWP_file == NULL)
+	{
+		E(" %s: proc SMWP file create failed!\n", __func__);
+		goto fail_13;
+	}
+	himax_proc_GESTURE_file = proc_create(HIMAX_PROC_GESTURE_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_Gesture_ops);
+	if(himax_proc_GESTURE_file == NULL)
+	{
+		E(" %s: proc GESTURE file create failed!\n", __func__);
+		goto fail_14;
+	}
+#endif
+
+#ifdef HX_TP_PROC_SENSE_ON_OFF
+	himax_proc_SENSE_ON_OFF_file = proc_create(HIMAX_PROC_SENSE_ON_OFF_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_sense_on_off_ops);
+	if(himax_proc_SENSE_ON_OFF_file == NULL)
+	{
+		E(" %s: proc SENSE_ON_OFF file create failed!\n", __func__);
+		goto fail_15;
+	}
+#endif
+
+	return 0 ;
+
+#ifdef HX_TP_PROC_SENSE_ON_OFF
+	fail_15:
+#endif
+#ifdef HX_SMART_WAKEUP
+	remove_proc_entry( HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir );
+	fail_14:
+	remove_proc_entry( HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir );
+	fail_13:
+#endif
+#ifdef HX_HIGH_SENSE
+	remove_proc_entry( HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir );
+	fail_12:
+#endif
+#ifdef HX_TP_PROC_SELF_TEST
+	remove_proc_entry( HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir );
+	fail_11:
+#endif
+#ifdef HX_TP_PROC_FLASH_DUMP
+	remove_proc_entry( HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir );
+	fail_10:
+#endif
+#ifdef HX_TP_PROC_DEBUG
+	remove_proc_entry( HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir );
+	fail_9:
+#endif
+#ifdef HX_TP_PROC_REGISTER
+	remove_proc_entry( HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir );
+	fail_8:
+#endif
+#ifdef HX_TP_PROC_DIAG
+	remove_proc_entry( HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir );
+	fail_7:
+	remove_proc_entry( HIMAX_PROC_DIAG_ARR_FILE, himax_touch_proc_dir );
+	fail_7_1:
+#endif
+#ifdef HX_TP_PROC_RESET
+	remove_proc_entry( HIMAX_PROC_RESET_FILE, himax_touch_proc_dir );
+	fail_6:
+#endif
+	remove_proc_entry( HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir );
+	fail_5: remove_proc_entry( HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir );
+	fail_4: remove_proc_entry( HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir );
+	fail_3: remove_proc_entry( HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir );
+	fail_2: remove_proc_entry( HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir );
+	fail_1: remove_proc_entry( HIMAX_PROC_TOUCH_FOLDER, NULL );
+	return -ENOMEM;
+}
+
+void himax_touch_proc_deinit(void)
+{
+#ifdef HX_TP_PROC_SENSE_ON_OFF
+	remove_proc_entry( HIMAX_PROC_SENSE_ON_OFF_FILE, himax_touch_proc_dir );
+#endif
+#ifdef HX_SMART_WAKEUP
+	remove_proc_entry( HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir );
+	remove_proc_entry( HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir );
+#endif
+#ifdef HX_DOT_VIEW
+	remove_proc_entry( HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir );
+#endif
+#ifdef HX_TP_PROC_SELF_TEST
+	remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir);
+#endif
+#ifdef HX_TP_PROC_FLASH_DUMP
+	remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir);
+#endif
+#ifdef HX_TP_PROC_DEBUG
+	remove_proc_entry( HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir );
+#endif
+#ifdef HX_TP_PROC_REGISTER
+	remove_proc_entry(HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir);
+#endif
+#ifdef HX_TP_PROC_DIAG
+	remove_proc_entry(HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir);
+#endif
+#ifdef HX_TP_PROC_RESET
+	remove_proc_entry( HIMAX_PROC_RESET_FILE, himax_touch_proc_dir );
+#endif
+	remove_proc_entry( HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir );
+	remove_proc_entry( HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir );
+	remove_proc_entry( HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir );
+	remove_proc_entry( HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir );
+	remove_proc_entry( HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir );
+	remove_proc_entry( HIMAX_PROC_TOUCH_FOLDER, NULL );
+}
+#endif
diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.h b/drivers/input/touchscreen/hxchipset/himax_debug.h
new file mode 100644
index 0000000..91a7ae2
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/himax_debug.h
@@ -0,0 +1,181 @@
+/* Himax Android Driver Sample Code for Himax chipset
+*
+* Copyright (C) 2015 Himax Corporation.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+*/
+
+#include "himax_platform.h"
+#include "himax_common.h"
+
+#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG)
+	#define HIMAX_PROC_TOUCH_FOLDER 	"android_touch"
+	#define HIMAX_PROC_DEBUG_LEVEL_FILE	"debug_level"
+	#define HIMAX_PROC_VENDOR_FILE		"vendor"
+	#define HIMAX_PROC_ATTN_FILE		"attn"
+	#define HIMAX_PROC_INT_EN_FILE		"int_en"
+	#define HIMAX_PROC_LAYOUT_FILE		"layout"
+
+	static struct proc_dir_entry *himax_touch_proc_dir;
+	static struct proc_dir_entry *himax_proc_debug_level_file;
+	static struct proc_dir_entry *himax_proc_vendor_file;
+	static struct proc_dir_entry *himax_proc_attn_file;
+	static struct proc_dir_entry *himax_proc_int_en_file;
+	static struct proc_dir_entry *himax_proc_layout_file;
+
+	uint8_t HX_PROC_SEND_FLAG;
+
+extern int himax_touch_proc_init(void);
+extern void himax_touch_proc_deinit(void);
+bool getFlashDumpGoing(void);
+
+#ifdef HX_TP_PROC_REGISTER
+	#define HIMAX_PROC_REGISTER_FILE	"register"
+	struct proc_dir_entry *himax_proc_register_file;
+	uint8_t register_command[4];
+#endif
+
+#ifdef HX_TP_PROC_DIAG
+	#define HIMAX_PROC_DIAG_FILE	"diag"
+	struct proc_dir_entry *himax_proc_diag_file;
+	#define HIMAX_PROC_DIAG_ARR_FILE	"diag_arr"
+	struct proc_dir_entry *himax_proc_diag_arrange_file;
+
+#ifdef HX_TP_PROC_2T2R
+	static bool Is_2T2R;
+	static uint8_t x_channel_2;
+	static uint8_t y_channel_2;
+	static uint8_t *diag_mutual_2;
+	
+	int16_t *getMutualBuffer_2(void);
+	uint8_t 	getXChannel_2(void);
+	uint8_t 	getYChannel_2(void);
+	
+	void 	setMutualBuffer_2(void);
+	void 	setXChannel_2(uint8_t x);
+	void 	setYChannel_2(uint8_t y);
+#endif
+	uint8_t x_channel;
+	uint8_t y_channel;
+	int16_t *diag_mutual;
+	int16_t *diag_mutual_new;
+	int16_t *diag_mutual_old;
+	uint8_t diag_max_cnt;
+
+	int diag_command;
+	uint8_t diag_coor[128];// = {0xFF};
+	int16_t diag_self[100] = {0};
+
+	int16_t *getMutualBuffer(void);
+	int16_t *getMutualNewBuffer(void);
+	int16_t *getMutualOldBuffer(void);
+	int16_t *getSelfBuffer(void);
+	uint8_t 	getDiagCommand(void);
+	uint8_t 	getXChannel(void);
+	uint8_t 	getYChannel(void);
+	
+	void 	setMutualBuffer(void);
+	void 	setMutualNewBuffer(void);
+	void 	setMutualOldBuffer(void);
+	void 	setXChannel(uint8_t x);
+	void 	setYChannel(uint8_t y);
+	uint8_t	coordinate_dump_enable = 0;
+	struct file	*coordinate_fn;
+#endif
+
+#ifdef HX_TP_PROC_DEBUG
+	#define HIMAX_PROC_DEBUG_FILE	"debug"
+	struct proc_dir_entry *himax_proc_debug_file = NULL;
+
+	bool	fw_update_complete = false;
+	int handshaking_result = 0;
+	unsigned char debug_level_cmd = 0;
+	unsigned char upgrade_fw[128*1024];
+#endif
+
+#ifdef HX_TP_PROC_FLASH_DUMP
+	#define HIMAX_PROC_FLASH_DUMP_FILE	"flash_dump"
+	struct proc_dir_entry *himax_proc_flash_dump_file = NULL;
+
+	static int Flash_Size = 131072;
+	static uint8_t *flash_buffer 				= NULL;
+	static uint8_t flash_command 				= 0;
+	static uint8_t flash_read_step 			= 0;
+	static uint8_t flash_progress 			= 0;
+	static uint8_t flash_dump_complete	= 0;
+	static uint8_t flash_dump_fail 			= 0;
+	static uint8_t sys_operation				= 0;
+	static uint8_t flash_dump_sector	 	= 0;
+	static uint8_t flash_dump_page 			= 0;
+	static bool    flash_dump_going			= false;
+
+	static uint8_t getFlashCommand(void);
+	static uint8_t getFlashDumpComplete(void);
+	static uint8_t getFlashDumpFail(void);
+	static uint8_t getFlashDumpProgress(void);
+	static uint8_t getFlashReadStep(void);
+	//static uint8_t getFlashDumpSector(void);
+	//static uint8_t getFlashDumpPage(void);
+
+	void setFlashBuffer(void);
+	uint8_t getSysOperation(void);
+
+	static void setFlashCommand(uint8_t command);
+	static void setFlashReadStep(uint8_t step);
+	static void setFlashDumpComplete(uint8_t complete);
+	static void setFlashDumpFail(uint8_t fail);
+	static void setFlashDumpProgress(uint8_t progress);
+	void setSysOperation(uint8_t operation);
+	static void setFlashDumpSector(uint8_t sector);
+	static void setFlashDumpPage(uint8_t page);
+	static void setFlashDumpGoing(bool going);
+
+#endif
+
+#ifdef HX_TP_PROC_SELF_TEST
+	#define HIMAX_PROC_SELF_TEST_FILE	"self_test"
+	struct proc_dir_entry *himax_proc_self_test_file = NULL;
+	uint32_t **raw_data_array;
+	uint8_t X_NUM = 0, Y_NUM = 0;
+	uint8_t sel_type = 0x0D;
+#endif
+
+#ifdef HX_TP_PROC_RESET
+#define HIMAX_PROC_RESET_FILE		"reset"
+extern void himax_HW_reset(uint8_t loadconfig,uint8_t int_off);
+struct proc_dir_entry *himax_proc_reset_file 		= NULL;
+#endif
+
+#ifdef HX_HIGH_SENSE
+	#define HIMAX_PROC_HSEN_FILE "HSEN"
+	struct proc_dir_entry *himax_proc_HSEN_file = NULL;
+#endif
+
+#ifdef HX_TP_PROC_SENSE_ON_OFF
+	#define HIMAX_PROC_SENSE_ON_OFF_FILE "SenseOnOff"
+	struct proc_dir_entry *himax_proc_SENSE_ON_OFF_file = NULL;
+#endif
+
+#ifdef HX_RST_PIN_FUNC
+	void himax_HW_reset(uint8_t loadconfig,uint8_t int_off);
+#endif
+
+#ifdef HX_SMART_WAKEUP
+#define HIMAX_PROC_SMWP_FILE "SMWP"
+struct proc_dir_entry *himax_proc_SMWP_file = NULL;
+#define HIMAX_PROC_GESTURE_FILE "GESTURE"
+struct proc_dir_entry *himax_proc_GESTURE_file = NULL;
+uint8_t HX_SMWP_EN = 0;
+//extern bool FAKE_POWER_KEY_SEND;
+#endif
+
+#endif
+
diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.c b/drivers/input/touchscreen/hxchipset/himax_ic.c
new file mode 100644
index 0000000..6ad8dc0
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/himax_ic.c
@@ -0,0 +1,2118 @@
+/* Himax Android Driver Sample Code for HMX83100 chipset
+*
+* Copyright (C) 2015 Himax Corporation.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+*/
+
+#include "himax_ic.h"
+
+static unsigned char i_TP_CRC_FW_128K[]=
+{
+	#include "HX_CRC_128.i"
+};
+static unsigned char i_TP_CRC_FW_64K[]=
+{
+	#include "HX_CRC_64.i"
+};
+static unsigned char i_TP_CRC_FW_124K[]=
+{
+	#include "HX_CRC_124.i"
+};
+static unsigned char i_TP_CRC_FW_60K[]=
+{
+	#include "HX_CRC_60.i"
+};
+
+
+unsigned long	FW_VER_MAJ_FLASH_ADDR;
+unsigned long 	FW_VER_MAJ_FLASH_LENG;
+unsigned long 	FW_VER_MIN_FLASH_ADDR;
+unsigned long 	FW_VER_MIN_FLASH_LENG;
+unsigned long 	CFG_VER_MAJ_FLASH_ADDR;
+unsigned long 	CFG_VER_MAJ_FLASH_LENG;
+unsigned long 	CFG_VER_MIN_FLASH_ADDR;
+unsigned long 	CFG_VER_MIN_FLASH_LENG;
+
+unsigned char	IC_TYPE = 0;
+unsigned char	IC_CHECKSUM = 0;
+
+extern struct himax_ic_data* ic_data;
+
+int himax_hand_shaking(struct i2c_client *client)    //0:Running, 1:Stop, 2:I2C Fail
+{
+	int ret, result;
+	uint8_t hw_reset_check[1];
+	uint8_t hw_reset_check_2[1];
+	uint8_t buf0[2];
+	uint8_t	IC_STATUS_CHECK = 0xAA;	
+
+	memset(hw_reset_check, 0x00, sizeof(hw_reset_check));
+	memset(hw_reset_check_2, 0x00, sizeof(hw_reset_check_2));
+
+	buf0[0] = 0xF2;
+	if (IC_STATUS_CHECK == 0xAA) {
+		buf0[1] = 0xAA;
+		IC_STATUS_CHECK = 0x55;
+	} else {
+		buf0[1] = 0x55;
+		IC_STATUS_CHECK = 0xAA;
+	}
+
+	ret = i2c_himax_master_write(client, buf0, 2, HIMAX_I2C_RETRY_TIMES);
+	if (ret < 0) {
+		E("[Himax]:write 0xF2 failed line: %d \n",__LINE__);
+		goto work_func_send_i2c_msg_fail;
+	}
+	msleep(50); 
+  	
+	buf0[0] = 0xF2;
+	buf0[1] = 0x00;
+	ret = i2c_himax_master_write(client, buf0, 2, HIMAX_I2C_RETRY_TIMES);
+	if (ret < 0) {
+		E("[Himax]:write 0x92 failed line: %d \n",__LINE__);
+		goto work_func_send_i2c_msg_fail;
+	}
+	usleep_range(2000, 4000);
+  	
+	ret = i2c_himax_read(client, 0xD1, hw_reset_check, 1, HIMAX_I2C_RETRY_TIMES);
+	if (ret < 0) {
+		E("[Himax]:i2c_himax_read 0xD1 failed line: %d \n",__LINE__);
+		goto work_func_send_i2c_msg_fail;
+	}
+	
+	if ((IC_STATUS_CHECK != hw_reset_check[0])) {
+		usleep_range(2000, 4000);
+		ret = i2c_himax_read(client, 0xD1, hw_reset_check_2, 1, HIMAX_I2C_RETRY_TIMES);
+		if (ret < 0) {
+			E("[Himax]:i2c_himax_read 0xD1 failed line: %d \n",__LINE__);
+			goto work_func_send_i2c_msg_fail;
+		}
+	
+		if (hw_reset_check[0] == hw_reset_check_2[0]) {
+			result = 1; 
+		} else {
+			result = 0; 
+		}
+	} else {
+		result = 0; 
+	}
+	
+	return result;
+
+work_func_send_i2c_msg_fail:
+	return 2;
+}
+
+void himax_diag_register_set(struct i2c_client *client, uint8_t diag_command)
+{
+	uint8_t tmp_addr[4];
+	uint8_t tmp_data[4];
+
+	if(diag_command != 0)
+		diag_command = diag_command + 5;
+
+	tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0x80;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = diag_command;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+}
+
+void himax_flash_dump_func(struct i2c_client *client, uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer)
+{
+	//struct himax_ts_data *ts = container_of(work, struct himax_ts_data, flash_work);
+
+//	uint8_t sector = 0;
+//	uint8_t page = 0;
+	uint8_t tmp_addr[4];
+	uint8_t tmp_data[4];
+	uint8_t out_buffer[20];
+	uint8_t in_buffer[260] = {0};
+	int page_prog_start = 0;
+	int i = 0;
+
+	himax_sense_off(client);
+	himax_burst_enable(client, 0);
+	/*=============Dump Flash Start=============*/
+	//=====================================
+	// SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780
+	//=====================================
+	tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+	for (page_prog_start = 0; page_prog_start < Flash_Size; page_prog_start = page_prog_start + 256)
+	{
+		//=================================
+		// SPI Transfer Control
+		// Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF
+		// Set read start address  : 0x8000_0028 ==> 0x0000_0000
+		// Set command			   : 0x8000_0024 ==> 0x0000_003B
+		//=================================
+		tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20;
+		tmp_data[3] = 0x69; tmp_data[2] = 0x40; tmp_data[1] = 0x02; tmp_data[0] = 0xFF;
+		himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+		tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28;
+		if (page_prog_start < 0x100)
+		{
+			tmp_data[3] = 0x00;
+			tmp_data[2] = 0x00;
+			tmp_data[1] = 0x00;
+			tmp_data[0] = (uint8_t)page_prog_start;
+		}
+		else if (page_prog_start >= 0x100 && page_prog_start < 0x10000)
+		{
+			tmp_data[3] = 0x00;
+			tmp_data[2] = 0x00;
+			tmp_data[1] = (uint8_t)(page_prog_start >> 8);
+			tmp_data[0] = (uint8_t)page_prog_start;
+		}
+		else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000)
+		{
+			tmp_data[3] = 0x00;
+			tmp_data[2] = (uint8_t)(page_prog_start >> 16);
+			tmp_data[1] = (uint8_t)(page_prog_start >> 8);
+			tmp_data[0] = (uint8_t)page_prog_start;
+		}
+		himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+		tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24;
+		tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x3B;
+		himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+		//==================================
+		// AHB_I2C Burst Read
+		// Set SPI data register : 0x8000_002C ==> 0x00
+		//==================================
+		out_buffer[0] = 0x2C;
+		out_buffer[1] = 0x00;
+		out_buffer[2] = 0x00;
+		out_buffer[3] = 0x80;
+		i2c_himax_write(client, 0x00 ,out_buffer, 4, 3);
+
+		//==================================
+		// Read access : 0x0C ==> 0x00
+		//==================================
+		out_buffer[0] = 0x00;
+		i2c_himax_write(client, 0x0C ,out_buffer, 1, 3);
+
+		//==================================
+		// Read 128 bytes two times
+		//==================================
+		i2c_himax_read(client, 0x08 ,in_buffer, 128, 3);
+		for (i = 0; i < 128; i++)
+			flash_buffer[i + page_prog_start] = in_buffer[i];
+
+		i2c_himax_read(client, 0x08 ,in_buffer, 128, 3);
+		for (i = 0; i < 128; i++)
+			flash_buffer[(i + 128) + page_prog_start] = in_buffer[i];
+
+		I("%s:Verify Progress: %x\n", __func__, page_prog_start);
+	}
+
+/*=============Dump Flash End=============*/
+		//msleep(100);
+		/*
+		for( i=0 ; i<8 ;i++)
+		{
+			for(j=0 ; j<64 ; j++)
+			{
+				setFlashDumpProgress(i*32 + j);
+			}
+		}
+		*/
+	himax_sense_on(client, 0x01);
+
+	return;
+
+}
+
+int himax_chip_self_test(struct i2c_client *client)
+{
+	uint8_t tmp_addr[4];
+	uint8_t tmp_data[128];
+	int pf_value=0x00;
+	uint8_t test_result_id = 0;
+	int j;
+
+	memset(tmp_addr, 0x00, sizeof(tmp_addr));
+	memset(tmp_data, 0x00, sizeof(tmp_data));
+
+	himax_interface_on(client);
+	himax_sense_off(client);
+
+	//Set criteria
+	himax_burst_enable(client, 1);
+
+	tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x94;
+	tmp_data[3] = 0x14; tmp_data[2] = 0xC8; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+	tmp_data[7] = 0x13; tmp_data[6] = 0x60; tmp_data[5] = 0x0A; tmp_data[4] = 0x99;
+
+	himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 8);
+
+	//start selftest
+	// 0x9008_805C ==> 0x0000_0001
+	tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x5C;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+	himax_sense_on(client, 1);
+
+	msleep(2000);
+
+	himax_sense_off(client);
+	msleep(20);
+
+	//=====================================
+	// Read test result ID : 0x9008_8078 ==> 0xA/0xB/0xC/0xF
+	//=====================================
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+	tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x78;
+	himax_register_read(client, tmp_addr, 1, tmp_data);
+
+	test_result_id = tmp_data[0];
+
+	I("%s: check test result, test_result_id=%x, test_result=%x\n", __func__
+	,test_result_id,tmp_data[0]);
+
+	if (test_result_id==0xF) {
+		I("[Himax]: self-test pass\n");
+		pf_value = 0x1;
+	} else {
+		E("[Himax]: self-test fail\n");
+		pf_value = 0x0;
+	}
+	himax_burst_enable(client, 1);
+
+	for (j = 0;j < 10; j++){
+		tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+		tmp_addr[3] = 0x90; tmp_addr[2] = 0x06; tmp_addr[1] = 0x00; tmp_addr[0] = 0x0C;
+		himax_register_read(client, tmp_addr, 1, tmp_data);
+		I("[Himax]: 9006000C = %d\n", tmp_data[0]);
+		if (tmp_data[0] != 0){
+		tmp_data[3] = 0x90; tmp_data[2] = 0x06; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+		if ( i2c_himax_write(client, 0x00 ,tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) {
+			E("%s: i2c access fail!\n", __func__);
+		}
+		tmp_data[0] = 0x00;
+		if ( i2c_himax_write(client, 0x0C ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+			E("%s: i2c access fail!\n", __func__);
+		}
+			i2c_himax_read(client, 0x08, tmp_data, 124,HIMAX_I2C_RETRY_TIMES);
+		}else{
+			break;
+		}
+	}
+
+	himax_sense_on(client, 1);
+	msleep(120);
+
+	return pf_value;
+}
+
+void himax_set_HSEN_enable(struct i2c_client *client, uint8_t HSEN_enable)
+{
+	uint8_t tmp_addr[4];
+	uint8_t tmp_data[4];
+
+	himax_burst_enable(client, 0);
+	tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x50;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = HSEN_enable;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+}
+void himax_get_HSEN_enable(struct i2c_client *client,uint8_t *tmp_data)
+{
+	uint8_t tmp_addr[4];
+
+	tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x50;
+	himax_register_read(client, tmp_addr, 1, tmp_data);
+}
+
+void himax_set_SMWP_enable(struct i2c_client *client, uint8_t SMWP_enable)
+{
+	uint8_t tmp_addr[4];
+	uint8_t tmp_data[4];
+
+	tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x54;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = SMWP_enable;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+}
+
+void himax_get_SMWP_enable(struct i2c_client *client,uint8_t *tmp_data)
+{
+	uint8_t tmp_addr[4];
+
+	tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x54;
+	himax_register_read(client, tmp_addr, 1, tmp_data);
+}
+
+int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte)
+{
+	uint8_t tmp_data[4];
+
+	tmp_data[0] = 0x31;
+	if ( i2c_himax_write(client, 0x13 ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return -EBUSY;
+	}
+	
+	tmp_data[0] = (0x10 | auto_add_4_byte);
+	if ( i2c_himax_write(client, 0x0D ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return -EBUSY;
+	}
+	return 0;
+
+}
+
+void himax_register_read(struct i2c_client *client, uint8_t *read_addr, int read_length, uint8_t *read_data)
+{
+	uint8_t tmp_data[4];
+	int i = 0;
+	int address = 0;
+
+	if(read_length>256)
+	{
+		E("%s: read len over 256!\n", __func__);
+		return;
+	}
+	if (read_length > 1)
+		himax_burst_enable(client, 1);
+	else
+	himax_burst_enable(client, 0);
+	address = (read_addr[3] << 24) + (read_addr[2] << 16) + (read_addr[1] << 8) + read_addr[0];
+	i = address;
+		tmp_data[0] = (uint8_t)i;
+		tmp_data[1] = (uint8_t)(i >> 8);
+		tmp_data[2] = (uint8_t)(i >> 16);
+		tmp_data[3] = (uint8_t)(i >> 24);
+		if ( i2c_himax_write(client, 0x00 ,tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) {
+				E("%s: i2c access fail!\n", __func__);
+				return;
+		 	}
+		tmp_data[0] = 0x00;
+		if ( i2c_himax_write(client, 0x0C ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+				E("%s: i2c access fail!\n", __func__);
+				return;
+		 	}
+		
+		if ( i2c_himax_read(client, 0x08 ,read_data, read_length * 4, HIMAX_I2C_RETRY_TIMES) < 0) {
+			E("%s: i2c access fail!\n", __func__);
+			return;
+		}
+	if (read_length > 1)
+		himax_burst_enable(client, 0);
+}
+
+void himax_flash_read(struct i2c_client *client, uint8_t *reg_byte, uint8_t *read_data)
+{
+    uint8_t tmpbyte[2];
+    
+    if ( i2c_himax_write(client, 0x00 ,&reg_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+	if ( i2c_himax_write(client, 0x01 ,&reg_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+	if ( i2c_himax_write(client, 0x02 ,&reg_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+	if ( i2c_himax_write(client, 0x03 ,&reg_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+    tmpbyte[0] = 0x00;
+    if ( i2c_himax_write(client, 0x0C ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+	if ( i2c_himax_read(client, 0x08 ,&read_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+	if ( i2c_himax_read(client, 0x09 ,&read_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+	if ( i2c_himax_read(client, 0x0A ,&read_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+	if ( i2c_himax_read(client, 0x0B ,&read_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+	if ( i2c_himax_read(client, 0x18 ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}// No bus request
+
+	if ( i2c_himax_read(client, 0x0F ,&tmpbyte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}// idle state
+
+}
+
+void himax_flash_write_burst(struct i2c_client *client, uint8_t * reg_byte, uint8_t * write_data)
+{
+    uint8_t data_byte[8];
+	int i = 0, j = 0;
+
+     for (i = 0; i < 4; i++)
+     { 
+         data_byte[i] = reg_byte[i];
+     }
+     for (j = 4; j < 8; j++)
+     {
+         data_byte[j] = write_data[j-4];
+     }
+	 
+	 if ( i2c_himax_write(client, 0x00 ,data_byte, 8, HIMAX_I2C_RETRY_TIMES) < 0) {
+		 E("%s: i2c access fail!\n", __func__);
+		 return;
+	 }
+
+}
+
+int himax_flash_write_burst_lenth(struct i2c_client *client, uint8_t *reg_byte, uint8_t *write_data, int length)
+{
+    uint8_t data_byte[256];
+	int i = 0, j = 0;
+
+    for (i = 0; i < 4; i++)
+    {
+        data_byte[i] = reg_byte[i];
+    }
+    for (j = 4; j < length + 4; j++)
+    {
+        data_byte[j] = write_data[j - 4];
+    }
+   
+	if ( i2c_himax_write(client, 0x00 ,data_byte, length + 4, HIMAX_I2C_RETRY_TIMES) < 0) {
+		 E("%s: i2c access fail!\n", __func__);
+		 return -EBUSY;
+	}
+
+    return 0;
+}
+
+int himax_register_write(struct i2c_client *client, uint8_t *write_addr, int write_length, uint8_t *write_data)
+{
+	int i =0, address = 0;
+	int ret = 0;
+
+	address = (write_addr[3] << 24) + (write_addr[2] << 16) + (write_addr[1] << 8) + write_addr[0];
+
+	for (i = address; i < address + write_length * 4; i = i + 4)
+	{
+		if (write_length > 1)
+		{
+			ret = himax_burst_enable(client, 1);
+			if(ret)
+				return ret;
+		}
+		else
+		{
+			ret = himax_burst_enable(client, 0);
+			if(ret)
+				return ret;
+		}
+	ret = himax_flash_write_burst_lenth(client, write_addr, write_data, write_length * 4);
+	if(ret < 0)
+		return ret;
+	}
+
+	return 0;
+}
+
+void himax_sense_off(struct i2c_client *client)
+{
+	uint8_t wdt_off = 0x00;
+	uint8_t tmp_addr[4];
+	uint8_t tmp_data[5];	
+
+	himax_burst_enable(client, 0);
+
+	while(wdt_off == 0x00)
+	{
+		// 0x9000_800C ==> 0x0000_AC53
+		tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C;
+		tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0xAC; tmp_data[0] = 0x53;
+		himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+		//=====================================
+    // Read Watch Dog disable password : 0x9000_800C ==> 0x0000_AC53
+    //=====================================
+		tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C;
+		himax_register_read(client, tmp_addr, 1, tmp_data);
+		
+		//Check WDT
+		if (tmp_data[0] == 0x53 && tmp_data[1] == 0xAC && tmp_data[2] == 0x00 && tmp_data[3] == 0x00)
+			wdt_off = 0x01;
+		else
+			wdt_off = 0x00;
+	}
+
+	// VCOM		//0x9008_806C ==> 0x0000_0001
+	tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x6C;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+	msleep(20);
+
+	// 0x9000_0010 ==> 0x0000_00DA
+	tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xDA;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+	//=====================================
+	// Read CPU clock off password : 0x9000_0010 ==> 0x0000_00DA
+	//=====================================
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+	tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10;
+	himax_register_read(client, tmp_addr, 1, tmp_data);
+	I("%s: CPU clock off password data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__
+		,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]);
+
+}
+
+void himax_interface_on(struct i2c_client *client)
+{
+	uint8_t tmp_addr[4];
+	uint8_t tmp_data[5];
+
+    //===========================================
+    //  Any Cmd for ineterface on : 0x9000_0000 ==> 0x0000_0000
+    //===========================================
+    tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00;
+    himax_flash_read(client, tmp_addr, tmp_data); //avoid RD/WR fail
+}
+
+bool wait_wip(struct i2c_client *client, int Timing)
+{
+	uint8_t tmp_addr[4];
+	uint8_t tmp_data[4];
+	uint8_t in_buffer[10];
+	//uint8_t out_buffer[20];
+	int retry_cnt = 0;
+
+	//=====================================
+	// SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780
+	//=====================================
+	tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+	in_buffer[0] = 0x01;
+
+	do
+	{
+		//=====================================
+		// SPI Transfer Control : 0x8000_0020 ==> 0x4200_0003
+		//=====================================
+		tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20;
+		tmp_data[3] = 0x42; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x03;
+		himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+		//=====================================
+		// SPI Command : 0x8000_0024 ==> 0x0000_0005
+		// read 0x8000_002C for 0x01, means wait success
+		//=====================================
+		tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24;
+		tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x05;
+		himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+		in_buffer[0] = in_buffer[1] = in_buffer[2] = in_buffer[3] = 0xFF;
+		tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C;
+		himax_register_read(client, tmp_addr, 1, in_buffer);
+		
+		if ((in_buffer[0] & 0x01) == 0x00)
+			return true;
+
+		retry_cnt++;
+		
+		if (in_buffer[0] != 0x00 || in_buffer[1] != 0x00 || in_buffer[2] != 0x00 || in_buffer[3] != 0x00)
+        	I("%s:Wait wip retry_cnt:%d, buffer[0]=%d, buffer[1]=%d, buffer[2]=%d, buffer[3]=%d \n", __func__, 
+            retry_cnt,in_buffer[0],in_buffer[1],in_buffer[2],in_buffer[3]);
+
+		if (retry_cnt > 100)
+        {        	
+			E("%s: Wait wip error!\n", __func__);
+            return false;
+        }
+		msleep(Timing);
+	}while ((in_buffer[0] & 0x01) == 0x01);
+	return true;
+}
+
+void himax_sense_on(struct i2c_client *client, uint8_t FlashMode)
+{
+	uint8_t tmp_addr[4];
+	uint8_t tmp_data[128];
+
+	himax_interface_on(client);
+	himax_burst_enable(client, 0);
+	//CPU reset
+	// 0x9000_0014 ==> 0x0000_00CA
+	tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xCA;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+	//=====================================
+	// Read pull low CPU reset signal : 0x9000_0014 ==> 0x0000_00CA
+	//=====================================
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+	tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14;
+	himax_register_read(client, tmp_addr, 1, tmp_data);
+
+	I("%s: check pull low CPU reset signal  data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__
+	,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]);
+
+	// 0x9000_0014 ==> 0x0000_0000
+	tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+	//=====================================
+	// Read revert pull low CPU reset signal : 0x9000_0014 ==> 0x0000_0000
+	//=====================================
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+	tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14;
+	himax_register_read(client, tmp_addr, 1, tmp_data);
+
+	I("%s: revert pull low CPU reset signal data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__
+	,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]);
+
+	//=====================================
+  // Reset TCON
+  //=====================================
+  tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0;
+  tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+  himax_flash_write_burst(client, tmp_addr, tmp_data);
+	usleep_range(10000, 20000);
+  tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0;
+  tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01;
+  himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+	if (FlashMode == 0x00)	//SRAM
+	{
+		//=====================================
+		//			Re-map
+		//=====================================
+		tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00;
+		tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xF1;
+		himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4);
+		I("%s:83100_Chip_Re-map ON\n", __func__);
+	}
+	else
+	{
+		//=====================================
+		//			Re-map off
+		//=====================================
+		tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00;
+		tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+		himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4);
+		I("%s:83100_Chip_Re-map OFF\n", __func__);
+	}
+	//=====================================
+	//			CPU clock on
+	//=====================================
+	tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+	himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4);
+
+}
+
+void himax_chip_erase(struct i2c_client *client)
+{
+	uint8_t tmp_addr[4];
+	uint8_t tmp_data[4];
+
+	himax_burst_enable(client, 0);
+
+	//=====================================
+	// SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780
+	//=====================================
+	tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+	//=====================================
+	// Chip Erase
+	// Write Enable : 1. 0x8000_0020 ==> 0x4700_0000
+	//				  2. 0x8000_0024 ==> 0x0000_0006
+	//=====================================
+	tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20;
+	tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+	tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+	//=====================================
+	// Chip Erase
+	// Erase Command : 0x8000_0024 ==> 0x0000_00C7
+	//=====================================
+	tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xC7;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+	
+	msleep(2000);
+	
+	if (!wait_wip(client, 100))
+		E("%s:83100_Chip_Erase Fail\n", __func__);
+
+}
+
+bool himax_block_erase(struct i2c_client *client)
+{
+	uint8_t tmp_addr[4];
+	uint8_t tmp_data[4];
+
+	himax_burst_enable(client, 0);
+
+	//=====================================
+	// SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780
+	//=====================================
+	tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+	//=====================================
+	// Chip Erase
+	// Write Enable : 1. 0x8000_0020 ==> 0x4700_0000
+	//				  2. 0x8000_0024 ==> 0x0000_0006
+	//=====================================
+	tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20;
+	tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+	tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+	//=====================================
+	// Block Erase
+	// Erase Command : 0x8000_0028 ==> 0x0000_0000 //SPI addr
+	//				   0x8000_0020 ==> 0x6700_0000 //control
+	//				   0x8000_0024 ==> 0x0000_0052 //BE
+	//=====================================
+	tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+	
+	tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20;
+	tmp_data[3] = 0x67; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+	
+	tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x52;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+	msleep(1000);
+
+	if (!wait_wip(client, 100))
+	{
+		E("%s:83100_Erase Fail\n", __func__);
+		return false;
+	}
+	else
+	{
+		return true;
+	}
+
+}
+
+bool himax_sector_erase(struct i2c_client *client, int start_addr)
+{
+	uint8_t tmp_addr[4];
+	uint8_t tmp_data[4];
+	int page_prog_start = 0;
+
+	himax_burst_enable(client, 0);
+
+	//=====================================
+	// SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780
+	//=====================================
+	tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+	for (page_prog_start = start_addr; page_prog_start < start_addr + 0x0F000; page_prog_start = page_prog_start + 0x1000)
+		{
+			//=====================================
+			// Chip Erase
+			// Write Enable : 1. 0x8000_0020 ==> 0x4700_0000
+			//				  2. 0x8000_0024 ==> 0x0000_0006
+			//=====================================
+			tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20;
+			tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+			himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+			tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24;
+			tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06;
+			himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+			//=====================================
+			// Sector Erase
+			// Erase Command : 0x8000_0028 ==> 0x0000_0000 //SPI addr
+			// 				0x8000_0020 ==> 0x6700_0000 //control
+			// 				0x8000_0024 ==> 0x0000_0020 //SE
+			//=====================================
+			tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28;
+			if (page_prog_start < 0x100)
+			{
+			 tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = (uint8_t)page_prog_start;
+			}
+			else if (page_prog_start >= 0x100 && page_prog_start < 0x10000)
+			{
+			 tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start;
+			}
+			else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000)
+			{
+			 tmp_data[3] = 0x00; tmp_data[2] = (uint8_t)(page_prog_start >> 16); tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start;
+			}
+			himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+			tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20;
+			tmp_data[3] = 0x67; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+			himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+			tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24;
+			tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x20;
+			himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+			msleep(200);
+
+			if (!wait_wip(client, 100))
+			{
+				E("%s:83100_Erase Fail\n", __func__);
+				return false;
+			}
+		}	
+		return true;
+}
+
+void himax_sram_write(struct i2c_client *client, uint8_t *FW_content)
+{
+	int i = 0;
+	uint8_t tmp_addr[4];
+	uint8_t tmp_data[128];
+	int FW_length = 0x4000; // 0x4000 = 16K bin file
+	
+	//himax_sense_off(client);
+
+	for (i = 0; i < FW_length; i = i + 128) 
+	{
+		himax_burst_enable(client, 1);
+
+		if (i < 0x100)
+		{
+			tmp_addr[3] = 0x08; 
+			tmp_addr[2] = 0x00; 
+			tmp_addr[1] = 0x00; 
+			tmp_addr[0] = i;
+		}
+		else if (i >= 0x100 && i < 0x10000)
+		{
+			tmp_addr[3] = 0x08; 
+			tmp_addr[2] = 0x00; 
+			tmp_addr[1] = (i >> 8); 
+			tmp_addr[0] = i;
+		}
+
+		memcpy(&tmp_data[0], &FW_content[i], 128);
+		himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 128);
+
+	}
+
+	if (!wait_wip(client, 100))
+		E("%s:83100_Sram_Write Fail\n", __func__);
+}
+
+bool himax_sram_verify(struct i2c_client *client, uint8_t *FW_File, int FW_Size)
+{
+	int i = 0;
+	uint8_t out_buffer[20];
+	uint8_t in_buffer[128];
+	uint8_t *get_fw_content;
+
+	get_fw_content = kzalloc(0x4000*sizeof(uint8_t), GFP_KERNEL);
+	if (!get_fw_content)
+		return false;
+
+	for (i = 0; i < 0x4000; i = i + 128)
+	{
+		himax_burst_enable(client, 1);
+
+		//==================================
+		//	AHB_I2C Burst Read
+		//==================================
+		if (i < 0x100)
+		{
+			out_buffer[3] = 0x08; 
+			out_buffer[2] = 0x00; 
+			out_buffer[1] = 0x00; 
+			out_buffer[0] = i;
+		}
+		else if (i >= 0x100 && i < 0x10000)
+		{
+			out_buffer[3] = 0x08; 
+			out_buffer[2] = 0x00; 
+			out_buffer[1] = (i >> 8); 
+			out_buffer[0] = i;
+		}
+
+		if ( i2c_himax_write(client, 0x00 ,out_buffer, 4, HIMAX_I2C_RETRY_TIMES) < 0) {
+			E("%s: i2c access fail!\n", __func__);
+			return false;
+		}
+
+		out_buffer[0] = 0x00;		
+		if ( i2c_himax_write(client, 0x0C ,out_buffer, 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+			E("%s: i2c access fail!\n", __func__);
+			return false;
+		}
+
+		if ( i2c_himax_read(client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES) < 0) {
+			E("%s: i2c access fail!\n", __func__);
+			return false;
+		}
+		memcpy(&get_fw_content[i], &in_buffer[0], 128);
+	}
+
+	for (i = 0; i < FW_Size; i++)
+		{
+	        if (FW_File[i] != get_fw_content[i])
+	        	{
+					E("%s: fail! SRAM[%x]=%x NOT CRC_ifile=%x\n", __func__,i,get_fw_content[i],FW_File[i]);
+		            return false;
+	        	}
+		}
+
+	kfree(get_fw_content);
+
+	return true;
+}
+
+void himax_flash_programming(struct i2c_client *client, uint8_t *FW_content, int FW_Size)
+{
+	int page_prog_start = 0;
+	int program_length = 48;
+	int i = 0, j = 0, k = 0;
+	uint8_t tmp_addr[4];
+	uint8_t tmp_data[4];
+	uint8_t buring_data[256];    // Read for flash data, 128K
+									 // 4 bytes for 0x80002C padding
+
+	//himax_interface_on(client);
+	himax_burst_enable(client, 0);
+
+	//=====================================
+	// SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780
+	//=====================================
+	tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+	for (page_prog_start = 0; page_prog_start < FW_Size; page_prog_start = page_prog_start + 256)
+	{
+		//msleep(5);
+		//=====================================
+		// Write Enable : 1. 0x8000_0020 ==> 0x4700_0000
+		//				  2. 0x8000_0024 ==> 0x0000_0006
+		//=====================================
+		tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20;
+		tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+		himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+		tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24;
+		tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06;
+		himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+		//=================================
+		// SPI Transfer Control
+		// Set 256 bytes page write : 0x8000_0020 ==> 0x610F_F000
+		// Set read start address	: 0x8000_0028 ==> 0x0000_0000			
+		//=================================
+		tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20;
+		tmp_data[3] = 0x61; tmp_data[2] = 0x0F; tmp_data[1] = 0xF0; tmp_data[0] = 0x00;
+		// data bytes should be 0x6100_0000 + ((word_number)*4-1)*4096 = 0x6100_0000 + 0xFF000 = 0x610F_F000
+		// Programmable size = 1 page = 256 bytes, word_number = 256 byte / 4 = 64
+		himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+		tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28;
+		//tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; // Flash start address 1st : 0x0000_0000
+
+		if (page_prog_start < 0x100)
+		{
+			tmp_data[3] = 0x00; 
+			tmp_data[2] = 0x00; 
+			tmp_data[1] = 0x00; 
+			tmp_data[0] = (uint8_t)page_prog_start;
+		}
+		else if (page_prog_start >= 0x100 && page_prog_start < 0x10000)
+		{
+			tmp_data[3] = 0x00; 
+			tmp_data[2] = 0x00; 
+			tmp_data[1] = (uint8_t)(page_prog_start >> 8); 
+			tmp_data[0] = (uint8_t)page_prog_start;
+		}
+		else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000)
+		{
+			tmp_data[3] = 0x00; 
+			tmp_data[2] = (uint8_t)(page_prog_start >> 16); 
+			tmp_data[1] = (uint8_t)(page_prog_start >> 8); 
+			tmp_data[0] = (uint8_t)page_prog_start;
+		}
+		
+		himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+
+		//=================================
+		// Send 16 bytes data : 0x8000_002C ==> 16 bytes data	  
+		//=================================
+		buring_data[0] = 0x2C;
+		buring_data[1] = 0x00;
+		buring_data[2] = 0x00;
+		buring_data[3] = 0x80;
+		
+		for (i = /*0*/page_prog_start, j = 0; i < 16 + page_prog_start/**/; i++, j++)	/// <------ bin file
+		{
+			buring_data[j + 4] = FW_content[i];
+		}
+
+
+		if ( i2c_himax_write(client, 0x00 ,buring_data, 20, HIMAX_I2C_RETRY_TIMES) < 0) {
+			E("%s: i2c access fail!\n", __func__);
+			return;
+		}
+		//=================================
+		// Write command : 0x8000_0024 ==> 0x0000_0002
+		//=================================
+		tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24;
+		tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x02;
+		himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+		//=================================
+		// Send 240 bytes data : 0x8000_002C ==> 240 bytes data	 
+		//=================================
+
+		for (j = 0; j < 5; j++)
+		{
+			for (i = (page_prog_start + 16 + (j * 48)), k = 0; i < (page_prog_start + 16 + (j * 48)) + program_length; i++, k++)   /// <------ bin file
+			{
+				buring_data[k+4] = FW_content[i];//(byte)i;
+			}
+
+			if ( i2c_himax_write(client, 0x00 ,buring_data, program_length+4, HIMAX_I2C_RETRY_TIMES) < 0) {
+				E("%s: i2c access fail!\n", __func__);
+				return;
+			}
+
+		}
+
+		if (!wait_wip(client, 1))
+			E("%s:83100_Flash_Programming Fail\n", __func__);
+	}
+}
+
+bool himax_check_chip_version(struct i2c_client *client)
+{
+	uint8_t tmp_addr[4];
+	uint8_t tmp_data[4];
+	uint8_t ret_data = 0x00;
+	int i = 0;
+	int ret = 0;
+	himax_sense_off(client);
+	for (i = 0; i < 5; i++)
+	{
+		// 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver)
+		tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20;
+		tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01;
+		ret = himax_register_write(client, tmp_addr, 1, tmp_data);
+		if(ret)
+			return false;
+
+		// 2. Set bank as 0 (0x8001_BD01 = 0x0000_0000)
+		tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xBD; tmp_addr[0] = 0x01;
+		tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+		ret = himax_register_write(client, tmp_addr, 1, tmp_data);
+		if(ret)
+			return false;
+
+		// 3. Read driver ID register RF4H 1 byte (0x8001_F401)
+		//	  Driver register RF4H 1 byte value = 0x84H, read back value will become 0x84848484
+		tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xF4; tmp_addr[0] = 0x01;
+		himax_register_read(client, tmp_addr, 1, tmp_data);
+		ret_data = tmp_data[0];
+
+		I("%s:Read driver IC ID = %X\n", __func__, ret_data);
+		if (ret_data == 0x84)
+		{
+			IC_TYPE         = HX_83100_SERIES_PWON;
+			//himax_sense_on(client, 0x01);
+			ret_data = true;
+			break;
+		}
+		else
+		{
+			ret_data = false;
+			E("%s:Read driver ID register Fail:\n", __func__);
+		}
+	}
+	// 4. After read finish, set DDREG_Req = 0 (0x9000_0020 = 0x0000_0000) (Unlock register R/W from driver)
+	tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+	himax_register_write(client, tmp_addr, 1, tmp_data);
+	//himax_sense_on(client, 0x01);
+	return ret_data;
+}
+
+#if 1
+int himax_check_CRC(struct i2c_client *client, int mode)
+{
+	bool burnFW_success = false;
+	uint8_t tmp_addr[4];
+	uint8_t tmp_data[4];
+	int tmp_value;
+	int CRC_value = 0;
+
+	memset(tmp_data, 0x00, sizeof(tmp_data));
+
+	if (1)
+	{
+		if(mode == fw_image_60k)
+		{
+			himax_sram_write(client, (i_TP_CRC_FW_60K));
+			burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_60K, 0x4000);
+		}
+		else if(mode == fw_image_64k)
+		{
+			himax_sram_write(client, (i_TP_CRC_FW_64K));
+			burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_64K, 0x4000);
+		}
+		else if(mode == fw_image_124k)
+		{
+			himax_sram_write(client, (i_TP_CRC_FW_124K));
+			burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_124K, 0x4000);
+		}
+		else if(mode == fw_image_128k)
+		{
+			himax_sram_write(client, (i_TP_CRC_FW_128K));
+			burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_128K, 0x4000);
+		}
+		if (burnFW_success)
+		{
+			I("%s: Start to do CRC FW mode=%d \n", __func__,mode);
+			himax_sense_on(client, 0x00);	// run CRC firmware
+
+			while(true)
+			{
+				msleep(100);
+
+				tmp_addr[3] = 0x90; 
+				tmp_addr[2] = 0x08; 
+				tmp_addr[1] = 0x80; 
+				tmp_addr[0] = 0x94;
+				himax_register_read(client, tmp_addr, 1, tmp_data);
+
+				I("%s: CRC from firmware is %x, %x, %x, %x \n", __func__,tmp_data[3],
+					tmp_data[2],tmp_data[1],tmp_data[0]);
+
+				if (tmp_data[3] == 0xFF && tmp_data[2] == 0xFF && tmp_data[1] == 0xFF && tmp_data[0] == 0xFF)
+				{ 
+					}
+				else
+					break;
+			}
+
+			CRC_value = tmp_data[3];
+
+			tmp_value = tmp_data[2] << 8;
+			CRC_value += tmp_value;
+
+			tmp_value = tmp_data[1] << 16;
+			CRC_value += tmp_value;
+
+			tmp_value = tmp_data[0] << 24;
+			CRC_value += tmp_value;
+
+			I("%s: CRC Value is %x \n", __func__, CRC_value);
+
+			//Close Remapping
+	        //=====================================
+	        //          Re-map close
+	        //=====================================
+	        tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00;
+	        tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+	        himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4);
+			return CRC_value;				
+		}
+		else
+		{
+			E("%s: SRAM write fail\n", __func__);
+			return 0;
+		}		
+	}
+	else
+		I("%s: NO CRC Check File \n", __func__);
+
+	return 0;
+}
+
+bool Calculate_CRC_with_AP(unsigned char *FW_content , int CRC_from_FW, int mode)
+{
+	uint8_t tmp_data[4];
+	int i, j;
+	int fw_data;
+	int fw_data_2;
+	int CRC = 0xFFFFFFFF;
+	int PolyNomial = 0x82F63B78;
+	int length = 0;
+	
+	if (mode == fw_image_128k)
+		length = 0x8000;
+	else if (mode == fw_image_124k)
+		length = 0x7C00;
+	else if (mode == fw_image_64k)
+		length = 0x4000;
+	else //if (mode == fw_image_60k)
+		length = 0x3C00;
+
+	for (i = 0; i < length; i++)
+	{
+		fw_data = FW_content[i * 4 ];
+		
+		for (j = 1; j < 4; j++)
+		{
+			fw_data_2 = FW_content[i * 4 + j];
+			fw_data += (fw_data_2) << (8 * j);
+		}
+
+		CRC = fw_data ^ CRC;
+
+		for (j = 0; j < 32; j++)
+		{
+			if ((CRC % 2) != 0)
+			{
+				CRC = ((CRC >> 1) & 0x7FFFFFFF) ^ PolyNomial;				
+			}
+			else
+			{
+				CRC = (((CRC >> 1) ^ 0x7FFFFFFF)& 0x7FFFFFFF);				
+			}
+		}
+	}
+
+	I("%s: CRC calculate from bin file is %x \n", __func__, CRC);
+
+	tmp_data[0] = (uint8_t)(CRC >> 24);
+	tmp_data[1] = (uint8_t)(CRC >> 16);
+	tmp_data[2] = (uint8_t)(CRC >> 8);
+	tmp_data[3] = (uint8_t) CRC;
+
+	CRC = tmp_data[0];
+	CRC += tmp_data[1] << 8;			
+	CRC += tmp_data[2] << 16;
+	CRC += tmp_data[3] << 24;
+
+	I("%s: CRC calculate from bin file REVERSE %x \n", __func__, CRC);
+	I("%s: CRC calculate from FWis %x \n", __func__, CRC_from_FW);
+	if (CRC_from_FW == CRC)
+		return true;
+	else
+		return false;
+}
+#endif
+
+int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref)
+{
+	int CRC_from_FW = 0;
+	int burnFW_success = 0;
+
+	if (len != 0x10000)   //64k
+    {
+    	E("%s: The file size is not 64K bytes\n", __func__);
+    	return false;
+		}
+	himax_sense_off(client);
+	msleep(500);
+	himax_interface_on(client);
+  if (!himax_sector_erase(client, 0x00000))
+			{
+            E("%s:Sector erase fail!Please restart the IC.\n", __func__);
+            return false;
+      }
+	himax_flash_programming(client, fw, 0x0F000);
+
+	//burnFW_success = himax_83100_Verify(fw, len);
+	//if(burnFW_success==false)
+	//	return burnFW_success;
+
+	CRC_from_FW = himax_check_CRC(client,fw_image_60k);
+	burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_60k);
+	//himax_sense_on(client, 0x01);
+	return burnFW_success;
+}
+
+int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref)
+{
+	int CRC_from_FW = 0;
+	int burnFW_success = 0;
+
+	if (len != 0x10000)   //64k
+  {
+    	E("%s: The file size is not 64K bytes\n", __func__);
+    	return false;
+	}
+	himax_sense_off(client);
+	msleep(500);
+	himax_interface_on(client);
+	himax_chip_erase(client);
+	himax_flash_programming(client, fw, len);
+
+	//burnFW_success = himax_83100_Verify(fw, len);
+	//if(burnFW_success==false)
+	//	return burnFW_success;
+
+	CRC_from_FW = himax_check_CRC(client,fw_image_64k);
+	burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_64k);
+	//himax_sense_on(client, 0x01);
+	return burnFW_success;
+}
+
+int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref)
+{
+	int CRC_from_FW = 0;
+	int burnFW_success = 0;
+
+	if (len != 0x20000)   //128k
+  {
+    	E("%s: The file size is not 128K bytes\n", __func__);
+    	return false;
+	}
+	himax_sense_off(client);
+	msleep(500);
+	himax_interface_on(client);
+	if (!himax_block_erase(client))
+    	{
+            E("%s:Block erase fail!Please restart the IC.\n", __func__);
+            return false;
+      }
+
+    if (!himax_sector_erase(client, 0x10000))
+    	{
+            E("%s:Sector erase fail!Please restart the IC.\n", __func__);
+            return false;
+      }
+	himax_flash_programming(client, fw, 0x1F000);
+
+
+	//burnFW_success = himax_83100_Verify(fw, len);
+	//if(burnFW_success==false)
+	//	return burnFW_success;
+
+	CRC_from_FW = himax_check_CRC(client,fw_image_124k);
+	burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_124k);
+	//himax_sense_on(client, 0x01);
+	return burnFW_success;
+}
+
+int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref)
+{
+	int CRC_from_FW = 0;
+	int burnFW_success = 0;
+
+	if (len != 0x20000)   //128k
+  {
+    	E("%s: The file size is not 128K bytes\n", __func__);
+    	return false;
+	}
+	himax_sense_off(client);
+	msleep(500);
+	himax_interface_on(client);
+	himax_chip_erase(client);
+
+	himax_flash_programming(client, fw, len);
+
+	//burnFW_success = himax_83100_Verify(fw, len);
+	//if(burnFW_success==false)
+	//	return burnFW_success;
+
+	CRC_from_FW = himax_check_CRC(client,fw_image_128k);
+	burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_128k);
+	//himax_sense_on(client, 0x01);
+	return burnFW_success;
+}
+
+void himax_touch_information(struct i2c_client *client)
+{
+	uint8_t cmd[4];
+	char data[12] = {0};
+
+	I("%s:IC_TYPE =%d\n", __func__,IC_TYPE);
+
+	if(IC_TYPE == HX_83100_SERIES_PWON)
+	{
+		cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xF8;
+		himax_register_read(client, cmd, 1, data);
+
+		ic_data->HX_RX_NUM				= data[1];
+		ic_data->HX_TX_NUM				= data[2];
+		ic_data->HX_MAX_PT				= data[3];
+
+		cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xFC;
+		himax_register_read(client, cmd, 1, data);
+
+	  if((data[1] & 0x04) == 0x04) {
+			ic_data->HX_XY_REVERSE = true;
+	  } else {
+			ic_data->HX_XY_REVERSE = false;
+	  }
+		ic_data->HX_Y_RES = data[3]*256;
+		cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x01; cmd[0] = 0x00;
+		himax_register_read(client, cmd, 1, data);
+		ic_data->HX_Y_RES = ic_data->HX_Y_RES + data[0];
+		ic_data->HX_X_RES = data[1]*256 + data[2];
+		cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0x8C;
+		himax_register_read(client, cmd, 1, data);
+	  if((data[0] & 0x01) == 1) {
+			ic_data->HX_INT_IS_EDGE = true;
+	  } else {
+			ic_data->HX_INT_IS_EDGE = false;
+	  }
+	  if (ic_data->HX_RX_NUM > 40)
+			ic_data->HX_RX_NUM = 29;
+	  if (ic_data->HX_TX_NUM > 20)
+			ic_data->HX_TX_NUM = 16;
+	  if (ic_data->HX_MAX_PT > 10)
+			ic_data->HX_MAX_PT = 10;
+	  if (ic_data->HX_Y_RES > 2000)
+			ic_data->HX_Y_RES = 1280;
+	  if (ic_data->HX_X_RES > 2000)
+			ic_data->HX_X_RES = 720;
+#ifdef HX_EN_MUT_BUTTON
+		cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xE8;
+		himax_register_read(client, cmd, 1, data);
+		ic_data->HX_BT_NUM				= data[3];
+#endif
+		I("%s:HX_RX_NUM =%d,HX_TX_NUM =%d,HX_MAX_PT=%d \n", __func__,ic_data->HX_RX_NUM,ic_data->HX_TX_NUM,ic_data->HX_MAX_PT);
+		I("%s:HX_XY_REVERSE =%d,HX_Y_RES =%d,HX_X_RES=%d \n", __func__,ic_data->HX_XY_REVERSE,ic_data->HX_Y_RES,ic_data->HX_X_RES);
+		I("%s:HX_INT_IS_EDGE =%d \n", __func__,ic_data->HX_INT_IS_EDGE);
+	}
+	else
+	{
+		ic_data->HX_RX_NUM				= 0;
+		ic_data->HX_TX_NUM				= 0;
+		ic_data->HX_BT_NUM				= 0;
+		ic_data->HX_X_RES				= 0;
+		ic_data->HX_Y_RES				= 0;
+		ic_data->HX_MAX_PT				= 0;
+		ic_data->HX_XY_REVERSE		= false;
+		ic_data->HX_INT_IS_EDGE		= false;
+	}
+}
+
+void himax_read_FW_ver(struct i2c_client *client)
+{
+	uint8_t cmd[4];
+	uint8_t data[64] = {0};
+
+	//=====================================
+	// Read FW version : 0x0000_E303
+	//=====================================
+	cmd[3] = 0x00; cmd[2] = 0x00; cmd[1] = 0xE3; cmd[0] = 0x00;
+	himax_register_read(client, cmd, 1, data);
+
+	ic_data->vendor_config_ver = data[3]<<8;
+
+	cmd[3] = 0x00; cmd[2] = 0x00; cmd[1] = 0xE3; cmd[0] = 0x04;
+	himax_register_read(client, cmd, 1, data);
+
+	ic_data->vendor_config_ver = data[0] | ic_data->vendor_config_ver;
+	I("CFG_VER : %X \n",ic_data->vendor_config_ver);
+
+	cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0x28;
+	himax_register_read(client, cmd, 1, data);
+
+	ic_data->vendor_fw_ver = data[0]<<8 | data[1];
+	I("FW_VER : %X \n",ic_data->vendor_fw_ver);
+
+
+	return;
+}
+
+bool himax_ic_package_check(struct i2c_client *client)
+{
+#if 0
+	uint8_t cmd[3];
+	uint8_t data[3];
+
+	memset(cmd, 0x00, sizeof(cmd));
+	memset(data, 0x00, sizeof(data));
+
+	if (i2c_himax_read(client, 0xD1, cmd, 3, HIMAX_I2C_RETRY_TIMES) < 0)
+		return false ;
+
+	if (i2c_himax_read(client, 0x31, data, 3, HIMAX_I2C_RETRY_TIMES) < 0)
+		return false;
+
+	if((data[0] == 0x85 && data[1] == 0x29))
+		{
+			IC_TYPE         = HX_85XX_F_SERIES_PWON;
+    	IC_CHECKSUM 		= HX_TP_BIN_CHECKSUM_CRC;
+    	//Himax: Set FW and CFG Flash Address                                          
+    	FW_VER_MAJ_FLASH_ADDR   = 64901;  //0xFD85                              
+    	FW_VER_MAJ_FLASH_LENG   = 1;
+    	FW_VER_MIN_FLASH_ADDR   = 64902;  //0xFD86                                     
+    	FW_VER_MIN_FLASH_LENG   = 1;
+    	CFG_VER_MAJ_FLASH_ADDR 	= 64928;   //0xFDA0         
+    	CFG_VER_MAJ_FLASH_LENG 	= 12;
+    	CFG_VER_MIN_FLASH_ADDR 	= 64940;   //0xFDAC
+    	CFG_VER_MIN_FLASH_LENG 	= 12;
+			I("Himax IC package 852x F\n");
+			}
+	if((data[0] == 0x85 && data[1] == 0x30) || (cmd[0] == 0x05 && cmd[1] == 0x85 && cmd[2] == 0x29))
+		{
+			IC_TYPE 		= HX_85XX_E_SERIES_PWON;
+			IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC;
+			//Himax: Set FW and CFG Flash Address                                          
+			FW_VER_MAJ_FLASH_ADDR	= 133;	//0x0085                              
+			FW_VER_MAJ_FLASH_LENG	= 1;                                               
+			FW_VER_MIN_FLASH_ADDR	= 134;  //0x0086                                     
+			FW_VER_MIN_FLASH_LENG	= 1;                                                
+			CFG_VER_MAJ_FLASH_ADDR = 160;	//0x00A0         
+			CFG_VER_MAJ_FLASH_LENG = 12; 	                                 
+			CFG_VER_MIN_FLASH_ADDR = 172;	//0x00AC
+			CFG_VER_MIN_FLASH_LENG = 12;   
+			I("Himax IC package 852x E\n");
+		}
+	else if((data[0] == 0x85 && data[1] == 0x31))
+		{
+			IC_TYPE         = HX_85XX_ES_SERIES_PWON;
+    	IC_CHECKSUM 		= HX_TP_BIN_CHECKSUM_CRC;
+    	//Himax: Set FW and CFG Flash Address                                          
+    	FW_VER_MAJ_FLASH_ADDR   = 133;  //0x0085                              
+    	FW_VER_MAJ_FLASH_LENG   = 1;
+    	FW_VER_MIN_FLASH_ADDR   = 134;  //0x0086                                     
+    	FW_VER_MIN_FLASH_LENG   = 1;
+    	CFG_VER_MAJ_FLASH_ADDR 	= 160;   //0x00A0         
+    	CFG_VER_MAJ_FLASH_LENG 	= 12;
+    	CFG_VER_MIN_FLASH_ADDR 	= 172;   //0x00AC
+    	CFG_VER_MIN_FLASH_LENG 	= 12;
+			I("Himax IC package 852x ES\n");
+			}
+	else if ((data[0] == 0x85 && data[1] == 0x28) || (cmd[0] == 0x04 && cmd[1] == 0x85 &&
+		(cmd[2] == 0x26 || cmd[2] == 0x27 || cmd[2] == 0x28))) {
+		IC_TYPE                = HX_85XX_D_SERIES_PWON;
+		IC_CHECKSUM            = HX_TP_BIN_CHECKSUM_CRC;
+		//Himax: Set FW and CFG Flash Address
+		FW_VER_MAJ_FLASH_ADDR  = 133;                    // 0x0085
+		FW_VER_MAJ_FLASH_LENG  = 1;
+		FW_VER_MIN_FLASH_ADDR  = 134;                    // 0x0086
+		FW_VER_MIN_FLASH_LENG  = 1;
+		CFG_VER_MAJ_FLASH_ADDR = 160;                    // 0x00A0
+		CFG_VER_MAJ_FLASH_LENG = 12;
+		CFG_VER_MIN_FLASH_ADDR = 172;                    // 0x00AC
+		CFG_VER_MIN_FLASH_LENG = 12;
+		I("Himax IC package 852x D\n");
+	} else if ((data[0] == 0x85 && data[1] == 0x23) || (cmd[0] == 0x03 && cmd[1] == 0x85 &&
+			(cmd[2] == 0x26 || cmd[2] == 0x27 || cmd[2] == 0x28 || cmd[2] == 0x29))) {
+		IC_TYPE                = HX_85XX_C_SERIES_PWON;
+		IC_CHECKSUM            = HX_TP_BIN_CHECKSUM_SW;
+		//Himax: Set FW and CFG Flash Address
+		FW_VER_MAJ_FLASH_ADDR  = 133;                   // 0x0085
+		FW_VER_MAJ_FLASH_LENG  = 1;
+		FW_VER_MIN_FLASH_ADDR  = 134;                   // 0x0086
+		FW_VER_MIN_FLASH_LENG  = 1;
+		CFG_VER_MAJ_FLASH_ADDR = 135;                   // 0x0087
+		CFG_VER_MAJ_FLASH_LENG = 12;
+		CFG_VER_MIN_FLASH_ADDR = 147;                   // 0x0093
+		CFG_VER_MIN_FLASH_LENG = 12;
+		I("Himax IC package 852x C\n");
+	} else if ((data[0] == 0x85 && data[1] == 0x26) ||
+		   (cmd[0] == 0x02 && cmd[1] == 0x85 &&
+		   (cmd[2] == 0x19 || cmd[2] == 0x25 || cmd[2] == 0x26))) {
+		IC_TYPE                = HX_85XX_B_SERIES_PWON;
+		IC_CHECKSUM            = HX_TP_BIN_CHECKSUM_SW;
+		//Himax: Set FW and CFG Flash Address
+		FW_VER_MAJ_FLASH_ADDR  = 133;                   // 0x0085
+		FW_VER_MAJ_FLASH_LENG  = 1;
+		FW_VER_MIN_FLASH_ADDR  = 728;                   // 0x02D8
+		FW_VER_MIN_FLASH_LENG  = 1;
+		CFG_VER_MAJ_FLASH_ADDR = 692;                   // 0x02B4
+		CFG_VER_MAJ_FLASH_LENG = 3;
+		CFG_VER_MIN_FLASH_ADDR = 704;                   // 0x02C0
+		CFG_VER_MIN_FLASH_LENG = 3;
+		I("Himax IC package 852x B\n");
+	} else if ((data[0] == 0x85 && data[1] == 0x20) || (cmd[0] == 0x01 &&
+			cmd[1] == 0x85 && cmd[2] == 0x19)) {
+		IC_TYPE     = HX_85XX_A_SERIES_PWON;
+		IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW;
+		I("Himax IC package 852x A\n");
+	} else {
+		E("Himax IC package incorrect!!\n");
+	}*/
+#else
+		IC_TYPE         = HX_83100_SERIES_PWON;
+    IC_CHECKSUM 		= HX_TP_BIN_CHECKSUM_CRC;
+    //Himax: Set FW and CFG Flash Address
+    FW_VER_MAJ_FLASH_ADDR   = 57384;   //0xE028
+    FW_VER_MAJ_FLASH_LENG   = 1;
+    FW_VER_MIN_FLASH_ADDR   = 57385;   //0xE029
+    FW_VER_MIN_FLASH_LENG   = 1;
+    CFG_VER_MAJ_FLASH_ADDR 	= 58115;  //0xE303
+    CFG_VER_MAJ_FLASH_LENG 	= 1;
+    CFG_VER_MIN_FLASH_ADDR 	= 58116;  //0xE304
+    CFG_VER_MIN_FLASH_LENG 	= 1;
+		I("Himax IC package 83100_in\n");
+
+#endif
+	return true;
+}
+
+void himax_read_event_stack(struct i2c_client *client, 	uint8_t *buf, uint8_t length)
+{
+	uint8_t cmd[4];
+
+	cmd[3] = 0x90; cmd[2] = 0x06; cmd[1] = 0x00; cmd[0] = 0x00;	
+	if ( i2c_himax_write(client, 0x00 ,cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);		
+	}
+
+	cmd[0] = 0x00;		
+	if ( i2c_himax_write(client, 0x0C ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);		
+	}
+
+	i2c_himax_read(client, 0x08, buf, length, HIMAX_I2C_RETRY_TIMES);
+}
+
+#if 0
+static void himax_83100_Flash_Write(uint8_t * reg_byte, uint8_t * write_data)
+{
+	uint8_t tmpbyte[2];
+
+    if ( i2c_himax_write(private_ts->client, 0x00 ,&reg_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+	if ( i2c_himax_write(private_ts->client, 0x01 ,&reg_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+	if ( i2c_himax_write(private_ts->client, 0x02 ,&reg_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+	if ( i2c_himax_write(private_ts->client, 0x03 ,&reg_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+	if ( i2c_himax_write(private_ts->client, 0x04 ,&write_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+	if ( i2c_himax_write(private_ts->client, 0x05 ,&write_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+	if ( i2c_himax_write(private_ts->client, 0x06 ,&write_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+	if ( i2c_himax_write(private_ts->client, 0x07 ,&write_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+    if (isBusrtOn == false)
+    {
+        tmpbyte[0] = 0x01;
+		if ( i2c_himax_write(private_ts->client, 0x0C ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+		}
+    }
+}
+#endif
+#if 0
+static void himax_83100_Flash_Burst_Write(uint8_t * reg_byte, uint8_t * write_data)
+{
+    //uint8_t tmpbyte[2];
+	int i = 0;
+
+	if ( i2c_himax_write(private_ts->client, 0x00 ,&reg_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+	if ( i2c_himax_write(private_ts->client, 0x01 ,&reg_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+	if ( i2c_himax_write(private_ts->client, 0x02 ,&reg_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+	if ( i2c_himax_write(private_ts->client, 0x03 ,&reg_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		return;
+	}
+
+    // Write 256 bytes with continue burst mode
+    for (i = 0; i < 256; i = i + 4)
+    {
+		if ( i2c_himax_write(private_ts->client, 0x04 ,&write_data[i], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+			E("%s: i2c access fail!\n", __func__);
+			return;
+		}
+
+		if ( i2c_himax_write(private_ts->client, 0x05 ,&write_data[i+1], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+			E("%s: i2c access fail!\n", __func__);
+			return;
+		}
+
+		if ( i2c_himax_write(private_ts->client, 0x06 ,&write_data[i+2], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+			E("%s: i2c access fail!\n", __func__);
+			return;
+		}
+
+		if ( i2c_himax_write(private_ts->client, 0x07 ,&write_data[i+3], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+			E("%s: i2c access fail!\n", __func__);
+			return;
+		}
+    }
+
+    //if (isBusrtOn == false)
+    //{
+    //   tmpbyte[0] = 0x01;
+	//	if ( i2c_himax_write(private_ts->client, 0x0C ,&tmpbyte[0], 1, 3) < 0) {
+	//	E("%s: i2c access fail!\n", __func__);
+	//	return;
+	//	}
+    //}
+
+}
+#endif
+
+#if 0
+static bool himax_83100_Verify(uint8_t *FW_File, int FW_Size)
+{
+	uint8_t tmp_addr[4];
+	uint8_t tmp_data[4];
+	uint8_t out_buffer[20];
+	uint8_t in_buffer[260];
+
+	int fail_addr=0, fail_cnt=0;
+	int page_prog_start = 0;
+	int i = 0;
+
+	himax_interface_on(private_ts->client);
+	himax_burst_enable(private_ts->client, 0);
+
+	//=====================================
+	// SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780
+	//=====================================
+	tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80;
+	himax_83100_Flash_Write(tmp_addr, tmp_data);
+
+	for (page_prog_start = 0; page_prog_start < FW_Size; page_prog_start = page_prog_start + 256)
+	{
+		//=================================
+		// SPI Transfer Control
+		// Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF
+		// Set read start address  : 0x8000_0028 ==> 0x0000_0000
+		// Set command			   : 0x8000_0024 ==> 0x0000_003B
+		//=================================
+		tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20;
+		tmp_data[3] = 0x69; tmp_data[2] = 0x40; tmp_data[1] = 0x02; tmp_data[0] = 0xFF;
+		himax_83100_Flash_Write(tmp_addr, tmp_data);
+
+		tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28;
+		if (page_prog_start < 0x100)
+		{
+			tmp_data[3] = 0x00;
+			tmp_data[2] = 0x00;
+			tmp_data[1] = 0x00;
+			tmp_data[0] = (uint8_t)page_prog_start;
+		}
+		else if (page_prog_start >= 0x100 && page_prog_start < 0x10000)
+		{
+			tmp_data[3] = 0x00;
+			tmp_data[2] = 0x00;
+			tmp_data[1] = (uint8_t)(page_prog_start >> 8);
+			tmp_data[0] = (uint8_t)page_prog_start;
+		}
+		else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000)
+		{
+			tmp_data[3] = 0x00;
+			tmp_data[2] = (uint8_t)(page_prog_start >> 16);
+			tmp_data[1] = (uint8_t)(page_prog_start >> 8);
+			tmp_data[0] = (uint8_t)page_prog_start;
+		}
+		himax_83100_Flash_Write(tmp_addr, tmp_data);
+
+		tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24;
+		tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x3B;
+		himax_83100_Flash_Write(tmp_addr, tmp_data);
+
+		//==================================
+		// AHB_I2C Burst Read
+		// Set SPI data register : 0x8000_002C ==> 0x00
+		//==================================
+		out_buffer[0] = 0x2C;
+		out_buffer[1] = 0x00;
+		out_buffer[2] = 0x00;
+		out_buffer[3] = 0x80;
+		i2c_himax_write(private_ts->client, 0x00 ,out_buffer, 4, HIMAX_I2C_RETRY_TIMES);
+
+		//==================================
+		// Read access : 0x0C ==> 0x00
+		//==================================
+		out_buffer[0] = 0x00;
+		i2c_himax_write(private_ts->client, 0x0C ,out_buffer, 1, HIMAX_I2C_RETRY_TIMES);
+
+		//==================================
+		// Read 128 bytes two times
+		//==================================
+		i2c_himax_read(private_ts->client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES);
+		for (i = 0; i < 128; i++)
+			flash_buffer[i + page_prog_start] = in_buffer[i];
+
+		i2c_himax_read(private_ts->client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES);
+		for (i = 0; i < 128; i++)
+			flash_buffer[(i + 128) + page_prog_start] = in_buffer[i];
+
+		//tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C;
+		//himax_register_read(tmp_addr, 32, out in_buffer);
+		//for (int i = 0; i < 128; i++)
+		//	  flash_buffer[i + page_prog_start] = in_buffer[i];
+		//tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C;
+		//himax_register_read(tmp_addr, 32, out in_buffer);
+		//for (int i = 0; i < 128; i++)
+		//	  flash_buffer[i + page_prog_start] = in_buffer[i];
+
+		I("%s:Verify Progress: %x\n", __func__, page_prog_start);
+	}
+
+	fail_cnt = 0;
+	for (i = 0; i < FW_Size; i++)
+	{
+		if (FW_File[i] != flash_buffer[i])
+		{
+			if (fail_cnt == 0)
+				fail_addr = i;
+
+			fail_cnt++;
+			//E("%s Fail Block:%x\n", __func__, i);
+			//return false;
+		}
+	}
+	if (fail_cnt > 0)
+	{
+		E("%s:Start Fail Block:%x and fail block count=%x\n" , __func__,fail_addr,fail_cnt);
+		return false;
+	}
+
+	I("%s:Byte read verify pass.\n", __func__);
+	return true;
+
+}
+#endif
+
+void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data)
+{
+	int i;
+	int cnt = 0;
+	unsigned char tmp_addr[4];
+	unsigned char tmp_data[4];
+  uint8_t max_i2c_size = 32;
+	int total_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM * 2;
+	int total_size_4bytes = total_size / 4;
+	int total_read_times = 0;
+	unsigned long address = 0x08000468;
+  tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x64;
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x5A; tmp_data[0] = 0xA5;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+  do
+	{
+		cnt++;
+		himax_register_read(client, tmp_addr, 1, tmp_data);
+		usleep_range(10000, 20000);
+	} while ((tmp_data[1] != 0xA5 || tmp_data[0] != 0x5A) && cnt < 100);
+  tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x68;
+  if (total_size_4bytes % max_i2c_size == 0)
+	{
+		total_read_times = total_size_4bytes / max_i2c_size;
+	}
+	else
+	{
+		total_read_times = total_size_4bytes / max_i2c_size + 1;
+	}
+	for (i = 0; i < (total_read_times); i++)
+	{
+		if ( total_size_4bytes >= max_i2c_size)
+		{
+			himax_register_read(client, tmp_addr, max_i2c_size, &info_data[i*max_i2c_size*4]);
+			total_size_4bytes = total_size_4bytes - max_i2c_size;
+		}
+		else
+		{
+			himax_register_read(client, tmp_addr, total_size_4bytes % max_i2c_size, &info_data[i*max_i2c_size*4]);
+		}
+		address += max_i2c_size*4;
+		tmp_addr[1] = (uint8_t)((address>>8)&0x00FF);
+		tmp_addr[0] = (uint8_t)((address)&0x00FF);
+	}
+	tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x64;
+	tmp_data[3] = 0x11; tmp_data[2] = 0x22; tmp_data[1] = 0x33; tmp_data[0] = 0x44;
+	himax_flash_write_burst(client, tmp_addr, tmp_data);
+}
+//ts_work
+int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max){
+	int RawDataLen;
+	if (raw_cnt_rmd != 0x00) {
+		RawDataLen = 124 - ((HX_MAX_PT+raw_cnt_max+3)*4) - 1;
+	}else{
+		RawDataLen = 124 - ((HX_MAX_PT+raw_cnt_max+2)*4) - 1;
+	}
+	return RawDataLen;
+}
+
+bool read_event_stack(struct i2c_client *client, uint8_t *buf, int length)
+{
+	uint8_t cmd[4];
+
+	if(length > 56)
+		length = 124;
+	//=====================
+	//AHB I2C Burst Read
+	//=====================
+	cmd[0] = 0x31;
+	if ( i2c_himax_write(client, 0x13 ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		goto err_workqueue_out;
+	}
+
+	cmd[0] = 0x10;
+	if ( i2c_himax_write(client, 0x0D ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		goto err_workqueue_out;
+	}
+	//=====================
+	//Read event stack
+	//=====================
+	cmd[3] = 0x90; cmd[2] = 0x06; cmd[1] = 0x00; cmd[0] = 0x00;
+	if ( i2c_himax_write(client, 0x00 ,cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		goto err_workqueue_out;
+	}
+
+	cmd[0] = 0x00;
+	if ( i2c_himax_write(client, 0x0C ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+		E("%s: i2c access fail!\n", __func__);
+		goto err_workqueue_out;
+	}
+	i2c_himax_read(client, 0x08, buf, length,HIMAX_I2C_RETRY_TIMES);
+	return 1;
+	
+	err_workqueue_out:
+	return 0;
+}
+
+bool post_read_event_stack(struct i2c_client *client)
+{
+	return 1;
+}
+bool diag_check_sum( uint8_t hx_touch_info_size, uint8_t *buf) //return checksum value
+{
+	uint16_t check_sum_cal = 0;
+	int i;
+
+	//Check 124th byte CRC
+	for (i = hx_touch_info_size, check_sum_cal = 0; i < 124; i=i+2)
+	{
+		check_sum_cal += (buf[i+1]*256 + buf[i]);
+	}
+	if (check_sum_cal % 0x10000 != 0)
+	{
+		I("%s: diag check sum fail! check_sum_cal=%X, hx_touch_info_size=%d, \n",__func__,check_sum_cal, hx_touch_info_size);
+		return 0;
+	}
+	return 1;
+}
+
+
+void diag_parse_raw_data(int hx_touch_info_size, int RawDataLen, int mul_num, int self_num, uint8_t *buf, uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data)
+{
+	int RawDataLen_word;
+	int index = 0;
+	int temp1, temp2,i;
+	
+	if (buf[hx_touch_info_size] == 0x3A && buf[hx_touch_info_size+1] == 0xA3 && buf[hx_touch_info_size+2] > 0 && buf[hx_touch_info_size+3] == diag_cmd+5 )
+	{
+			RawDataLen_word = RawDataLen/2;
+			index = (buf[hx_touch_info_size+2] - 1) * RawDataLen_word;
+		//I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num);
+			for (i = 0; i < RawDataLen_word; i++)
+		{
+			temp1 = index + i;
+
+			if (temp1 < mul_num)
+			{ //mutual
+					mutual_data[index + i] = buf[i*2 + hx_touch_info_size+4+1]*256 + buf[i*2 + hx_touch_info_size+4];	//4: RawData Header, 1:HSB
+			}
+			else
+			{//self
+				temp1 = i + index;
+				temp2 = self_num + mul_num;
+				
+				if (temp1 >= temp2)
+				{
+					break;
+				}
+
+					self_data[i+index-mul_num] = buf[i*2 + hx_touch_info_size+4];	//4: RawData Header
+					self_data[i+index-mul_num+1] = buf[i*2 + hx_touch_info_size+4+1];
+			}
+		}
+	}
+	else
+	{
+		I("[HIMAX TP MSG]%s: header format is wrong!\n", __func__);
+			I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num);
+	}
+}
diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.h b/drivers/input/touchscreen/hxchipset/himax_ic.h
new file mode 100644
index 0000000..18cd12b
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/himax_ic.h
@@ -0,0 +1,82 @@
+/* Himax Android Driver Sample Code for HMX83100 chipset
+*
+* Copyright (C) 2015 Himax Corporation.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+*/
+
+#include "himax_platform.h"
+#include "himax_common.h"
+
+#include <linux/slab.h>
+
+
+#define HX_85XX_A_SERIES_PWON		1
+#define HX_85XX_B_SERIES_PWON		2
+#define HX_85XX_C_SERIES_PWON		3
+#define HX_85XX_D_SERIES_PWON		4
+#define HX_85XX_E_SERIES_PWON		5
+#define HX_85XX_ES_SERIES_PWON		6
+#define HX_85XX_F_SERIES_PWON		7
+#define HX_83100_SERIES_PWON		8
+
+#define HX_TP_BIN_CHECKSUM_SW		1
+#define HX_TP_BIN_CHECKSUM_HW		2
+#define HX_TP_BIN_CHECKSUM_CRC	3
+
+enum fw_image_type {
+	fw_image_60k	= 0x01,
+	fw_image_64k,
+	fw_image_124k,
+	fw_image_128k,
+};
+
+int himax_hand_shaking(struct i2c_client *client);
+void himax_set_SMWP_enable(struct i2c_client *client,uint8_t SMWP_enable);
+void himax_get_SMWP_enable(struct i2c_client *client,uint8_t *tmp_data);
+void himax_set_HSEN_enable(struct i2c_client *client,uint8_t HSEN_enable);
+void himax_get_HSEN_enable(struct i2c_client *client,uint8_t *tmp_data);
+void himax_diag_register_set(struct i2c_client *client, uint8_t diag_command);
+void himax_flash_dump_func(struct i2c_client *client, uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer);
+int himax_chip_self_test(struct i2c_client *client);
+int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte); ////himax_83100_BURST_INC0_EN
+void himax_register_read(struct i2c_client *client, uint8_t *read_addr, int read_length, uint8_t *read_data); ////RegisterRead83100
+void himax_flash_read(struct i2c_client *client, uint8_t *reg_byte, uint8_t *read_data); ////himax_83100_Flash_Read
+void himax_flash_write_burst(struct i2c_client *client, uint8_t * reg_byte, uint8_t * write_data); ////himax_83100_Flash_Write_Burst
+int himax_flash_write_burst_lenth(struct i2c_client *client, uint8_t *reg_byte, uint8_t *write_data, int length); ////himax_83100_Flash_Write_Burst_lenth
+int himax_register_write(struct i2c_client *client, uint8_t *write_addr, int write_length, uint8_t *write_data); ////RegisterWrite83100
+void himax_sense_off(struct i2c_client *client); ////himax_83100_SenseOff
+void himax_interface_on(struct i2c_client *client); ////himax_83100_Interface_on
+bool wait_wip(struct i2c_client *client, int Timing);
+void himax_sense_on(struct i2c_client *client, uint8_t FlashMode); ////himax_83100_SenseOn
+void himax_chip_erase(struct i2c_client *client); ////himax_83100_Chip_Erase
+bool himax_block_erase(struct i2c_client *client); ////himax_83100_Block_Erase
+bool himax_sector_erase(struct i2c_client *client, int start_addr); ////himax_83100_Sector_Erase
+void himax_sram_write(struct i2c_client *client, uint8_t *FW_content); ////himax_83100_Sram_Write
+bool himax_sram_verify(struct i2c_client *client, uint8_t *FW_File, int FW_Size); ////himax_83100_Sram_Verify
+void himax_flash_programming(struct i2c_client *client, uint8_t *FW_content, int FW_Size); ////himax_83100_Flash_Programming
+bool himax_check_chip_version(struct i2c_client *client); ////himax_83100_CheckChipVersion
+int himax_check_CRC(struct i2c_client *client, int mode); ////himax_83100_Check_CRC
+bool Calculate_CRC_with_AP(unsigned char *FW_content , int CRC_from_FW, int mode);
+int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref);
+int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref);
+int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref);
+int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref);
+void himax_touch_information(struct i2c_client *client);
+void himax_read_FW_ver(struct i2c_client *client);
+bool himax_ic_package_check(struct i2c_client *client);
+void himax_read_event_stack(struct i2c_client *client, uint8_t *buf, uint8_t length);
+int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max);
+bool read_event_stack(struct i2c_client *client, uint8_t *buf_ts, int length);
+bool post_read_event_stack(struct i2c_client *client);
+bool diag_check_sum( uint8_t hx_touch_info_size, uint8_t *buf_ts); //return checksum value
+void diag_parse_raw_data(int hx_touch_info_size, int RawDataLen, int mul_num, int self_num, uint8_t *buf_ts, uint8_t diag_cmd, int16_t *mutual_data,	int16_t *self_data);
+void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data);
\ No newline at end of file
diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.c b/drivers/input/touchscreen/hxchipset/himax_platform.c
new file mode 100644
index 0000000..7e8a1d6
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/himax_platform.c
@@ -0,0 +1,796 @@
+/* Himax Android Driver Sample Code for HIMAX chipset
+*
+* Copyright (C) 2015 Himax Corporation.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+*/
+
+#include "himax_platform.h"
+#include "himax_common.h"
+
+int irq_enable_count = 0;
+#ifdef HX_SMART_WAKEUP
+#define TS_WAKE_LOCK_TIMEOUT		(2 * HZ)
+#endif
+
+#define PINCTRL_STATE_ACTIVE	"pmx_ts_active"
+#define PINCTRL_STATE_SUSPEND	"pmx_ts_suspend"
+#define PINCTRL_STATE_RELEASE	"pmx_ts_release"
+
+extern struct himax_ic_data* ic_data;
+extern void himax_ts_work(struct himax_ts_data *ts);
+extern enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer);
+extern int himax_ts_init(struct himax_ts_data *ts);
+
+extern int tp_rst_gpio;
+
+#ifdef HX_TP_PROC_DIAG
+extern uint8_t getDiagCommand(void);
+#endif
+
+void himax_vk_parser(struct device_node *dt,
+				struct himax_i2c_platform_data *pdata)
+{
+	u32 data = 0;
+	uint8_t cnt = 0, i = 0;
+	uint32_t coords[4] = {0};
+	struct device_node *node, *pp = NULL;
+	struct himax_virtual_key *vk;
+
+	node = of_parse_phandle(dt, "virtualkey", 0);
+	if (node == NULL) {
+		I(" DT-No vk info in DT");
+		return;
+	} else {
+		while ((pp = of_get_next_child(node, pp)))
+			cnt++;
+		if (!cnt)
+			return;
+
+		vk = kzalloc(cnt * (sizeof *vk), GFP_KERNEL);
+		if (!vk)
+			return;
+		pp = NULL;
+		while ((pp = of_get_next_child(node, pp))) {
+			if (of_property_read_u32(pp, "idx", &data) == 0)
+				vk[i].index = data;
+			if (of_property_read_u32_array(pp, "range", coords, 4) == 0) {
+				vk[i].x_range_min = coords[0], vk[i].x_range_max = coords[1];
+				vk[i].y_range_min = coords[2], vk[i].y_range_max = coords[3];
+			} else
+				I(" range faile");
+			i++;
+		}
+		pdata->virtual_key = vk;
+		for (i = 0; i < cnt; i++)
+			I(" vk[%d] idx:%d x_min:%d, y_max:%d", i,pdata->virtual_key[i].index,
+				pdata->virtual_key[i].x_range_min, pdata->virtual_key[i].y_range_max);
+	}
+}
+
+int himax_parse_dt(struct himax_ts_data *ts,
+				struct himax_i2c_platform_data *pdata)
+{
+	int rc, coords_size = 0;
+	uint32_t coords[4] = {0};
+	struct property *prop;
+	struct device_node *dt = ts->client->dev.of_node;
+	u32 data = 0;
+
+	prop = of_find_property(dt, "himax,panel-coords", NULL);
+	if (prop) {
+		coords_size = prop->length / sizeof(u32);
+		if (coords_size != 4)
+			D(" %s:Invalid panel coords size %d", __func__, coords_size);
+	}
+
+	if (of_property_read_u32_array(dt, "himax,panel-coords", coords, coords_size) == 0) {
+		pdata->abs_x_min = coords[0], pdata->abs_x_max = coords[1];
+		pdata->abs_y_min = coords[2], pdata->abs_y_max = coords[3];
+		I(" DT-%s:panel-coords = %d, %d, %d, %d\n", __func__, pdata->abs_x_min,
+				pdata->abs_x_max, pdata->abs_y_min, pdata->abs_y_max);
+	}
+
+	prop = of_find_property(dt, "himax,display-coords", NULL);
+	if (prop) {
+		coords_size = prop->length / sizeof(u32);
+		if (coords_size != 4)
+			D(" %s:Invalid display coords size %d", __func__, coords_size);
+	}
+	rc = of_property_read_u32_array(dt, "himax,display-coords", coords, coords_size);
+	if (rc && (rc != -EINVAL)) {
+		D(" %s:Fail to read display-coords %d\n", __func__, rc);
+		return rc;
+	}
+	pdata->screenWidth  = coords[1];
+	pdata->screenHeight = coords[3];
+	I(" DT-%s:display-coords = (%d, %d)", __func__, pdata->screenWidth,
+		pdata->screenHeight);
+
+	pdata->gpio_irq = of_get_named_gpio(dt, "himax,irq-gpio", 0);
+	if (!gpio_is_valid(pdata->gpio_irq)) {
+		I(" DT:gpio_irq value is not valid\n");
+	}
+
+	pdata->gpio_reset = of_get_named_gpio(dt, "himax,rst-gpio", 0);
+	if (!gpio_is_valid(pdata->gpio_reset)) {
+		I(" DT:gpio_rst value is not valid\n");
+	}
+	pdata->gpio_3v3_en = of_get_named_gpio(dt, "himax,3v3-gpio", 0);
+	if (!gpio_is_valid(pdata->gpio_3v3_en)) {
+		I(" DT:gpio_3v3_en value is not valid\n");
+	}
+	I(" DT:gpio_irq=%d, gpio_rst=%d, gpio_3v3_en=%d", pdata->gpio_irq, pdata->gpio_reset, pdata->gpio_3v3_en);
+
+	if (of_property_read_u32(dt, "report_type", &data) == 0) {
+		pdata->protocol_type = data;
+		I(" DT:protocol_type=%d", pdata->protocol_type);
+	}
+
+	himax_vk_parser(dt, pdata);
+
+	return 0;
+}
+
+int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry)
+{
+	int retry;
+	struct i2c_msg msg[] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = 1,
+			.buf = &command,
+		},
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = length,
+			.buf = data,
+		}
+	};
+
+	for (retry = 0; retry < toRetry; retry++) {
+		if (i2c_transfer(client->adapter, msg, 2) == 2)
+			break;
+		msleep(20);
+	}
+	if (retry == toRetry) {
+		E("%s: i2c_read_block retry over %d\n",
+			__func__, toRetry);
+		return -EIO;
+	}
+	return 0;
+
+}
+
+int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry)
+{
+	int retry/*, loop_i*/;
+	uint8_t buf[length + 1];
+
+	struct i2c_msg msg[] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = length + 1,
+			.buf = buf,
+		}
+	};
+
+	buf[0] = command;
+	memcpy(buf+1, data, length);
+	
+	for (retry = 0; retry < toRetry; retry++) {
+		if (i2c_transfer(client->adapter, msg, 1) == 1)
+			break;
+		msleep(20);
+	}
+
+	if (retry == toRetry) {
+		E("%s: i2c_write_block retry over %d\n",
+			__func__, toRetry);
+		return -EIO;
+	}
+	return 0;
+
+}
+
+int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry)
+{
+	int retry;
+	struct i2c_msg msg[] = {
+		{
+		.addr = client->addr,
+		.flags = I2C_M_RD,
+		.len = length,
+		.buf = data,
+		}
+	};
+
+	for (retry = 0; retry < toRetry; retry++) {
+		if (i2c_transfer(client->adapter, msg, 1) == 1)
+			break;
+		msleep(20);
+	}
+	if (retry == toRetry) {
+		E("%s: i2c_read_block retry over %d\n",
+		       __func__, toRetry);
+		return -EIO;
+	}
+	return 0;
+}
+
+int i2c_himax_write_command(struct i2c_client *client, uint8_t command, uint8_t toRetry)
+{
+	return i2c_himax_write(client, command, NULL, 0, toRetry);
+}
+
+int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t length, uint8_t toRetry)
+{
+	int retry/*, loop_i*/;
+	uint8_t buf[length];
+
+	struct i2c_msg msg[] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = length,
+			.buf = buf,
+		}
+	};
+
+	memcpy(buf, data, length);
+	
+	for (retry = 0; retry < toRetry; retry++) {
+		if (i2c_transfer(client->adapter, msg, 1) == 1)
+			break;
+		msleep(20);
+	}
+
+	if (retry == toRetry) {
+		E("%s: i2c_write_block retry over %d\n",
+		       __func__, toRetry);
+		return -EIO;
+	}
+	return 0;
+}
+
+void himax_int_enable(int irqnum, int enable)
+{
+	if (enable == 1 && irq_enable_count == 0) {
+		enable_irq(irqnum);
+		irq_enable_count++;
+	} else if (enable == 0 && irq_enable_count == 1) {
+		disable_irq_nosync(irqnum);
+		irq_enable_count--;
+	}
+	I("irq_enable_count = %d", irq_enable_count);
+}
+
+void himax_rst_gpio_set(int pinnum, uint8_t value)
+{
+	gpio_direction_output(pinnum, value);
+}
+
+uint8_t himax_int_gpio_read(int pinnum)
+{
+	return gpio_get_value(pinnum);
+}
+
+#if defined(CONFIG_HMX_DB)
+static int himax_regulator_configure(struct i2c_client *client,struct himax_i2c_platform_data *pdata)
+{
+    int retval;
+    pdata->vcc_dig = regulator_get(&client->dev,
+                                   "vdd");
+    if (IS_ERR(pdata->vcc_dig))
+    {
+        E("%s: Failed to get regulator vdd\n",
+          __func__);
+        retval = PTR_ERR(pdata->vcc_dig);
+        return retval;
+    }
+    pdata->vcc_ana = regulator_get(&client->dev,
+                                   "avdd");
+    if (IS_ERR(pdata->vcc_ana))
+    {
+        E("%s: Failed to get regulator avdd\n",
+          __func__);
+        retval = PTR_ERR(pdata->vcc_ana);
+        regulator_put(pdata->vcc_ana);
+        return retval;
+    }
+
+    return 0;
+};
+
+static int himax_power_on(struct himax_i2c_platform_data *pdata, bool on)
+{
+    int retval;
+
+    if (on)
+    {
+        retval = regulator_enable(pdata->vcc_dig);
+        if (retval)
+        {
+            E("%s: Failed to enable regulator vdd\n",
+              __func__);
+            return retval;
+        }
+        msleep(100);
+        retval = regulator_enable(pdata->vcc_ana);
+        if (retval)
+        {
+            E("%s: Failed to enable regulator avdd\n",
+              __func__);
+            regulator_disable(pdata->vcc_dig);
+            return retval;
+        }
+    }
+    else
+    {
+        regulator_disable(pdata->vcc_dig);
+        regulator_disable(pdata->vcc_ana);
+    }
+
+    return 0;
+}
+
+int himax_ts_pinctrl_init(struct himax_ts_data *ts)
+{
+	int retval;
+
+	/* Get pinctrl if target uses pinctrl */
+	ts->ts_pinctrl = devm_pinctrl_get(&(ts->client->dev));
+	if (IS_ERR_OR_NULL(ts->ts_pinctrl)) {
+		retval = PTR_ERR(ts->ts_pinctrl);
+		dev_dbg(&ts->client->dev,
+			"Target does not use pinctrl %d\n", retval);
+		goto err_pinctrl_get;
+	}
+
+	ts->pinctrl_state_active
+		= pinctrl_lookup_state(ts->ts_pinctrl,
+				PINCTRL_STATE_ACTIVE);
+	if (IS_ERR_OR_NULL(ts->pinctrl_state_active)) {
+		retval = PTR_ERR(ts->pinctrl_state_active);
+		dev_err(&ts->client->dev,
+			"Can not lookup %s pinstate %d\n",
+			PINCTRL_STATE_ACTIVE, retval);
+		goto err_pinctrl_lookup;
+	}
+
+	ts->pinctrl_state_suspend
+		= pinctrl_lookup_state(ts->ts_pinctrl,
+			PINCTRL_STATE_SUSPEND);
+	if (IS_ERR_OR_NULL(ts->pinctrl_state_suspend)) {
+		retval = PTR_ERR(ts->pinctrl_state_suspend);
+		dev_err(&ts->client->dev,
+			"Can not lookup %s pinstate %d\n",
+			PINCTRL_STATE_SUSPEND, retval);
+		goto err_pinctrl_lookup;
+	}
+
+	ts->pinctrl_state_release
+		= pinctrl_lookup_state(ts->ts_pinctrl,
+			PINCTRL_STATE_RELEASE);
+	if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) {
+		retval = PTR_ERR(ts->pinctrl_state_release);
+		dev_dbg(&ts->client->dev,
+			"Can not lookup %s pinstate %d\n",
+			PINCTRL_STATE_RELEASE, retval);
+	}
+
+	return 0;
+
+err_pinctrl_lookup:
+	devm_pinctrl_put(ts->ts_pinctrl);
+err_pinctrl_get:
+	ts->ts_pinctrl = NULL;
+	return retval;
+}
+
+int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata)
+{
+    int error;
+
+    error = himax_regulator_configure(client, pdata);
+    if (error)
+    {
+        E("Failed to intialize hardware\n");
+        goto err_regulator_not_on;
+    }
+
+#ifdef HX_RST_PIN_FUNC
+    if (gpio_is_valid(pdata->gpio_reset))
+    {
+        /* configure touchscreen reset out gpio */
+        error = gpio_request(pdata->gpio_reset, "hmx_reset_gpio");
+        if (error)
+        {
+            E("unable to request gpio [%d]\n",
+              pdata->gpio_reset);
+            goto err_regulator_on;
+        }
+
+        error = gpio_direction_output(pdata->gpio_reset, 0);
+        if (error)
+        {
+            E("unable to set direction for gpio [%d]\n",
+              pdata->gpio_reset);
+            goto err_gpio_reset_req;
+        }
+    }
+#endif
+
+    error = himax_power_on(pdata, true);
+    if (error)
+    {
+        E("Failed to power on hardware\n");
+        goto err_gpio_reset_req;
+    }
+#ifdef HX_IRQ_PIN_FUNC
+    if (gpio_is_valid(pdata->gpio_irq))
+    {
+        /* configure touchscreen irq gpio */
+        error = gpio_request(pdata->gpio_irq, "hmx_gpio_irq");
+        if (error)
+        {
+            E("unable to request gpio [%d]\n",
+              pdata->gpio_irq);
+            goto err_power_on;
+        }
+        error = gpio_direction_input(pdata->gpio_irq);
+        if (error)
+        {
+            E("unable to set direction for gpio [%d]\n",
+              pdata->gpio_irq);
+            goto err_gpio_irq_req;
+        }
+        client->irq = gpio_to_irq(pdata->gpio_irq);
+    }
+    else
+    {
+        E("irq gpio not provided\n");
+        goto err_power_on;
+    }
+#endif
+
+    msleep(20);
+
+#ifdef HX_RST_PIN_FUNC
+    if (gpio_is_valid(pdata->gpio_reset))
+    {
+        error = gpio_direction_output(pdata->gpio_reset, 1);
+        if (error)
+        {
+            E("unable to set direction for gpio [%d]\n",
+              pdata->gpio_reset);
+            goto err_gpio_irq_req;
+        }
+    }
+#endif
+    return 0;
+#ifdef HX_RST_PIN_FUNC
+	err_gpio_irq_req:
+#endif
+#ifdef HX_IRQ_PIN_FUNC
+    if (gpio_is_valid(pdata->gpio_irq))
+        gpio_free(pdata->gpio_irq);
+	err_power_on:
+#endif
+    himax_power_on(pdata, false);
+	err_gpio_reset_req:
+#ifdef HX_RST_PIN_FUNC
+    if (gpio_is_valid(pdata->gpio_reset))
+        gpio_free(pdata->gpio_reset);
+	err_regulator_on:
+#endif
+	err_regulator_not_on:
+
+    return error;
+}
+
+#else
+int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata)
+{
+		int error=0;
+	
+#ifdef HX_RST_PIN_FUNC
+		if (pdata->gpio_reset >= 0)
+		{
+			error = gpio_request(pdata->gpio_reset, "himax-reset");
+			if (error < 0)
+			{
+				E("%s: request reset pin failed\n", __func__);
+				return error;
+			}
+			error = gpio_direction_output(pdata->gpio_reset, 0);
+			if (error)
+			{
+				E("unable to set direction for gpio [%d]\n",
+				  pdata->gpio_reset);
+				return error;
+			}
+		}
+#endif
+		if (pdata->gpio_3v3_en >= 0)
+		{
+			error = gpio_request(pdata->gpio_3v3_en, "himax-3v3_en");
+			if (error < 0)
+			{
+				E("%s: request 3v3_en pin failed\n", __func__);
+				return error;
+			}
+			gpio_direction_output(pdata->gpio_3v3_en, 1);
+			I("3v3_en pin =%d\n", gpio_get_value(pdata->gpio_3v3_en));
+		}
+
+#ifdef HX_IRQ_PIN_FUNC
+		if (gpio_is_valid(pdata->gpio_irq))
+		{
+			/* configure touchscreen irq gpio */
+			error = gpio_request(pdata->gpio_irq, "himax_gpio_irq");
+			if (error)
+			{
+				E("unable to request gpio [%d]\n",pdata->gpio_irq);
+				return error;
+			}
+			error = gpio_direction_input(pdata->gpio_irq);
+			if (error)
+			{
+				E("unable to set direction for gpio [%d]\n",pdata->gpio_irq);
+				return error;
+			}
+			client->irq = gpio_to_irq(pdata->gpio_irq);
+		}
+		else
+		{
+			E("irq gpio not provided\n");
+			return error;
+		}
+#endif
+
+		msleep(20);
+	
+#ifdef HX_RST_PIN_FUNC
+		if (pdata->gpio_reset >= 0)
+		{
+			error = gpio_direction_output(pdata->gpio_reset, 1);
+			if (error)
+			{
+				E("unable to set direction for gpio [%d]\n",
+				  pdata->gpio_reset);
+				return error;
+			}
+		}
+		msleep(20);
+#endif
+	
+		return error;
+	}
+#endif
+
+static void himax_ts_isr_func(struct himax_ts_data *ts)
+{
+	himax_ts_work(ts);
+}
+
+irqreturn_t himax_ts_thread(int irq, void *ptr)
+{
+	uint8_t diag_cmd;
+	struct himax_ts_data *ts = ptr;
+	struct timespec timeStart, timeEnd, timeDelta;
+
+	diag_cmd = getDiagCommand();
+
+	if (ts->debug_log_level & BIT(2)) {
+			getnstimeofday(&timeStart);
+			usleep_range(5000, 7000);
+			//I(" Irq start time = %ld.%06ld s\n",
+			//	timeStart.tv_sec, timeStart.tv_nsec/1000);
+	}
+
+#ifdef HX_SMART_WAKEUP
+	if (atomic_read(&ts->suspend_mode)&&(!FAKE_POWER_KEY_SEND)&&(ts->SMWP_enable)&&(!diag_cmd)) {
+		wake_lock_timeout(&ts->ts_SMWP_wake_lock, TS_WAKE_LOCK_TIMEOUT);
+		msleep(200);
+		himax_wake_check_func();
+		return IRQ_HANDLED;
+	}
+#endif
+	himax_ts_isr_func((struct himax_ts_data *)ptr);
+	if(ts->debug_log_level & BIT(2)) {
+			getnstimeofday(&timeEnd);
+				timeDelta.tv_nsec = (timeEnd.tv_sec*1000000000+timeEnd.tv_nsec)
+				-(timeStart.tv_sec*1000000000+timeStart.tv_nsec);
+			//I("Irq finish time = %ld.%06ld s\n",
+			//	timeEnd.tv_sec, timeEnd.tv_nsec/1000);
+			//I("Touch latency = %ld us\n", timeDelta.tv_nsec/1000);
+	}
+	return IRQ_HANDLED;
+}
+
+static void himax_ts_work_func(struct work_struct *work)
+{
+	struct himax_ts_data *ts = container_of(work, struct himax_ts_data, work);
+	himax_ts_work(ts);
+}
+
+int tp_irq = -1;
+
+int himax_ts_register_interrupt(struct i2c_client *client)
+{
+	struct himax_ts_data *ts = i2c_get_clientdata(client);
+	int ret = 0;
+
+	ts->irq_enabled = 0;
+	//Work functon
+	if (client->irq) {/*INT mode*/
+		ts->use_irq = 1;
+		if(ic_data->HX_INT_IS_EDGE)
+			{
+				I("%s edge triiger falling\n ",__func__);
+				ret = request_threaded_irq(client->irq, NULL, himax_ts_thread,IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, ts);
+			}
+		else
+			{
+				I("%s level trigger low\n ",__func__);
+				ret = request_threaded_irq(client->irq, NULL, himax_ts_thread,IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, ts);
+			}
+		if (ret == 0) {
+			ts->irq_enabled = 1;
+			irq_enable_count = 1;
+			tp_irq = client->irq;
+			I("%s: irq enabled at qpio: %d\n", __func__, client->irq);
+#ifdef HX_SMART_WAKEUP
+			irq_set_irq_wake(client->irq, 1);
+#endif
+		} else {
+			ts->use_irq = 0;
+			E("%s: request_irq failed\n", __func__);
+		}
+	} else {
+		I("%s: client->irq is empty, use polling mode.\n", __func__);
+	}
+
+	if (!ts->use_irq) {/*if use polling mode need to disable HX_ESD_WORKAROUND function*/
+		ts->himax_wq = create_singlethread_workqueue("himax_touch");
+
+		INIT_WORK(&ts->work, himax_ts_work_func);
+
+		hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+		ts->timer.function = himax_ts_timer_func;
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+		I("%s: polling mode enabled\n", __func__);
+	}
+	return ret;
+}
+
+static int himax_common_suspend(struct device *dev)
+{
+	struct himax_ts_data *ts = dev_get_drvdata(dev);
+
+	I("%s: enter \n", __func__);
+
+	himax_chip_common_suspend(ts);
+	return 0;
+}
+
+static int himax_common_resume(struct device *dev)
+{
+	struct himax_ts_data *ts = dev_get_drvdata(dev);
+
+	I("%s: enter \n", __func__);
+
+	himax_chip_common_resume(ts);
+	return 0;
+}
+
+#if defined(CONFIG_FB)
+int fb_notifier_callback(struct notifier_block *self,
+				 unsigned long event, void *data)
+{
+	struct fb_event *evdata = data;
+	int *blank;
+	struct himax_ts_data *ts=
+		container_of(self, struct himax_ts_data, fb_notif);
+
+	I(" %s\n", __func__);
+	if (evdata && evdata->data && event == FB_EVENT_BLANK && ts &&
+			ts->client) {
+		blank = evdata->data;
+
+		mutex_lock(&ts->fb_mutex);
+		switch (*blank) {
+		case FB_BLANK_UNBLANK:
+			if (!ts->probe_done) {
+				himax_ts_init(ts);
+				ts->probe_done = true;
+			} else {
+				himax_common_resume(&ts->client->dev);
+			}
+		break;
+
+		case FB_BLANK_POWERDOWN:
+		case FB_BLANK_HSYNC_SUSPEND:
+		case FB_BLANK_VSYNC_SUSPEND:
+		case FB_BLANK_NORMAL:
+			himax_common_suspend(&ts->client->dev);
+		break;
+		}
+		mutex_unlock(&ts->fb_mutex);
+	}
+
+	return 0;
+}
+#endif
+
+static const struct i2c_device_id himax_common_ts_id[] = {
+	{HIMAX_common_NAME, 0 },
+	{}
+};
+
+static const struct dev_pm_ops himax_common_pm_ops = {
+#if (!defined(CONFIG_FB))
+	.suspend = himax_common_suspend,
+	.resume  = himax_common_resume,
+#endif
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id himax_match_table[] = {
+	{.compatible = "himax,hxcommon" },
+	{},
+};
+#else
+#define himax_match_table NULL
+#endif
+
+static struct i2c_driver himax_common_driver = {
+	.id_table	= himax_common_ts_id,
+	.probe		= himax_chip_common_probe,
+	.remove		= himax_chip_common_remove,
+	.driver		= {
+	.name = HIMAX_common_NAME,
+	.owner = THIS_MODULE,
+	.of_match_table = himax_match_table,
+#ifdef CONFIG_PM
+	.pm				= &himax_common_pm_ops,
+#endif
+	},
+};
+
+static void __init himax_common_init_async(void *unused, async_cookie_t cookie)
+{
+	I("%s:Enter \n", __func__);
+	i2c_add_driver(&himax_common_driver);
+}
+
+static int __init himax_common_init(void)
+{
+	I("Himax common touch panel driver init\n");
+	async_schedule(himax_common_init_async, NULL);
+	return 0;
+}
+
+static void __exit himax_common_exit(void)
+{
+	i2c_del_driver(&himax_common_driver);
+}
+
+module_init(himax_common_init);
+module_exit(himax_common_exit);
+
+MODULE_DESCRIPTION("Himax_common driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.h b/drivers/input/touchscreen/hxchipset/himax_platform.h
new file mode 100644
index 0000000..1223685
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/himax_platform.h
@@ -0,0 +1,135 @@
+/* Himax Android Driver Sample Code for Himax chipset
+*
+* Copyright (C) 2015 Himax Corporation.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+*/
+
+#ifndef HIMAX_PLATFORM_H
+#define HIMAX_PLATFORM_H
+
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/gpio.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#if defined(CONFIG_HMX_DB)
+#include <linux/regulator/consumer.h>
+#endif
+
+#define QCT
+
+#define HIMAX_I2C_RETRY_TIMES 10
+
+#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG)
+#define D(x...) pr_debug("[HXTP] " x)
+#define I(x...) pr_info("[HXTP] " x)
+#define W(x...) pr_warning("[HXTP][WARNING] " x)
+#define E(x...) pr_err("[HXTP][ERROR] " x)
+#define DIF(x...) \
+do {\
+	if (debug_flag) \
+	pr_debug("[HXTP][DEBUG] " x) \
+} while(0)
+#else
+#define D(x...)
+#define I(x...)
+#define W(x...)
+#define E(x...)
+#define DIF(x...)
+#endif
+
+#if defined(CONFIG_HMX_DB)
+/* Analog voltage @2.7 V */
+#define HX_VTG_MIN_UV			2700000
+#define HX_VTG_MAX_UV			3300000
+#define HX_ACTIVE_LOAD_UA		15000
+#define HX_LPM_LOAD_UA 			10
+/* Digital voltage @1.8 V */
+#define HX_VTG_DIG_MIN_UV		1800000
+#define HX_VTG_DIG_MAX_UV		1800000
+#define HX_ACTIVE_LOAD_DIG_UA	10000
+#define HX_LPM_LOAD_DIG_UA 		10
+
+#define HX_I2C_VTG_MIN_UV		1800000
+#define HX_I2C_VTG_MAX_UV		1800000
+#define HX_I2C_LOAD_UA 			10000
+#define HX_I2C_LPM_LOAD_UA 		10
+#endif
+
+#define HIMAX_common_NAME 				"himax_tp"
+#define HIMAX_I2C_ADDR					0x48
+#define INPUT_DEV_NAME					"himax-touchscreen"
+
+struct himax_i2c_platform_data {	
+	int abs_x_min;
+	int abs_x_max;
+	int abs_x_fuzz;
+	int abs_y_min;
+	int abs_y_max;
+	int abs_y_fuzz;
+	int abs_pressure_min;
+	int abs_pressure_max;
+	int abs_pressure_fuzz;
+	int abs_width_min;
+	int abs_width_max;
+	int screenWidth;
+	int screenHeight;
+	uint8_t fw_version;
+	uint8_t tw_id;
+	uint8_t powerOff3V3;
+	uint8_t cable_config[2];
+	uint8_t protocol_type;
+	int gpio_irq;
+	int gpio_reset;
+	int gpio_3v3_en;
+	int (*power)(int on);
+	void (*reset)(void);
+	struct himax_virtual_key *virtual_key;
+	struct kobject *vk_obj;
+	struct kobj_attribute *vk2Use;
+
+	struct himax_config *hx_config;
+	int hx_config_size;
+#if defined(CONFIG_HMX_DB)
+	bool	i2c_pull_up;
+	bool	digital_pwr_regulator;
+	int reset_gpio;
+	u32 reset_gpio_flags;
+	int irq_gpio;
+	u32 irq_gpio_flags;
+
+	struct regulator *vcc_ana; //For Dragon Board
+	struct regulator *vcc_dig; //For Dragon Board
+	struct regulator *vcc_i2c; //For Dragon Board
+#endif	
+};
+
+
+extern int irq_enable_count;
+extern int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry);
+extern int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry);
+extern int i2c_himax_write_command(struct i2c_client *client, uint8_t command, uint8_t toRetry);
+extern int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t length, uint8_t toRetry);
+extern int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry);
+extern void himax_int_enable(int irqnum, int enable);
+extern int himax_ts_register_interrupt(struct i2c_client *client);
+extern void himax_rst_gpio_set(int pinnum, uint8_t value);
+extern uint8_t himax_int_gpio_read(int pinnum);
+
+extern int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata);
+
+#if defined(CONFIG_FB)
+extern int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data);
+#endif
+
+#endif
diff --git a/drivers/iommu/arm-smmu-errata.c b/drivers/iommu/arm-smmu-errata.c
index 2ee2028..e1cb1a4 100644
--- a/drivers/iommu/arm-smmu-errata.c
+++ b/drivers/iommu/arm-smmu-errata.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -41,7 +41,7 @@
 		ret = hyp_assign_phys(page_to_phys(page), PAGE_ALIGN(size),
 				&source_vm, 1,
 				&dest_vm, &dest_perm, 1);
-		if (ret) {
+		if (ret && (ret != -EIO)) {
 			__free_pages(page, get_order(size));
 			page = NULL;
 		}
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index e0b2f63..1719336 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -579,6 +579,7 @@
 	{ ARM_SMMU_OPT_MMU500_ERRATA1, "qcom,mmu500-errata-1" },
 	{ ARM_SMMU_OPT_STATIC_CB, "qcom,enable-static-cb"},
 	{ ARM_SMMU_OPT_HALT, "qcom,enable-smmu-halt"},
+	{ ARM_SMMU_OPT_HIBERNATION, "qcom,hibernation-support"},
 	{ 0, NULL},
 };
 
@@ -704,6 +705,11 @@
 		mutex_unlock(&smmu_domain->assign_lock);
 }
 
+static bool arm_smmu_opt_hibernation(struct arm_smmu_device *smmu)
+{
+	return smmu->options & ARM_SMMU_OPT_HIBERNATION;
+}
+
 /*
  * init()
  * Hook for additional device tree parsing at probe time.
@@ -1859,6 +1865,14 @@
 		goto out_unlock;
 	}
 
+	if (arm_smmu_has_secure_vmid(smmu_domain) &&
+	    arm_smmu_opt_hibernation(smmu)) {
+		dev_err(smmu->dev,
+			"Secure usecases not supported with hibernation\n");
+		ret = -EPERM;
+		goto out_unlock;
+	}
+
 	/*
 	 * Mapping the requested stage onto what we support is surprisingly
 	 * complicated, mainly because the spec allows S1+S2 SMMUs without
@@ -3994,6 +4008,33 @@
 	return cb;
 }
 
+static void parse_static_cb_cfg(struct arm_smmu_device *smmu)
+{
+	u32 idx = 0;
+	u32 val;
+	int ret;
+
+	if (!(arm_smmu_is_static_cb(smmu) &&
+	      arm_smmu_opt_hibernation(smmu)))
+		return;
+
+	/*
+	 * Context banks may be xpu-protected. Require a devicetree property to
+	 * indicate which context banks HLOS has access to.
+	 */
+	bitmap_set(smmu->secure_context_map, 0, ARM_SMMU_MAX_CBS);
+	while (idx < ARM_SMMU_MAX_CBS) {
+		ret = of_property_read_u32_index(
+				smmu->dev->of_node, "qcom,static-ns-cbs",
+				idx++, &val);
+		if (ret)
+			break;
+
+		bitmap_clear(smmu->secure_context_map, val, 1);
+		dev_dbg(smmu->dev, "Detected NS context bank: %d\n", idx);
+	}
+}
+
 static int arm_smmu_handoff_cbs(struct arm_smmu_device *smmu)
 {
 	u32 i, raw_smr, raw_s2cr;
@@ -4693,6 +4734,7 @@
 	}
 
 	parse_driver_options(smmu);
+	parse_static_cb_cfg(smmu);
 
 	smmu->pwr = arm_smmu_init_power_resources(pdev);
 	if (IS_ERR(smmu->pwr))
@@ -4799,8 +4841,9 @@
 	if (arm_smmu_power_on(smmu->pwr))
 		return -EINVAL;
 
-	if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS) ||
-	    !bitmap_empty(smmu->secure_context_map, ARM_SMMU_MAX_CBS))
+	if (!(bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS) &&
+		(bitmap_empty(smmu->secure_context_map, ARM_SMMU_MAX_CBS) ||
+		 arm_smmu_opt_hibernation(smmu))))
 		dev_err(&pdev->dev, "removing device with active domains!\n");
 
 	idr_destroy(&smmu->asid_idr);
@@ -4814,10 +4857,43 @@
 	return 0;
 }
 
+static int arm_smmu_pm_freeze(struct device *dev)
+{
+	struct arm_smmu_device *smmu = dev_get_drvdata(dev);
+
+	if (!arm_smmu_opt_hibernation(smmu)) {
+		dev_err(smmu->dev, "Aborting: Hibernation not supported\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int arm_smmu_pm_restore(struct device *dev)
+{
+	struct arm_smmu_device *smmu = dev_get_drvdata(dev);
+	int ret;
+
+	ret = arm_smmu_power_on(smmu->pwr);
+	if (ret)
+		return ret;
+
+	arm_smmu_device_reset(smmu);
+	arm_smmu_power_off(smmu->pwr);
+	return 0;
+}
+
+static const struct dev_pm_ops arm_smmu_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
+	.freeze = arm_smmu_pm_freeze,
+	.restore = arm_smmu_pm_restore,
+#endif
+};
+
 static struct platform_driver arm_smmu_driver = {
 	.driver	= {
 		.name		= "arm-smmu",
 		.of_match_table	= of_match_ptr(arm_smmu_of_match),
+		.pm		= &arm_smmu_pm_ops,
 	},
 	.probe	= arm_smmu_device_dt_probe,
 	.remove	= arm_smmu_device_remove,
@@ -4828,6 +4904,7 @@
 {
 	static bool registered;
 	int ret = 0;
+	struct device_node *node;
 	ktime_t cur;
 
 	if (registered)
@@ -4839,9 +4916,12 @@
 		return ret;
 
 	ret = platform_driver_register(&arm_smmu_driver);
-#ifdef CONFIG_MSM_TZ_SMMU
-	ret = register_iommu_sec_ptbl();
-#endif
+	/* Disable secure usecases if hibernation support is enabled */
+	node = of_find_compatible_node(NULL, NULL, "qcom,qsmmu-v500");
+	if (IS_ENABLED(CONFIG_MSM_TZ_SMMU) && node &&
+	    !of_find_property(node, "qcom,hibernation-support", NULL))
+		ret = register_iommu_sec_ptbl();
+
 	registered = !ret;
 	trace_smmu_init(ktime_us_delta(ktime_get(), cur));
 
diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c
index 3a1c406..f846f01 100644
--- a/drivers/iommu/intel-svm.c
+++ b/drivers/iommu/intel-svm.c
@@ -389,6 +389,7 @@
 				pasid_max - 1, GFP_KERNEL);
 		if (ret < 0) {
 			kfree(svm);
+			kfree(sdev);
 			goto out;
 		}
 		svm->pasid = ret;
diff --git a/drivers/iommu/io-pgtable-msm-secure.c b/drivers/iommu/io-pgtable-msm-secure.c
index d0a8a79..e0314f9 100644
--- a/drivers/iommu/io-pgtable-msm-secure.c
+++ b/drivers/iommu/io-pgtable-msm-secure.c
@@ -47,6 +47,11 @@
 
 int msm_iommu_sec_pgtbl_init(void)
 {
+	struct msm_scm_ptbl_init {
+		unsigned int paddr;
+		unsigned int size;
+		unsigned int spare;
+	} pinit = {0};
 	int psize[2] = {0, 0};
 	unsigned int spare = 0;
 	int ret, ptbl_ret = 0;
@@ -55,7 +60,12 @@
 	dma_addr_t paddr;
 	unsigned long attrs = 0;
 
-	if (is_scm_armv8()) {
+	struct scm_desc desc = {0};
+
+	if (!is_scm_armv8()) {
+		ret = scm_call(SCM_SVC_MP, IOMMU_SECURE_PTBL_SIZE, &spare,
+				sizeof(spare), psize, sizeof(psize));
+	} else {
 		struct scm_desc desc = {0};
 
 		desc.args[0] = spare;
@@ -64,12 +74,11 @@
 				IOMMU_SECURE_PTBL_SIZE), &desc);
 		psize[0] = desc.ret[0];
 		psize[1] = desc.ret[1];
-		if (ret || psize[1]) {
-			pr_err("scm call IOMMU_SECURE_PTBL_SIZE failed\n");
-			return ret;
-		}
 	}
-
+	if (ret || psize[1]) {
+		pr_err("scm call IOMMU_SECURE_PTBL_SIZE failed\n");
+		goto fail;
+	}
 	/* Now allocate memory for the secure page tables */
 	attrs = DMA_ATTR_NO_KERNEL_MAPPING;
 	dev.coherent_dma_mask = DMA_BIT_MASK(sizeof(dma_addr_t) * 8);
@@ -78,34 +87,42 @@
 	if (!cpu_addr) {
 		pr_err("%s: Failed to allocate %d bytes for PTBL\n",
 				__func__, psize[0]);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto fail;
 	}
 
-	if (is_scm_armv8()) {
-		struct scm_desc desc = {0};
+	pinit.paddr = (unsigned int)paddr;
+	/* paddr may be a physical address > 4GB */
+	desc.args[0] = paddr;
+	desc.args[1] = pinit.size = psize[0];
+	desc.args[2] = pinit.spare;
+	desc.arginfo = SCM_ARGS(3, SCM_RW, SCM_VAL, SCM_VAL);
 
-		desc.args[0] = paddr;
-		desc.args[1] = psize[0];
-		desc.args[2] = 0;
-		desc.arginfo = SCM_ARGS(3, SCM_RW, SCM_VAL, SCM_VAL);
-
+	if (!is_scm_armv8()) {
+		ret = scm_call(SCM_SVC_MP, IOMMU_SECURE_PTBL_INIT, &pinit,
+				sizeof(pinit), &ptbl_ret, sizeof(ptbl_ret));
+	} else {
 		ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
 				IOMMU_SECURE_PTBL_INIT), &desc);
 		ptbl_ret = desc.ret[0];
-
-		if (ret) {
-			pr_err("scm call IOMMU_SECURE_PTBL_INIT failed\n");
-			return ret;
-		}
-
-		if (ptbl_ret) {
-			pr_err("scm call IOMMU_SECURE_PTBL_INIT extended ret fail\n");
-			return ret;
-		}
+	}
+	if (ret) {
+		pr_err("scm call IOMMU_SECURE_PTBL_INIT failed\n");
+		goto fail_mem;
+	}
+	if (ptbl_ret) {
+		pr_err("scm call IOMMU_SECURE_PTBL_INIT extended ret fail\n");
+		goto fail_mem;
 	}
 
 	return 0;
+
+fail_mem:
+	dma_free_attrs(&dev, psize[0], cpu_addr, paddr, attrs);
+fail:
+	return ret;
 }
+
 EXPORT_SYMBOL(msm_iommu_sec_pgtbl_init);
 
 static int msm_secure_map(struct io_pgtable_ops *ops, unsigned long iova,
diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
index 9ae7180..1c2ca8d 100644
--- a/drivers/irqchip/irq-gic-common.c
+++ b/drivers/irqchip/irq-gic-common.c
@@ -21,6 +21,8 @@
 
 #include "irq-gic-common.h"
 
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
 static const struct gic_kvm_info *gic_kvm_info;
 
 const struct gic_kvm_info *gic_get_kvm_info(void)
@@ -52,11 +54,13 @@
 	u32 confoff = (irq / 16) * 4;
 	u32 val, oldval;
 	int ret = 0;
+	unsigned long flags;
 
 	/*
 	 * Read current configuration register, and insert the config
 	 * for "irq", depending on "type".
 	 */
+	raw_spin_lock_irqsave(&irq_controller_lock, flags);
 	val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
 	if (type & IRQ_TYPE_LEVEL_MASK)
 		val &= ~confmask;
@@ -64,8 +68,10 @@
 		val |= confmask;
 
 	/* If the current configuration is the same, then we are done */
-	if (val == oldval)
+	if (val == oldval) {
+		raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 		return 0;
+	}
 
 	/*
 	 * Write back the new configuration, and possibly re-enable
@@ -83,6 +89,7 @@
 			pr_warn("GIC: PPI%d is secure or misconfigured\n",
 				irq - 16);
 	}
+	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 
 	if (sync_access)
 		sync_access();
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 307d545..2f0f448 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -1359,6 +1359,10 @@
 	u32 size = reg == GIC_PIDR2_ARCH_GICv4 ? SZ_64K * 4 : SZ_64K * 2;
 	void __iomem *redist_base;
 
+	/* GICC entry which has !ACPI_MADT_ENABLED is not unusable so skip */
+	if (!(gicc->flags & ACPI_MADT_ENABLED))
+		return 0;
+
 	redist_base = ioremap(gicc->gicr_base_address, size);
 	if (!redist_base)
 		return -ENOMEM;
@@ -1408,6 +1412,13 @@
 	if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address)
 		return 0;
 
+	/*
+	 * It's perfectly valid firmware can pass disabled GICC entry, driver
+	 * should not treat as errors, skip the entry instead of probe fail.
+	 */
+	if (!(gicc->flags & ACPI_MADT_ENABLED))
+		return 0;
+
 	return -ENODEV;
 }
 
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 03b79b0..05d87f6 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -105,10 +105,7 @@
 static inline void get_mbigen_clear_reg(irq_hw_number_t hwirq,
 					u32 *mask, u32 *addr)
 {
-	unsigned int ofst;
-
-	hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP;
-	ofst = hwirq / 32 * 4;
+	unsigned int ofst = (hwirq / 32) * 4;
 
 	*mask = 1 << (hwirq % 32);
 	*addr = ofst + REG_MBIGEN_CLEAR_OFFSET;
diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c
index 9cb4b62..b92a19a 100644
--- a/drivers/isdn/mISDN/stack.c
+++ b/drivers/isdn/mISDN/stack.c
@@ -72,7 +72,7 @@
 		if (sk->sk_state != MISDN_BOUND)
 			continue;
 		if (!cskb)
-			cskb = skb_copy(skb, GFP_KERNEL);
+			cskb = skb_copy(skb, GFP_ATOMIC);
 		if (!cskb) {
 			printk(KERN_WARNING "%s no skb\n", __func__);
 			break;
diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c
index 840401a..f672648 100644
--- a/drivers/leds/leds-pca955x.c
+++ b/drivers/leds/leds-pca955x.c
@@ -266,7 +266,7 @@
 			"slave address 0x%02x\n",
 			id->name, chip->bits, client->addr);
 
-	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 		return -EIO;
 
 	if (pdata) {
diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c
index 537903b..d23337e 100644
--- a/drivers/md/bcache/alloc.c
+++ b/drivers/md/bcache/alloc.c
@@ -512,15 +512,21 @@
 
 /*
  * We keep multiple buckets open for writes, and try to segregate different
- * write streams for better cache utilization: first we look for a bucket where
- * the last write to it was sequential with the current write, and failing that
- * we look for a bucket that was last used by the same task.
+ * write streams for better cache utilization: first we try to segregate flash
+ * only volume write streams from cached devices, secondly we look for a bucket
+ * where the last write to it was sequential with the current write, and
+ * failing that we look for a bucket that was last used by the same task.
  *
  * The ideas is if you've got multiple tasks pulling data into the cache at the
  * same time, you'll get better cache utilization if you try to segregate their
  * data and preserve locality.
  *
- * For example, say you've starting Firefox at the same time you're copying a
+ * For example, dirty sectors of flash only volume is not reclaimable, if their
+ * dirty sectors mixed with dirty sectors of cached device, such buckets will
+ * be marked as dirty and won't be reclaimed, though the dirty data of cached
+ * device have been written back to backend device.
+ *
+ * And say you've starting Firefox at the same time you're copying a
  * bunch of files. Firefox will likely end up being fairly hot and stay in the
  * cache awhile, but the data you copied might not be; if you wrote all that
  * data to the same buckets it'd get invalidated at the same time.
@@ -537,7 +543,10 @@
 	struct open_bucket *ret, *ret_task = NULL;
 
 	list_for_each_entry_reverse(ret, &c->data_buckets, list)
-		if (!bkey_cmp(&ret->key, search))
+		if (UUID_FLASH_ONLY(&c->uuids[KEY_INODE(&ret->key)]) !=
+		    UUID_FLASH_ONLY(&c->uuids[KEY_INODE(search)]))
+			continue;
+		else if (!bkey_cmp(&ret->key, search))
 			goto found;
 		else if (ret->last_write_point == write_point)
 			ret_task = ret;
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 28864ad..e4c2d5d 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -892,6 +892,12 @@
 
 	mutex_lock(&bch_register_lock);
 
+	cancel_delayed_work_sync(&dc->writeback_rate_update);
+	if (!IS_ERR_OR_NULL(dc->writeback_thread)) {
+		kthread_stop(dc->writeback_thread);
+		dc->writeback_thread = NULL;
+	}
+
 	memset(&dc->sb.set_uuid, 0, 16);
 	SET_BDEV_STATE(&dc->sb, BDEV_STATE_NONE);
 
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index be13ebf..f688bfe 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -1777,12 +1777,12 @@
 	    cmd == DM_LIST_VERSIONS_CMD)
 		return 0;
 
-	if ((cmd == DM_DEV_CREATE_CMD)) {
+	if (cmd == DM_DEV_CREATE_CMD) {
 		if (!*param->name) {
 			DMWARN("name not supplied when creating device");
 			return -EINVAL;
 		}
-	} else if ((*param->uuid && *param->name)) {
+	} else if (*param->uuid && *param->name) {
 		DMWARN("only supply one of name or uuid, cmd(%u)", cmd);
 		return -EINVAL;
 	}
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
index 5d0a996..d96aa84 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -19,6 +19,7 @@
 
 #include <linux/module.h>
 #include <linux/reboot.h>
+#include <linux/vmalloc.h>
 
 #define DM_MSG_PREFIX			"verity"
 
@@ -32,6 +33,7 @@
 #define DM_VERITY_OPT_LOGGING		"ignore_corruption"
 #define DM_VERITY_OPT_RESTART		"restart_on_corruption"
 #define DM_VERITY_OPT_IGN_ZEROES	"ignore_zero_blocks"
+#define DM_VERITY_OPT_AT_MOST_ONCE	"check_at_most_once"
 
 #define DM_VERITY_OPTS_MAX		(2 + DM_VERITY_OPTS_FEC)
 
@@ -395,6 +397,18 @@
 }
 
 /*
+ * Moves the bio iter one data block forward.
+ */
+static inline void verity_bv_skip_block(struct dm_verity *v,
+					struct dm_verity_io *io,
+					struct bvec_iter *iter)
+{
+	struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size);
+
+	bio_advance_iter(bio, iter, 1 << v->data_dev_block_bits);
+}
+
+/*
  * Verify one "dm_verity_io" structure.
  */
 static int verity_verify_io(struct dm_verity_io *io)
@@ -406,9 +420,16 @@
 
 	for (b = 0; b < io->n_blocks; b++) {
 		int r;
+		sector_t cur_block = io->block + b;
 		struct shash_desc *desc = verity_io_hash_desc(v, io);
 
-		r = verity_hash_for_block(v, io, io->block + b,
+		if (v->validated_blocks &&
+		    likely(test_bit(cur_block, v->validated_blocks))) {
+			verity_bv_skip_block(v, io, &io->iter);
+			continue;
+		}
+
+		r = verity_hash_for_block(v, io, cur_block,
 					  verity_io_want_digest(v, io),
 					  &is_zero);
 		if (unlikely(r < 0))
@@ -441,13 +462,16 @@
 			return r;
 
 		if (likely(memcmp(verity_io_real_digest(v, io),
-				  verity_io_want_digest(v, io), v->digest_size) == 0))
+				  verity_io_want_digest(v, io), v->digest_size) == 0)) {
+			if (v->validated_blocks)
+				set_bit(cur_block, v->validated_blocks);
 			continue;
+		}
 		else if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_DATA,
-					   io->block + b, NULL, &start) == 0)
+					   cur_block, NULL, &start) == 0)
 			continue;
 		else if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA,
-					   io->block + b))
+					   cur_block))
 			return -EIO;
 	}
 
@@ -641,6 +665,8 @@
 			args += DM_VERITY_OPTS_FEC;
 		if (v->zero_digest)
 			args++;
+		if (v->validated_blocks)
+			args++;
 		if (!args)
 			return;
 		DMEMIT(" %u", args);
@@ -659,6 +685,8 @@
 		}
 		if (v->zero_digest)
 			DMEMIT(" " DM_VERITY_OPT_IGN_ZEROES);
+		if (v->validated_blocks)
+			DMEMIT(" " DM_VERITY_OPT_AT_MOST_ONCE);
 		sz = verity_fec_status_table(v, sz, result, maxlen);
 		break;
 	}
@@ -712,6 +740,7 @@
 	if (v->bufio)
 		dm_bufio_client_destroy(v->bufio);
 
+	vfree(v->validated_blocks);
 	kfree(v->salt);
 	kfree(v->root_digest);
 	kfree(v->zero_digest);
@@ -733,6 +762,26 @@
 }
 EXPORT_SYMBOL_GPL(verity_dtr);
 
+static int verity_alloc_most_once(struct dm_verity *v)
+{
+	struct dm_target *ti = v->ti;
+
+	/* the bitset can only handle INT_MAX blocks */
+	if (v->data_blocks > INT_MAX) {
+		ti->error = "device too large to use check_at_most_once";
+		return -E2BIG;
+	}
+
+	v->validated_blocks = vzalloc(BITS_TO_LONGS(v->data_blocks) *
+				       sizeof(unsigned long));
+	if (!v->validated_blocks) {
+		ti->error = "failed to allocate bitset for check_at_most_once";
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
 static int verity_alloc_zero_digest(struct dm_verity *v)
 {
 	int r = -ENOMEM;
@@ -802,6 +851,12 @@
 			}
 			continue;
 
+		} else if (!strcasecmp(arg_name, DM_VERITY_OPT_AT_MOST_ONCE)) {
+			r = verity_alloc_most_once(v);
+			if (r)
+				return r;
+			continue;
+
 		} else if (verity_is_fec_opt_arg(arg_name)) {
 			r = verity_fec_parse_opt_args(as, v, &argc, arg_name);
 			if (r)
@@ -1070,7 +1125,7 @@
 
 static struct target_type verity_target = {
 	.name		= "verity",
-	.version	= {1, 3, 0},
+	.version	= {1, 4, 0},
 	.module		= THIS_MODULE,
 	.ctr		= verity_ctr,
 	.dtr		= verity_dtr,
diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h
index 75effca..6d6d8df 100644
--- a/drivers/md/dm-verity.h
+++ b/drivers/md/dm-verity.h
@@ -63,6 +63,7 @@
 	sector_t hash_level_block[DM_VERITY_MAX_LEVELS];
 
 	struct dm_verity_fec *fec;	/* forward error correction */
+	unsigned long *validated_blocks; /* bitset blocks validated */
 };
 
 struct dm_verity_io {
diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c
index ba7edcd..fcc2b57 100644
--- a/drivers/md/md-cluster.c
+++ b/drivers/md/md-cluster.c
@@ -1122,8 +1122,10 @@
 	cmsg.raid_slot = cpu_to_le32(rdev->desc_nr);
 	lock_comm(cinfo);
 	ret = __sendmsg(cinfo, &cmsg);
-	if (ret)
+	if (ret) {
+		unlock_comm(cinfo);
 		return ret;
+	}
 	cinfo->no_new_dev_lockres->flags |= DLM_LKF_NOQUEUE;
 	ret = dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_EX);
 	cinfo->no_new_dev_lockres->flags &= ~DLM_LKF_NOQUEUE;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index c17c882..2b04c720 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -3681,6 +3681,7 @@
 
 		if (blk_queue_discard(bdev_get_queue(rdev->bdev)))
 			discard_supported = true;
+		first = 0;
 	}
 
 	if (mddev->queue) {
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index edf37fd..a7549a4 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -110,8 +110,7 @@
 static inline void lock_all_device_hash_locks_irq(struct r5conf *conf)
 {
 	int i;
-	local_irq_disable();
-	spin_lock(conf->hash_locks);
+	spin_lock_irq(conf->hash_locks);
 	for (i = 1; i < NR_STRIPE_HASH_LOCKS; i++)
 		spin_lock_nest_lock(conf->hash_locks + i, conf->hash_locks);
 	spin_lock(&conf->device_lock);
@@ -121,9 +120,9 @@
 {
 	int i;
 	spin_unlock(&conf->device_lock);
-	for (i = NR_STRIPE_HASH_LOCKS; i; i--)
-		spin_unlock(conf->hash_locks + i - 1);
-	local_irq_enable();
+	for (i = NR_STRIPE_HASH_LOCKS - 1; i; i--)
+		spin_unlock(conf->hash_locks + i);
+	spin_unlock_irq(conf->hash_locks);
 }
 
 /* bio's attached to a stripe+device for I/O are linked together in bi_sector
@@ -732,12 +731,11 @@
 
 static void lock_two_stripes(struct stripe_head *sh1, struct stripe_head *sh2)
 {
-	local_irq_disable();
 	if (sh1 > sh2) {
-		spin_lock(&sh2->stripe_lock);
+		spin_lock_irq(&sh2->stripe_lock);
 		spin_lock_nested(&sh1->stripe_lock, 1);
 	} else {
-		spin_lock(&sh1->stripe_lock);
+		spin_lock_irq(&sh1->stripe_lock);
 		spin_lock_nested(&sh2->stripe_lock, 1);
 	}
 }
@@ -745,8 +743,7 @@
 static void unlock_two_stripes(struct stripe_head *sh1, struct stripe_head *sh2)
 {
 	spin_unlock(&sh1->stripe_lock);
-	spin_unlock(&sh2->stripe_lock);
-	local_irq_enable();
+	spin_unlock_irq(&sh2->stripe_lock);
 }
 
 /* Only freshly new full stripe normal write stripe can be added to a batch list */
diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c
index 142ae28..d558ed3 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.c
+++ b/drivers/media/i2c/cx25840/cx25840-core.c
@@ -420,11 +420,13 @@
 	INIT_WORK(&state->fw_work, cx25840_work_handler);
 	init_waitqueue_head(&state->fw_wait);
 	q = create_singlethread_workqueue("cx25840_fw");
-	prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
-	queue_work(q, &state->fw_work);
-	schedule();
-	finish_wait(&state->fw_wait, &wait);
-	destroy_workqueue(q);
+	if (q) {
+		prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
+		queue_work(q, &state->fw_work);
+		schedule();
+		finish_wait(&state->fw_wait, &wait);
+		destroy_workqueue(q);
+	}
 
 	/* 6. */
 	cx25840_write(client, 0x115, 0x8c);
@@ -634,11 +636,13 @@
 	INIT_WORK(&state->fw_work, cx25840_work_handler);
 	init_waitqueue_head(&state->fw_wait);
 	q = create_singlethread_workqueue("cx25840_fw");
-	prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
-	queue_work(q, &state->fw_work);
-	schedule();
-	finish_wait(&state->fw_wait, &wait);
-	destroy_workqueue(q);
+	if (q) {
+		prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
+		queue_work(q, &state->fw_work);
+		schedule();
+		finish_wait(&state->fw_wait, &wait);
+		destroy_workqueue(q);
+	}
 
 	/* Call the cx23888 specific std setup func, we no longer rely on
 	 * the generic cx24840 func.
@@ -752,11 +756,13 @@
 	INIT_WORK(&state->fw_work, cx25840_work_handler);
 	init_waitqueue_head(&state->fw_wait);
 	q = create_singlethread_workqueue("cx25840_fw");
-	prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
-	queue_work(q, &state->fw_work);
-	schedule();
-	finish_wait(&state->fw_wait, &wait);
-	destroy_workqueue(q);
+	if (q) {
+		prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
+		queue_work(q, &state->fw_work);
+		schedule();
+		finish_wait(&state->fw_wait, &wait);
+		destroy_workqueue(q);
+	}
 
 	cx25840_std_setup(client);
 
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
index 4168ce6..f7990b6 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
+++ b/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h
@@ -183,6 +183,7 @@
 	uint32_t                        num_out_map_entries;
 	void                           *priv;
 	uint64_t                        request_id;
+	bool                            init_packet;
 };
 
 /**
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_node.c b/drivers/media/platform/msm/camera/cam_core/cam_node.c
index a943680..0a9fabc 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_node.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_node.c
@@ -18,6 +18,34 @@
 #include "cam_trace.h"
 #include "cam_debug_util.h"
 
+static void cam_node_print_ctx_state(
+	struct cam_node *node)
+{
+	int i;
+	struct cam_context *ctx;
+
+	CAM_INFO(CAM_CORE, "[%s] state=%d, ctx_size %d",
+		node->name, node->state, node->ctx_size);
+
+	mutex_lock(&node->list_mutex);
+	for (i = 0; i < node->ctx_size; i++) {
+		ctx = &node->ctx_list[i];
+
+		spin_lock(&ctx->lock);
+		CAM_INFO(CAM_CORE,
+			"[%s][%d] : state=%d, refcount=%d, active_req_list=%d, pending_req_list=%d, wait_req_list=%d, free_req_list=%d",
+			ctx->dev_name ? ctx->dev_name : "null",
+			i, ctx->state,
+			atomic_read(&(ctx->refcount.refcount)),
+			list_empty(&ctx->active_req_list),
+			list_empty(&ctx->pending_req_list),
+			list_empty(&ctx->wait_req_list),
+			list_empty(&ctx->free_req_list));
+		spin_unlock(&ctx->lock);
+	}
+	mutex_unlock(&node->list_mutex);
+}
+
 static struct cam_context *cam_node_get_ctxt_from_free_list(
 		struct cam_node *node)
 {
@@ -75,6 +103,10 @@
 
 	ctx = cam_node_get_ctxt_from_free_list(node);
 	if (!ctx) {
+		CAM_ERR(CAM_CORE, "No free ctx in free list node %s",
+			node->name);
+		cam_node_print_ctx_state(node);
+
 		rc = -ENOMEM;
 		goto err;
 	}
@@ -86,6 +118,9 @@
 		goto free_ctx;
 	}
 
+	CAM_DBG(CAM_CORE, "[%s] Acquire ctx_id %d",
+		node->name, ctx->ctx_id);
+
 	return 0;
 free_ctx:
 	cam_context_putref(ctx);
@@ -260,6 +295,10 @@
 		CAM_ERR(CAM_CORE, "destroy device handle is failed node %s",
 			node->name);
 
+	CAM_DBG(CAM_CORE, "[%s] Release ctx_id=%d, refcount=%d",
+		node->name, ctx->ctx_id,
+		atomic_read(&(ctx->refcount.refcount)));
+
 	cam_context_putref(ctx);
 	return rc;
 }
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
index 97e977d..f9985eb 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
@@ -1244,6 +1244,7 @@
 	cfg.hw_update_entries = req_isp->cfg;
 	cfg.num_hw_update_entries = req_isp->num_cfg;
 	cfg.priv  = &req_isp->hw_update_data;
+	cfg.init_packet = 0;
 
 	rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg);
 	if (rc) {
@@ -2374,6 +2375,7 @@
 	arg.hw_update_entries = req_isp->cfg;
 	arg.num_hw_update_entries = req_isp->num_cfg;
 	arg.priv  = &req_isp->hw_update_data;
+	arg.init_packet = 1;
 
 	ctx_isp->frame_id = 0;
 	ctx_isp->active_req_cnt = 0;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index 0a127ef..38a4497 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -1611,7 +1611,7 @@
 			cdm_cmd->cmd[i].len = cmd->len;
 		}
 
-		if (cfg->request_id == 1)
+		if (cfg->init_packet)
 			init_completion(&ctx->config_done_complete);
 
 		CAM_DBG(CAM_ISP, "Submit to CDM");
@@ -1621,7 +1621,7 @@
 			return rc;
 		}
 
-		if (cfg->request_id == 1) {
+		if (cfg->init_packet) {
 			rc = wait_for_completion_timeout(
 				&ctx->config_done_complete,
 				msecs_to_jiffies(30));
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
index 1d38f3b..e869e2b 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
@@ -579,8 +579,15 @@
 				io_addr[plane_id] +=
 						io_cfg[i].offsets[plane_id];
 				CAM_DBG(CAM_ISP,
-					"get io_addr for plane %d: 0x%llx",
-					plane_id, io_addr[plane_id]);
+					"get io_addr for plane %d: 0x%llx, mem_hdl=0x%x",
+					plane_id, io_addr[plane_id],
+					io_cfg[i].mem_handle[plane_id]);
+
+				CAM_DBG(CAM_ISP,
+					"mmu_hdl=0x%x, size=%d, end=0x%x",
+					mmu_hdl, (int)size,
+					io_addr[plane_id]+size);
+
 			}
 			if (!plane_id) {
 				CAM_ERR(CAM_ISP, "No valid planes for res%d",
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c
index 8863275..3a89732 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -273,8 +273,7 @@
 int cam_tasklet_start(void  *tasklet_info)
 {
 	struct cam_tasklet_info       *tasklet = tasklet_info;
-	struct cam_tasklet_queue_cmd  *tasklet_cmd;
-	struct cam_tasklet_queue_cmd  *tasklet_cmd_temp;
+	int i = 0;
 
 	if (atomic_read(&tasklet->tasklet_active)) {
 		CAM_ERR(CAM_ISP, "Tasklet already active. idx = %d",
@@ -283,11 +282,11 @@
 	}
 	atomic_set(&tasklet->tasklet_active, 1);
 
-	/* flush the command queue first */
-	list_for_each_entry_safe(tasklet_cmd, tasklet_cmd_temp,
-		&tasklet->used_cmd_list, list) {
-		list_del_init(&tasklet_cmd->list);
-		list_add_tail(&tasklet_cmd->list, &tasklet->free_cmd_list);
+	/* clean up the command queue first */
+	for (i = 0; i < CAM_TASKLETQ_SIZE; i++) {
+		list_del_init(&tasklet->cmd_queue[i].list);
+		list_add_tail(&tasklet->cmd_queue[i].list,
+			&tasklet->free_cmd_list);
 	}
 
 	tasklet_enable(&tasklet->tasklet);
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
index 053eb00..d20450c 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
@@ -989,10 +989,6 @@
 	cam_io_w_mb(1, soc_info->reg_map[0].mem_base +
 		csid_reg->cmn_reg->csid_irq_cmd_addr);
 
-	/* Enable the top IRQ interrupt */
-	cam_io_w_mb(1, soc_info->reg_map[0].mem_base +
-			csid_reg->cmn_reg->csid_top_irq_mask_addr);
-
 	val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
 			csid_reg->cmn_reg->csid_hw_version_addr);
 	CAM_DBG(CAM_ISP, "CSID:%d CSID HW version: 0x%x",
@@ -2171,25 +2167,38 @@
 	struct cam_ife_csid_hw *csid_hw)
 {
 	int rc = 0;
+	uint32_t status;
 	struct cam_ife_csid_reg_offset *csid_reg =
 		csid_hw->csid_info->csid_reg;
+	struct cam_hw_soc_info          *soc_info;
 
-	init_completion(&csid_hw->csid_top_complete);
+	soc_info = &csid_hw->hw_info->soc_info;
+	/* clear the top interrupt first */
+	cam_io_w_mb(1, soc_info->reg_map[0].mem_base +
+		csid_reg->cmn_reg->csid_top_irq_clear_addr);
+	cam_io_w_mb(1, soc_info->reg_map[0].mem_base +
+		csid_reg->cmn_reg->csid_irq_cmd_addr);
+
 	cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb,
-		csid_hw->hw_info->soc_info.reg_map[0].mem_base +
+		soc_info->reg_map[0].mem_base +
 		csid_reg->cmn_reg->csid_rst_strobes_addr);
-
-	CAM_DBG(CAM_ISP, " Waiting for SW reset complete from irq handler");
-	rc = wait_for_completion_timeout(&csid_hw->csid_top_complete,
-		msecs_to_jiffies(IFE_CSID_TIMEOUT));
-	if (rc <= 0) {
-		CAM_ERR(CAM_ISP, "CSID:%d reset completion in fail rc = %d",
-			csid_hw->hw_intf->hw_idx, rc);
-		if (rc == 0)
-			rc = -ETIMEDOUT;
+	rc = readl_poll_timeout(soc_info->reg_map[0].mem_base +
+		csid_reg->cmn_reg->csid_top_irq_status_addr,
+			status, (status & 0x1) == 0x1,
+		CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US);
+	if (rc < 0) {
+		CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d",
+			  csid_hw->hw_intf->hw_idx, rc);
+		rc = -ETIMEDOUT;
 	} else {
+		CAM_DBG(CAM_ISP, "CSID:%d hw reset completed %d",
+			csid_hw->hw_intf->hw_idx, rc);
 		rc = 0;
 	}
+	cam_io_w_mb(1, soc_info->reg_map[0].mem_base +
+		csid_reg->cmn_reg->csid_top_irq_clear_addr);
+	cam_io_w_mb(1, soc_info->reg_map[0].mem_base +
+		csid_reg->cmn_reg->csid_irq_cmd_addr);
 
 	return rc;
 }
@@ -2529,8 +2538,6 @@
 		csid_reg->rdi_reg[i]->csid_rdi_irq_status_addr);
 
 	/* clear */
-	cam_io_w_mb(irq_status_top, soc_info->reg_map[0].mem_base +
-		csid_reg->cmn_reg->csid_top_irq_clear_addr);
 	cam_io_w_mb(irq_status_rx, soc_info->reg_map[0].mem_base +
 		csid_reg->csi2_reg->csid_csi2_rx_irq_clear_addr);
 	if (csid_reg->cmn_reg->no_pix)
@@ -2551,13 +2558,6 @@
 	CAM_DBG(CAM_ISP, "irq_status_rdi1= 0x%x", irq_status_rdi[1]);
 	CAM_DBG(CAM_ISP, "irq_status_rdi2= 0x%x", irq_status_rdi[2]);
 
-	if (irq_status_top) {
-		CAM_DBG(CAM_ISP, "CSID global reset complete......Exit");
-		complete(&csid_hw->csid_top_complete);
-		return IRQ_HANDLED;
-	}
-
-
 	if (irq_status_rx & BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) {
 		CAM_DBG(CAM_ISP, "csi rx reset complete");
 		complete(&csid_hw->csid_csi2_complete);
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
index 65052e1..adfac57 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
@@ -183,6 +183,7 @@
 	int32_t                      curr_idx = traverse_data->idx;
 	struct cam_req_mgr_req_tbl  *tbl;
 	struct cam_req_mgr_apply    *apply_data;
+	struct cam_req_mgr_tbl_slot *slot = NULL;
 
 	if (!traverse_data->tbl || !traverse_data->apply_data) {
 		CAM_ERR(CAM_CRM, "NULL pointer %pK %pK",
@@ -193,17 +194,18 @@
 
 	tbl = traverse_data->tbl;
 	apply_data = traverse_data->apply_data;
+	slot = &tbl->slot[curr_idx];
 	CAM_DBG(CAM_CRM,
 		"Enter pd %d idx %d state %d skip %d status %d skip_idx %d",
 		tbl->pd, curr_idx, tbl->slot[curr_idx].state,
 		tbl->skip_traverse, traverse_data->in_q->slot[curr_idx].status,
 		traverse_data->in_q->slot[curr_idx].skip_idx);
 
-	if ((tbl->inject_delay > 0) &&
+	if ((slot->inject_delay > 0) &&
 		(traverse_data->self_link == true)) {
 		CAM_DBG(CAM_CRM, "Injecting Delay of one frame");
 		apply_data[tbl->pd].req_id = -1;
-		tbl->inject_delay--;
+		slot->inject_delay--;
 		/* This pd table is not ready to proceed with asked idx */
 		SET_FAILURE_BIT(traverse_data->result, tbl->pd);
 		return -EAGAIN;
@@ -1593,10 +1595,13 @@
 		goto end;
 	}
 
-	if (add_req->skip_before_applying > tbl->inject_delay)
-		tbl->inject_delay = add_req->skip_before_applying;
-
 	slot = &tbl->slot[idx];
+	if (add_req->skip_before_applying > slot->inject_delay) {
+		slot->inject_delay = add_req->skip_before_applying;
+		CAM_DBG(CAM_CRM, "Req_id %llu injecting delay %u",
+			add_req->req_id, add_req->skip_before_applying);
+	}
+
 	if (slot->state != CRM_REQ_STATE_PENDING &&
 		slot->state != CRM_REQ_STATE_EMPTY) {
 		CAM_WARN(CAM_CRM, "Unexpected state %d for slot %d map %x",
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h
index 5ad23b7..73ffb81 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h
@@ -166,11 +166,13 @@
  * @idx           : slot index
  * @req_ready_map : mask tracking which all devices have request ready
  * @state         : state machine for life cycle of a slot
+ * @inject_delay  : insert extra bubbling for flash type of use cases
  */
 struct cam_req_mgr_tbl_slot {
 	int32_t             idx;
 	uint32_t            req_ready_map;
 	enum crm_req_state  state;
+	uint32_t            inject_delay;
 };
 
 /**
@@ -185,7 +187,6 @@
  * @pd_delta      : differnce between this table's pipeline delay and next
  * @num_slots     : number of request slots present in the table
  * @slot          : array of slots tracking requests availability at devices
- * @inject_delay  : insert extra bubbling for flash type of use cases
  */
 struct cam_req_mgr_req_tbl {
 	int32_t                     id;
@@ -197,7 +198,6 @@
 	int32_t                     pd_delta;
 	int32_t                     num_slots;
 	struct cam_req_mgr_tbl_slot slot[MAX_REQ_SLOTS];
-	uint32_t                    inject_delay;
 };
 
 /**
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c
index fb37526..da08bc7 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c
@@ -16,7 +16,6 @@
 #include "cam_cci_core.h"
 
 #define CCI_MAX_DELAY 1000000
-#define CCI_TIMEOUT msecs_to_jiffies(500)
 
 static struct v4l2_subdev *g_cci_subdev;
 
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h
index d25964e..7cde619 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h
@@ -45,7 +45,7 @@
 #define CYCLES_PER_MICRO_SEC_DEFAULT 4915
 #define CCI_MAX_DELAY 1000000
 
-#define CCI_TIMEOUT msecs_to_jiffies(500)
+#define CCI_TIMEOUT msecs_to_jiffies(1500)
 
 #define NUM_MASTERS 2
 #define NUM_QUEUES 2
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
index d5bee96..d58834c 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
@@ -730,8 +730,9 @@
 
 		s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE;
 		CAM_INFO(CAM_SENSOR,
-			"CAM_ACQUIRE_DEV Success, sensor_id:0x%x",
-			s_ctrl->sensordata->slave_info.sensor_id);
+			"CAM_ACQUIRE_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x",
+			s_ctrl->sensordata->slave_info.sensor_id,
+			s_ctrl->sensordata->slave_info.sensor_slave_addr);
 	}
 		break;
 	case CAM_RELEASE_DEV: {
@@ -770,8 +771,9 @@
 
 		s_ctrl->sensor_state = CAM_SENSOR_INIT;
 		CAM_INFO(CAM_SENSOR,
-			"CAM_RELEASE_DEV Success, sensor_id:0x%x",
-			s_ctrl->sensordata->slave_info.sensor_id);
+			"CAM_RELEASE_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x",
+			s_ctrl->sensordata->slave_info.sensor_id,
+			s_ctrl->sensordata->slave_info.sensor_slave_addr);
 		s_ctrl->streamon_count = 0;
 		s_ctrl->streamoff_count = 0;
 	}
@@ -810,8 +812,9 @@
 		}
 		s_ctrl->sensor_state = CAM_SENSOR_START;
 		CAM_INFO(CAM_SENSOR,
-			"CAM_START_DEV Success, sensor_id:0x%x",
-			s_ctrl->sensordata->slave_info.sensor_id);
+			"CAM_START_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x",
+			s_ctrl->sensordata->slave_info.sensor_id,
+			s_ctrl->sensordata->slave_info.sensor_slave_addr);
 	}
 		break;
 	case CAM_STOP_DEV: {
@@ -836,8 +839,9 @@
 		cam_sensor_release_resource(s_ctrl);
 		s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE;
 		CAM_INFO(CAM_SENSOR,
-			"CAM_STOP_DEV Success, sensor_id:0x%x",
-			s_ctrl->sensordata->slave_info.sensor_id);
+			"CAM_STOP_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x",
+			s_ctrl->sensordata->slave_info.sensor_id,
+			s_ctrl->sensordata->slave_info.sensor_slave_addr);
 	}
 		break;
 	case CAM_CONFIG_DEV: {
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
index a399963..10d29c9 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
@@ -1303,6 +1303,11 @@
 	for (index = 0; index < ctrl->power_setting_size; index++) {
 		CAM_DBG(CAM_SENSOR, "index: %d", index);
 		power_setting = &ctrl->power_setting[index];
+		if (!power_setting) {
+			CAM_ERR(CAM_SENSOR, "Invalid power up settings");
+			return -EINVAL;
+		}
+
 		CAM_DBG(CAM_SENSOR, "seq_type %d", power_setting->seq_type);
 
 		switch (power_setting->seq_type) {
@@ -1589,6 +1594,11 @@
 
 	pd = &ctrl->power_down_setting[index];
 
+	if (!pd) {
+		CAM_ERR(CAM_SENSOR, "Invalid power down setting");
+		return -EINVAL;
+	}
+
 	for (j = 0; j < num_vreg; j++) {
 		if (!strcmp(soc_info->rgltr_name[j], "cam_clk")) {
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
index 72586fa..6fc8e1e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -293,10 +293,18 @@
 	void __iomem *csiphybase;
 	enum snps_csiphy_mode mode = INVALID_MODE;
 	uint32_t value, num_tries, num_lanes, offset;
+	uint32_t clk_mux_reg = 0;
 
 	csiphybase = csiphy_dev->base;
+	if (csiphy_dev->clk_mux_base != NULL)
+		clk_mux_reg = msm_camera_io_r(csiphy_dev->clk_mux_base);
+	else {
+		pr_err("%s: invalid clk_mux_base\n", __func__);
+		return -EINVAL;
+	}
+
 	/* lane mask usage
-	 * BIT	  LANE
+	 * BIT     LANE
 	 * 0(LSB)  PHY A data 0
 	 * 1       PHY A data 1
 	 * 2       PHY B data 0
@@ -318,6 +326,9 @@
 			return -EINVAL;
 		}
 		csiphy_dev->snps_state = CONFIGURED_AGGREGATE_MODE;
+		clk_mux_reg &= ~0xff;
+		clk_mux_reg |= csiphy_params->csid_core << 4;
+		clk_mux_reg |= (uint32_t)csiphy_params->csid_core;
 	} else if (lane_mask == LANE_MASK_PHY_A) { /* PHY A */
 		/* 2 lane config */
 		num_lanes = 2;
@@ -333,6 +344,8 @@
 			pr_err("%s: invalid request\n", __func__);
 			return -EINVAL;
 		}
+		clk_mux_reg &= ~0xf;
+		clk_mux_reg |= (uint32_t)csiphy_params->csid_core;
 	} else if (lane_mask == LANE_MASK_PHY_B) { /* PHY B */
 		/* 2 lane config */
 		num_lanes = 2;
@@ -348,11 +361,17 @@
 			pr_err("%s: invalid request\n", __func__);
 			return -EINVAL;
 		}
+		clk_mux_reg &= ~0xf0;
+		clk_mux_reg |= csiphy_params->csid_core << 4;
 	} else { /* None of available configurations */
 		pr_err("%s: invalid configuration requested\n", __func__);
 		return -EINVAL;
 	}
 
+	msm_camera_io_w(clk_mux_reg, csiphy_dev->clk_mux_base);
+	/* ensure write is done */
+	mb();
+
 	if (mode == AGGREGATE_MODE || mode == TWO_LANE_PHY_A) {
 		ret = msm_csiphy_snps_2_lane_config(csiphy_dev,
 			csiphy_params, TWO_LANE_PHY_A, num_lanes);
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 9a7d272..3679c59 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -2275,6 +2275,7 @@
 			enable.enable = 0;
 		pdata = &enable;
 		inst->clk_data.low_latency_mode = (bool) enable.enable;
+		msm_dcvs_try_enable(inst);
 		break;
 	}
 	case V4L2_CID_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index 4a0aa58..6ae030f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -114,14 +114,18 @@
 {
 	struct recon_buf *binfo, *nextb;
 	struct vidc_input_cr_data *temp, *next;
-	u32 min_cf = 0, max_cf = 0;
-	u32 min_input_cr = 0, max_input_cr = 0, min_cr = 0, max_cr = 0;
+	u32 max_cr = 0, max_cf = 0, max_input_cr = 0;
+	u32 min_cr = MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO;
+	u32 min_input_cr = MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO;
+	u32 min_cf = MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR;
 
 	mutex_lock(&inst->reconbufs.lock);
 	list_for_each_entry_safe(binfo, nextb, &inst->reconbufs.list, list) {
-		min_cr = min(min_cr, binfo->CR);
+		if (binfo->CR)
+			min_cr = min(min_cr, binfo->CR);
+		if (binfo->CF)
+			min_cf = min(min_cf, binfo->CF);
 		max_cr = max(max_cr, binfo->CR);
-		min_cf = min(min_cf, binfo->CF);
 		max_cf = max(max_cf, binfo->CF);
 	}
 	mutex_unlock(&inst->reconbufs.lock);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index b392610..f9bc79c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -2035,6 +2035,7 @@
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
 	struct v4l2_event flush_event = {0};
+	struct recon_buf *binfo;
 	u32 *ptr = NULL;
 	enum hal_flush flush_type;
 	int rc;
@@ -2089,6 +2090,13 @@
 		goto exit;
 	}
 
+	mutex_lock(&inst->reconbufs.lock);
+	list_for_each_entry(binfo, &inst->reconbufs.list, list) {
+		binfo->CR = 0;
+		binfo->CF = 0;
+	}
+	mutex_unlock(&inst->reconbufs.lock);
+
 	dprintk(VIDC_DBG,
 		"Notify flush complete, flush_type: %x\n", flush_type);
 	v4l2_event_queue_fh(&inst->event_handler, &flush_event);
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 7e7ed47..ade04e3 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -60,6 +60,9 @@
 /* Poll interval in uS */
 #define POLL_INTERVAL_US 50
 
+#define VENUS_AXI_HALT_ACK_TIMEOUT_US		500000
+
+
 enum tzbsp_video_state {
 	TZBSP_VIDEO_STATE_SUSPEND = 0,
 	TZBSP_VIDEO_STATE_RESUME = 1,
@@ -2850,12 +2853,52 @@
 	mutex_unlock(&device->lock);
 }
 
+static int __halt_axi(struct venus_hfi_device *device)
+{
+	u32 reg;
+	int rc = 0;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid input\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Driver needs to make sure that clocks are enabled to read Venus AXI
+	 * registers. If not skip AXI HALT.
+	 */
+	if (!device->power_enabled) {
+		dprintk(VIDC_WARN,
+			"Clocks are OFF, skipping AXI HALT\n");
+		return -EINVAL;
+	}
+
+	/* Halt AXI and AXI IMEM VBIF Access */
+	reg = __read_register(device, VENUS_WRAPPER_AXI_HALT);
+	reg |= BRIC_AXI_HALT;
+	__write_register(device, VENUS_WRAPPER_AXI_HALT, reg);
+
+	/* Request for AXI bus port halt */
+	rc = readl_poll_timeout(device->hal_data->register_base
+			+ VENUS_WRAPPER_AXI_HALT_STATUS,
+			reg, reg & BRIC_AXI_HALT_ACK,
+			POLL_INTERVAL_US,
+			VENUS_AXI_HALT_ACK_TIMEOUT_US);
+	if (rc)
+		dprintk(VIDC_WARN, "AXI bus port halt timeout\n");
+
+	return rc;
+}
+
 static void __process_sys_error(struct venus_hfi_device *device)
 {
 	struct hfi_sfr_struct *vsfr = NULL;
 
 	__set_state(device, VENUS_STATE_DEINIT);
 
+	if (__halt_axi(device))
+		dprintk(VIDC_WARN, "Failed to halt AXI after SYS_ERROR\n");
+
 	vsfr = (struct hfi_sfr_struct *)device->sfr.align_virtual_addr;
 	if (vsfr) {
 		void *p = memchr(vsfr->rg_data, '\0', vsfr->bufSize);
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_io.h b/drivers/media/platform/msm/vidc/vidc_hfi_io.h
index 3433483..3ddd633 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_io.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_io.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -148,6 +148,12 @@
 #define VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK		BIT(0)
 #define VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US		500000
 
+#define VENUS_WRAPPER_AXI_HALT 0x000E2008
+#define VENUS_WRAPPER_AXI_HALT_STATUS 0x000E200C
+
+#define BRIC_AXI_HALT BIT(16)
+#define BRIC_AXI_HALT_ACK BIT(16)
+
 #define VIDC_VENUS0_WRAPPER_VBIF_REQ_PRIORITY \
 	(VIDC_WRAPPER_BASE_OFFS + 0x20)
 #define VIDC_VENUS0_WRAPPER_VBIF_PRIORITY_LEVEL \
diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c
index c12209c..390d708 100644
--- a/drivers/media/platform/pxa_camera.c
+++ b/drivers/media/platform/pxa_camera.c
@@ -2169,6 +2169,12 @@
 	pxa_dma_stop_channels(pcdev);
 
 	pxa_camera_destroy_formats(pcdev);
+
+	if (pcdev->mclk_clk) {
+		v4l2_clk_unregister(pcdev->mclk_clk);
+		pcdev->mclk_clk = NULL;
+	}
+
 	video_unregister_device(&pcdev->vdev);
 	pcdev->sensor = NULL;
 
@@ -2495,7 +2501,13 @@
 	dma_release_channel(pcdev->dma_chans[1]);
 	dma_release_channel(pcdev->dma_chans[2]);
 
-	v4l2_clk_unregister(pcdev->mclk_clk);
+	v4l2_async_notifier_unregister(&pcdev->notifier);
+
+	if (pcdev->mclk_clk) {
+		v4l2_clk_unregister(pcdev->mclk_clk);
+		pcdev->mclk_clk = NULL;
+	}
+
 	v4l2_device_unregister(&pcdev->v4l2_dev);
 
 	dev_info(&pdev->dev, "PXA Camera driver unloaded\n");
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index db525cd..d9f88a4 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -1381,8 +1381,13 @@
 		goto rc_dev_fail;
 
 	/* wire up inbound data handler */
-	usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp,
-				mceusb_dev_recv, ir, ep_in->bInterval);
+	if (usb_endpoint_xfer_int(ep_in))
+		usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp,
+				 mceusb_dev_recv, ir, ep_in->bInterval);
+	else
+		usb_fill_bulk_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp,
+				  mceusb_dev_recv, ir);
+
 	ir->urb_in->transfer_dma = ir->dma_in;
 	ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c
index 0324633..e56a49a 100644
--- a/drivers/media/usb/usbtv/usbtv-core.c
+++ b/drivers/media/usb/usbtv/usbtv-core.c
@@ -109,6 +109,8 @@
 	return 0;
 
 usbtv_audio_fail:
+	/* we must not free at this point */
+	usb_get_dev(usbtv->udev);
 	usbtv_video_free(usbtv);
 
 usbtv_video_fail:
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index 9eaab98..d4e93f1 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -101,7 +101,7 @@
 static int put_v4l2_window32(struct v4l2_window __user *kp,
 			     struct v4l2_window32 __user *up)
 {
-	struct v4l2_clip __user *kclips = kp->clips;
+	struct v4l2_clip __user *kclips;
 	struct v4l2_clip32 __user *uclips;
 	compat_caddr_t p;
 	u32 clipcount;
@@ -116,6 +116,8 @@
 	if (!clipcount)
 		return 0;
 
+	if (get_user(kclips, &kp->clips))
+		return -EFAULT;
 	if (get_user(p, &up->clips))
 		return -EFAULT;
 	uclips = compat_ptr(p);
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index 9ccf7f5..4299ce0 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -334,6 +334,10 @@
 	struct vb2_buffer *vb;
 	int ret;
 
+	/* Ensure that q->num_buffers+num_buffers is below VB2_MAX_FRAME */
+	num_buffers = min_t(unsigned int, num_buffers,
+			    VB2_MAX_FRAME - q->num_buffers);
+
 	for (buffer = 0; buffer < num_buffers; ++buffer) {
 		/* Allocate videobuf buffer structures */
 		vb = kzalloc(q->buf_struct_size, GFP_KERNEL);
diff --git a/drivers/misc/cxl/flash.c b/drivers/misc/cxl/flash.c
index c63d61e..381a9a1 100644
--- a/drivers/misc/cxl/flash.c
+++ b/drivers/misc/cxl/flash.c
@@ -401,8 +401,10 @@
 	if (down_interruptible(&sem) != 0)
 		return -EPERM;
 
-	if (!(adapter = get_cxl_adapter(adapter_num)))
-		return -ENODEV;
+	if (!(adapter = get_cxl_adapter(adapter_num))) {
+		rc = -ENODEV;
+		goto err_unlock;
+	}
 
 	file->private_data = adapter;
 	continue_token = 0;
@@ -446,6 +448,8 @@
 		free_page((unsigned long) le);
 err:
 	put_device(&adapter->dev);
+err_unlock:
+	up(&sem);
 
 	return rc;
 }
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 41f3186..60f5a8d 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -551,7 +551,6 @@
 		break;
 
 	default:
-		dev_err(dev->dev, ": unsupported ioctl %d.\n", cmd);
 		rets = -ENOIOCTLCMD;
 	}
 
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index c0143db..2b31ed3 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -4510,6 +4510,7 @@
 		strlcpy(entry->app_name, app_name, MAX_APP_NAME_SIZE);
 		if (__qseecom_get_fw_size(app_name, &fw_size, &app_arch)) {
 			ret = -EIO;
+			kfree(entry);
 			goto exit_entry_free;
 		}
 		entry->app_arch = app_arch;
diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c
index 728c65a..a940f97 100644
--- a/drivers/misc/uid_sys_stats.c
+++ b/drivers/misc/uid_sys_stats.c
@@ -14,6 +14,7 @@
  */
 
 #include <linux/atomic.h>
+#include <linux/cpufreq_times.h>
 #include <linux/err.h>
 #include <linux/hashtable.h>
 #include <linux/init.h>
@@ -422,6 +423,10 @@
 		kstrtol(end_uid, 10, &uid_end) != 0) {
 		return -EINVAL;
 	}
+
+	/* Also remove uids from /proc/uid_time_in_state */
+	cpufreq_task_times_remove_uids(uid_start, uid_end);
+
 	rt_mutex_lock(&uid_lock);
 
 	for (; uid_start <= uid_end; uid_start++) {
diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c
index f84a427..f735ab4 100644
--- a/drivers/misc/vmw_vmci/vmci_queue_pair.c
+++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c
@@ -298,8 +298,11 @@
 	size_t pas_size;
 	size_t vas_size;
 	size_t queue_size = sizeof(*queue) + sizeof(*queue->kernel_if);
-	const u64 num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
+	u64 num_pages;
 
+	if (size > SIZE_MAX - PAGE_SIZE)
+		return NULL;
+	num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
 	if (num_pages >
 		 (SIZE_MAX - queue_size) /
 		 (sizeof(*queue->kernel_if->u.g.pas) +
@@ -624,9 +627,12 @@
 {
 	struct vmci_queue *queue;
 	size_t queue_page_size;
-	const u64 num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
+	u64 num_pages;
 	const size_t queue_size = sizeof(*queue) + sizeof(*(queue->kernel_if));
 
+	if (size > SIZE_MAX - PAGE_SIZE)
+		return NULL;
+	num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
 	if (num_pages > (SIZE_MAX - queue_size) /
 		 sizeof(*queue->kernel_if->u.h.page))
 		return NULL;
diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c
index 684087d..1752007 100644
--- a/drivers/mmc/host/jz4740_mmc.c
+++ b/drivers/mmc/host/jz4740_mmc.c
@@ -368,9 +368,9 @@
 		host->irq_mask &= ~irq;
 	else
 		host->irq_mask |= irq;
-	spin_unlock_irqrestore(&host->lock, flags);
 
 	writew(host->irq_mask, host->base + JZ_REG_MMC_IMASK);
+	spin_unlock_irqrestore(&host->lock, flags);
 }
 
 static void jz4740_mmc_clock_enable(struct jz4740_mmc_host *host,
diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index b0b9ceb..cfb7947 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -492,6 +492,8 @@
 		slot->host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
 		break;
 	case INTEL_MRFLD_SDIO:
+		/* Advertise 2.0v for compatibility with the SDIO card's OCR */
+		slot->host->ocr_mask = MMC_VDD_20_21 | MMC_VDD_165_195;
 		slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE |
 					 MMC_CAP_POWER_OFF_CARD;
 		break;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index b674b38..36aecd2 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1575,6 +1575,13 @@
 	if (mode != MMC_POWER_OFF) {
 		switch (1 << vdd) {
 		case MMC_VDD_165_195:
+		/*
+		 * Without a regulator, SDHCI does not support 2.0v
+		 * so we only get here if the driver deliberately
+		 * added the 2.0v range to ocr_avail. Map it to 1.8v
+		 * for the purpose of turning on the power.
+		 */
+		case MMC_VDD_20_21:
 			pwr = SDHCI_POWER_180;
 			break;
 		case MMC_VDD_29_30:
diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c
index 7c0b27d..b479bd8 100644
--- a/drivers/mtd/chips/jedec_probe.c
+++ b/drivers/mtd/chips/jedec_probe.c
@@ -1889,6 +1889,8 @@
 	do {
 		uint32_t ofs = cfi_build_cmd_addr(0 + (bank << 8), map, cfi);
 		mask = (1 << (cfi->device_type * 8)) - 1;
+		if (ofs >= map->size)
+			return 0;
 		result = map_read(map, base + ofs);
 		bank++;
 	} while ((result.x[0] & mask) == CFI_MFR_CONTINUATION);
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 427039b..d9dab42 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -2047,18 +2047,20 @@
 
 	ret = nand_boot_init(this);
 	if (ret)
-		goto err_out;
+		goto err_nand_cleanup;
 	ret = chip->scan_bbt(mtd);
 	if (ret)
-		goto err_out;
+		goto err_nand_cleanup;
 
 	ret = mtd_device_register(mtd, NULL, 0);
 	if (ret)
-		goto err_out;
+		goto err_nand_cleanup;
 	return 0;
 
+err_nand_cleanup:
+	nand_cleanup(chip);
 err_out:
-	gpmi_nand_exit(this);
+	gpmi_free_dma_buffer(this);
 	return ret;
 }
 
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index a3e86e5..5fb4516 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4785,6 +4785,11 @@
 		goto err_free;
 	}
 	ecc->total = ecc->steps * ecc->bytes;
+	if (ecc->total > mtd->oobsize) {
+		WARN(1, "Total number of ECC bytes exceeded oobsize\n");
+		ret = -EINVAL;
+		goto err_free;
+	}
 
 	/*
 	 * The number of bytes available for a client to place data into
diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c
index 1cb3f77..766b2c3 100644
--- a/drivers/mtd/tests/oobtest.c
+++ b/drivers/mtd/tests/oobtest.c
@@ -193,6 +193,9 @@
 		ops.datbuf    = NULL;
 		ops.oobbuf    = readbuf;
 		err = mtd_read_oob(mtd, addr, &ops);
+		if (mtd_is_bitflip(err))
+			err = 0;
+
 		if (err || ops.oobretlen != use_len) {
 			pr_err("error: readoob failed at %#llx\n",
 			       (long long)addr);
@@ -227,6 +230,9 @@
 			ops.datbuf    = NULL;
 			ops.oobbuf    = readbuf;
 			err = mtd_read_oob(mtd, addr, &ops);
+			if (mtd_is_bitflip(err))
+				err = 0;
+
 			if (err || ops.oobretlen != mtd->oobavail) {
 				pr_err("error: readoob failed at %#llx\n",
 						(long long)addr);
@@ -286,6 +292,9 @@
 
 	/* read entire block's OOB at one go */
 	err = mtd_read_oob(mtd, addr, &ops);
+	if (mtd_is_bitflip(err))
+		err = 0;
+
 	if (err || ops.oobretlen != len) {
 		pr_err("error: readoob failed at %#llx\n",
 		       (long long)addr);
@@ -527,6 +536,9 @@
 	pr_info("attempting to start read past end of OOB\n");
 	pr_info("an error is expected...\n");
 	err = mtd_read_oob(mtd, addr0, &ops);
+	if (mtd_is_bitflip(err))
+		err = 0;
+
 	if (err) {
 		pr_info("error occurred as expected\n");
 		err = 0;
@@ -571,6 +583,9 @@
 		pr_info("attempting to read past end of device\n");
 		pr_info("an error is expected...\n");
 		err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
+		if (mtd_is_bitflip(err))
+			err = 0;
+
 		if (err) {
 			pr_info("error occurred as expected\n");
 			err = 0;
@@ -615,6 +630,9 @@
 		pr_info("attempting to read past end of device\n");
 		pr_info("an error is expected...\n");
 		err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
+		if (mtd_is_bitflip(err))
+			err = 0;
+
 		if (err) {
 			pr_info("error occurred as expected\n");
 			err = 0;
@@ -684,6 +702,9 @@
 		ops.datbuf    = NULL;
 		ops.oobbuf    = readbuf;
 		err = mtd_read_oob(mtd, addr, &ops);
+		if (mtd_is_bitflip(err))
+			err = 0;
+
 		if (err)
 			goto out;
 		if (memcmpshow(addr, readbuf, writebuf,
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
index 46913ef2..479a5f0 100644
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -244,7 +244,7 @@
 	 * in any case.
 	 */
 	if (mode & FMODE_WRITE) {
-		ret = -EPERM;
+		ret = -EROFS;
 		goto out_unlock;
 	}
 
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index e1da78f..68902b8 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -894,6 +894,17 @@
 		return -EINVAL;
 	}
 
+	/*
+	 * Both UBI and UBIFS have been designed for SLC NAND and NOR flashes.
+	 * MLC NAND is different and needs special care, otherwise UBI or UBIFS
+	 * will die soon and you will lose all your data.
+	 */
+	if (mtd->type == MTD_MLCNANDFLASH) {
+		pr_err("ubi: refuse attaching mtd%d - MLC NAND is not supported\n",
+			mtd->index);
+		return -EINVAL;
+	}
+
 	if (ubi_num == UBI_DEV_NUM_AUTO) {
 		/* Search for an empty slot in the @ubi_devices array */
 		for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++)
diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c
index 4f0bd6b..69dd216 100644
--- a/drivers/mtd/ubi/fastmap-wl.c
+++ b/drivers/mtd/ubi/fastmap-wl.c
@@ -362,7 +362,6 @@
 {
 	int i;
 
-	flush_work(&ubi->fm_work);
 	return_unused_pool_pebs(ubi, &ubi->fm_pool);
 	return_unused_pool_pebs(ubi, &ubi->fm_wl_pool);
 
diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
index c1f5c29..b44c8d3 100644
--- a/drivers/mtd/ubi/fastmap.c
+++ b/drivers/mtd/ubi/fastmap.c
@@ -828,6 +828,24 @@
 	return ret;
 }
 
+static struct ubi_ainf_peb *clone_aeb(struct ubi_attach_info *ai,
+				      struct ubi_ainf_peb *old)
+{
+	struct ubi_ainf_peb *new;
+
+	new = ubi_alloc_aeb(ai, old->pnum, old->ec);
+	if (!new)
+		return NULL;
+
+	new->vol_id = old->vol_id;
+	new->sqnum = old->sqnum;
+	new->lnum = old->lnum;
+	new->scrub = old->scrub;
+	new->copy_flag = old->copy_flag;
+
+	return new;
+}
+
 /**
  * ubi_scan_fastmap - scan the fastmap.
  * @ubi: UBI device object
@@ -847,7 +865,7 @@
 	struct ubi_vid_hdr *vh;
 	struct ubi_ec_hdr *ech;
 	struct ubi_fastmap_layout *fm;
-	struct ubi_ainf_peb *tmp_aeb, *aeb;
+	struct ubi_ainf_peb *aeb;
 	int i, used_blocks, pnum, fm_anchor, ret = 0;
 	size_t fm_size;
 	__be32 crc, tmp_crc;
@@ -857,9 +875,16 @@
 	if (fm_anchor < 0)
 		return UBI_NO_FASTMAP;
 
-	/* Move all (possible) fastmap blocks into our new attach structure. */
-	list_for_each_entry_safe(aeb, tmp_aeb, &scan_ai->fastmap, u.list)
-		list_move_tail(&aeb->u.list, &ai->fastmap);
+	/* Copy all (possible) fastmap blocks into our new attach structure. */
+	list_for_each_entry(aeb, &scan_ai->fastmap, u.list) {
+		struct ubi_ainf_peb *new;
+
+		new = clone_aeb(ai, aeb);
+		if (!new)
+			return -ENOMEM;
+
+		list_add(&new->u.list, &ai->fastmap);
+	}
 
 	down_write(&ubi->fm_protect);
 	memset(ubi->fm_buf, 0, ubi->fm_size);
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 4907c9b..513457a 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1524,39 +1524,6 @@
 			goto err_close;
 	}
 
-	/* If the mode uses primary, then the following is handled by
-	 * bond_change_active_slave().
-	 */
-	if (!bond_uses_primary(bond)) {
-		/* set promiscuity level to new slave */
-		if (bond_dev->flags & IFF_PROMISC) {
-			res = dev_set_promiscuity(slave_dev, 1);
-			if (res)
-				goto err_close;
-		}
-
-		/* set allmulti level to new slave */
-		if (bond_dev->flags & IFF_ALLMULTI) {
-			res = dev_set_allmulti(slave_dev, 1);
-			if (res)
-				goto err_close;
-		}
-
-		netif_addr_lock_bh(bond_dev);
-
-		dev_mc_sync_multiple(slave_dev, bond_dev);
-		dev_uc_sync_multiple(slave_dev, bond_dev);
-
-		netif_addr_unlock_bh(bond_dev);
-	}
-
-	if (BOND_MODE(bond) == BOND_MODE_8023AD) {
-		/* add lacpdu mc addr to mc list */
-		u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
-
-		dev_mc_add(slave_dev, lacpdu_multicast);
-	}
-
 	res = vlan_vids_add_by_dev(slave_dev, bond_dev);
 	if (res) {
 		netdev_err(bond_dev, "Couldn't add bond vlan ids to %s\n",
@@ -1719,6 +1686,40 @@
 		goto err_upper_unlink;
 	}
 
+	/* If the mode uses primary, then the following is handled by
+	 * bond_change_active_slave().
+	 */
+	if (!bond_uses_primary(bond)) {
+		/* set promiscuity level to new slave */
+		if (bond_dev->flags & IFF_PROMISC) {
+			res = dev_set_promiscuity(slave_dev, 1);
+			if (res)
+				goto err_sysfs_del;
+		}
+
+		/* set allmulti level to new slave */
+		if (bond_dev->flags & IFF_ALLMULTI) {
+			res = dev_set_allmulti(slave_dev, 1);
+			if (res) {
+				if (bond_dev->flags & IFF_PROMISC)
+					dev_set_promiscuity(slave_dev, -1);
+				goto err_sysfs_del;
+			}
+		}
+
+		netif_addr_lock_bh(bond_dev);
+		dev_mc_sync_multiple(slave_dev, bond_dev);
+		dev_uc_sync_multiple(slave_dev, bond_dev);
+		netif_addr_unlock_bh(bond_dev);
+
+		if (BOND_MODE(bond) == BOND_MODE_8023AD) {
+			/* add lacpdu mc addr to mc list */
+			u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
+
+			dev_mc_add(slave_dev, lacpdu_multicast);
+		}
+	}
+
 	bond->slave_cnt++;
 	bond_compute_features(bond);
 	bond_set_carrier(bond);
@@ -1742,6 +1743,9 @@
 	return 0;
 
 /* Undo stages on error */
+err_sysfs_del:
+	bond_sysfs_slave_del(new_slave);
+
 err_upper_unlink:
 	bond_upper_dev_unlink(bond, new_slave);
 
@@ -1749,9 +1753,6 @@
 	netdev_rx_handler_unregister(slave_dev);
 
 err_detach:
-	if (!bond_uses_primary(bond))
-		bond_hw_addr_flush(bond_dev, slave_dev);
-
 	vlan_vids_del_by_dev(slave_dev, bond_dev);
 	if (rcu_access_pointer(bond->primary_slave) == new_slave)
 		RCU_INIT_POINTER(bond->primary_slave, NULL);
@@ -2605,11 +2606,13 @@
 	bond_for_each_slave_rcu(bond, slave, iter) {
 		unsigned long trans_start = dev_trans_start(slave->dev);
 
+		slave->new_link = BOND_LINK_NOCHANGE;
+
 		if (slave->link != BOND_LINK_UP) {
 			if (bond_time_in_interval(bond, trans_start, 1) &&
 			    bond_time_in_interval(bond, slave->last_rx, 1)) {
 
-				slave->link  = BOND_LINK_UP;
+				slave->new_link = BOND_LINK_UP;
 				slave_state_changed = 1;
 
 				/* primary_slave has no meaning in round-robin
@@ -2636,7 +2639,7 @@
 			if (!bond_time_in_interval(bond, trans_start, 2) ||
 			    !bond_time_in_interval(bond, slave->last_rx, 2)) {
 
-				slave->link  = BOND_LINK_DOWN;
+				slave->new_link = BOND_LINK_DOWN;
 				slave_state_changed = 1;
 
 				if (slave->link_failure_count < UINT_MAX)
@@ -2667,6 +2670,11 @@
 		if (!rtnl_trylock())
 			goto re_arm;
 
+		bond_for_each_slave(bond, slave, iter) {
+			if (slave->new_link != BOND_LINK_NOCHANGE)
+				slave->link = slave->new_link;
+		}
+
 		if (slave_state_changed) {
 			bond_slave_state_change(bond);
 			if (BOND_MODE(bond) == BOND_MODE_XOR)
diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c
index e2512ab..e13c9cd 100644
--- a/drivers/net/ethernet/amazon/ena/ena_com.c
+++ b/drivers/net/ethernet/amazon/ena/ena_com.c
@@ -61,6 +61,8 @@
 
 #define ENA_MMIO_READ_TIMEOUT 0xFFFFFFFF
 
+#define ENA_REGS_ADMIN_INTR_MASK 1
+
 /*****************************************************************************/
 /*****************************************************************************/
 /*****************************************************************************/
@@ -232,11 +234,9 @@
 	tail_masked = admin_queue->sq.tail & queue_size_mask;
 
 	/* In case of queue FULL */
-	cnt = admin_queue->sq.tail - admin_queue->sq.head;
+	cnt = atomic_read(&admin_queue->outstanding_cmds);
 	if (cnt >= admin_queue->q_depth) {
-		pr_debug("admin queue is FULL (tail %d head %d depth: %d)\n",
-			 admin_queue->sq.tail, admin_queue->sq.head,
-			 admin_queue->q_depth);
+		pr_debug("admin queue is full.\n");
 		admin_queue->stats.out_of_space++;
 		return ERR_PTR(-ENOSPC);
 	}
@@ -508,15 +508,20 @@
 static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_ctx,
 						     struct ena_com_admin_queue *admin_queue)
 {
-	unsigned long flags;
-	u32 start_time;
+	unsigned long flags, timeout;
 	int ret;
 
-	start_time = ((u32)jiffies_to_usecs(jiffies));
+	timeout = jiffies + ADMIN_CMD_TIMEOUT_US;
 
-	while (comp_ctx->status == ENA_CMD_SUBMITTED) {
-		if ((((u32)jiffies_to_usecs(jiffies)) - start_time) >
-		    ADMIN_CMD_TIMEOUT_US) {
+	while (1) {
+		spin_lock_irqsave(&admin_queue->q_lock, flags);
+		ena_com_handle_admin_completion(admin_queue);
+		spin_unlock_irqrestore(&admin_queue->q_lock, flags);
+
+		if (comp_ctx->status != ENA_CMD_SUBMITTED)
+			break;
+
+		if (time_is_before_jiffies(timeout)) {
 			pr_err("Wait for completion (polling) timeout\n");
 			/* ENA didn't have any completion */
 			spin_lock_irqsave(&admin_queue->q_lock, flags);
@@ -528,10 +533,6 @@
 			goto err;
 		}
 
-		spin_lock_irqsave(&admin_queue->q_lock, flags);
-		ena_com_handle_admin_completion(admin_queue);
-		spin_unlock_irqrestore(&admin_queue->q_lock, flags);
-
 		msleep(100);
 	}
 
@@ -1449,6 +1450,12 @@
 
 void ena_com_set_admin_polling_mode(struct ena_com_dev *ena_dev, bool polling)
 {
+	u32 mask_value = 0;
+
+	if (polling)
+		mask_value = ENA_REGS_ADMIN_INTR_MASK;
+
+	writel(mask_value, ena_dev->reg_bar + ENA_REGS_INTR_MASK_OFF);
 	ena_dev->admin_queue.polling = polling;
 }
 
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c
index bfeaec5..0d9ce08 100644
--- a/drivers/net/ethernet/amazon/ena/ena_netdev.c
+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c
@@ -1542,6 +1542,7 @@
 			  "Failed to get TX queue handlers. TX queue num %d rc: %d\n",
 			  qid, rc);
 		ena_com_destroy_io_queue(ena_dev, ena_qid);
+		return rc;
 	}
 
 	ena_com_update_numa_node(tx_ring->ena_com_io_cq, ctx.numa_node);
@@ -1606,6 +1607,7 @@
 			  "Failed to get RX queue handlers. RX queue num %d rc: %d\n",
 			  qid, rc);
 		ena_com_destroy_io_queue(ena_dev, ena_qid);
+		return rc;
 	}
 
 	ena_com_update_numa_node(rx_ring->ena_com_io_cq, ctx.numa_node);
@@ -2806,6 +2808,11 @@
 {
 	int release_bars;
 
+	if (ena_dev->mem_bar)
+		devm_iounmap(&pdev->dev, ena_dev->mem_bar);
+
+	devm_iounmap(&pdev->dev, ena_dev->reg_bar);
+
 	release_bars = pci_select_bars(pdev, IORESOURCE_MEM) & ENA_BAR_MASK;
 	pci_release_selected_regions(pdev, release_bars);
 }
@@ -2893,8 +2900,9 @@
 		goto err_free_ena_dev;
 	}
 
-	ena_dev->reg_bar = ioremap(pci_resource_start(pdev, ENA_REG_BAR),
-				   pci_resource_len(pdev, ENA_REG_BAR));
+	ena_dev->reg_bar = devm_ioremap(&pdev->dev,
+					pci_resource_start(pdev, ENA_REG_BAR),
+					pci_resource_len(pdev, ENA_REG_BAR));
 	if (!ena_dev->reg_bar) {
 		dev_err(&pdev->dev, "failed to remap regs bar\n");
 		rc = -EFAULT;
@@ -2914,8 +2922,9 @@
 	ena_set_push_mode(pdev, ena_dev, &get_feat_ctx);
 
 	if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
-		ena_dev->mem_bar = ioremap_wc(pci_resource_start(pdev, ENA_MEM_BAR),
-					      pci_resource_len(pdev, ENA_MEM_BAR));
+		ena_dev->mem_bar = devm_ioremap_wc(&pdev->dev,
+						   pci_resource_start(pdev, ENA_MEM_BAR),
+						   pci_resource_len(pdev, ENA_MEM_BAR));
 		if (!ena_dev->mem_bar) {
 			rc = -EFAULT;
 			goto err_device_destroy;
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
index 651f308..fca2e42 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
@@ -1680,6 +1680,30 @@
 	}
 }
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id xgene_enet_acpi_match[] = {
+	{ "APMC0D05", XGENE_ENET1},
+	{ "APMC0D30", XGENE_ENET1},
+	{ "APMC0D31", XGENE_ENET1},
+	{ "APMC0D3F", XGENE_ENET1},
+	{ "APMC0D26", XGENE_ENET2},
+	{ "APMC0D25", XGENE_ENET2},
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match);
+#endif
+
+static const struct of_device_id xgene_enet_of_match[] = {
+	{.compatible = "apm,xgene-enet",    .data = (void *)XGENE_ENET1},
+	{.compatible = "apm,xgene1-sgenet", .data = (void *)XGENE_ENET1},
+	{.compatible = "apm,xgene1-xgenet", .data = (void *)XGENE_ENET1},
+	{.compatible = "apm,xgene2-sgenet", .data = (void *)XGENE_ENET2},
+	{.compatible = "apm,xgene2-xgenet", .data = (void *)XGENE_ENET2},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, xgene_enet_of_match);
+
 static int xgene_enet_probe(struct platform_device *pdev)
 {
 	struct net_device *ndev;
@@ -1826,32 +1850,6 @@
 	xgene_enet_remove(pdev);
 }
 
-#ifdef CONFIG_ACPI
-static const struct acpi_device_id xgene_enet_acpi_match[] = {
-	{ "APMC0D05", XGENE_ENET1},
-	{ "APMC0D30", XGENE_ENET1},
-	{ "APMC0D31", XGENE_ENET1},
-	{ "APMC0D3F", XGENE_ENET1},
-	{ "APMC0D26", XGENE_ENET2},
-	{ "APMC0D25", XGENE_ENET2},
-	{ }
-};
-MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match);
-#endif
-
-#ifdef CONFIG_OF
-static const struct of_device_id xgene_enet_of_match[] = {
-	{.compatible = "apm,xgene-enet",    .data = (void *)XGENE_ENET1},
-	{.compatible = "apm,xgene1-sgenet", .data = (void *)XGENE_ENET1},
-	{.compatible = "apm,xgene1-xgenet", .data = (void *)XGENE_ENET1},
-	{.compatible = "apm,xgene2-sgenet", .data = (void *)XGENE_ENET2},
-	{.compatible = "apm,xgene2-xgenet", .data = (void *)XGENE_ENET2},
-	{},
-};
-
-MODULE_DEVICE_TABLE(of, xgene_enet_of_match);
-#endif
-
 static struct platform_driver xgene_enet_driver = {
 	.driver = {
 		   .name = "xgene-enet",
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index ca6c471..31287ce 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -3887,15 +3887,26 @@
 		/* when transmitting in a vf, start bd must hold the ethertype
 		 * for fw to enforce it
 		 */
+		u16 vlan_tci = 0;
 #ifndef BNX2X_STOP_ON_ERROR
-		if (IS_VF(bp))
+		if (IS_VF(bp)) {
 #endif
-			tx_start_bd->vlan_or_ethertype =
-				cpu_to_le16(ntohs(eth->h_proto));
+			/* Still need to consider inband vlan for enforced */
+			if (__vlan_get_tag(skb, &vlan_tci)) {
+				tx_start_bd->vlan_or_ethertype =
+					cpu_to_le16(ntohs(eth->h_proto));
+			} else {
+				tx_start_bd->bd_flags.as_bitfield |=
+					(X_ETH_INBAND_VLAN <<
+					 ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT);
+				tx_start_bd->vlan_or_ethertype =
+					cpu_to_le16(vlan_tci);
+			}
 #ifndef BNX2X_STOP_ON_ERROR
-		else
+		} else {
 			/* used by FW for packet accounting */
 			tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod);
+		}
 #endif
 	}
 
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.c b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
index 0f68118..a36e386 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_ioc.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
@@ -2845,7 +2845,7 @@
 static void
 bfa_ioc_get_adapter_manufacturer(struct bfa_ioc *ioc, char *manufacturer)
 {
-	memcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
+	strncpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
 }
 
 static void
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 0c2a32a..3ec32d7 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -2742,6 +2742,16 @@
 	return -EOPNOTSUPP;
 }
 
+static netdev_features_t cxgb_fix_features(struct net_device *dev,
+					   netdev_features_t features)
+{
+	/* Disable GRO, if RX_CSUM is disabled */
+	if (!(features & NETIF_F_RXCSUM))
+		features &= ~NETIF_F_GRO;
+
+	return features;
+}
+
 static const struct net_device_ops cxgb4_netdev_ops = {
 	.ndo_open             = cxgb_open,
 	.ndo_stop             = cxgb_close,
@@ -2766,6 +2776,7 @@
 #endif
 	.ndo_set_tx_maxrate   = cxgb_set_tx_maxrate,
 	.ndo_setup_tc         = cxgb_setup_tc,
+	.ndo_fix_features     = cxgb_fix_features,
 };
 
 #ifdef CONFIG_PCI_IOV
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index 6fd3be6..ebeeb35 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -6185,13 +6185,18 @@
 	if (!t4_fw_matches_chip(adap, fw_hdr))
 		return -EINVAL;
 
+	/* Disable FW_OK flag so that mbox commands with FW_OK flag set
+	 * wont be sent when we are flashing FW.
+	 */
+	adap->flags &= ~FW_OK;
+
 	ret = t4_fw_halt(adap, mbox, force);
 	if (ret < 0 && !force)
-		return ret;
+		goto out;
 
 	ret = t4_load_fw(adap, fw_data, size);
 	if (ret < 0)
-		return ret;
+		goto out;
 
 	/*
 	 * Older versions of the firmware don't understand the new
@@ -6202,7 +6207,17 @@
 	 * its header flags to see if it advertises the capability.
 	 */
 	reset = ((be32_to_cpu(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0);
-	return t4_fw_restart(adap, mbox, reset);
+	ret = t4_fw_restart(adap, mbox, reset);
+
+	/* Grab potentially new Firmware Device Log parameters so we can see
+	 * how healthy the new Firmware is.  It's okay to contact the new
+	 * Firmware for these parameters even though, as far as it's
+	 * concerned, we've never said "HELLO" to it ...
+	 */
+	(void)t4_init_devlog_params(adap);
+out:
+	adap->flags |= FW_OK;
+	return ret;
 }
 
 /**
@@ -8073,7 +8088,16 @@
 		ret = t4_cim_read(adap, UP_UP_DBG_LA_DATA_A, 1, &la_buf[i]);
 		if (ret)
 			break;
-		idx = (idx + 1) & UPDBGLARDPTR_M;
+
+		/* Bits 0-3 of UpDbgLaRdPtr can be between 0000 to 1001 to
+		 * identify the 32-bit portion of the full 312-bit data
+		 */
+		if (is_t6(adap->params.chip) && (idx & 0xf) >= 9)
+			idx = (idx & 0xff0) + 0x10;
+		else
+			idx++;
+		/* address can't exceed 0xfff */
+		idx &= UPDBGLARDPTR_M;
 	}
 restart:
 	if (cfg & UPDBGLAEN_F) {
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
index f3ed9ce..9d64e8e 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
@@ -2616,8 +2616,8 @@
 int t4vf_sge_init(struct adapter *adapter)
 {
 	struct sge_params *sge_params = &adapter->params.sge;
-	u32 fl0 = sge_params->sge_fl_buffer_size[0];
-	u32 fl1 = sge_params->sge_fl_buffer_size[1];
+	u32 fl_small_pg = sge_params->sge_fl_buffer_size[0];
+	u32 fl_large_pg = sge_params->sge_fl_buffer_size[1];
 	struct sge *s = &adapter->sge;
 
 	/*
@@ -2625,9 +2625,20 @@
 	 * the Physical Function Driver.  Ideally we should be able to deal
 	 * with _any_ configuration.  Practice is different ...
 	 */
-	if (fl0 != PAGE_SIZE || (fl1 != 0 && fl1 <= fl0)) {
+
+	/* We only bother using the Large Page logic if the Large Page Buffer
+	 * is larger than our Page Size Buffer.
+	 */
+	if (fl_large_pg <= fl_small_pg)
+		fl_large_pg = 0;
+
+	/* The Page Size Buffer must be exactly equal to our Page Size and the
+	 * Large Page Size Buffer should be 0 (per above) or a power of 2.
+	 */
+	if (fl_small_pg != PAGE_SIZE ||
+	    (fl_large_pg & (fl_large_pg - 1)) != 0) {
 		dev_err(adapter->pdev_dev, "bad SGE FL buffer sizes [%d, %d]\n",
-			fl0, fl1);
+			fl_small_pg, fl_large_pg);
 		return -EINVAL;
 	}
 	if ((sge_params->sge_control & RXPKTCPLMODE_F) !=
@@ -2639,8 +2650,8 @@
 	/*
 	 * Now translate the adapter parameters into our internal forms.
 	 */
-	if (fl1)
-		s->fl_pg_order = ilog2(fl1) - PAGE_SHIFT;
+	if (fl_large_pg)
+		s->fl_pg_order = ilog2(fl_large_pg) - PAGE_SHIFT;
 	s->stat_len = ((sge_params->sge_control & EGRSTATUSPAGESIZE_F)
 			? 128 : 64);
 	s->pktshift = PKTSHIFT_G(sge_params->sge_control);
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 05e5b38..fe00f71 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -2371,6 +2371,10 @@
 static inline void fec_enet_update_ethtool_stats(struct net_device *dev)
 {
 }
+
+static inline void fec_enet_clear_ethtool_stats(struct net_device *dev)
+{
+}
 #endif /* !defined(CONFIG_M5272) */
 
 static int fec_enet_nway_reset(struct net_device *dev)
diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
index 446c7b3..a10de1e 100644
--- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c
+++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
@@ -381,7 +381,7 @@
 {
 	const struct of_device_id *id =
 		of_match_device(fsl_pq_mdio_match, &pdev->dev);
-	const struct fsl_pq_mdio_data *data = id->data;
+	const struct fsl_pq_mdio_data *data;
 	struct device_node *np = pdev->dev.of_node;
 	struct resource res;
 	struct device_node *tbi;
@@ -389,6 +389,13 @@
 	struct mii_bus *new_bus;
 	int err;
 
+	if (!id) {
+		dev_err(&pdev->dev, "Failed to match device\n");
+		return -ENODEV;
+	}
+
+	data = id->data;
+
 	dev_dbg(&pdev->dev, "found %s compatible node\n", id->compatible);
 
 	new_bus = mdiobus_alloc_size(sizeof(*priv));
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
index 34b5e69..02a03bc 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
@@ -671,7 +671,7 @@
 
 static int hns_gmac_get_sset_count(int stringset)
 {
-	if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS)
+	if (stringset == ETH_SS_STATS)
 		return ARRAY_SIZE(g_gmac_stats_string);
 
 	return 0;
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
index 4ecb809..6ea8722 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
@@ -422,7 +422,7 @@
 
 int hns_ppe_get_sset_count(int stringset)
 {
-	if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS)
+	if (stringset == ETH_SS_STATS)
 		return ETH_PPE_STATIC_NUM;
 	return 0;
 }
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
index fbbbbff..f3be9ac 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
@@ -798,7 +798,7 @@
  */
 int hns_rcb_get_ring_sset_count(int stringset)
 {
-	if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS)
+	if (stringset == ETH_SS_STATS)
 		return HNS_RING_STATIC_REG_NUM;
 
 	return 0;
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
index 86a496d..6be0cae 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -1017,8 +1017,10 @@
 			cnt--;
 
 		return cnt;
-	} else {
+	} else if (stringset == ETH_SS_STATS) {
 		return (HNS_NET_STATS_CNT + ops->get_sset_count(h, stringset));
+	} else {
+		return -EOPNOTSUPP;
 	}
 }
 
diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index 8f13919..5977b69 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -342,6 +342,7 @@
 {
 	struct emac_regs __iomem *p = dev->emacp;
 	int n = 20;
+	bool __maybe_unused try_internal_clock = false;
 
 	DBG(dev, "reset" NL);
 
@@ -354,6 +355,7 @@
 	}
 
 #ifdef CONFIG_PPC_DCR_NATIVE
+do_retry:
 	/*
 	 * PPC460EX/GT Embedded Processor Advanced User's Manual
 	 * section 28.10.1 Mode Register 0 (EMACx_MR0) states:
@@ -361,10 +363,19 @@
 	 * of the EMAC. If none is present, select the internal clock
 	 * (SDR0_ETH_CFG[EMACx_PHY_CLK] = 1).
 	 * After a soft reset, select the external clock.
+	 *
+	 * The AR8035-A PHY Meraki MR24 does not provide a TX Clk if the
+	 * ethernet cable is not attached. This causes the reset to timeout
+	 * and the PHY detection code in emac_init_phy() is unable to
+	 * communicate and detect the AR8035-A PHY. As a result, the emac
+	 * driver bails out early and the user has no ethernet.
+	 * In order to stay compatible with existing configurations, the
+	 * driver will temporarily switch to the internal clock, after
+	 * the first reset fails.
 	 */
 	if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) {
-		if (dev->phy_address == 0xffffffff &&
-		    dev->phy_map == 0xffffffff) {
+		if (try_internal_clock || (dev->phy_address == 0xffffffff &&
+					   dev->phy_map == 0xffffffff)) {
 			/* No PHY: select internal loop clock before reset */
 			dcri_clrset(SDR0, SDR0_ETH_CFG,
 				    0, SDR0_ETH_CFG_ECS << dev->cell_index);
@@ -382,8 +393,15 @@
 
 #ifdef CONFIG_PPC_DCR_NATIVE
 	if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) {
-		if (dev->phy_address == 0xffffffff &&
-		    dev->phy_map == 0xffffffff) {
+		if (!n && !try_internal_clock) {
+			/* first attempt has timed out. */
+			n = 20;
+			try_internal_clock = true;
+			goto do_retry;
+		}
+
+		if (try_internal_clock || (dev->phy_address == 0xffffffff &&
+					   dev->phy_map == 0xffffffff)) {
 			/* No PHY: restore external clock source after reset */
 			dcri_clrset(SDR0, SDR0_ETH_CFG,
 				    SDR0_ETH_CFG_ECS << dev->cell_index, 0);
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 528a926..825ec8f 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -1182,6 +1182,7 @@
 	struct e1000_hw *hw = &adapter->hw;
 
 	if (er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID) {
+		struct sk_buff *skb = adapter->tx_hwtstamp_skb;
 		struct skb_shared_hwtstamps shhwtstamps;
 		u64 txstmp;
 
@@ -1190,9 +1191,14 @@
 
 		e1000e_systim_to_hwtstamp(adapter, &shhwtstamps, txstmp);
 
-		skb_tstamp_tx(adapter->tx_hwtstamp_skb, &shhwtstamps);
-		dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
+		/* Clear the global tx_hwtstamp_skb pointer and force writes
+		 * prior to notifying the stack of a Tx timestamp.
+		 */
 		adapter->tx_hwtstamp_skb = NULL;
+		wmb(); /* force write prior to skb_tstamp_tx */
+
+		skb_tstamp_tx(skb, &shhwtstamps);
+		dev_kfree_skb_any(skb);
 	} else if (time_after(jiffies, adapter->tx_hwtstamp_start
 			      + adapter->tx_timeout_factor * HZ)) {
 		dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
@@ -6645,12 +6651,17 @@
 static int e1000e_pm_suspend(struct device *dev)
 {
 	struct pci_dev *pdev = to_pci_dev(dev);
+	int rc;
 
 	e1000e_flush_lpic(pdev);
 
 	e1000e_pm_freeze(dev);
 
-	return __e1000_shutdown(pdev, false);
+	rc = __e1000_shutdown(pdev, false);
+	if (rc)
+		e1000e_pm_thaw(dev);
+
+	return rc;
 }
 
 static int e1000e_pm_resume(struct device *dev)
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
index ddf478d..614f93e 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
@@ -154,6 +154,7 @@
 	adapter->current_op = I40E_VIRTCHNL_OP_GET_VF_RESOURCES;
 	adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_CONFIG;
 	caps = I40E_VIRTCHNL_VF_OFFLOAD_L2 |
+	       I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF |
 	       I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ |
 	       I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG |
 	       I40E_VIRTCHNL_VF_OFFLOAD_VLAN |
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index a7895c4..9eb9b68 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -721,6 +721,7 @@
  **/
 static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)
 {
+	struct sk_buff *skb = adapter->ptp_tx_skb;
 	struct e1000_hw *hw = &adapter->hw;
 	struct skb_shared_hwtstamps shhwtstamps;
 	u64 regval;
@@ -748,10 +749,17 @@
 	shhwtstamps.hwtstamp =
 		ktime_add_ns(shhwtstamps.hwtstamp, adjust);
 
-	skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps);
-	dev_kfree_skb_any(adapter->ptp_tx_skb);
+	/* Clear the lock early before calling skb_tstamp_tx so that
+	 * applications are not woken up before the lock bit is clear. We use
+	 * a copy of the skb pointer to ensure other threads can't change it
+	 * while we're notifying the stack.
+	 */
 	adapter->ptp_tx_skb = NULL;
 	clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
+
+	/* Notify the stack and free the skb after we've unlocked */
+	skb_tstamp_tx(skb, &shhwtstamps);
+	dev_kfree_skb_any(skb);
 }
 
 /**
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 941c8e2..93ab0b3 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -5079,7 +5079,7 @@
 	INIT_WORK(&hw->restart_work, sky2_restart);
 
 	pci_set_drvdata(pdev, hw);
-	pdev->d3_delay = 150;
+	pdev->d3_delay = 200;
 
 	return 0;
 
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
index b04760a..af2e6ea 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
@@ -156,57 +156,63 @@
 static u8 mlx4_en_dcbnl_set_all(struct net_device *netdev)
 {
 	struct mlx4_en_priv *priv = netdev_priv(netdev);
+	struct mlx4_en_port_profile *prof = priv->prof;
 	struct mlx4_en_dev *mdev = priv->mdev;
+	u8 tx_pause, tx_ppp, rx_pause, rx_ppp;
 
 	if (!(priv->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
 		return 1;
 
 	if (priv->cee_config.pfc_state) {
 		int tc;
+		rx_ppp = prof->rx_ppp;
+		tx_ppp = prof->tx_ppp;
 
-		priv->prof->rx_pause = 0;
-		priv->prof->tx_pause = 0;
 		for (tc = 0; tc < CEE_DCBX_MAX_PRIO; tc++) {
 			u8 tc_mask = 1 << tc;
 
 			switch (priv->cee_config.dcb_pfc[tc]) {
 			case pfc_disabled:
-				priv->prof->tx_ppp &= ~tc_mask;
-				priv->prof->rx_ppp &= ~tc_mask;
+				tx_ppp &= ~tc_mask;
+				rx_ppp &= ~tc_mask;
 				break;
 			case pfc_enabled_full:
-				priv->prof->tx_ppp |= tc_mask;
-				priv->prof->rx_ppp |= tc_mask;
+				tx_ppp |= tc_mask;
+				rx_ppp |= tc_mask;
 				break;
 			case pfc_enabled_tx:
-				priv->prof->tx_ppp |= tc_mask;
-				priv->prof->rx_ppp &= ~tc_mask;
+				tx_ppp |= tc_mask;
+				rx_ppp &= ~tc_mask;
 				break;
 			case pfc_enabled_rx:
-				priv->prof->tx_ppp &= ~tc_mask;
-				priv->prof->rx_ppp |= tc_mask;
+				tx_ppp &= ~tc_mask;
+				rx_ppp |= tc_mask;
 				break;
 			default:
 				break;
 			}
 		}
-		en_dbg(DRV, priv, "Set pfc on\n");
+		rx_pause = !!(rx_ppp || tx_ppp) ? 0 : prof->rx_pause;
+		tx_pause = !!(rx_ppp || tx_ppp) ? 0 : prof->tx_pause;
 	} else {
-		priv->prof->rx_pause = 1;
-		priv->prof->tx_pause = 1;
-		en_dbg(DRV, priv, "Set pfc off\n");
+		rx_ppp = 0;
+		tx_ppp = 0;
+		rx_pause = prof->rx_pause;
+		tx_pause = prof->tx_pause;
 	}
 
 	if (mlx4_SET_PORT_general(mdev->dev, priv->port,
 				  priv->rx_skb_size + ETH_FCS_LEN,
-				  priv->prof->tx_pause,
-				  priv->prof->tx_ppp,
-				  priv->prof->rx_pause,
-				  priv->prof->rx_ppp)) {
+				  tx_pause, tx_ppp, rx_pause, rx_ppp)) {
 		en_err(priv, "Failed setting pause params\n");
 		return 1;
 	}
 
+	prof->tx_ppp = tx_ppp;
+	prof->rx_ppp = rx_ppp;
+	prof->tx_pause = tx_pause;
+	prof->rx_pause = rx_pause;
+
 	return 0;
 }
 
@@ -310,6 +316,7 @@
 		}
 
 		switch (ets->tc_tsa[i]) {
+		case IEEE_8021QAZ_TSA_VENDOR:
 		case IEEE_8021QAZ_TSA_STRICT:
 			break;
 		case IEEE_8021QAZ_TSA_ETS:
@@ -347,6 +354,10 @@
 	/* higher TC means higher priority => lower pg */
 	for (i = IEEE_8021QAZ_MAX_TCS - 1; i >= 0; i--) {
 		switch (ets->tc_tsa[i]) {
+		case IEEE_8021QAZ_TSA_VENDOR:
+			pg[i] = MLX4_EN_TC_VENDOR;
+			tc_tx_bw[i] = MLX4_EN_BW_MAX;
+			break;
 		case IEEE_8021QAZ_TSA_STRICT:
 			pg[i] = num_strict++;
 			tc_tx_bw[i] = MLX4_EN_BW_MAX;
@@ -403,6 +414,7 @@
 	struct mlx4_en_priv *priv = netdev_priv(dev);
 	struct mlx4_en_port_profile *prof = priv->prof;
 	struct mlx4_en_dev *mdev = priv->mdev;
+	u32 tx_pause, tx_ppp, rx_pause, rx_ppp;
 	int err;
 
 	en_dbg(DRV, priv, "cap: 0x%x en: 0x%x mbc: 0x%x delay: %d\n",
@@ -411,23 +423,26 @@
 			pfc->mbc,
 			pfc->delay);
 
-	prof->rx_pause = !pfc->pfc_en;
-	prof->tx_pause = !pfc->pfc_en;
-	prof->rx_ppp = pfc->pfc_en;
-	prof->tx_ppp = pfc->pfc_en;
+	rx_pause = prof->rx_pause && !pfc->pfc_en;
+	tx_pause = prof->tx_pause && !pfc->pfc_en;
+	rx_ppp = pfc->pfc_en;
+	tx_ppp = pfc->pfc_en;
 
 	err = mlx4_SET_PORT_general(mdev->dev, priv->port,
 				    priv->rx_skb_size + ETH_FCS_LEN,
-				    prof->tx_pause,
-				    prof->tx_ppp,
-				    prof->rx_pause,
-				    prof->rx_ppp);
-	if (err)
+				    tx_pause, tx_ppp, rx_pause, rx_ppp);
+	if (err) {
 		en_err(priv, "Failed setting pause params\n");
-	else
-		mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap,
-						prof->rx_ppp, prof->rx_pause,
-						prof->tx_ppp, prof->tx_pause);
+		return err;
+	}
+
+	mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap,
+					rx_ppp, rx_pause, tx_ppp, tx_pause);
+
+	prof->tx_ppp = tx_ppp;
+	prof->rx_ppp = rx_ppp;
+	prof->rx_pause = rx_pause;
+	prof->tx_pause = tx_pause;
 
 	return err;
 }
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index bdda17d..24977cc 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -1003,27 +1003,32 @@
 {
 	struct mlx4_en_priv *priv = netdev_priv(dev);
 	struct mlx4_en_dev *mdev = priv->mdev;
+	u8 tx_pause, tx_ppp, rx_pause, rx_ppp;
 	int err;
 
 	if (pause->autoneg)
 		return -EINVAL;
 
-	priv->prof->tx_pause = pause->tx_pause != 0;
-	priv->prof->rx_pause = pause->rx_pause != 0;
+	tx_pause = !!(pause->tx_pause);
+	rx_pause = !!(pause->rx_pause);
+	rx_ppp = priv->prof->rx_ppp && !(tx_pause || rx_pause);
+	tx_ppp = priv->prof->tx_ppp && !(tx_pause || rx_pause);
+
 	err = mlx4_SET_PORT_general(mdev->dev, priv->port,
 				    priv->rx_skb_size + ETH_FCS_LEN,
-				    priv->prof->tx_pause,
-				    priv->prof->tx_ppp,
-				    priv->prof->rx_pause,
-				    priv->prof->rx_ppp);
-	if (err)
-		en_err(priv, "Failed setting pause params\n");
-	else
-		mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap,
-						priv->prof->rx_ppp,
-						priv->prof->rx_pause,
-						priv->prof->tx_ppp,
-						priv->prof->tx_pause);
+				    tx_pause, tx_ppp, rx_pause, rx_ppp);
+	if (err) {
+		en_err(priv, "Failed setting pause params, err = %d\n", err);
+		return err;
+	}
+
+	mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap,
+					rx_ppp, rx_pause, tx_ppp, tx_pause);
+
+	priv->prof->tx_pause = tx_pause;
+	priv->prof->rx_pause = rx_pause;
+	priv->prof->tx_ppp = tx_ppp;
+	priv->prof->rx_ppp = rx_ppp;
 
 	return err;
 }
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c
index bf7628d..22c3fdd 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c
@@ -163,9 +163,9 @@
 		params->udp_rss = 0;
 	}
 	for (i = 1; i <= MLX4_MAX_PORTS; i++) {
-		params->prof[i].rx_pause = 1;
+		params->prof[i].rx_pause = !(pfcrx || pfctx);
 		params->prof[i].rx_ppp = pfcrx;
-		params->prof[i].tx_pause = 1;
+		params->prof[i].tx_pause = !(pfcrx || pfctx);
 		params->prof[i].tx_ppp = pfctx;
 		params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE;
 		params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index d223e7c..0160c93 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -3125,6 +3125,13 @@
 	priv->msg_enable = MLX4_EN_MSG_LEVEL;
 #ifdef CONFIG_MLX4_EN_DCB
 	if (!mlx4_is_slave(priv->mdev->dev)) {
+		u8 prio;
+
+		for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; ++prio) {
+			priv->ets.prio_tc[prio] = prio;
+			priv->ets.tc_tsa[prio]  = IEEE_8021QAZ_TSA_VENDOR;
+		}
+
 		priv->dcbx_cap = DCB_CAP_DCBX_VER_CEE | DCB_CAP_DCBX_HOST |
 			DCB_CAP_DCBX_VER_IEEE;
 		priv->flags |= MLX4_EN_DCB_ENABLED;
diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c
index 1a670b6..0710b36 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mcg.c
+++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c
@@ -35,6 +35,7 @@
 #include <linux/etherdevice.h>
 
 #include <linux/mlx4/cmd.h>
+#include <linux/mlx4/qp.h>
 #include <linux/export.h>
 
 #include "mlx4.h"
@@ -985,16 +986,21 @@
 	if (IS_ERR(mailbox))
 		return PTR_ERR(mailbox);
 
+	if (!mlx4_qp_lookup(dev, rule->qpn)) {
+		mlx4_err_rule(dev, "QP doesn't exist\n", rule);
+		ret = -EINVAL;
+		goto out;
+	}
+
 	trans_rule_ctrl_to_hw(rule, mailbox->buf);
 
 	size += sizeof(struct mlx4_net_trans_rule_hw_ctrl);
 
 	list_for_each_entry(cur, &rule->list, list) {
 		ret = parse_trans_rule(dev, cur, mailbox->buf + size);
-		if (ret < 0) {
-			mlx4_free_cmd_mailbox(dev, mailbox);
-			return ret;
-		}
+		if (ret < 0)
+			goto out;
+
 		size += ret;
 	}
 
@@ -1021,6 +1027,7 @@
 		}
 	}
 
+out:
 	mlx4_free_cmd_mailbox(dev, mailbox);
 
 	return ret;
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index df0f396..18f221d 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -472,6 +472,7 @@
 #define MLX4_EN_BW_MIN 1
 #define MLX4_EN_BW_MAX 100 /* Utilize 100% of the line */
 
+#define MLX4_EN_TC_VENDOR 0
 #define MLX4_EN_TC_ETS 7
 
 enum dcb_pfc_type {
diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c
index 6143113..474ff36 100644
--- a/drivers/net/ethernet/mellanox/mlx4/qp.c
+++ b/drivers/net/ethernet/mellanox/mlx4/qp.c
@@ -387,6 +387,19 @@
 		__mlx4_qp_free_icm(dev, qpn);
 }
 
+struct mlx4_qp *mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn)
+{
+	struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
+	struct mlx4_qp *qp;
+
+	spin_lock(&qp_table->lock);
+
+	qp = __mlx4_qp_lookup(dev, qpn);
+
+	spin_unlock(&qp_table->lock);
+	return qp;
+}
+
 int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp, gfp_t gfp)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
@@ -474,6 +487,12 @@
 	}
 
 	if (attr & MLX4_UPDATE_QP_QOS_VPORT) {
+		if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP)) {
+			mlx4_warn(dev, "Granular QoS per VF is not enabled\n");
+			err = -EOPNOTSUPP;
+			goto out;
+		}
+
 		qp_mask |= 1ULL << MLX4_UPD_QP_MASK_QOS_VPP;
 		cmd->qp_context.qos_vport = params->qos_vport;
 	}
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index 1822382..d6b06be 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -5048,6 +5048,7 @@
 						 &tracker->res_tree[RES_FS_RULE]);
 					list_del(&fs_rule->com.list);
 					spin_unlock_irq(mlx4_tlock(dev));
+					kfree(fs_rule->mirr_mbox);
 					kfree(fs_rule);
 					state = 0;
 					break;
@@ -5214,6 +5215,13 @@
 	mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex);
 }
 
+static void update_qos_vpp(struct mlx4_update_qp_context *ctx,
+			   struct mlx4_vf_immed_vlan_work *work)
+{
+	ctx->qp_mask |= cpu_to_be64(1ULL << MLX4_UPD_QP_MASK_QOS_VPP);
+	ctx->qp_context.qos_vport = work->qos_vport;
+}
+
 void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work)
 {
 	struct mlx4_vf_immed_vlan_work *work =
@@ -5328,11 +5336,10 @@
 					qp->sched_queue & 0xC7;
 				upd_context->qp_context.pri_path.sched_queue |=
 					((work->qos & 0x7) << 3);
-				upd_context->qp_mask |=
-					cpu_to_be64(1ULL <<
-						    MLX4_UPD_QP_MASK_QOS_VPP);
-				upd_context->qp_context.qos_vport =
-					work->qos_vport;
+
+				if (dev->caps.flags2 &
+				    MLX4_DEV_CAP_FLAG2_QOS_VPP)
+					update_qos_vpp(upd_context, work);
 			}
 
 			err = mlx4_cmd(dev, mailbox->dma,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 38981db..2d235e8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -2741,6 +2741,9 @@
 
 	mutex_unlock(&priv->state_lock);
 
+	if (mlx5e_vxlan_allowed(priv->mdev))
+		udp_tunnel_get_rx_info(netdev);
+
 	return err;
 }
 
@@ -3785,13 +3788,6 @@
 	if (netdev->reg_state != NETREG_REGISTERED)
 		return;
 
-	/* Device already registered: sync netdev system state */
-	if (mlx5e_vxlan_allowed(mdev)) {
-		rtnl_lock();
-		udp_tunnel_get_rx_info(netdev);
-		rtnl_unlock();
-	}
-
 	queue_work(priv->wq, &priv->set_rx_mode_work);
 }
 
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 981cd1d..3c183b8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -548,7 +548,6 @@
 	struct mlx5_priv *priv  = &mdev->priv;
 	struct msix_entry *msix = priv->msix_arr;
 	int irq                 = msix[i + MLX5_EQ_VEC_COMP_BASE].vector;
-	int err;
 
 	if (!zalloc_cpumask_var(&priv->irq_info[i].mask, GFP_KERNEL)) {
 		mlx5_core_warn(mdev, "zalloc_cpumask_var failed");
@@ -558,18 +557,11 @@
 	cpumask_set_cpu(cpumask_local_spread(i, priv->numa_node),
 			priv->irq_info[i].mask);
 
-	err = irq_set_affinity_hint(irq, priv->irq_info[i].mask);
-	if (err) {
-		mlx5_core_warn(mdev, "irq_set_affinity_hint failed,irq 0x%.4x",
-			       irq);
-		goto err_clear_mask;
-	}
+	if (IS_ENABLED(CONFIG_SMP) &&
+	    irq_set_affinity_hint(irq, priv->irq_info[i].mask))
+		mlx5_core_warn(mdev, "irq_set_affinity_hint failed, irq 0x%.4x", irq);
 
 	return 0;
-
-err_clear_mask:
-	free_cpumask_var(priv->irq_info[i].mask);
-	return err;
 }
 
 static void mlx5_irq_clear_affinity_hint(struct mlx5_core_dev *mdev, int i)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index bea9ae3..60e1edc 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -1448,8 +1448,7 @@
 	err = mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid,
 				      adding, true);
 	if (err) {
-		if (net_ratelimit())
-			netdev_err(mlxsw_sp_port->dev, "Failed to set FDB entry\n");
+		dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to set FDB entry\n");
 		return;
 	}
 
@@ -1509,8 +1508,7 @@
 	err = mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, lag_id, mac, fid, lag_vid,
 					  adding, true);
 	if (err) {
-		if (net_ratelimit())
-			netdev_err(mlxsw_sp_port->dev, "Failed to set FDB entry\n");
+		dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to set FDB entry\n");
 		return;
 	}
 
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
index b8d5270..e306765 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
@@ -247,7 +247,7 @@
 	cmd.req.arg3 = 0;
 
 	if (recv_ctx->state == NX_HOST_CTX_STATE_ACTIVE)
-		netxen_issue_cmd(adapter, &cmd);
+		rcode = netxen_issue_cmd(adapter, &cmd);
 
 	if (rcode != NX_RCODE_SUCCESS)
 		return -EIO;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c
index afe5e57..d023137 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_dev.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c
@@ -850,7 +850,7 @@
 						   NULL) +
 		       qed_cxt_get_proto_cid_count(p_hwfn, PROTOCOLID_ETH,
 						   NULL);
-	norm_regsize = roundup(QED_PF_DEMS_SIZE * non_pwm_conn, 4096);
+	norm_regsize = roundup(QED_PF_DEMS_SIZE * non_pwm_conn, PAGE_SIZE);
 	min_addr_reg1 = norm_regsize / 4096;
 	pwm_regsize = db_bar_size - norm_regsize;
 
@@ -1628,6 +1628,9 @@
 		DP_NOTICE(p_hwfn, "Unknown Speed in 0x%08x\n", link_temp);
 	}
 
+	p_hwfn->mcp_info->link_capabilities.default_speed_autoneg =
+		link->speed.autoneg;
+
 	link_temp &= NVM_CFG1_PORT_DRV_FLOW_CONTROL_MASK;
 	link_temp >>= NVM_CFG1_PORT_DRV_FLOW_CONTROL_OFFSET;
 	link->pause.autoneg = !!(link_temp &
diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c
index dba3fbe..0b949c6 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_main.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_main.c
@@ -1240,7 +1240,7 @@
 
 	/* TODO - at the moment assume supported and advertised speed equal */
 	if_link->supported_caps = QED_LM_FIBRE_BIT;
-	if (params.speed.autoneg)
+	if (link_caps.default_speed_autoneg)
 		if_link->supported_caps |= QED_LM_Autoneg_BIT;
 	if (params.pause.autoneg ||
 	    (params.pause.forced_rx && params.pause.forced_tx))
@@ -1250,6 +1250,10 @@
 		if_link->supported_caps |= QED_LM_Pause_BIT;
 
 	if_link->advertised_caps = if_link->supported_caps;
+	if (params.speed.autoneg)
+		if_link->advertised_caps |= QED_LM_Autoneg_BIT;
+	else
+		if_link->advertised_caps &= ~QED_LM_Autoneg_BIT;
 	if (params.speed.advertised_speeds &
 	    NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G)
 		if_link->advertised_caps |= QED_LM_1000baseT_Half_BIT |
diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h
index dff520e..7b7a84d 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h
@@ -35,6 +35,7 @@
 
 struct qed_mcp_link_capabilities {
 	u32 speed_capabilities;
+	bool default_speed_autoneg;
 };
 
 struct qed_mcp_link_state {
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index 509b596..bd1ec70 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -341,7 +341,7 @@
 			}
 			return -EIO;
 		}
-		usleep_range(1000, 1500);
+		udelay(1200);
 	}
 
 	if (id_reg)
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c b/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c
index be258d9..e3223f2 100644
--- a/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c
@@ -765,7 +765,7 @@
 		sizeof(struct mpi_coredump_global_header);
 	mpi_coredump->mpi_global_header.imageSize =
 		sizeof(struct ql_mpi_coredump);
-	memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump",
+	strncpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump",
 		sizeof(mpi_coredump->mpi_global_header.idString));
 
 	/* Get generic NIC reg dump */
@@ -1255,7 +1255,7 @@
 		sizeof(struct mpi_coredump_global_header);
 	mpi_coredump->mpi_global_header.imageSize =
 		sizeof(struct ql_reg_dump);
-	memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump",
+	strncpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump",
 		sizeof(mpi_coredump->mpi_global_header.idString));
 
 
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
index 6e2add9..8bbb55f 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.c
+++ b/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -296,8 +296,9 @@
 
 	/* Allocate rx SKB if we don't have one available. */
 	if (!qca->rx_skb) {
-		qca->rx_skb = netdev_alloc_skb(net_dev,
-					       net_dev->mtu + VLAN_ETH_HLEN);
+		qca->rx_skb = netdev_alloc_skb_ip_align(net_dev,
+							net_dev->mtu +
+							VLAN_ETH_HLEN);
 		if (!qca->rx_skb) {
 			netdev_dbg(net_dev, "out of RX resources\n");
 			qca->stats.out_of_mem++;
@@ -377,7 +378,7 @@
 					qca->rx_skb, qca->rx_skb->dev);
 				qca->rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
 				netif_rx_ni(qca->rx_skb);
-				qca->rx_skb = netdev_alloc_skb(net_dev,
+				qca->rx_skb = netdev_alloc_skb_ip_align(net_dev,
 					net_dev->mtu + VLAN_ETH_HLEN);
 				if (!qca->rx_skb) {
 					netdev_dbg(net_dev, "out of RX resources\n");
@@ -759,7 +760,8 @@
 	if (!qca->rx_buffer)
 		return -ENOBUFS;
 
-	qca->rx_skb = netdev_alloc_skb(dev, qca->net_dev->mtu + VLAN_ETH_HLEN);
+	qca->rx_skb = netdev_alloc_skb_ip_align(dev, qca->net_dev->mtu +
+						VLAN_ETH_HLEN);
 	if (!qca->rx_skb) {
 		kfree(qca->rx_buffer);
 		netdev_info(qca->net_dev, "Failed to allocate RX sk_buff.\n");
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 18e68c9..dbb6364 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -8446,12 +8446,12 @@
 		goto err_out_msi_5;
 	}
 
+	pci_set_drvdata(pdev, dev);
+
 	rc = register_netdev(dev);
 	if (rc < 0)
 		goto err_out_cnt_6;
 
-	pci_set_drvdata(pdev, dev);
-
 	netif_info(tp, probe, dev, "%s at 0x%p, %pM, XID %08x IRQ %d\n",
 		   rtl_chip_infos[chipset].name, ioaddr, dev->dev_addr,
 		   (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), pdev->irq);
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index b6816ae..c8fd99b 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -3133,7 +3133,7 @@
 	/* MDIO bus init */
 	ret = sh_mdio_init(mdp, pd);
 	if (ret) {
-		dev_err(&ndev->dev, "failed to initialise MDIO\n");
+		dev_err(&pdev->dev, "failed to initialise MDIO\n");
 		goto out_release;
 	}
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 98bbb91..c212d1d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -478,7 +478,10 @@
 			/* PTP v1, UDP, any kind of event packet */
 			config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
 			/* take time stamp for all event messages */
-			snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
+			if (priv->plat->has_gmac4)
+				snap_type_sel = PTP_GMAC4_TCR_SNAPTYPSEL_1;
+			else
+				snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
 
 			ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
 			ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
@@ -510,7 +513,10 @@
 			config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
 			ptp_v2 = PTP_TCR_TSVER2ENA;
 			/* take time stamp for all event messages */
-			snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
+			if (priv->plat->has_gmac4)
+				snap_type_sel = PTP_GMAC4_TCR_SNAPTYPSEL_1;
+			else
+				snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
 
 			ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
 			ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
@@ -544,7 +550,10 @@
 			config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
 			ptp_v2 = PTP_TCR_TSVER2ENA;
 			/* take time stamp for all event messages */
-			snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
+			if (priv->plat->has_gmac4)
+				snap_type_sel = PTP_GMAC4_TCR_SNAPTYPSEL_1;
+			else
+				snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
 
 			ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
 			ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
index c06938c..174777c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
@@ -63,7 +63,8 @@
 /* Enable Snapshot for Messages Relevant to Master */
 #define	PTP_TCR_TSMSTRENA	BIT(15)
 /* Select PTP packets for Taking Snapshots */
-#define	PTP_TCR_SNAPTYPSEL_1	GENMASK(17, 16)
+#define	PTP_TCR_SNAPTYPSEL_1	BIT(16)
+#define	PTP_GMAC4_TCR_SNAPTYPSEL_1	GENMASK(17, 16)
 /* Enable MAC address for PTP Frame Filtering */
 #define	PTP_TCR_TSENMACADDR	BIT(18)
 
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 2bd1282..552de9c 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -282,6 +282,10 @@
 /* Bit definitions for the CPSW1_TS_SEQ_LTYPE register */
 #define CPSW_V1_SEQ_ID_OFS_SHIFT	16
 
+#define CPSW_MAX_BLKS_TX		15
+#define CPSW_MAX_BLKS_TX_SHIFT		4
+#define CPSW_MAX_BLKS_RX		5
+
 struct cpsw_host_regs {
 	u32	max_blks;
 	u32	blk_cnt;
@@ -1160,11 +1164,23 @@
 	switch (cpsw->version) {
 	case CPSW_VERSION_1:
 		slave_write(slave, TX_PRIORITY_MAPPING, CPSW1_TX_PRI_MAP);
+		/* Increase RX FIFO size to 5 for supporting fullduplex
+		 * flow control mode
+		 */
+		slave_write(slave,
+			    (CPSW_MAX_BLKS_TX << CPSW_MAX_BLKS_TX_SHIFT) |
+			    CPSW_MAX_BLKS_RX, CPSW1_MAX_BLKS);
 		break;
 	case CPSW_VERSION_2:
 	case CPSW_VERSION_3:
 	case CPSW_VERSION_4:
 		slave_write(slave, TX_PRIORITY_MAPPING, CPSW2_TX_PRI_MAP);
+		/* Increase RX FIFO size to 5 for supporting fullduplex
+		 * flow control mode
+		 */
+		slave_write(slave,
+			    (CPSW_MAX_BLKS_TX << CPSW_MAX_BLKS_TX_SHIFT) |
+			    CPSW_MAX_BLKS_RX, CPSW2_MAX_BLKS);
 		break;
 	}
 
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 3c1f89a..92ad43e 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -209,6 +209,7 @@
 	struct genevehdr *gnvh = geneve_hdr(skb);
 	struct metadata_dst *tun_dst = NULL;
 	struct pcpu_sw_netstats *stats;
+	unsigned int len;
 	int err = 0;
 	void *oiph;
 
@@ -222,8 +223,10 @@
 		tun_dst = udp_tun_rx_dst(skb, geneve_get_sk_family(gs), flags,
 					 vni_to_tunnel_id(gnvh->vni),
 					 gnvh->opt_len * 4);
-		if (!tun_dst)
+		if (!tun_dst) {
+			geneve->dev->stats.rx_dropped++;
 			goto drop;
+		}
 		/* Update tunnel dst according to Geneve options. */
 		ip_tunnel_info_opts_set(&tun_dst->u.tun_info,
 					gnvh->options, gnvh->opt_len * 4);
@@ -231,8 +234,11 @@
 		/* Drop packets w/ critical options,
 		 * since we don't support any...
 		 */
-		if (gnvh->critical)
+		if (gnvh->critical) {
+			geneve->dev->stats.rx_frame_errors++;
+			geneve->dev->stats.rx_errors++;
 			goto drop;
+		}
 	}
 
 	skb_reset_mac_header(skb);
@@ -243,8 +249,10 @@
 		skb_dst_set(skb, &tun_dst->dst);
 
 	/* Ignore packet loops (and multicast echo) */
-	if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr))
+	if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr)) {
+		geneve->dev->stats.rx_errors++;
 		goto drop;
+	}
 
 	oiph = skb_network_header(skb);
 	skb_reset_network_header(skb);
@@ -276,13 +284,15 @@
 		}
 	}
 
-	stats = this_cpu_ptr(geneve->dev->tstats);
-	u64_stats_update_begin(&stats->syncp);
-	stats->rx_packets++;
-	stats->rx_bytes += skb->len;
-	u64_stats_update_end(&stats->syncp);
-
-	gro_cells_receive(&geneve->gro_cells, skb);
+	len = skb->len;
+	err = gro_cells_receive(&geneve->gro_cells, skb);
+	if (likely(err == NET_RX_SUCCESS)) {
+		stats = this_cpu_ptr(geneve->dev->tstats);
+		u64_stats_update_begin(&stats->syncp);
+		stats->rx_packets++;
+		stats->rx_bytes += len;
+		u64_stats_update_end(&stats->syncp);
+	}
 	return;
 drop:
 	/* Consume bad packet */
@@ -332,7 +342,7 @@
 	struct geneve_sock *gs;
 	int opts_len;
 
-	/* Need Geneve and inner Ethernet header to be present */
+	/* Need UDP and Geneve header to be present */
 	if (unlikely(!pskb_may_pull(skb, GENEVE_BASE_HLEN)))
 		goto drop;
 
@@ -355,8 +365,10 @@
 	opts_len = geneveh->opt_len * 4;
 	if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len,
 				 htons(ETH_P_TEB),
-				 !net_eq(geneve->net, dev_net(geneve->dev))))
+				 !net_eq(geneve->net, dev_net(geneve->dev)))) {
+		geneve->dev->stats.rx_dropped++;
 		goto drop;
+	}
 
 	geneve_rx(geneve, gs, skb);
 	return 0;
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index 4bad0b8..27160d1 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -576,6 +576,8 @@
 	case HDLCDRVCTL_CALIBRATE:
 		if(!capable(CAP_SYS_RAWIO))
 			return -EPERM;
+		if (s->par.bitrate <= 0)
+			return -EINVAL;
 		if (bi.data.calibrate > INT_MAX / s->par.bitrate)
 			return -EINVAL;
 		s->hdlctx.calibrate = bi.data.calibrate * s->par.bitrate / 16;
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 2caac0c..365a48c 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -742,7 +742,12 @@
 	macsec_fill_iv(iv, secy->sci, pn);
 
 	sg_init_table(sg, ret);
-	skb_to_sgvec(skb, sg, 0, skb->len);
+	ret = skb_to_sgvec(skb, sg, 0, skb->len);
+	if (unlikely(ret < 0)) {
+		macsec_txsa_put(tx_sa);
+		kfree_skb(skb);
+		return ERR_PTR(ret);
+	}
 
 	if (tx_sc->encrypt) {
 		int len = skb->len - macsec_hdr_len(sci_present) -
@@ -949,7 +954,11 @@
 	macsec_fill_iv(iv, sci, ntohl(hdr->packet_number));
 
 	sg_init_table(sg, ret);
-	skb_to_sgvec(skb, sg, 0, skb->len);
+	ret = skb_to_sgvec(skb, sg, 0, skb->len);
+	if (unlikely(ret < 0)) {
+		kfree_skb(skb);
+		return ERR_PTR(ret);
+	}
 
 	if (hdr->tci_an & MACSEC_TCI_E) {
 		/* confidentiality: ethernet + macsec header
diff --git a/drivers/net/phy/mdio-mux.c b/drivers/net/phy/mdio-mux.c
index 963838d..599ce24 100644
--- a/drivers/net/phy/mdio-mux.c
+++ b/drivers/net/phy/mdio-mux.c
@@ -122,10 +122,9 @@
 	pb = devm_kzalloc(dev, sizeof(*pb), GFP_KERNEL);
 	if (pb == NULL) {
 		ret_val = -ENOMEM;
-		goto err_parent_bus;
+		goto err_pb_kz;
 	}
 
-
 	pb->switch_data = data;
 	pb->switch_fn = switch_fn;
 	pb->current_child = -1;
@@ -154,6 +153,7 @@
 		cb->mii_bus = mdiobus_alloc();
 		if (!cb->mii_bus) {
 			ret_val = -ENOMEM;
+			devm_kfree(dev, cb);
 			of_node_put(child_bus_node);
 			break;
 		}
@@ -170,7 +170,6 @@
 			mdiobus_free(cb->mii_bus);
 			devm_kfree(dev, cb);
 		} else {
-			of_node_get(child_bus_node);
 			cb->next = pb->children;
 			pb->children = cb;
 		}
@@ -181,9 +180,11 @@
 		return 0;
 	}
 
+	devm_kfree(dev, pb);
+err_pb_kz:
 	/* balance the reference of_mdio_find_bus() took */
-	put_device(&pb->mii_bus->dev);
-
+	if (!mux_bus)
+		put_device(&parent_bus->dev);
 err_parent_bus:
 	of_node_put(parent_bus_node);
 	return ret_val;
diff --git a/drivers/net/phy/mdio-xgene.c b/drivers/net/phy/mdio-xgene.c
index 39be3b8..20fbcc9 100644
--- a/drivers/net/phy/mdio-xgene.c
+++ b/drivers/net/phy/mdio-xgene.c
@@ -314,6 +314,30 @@
 }
 #endif
 
+static const struct of_device_id xgene_mdio_of_match[] = {
+	{
+		.compatible = "apm,xgene-mdio-rgmii",
+		.data = (void *)XGENE_MDIO_RGMII
+	},
+	{
+		.compatible = "apm,xgene-mdio-xfi",
+		.data = (void *)XGENE_MDIO_XFI
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, xgene_mdio_of_match);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id xgene_mdio_acpi_match[] = {
+	{ "APMC0D65", XGENE_MDIO_RGMII },
+	{ "APMC0D66", XGENE_MDIO_XFI },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(acpi, xgene_mdio_acpi_match);
+#endif
+
+
 static int xgene_mdio_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -439,32 +463,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_OF
-static const struct of_device_id xgene_mdio_of_match[] = {
-	{
-		.compatible = "apm,xgene-mdio-rgmii",
-		.data = (void *)XGENE_MDIO_RGMII
-	},
-	{
-		.compatible = "apm,xgene-mdio-xfi",
-		.data = (void *)XGENE_MDIO_XFI
-	},
-	{},
-};
-
-MODULE_DEVICE_TABLE(of, xgene_mdio_of_match);
-#endif
-
-#ifdef CONFIG_ACPI
-static const struct acpi_device_id xgene_mdio_acpi_match[] = {
-	{ "APMC0D65", XGENE_MDIO_RGMII },
-	{ "APMC0D66", XGENE_MDIO_XFI },
-	{ }
-};
-
-MODULE_DEVICE_TABLE(acpi, xgene_mdio_acpi_match);
-#endif
-
 static struct platform_driver xgene_mdio_driver = {
 	.driver = {
 		.name = "xgene-mdio",
diff --git a/drivers/net/phy/mdio-xgene.h b/drivers/net/phy/mdio-xgene.h
index 354241b..594a11d 100644
--- a/drivers/net/phy/mdio-xgene.h
+++ b/drivers/net/phy/mdio-xgene.h
@@ -132,10 +132,6 @@
 #define GET_BIT(field, src) \
 		xgene_enet_get_field_value(field ## _POS, 1, src)
 
-static const struct of_device_id xgene_mdio_of_match[];
-#ifdef CONFIG_ACPI
-static const struct acpi_device_id xgene_mdio_acpi_match[];
-#endif
 int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg);
 int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data);
 struct phy_device *xgene_enet_phy_register(struct mii_bus *bus, int phy_addr);
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index e2d9ca6..4d21764 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -148,6 +148,12 @@
 	if (phydev->drv->aneg_done)
 		return phydev->drv->aneg_done(phydev);
 
+	/* Avoid genphy_aneg_done() if the Clause 45 PHY does not
+	 * implement Clause 22 registers
+	 */
+	if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0)))
+		return -EINVAL;
+
 	return genphy_aneg_done(phydev);
 }
 
diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c
index 1951b10..3045c96 100644
--- a/drivers/net/ppp/pptp.c
+++ b/drivers/net/ppp/pptp.c
@@ -465,7 +465,6 @@
 	po->chan.mtu = dst_mtu(&rt->dst);
 	if (!po->chan.mtu)
 		po->chan.mtu = PPP_MRU;
-	ip_rt_put(rt);
 	po->chan.mtu -= PPTP_HEADER_OVERHEAD;
 
 	po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header);
diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c
index 27ed252..cfd81eb 100644
--- a/drivers/net/slip/slhc.c
+++ b/drivers/net/slip/slhc.c
@@ -509,6 +509,10 @@
 		if(x < 0 || x > comp->rslot_limit)
 			goto bad;
 
+		/* Check if the cstate is initialized */
+		if (!comp->rstate[x].initialized)
+			goto bad;
+
 		comp->flags &=~ SLF_TOSS;
 		comp->recv_current = x;
 	} else {
@@ -673,6 +677,7 @@
 	if (cs->cs_tcp.doff > 5)
 	  memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4);
 	cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2;
+	cs->initialized = true;
 	/* Put headers back on packet
 	 * Neither header checksum is recalculated
 	 */
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index a0a9c9d..8673ef3 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -1203,11 +1203,6 @@
 		goto err_dev_open;
 	}
 
-	netif_addr_lock_bh(dev);
-	dev_uc_sync_multiple(port_dev, dev);
-	dev_mc_sync_multiple(port_dev, dev);
-	netif_addr_unlock_bh(dev);
-
 	err = vlan_vids_add_by_dev(port_dev, dev);
 	if (err) {
 		netdev_err(dev, "Failed to add vlan ids to device %s\n",
@@ -1247,6 +1242,11 @@
 		goto err_option_port_add;
 	}
 
+	netif_addr_lock_bh(dev);
+	dev_uc_sync_multiple(port_dev, dev);
+	dev_mc_sync_multiple(port_dev, dev);
+	netif_addr_unlock_bh(dev);
+
 	port->index = -1;
 	list_add_tail_rcu(&port->list, &team->port_list);
 	team_port_enable(team, port);
@@ -1271,8 +1271,6 @@
 	vlan_vids_del_by_dev(port_dev, dev);
 
 err_vids_add:
-	dev_uc_unsync(port_dev, dev);
-	dev_mc_unsync(port_dev, dev);
 	dev_close(port_dev);
 
 err_dev_open:
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index 1fca002..4fb4686 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -774,6 +774,12 @@
 				      USB_CDC_PROTO_NONE),
 	.driver_info = (unsigned long)&wwan_info,
 }, {
+	/* Cinterion AHS3 modem by GEMALTO */
+	USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x0055, USB_CLASS_COMM,
+				      USB_CDC_SUBCLASS_ETHERNET,
+				      USB_CDC_PROTO_NONE),
+	.driver_info = (unsigned long)&wwan_info,
+}, {
 	/* Telit modules */
 	USB_VENDOR_AND_INTERFACE_INFO(0x1bc7, USB_CLASS_COMM,
 			USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index dc6d3b0..feb61ea 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -1118,6 +1118,7 @@
 	u16 n = 0, index, ndplen;
 	u8 ready2send = 0;
 	u32 delayed_ndp_size;
+	size_t padding_count;
 
 	/* When our NDP gets written in cdc_ncm_ndp(), then skb_out->len gets updated
 	 * accordingly. Otherwise, we should check here.
@@ -1274,11 +1275,13 @@
 	 * a ZLP after full sized NTBs.
 	 */
 	if (!(dev->driver_info->flags & FLAG_SEND_ZLP) &&
-	    skb_out->len > ctx->min_tx_pkt)
-		memset(skb_put(skb_out, ctx->tx_max - skb_out->len), 0,
-		       ctx->tx_max - skb_out->len);
-	else if (skb_out->len < ctx->tx_max && (skb_out->len % dev->maxpacket) == 0)
+	    skb_out->len > ctx->min_tx_pkt) {
+		padding_count = ctx->tx_max - skb_out->len;
+		memset(skb_put(skb_out, padding_count), 0, padding_count);
+	} else if (skb_out->len < ctx->tx_max &&
+		   (skb_out->len % dev->maxpacket) == 0) {
 		*skb_put(skb_out, 1) = 0;	/* force short packet */
+	}
 
 	/* set final frame length */
 	nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data;
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
index c53385a..f5a9667 100644
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -873,7 +873,8 @@
 			offset += 0x100;
 		else
 			ret = -EINVAL;
-		ret = lan78xx_read_raw_otp(dev, offset, length, data);
+		if (!ret)
+			ret = lan78xx_read_raw_otp(dev, offset, length, data);
 	}
 
 	return ret;
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 1568aed..472ed6d 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -529,7 +529,12 @@
 	hdr = skb_vnet_hdr(skb);
 	sg_init_table(rq->sg, 2);
 	sg_set_buf(rq->sg, hdr, vi->hdr_len);
-	skb_to_sgvec(skb, rq->sg + 1, 0, skb->len);
+
+	err = skb_to_sgvec(skb, rq->sg + 1, 0, skb->len);
+	if (unlikely(err < 0)) {
+		dev_kfree_skb(skb);
+		return err;
+	}
 
 	err = virtqueue_add_inbuf(rq->vq, rq->sg, 2, skb, gfp);
 	if (err < 0)
@@ -831,7 +836,7 @@
 	struct virtio_net_hdr_mrg_rxbuf *hdr;
 	const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
 	struct virtnet_info *vi = sq->vq->vdev->priv;
-	unsigned num_sg;
+	int num_sg;
 	unsigned hdr_len = vi->hdr_len;
 	bool can_push;
 
@@ -858,11 +863,16 @@
 	if (can_push) {
 		__skb_push(skb, hdr_len);
 		num_sg = skb_to_sgvec(skb, sq->sg, 0, skb->len);
+		if (unlikely(num_sg < 0))
+			return num_sg;
 		/* Pull header back to avoid skew in tx bytes calculations. */
 		__skb_pull(skb, hdr_len);
 	} else {
 		sg_set_buf(sq->sg, hdr, hdr_len);
-		num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len) + 1;
+		num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len);
+		if (unlikely(num_sg < 0))
+			return num_sg;
+		num_sg++;
 	}
 	return virtqueue_add_outbuf(sq->vq, sq->sg, num_sg, skb, GFP_ATOMIC);
 }
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 4afba17..f809eed 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -2962,6 +2962,11 @@
 	/* we need to enable NAPI, otherwise dev_close will deadlock */
 	for (i = 0; i < adapter->num_rx_queues; i++)
 		napi_enable(&adapter->rx_queue[i].napi);
+	/*
+	 * Need to clear the quiesce bit to ensure that vmxnet3_close
+	 * can quiesce the device properly
+	 */
+	clear_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state);
 	dev_close(adapter->netdev);
 }
 
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 346e486..42c9480 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -585,13 +585,15 @@
 	neigh = __ipv4_neigh_lookup_noref(dev, nexthop);
 	if (unlikely(!neigh))
 		neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);
-	if (!IS_ERR(neigh))
+	if (!IS_ERR(neigh)) {
 		ret = dst_neigh_output(dst, neigh, skb);
+		rcu_read_unlock_bh();
+		return ret;
+	}
 
 	rcu_read_unlock_bh();
 err:
-	if (unlikely(ret < 0))
-		vrf_tx_error(skb->dev, skb);
+	vrf_tx_error(skb->dev, skb);
 	return ret;
 }
 
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 0f5dfb8..28afdf2 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -930,7 +930,7 @@
 			return false;
 
 		/* Don't migrate static entries, drop packets */
-		if (f->state & NUD_NOARP)
+		if (f->state & (NUD_PERMANENT | NUD_NOARP))
 			return true;
 
 		if (net_ratelimit())
diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c
index 6564753..a8bd68f 100644
--- a/drivers/net/wan/fsl_ucc_hdlc.c
+++ b/drivers/net/wan/fsl_ucc_hdlc.c
@@ -137,7 +137,7 @@
 	priv->tx_ring_size = TX_BD_RING_LEN;
 	/* Alloc Rx BD */
 	priv->rx_bd_base = dma_alloc_coherent(priv->dev,
-			RX_BD_RING_LEN * sizeof(struct qe_bd *),
+			RX_BD_RING_LEN * sizeof(struct qe_bd),
 			&priv->dma_rx_bd, GFP_KERNEL);
 
 	if (!priv->rx_bd_base) {
@@ -148,7 +148,7 @@
 
 	/* Alloc Tx BD */
 	priv->tx_bd_base = dma_alloc_coherent(priv->dev,
-			TX_BD_RING_LEN * sizeof(struct qe_bd *),
+			TX_BD_RING_LEN * sizeof(struct qe_bd),
 			&priv->dma_tx_bd, GFP_KERNEL);
 
 	if (!priv->tx_bd_base) {
@@ -158,7 +158,7 @@
 	}
 
 	/* Alloc parameter ram for ucc hdlc */
-	priv->ucc_pram_offset = qe_muram_alloc(sizeof(priv->ucc_pram),
+	priv->ucc_pram_offset = qe_muram_alloc(sizeof(struct ucc_hdlc_param),
 				ALIGNMENT_OF_UCC_HDLC_PRAM);
 
 	if (priv->ucc_pram_offset < 0) {
@@ -295,11 +295,11 @@
 	qe_muram_free(priv->ucc_pram_offset);
 free_tx_bd:
 	dma_free_coherent(priv->dev,
-			  TX_BD_RING_LEN * sizeof(struct qe_bd *),
+			  TX_BD_RING_LEN * sizeof(struct qe_bd),
 			  priv->tx_bd_base, priv->dma_tx_bd);
 free_rx_bd:
 	dma_free_coherent(priv->dev,
-			  RX_BD_RING_LEN * sizeof(struct qe_bd *),
+			  RX_BD_RING_LEN * sizeof(struct qe_bd),
 			  priv->rx_bd_base, priv->dma_rx_bd);
 free_uccf:
 	ucc_fast_free(priv->uccf);
@@ -454,7 +454,7 @@
 static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit)
 {
 	struct net_device *dev = priv->ndev;
-	struct sk_buff *skb;
+	struct sk_buff *skb = NULL;
 	hdlc_device *hdlc = dev_to_hdlc(dev);
 	struct qe_bd *bd;
 	u32 bd_status;
@@ -688,7 +688,7 @@
 
 	if (priv->rx_bd_base) {
 		dma_free_coherent(priv->dev,
-				  RX_BD_RING_LEN * sizeof(struct qe_bd *),
+				  RX_BD_RING_LEN * sizeof(struct qe_bd),
 				  priv->rx_bd_base, priv->dma_rx_bd);
 
 		priv->rx_bd_base = NULL;
@@ -697,7 +697,7 @@
 
 	if (priv->tx_bd_base) {
 		dma_free_coherent(priv->dev,
-				  TX_BD_RING_LEN * sizeof(struct qe_bd *),
+				  TX_BD_RING_LEN * sizeof(struct qe_bd),
 				  priv->tx_bd_base, priv->dma_tx_bd);
 
 		priv->tx_bd_base = NULL;
@@ -1002,7 +1002,7 @@
 	struct device_node *np = pdev->dev.of_node;
 	struct ucc_hdlc_private *uhdlc_priv = NULL;
 	struct ucc_tdm_info *ut_info;
-	struct ucc_tdm *utdm;
+	struct ucc_tdm *utdm = NULL;
 	struct resource res;
 	struct net_device *dev;
 	hdlc_device *hdlc;
diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h
index 7d3231a..82bdec7 100644
--- a/drivers/net/wireless/ath/ath10k/bmi.h
+++ b/drivers/net/wireless/ath/ath10k/bmi.h
@@ -83,6 +83,8 @@
 #define BMI_NVRAM_SEG_NAME_SZ 16
 
 #define BMI_PARAM_GET_EEPROM_BOARD_ID 0x10
+#define BMI_PARAM_GET_FLASH_BOARD_ID 0x8000
+#define BMI_PARAM_FLASH_SECTION_ALL 0x10000
 
 #define ATH10K_BMI_BOARD_ID_FROM_OTP_MASK   0x7c00
 #define ATH10K_BMI_BOARD_ID_FROM_OTP_LSB    10
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 7b3017f..65ad7a1 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -652,7 +652,7 @@
 {
 	u32 result, address;
 	u8 board_id, chip_id;
-	int ret;
+	int ret, bmi_board_id_param;
 
 	address = ar->hw_params.patch_load_addr;
 
@@ -676,8 +676,13 @@
 		return ret;
 	}
 
-	ret = ath10k_bmi_execute(ar, address, BMI_PARAM_GET_EEPROM_BOARD_ID,
-				 &result);
+	if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT ||
+	    ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE)
+		bmi_board_id_param = BMI_PARAM_GET_FLASH_BOARD_ID;
+	else
+		bmi_board_id_param = BMI_PARAM_GET_EEPROM_BOARD_ID;
+
+	ret = ath10k_bmi_execute(ar, address, bmi_board_id_param, &result);
 	if (ret) {
 		ath10k_err(ar, "could not execute otp for board id check: %d\n",
 			   ret);
@@ -739,6 +744,11 @@
 		return ret;
 	}
 
+	/* As of now pre-cal is valid for 10_4 variants */
+	if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT ||
+	    ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE)
+		bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL;
+
 	ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result);
 	if (ret) {
 		ath10k_err(ar, "could not execute otp (%d)\n", ret);
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index 4f8d9ed..4a10544 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -939,7 +939,10 @@
 	}
 
 	for (i = 0; i < eesize; ++i) {
-		AR5K_EEPROM_READ(i, val);
+		if (!ath5k_hw_nvram_read(ah, i, &val)) {
+			ret = -EIO;
+			goto freebuf;
+		}
 		buf[i] = val;
 	}
 
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 1875387..0f34c43 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -33,10 +33,8 @@
 MODULE_PARM_DESC(ftm_mode, " Set factory test mode, default - false");
 
 #ifdef CONFIG_PM
-#ifdef CONFIG_PM_SLEEP
 static int wil6210_pm_notify(struct notifier_block *notify_block,
 			     unsigned long mode, void *unused);
-#endif /* CONFIG_PM_SLEEP */
 #endif /* CONFIG_PM */
 
 static
@@ -354,7 +352,6 @@
 	}
 
 #ifdef CONFIG_PM
-#ifdef CONFIG_PM_SLEEP
 	wil->pm_notify.notifier_call = wil6210_pm_notify;
 	rc = register_pm_notifier(&wil->pm_notify);
 	if (rc)
@@ -362,7 +359,6 @@
 		 * be prevented in a later phase if needed
 		 */
 		wil_err(wil, "register_pm_notifier failed: %d\n", rc);
-#endif /* CONFIG_PM_SLEEP */
 #endif /* CONFIG_PM */
 
 	wil6210_debugfs_init(wil);
@@ -397,9 +393,7 @@
 	wil_dbg_misc(wil, "pcie_remove\n");
 
 #ifdef CONFIG_PM
-#ifdef CONFIG_PM_SLEEP
 	unregister_pm_notifier(&wil->pm_notify);
-#endif /* CONFIG_PM_SLEEP */
 #endif /* CONFIG_PM */
 
 	wil_pm_runtime_forbid(wil);
@@ -428,7 +422,6 @@
 MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
 
 #ifdef CONFIG_PM
-#ifdef CONFIG_PM_SLEEP
 
 static int wil6210_suspend(struct device *dev, bool is_runtime)
 {
@@ -546,7 +539,6 @@
 {
 	return wil6210_resume(dev, false);
 }
-#endif /* CONFIG_PM_SLEEP */
 
 static int wil6210_pm_runtime_idle(struct device *dev)
 {
@@ -578,10 +570,12 @@
 #endif /* CONFIG_PM */
 
 static const struct dev_pm_ops wil6210_pm_ops = {
+#ifdef CONFIG_PM
 	SET_SYSTEM_SLEEP_PM_OPS(wil6210_pm_suspend, wil6210_pm_resume)
 	SET_RUNTIME_PM_OPS(wil6210_pm_runtime_suspend,
 			   wil6210_pm_runtime_resume,
 			   wil6210_pm_runtime_idle)
+#endif /* CONFIG_PM */
 };
 
 static struct pci_driver wil6210_driver = {
diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c
index 14533ed..0a96518 100644
--- a/drivers/net/wireless/ath/wil6210/pm.c
+++ b/drivers/net/wireless/ath/wil6210/pm.c
@@ -33,7 +33,11 @@
 	if (wmi_only || debug_fw) {
 		wil_dbg_pm(wil, "Deny any suspend - %s mode\n",
 			   wmi_only ? "wmi_only" : "debug_fw");
-		rc = -EPERM;
+		rc = -EBUSY;
+		goto out;
+	}
+	if (is_runtime && !wil->platform_ops.suspend) {
+		rc = -EBUSY;
 		goto out;
 	}
 	if (!(ndev->flags & IFF_UP)) {
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index dcec343..d0fecd9 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -323,6 +323,8 @@
 		return -ENOMEM;
 	}
 
+	d->mac.pn_15_0 = 0;
+	d->mac.pn_47_16 = 0;
 	d->dma.d0 = RX_DMA_D0_CMD_DMA_RT | RX_DMA_D0_CMD_DMA_IT;
 	wil_desc_addr_set(&d->dma.addr, pa);
 	/* ip_length don't care */
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 9b68663..f4476ee 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -798,9 +798,7 @@
 	int fw_calib_result;
 
 #ifdef CONFIG_PM
-#ifdef CONFIG_PM_SLEEP
 	struct notifier_block pm_notify;
-#endif /* CONFIG_PM_SLEEP */
 #endif /* CONFIG_PM */
 
 	bool suspend_resp_rcvd;
diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c
index 4c4c761..e4efb98 100644
--- a/drivers/net/wireless/cnss2/main.c
+++ b/drivers/net/wireless/cnss2/main.c
@@ -1675,6 +1675,7 @@
 
 static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv)
 {
+	plat_priv->cal_done = true;
 	cnss_wlfw_wlan_mode_send_sync(plat_priv, QMI_WLFW_OFF_V01);
 	cnss_shutdown(plat_priv);
 	clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h
index c11b206..b62c014 100644
--- a/drivers/net/wireless/cnss2/main.h
+++ b/drivers/net/wireless/cnss2/main.h
@@ -107,6 +107,7 @@
 	void *va;
 	phys_addr_t pa;
 	bool valid;
+	u32 type;
 };
 
 enum cnss_fw_dump_type {
@@ -198,7 +199,8 @@
 	struct wlfw_rf_board_info_s_v01 board_info;
 	struct wlfw_soc_info_s_v01 soc_info;
 	struct wlfw_fw_version_info_s_v01 fw_version_info;
-	struct cnss_fw_mem fw_mem;
+	u32 fw_mem_seg_len;
+	struct cnss_fw_mem fw_mem[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
 	struct cnss_fw_mem m3_mem;
 	struct cnss_pin_connect_result pin_result;
 	struct dentry *root_dentry;
@@ -210,6 +212,7 @@
 	u32 diag_reg_read_mem_type;
 	u32 diag_reg_read_len;
 	u8 *diag_reg_read_buf;
+	bool cal_done;
 };
 
 void *cnss_bus_dev_to_bus_priv(struct device *dev);
diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c
index 9d1fbf9..4726750 100644
--- a/drivers/net/wireless/cnss2/pci.c
+++ b/drivers/net/wireless/cnss2/pci.c
@@ -732,18 +732,21 @@
 int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv)
 {
 	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
-	struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
+	struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
+	int i;
 
-	if (!fw_mem->va && fw_mem->size) {
-		fw_mem->va = dma_alloc_coherent(&pci_priv->pci_dev->dev,
-						fw_mem->size, &fw_mem->pa,
-						GFP_KERNEL);
-		if (!fw_mem->va) {
-			cnss_pr_err("Failed to allocate memory for FW, size: 0x%zx\n",
-				    fw_mem->size);
-			fw_mem->size = 0;
+	for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
+		if (!fw_mem[i].va && fw_mem[i].size) {
+			fw_mem[i].va =
+				dma_alloc_coherent(&pci_priv->pci_dev->dev,
+						   fw_mem[i].size,
+						   &fw_mem[i].pa, GFP_KERNEL);
+			if (!fw_mem[i].va) {
+				cnss_pr_err("Failed to allocate memory for FW, size: 0x%zx, type: %u\n",
+					    fw_mem[i].size, fw_mem[i].type);
 
-			return -ENOMEM;
+				return -ENOMEM;
+			}
 		}
 	}
 
@@ -753,17 +756,25 @@
 static void cnss_pci_free_fw_mem(struct cnss_pci_data *pci_priv)
 {
 	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
-	struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
+	struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
+	int i;
 
-	if (fw_mem->va && fw_mem->size) {
-		cnss_pr_dbg("Freeing memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx\n",
-			    fw_mem->va, &fw_mem->pa, fw_mem->size);
-		dma_free_coherent(&pci_priv->pci_dev->dev, fw_mem->size,
-				  fw_mem->va, fw_mem->pa);
-		fw_mem->va = NULL;
-		fw_mem->pa = 0;
-		fw_mem->size = 0;
+	for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
+		if (fw_mem[i].va && fw_mem[i].size) {
+			cnss_pr_dbg("Freeing memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n",
+				    fw_mem[i].va, &fw_mem[i].pa,
+				    fw_mem[i].size, fw_mem[i].type);
+			dma_free_coherent(&pci_priv->pci_dev->dev,
+					  fw_mem[i].size, fw_mem[i].va,
+					  fw_mem[i].pa);
+			fw_mem[i].va = NULL;
+			fw_mem[i].pa = 0;
+			fw_mem[i].size = 0;
+			fw_mem[i].type = 0;
+		}
 	}
+
+	plat_priv->fw_mem_seg_len = 0;
 }
 
 int cnss_pci_load_m3(struct cnss_pci_data *pci_priv)
@@ -1107,7 +1118,7 @@
 	struct cnss_dump_seg *dump_seg =
 		plat_priv->ramdump_info_v2.dump_data_vaddr;
 	struct image_info *fw_image, *rddm_image;
-	struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
+	struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
 	int ret, i;
 
 	ret = mhi_download_rddm_img(pci_priv->mhi_ctrl, in_panic);
@@ -1152,18 +1163,20 @@
 
 	dump_data->nentries += rddm_image->entries;
 
-	if (fw_mem->pa && fw_mem->va && fw_mem->size) {
-		cnss_pr_dbg("Collect remote heap dump segment, nentries 1\n");
+	cnss_pr_dbg("Collect remote heap dump segment\n");
 
-		dump_seg->address = fw_mem->pa;
-		dump_seg->v_address = fw_mem->va;
-		dump_seg->size = fw_mem->size;
-		dump_seg->type = CNSS_FW_REMOTE_HEAP;
-		cnss_pr_dbg("seg-0: address 0x%lx, v_address %pK, size 0x%lx\n",
-			    dump_seg->address, dump_seg->v_address,
-			    dump_seg->size);
-		dump_seg++;
-		dump_data->nentries++;
+	for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
+		if (fw_mem[i].type == QMI_WLFW_MEM_TYPE_DDR_V01) {
+			dump_seg->address = fw_mem[i].pa;
+			dump_seg->v_address = fw_mem[i].va;
+			dump_seg->size = fw_mem[i].size;
+			dump_seg->type = CNSS_FW_REMOTE_HEAP;
+			cnss_pr_dbg("seg-%d: address 0x%lx, v_address %pK, size 0x%lx\n",
+				    i, dump_seg->address, dump_seg->v_address,
+				    dump_seg->size);
+			dump_seg++;
+			dump_data->nentries++;
+		}
 	}
 
 	if (dump_data->nentries > 0)
diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c
index f4344ae..b8777c1 100644
--- a/drivers/net/wireless/cnss2/qmi.c
+++ b/drivers/net/wireless/cnss2/qmi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -159,10 +159,9 @@
 	memset(&req, 0, sizeof(req));
 	memset(&resp, 0, sizeof(resp));
 
-	req.daemon_support_valid = 1;
-	req.daemon_support = daemon_support;
-
-	cnss_pr_dbg("daemon_support is %d\n", req.daemon_support);
+	req.num_clients_valid = 1;
+	req.num_clients = daemon_support ? 2 : 1;
+	cnss_pr_dbg("Number of clients is %d\n", req.num_clients);
 
 	req.wake_msi = cnss_get_wake_msi(plat_priv);
 	if (req.wake_msi) {
@@ -170,6 +169,19 @@
 		req.wake_msi_valid = 1;
 	}
 
+	req.bdf_support_valid = 1;
+	req.bdf_support = 1;
+
+	req.m3_support_valid = 1;
+	req.m3_support = 1;
+
+	req.m3_cache_support_valid = 1;
+	req.m3_cache_support = 1;
+
+	req.cal_done_valid = 1;
+	req.cal_done = plat_priv->cal_done;
+	cnss_pr_dbg("Calibration done is %d\n", plat_priv->cal_done);
+
 	req_desc.max_msg_len = WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN;
 	req_desc.msg_id = QMI_WLFW_HOST_CAP_REQ_V01;
 	req_desc.ei_array = wlfw_host_cap_req_msg_v01_ei;
@@ -221,8 +233,8 @@
 	req.request_mem_enable = 1;
 	req.fw_mem_ready_enable_valid = 1;
 	req.fw_mem_ready_enable = 1;
-	req.cold_boot_cal_done_enable_valid = 1;
-	req.cold_boot_cal_done_enable = 1;
+	req.fw_init_done_enable_valid = 1;
+	req.fw_init_done_enable = 1;
 	req.pin_connect_result_enable_valid = 1;
 	req.pin_connect_result_enable = 1;
 
@@ -260,27 +272,48 @@
 					  void *msg, unsigned int msg_len)
 {
 	struct msg_desc ind_desc;
-	struct wlfw_request_mem_ind_msg_v01 ind_msg;
-	struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
-	int ret = 0;
+	struct wlfw_request_mem_ind_msg_v01 *ind_msg;
+	int ret = 0, i;
+
+	ind_msg = kzalloc(sizeof(*ind_msg), GFP_KERNEL);
+	if (!ind_msg)
+		return -ENOMEM;
 
 	ind_desc.msg_id = QMI_WLFW_REQUEST_MEM_IND_V01;
 	ind_desc.max_msg_len = WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN;
 	ind_desc.ei_array = wlfw_request_mem_ind_msg_v01_ei;
 
-	ret = qmi_kernel_decode(&ind_desc, &ind_msg, msg, msg_len);
+	ret = qmi_kernel_decode(&ind_desc, ind_msg, msg, msg_len);
 	if (ret < 0) {
 		cnss_pr_err("Failed to decode request memory indication, msg_len: %u, err = %d\n",
 			    ret, msg_len);
-		return ret;
+		goto out;
 	}
 
-	fw_mem->size = ind_msg.size;
+	if (ind_msg->mem_seg_len == 0 ||
+	    ind_msg->mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG_V01) {
+		cnss_pr_err("Invalid memory segment length: %u\n",
+			    ind_msg->mem_seg_len);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	cnss_pr_dbg("FW memory segment count is %u\n", ind_msg->mem_seg_len);
+	plat_priv->fw_mem_seg_len = ind_msg->mem_seg_len;
+	for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
+		plat_priv->fw_mem[i].type = ind_msg->mem_seg[i].type;
+		plat_priv->fw_mem[i].size = ind_msg->mem_seg[i].size;
+	}
 
 	cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_REQUEST_MEM,
 			       0, NULL);
 
+	kfree(ind_msg);
 	return 0;
+
+out:
+	kfree(ind_msg);
+	return ret;
 }
 
 static int cnss_qmi_pin_result_ind_hdlr(struct cnss_plat_data *plat_priv,
@@ -317,30 +350,47 @@
 
 int cnss_wlfw_respond_mem_send_sync(struct cnss_plat_data *plat_priv)
 {
-	struct wlfw_respond_mem_req_msg_v01 req;
-	struct wlfw_respond_mem_resp_msg_v01 resp;
+	struct wlfw_respond_mem_req_msg_v01 *req;
+	struct wlfw_respond_mem_resp_msg_v01 *resp;
 	struct msg_desc req_desc, resp_desc;
-	struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
-	int ret = 0;
+	struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
+	int ret = 0, i;
 
 	cnss_pr_dbg("Sending respond memory message, state: 0x%lx\n",
 		    plat_priv->driver_state);
 
-	if (!fw_mem->pa || !fw_mem->size) {
-		cnss_pr_err("Memory for FW is not available!\n");
-		ret = -ENOMEM;
-		goto out;
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp)
+		return -ENOMEM;
+
+	req->mem_seg_len = plat_priv->fw_mem_seg_len;
+	for (i = 0; i < req->mem_seg_len; i++) {
+		if (!fw_mem[i].pa || !fw_mem[i].size) {
+			if (fw_mem[i].type == 0) {
+				cnss_pr_err("Invalid memory for FW type, segment = %d\n",
+					    i);
+				ret = -EINVAL;
+				goto out;
+			}
+			cnss_pr_err("Memory for FW is not available for type: %u\n",
+				    fw_mem[i].type);
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		cnss_pr_dbg("Memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n",
+			    fw_mem[i].va, &fw_mem[i].pa,
+			    fw_mem[i].size, fw_mem[i].type);
+
+		req->mem_seg[i].addr = fw_mem[i].pa;
+		req->mem_seg[i].size = fw_mem[i].size;
+		req->mem_seg[i].type = fw_mem[i].type;
 	}
 
-	cnss_pr_dbg("Memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx\n",
-		    fw_mem->va, &fw_mem->pa, fw_mem->size);
-
-	memset(&req, 0, sizeof(req));
-	memset(&resp, 0, sizeof(resp));
-
-	req.addr = fw_mem->pa;
-	req.size = fw_mem->size;
-
 	req_desc.max_msg_len = WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN;
 	req_desc.msg_id = QMI_WLFW_RESPOND_MEM_REQ_V01;
 	req_desc.ei_array = wlfw_respond_mem_req_msg_v01_ei;
@@ -349,8 +399,8 @@
 	resp_desc.msg_id = QMI_WLFW_RESPOND_MEM_RESP_V01;
 	resp_desc.ei_array = wlfw_respond_mem_resp_msg_v01_ei;
 
-	ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
-				sizeof(req), &resp_desc, &resp, sizeof(resp),
+	ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, req,
+				sizeof(*req), &resp_desc, resp, sizeof(*resp),
 				QMI_WLFW_TIMEOUT_MS);
 	if (ret < 0) {
 		cnss_pr_err("Failed to send respond memory request, err = %d\n",
@@ -358,16 +408,21 @@
 		goto out;
 	}
 
-	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
 		cnss_pr_err("Respond memory request failed, result: %d, err: %d\n",
-			    resp.resp.result, resp.resp.error);
-		ret = resp.resp.result;
+			    resp->resp.result, resp->resp.error);
+		ret = resp->resp.result;
 		goto out;
 	}
 
+	kfree(req);
+	kfree(resp);
 	return 0;
+
 out:
 	CNSS_ASSERT(0);
+	kfree(req);
+	kfree(resp);
 	return ret;
 }
 
@@ -908,12 +963,12 @@
 				       CNSS_DRIVER_EVENT_FW_MEM_READY,
 				       0, NULL);
 		break;
-	case QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01:
+	case QMI_WLFW_FW_READY_IND_V01:
 		cnss_driver_event_post(plat_priv,
 				       CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE,
 				       0, NULL);
 		break;
-	case QMI_WLFW_FW_READY_IND_V01:
+	case QMI_WLFW_FW_INIT_DONE_IND_V01:
 		cnss_driver_event_post(plat_priv,
 				       CNSS_DRIVER_EVENT_FW_READY,
 				       0, NULL);
@@ -974,11 +1029,11 @@
 	cnss_pr_info("QMI WLFW service connected, state: 0x%lx\n",
 		     plat_priv->driver_state);
 
-	ret = cnss_wlfw_host_cap_send_sync(plat_priv);
+	ret = cnss_wlfw_ind_register_send_sync(plat_priv);
 	if (ret < 0)
 		goto out;
 
-	ret = cnss_wlfw_ind_register_send_sync(plat_priv);
+	ret = cnss_wlfw_host_cap_send_sync(plat_priv);
 	if (ret < 0)
 		goto out;
 
diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c
index 7d6a771..bbf707b 100644
--- a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c
+++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -62,7 +62,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -97,7 +97,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -123,7 +123,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -140,7 +140,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -175,7 +175,131 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct elem_info wlfw_mem_cfg_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_mem_cfg_s_v01,
+					   offset),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_mem_cfg_s_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_mem_cfg_s_v01,
+					   secure_flag),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct elem_info wlfw_mem_seg_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_mem_seg_s_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_mem_type_enum_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_mem_seg_s_v01,
+					   type),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_mem_seg_s_v01,
+					   mem_cfg_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_MEM_CFG_V01,
+		.elem_size      = sizeof(struct wlfw_mem_cfg_s_v01),
+		.is_array       = VAR_LEN_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_mem_seg_s_v01,
+					   mem_cfg),
+		.ei_array      = wlfw_mem_cfg_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct elem_info wlfw_mem_seg_resp_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_mem_seg_resp_s_v01,
+					   addr),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_mem_seg_resp_s_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_mem_type_enum_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_mem_seg_resp_s_v01,
+					   type),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_mem_seg_resp_s_v01,
+					   restore),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -201,7 +325,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -218,7 +342,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -235,7 +359,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -261,7 +385,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -418,7 +542,7 @@
 		.is_array       = NO_ARRAY,
 		.tlv_type       = 0x18,
 		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
-					   cold_boot_cal_done_enable_valid),
+					   fw_init_done_enable_valid),
 	},
 	{
 		.data_type      = QMI_UNSIGNED_1_BYTE,
@@ -427,7 +551,7 @@
 		.is_array       = NO_ARRAY,
 		.tlv_type       = 0x18,
 		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
-					   cold_boot_cal_done_enable),
+					   fw_init_done_enable),
 	},
 	{
 		.data_type      = QMI_OPT_FLAG,
@@ -448,9 +572,45 @@
 					   rejuvenate_enable),
 	},
 	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x1A,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   xo_cal_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x1A,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   xo_cal_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x1B,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   cal_done_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x1B,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   cal_done_enable),
+	},
+	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -489,7 +649,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -497,7 +657,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -505,7 +665,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -573,7 +733,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -608,7 +768,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -626,7 +786,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -764,7 +924,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -782,7 +942,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -790,7 +950,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -920,7 +1080,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1054,7 +1214,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1073,7 +1233,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1117,7 +1277,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1135,7 +1295,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1153,7 +1313,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1269,7 +1429,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1288,7 +1448,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1316,7 +1476,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1342,7 +1502,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1459,7 +1619,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1485,7 +1645,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1522,7 +1682,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1530,7 +1690,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1548,7 +1708,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1574,7 +1734,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1592,7 +1752,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1627,7 +1787,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1676,7 +1836,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1724,7 +1884,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1743,7 +1903,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1760,7 +1920,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1778,7 +1938,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1804,7 +1964,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1822,7 +1982,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1834,16 +1994,16 @@
 		.is_array       = NO_ARRAY,
 		.tlv_type       = 0x10,
 		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
-					   daemon_support_valid),
+					   num_clients_valid),
 	},
 	{
-		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.data_type      = QMI_UNSIGNED_4_BYTE,
 		.elem_len       = 1,
-		.elem_size      = sizeof(u8),
+		.elem_size      = sizeof(u32),
 		.is_array       = NO_ARRAY,
 		.tlv_type       = 0x10,
 		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
-					   daemon_support),
+					   num_clients),
 	},
 	{
 		.data_type      = QMI_OPT_FLAG,
@@ -1864,9 +2024,216 @@
 					   wake_msi),
 	},
 	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   gpios_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   gpios_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = QMI_WLFW_MAX_NUM_GPIO_V01,
+		.elem_size      = sizeof(u32),
+		.is_array       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   gpios),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   nm_modem_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   nm_modem),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   bdf_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   bdf_support),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   bdf_cache_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   bdf_cache_support),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x16,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   m3_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x16,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   m3_support),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x17,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   m3_cache_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x17,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   m3_cache_support),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x18,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   cal_filesys_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x18,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   cal_filesys_support),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x19,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   cal_cache_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x19,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   cal_cache_support),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x1A,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   cal_done_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x1A,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   cal_done),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x1B,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   mem_bucket_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x1B,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   mem_bucket),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x1C,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   mem_cfg_mode_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x1C,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   mem_cfg_mode),
+	},
+	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1884,50 +2251,61 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
 struct elem_info wlfw_request_mem_ind_msg_v01_ei[] = {
 	{
-		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.data_type      = QMI_DATA_LEN,
 		.elem_len       = 1,
-		.elem_size      = sizeof(u32),
+		.elem_size      = sizeof(u8),
 		.is_array       = NO_ARRAY,
 		.tlv_type       = 0x01,
 		.offset         = offsetof(struct wlfw_request_mem_ind_msg_v01,
-					   size),
+					   mem_seg_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_MEM_SEG_V01,
+		.elem_size      = sizeof(struct wlfw_mem_seg_s_v01),
+		.is_array       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct wlfw_request_mem_ind_msg_v01,
+					   mem_seg),
+		.ei_array      = wlfw_mem_seg_s_v01_ei,
 	},
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
 struct elem_info wlfw_respond_mem_req_msg_v01_ei[] = {
 	{
-		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.data_type      = QMI_DATA_LEN,
 		.elem_len       = 1,
-		.elem_size      = sizeof(u64),
+		.elem_size      = sizeof(u8),
 		.is_array       = NO_ARRAY,
 		.tlv_type       = 0x01,
 		.offset         = offsetof(struct wlfw_respond_mem_req_msg_v01,
-					   addr),
+					   mem_seg_len),
 	},
 	{
-		.data_type      = QMI_UNSIGNED_4_BYTE,
-		.elem_len       = 1,
-		.elem_size      = sizeof(u32),
-		.is_array       = NO_ARRAY,
-		.tlv_type       = 0x02,
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_MEM_SEG_V01,
+		.elem_size      = sizeof(struct wlfw_mem_seg_resp_s_v01),
+		.is_array       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x01,
 		.offset         = offsetof(struct wlfw_respond_mem_req_msg_v01,
-					   size),
+					   mem_seg),
+		.ei_array      = wlfw_mem_seg_resp_s_v01_ei,
 	},
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1945,7 +2323,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -1953,15 +2331,15 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
-struct elem_info wlfw_cold_boot_cal_done_ind_msg_v01_ei[] = {
+struct elem_info wlfw_fw_init_done_ind_msg_v01_ei[] = {
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -2041,7 +2419,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -2049,7 +2427,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -2068,7 +2446,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -2096,7 +2474,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -2155,7 +2533,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -2181,7 +2559,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -2199,7 +2577,7 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
 
@@ -2216,6 +2594,14 @@
 	{
 		.data_type      = QMI_EOTI,
 		.is_array       = NO_ARRAY,
-		.is_array       = QMI_COMMON_TLV_TYPE,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_cal_done_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
 	},
 };
diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h
index 9b56eb0..00a873d 100644
--- a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h
+++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -23,10 +23,12 @@
 #define QMI_WLFW_BDF_DOWNLOAD_REQ_V01 0x0025
 #define QMI_WLFW_FW_MEM_READY_IND_V01 0x0037
 #define QMI_WLFW_INITIATE_CAL_UPDATE_IND_V01 0x002A
+#define QMI_WLFW_CAL_DONE_IND_V01 0x003E
 #define QMI_WLFW_HOST_CAP_REQ_V01 0x0034
 #define QMI_WLFW_DYNAMIC_FEATURE_MASK_RESP_V01 0x003B
 #define QMI_WLFW_M3_INFO_REQ_V01 0x003C
 #define QMI_WLFW_CAP_REQ_V01 0x0024
+#define QMI_WLFW_FW_INIT_DONE_IND_V01 0x0038
 #define QMI_WLFW_CAL_REPORT_REQ_V01 0x0026
 #define QMI_WLFW_M3_INFO_RESP_V01 0x003C
 #define QMI_WLFW_CAL_UPDATE_RESP_V01 0x0029
@@ -42,7 +44,6 @@
 #define QMI_WLFW_WLAN_MODE_REQ_V01 0x0022
 #define QMI_WLFW_IND_REGISTER_REQ_V01 0x0020
 #define QMI_WLFW_WLAN_CFG_RESP_V01 0x0023
-#define QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01 0x0038
 #define QMI_WLFW_REQUEST_MEM_IND_V01 0x0035
 #define QMI_WLFW_REJUVENATE_IND_V01 0x0039
 #define QMI_WLFW_DYNAMIC_FEATURE_MASK_REQ_V01 0x003B
@@ -72,13 +73,16 @@
 #define QMI_WLFW_IND_REGISTER_RESP_V01 0x0020
 
 #define QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01 2
+#define QMI_WLFW_MAX_NUM_MEM_SEG_V01 32
 #define QMI_WLFW_MAX_NUM_CAL_V01 5
 #define QMI_WLFW_MAX_DATA_SIZE_V01 6144
 #define QMI_WLFW_FUNCTION_NAME_LEN_V01 128
 #define QMI_WLFW_MAX_NUM_CE_V01 12
 #define QMI_WLFW_MAX_TIMESTAMP_LEN_V01 32
 #define QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01 6144
+#define QMI_WLFW_MAX_NUM_GPIO_V01 32
 #define QMI_WLFW_MAX_BUILD_ID_LEN_V01 128
+#define QMI_WLFW_MAX_NUM_MEM_CFG_V01 2
 #define QMI_WLFW_MAX_STR_LEN_V01 16
 #define QMI_WLFW_MAX_NUM_SHADOW_REG_V01 24
 #define QMI_WLFW_MAC_ADDR_SIZE_V01 6
@@ -117,6 +121,17 @@
 	WLFW_PIPEDIR_ENUM_MAX_VAL_V01 = INT_MAX,
 };
 
+enum wlfw_mem_type_enum_v01 {
+	WLFW_MEM_TYPE_ENUM_MIN_VAL_V01 = INT_MIN,
+	QMI_WLFW_MEM_TYPE_MSA_V01 = 0,
+	QMI_WLFW_MEM_TYPE_DDR_V01 = 1,
+	QMI_WLFW_MEM_BDF_V01 = 2,
+	QMI_WLFW_MEM_M3_V01 = 3,
+	QMI_WLFW_MEM_CAL_V01 = 4,
+	QMI_WLFW_MEM_DPD_V01 = 5,
+	WLFW_MEM_TYPE_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
 #define QMI_WLFW_CE_ATTR_FLAGS_V01 ((u32)0x00)
 #define QMI_WLFW_CE_ATTR_NO_SNOOP_V01 ((u32)0x01)
 #define QMI_WLFW_CE_ATTR_BYTE_SWAP_DATA_V01 ((u32)0x02)
@@ -128,6 +143,7 @@
 #define QMI_WLFW_FW_READY_V01 ((u64)0x02ULL)
 #define QMI_WLFW_MSA_READY_V01 ((u64)0x04ULL)
 #define QMI_WLFW_FW_MEM_READY_V01 ((u64)0x08ULL)
+#define QMI_WLFW_FW_INIT_DONE_V01 ((u64)0x10ULL)
 
 #define QMI_WLFW_FW_REJUVENATE_V01 ((u64)0x01ULL)
 
@@ -160,6 +176,26 @@
 	u8 secure_flag;
 };
 
+struct wlfw_mem_cfg_s_v01 {
+	u64 offset;
+	u32 size;
+	u8 secure_flag;
+};
+
+struct wlfw_mem_seg_s_v01 {
+	u32 size;
+	enum wlfw_mem_type_enum_v01 type;
+	u32 mem_cfg_len;
+	struct wlfw_mem_cfg_s_v01 mem_cfg[QMI_WLFW_MAX_NUM_MEM_CFG_V01];
+};
+
+struct wlfw_mem_seg_resp_s_v01 {
+	u64 addr;
+	u32 size;
+	enum wlfw_mem_type_enum_v01 type;
+	u8 restore;
+};
+
 struct wlfw_rf_chip_info_s_v01 {
 	u32 chip_id;
 	u32 chip_family;
@@ -195,13 +231,17 @@
 	u8 request_mem_enable;
 	u8 fw_mem_ready_enable_valid;
 	u8 fw_mem_ready_enable;
-	u8 cold_boot_cal_done_enable_valid;
-	u8 cold_boot_cal_done_enable;
+	u8 fw_init_done_enable_valid;
+	u8 fw_init_done_enable;
 	u8 rejuvenate_enable_valid;
 	u32 rejuvenate_enable;
+	u8 xo_cal_enable_valid;
+	u8 xo_cal_enable;
+	u8 cal_done_enable_valid;
+	u8 cal_done_enable;
 };
 
-#define WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 46
+#define WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 54
 extern struct elem_info wlfw_ind_register_req_msg_v01_ei[];
 
 struct wlfw_ind_register_resp_msg_v01 {
@@ -533,13 +573,36 @@
 extern struct elem_info wlfw_mac_addr_resp_msg_v01_ei[];
 
 struct wlfw_host_cap_req_msg_v01 {
-	u8 daemon_support_valid;
-	u8 daemon_support;
+	u8 num_clients_valid;
+	u32 num_clients;
 	u8 wake_msi_valid;
 	u32 wake_msi;
+	u8 gpios_valid;
+	u32 gpios_len;
+	u32 gpios[QMI_WLFW_MAX_NUM_GPIO_V01];
+	u8 nm_modem_valid;
+	u8 nm_modem;
+	u8 bdf_support_valid;
+	u8 bdf_support;
+	u8 bdf_cache_support_valid;
+	u8 bdf_cache_support;
+	u8 m3_support_valid;
+	u8 m3_support;
+	u8 m3_cache_support_valid;
+	u8 m3_cache_support;
+	u8 cal_filesys_support_valid;
+	u8 cal_filesys_support;
+	u8 cal_cache_support_valid;
+	u8 cal_cache_support;
+	u8 cal_done_valid;
+	u8 cal_done;
+	u8 mem_bucket_valid;
+	u32 mem_bucket;
+	u8 mem_cfg_mode_valid;
+	u8 mem_cfg_mode;
 };
 
-#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 11
+#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 189
 extern struct elem_info wlfw_host_cap_req_msg_v01_ei[];
 
 struct wlfw_host_cap_resp_msg_v01 {
@@ -550,18 +613,19 @@
 extern struct elem_info wlfw_host_cap_resp_msg_v01_ei[];
 
 struct wlfw_request_mem_ind_msg_v01 {
-	u32 size;
+	u32 mem_seg_len;
+	struct wlfw_mem_seg_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
 };
 
-#define WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN 7
+#define WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN 1124
 extern struct elem_info wlfw_request_mem_ind_msg_v01_ei[];
 
 struct wlfw_respond_mem_req_msg_v01 {
-	u64 addr;
-	u32 size;
+	u32 mem_seg_len;
+	struct wlfw_mem_seg_resp_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
 };
 
-#define WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN 18
+#define WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN 548
 extern struct elem_info wlfw_respond_mem_req_msg_v01_ei[];
 
 struct wlfw_respond_mem_resp_msg_v01 {
@@ -578,12 +642,12 @@
 #define WLFW_FW_MEM_READY_IND_MSG_V01_MAX_MSG_LEN 0
 extern struct elem_info wlfw_fw_mem_ready_ind_msg_v01_ei[];
 
-struct wlfw_cold_boot_cal_done_ind_msg_v01 {
+struct wlfw_fw_init_done_ind_msg_v01 {
 	char placeholder;
 };
 
-#define WLFW_COLD_BOOT_CAL_DONE_IND_MSG_V01_MAX_MSG_LEN 0
-extern struct elem_info wlfw_cold_boot_cal_done_ind_msg_v01_ei[];
+#define WLFW_FW_INIT_DONE_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_fw_init_done_ind_msg_v01_ei[];
 
 struct wlfw_rejuvenate_ind_msg_v01 {
 	u8 cause_for_rejuvenation_valid;
@@ -654,4 +718,11 @@
 #define WLFW_XO_CAL_IND_MSG_V01_MAX_MSG_LEN 4
 extern struct elem_info wlfw_xo_cal_ind_msg_v01_ei[];
 
+struct wlfw_cal_done_ind_msg_v01 {
+	char placeholder;
+};
+
+#define WLFW_CAL_DONE_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_cal_done_ind_msg_v01_ei[];
+
 #endif
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c b/drivers/net/wireless/intel/iwlwifi/iwl-7000.c
index d4b73de..b35adbc 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-7000.c
@@ -79,8 +79,8 @@
 /* Lowest firmware API version supported */
 #define IWL7260_UCODE_API_MIN	17
 #define IWL7265_UCODE_API_MIN	17
-#define IWL7265D_UCODE_API_MIN	17
-#define IWL3168_UCODE_API_MIN	20
+#define IWL7265D_UCODE_API_MIN	22
+#define IWL3168_UCODE_API_MIN	22
 
 /* NVM versions */
 #define IWL7260_NVM_VERSION		0x0a1d
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c
index 8d3e53f..20d08dd 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c
@@ -74,8 +74,8 @@
 #define IWL8265_UCODE_API_MAX	26
 
 /* Lowest firmware API version supported */
-#define IWL8000_UCODE_API_MIN	17
-#define IWL8265_UCODE_API_MIN	20
+#define IWL8000_UCODE_API_MIN	22
+#define IWL8265_UCODE_API_MIN	22
 
 /* NVM versions */
 #define IWL8000_NVM_VERSION		0x0a1d
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
index 406ef30..da8234b 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
@@ -369,6 +369,7 @@
 #define MON_DMARB_RD_DATA_ADDR		(0xa03c5c)
 
 #define DBGC_IN_SAMPLE			(0xa03c00)
+#define DBGC_OUT_CTRL			(0xa03c0c)
 
 /* enable the ID buf for read */
 #define WFPM_PS_CTL_CLR			0xA0300C
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
index 700d244..2642d8e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
@@ -914,14 +914,6 @@
 	return 0;
 }
 
-static inline void iwl_mvm_restart_early_start(struct iwl_mvm *mvm)
-{
-	if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000)
-		iwl_clear_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100);
-	else
-		iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 1);
-}
-
 int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 conf_id)
 {
 	u8 *ptr;
@@ -935,10 +927,8 @@
 	/* EARLY START - firmware's configuration is hard coded */
 	if ((!mvm->fw->dbg_conf_tlv[conf_id] ||
 	     !mvm->fw->dbg_conf_tlv[conf_id]->num_of_hcmds) &&
-	    conf_id == FW_DBG_START_FROM_ALIVE) {
-		iwl_mvm_restart_early_start(mvm);
+	    conf_id == FW_DBG_START_FROM_ALIVE)
 		return 0;
-	}
 
 	if (!mvm->fw->dbg_conf_tlv[conf_id])
 		return -EINVAL;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index c60703e..2b1c691 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -1666,8 +1666,11 @@
  */
 static inline u32 iwl_mvm_flushable_queues(struct iwl_mvm *mvm)
 {
+	u32 cmd_queue = iwl_mvm_is_dqa_supported(mvm) ? IWL_MVM_DQA_CMD_QUEUE :
+		IWL_MVM_CMD_QUEUE;
+
 	return ((BIT(mvm->cfg->base_params->num_of_queues) - 1) &
-		~BIT(IWL_MVM_CMD_QUEUE));
+		~BIT(cmd_queue));
 }
 
 static inline
@@ -1687,6 +1690,7 @@
 static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm)
 {
 	mvm->ucode_loaded = false;
+	mvm->fw_dbg_conf = FW_DBG_INVALID;
 	iwl_trans_stop_device(mvm->trans);
 }
 
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index 4d35deb..6d38eec 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -1118,22 +1118,38 @@
 
 	mutex_lock(&mvm->mutex);
 
-	/* stop recording */
 	if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+		/* stop recording */
 		iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100);
+
+		iwl_mvm_fw_error_dump(mvm);
+
+		/* start recording again if the firmware is not crashed */
+		if (!test_bit(STATUS_FW_ERROR, &mvm->trans->status) &&
+		    mvm->fw->dbg_dest_tlv)
+			iwl_clear_bits_prph(mvm->trans,
+					    MON_BUFF_SAMPLE_CTL, 0x100);
 	} else {
+		u32 in_sample = iwl_read_prph(mvm->trans, DBGC_IN_SAMPLE);
+		u32 out_ctrl = iwl_read_prph(mvm->trans, DBGC_OUT_CTRL);
+
+		/* stop recording */
 		iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0);
-		/* wait before we collect the data till the DBGC stop */
 		udelay(100);
+		iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, 0);
+		/* wait before we collect the data till the DBGC stop */
+		udelay(500);
+
+		iwl_mvm_fw_error_dump(mvm);
+
+		/* start recording again if the firmware is not crashed */
+		if (!test_bit(STATUS_FW_ERROR, &mvm->trans->status) &&
+		    mvm->fw->dbg_dest_tlv) {
+			iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, in_sample);
+			iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, out_ctrl);
+		}
 	}
 
-	iwl_mvm_fw_error_dump(mvm);
-
-	/* start recording again if the firmware is not crashed */
-	WARN_ON_ONCE((!test_bit(STATUS_FW_ERROR, &mvm->trans->status)) &&
-		     mvm->fw->dbg_dest_tlv &&
-		     iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf));
-
 	mutex_unlock(&mvm->mutex);
 
 	iwl_mvm_unref(mvm, IWL_MVM_REF_FW_DBG_COLLECT);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
index bec7d9c..c520356 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
@@ -790,11 +790,13 @@
 	struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata);
 	int ret;
 
-	if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR))
-		return -EIO;
-
 	mutex_lock(&mvm->mutex);
 
+	if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) {
+		ret = -EIO;
+		goto unlock;
+	}
+
 	if (new_state >= ARRAY_SIZE(iwl_mvm_cdev_budgets)) {
 		ret = -EINVAL;
 		goto unlock;
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index 10ef44e..fe32de2 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -2824,7 +2824,8 @@
 #ifdef CONFIG_PM_SLEEP
 static int iwl_trans_pcie_suspend(struct iwl_trans *trans)
 {
-	if (trans->runtime_pm_mode == IWL_PLAT_PM_MODE_D0I3)
+	if (trans->runtime_pm_mode == IWL_PLAT_PM_MODE_D0I3 &&
+	    (trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3))
 		return iwl_pci_fw_enter_d0i3(trans);
 
 	return 0;
@@ -2832,7 +2833,8 @@
 
 static void iwl_trans_pcie_resume(struct iwl_trans *trans)
 {
-	if (trans->runtime_pm_mode == IWL_PLAT_PM_MODE_D0I3)
+	if (trans->runtime_pm_mode == IWL_PLAT_PM_MODE_D0I3 &&
+	    (trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3))
 		iwl_pci_fw_exit_d0i3(trans);
 }
 #endif /* CONFIG_PM_SLEEP */
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
index 13da95a..987c7c4 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
@@ -142,15 +142,25 @@
 	if (!rt2x00dev->ops->hw->set_rts_threshold &&
 	    (tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS |
 						IEEE80211_TX_RC_USE_CTS_PROTECT))) {
-		if (rt2x00queue_available(queue) <= 1)
-			goto exit_fail;
+		if (rt2x00queue_available(queue) <= 1) {
+			/*
+			 * Recheck for full queue under lock to avoid race
+			 * conditions with rt2x00lib_txdone().
+			 */
+			spin_lock(&queue->tx_lock);
+			if (rt2x00queue_threshold(queue))
+				rt2x00queue_pause_queue(queue);
+			spin_unlock(&queue->tx_lock);
+
+			goto exit_free_skb;
+		}
 
 		if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb))
-			goto exit_fail;
+			goto exit_free_skb;
 	}
 
 	if (unlikely(rt2x00queue_write_tx_frame(queue, skb, control->sta, false)))
-		goto exit_fail;
+		goto exit_free_skb;
 
 	/*
 	 * Pausing queue has to be serialized with rt2x00lib_txdone(). Note
@@ -164,10 +174,6 @@
 
 	return;
 
- exit_fail:
-	spin_lock(&queue->tx_lock);
-	rt2x00queue_pause_queue(queue);
-	spin_unlock(&queue->tx_lock);
  exit_free_skb:
 	ieee80211_free_txskb(hw, skb);
 }
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 0881ba8..c78abfc 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -247,7 +247,10 @@
 	0x04, 0x08,		/* Noise gain, limit offset */
 	0x28, 0x28,		/* det rssi, med busy offsets */
 	7,			/* det sync thresh */
-	0, 2, 2			/* test mode, min, max */
+	0, 2, 2,		/* test mode, min, max */
+	0,			/* rx/tx delay */
+	0, 0, 0, 0, 0, 0,	/* current BSS id */
+	0			/* hop set */
 };
 
 /*===========================================================================*/
@@ -598,7 +601,7 @@
 	 *    a_beacon_period = hops    a_beacon_period = KuS
 	 *//* 64ms = 010000 */
 	if (local->fw_ver == 0x55) {
-		memcpy((UCHAR *) &local->sparm.b4, b4_default_startup_parms,
+		memcpy(&local->sparm.b4, b4_default_startup_parms,
 		       sizeof(struct b4_startup_params));
 		/* Translate sane kus input values to old build 4/5 format */
 		/* i = hop time in uS truncated to 3 bytes */
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
index 231f84d..6113624 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
@@ -1454,6 +1454,7 @@
 		goto err_free_dev;
 	}
 	mutex_init(&priv->io_mutex);
+	mutex_init(&priv->conf_mutex);
 
 	SET_IEEE80211_DEV(dev, &intf->dev);
 	usb_set_intfdata(intf, dev);
@@ -1627,7 +1628,6 @@
 		printk(KERN_ERR "rtl8187: Cannot register device\n");
 		goto err_free_dmabuf;
 	}
-	mutex_init(&priv->conf_mutex);
 	skb_queue_head_init(&priv->b_tx_status.queue);
 
 	wiphy_info(dev->wiphy, "hwaddr %pM, %s V%d + %s, rfkill mask %d\n",
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index 1c539c8..5e41bf0 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -1200,8 +1200,7 @@
 		WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
 
 		enable = bss_conf->arp_addr_cnt == 1 && bss_conf->assoc;
-		wl1251_acx_arp_ip_filter(wl, enable, addr);
-
+		ret = wl1251_acx_arp_ip_filter(wl, enable, addr);
 		if (ret < 0)
 			goto out_sleep;
 	}
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index b09c81e..1b28786 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -2038,7 +2038,10 @@
 	case XenbusStateInitialised:
 	case XenbusStateReconfiguring:
 	case XenbusStateReconfigured:
+		break;
+
 	case XenbusStateUnknown:
+		wake_up_all(&module_unload_q);
 		break;
 
 	case XenbusStateInitWait:
@@ -2169,7 +2172,9 @@
 		xenbus_switch_state(dev, XenbusStateClosing);
 		wait_event(module_unload_q,
 			   xenbus_read_driver_state(dev->otherend) ==
-			   XenbusStateClosing);
+			   XenbusStateClosing ||
+			   xenbus_read_driver_state(dev->otherend) ==
+			   XenbusStateUnknown);
 
 		xenbus_switch_state(dev, XenbusStateClosed);
 		wait_event(module_unload_q,
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index b8fb1ef..74257ac 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -1747,7 +1747,7 @@
 	}
 
 	if (i < nd_region->ndr_mappings) {
-		struct nvdimm_drvdata *ndd = to_ndd(&nd_region->mapping[i]);
+		struct nvdimm *nvdimm = nd_region->mapping[i].nvdimm;
 
 		/*
 		 * Give up if we don't find an instance of a uuid at each
@@ -1755,7 +1755,7 @@
 		 * find a dimm with two instances of the same uuid.
 		 */
 		dev_err(&nd_region->dev, "%s missing label for %pUb\n",
-				dev_name(ndd->dev), nd_label->uuid);
+				nvdimm_name(nvdimm), nd_label->uuid);
 		rc = -EINVAL;
 		goto err;
 	}
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index ad9d82e..c823e93 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2040,6 +2040,10 @@
 	struct nvme_ns *ns;
 
 	mutex_lock(&ctrl->namespaces_mutex);
+
+	/* Forcibly start all queues to avoid having stuck requests */
+	blk_mq_start_hw_queues(ctrl->admin_q);
+
 	list_for_each_entry(ns, &ctrl->namespaces, list) {
 		/*
 		 * Revalidating a dead namespace sets capacity to 0. This will
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index e48ecb9..8cc856e 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -1263,7 +1263,7 @@
 	bool nssro = dev->subsystem && (csts & NVME_CSTS_NSSRO);
 
 	/* If there is a reset ongoing, we shouldn't reset again. */
-	if (work_busy(&dev->reset_work))
+	if (dev->ctrl.state == NVME_CTRL_RESETTING)
 		return false;
 
 	/* We shouldn't reset unless the controller is on fatal error state
@@ -1755,7 +1755,7 @@
 	struct nvme_dev *dev = container_of(work, struct nvme_dev, reset_work);
 	int result = -ENODEV;
 
-	if (WARN_ON(dev->ctrl.state == NVME_CTRL_RESETTING))
+	if (WARN_ON(dev->ctrl.state != NVME_CTRL_RESETTING))
 		goto out;
 
 	/*
@@ -1765,9 +1765,6 @@
 	if (dev->ctrl.ctrl_config & NVME_CC_ENABLE)
 		nvme_dev_disable(dev, false);
 
-	if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_RESETTING))
-		goto out;
-
 	result = nvme_pci_enable(dev);
 	if (result)
 		goto out;
@@ -1841,8 +1838,8 @@
 {
 	if (!dev->ctrl.admin_q || blk_queue_dying(dev->ctrl.admin_q))
 		return -ENODEV;
-	if (work_busy(&dev->reset_work))
-		return -ENODEV;
+	if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_RESETTING))
+		return -EBUSY;
 	if (!queue_work(nvme_workq, &dev->reset_work))
 		return -EBUSY;
 	return 0;
@@ -1944,6 +1941,7 @@
 	if (result)
 		goto release_pools;
 
+	nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_RESETTING);
 	dev_info(dev->ctrl.device, "pci function %s\n", dev_name(&pdev->dev));
 
 	queue_work(nvme_workq, &dev->reset_work);
@@ -1987,6 +1985,7 @@
 
 	nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_DELETING);
 
+	cancel_work_sync(&dev->reset_work);
 	pci_set_drvdata(pdev, NULL);
 
 	if (!pci_device_is_present(pdev)) {
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 4aba42f..8d8e4c5 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -502,7 +502,7 @@
 }
 EXPORT_SYMBOL_GPL(of_platform_default_populate);
 
-#ifndef CONFIG_PPC
+#if !defined(CONFIG_PPC) && !defined(CONFIG_ARCH_MSM8953_BOOT_ORDERING)
 static int __init of_platform_default_populate_init(void)
 {
 	struct device_node *node;
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 78530d1..bdce067 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -2646,6 +2646,7 @@
 	netmos_9901,
 	netmos_9865,
 	quatech_sppxp100,
+	wch_ch382l,
 };
 
 
@@ -2708,6 +2709,7 @@
 	/* netmos_9901 */               { 1, { { 0, -1 }, } },
 	/* netmos_9865 */               { 1, { { 0, -1 }, } },
 	/* quatech_sppxp100 */		{ 1, { { 0, 1 }, } },
+	/* wch_ch382l */		{ 1, { { 2, -1 }, } },
 };
 
 static const struct pci_device_id parport_pc_pci_tbl[] = {
@@ -2797,6 +2799,8 @@
 	/* Quatech SPPXP-100 Parallel port PCI ExpressCard */
 	{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SPPXP_100,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 },
+	/* WCH CH382L PCI-E single parallel port card */
+	{ 0x1c00, 0x3050, 0x1c00, 0x3050, 0, 0, wch_ch382l },
 	{ 0, } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, parport_pc_pci_tbl);
diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c
index cec5a96..cc68136 100644
--- a/drivers/pci/host/pci-msm.c
+++ b/drivers/pci/host/pci-msm.c
@@ -6301,7 +6301,7 @@
 	return ret;
 }
 
-static void msm_pcie_fixup_suspend(struct pci_dev *dev)
+static void msm_pcie_fixup_suspend_late(struct pci_dev *dev)
 {
 	int ret;
 	struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(dev->bus);
@@ -6334,8 +6334,8 @@
 
 	mutex_unlock(&pcie_dev->recovery_lock);
 }
-DECLARE_PCI_FIXUP_SUSPEND(PCIE_VENDOR_ID_QCOM, PCI_ANY_ID,
-			  msm_pcie_fixup_suspend);
+DECLARE_PCI_FIXUP_SUSPEND_LATE(PCIE_VENDOR_ID_QCOM, PCI_ANY_ID,
+			  msm_pcie_fixup_suspend_late);
 
 /* Resume the PCIe link */
 static int msm_pcie_pm_resume(struct pci_dev *dev,
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index a46b585..d44b558 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -587,6 +587,7 @@
 {
 	unsigned long long sta = 0;
 	struct acpiphp_func *func;
+	u32 dvid;
 
 	list_for_each_entry(func, &slot->funcs, sibling) {
 		if (func->flags & FUNC_HAS_STA) {
@@ -597,19 +598,27 @@
 			if (ACPI_SUCCESS(status) && sta)
 				break;
 		} else {
-			u32 dvid;
-
-			pci_bus_read_config_dword(slot->bus,
-						  PCI_DEVFN(slot->device,
-							    func->function),
-						  PCI_VENDOR_ID, &dvid);
-			if (dvid != 0xffffffff) {
+			if (pci_bus_read_dev_vendor_id(slot->bus,
+					PCI_DEVFN(slot->device, func->function),
+					&dvid, 0)) {
 				sta = ACPI_STA_ALL;
 				break;
 			}
 		}
 	}
 
+	if (!sta) {
+		/*
+		 * Check for the slot itself since it may be that the
+		 * ACPI slot is a device below PCIe upstream port so in
+		 * that case it may not even be reachable yet.
+		 */
+		if (pci_bus_read_dev_vendor_id(slot->bus,
+				PCI_DEVFN(slot->device, 0), &dvid, 0)) {
+			sta = ACPI_STA_ALL;
+		}
+	}
+
 	return (unsigned int)sta;
 }
 
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index a98be6d..56340ab 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -231,7 +231,7 @@
 			res->flags |= IORESOURCE_ROM_ENABLE;
 		l64 = l & PCI_ROM_ADDRESS_MASK;
 		sz64 = sz & PCI_ROM_ADDRESS_MASK;
-		mask64 = (u32)PCI_ROM_ADDRESS_MASK;
+		mask64 = PCI_ROM_ADDRESS_MASK;
 	}
 
 	if (res->flags & IORESOURCE_MEM_64) {
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 4bc589e..85774b7 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -63,7 +63,7 @@
 		mask = (u32)PCI_BASE_ADDRESS_IO_MASK;
 		new |= res->flags & ~PCI_BASE_ADDRESS_IO_MASK;
 	} else if (resno == PCI_ROM_RESOURCE) {
-		mask = (u32)PCI_ROM_ADDRESS_MASK;
+		mask = PCI_ROM_ADDRESS_MASK;
 	} else {
 		mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
 		new |= res->flags & ~PCI_BASE_ADDRESS_MEM_MASK;
diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c
index 0a96502..fc5b18d 100644
--- a/drivers/pinctrl/intel/pinctrl-baytrail.c
+++ b/drivers/pinctrl/intel/pinctrl-baytrail.c
@@ -46,6 +46,9 @@
 #define BYT_TRIG_POS		BIT(25)
 #define BYT_TRIG_LVL		BIT(24)
 #define BYT_DEBOUNCE_EN		BIT(20)
+#define BYT_GLITCH_FILTER_EN	BIT(19)
+#define BYT_GLITCH_F_SLOW_CLK	BIT(17)
+#define BYT_GLITCH_F_FAST_CLK	BIT(16)
 #define BYT_PULL_STR_SHIFT	9
 #define BYT_PULL_STR_MASK	(3 << BYT_PULL_STR_SHIFT)
 #define BYT_PULL_STR_2K		(0 << BYT_PULL_STR_SHIFT)
@@ -1579,6 +1582,9 @@
 	 */
 	value &= ~(BYT_DIRECT_IRQ_EN | BYT_TRIG_POS | BYT_TRIG_NEG |
 		   BYT_TRIG_LVL);
+	/* Enable glitch filtering */
+	value |= BYT_GLITCH_FILTER_EN | BYT_GLITCH_F_SLOW_CLK |
+		 BYT_GLITCH_F_FAST_CLK;
 
 	writel(value, reg);
 
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
index 7511723..257c1c2 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
@@ -138,7 +138,6 @@
 	MESON_PIN(GPIOX_19, EE_OFF),
 	MESON_PIN(GPIOX_20, EE_OFF),
 	MESON_PIN(GPIOX_21, EE_OFF),
-	MESON_PIN(GPIOX_22, EE_OFF),
 
 	MESON_PIN(GPIOCLK_0, EE_OFF),
 	MESON_PIN(GPIOCLK_1, EE_OFF),
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index dc445a0..e729c56 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -1572,6 +1572,10 @@
 			 GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK) |
 		((props->use_db_eng << GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT) &
 			 GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK));
+	if (gsi_ctx->per.ver >= GSI_VER_2_0)
+		val |= ((props->prefetch_mode <<
+			GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_SHFT)
+			& GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_BMSK);
 	gsi_writel(val, gsi_ctx->base +
 			GSI_EE_n_GSI_CH_k_QOS_OFFS(props->ch_id, ee));
 }
diff --git a/drivers/platform/msm/gsi/gsi_reg.h b/drivers/platform/msm/gsi/gsi_reg.h
index 7817613..add3876 100644
--- a/drivers/platform/msm/gsi/gsi_reg.h
+++ b/drivers/platform/msm/gsi/gsi_reg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -1124,6 +1124,8 @@
 #define GSI_EE_n_GSI_CH_k_QOS_RMSK 0x303
 #define GSI_EE_n_GSI_CH_k_QOS_MAXk 30
 #define GSI_EE_n_GSI_CH_k_QOS_MAXn 3
+#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_BMSK 0x400
+#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_SHFT 0xa
 #define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK 0x200
 #define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT 0x9
 #define GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK 0x100
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
index ebf1d29..d9e3ab9 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
@@ -1847,12 +1847,15 @@
 	}
 
 	if (ipa_pm_is_used()) {
-		result = ipa_pm_set_perf_profile(
-			ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl,
-			params->max_supported_bandwidth_mbps);
-		if (result) {
-			IPA_USB_ERR("failed to set perf profile\n");
-			return result;
+		/* perf profile is not set on  USB DPL pipe */
+		if (ttype != IPA_USB_TRANSPORT_DPL) {
+			result = ipa_pm_set_perf_profile(
+				ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl,
+				params->max_supported_bandwidth_mbps);
+			if (result) {
+				IPA_USB_ERR("failed to set perf profile\n");
+				return result;
+			}
 		}
 
 		result = ipa_pm_activate_sync(
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
index f062ed2..953469a 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
@@ -432,6 +432,8 @@
 
 	list_for_each_entry(entry, &ipa_ctx->hdr_tbl.head_hdr_entry_list,
 			link) {
+		if (entry->cookie != IPA_HDR_COOKIE)
+			continue;
 		nbytes = scnprintf(
 			dbg_buff,
 			IPA_MAX_MSG_LEN,
@@ -606,6 +608,14 @@
 	if (attrib->protocol_eq_present)
 		pr_err("protocol:%d ", attrib->protocol_eq);
 
+	if (attrib->num_ihl_offset_range_16 >
+			IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS) {
+		IPAERR_RL("num_ihl_offset_range_16  Max %d passed value %d\n",
+			IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS,
+			attrib->num_ihl_offset_range_16);
+		return -EPERM;
+	}
+
 	for (i = 0; i < attrib->num_ihl_offset_range_16; i++) {
 		pr_err(
 			   "(ihl_ofst_range16: ofst:%u lo:%u hi:%u) ",
@@ -614,6 +624,12 @@
 			   attrib->ihl_offset_range_16[i].range_high);
 	}
 
+	if (attrib->num_offset_meq_32 > IPA_IPFLTR_NUM_MEQ_32_EQNS) {
+		IPAERR_RL("num_offset_meq_32  Max %d passed value %d\n",
+		IPA_IPFLTR_NUM_MEQ_32_EQNS, attrib->num_offset_meq_32);
+		return -EPERM;
+	}
+
 	for (i = 0; i < attrib->num_offset_meq_32; i++) {
 		pr_err(
 			   "(ofst_meq32: ofst:%u mask:0x%x val:0x%x) ",
@@ -635,6 +651,12 @@
 				attrib->ihl_offset_eq_16.value);
 	}
 
+	if (attrib->num_ihl_offset_meq_32 > IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS) {
+		IPAERR_RL("num_ihl_offset_meq_32  Max %d passed value %d\n",
+		IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS, attrib->num_ihl_offset_meq_32);
+		return -EPERM;
+	}
+
 	for (i = 0; i < attrib->num_ihl_offset_meq_32; i++) {
 		pr_err(
 				"(ihl_ofst_meq32: ofts:%d mask:0x%x val:0x%x) ",
@@ -643,6 +665,12 @@
 				attrib->ihl_offset_meq_32[i].value);
 	}
 
+	if (attrib->num_offset_meq_128 > IPA_IPFLTR_NUM_MEQ_128_EQNS) {
+		IPAERR_RL("num_offset_meq_128  Max %d passed value %d\n",
+		IPA_IPFLTR_NUM_MEQ_128_EQNS, attrib->num_offset_meq_128);
+		return -EPERM;
+	}
+
 	for (i = 0; i < attrib->num_offset_meq_128; i++) {
 		for (j = 0; j < 16; j++) {
 			addr[j] = attrib->offset_meq_128[i].value[j];
@@ -812,11 +840,14 @@
 	u32 rt_tbl_idx;
 	u32 bitmap;
 	bool eq;
+	int res = 0;
 
 	tbl = &ipa_ctx->glob_flt_tbl[ip];
 	mutex_lock(&ipa_ctx->lock);
 	i = 0;
 	list_for_each_entry(entry, &tbl->head_flt_rule_list, link) {
+		if (entry->cookie != IPA_FLT_COOKIE)
+			continue;
 		if (entry->rule.eq_attrib_type) {
 			rt_tbl_idx = entry->rule.rt_tbl_idx;
 			bitmap = entry->rule.eq_attrib.rule_eq_bitmap;
@@ -835,10 +866,14 @@
 			i, entry->rule.action, rt_tbl_idx);
 		pr_err("attrib_mask:%08x retain_hdr:%d eq:%d ",
 			bitmap, entry->rule.retain_hdr, eq);
-		if (eq)
-			ipa_attrib_dump_eq(
+		if (eq) {
+			res = ipa_attrib_dump_eq(
 				&entry->rule.eq_attrib);
-		else
+			if (res) {
+				IPAERR_RL("failed read attrib eq\n");
+				goto bail;
+			}
+		} else
 			ipa_attrib_dump(
 				&entry->rule.attrib, ip);
 		i++;
@@ -848,6 +883,8 @@
 		tbl = &ipa_ctx->flt_tbl[j][ip];
 		i = 0;
 		list_for_each_entry(entry, &tbl->head_flt_rule_list, link) {
+			if (entry->cookie != IPA_FLT_COOKIE)
+				continue;
 			if (entry->rule.eq_attrib_type) {
 				rt_tbl_idx = entry->rule.rt_tbl_idx;
 				bitmap = entry->rule.eq_attrib.rule_eq_bitmap;
@@ -867,18 +904,23 @@
 			pr_err("attrib_mask:%08x retain_hdr:%d ",
 				bitmap, entry->rule.retain_hdr);
 			pr_err("eq:%d ", eq);
-			if (eq)
-				ipa_attrib_dump_eq(
-					&entry->rule.eq_attrib);
-			else
+			if (eq) {
+				res = ipa_attrib_dump_eq(
+						&entry->rule.eq_attrib);
+				if (res) {
+					IPAERR_RL("failed read attrib eq\n");
+					goto bail;
+				}
+			} else
 				ipa_attrib_dump(
 					&entry->rule.attrib, ip);
 			i++;
 		}
 	}
+bail:
 	mutex_unlock(&ipa_ctx->lock);
 
-	return 0;
+	return res;
 }
 
 static ssize_t ipa_read_stats(struct file *file, char __user *ubuf,
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h
index 1f5d619..98f5574 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -281,7 +281,7 @@
 {
 }
 
-static int rmnet_ipa_reset_tethering_stats
+static inline int rmnet_ipa_reset_tethering_stats
 (
 	struct wan_ioctl_reset_tether_stats *data
 )
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index af926fb..c523b3d 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -3947,16 +3947,18 @@
 {
 	u32 clk_rate;
 
-	if (!ipa3_ctx->enable_clock_scaling)
+	IPADBG_LOW("idx = %d\n", idx);
+
+	if (!ipa3_ctx->enable_clock_scaling) {
+		ipa3_ctx->ipa3_active_clients.bus_vote_idx = idx;
 		return 0;
+	}
 
 	if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_NORMAL) {
 		IPAERR("not supported in this mode\n");
 		return 0;
 	}
 
-	IPADBG_LOW("idx = %d\n", idx);
-
 	if (idx <= 0 || idx >= ipa3_ctx->ctrl->msm_bus_data_ptr->num_usecases) {
 		IPAERR("bad voltage\n");
 		return -EINVAL;
@@ -4718,12 +4720,12 @@
 	ipa3_ctx->ipa_initialization_complete = true;
 	mutex_unlock(&ipa3_ctx->lock);
 
+	ipa3_debugfs_init();
+
 	ipa3_trigger_ipa_ready_cbs();
 	complete_all(&ipa3_ctx->init_completion_obj);
 	pr_info("IPA driver initialization was successful.\n");
 
-	ipa3_debugfs_init();
-
 	return 0;
 
 fail_teth_bridge_driver_init:
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index ee9c49c..dc5f5e0 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -372,6 +372,8 @@
 
 	list_for_each_entry(entry, &ipa3_ctx->hdr_tbl.head_hdr_entry_list,
 			link) {
+		if (entry->cookie != IPA_HDR_COOKIE)
+			continue;
 		nbytes = scnprintf(
 			dbg_buff,
 			IPA_MAX_MSG_LEN,
@@ -556,6 +558,12 @@
 	if (attrib->tc_eq_present)
 		pr_err("tc:%d ", attrib->tc_eq);
 
+	if (attrib->num_offset_meq_128 > IPA_IPFLTR_NUM_MEQ_128_EQNS) {
+		IPAERR_RL("num_offset_meq_128  Max %d passed value %d\n",
+		IPA_IPFLTR_NUM_MEQ_128_EQNS, attrib->num_offset_meq_128);
+		return -EPERM;
+	}
+
 	for (i = 0; i < attrib->num_offset_meq_128; i++) {
 		for (j = 0; j < 16; j++) {
 			addr[j] = attrib->offset_meq_128[i].value[j];
@@ -567,6 +575,12 @@
 			mask, addr);
 	}
 
+	if (attrib->num_offset_meq_32 > IPA_IPFLTR_NUM_MEQ_32_EQNS) {
+		IPAERR_RL("num_offset_meq_32  Max %d passed value %d\n",
+		IPA_IPFLTR_NUM_MEQ_32_EQNS, attrib->num_offset_meq_32);
+		return -EPERM;
+	}
+
 	for (i = 0; i < attrib->num_offset_meq_32; i++)
 		pr_err(
 			   "(ofst_meq32: ofst:%u mask:0x%x val:0x%x) ",
@@ -574,6 +588,12 @@
 			   attrib->offset_meq_32[i].mask,
 			   attrib->offset_meq_32[i].value);
 
+	if (attrib->num_ihl_offset_meq_32 > IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS) {
+		IPAERR_RL("num_ihl_offset_meq_32  Max %d passed value %d\n",
+		IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS, attrib->num_ihl_offset_meq_32);
+		return -EPERM;
+	}
+
 	for (i = 0; i < attrib->num_ihl_offset_meq_32; i++)
 		pr_err(
 			"(ihl_ofst_meq32: ofts:%d mask:0x%x val:0x%x) ",
@@ -588,6 +608,14 @@
 			attrib->metadata_meq32.mask,
 			attrib->metadata_meq32.value);
 
+	if (attrib->num_ihl_offset_range_16 >
+			IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS) {
+		IPAERR_RL("num_ihl_offset_range_16  Max %d passed value %d\n",
+			IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS,
+			attrib->num_ihl_offset_range_16);
+		return -EPERM;
+	}
+
 	for (i = 0; i < attrib->num_ihl_offset_range_16; i++)
 		pr_err(
 			   "(ihl_ofst_range16: ofst:%u lo:%u hi:%u) ",
@@ -780,7 +808,11 @@
 			pr_err("rule_id:%u prio:%u retain_hdr:%u ",
 				rules[rl].id, rules[rl].priority,
 				rules[rl].retain_hdr);
-			ipa3_attrib_dump_eq(&rules[rl].eq_attrib);
+			res = ipa3_attrib_dump_eq(&rules[rl].eq_attrib);
+			if (res) {
+				IPAERR_RL("failed read attrib eq\n");
+				goto bail;
+			}
 		}
 
 		pr_err("=== Routing Table %d = Non-Hashable Rules ===\n", tbl);
@@ -811,7 +843,11 @@
 			pr_err("rule_id:%u prio:%u retain_hdr:%u\n",
 				rules[rl].id, rules[rl].priority,
 				rules[rl].retain_hdr);
-			ipa3_attrib_dump_eq(&rules[rl].eq_attrib);
+			res = ipa3_attrib_dump_eq(&rules[rl].eq_attrib);
+			if (res) {
+				IPAERR_RL("failed read attrib eq\n");
+				goto bail;
+			}
 		}
 		pr_err("\n");
 	}
@@ -885,6 +921,7 @@
 	u32 rt_tbl_idx;
 	u32 bitmap;
 	bool eq;
+	int res = 0;
 
 	mutex_lock(&ipa3_ctx->lock);
 
@@ -894,6 +931,8 @@
 		tbl = &ipa3_ctx->flt_tbl[j][ip];
 		i = 0;
 		list_for_each_entry(entry, &tbl->head_flt_rule_list, link) {
+			if (entry->cookie != IPA_FLT_COOKIE)
+				continue;
 			if (entry->rule.eq_attrib_type) {
 				rt_tbl_idx = entry->rule.rt_tbl_idx;
 				bitmap = entry->rule.eq_attrib.rule_eq_bitmap;
@@ -919,18 +958,23 @@
 				pr_err("pdn index %d, set metadata %d ",
 					entry->rule.pdn_idx,
 					entry->rule.set_metadata);
-			if (eq)
-				ipa3_attrib_dump_eq(
-					&entry->rule.eq_attrib);
-			else
+			if (eq) {
+				res = ipa3_attrib_dump_eq(
+						&entry->rule.eq_attrib);
+				if (res) {
+					IPAERR_RL("failed read attrib eq\n");
+					goto bail;
+				}
+			} else
 				ipa3_attrib_dump(
 					&entry->rule.attrib, ip);
 			i++;
 		}
 	}
+bail:
 	mutex_unlock(&ipa3_ctx->lock);
 
-	return 0;
+	return res;
 }
 
 static ssize_t ipa3_read_flt_hw(struct file *file, char __user *ubuf,
@@ -985,7 +1029,11 @@
 				pr_err("pdn: %u, set_metadata: %u ",
 					rules[rl].rule.pdn_idx,
 					rules[rl].rule.set_metadata);
-			ipa3_attrib_dump_eq(&rules[rl].rule.eq_attrib);
+			res = ipa3_attrib_dump_eq(&rules[rl].rule.eq_attrib);
+			if (res) {
+				IPAERR_RL("failed read attrib eq\n");
+				goto bail;
+			}
 		}
 
 		pr_err("=== Filtering Table ep:%d = Non-Hashable Rules ===\n",
@@ -1013,7 +1061,11 @@
 				pr_err("pdn: %u, set_metadata: %u ",
 					rules[rl].rule.pdn_idx,
 					rules[rl].rule.set_metadata);
-			ipa3_attrib_dump_eq(&rules[rl].rule.eq_attrib);
+			res = ipa3_attrib_dump_eq(&rules[rl].rule.eq_attrib);
+			if (res) {
+				IPAERR_RL("failed read attrib eq\n");
+				goto bail;
+			}
 		}
 		pr_err("\n");
 	}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 9a0f44a..e73349a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -646,7 +646,6 @@
 	atomic_set(&comp->cnt, 2);
 
 	sys = ipa3_ctx->ep[ep_idx].sys;
-	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
 
 	if (num_desc == 1) {
 		if (descr->callback || descr->user1)
@@ -685,7 +684,6 @@
 		kfree(comp);
 
 bail:
-	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
 	return result;
 }
 
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
index 29fd547..6742773 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
@@ -61,8 +61,10 @@
 	gen_params.rule = (const struct ipa_flt_rule *)&entry->rule;
 
 	res = ipahal_flt_generate_hw_rule(&gen_params, &entry->hw_len, buf);
-	if (res)
+	if (res) {
 		IPAERR_RL("failed to generate flt h/w rule\n");
+		return res;
+	}
 
 	return 0;
 }
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
index 0772dde..9bc6d39 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
@@ -16,7 +16,7 @@
 #include <linux/msm_ipa.h>
 
 /* internal to ipa */
-#define IPA_PM_MAX_CLIENTS 12 /* actual max is value -1 since we start from 1*/
+#define IPA_PM_MAX_CLIENTS 14 /* actual max is value -1 since we start from 1*/
 #define IPA_PM_MAX_EX_CL 64
 #define IPA_PM_THRESHOLD_MAX 5
 #define IPA_PM_EXCEPTION_MAX 2
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c
index f5ef141..e746229 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -818,6 +818,11 @@
 {
 	u32 opcode;
 
+	if (ipa3_ctx->ipa_hw_type > IPA_HW_v4_0) {
+		IPADBG_LOW("not supported past IPA v4.0\n");
+		return 0;
+	}
+
 	/*
 	 * If the uC interface has not been initialized yet,
 	 * don't notify the uC on the enable/disable
diff --git a/drivers/platform/msm/ipa/test/ipa_pm_ut.c b/drivers/platform/msm/ipa/test/ipa_pm_ut.c
index e07040a..83b705d 100644
--- a/drivers/platform/msm/ipa/test/ipa_pm_ut.c
+++ b/drivers/platform/msm/ipa/test/ipa_pm_ut.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -23,18 +23,32 @@
 
 static int ipa_pm_ut_setup(void **ppriv)
 {
+	int i;
 
 	IPA_UT_DBG("Start Setup\n");
 
 	/* decrement UT vote */
 	IPA_ACTIVE_CLIENTS_DEC_SPECIAL("IPA_UT");
 
+	/*decouple PM from RPM */
+	ipa3_ctx->enable_clock_scaling = false;
+
+	if (ipa3_ctx->use_ipa_pm) {
+		for (i = 0; i < IPA_PM_MAX_CLIENTS; i++) {
+			ipa_pm_deactivate_sync(i);
+			ipa_pm_deregister(i);
+		}
+
+		ipa_pm_destroy();
+	}
+
 	return 0;
 }
 
 static int ipa_pm_ut_teardown(void *priv)
 {
 	IPA_UT_DBG("Start Teardown\n");
+	IPA_UT_ERR("WARNING: IPA_PM HAS BEEN DESTROYED, REBOOT TO RE_INIT\n");
 
 	/* undo UT vote */
 	IPA_ACTIVE_CLIENTS_INC_SPECIAL("IPA_UT");
@@ -106,7 +120,7 @@
 	struct callback_param user_data;
 
 	struct ipa_pm_init_params init_params = {
-		.threshold_size = IPA_PM_THRESHOLD_MAX,
+		.threshold_size = 2,
 		.default_threshold = {600, 1000}
 	};
 
@@ -223,7 +237,7 @@
 	struct callback_param user_data;
 
 	struct ipa_pm_init_params init_params = {
-		.threshold_size = IPA_PM_THRESHOLD_MAX,
+		.threshold_size = 2,
 		.default_threshold = {600, 1000}
 	};
 
@@ -327,7 +341,7 @@
 	struct callback_param user_data;
 
 	struct ipa_pm_init_params init_params = {
-		.threshold_size = IPA_PM_THRESHOLD_MAX,
+		.threshold_size = 2,
 		.default_threshold = {600, 1000}
 	};
 
@@ -436,7 +450,7 @@
 
 
 	struct ipa_pm_init_params init_params = {
-		.threshold_size = IPA_PM_THRESHOLD_MAX,
+		.threshold_size = 2,
 		.default_threshold = {600, 1000}
 	};
 
@@ -648,7 +662,7 @@
 	struct callback_param user_data;
 
 	struct ipa_pm_init_params init_params = {
-		.threshold_size = IPA_PM_THRESHOLD_MAX,
+		.threshold_size = 2,
 		.default_threshold = {600, 1000}
 	};
 
@@ -797,7 +811,7 @@
 	struct callback_param user_data;
 
 	struct ipa_pm_init_params init_params = {
-		.threshold_size = IPA_PM_THRESHOLD_MAX,
+		.threshold_size = 2,
 		.default_threshold = {600, 1000}
 	};
 
@@ -885,7 +899,7 @@
 	unsigned long flags;
 
 	struct ipa_pm_init_params init_params = {
-		.threshold_size = IPA_PM_THRESHOLD_MAX,
+		.threshold_size = 2,
 		.default_threshold = {600, 1000}
 	};
 
@@ -957,7 +971,7 @@
 	int i, hdl_USB, hdl_WLAN, vote;
 
 	struct ipa_pm_init_params init_params = {
-		.threshold_size = IPA_PM_THRESHOLD_MAX,
+		.threshold_size = 2,
 		.default_threshold = {600, 1000}
 	};
 
@@ -1095,7 +1109,7 @@
 	int hdl_USB, hdl_WLAN, vote, idx;
 
 	struct ipa_pm_init_params init_params = {
-		.threshold_size = IPA_PM_THRESHOLD_MAX,
+		.threshold_size = 2,
 		.default_threshold = {600, 1000}
 	};
 
@@ -1210,7 +1224,7 @@
 	int hdl_USB, hdl_WLAN, hdl_MODEM, vote, idx;
 
 	struct ipa_pm_init_params init_params = {
-		.threshold_size = IPA_PM_THRESHOLD_MAX,
+		.threshold_size = 2,
 		.default_threshold = {600, 1000}
 	};
 
@@ -1377,7 +1391,7 @@
 	int hdl_USB, hdl_WLAN, hdl_MODEM, vote, idx;
 
 	struct ipa_pm_init_params init_params = {
-		.threshold_size = IPA_PM_THRESHOLD_MAX,
+		.threshold_size = 2,
 		.default_threshold = {600, 1000}
 	};
 
@@ -1542,7 +1556,7 @@
 	};
 
 	struct ipa_pm_init_params init_params = {
-		.threshold_size = IPA_PM_THRESHOLD_MAX,
+		.threshold_size = 2,
 		.default_threshold = {600, 1000},
 		.exception_size = 1,
 		.exceptions[0] = exceptions,
diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c
index 1c16e5a..fb513ec 100644
--- a/drivers/platform/msm/mhi_dev/mhi.c
+++ b/drivers/platform/msm/mhi_dev/mhi.c
@@ -1418,16 +1418,20 @@
 	union mhi_dev_ring_element_type *el;
 	int rc = 0;
 	struct mhi_req *req = (struct mhi_req *)mreq;
-	struct mhi_req *local_req = NULL;
 	union mhi_dev_ring_element_type *compl_ev = NULL;
 	struct mhi_dev *mhi = NULL;
 	unsigned long flags;
+	size_t transfer_len;
+	u32 snd_cmpl;
+	uint32_t rd_offset;
 
 	client = req->client;
 	ch = client->channel;
 	mhi = ch->ring->mhi_dev;
 	el = req->el;
-	local_req = req;
+	transfer_len = req->len;
+	snd_cmpl = req->snd_cmpl;
+	rd_offset = req->rd_offset;
 	ch->curr_ereq->context = ch;
 
 	dma_unmap_single(&mhi_ctx->pdev->dev, req->dma,
@@ -1441,14 +1445,13 @@
 		compl_ev->evt_tr_comp.chid = ch->ch_id;
 		compl_ev->evt_tr_comp.type =
 				MHI_DEV_RING_EL_TRANSFER_COMPLETION_EVENT;
-		compl_ev->evt_tr_comp.len = el->tre.len;
+		compl_ev->evt_tr_comp.len = transfer_len;
 		compl_ev->evt_tr_comp.code = MHI_CMD_COMPL_CODE_EOT;
 		compl_ev->evt_tr_comp.ptr = ch->ring->ring_ctx->generic.rbase +
-				local_req->rd_offset * TR_RING_ELEMENT_SZ;
+						rd_offset * TR_RING_ELEMENT_SZ;
 		ch->curr_ereq->num_events++;
 
-		if (ch->curr_ereq->num_events >= MAX_TR_EVENTS ||
-				local_req->snd_cmpl){
+		if (ch->curr_ereq->num_events >= MAX_TR_EVENTS || snd_cmpl) {
 			mhi_log(MHI_MSG_VERBOSE,
 					"num of tr events %d for ch %d\n",
 					ch->curr_ereq->num_events, ch->ch_id);
diff --git a/drivers/platform/msm/qcom-geni-se.c b/drivers/platform/msm/qcom-geni-se.c
index 6ce2161..ed4b837 100644
--- a/drivers/platform/msm/qcom-geni-se.c
+++ b/drivers/platform/msm/qcom-geni-se.c
@@ -317,7 +317,9 @@
 
 static int geni_se_select_dma_mode(void __iomem *base)
 {
+	int proto = get_se_proto(base);
 	unsigned int geni_dma_mode = 0;
+	unsigned int common_geni_m_irq_en;
 
 	geni_write_reg(0, base, SE_GSI_EVENT_EN);
 	geni_write_reg(0xFFFFFFFF, base, SE_GENI_M_IRQ_CLEAR);
@@ -326,6 +328,12 @@
 	geni_write_reg(0xFFFFFFFF, base, SE_DMA_RX_IRQ_CLR);
 	geni_write_reg(0xFFFFFFFF, base, SE_IRQ_EN);
 
+	common_geni_m_irq_en = geni_read_reg(base, SE_GENI_M_IRQ_EN);
+	if (proto != UART)
+		common_geni_m_irq_en &=
+			~(M_TX_FIFO_WATERMARK_EN | M_RX_FIFO_WATERMARK_EN);
+
+	geni_write_reg(common_geni_m_irq_en, base, SE_GENI_M_IRQ_EN);
 	geni_dma_mode = geni_read_reg(base, SE_GENI_DMA_MODE_EN);
 	geni_dma_mode |= GENI_DMA_MODE_EN;
 	geni_write_reg(geni_dma_mode, base, SE_GENI_DMA_MODE_EN);
diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile
index da20d93..ffc1ce3 100644
--- a/drivers/power/supply/qcom/Makefile
+++ b/drivers/power/supply/qcom/Makefile
@@ -7,7 +7,7 @@
 obj-$(CONFIG_SMB1351_USB_CHARGER) += smb1351-charger.o pmic-voter.o battery.o
 obj-$(CONFIG_QPNP_SMB2)		+= step-chg-jeita.o battery.o qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o
 obj-$(CONFIG_SMB138X_CHARGER)	+= step-chg-jeita.o smb138x-charger.o smb-lib.o pmic-voter.o storm-watch.o battery.o
-obj-$(CONFIG_QPNP_QG)		+= qpnp-qg.o pmic-voter.o qg-util.o qg-soc.o qg-sdam.o qg-battery-profile.o qg-profile-lib.o
+obj-$(CONFIG_QPNP_QG)		+= qpnp-qg.o pmic-voter.o qg-util.o qg-soc.o qg-sdam.o qg-battery-profile.o qg-profile-lib.o fg-alg.o
 obj-$(CONFIG_QPNP_QNOVO)	+= qpnp-qnovo.o battery.o
 obj-$(CONFIG_QPNP_TYPEC)	+= qpnp-typec.o
 obj-$(CONFIG_QPNP_SMB5)		+= step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o schgm-flash.o
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index 275b982..e8d91ae 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -78,6 +78,7 @@
 	struct class		qcom_batt_class;
 	struct wakeup_source	*pl_ws;
 	struct notifier_block	nb;
+	bool			pl_disable;
 };
 
 struct pl_data *the_chip;
@@ -88,6 +89,7 @@
 
 enum {
 	AICL_RERUN_WA_BIT	= BIT(0),
+	FORCE_INOV_DISABLE_BIT	= BIT(1),
 };
 
 static int debug_mask;
@@ -848,6 +850,12 @@
 		chip->pl_settled_ua = 0;
 	}
 
+	/* notify parallel state change */
+	if (chip->pl_psy && (chip->pl_disable != pl_disable)) {
+		power_supply_changed(chip->pl_psy);
+		chip->pl_disable = (bool)pl_disable;
+	}
+
 	pl_dbg(chip, PR_PARALLEL, "parallel charging %s\n",
 		   pl_disable ? "disabled" : "enabled");
 
@@ -916,7 +924,8 @@
 	chip->pl_mode = pval.intval;
 
 	/* Disable autonomous votage increments for USBIN-USBIN */
-	if (IS_USBIN(chip->pl_mode)) {
+	if (IS_USBIN(chip->pl_mode)
+			&& (chip->wa_flags & FORCE_INOV_DISABLE_BIT)) {
 		if (!chip->hvdcp_hw_inov_dis_votable)
 			chip->hvdcp_hw_inov_dis_votable =
 					find_votable("HVDCP_HW_INOV_DIS");
@@ -1041,7 +1050,6 @@
 	else
 		vote(chip->pl_enable_votable_indirect, USBIN_I_VOTER, true, 0);
 
-	rerun_election(chip->fcc_votable);
 
 	if (IS_USBIN(chip->pl_mode)) {
 		/*
@@ -1200,7 +1208,9 @@
 	switch (smb_version) {
 	case PMI8998_SUBTYPE:
 	case PM660_SUBTYPE:
-		chip->wa_flags = AICL_RERUN_WA_BIT;
+		chip->wa_flags = AICL_RERUN_WA_BIT | FORCE_INOV_DISABLE_BIT;
+		break;
+	case PMI632_SUBTYPE:
 		break;
 	default:
 		break;
@@ -1301,6 +1311,7 @@
 		goto unreg_notifier;
 	}
 
+	chip->pl_disable = true;
 	chip->qcom_batt_class.name = "qcom-battery",
 	chip->qcom_batt_class.owner = THIS_MODULE,
 	chip->qcom_batt_class.class_attrs = pl_attributes;
diff --git a/drivers/power/supply/qcom/fg-alg.c b/drivers/power/supply/qcom/fg-alg.c
index 3d74f7e..9b9a880 100644
--- a/drivers/power/supply/qcom/fg-alg.c
+++ b/drivers/power/supply/qcom/fg-alg.c
@@ -164,13 +164,13 @@
 }
 
 /**
- * get_cycle_count -
+ * get_bucket_cycle_count -
  * @counter: Cycle counter object
  *
  * Returns the cycle counter for a SOC bucket.
  *
  */
-int get_cycle_count(struct cycle_counter *counter)
+static int get_bucket_cycle_count(struct cycle_counter *counter)
 {
 	int count;
 
@@ -187,6 +187,68 @@
 }
 
 /**
+ * get_cycle_counts -
+ * @counter: Cycle counter object
+ * @buf: Bucket cycle counts formatted in a string returned to the caller
+ *
+ * Get cycle count for all buckets in a string format
+ */
+int get_cycle_counts(struct cycle_counter *counter, const char **buf)
+{
+	int i, rc, len = 0;
+
+	for (i = 1; i <= BUCKET_COUNT; i++) {
+		counter->id = i;
+		rc = get_bucket_cycle_count(counter);
+		if (rc < 0) {
+			pr_err("Couldn't get cycle count rc=%d\n", rc);
+			return rc;
+		}
+
+		if (sizeof(counter->str_buf) - len < 8) {
+			pr_err("Invalid length %d\n", len);
+			return -EINVAL;
+		}
+
+		len += snprintf(counter->str_buf+len, 8, "%d ", rc);
+	}
+
+	counter->str_buf[len] = '\0';
+	*buf = counter->str_buf;
+	return 0;
+}
+
+/**
+ * get_cycle_count -
+ * @counter: Cycle counter object
+ * @count: Average cycle count returned to the caller
+ *
+ * Get average cycle count for all buckets
+ */
+int get_cycle_count(struct cycle_counter *counter, int *count)
+{
+	int i, rc, temp = 0;
+
+	for (i = 1; i <= BUCKET_COUNT; i++) {
+		counter->id = i;
+		rc = get_bucket_cycle_count(counter);
+		if (rc < 0) {
+			pr_err("Couldn't get cycle count rc=%d\n", rc);
+			return rc;
+		}
+
+		temp += rc;
+	}
+
+	/*
+	 * Normalize the counter across each bucket so that we can get
+	 * the overall charge cycle count.
+	 */
+	*count = temp / BUCKET_COUNT;
+	return 0;
+}
+
+/**
  * cycle_count_init -
  * @counter: Cycle counter object
  *
@@ -327,13 +389,15 @@
  */
 static int cap_learning_begin(struct cap_learning *cl, u32 batt_soc)
 {
-	int rc, cc_soc_sw, batt_soc_msb;
+	int rc, cc_soc_sw, batt_soc_msb, batt_soc_pct;
 
 	batt_soc_msb = batt_soc >> 24;
-	if (DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW) >
-		cl->dt.start_soc) {
-		pr_debug("Battery SOC %d is high!, not starting\n",
-			batt_soc_msb);
+	batt_soc_pct = DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW);
+
+	if (batt_soc_pct > cl->dt.max_start_soc ||
+			batt_soc_pct < cl->dt.min_start_soc) {
+		pr_debug("Battery SOC %d is high/low, not starting\n",
+			batt_soc_pct);
 		return -EINVAL;
 	}
 
diff --git a/drivers/power/supply/qcom/fg-alg.h b/drivers/power/supply/qcom/fg-alg.h
index ff5bece..7c25007 100644
--- a/drivers/power/supply/qcom/fg-alg.h
+++ b/drivers/power/supply/qcom/fg-alg.h
@@ -21,6 +21,7 @@
 	bool		started[BUCKET_COUNT];
 	u16		count[BUCKET_COUNT];
 	u8		last_soc[BUCKET_COUNT];
+	char		str_buf[BUCKET_COUNT * 8];
 	int		id;
 	int		last_bucket;
 	struct mutex	lock;
@@ -29,7 +30,8 @@
 };
 
 struct cl_params {
-	int	start_soc;
+	int	min_start_soc;
+	int	max_start_soc;
 	int	max_temp;
 	int	min_temp;
 	int	max_cap_inc;
@@ -60,7 +62,8 @@
 void clear_cycle_count(struct cycle_counter *counter);
 void cycle_count_update(struct cycle_counter *counter, int batt_soc,
 		int charge_status, bool charge_done, bool input_present);
-int get_cycle_count(struct cycle_counter *counter);
+int get_cycle_count(struct cycle_counter *counter, int *count);
+int get_cycle_counts(struct cycle_counter *counter, const char **buf);
 int cycle_count_init(struct cycle_counter *counter);
 void cap_learning_abort(struct cap_learning *cl);
 void cap_learning_update(struct cap_learning *cl, int batt_temp,
diff --git a/drivers/power/supply/qcom/qg-battery-profile.c b/drivers/power/supply/qcom/qg-battery-profile.c
index 441c759..36edd76 100644
--- a/drivers/power/supply/qcom/qg-battery-profile.c
+++ b/drivers/power/supply/qcom/qg-battery-profile.c
@@ -22,6 +22,7 @@
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 #include <uapi/linux/qg-profile.h>
+#include "qg-battery-profile.h"
 #include "qg-profile-lib.h"
 #include "qg-defs.h"
 
@@ -410,6 +411,26 @@
 	return 0;
 }
 
+int qg_get_nominal_capacity(u32 *nom_cap_uah, int batt_temp, bool charging)
+{
+	u8 table_index = charging ? TABLE_FCC1 : TABLE_FCC2;
+	u32 fcc_mah;
+
+	if (!the_battery || !the_battery->profile) {
+		pr_err("Battery profile not loaded\n");
+		return -ENODEV;
+	}
+
+	fcc_mah = interpolate_single_row_lut(
+				&the_battery->profile[table_index],
+					batt_temp, DEGC_SCALE);
+	fcc_mah = CAP(QG_MIN_FCC_MAH, QG_MAX_FCC_MAH, fcc_mah);
+
+	*nom_cap_uah = fcc_mah * 1000;
+
+	return 0;
+}
+
 int qg_batterydata_init(struct device_node *profile_node)
 {
 	int rc = 0;
diff --git a/drivers/power/supply/qcom/qg-battery-profile.h b/drivers/power/supply/qcom/qg-battery-profile.h
index 143a4f2..1b06277 100644
--- a/drivers/power/supply/qcom/qg-battery-profile.h
+++ b/drivers/power/supply/qcom/qg-battery-profile.h
@@ -15,5 +15,6 @@
 int qg_batterydata_init(struct device_node *node);
 void qg_batterydata_exit(void);
 int lookup_soc_ocv(u32 *soc, u32 ocv_uv, int batt_temp, bool charging);
+int qg_get_nominal_capacity(u32 *nom_cap_uah, int batt_temp, bool charging);
 
 #endif /* __QG_BATTERY_PROFILE_H__ */
diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h
index 6e44f33..a1aeac2 100644
--- a/drivers/power/supply/qcom/qg-core.h
+++ b/drivers/power/supply/qcom/qg-core.h
@@ -12,6 +12,9 @@
 #ifndef __QG_CORE_H__
 #define __QG_CORE_H__
 
+#include <linux/kernel.h>
+#include "fg-alg.h"
+
 struct qg_batt_props {
 	const char		*batt_type_str;
 	int			float_volt_uv;
@@ -49,6 +52,8 @@
 	int			cold_temp_threshold;
 	bool			hold_soc_while_full;
 	bool			linearize_soc;
+	bool			cl_disable;
+	bool			cl_feedback_on;
 };
 
 struct qpnp_qg {
@@ -109,12 +114,18 @@
 	int			maint_soc;
 	int			msoc;
 	int			pon_soc;
+	int			batt_soc;
+	int			cc_soc;
 	struct alarm		alarm_timer;
 	u32			sdam_data[SDAM_MAX];
 
 	/* DT */
 	struct qg_dt		dt;
 	struct qg_batt_props	bp;
+	/* capacity learning */
+	struct cap_learning	*cl;
+	/* charge counter */
+	struct cycle_counter	*counter;
 };
 
 enum ocv_type {
@@ -135,6 +146,7 @@
 	QG_DEBUG_PM		= BIT(7),
 	QG_DEBUG_BUS_READ	= BIT(8),
 	QG_DEBUG_BUS_WRITE	= BIT(9),
+	QG_DEBUG_ALG_CL		= BIT(10),
 };
 
 enum qg_irq {
diff --git a/drivers/power/supply/qcom/qg-defs.h b/drivers/power/supply/qcom/qg-defs.h
index 6ae9aa2..2061208 100644
--- a/drivers/power/supply/qcom/qg-defs.h
+++ b/drivers/power/supply/qcom/qg-defs.h
@@ -47,4 +47,7 @@
 #define CAP(min, max, value)			\
 		((min > value) ? min : ((value > max) ? max : value))
 
+#define QG_SOC_FULL	10000
+#define BATT_SOC_32BIT	GENMASK(31, 0)
+
 #endif /* __QG_DEFS_H__ */
diff --git a/drivers/power/supply/qcom/qg-reg.h b/drivers/power/supply/qcom/qg-reg.h
index 96533d4..66f9be1 100644
--- a/drivers/power/supply/qcom/qg-reg.h
+++ b/drivers/power/supply/qcom/qg-reg.h
@@ -87,6 +87,8 @@
 #define QG_SDAM_OCV_OFFSET			0x4C
 #define QG_SDAM_IBAT_OFFSET			0x50
 #define QG_SDAM_TIME_OFFSET			0x54
+#define QG_SDAM_CYCLE_COUNT_OFFSET		0x58
+#define QG_SDAM_LEARNED_CAPACITY_OFFSET		0x68
 #define QG_SDAM_PON_OCV_OFFSET			0x7C
 
 #endif
diff --git a/drivers/power/supply/qcom/qg-sdam.c b/drivers/power/supply/qcom/qg-sdam.c
index 54eed16..7bc4afa 100644
--- a/drivers/power/supply/qcom/qg-sdam.c
+++ b/drivers/power/supply/qcom/qg-sdam.c
@@ -130,6 +130,53 @@
 	return rc;
 }
 
+int qg_sdam_multibyte_write(u32 offset, u8 *data, u32 length)
+{
+	int rc, i;
+	struct qg_sdam *chip = the_chip;
+
+	if (!chip) {
+		pr_err("Invalid sdam-chip pointer\n");
+		return -EINVAL;
+	}
+
+	offset = chip->sdam_base + offset;
+	rc = regmap_bulk_write(chip->regmap, offset, data, (size_t)length);
+	if (rc < 0) {
+		pr_err("Failed to write offset=%0x4x value=%d\n",
+					offset, *data);
+	} else {
+		for (i = 0; i < length; i++)
+			pr_debug("QG SDAM write offset=%0x4x value=%d\n",
+					offset++, data[i]);
+	}
+
+	return rc;
+}
+
+int qg_sdam_multibyte_read(u32 offset, u8 *data, u32 length)
+{
+	int rc, i;
+	struct qg_sdam *chip = the_chip;
+
+	if (!chip) {
+		pr_err("Invalid sdam-chip pointer\n");
+		return -EINVAL;
+	}
+
+	offset = chip->sdam_base + offset;
+	rc = regmap_raw_read(chip->regmap, offset, (u8 *)data, (size_t)length);
+	if (rc < 0) {
+		pr_err("Failed to read offset=%0x4x\n", offset);
+	} else {
+		for (i = 0; i < length; i++)
+			pr_debug("QG SDAM read offset=%0x4x value=%d\n",
+					offset++, data[i]);
+	}
+
+	return rc;
+}
+
 int qg_sdam_read_all(u32 *sdam_data)
 {
 	int i, rc;
diff --git a/drivers/power/supply/qcom/qg-sdam.h b/drivers/power/supply/qcom/qg-sdam.h
index 51af04c..10e684f 100644
--- a/drivers/power/supply/qcom/qg-sdam.h
+++ b/drivers/power/supply/qcom/qg-sdam.h
@@ -37,5 +37,7 @@
 int qg_sdam_read(u8 param, u32 *data);
 int qg_sdam_write_all(u32 *sdam_data);
 int qg_sdam_read_all(u32 *sdam_data);
+int qg_sdam_multibyte_write(u32 offset, u8 *sdam_data, u32 length);
+int qg_sdam_multibyte_read(u32 offset, u8 *sdam_data, u32 length);
 
 #endif
diff --git a/drivers/power/supply/qcom/qg-soc.c b/drivers/power/supply/qcom/qg-soc.c
index c4d5043..af8b158 100644
--- a/drivers/power/supply/qcom/qg-soc.c
+++ b/drivers/power/supply/qcom/qg-soc.c
@@ -13,9 +13,11 @@
 #define pr_fmt(fmt)	"QG-K: %s: " fmt, __func__
 
 #include <linux/alarmtimer.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/power_supply.h>
 #include <uapi/linux/qg.h>
+#include "fg-alg.h"
 #include "qg-sdam.h"
 #include "qg-core.h"
 #include "qg-reg.h"
@@ -98,11 +100,12 @@
 
 static void update_msoc(struct qpnp_qg *chip)
 {
-	int rc;
+	int rc = 0, batt_temp = 0,  batt_soc_32bit = 0;
+	bool usb_present = is_usb_present(chip);
 
 	if (chip->catch_up_soc > chip->msoc) {
 		/* SOC increased */
-		if (is_usb_present(chip)) /* Increment if USB is present */
+		if (usb_present) /* Increment if USB is present */
 			chip->msoc += chip->dt.delta_soc;
 	} else if (chip->catch_up_soc < chip->msoc) {
 		/* SOC dropped */
@@ -130,6 +133,25 @@
 	if (rc < 0)
 		pr_err("Failed to update SDAM with MSOC rc=%d\n", rc);
 
+	if (!chip->dt.cl_disable && chip->cl->active) {
+		rc = qg_get_battery_temp(chip, &batt_temp);
+		if (rc < 0) {
+			pr_err("Failed to read BATT_TEMP rc=%d\n", rc);
+		} else {
+			batt_soc_32bit = div64_u64(
+						chip->batt_soc * BATT_SOC_32BIT,
+						QG_SOC_FULL);
+			cap_learning_update(chip->cl, batt_temp, batt_soc_32bit,
+					chip->charge_status, chip->charge_done,
+					usb_present, false);
+		}
+	}
+
+	cycle_count_update(chip->counter,
+			DIV_ROUND_CLOSEST(chip->msoc * 255, 100),
+			chip->charge_status, chip->charge_done,
+			usb_present);
+
 	qg_dbg(chip, QG_DEBUG_SOC,
 		"SOC scale: Update maint_soc=%d msoc=%d catch_up_soc=%d delta_soc=%d\n",
 				chip->maint_soc, chip->msoc,
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 7ba0ce5..eaf138c 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -2080,12 +2080,21 @@
 
 static int fg_adjust_recharge_soc(struct fg_chip *chip)
 {
+	union power_supply_propval prop = {0, };
 	int rc, msoc, recharge_soc, new_recharge_soc = 0;
 	bool recharge_soc_status;
 
 	if (!chip->dt.auto_recharge_soc)
 		return 0;
 
+	rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH,
+		&prop);
+	if (rc < 0) {
+		pr_err("Error in getting battery health, rc=%d\n", rc);
+		return rc;
+	}
+	chip->health = prop.intval;
+
 	recharge_soc = chip->dt.recharge_soc_thr;
 	recharge_soc_status = chip->recharge_soc_adjusted;
 	/*
@@ -2116,6 +2125,9 @@
 			if (!chip->recharge_soc_adjusted)
 				return 0;
 
+			if (chip->health != POWER_SUPPLY_HEALTH_GOOD)
+				return 0;
+
 			/* Restore the default value */
 			new_recharge_soc = recharge_soc;
 			chip->recharge_soc_adjusted = false;
diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c
index f7a6b7a..5a0682c 100644
--- a/drivers/power/supply/qcom/qpnp-qg.c
+++ b/drivers/power/supply/qcom/qpnp-qg.c
@@ -16,6 +16,7 @@
 #include <linux/cdev.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
+#include <linux/kernel.h>
 #include <linux/ktime.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -28,6 +29,7 @@
 #include <linux/pmic-voter.h>
 #include <linux/qpnp/qpnp-adc.h>
 #include <uapi/linux/qg.h>
+#include "fg-alg.h"
 #include "qg-sdam.h"
 #include "qg-core.h"
 #include "qg-reg.h"
@@ -259,8 +261,13 @@
 	int rc = 0, i, j = 0, temp;
 	u8 v_fifo[MAX_FIFO_LENGTH * 2], i_fifo[MAX_FIFO_LENGTH * 2];
 	u32 sample_interval = 0, sample_count = 0, fifo_v = 0, fifo_i = 0;
+	unsigned long rtc_sec = 0;
 
-	chip->kdata.fifo_time = (u32)ktime_get_seconds();
+	rc = get_rtc_time(&rtc_sec);
+	if (rc < 0)
+		pr_err("Failed to get RTC time, rc=%d\n", rc);
+
+	chip->kdata.fifo_time = (u32)rtc_sec;
 
 	if (!fifo_length) {
 		pr_debug("No FIFO data\n");
@@ -641,6 +648,12 @@
 			struct qpnp_qg, udata_work);
 	int rc;
 
+	if (chip->udata.param[QG_CC_SOC].valid)
+		chip->cc_soc = chip->udata.param[QG_CC_SOC].data;
+
+	if (chip->udata.param[QG_BATT_SOC].valid)
+		chip->batt_soc = chip->udata.param[QG_BATT_SOC].data;
+
 	if (chip->udata.param[QG_SOC].valid) {
 		qg_dbg(chip, QG_DEBUG_SOC, "udata SOC=%d last SOC=%d\n",
 			chip->udata.param[QG_SOC].data, chip->catch_up_soc);
@@ -946,6 +959,127 @@
 	return 0;
 }
 
+/* ALG callback functions below */
+
+static int qg_get_learned_capacity(void *data, int64_t *learned_cap_uah)
+{
+	struct qpnp_qg *chip = data;
+	int16_t cc_mah;
+	int rc;
+
+	if (!chip)
+		return -ENODEV;
+
+	if (chip->battery_missing || !chip->profile_loaded)
+		return -EPERM;
+
+	rc = qg_sdam_multibyte_read(QG_SDAM_LEARNED_CAPACITY_OFFSET,
+					(u8 *)&cc_mah, 2);
+	if (rc < 0) {
+		pr_err("Error in reading learned_capacity, rc=%d\n", rc);
+		return rc;
+	}
+	*learned_cap_uah = cc_mah * 1000;
+
+	qg_dbg(chip, QG_DEBUG_ALG_CL, "Retrieved learned capacity %llduah\n",
+					*learned_cap_uah);
+	return 0;
+}
+
+static int qg_store_learned_capacity(void *data, int64_t learned_cap_uah)
+{
+	struct qpnp_qg *chip = data;
+	int16_t cc_mah;
+	int rc;
+
+	if (!chip)
+		return -ENODEV;
+
+	if (chip->battery_missing || !learned_cap_uah)
+		return -EPERM;
+
+	cc_mah = div64_s64(learned_cap_uah, 1000);
+	rc = qg_sdam_multibyte_write(QG_SDAM_LEARNED_CAPACITY_OFFSET,
+					 (u8 *)&cc_mah, 2);
+	if (rc < 0) {
+		pr_err("Error in writing learned_capacity, rc=%d\n", rc);
+		return rc;
+	}
+
+	qg_dbg(chip, QG_DEBUG_ALG_CL, "Stored learned capacity %llduah\n",
+					learned_cap_uah);
+	return 0;
+}
+
+static int qg_get_cc_soc(void *data, int *cc_soc)
+{
+	struct qpnp_qg *chip = data;
+
+	if (!chip)
+		return -ENODEV;
+
+	if (chip->cc_soc == INT_MIN)
+		return -EINVAL;
+
+	*cc_soc = chip->cc_soc;
+
+	return 0;
+}
+
+static int qg_restore_cycle_count(void *data, u16 *buf, int length)
+{
+	struct qpnp_qg *chip = data;
+	int id, rc = 0;
+	u8 tmp[2];
+
+	if (!chip)
+		return -ENODEV;
+
+	if (chip->battery_missing || !chip->profile_loaded)
+		return -EPERM;
+
+	if (!buf || length > BUCKET_COUNT)
+		return -EINVAL;
+
+	for (id = 0; id < length; id++) {
+		rc = qg_sdam_multibyte_read(
+				QG_SDAM_CYCLE_COUNT_OFFSET + (id * 2),
+				(u8 *)tmp, 2);
+		if (rc < 0) {
+			pr_err("failed to read bucket %d rc=%d\n", id, rc);
+			return rc;
+		}
+		*buf++ = tmp[0] | tmp[1] << 8;
+	}
+
+	return rc;
+}
+
+static int qg_store_cycle_count(void *data, u16 *buf, int id, int length)
+{
+	struct qpnp_qg *chip = data;
+	int rc = 0;
+
+	if (!chip)
+		return -ENODEV;
+
+	if (chip->battery_missing || !chip->profile_loaded)
+		return -EPERM;
+
+	if (!buf || length > BUCKET_COUNT * 2 || id < 0 ||
+		id > BUCKET_COUNT - 1 ||
+		(((id * 2) + length) > BUCKET_COUNT * 2))
+		return -EINVAL;
+
+	rc = qg_sdam_multibyte_write(
+			QG_SDAM_CYCLE_COUNT_OFFSET + (id * 2),
+			(u8 *)buf, length);
+	if (rc < 0)
+		pr_err("failed to write bucket %d rc=%d\n", id, rc);
+
+	return rc;
+}
+
 #define DEFAULT_BATT_TYPE	"Unknown Battery"
 #define MISSING_BATT_TYPE	"Missing Battery"
 #define DEBUG_BATT_TYPE		"Debug Board"
@@ -968,17 +1102,36 @@
 static int qg_get_battery_current(struct qpnp_qg *chip, int *ibat_ua)
 {
 	int rc = 0, last_ibat = 0;
+	u32 fifo_length = 0;
 
 	if (chip->battery_missing) {
 		*ibat_ua = 0;
 		return 0;
 	}
 
-	rc = qg_read(chip, chip->qg_base + QG_LAST_ADC_I_DATA0_REG,
-				(u8 *)&last_ibat, 2);
-	if (rc < 0) {
-		pr_err("Failed to read LAST_ADV_I reg, rc=%d\n", rc);
-		return rc;
+	if (chip->parallel_enabled) {
+		/* read the last real-time FIFO */
+		rc = get_fifo_length(chip, &fifo_length, true);
+		if (rc < 0) {
+			pr_err("Failed to read RT FIFO length, rc=%d\n", rc);
+			return rc;
+		}
+		fifo_length = (fifo_length == 0) ? 0 : fifo_length - 1;
+		fifo_length *= 2;
+		rc = qg_read(chip, chip->qg_base + QG_I_FIFO0_DATA0_REG +
+					fifo_length, (u8 *)&last_ibat, 2);
+		if (rc < 0) {
+			pr_err("Failed to read FIFO_I_%d reg, rc=%d\n",
+					fifo_length / 2, rc);
+			return rc;
+		}
+	} else {
+		rc = qg_read(chip, chip->qg_base + QG_LAST_ADC_I_DATA0_REG,
+					(u8 *)&last_ibat, 2);
+		if (rc < 0) {
+			pr_err("Failed to read LAST_ADV_I reg, rc=%d\n", rc);
+			return rc;
+		}
 	}
 
 	last_ibat = sign_extend32(last_ibat, 15);
@@ -1046,6 +1199,32 @@
 			       enum power_supply_property psp,
 			       const union power_supply_propval *pval)
 {
+	struct qpnp_qg *chip = power_supply_get_drvdata(psy);
+	int rc = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CHARGE_FULL:
+		if (chip->dt.cl_disable) {
+			pr_warn("Capacity learning disabled!\n");
+			return 0;
+		}
+		if (chip->cl->active) {
+			pr_warn("Capacity learning active!\n");
+			return 0;
+		}
+		if (pval->intval <= 0 || pval->intval > chip->cl->nom_cap_uah) {
+			pr_err("charge_full is out of bounds\n");
+			return -EINVAL;
+		}
+		mutex_lock(&chip->cl->lock);
+		rc = qg_store_learned_capacity(chip, pval->intval);
+		if (!rc)
+			chip->cl->learned_cap_uah = pval->intval;
+		mutex_unlock(&chip->cl->lock);
+		break;
+	default:
+		break;
+	}
 	return 0;
 }
 
@@ -1055,6 +1234,7 @@
 {
 	struct qpnp_qg *chip = power_supply_get_drvdata(psy);
 	int rc = 0;
+	int64_t temp = 0;
 
 	pval->intval = 0;
 
@@ -1106,6 +1286,27 @@
 	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
 		pval->intval = chip->charge_counter_uah;
 		break;
+	case POWER_SUPPLY_PROP_CHARGE_FULL:
+		if (!chip->dt.cl_disable && chip->dt.cl_feedback_on)
+			rc = qg_get_learned_capacity(chip, &temp);
+		else
+			rc = qg_get_nominal_capacity((int *)&temp, 250, true);
+		if (!rc)
+			pval->intval = (int)temp;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+		rc = qg_get_nominal_capacity((int *)&temp, 250, true);
+		if (!rc)
+			pval->intval = (int)temp;
+		break;
+	case POWER_SUPPLY_PROP_CYCLE_COUNTS:
+		rc = get_cycle_counts(chip->counter, &pval->strval);
+		if (rc < 0)
+			pval->strval = NULL;
+		break;
+	case POWER_SUPPLY_PROP_CYCLE_COUNT:
+		rc = get_cycle_count(chip->counter, &pval->intval);
+		break;
 	default:
 		pr_debug("Unsupported property %d\n", psp);
 		break;
@@ -1117,6 +1318,12 @@
 static int qg_property_is_writeable(struct power_supply *psy,
 				enum power_supply_property psp)
 {
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CHARGE_FULL:
+		return 1;
+	default:
+		break;
+	}
 	return 0;
 }
 
@@ -1136,6 +1343,10 @@
 	POWER_SUPPLY_PROP_VOLTAGE_MAX,
 	POWER_SUPPLY_PROP_BATT_FULL_CURRENT,
 	POWER_SUPPLY_PROP_BATT_PROFILE_VERSION,
+	POWER_SUPPLY_PROP_CYCLE_COUNT,
+	POWER_SUPPLY_PROP_CYCLE_COUNTS,
+	POWER_SUPPLY_PROP_CHARGE_FULL,
+	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
 };
 
 static const struct power_supply_desc qg_psy_desc = {
@@ -1262,7 +1473,7 @@
 	struct qpnp_qg *chip = container_of(work,
 			struct qpnp_qg, qg_status_change_work);
 	union power_supply_propval prop = {0, };
-	int rc = 0;
+	int rc = 0, batt_temp = 0, batt_soc_32b = 0;
 
 	if (!is_batt_available(chip)) {
 		pr_debug("batt-psy not available\n");
@@ -1294,6 +1505,24 @@
 	if (rc < 0)
 		pr_err("Failed to update usb status, rc=%d\n", rc);
 
+	cycle_count_update(chip->counter,
+			DIV_ROUND_CLOSEST(chip->msoc * 255, 100),
+			chip->charge_status, chip->charge_done,
+			chip->usb_present);
+
+	if (!chip->dt.cl_disable) {
+		rc = qg_get_battery_temp(chip, &batt_temp);
+		if (rc < 0) {
+			pr_err("Failed to read BATT_TEMP at PON rc=%d\n", rc);
+		} else {
+			batt_soc_32b = div64_u64(
+					chip->batt_soc * BATT_SOC_32BIT,
+					QG_SOC_FULL);
+			cap_learning_update(chip->cl, batt_temp, batt_soc_32b,
+				chip->charge_status, chip->charge_done,
+				chip->usb_present, false);
+		}
+	}
 	rc = qg_charge_full_update(chip);
 	if (rc < 0)
 		pr_err("Failed in charge_full_update, rc=%d\n", rc);
@@ -2069,6 +2298,64 @@
 	return 0;
 }
 
+static int qg_alg_init(struct qpnp_qg *chip)
+{
+	struct cycle_counter *counter;
+	struct cap_learning *cl;
+	struct device_node *node = chip->dev->of_node;
+	int rc;
+
+	counter = devm_kzalloc(chip->dev, sizeof(*counter), GFP_KERNEL);
+	if (!counter)
+		return -ENOMEM;
+
+	counter->restore_count = qg_restore_cycle_count;
+	counter->store_count = qg_store_cycle_count;
+	counter->data = chip;
+
+	rc = cycle_count_init(counter);
+	if (rc < 0) {
+		dev_err(chip->dev, "Error in initializing cycle counter, rc:%d\n",
+			rc);
+		counter->data = NULL;
+		devm_kfree(chip->dev, counter);
+		return rc;
+	}
+
+	chip->counter = counter;
+
+	chip->dt.cl_disable = of_property_read_bool(node,
+					"qcom,cl-disable");
+
+	/*Return if capacity learning is disabled*/
+	if (chip->dt.cl_disable)
+		return 0;
+
+	cl = devm_kzalloc(chip->dev, sizeof(*cl), GFP_KERNEL);
+	if (!cl)
+		return -ENOMEM;
+
+	cl->cc_soc_max = QG_SOC_FULL;
+	cl->get_cc_soc = qg_get_cc_soc;
+	cl->get_learned_capacity = qg_get_learned_capacity;
+	cl->store_learned_capacity = qg_store_learned_capacity;
+	cl->data = chip;
+
+	rc = cap_learning_init(cl);
+	if (rc < 0) {
+		dev_err(chip->dev, "Error in initializing capacity learning, rc:%d\n",
+			rc);
+		counter->data = NULL;
+		cl->data = NULL;
+		devm_kfree(chip->dev, counter);
+		devm_kfree(chip->dev, cl);
+		return rc;
+	}
+
+	chip->cl = cl;
+	return 0;
+}
+
 #define DEFAULT_VBATT_EMPTY_MV		3200
 #define DEFAULT_VBATT_EMPTY_COLD_MV	3000
 #define DEFAULT_VBATT_CUTOFF_MV		3400
@@ -2082,6 +2369,14 @@
 #define DEFAULT_DELTA_SOC		1
 #define DEFAULT_SHUTDOWN_SOC_SECS	360
 #define DEFAULT_COLD_TEMP_THRESHOLD	0
+#define DEFAULT_CL_MIN_START_SOC	10
+#define DEFAULT_CL_MAX_START_SOC	15
+#define DEFAULT_CL_MIN_TEMP_DECIDEGC	150
+#define DEFAULT_CL_MAX_TEMP_DECIDEGC	500
+#define DEFAULT_CL_MAX_INC_DECIPERC	5
+#define DEFAULT_CL_MAX_DEC_DECIPERC	100
+#define DEFAULT_CL_MIN_LIM_DECIPERC	0
+#define DEFAULT_CL_MAX_LIM_DECIPERC	0
 static int qg_parse_dt(struct qpnp_qg *chip)
 {
 	int rc = 0;
@@ -2275,6 +2570,65 @@
 	else
 		chip->dt.rbat_conn_mohm = temp;
 
+	/* Capacity learning params*/
+	if (!chip->dt.cl_disable) {
+		chip->dt.cl_feedback_on = of_property_read_bool(node,
+						"qcom,cl-feedback-on");
+
+		rc = of_property_read_u32(node, "qcom,cl-min-start-soc", &temp);
+		if (rc < 0)
+			chip->cl->dt.min_start_soc = DEFAULT_CL_MIN_START_SOC;
+		else
+			chip->cl->dt.min_start_soc = temp;
+
+		rc = of_property_read_u32(node, "qcom,cl-max-start-soc", &temp);
+		if (rc < 0)
+			chip->cl->dt.max_start_soc = DEFAULT_CL_MAX_START_SOC;
+		else
+			chip->cl->dt.max_start_soc = temp;
+
+		rc = of_property_read_u32(node, "qcom,cl-min-temp", &temp);
+		if (rc < 0)
+			chip->cl->dt.min_temp = DEFAULT_CL_MIN_TEMP_DECIDEGC;
+		else
+			chip->cl->dt.min_temp = temp;
+
+		rc = of_property_read_u32(node, "qcom,cl-max-temp", &temp);
+		if (rc < 0)
+			chip->cl->dt.max_temp = DEFAULT_CL_MAX_TEMP_DECIDEGC;
+		else
+			chip->cl->dt.max_temp = temp;
+
+		rc = of_property_read_u32(node, "qcom,cl-max-increment", &temp);
+		if (rc < 0)
+			chip->cl->dt.max_cap_inc = DEFAULT_CL_MAX_INC_DECIPERC;
+		else
+			chip->cl->dt.max_cap_inc = temp;
+
+		rc = of_property_read_u32(node, "qcom,cl-max-decrement", &temp);
+		if (rc < 0)
+			chip->cl->dt.max_cap_dec = DEFAULT_CL_MAX_DEC_DECIPERC;
+		else
+			chip->cl->dt.max_cap_dec = temp;
+
+		rc = of_property_read_u32(node, "qcom,cl-min-limit", &temp);
+		if (rc < 0)
+			chip->cl->dt.min_cap_limit =
+						DEFAULT_CL_MIN_LIM_DECIPERC;
+		else
+			chip->cl->dt.min_cap_limit = temp;
+
+		rc = of_property_read_u32(node, "qcom,cl-max-limit", &temp);
+		if (rc < 0)
+			chip->cl->dt.max_cap_limit =
+						DEFAULT_CL_MAX_LIM_DECIPERC;
+		else
+			chip->cl->dt.max_cap_limit = temp;
+
+		qg_dbg(chip, QG_DEBUG_PON, "DT: cl_min_start_soc=%d cl_max_start_soc=%d cl_min_temp=%d cl_max_temp=%d\n",
+			chip->cl->dt.min_start_soc, chip->cl->dt.max_start_soc,
+			chip->cl->dt.min_temp, chip->cl->dt.max_temp);
+	}
 	qg_dbg(chip, QG_DEBUG_PON, "DT: vbatt_empty_mv=%dmV vbatt_low_mv=%dmV delta_soc=%d\n",
 			chip->dt.vbatt_empty_mv, chip->dt.vbatt_low_mv,
 			chip->dt.delta_soc);
@@ -2392,7 +2746,9 @@
 		chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv;
 		chip->kdata.param[QG_GOOD_OCV_UV].valid = true;
 		 /* Clear suspend data as there has been a GOOD OCV */
+		memset(&chip->kdata, 0, sizeof(chip->kdata));
 		chip->suspend_data = false;
+
 		qg_dbg(chip, QG_DEBUG_PM, "GOOD OCV @ resume good_ocv=%d uV\n",
 				ocv_uv);
 	}
@@ -2464,7 +2820,7 @@
 
 static int qpnp_qg_probe(struct platform_device *pdev)
 {
-	int rc = 0, soc = 0;
+	int rc = 0, soc = 0, nom_cap_uah;
 	struct qpnp_qg *chip;
 
 	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
@@ -2497,6 +2853,14 @@
 	mutex_init(&chip->data_lock);
 	init_waitqueue_head(&chip->qg_wait_q);
 	chip->maint_soc = -EINVAL;
+	chip->batt_soc = INT_MIN;
+	chip->cc_soc = INT_MIN;
+
+	rc = qg_alg_init(chip);
+	if (rc < 0) {
+		pr_err("Error in alg_init, rc:%d\n", rc);
+		return rc;
+	}
 
 	rc = qg_parse_dt(chip);
 	if (rc < 0) {
@@ -2534,6 +2898,30 @@
 		return rc;
 	}
 
+	if (chip->profile_loaded) {
+		if (!chip->dt.cl_disable) {
+			/*
+			 * Use FCC @ 25 C and charge-profile for
+			 * Nominal Capacity
+			 */
+			rc = qg_get_nominal_capacity(&nom_cap_uah, 250, true);
+			if (!rc) {
+				rc = cap_learning_post_profile_init(chip->cl,
+						nom_cap_uah);
+				if (rc < 0) {
+					pr_err("Error in cap_learning_post_profile_init rc=%d\n",
+						rc);
+					return rc;
+				}
+			}
+		}
+		rc = restore_cycle_count(chip->counter);
+		if (rc < 0) {
+			pr_err("Error in restoring cycle_count, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
 	rc = qg_determine_pon_soc(chip);
 	if (rc < 0) {
 		pr_err("Failed to determine initial state, rc=%d\n", rc);
@@ -2627,6 +3015,22 @@
 	return 0;
 }
 
+static void qpnp_qg_shutdown(struct platform_device *pdev)
+{
+	struct qpnp_qg *chip = platform_get_drvdata(pdev);
+
+	if (!is_usb_present(chip) || !chip->profile_loaded)
+		return;
+	/*
+	 * Charging status doesn't matter when the device shuts down and we
+	 * have to treat this as charge done. Hence pass charge_done as true.
+	 */
+	cycle_count_update(chip->counter,
+			DIV_ROUND_CLOSEST(chip->msoc * 255, 100),
+			POWER_SUPPLY_STATUS_NOT_CHARGING,
+			true, chip->usb_present);
+}
+
 static const struct of_device_id match_table[] = {
 	{ .compatible = "qcom,qpnp-qg", },
 	{ },
@@ -2641,6 +3045,7 @@
 	},
 	.probe		= qpnp_qg_probe,
 	.remove		= qpnp_qg_remove,
+	.shutdown	= qpnp_qg_shutdown,
 };
 module_platform_driver(qpnp_qg_driver);
 
diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c
index d3aaf26..8c00d9c 100644
--- a/drivers/power/supply/qcom/qpnp-smb5.c
+++ b/drivers/power/supply/qcom/qpnp-smb5.c
@@ -52,6 +52,13 @@
 		.max_u  = 3000000,
 		.step_u = 50000,
 	},
+	.icl_max_stat		= {
+		.name   = "dcdc icl max status",
+		.reg    = ICL_MAX_STATUS_REG,
+		.min_u  = 0,
+		.max_u  = 3000000,
+		.step_u = 50000,
+	},
 	.icl_stat		= {
 		.name   = "input current limit status",
 		.reg    = AICL_ICL_STATUS_REG,
@@ -90,7 +97,7 @@
 	},
 };
 
-static struct smb_params smb5_pmi855_params = {
+static struct smb_params smb5_pm855b_params = {
 	.fcc			= {
 		.name   = "fast charge current",
 		.reg    = CHGR_FAST_CHARGE_CURRENT_CFG_REG,
@@ -112,8 +119,15 @@
 		.max_u  = 5000000,
 		.step_u = 50000,
 	},
+	.icl_max_stat		= {
+		.name   = "dcdc icl max status",
+		.reg    = ICL_MAX_STATUS_REG,
+		.min_u  = 0,
+		.max_u  = 5000000,
+		.step_u = 50000,
+	},
 	.icl_stat		= {
-		.name   = "input current limit status",
+		.name   = "aicl icl status",
 		.reg    = AICL_ICL_STATUS_REG,
 		.min_u  = 0,
 		.max_u  = 5000000,
@@ -177,6 +191,11 @@
 	debug_mask, __debug_mask, int, 0600
 );
 
+static int __pd_disabled;
+module_param_named(
+	pd_disabled, __pd_disabled, int, 0600
+);
+
 static int __weak_chg_icl_ua = 500000;
 module_param_named(
 	weak_chg_icl_ua, __weak_chg_icl_ua, int, 0600
@@ -216,7 +235,7 @@
 	switch (pmic_rev_id->pmic_subtype) {
 	case PM855B_SUBTYPE:
 		chip->chg.smb_version = PM855B_SUBTYPE;
-		chg->param = smb5_pmi855_params;
+		chg->param = smb5_pm855b_params;
 		chg->name = "pm855b_charger";
 		break;
 	case PMI632_SUBTYPE:
@@ -224,6 +243,8 @@
 		chg->param = smb5_pmi632_params;
 		chg->use_extcon = true;
 		chg->name = "pmi632_charger";
+		/* PMI632 does not support PD */
+		__pd_disabled = 1;
 		chg->hw_max_icl_ua =
 			(chip->dt.usb_icl_ua > 0) ? chip->dt.usb_icl_ua
 						: PMI632_MAX_ICL_UA;
@@ -434,7 +455,6 @@
 	POWER_SUPPLY_PROP_TYPEC_MODE,
 	POWER_SUPPLY_PROP_TYPEC_POWER_ROLE,
 	POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION,
-	POWER_SUPPLY_PROP_PD_ALLOWED,
 	POWER_SUPPLY_PROP_PD_ACTIVE,
 	POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
 	POWER_SUPPLY_PROP_INPUT_CURRENT_NOW,
@@ -515,9 +535,6 @@
 		else
 			rc = smblib_get_prop_typec_cc_orientation(chg, val);
 		break;
-	case POWER_SUPPLY_PROP_PD_ALLOWED:
-		rc = smblib_get_prop_pd_allowed(chg, val);
-		break;
 	case POWER_SUPPLY_PROP_PD_ACTIVE:
 		val->intval = chg->pd_active;
 		break;
@@ -605,12 +622,6 @@
 	struct smb_charger *chg = &chip->chg;
 	int rc = 0;
 
-	mutex_lock(&chg->lock);
-	if (!chg->typec_present) {
-		rc = -EINVAL;
-		goto unlock;
-	}
-
 	switch (psp) {
 	case POWER_SUPPLY_PROP_PD_CURRENT_MAX:
 		rc = smblib_set_prop_pd_current_max(chg, val);
@@ -652,8 +663,6 @@
 		break;
 	}
 
-unlock:
-	mutex_unlock(&chg->lock);
 	return rc;
 }
 
@@ -1077,6 +1086,7 @@
 	POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
 	POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
 	POWER_SUPPLY_PROP_CHARGE_COUNTER,
+	POWER_SUPPLY_PROP_CYCLE_COUNT,
 	POWER_SUPPLY_PROP_RECHARGE_SOC,
 };
 
@@ -1171,6 +1181,9 @@
 	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
 		rc = smblib_get_prop_batt_charge_counter(chg, val);
 		break;
+	case POWER_SUPPLY_PROP_CYCLE_COUNT:
+		rc = smblib_get_prop_batt_cycle_count(chg, val);
+		break;
 	case POWER_SUPPLY_PROP_RECHARGE_SOC:
 		val->intval = chg->auto_recharge_soc;
 		break;
@@ -1424,6 +1437,42 @@
 static int smb5_configure_typec(struct smb_charger *chg)
 {
 	int rc;
+	u8 val = 0;
+
+	rc = smblib_read(chg, LEGACY_CABLE_STATUS_REG, &val);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't read Legacy status rc=%d\n", rc);
+		return rc;
+	}
+	/*
+	 * If Legacy cable is detected re-trigger Legacy detection
+	 * by disabling/enabling typeC mode.
+	 */
+	if (val & TYPEC_LEGACY_CABLE_STATUS_BIT) {
+		rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
+				TYPEC_DISABLE_CMD_BIT, TYPEC_DISABLE_CMD_BIT);
+		if (rc < 0) {
+			dev_err(chg->dev, "Couldn't disable TYPEC rc=%d\n", rc);
+			return rc;
+		}
+
+		/* delay before enabling typeC */
+		msleep(500);
+
+		rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
+				TYPEC_DISABLE_CMD_BIT, 0);
+		if (rc < 0) {
+			dev_err(chg->dev, "Couldn't enable TYPEC rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	/* disable apsd */
+	rc = smblib_configure_hvdcp_apsd(chg, false);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't disable APSD rc=%d\n", rc);
+		return rc;
+	}
 
 	rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_1_REG,
 				TYPEC_CCOUT_DETACH_INT_EN_BIT |
@@ -1459,14 +1508,6 @@
 {
 	int rc;
 
-	/* configure micro USB mode */
-	rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG,
-			EN_MICRO_USB_MODE_BIT, EN_MICRO_USB_MODE_BIT);
-	if (rc < 0) {
-		dev_err(chg->dev, "Couldn't enable micro USB mode rc=%d\n", rc);
-		return rc;
-	}
-
 	rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
 					MICRO_USB_STATE_CHANGE_INT_EN_BIT,
 					MICRO_USB_STATE_CHANGE_INT_EN_BIT);
@@ -1500,7 +1541,6 @@
 				&chg->default_icl_ua);
 
 	/* Use SW based VBUS control, disable HW autonomous mode */
-	/* TODO: auth can be enabled through vote based on APSD flow */
 	rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
 		HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
 		HVDCP_AUTH_ALG_EN_CFG_BIT);
@@ -1537,18 +1577,40 @@
 		type = !!(val & EN_MICRO_USB_MODE_BIT);
 	}
 
-	chg->connector_type = type ? POWER_SUPPLY_CONNECTOR_MICRO_USB
-					: POWER_SUPPLY_CONNECTOR_TYPEC;
 	pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC");
 
+	if (type) {
+		chg->connector_type = POWER_SUPPLY_CONNECTOR_MICRO_USB;
+		rc = smb5_configure_micro_usb(chg);
+	} else {
+		chg->connector_type = POWER_SUPPLY_CONNECTOR_TYPEC;
+		rc = smb5_configure_typec(chg);
+	}
+	if (rc < 0) {
+		dev_err(chg->dev,
+			"Couldn't configure TypeC/micro-USB mode rc=%d\n", rc);
+		return rc;
+	}
+
 	/*
 	 * PMI632 based hw init:
+	 * - Enable STAT pin function on SMB_EN
+	 * - Rerun APSD to ensure proper charger detection if device
+	 *   boots with charger connected.
 	 * - Initialize flash module for PMI632
 	 */
-	if (chg->smb_version == PMI632_SUBTYPE)
-		schgm_flash_init(chg);
+	if (chg->smb_version == PMI632_SUBTYPE) {
+		rc = smblib_masked_write(chg, MISC_SMB_EN_CMD_REG,
+					EN_STAT_CMD_BIT, EN_STAT_CMD_BIT);
+		if (rc < 0) {
+			dev_err(chg->dev, "Couldn't configure SMB_EN rc=%d\n",
+					rc);
+			return rc;
+		}
 
-	smblib_rerun_apsd_if_required(chg);
+		schgm_flash_init(chg);
+		smblib_rerun_apsd_if_required(chg);
+	}
 
 	/* vote 0mA on usb_icl for non battery platforms */
 	vote(chg->usb_icl_votable,
@@ -1565,12 +1627,6 @@
 	vote(chg->fv_votable,
 		BATT_PROFILE_VOTER, chg->batt_profile_fv_uv > 0,
 		chg->batt_profile_fv_uv);
-	vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER,
-			true, 0);
-	vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
-			true, 0);
-	vote(chg->pd_disallowed_votable_indirect, MICRO_USB_VOTER,
-		chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB, 0);
 
 	/* Some h/w limit maximum supported ICL */
 	vote(chg->usb_icl_votable, HW_LIMIT_VOTER,
@@ -1578,13 +1634,15 @@
 
 	/*
 	 * AICL configuration:
-	 * start from min and AICL ADC disable
+	 * AICL ADC disable
 	 */
-	rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG,
+	if (chg->smb_version != PMI632_SUBTYPE) {
+		rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG,
 				USBIN_AICL_ADC_EN_BIT, 0);
-	if (rc < 0) {
-		dev_err(chg->dev, "Couldn't configure AICL rc=%d\n", rc);
-		return rc;
+		if (rc < 0) {
+			dev_err(chg->dev, "Couldn't config AICL rc=%d\n", rc);
+			return rc;
+		}
 	}
 
 	/* enable the charging path */
@@ -1594,16 +1652,6 @@
 		return rc;
 	}
 
-	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
-		rc = smb5_configure_micro_usb(chg);
-	else
-		rc = smb5_configure_typec(chg);
-	if (rc < 0) {
-		dev_err(chg->dev,
-			"Couldn't configure TypeC/micro-USB mode rc=%d\n", rc);
-		return rc;
-	}
-
 	/* configure VBUS for software control */
 	rc = smblib_masked_write(chg, DCDC_OTG_CFG_REG, OTG_EN_SRC_CFG_BIT, 0);
 	if (rc < 0) {
@@ -1812,11 +1860,21 @@
 {
 	struct smb_irq_data irq_data = {chip, "determine-initial-status"};
 	struct smb_charger *chg = &chip->chg;
+	union power_supply_propval val;
+	int rc;
+
+	rc = smblib_get_prop_usb_present(chg, &val);
+	if (rc < 0) {
+		pr_err("Couldn't get usb present rc=%d\n", rc);
+		return rc;
+	}
+	chg->early_usb_attach = val.intval;
 
 	if (chg->bms_psy)
 		smblib_suspend_on_debug_battery(chg);
 
 	usb_plugin_irq_handler(0, &irq_data);
+	typec_attach_detach_irq_handler(0, &irq_data);
 	typec_state_change_irq_handler(0, &irq_data);
 	usb_source_change_irq_handler(0, &irq_data);
 	chg_state_change_irq_handler(0, &irq_data);
@@ -2008,6 +2066,7 @@
 	},
 	[TYPEC_ATTACH_DETACH_IRQ] = {
 		.name		= "typec-attach-detach",
+		.handler	= typec_attach_detach_irq_handler,
 	},
 	[TYPEC_LEGACY_CABLE_DETECT_IRQ] = {
 		.name		= "typec-legacy-cable-detect",
@@ -2303,6 +2362,7 @@
 	chg = &chip->chg;
 	chg->dev = &pdev->dev;
 	chg->debug_mask = &__debug_mask;
+	chg->pd_disabled = &__pd_disabled;
 	chg->weak_chg_icl_ua = &__weak_chg_icl_ua;
 	chg->mode = PARALLEL_MASTER;
 	chg->irq_info = smb5_irqs;
@@ -2452,6 +2512,10 @@
 	struct smb5 *chip = platform_get_drvdata(pdev);
 	struct smb_charger *chg = &chip->chg;
 
+	/* force enable APSD */
+	smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
+				BC1P2_SRC_DETECT_BIT, BC1P2_SRC_DETECT_BIT);
+
 	smb5_free_interrupts(chg);
 	smblib_deinit(chg);
 	platform_set_drvdata(pdev, NULL);
diff --git a/drivers/power/supply/qcom/qpnp-smbcharger.c b/drivers/power/supply/qcom/qpnp-smbcharger.c
index 9b5c25f..3bb4810 100644
--- a/drivers/power/supply/qcom/qpnp-smbcharger.c
+++ b/drivers/power/supply/qcom/qpnp-smbcharger.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, 2018 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
@@ -8488,6 +8488,8 @@
 out:
 	handle_usb_removal(chip);
 votables_cleanup:
+	if (chip->hvdcp_enable_votable)
+		destroy_votable(chip->hvdcp_enable_votable);
 	if (chip->aicl_deglitch_short_votable)
 		destroy_votable(chip->aicl_deglitch_short_votable);
 	if (chip->hw_aicl_rerun_enable_indirect_votable)
diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c
index 327ae63..1d99ccb 100644
--- a/drivers/power/supply/qcom/smb1355-charger.c
+++ b/drivers/power/supply/qcom/smb1355-charger.c
@@ -108,6 +108,9 @@
 #define BARK_BITE_WDOG_PET_REG			(MISC_BASE + 0x43)
 #define BARK_BITE_WDOG_PET_BIT			BIT(0)
 
+#define CLOCK_REQUEST_REG			(MISC_BASE + 0x44)
+#define CLOCK_REQUEST_CMD_BIT			BIT(0)
+
 #define WD_CFG_REG				(MISC_BASE + 0x51)
 #define WATCHDOG_TRIGGER_AFP_EN_BIT		BIT(7)
 #define BARK_WDOG_INT_EN_BIT			BIT(6)
@@ -249,6 +252,9 @@
 
 static bool is_secure(struct smb1355 *chip, int addr)
 {
+	if (addr == CLOCK_REQUEST_REG)
+		return true;
+
 	/* assume everything above 0xA0 is secure */
 	return (addr & 0xFF) >= 0xA0;
 }
@@ -265,6 +271,25 @@
 	return rc;
 }
 
+static int smb1355_masked_force_write(struct smb1355 *chip, u16 addr, u8 mask,
+					u8 val)
+{
+	int rc;
+
+	mutex_lock(&chip->write_lock);
+	if (is_secure(chip, addr)) {
+		rc = regmap_write(chip->regmap, (addr & 0xFF00) | 0xD0, 0xA5);
+		if (rc < 0)
+			goto unlock;
+	}
+
+	rc = regmap_write_bits(chip->regmap, addr, mask, val);
+
+unlock:
+	mutex_unlock(&chip->write_lock);
+	return rc;
+}
+
 static int smb1355_masked_write(struct smb1355 *chip, u16 addr, u8 mask, u8 val)
 {
 	int rc;
@@ -494,6 +519,7 @@
 	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
 	POWER_SUPPLY_PROP_MIN_ICL,
 	POWER_SUPPLY_PROP_CURRENT_MAX,
+	POWER_SUPPLY_PROP_SET_SHIP_MODE,
 };
 
 static int smb1355_get_prop_batt_charge_type(struct smb1355 *chip,
@@ -635,6 +661,10 @@
 	case POWER_SUPPLY_PROP_PARALLEL_FCC_MAX:
 		val->intval = chip->max_fcc;
 		break;
+	case POWER_SUPPLY_PROP_SET_SHIP_MODE:
+		/* Not in ship mode as long as device is active */
+		val->intval = 0;
+		break;
 	default:
 		pr_err_ratelimited("parallel psy get prop %d not supported\n",
 			prop);
@@ -726,6 +756,20 @@
 	return rc;
 }
 
+static int smb1355_clk_request(struct smb1355 *chip, bool enable)
+{
+	int rc;
+
+	rc = smb1355_masked_force_write(chip, CLOCK_REQUEST_REG,
+				CLOCK_REQUEST_CMD_BIT,
+				enable ? CLOCK_REQUEST_CMD_BIT : 0);
+	if (rc < 0)
+		pr_err("Couldn't %s clock rc=%d\n",
+			       enable ? "enable" : "disable", rc);
+
+	return rc;
+}
+
 static int smb1355_parallel_set_prop(struct power_supply *psy,
 				     enum power_supply_property prop,
 				     const union power_supply_propval *val)
@@ -752,6 +796,11 @@
 		chip->c_health = val->intval;
 		power_supply_changed(chip->parallel_psy);
 		break;
+	case POWER_SUPPLY_PROP_SET_SHIP_MODE:
+		if (!val->intval)
+			break;
+		rc = smb1355_clk_request(chip, false);
+		break;
 	default:
 		pr_debug("parallel power supply set prop %d not supported\n",
 			prop);
@@ -930,6 +979,11 @@
 {
 	int rc;
 
+	/* request clock always on */
+	rc = smb1355_clk_request(chip, true);
+	if (rc < 0)
+		return rc;
+
 	/* enable watchdog bark and bite interrupts, and disable the watchdog */
 	rc = smb1355_masked_write(chip, WD_CFG_REG, WDOG_TIMER_EN_BIT
 			| WDOG_TIMER_EN_ON_PLUGIN_BIT | BITE_WDOG_INT_EN_BIT
@@ -1340,6 +1394,8 @@
 	rc = smb1355_set_parallel_charging(chip, true);
 	if (rc < 0)
 		pr_err("Couldn't disable parallel path rc=%d\n", rc);
+
+	smb1355_clk_request(chip, false);
 }
 
 static struct platform_driver smb1355_driver = {
diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c
index 8756186..a5af817 100644
--- a/drivers/power/supply/qcom/smb5-lib.c
+++ b/drivers/power/supply/qcom/smb5-lib.c
@@ -39,6 +39,10 @@
 				__func__, ##__VA_ARGS__);	\
 	} while (0)
 
+#define typec_rp_med_high(chg, typec_mode)			\
+	((typec_mode == POWER_SUPPLY_TYPEC_SOURCE_MEDIUM	\
+	|| typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH)	\
+	&& !chg->typec_legacy)
 
 int smblib_read(struct smb_charger *chg, u16 addr, u8 *val)
 {
@@ -508,6 +512,23 @@
 /********************
  * HELPER FUNCTIONS *
  ********************/
+int smblib_configure_hvdcp_apsd(struct smb_charger *chg, bool enable)
+{
+	int rc;
+	u8 mask = HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT;
+
+	if (chg->pd_disabled)
+		return 0;
+
+	rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, mask,
+						enable ? mask : 0);
+	if (rc < 0)
+		smblib_err(chg, "failed to write USBIN_OPTIONS_1_CFG rc=%d\n",
+				rc);
+
+	return rc;
+}
+
 static int smblib_request_dpdm(struct smb_charger *chg, bool enable)
 {
 	int rc = 0;
@@ -654,7 +675,7 @@
 	return 0;
 }
 
-#define USBIN_100MA	100000
+#define SDP_100_MA			100000
 static void smblib_uusb_removal(struct smb_charger *chg)
 {
 	int rc;
@@ -663,10 +684,6 @@
 
 	cancel_delayed_work_sync(&chg->pl_enable_work);
 
-	rc = smblib_request_dpdm(chg, false);
-	if (rc < 0)
-		smblib_err(chg, "Couldn't to disable DPDM rc=%d\n", rc);
-
 	if (chg->wa_flags & BOOST_BACK_WA) {
 		data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data;
 		if (data) {
@@ -683,6 +700,7 @@
 	/* reset both usbin current and voltage votes */
 	vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
 	vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
+	vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, SDP_100_MA);
 	vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
 
 	/* reconfigure allowed voltage for HVDCP */
@@ -705,8 +723,6 @@
 		smblib_err(chg, "Couldn't write float charger options rc=%d\n",
 			rc);
 
-	/* leave the ICL configured to 100mA for next insertion */
-	vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, true, USBIN_100MA);
 	/* clear USB ICL vote for USB_PSY_VOTER */
 	rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
 	if (rc < 0)
@@ -772,6 +788,7 @@
 }
 
 #define USBIN_25MA	25000
+#define USBIN_100MA	100000
 #define USBIN_150MA	150000
 #define USBIN_500MA	500000
 #define USBIN_900MA	900000
@@ -885,6 +902,10 @@
 set_mode:
 	rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
 		USBIN_MODE_CHG_BIT, hc_mode ? USBIN_MODE_CHG_BIT : 0);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't set USBIN_ICL_OPTIONS rc=%d\n", rc);
+		goto out;
+	}
 
 	/* unsuspend after configuring current and override */
 	rc = smblib_set_usb_suspend(chg, false);
@@ -925,7 +946,8 @@
 			return INT_MAX;
 
 		/* override is set */
-		rc = smblib_get_charge_param(chg, &chg->param.usb_icl, icl_ua);
+		rc = smblib_get_charge_param(chg, &chg->param.icl_max_stat,
+					icl_ua);
 		if (rc < 0) {
 			smblib_err(chg, "Couldn't get HC ICL rc=%d\n", rc);
 			return rc;
@@ -954,18 +976,6 @@
 	return smblib_set_dc_suspend(chg, (bool)suspend);
 }
 
-static int smblib_pd_disallowed_votable_indirect_callback(
-	struct votable *votable, void *data, int disallowed, const char *client)
-{
-	struct smb_charger *chg = data;
-	int rc;
-
-	rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER,
-		!disallowed, 0);
-
-	return rc;
-}
-
 static int smblib_awake_vote_callback(struct votable *votable, void *data,
 			int awake, const char *client)
 {
@@ -1459,6 +1469,19 @@
 	return rc;
 }
 
+int smblib_get_prop_batt_cycle_count(struct smb_charger *chg,
+				     union power_supply_propval *val)
+{
+	int rc;
+
+	if (!chg->bms_psy)
+		return -EINVAL;
+
+	rc = power_supply_get_property(chg->bms_psy,
+				       POWER_SUPPLY_PROP_CYCLE_COUNT, val);
+	return rc;
+}
+
 /***********************
  * BATTERY PSY SETTERS *
  ***********************/
@@ -1989,13 +2012,6 @@
 	return rc;
 }
 
-int smblib_get_prop_pd_allowed(struct smb_charger *chg,
-			       union power_supply_propval *val)
-{
-	val->intval = get_effective_result(chg->pd_allowed_votable);
-	return 0;
-}
-
 int smblib_get_prop_input_current_settled(struct smb_charger *chg,
 					  union power_supply_propval *val)
 {
@@ -2039,13 +2055,7 @@
 int smblib_get_pe_start(struct smb_charger *chg,
 			       union power_supply_propval *val)
 {
-	/*
-	 * hvdcp timeout voter is the last one to allow pd. Use its vote
-	 * to indicate start of pe engine
-	 */
-	val->intval
-		= !get_client_vote_locked(chg->pd_disallowed_votable_indirect,
-			APSD_VOTER);
+	val->intval = chg->ok_to_pd;
 	return 0;
 }
 
@@ -2132,24 +2142,40 @@
 
 	if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) {
 		if (usb_current == -ETIMEDOUT) {
-			/*
-			 * Valid FLOAT charger, report the current based
-			 * of Rp
-			 */
+			if ((chg->float_cfg & FLOAT_OPTIONS_MASK)
+						== FORCE_FLOAT_SDP_CFG_BIT) {
+				/*
+				 * Confiugure USB500 mode if Float charger is
+				 * configured for SDP.
+				 */
+				rc = set_sdp_current(chg, USBIN_500MA);
+				if (rc < 0)
+					smblib_err(chg,
+						"Couldn't set SDP ICL rc=%d\n",
+						rc);
+
+				return rc;
+			}
+
 			if (chg->connector_type ==
 					POWER_SUPPLY_CONNECTOR_TYPEC) {
+				/*
+				 * Valid FLOAT charger, report the current
+				 * based of Rp.
+				 */
 				typec_mode = smblib_get_prop_typec_mode(chg);
 				rp_ua = get_rp_based_dcp_current(chg,
 								typec_mode);
 				rc = vote(chg->usb_icl_votable,
-						DYNAMIC_RP_VOTER, true, rp_ua);
-				if (rc < 0) {
-					pr_err("Couldn't vote ICL DYNAMIC_RP_VOTER rc=%d\n",
-							rc);
+					SW_ICL_MAX_VOTER, true, rp_ua);
+				if (rc < 0)
 					return rc;
-				}
+			} else {
+				rc = vote(chg->usb_icl_votable,
+					SW_ICL_MAX_VOTER, true, DCP_CURRENT_UA);
+				if (rc < 0)
+					return rc;
 			}
-			/* No specific handling required for micro-USB */
 		} else {
 			/*
 			 * FLOAT charger detected as SDP by USB driver,
@@ -2158,12 +2184,13 @@
 			 */
 			chg->real_charger_type = POWER_SUPPLY_TYPE_USB;
 			rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
-							true, usb_current);
-			if (rc < 0) {
-				pr_err("Couldn't vote ICL USB_PSY_VOTER rc=%d\n",
-						rc);
+						true, usb_current);
+			if (rc < 0)
 				return rc;
-			}
+			rc = vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER,
+							false, 0);
+			if (rc < 0)
+				return rc;
 		}
 	} else {
 		rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
@@ -2173,12 +2200,12 @@
 			return rc;
 		}
 
-	}
+		rc = vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0);
+		if (rc < 0) {
+			pr_err("Couldn't remove SW_ICL_MAX vote rc=%d\n", rc);
+			return rc;
+		}
 
-	rc = vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0);
-	if (rc < 0) {
-		pr_err("Couldn't unvote ICL DEFAULT_100MA_VOTER rc=%d\n", rc);
-		return rc;
 	}
 
 	return 0;
@@ -2298,14 +2325,14 @@
 	return rc;
 }
 
-static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active)
+int smblib_set_prop_pd_active(struct smb_charger *chg,
+				const union power_supply_propval *val)
 {
 	int rc = 0;
 
-	chg->pd_active = pd_active;
+	chg->pd_active = val->intval;
 
 	if (chg->pd_active) {
-		vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
 		vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
 
 		/*
@@ -2313,24 +2340,24 @@
 		 * It is guaranteed that pd_active is set prior to
 		 * pd_current_max
 		 */
-		rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
-		if (rc < 0)
-			smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
-									rc);
-
-		/* clear USB ICL vote for DCP_VOTER */
-		rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
-		if (rc < 0)
-			smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
-									rc);
-
-		/* remove USB_PSY_VOTER */
-		rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
-		if (rc < 0)
-			smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
+		vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
+		vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0);
 	} else {
-		vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
+		vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, SDP_100_MA);
+		vote(chg->usb_icl_votable, PD_VOTER, false, 0);
 		vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
+
+		/* PD hard resets failed, rerun apsd */
+		if (chg->ok_to_pd) {
+			chg->ok_to_pd = false;
+			rc = smblib_configure_hvdcp_apsd(chg, true);
+			if (rc < 0) {
+				dev_err(chg->dev,
+					"Couldn't enable APSD rc=%d\n", rc);
+				return rc;
+			}
+			smblib_rerun_apsd_if_required(chg);
+		}
 	}
 
 	smblib_update_usb_type(chg);
@@ -2338,15 +2365,6 @@
 	return rc;
 }
 
-int smblib_set_prop_pd_active(struct smb_charger *chg,
-			      const union power_supply_propval *val)
-{
-	if (!get_effective_result(chg->pd_allowed_votable))
-		return -EINVAL;
-
-	return __smblib_set_prop_pd_active(chg, val->intval);
-}
-
 int smblib_set_prop_ship_mode(struct smb_charger *chg,
 				const union power_supply_propval *val)
 {
@@ -2657,11 +2675,7 @@
 
 static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
 {
-	if (vbus_rising) {
-		/* use the typec flag even though its not typec */
-		chg->typec_present = 1;
-	} else {
-		chg->typec_present = 0;
+	if (!vbus_rising) {
 		smblib_update_usb_type(chg);
 		smblib_notify_device_mode(chg, false);
 		smblib_uusb_removal(chg);
@@ -2764,12 +2778,10 @@
 	struct smb_irq_data *irq_data = data;
 	struct smb_charger *chg = irq_data->parent_data;
 
-	mutex_lock(&chg->lock);
 	if (chg->pd_hard_reset)
 		smblib_usb_plugin_hard_reset_locked(chg);
 	else
 		smblib_usb_plugin_locked(chg);
-	mutex_unlock(&chg->lock);
 
 	return IRQ_HANDLED;
 }
@@ -2858,8 +2870,6 @@
 	if (!rising)
 		return;
 
-	vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0);
-
 	if (chg->mode == PARALLEL_MASTER)
 		vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
 
@@ -2872,33 +2882,18 @@
 static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
 					      bool rising, bool qc_charger)
 {
-	const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
-
-	/* Hold off PD only until hvdcp 2.0 detection timeout */
 	if (rising) {
 
-		/* enable HDC and ICL irq for QC2/3 charger */
-		if (qc_charger)
+		if (qc_charger) {
+			/* enable HDC and ICL irq for QC2/3 charger */
 			vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0);
-		else
-			vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
-							false, 0);
-
-		/*
-		 * HVDCP detection timeout done
-		 * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
-		 */
-		if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
-			/* enforce DCP ICL if specified */
+			vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
+				HVDCP_CURRENT_UA);
+		} else {
+			/* A plain DCP, enforce DCP ICL if specified */
 			vote(chg->usb_icl_votable, DCP_VOTER,
 				chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
-
-		/*
-		 * if pd is not allowed, then set pd_active = false right here,
-		 * so that it starts the hvdcp engine
-		 */
-		if (!get_effective_result(chg->pd_allowed_votable))
-			__smblib_set_prop_pd_active(chg, 0);
+		}
 	}
 
 	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n", __func__,
@@ -2913,6 +2908,69 @@
 		   rising ? "rising" : "falling");
 }
 
+static void update_sw_icl_max(struct smb_charger *chg, int pst)
+{
+	int typec_mode;
+	int rp_ua;
+
+	/* while PD is active it should have complete ICL control */
+	if (chg->pd_active)
+		return;
+
+	/*
+	 * HVDCP 2/3, handled separately
+	 * For UNKNOWN(input not present) return without updating ICL
+	 */
+	if (pst == POWER_SUPPLY_TYPE_USB_HVDCP
+			|| pst == POWER_SUPPLY_TYPE_USB_HVDCP_3
+			|| pst == POWER_SUPPLY_TYPE_UNKNOWN)
+		return;
+
+	/* TypeC rp med or high, use rp value */
+	typec_mode = smblib_get_prop_typec_mode(chg);
+	if (typec_rp_med_high(chg, typec_mode)) {
+		rp_ua = get_rp_based_dcp_current(chg, typec_mode);
+		vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, rp_ua);
+		return;
+	}
+
+	/* rp-std or legacy, USB BC 1.2 */
+	switch (pst) {
+	case POWER_SUPPLY_TYPE_USB:
+		/*
+		 * USB_PSY will vote to increase the current to 500/900mA once
+		 * enumeration is done.
+		 */
+		if (!is_client_vote_enabled(chg->usb_icl_votable,
+								USB_PSY_VOTER))
+			vote(chg->usb_icl_votable, USB_PSY_VOTER, true,
+					SDP_100_MA);
+		vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0);
+		break;
+	case POWER_SUPPLY_TYPE_USB_CDP:
+		vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
+					CDP_CURRENT_UA);
+		break;
+	case POWER_SUPPLY_TYPE_USB_DCP:
+		vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
+					DCP_CURRENT_UA);
+		break;
+	case POWER_SUPPLY_TYPE_USB_FLOAT:
+		/*
+		 * limit ICL to 100mA, the USB driver will enumerate to check
+		 * if this is a SDP and appropriately set the current
+		 */
+		vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
+					SDP_100_MA);
+		break;
+	default:
+		smblib_err(chg, "Unknown APSD %d; forcing 500mA\n", pst);
+		vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
+					SDP_CURRENT_UA);
+		break;
+	}
+}
+
 static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
 {
 	const struct apsd_result *apsd_result;
@@ -2922,25 +2980,18 @@
 
 	apsd_result = smblib_update_usb_type(chg);
 
+	update_sw_icl_max(chg, apsd_result->pst);
+
 	switch (apsd_result->bit) {
 	case SDP_CHARGER_BIT:
 	case CDP_CHARGER_BIT:
 	case FLOAT_CHARGER_BIT:
-		/* if not DCP then no hvdcp timeout happens. Enable pd here */
-		vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
-				false, 0);
 		if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
 				|| chg->use_extcon)
 			smblib_notify_device_mode(chg, true);
 		break;
 	case OCP_CHARGER_BIT:
-		vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0);
-		/* if not DCP then no hvdcp timeout happens, Enable pd here. */
-		vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
-				false, 0);
-		break;
 	case DCP_CHARGER_BIT:
-		vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0);
 		break;
 	default:
 		break;
@@ -2957,6 +3008,14 @@
 	int rc = 0;
 	u8 stat;
 
+	/*
+	 * Prepared to run PD or PD is active. At this moment, APSD is disabled,
+	 * but there still can be irq on apsd_done from previously unfinished
+	 * APSD run, skip it.
+	 */
+	if (chg->ok_to_pd)
+		return IRQ_HANDLED;
+
 	rc = smblib_read(chg, APSD_STATUS_REG, &stat);
 	if (rc < 0) {
 		smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
@@ -2972,7 +3031,7 @@
 		 * charger-mis-detection.
 		 */
 		chg->uusb_apsd_rerun_done = true;
-		smblib_rerun_apsd(chg);
+		smblib_rerun_apsd_if_required(chg);
 		return IRQ_HANDLED;
 	}
 
@@ -3011,32 +3070,69 @@
 
 static void typec_sink_insertion(struct smb_charger *chg)
 {
-	/* when a sink is inserted we should not wait on hvdcp timeout to
-	 * enable pd
-	 */
-	vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0);
+	vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
+
 	if (chg->use_extcon) {
 		smblib_notify_usb_host(chg, true);
 		chg->otg_present = true;
 	}
+
+	if (!chg->pr_swap_in_progress)
+		chg->ok_to_pd = !(*chg->pd_disabled) || chg->early_usb_attach;
+}
+
+static void typec_src_insertion(struct smb_charger *chg)
+{
+	int rc = 0;
+	u8 stat;
+
+	if (chg->pr_swap_in_progress)
+		return;
+
+	rc = smblib_read(chg, LEGACY_CABLE_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_STATE_MACHINE_STATUS_REG rc=%d\n",
+			rc);
+		return;
+	}
+
+	chg->typec_legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
+	chg->ok_to_pd = !(chg->typec_legacy || *chg->pd_disabled)
+						|| chg->early_usb_attach;
+	if (!chg->ok_to_pd) {
+		rc = smblib_configure_hvdcp_apsd(chg, true);
+		if (rc < 0) {
+			dev_err(chg->dev,
+				"Couldn't enable APSD rc=%d\n", rc);
+			return;
+		}
+		smblib_rerun_apsd_if_required(chg);
+	}
 }
 
 static void typec_sink_removal(struct smb_charger *chg)
 {
-	smblib_set_charge_param(chg, &chg->param.freq_switcher,
-			chg->chg_freq.freq_above_otg_threshold);
-	chg->boost_current_ua = 0;
+	vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
+
+	if (chg->use_extcon) {
+		if (chg->otg_present)
+			smblib_notify_usb_host(chg, false);
+		chg->otg_present = false;
+	}
 }
 
-static void smblib_handle_typec_removal(struct smb_charger *chg)
+static void typec_src_removal(struct smb_charger *chg)
 {
 	int rc;
 	struct smb_irq_data *data;
 	struct storm_watch *wdata;
 
-	rc = smblib_request_dpdm(chg, false);
+	/* disable apsd */
+	rc = smblib_configure_hvdcp_apsd(chg, false);
 	if (rc < 0)
-		smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
+		smblib_err(chg, "Couldn't disable APSD rc=%d\n", rc);
+
+	smblib_update_usb_type(chg);
 
 	if (chg->wa_flags & BOOST_BACK_WA) {
 		data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data;
@@ -3052,7 +3148,7 @@
 	cancel_delayed_work_sync(&chg->pl_enable_work);
 
 	/* reset input current limit voters */
-	vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, true, USBIN_100MA);
+	vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, SDP_100_MA);
 	vote(chg->usb_icl_votable, PD_VOTER, false, 0);
 	vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
 	vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
@@ -3060,12 +3156,6 @@
 	vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
 	vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
 	vote(chg->usb_icl_votable, CTM_VOTER, false, 0);
-	vote(chg->usb_icl_votable, DYNAMIC_RP_VOTER, false, 0);
-
-	/* reset power delivery voters */
-	vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
-	vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
-	vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, true, 0);
 
 	/* reset usb irq voters */
 	vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
@@ -3078,14 +3168,10 @@
 	vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
 	vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
 
-	chg->vconn_attempts = 0;
-	chg->otg_attempts = 0;
 	chg->pulse_cnt = 0;
 	chg->usb_icl_delta_ua = 0;
 	chg->voltage_min_uv = MICRO_5V;
 	chg->voltage_max_uv = MICRO_5V;
-	chg->pd_active = 0;
-	chg->pd_hard_reset = 0;
 
 	/* write back the default FLOAT charger configuration */
 	rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
@@ -3094,12 +3180,6 @@
 		smblib_err(chg, "Couldn't write float charger options rc=%d\n",
 			rc);
 
-	/* reset back to 103mS tCC debounce */
-	rc = smblib_masked_write(chg, TYPE_C_DEBOUNCE_OPTION_REG,
-					REDUCE_TCCDEBOUNCE_TO_2MS_BIT, 0);
-	if (rc < 0)
-		smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc);
-
 	/* reconfigure allowed voltage for HVDCP */
 	rc = smblib_set_adapter_allowance(chg,
 			USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
@@ -3107,157 +3187,35 @@
 		smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
 			rc);
 
-	/* enable DRP */
-	rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
-				 TYPEC_POWER_ROLE_CMD_MASK, 0);
-	if (rc < 0)
-		smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
+	if (chg->use_extcon)
+		smblib_notify_device_mode(chg, false);
 
-	/* HW controlled CC_OUT */
-	rc = smblib_masked_write(chg, TYPE_C_CCOUT_CONTROL_REG,
-				TYPEC_CCOUT_SRC_BIT, 0);
-	if (rc < 0)
-		smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
-
-	/* clear exit sink based on cc */
-	rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG,
-						EXIT_SNK_BASED_ON_CC_BIT, 0);
-	if (rc < 0)
-		smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n",
-				rc);
-
-	typec_sink_removal(chg);
-	smblib_update_usb_type(chg);
-
-	if (chg->use_extcon) {
-		if (chg->otg_present)
-			smblib_notify_usb_host(chg, false);
-		else
-			smblib_notify_device_mode(chg, false);
-	}
-	chg->otg_present = false;
-}
-
-static void smblib_handle_typec_insertion(struct smb_charger *chg)
-{
-	int rc;
-	u8 stat;
-
-	vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
-
-	rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
-	if (rc < 0) {
-		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
-		return;
-	}
-
-	if (stat & SNK_SRC_MODE_BIT) {
-		typec_sink_insertion(chg);
-	} else {
-		rc = smblib_request_dpdm(chg, true);
-		if (rc < 0)
-			smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
-		typec_sink_removal(chg);
-	}
+	chg->typec_legacy = false;
 }
 
 static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode)
 {
-	int rp_ua;
 	const struct apsd_result *apsd = smblib_get_apsd_result(chg);
 
-	if ((apsd->pst != POWER_SUPPLY_TYPE_USB_DCP)
-		&& (apsd->pst != POWER_SUPPLY_TYPE_USB_FLOAT))
-		return;
-
-	/*
-	 * if APSD indicates FLOAT and the USB stack had detected SDP,
-	 * do not respond to Rp changes as we do not confirm that its
-	 * a legacy cable
-	 */
-	if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
-		return;
 	/*
 	 * We want the ICL vote @ 100mA for a FLOAT charger
 	 * until the detection by the USB stack is complete.
 	 * Ignore the Rp changes unless there is a
-	 * pre-existing valid vote.
+	 * pre-existing valid vote or FLOAT is configured for
+	 * SDP current.
 	 */
-	if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
-		(get_client_vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER)
-					<= USBIN_100MA))
+	if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT) {
+		if (get_client_vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER)
+					<= USBIN_100MA
+			|| (chg->float_cfg & FLOAT_OPTIONS_MASK)
+					== FORCE_FLOAT_SDP_CFG_BIT)
 		return;
+	}
 
-	/*
-	 * handle Rp change for DCP/FLOAT/OCP.
-	 * Update the current only if the Rp is different from
-	 * the last Rp value.
-	 */
+	update_sw_icl_max(chg, apsd->pst);
+
 	smblib_dbg(chg, PR_MISC, "CC change old_mode=%d new_mode=%d\n",
 						chg->typec_mode, typec_mode);
-
-	rp_ua = get_rp_based_dcp_current(chg, typec_mode);
-	vote(chg->usb_icl_votable, DYNAMIC_RP_VOTER, true, rp_ua);
-}
-
-static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
-{
-	u8 stat;
-	int typec_mode, rc;
-
-	if (chg->pr_swap_in_progress)
-		return;
-
-	typec_mode = smblib_get_prop_typec_mode(chg);
-	if (chg->typec_present && (typec_mode != chg->typec_mode))
-		smblib_handle_rp_change(chg, typec_mode);
-
-	chg->typec_mode = typec_mode;
-
-	if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
-		chg->typec_present = true;
-		smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
-			smblib_typec_mode_name[chg->typec_mode]);
-		smblib_handle_typec_insertion(chg);
-	} else if (chg->typec_present &&
-				chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
-		chg->typec_present = false;
-		smblib_dbg(chg, PR_MISC, "TypeC removal\n");
-		smblib_handle_typec_removal(chg);
-	}
-
-	rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
-	if (rc < 0) {
-		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
-		return;
-	}
-	/* suspend usb if sink */
-	if ((stat & SNK_SRC_MODE_BIT) && chg->typec_present)
-		vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
-	else
-		vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
-
-	smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
-				smblib_typec_mode_name[chg->typec_mode]);
-}
-
-static void smblib_usb_typec_change(struct smb_charger *chg)
-{
-	int rc;
-	u8 stat;
-
-	smblib_handle_typec_cc_state_change(chg);
-
-	rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
-	if (rc < 0) {
-		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
-		return;
-	}
-
-	if (stat & TYPEC_VBUS_ERROR_STATUS_BIT)
-		smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
-
-	power_supply_changed(chg->usb_psy);
 }
 
 irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data)
@@ -3281,17 +3239,81 @@
 {
 	struct smb_irq_data *irq_data = data;
 	struct smb_charger *chg = irq_data->parent_data;
+	int typec_mode;
 
-	if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
-			|| chg->pr_swap_in_progress) {
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
 		smblib_dbg(chg, PR_INTERRUPT,
-				"Ignoring since pr_swap_in_progress\n");
+				"Ignoring for micro USB\n");
 		return IRQ_HANDLED;
 	}
 
-	mutex_lock(&chg->lock);
-	smblib_usb_typec_change(chg);
-	mutex_unlock(&chg->lock);
+	typec_mode = smblib_get_prop_typec_mode(chg);
+	if (chg->sink_src_mode != UNATTACHED_MODE
+			&& (typec_mode != chg->typec_mode))
+		smblib_handle_rp_change(chg, typec_mode);
+	chg->typec_mode = typec_mode;
+
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
+				smblib_typec_mode_name[chg->typec_mode]);
+
+	power_supply_changed(chg->usb_psy);
+
+	return IRQ_HANDLED;
+}
+
+irqreturn_t typec_attach_detach_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+	u8 stat;
+	int rc;
+
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
+
+	rc = smblib_read(chg, TYPE_C_STATE_MACHINE_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_STATE_MACHINE_STATUS_REG rc=%d\n",
+			rc);
+		return IRQ_HANDLED;
+	}
+
+	if (stat & TYPEC_ATTACH_DETACH_STATE_BIT) {
+		rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't read TYPE_C_MISC_STATUS_REG rc=%d\n",
+				rc);
+			return IRQ_HANDLED;
+		}
+
+		if (stat & SNK_SRC_MODE_BIT) {
+			chg->sink_src_mode = SRC_MODE;
+			typec_sink_insertion(chg);
+		} else {
+			chg->sink_src_mode = SINK_MODE;
+			typec_src_insertion(chg);
+		}
+
+	} else {
+		switch (chg->sink_src_mode) {
+		case SRC_MODE:
+			typec_sink_removal(chg);
+			break;
+		case SINK_MODE:
+			typec_src_removal(chg);
+			break;
+		default:
+			break;
+		}
+
+		if (!chg->pr_swap_in_progress) {
+			chg->ok_to_pd = false;
+			chg->sink_src_mode = UNATTACHED_MODE;
+			chg->early_usb_attach = false;
+		}
+	}
+
+	power_supply_changed(chg->usb_psy);
+
 	return IRQ_HANDLED;
 }
 
@@ -3426,19 +3448,55 @@
 				const union power_supply_propval *val)
 {
 	int rc;
+	u8 stat = 0, orientation;
 
 	chg->pr_swap_in_progress = val->intval;
 
-	/*
-	 * call the cc changed irq to handle real removals while
-	 * PR_SWAP was in progress
-	 */
-	smblib_usb_typec_change(chg);
 	rc = smblib_masked_write(chg, TYPE_C_DEBOUNCE_OPTION_REG,
 			REDUCE_TCCDEBOUNCE_TO_2MS_BIT,
 			val->intval ? REDUCE_TCCDEBOUNCE_TO_2MS_BIT : 0);
 	if (rc < 0)
 		smblib_err(chg, "Couldn't set tCC debounce rc=%d\n", rc);
+
+	rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG,
+			BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT,
+			val->intval ? BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT : 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't set exit state cfg rc=%d\n", rc);
+
+	if (chg->pr_swap_in_progress) {
+		rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
+				rc);
+		}
+
+		orientation =
+			stat & CC_ORIENTATION_BIT ? TYPEC_CCOUT_VALUE_BIT : 0;
+		rc = smblib_masked_write(chg, TYPE_C_CCOUT_CONTROL_REG,
+			TYPEC_CCOUT_SRC_BIT | TYPEC_CCOUT_BUFFER_EN_BIT
+					| TYPEC_CCOUT_VALUE_BIT,
+			TYPEC_CCOUT_SRC_BIT | TYPEC_CCOUT_BUFFER_EN_BIT
+					| orientation);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't read TYPE_C_CCOUT_CONTROL_REG rc=%d\n",
+				rc);
+		}
+	} else {
+		rc = smblib_masked_write(chg, TYPE_C_CCOUT_CONTROL_REG,
+			TYPEC_CCOUT_SRC_BIT, 0);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't read TYPE_C_CCOUT_CONTROL_REG rc=%d\n",
+				rc);
+		}
+
+		/* enable DRP */
+		rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
+				 TYPEC_POWER_ROLE_CMD_MASK, 0);
+		if (rc < 0)
+			smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
+	}
+
 	return 0;
 }
 
@@ -3461,6 +3519,9 @@
 	otg = !!(stat & U_USB_GROUND_NOVBUS_BIT);
 	if (chg->otg_present != otg)
 		smblib_notify_usb_host(chg, otg);
+	else
+		goto out;
+
 	chg->otg_present = otg;
 	if (!otg)
 		chg->boost_current_ua = 0;
@@ -3681,23 +3742,6 @@
 		return rc;
 	}
 
-	chg->pd_disallowed_votable_indirect
-		= create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
-			smblib_pd_disallowed_votable_indirect_callback, chg);
-	if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
-		rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
-		chg->pd_disallowed_votable_indirect = NULL;
-		return rc;
-	}
-
-	chg->pd_allowed_votable = create_votable("PD_ALLOWED",
-					VOTE_SET_ANY, NULL, NULL);
-	if (IS_ERR(chg->pd_allowed_votable)) {
-		rc = PTR_ERR(chg->pd_allowed_votable);
-		chg->pd_allowed_votable = NULL;
-		return rc;
-	}
-
 	chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
 					smblib_awake_vote_callback,
 					chg);
@@ -3735,10 +3779,6 @@
 		destroy_votable(chg->dc_suspend_votable);
 	if (chg->usb_icl_votable)
 		destroy_votable(chg->usb_icl_votable);
-	if (chg->pd_disallowed_votable_indirect)
-		destroy_votable(chg->pd_disallowed_votable_indirect);
-	if (chg->pd_allowed_votable)
-		destroy_votable(chg->pd_allowed_votable);
 	if (chg->awake_votable)
 		destroy_votable(chg->awake_votable);
 	if (chg->chg_disable_votable)
@@ -3750,7 +3790,6 @@
 	int rc = 0;
 
 	mutex_init(&chg->lock);
-	mutex_init(&chg->otg_oc_lock);
 	INIT_WORK(&chg->bms_update_work, bms_update_work);
 	INIT_WORK(&chg->pl_update_work, pl_update_work);
 	INIT_WORK(&chg->jeita_update_work, jeita_update_work);
@@ -3763,6 +3802,7 @@
 	chg->fake_input_current_limited = -EINVAL;
 	chg->fake_batt_status = -EINVAL;
 	chg->jeita_configured = false;
+	chg->sink_src_mode = UNATTACHED_MODE;
 
 	switch (chg->mode) {
 	case PARALLEL_MASTER:
diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h
index 5d6d3a6..14eba8c 100644
--- a/drivers/power/supply/qcom/smb5-lib.h
+++ b/drivers/power/supply/qcom/smb5-lib.h
@@ -56,6 +56,7 @@
 #define CTM_VOTER			"CTM_VOTER"
 #define SW_QC3_VOTER			"SW_QC3_VOTER"
 #define AICL_RERUN_VOTER		"AICL_RERUN_VOTER"
+#define SW_ICL_MAX_VOTER		"SW_ICL_MAX_VOTER"
 #define QNOVO_VOTER			"QNOVO_VOTER"
 #define BATT_PROFILE_VOTER		"BATT_PROFILE_VOTER"
 #define OTG_DELAY_VOTER			"OTG_DELAY_VOTER"
@@ -65,8 +66,6 @@
 #define PL_FCC_LOW_VOTER		"PL_FCC_LOW_VOTER"
 #define WBC_VOTER			"WBC_VOTER"
 #define HW_LIMIT_VOTER			"HW_LIMIT_VOTER"
-#define DYNAMIC_RP_VOTER		"DYNAMIC_RP_VOTER"
-#define DEFAULT_100MA_VOTER		"DEFAULT_100MA_VOTER"
 #define FORCE_RECHARGE_VOTER		"FORCE_RECHARGE_VOTER"
 
 #define BOOST_BACK_STORM_COUNT	3
@@ -80,6 +79,12 @@
 	NUM_MODES,
 };
 
+enum sink_src_mode {
+	SINK_MODE,
+	SRC_MODE,
+	UNATTACHED_MODE,
+};
+
 enum {
 	BOOST_BACK_WA			= BIT(0),
 };
@@ -228,6 +233,7 @@
 	struct smb_chg_param	fcc;
 	struct smb_chg_param	fv;
 	struct smb_chg_param	usb_icl;
+	struct smb_chg_param	icl_max_stat;
 	struct smb_chg_param	icl_stat;
 	struct smb_chg_param	otg_cl;
 	struct smb_chg_param	jeita_cc_comp_hot;
@@ -259,6 +265,7 @@
 	struct smb_params	param;
 	struct smb_iio		iio;
 	int			*debug_mask;
+	int			*pd_disabled;
 	enum smb_mode		mode;
 	struct smb_chg_freq	chg_freq;
 	int			smb_version;
@@ -269,7 +276,6 @@
 	/* locks */
 	struct mutex		lock;
 	struct mutex		ps_change_lock;
-	struct mutex		otg_oc_lock;
 
 	/* power supplies */
 	struct power_supply		*batt_psy;
@@ -296,8 +302,6 @@
 	struct votable		*fcc_votable;
 	struct votable		*fv_votable;
 	struct votable		*usb_icl_votable;
-	struct votable		*pd_disallowed_votable_indirect;
-	struct votable		*pd_allowed_votable;
 	struct votable		*awake_votable;
 	struct votable		*pl_disable_votable;
 	struct votable		*chg_disable_votable;
@@ -315,10 +319,17 @@
 	struct delayed_work	uusb_otg_work;
 	struct delayed_work	bb_removal_work;
 
-	/* cached status */
+	/* pd */
 	int			voltage_min_uv;
 	int			voltage_max_uv;
 	int			pd_active;
+	bool			pd_hard_reset;
+	bool			pr_swap_in_progress;
+	bool			early_usb_attach;
+	bool			ok_to_pd;
+	bool			typec_legacy;
+
+	/* cached status */
 	bool			system_suspend_supported;
 	int			boost_threshold_ua;
 	int			system_temp_level;
@@ -334,15 +345,10 @@
 	int			connector_type;
 	bool			otg_en;
 	bool			suspend_input_on_debug_batt;
-	int			otg_attempts;
-	int			vconn_attempts;
 	int			default_icl_ua;
 	int			otg_cl_ua;
 	bool			uusb_apsd_rerun_done;
-	bool			pd_hard_reset;
-	bool			typec_present;
 	int			fake_input_current_limited;
-	bool			pr_swap_in_progress;
 	int			typec_mode;
 	int			usb_icl_change_irq_enabled;
 	u32			jeita_status;
@@ -352,6 +358,7 @@
 	int			hw_max_icl_ua;
 	int			auto_recharge_soc;
 	bool			jeita_configured;
+	enum sink_src_mode	sink_src_mode;
 
 	/* workaround flag */
 	u32			wa_flags;
@@ -420,6 +427,7 @@
 irqreturn_t usb_source_change_irq_handler(int irq, void *data);
 irqreturn_t icl_change_irq_handler(int irq, void *data);
 irqreturn_t typec_state_change_irq_handler(int irq, void *data);
+irqreturn_t typec_attach_detach_irq_handler(int irq, void *data);
 irqreturn_t dc_plugin_irq_handler(int irq, void *data);
 irqreturn_t high_duty_cycle_irq_handler(int irq, void *data);
 irqreturn_t switcher_power_ok_irq_handler(int irq, void *data);
@@ -454,6 +462,8 @@
 				union power_supply_propval *val);
 int smblib_get_prop_batt_charge_counter(struct smb_charger *chg,
 				union power_supply_propval *val);
+int smblib_get_prop_batt_cycle_count(struct smb_charger *chg,
+				union power_supply_propval *val);
 int smblib_set_prop_input_suspend(struct smb_charger *chg,
 				const union power_supply_propval *val);
 int smblib_set_prop_batt_capacity(struct smb_charger *chg,
@@ -485,8 +495,6 @@
 				union power_supply_propval *val);
 int smblib_get_prop_typec_power_role(struct smb_charger *chg,
 				union power_supply_propval *val);
-int smblib_get_prop_pd_allowed(struct smb_charger *chg,
-				union power_supply_propval *val);
 int smblib_get_prop_input_current_settled(struct smb_charger *chg,
 				union power_supply_propval *val);
 int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
@@ -530,6 +538,7 @@
 int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override);
 int smblib_configure_wdog(struct smb_charger *chg, bool enable);
 int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val);
+int smblib_configure_hvdcp_apsd(struct smb_charger *chg, bool enable);
 
 int smblib_init(struct smb_charger *chg);
 int smblib_deinit(struct smb_charger *chg);
diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h
index e199087..79a8bd0 100644
--- a/drivers/power/supply/qcom/smb5-reg.h
+++ b/drivers/power/supply/qcom/smb5-reg.h
@@ -105,6 +105,8 @@
 /********************************
  *  DCDC Peripheral Registers  *
  ********************************/
+#define ICL_MAX_STATUS_REG			(DCDC_BASE + 0x06)
+
 #define AICL_ICL_STATUS_REG			(DCDC_BASE + 0x08)
 
 #define AICL_STATUS_REG				(DCDC_BASE + 0x0A)
@@ -215,6 +217,7 @@
 #define HVDCP_AUTH_ALG_EN_CFG_BIT		BIT(6)
 #define HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT	BIT(5)
 #define BC1P2_SRC_DETECT_BIT			BIT(3)
+#define HVDCP_EN_BIT				BIT(2)
 
 #define USBIN_OPTIONS_2_CFG_REG			(USBIN_BASE + 0x63)
 #define FLOAT_OPTIONS_MASK			GENMASK(2, 0)
@@ -262,6 +265,9 @@
 #define SRC_RA_OPEN_BIT				BIT(1)
 #define AUDIO_ACCESS_RA_RA_BIT			BIT(0)
 
+#define TYPE_C_STATE_MACHINE_STATUS_REG		(TYPEC_BASE + 0x09)
+#define TYPEC_ATTACH_DETACH_STATE_BIT		BIT(5)
+
 #define TYPE_C_MISC_STATUS_REG			(TYPEC_BASE + 0x0B)
 #define SNK_SRC_MODE_BIT			BIT(6)
 #define TYPEC_VBUS_ERROR_STATUS_BIT		BIT(4)
@@ -269,6 +275,7 @@
 #define CC_ATTACHED_BIT				BIT(0)
 
 #define LEGACY_CABLE_STATUS_REG			(TYPEC_BASE + 0x0D)
+#define TYPEC_LEGACY_CABLE_STATUS_BIT		BIT(1)
 #define TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT	BIT(0)
 
 #define TYPEC_U_USB_STATUS_REG			(TYPEC_BASE + 0x0F)
@@ -276,7 +283,7 @@
 #define U_USB_GROUND_BIT			BIT(4)
 
 #define TYPE_C_MODE_CFG_REG			(TYPEC_BASE + 0x44)
-#define TYPEC_POWER_ROLE_CMD_MASK		GENMASK(2, 0)
+#define TYPEC_POWER_ROLE_CMD_MASK		GENMASK(2, 1)
 #define EN_SRC_ONLY_BIT				BIT(2)
 #define EN_SNK_ONLY_BIT				BIT(1)
 #define TYPEC_DISABLE_CMD_BIT			BIT(0)
@@ -287,10 +294,12 @@
 #define VCONN_EN_SRC_BIT			BIT(0)
 
 #define TYPE_C_CCOUT_CONTROL_REG		(TYPEC_BASE + 0x48)
+#define TYPEC_CCOUT_BUFFER_EN_BIT		BIT(2)
 #define TYPEC_CCOUT_VALUE_BIT			BIT(1)
 #define TYPEC_CCOUT_SRC_BIT			BIT(0)
 
 #define TYPE_C_EXIT_STATE_CFG_REG		(TYPEC_BASE + 0x50)
+#define BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT	BIT(3)
 #define EXIT_SNK_BASED_ON_CC_BIT		BIT(0)
 
 #define TYPE_C_INTERRUPT_EN_CFG_1_REG			(TYPEC_BASE + 0x5E)
@@ -318,7 +327,7 @@
 #define TYPEC_U_USB_CFG_REG			(TYPEC_BASE + 0x70)
 #define EN_MICRO_USB_MODE_BIT			BIT(0)
 
-#define TYPEC_MICRO_USB_MODE_REG		(TYPEC_BASE + 0x70)
+#define TYPEC_MICRO_USB_MODE_REG		(TYPEC_BASE + 0x73)
 #define MICRO_USB_MODE_ONLY_BIT			BIT(0)
 /********************************
  *  MISC Peripheral Registers  *
diff --git a/drivers/powercap/powercap_sys.c b/drivers/powercap/powercap_sys.c
index 14bde0d..5b10b50 100644
--- a/drivers/powercap/powercap_sys.c
+++ b/drivers/powercap/powercap_sys.c
@@ -538,6 +538,7 @@
 
 	power_zone->id = result;
 	idr_init(&power_zone->idr);
+	result = -ENOMEM;
 	power_zone->name = kstrdup(name, GFP_KERNEL);
 	if (!power_zone->name)
 		goto err_name_alloc;
diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
index 1c85ecc..0fcf94f 100644
--- a/drivers/pwm/pwm-rcar.c
+++ b/drivers/pwm/pwm-rcar.c
@@ -156,8 +156,12 @@
 	if (div < 0)
 		return div;
 
-	/* Let the core driver set pwm->period if disabled and duty_ns == 0 */
-	if (!pwm_is_enabled(pwm) && !duty_ns)
+	/*
+	 * Let the core driver set pwm->period if disabled and duty_ns == 0.
+	 * But, this driver should prevent to set the new duty_ns if current
+	 * duty_cycle is not set
+	 */
+	if (!pwm_is_enabled(pwm) && !duty_ns && !pwm->state.duty_cycle)
 		return 0;
 
 	rcar_pwm_update(rp, RCAR_PWMCR_SYNC, RCAR_PWMCR_SYNC, RCAR_PWMCR);
diff --git a/drivers/regulator/cpr3-regulator.c b/drivers/regulator/cpr3-regulator.c
index 9510016..2eff0cf 100644
--- a/drivers/regulator/cpr3-regulator.c
+++ b/drivers/regulator/cpr3-regulator.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -178,6 +178,7 @@
 
 #define CPR4_REG_MISC				0x700
 #define CPR4_MISC_RESET_STEP_QUOT_LOOP_EN	BIT(2)
+#define CPR4_MISC_THREAD_HAS_ALWAYS_VOTE_EN	BIT(3)
 #define CPR4_MISC_MARGIN_TABLE_ROW_SELECT_MASK	GENMASK(23, 20)
 #define CPR4_MISC_MARGIN_TABLE_ROW_SELECT_SHIFT	20
 #define CPR4_MISC_TEMP_SENSOR_ID_START_MASK	GENMASK(27, 24)
@@ -733,6 +734,11 @@
 				CPR4_MISC_RESET_STEP_QUOT_LOOP_EN,
 				CPR4_MISC_RESET_STEP_QUOT_LOOP_EN);
 
+	if (ctrl->thread_has_always_vote_en)
+		cpr3_masked_write(ctrl, CPR4_REG_MISC,
+			CPR4_MISC_THREAD_HAS_ALWAYS_VOTE_EN,
+			CPR4_MISC_THREAD_HAS_ALWAYS_VOTE_EN);
+
 	if (ctrl->supports_hw_closed_loop) {
 		if (ctrl->saw_use_unit_mV)
 			pmic_step_size = ctrl->step_volt / 1000;
diff --git a/drivers/regulator/cpr3-regulator.h b/drivers/regulator/cpr3-regulator.h
index 778f482..39d3f82 100644
--- a/drivers/regulator/cpr3-regulator.h
+++ b/drivers/regulator/cpr3-regulator.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -766,6 +766,12 @@
  *			the CPR controller to first use the default step_quot
  *			and then later switch to the run-time calibrated
  *			step_quot.
+ * @thread_has_always_vote_en: Boolean value which indicates that this CPR
+ *			controller should be configured to keep thread vote
+ *			always enabled. This configuration allows the CPR
+ *			controller to not consider MID/DN recommendations from
+ *			other thread when all sensors mapped to a thread
+ *			collapsed.
  *
  * This structure contains both configuration and runtime state data.  The
  * elements cpr_allowed_sw, use_hw_closed_loop, aggr_corner, cpr_enabled,
@@ -879,6 +885,7 @@
 	struct notifier_block	panic_notifier;
 	bool			support_ldo300_vreg;
 	bool			reset_step_quot_loop_en;
+	bool			thread_has_always_vote_en;
 };
 
 /* Used for rounding voltages to the closest physically available set point. */
diff --git a/drivers/regulator/cpr3-util.c b/drivers/regulator/cpr3-util.c
index 39ee3c5..9e138ce 100644
--- a/drivers/regulator/cpr3-util.c
+++ b/drivers/regulator/cpr3-util.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -1241,6 +1241,16 @@
 					"qcom,cpr-reset-step-quot-loop-en");
 
 	/*
+	 * Configure CPR controller to not consider MID/DN recommendations
+	 * from other thread when all sensors mapped to a thread collapsed
+	 * in a multi-thread configuration.
+	 */
+	if (ctrl->thread_count > 1)
+		ctrl->thread_has_always_vote_en
+			= of_property_read_bool(ctrl->dev->of_node,
+					"qcom,cpr-thread-has-always-vote-en");
+
+	/*
 	 * Regulator device handles are not necessary for CPRh controllers
 	 * since communication with the regulators is completely managed
 	 * in hardware.
diff --git a/drivers/regulator/cpr4-apss-regulator.c b/drivers/regulator/cpr4-apss-regulator.c
index d5a0e33..725fc58 100644
--- a/drivers/regulator/cpr4-apss-regulator.c
+++ b/drivers/regulator/cpr4-apss-regulator.c
@@ -36,8 +36,8 @@
 #include "cpr3-regulator.h"
 
 #define MSM8953_APSS_FUSE_CORNERS	4
-#define SDM632_POWER_APSS_FUSE_CORNERS	5
-#define SDM632_PERF_APSS_FUSE_CORNERS	3
+#define SDM632_POWER_APSS_FUSE_CORNERS	4
+#define SDM632_PERF_APSS_FUSE_CORNERS	4
 
 /**
  * struct cpr4_apss_fuses - APSS specific fuse data
@@ -103,27 +103,27 @@
 
 enum cpr4_sdm632_power_apss_fuse_corner {
 	CPR4_SDM632_POWER_APSS_FUSE_CORNER_LOWSVS	= 0,
-	CPR4_SDM632_POWER_APSS_FUSE_CORNER_SVS		= 1,
-	CPR4_SDM632_POWER_APSS_FUSE_CORNER_SVS_L1	= 2,
-	CPR4_SDM632_POWER_APSS_FUSE_CORNER_NOM		= 3,
-	CPR4_SDM632_POWER_APSS_FUSE_CORNER_TURBO_L1	= 4,
+	CPR4_SDM632_POWER_APSS_FUSE_CORNER_SVS_L1	= 1,
+	CPR4_SDM632_POWER_APSS_FUSE_CORNER_NOM		= 2,
+	CPR4_SDM632_POWER_APSS_FUSE_CORNER_TURBO_L1	= 3,
 };
 
 static const char * const cpr4_sdm632_power_apss_fuse_corner_name[] = {
 	[CPR4_SDM632_POWER_APSS_FUSE_CORNER_LOWSVS]	= "LowSVS",
-	[CPR4_SDM632_POWER_APSS_FUSE_CORNER_SVS]	= "SVS",
 	[CPR4_SDM632_POWER_APSS_FUSE_CORNER_SVS_L1]	= "SVS_L1",
 	[CPR4_SDM632_POWER_APSS_FUSE_CORNER_NOM]	= "NOM",
 	[CPR4_SDM632_POWER_APSS_FUSE_CORNER_TURBO_L1]	= "TURBO_L1",
 };
 
 enum cpr4_sdm632_perf_apss_fuse_corner {
-	CPR4_SDM632_PERF_APSS_FUSE_CORNER_SVS_L1	= 0,
-	CPR4_SDM632_PERF_APSS_FUSE_CORNER_NOM		= 1,
-	CPR4_SDM632_PERF_APSS_FUSE_CORNER_TURBO_L1	= 2,
+	CPR4_SDM632_PERF_APSS_FUSE_CORNER_LOWSVS	= 0,
+	CPR4_SDM632_PERF_APSS_FUSE_CORNER_SVS_L1	= 1,
+	CPR4_SDM632_PERF_APSS_FUSE_CORNER_NOM		= 2,
+	CPR4_SDM632_PERF_APSS_FUSE_CORNER_TURBO_L1	= 3,
 };
 
 static const char * const cpr4_sdm632_perf_apss_fuse_corner_name[] = {
+	[CPR4_SDM632_PERF_APSS_FUSE_CORNER_LOWSVS]	= "LowSVS",
 	[CPR4_SDM632_PERF_APSS_FUSE_CORNER_SVS_L1]	= "SVS_L1",
 	[CPR4_SDM632_PERF_APSS_FUSE_CORNER_NOM]		= "NOM",
 	[CPR4_SDM632_PERF_APSS_FUSE_CORNER_TURBO_L1]	= "TURBO_L1",
@@ -229,12 +229,12 @@
 sdm632_apss_ro_sel_param[2][SDM632_POWER_APSS_FUSE_CORNERS][2] = {
 	[CPR4_APSS_POWER_CLUSTER_ID] = {
 		{{73, 28, 31}, {} },
-		{{73, 24, 27}, {} },
 		{{73, 20, 23}, {} },
 		{{73, 16, 19}, {} },
 		{{73, 12, 15}, {} },
 	},
 	[CPR4_APSS_PERF_CLUSTER_ID] = {
+		{{73, 28, 31}, {} },
 		{{73,  8, 11}, {} },
 		{{73,  4,  7}, {} },
 		{{73,  0,  3}, {} },
@@ -245,12 +245,12 @@
 sdm632_apss_init_voltage_param[2][SDM632_POWER_APSS_FUSE_CORNERS][2] = {
 	[CPR4_APSS_POWER_CLUSTER_ID] = {
 		{{74, 18, 23}, {} },
-		{{74, 12, 17}, {} },
 		{{71, 24, 29}, {} },
 		{{74,  6, 11}, {} },
 		{{74,  0,  5}, {} },
 	},
 	[CPR4_APSS_PERF_CLUSTER_ID] = {
+		{{74, 18, 23}, {} },
 		{{71, 18, 23}, {} },
 		{{71, 12, 17}, {} },
 		{{71,  6, 11}, {} },
@@ -261,12 +261,12 @@
 sdm632_apss_target_quot_param[2][SDM632_POWER_APSS_FUSE_CORNERS][2] = {
 	[CPR4_APSS_POWER_CLUSTER_ID] = {
 		{{75, 44, 55}, {} },
-		{{75, 32, 43}, {} },
 		{{72, 44, 55}, {} },
 		{{75, 20, 31}, {} },
 		{{75,  8, 19}, {} },
 	},
 	[CPR4_APSS_PERF_CLUSTER_ID] = {
+		{{75, 44, 55}, {} },
 		{{72, 32, 43}, {} },
 		{{72, 20, 31}, {} },
 		{{72,  8, 19}, {} },
@@ -277,13 +277,13 @@
 sdm632_apss_quot_offset_param[2][SDM632_POWER_APSS_FUSE_CORNERS][2] = {
 	[CPR4_APSS_POWER_CLUSTER_ID] = {
 		{{} },
-		{{74, 39, 45}, {} },
 		{{71, 46, 52}, {} },
 		{{74, 32, 38}, {} },
 		{{74, 24, 30}, {} },
 	},
 	[CPR4_APSS_PERF_CLUSTER_ID] = {
 		{{} },
+		{{74, 39, 45}, {} },
 		{{71, 39, 45}, {} },
 		{{71, 32, 38}, {} },
 	},
@@ -322,12 +322,12 @@
 sdm632_apss_fuse_ref_volt[2][SDM632_POWER_APSS_FUSE_CORNERS] = {
 	[CPR4_APSS_POWER_CLUSTER_ID] = {
 		645000,
-		720000,
 		790000,
 		865000,
 		1065000,
 	},
 	[CPR4_APSS_PERF_CLUSTER_ID] = {
+		645000,
 		790000,
 		865000,
 		1065000,
@@ -1025,7 +1025,7 @@
 		} else {
 			corner_name = cpr4_sdm632_perf_apss_fuse_corner_name;
 			lowest_fuse_corner =
-				CPR4_SDM632_PERF_APSS_FUSE_CORNER_SVS_L1;
+				CPR4_SDM632_PERF_APSS_FUSE_CORNER_LOWSVS;
 			highest_fuse_corner =
 				CPR4_SDM632_PERF_APSS_FUSE_CORNER_TURBO_L1;
 		}
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 99b5e35..162afcc 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -227,6 +227,13 @@
 			missing = year;
 	}
 
+	/* Can't proceed if alarm is still invalid after replacing
+	 * missing fields.
+	 */
+	err = rtc_valid_tm(&alarm->time);
+	if (err)
+		goto done;
+
 	/* with luck, no rollover is needed */
 	t_now = rtc_tm_to_time64(&now);
 	t_alm = rtc_tm_to_time64(&alarm->time);
@@ -278,9 +285,9 @@
 		dev_warn(&rtc->dev, "alarm rollover not handled\n");
 	}
 
-done:
 	err = rtc_valid_tm(&alarm->time);
 
+done:
 	if (err) {
 		dev_warn(&rtc->dev, "invalid alarm value: %d-%d-%d %d:%d:%d\n",
 			alarm->time.tm_year + 1900, alarm->time.tm_mon + 1,
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index 58698d2..c4ca6a3 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -168,6 +168,7 @@
 /* Sets the given date and time to the real time clock. */
 static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm)
 {
+	struct m41t80_data *clientdata = i2c_get_clientdata(client);
 	unsigned char buf[8];
 	int err, flags;
 
@@ -183,6 +184,17 @@
 	buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year - 100);
 	buf[M41T80_REG_WDAY] = tm->tm_wday;
 
+	/* If the square wave output is controlled in the weekday register */
+	if (clientdata->features & M41T80_FEATURE_SQ_ALT) {
+		int val;
+
+		val = i2c_smbus_read_byte_data(client, M41T80_REG_WDAY);
+		if (val < 0)
+			return val;
+
+		buf[M41T80_REG_WDAY] |= (val & 0xf0);
+	}
+
 	err = i2c_smbus_write_i2c_block_data(client, M41T80_REG_SSEC,
 					     sizeof(buf), buf);
 	if (err < 0) {
diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c
index e4324dc..aa53fce 100644
--- a/drivers/rtc/rtc-opal.c
+++ b/drivers/rtc/rtc-opal.c
@@ -150,6 +150,16 @@
 
 	y_m_d = be32_to_cpu(__y_m_d);
 	h_m_s_ms = ((u64)be32_to_cpu(__h_m) << 32);
+
+	/* check if no alarm is set */
+	if (y_m_d == 0 && h_m_s_ms == 0) {
+		pr_debug("No alarm is set\n");
+		rc = -ENOENT;
+		goto exit;
+	} else {
+		pr_debug("Alarm set to %x %llx\n", y_m_d, h_m_s_ms);
+	}
+
 	opal_to_tm(y_m_d, h_m_s_ms, &alarm->time);
 
 exit:
diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c
index 0f11c2a..a753ef9 100644
--- a/drivers/rtc/rtc-snvs.c
+++ b/drivers/rtc/rtc-snvs.c
@@ -257,7 +257,7 @@
 		of_property_read_u32(pdev->dev.of_node, "offset", &data->offset);
 	}
 
-	if (!data->regmap) {
+	if (IS_ERR(data->regmap)) {
 		dev_err(&pdev->dev, "Can't find snvs syscon\n");
 		return -ENODEV;
 	}
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 5ecd408..0da2465 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -1950,8 +1950,12 @@
 {
 	int mask = ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM);
 
-	if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) {
-		/* dasd is being set offline. */
+	if (test_bit(DASD_FLAG_OFFLINE, &device->flags) &&
+	    !test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) {
+		/*
+		 * dasd is being set offline
+		 * but it is no safe offline where we have to allow I/O
+		 */
 		return 1;
 	}
 	if (device->stopped) {
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 71bf9bd..66e9bb0 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -126,7 +126,7 @@
 static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state,
 			int start, int count, int auto_ack)
 {
-	int rc, tmp_count = count, tmp_start = start, nr = q->nr, retried = 0;
+	int rc, tmp_count = count, tmp_start = start, nr = q->nr;
 	unsigned int ccq = 0;
 
 	qperf_inc(q, eqbs);
@@ -149,14 +149,7 @@
 		qperf_inc(q, eqbs_partial);
 		DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS part:%02x",
 			tmp_count);
-		/*
-		 * Retry once, if that fails bail out and process the
-		 * extracted buffers before trying again.
-		 */
-		if (!retried++)
-			goto again;
-		else
-			return count - tmp_count;
+		return count - tmp_count;
 	}
 
 	DBF_ERROR("%4x EQBS ERROR", SCH_NO(q));
@@ -212,7 +205,10 @@
 	return 0;
 }
 
-/* returns number of examined buffers and their common state in *state */
+/*
+ * Returns number of examined buffers and their common state in *state.
+ * Requested number of buffers-to-examine must be > 0.
+ */
 static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr,
 				 unsigned char *state, unsigned int count,
 				 int auto_ack, int merge_pending)
@@ -223,17 +219,23 @@
 	if (is_qebsm(q))
 		return qdio_do_eqbs(q, state, bufnr, count, auto_ack);
 
-	for (i = 0; i < count; i++) {
-		if (!__state) {
-			__state = q->slsb.val[bufnr];
-			if (merge_pending && __state == SLSB_P_OUTPUT_PENDING)
-				__state = SLSB_P_OUTPUT_EMPTY;
-		} else if (merge_pending) {
-			if ((q->slsb.val[bufnr] & __state) != __state)
-				break;
-		} else if (q->slsb.val[bufnr] != __state)
-			break;
+	/* get initial state: */
+	__state = q->slsb.val[bufnr];
+	if (merge_pending && __state == SLSB_P_OUTPUT_PENDING)
+		__state = SLSB_P_OUTPUT_EMPTY;
+
+	for (i = 1; i < count; i++) {
 		bufnr = next_buf(bufnr);
+
+		/* merge PENDING into EMPTY: */
+		if (merge_pending &&
+		    q->slsb.val[bufnr] == SLSB_P_OUTPUT_PENDING &&
+		    __state == SLSB_P_OUTPUT_EMPTY)
+			continue;
+
+		/* stop if next state differs from initial state: */
+		if (q->slsb.val[bufnr] != __state)
+			break;
 	}
 	*state = __state;
 	return i;
diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h
index fdd4eb4..e58786f 100644
--- a/drivers/scsi/bnx2fc/bnx2fc.h
+++ b/drivers/scsi/bnx2fc/bnx2fc.h
@@ -191,6 +191,7 @@
 	struct bnx2fc_cmd_mgr *cmd_mgr;
 	spinlock_t hba_lock;
 	struct mutex hba_mutex;
+	struct mutex hba_stats_mutex;
 	unsigned long adapter_state;
 		#define ADAPTER_STATE_UP		0
 		#define ADAPTER_STATE_GOING_DOWN	1
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index f9ddb61..bee7d37 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -670,15 +670,17 @@
 	if (!fw_stats)
 		return NULL;
 
+	mutex_lock(&hba->hba_stats_mutex);
+
 	bnx2fc_stats = fc_get_host_stats(shost);
 
 	init_completion(&hba->stat_req_done);
 	if (bnx2fc_send_stat_req(hba))
-		return bnx2fc_stats;
+		goto unlock_stats_mutex;
 	rc = wait_for_completion_timeout(&hba->stat_req_done, (2 * HZ));
 	if (!rc) {
 		BNX2FC_HBA_DBG(lport, "FW stat req timed out\n");
-		return bnx2fc_stats;
+		goto unlock_stats_mutex;
 	}
 	BNX2FC_STATS(hba, rx_stat2, fc_crc_cnt);
 	bnx2fc_stats->invalid_crc_count += hba->bfw_stats.fc_crc_cnt;
@@ -700,6 +702,9 @@
 
 	memcpy(&hba->prev_stats, hba->stats_buffer,
 	       sizeof(struct fcoe_statistics_params));
+
+unlock_stats_mutex:
+	mutex_unlock(&hba->hba_stats_mutex);
 	return bnx2fc_stats;
 }
 
@@ -1348,6 +1353,7 @@
 	}
 	spin_lock_init(&hba->hba_lock);
 	mutex_init(&hba->hba_mutex);
+	mutex_init(&hba->hba_stats_mutex);
 
 	hba->cnic = cnic;
 
diff --git a/drivers/scsi/csiostor/csio_hw.c b/drivers/scsi/csiostor/csio_hw.c
index 622bdab..dab195f 100644
--- a/drivers/scsi/csiostor/csio_hw.c
+++ b/drivers/scsi/csiostor/csio_hw.c
@@ -1769,7 +1769,6 @@
 		goto bye;
 	}
 
-	mempool_free(mbp, hw->mb_mempool);
 	if (finicsum != cfcsum) {
 		csio_warn(hw,
 		      "Config File checksum mismatch: csum=%#x, computed=%#x\n",
@@ -1780,6 +1779,10 @@
 	rv = csio_hw_validate_caps(hw, mbp);
 	if (rv != 0)
 		goto bye;
+
+	mempool_free(mbp, hw->mb_mempool);
+	mbp = NULL;
+
 	/*
 	 * Note that we're operating with parameters
 	 * not supplied by the driver, rather than from hard-wired
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 4abd3fc..c2b6829 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1695,6 +1695,15 @@
 		 */
 		switch (session->state) {
 		case ISCSI_STATE_FAILED:
+			/*
+			 * cmds should fail during shutdown, if the session
+			 * state is bad, allowing completion to happen
+			 */
+			if (unlikely(system_state != SYSTEM_RUNNING)) {
+				reason = FAILURE_SESSION_FAILED;
+				sc->result = DID_NO_CONNECT << 16;
+				break;
+			}
 		case ISCSI_STATE_IN_RECOVERY:
 			reason = FAILURE_SESSION_IN_RECOVERY;
 			sc->result = DID_IMM_RETRY << 16;
@@ -1980,6 +1989,19 @@
 
 	if (session->state != ISCSI_STATE_LOGGED_IN) {
 		/*
+		 * During shutdown, if session is prematurely disconnected,
+		 * recovery won't happen and there will be hung cmds. Not
+		 * handling cmds would trigger EH, also bad in this case.
+		 * Instead, handle cmd, allow completion to happen and let
+		 * upper layer to deal with the result.
+		 */
+		if (unlikely(system_state != SYSTEM_RUNNING)) {
+			sc->result = DID_NO_CONNECT << 16;
+			ISCSI_DBG_EH(session, "sc on shutdown, handled\n");
+			rc = BLK_EH_HANDLED;
+			goto done;
+		}
+		/*
 		 * We are probably in the middle of iscsi recovery so let
 		 * that complete and handle the error.
 		 */
@@ -2083,7 +2105,7 @@
 		task->last_timeout = jiffies;
 	spin_unlock(&session->frwd_lock);
 	ISCSI_DBG_EH(session, "return %s\n", rc == BLK_EH_RESET_TIMER ?
-		     "timer reset" : "nh");
+		     "timer reset" : "shutdown or nh");
 	return rc;
 }
 
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 022bb6e..12886f9 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -282,6 +282,7 @@
 	phy->phy->minimum_linkrate = dr->pmin_linkrate;
 	phy->phy->maximum_linkrate = dr->pmax_linkrate;
 	phy->phy->negotiated_linkrate = phy->linkrate;
+	phy->phy->enabled = (phy->linkrate != SAS_PHY_DISABLED);
 
  skip:
 	if (new_phy)
@@ -675,7 +676,7 @@
 	res = smp_execute_task(dev, req, RPEL_REQ_SIZE,
 			            resp, RPEL_RESP_SIZE);
 
-	if (!res)
+	if (res)
 		goto out;
 
 	phy->invalid_dword_count = scsi_to_u32(&resp[12]);
@@ -684,6 +685,7 @@
 	phy->phy_reset_problem_count = scsi_to_u32(&resp[24]);
 
  out:
+	kfree(req);
 	kfree(resp);
 	return res;
 
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index 7568e06..44da9d8 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -4065,19 +4065,6 @@
 		return 0;
 	}
 
-	/*
-	 * Bug work around for firmware SATL handling.  The loop
-	 * is based on atomic operations and ensures consistency
-	 * since we're lockless at this point
-	 */
-	do {
-		if (test_bit(0, &sas_device_priv_data->ata_command_pending)) {
-			scmd->result = SAM_STAT_BUSY;
-			scmd->scsi_done(scmd);
-			return 0;
-		}
-	} while (_scsih_set_satl_pending(scmd, true));
-
 	sas_target_priv_data = sas_device_priv_data->sas_target;
 
 	/* invalid device handle */
@@ -4103,6 +4090,19 @@
 	    sas_device_priv_data->block)
 		return SCSI_MLQUEUE_DEVICE_BUSY;
 
+	/*
+	 * Bug work around for firmware SATL handling.  The loop
+	 * is based on atomic operations and ensures consistency
+	 * since we're lockless at this point
+	 */
+	do {
+		if (test_bit(0, &sas_device_priv_data->ata_command_pending)) {
+			scmd->result = SAM_STAT_BUSY;
+			scmd->scsi_done(scmd);
+			return 0;
+		}
+	} while (_scsih_set_satl_pending(scmd, true));
+
 	if (scmd->sc_data_direction == DMA_FROM_DEVICE)
 		mpi_control = MPI2_SCSIIO_CONTROL_READ;
 	else if (scmd->sc_data_direction == DMA_TO_DEVICE)
@@ -4124,6 +4124,7 @@
 	if (!smid) {
 		pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
 		    ioc->name, __func__);
+		_scsih_set_satl_pending(scmd, false);
 		goto out;
 	}
 	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
@@ -4154,6 +4155,7 @@
 	if (mpi_request->DataLength) {
 		if (ioc->build_sg_scmd(ioc, scmd, smid)) {
 			mpt3sas_base_free_smid(ioc, smid);
+			_scsih_set_satl_pending(scmd, false);
 			goto out;
 		}
 	} else
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index 8f4adc1..cbc8e93 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -819,6 +819,7 @@
 	.change_queue_depth = virtscsi_change_queue_depth,
 	.eh_abort_handler = virtscsi_abort,
 	.eh_device_reset_handler = virtscsi_device_reset,
+	.slave_alloc = virtscsi_device_alloc,
 
 	.can_queue = 1024,
 	.dma_boundary = UINT_MAX,
diff --git a/drivers/soc/qcom/dcc.c b/drivers/soc/qcom/dcc.c
index a687286..bef0757 100644
--- a/drivers/soc/qcom/dcc.c
+++ b/drivers/soc/qcom/dcc.c
@@ -731,7 +731,8 @@
 
 	mutex_lock(&drvdata->mutex);
 
-	if (!len) {
+	/* Check the len to avoid allocate huge memory */
+	if (!len || len > (drvdata->ram_size / 8)) {
 		dev_err(drvdata->dev, "DCC: Invalid length!\n");
 		ret = -EINVAL;
 		goto err;
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 683b074..c254299 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -2453,6 +2453,9 @@
 	if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state))
 		goto out;
 
+	if (priv->force_err_fatal)
+		ICNSS_ASSERT(0);
+
 	if (priv->early_crash_ind) {
 		icnss_pr_dbg("PD Down ignored as early indication is processed: %d, state: 0x%lx\n",
 			     event_data->crashed, priv->state);
@@ -2467,9 +2470,6 @@
 		goto out;
 	}
 
-	if (priv->force_err_fatal)
-		ICNSS_ASSERT(0);
-
 	icnss_fw_crashed(priv, event_data);
 
 out:
diff --git a/drivers/soc/qcom/microdump_collector.c b/drivers/soc/qcom/microdump_collector.c
index 4a22b4d..6e9da60 100644
--- a/drivers/soc/qcom/microdump_collector.c
+++ b/drivers/soc/qcom/microdump_collector.c
@@ -48,9 +48,9 @@
 		crash_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size_reason
 				, 0, SMEM_ANY_HOST_FLAG);
 		if (IS_ERR_OR_NULL(crash_reason)) {
-			pr_err("%s: Error in getting SMEM_reason pointer\n",
-				__func__);
-			return -ENODEV;
+			pr_info("%s: smem %d not available\n",
+				__func__, SMEM_SSR_REASON_MSS0);
+			goto out;
 		}
 
 		segment[0].v_address = crash_reason;
@@ -58,9 +58,9 @@
 
 		crash_data = smem_get_entry(smem_id, &size_data, SMEM_MODEM, 0);
 		if (IS_ERR_OR_NULL(crash_data)) {
-			pr_err("%s: Error in getting SMEM_data pointer\n",
-				__func__);
-			return -ENODEV;
+			pr_info("%s: smem %d not available\n ",
+				__func__, smem_id);
+			goto out;
 		}
 
 		segment[1].v_address = crash_data;
@@ -68,10 +68,11 @@
 
 		ret = do_ramdump(drv->microdump_dev, segment, 2);
 		if (ret)
-			pr_err("%s: do_ramdump() failed\n", __func__);
+			pr_info("%s: do_ramdump() failed\n", __func__);
 	}
 
-	return ret;
+out:
+	return NOTIFY_OK;
 }
 
 static int microdump_modem_ssr_register_notifier(struct microdump_data *drv)
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index 360dbcf..8776379 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -263,6 +263,7 @@
 	struct pil_priv *priv = desc->priv;
 	struct pil_seg *seg;
 	int count = 0, ret;
+	u32 encryption_status = 0;
 
 	if (desc->minidump_ss) {
 		pr_info("Minidump : md_ss_toc->md_ss_toc_init is 0x%x\n",
@@ -280,12 +281,14 @@
 		 * Collect minidump if SS ToC is valid and segment table
 		 * is initialized in memory and encryption status is set.
 		 */
+		encryption_status = desc->minidump_ss->encryption_status;
+
 		if ((desc->minidump_ss->md_ss_smem_regions_baseptr != 0) &&
 			(desc->minidump_ss->md_ss_toc_init == true) &&
 			(desc->minidump_ss->md_ss_enable_status ==
 				MD_SS_ENABLED)) {
-			if (desc->minidump_ss->encryption_status ==
-				MD_SS_ENCR_DONE) {
+			if (encryption_status == MD_SS_ENCR_DONE ||
+				encryption_status == MD_SS_ENCR_NOTREQ) {
 				pr_info("Minidump : Dumping for %s\n",
 					desc->name);
 				return pil_do_minidump(desc, minidump_dev);
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index 6283477..2a46d0b 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -797,14 +797,18 @@
 int pil_mss_debug_reset(struct pil_desc *pil)
 {
 	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+	u32 encryption_status;
 	int ret;
 
+
 	if (!pil->minidump_ss)
 		return 0;
-	if (pil->minidump_ss) {
-		if (pil->minidump_ss->md_ss_enable_status != MD_SS_ENABLED)
-			return 0;
-	}
+
+	encryption_status = pil->minidump_ss->encryption_status;
+
+	if ((pil->minidump_ss->md_ss_enable_status != MD_SS_ENABLED) ||
+		encryption_status == MD_SS_ENCR_NOTREQ)
+		return 0;
 
 	/*
 	 * Bring subsystem out of reset and enable required
@@ -836,7 +840,7 @@
 	 * complete before returning
 	 */
 	pr_info("Minidump: waiting encryption to complete\n");
-	msleep(10000);
+	msleep(13000);
 	if (pil->minidump_ss) {
 		writel_relaxed(0x2, drv->reg_base + QDSP6SS_NMI_CFG);
 		/* Let write complete before proceeding */
diff --git a/drivers/soc/qcom/qdss_bridge.c b/drivers/soc/qcom/qdss_bridge.c
index 8668155..fb70a07 100644
--- a/drivers/soc/qcom/qdss_bridge.c
+++ b/drivers/soc/qcom/qdss_bridge.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -245,7 +245,7 @@
 
 	switch (event) {
 	case USB_QDSS_CONNECT:
-		usb_qdss_alloc_req(drvdata->usb_ch, poolsize, 0);
+		usb_qdss_alloc_req(ch, poolsize, 0);
 		mhi_queue_read(drvdata);
 		break;
 
diff --git a/drivers/soc/qcom/wcnss/wcnss_vreg.c b/drivers/soc/qcom/wcnss/wcnss_vreg.c
index 9d24ce1..1e61250 100644
--- a/drivers/soc/qcom/wcnss/wcnss_vreg.c
+++ b/drivers/soc/qcom/wcnss/wcnss_vreg.c
@@ -206,7 +206,7 @@
 					 voltage_levels,
 					 ARRAY_SIZE(voltage_levels));
 	if (ret) {
-		dev_err(dev, "error reading %s property\n", vreg_name);
+		wcnss_log(ERR, "error reading %s property\n", vreg_name);
 		return ret;
 	}
 
@@ -217,7 +217,8 @@
 	ret = of_property_read_u32(dev->of_node, current_vreg_name,
 				   &current_vreg);
 	if (ret) {
-		dev_err(dev, "error reading %s property\n", current_vreg_name);
+		wcnss_log(ERR, "error reading %s property\n",
+			  current_vreg_name);
 		return ret;
 	}
 
@@ -240,12 +241,14 @@
 		if (IS_ERR(pronto_vregs[vreg_i].regulator)) {
 			if (pronto_vregs[vreg_i].required) {
 				rc = PTR_ERR(pronto_vregs[vreg_i].regulator);
-				dev_err(dev, "regulator get of %s failed (%d)\n",
+				wcnss_log(ERR,
+					"regulator get of %s failed (%d)\n",
 					pronto_vregs[vreg_i].name, rc);
 				return rc;
 			} else {
-				dev_dbg(dev, "Skip optional regulator configuration: %s\n",
-					pronto_vregs[vreg_i].name);
+				wcnss_log(DBG,
+				"Skip optional regulator configuration: %s\n",
+				pronto_vregs[vreg_i].name);
 				continue;
 			}
 		}
@@ -255,7 +258,8 @@
 					       pronto_vregs[vreg_i].volt,
 					       wlan_config->pronto_vlevel);
 		if (rc) {
-			dev_err(dev, "error reading voltage-level property\n");
+			wcnss_log(ERR,
+				  "error reading voltage-level property\n");
 			return rc;
 		}
 		pronto_vregs[vreg_i].state |= VREG_GET_REGULATOR_MASK;
@@ -269,12 +273,14 @@
 		if (IS_ERR(iris_vregs[vreg_i].regulator)) {
 			if (iris_vregs[vreg_i].required) {
 				rc = PTR_ERR(iris_vregs[vreg_i].regulator);
-				dev_err(dev, "regulator get of %s failed (%d)\n",
+				wcnss_log(ERR,
+					"regulator get of %s failed (%d)\n",
 					iris_vregs[vreg_i].name, rc);
 				return rc;
 			} else {
-				dev_dbg(dev, "Skip optional regulator configuration: %s\n",
-					iris_vregs[vreg_i].name);
+				wcnss_log(DBG,
+				"Skip optional regulator configuration: %s\n",
+				iris_vregs[vreg_i].name);
 				continue;
 			}
 		}
@@ -284,7 +290,8 @@
 					       iris_vregs[vreg_i].volt,
 					       wlan_config->iris_vlevel);
 		if (rc) {
-			dev_err(dev, "error reading voltage-level property\n");
+			wcnss_log(ERR,
+				  "error reading voltage-level property\n");
 			return rc;
 		}
 		iris_vregs[vreg_i].state |= VREG_GET_REGULATOR_MASK;
@@ -334,7 +341,7 @@
 
 		clk = clk_get(dev, "xo");
 		if (IS_ERR(clk)) {
-			pr_err("Couldn't get xo clock\n");
+			wcnss_log(ERR, "Couldn't get xo clock\n");
 			return PTR_ERR(clk);
 		}
 
@@ -344,7 +351,7 @@
 
 		clk = clk_get(dev, "cxo");
 		if (IS_ERR(clk)) {
-			pr_err("Couldn't get cxo clock\n");
+			wcnss_log(ERR, "Couldn't get cxo clock\n");
 			return PTR_ERR(clk);
 		}
 	}
@@ -352,21 +359,21 @@
 	if (on) {
 		msm_wcnss_base = cfg->msm_wcnss_base;
 		if (!msm_wcnss_base) {
-			pr_err("ioremap wcnss physical failed\n");
+			wcnss_log(ERR, "ioremap wcnss physical failed\n");
 			goto fail;
 		}
 
 		/* Enable IRIS XO */
 		rc = clk_prepare_enable(clk);
 		if (rc) {
-			pr_err("clk enable failed\n");
+			wcnss_log(ERR, "clk enable failed\n");
 			goto fail;
 		}
 
 		/* NV bit is set to indicate that platform driver is capable
 		 * of doing NV download.
 		 */
-		pr_debug("wcnss: Indicate NV bin download\n");
+		wcnss_log(DBG, "Indicate NV bin download\n");
 		spare_reg = msm_wcnss_base + spare_offset;
 		reg = readl_relaxed(spare_reg);
 		reg |= NVBIN_DLND_BIT;
@@ -403,10 +410,11 @@
 					cpu_relax();
 
 				iris_reg = readl_relaxed(iris_read_reg);
-				pr_info("wcnss: IRIS Reg: %08x\n", iris_reg);
+				wcnss_log(INFO, "IRIS Reg: %08x\n", iris_reg);
 
 				if (validate_iris_chip_id(iris_reg) && i >= 4) {
-					pr_info("wcnss: IRIS Card absent/invalid\n");
+					wcnss_log(INFO,
+						"IRIS Card absent/invalid\n");
 					auto_detect = WCNSS_XO_INVALID;
 					/* Reset iris read bit */
 					reg &= ~WCNSS_PMU_CFG_IRIS_XO_READ;
@@ -416,7 +424,8 @@
 					reg &= ~(WCNSS_PMU_CFG_IRIS_XO_MODE);
 					goto xo_configure;
 				} else if (!validate_iris_chip_id(iris_reg)) {
-					pr_debug("wcnss: IRIS Card is present\n");
+					wcnss_log(DBG,
+						  "IRIS Card is present\n");
 					break;
 				}
 				reg &= ~WCNSS_PMU_CFG_IRIS_XO_READ;
@@ -472,13 +481,13 @@
 		    auto_detect ==  WCNSS_XO_19MHZ) {
 			clk_rf = clk_get(dev, "rf_clk");
 			if (IS_ERR(clk_rf)) {
-				pr_err("Couldn't get rf_clk\n");
+				wcnss_log(ERR, "Couldn't get rf_clk\n");
 				goto fail;
 			}
 
 			rc = clk_prepare_enable(clk_rf);
 			if (rc) {
-				pr_err("clk_rf enable failed\n");
+				wcnss_log(ERR, "clk_rf enable failed\n");
 				goto fail;
 			}
 			if (iris_xo_set)
@@ -489,7 +498,7 @@
 		    auto_detect ==  WCNSS_XO_19MHZ) {
 		clk_rf = clk_get(dev, "rf_clk");
 		if (IS_ERR(clk_rf)) {
-			pr_err("Couldn't get rf_clk\n");
+			wcnss_log(ERR, "Couldn't get rf_clk\n");
 			goto fail;
 		}
 		clk_disable_unprepare(clk_rf);
@@ -517,7 +526,7 @@
 	cfg = wcnss_get_wlan_config();
 
 	if (!cfg) {
-		pr_err("Failed to get WLAN configuration\n");
+		wcnss_log(ERR, "Failed to get WLAN configuration\n");
 		return;
 	}
 
@@ -530,7 +539,8 @@
 		if (regulators[i].state & VREG_OPTIMUM_MODE_MASK) {
 			rc = regulator_set_load(regulators[i].regulator, 0);
 			if (rc < 0) {
-				pr_err("regulator set load(%s) failed (%d)\n",
+				wcnss_log(ERR,
+					"regulator set load(%s) failed (%d)\n",
 				       regulators[i].name, rc);
 			}
 		}
@@ -553,15 +563,16 @@
 						   max_voltage);
 
 			if (rc)
-				pr_err("regulator_set_voltage(%s) failed (%d)\n",
-				       regulators[i].name, rc);
+				wcnss_log(ERR,
+				"regulator_set_voltage(%s) failed (%d)\n",
+				regulators[i].name, rc);
 		}
 
 		/* Disable regulator */
 		if (regulators[i].state & VREG_ENABLE_MASK) {
 			rc = regulator_disable(regulators[i].regulator);
 			if (rc < 0)
-				pr_err("vreg %s disable failed (%d)\n",
+				wcnss_log(ERR, "vreg %s disable failed (%d)\n",
 				       regulators[i].name, rc);
 		}
 	}
@@ -579,7 +590,7 @@
 	cfg = wcnss_get_wlan_config();
 
 	if (!cfg) {
-		pr_err("Failed to get WLAN configuration\n");
+		wcnss_log(ERR, "Failed to get WLAN configuration\n");
 		return -EINVAL;
 	}
 
@@ -608,7 +619,8 @@
 						   max_voltage);
 
 			if (rc) {
-				pr_err("regulator_set_voltage(%s) failed (%d)\n",
+				wcnss_log(ERR,
+				"regulator_set_voltage(%s) failed (%d)\n",
 				       regulators[i].name, rc);
 				goto fail;
 			}
@@ -620,7 +632,8 @@
 			rc = regulator_set_load(regulators[i].regulator,
 						voltage_level[i].uA_load);
 			if (rc < 0) {
-				pr_err("regulator set load(%s) failed (%d)\n",
+				wcnss_log(ERR,
+				"regulator set load(%s) failed (%d)\n",
 				       regulators[i].name, rc);
 				goto fail;
 			}
@@ -630,7 +643,7 @@
 		/* Enable the regulator */
 		rc = regulator_enable(regulators[i].regulator);
 		if (rc) {
-			pr_err("vreg %s enable failed (%d)\n",
+			wcnss_log(ERR, "vreg %s enable failed (%d)\n",
 			       regulators[i].name, rc);
 			goto fail;
 		}
@@ -653,7 +666,7 @@
 				cfg->iris_vlevel);
 		break;
 	default:
-		pr_err("%s invalid hardware %d\n", __func__, hw_type);
+		wcnss_log(ERR, "%s invalid hardware %d\n", __func__, hw_type);
 	}
 }
 
@@ -669,7 +682,7 @@
 				     cfg->iris_vlevel);
 		break;
 	default:
-		pr_err("%s invalid hardware %d\n", __func__, hw_type);
+		wcnss_log(ERR, "%s invalid hardware %d\n", __func__, hw_type);
 	}
 	return ret;
 }
@@ -683,7 +696,7 @@
 				ARRAY_SIZE(pronto_vregs), cfg->pronto_vlevel);
 		break;
 	default:
-		pr_err("%s invalid hardware %d\n", __func__, hw_type);
+		wcnss_log(ERR, "%s invalid hardware %d\n", __func__, hw_type);
 	}
 }
 
@@ -700,7 +713,7 @@
 				     cfg->pronto_vlevel);
 		break;
 	default:
-		pr_err("%s invalid hardware %d\n", __func__, hw_type);
+		wcnss_log(ERR, "%s invalid hardware %d\n", __func__, hw_type);
 	}
 
 	return ret;
diff --git a/drivers/soc/qcom/wcnss/wcnss_wlan.c b/drivers/soc/qcom/wcnss/wcnss_wlan.c
index c3fb30b..08bd78b 100644
--- a/drivers/soc/qcom/wcnss/wcnss_wlan.c
+++ b/drivers/soc/qcom/wcnss/wcnss_wlan.c
@@ -38,6 +38,7 @@
 #include <linux/pm_qos.h>
 #include <linux/bitops.h>
 #include <linux/cdev.h>
+#include <linux/ipc_logging.h>
 #include <soc/qcom/socinfo.h>
 
 #include <soc/qcom/subsystem_restart.h>
@@ -452,6 +453,53 @@
 	struct cdev ctrl_dev, node_dev;
 } *penv = NULL;
 
+static void *wcnss_ipc_log;
+
+#define IPC_NUM_LOG_PAGES	12
+#define wcnss_ipc_log_string(_x...) do {		\
+	if (wcnss_ipc_log)				\
+		ipc_log_string(wcnss_ipc_log, _x);	\
+	} while (0)
+
+void wcnss_log(enum wcnss_log_type type, const char *_fmt, ...)
+{
+	struct va_format vaf = {
+		.fmt = _fmt,
+	};
+	va_list args;
+
+	va_start(args, _fmt);
+	vaf.va = &args;
+	switch (type) {
+	case ERR:
+		pr_err("wcnss: %pV", &vaf);
+		wcnss_ipc_log_string("wcnss: %pV", &vaf);
+		break;
+	case WARN:
+		pr_warn("wcnss: %pV", &vaf);
+		wcnss_ipc_log_string("wcnss: %pV", &vaf);
+		break;
+	case INFO:
+		pr_info("wcnss: %pV", &vaf);
+		wcnss_ipc_log_string("wcnss: %pV", &vaf);
+		break;
+	case DBG:
+#if defined(CONFIG_DYNAMIC_DEBUG)
+		pr_debug("wcnss: %pV", &vaf);
+		wcnss_ipc_log_string("wcnss: %pV", &vaf);
+#elif defined(DEBUG)
+		pr_debug("wcnss: %pV", &vaf);
+		wcnss_ipc_log_string("wcnss: %pV", &vaf);
+#else
+		pr_devel("wcnss: %pV", &vaf);
+		wcnss_ipc_log_string("wcnss: %pV", &vaf);
+#endif
+		break;
+	}
+	va_end(args);
+}
+EXPORT_SYMBOL(wcnss_log);
+
 static ssize_t wcnss_wlan_macaddr_store(struct device *dev,
 					struct device_attribute *attr,
 					const char *buf, size_t count)
@@ -463,14 +511,14 @@
 		return -ENODEV;
 
 	if (strlen(buf) != WCNSS_USER_MAC_ADDR_LENGTH) {
-		dev_err(dev, "%s: Invalid MAC addr length\n", __func__);
+		wcnss_log(ERR, "%s: Invalid MAC addr length\n", __func__);
 		return -EINVAL;
 	}
 
 	if (sscanf(buf, MAC_ADDRESS_STR, &mac_addr[0], &mac_addr[1],
 		   &mac_addr[2], &mac_addr[3], &mac_addr[4],
 		   &mac_addr[5]) != WLAN_MAC_ADDR_SIZE) {
-		pr_err("%s: Failed to Copy MAC\n", __func__);
+		wcnss_log(ERR, "%s: Failed to Copy MAC\n", __func__);
 		return -EINVAL;
 	}
 
@@ -479,7 +527,7 @@
 		       (char *)&mac_addr[index], sizeof(char));
 	}
 
-	pr_info("%s: Write MAC Addr:" MAC_ADDRESS_STR "\n", __func__,
+	wcnss_log(INFO, "%s: Write MAC Addr:" MAC_ADDRESS_STR "\n", __func__,
 		penv->wlan_nv_mac_addr[0], penv->wlan_nv_mac_addr[1],
 		penv->wlan_nv_mac_addr[2], penv->wlan_nv_mac_addr[3],
 		penv->wlan_nv_mac_addr[4], penv->wlan_nv_mac_addr[5]);
@@ -555,19 +603,19 @@
 
 	ccu_reg = penv->riva_ccu_base + CCU_RIVA_INVALID_ADDR_OFFSET;
 	reg = readl_relaxed(ccu_reg);
-	pr_info_ratelimited("%s: CCU_CCPU_INVALID_ADDR %08x\n", __func__, reg);
+	wcnss_log(INFO, "%s: CCU_CCPU_INVALID_ADDR %08x\n", __func__, reg);
 
 	ccu_reg = penv->riva_ccu_base + CCU_RIVA_LAST_ADDR0_OFFSET;
 	reg = readl_relaxed(ccu_reg);
-	pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR0 %08x\n", __func__, reg);
+	wcnss_log(INFO, "%s: CCU_CCPU_LAST_ADDR0 %08x\n", __func__, reg);
 
 	ccu_reg = penv->riva_ccu_base + CCU_RIVA_LAST_ADDR1_OFFSET;
 	reg = readl_relaxed(ccu_reg);
-	pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR1 %08x\n", __func__, reg);
+	wcnss_log(INFO, "%s: CCU_CCPU_LAST_ADDR1 %08x\n", __func__, reg);
 
 	ccu_reg = penv->riva_ccu_base + CCU_RIVA_LAST_ADDR2_OFFSET;
 	reg = readl_relaxed(ccu_reg);
-	pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
+	wcnss_log(INFO, "%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
 }
 EXPORT_SYMBOL(wcnss_riva_log_debug_regs);
 
@@ -586,13 +634,12 @@
 			break;
 	}
 
-	if (iter == A2XB_FIFO_COUNTER) {
-		pr_err("%s data FIFO testbus possibly stalled reg%08x\n",
-		       type, reg);
-	} else {
-		pr_err("%s data FIFO tstbus not stalled reg%08x\n",
-		       type, reg);
-	}
+	if (iter == A2XB_FIFO_COUNTER)
+		wcnss_log(ERR,
+		"%s data FIFO testbus possibly stalled reg%08x\n", type, reg);
+	else
+		wcnss_log(ERR,
+		"%s data FIFO tstbus not stalled reg%08x\n", type, reg);
 }
 
 int wcnss_get_dual_band_capability_info(struct platform_device *pdev)
@@ -627,71 +674,72 @@
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SPARE_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("PRONTO_PMU_SPARE %08x\n", reg);
+	wcnss_log(ERR, "PRONTO_PMU_SPARE %08x\n", reg);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_CPU_CBCR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("PRONTO_PMU_COM_CPU_CBCR %08x\n", reg);
+	wcnss_log(ERR, "PRONTO_PMU_COM_CPU_CBCR %08x\n", reg);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_AHB_CBCR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("PRONTO_PMU_COM_AHB_CBCR %08x\n", reg);
+	wcnss_log(ERR, "PRONTO_PMU_COM_AHB_CBCR %08x\n", reg);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CFG_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("PRONTO_PMU_CFG %08x\n", reg);
+	wcnss_log(ERR, "PRONTO_PMU_CFG %08x\n", reg);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_CSR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("PRONTO_PMU_COM_CSR %08x\n", reg);
+	wcnss_log(ERR, "PRONTO_PMU_COM_CSR %08x\n", reg);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SOFT_RESET_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("PRONTO_PMU_SOFT_RESET %08x\n", reg);
+	wcnss_log(ERR, "PRONTO_PMU_SOFT_RESET %08x\n", reg);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WDOG_CTL;
 	reg = readl_relaxed(reg_addr);
-	pr_err("PRONTO_PMU_WDOG_CTL %08x\n", reg);
+	wcnss_log(ERR, "PRONTO_PMU_WDOG_CTL %08x\n", reg);
 
 	reg_addr = penv->pronto_saw2_base + PRONTO_SAW2_SPM_STS_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("PRONTO_SAW2_SPM_STS %08x\n", reg);
+	wcnss_log(ERR, "PRONTO_SAW2_SPM_STS %08x\n", reg);
 
 	reg_addr = penv->pronto_saw2_base + PRONTO_SAW2_SPM_CTL;
 	reg = readl_relaxed(reg_addr);
-	pr_err("PRONTO_SAW2_SPM_CTL %08x\n", reg);
+	wcnss_log(ERR, "PRONTO_SAW2_SPM_CTL %08x\n", reg);
 
 	if (penv->is_a2xb_split_reg) {
 		reg_addr = penv->msm_wcnss_base +
 			   PMU_A2XB_CFG_HSPLIT_RESP_LIMIT_OFFSET;
 		reg = readl_relaxed(reg_addr);
-		pr_err("PMU_A2XB_CFG_HSPLIT_RESP_LIMIT %08x\n", reg);
+		wcnss_log(ERR, "PMU_A2XB_CFG_HSPLIT_RESP_LIMIT %08x\n", reg);
 	}
 
 	reg_addr = penv->pronto_saw2_base + PRONTO_SAW2_SAW2_VERSION;
 	reg = readl_relaxed(reg_addr);
-	pr_err("PRONTO_SAW2_SAW2_VERSION %08x\n", reg);
+	wcnss_log(ERR, "PRONTO_SAW2_SAW2_VERSION %08x\n", reg);
 	reg >>= PRONTO_SAW2_MAJOR_VER_OFFSET;
 
 	reg_addr = penv->msm_wcnss_base  + PRONTO_PMU_CCPU_BOOT_REMAP_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("PRONTO_PMU_CCPU_BOOT_REMAP %08x\n", reg);
+	wcnss_log(ERR, "PRONTO_PMU_CCPU_BOOT_REMAP %08x\n", reg);
 
 	reg_addr = penv->pronto_pll_base + PRONTO_PLL_STATUS_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("PRONTO_PLL_STATUS %08x\n", reg);
+	wcnss_log(ERR, "PRONTO_PLL_STATUS %08x\n", reg);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CPU_AHB_CMD_RCGR_OFFSET;
 	reg4 = readl_relaxed(reg_addr);
-	pr_err("PMU_CPU_CMD_RCGR %08x\n", reg4);
+	wcnss_log(ERR, "PMU_CPU_CMD_RCGR %08x\n", reg4);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_GDSCR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("PRONTO_PMU_COM_GDSCR %08x\n", reg);
+	wcnss_log(ERR, "PRONTO_PMU_COM_GDSCR %08x\n", reg);
 	reg >>= 31;
 
 	if (!reg) {
-		pr_err("Cannot log, Pronto common SS is power collapsed\n");
+		wcnss_log(ERR,
+		"Cannot log, Pronto common SS is power collapsed\n");
 		return;
 	}
 	reg &= ~(PRONTO_PMU_COM_GDSCR_SW_COLLAPSE
@@ -705,47 +753,47 @@
 
 	reg_addr = penv->pronto_a2xb_base + A2XB_CFG_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("A2XB_CFG_OFFSET %08x\n", reg);
+	wcnss_log(ERR, "A2XB_CFG_OFFSET %08x\n", reg);
 
 	reg_addr = penv->pronto_a2xb_base + A2XB_INT_SRC_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("A2XB_INT_SRC_OFFSET %08x\n", reg);
+	wcnss_log(ERR, "A2XB_INT_SRC_OFFSET %08x\n", reg);
 
 	reg_addr = penv->pronto_a2xb_base + A2XB_ERR_INFO_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("A2XB_ERR_INFO_OFFSET %08x\n", reg);
+	wcnss_log(ERR, "A2XB_ERR_INFO_OFFSET %08x\n", reg);
 
 	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_INVALID_ADDR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("CCU_CCPU_INVALID_ADDR %08x\n", reg);
+	wcnss_log(ERR, "CCU_CCPU_INVALID_ADDR %08x\n", reg);
 
 	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR0_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("CCU_CCPU_LAST_ADDR0 %08x\n", reg);
+	wcnss_log(ERR, "CCU_CCPU_LAST_ADDR0 %08x\n", reg);
 
 	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR1_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("CCU_CCPU_LAST_ADDR1 %08x\n", reg);
+	wcnss_log(ERR, "CCU_CCPU_LAST_ADDR1 %08x\n", reg);
 
 	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR2_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("CCU_CCPU_LAST_ADDR2 %08x\n", reg);
+	wcnss_log(ERR, "CCU_CCPU_LAST_ADDR2 %08x\n", reg);
 
 	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_AOWBR_ERR_ADDR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("CCU_PRONTO_AOWBR_ERR_ADDR_OFFSET %08x\n", reg);
+	wcnss_log(ERR, "CCU_PRONTO_AOWBR_ERR_ADDR_OFFSET %08x\n", reg);
 
 	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_AOWBR_TIMEOUT_REG_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("CCU_PRONTO_AOWBR_TIMEOUT_REG_OFFSET %08x\n", reg);
+	wcnss_log(ERR, "CCU_PRONTO_AOWBR_TIMEOUT_REG_OFFSET %08x\n", reg);
 
 	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_AOWBR_ERR_TIMEOUT_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("CCU_PRONTO_AOWBR_ERR_TIMEOUT_OFFSET %08x\n", reg);
+	wcnss_log(ERR, "CCU_PRONTO_AOWBR_ERR_TIMEOUT_OFFSET %08x\n", reg);
 
 	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_A2AB_ERR_ADDR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("CCU_PRONTO_A2AB_ERR_ADDR_OFFSET %08x\n", reg);
+	wcnss_log(ERR, "CCU_PRONTO_A2AB_ERR_ADDR_OFFSET %08x\n", reg);
 
 	tst_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_OFFSET;
 	tst_ctrl_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_CTRL_OFFSET;
@@ -760,7 +808,7 @@
 					       A2XB_READ_FIFO_FILL_MASK,
 					       "Read");
 	} else {
-		pr_err("Read data FIFO testbus %08x\n", reg);
+		wcnss_log(ERR, "Read data FIFO testbus %08x\n", reg);
 	}
 	/*  command FIFO */
 	reg = 0;
@@ -771,7 +819,7 @@
 		wcnss_pronto_is_a2xb_bus_stall(tst_addr,
 					       A2XB_CMD_FIFO_FILL_MASK, "Cmd");
 	} else {
-		pr_err("Command FIFO testbus %08x\n", reg);
+		wcnss_log(ERR, "Command FIFO testbus %08x\n", reg);
 	}
 
 	/*  write data FIFO */
@@ -784,7 +832,7 @@
 					       A2XB_WRITE_FIFO_FILL_MASK,
 					       "Write");
 	} else {
-		pr_err("Write data FIFO testbus %08x\n", reg);
+		wcnss_log(ERR, "Write data FIFO testbus %08x\n", reg);
 	}
 
 	/*   AXIM SEL CFG0 */
@@ -793,7 +841,7 @@
 				WCNSS_TSTBUS_CTRL_AXIM_CFG0;
 	writel_relaxed(reg, tst_ctrl_addr);
 	reg = readl_relaxed(tst_addr);
-	pr_err("AXIM SEL CFG0 testbus %08x\n", reg);
+	wcnss_log(ERR, "AXIM SEL CFG0 testbus %08x\n", reg);
 
 	/*   AXIM SEL CFG1 */
 	reg = 0;
@@ -801,7 +849,7 @@
 				WCNSS_TSTBUS_CTRL_AXIM_CFG1;
 	writel_relaxed(reg, tst_ctrl_addr);
 	reg = readl_relaxed(tst_addr);
-	pr_err("AXIM SEL CFG1 testbus %08x\n", reg);
+	wcnss_log(ERR, "AXIM SEL CFG1 testbus %08x\n", reg);
 
 	/*   CTRL SEL CFG0 */
 	reg = 0;
@@ -809,7 +857,7 @@
 		WCNSS_TSTBUS_CTRL_CTRL_CFG0;
 	writel_relaxed(reg, tst_ctrl_addr);
 	reg = readl_relaxed(tst_addr);
-	pr_err("CTRL SEL CFG0 testbus %08x\n", reg);
+	wcnss_log(ERR, "CTRL SEL CFG0 testbus %08x\n", reg);
 
 	/*   CTRL SEL CFG1 */
 	reg = 0;
@@ -817,7 +865,7 @@
 		WCNSS_TSTBUS_CTRL_CTRL_CFG1;
 	writel_relaxed(reg, tst_ctrl_addr);
 	reg = readl_relaxed(tst_addr);
-	pr_err("CTRL SEL CFG1 testbus %08x\n", reg);
+	wcnss_log(ERR, "CTRL SEL CFG1 testbus %08x\n", reg);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WLAN_BCR_OFFSET;
 	reg = readl_relaxed(reg_addr);
@@ -827,7 +875,7 @@
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WLAN_AHB_CBCR_OFFSET;
 	reg3 = readl_relaxed(reg_addr);
-	pr_err("PMU_WLAN_AHB_CBCR %08x\n", reg3);
+	wcnss_log(ERR, "PMU_WLAN_AHB_CBCR %08x\n", reg3);
 
 	msleep(50);
 
@@ -836,76 +884,76 @@
 	    (!(reg4 & PRONTO_PMU_CPU_AHB_CMD_RCGR_ROOT_EN)) ||
 	    (reg3 & PRONTO_PMU_WLAN_AHB_CBCR_CLK_OFF) ||
 	    (!(reg3 & PRONTO_PMU_WLAN_AHB_CBCR_CLK_EN))) {
-		pr_err("Cannot log, wlan domain is power collapsed\n");
+		wcnss_log(ERR, "Cannot log, wlan domain is power collapsed\n");
 		return;
 	}
 
 	reg = readl_relaxed(penv->wlan_tx_phy_aborts);
-	pr_err("WLAN_TX_PHY_ABORTS %08x\n", reg);
+	wcnss_log(ERR, "WLAN_TX_PHY_ABORTS %08x\n", reg);
 
 	reg_addr = penv->pronto_mcu_base + MCU_APB2PHY_STATUS_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("MCU_APB2PHY_STATUS %08x\n", reg);
+	wcnss_log(ERR, "MCU_APB2PHY_STATUS %08x\n", reg);
 
 	reg_addr = penv->pronto_mcu_base + MCU_CBR_CCAHB_ERR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("MCU_CBR_CCAHB_ERR %08x\n", reg);
+	wcnss_log(ERR, "MCU_CBR_CCAHB_ERR %08x\n", reg);
 
 	reg_addr = penv->pronto_mcu_base + MCU_CBR_CAHB_ERR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("MCU_CBR_CAHB_ERR %08x\n", reg);
+	wcnss_log(ERR, "MCU_CBR_CAHB_ERR %08x\n", reg);
 
 	reg_addr = penv->pronto_mcu_base + MCU_CBR_CCAHB_TIMEOUT_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("MCU_CBR_CCAHB_TIMEOUT %08x\n", reg);
+	wcnss_log(ERR, "MCU_CBR_CCAHB_TIMEOUT %08x\n", reg);
 
 	reg_addr = penv->pronto_mcu_base + MCU_CBR_CAHB_TIMEOUT_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("MCU_CBR_CAHB_TIMEOUT %08x\n", reg);
+	wcnss_log(ERR, "MCU_CBR_CAHB_TIMEOUT %08x\n", reg);
 
 	reg_addr = penv->pronto_mcu_base + MCU_DBR_CDAHB_ERR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("MCU_DBR_CDAHB_ERR %08x\n", reg);
+	wcnss_log(ERR, "MCU_DBR_CDAHB_ERR %08x\n", reg);
 
 	reg_addr = penv->pronto_mcu_base + MCU_DBR_DAHB_ERR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("MCU_DBR_DAHB_ERR %08x\n", reg);
+	wcnss_log(ERR, "MCU_DBR_DAHB_ERR %08x\n", reg);
 
 	reg_addr = penv->pronto_mcu_base + MCU_DBR_CDAHB_TIMEOUT_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("MCU_DBR_CDAHB_TIMEOUT %08x\n", reg);
+	wcnss_log(ERR, "MCU_DBR_CDAHB_TIMEOUT %08x\n", reg);
 
 	reg_addr = penv->pronto_mcu_base + MCU_DBR_DAHB_TIMEOUT_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("MCU_DBR_DAHB_TIMEOUT %08x\n", reg);
+	wcnss_log(ERR, "MCU_DBR_DAHB_TIMEOUT %08x\n", reg);
 
 	reg_addr = penv->pronto_mcu_base + MCU_FDBR_CDAHB_ERR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("MCU_FDBR_CDAHB_ERR %08x\n", reg);
+	wcnss_log(ERR, "MCU_FDBR_CDAHB_ERR %08x\n", reg);
 
 	reg_addr = penv->pronto_mcu_base + MCU_FDBR_FDAHB_ERR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("MCU_FDBR_FDAHB_ERR %08x\n", reg);
+	wcnss_log(ERR, "MCU_FDBR_FDAHB_ERR %08x\n", reg);
 
 	reg_addr = penv->pronto_mcu_base + MCU_FDBR_CDAHB_TIMEOUT_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("MCU_FDBR_CDAHB_TIMEOUT %08x\n", reg);
+	wcnss_log(ERR, "MCU_FDBR_CDAHB_TIMEOUT %08x\n", reg);
 
 	reg_addr = penv->pronto_mcu_base + MCU_FDBR_FDAHB_TIMEOUT_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_err("MCU_FDBR_FDAHB_TIMEOUT %08x\n", reg);
+	wcnss_log(ERR, "MCU_FDBR_FDAHB_TIMEOUT %08x\n", reg);
 
 	reg = readl_relaxed(penv->wlan_brdg_err_source);
-	pr_err("WLAN_BRDG_ERR_SOURCE %08x\n", reg);
+	wcnss_log(ERR, "WLAN_BRDG_ERR_SOURCE %08x\n", reg);
 
 	reg = readl_relaxed(penv->wlan_tx_status);
-	pr_err("WLAN_TXP_STATUS %08x\n", reg);
+	wcnss_log(ERR, "WLAN_TXP_STATUS %08x\n", reg);
 
 	reg = readl_relaxed(penv->alarms_txctl);
-	pr_err("ALARMS_TXCTL %08x\n", reg);
+	wcnss_log(ERR, "ALARMS_TXCTL %08x\n", reg);
 
 	reg = readl_relaxed(penv->alarms_tactl);
-	pr_err("ALARMS_TACTL %08x\n", reg);
+	wcnss_log(ERR, "ALARMS_TACTL %08x\n", reg);
 }
 EXPORT_SYMBOL(wcnss_pronto_log_debug_regs);
 
@@ -930,13 +978,13 @@
 	if (!IS_ERR_OR_NULL(pin_state)) {
 		ret = pinctrl_select_state(penv->pinctrl, pin_state);
 		if (ret < 0) {
-			pr_err("%s: can not set gpio pins err: %d\n",
+			wcnss_log(ERR, "%s: can not set gpio pins err: %d\n",
 			       __func__, ret);
 			goto pinctrl_set_err;
 		}
 
 	} else {
-		pr_err("%s: invalid gpio pinstate err: %lu\n",
+		wcnss_log(ERR, "%s: invalid gpio pinstate err: %lu\n",
 		       __func__, PTR_ERR(pin_state));
 		goto pinctrl_set_err;
 	}
@@ -945,7 +993,7 @@
 		ret = gpio_request_one(penv->gpios[i],
 				       GPIOF_DIR_IN, NULL);
 		if (ret) {
-			pr_err("%s: request failed for gpio:%d\n",
+			wcnss_log(ERR, "%s: request failed for gpio:%d\n",
 			       __func__, penv->gpios[i]);
 			i--;
 			goto gpio_req_err;
@@ -956,7 +1004,7 @@
 		ret = gpio_request_one(penv->gpios[i],
 				       GPIOF_OUT_INIT_LOW, NULL);
 		if (ret) {
-			pr_err("%s: request failed for gpio:%d\n",
+			wcnss_log(ERR, "%s: request failed for gpio:%d\n",
 			       __func__, penv->gpios[i]);
 			i--;
 			goto gpio_req_err;
@@ -1072,12 +1120,13 @@
 		0x04, 0x05, 0x11, 0x1e, 0x40, 0x48,
 		0x49, 0x4b, 0x00, 0x01, 0x4d};
 
-	pr_info("%s: IRIS Registers [address] : value\n", __func__);
+	wcnss_log(INFO, "%s: IRIS Registers [address] : value\n", __func__);
 
 	for (i = 0; i < ARRAY_SIZE(regs_array); i++) {
 		reg_val = wcnss_rf_read_reg(regs_array[i]);
 
-		pr_info("[0x%08x] : 0x%08x\n", regs_array[i], reg_val);
+		wcnss_log(INFO, "IRIS Reg Addr: [0x%08x] : Reg val: 0x%08x\n",
+			  regs_array[i], reg_val);
 	}
 }
 
@@ -1111,24 +1160,25 @@
 
 	if (!IS_ERR(measure) && !IS_ERR(wcnss_debug_mux)) {
 		if (clk_set_parent(measure, wcnss_debug_mux)) {
-			pr_err("Setting measure clk parent failed\n");
+			wcnss_log(ERR, "Setting measure clk parent failed\n");
 			return;
 		}
 
 		if (clk_prepare_enable(measure)) {
-			pr_err("measure clk enable failed\n");
+			wcnss_log(ERR, "measure clk enable failed\n");
 			return;
 		}
 
 		clk_rate = clk_get_rate(measure);
-		pr_debug("wcnss: clock frequency is: %luHz\n", clk_rate);
+		wcnss_log(DBG, "clock frequency is: %luHz\n", clk_rate);
 
 		if (clk_rate) {
 			wcnss_pronto_log_debug_regs();
 			if (wcnss_get_mux_control())
 				wcnss_log_iris_regs();
 		} else {
-			pr_err("clock frequency is zero, cannot access PMU or other registers\n");
+			wcnss_log(ERR, "clock frequency is zero, cannot");
+			wcnss_log(ERR, " access PMU or other registers\n");
 			wcnss_log_iris_regs();
 		}
 
@@ -1153,8 +1203,8 @@
 			wmb();
 			__raw_writel(1 << 16, penv->fiq_reg);
 		} else {
-			pr_info("%s: Block FIQ during power up sequence\n",
-				__func__);
+			wcnss_log(INFO,
+			"%s: Block FIQ during power up sequence\n", __func__);
 		}
 	} else {
 		wcnss_riva_log_debug_regs();
@@ -1202,20 +1252,20 @@
 
 static void wcnss_pm_qos_add_request(void)
 {
-	pr_info("%s: add request\n", __func__);
+	wcnss_log(INFO, "%s: add request\n", __func__);
 	pm_qos_add_request(&penv->wcnss_pm_qos_request, PM_QOS_CPU_DMA_LATENCY,
 			   PM_QOS_DEFAULT_VALUE);
 }
 
 static void wcnss_pm_qos_remove_request(void)
 {
-	pr_info("%s: remove request\n", __func__);
+	wcnss_log(INFO, "%s: remove request\n", __func__);
 	pm_qos_remove_request(&penv->wcnss_pm_qos_request);
 }
 
 void wcnss_pm_qos_update_request(int val)
 {
-	pr_info("%s: update request %d\n", __func__, val);
+	wcnss_log(INFO, "%s: update request %d\n", __func__, val);
 	pm_qos_update_request(&penv->wcnss_pm_qos_request, val);
 }
 
@@ -1248,21 +1298,21 @@
 	int len = 0;
 
 	if (penv != data) {
-		pr_err("wcnss: invalid env pointer in smd callback\n");
+		wcnss_log(ERR, "invalid env pointer in smd callback\n");
 		return;
 	}
 	switch (event) {
 	case SMD_EVENT_DATA:
 		len = smd_read_avail(penv->smd_ch);
 		if (len < 0) {
-			pr_err("wcnss: failed to read from smd %d\n", len);
+			wcnss_log(ERR, "failed to read from smd %d\n", len);
 			return;
 		}
 		schedule_work(&penv->wcnssctrl_rx_work);
 		break;
 
 	case SMD_EVENT_OPEN:
-		pr_debug("wcnss: opening WCNSS SMD channel :%s",
+		wcnss_log(DBG, "opening WCNSS SMD channel :%s",
 			 WCNSS_CTRL_CHANNEL);
 		schedule_work(&penv->wcnssctrl_version_work);
 		schedule_work(&penv->wcnss_pm_config_work);
@@ -1273,7 +1323,7 @@
 		break;
 
 	case SMD_EVENT_CLOSE:
-		pr_debug("wcnss: closing WCNSS SMD channel :%s",
+		wcnss_log(DBG, "closing WCNSS SMD channel :%s",
 			 WCNSS_CTRL_CHANNEL);
 		penv->nv_downloaded = 0;
 		penv->is_cbc_done = 0;
@@ -1290,7 +1340,7 @@
 	struct pinctrl_state *pin_state;
 	int ret;
 
-	pr_debug("%s: Set GPIO state : %d\n", __func__, active);
+	wcnss_log(DBG, "%s: Set GPIO state : %d\n", __func__, active);
 
 	pin_state = active ? penv->wcnss_5wire_active
 			: penv->wcnss_5wire_suspend;
@@ -1298,13 +1348,13 @@
 	if (!IS_ERR_OR_NULL(pin_state)) {
 		ret = pinctrl_select_state(penv->pinctrl, pin_state);
 		if (ret < 0) {
-			pr_err("%s: can not set %s pins\n", __func__,
+			wcnss_log(ERR, "%s: can not set %s pins\n", __func__,
 			       active ? WCNSS_PINCTRL_STATE_DEFAULT
 			       : WCNSS_PINCTRL_STATE_SLEEP);
 			return ret;
 		}
 	} else {
-		pr_err("%s: invalid '%s' pinstate\n", __func__,
+		wcnss_log(ERR, "%s: invalid '%s' pinstate\n", __func__,
 		       active ? WCNSS_PINCTRL_STATE_DEFAULT
 		       : WCNSS_PINCTRL_STATE_SLEEP);
 		return PTR_ERR(pin_state);
@@ -1323,7 +1373,7 @@
 	penv->pinctrl = devm_pinctrl_get(&pdev->dev);
 
 	if (IS_ERR_OR_NULL(penv->pinctrl)) {
-		pr_err("%s: failed to get pinctrl\n", __func__);
+		wcnss_log(ERR, "%s: failed to get pinctrl\n", __func__);
 		return PTR_ERR(penv->pinctrl);
 	}
 
@@ -1332,7 +1382,7 @@
 			WCNSS_PINCTRL_STATE_DEFAULT);
 
 	if (IS_ERR_OR_NULL(penv->wcnss_5wire_active)) {
-		pr_err("%s: can not get default pinstate\n", __func__);
+		wcnss_log(ERR, "%s: can not get default pinstate\n", __func__);
 		return PTR_ERR(penv->wcnss_5wire_active);
 	}
 
@@ -1341,19 +1391,20 @@
 			WCNSS_PINCTRL_STATE_SLEEP);
 
 	if (IS_ERR_OR_NULL(penv->wcnss_5wire_suspend)) {
-		pr_warn("%s: can not get sleep pinstate\n", __func__);
+		wcnss_log(WARN, "%s: can not get sleep pinstate\n", __func__);
 		return PTR_ERR(penv->wcnss_5wire_suspend);
 	}
 
 	penv->wcnss_gpio_active = pinctrl_lookup_state(penv->pinctrl,
 					WCNSS_PINCTRL_GPIO_STATE_DEFAULT);
 	if (IS_ERR_OR_NULL(penv->wcnss_gpio_active))
-		pr_warn("%s: can not get gpio default pinstate\n", __func__);
+		wcnss_log(WARN, "%s: can not get gpio default pinstate\n",
+			  __func__);
 
 	for (i = 0; i < WCNSS_WLAN_MAX_GPIO; i++) {
 		penv->gpios[i] = of_get_gpio(node, i);
 		if (penv->gpios[i] < 0)
-			pr_warn("%s: Fail to get 5wire gpio: %d\n",
+			wcnss_log(WARN, "%s: Fail to get 5wire gpio: %d\n",
 				__func__, i);
 	}
 
@@ -1370,13 +1421,13 @@
 	/* Use Pinctrl to configure 5 wire GPIOs */
 	rc = wcnss_pinctrl_init(pdev);
 	if (rc) {
-		pr_err("%s: failed to get pin resources\n", __func__);
+		wcnss_log(ERR, "%s: failed to get pin resources\n", __func__);
 		penv->pinctrl = NULL;
 		goto gpio_probe;
 	} else {
 		rc = wcnss_pinctrl_set_state(true);
 		if (rc)
-			pr_err("%s: failed to set pin state\n",
+			wcnss_log(ERR, "%s: failed to set pin state\n",
 			       __func__);
 		penv->use_pinctrl = true;
 		return rc;
@@ -1389,7 +1440,7 @@
 		if (enable) {
 			rc = gpio_request(gpio, "wcnss_wlan");
 			if (rc) {
-				pr_err("WCNSS gpio_request %d err %d\n",
+				wcnss_log(ERR, "WCNSS gpio_request %d err %d\n",
 				       gpio, rc);
 				goto fail;
 			}
@@ -1418,7 +1469,8 @@
 		if (enable) {
 			rc = gpio_request(i, gpios_5wire->name);
 			if (rc) {
-				pr_err("WCNSS gpio_request %d err %d\n", i, rc);
+				wcnss_log(ERR,
+					  "gpio_request %d err %d\n", i, rc);
 				goto fail;
 			}
 		} else {
@@ -1442,7 +1494,7 @@
 
 	penv->smd_channel_ready = 1;
 
-	pr_info("%s: SMD ctrl channel up\n", __func__);
+	wcnss_log(INFO, "%s: SMD ctrl channel up\n", __func__);
 	return 0;
 }
 
@@ -1452,7 +1504,7 @@
 	if (penv)
 		penv->smd_channel_ready = 0;
 
-	pr_info("%s: SMD ctrl channel down\n", __func__);
+	wcnss_log(INFO, "%s: SMD ctrl channel down\n", __func__);
 
 	return 0;
 }
@@ -1487,7 +1539,7 @@
 				     &penv->smd_ch, penv,
 				     wcnss_smd_notify_event);
 	if (ret < 0) {
-		pr_err("wcnss: cannot open the smd command channel %s: %d\n",
+		wcnss_log(ERR, "cannot open the smd command channel %s: %d\n",
 		       WCNSS_CTRL_CHANNEL, ret);
 		return -ENODEV;
 	}
@@ -1611,14 +1663,15 @@
 {
 	if (penv && dev && (dev == &penv->pdev->dev) && pm_ops) {
 		if (!penv->pm_ops) {
-			pr_err("%s: pm_ops is already unregistered.\n",
+			wcnss_log(ERR, "%s: pm_ops is already unregistered.\n",
 			       __func__);
 			return;
 		}
 
 		if (pm_ops->suspend != penv->pm_ops->suspend ||
 		    pm_ops->resume != penv->pm_ops->resume)
-			pr_err("PM APIs dont match with registered APIs\n");
+			wcnss_log(ERR,
+			"PM APIs dont match with registered APIs\n");
 		penv->pm_ops = NULL;
 	}
 }
@@ -1637,7 +1690,7 @@
 {
 	if (penv && tm_notify) {
 		if (tm_notify != penv->tm_notify)
-			pr_err("tm_notify doesn't match registered\n");
+			wcnss_log(ERR, "tm_notify doesn't match registered\n");
 		penv->tm_notify = NULL;
 	}
 }
@@ -1647,7 +1700,7 @@
 {
 	if (penv) {
 		penv->serial_number = socinfo_get_serial_number();
-		pr_info("%s: Device serial number: %u\n",
+		wcnss_log(INFO, "%s: Device serial number: %u\n",
 			__func__, penv->serial_number);
 		return penv->serial_number;
 	}
@@ -1662,7 +1715,7 @@
 		return -ENODEV;
 
 	memcpy(mac_addr, penv->wlan_nv_mac_addr, WLAN_MAC_ADDR_SIZE);
-	pr_debug("%s: Get MAC Addr:" MAC_ADDRESS_STR "\n", __func__,
+	wcnss_log(DBG, "%s: Get MAC Addr:" MAC_ADDRESS_STR "\n", __func__,
 		 penv->wlan_nv_mac_addr[0], penv->wlan_nv_mac_addr[1],
 		 penv->wlan_nv_mac_addr[2], penv->wlan_nv_mac_addr[3],
 		 penv->wlan_nv_mac_addr[4], penv->wlan_nv_mac_addr[5]);
@@ -1682,7 +1735,7 @@
 		return ret;
 
 	if (enable_wcnss_suspend_notify)
-		pr_debug("Suspend notification activated for wcnss\n");
+		wcnss_log(DBG, "Suspend notification activated for wcnss\n");
 
 	return 0;
 }
@@ -1875,12 +1928,12 @@
 
 	ret = smd_write_avail(penv->smd_ch);
 	if (ret < len) {
-		pr_err("wcnss: no space available for smd frame\n");
+		wcnss_log(ERR, "no space available for smd frame\n");
 		return -ENOSPC;
 	}
 	ret = smd_write(penv->smd_ch, data, len);
 	if (ret < len) {
-		pr_err("wcnss: failed to write Command %d", len);
+		wcnss_log(ERR, "failed to write Command %d", len);
 		ret = -ENODEV;
 	}
 	return ret;
@@ -1892,19 +1945,19 @@
 	struct qpnp_vadc_result adc_result;
 
 	if (!penv->vadc_dev) {
-		pr_err("wcnss: not setting up vadc\n");
+		wcnss_log(ERR, "not setting up vadc\n");
 		return rc;
 	}
 
 	rc = qpnp_vadc_read(penv->vadc_dev, VBAT_SNS, &adc_result);
 	if (rc) {
-		pr_err("error reading adc channel = %d, rc = %d\n",
+		wcnss_log(ERR, "error reading adc channel = %d, rc = %d\n",
 		       VBAT_SNS, rc);
 		return rc;
 	}
 
-	pr_info("Battery mvolts phy=%lld meas=0x%llx\n", adc_result.physical,
-		adc_result.measurement);
+	wcnss_log(INFO, "Battery mvolts phy=%lld meas=0x%llx\n",
+		  adc_result.physical, adc_result.measurement);
 	*result_uv = (int)adc_result.physical;
 
 	return 0;
@@ -1918,7 +1971,7 @@
 	cancel_delayed_work_sync(&penv->vbatt_work);
 
 	if (state == ADC_TM_LOW_STATE) {
-		pr_debug("wcnss: low voltage notification triggered\n");
+		wcnss_log(DBG, "low voltage notification triggered\n");
 		penv->vbat_monitor_params.state_request =
 			ADC_TM_HIGH_THR_ENABLE;
 		penv->vbat_monitor_params.high_thr = WCNSS_VBATT_THRESHOLD +
@@ -1930,14 +1983,14 @@
 		penv->vbat_monitor_params.low_thr = WCNSS_VBATT_THRESHOLD -
 		WCNSS_VBATT_GUARD;
 		penv->vbat_monitor_params.high_thr = 0;
-		pr_debug("wcnss: high voltage notification triggered\n");
+		wcnss_log(DBG, "high voltage notification triggered\n");
 	} else {
-		pr_debug("wcnss: unknown voltage notification state: %d\n",
+		wcnss_log(DBG, "unknown voltage notification state: %d\n",
 			 state);
 		mutex_unlock(&penv->vbat_monitor_mutex);
 		return;
 	}
-	pr_debug("wcnss: set low thr to %d and high to %d\n",
+	wcnss_log(DBG, "set low thr to %d and high to %d\n",
 		 penv->vbat_monitor_params.low_thr,
 		 penv->vbat_monitor_params.high_thr);
 
@@ -1945,7 +1998,7 @@
 					 &penv->vbat_monitor_params);
 
 	if (rc)
-		pr_err("%s: tm setup failed: %d\n", __func__, rc);
+		wcnss_log(ERR, "%s: tm setup failed: %d\n", __func__, rc);
 	else
 		schedule_delayed_work(&penv->vbatt_work,
 				      msecs_to_jiffies(2000));
@@ -1958,7 +2011,7 @@
 	int rc = -1;
 
 	if (!penv->adc_tm_dev) {
-		pr_err("wcnss: not setting up vbatt\n");
+		wcnss_log(ERR, "not setting up vbatt\n");
 		return rc;
 	}
 	penv->vbat_monitor_params.low_thr = WCNSS_VBATT_THRESHOLD;
@@ -1973,14 +2026,14 @@
 	penv->vbat_monitor_params.btm_ctx = (void *)penv;
 	penv->vbat_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S;
 	penv->vbat_monitor_params.threshold_notification = &wcnss_notify_vbat;
-	pr_debug("wcnss: set low thr to %d and high to %d\n",
+	wcnss_log(DBG, "set low thr to %d and high to %d\n",
 		 penv->vbat_monitor_params.low_thr,
 		 penv->vbat_monitor_params.high_thr);
 
 	rc = qpnp_adc_tm_channel_measure(penv->adc_tm_dev,
 					 &penv->vbat_monitor_params);
 	if (rc)
-		pr_err("%s: tm setup failed: %d\n", __func__, rc);
+		wcnss_log(ERR, "%s: tm setup failed: %d\n", __func__, rc);
 
 	return rc;
 }
@@ -1997,12 +2050,12 @@
 	mutex_lock(&penv->vbat_monitor_mutex);
 	vbatt_msg.vbatt.curr_volt = penv->wlan_config.vbatt;
 	mutex_unlock(&penv->vbat_monitor_mutex);
-	pr_debug("wcnss: send curr_volt: %d to FW\n",
+	wcnss_log(DBG, "send curr_volt: %d to FW\n",
 		 vbatt_msg.vbatt.curr_volt);
 
 	ret = wcnss_smd_tx(&vbatt_msg, vbatt_msg.hdr.msg_len);
 	if (ret < 0)
-		pr_err("wcnss: smd tx failed\n");
+		wcnss_log(ERR, "smd tx failed\n");
 }
 
 static void wcnss_update_vbatt(struct work_struct *work)
@@ -2020,13 +2073,13 @@
 	     penv->fw_vbatt_state == WCNSS_CONFIG_UNSPECIFIED)) {
 		vbatt_msg.vbatt.curr_volt = WCNSS_VBATT_HIGH;
 		penv->fw_vbatt_state = WCNSS_VBATT_HIGH;
-		pr_debug("wcnss: send HIGH BATT to FW\n");
+		wcnss_log(DBG, "send HIGH BATT to FW\n");
 	} else if (!penv->vbat_monitor_params.low_thr &&
 		   (penv->fw_vbatt_state == WCNSS_VBATT_HIGH ||
 		    penv->fw_vbatt_state == WCNSS_CONFIG_UNSPECIFIED)){
 		vbatt_msg.vbatt.curr_volt = WCNSS_VBATT_LOW;
 		penv->fw_vbatt_state = WCNSS_VBATT_LOW;
-		pr_debug("wcnss: send LOW BATT to FW\n");
+		wcnss_log(DBG, "send LOW BATT to FW\n");
 	} else {
 		mutex_unlock(&penv->vbat_monitor_mutex);
 		return;
@@ -2034,7 +2087,7 @@
 	mutex_unlock(&penv->vbat_monitor_mutex);
 	ret = wcnss_smd_tx(&vbatt_msg, vbatt_msg.hdr.msg_len);
 	if (ret < 0)
-		pr_err("wcnss: smd tx failed\n");
+		wcnss_log(ERR, "smd tx failed\n");
 }
 
 static unsigned char wcnss_fw_status(void)
@@ -2046,13 +2099,13 @@
 
 	len = smd_read_avail(penv->smd_ch);
 	if (len < 1) {
-		pr_err("%s: invalid firmware status", __func__);
+		wcnss_log(ERR, "%s: invalid firmware status", __func__);
 		return fw_status;
 	}
 
 	rc = smd_read(penv->smd_ch, &fw_status, 1);
 	if (rc < 0) {
-		pr_err("%s: incomplete data read from smd\n", __func__);
+		wcnss_log(ERR, "%s: incomplete data read from smd\n", __func__);
 		return fw_status;
 	}
 	return fw_status;
@@ -2075,7 +2128,7 @@
 
 	rc = wcnss_smd_tx(msg, rsphdr->msg_len);
 	if (rc < 0)
-		pr_err("wcnss: smd tx failed\n");
+		wcnss_log(ERR, "smd tx failed\n");
 
 	kfree(msg);
 }
@@ -2088,7 +2141,7 @@
 	unsigned char fw_status = WCNSS_RESP_FAIL;
 
 	if (len < sizeof(struct cal_data_params)) {
-		pr_err("wcnss: incomplete cal header length\n");
+		wcnss_log(ERR, "incomplete cal header length\n");
 		return;
 	}
 
@@ -2096,18 +2149,18 @@
 	rc = smd_read(penv->smd_ch, (unsigned char *)&calhdr,
 		      sizeof(struct cal_data_params));
 	if (rc < sizeof(struct cal_data_params)) {
-		pr_err("wcnss: incomplete cal header read from smd\n");
+		wcnss_log(ERR, "incomplete cal header read from smd\n");
 		mutex_unlock(&penv->dev_lock);
 		return;
 	}
 
 	if (penv->fw_cal_exp_frag != calhdr.frag_number) {
-		pr_err("wcnss: Invalid frgament");
+		wcnss_log(ERR, "Invalid frgament");
 		goto unlock_exit;
 	}
 
 	if (calhdr.frag_size > WCNSS_MAX_FRAME_SIZE) {
-		pr_err("wcnss: Invalid fragment size");
+		wcnss_log(ERR, "Invalid fragment size");
 		goto unlock_exit;
 	}
 
@@ -2125,7 +2178,7 @@
 
 	if (calhdr.frag_number == 0) {
 		if (calhdr.total_size > MAX_CALIBRATED_DATA_SIZE) {
-			pr_err("wcnss: Invalid cal data size %d",
+			wcnss_log(ERR, "Invalid cal data size %d",
 			       calhdr.total_size);
 			goto unlock_exit;
 		}
@@ -2141,7 +2194,7 @@
 
 	if (penv->fw_cal_rcvd + calhdr.frag_size >
 			MAX_CALIBRATED_DATA_SIZE) {
-		pr_err("calibrated data size is more than expected %d",
+		wcnss_log(ERR, "calibrated data size is more than expected %d",
 		       penv->fw_cal_rcvd + calhdr.frag_size);
 		penv->fw_cal_exp_frag = 0;
 		penv->fw_cal_rcvd = 0;
@@ -2160,7 +2213,7 @@
 	if (calhdr.msg_flags & LAST_FRAGMENT) {
 		penv->fw_cal_exp_frag = 0;
 		penv->fw_cal_available = true;
-		pr_info("wcnss: cal data collection completed\n");
+		wcnss_log(INFO, "cal data collection completed\n");
 	}
 	mutex_unlock(&penv->dev_lock);
 	wake_up(&penv->read_wait);
@@ -2190,18 +2243,18 @@
 
 	len = smd_read_avail(penv->smd_ch);
 	if (len > WCNSS_MAX_FRAME_SIZE) {
-		pr_err("wcnss: frame larger than the allowed size\n");
+		wcnss_log(ERR, "frame larger than the allowed size\n");
 		smd_read(penv->smd_ch, NULL, len);
 		return;
 	}
 	if (len < sizeof(struct smd_msg_hdr)) {
-		pr_debug("wcnss: incomplete header available len = %d\n", len);
+		wcnss_log(DBG, "incomplete header available len = %d\n", len);
 		return;
 	}
 
 	rc = smd_read(penv->smd_ch, buf, sizeof(struct smd_msg_hdr));
 	if (rc < sizeof(struct smd_msg_hdr)) {
-		pr_err("wcnss: incomplete header read from smd\n");
+		wcnss_log(ERR, "incomplete header read from smd\n");
 		return;
 	}
 	len -= sizeof(struct smd_msg_hdr);
@@ -2212,14 +2265,14 @@
 	case WCNSS_VERSION_RSP:
 		if (len != sizeof(struct wcnss_version)
 				- sizeof(struct smd_msg_hdr)) {
-			pr_err("wcnss: invalid version data from wcnss %d\n",
+			wcnss_log(ERR, "invalid version data from wcnss %d\n",
 			       len);
 			return;
 		}
 		rc = smd_read(penv->smd_ch, buf + sizeof(struct smd_msg_hdr),
 			      len);
 		if (rc < len) {
-			pr_err("wcnss: incomplete data read from smd\n");
+			wcnss_log(ERR, "incomplete data read from smd\n");
 			return;
 		}
 		pversion = (struct wcnss_version *)buf;
@@ -2228,14 +2281,15 @@
 		snprintf(penv->wcnss_version, WCNSS_VERSION_LEN,
 			 "%02x%02x%02x%02x", pversion->major, pversion->minor,
 			 pversion->version, pversion->revision);
-		pr_info("wcnss: version %s\n", penv->wcnss_version);
+		wcnss_log(INFO, "version %s\n", penv->wcnss_version);
 		/* schedule work to download nvbin to ccpu */
 		hw_type = wcnss_hardware_type();
 		switch (hw_type) {
 		case WCNSS_RIVA_HW:
 			/* supported only if riva major >= 1 and minor >= 4 */
 			if ((pversion->major >= 1) && (pversion->minor >= 4)) {
-				pr_info("wcnss: schedule dnld work for riva\n");
+				wcnss_log(INFO,
+					  "schedule download work for riva\n");
 				schedule_work(&penv->wcnssctrl_nvbin_dnld_work);
 			}
 			break;
@@ -2245,41 +2299,43 @@
 			smd_msg.msg_len = sizeof(smd_msg);
 			rc = wcnss_smd_tx(&smd_msg, smd_msg.msg_len);
 			if (rc < 0)
-				pr_err("wcnss: smd tx failed: %s\n", __func__);
+				wcnss_log(ERR, "smd tx failed: %s\n", __func__);
 
 			/* supported only if pronto major >= 1 and minor >= 4 */
 			if ((pversion->major >= 1) && (pversion->minor >= 4)) {
-				pr_info("wcnss: schedule dnld work for pronto\n");
+				wcnss_log(INFO,
+					  "schedule dnld work for pronto\n");
 				schedule_work(&penv->wcnssctrl_nvbin_dnld_work);
 			}
 			break;
 
 		default:
-			pr_info("wcnss: unknown hw type (%d), will not schedule dnld work\n",
-				hw_type);
+			wcnss_log(INFO,
+			"unknown hw type (%d) will not schedule dnld work\n",
+			hw_type);
 			break;
 		}
 		break;
 
 	case WCNSS_BUILD_VER_RSP:
 		if (len > WCNSS_MAX_BUILD_VER_LEN) {
-			pr_err("wcnss: invalid build version data from wcnss %d\n",
-			       len);
+			wcnss_log(ERR,
+			"invalid build version data from wcnss %d\n", len);
 			return;
 		}
 		rc = smd_read(penv->smd_ch, build, len);
 		if (rc < len) {
-			pr_err("wcnss: incomplete data read from smd\n");
+			wcnss_log(ERR, "incomplete data read from smd\n");
 			return;
 		}
 		build[len] = 0;
-		pr_info("wcnss: build version %s\n", build);
+		wcnss_log(INFO, "build version %s\n", build);
 		break;
 
 	case WCNSS_NVBIN_DNLD_RSP:
 		penv->nv_downloaded = true;
 		fw_status = wcnss_fw_status();
-		pr_debug("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu %u\n",
+		wcnss_log(DBG, "received WCNSS_NVBIN_DNLD_RSP from ccpu %u\n",
 			 fw_status);
 		if (fw_status != WAIT_FOR_CBC_IND)
 			penv->is_cbc_done = 1;
@@ -2289,12 +2345,12 @@
 	case WCNSS_CALDATA_DNLD_RSP:
 		penv->nv_downloaded = true;
 		fw_status = wcnss_fw_status();
-		pr_debug("wcnss: received WCNSS_CALDATA_DNLD_RSP from ccpu %u\n",
+		wcnss_log(DBG, "received WCNSS_CALDATA_DNLD_RSP from ccpu %u\n",
 			 fw_status);
 		break;
 	case WCNSS_CBC_COMPLETE_IND:
 		penv->is_cbc_done = 1;
-		pr_debug("wcnss: received WCNSS_CBC_COMPLETE_IND from FW\n");
+		wcnss_log(DBG, "received WCNSS_CBC_COMPLETE_IND from FW\n");
 		break;
 
 	case WCNSS_CALDATA_UPLD_REQ:
@@ -2302,7 +2358,7 @@
 		break;
 
 	default:
-		pr_err("wcnss: invalid message type %d\n", phdr->msg_type);
+		wcnss_log(ERR, "invalid message type %d\n", phdr->msg_type);
 	}
 }
 
@@ -2315,7 +2371,7 @@
 	smd_msg.msg_len = sizeof(smd_msg);
 	ret = wcnss_smd_tx(&smd_msg, smd_msg.msg_len);
 	if (ret < 0)
-		pr_err("wcnss: smd tx failed\n");
+		wcnss_log(ERR, "smd tx failed\n");
 }
 
 static void wcnss_send_pm_config(struct work_struct *worker)
@@ -2340,12 +2396,12 @@
 	rc = of_property_read_u32_array(penv->pdev->dev.of_node,
 					"qcom,wcnss-pm", payload, prop_len);
 	if (rc < 0) {
-		pr_err("wcnss: property read failed\n");
+		wcnss_log(ERR, "property read failed\n");
 		kfree(msg);
 		return;
 	}
 
-	pr_debug("%s:size=%d: <%d, %d, %d, %d, %d %d>\n", __func__,
+	wcnss_log(DBG, "%s:size=%d: <%d, %d, %d, %d, %d %d>\n", __func__,
 		 prop_len, *payload, *(payload + 1), *(payload + 2),
 		 *(payload + 3), *(payload + 4), *(payload + 5));
 
@@ -2355,7 +2411,7 @@
 
 	rc = wcnss_smd_tx(msg, hdr->msg_len);
 	if (rc < 0)
-		pr_err("wcnss: smd tx failed\n");
+		wcnss_log(ERR, "smd tx failed\n");
 
 	kfree(msg);
 }
@@ -2386,7 +2442,8 @@
 	ret = request_firmware(&nv, NVBIN_FILE, dev);
 
 	if (ret || !nv || !nv->data || !nv->size) {
-		pr_err("wcnss: %s: request_firmware failed for %s (ret = %d)\n",
+		wcnss_log(ERR,
+			  "%s: request_firmware failed for %s (ret = %d)\n",
 		       __func__, NVBIN_FILE, ret);
 		goto out;
 	}
@@ -2399,7 +2456,7 @@
 
 	total_fragments = TOTALFRAGMENTS(nv_blob_size);
 
-	pr_info("wcnss: NV bin size: %d, total_fragments: %d\n",
+	wcnss_log(INFO, "NV bin size: %d, total_fragments: %d\n",
 		nv_blob_size, total_fragments);
 
 	/* get buffer for nv bin dnld req message */
@@ -2447,11 +2504,12 @@
 
 		retry_count = 0;
 		while ((ret == -ENOSPC) && (retry_count <= 3)) {
-			pr_debug("wcnss: %s: smd tx failed, ENOSPC\n",
+			wcnss_log(DBG, "%s: smd tx failed, ENOSPC\n",
 				 __func__);
-			pr_debug("fragment: %d, len: %d, TotFragments: %d, retry_count: %d\n",
-				 count, dnld_req_msg->hdr.msg_len,
-				 total_fragments, retry_count);
+			wcnss_log(DBG, "fragment %d, len: %d,", count,
+				  dnld_req_msg->hdr.msg_len);
+			wcnss_log(DBG, "TotFragments: %d, retry_count: %d\n",
+				  total_fragments, retry_count);
 
 			/* wait and try again */
 			msleep(20);
@@ -2461,10 +2519,11 @@
 		}
 
 		if (ret < 0) {
-			pr_err("wcnss: %s: smd tx failed\n", __func__);
-			pr_err("fragment %d, len: %d, TotFragments: %d, retry_count: %d\n",
-			       count, dnld_req_msg->hdr.msg_len,
-			       total_fragments, retry_count);
+			wcnss_log(ERR, "%s: smd tx failed\n", __func__);
+			wcnss_log(ERR, "fragment %d, len: %d,", count,
+				  dnld_req_msg->hdr.msg_len);
+			wcnss_log(ERR, "TotFragments: %d, retry_count: %d\n",
+				  total_fragments, retry_count);
 			goto err_dnld;
 		}
 	}
@@ -2538,11 +2597,12 @@
 
 		retry_count = 0;
 		while ((ret == -ENOSPC) && (retry_count <= 3)) {
-			pr_debug("wcnss: %s: smd tx failed, ENOSPC\n",
+			wcnss_log(DBG, "%s: smd tx failed, ENOSPC\n",
 				 __func__);
-			pr_debug("fragment: %d, len: %d, TotFragments: %d, retry_count: %d\n",
-				 count, cal_msg->hdr.msg_len,
-				 total_fragments, retry_count);
+			wcnss_log(DBG, "fragment: %d, len: %d",
+				  count, cal_msg->hdr.msg_len);
+			wcnss_log(DBG, " TotFragments: %d, retry_count: %d\n",
+				  total_fragments, retry_count);
 
 			/* wait and try again */
 			msleep(20);
@@ -2552,10 +2612,10 @@
 		}
 
 		if (ret < 0) {
-			pr_err("wcnss: %s: smd tx failed\n", __func__);
-			pr_err("fragment %d, len: %d, TotFragments: %d, retry_count: %d\n",
-			       count, cal_msg->hdr.msg_len,
-				total_fragments, retry_count);
+			wcnss_log(ERR, "%s: smd tx failed: fragment %d, len:%d",
+				  count, cal_msg->hdr.msg_len, __func__);
+			wcnss_log(ERR, " TotFragments: %d, retry_count: %d\n",
+				  total_fragments, retry_count);
 			goto err_dnld;
 		}
 	}
@@ -2578,17 +2638,17 @@
 			msleep(500);
 	}
 	if (penv->fw_cal_available) {
-		pr_info_ratelimited("wcnss: cal download, using fw cal");
+		wcnss_log(INFO, "cal download, using fw cal");
 		wcnss_caldata_dnld(penv->fw_cal_data, penv->fw_cal_rcvd, true);
 
 	} else if (penv->user_cal_available) {
-		pr_info_ratelimited("wcnss: cal download, using user cal");
+		wcnss_log(INFO, "cal download, using user cal");
 		wcnss_caldata_dnld(penv->user_cal_data,
 				   penv->user_cal_rcvd, true);
 	}
 
 nv_download:
-	pr_info_ratelimited("wcnss: NV download");
+	wcnss_log(INFO, "NV download");
 	wcnss_nvbin_dnld();
 }
 
@@ -2631,20 +2691,20 @@
 	switch (cmd) {
 	case WCNSS_USR_HAS_CAL_DATA:
 		if (buf[2] > 1)
-			pr_err("%s: Invalid data for cal %d\n", __func__,
-			       buf[2]);
+			wcnss_log(ERR, "%s: Invalid data for cal %d\n",
+				  __func__, buf[2]);
 		has_calibrated_data = buf[2];
 		break;
 	case WCNSS_USR_WLAN_MAC_ADDR:
 		memcpy(&penv->wlan_nv_mac_addr,  &buf[2],
 		       sizeof(penv->wlan_nv_mac_addr));
-		pr_debug("%s: MAC Addr:" MAC_ADDRESS_STR "\n", __func__,
+		wcnss_log(DBG, "%s: MAC Addr:" MAC_ADDRESS_STR "\n", __func__,
 			 penv->wlan_nv_mac_addr[0], penv->wlan_nv_mac_addr[1],
 			 penv->wlan_nv_mac_addr[2], penv->wlan_nv_mac_addr[3],
 			 penv->wlan_nv_mac_addr[4], penv->wlan_nv_mac_addr[5]);
 		break;
 	default:
-		pr_err("%s: Invalid command %d\n", __func__, cmd);
+		wcnss_log(ERR, "%s: Invalid command %d\n", __func__, cmd);
 		break;
 	}
 }
@@ -2703,7 +2763,7 @@
 
 	rc = wcnss_parse_voltage_regulator(&penv->wlan_config, &pdev->dev);
 	if (rc) {
-		dev_err(&pdev->dev, "Failed to parse voltage regulators\n");
+		wcnss_log(ERR, "Failed to parse voltage regulators\n");
 		goto fail;
 	}
 
@@ -2742,7 +2802,7 @@
 
 		/* allocate 5-wire GPIO resources */
 		if (!penv->gpios_5wire) {
-			dev_err(&pdev->dev, "insufficient IO resources\n");
+			wcnss_log(ERR, "insufficient IO resources\n");
 			ret = -ENOENT;
 			goto fail_gpio_res;
 		}
@@ -2752,7 +2812,7 @@
 	}
 
 	if (ret) {
-		dev_err(&pdev->dev, "WCNSS gpios config failed.\n");
+		wcnss_log(ERR, "gpios config failed.\n");
 		goto fail_gpio_res;
 	}
 
@@ -2765,7 +2825,7 @@
 							"wcnss_wlanrx_irq");
 
 	if (!(penv->mmio_res && penv->tx_irq_res && penv->rx_irq_res)) {
-		dev_err(&pdev->dev, "insufficient resources\n");
+		wcnss_log(ERR, "insufficient resources\n");
 		ret = -ENOENT;
 		goto fail_res;
 	}
@@ -2785,7 +2845,7 @@
 						   "pronto_phy_base");
 		if (!res) {
 			ret = -EIO;
-			pr_err("%s: resource pronto_phy_base failed\n",
+			wcnss_log(ERR, "%s: resource pronto_phy_base failed\n",
 			       __func__);
 			goto fail_ioremap;
 		}
@@ -2797,7 +2857,7 @@
 						   "riva_phy_base");
 		if (!res) {
 			ret = -EIO;
-			pr_err("%s: resource riva_phy_base failed\n",
+			wcnss_log(ERR, "%s: resource riva_phy_base failed\n",
 			       __func__);
 			goto fail_ioremap;
 		}
@@ -2807,7 +2867,7 @@
 
 	if (!penv->msm_wcnss_base) {
 		ret = -ENOMEM;
-		pr_err("%s: ioremap wcnss physical failed\n", __func__);
+		wcnss_log(ERR, "%s: ioremap wcnss physical failed\n", __func__);
 		goto fail_ioremap;
 	}
 
@@ -2818,7 +2878,7 @@
 						   "riva_ccu_base");
 		if (!res) {
 			ret = -EIO;
-			pr_err("%s: resource riva_ccu_base failed\n",
+			wcnss_log(ERR, "%s: resource riva_ccu_base failed\n",
 			       __func__);
 			goto fail_ioremap;
 		}
@@ -2827,7 +2887,7 @@
 
 		if (!penv->riva_ccu_base) {
 			ret = -ENOMEM;
-			pr_err("%s: ioremap riva ccu physical failed\n",
+			wcnss_log(ERR, "%s: ioremap riva ccu physical failed\n",
 			       __func__);
 			goto fail_ioremap;
 		}
@@ -2837,7 +2897,7 @@
 						   "pronto_a2xb_base");
 		if (!res) {
 			ret = -EIO;
-			pr_err("%s: resource pronto_a2xb_base failed\n",
+			wcnss_log(ERR, "%s: resource pronto_a2xb_base failed\n",
 			       __func__);
 			goto fail_ioremap;
 		}
@@ -2846,8 +2906,8 @@
 
 		if (!penv->pronto_a2xb_base) {
 			ret = -ENOMEM;
-			pr_err("%s: ioremap pronto a2xb physical failed\n",
-			       __func__);
+			wcnss_log(ERR,
+			"%s: ioremap pronto a2xb physical failed\n", __func__);
 			goto fail_ioremap;
 		}
 
@@ -2856,7 +2916,7 @@
 						   "pronto_ccpu_base");
 		if (!res) {
 			ret = -EIO;
-			pr_err("%s: resource pronto_ccpu_base failed\n",
+			wcnss_log(ERR, "%s: resource pronto_ccpu_base failed\n",
 			       __func__);
 			goto fail_ioremap;
 		}
@@ -2865,8 +2925,8 @@
 
 		if (!penv->pronto_ccpu_base) {
 			ret = -ENOMEM;
-			pr_err("%s: ioremap pronto ccpu physical failed\n",
-			       __func__);
+			wcnss_log(ERR,
+			"%s: ioremap pronto ccpu physical failed\n", __func__);
 			goto fail_ioremap;
 		}
 
@@ -2874,14 +2934,15 @@
 		res = platform_get_resource_byname(penv->pdev,
 						   IORESOURCE_MEM, "wcnss_fiq");
 		if (!res) {
-			dev_err(&pdev->dev, "insufficient irq mem resources\n");
+			wcnss_log(ERR, "insufficient irq mem resources\n");
 			ret = -ENOENT;
 			goto fail_ioremap;
 		}
 		penv->fiq_reg = ioremap_nocache(res->start, resource_size(res));
 		if (!penv->fiq_reg) {
-			pr_err("wcnss: %s: ioremap_nocache() failed fiq_reg addr:%pr\n",
-			       __func__, &res->start);
+			wcnss_log(ERR, "%s", __func__,
+			"ioremap_nocache() failed fiq_reg addr:%pr\n",
+			&res->start);
 			ret = -ENOMEM;
 			goto fail_ioremap;
 		}
@@ -2891,7 +2952,7 @@
 						   "pronto_saw2_base");
 		if (!res) {
 			ret = -EIO;
-			pr_err("%s: resource pronto_saw2_base failed\n",
+			wcnss_log(ERR, "%s: resource pronto_saw2_base failed\n",
 			       __func__);
 			goto fail_ioremap2;
 		}
@@ -2899,8 +2960,8 @@
 			devm_ioremap_resource(&pdev->dev, res);
 
 		if (!penv->pronto_saw2_base) {
-			pr_err("%s: ioremap wcnss physical(saw2) failed\n",
-			       __func__);
+			wcnss_log(ERR,
+			"%s: ioremap wcnss physical(saw2) failed\n", __func__);
 			ret = -ENOMEM;
 			goto fail_ioremap2;
 		}
@@ -2908,8 +2969,8 @@
 		penv->pronto_pll_base =
 			penv->msm_wcnss_base + PRONTO_PLL_MODE_OFFSET;
 		if (!penv->pronto_pll_base) {
-			pr_err("%s: ioremap wcnss physical(pll) failed\n",
-			       __func__);
+			wcnss_log(ERR,
+			"%s: ioremap wcnss physical(pll) failed\n", __func__);
 			ret = -ENOMEM;
 			goto fail_ioremap2;
 		}
@@ -2919,8 +2980,8 @@
 						   "wlan_tx_phy_aborts");
 		if (!res) {
 			ret = -EIO;
-			pr_err("%s: resource wlan_tx_phy_aborts failed\n",
-			       __func__);
+			wcnss_log(ERR,
+			"%s: resource wlan_tx_phy_aborts failed\n", __func__);
 			goto fail_ioremap2;
 		}
 		penv->wlan_tx_phy_aborts =
@@ -2928,7 +2989,8 @@
 
 		if (!penv->wlan_tx_phy_aborts) {
 			ret = -ENOMEM;
-			pr_err("%s: ioremap wlan TX PHY failed\n", __func__);
+			wcnss_log(ERR, "%s: ioremap wlan TX PHY failed\n",
+				  __func__);
 			goto fail_ioremap2;
 		}
 
@@ -2937,8 +2999,8 @@
 						   "wlan_brdg_err_source");
 		if (!res) {
 			ret = -EIO;
-			pr_err("%s: resource wlan_brdg_err_source failed\n",
-			       __func__);
+			wcnss_log(ERR,
+			"%s: get wlan_brdg_err_source res failed\n", __func__);
 			goto fail_ioremap2;
 		}
 		penv->wlan_brdg_err_source =
@@ -2946,7 +3008,8 @@
 
 		if (!penv->wlan_brdg_err_source) {
 			ret = -ENOMEM;
-			pr_err("%s: ioremap wlan BRDG ERR failed\n", __func__);
+			wcnss_log(ERR, "%s: ioremap wlan BRDG ERR failed\n",
+				  __func__);
 			goto fail_ioremap2;
 		}
 
@@ -2955,7 +3018,7 @@
 						   "wlan_tx_status");
 		if (!res) {
 			ret = -EIO;
-			pr_err("%s: resource wlan_tx_status failed\n",
+			wcnss_log(ERR, "%s: resource wlan_tx_status failed\n",
 			       __func__);
 			goto fail_ioremap2;
 		}
@@ -2964,7 +3027,8 @@
 
 		if (!penv->wlan_tx_status) {
 			ret = -ENOMEM;
-			pr_err("%s: ioremap wlan TX STATUS failed\n", __func__);
+			wcnss_log(ERR, "%s: ioremap wlan TX STATUS failed\n",
+				   __func__);
 			goto fail_ioremap2;
 		}
 
@@ -2973,8 +3037,8 @@
 						   "alarms_txctl");
 		if (!res) {
 			ret = -EIO;
-			pr_err("%s: resource alarms_txctl failed\n",
-			       __func__);
+			wcnss_log(ERR,
+			"%s: resource alarms_txctl failed\n", __func__);
 			goto fail_ioremap2;
 		}
 		penv->alarms_txctl =
@@ -2982,7 +3046,8 @@
 
 		if (!penv->alarms_txctl) {
 			ret = -ENOMEM;
-			pr_err("%s: ioremap alarms TXCTL failed\n", __func__);
+			wcnss_log(ERR,
+			"%s: ioremap alarms TXCTL failed\n", __func__);
 			goto fail_ioremap2;
 		}
 
@@ -2991,8 +3056,8 @@
 						   "alarms_tactl");
 		if (!res) {
 			ret = -EIO;
-			pr_err("%s: resource alarms_tactl failed\n",
-			       __func__);
+			wcnss_log(ERR,
+			"%s: resource alarms_tactl failed\n", __func__);
 			goto fail_ioremap2;
 		}
 		penv->alarms_tactl =
@@ -3000,7 +3065,8 @@
 
 		if (!penv->alarms_tactl) {
 			ret = -ENOMEM;
-			pr_err("%s: ioremap alarms TACTL failed\n", __func__);
+			wcnss_log(ERR,
+			"%s: ioremap alarms TACTL failed\n", __func__);
 			goto fail_ioremap2;
 		}
 
@@ -3009,8 +3075,8 @@
 						   "pronto_mcu_base");
 		if (!res) {
 			ret = -EIO;
-			pr_err("%s: resource pronto_mcu_base failed\n",
-			       __func__);
+			wcnss_log(ERR,
+			"%s: resource pronto_mcu_base failed\n", __func__);
 			goto fail_ioremap2;
 		}
 		penv->pronto_mcu_base =
@@ -3018,8 +3084,8 @@
 
 		if (!penv->pronto_mcu_base) {
 			ret = -ENOMEM;
-			pr_err("%s: ioremap pronto mcu physical failed\n",
-			       __func__);
+			wcnss_log(ERR,
+			"%s: ioremap pronto mcu physical failed\n", __func__);
 			goto fail_ioremap2;
 		}
 
@@ -3027,8 +3093,8 @@
 					  "qcom,is-dual-band-disabled")) {
 			ret = wcnss_get_dual_band_capability_info(pdev);
 			if (ret) {
-				pr_err("%s: failed to get dual band info\n",
-				       __func__);
+				wcnss_log(ERR,
+				"%s: failed to get dual band info\n", __func__);
 				goto fail_ioremap2;
 			}
 		}
@@ -3036,7 +3102,7 @@
 
 	penv->adc_tm_dev = qpnp_get_adc_tm(&penv->pdev->dev, "wcnss");
 	if (IS_ERR(penv->adc_tm_dev)) {
-		pr_err("%s:  adc get failed\n", __func__);
+		wcnss_log(ERR, "%s: adc get failed\n", __func__);
 		penv->adc_tm_dev = NULL;
 	} else {
 		INIT_DELAYED_WORK(&penv->vbatt_work, wcnss_update_vbatt);
@@ -3045,14 +3111,14 @@
 
 	penv->snoc_wcnss = devm_clk_get(&penv->pdev->dev, "snoc_wcnss");
 	if (IS_ERR(penv->snoc_wcnss)) {
-		pr_err("%s: couldn't get snoc_wcnss\n", __func__);
+		wcnss_log(ERR, "%s: couldn't get snoc_wcnss\n", __func__);
 		penv->snoc_wcnss = NULL;
 	} else {
 		if (of_property_read_u32(pdev->dev.of_node,
 					 "qcom,snoc-wcnss-clock-freq",
 					 &penv->snoc_wcnss_clock_freq)) {
-			pr_debug("%s: wcnss snoc clock frequency is not defined\n",
-				 __func__);
+			wcnss_log(DBG,
+			"%s: snoc clock frequency is not defined\n", __func__);
 			devm_clk_put(&penv->pdev->dev, penv->snoc_wcnss);
 			penv->snoc_wcnss = NULL;
 		}
@@ -3062,7 +3128,7 @@
 		penv->vadc_dev = qpnp_get_vadc(&penv->pdev->dev, "wcnss");
 
 		if (IS_ERR(penv->vadc_dev)) {
-			pr_debug("%s:  vadc get failed\n", __func__);
+			wcnss_log(DBG, "%s: vadc get failed\n", __func__);
 			penv->vadc_dev = NULL;
 		} else {
 			rc = wcnss_get_battery_volt(&penv->wlan_config.vbatt);
@@ -3070,8 +3136,8 @@
 				  wcnss_send_vbatt_indication);
 
 			if (rc < 0)
-				pr_err("Failed to get battery voltage with error= %d\n",
-				       rc);
+				wcnss_log(ERR,
+				"battery voltage get failed:err=%d\n", rc);
 		}
 	}
 
@@ -3079,7 +3145,7 @@
 		/* trigger initialization of the WCNSS */
 		penv->pil = subsystem_get(WCNSS_PIL_DEVICE);
 		if (IS_ERR(penv->pil)) {
-			dev_err(&pdev->dev, "Peripheral Loader failed on WCNSS.\n");
+			wcnss_log(ERR, "Peripheral Loader failed on WCNSS.\n");
 			ret = PTR_ERR(penv->pil);
 			wcnss_disable_pc_add_req();
 			wcnss_pronto_log_debug_regs();
@@ -3129,7 +3195,7 @@
 	int rc;
 
 	if (!penv->snoc_wcnss) {
-		pr_err("%s: couldn't get clk snoc_wcnss\n", __func__);
+		wcnss_log(ERR, "%s: couldn't get clk snoc_wcnss\n", __func__);
 		return;
 	}
 
@@ -3137,13 +3203,15 @@
 		rc = clk_set_rate(penv->snoc_wcnss,
 				  penv->snoc_wcnss_clock_freq);
 		if (rc) {
-			pr_err("%s: snoc_wcnss_clk-clk_set_rate failed =%d\n",
-			       __func__, rc);
+			wcnss_log(ERR,
+				  "%s: snoc_wcnss_clk-clk_set_rate failed=%d\n",
+				__func__, rc);
 			return;
 		}
 
 		if (clk_prepare_enable(penv->snoc_wcnss)) {
-			pr_err("%s: snoc_wcnss clk enable failed\n", __func__);
+			wcnss_log(ERR, "%s: snoc_wcnss clk enable failed\n",
+				  __func__);
 			return;
 		}
 	} else {
@@ -3219,7 +3287,7 @@
 		return -EFAULT;
 
 	if (!penv->triggered) {
-		pr_info(DEVICE " triggered by userspace\n");
+		wcnss_log(INFO, DEVICE " triggered by userspace\n");
 		pdev = penv->pdev;
 		rc = wcnss_trigger_config(pdev);
 		if (rc)
@@ -3282,8 +3350,8 @@
 				    user_buffer, 4);
 		if (!penv->user_cal_exp_size ||
 		    penv->user_cal_exp_size > MAX_CALIBRATED_DATA_SIZE) {
-			pr_err(DEVICE " invalid size to write %d\n",
-			       penv->user_cal_exp_size);
+			wcnss_log(ERR, DEVICE " invalid size to write %d\n",
+				  penv->user_cal_exp_size);
 			penv->user_cal_exp_size = 0;
 			mutex_unlock(&penv->dev_lock);
 			return -EFAULT;
@@ -3297,8 +3365,8 @@
 	mutex_lock(&penv->dev_lock);
 	if ((UINT32_MAX - count < penv->user_cal_rcvd) ||
 	    (penv->user_cal_exp_size < count + penv->user_cal_rcvd)) {
-		pr_err(DEVICE " invalid size to write %zu\n", count +
-		       penv->user_cal_rcvd);
+		wcnss_log(ERR, DEVICE " invalid size to write %zu\n",
+			  count + penv->user_cal_rcvd);
 		mutex_unlock(&penv->dev_lock);
 		return -ENOMEM;
 	}
@@ -3320,7 +3388,7 @@
 	kfree(cal_data);
 	if (penv->user_cal_rcvd == penv->user_cal_exp_size) {
 		penv->user_cal_available = true;
-		pr_info_ratelimited("wcnss: user cal written");
+		wcnss_log(INFO, "user cal written");
 	}
 	mutex_unlock(&penv->dev_lock);
 
@@ -3342,12 +3410,12 @@
 
 	if (!(code >= SUBSYS_NOTIF_MIN_INDEX) &&
 	    (code <= SUBSYS_NOTIF_MAX_INDEX)) {
-		pr_debug("%s: Invaild subsystem notification code: %lu\n",
-			 __func__, code);
+		wcnss_log(DBG, "%s: Invaild subsystem notification code: %lu\n",
+			  __func__, code);
 		return NOTIFY_DONE;
 	}
 
-	pr_info("%s: wcnss notification event: %lu : %s\n",
+	wcnss_log(INFO, "%s: notification event: %lu : %s\n",
 		 __func__, code, wcnss_subsys_notif_type[code]);
 
 	if (code == SUBSYS_PROXY_VOTE) {
@@ -3356,7 +3424,7 @@
 					       WCNSS_WLAN_SWITCH_ON, &xo_mode);
 			wcnss_set_iris_xo_mode(xo_mode);
 			if (ret)
-				pr_err("Failed to execute wcnss_wlan_power\n");
+				wcnss_log(ERR, "wcnss_wlan_power failed\n");
 		}
 	} else if (code == SUBSYS_PROXY_UNVOTE) {
 		if (pdev && pwlanconfig) {
@@ -3407,30 +3475,30 @@
 
 	ret = alloc_chrdev_region(&penv->dev_ctrl, 0, 1, CTRL_DEVICE);
 	if (ret < 0) {
-		dev_err(&pdev->dev, "CTRL Device Registration failed\n");
+		wcnss_log(ERR, "CTRL Device Registration failed\n");
 		goto alloc_region_ctrl;
 	}
 	ret = alloc_chrdev_region(&penv->dev_node, 0, 1, DEVICE);
 	if (ret < 0) {
-		dev_err(&pdev->dev, "NODE Device Registration failed\n");
+		wcnss_log(ERR, "NODE Device Registration failed\n");
 		goto alloc_region_node;
 	}
 
 	penv->node_class = class_create(THIS_MODULE, "wcnss");
 	if (!penv->node_class) {
-		dev_err(&pdev->dev, "NODE Device Class Creation failed\n");
+		wcnss_log(ERR, "NODE Device Class Creation failed\n");
 		goto class_create_node;
 	}
 
 	if (device_create(penv->node_class, NULL, penv->dev_ctrl, NULL,
 			 CTRL_DEVICE) == NULL) {
-		dev_err(&pdev->dev, "CTRL Device Creation failed\n");
+		wcnss_log(ERR, "CTRL Device Creation failed\n");
 		goto device_create_ctrl;
 	}
 
 	if (device_create(penv->node_class, NULL, penv->dev_node, NULL,
 			  DEVICE) == NULL) {
-		dev_err(&pdev->dev, "NODE Device Creation failed\n");
+		wcnss_log(ERR, "NODE Device Creation failed\n");
 		goto device_create_node;
 	}
 
@@ -3438,11 +3506,11 @@
 	cdev_init(&penv->node_dev, &wcnss_node_fops);
 
 	if (cdev_add(&penv->ctrl_dev, penv->dev_ctrl, 1) == -1) {
-		dev_err(&pdev->dev, "CTRL Device addition failed\n");
+		wcnss_log(ERR, "CTRL Device addition failed\n");
 		goto cdev_add_ctrl;
 	}
 	if (cdev_add(&penv->node_dev, penv->dev_node, 1) == -1) {
-		dev_err(&pdev->dev, "NODE Device addition failed\n");
+		wcnss_log(ERR, "NODE Device addition failed\n");
 		goto cdev_add_node;
 	}
 
@@ -3466,7 +3534,7 @@
 
 static void wcnss_cdev_unregister(struct platform_device *pdev)
 {
-	dev_err(&pdev->dev, "Unregistering cdev devices\n");
+	wcnss_log(ERR, "Unregistering cdev devices\n");
 	cdev_del(&penv->ctrl_dev);
 	cdev_del(&penv->node_dev);
 	device_destroy(penv->node_class, penv->dev_ctrl);
@@ -3483,7 +3551,7 @@
 
 	/* verify we haven't been called more than once */
 	if (penv) {
-		dev_err(&pdev->dev, "cannot handle multiple devices.\n");
+		wcnss_log(ERR, "cannot handle multiple devices.\n");
 		return -ENODEV;
 	}
 
@@ -3497,7 +3565,7 @@
 	penv->user_cal_data =
 		devm_kzalloc(&pdev->dev, MAX_CALIBRATED_DATA_SIZE, GFP_KERNEL);
 	if (!penv->user_cal_data) {
-		dev_err(&pdev->dev, "Failed to alloc memory for cal data.\n");
+		wcnss_log(ERR, "Failed to alloc memory for cal data.\n");
 		return -ENOMEM;
 	}
 
@@ -3511,7 +3579,7 @@
 	/* register wcnss event notification */
 	penv->wcnss_notif_hdle = subsys_notif_register_notifier("wcnss", &wnb);
 	if (IS_ERR(penv->wcnss_notif_hdle)) {
-		pr_err("wcnss: register event notification failed!\n");
+		wcnss_log(ERR, "register event notification failed!\n");
 		return PTR_ERR(penv->wcnss_notif_hdle);
 	}
 
@@ -3534,7 +3602,7 @@
 	 * device so that we know that WCNSS configuration can take
 	 * place
 	 */
-	pr_info(DEVICE " probed in built-in mode\n");
+	wcnss_log(INFO, DEVICE " probed in built-in mode\n");
 
 	return wcnss_cdev_register(pdev);
 }
@@ -3579,6 +3647,11 @@
 
 static int __init wcnss_wlan_init(void)
 {
+
+	wcnss_ipc_log = ipc_log_context_create(IPC_NUM_LOG_PAGES, "wcnss", 0);
+	if (!wcnss_ipc_log)
+		wcnss_log(ERR, "Unable to create log context\n");
+
 	platform_driver_register(&wcnss_wlan_driver);
 	platform_driver_register(&wcnss_wlan_ctrl_driver);
 	platform_driver_register(&wcnss_ctrl_driver);
@@ -3599,6 +3672,8 @@
 	platform_driver_unregister(&wcnss_ctrl_driver);
 	platform_driver_unregister(&wcnss_wlan_ctrl_driver);
 	platform_driver_unregister(&wcnss_wlan_driver);
+	ipc_log_context_destroy(wcnss_ipc_log);
+	wcnss_ipc_log = NULL;
 }
 
 module_init(wcnss_wlan_init);
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 6ee1da0..fc96f62 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -156,7 +156,6 @@
 config SPI_BCM_QSPI
 	tristate "Broadcom BSPI and MSPI controller support"
 	depends on ARCH_BRCMSTB || ARCH_BCM || ARCH_BCM_IPROC || COMPILE_TEST
-	depends on MTD_NORFLASH
 	default ARCH_BCM_IPROC
 	help
 	  Enables support for the Broadcom SPI flash and MSPI controller.
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index 02fb967..0d8f43a 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -646,7 +646,7 @@
 			buf = t->rx_buf;
 		t->rx_dma = dma_map_single(&spi->dev, buf,
 				t->len, DMA_FROM_DEVICE);
-		if (dma_mapping_error(&spi->dev, !t->rx_dma)) {
+		if (dma_mapping_error(&spi->dev, t->rx_dma)) {
 			ret = -EFAULT;
 			goto err_rx_map;
 		}
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index a074763..dfa387c 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -356,9 +356,6 @@
 	if (mode & SPI_CPHA)
 		flags |= GSI_CPHA;
 
-	if (xfer->cs_change)
-		flags |= GSI_CS_TOGGLE;
-
 	word_len = xfer->bits_per_word - MIN_WORD_LEN;
 	pack |= (GSI_TX_PACK_EN | GSI_RX_PACK_EN);
 	ret = get_spi_clk_cfg(mas->cur_speed_hz, mas, &idx, &div);
@@ -586,8 +583,11 @@
 	}
 
 	cs |= spi_slv->chip_select;
-	if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers))
-		go_flags |= FRAGMENTATION;
+	if (!xfer->cs_change) {
+		if (!list_is_last(&xfer->transfer_list,
+					&spi->cur_msg->transfers))
+			go_flags |= FRAGMENTATION;
+	}
 	go_tre = setup_go_tre(cmd, cs, rx_len, go_flags, mas);
 
 	sg_init_table(xfer_tx_sg, tx_nent);
@@ -940,8 +940,6 @@
 		m_cmd = SPI_RX_ONLY;
 
 	spi_tx_cfg &= ~CS_TOGGLE;
-	if (xfer->cs_change)
-		spi_tx_cfg |= CS_TOGGLE;
 	if (!(mas->cur_word_len % MIN_WORD_LEN)) {
 		trans_len =
 			((xfer->len << 3) / mas->cur_word_len) & TRANS_LEN_MSK;
@@ -950,8 +948,12 @@
 
 		trans_len = (xfer->len / bytes_per_word) & TRANS_LEN_MSK;
 	}
-	if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers))
-		m_param |= FRAGMENTATION;
+
+	if (!xfer->cs_change) {
+		if (!list_is_last(&xfer->transfer_list,
+					&spi->cur_msg->transfers))
+			m_param |= FRAGMENTATION;
+	}
 
 	mas->cur_xfer = xfer;
 	if (m_cmd & SPI_TX_ONLY) {
@@ -966,8 +968,9 @@
 	geni_write_reg(spi_tx_cfg, mas->base, SE_SPI_TRANS_CFG);
 	geni_setup_m_cmd(mas->base, m_cmd, m_param);
 	GENI_SE_DBG(mas->ipc, false, mas->dev,
-		"%s: trans_len %d xferlen%d tx_cfg 0x%x cmd 0x%x\n",
-		__func__, trans_len, xfer->len, spi_tx_cfg, m_cmd);
+		"%s: trans_len %d xferlen%d tx_cfg 0x%x cmd 0x%x cs %d\n",
+		__func__, trans_len, xfer->len, spi_tx_cfg, m_cmd,
+		xfer->cs_change);
 	if (m_cmd & SPI_TX_ONLY)
 		geni_write_reg(mas->tx_wm, mas->base, SE_GENI_TX_WATERMARK_REG);
 	/* Ensure all writes are done before the WM interrupt */
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 6db8063..c2e85e2 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -743,8 +743,14 @@
 	for (i = 0; i < sgs; i++) {
 
 		if (vmalloced_buf || kmap_buf) {
-			min = min_t(size_t,
-				    len, desc_len - offset_in_page(buf));
+			/*
+			 * Next scatterlist entry size is the minimum between
+			 * the desc_len and the remaining buffer length that
+			 * fits in a page.
+			 */
+			min = min_t(size_t, desc_len,
+				    min_t(size_t, len,
+					  PAGE_SIZE - offset_in_page(buf)));
 			if (vmalloced_buf)
 				vm_page = vmalloc_to_page(buf);
 			else
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index 7bd27a4..a17c483 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -33,6 +33,15 @@
 	  /sys/module/lowmemorykiller/parameters/adj and convert them
 	  to oom_score_adj values.
 
+config ANDROID_VSOC
+	tristate "Android Virtual SoC support"
+	default n
+	depends on PCI_MSI
+	---help---
+	  This option adds support for the Virtual SoC driver needed to boot
+	  a 'cuttlefish' Android image inside QEmu. The driver interacts with
+	  a QEmu ivshmem device. If built as a module, it will be called vsoc.
+
 source "drivers/staging/android/ion/Kconfig"
 
 source "drivers/staging/android/fiq_debugger/Kconfig"
diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile
index 21b0ff4..93c5f5a 100644
--- a/drivers/staging/android/Makefile
+++ b/drivers/staging/android/Makefile
@@ -5,3 +5,4 @@
 
 obj-$(CONFIG_ASHMEM)			+= ashmem.o
 obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER)	+= lowmemorykiller.o
+obj-$(CONFIG_ANDROID_VSOC)		+= vsoc.o
diff --git a/drivers/staging/android/TODO b/drivers/staging/android/TODO
index 64d8c87..dd64148 100644
--- a/drivers/staging/android/TODO
+++ b/drivers/staging/android/TODO
@@ -33,5 +33,15 @@
  - clean up and ABI check for security issues
  - move it to drivers/base/dma-buf
 
+vsoc.c, uapi/vsoc_shm.h
+ - The current driver uses the same wait queue for all of the futexes in a
+   region. This will cause false wakeups in regions with a large number of
+   waiting threads. We should eventually use multiple queues and select the
+   queue based on the region.
+ - Add debugfs support for examining the permissions of regions.
+ - Use ioremap_wc instead of ioremap_nocache.
+ - Remove VSOC_WAIT_FOR_INCOMING_INTERRUPT ioctl. This functionality has been
+   superseded by the futex and is there for legacy reasons.
+
 Please send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc:
 Arve Hjønnevåg <arve@android.com> and Riley Andrews <riandrews@android.com>
diff --git a/drivers/staging/android/uapi/vsoc_shm.h b/drivers/staging/android/uapi/vsoc_shm.h
new file mode 100644
index 0000000..741b138
--- /dev/null
+++ b/drivers/staging/android/uapi/vsoc_shm.h
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2017 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _UAPI_LINUX_VSOC_SHM_H
+#define _UAPI_LINUX_VSOC_SHM_H
+
+#include <linux/types.h>
+
+/**
+ * A permission is a token that permits a receiver to read and/or write an area
+ * of memory within a Vsoc region.
+ *
+ * An fd_scoped permission grants both read and write access, and can be
+ * attached to a file description (see open(2)).
+ * Ownership of the area can then be shared by passing a file descriptor
+ * among processes.
+ *
+ * begin_offset and end_offset define the area of memory that is controlled by
+ * the permission. owner_offset points to a word, also in shared memory, that
+ * controls ownership of the area.
+ *
+ * ownership of the region expires when the associated file description is
+ * released.
+ *
+ * At most one permission can be attached to each file description.
+ *
+ * This is useful when implementing HALs like gralloc that scope and pass
+ * ownership of shared resources via file descriptors.
+ *
+ * The caller is responsibe for doing any fencing.
+ *
+ * The calling process will normally identify a currently free area of
+ * memory. It will construct a proposed fd_scoped_permission_arg structure:
+ *
+ *   begin_offset and end_offset describe the area being claimed
+ *
+ *   owner_offset points to the location in shared memory that indicates the
+ *   owner of the area.
+ *
+ *   owned_value is the value that will be stored in owner_offset iff the
+ *   permission can be granted. It must be different than VSOC_REGION_FREE.
+ *
+ * Two fd_scoped_permission structures are compatible if they vary only by
+ * their owned_value fields.
+ *
+ * The driver ensures that, for any group of simultaneous callers proposing
+ * compatible fd_scoped_permissions, it will accept exactly one of the
+ * propopsals. The other callers will get a failure with errno of EAGAIN.
+ *
+ * A process receiving a file descriptor can identify the region being
+ * granted using the VSOC_GET_FD_SCOPED_PERMISSION ioctl.
+ */
+struct fd_scoped_permission {
+	__u32 begin_offset;
+	__u32 end_offset;
+	__u32 owner_offset;
+	__u32 owned_value;
+};
+
+/*
+ * This value represents a free area of memory. The driver expects to see this
+ * value at owner_offset when creating a permission otherwise it will not do it,
+ * and will write this value back once the permission is no longer needed.
+ */
+#define VSOC_REGION_FREE ((__u32)0)
+
+/**
+ * ioctl argument for VSOC_CREATE_FD_SCOPE_PERMISSION
+ */
+struct fd_scoped_permission_arg {
+	struct fd_scoped_permission perm;
+	__s32 managed_region_fd;
+};
+
+#define VSOC_NODE_FREE ((__u32)0)
+
+/*
+ * Describes a signal table in shared memory. Each non-zero entry in the
+ * table indicates that the receiver should signal the futex at the given
+ * offset. Offsets are relative to the region, not the shared memory window.
+ *
+ * interrupt_signalled_offset is used to reliably signal interrupts across the
+ * vmm boundary. There are two roles: transmitter and receiver. For example,
+ * in the host_to_guest_signal_table the host is the transmitter and the
+ * guest is the receiver. The protocol is as follows:
+ *
+ * 1. The transmitter should convert the offset of the futex to an offset
+ *    in the signal table [0, (1 << num_nodes_lg2))
+ *    The transmitter can choose any appropriate hashing algorithm, including
+ *    hash = futex_offset & ((1 << num_nodes_lg2) - 1)
+ *
+ * 3. The transmitter should atomically compare and swap futex_offset with 0
+ *    at hash. There are 3 possible outcomes
+ *      a. The swap fails because the futex_offset is already in the table.
+ *         The transmitter should stop.
+ *      b. Some other offset is in the table. This is a hash collision. The
+ *         transmitter should move to another table slot and try again. One
+ *         possible algorithm:
+ *         hash = (hash + 1) & ((1 << num_nodes_lg2) - 1)
+ *      c. The swap worked. Continue below.
+ *
+ * 3. The transmitter atomically swaps 1 with the value at the
+ *    interrupt_signalled_offset. There are two outcomes:
+ *      a. The prior value was 1. In this case an interrupt has already been
+ *         posted. The transmitter is done.
+ *      b. The prior value was 0, indicating that the receiver may be sleeping.
+ *         The transmitter will issue an interrupt.
+ *
+ * 4. On waking the receiver immediately exchanges a 0 with the
+ *    interrupt_signalled_offset. If it receives a 0 then this a spurious
+ *    interrupt. That may occasionally happen in the current protocol, but
+ *    should be rare.
+ *
+ * 5. The receiver scans the signal table by atomicaly exchanging 0 at each
+ *    location. If a non-zero offset is returned from the exchange the
+ *    receiver wakes all sleepers at the given offset:
+ *      futex((int*)(region_base + old_value), FUTEX_WAKE, MAX_INT);
+ *
+ * 6. The receiver thread then does a conditional wait, waking immediately
+ *    if the value at interrupt_signalled_offset is non-zero. This catches cases
+ *    here additional  signals were posted while the table was being scanned.
+ *    On the guest the wait is handled via the VSOC_WAIT_FOR_INCOMING_INTERRUPT
+ *    ioctl.
+ */
+struct vsoc_signal_table_layout {
+	/* log_2(Number of signal table entries) */
+	__u32 num_nodes_lg2;
+	/*
+	 * Offset to the first signal table entry relative to the start of the
+	 * region
+	 */
+	__u32 futex_uaddr_table_offset;
+	/*
+	 * Offset to an atomic_t / atomic uint32_t. A non-zero value indicates
+	 * that one or more offsets are currently posted in the table.
+	 * semi-unique access to an entry in the table
+	 */
+	__u32 interrupt_signalled_offset;
+};
+
+#define VSOC_REGION_WHOLE ((__s32)0)
+#define VSOC_DEVICE_NAME_SZ 16
+
+/**
+ * Each HAL would (usually) talk to a single device region
+ * Mulitple entities care about these regions:
+ * - The ivshmem_server will populate the regions in shared memory
+ * - The guest kernel will read the region, create minor device nodes, and
+ *   allow interested parties to register for FUTEX_WAKE events in the region
+ * - HALs will access via the minor device nodes published by the guest kernel
+ * - Host side processes will access the region via the ivshmem_server:
+ *   1. Pass name to ivshmem_server at a UNIX socket
+ *   2. ivshmemserver will reply with 2 fds:
+ *     - host->guest doorbell fd
+ *     - guest->host doorbell fd
+ *     - fd for the shared memory region
+ *     - region offset
+ *   3. Start a futex receiver thread on the doorbell fd pointed at the
+ *      signal_nodes
+ */
+struct vsoc_device_region {
+	__u16 current_version;
+	__u16 min_compatible_version;
+	__u32 region_begin_offset;
+	__u32 region_end_offset;
+	__u32 offset_of_region_data;
+	struct vsoc_signal_table_layout guest_to_host_signal_table;
+	struct vsoc_signal_table_layout host_to_guest_signal_table;
+	/* Name of the device. Must always be terminated with a '\0', so
+	 * the longest supported device name is 15 characters.
+	 */
+	char device_name[VSOC_DEVICE_NAME_SZ];
+	/* There are two ways that permissions to access regions are handled:
+	 *   - When subdivided_by is VSOC_REGION_WHOLE, any process that can
+	 *     open the device node for the region gains complete access to it.
+	 *   - When subdivided is set processes that open the region cannot
+	 *     access it. Access to a sub-region must be established by invoking
+	 *     the VSOC_CREATE_FD_SCOPE_PERMISSION ioctl on the region
+	 *     referenced in subdivided_by, providing a fileinstance
+	 *     (represented by a fd) opened on this region.
+	 */
+	__u32 managed_by;
+};
+
+/*
+ * The vsoc layout descriptor.
+ * The first 4K should be reserved for the shm header and region descriptors.
+ * The regions should be page aligned.
+ */
+
+struct vsoc_shm_layout_descriptor {
+	__u16 major_version;
+	__u16 minor_version;
+
+	/* size of the shm. This may be redundant but nice to have */
+	__u32 size;
+
+	/* number of shared memory regions */
+	__u32 region_count;
+
+	/* The offset to the start of region descriptors */
+	__u32 vsoc_region_desc_offset;
+};
+
+/*
+ * This specifies the current version that should be stored in
+ * vsoc_shm_layout_descriptor.major_version and
+ * vsoc_shm_layout_descriptor.minor_version.
+ * It should be updated only if the vsoc_device_region and
+ * vsoc_shm_layout_descriptor structures have changed.
+ * Versioning within each region is transferred
+ * via the min_compatible_version and current_version fields in
+ * vsoc_device_region. The driver does not consult these fields: they are left
+ * for the HALs and host processes and will change independently of the layout
+ * version.
+ */
+#define CURRENT_VSOC_LAYOUT_MAJOR_VERSION 2
+#define CURRENT_VSOC_LAYOUT_MINOR_VERSION 0
+
+#define VSOC_CREATE_FD_SCOPED_PERMISSION \
+	_IOW(0xF5, 0, struct fd_scoped_permission)
+#define VSOC_GET_FD_SCOPED_PERMISSION _IOR(0xF5, 1, struct fd_scoped_permission)
+
+/*
+ * This is used to signal the host to scan the guest_to_host_signal_table
+ * for new futexes to wake. This sends an interrupt if one is not already
+ * in flight.
+ */
+#define VSOC_MAYBE_SEND_INTERRUPT_TO_HOST _IO(0xF5, 2)
+
+/*
+ * When this returns the guest will scan host_to_guest_signal_table to
+ * check for new futexes to wake.
+ */
+/* TODO(ghartman): Consider moving this to the bottom half */
+#define VSOC_WAIT_FOR_INCOMING_INTERRUPT _IO(0xF5, 3)
+
+/*
+ * Guest HALs will use this to retrieve the region description after
+ * opening their device node.
+ */
+#define VSOC_DESCRIBE_REGION _IOR(0xF5, 4, struct vsoc_device_region)
+
+/*
+ * Wake any threads that may be waiting for a host interrupt on this region.
+ * This is mostly used during shutdown.
+ */
+#define VSOC_SELF_INTERRUPT _IO(0xF5, 5)
+
+/*
+ * This is used to signal the host to scan the guest_to_host_signal_table
+ * for new futexes to wake. This sends an interrupt unconditionally.
+ */
+#define VSOC_SEND_INTERRUPT_TO_HOST _IO(0xF5, 6)
+
+enum wait_types {
+	VSOC_WAIT_UNDEFINED = 0,
+	VSOC_WAIT_IF_EQUAL = 1,
+	VSOC_WAIT_IF_EQUAL_TIMEOUT = 2
+};
+
+/*
+ * Wait for a condition to be true
+ *
+ * Note, this is sized and aligned so the 32 bit and 64 bit layouts are
+ * identical.
+ */
+struct vsoc_cond_wait {
+	/* Input: Offset of the 32 bit word to check */
+	__u32 offset;
+	/* Input: Value that will be compared with the offset */
+	__u32 value;
+	/* Monotonic time to wake at in seconds */
+	__u64 wake_time_sec;
+	/* Input: Monotonic time to wait in nanoseconds */
+	__u32 wake_time_nsec;
+	/* Input: Type of wait */
+	__u32 wait_type;
+	/* Output: Number of times the thread woke before returning. */
+	__u32 wakes;
+	/* Ensure that we're 8-byte aligned and 8 byte length for 32/64 bit
+	 * compatibility.
+	 */
+	__u32 reserved_1;
+};
+
+#define VSOC_COND_WAIT _IOWR(0xF5, 7, struct vsoc_cond_wait)
+
+/* Wake any local threads waiting at the offset given in arg */
+#define VSOC_COND_WAKE _IO(0xF5, 8)
+
+#endif /* _UAPI_LINUX_VSOC_SHM_H */
diff --git a/drivers/staging/android/vsoc.c b/drivers/staging/android/vsoc.c
new file mode 100644
index 0000000..587c66d7
--- /dev/null
+++ b/drivers/staging/android/vsoc.c
@@ -0,0 +1,1169 @@
+/*
+ * drivers/android/staging/vsoc.c
+ *
+ * Android Virtual System on a Chip (VSoC) driver
+ *
+ * Copyright (C) 2017 Google, Inc.
+ *
+ * Author: ghartman@google.com
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * Based on drivers/char/kvm_ivshmem.c - driver for KVM Inter-VM shared memory
+ *         Copyright 2009 Cam Macdonell <cam@cs.ualberta.ca>
+ *
+ * Based on cirrusfb.c and 8139cp.c:
+ *   Copyright 1999-2001 Jeff Garzik
+ *   Copyright 2001-2004 Jeff Garzik
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/freezer.h>
+#include <linux/futex.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/cdev.h>
+#include <linux/file.h>
+#include "uapi/vsoc_shm.h"
+
+#define VSOC_DEV_NAME "vsoc"
+
+/*
+ * Description of the ivshmem-doorbell PCI device used by QEmu. These
+ * constants follow docs/specs/ivshmem-spec.txt, which can be found in
+ * the QEmu repository. This was last reconciled with the version that
+ * came out with 2.8
+ */
+
+/*
+ * These constants are determined KVM Inter-VM shared memory device
+ * register offsets
+ */
+enum {
+	INTR_MASK = 0x00,	/* Interrupt Mask */
+	INTR_STATUS = 0x04,	/* Interrupt Status */
+	IV_POSITION = 0x08,	/* VM ID */
+	DOORBELL = 0x0c,	/* Doorbell */
+};
+
+static const int REGISTER_BAR;  /* Equal to 0 */
+static const int MAX_REGISTER_BAR_LEN = 0x100;
+/*
+ * The MSI-x BAR is not used directly.
+ *
+ * static const int MSI_X_BAR = 1;
+ */
+static const int SHARED_MEMORY_BAR = 2;
+
+struct vsoc_region_data {
+	char name[VSOC_DEVICE_NAME_SZ + 1];
+	wait_queue_head_t interrupt_wait_queue;
+	/* TODO(b/73664181): Use multiple futex wait queues */
+	wait_queue_head_t futex_wait_queue;
+	/* Flag indicating that an interrupt has been signalled by the host. */
+	atomic_t *incoming_signalled;
+	/* Flag indicating the guest has signalled the host. */
+	atomic_t *outgoing_signalled;
+	int irq_requested;
+	int device_created;
+};
+
+struct vsoc_device {
+	/* Kernel virtual address of REGISTER_BAR. */
+	void __iomem *regs;
+	/* Physical address of SHARED_MEMORY_BAR. */
+	phys_addr_t shm_phys_start;
+	/* Kernel virtual address of SHARED_MEMORY_BAR. */
+	void *kernel_mapped_shm;
+	/* Size of the entire shared memory window in bytes. */
+	size_t shm_size;
+	/*
+	 * Pointer to the virtual address of the shared memory layout structure.
+	 * This is probably identical to kernel_mapped_shm, but saving this
+	 * here saves a lot of annoying casts.
+	 */
+	struct vsoc_shm_layout_descriptor *layout;
+	/*
+	 * Points to a table of region descriptors in the kernel's virtual
+	 * address space. Calculated from
+	 * vsoc_shm_layout_descriptor.vsoc_region_desc_offset
+	 */
+	struct vsoc_device_region *regions;
+	/* Head of a list of permissions that have been granted. */
+	struct list_head permissions;
+	struct pci_dev *dev;
+	/* Per-region (and therefore per-interrupt) information. */
+	struct vsoc_region_data *regions_data;
+	/*
+	 * Table of msi-x entries. This has to be separated from struct
+	 * vsoc_region_data because the kernel deals with them as an array.
+	 */
+	struct msix_entry *msix_entries;
+	/*
+	 * Flags that indicate what we've initialzied. These are used to do an
+	 * orderly cleanup of the device.
+	 */
+	char enabled_device;
+	char requested_regions;
+	char cdev_added;
+	char class_added;
+	char msix_enabled;
+	/* Mutex that protectes the permission list */
+	struct mutex mtx;
+	/* Major number assigned by the kernel */
+	int major;
+
+	struct cdev cdev;
+	struct class *class;
+};
+
+static struct vsoc_device vsoc_dev;
+
+/*
+ * TODO(ghartman): Add a /sys filesystem entry that summarizes the permissions.
+ */
+
+struct fd_scoped_permission_node {
+	struct fd_scoped_permission permission;
+	struct list_head list;
+};
+
+struct vsoc_private_data {
+	struct fd_scoped_permission_node *fd_scoped_permission_node;
+};
+
+static long vsoc_ioctl(struct file *, unsigned int, unsigned long);
+static int vsoc_mmap(struct file *, struct vm_area_struct *);
+static int vsoc_open(struct inode *, struct file *);
+static int vsoc_release(struct inode *, struct file *);
+static ssize_t vsoc_read(struct file *, char *, size_t, loff_t *);
+static ssize_t vsoc_write(struct file *, const char *, size_t, loff_t *);
+static loff_t vsoc_lseek(struct file *filp, loff_t offset, int origin);
+static int do_create_fd_scoped_permission(
+	struct vsoc_device_region *region_p,
+	struct fd_scoped_permission_node *np,
+	struct fd_scoped_permission_arg *__user arg);
+static void do_destroy_fd_scoped_permission(
+	struct vsoc_device_region *owner_region_p,
+	struct fd_scoped_permission *perm);
+static long do_vsoc_describe_region(struct file *,
+				    struct vsoc_device_region __user *);
+static ssize_t vsoc_get_area(struct file *filp, __u32 *perm_off);
+
+/**
+ * Validate arguments on entry points to the driver.
+ */
+inline int vsoc_validate_inode(struct inode *inode)
+{
+	if (iminor(inode) >= vsoc_dev.layout->region_count) {
+		dev_err(&vsoc_dev.dev->dev,
+			"describe_region: invalid region %d\n", iminor(inode));
+		return -ENODEV;
+	}
+	return 0;
+}
+
+inline int vsoc_validate_filep(struct file *filp)
+{
+	int ret = vsoc_validate_inode(file_inode(filp));
+
+	if (ret)
+		return ret;
+	if (!filp->private_data) {
+		dev_err(&vsoc_dev.dev->dev,
+			"No private data on fd, region %d\n",
+			iminor(file_inode(filp)));
+		return -EBADFD;
+	}
+	return 0;
+}
+
+/* Converts from shared memory offset to virtual address */
+static inline void *shm_off_to_virtual_addr(__u32 offset)
+{
+	return vsoc_dev.kernel_mapped_shm + offset;
+}
+
+/* Converts from shared memory offset to physical address */
+static inline phys_addr_t shm_off_to_phys_addr(__u32 offset)
+{
+	return vsoc_dev.shm_phys_start + offset;
+}
+
+/**
+ * Convenience functions to obtain the region from the inode or file.
+ * Dangerous to call before validating the inode/file.
+ */
+static inline struct vsoc_device_region *vsoc_region_from_inode(
+	struct inode *inode)
+{
+	return &vsoc_dev.regions[iminor(inode)];
+}
+
+static inline struct vsoc_device_region *vsoc_region_from_filep(
+	struct file *inode)
+{
+	return vsoc_region_from_inode(file_inode(inode));
+}
+
+static inline uint32_t vsoc_device_region_size(struct vsoc_device_region *r)
+{
+	return r->region_end_offset - r->region_begin_offset;
+}
+
+static const struct file_operations vsoc_ops = {
+	.owner = THIS_MODULE,
+	.open = vsoc_open,
+	.mmap = vsoc_mmap,
+	.read = vsoc_read,
+	.unlocked_ioctl = vsoc_ioctl,
+	.compat_ioctl = vsoc_ioctl,
+	.write = vsoc_write,
+	.llseek = vsoc_lseek,
+	.release = vsoc_release,
+};
+
+static struct pci_device_id vsoc_id_table[] = {
+	{0x1af4, 0x1110, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0},
+};
+
+MODULE_DEVICE_TABLE(pci, vsoc_id_table);
+
+static void vsoc_remove_device(struct pci_dev *pdev);
+static int vsoc_probe_device(struct pci_dev *pdev,
+			     const struct pci_device_id *ent);
+
+static struct pci_driver vsoc_pci_driver = {
+	.name = "vsoc",
+	.id_table = vsoc_id_table,
+	.probe = vsoc_probe_device,
+	.remove = vsoc_remove_device,
+};
+
+static int do_create_fd_scoped_permission(
+	struct vsoc_device_region *region_p,
+	struct fd_scoped_permission_node *np,
+	struct fd_scoped_permission_arg *__user arg)
+{
+	struct file *managed_filp;
+	s32 managed_fd;
+	atomic_t *owner_ptr = NULL;
+	struct vsoc_device_region *managed_region_p;
+
+	if (copy_from_user(&np->permission, &arg->perm, sizeof(*np)) ||
+	    copy_from_user(&managed_fd,
+			   &arg->managed_region_fd, sizeof(managed_fd))) {
+		return -EFAULT;
+	}
+	managed_filp = fdget(managed_fd).file;
+	/* Check that it's a valid fd, */
+	if (!managed_filp || vsoc_validate_filep(managed_filp))
+		return -EPERM;
+	/* EEXIST if the given fd already has a permission. */
+	if (((struct vsoc_private_data *)managed_filp->private_data)->
+	    fd_scoped_permission_node)
+		return -EEXIST;
+	managed_region_p = vsoc_region_from_filep(managed_filp);
+	/* Check that the provided region is managed by this one */
+	if (&vsoc_dev.regions[managed_region_p->managed_by] != region_p)
+		return -EPERM;
+	/* The area must be well formed and have non-zero size */
+	if (np->permission.begin_offset >= np->permission.end_offset)
+		return -EINVAL;
+	/* The area must fit in the memory window */
+	if (np->permission.end_offset >
+	    vsoc_device_region_size(managed_region_p))
+		return -ERANGE;
+	/* The area must be in the region data section */
+	if (np->permission.begin_offset <
+	    managed_region_p->offset_of_region_data)
+		return -ERANGE;
+	/* The area must be page aligned */
+	if (!PAGE_ALIGNED(np->permission.begin_offset) ||
+	    !PAGE_ALIGNED(np->permission.end_offset))
+		return -EINVAL;
+	/* Owner offset must be naturally aligned in the window */
+	if (np->permission.owner_offset &
+	    (sizeof(np->permission.owner_offset) - 1))
+		return -EINVAL;
+	/* The owner flag must reside in the owner memory */
+	if (np->permission.owner_offset + sizeof(np->permission.owner_offset) >
+	    vsoc_device_region_size(region_p))
+		return -ERANGE;
+	/* The owner flag must reside in the data section */
+	if (np->permission.owner_offset < region_p->offset_of_region_data)
+		return -EINVAL;
+	/* The owner value must change to claim the memory */
+	if (np->permission.owned_value == VSOC_REGION_FREE)
+		return -EINVAL;
+	owner_ptr =
+	    (atomic_t *)shm_off_to_virtual_addr(region_p->region_begin_offset +
+						np->permission.owner_offset);
+	/* We've already verified that this is in the shared memory window, so
+	 * it should be safe to write to this address.
+	 */
+	if (atomic_cmpxchg(owner_ptr,
+			   VSOC_REGION_FREE,
+			   np->permission.owned_value) != VSOC_REGION_FREE) {
+		return -EBUSY;
+	}
+	((struct vsoc_private_data *)managed_filp->private_data)->
+	    fd_scoped_permission_node = np;
+	/* The file offset needs to be adjusted if the calling
+	 * process did any read/write operations on the fd
+	 * before creating the permission.
+	 */
+	if (managed_filp->f_pos) {
+		if (managed_filp->f_pos > np->permission.end_offset) {
+			/* If the offset is beyond the permission end, set it
+			 * to the end.
+			 */
+			managed_filp->f_pos = np->permission.end_offset;
+		} else {
+			/* If the offset is within the permission interval
+			 * keep it there otherwise reset it to zero.
+			 */
+			if (managed_filp->f_pos < np->permission.begin_offset) {
+				managed_filp->f_pos = 0;
+			} else {
+				managed_filp->f_pos -=
+				    np->permission.begin_offset;
+			}
+		}
+	}
+	return 0;
+}
+
+static void do_destroy_fd_scoped_permission_node(
+	struct vsoc_device_region *owner_region_p,
+	struct fd_scoped_permission_node *node)
+{
+	if (node) {
+		do_destroy_fd_scoped_permission(owner_region_p,
+						&node->permission);
+		mutex_lock(&vsoc_dev.mtx);
+		list_del(&node->list);
+		mutex_unlock(&vsoc_dev.mtx);
+		kfree(node);
+	}
+}
+
+static void do_destroy_fd_scoped_permission(
+		struct vsoc_device_region *owner_region_p,
+		struct fd_scoped_permission *perm)
+{
+	atomic_t *owner_ptr = NULL;
+	int prev = 0;
+
+	if (!perm)
+		return;
+	owner_ptr = (atomic_t *)shm_off_to_virtual_addr(
+		owner_region_p->region_begin_offset + perm->owner_offset);
+	prev = atomic_xchg(owner_ptr, VSOC_REGION_FREE);
+	if (prev != perm->owned_value)
+		dev_err(&vsoc_dev.dev->dev,
+			"%x-%x: owner (%s) %x: expected to be %x was %x",
+			perm->begin_offset, perm->end_offset,
+			owner_region_p->device_name, perm->owner_offset,
+			perm->owned_value, prev);
+}
+
+static long do_vsoc_describe_region(struct file *filp,
+				    struct vsoc_device_region __user *dest)
+{
+	struct vsoc_device_region *region_p;
+	int retval = vsoc_validate_filep(filp);
+
+	if (retval)
+		return retval;
+	region_p = vsoc_region_from_filep(filp);
+	if (copy_to_user(dest, region_p, sizeof(*region_p)))
+		return -EFAULT;
+	return 0;
+}
+
+/**
+ * Implements the inner logic of cond_wait. Copies to and from userspace are
+ * done in the helper function below.
+ */
+static int handle_vsoc_cond_wait(struct file *filp, struct vsoc_cond_wait *arg)
+{
+	DEFINE_WAIT(wait);
+	u32 region_number = iminor(file_inode(filp));
+	struct vsoc_region_data *data = vsoc_dev.regions_data + region_number;
+	struct hrtimer_sleeper timeout, *to = NULL;
+	int ret = 0;
+	struct vsoc_device_region *region_p = vsoc_region_from_filep(filp);
+	atomic_t *address = NULL;
+	struct timespec ts;
+
+	/* Ensure that the offset is aligned */
+	if (arg->offset & (sizeof(uint32_t) - 1))
+		return -EADDRNOTAVAIL;
+	/* Ensure that the offset is within shared memory */
+	if (((uint64_t)arg->offset) + region_p->region_begin_offset +
+	    sizeof(uint32_t) > region_p->region_end_offset)
+		return -E2BIG;
+	address = shm_off_to_virtual_addr(region_p->region_begin_offset +
+					  arg->offset);
+
+	/* Ensure that the type of wait is valid */
+	switch (arg->wait_type) {
+	case VSOC_WAIT_IF_EQUAL:
+		break;
+	case VSOC_WAIT_IF_EQUAL_TIMEOUT:
+		to = &timeout;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (to) {
+		/* Copy the user-supplied timesec into the kernel structure.
+		 * We do things this way to flatten differences between 32 bit
+		 * and 64 bit timespecs.
+		 */
+		ts.tv_sec = arg->wake_time_sec;
+		ts.tv_nsec = arg->wake_time_nsec;
+
+		if (!timespec_valid(&ts))
+			return -EINVAL;
+		hrtimer_init_on_stack(&to->timer, CLOCK_MONOTONIC,
+				      HRTIMER_MODE_ABS);
+		hrtimer_set_expires_range_ns(&to->timer, timespec_to_ktime(ts),
+					     current->timer_slack_ns);
+
+		hrtimer_init_sleeper(to, current);
+	}
+
+	while (1) {
+		prepare_to_wait(&data->futex_wait_queue, &wait,
+				TASK_INTERRUPTIBLE);
+		/*
+		 * Check the sentinel value after prepare_to_wait. If the value
+		 * changes after this check the writer will call signal,
+		 * changing the task state from INTERRUPTIBLE to RUNNING. That
+		 * will ensure that schedule() will eventually schedule this
+		 * task.
+		 */
+		if (atomic_read(address) != arg->value) {
+			ret = 0;
+			break;
+		}
+		if (to) {
+			hrtimer_start_expires(&to->timer, HRTIMER_MODE_ABS);
+			if (likely(to->task))
+				freezable_schedule();
+			hrtimer_cancel(&to->timer);
+			if (!to->task) {
+				ret = -ETIMEDOUT;
+				break;
+			}
+		} else {
+			freezable_schedule();
+		}
+		/* Count the number of times that we woke up. This is useful
+		 * for unit testing.
+		 */
+		++arg->wakes;
+		if (signal_pending(current)) {
+			ret = -EINTR;
+			break;
+		}
+	}
+	finish_wait(&data->futex_wait_queue, &wait);
+	if (to)
+		destroy_hrtimer_on_stack(&to->timer);
+	return ret;
+}
+
+/**
+ * Handles the details of copying from/to userspace to ensure that the copies
+ * happen on all of the return paths of cond_wait.
+ */
+static int do_vsoc_cond_wait(struct file *filp,
+			     struct vsoc_cond_wait __user *untrusted_in)
+{
+	struct vsoc_cond_wait arg;
+	int rval = 0;
+
+	if (copy_from_user(&arg, untrusted_in, sizeof(arg)))
+		return -EFAULT;
+	/* wakes is an out parameter. Initialize it to something sensible. */
+	arg.wakes = 0;
+	rval = handle_vsoc_cond_wait(filp, &arg);
+	if (copy_to_user(untrusted_in, &arg, sizeof(arg)))
+		return -EFAULT;
+	return rval;
+}
+
+static int do_vsoc_cond_wake(struct file *filp, uint32_t offset)
+{
+	struct vsoc_device_region *region_p = vsoc_region_from_filep(filp);
+	u32 region_number = iminor(file_inode(filp));
+	struct vsoc_region_data *data = vsoc_dev.regions_data + region_number;
+	/* Ensure that the offset is aligned */
+	if (offset & (sizeof(uint32_t) - 1))
+		return -EADDRNOTAVAIL;
+	/* Ensure that the offset is within shared memory */
+	if (((uint64_t)offset) + region_p->region_begin_offset +
+	    sizeof(uint32_t) > region_p->region_end_offset)
+		return -E2BIG;
+	/*
+	 * TODO(b/73664181): Use multiple futex wait queues.
+	 * We need to wake every sleeper when the condition changes. Typically
+	 * only a single thread will be waiting on the condition, but there
+	 * are exceptions. The worst case is about 10 threads.
+	 */
+	wake_up_interruptible_all(&data->futex_wait_queue);
+	return 0;
+}
+
+static long vsoc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	int rv = 0;
+	struct vsoc_device_region *region_p;
+	u32 reg_num;
+	struct vsoc_region_data *reg_data;
+	int retval = vsoc_validate_filep(filp);
+
+	if (retval)
+		return retval;
+	region_p = vsoc_region_from_filep(filp);
+	reg_num = iminor(file_inode(filp));
+	reg_data = vsoc_dev.regions_data + reg_num;
+	switch (cmd) {
+	case VSOC_CREATE_FD_SCOPED_PERMISSION:
+		{
+			struct fd_scoped_permission_node *node = NULL;
+
+			node = kzalloc(sizeof(*node), GFP_KERNEL);
+			/* We can't allocate memory for the permission */
+			if (!node)
+				return -ENOMEM;
+			INIT_LIST_HEAD(&node->list);
+			rv = do_create_fd_scoped_permission(
+				region_p,
+				node,
+				(struct fd_scoped_permission_arg __user *)arg);
+			if (!rv) {
+				mutex_lock(&vsoc_dev.mtx);
+				list_add(&node->list, &vsoc_dev.permissions);
+				mutex_unlock(&vsoc_dev.mtx);
+			} else {
+				kfree(node);
+				return rv;
+			}
+		}
+		break;
+
+	case VSOC_GET_FD_SCOPED_PERMISSION:
+		{
+			struct fd_scoped_permission_node *node =
+			    ((struct vsoc_private_data *)filp->private_data)->
+			    fd_scoped_permission_node;
+			if (!node)
+				return -ENOENT;
+			if (copy_to_user
+			    ((struct fd_scoped_permission __user *)arg,
+			     &node->permission, sizeof(node->permission)))
+				return -EFAULT;
+		}
+		break;
+
+	case VSOC_MAYBE_SEND_INTERRUPT_TO_HOST:
+		if (!atomic_xchg(
+			    reg_data->outgoing_signalled,
+			    1)) {
+			writel(reg_num, vsoc_dev.regs + DOORBELL);
+			return 0;
+		} else {
+			return -EBUSY;
+		}
+		break;
+
+	case VSOC_SEND_INTERRUPT_TO_HOST:
+		writel(reg_num, vsoc_dev.regs + DOORBELL);
+		return 0;
+
+	case VSOC_WAIT_FOR_INCOMING_INTERRUPT:
+		wait_event_interruptible(
+			reg_data->interrupt_wait_queue,
+			(atomic_read(reg_data->incoming_signalled) != 0));
+		break;
+
+	case VSOC_DESCRIBE_REGION:
+		return do_vsoc_describe_region(
+			filp,
+			(struct vsoc_device_region __user *)arg);
+
+	case VSOC_SELF_INTERRUPT:
+		atomic_set(reg_data->incoming_signalled, 1);
+		wake_up_interruptible(&reg_data->interrupt_wait_queue);
+		break;
+
+	case VSOC_COND_WAIT:
+		return do_vsoc_cond_wait(filp,
+					 (struct vsoc_cond_wait __user *)arg);
+	case VSOC_COND_WAKE:
+		return do_vsoc_cond_wake(filp, arg);
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static ssize_t vsoc_read(struct file *filp, char *buffer, size_t len,
+			 loff_t *poffset)
+{
+	__u32 area_off;
+	void *area_p;
+	ssize_t area_len;
+	int retval = vsoc_validate_filep(filp);
+
+	if (retval)
+		return retval;
+	area_len = vsoc_get_area(filp, &area_off);
+	area_p = shm_off_to_virtual_addr(area_off);
+	area_p += *poffset;
+	area_len -= *poffset;
+	if (area_len <= 0)
+		return 0;
+	if (area_len < len)
+		len = area_len;
+	if (copy_to_user(buffer, area_p, len))
+		return -EFAULT;
+	*poffset += len;
+	return len;
+}
+
+static loff_t vsoc_lseek(struct file *filp, loff_t offset, int origin)
+{
+	ssize_t area_len = 0;
+	int retval = vsoc_validate_filep(filp);
+
+	if (retval)
+		return retval;
+	area_len = vsoc_get_area(filp, NULL);
+	switch (origin) {
+	case SEEK_SET:
+		break;
+
+	case SEEK_CUR:
+		if (offset > 0 && offset + filp->f_pos < 0)
+			return -EOVERFLOW;
+		offset += filp->f_pos;
+		break;
+
+	case SEEK_END:
+		if (offset > 0 && offset + area_len < 0)
+			return -EOVERFLOW;
+		offset += area_len;
+		break;
+
+	case SEEK_DATA:
+		if (offset >= area_len)
+			return -EINVAL;
+		if (offset < 0)
+			offset = 0;
+		break;
+
+	case SEEK_HOLE:
+		/* Next hole is always the end of the region, unless offset is
+		 * beyond that
+		 */
+		if (offset < area_len)
+			offset = area_len;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (offset < 0 || offset > area_len)
+		return -EINVAL;
+	filp->f_pos = offset;
+
+	return offset;
+}
+
+static ssize_t vsoc_write(struct file *filp, const char *buffer,
+			  size_t len, loff_t *poffset)
+{
+	__u32 area_off;
+	void *area_p;
+	ssize_t area_len;
+	int retval = vsoc_validate_filep(filp);
+
+	if (retval)
+		return retval;
+	area_len = vsoc_get_area(filp, &area_off);
+	area_p = shm_off_to_virtual_addr(area_off);
+	area_p += *poffset;
+	area_len -= *poffset;
+	if (area_len <= 0)
+		return 0;
+	if (area_len < len)
+		len = area_len;
+	if (copy_from_user(area_p, buffer, len))
+		return -EFAULT;
+	*poffset += len;
+	return len;
+}
+
+static irqreturn_t vsoc_interrupt(int irq, void *region_data_v)
+{
+	struct vsoc_region_data *region_data =
+	    (struct vsoc_region_data *)region_data_v;
+	int reg_num = region_data - vsoc_dev.regions_data;
+
+	if (unlikely(!region_data))
+		return IRQ_NONE;
+
+	if (unlikely(reg_num < 0 ||
+		     reg_num >= vsoc_dev.layout->region_count)) {
+		dev_err(&vsoc_dev.dev->dev,
+			"invalid irq @%p reg_num=0x%04x\n",
+			region_data, reg_num);
+		return IRQ_NONE;
+	}
+	if (unlikely(vsoc_dev.regions_data + reg_num != region_data)) {
+		dev_err(&vsoc_dev.dev->dev,
+			"irq not aligned @%p reg_num=0x%04x\n",
+			region_data, reg_num);
+		return IRQ_NONE;
+	}
+	wake_up_interruptible(&region_data->interrupt_wait_queue);
+	return IRQ_HANDLED;
+}
+
+static int vsoc_probe_device(struct pci_dev *pdev,
+			     const struct pci_device_id *ent)
+{
+	int result;
+	int i;
+	resource_size_t reg_size;
+	dev_t devt;
+
+	vsoc_dev.dev = pdev;
+	result = pci_enable_device(pdev);
+	if (result) {
+		dev_err(&pdev->dev,
+			"pci_enable_device failed %s: error %d\n",
+			pci_name(pdev), result);
+		return result;
+	}
+	vsoc_dev.enabled_device = 1;
+	result = pci_request_regions(pdev, "vsoc");
+	if (result < 0) {
+		dev_err(&pdev->dev, "pci_request_regions failed\n");
+		vsoc_remove_device(pdev);
+		return -EBUSY;
+	}
+	vsoc_dev.requested_regions = 1;
+	/* Set up the control registers in BAR 0 */
+	reg_size = pci_resource_len(pdev, REGISTER_BAR);
+	if (reg_size > MAX_REGISTER_BAR_LEN)
+		vsoc_dev.regs =
+		    pci_iomap(pdev, REGISTER_BAR, MAX_REGISTER_BAR_LEN);
+	else
+		vsoc_dev.regs = pci_iomap(pdev, REGISTER_BAR, reg_size);
+
+	if (!vsoc_dev.regs) {
+		dev_err(&pdev->dev,
+			"cannot ioremap registers of size %zu\n",
+		       (size_t)reg_size);
+		vsoc_remove_device(pdev);
+		return -EBUSY;
+	}
+
+	/* Map the shared memory in BAR 2 */
+	vsoc_dev.shm_phys_start = pci_resource_start(pdev, SHARED_MEMORY_BAR);
+	vsoc_dev.shm_size = pci_resource_len(pdev, SHARED_MEMORY_BAR);
+
+	dev_info(&pdev->dev, "shared memory @ DMA %p size=0x%zx\n",
+		 (void *)vsoc_dev.shm_phys_start, vsoc_dev.shm_size);
+	/* TODO(ghartman): ioremap_wc should work here */
+	vsoc_dev.kernel_mapped_shm = ioremap_nocache(
+			vsoc_dev.shm_phys_start, vsoc_dev.shm_size);
+	if (!vsoc_dev.kernel_mapped_shm) {
+		dev_err(&vsoc_dev.dev->dev, "cannot iomap region\n");
+		vsoc_remove_device(pdev);
+		return -EBUSY;
+	}
+
+	vsoc_dev.layout =
+	    (struct vsoc_shm_layout_descriptor *)vsoc_dev.kernel_mapped_shm;
+	dev_info(&pdev->dev, "major_version: %d\n",
+		 vsoc_dev.layout->major_version);
+	dev_info(&pdev->dev, "minor_version: %d\n",
+		 vsoc_dev.layout->minor_version);
+	dev_info(&pdev->dev, "size: 0x%x\n", vsoc_dev.layout->size);
+	dev_info(&pdev->dev, "regions: %d\n", vsoc_dev.layout->region_count);
+	if (vsoc_dev.layout->major_version !=
+	    CURRENT_VSOC_LAYOUT_MAJOR_VERSION) {
+		dev_err(&vsoc_dev.dev->dev,
+			"driver supports only major_version %d\n",
+			CURRENT_VSOC_LAYOUT_MAJOR_VERSION);
+		vsoc_remove_device(pdev);
+		return -EBUSY;
+	}
+	result = alloc_chrdev_region(&devt, 0, vsoc_dev.layout->region_count,
+				     VSOC_DEV_NAME);
+	if (result) {
+		dev_err(&vsoc_dev.dev->dev, "alloc_chrdev_region failed\n");
+		vsoc_remove_device(pdev);
+		return -EBUSY;
+	}
+	vsoc_dev.major = MAJOR(devt);
+	cdev_init(&vsoc_dev.cdev, &vsoc_ops);
+	vsoc_dev.cdev.owner = THIS_MODULE;
+	result = cdev_add(&vsoc_dev.cdev, devt, vsoc_dev.layout->region_count);
+	if (result) {
+		dev_err(&vsoc_dev.dev->dev, "cdev_add error\n");
+		vsoc_remove_device(pdev);
+		return -EBUSY;
+	}
+	vsoc_dev.cdev_added = 1;
+	vsoc_dev.class = class_create(THIS_MODULE, VSOC_DEV_NAME);
+	if (IS_ERR(vsoc_dev.class)) {
+		dev_err(&vsoc_dev.dev->dev, "class_create failed\n");
+		vsoc_remove_device(pdev);
+		return PTR_ERR(vsoc_dev.class);
+	}
+	vsoc_dev.class_added = 1;
+	vsoc_dev.regions = (struct vsoc_device_region *)
+		(vsoc_dev.kernel_mapped_shm +
+		 vsoc_dev.layout->vsoc_region_desc_offset);
+	vsoc_dev.msix_entries = kcalloc(
+			vsoc_dev.layout->region_count,
+			sizeof(vsoc_dev.msix_entries[0]), GFP_KERNEL);
+	if (!vsoc_dev.msix_entries) {
+		dev_err(&vsoc_dev.dev->dev,
+			"unable to allocate msix_entries\n");
+		vsoc_remove_device(pdev);
+		return -ENOSPC;
+	}
+	vsoc_dev.regions_data = kcalloc(
+			vsoc_dev.layout->region_count,
+			sizeof(vsoc_dev.regions_data[0]), GFP_KERNEL);
+	if (!vsoc_dev.regions_data) {
+		dev_err(&vsoc_dev.dev->dev,
+			"unable to allocate regions' data\n");
+		vsoc_remove_device(pdev);
+		return -ENOSPC;
+	}
+	for (i = 0; i < vsoc_dev.layout->region_count; ++i)
+		vsoc_dev.msix_entries[i].entry = i;
+
+	result = pci_enable_msix_exact(vsoc_dev.dev, vsoc_dev.msix_entries,
+				       vsoc_dev.layout->region_count);
+	if (result) {
+		dev_info(&pdev->dev, "pci_enable_msix failed: %d\n", result);
+		vsoc_remove_device(pdev);
+		return -ENOSPC;
+	}
+	/* Check that all regions are well formed */
+	for (i = 0; i < vsoc_dev.layout->region_count; ++i) {
+		const struct vsoc_device_region *region = vsoc_dev.regions + i;
+
+		if (!PAGE_ALIGNED(region->region_begin_offset) ||
+		    !PAGE_ALIGNED(region->region_end_offset)) {
+			dev_err(&vsoc_dev.dev->dev,
+				"region %d not aligned (%x:%x)", i,
+				region->region_begin_offset,
+				region->region_end_offset);
+			vsoc_remove_device(pdev);
+			return -EFAULT;
+		}
+		if (region->region_begin_offset >= region->region_end_offset ||
+		    region->region_end_offset > vsoc_dev.shm_size) {
+			dev_err(&vsoc_dev.dev->dev,
+				"region %d offsets are wrong: %x %x %zx",
+				i, region->region_begin_offset,
+				region->region_end_offset, vsoc_dev.shm_size);
+			vsoc_remove_device(pdev);
+			return -EFAULT;
+		}
+		if (region->managed_by >= vsoc_dev.layout->region_count) {
+			dev_err(&vsoc_dev.dev->dev,
+				"region %d has invalid owner: %u",
+				i, region->managed_by);
+			vsoc_remove_device(pdev);
+			return -EFAULT;
+		}
+	}
+	vsoc_dev.msix_enabled = 1;
+	for (i = 0; i < vsoc_dev.layout->region_count; ++i) {
+		const struct vsoc_device_region *region = vsoc_dev.regions + i;
+		size_t name_sz = sizeof(vsoc_dev.regions_data[i].name) - 1;
+		const struct vsoc_signal_table_layout *h_to_g_signal_table =
+			&region->host_to_guest_signal_table;
+		const struct vsoc_signal_table_layout *g_to_h_signal_table =
+			&region->guest_to_host_signal_table;
+
+		vsoc_dev.regions_data[i].name[name_sz] = '\0';
+		memcpy(vsoc_dev.regions_data[i].name, region->device_name,
+		       name_sz);
+		dev_info(&pdev->dev, "region %d name=%s\n",
+			 i, vsoc_dev.regions_data[i].name);
+		init_waitqueue_head(
+				&vsoc_dev.regions_data[i].interrupt_wait_queue);
+		init_waitqueue_head(&vsoc_dev.regions_data[i].futex_wait_queue);
+		vsoc_dev.regions_data[i].incoming_signalled =
+			vsoc_dev.kernel_mapped_shm +
+			region->region_begin_offset +
+			h_to_g_signal_table->interrupt_signalled_offset;
+		vsoc_dev.regions_data[i].outgoing_signalled =
+			vsoc_dev.kernel_mapped_shm +
+			region->region_begin_offset +
+			g_to_h_signal_table->interrupt_signalled_offset;
+
+		result = request_irq(
+				vsoc_dev.msix_entries[i].vector,
+				vsoc_interrupt, 0,
+				vsoc_dev.regions_data[i].name,
+				vsoc_dev.regions_data + i);
+		if (result) {
+			dev_info(&pdev->dev,
+				 "request_irq failed irq=%d vector=%d\n",
+				i, vsoc_dev.msix_entries[i].vector);
+			vsoc_remove_device(pdev);
+			return -ENOSPC;
+		}
+		vsoc_dev.regions_data[i].irq_requested = 1;
+		if (!device_create(vsoc_dev.class, NULL,
+				   MKDEV(vsoc_dev.major, i),
+				   NULL, vsoc_dev.regions_data[i].name)) {
+			dev_err(&vsoc_dev.dev->dev, "device_create failed\n");
+			vsoc_remove_device(pdev);
+			return -EBUSY;
+		}
+		vsoc_dev.regions_data[i].device_created = 1;
+	}
+	return 0;
+}
+
+/*
+ * This should undo all of the allocations in the probe function in reverse
+ * order.
+ *
+ * Notes:
+ *
+ *   The device may have been partially initialized, so double check
+ *   that the allocations happened.
+ *
+ *   This function may be called multiple times, so mark resources as freed
+ *   as they are deallocated.
+ */
+static void vsoc_remove_device(struct pci_dev *pdev)
+{
+	int i;
+	/*
+	 * pdev is the first thing to be set on probe and the last thing
+	 * to be cleared here. If it's NULL then there is no cleanup.
+	 */
+	if (!pdev || !vsoc_dev.dev)
+		return;
+	dev_info(&pdev->dev, "remove_device\n");
+	if (vsoc_dev.regions_data) {
+		for (i = 0; i < vsoc_dev.layout->region_count; ++i) {
+			if (vsoc_dev.regions_data[i].device_created) {
+				device_destroy(vsoc_dev.class,
+					       MKDEV(vsoc_dev.major, i));
+				vsoc_dev.regions_data[i].device_created = 0;
+			}
+			if (vsoc_dev.regions_data[i].irq_requested)
+				free_irq(vsoc_dev.msix_entries[i].vector, NULL);
+			vsoc_dev.regions_data[i].irq_requested = 0;
+		}
+		kfree(vsoc_dev.regions_data);
+		vsoc_dev.regions_data = 0;
+	}
+	if (vsoc_dev.msix_enabled) {
+		pci_disable_msix(pdev);
+		vsoc_dev.msix_enabled = 0;
+	}
+	kfree(vsoc_dev.msix_entries);
+	vsoc_dev.msix_entries = 0;
+	vsoc_dev.regions = 0;
+	if (vsoc_dev.class_added) {
+		class_destroy(vsoc_dev.class);
+		vsoc_dev.class_added = 0;
+	}
+	if (vsoc_dev.cdev_added) {
+		cdev_del(&vsoc_dev.cdev);
+		vsoc_dev.cdev_added = 0;
+	}
+	if (vsoc_dev.major && vsoc_dev.layout) {
+		unregister_chrdev_region(MKDEV(vsoc_dev.major, 0),
+					 vsoc_dev.layout->region_count);
+		vsoc_dev.major = 0;
+	}
+	vsoc_dev.layout = 0;
+	if (vsoc_dev.kernel_mapped_shm) {
+		pci_iounmap(pdev, vsoc_dev.kernel_mapped_shm);
+		vsoc_dev.kernel_mapped_shm = 0;
+	}
+	if (vsoc_dev.regs) {
+		pci_iounmap(pdev, vsoc_dev.regs);
+		vsoc_dev.regs = 0;
+	}
+	if (vsoc_dev.requested_regions) {
+		pci_release_regions(pdev);
+		vsoc_dev.requested_regions = 0;
+	}
+	if (vsoc_dev.enabled_device) {
+		pci_disable_device(pdev);
+		vsoc_dev.enabled_device = 0;
+	}
+	/* Do this last: it indicates that the device is not initialized. */
+	vsoc_dev.dev = NULL;
+}
+
+static void __exit vsoc_cleanup_module(void)
+{
+	vsoc_remove_device(vsoc_dev.dev);
+	pci_unregister_driver(&vsoc_pci_driver);
+}
+
+static int __init vsoc_init_module(void)
+{
+	int err = -ENOMEM;
+
+	INIT_LIST_HEAD(&vsoc_dev.permissions);
+	mutex_init(&vsoc_dev.mtx);
+
+	err = pci_register_driver(&vsoc_pci_driver);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+static int vsoc_open(struct inode *inode, struct file *filp)
+{
+	/* Can't use vsoc_validate_filep because filp is still incomplete */
+	int ret = vsoc_validate_inode(inode);
+
+	if (ret)
+		return ret;
+	filp->private_data =
+		kzalloc(sizeof(struct vsoc_private_data), GFP_KERNEL);
+	if (!filp->private_data)
+		return -ENOMEM;
+	return 0;
+}
+
+static int vsoc_release(struct inode *inode, struct file *filp)
+{
+	struct vsoc_private_data *private_data = NULL;
+	struct fd_scoped_permission_node *node = NULL;
+	struct vsoc_device_region *owner_region_p = NULL;
+	int retval = vsoc_validate_filep(filp);
+
+	if (retval)
+		return retval;
+	private_data = (struct vsoc_private_data *)filp->private_data;
+	if (!private_data)
+		return 0;
+
+	node = private_data->fd_scoped_permission_node;
+	if (node) {
+		owner_region_p = vsoc_region_from_inode(inode);
+		if (owner_region_p->managed_by != VSOC_REGION_WHOLE) {
+			owner_region_p =
+			    &vsoc_dev.regions[owner_region_p->managed_by];
+		}
+		do_destroy_fd_scoped_permission_node(owner_region_p, node);
+		private_data->fd_scoped_permission_node = NULL;
+	}
+	kfree(private_data);
+	filp->private_data = NULL;
+
+	return 0;
+}
+
+/*
+ * Returns the device relative offset and length of the area specified by the
+ * fd scoped permission. If there is no fd scoped permission set, a default
+ * permission covering the entire region is assumed, unless the region is owned
+ * by another one, in which case the default is a permission with zero size.
+ */
+static ssize_t vsoc_get_area(struct file *filp, __u32 *area_offset)
+{
+	__u32 off = 0;
+	ssize_t length = 0;
+	struct vsoc_device_region *region_p;
+	struct fd_scoped_permission *perm;
+
+	region_p = vsoc_region_from_filep(filp);
+	off = region_p->region_begin_offset;
+	perm = &((struct vsoc_private_data *)filp->private_data)->
+		fd_scoped_permission_node->permission;
+	if (perm) {
+		off += perm->begin_offset;
+		length = perm->end_offset - perm->begin_offset;
+	} else if (region_p->managed_by == VSOC_REGION_WHOLE) {
+		/* No permission set and the regions is not owned by another,
+		 * default to full region access.
+		 */
+		length = vsoc_device_region_size(region_p);
+	} else {
+		/* return zero length, access is denied. */
+		length = 0;
+	}
+	if (area_offset)
+		*area_offset = off;
+	return length;
+}
+
+static int vsoc_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	unsigned long len = vma->vm_end - vma->vm_start;
+	__u32 area_off;
+	phys_addr_t mem_off;
+	ssize_t area_len;
+	int retval = vsoc_validate_filep(filp);
+
+	if (retval)
+		return retval;
+	area_len = vsoc_get_area(filp, &area_off);
+	/* Add the requested offset */
+	area_off += (vma->vm_pgoff << PAGE_SHIFT);
+	area_len -= (vma->vm_pgoff << PAGE_SHIFT);
+	if (area_len < len)
+		return -EINVAL;
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	mem_off = shm_off_to_phys_addr(area_off);
+	if (io_remap_pfn_range(vma, vma->vm_start, mem_off >> PAGE_SHIFT,
+			       len, vma->vm_page_prot))
+		return -EAGAIN;
+	return 0;
+}
+
+module_init(vsoc_init_module);
+module_exit(vsoc_cleanup_module);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Greg Hartman <ghartman@google.com>");
+MODULE_DESCRIPTION("VSoC interpretation of QEmu's ivshmem device");
+MODULE_VERSION("1.0");
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index a574885..18c5312 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -1284,6 +1284,8 @@
 		ack |= NISTC_INTA_ACK_AI_START;
 	if (a_status & NISTC_AI_STATUS1_STOP)
 		ack |= NISTC_INTA_ACK_AI_STOP;
+	if (a_status & NISTC_AI_STATUS1_OVER)
+		ack |= NISTC_INTA_ACK_AI_ERR;
 	if (ack)
 		ni_stc_writew(dev, ack, NISTC_INTA_ACK_REG);
 }
diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c
index 170de1c..f815f9d 100644
--- a/drivers/staging/wlan-ng/prism2mgmt.c
+++ b/drivers/staging/wlan-ng/prism2mgmt.c
@@ -169,7 +169,7 @@
 				     hw->ident_sta_fw.variant) >
 	    HFA384x_FIRMWARE_VERSION(1, 5, 0)) {
 		if (msg->scantype.data != P80211ENUM_scantype_active)
-			word = cpu_to_le16(msg->maxchanneltime.data);
+			word = msg->maxchanneltime.data;
 		else
 			word = 0;
 
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index 06912f0..b7cb49a 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -587,6 +587,9 @@
 	regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
 	regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
 
+	data->irq_enabled = true;
+	data->mode = THERMAL_DEVICE_ENABLED;
+
 	ret = devm_request_threaded_irq(&pdev->dev, data->irq,
 			imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
 			0, "imx_thermal", data);
@@ -598,9 +601,6 @@
 		return ret;
 	}
 
-	data->irq_enabled = true;
-	data->mode = THERMAL_DEVICE_ENABLED;
-
 	return 0;
 }
 
diff --git a/drivers/thermal/power_allocator.c b/drivers/thermal/power_allocator.c
index b4d3116..3055f9a 100644
--- a/drivers/thermal/power_allocator.c
+++ b/drivers/thermal/power_allocator.c
@@ -523,6 +523,7 @@
 	struct thermal_instance *instance;
 	struct power_allocator_params *params = tz->governor_data;
 
+	mutex_lock(&tz->lock);
 	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
 		if ((instance->trip != params->trip_max_desired_temperature) ||
 		    (!cdev_is_power_actor(instance->cdev)))
@@ -534,6 +535,7 @@
 		mutex_unlock(&instance->cdev->lock);
 		thermal_cdev_update(instance->cdev);
 	}
+	mutex_unlock(&tz->lock);
 }
 
 /**
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index 5c0022e..5d345cc 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -191,6 +191,8 @@
 
 #define QPNP_BTM_MEAS_INTERVAL_CTL			0x50
 #define QPNP_BTM_MEAS_INTERVAL_CTL2			0x51
+#define QPNP_BTM_MEAS_INTERVAL_CTL_PM5			0x44
+#define QPNP_BTM_MEAS_INTERVAL_CTL2_PM5		0x45
 #define QPNP_ADC_TM_MEAS_INTERVAL_TIME_SHIFT		0x3
 #define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT		0x4
 #define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_MASK		0xf0
@@ -742,6 +744,7 @@
 	bool chan_found = false;
 	u8 meas_interval_timer2 = 0, timer_interval_store = 0;
 	uint32_t btm_chan_idx = 0;
+	bool is_pmic_5 = chip->adc->adc_prop->is_pmic_5;
 
 	while (i < chip->max_channels_available) {
 		if (chip->sensor[i].btm_channel_num == btm_chan) {
@@ -763,10 +766,18 @@
 			rc = qpnp_adc_tm_write_reg(chip,
 				QPNP_ADC_TM_MEAS_INTERVAL_CTL,
 				chip->sensor[chan_idx].meas_interval, 1);
-		else
-			rc = qpnp_adc_tm_write_reg(chip,
-				QPNP_BTM_MEAS_INTERVAL_CTL,
-				chip->sensor[chan_idx].meas_interval, 1);
+		else {
+			if (!is_pmic_5)
+				rc = qpnp_adc_tm_write_reg(chip,
+					QPNP_BTM_MEAS_INTERVAL_CTL,
+					chip->sensor[chan_idx].meas_interval,
+					1);
+			else
+				rc = qpnp_adc_tm_write_reg(chip,
+					QPNP_BTM_MEAS_INTERVAL_CTL_PM5,
+					chip->sensor[chan_idx].meas_interval,
+					1);
+		}
 		if (rc < 0) {
 			pr_err("timer1 configure failed\n");
 			return rc;
@@ -778,10 +789,16 @@
 			rc = qpnp_adc_tm_read_reg(chip,
 				QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
 				&meas_interval_timer2, 1);
-		else
-			rc = qpnp_adc_tm_read_reg(chip,
+		else {
+			if (!is_pmic_5)
+				rc = qpnp_adc_tm_read_reg(chip,
 					QPNP_BTM_MEAS_INTERVAL_CTL2,
 					&meas_interval_timer2, 1);
+			else
+				rc = qpnp_adc_tm_read_reg(chip,
+					QPNP_BTM_MEAS_INTERVAL_CTL2_PM5,
+					&meas_interval_timer2, 1);
+		}
 		if (rc < 0) {
 			pr_err("timer2 configure read failed\n");
 			return rc;
@@ -794,10 +811,16 @@
 			rc = qpnp_adc_tm_write_reg(chip,
 				QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
 				meas_interval_timer2, 1);
-		else
-			rc = qpnp_adc_tm_write_reg(chip,
-				QPNP_BTM_MEAS_INTERVAL_CTL2,
-				meas_interval_timer2, 1);
+		else {
+			if (!is_pmic_5)
+				rc = qpnp_adc_tm_write_reg(chip,
+					QPNP_BTM_MEAS_INTERVAL_CTL2,
+					meas_interval_timer2, 1);
+			else
+				rc = qpnp_adc_tm_write_reg(chip,
+					QPNP_BTM_MEAS_INTERVAL_CTL2_PM5,
+					meas_interval_timer2, 1);
+		}
 		if (rc < 0) {
 			pr_err("timer2 configure failed\n");
 			return rc;
@@ -808,10 +831,16 @@
 			rc = qpnp_adc_tm_read_reg(chip,
 				QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
 				&meas_interval_timer2, 1);
-		else
-			rc = qpnp_adc_tm_read_reg(chip,
-				QPNP_BTM_MEAS_INTERVAL_CTL2,
-				&meas_interval_timer2, 1);
+		else {
+			if (!is_pmic_5)
+				rc = qpnp_adc_tm_read_reg(chip,
+					QPNP_BTM_MEAS_INTERVAL_CTL2,
+					&meas_interval_timer2, 1);
+			else
+				rc = qpnp_adc_tm_read_reg(chip,
+					QPNP_BTM_MEAS_INTERVAL_CTL2_PM5,
+					&meas_interval_timer2, 1);
+		}
 		if (rc < 0) {
 			pr_err("timer3 read failed\n");
 			return rc;
@@ -823,10 +852,16 @@
 			rc = qpnp_adc_tm_write_reg(chip,
 				QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
 				meas_interval_timer2, 1);
-		else
-			rc = qpnp_adc_tm_write_reg(chip,
-				QPNP_BTM_MEAS_INTERVAL_CTL2,
-				meas_interval_timer2, 1);
+		else {
+			if (!is_pmic_5)
+				rc = qpnp_adc_tm_write_reg(chip,
+					QPNP_BTM_MEAS_INTERVAL_CTL2,
+					meas_interval_timer2, 1);
+			else
+				rc = qpnp_adc_tm_write_reg(chip,
+					QPNP_BTM_MEAS_INTERVAL_CTL2_PM5,
+					meas_interval_timer2, 1);
+		}
 		if (rc < 0) {
 			pr_err("timer3 configure failed\n");
 			return rc;
@@ -2997,6 +3032,7 @@
 static const struct of_device_id qpnp_adc_tm_match_table[] = {
 	{	.compatible = "qcom,qpnp-adc-tm" },
 	{	.compatible = "qcom,qpnp-adc-tm-hc" },
+	{	.compatible = "qcom,qpnp-adc-tm-hc-pm5" },
 	{}
 };
 
diff --git a/drivers/thermal/tsens.h b/drivers/thermal/tsens.h
index 730d124..d35b867 100644
--- a/drivers/thermal/tsens.h
+++ b/drivers/thermal/tsens.h
@@ -153,8 +153,8 @@
 	spinlock_t			tsens_crit_lock;
 	spinlock_t			tsens_upp_low_lock;
 	const struct tsens_data		*ctrl_data;
+	struct tsens_mtc_sysfs  mtcsys;
 	struct tsens_sensor		sensor[0];
-	struct tsens_mtc_sysfs	mtcsys;
 };
 
 extern const struct tsens_data data_tsens2xxx, data_tsens23xx, data_tsens24xx;
diff --git a/drivers/thermal/tsens1xxx.c b/drivers/thermal/tsens1xxx.c
index d63fcd1..19e2b5a 100644
--- a/drivers/thermal/tsens1xxx.c
+++ b/drivers/thermal/tsens1xxx.c
@@ -517,8 +517,8 @@
 			th_temp = code_to_degc((threshold &
 					TSENS_UPPER_THRESHOLD_MASK) >>
 					TSENS_UPPER_THRESHOLD_SHIFT,
-					tm->sensor);
-			if (th_temp > temp) {
+					(tm->sensor + i));
+			if (th_temp > (temp/TSENS_SCALE_MILLIDEG)) {
 				pr_debug("Re-arm high threshold\n");
 				rc = tsens_tz_activate_trip_type(
 						&tm->sensor[i],
@@ -539,8 +539,8 @@
 					tm->tsens_tm_addr + addr_offset));
 			th_temp = code_to_degc((threshold &
 					TSENS_LOWER_THRESHOLD_MASK),
-					tm->sensor);
-			if (th_temp < temp) {
+					(tm->sensor + i));
+			if (th_temp < (temp/TSENS_SCALE_MILLIDEG)) {
 				pr_debug("Re-arm Low threshold\n");
 				rc = tsens_tz_activate_trip_type(
 						&tm->sensor[i],
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
index a8c2041..cba6bc6 100644
--- a/drivers/thunderbolt/nhi.c
+++ b/drivers/thunderbolt/nhi.c
@@ -628,6 +628,7 @@
 					    * we just disable hotplug, the
 					    * pci-tunnels stay alive.
 					    */
+	.thaw_noirq = nhi_resume_noirq,
 	.restore_noirq = nhi_resume_noirq,
 };
 
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 54cab59..fe22917 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -1467,6 +1467,10 @@
  *	in which case an opening port goes back to closed and a closing port
  *	is simply put into closed state (any further frames from the other
  *	end will get a DM response)
+ *
+ *	Some control dlci can stay in ADM mode with other dlci working just
+ *	fine. In that case we can just keep the control dlci open after the
+ *	DLCI_OPENING retries time out.
  */
 
 static void gsm_dlci_t1(unsigned long data)
@@ -1480,8 +1484,15 @@
 		if (dlci->retries) {
 			gsm_command(dlci->gsm, dlci->addr, SABM|PF);
 			mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
-		} else
+		} else if (!dlci->addr && gsm->control == (DM | PF)) {
+			if (debug & 8)
+				pr_info("DLCI %d opening in ADM mode.\n",
+					dlci->addr);
+			gsm_dlci_open(dlci);
+		} else {
 			gsm_dlci_close(dlci);
+		}
+
 		break;
 	case DLCI_CLOSING:
 		dlci->retries--;
@@ -1499,8 +1510,8 @@
  *	@dlci: DLCI to open
  *
  *	Commence opening a DLCI from the Linux side. We issue SABM messages
- *	to the modem which should then reply with a UA, at which point we
- *	will move into open state. Opening is done asynchronously with retry
+ *	to the modem which should then reply with a UA or ADM, at which point
+ *	we will move into open state. Opening is done asynchronously with retry
  *	running off timers and the responses.
  */
 
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index faf50df..1c70541 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -2182,6 +2182,12 @@
 				}
 				if (tty_hung_up_p(file))
 					break;
+				/*
+				 * Abort readers for ttys which never actually
+				 * get hung up.  See __tty_hangup().
+				 */
+				if (test_bit(TTY_HUPPING, &tty->flags))
+					break;
 				if (!timeout)
 					break;
 				if (file->f_flags & O_NONBLOCK) {
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index da31159..e8b34f1 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -613,6 +613,10 @@
 	up->lsr_saved_flags = 0;
 	up->msr_saved_flags = 0;
 
+	/* Disable DMA for console UART */
+	if (uart_console(port))
+		up->dma = NULL;
+
 	if (up->dma) {
 		ret = serial8250_request_dma(up);
 		if (ret) {
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index f76b3db..8e5d100 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -1660,7 +1660,7 @@
 		msm_port->rx_buf = devm_kzalloc(uport->dev, DMA_RX_BUF_SIZE,
 								GFP_KERNEL);
 		if (!msm_port->rx_buf) {
-			kfree(msm_port->rx_fifo);
+			devm_kfree(uport->dev, msm_port->rx_fifo);
 			msm_port->rx_fifo = NULL;
 			ret = -ENOMEM;
 			goto exit_portsetup;
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c
index fcf803f..cdd2f94 100644
--- a/drivers/tty/serial/sccnxp.c
+++ b/drivers/tty/serial/sccnxp.c
@@ -884,14 +884,19 @@
 
 	clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(clk)) {
-		if (PTR_ERR(clk) == -EPROBE_DEFER) {
-			ret = -EPROBE_DEFER;
+		ret = PTR_ERR(clk);
+		if (ret == -EPROBE_DEFER)
 			goto err_out;
-		}
+		uartclk = 0;
+	} else {
+		clk_prepare_enable(clk);
+		uartclk = clk_get_rate(clk);
+	}
+
+	if (!uartclk) {
 		dev_notice(&pdev->dev, "Using default clock frequency\n");
 		uartclk = s->chip->freq_std;
-	} else
-		uartclk = clk_get_rate(clk);
+	}
 
 	/* Check input frequency */
 	if ((uartclk < s->chip->freq_min) || (uartclk > s->chip->freq_max)) {
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index a55c94d..107f0d1 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1545,7 +1545,16 @@
 	if (s->chan_rx)
 		sci_rx_dma_release(s, false);
 }
-#else
+
+static void sci_flush_buffer(struct uart_port *port)
+{
+	/*
+	 * In uart_flush_buffer(), the xmit circular buffer has just been
+	 * cleared, so we have to reset tx_dma_len accordingly.
+	 */
+	to_sci_port(port)->tx_dma_len = 0;
+}
+#else /* !CONFIG_SERIAL_SH_SCI_DMA */
 static inline void sci_request_dma(struct uart_port *port)
 {
 }
@@ -1553,7 +1562,9 @@
 static inline void sci_free_dma(struct uart_port *port)
 {
 }
-#endif
+
+#define sci_flush_buffer	NULL
+#endif /* !CONFIG_SERIAL_SH_SCI_DMA */
 
 static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
 {
@@ -2551,6 +2562,7 @@
 	.break_ctl	= sci_break_ctl,
 	.startup	= sci_startup,
 	.shutdown	= sci_shutdown,
+	.flush_buffer	= sci_flush_buffer,
 	.set_termios	= sci_set_termios,
 	.pm		= sci_pm,
 	.type		= sci_type,
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index fb9bada..4ee0a9d 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -709,6 +709,14 @@
 		return;
 	}
 
+	/*
+	 * Some console devices aren't actually hung up for technical and
+	 * historical reasons, which can lead to indefinite interruptible
+	 * sleep in n_tty_read().  The following explicitly tells
+	 * n_tty_read() to abort readers.
+	 */
+	set_bit(TTY_HUPPING, &tty->flags);
+
 	/* inuse_filps is protected by the single tty lock,
 	   this really needs to change if we want to flush the
 	   workqueue with the lock held */
@@ -763,6 +771,7 @@
 	 * from the ldisc side, which is now guaranteed.
 	 */
 	set_bit(TTY_HUPPED, &tty->flags);
+	clear_bit(TTY_HUPPING, &tty->flags);
 	tty_unlock(tty);
 
 	if (f)
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 68c7bb0..9e1ac58 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -1354,6 +1354,11 @@
 		case 3:
 			vc->vc_italic = 1;
 			break;
+		case 21:
+			/*
+			 * No console drivers support double underline, so
+			 * convert it to a single underline.
+			 */
 		case 4:
 			vc->vc_underline = 1;
 			break;
@@ -1389,7 +1394,6 @@
 			vc->vc_disp_ctrl = 1;
 			vc->vc_toggle_meta = 1;
 			break;
-		case 21:
 		case 22:
 			vc->vc_intensity = 1;
 			break;
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index fba021f..208bc52 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -279,7 +279,7 @@
 		map = kzalloc(sizeof(*map), GFP_KERNEL);
 		if (!map) {
 			ret = -ENOMEM;
-			goto err_map_kobj;
+			goto err_map;
 		}
 		kobject_init(&map->kobj, &map_attr_type);
 		map->mem = mem;
@@ -289,7 +289,7 @@
 			goto err_map_kobj;
 		ret = kobject_uevent(&map->kobj, KOBJ_ADD);
 		if (ret)
-			goto err_map;
+			goto err_map_kobj;
 	}
 
 	for (pi = 0; pi < MAX_UIO_PORT_REGIONS; pi++) {
@@ -308,7 +308,7 @@
 		portio = kzalloc(sizeof(*portio), GFP_KERNEL);
 		if (!portio) {
 			ret = -ENOMEM;
-			goto err_portio_kobj;
+			goto err_portio;
 		}
 		kobject_init(&portio->kobj, &portio_attr_type);
 		portio->port = port;
@@ -319,7 +319,7 @@
 			goto err_portio_kobj;
 		ret = kobject_uevent(&portio->kobj, KOBJ_ADD);
 		if (ret)
-			goto err_portio;
+			goto err_portio_kobj;
 	}
 
 	return 0;
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 6e0d614..64c6af2c 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -839,7 +839,7 @@
 {
 	ci_hdrc_gadget_destroy(ci);
 	ci_hdrc_host_destroy(ci);
-	if (ci->is_otg)
+	if (ci->is_otg && ci->roles[CI_ROLE_GADGET])
 		ci_hdrc_otg_destroy(ci);
 }
 
@@ -939,27 +939,35 @@
 	/* initialize role(s) before the interrupt is requested */
 	if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) {
 		ret = ci_hdrc_host_init(ci);
-		if (ret)
-			dev_info(dev, "doesn't support host\n");
+		if (ret) {
+			if (ret == -ENXIO)
+				dev_info(dev, "doesn't support host\n");
+			else
+				goto deinit_phy;
+		}
 	}
 
 	if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) {
 		ret = ci_hdrc_gadget_init(ci);
-		if (ret)
-			dev_info(dev, "doesn't support gadget\n");
+		if (ret) {
+			if (ret == -ENXIO)
+				dev_info(dev, "doesn't support gadget\n");
+			else
+				goto deinit_host;
+		}
 	}
 
 	if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) {
 		dev_err(dev, "no supported roles\n");
 		ret = -ENODEV;
-		goto deinit_phy;
+		goto deinit_gadget;
 	}
 
 	if (ci->is_otg && ci->roles[CI_ROLE_GADGET]) {
 		ret = ci_hdrc_otg_init(ci);
 		if (ret) {
 			dev_err(dev, "init otg fails, ret = %d\n", ret);
-			goto stop;
+			goto deinit_gadget;
 		}
 	}
 
@@ -1024,7 +1032,12 @@
 
 	ci_extcon_unregister(ci);
 stop:
-	ci_role_destroy(ci);
+	if (ci->is_otg && ci->roles[CI_ROLE_GADGET])
+		ci_hdrc_otg_destroy(ci);
+deinit_gadget:
+	ci_hdrc_gadget_destroy(ci);
+deinit_host:
+	ci_hdrc_host_destroy(ci);
 deinit_phy:
 	ci_usb_phy_exit(ci);
 
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 0f10ff2..8df85f6 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -240,8 +240,13 @@
 	if (!udev->parent)
 		rc = hcd_bus_suspend(udev, msg);
 
-	/* Non-root devices don't need to do anything for FREEZE or PRETHAW */
-	else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
+	/*
+	 * Non-root USB2 devices don't need to do anything for FREEZE
+	 * or PRETHAW. USB3 devices don't support global suspend and
+	 * needs to be selectively suspended.
+	 */
+	else if ((msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
+		 && (udev->speed < USB_SPEED_SUPER))
 		rc = 0;
 	else
 		rc = usb_port_suspend(udev, msg);
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index dfc0566..919a321 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3220,7 +3220,6 @@
 		dwc2_core_init(hsotg, false);
 		dwc2_enable_global_interrupts(hsotg);
 		spin_lock_irqsave(&hsotg->lock, flags);
-		dwc2_hsotg_disconnect(hsotg);
 		dwc2_hsotg_core_init_disconnected(hsotg, false);
 		spin_unlock_irqrestore(&hsotg->lock, flags);
 		dwc2_hsotg_core_connect(hsotg);
@@ -3238,8 +3237,12 @@
 		if (count > 250)
 			dev_err(hsotg->dev,
 				"Connection id status change timed out\n");
-		hsotg->op_state = OTG_STATE_A_HOST;
 
+		spin_lock_irqsave(&hsotg->lock, flags);
+		dwc2_hsotg_disconnect(hsotg);
+		spin_unlock_irqrestore(&hsotg->lock, flags);
+
+		hsotg->op_state = OTG_STATE_A_HOST;
 		/* Initialize the Core for Host mode */
 		dwc2_core_init(hsotg, false);
 		dwc2_enable_global_interrupts(hsotg);
diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c
index 7266470..12ee23f 100644
--- a/drivers/usb/dwc3/dwc3-keystone.c
+++ b/drivers/usb/dwc3/dwc3-keystone.c
@@ -107,6 +107,10 @@
 		return PTR_ERR(kdwc->usbss);
 
 	kdwc->clk = devm_clk_get(kdwc->dev, "usb");
+	if (IS_ERR(kdwc->clk)) {
+		dev_err(kdwc->dev, "unable to get usb clock\n");
+		return PTR_ERR(kdwc->clk);
+	}
 
 	error = clk_prepare_enable(kdwc->clk);
 	if (error < 0) {
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 427291a..d6493ab 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -173,7 +173,7 @@
 	ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
 	if (ret) {
 		dev_err(dev, "couldn't add resources to dwc3 device\n");
-		return ret;
+		goto err;
 	}
 
 	dwc3->dev.parent = dev;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index b804da1..f878b8d1 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1307,7 +1307,7 @@
 
 	if (req->request.status == -EINPROGRESS) {
 		ret = -EBUSY;
-		dev_err_ratelimited(dwc->dev, "%s: %p request already in queue",
+		dev_err_ratelimited(dwc->dev, "%s: %pK request already in queue",
 					dep->name, req);
 		return ret;
 	}
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 939c219..703fb24 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -3951,7 +3951,7 @@
 	usb_del_gadget_udc(&udc->gadget);
 remove_trans:
 	if (udc->transceiver)
-		otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
+		otg_set_peripheral(udc->transceiver->otg, NULL);
 
 	err("error = %i", retval);
 put_transceiver:
@@ -3989,7 +3989,7 @@
 	usb_del_gadget_udc(&udc->gadget);
 
 	if (udc->transceiver) {
-		otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
+		otg_set_peripheral(udc->transceiver->otg, NULL);
 		usb_put_phy(udc->transceiver);
 	}
 	destroy_eps(udc);
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 8eed1b3..9974332 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -1097,7 +1097,7 @@
 		spin_unlock_irq(&epfile->ffs->eps_lock);
 
 		extra_buf_alloc = ffs->gadget->extra_buf_alloc;
-		if (io_data->read)
+		if (!io_data->read)
 			data = kmalloc(data_len + extra_buf_alloc,
 					GFP_KERNEL);
 		else
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
index 1979156..4b4ce0e 100644
--- a/drivers/usb/gadget/function/f_midi.c
+++ b/drivers/usb/gadget/function/f_midi.c
@@ -413,7 +413,8 @@
 		if (err) {
 			ERROR(midi, "%s: couldn't enqueue request: %d\n",
 				    midi->out_ep->name, err);
-			free_ep_req(midi->out_ep, req);
+			if (req->buf != NULL)
+				free_ep_req(midi->out_ep, req);
 			return err;
 		}
 	}
diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c
index d1c3741..0ce2c407 100644
--- a/drivers/usb/gadget/function/f_qdss.c
+++ b/drivers/usb/gadget/function/f_qdss.c
@@ -1,7 +1,7 @@
 /*
  * f_qdss.c -- QDSS function Driver
  *
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, 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
@@ -117,6 +117,39 @@
 	.wBytesPerInterval  =	0,
 };
 
+/* Full speed support */
+static struct usb_endpoint_descriptor qdss_fs_data_desc = {
+	.bLength            =	 USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType    =	 USB_DT_ENDPOINT,
+	.bEndpointAddress   =	 USB_DIR_IN,
+	.bmAttributes       =	 USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize     =	 cpu_to_le16(64),
+};
+
+static struct usb_endpoint_descriptor qdss_fs_ctrl_in_desc  = {
+	.bLength            =    USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType    =    USB_DT_ENDPOINT,
+	.bEndpointAddress   =    USB_DIR_IN,
+	.bmAttributes       =    USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize     =    cpu_to_le16(64),
+};
+
+static struct usb_endpoint_descriptor qdss_fs_ctrl_out_desc = {
+	.bLength            =     USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType    =     USB_DT_ENDPOINT,
+	.bEndpointAddress   =     USB_DIR_OUT,
+	.bmAttributes       =     USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize     =     cpu_to_le16(64),
+};
+
+static struct usb_descriptor_header *qdss_fs_desc[] = {
+	(struct usb_descriptor_header *) &qdss_data_intf_desc,
+	(struct usb_descriptor_header *) &qdss_fs_data_desc,
+	(struct usb_descriptor_header *) &qdss_ctrl_intf_desc,
+	(struct usb_descriptor_header *) &qdss_fs_ctrl_in_desc,
+	(struct usb_descriptor_header *) &qdss_fs_ctrl_out_desc,
+	NULL,
+};
 static struct usb_descriptor_header *qdss_hs_desc[] = {
 	(struct usb_descriptor_header *) &qdss_data_intf_desc,
 	(struct usb_descriptor_header *) &qdss_hs_data_desc,
@@ -138,6 +171,11 @@
 	NULL,
 };
 
+static struct usb_descriptor_header *qdss_fs_data_only_desc[] = {
+	(struct usb_descriptor_header *) &qdss_data_intf_desc,
+	(struct usb_descriptor_header *) &qdss_fs_data_desc,
+	NULL,
+};
 static struct usb_descriptor_header *qdss_hs_data_only_desc[] = {
 	(struct usb_descriptor_header *) &qdss_data_intf_desc,
 	(struct usb_descriptor_header *) &qdss_hs_data_desc,
@@ -367,6 +405,9 @@
 
 	if (gadget_is_dualspeed(gadget) && f->hs_descriptors)
 		usb_free_descriptors(f->hs_descriptors);
+
+	if (f->fs_descriptors)
+		usb_free_descriptors(f->fs_descriptors);
 }
 
 static int qdss_bind(struct usb_configuration *c, struct usb_function *f)
@@ -378,11 +419,6 @@
 
 	pr_debug("qdss_bind\n");
 
-	if (!gadget_is_dualspeed(gadget) && !gadget_is_superspeed(gadget)) {
-		pr_err("qdss_bind: full-speed is not supported\n");
-		return -ENOTSUPP;
-	}
-
 	/* Allocate data I/F */
 	iface = usb_interface_id(c, f);
 	if (iface < 0) {
@@ -447,6 +483,18 @@
 		ep->driver_data = qdss;
 	}
 
+	/*update fs descriptors*/
+	qdss_fs_data_desc.bEndpointAddress =
+		qdss_ss_data_desc.bEndpointAddress;
+	if (qdss->debug_inface_enabled) {
+		qdss_fs_ctrl_in_desc.bEndpointAddress =
+		qdss_ss_ctrl_in_desc.bEndpointAddress;
+		qdss_fs_ctrl_out_desc.bEndpointAddress =
+		qdss_ss_ctrl_out_desc.bEndpointAddress;
+		f->fs_descriptors = usb_copy_descriptors(qdss_fs_desc);
+	} else
+		f->fs_descriptors = usb_copy_descriptors(
+							qdss_fs_data_only_desc);
 	/*update descriptors*/
 	qdss_hs_data_desc.bEndpointAddress =
 		qdss_ss_data_desc.bEndpointAddress;
@@ -650,7 +698,7 @@
 		goto fail1;
 	}
 
-	if (intf == qdss->data_iface_id) {
+	if (intf == qdss->data_iface_id && !qdss->data_enabled) {
 		/* Increment usage count on connect */
 		usb_gadget_autopm_get_async(qdss->gadget);
 
@@ -1144,7 +1192,7 @@
 	struct f_qdss *usb_qdss = opts->usb_qdss;
 
 	usb_qdss->port.function.name = "usb_qdss";
-	usb_qdss->port.function.fs_descriptors = qdss_hs_desc;
+	usb_qdss->port.function.fs_descriptors = qdss_fs_desc;
 	usb_qdss->port.function.hs_descriptors = qdss_hs_desc;
 	usb_qdss->port.function.strings = qdss_strings;
 	usb_qdss->port.function.bind = qdss_bind;
diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
index bc4f9f7..814b4a3e 100644
--- a/drivers/usb/gadget/function/f_rndis.c
+++ b/drivers/usb/gadget/function/f_rndis.c
@@ -767,7 +767,7 @@
 	 */
 	if (!rndis_opts->bound) {
 		mutex_lock(&rndis_opts->lock);
-		rndis_opts->net = gether_setup_default();
+		rndis_opts->net = gether_setup_name_default("rndis");
 		if (IS_ERR(rndis_opts->net)) {
 			status = PTR_ERR(rndis_opts->net);
 			mutex_unlock(&rndis_opts->lock);
diff --git a/drivers/usb/gadget/u_f.h b/drivers/usb/gadget/u_f.h
index 7d53a47..2f03334 100644
--- a/drivers/usb/gadget/u_f.h
+++ b/drivers/usb/gadget/u_f.h
@@ -64,7 +64,9 @@
 /* Frees a usb_request previously allocated by alloc_ep_req() */
 static inline void free_ep_req(struct usb_ep *ep, struct usb_request *req)
 {
+	WARN_ON(req->buf == NULL);
 	kfree(req->buf);
+	req->buf = NULL;
 	usb_ep_free_request(ep, req);
 }
 
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 6959071..0c71938 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -139,10 +139,8 @@
 		goto out;
 
 	ret = ep->ops->disable(ep);
-	if (ret) {
-		ret = ret;
+	if (ret)
 		goto out;
-	}
 
 	ep->enabled = false;
 
@@ -250,6 +248,9 @@
  * arranges to poll once per interval, and the gadget driver usually will
  * have queued some data to transfer at that time.
  *
+ * Note that @req's ->complete() callback must never be called from
+ * within usb_ep_queue() as that can create deadlock situations.
+ *
  * Returns zero, or a negative error code.  Endpoints that are not enabled
  * report errors; errors will also be
  * reported when the usb peripheral is disconnected.
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index a1dedf0..1ce079d 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -489,7 +489,6 @@
 static struct platform_driver usb_xhci_driver = {
 	.probe	= xhci_plat_probe,
 	.remove	= xhci_plat_remove,
-	.shutdown	= usb_hcd_platform_shutdown,
 	.driver	= {
 		.name = "xhci-hcd",
 		.pm = DEV_PM_OPS,
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index 844a309..e85b9c2 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -114,15 +114,19 @@
 		}
 
 		is_in = epnum & USB_DIR_IN;
-		if (is_in) {
-			epnum &= 0x0f;
-			ep = &musb->endpoints[epnum].ep_in;
-		} else {
-			ep = &musb->endpoints[epnum].ep_out;
+		epnum &= 0x0f;
+		if (epnum >= MUSB_C_NUM_EPS) {
+			handled = -EINVAL;
+			break;
 		}
+
+		if (is_in)
+			ep = &musb->endpoints[epnum].ep_in;
+		else
+			ep = &musb->endpoints[epnum].ep_out;
 		regs = musb->endpoints[epnum].regs;
 
-		if (epnum >= MUSB_C_NUM_EPS || !ep->desc) {
+		if (!ep->desc) {
 			handled = -EINVAL;
 			break;
 		}
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 6111d39..d21823b 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -942,7 +942,7 @@
 
 	/* check against received length to avoid overrun */
 	if (bytes_to_copy > len - sizeof(ext_hdr)) {
-		usbpd_warn(&pd->dev, "not enough bytes in chunk, expected:%u received:%lu\n",
+		usbpd_warn(&pd->dev, "not enough bytes in chunk, expected:%u received:%zu\n",
 			bytes_to_copy, len - sizeof(ext_hdr));
 		bytes_to_copy = len - sizeof(ext_hdr);
 	}
diff --git a/drivers/usb/phy/phy-msm-qusb.c b/drivers/usb/phy/phy-msm-qusb.c
index 9c33c6e..47db12b 100644
--- a/drivers/usb/phy/phy-msm-qusb.c
+++ b/drivers/usb/phy/phy-msm-qusb.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, 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
@@ -706,7 +706,9 @@
 				qphy->base + QUSB2PHY_PORT_INTR_CTRL);
 
 			/* Disable PHY */
-			writel_relaxed(POWER_DOWN,
+			writel_relaxed(POWER_DOWN |
+				readl_relaxed(qphy->base +
+					QUSB2PHY_PORT_POWERDOWN),
 				qphy->base + QUSB2PHY_PORT_POWERDOWN);
 			/* Make sure that above write is completed */
 			wmb();
diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c
index ad3bbf7..174f75f 100644
--- a/drivers/usb/phy/phy-msm-ssusb-qmp.c
+++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c
@@ -25,10 +25,10 @@
 #include <linux/clk.h>
 #include <linux/reset.h>
 
-enum core_ldo_levels {
-	CORE_LEVEL_NONE = 0,
-	CORE_LEVEL_MIN,
-	CORE_LEVEL_MAX,
+enum ldo_levels {
+	VOLTAGE_LEVEL_NONE = 0,
+	VOLTAGE_LEVEL_MIN,
+	VOLTAGE_LEVEL_MAX,
 };
 
 #define INIT_MAX_TIME_USEC			1000
@@ -38,6 +38,8 @@
 #define USB_SSPHY_1P2_VOL_MAX		1200000 /* uV */
 #define USB_SSPHY_HPM_LOAD		23000	/* uA */
 
+#define USB_SSPHY_LOAD_DEFAULT		-1
+
 /* USB3PHY_PCIE_USB3_PCS_PCS_STATUS bit */
 #define PHYSTATUS				BIT(6)
 
@@ -119,6 +121,9 @@
 	int			vdd_levels[3]; /* none, low, high */
 	struct regulator	*core_ldo;
 	int			core_voltage_levels[3];
+	struct regulator	*fpc_redrive_ldo;
+	int			redrive_voltage_levels[3];
+	int			redrive_load;
 	struct clk		*ref_clk_src;
 	struct clk		*ref_clk;
 	struct clk		*aux_clk;
@@ -226,6 +231,33 @@
 	}
 }
 
+static int msm_ldo_enable(struct msm_ssphy_qmp *phy,
+		struct regulator *ldo, int *voltage_levels, int load)
+{
+	int ret = 0;
+
+	dev_dbg(phy->phy.dev,
+		"ldo: min_vol:%duV max_vol:%duV\n",
+		voltage_levels[VOLTAGE_LEVEL_MIN],
+		voltage_levels[VOLTAGE_LEVEL_MAX]);
+
+	if (load > 0) {
+		ret = regulator_set_load(ldo, load);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = regulator_set_voltage(ldo,
+			voltage_levels[VOLTAGE_LEVEL_MIN],
+			voltage_levels[VOLTAGE_LEVEL_MAX]);
+	if (ret)
+		return ret;
+
+	ret = regulator_enable(ldo);
+
+	return ret;
+}
+
 static int msm_ssusb_qmp_ldo_enable(struct msm_ssphy_qmp *phy, int on)
 {
 	int min, rc = 0;
@@ -245,74 +277,65 @@
 	if (!on)
 		goto disable_regulators;
 
-	rc = regulator_set_voltage(phy->vdd, phy->vdd_levels[min],
-				    phy->vdd_levels[2]);
-	if (rc) {
-		dev_err(phy->phy.dev, "unable to set voltage for ssusb vdd\n");
-		return rc;
+	if (phy->fpc_redrive_ldo) {
+		rc = msm_ldo_enable(phy, phy->fpc_redrive_ldo,
+				phy->redrive_voltage_levels,
+				phy->redrive_load);
+		if (rc < 0) {
+			dev_err(phy->phy.dev,
+				"enable phy->fpc_redrive_ldo failed\n");
+			return rc;
+		}
+
+		dev_dbg(phy->phy.dev,
+			"fpc redrive ldo: min_vol:%duV max_vol:%duV\n",
+			phy->redrive_voltage_levels[VOLTAGE_LEVEL_MIN],
+			phy->redrive_voltage_levels[VOLTAGE_LEVEL_MAX]);
 	}
 
-	dev_dbg(phy->phy.dev, "min_vol:%d max_vol:%d\n",
-		phy->vdd_levels[min], phy->vdd_levels[2]);
-
-	rc = regulator_enable(phy->vdd);
-	if (rc) {
-		dev_err(phy->phy.dev,
-			"regulator_enable(phy->vdd) failed, ret=%d",
-			rc);
-		goto unconfig_vdd;
-	}
-
-	rc = regulator_set_load(phy->core_ldo, USB_SSPHY_HPM_LOAD);
+	rc = msm_ldo_enable(phy, phy->vdd, phy->vdd_levels,
+			USB_SSPHY_LOAD_DEFAULT);
 	if (rc < 0) {
-		dev_err(phy->phy.dev, "Unable to set HPM of core_ldo\n");
+		dev_err(phy->phy.dev, "enable phy->vdd failed\n");
+		goto disable_fpc_redrive;
+	}
+
+	dev_dbg(phy->phy.dev,
+		"vdd ldo: min_vol:%duV max_vol:%duV\n",
+		phy->vdd_levels[VOLTAGE_LEVEL_MIN],
+		phy->vdd_levels[VOLTAGE_LEVEL_MAX]);
+
+	rc = msm_ldo_enable(phy, phy->core_ldo, phy->core_voltage_levels,
+			USB_SSPHY_HPM_LOAD);
+	if (rc < 0) {
+		dev_err(phy->phy.dev, "enable phy->core_ldo failed\n");
 		goto disable_vdd;
 	}
 
-	rc = regulator_set_voltage(phy->core_ldo,
-			phy->core_voltage_levels[CORE_LEVEL_MIN],
-			phy->core_voltage_levels[CORE_LEVEL_MAX]);
-	if (rc) {
-		dev_err(phy->phy.dev, "unable to set voltage for core_ldo\n");
-		goto put_core_ldo_lpm;
-	}
-
-	rc = regulator_enable(phy->core_ldo);
-	if (rc) {
-		dev_err(phy->phy.dev, "Unable to enable core_ldo\n");
-		goto unset_core_ldo;
-	}
+	dev_dbg(phy->phy.dev,
+		"core ldo: min_vol:%duV max_vol:%duV\n",
+		phy->core_voltage_levels[VOLTAGE_LEVEL_MIN],
+		phy->core_voltage_levels[VOLTAGE_LEVEL_MAX]);
 
 	return 0;
 
 disable_regulators:
 	rc = regulator_disable(phy->core_ldo);
 	if (rc)
-		dev_err(phy->phy.dev, "Unable to disable core_ldo\n");
-
-unset_core_ldo:
-	rc = regulator_set_voltage(phy->core_ldo,
-			phy->core_voltage_levels[CORE_LEVEL_NONE],
-			phy->core_voltage_levels[CORE_LEVEL_MAX]);
-	if (rc)
-		dev_err(phy->phy.dev, "unable to set voltage for core_ldo\n");
-
-put_core_ldo_lpm:
-	rc = regulator_set_load(phy->core_ldo, 0);
-	if (rc < 0)
-		dev_err(phy->phy.dev, "Unable to set LPM of core_ldo\n");
+		dev_err(phy->phy.dev, "disable phy->core_ldo failed\n");
 
 disable_vdd:
 	rc = regulator_disable(phy->vdd);
 	if (rc)
-		dev_err(phy->phy.dev, "regulator_disable(phy->vdd) failed, ret=%d",
-			rc);
+		dev_err(phy->phy.dev, "disable phy->vdd failed\n");
 
-unconfig_vdd:
-	rc = regulator_set_voltage(phy->vdd, phy->vdd_levels[min],
-				    phy->vdd_levels[2]);
-	if (rc)
-		dev_err(phy->phy.dev, "unable to set voltage for ssusb vdd\n");
+disable_fpc_redrive:
+	if (phy->fpc_redrive_ldo) {
+		rc = regulator_disable(phy->fpc_redrive_ldo);
+		if (rc)
+			dev_err(phy->phy.dev,
+				"disable phy->fpc_redrive_ldo failed\n");
+	}
 
 	return rc < 0 ? rc : 0;
 }
@@ -944,9 +967,9 @@
 	}
 
 	/* Set default core voltage values */
-	phy->core_voltage_levels[CORE_LEVEL_NONE] = 0;
-	phy->core_voltage_levels[CORE_LEVEL_MIN] = USB_SSPHY_1P2_VOL_MIN;
-	phy->core_voltage_levels[CORE_LEVEL_MAX] = USB_SSPHY_1P2_VOL_MAX;
+	phy->core_voltage_levels[VOLTAGE_LEVEL_NONE] = 0;
+	phy->core_voltage_levels[VOLTAGE_LEVEL_MIN] = USB_SSPHY_1P2_VOL_MIN;
+	phy->core_voltage_levels[VOLTAGE_LEVEL_MAX] = USB_SSPHY_1P2_VOL_MAX;
 
 	if (of_get_property(dev->of_node, "qcom,core-voltage-level", &len) &&
 		len == sizeof(phy->core_voltage_levels)) {
@@ -990,6 +1013,39 @@
 		goto err;
 	}
 
+	phy->fpc_redrive_ldo = devm_regulator_get_optional(dev, "fpc-redrive");
+	if (IS_ERR(phy->fpc_redrive_ldo)) {
+		phy->fpc_redrive_ldo = NULL;
+		dev_dbg(dev, "no FPC re-drive ldo regulator\n");
+	} else {
+		if (of_get_property(dev->of_node,
+				"qcom,redrive-voltage-level", &len) &&
+				len == sizeof(phy->redrive_voltage_levels)) {
+			ret = of_property_read_u32_array(dev->of_node,
+					"qcom,redrive-voltage-level",
+					(u32 *) phy->redrive_voltage_levels,
+					len / sizeof(u32));
+			if (ret) {
+				dev_err(dev,
+					"err qcom,redrive-voltage-level\n");
+				goto err;
+			}
+		} else {
+			ret = -EINVAL;
+			dev_err(dev, "err inputs for redrive-voltage-level\n");
+			goto err;
+		}
+
+		ret = of_property_read_u32(dev->of_node, "qcom,redrive-load",
+				&phy->redrive_load);
+		if (ret) {
+			dev_err(&pdev->dev, "unable to read redrive load\n");
+			goto err;
+		}
+
+		dev_dbg(dev, "Get FPC re-drive ldo regulator\n");
+	}
+
 	platform_set_drvdata(pdev, phy);
 
 	if (of_property_read_bool(dev->of_node, "qcom,vbus-valid-override"))
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 3178d8a..cab80ac 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -152,6 +152,7 @@
 	{ USB_DEVICE(0x12B8, 0xEC62) }, /* Link G4+ ECU */
 	{ USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
 	{ USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */
+	{ USB_DEVICE(0x155A, 0x1006) },	/* ELDAT Easywave RX09 */
 	{ USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */
 	{ USB_DEVICE(0x166A, 0x0301) }, /* Clipsal 5800PC C-Bus Wireless PC Interface */
 	{ USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 0c743e4..71cbc68 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -773,6 +773,7 @@
 		.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
 	{ USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
 	{ USB_DEVICE(NOVITUS_VID, NOVITUS_BONO_E_PID) },
+	{ USB_DEVICE(FTDI_VID, RTSYSTEMS_USB_VX8_PID) },
 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S03_PID) },
 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_59_PID) },
 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57A_PID) },
@@ -935,6 +936,7 @@
 	{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_FHE_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) },
 	{ USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 543d280..76a10b2 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -922,6 +922,9 @@
 /*
  * RT Systems programming cables for various ham radios
  */
+/* This device uses the VID of FTDI */
+#define RTSYSTEMS_USB_VX8_PID   0x9e50  /* USB-VX8 USB to 7 pin modular plug for Yaesu VX-8 radio */
+
 #define RTSYSTEMS_VID		0x2100	/* Vendor ID */
 #define RTSYSTEMS_USB_S03_PID	0x9001	/* RTS-03 USB to Serial Adapter */
 #define RTSYSTEMS_USB_59_PID	0x9e50	/* USB-59 USB to 8 pin plug */
@@ -1441,6 +1444,12 @@
 #define FTDI_CINTERION_MC55I_PID	0xA951
 
 /*
+ * Product: FirmwareHubEmulator
+ * Manufacturer: Harman Becker Automotive Systems
+ */
+#define FTDI_FHE_PID		0xA9A0
+
+/*
  * Product: Comet Caller ID decoder
  * Manufacturer: Crucible Technologies
  */
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index 4340b49..4d6eb48 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -1942,6 +1942,8 @@
 	bcb->CDB[0] = 0xEF;
 
 	result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0);
+	if (us->srb != NULL)
+		scsi_set_resid(us->srb, 0);
 	info->BIN_FLAG = flag;
 	kfree(buf);
 
@@ -2295,21 +2297,22 @@
 
 static int ene_transport(struct scsi_cmnd *srb, struct us_data *us)
 {
-	int result = 0;
+	int result = USB_STOR_XFER_GOOD;
 	struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
 
 	/*US_DEBUG(usb_stor_show_command(us, srb)); */
 	scsi_set_resid(srb, 0);
-	if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready))) {
+	if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready)))
 		result = ene_init(us);
-	} else {
+	if (result == USB_STOR_XFER_GOOD) {
+		result = USB_STOR_TRANSPORT_ERROR;
 		if (info->SD_Status.Ready)
 			result = sd_scsi_irp(us, srb);
 
 		if (info->MS_Status.Ready)
 			result = ms_scsi_irp(us, srb);
 	}
-	return 0;
+	return result;
 }
 
 static struct scsi_host_template ene_ub6250_host_template;
diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c
index 9f1ec43..7b8a957 100644
--- a/drivers/vfio/pci/vfio_pci_config.c
+++ b/drivers/vfio/pci/vfio_pci_config.c
@@ -810,6 +810,7 @@
 {
 	__le16 *ctrl = (__le16 *)(vdev->vconfig + pos -
 				  offset + PCI_EXP_DEVCTL);
+	int readrq = le16_to_cpu(*ctrl) & PCI_EXP_DEVCTL_READRQ;
 
 	count = vfio_default_config_write(vdev, pos, count, perm, offset, val);
 	if (count < 0)
@@ -835,6 +836,27 @@
 			pci_try_reset_function(vdev->pdev);
 	}
 
+	/*
+	 * MPS is virtualized to the user, writes do not change the physical
+	 * register since determining a proper MPS value requires a system wide
+	 * device view.  The MRRS is largely independent of MPS, but since the
+	 * user does not have that system-wide view, they might set a safe, but
+	 * inefficiently low value.  Here we allow writes through to hardware,
+	 * but we set the floor to the physical device MPS setting, so that
+	 * we can at least use full TLPs, as defined by the MPS value.
+	 *
+	 * NB, if any devices actually depend on an artificially low MRRS
+	 * setting, this will need to be revisited, perhaps with a quirk
+	 * though pcie_set_readrq().
+	 */
+	if (readrq != (le16_to_cpu(*ctrl) & PCI_EXP_DEVCTL_READRQ)) {
+		readrq = 128 <<
+			((le16_to_cpu(*ctrl) & PCI_EXP_DEVCTL_READRQ) >> 12);
+		readrq = max(readrq, pcie_get_mps(vdev->pdev));
+
+		pcie_set_readrq(vdev->pdev, readrq);
+	}
+
 	return count;
 }
 
@@ -853,11 +875,12 @@
 	 * Allow writes to device control fields, except devctl_phantom,
 	 * which could confuse IOMMU, MPS, which can break communication
 	 * with other physical devices, and the ARI bit in devctl2, which
-	 * is set at probe time.  FLR gets virtualized via our writefn.
+	 * is set at probe time.  FLR and MRRS get virtualized via our
+	 * writefn.
 	 */
 	p_setw(perm, PCI_EXP_DEVCTL,
-	       PCI_EXP_DEVCTL_BCR_FLR | PCI_EXP_DEVCTL_PAYLOAD,
-	       ~PCI_EXP_DEVCTL_PHANTOM);
+	       PCI_EXP_DEVCTL_BCR_FLR | PCI_EXP_DEVCTL_PAYLOAD |
+	       PCI_EXP_DEVCTL_READRQ, ~PCI_EXP_DEVCTL_PHANTOM);
 	p_setw(perm, PCI_EXP_DEVCTL2, NO_VIRT, ~PCI_EXP_DEVCTL2_ARI);
 	return 0;
 }
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index e5b7652..487586e 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -524,7 +524,7 @@
 
 	if (!len && vq->busyloop_timeout) {
 		/* Both tx vq and rx socket were polled here */
-		mutex_lock(&vq->mutex);
+		mutex_lock_nested(&vq->mutex, 1);
 		vhost_disable_notify(&net->dev, vq);
 
 		preempt_disable();
@@ -657,7 +657,7 @@
 	struct iov_iter fixup;
 	__virtio16 num_buffers;
 
-	mutex_lock(&vq->mutex);
+	mutex_lock_nested(&vq->mutex, 0);
 	sock = vq->private_data;
 	if (!sock)
 		goto out;
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index cd38f5a..fce49eb 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -211,8 +211,7 @@
 	if (mask)
 		vhost_poll_wakeup(&poll->wait, 0, 0, (void *)mask);
 	if (mask & POLLERR) {
-		if (poll->wqh)
-			remove_wait_queue(poll->wqh, &poll->wait);
+		vhost_poll_stop(poll);
 		ret = -EINVAL;
 	}
 
@@ -1176,14 +1175,14 @@
 /* Caller should have vq mutex and device mutex */
 int vhost_vq_access_ok(struct vhost_virtqueue *vq)
 {
-	if (vq->iotlb) {
-		/* When device IOTLB was used, the access validation
-		 * will be validated during prefetching.
-		 */
+	if (!vq_log_access_ok(vq, vq->log_base))
+		return 0;
+
+	/* Access validation occurs at prefetch time with IOTLB */
+	if (vq->iotlb)
 		return 1;
-	}
-	return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used) &&
-		vq_log_access_ok(vq, vq->log_base);
+
+	return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used);
 }
 EXPORT_SYMBOL_GPL(vhost_vq_access_ok);
 
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 16c8fcf..8c835f1 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -134,7 +134,7 @@
 {
 	int rc;
 	struct backlight_device *bd = to_backlight_device(dev);
-	unsigned long power;
+	unsigned long power, old_power;
 
 	rc = kstrtoul(buf, 0, &power);
 	if (rc)
@@ -145,10 +145,16 @@
 	if (bd->ops) {
 		pr_debug("set power to %lu\n", power);
 		if (bd->props.power != power) {
+			old_power = bd->props.power;
 			bd->props.power = power;
-			backlight_update_status(bd);
+			rc = backlight_update_status(bd);
+			if (rc)
+				bd->props.power = old_power;
+			else
+				rc = count;
+		} else {
+			rc = count;
 		}
-		rc = count;
 	}
 	mutex_unlock(&bd->ops_lock);
 
@@ -176,8 +182,7 @@
 		else {
 			pr_debug("set brightness to %lu\n", brightness);
 			bd->props.brightness = brightness;
-			backlight_update_status(bd);
-			rc = 0;
+			rc = backlight_update_status(bd);
 		}
 	}
 	mutex_unlock(&bd->ops_lock);
diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c
index d7c239e..f557406 100644
--- a/drivers/video/backlight/corgi_lcd.c
+++ b/drivers/video/backlight/corgi_lcd.c
@@ -177,7 +177,7 @@
 	struct spi_message msg;
 	struct spi_transfer xfer = {
 		.len		= 1,
-		.cs_change	= 1,
+		.cs_change	= 0,
 		.tx_buf		= lcd->buf,
 	};
 
diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c
index eab1f84..e4bd63e 100644
--- a/drivers/video/backlight/tdo24m.c
+++ b/drivers/video/backlight/tdo24m.c
@@ -369,7 +369,7 @@
 
 	spi_message_init(m);
 
-	x->cs_change = 1;
+	x->cs_change = 0;
 	x->tx_buf = &lcd->buf[0];
 	spi_message_add_tail(x, m);
 
diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c
index 6a41ea9..4dc5ee8 100644
--- a/drivers/video/backlight/tosa_lcd.c
+++ b/drivers/video/backlight/tosa_lcd.c
@@ -49,7 +49,7 @@
 	struct spi_message msg;
 	struct spi_transfer xfer = {
 		.len		= 1,
-		.cs_change	= 1,
+		.cs_change	= 0,
 		.tx_buf		= buf,
 	};
 
diff --git a/drivers/video/fbdev/msm/dsi_host_v2.c b/drivers/video/fbdev/msm/dsi_host_v2.c
index 33775ec..2cca469 100644
--- a/drivers/video/fbdev/msm/dsi_host_v2.c
+++ b/drivers/video/fbdev/msm/dsi_host_v2.c
@@ -753,8 +753,8 @@
 			}
 
 			if (dchdr->wait)
-				usleep_range(dchdr->wait * 1000,
-					     dchdr->wait * 1000);
+				usleep_range((dchdr->wait * 1000),
+					     (dchdr->wait * 1000) + 10);
 
 			mdss_dsi_buf_init(tp);
 			len = 0;
diff --git a/drivers/video/fbdev/msm/mdp3.c b/drivers/video/fbdev/msm/mdp3.c
index 591c240..c9db88e 100644
--- a/drivers/video/fbdev/msm/mdp3.c
+++ b/drivers/video/fbdev/msm/mdp3.c
@@ -2111,9 +2111,41 @@
 static DEVICE_ATTR(smart_blit, 0664,
 			mdp3_show_smart_blit, mdp3_store_smart_blit);
 
+static ssize_t mdp3_store_twm(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t len)
+{
+	u32 data = -1;
+	ssize_t rc = 0;
+
+	rc = kstrtoint(buf, 10, &data);
+	if (rc) {
+		pr_err("kstrtoint failed. rc=%d\n", rc);
+		return rc;
+	}
+	mdp3_res->twm_en = data ? true : false;
+	pr_err("TWM :  %s\n", (mdp3_res->twm_en) ?
+		"ENABLED" : "DISABLED");
+	return len;
+}
+
+static ssize_t mdp3_show_twm(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = 0;
+
+	pr_err("TWM :  %s\n", (mdp3_res->twm_en) ?
+		"ENABLED" : "DISABLED");
+	ret = snprintf(buf, PAGE_SIZE, "%d\n", mdp3_res->twm_en);
+	return ret;
+}
+
+static DEVICE_ATTR(twm_enable, 0664,
+		mdp3_show_twm, mdp3_store_twm);
+
 static struct attribute *mdp3_fs_attrs[] = {
 	&dev_attr_caps.attr,
 	&dev_attr_smart_blit.attr,
+	&dev_attr_twm_enable.attr,
 	NULL
 };
 
@@ -2378,6 +2410,7 @@
 		mdp3_dynamic_clock_gating_ctrl;
 	mdp3_res->mdss_util->panel_intf_type = mdp3_panel_intf_type;
 	mdp3_res->mdss_util->panel_intf_status = mdp3_panel_get_intf_status;
+	mdp3_res->twm_en = false;
 
 	if (mdp3_res->mdss_util->param_check(mdss_mdp3_panel)) {
 		mdp3_res->mdss_util->display_disabled = true;
diff --git a/drivers/video/fbdev/msm/mdp3.h b/drivers/video/fbdev/msm/mdp3.h
index 6fb39a7..7132dee 100644
--- a/drivers/video/fbdev/msm/mdp3.h
+++ b/drivers/video/fbdev/msm/mdp3.h
@@ -208,7 +208,7 @@
 	bool solid_fill_vote_en;
 	struct list_head reg_bus_clist;
 	struct mutex reg_bus_lock;
-
+	bool twm_en;
 	u32 max_bw;
 
 	u8 ppp_formats[BITS_TO_BYTES(MDP_IMGTYPE_LIMIT1)];
diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.c b/drivers/video/fbdev/msm/mdp3_ctrl.c
index 589f2df..2d13210 100644
--- a/drivers/video/fbdev/msm/mdp3_ctrl.c
+++ b/drivers/video/fbdev/msm/mdp3_ctrl.c
@@ -983,6 +983,11 @@
 	return rc;
 }
 
+static bool mdp3_is_twm_en(void)
+{
+	return mdp3_res->twm_en;
+}
+
 static int mdp3_ctrl_off(struct msm_fb_data_type *mfd)
 {
 	int rc = 0;
@@ -1025,8 +1030,10 @@
 			pr_debug("fb%d is off already", mfd->index);
 			goto off_error;
 		}
-		if (panel && panel->set_backlight)
+		if (panel && panel->set_backlight) {
+			if (!mdp3_is_twm_en())
 			panel->set_backlight(panel, 0);
+		}
 	}
 
 	/*
@@ -1034,12 +1041,13 @@
 	 * events need to be sent to the interface so that the
 	 * panel can be configured in low power mode
 	 */
-	if (panel->event_handler)
-		rc = panel->event_handler(panel, MDSS_EVENT_BLANK,
-			(void *) (long int)mfd->panel_power_state);
-	if (rc)
-		pr_err("EVENT_BLANK error (%d)\n", rc);
-
+	if (!mdp3_is_twm_en()) {
+		if (panel->event_handler)
+			rc = panel->event_handler(panel, MDSS_EVENT_BLANK,
+				(void *) (long int)mfd->panel_power_state);
+		if (rc)
+			pr_err("EVENT_BLANK error (%d)\n", rc);
+	}
 	if (intf_stopped) {
 		if (!mdp3_session->clk_on)
 			mdp3_ctrl_clk_enable(mfd, 1);
@@ -1065,9 +1073,27 @@
 		mdp3_irq_deregister();
 	}
 
-	if (panel->event_handler)
-		rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF,
-			(void *) (long int)mfd->panel_power_state);
+	if (panel->event_handler) {
+		if (mdp3_is_twm_en()) {
+			pr_info("TWM active skip panel off, disable disp_en\n");
+			if (gpio_is_valid(panel->panel_en_gpio)) {
+				rc = gpio_direction_output(
+					panel->panel_en_gpio, 1);
+			if (rc) {
+				pr_err("%s:set dir for gpio(%d) FAIL\n",
+					__func__, panel->panel_en_gpio);
+			} else {
+				gpio_set_value((panel->panel_en_gpio), 0);
+				usleep_range(100, 110);
+				pr_debug("%s:set disp_en_gpio_%d Low\n",
+					__func__, panel->panel_en_gpio);
+				}
+			}
+		} else {
+			rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF,
+				(void *) (long int)mfd->panel_power_state);
+		}
+	}
 	if (rc)
 		pr_err("EVENT_PANEL_OFF error (%d)\n", rc);
 
@@ -2870,6 +2896,7 @@
 	mdp3_interface->configure_panel = mdp3_update_panel_info;
 	mdp3_interface->input_event_handler = NULL;
 	mdp3_interface->signal_retire_fence = NULL;
+	mdp3_interface->is_twm_en = mdp3_is_twm_en;
 
 	mdp3_session = kzalloc(sizeof(struct mdp3_session_data), GFP_KERNEL);
 	if (!mdp3_session)
diff --git a/drivers/video/fbdev/msm/mdp3_ppp.c b/drivers/video/fbdev/msm/mdp3_ppp.c
index 9253a69..6095073 100644
--- a/drivers/video/fbdev/msm/mdp3_ppp.c
+++ b/drivers/video/fbdev/msm/mdp3_ppp.c
@@ -196,12 +196,20 @@
 
 	if (((req->src_rect.x + req->src_rect.w) > req->src.width) ||
 	    ((req->src_rect.y + req->src_rect.h) > req->src.height)) {
+		pr_err("%s: src roi (x=%d,y=%d,w=%d, h=%d) WxH(%dx%d)\n",
+			__func__, req->src_rect.x, req->src_rect.y,
+			 req->src_rect.w, req->src_rect.h, req->src.width,
+			 req->src.height);
 		pr_err("%s: src roi larger than boundary\n", __func__);
 		return -EINVAL;
 	}
 
 	if (((req->dst_rect.x + req->dst_rect.w) > req->dst.width) ||
 	    ((req->dst_rect.y + req->dst_rect.h) > req->dst.height)) {
+		pr_err("%s: dst roi (x=%d,y=%d,w=%d, h=%d) WxH(%dx%d)\n",
+			__func__, req->dst_rect.x, req->dst_rect.y,
+			req->dst_rect.w, req->dst_rect.h, req->dst.width,
+			req->dst.height);
 		pr_err("%s: dst roi larger than boundary\n", __func__);
 		return -EINVAL;
 	}
diff --git a/drivers/video/fbdev/msm/mdss_debug.c b/drivers/video/fbdev/msm/mdss_debug.c
index f38d40c..7d07040 100644
--- a/drivers/video/fbdev/msm/mdss_debug.c
+++ b/drivers/video/fbdev/msm/mdss_debug.c
@@ -46,6 +46,42 @@
 
 #define INVALID_XIN_ID     0xFF
 
+static u32 dsi_dbg_bus_sdm660[] = {
+	0x0001, 0x1001, 0x0001, 0x0011,
+	0x1021, 0x0021, 0x0031, 0x0041,
+	0x0051, 0x0061, 0x3061, 0x0061,
+	0x2061, 0x2061, 0x1061, 0x1061,
+	0x1061, 0x0071, 0x0071, 0x0071,
+	0x0081, 0x0081, 0x00A1, 0x00A1,
+	0x10A1, 0x20A1, 0x30A1, 0x10A1,
+	0x10A1, 0x30A1, 0x20A1, 0x00B1,
+	0x00C1, 0x00C1, 0x10C1, 0x20C1,
+	0x30C1, 0x00D1, 0x00D1, 0x20D1,
+	0x30D1, 0x00E1, 0x00E1, 0x00E1,
+	0x00F1, 0x00F1, 0x0101, 0x0101,
+	0x1101, 0x2101, 0x3101, 0x0111,
+	0x0141, 0x1141, 0x0141, 0x1141,
+	0x1141, 0x0151, 0x0151, 0x1151,
+	0x2151, 0x3151, 0x0161, 0x0161,
+	0x1161, 0x0171, 0x0171, 0x0181,
+	0x0181, 0x0191, 0x0191, 0x01A1,
+	0x01A1, 0x01B1, 0x01B1, 0x11B1,
+	0x21B1, 0x01C1, 0x01C1, 0x11C1,
+	0x21C1, 0x31C1, 0x01D1, 0x01D1,
+	0x01D1, 0x01D1, 0x11D1, 0x21D1,
+	0x21D1, 0x01E1, 0x01E1, 0x01F1,
+	0x01F1, 0x0201, 0x0201, 0x0211,
+	0x0221, 0x0231, 0x0241, 0x0251,
+	0x0281, 0x0291, 0x0281, 0x0291,
+	0x02A1, 0x02B1, 0x02C1, 0x0321,
+	0x0321, 0x1321, 0x2321, 0x3321,
+	0x0331, 0x0331, 0x1331, 0x0341,
+	0x0341, 0x1341, 0x2341, 0x3341,
+	0x0351, 0x0361, 0x0361, 0x1361,
+	0x2361, 0x0371, 0x0381, 0x0391,
+	0x03C1, 0x03D1, 0x03E1, 0x03F1,
+};
+
 static DEFINE_MUTEX(mdss_debug_lock);
 
 static char panel_reg[2] = {DEFAULT_READ_PANEL_POWER_MODE_REG, 0x00};
@@ -1377,6 +1413,38 @@
 			}
 		} else {
 			if (block_id <= DISPLAY_MISR_HDMI) {
+				/*
+				 * In Dual LM single display configuration,
+				 * the interface number (i.e. block_id)
+				 * might not be the one given from ISR.
+				 * We should always check with the actual
+				 * intf_num from ctl.
+				 */
+				struct msm_fb_data_type *mfd = NULL;
+
+				/*
+				 * ISR pass in NULL ctl, so we need to get it
+				 * from the mdata.
+				 */
+				if (!ctl && mdata->mixer_intf)
+					ctl = mdata->mixer_intf->ctl;
+				if (ctl)
+					mfd = ctl->mfd;
+				if (mfd && is_dual_lm_single_display(mfd)) {
+					switch (ctl->intf_num) {
+					case MDSS_MDP_INTF1:
+						block_id = DISPLAY_MISR_DSI0;
+						break;
+					case MDSS_MDP_INTF2:
+						block_id = DISPLAY_MISR_DSI1;
+						break;
+					default:
+						pr_err("Unmatch INTF for Dual LM single display configuration, INTF:%d\n",
+								ctl->intf_num);
+						return NULL;
+					}
+				}
+
 				intf_base = (char *)mdss_mdp_get_intf_base_addr(
 						mdata, block_id);
 
@@ -1390,11 +1458,15 @@
 
 					/*
 					 * extra offset required for
-					 * cmd misr in 8996
+					 * cmd misr in 8996 and mdss3.x
 					 */
 					if (IS_MDSS_MAJOR_MINOR_SAME(
 						  mdata->mdp_rev,
-						  MDSS_MDP_HW_REV_107)) {
+						  MDSS_MDP_HW_REV_107) ||
+						(mdata->mdp_rev ==
+							MDSS_MDP_HW_REV_300) ||
+						(mdata->mdp_rev ==
+							MDSS_MDP_HW_REV_301)) {
 						ctrl_reg += 0x8;
 						value_reg += 0x8;
 					}
@@ -1786,6 +1858,24 @@
 
 }
 
+void mdss_dsi_debug_bus_init(struct mdss_dsi_data *sdata)
+{
+	if (!sdata)
+		return;
+
+	sdata->dbg_bus = NULL;
+	sdata->dbg_bus_size = 0;
+
+	switch (sdata->shared_data->hw_rev) {
+	case MDSS_DSI_HW_REV_201:
+		sdata->dbg_bus = dsi_dbg_bus_sdm660;
+		sdata->dbg_bus_size = ARRAY_SIZE(dsi_dbg_bus_sdm660);
+		break;
+	default:
+		break;
+	}
+}
+
 int mdss_dump_misr_data(char **buf, u32 size)
 {
 	struct mdss_mdp_misr_map  *dsi0_map;
diff --git a/drivers/video/fbdev/msm/mdss_debug.h b/drivers/video/fbdev/msm/mdss_debug.h
index 0d482c0..64df339 100644
--- a/drivers/video/fbdev/msm/mdss_debug.h
+++ b/drivers/video/fbdev/msm/mdss_debug.h
@@ -78,8 +78,8 @@
 #define MDSS_XLOG_IOMMU(...) mdss_xlog(__func__, __LINE__, MDSS_XLOG_IOMMU, \
 		##__VA_ARGS__, DATA_LIMITER)
 
-#define ATRACE_END(name) trace_mdss_mark_write(current->tgid, name, 0)
-#define ATRACE_BEGIN(name) trace_mdss_mark_write(current->tgid, name, 1)
+#define ATRACE_END(name) trace_tracing_mark_write(current->tgid, name, 0)
+#define ATRACE_BEGIN(name) trace_tracing_mark_write(current->tgid, name, 1)
 #define ATRACE_FUNC() ATRACE_BEGIN(__func__)
 
 #define ATRACE_INT(name, value) \
@@ -173,6 +173,7 @@
 void mdss_dump_reg(const char *dump_name, u32 reg_dump_flag, char *addr,
 	int len, u32 **dump_mem, bool from_isr);
 void mdss_mdp_debug_mid(u32 mid);
+void mdss_dump_dsi_debug_bus(u32 bus_dump_flag, u32 **dump_mem);
 #else
 struct mdss_debug_base;
 struct dump_offset;
diff --git a/drivers/video/fbdev/msm/mdss_debug_xlog.c b/drivers/video/fbdev/msm/mdss_debug_xlog.c
index a651b55..7bf4f11 100644
--- a/drivers/video/fbdev/msm/mdss_debug_xlog.c
+++ b/drivers/video/fbdev/msm/mdss_debug_xlog.c
@@ -32,6 +32,7 @@
 #define XLOG_DEFAULT_REGDUMP 0x2 /* dump in RAM */
 #define XLOG_DEFAULT_DBGBUSDUMP 0x2 /* dump in RAM */
 #define XLOG_DEFAULT_VBIF_DBGBUSDUMP 0x2 /* dump in RAM */
+#define XLOG_DEFAULT_DSI_DBGBUSDUMP 0x2 /* dump in RAM */
 
 /*
  * xlog will print this number of entries when it is called through
@@ -73,14 +74,17 @@
 	u32 enable_reg_dump;
 	u32 enable_dbgbus_dump;
 	u32 enable_vbif_dbgbus_dump;
+	u32 enable_dsi_dbgbus_dump;
 	struct work_struct xlog_dump_work;
 	struct mdss_debug_base *blk_arr[MDSS_DEBUG_BASE_MAX];
 	bool work_panic;
 	bool work_dbgbus;
 	bool work_vbif_dbgbus;
+	bool work_dsi_dbgbus;
 	u32 *dbgbus_dump; /* address for the debug bus dump */
 	u32 *vbif_dbgbus_dump; /* address for the vbif debug bus dump */
 	u32 *nrt_vbif_dbgbus_dump; /* address for the nrt vbif debug bus dump */
+	u32 *dsi_dbgbus_dump; /* address for the dsi debug bus dump */
 } mdss_dbg_xlog;
 
 static inline bool mdss_xlog_is_enabled(u32 flag)
@@ -572,7 +576,7 @@
 
 static void mdss_xlog_dump_array(struct mdss_debug_base *blk_arr[],
 	u32 len, bool dead, const char *name, bool dump_dbgbus,
-	bool dump_vbif_dbgbus)
+	bool dump_vbif_dbgbus, bool dump_dsi_dbgbus)
 {
 	int i;
 
@@ -596,6 +600,10 @@
 			&mdss_dbg_xlog.nrt_vbif_dbgbus_dump, false);
 	}
 
+	if (dump_dsi_dbgbus)
+		mdss_dump_dsi_debug_bus(mdss_dbg_xlog.enable_dsi_dbgbus_dump,
+			&mdss_dbg_xlog.dsi_dbgbus_dump);
+
 	if (dead && mdss_dbg_xlog.panic_on_err)
 		panic(name);
 }
@@ -607,7 +615,8 @@
 		ARRAY_SIZE(mdss_dbg_xlog.blk_arr),
 		mdss_dbg_xlog.work_panic, "xlog_workitem",
 		mdss_dbg_xlog.work_dbgbus,
-		mdss_dbg_xlog.work_vbif_dbgbus);
+		mdss_dbg_xlog.work_vbif_dbgbus,
+		mdss_dbg_xlog.work_dsi_dbgbus);
 }
 
 void mdss_xlog_tout_handler_default(bool queue, const char *name, ...)
@@ -615,6 +624,7 @@
 	int i, index = 0;
 	bool dead = false;
 	bool dump_dbgbus = false, dump_vbif_dbgbus = false;
+	bool dump_dsi_dbgbus = false;
 	va_list args;
 	char *blk_name = NULL;
 	struct mdss_debug_base *blk_base = NULL;
@@ -650,6 +660,9 @@
 		if (!strcmp(blk_name, "vbif_dbg_bus"))
 			dump_vbif_dbgbus = true;
 
+		if (!strcmp(blk_name, "dsi_dbg_bus"))
+			dump_dsi_dbgbus = true;
+
 		if (!strcmp(blk_name, "panic"))
 			dead = true;
 	}
@@ -660,10 +673,11 @@
 		mdss_dbg_xlog.work_panic = dead;
 		mdss_dbg_xlog.work_dbgbus = dump_dbgbus;
 		mdss_dbg_xlog.work_vbif_dbgbus = dump_vbif_dbgbus;
+		mdss_dbg_xlog.work_dsi_dbgbus = dump_dsi_dbgbus;
 		schedule_work(&mdss_dbg_xlog.xlog_dump_work);
 	} else {
 		mdss_xlog_dump_array(blk_arr, blk_len, dead, name, dump_dbgbus,
-			dump_vbif_dbgbus);
+			dump_vbif_dbgbus, dump_dsi_dbgbus);
 	}
 }
 
@@ -752,6 +766,7 @@
 	mdss_dbg_xlog.enable_reg_dump = XLOG_DEFAULT_REGDUMP;
 	mdss_dbg_xlog.enable_dbgbus_dump = XLOG_DEFAULT_DBGBUSDUMP;
 	mdss_dbg_xlog.enable_vbif_dbgbus_dump = XLOG_DEFAULT_VBIF_DBGBUSDUMP;
+	mdss_dbg_xlog.enable_dsi_dbgbus_dump = XLOG_DEFAULT_DSI_DBGBUSDUMP;
 
 	pr_info("xlog_status: enable:%d, panic:%d, dump:%d\n",
 		mdss_dbg_xlog.xlog_enable, mdss_dbg_xlog.panic_on_err,
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index d8e74da..d3e5269 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -27,6 +27,7 @@
 #include <linux/msm-bus.h>
 #include <linux/pm_qos.h>
 #include <linux/mdss_io_util.h>
+#include <linux/dma-buf.h>
 
 #include "mdss.h"
 #include "mdss_panel.h"
@@ -46,6 +47,97 @@
 
 static struct pm_qos_request mdss_dsi_pm_qos_request;
 
+void mdss_dump_dsi_debug_bus(u32 bus_dump_flag,
+	u32 **dump_mem)
+{
+	struct mdss_dsi_data *sdata = mdss_dsi_res;
+	struct mdss_dsi_ctrl_pdata *m_ctrl, *s_ctrl;
+	bool in_log, in_mem;
+	u32 *dump_addr = NULL;
+	u32 status0 = 0, status1 = 0;
+	phys_addr_t phys = 0;
+	int list_size = 0;
+	int i;
+	bool dsi0_active = false, dsi1_active = false;
+
+	if (!sdata || !sdata->dbg_bus || !sdata->dbg_bus_size)
+		return;
+
+	m_ctrl = sdata->ctrl_pdata[0];
+	s_ctrl = sdata->ctrl_pdata[1];
+
+	if (!m_ctrl)
+		return;
+
+	if (m_ctrl && m_ctrl->shared_data->dsi0_active)
+		dsi0_active = true;
+	if (s_ctrl && s_ctrl->shared_data->dsi1_active)
+		dsi1_active = true;
+
+	list_size = (sdata->dbg_bus_size * sizeof(sdata->dbg_bus[0]) * 4);
+
+	in_log = (bus_dump_flag & MDSS_DBG_DUMP_IN_LOG);
+	in_mem = (bus_dump_flag & MDSS_DBG_DUMP_IN_MEM);
+
+	if (in_mem) {
+		if (!(*dump_mem))
+			*dump_mem = dma_alloc_coherent(&sdata->pdev->dev,
+				list_size, &phys, GFP_KERNEL);
+
+		if (*dump_mem) {
+			dump_addr = *dump_mem;
+			pr_info("%s: start_addr:0x%pK end_addr:0x%pK\n",
+				__func__, dump_addr, dump_addr + list_size);
+		} else {
+			in_mem = false;
+			pr_err("dump_mem: allocation fails\n");
+		}
+	}
+
+	pr_info("========= Start DSI Debug Bus =========\n");
+
+	mdss_dsi_clk_ctrl(m_ctrl, m_ctrl->dsi_clk_handle,
+			  MDSS_DSI_CORE_CLK, MDSS_DSI_CLK_ON);
+
+	for (i = 0; i < sdata->dbg_bus_size; i++) {
+		if (dsi0_active) {
+			writel_relaxed(sdata->dbg_bus[i],
+					m_ctrl->ctrl_base + 0x124);
+			wmb(); /* ensure regsiter is committed */
+		}
+		if (dsi1_active) {
+			writel_relaxed(sdata->dbg_bus[i],
+					s_ctrl->ctrl_base + 0x124);
+			wmb(); /* ensure register is committed */
+		}
+
+		if (dsi0_active) {
+			status0 = readl_relaxed(m_ctrl->ctrl_base + 0x128);
+			if (in_log)
+				pr_err("CTRL:0 bus_ctrl: 0x%x status: 0x%x\n",
+					sdata->dbg_bus[i], status0);
+		}
+		if (dsi1_active) {
+			status1 = readl_relaxed(s_ctrl->ctrl_base + 0x128);
+			if (in_log)
+				pr_err("CTRL:1 bus_ctrl: 0x%x status: 0x%x\n",
+					sdata->dbg_bus[i], status1);
+		}
+
+		if (dump_addr && in_mem) {
+			dump_addr[i*4]     = sdata->dbg_bus[i];
+			dump_addr[i*4 + 1] = status0;
+			dump_addr[i*4 + 2] = status1;
+			dump_addr[i*4 + 3] = 0x0;
+		}
+	}
+
+	mdss_dsi_clk_ctrl(m_ctrl, m_ctrl->dsi_clk_handle,
+			  MDSS_DSI_CORE_CLK, MDSS_DSI_CLK_OFF);
+
+	pr_info("========End DSI Debug Bus=========\n");
+}
+
 static void mdss_dsi_pm_qos_add_request(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
 	struct irq_info *irq_info;
@@ -1704,7 +1796,8 @@
 			ATRACE_BEGIN("dsi_panel_off");
 			ret = ctrl_pdata->off(pdata);
 			if (ret) {
-				pr_err("%s: Panel OFF failed\n", __func__);
+				pr_err("%s: Panel OFF failed\n",
+					__func__);
 				goto error;
 			}
 			ATRACE_END("dsi_panel_off");
@@ -3340,6 +3433,8 @@
 	else
 		ctrl_pdata->shared_data->dsi1_active = true;
 
+	mdss_dsi_debug_bus_init(mdss_dsi_res);
+
 	return 0;
 
 error_shadow_clk_deinit:
@@ -4069,6 +4164,7 @@
 		if (!gpio_is_valid(ctrl_pdata->disp_en_gpio))
 			pr_debug("%s:%d, Disp_en gpio not specified\n",
 					__func__, __LINE__);
+		pdata->panel_en_gpio = ctrl_pdata->disp_en_gpio;
 	}
 
 	ctrl_pdata->disp_te_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index fd6c4d9..5e921ff 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -57,7 +57,7 @@
 #define MDSS_DSI_HW_REV_104             0x10040000      /* 8996   */
 #define MDSS_DSI_HW_REV_104_1           0x10040001      /* 8996   */
 #define MDSS_DSI_HW_REV_104_2           0x10040002      /* 8937   */
-
+#define MDSS_DSI_HW_REV_201		20010000	/* 660 */
 #define MDSS_DSI_HW_REV_STEP_0		0x0
 #define MDSS_DSI_HW_REV_STEP_1		0x1
 #define MDSS_DSI_HW_REV_STEP_2		0x2
@@ -297,6 +297,8 @@
 	 * mutex, clocks, regulator information, setup information
 	 */
 	struct dsi_shared_data *shared_data;
+	u32 *dbg_bus;
+	int dbg_bus_size;
 };
 
 /*
@@ -407,7 +409,7 @@
 	int (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
 	void (*switch_mode)(struct mdss_panel_data *pdata, int mode);
 	struct mdss_panel_data panel_data;
-	unsigned char *ctrl_base;
+	unsigned char __iomem *ctrl_base;
 	struct mdss_io_data ctrl_io;
 	struct mdss_io_data mmss_misc_io;
 	struct mdss_io_data phy_io;
@@ -684,6 +686,8 @@
 int mdss_dsi_phy_pll_reset_status(struct mdss_dsi_ctrl_pdata *ctrl);
 int mdss_dsi_panel_power_ctrl(struct mdss_panel_data *pdata, int power_state);
 
+void mdss_dsi_debug_bus_init(struct mdss_dsi_data *sdata);
+
 static inline const char *__mdss_dsi_pm_name(enum dsi_pm_type module)
 {
 	switch (module) {
diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c
index 7d737b5..f425620 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_host.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_host.c
@@ -161,7 +161,14 @@
 
 	MDSS_XLOG(ctrl->ndx, enable, ctrl->mdp_busy, current->pid,
 		client);
-	if (enable == 0) {
+	/*
+	 * ensure that before going into ecg or turning
+	 * off the clocks, cmd_mdp_busy is not true. During a
+	 * race condition, clocks are turned off and so the
+	 * isr for cmd_mdp_busy does not get cleared in hw.
+	 */
+	if (enable == MDSS_DSI_CLK_OFF ||
+		enable == MDSS_DSI_CLK_EARLY_GATE) {
 		/* need wait before disable */
 		mutex_lock(&ctrl->cmd_mutex);
 		mdss_dsi_cmd_mdp_busy(ctrl);
@@ -1155,6 +1162,8 @@
 
 		rc = mdss_dsi_cmdlist_put(ctrl, &cmdreq);
 		if (rc <= 0) {
+			if (!mdss_dsi_sync_wait_enable(ctrl) ||
+				mdss_dsi_sync_wait_trigger(ctrl))
 			pr_err("%s: get status: fail\n", __func__);
 			return rc;
 		}
@@ -1242,6 +1251,15 @@
 {
 	u32 data, offset;
 
+	if (!dsc) {
+		if (ctrl->panel_mode == DSI_VIDEO_MODE)
+			offset = MDSS_DSI_VIDEO_COMPRESSION_MODE_CTRL;
+		else
+			offset = MDSS_DSI_COMMAND_COMPRESSION_MODE_CTRL;
+		MIPI_OUTP((ctrl->ctrl_base) + offset, 0);
+		return;
+	}
+
 	if (dsc->pkt_per_line <= 0) {
 		pr_err("%s: Error: pkt_per_line cannot be negative or 0\n",
 			__func__);
@@ -1430,8 +1448,7 @@
 		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x5C, stream_total);
 	}
 
-	if (dsc)	/* compressed */
-		mdss_dsi_dsc_config(ctrl_pdata, dsc);
+	mdss_dsi_dsc_config(ctrl_pdata, dsc);
 }
 
 void mdss_dsi_ctrl_setup(struct mdss_dsi_ctrl_pdata *ctrl)
@@ -1488,6 +1505,8 @@
 	/* mask out overflow errors */
 	if (ignore_underflow)
 		mdss_dsi_set_reg(ctrl_pdata, 0x10c, 0x0f0000, 0x0f0000);
+
+	MDSS_XLOG(ctrl_pdata->ndx, ctrl_pdata->mdp_busy);
 	MIPI_OUTP(ctrl_pdata->ctrl_base + 0x098, 0x01); /* trigger  */
 	wmb(); /* ensure write is finished before progressing */
 
@@ -1689,8 +1708,8 @@
 					__func__,  cm->payload[0], len);
 
 			if (!wait || dchdr->wait > VSYNC_PERIOD)
-				usleep_range(dchdr->wait * 1000,
-					     dchdr->wait * 1000);
+				usleep_range((dchdr->wait * 1000),
+					     (dchdr->wait * 1000) + 10);
 
 			mdss_dsi_buf_init(tp);
 			len = 0;
@@ -2108,6 +2127,7 @@
 
 	MIPI_OUTP((ctrl->ctrl_base) + 0x090, 0x01);
 	wmb(); /* ensure write is finished before progressing */
+	MDSS_XLOG(ctrl->dma_addr, len);
 
 	if (ctrl->do_unicast) {
 		/* let cmd_trigger to kickoff later */
@@ -2186,6 +2206,7 @@
 	bool ack_error = false;
 	char reg[16];
 	int repeated_bytes = 0;
+	struct mdss_dsi_ctrl_pdata *mctrl = mdss_dsi_get_other_ctrl(ctrl);
 
 	lp = (u32 *)rp->data;
 	temp = (u32 *)reg;
@@ -2246,7 +2267,11 @@
 	off += ((cnt - 1) * 4);
 
 	for (i = 0; i < cnt; i++) {
-		data = (u32)MIPI_INP((ctrl->ctrl_base) + off);
+		if (mdss_dsi_sync_wait_trigger(ctrl))
+			data = (u32)MIPI_INP((mctrl->ctrl_base) + off);
+		else
+			data = (u32)MIPI_INP((ctrl->ctrl_base) + off);
+
 		/* to network byte order */
 		if (!repeated_bytes)
 			*lp++ = ntohl(data);
@@ -2974,7 +2999,10 @@
 		 * warning message is ignored.
 		 */
 		if (ctrl->panel_data.panel_info.esd_check_enabled &&
-			(ctrl->status_mode == ESD_BTA) && (status & 0x1008000))
+			((ctrl->status_mode == ESD_BTA) ||
+			 (ctrl->status_mode == ESD_REG) ||
+			 (ctrl->status_mode == ESD_REG_NT35596)) &&
+			 (status & 0x1008000))
 			return false;
 
 		pr_err("%s: status=%x\n", __func__, status);
@@ -3127,7 +3155,7 @@
 		pr_err("%s: panic in WQ as dsi error intrs within:%dms\n",
 				__func__, err_container->err_time_delta);
 		MDSS_XLOG_TOUT_HANDLER_WQ("mdp", "dsi0_ctrl", "dsi0_phy",
-			"dsi1_ctrl", "dsi1_phy");
+			"dsi1_ctrl", "dsi1_phy", "dsi_dbg_bus", "panic");
 	}
 }
 
@@ -3205,8 +3233,10 @@
 		 * cleared.
 		 */
 		if (ctrl->panel_data.panel_info.esd_check_enabled &&
-			(ctrl->status_mode == ESD_BTA) &&
-			(ctrl->panel_mode == DSI_VIDEO_MODE)) {
+			((ctrl->status_mode == ESD_BTA) ||
+			 (ctrl->status_mode == ESD_REG) ||
+			 (ctrl->status_mode == ESD_REG_NT35596)) &&
+			 (ctrl->panel_mode == DSI_VIDEO_MODE)) {
 			isr &= ~DSI_INTR_ERROR;
 			/* clear only overflow */
 			mdss_dsi_set_reg(ctrl, 0x0c, 0x44440000, 0x44440000);
@@ -3215,6 +3245,7 @@
 	}
 
 	if (isr & DSI_INTR_VIDEO_DONE) {
+		MDSS_XLOG(ctrl->ndx, isr, 0x111);
 		spin_lock(&ctrl->mdp_lock);
 		mdss_dsi_disable_irq_nosync(ctrl, DSI_VIDEO_TERM);
 		complete(&ctrl->video_comp);
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index 1688503..e586667 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -427,6 +427,8 @@
 						__func__);
 					goto exit;
 				}
+				gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
+				usleep_range(100, 110);
 			}
 
 			if (pdata->panel_info.rst_seq_len) {
@@ -443,8 +445,8 @@
 				gpio_set_value((ctrl_pdata->rst_gpio),
 					pdata->panel_info.rst_seq[i]);
 				if (pdata->panel_info.rst_seq[++i])
-					usleep_range(pinfo->rst_seq[i] * 1000,
-						     pinfo->rst_seq[i] * 1000);
+					usleep_range((pinfo->rst_seq[i] * 1000),
+					(pinfo->rst_seq[i] * 1000) + 10);
 			}
 
 			if (gpio_is_valid(ctrl_pdata->bklt_en_gpio)) {
@@ -497,6 +499,7 @@
 		}
 		if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
 			gpio_set_value((ctrl_pdata->disp_en_gpio), 0);
+			usleep_range(100, 110);
 			gpio_free(ctrl_pdata->disp_en_gpio);
 		}
 		gpio_set_value((ctrl_pdata->rst_gpio), 0);
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index 27299d10..72f651e 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -1161,11 +1161,24 @@
 		if (pdata->next) {
 			spt = mdss_panel_get_timing_by_name(pdata->next,
 					modedb[i].name);
-			if (!IS_ERR_OR_NULL(spt))
+			/* for split config, recalculate xres and pixel clock */
+			if (!IS_ERR_OR_NULL(spt)) {
+				unsigned long pclk, h_total, v_total;
 				modedb[i].xres += spt->xres;
-			else
+				h_total = modedb[i].xres +
+					modedb[i].left_margin +
+					modedb[i].right_margin +
+					modedb[i].hsync_len;
+				v_total = modedb[i].yres +
+					modedb[i].lower_margin +
+					modedb[i].upper_margin +
+					modedb[i].vsync_len;
+				pclk = h_total * v_total * modedb[i].refresh;
+				modedb[i].pixclock = KHZ2PICOS(pclk / 1000);
+			} else {
 				pr_debug("no matching split config for %s\n",
 						modedb[i].name);
+			}
 
 			/*
 			 * if no panel timing found for current, need to
@@ -1653,6 +1666,7 @@
 	u32 temp = bkl_lvl;
 	bool ad_bl_notify_needed = false;
 	bool bl_notify_needed = false;
+	bool twm_en = false;
 
 	if ((((mdss_fb_is_power_off(mfd) && mfd->dcm_state != DCM_ENTER)
 		|| !mfd->allow_bl_update) && !IS_CALIB_MODE_BL(mfd)) ||
@@ -1687,9 +1701,17 @@
 			if (mfd->bl_level != bkl_lvl)
 				bl_notify_needed = true;
 			pr_debug("backlight sent to panel :%d\n", temp);
-			pdata->set_backlight(pdata, temp);
-			mfd->bl_level = bkl_lvl;
-			mfd->bl_level_scaled = temp;
+
+			if (mfd->mdp.is_twm_en)
+				twm_en = mfd->mdp.is_twm_en();
+
+			if (twm_en) {
+				pr_info("TWM Enabled skip backlight update\n");
+			} else {
+				pdata->set_backlight(pdata, temp);
+				mfd->bl_level = bkl_lvl;
+				mfd->bl_level_scaled = temp;
+			}
 		}
 		if (ad_bl_notify_needed)
 			mdss_fb_bl_update_notify(mfd,
@@ -4730,6 +4752,9 @@
 	if (!mfd || !mfd->panel_info)
 		return -EINVAL;
 
+	/* make sure that we are idle while switching */
+	mdss_fb_wait_for_kickoff(mfd);
+
 	pinfo = mfd->panel_info;
 	if (pinfo->mipi.dms_mode == DYNAMIC_MODE_SWITCH_SUSPEND_RESUME) {
 		ret = mdss_fb_blanking_mode_switch(mfd, mode);
diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h
index c85f033..5f2baef 100644
--- a/drivers/video/fbdev/msm/mdss_fb.h
+++ b/drivers/video/fbdev/msm/mdss_fb.h
@@ -236,6 +236,7 @@
 	int (*pp_release_fnc)(struct msm_fb_data_type *mfd);
 	void (*signal_retire_fence)(struct msm_fb_data_type *mfd,
 					int retire_cnt);
+	bool (*is_twm_en)(void);
 	void *private1;
 };
 
diff --git a/drivers/video/fbdev/msm/mdss_io_util.c b/drivers/video/fbdev/msm/mdss_io_util.c
index 3117793..2f70ad3 100644
--- a/drivers/video/fbdev/msm/mdss_io_util.c
+++ b/drivers/video/fbdev/msm/mdss_io_util.c
@@ -275,8 +275,8 @@
 			}
 			need_sleep = !regulator_is_enabled(in_vreg[i].vreg);
 			if (in_vreg[i].pre_on_sleep && need_sleep)
-				usleep_range(in_vreg[i].pre_on_sleep * 1000,
-					in_vreg[i].pre_on_sleep * 1000);
+				usleep_range((in_vreg[i].pre_on_sleep * 1000),
+					(in_vreg[i].pre_on_sleep * 1000) + 10);
 			rc = regulator_set_load(in_vreg[i].vreg,
 				in_vreg[i].load[DSS_REG_MODE_ENABLE]);
 			if (rc < 0) {
@@ -287,8 +287,8 @@
 			}
 			rc = regulator_enable(in_vreg[i].vreg);
 			if (in_vreg[i].post_on_sleep && need_sleep)
-				usleep_range(in_vreg[i].post_on_sleep * 1000,
-					in_vreg[i].post_on_sleep * 1000);
+				usleep_range((in_vreg[i].post_on_sleep * 1000),
+					(in_vreg[i].post_on_sleep * 1000) + 10);
 			if (rc < 0) {
 				DEV_ERR("%pS->%s: %s enable failed\n",
 					__builtin_return_address(0), __func__,
@@ -299,8 +299,8 @@
 	} else {
 		for (i = num_vreg-1; i >= 0; i--) {
 			if (in_vreg[i].pre_off_sleep)
-				usleep_range(in_vreg[i].pre_off_sleep * 1000,
-					in_vreg[i].pre_off_sleep * 1000);
+				usleep_range((in_vreg[i].pre_off_sleep * 1000),
+					(in_vreg[i].pre_off_sleep * 1000) + 10);
 			regulator_set_load(in_vreg[i].vreg,
 				in_vreg[i].load[DSS_REG_MODE_DISABLE]);
 
@@ -308,8 +308,8 @@
 				regulator_disable(in_vreg[i].vreg);
 
 			if (in_vreg[i].post_off_sleep)
-				usleep_range(in_vreg[i].post_off_sleep * 1000,
-					in_vreg[i].post_off_sleep * 1000);
+				usleep_range((in_vreg[i].post_off_sleep * 1000),
+				(in_vreg[i].post_off_sleep * 1000) + 10);
 		}
 	}
 	return rc;
@@ -321,14 +321,14 @@
 vreg_set_opt_mode_fail:
 	for (i--; i >= 0; i--) {
 		if (in_vreg[i].pre_off_sleep)
-			usleep_range(in_vreg[i].pre_off_sleep * 1000,
-				in_vreg[i].pre_off_sleep * 1000);
+			usleep_range((in_vreg[i].pre_off_sleep * 1000),
+				(in_vreg[i].pre_off_sleep * 1000) + 10);
 		regulator_set_load(in_vreg[i].vreg,
 			in_vreg[i].load[DSS_REG_MODE_DISABLE]);
 		regulator_disable(in_vreg[i].vreg);
 		if (in_vreg[i].post_off_sleep)
-			usleep_range(in_vreg[i].post_off_sleep * 1000,
-				in_vreg[i].post_off_sleep * 1000);
+			usleep_range((in_vreg[i].post_off_sleep * 1000),
+				(in_vreg[i].post_off_sleep * 1000) + 10);
 	}
 
 	return rc;
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index e472e7f..a6d43a6 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -1456,6 +1456,35 @@
 }
 
 /**
+ * mdss_mdp_retention_init() - initialize retention setting
+ * @mdata: pointer to the global mdss data structure.
+ */
+static int mdss_mdp_retention_init(struct mdss_data_type *mdata)
+{
+	struct clk *mdss_axi_clk = mdss_mdp_get_clk(MDSS_CLK_AXI);
+	int rc;
+
+	if (!mdss_axi_clk) {
+		pr_err("failed to get AXI clock\n");
+		return -EINVAL;
+	}
+
+	rc = clk_set_flags(mdss_axi_clk, CLKFLAG_NORETAIN_MEM);
+	if (rc) {
+		pr_err("failed to set AXI no memory retention %d\n", rc);
+		return rc;
+	}
+
+	rc = clk_set_flags(mdss_axi_clk, CLKFLAG_NORETAIN_PERIPH);
+	if (rc) {
+		pr_err("failed to set AXI no periphery retention %d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+/**
  * mdss_bus_bandwidth_ctrl() -- place bus bandwidth request
  * @enable:	value of enable or disable
  *
@@ -2695,6 +2724,12 @@
 		goto probe_done;
 	}
 
+	rc = mdss_mdp_retention_init(mdata);
+	if (rc) {
+		pr_err("unable to initialize mdss mdp retention\n");
+		goto probe_done;
+	}
+
 	pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT_MS);
 	if (mdata->idle_pc_enabled)
 		pm_runtime_use_autosuspend(&pdev->dev);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index 344d6ef..9de02d9 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -571,11 +571,12 @@
 	u32 fps, u32 v_total)
 {
 	u32 active_line_cycle, backfill_cycle, total_cycle;
-	u32 ver_dwnscale;
+	u64 ver_dwnscale;
 	u32 active_line;
 	u32 backfill_line;
 
-	ver_dwnscale = (src_h << PHASE_STEP_SHIFT) / dst.h;
+	ver_dwnscale = src_h << PHASE_STEP_SHIFT;
+	do_div(ver_dwnscale, dst.h);
 
 	if (ver_dwnscale > (MDSS_MDP_QSEED3_VER_DOWNSCALE_LIM
 			<< PHASE_STEP_SHIFT)) {
@@ -599,7 +600,7 @@
 	total_cycle = active_line_cycle + backfill_cycle;
 
 	pr_debug("line: active=%d backfill=%d vds=%d\n",
-		active_line, backfill_line, ver_dwnscale);
+		active_line, backfill_line, (u32)ver_dwnscale);
 	pr_debug("cycle: total=%d active=%d backfill=%d\n",
 		total_cycle, active_line_cycle, backfill_cycle);
 
@@ -4340,11 +4341,13 @@
 		return;
 
 	pr_debug("hw ctl reset is set for ctl:%d\n", ctl->num);
-	status = mdss_mdp_poll_ctl_reset_status(ctl, 5);
+	/* poll for at least ~1 frame */
+	status = mdss_mdp_poll_ctl_reset_status(ctl, 320);
 	if (status) {
-		pr_err("hw recovery is not complete for ctl:%d\n", ctl->num);
+		pr_err("hw recovery is not complete for ctl:%d status:0x%x\n",
+			ctl->num, status);
 		MDSS_XLOG_TOUT_HANDLER("mdp", "vbif", "vbif_nrt", "dbg_bus",
-			"vbif_dbg_bus", "panic");
+			"vbif_dbg_bus", "dsi_dbg_bus", "panic");
 	}
 }
 
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
index 764b830..b49e954 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
@@ -1975,12 +1975,14 @@
 			MDSS_XLOG(0xbad);
 			MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0_ctrl", "dsi0_phy",
 				"dsi1_ctrl", "dsi1_phy", "vbif", "vbif_nrt",
-				"dbg_bus", "vbif_dbg_bus", "panic");
+				"dbg_bus", "vbif_dbg_bus",
+				"dsi_dbg_bus", "panic");
 		} else if (ctx->pp_timeout_report_cnt == MAX_RECOVERY_TRIALS) {
 			MDSS_XLOG(0xbad2);
 			MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0_ctrl", "dsi0_phy",
 				"dsi1_ctrl", "dsi1_phy", "vbif", "vbif_nrt",
-				"dbg_bus", "vbif_dbg_bus", "panic");
+				"dbg_bus", "vbif_dbg_bus",
+				"dsi_dbg_bus", "panic");
 			mdss_fb_report_panel_dead(ctl->mfd);
 		}
 
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
index 7b69aa3..f18987c 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
@@ -1252,7 +1252,7 @@
 			pr_err("error polling for vsync\n");
 			MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0_ctrl", "dsi0_phy",
 				"dsi1_ctrl", "dsi1_phy", "vbif", "dbg_bus",
-				"vbif_dbg_bus", "panic");
+				"vbif_dbg_bus", "dsi_dbg_bus", "panic");
 		}
 	} else {
 		rc = 0;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index 80708aa..672b634 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -6603,6 +6603,7 @@
 	mdp5_interface->configure_panel = mdss_mdp_update_panel_info;
 	mdp5_interface->input_event_handler = mdss_mdp_input_event_handler;
 	mdp5_interface->signal_retire_fence = mdss_mdp_signal_retire_fence;
+	mdp5_interface->is_twm_en = NULL;
 
 	if (mfd->panel_info->type == WRITEBACK_PANEL) {
 		mdp5_interface->atomic_validate =
diff --git a/drivers/video/fbdev/msm/mdss_mdp_trace.h b/drivers/video/fbdev/msm/mdss_mdp_trace.h
index f8a6baf..c100e9c 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_trace.h
+++ b/drivers/video/fbdev/msm/mdss_mdp_trace.h
@@ -376,7 +376,7 @@
 			__entry->kickoff_cnt)
 );
 
-TRACE_EVENT(mdss_mark_write,
+TRACE_EVENT(tracing_mark_write,
 	TP_PROTO(int pid, const char *name, bool trace_begin),
 	TP_ARGS(pid, name, trace_begin),
 	TP_STRUCT__entry(
diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h
index a3f9349..c9e7e61 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -821,6 +821,7 @@
 	struct mdss_panel_data *next;
 
 	int panel_te_gpio;
+	int panel_en_gpio;
 	struct completion te_done;
 };
 
diff --git a/drivers/video/fbdev/msm/mdss_qpic.c b/drivers/video/fbdev/msm/mdss_qpic.c
index aa8d783..2f170cc 100644
--- a/drivers/video/fbdev/msm/mdss_qpic.c
+++ b/drivers/video/fbdev/msm/mdss_qpic.c
@@ -231,6 +231,7 @@
 	qpic_interface->dma_fnc = mdss_qpic_pan_display;
 	qpic_interface->ioctl_handler = NULL;
 	qpic_interface->kickoff_fnc = NULL;
+	qpic_interface->is_twm_en = NULL;
 	return 0;
 }
 
diff --git a/drivers/video/fbdev/msm/mdss_smmu.c b/drivers/video/fbdev/msm/mdss_smmu.c
index 2d8b5d5..972c8de 100644
--- a/drivers/video/fbdev/msm/mdss_smmu.c
+++ b/drivers/video/fbdev/msm/mdss_smmu.c
@@ -693,13 +693,13 @@
 }
 
 static struct mdss_smmu_domain mdss_mdp_unsec = {
-	"mdp_0", MDSS_IOMMU_DOMAIN_UNSECURE, SZ_1M, (SZ_4G - SZ_1M)};
+	"mdp_0", MDSS_IOMMU_DOMAIN_UNSECURE, SZ_128K, (SZ_4G - SZ_128M)};
 static struct mdss_smmu_domain mdss_rot_unsec = {
-	NULL, MDSS_IOMMU_DOMAIN_ROT_UNSECURE, SZ_1M, (SZ_4G - SZ_1M)};
+	NULL, MDSS_IOMMU_DOMAIN_ROT_UNSECURE, SZ_128K, (SZ_4G - SZ_128M)};
 static struct mdss_smmu_domain mdss_mdp_sec = {
-	"mdp_1", MDSS_IOMMU_DOMAIN_SECURE, SZ_1M, (SZ_4G - SZ_1M)};
+	"mdp_1", MDSS_IOMMU_DOMAIN_SECURE, SZ_128K, (SZ_4G - SZ_128M)};
 static struct mdss_smmu_domain mdss_rot_sec = {
-	NULL, MDSS_IOMMU_DOMAIN_ROT_SECURE, SZ_1M, (SZ_4G - SZ_1M)};
+	NULL, MDSS_IOMMU_DOMAIN_ROT_SECURE, SZ_128K, (SZ_4G - SZ_128M)};
 
 static const struct of_device_id mdss_smmu_dt_match[] = {
 	{ .compatible = "qcom,smmu_mdp_unsec", .data = &mdss_mdp_unsec},
diff --git a/drivers/video/fbdev/vfb.c b/drivers/video/fbdev/vfb.c
index a042329..026df9a 100644
--- a/drivers/video/fbdev/vfb.c
+++ b/drivers/video/fbdev/vfb.c
@@ -241,8 +241,23 @@
  */
 static int vfb_set_par(struct fb_info *info)
 {
+	switch (info->var.bits_per_pixel) {
+	case 1:
+		info->fix.visual = FB_VISUAL_MONO01;
+		break;
+	case 8:
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		break;
+	case 16:
+	case 24:
+	case 32:
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+		break;
+	}
+
 	info->fix.line_length = get_line_length(info->var.xres_virtual,
 						info->var.bits_per_pixel);
+
 	return 0;
 }
 
@@ -454,6 +469,8 @@
 		goto err2;
 	platform_set_drvdata(dev, info);
 
+	vfb_set_par(info);
+
 	fb_info(info, "Virtual frame buffer device, using %ldK of video memory\n",
 		videomemorysize >> 10);
 	return 0;
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 3eb58cb..8f8909a 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -799,11 +799,12 @@
 	  the timeout module parameter.
 
 config F71808E_WDT
-	tristate "Fintek F71808E, F71862FG, F71869, F71882FG and F71889FG Watchdog"
+	tristate "Fintek F718xx, F818xx Super I/O Watchdog"
 	depends on X86
 	help
-	  This is the driver for the hardware watchdog on the Fintek
-	  F71808E, F71862FG, F71869, F71882FG and F71889FG Super I/O controllers.
+	  This is the driver for the hardware watchdog on the Fintek F71808E,
+	  F71862FG, F71868, F71869, F71882FG, F71889FG, F81865 and F81866
+	  Super I/O controllers.
 
 	  You can compile this driver directly into the kernel, or use
 	  it as a module.  The module will be called f71808e_wdt.
diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c
index 1b7e916..e682bf0 100644
--- a/drivers/watchdog/f71808e_wdt.c
+++ b/drivers/watchdog/f71808e_wdt.c
@@ -57,6 +57,7 @@
 #define SIO_F71808_ID		0x0901	/* Chipset ID */
 #define SIO_F71858_ID		0x0507	/* Chipset ID */
 #define SIO_F71862_ID		0x0601	/* Chipset ID */
+#define SIO_F71868_ID		0x1106	/* Chipset ID */
 #define SIO_F71869_ID		0x0814	/* Chipset ID */
 #define SIO_F71869A_ID		0x1007	/* Chipset ID */
 #define SIO_F71882_ID		0x0541	/* Chipset ID */
@@ -101,7 +102,7 @@
 static unsigned int pulse_width = WATCHDOG_PULSE_WIDTH;
 module_param(pulse_width, uint, 0);
 MODULE_PARM_DESC(pulse_width,
-	"Watchdog signal pulse width. 0(=level), 1 ms, 25 ms, 125 ms or 5000 ms"
+	"Watchdog signal pulse width. 0(=level), 1, 25, 30, 125, 150, 5000 or 6000 ms"
 			" (default=" __MODULE_STRING(WATCHDOG_PULSE_WIDTH) ")");
 
 static unsigned int f71862fg_pin = WATCHDOG_F71862FG_PIN;
@@ -119,13 +120,14 @@
 MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with"
 	" given initial timeout. Zero (default) disables this feature.");
 
-enum chips { f71808fg, f71858fg, f71862fg, f71869, f71882fg, f71889fg, f81865,
-	     f81866};
+enum chips { f71808fg, f71858fg, f71862fg, f71868, f71869, f71882fg, f71889fg,
+	     f81865, f81866};
 
 static const char *f71808e_names[] = {
 	"f71808fg",
 	"f71858fg",
 	"f71862fg",
+	"f71868",
 	"f71869",
 	"f71882fg",
 	"f71889fg",
@@ -252,16 +254,23 @@
 static int watchdog_set_pulse_width(unsigned int pw)
 {
 	int err = 0;
+	unsigned int t1 = 25, t2 = 125, t3 = 5000;
+
+	if (watchdog.type == f71868) {
+		t1 = 30;
+		t2 = 150;
+		t3 = 6000;
+	}
 
 	mutex_lock(&watchdog.lock);
 
-	if        (pw <=    1) {
+	if        (pw <=  1) {
 		watchdog.pulse_val = 0;
-	} else if (pw <=   25) {
+	} else if (pw <= t1) {
 		watchdog.pulse_val = 1;
-	} else if (pw <=  125) {
+	} else if (pw <= t2) {
 		watchdog.pulse_val = 2;
-	} else if (pw <= 5000) {
+	} else if (pw <= t3) {
 		watchdog.pulse_val = 3;
 	} else {
 		pr_err("pulse width out of range\n");
@@ -354,6 +363,7 @@
 			goto exit_superio;
 		break;
 
+	case f71868:
 	case f71869:
 		/* GPIO14 --> WDTRST# */
 		superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 4);
@@ -486,7 +496,7 @@
 
 	is_running = (superio_inb(watchdog.sioaddr, SIO_REG_ENABLE) & BIT(0))
 		&& (superio_inb(watchdog.sioaddr, F71808FG_REG_WDT_CONF)
-			& F71808FG_FLAG_WD_EN);
+			& BIT(F71808FG_FLAG_WD_EN));
 
 	superio_exit(watchdog.sioaddr);
 
@@ -792,6 +802,9 @@
 		watchdog.type = f71862fg;
 		err = f71862fg_pin_configure(0); /* validate module parameter */
 		break;
+	case SIO_F71868_ID:
+		watchdog.type = f71868;
+		break;
 	case SIO_F71869_ID:
 	case SIO_F71869A_ID:
 		watchdog.type = f71869;
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index a11f731..6182d69 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -746,7 +746,7 @@
 
 	autofs4_del_active(dentry);
 
-	inode = autofs4_get_inode(dir->i_sb, S_IFDIR | 0555);
+	inode = autofs4_get_inode(dir->i_sb, S_IFDIR | mode);
 	if (!inode)
 		return -ENOMEM;
 	d_add(dentry, inode);
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 8ed05d9..03ac3ab 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -2453,7 +2453,7 @@
 	if (!uptodate) {
 		ClearPageUptodate(page);
 		SetPageError(page);
-		ret = ret < 0 ? ret : -EIO;
+		ret = err < 0 ? err : -EIO;
 		mapping_set_error(page->mapping, ret);
 	}
 }
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 5539f0b..5240173 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -3664,7 +3664,7 @@
 
 		src_offset = btrfs_item_ptr_offset(src, start_slot + i);
 
-		if ((i == (nr - 1)))
+		if (i == nr - 1)
 			last_key = ins_keys[i];
 
 		if (ins_keys[i].type == BTRFS_INODE_ITEM_KEY) {
diff --git a/fs/buffer.c b/fs/buffer.c
index 5d8f496..3a8064d 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1455,12 +1455,48 @@
 	return 0;
 }
 
+static void __evict_bh_lru(void *arg)
+{
+	struct bh_lru *b = &get_cpu_var(bh_lrus);
+	struct buffer_head *bh = arg;
+	int i;
+
+	for (i = 0; i < BH_LRU_SIZE; i++) {
+		if (b->bhs[i] == bh) {
+			brelse(b->bhs[i]);
+			b->bhs[i] = NULL;
+			goto out;
+		}
+	}
+out:
+	put_cpu_var(bh_lrus);
+}
+
+static bool bh_exists_in_lru(int cpu, void *arg)
+{
+	struct bh_lru *b = per_cpu_ptr(&bh_lrus, cpu);
+	struct buffer_head *bh = arg;
+	int i;
+
+	for (i = 0; i < BH_LRU_SIZE; i++) {
+		if (b->bhs[i] == bh)
+			return 1;
+	}
+
+	return 0;
+
+}
 void invalidate_bh_lrus(void)
 {
 	on_each_cpu_cond(has_bh_in_lru, invalidate_bh_lru, NULL, 1, GFP_KERNEL);
 }
 EXPORT_SYMBOL_GPL(invalidate_bh_lrus);
 
+static void evict_bh_lrus(struct buffer_head *bh)
+{
+	on_each_cpu_cond(bh_exists_in_lru, __evict_bh_lru, bh, 1, GFP_ATOMIC);
+}
+
 void set_bh_page(struct buffer_head *bh,
 		struct page *page, unsigned long offset)
 {
@@ -3250,8 +3286,15 @@
 	do {
 		if (buffer_write_io_error(bh) && page->mapping)
 			mapping_set_error(page->mapping, -EIO);
-		if (buffer_busy(bh))
-			goto failed;
+		if (buffer_busy(bh)) {
+			/*
+			 * Check if the busy failure was due to an
+			 * outstanding LRU reference
+			 */
+			evict_bh_lrus(bh);
+			if (buffer_busy(bh))
+				goto failed;
+		}
 		bh = bh->b_this_page;
 	} while (bh != head);
 
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index ca3f630..e7ddb23 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -598,7 +598,8 @@
 struct ceph_aio_request {
 	struct kiocb *iocb;
 	size_t total_len;
-	int write;
+	bool write;
+	bool should_dirty;
 	int error;
 	struct list_head osd_reqs;
 	unsigned num_reqs;
@@ -708,7 +709,7 @@
 		}
 	}
 
-	ceph_put_page_vector(osd_data->pages, num_pages, !aio_req->write);
+	ceph_put_page_vector(osd_data->pages, num_pages, aio_req->should_dirty);
 	ceph_osdc_put_request(req);
 
 	if (rc < 0)
@@ -890,6 +891,7 @@
 	size_t count = iov_iter_count(iter);
 	loff_t pos = iocb->ki_pos;
 	bool write = iov_iter_rw(iter) == WRITE;
+	bool should_dirty = !write && iter_is_iovec(iter);
 
 	if (write && ceph_snap(file_inode(file)) != CEPH_NOSNAP)
 		return -EROFS;
@@ -954,6 +956,7 @@
 			if (aio_req) {
 				aio_req->iocb = iocb;
 				aio_req->write = write;
+				aio_req->should_dirty = should_dirty;
 				INIT_LIST_HEAD(&aio_req->osd_reqs);
 				if (write) {
 					aio_req->mtime = mtime;
@@ -1012,7 +1015,7 @@
 				len = ret;
 		}
 
-		ceph_put_page_vector(pages, num_pages, !write);
+		ceph_put_page_vector(pages, num_pages, should_dirty);
 
 		ceph_osdc_put_request(req);
 		if (ret < 0)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 7b496a4..4ed4736 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1412,6 +1412,7 @@
 #define CIFS_FATTR_NEED_REVAL		0x4
 #define CIFS_FATTR_INO_COLLISION	0x8
 #define CIFS_FATTR_UNKNOWN_NLINK	0x10
+#define CIFS_FATTR_FAKE_ROOT_INO	0x20
 
 struct cifs_fattr {
 	u32		cf_flags;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 02e403a..49eeed2 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -589,7 +589,7 @@
 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 	int rc = 0;
 
-	down_read(&cinode->lock_sem);
+	down_read_nested(&cinode->lock_sem, SINGLE_DEPTH_NESTING);
 	if (cinode->can_cache_brlcks) {
 		/* can cache locks - no need to relock */
 		up_read(&cinode->lock_sem);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 7ab5be7..24c19eb 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -701,6 +701,18 @@
 	return rc;
 }
 
+/* Simple function to return a 64 bit hash of string.  Rarely called */
+static __u64 simple_hashstr(const char *str)
+{
+	const __u64 hash_mult =  1125899906842597L; /* a big enough prime */
+	__u64 hash = 0;
+
+	while (*str)
+		hash = (hash + (__u64) *str++) * hash_mult;
+
+	return hash;
+}
+
 int
 cifs_get_inode_info(struct inode **inode, const char *full_path,
 		    FILE_ALL_INFO *data, struct super_block *sb, int xid,
@@ -810,6 +822,14 @@
 						 tmprc);
 					fattr.cf_uniqueid = iunique(sb, ROOT_I);
 					cifs_autodisable_serverino(cifs_sb);
+				} else if ((fattr.cf_uniqueid == 0) &&
+						strlen(full_path) == 0) {
+					/* some servers ret bad root ino ie 0 */
+					cifs_dbg(FYI, "Invalid (0) inodenum\n");
+					fattr.cf_flags |=
+						CIFS_FATTR_FAKE_ROOT_INO;
+					fattr.cf_uniqueid =
+						simple_hashstr(tcon->treeName);
 				}
 			}
 		} else
@@ -826,6 +846,16 @@
 				&fattr.cf_uniqueid, data);
 			if (tmprc)
 				fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
+			else if ((fattr.cf_uniqueid == 0) &&
+					strlen(full_path) == 0) {
+				/*
+				 * Reuse existing root inode num since
+				 * inum zero for root causes ls of . and .. to
+				 * not be returned
+				 */
+				cifs_dbg(FYI, "Srv ret 0 inode num for root\n");
+				fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
+			}
 		} else
 			fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
 	}
@@ -887,6 +917,9 @@
 	}
 
 cgii_exit:
+	if ((*inode) && ((*inode)->i_ino == 0))
+		cifs_dbg(FYI, "inode number of zero returned\n");
+
 	kfree(buf);
 	cifs_put_tlink(tlink);
 	return rc;
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 7c26286..44b7ccb 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1151,15 +1151,19 @@
 		goto tcon_exit;
 	}
 
-	if (rsp->ShareType & SMB2_SHARE_TYPE_DISK)
+	switch (rsp->ShareType) {
+	case SMB2_SHARE_TYPE_DISK:
 		cifs_dbg(FYI, "connection to disk share\n");
-	else if (rsp->ShareType & SMB2_SHARE_TYPE_PIPE) {
+		break;
+	case SMB2_SHARE_TYPE_PIPE:
 		tcon->ipc = true;
 		cifs_dbg(FYI, "connection to pipe share\n");
-	} else if (rsp->ShareType & SMB2_SHARE_TYPE_PRINT) {
-		tcon->print = true;
+		break;
+	case SMB2_SHARE_TYPE_PRINT:
+		tcon->ipc = true;
 		cifs_dbg(FYI, "connection to printer\n");
-	} else {
+		break;
+	default:
 		cifs_dbg(VFS, "unknown share type %d\n", rsp->ShareType);
 		rc = -EOPNOTSUPP;
 		goto tcon_error_exit;
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index f2d7402..93c8e4a 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -833,7 +833,7 @@
  */
 #define XFORM(i) (((i) ^ ((i) << 27) ^ ((i) << 17)) & 0xffffffff)
 
-#define COMPATIBLE_IOCTL(cmd) XFORM(cmd),
+#define COMPATIBLE_IOCTL(cmd) XFORM((u32)cmd),
 /* ioctl should not be warned about even if it's not implemented.
    Valid reasons to use this:
    - It is implemented with ->compat_ioctl on some device, but programs
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index 2596c9a..d7b4c48 100644
--- a/fs/crypto/bio.c
+++ b/fs/crypto/bio.c
@@ -25,15 +25,8 @@
 #include <linux/namei.h>
 #include "fscrypt_private.h"
 
-/*
- * Call fscrypt_decrypt_page on every single page, reusing the encryption
- * context.
- */
-static void completion_pages(struct work_struct *work)
+static void __fscrypt_decrypt_bio(struct bio *bio, bool done)
 {
-	struct fscrypt_ctx *ctx =
-		container_of(work, struct fscrypt_ctx, r.work);
-	struct bio *bio = ctx->r.bio;
 	struct bio_vec *bv;
 	int i;
 
@@ -45,22 +38,38 @@
 		if (ret) {
 			WARN_ON_ONCE(1);
 			SetPageError(page);
-		} else {
+		} else if (done) {
 			SetPageUptodate(page);
 		}
-		unlock_page(page);
+		if (done)
+			unlock_page(page);
 	}
+}
+
+void fscrypt_decrypt_bio(struct bio *bio)
+{
+	__fscrypt_decrypt_bio(bio, false);
+}
+EXPORT_SYMBOL(fscrypt_decrypt_bio);
+
+static void completion_pages(struct work_struct *work)
+{
+	struct fscrypt_ctx *ctx =
+		container_of(work, struct fscrypt_ctx, r.work);
+	struct bio *bio = ctx->r.bio;
+
+	__fscrypt_decrypt_bio(bio, true);
 	fscrypt_release_ctx(ctx);
 	bio_put(bio);
 }
 
-void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx, struct bio *bio)
+void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, struct bio *bio)
 {
 	INIT_WORK(&ctx->r.work, completion_pages);
 	ctx->r.bio = bio;
-	queue_work(fscrypt_read_workqueue, &ctx->r.work);
+	fscrypt_enqueue_decrypt_work(&ctx->r.work);
 }
-EXPORT_SYMBOL(fscrypt_decrypt_bio_pages);
+EXPORT_SYMBOL(fscrypt_enqueue_decrypt_bio);
 
 void fscrypt_pullback_bio_page(struct page **page, bool restore)
 {
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index 732a786..0758d32 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -27,6 +27,7 @@
 #include <linux/dcache.h>
 #include <linux/namei.h>
 #include <crypto/aes.h>
+#include <crypto/skcipher.h>
 #include "fscrypt_private.h"
 
 static unsigned int num_prealloc_crypto_pages = 32;
@@ -44,12 +45,18 @@
 static LIST_HEAD(fscrypt_free_ctxs);
 static DEFINE_SPINLOCK(fscrypt_ctx_lock);
 
-struct workqueue_struct *fscrypt_read_workqueue;
+static struct workqueue_struct *fscrypt_read_workqueue;
 static DEFINE_MUTEX(fscrypt_init_mutex);
 
 static struct kmem_cache *fscrypt_ctx_cachep;
 struct kmem_cache *fscrypt_info_cachep;
 
+void fscrypt_enqueue_decrypt_work(struct work_struct *work)
+{
+	queue_work(fscrypt_read_workqueue, work);
+}
+EXPORT_SYMBOL(fscrypt_enqueue_decrypt_work);
+
 /**
  * fscrypt_release_ctx() - Releases an encryption context
  * @ctx: The encryption context to release.
diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c
index 6eb4343..b18fa32 100644
--- a/fs/crypto/fname.c
+++ b/fs/crypto/fname.c
@@ -12,42 +12,46 @@
 
 #include <linux/scatterlist.h>
 #include <linux/ratelimit.h>
+#include <crypto/skcipher.h>
 #include "fscrypt_private.h"
 
+static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
+{
+	if (str->len == 1 && str->name[0] == '.')
+		return true;
+
+	if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
+		return true;
+
+	return false;
+}
+
 /**
  * fname_encrypt() - encrypt a filename
  *
- * The caller must have allocated sufficient memory for the @oname string.
+ * The output buffer must be at least as large as the input buffer.
+ * Any extra space is filled with NUL padding before encryption.
  *
  * Return: 0 on success, -errno on failure
  */
-static int fname_encrypt(struct inode *inode,
-			const struct qstr *iname, struct fscrypt_str *oname)
+int fname_encrypt(struct inode *inode, const struct qstr *iname,
+		  u8 *out, unsigned int olen)
 {
 	struct skcipher_request *req = NULL;
 	DECLARE_CRYPTO_WAIT(wait);
-	struct fscrypt_info *ci = inode->i_crypt_info;
-	struct crypto_skcipher *tfm = ci->ci_ctfm;
+	struct crypto_skcipher *tfm = inode->i_crypt_info->ci_ctfm;
 	int res = 0;
 	char iv[FS_CRYPTO_BLOCK_SIZE];
 	struct scatterlist sg;
-	int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK);
-	unsigned int lim;
-	unsigned int cryptlen;
-
-	lim = inode->i_sb->s_cop->max_namelen(inode);
-	if (iname->len <= 0 || iname->len > lim)
-		return -EIO;
 
 	/*
 	 * Copy the filename to the output buffer for encrypting in-place and
 	 * pad it with the needed number of NUL bytes.
 	 */
-	cryptlen = max_t(unsigned int, iname->len, FS_CRYPTO_BLOCK_SIZE);
-	cryptlen = round_up(cryptlen, padding);
-	cryptlen = min(cryptlen, lim);
-	memcpy(oname->name, iname->name, iname->len);
-	memset(oname->name + iname->len, 0, cryptlen - iname->len);
+	if (WARN_ON(olen < iname->len))
+		return -ENOBUFS;
+	memcpy(out, iname->name, iname->len);
+	memset(out + iname->len, 0, olen - iname->len);
 
 	/* Initialize the IV */
 	memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
@@ -62,8 +66,8 @@
 	skcipher_request_set_callback(req,
 			CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
 			crypto_req_done, &wait);
-	sg_init_one(&sg, oname->name, cryptlen);
-	skcipher_request_set_crypt(req, &sg, &sg, cryptlen, iv);
+	sg_init_one(&sg, out, olen);
+	skcipher_request_set_crypt(req, &sg, &sg, olen, iv);
 
 	/* Do the encryption */
 	res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
@@ -74,7 +78,6 @@
 		return res;
 	}
 
-	oname->len = cryptlen;
 	return 0;
 }
 
@@ -187,50 +190,52 @@
 	return cp - dst;
 }
 
-u32 fscrypt_fname_encrypted_size(const struct inode *inode, u32 ilen)
+bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len,
+				  u32 max_len, u32 *encrypted_len_ret)
 {
-	int padding = 32;
-	struct fscrypt_info *ci = inode->i_crypt_info;
+	int padding = 4 << (inode->i_crypt_info->ci_flags &
+			    FS_POLICY_FLAGS_PAD_MASK);
+	u32 encrypted_len;
 
-	if (ci)
-		padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK);
-	ilen = max(ilen, (u32)FS_CRYPTO_BLOCK_SIZE);
-	return round_up(ilen, padding);
+	if (orig_len > max_len)
+		return false;
+	encrypted_len = max(orig_len, (u32)FS_CRYPTO_BLOCK_SIZE);
+	encrypted_len = round_up(encrypted_len, padding);
+	*encrypted_len_ret = min(encrypted_len, max_len);
+	return true;
 }
-EXPORT_SYMBOL(fscrypt_fname_encrypted_size);
 
 /**
- * fscrypt_fname_crypto_alloc_obuff() -
+ * fscrypt_fname_alloc_buffer - allocate a buffer for presented filenames
  *
- * Allocates an output buffer that is sufficient for the crypto operation
- * specified by the context and the direction.
+ * Allocate a buffer that is large enough to hold any decrypted or encoded
+ * filename (null-terminated), for the given maximum encrypted filename length.
+ *
+ * Return: 0 on success, -errno on failure
  */
 int fscrypt_fname_alloc_buffer(const struct inode *inode,
-				u32 ilen, struct fscrypt_str *crypto_str)
+			       u32 max_encrypted_len,
+			       struct fscrypt_str *crypto_str)
 {
-	u32 olen = fscrypt_fname_encrypted_size(inode, ilen);
 	const u32 max_encoded_len =
 		max_t(u32, BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE),
 		      1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name)));
+	u32 max_presented_len;
 
-	crypto_str->len = olen;
-	olen = max(olen, max_encoded_len);
+	max_presented_len = max(max_encoded_len, max_encrypted_len);
 
-	/*
-	 * Allocated buffer can hold one more character to null-terminate the
-	 * string
-	 */
-	crypto_str->name = kmalloc(olen + 1, GFP_NOFS);
-	if (!(crypto_str->name))
+	crypto_str->name = kmalloc(max_presented_len + 1, GFP_NOFS);
+	if (!crypto_str->name)
 		return -ENOMEM;
+	crypto_str->len = max_presented_len;
 	return 0;
 }
 EXPORT_SYMBOL(fscrypt_fname_alloc_buffer);
 
 /**
- * fscrypt_fname_crypto_free_buffer() -
+ * fscrypt_fname_free_buffer - free the buffer for presented filenames
  *
- * Frees the buffer allocated for crypto operation.
+ * Free the buffer allocated by fscrypt_fname_alloc_buffer().
  */
 void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str)
 {
@@ -297,35 +302,6 @@
 EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
 
 /**
- * fscrypt_fname_usr_to_disk() - converts a filename from user space to disk
- * space
- *
- * The caller must have allocated sufficient memory for the @oname string.
- *
- * Return: 0 on success, -errno on failure
- */
-int fscrypt_fname_usr_to_disk(struct inode *inode,
-			const struct qstr *iname,
-			struct fscrypt_str *oname)
-{
-	if (fscrypt_is_dot_dotdot(iname)) {
-		oname->name[0] = '.';
-		oname->name[iname->len - 1] = '.';
-		oname->len = iname->len;
-		return 0;
-	}
-	if (inode->i_crypt_info)
-		return fname_encrypt(inode, iname, oname);
-	/*
-	 * Without a proper key, a user is not allowed to modify the filenames
-	 * in a directory. Consequently, a user space name cannot be mapped to
-	 * a disk-space name
-	 */
-	return -ENOKEY;
-}
-EXPORT_SYMBOL(fscrypt_fname_usr_to_disk);
-
-/**
  * fscrypt_setup_filename() - prepare to search a possibly encrypted directory
  * @dir: the directory that will be searched
  * @iname: the user-provided filename being searched for
@@ -368,11 +344,17 @@
 		return ret;
 
 	if (dir->i_crypt_info) {
-		ret = fscrypt_fname_alloc_buffer(dir, iname->len,
-							&fname->crypto_buf);
-		if (ret)
-			return ret;
-		ret = fname_encrypt(dir, iname, &fname->crypto_buf);
+		if (!fscrypt_fname_encrypted_size(dir, iname->len,
+						  dir->i_sb->s_cop->max_namelen(dir),
+						  &fname->crypto_buf.len))
+			return -ENAMETOOLONG;
+		fname->crypto_buf.name = kmalloc(fname->crypto_buf.len,
+						 GFP_NOFS);
+		if (!fname->crypto_buf.name)
+			return -ENOMEM;
+
+		ret = fname_encrypt(dir, iname, fname->crypto_buf.name,
+				    fname->crypto_buf.len);
 		if (ret)
 			goto errout;
 		fname->disk_name.name = fname->crypto_buf.name;
@@ -424,7 +406,7 @@
 	return 0;
 
 errout:
-	fscrypt_fname_free_buffer(&fname->crypto_buf);
+	kfree(fname->crypto_buf.name);
 	return ret;
 }
 EXPORT_SYMBOL(fscrypt_setup_filename);
diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
index 4688a64..d36a648 100644
--- a/fs/crypto/fscrypt_private.h
+++ b/fs/crypto/fscrypt_private.h
@@ -49,6 +49,15 @@
 
 #define FS_ENCRYPTION_CONTEXT_FORMAT_V1		1
 
+/**
+ * For encrypted symlinks, the ciphertext length is stored at the beginning
+ * of the string in little-endian format.
+ */
+struct fscrypt_symlink_data {
+	__le16 len;
+	char encrypted_path[1];
+} __packed;
+
 /*
  * A pointer to this structure is stored in the file system's in-core
  * representation of an inode.
@@ -70,9 +79,23 @@
 #define FS_CTX_REQUIRES_FREE_ENCRYPT_FL		0x00000001
 #define FS_CTX_HAS_BOUNCE_BUFFER_FL		0x00000002
 
+static inline bool fscrypt_valid_enc_modes(u32 contents_mode,
+					   u32 filenames_mode)
+{
+	if (contents_mode == FS_ENCRYPTION_MODE_AES_128_CBC &&
+	    filenames_mode == FS_ENCRYPTION_MODE_AES_128_CTS)
+		return true;
+
+	if (contents_mode == FS_ENCRYPTION_MODE_AES_256_XTS &&
+	    filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS)
+		return true;
+
+	return false;
+}
+
 /* crypto.c */
+extern struct kmem_cache *fscrypt_info_cachep;
 extern int fscrypt_initialize(unsigned int cop_flags);
-extern struct workqueue_struct *fscrypt_read_workqueue;
 extern int fscrypt_do_page_crypto(const struct inode *inode,
 				  fscrypt_direction_t rw, u64 lblk_num,
 				  struct page *src_page,
@@ -82,6 +105,13 @@
 extern struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx,
 					      gfp_t gfp_flags);
 
+/* fname.c */
+extern int fname_encrypt(struct inode *inode, const struct qstr *iname,
+			 u8 *out, unsigned int olen);
+extern bool fscrypt_fname_encrypted_size(const struct inode *inode,
+					 u32 orig_len, u32 max_len,
+					 u32 *encrypted_len_ret);
+
 /* keyinfo.c */
 extern void __exit fscrypt_essiv_cleanup(void);
 
diff --git a/fs/crypto/hooks.c b/fs/crypto/hooks.c
index 9f5fb2e..bec0649 100644
--- a/fs/crypto/hooks.c
+++ b/fs/crypto/hooks.c
@@ -110,3 +110,161 @@
 	return 0;
 }
 EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup);
+
+int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len,
+			      unsigned int max_len,
+			      struct fscrypt_str *disk_link)
+{
+	int err;
+
+	/*
+	 * To calculate the size of the encrypted symlink target we need to know
+	 * the amount of NUL padding, which is determined by the flags set in
+	 * the encryption policy which will be inherited from the directory.
+	 * The easiest way to get access to this is to just load the directory's
+	 * fscrypt_info, since we'll need it to create the dir_entry anyway.
+	 *
+	 * Note: in test_dummy_encryption mode, @dir may be unencrypted.
+	 */
+	err = fscrypt_get_encryption_info(dir);
+	if (err)
+		return err;
+	if (!fscrypt_has_encryption_key(dir))
+		return -ENOKEY;
+
+	/*
+	 * Calculate the size of the encrypted symlink and verify it won't
+	 * exceed max_len.  Note that for historical reasons, encrypted symlink
+	 * targets are prefixed with the ciphertext length, despite this
+	 * actually being redundant with i_size.  This decreases by 2 bytes the
+	 * longest symlink target we can accept.
+	 *
+	 * We could recover 1 byte by not counting a null terminator, but
+	 * counting it (even though it is meaningless for ciphertext) is simpler
+	 * for now since filesystems will assume it is there and subtract it.
+	 */
+	if (!fscrypt_fname_encrypted_size(dir, len,
+					  max_len - sizeof(struct fscrypt_symlink_data),
+					  &disk_link->len))
+		return -ENAMETOOLONG;
+	disk_link->len += sizeof(struct fscrypt_symlink_data);
+
+	disk_link->name = NULL;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(__fscrypt_prepare_symlink);
+
+int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
+			      unsigned int len, struct fscrypt_str *disk_link)
+{
+	int err;
+	struct qstr iname = QSTR_INIT(target, len);
+	struct fscrypt_symlink_data *sd;
+	unsigned int ciphertext_len;
+
+	err = fscrypt_require_key(inode);
+	if (err)
+		return err;
+
+	if (disk_link->name) {
+		/* filesystem-provided buffer */
+		sd = (struct fscrypt_symlink_data *)disk_link->name;
+	} else {
+		sd = kmalloc(disk_link->len, GFP_NOFS);
+		if (!sd)
+			return -ENOMEM;
+	}
+	ciphertext_len = disk_link->len - sizeof(*sd);
+	sd->len = cpu_to_le16(ciphertext_len);
+
+	err = fname_encrypt(inode, &iname, sd->encrypted_path, ciphertext_len);
+	if (err) {
+		if (!disk_link->name)
+			kfree(sd);
+		return err;
+	}
+	/*
+	 * Null-terminating the ciphertext doesn't make sense, but we still
+	 * count the null terminator in the length, so we might as well
+	 * initialize it just in case the filesystem writes it out.
+	 */
+	sd->encrypted_path[ciphertext_len] = '\0';
+
+	if (!disk_link->name)
+		disk_link->name = (unsigned char *)sd;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(__fscrypt_encrypt_symlink);
+
+/**
+ * fscrypt_get_symlink - get the target of an encrypted symlink
+ * @inode: the symlink inode
+ * @caddr: the on-disk contents of the symlink
+ * @max_size: size of @caddr buffer
+ * @done: if successful, will be set up to free the returned target
+ *
+ * If the symlink's encryption key is available, we decrypt its target.
+ * Otherwise, we encode its target for presentation.
+ *
+ * This may sleep, so the filesystem must have dropped out of RCU mode already.
+ *
+ * Return: the presentable symlink target or an ERR_PTR()
+ */
+const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
+				unsigned int max_size,
+				struct delayed_call *done)
+{
+	const struct fscrypt_symlink_data *sd;
+	struct fscrypt_str cstr, pstr;
+	int err;
+
+	/* This is for encrypted symlinks only */
+	if (WARN_ON(!IS_ENCRYPTED(inode)))
+		return ERR_PTR(-EINVAL);
+
+	/*
+	 * Try to set up the symlink's encryption key, but we can continue
+	 * regardless of whether the key is available or not.
+	 */
+	err = fscrypt_get_encryption_info(inode);
+	if (err)
+		return ERR_PTR(err);
+
+	/*
+	 * For historical reasons, encrypted symlink targets are prefixed with
+	 * the ciphertext length, even though this is redundant with i_size.
+	 */
+
+	if (max_size < sizeof(*sd))
+		return ERR_PTR(-EUCLEAN);
+	sd = caddr;
+	cstr.name = (unsigned char *)sd->encrypted_path;
+	cstr.len = le16_to_cpu(sd->len);
+
+	if (cstr.len == 0)
+		return ERR_PTR(-EUCLEAN);
+
+	if (cstr.len + sizeof(*sd) - 1 > max_size)
+		return ERR_PTR(-EUCLEAN);
+
+	err = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr);
+	if (err)
+		return ERR_PTR(err);
+
+	err = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr);
+	if (err)
+		goto err_kfree;
+
+	err = -EUCLEAN;
+	if (pstr.name[0] == '\0')
+		goto err_kfree;
+
+	pstr.name[pstr.len] = '\0';
+	set_delayed_call(done, kfree_link, pstr.name);
+	return pstr.name;
+
+err_kfree:
+	kfree(pstr.name);
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(fscrypt_get_symlink);
diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c
index c891d2e..aae68c0 100644
--- a/fs/crypto/keyinfo.c
+++ b/fs/crypto/keyinfo.c
@@ -13,6 +13,7 @@
 #include <linux/ratelimit.h>
 #include <crypto/aes.h>
 #include <crypto/sha.h>
+#include <crypto/skcipher.h>
 #include "fscrypt_private.h"
 
 static struct crypto_shash *essiv_hash_tfm;
@@ -353,19 +354,9 @@
 }
 EXPORT_SYMBOL(fscrypt_get_encryption_info);
 
-void fscrypt_put_encryption_info(struct inode *inode, struct fscrypt_info *ci)
+void fscrypt_put_encryption_info(struct inode *inode)
 {
-	struct fscrypt_info *prev;
-
-	if (ci == NULL)
-		ci = ACCESS_ONCE(inode->i_crypt_info);
-	if (ci == NULL)
-		return;
-
-	prev = cmpxchg(&inode->i_crypt_info, ci, NULL);
-	if (prev != ci)
-		return;
-
-	put_crypt_info(ci);
+	put_crypt_info(inode->i_crypt_info);
+	inode->i_crypt_info = NULL;
 }
 EXPORT_SYMBOL(fscrypt_put_encryption_info);
diff --git a/fs/dcache.c b/fs/dcache.c
index 210a135..885f74e 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -461,9 +461,11 @@
  * d_drop() is used mainly for stuff that wants to invalidate a dentry for some
  * reason (NFS timeouts or autofs deletes).
  *
- * __d_drop requires dentry->d_lock.
+ * __d_drop requires dentry->d_lock
+ * ___d_drop doesn't mark dentry as "unhashed"
+ *   (dentry->d_hash.pprev will be LIST_POISON2, not NULL).
  */
-void __d_drop(struct dentry *dentry)
+static void ___d_drop(struct dentry *dentry)
 {
 	if (!d_unhashed(dentry)) {
 		struct hlist_bl_head *b;
@@ -479,12 +481,17 @@
 
 		hlist_bl_lock(b);
 		__hlist_bl_del(&dentry->d_hash);
-		dentry->d_hash.pprev = NULL;
 		hlist_bl_unlock(b);
 		/* After this call, in-progress rcu-walk path lookup will fail. */
 		write_seqcount_invalidate(&dentry->d_seq);
 	}
 }
+
+void __d_drop(struct dentry *dentry)
+{
+	___d_drop(dentry);
+	dentry->d_hash.pprev = NULL;
+}
 EXPORT_SYMBOL(__d_drop);
 
 void d_drop(struct dentry *dentry)
@@ -2378,7 +2385,7 @@
 static void __d_rehash(struct dentry *entry)
 {
 	struct hlist_bl_head *b = d_hash(entry->d_name.hash);
-	BUG_ON(!d_unhashed(entry));
+
 	hlist_bl_lock(b);
 	hlist_bl_add_head_rcu(&entry->d_hash, b);
 	hlist_bl_unlock(b);
@@ -2815,9 +2822,9 @@
 	write_seqcount_begin_nested(&target->d_seq, DENTRY_D_LOCK_NESTED);
 
 	/* unhash both */
-	/* __d_drop does write_seqcount_barrier, but they're OK to nest. */
-	__d_drop(dentry);
-	__d_drop(target);
+	/* ___d_drop does write_seqcount_barrier, but they're OK to nest. */
+	___d_drop(dentry);
+	___d_drop(target);
 
 	/* Switch the names.. */
 	if (exchange)
@@ -2829,6 +2836,8 @@
 	__d_rehash(dentry);
 	if (exchange)
 		__d_rehash(target);
+	else
+		target->d_hash.pprev = NULL;
 
 	/* ... and switch them in the tree */
 	if (IS_ROOT(dentry)) {
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index e04ec86..176b4b2 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -242,8 +242,6 @@
 	 */
 	ext4_mark_bitmap_end(num_clusters_in_group(sb, block_group),
 			     sb->s_blocksize * 8, bh->b_data);
-	ext4_block_bitmap_csum_set(sb, block_group, gdp, bh);
-	ext4_group_desc_csum_set(sb, block_group, gdp);
 	return 0;
 }
 
@@ -447,6 +445,7 @@
 		err = ext4_init_block_bitmap(sb, bh, block_group, desc);
 		set_bitmap_uptodate(bh);
 		set_buffer_uptodate(bh);
+		set_buffer_verified(bh);
 		ext4_unlock_group(sb, block_group);
 		unlock_buffer(bh);
 		if (err) {
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 510e664..08fca4a 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -429,7 +429,7 @@
 		int i, num;
 		unsigned long nr_pages;
 
-		num = min_t(pgoff_t, end - index, PAGEVEC_SIZE);
+		num = min_t(pgoff_t, end - index, PAGEVEC_SIZE - 1) + 1;
 		nr_pages = pagevec_lookup(&pvec, inode->i_mapping, index,
 					  (pgoff_t)num);
 		if (nr_pages == 0)
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 2cec605..ef76b83 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -63,44 +63,6 @@
 		memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
 }
 
-/* Initializes an uninitialized inode bitmap */
-static int ext4_init_inode_bitmap(struct super_block *sb,
-				       struct buffer_head *bh,
-				       ext4_group_t block_group,
-				       struct ext4_group_desc *gdp)
-{
-	struct ext4_group_info *grp;
-	struct ext4_sb_info *sbi = EXT4_SB(sb);
-	J_ASSERT_BH(bh, buffer_locked(bh));
-
-	/* If checksum is bad mark all blocks and inodes use to prevent
-	 * allocation, essentially implementing a per-group read-only flag. */
-	if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
-		grp = ext4_get_group_info(sb, block_group);
-		if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
-			percpu_counter_sub(&sbi->s_freeclusters_counter,
-					   grp->bb_free);
-		set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
-		if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
-			int count;
-			count = ext4_free_inodes_count(sb, gdp);
-			percpu_counter_sub(&sbi->s_freeinodes_counter,
-					   count);
-		}
-		set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
-		return -EFSBADCRC;
-	}
-
-	memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
-	ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8,
-			bh->b_data);
-	ext4_inode_bitmap_csum_set(sb, block_group, gdp, bh,
-				   EXT4_INODES_PER_GROUP(sb) / 8);
-	ext4_group_desc_csum_set(sb, block_group, gdp);
-
-	return 0;
-}
-
 void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate)
 {
 	if (uptodate) {
@@ -184,17 +146,14 @@
 
 	ext4_lock_group(sb, block_group);
 	if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
-		err = ext4_init_inode_bitmap(sb, bh, block_group, desc);
+		memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
+		ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb),
+				     sb->s_blocksize * 8, bh->b_data);
 		set_bitmap_uptodate(bh);
 		set_buffer_uptodate(bh);
 		set_buffer_verified(bh);
 		ext4_unlock_group(sb, block_group);
 		unlock_buffer(bh);
-		if (err) {
-			ext4_error(sb, "Failed to init inode bitmap for group "
-				   "%u: %d", block_group, err);
-			goto out;
-		}
 		return bh;
 	}
 	ext4_unlock_group(sb, block_group);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 21c0670..2bf83d0 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3421,7 +3421,6 @@
 {
 	struct file *file = iocb->ki_filp;
 	struct inode *inode = file->f_mapping->host;
-	struct ext4_inode_info *ei = EXT4_I(inode);
 	ssize_t ret;
 	loff_t offset = iocb->ki_pos;
 	size_t count = iov_iter_count(iter);
@@ -3445,7 +3444,7 @@
 			goto out;
 		}
 		orphan = 1;
-		ei->i_disksize = inode->i_size;
+		ext4_update_i_disksize(inode, inode->i_size);
 		ext4_journal_stop(handle);
 	}
 
@@ -3573,7 +3572,7 @@
 		if (ret > 0) {
 			loff_t end = offset + ret;
 			if (end > inode->i_size) {
-				ei->i_disksize = end;
+				ext4_update_i_disksize(inode, end);
 				i_size_write(inode, end);
 				/*
 				 * We're going to return a positive `ret'
@@ -4561,6 +4560,12 @@
 		goto bad_inode;
 	raw_inode = ext4_raw_inode(&iloc);
 
+	if ((ino == EXT4_ROOT_INO) && (raw_inode->i_links_count == 0)) {
+		EXT4_ERROR_INODE(inode, "root inode unallocated");
+		ret = -EFSCORRUPTED;
+		goto bad_inode;
+	}
+
 	if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) {
 		ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize);
 		if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index e5e99a7..4beca06 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -3878,7 +3878,8 @@
 
 	err = ext4_mb_load_buddy(sb, group, &e4b);
 	if (err) {
-		ext4_error(sb, "Error loading buddy information for %u", group);
+		ext4_warning(sb, "Error %d loading buddy information for %u",
+			     err, group);
 		put_bh(bitmap_bh);
 		return 0;
 	}
@@ -4035,10 +4036,11 @@
 		BUG_ON(pa->pa_type != MB_INODE_PA);
 		group = ext4_get_group_number(sb, pa->pa_pstart);
 
-		err = ext4_mb_load_buddy(sb, group, &e4b);
+		err = ext4_mb_load_buddy_gfp(sb, group, &e4b,
+					     GFP_NOFS|__GFP_NOFAIL);
 		if (err) {
-			ext4_error(sb, "Error loading buddy information for %u",
-					group);
+			ext4_error(sb, "Error %d loading buddy information for %u",
+				   err, group);
 			continue;
 		}
 
@@ -4294,11 +4296,14 @@
 	spin_unlock(&lg->lg_prealloc_lock);
 
 	list_for_each_entry_safe(pa, tmp, &discard_list, u.pa_tmp_list) {
+		int err;
 
 		group = ext4_get_group_number(sb, pa->pa_pstart);
-		if (ext4_mb_load_buddy(sb, group, &e4b)) {
-			ext4_error(sb, "Error loading buddy information for %u",
-					group);
+		err = ext4_mb_load_buddy_gfp(sb, group, &e4b,
+					     GFP_NOFS|__GFP_NOFAIL);
+		if (err) {
+			ext4_error(sb, "Error %d loading buddy information for %u",
+				   err, group);
 			continue;
 		}
 		ext4_lock_group(sb, group);
@@ -5122,8 +5127,8 @@
 
 	ret = ext4_mb_load_buddy(sb, group, &e4b);
 	if (ret) {
-		ext4_error(sb, "Error in loading buddy "
-				"information for %u", group);
+		ext4_warning(sb, "Error %d loading buddy information for %u",
+			     ret, group);
 		return ret;
 	}
 	bitmap = e4b.bd_bitmap;
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 8338cd4..e3183e8 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -3027,36 +3027,16 @@
 	struct inode *inode;
 	int err, len = strlen(symname);
 	int credits;
-	bool encryption_required;
 	struct fscrypt_str disk_link;
-	struct fscrypt_symlink_data *sd = NULL;
 
-	disk_link.len = len + 1;
-	disk_link.name = (char *) symname;
-
-	encryption_required = (ext4_encrypted_inode(dir) ||
-			       DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb)));
-	if (encryption_required) {
-		err = fscrypt_get_encryption_info(dir);
-		if (err)
-			return err;
-		if (!fscrypt_has_encryption_key(dir))
-			return -ENOKEY;
-		disk_link.len = (fscrypt_fname_encrypted_size(dir, len) +
-				 sizeof(struct fscrypt_symlink_data));
-		sd = kzalloc(disk_link.len, GFP_KERNEL);
-		if (!sd)
-			return -ENOMEM;
-	}
-
-	if (disk_link.len > dir->i_sb->s_blocksize) {
-		err = -ENAMETOOLONG;
-		goto err_free_sd;
-	}
+	err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize,
+				      &disk_link);
+	if (err)
+		return err;
 
 	err = dquot_initialize(dir);
 	if (err)
-		goto err_free_sd;
+		return err;
 
 	if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
 		/*
@@ -3085,27 +3065,18 @@
 	if (IS_ERR(inode)) {
 		if (handle)
 			ext4_journal_stop(handle);
-		err = PTR_ERR(inode);
-		goto err_free_sd;
+		return PTR_ERR(inode);
 	}
 
-	if (encryption_required) {
-		struct qstr istr;
-		struct fscrypt_str ostr =
-			FSTR_INIT(sd->encrypted_path, disk_link.len);
-
-		istr.name = (const unsigned char *) symname;
-		istr.len = len;
-		err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr);
+	if (IS_ENCRYPTED(inode)) {
+		err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link);
 		if (err)
 			goto err_drop_inode;
-		sd->len = cpu_to_le16(ostr.len);
-		disk_link.name = (char *) sd;
 		inode->i_op = &ext4_encrypted_symlink_inode_operations;
 	}
 
 	if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
-		if (!encryption_required)
+		if (!IS_ENCRYPTED(inode))
 			inode->i_op = &ext4_symlink_inode_operations;
 		inode_nohighmem(inode);
 		ext4_set_aops(inode);
@@ -3147,7 +3118,7 @@
 	} else {
 		/* clear the extent format for fast symlink */
 		ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS);
-		if (!encryption_required) {
+		if (!IS_ENCRYPTED(inode)) {
 			inode->i_op = &ext4_fast_symlink_inode_operations;
 			inode->i_link = (char *)&EXT4_I(inode)->i_data;
 		}
@@ -3162,16 +3133,17 @@
 
 	if (handle)
 		ext4_journal_stop(handle);
-	kfree(sd);
-	return err;
+	goto out_free_encrypted_link;
+
 err_drop_inode:
 	if (handle)
 		ext4_journal_stop(handle);
 	clear_nlink(inode);
 	unlock_new_inode(inode);
 	iput(inode);
-err_free_sd:
-	kfree(sd);
+out_free_encrypted_link:
+	if (disk_link.name != (unsigned char *)symname)
+		kfree(disk_link.name);
 	return err;
 }
 
diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
index 2531cc1..c39a12d 100644
--- a/fs/ext4/readpage.c
+++ b/fs/ext4/readpage.c
@@ -91,7 +91,7 @@
 		if (bio->bi_error) {
 			fscrypt_release_ctx(bio->bi_private);
 		} else {
-			fscrypt_decrypt_bio_pages(bio->bi_private, bio);
+			fscrypt_enqueue_decrypt_bio(bio->bi_private, bio);
 			return;
 		}
 	}
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 43ce5fc..e95b6e1 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1028,9 +1028,7 @@
 		jbd2_free_inode(EXT4_I(inode)->jinode);
 		EXT4_I(inode)->jinode = NULL;
 	}
-#ifdef CONFIG_EXT4_FS_ENCRYPTION
-	fscrypt_put_encryption_info(inode, NULL);
-#endif
+	fscrypt_put_encryption_info(inode);
 }
 
 static struct inode *ext4_nfs_get_inode(struct super_block *sb,
@@ -2272,6 +2270,8 @@
 			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
 				 "Block bitmap for group %u overlaps "
 				 "superblock", i);
+			if (!(sb->s_flags & MS_RDONLY))
+				return 0;
 		}
 		if (block_bitmap < first_block || block_bitmap > last_block) {
 			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
@@ -2284,6 +2284,8 @@
 			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
 				 "Inode bitmap for group %u overlaps "
 				 "superblock", i);
+			if (!(sb->s_flags & MS_RDONLY))
+				return 0;
 		}
 		if (inode_bitmap < first_block || inode_bitmap > last_block) {
 			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
@@ -2296,6 +2298,8 @@
 			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
 				 "Inode table for group %u overlaps "
 				 "superblock", i);
+			if (!(sb->s_flags & MS_RDONLY))
+				return 0;
 		}
 		if (inode_table < first_block ||
 		    inode_table + sbi->s_itb_per_group - 1 > last_block) {
diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
index 557b3b0..d4ce3af 100644
--- a/fs/ext4/symlink.c
+++ b/fs/ext4/symlink.c
@@ -27,59 +27,28 @@
 					   struct delayed_call *done)
 {
 	struct page *cpage = NULL;
-	char *caddr, *paddr = NULL;
-	struct fscrypt_str cstr, pstr;
-	struct fscrypt_symlink_data *sd;
-	int res;
-	u32 max_size = inode->i_sb->s_blocksize;
+	const void *caddr;
+	unsigned int max_size;
+	const char *paddr;
 
 	if (!dentry)
 		return ERR_PTR(-ECHILD);
 
-	res = fscrypt_get_encryption_info(inode);
-	if (res)
-		return ERR_PTR(res);
-
 	if (ext4_inode_is_fast_symlink(inode)) {
-		caddr = (char *) EXT4_I(inode)->i_data;
+		caddr = EXT4_I(inode)->i_data;
 		max_size = sizeof(EXT4_I(inode)->i_data);
 	} else {
 		cpage = read_mapping_page(inode->i_mapping, 0, NULL);
 		if (IS_ERR(cpage))
 			return ERR_CAST(cpage);
 		caddr = page_address(cpage);
+		max_size = inode->i_sb->s_blocksize;
 	}
 
-	/* Symlink is encrypted */
-	sd = (struct fscrypt_symlink_data *)caddr;
-	cstr.name = sd->encrypted_path;
-	cstr.len  = le16_to_cpu(sd->len);
-	if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) {
-		/* Symlink data on the disk is corrupted */
-		res = -EFSCORRUPTED;
-		goto errout;
-	}
-
-	res = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr);
-	if (res)
-		goto errout;
-	paddr = pstr.name;
-
-	res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr);
-	if (res)
-		goto errout;
-
-	/* Null-terminate the name */
-	paddr[pstr.len] = '\0';
+	paddr = fscrypt_get_symlink(inode, caddr, max_size, done);
 	if (cpage)
 		put_page(cpage);
-	set_delayed_call(done, kfree_link, paddr);
 	return paddr;
-errout:
-	if (cpage)
-		put_page(cpage);
-	kfree(paddr);
-	return ERR_PTR(res);
 }
 
 const struct inode_operations ext4_encrypted_symlink_inode_operations = {
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index 701781a..91b2d00 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -68,6 +68,7 @@
 		.old_blkaddr = index,
 		.new_blkaddr = index,
 		.encrypted_page = NULL,
+		.is_meta = is_meta,
 	};
 
 	if (unlikely(!is_meta))
@@ -162,6 +163,7 @@
 		.op_flags = sync ? (REQ_META | REQ_PRIO) : REQ_RAHEAD,
 		.encrypted_page = NULL,
 		.in_list = false,
+		.is_meta = (type != META_POR),
 	};
 	struct blk_plug plug;
 
@@ -383,7 +385,7 @@
 	if (!PageUptodate(page))
 		SetPageUptodate(page);
 	if (!PageDirty(page)) {
-		f2fs_set_page_dirty_nobuffers(page);
+		__set_page_dirty_nobuffers(page);
 		inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_META);
 		SetPagePrivate(page);
 		f2fs_trace_pid(page);
@@ -572,13 +574,8 @@
 	struct node_info ni;
 	int err = acquire_orphan_inode(sbi);
 
-	if (err) {
-		set_sbi_flag(sbi, SBI_NEED_FSCK);
-		f2fs_msg(sbi->sb, KERN_WARNING,
-				"%s: orphan failed (ino=%x), run fsck to fix.",
-				__func__, ino);
-		return err;
-	}
+	if (err)
+		goto err_out;
 
 	__add_ino_entry(sbi, ino, 0, ORPHAN_INO);
 
@@ -592,6 +589,11 @@
 		return PTR_ERR(inode);
 	}
 
+	err = dquot_initialize(inode);
+	if (err)
+		goto err_out;
+
+	dquot_initialize(inode);
 	clear_nlink(inode);
 
 	/* truncate all the data during iput */
@@ -601,14 +603,18 @@
 
 	/* ENOMEM was fully retried in f2fs_evict_inode. */
 	if (ni.blk_addr != NULL_ADDR) {
-		set_sbi_flag(sbi, SBI_NEED_FSCK);
-		f2fs_msg(sbi->sb, KERN_WARNING,
-			"%s: orphan failed (ino=%x) by kernel, retry mount.",
-				__func__, ino);
-		return -EIO;
+		err = -EIO;
+		goto err_out;
 	}
 	__remove_ino_entry(sbi, ino, ORPHAN_INO);
 	return 0;
+
+err_out:
+	set_sbi_flag(sbi, SBI_NEED_FSCK);
+	f2fs_msg(sbi->sb, KERN_WARNING,
+			"%s: orphan failed (ino=%x), run fsck to fix.",
+			__func__, ino);
+	return err;
 }
 
 int recover_orphan_inodes(struct f2fs_sb_info *sbi)
@@ -1139,6 +1145,8 @@
 
 	if (cpc->reason & CP_TRIMMED)
 		__set_ckpt_flags(ckpt, CP_TRIMMED_FLAG);
+	else
+		__clear_ckpt_flags(ckpt, CP_TRIMMED_FLAG);
 
 	if (cpc->reason & CP_UMOUNT)
 		__set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
@@ -1165,6 +1173,39 @@
 	spin_unlock_irqrestore(&sbi->cp_lock, flags);
 }
 
+static void commit_checkpoint(struct f2fs_sb_info *sbi,
+	void *src, block_t blk_addr)
+{
+	struct writeback_control wbc = {
+		.for_reclaim = 0,
+	};
+
+	/*
+	 * pagevec_lookup_tag and lock_page again will take
+	 * some extra time. Therefore, update_meta_pages and
+	 * sync_meta_pages are combined in this function.
+	 */
+	struct page *page = grab_meta_page(sbi, blk_addr);
+	int err;
+
+	memcpy(page_address(page), src, PAGE_SIZE);
+	set_page_dirty(page);
+
+	f2fs_wait_on_page_writeback(page, META, true);
+	f2fs_bug_on(sbi, PageWriteback(page));
+	if (unlikely(!clear_page_dirty_for_io(page)))
+		f2fs_bug_on(sbi, 1);
+
+	/* writeout cp pack 2 page */
+	err = __f2fs_write_meta_page(page, &wbc, FS_CP_META_IO);
+	f2fs_bug_on(sbi, err);
+
+	f2fs_put_page(page, 0);
+
+	/* submit checkpoint (with barrier if NOBARRIER is not set) */
+	f2fs_submit_merged_write(sbi, META_FLUSH);
+}
+
 static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 {
 	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
@@ -1267,16 +1308,6 @@
 		}
 	}
 
-	/* need to wait for end_io results */
-	wait_on_all_pages_writeback(sbi);
-	if (unlikely(f2fs_cp_error(sbi)))
-		return -EIO;
-
-	/* flush all device cache */
-	err = f2fs_flush_device_cache(sbi);
-	if (err)
-		return err;
-
 	/* write out checkpoint buffer at block 0 */
 	update_meta_page(sbi, ckpt, start_blk++);
 
@@ -1304,26 +1335,26 @@
 		start_blk += NR_CURSEG_NODE_TYPE;
 	}
 
-	/* writeout checkpoint block */
-	update_meta_page(sbi, ckpt, start_blk);
+	/* update user_block_counts */
+	sbi->last_valid_block_count = sbi->total_valid_block_count;
+	percpu_counter_set(&sbi->alloc_valid_block_count, 0);
 
-	/* wait for previous submitted node/meta pages writeback */
+	/* Here, we have one bio having CP pack except cp pack 2 page */
+	sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
+
+	/* wait for previous submitted meta pages writeback */
 	wait_on_all_pages_writeback(sbi);
 
 	if (unlikely(f2fs_cp_error(sbi)))
 		return -EIO;
 
-	filemap_fdatawait_range(NODE_MAPPING(sbi), 0, LLONG_MAX);
-	filemap_fdatawait_range(META_MAPPING(sbi), 0, LLONG_MAX);
+	/* flush all device cache */
+	err = f2fs_flush_device_cache(sbi);
+	if (err)
+		return err;
 
-	/* update user_block_counts */
-	sbi->last_valid_block_count = sbi->total_valid_block_count;
-	percpu_counter_set(&sbi->alloc_valid_block_count, 0);
-
-	/* Here, we only have one bio having CP pack */
-	sync_meta_pages(sbi, META_FLUSH, LONG_MAX, FS_CP_META_IO);
-
-	/* wait for previous submitted meta pages writeback */
+	/* barrier and flush checkpoint cp pack 2 page if it can */
+	commit_checkpoint(sbi, ckpt, start_blk);
 	wait_on_all_pages_writeback(sbi);
 
 	release_ino_entry(sbi, false);
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 6c13ee3..b1fd4e2 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -19,8 +19,6 @@
 #include <linux/bio.h>
 #include <linux/prefetch.h>
 #include <linux/uio.h>
-#include <linux/mm.h>
-#include <linux/memcontrol.h>
 #include <linux/cleancache.h>
 
 #include "f2fs.h"
@@ -30,6 +28,11 @@
 #include <trace/events/f2fs.h>
 #include <trace/events/android_fs.h>
 
+#define NUM_PREALLOC_POST_READ_CTXS	128
+
+static struct kmem_cache *bio_post_read_ctx_cache;
+static mempool_t *bio_post_read_ctx_pool;
+
 static bool __is_cp_guaranteed(struct page *page)
 {
 	struct address_space *mapping = page->mapping;
@@ -50,11 +53,77 @@
 	return false;
 }
 
-static void f2fs_read_end_io(struct bio *bio)
+/* postprocessing steps for read bios */
+enum bio_post_read_step {
+	STEP_INITIAL = 0,
+	STEP_DECRYPT,
+};
+
+struct bio_post_read_ctx {
+	struct bio *bio;
+	struct work_struct work;
+	unsigned int cur_step;
+	unsigned int enabled_steps;
+};
+
+static void __read_end_io(struct bio *bio)
 {
-	struct bio_vec *bvec;
+	struct page *page;
+	struct bio_vec *bv;
 	int i;
 
+	bio_for_each_segment_all(bv, bio, i) {
+		page = bv->bv_page;
+
+		/* PG_error was set if any post_read step failed */
+		if (bio->bi_error || PageError(page)) {
+			ClearPageUptodate(page);
+			SetPageError(page);
+		} else {
+			SetPageUptodate(page);
+		}
+		unlock_page(page);
+	}
+	if (bio->bi_private)
+		mempool_free(bio->bi_private, bio_post_read_ctx_pool);
+	bio_put(bio);
+}
+
+static void bio_post_read_processing(struct bio_post_read_ctx *ctx);
+
+static void decrypt_work(struct work_struct *work)
+{
+	struct bio_post_read_ctx *ctx =
+		container_of(work, struct bio_post_read_ctx, work);
+
+	fscrypt_decrypt_bio(ctx->bio);
+
+	bio_post_read_processing(ctx);
+}
+
+static void bio_post_read_processing(struct bio_post_read_ctx *ctx)
+{
+	switch (++ctx->cur_step) {
+	case STEP_DECRYPT:
+		if (ctx->enabled_steps & (1 << STEP_DECRYPT)) {
+			INIT_WORK(&ctx->work, decrypt_work);
+			fscrypt_enqueue_decrypt_work(&ctx->work);
+			return;
+		}
+		ctx->cur_step++;
+		/* fall-through */
+	default:
+		__read_end_io(ctx->bio);
+	}
+}
+
+static bool f2fs_bio_post_read_required(struct bio *bio)
+{
+	return bio->bi_private && !bio->bi_error;
+}
+
+static void f2fs_read_end_io(struct bio *bio)
+{
 #ifdef CONFIG_F2FS_FAULT_INJECTION
 	if (time_to_inject(F2FS_P_SB(bio->bi_io_vec->bv_page), FAULT_IO)) {
 		f2fs_show_injection_info(FAULT_IO);
@@ -62,28 +131,15 @@
 	}
 #endif
 
-	if (f2fs_bio_encrypted(bio)) {
-		if (bio->bi_error) {
-			fscrypt_release_ctx(bio->bi_private);
-		} else {
-			fscrypt_decrypt_bio_pages(bio->bi_private, bio);
-			return;
-		}
+	if (f2fs_bio_post_read_required(bio)) {
+		struct bio_post_read_ctx *ctx = bio->bi_private;
+
+		ctx->cur_step = STEP_INITIAL;
+		bio_post_read_processing(ctx);
+		return;
 	}
 
-	bio_for_each_segment_all(bvec, bio, i) {
-		struct page *page = bvec->bv_page;
-
-		if (!bio->bi_error) {
-			if (!PageUptodate(page))
-				SetPageUptodate(page);
-		} else {
-			ClearPageUptodate(page);
-			SetPageError(page);
-		}
-		unlock_page(page);
-	}
-	bio_put(bio);
+	__read_end_io(bio);
 }
 
 static void f2fs_write_end_io(struct bio *bio)
@@ -174,15 +230,22 @@
  */
 static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr,
 				struct writeback_control *wbc,
-				int npages, bool is_read)
+				int npages, bool is_read,
+				enum page_type type, enum temp_type temp)
 {
 	struct bio *bio;
 
 	bio = f2fs_bio_alloc(sbi, npages, true);
 
 	f2fs_target_device(sbi, blk_addr, bio);
-	bio->bi_end_io = is_read ? f2fs_read_end_io : f2fs_write_end_io;
-	bio->bi_private = is_read ? NULL : sbi;
+	if (is_read) {
+		bio->bi_end_io = f2fs_read_end_io;
+		bio->bi_private = NULL;
+	} else {
+		bio->bi_end_io = f2fs_write_end_io;
+		bio->bi_private = sbi;
+		bio->bi_write_hint = io_type_to_rw_hint(sbi, type, temp);
+	}
 	if (wbc)
 		wbc_init_bio(wbc, bio);
 
@@ -195,13 +258,12 @@
 	if (!is_read_io(bio_op(bio))) {
 		unsigned int start;
 
-		if (f2fs_sb_mounted_blkzoned(sbi->sb) &&
-			current->plug && (type == DATA || type == NODE))
-			blk_finish_plug(current->plug);
-
 		if (type != DATA && type != NODE)
 			goto submit_io;
 
+		if (f2fs_sb_has_blkzoned(sbi->sb) && current->plug)
+			blk_finish_plug(current->plug);
+
 		start = bio->bi_iter.bi_size >> F2FS_BLKSIZE_BITS;
 		start %= F2FS_IO_SIZE(sbi);
 
@@ -376,12 +438,13 @@
 	struct page *page = fio->encrypted_page ?
 			fio->encrypted_page : fio->page;
 
+	verify_block_addr(fio, fio->new_blkaddr);
 	trace_f2fs_submit_page_bio(page, fio);
 	f2fs_trace_ios(fio, 0);
 
 	/* Allocate a new bio */
 	bio = __bio_alloc(fio->sbi, fio->new_blkaddr, fio->io_wbc,
-				1, is_read_io(fio->op));
+				1, is_read_io(fio->op), fio->type, fio->temp);
 
 	if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
 		bio_put(bio);
@@ -421,8 +484,8 @@
 	}
 
 	if (fio->old_blkaddr != NEW_ADDR)
-		verify_block_addr(sbi, fio->old_blkaddr);
-	verify_block_addr(sbi, fio->new_blkaddr);
+		verify_block_addr(fio, fio->old_blkaddr);
+	verify_block_addr(fio, fio->new_blkaddr);
 
 	bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page;
 
@@ -444,7 +507,8 @@
 			goto out_fail;
 		}
 		io->bio = __bio_alloc(sbi, fio->new_blkaddr, fio->io_wbc,
-						BIO_MAX_PAGES, false);
+						BIO_MAX_PAGES, false,
+						fio->type, fio->temp);
 		io->fio = *fio;
 	}
 
@@ -472,29 +536,33 @@
 							 unsigned nr_pages)
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-	struct fscrypt_ctx *ctx = NULL;
 	struct bio *bio;
+	struct bio_post_read_ctx *ctx;
+	unsigned int post_read_steps = 0;
 
-	if (f2fs_encrypted_file(inode)) {
-		ctx = fscrypt_get_ctx(inode, GFP_NOFS);
-		if (IS_ERR(ctx))
-			return ERR_CAST(ctx);
+	bio = f2fs_bio_alloc(sbi, min_t(int, nr_pages, BIO_MAX_PAGES), false);
+	if (!bio)
+		return ERR_PTR(-ENOMEM);
+	f2fs_target_device(sbi, blkaddr, bio);
+	bio->bi_end_io = f2fs_read_end_io;
+	bio_set_op_attrs(bio, REQ_OP_READ, 0);
+
+	if (f2fs_encrypted_file(inode))
+		post_read_steps |= 1 << STEP_DECRYPT;
+	if (post_read_steps) {
+		ctx = mempool_alloc(bio_post_read_ctx_pool, GFP_NOFS);
+		if (!ctx) {
+			bio_put(bio);
+			return ERR_PTR(-ENOMEM);
+		}
+		ctx->bio = bio;
+		ctx->enabled_steps = post_read_steps;
+		bio->bi_private = ctx;
 
 		/* wait the page to be moved by cleaning */
 		f2fs_wait_on_block_writeback(sbi, blkaddr);
 	}
 
-	bio = f2fs_bio_alloc(sbi, min_t(int, nr_pages, BIO_MAX_PAGES), false);
-	if (!bio) {
-		if (ctx)
-			fscrypt_release_ctx(ctx);
-		return ERR_PTR(-ENOMEM);
-	}
-	f2fs_target_device(sbi, blkaddr, bio);
-	bio->bi_end_io = f2fs_read_end_io;
-	bio->bi_private = ctx;
-	bio_set_op_attrs(bio, REQ_OP_READ, 0);
-
 	return bio;
 }
 
@@ -831,13 +899,6 @@
 	return 0;
 }
 
-static inline bool __force_buffered_io(struct inode *inode, int rw)
-{
-	return (f2fs_encrypted_file(inode) ||
-			(rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) ||
-			F2FS_I_SB(inode)->s_ndevs);
-}
-
 int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
 {
 	struct inode *inode = file_inode(iocb->ki_filp);
@@ -868,9 +929,8 @@
 	map.m_seg_type = NO_CHECK_TYPE;
 
 	if (direct_io) {
-		/* map.m_seg_type = rw_hint_to_seg_type(iocb->ki_hint); */
-		map.m_seg_type = rw_hint_to_seg_type(WRITE_LIFE_NOT_SET);
-		flag = __force_buffered_io(inode, WRITE) ?
+		map.m_seg_type = rw_hint_to_seg_type(iocb->ki_hint);
+		flag = f2fs_force_buffered_io(inode, WRITE) ?
 					F2FS_GET_BLOCK_PRE_AIO :
 					F2FS_GET_BLOCK_PRE_DIO;
 		goto map_blocks;
@@ -1114,6 +1174,31 @@
 	return err;
 }
 
+bool f2fs_overwrite_io(struct inode *inode, loff_t pos, size_t len)
+{
+	struct f2fs_map_blocks map;
+	block_t last_lblk;
+	int err;
+
+	if (pos + len > i_size_read(inode))
+		return false;
+
+	map.m_lblk = F2FS_BYTES_TO_BLK(pos);
+	map.m_next_pgofs = NULL;
+	map.m_next_extent = NULL;
+	map.m_seg_type = NO_CHECK_TYPE;
+	last_lblk = F2FS_BLK_ALIGN(pos + len);
+
+	while (map.m_lblk < last_lblk) {
+		map.m_len = last_lblk - map.m_lblk;
+		err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_DEFAULT);
+		if (err || map.m_len == 0)
+			return false;
+		map.m_lblk += map.m_len;
+	}
+	return true;
+}
+
 static int __get_data_block(struct inode *inode, sector_t iblock,
 			struct buffer_head *bh, int create, int flag,
 			pgoff_t *next_pgofs, int seg_type)
@@ -1151,8 +1236,7 @@
 	return __get_data_block(inode, iblock, bh_result, create,
 						F2FS_GET_BLOCK_DEFAULT, NULL,
 						rw_hint_to_seg_type(
-							WRITE_LIFE_NOT_SET));
-						/* inode->i_write_hint)); */
+							inode->i_write_hint));
 }
 
 static int get_data_block_bmap(struct inode *inode, sector_t iblock,
@@ -1500,7 +1584,7 @@
 	if (!f2fs_encrypted_file(inode))
 		return 0;
 
-	/* wait for GCed encrypted page writeback */
+	/* wait for GCed page writeback via META_MAPPING */
 	f2fs_wait_on_block_writeback(fio->sbi, fio->old_blkaddr);
 
 retry_encrypt:
@@ -1650,6 +1734,7 @@
 			goto out_writepage;
 
 		set_page_writeback(page);
+		ClearPageError(page);
 		f2fs_put_dnode(&dn);
 		if (fio->need_lock == LOCK_REQ)
 			f2fs_unlock_op(fio->sbi);
@@ -1672,6 +1757,7 @@
 		goto out_writepage;
 
 	set_page_writeback(page);
+	ClearPageError(page);
 
 	/* LFS mode write path */
 	write_data_page(&dn, fio);
@@ -2212,8 +2298,8 @@
 
 	f2fs_wait_on_page_writeback(page, DATA, false);
 
-	/* wait for GCed encrypted page writeback */
-	if (f2fs_encrypted_file(inode))
+	/* wait for GCed page writeback via META_MAPPING */
+	if (f2fs_post_read_required(inode))
 		f2fs_wait_on_block_writeback(sbi, blkaddr);
 
 	if (len == PAGE_SIZE || PageUptodate(page))
@@ -2304,16 +2390,19 @@
 {
 	struct address_space *mapping = iocb->ki_filp->f_mapping;
 	struct inode *inode = mapping->host;
+	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
 	size_t count = iov_iter_count(iter);
 	loff_t offset = iocb->ki_pos;
 	int rw = iov_iter_rw(iter);
 	int err;
+	enum rw_hint hint = iocb->ki_hint;
+	int whint_mode = F2FS_OPTION(sbi).whint_mode;
 
 	err = check_direct_IO(inode, iter, offset);
 	if (err)
 		return err;
 
-	if (__force_buffered_io(inode, rw))
+	if (f2fs_force_buffered_io(inode, rw))
 		return 0;
 
 	trace_f2fs_direct_IO_enter(inode, offset, count, rw);
@@ -2340,12 +2429,24 @@
 						 current->pid, path,
 						 current->comm);
 	}
+	if (rw == WRITE && whint_mode == WHINT_MODE_OFF)
+		iocb->ki_hint = WRITE_LIFE_NOT_SET;
 
-	down_read(&F2FS_I(inode)->dio_rwsem[rw]);
+	if (!down_read_trylock(&F2FS_I(inode)->dio_rwsem[rw])) {
+		if (iocb->ki_flags & IOCB_NOWAIT) {
+			iocb->ki_hint = hint;
+			err = -EAGAIN;
+			goto out;
+		}
+		down_read(&F2FS_I(inode)->dio_rwsem[rw]);
+	}
+
 	err = blockdev_direct_IO(iocb, inode, iter, get_data_block_dio);
 	up_read(&F2FS_I(inode)->dio_rwsem[rw]);
 
 	if (rw == WRITE) {
+		if (whint_mode == WHINT_MODE_OFF)
+			iocb->ki_hint = hint;
 		if (err > 0) {
 			f2fs_update_iostat(F2FS_I_SB(inode), APP_DIRECT_IO,
 									err);
@@ -2354,7 +2455,7 @@
 			f2fs_write_failed(mapping, offset + count);
 		}
 	}
-
+out:
 	if (trace_android_fs_dataread_start_enabled() &&
 	    (rw == READ))
 		trace_android_fs_dataread_end(inode, offset, count);
@@ -2411,35 +2512,6 @@
 	return 1;
 }
 
-/*
- * This was copied from __set_page_dirty_buffers which gives higher performance
- * in very high speed storages. (e.g., pmem)
- */
-void f2fs_set_page_dirty_nobuffers(struct page *page)
-{
-	struct address_space *mapping = page->mapping;
-	unsigned long flags;
-
-	if (unlikely(!mapping))
-		return;
-
-	spin_lock(&mapping->private_lock);
-	lock_page_memcg(page);
-	SetPageDirty(page);
-	spin_unlock(&mapping->private_lock);
-
-	spin_lock_irqsave(&mapping->tree_lock, flags);
-	WARN_ON_ONCE(!PageUptodate(page));
-	account_page_dirtied(page, mapping);
-	radix_tree_tag_set(&mapping->page_tree,
-			page_index(page), PAGECACHE_TAG_DIRTY);
-	spin_unlock_irqrestore(&mapping->tree_lock, flags);
-	unlock_page_memcg(page);
-
-	__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
-	return;
-}
-
 static int f2fs_set_data_page_dirty(struct page *page)
 {
 	struct address_space *mapping = page->mapping;
@@ -2463,7 +2535,7 @@
 	}
 
 	if (!PageDirty(page)) {
-		f2fs_set_page_dirty_nobuffers(page);
+		__set_page_dirty_nobuffers(page);
 		update_dirty_page(inode, page);
 		return 1;
 	}
@@ -2556,3 +2628,27 @@
 	.migratepage    = f2fs_migrate_page,
 #endif
 };
+
+int __init f2fs_init_post_read_processing(void)
+{
+	bio_post_read_ctx_cache = KMEM_CACHE(bio_post_read_ctx, 0);
+	if (!bio_post_read_ctx_cache)
+		goto fail;
+	bio_post_read_ctx_pool =
+		mempool_create_slab_pool(NUM_PREALLOC_POST_READ_CTXS,
+					 bio_post_read_ctx_cache);
+	if (!bio_post_read_ctx_pool)
+		goto fail_free_cache;
+	return 0;
+
+fail_free_cache:
+	kmem_cache_destroy(bio_post_read_ctx_cache);
+fail:
+	return -ENOMEM;
+}
+
+void __exit f2fs_destroy_post_read_processing(void)
+{
+	mempool_destroy(bio_post_read_ctx_pool);
+	kmem_cache_destroy(bio_post_read_ctx_cache);
+}
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index a352ace5..f9a1e18 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -361,6 +361,7 @@
 			struct page *dpage)
 {
 	struct page *page;
+	int dummy_encrypt = DUMMY_ENCRYPTION_ENABLED(F2FS_I_SB(dir));
 	int err;
 
 	if (is_inode_flag_set(inode, FI_NEW_INODE)) {
@@ -387,7 +388,8 @@
 		if (err)
 			goto put_error;
 
-		if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode)) {
+		if ((f2fs_encrypted_inode(dir) || dummy_encrypt) &&
+					f2fs_may_encrypt(inode)) {
 			err = fscrypt_inherit_context(dir, inode, page, false);
 			if (err)
 				goto put_error;
@@ -396,8 +398,6 @@
 		page = get_node_page(F2FS_I_SB(dir), inode->i_ino);
 		if (IS_ERR(page))
 			return page;
-
-		set_cold_node(inode, page);
 	}
 
 	if (new_name) {
@@ -704,7 +704,8 @@
 
 	f2fs_update_time(F2FS_I_SB(dir), REQ_TIME);
 
-	add_ino_entry(F2FS_I_SB(dir), dir->i_ino, TRANS_DIR_INO);
+	if (F2FS_OPTION(F2FS_I_SB(dir)).fsync_mode == FSYNC_MODE_STRICT)
+		add_ino_entry(F2FS_I_SB(dir), dir->i_ino, TRANS_DIR_INO);
 
 	if (f2fs_has_inline_dentry(dir))
 		return f2fs_delete_inline_entry(dentry, page, dir, inode);
diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c
index ff2352a..d5a861b 100644
--- a/fs/f2fs/extent_cache.c
+++ b/fs/f2fs/extent_cache.c
@@ -460,7 +460,7 @@
 				struct rb_node *insert_parent)
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-	struct rb_node **p = &et->root.rb_node;
+	struct rb_node **p;
 	struct rb_node *parent = NULL;
 	struct extent_node *en = NULL;
 
@@ -706,6 +706,9 @@
 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
 	struct extent_tree *et = F2FS_I(inode)->extent_tree;
 
+	if (!f2fs_may_extent_tree(inode))
+		return;
+
 	set_inode_flag(inode, FI_NO_EXTENT);
 
 	write_lock(&et->lock);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index e5d3e22..84be1e7 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -99,9 +99,10 @@
 #define F2FS_MOUNT_INLINE_XATTR_SIZE	0x00800000
 #define F2FS_MOUNT_RESERVE_ROOT		0x01000000
 
-#define clear_opt(sbi, option)	((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
-#define set_opt(sbi, option)	((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
-#define test_opt(sbi, option)	((sbi)->mount_opt.opt & F2FS_MOUNT_##option)
+#define F2FS_OPTION(sbi)	((sbi)->mount_opt)
+#define clear_opt(sbi, option)	(F2FS_OPTION(sbi).opt &= ~F2FS_MOUNT_##option)
+#define set_opt(sbi, option)	(F2FS_OPTION(sbi).opt |= F2FS_MOUNT_##option)
+#define test_opt(sbi, option)	(F2FS_OPTION(sbi).opt & F2FS_MOUNT_##option)
 
 #define ver_after(a, b)	(typecheck(unsigned long long, a) &&		\
 		typecheck(unsigned long long, b) &&			\
@@ -114,7 +115,26 @@
 typedef u32 nid_t;
 
 struct f2fs_mount_info {
-	unsigned int	opt;
+	unsigned int opt;
+	int write_io_size_bits;		/* Write IO size bits */
+	block_t root_reserved_blocks;	/* root reserved blocks */
+	kuid_t s_resuid;		/* reserved blocks for uid */
+	kgid_t s_resgid;		/* reserved blocks for gid */
+	int active_logs;		/* # of active logs */
+	int inline_xattr_size;		/* inline xattr size */
+#ifdef CONFIG_F2FS_FAULT_INJECTION
+	struct f2fs_fault_info fault_info;	/* For fault injection */
+#endif
+#ifdef CONFIG_QUOTA
+	/* Names of quota files with journalled quota */
+	char *s_qf_names[MAXQUOTAS];
+	int s_jquota_fmt;			/* Format of quota to use */
+#endif
+	/* For which write hints are passed down to block layer */
+	int whint_mode;
+	int alloc_mode;			/* segment allocation policy */
+	int fsync_mode;			/* fsync policy */
+	bool test_dummy_encryption;	/* test dummy encryption */
 };
 
 #define F2FS_FEATURE_ENCRYPT		0x0001
@@ -126,6 +146,8 @@
 #define F2FS_FEATURE_FLEXIBLE_INLINE_XATTR	0x0040
 #define F2FS_FEATURE_QUOTA_INO		0x0080
 #define F2FS_FEATURE_INODE_CRTIME	0x0100
+#define F2FS_FEATURE_LOST_FOUND		0x0200
+#define F2FS_FEATURE_VERITY		0x0400	/* reserved */
 
 #define F2FS_HAS_FEATURE(sb, mask)					\
 	((F2FS_SB(sb)->raw_super->feature & cpu_to_le32(mask)) != 0)
@@ -448,7 +470,7 @@
 	d->inode = inode;
 	d->max = NR_DENTRY_IN_BLOCK;
 	d->nr_bitmap = SIZE_OF_DENTRY_BITMAP;
-	d->bitmap = &t->dentry_bitmap;
+	d->bitmap = t->dentry_bitmap;
 	d->dentry = t->dentry;
 	d->filename = t->filename;
 }
@@ -574,6 +596,8 @@
 #define FADVISE_ENCRYPT_BIT	0x04
 #define FADVISE_ENC_NAME_BIT	0x08
 #define FADVISE_KEEP_SIZE_BIT	0x10
+#define FADVISE_HOT_BIT		0x20
+#define FADVISE_VERITY_BIT	0x40	/* reserved */
 
 #define file_is_cold(inode)	is_file(inode, FADVISE_COLD_BIT)
 #define file_wrong_pino(inode)	is_file(inode, FADVISE_LOST_PINO_BIT)
@@ -588,6 +612,9 @@
 #define file_set_enc_name(inode) set_file(inode, FADVISE_ENC_NAME_BIT)
 #define file_keep_isize(inode)	is_file(inode, FADVISE_KEEP_SIZE_BIT)
 #define file_set_keep_isize(inode) set_file(inode, FADVISE_KEEP_SIZE_BIT)
+#define file_is_hot(inode)	is_file(inode, FADVISE_HOT_BIT)
+#define file_set_hot(inode)	set_file(inode, FADVISE_HOT_BIT)
+#define file_clear_hot(inode)	clear_file(inode, FADVISE_HOT_BIT)
 
 #define DEF_DIR_LEVEL		0
 
@@ -635,6 +662,7 @@
 	kprojid_t i_projid;		/* id for project quota */
 	int i_inline_xattr_size;	/* inline xattr size */
 	struct timespec i_crtime;	/* inode creation time */
+	struct timespec i_disk_time[4];	/* inode disk times */
 };
 
 static inline void get_extent_info(struct extent_info *ext,
@@ -741,7 +769,7 @@
 	unsigned int nid_cnt[MAX_NID_STATE];	/* the number of free node id */
 	spinlock_t nid_list_lock;	/* protect nid lists ops */
 	struct mutex build_lock;	/* lock for build free nids */
-	unsigned char (*free_nid_bitmap)[NAT_ENTRY_BITMAP_SIZE];
+	unsigned char **free_nid_bitmap;
 	unsigned char *nat_block_bitmap;
 	unsigned short *free_nid_count;	/* free nid count of NAT block */
 
@@ -974,6 +1002,7 @@
 	bool submitted;		/* indicate IO submission */
 	int need_lock;		/* indicate we need to lock cp_rwsem */
 	bool in_list;		/* indicate fio is in io_list */
+	bool is_meta;		/* indicate borrow meta inode mapping or not */
 	enum iostat_type io_type;	/* io type */
 	struct writeback_control *io_wbc; /* writeback control */
 };
@@ -1035,10 +1064,34 @@
 	MAX_TIME,
 };
 
+enum {
+	WHINT_MODE_OFF,		/* not pass down write hints */
+	WHINT_MODE_USER,	/* try to pass down hints given by users */
+	WHINT_MODE_FS,		/* pass down hints with F2FS policy */
+};
+
+enum {
+	ALLOC_MODE_DEFAULT,	/* stay default */
+	ALLOC_MODE_REUSE,	/* reuse segments as much as possible */
+};
+
+enum fsync_mode {
+	FSYNC_MODE_POSIX,	/* fsync follows posix semantics */
+	FSYNC_MODE_STRICT,	/* fsync behaves in line with ext4 */
+};
+
+#ifdef CONFIG_F2FS_FS_ENCRYPTION
+#define DUMMY_ENCRYPTION_ENABLED(sbi) \
+			(unlikely(F2FS_OPTION(sbi).test_dummy_encryption))
+#else
+#define DUMMY_ENCRYPTION_ENABLED(sbi) (0)
+#endif
+
 struct f2fs_sb_info {
 	struct super_block *sb;			/* pointer to VFS super block */
 	struct proc_dir_entry *s_proc;		/* proc entry */
 	struct f2fs_super_block *raw_super;	/* raw super block pointer */
+	struct rw_semaphore sb_lock;		/* lock for raw super block */
 	int valid_super_block;			/* valid super block no */
 	unsigned long s_flag;				/* flags for sbi */
 
@@ -1058,7 +1111,6 @@
 	struct f2fs_bio_info *write_io[NR_PAGE_TYPE];	/* for write bios */
 	struct mutex wio_mutex[NR_PAGE_TYPE - 1][NR_TEMP_TYPE];
 						/* bio ordering for NODE/DATA */
-	int write_io_size_bits;			/* Write IO size bits */
 	mempool_t *write_io_dummy;		/* Dummy pages */
 
 	/* for checkpoint */
@@ -1108,9 +1160,7 @@
 	unsigned int total_node_count;		/* total node block count */
 	unsigned int total_valid_node_count;	/* valid node block count */
 	loff_t max_file_blocks;			/* max block index of file */
-	int active_logs;			/* # of active logs */
 	int dir_level;				/* directory level */
-	int inline_xattr_size;			/* inline xattr size */
 	unsigned int trigger_ssr_threshold;	/* threshold to trigger ssr */
 	int readdir_ra;				/* readahead inode in readdir */
 
@@ -1120,9 +1170,6 @@
 	block_t last_valid_block_count;		/* for recovery */
 	block_t reserved_blocks;		/* configurable reserved blocks */
 	block_t current_reserved_blocks;	/* current reserved blocks */
-	block_t root_reserved_blocks;		/* root reserved blocks */
-	kuid_t s_resuid;			/* reserved blocks for uid */
-	kgid_t s_resgid;			/* reserved blocks for gid */
 
 	unsigned int nquota_files;		/* # of quota sysfile */
 
@@ -1207,17 +1254,6 @@
 
 	/* Precomputed FS UUID checksum for seeding other checksums */
 	__u32 s_chksum_seed;
-
-	/* For fault injection */
-#ifdef CONFIG_F2FS_FAULT_INJECTION
-	struct f2fs_fault_info fault_info;
-#endif
-
-#ifdef CONFIG_QUOTA
-	/* Names of quota files with journalled quota */
-	char *s_qf_names[MAXQUOTAS];
-	int s_jquota_fmt;			/* Format of quota to use */
-#endif
 };
 
 #ifdef CONFIG_F2FS_FAULT_INJECTION
@@ -1227,7 +1263,7 @@
 		__func__, __builtin_return_address(0))
 static inline bool time_to_inject(struct f2fs_sb_info *sbi, int type)
 {
-	struct f2fs_fault_info *ffi = &sbi->fault_info;
+	struct f2fs_fault_info *ffi = &F2FS_OPTION(sbi).fault_info;
 
 	if (!ffi->inject_rate)
 		return false;
@@ -1576,7 +1612,7 @@
 }
 
 static inline bool __allow_reserved_blocks(struct f2fs_sb_info *sbi,
-					struct inode *inode)
+					struct inode *inode, bool cap)
 {
 	if (!inode)
 		return true;
@@ -1584,12 +1620,12 @@
 		return false;
 	if (IS_NOQUOTA(inode))
 		return true;
-	if (capable(CAP_SYS_RESOURCE))
+	if (uid_eq(F2FS_OPTION(sbi).s_resuid, current_fsuid()))
 		return true;
-	if (uid_eq(sbi->s_resuid, current_fsuid()))
+	if (!gid_eq(F2FS_OPTION(sbi).s_resgid, GLOBAL_ROOT_GID) &&
+					in_group_p(F2FS_OPTION(sbi).s_resgid))
 		return true;
-	if (!gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) &&
-					in_group_p(sbi->s_resgid))
+	if (cap && capable(CAP_SYS_RESOURCE))
 		return true;
 	return false;
 }
@@ -1624,8 +1660,8 @@
 	avail_user_block_count = sbi->user_block_count -
 					sbi->current_reserved_blocks;
 
-	if (!__allow_reserved_blocks(sbi, inode))
-		avail_user_block_count -= sbi->root_reserved_blocks;
+	if (!__allow_reserved_blocks(sbi, inode, true))
+		avail_user_block_count -= F2FS_OPTION(sbi).root_reserved_blocks;
 
 	if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
 		diff = sbi->total_valid_block_count - avail_user_block_count;
@@ -1760,6 +1796,12 @@
 	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
 	int offset;
 
+	if (is_set_ckpt_flags(sbi, CP_LARGE_NAT_BITMAP_FLAG)) {
+		offset = (flag == SIT_BITMAP) ?
+			le32_to_cpu(ckpt->nat_ver_bitmap_bytesize) : 0;
+		return &ckpt->sit_nat_version_bitmap + offset;
+	}
+
 	if (__cp_payload(sbi) > 0) {
 		if (flag == NAT_BITMAP)
 			return &ckpt->sit_nat_version_bitmap;
@@ -1825,8 +1867,8 @@
 	valid_block_count = sbi->total_valid_block_count +
 					sbi->current_reserved_blocks + 1;
 
-	if (!__allow_reserved_blocks(sbi, inode))
-		valid_block_count += sbi->root_reserved_blocks;
+	if (!__allow_reserved_blocks(sbi, inode, false))
+		valid_block_count += F2FS_OPTION(sbi).root_reserved_blocks;
 
 	if (unlikely(valid_block_count > sbi->user_block_count)) {
 		spin_unlock(&sbi->stat_lock);
@@ -2428,7 +2470,17 @@
 	}
 	if (!is_inode_flag_set(inode, FI_AUTO_RECOVER) ||
 			file_keep_isize(inode) ||
-			i_size_read(inode) & PAGE_MASK)
+			i_size_read(inode) & ~PAGE_MASK)
+		return false;
+
+	if (!timespec_equal(F2FS_I(inode)->i_disk_time, &inode->i_atime))
+		return false;
+	if (!timespec_equal(F2FS_I(inode)->i_disk_time + 1, &inode->i_ctime))
+		return false;
+	if (!timespec_equal(F2FS_I(inode)->i_disk_time + 2, &inode->i_mtime))
+		return false;
+	if (!timespec_equal(F2FS_I(inode)->i_disk_time + 3,
+						&F2FS_I(inode)->i_crtime))
 		return false;
 
 	down_read(&F2FS_I(inode)->i_sem);
@@ -2438,8 +2490,7 @@
 	return ret;
 }
 
-#define sb_rdonly	f2fs_readonly
-static inline int f2fs_readonly(struct super_block *sb)
+static inline bool f2fs_readonly(struct super_block *sb)
 {
 	return sb->s_flags & MS_RDONLY;
 }
@@ -2501,15 +2552,6 @@
 	return ret;
 }
 
-enum rw_hint {
-	WRITE_LIFE_NOT_SET	= 0,
-	WRITE_LIFE_NONE		= 1, /* RWH_WRITE_LIFE_NONE */
-	WRITE_LIFE_SHORT	= 2, /* RWH_WRITE_LIFE_SHORT */
-	WRITE_LIFE_MEDIUM	= 3, /* RWH_WRITE_LIFE_MEDIUM */
-	WRITE_LIFE_LONG		= 4, /* RWH_WRITE_LIFE_LONG */
-	WRITE_LIFE_EXTREME	= 5, /* RWH_WRITE_LIFE_EXTREME */
-};
-
 static inline int wbc_to_write_flags(struct writeback_control *wbc)
 {
 	if (wbc->sync_mode == WB_SYNC_ALL)
@@ -2628,6 +2670,8 @@
 /*
  * namei.c
  */
+int update_extension_list(struct f2fs_sb_info *sbi, const char *name,
+							bool hot, bool set);
 struct dentry *f2fs_get_parent(struct dentry *child);
 
 /*
@@ -2800,6 +2844,8 @@
 int __init create_segment_manager_caches(void);
 void destroy_segment_manager_caches(void);
 int rw_hint_to_seg_type(enum rw_hint hint);
+enum rw_hint io_type_to_rw_hint(struct f2fs_sb_info *sbi, enum page_type type,
+				enum temp_type temp);
 
 /*
  * checkpoint.c
@@ -2840,6 +2886,8 @@
 /*
  * data.c
  */
+int f2fs_init_post_read_processing(void);
+void f2fs_destroy_post_read_processing(void);
 void f2fs_submit_merged_write(struct f2fs_sb_info *sbi, enum page_type type);
 void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi,
 				struct inode *inode, nid_t ino, pgoff_t idx,
@@ -2871,7 +2919,6 @@
 			u64 start, u64 len);
 bool should_update_inplace(struct inode *inode, struct f2fs_io_info *fio);
 bool should_update_outplace(struct inode *inode, struct f2fs_io_info *fio);
-void f2fs_set_page_dirty_nobuffers(struct page *page);
 int __f2fs_write_data_pages(struct address_space *mapping,
 						struct writeback_control *wbc,
 						enum iostat_type io_type);
@@ -2882,6 +2929,7 @@
 int f2fs_migrate_page(struct address_space *mapping, struct page *newpage,
 			struct page *page, enum migrate_mode mode);
 #endif
+bool f2fs_overwrite_io(struct inode *inode, loff_t pos, size_t len);
 
 /*
  * gc.c
@@ -3199,50 +3247,30 @@
 #endif
 }
 
-static inline bool f2fs_bio_encrypted(struct bio *bio)
+/*
+ * Returns true if the reads of the inode's data need to undergo some
+ * postprocessing step, like decryption or authenticity verification.
+ */
+static inline bool f2fs_post_read_required(struct inode *inode)
 {
-	return bio->bi_private != NULL;
+	return f2fs_encrypted_file(inode);
 }
 
-static inline int f2fs_sb_has_crypto(struct super_block *sb)
-{
-	return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_ENCRYPT);
+#define F2FS_FEATURE_FUNCS(name, flagname) \
+static inline int f2fs_sb_has_##name(struct super_block *sb) \
+{ \
+	return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_##flagname); \
 }
 
-static inline int f2fs_sb_mounted_blkzoned(struct super_block *sb)
-{
-	return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_BLKZONED);
-}
-
-static inline int f2fs_sb_has_extra_attr(struct super_block *sb)
-{
-	return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_EXTRA_ATTR);
-}
-
-static inline int f2fs_sb_has_project_quota(struct super_block *sb)
-{
-	return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_PRJQUOTA);
-}
-
-static inline int f2fs_sb_has_inode_chksum(struct super_block *sb)
-{
-	return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_INODE_CHKSUM);
-}
-
-static inline int f2fs_sb_has_flexible_inline_xattr(struct super_block *sb)
-{
-	return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_FLEXIBLE_INLINE_XATTR);
-}
-
-static inline int f2fs_sb_has_quota_ino(struct super_block *sb)
-{
-	return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_QUOTA_INO);
-}
-
-static inline int f2fs_sb_has_inode_crtime(struct super_block *sb)
-{
-	return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_INODE_CRTIME);
-}
+F2FS_FEATURE_FUNCS(encrypt, ENCRYPT);
+F2FS_FEATURE_FUNCS(blkzoned, BLKZONED);
+F2FS_FEATURE_FUNCS(extra_attr, EXTRA_ATTR);
+F2FS_FEATURE_FUNCS(project_quota, PRJQUOTA);
+F2FS_FEATURE_FUNCS(inode_chksum, INODE_CHKSUM);
+F2FS_FEATURE_FUNCS(flexible_inline_xattr, FLEXIBLE_INLINE_XATTR);
+F2FS_FEATURE_FUNCS(quota_ino, QUOTA_INO);
+F2FS_FEATURE_FUNCS(inode_crtime, INODE_CRTIME);
+F2FS_FEATURE_FUNCS(lost_found, LOST_FOUND);
 
 #ifdef CONFIG_BLK_DEV_ZONED
 static inline int get_blkz_type(struct f2fs_sb_info *sbi,
@@ -3262,7 +3290,7 @@
 {
 	struct request_queue *q = bdev_get_queue(sbi->sb->s_bdev);
 
-	return blk_queue_discard(q) || f2fs_sb_mounted_blkzoned(sbi->sb);
+	return blk_queue_discard(q) || f2fs_sb_has_blkzoned(sbi->sb);
 }
 
 static inline void set_opt_mode(struct f2fs_sb_info *sbi, unsigned int mt)
@@ -3291,4 +3319,11 @@
 #endif
 }
 
+static inline bool f2fs_force_buffered_io(struct inode *inode, int rw)
+{
+	return (f2fs_post_read_required(inode) ||
+			(rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) ||
+			F2FS_I_SB(inode)->s_ndevs);
+}
+
 #endif
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index b926df7..0e39c77 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -112,8 +112,8 @@
 	/* fill the page */
 	f2fs_wait_on_page_writeback(page, DATA, false);
 
-	/* wait for GCed encrypted page writeback */
-	if (f2fs_encrypted_file(inode))
+	/* wait for GCed page writeback via META_MAPPING */
+	if (f2fs_post_read_required(inode))
 		f2fs_wait_on_block_writeback(sbi, dn.data_blkaddr);
 
 out_sem:
@@ -165,9 +165,10 @@
 		cp_reason = CP_NODE_NEED_CP;
 	else if (test_opt(sbi, FASTBOOT))
 		cp_reason = CP_FASTBOOT_MODE;
-	else if (sbi->active_logs == 2)
+	else if (F2FS_OPTION(sbi).active_logs == 2)
 		cp_reason = CP_SPEC_LOG_NUM;
-	else if (need_dentry_mark(sbi, inode->i_ino) &&
+	else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT &&
+		need_dentry_mark(sbi, inode->i_ino) &&
 		exist_written_data(sbi, F2FS_I(inode)->i_pino, TRANS_DIR_INO))
 		cp_reason = CP_RECOVER_DIR;
 
@@ -480,6 +481,9 @@
 
 	if (err)
 		return err;
+
+	filp->f_mode |= FMODE_NOWAIT;
+
 	return dquot_file_open(inode, filp);
 }
 
@@ -570,7 +574,6 @@
 int truncate_blocks(struct inode *inode, u64 from, bool lock)
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-	unsigned int blocksize = inode->i_sb->s_blocksize;
 	struct dnode_of_data dn;
 	pgoff_t free_from;
 	int count = 0, err = 0;
@@ -579,7 +582,7 @@
 
 	trace_f2fs_truncate_blocks_enter(inode, from);
 
-	free_from = (pgoff_t)F2FS_BYTES_TO_BLK(from + blocksize - 1);
+	free_from = (pgoff_t)F2FS_BLK_ALIGN(from);
 
 	if (free_from >= sbi->max_file_blocks)
 		goto free_partial;
@@ -1350,8 +1353,12 @@
 	}
 
 out:
-	if (!(mode & FALLOC_FL_KEEP_SIZE) && i_size_read(inode) < new_size)
-		f2fs_i_size_write(inode, new_size);
+	if (new_size > i_size_read(inode)) {
+		if (mode & FALLOC_FL_KEEP_SIZE)
+			file_set_keep_isize(inode);
+		else
+			f2fs_i_size_write(inode, new_size);
+	}
 out_sem:
 	up_write(&F2FS_I(inode)->i_mmap_sem);
 
@@ -1705,6 +1712,8 @@
 
 	inode_lock(inode);
 
+	down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
+
 	if (f2fs_is_volatile_file(inode))
 		goto err_out;
 
@@ -1723,6 +1732,7 @@
 		ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 1, false);
 	}
 err_out:
+	up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
 	inode_unlock(inode);
 	mnt_drop_write_file(filp);
 	return ret;
@@ -1932,7 +1942,7 @@
 {
 	struct inode *inode = file_inode(filp);
 
-	if (!f2fs_sb_has_crypto(inode->i_sb))
+	if (!f2fs_sb_has_encrypt(inode->i_sb))
 		return -EOPNOTSUPP;
 
 	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
@@ -1942,7 +1952,7 @@
 
 static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg)
 {
-	if (!f2fs_sb_has_crypto(file_inode(filp)->i_sb))
+	if (!f2fs_sb_has_encrypt(file_inode(filp)->i_sb))
 		return -EOPNOTSUPP;
 	return fscrypt_ioctl_get_policy(filp, (void __user *)arg);
 }
@@ -1953,16 +1963,18 @@
 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
 	int err;
 
-	if (!f2fs_sb_has_crypto(inode->i_sb))
+	if (!f2fs_sb_has_encrypt(inode->i_sb))
 		return -EOPNOTSUPP;
 
-	if (uuid_is_nonzero(sbi->raw_super->encrypt_pw_salt))
-		goto got_it;
-
 	err = mnt_want_write_file(filp);
 	if (err)
 		return err;
 
+	down_write(&sbi->sb_lock);
+
+	if (uuid_is_nonzero(sbi->raw_super->encrypt_pw_salt))
+		goto got_it;
+
 	/* update superblock with uuid */
 	generate_random_uuid(sbi->raw_super->encrypt_pw_salt);
 
@@ -1970,15 +1982,16 @@
 	if (err) {
 		/* undo new data */
 		memset(sbi->raw_super->encrypt_pw_salt, 0, 16);
-		mnt_drop_write_file(filp);
-		return err;
+		goto out_err;
 	}
-	mnt_drop_write_file(filp);
 got_it:
 	if (copy_to_user((__u8 __user *)arg, sbi->raw_super->encrypt_pw_salt,
 									16))
-		return -EFAULT;
-	return 0;
+		err = -EFAULT;
+out_err:
+	up_write(&sbi->sb_lock);
+	mnt_drop_write_file(filp);
+	return err;
 }
 
 static int f2fs_ioc_gc(struct file *filp, unsigned long arg)
@@ -2039,8 +2052,10 @@
 		return ret;
 
 	end = range.start + range.len;
-	if (range.start < MAIN_BLKADDR(sbi) || end >= MAX_BLKADDR(sbi))
-		return -EINVAL;
+	if (range.start < MAIN_BLKADDR(sbi) || end >= MAX_BLKADDR(sbi)) {
+		ret = -EINVAL;
+		goto out;
+	}
 do_more:
 	if (!range.sync) {
 		if (!mutex_trylock(&sbi->gc_mutex)) {
@@ -2681,25 +2696,54 @@
 	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
 		return -EIO;
 
-	inode_lock(inode);
+	if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT))
+		return -EINVAL;
+
+	if (!inode_trylock(inode)) {
+		if (iocb->ki_flags & IOCB_NOWAIT)
+			return -EAGAIN;
+		inode_lock(inode);
+	}
+
 	ret = generic_write_checks(iocb, from);
 	if (ret > 0) {
+		bool preallocated = false;
+		size_t target_size = 0;
 		int err;
 
 		if (iov_iter_fault_in_readable(from, iov_iter_count(from)))
 			set_inode_flag(inode, FI_NO_PREALLOC);
 
-		err = f2fs_preallocate_blocks(iocb, from);
-		if (err) {
-			clear_inode_flag(inode, FI_NO_PREALLOC);
-			inode_unlock(inode);
-			return err;
+		if ((iocb->ki_flags & IOCB_NOWAIT) &&
+			(iocb->ki_flags & IOCB_DIRECT)) {
+				if (!f2fs_overwrite_io(inode, iocb->ki_pos,
+						iov_iter_count(from)) ||
+					f2fs_has_inline_data(inode) ||
+					f2fs_force_buffered_io(inode, WRITE)) {
+						inode_unlock(inode);
+						return -EAGAIN;
+				}
+
+		} else {
+			preallocated = true;
+			target_size = iocb->ki_pos + iov_iter_count(from);
+
+			err = f2fs_preallocate_blocks(iocb, from);
+			if (err) {
+				clear_inode_flag(inode, FI_NO_PREALLOC);
+				inode_unlock(inode);
+				return err;
+			}
 		}
 		blk_start_plug(&plug);
 		ret = __generic_file_write_iter(iocb, from);
 		blk_finish_plug(&plug);
 		clear_inode_flag(inode, FI_NO_PREALLOC);
 
+		/* if we couldn't write data, we should deallocate blocks. */
+		if (preallocated && i_size_read(inode) < target_size)
+			f2fs_truncate(inode);
+
 		if (ret > 0)
 			f2fs_update_iostat(F2FS_I_SB(inode), APP_WRITE_IO, ret);
 	}
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 3b26aa1..604d3fc 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -76,14 +76,15 @@
 		 * invalidated soon after by user update or deletion.
 		 * So, I'd like to wait some time to collect dirty segments.
 		 */
-		if (!mutex_trylock(&sbi->gc_mutex))
-			goto next;
-
 		if (gc_th->gc_urgent) {
 			wait_ms = gc_th->urgent_sleep_time;
+			mutex_lock(&sbi->gc_mutex);
 			goto do_gc;
 		}
 
+		if (!mutex_trylock(&sbi->gc_mutex))
+			goto next;
+
 		if (!is_idle(sbi)) {
 			increase_sleep_time(gc_th, &wait_ms);
 			mutex_unlock(&sbi->gc_mutex);
@@ -161,12 +162,17 @@
 {
 	int gc_mode = (gc_type == BG_GC) ? GC_CB : GC_GREEDY;
 
-	if (gc_th && gc_th->gc_idle) {
+	if (!gc_th)
+		return gc_mode;
+
+	if (gc_th->gc_idle) {
 		if (gc_th->gc_idle == 1)
 			gc_mode = GC_CB;
 		else if (gc_th->gc_idle == 2)
 			gc_mode = GC_GREEDY;
 	}
+	if (gc_th->gc_urgent)
+		gc_mode = GC_GREEDY;
 	return gc_mode;
 }
 
@@ -188,11 +194,14 @@
 	}
 
 	/* we need to check every dirty segments in the FG_GC case */
-	if (gc_type != FG_GC && p->max_search > sbi->max_victim_search)
+	if (gc_type != FG_GC &&
+			(sbi->gc_thread && !sbi->gc_thread->gc_urgent) &&
+			p->max_search > sbi->max_victim_search)
 		p->max_search = sbi->max_victim_search;
 
-	/* let's select beginning hot/small space first */
-	if (type == CURSEG_HOT_DATA || IS_NODESEG(type))
+	/* let's select beginning hot/small space first in no_heap mode*/
+	if (test_opt(sbi, NOHEAP) &&
+		(type == CURSEG_HOT_DATA || IS_NODESEG(type)))
 		p->offset = 0;
 	else
 		p->offset = SIT_I(sbi)->last_victim[p->gc_mode];
@@ -841,8 +850,8 @@
 			if (IS_ERR(inode) || is_bad_inode(inode))
 				continue;
 
-			/* if encrypted inode, let's go phase 3 */
-			if (f2fs_encrypted_file(inode)) {
+			/* if inode uses special I/O path, let's go phase 3 */
+			if (f2fs_post_read_required(inode)) {
 				add_gc_inode(gc_list, inode);
 				continue;
 			}
@@ -890,7 +899,7 @@
 
 			start_bidx = start_bidx_of_node(nofs, inode)
 								+ ofs_in_node;
-			if (f2fs_encrypted_file(inode))
+			if (f2fs_post_read_required(inode))
 				move_data_block(inode, start_bidx, segno, off);
 			else
 				move_data_page(inode, start_bidx, gc_type,
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index 1925814..26832e7 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -26,7 +26,7 @@
 	if (i_size_read(inode) > MAX_INLINE_DATA(inode))
 		return false;
 
-	if (f2fs_encrypted_file(inode))
+	if (f2fs_post_read_required(inode))
 		return false;
 
 	return true;
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 10be247..e0d9e8f 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -284,6 +284,10 @@
 		fi->i_crtime.tv_nsec = le32_to_cpu(ri->i_crtime_nsec);
 	}
 
+	F2FS_I(inode)->i_disk_time[0] = inode->i_atime;
+	F2FS_I(inode)->i_disk_time[1] = inode->i_ctime;
+	F2FS_I(inode)->i_disk_time[2] = inode->i_mtime;
+	F2FS_I(inode)->i_disk_time[3] = F2FS_I(inode)->i_crtime;
 	f2fs_put_page(node_page, 1);
 
 	stat_inc_inline_xattr(inode);
@@ -439,12 +443,15 @@
 	}
 
 	__set_inode_rdev(inode, ri);
-	set_cold_node(inode, node_page);
 
 	/* deleted inode */
 	if (inode->i_nlink == 0)
 		clear_inline_node(node_page);
 
+	F2FS_I(inode)->i_disk_time[0] = inode->i_atime;
+	F2FS_I(inode)->i_disk_time[1] = inode->i_ctime;
+	F2FS_I(inode)->i_disk_time[2] = inode->i_mtime;
+	F2FS_I(inode)->i_disk_time[3] = F2FS_I(inode)->i_crtime;
 }
 
 void update_inode_page(struct inode *inode)
@@ -585,7 +592,7 @@
 			!exist_written_data(sbi, inode->i_ino, ORPHAN_INO));
 	}
 out_clear:
-	fscrypt_put_encryption_info(inode, NULL);
+	fscrypt_put_encryption_info(inode);
 	clear_inode(inode);
 }
 
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index 59e8dca..392d1ed 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -78,7 +78,8 @@
 	set_inode_flag(inode, FI_NEW_INODE);
 
 	/* If the directory encrypted, then we should encrypt the inode. */
-	if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode))
+	if ((f2fs_encrypted_inode(dir) || DUMMY_ENCRYPTION_ENABLED(sbi)) &&
+				f2fs_may_encrypt(inode))
 		f2fs_set_encrypted_inode(inode);
 
 	if (f2fs_sb_has_extra_attr(sbi->sb)) {
@@ -97,7 +98,7 @@
 	if (f2fs_sb_has_flexible_inline_xattr(sbi->sb)) {
 		f2fs_bug_on(sbi, !f2fs_has_extra_attr(inode));
 		if (f2fs_has_inline_xattr(inode))
-			xattr_size = sbi->inline_xattr_size;
+			xattr_size = F2FS_OPTION(sbi).inline_xattr_size;
 		/* Otherwise, will be 0 */
 	} else if (f2fs_has_inline_xattr(inode) ||
 				f2fs_has_inline_dentry(inode)) {
@@ -142,7 +143,7 @@
 	return ERR_PTR(err);
 }
 
-static int is_multimedia_file(const unsigned char *s, const char *sub)
+static int is_extension_exist(const unsigned char *s, const char *sub)
 {
 	size_t slen = strlen(s);
 	size_t sublen = strlen(sub);
@@ -168,19 +169,94 @@
 /*
  * Set multimedia files as cold files for hot/cold data separation
  */
-static inline void set_cold_files(struct f2fs_sb_info *sbi, struct inode *inode,
+static inline void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode,
 		const unsigned char *name)
 {
-	int i;
-	__u8 (*extlist)[8] = sbi->raw_super->extension_list;
+	__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
+	int i, cold_count, hot_count;
 
-	int count = le32_to_cpu(sbi->raw_super->extension_count);
-	for (i = 0; i < count; i++) {
-		if (is_multimedia_file(name, extlist[i])) {
+	down_read(&sbi->sb_lock);
+
+	cold_count = le32_to_cpu(sbi->raw_super->extension_count);
+	hot_count = sbi->raw_super->hot_ext_count;
+
+	for (i = 0; i < cold_count + hot_count; i++) {
+		if (!is_extension_exist(name, extlist[i]))
+			continue;
+		if (i < cold_count)
 			file_set_cold(inode);
-			break;
-		}
+		else
+			file_set_hot(inode);
+		break;
 	}
+
+	up_read(&sbi->sb_lock);
+}
+
+int update_extension_list(struct f2fs_sb_info *sbi, const char *name,
+							bool hot, bool set)
+{
+	__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
+	int cold_count = le32_to_cpu(sbi->raw_super->extension_count);
+	int hot_count = sbi->raw_super->hot_ext_count;
+	int total_count = cold_count + hot_count;
+	int start, count;
+	int i;
+
+	if (set) {
+		if (total_count == F2FS_MAX_EXTENSION)
+			return -EINVAL;
+	} else {
+		if (!hot && !cold_count)
+			return -EINVAL;
+		if (hot && !hot_count)
+			return -EINVAL;
+	}
+
+	if (hot) {
+		start = cold_count;
+		count = total_count;
+	} else {
+		start = 0;
+		count = cold_count;
+	}
+
+	for (i = start; i < count; i++) {
+		if (strcmp(name, extlist[i]))
+			continue;
+
+		if (set)
+			return -EINVAL;
+
+		memcpy(extlist[i], extlist[i + 1],
+				F2FS_EXTENSION_LEN * (total_count - i - 1));
+		memset(extlist[total_count - 1], 0, F2FS_EXTENSION_LEN);
+		if (hot)
+			sbi->raw_super->hot_ext_count = hot_count - 1;
+		else
+			sbi->raw_super->extension_count =
+						cpu_to_le32(cold_count - 1);
+		return 0;
+	}
+
+	if (!set)
+		return -EINVAL;
+
+	if (hot) {
+		strncpy(extlist[count], name, strlen(name));
+		sbi->raw_super->hot_ext_count = hot_count + 1;
+	} else {
+		char buf[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN];
+
+		memcpy(buf, &extlist[cold_count],
+				F2FS_EXTENSION_LEN * hot_count);
+		memset(extlist[cold_count], 0, F2FS_EXTENSION_LEN);
+		strncpy(extlist[cold_count], name, strlen(name));
+		memcpy(&extlist[cold_count + 1], buf,
+				F2FS_EXTENSION_LEN * hot_count);
+		sbi->raw_super->extension_count = cpu_to_le32(cold_count + 1);
+	}
+	return 0;
 }
 
 static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
@@ -203,7 +279,7 @@
 		return PTR_ERR(inode);
 
 	if (!test_opt(sbi, DISABLE_EXT_IDENTIFY))
-		set_cold_files(sbi, inode, dentry->d_name.name);
+		set_file_temperature(sbi, inode, dentry->d_name.name);
 
 	inode->i_op = &f2fs_file_inode_operations;
 	inode->i_fop = &f2fs_file_operations;
@@ -218,8 +294,8 @@
 
 	alloc_nid_done(sbi, ino);
 
-	d_instantiate(dentry, inode);
 	unlock_new_inode(inode);
+	d_instantiate(dentry, inode);
 
 	if (IS_DIRSYNC(dir))
 		f2fs_sync_fs(sbi->sb, 1);
@@ -481,27 +557,16 @@
 	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
 	struct inode *inode;
 	size_t len = strlen(symname);
-	struct fscrypt_str disk_link = FSTR_INIT((char *)symname, len + 1);
-	struct fscrypt_symlink_data *sd = NULL;
+	struct fscrypt_str disk_link;
 	int err;
 
 	if (unlikely(f2fs_cp_error(sbi)))
 		return -EIO;
 
-	if (f2fs_encrypted_inode(dir)) {
-		err = fscrypt_get_encryption_info(dir);
-		if (err)
-			return err;
-
-		if (!fscrypt_has_encryption_key(dir))
-			return -ENOKEY;
-
-		disk_link.len = (fscrypt_fname_encrypted_size(dir, len) +
-				sizeof(struct fscrypt_symlink_data));
-	}
-
-	if (disk_link.len > dir->i_sb->s_blocksize)
-		return -ENAMETOOLONG;
+	err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize,
+				      &disk_link);
+	if (err)
+		return err;
 
 	err = dquot_initialize(dir);
 	if (err)
@@ -511,7 +576,7 @@
 	if (IS_ERR(inode))
 		return PTR_ERR(inode);
 
-	if (f2fs_encrypted_inode(inode))
+	if (IS_ENCRYPTED(inode))
 		inode->i_op = &f2fs_encrypted_symlink_inode_operations;
 	else
 		inode->i_op = &f2fs_symlink_inode_operations;
@@ -521,44 +586,19 @@
 	f2fs_lock_op(sbi);
 	err = f2fs_add_link(dentry, inode);
 	if (err)
-		goto out;
+		goto out_handle_failed_inode;
 	f2fs_unlock_op(sbi);
 	alloc_nid_done(sbi, inode->i_ino);
 
-	if (f2fs_encrypted_inode(inode)) {
-		struct qstr istr = QSTR_INIT(symname, len);
-		struct fscrypt_str ostr;
-
-		sd = f2fs_kzalloc(sbi, disk_link.len, GFP_NOFS);
-		if (!sd) {
-			err = -ENOMEM;
-			goto err_out;
-		}
-
-		err = fscrypt_get_encryption_info(inode);
-		if (err)
-			goto err_out;
-
-		if (!fscrypt_has_encryption_key(inode)) {
-			err = -ENOKEY;
-			goto err_out;
-		}
-
-		ostr.name = sd->encrypted_path;
-		ostr.len = disk_link.len;
-		err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr);
-		if (err)
-			goto err_out;
-
-		sd->len = cpu_to_le16(ostr.len);
-		disk_link.name = (char *)sd;
-	}
+	err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link);
+	if (err)
+		goto err_out;
 
 	err = page_symlink(inode, disk_link.name, disk_link.len);
 
 err_out:
-	d_instantiate(dentry, inode);
 	unlock_new_inode(inode);
+	d_instantiate(dentry, inode);
 
 	/*
 	 * Let's flush symlink data in order to avoid broken symlink as much as
@@ -579,12 +619,14 @@
 		f2fs_unlink(dir, dentry);
 	}
 
-	kfree(sd);
-
 	f2fs_balance_fs(sbi, true);
-	return err;
-out:
+	goto out_free_encrypted_link;
+
+out_handle_failed_inode:
 	handle_failed_inode(inode);
+out_free_encrypted_link:
+	if (disk_link.name != (unsigned char *)symname)
+		kfree(disk_link.name);
 	return err;
 }
 
@@ -619,8 +661,8 @@
 
 	alloc_nid_done(sbi, inode->i_ino);
 
-	d_instantiate(dentry, inode);
 	unlock_new_inode(inode);
+	d_instantiate(dentry, inode);
 
 	if (IS_DIRSYNC(dir))
 		f2fs_sync_fs(sbi->sb, 1);
@@ -671,8 +713,8 @@
 
 	alloc_nid_done(sbi, inode->i_ino);
 
-	d_instantiate(dentry, inode);
 	unlock_new_inode(inode);
+	d_instantiate(dentry, inode);
 
 	if (IS_DIRSYNC(dir))
 		f2fs_sync_fs(sbi->sb, 1);
@@ -746,10 +788,12 @@
 
 static int f2fs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
-	if (unlikely(f2fs_cp_error(F2FS_I_SB(dir))))
+	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
+
+	if (unlikely(f2fs_cp_error(sbi)))
 		return -EIO;
 
-	if (f2fs_encrypted_inode(dir)) {
+	if (f2fs_encrypted_inode(dir) || DUMMY_ENCRYPTION_ENABLED(sbi)) {
 		int err = fscrypt_get_encryption_info(dir);
 		if (err)
 			return err;
@@ -929,7 +973,8 @@
 			f2fs_put_page(old_dir_page, 0);
 		f2fs_i_links_write(old_dir, false);
 	}
-	add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
+	if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT)
+		add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
 
 	f2fs_unlock_op(sbi);
 
@@ -1079,8 +1124,10 @@
 	}
 	f2fs_mark_inode_dirty_sync(new_dir, false);
 
-	add_ino_entry(sbi, old_dir->i_ino, TRANS_DIR_INO);
-	add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
+	if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT) {
+		add_ino_entry(sbi, old_dir->i_ino, TRANS_DIR_INO);
+		add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
+	}
 
 	f2fs_unlock_op(sbi);
 
@@ -1132,68 +1179,20 @@
 					   struct inode *inode,
 					   struct delayed_call *done)
 {
-	struct page *cpage = NULL;
-	char *caddr, *paddr = NULL;
-	struct fscrypt_str cstr = FSTR_INIT(NULL, 0);
-	struct fscrypt_str pstr = FSTR_INIT(NULL, 0);
-	struct fscrypt_symlink_data *sd;
-	u32 max_size = inode->i_sb->s_blocksize;
-	int res;
+	struct page *page;
+	const char *target;
 
 	if (!dentry)
 		return ERR_PTR(-ECHILD);
 
-	res = fscrypt_get_encryption_info(inode);
-	if (res)
-		return ERR_PTR(res);
+	page = read_mapping_page(inode->i_mapping, 0, NULL);
+	if (IS_ERR(page))
+		return ERR_CAST(page);
 
-	cpage = read_mapping_page(inode->i_mapping, 0, NULL);
-	if (IS_ERR(cpage))
-		return ERR_CAST(cpage);
-	caddr = page_address(cpage);
-
-	/* Symlink is encrypted */
-	sd = (struct fscrypt_symlink_data *)caddr;
-	cstr.name = sd->encrypted_path;
-	cstr.len = le16_to_cpu(sd->len);
-
-	/* this is broken symlink case */
-	if (unlikely(cstr.len == 0)) {
-		res = -ENOENT;
-		goto errout;
-	}
-
-	if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) {
-		/* Symlink data on the disk is corrupted */
-		res = -EIO;
-		goto errout;
-	}
-	res = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr);
-	if (res)
-		goto errout;
-
-	res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr);
-	if (res)
-		goto errout;
-
-	/* this is broken symlink case */
-	if (unlikely(pstr.name[0] == 0)) {
-		res = -ENOENT;
-		goto errout;
-	}
-
-	paddr = pstr.name;
-
-	/* Null-terminate the name */
-	paddr[pstr.len] = '\0';
-
-	put_page(cpage);
-	set_delayed_call(done, kfree_link, paddr);
-	return paddr;
-errout:
-	fscrypt_fname_free_buffer(&pstr);
-	put_page(cpage);
-	return ERR_PTR(res);
+	target = fscrypt_get_symlink(inode, page_address(page),
+				     inode->i_sb->s_blocksize, done);
+	put_page(page);
+	return target;
 }
 
 const struct inode_operations f2fs_encrypted_symlink_inode_operations = {
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 7cded84..ccf410a 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -193,8 +193,8 @@
 	__free_nat_entry(e);
 }
 
-static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i,
-						struct nat_entry *ne)
+static struct nat_entry_set *__grab_nat_entry_set(struct f2fs_nm_info *nm_i,
+							struct nat_entry *ne)
 {
 	nid_t set = NAT_BLOCK_OFFSET(ne->ni.nid);
 	struct nat_entry_set *head;
@@ -209,15 +209,36 @@
 		head->entry_cnt = 0;
 		f2fs_radix_tree_insert(&nm_i->nat_set_root, set, head);
 	}
+	return head;
+}
+
+static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i,
+						struct nat_entry *ne)
+{
+	struct nat_entry_set *head;
+	bool new_ne = nat_get_blkaddr(ne) == NEW_ADDR;
+
+	if (!new_ne)
+		head = __grab_nat_entry_set(nm_i, ne);
+
+	/*
+	 * update entry_cnt in below condition:
+	 * 1. update NEW_ADDR to valid block address;
+	 * 2. update old block address to new one;
+	 */
+	if (!new_ne && (get_nat_flag(ne, IS_PREALLOC) ||
+				!get_nat_flag(ne, IS_DIRTY)))
+		head->entry_cnt++;
+
+	set_nat_flag(ne, IS_PREALLOC, new_ne);
 
 	if (get_nat_flag(ne, IS_DIRTY))
 		goto refresh_list;
 
 	nm_i->dirty_nat_cnt++;
-	head->entry_cnt++;
 	set_nat_flag(ne, IS_DIRTY, true);
 refresh_list:
-	if (nat_get_blkaddr(ne) == NEW_ADDR)
+	if (new_ne)
 		list_del_init(&ne->list);
 	else
 		list_move_tail(&ne->list, &head->entry_list);
@@ -1076,7 +1097,7 @@
 
 	f2fs_wait_on_page_writeback(page, NODE, true);
 	fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true);
-	set_cold_node(dn->inode, page);
+	set_cold_node(page, S_ISDIR(dn->inode->i_mode));
 	if (!PageUptodate(page))
 		SetPageUptodate(page);
 	if (set_page_dirty(page))
@@ -1751,7 +1772,7 @@
 	if (!PageUptodate(page))
 		SetPageUptodate(page);
 	if (!PageDirty(page)) {
-		f2fs_set_page_dirty_nobuffers(page);
+		__set_page_dirty_nobuffers(page);
 		inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_NODES);
 		SetPagePrivate(page);
 		f2fs_trace_pid(page);
@@ -2310,6 +2331,7 @@
 	if (!PageUptodate(ipage))
 		SetPageUptodate(ipage);
 	fill_node_footer(ipage, ino, ino, 0, true);
+	set_cold_node(page, false);
 
 	src = F2FS_INODE(page);
 	dst = F2FS_INODE(ipage);
@@ -2599,8 +2621,7 @@
 	if (!enabled_nat_bits(sbi, NULL))
 		return 0;
 
-	nm_i->nat_bits_blocks = F2FS_BYTES_TO_BLK((nat_bits_bytes << 1) + 8 +
-						F2FS_BLKSIZE - 1);
+	nm_i->nat_bits_blocks = F2FS_BLK_ALIGN((nat_bits_bytes << 1) + 8);
 	nm_i->nat_bits = f2fs_kzalloc(sbi,
 			nm_i->nat_bits_blocks << F2FS_BLKSIZE_BITS, GFP_KERNEL);
 	if (!nm_i->nat_bits)
@@ -2726,12 +2747,20 @@
 static int init_free_nid_cache(struct f2fs_sb_info *sbi)
 {
 	struct f2fs_nm_info *nm_i = NM_I(sbi);
+	int i;
 
-	nm_i->free_nid_bitmap = f2fs_kvzalloc(sbi, nm_i->nat_blocks *
-					NAT_ENTRY_BITMAP_SIZE, GFP_KERNEL);
+	nm_i->free_nid_bitmap = f2fs_kzalloc(sbi, nm_i->nat_blocks *
+				sizeof(unsigned char *), GFP_KERNEL);
 	if (!nm_i->free_nid_bitmap)
 		return -ENOMEM;
 
+	for (i = 0; i < nm_i->nat_blocks; i++) {
+		nm_i->free_nid_bitmap[i] = f2fs_kvzalloc(sbi,
+				NAT_ENTRY_BITMAP_SIZE_ALIGNED, GFP_KERNEL);
+		if (!nm_i->free_nid_bitmap)
+			return -ENOMEM;
+	}
+
 	nm_i->nat_block_bitmap = f2fs_kvzalloc(sbi, nm_i->nat_blocks / 8,
 								GFP_KERNEL);
 	if (!nm_i->nat_block_bitmap)
@@ -2822,7 +2851,13 @@
 	up_write(&nm_i->nat_tree_lock);
 
 	kvfree(nm_i->nat_block_bitmap);
-	kvfree(nm_i->free_nid_bitmap);
+	if (nm_i->free_nid_bitmap) {
+		int i;
+
+		for (i = 0; i < nm_i->nat_blocks; i++)
+			kvfree(nm_i->free_nid_bitmap[i]);
+		kfree(nm_i->free_nid_bitmap);
+	}
 	kvfree(nm_i->free_nid_count);
 
 	kfree(nm_i->nat_bitmap);
diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h
index 081ef0d..b95e49e 100644
--- a/fs/f2fs/node.h
+++ b/fs/f2fs/node.h
@@ -44,6 +44,7 @@
 	HAS_FSYNCED_INODE,	/* is the inode fsynced before? */
 	HAS_LAST_FSYNC,		/* has the latest node fsync mark? */
 	IS_DIRTY,		/* this nat entry is dirty? */
+	IS_PREALLOC,		/* nat entry is preallocated */
 };
 
 /*
@@ -422,12 +423,12 @@
 	ClearPageChecked(page);
 }
 
-static inline void set_cold_node(struct inode *inode, struct page *page)
+static inline void set_cold_node(struct page *page, bool is_dir)
 {
 	struct f2fs_node *rn = F2FS_NODE(page);
 	unsigned int flag = le32_to_cpu(rn->footer.flag);
 
-	if (S_ISDIR(inode->i_mode))
+	if (is_dir)
 		flag &= ~(0x1 << COLD_BIT_SHIFT);
 	else
 		flag |= (0x1 << COLD_BIT_SHIFT);
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
index 210de28..4ddc226 100644
--- a/fs/f2fs/recovery.c
+++ b/fs/f2fs/recovery.c
@@ -242,6 +242,9 @@
 	struct curseg_info *curseg;
 	struct page *page = NULL;
 	block_t blkaddr;
+	unsigned int loop_cnt = 0;
+	unsigned int free_blocks = sbi->user_block_count -
+					valid_user_blocks(sbi);
 	int err = 0;
 
 	/* get node pages in the current segment */
@@ -294,6 +297,17 @@
 		if (IS_INODE(page) && is_dent_dnode(page))
 			entry->last_dentry = blkaddr;
 next:
+		/* sanity check in order to detect looped node chain */
+		if (++loop_cnt >= free_blocks ||
+			blkaddr == next_blkaddr_of_node(page)) {
+			f2fs_msg(sbi->sb, KERN_NOTICE,
+				"%s: detect looped node chain, "
+				"blkaddr:%u, next:%u",
+				__func__, blkaddr, next_blkaddr_of_node(page));
+			err = -EINVAL;
+			break;
+		}
+
 		/* check next segment */
 		blkaddr = next_blkaddr_of_node(page);
 		f2fs_put_page(page, 1);
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index cc34d88..fc4ee38 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -1411,12 +1411,11 @@
 		if (kthread_should_stop())
 			return 0;
 
-		if (dcc->discard_wake) {
+		if (dcc->discard_wake)
 			dcc->discard_wake = 0;
-			if (sbi->gc_thread && sbi->gc_thread->gc_urgent)
-				init_discard_policy(&dpolicy,
-							DPOLICY_FORCE, 1);
-		}
+
+		if (sbi->gc_thread && sbi->gc_thread->gc_urgent)
+			init_discard_policy(&dpolicy, DPOLICY_FORCE, 1);
 
 		sb_start_intwrite(sbi->sb);
 
@@ -1485,7 +1484,7 @@
 		struct block_device *bdev, block_t blkstart, block_t blklen)
 {
 #ifdef CONFIG_BLK_DEV_ZONED
-	if (f2fs_sb_mounted_blkzoned(sbi->sb) &&
+	if (f2fs_sb_has_blkzoned(sbi->sb) &&
 				bdev_zoned_model(bdev) != BLK_ZONED_NONE)
 		return __f2fs_issue_discard_zone(sbi, bdev, blkstart, blklen);
 #endif
@@ -1683,7 +1682,7 @@
 					sbi->blocks_per_seg, cur_pos);
 			len = next_pos - cur_pos;
 
-			if (f2fs_sb_mounted_blkzoned(sbi->sb) ||
+			if (f2fs_sb_has_blkzoned(sbi->sb) ||
 			    (force && len < cpc->trim_minlen))
 				goto skip;
 
@@ -1727,7 +1726,7 @@
 	} else if (discard_type == DPOLICY_FORCE) {
 		dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME;
 		dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME;
-		dpolicy->io_aware = true;
+		dpolicy->io_aware = false;
 	} else if (discard_type == DPOLICY_FSTRIM) {
 		dpolicy->io_aware = false;
 	} else if (discard_type == DPOLICY_UMOUNT) {
@@ -1863,7 +1862,7 @@
 			sbi->discard_blks--;
 
 		/* don't overwrite by SSR to keep node chain */
-		if (se->type == CURSEG_WARM_NODE) {
+		if (IS_NODESEG(se->type)) {
 			if (!f2fs_test_and_set_bit(offset, se->ckpt_valid_map))
 				se->ckpt_valid_blocks++;
 		}
@@ -2164,11 +2163,17 @@
 	if (sbi->segs_per_sec != 1)
 		return CURSEG_I(sbi, type)->segno;
 
-	if (type == CURSEG_HOT_DATA || IS_NODESEG(type))
+	if (test_opt(sbi, NOHEAP) &&
+		(type == CURSEG_HOT_DATA || IS_NODESEG(type)))
 		return 0;
 
 	if (SIT_I(sbi)->last_victim[ALLOC_NEXT])
 		return SIT_I(sbi)->last_victim[ALLOC_NEXT];
+
+	/* find segments from 0 to reuse freed segments */
+	if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_REUSE)
+		return 0;
+
 	return CURSEG_I(sbi, type)->segno;
 }
 
@@ -2455,6 +2460,101 @@
 	}
 }
 
+/* This returns write hints for each segment type. This hints will be
+ * passed down to block layer. There are mapping tables which depend on
+ * the mount option 'whint_mode'.
+ *
+ * 1) whint_mode=off. F2FS only passes down WRITE_LIFE_NOT_SET.
+ *
+ * 2) whint_mode=user-based. F2FS tries to pass down hints given by users.
+ *
+ * User                  F2FS                     Block
+ * ----                  ----                     -----
+ *                       META                     WRITE_LIFE_NOT_SET
+ *                       HOT_NODE                 "
+ *                       WARM_NODE                "
+ *                       COLD_NODE                "
+ * ioctl(COLD)           COLD_DATA                WRITE_LIFE_EXTREME
+ * extension list        "                        "
+ *
+ * -- buffered io
+ * WRITE_LIFE_EXTREME    COLD_DATA                WRITE_LIFE_EXTREME
+ * WRITE_LIFE_SHORT      HOT_DATA                 WRITE_LIFE_SHORT
+ * WRITE_LIFE_NOT_SET    WARM_DATA                WRITE_LIFE_NOT_SET
+ * WRITE_LIFE_NONE       "                        "
+ * WRITE_LIFE_MEDIUM     "                        "
+ * WRITE_LIFE_LONG       "                        "
+ *
+ * -- direct io
+ * WRITE_LIFE_EXTREME    COLD_DATA                WRITE_LIFE_EXTREME
+ * WRITE_LIFE_SHORT      HOT_DATA                 WRITE_LIFE_SHORT
+ * WRITE_LIFE_NOT_SET    WARM_DATA                WRITE_LIFE_NOT_SET
+ * WRITE_LIFE_NONE       "                        WRITE_LIFE_NONE
+ * WRITE_LIFE_MEDIUM     "                        WRITE_LIFE_MEDIUM
+ * WRITE_LIFE_LONG       "                        WRITE_LIFE_LONG
+ *
+ * 3) whint_mode=fs-based. F2FS passes down hints with its policy.
+ *
+ * User                  F2FS                     Block
+ * ----                  ----                     -----
+ *                       META                     WRITE_LIFE_MEDIUM;
+ *                       HOT_NODE                 WRITE_LIFE_NOT_SET
+ *                       WARM_NODE                "
+ *                       COLD_NODE                WRITE_LIFE_NONE
+ * ioctl(COLD)           COLD_DATA                WRITE_LIFE_EXTREME
+ * extension list        "                        "
+ *
+ * -- buffered io
+ * WRITE_LIFE_EXTREME    COLD_DATA                WRITE_LIFE_EXTREME
+ * WRITE_LIFE_SHORT      HOT_DATA                 WRITE_LIFE_SHORT
+ * WRITE_LIFE_NOT_SET    WARM_DATA                WRITE_LIFE_LONG
+ * WRITE_LIFE_NONE       "                        "
+ * WRITE_LIFE_MEDIUM     "                        "
+ * WRITE_LIFE_LONG       "                        "
+ *
+ * -- direct io
+ * WRITE_LIFE_EXTREME    COLD_DATA                WRITE_LIFE_EXTREME
+ * WRITE_LIFE_SHORT      HOT_DATA                 WRITE_LIFE_SHORT
+ * WRITE_LIFE_NOT_SET    WARM_DATA                WRITE_LIFE_NOT_SET
+ * WRITE_LIFE_NONE       "                        WRITE_LIFE_NONE
+ * WRITE_LIFE_MEDIUM     "                        WRITE_LIFE_MEDIUM
+ * WRITE_LIFE_LONG       "                        WRITE_LIFE_LONG
+ */
+
+enum rw_hint io_type_to_rw_hint(struct f2fs_sb_info *sbi,
+				enum page_type type, enum temp_type temp)
+{
+	if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_USER) {
+		if (type == DATA) {
+			if (temp == WARM)
+				return WRITE_LIFE_NOT_SET;
+			else if (temp == HOT)
+				return WRITE_LIFE_SHORT;
+			else if (temp == COLD)
+				return WRITE_LIFE_EXTREME;
+		} else {
+			return WRITE_LIFE_NOT_SET;
+		}
+	} else if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_FS) {
+		if (type == DATA) {
+			if (temp == WARM)
+				return WRITE_LIFE_LONG;
+			else if (temp == HOT)
+				return WRITE_LIFE_SHORT;
+			else if (temp == COLD)
+				return WRITE_LIFE_EXTREME;
+		} else if (type == NODE) {
+			if (temp == WARM || temp == HOT)
+				return WRITE_LIFE_NOT_SET;
+			else if (temp == COLD)
+				return WRITE_LIFE_NONE;
+		} else if (type == META) {
+			return WRITE_LIFE_MEDIUM;
+		}
+	}
+	return WRITE_LIFE_NOT_SET;
+}
+
 static int __get_segment_type_2(struct f2fs_io_info *fio)
 {
 	if (fio->type == DATA)
@@ -2487,7 +2587,8 @@
 
 		if (is_cold_data(fio->page) || file_is_cold(inode))
 			return CURSEG_COLD_DATA;
-		if (is_inode_flag_set(inode, FI_HOT_DATA))
+		if (file_is_hot(inode) ||
+				is_inode_flag_set(inode, FI_HOT_DATA))
 			return CURSEG_HOT_DATA;
 		/* rw_hint_to_seg_type(inode->i_write_hint); */
 		return CURSEG_WARM_DATA;
@@ -2503,7 +2604,7 @@
 {
 	int type = 0;
 
-	switch (fio->sbi->active_logs) {
+	switch (F2FS_OPTION(fio->sbi).active_logs) {
 	case 2:
 		type = __get_segment_type_2(fio);
 		break;
@@ -2643,6 +2744,7 @@
 	struct f2fs_io_info fio = {
 		.sbi = sbi,
 		.type = META,
+		.temp = HOT,
 		.op = REQ_OP_WRITE,
 		.op_flags = REQ_SYNC | REQ_META | REQ_PRIO,
 		.old_blkaddr = page->index,
@@ -2689,8 +2791,15 @@
 int rewrite_data_page(struct f2fs_io_info *fio)
 {
 	int err;
+	struct f2fs_sb_info *sbi = fio->sbi;
 
 	fio->new_blkaddr = fio->old_blkaddr;
+	/* i/o temperature is needed for passing down write hints */
+	__get_segment_type(fio);
+
+	f2fs_bug_on(sbi, !IS_DATASEG(get_seg_entry(sbi,
+			GET_SEGNO(sbi, fio->new_blkaddr))->type));
+
 	stat_inc_inplace_blocks(fio->sbi);
 
 	err = f2fs_submit_page_bio(fio);
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
index f11c4bc..3325d07 100644
--- a/fs/f2fs/segment.h
+++ b/fs/f2fs/segment.h
@@ -53,13 +53,19 @@
 	 ((secno) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno /		\
 	  (sbi)->segs_per_sec))	\
 
-#define MAIN_BLKADDR(sbi)	(SM_I(sbi)->main_blkaddr)
-#define SEG0_BLKADDR(sbi)	(SM_I(sbi)->seg0_blkaddr)
+#define MAIN_BLKADDR(sbi)						\
+	(SM_I(sbi) ? SM_I(sbi)->main_blkaddr : 				\
+		le32_to_cpu(F2FS_RAW_SUPER(sbi)->main_blkaddr))
+#define SEG0_BLKADDR(sbi)						\
+	(SM_I(sbi) ? SM_I(sbi)->seg0_blkaddr : 				\
+		le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment0_blkaddr))
 
 #define MAIN_SEGS(sbi)	(SM_I(sbi)->main_segments)
 #define MAIN_SECS(sbi)	((sbi)->total_sections)
 
-#define TOTAL_SEGS(sbi)	(SM_I(sbi)->segment_count)
+#define TOTAL_SEGS(sbi)							\
+	(SM_I(sbi) ? SM_I(sbi)->segment_count : 				\
+		le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count))
 #define TOTAL_BLKS(sbi)	(TOTAL_SEGS(sbi) << (sbi)->log_blocks_per_seg)
 
 #define MAX_BLKADDR(sbi)	(SEG0_BLKADDR(sbi) + TOTAL_BLKS(sbi))
@@ -596,6 +602,8 @@
 #define DEF_MIN_FSYNC_BLOCKS	8
 #define DEF_MIN_HOT_BLOCKS	16
 
+#define SMALL_VOLUME_SEGMENTS	(16 * 512)	/* 16GB */
+
 enum {
 	F2FS_IPU_FORCE,
 	F2FS_IPU_SSR,
@@ -630,10 +638,17 @@
 	f2fs_bug_on(sbi, segno > TOTAL_SEGS(sbi) - 1);
 }
 
-static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr)
+static inline void verify_block_addr(struct f2fs_io_info *fio, block_t blk_addr)
 {
-	BUG_ON(blk_addr < SEG0_BLKADDR(sbi)
-			|| blk_addr >= MAX_BLKADDR(sbi));
+	struct f2fs_sb_info *sbi = fio->sbi;
+
+	if (PAGE_TYPE_OF_BIO(fio->type) == META &&
+				(!is_read_io(fio->op) || fio->is_meta))
+		BUG_ON(blk_addr < SEG0_BLKADDR(sbi) ||
+				blk_addr >= MAIN_BLKADDR(sbi));
+	else
+		BUG_ON(blk_addr < MAIN_BLKADDR(sbi) ||
+				blk_addr >= MAX_BLKADDR(sbi));
 }
 
 /*
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 78b763c..7d4621a 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -60,7 +60,7 @@
 static void f2fs_build_fault_attr(struct f2fs_sb_info *sbi,
 						unsigned int rate)
 {
-	struct f2fs_fault_info *ffi = &sbi->fault_info;
+	struct f2fs_fault_info *ffi = &F2FS_OPTION(sbi).fault_info;
 
 	if (rate) {
 		atomic_set(&ffi->inject_ops, 0);
@@ -129,6 +129,10 @@
 	Opt_jqfmt_vfsold,
 	Opt_jqfmt_vfsv0,
 	Opt_jqfmt_vfsv1,
+	Opt_whint,
+	Opt_alloc,
+	Opt_fsync,
+	Opt_test_dummy_encryption,
 	Opt_err,
 };
 
@@ -182,6 +186,10 @@
 	{Opt_jqfmt_vfsold, "jqfmt=vfsold"},
 	{Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
 	{Opt_jqfmt_vfsv1, "jqfmt=vfsv1"},
+	{Opt_whint, "whint_mode=%s"},
+	{Opt_alloc, "alloc_mode=%s"},
+	{Opt_fsync, "fsync_mode=%s"},
+	{Opt_test_dummy_encryption, "test_dummy_encryption"},
 	{Opt_err, NULL},
 };
 
@@ -202,21 +210,24 @@
 	block_t limit = (sbi->user_block_count << 1) / 1000;
 
 	/* limit is 0.2% */
-	if (test_opt(sbi, RESERVE_ROOT) && sbi->root_reserved_blocks > limit) {
-		sbi->root_reserved_blocks = limit;
+	if (test_opt(sbi, RESERVE_ROOT) &&
+			F2FS_OPTION(sbi).root_reserved_blocks > limit) {
+		F2FS_OPTION(sbi).root_reserved_blocks = limit;
 		f2fs_msg(sbi->sb, KERN_INFO,
 			"Reduce reserved blocks for root = %u",
-				sbi->root_reserved_blocks);
+			F2FS_OPTION(sbi).root_reserved_blocks);
 	}
 	if (!test_opt(sbi, RESERVE_ROOT) &&
-		(!uid_eq(sbi->s_resuid,
+		(!uid_eq(F2FS_OPTION(sbi).s_resuid,
 				make_kuid(&init_user_ns, F2FS_DEF_RESUID)) ||
-		!gid_eq(sbi->s_resgid,
+		!gid_eq(F2FS_OPTION(sbi).s_resgid,
 				make_kgid(&init_user_ns, F2FS_DEF_RESGID))))
 		f2fs_msg(sbi->sb, KERN_INFO,
 			"Ignore s_resuid=%u, s_resgid=%u w/o reserve_root",
-				from_kuid_munged(&init_user_ns, sbi->s_resuid),
-				from_kgid_munged(&init_user_ns, sbi->s_resgid));
+				from_kuid_munged(&init_user_ns,
+					F2FS_OPTION(sbi).s_resuid),
+				from_kgid_munged(&init_user_ns,
+					F2FS_OPTION(sbi).s_resgid));
 }
 
 static void init_once(void *foo)
@@ -236,7 +247,7 @@
 	char *qname;
 	int ret = -EINVAL;
 
-	if (sb_any_quota_loaded(sb) && !sbi->s_qf_names[qtype]) {
+	if (sb_any_quota_loaded(sb) && !F2FS_OPTION(sbi).s_qf_names[qtype]) {
 		f2fs_msg(sb, KERN_ERR,
 			"Cannot change journaled "
 			"quota options when quota turned on");
@@ -254,8 +265,8 @@
 			"Not enough memory for storing quotafile name");
 		return -EINVAL;
 	}
-	if (sbi->s_qf_names[qtype]) {
-		if (strcmp(sbi->s_qf_names[qtype], qname) == 0)
+	if (F2FS_OPTION(sbi).s_qf_names[qtype]) {
+		if (strcmp(F2FS_OPTION(sbi).s_qf_names[qtype], qname) == 0)
 			ret = 0;
 		else
 			f2fs_msg(sb, KERN_ERR,
@@ -268,7 +279,7 @@
 			"quotafile must be on filesystem root");
 		goto errout;
 	}
-	sbi->s_qf_names[qtype] = qname;
+	F2FS_OPTION(sbi).s_qf_names[qtype] = qname;
 	set_opt(sbi, QUOTA);
 	return 0;
 errout:
@@ -280,13 +291,13 @@
 {
 	struct f2fs_sb_info *sbi = F2FS_SB(sb);
 
-	if (sb_any_quota_loaded(sb) && sbi->s_qf_names[qtype]) {
+	if (sb_any_quota_loaded(sb) && F2FS_OPTION(sbi).s_qf_names[qtype]) {
 		f2fs_msg(sb, KERN_ERR, "Cannot change journaled quota options"
 			" when quota turned on");
 		return -EINVAL;
 	}
-	kfree(sbi->s_qf_names[qtype]);
-	sbi->s_qf_names[qtype] = NULL;
+	kfree(F2FS_OPTION(sbi).s_qf_names[qtype]);
+	F2FS_OPTION(sbi).s_qf_names[qtype] = NULL;
 	return 0;
 }
 
@@ -302,15 +313,19 @@
 			 "Cannot enable project quota enforcement.");
 		return -1;
 	}
-	if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA] ||
-			sbi->s_qf_names[PRJQUOTA]) {
-		if (test_opt(sbi, USRQUOTA) && sbi->s_qf_names[USRQUOTA])
+	if (F2FS_OPTION(sbi).s_qf_names[USRQUOTA] ||
+			F2FS_OPTION(sbi).s_qf_names[GRPQUOTA] ||
+			F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]) {
+		if (test_opt(sbi, USRQUOTA) &&
+				F2FS_OPTION(sbi).s_qf_names[USRQUOTA])
 			clear_opt(sbi, USRQUOTA);
 
-		if (test_opt(sbi, GRPQUOTA) && sbi->s_qf_names[GRPQUOTA])
+		if (test_opt(sbi, GRPQUOTA) &&
+				F2FS_OPTION(sbi).s_qf_names[GRPQUOTA])
 			clear_opt(sbi, GRPQUOTA);
 
-		if (test_opt(sbi, PRJQUOTA) && sbi->s_qf_names[PRJQUOTA])
+		if (test_opt(sbi, PRJQUOTA) &&
+				F2FS_OPTION(sbi).s_qf_names[PRJQUOTA])
 			clear_opt(sbi, PRJQUOTA);
 
 		if (test_opt(sbi, GRPQUOTA) || test_opt(sbi, USRQUOTA) ||
@@ -320,19 +335,19 @@
 			return -1;
 		}
 
-		if (!sbi->s_jquota_fmt) {
+		if (!F2FS_OPTION(sbi).s_jquota_fmt) {
 			f2fs_msg(sbi->sb, KERN_ERR, "journaled quota format "
 					"not specified");
 			return -1;
 		}
 	}
 
-	if (f2fs_sb_has_quota_ino(sbi->sb) && sbi->s_jquota_fmt) {
+	if (f2fs_sb_has_quota_ino(sbi->sb) && F2FS_OPTION(sbi).s_jquota_fmt) {
 		f2fs_msg(sbi->sb, KERN_INFO,
 			"QUOTA feature is enabled, so ignore jquota_fmt");
-		sbi->s_jquota_fmt = 0;
+		F2FS_OPTION(sbi).s_jquota_fmt = 0;
 	}
-	if (f2fs_sb_has_quota_ino(sbi->sb) && sb_rdonly(sbi->sb)) {
+	if (f2fs_sb_has_quota_ino(sbi->sb) && f2fs_readonly(sbi->sb)) {
 		f2fs_msg(sbi->sb, KERN_INFO,
 			 "Filesystem with quota feature cannot be mounted RDWR "
 			 "without CONFIG_QUOTA");
@@ -403,14 +418,14 @@
 			q = bdev_get_queue(sb->s_bdev);
 			if (blk_queue_discard(q)) {
 				set_opt(sbi, DISCARD);
-			} else if (!f2fs_sb_mounted_blkzoned(sb)) {
+			} else if (!f2fs_sb_has_blkzoned(sb)) {
 				f2fs_msg(sb, KERN_WARNING,
 					"mounting with \"discard\" option, but "
 					"the device does not support discard");
 			}
 			break;
 		case Opt_nodiscard:
-			if (f2fs_sb_mounted_blkzoned(sb)) {
+			if (f2fs_sb_has_blkzoned(sb)) {
 				f2fs_msg(sb, KERN_WARNING,
 					"discard is required for zoned block devices");
 				return -EINVAL;
@@ -440,7 +455,7 @@
 			if (args->from && match_int(args, &arg))
 				return -EINVAL;
 			set_opt(sbi, INLINE_XATTR_SIZE);
-			sbi->inline_xattr_size = arg;
+			F2FS_OPTION(sbi).inline_xattr_size = arg;
 			break;
 #else
 		case Opt_user_xattr:
@@ -480,7 +495,7 @@
 				return -EINVAL;
 			if (arg != 2 && arg != 4 && arg != NR_CURSEG_TYPE)
 				return -EINVAL;
-			sbi->active_logs = arg;
+			F2FS_OPTION(sbi).active_logs = arg;
 			break;
 		case Opt_disable_ext_identify:
 			set_opt(sbi, DISABLE_EXT_IDENTIFY);
@@ -524,9 +539,9 @@
 			if (test_opt(sbi, RESERVE_ROOT)) {
 				f2fs_msg(sb, KERN_INFO,
 					"Preserve previous reserve_root=%u",
-					sbi->root_reserved_blocks);
+					F2FS_OPTION(sbi).root_reserved_blocks);
 			} else {
-				sbi->root_reserved_blocks = arg;
+				F2FS_OPTION(sbi).root_reserved_blocks = arg;
 				set_opt(sbi, RESERVE_ROOT);
 			}
 			break;
@@ -539,7 +554,7 @@
 					"Invalid uid value %d", arg);
 				return -EINVAL;
 			}
-			sbi->s_resuid = uid;
+			F2FS_OPTION(sbi).s_resuid = uid;
 			break;
 		case Opt_resgid:
 			if (args->from && match_int(args, &arg))
@@ -550,7 +565,7 @@
 					"Invalid gid value %d", arg);
 				return -EINVAL;
 			}
-			sbi->s_resgid = gid;
+			F2FS_OPTION(sbi).s_resgid = gid;
 			break;
 		case Opt_mode:
 			name = match_strdup(&args[0]);
@@ -559,7 +574,7 @@
 				return -ENOMEM;
 			if (strlen(name) == 8 &&
 					!strncmp(name, "adaptive", 8)) {
-				if (f2fs_sb_mounted_blkzoned(sb)) {
+				if (f2fs_sb_has_blkzoned(sb)) {
 					f2fs_msg(sb, KERN_WARNING,
 						 "adaptive mode is not allowed with "
 						 "zoned block device feature");
@@ -585,7 +600,7 @@
 					1 << arg, BIO_MAX_PAGES);
 				return -EINVAL;
 			}
-			sbi->write_io_size_bits = arg;
+			F2FS_OPTION(sbi).write_io_size_bits = arg;
 			break;
 		case Opt_fault_injection:
 			if (args->from && match_int(args, &arg))
@@ -646,13 +661,13 @@
 				return ret;
 			break;
 		case Opt_jqfmt_vfsold:
-			sbi->s_jquota_fmt = QFMT_VFS_OLD;
+			F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_OLD;
 			break;
 		case Opt_jqfmt_vfsv0:
-			sbi->s_jquota_fmt = QFMT_VFS_V0;
+			F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_V0;
 			break;
 		case Opt_jqfmt_vfsv1:
-			sbi->s_jquota_fmt = QFMT_VFS_V1;
+			F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_V1;
 			break;
 		case Opt_noquota:
 			clear_opt(sbi, QUOTA);
@@ -679,6 +694,73 @@
 					"quota operations not supported");
 			break;
 #endif
+		case Opt_whint:
+			name = match_strdup(&args[0]);
+			if (!name)
+				return -ENOMEM;
+			if (strlen(name) == 10 &&
+					!strncmp(name, "user-based", 10)) {
+				F2FS_OPTION(sbi).whint_mode = WHINT_MODE_USER;
+			} else if (strlen(name) == 3 &&
+					!strncmp(name, "off", 3)) {
+				F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF;
+			} else if (strlen(name) == 8 &&
+					!strncmp(name, "fs-based", 8)) {
+				F2FS_OPTION(sbi).whint_mode = WHINT_MODE_FS;
+			} else {
+				kfree(name);
+				return -EINVAL;
+			}
+			kfree(name);
+			break;
+		case Opt_alloc:
+			name = match_strdup(&args[0]);
+			if (!name)
+				return -ENOMEM;
+
+			if (strlen(name) == 7 &&
+					!strncmp(name, "default", 7)) {
+				F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT;
+			} else if (strlen(name) == 5 &&
+					!strncmp(name, "reuse", 5)) {
+				F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_REUSE;
+			} else {
+				kfree(name);
+				return -EINVAL;
+			}
+			kfree(name);
+			break;
+		case Opt_fsync:
+			name = match_strdup(&args[0]);
+			if (!name)
+				return -ENOMEM;
+			if (strlen(name) == 5 &&
+					!strncmp(name, "posix", 5)) {
+				F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX;
+			} else if (strlen(name) == 6 &&
+					!strncmp(name, "strict", 6)) {
+				F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_STRICT;
+			} else {
+				kfree(name);
+				return -EINVAL;
+			}
+			kfree(name);
+			break;
+		case Opt_test_dummy_encryption:
+#ifdef CONFIG_F2FS_FS_ENCRYPTION
+			if (!f2fs_sb_has_encrypt(sb)) {
+				f2fs_msg(sb, KERN_ERR, "Encrypt feature is off");
+				return -EINVAL;
+			}
+
+			F2FS_OPTION(sbi).test_dummy_encryption = true;
+			f2fs_msg(sb, KERN_INFO,
+					"Test dummy encryption mode enabled");
+#else
+			f2fs_msg(sb, KERN_INFO,
+					"Test dummy encryption mount option ignored");
+#endif
+			break;
 		default:
 			f2fs_msg(sb, KERN_ERR,
 				"Unrecognized mount option \"%s\" or missing value",
@@ -699,14 +781,22 @@
 	}
 
 	if (test_opt(sbi, INLINE_XATTR_SIZE)) {
+		if (!f2fs_sb_has_extra_attr(sb) ||
+			!f2fs_sb_has_flexible_inline_xattr(sb)) {
+			f2fs_msg(sb, KERN_ERR,
+					"extra_attr or flexible_inline_xattr "
+					"feature is off");
+			return -EINVAL;
+		}
 		if (!test_opt(sbi, INLINE_XATTR)) {
 			f2fs_msg(sb, KERN_ERR,
 					"inline_xattr_size option should be "
 					"set with inline_xattr option");
 			return -EINVAL;
 		}
-		if (!sbi->inline_xattr_size ||
-			sbi->inline_xattr_size >= DEF_ADDRS_PER_INODE -
+		if (!F2FS_OPTION(sbi).inline_xattr_size ||
+			F2FS_OPTION(sbi).inline_xattr_size >=
+					DEF_ADDRS_PER_INODE -
 					F2FS_TOTAL_EXTRA_ATTR_SIZE -
 					DEF_INLINE_RESERVED_SIZE -
 					DEF_MIN_INLINE_SIZE) {
@@ -715,6 +805,12 @@
 			return -EINVAL;
 		}
 	}
+
+	/* Not pass down write hints if the number of active logs is lesser
+	 * than NR_CURSEG_TYPE.
+	 */
+	if (F2FS_OPTION(sbi).active_logs != NR_CURSEG_TYPE)
+		F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF;
 	return 0;
 }
 
@@ -731,7 +827,6 @@
 	/* Initialize f2fs-specific inode info */
 	atomic_set(&fi->dirty_pages, 0);
 	fi->i_current_depth = 1;
-	fi->i_advise = 0;
 	init_rwsem(&fi->i_sem);
 	INIT_LIST_HEAD(&fi->dirty_list);
 	INIT_LIST_HEAD(&fi->gdirty_list);
@@ -743,10 +838,6 @@
 	init_rwsem(&fi->i_mmap_sem);
 	init_rwsem(&fi->i_xattr_sem);
 
-#ifdef CONFIG_QUOTA
-	memset(&fi->i_dquot, 0, sizeof(fi->i_dquot));
-	fi->i_reserved_quota = 0;
-#endif
 	/* Will be used by directory only */
 	fi->i_dir_level = F2FS_SB(sb)->dir_level;
 
@@ -956,7 +1047,7 @@
 	mempool_destroy(sbi->write_io_dummy);
 #ifdef CONFIG_QUOTA
 	for (i = 0; i < MAXQUOTAS; i++)
-		kfree(sbi->s_qf_names[i]);
+		kfree(F2FS_OPTION(sbi).s_qf_names[i]);
 #endif
 	destroy_percpu_info(sbi);
 	for (i = 0; i < NR_PAGE_TYPE; i++)
@@ -1070,8 +1161,9 @@
 	buf->f_blocks = total_count - start_count;
 	buf->f_bfree = user_block_count - valid_user_blocks(sbi) -
 						sbi->current_reserved_blocks;
-	if (buf->f_bfree > sbi->root_reserved_blocks)
-		buf->f_bavail = buf->f_bfree - sbi->root_reserved_blocks;
+	if (buf->f_bfree > F2FS_OPTION(sbi).root_reserved_blocks)
+		buf->f_bavail = buf->f_bfree -
+				F2FS_OPTION(sbi).root_reserved_blocks;
 	else
 		buf->f_bavail = 0;
 
@@ -1106,10 +1198,10 @@
 #ifdef CONFIG_QUOTA
 	struct f2fs_sb_info *sbi = F2FS_SB(sb);
 
-	if (sbi->s_jquota_fmt) {
+	if (F2FS_OPTION(sbi).s_jquota_fmt) {
 		char *fmtname = "";
 
-		switch (sbi->s_jquota_fmt) {
+		switch (F2FS_OPTION(sbi).s_jquota_fmt) {
 		case QFMT_VFS_OLD:
 			fmtname = "vfsold";
 			break;
@@ -1123,14 +1215,17 @@
 		seq_printf(seq, ",jqfmt=%s", fmtname);
 	}
 
-	if (sbi->s_qf_names[USRQUOTA])
-		seq_show_option(seq, "usrjquota", sbi->s_qf_names[USRQUOTA]);
+	if (F2FS_OPTION(sbi).s_qf_names[USRQUOTA])
+		seq_show_option(seq, "usrjquota",
+			F2FS_OPTION(sbi).s_qf_names[USRQUOTA]);
 
-	if (sbi->s_qf_names[GRPQUOTA])
-		seq_show_option(seq, "grpjquota", sbi->s_qf_names[GRPQUOTA]);
+	if (F2FS_OPTION(sbi).s_qf_names[GRPQUOTA])
+		seq_show_option(seq, "grpjquota",
+			F2FS_OPTION(sbi).s_qf_names[GRPQUOTA]);
 
-	if (sbi->s_qf_names[PRJQUOTA])
-		seq_show_option(seq, "prjjquota", sbi->s_qf_names[PRJQUOTA]);
+	if (F2FS_OPTION(sbi).s_qf_names[PRJQUOTA])
+		seq_show_option(seq, "prjjquota",
+			F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]);
 #endif
 }
 
@@ -1165,7 +1260,7 @@
 		seq_puts(seq, ",noinline_xattr");
 	if (test_opt(sbi, INLINE_XATTR_SIZE))
 		seq_printf(seq, ",inline_xattr_size=%u",
-					sbi->inline_xattr_size);
+					F2FS_OPTION(sbi).inline_xattr_size);
 #endif
 #ifdef CONFIG_F2FS_FS_POSIX_ACL
 	if (test_opt(sbi, POSIX_ACL))
@@ -1201,18 +1296,20 @@
 		seq_puts(seq, "adaptive");
 	else if (test_opt(sbi, LFS))
 		seq_puts(seq, "lfs");
-	seq_printf(seq, ",active_logs=%u", sbi->active_logs);
+	seq_printf(seq, ",active_logs=%u", F2FS_OPTION(sbi).active_logs);
 	if (test_opt(sbi, RESERVE_ROOT))
 		seq_printf(seq, ",reserve_root=%u,resuid=%u,resgid=%u",
-				sbi->root_reserved_blocks,
-				from_kuid_munged(&init_user_ns, sbi->s_resuid),
-				from_kgid_munged(&init_user_ns, sbi->s_resgid));
+				F2FS_OPTION(sbi).root_reserved_blocks,
+				from_kuid_munged(&init_user_ns,
+					F2FS_OPTION(sbi).s_resuid),
+				from_kgid_munged(&init_user_ns,
+					F2FS_OPTION(sbi).s_resgid));
 	if (F2FS_IO_SIZE_BITS(sbi))
 		seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
 #ifdef CONFIG_F2FS_FAULT_INJECTION
 	if (test_opt(sbi, FAULT_INJECTION))
 		seq_printf(seq, ",fault_injection=%u",
-				sbi->fault_info.inject_rate);
+				F2FS_OPTION(sbi).fault_info.inject_rate);
 #endif
 #ifdef CONFIG_QUOTA
 	if (test_opt(sbi, QUOTA))
@@ -1225,15 +1322,37 @@
 		seq_puts(seq, ",prjquota");
 #endif
 	f2fs_show_quota_options(seq, sbi->sb);
+	if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_USER)
+		seq_printf(seq, ",whint_mode=%s", "user-based");
+	else if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_FS)
+		seq_printf(seq, ",whint_mode=%s", "fs-based");
+#ifdef CONFIG_F2FS_FS_ENCRYPTION
+	if (F2FS_OPTION(sbi).test_dummy_encryption)
+		seq_puts(seq, ",test_dummy_encryption");
+#endif
 
+	if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_DEFAULT)
+		seq_printf(seq, ",alloc_mode=%s", "default");
+	else if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_REUSE)
+		seq_printf(seq, ",alloc_mode=%s", "reuse");
+
+	if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_POSIX)
+		seq_printf(seq, ",fsync_mode=%s", "posix");
+	else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT)
+		seq_printf(seq, ",fsync_mode=%s", "strict");
 	return 0;
 }
 
 static void default_options(struct f2fs_sb_info *sbi)
 {
 	/* init some FS parameters */
-	sbi->active_logs = NR_CURSEG_TYPE;
-	sbi->inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS;
+	F2FS_OPTION(sbi).active_logs = NR_CURSEG_TYPE;
+	F2FS_OPTION(sbi).inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS;
+	F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF;
+	F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT;
+	F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX;
+	F2FS_OPTION(sbi).test_dummy_encryption = false;
+	sbi->readdir_ra = 1;
 
 	set_opt(sbi, BG_GC);
 	set_opt(sbi, INLINE_XATTR);
@@ -1243,7 +1362,7 @@
 	set_opt(sbi, NOHEAP);
 	sbi->sb->s_flags |= MS_LAZYTIME;
 	set_opt(sbi, FLUSH_MERGE);
-	if (f2fs_sb_mounted_blkzoned(sbi->sb)) {
+	if (f2fs_sb_has_blkzoned(sbi->sb)) {
 		set_opt_mode(sbi, F2FS_MOUNT_LFS);
 		set_opt(sbi, DISCARD);
 	} else {
@@ -1270,16 +1389,11 @@
 	struct f2fs_sb_info *sbi = F2FS_SB(sb);
 	struct f2fs_mount_info org_mount_opt;
 	unsigned long old_sb_flags;
-	int err, active_logs;
+	int err;
 	bool need_restart_gc = false;
 	bool need_stop_gc = false;
 	bool no_extent_cache = !test_opt(sbi, EXTENT_CACHE);
-#ifdef CONFIG_F2FS_FAULT_INJECTION
-	struct f2fs_fault_info ffi = sbi->fault_info;
-#endif
 #ifdef CONFIG_QUOTA
-	int s_jquota_fmt;
-	char *s_qf_names[MAXQUOTAS];
 	int i, j;
 #endif
 
@@ -1289,21 +1403,21 @@
 	 */
 	org_mount_opt = sbi->mount_opt;
 	old_sb_flags = sb->s_flags;
-	active_logs = sbi->active_logs;
 
 #ifdef CONFIG_QUOTA
-	s_jquota_fmt = sbi->s_jquota_fmt;
+	org_mount_opt.s_jquota_fmt = F2FS_OPTION(sbi).s_jquota_fmt;
 	for (i = 0; i < MAXQUOTAS; i++) {
-		if (sbi->s_qf_names[i]) {
-			s_qf_names[i] = kstrdup(sbi->s_qf_names[i],
-							 GFP_KERNEL);
-			if (!s_qf_names[i]) {
+		if (F2FS_OPTION(sbi).s_qf_names[i]) {
+			org_mount_opt.s_qf_names[i] =
+				kstrdup(F2FS_OPTION(sbi).s_qf_names[i],
+				GFP_KERNEL);
+			if (!org_mount_opt.s_qf_names[i]) {
 				for (j = 0; j < i; j++)
-					kfree(s_qf_names[j]);
+					kfree(org_mount_opt.s_qf_names[j]);
 				return -ENOMEM;
 			}
 		} else {
-			s_qf_names[i] = NULL;
+			org_mount_opt.s_qf_names[i] = NULL;
 		}
 	}
 #endif
@@ -1373,7 +1487,8 @@
 		need_stop_gc = true;
 	}
 
-	if (*flags & MS_RDONLY) {
+	if (*flags & MS_RDONLY ||
+		F2FS_OPTION(sbi).whint_mode != org_mount_opt.whint_mode) {
 		writeback_inodes_sb(sb, WB_REASON_SYNC);
 		sync_inodes_sb(sb);
 
@@ -1399,7 +1514,7 @@
 #ifdef CONFIG_QUOTA
 	/* Release old quota file names */
 	for (i = 0; i < MAXQUOTAS; i++)
-		kfree(s_qf_names[i]);
+		kfree(org_mount_opt.s_qf_names[i]);
 #endif
 	/* Update the POSIXACL Flag */
 	sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
@@ -1417,18 +1532,14 @@
 	}
 restore_opts:
 #ifdef CONFIG_QUOTA
-	sbi->s_jquota_fmt = s_jquota_fmt;
+	F2FS_OPTION(sbi).s_jquota_fmt = org_mount_opt.s_jquota_fmt;
 	for (i = 0; i < MAXQUOTAS; i++) {
-		kfree(sbi->s_qf_names[i]);
-		sbi->s_qf_names[i] = s_qf_names[i];
+		kfree(F2FS_OPTION(sbi).s_qf_names[i]);
+		F2FS_OPTION(sbi).s_qf_names[i] = org_mount_opt.s_qf_names[i];
 	}
 #endif
 	sbi->mount_opt = org_mount_opt;
-	sbi->active_logs = active_logs;
 	sb->s_flags = old_sb_flags;
-#ifdef CONFIG_F2FS_FAULT_INJECTION
-	sbi->fault_info = ffi;
-#endif
 	return err;
 }
 
@@ -1550,8 +1661,8 @@
 
 static int f2fs_quota_on_mount(struct f2fs_sb_info *sbi, int type)
 {
-	return dquot_quota_on_mount(sbi->sb, sbi->s_qf_names[type],
-						sbi->s_jquota_fmt, type);
+	return dquot_quota_on_mount(sbi->sb, F2FS_OPTION(sbi).s_qf_names[type],
+					F2FS_OPTION(sbi).s_jquota_fmt, type);
 }
 
 int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly)
@@ -1570,7 +1681,7 @@
 	}
 
 	for (i = 0; i < MAXQUOTAS; i++) {
-		if (sbi->s_qf_names[i]) {
+		if (F2FS_OPTION(sbi).s_qf_names[i]) {
 			err = f2fs_quota_on_mount(sbi, i);
 			if (!err) {
 				enabled = 1;
@@ -1797,11 +1908,28 @@
 static int f2fs_set_context(struct inode *inode, const void *ctx, size_t len,
 							void *fs_data)
 {
+	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+
+	/*
+	 * Encrypting the root directory is not allowed because fsck
+	 * expects lost+found directory to exist and remain unencrypted
+	 * if LOST_FOUND feature is enabled.
+	 *
+	 */
+	if (f2fs_sb_has_lost_found(sbi->sb) &&
+			inode->i_ino == F2FS_ROOT_INO(sbi))
+		return -EPERM;
+
 	return f2fs_setxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION,
 				F2FS_XATTR_NAME_ENCRYPTION_CONTEXT,
 				ctx, len, fs_data, XATTR_CREATE);
 }
 
+static bool f2fs_dummy_context(struct inode *inode)
+{
+	return DUMMY_ENCRYPTION_ENABLED(F2FS_I_SB(inode));
+}
+
 static unsigned f2fs_max_namelen(struct inode *inode)
 {
 	return S_ISLNK(inode->i_mode) ?
@@ -1812,6 +1940,7 @@
 	.key_prefix	= "f2fs:",
 	.get_context	= f2fs_get_context,
 	.set_context	= f2fs_set_context,
+	.dummy_context	= f2fs_dummy_context,
 	.empty_dir	= f2fs_empty_dir,
 	.max_namelen	= f2fs_max_namelen,
 };
@@ -1894,7 +2023,6 @@
 	lock_buffer(bh);
 	if (super)
 		memcpy(bh->b_data + F2FS_SUPER_OFFSET, super, sizeof(*super));
-	set_buffer_uptodate(bh);
 	set_buffer_dirty(bh);
 	unlock_buffer(bh);
 
@@ -2181,6 +2309,8 @@
 
 	sbi->dirty_device = 0;
 	spin_lock_init(&sbi->dev_lock);
+
+	init_rwsem(&sbi->sb_lock);
 }
 
 static int init_percpu_info(struct f2fs_sb_info *sbi)
@@ -2206,7 +2336,7 @@
 	unsigned int n = 0;
 	int err = -EIO;
 
-	if (!f2fs_sb_mounted_blkzoned(sbi->sb))
+	if (!f2fs_sb_has_blkzoned(sbi->sb))
 		return 0;
 
 	if (sbi->blocks_per_blkz && sbi->blocks_per_blkz !=
@@ -2334,7 +2464,7 @@
 	}
 
 	/* write back-up superblock first */
-	bh = sb_getblk(sbi->sb, sbi->valid_super_block ? 0: 1);
+	bh = sb_bread(sbi->sb, sbi->valid_super_block ? 0 : 1);
 	if (!bh)
 		return -EIO;
 	err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi));
@@ -2345,7 +2475,7 @@
 		return err;
 
 	/* write current valid superblock */
-	bh = sb_getblk(sbi->sb, sbi->valid_super_block);
+	bh = sb_bread(sbi->sb, sbi->valid_super_block);
 	if (!bh)
 		return -EIO;
 	err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi));
@@ -2417,7 +2547,7 @@
 
 #ifdef CONFIG_BLK_DEV_ZONED
 		if (bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HM &&
-				!f2fs_sb_mounted_blkzoned(sbi->sb)) {
+				!f2fs_sb_has_blkzoned(sbi->sb)) {
 			f2fs_msg(sbi->sb, KERN_ERR,
 				"Zoned block device feature not enabled\n");
 			return -EINVAL;
@@ -2451,6 +2581,18 @@
 	return 0;
 }
 
+static void f2fs_tuning_parameters(struct f2fs_sb_info *sbi)
+{
+	struct f2fs_sm_info *sm_i = SM_I(sbi);
+
+	/* adjust parameters according to the volume size */
+	if (sm_i->main_segments <= SMALL_VOLUME_SEGMENTS) {
+		F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_REUSE;
+		sm_i->dcc_info->discard_granularity = 1;
+		sm_i->ipu_policy = 1 << F2FS_IPU_FORCE;
+	}
+}
+
 static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct f2fs_sb_info *sbi;
@@ -2498,8 +2640,8 @@
 	sb->s_fs_info = sbi;
 	sbi->raw_super = raw_super;
 
-	sbi->s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID);
-	sbi->s_resgid = make_kgid(&init_user_ns, F2FS_DEF_RESGID);
+	F2FS_OPTION(sbi).s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID);
+	F2FS_OPTION(sbi).s_resgid = make_kgid(&init_user_ns, F2FS_DEF_RESGID);
 
 	/* precompute checksum seed for metadata */
 	if (f2fs_sb_has_inode_chksum(sb))
@@ -2512,7 +2654,7 @@
 	 * devices, but mandatory for host-managed zoned block devices.
 	 */
 #ifndef CONFIG_BLK_DEV_ZONED
-	if (f2fs_sb_mounted_blkzoned(sb)) {
+	if (f2fs_sb_has_blkzoned(sb)) {
 		f2fs_msg(sb, KERN_ERR,
 			 "Zoned block device support is not enabled\n");
 		err = -EOPNOTSUPP;
@@ -2728,7 +2870,7 @@
 	 * Turn on quotas which were not enabled for read-only mounts if
 	 * filesystem has quota feature, so that they are updated correctly.
 	 */
-	if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb)) {
+	if (f2fs_sb_has_quota_ino(sb) && !f2fs_readonly(sb)) {
 		err = f2fs_enable_quotas(sb);
 		if (err) {
 			f2fs_msg(sb, KERN_ERR,
@@ -2803,6 +2945,8 @@
 
 	f2fs_join_shrinker(sbi);
 
+	f2fs_tuning_parameters(sbi);
+
 	f2fs_msg(sbi->sb, KERN_NOTICE, "Mounted with checkpoint version = %llx",
 				cur_cp_version(F2FS_CKPT(sbi)));
 	f2fs_update_time(sbi, CP_TIME);
@@ -2811,7 +2955,7 @@
 
 free_meta:
 #ifdef CONFIG_QUOTA
-	if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb))
+	if (f2fs_sb_has_quota_ino(sb) && !f2fs_readonly(sb))
 		f2fs_quota_off_umount(sbi->sb);
 #endif
 	f2fs_sync_inode_meta(sbi);
@@ -2855,7 +2999,7 @@
 free_options:
 #ifdef CONFIG_QUOTA
 	for (i = 0; i < MAXQUOTAS; i++)
-		kfree(sbi->s_qf_names[i]);
+		kfree(F2FS_OPTION(sbi).s_qf_names[i]);
 #endif
 	kfree(options);
 free_sb_buf:
@@ -2952,8 +3096,13 @@
 	err = f2fs_create_root_stats();
 	if (err)
 		goto free_filesystem;
+	err = f2fs_init_post_read_processing();
+	if (err)
+		goto free_root_stats;
 	return 0;
 
+free_root_stats:
+	f2fs_destroy_root_stats();
 free_filesystem:
 	unregister_filesystem(&f2fs_fs_type);
 free_shrinker:
@@ -2976,6 +3125,7 @@
 
 static void __exit exit_f2fs_fs(void)
 {
+	f2fs_destroy_post_read_processing();
 	f2fs_destroy_root_stats();
 	unregister_filesystem(&f2fs_fs_type);
 	unregister_shrinker(&f2fs_shrinker_info);
diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
index d978c7b..f33a56d 100644
--- a/fs/f2fs/sysfs.c
+++ b/fs/f2fs/sysfs.c
@@ -58,7 +58,7 @@
 #ifdef CONFIG_F2FS_FAULT_INJECTION
 	else if (struct_type == FAULT_INFO_RATE ||
 					struct_type == FAULT_INFO_TYPE)
-		return (unsigned char *)&sbi->fault_info;
+		return (unsigned char *)&F2FS_OPTION(sbi).fault_info;
 #endif
 	return NULL;
 }
@@ -92,10 +92,10 @@
 	if (!sb->s_bdev->bd_part)
 		return snprintf(buf, PAGE_SIZE, "0\n");
 
-	if (f2fs_sb_has_crypto(sb))
+	if (f2fs_sb_has_encrypt(sb))
 		len += snprintf(buf, PAGE_SIZE - len, "%s",
 						"encryption");
-	if (f2fs_sb_mounted_blkzoned(sb))
+	if (f2fs_sb_has_blkzoned(sb))
 		len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
 				len ? ", " : "", "blkzoned");
 	if (f2fs_sb_has_extra_attr(sb))
@@ -116,6 +116,9 @@
 	if (f2fs_sb_has_inode_crtime(sb))
 		len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
 				len ? ", " : "", "inode_crtime");
+	if (f2fs_sb_has_lost_found(sb))
+		len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
+				len ? ", " : "", "lost_found");
 	len += snprintf(buf + len, PAGE_SIZE - len, "\n");
 	return len;
 }
@@ -136,6 +139,27 @@
 	if (!ptr)
 		return -EINVAL;
 
+	if (!strcmp(a->attr.name, "extension_list")) {
+		__u8 (*extlist)[F2FS_EXTENSION_LEN] =
+					sbi->raw_super->extension_list;
+		int cold_count = le32_to_cpu(sbi->raw_super->extension_count);
+		int hot_count = sbi->raw_super->hot_ext_count;
+		int len = 0, i;
+
+		len += snprintf(buf + len, PAGE_SIZE - len,
+						"cold file extenstion:\n");
+		for (i = 0; i < cold_count; i++)
+			len += snprintf(buf + len, PAGE_SIZE - len, "%s\n",
+								extlist[i]);
+
+		len += snprintf(buf + len, PAGE_SIZE - len,
+						"hot file extenstion:\n");
+		for (i = cold_count; i < cold_count + hot_count; i++)
+			len += snprintf(buf + len, PAGE_SIZE - len, "%s\n",
+								extlist[i]);
+		return len;
+	}
+
 	ui = (unsigned int *)(ptr + a->offset);
 
 	return snprintf(buf, PAGE_SIZE, "%u\n", *ui);
@@ -154,6 +178,41 @@
 	if (!ptr)
 		return -EINVAL;
 
+	if (!strcmp(a->attr.name, "extension_list")) {
+		const char *name = strim((char *)buf);
+		bool set = true, hot;
+
+		if (!strncmp(name, "[h]", 3))
+			hot = true;
+		else if (!strncmp(name, "[c]", 3))
+			hot = false;
+		else
+			return -EINVAL;
+
+		name += 3;
+
+		if (*name == '!') {
+			name++;
+			set = false;
+		}
+
+		if (strlen(name) >= F2FS_EXTENSION_LEN)
+			return -EINVAL;
+
+		down_write(&sbi->sb_lock);
+
+		ret = update_extension_list(sbi, name, hot, set);
+		if (ret)
+			goto out;
+
+		ret = f2fs_commit_super(sbi, false);
+		if (ret)
+			update_extension_list(sbi, name, hot, !set);
+out:
+		up_write(&sbi->sb_lock);
+		return ret ? ret : count;
+	}
+
 	ui = (unsigned int *)(ptr + a->offset);
 
 	ret = kstrtoul(skip_spaces(buf), 0, &t);
@@ -166,7 +225,7 @@
 	if (a->struct_type == RESERVED_BLOCKS) {
 		spin_lock(&sbi->stat_lock);
 		if (t > (unsigned long)(sbi->user_block_count -
-					sbi->root_reserved_blocks)) {
+				F2FS_OPTION(sbi).root_reserved_blocks)) {
 			spin_unlock(&sbi->stat_lock);
 			return -EINVAL;
 		}
@@ -236,6 +295,7 @@
 	FEAT_FLEXIBLE_INLINE_XATTR,
 	FEAT_QUOTA_INO,
 	FEAT_INODE_CRTIME,
+	FEAT_LOST_FOUND,
 };
 
 static ssize_t f2fs_feature_show(struct f2fs_attr *a,
@@ -251,6 +311,7 @@
 	case FEAT_FLEXIBLE_INLINE_XATTR:
 	case FEAT_QUOTA_INO:
 	case FEAT_INODE_CRTIME:
+	case FEAT_LOST_FOUND:
 		return snprintf(buf, PAGE_SIZE, "supported\n");
 	}
 	return 0;
@@ -307,6 +368,7 @@
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_enable, iostat_enable);
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, readdir_ra, readdir_ra);
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold);
+F2FS_RW_ATTR(F2FS_SBI, f2fs_super_block, extension_list, extension_list);
 #ifdef CONFIG_F2FS_FAULT_INJECTION
 F2FS_RW_ATTR(FAULT_INFO_RATE, f2fs_fault_info, inject_rate, inject_rate);
 F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type);
@@ -329,6 +391,7 @@
 F2FS_FEATURE_RO_ATTR(flexible_inline_xattr, FEAT_FLEXIBLE_INLINE_XATTR);
 F2FS_FEATURE_RO_ATTR(quota_ino, FEAT_QUOTA_INO);
 F2FS_FEATURE_RO_ATTR(inode_crtime, FEAT_INODE_CRTIME);
+F2FS_FEATURE_RO_ATTR(lost_found, FEAT_LOST_FOUND);
 
 #define ATTR_LIST(name) (&f2fs_attr_##name.attr)
 static struct attribute *f2fs_attrs[] = {
@@ -357,6 +420,7 @@
 	ATTR_LIST(iostat_enable),
 	ATTR_LIST(readdir_ra),
 	ATTR_LIST(gc_pin_file_thresh),
+	ATTR_LIST(extension_list),
 #ifdef CONFIG_F2FS_FAULT_INJECTION
 	ATTR_LIST(inject_rate),
 	ATTR_LIST(inject_type),
@@ -383,6 +447,7 @@
 	ATTR_LIST(flexible_inline_xattr),
 	ATTR_LIST(quota_ino),
 	ATTR_LIST(inode_crtime),
+	ATTR_LIST(lost_found),
 	NULL,
 };
 
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index ad2e55d..5af226f 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -745,11 +745,12 @@
 	 */
 	if (inode && inode_to_wb_is_valid(inode)) {
 		struct bdi_writeback *wb;
-		bool locked, congested;
+		struct wb_lock_cookie lock_cookie = {};
+		bool congested;
 
-		wb = unlocked_inode_to_wb_begin(inode, &locked);
+		wb = unlocked_inode_to_wb_begin(inode, &lock_cookie);
 		congested = wb_congested(wb, cong_bits);
-		unlocked_inode_to_wb_end(inode, locked);
+		unlocked_inode_to_wb_end(inode, &lock_cookie);
 		return congested;
 	}
 
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 658fa9e..a0b0683 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1891,8 +1891,10 @@
 
 	err = copy_out_args(cs, &req->out, nbytes);
 	if (req->in.h.opcode == FUSE_CANONICAL_PATH) {
-		req->out.h.error = kern_path((char *)req->out.args[0].value, 0,
-							req->canonical_path);
+		char *path = (char *)req->out.args[0].value;
+
+		path[req->out.args[0].size - 1] = 0;
+		req->out.h.error = kern_path(path, 0, req->canonical_path);
 	}
 	fuse_copy_finish(cs);
 
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index f06c39c..d10bb2c 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -951,7 +951,7 @@
 }
 
 /*
- * This is a variaon of __jbd2_update_log_tail which checks for validity of
+ * This is a variation of __jbd2_update_log_tail which checks for validity of
  * provided log tail and locks j_checkpoint_mutex. So it is safe against races
  * with other threads updating log tail.
  */
@@ -1394,6 +1394,9 @@
 	journal_superblock_t *sb = journal->j_superblock;
 	int ret;
 
+	if (is_journal_aborted(journal))
+		return -EIO;
+
 	BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex));
 	jbd_debug(1, "JBD2: updating superblock (start %lu, seq %u)\n",
 		  tail_block, tail_tid);
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 5ef21f4..59c019a 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -342,7 +342,7 @@
 static void jffs2_kill_sb(struct super_block *sb)
 {
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-	if (!(sb->s_flags & MS_RDONLY))
+	if (c && !(sb->s_flags & MS_RDONLY))
 		jffs2_stop_garbage_collect_thread(c);
 	kill_mtd_super(sb);
 	kfree(c);
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index a770da3..4d51259 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -132,6 +132,8 @@
 {
 	int		err = 0;
 	struct svc_rqst *rqstp = vrqstp;
+	struct net *net = &init_net;
+	struct lockd_net *ln = net_generic(net, lockd_net_id);
 
 	/* try_to_freeze() is called from svc_recv() */
 	set_freezable();
@@ -176,6 +178,8 @@
 	if (nlmsvc_ops)
 		nlmsvc_invalidate_all();
 	nlm_shutdown_hosts();
+	cancel_delayed_work_sync(&ln->grace_period_end);
+	locks_end_grace(&ln->lockd_manager);
 	return 0;
 }
 
@@ -270,8 +274,6 @@
 	if (ln->nlmsvc_users) {
 		if (--ln->nlmsvc_users == 0) {
 			nlm_shutdown_hosts_net(net);
-			cancel_delayed_work_sync(&ln->grace_period_end);
-			locks_end_grace(&ln->lockd_manager);
 			svc_shutdown_net(serv, net);
 			dprintk("lockd_down_net: per-net data destroyed; net=%p\n", net);
 		}
diff --git a/fs/namei.c b/fs/namei.c
index 02fc285..a5a05d3 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -221,9 +221,10 @@
 	if (len <= EMBEDDED_NAME_MAX) {
 		result->name = (char *)result->iname;
 	} else if (len <= PATH_MAX) {
+		const size_t size = offsetof(struct filename, iname[1]);
 		struct filename *tmp;
 
-		tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+		tmp = kmalloc(size, GFP_KERNEL);
 		if (unlikely(!tmp)) {
 			__putname(result);
 			return ERR_PTR(-ENOMEM);
diff --git a/fs/namespace.c b/fs/namespace.c
index 2160bb9..4628d08c 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1051,7 +1051,8 @@
 			goto out_free;
 	}
 
-	mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~(MNT_WRITE_HOLD|MNT_MARKED);
+	mnt->mnt.mnt_flags = old->mnt.mnt_flags;
+	mnt->mnt.mnt_flags &= ~(MNT_WRITE_HOLD|MNT_MARKED|MNT_INTERNAL);
 	/* Don't allow unprivileged users to change mount flags */
 	if (flag & CL_UNPRIVILEGED) {
 		mnt->mnt.mnt_flags |= MNT_LOCK_ATIME;
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c
index 13abd60..4539008 100644
--- a/fs/nfs/flexfilelayout/flexfilelayout.c
+++ b/fs/nfs/flexfilelayout/flexfilelayout.c
@@ -475,6 +475,7 @@
 			goto out_err_free;
 
 		/* fh */
+		rc = -EIO;
 		p = xdr_inline_decode(&stream, 4);
 		if (!p)
 			goto out_err_free;
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 4638654..1b1b616 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3300,6 +3300,7 @@
 		.rpc_resp = &res,
 	};
 	int status;
+	int i;
 
 	bitmask[0] = FATTR4_WORD0_SUPPORTED_ATTRS |
 		     FATTR4_WORD0_FH_EXPIRE_TYPE |
@@ -3365,8 +3366,13 @@
 		server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
 		server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
 		server->cache_consistency_bitmask[2] = 0;
+
+		/* Avoid a regression due to buggy server */
+		for (i = 0; i < ARRAY_SIZE(res.exclcreat_bitmask); i++)
+			res.exclcreat_bitmask[i] &= res.attr_bitmask[i];
 		memcpy(server->exclcreat_bitmask, res.exclcreat_bitmask,
 			sizeof(server->exclcreat_bitmask));
+
 		server->acl_bitmask = res.acl_bitmask;
 		server->fh_expire_type = res.fh_expire_type;
 	}
@@ -8173,6 +8179,12 @@
 		/* fall through */
 	case -NFS4ERR_RETRY_UNCACHED_REP:
 		return -EAGAIN;
+	case -NFS4ERR_BADSESSION:
+	case -NFS4ERR_DEADSESSION:
+	case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
+		nfs4_schedule_session_recovery(clp->cl_session,
+				task->tk_status);
+		break;
 	default:
 		nfs4_schedule_lease_recovery(clp);
 	}
@@ -8251,7 +8263,6 @@
 	if (status == 0)
 		status = task->tk_status;
 	rpc_put_task(task);
-	return 0;
 out:
 	dprintk("<-- %s status=%d\n", __func__, status);
 	return status;
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 71deeae..0bb0e62 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -1637,13 +1637,14 @@
 	nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_reboot);
 }
 
-static void nfs4_reclaim_complete(struct nfs_client *clp,
+static int nfs4_reclaim_complete(struct nfs_client *clp,
 				 const struct nfs4_state_recovery_ops *ops,
 				 struct rpc_cred *cred)
 {
 	/* Notify the server we're done reclaiming our state */
 	if (ops->reclaim_complete)
-		(void)ops->reclaim_complete(clp, cred);
+		return ops->reclaim_complete(clp, cred);
+	return 0;
 }
 
 static void nfs4_clear_reclaim_server(struct nfs_server *server)
@@ -1690,13 +1691,16 @@
 {
 	const struct nfs4_state_recovery_ops *ops;
 	struct rpc_cred *cred;
+	int err;
 
 	if (!nfs4_state_clear_reclaim_reboot(clp))
 		return;
 	ops = clp->cl_mvops->reboot_recovery_ops;
 	cred = nfs4_get_clid_cred(clp);
-	nfs4_reclaim_complete(clp, ops, cred);
+	err = nfs4_reclaim_complete(clp, ops, cred);
 	put_rpccred(cred);
+	if (err == -NFS4ERR_CONN_NOT_BOUND_TO_SESSION)
+		set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
 }
 
 static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp)
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index e0e5f7c..8a459b1 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -92,7 +92,7 @@
 				       u32 event_mask,
 				       void *data, int data_type)
 {
-	__u32 marks_mask, marks_ignored_mask;
+	__u32 marks_mask = 0, marks_ignored_mask = 0;
 	struct path *path = data;
 
 	pr_debug("%s: inode_mark=%p vfsmnt_mark=%p mask=%x data=%p"
@@ -108,24 +108,20 @@
 	    !d_can_lookup(path->dentry))
 		return false;
 
-	if (inode_mark && vfsmnt_mark) {
-		marks_mask = (vfsmnt_mark->mask | inode_mark->mask);
-		marks_ignored_mask = (vfsmnt_mark->ignored_mask | inode_mark->ignored_mask);
-	} else if (inode_mark) {
-		/*
-		 * if the event is for a child and this inode doesn't care about
-		 * events on the child, don't send it!
-		 */
-		if ((event_mask & FS_EVENT_ON_CHILD) &&
-		    !(inode_mark->mask & FS_EVENT_ON_CHILD))
-			return false;
-		marks_mask = inode_mark->mask;
-		marks_ignored_mask = inode_mark->ignored_mask;
-	} else if (vfsmnt_mark) {
-		marks_mask = vfsmnt_mark->mask;
-		marks_ignored_mask = vfsmnt_mark->ignored_mask;
-	} else {
-		BUG();
+	/*
+	 * if the event is for a child and this inode doesn't care about
+	 * events on the child, don't send it!
+	 */
+	if (inode_mark &&
+	    (!(event_mask & FS_EVENT_ON_CHILD) ||
+	     (inode_mark->mask & FS_EVENT_ON_CHILD))) {
+		marks_mask |= inode_mark->mask;
+		marks_ignored_mask |= inode_mark->ignored_mask;
+	}
+
+	if (vfsmnt_mark) {
+		marks_mask |= vfsmnt_mark->mask;
+		marks_ignored_mask |= vfsmnt_mark->ignored_mask;
 	}
 
 	if (d_is_dir(path->dentry) &&
diff --git a/fs/orangefs/super.c b/fs/orangefs/super.c
index 629d8c9..6e35ef6 100644
--- a/fs/orangefs/super.c
+++ b/fs/orangefs/super.c
@@ -559,6 +559,11 @@
 	/* provided sb cleanup */
 	kill_anon_super(sb);
 
+	if (!ORANGEFS_SB(sb)) {
+		mutex_lock(&orangefs_request_mutex);
+		mutex_unlock(&orangefs_request_mutex);
+		return;
+	}
 	/*
 	 * issue the unmount to userspace to tell it to remove the
 	 * dynamic mount info it has for this superblock
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 306b6c1..8546384 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -180,6 +180,9 @@
 		inc_nlink(inode);
 	}
 	d_instantiate(dentry, inode);
+	/* Force lookup of new upper hardlink to find its lower */
+	if (hardlink)
+		d_drop(dentry);
 }
 
 static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 7fb53d0..16f6db8 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -227,6 +227,16 @@
 	return res;
 }
 
+static bool ovl_can_list(const char *s)
+{
+	/* List all non-trusted xatts */
+	if (strncmp(s, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) != 0)
+		return true;
+
+	/* Never list trusted.overlay, list other trusted for superuser only */
+	return !ovl_is_private_xattr(s) && capable(CAP_SYS_ADMIN);
+}
+
 ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
 {
 	struct dentry *realdentry = ovl_dentry_real(dentry);
@@ -250,7 +260,7 @@
 			return -EIO;
 
 		len -= slen;
-		if (ovl_is_private_xattr(s)) {
+		if (!ovl_can_list(s)) {
 			res -= slen;
 			memmove(s, s + slen, len);
 		} else {
diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig
index 1ade120..08dce22 100644
--- a/fs/proc/Kconfig
+++ b/fs/proc/Kconfig
@@ -81,3 +81,10 @@
 
 	  Say Y if you are running any user-space software which takes benefit from
 	  this interface. For example, rkt is such a piece of software.
+
+config PROC_UID
+	bool "Include /proc/uid/ files"
+	default y
+	depends on PROC_FS && RT_MUTEXES
+	help
+	Provides aggregated per-uid information under /proc/uid.
diff --git a/fs/proc/Makefile b/fs/proc/Makefile
index 12c6922..dea53ba 100644
--- a/fs/proc/Makefile
+++ b/fs/proc/Makefile
@@ -25,6 +25,7 @@
 proc-y	+= namespaces.o
 proc-y	+= self.o
 proc-y	+= thread_self.o
+proc-$(CONFIG_PROC_UID)  += uid.o
 proc-$(CONFIG_PROC_SYSCTL)	+= proc_sysctl.o
 proc-$(CONFIG_NET)		+= proc_net.o
 proc-$(CONFIG_PROC_KCORE)	+= kcore.o
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 1370a4e..abe157a5 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -87,6 +87,7 @@
 #include <linux/slab.h>
 #include <linux/flex_array.h>
 #include <linux/posix-timers.h>
+#include <linux/cpufreq_times.h>
 #ifdef CONFIG_HARDWALL
 #include <asm/hardwall.h>
 #endif
@@ -3166,8 +3167,8 @@
 	ONE("cgroup",  S_IRUGO, proc_cgroup_show),
 #endif
 	ONE("oom_score",  S_IRUGO, proc_oom_score),
-	REG("oom_adj",    S_IRUSR, proc_oom_adj_operations),
-	REG("oom_score_adj", S_IRUSR, proc_oom_score_adj_operations),
+	REG("oom_adj",    S_IRUGO|S_IWUSR, proc_oom_adj_operations),
+	REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
 #ifdef CONFIG_AUDITSYSCALL
 	REG("loginuid",   S_IWUSR|S_IRUGO, proc_loginuid_operations),
 	REG("sessionid",  S_IRUGO, proc_sessionid_operations),
@@ -3198,6 +3199,9 @@
 	REG("timers",	  S_IRUGO, proc_timers_operations),
 #endif
 	REG("timerslack_ns", S_IRUGO|S_IWUGO, proc_pid_set_timerslack_ns_operations),
+#ifdef CONFIG_CPU_FREQ_TIMES
+	ONE("time_in_state", 0444, proc_time_in_state_show),
+#endif
 };
 
 static int proc_tgid_base_readdir(struct file *file, struct dir_context *ctx)
@@ -3561,8 +3565,8 @@
 	ONE("cgroup",  S_IRUGO, proc_cgroup_show),
 #endif
 	ONE("oom_score", S_IRUGO, proc_oom_score),
-	REG("oom_adj",   S_IRUSR, proc_oom_adj_operations),
-	REG("oom_score_adj", S_IRUSR, proc_oom_score_adj_operations),
+	REG("oom_adj",   S_IRUGO|S_IWUSR, proc_oom_adj_operations),
+	REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
 #ifdef CONFIG_AUDITSYSCALL
 	REG("loginuid",  S_IWUSR|S_IRUGO, proc_loginuid_operations),
 	REG("sessionid",  S_IRUGO, proc_sessionid_operations),
@@ -3586,6 +3590,9 @@
 	REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations),
 	REG("setgroups",  S_IRUGO|S_IWUSR, proc_setgroups_operations),
 #endif
+#ifdef CONFIG_CPU_FREQ_TIMES
+	ONE("time_in_state", 0444, proc_time_in_state_show),
+#endif
 };
 
 static int proc_tid_base_readdir(struct file *file, struct dir_context *ctx)
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 6dfb414..d8105cd 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -257,6 +257,15 @@
 #endif
 
 /*
+ * uid.c
+ */
+#ifdef CONFIG_PROC_UID
+extern int proc_uid_init(void);
+#else
+static inline void proc_uid_init(void) { }
+#endif
+
+/*
  * proc_tty.c
  */
 #ifdef CONFIG_TTY
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 8d3e484..c2f5014 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -131,7 +131,7 @@
 	proc_symlink("mounts", NULL, "self/mounts");
 
 	proc_net_init();
-
+	proc_uid_init();
 #ifdef CONFIG_SYSVIPC
 	proc_mkdir("sysvipc", NULL);
 #endif
diff --git a/fs/proc/uid.c b/fs/proc/uid.c
new file mode 100644
index 0000000..3fd7b9f
--- /dev/null
+++ b/fs/proc/uid.c
@@ -0,0 +1,295 @@
+/*
+ * /proc/uid support
+ */
+
+#include <linux/cpufreq_times.h>
+#include <linux/fs.h>
+#include <linux/hashtable.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/rtmutex.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include "internal.h"
+
+static struct proc_dir_entry *proc_uid;
+
+#define UID_HASH_BITS 10
+
+static DECLARE_HASHTABLE(proc_uid_hash_table, UID_HASH_BITS);
+
+/*
+ * use rt_mutex here to avoid priority inversion between high-priority readers
+ * of these files and tasks calling proc_register_uid().
+ */
+static DEFINE_RT_MUTEX(proc_uid_lock); /* proc_uid_hash_table */
+
+struct uid_hash_entry {
+	uid_t uid;
+	struct hlist_node hash;
+};
+
+/* Caller must hold proc_uid_lock */
+static bool uid_hash_entry_exists_locked(uid_t uid)
+{
+	struct uid_hash_entry *entry;
+
+	hash_for_each_possible(proc_uid_hash_table, entry, hash, uid) {
+		if (entry->uid == uid)
+			return true;
+	}
+	return false;
+}
+
+void proc_register_uid(kuid_t kuid)
+{
+	struct uid_hash_entry *entry;
+	bool exists;
+	uid_t uid = from_kuid_munged(current_user_ns(), kuid);
+
+	rt_mutex_lock(&proc_uid_lock);
+	exists = uid_hash_entry_exists_locked(uid);
+	rt_mutex_unlock(&proc_uid_lock);
+	if (exists)
+		return;
+
+	entry = kzalloc(sizeof(struct uid_hash_entry), GFP_KERNEL);
+	if (!entry)
+		return;
+	entry->uid = uid;
+
+	rt_mutex_lock(&proc_uid_lock);
+	if (uid_hash_entry_exists_locked(uid))
+		kfree(entry);
+	else
+		hash_add(proc_uid_hash_table, &entry->hash, uid);
+	rt_mutex_unlock(&proc_uid_lock);
+}
+
+struct uid_entry {
+	const char *name;
+	int len;
+	umode_t mode;
+	const struct inode_operations *iop;
+	const struct file_operations *fop;
+};
+
+#define NOD(NAME, MODE, IOP, FOP) {			\
+	.name	= (NAME),				\
+	.len	= sizeof(NAME) - 1,			\
+	.mode	= MODE,					\
+	.iop	= IOP,					\
+	.fop	= FOP,					\
+}
+
+#ifdef CONFIG_CPU_FREQ_TIMES
+static const struct file_operations proc_uid_time_in_state_operations = {
+	.open		= single_uid_time_in_state_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+#endif
+
+static const struct uid_entry uid_base_stuff[] = {
+#ifdef CONFIG_CPU_FREQ_TIMES
+	NOD("time_in_state", 0444, NULL, &proc_uid_time_in_state_operations),
+#endif
+};
+
+static const struct inode_operations proc_uid_def_inode_operations = {
+	.setattr	= proc_setattr,
+};
+
+static struct inode *proc_uid_make_inode(struct super_block *sb, kuid_t kuid)
+{
+	struct inode *inode;
+
+	inode = new_inode(sb);
+	if (!inode)
+		return NULL;
+
+	inode->i_ino = get_next_ino();
+	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+	inode->i_op = &proc_uid_def_inode_operations;
+	inode->i_uid = kuid;
+
+	return inode;
+}
+
+static int proc_uident_instantiate(struct inode *dir, struct dentry *dentry,
+				   struct task_struct *unused, const void *ptr)
+{
+	const struct uid_entry *u = ptr;
+	struct inode *inode;
+
+	inode = proc_uid_make_inode(dir->i_sb, dir->i_uid);
+	if (!inode)
+		return -ENOENT;
+
+	inode->i_mode = u->mode;
+	if (S_ISDIR(inode->i_mode))
+		set_nlink(inode, 2);
+	if (u->iop)
+		inode->i_op = u->iop;
+	if (u->fop)
+		inode->i_fop = u->fop;
+	d_add(dentry, inode);
+	return 0;
+}
+
+static struct dentry *proc_uid_base_lookup(struct inode *dir,
+					   struct dentry *dentry,
+					   unsigned int flags)
+{
+	const struct uid_entry *u, *last;
+	unsigned int nents = ARRAY_SIZE(uid_base_stuff);
+
+	if (nents == 0)
+		return ERR_PTR(-ENOENT);
+
+	last = &uid_base_stuff[nents - 1];
+	for (u = uid_base_stuff; u <= last; u++) {
+		if (u->len != dentry->d_name.len)
+			continue;
+		if (!memcmp(dentry->d_name.name, u->name, u->len))
+			break;
+	}
+	if (u > last)
+		return ERR_PTR(-ENOENT);
+
+	return ERR_PTR(proc_uident_instantiate(dir, dentry, NULL, u));
+}
+
+static int proc_uid_base_readdir(struct file *file, struct dir_context *ctx)
+{
+	unsigned int nents = ARRAY_SIZE(uid_base_stuff);
+	const struct uid_entry *u;
+
+	if (!dir_emit_dots(file, ctx))
+		return 0;
+
+	if (ctx->pos >= nents + 2)
+		return 0;
+
+	for (u = uid_base_stuff + (ctx->pos - 2);
+	     u <= uid_base_stuff + nents - 1; u++) {
+		if (!proc_fill_cache(file, ctx, u->name, u->len,
+				     proc_uident_instantiate, NULL, u))
+			break;
+		ctx->pos++;
+	}
+
+	return 0;
+}
+
+static const struct inode_operations proc_uid_base_inode_operations = {
+	.lookup		= proc_uid_base_lookup,
+	.setattr	= proc_setattr,
+};
+
+static const struct file_operations proc_uid_base_operations = {
+	.read		= generic_read_dir,
+	.iterate	= proc_uid_base_readdir,
+	.llseek		= default_llseek,
+};
+
+static int proc_uid_instantiate(struct inode *dir, struct dentry *dentry,
+				struct task_struct *unused, const void *ptr)
+{
+	unsigned int i, len;
+	nlink_t nlinks;
+	kuid_t *kuid = (kuid_t *)ptr;
+	struct inode *inode = proc_uid_make_inode(dir->i_sb, *kuid);
+
+	if (!inode)
+		return -ENOENT;
+
+	inode->i_mode = S_IFDIR | 0555;
+	inode->i_op = &proc_uid_base_inode_operations;
+	inode->i_fop = &proc_uid_base_operations;
+	inode->i_flags |= S_IMMUTABLE;
+
+	nlinks = 2;
+	len = ARRAY_SIZE(uid_base_stuff);
+	for (i = 0; i < len; ++i) {
+		if (S_ISDIR(uid_base_stuff[i].mode))
+			++nlinks;
+	}
+	set_nlink(inode, nlinks);
+
+	d_add(dentry, inode);
+
+	return 0;
+}
+
+static int proc_uid_readdir(struct file *file, struct dir_context *ctx)
+{
+	int last_shown, i;
+	unsigned long bkt;
+	struct uid_hash_entry *entry;
+
+	if (!dir_emit_dots(file, ctx))
+		return 0;
+
+	i = 0;
+	last_shown = ctx->pos - 2;
+	rt_mutex_lock(&proc_uid_lock);
+	hash_for_each(proc_uid_hash_table, bkt, entry, hash) {
+		int len;
+		char buf[PROC_NUMBUF];
+
+		if (i < last_shown)
+			continue;
+		len = snprintf(buf, sizeof(buf), "%u", entry->uid);
+		if (!proc_fill_cache(file, ctx, buf, len,
+				     proc_uid_instantiate, NULL, &entry->uid))
+			break;
+		i++;
+		ctx->pos++;
+	}
+	rt_mutex_unlock(&proc_uid_lock);
+	return 0;
+}
+
+static struct dentry *proc_uid_lookup(struct inode *dir, struct dentry *dentry,
+				      unsigned int flags)
+{
+	int result = -ENOENT;
+
+	uid_t uid = name_to_int(&dentry->d_name);
+	bool uid_exists;
+
+	rt_mutex_lock(&proc_uid_lock);
+	uid_exists = uid_hash_entry_exists_locked(uid);
+	rt_mutex_unlock(&proc_uid_lock);
+	if (uid_exists) {
+		kuid_t kuid = make_kuid(current_user_ns(), uid);
+
+		result = proc_uid_instantiate(dir, dentry, NULL, &kuid);
+	}
+	return ERR_PTR(result);
+}
+
+static const struct file_operations proc_uid_operations = {
+	.read		= generic_read_dir,
+	.iterate	= proc_uid_readdir,
+	.llseek		= default_llseek,
+};
+
+static const struct inode_operations proc_uid_inode_operations = {
+	.lookup		= proc_uid_lookup,
+	.setattr	= proc_setattr,
+};
+
+int __init proc_uid_init(void)
+{
+	proc_uid = proc_mkdir("uid", NULL);
+	if (!proc_uid)
+		return -ENOMEM;
+	proc_uid->proc_iops = &proc_uid_inode_operations;
+	proc_uid->proc_fops = &proc_uid_operations;
+
+	return 0;
+}
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index 7610818..2a5c481 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -2640,7 +2640,7 @@
 	if (IS_ERR(journal->j_dev_bd)) {
 		result = PTR_ERR(journal->j_dev_bd);
 		journal->j_dev_bd = NULL;
-		reiserfs_warning(super,
+		reiserfs_warning(super, "sh-457",
 				 "journal_init_dev: Cannot open '%s': %i",
 				 jdev_name, result);
 		return result;
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 4ec05108..03dda1c 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -1728,8 +1728,11 @@
 
 	dbg_save_space_info(c);
 
-	for (i = 0; i < c->jhead_cnt; i++)
-		ubifs_wbuf_sync(&c->jheads[i].wbuf);
+	for (i = 0; i < c->jhead_cnt; i++) {
+		err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
+		if (err)
+			ubifs_ro_mode(c, err);
+	}
 
 	c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY);
 	c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS);
@@ -1795,8 +1798,11 @@
 			int err;
 
 			/* Synchronize write-buffers */
-			for (i = 0; i < c->jhead_cnt; i++)
-				ubifs_wbuf_sync(&c->jheads[i].wbuf);
+			for (i = 0; i < c->jhead_cnt; i++) {
+				err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
+				if (err)
+					ubifs_ro_mode(c, err);
+			}
 
 			/*
 			 * We are being cleanly unmounted which means the
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c
index 695389a..3a3be23 100644
--- a/fs/udf/unicode.c
+++ b/fs/udf/unicode.c
@@ -28,6 +28,9 @@
 
 #include "udf_sb.h"
 
+#define SURROGATE_MASK 0xfffff800
+#define SURROGATE_PAIR 0x0000d800
+
 static int udf_uni2char_utf8(wchar_t uni,
 			     unsigned char *out,
 			     int boundlen)
@@ -37,6 +40,9 @@
 	if (boundlen <= 0)
 		return -ENAMETOOLONG;
 
+	if ((uni & SURROGATE_MASK) == SURROGATE_PAIR)
+		return -EINVAL;
+
 	if (uni < 0x80) {
 		out[u_len++] = (unsigned char)uni;
 	} else if (uni < 0x800) {
diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h
index 8f66aaa..9e3f761 100644
--- a/include/acpi/platform/acgcc.h
+++ b/include/acpi/platform/acgcc.h
@@ -48,7 +48,17 @@
  * Use compiler specific <stdarg.h> is a good practice for even when
  * -nostdinc is specified (i.e., ACPI_USE_STANDARD_HEADERS undefined.
  */
+#ifndef va_arg
+#ifdef ACPI_USE_BUILTIN_STDARG
+typedef __builtin_va_list va_list;
+#define va_start(v, l)          __builtin_va_start(v, l)
+#define va_end(v)               __builtin_va_end(v)
+#define va_arg(v, l)            __builtin_va_arg(v, l)
+#define va_copy(d, s)           __builtin_va_copy(d, s)
+#else
 #include <stdarg.h>
+#endif
+#endif
 
 #define ACPI_INLINE             __inline__
 
diff --git a/include/acpi/platform/acintel.h b/include/acpi/platform/acintel.h
index 17bd3b7..bdb6858 100644
--- a/include/acpi/platform/acintel.h
+++ b/include/acpi/platform/acintel.h
@@ -48,7 +48,9 @@
  * Use compiler specific <stdarg.h> is a good practice for even when
  * -nostdinc is specified (i.e., ACPI_USE_STANDARD_HEADERS undefined.
  */
+#ifndef va_arg
 #include <stdarg.h>
+#endif
 
 /* Configuration specific to Intel 64-bit C compiler */
 
diff --git a/include/crypto/ice.h b/include/crypto/ice.h
index b02a440..133041e 100644
--- a/include/crypto/ice.h
+++ b/include/crypto/ice.h
@@ -53,16 +53,22 @@
 
 struct qcom_ice_variant_ops *qcom_ice_get_variant_ops(struct device_node *node);
 struct platform_device *qcom_ice_get_pdevice(struct device_node *node);
-void qcom_ice_set_fde_flag(int flag);
-int qcom_ice_set_fde_conf(sector_t strt, sector_t size, int idx, int mode);
 
 #ifdef CONFIG_CRYPTO_DEV_QCOM_ICE
 int qcom_ice_setup_ice_hw(const char *storage_type, int enable);
+void qcom_ice_set_fde_flag(int flag);
+int qcom_ice_set_fde_conf(sector_t strt, sector_t size, int idx, int mode);
 #else
 static inline int qcom_ice_setup_ice_hw(const char *storage_type, int enable)
 {
 	return 0;
 }
+static inline void qcom_ice_set_fde_flag(int flag) {}
+static inline int qcom_ice_set_fde_conf(sector_t strt, sector_t size, int idx,
+					int mode)
+{
+	return 0;
+}
 #endif
 
 struct qcom_ice_variant_ops {
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index 3c2024d..328f232 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -32,6 +32,7 @@
  * @type: payload data type
  * @flags: flags controlling this message transmission
  * @ctrl: ctrl index to transmit on
+ * @wait_ms: duration in ms to wait after message transmission
  * @tx_len: length of @tx_buf
  * @tx_buf: data to be written
  * @rx_len: length of @rx_buf
@@ -42,6 +43,7 @@
 	u8 type;
 	u16 flags;
 	u32 ctrl;
+	u32 wait_ms;
 
 	size_t tx_len;
 	const void *tx_buf;
diff --git a/include/dt-bindings/arm/arm-smmu.h b/include/dt-bindings/arm/arm-smmu.h
index 3a1dbd3..1de45a9 100644
--- a/include/dt-bindings/arm/arm-smmu.h
+++ b/include/dt-bindings/arm/arm-smmu.h
@@ -23,5 +23,6 @@
 #define ARM_SMMU_OPT_MMU500_ERRATA1	(1 << 7)
 #define ARM_SMMU_OPT_STATIC_CB          (1 << 8)
 #define ARM_SMMU_OPT_HALT               (1 << 9)
+#define ARM_SMMU_OPT_HIBERNATION	(1 << 10)
 
 #endif
diff --git a/include/dt-bindings/clock/mt2701-clk.h b/include/dt-bindings/clock/mt2701-clk.h
index 2062c67..a72db8d 100644
--- a/include/dt-bindings/clock/mt2701-clk.h
+++ b/include/dt-bindings/clock/mt2701-clk.h
@@ -176,7 +176,8 @@
 #define CLK_TOP_AUD_EXT1			156
 #define CLK_TOP_AUD_EXT2			157
 #define CLK_TOP_NFI1X_PAD			158
-#define CLK_TOP_NR				159
+#define CLK_TOP_AXISEL_D4			159
+#define CLK_TOP_NR				160
 
 /* APMIXEDSYS */
 
diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
new file mode 100644
index 0000000..e518e4e
--- /dev/null
+++ b/include/kvm/arm_psci.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __KVM_ARM_PSCI_H__
+#define __KVM_ARM_PSCI_H__
+
+#include <linux/kvm_host.h>
+#include <uapi/linux/psci.h>
+
+#define KVM_ARM_PSCI_0_1	PSCI_VERSION(0, 1)
+#define KVM_ARM_PSCI_0_2	PSCI_VERSION(0, 2)
+#define KVM_ARM_PSCI_1_0	PSCI_VERSION(1, 0)
+
+#define KVM_ARM_PSCI_LATEST	KVM_ARM_PSCI_1_0
+
+/*
+ * We need the KVM pointer independently from the vcpu as we can call
+ * this from HYP, and need to apply kern_hyp_va on it...
+ */
+static inline int kvm_psci_version(struct kvm_vcpu *vcpu, struct kvm *kvm)
+{
+	/*
+	 * Our PSCI implementation stays the same across versions from
+	 * v0.2 onward, only adding the few mandatory functions (such
+	 * as FEATURES with 1.0) that are required by newer
+	 * revisions. It is thus safe to return the latest.
+	 */
+	if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
+		return KVM_ARM_PSCI_LATEST;
+
+	return KVM_ARM_PSCI_0_1;
+}
+
+
+int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
+
+#endif /* __KVM_ARM_PSCI_H__ */
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index 4c5bca38..43690f5 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -14,14 +14,16 @@
 #ifndef __LINUX_ARM_SMCCC_H
 #define __LINUX_ARM_SMCCC_H
 
+#include <uapi/linux/const.h>
+
 /*
  * This file provides common defines for ARM SMC Calling Convention as
  * specified in
  * http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
  */
 
-#define ARM_SMCCC_STD_CALL		0
-#define ARM_SMCCC_FAST_CALL		1
+#define ARM_SMCCC_STD_CALL	        _AC(0,U)
+#define ARM_SMCCC_FAST_CALL	        _AC(1,U)
 #define ARM_SMCCC_TYPE_SHIFT		31
 
 #define ARM_SMCCC_SMC_32		0
@@ -60,6 +62,24 @@
 #define ARM_SMCCC_QUIRK_NONE		0
 #define ARM_SMCCC_QUIRK_QCOM_A6		1 /* Save/restore register a6 */
 
+#define ARM_SMCCC_VERSION_1_0		0x10000
+#define ARM_SMCCC_VERSION_1_1		0x10001
+
+#define ARM_SMCCC_VERSION_FUNC_ID					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 0)
+
+#define ARM_SMCCC_ARCH_FEATURES_FUNC_ID					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 1)
+
+#define ARM_SMCCC_ARCH_WORKAROUND_1					\
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,				\
+			   ARM_SMCCC_SMC_32,				\
+			   0, 0x8000)
+
 #ifndef __ASSEMBLY__
 
 #include <linux/linkage.h>
@@ -130,5 +150,148 @@
 
 #define arm_smccc_hvc_quirk(...) __arm_smccc_hvc(__VA_ARGS__)
 
+/* SMCCC v1.1 implementation madness follows */
+#ifdef CONFIG_ARM64
+
+#define SMCCC_SMC_INST	"smc	#0"
+#define SMCCC_HVC_INST	"hvc	#0"
+#define SMCCC_REG(n)	asm("x" # n)
+
+#elif defined(CONFIG_ARM)
+#include <asm/opcodes-sec.h>
+#include <asm/opcodes-virt.h>
+
+#define SMCCC_SMC_INST	__SMC(0)
+#define SMCCC_HVC_INST	__HVC(0)
+#define SMCCC_REG(n)	asm("r" # n)
+
+#endif
+
+#define ___count_args(_0, _1, _2, _3, _4, _5, _6, _7, _8, x, ...) x
+
+#define __count_args(...)						\
+	___count_args(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0)
+
+#define __constraint_write_0						\
+	"+r" (r0), "=&r" (r1), "=&r" (r2), "=&r" (r3)
+#define __constraint_write_1						\
+	"+r" (r0), "+r" (r1), "=&r" (r2), "=&r" (r3)
+#define __constraint_write_2						\
+	"+r" (r0), "+r" (r1), "+r" (r2), "=&r" (r3)
+#define __constraint_write_3						\
+	"+r" (r0), "+r" (r1), "+r" (r2), "+r" (r3)
+#define __constraint_write_4	__constraint_write_3
+#define __constraint_write_5	__constraint_write_4
+#define __constraint_write_6	__constraint_write_5
+#define __constraint_write_7	__constraint_write_6
+
+#define __constraint_read_0
+#define __constraint_read_1
+#define __constraint_read_2
+#define __constraint_read_3
+#define __constraint_read_4	"r" (r4)
+#define __constraint_read_5	__constraint_read_4, "r" (r5)
+#define __constraint_read_6	__constraint_read_5, "r" (r6)
+#define __constraint_read_7	__constraint_read_6, "r" (r7)
+
+#define __declare_arg_0(a0, res)					\
+	struct arm_smccc_res   *___res = res;				\
+	register u32           r0 SMCCC_REG(0) = a0;			\
+	register unsigned long r1 SMCCC_REG(1);				\
+	register unsigned long r2 SMCCC_REG(2);				\
+	register unsigned long r3 SMCCC_REG(3)
+
+#define __declare_arg_1(a0, a1, res)					\
+	struct arm_smccc_res   *___res = res;				\
+	register u32           r0 SMCCC_REG(0) = a0;			\
+	register typeof(a1)    r1 SMCCC_REG(1) = a1;			\
+	register unsigned long r2 SMCCC_REG(2);				\
+	register unsigned long r3 SMCCC_REG(3)
+
+#define __declare_arg_2(a0, a1, a2, res)				\
+	struct arm_smccc_res   *___res = res;				\
+	register u32           r0 SMCCC_REG(0) = a0;			\
+	register typeof(a1)    r1 SMCCC_REG(1) = a1;			\
+	register typeof(a2)    r2 SMCCC_REG(2) = a2;			\
+	register unsigned long r3 SMCCC_REG(3)
+
+#define __declare_arg_3(a0, a1, a2, a3, res)				\
+	struct arm_smccc_res   *___res = res;				\
+	register u32           r0 SMCCC_REG(0) = a0;			\
+	register typeof(a1)    r1 SMCCC_REG(1) = a1;			\
+	register typeof(a2)    r2 SMCCC_REG(2) = a2;			\
+	register typeof(a3)    r3 SMCCC_REG(3) = a3
+
+#define __declare_arg_4(a0, a1, a2, a3, a4, res)			\
+	__declare_arg_3(a0, a1, a2, a3, res);				\
+	register typeof(a4) r4 SMCCC_REG(4) = a4
+
+#define __declare_arg_5(a0, a1, a2, a3, a4, a5, res)			\
+	__declare_arg_4(a0, a1, a2, a3, a4, res);			\
+	register typeof(a5) r5 SMCCC_REG(5) = a5
+
+#define __declare_arg_6(a0, a1, a2, a3, a4, a5, a6, res)		\
+	__declare_arg_5(a0, a1, a2, a3, a4, a5, res);			\
+	register typeof(a6) r6 SMCCC_REG(6) = a6
+
+#define __declare_arg_7(a0, a1, a2, a3, a4, a5, a6, a7, res)		\
+	__declare_arg_6(a0, a1, a2, a3, a4, a5, a6, res);		\
+	register typeof(a7) r7 SMCCC_REG(7) = a7
+
+#define ___declare_args(count, ...) __declare_arg_ ## count(__VA_ARGS__)
+#define __declare_args(count, ...)  ___declare_args(count, __VA_ARGS__)
+
+#define ___constraints(count)						\
+	: __constraint_write_ ## count					\
+	: __constraint_read_ ## count					\
+	: "memory"
+#define __constraints(count)	___constraints(count)
+
+/*
+ * We have an output list that is not necessarily used, and GCC feels
+ * entitled to optimise the whole sequence away. "volatile" is what
+ * makes it stick.
+ */
+#define __arm_smccc_1_1(inst, ...)					\
+	do {								\
+		__declare_args(__count_args(__VA_ARGS__), __VA_ARGS__);	\
+		asm volatile(inst "\n"					\
+			     __constraints(__count_args(__VA_ARGS__)));	\
+		if (___res)						\
+			*___res = (typeof(*___res)){r0, r1, r2, r3};	\
+	} while (0)
+
+/*
+ * arm_smccc_1_1_smc() - make an SMCCC v1.1 compliant SMC call
+ *
+ * This is a variadic macro taking one to eight source arguments, and
+ * an optional return structure.
+ *
+ * @a0-a7: arguments passed in registers 0 to 7
+ * @res: result values from registers 0 to 3
+ *
+ * This macro is used to make SMC calls following SMC Calling Convention v1.1.
+ * The content of the supplied param are copied to registers 0 to 7 prior
+ * to the SMC instruction. The return values are updated with the content
+ * from register 0 to 3 on return from the SMC instruction if not NULL.
+ */
+#define arm_smccc_1_1_smc(...)	__arm_smccc_1_1(SMCCC_SMC_INST, __VA_ARGS__)
+
+/*
+ * arm_smccc_1_1_hvc() - make an SMCCC v1.1 compliant HVC call
+ *
+ * This is a variadic macro taking one to eight source arguments, and
+ * an optional return structure.
+ *
+ * @a0-a7: arguments passed in registers 0 to 7
+ * @res: result values from registers 0 to 3
+ *
+ * This macro is used to make HVC calls following SMC Calling Convention v1.1.
+ * The content of the supplied param are copied to registers 0 to 7 prior
+ * to the HVC instruction. The return values are updated with the content
+ * from register 0 to 3 on return from the HVC instruction if not NULL.
+ */
+#define arm_smccc_1_1_hvc(...)	__arm_smccc_1_1(SMCCC_HVC_INST, __VA_ARGS__)
+
 #endif /*__ASSEMBLY__*/
 #endif /*__LINUX_ARM_SMCCC_H*/
diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h
index 0691068..002f87c 100644
--- a/include/linux/backing-dev-defs.h
+++ b/include/linux/backing-dev-defs.h
@@ -195,6 +195,11 @@
 	set_wb_congested(bdi->wb.congested, sync);
 }
 
+struct wb_lock_cookie {
+	bool locked;
+	unsigned long flags;
+};
+
 #ifdef CONFIG_CGROUP_WRITEBACK
 
 /**
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index c52a48c..8272fcf7 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -374,7 +374,7 @@
 /**
  * unlocked_inode_to_wb_begin - begin unlocked inode wb access transaction
  * @inode: target inode
- * @lockedp: temp bool output param, to be passed to the end function
+ * @cookie: output param, to be passed to the end function
  *
  * The caller wants to access the wb associated with @inode but isn't
  * holding inode->i_lock, mapping->tree_lock or wb->list_lock.  This
@@ -382,12 +382,12 @@
  * association doesn't change until the transaction is finished with
  * unlocked_inode_to_wb_end().
  *
- * The caller must call unlocked_inode_to_wb_end() with *@lockdep
- * afterwards and can't sleep during transaction.  IRQ may or may not be
- * disabled on return.
+ * The caller must call unlocked_inode_to_wb_end() with *@cookie afterwards and
+ * can't sleep during the transaction.  IRQs may or may not be disabled on
+ * return.
  */
 static inline struct bdi_writeback *
-unlocked_inode_to_wb_begin(struct inode *inode, bool *lockedp)
+unlocked_inode_to_wb_begin(struct inode *inode, struct wb_lock_cookie *cookie)
 {
 	rcu_read_lock();
 
@@ -395,10 +395,10 @@
 	 * Paired with store_release in inode_switch_wb_work_fn() and
 	 * ensures that we see the new wb if we see cleared I_WB_SWITCH.
 	 */
-	*lockedp = smp_load_acquire(&inode->i_state) & I_WB_SWITCH;
+	cookie->locked = smp_load_acquire(&inode->i_state) & I_WB_SWITCH;
 
-	if (unlikely(*lockedp))
-		spin_lock_irq(&inode->i_mapping->tree_lock);
+	if (unlikely(cookie->locked))
+		spin_lock_irqsave(&inode->i_mapping->tree_lock, cookie->flags);
 
 	/*
 	 * Protected by either !I_WB_SWITCH + rcu_read_lock() or tree_lock.
@@ -410,12 +410,13 @@
 /**
  * unlocked_inode_to_wb_end - end inode wb access transaction
  * @inode: target inode
- * @locked: *@lockedp from unlocked_inode_to_wb_begin()
+ * @cookie: @cookie from unlocked_inode_to_wb_begin()
  */
-static inline void unlocked_inode_to_wb_end(struct inode *inode, bool locked)
+static inline void unlocked_inode_to_wb_end(struct inode *inode,
+					    struct wb_lock_cookie *cookie)
 {
-	if (unlikely(locked))
-		spin_unlock_irq(&inode->i_mapping->tree_lock);
+	if (unlikely(cookie->locked))
+		spin_unlock_irqrestore(&inode->i_mapping->tree_lock, cookie->flags);
 
 	rcu_read_unlock();
 }
@@ -462,12 +463,13 @@
 }
 
 static inline struct bdi_writeback *
-unlocked_inode_to_wb_begin(struct inode *inode, bool *lockedp)
+unlocked_inode_to_wb_begin(struct inode *inode, struct wb_lock_cookie *cookie)
 {
 	return inode_to_wb(inode);
 }
 
-static inline void unlocked_inode_to_wb_end(struct inode *inode, bool locked)
+static inline void unlocked_inode_to_wb_end(struct inode *inode,
+					    struct wb_lock_cookie *cookie)
 {
 }
 
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 2b8b6e0..e4d84d3 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -25,6 +25,7 @@
 struct bio {
 	struct bio		*bi_next;	/* request queue link */
 	struct block_device	*bi_bdev;
+	unsigned short		bi_write_hint;
 	int			bi_error;
 	unsigned int		bi_opf;		/* bottom bits req flags,
 						 * top bits REQ_OP. Use
diff --git a/include/linux/cpufreq_times.h b/include/linux/cpufreq_times.h
new file mode 100644
index 0000000..3fb3875
--- /dev/null
+++ b/include/linux/cpufreq_times.h
@@ -0,0 +1,40 @@
+/* drivers/cpufreq/cpufreq_times.c
+ *
+ * Copyright (C) 2018 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_CPUFREQ_TIMES_H
+#define _LINUX_CPUFREQ_TIMES_H
+
+#include <linux/cpufreq.h>
+#include <linux/cputime.h>
+#include <linux/pid.h>
+
+#ifdef CONFIG_CPU_FREQ_TIMES
+void cpufreq_task_times_init(struct task_struct *p);
+void cpufreq_task_times_exit(struct task_struct *p);
+int proc_time_in_state_show(struct seq_file *m, struct pid_namespace *ns,
+			    struct pid *pid, struct task_struct *p);
+void cpufreq_acct_update_power(struct task_struct *p, cputime_t cputime);
+void cpufreq_times_create_policy(struct cpufreq_policy *policy);
+void cpufreq_times_record_transition(struct cpufreq_freqs *freq);
+void cpufreq_task_times_remove_uids(uid_t uid_start, uid_t uid_end);
+int single_uid_time_in_state_open(struct inode *inode, struct file *file);
+#else
+static inline void cpufreq_times_create_policy(struct cpufreq_policy *policy) {}
+static inline void cpufreq_times_record_transition(
+	struct cpufreq_freqs *freq) {}
+static inline void cpufreq_task_times_remove_uids(uid_t uid_start,
+						  uid_t uid_end) {}
+#endif /* CONFIG_CPU_FREQ_TIMES */
+#endif /* _LINUX_CPUFREQ_TIMES_H */
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index b49f866..bd96bb2 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -695,6 +695,11 @@
 void free_cpumask_var(cpumask_var_t mask);
 void free_bootmem_cpumask_var(cpumask_var_t mask);
 
+static inline bool cpumask_available(cpumask_var_t mask)
+{
+	return mask != NULL;
+}
+
 #else
 typedef struct cpumask cpumask_var_t[1];
 
@@ -735,6 +740,11 @@
 static inline void free_bootmem_cpumask_var(cpumask_var_t mask)
 {
 }
+
+static inline bool cpumask_available(cpumask_var_t mask)
+{
+	return true;
+}
 #endif /* CONFIG_CPUMASK_OFFSTACK */
 
 /* It's common to want to use cpu_all_mask in struct member initializers,
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 3c7ec22..d9912e0 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -146,7 +146,7 @@
  * a new RANGE of SSIDs to the msg_mask_tbl.
  */
 #define MSG_MASK_TBL_CNT		26
-#define APPS_EVENT_LAST_ID		0x0C5A
+#define APPS_EVENT_LAST_ID		0x0C5B
 
 #define MSG_SSID_0			0
 #define MSG_SSID_0_LAST			125
@@ -896,7 +896,7 @@
 /* LOG CODES */
 static const uint32_t log_code_last_tbl[] = {
 	0x0,	/* EQUIP ID 0 */
-	0x1C68,	/* EQUIP ID 1 */
+	0x1C6A,	/* EQUIP ID 1 */
 	0x0,	/* EQUIP ID 2 */
 	0x0,	/* EQUIP ID 3 */
 	0x4910,	/* EQUIP ID 4 */
diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h
index 393b880..aa5db8b 100644
--- a/include/linux/f2fs_fs.h
+++ b/include/linux/f2fs_fs.h
@@ -21,6 +21,7 @@
 #define F2FS_BLKSIZE			4096	/* support only 4KB block */
 #define F2FS_BLKSIZE_BITS		12	/* bits for F2FS_BLKSIZE */
 #define F2FS_MAX_EXTENSION		64	/* # of extension entries */
+#define F2FS_EXTENSION_LEN		8	/* max size of extension */
 #define F2FS_BLK_ALIGN(x)	(((x) + F2FS_BLKSIZE - 1) >> F2FS_BLKSIZE_BITS)
 
 #define NULL_ADDR		((block_t)0)	/* used as block_t addresses */
@@ -38,10 +39,10 @@
 
 #define F2FS_MAX_QUOTAS		3
 
-#define F2FS_IO_SIZE(sbi)	(1 << (sbi)->write_io_size_bits) /* Blocks */
-#define F2FS_IO_SIZE_KB(sbi)	(1 << ((sbi)->write_io_size_bits + 2)) /* KB */
-#define F2FS_IO_SIZE_BYTES(sbi)	(1 << ((sbi)->write_io_size_bits + 12)) /* B */
-#define F2FS_IO_SIZE_BITS(sbi)	((sbi)->write_io_size_bits) /* power of 2 */
+#define F2FS_IO_SIZE(sbi)	(1 << F2FS_OPTION(sbi).write_io_size_bits) /* Blocks */
+#define F2FS_IO_SIZE_KB(sbi)	(1 << (F2FS_OPTION(sbi).write_io_size_bits + 2)) /* KB */
+#define F2FS_IO_SIZE_BYTES(sbi)	(1 << (F2FS_OPTION(sbi).write_io_size_bits + 12)) /* B */
+#define F2FS_IO_SIZE_BITS(sbi)	(F2FS_OPTION(sbi).write_io_size_bits) /* power of 2 */
 #define F2FS_IO_SIZE_MASK(sbi)	(F2FS_IO_SIZE(sbi) - 1)
 
 /* This flag is used by node and meta inodes, and by recovery */
@@ -101,7 +102,7 @@
 	__u8 uuid[16];			/* 128-bit uuid for volume */
 	__le16 volume_name[MAX_VOLUME_NAME];	/* volume name */
 	__le32 extension_count;		/* # of extensions below */
-	__u8 extension_list[F2FS_MAX_EXTENSION][8];	/* extension array */
+	__u8 extension_list[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN];/* extension array */
 	__le32 cp_payload;
 	__u8 version[VERSION_LEN];	/* the kernel version */
 	__u8 init_version[VERSION_LEN];	/* the initial kernel version */
@@ -110,12 +111,14 @@
 	__u8 encrypt_pw_salt[16];	/* Salt used for string2key algorithm */
 	struct f2fs_device devs[MAX_DEVICES];	/* device list */
 	__le32 qf_ino[F2FS_MAX_QUOTAS];	/* quota inode numbers */
-	__u8 reserved[315];		/* valid reserved region */
+	__u8 hot_ext_count;		/* # of hot file extension */
+	__u8 reserved[314];		/* valid reserved region */
 } __packed;
 
 /*
  * For checkpoint
  */
+#define CP_LARGE_NAT_BITMAP_FLAG	0x00000400
 #define CP_NOCRC_RECOVERY_FLAG	0x00000200
 #define CP_TRIMMED_FLAG		0x00000100
 #define CP_NAT_BITS_FLAG	0x00000080
@@ -302,6 +305,10 @@
  */
 #define NAT_ENTRY_PER_BLOCK (PAGE_SIZE / sizeof(struct f2fs_nat_entry))
 #define NAT_ENTRY_BITMAP_SIZE	((NAT_ENTRY_PER_BLOCK + 7) / 8)
+#define NAT_ENTRY_BITMAP_SIZE_ALIGNED				\
+	((NAT_ENTRY_BITMAP_SIZE + BITS_PER_LONG - 1) /		\
+	BITS_PER_LONG * BITS_PER_LONG)
+
 
 struct f2fs_nat_entry {
 	__u8 version;		/* latest version of cached nat entry */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index db3bdb2..8a3bdad 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -21,6 +21,7 @@
 #include <linux/mm_types.h>
 #include <linux/capability.h>
 #include <linux/semaphore.h>
+#include <linux/fcntl.h>
 #include <linux/fiemap.h>
 #include <linux/rculist_bl.h>
 #include <linux/atomic.h>
@@ -144,6 +145,9 @@
 /* File was opened by fanotify and shouldn't generate fanotify events */
 #define FMODE_NONOTIFY		((__force fmode_t)0x4000000)
 
+/* File is capable of returning -EAGAIN if I/O will block */
+#define FMODE_NOWAIT		((__force fmode_t)0x8000000)
+
 /*
  * Flag for rw_copy_check_uvector and compat_rw_copy_check_uvector
  * that indicates that they should check the contents of the iovec are
@@ -316,6 +320,18 @@
 struct address_space;
 struct writeback_control;
 
+/*
+ * Write life time hint values.
+ */
+enum rw_hint {
+	WRITE_LIFE_NOT_SET	= 0,
+	WRITE_LIFE_NONE		= RWH_WRITE_LIFE_NONE,
+	WRITE_LIFE_SHORT	= RWH_WRITE_LIFE_SHORT,
+	WRITE_LIFE_MEDIUM	= RWH_WRITE_LIFE_MEDIUM,
+	WRITE_LIFE_LONG		= RWH_WRITE_LIFE_LONG,
+	WRITE_LIFE_EXTREME	= RWH_WRITE_LIFE_EXTREME,
+};
+
 #define IOCB_EVENTFD		(1 << 0)
 #define IOCB_APPEND		(1 << 1)
 #define IOCB_DIRECT		(1 << 2)
@@ -323,6 +339,7 @@
 #define IOCB_DSYNC		(1 << 4)
 #define IOCB_SYNC		(1 << 5)
 #define IOCB_WRITE		(1 << 6)
+#define IOCB_NOWAIT		(1 << 7)
 
 struct kiocb {
 	struct file		*ki_filp;
@@ -330,6 +347,7 @@
 	void (*ki_complete)(struct kiocb *iocb, long ret, long ret2);
 	void			*private;
 	int			ki_flags;
+	enum rw_hint		ki_hint;
 };
 
 static inline bool is_sync_kiocb(struct kiocb *kiocb)
@@ -644,6 +662,7 @@
 	spinlock_t		i_lock;	/* i_blocks, i_bytes, maybe i_size */
 	unsigned short          i_bytes;
 	unsigned int		i_blkbits;
+	enum rw_hint		i_write_hint;
 	blkcnt_t		i_blocks;
 
 #ifdef __NEED_I_SIZE_ORDERED
@@ -1071,8 +1090,6 @@
 #define OFFT_OFFSET_MAX	INT_LIMIT(off_t)
 #endif
 
-#include <linux/fcntl.h>
-
 extern void send_sigio(struct fown_struct *fown, int fd, int band);
 
 /*
diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
index 8641e56..9e535af 100644
--- a/include/linux/fscrypt.h
+++ b/include/linux/fscrypt.h
@@ -13,42 +13,13 @@
 #ifndef _LINUX_FSCRYPT_H
 #define _LINUX_FSCRYPT_H
 
-#include <linux/key.h>
 #include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/bio.h>
-#include <linux/dcache.h>
-#include <crypto/skcipher.h>
-#include <uapi/linux/fs.h>
 
 #define FS_CRYPTO_BLOCK_SIZE		16
 
+struct fscrypt_ctx;
 struct fscrypt_info;
 
-struct fscrypt_ctx {
-	union {
-		struct {
-			struct page *bounce_page;	/* Ciphertext page */
-			struct page *control_page;	/* Original page  */
-		} w;
-		struct {
-			struct bio *bio;
-			struct work_struct work;
-		} r;
-		struct list_head free_list;	/* Free list */
-	};
-	u8 flags;				/* Flags */
-};
-
-/**
- * For encrypted symlinks, the ciphertext length is stored at the beginning
- * of the string in little-endian format.
- */
-struct fscrypt_symlink_data {
-	__le16 len;
-	char encrypted_path[1];
-} __packed;
-
 struct fscrypt_str {
 	unsigned char *name;
 	u32 len;
@@ -67,86 +38,11 @@
 #define fname_name(p)		((p)->disk_name.name)
 #define fname_len(p)		((p)->disk_name.len)
 
-/*
- * fscrypt superblock flags
- */
-#define FS_CFLG_OWN_PAGES (1U << 1)
-
-/*
- * crypto opertions for filesystems
- */
-struct fscrypt_operations {
-	unsigned int flags;
-	const char *key_prefix;
-	int (*get_context)(struct inode *, void *, size_t);
-	int (*set_context)(struct inode *, const void *, size_t, void *);
-	bool (*dummy_context)(struct inode *);
-	bool (*empty_dir)(struct inode *);
-	unsigned (*max_namelen)(struct inode *);
-};
-
-static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
-{
-	if (inode->i_sb->s_cop->dummy_context &&
-				inode->i_sb->s_cop->dummy_context(inode))
-		return true;
-	return false;
-}
-
-static inline bool fscrypt_valid_enc_modes(u32 contents_mode,
-					u32 filenames_mode)
-{
-	if (contents_mode == FS_ENCRYPTION_MODE_AES_128_CBC &&
-	    filenames_mode == FS_ENCRYPTION_MODE_AES_128_CTS)
-		return true;
-
-	if (contents_mode == FS_ENCRYPTION_MODE_AES_256_XTS &&
-	    filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS)
-		return true;
-
-	return false;
-}
-
-static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
-{
-	if (str->len == 1 && str->name[0] == '.')
-		return true;
-
-	if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
-		return true;
-
-	return false;
-}
-
 #if __FS_HAS_ENCRYPTION
-
-static inline struct page *fscrypt_control_page(struct page *page)
-{
-	return ((struct fscrypt_ctx *)page_private(page))->w.control_page;
-}
-
-static inline bool fscrypt_has_encryption_key(const struct inode *inode)
-{
-	return (inode->i_crypt_info != NULL);
-}
-
 #include <linux/fscrypt_supp.h>
-
-#else /* !__FS_HAS_ENCRYPTION */
-
-static inline struct page *fscrypt_control_page(struct page *page)
-{
-	WARN_ON_ONCE(1);
-	return ERR_PTR(-EINVAL);
-}
-
-static inline bool fscrypt_has_encryption_key(const struct inode *inode)
-{
-	return 0;
-}
-
+#else
 #include <linux/fscrypt_notsupp.h>
-#endif /* __FS_HAS_ENCRYPTION */
+#endif
 
 /**
  * fscrypt_require_key - require an inode's encryption key
@@ -287,4 +183,68 @@
 	return 0;
 }
 
+/**
+ * fscrypt_prepare_symlink - prepare to create a possibly-encrypted symlink
+ * @dir: directory in which the symlink is being created
+ * @target: plaintext symlink target
+ * @len: length of @target excluding null terminator
+ * @max_len: space the filesystem has available to store the symlink target
+ * @disk_link: (out) the on-disk symlink target being prepared
+ *
+ * This function computes the size the symlink target will require on-disk,
+ * stores it in @disk_link->len, and validates it against @max_len.  An
+ * encrypted symlink may be longer than the original.
+ *
+ * Additionally, @disk_link->name is set to @target if the symlink will be
+ * unencrypted, but left NULL if the symlink will be encrypted.  For encrypted
+ * symlinks, the filesystem must call fscrypt_encrypt_symlink() to create the
+ * on-disk target later.  (The reason for the two-step process is that some
+ * filesystems need to know the size of the symlink target before creating the
+ * inode, e.g. to determine whether it will be a "fast" or "slow" symlink.)
+ *
+ * Return: 0 on success, -ENAMETOOLONG if the symlink target is too long,
+ * -ENOKEY if the encryption key is missing, or another -errno code if a problem
+ * occurred while setting up the encryption key.
+ */
+static inline int fscrypt_prepare_symlink(struct inode *dir,
+					  const char *target,
+					  unsigned int len,
+					  unsigned int max_len,
+					  struct fscrypt_str *disk_link)
+{
+	if (IS_ENCRYPTED(dir) || fscrypt_dummy_context_enabled(dir))
+		return __fscrypt_prepare_symlink(dir, len, max_len, disk_link);
+
+	disk_link->name = (unsigned char *)target;
+	disk_link->len = len + 1;
+	if (disk_link->len > max_len)
+		return -ENAMETOOLONG;
+	return 0;
+}
+
+/**
+ * fscrypt_encrypt_symlink - encrypt the symlink target if needed
+ * @inode: symlink inode
+ * @target: plaintext symlink target
+ * @len: length of @target excluding null terminator
+ * @disk_link: (in/out) the on-disk symlink target being prepared
+ *
+ * If the symlink target needs to be encrypted, then this function encrypts it
+ * into @disk_link->name.  fscrypt_prepare_symlink() must have been called
+ * previously to compute @disk_link->len.  If the filesystem did not allocate a
+ * buffer for @disk_link->name after calling fscrypt_prepare_link(), then one
+ * will be kmalloc()'ed and the filesystem will be responsible for freeing it.
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static inline int fscrypt_encrypt_symlink(struct inode *inode,
+					  const char *target,
+					  unsigned int len,
+					  struct fscrypt_str *disk_link)
+{
+	if (IS_ENCRYPTED(inode))
+		return __fscrypt_encrypt_symlink(inode, target, len, disk_link);
+	return 0;
+}
+
 #endif	/* _LINUX_FSCRYPT_H */
diff --git a/include/linux/fscrypt_notsupp.h b/include/linux/fscrypt_notsupp.h
index c4c6bf2..6f97714 100644
--- a/include/linux/fscrypt_notsupp.h
+++ b/include/linux/fscrypt_notsupp.h
@@ -13,7 +13,21 @@
 #ifndef _LINUX_FSCRYPT_NOTSUPP_H
 #define _LINUX_FSCRYPT_NOTSUPP_H
 
+static inline bool fscrypt_has_encryption_key(const struct inode *inode)
+{
+	return false;
+}
+
+static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
+{
+	return false;
+}
+
 /* crypto.c */
+static inline void fscrypt_enqueue_decrypt_work(struct work_struct *work)
+{
+}
+
 static inline struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode,
 						  gfp_t gfp_flags)
 {
@@ -42,6 +56,11 @@
 	return -EOPNOTSUPP;
 }
 
+static inline struct page *fscrypt_control_page(struct page *page)
+{
+	WARN_ON_ONCE(1);
+	return ERR_PTR(-EINVAL);
+}
 
 static inline void fscrypt_restore_control_page(struct page *page)
 {
@@ -89,8 +108,7 @@
 	return -EOPNOTSUPP;
 }
 
-static inline void fscrypt_put_encryption_info(struct inode *inode,
-					       struct fscrypt_info *ci)
+static inline void fscrypt_put_encryption_info(struct inode *inode)
 {
 	return;
 }
@@ -115,16 +133,8 @@
 	return;
 }
 
-static inline u32 fscrypt_fname_encrypted_size(const struct inode *inode,
-					       u32 ilen)
-{
-	/* never happens */
-	WARN_ON(1);
-	return 0;
-}
-
 static inline int fscrypt_fname_alloc_buffer(const struct inode *inode,
-					     u32 ilen,
+					     u32 max_encrypted_len,
 					     struct fscrypt_str *crypto_str)
 {
 	return -EOPNOTSUPP;
@@ -143,13 +153,6 @@
 	return -EOPNOTSUPP;
 }
 
-static inline int fscrypt_fname_usr_to_disk(struct inode *inode,
-					    const struct qstr *iname,
-					    struct fscrypt_str *oname)
-{
-	return -EOPNOTSUPP;
-}
-
 static inline bool fscrypt_match_name(const struct fscrypt_name *fname,
 				      const u8 *de_name, u32 de_name_len)
 {
@@ -160,10 +163,13 @@
 }
 
 /* bio.c */
-static inline void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx,
-					     struct bio *bio)
+static inline void fscrypt_decrypt_bio(struct bio *bio)
 {
-	return;
+}
+
+static inline void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx,
+					       struct bio *bio)
+{
 }
 
 static inline void fscrypt_pullback_bio_page(struct page **page, bool restore)
@@ -207,4 +213,28 @@
 	return -EOPNOTSUPP;
 }
 
+static inline int __fscrypt_prepare_symlink(struct inode *dir,
+					    unsigned int len,
+					    unsigned int max_len,
+					    struct fscrypt_str *disk_link)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline int __fscrypt_encrypt_symlink(struct inode *inode,
+					    const char *target,
+					    unsigned int len,
+					    struct fscrypt_str *disk_link)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline const char *fscrypt_get_symlink(struct inode *inode,
+					      const void *caddr,
+					      unsigned int max_size,
+					      struct delayed_call *done)
+{
+	return ERR_PTR(-EOPNOTSUPP);
+}
+
 #endif	/* _LINUX_FSCRYPT_NOTSUPP_H */
diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h
index 2db5e970..1ed79ee 100644
--- a/include/linux/fscrypt_supp.h
+++ b/include/linux/fscrypt_supp.h
@@ -10,8 +10,55 @@
 #ifndef _LINUX_FSCRYPT_SUPP_H
 #define _LINUX_FSCRYPT_SUPP_H
 
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+/*
+ * fscrypt superblock flags
+ */
+#define FS_CFLG_OWN_PAGES (1U << 1)
+
+/*
+ * crypto operations for filesystems
+ */
+struct fscrypt_operations {
+	unsigned int flags;
+	const char *key_prefix;
+	int (*get_context)(struct inode *, void *, size_t);
+	int (*set_context)(struct inode *, const void *, size_t, void *);
+	bool (*dummy_context)(struct inode *);
+	bool (*empty_dir)(struct inode *);
+	unsigned (*max_namelen)(struct inode *);
+};
+
+struct fscrypt_ctx {
+	union {
+		struct {
+			struct page *bounce_page;	/* Ciphertext page */
+			struct page *control_page;	/* Original page  */
+		} w;
+		struct {
+			struct bio *bio;
+			struct work_struct work;
+		} r;
+		struct list_head free_list;	/* Free list */
+	};
+	u8 flags;				/* Flags */
+};
+
+static inline bool fscrypt_has_encryption_key(const struct inode *inode)
+{
+	return (inode->i_crypt_info != NULL);
+}
+
+static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
+{
+	return inode->i_sb->s_cop->dummy_context &&
+		inode->i_sb->s_cop->dummy_context(inode);
+}
+
 /* crypto.c */
-extern struct kmem_cache *fscrypt_info_cachep;
+extern void fscrypt_enqueue_decrypt_work(struct work_struct *);
 extern struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *, gfp_t);
 extern void fscrypt_release_ctx(struct fscrypt_ctx *);
 extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *,
@@ -19,6 +66,12 @@
 						u64, gfp_t);
 extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int,
 				unsigned int, u64);
+
+static inline struct page *fscrypt_control_page(struct page *page)
+{
+	return ((struct fscrypt_ctx *)page_private(page))->w.control_page;
+}
+
 extern void fscrypt_restore_control_page(struct page *);
 
 extern const struct dentry_operations fscrypt_d_ops;
@@ -43,7 +96,7 @@
 					void *, bool);
 /* keyinfo.c */
 extern int fscrypt_get_encryption_info(struct inode *);
-extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *);
+extern void fscrypt_put_encryption_info(struct inode *);
 
 /* fname.c */
 extern int fscrypt_setup_filename(struct inode *, const struct qstr *,
@@ -54,14 +107,11 @@
 	kfree(fname->crypto_buf.name);
 }
 
-extern u32 fscrypt_fname_encrypted_size(const struct inode *, u32);
 extern int fscrypt_fname_alloc_buffer(const struct inode *, u32,
 				struct fscrypt_str *);
 extern void fscrypt_fname_free_buffer(struct fscrypt_str *);
 extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32,
 			const struct fscrypt_str *, struct fscrypt_str *);
-extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *,
-			struct fscrypt_str *);
 
 #define FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE	32
 
@@ -138,7 +188,9 @@
 }
 
 /* bio.c */
-extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *);
+extern void fscrypt_decrypt_bio(struct bio *);
+extern void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx,
+					struct bio *bio);
 extern void fscrypt_pullback_bio_page(struct page **, bool);
 extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t,
 				 unsigned int);
@@ -152,5 +204,14 @@
 				    struct dentry *new_dentry,
 				    unsigned int flags);
 extern int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry);
+extern int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len,
+				     unsigned int max_len,
+				     struct fscrypt_str *disk_link);
+extern int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
+				     unsigned int len,
+				     struct fscrypt_str *disk_link);
+extern const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
+				       unsigned int max_size,
+				       struct delayed_call *done);
 
 #endif	/* _LINUX_FSCRYPT_SUPP_H */
diff --git a/include/linux/hid.h b/include/linux/hid.h
index b2ec827..fab65b6 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -801,7 +801,7 @@
 extern void hidinput_disconnect(struct hid_device *);
 
 int hid_set_field(struct hid_field *, unsigned, __s32);
-int hid_input_report(struct hid_device *, int type, u8 *, int, int);
+int hid_input_report(struct hid_device *, int type, u8 *, u32, int);
 int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field);
 struct hid_field *hidinput_get_led_field(struct hid_device *hid);
 unsigned int hidinput_count_leds(struct hid_device *hid);
@@ -1106,13 +1106,13 @@
  *
  * @report: the report we want to know the length
  */
-static inline int hid_report_len(struct hid_report *report)
+static inline u32 hid_report_len(struct hid_report *report)
 {
 	/* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */
 	return ((report->size - 1) >> 3) + 1 + (report->id > 0);
 }
 
-int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
 		int interrupt);
 
 /* HID quirks API */
diff --git a/include/linux/init.h b/include/linux/init.h
index 906ec32..d4b13a4 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -133,6 +133,9 @@
 void __init load_default_modules(void);
 int __init init_rootfs(void);
 
+#if defined(CONFIG_DEBUG_RODATA) || defined(CONFIG_DEBUG_SET_MODULE_RONX)
+extern bool rodata_enabled;
+#endif
 #ifdef CONFIG_DEBUG_RODATA
 void mark_rodata_ro(void);
 #endif
diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
index 589d14e..c2a0f00 100644
--- a/include/linux/jiffies.h
+++ b/include/linux/jiffies.h
@@ -1,6 +1,7 @@
 #ifndef _LINUX_JIFFIES_H
 #define _LINUX_JIFFIES_H
 
+#include <linux/cache.h>
 #include <linux/math64.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
@@ -63,19 +64,17 @@
 /* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */
 #define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ)
 
-/* some arch's have a small-data section that can be accessed register-relative
- * but that can only take up to, say, 4-byte variables. jiffies being part of
- * an 8-byte variable may not be correctly accessed unless we force the issue
- */
-#define __jiffy_data  __attribute__((section(".data")))
+#ifndef __jiffy_arch_data
+#define __jiffy_arch_data
+#endif
 
 /*
  * The 64-bit value is not atomic - you MUST NOT read it
  * without sampling the sequence number in jiffies_lock.
  * get_jiffies_64() will do this for you as appropriate.
  */
-extern u64 __jiffy_data jiffies_64;
-extern unsigned long volatile __jiffy_data jiffies;
+extern u64 __cacheline_aligned_in_smp jiffies_64;
+extern unsigned long volatile __cacheline_aligned_in_smp __jiffy_arch_data jiffies;
 
 #if (BITS_PER_LONG < 64)
 u64 get_jiffies_64(void);
diff --git a/include/linux/mlx4/qp.h b/include/linux/mlx4/qp.h
index b4ee8f6..8e2828d 100644
--- a/include/linux/mlx4/qp.h
+++ b/include/linux/mlx4/qp.h
@@ -470,6 +470,7 @@
 	u16	rate_val;
 };
 
+struct mlx4_qp *mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn);
 int mlx4_update_qp(struct mlx4_dev *dev, u32 qpn,
 		   enum mlx4_update_qp_attr attr,
 		   struct mlx4_update_qp_params *params);
diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h
index 5827614..5f3e622 100644
--- a/include/linux/mlx5/device.h
+++ b/include/linux/mlx5/device.h
@@ -750,8 +750,14 @@
 };
 
 enum {
-	CQE_RSS_HTYPE_IP	= 0x3 << 6,
-	CQE_RSS_HTYPE_L4	= 0x3 << 2,
+	CQE_RSS_HTYPE_IP	= 0x3 << 2,
+	/* cqe->rss_hash_type[3:2] - IP destination selected for hash
+	 * (00 = none,  01 = IPv4, 10 = IPv6, 11 = Reserved)
+	 */
+	CQE_RSS_HTYPE_L4	= 0x3 << 6,
+	/* cqe->rss_hash_type[7:6] - L4 destination selected for hash
+	 * (00 = none, 01 = TCP. 10 = UDP, 11 = IPSEC.SPI
+	 */
 };
 
 enum {
diff --git a/include/linux/msm_gsi.h b/include/linux/msm_gsi.h
index 6e0b439..81e7e75 100644
--- a/include/linux/msm_gsi.h
+++ b/include/linux/msm_gsi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -219,6 +219,11 @@
 	GSI_TWO_PREFETCH_SEG = 0x1
 };
 
+enum gsi_prefetch_mode {
+	GSI_USE_PREFETCH_BUFS = 0x0,
+	GSI_ESCAPE_BUF_ONLY = 0x1
+};
+
 enum gsi_chan_evt {
 	GSI_CHAN_EVT_INVALID = 0x0,
 	GSI_CHAN_EVT_SUCCESS = 0x1,
@@ -357,6 +362,7 @@
 	enum gsi_chan_use_db_eng use_db_eng;
 	enum gsi_max_prefetch max_prefetch;
 	uint8_t low_weight;
+	enum gsi_prefetch_mode prefetch_mode;
 	void (*xfer_cb)(struct gsi_chan_xfer_notify *notify);
 	void (*err_cb)(struct gsi_chan_err_notify *notify);
 	void *chan_user_data;
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 9bfeb88..69111fa 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -254,6 +254,8 @@
 bool xt_find_jump_offset(const unsigned int *offsets,
 			 unsigned int target, unsigned int size);
 
+int xt_check_proc_name(const char *name, unsigned int size);
+
 int xt_check_match(struct xt_mtchk_param *, unsigned int size, u_int8_t proto,
 		   bool inv_proto);
 int xt_check_target(struct xt_tgchk_param *, unsigned int size, u_int8_t proto,
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 1b71179..3652290 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1348,9 +1348,9 @@
 		unsigned int min_vecs, unsigned int max_vecs,
 		unsigned int flags)
 {
-	if (min_vecs > 1)
-		return -EINVAL;
-	return 1;
+	if ((flags & PCI_IRQ_LEGACY) && min_vecs == 1 && dev->irq)
+		return 1;
+	return -ENOSPC;
 }
 static inline void pci_free_irq_vectors(struct pci_dev *dev)
 {
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index b97bf2e..b326d0a 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -74,6 +74,12 @@
 
 #endif /* CONFIG_PROC_FS */
 
+#ifdef CONFIG_PROC_UID
+extern void proc_register_uid(kuid_t uid);
+#else
+static inline void proc_register_uid(kuid_t uid) {}
+#endif
+
 struct net;
 
 static inline struct proc_dir_entry *proc_net_mkdir(
diff --git a/include/linux/psci.h b/include/linux/psci.h
index 6306ab1..347077c 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -25,6 +25,17 @@
 int psci_cpu_init_idle(unsigned int cpu);
 int psci_cpu_suspend_enter(unsigned long index);
 
+enum psci_conduit {
+	PSCI_CONDUIT_NONE,
+	PSCI_CONDUIT_SMC,
+	PSCI_CONDUIT_HVC,
+};
+
+enum smccc_version {
+	SMCCC_VERSION_1_0,
+	SMCCC_VERSION_1_1,
+};
+
 struct psci_operations {
 	u32 (*get_version)(void);
 	int (*cpu_suspend)(u32 state, unsigned long entry_point);
@@ -34,6 +45,8 @@
 	int (*affinity_info)(unsigned long target_affinity,
 			unsigned long lowest_affinity_level);
 	int (*migrate_info_type)(void);
+	enum psci_conduit conduit;
+	enum smccc_version smccc_version;
 };
 
 extern struct psci_operations psci_ops;
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 031573d..48fe2e9 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -1065,12 +1065,14 @@
  * @full_scale_code: Full scale value with intrinsic offset removed.
  * @biploar: Polarity for QPNP ADC.
  * @adc_hc: Represents using HC variant of the ADC controller.
+ * @is_pmic_5: To check if PMIC5 is used.
  */
 struct qpnp_adc_properties {
 	uint32_t	adc_vdd_reference;
 	uint32_t	full_scale_code;
 	bool		bipolar;
 	bool		adc_hc;
+	bool		is_pmic_5;
 };
 
 /**
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 4b2a1bc..0748b7b 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1664,6 +1664,7 @@
 	u64 dl_deadline;	/* relative deadline of each instance	*/
 	u64 dl_period;		/* separation of two instances (period) */
 	u64 dl_bw;		/* dl_runtime / dl_deadline		*/
+	u64 dl_density;		/* dl_runtime / dl_deadline		*/
 
 	/*
 	 * Actual scheduling parameters. Initialized with the values above,
@@ -1913,6 +1914,10 @@
 
 	cputime_t utime, stime, utimescaled, stimescaled;
 	cputime_t gtime;
+#ifdef CONFIG_CPU_FREQ_TIMES
+	u64 *time_in_state;
+	unsigned int max_state;
+#endif
 	struct prev_cputime prev_cputime;
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
 	seqcount_t vtime_seqcount;
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index c73bef9..3fbfe96 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -988,10 +988,10 @@
 				     unsigned int headroom);
 struct sk_buff *skb_copy_expand(const struct sk_buff *skb, int newheadroom,
 				int newtailroom, gfp_t priority);
-int skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg,
-			int offset, int len);
-int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset,
-		 int len);
+int __must_check skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg,
+				     int offset, int len);
+int __must_check skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg,
+			      int offset, int len);
 int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer);
 int skb_pad(struct sk_buff *skb, int pad);
 #define dev_kfree_skb(a)	consume_skb(a)
diff --git a/include/linux/tty.h b/include/linux/tty.h
index a41244f..6f1ee85 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -355,6 +355,7 @@
 #define TTY_PTY_LOCK 		16	/* pty private */
 #define TTY_NO_WRITE_SPLIT 	17	/* Preserve write boundaries to driver */
 #define TTY_HUPPED 		18	/* Post driver->hangup() */
+#define TTY_HUPPING		19	/* Hangup in progress */
 #define TTY_LDISC_HALTED	22	/* Line discipline is halted */
 
 /* Values for tty->flow_change */
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index b37f8df..05fb7b5 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -63,6 +63,13 @@
 	WCNSS_WLAN_MAX_GPIO,
 };
 
+enum wcnss_log_type {
+	ERR,
+	WARN,
+	INFO,
+	DBG,
+};
+
 #define WCNSS_VBATT_THRESHOLD           3500000
 #define WCNSS_VBATT_GUARD               20000
 #define WCNSS_VBATT_HIGH                3700000
@@ -145,6 +152,7 @@
 void wcnss_snoc_vote(bool clk_chk_en);
 int wcnss_parse_voltage_regulator(struct wcnss_wlan_config *wlan_config,
 				  struct device *dev);
+void wcnss_log(enum wcnss_log_type type, const char *_fmt, ...);
 
 #ifdef CONFIG_WCNSS_REGISTER_DUMP_ON_BITE
 void wcnss_log_debug_regs_on_bite(void);
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 554671c..4931787 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -893,7 +893,7 @@
 				     u16 conn_timeout);
 struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
 				u8 dst_type, u8 sec_level, u16 conn_timeout,
-				u8 role);
+				u8 role, bdaddr_t *direct_rpa);
 struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
 				 u8 sec_level, u8 auth_type);
 struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 520c4c3..f656728 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -64,6 +64,9 @@
 /* Indicate backport support for external authentication*/
 #define CFG80211_EXTERNAL_AUTH_SUPPORT 1
 
+/* Indicate backport support for processing user cell base hint */
+#define CFG80211_USER_HINT_CELL_BASE_SELF_MANAGED 1
+
 /**
  * DOC: Introduction
  *
@@ -1011,9 +1014,9 @@
  * @RATE_INFO_BW_160: 160 MHz bandwidth
  */
 enum rate_info_bw {
+	RATE_INFO_BW_20 = 0,
 	RATE_INFO_BW_5,
 	RATE_INFO_BW_10,
-	RATE_INFO_BW_20,
 	RATE_INFO_BW_40,
 	RATE_INFO_BW_80,
 	RATE_INFO_BW_160,
diff --git a/include/net/slhc_vj.h b/include/net/slhc_vj.h
index 8716d59..8fcf890 100644
--- a/include/net/slhc_vj.h
+++ b/include/net/slhc_vj.h
@@ -127,6 +127,7 @@
  */
 struct cstate {
 	byte_t	cs_this;	/* connection id number (xmit) */
+	bool	initialized;	/* true if initialized */
 	struct cstate *next;	/* next in ring (xmit) */
 	struct iphdr cs_ip;	/* ip/tcp hdr from most recent packet */
 	struct tcphdr cs_tcp;
diff --git a/include/net/x25.h b/include/net/x25.h
index c383aa4..6d30a01 100644
--- a/include/net/x25.h
+++ b/include/net/x25.h
@@ -298,10 +298,10 @@
 
 /* sysctl_net_x25.c */
 #ifdef CONFIG_SYSCTL
-void x25_register_sysctl(void);
+int x25_register_sysctl(void);
 void x25_unregister_sysctl(void);
 #else
-static inline void x25_register_sysctl(void) {};
+static inline int x25_register_sysctl(void) { return 0; };
 static inline void x25_unregister_sysctl(void) {};
 #endif /* CONFIG_SYSCTL */
 
diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h
index 818a38f..f888263 100644
--- a/include/rdma/ib_addr.h
+++ b/include/rdma/ib_addr.h
@@ -129,6 +129,8 @@
 	      const unsigned char *dst_dev_addr);
 
 int rdma_addr_size(struct sockaddr *addr);
+int rdma_addr_size_in6(struct sockaddr_in6 *addr);
+int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr);
 
 int rdma_addr_find_smac_by_sgid(union ib_gid *sgid, u8 *smac, u16 *vlan_id);
 int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid,
diff --git a/include/soc/fsl/qe/qe.h b/include/soc/fsl/qe/qe.h
index 0cd4c1147..226f915 100644
--- a/include/soc/fsl/qe/qe.h
+++ b/include/soc/fsl/qe/qe.h
@@ -668,6 +668,10 @@
 #define UCC_FAST_GUMR_CTSS	0x00800000
 #define UCC_FAST_GUMR_TXSY	0x00020000
 #define UCC_FAST_GUMR_RSYN	0x00010000
+#define UCC_FAST_GUMR_SYNL_MASK	0x0000C000
+#define UCC_FAST_GUMR_SYNL_16	0x0000C000
+#define UCC_FAST_GUMR_SYNL_8	0x00008000
+#define UCC_FAST_GUMR_SYNL_AUTO	0x00004000
 #define UCC_FAST_GUMR_RTSM	0x00002000
 #define UCC_FAST_GUMR_REVD	0x00000400
 #define UCC_FAST_GUMR_ENR	0x00000020
diff --git a/include/sound/pcm_oss.h b/include/sound/pcm_oss.h
index 760c969..12bbf8c 100644
--- a/include/sound/pcm_oss.h
+++ b/include/sound/pcm_oss.h
@@ -57,6 +57,7 @@
 	char *buffer;				/* vmallocated period */
 	size_t buffer_used;			/* used length from period buffer */
 	struct mutex params_lock;
+	atomic_t rw_ref;		/* concurrent read/write accesses */
 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
 	struct snd_pcm_plugin *plugin_first;
 	struct snd_pcm_plugin *plugin_last;
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index e06df4d..b355ebf 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -713,10 +713,10 @@
 TRACE_EVENT(sched_task_util,
 
 	TP_PROTO(struct task_struct *p, int next_cpu, int backup_cpu,
-		 int target_cpu, bool sync, bool need_idle,
+		 int target_cpu, bool sync, bool need_idle, int fastpath,
 		 bool placement_boost, int rtg_cpu, u64 start_t),
 
-	TP_ARGS(p, next_cpu, backup_cpu, target_cpu, sync, need_idle,
+	TP_ARGS(p, next_cpu, backup_cpu, target_cpu, sync, need_idle, fastpath,
 		placement_boost, rtg_cpu, start_t),
 
 	TP_STRUCT__entry(
@@ -729,6 +729,7 @@
 		__field(int, target_cpu			)
 		__field(bool, sync			)
 		__field(bool, need_idle			)
+		__field(int, fastpath			)
 		__field(bool, placement_boost		)
 		__field(int, rtg_cpu			)
 		__field(u64, latency			)
@@ -744,13 +745,14 @@
 		__entry->target_cpu		= target_cpu;
 		__entry->sync			= sync;
 		__entry->need_idle		= need_idle;
+		__entry->fastpath		= fastpath;
 		__entry->placement_boost	= placement_boost;
 		__entry->rtg_cpu		= rtg_cpu;
 		__entry->latency		= (sched_clock() - start_t);
 	),
 
-	TP_printk("pid=%d comm=%s util=%lu prev_cpu=%d next_cpu=%d backup_cpu=%d target_cpu=%d sync=%d need_idle=%d placement_boost=%d rtg_cpu=%d latency=%llu",
-		__entry->pid, __entry->comm, __entry->util, __entry->prev_cpu, __entry->next_cpu, __entry->backup_cpu, __entry->target_cpu, __entry->sync, __entry->need_idle, __entry->placement_boost, __entry->rtg_cpu, __entry->latency)
+	TP_printk("pid=%d comm=%s util=%lu prev_cpu=%d next_cpu=%d backup_cpu=%d target_cpu=%d sync=%d need_idle=%d fastpath=%d placement_boost=%d rtg_cpu=%d latency=%llu",
+		__entry->pid, __entry->comm, __entry->util, __entry->prev_cpu, __entry->next_cpu, __entry->backup_cpu, __entry->target_cpu, __entry->sync, __entry->need_idle,  __entry->fastpath, __entry->placement_boost, __entry->rtg_cpu, __entry->latency)
 );
 
 #endif
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index c9248e5a..5da3634 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -472,6 +472,8 @@
 header-y += v4l2-dv-timings.h
 header-y += v4l2-mediabus.h
 header-y += v4l2-subdev.h
+header-y += msm_vidc_dec.h
+header-y += msm_vidc_enc.h
 header-y += veth.h
 header-y += vfio.h
 header-y += vhost.h
diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.h
index beed138..f85ed3a 100644
--- a/include/uapi/linux/fcntl.h
+++ b/include/uapi/linux/fcntl.h
@@ -43,6 +43,27 @@
 /* (1U << 31) is reserved for signed error codes */
 
 /*
+ * Set/Get write life time hints. {GET,SET}_RW_HINT operate on the
+ * underlying inode, while {GET,SET}_FILE_RW_HINT operate only on
+ * the specific file.
+ */
+#define F_GET_RW_HINT		(F_LINUX_SPECIFIC_BASE + 11)
+#define F_SET_RW_HINT		(F_LINUX_SPECIFIC_BASE + 12)
+#define F_GET_FILE_RW_HINT	(F_LINUX_SPECIFIC_BASE + 13)
+#define F_SET_FILE_RW_HINT	(F_LINUX_SPECIFIC_BASE + 14)
+
+/*
+ * Valid hint values for F_{GET,SET}_RW_HINT. 0 is "not set", or can be
+ * used to clear any hints previously set.
+ */
+#define RWF_WRITE_LIFE_NOT_SET	0
+#define RWH_WRITE_LIFE_NONE	1
+#define RWH_WRITE_LIFE_SHORT	2
+#define RWH_WRITE_LIFE_MEDIUM	3
+#define RWH_WRITE_LIFE_LONG	4
+#define RWH_WRITE_LIFE_EXTREME	5
+
+/*
  * Types of directory notifications that may be requested.
  */
 #define DN_ACCESS	0x00000001	/* File accessed */
diff --git a/include/uapi/linux/msm_vidc_dec.h b/include/uapi/linux/msm_vidc_dec.h
new file mode 100644
index 0000000..46af82b
--- /dev/null
+++ b/include/uapi/linux/msm_vidc_dec.h
@@ -0,0 +1,629 @@
+#ifndef _UAPI_MSM_VIDC_DEC_H_
+#define _UAPI_MSM_VIDC_DEC_H_
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/* STATUS CODES */
+/* Base value for status codes */
+#define VDEC_S_BASE	0x40000000
+/* Success */
+#define VDEC_S_SUCCESS	(VDEC_S_BASE)
+/* General failure */
+#define VDEC_S_EFAIL	(VDEC_S_BASE + 1)
+/* Fatal irrecoverable  failure. Need to  tear down session. */
+#define VDEC_S_EFATAL   (VDEC_S_BASE + 2)
+/* Error detected in the passed  parameters */
+#define VDEC_S_EBADPARAM	(VDEC_S_BASE + 3)
+/* Command called in invalid  state. */
+#define VDEC_S_EINVALSTATE	(VDEC_S_BASE + 4)
+ /* Insufficient OS  resources - thread, memory etc. */
+#define VDEC_S_ENOSWRES	(VDEC_S_BASE + 5)
+ /* Insufficient HW resources -  core capacity  maxed  out. */
+#define VDEC_S_ENOHWRES	(VDEC_S_BASE + 6)
+/* Invalid command  called */
+#define VDEC_S_EINVALCMD	(VDEC_S_BASE + 7)
+/* Command timeout. */
+#define VDEC_S_ETIMEOUT	(VDEC_S_BASE + 8)
+/* Pre-requirement is  not met for API. */
+#define VDEC_S_ENOPREREQ	(VDEC_S_BASE + 9)
+/* Command queue is full. */
+#define VDEC_S_ECMDQFULL	(VDEC_S_BASE + 10)
+/* Command is not supported  by this driver */
+#define VDEC_S_ENOTSUPP	(VDEC_S_BASE + 11)
+/* Command is not implemented by thedriver. */
+#define VDEC_S_ENOTIMPL	(VDEC_S_BASE + 12)
+/* Command is not implemented by the driver.  */
+#define VDEC_S_BUSY	(VDEC_S_BASE + 13)
+#define VDEC_S_INPUT_BITSTREAM_ERR (VDEC_S_BASE + 14)
+
+#define VDEC_INTF_VER	1
+#define VDEC_MSG_BASE	0x0000000
+/*
+ *Codes to identify asynchronous message responses and events that driver
+ *wants to communicate to the app.
+ */
+#define VDEC_MSG_INVALID	(VDEC_MSG_BASE + 0)
+#define VDEC_MSG_RESP_INPUT_BUFFER_DONE	(VDEC_MSG_BASE + 1)
+#define VDEC_MSG_RESP_OUTPUT_BUFFER_DONE	(VDEC_MSG_BASE + 2)
+#define VDEC_MSG_RESP_INPUT_FLUSHED	(VDEC_MSG_BASE + 3)
+#define VDEC_MSG_RESP_OUTPUT_FLUSHED	(VDEC_MSG_BASE + 4)
+#define VDEC_MSG_RESP_FLUSH_INPUT_DONE	(VDEC_MSG_BASE + 5)
+#define VDEC_MSG_RESP_FLUSH_OUTPUT_DONE	(VDEC_MSG_BASE + 6)
+#define VDEC_MSG_RESP_START_DONE	(VDEC_MSG_BASE + 7)
+#define VDEC_MSG_RESP_STOP_DONE	(VDEC_MSG_BASE + 8)
+#define VDEC_MSG_RESP_PAUSE_DONE	(VDEC_MSG_BASE + 9)
+#define VDEC_MSG_RESP_RESUME_DONE	(VDEC_MSG_BASE + 10)
+#define VDEC_MSG_RESP_RESOURCE_LOADED	(VDEC_MSG_BASE + 11)
+#define VDEC_EVT_RESOURCES_LOST	(VDEC_MSG_BASE + 12)
+#define VDEC_MSG_EVT_CONFIG_CHANGED	(VDEC_MSG_BASE + 13)
+#define VDEC_MSG_EVT_HW_ERROR	(VDEC_MSG_BASE + 14)
+#define VDEC_MSG_EVT_INFO_CONFIG_CHANGED	(VDEC_MSG_BASE + 15)
+#define VDEC_MSG_EVT_INFO_FIELD_DROPPED	(VDEC_MSG_BASE + 16)
+#define VDEC_MSG_EVT_HW_OVERLOAD	(VDEC_MSG_BASE + 17)
+#define VDEC_MSG_EVT_MAX_CLIENTS	(VDEC_MSG_BASE + 18)
+#define VDEC_MSG_EVT_HW_UNSUPPORTED	(VDEC_MSG_BASE + 19)
+
+/*Buffer flags bits masks.*/
+#define VDEC_BUFFERFLAG_EOS	0x00000001
+#define VDEC_BUFFERFLAG_DECODEONLY	0x00000004
+#define VDEC_BUFFERFLAG_DATACORRUPT	0x00000008
+#define VDEC_BUFFERFLAG_ENDOFFRAME	0x00000010
+#define VDEC_BUFFERFLAG_SYNCFRAME	0x00000020
+#define VDEC_BUFFERFLAG_EXTRADATA	0x00000040
+#define VDEC_BUFFERFLAG_CODECCONFIG	0x00000080
+
+/*Post processing flags bit masks*/
+#define VDEC_EXTRADATA_NONE 0x001
+#define VDEC_EXTRADATA_QP 0x004
+#define VDEC_EXTRADATA_MB_ERROR_MAP 0x008
+#define VDEC_EXTRADATA_SEI 0x010
+#define VDEC_EXTRADATA_VUI 0x020
+#define VDEC_EXTRADATA_VC1 0x040
+
+#define VDEC_EXTRADATA_EXT_DATA          0x0800
+#define VDEC_EXTRADATA_USER_DATA         0x1000
+#define VDEC_EXTRADATA_EXT_BUFFER        0x2000
+
+#define VDEC_CMDBASE	0x800
+#define VDEC_CMD_SET_INTF_VERSION	(VDEC_CMDBASE)
+
+#define VDEC_IOCTL_MAGIC 'v'
+
+struct vdec_ioctl_msg {
+	void __user *in;
+	void __user *out;
+};
+
+/*
+ * CMD params: InputParam:enum vdec_codec
+ * OutputParam: struct vdec_profile_level
+ */
+#define VDEC_IOCTL_GET_PROFILE_LEVEL_SUPPORTED \
+	_IOWR(VDEC_IOCTL_MAGIC, 0, struct vdec_ioctl_msg)
+
+/*
+ * CMD params:InputParam: NULL
+ * OutputParam: uint32_t(bitmask)
+ */
+#define VDEC_IOCTL_GET_INTERLACE_FORMAT \
+	_IOR(VDEC_IOCTL_MAGIC, 1, struct vdec_ioctl_msg)
+
+/*
+ * CMD params: InputParam:  enum vdec_codec
+ * OutputParam: struct vdec_profile_level
+ */
+#define VDEC_IOCTL_GET_CURRENT_PROFILE_LEVEL \
+	_IOWR(VDEC_IOCTL_MAGIC, 2, struct vdec_ioctl_msg)
+
+/*
+ * CMD params: SET: InputParam: enum vdec_output_fromat  OutputParam: NULL
+ * GET:  InputParam: NULL OutputParam: enum vdec_output_fromat
+ */
+#define VDEC_IOCTL_SET_OUTPUT_FORMAT \
+	_IOWR(VDEC_IOCTL_MAGIC, 3, struct vdec_ioctl_msg)
+#define VDEC_IOCTL_GET_OUTPUT_FORMAT \
+	_IOWR(VDEC_IOCTL_MAGIC, 4, struct vdec_ioctl_msg)
+
+/*
+ * CMD params: SET: InputParam: enum vdec_codec OutputParam: NULL
+ * GET: InputParam: NULL OutputParam: enum vdec_codec
+ */
+#define VDEC_IOCTL_SET_CODEC \
+	_IOW(VDEC_IOCTL_MAGIC, 5, struct vdec_ioctl_msg)
+#define VDEC_IOCTL_GET_CODEC \
+	_IOR(VDEC_IOCTL_MAGIC, 6, struct vdec_ioctl_msg)
+
+/*
+ * CMD params: SET: InputParam: struct vdec_picsize outputparam: NULL
+ * GET: InputParam: NULL outputparam: struct vdec_picsize
+ */
+#define VDEC_IOCTL_SET_PICRES \
+	_IOW(VDEC_IOCTL_MAGIC, 7, struct vdec_ioctl_msg)
+#define VDEC_IOCTL_GET_PICRES \
+	_IOR(VDEC_IOCTL_MAGIC, 8, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_SET_EXTRADATA \
+	_IOW(VDEC_IOCTL_MAGIC, 9, struct vdec_ioctl_msg)
+#define VDEC_IOCTL_GET_EXTRADATA \
+	_IOR(VDEC_IOCTL_MAGIC, 10, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_SET_SEQUENCE_HEADER \
+	_IOW(VDEC_IOCTL_MAGIC, 11, struct vdec_ioctl_msg)
+
+/*
+ * CMD params: SET: InputParam - vdec_allocatorproperty, OutputParam - NULL
+ * GET: InputParam - NULL, OutputParam - vdec_allocatorproperty
+ */
+#define VDEC_IOCTL_SET_BUFFER_REQ \
+	_IOW(VDEC_IOCTL_MAGIC, 12, struct vdec_ioctl_msg)
+#define VDEC_IOCTL_GET_BUFFER_REQ \
+	_IOR(VDEC_IOCTL_MAGIC, 13, struct vdec_ioctl_msg)
+/* CMD params: InputParam - vdec_buffer, OutputParam - uint8_t** */
+#define VDEC_IOCTL_ALLOCATE_BUFFER \
+	_IOWR(VDEC_IOCTL_MAGIC, 14, struct vdec_ioctl_msg)
+/* CMD params: InputParam - uint8_t *, OutputParam - NULL.*/
+#define VDEC_IOCTL_FREE_BUFFER \
+	_IOW(VDEC_IOCTL_MAGIC, 15, struct vdec_ioctl_msg)
+
+/*CMD params: CMD: InputParam - struct vdec_setbuffer_cmd, OutputParam - NULL*/
+#define VDEC_IOCTL_SET_BUFFER \
+	_IOW(VDEC_IOCTL_MAGIC, 16, struct vdec_ioctl_msg)
+
+/* CMD params: InputParam - struct vdec_fillbuffer_cmd, OutputParam - NULL*/
+#define VDEC_IOCTL_FILL_OUTPUT_BUFFER \
+	_IOW(VDEC_IOCTL_MAGIC, 17, struct vdec_ioctl_msg)
+
+/*CMD params: InputParam - struct vdec_frameinfo , OutputParam - NULL*/
+#define VDEC_IOCTL_DECODE_FRAME \
+	_IOW(VDEC_IOCTL_MAGIC, 18, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_LOAD_RESOURCES _IO(VDEC_IOCTL_MAGIC, 19)
+#define VDEC_IOCTL_CMD_START _IO(VDEC_IOCTL_MAGIC, 20)
+#define VDEC_IOCTL_CMD_STOP _IO(VDEC_IOCTL_MAGIC, 21)
+#define VDEC_IOCTL_CMD_PAUSE _IO(VDEC_IOCTL_MAGIC, 22)
+#define VDEC_IOCTL_CMD_RESUME _IO(VDEC_IOCTL_MAGIC, 23)
+
+/*CMD params: InputParam - enum vdec_bufferflush , OutputParam - NULL */
+#define VDEC_IOCTL_CMD_FLUSH _IOW(VDEC_IOCTL_MAGIC, 24, struct vdec_ioctl_msg)
+
+/* ========================================================
+ * IOCTL for getting asynchronous notification from driver
+ * ========================================================
+ */
+
+/*IOCTL params: InputParam - NULL, OutputParam - struct vdec_msginfo*/
+#define VDEC_IOCTL_GET_NEXT_MSG \
+	_IOR(VDEC_IOCTL_MAGIC, 25, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_STOP_NEXT_MSG _IO(VDEC_IOCTL_MAGIC, 26)
+
+#define VDEC_IOCTL_GET_NUMBER_INSTANCES \
+	_IOR(VDEC_IOCTL_MAGIC, 27, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_SET_PICTURE_ORDER \
+	_IOW(VDEC_IOCTL_MAGIC, 28, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_SET_FRAME_RATE \
+	_IOW(VDEC_IOCTL_MAGIC, 29, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_SET_H264_MV_BUFFER \
+	_IOW(VDEC_IOCTL_MAGIC, 30, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_FREE_H264_MV_BUFFER \
+	_IOW(VDEC_IOCTL_MAGIC, 31, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_GET_MV_BUFFER_SIZE  \
+	_IOR(VDEC_IOCTL_MAGIC, 32, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_SET_IDR_ONLY_DECODING \
+	_IO(VDEC_IOCTL_MAGIC, 33)
+
+#define VDEC_IOCTL_SET_CONT_ON_RECONFIG  \
+	_IO(VDEC_IOCTL_MAGIC, 34)
+
+#define VDEC_IOCTL_SET_DISABLE_DMX \
+	_IOW(VDEC_IOCTL_MAGIC, 35, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_GET_DISABLE_DMX \
+	_IOR(VDEC_IOCTL_MAGIC, 36, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_GET_DISABLE_DMX_SUPPORT \
+	_IOR(VDEC_IOCTL_MAGIC, 37, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_SET_PERF_CLK \
+	_IOR(VDEC_IOCTL_MAGIC, 38, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_SET_META_BUFFERS \
+	_IOW(VDEC_IOCTL_MAGIC, 39, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_FREE_META_BUFFERS \
+	_IO(VDEC_IOCTL_MAGIC, 40)
+
+enum vdec_picture {
+	PICTURE_TYPE_I,
+	PICTURE_TYPE_P,
+	PICTURE_TYPE_B,
+	PICTURE_TYPE_BI,
+	PICTURE_TYPE_SKIP,
+	PICTURE_TYPE_IDR,
+	PICTURE_TYPE_UNKNOWN
+};
+
+enum vdec_buffer {
+	VDEC_BUFFER_TYPE_INPUT,
+	VDEC_BUFFER_TYPE_OUTPUT
+};
+
+struct vdec_allocatorproperty {
+	enum vdec_buffer buffer_type;
+	uint32_t mincount;
+	uint32_t maxcount;
+	uint32_t actualcount;
+	size_t buffer_size;
+	uint32_t alignment;
+	uint32_t buf_poolid;
+	size_t meta_buffer_size;
+};
+
+struct vdec_bufferpayload {
+	void __user *bufferaddr;
+	size_t buffer_len;
+	int pmem_fd;
+	size_t offset;
+	size_t mmaped_size;
+};
+
+struct vdec_setbuffer_cmd {
+	enum vdec_buffer buffer_type;
+	struct vdec_bufferpayload buffer;
+};
+
+struct vdec_fillbuffer_cmd {
+	struct vdec_bufferpayload buffer;
+	void *client_data;
+};
+
+enum vdec_bufferflush {
+	VDEC_FLUSH_TYPE_INPUT,
+	VDEC_FLUSH_TYPE_OUTPUT,
+	VDEC_FLUSH_TYPE_ALL
+};
+
+enum vdec_codec {
+	VDEC_CODECTYPE_H264 = 0x1,
+	VDEC_CODECTYPE_H263 = 0x2,
+	VDEC_CODECTYPE_MPEG4 = 0x3,
+	VDEC_CODECTYPE_DIVX_3 = 0x4,
+	VDEC_CODECTYPE_DIVX_4 = 0x5,
+	VDEC_CODECTYPE_DIVX_5 = 0x6,
+	VDEC_CODECTYPE_DIVX_6 = 0x7,
+	VDEC_CODECTYPE_XVID = 0x8,
+	VDEC_CODECTYPE_MPEG1 = 0x9,
+	VDEC_CODECTYPE_MPEG2 = 0xa,
+	VDEC_CODECTYPE_VC1 = 0xb,
+	VDEC_CODECTYPE_VC1_RCV = 0xc,
+	VDEC_CODECTYPE_HEVC = 0xd,
+	VDEC_CODECTYPE_MVC = 0xe,
+	VDEC_CODECTYPE_VP8 = 0xf,
+	VDEC_CODECTYPE_VP9 = 0x10,
+};
+
+enum vdec_mpeg2_profile {
+	VDEC_MPEG2ProfileSimple = 0x1,
+	VDEC_MPEG2ProfileMain = 0x2,
+	VDEC_MPEG2Profile422 = 0x4,
+	VDEC_MPEG2ProfileSNR = 0x8,
+	VDEC_MPEG2ProfileSpatial = 0x10,
+	VDEC_MPEG2ProfileHigh = 0x20,
+	VDEC_MPEG2ProfileKhronosExtensions = 0x6F000000,
+	VDEC_MPEG2ProfileVendorStartUnused = 0x7F000000,
+	VDEC_MPEG2ProfileMax = 0x7FFFFFFF
+};
+
+enum vdec_mpeg2_level {
+
+	VDEC_MPEG2LevelLL = 0x1,
+	VDEC_MPEG2LevelML = 0x2,
+	VDEC_MPEG2LevelH14 = 0x4,
+	VDEC_MPEG2LevelHL = 0x8,
+	VDEC_MPEG2LevelKhronosExtensions = 0x6F000000,
+	VDEC_MPEG2LevelVendorStartUnused = 0x7F000000,
+	VDEC_MPEG2LevelMax = 0x7FFFFFFF
+};
+
+enum vdec_mpeg4_profile {
+	VDEC_MPEG4ProfileSimple = 0x01,
+	VDEC_MPEG4ProfileSimpleScalable = 0x02,
+	VDEC_MPEG4ProfileCore = 0x04,
+	VDEC_MPEG4ProfileMain = 0x08,
+	VDEC_MPEG4ProfileNbit = 0x10,
+	VDEC_MPEG4ProfileScalableTexture = 0x20,
+	VDEC_MPEG4ProfileSimpleFace = 0x40,
+	VDEC_MPEG4ProfileSimpleFBA = 0x80,
+	VDEC_MPEG4ProfileBasicAnimated = 0x100,
+	VDEC_MPEG4ProfileHybrid = 0x200,
+	VDEC_MPEG4ProfileAdvancedRealTime = 0x400,
+	VDEC_MPEG4ProfileCoreScalable = 0x800,
+	VDEC_MPEG4ProfileAdvancedCoding = 0x1000,
+	VDEC_MPEG4ProfileAdvancedCore = 0x2000,
+	VDEC_MPEG4ProfileAdvancedScalable = 0x4000,
+	VDEC_MPEG4ProfileAdvancedSimple = 0x8000,
+	VDEC_MPEG4ProfileKhronosExtensions = 0x6F000000,
+	VDEC_MPEG4ProfileVendorStartUnused = 0x7F000000,
+	VDEC_MPEG4ProfileMax = 0x7FFFFFFF
+};
+
+enum vdec_mpeg4_level {
+	VDEC_MPEG4Level0 = 0x01,
+	VDEC_MPEG4Level0b = 0x02,
+	VDEC_MPEG4Level1 = 0x04,
+	VDEC_MPEG4Level2 = 0x08,
+	VDEC_MPEG4Level3 = 0x10,
+	VDEC_MPEG4Level4 = 0x20,
+	VDEC_MPEG4Level4a = 0x40,
+	VDEC_MPEG4Level5 = 0x80,
+	VDEC_MPEG4LevelKhronosExtensions = 0x6F000000,
+	VDEC_MPEG4LevelVendorStartUnused = 0x7F000000,
+	VDEC_MPEG4LevelMax = 0x7FFFFFFF
+};
+
+enum vdec_avc_profile {
+	VDEC_AVCProfileBaseline = 0x01,
+	VDEC_AVCProfileMain = 0x02,
+	VDEC_AVCProfileExtended = 0x04,
+	VDEC_AVCProfileHigh = 0x08,
+	VDEC_AVCProfileHigh10 = 0x10,
+	VDEC_AVCProfileHigh422 = 0x20,
+	VDEC_AVCProfileHigh444 = 0x40,
+	VDEC_AVCProfileKhronosExtensions = 0x6F000000,
+	VDEC_AVCProfileVendorStartUnused = 0x7F000000,
+	VDEC_AVCProfileMax = 0x7FFFFFFF
+};
+
+enum vdec_avc_level {
+	VDEC_AVCLevel1 = 0x01,
+	VDEC_AVCLevel1b = 0x02,
+	VDEC_AVCLevel11 = 0x04,
+	VDEC_AVCLevel12 = 0x08,
+	VDEC_AVCLevel13 = 0x10,
+	VDEC_AVCLevel2 = 0x20,
+	VDEC_AVCLevel21 = 0x40,
+	VDEC_AVCLevel22 = 0x80,
+	VDEC_AVCLevel3 = 0x100,
+	VDEC_AVCLevel31 = 0x200,
+	VDEC_AVCLevel32 = 0x400,
+	VDEC_AVCLevel4 = 0x800,
+	VDEC_AVCLevel41 = 0x1000,
+	VDEC_AVCLevel42 = 0x2000,
+	VDEC_AVCLevel5 = 0x4000,
+	VDEC_AVCLevel51 = 0x8000,
+	VDEC_AVCLevelKhronosExtensions = 0x6F000000,
+	VDEC_AVCLevelVendorStartUnused = 0x7F000000,
+	VDEC_AVCLevelMax = 0x7FFFFFFF
+};
+
+enum vdec_divx_profile {
+	VDEC_DIVXProfile_qMobile = 0x01,
+	VDEC_DIVXProfile_Mobile = 0x02,
+	VDEC_DIVXProfile_HD = 0x04,
+	VDEC_DIVXProfile_Handheld = 0x08,
+	VDEC_DIVXProfile_Portable = 0x10,
+	VDEC_DIVXProfile_HomeTheater = 0x20
+};
+
+enum vdec_xvid_profile {
+	VDEC_XVIDProfile_Simple = 0x1,
+	VDEC_XVIDProfile_Advanced_Realtime_Simple = 0x2,
+	VDEC_XVIDProfile_Advanced_Simple = 0x4
+};
+
+enum vdec_xvid_level {
+	VDEC_XVID_LEVEL_S_L0 = 0x1,
+	VDEC_XVID_LEVEL_S_L1 = 0x2,
+	VDEC_XVID_LEVEL_S_L2 = 0x4,
+	VDEC_XVID_LEVEL_S_L3 = 0x8,
+	VDEC_XVID_LEVEL_ARTS_L1 = 0x10,
+	VDEC_XVID_LEVEL_ARTS_L2 = 0x20,
+	VDEC_XVID_LEVEL_ARTS_L3 = 0x40,
+	VDEC_XVID_LEVEL_ARTS_L4 = 0x80,
+	VDEC_XVID_LEVEL_AS_L0 = 0x100,
+	VDEC_XVID_LEVEL_AS_L1 = 0x200,
+	VDEC_XVID_LEVEL_AS_L2 = 0x400,
+	VDEC_XVID_LEVEL_AS_L3 = 0x800,
+	VDEC_XVID_LEVEL_AS_L4 = 0x1000
+};
+
+enum vdec_h263profile {
+	VDEC_H263ProfileBaseline = 0x01,
+	VDEC_H263ProfileH320Coding = 0x02,
+	VDEC_H263ProfileBackwardCompatible = 0x04,
+	VDEC_H263ProfileISWV2 = 0x08,
+	VDEC_H263ProfileISWV3 = 0x10,
+	VDEC_H263ProfileHighCompression = 0x20,
+	VDEC_H263ProfileInternet = 0x40,
+	VDEC_H263ProfileInterlace = 0x80,
+	VDEC_H263ProfileHighLatency = 0x100,
+	VDEC_H263ProfileKhronosExtensions = 0x6F000000,
+	VDEC_H263ProfileVendorStartUnused = 0x7F000000,
+	VDEC_H263ProfileMax = 0x7FFFFFFF
+};
+
+enum vdec_h263level {
+	VDEC_H263Level10 = 0x01,
+	VDEC_H263Level20 = 0x02,
+	VDEC_H263Level30 = 0x04,
+	VDEC_H263Level40 = 0x08,
+	VDEC_H263Level45 = 0x10,
+	VDEC_H263Level50 = 0x20,
+	VDEC_H263Level60 = 0x40,
+	VDEC_H263Level70 = 0x80,
+	VDEC_H263LevelKhronosExtensions = 0x6F000000,
+	VDEC_H263LevelVendorStartUnused = 0x7F000000,
+	VDEC_H263LevelMax = 0x7FFFFFFF
+};
+
+enum vdec_wmv_format {
+	VDEC_WMVFormatUnused = 0x01,
+	VDEC_WMVFormat7 = 0x02,
+	VDEC_WMVFormat8 = 0x04,
+	VDEC_WMVFormat9 = 0x08,
+	VDEC_WMFFormatKhronosExtensions = 0x6F000000,
+	VDEC_WMFFormatVendorStartUnused = 0x7F000000,
+	VDEC_WMVFormatMax = 0x7FFFFFFF
+};
+
+enum vdec_vc1_profile {
+	VDEC_VC1ProfileSimple = 0x1,
+	VDEC_VC1ProfileMain = 0x2,
+	VDEC_VC1ProfileAdvanced = 0x4
+};
+
+enum vdec_vc1_level {
+	VDEC_VC1_LEVEL_S_Low = 0x1,
+	VDEC_VC1_LEVEL_S_Medium = 0x2,
+	VDEC_VC1_LEVEL_M_Low = 0x4,
+	VDEC_VC1_LEVEL_M_Medium = 0x8,
+	VDEC_VC1_LEVEL_M_High = 0x10,
+	VDEC_VC1_LEVEL_A_L0 = 0x20,
+	VDEC_VC1_LEVEL_A_L1 = 0x40,
+	VDEC_VC1_LEVEL_A_L2 = 0x80,
+	VDEC_VC1_LEVEL_A_L3 = 0x100,
+	VDEC_VC1_LEVEL_A_L4 = 0x200
+};
+
+struct vdec_profile_level {
+	uint32_t profiles;
+	uint32_t levels;
+};
+
+enum vdec_interlaced_format {
+	VDEC_InterlaceFrameProgressive = 0x1,
+	VDEC_InterlaceInterleaveFrameTopFieldFirst = 0x2,
+	VDEC_InterlaceInterleaveFrameBottomFieldFirst = 0x4
+};
+
+#define VDEC_YUV_FORMAT_NV12_TP10_UBWC \
+	VDEC_YUV_FORMAT_NV12_TP10_UBWC
+
+enum vdec_output_fromat {
+	VDEC_YUV_FORMAT_NV12 = 0x1,
+	VDEC_YUV_FORMAT_TILE_4x2 = 0x2,
+	VDEC_YUV_FORMAT_NV12_UBWC = 0x3,
+	VDEC_YUV_FORMAT_NV12_TP10_UBWC = 0x4
+};
+
+enum vdec_output_order {
+	VDEC_ORDER_DISPLAY = 0x1,
+	VDEC_ORDER_DECODE = 0x2
+};
+
+struct vdec_picsize {
+	uint32_t frame_width;
+	uint32_t frame_height;
+	uint32_t stride;
+	uint32_t scan_lines;
+};
+
+struct vdec_seqheader {
+	void __user *ptr_seqheader;
+	size_t seq_header_len;
+	int pmem_fd;
+	size_t pmem_offset;
+};
+
+struct vdec_mberror {
+	void __user *ptr_errormap;
+	size_t err_mapsize;
+};
+
+struct vdec_input_frameinfo {
+	void __user *bufferaddr;
+	size_t offset;
+	size_t datalen;
+	uint32_t flags;
+	int64_t timestamp;
+	void *client_data;
+	int pmem_fd;
+	size_t pmem_offset;
+	void __user *desc_addr;
+	uint32_t desc_size;
+};
+
+struct vdec_framesize {
+	uint32_t   left;
+	uint32_t   top;
+	uint32_t   right;
+	uint32_t   bottom;
+};
+
+struct vdec_aspectratioinfo {
+	uint32_t aspect_ratio;
+	uint32_t par_width;
+	uint32_t par_height;
+};
+
+struct vdec_sep_metadatainfo {
+	void __user *metabufaddr;
+	uint32_t size;
+	int fd;
+	int offset;
+	uint32_t buffer_size;
+};
+
+struct vdec_output_frameinfo {
+	void __user *bufferaddr;
+	size_t offset;
+	size_t len;
+	uint32_t flags;
+	int64_t time_stamp;
+	enum vdec_picture pic_type;
+	void *client_data;
+	void *input_frame_clientdata;
+	struct vdec_picsize picsize;
+	struct vdec_framesize framesize;
+	enum vdec_interlaced_format interlaced_format;
+	struct vdec_aspectratioinfo aspect_ratio_info;
+	struct vdec_sep_metadatainfo metadata_info;
+};
+
+union vdec_msgdata {
+	struct vdec_output_frameinfo output_frame;
+	void *input_frame_clientdata;
+};
+
+struct vdec_msginfo {
+	uint32_t status_code;
+	uint32_t msgcode;
+	union vdec_msgdata msgdata;
+	size_t msgdatasize;
+};
+
+struct vdec_framerate {
+	unsigned long fps_denominator;
+	unsigned long fps_numerator;
+};
+
+struct vdec_h264_mv {
+	size_t size;
+	int count;
+	int pmem_fd;
+	int offset;
+};
+
+struct vdec_mv_buff_size {
+	int width;
+	int height;
+	int size;
+	int alignment;
+};
+
+struct vdec_meta_buffers {
+	size_t size;
+	int count;
+	int pmem_fd;
+	int pmem_fd_iommu;
+	int offset;
+};
+
+#endif /* end of macro _VDECDECODER_H_ */
diff --git a/include/uapi/linux/msm_vidc_enc.h b/include/uapi/linux/msm_vidc_enc.h
new file mode 100644
index 0000000..f4f1630
--- /dev/null
+++ b/include/uapi/linux/msm_vidc_enc.h
@@ -0,0 +1,752 @@
+#ifndef _UAPI_MSM_VIDC_ENC_H_
+#define _UAPI_MSM_VIDC_ENC_H_
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/** STATUS CODES*/
+/* Base value for status codes */
+#define VEN_S_BASE	0x00000000
+#define VEN_S_SUCCESS	(VEN_S_BASE)/* Success */
+#define VEN_S_EFAIL	(VEN_S_BASE+1)/* General failure */
+#define VEN_S_EFATAL	(VEN_S_BASE+2)/* Fatal irrecoverable failure*/
+#define VEN_S_EBADPARAM	(VEN_S_BASE+3)/* Error passed parameters*/
+/*Command called in invalid state*/
+#define VEN_S_EINVALSTATE	(VEN_S_BASE+4)
+#define VEN_S_ENOSWRES	(VEN_S_BASE+5)/* Insufficient OS resources*/
+#define VEN_S_ENOHWRES	(VEN_S_BASE+6)/*Insufficient HW resources */
+#define VEN_S_EBUFFREQ	(VEN_S_BASE+7)/* Buffer requirements were not met*/
+#define VEN_S_EINVALCMD	(VEN_S_BASE+8)/* Invalid command called */
+#define VEN_S_ETIMEOUT	(VEN_S_BASE+9)/* Command timeout. */
+/*Re-attempt was made when multiple invocation not supported for API.*/
+#define VEN_S_ENOREATMPT	(VEN_S_BASE+10)
+#define VEN_S_ENOPREREQ	(VEN_S_BASE+11)/*Pre-requirement is not met for API*/
+#define VEN_S_ECMDQFULL	(VEN_S_BASE+12)/*Command queue is full*/
+#define VEN_S_ENOTSUPP	(VEN_S_BASE+13)/*Command not supported*/
+#define VEN_S_ENOTIMPL	(VEN_S_BASE+14)/*Command not implemented.*/
+#define VEN_S_ENOTPMEM	(VEN_S_BASE+15)/*Buffer is not from PMEM*/
+#define VEN_S_EFLUSHED	(VEN_S_BASE+16)/*returned buffer was flushed*/
+#define VEN_S_EINSUFBUF	(VEN_S_BASE+17)/*provided buffer size insufficient*/
+#define VEN_S_ESAMESTATE	(VEN_S_BASE+18)
+#define VEN_S_EINVALTRANS	(VEN_S_BASE+19)
+
+#define VEN_INTF_VER			 1
+
+/*Asynchronous messages from driver*/
+#define VEN_MSG_INDICATION	0
+#define VEN_MSG_INPUT_BUFFER_DONE	1
+#define VEN_MSG_OUTPUT_BUFFER_DONE	2
+#define VEN_MSG_NEED_OUTPUT_BUFFER	3
+#define VEN_MSG_FLUSH_INPUT_DONE	4
+#define VEN_MSG_FLUSH_OUTPUT_DONE	5
+#define VEN_MSG_START	6
+#define VEN_MSG_STOP	7
+#define VEN_MSG_PAUSE	8
+#define VEN_MSG_RESUME	9
+#define VEN_MSG_STOP_READING_MSG	10
+#define VEN_MSG_LTRUSE_FAILED	    11
+#define VEN_MSG_HW_OVERLOAD	12
+#define VEN_MSG_MAX_CLIENTS	13
+
+
+/*Buffer flags bits masks*/
+#define VEN_BUFFLAG_EOS	0x00000001
+#define VEN_BUFFLAG_ENDOFFRAME	0x00000010
+#define VEN_BUFFLAG_SYNCFRAME	0x00000020
+#define VEN_BUFFLAG_EXTRADATA	0x00000040
+#define VEN_BUFFLAG_CODECCONFIG	0x00000080
+
+/*Post processing flags bit masks*/
+#define VEN_EXTRADATA_NONE          0x001
+#define VEN_EXTRADATA_QCOMFILLER    0x002
+#define VEN_EXTRADATA_SLICEINFO     0x100
+#define VEN_EXTRADATA_LTRINFO       0x200
+#define VEN_EXTRADATA_MBINFO        0x400
+
+/*ENCODER CONFIGURATION CONSTANTS*/
+
+/*Encoded video frame types*/
+#define VEN_FRAME_TYPE_I	1/* I frame type */
+#define VEN_FRAME_TYPE_P	2/* P frame type */
+#define VEN_FRAME_TYPE_B	3/* B frame type */
+
+/*Video codec types*/
+#define VEN_CODEC_MPEG4	1/* MPEG4 Codec */
+#define VEN_CODEC_H264	2/* H.264 Codec */
+#define VEN_CODEC_H263	3/* H.263 Codec */
+
+/*Video codec profile types.*/
+#define VEN_PROFILE_MPEG4_SP      1/* 1 - MPEG4 SP profile      */
+#define VEN_PROFILE_MPEG4_ASP     2/* 2 - MPEG4 ASP profile     */
+#define VEN_PROFILE_H264_BASELINE 3/* 3 - H264 Baseline profile	*/
+#define VEN_PROFILE_H264_MAIN     4/* 4 - H264 Main profile     */
+#define VEN_PROFILE_H264_HIGH     5/* 5 - H264 High profile     */
+#define VEN_PROFILE_H263_BASELINE 6/* 6 - H263 Baseline profile */
+
+/*Video codec profile level types.*/
+#define VEN_LEVEL_MPEG4_0	 0x1/* MPEG4 Level 0  */
+#define VEN_LEVEL_MPEG4_1	 0x2/* MPEG4 Level 1  */
+#define VEN_LEVEL_MPEG4_2	 0x3/* MPEG4 Level 2  */
+#define VEN_LEVEL_MPEG4_3	 0x4/* MPEG4 Level 3  */
+#define VEN_LEVEL_MPEG4_4	 0x5/* MPEG4 Level 4  */
+#define VEN_LEVEL_MPEG4_5	 0x6/* MPEG4 Level 5  */
+#define VEN_LEVEL_MPEG4_3b	 0x7/* MPEG4 Level 3b */
+#define VEN_LEVEL_MPEG4_6	 0x8/* MPEG4 Level 6  */
+
+#define VEN_LEVEL_H264_1	 0x9/* H.264 Level 1   */
+#define VEN_LEVEL_H264_1b        0xA/* H.264 Level 1b  */
+#define VEN_LEVEL_H264_1p1	 0xB/* H.264 Level 1.1 */
+#define VEN_LEVEL_H264_1p2	 0xC/* H.264 Level 1.2 */
+#define VEN_LEVEL_H264_1p3	 0xD/* H.264 Level 1.3 */
+#define VEN_LEVEL_H264_2	 0xE/* H.264 Level 2   */
+#define VEN_LEVEL_H264_2p1	 0xF/* H.264 Level 2.1 */
+#define VEN_LEVEL_H264_2p2	0x10/* H.264 Level 2.2 */
+#define VEN_LEVEL_H264_3	0x11/* H.264 Level 3   */
+#define VEN_LEVEL_H264_3p1	0x12/* H.264 Level 3.1 */
+#define VEN_LEVEL_H264_3p2	0x13/* H.264 Level 3.2 */
+#define VEN_LEVEL_H264_4	0x14/* H.264 Level 4   */
+
+#define VEN_LEVEL_H263_10	0x15/* H.263 Level 10  */
+#define VEN_LEVEL_H263_20	0x16/* H.263 Level 20  */
+#define VEN_LEVEL_H263_30	0x17/* H.263 Level 30  */
+#define VEN_LEVEL_H263_40	0x18/* H.263 Level 40  */
+#define VEN_LEVEL_H263_45	0x19/* H.263 Level 45  */
+#define VEN_LEVEL_H263_50	0x1A/* H.263 Level 50  */
+#define VEN_LEVEL_H263_60	0x1B/* H.263 Level 60  */
+#define VEN_LEVEL_H263_70	0x1C/* H.263 Level 70  */
+
+/*Entropy coding model selection for H.264 encoder.*/
+#define VEN_ENTROPY_MODEL_CAVLC	1
+#define VEN_ENTROPY_MODEL_CABAC	2
+/*Cabac model number (0,1,2) for encoder.*/
+#define VEN_CABAC_MODEL_0	1/* CABAC Model 0. */
+#define VEN_CABAC_MODEL_1	2/* CABAC Model 1. */
+#define VEN_CABAC_MODEL_2	3/* CABAC Model 2. */
+
+/*Deblocking filter control type for encoder.*/
+#define VEN_DB_DISABLE	1/* 1 - Disable deblocking filter*/
+#define VEN_DB_ALL_BLKG_BNDRY	2/* 2 - All blocking boundary filtering*/
+#define VEN_DB_SKIP_SLICE_BNDRY	3/* 3 - Filtering except sliceboundary*/
+
+/*Different methods of Multi slice selection.*/
+#define VEN_MSLICE_OFF	1
+#define VEN_MSLICE_CNT_MB	2 /*number of MBscount per slice*/
+#define VEN_MSLICE_CNT_BYTE	3 /*number of bytes count per slice.*/
+#define VEN_MSLICE_GOB	4 /*Multi slice by GOB for H.263 only.*/
+
+/*Different modes for Rate Control.*/
+#define VEN_RC_OFF	1
+#define VEN_RC_VBR_VFR	2
+#define VEN_RC_VBR_CFR	3
+#define VEN_RC_CBR_VFR	4
+#define VEN_RC_CBR_CFR	5
+
+/*Different modes for flushing buffers*/
+#define VEN_FLUSH_INPUT	1
+#define VEN_FLUSH_OUTPUT	2
+#define VEN_FLUSH_ALL	3
+
+/*Different input formats for YUV data.*/
+#define VEN_INPUTFMT_NV12	1/* NV12 Linear */
+#define VEN_INPUTFMT_NV21	2/* NV21 Linear */
+#define VEN_INPUTFMT_NV12_16M2KA	3/* NV12 Linear */
+
+/*Different allowed rotation modes.*/
+#define VEN_ROTATION_0	1/* 0 degrees */
+#define VEN_ROTATION_90	2/* 90 degrees */
+#define VEN_ROTATION_180	3/* 180 degrees */
+#define VEN_ROTATION_270	4/* 270 degrees */
+
+/*IOCTL timeout values*/
+#define VEN_TIMEOUT_INFINITE	0xffffffff
+
+/*Different allowed intra refresh modes.*/
+#define VEN_IR_OFF	1
+#define VEN_IR_CYCLIC	2
+#define VEN_IR_RANDOM	3
+
+/*IOCTL BASE CODES Not to be used directly by the client.*/
+/* Base value for ioctls that are not related to encoder configuration.*/
+#define VEN_IOCTLBASE_NENC	0x800
+/* Base value for encoder configuration ioctls*/
+#define VEN_IOCTLBASE_ENC	0x850
+
+struct venc_ioctl_msg {
+	void __user *in;
+	void __user *out;
+};
+
+/*NON ENCODER CONFIGURATION IOCTLs*/
+
+/*IOCTL params:SET: InputData - unsigned long, OutputData - NULL*/
+#define VEN_IOCTL_SET_INTF_VERSION \
+	_IOW(VEN_IOCTLBASE_NENC, 0, struct venc_ioctl_msg)
+
+/*IOCTL params:CMD: InputData - venc_timeout, OutputData - venc_msg*/
+#define VEN_IOCTL_CMD_READ_NEXT_MSG \
+	_IOWR(VEN_IOCTLBASE_NENC, 1, struct venc_ioctl_msg)
+
+/*IOCTL params:CMD: InputData - NULL, OutputData - NULL*/
+#define VEN_IOCTL_CMD_STOP_READ_MSG	_IO(VEN_IOCTLBASE_NENC, 2)
+
+/*
+ * IOCTL params:SET: InputData - venc_allocatorproperty, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_allocatorproperty
+ */
+#define VEN_IOCTL_SET_INPUT_BUFFER_REQ \
+	_IOW(VEN_IOCTLBASE_NENC, 3, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_INPUT_BUFFER_REQ \
+	_IOR(VEN_IOCTLBASE_NENC, 4, struct venc_ioctl_msg)
+
+/*IOCTL params:CMD: InputData - venc_bufferpayload, OutputData - NULL*/
+#define VEN_IOCTL_CMD_ALLOC_INPUT_BUFFER \
+	_IOW(VEN_IOCTLBASE_NENC, 5, struct venc_ioctl_msg)
+
+/*IOCTL params:CMD: InputData - venc_bufferpayload, OutputData - NULL*/
+#define VEN_IOCTL_SET_INPUT_BUFFER \
+	_IOW(VEN_IOCTLBASE_NENC, 6, struct venc_ioctl_msg)
+
+/*IOCTL params: CMD: InputData - venc_bufferpayload, OutputData - NULL*/
+#define VEN_IOCTL_CMD_FREE_INPUT_BUFFER \
+	_IOW(VEN_IOCTLBASE_NENC, 7, struct venc_ioctl_msg)
+
+/*
+ * IOCTL params:SET: InputData - venc_allocatorproperty, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_allocatorproperty
+ */
+#define VEN_IOCTL_SET_OUTPUT_BUFFER_REQ \
+	_IOW(VEN_IOCTLBASE_NENC, 8, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_OUTPUT_BUFFER_REQ \
+	_IOR(VEN_IOCTLBASE_NENC, 9, struct venc_ioctl_msg)
+
+/*IOCTL params:CMD: InputData - venc_bufferpayload, OutputData - NULL*/
+#define VEN_IOCTL_CMD_ALLOC_OUTPUT_BUFFER \
+	_IOW(VEN_IOCTLBASE_NENC, 10, struct venc_ioctl_msg)
+
+
+/*IOCTL params:CMD: InputData - venc_bufferpayload, OutputData - NULL*/
+#define VEN_IOCTL_SET_OUTPUT_BUFFER \
+	_IOW(VEN_IOCTLBASE_NENC, 11, struct venc_ioctl_msg)
+
+/*IOCTL params:CMD: InputData - venc_bufferpayload, OutputData - NULL.*/
+#define VEN_IOCTL_CMD_FREE_OUTPUT_BUFFER \
+	_IOW(VEN_IOCTLBASE_NENC, 12, struct venc_ioctl_msg)
+
+
+/* Asynchronous respone message code:* VEN_MSG_START*/
+#define VEN_IOCTL_CMD_START	_IO(VEN_IOCTLBASE_NENC, 13)
+
+
+/*
+ * IOCTL params:CMD: InputData - venc_buffer, OutputData - NULL
+ * Asynchronous respone message code:VEN_MSG_INPUT_BUFFER_DONE
+ */
+#define VEN_IOCTL_CMD_ENCODE_FRAME \
+	_IOW(VEN_IOCTLBASE_NENC, 14, struct venc_ioctl_msg)
+
+
+/*
+ *IOCTL params:CMD: InputData - venc_buffer, OutputData - NULL
+ *Asynchronous response message code:VEN_MSG_OUTPUT_BUFFER_DONE
+ */
+#define VEN_IOCTL_CMD_FILL_OUTPUT_BUFFER \
+	_IOW(VEN_IOCTLBASE_NENC, 15, struct venc_ioctl_msg)
+
+/*
+ * IOCTL params:CMD: InputData - venc_bufferflush, OutputData - NULL
+ * Asynchronous response message code:VEN_MSG_INPUT_BUFFER_DONE
+ */
+#define VEN_IOCTL_CMD_FLUSH \
+	_IOW(VEN_IOCTLBASE_NENC, 16, struct venc_ioctl_msg)
+
+
+/*Asynchronous respone message code:VEN_MSG_PAUSE*/
+#define VEN_IOCTL_CMD_PAUSE	_IO(VEN_IOCTLBASE_NENC, 17)
+
+/*Asynchronous respone message code:VEN_MSG_RESUME*/
+#define VEN_IOCTL_CMD_RESUME _IO(VEN_IOCTLBASE_NENC, 18)
+
+/* Asynchronous respone message code:VEN_MSG_STOP*/
+#define VEN_IOCTL_CMD_STOP _IO(VEN_IOCTLBASE_NENC, 19)
+
+#define VEN_IOCTL_SET_RECON_BUFFER \
+	_IOW(VEN_IOCTLBASE_NENC, 20, struct venc_ioctl_msg)
+
+#define VEN_IOCTL_FREE_RECON_BUFFER \
+	_IOW(VEN_IOCTLBASE_NENC, 21, struct venc_ioctl_msg)
+
+#define VEN_IOCTL_GET_RECON_BUFFER_SIZE \
+	_IOW(VEN_IOCTLBASE_NENC, 22, struct venc_ioctl_msg)
+
+
+
+/*ENCODER PROPERTY CONFIGURATION & CAPABILITY IOCTLs*/
+
+/*
+ * IOCTL params:SET: InputData - venc_basecfg, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_basecfg
+ */
+#define VEN_IOCTL_SET_BASE_CFG \
+	_IOW(VEN_IOCTLBASE_ENC, 1, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_BASE_CFG \
+	_IOR(VEN_IOCTLBASE_ENC, 2, struct venc_ioctl_msg)
+
+/*
+ * IOCTL params:SET: InputData - venc_switch, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_switch
+ */
+#define VEN_IOCTL_SET_LIVE_MODE \
+	_IOW(VEN_IOCTLBASE_ENC, 3, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_LIVE_MODE \
+	_IOR(VEN_IOCTLBASE_ENC, 4, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_profile, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_profile
+ */
+#define VEN_IOCTL_SET_CODEC_PROFILE \
+	_IOW(VEN_IOCTLBASE_ENC, 5, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_CODEC_PROFILE \
+	_IOR(VEN_IOCTLBASE_ENC, 6, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - ven_profilelevel, OutputData - NULL
+ * GET: InputData - NULL, OutputData - ven_profilelevel
+ */
+#define VEN_IOCTL_SET_PROFILE_LEVEL \
+	_IOW(VEN_IOCTLBASE_ENC, 7, struct venc_ioctl_msg)
+
+#define VEN_IOCTL_GET_PROFILE_LEVEL \
+	_IOR(VEN_IOCTLBASE_ENC, 8, struct venc_ioctl_msg)
+
+/*
+ * IOCTL params:SET: InputData - venc_switch, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_switch
+ */
+#define VEN_IOCTL_SET_SHORT_HDR \
+	_IOW(VEN_IOCTLBASE_ENC, 9, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_SHORT_HDR \
+	_IOR(VEN_IOCTLBASE_ENC, 10, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params: SET: InputData - venc_sessionqp, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_sessionqp
+ */
+#define VEN_IOCTL_SET_SESSION_QP \
+	_IOW(VEN_IOCTLBASE_ENC, 11, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_SESSION_QP \
+	_IOR(VEN_IOCTLBASE_ENC, 12, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_intraperiod, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_intraperiod
+ */
+#define VEN_IOCTL_SET_INTRA_PERIOD \
+	_IOW(VEN_IOCTLBASE_ENC, 13, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_INTRA_PERIOD \
+	_IOR(VEN_IOCTLBASE_ENC, 14, struct venc_ioctl_msg)
+
+
+/* Request an Iframe*/
+#define VEN_IOCTL_CMD_REQUEST_IFRAME _IO(VEN_IOCTLBASE_ENC, 15)
+
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_capability*/
+#define VEN_IOCTL_GET_CAPABILITY \
+	_IOR(VEN_IOCTLBASE_ENC, 16, struct venc_ioctl_msg)
+
+
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_seqheader*/
+#define VEN_IOCTL_GET_SEQUENCE_HDR \
+	_IOR(VEN_IOCTLBASE_ENC, 17, struct venc_ioctl_msg)
+
+/*
+ * IOCTL params:SET: InputData - venc_entropycfg, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_entropycfg
+ */
+#define VEN_IOCTL_SET_ENTROPY_CFG \
+	_IOW(VEN_IOCTLBASE_ENC, 18, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_ENTROPY_CFG \
+	_IOR(VEN_IOCTLBASE_ENC, 19, struct venc_ioctl_msg)
+
+/*
+ * IOCTL params:SET: InputData - venc_dbcfg, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_dbcfg
+ */
+#define VEN_IOCTL_SET_DEBLOCKING_CFG \
+	_IOW(VEN_IOCTLBASE_ENC, 20, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_DEBLOCKING_CFG \
+	_IOR(VEN_IOCTLBASE_ENC, 21, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_intrarefresh, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_intrarefresh
+ */
+#define VEN_IOCTL_SET_INTRA_REFRESH \
+	_IOW(VEN_IOCTLBASE_ENC, 22, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_INTRA_REFRESH \
+	_IOR(VEN_IOCTLBASE_ENC, 23, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_multiclicecfg, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_multiclicecfg
+ */
+#define VEN_IOCTL_SET_MULTI_SLICE_CFG \
+	_IOW(VEN_IOCTLBASE_ENC, 24, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_MULTI_SLICE_CFG \
+	_IOR(VEN_IOCTLBASE_ENC, 25, struct venc_ioctl_msg)
+
+/*
+ * IOCTL params:SET: InputData - venc_ratectrlcfg, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_ratectrlcfg
+ */
+#define VEN_IOCTL_SET_RATE_CTRL_CFG \
+	_IOW(VEN_IOCTLBASE_ENC, 26, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_RATE_CTRL_CFG \
+	_IOR(VEN_IOCTLBASE_ENC, 27, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_voptimingcfg, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_voptimingcfg
+ */
+#define VEN_IOCTL_SET_VOP_TIMING_CFG \
+	_IOW(VEN_IOCTLBASE_ENC, 28, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_VOP_TIMING_CFG \
+	_IOR(VEN_IOCTLBASE_ENC, 29, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_framerate, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_framerate
+ */
+#define VEN_IOCTL_SET_FRAME_RATE \
+	_IOW(VEN_IOCTLBASE_ENC, 30, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_FRAME_RATE \
+	_IOR(VEN_IOCTLBASE_ENC, 31, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_targetbitrate, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_targetbitrate
+ */
+#define VEN_IOCTL_SET_TARGET_BITRATE \
+	_IOW(VEN_IOCTLBASE_ENC, 32, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_TARGET_BITRATE \
+	_IOR(VEN_IOCTLBASE_ENC, 33, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_rotation, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_rotation
+ */
+#define VEN_IOCTL_SET_ROTATION \
+	_IOW(VEN_IOCTLBASE_ENC, 34, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_ROTATION \
+	_IOR(VEN_IOCTLBASE_ENC, 35, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_headerextension, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_headerextension
+ */
+#define VEN_IOCTL_SET_HEC \
+	_IOW(VEN_IOCTLBASE_ENC, 36, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_HEC \
+	_IOR(VEN_IOCTLBASE_ENC, 37, struct venc_ioctl_msg)
+
+/*
+ * IOCTL params:SET: InputData - venc_switch, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_switch
+ */
+#define VEN_IOCTL_SET_DATA_PARTITION \
+	_IOW(VEN_IOCTLBASE_ENC, 38, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_DATA_PARTITION \
+	_IOR(VEN_IOCTLBASE_ENC, 39, struct venc_ioctl_msg)
+
+/*
+ * IOCTL params:SET: InputData - venc_switch, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_switch
+ */
+#define VEN_IOCTL_SET_RVLC \
+	_IOW(VEN_IOCTLBASE_ENC, 40, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_RVLC \
+	_IOR(VEN_IOCTLBASE_ENC, 41, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_switch, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_switch
+ */
+#define VEN_IOCTL_SET_AC_PREDICTION \
+	_IOW(VEN_IOCTLBASE_ENC, 42, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_AC_PREDICTION \
+	_IOR(VEN_IOCTLBASE_ENC, 43, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_qprange, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_qprange
+ */
+#define VEN_IOCTL_SET_QP_RANGE \
+	_IOW(VEN_IOCTLBASE_ENC, 44, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_QP_RANGE \
+	_IOR(VEN_IOCTLBASE_ENC, 45, struct venc_ioctl_msg)
+
+#define VEN_IOCTL_GET_NUMBER_INSTANCES \
+	_IOR(VEN_IOCTLBASE_ENC, 46, struct venc_ioctl_msg)
+
+#define VEN_IOCTL_SET_METABUFFER_MODE \
+	_IOW(VEN_IOCTLBASE_ENC, 47, struct venc_ioctl_msg)
+
+
+/*IOCTL params:SET: InputData - unsigned int, OutputData - NULL.*/
+#define VEN_IOCTL_SET_EXTRADATA \
+	_IOW(VEN_IOCTLBASE_ENC, 48, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - unsigned int.*/
+#define VEN_IOCTL_GET_EXTRADATA \
+	_IOR(VEN_IOCTLBASE_ENC, 49, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - NULL, OutputData - NULL.*/
+#define VEN_IOCTL_SET_SLICE_DELIVERY_MODE \
+	_IO(VEN_IOCTLBASE_ENC, 50)
+
+#define VEN_IOCTL_SET_H263_PLUSPTYPE \
+	_IOW(VEN_IOCTLBASE_ENC, 51, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_range, OutputData - NULL.*/
+#define VEN_IOCTL_SET_CAPABILITY_LTRCOUNT \
+	_IOW(VEN_IOCTLBASE_ENC, 52, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_range.*/
+#define VEN_IOCTL_GET_CAPABILITY_LTRCOUNT \
+	_IOR(VEN_IOCTLBASE_ENC, 53, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltrmode, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRMODE \
+	_IOW(VEN_IOCTLBASE_ENC, 54, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltrmode.*/
+#define VEN_IOCTL_GET_LTRMODE \
+	_IOR(VEN_IOCTLBASE_ENC, 55, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltrcount, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRCOUNT \
+	_IOW(VEN_IOCTLBASE_ENC, 56, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltrcount.*/
+#define VEN_IOCTL_GET_LTRCOUNT \
+	_IOR(VEN_IOCTLBASE_ENC, 57, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltrperiod, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRPERIOD \
+	_IOW(VEN_IOCTLBASE_ENC, 58, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltrperiod.*/
+#define VEN_IOCTL_GET_LTRPERIOD \
+	_IOR(VEN_IOCTLBASE_ENC, 59, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltruse, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRUSE \
+	_IOW(VEN_IOCTLBASE_ENC, 60, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltruse.*/
+#define VEN_IOCTL_GET_LTRUSE \
+	_IOR(VEN_IOCTLBASE_ENC, 61, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltrmark, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRMARK \
+	_IOW(VEN_IOCTLBASE_ENC, 62, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltrmark.*/
+#define VEN_IOCTL_GET_LTRMARK \
+	_IOR(VEN_IOCTLBASE_ENC, 63, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - unsigned int, OutputData - NULL*/
+#define VEN_IOCTL_SET_SPS_PPS_FOR_IDR \
+	_IOW(VEN_IOCTLBASE_ENC, 64, struct venc_ioctl_msg)
+
+struct venc_range {
+	unsigned long	max;
+	unsigned long	min;
+	unsigned long	step_size;
+};
+
+struct venc_switch {
+	unsigned char	status;
+};
+
+struct venc_allocatorproperty {
+	unsigned long	 mincount;
+	unsigned long	 maxcount;
+	unsigned long	 actualcount;
+	unsigned long	 datasize;
+	unsigned long	 suffixsize;
+	unsigned long	 alignment;
+	unsigned long	 bufpoolid;
+};
+
+struct venc_bufferpayload {
+	unsigned char *pbuffer;
+	size_t	sz;
+	int	fd;
+	unsigned int	offset;
+	unsigned int	maped_size;
+	unsigned long	filled_len;
+};
+
+struct venc_buffer {
+	unsigned char *ptrbuffer;
+	unsigned long	sz;
+	unsigned long	len;
+	unsigned long	offset;
+	long long	timestamp;
+	unsigned long	flags;
+	void	*clientdata;
+};
+
+struct venc_basecfg {
+	unsigned long	input_width;
+	unsigned long	input_height;
+	unsigned long	dvs_width;
+	unsigned long	dvs_height;
+	unsigned long	codectype;
+	unsigned long	fps_num;
+	unsigned long	fps_den;
+	unsigned long	targetbitrate;
+	unsigned long	inputformat;
+};
+
+struct venc_profile {
+	unsigned long	profile;
+};
+struct ven_profilelevel {
+	unsigned long	level;
+};
+
+struct venc_sessionqp {
+	unsigned long	iframeqp;
+	unsigned long	pframqp;
+};
+
+struct venc_qprange {
+	unsigned long	maxqp;
+	unsigned long	minqp;
+};
+
+struct venc_plusptype {
+	unsigned long	plusptype_enable;
+};
+
+struct venc_intraperiod {
+	unsigned long	num_pframes;
+	unsigned long	num_bframes;
+};
+struct venc_seqheader {
+	unsigned char *hdrbufptr;
+	unsigned long	bufsize;
+	unsigned long	hdrlen;
+};
+
+struct venc_capability {
+	unsigned long	codec_types;
+	unsigned long	maxframe_width;
+	unsigned long	maxframe_height;
+	unsigned long	maxtarget_bitrate;
+	unsigned long	maxframe_rate;
+	unsigned long	input_formats;
+	unsigned char	dvs;
+};
+
+struct venc_entropycfg {
+	unsigned int longentropysel;
+	unsigned long	cabacmodel;
+};
+
+struct venc_dbcfg {
+	unsigned long	db_mode;
+	unsigned long	slicealpha_offset;
+	unsigned long	slicebeta_offset;
+};
+
+struct venc_intrarefresh {
+	unsigned long	irmode;
+	unsigned long	mbcount;
+};
+
+struct venc_multiclicecfg {
+	unsigned long	mslice_mode;
+	unsigned long	mslice_size;
+};
+
+struct venc_bufferflush {
+	unsigned long	flush_mode;
+};
+
+struct venc_ratectrlcfg {
+	unsigned long	rcmode;
+};
+
+struct	venc_voptimingcfg {
+	unsigned long	voptime_resolution;
+};
+struct venc_framerate {
+	unsigned long	fps_denominator;
+	unsigned long	fps_numerator;
+};
+
+struct venc_targetbitrate {
+	unsigned long	target_bitrate;
+};
+
+
+struct venc_rotation {
+	unsigned long	rotation;
+};
+
+struct venc_timeout {
+	 unsigned long	millisec;
+};
+
+struct venc_headerextension {
+	 unsigned long	header_extension;
+};
+
+struct venc_msg {
+	unsigned long	statuscode;
+	unsigned long	msgcode;
+	struct venc_buffer	buf;
+	unsigned long	msgdata_size;
+};
+
+struct venc_recon_addr {
+	unsigned char *pbuffer;
+	unsigned long buffer_size;
+	unsigned long pmem_fd;
+	unsigned long offset;
+};
+
+struct venc_recon_buff_size {
+	int width;
+	int height;
+	int size;
+	int alignment;
+};
+
+struct venc_ltrmode {
+	unsigned long   ltr_mode;
+};
+
+struct venc_ltrcount {
+	unsigned long   ltr_count;
+};
+
+struct venc_ltrperiod {
+	unsigned long   ltr_period;
+};
+
+struct venc_ltruse {
+	unsigned long   ltr_id;
+	unsigned long   ltr_frames;
+};
+
+#endif /* _UAPI_MSM_VIDC_ENC_H_ */
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index 2c5810a..b67cfd8 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -106,7 +106,7 @@
 #define PCI_SUBSYSTEM_ID	0x2e
 #define PCI_ROM_ADDRESS		0x30	/* Bits 31..11 are address, 10..1 reserved */
 #define  PCI_ROM_ADDRESS_ENABLE	0x01
-#define PCI_ROM_ADDRESS_MASK	(~0x7ffUL)
+#define PCI_ROM_ADDRESS_MASK	(~0x7ffU)
 
 #define PCI_CAPABILITY_LIST	0x34	/* Offset of first capability list entry */
 
diff --git a/include/uapi/linux/psci.h b/include/uapi/linux/psci.h
index 3d7a0fc..39930ca 100644
--- a/include/uapi/linux/psci.h
+++ b/include/uapi/linux/psci.h
@@ -87,6 +87,9 @@
 		(((ver) & PSCI_VERSION_MAJOR_MASK) >> PSCI_VERSION_MAJOR_SHIFT)
 #define PSCI_VERSION_MINOR(ver)			\
 		((ver) & PSCI_VERSION_MINOR_MASK)
+#define PSCI_VERSION(maj, min)						\
+	((((maj) << PSCI_VERSION_MAJOR_SHIFT) & PSCI_VERSION_MAJOR_MASK) | \
+	 ((min) & PSCI_VERSION_MINOR_MASK))
 
 /* PSCI features decoding (>=1.0) */
 #define PSCI_1_0_FEATURES_CPU_SUSPEND_PF_SHIFT	1
diff --git a/include/uapi/linux/qg.h b/include/uapi/linux/qg.h
index 54488ff..2c7b49a 100644
--- a/include/uapi/linux/qg.h
+++ b/include/uapi/linux/qg.h
@@ -12,8 +12,8 @@
 	QG_ESR,
 	QG_CHARGE_COUNTER,
 	QG_FIFO_TIME_DELTA,
-	QG_RESERVED_1,
-	QG_RESERVED_2,
+	QG_BATT_SOC,
+	QG_CC_SOC,
 	QG_RESERVED_3,
 	QG_RESERVED_4,
 	QG_RESERVED_5,
@@ -25,6 +25,9 @@
 	QG_MAX,
 };
 
+#define QG_BATT_SOC QG_BATT_SOC
+#define QG_CC_SOC QG_CC_SOC
+
 struct fifo_data {
 	unsigned int			v;
 	unsigned int			i;
diff --git a/include/uapi/linux/random.h b/include/uapi/linux/random.h
index 3f93d16..b455b0d 100644
--- a/include/uapi/linux/random.h
+++ b/include/uapi/linux/random.h
@@ -34,6 +34,9 @@
 /* Clear the entropy pool and associated counters.  (Superuser only.) */
 #define RNDCLEARPOOL	_IO( 'R', 0x06 )
 
+/* Reseed CRNG.  (Superuser only.) */
+#define RNDRESEEDCRNG	_IO( 'R', 0x07 )
+
 struct rand_pool_info {
 	int	entropy_count;
 	int	buf_size;
diff --git a/include/uapi/media/msm_media_info.h b/include/uapi/media/msm_media_info.h
index 4f12e5c..3fd0c88 100644
--- a/include/uapi/media/msm_media_info.h
+++ b/include/uapi/media/msm_media_info.h
@@ -1229,6 +1229,7 @@
 {
 	const unsigned int extra_size = VENUS_EXTRADATA_SIZE(width, height);
 	unsigned int uv_alignment = 0, size = 0;
+	unsigned int w_alignment = 512;
 	unsigned int y_plane, uv_plane, y_stride,
 		uv_stride, y_sclines, uv_sclines;
 	unsigned int y_ubwc_plane = 0, uv_ubwc_plane = 0;
@@ -1252,6 +1253,17 @@
 	switch (color_fmt) {
 	case COLOR_FMT_NV21:
 	case COLOR_FMT_NV12:
+		uv_alignment = 4096;
+		y_plane = y_stride * y_sclines;
+		uv_plane = uv_stride * uv_sclines + uv_alignment;
+		size = y_plane + uv_plane +
+				MSM_MEDIA_MAX(extra_size, 8 * y_stride);
+		size = MSM_MEDIA_ALIGN(size, 4096);
+
+		/* Additional size to cover last row of non-aligned frame */
+		size += MSM_MEDIA_ALIGN(width, w_alignment) * w_alignment;
+		size = MSM_MEDIA_ALIGN(size, 4096);
+		break;
 	case COLOR_FMT_P010:
 		uv_alignment = 4096;
 		y_plane = y_stride * y_sclines;
@@ -1288,6 +1300,10 @@
 			uv_meta_plane)*2 +
 			MSM_MEDIA_MAX(extra_size + 8192, 48 * y_stride);
 		size = MSM_MEDIA_ALIGN(size, 4096);
+
+		/* Additional size to cover last row of non-aligned frame */
+		size += MSM_MEDIA_ALIGN(width, w_alignment) * w_alignment;
+		size = MSM_MEDIA_ALIGN(size, 4096);
 		break;
 	case COLOR_FMT_NV12_BPP10_UBWC:
 		y_ubwc_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096);
diff --git a/init/Kconfig b/init/Kconfig
index 854bd5d..e3929edd 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -840,6 +840,16 @@
 		     13 =>  8 KB
 		     12 =>  4 KB
 
+config CONSOLE_FLUSH_ON_HOTPLUG
+	bool "Enable console flush configurable in hot plug code path"
+	depends on HOTPLUG_CPU
+	def_bool n
+	help
+	In cpu hot plug path console lock acquire and release causes the
+	console to flush. If console lock is not free hot plug latency
+	increases. So make console flush configurable in hot plug path
+	and default disabled to help in cpu hot plug latencies.
+
 config LOG_CPU_MAX_BUF_SHIFT
 	int "CPU kernel log buffer size contribution (13 => 8 KB, 17 => 128KB)"
 	depends on SMP
diff --git a/init/main.c b/init/main.c
index 17e439f..f9cd3f0 100644
--- a/init/main.c
+++ b/init/main.c
@@ -81,6 +81,7 @@
 #include <linux/proc_ns.h>
 #include <linux/io.h>
 #include <linux/kaiser.h>
+#include <linux/cache.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -913,14 +914,16 @@
 
 static noinline void __init kernel_init_freeable(void);
 
-#ifdef CONFIG_DEBUG_RODATA
-static bool rodata_enabled = true;
+#if defined(CONFIG_DEBUG_RODATA) || defined(CONFIG_SET_MODULE_RONX)
+bool rodata_enabled __ro_after_init = true;
 static int __init set_debug_rodata(char *str)
 {
 	return strtobool(str, &rodata_enabled);
 }
 __setup("rodata=", set_debug_rodata);
+#endif
 
+#ifdef CONFIG_DEBUG_RODATA
 static void mark_readonly(void)
 {
 	if (rodata_enabled)
diff --git a/ipc/shm.c b/ipc/shm.c
index e2072ae..b626745 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -198,6 +198,12 @@
 	if (IS_ERR(shp))
 		return PTR_ERR(shp);
 
+	if (shp->shm_file != sfd->file) {
+		/* ID was reused */
+		shm_unlock(shp);
+		return -EINVAL;
+	}
+
 	shp->shm_atim = get_seconds();
 	shp->shm_lprid = task_tgid_vnr(current);
 	shp->shm_nattch++;
@@ -381,6 +387,17 @@
 	return sfd->vm_ops->fault(vma, vmf);
 }
 
+static int shm_split(struct vm_area_struct *vma, unsigned long addr)
+{
+	struct file *file = vma->vm_file;
+	struct shm_file_data *sfd = shm_file_data(file);
+
+	if (sfd->vm_ops && sfd->vm_ops->split)
+		return sfd->vm_ops->split(vma, addr);
+
+	return 0;
+}
+
 #ifdef CONFIG_NUMA
 static int shm_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
 {
@@ -414,8 +431,9 @@
 	int ret;
 
 	/*
-	 * In case of remap_file_pages() emulation, the file can represent
-	 * removed IPC ID: propogate shm_lock() error to caller.
+	 * In case of remap_file_pages() emulation, the file can represent an
+	 * IPC ID that was removed, and possibly even reused by another shm
+	 * segment already.  Propagate this case as an error to caller.
 	 */
 	ret =__shm_open(vma);
 	if (ret)
@@ -439,6 +457,7 @@
 	struct shm_file_data *sfd = shm_file_data(file);
 
 	put_ipc_ns(sfd->ns);
+	fput(sfd->file);
 	shm_file_data(file) = NULL;
 	kfree(sfd);
 	return 0;
@@ -503,6 +522,7 @@
 	.open	= shm_open,	/* callback for a new vm-area open */
 	.close	= shm_close,	/* callback for when the vm-area is released */
 	.fault	= shm_fault,
+	.split	= shm_split,
 #if defined(CONFIG_NUMA)
 	.set_policy = shm_set_policy,
 	.get_policy = shm_get_policy,
@@ -1200,7 +1220,16 @@
 	file->f_mapping = shp->shm_file->f_mapping;
 	sfd->id = shp->shm_perm.id;
 	sfd->ns = get_ipc_ns(ns);
-	sfd->file = shp->shm_file;
+	/*
+	 * We need to take a reference to the real shm file to prevent the
+	 * pointer from becoming stale in cases where the lifetime of the outer
+	 * file extends beyond that of the shm segment.  It's not usually
+	 * possible, but it can happen during remap_file_pages() emulation as
+	 * that unmaps the memory, then does ->mmap() via file reference only.
+	 * We'll deny the ->mmap() if the shm segment was since removed, but to
+	 * detect shm ID reuse we need to compare the file pointers.
+	 */
+	sfd->file = get_file(shp->shm_file);
 	sfd->vm_ops = NULL;
 
 	err = security_mmap_file(file, prot, flags);
diff --git a/kernel/cpu.c b/kernel/cpu.c
index c68d150..3f3b7f8 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -64,6 +64,12 @@
 
 static DEFINE_PER_CPU(struct cpuhp_cpu_state, cpuhp_state);
 
+#if defined(CONFIG_LOCKDEP) && defined(CONFIG_SMP)
+static struct lock_class_key cpuhp_state_key;
+static struct lockdep_map cpuhp_state_lock_map =
+	STATIC_LOCKDEP_MAP_INIT("cpuhp_state", &cpuhp_state_key);
+#endif
+
 /**
  * cpuhp_step - Hotplug state machine step
  * @name:	Name of the step
@@ -572,6 +578,7 @@
 
 	st->should_run = false;
 
+	lock_map_acquire(&cpuhp_state_lock_map);
 	/* Single callback invocation for [un]install ? */
 	if (st->single) {
 		if (st->cb_state < CPUHP_AP_ONLINE) {
@@ -603,6 +610,7 @@
 		else if (st->state > st->target)
 			ret = cpuhp_ap_offline(cpu, st);
 	}
+	lock_map_release(&cpuhp_state_lock_map);
 	st->result = ret;
 	complete(&st->done);
 }
@@ -617,6 +625,9 @@
 	if (!cpu_online(cpu))
 		return 0;
 
+	lock_map_acquire(&cpuhp_state_lock_map);
+	lock_map_release(&cpuhp_state_lock_map);
+
 	/*
 	 * If we are up and running, use the hotplug thread. For early calls
 	 * we invoke the thread function directly.
@@ -660,6 +671,8 @@
 	enum cpuhp_state state = st->state;
 
 	trace_cpuhp_enter(cpu, st->target, state, cpuhp_kick_ap_work);
+	lock_map_acquire(&cpuhp_state_lock_map);
+	lock_map_release(&cpuhp_state_lock_map);
 	__cpuhp_kick_ap_work(st);
 	wait_for_completion(&st->done);
 	trace_cpuhp_exit(cpu, st->state, state, st->result);
diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
index e9fdb52..411226b 100644
--- a/kernel/events/callchain.c
+++ b/kernel/events/callchain.c
@@ -227,12 +227,18 @@
 		}
 
 		if (regs) {
+			mm_segment_t fs;
+
 			if (crosstask)
 				goto exit_put;
 
 			if (add_mark)
 				perf_callchain_store_context(&ctx, PERF_CONTEXT_USER);
+
+			fs = get_fs();
+			set_fs(USER_DS);
 			perf_callchain_user(&ctx, regs);
+			set_fs(fs);
 		}
 	}
 
diff --git a/kernel/events/core.c b/kernel/events/core.c
index cd941f8..2ea4eb1 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -4181,6 +4181,9 @@
 	if (event->ctx)
 		put_ctx(event->ctx);
 
+	if (event->hw.target)
+		put_task_struct(event->hw.target);
+
 	exclusive_event_destroy(event);
 	module_put(event->pmu->module);
 
@@ -5799,9 +5802,6 @@
 	__output_copy(handle, values, n * sizeof(u64));
 }
 
-/*
- * XXX PERF_FORMAT_GROUP vs inherited events seems difficult.
- */
 static void perf_output_read_group(struct perf_output_handle *handle,
 			    struct perf_event *event,
 			    u64 enabled, u64 running)
@@ -5846,6 +5846,13 @@
 #define PERF_FORMAT_TOTAL_TIMES (PERF_FORMAT_TOTAL_TIME_ENABLED|\
 				 PERF_FORMAT_TOTAL_TIME_RUNNING)
 
+/*
+ * XXX PERF_SAMPLE_READ vs inherited events seems difficult.
+ *
+ * The problem is that its both hard and excessively expensive to iterate the
+ * child list, not to mention that its impossible to IPI the children running
+ * on another CPU, from interrupt/NMI context.
+ */
 static void perf_output_read(struct perf_output_handle *handle,
 			     struct perf_event *event)
 {
@@ -9462,6 +9469,7 @@
 		 * and we cannot use the ctx information because we need the
 		 * pmu before we get a ctx.
 		 */
+		get_task_struct(task);
 		event->hw.target = task;
 	}
 
@@ -9511,9 +9519,10 @@
 	local64_set(&hwc->period_left, hwc->sample_period);
 
 	/*
-	 * we currently do not support PERF_FORMAT_GROUP on inherited events
+	 * We currently do not support PERF_SAMPLE_READ on inherited events.
+	 * See perf_output_read().
 	 */
-	if (attr->inherit && (attr->read_format & PERF_FORMAT_GROUP))
+	if (attr->inherit && (attr->sample_type & PERF_SAMPLE_READ))
 		goto err_ns;
 
 	if (!has_branch_stack(event))
@@ -9541,8 +9550,10 @@
 		event->addr_filters_offs = kcalloc(pmu->nr_addr_filters,
 						   sizeof(unsigned long),
 						   GFP_KERNEL);
-		if (!event->addr_filters_offs)
+		if (!event->addr_filters_offs) {
+			err = -ENOMEM;
 			goto err_per_task;
+		}
 
 		/* force hw sync on the address filters */
 		event->addr_filters_gen = 1;
@@ -9576,6 +9587,8 @@
 		perf_detach_cgroup(event);
 	if (event->ns)
 		put_pid_ns(event->ns);
+	if (event->hw.target)
+		put_task_struct(event->hw.target);
 	kfree(event);
 
 	return ERR_PTR(err);
diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c
index 3f8cb1e..253ae2d 100644
--- a/kernel/events/hw_breakpoint.c
+++ b/kernel/events/hw_breakpoint.c
@@ -427,16 +427,9 @@
  * modify_user_hw_breakpoint - modify a user-space hardware breakpoint
  * @bp: the breakpoint structure to modify
  * @attr: new breakpoint attributes
- * @triggered: callback to trigger when we hit the breakpoint
- * @tsk: pointer to 'task_struct' of the process to which the address belongs
  */
 int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr)
 {
-	u64 old_addr = bp->attr.bp_addr;
-	u64 old_len = bp->attr.bp_len;
-	int old_type = bp->attr.bp_type;
-	int err = 0;
-
 	/*
 	 * modify_user_hw_breakpoint can be invoked with IRQs disabled and hence it
 	 * will not be possible to raise IPIs that invoke __perf_event_disable.
@@ -451,27 +444,18 @@
 	bp->attr.bp_addr = attr->bp_addr;
 	bp->attr.bp_type = attr->bp_type;
 	bp->attr.bp_len = attr->bp_len;
+	bp->attr.disabled = 1;
 
-	if (attr->disabled)
-		goto end;
+	if (!attr->disabled) {
+		int err = validate_hw_breakpoint(bp);
 
-	err = validate_hw_breakpoint(bp);
-	if (!err)
+		if (err)
+			return err;
+
 		perf_event_enable(bp);
-
-	if (err) {
-		bp->attr.bp_addr = old_addr;
-		bp->attr.bp_type = old_type;
-		bp->attr.bp_len = old_len;
-		if (!bp->attr.disabled)
-			perf_event_enable(bp);
-
-		return err;
+		bp->attr.disabled = 0;
 	}
 
-end:
-	bp->attr.disabled = attr->disabled;
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint);
diff --git a/kernel/exit.c b/kernel/exit.c
index 35ff283..4b4f03a 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -54,6 +54,7 @@
 #include <linux/writeback.h>
 #include <linux/shm.h>
 #include <linux/kcov.h>
+#include <linux/cpufreq_times.h>
 
 #include "sched/tune.h"
 
@@ -171,6 +172,9 @@
 {
 	struct task_struct *leader;
 	int zap_leader;
+#ifdef CONFIG_CPU_FREQ_TIMES
+	cpufreq_task_times_exit(p);
+#endif
 repeat:
 	/* don't need to get the RCU readlock here - the process is dead and
 	 * can't be modifying its own credentials. But shut RCU-lockdep up */
@@ -765,7 +769,11 @@
 	 * leave this task alone and wait for reboot.
 	 */
 	if (unlikely(tsk->flags & PF_EXITING)) {
+#ifdef CONFIG_PANIC_ON_RECURSIVE_FAULT
+		panic("Recursive fault!\n");
+#else
 		pr_alert("Fixing recursive fault but reboot is needed!\n");
+#endif
 		/*
 		 * We can do this unlocked here. The futex code uses
 		 * this flag just to verify whether the pi state
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index c1195eb..c93d4df 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -853,7 +853,7 @@
 	 * This code is triggered unconditionally. Check the affinity
 	 * mask pointer. For CPU_MASK_OFFSTACK=n this is optimized out.
 	 */
-	if (desc->irq_common_data.affinity)
+	if (cpumask_available(desc->irq_common_data.affinity))
 		cpumask_copy(mask, desc->irq_common_data.affinity);
 	else
 		valid = false;
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index a1a07cf..6948518 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -125,7 +125,7 @@
 	return module_alloc(PAGE_SIZE);
 }
 
-static void free_insn_page(void *page)
+void __weak free_insn_page(void *page)
 {
 	module_memfree(page);
 }
diff --git a/kernel/module.c b/kernel/module.c
index dec20c7..13ad2f8 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1911,6 +1911,9 @@
 /* livepatching wants to disable read-only so it can frob module. */
 void module_disable_ro(const struct module *mod)
 {
+	if (!rodata_enabled)
+		return;
+
 	frob_text(&mod->core_layout, set_memory_rw);
 	frob_rodata(&mod->core_layout, set_memory_rw);
 	frob_ro_after_init(&mod->core_layout, set_memory_rw);
@@ -1920,6 +1923,9 @@
 
 void module_enable_ro(const struct module *mod, bool after_init)
 {
+	if (!rodata_enabled)
+		return;
+
 	frob_text(&mod->core_layout, set_memory_ro);
 	frob_rodata(&mod->core_layout, set_memory_ro);
 	frob_text(&mod->init_layout, set_memory_ro);
@@ -1952,6 +1958,9 @@
 {
 	struct module *mod;
 
+	if (!rodata_enabled)
+		return;
+
 	mutex_lock(&module_mutex);
 	list_for_each_entry_rcu(mod, &modules, list) {
 		if (mod->state == MODULE_STATE_UNFORMED)
@@ -1968,6 +1977,9 @@
 {
 	struct module *mod;
 
+	if (!rodata_enabled)
+		return;
+
 	mutex_lock(&module_mutex);
 	list_for_each_entry_rcu(mod, &modules, list) {
 		if (mod->state == MODULE_STATE_UNFORMED)
@@ -1981,10 +1993,12 @@
 
 static void disable_ro_nx(const struct module_layout *layout)
 {
-	frob_text(layout, set_memory_rw);
-	frob_rodata(layout, set_memory_rw);
+	if (rodata_enabled) {
+		frob_text(layout, set_memory_rw);
+		frob_rodata(layout, set_memory_rw);
+		frob_ro_after_init(layout, set_memory_rw);
+	}
 	frob_rodata(layout, set_memory_x);
-	frob_ro_after_init(layout, set_memory_rw);
 	frob_ro_after_init(layout, set_memory_x);
 	frob_writable_data(layout, set_memory_x);
 }
diff --git a/kernel/pid.c b/kernel/pid.c
index 693a643..fa704f8 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -322,8 +322,10 @@
 	}
 
 	if (unlikely(is_child_reaper(pid))) {
-		if (pid_ns_prepare_proc(ns))
+		if (pid_ns_prepare_proc(ns)) {
+			disable_pid_allocation(ns);
 			goto out_free;
+		}
 	}
 
 	get_pid_ns(ns);
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index a29eaee..bf60b37 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -94,6 +94,16 @@
 	  For more details, refer to the description of CONFIG_HIBERNATION
 	  for booting without resuming.
 
+config HIBERNATION_SKIP_CRC
+	bool "Skip LZO image CRC check"
+	default n
+	depends on HIBERNATION
+	---help---
+	  Some filesystem devices may have hw based integrity checks. In this
+	  scenario, repeating the integrity check in software is unnecessary
+	  and wasteful. This config option has no effect if uncompressed
+	  hibernation images are used.
+
 config ARCH_SAVE_PAGE_KEYS
 	bool
 
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 95db6b79..1f6aef2 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -606,9 +606,10 @@
 		}
 		atomic_set(&d->ready, 0);
 
-		for (i = 0; i < d->run_threads; i++)
-			*d->crc32 = crc32_le(*d->crc32,
-			                     d->unc[i], *d->unc_len[i]);
+		if (!IS_ENABLED(CONFIG_HIBERNATION_SKIP_CRC))
+			for (i = 0; i < d->run_threads; i++)
+				*d->crc32 = crc32_le(*d->crc32,
+						d->unc[i], *d->unc_len[i]);
 		atomic_set(&d->stop, 1);
 		wake_up(&d->done);
 	}
@@ -1455,7 +1456,8 @@
 		if (!snapshot_image_loaded(snapshot))
 			ret = -ENODATA;
 		if (!ret) {
-			if (swsusp_header->flags & SF_CRC32_MODE) {
+			if ((swsusp_header->flags & SF_CRC32_MODE) &&
+			    (!IS_ENABLED(CONFIG_HIBERNATION_SKIP_CRC))) {
 				if(handle->crc32 != swsusp_header->crc32) {
 					printk(KERN_ERR
 					       "PM: Invalid image CRC32!\n");
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 3012f95..396b020 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2172,6 +2172,8 @@
 	console_unlock();
 }
 
+#ifdef CONFIG_CONSOLE_FLUSH_ON_HOTPLUG
+
 /**
  * console_cpu_notify - print deferred console messages after CPU hotplug
  * @self: notifier struct
@@ -2197,6 +2199,8 @@
 	return NOTIFY_OK;
 }
 
+#endif
+
 /**
  * console_lock - lock the console system for exclusive use.
  *
@@ -2850,7 +2854,9 @@
 				unregister_console(con);
 		}
 	}
+#ifdef CONFIG_CONSOLE_FLUSH_ON_HOTPLUG
 	hotcpu_notifier(console_cpu_notify, 0);
+#endif
 	return 0;
 }
 late_initcall(printk_late_init);
diff --git a/kernel/resource.c b/kernel/resource.c
index 89778a3..fbea5af 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -633,7 +633,8 @@
 			alloc.start = constraint->alignf(constraint->alignf_data, &avail,
 					size, constraint->align);
 			alloc.end = alloc.start + size - 1;
-			if (resource_contains(&avail, &alloc)) {
+			if (alloc.start <= alloc.end &&
+			    resource_contains(&avail, &alloc)) {
 				new->start = alloc.start;
 				new->end = alloc.end;
 				return 0;
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 467801c..fb2e56c 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -76,6 +76,7 @@
 #include <linux/frame.h>
 #include <linux/prefetch.h>
 #include <linux/irq.h>
+#include <linux/cpufreq_times.h>
 
 #include <asm/switch_to.h>
 #include <asm/tlb.h>
@@ -2174,7 +2175,6 @@
 	wallclock = ktime_get_ns();
 	update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0);
 	update_task_ravg(p, rq, TASK_WAKE, wallclock, 0);
-	cpufreq_update_util(rq, 0);
 	raw_spin_unlock(&rq->lock);
 
 	rcu_read_lock();
@@ -2263,7 +2263,6 @@
 
 		update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0);
 		update_task_ravg(p, rq, TASK_WAKE, wallclock, 0);
-		cpufreq_update_util(rq, 0);
 		ttwu_activate(rq, p, ENQUEUE_WAKEUP);
 		note_task_waking(p, wallclock);
 	}
@@ -2309,6 +2308,7 @@
 	dl_se->dl_period = 0;
 	dl_se->flags = 0;
 	dl_se->dl_bw = 0;
+	dl_se->dl_density = 0;
 
 	dl_se->dl_throttled = 0;
 	dl_se->dl_yielded = 0;
@@ -2344,6 +2344,10 @@
 	memset(&p->se.statistics, 0, sizeof(p->se.statistics));
 #endif
 
+#ifdef CONFIG_CPU_FREQ_TIMES
+	cpufreq_task_times_init(p);
+#endif
+
 	RB_CLEAR_NODE(&p->dl.rb_node);
 	init_dl_task_timer(&p->dl);
 	__dl_clear_params(p);
@@ -3636,7 +3640,6 @@
 
 		update_task_ravg(prev, rq, PUT_PREV_TASK, wallclock, 0);
 		update_task_ravg(next, rq, PICK_NEXT_TASK, wallclock, 0);
-		cpufreq_update_util(rq, 0);
 		rq->nr_switches++;
 		rq->curr = next;
 		++*switch_count;
@@ -3645,7 +3648,6 @@
 		rq = context_switch(rq, prev, next, cookie); /* unlocks the rq */
 	} else {
 		update_task_ravg(prev, rq, TASK_UPDATE, wallclock, 0);
-		cpufreq_update_util(rq, 0);
 		lockdep_unpin_lock(&rq->lock, cookie);
 		raw_spin_unlock_irq(&rq->lock);
 	}
@@ -4156,6 +4158,7 @@
 	dl_se->dl_period = attr->sched_period ?: dl_se->dl_deadline;
 	dl_se->flags = attr->sched_flags;
 	dl_se->dl_bw = to_ratio(dl_se->dl_period, dl_se->dl_runtime);
+	dl_se->dl_density = to_ratio(dl_se->dl_deadline, dl_se->dl_runtime);
 
 	/*
 	 * Changing the parameters of a task is 'tricky' and we're not doing
diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c
index e4f48f1..50f2ea8 100644
--- a/kernel/sched/cputime.c
+++ b/kernel/sched/cputime.c
@@ -4,6 +4,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/static_key.h>
 #include <linux/context_tracking.h>
+#include <linux/cpufreq_times.h>
 #include "sched.h"
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
@@ -157,6 +158,11 @@
 
 	/* Account for user time used */
 	acct_account_cputime(p);
+
+#ifdef CONFIG_CPU_FREQ_TIMES
+	/* Account power usage for user time */
+	cpufreq_acct_update_power(p, cputime);
+#endif
 }
 
 /*
@@ -207,6 +213,10 @@
 
 	/* Account for system time used */
 	acct_account_cputime(p);
+#ifdef CONFIG_CPU_FREQ_TIMES
+	/* Account power usage for system time */
+	cpufreq_acct_update_power(p, cputime);
+#endif
 }
 
 /*
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index 0a295ac..d7c7dd6 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -485,13 +485,84 @@
 }
 
 /*
- * When a -deadline entity is queued back on the runqueue, its runtime and
- * deadline might need updating.
+ * Revised wakeup rule [1]: For self-suspending tasks, rather then
+ * re-initializing task's runtime and deadline, the revised wakeup
+ * rule adjusts the task's runtime to avoid the task to overrun its
+ * density.
  *
- * The policy here is that we update the deadline of the entity only if:
- *  - the current deadline is in the past,
- *  - using the remaining runtime with the current deadline would make
- *    the entity exceed its bandwidth.
+ * Reasoning: a task may overrun the density if:
+ *    runtime / (deadline - t) > dl_runtime / dl_deadline
+ *
+ * Therefore, runtime can be adjusted to:
+ *     runtime = (dl_runtime / dl_deadline) * (deadline - t)
+ *
+ * In such way that runtime will be equal to the maximum density
+ * the task can use without breaking any rule.
+ *
+ * [1] Luca Abeni, Giuseppe Lipari, and Juri Lelli. 2015. Constant
+ * bandwidth server revisited. SIGBED Rev. 11, 4 (January 2015), 19-24.
+ */
+static void
+update_dl_revised_wakeup(struct sched_dl_entity *dl_se, struct rq *rq)
+{
+	u64 laxity = dl_se->deadline - rq_clock(rq);
+
+	/*
+	 * If the task has deadline < period, and the deadline is in the past,
+	 * it should already be throttled before this check.
+	 *
+	 * See update_dl_entity() comments for further details.
+	 */
+	WARN_ON(dl_time_before(dl_se->deadline, rq_clock(rq)));
+
+	dl_se->runtime = (dl_se->dl_density * laxity) >> 20;
+}
+
+/*
+ * Regarding the deadline, a task with implicit deadline has a relative
+ * deadline == relative period. A task with constrained deadline has a
+ * relative deadline <= relative period.
+ *
+ * We support constrained deadline tasks. However, there are some restrictions
+ * applied only for tasks which do not have an implicit deadline. See
+ * update_dl_entity() to know more about such restrictions.
+ *
+ * The dl_is_implicit() returns true if the task has an implicit deadline.
+ */
+static inline bool dl_is_implicit(struct sched_dl_entity *dl_se)
+{
+	return dl_se->dl_deadline == dl_se->dl_period;
+}
+
+/*
+ * When a deadline entity is placed in the runqueue, its runtime and deadline
+ * might need to be updated. This is done by a CBS wake up rule. There are two
+ * different rules: 1) the original CBS; and 2) the Revisited CBS.
+ *
+ * When the task is starting a new period, the Original CBS is used. In this
+ * case, the runtime is replenished and a new absolute deadline is set.
+ *
+ * When a task is queued before the begin of the next period, using the
+ * remaining runtime and deadline could make the entity to overflow, see
+ * dl_entity_overflow() to find more about runtime overflow. When such case
+ * is detected, the runtime and deadline need to be updated.
+ *
+ * If the task has an implicit deadline, i.e., deadline == period, the Original
+ * CBS is applied. the runtime is replenished and a new absolute deadline is
+ * set, as in the previous cases.
+ *
+ * However, the Original CBS does not work properly for tasks with
+ * deadline < period, which are said to have a constrained deadline. By
+ * applying the Original CBS, a constrained deadline task would be able to run
+ * runtime/deadline in a period. With deadline < period, the task would
+ * overrun the runtime/period allowed bandwidth, breaking the admission test.
+ *
+ * In order to prevent this misbehave, the Revisited CBS is used for
+ * constrained deadline tasks when a runtime overflow is detected. In the
+ * Revisited CBS, rather than replenishing & setting a new absolute deadline,
+ * the remaining runtime of the task is reduced to avoid runtime overflow.
+ * Please refer to the comments update_dl_revised_wakeup() function to find
+ * more about the Revised CBS rule.
  */
 static void update_dl_entity(struct sched_dl_entity *dl_se,
 			     struct sched_dl_entity *pi_se)
@@ -501,6 +572,14 @@
 
 	if (dl_time_before(dl_se->deadline, rq_clock(rq)) ||
 	    dl_entity_overflow(dl_se, pi_se, rq_clock(rq))) {
+
+		if (unlikely(!dl_is_implicit(dl_se) &&
+			     !dl_time_before(dl_se->deadline, rq_clock(rq)) &&
+			     !dl_se->dl_boosted)){
+			update_dl_revised_wakeup(dl_se, rq);
+			return;
+		}
+
 		dl_se->deadline = rq_clock(rq) + pi_se->dl_deadline;
 		dl_se->runtime = pi_se->dl_runtime;
 	}
@@ -964,11 +1043,6 @@
 	__dequeue_dl_entity(dl_se);
 }
 
-static inline bool dl_is_constrained(struct sched_dl_entity *dl_se)
-{
-	return dl_se->dl_deadline < dl_se->dl_period;
-}
-
 static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags)
 {
 	struct task_struct *pi_task = rt_mutex_get_top_task(p);
@@ -1000,7 +1074,7 @@
 	 * If that is the case, the task will be throttled and
 	 * the replenishment timer will be set to the next period.
 	 */
-	if (!p->dl.dl_throttled && dl_is_constrained(&p->dl))
+	if (!p->dl.dl_throttled && !dl_is_implicit(&p->dl))
 		dl_check_constrained_dl(&p->dl);
 
 	/*
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 04ba6d0..78c433a 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -2511,7 +2511,8 @@
 		return;
 
 
-	down_read(&mm->mmap_sem);
+	if (!down_read_trylock(&mm->mmap_sem))
+		return;
 	vma = find_vma(mm, start);
 	if (!vma) {
 		reset_ptenuma_scan(p);
@@ -6871,6 +6872,13 @@
 	if (!sg->group_weight)
 		return true;
 
+	/*
+	 * Don't skip a group if a task affinity allows it
+	 * to run only on that group.
+	 */
+	if (cpumask_subset(tsk_cpus_allowed(p), sched_group_cpus(sg)))
+		return false;
+
 	if (!task_fits_max(p, fcpu))
 		return true;
 
@@ -7357,6 +7365,12 @@
 }
 #endif
 
+enum fastpaths {
+	NONE = 0,
+	SYNC_WAKEUP,
+	PREV_CPU_BIAS,
+};
+
 static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync)
 {
 	bool boosted, prefer_idle;
@@ -7367,6 +7381,7 @@
 	struct cpumask *rtg_target = find_rtg_target(p);
 	struct find_best_target_env fbt_env;
 	u64 start_t = 0;
+	int fastpath = 0;
 
 	if (trace_sched_task_util_enabled())
 		start_t = sched_clock();
@@ -7403,12 +7418,17 @@
 		if (bias_to_waker_cpu(p, cpu, rtg_target)) {
 			schedstat_inc(p->se.statistics.nr_wakeups_secb_sync);
 			schedstat_inc(this_rq()->eas_stats.secb_sync);
-			return cpu;
+			target_cpu = cpu;
+			fastpath = SYNC_WAKEUP;
+			goto out;
 		}
 	}
 
-	if (bias_to_prev_cpu(p, rtg_target))
-		return prev_cpu;
+	if (bias_to_prev_cpu(p, rtg_target)) {
+		target_cpu = prev_cpu;
+		fastpath = PREV_CPU_BIAS;
+		goto out;
+	}
 
 	rcu_read_lock();
 
@@ -7495,11 +7515,12 @@
 	schedstat_inc(this_rq()->eas_stats.secb_count);
 
 unlock:
-	trace_sched_task_util(p, next_cpu, backup_cpu, target_cpu, sync,
-			      fbt_env.need_idle, fbt_env.placement_boost,
-			      rtg_target ? cpumask_first(rtg_target) : -1,
-			      start_t);
 	rcu_read_unlock();
+out:
+	trace_sched_task_util(p, next_cpu, backup_cpu, target_cpu, sync,
+			      fbt_env.need_idle, fastpath,
+			      fbt_env.placement_boost, rtg_target ?
+			      cpumask_first(rtg_target) : -1, start_t);
 	return target_cpu;
 }
 
@@ -8790,13 +8811,12 @@
 	int max_cap_cpu;
 	unsigned long flags;
 
-	capacity = min(capacity, thermal_cap(cpu));
-
-	cpu_rq(cpu)->cpu_capacity_orig = capacity;
-
 	capacity *= arch_scale_max_freq_capacity(sd, cpu);
 	capacity >>= SCHED_CAPACITY_SHIFT;
 
+	capacity = min(capacity, thermal_cap(cpu));
+	cpu_rq(cpu)->cpu_capacity_orig = capacity;
+
 	mcc = &cpu_rq(cpu)->rd->max_cpu_capacity;
 
 	raw_spin_lock_irqsave(&mcc->lock, flags);
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index f27ab13..61aa3c7 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -798,7 +798,6 @@
 	int cstate, wakeup_latency, wakeup_energy;
 	u64 window_start;
 	s64 cum_window_start;
-	u64 load_reported_window;
 	unsigned long walt_flags;
 
 	u64 cur_irqload;
@@ -1862,6 +1861,8 @@
 }
 
 #ifdef CONFIG_SCHED_WALT
+extern atomic64_t walt_irq_work_lastq_ws;
+
 static inline unsigned long
 cpu_util_freq_walt(int cpu, struct sched_walt_cpu_load *walt_load)
 {
@@ -1898,7 +1899,7 @@
 		walt_load->prev_window_util = util;
 		walt_load->nl = nl;
 		walt_load->pl = pl;
-		walt_load->ws = rq->load_reported_window;
+		walt_load->ws = atomic64_read(&walt_irq_work_lastq_ws);
 	}
 
 	return (util >= capacity) ? capacity : util;
@@ -2268,22 +2269,8 @@
 	struct update_util_data *data;
 
 #ifdef CONFIG_SCHED_WALT
-	unsigned int exception_flags = SCHED_CPUFREQ_INTERCLUSTER_MIG |
-				SCHED_CPUFREQ_PL | SCHED_CPUFREQ_EARLY_DET |
-				SCHED_CPUFREQ_FORCE_UPDATE;
-
-	/*
-	 * Skip if we've already reported, but not if this is an inter-cluster
-	 * migration. Also only allow WALT update sites.
-	 */
 	if (!(flags & SCHED_CPUFREQ_WALT))
 		return;
-	if (!sched_disable_window_stats &&
-		(rq->load_reported_window == rq->window_start) &&
-		!(flags & exception_flags))
-		return;
-	if (!(flags & exception_flags))
-		rq->load_reported_window = rq->window_start;
 #endif
 
 	data = rcu_dereference_sched(*per_cpu_ptr(&cpufreq_update_util_data,
diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c
index a9fb367..a2debf9 100644
--- a/kernel/sched/walt.c
+++ b/kernel/sched/walt.c
@@ -44,7 +44,7 @@
 static struct cpu_cycle_counter_cb cpu_cycle_counter_cb;
 static bool use_cycle_counter;
 DEFINE_MUTEX(cluster_lock);
-static atomic64_t walt_irq_work_lastq_ws;
+atomic64_t walt_irq_work_lastq_ws;
 
 static struct irq_work walt_cpufreq_irq_work;
 static struct irq_work walt_migration_irq_work;
@@ -847,8 +847,7 @@
 
 	if (p == src_rq->ed_task) {
 		src_rq->ed_task = NULL;
-		if (!dest_rq->ed_task)
-			dest_rq->ed_task = p;
+		dest_rq->ed_task = p;
 	}
 
 done:
diff --git a/kernel/smpboot.c b/kernel/smpboot.c
index 1650578..10c5a3a 100644
--- a/kernel/smpboot.c
+++ b/kernel/smpboot.c
@@ -121,7 +121,45 @@
 		}
 
 		if (kthread_should_park()) {
+			/*
+			 * Serialize against wakeup. If we take the lock first,
+			 * wakeup is skipped. If we run later, we observe,
+			 * TASK_RUNNING update from wakeup path, before moving
+			 * forward. This helps avoid the race, where wakeup
+			 * observes TASK_INTERRUPTIBLE, and also observes
+			 * the TASK_PARKED in kthread_parkme() before updating
+			 * task state to TASK_RUNNING. In this case, kthread
+			 * gets parked in TASK_RUNNING state. This results
+			 * in panic later on in kthread_unpark(), as it sees
+			 * KTHREAD_IS_PARKED flag set but fails to rebind the
+			 * kthread, due to it being not in TASK_PARKED state.
+			 *
+			 * Control thread                      Hotplug Thread
+			 *
+			 * kthread_park()
+			 *   set KTHREAD_SHOULD_PARK
+			 *                                smpboot_thread_fn()
+			 *                                  set_current_state(
+			 *                                  TASK_INTERRUPTIBLE);
+			 *                                  kthread_parkme()
+			 *
+			 *   wake_up_process()
+			 *
+			 * raw_spin_lock_irqsave(&p->pi_lock, flags);
+			 * if (!(p->state & state))
+			 *            goto out;
+			 *
+			 *                                  __set_current_state(
+			 *                                  TASK_PARKED);
+			 *
+			 * if (p->on_rq && ttwu_remote(p, wake_flags))
+			 *   ttwu_remote()
+			 *     p->state = TASK_RUNNING;
+			 *                                   schedule();
+			 */
+			raw_spin_lock(&current->pi_lock);
 			__set_current_state(TASK_RUNNING);
+			raw_spin_unlock(&current->pi_lock);
 			preempt_enable();
 			if (ht->park && td->status == HP_THREAD_ACTIVE) {
 				BUG_ON(td->cpu != smp_processor_id());
diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c
index 79bbaf0..59b482f 100644
--- a/kernel/trace/trace_irqsoff.c
+++ b/kernel/trace/trace_irqsoff.c
@@ -478,14 +478,11 @@
 #ifdef CONFIG_PREEMPTIRQ_EVENTS
 	struct irqsoff_store *is = &per_cpu(the_irqsoff,
 						raw_smp_processor_id());
+	u64 delta = sched_clock() - is->ts;
 
-	if (!is->ts) {
-		is->ts = sched_clock();
-		is->caddr[0] = CALLER_ADDR0;
-		is->caddr[1] = CALLER_ADDR1;
-		is->caddr[2] = CALLER_ADDR2;
-		is->caddr[3] = CALLER_ADDR3;
-	}
+	if (delta > sysctl_irqsoff_tracing_threshold_ns)
+		trace_irqs_disable(delta, is->caddr[0], is->caddr[1],
+						is->caddr[2], is->caddr[3]);
 #endif /* CONFIG_PREEMPTIRQ_EVENTS */
 
 	if (!preempt_trace() && irq_trace())
@@ -497,15 +494,12 @@
 #ifdef CONFIG_PREEMPTIRQ_EVENTS
 	struct irqsoff_store *is = &per_cpu(the_irqsoff,
 						raw_smp_processor_id());
-	u64 delta = 0;
 
-	if (is->ts) {
-		delta = sched_clock() - is->ts;
-		is->ts = 0;
-	}
-	if (delta > sysctl_irqsoff_tracing_threshold_ns)
-		trace_irqs_disable(delta, is->caddr[0], is->caddr[1],
-						is->caddr[2], is->caddr[3]);
+	is->ts = sched_clock();
+	is->caddr[0] = CALLER_ADDR0;
+	is->caddr[1] = CALLER_ADDR1;
+	is->caddr[2] = CALLER_ADDR2;
+	is->caddr[3] = CALLER_ADDR3;
 #endif /* CONFIG_PREEMPTIRQ_EVENTS */
 
 	if (!preempt_trace() && irq_trace())
diff --git a/kernel/user.c b/kernel/user.c
index b069ccb..41e94e4 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/export.h>
 #include <linux/user_namespace.h>
+#include <linux/proc_fs.h>
 #include <linux/proc_ns.h>
 
 /*
@@ -201,6 +202,7 @@
 		}
 		spin_unlock_irq(&uidhash_lock);
 	}
+	proc_register_uid(uid);
 
 	return up;
 
@@ -222,6 +224,7 @@
 	spin_lock_irq(&uidhash_lock);
 	uid_hash_insert(&root_user, uidhashentry(GLOBAL_ROOT_UID));
 	spin_unlock_irq(&uidhash_lock);
+	proc_register_uid(GLOBAL_ROOT_UID);
 
 	return 0;
 }
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 558be53..079d91a 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -834,6 +834,17 @@
 	default 0 if !BOOTPARAM_SOFTLOCKUP_PANIC
 	default 1 if BOOTPARAM_SOFTLOCKUP_PANIC
 
+config PANIC_ON_RECURSIVE_FAULT
+	bool "Panic on recursive faults during task exit"
+	help
+	  Panic upon the detection of a recursive fault during task exit,
+	  rather than putting the task into an uninterruptible sleep.
+	  This is particularly useful for debugging system hangs in
+	  scenarios where the task experiencing the fault is critical
+	  for system operation, rendering the system inoperable.
+
+	  Say N if unsure.
+
 config DETECT_HUNG_TASK
 	bool "Detect Hung Tasks"
 	depends on DEBUG_KERNEL
diff --git a/mm/cma.c b/mm/cma.c
index 5fc1809..e97ad01 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -438,6 +438,8 @@
 	struct page *page = NULL;
 	int retry_after_sleep = 0;
 	int ret = -ENOMEM;
+	int max_retries = 2;
+	int available_regions = 0;
 
 	if (!cma || !cma->count)
 		return NULL;
@@ -464,9 +466,16 @@
 				bitmap_maxno, start, bitmap_count, mask,
 				offset);
 		if (bitmap_no >= bitmap_maxno) {
-			if (retry_after_sleep < 2) {
+			if (retry_after_sleep < max_retries) {
 				start = 0;
 				/*
+				 * update max retries if available free regions
+				 * are less.
+				 */
+				if (available_regions < 3)
+					max_retries = 5;
+				available_regions = 0;
+				/*
 				 * Page may be momentarily pinned by some other
 				 * process which has been scheduled out, eg.
 				 * in exit path, during unmap call, or process
@@ -483,6 +492,8 @@
 				break;
 			}
 		}
+
+		available_regions++;
 		bitmap_set(cma->bitmap, bitmap_no, bitmap_count);
 		/*
 		 * It's safe to drop the lock here. We've marked this region for
diff --git a/mm/filemap.c b/mm/filemap.c
index 03c79ef..211df83 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -618,7 +618,7 @@
 	VM_BUG_ON_PAGE(!PageLocked(new), new);
 	VM_BUG_ON_PAGE(new->mapping, new);
 
-	error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
+	error = radix_tree_preload(gfp_mask & GFP_RECLAIM_MASK);
 	if (!error) {
 		struct address_space *mapping = old->mapping;
 		void (*freepage)(struct page *);
@@ -674,7 +674,7 @@
 			return error;
 	}
 
-	error = radix_tree_maybe_preload(gfp_mask & ~__GFP_HIGHMEM);
+	error = radix_tree_maybe_preload(gfp_mask & GFP_RECLAIM_MASK);
 	if (error) {
 		if (!huge)
 			mem_cgroup_cancel_charge(page, memcg, false);
@@ -1249,8 +1249,7 @@
 		if (fgp_flags & FGP_ACCESSED)
 			__SetPageReferenced(page);
 
-		err = add_to_page_cache_lru(page, mapping, offset,
-				gfp_mask & GFP_RECLAIM_MASK);
+		err = add_to_page_cache_lru(page, mapping, offset, gfp_mask);
 		if (unlikely(err)) {
 			put_page(page);
 			page = NULL;
@@ -1998,7 +1997,7 @@
 		if (!page)
 			return -ENOMEM;
 
-		ret = add_to_page_cache_lru(page, mapping, offset, gfp_mask & GFP_KERNEL);
+		ret = add_to_page_cache_lru(page, mapping, offset, gfp_mask);
 		if (ret == 0)
 			ret = mapping->a_ops->readpage(file, page);
 		else if (ret == -EEXIST)
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index e6fbdf4..ca18dc0 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -2506,13 +2506,13 @@
 	if (mapping && mapping_cap_account_dirty(mapping)) {
 		struct inode *inode = mapping->host;
 		struct bdi_writeback *wb;
-		bool locked;
+		struct wb_lock_cookie cookie = {};
 
-		wb = unlocked_inode_to_wb_begin(inode, &locked);
+		wb = unlocked_inode_to_wb_begin(inode, &cookie);
 		current->nr_dirtied--;
 		dec_node_page_state(page, NR_DIRTIED);
 		dec_wb_stat(wb, WB_DIRTIED);
-		unlocked_inode_to_wb_end(inode, locked);
+		unlocked_inode_to_wb_end(inode, &cookie);
 	}
 }
 EXPORT_SYMBOL(account_page_redirty);
@@ -2618,15 +2618,15 @@
 	if (mapping_cap_account_dirty(mapping)) {
 		struct inode *inode = mapping->host;
 		struct bdi_writeback *wb;
-		bool locked;
+		struct wb_lock_cookie cookie = {};
 
 		lock_page_memcg(page);
-		wb = unlocked_inode_to_wb_begin(inode, &locked);
+		wb = unlocked_inode_to_wb_begin(inode, &cookie);
 
 		if (TestClearPageDirty(page))
 			account_page_cleaned(page, mapping, wb);
 
-		unlocked_inode_to_wb_end(inode, locked);
+		unlocked_inode_to_wb_end(inode, &cookie);
 		unlock_page_memcg(page);
 	} else {
 		ClearPageDirty(page);
@@ -2658,7 +2658,7 @@
 	if (mapping && mapping_cap_account_dirty(mapping)) {
 		struct inode *inode = mapping->host;
 		struct bdi_writeback *wb;
-		bool locked;
+		struct wb_lock_cookie cookie = {};
 
 		/*
 		 * Yes, Virginia, this is indeed insane.
@@ -2695,7 +2695,7 @@
 		 * always locked coming in here, so we get the desired
 		 * exclusion.
 		 */
-		wb = unlocked_inode_to_wb_begin(inode, &locked);
+		wb = unlocked_inode_to_wb_begin(inode, &cookie);
 		if (TestClearPageDirty(page)) {
 			mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_DIRTY);
 			dec_node_page_state(page, NR_FILE_DIRTY);
@@ -2703,7 +2703,7 @@
 			dec_wb_stat(wb, WB_RECLAIMABLE);
 			ret = 1;
 		}
-		unlocked_inode_to_wb_end(inode, locked);
+		unlocked_inode_to_wb_end(inode, &cookie);
 		return ret;
 	}
 	return TestClearPageDirty(page);
diff --git a/mm/slab.c b/mm/slab.c
index 1f82d16..c59844d 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -4096,7 +4096,8 @@
 	next_reap_node();
 out:
 	/* Set up the next iteration */
-	schedule_delayed_work(work, round_jiffies_relative(REAPTIMEOUT_AC));
+	schedule_delayed_work_on(smp_processor_id(), work,
+				round_jiffies_relative(REAPTIMEOUT_AC));
 }
 
 #ifdef CONFIG_SLABINFO
diff --git a/mm/vmpressure.c b/mm/vmpressure.c
index 1306f32..e468da6 100644
--- a/mm/vmpressure.c
+++ b/mm/vmpressure.c
@@ -423,7 +423,7 @@
 void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
 		unsigned long scanned, unsigned long reclaimed)
 {
-	if (!memcg)
+	if (!memcg && tree)
 		vmpressure_global(gfp, scanned, reclaimed);
 
 	if (IS_ENABLED(CONFIG_MEMCG))
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 658d62c..c5b94d61 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -3023,7 +3023,7 @@
 	unsigned long nr_reclaimed;
 	struct scan_control sc = {
 		.nr_to_reclaim = SWAP_CLUSTER_MAX,
-		.gfp_mask = (gfp_mask = memalloc_noio_flags(gfp_mask)),
+		.gfp_mask = memalloc_noio_flags(gfp_mask),
 		.reclaim_idx = gfp_zone(gfp_mask),
 		.order = order,
 		.nodemask = nodemask,
@@ -3038,12 +3038,12 @@
 	 * 1 is returned so that the page allocator does not OOM kill at this
 	 * point.
 	 */
-	if (throttle_direct_reclaim(gfp_mask, zonelist, nodemask))
+	if (throttle_direct_reclaim(sc.gfp_mask, zonelist, nodemask))
 		return 1;
 
 	trace_mm_vmscan_direct_reclaim_begin(order,
 				sc.may_writepage,
-				gfp_mask,
+				sc.gfp_mask,
 				sc.reclaim_idx);
 
 	nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
@@ -3827,16 +3827,15 @@
 	const unsigned long nr_pages = 1 << order;
 	struct task_struct *p = current;
 	struct reclaim_state reclaim_state;
-	int classzone_idx = gfp_zone(gfp_mask);
 	struct scan_control sc = {
 		.nr_to_reclaim = max(nr_pages, SWAP_CLUSTER_MAX),
-		.gfp_mask = (gfp_mask = memalloc_noio_flags(gfp_mask)),
+		.gfp_mask = memalloc_noio_flags(gfp_mask),
 		.order = order,
 		.priority = NODE_RECLAIM_PRIORITY,
 		.may_writepage = !!(node_reclaim_mode & RECLAIM_WRITE),
 		.may_unmap = !!(node_reclaim_mode & RECLAIM_UNMAP),
 		.may_swap = 1,
-		.reclaim_idx = classzone_idx,
+		.reclaim_idx = gfp_zone(gfp_mask),
 	};
 
 	cond_resched();
@@ -3846,7 +3845,7 @@
 	 * and RECLAIM_UNMAP.
 	 */
 	p->flags |= PF_MEMALLOC | PF_SWAPWRITE;
-	lockdep_set_current_reclaim_state(gfp_mask);
+	lockdep_set_current_reclaim_state(sc.gfp_mask);
 	reclaim_state.reclaimed_slab = 0;
 	p->reclaim_state = &reclaim_state;
 
diff --git a/mm/vmstat.c b/mm/vmstat.c
index f97fb09..8bd62ed 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -1356,8 +1356,6 @@
 			return zone == compare;
 	}
 
-	/* The zone must be somewhere! */
-	WARN_ON_ONCE(1);
 	return false;
 }
 
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 7671441..fb3e2a5 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -29,6 +29,7 @@
 #include <linux/net_tstamp.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
+#include <linux/phy.h>
 #include <net/arp.h>
 #include <net/switchdev.h>
 
@@ -658,8 +659,11 @@
 {
 	const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
 	const struct ethtool_ops *ops = vlan->real_dev->ethtool_ops;
+	struct phy_device *phydev = vlan->real_dev->phydev;
 
-	if (ops->get_ts_info) {
+	if (phydev && phydev->drv && phydev->drv->ts_info) {
+		 return phydev->drv->ts_info(phydev, info);
+	} else if (ops->get_ts_info) {
 		return ops->get_ts_info(vlan->real_dev, info);
 	} else {
 		info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index dc59eae..cc06149 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -749,18 +749,31 @@
 }
 
 static void hci_req_add_le_create_conn(struct hci_request *req,
-				       struct hci_conn *conn)
+				       struct hci_conn *conn,
+				       bdaddr_t *direct_rpa)
 {
 	struct hci_cp_le_create_conn cp;
 	struct hci_dev *hdev = conn->hdev;
 	u8 own_addr_type;
 
-	/* Update random address, but set require_privacy to false so
-	 * that we never connect with an non-resolvable address.
+	/* If direct address was provided we use it instead of current
+	 * address.
 	 */
-	if (hci_update_random_address(req, false, conn_use_rpa(conn),
-				      &own_addr_type))
-		return;
+	if (direct_rpa) {
+		if (bacmp(&req->hdev->random_addr, direct_rpa))
+			hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
+								direct_rpa);
+
+		/* direct address is always RPA */
+		own_addr_type = ADDR_LE_DEV_RANDOM;
+	} else {
+		/* Update random address, but set require_privacy to false so
+		 * that we never connect with an non-resolvable address.
+		 */
+		if (hci_update_random_address(req, false, conn_use_rpa(conn),
+					      &own_addr_type))
+			return;
+	}
 
 	memset(&cp, 0, sizeof(cp));
 
@@ -825,7 +838,7 @@
 
 struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
 				u8 dst_type, u8 sec_level, u16 conn_timeout,
-				u8 role)
+				u8 role, bdaddr_t *direct_rpa)
 {
 	struct hci_conn_params *params;
 	struct hci_conn *conn;
@@ -940,7 +953,7 @@
 		hci_dev_set_flag(hdev, HCI_LE_SCAN_INTERRUPTED);
 	}
 
-	hci_req_add_le_create_conn(&req, conn);
+	hci_req_add_le_create_conn(&req, conn, direct_rpa);
 
 create_conn:
 	err = hci_req_run(&req, create_le_conn_complete);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 3ac89e9..4bd72d2 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -548,6 +548,7 @@
 {
 	struct hci_dev *hdev = req->hdev;
 	u8 events[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+	bool changed = false;
 
 	/* If Connectionless Slave Broadcast master role is supported
 	 * enable all necessary events for it.
@@ -557,6 +558,7 @@
 		events[1] |= 0x80;	/* Synchronization Train Complete */
 		events[2] |= 0x10;	/* Slave Page Response Timeout */
 		events[2] |= 0x20;	/* CSB Channel Map Change */
+		changed = true;
 	}
 
 	/* If Connectionless Slave Broadcast slave role is supported
@@ -567,13 +569,24 @@
 		events[2] |= 0x02;	/* CSB Receive */
 		events[2] |= 0x04;	/* CSB Timeout */
 		events[2] |= 0x08;	/* Truncated Page Complete */
+		changed = true;
 	}
 
 	/* Enable Authenticated Payload Timeout Expired event if supported */
-	if (lmp_ping_capable(hdev) || hdev->le_features[0] & HCI_LE_PING)
+	if (lmp_ping_capable(hdev) || hdev->le_features[0] & HCI_LE_PING) {
 		events[2] |= 0x80;
+		changed = true;
+	}
 
-	hci_req_add(req, HCI_OP_SET_EVENT_MASK_PAGE_2, sizeof(events), events);
+	/* Some Broadcom based controllers indicate support for Set Event
+	 * Mask Page 2 command, but then actually do not support it. Since
+	 * the default value is all bits set to zero, the command is only
+	 * required if the event mask has to be changed. In case no change
+	 * to the event mask is needed, skip this command.
+	 */
+	if (changed)
+		hci_req_add(req, HCI_OP_SET_EVENT_MASK_PAGE_2,
+			    sizeof(events), events);
 }
 
 static int hci_init3_req(struct hci_request *req, unsigned long opt)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index e17aacb..d2f9eb1 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -4646,7 +4646,8 @@
 /* This function requires the caller holds hdev->lock */
 static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
 					      bdaddr_t *addr,
-					      u8 addr_type, u8 adv_type)
+					      u8 addr_type, u8 adv_type,
+					      bdaddr_t *direct_rpa)
 {
 	struct hci_conn *conn;
 	struct hci_conn_params *params;
@@ -4697,7 +4698,8 @@
 	}
 
 	conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW,
-			      HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER);
+			      HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER,
+			      direct_rpa);
 	if (!IS_ERR(conn)) {
 		/* If HCI_AUTO_CONN_EXPLICIT is set, conn is already owned
 		 * by higher layer that tried to connect, if no then
@@ -4807,8 +4809,13 @@
 		bdaddr_type = irk->addr_type;
 	}
 
-	/* Check if we have been requested to connect to this device */
-	conn = check_pending_le_conn(hdev, bdaddr, bdaddr_type, type);
+	/* Check if we have been requested to connect to this device.
+	 *
+	 * direct_addr is set only for directed advertising reports (it is NULL
+	 * for advertising reports) and is already verified to be RPA above.
+	 */
+	conn = check_pending_le_conn(hdev, bdaddr, bdaddr_type, type,
+								direct_addr);
 	if (conn && type == LE_ADV_IND) {
 		/* Store report for later inclusion by
 		 * mgmt_device_connected
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 2bbca23..1fc23cb 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -7148,7 +7148,7 @@
 			hcon = hci_connect_le(hdev, dst, dst_type,
 					      chan->sec_level,
 					      HCI_LE_CONN_TIMEOUT,
-					      HCI_ROLE_SLAVE);
+					      HCI_ROLE_SLAVE, NULL);
 		else
 			hcon = hci_connect_le_scan(hdev, dst, dst_type,
 						   chan->sec_level,
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 658c900..ead4d1b 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -2233,8 +2233,14 @@
 	else
 		sec_level = authreq_to_seclevel(auth);
 
-	if (smp_sufficient_security(hcon, sec_level, SMP_USE_LTK))
+	if (smp_sufficient_security(hcon, sec_level, SMP_USE_LTK)) {
+		/* If link is already encrypted with sufficient security we
+		 * still need refresh encryption as per Core Spec 5.0 Vol 3,
+		 * Part H 2.4.6
+		 */
+		smp_ltk_encrypt(conn, hcon->sec_level);
 		return 0;
+	}
 
 	if (sec_level > hcon->pending_sec_level)
 		hcon->pending_sec_level = sec_level;
diff --git a/net/bridge/netfilter/ebt_among.c b/net/bridge/netfilter/ebt_among.c
index 9637a68..9adf162 100644
--- a/net/bridge/netfilter/ebt_among.c
+++ b/net/bridge/netfilter/ebt_among.c
@@ -177,6 +177,28 @@
 	return w && w->poolsize >= (INT_MAX / sizeof(struct ebt_mac_wormhash_tuple));
 }
 
+static bool wormhash_offset_invalid(int off, unsigned int len)
+{
+	if (off == 0) /* not present */
+		return false;
+
+	if (off < (int)sizeof(struct ebt_among_info) ||
+	    off % __alignof__(struct ebt_mac_wormhash))
+		return true;
+
+	off += sizeof(struct ebt_mac_wormhash);
+
+	return off > len;
+}
+
+static bool wormhash_sizes_valid(const struct ebt_mac_wormhash *wh, int a, int b)
+{
+	if (a == 0)
+		a = sizeof(struct ebt_among_info);
+
+	return ebt_mac_wormhash_size(wh) + a == b;
+}
+
 static int ebt_among_mt_check(const struct xt_mtchk_param *par)
 {
 	const struct ebt_among_info *info = par->matchinfo;
@@ -189,6 +211,10 @@
 	if (expected_length > em->match_size)
 		return -EINVAL;
 
+	if (wormhash_offset_invalid(info->wh_dst_ofs, em->match_size) ||
+	    wormhash_offset_invalid(info->wh_src_ofs, em->match_size))
+		return -EINVAL;
+
 	wh_dst = ebt_among_wh_dst(info);
 	if (poolsize_invalid(wh_dst))
 		return -EINVAL;
@@ -201,6 +227,14 @@
 	if (poolsize_invalid(wh_src))
 		return -EINVAL;
 
+	if (info->wh_src_ofs < info->wh_dst_ofs) {
+		if (!wormhash_sizes_valid(wh_src, info->wh_src_ofs, info->wh_dst_ofs))
+			return -EINVAL;
+	} else {
+		if (!wormhash_sizes_valid(wh_dst, info->wh_dst_ofs, info->wh_src_ofs))
+			return -EINVAL;
+	}
+
 	expected_length += ebt_mac_wormhash_size(wh_src);
 
 	if (em->match_size != EBT_ALIGN(expected_length)) {
diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
index d3f6c26..255c0a0 100644
--- a/net/ceph/osdmap.c
+++ b/net/ceph/osdmap.c
@@ -295,6 +295,7 @@
 		u32 yes;
 		struct crush_rule *r;
 
+		err = -EINVAL;
 		ceph_decode_32_safe(p, end, yes, bad);
 		if (!yes) {
 			dout("crush_decode NO rule %d off %x %p to %p\n",
diff --git a/net/core/dev.c b/net/core/dev.c
index fe1dc21..802b3fa 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -995,7 +995,7 @@
 {
 	if (*name == '\0')
 		return false;
-	if (strlen(name) >= IFNAMSIZ)
+	if (strnlen(name, IFNAMSIZ) == IFNAMSIZ)
 		return false;
 	if (!strcmp(name, ".") || !strcmp(name, ".."))
 		return false;
@@ -2669,7 +2669,7 @@
 		if (unlikely(!pskb_may_pull(skb, sizeof(struct ethhdr))))
 			return 0;
 
-		eth = (struct ethhdr *)skb_mac_header(skb);
+		eth = (struct ethhdr *)skb->data;
 		type = eth->h_proto;
 	}
 
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index eecad95..cb9a16b 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1139,10 +1139,6 @@
 		lladdr = neigh->ha;
 	}
 
-	if (new & NUD_CONNECTED)
-		neigh->confirmed = jiffies;
-	neigh->updated = jiffies;
-
 	/* If entry was valid and address is not changed,
 	   do not change entry state, if new one is STALE.
 	 */
@@ -1164,6 +1160,16 @@
 		}
 	}
 
+	/* Update timestamps only once we know we will make a change to the
+	 * neighbour entry. Otherwise we risk to move the locktime window with
+	 * noop updates and ignore relevant ARP updates.
+	 */
+	if (new != old || lladdr != neigh->ha) {
+		if (new & NUD_CONNECTED)
+			neigh->confirmed = jiffies;
+		neigh->updated = jiffies;
+	}
+
 	if (new != old) {
 		neigh_del_timer(neigh);
 		if (new & NUD_PROBE)
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index b7efe2f..04fd04c 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -312,6 +312,25 @@
 	goto out;
 }
 
+static int __net_init net_defaults_init_net(struct net *net)
+{
+	net->core.sysctl_somaxconn = SOMAXCONN;
+	return 0;
+}
+
+static struct pernet_operations net_defaults_ops = {
+	.init = net_defaults_init_net,
+};
+
+static __init int net_defaults_init(void)
+{
+	if (register_pernet_subsys(&net_defaults_ops))
+		panic("Cannot initialize net default settings");
+
+	return 0;
+}
+
+core_initcall(net_defaults_init);
 
 #ifdef CONFIG_NET_NS
 static struct ucounts *inc_net_namespaces(struct user_namespace *ns)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 2cc4a1b..e2136eb 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2621,7 +2621,8 @@
 {
 	int pos = skb_headlen(skb);
 
-	skb_shinfo(skb1)->tx_flags = skb_shinfo(skb)->tx_flags & SKBTX_SHARED_FRAG;
+	skb_shinfo(skb1)->tx_flags |= skb_shinfo(skb)->tx_flags &
+				      SKBTX_SHARED_FRAG;
 	if (len < pos)	/* Split line is inside header. */
 		skb_split_inside_header(skb, skb1, len, pos);
 	else		/* Second chunk has no header, nothing to copy. */
@@ -3234,8 +3235,8 @@
 		skb_copy_from_linear_data_offset(head_skb, offset,
 						 skb_put(nskb, hsize), hsize);
 
-		skb_shinfo(nskb)->tx_flags = skb_shinfo(head_skb)->tx_flags &
-			SKBTX_SHARED_FRAG;
+		skb_shinfo(nskb)->tx_flags |= skb_shinfo(head_skb)->tx_flags &
+					      SKBTX_SHARED_FRAG;
 
 		while (pos < offset + len) {
 			if (i >= nfrags) {
@@ -3481,24 +3482,18 @@
 						NULL);
 }
 
-/**
- *	skb_to_sgvec - Fill a scatter-gather list from a socket buffer
- *	@skb: Socket buffer containing the buffers to be mapped
- *	@sg: The scatter-gather list to map into
- *	@offset: The offset into the buffer's contents to start mapping
- *	@len: Length of buffer space to be mapped
- *
- *	Fill the specified scatter-gather list with mappings/pointers into a
- *	region of the buffer space attached to a socket buffer.
- */
 static int
-__skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
+__skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len,
+	       unsigned int recursion_level)
 {
 	int start = skb_headlen(skb);
 	int i, copy = start - offset;
 	struct sk_buff *frag_iter;
 	int elt = 0;
 
+	if (unlikely(recursion_level >= 24))
+		return -EMSGSIZE;
+
 	if (copy > 0) {
 		if (copy > len)
 			copy = len;
@@ -3517,6 +3512,8 @@
 		end = start + skb_frag_size(&skb_shinfo(skb)->frags[i]);
 		if ((copy = end - offset) > 0) {
 			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+			if (unlikely(elt && sg_is_last(&sg[elt - 1])))
+				return -EMSGSIZE;
 
 			if (copy > len)
 				copy = len;
@@ -3531,16 +3528,22 @@
 	}
 
 	skb_walk_frags(skb, frag_iter) {
-		int end;
+		int end, ret;
 
 		WARN_ON(start > offset + len);
 
 		end = start + frag_iter->len;
 		if ((copy = end - offset) > 0) {
+			if (unlikely(elt && sg_is_last(&sg[elt - 1])))
+				return -EMSGSIZE;
+
 			if (copy > len)
 				copy = len;
-			elt += __skb_to_sgvec(frag_iter, sg+elt, offset - start,
-					      copy);
+			ret = __skb_to_sgvec(frag_iter, sg+elt, offset - start,
+					      copy, recursion_level + 1);
+			if (unlikely(ret < 0))
+				return ret;
+			elt += ret;
 			if ((len -= copy) == 0)
 				return elt;
 			offset += copy;
@@ -3551,6 +3554,31 @@
 	return elt;
 }
 
+/**
+ *	skb_to_sgvec - Fill a scatter-gather list from a socket buffer
+ *	@skb: Socket buffer containing the buffers to be mapped
+ *	@sg: The scatter-gather list to map into
+ *	@offset: The offset into the buffer's contents to start mapping
+ *	@len: Length of buffer space to be mapped
+ *
+ *	Fill the specified scatter-gather list with mappings/pointers into a
+ *	region of the buffer space attached to a socket buffer. Returns either
+ *	the number of scatterlist items used, or -EMSGSIZE if the contents
+ *	could not fit.
+ */
+int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
+{
+	int nsg = __skb_to_sgvec(skb, sg, offset, len, 0);
+
+	if (nsg <= 0)
+		return nsg;
+
+	sg_mark_end(&sg[nsg - 1]);
+
+	return nsg;
+}
+EXPORT_SYMBOL_GPL(skb_to_sgvec);
+
 /* As compared with skb_to_sgvec, skb_to_sgvec_nomark only map skb to given
  * sglist without mark the sg which contain last skb data as the end.
  * So the caller can mannipulate sg list as will when padding new data after
@@ -3573,19 +3601,11 @@
 int skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg,
 			int offset, int len)
 {
-	return __skb_to_sgvec(skb, sg, offset, len);
+	return __skb_to_sgvec(skb, sg, offset, len, 0);
 }
 EXPORT_SYMBOL_GPL(skb_to_sgvec_nomark);
 
-int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
-{
-	int nsg = __skb_to_sgvec(skb, sg, offset, len);
 
-	sg_mark_end(&sg[nsg - 1]);
-
-	return nsg;
-}
-EXPORT_SYMBOL_GPL(skb_to_sgvec);
 
 /**
  *	skb_cow_data - Check that a socket buffer's data buffers are writable
@@ -3868,7 +3888,8 @@
 		return;
 
 	if (tsonly) {
-		skb_shinfo(skb)->tx_flags = skb_shinfo(orig_skb)->tx_flags;
+		skb_shinfo(skb)->tx_flags |= skb_shinfo(orig_skb)->tx_flags &
+					     SKBTX_ANY_TSTAMP;
 		skb_shinfo(skb)->tskey = skb_shinfo(orig_skb)->tskey;
 	}
 
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 1b46190..546ba76 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -438,8 +438,6 @@
 {
 	struct ctl_table *tbl;
 
-	net->core.sysctl_somaxconn = SOMAXCONN;
-
 	tbl = netns_core_table;
 	if (!net_eq(net, &init_net)) {
 		tbl = kmemdup(tbl, sizeof(netns_core_table), GFP_KERNEL);
diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c
index 4ebe2aa..04b5450 100644
--- a/net/hsr/hsr_forward.c
+++ b/net/hsr/hsr_forward.c
@@ -324,8 +324,7 @@
 	unsigned long irqflags;
 
 	frame->is_supervision = is_supervision_frame(port->hsr, skb);
-	frame->node_src = hsr_get_node(&port->hsr->node_db, skb,
-				       frame->is_supervision);
+	frame->node_src = hsr_get_node(port, skb, frame->is_supervision);
 	if (frame->node_src == NULL)
 		return -1; /* Unknown node and !is_supervision, or no mem */
 
diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c
index 7ea9258..284a9b8 100644
--- a/net/hsr/hsr_framereg.c
+++ b/net/hsr/hsr_framereg.c
@@ -158,9 +158,10 @@
 
 /* Get the hsr_node from which 'skb' was sent.
  */
-struct hsr_node *hsr_get_node(struct list_head *node_db, struct sk_buff *skb,
+struct hsr_node *hsr_get_node(struct hsr_port *port, struct sk_buff *skb,
 			      bool is_sup)
 {
+	struct list_head *node_db = &port->hsr->node_db;
 	struct hsr_node *node;
 	struct ethhdr *ethhdr;
 	u16 seq_out;
@@ -186,7 +187,11 @@
 		 */
 		seq_out = hsr_get_skb_sequence_nr(skb) - 1;
 	} else {
-		WARN_ONCE(1, "%s: Non-HSR frame\n", __func__);
+		/* this is called also for frames from master port and
+		 * so warn only for non master ports
+		 */
+		if (port->type != HSR_PT_MASTER)
+			WARN_ONCE(1, "%s: Non-HSR frame\n", __func__);
 		seq_out = HSR_SEQNR_START;
 	}
 
diff --git a/net/hsr/hsr_framereg.h b/net/hsr/hsr_framereg.h
index 438b40f..4e04f0e 100644
--- a/net/hsr/hsr_framereg.h
+++ b/net/hsr/hsr_framereg.h
@@ -18,7 +18,7 @@
 
 struct hsr_node *hsr_add_node(struct list_head *node_db, unsigned char addr[],
 			      u16 seq_out);
-struct hsr_node *hsr_get_node(struct list_head *node_db, struct sk_buff *skb,
+struct hsr_node *hsr_get_node(struct hsr_port *port, struct sk_buff *skb,
 			      bool is_sup);
 void hsr_handle_sup_frame(struct sk_buff *skb, struct hsr_node *node_curr,
 			  struct hsr_port *port);
diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c
index e0bd013..bf5d26d 100644
--- a/net/ieee802154/socket.c
+++ b/net/ieee802154/socket.c
@@ -304,12 +304,12 @@
 	skb->sk  = sk;
 	skb->protocol = htons(ETH_P_IEEE802154);
 
-	dev_put(dev);
-
 	err = dev_queue_xmit(skb);
 	if (err > 0)
 		err = net_xmit_errno(err);
 
+	dev_put(dev);
+
 	return err ?: size;
 
 out_skb:
@@ -693,12 +693,12 @@
 	skb->sk  = sk;
 	skb->protocol = htons(ETH_P_IEEE802154);
 
-	dev_put(dev);
-
 	err = dev_queue_xmit(skb);
 	if (err > 0)
 		err = net_xmit_errno(err);
 
+	dev_put(dev);
+
 	return err ?: size;
 
 out_skb:
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index 22377c8..e8f8623 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -220,7 +220,9 @@
 	ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
 
 	sg_init_table(sg, nfrags + sglists);
-	skb_to_sgvec_nomark(skb, sg, 0, skb->len);
+	err = skb_to_sgvec_nomark(skb, sg, 0, skb->len);
+	if (unlikely(err < 0))
+		goto out_free;
 
 	if (x->props.flags & XFRM_STATE_ESN) {
 		/* Attach seqhi sg right after packet payload */
@@ -393,7 +395,9 @@
 	skb_push(skb, ihl);
 
 	sg_init_table(sg, nfrags + sglists);
-	skb_to_sgvec_nomark(skb, sg, 0, skb->len);
+	err = skb_to_sgvec_nomark(skb, sg, 0, skb->len);
+	if (unlikely(err < 0))
+		goto out_free;
 
 	if (x->props.flags & XFRM_STATE_ESN) {
 		/* Attach seqhi sg right after packet payload */
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index e60517e..8cae791 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -437,7 +437,7 @@
 	/*unsigned long now; */
 	struct net *net = dev_net(dev);
 
-	rt = ip_route_output(net, sip, tip, 0, 0);
+	rt = ip_route_output(net, sip, tip, 0, l3mdev_master_ifindex_rcu(dev));
 	if (IS_ERR(rt))
 		return 1;
 	if (rt->dst.dev != dev) {
@@ -658,6 +658,7 @@
 	unsigned char *arp_ptr;
 	struct rtable *rt;
 	unsigned char *sha;
+	unsigned char *tha = NULL;
 	__be32 sip, tip;
 	u16 dev_type = dev->type;
 	int addr_type;
@@ -729,6 +730,7 @@
 		break;
 #endif
 	default:
+		tha = arp_ptr;
 		arp_ptr += dev->addr_len;
 	}
 	memcpy(&tip, arp_ptr, 4);
@@ -847,8 +849,18 @@
 		   It is possible, that this option should be enabled for some
 		   devices (strip is candidate)
 		 */
-		is_garp = arp->ar_op == htons(ARPOP_REQUEST) && tip == sip &&
-			  addr_type == RTN_UNICAST;
+		is_garp = tip == sip && addr_type == RTN_UNICAST;
+
+		/* Unsolicited ARP _replies_ also require target hwaddr to be
+		 * the same as source.
+		 */
+		if (is_garp && arp->ar_op == htons(ARPOP_REPLY))
+			is_garp =
+				/* IPv4 over IEEE 1394 doesn't provide target
+				 * hardware address field in its ARP payload.
+				 */
+				tha &&
+				!memcmp(tha, sha, dev->addr_len);
 
 		if (!n &&
 		    ((arp->ar_op == htons(ARPOP_REPLY)  &&
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 20fb25e..3d8021d 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -268,10 +268,11 @@
 	esph->spi = x->id.spi;
 
 	sg_init_table(sg, nfrags);
-	skb_to_sgvec(skb, sg,
-		     (unsigned char *)esph - skb->data,
-		     assoclen + ivlen + clen + alen);
-
+	err = skb_to_sgvec(skb, sg,
+		           (unsigned char *)esph - skb->data,
+		           assoclen + ivlen + clen + alen);
+	if (unlikely(err < 0))
+		goto error;
 	aead_request_set_crypt(req, sg, sg, ivlen + clen, iv);
 	aead_request_set_ad(req, assoclen);
 
@@ -481,7 +482,9 @@
 	}
 
 	sg_init_table(sg, nfrags);
-	skb_to_sgvec(skb, sg, 0, skb->len);
+	err = skb_to_sgvec(skb, sg, 0, skb->len);
+	if (unlikely(err < 0))
+		goto out;
 
 	aead_request_set_crypt(req, sg, sg, elen + ivlen, iv);
 	aead_request_set_ad(req, assoclen);
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 7e7b7a3..e1be244 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -1611,18 +1611,20 @@
 	bool first = false;
 
 	for_nexthops(fi) {
+		if (net->ipv4.sysctl_fib_multipath_use_neigh) {
+			if (!fib_good_nh(nh))
+				continue;
+			if (!first) {
+				res->nh_sel = nhsel;
+				first = true;
+			}
+		}
+
 		if (hash > atomic_read(&nh->nh_upper_bound))
 			continue;
 
-		if (!net->ipv4.sysctl_fib_multipath_use_neigh ||
-		    fib_good_nh(nh)) {
-			res->nh_sel = nhsel;
-			return;
-		}
-		if (!first) {
-			res->nh_sel = nhsel;
-			first = true;
-		}
+		res->nh_sel = nhsel;
+		return;
 	} endfor_nexthops(fi);
 }
 #endif
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index 96536a0..e1271e75 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -253,13 +253,14 @@
 	struct net_device *dev;
 	char name[IFNAMSIZ];
 
-	if (parms->name[0])
-		strlcpy(name, parms->name, IFNAMSIZ);
-	else {
-		if (strlen(ops->kind) > (IFNAMSIZ - 3)) {
-			err = -E2BIG;
+	err = -E2BIG;
+	if (parms->name[0]) {
+		if (!dev_valid_name(parms->name))
 			goto failed;
-		}
+		strlcpy(name, parms->name, IFNAMSIZ);
+	} else {
+		if (strlen(ops->kind) > (IFNAMSIZ - 3))
+			goto failed;
 		strlcpy(name, ops->kind, IFNAMSIZ);
 		strncat(name, "%d", 2);
 	}
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 27089f5..742a343 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1929,6 +1929,20 @@
 	struct net *net = dev_net(skb->dev);
 	int local = skb_rtable(skb)->rt_flags & RTCF_LOCAL;
 	struct mr_table *mrt;
+	struct net_device *dev;
+
+	/* skb->dev passed in is the loX master dev for vrfs.
+	 * As there are no vifs associated with loopback devices,
+	 * get the proper interface that does have a vif associated with it.
+	 */
+	dev = skb->dev;
+	if (netif_is_l3_master(skb->dev)) {
+		dev = dev_get_by_index_rcu(net, IPCB(skb)->iif);
+		if (!dev) {
+			kfree_skb(skb);
+			return -ENODEV;
+		}
+	}
 
 	/* Packet is looped back after forward, it should not be
 	 * forwarded second time, but still can be delivered locally.
@@ -1966,7 +1980,7 @@
 	/* already under rcu_read_lock() */
 	cache = ipmr_cache_find(mrt, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
 	if (!cache) {
-		int vif = ipmr_find_vif(mrt, skb->dev);
+		int vif = ipmr_find_vif(mrt, dev);
 
 		if (vif >= 0)
 			cache = ipmr_cache_find_any(mrt, ip_hdr(skb)->daddr,
@@ -1986,7 +2000,7 @@
 		}
 
 		read_lock(&mrt_lock);
-		vif = ipmr_find_vif(mrt, skb->dev);
+		vif = ipmr_find_vif(mrt, dev);
 		if (vif >= 0) {
 			int err2 = ipmr_cache_unresolved(mrt, vif, skb);
 			read_unlock(&mrt_lock);
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c
index 574f7eb..ac8342d 100644
--- a/net/ipv4/netfilter/nf_nat_h323.c
+++ b/net/ipv4/netfilter/nf_nat_h323.c
@@ -252,16 +252,16 @@
 	if (set_h245_addr(skb, protoff, data, dataoff, taddr,
 			  &ct->tuplehash[!dir].tuple.dst.u3,
 			  htons((port & htons(1)) ? nated_port + 1 :
-						    nated_port)) == 0) {
-		/* Save ports */
-		info->rtp_port[i][dir] = rtp_port;
-		info->rtp_port[i][!dir] = htons(nated_port);
-	} else {
+						    nated_port))) {
 		nf_ct_unexpect_related(rtp_exp);
 		nf_ct_unexpect_related(rtcp_exp);
 		return -1;
 	}
 
+	/* Save ports */
+	info->rtp_port[i][dir] = rtp_port;
+	info->rtp_port[i][!dir] = htons(nated_port);
+
 	/* Success */
 	pr_debug("nf_nat_h323: expect RTP %pI4:%hu->%pI4:%hu\n",
 		 &rtp_exp->tuple.src.u3.ip,
@@ -370,15 +370,15 @@
 	/* Modify signal */
 	if (set_h225_addr(skb, protoff, data, dataoff, taddr,
 			  &ct->tuplehash[!dir].tuple.dst.u3,
-			  htons(nated_port)) == 0) {
-		/* Save ports */
-		info->sig_port[dir] = port;
-		info->sig_port[!dir] = htons(nated_port);
-	} else {
+			  htons(nated_port))) {
 		nf_ct_unexpect_related(exp);
 		return -1;
 	}
 
+	/* Save ports */
+	info->sig_port[dir] = port;
+	info->sig_port[!dir] = htons(nated_port);
+
 	pr_debug("nf_nat_q931: expect H.245 %pI4:%hu->%pI4:%hu\n",
 		 &exp->tuple.src.u3.ip,
 		 ntohs(exp->tuple.src.u.tcp.port),
@@ -462,24 +462,27 @@
 	/* Modify signal */
 	if (set_h225_addr(skb, protoff, data, 0, &taddr[idx],
 			  &ct->tuplehash[!dir].tuple.dst.u3,
-			  htons(nated_port)) == 0) {
-		/* Save ports */
-		info->sig_port[dir] = port;
-		info->sig_port[!dir] = htons(nated_port);
-
-		/* Fix for Gnomemeeting */
-		if (idx > 0 &&
-		    get_h225_addr(ct, *data, &taddr[0], &addr, &port) &&
-		    (ntohl(addr.ip) & 0xff000000) == 0x7f000000) {
-			set_h225_addr(skb, protoff, data, 0, &taddr[0],
-				      &ct->tuplehash[!dir].tuple.dst.u3,
-				      info->sig_port[!dir]);
-		}
-	} else {
+			  htons(nated_port))) {
 		nf_ct_unexpect_related(exp);
 		return -1;
 	}
 
+	/* Save ports */
+	info->sig_port[dir] = port;
+	info->sig_port[!dir] = htons(nated_port);
+
+	/* Fix for Gnomemeeting */
+	if (idx > 0 &&
+	    get_h225_addr(ct, *data, &taddr[0], &addr, &port) &&
+	    (ntohl(addr.ip) & 0xff000000) == 0x7f000000) {
+		if (set_h225_addr(skb, protoff, data, 0, &taddr[0],
+				  &ct->tuplehash[!dir].tuple.dst.u3,
+				  info->sig_port[!dir])) {
+			nf_ct_unexpect_related(exp);
+			return -1;
+		}
+	}
+
 	/* Success */
 	pr_debug("nf_nat_ras: expect Q.931 %pI4:%hu->%pI4:%hu\n",
 		 &exp->tuple.src.u3.ip,
@@ -550,9 +553,9 @@
 	}
 
 	/* Modify signal */
-	if (!set_h225_addr(skb, protoff, data, dataoff, taddr,
-			   &ct->tuplehash[!dir].tuple.dst.u3,
-			   htons(nated_port)) == 0) {
+	if (set_h225_addr(skb, protoff, data, dataoff, taddr,
+			  &ct->tuplehash[!dir].tuple.dst.u3,
+			  htons(nated_port))) {
 		nf_ct_unexpect_related(exp);
 		return -1;
 	}
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index c14c213..16d3619 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -116,6 +116,7 @@
 #define FLAG_DSACKING_ACK	0x800 /* SACK blocks contained D-SACK info */
 #define FLAG_SACK_RENEGING	0x2000 /* snd_una advanced to a sacked seq */
 #define FLAG_UPDATE_TS_RECENT	0x4000 /* tcp_replace_ts_recent() */
+#define FLAG_NO_CHALLENGE_ACK	0x8000 /* do not call tcp_send_challenge_ack()	*/
 
 #define FLAG_ACKED		(FLAG_DATA_ACKED|FLAG_SYN_ACKED)
 #define FLAG_NOT_DUP		(FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED)
@@ -3619,7 +3620,8 @@
 	if (before(ack, prior_snd_una)) {
 		/* RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation] */
 		if (before(ack, prior_snd_una - tp->max_window)) {
-			tcp_send_challenge_ack(sk, skb);
+			if (!(flag & FLAG_NO_CHALLENGE_ACK))
+				tcp_send_challenge_ack(sk, skb);
 			return -1;
 		}
 		goto old_ack;
@@ -5971,13 +5973,17 @@
 
 	/* step 5: check the ACK field */
 	acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH |
-				      FLAG_UPDATE_TS_RECENT) > 0;
+				      FLAG_UPDATE_TS_RECENT |
+				      FLAG_NO_CHALLENGE_ACK) > 0;
 
+	if (!acceptable) {
+		if (sk->sk_state == TCP_SYN_RECV)
+			return 1;	/* send one RST */
+		tcp_send_challenge_ack(sk, skb);
+		goto discard;
+	}
 	switch (sk->sk_state) {
 	case TCP_SYN_RECV:
-		if (!acceptable)
-			return 1;
-
 		if (!tp->srtt_us)
 			tcp_synack_rtt_meas(sk, req);
 
@@ -6047,14 +6053,6 @@
 		 * our SYNACK so stop the SYNACK timer.
 		 */
 		if (req) {
-			/* Return RST if ack_seq is invalid.
-			 * Note that RFC793 only says to generate a
-			 * DUPACK for it but for TCP Fast Open it seems
-			 * better to treat this case like TCP_SYN_RECV
-			 * above.
-			 */
-			if (!acceptable)
-				return 1;
 			/* We no longer need the request sock. */
 			reqsk_fastopen_remove(sk, req, false);
 			tcp_rearm_rto(sk);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index a5c1ff3..9077060 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -994,7 +994,10 @@
 	INIT_HLIST_NODE(&ifa->addr_lst);
 	ifa->scope = scope;
 	ifa->prefix_len = pfxlen;
-	ifa->flags = flags | IFA_F_TENTATIVE;
+	ifa->flags = flags;
+	/* No need to add the TENTATIVE flag for addresses with NODAD */
+	if (!(flags & IFA_F_NODAD))
+		ifa->flags |= IFA_F_TENTATIVE;
 	ifa->valid_lft = valid_lft;
 	ifa->prefered_lft = prefered_lft;
 	ifa->cstamp = ifa->tstamp = jiffies;
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 189eb10..e742c4d 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -423,7 +423,9 @@
 	ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
 
 	sg_init_table(sg, nfrags + sglists);
-	skb_to_sgvec_nomark(skb, sg, 0, skb->len);
+	err = skb_to_sgvec_nomark(skb, sg, 0, skb->len);
+	if (unlikely(err < 0))
+		goto out_free;
 
 	if (x->props.flags & XFRM_STATE_ESN) {
 		/* Attach seqhi sg right after packet payload */
@@ -603,7 +605,9 @@
 	ip6h->hop_limit   = 0;
 
 	sg_init_table(sg, nfrags + sglists);
-	skb_to_sgvec_nomark(skb, sg, 0, skb->len);
+	err = skb_to_sgvec_nomark(skb, sg, 0, skb->len);
+	if (unlikely(err < 0))
+		goto out_free;
 
 	if (x->props.flags & XFRM_STATE_ESN) {
 		/* Attach seqhi sg right after packet payload */
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index cbcdd5d..44a2010 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -248,9 +248,11 @@
 	esph->spi = x->id.spi;
 
 	sg_init_table(sg, nfrags);
-	skb_to_sgvec(skb, sg,
-		     (unsigned char *)esph - skb->data,
-		     assoclen + ivlen + clen + alen);
+	err = skb_to_sgvec(skb, sg,
+		           (unsigned char *)esph - skb->data,
+		           assoclen + ivlen + clen + alen);
+	if (unlikely(err < 0))
+		goto error;
 
 	aead_request_set_crypt(req, sg, sg, ivlen + clen, iv);
 	aead_request_set_ad(req, assoclen);
@@ -423,7 +425,9 @@
 	}
 
 	sg_init_table(sg, nfrags);
-	skb_to_sgvec(skb, sg, 0, skb->len);
+	ret = skb_to_sgvec(skb, sg, 0, skb->len);
+	if (unlikely(ret < 0))
+		goto out;
 
 	aead_request_set_crypt(req, sg, sg, elen + ivlen, iv);
 	aead_request_set_ad(req, assoclen);
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 21bd54f..a88aff0 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -319,11 +319,13 @@
 	if (t || !create)
 		return t;
 
-	if (parms->name[0])
+	if (parms->name[0]) {
+		if (!dev_valid_name(parms->name))
+			return NULL;
 		strlcpy(name, parms->name, IFNAMSIZ);
-	else
+	} else {
 		strcpy(name, "ip6gre%d");
-
+	}
 	dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN,
 			   ip6gre_tunnel_setup);
 	if (!dev)
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 55ca65c..de0188e 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -365,6 +365,11 @@
 static inline int ip6_forward_finish(struct net *net, struct sock *sk,
 				     struct sk_buff *skb)
 {
+	struct dst_entry *dst = skb_dst(skb);
+
+	__IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
+	__IP6_ADD_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len);
+
 	return dst_output(net, sk, skb);
 }
 
@@ -558,8 +563,6 @@
 
 	hdr->hop_limit--;
 
-	__IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
-	__IP6_ADD_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len);
 	return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD,
 		       net, NULL, skb, skb->dev, dst->dev,
 		       ip6_forward_finish);
@@ -1276,7 +1279,7 @@
 		if (np->frag_size)
 			mtu = np->frag_size;
 	}
-	if (mtu < IPV6_MIN_MTU)
+	if (!(rt->dst.flags & DST_XFRM_TUNNEL) && mtu < IPV6_MIN_MTU)
 		return -EINVAL;
 	cork->base.fragsize = mtu;
 	if (dst_allfrag(rt->dst.path))
@@ -1299,7 +1302,7 @@
 			     const struct sockcm_cookie *sockc)
 {
 	struct sk_buff *skb, *skb_prev = NULL;
-	unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu;
+	unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu, pmtu;
 	int exthdrlen = 0;
 	int dst_exthdrlen = 0;
 	int hh_len;
@@ -1335,6 +1338,12 @@
 		      sizeof(struct frag_hdr) : 0) +
 		     rt->rt6i_nfheader_len;
 
+	/* as per RFC 7112 section 5, the entire IPv6 Header Chain must fit
+	 * the first fragment
+	 */
+	if (headersize + transhdrlen > mtu)
+		goto emsgsize;
+
 	if (cork->length + length > mtu - headersize && ipc6->dontfrag &&
 	    (sk->sk_protocol == IPPROTO_UDP ||
 	     sk->sk_protocol == IPPROTO_RAW)) {
@@ -1350,9 +1359,8 @@
 
 	if (cork->length + length > maxnonfragsize - headersize) {
 emsgsize:
-		ipv6_local_error(sk, EMSGSIZE, fl6,
-				 mtu - headersize +
-				 sizeof(struct ipv6hdr));
+		pmtu = max_t(int, mtu - headersize + sizeof(struct ipv6hdr), 0);
+		ipv6_local_error(sk, EMSGSIZE, fl6, pmtu);
 		return -EMSGSIZE;
 	}
 
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 8ff62e4..f338848 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -298,13 +298,16 @@
 	struct net_device *dev;
 	struct ip6_tnl *t;
 	char name[IFNAMSIZ];
-	int err = -ENOMEM;
+	int err = -E2BIG;
 
-	if (p->name[0])
+	if (p->name[0]) {
+		if (!dev_valid_name(p->name))
+			goto failed;
 		strlcpy(name, p->name, IFNAMSIZ);
-	else
+	} else {
 		sprintf(name, "ip6tnl%%d");
-
+	}
+	err = -ENOMEM;
 	dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN,
 			   ip6_tnl_dev_setup);
 	if (!dev)
@@ -1097,6 +1100,9 @@
 
 	if (!dst) {
 route_lookup:
+		/* add dsfield to flowlabel for route lookup */
+		fl6->flowlabel = ip6_make_flowinfo(dsfield, fl6->flowlabel);
+
 		dst = ip6_route_output(net, NULL, fl6);
 
 		if (dst->error)
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c
index 2e3f4f1..5ae1681 100644
--- a/net/ipv6/ip6_vti.c
+++ b/net/ipv6/ip6_vti.c
@@ -212,10 +212,13 @@
 	char name[IFNAMSIZ];
 	int err;
 
-	if (p->name[0])
+	if (p->name[0]) {
+		if (!dev_valid_name(p->name))
+			goto failed;
 		strlcpy(name, p->name, IFNAMSIZ);
-	else
+	} else {
 		sprintf(name, "ip6_vti%%d");
+	}
 
 	dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, vti6_dev_setup);
 	if (!dev)
@@ -626,7 +629,6 @@
 {
 	struct net_device *dev = t->dev;
 	struct __ip6_tnl_parm *p = &t->parms;
-	struct net_device *tdev = NULL;
 
 	memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
 	memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr));
@@ -639,25 +641,6 @@
 		dev->flags |= IFF_POINTOPOINT;
 	else
 		dev->flags &= ~IFF_POINTOPOINT;
-
-	if (p->flags & IP6_TNL_F_CAP_XMIT) {
-		int strict = (ipv6_addr_type(&p->raddr) &
-			      (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL));
-		struct rt6_info *rt = rt6_lookup(t->net,
-						 &p->raddr, &p->laddr,
-						 p->link, strict);
-
-		if (rt)
-			tdev = rt->dst.dev;
-		ip6_rt_put(rt);
-	}
-
-	if (!tdev && p->link)
-		tdev = __dev_get_by_index(t->net, p->link);
-
-	if (tdev)
-		dev->mtu = max_t(int, tdev->mtu - dev->hard_header_len,
-				 IPV6_MIN_MTU);
 }
 
 /**
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 0d54cc5..96be019 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -847,6 +847,9 @@
 	struct fib6_node *fn;
 	struct rt6_info *rt;
 
+	if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
+		flags &= ~RT6_LOOKUP_F_IFACE;
+
 	read_lock_bh(&table->tb6_lock);
 	fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
 restart:
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index d4d84da..dcb2921 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -244,11 +244,13 @@
 	if (!create)
 		goto failed;
 
-	if (parms->name[0])
+	if (parms->name[0]) {
+		if (!dev_valid_name(parms->name))
+			goto failed;
 		strlcpy(name, parms->name, IFNAMSIZ);
-	else
+	} else {
 		strcpy(name, "sit%d");
-
+	}
 	dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN,
 			   ipip6_tunnel_setup);
 	if (!dev)
@@ -657,6 +659,7 @@
 		if (iptunnel_pull_header(skb, 0, htons(ETH_P_IPV6),
 		    !net_eq(tunnel->net, dev_net(tunnel->dev))))
 			goto out;
+		iph = ip_hdr(skb);
 
 		err = IP_ECN_decapsulate(iph, skb);
 		if (unlikely(err)) {
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 6482b00..15150b4 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -3305,7 +3305,7 @@
 		p += pol->sadb_x_policy_len*8;
 		sec_ctx = (struct sadb_x_sec_ctx *)p;
 		if (len < pol->sadb_x_policy_len*8 +
-		    sec_ctx->sadb_x_sec_len) {
+		    sec_ctx->sadb_x_sec_len*8) {
 			*dir = -EINVAL;
 			goto out;
 		}
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
index ee03bc8..ce12384 100644
--- a/net/l2tp/l2tp_netlink.c
+++ b/net/l2tp/l2tp_netlink.c
@@ -750,6 +750,8 @@
 
 	if ((session->ifname[0] &&
 	     nla_put_string(skb, L2TP_ATTR_IFNAME, session->ifname)) ||
+	    (session->offset &&
+	     nla_put_u16(skb, L2TP_ATTR_OFFSET, session->offset)) ||
 	    (session->cookie_len &&
 	     nla_put(skb, L2TP_ATTR_COOKIE, session->cookie_len,
 		     &session->cookie[0])) ||
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index db916cf..f7caf0f 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -309,6 +309,8 @@
 	int rc = -EINVAL;
 
 	dprintk("%s: binding %02X\n", __func__, addr->sllc_sap);
+
+	lock_sock(sk);
 	if (unlikely(!sock_flag(sk, SOCK_ZAPPED) || addrlen != sizeof(*addr)))
 		goto out;
 	rc = -EAFNOSUPPORT;
@@ -380,6 +382,7 @@
 out_put:
 	llc_sap_put(sap);
 out:
+	release_sock(sk);
 	return rc;
 }
 
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index efa2a2f..d7801f6 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2341,10 +2341,17 @@
 	struct ieee80211_sub_if_data *sdata;
 	enum nl80211_tx_power_setting txp_type = type;
 	bool update_txp_type = false;
+	bool has_monitor = false;
 
 	if (wdev) {
 		sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
 
+		if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
+			sdata = rtnl_dereference(local->monitor_sdata);
+			if (!sdata)
+				return -EOPNOTSUPP;
+		}
+
 		switch (type) {
 		case NL80211_TX_POWER_AUTOMATIC:
 			sdata->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
@@ -2383,15 +2390,34 @@
 
 	mutex_lock(&local->iflist_mtx);
 	list_for_each_entry(sdata, &local->interfaces, list) {
+		if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
+			has_monitor = true;
+			continue;
+		}
 		sdata->user_power_level = local->user_power_level;
 		if (txp_type != sdata->vif.bss_conf.txpower_type)
 			update_txp_type = true;
 		sdata->vif.bss_conf.txpower_type = txp_type;
 	}
-	list_for_each_entry(sdata, &local->interfaces, list)
+	list_for_each_entry(sdata, &local->interfaces, list) {
+		if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
+			continue;
 		ieee80211_recalc_txpower(sdata, update_txp_type);
+	}
 	mutex_unlock(&local->iflist_mtx);
 
+	if (has_monitor) {
+		sdata = rtnl_dereference(local->monitor_sdata);
+		if (sdata) {
+			sdata->user_power_level = local->user_power_level;
+			if (txp_type != sdata->vif.bss_conf.txpower_type)
+				update_txp_type = true;
+			sdata->vif.bss_conf.txpower_type = txp_type;
+
+			ieee80211_recalc_txpower(sdata, update_txp_type);
+		}
+	}
+
 	return 0;
 }
 
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 09f77e4..49c8a9c 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -164,7 +164,8 @@
 	if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
 			 sdata->vif.type == NL80211_IFTYPE_NAN ||
 			 (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
-			  !sdata->vif.mu_mimo_owner)))
+			  !sdata->vif.mu_mimo_owner &&
+			  !(changed & BSS_CHANGED_TXPOWER))))
 		return;
 
 	if (!check_sdata_in_driver(sdata))
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index d31818e..a5acaf1 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -427,7 +427,7 @@
 	case NL80211_CHAN_WIDTH_5:
 	case NL80211_CHAN_WIDTH_10:
 		cfg80211_chandef_create(&chandef, cbss->channel,
-					NL80211_CHAN_WIDTH_20_NOHT);
+					NL80211_CHAN_NO_HT);
 		chandef.width = sdata->u.ibss.chandef.width;
 		break;
 	case NL80211_CHAN_WIDTH_80:
@@ -439,7 +439,7 @@
 	default:
 		/* fall back to 20 MHz for unsupported modes */
 		cfg80211_chandef_create(&chandef, cbss->channel,
-					NL80211_CHAN_WIDTH_20_NOHT);
+					NL80211_CHAN_NO_HT);
 		break;
 	}
 
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 0519edb..973adf3 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -4332,6 +4332,10 @@
 	if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data))
 		return -EINVAL;
 
+	/* If a reconfig is happening, bail out */
+	if (local->in_reconfig)
+		return -EBUSY;
+
 	if (assoc) {
 		rcu_read_lock();
 		have_sta = sta_info_get(sdata, cbss->bssid);
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index dbceb42..e6096df 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -173,9 +173,11 @@
 		/* try default if specific alg requested but not found */
 		ops = ieee80211_try_rate_control_ops_get(ieee80211_default_rc_algo);
 
-	/* try built-in one if specific alg requested but not found */
-	if (!ops && strlen(CONFIG_MAC80211_RC_DEFAULT))
+	/* Note: check for > 0 is intentional to avoid clang warning */
+	if (!ops && (strlen(CONFIG_MAC80211_RC_DEFAULT) > 0))
+		/* try built-in one if specific alg requested but not found */
 		ops = ieee80211_try_rate_control_ops_get(CONFIG_MAC80211_RC_DEFAULT);
+
 	kernel_param_unlock(THIS_MODULE);
 
 	return ops;
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index f66c08f..18e96a2 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1621,7 +1621,6 @@
 	struct nf_conntrack_tuple_hash *h;
 	struct nf_conn *ct;
 	struct hlist_nulls_node *n;
-	int cpu;
 	spinlock_t *lockp;
 
 	for (; *bucket < nf_conntrack_htable_size; (*bucket)++) {
@@ -1643,18 +1642,6 @@
 		cond_resched();
 	}
 
-	for_each_possible_cpu(cpu) {
-		struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
-
-		spin_lock_bh(&pcpu->lock);
-		hlist_nulls_for_each_entry(h, n, &pcpu->unconfirmed, hnnode) {
-			ct = nf_ct_tuplehash_to_ctrack(h);
-			if (iter(ct, data))
-				set_bit(IPS_DYING_BIT, &ct->status);
-		}
-		spin_unlock_bh(&pcpu->lock);
-		cond_resched();
-	}
 	return NULL;
 found:
 	atomic_inc(&ct->ct_general.use);
@@ -1663,6 +1650,34 @@
 	return ct;
 }
 
+static void
+__nf_ct_unconfirmed_destroy(struct net *net)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu) {
+		struct nf_conntrack_tuple_hash *h;
+		struct hlist_nulls_node *n;
+		struct ct_pcpu *pcpu;
+
+		pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
+
+		spin_lock_bh(&pcpu->lock);
+		hlist_nulls_for_each_entry(h, n, &pcpu->unconfirmed, hnnode) {
+			struct nf_conn *ct;
+
+			ct = nf_ct_tuplehash_to_ctrack(h);
+
+			/* we cannot call iter() on unconfirmed list, the
+			 * owning cpu can reallocate ct->ext at any time.
+			 */
+			set_bit(IPS_DYING_BIT, &ct->status);
+		}
+		spin_unlock_bh(&pcpu->lock);
+		cond_resched();
+	}
+}
+
 void nf_ct_iterate_cleanup(struct net *net,
 			   int (*iter)(struct nf_conn *i, void *data),
 			   void *data, u32 portid, int report)
@@ -1675,6 +1690,10 @@
 	if (atomic_read(&net->ct.count) == 0)
 		return;
 
+	__nf_ct_unconfirmed_destroy(net);
+
+	synchronize_net();
+
 	while ((ct = get_next_corpse(net, iter, data, &bucket)) != NULL) {
 		/* Time to push up daises... */
 
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 3c37253..c9ca529 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -894,8 +894,13 @@
 	}
 out:
 	local_bh_enable();
-	if (last)
+	if (last) {
+		/* nf ct hash resize happened, now clear the leftover. */
+		if ((struct nf_conn *)cb->args[1] == last)
+			cb->args[1] = 0;
+
 		nf_ct_put(last);
+	}
 
 	while (i) {
 		i--;
@@ -1012,9 +1017,8 @@
 
 static int
 ctnetlink_parse_tuple(const struct nlattr * const cda[],
-		      struct nf_conntrack_tuple *tuple,
-		      enum ctattr_type type, u_int8_t l3num,
-		      struct nf_conntrack_zone *zone)
+		      struct nf_conntrack_tuple *tuple, u32 type,
+		      u_int8_t l3num, struct nf_conntrack_zone *zone)
 {
 	struct nlattr *tb[CTA_TUPLE_MAX+1];
 	int err;
@@ -2424,7 +2428,7 @@
 
 static int ctnetlink_exp_dump_tuple(struct sk_buff *skb,
 				    const struct nf_conntrack_tuple *tuple,
-				    enum ctattr_expect type)
+				    u32 type)
 {
 	struct nlattr *nest_parms;
 
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 7ad1a86..59be898 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -367,6 +367,36 @@
 	return buf;
 }
 
+/**
+ * xt_check_proc_name - check that name is suitable for /proc file creation
+ *
+ * @name: file name candidate
+ * @size: length of buffer
+ *
+ * some x_tables modules wish to create a file in /proc.
+ * This function makes sure that the name is suitable for this
+ * purpose, it checks that name is NUL terminated and isn't a 'special'
+ * name, like "..".
+ *
+ * returns negative number on error or 0 if name is useable.
+ */
+int xt_check_proc_name(const char *name, unsigned int size)
+{
+	if (name[0] == '\0')
+		return -EINVAL;
+
+	if (strnlen(name, size) == size)
+		return -ENAMETOOLONG;
+
+	if (strcmp(name, ".") == 0 ||
+	    strcmp(name, "..") == 0 ||
+	    strchr(name, '/'))
+		return -EINVAL;
+
+	return 0;
+}
+EXPORT_SYMBOL(xt_check_proc_name);
+
 int xt_check_match(struct xt_mtchk_param *par,
 		   unsigned int size, u_int8_t proto, bool inv_proto)
 {
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index b89b688..a1a29cd 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -794,8 +794,9 @@
 	struct hashlimit_cfg2 cfg = {};
 	int ret;
 
-	if (info->name[sizeof(info->name) - 1] != '\0')
-		return -EINVAL;
+	ret = xt_check_proc_name(info->name, sizeof(info->name));
+	if (ret)
+		return ret;
 
 	ret = cfg_copy(&cfg, (void *)&info->cfg, 1);
 
@@ -809,9 +810,11 @@
 static int hashlimit_mt_check(const struct xt_mtchk_param *par)
 {
 	struct xt_hashlimit_mtinfo2 *info = par->matchinfo;
+	int ret;
 
-	if (info->name[sizeof(info->name) - 1] != '\0')
-		return -EINVAL;
+	ret = xt_check_proc_name(info->name, sizeof(info->name));
+	if (ret)
+		return ret;
 
 	return hashlimit_mt_check_common(par, &info->hinfo, &info->cfg,
 					 info->name, 2);
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c
index e3b7a09..79d7ad6 100644
--- a/net/netfilter/xt_recent.c
+++ b/net/netfilter/xt_recent.c
@@ -361,9 +361,9 @@
 			info->hit_count, XT_RECENT_MAX_NSTAMPS - 1);
 		return -EINVAL;
 	}
-	if (info->name[0] == '\0' ||
-	    strnlen(info->name, XT_RECENT_NAME_LEN) == XT_RECENT_NAME_LEN)
-		return -EINVAL;
+	ret = xt_check_proc_name(info->name, sizeof(info->name));
+	if (ret)
+		return ret;
 
 	if (ip_pkt_list_tot && info->hit_count < ip_pkt_list_tot)
 		nstamp_mask = roundup_pow_of_two(ip_pkt_list_tot) - 1;
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index c1f59a0..1e97b8d 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1054,6 +1054,9 @@
 	if (addr->sa_family != AF_NETLINK)
 		return -EINVAL;
 
+	if (alen < sizeof(struct sockaddr_nl))
+		return -EINVAL;
+
 	if ((nladdr->nl_groups || nladdr->nl_pid) &&
 	    !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))
 		return -EPERM;
diff --git a/net/rds/bind.c b/net/rds/bind.c
index 095f6ce..adb53ae 100644
--- a/net/rds/bind.c
+++ b/net/rds/bind.c
@@ -114,6 +114,7 @@
 			  rs, &addr, (int)ntohs(*port));
 			break;
 		} else {
+			rs->rs_bound_addr = 0;
 			rds_sock_put(rs);
 			ret = -ENOMEM;
 			break;
diff --git a/net/rds/send.c b/net/rds/send.c
index ef53d164..50241d3 100644
--- a/net/rds/send.c
+++ b/net/rds/send.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Oracle.  All rights reserved.
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -983,10 +983,15 @@
 	if (conn->c_npaths == 0 && hash != 0) {
 		rds_send_ping(conn);
 
-		if (conn->c_npaths == 0) {
-			wait_event_interruptible(conn->c_hs_waitq,
-						 (conn->c_npaths != 0));
-		}
+		/* The underlying connection is not up yet.  Need to wait
+		 * until it is up to be sure that the non-zero c_path can be
+		 * used.  But if we are interrupted, we have to use the zero
+		 * c_path in case the connection ends up being non-MP capable.
+		 */
+		if (conn->c_npaths == 0)
+			if (wait_event_interruptible(conn->c_hs_waitq,
+						     conn->c_npaths != 0))
+				hash = 0;
 		if (conn->c_npaths == 1)
 			hash = 0;
 	}
diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c
index 4374e7b..90df95e 100644
--- a/net/rxrpc/rxkad.c
+++ b/net/rxrpc/rxkad.c
@@ -229,7 +229,9 @@
 	len &= ~(call->conn->size_align - 1);
 
 	sg_init_table(sg, nsg);
-	skb_to_sgvec(skb, sg, 0, len);
+	err = skb_to_sgvec(skb, sg, 0, len);
+	if (unlikely(err < 0))
+		goto out;
 	skcipher_request_set_crypt(req, sg, sg, len, iv.x);
 	crypto_skcipher_encrypt(req);
 
@@ -325,7 +327,7 @@
 	struct sk_buff *trailer;
 	u32 data_size, buf;
 	u16 check;
-	int nsg;
+	int nsg, ret;
 
 	_enter("");
 
@@ -342,7 +344,9 @@
 		goto nomem;
 
 	sg_init_table(sg, nsg);
-	skb_to_sgvec(skb, sg, offset, 8);
+	ret = skb_to_sgvec(skb, sg, offset, 8);
+	if (unlikely(ret < 0))
+		return ret;
 
 	/* start the decryption afresh */
 	memset(&iv, 0, sizeof(iv));
@@ -405,7 +409,7 @@
 	struct sk_buff *trailer;
 	u32 data_size, buf;
 	u16 check;
-	int nsg;
+	int nsg, ret;
 
 	_enter(",{%d}", skb->len);
 
@@ -429,7 +433,12 @@
 	}
 
 	sg_init_table(sg, nsg);
-	skb_to_sgvec(skb, sg, offset, len);
+	ret = skb_to_sgvec(skb, sg, offset, len);
+	if (unlikely(ret < 0)) {
+		if (sg != _sg)
+			kfree(sg);
+		return ret;
+	}
 
 	/* decrypt from the session key */
 	token = call->conn->params.key->payload.data[0];
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index f311732..67adb4e 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -95,8 +95,10 @@
 				continue;
 
 			nest = nla_nest_start(skb, n_i);
-			if (nest == NULL)
+			if (nest == NULL) {
+				index--;
 				goto nla_put_failure;
+			}
 			err = tcf_action_dump_1(skb, p, 0, 0);
 			if (err < 0) {
 				index--;
diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c
index 1d39600..40496f3 100644
--- a/net/sched/act_bpf.c
+++ b/net/sched/act_bpf.c
@@ -245,10 +245,14 @@
 
 static void tcf_bpf_cfg_cleanup(const struct tcf_bpf_cfg *cfg)
 {
-	if (cfg->is_ebpf)
-		bpf_prog_put(cfg->filter);
-	else
-		bpf_prog_destroy(cfg->filter);
+	struct bpf_prog *filter = cfg->filter;
+
+	if (filter) {
+		if (cfg->is_ebpf)
+			bpf_prog_put(filter);
+		else
+			bpf_prog_destroy(filter);
+	}
 
 	kfree(cfg->bpf_ops);
 	kfree(cfg->bpf_name);
diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c
index f85313d..bd8e86c 100644
--- a/net/sched/act_skbmod.c
+++ b/net/sched/act_skbmod.c
@@ -192,7 +192,8 @@
 	struct tcf_skbmod_params  *p;
 
 	p = rcu_dereference_protected(d->skbmod_p, 1);
-	kfree_rcu(p, rcu);
+	if (p)
+		kfree_rcu(p, rcu);
 }
 
 static int tcf_skbmod_dump(struct sk_buff *skb, struct tc_action *a,
diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c
index b6e3abe..901fb8b 100644
--- a/net/sched/act_tunnel_key.c
+++ b/net/sched/act_tunnel_key.c
@@ -196,11 +196,12 @@
 	struct tcf_tunnel_key_params *params;
 
 	params = rcu_dereference_protected(t->params, 1);
+	if (params) {
+		if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET)
+			dst_release(&params->tcft_enc_metadata->dst);
 
-	if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET)
-		dst_release(&params->tcft_enc_metadata->dst);
-
-	kfree_rcu(params, rcu);
+		kfree_rcu(params, rcu);
+	}
 }
 
 static int tunnel_key_dump_addresses(struct sk_buff *skb,
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 11f69d4..355d95a7 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -727,8 +727,10 @@
 			sctp_v6_map_v4(addr);
 	}
 
-	if (addr->sa.sa_family == AF_INET)
+	if (addr->sa.sa_family == AF_INET) {
+		memset(addr->v4.sin_zero, 0, sizeof(addr->v4.sin_zero));
 		return sizeof(struct sockaddr_in);
+	}
 	return sizeof(struct sockaddr_in6);
 }
 
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 8cdd6bb..78f3805 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -335,11 +335,14 @@
 	if (!opt->pf->af_supported(addr->sa.sa_family, opt))
 		return NULL;
 
-	/* V4 mapped address are really of AF_INET family */
-	if (addr->sa.sa_family == AF_INET6 &&
-	    ipv6_addr_v4mapped(&addr->v6.sin6_addr) &&
-	    !opt->pf->af_supported(AF_INET, opt))
-		return NULL;
+	if (addr->sa.sa_family == AF_INET6) {
+		if (len < SIN6_LEN_RFC2133)
+			return NULL;
+		/* V4 mapped address are really of AF_INET family */
+		if (ipv6_addr_v4mapped(&addr->v6.sin6_addr) &&
+		    !opt->pf->af_supported(AF_INET, opt))
+			return NULL;
+	}
 
 	/* If we get this far, af is valid. */
 	af = sctp_get_af_specific(addr->sa.sa_family);
@@ -1519,7 +1522,7 @@
 
 	pr_debug("%s: sk:%p, timeout:%ld\n", __func__, sk, timeout);
 
-	lock_sock(sk);
+	lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
 	sk->sk_shutdown = SHUTDOWN_MASK;
 	sk->sk_state = SCTP_SS_CLOSING;
 
@@ -1569,7 +1572,7 @@
 	 * held and that should be grabbed before socket lock.
 	 */
 	spin_lock_bh(&net->sctp.addr_wq_lock);
-	bh_lock_sock(sk);
+	bh_lock_sock_nested(sk);
 
 	/* Hold the sock, since sk_common_release() will put sock_put()
 	 * and we have just a little more cleanup.
diff --git a/net/strparser/strparser.c b/net/strparser/strparser.c
index b5c279b..6cbc935 100644
--- a/net/strparser/strparser.c
+++ b/net/strparser/strparser.c
@@ -59,7 +59,7 @@
 	strp->rx_stopped = 1;
 
 	/* Report an error on the lower socket */
-	csk->sk_err = err;
+	csk->sk_err = -err;
 	csk->sk_error_report(csk);
 }
 
@@ -422,7 +422,7 @@
 	/* Message assembly timed out */
 	STRP_STATS_INCR(strp->stats.rx_msg_timeouts);
 	lock_sock(strp->sk);
-	strp->cb.abort_parser(strp, ETIMEDOUT);
+	strp->cb.abort_parser(strp, -ETIMEDOUT);
 	release_sock(strp->sk);
 }
 
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 79aec90..4afd414 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -237,9 +237,6 @@
 
 	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
 
-	err = crypto_ahash_init(req);
-	if (err)
-		goto out;
 	err = crypto_ahash_setkey(hmac_md5, cksumkey, kctx->gk5e->keylength);
 	if (err)
 		goto out;
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 61a504f..34f9405 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -1375,6 +1375,7 @@
 	struct dentry *clnt_dir = pipe_dentry->d_parent;
 	struct dentry *gssd_dir = clnt_dir->d_parent;
 
+	dget(pipe_dentry);
 	__rpc_rmpipe(d_inode(clnt_dir), pipe_dentry);
 	__rpc_depopulate(clnt_dir, gssd_dummy_info_file, 0, 1);
 	__rpc_depopulate(gssd_dir, gssd_dummy_clnt_dir, 0, 1);
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index d24d14e..1bf9153 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2384,7 +2384,12 @@
 	case -EHOSTUNREACH:
 	case -EADDRINUSE:
 	case -ENOBUFS:
-		/* retry with existing socket, after a delay */
+		/*
+		 * xs_tcp_force_close() wakes tasks with -EIO.
+		 * We need to wake them first to ensure the
+		 * correct error code.
+		 */
+		xprt_wake_pending_tasks(xprt, status);
 		xs_tcp_force_close(xprt);
 		goto out;
 	}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 76e308f..f00e7d3 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4133,7 +4133,7 @@
 	struct nlattr *rate;
 	u32 bitrate;
 	u16 bitrate_compat;
-	enum nl80211_attrs rate_flg;
+	enum nl80211_rate_info rate_flg;
 
 	rate = nla_nest_start(msg, attr);
 	if (!rate)
@@ -14868,7 +14868,8 @@
 	if (!ft_event->target_ap)
 		return;
 
-	msg = nlmsg_new(100 + ft_event->ric_ies_len, GFP_KERNEL);
+	msg = nlmsg_new(100 + ft_event->ies_len + ft_event->ric_ies_len,
+			GFP_KERNEL);
 	if (!msg)
 		return;
 
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index bc0ebd4..9195f23 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -2142,6 +2142,21 @@
 	reg_free_request(reg_request);
 }
 
+static void notify_self_managed_wiphys(struct regulatory_request *request)
+{
+	struct cfg80211_registered_device *rdev;
+	struct wiphy *wiphy;
+
+	list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+		wiphy = &rdev->wiphy;
+		if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
+		    request->initiator == NL80211_REGDOM_SET_BY_USER &&
+		    request->user_reg_hint_type ==
+				NL80211_USER_REG_HINT_CELL_BASE)
+			reg_call_notifier(wiphy, request);
+	}
+}
+
 static bool reg_only_self_managed_wiphys(void)
 {
 	struct cfg80211_registered_device *rdev;
@@ -2193,6 +2208,7 @@
 
 	spin_unlock(&reg_requests_lock);
 
+	notify_self_managed_wiphys(reg_request);
 	if (reg_only_self_managed_wiphys()) {
 		reg_free_request(reg_request);
 		return;
@@ -3073,17 +3089,26 @@
 
 void wiphy_regulatory_register(struct wiphy *wiphy)
 {
-	struct regulatory_request *lr;
+	struct regulatory_request *lr = get_last_request();
 
-	/* self-managed devices ignore external hints */
-	if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
+	/* self-managed devices ignore beacon hints and country IE */
+	if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) {
 		wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS |
 					   REGULATORY_COUNTRY_IE_IGNORE;
 
+		/*
+		 * The last request may have been received before this
+		 * registration call. Call the driver notifier if
+		 * initiator is USER and user type is CELL_BASE.
+		 */
+		if (lr->initiator == NL80211_REGDOM_SET_BY_USER &&
+		    lr->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE)
+			reg_call_notifier(wiphy, lr);
+	}
+
 	if (!reg_dev_ignore_cell_hint(wiphy))
 		reg_num_devs_support_basehint++;
 
-	lr = get_last_request();
 	wiphy_update_regulatory(wiphy, lr->initiator);
 }
 
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 29c5661..13ff407 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -549,7 +549,7 @@
 			    int offset, int len)
 {
 	struct skb_shared_info *sh = skb_shinfo(skb);
-	const skb_frag_t *frag = &sh->frags[-1];
+	const skb_frag_t *frag = &sh->frags[0];
 	struct page *frag_page;
 	void *frag_ptr;
 	int frag_len, frag_size;
@@ -562,10 +562,10 @@
 
 	while (offset >= frag_size) {
 		offset -= frag_size;
-		frag++;
 		frag_page = skb_frag_page(frag);
 		frag_ptr = skb_frag_address(frag);
 		frag_size = skb_frag_size(frag);
+		frag++;
 	}
 
 	frag_ptr += offset;
@@ -577,12 +577,12 @@
 	len -= cur_len;
 
 	while (len > 0) {
-		frag++;
 		frag_len = skb_frag_size(frag);
 		cur_len = min(len, frag_len);
 		__frame_add_frag(frame, skb_frag_page(frag),
 				 skb_frag_address(frag), cur_len, frag_len);
 		len -= cur_len;
+		frag++;
 	}
 }
 
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index f83b74d..0077216 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -1790,32 +1790,40 @@
 
 static int __init x25_init(void)
 {
-	int rc = proto_register(&x25_proto, 0);
+	int rc;
 
-	if (rc != 0)
+	rc = proto_register(&x25_proto, 0);
+	if (rc)
 		goto out;
 
 	rc = sock_register(&x25_family_ops);
-	if (rc != 0)
+	if (rc)
 		goto out_proto;
 
 	dev_add_pack(&x25_packet_type);
 
 	rc = register_netdevice_notifier(&x25_dev_notifier);
-	if (rc != 0)
+	if (rc)
 		goto out_sock;
 
+	rc = x25_register_sysctl();
+	if (rc)
+		goto out_dev;
+
+	rc = x25_proc_init();
+	if (rc)
+		goto out_sysctl;
+
 	pr_info("Linux Version 0.2\n");
 
-	x25_register_sysctl();
-	rc = x25_proc_init();
-	if (rc != 0)
-		goto out_dev;
 out:
 	return rc;
+out_sysctl:
+	x25_unregister_sysctl();
 out_dev:
 	unregister_netdevice_notifier(&x25_dev_notifier);
 out_sock:
+	dev_remove_pack(&x25_packet_type);
 	sock_unregister(AF_X25);
 out_proto:
 	proto_unregister(&x25_proto);
diff --git a/net/x25/sysctl_net_x25.c b/net/x25/sysctl_net_x25.c
index 4323952..703d46a 100644
--- a/net/x25/sysctl_net_x25.c
+++ b/net/x25/sysctl_net_x25.c
@@ -73,9 +73,12 @@
 	{ 0, },
 };
 
-void __init x25_register_sysctl(void)
+int __init x25_register_sysctl(void)
 {
 	x25_table_header = register_net_sysctl(&init_net, "net/x25", x25_table);
+	if (!x25_table_header)
+		return -ENOMEM;
+	return 0;
 }
 
 void x25_unregister_sysctl(void)
diff --git a/net/xfrm/xfrm_ipcomp.c b/net/xfrm/xfrm_ipcomp.c
index ccfdc71..a00ec71 100644
--- a/net/xfrm/xfrm_ipcomp.c
+++ b/net/xfrm/xfrm_ipcomp.c
@@ -283,7 +283,7 @@
 		struct crypto_comp *tfm;
 
 		/* This can be any valid CPU ID so we don't need locking. */
-		tfm = __this_cpu_read(*pos->tfms);
+		tfm = this_cpu_read(*pos->tfms);
 
 		if (!strcmp(crypto_comp_name(tfm), alg_name)) {
 			pos->users++;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 74f2e8f..d869b1d 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1246,6 +1246,8 @@
 	x->curlft.add_time = orig->curlft.add_time;
 	x->km.state = orig->km.state;
 	x->km.seq = orig->km.seq;
+	x->replay = orig->replay;
+	x->preplay = orig->preplay;
 
 	return x;
 
@@ -1883,6 +1885,11 @@
 	struct xfrm_mgr *km;
 	struct xfrm_policy *pol = NULL;
 
+#ifdef CONFIG_COMPAT
+	if (in_compat_syscall())
+		return -EOPNOTSUPP;
+#endif
+
 	if (!optval && !optlen) {
 		xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL);
 		xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL);
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 3b3455a..35e60d3 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -121,22 +121,17 @@
 	struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL];
 	struct xfrm_replay_state_esn *rs;
 
-	if (p->flags & XFRM_STATE_ESN) {
-		if (!rt)
-			return -EINVAL;
-
-		rs = nla_data(rt);
-
-		if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8)
-			return -EINVAL;
-
-		if (nla_len(rt) < xfrm_replay_state_esn_len(rs) &&
-		    nla_len(rt) != sizeof(*rs))
-			return -EINVAL;
-	}
-
 	if (!rt)
-		return 0;
+		return (p->flags & XFRM_STATE_ESN) ? -EINVAL : 0;
+
+	rs = nla_data(rt);
+
+	if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8)
+		return -EINVAL;
+
+	if (nla_len(rt) < xfrm_replay_state_esn_len(rs) &&
+	    nla_len(rt) != sizeof(*rs))
+		return -EINVAL;
 
 	/* As only ESP and AH support ESN feature. */
 	if ((p->id.proto != IPPROTO_ESP) && (p->id.proto != IPPROTO_AH))
diff --git a/scripts/tags.sh b/scripts/tags.sh
index a2ff338..2a61db3 100755
--- a/scripts/tags.sh
+++ b/scripts/tags.sh
@@ -106,6 +106,7 @@
 		case "$i" in
 			*.[cS])
 				j=${i/\.[cS]/\.o}
+				j="${j#$tree}"
 				if [ -e $j ]; then
 					echo $i
 				fi
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index da939fd..8e12ffe 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -407,18 +407,6 @@
 	kfree(sbsec);
 }
 
-/* The file system's label must be initialized prior to use. */
-
-static const char *labeling_behaviors[7] = {
-	"uses xattr",
-	"uses transition SIDs",
-	"uses task SIDs",
-	"uses genfs_contexts",
-	"not configured for labeling",
-	"uses mountpoint labeling",
-	"uses native labeling",
-};
-
 static inline int inode_doinit(struct inode *inode)
 {
 	return inode_doinit_with_dentry(inode, NULL);
@@ -530,10 +518,6 @@
 		}
 	}
 
-	if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
-		printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
-		       sb->s_id, sb->s_type->name);
-
 	sbsec->flags |= SE_SBINITIALIZED;
 	if (selinux_is_sblabel_mnt(sb))
 		sbsec->flags |= SBLABEL_MNT;
@@ -2062,8 +2046,9 @@
 static inline u32 open_file_to_av(struct file *file)
 {
 	u32 av = file_to_av(file);
+	struct inode *inode = file_inode(file);
 
-	if (selinux_policycap_openperm)
+	if (selinux_policycap_openperm && inode->i_sb->s_magic != SOCKFS_MAGIC)
 		av |= FILE__OPEN;
 
 	return av;
@@ -3066,6 +3051,7 @@
 static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 {
 	const struct cred *cred = current_cred();
+	struct inode *inode = d_backing_inode(dentry);
 	unsigned int ia_valid = iattr->ia_valid;
 	__u32 av = FILE__WRITE;
 
@@ -3081,8 +3067,10 @@
 			ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
 		return dentry_has_perm(cred, dentry, FILE__SETATTR);
 
-	if (selinux_policycap_openperm && (ia_valid & ATTR_SIZE)
-			&& !(ia_valid & ATTR_FILE))
+	if (selinux_policycap_openperm &&
+	    inode->i_sb->s_magic != SOCKFS_MAGIC &&
+	    (ia_valid & ATTR_SIZE) &&
+	    !(ia_valid & ATTR_FILE))
 		av |= FILE__OPEN;
 
 	return dentry_has_perm(cred, dentry, av);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 66ea81c..9b517a4 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -154,7 +154,7 @@
 		}
 
 		k = 0;
-		while (p_in->perms && p_in->perms[k]) {
+		while (p_in->perms[k]) {
 			/* An empty permission string skips ahead */
 			if (!*p_in->perms[k]) {
 				k++;
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 3e7c357..cfb8f58 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -834,8 +834,25 @@
 	return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
 }
 
-static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream,
-				     bool trylock)
+/* parameter locking: returns immediately if tried during streaming */
+static int lock_params(struct snd_pcm_runtime *runtime)
+{
+	if (mutex_lock_interruptible(&runtime->oss.params_lock))
+		return -ERESTARTSYS;
+	if (atomic_read(&runtime->oss.rw_ref)) {
+		mutex_unlock(&runtime->oss.params_lock);
+		return -EBUSY;
+	}
+	return 0;
+}
+
+static void unlock_params(struct snd_pcm_runtime *runtime)
+{
+	mutex_unlock(&runtime->oss.params_lock);
+}
+
+/* call with params_lock held */
+static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_hw_params *params, *sparams;
@@ -849,11 +866,8 @@
 	struct snd_mask sformat_mask;
 	struct snd_mask mask;
 
-	if (trylock) {
-		if (!(mutex_trylock(&runtime->oss.params_lock)))
-			return -EAGAIN;
-	} else if (mutex_lock_interruptible(&runtime->oss.params_lock))
-		return -EINTR;
+	if (!runtime->oss.params)
+		return 0;
 	sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL);
 	params = kmalloc(sizeof(*params), GFP_KERNEL);
 	sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
@@ -1079,6 +1093,23 @@
 	kfree(sw_params);
 	kfree(params);
 	kfree(sparams);
+	return err;
+}
+
+/* this one takes the lock by itself */
+static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream,
+				     bool trylock)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int err;
+
+	if (trylock) {
+		if (!(mutex_trylock(&runtime->oss.params_lock)))
+			return -EAGAIN;
+	} else if (mutex_lock_interruptible(&runtime->oss.params_lock))
+		return -ERESTARTSYS;
+
+	err = snd_pcm_oss_change_params_locked(substream);
 	mutex_unlock(&runtime->oss.params_lock);
 	return err;
 }
@@ -1107,6 +1138,10 @@
 	return 0;
 }
 
+/* call with params_lock held */
+/* NOTE: this always call PREPARE unconditionally no matter whether
+ * runtime->oss.prepare is set or not
+ */
 static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
 {
 	int err;
@@ -1131,8 +1166,6 @@
 	struct snd_pcm_runtime *runtime;
 	int err;
 
-	if (substream == NULL)
-		return 0;
 	runtime = substream->runtime;
 	if (runtime->oss.params) {
 		err = snd_pcm_oss_change_params(substream, false);
@@ -1140,6 +1173,29 @@
 			return err;
 	}
 	if (runtime->oss.prepare) {
+		if (mutex_lock_interruptible(&runtime->oss.params_lock))
+			return -ERESTARTSYS;
+		err = snd_pcm_oss_prepare(substream);
+		mutex_unlock(&runtime->oss.params_lock);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
+/* call with params_lock held */
+static int snd_pcm_oss_make_ready_locked(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime;
+	int err;
+
+	runtime = substream->runtime;
+	if (runtime->oss.params) {
+		err = snd_pcm_oss_change_params_locked(substream);
+		if (err < 0)
+			return err;
+	}
+	if (runtime->oss.prepare) {
 		err = snd_pcm_oss_prepare(substream);
 		if (err < 0)
 			return err;
@@ -1361,19 +1417,21 @@
 static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const char __user *buf, size_t bytes)
 {
 	size_t xfer = 0;
-	ssize_t tmp;
+	ssize_t tmp = 0;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
 	if (atomic_read(&substream->mmap_count))
 		return -ENXIO;
 
-	if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
-		return tmp;
+	atomic_inc(&runtime->oss.rw_ref);
 	while (bytes > 0) {
 		if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
 			tmp = -ERESTARTSYS;
 			break;
 		}
+		tmp = snd_pcm_oss_make_ready_locked(substream);
+		if (tmp < 0)
+			goto err;
 		if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
 			tmp = bytes;
 			if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)
@@ -1429,6 +1487,7 @@
 		}
 		tmp = 0;
 	}
+	atomic_dec(&runtime->oss.rw_ref);
 	return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
 }
 
@@ -1468,19 +1527,21 @@
 static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __user *buf, size_t bytes)
 {
 	size_t xfer = 0;
-	ssize_t tmp;
+	ssize_t tmp = 0;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
 	if (atomic_read(&substream->mmap_count))
 		return -ENXIO;
 
-	if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
-		return tmp;
+	atomic_inc(&runtime->oss.rw_ref);
 	while (bytes > 0) {
 		if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
 			tmp = -ERESTARTSYS;
 			break;
 		}
+		tmp = snd_pcm_oss_make_ready_locked(substream);
+		if (tmp < 0)
+			goto err;
 		if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
 			if (runtime->oss.buffer_used == 0) {
 				tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1);
@@ -1521,6 +1582,7 @@
 		}
 		tmp = 0;
 	}
+	atomic_dec(&runtime->oss.rw_ref);
 	return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
 }
 
@@ -1536,10 +1598,12 @@
 			continue;
 		runtime = substream->runtime;
 		snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
+		mutex_lock(&runtime->oss.params_lock);
 		runtime->oss.prepare = 1;
 		runtime->oss.buffer_used = 0;
 		runtime->oss.prev_hw_ptr_period = 0;
 		runtime->oss.period_ptr = 0;
+		mutex_unlock(&runtime->oss.params_lock);
 	}
 	return 0;
 }
@@ -1625,9 +1689,13 @@
 			goto __direct;
 		if ((err = snd_pcm_oss_make_ready(substream)) < 0)
 			return err;
+		atomic_inc(&runtime->oss.rw_ref);
+		if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
+			atomic_dec(&runtime->oss.rw_ref);
+			return -ERESTARTSYS;
+		}
 		format = snd_pcm_oss_format_from(runtime->oss.format);
 		width = snd_pcm_format_physical_width(format);
-		mutex_lock(&runtime->oss.params_lock);
 		if (runtime->oss.buffer_used > 0) {
 #ifdef OSS_DEBUG
 			pcm_dbg(substream->pcm, "sync: buffer_used\n");
@@ -1637,10 +1705,8 @@
 						   runtime->oss.buffer + runtime->oss.buffer_used,
 						   size);
 			err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes);
-			if (err < 0) {
-				mutex_unlock(&runtime->oss.params_lock);
-				return err;
-			}
+			if (err < 0)
+				goto unlock;
 		} else if (runtime->oss.period_ptr > 0) {
 #ifdef OSS_DEBUG
 			pcm_dbg(substream->pcm, "sync: period_ptr\n");
@@ -1650,10 +1716,8 @@
 						   runtime->oss.buffer,
 						   size * 8 / width);
 			err = snd_pcm_oss_sync1(substream, size);
-			if (err < 0) {
-				mutex_unlock(&runtime->oss.params_lock);
-				return err;
-			}
+			if (err < 0)
+				goto unlock;
 		}
 		/*
 		 * The ALSA's period might be a bit large than OSS one.
@@ -1684,7 +1748,11 @@
 				snd_pcm_lib_writev(substream, buffers, size);
 			}
 		}
+unlock:
 		mutex_unlock(&runtime->oss.params_lock);
+		atomic_dec(&runtime->oss.rw_ref);
+		if (err < 0)
+			return err;
 		/*
 		 * finish sync: drain the buffer
 		 */
@@ -1695,7 +1763,9 @@
 		substream->f_flags = saved_f_flags;
 		if (err < 0)
 			return err;
+		mutex_lock(&runtime->oss.params_lock);
 		runtime->oss.prepare = 1;
+		mutex_unlock(&runtime->oss.params_lock);
 	}
 
 	substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
@@ -1706,8 +1776,10 @@
 		err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
 		if (err < 0)
 			return err;
+		mutex_lock(&runtime->oss.params_lock);
 		runtime->oss.buffer_used = 0;
 		runtime->oss.prepare = 1;
+		mutex_unlock(&runtime->oss.params_lock);
 	}
 	return 0;
 }
@@ -1719,6 +1791,8 @@
 	for (idx = 1; idx >= 0; --idx) {
 		struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
 		struct snd_pcm_runtime *runtime;
+		int err;
+
 		if (substream == NULL)
 			continue;
 		runtime = substream->runtime;
@@ -1726,10 +1800,14 @@
 			rate = 1000;
 		else if (rate > 192000)
 			rate = 192000;
+		err = lock_params(runtime);
+		if (err < 0)
+			return err;
 		if (runtime->oss.rate != rate) {
 			runtime->oss.params = 1;
 			runtime->oss.rate = rate;
 		}
+		unlock_params(runtime);
 	}
 	return snd_pcm_oss_get_rate(pcm_oss_file);
 }
@@ -1754,13 +1832,19 @@
 	for (idx = 1; idx >= 0; --idx) {
 		struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
 		struct snd_pcm_runtime *runtime;
+		int err;
+
 		if (substream == NULL)
 			continue;
 		runtime = substream->runtime;
+		err = lock_params(runtime);
+		if (err < 0)
+			return err;
 		if (runtime->oss.channels != channels) {
 			runtime->oss.params = 1;
 			runtime->oss.channels = channels;
 		}
+		unlock_params(runtime);
 	}
 	return snd_pcm_oss_get_channels(pcm_oss_file);
 }
@@ -1833,6 +1917,7 @@
 static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format)
 {
 	int formats, idx;
+	int err;
 	
 	if (format != AFMT_QUERY) {
 		formats = snd_pcm_oss_get_formats(pcm_oss_file);
@@ -1846,10 +1931,14 @@
 			if (substream == NULL)
 				continue;
 			runtime = substream->runtime;
+			err = lock_params(runtime);
+			if (err < 0)
+				return err;
 			if (runtime->oss.format != format) {
 				runtime->oss.params = 1;
 				runtime->oss.format = format;
 			}
+			unlock_params(runtime);
 		}
 	}
 	return snd_pcm_oss_get_format(pcm_oss_file);
@@ -1869,8 +1958,6 @@
 {
 	struct snd_pcm_runtime *runtime;
 
-	if (substream == NULL)
-		return 0;
 	runtime = substream->runtime;
 	if (subdivide == 0) {
 		subdivide = runtime->oss.subdivision;
@@ -1894,9 +1981,17 @@
 
 	for (idx = 1; idx >= 0; --idx) {
 		struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
+		struct snd_pcm_runtime *runtime;
+
 		if (substream == NULL)
 			continue;
-		if ((err = snd_pcm_oss_set_subdivide1(substream, subdivide)) < 0)
+		runtime = substream->runtime;
+		err = lock_params(runtime);
+		if (err < 0)
+			return err;
+		err = snd_pcm_oss_set_subdivide1(substream, subdivide);
+		unlock_params(runtime);
+		if (err < 0)
 			return err;
 	}
 	return err;
@@ -1906,8 +2001,6 @@
 {
 	struct snd_pcm_runtime *runtime;
 
-	if (substream == NULL)
-		return 0;
 	runtime = substream->runtime;
 	if (runtime->oss.subdivision || runtime->oss.fragshift)
 		return -EINVAL;
@@ -1927,9 +2020,17 @@
 
 	for (idx = 1; idx >= 0; --idx) {
 		struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
+		struct snd_pcm_runtime *runtime;
+
 		if (substream == NULL)
 			continue;
-		if ((err = snd_pcm_oss_set_fragment1(substream, val)) < 0)
+		runtime = substream->runtime;
+		err = lock_params(runtime);
+		if (err < 0)
+			return err;
+		err = snd_pcm_oss_set_fragment1(substream, val);
+		unlock_params(runtime);
+		if (err < 0)
 			return err;
 	}
 	return err;
@@ -2013,6 +2114,9 @@
 	}
       	if (psubstream) {
       		runtime = psubstream->runtime;
+		cmd = 0;
+		if (mutex_lock_interruptible(&runtime->oss.params_lock))
+			return -ERESTARTSYS;
 		if (trigger & PCM_ENABLE_OUTPUT) {
 			if (runtime->oss.trigger)
 				goto _skip1;
@@ -2030,13 +2134,19 @@
 			cmd = SNDRV_PCM_IOCTL_DROP;
 			runtime->oss.prepare = 1;
 		}
-		err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL);
-		if (err < 0)
-			return err;
-	}
  _skip1:
+		mutex_unlock(&runtime->oss.params_lock);
+		if (cmd) {
+			err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL);
+			if (err < 0)
+				return err;
+		}
+	}
 	if (csubstream) {
       		runtime = csubstream->runtime;
+		cmd = 0;
+		if (mutex_lock_interruptible(&runtime->oss.params_lock))
+			return -ERESTARTSYS;
 		if (trigger & PCM_ENABLE_INPUT) {
 			if (runtime->oss.trigger)
 				goto _skip2;
@@ -2051,11 +2161,14 @@
 			cmd = SNDRV_PCM_IOCTL_DROP;
 			runtime->oss.prepare = 1;
 		}
-		err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL);
-		if (err < 0)
-			return err;
-	}
  _skip2:
+		mutex_unlock(&runtime->oss.params_lock);
+		if (cmd) {
+			err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL);
+			if (err < 0)
+				return err;
+		}
+	}
 	return 0;
 }
 
@@ -2307,6 +2420,7 @@
 	runtime->oss.maxfrags = 0;
 	runtime->oss.subdivision = 0;
 	substream->pcm_release = snd_pcm_oss_release_substream;
+	atomic_set(&runtime->oss.rw_ref, 0);
 }
 
 static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file)
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 48f6aee..d79a04e 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -28,6 +28,7 @@
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/pcm.h>
+#include <sound/timer.h>
 #include <sound/control.h>
 #include <sound/info.h>
 
@@ -1036,8 +1037,13 @@
 	snd_free_pages((void*)runtime->control,
 		       PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
 	kfree(runtime->hw_constraints.rules);
-	kfree(runtime);
+	/* Avoid concurrent access to runtime via PCM timer interface */
+	if (substream->timer)
+		spin_lock_irq(&substream->timer->lock);
 	substream->runtime = NULL;
+	if (substream->timer)
+		spin_unlock_irq(&substream->timer->lock);
+	kfree(runtime);
 	put_pid(substream->pid);
 	substream->pid = NULL;
 	substream->pstr->substream_opened--;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 8e5649a..019f60b 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -3460,7 +3460,7 @@
 					 area,
 					 substream->runtime->dma_area,
 					 substream->runtime->dma_addr,
-					 area->vm_end - area->vm_start);
+					 substream->runtime->dma_bytes);
 #endif /* CONFIG_X86 */
 	/* mmap with fault handler */
 	area->vm_ops = &snd_pcm_vm_ops_data_fault;
diff --git a/sound/core/rawmidi_compat.c b/sound/core/rawmidi_compat.c
index f69764d..e30e30b 100644
--- a/sound/core/rawmidi_compat.c
+++ b/sound/core/rawmidi_compat.c
@@ -36,8 +36,6 @@
 	struct snd_rawmidi_params params;
 	unsigned int val;
 
-	if (rfile->output == NULL)
-		return -EINVAL;
 	if (get_user(params.stream, &src->stream) ||
 	    get_user(params.buffer_size, &src->buffer_size) ||
 	    get_user(params.avail_min, &src->avail_min) ||
@@ -46,8 +44,12 @@
 	params.no_active_sensing = val;
 	switch (params.stream) {
 	case SNDRV_RAWMIDI_STREAM_OUTPUT:
+		if (!rfile->output)
+			return -EINVAL;
 		return snd_rawmidi_output_params(rfile->output, &params);
 	case SNDRV_RAWMIDI_STREAM_INPUT:
+		if (!rfile->input)
+			return -EINVAL;
 		return snd_rawmidi_input_params(rfile->input, &params);
 	}
 	return -EINVAL;
@@ -67,16 +69,18 @@
 	int err;
 	struct snd_rawmidi_status status;
 
-	if (rfile->output == NULL)
-		return -EINVAL;
 	if (get_user(status.stream, &src->stream))
 		return -EFAULT;
 
 	switch (status.stream) {
 	case SNDRV_RAWMIDI_STREAM_OUTPUT:
+		if (!rfile->output)
+			return -EINVAL;
 		err = snd_rawmidi_output_status(rfile->output, &status);
 		break;
 	case SNDRV_RAWMIDI_STREAM_INPUT:
+		if (!rfile->input)
+			return -EINVAL;
 		err = snd_rawmidi_input_status(rfile->input, &status);
 		break;
 	default:
@@ -112,16 +116,18 @@
 	int err;
 	struct snd_rawmidi_status status;
 
-	if (rfile->output == NULL)
-		return -EINVAL;
 	if (get_user(status.stream, &src->stream))
 		return -EFAULT;
 
 	switch (status.stream) {
 	case SNDRV_RAWMIDI_STREAM_OUTPUT:
+		if (!rfile->output)
+			return -EINVAL;
 		err = snd_rawmidi_output_status(rfile->output, &status);
 		break;
 	case SNDRV_RAWMIDI_STREAM_INPUT:
+		if (!rfile->input)
+			return -EINVAL;
 		err = snd_rawmidi_input_status(rfile->input, &status);
 		break;
 	default:
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 733b342..7d3f88d 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1514,7 +1514,8 @@
 		 */
 		u8 val;
 		pci_read_config_byte(chip->pci, 0x42, &val);
-		if (!(val & 0x80) && chip->pci->revision == 0x30)
+		if (!(val & 0x80) && (chip->pci->revision == 0x30 ||
+				      chip->pci->revision == 0x20))
 			snoop = false;
 	}
 
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 993bde2..7693e63 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -54,10 +54,17 @@
  * using 2 wire for device control, so we cache them instead.
  * There is no point in caching the reset register
  */
-static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = {
-	0x0097, 0x0097, 0x0079, 0x0079,
-	0x000a, 0x0008, 0x009f, 0x000a,
-	0x0000, 0x0000
+static const struct reg_default ssm2602_reg[SSM2602_CACHEREGNUM] = {
+	{ .reg = 0x00, .def = 0x0097 },
+	{ .reg = 0x01, .def = 0x0097 },
+	{ .reg = 0x02, .def = 0x0079 },
+	{ .reg = 0x03, .def = 0x0079 },
+	{ .reg = 0x04, .def = 0x000a },
+	{ .reg = 0x05, .def = 0x0008 },
+	{ .reg = 0x06, .def = 0x009f },
+	{ .reg = 0x07, .def = 0x000a },
+	{ .reg = 0x08, .def = 0x0000 },
+	{ .reg = 0x09, .def = 0x0000 }
 };
 
 
@@ -620,8 +627,8 @@
 	.volatile_reg = ssm2602_register_volatile,
 
 	.cache_type = REGCACHE_RBTREE,
-	.reg_defaults_raw = ssm2602_reg,
-	.num_reg_defaults_raw = ARRAY_SIZE(ssm2602_reg),
+	.reg_defaults = ssm2602_reg,
+	.num_reg_defaults = ARRAY_SIZE(ssm2602_reg),
 };
 EXPORT_SYMBOL_GPL(ssm2602_regmap_config);
 
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index dd88c2c..48804e4 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -201,7 +201,7 @@
 	if (ret < 0)
 		return ret;
 
-	ret = asoc_simple_card_init_mic(rtd->card, &priv->hp_jack, PREFIX);
+	ret = asoc_simple_card_init_mic(rtd->card, &priv->mic_jack, PREFIX);
 	if (ret < 0)
 		return ret;
 
diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c
index 4ccc80e..c798f8d 100644
--- a/sound/soc/intel/atom/sst/sst_stream.c
+++ b/sound/soc/intel/atom/sst/sst_stream.c
@@ -221,7 +221,7 @@
 		sst_free_block(sst_drv_ctx, block);
 out:
 	test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id);
-	return 0;
+	return ret;
 }
 
 /*
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index 9052561..b1eb696 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -111,6 +111,7 @@
 	SND_SOC_DAPM_HP("Headphone", NULL),
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
 	SND_SOC_DAPM_MIC("Int Mic", NULL),
+	SND_SOC_DAPM_MIC("Int Analog Mic", NULL),
 	SND_SOC_DAPM_SPK("Ext Spk", NULL),
 	SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
 			platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
@@ -121,6 +122,8 @@
 	{"IN1N", NULL, "Headset Mic"},
 	{"DMIC L1", NULL, "Int Mic"},
 	{"DMIC R1", NULL, "Int Mic"},
+	{"IN2P", NULL, "Int Analog Mic"},
+	{"IN2N", NULL, "Int Analog Mic"},
 	{"Headphone", NULL, "HPOL"},
 	{"Headphone", NULL, "HPOR"},
 	{"Ext Spk", NULL, "SPOL"},
@@ -134,6 +137,9 @@
 	{"Headphone", NULL, "Platform Clock"},
 	{"Headset Mic", NULL, "Platform Clock"},
 	{"Int Mic", NULL, "Platform Clock"},
+	{"Int Analog Mic", NULL, "Platform Clock"},
+	{"Int Analog Mic", NULL, "micbias1"},
+	{"Int Analog Mic", NULL, "micbias2"},
 	{"Ext Spk", NULL, "Platform Clock"},
 };
 
@@ -162,6 +168,7 @@
 	SOC_DAPM_PIN_SWITCH("Headphone"),
 	SOC_DAPM_PIN_SWITCH("Headset Mic"),
 	SOC_DAPM_PIN_SWITCH("Int Mic"),
+	SOC_DAPM_PIN_SWITCH("Int Analog Mic"),
 	SOC_DAPM_PIN_SWITCH("Ext Spk"),
 };
 
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index 805b7f2..78472c9 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -331,7 +331,11 @@
 	if (skl->skl_sst->is_first_boot == true)
 		return 0;
 
+	/* disable dynamic clock gating during fw and lib download */
+	ctx->enable_miscbdcge(ctx->dev, false);
+
 	ret = skl_dsp_wake(ctx->dsp);
+	ctx->enable_miscbdcge(ctx->dev, true);
 	if (ret < 0)
 		return ret;
 
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index 58c7286..2fd213c 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -1191,7 +1191,11 @@
 			return -EIO;
 		}
 
+		/* disable dynamic clock gating during fw and lib download */
+		skl->skl_sst->enable_miscbdcge(platform->dev, false);
+
 		ret = ops->init_fw(platform->dev, skl->skl_sst);
+		skl->skl_sst->enable_miscbdcge(platform->dev, true);
 		if (ret < 0) {
 			dev_err(platform->dev, "Failed to boot first fw: %d\n", ret);
 			return ret;
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index fefa6ad..17e305b 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -552,6 +552,13 @@
 		struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
 		u32 *buf = (u32 *)(runtime->dma_area +
 				   rsnd_dai_pointer_offset(io, 0));
+		int shift = 0;
+
+		switch (runtime->sample_bits) {
+		case 32:
+			shift = 8;
+			break;
+		}
 
 		/*
 		 * 8/16/32 data can be assesse to TDR/RDR register
@@ -559,9 +566,9 @@
 		 * see rsnd_ssi_init()
 		 */
 		if (rsnd_io_is_play(io))
-			rsnd_mod_write(mod, SSITDR, *buf);
+			rsnd_mod_write(mod, SSITDR, (*buf) << shift);
 		else
-			*buf = rsnd_mod_read(mod, SSIRDR);
+			*buf = (rsnd_mod_read(mod, SSIRDR) >> shift);
 
 		elapsed = rsnd_dai_pointer_update(io, sizeof(*buf));
 	}
diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c
index d0fb2f2..4f4ebe9 100644
--- a/sound/usb/line6/midi.c
+++ b/sound/usb/line6/midi.c
@@ -125,7 +125,7 @@
 	}
 
 	usb_fill_int_urb(urb, line6->usbdev,
-			 usb_sndbulkpipe(line6->usbdev,
+			 usb_sndintpipe(line6->usbdev,
 					 line6->properties->ep_ctrl_w),
 			 transfer_buffer, length, midi_sent, line6,
 			 line6->interval);
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 1cd7f8b..45655b9 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1175,6 +1175,7 @@
 	switch (id) {
 	case USB_ID(0x0644, 0x8043): /* TEAC UD-501/UD-503/NT-503 */
 	case USB_ID(0x0644, 0x8044): /* Esoteric D-05X */
+	case USB_ID(0x0644, 0x804a): /* TEAC UD-301 */
 		return true;
 	}
 	return false;
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 4c596ba..0fd8bfb 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -679,6 +679,10 @@
 	{ .name	    = "mlockall",   .errmsg = true,
 	  .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
 	{ .name	    = "mmap",	    .hexret = true,
+/* The standard mmap maps to old_mmap on s390x */
+#if defined(__s390x__)
+	.alias = "old_mmap",
+#endif
 	  .arg_scnprintf = { [0] = SCA_HEX,	  /* addr */
 			     [2] = SCA_MMAP_PROT, /* prot */
 			     [3] = SCA_MMAP_FLAGS, /* flags */ }, },
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index d2c6cdd..4bc5882 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -366,7 +366,23 @@
 	if (!is_regular_file(name))
 		return -EINVAL;
 
+	if (dso__needs_decompress(dso)) {
+		char newpath[KMOD_DECOMP_LEN];
+		size_t len = sizeof(newpath);
+
+		if (dso__decompress_kmodule_path(dso, name, newpath, len) < 0) {
+			free(name);
+			return -dso->load_errno;
+		}
+
+		strcpy(name, newpath);
+	}
+
 	fd = do_open(name);
+
+	if (dso__needs_decompress(dso))
+		unlink(name);
+
 	free(name);
 	return fd;
 }
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 28bdb48..ab36aa5 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1454,8 +1454,16 @@
 
 		dso__set_build_id(dso, &bev->build_id);
 
-		if (!is_kernel_module(filename, cpumode))
-			dso->kernel = dso_type;
+		if (dso_type != DSO_TYPE_USER) {
+			struct kmod_path m = { .name = NULL, };
+
+			if (!kmod_path__parse_name(&m, filename) && m.kmod)
+				dso__set_short_name(dso, strdup(m.name), true);
+			else
+				dso->kernel = dso_type;
+
+			free(m.name);
+		}
 
 		build_id__sprintf(dso->build_id, sizeof(dso->build_id),
 				  sbuild_id);
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
index 7e27207..cac3953 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
@@ -1300,6 +1300,7 @@
 	intel_pt_clear_tx_flags(decoder);
 	decoder->have_tma = false;
 	decoder->cbr = 0;
+	decoder->timestamp_insn_cnt = 0;
 	decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC;
 	decoder->overflow = true;
 	return -EOVERFLOW;
@@ -1522,6 +1523,7 @@
 		case INTEL_PT_PSBEND:
 			intel_pt_log("ERROR: Missing TIP after FUP\n");
 			decoder->pkt_state = INTEL_PT_STATE_ERR3;
+			decoder->pkt_step = 0;
 			return -ENOENT;
 
 		case INTEL_PT_OVF:
@@ -2182,14 +2184,6 @@
 	return &decoder->state;
 }
 
-static bool intel_pt_at_psb(unsigned char *buf, size_t len)
-{
-	if (len < INTEL_PT_PSB_LEN)
-		return false;
-	return memmem(buf, INTEL_PT_PSB_LEN, INTEL_PT_PSB_STR,
-		      INTEL_PT_PSB_LEN);
-}
-
 /**
  * intel_pt_next_psb - move buffer pointer to the start of the next PSB packet.
  * @buf: pointer to buffer pointer
@@ -2278,6 +2272,7 @@
  * @buf: buffer
  * @len: size of buffer
  * @tsc: TSC value returned
+ * @rem: returns remaining size when TSC is found
  *
  * Find a TSC packet in @buf and return the TSC value.  This function assumes
  * that @buf starts at a PSB and that PSB+ will contain TSC and so stops if a
@@ -2285,7 +2280,8 @@
  *
  * Return: %true if TSC is found, false otherwise.
  */
-static bool intel_pt_next_tsc(unsigned char *buf, size_t len, uint64_t *tsc)
+static bool intel_pt_next_tsc(unsigned char *buf, size_t len, uint64_t *tsc,
+			      size_t *rem)
 {
 	struct intel_pt_pkt packet;
 	int ret;
@@ -2296,6 +2292,7 @@
 			return false;
 		if (packet.type == INTEL_PT_TSC) {
 			*tsc = packet.payload;
+			*rem = len;
 			return true;
 		}
 		if (packet.type == INTEL_PT_PSBEND)
@@ -2346,6 +2343,8 @@
  * @len_a: size of first buffer
  * @buf_b: second buffer
  * @len_b: size of second buffer
+ * @consecutive: returns true if there is data in buf_b that is consecutive
+ *               to buf_a
  *
  * If the trace contains TSC we can look at the last TSC of @buf_a and the
  * first TSC of @buf_b in order to determine if the buffers overlap, and then
@@ -2358,33 +2357,41 @@
 static unsigned char *intel_pt_find_overlap_tsc(unsigned char *buf_a,
 						size_t len_a,
 						unsigned char *buf_b,
-						size_t len_b)
+						size_t len_b, bool *consecutive)
 {
 	uint64_t tsc_a, tsc_b;
 	unsigned char *p;
-	size_t len;
+	size_t len, rem_a, rem_b;
 
 	p = intel_pt_last_psb(buf_a, len_a);
 	if (!p)
 		return buf_b; /* No PSB in buf_a => no overlap */
 
 	len = len_a - (p - buf_a);
-	if (!intel_pt_next_tsc(p, len, &tsc_a)) {
+	if (!intel_pt_next_tsc(p, len, &tsc_a, &rem_a)) {
 		/* The last PSB+ in buf_a is incomplete, so go back one more */
 		len_a -= len;
 		p = intel_pt_last_psb(buf_a, len_a);
 		if (!p)
 			return buf_b; /* No full PSB+ => assume no overlap */
 		len = len_a - (p - buf_a);
-		if (!intel_pt_next_tsc(p, len, &tsc_a))
+		if (!intel_pt_next_tsc(p, len, &tsc_a, &rem_a))
 			return buf_b; /* No TSC in buf_a => assume no overlap */
 	}
 
 	while (1) {
 		/* Ignore PSB+ with no TSC */
-		if (intel_pt_next_tsc(buf_b, len_b, &tsc_b) &&
-		    intel_pt_tsc_cmp(tsc_a, tsc_b) < 0)
-			return buf_b; /* tsc_a < tsc_b => no overlap */
+		if (intel_pt_next_tsc(buf_b, len_b, &tsc_b, &rem_b)) {
+			int cmp = intel_pt_tsc_cmp(tsc_a, tsc_b);
+
+			/* Same TSC, so buffers are consecutive */
+			if (!cmp && rem_b >= rem_a) {
+				*consecutive = true;
+				return buf_b + len_b - (rem_b - rem_a);
+			}
+			if (cmp < 0)
+				return buf_b; /* tsc_a < tsc_b => no overlap */
+		}
 
 		if (!intel_pt_step_psb(&buf_b, &len_b))
 			return buf_b + len_b; /* No PSB in buf_b => no data */
@@ -2398,6 +2405,8 @@
  * @buf_b: second buffer
  * @len_b: size of second buffer
  * @have_tsc: can use TSC packets to detect overlap
+ * @consecutive: returns true if there is data in buf_b that is consecutive
+ *               to buf_a
  *
  * When trace samples or snapshots are recorded there is the possibility that
  * the data overlaps.  Note that, for the purposes of decoding, data is only
@@ -2408,7 +2417,7 @@
  */
 unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a,
 				     unsigned char *buf_b, size_t len_b,
-				     bool have_tsc)
+				     bool have_tsc, bool *consecutive)
 {
 	unsigned char *found;
 
@@ -2420,7 +2429,8 @@
 		return buf_b; /* No overlap */
 
 	if (have_tsc) {
-		found = intel_pt_find_overlap_tsc(buf_a, len_a, buf_b, len_b);
+		found = intel_pt_find_overlap_tsc(buf_a, len_a, buf_b, len_b,
+						  consecutive);
 		if (found)
 			return found;
 	}
@@ -2435,28 +2445,16 @@
 	}
 
 	/* Now len_b >= len_a */
-	if (len_b > len_a) {
-		/* The leftover buffer 'b' must start at a PSB */
-		while (!intel_pt_at_psb(buf_b + len_a, len_b - len_a)) {
-			if (!intel_pt_step_psb(&buf_a, &len_a))
-				return buf_b; /* No overlap */
-		}
-	}
-
 	while (1) {
 		/* Potential overlap so check the bytes */
 		found = memmem(buf_a, len_a, buf_b, len_a);
-		if (found)
+		if (found) {
+			*consecutive = true;
 			return buf_b + len_a;
+		}
 
 		/* Try again at next PSB in buffer 'a' */
 		if (!intel_pt_step_psb(&buf_a, &len_a))
 			return buf_b; /* No overlap */
-
-		/* The leftover buffer 'b' must start at a PSB */
-		while (!intel_pt_at_psb(buf_b + len_a, len_b - len_a)) {
-			if (!intel_pt_step_psb(&buf_a, &len_a))
-				return buf_b; /* No overlap */
-		}
 	}
 }
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
index 8939998..9ae4df1 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
@@ -103,7 +103,7 @@
 
 unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a,
 				     unsigned char *buf_b, size_t len_b,
-				     bool have_tsc);
+				     bool have_tsc, bool *consecutive);
 
 int intel_pt__strerror(int code, char *buf, size_t buflen);
 
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index dc041d4..b1161d7 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -131,6 +131,7 @@
 	bool stop;
 	bool step_through_buffers;
 	bool use_buffer_pid_tid;
+	bool sync_switch;
 	pid_t pid, tid;
 	int cpu;
 	int switch_state;
@@ -194,14 +195,17 @@
 static int intel_pt_do_fix_overlap(struct intel_pt *pt, struct auxtrace_buffer *a,
 				   struct auxtrace_buffer *b)
 {
+	bool consecutive = false;
 	void *start;
 
 	start = intel_pt_find_overlap(a->data, a->size, b->data, b->size,
-				      pt->have_tsc);
+				      pt->have_tsc, &consecutive);
 	if (!start)
 		return -EINVAL;
 	b->use_size = b->data + b->size - start;
 	b->use_data = start;
+	if (b->use_size && consecutive)
+		b->consecutive = true;
 	return 0;
 }
 
@@ -928,10 +932,12 @@
 			if (pt->timeless_decoding || !pt->have_sched_switch)
 				ptq->use_buffer_pid_tid = true;
 		}
+
+		ptq->sync_switch = pt->sync_switch;
 	}
 
 	if (!ptq->on_heap &&
-	    (!pt->sync_switch ||
+	    (!ptq->sync_switch ||
 	     ptq->switch_state != INTEL_PT_SS_EXPECTING_SWITCH_EVENT)) {
 		const struct intel_pt_state *state;
 		int ret;
@@ -1333,7 +1339,7 @@
 	if (pt->synth_opts.last_branch)
 		intel_pt_update_last_branch_rb(ptq);
 
-	if (!pt->sync_switch)
+	if (!ptq->sync_switch)
 		return 0;
 
 	if (intel_pt_is_switch_ip(ptq, state->to_ip)) {
@@ -1414,6 +1420,21 @@
 	return switch_ip;
 }
 
+static void intel_pt_enable_sync_switch(struct intel_pt *pt)
+{
+	unsigned int i;
+
+	pt->sync_switch = true;
+
+	for (i = 0; i < pt->queues.nr_queues; i++) {
+		struct auxtrace_queue *queue = &pt->queues.queue_array[i];
+		struct intel_pt_queue *ptq = queue->priv;
+
+		if (ptq)
+			ptq->sync_switch = true;
+	}
+}
+
 static int intel_pt_run_decoder(struct intel_pt_queue *ptq, u64 *timestamp)
 {
 	const struct intel_pt_state *state = ptq->state;
@@ -1430,7 +1451,7 @@
 			if (pt->switch_ip) {
 				intel_pt_log("switch_ip: %"PRIx64" ptss_ip: %"PRIx64"\n",
 					     pt->switch_ip, pt->ptss_ip);
-				pt->sync_switch = true;
+				intel_pt_enable_sync_switch(pt);
 			}
 		}
 	}
@@ -1446,9 +1467,9 @@
 		if (state->err) {
 			if (state->err == INTEL_PT_ERR_NODATA)
 				return 1;
-			if (pt->sync_switch &&
+			if (ptq->sync_switch &&
 			    state->from_ip >= pt->kernel_start) {
-				pt->sync_switch = false;
+				ptq->sync_switch = false;
 				intel_pt_next_tid(pt, ptq);
 			}
 			if (pt->synth_opts.errors) {
@@ -1474,7 +1495,7 @@
 				     state->timestamp, state->est_timestamp);
 			ptq->timestamp = state->est_timestamp;
 		/* Use estimated TSC in unknown switch state */
-		} else if (pt->sync_switch &&
+		} else if (ptq->sync_switch &&
 			   ptq->switch_state == INTEL_PT_SS_UNKNOWN &&
 			   intel_pt_is_switch_ip(ptq, state->to_ip) &&
 			   ptq->next_tid == -1) {
@@ -1621,7 +1642,7 @@
 		return 1;
 
 	ptq = intel_pt_cpu_to_ptq(pt, cpu);
-	if (!ptq)
+	if (!ptq || !ptq->sync_switch)
 		return 1;
 
 	switch (ptq->switch_state) {
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 4d2e22f..c93dacc 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2609,6 +2609,14 @@
 
 out:
 	free(nbase);
+
+	/* Final validation */
+	if (ret >= 0 && !is_c_func_name(buf)) {
+		pr_warning("Internal error: \"%s\" is an invalid event name.\n",
+			   buf);
+		ret = -EINVAL;
+	}
+
 	return ret;
 }
 
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 783a53f..b46e1cf 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -38,6 +38,14 @@
 		return 0;
 
 	mod = dwfl_addrmodule(ui->dwfl, ip);
+	if (mod) {
+		Dwarf_Addr s;
+
+		dwfl_module_info(mod, NULL, &s, NULL, NULL, NULL, NULL, NULL);
+		if (s != al->map->start)
+			mod = 0;
+	}
+
 	if (!mod)
 		mod = dwfl_report_elf(ui->dwfl, dso->short_name,
 				      dso->long_name, -1, al->map->start,
@@ -167,12 +175,16 @@
 {
 	struct unwind_info *ui = arg;
 	Dwarf_Addr pc;
+	bool isactivation;
 
-	if (!dwfl_frame_pc(state, &pc, NULL)) {
+	if (!dwfl_frame_pc(state, &pc, &isactivation)) {
 		pr_err("%s", dwfl_errmsg(-1));
 		return DWARF_CB_ABORT;
 	}
 
+	if (!isactivation)
+		--pc;
+
 	return entry(pc, ui) || !(--ui->max_stack) ?
 	       DWARF_CB_ABORT : DWARF_CB_OK;
 }
diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c
index 20c2e57..1203834 100644
--- a/tools/perf/util/unwind-libunwind-local.c
+++ b/tools/perf/util/unwind-libunwind-local.c
@@ -646,6 +646,17 @@
 
 		while (!ret && (unw_step(&c) > 0) && i < max_stack) {
 			unw_get_reg(&c, UNW_REG_IP, &ips[i]);
+
+			/*
+			 * Decrement the IP for any non-activation frames.
+			 * this is required to properly find the srcline
+			 * for caller frames.
+			 * See also the documentation for dwfl_frame_pc(),
+			 * which this code tries to replicate.
+			 */
+			if (unw_is_signal_frame(&c) <= 0)
+				--ips[i];
+
 			++i;
 		}
 
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 85c5680..dfb010b 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -207,7 +207,7 @@
 
 		size -= ret;
 		off_in += ret;
-		off_out -= ret;
+		off_out += ret;
 	}
 	munmap(ptr, off_in + size);
 
diff --git a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c
index d9c49f4..e79ccd6 100644
--- a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c
+++ b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c
@@ -42,12 +42,12 @@
 	printf("Check DSCR TM context switch: ");
 	fflush(stdout);
 	for (;;) {
-		rv = 1;
 		asm __volatile__ (
 			/* set a known value into the DSCR */
 			"ld      3, %[dscr1];"
 			"mtspr   %[sprn_dscr], 3;"
 
+			"li      %[rv], 1;"
 			/* start and suspend a transaction */
 			"tbegin.;"
 			"beq     1f;"
diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c
index cbb0564..f689981 100644
--- a/tools/testing/selftests/seccomp/seccomp_bpf.c
+++ b/tools/testing/selftests/seccomp/seccomp_bpf.c
@@ -1318,7 +1318,7 @@
 	iov.iov_len = sizeof(regs);
 	ret = ptrace(PTRACE_GETREGSET, tracee, NT_PRSTATUS, &iov);
 #endif
-	EXPECT_EQ(0, ret);
+	EXPECT_EQ(0, ret) {}
 
 #if defined(__x86_64__) || defined(__i386__) || defined(__powerpc__) || \
     defined(__s390__) || defined(__hppa__)