Merge commit '406a0a8400fd2d1d5b68c993e191f4c05a8c23a9' into android-msm-mako-3.4-wip

(needs additional patches to compile)

* commit '406a0a8400fd2d1d5b68c993e191f4c05a8c23a9': (450 commits)
  msm: vidc: Separate partition for shared memory
  arm/dt: Move MDSS device nodes to separate dtsi file
  msm: cpr: Add support for CPR in 8625
  defconfig: msm8974: enable genlock
  msm: Remove idle stats and cpuidle hooks
  msm: timer: Add a stub for msm_timer_get_timer0_base
  msm: iomap: Add mappings for the MPM PS_HOLD region
  msm:  vidc: Adds support for Rate Control
  ASoc: msm: Add low latency playback and recording support.
  msm: Fix for overflow cpu alive mask dump.
  tty: hold lock across tty buffer finding and buffer filling
  msm: Turn off cpu alive mask messages.
  msm: kgsl: Add GPU clock statistics.
  Bluetooth: Enable BT&FM kernel modules for MSM8974
  v4l2: Add mutex to streamon() and dqbuf()in v4l2 framework.
  msm: mdss: fix suspend coming to MDP before panel drivers
  msm: mdss: allocate framebuffer memory from ion pool
  msm: mdss: improve clock and bus scaling logic
  platform: msm: Add driver for QPNP PMIC clkdiv peripherals
  msm: add adsp loader driver
  ...

Conflicts:
	drivers/base/power/main.c
	drivers/power/pm8921-bms.c
	drivers/power/pm8921-charger.c
	drivers/usb/gadget/Kconfig
	drivers/usb/gadget/android.c
	drivers/usb/host/ehci-msm-hsic.c
	drivers/video/msm/mdp4_overlay_dsi_video.c
	include/linux/mfd/pm8xxx/pm8921-charger.h

Signed-off-by: Iliyan Malchev <malchev@google.com>
diff --git a/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
new file mode 100644
index 0000000..a39356c
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
@@ -0,0 +1,78 @@
+DCVS Core Info
+
+This data describes specific DCVS tuning data for a specific core (CPU, GPU,
+etc).
+
+Required properties:
+
+- qcom,core-max-time-us:	Maximum time limit in micorseconds for switching clock rate.
+				Limited to this value if switching time takes longer than this limit. Typical value is 100000.
+- qcom,algo-slack-time-us:	Time in microseconds after which the QoS guarantee will kick in
+				and the clock rate will increased as necessary. Typical value is about 30000.
+- qcom,algo-disable-pc-threshold:	If core frequency (kHz) is higher than this value, power collapse is disallowed. Set to 0 for GPU.
+- qcom,algo-ss-window-size:	Steady state window size in microseconds.
+- qcom,algo-ss-util-pct:	When determining the steady state level, this percentage value is used to provide headroom
+				from the utilized cpu to the selected level.
+- qcom,algo-ee-max-util-pct:	When determining the level with the lowest energy, any level that exceeds this busy
+				percentage, for the measured work in the last window, is disqualified for performance reasons.
+- qcom,algo-ss-iobusy-conv:	Used to convert correlation time into assumed IO Busy time, which is removed
+				from measured elapsed time when computing cpu utilization.
+
+
+A number of frequency levels are represented as sub-nodes:
+
+required properties:
+- reg:			The index of the frequency entry
+- qcom,freq		The frequency of the DVS entry (in kHZ)
+- qcom,idle-energy: 	The idle energy cost of the entry (in micro watts)
+- qcom,active-energy:	The active energy cost of the entry (in micro watts)
+
+Sample:
+
+qcom,kgsl-3d0@fdb00000 {
+	...
+	qcom,dcvs-core-info {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		compatible = "qcom,dcvs-core-info";
+
+		qcom,core-max-time-us = <100000>;
+		qcom,algo-slack-time-us = <39000>;
+		qcom,algo-disable-pc-threshold = <86000>;
+		qcom,algo-ss-window-size = <1000000>;
+		qcom,algo-ss-util-pct = <95>;
+		qcom,algo-em-max-util-pct = <97>;
+		qcom,algo-ss-iobusy-conv = <100>;
+
+		qcom,dcvs-freq@0 {
+			reg = <0>;
+			qcom,freq = <0>;
+			qcom,idle-energy = <0>;
+			qcom,active-energy = <333932>;
+		};
+
+		qcom,dcvs-freq@1 {
+			reg = <1>;
+			qcom,freq = <0>;
+			qcom,idle-energy = <0>;
+			qcom,active-energy = <497532>;
+		};
+
+		qcom,dcvs-freq@2 {
+			reg = <2>;
+			qcom,freq = <0>;
+			qcom,idle-energy = <0>;
+			qcom,active-energy = <707610>;
+		};
+
+		qcom,dcvs-freq@3 {
+			reg = <3>;
+			qcom,freq = <0>;
+			qcom,idle-energy = <0>;
+			qcom,active-energy = <844545>;
+		};
+	};
+	...
+};
+
diff --git a/Documentation/devicetree/bindings/arm/msm/msm-id.txt b/Documentation/devicetree/bindings/arm/msm/msm-id.txt
new file mode 100644
index 0000000..b8c71d76
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm-id.txt
@@ -0,0 +1,18 @@
+* MSM-ID
+
+The qcom,msm-id entry specifies the MSM chipset, platform and hardware revision.
+It can optionally be an array of these to indicate multiple hardware that use
+the same device tree.  It is expected that the bootloader will use this
+information at boot-up to decide which device tree to use when given multiple
+device trees, some of which may not be compatible with the actual hardware.  It
+is the bootloader's responsibility to pass the correct device tree to the kernel.
+
+Format:
+
+It is expected that the qcom,msm-id entry be at the top level of the device
+tree structure.  The format of the entry is:
+
+   qcom,msm-id = <chipset_id, platform_id, rev_id> [, <c2, p2, r2> ...]
+
+Example:
+   qcom,msm-id = <126 15 0>;
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_ion.txt b/Documentation/devicetree/bindings/arm/msm/msm_ion.txt
new file mode 100644
index 0000000..5c6b804
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm_ion.txt
@@ -0,0 +1,50 @@
+ION Memory Manager (ION)
+
+ION is a memory manager that allows for sharing of buffers between different
+processes and between user space and kernel space. ION manages different
+memory spaces by separating the memory spaces into "heaps". Depending on the
+type of heap ION must reserve memory using the msm specific memory reservation
+bindings (see Documentation/devicetree/bindings/arm/msm/memory-reserve.txt).
+
+Required properties
+
+- compatible: "qcom,msm-ion"
+- reg: The ID of the ION heap.
+
+Optional properties
+
+- compatible: "qcom,msm-ion-reserve" This is required if memory is to be reserved
+  as specified by qcom,memory-reservation-size below.
+- qcom,heap-align: Alignment of start of the memory in the heap.
+- qcom,heap-adjacent: ID of heap this heap needs to be adjacent to.
+- qcom,memory-reservation-size: size of reserved memory for the ION heap.
+- qcom,memory-reservation-type: type of memory to be reserved
+(see memory-reserve.txt for information about memory reservations)
+
+Example:
+	qcom,ion {
+                 compatible = "qcom,msm-ion";
+                 #address-cells = <1>;
+                 #size-cells = <0>;
+
+                 qcom,ion-heap@30 { /* SYSTEM HEAP */
+                         reg = <30>;
+                 };
+
+                 qcom,ion-heap@8 { /* CP_MM HEAP */
+                         compatible = "qcom,msm-ion-reserve";
+                         reg = <8>;
+                         qcom,heap-align = <0x1000>;
+                         qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
+                         qcom,memory-reservation-size = <0x7800000>;
+                 };
+
+                 qcom,ion-heap@29 { /* FIRMWARE HEAP */
+                         compatible = "qcom,msm-ion-reserve";
+                         reg = <29>;
+                         qcom,heap-align = <0x20000>;
+                         qcom,heap-adjacent = <8>;
+                         qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
+                         qcom,memory-reservation-size = <0xA00000>;
+
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
new file mode 100644
index 0000000..5d1fafb
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -0,0 +1,34 @@
+MSM thermal driver (MSM_THERMAL)
+
+MSM_THERMAL is a kernel platform driver which regulates thermal conditions
+on the device during kernel boot. The goal of MSM_THERMAL is to prevent the
+temperature of the system from exceeding a thermal limit at which it cannot
+operate. Examples are CPU junction thermal limit, or POP memory thermal limit.
+The MSM_THERMAL driver polls the TSENS sensor hardware during boot, and
+reduces the maximum CPU frequency allowed in steps, to limit power/thermal
+output when a threshold temperature is crossed. It restores the maximum CPU
+frequency allowed in the same stepwise fashion when the threshold temperature
+(with hysteresis gap) is cleared.
+
+The devicetree representation of the MSM_THERMAL block should be:
+
+Required properties
+
+- compatible: "qcom,msm-thermal"
+- qcom,sensor-id: The id of the TSENS sensor polled for temperature.
+			Typically the sensor closest to CPU0.
+- qcom,poll-ms: Sampling interval to read sensor, in ms.
+- qcom,limit-temp: Threshold temperature to start stepping CPU down, in degC.
+- qcom,temp-hysteresis: Degrees below threshold temperature to step CPU up.
+- qcom,freq-step: Number of frequency steps to take on each CPU mitigation.
+
+Example:
+
+	qcom,msm-thermal {
+		compatible = "qcom,msm-thermal";
+		qcom,sensor-id = <0>;
+		qcom,poll-ms = <250>;
+		qcom,limit-temp = <60>;
+		qcom,temp-hysteresis = <10>;
+		qcom,freq-step = <2>;
+	};
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
new file mode 100644
index 0000000..c584073
--- /dev/null
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -0,0 +1,106 @@
+* 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
+- reg : physical base address and length of the register set(s) of the component
+- 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
+
+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.
+
+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
+
+Examples:
+
+1. Sinks
+	tmc_etr: tmc@fc322000 {
+		compatible = "arm,coresight-tmc";
+		reg = <0xfc322000 0x1000>;
+
+		coresight-id = <0>;
+		coresight-name = "coresight-tmc-etr";
+		coresight-nr-inports = <1>;
+		coresight-default-sink;
+	};
+
+	tpiu: tpiu@fc318000 {
+		compatible = "arm,coresight-tpiu";
+		reg = <0xfc318000 0x1000>;
+
+		coresight-id = <1>;
+		coresight-name = "coresight-tpiu";
+		coresight-nr-inports = <1>;
+	};
+
+2. Links
+	funnel_merg: funnel@fc31b000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0xfc31b000 0x1000>;
+
+		coresight-id = <4>;
+		coresight-name = "coresight-funnel-merg";
+		coresight-nr-inports = <2>;
+		coresight-outports = <0>;
+		coresight-child-list = <&tmc_etf>;
+		coresight-child-ports = <0>;
+	};
+
+	funnel_in0: funnel@fc319000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0xfc319000 0x1000>;
+
+		coresight-id = <5>;
+		coresight-name = "coresight-funnel-in0";
+		coresight-nr-inports = <8>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_merg>;
+		coresight-child-ports = <0>;
+	};
+
+3. Sources
+	stm: stm@fc321000 {
+		compatible = "arm,coresight-stm";
+		reg = <0xfc321000 0x1000>,
+		      <0xfa280000 0x180000>;
+
+		coresight-id = <9>;
+		coresight-name = "coresight-stm";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in1>;
+		coresight-child-ports = <7>;
+	};
+
+	etm0: etm@fc33c000 {
+		compatible = "arm,coresight-etm";
+		reg = <0xfc33c000 0x1000>;
+
+		coresight-id = <10>;
+		coresight-name = "coresight-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_kpss>;
+		coresight-child-ports = <0>;
+	};
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
new file mode 100644
index 0000000..6db1150
--- /dev/null
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -0,0 +1,140 @@
+Qualcomm mdss-dsi-panel
+
+mdss-dsi-panel is a dsi panel driver which supports panels that
+are compatable with MIPI display serial interface specification.
+
+Required properties:
+- compatible:				Must be "qcom,mdss-dsi-panel"
+- status:        			A string that has to be set to "okay/ok" to enable
+					the panel driver. By default this property will be
+					set to "disable". Will be set to "ok/okay" status
+					for specific platforms.
+- qcom,mdss-pan-res:			A two dimensional array that specifies the panel
+					resolution.
+- qcom,mdss-pan-bpp:			Specifies the panel bits per pixel. Default value is 24(rgb888).
+					18 = for rgb666
+					16 = for rgb565
+- qcom,mdss-panel-on-cmds:		An array of variable length that lists the init commands
+					of the panel. Each command will have the format specified
+					as below:
+					--> data type of the command
+					--> specifies whether this command packet is last.
+					--> virtual channel
+					--> Needs acknowledge from the panel or not.
+					--> wait time after the command is transmitter.
+					--> size of payload
+					--> payload.
+- qcom,mdss-panel-off-cmds:		An array of variable length that lists the panel off
+					commands. Each command will have the format specified
+					as below:
+					--> data type of the command
+					--> specifies whether this command packet is last.
+					--> virtual channel
+					--> Needs acknowledge from the panel or not.
+					--> wait time after the command is transmitter.
+					--> size of payload
+					--> payload.
+
+Required structure:
+- A qcom,mdss-dsi-panel node must be a child of an mdss-dsi controller node that links to
+    one of the two DSI controllers.
+
+
+Optional properties:
+- label:		        	A string used as a descriptive name of the panel
+- qcom,mdss-pan-porch-values:		An array of size 6 that specifies the panel blanking values.
+- qcom,mdss-pan-underflow-clr:		Specifies the controller settings for the panel underflow clear
+					settings. Default value is 0xff.
+- qcom,mdss-pan-bl-levels:		Specifies the backlight levels supported by the panel.
+					Default range is 1 to 255.
+
+- qcom,mdss-pan-dsi-mode:		Specifies the panel operating mode.
+					0 = enable video mode(default mode).
+					1 = enable command mode.
+- qcom,mdss-pan-dsi-h-pulse-mode:	Specifies the pulse mode option for the panel.
+					0 = Don't send hsa/he following vs/ve packet(default)
+					1 = Send hsa/he following vs/ve packet
+- qcom,mdss-pan-dsi-h-power-stop:	An Array of size 3 that specifies the power mode
+					during horizontal porch and sync periods of the panel.
+					0 = high speed mode(default mode).
+					1 = Low power mode for horizontal porches and sync pulse.
+- qcom,mdss-pan-dsi-bllp-power-stop:	An Array of size 2 that specifies the power mode
+					during blanking period and after EOF(end of frame).
+					0 = high speed mode(default mode).
+					1 = Low power mode during blanking and EOF.
+- qcom,mdss-pan-dsi-traffic-mode:	Specifies the panel traffic mode.
+					0 = non burst with sync pulses (default mode).
+					1 = non burst with sync start event.
+					2 = burst mode.
+- qcom,mdss-pan-dsi-dst-format:		Specifies the destination format.
+					0 = DSI_VIDEO_DST_FORMAT_RGB565.
+					1 = DSI_VIDEO_DST_FORMAT_RGB666.
+					2 = DSI_VIDEO_DST_FORMAT_RGB666_LOOSE.
+					3 = DSI_VIDEO_DST_FORMAT_RGB888 (Default format)
+					6 = DSI_CMD_DST_FORMAT_RGB565
+					7 = DSI_CMD_DST_FORMAT_RGB666
+					8 = DSI_CMD_DST_FORMAT_RGB888
+- qcom,mdss-pan-dsi-vc:			Specifies the virtual channel identefier.
+					0 = default value.
+- qcom,mdss-pan-dsi-rgb-swap:		Specifies the R, G and B channel ordering.
+					0 = DSI_RGB_SWAP_RGB (default value)
+					1 = DSI_RGB_SWAP_RBG
+					2 = DSI_RGB_SWAP_BGR
+					3 = DSI_RGB_SWAP_BRG
+					4 = DSI_RGB_SWAP_GRB
+					5 = DSI_RGB_SWAP_GBR
+- qcom,mdss-pan-dsi-data-lanes:		An array that specifies the data lanes enabled.
+					<1 1 0 0> = data lanes 1 and 2 are enabled.(default).
+- qcom,mdss-pan-dsi-t-clk:		An array that specifies the byte clock cycles
+					before and after each mode switch.
+- qcom,mdss-pan-dsi-stream:		Specifies the packet stream to be used.
+					0 = stream 0 (default)
+					1 = stream 1
+- qcom,mdss-pan-dsi-mdp-tr:		Specifies the trigger mechanism to be used for MDP path.
+					0 = no trigger
+					2 = Tear check signal line used for trigger
+					4 = Triggered by software (default mode)
+					6 = Software trigger and TE
+- qcom,mdss-pan-dsi-dma-tr:		Specifies the trigger mechanism to be used for DMA path.
+					0 = no trigger
+					2 = Tear check signal line used for trigger
+					4 = Triggered by software (default mode)
+					5 = Software trigger and start/end of frame trigger.
+					6 = Software trigger and TE
+- qcom,mdss-pan-dsi-frame-rate:		Specifies the frame rate for the panel.
+					60 = 60 frames per second (default)
+
+Note, if a given optional qcom,* binding is not present, then the driver will configure
+the default values specified.
+
+Example:
+	qcom,mdss_dsi@fd922800 {
+
+		qcom,mdss_dsi_sim_video {
+			compatible = "qcom,mdss-dsi-panel";
+			label = "simulator video mode dsi panel";
+			status = "disable";
+			qcom,mdss-pan-res = <640 480>;
+			qcom,mdss-pan-bpp = <24>;
+			qcom,mdss-pan-porch-values = <6 2 6 6 2 6>;
+			qcom,mdss-pan-underflow-clr = <0xff>;
+			qcom,mdss-pan-bl-levels = <1 15>;
+			qcom,mdss-pan-dsi-mode = <0>;
+			qcom,mdss-pan-dsi-h-pulse-mode = <1>;
+			qcom,mdss-pan-dsi-h-power-stop = <1 1 1>;
+			qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+			qcom,mdss-pan-dsi-traffic-mode = <0>;
+			qcom,mdss-pan-dsi-dst-format = <3>;
+			qcom,mdss-pan-dsi-vc = <0>;
+			qcom,mdss-pan-dsi-rgb-swap = <0>;
+			qcom,mdss-pan-dsi-data-lanes = <1 1 0 0>;
+			qcom,mdss-pan-dsi-t-clk = <0x24 0x03>;
+			qcom,mdss-pan-dsi-stream = <0>;
+			qcom,mdss-pan-dsi-mdp-tr = <0x04>;
+			qcom,mdss-pan-dsi-dma-tr = <0x04>;
+			qcom,mdss-pan-frame-rate = <60>;
+			qcom,panel-on-cmds = [32 01 00 00 00 02 00 00];
+			qcom,panel-off-cmds = [22 01 00 00 00 00 00];
+		};
+
+	};
diff --git a/Documentation/devicetree/bindings/gpio/gpio-msm.txt b/Documentation/devicetree/bindings/gpio/gpio-msm.txt
new file mode 100644
index 0000000..359d700
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-msm.txt
@@ -0,0 +1,39 @@
+MSM GPIO controller bindings
+
+Required properties:
+- compatible:
+  - "qcom,msm-gpio" for MSM controllers
+- #gpio-cells : Should be two.
+  - first cell is the pin number
+  - second cell is used to specify optional parameters (unused)
+- gpio-controller : Marks the device node as a GPIO controller.
+- #interrupt-cells : Should be 2.
+- interrupt-controller: Mark the device node as an interrupt controller
+
+Example:
+
+	msmgpio: gpio@fd510000 {
+		compatible = "qcom,msm-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		reg = <0xfd510000 0x4000>;
+	};
+
+To specify gpios for a device:
+
+	device1@f991f000 {
+		compatible = "qcom,msm-device-v1";
+		reg = <0xf991f000 0x1000>;
+		gpios = <&msmgpio 45 0>;
+		cs-gpios = <&msmgpio 46 0>;
+	};
+
+45, 46 - gpio numbers.
+The driver for device1 can call of_get_gpio() to extract the
+gpio45. In order to extract gpio46, the driver needs to call
+of_get_named_gpio with "cs-gpios" as the name parameter.
+Please refer to the file: include/linux/of_gpio.h for the
+complete list of APIs the driver can use to extract gpio
+information from the device tree.
diff --git a/Documentation/devicetree/bindings/gpio/qpnp-pin.txt b/Documentation/devicetree/bindings/gpio/qpnp-pin.txt
index c58e073..31c3bc2 100644
--- a/Documentation/devicetree/bindings/gpio/qpnp-pin.txt
+++ b/Documentation/devicetree/bindings/gpio/qpnp-pin.txt
@@ -94,7 +94,7 @@
 			QPNP_PIN_OUT_STRENGTH_MED  = 2, (GPIO)
 			QPNP_PIN_OUT_STRENGTH_HIGH = 3, (GPIO)
 
-  - qcom,select:	select a function for the pin. Certain pins
+  - qcom,src-select:	select a function for the pin. Certain pins
 			can be paired (shorted) with each other. Some gpio pins
 			can act as alternate functions.
 			In the context of gpio, this acts as a source select.
diff --git a/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt b/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt
new file mode 100644
index 0000000..d50a21c
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt
@@ -0,0 +1,40 @@
+Adreno Power Levels
+
+The Adreno GPU definition should include a variable number of power levels
+defining the GPU and bus frequencies for the levels that the GPU can operate at.
+
+Required properties:
+
+- compatible:	The compatible name for the object (qcom,gpu-pwrlevels)
+
+Each powerlevel definition is as follows:
+
+- reg:              Index of the power level (lower is considered higher
+		    performance)
+- qcom,gpu-freq:    The GPU frequency for the power level (in HZ)
+- qcom,bus-freq:    An index representing the bus scaling usecase appropriate
+		    for the power level
+- qcom,io-fraction: A number indicating the fraction of the CPU I/O busy that
+		    this operating point should represent.
+
+Sample usage:
+
+qcom,kgsl-3d0@fdb00000 {
+	...
+	qcom,gpu-pwrlevels {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		compatible = "qcom,gpu-pwrlevels";
+
+		qcom,gpu-pwrlevel@0 {
+			reg = <0>;
+			qcom,gpu-freq = <5000000000>;
+			qcom,bus-freq = <3>;
+			qcom,io_fraction = <0>;
+		};
+	};
+
+	...
+};
+
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
new file mode 100644
index 0000000..16925fb
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -0,0 +1,159 @@
+Qualcomm GPU
+
+Qualcomm Adreno GPU
+
+Required properties:
+- label:		A string used as a descriptive name for the device.
+- compatible:		Must be "qcom,kgsl-3d0" and "qcom,kgsl-3d"
+- reg:			Specifies the base address and address size for this device.
+- interrupts:		Interrupt mapping for GPU IRQ.
+- interrupt-names:	String property to describe the name of the interrupt.
+- qcom,id:		An integer used as an identification number for the device.
+
+- qcom,clk-map:		A bit map value for clocks controlled by kgsl.
+				KGSL_CLK_SRC    0x00000001
+				KGSL_CLK_CORE   0x00000002
+				KGSL_CLK_IFACE  0x00000004
+				KGSL_CLK_MEM    0x00000008
+				KGSL_CLK_MEM_IFACE 0x00000010
+				KGSL_CLK_AXI    0x00000020
+
+Bus Scaling Data:
+- qcom,grp3d-vectors:	A series of 4 cell properties, format of which is:
+						<src dst ab ib>, <src dst ab ib>, // For Bus Scaling Usecase 1
+						<src dst ab ib>, <src dst ab ib>, // For Bus Scaling Usecase 2
+						<..  ..  .. ..>, <..  ..  .. ..>; // For Bus Scaling Usecase n
+						This property is a series of all vectors for all Bus Scaling Usecases.
+						Each set of vectors for each usecase describes bandwidth votes for a combination
+						of src/dst ports.  The driver will set the desired use case based on the selected
+						power level and the desired bandwidth vote will be registered for the port pairs.
+					Current values of src are:
+						0 = MSM_BUS_MASTER_GRAPHICS_3D
+						1 = MSM_BUS_MASTER_GRAPHICS_3D_PORT1
+						2 = MSM_BUS_MASTER_V_OCMEM_GFX3D
+					Current values of dst are:
+						0 = MSM_BUS_SLAVE_EBI_CH0
+						1 = MSM_BUS_SLAVE_OCMEM
+					ab: Represents aggregated bandwidth. This value is 0 for Graphics.
+					ib: Represents instantaneous bandwidth. This value has a range <0 8000 MB/s>
+- qcom,grp3d-num-vectors-per-usecase:	This represents the number of vectors in each Bus Scaling Usecase.
+- qcom,grp3d-num-bus-scale-usecases:	This is the the number of Bus Scaling use cases defined in the vectors property
+
+GDSC Oxili Regulators:
+- vddcx-supply:			Phandle for vddcx regulator device node.
+- vdd-supply:			Phandle for vdd regulator device node.
+
+IOMMU Data:
+- iommu:			Phandle for the KGSL IOMMU device node
+
+GPU Power levels:
+- qcom,gpu-pwrlevels:		Container for the GPU Power Levels (see
+				adreno-pwrlevels.txt)
+
+DCVS Core info
+- qcom,dcvs-core-info		Container for the DCVS core info (see
+				dcvs-core-info.txt)
+
+Optional Properties:
+- qcom,initial-powerlevel: This value indicates which qcom,gpu-pwrlevel should be used at start time
+			   and when coming back out of resume
+- qcom,idle-timeout:	   This property represents the time in microseconds for idle timeout.
+- qcom,nap-allowed:	   Boolean. <0> or <1> to disable/enable nap.
+- qcom,chipid:		   If it exists this property is used to replace
+			   the chip identification read from the GPU hardware.
+			   This is used to override faulty hardware readings.
+
+Example of A330 GPU in MSM8974:
+
+/ {
+	qcom,kgsl-3d0@fdb00000 {
+		label = "kgsl-3d0";
+		compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
+		reg = <0xfdb00000 0x20000>;
+		reg-names = "kgsl_3d0_reg_memory";
+		interrupts = <0 33 0>;
+		interrupt-names = "kgsl_3d0_irq";
+		qcom,id = <0>;
+
+		qcom,chipid = <0x03030000>;
+
+		/* Power Settings */
+
+		qcom,initial-pwrlevel = <1>;
+		qcom,idle-timeout = <83>; //<HZ/12>
+		qcom,nap-allowed = <1>;
+		qcom,clk-map = <0x00000016>; //KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE
+
+		/* Bus Scale Settings */
+		qcom,grp3d-vectors = <0 0 0 0>, <2 1 0 0>,
+				<0 0 0 2000>, <2 1 0 3000>,
+				<0 0 0 4000>, <2 1 0 5000>,
+				<0 0 0 6400>, <2 1 0 7600>;
+		qcom,grp3d-num-vectors-per-usecase = <2>;
+		qcom,grp3d-num-bus-scale-usecases = <4>;
+
+		/* GDSC oxili regulators */
+		vddcx-supply = <&gdsc_oxili_cx>;
+		vdd-supply = <&gdsc_oxili_gx>;
+
+		/* IOMMU Data */
+		iommu = <&kgsl>;
+
+		qcom,gpu-pwrlevels {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			compatible = "qcom,gpu-pwrlevels";
+
+			qcom,gpu-pwrlevel@0 {
+				reg = <0>;
+				qcom,gpu-freq = <5000000000>;
+				qcom,bus-freq = <3>;
+				qcom,io-fraction = <0>;
+			};
+		};
+
+		qcom,dcvs-core-info {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			compatible = "qcom,dcvs-core-info";
+
+			qcom,core-max-time-us = <100000>;
+			qcom,algo-slack-time-us = <39000>;
+			qcom,algo-disable-pc-threshold = <86000>;
+			qcom,algo-ss-window-size = <1000000>;
+			qcom,algo-ss-util-pct = <95>;
+			qcom,algo-em-max-util-pct = <97>;
+			qcom,algo-ss-iobusy-conv = <100>;
+
+			qcom,dcvs-freq@0 {
+				reg = <0>;
+				qcom,freq = <0>;
+				qcom,idle-energy = <0>;
+				qcom,active-energy = <333932>;
+			};
+
+			qcom,dcvs-freq@1 {
+				reg = <1>;
+				qcom,freq = <0>;
+				qcom,idle-energy = <0>;
+				qcom,active-energy = <497532>;
+			};
+
+			qcom,dcvs-freq@2 {
+				reg = <2>;
+				qcom,freq = <0>;
+				qcom,idle-energy = <0>;
+				qcom,active-energy = <707610>;
+			};
+
+			qcom,dcvs-freq@3 {
+				reg = <3>;
+				qcom,freq = <0>;
+				qcom,idle-energy = <0>;
+				qcom,active-energy = <844545>;
+			};
+		};
+	};
+};
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
new file mode 100644
index 0000000..33d5cc1
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
@@ -0,0 +1,102 @@
+Qualcomm's QPNP PMIC current ADC driver
+
+QPNP PMIC current ADC (IADC) provides interface to clients to read
+current. A 16 bit ADC is used for current measurements. There are multiple
+peripherals to the IADC and the scope of the driver is to provide interface
+for the USR peripheral of the IADC.
+
+IADC node
+
+Required properties:
+- compatible : should be "qcom,qpnp-iadc" for Current ADC driver.
+- reg : offset and length of the PMIC Aribter register map.
+- interrupts : The USR bank peripheral IADC interrupt.
+- qcom,adc-bit-resolution : Bit resolution of the ADC.
+- qcom,adc-vdd-reference : Voltage reference used by the ADC.
+- qcom,rsense : Internal rsense resistor used for current measurements.
+
+Channel node
+NOTE: Atleast one Channel node is required.
+
+Required properties:
+- label : Channel name used for sysfs entry.
+- qcom,channel-num : Channel number associated to the AMUX input.
+- qcom,decimation : Sampling rate to use for the individual channel measurement.
+		    Select from the following unsigned int.
+		    0 : 512
+		    1 : 1K
+		    2 : 2K
+		    3 : 4K
+- qcom,pre-div-channel-scaling : Pre-div used for the channel before the signal
+				 is being measured.
+- qcom,calibration-type : Calibration point values vary with temperature.
+			  For improved accuracy fresh gain and offset point values
+			  can be used for calibration. Reading fresh values for ever
+			  read affects the reading time. Application can use the historic
+			  values used from the trim register values.
+			  Select from the following strings.
+			  "absolute" : Uses TRIM gain and offset values for calibration.
+			  "ratiometric" : Calculate the gain and offset calibration value when an ADC
+			  	    request is issued.
+- qcom,scale-function : Scaling fuction used to convert raw ADC code to units specific to
+			a given channel.
+			Select from the following unsigned int.
+			0 : Default scaling to convert raw adc code to voltage.
+			1 : Conversion to temperature based on btm parameters.
+			2 : Returns result in milli degree's Centigrade.
+			3 : Returns current across 0.1 ohm resistor.
+			4 : Returns XO thermistor voltage in degree's Centigrade.
+- qcom,hw-settle-time : Settling period for the channel before ADC read.
+			Select from the following unsigned int.
+			0 : 0us
+			1 : 100us
+			2 : 200us
+			3 : 300us
+			4 : 400us
+			5 : 500us
+			6 : 600us
+			7 : 700us
+			8 : 800us
+			9 : 900us
+			0xa : 1ms
+			0xb : 2ms
+			0xc : 4ms
+			0xd : 6ms
+			0xe : 8ms
+			0xf : 10ms
+- qcom,fast-avg-setup : Average number of samples to be used for measurement. Fast averaging
+			provides the option to obtain a single measurement from the ADC that
+			is an average of multiple samples. The value selected is 2^(value)
+			Select from the following unsigned int.
+			0 : 1
+			1 : 2
+			2 : 4
+			3 : 8
+			4 : 16
+			5 : 32
+			6 : 64
+			7 : 128
+			8 : 256
+
+Example:
+	/* Main Node */
+	qcom,iadc@3200 {
+                        compatible = "qcom,qpnp-iadc";
+                        reg = <0x3200 0x100>;
+                        interrupts = <0 0x36 0>;
+                        qcom,adc-bit-resolution = <16>;
+                        qcom,adc-vdd-reference = <1800>;
+			qcom,rsense = <1500>;
+
+			/* Channel Node */
+                        chan@0 = {
+                                label = "rsense";
+                                qcom,channel-num = <0>;
+                                qcom,decimation = <0>;
+                                qcom,pre-div-channel-scaling = <20>;
+                                qcom,calibration-type = "fresh";
+                                qcom,scale-function = <0>;
+                                qcom,hw-settle-time = <0>;
+                                qcom,fast-avg-setup = <0>;
+                        };
+	};
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-server.txt b/Documentation/devicetree/bindings/media/video/msm-cam-server.txt
new file mode 100644
index 0000000..2b6f513
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-server.txt
@@ -0,0 +1,11 @@
+* Qualcomm MSM Camera Server
+
+Required properties:
+- compatible :
+    - "qcom,cam_server"
+
+Example:
+
+   qcom,cam_server {
+       compatible = "qcom,cam_server";
+   };
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
new file mode 100644
index 0000000..75916e5
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -0,0 +1,23 @@
+* Qualcomm MSM CCI
+
+Required properties:
+- cell-index: cci hardware core index
+- compatible :
+    - "qcom,cci"
+- reg : offset and length of the register set for the device
+    for the cci operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the cci interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+  property defined.
+
+Example:
+
+   qcom,cci@0xfda0c000 {
+       cell-index = <0>;
+       compatible = "qcom,cci";
+       reg = <0xfda0c000 0x300>;
+       reg-names = "cci";
+       interrupts = <0 50 0>;
+       interrupt-names = "cci";
+   };
diff --git a/Documentation/devicetree/bindings/media/video/msm-cpp.txt b/Documentation/devicetree/bindings/media/video/msm-cpp.txt
new file mode 100644
index 0000000..5cf0154
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-cpp.txt
@@ -0,0 +1,25 @@
+* Qualcomm MSM CPP
+
+Required properties:
+- cell-index: cpp hardware core index
+- compatible :
+    - "qcom,cpp"
+- reg : offset and length of the register set for the device
+    for the cpp operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the cpp interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+  property defined.
+- vdd-supply: phandle to GDSC regulator controlling VFE & CPP core.
+
+Example:
+
+   qcom,cpp@0xfda04000 {
+       cell-index = <0>;
+       compatible = "qcom,cpp";
+       reg = <0xfda04000 0x100>;
+       reg-names = "cpp";
+       interrupts = <0 49 0>;
+       interrupt-names = "cpp";
+       vdd-supply = <&gdsc_vfe>;
+   };
diff --git a/Documentation/devicetree/bindings/media/video/msm-csi-phy.txt b/Documentation/devicetree/bindings/media/video/msm-csi-phy.txt
new file mode 100644
index 0000000..90bdbda
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-csi-phy.txt
@@ -0,0 +1,23 @@
+* Qualcomm MSM CSI Phy
+
+Required properties:
+- cell-index: csi phy hardware core index
+- compatible :
+    - "qcom,csiphy"
+- reg : offset and length of the register set for the device
+    for the csiphy operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the csiphy interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+  property defined.
+
+Example:
+
+   qcom,csiphy@fda0ac00 {
+       cell-index = <0>;
+       compatible = "qcom,csiphy";
+       reg = <0xfda0ac00 0x200>;
+       reg-names = "csiphy";
+       interrupts = <0 78 0>;
+       interrupt-names = "csiphy";
+   };
diff --git a/Documentation/devicetree/bindings/media/video/msm-csid.txt b/Documentation/devicetree/bindings/media/video/msm-csid.txt
new file mode 100644
index 0000000..76a2825
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-csid.txt
@@ -0,0 +1,23 @@
+* Qualcomm MSM CSID
+
+Required properties:
+- cell-index: csid hardware core index
+- compatible :
+    - "qcom,csid"
+- reg : offset and length of the register set for the device
+    for the csid operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the csid interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+  property defined.
+
+Example:
+
+   qcom,csid@fda08000 {
+       cell-index = <0>;
+       compatible = "qcom,csid";
+       reg = <0xfda08000 0x200>;
+       reg-names = "csid";
+       interrupts = <0 51 0>;
+       interrupt-names = "csiphy";
+   };
diff --git a/Documentation/devicetree/bindings/media/video/msm-irqrouter.txt b/Documentation/devicetree/bindings/media/video/msm-irqrouter.txt
new file mode 100644
index 0000000..63fb7d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-irqrouter.txt
@@ -0,0 +1,18 @@
+* Qualcomm MSM IRQ Router
+
+Required properties:
+- cell-index: irq router hardware core index
+- compatible :
+    - "qcom,irqrouter"
+- reg : offset and length of the register set for the device
+    for the irqrouter operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+
+Example:
+
+   qcom,irqrouter@0xfda0c000 {
+       cell-index = <0>;
+       compatible = "qcom,irqrouter";
+       reg = <0xfda00000 0x100>;
+       reg-names = "irqrouter";
+   };
diff --git a/Documentation/devicetree/bindings/media/video/msm-ispif.txt b/Documentation/devicetree/bindings/media/video/msm-ispif.txt
new file mode 100644
index 0000000..ff33b17
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-ispif.txt
@@ -0,0 +1,23 @@
+* Qualcomm MSM ISPIF
+
+Required properties:
+- cell-index: ispif hardware core index
+- compatible :
+    - "qcom,ispif"
+- reg : offset and length of the register set for the device
+    for the ispif operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the ispif interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+  property defined.
+
+Example:
+
+   qcom,ispif@0xfda0a000 {
+       cell-index = <0>;
+       compatible = "qcom,ispif";
+       reg = <0xfda0a000 0x300>;
+       reg-names = "ispif";
+       interrupts = <0 55 0>;
+       interrupt-names = "ispif";
+   };
diff --git a/Documentation/devicetree/bindings/media/video/msm-jpeg.txt b/Documentation/devicetree/bindings/media/video/msm-jpeg.txt
new file mode 100644
index 0000000..41e0b3f
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-jpeg.txt
@@ -0,0 +1,25 @@
+* Qualcomm MSM JPEG
+
+Required properties:
+- cell-index: jpeg hardware core index
+- compatible :
+    - "qcom,jpeg"
+- reg : offset and length of the register set for the device
+    for the jpeg operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the jpeg interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+  property defined.
+- vdd-supply: phandle to GDSC regulator controlling JPEG core.
+
+Example:
+
+   qcom,jpeg@0xfda20000 {
+       cell-index = <0>;
+       compatible = "qcom,jpeg";
+       reg = <0xfda20000 0x400>;
+       reg-names = "jpeg";
+       interrupts = <0 60 0>;
+       interrupt-names = "jpeg";
+       vdd-supply = <&gdsc_jpeg>;
+   };
diff --git a/Documentation/devicetree/bindings/media/video/msm-vfe.txt b/Documentation/devicetree/bindings/media/video/msm-vfe.txt
new file mode 100644
index 0000000..7a70cac
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-vfe.txt
@@ -0,0 +1,25 @@
+* Qualcomm MSM VFE
+
+Required properties:
+- cell-index: vfe hardware core index
+- compatible :
+    - "qcom,vfe"
+- reg : offset and length of the register set for the device
+    for the vfe operating in compatible mode.
+- reg-names : should specify relevant names to each reg property defined.
+- interrupts : should contain the vfe interrupt.
+- interrupt-names : should specify relevant names to each interrupts
+  property defined.
+- vdd-supply: phandle to GDSC regulator controlling VFE core.
+
+Example:
+
+   qcom,vfe@0xfda10000 {
+       cell-index = <0>;
+       compatible = "qcom,vfe";
+       reg = <0xfda10000 0x1000>;
+       reg-names = "vfe";
+       interrupts = <0 58 0>;
+       interrupt-names = "vfe";
+       vdd-supply = <&gdsc_vfe>;
+   };
diff --git a/Documentation/devicetree/bindings/ocmem/msm-ocmem.txt b/Documentation/devicetree/bindings/ocmem/msm-ocmem.txt
index 1549f10..e212aca 100644
--- a/Documentation/devicetree/bindings/ocmem/msm-ocmem.txt
+++ b/Documentation/devicetree/bindings/ocmem/msm-ocmem.txt
@@ -18,6 +18,7 @@
 		    "ocmem_irq" corresponds to OCMEM Error Interrupt.
 		    "dm_irq" corresponds to DM Interrupt.
 - qcom,ocmem-num-regions: The number of OCMEM hardware memory regions.
+- qcom,resource-type: The hardware resource type of the OCMEM core.
 
 In addition to the information on the OCMEM core, the
 device tree contains additional information describing partitions
@@ -51,6 +52,7 @@
 		interrupts = <0 76 0 0 77 0>;
 		interrupt-names = "ocmem_irq", "dm_irq";
 		qcom,ocmem-num-regions = <0x3>;
+		qcom,resource-type = <0x706d636f>
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges = <0x0 0xfec00000 0x180000>;
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 95e7f88..32c9c35 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -7,11 +7,12 @@
 
 Required properties:
 - compatible:	      Must be "qcom,pil-q6v5-mss"
-- reg:		      Four pairs of physical base addresses and region sizes of
+- reg:		      Five pairs of physical base addresses and region sizes of
 		      memory mapped registers. The first region corresponds to
 		      QDSP6SS_PUB, the second to the bus port halt register
-		      base, the third to the MSS_RELAY_MSG_BUFFER base, and the
-		      fourth to the MSS_RESTART register.
+		      base, the third to the MSS_RELAY_MSG_BUFFER base, the
+		      fourth to the MSS_RESTART register, and the fifth to the
+		      MSS_CLAMP_IO register.
 - vdd_mss-supply:     Reference to the regulator that supplies the processor.
 - qcom,firmware-name: Base name of the firmware image. Ex. "mdsp"
 - qcom,pil-self-auth: <0> if the hardware does not require self-authenticating
@@ -24,7 +25,8 @@
 		reg = <0xfc880000 0x100>,
 		      <0xfd485000 0x400>,
 		      <0xfc820000 0x020>,
-		      <0xfc401680 0x004>;
+		      <0xfc401680 0x004>,
+		      <0xfc980008 0x004>;
 		vdd_mss-supply = <&pm8841_s3>;
 
 		qcom,firmware-name = "mba";
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-clkdiv.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-clkdiv.txt
new file mode 100644
index 0000000..67303eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-clkdiv.txt
@@ -0,0 +1,43 @@
+* qpnp-clkdiv
+
+clkdiv configures the clock frequency of a set of outputs on the PMIC.
+These clocks are typically wired through alternate functions on
+gpio pins.
+
+Required properties :
+ - reg : The address and size of the peripheral. Size should be 0x1000, and the
+         address may vary.
+ - qcom,cxo-freq : The frequency of the cxo clock in Hz.
+
+Optional properties :
+ - qcom,cxo-div : Integer to divide the CXO clock by when constructing the
+		  output frequency. Please see the definitions in
+		  include/linux/qpnp-clkdiv.h to choose the appropriate value.
+ - qcom,enable : 0 == disable clock output
+		 1 == enable clock output.
+
+Note: if an optional property is not specified, no device configuration will
+      occur at probe time.
+
+Client required properties :
+ - <consumer name>-clk : A phandle to the corresponding divclk device. The
+			      consumer name refers to the name that will be
+			      passed to qpnp_clkdiv_get(), and allows for a
+			      client specific name to be associated with each
+			      divclk.
+
+Clkdiv device example :
+
+...
+	pm8941_clkdiv1: clkdiv@5b00 {
+		reg = <0x5b00 0x1000>;
+		qcom,cxo-freq = <19200000>;
+		qcom,cxo-div = <1>;
+		qcom,enable = <1>;
+	};
+
+Client device example :
+...
+	client {
+		my-clk = &pm8941_clkdiv1;
+	};
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
index 2e7f9c3..46b39ec 100644
--- a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
@@ -2,38 +2,93 @@
 
 The qpnp-power-on is a driver which supports the power-on(PON)
 peripheral on Qualcomm PMICs. The supported functionality includes
-power on/off reason, power-key press/release detection and other PON
-features. This peripheral is connected to the host processor via the SPMI
-interface.
+power on/off reason, key press/release detection, PMIC reset configurations
+and other PON specifc features. The PON module supports multiple physical
+power-on (KPDPWR_N, CBLPWR) and reset (KPDPWR_N, RESIN, KPDPWR+RESIN) sources.
+This peripheral is connected to the host processor via the SPMI interface.
 
 Required properties:
 - compatible:	Must be "qcom,qpnp-power-on"
 - reg:		Specifies the SPMI address and size for this PON (power-on) peripheral
-- interrupts:	Specifies the interrupt associated with the power-key.
+- interrupts:	Specifies the interrupt associated with PON.
 
 Optional properties:
-- qcom,pon-key-enable:		Enable power-key detection. It enables monitoring
-				of the KPDPWR_N line (connected to the power-key).
-- qcom,pon-key-dbc-delay:	The debouce delay for the power-key interrupt
+- qcom,pon-dbc-delay:		The debouce delay for the power-key interrupt
 				specifed in us. The value ranges from 2 seconds
 				to 1/64 of a second. Possible values are -
 				- 2, 1, 1/2, 1/4, 1/8, 1/16, 1/32, 1/64
 				- Intermediate value is rounded down to the
 				nearest valid value.
-- qcom,pon-key-pull-up:		The intial state of the KPDPWR_N pin
-				(connected to the power-key)
+- qcom,pon_1 ...pon_n		These represent the child nodes which describe
+				the properties (reset, key) for each of the pon
+				reset source. All the child nodes are optional,
+				if none of them are specified the driver fails
+				to register.
+
+All the below properties are in the sub-node section (properties of the child
+node).
+
+- qcom,pull-up:			The initial state of the reset pin under
+				consideration.
 				0 = No pull-up
 				1 = pull-up enabled
-
-If any of the above optional property is not defined, the driver will continue
-with the default hardware state.
+				This property is optional and is set to '0'
+				if not specified.
+- qcom,pon-type			The type of PON/RESET source. The driver
+				currently supports KPDPWR(0) and RESIN(1)
+				pon/reset sources. This property must be
+				specified.
+- qcom,support-reset		Indicates if this PON source supports
+				reset functionality.
+				0 = Not supported
+				1 = Supported
+				This property is optional and is set to '0'
+				if not specified.
+- qcom,s1-timer			The debouce timer for the BARK interrupt for
+				that reset source. Value is specified in ms.
+				Supported values are -
+				- 0, 32, 56, 80, 128, 184, 272, 408, 608, 904
+				  1352, 2048, 3072, 4480, 6720, 10256
+				This property must be specified only if
+				'support-reset' is set to 1.
+- qcom,s2-timer			The debouce timer for the S2 reset specified
+				in ms. On the expiry of this timer, the PMIC
+				executes the reset sequence. Supoprted values -
+				- 0, 10, 50, 100, 250, 500, 1000, 2000
+				This property is required only if
+				'support-reset' is set to 1.
+- qcom,s2-type			The type of reset associated with this source.
+				The supported resets are -
+				SOFT(0), WARM(1), SHUTDOWN(4), HARD(7)
+				This property is required only if
+				'support-reset' is set to 1.
+- linux,code			The input key-code associated with the reset source.
+				The reset source in its default configuration can be
+				used to support standard keys. This property is optional.
 
 Example:
 	qcom,power-on@800 {
 		compatible = "qcom,qpnp-power-on";
 		reg = <0x800 0x100>;
-		interrupts = <0x0 0x8 0x1>;
-		qcom,pon-key-enable= <true>;
-		qcom,pon-key-pull-up = <true>;
-		qcom,pon-key-dbc-delay = <15625>;
+		interrupts = <0x0 0x8 0x0>,
+			     <0x0 0x8 0x1>,
+			     <0x0 0x8 0x4>;
+		interrupt-names = "kpdpwr", "resin", "resin-bark";
+		qcom,pon-dbc-delay = <15625>;
+
+		qcom,pon_1 {
+			qcom,pon-type = <0>;
+			qcom,pull-up = <1>;
+			linux,code = <116>;
+		};
+
+		qcom,pon_2 {
+			qcom,pon-type = <1>;
+			qcom,support-reset = <1>;
+			qcom,pull-up = <1>;
+			qcom,s1-timer = <3072>;
+			qcom,s2-timer = <2000>;
+			qcom,s2-type = <1>;
+			linux,code = <114>;
+		};
 	}
diff --git a/Documentation/devicetree/bindings/pwm/qpnp-pwm.txt b/Documentation/devicetree/bindings/pwm/qpnp-pwm.txt
new file mode 100644
index 0000000..83ce3f8
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/qpnp-pwm.txt
@@ -0,0 +1,160 @@
+Qualcomm QPNP PWM/LPG controller
+
+qpnp-pwm driver supports Pulse Width Module (PWM) functionality. PWM feature is
+used in range of applications such as varying Display brightness, LED dimming,
+etc. The Qualcomm PMICs have a physical device called Light Pulse Generator
+(LPG). In addition to support PWM functionality, the LPG module provides
+a rich set of user defined PWM pattern configurations, such as sawtooth, linear
+up, linear down, triangular patterns etc. The PWM patterns are used in
+applications such as charger driver where the driver uses these patterns
+to indicate various states of charging.
+
+Required device bindings:
+- compatible:		should be "qcom,qpnp-pwm"
+- reg:			Offset and length of the controller's LPG channel register,
+			and LPG look-up table (LUT). The LPG look-up table is a
+			contiguous address space that is populated with PWM values.
+			The size of PWM value is 9 bit and the size of each
+			entry of the table is 8 bit. Thus, two entries are used
+			to fill each PWM value. The lower entry is used for PWM
+			LSB byte and higher entry is used for PWM MSB bit.
+- reg-names:		Names for the above registers.
+			"qpnp-lpg-channel-base" = physical base address of the
+			controller's LPG channel register.
+			"qpnp-lpg-lut-base" = physical base address of LPG LUT.
+- qcom,channel-id:	channel Id for the PWM.
+
+Optional device bindings:
+- qcom,channel-owner:	A string value to supply owner information.
+- qcom,mode-select:	0 = PWM mode
+			1 = LPG mode
+If this binding is specified along with the required bindings of PWM/LPG then
+in addition to configure PWM/LPG the qpnp-pwm driver also enables the feature
+at the probe time. In the case where the binding is not specified the qpnp-pwm
+driver does not enable the feature. Also, it is considered an error to specify
+a particular mode using this binding but not the respective feature subnode.
+
+All PWM devices support both PWM and LPG features within the same device.
+To support each feature, there are some required and optional bindings passed
+through device tree.
+
+The PWM device can enable one feature (either PWM or LPG) at any given time.
+Therefore, the qpnp-pwm driver applies the last PWM or LPG feature configuration
+and enables that feature.
+
+Required bindings to support PWM feature:
+- qcom,period:	PWM period time in microseconds.
+- qcom,duty:	PWM duty time in microseconds.
+- label:	"pwm"
+
+Required bindings to support LPG feature:
+The following bindings are needed to configure LPG mode, where a list of
+duty cycle percentages is populated. The size of the list cannot exceed
+the size of the LPG look-up table.
+
+- qcom,period:			PWM period time in microseconds.
+- qcom,duty-percents:		List of entries for look-up table
+- cell-index:			Index of look-up table that should be used to start
+				filling up the duty-pct list. start-idx + size of list
+				cannot exceed the size of look-up table.
+- label:			"lpg"
+
+
+Optional bindings to support LPG feature:
+- qcom,ramp-step-duration:	Time (in ms) to wait before loading next entry of LUT
+- qcom,lpg-lut-pause-hi:	Time (in ms) to wait once pattern reaches to hi
+				index.
+- qcom,lpg-lut-pause-lo:	Time (in ms) to wait once pattern reaches to lo
+				index.
+- qcom,lpg-lut-ramp-direction:	1 = Start the pattern from lo index to hi index.
+				0 = Start the pattern from hi index to lo index.
+- qcom,lpg-lut-pattern-repeat:	1 = Repeat the pattern after the pause once it
+				reaches to last duty cycle.
+				0 = Do not repeat the pattern.
+- qcom,lpg-lut-ramp-toggle:	1 = Toggle the direction of the pattern.
+				0 = Do not toggle the direction.
+- qcom,lpg-lut-enable-pause-hi:	1 = Enable pause time at hi index.
+				0 = Disable pause time at hi index.
+- qcom,lpg-lut-enable-pause-lo:	1 = Enable pause time at lo index.
+				0 = Disable pause time at lo index.
+
+
+Example:
+        qcom,spmi@fc4c0000 {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                qcom,pm8941@1 {
+                        spmi-slave-container;
+                        reg = <0x1>;
+                        #address-cells = <1>;
+                        #size-cells = <1>;
+
+                        pwm@b100 {
+                                #address-cells = <1>;
+                                #size-cells = <1>;
+                                compatible = "qcom,qpnp-pwm";
+                                reg = <0xb100 0x100>,
+                                      <0xb040 0x80>;
+				reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+                                qcom,channel-id = <0>;
+				status = "okay";
+                        };
+
+                        pwm@b200 {
+                                #address-cells = <1>;
+                                #size-cells = <1>;
+                                compatible = "qcom,qpnp-pwm";
+                                reg = <0xb200 0x100>,
+                                      <0xb040 0x80>;
+				reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+                                qcom,channel-id = <1>;
+                                qcom,period = <6000000>;
+				status = "okay";
+				qcom,pwm {
+					qcom,duty = <4000000>;
+					label = "pwm";
+				};
+                        };
+
+                        pwm@b500 {
+                                #address-cells = <1>;
+                                #size-cells = <1>;
+                                compatible = "qcom,qpnp-pwm";
+                                reg = <0xb500 0x100>,
+                                      <0xb040 0x80>;
+				reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
+                                qcom,channel-id = <4>;
+                                qcom,period = <6000000>;
+				qcom,mode-select = <0>;
+				qcom,channel-owner = "RGB-led";
+				status = "okay";
+
+				qcom,pwm {
+					qcom,duty = <4000000>;
+					label = "pwm";
+				};
+
+				qcom,lpg {
+					qcom,duty-percents = <1 14 28 42 56 84 100
+							100 84 56 42 28 14 1>;
+					cell-index = <0>;
+					qcom,ramp-step-duration = <20>;
+					label = "lpg";
+				};
+                        };
+                };
+        };
+
+There are couple of ways to configure PWM device channels as shown in above
+example,
+1. The PWM device channel #0 is configured with only required device bindings.
+In this case, the qpnp-pwm driver does not configure any mode by default.
+
+2. The qpnp-pwm driver configures PWM device channel #1 with PWM feature
+configuration, but does not enable the channel since "qcom,mode-select" binding
+is not specified in the devicetree.
+
+3. Both the PWM and LPG configurations are provided for PWM device channel #4.
+The qpnp-pwm driver configures both the modes, but enables PWM mode at the probe
+time. It also sets the channel owner information for the channel.
diff --git a/Documentation/devicetree/bindings/qdsp/adsp-loader.txt b/Documentation/devicetree/bindings/qdsp/adsp-loader.txt
new file mode 100644
index 0000000..74e58dc
--- /dev/null
+++ b/Documentation/devicetree/bindings/qdsp/adsp-loader.txt
@@ -0,0 +1,10 @@
+* MSM Application DSP loader binding
+
+Required properties:
+- compatible : "qcom,adsp-loader"
+
+Example:
+
+	qcom,msm-adsp-loader {
+		compatible = "qcom,adsp-loader";
+	};
diff --git a/Documentation/devicetree/bindings/regulator/qpnp-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-regulator.txt
index c9bc284..2116888 100644
--- a/Documentation/devicetree/bindings/regulator/qpnp-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/qpnp-regulator.txt
@@ -76,11 +76,13 @@
 					1 = 0.25 uA
 					2 = 0.55 uA
 					3 = 0.75 uA
-
-- spmi-dev-container:	This specifies that all the device nodes specified
-	within this node should have their resources coalesced into a single
-	spmi_device.  This is used to specify all SPMI peripherals that
-	logically make up a single regulator device.
+- qcom,force-type: 	       Override the type and subtype register values. Useful for some
+				regulators that have invalid types advertised by the hardware.
+				The format is two unsigned integers of the form <type subtype>.
+- spmi-dev-container:	       Specifies that all the device nodes specified
+				within this node should have their resources coalesced into a
+				single spmi_device.  This is used to specify all SPMI peripherals
+				that logically make up a single regulator device.
 
 Note, if a given optional qcom,* binding is not present, then the qpnp-regulator
 driver will leave that feature in the default hardware state.
diff --git a/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
index cf727d9..ecac09d 100644
--- a/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
+++ b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
@@ -25,6 +25,9 @@
  - qcom,max-clk-gear: Maximum clock gear at which this controller can be run
 		 (range: 1-10)
 		 Default value will be 10 if this entry is not specified
+ - qcom,rxreg-access: This boolean indicates that slimbus RX should use direct
+		 register access to receive data. This flag is only needed if
+		 BAM pipe is not available to receive data from slimbus
 Example:
 	slim@fe12f000 {
 		cell-index = <1>;
@@ -35,4 +38,5 @@
 		interrupts = <0 163 0 0 164 0>;
 		interrupt-names = "slimbus_irq", "slimbus_bam_irq";
 		qcom,min-clk-gear = <10>;
+		qcom,rxreg-access;
 	};
diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/taiko_codec.txt
new file mode 100644
index 0000000..9f3719b
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/taiko_codec.txt
@@ -0,0 +1,82 @@
+taiko audio CODEC
+
+Required properties:
+
+  - compatible : "qcom,taiko-slim-pgd"
+  - elemental-addr: codec slimbus slave PGD enumeration address.(48 bits)
+
+  - qcom,cdc-reset-gpio: gpio used for codec SOC reset.
+
+  - <supply-name>-supply: phandle to the regulator device tree node
+  - qcom,<supply-name>-voltage -  specifies voltage levels for supply. Should be
+       specified in pairs (min, max), units mV.
+  - qcom,<supply-name>-current - specifies max current in mA that can drawn
+       from the <supply-name>.
+
+    above three properties with "supply-name" set to  "qcom,cdc-vdd-buck", "qcom,cdc-vdd-tx-h",
+     "qcom,cdc-vdd-rx-h", "qcom,cdc-vddpx-1", "qcom,cdc-vdd-a-1p2v", "qcom,cdc-vddcx-1",
+     "qcom,cdc-vddcx-2" should be present.
+
+ - qcom,cdc-micbias-ldoh-v - LDOH output in volts ( should be 1.95 V and 3.00 V).
+
+ - qcom,cdc-micbias-cfilt1-mv - cfilt1 output voltage in milli volts.
+ - qcom,cdc-micbias-cfilt2-mv - cfilt2 output voltage in milli volts.
+ - qcom,cdc-micbias-cfilt3-mv - cfilt3 output voltage in milli volts.
+   cfilt volatge can be set to max of qcom,cdc-micbias-ldoh-v - 0.15V.
+
+ - qcom,cdc-micbias1-cfilt-sel = cfilt to use for micbias1 (should be from 1 to 3).
+ - qcom,cdc-micbias2-cfilt-sel = cfilt to use for micbias2 (should be from 1 to 3).
+ - qcom,cdc-micbias3-cfilt-sel = cfilt to use for micbias3 (should be from 1 to 3).
+ - qcom,cdc-micbias4-cfilt-sel = cfilt to use for micbias4 (should be from 1 to 3).
+
+ - qcom,cdc-slim-ifd-dev - namme of the codec slim interface device.
+ - qcom,cdc-slim-ifd-elemental-addr - codec slimbus slave interface device
+				     enumeration address.
+Example:
+
+taiko_codec {
+	compatible = "qcom,taiko-slim-pgd";
+	elemental-addr = [00 01 A0 00 17 02];
+
+	qcom,cdc-reset-gpio = <&msmgpio 63 0>;
+
+	cdc-vdd-buck-supply = <&pm8941_s2>;
+	qcom,cdc-vdd-buck-voltage = <2150000 2150000>;
+	qcom,cdc-vdd-buck-current = <500000>;
+
+	cdc-vdd-tx-h-supply = <&pm8941_s3>;
+	qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+	qcom,cdc-vdd-tx-h-current = <200000>;
+
+	cdc-vdd-rx-h-supply = <&pm8941_s3>;
+	qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+	qcom,cdc-vdd-rx-h-current = <200000>;
+
+	cdc-vddpx-1-supply = <&pm8941_s3>;
+	qcom,cdc-vddpx-1-voltage = <1800000 1800000>;
+	qcom,cdc-vddpx-1-current = <5000>;
+
+	cdc-vdd-a-1p2v-supply = <&pm8941_l1>;
+	qcom,cdc-vdd-a-1p2v-voltage = <1225000 1225000>;
+	qcom,cdc-vdd-a-1p2v-current = <5000>;
+
+	cdc-vddcx-1-supply = <&pm8941_l1>;
+	qcom,cdc-vddcx-1-voltage = <1225000 1225000>;
+	qcom,cdc-vddcx-1-current = <5000>;
+
+	cdc-vddcx-2-supply = <&pm8941_l1>;
+	qcom,cdc-vddcx-2-voltage = <1225000 1225000>;
+	qcom,cdc-vddcx-2-current = <5000>;
+
+	qcom,cdc-micbias-ldoh-v = <0x3>;
+	qcom,cdc-micbias-cfilt1-mv = <1800>;
+	qcom,cdc-micbias-cfilt2-mv = <2700>;
+	qcom,cdc-micbias-cfilt3-mv = <1800>;
+	qcom,cdc-micbias1-cfilt-sel = <0x0>;
+	qcom,cdc-micbias2-cfilt-sel = <0x1>;
+	qcom,cdc-micbias3-cfilt-sel = <0x2>;
+	qcom,cdc-micbias4-cfilt-sel = <0x2>;
+
+	qcom,cdc-slim-ifd = "taiko-slim-ifd";
+	qcom,cdc-slim-ifd-elemental-addr = [00 00 A0 00 17 02];
+};
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 95ddf34..8a4b833 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -20,6 +20,8 @@
             1 - PHY control
 	    2 - PMIC control
 	    3 - User control (via debugfs)
+- qcom,hsusb-otg-disable-reset: It present then core is RESET only during
+	    init, otherwise core is RESET for every cable disconnect as well
 
 Optional properties :
 - qcom,hsusb-otg-default-mode: The default USB mode after boot-up.
@@ -43,9 +45,77 @@
 		qcom,hsusb-otg-phy-type = <2>;
 		qcom,hsusb-otg-mode = <1>;
 		qcom,hsusb-otg-otg-control = <1>;
+		qcom,hsusb-otg-disable-reset;
 		qcom,hsusb-otg-default-mode = <2>;
 		qcom,hsusb-otg-phy-init-seq = <0x01 0x90 0xffffffff>;
 		qcom,hsusb-otg-power-budget = <500>;
 		qcom,hsusb-otg-pclk-src-name = "dfab_usb_clk";
 		qcom,hsusb-otg-pmic-id-irq = <47>
 	};
+
+BAM:
+
+Required properties:
+- compatible: should be "qcom,usb-bam-msm"
+- regs: offset and length of the register set in the memory map
+- interrupts: IRQ line
+- qcom,usb-active-bam: active BAM type. Can be one of
+            0 - HSUSB_BAM
+            1 - HSIC_BAM
+- qcom,usb-total-bam-num: total number of BAMs that are supported
+- qcom,usb-bam-num-pipes: max number of pipes that can be used
+- qcom,usb-base-address: physical base address of the BAM
+
+A number of USB BAM pipe parameters are represented as sub-nodes:
+
+Subnode Required:
+- label: a string describing the pipe's direction and use
+- qcom,usb-bam-type: BAM type. Can be one of
+            0 - HSUSB_BAM
+            1 - HSIC_BAM
+- qcom,src-bam-physical-address: source BAM physical address
+- qcom,src-bam-pipe-index: source BAM pipe index
+- qcom,dst-bam-physical-address: destination BAM physical address
+- qcom,dst-bam-pipe-index: destination BAM pipe index
+- qcom,data-fifo-offset: data fifo offset address
+- qcom,data-fifo-size: data fifo size
+- qcom,descriptor-fifo-offset: descriptor fifo offset address
+- qcom,descriptor-fifo-size: descriptor fifo size
+
+Example USB BAM controller device node:
+
+	qcom,usbbam@f9304000 {
+		compatible = "qcom,usb-bam-msm";
+		reg = <0xf9304000 0x9000>;
+		interrupts = <0 132 0>;
+		qcom,usb-active-bam = <0>;
+		qcom,usb-total-bam-num = <1>;
+		qcom,usb-bam-num-pipes = <16>;
+		qcom,usb-base-address = <0xf9200000>;
+
+		qcom,pipe1 {
+			label = "usb-to-peri-qdss-dwc3";
+			qcom,usb-bam-type = <0>;
+			qcom,src-bam-physical-address = <0>;
+			qcom,src-bam-pipe-index = <0>;
+			qcom,dst-bam-physical-address = <0>;
+			qcom,dst-bam-pipe-index = <0>;
+			qcom,data-fifo-offset = <0>;
+			qcom,data-fifo-size = <0>;
+			qcom,descriptor-fifo-offset = <0>;
+			qcom,descriptor-fifo-size = <0>;
+		};
+
+		qcom,pipe2 {
+			label = "peri-to-usb-qdss-dwc3";
+			qcom,usb-bam-type = <0>;
+			qcom,src-bam-physical-address = <0xfc37C000>;
+			qcom,src-bam-pipe-index = <0>;
+			qcom,dst-bam-physical-address = <0xf9304000>;
+			qcom,dst-bam-pipe-index = <2>;
+			qcom,data-fifo-offset = <0xf0000>;
+			qcom,data-fifo-size = <0x4000>;
+			qcom,descriptor-fifo-offset = <0xf4000>;
+			qcom,descriptor-fifo-size = <0x1400>;
+		};
+	};
diff --git a/Documentation/usb/misc_ksbridge.txt b/Documentation/usb/misc_ksbridge.txt
new file mode 100644
index 0000000..f409dc1
--- /dev/null
+++ b/Documentation/usb/misc_ksbridge.txt
@@ -0,0 +1,46 @@
+Introduction
+--------------
+ksbridge is a simple misc device which bridges Kickstart application
+to HSIC h/w. Driver supports two instances, one instance for
+flash-less-boot/ram-dumps and other instance for EFS Sync.
+
+Initialization
+--------------
+Create two bridge instances and register for usb devices 0x9008 and
+0x9048/0x904C. Misc device name depends on the USB PID.
+For PID: 9008, misc device name is ks_bridge and for PID:9048/904C,
+misc device name is efs_bridge. After KS opens the misc device, IN
+URBs will be submitted to H/W; By default IN URBS are configured
+to 20.
+
+TX PATH
+-------
+Transmit path is very simple. Bridge driver will exposes write system
+call to kickstart. Data from write call will be put into a list and a
+work is scheduled to take the data from the list and write to HSIC.
+
+Functions:
+ksb_fs_write: System call invoked when kickstart writes the data
+ksb_tomdm_work: Work function which submits data to HSIC h/w.
+
+Data Structures:
+to_mdm_list: Data is stored in this list
+to_mdm_work: mapped to ksb_tomdm_work function
+
+RX PATH
+-------
+During initialization 20 IN URBs are submitted to hsic controller. In
+completion handler of each URB, buffer is de-queued and add to a list.
+Read function is woken-up. A new buffer is created and submitted to
+controller.
+
+Functions:
+ksb_fs_read: system call invoked by ks when it tries to read the data
+ksb_rx_cb: rx urb completion handler
+ksb_start_rx_work: function called during initialization.
+
+Data Structures:
+ks_wait_q: read system call will block on this queue until data is
+available or device is disconnected
+to_ks_list: data queued to this list by rx urb completion handler,
+later de-queued by read system call.
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8fb7a8e..7930de5 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1849,9 +1849,6 @@
 config ARCH_MEMORY_REMOVE
 	def_bool n
 
-config ARCH_POPULATES_NODE_MAP
-	def_bool n
-
 config ENABLE_DMM
 	def_bool n
 
diff --git a/arch/arm/boot/dts/dsi-panel-sim-video.dtsi b/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
new file mode 100644
index 0000000..1e5c26c
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
@@ -0,0 +1,41 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&mdss_dsi {
+
+	qcom,mdss_dsi_sim_video {
+		compatible = "qcom,mdss-dsi-panel";
+		label = "simulator video mode dsi panel";
+		status = "disable";
+		qcom,mdss-pan-res = <640 480>;
+		qcom,mdss-pan-bpp = <24>;
+		qcom,mdss-pan-porch-values = <6 2 6 6 2 6>;
+		qcom,mdss-pan-underflow-clr = <0xff>;
+		qcom,mdss-pan-bl-levels = <1 15>;
+		qcom,mdss-pan-dsi-mode = <0>;
+		qcom,mdss-pan-dsi-h-pulse-mode = <1>;
+		qcom,mdss-pan-dsi-h-power-stop = <1 1 1>;
+		qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+		qcom,mdss-pan-dsi-traffic-mode = <0>;
+		qcom,mdss-pan-dsi-dst-format = <3>;
+		qcom,mdss-pan-dsi-vc = <0>;
+		qcom,mdss-pan-dsi-rgb-swap = <0>;
+		qcom,mdss-pan-dsi-data-lanes = <1 1 0 0>;
+		qcom,mdss-pan-dsi-t-clk = <0x24 0x03>;
+		qcom,mdss-pan-dsi-stream = <0>;
+		qcom,mdss-pan-dsi-mdp-tr = <0x04>;
+		qcom,mdss-pan-dsi-dma-tr = <0x04>;
+		qcom,mdss-pan-frame-rate = <60>;
+		qcom,panel-on-cmds = [32 01 00 00 00 02 00 00];
+		qcom,panel-off-cmds = [22 01 00 00 00 02 00 00];
+	};
+};
diff --git a/arch/arm/boot/dts/msm-iommu.dtsi b/arch/arm/boot/dts/msm-iommu.dtsi
index 0e2ddce9..e907de8 100755
--- a/arch/arm/boot/dts/msm-iommu.dtsi
+++ b/arch/arm/boot/dts/msm-iommu.dtsi
@@ -23,7 +23,7 @@
 
 		qcom,iommu-ctx@fda6c000 {
 			reg = <0xfda6c000 0x1000>;
-			interrupts = <0 69 0>;
+			interrupts = <0 70 0>;
 			qcom,iommu-ctx-sids = <0>;
 			label = "jpeg_enc0";
 		};
@@ -37,7 +37,7 @@
 
 		qcom,iommu-ctx@fda6e000 {
 			reg = <0xfda6e000 0x1000>;
-			interrupts = <0 71 0>;
+			interrupts = <0 70 0>;
 			qcom,iommu-ctx-sids = <2>;
 			label = "jpeg_dec";
 		};
@@ -55,7 +55,7 @@
 
 		qcom,iommu-ctx@fd930000 {
 			reg = <0xfd930000 0x1000>;
-			interrupts = <0 46 0>;
+			interrupts = <0 47 0>;
 			qcom,iommu-ctx-sids = <0>;
 			label = "mdp_0";
 		};
@@ -81,7 +81,7 @@
 
 		qcom,iommu-ctx@fdc8c000 {
 			reg = <0xfdc8c000 0x1000>;
-			interrupts = <0 43 0>;
+			interrupts = <0 42 0>;
 			qcom,iommu-ctx-sids = <0 1 2 3 4 5>;
 			label = "venus_ns";
 		};
@@ -95,7 +95,7 @@
 
 		qcom,iommu-ctx@fdc8e000 {
 			reg = <0xfdc8e000 0x1000>;
-			interrupts = <0 41 0>;
+			interrupts = <0 42 0>;
 			qcom,iommu-ctx-sids = <0xc0 0xc6>;
 			label = "venus_fw";
 		};
@@ -114,7 +114,7 @@
 
 		qcom,iommu-ctx@fdb18000 {
 			reg = <0xfdb18000 0x1000>;
-			interrupts = <0 240 0>;
+			interrupts = <0 241 0>;
 			qcom,iommu-ctx-sids = <0>;
 			label = "gfx3d_user";
 		};
@@ -139,7 +139,7 @@
 
 		qcom,iommu-ctx@fda4c000 {
 			reg = <0xfda4c000 0x1000>;
-			interrupts = <0 64 0>;
+			interrupts = <0 65 0>;
 			qcom,iommu-ctx-sids = <0>;
 			label = "vfe0";
 		};
@@ -153,7 +153,7 @@
 
 		qcom,iommu-ctx@fda4e000 {
 			reg = <0xfda4e000 0x1000>;
-			interrupts = <0 66 0>;
+			interrupts = <0 65 0>;
 			qcom,iommu-ctx-sids = <2>;
 			label = "cpp";
 		};
diff --git a/arch/arm/boot/dts/msm-pm8841.dtsi b/arch/arm/boot/dts/msm-pm8841.dtsi
index d84c8e0..967d5ec 100644
--- a/arch/arm/boot/dts/msm-pm8841.dtsi
+++ b/arch/arm/boot/dts/msm-pm8841.dtsi
@@ -91,6 +91,7 @@
 			compatible = "qcom,qpnp-regulator";
 			reg = <0x1700 0x300>;
 			status = "disabled";
+			qcom,force-type = <0x1c 0x08>;
 
 			qcom,ctl@1700 {
 				reg = <0x1700 0x100>;
@@ -131,6 +132,7 @@
 			compatible = "qcom,qpnp-regulator";
 			reg = <0x1d00 0x300>;
 			status = "disabled";
+			qcom,force-type = <0x1c 0x08>;
 
 			qcom,ctl@1d00 {
 				reg = <0x1d00 0x100>;
@@ -151,6 +153,7 @@
 			compatible = "qcom,qpnp-regulator";
 			reg = <0x2000 0x300>;
 			status = "disabled";
+			qcom,force-type = <0x1c 0x08>;
 
 			qcom,ctl@0 {
 				reg = <0x2000 0x100>;
@@ -171,6 +174,7 @@
 			compatible = "qcom,qpnp-regulator";
 			reg = <0x2300 0x300>;
 			status = "disabled";
+			qcom,force-type = <0x1c 0x08>;
 
 			qcom,ctl@2300 {
 				reg = <0x2300 0x100>;
@@ -191,6 +195,7 @@
 			compatible = "qcom,qpnp-regulator";
 			reg = <0x2600 0x300>;
 			status = "disabled";
+			qcom,force-type = <0x1c 0x08>;
 
 			qcom,ctl@2600 {
 				reg = <0x2600 0x100>;
@@ -211,6 +216,7 @@
 			compatible = "qcom,qpnp-regulator";
 			reg = <0x2900 0x300>;
 			status = "disabled";
+			qcom,force-type = <0x1c 0x08>;
 
 			qcom,ctl@2900 {
 				reg = <0x2900 0x100>;
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 51ec10c..84bc68b 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -25,11 +25,27 @@
 		qcom,power-on@800 {
 			compatible = "qcom,qpnp-power-on";
 			reg = <0x800 0x100>;
-			interrupts = <0x0 0x8 0x0>;
-			interrupt-names = "power-key";
-			qcom,pon-key-enable = <1>;
-			qcom,pon-key-dbc-delay = <15625>;
-			qcom,pon-key-pull-up = <1>;
+			interrupts = <0x0 0x8 0x0>,
+				     <0x0 0x8 0x1>,
+				     <0x0 0x8 0x4>;
+			interrupt-names = "kpdpwr", "resin", "resin-bark";
+			qcom,pon-dbc-delay = <15625>;
+
+			qcom,pon_1 {
+				qcom,pon-type = <0>;
+				qcom,pull-up = <1>;
+				linux,code = <116>;
+			};
+
+			qcom,pon_2 {
+				qcom,pon-type = <1>;
+				qcom,support-reset = <1>;
+				qcom,pull-up = <1>;
+				qcom,s1-timer = <0>;
+				qcom,s2-timer = <2000>;
+				qcom,s2-type = <1>;
+				linux,code = <114>;
+			};
 		};
 
 		pm8941_gpios {
@@ -350,6 +366,92 @@
 				qcom,hw-settle-time = <0>;
 				qcom,fast-avg-setup = <0>;
 			};
+
+			chan@2 {
+				label = "vchg_sns";
+				qcom,channel-num = <2>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <6>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@5 {
+				label = "vcoin";
+				qcom,channel-num = <5>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <3>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@6 {
+				label = "vbat_sns";
+				qcom,channel-num = <6>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <3>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@7 {
+				label = "vph_pwr";
+				qcom,channel-num = <7>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <3>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@9 {
+				label = "ref_625mv";
+				qcom,channel-num = <9>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <1>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@10 {
+				label = "ref_1125v";
+				qcom,channel-num = <10>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <1>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+		};
+
+		iadc@3600 {
+			compatible = "qcom,qpnp-iadc";
+			reg = <0x3600 0x100>;
+			interrupts = <0x0 0x36 0x0>;
+			qcom,adc-bit-resolution = <16>;
+			qcom,adc-vdd-reference = <1800>;
+			qcom,rsense = <1500>;
+
+			chan@0 {
+				label = "internal_rsense";
+				qcom,channel-num = <0>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <1>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
 		};
 	};
 
@@ -405,7 +507,7 @@
 			#address-cells = <1>;
 			#size-cells = <1>;
 			compatible = "qcom,qpnp-regulator";
-			reg = <0x1400 0x300>;
+			reg = <0x1a00 0x300>;
 			status = "disabled";
 
 			qcom,ctl@1a00 {
@@ -458,6 +560,7 @@
 			regulator-name = "8941_l5";
 			reg = <0x4400 0x100>;
 			compatible = "qcom,qpnp-regulator";
+			qcom,force-type = <0x04 0x10>;
 			status = "disabled";
 		};
 
@@ -472,6 +575,7 @@
 			regulator-name = "8941_l7";
 			reg = <0x4600 0x100>;
 			compatible = "qcom,qpnp-regulator";
+			qcom,force-type = <0x04 0x10>;
 			status = "disabled";
 		};
 
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
new file mode 100644
index 0000000..0375e93
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	qcom,cam_server {
+		compatible = "qcom,cam_server";
+		reg = <0xfd8C0000 0x10000>;
+		reg-names = "server";
+	};
+	qcom,csiphy@fda0ac00 {
+		cell-index = <0>;
+		compatible = "qcom,csiphy";
+		reg = <0xfda0ac00 0x200>;
+		reg-names = "csiphy";
+		interrupts = <0 78 0>;
+		interrupt-names = "csiphy";
+	};
+	qcom,csiphy@fda0b000 {
+		cell-index = <1>;
+		compatible = "qcom,csiphy";
+		reg = <0xfda0b000 0x200>;
+		reg-names = "csiphy";
+		interrupts = <0 79 0>;
+		interrupt-names = "csiphy";
+	};
+	qcom,csiphy@fda0b400 {
+		cell-index = <2>;
+		compatible = "qcom,csiphy";
+		reg = <0xfda0b400 0x200>;
+		reg-names = "csiphy";
+		interrupts = <0 80 0>;
+		interrupt-names = "csiphy";
+	};
+	qcom,csid@fda08000  {
+		cell-index = <0>;
+		compatible = "qcom,csid";
+		reg = <0xfda08000 0x100>;
+		reg-names = "csid";
+		interrupts = <0 51 0>;
+		interrupt-names = "csid";
+	};
+	qcom,csid@fda08400 {
+		cell-index = <1>;
+		compatible = "qcom,csid";
+		reg = <0xfda08400 0x100>;
+		reg-names = "csid";
+		interrupts = <0 52 0>;
+		interrupt-names = "csid";
+	};
+	qcom,csid@fda08800 {
+		cell-index = <2>;
+		compatible = "qcom,csid";
+		reg = <0xfda08800 0x100>;
+		reg-names = "csid";
+		interrupts = <0 53 0>;
+		interrupt-names = "csid";
+	};
+	qcom,csid@fda08C00 {
+		cell-index = <3>;
+		compatible = "qcom,csid";
+		reg = <0xfda08C00 0x100>;
+		reg-names = "csid";
+		interrupts = <0 54 0>;
+		interrupt-names = "csid";
+	};
+	qcom,ispif@fda0A000 {
+		cell-index = <0>;
+		compatible = "qcom,ispif";
+		reg = <0xfda0A000 0x300>;
+		reg-names = "ispif";
+		interrupts = <0 55 0>;
+		interrupt-names = "ispif";
+	};
+	qcom,cci@fda0C000 {
+		cell-index = <0>;
+		compatible = "qcom,cci";
+		reg = <0xfda0C000 0x1000>;
+		reg-names = "cci";
+		interrupts = <0 50 0>;
+		interrupt-names = "cci";
+	};
+	qcom,vfe@fda10000 {
+		cell-index = <0>;
+		compatible = "qcom,vfe40";
+		reg = <0xfda10000 0x1000>;
+		reg-names = "vfe";
+		interrupts = <0 57 0>;
+		interrupt-names = "vfe";
+		vdd-supply = <&gdsc_vfe>;
+	};
+	qcom,vfe@fda14000 {
+		cell-index = <1>;
+		compatible = "qcom,vfe40";
+		reg = <0xfda14000 0x1000>;
+		reg-names = "vfe";
+		interrupts = <0 58 0>;
+		interrupt-names = "vfe";
+		vdd-supply = <&gdsc_vfe>;
+	};
+	qcom,jpeg@fda1c000 {
+		cell-index = <0>;
+		compatible = "qcom,jpeg";
+		reg = <0xfda1c000 0x400>;
+		reg-names = "jpeg";
+		interrupts = <0 59 0>;
+		interrupt-names = "jpeg";
+	};
+	qcom,jpeg@fda20000 {
+		cell-index = <1>;
+		compatible = "qcom,jpeg";
+		reg = <0xfda20000 0x400>;
+		reg-names = "jpeg";
+		interrupts = <0 60 0>;
+		interrupt-names = "jpeg";
+	};
+	qcom,jpeg@fda24000 {
+		cell-index = <2>;
+		compatible = "qcom,jpeg";
+		reg = <0xfda24000 0x400>;
+		reg-names = "jpeg";
+		interrupts = <0 61 0>;
+		interrupt-names = "jpeg";
+	};
+	qcom,irqrouter@fda00000 {
+		cell-index = <0>;
+		compatible = "qcom,irqrouter";
+		reg = <0xfda00000 0x100>;
+		reg-names = "irqrouter";
+	};
+	qcom,cpp@fda04000 {
+		cell-index = <0>;
+		compatible = "qcom,cpp";
+		reg = <0xfda04000 0x100>;
+		reg-names = "cpp";
+		interrupts = <0 49 0>;
+		interrupt-names = "cpp";
+		vdd-supply = <&gdsc_vfe>;
+	};
+};
diff --git a/drivers/gpu/msm/adreno_postmortem.h b/arch/arm/boot/dts/msm8974-cdp.dts
similarity index 63%
rename from drivers/gpu/msm/adreno_postmortem.h
rename to arch/arm/boot/dts/msm8974-cdp.dts
index b677800..bfe24d2 100644
--- a/drivers/gpu/msm/adreno_postmortem.h
+++ b/arch/arm/boot/dts/msm8974-cdp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -8,14 +8,18 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
  */
 
-#ifndef __ADRENO_POSTMORTEM_H
-#define __ADRENO_POSTMORTEM_H
+/dts-v1/;
 
-struct kgsl_device;
+/include/ "msm8974.dtsi"
 
-int adreno_postmortem_dump(struct kgsl_device *device, int manual);
+/ {
+	model = "Qualcomm MSM 8974 CDP";
+	compatible = "qcom,msm8974-cdp", "qcom,msm8974";
+	qcom,msm-id = <126 1 0>, <126 8 0>;
 
-#endif /* __ADRENO_POSTMORTEM_H */
+	serial@f991e000 {
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
new file mode 100644
index 0000000..c28ef9e
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -0,0 +1,177 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+	tmc_etr: tmc@fc322000 {
+		compatible = "arm,coresight-tmc";
+		reg = <0xfc322000 0x1000>;
+
+		coresight-id = <0>;
+		coresight-name = "coresight-tmc-etr";
+		coresight-nr-inports = <1>;
+		coresight-default-sink;
+	};
+
+	tpiu: tpiu@fc318000 {
+		compatible = "arm,coresight-tpiu";
+		reg = <0xfc318000 0x1000>;
+
+		coresight-id = <1>;
+		coresight-name = "coresight-tpiu";
+		coresight-nr-inports = <1>;
+	};
+
+	replicator: replicator@fc31c000 {
+		compatible = "qcom,coresight-replicator";
+		reg = <0xfc31c000 0x1000>;
+
+		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>;
+	};
+
+	tmc_etf: tmc@fc307000 {
+		compatible = "arm,coresight-tmc";
+		reg = <0xfc307000 0x1000>;
+
+		coresight-id = <3>;
+		coresight-name = "coresight-tmc-etf";
+		coresight-nr-inports = <1>;
+		coresight-outports = <0>;
+		coresight-child-list = <&replicator>;
+		coresight-child-ports = <0>;
+	};
+
+	funnel_merg: funnel@fc31b000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0xfc31b000 0x1000>;
+
+		coresight-id = <4>;
+		coresight-name = "coresight-funnel-merg";
+		coresight-nr-inports = <2>;
+		coresight-outports = <0>;
+		coresight-child-list = <&tmc_etf>;
+		coresight-child-ports = <0>;
+	};
+
+	funnel_in0: funnel@fc319000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0xfc319000 0x1000>;
+
+		coresight-id = <5>;
+		coresight-name = "coresight-funnel-in0";
+		coresight-nr-inports = <8>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_merg>;
+		coresight-child-ports = <0>;
+	};
+
+	funnel_in1: funnel@fc31a000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0xfc31a000 0x1000>;
+
+		coresight-id = <6>;
+		coresight-name = "coresight-funnel-in1";
+		coresight-nr-inports = <8>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_merg>;
+		coresight-child-ports = <1>;
+	};
+
+	funnel_kpss: funnel@fc345000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0xfc345000 0x1000>;
+
+		coresight-id = <7>;
+		coresight-name = "coresight-funnel-kpss";
+		coresight-nr-inports = <4>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in1>;
+		coresight-child-ports = <5>;
+	};
+
+	funnel_mmss: funnel@fc364000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0xfc364000 0x1000>;
+
+		coresight-id = <8>;
+		coresight-name = "coresight-funnel-mmss";
+		coresight-nr-inports = <8>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in1>;
+		coresight-child-ports = <1>;
+	};
+
+	stm: stm@fc321000 {
+		compatible = "arm,coresight-stm";
+		reg = <0xfc321000 0x1000>,
+		      <0xfa280000 0x180000>;
+
+		coresight-id = <9>;
+		coresight-name = "coresight-stm";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in1>;
+		coresight-child-ports = <7>;
+	};
+
+	etm0: etm@fc33c000 {
+		compatible = "arm,coresight-etm";
+		reg = <0xfc33c000 0x1000>;
+
+		coresight-id = <10>;
+		coresight-name = "coresight-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_kpss>;
+		coresight-child-ports = <0>;
+	};
+
+	etm1: etm@fc33d000 {
+		compatible = "arm,coresight-etm";
+		reg = <0xfc33d000 0x1000>;
+
+		coresight-id = <11>;
+		coresight-name = "coresight-etm1";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_kpss>;
+		coresight-child-ports = <1>;
+	};
+
+	etm2: etm@fc33e000 {
+		compatible = "arm,coresight-etm";
+		reg = <0xfc33e000 0x1000>;
+
+		coresight-id = <12>;
+		coresight-name = "coresight-etm2";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_kpss>;
+		coresight-child-ports = <2>;
+	};
+
+	etm3: etm@fc33f000 {
+		compatible = "arm,coresight-etm";
+		reg = <0xfc33f000 0x1000>;
+
+		coresight-id = <13>;
+		coresight-name = "coresight-etm3";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_kpss>;
+		coresight-child-ports = <3>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-gpio.dtsi b/arch/arm/boot/dts/msm8974-gpio.dtsi
index 323fac4..5d93fa3 100644
--- a/arch/arm/boot/dts/msm8974-gpio.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpio.dtsi
@@ -25,14 +25,26 @@
 			};
 
 			gpio@c200 {
+				qcom,mode = <0>;
+				qcom,pull = <0>;
+				qcom,vin-sel = <2>;
+				qcom,select = <0>;
 				status = "ok";
 			};
 
 			gpio@c300 {
+				qcom,mode = <0>;
+				qcom,pull = <0>;
+				qcom,vin-sel = <2>;
+				qcom,select = <0>;
 				status = "ok";
 			};
 
 			gpio@c400 {
+				qcom,mode = <0>;
+				qcom,pull = <0>;
+				qcom,vin-sel = <2>;
+				qcom,select = <0>;
 				status = "ok";
 			};
 
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
new file mode 100644
index 0000000..a972d7f
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -0,0 +1,126 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+/ {
+	qcom,kgsl-3d0@fdb00000 {
+		label = "kgsl-3d0";
+		compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
+		reg = <0xfdb00000 0x20000>;
+		reg-names = "kgsl_3d0_reg_memory";
+		interrupts = <0 33 0>;
+		interrupt-names = "kgsl_3d0_irq";
+		qcom,id = <0>;
+
+		qcom,chipid = <0x03030000>;
+
+		qcom,initial-pwrlevel = <1>;
+
+		qcom,idle-timeout = <83>; //<HZ/12>
+		qcom,nap-allowed = <1>;
+		qcom,clk-map = <0x00000016>; //KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE
+
+		/* Bus Scale Settings */
+		qcom,grp3d-vectors = <0 0 0 0>, <2 1 0 0>,
+				<0 0 0 2000>, <2 1 0 3000>,
+				<0 0 0 4000>, <2 1 0 5000>,
+				<0 0 0 6400>, <2 1 0 7600>;
+		qcom,grp3d-num-vectors-per-usecase = <2>;
+		qcom,grp3d-num-bus-scale-usecases = <4>;
+
+		/* GDSC oxili regulators */
+		vddcx-supply = <&gdsc_oxili_cx>;
+		vdd-supply = <&gdsc_oxili_gx>;
+
+		/* Power levels */
+
+		/* IOMMU Data */
+		iommu = <&kgsl_iommu>;
+
+		qcom,gpu-pwrlevels {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			compatible = "qcom,gpu-pwrlevels";
+
+			qcom,gpu-pwrlevel@0 {
+				reg = <0>;
+				qcom,gpu-freq = <500000000>;
+				qcom,bus-freq = <3>;
+				qcom,io-fraction = <0>;
+			};
+
+			qcom,gpu-pwrlevel@1 {
+				reg = <1>;
+				qcom,gpu-freq = <333000000>;
+				qcom,bus-freq = <2>;
+				qcom,io-fraction = <33>;
+			};
+
+			qcom,gpu-pwrlevel@2 {
+				reg = <2>;
+				qcom,gpu-freq = <200000000>;
+				qcom,bus-freq = <1>;
+				qcom,io-fraction = <100>;
+			};
+
+			qcom,gpu-pwrlevel@3 {
+				reg = <3>;
+				qcom,gpu-freq = <27000000>;
+				qcom,bus-freq = <0>;
+				qcom,io-fraction = <0>;
+			};
+		};
+
+		qcom,dcvs-core-info {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			compatible = "qcom,dcvs-core-info";
+
+			qcom,core-max-time-us = <100000>;
+			qcom,algo-slack-time-us = <39000>;
+			qcom,algo-disable-pc-threshold = <86000>;
+			qcom,algo-ss-window-size = <1000000>;
+			qcom,algo-ss-util-pct = <95>;
+			qcom,algo-em-max-util-pct = <97>;
+			qcom,algo-ss-iobusy-conv = <100>;
+
+			qcom,dcvs-freq@0 {
+				reg = <0>;
+				qcom,freq = <0>;
+				qcom,idle-energy = <0>;
+				qcom,active-energy = <333932>;
+			};
+
+			qcom,dcvs-freq@1 {
+				reg = <1>;
+				qcom,freq = <0>;
+				qcom,idle-energy = <0>;
+				qcom,active-energy = <497532>;
+			};
+
+			qcom,dcvs-freq@2 {
+				reg = <2>;
+				qcom,freq = <0>;
+				qcom,idle-energy = <0>;
+				qcom,active-energy = <707610>;
+			};
+
+			qcom,dcvs-freq@3 {
+				reg = <3>;
+				qcom,freq = <0>;
+				qcom,idle-energy = <0>;
+				qcom,active-energy = <844545>;
+			};
+		};
+
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
new file mode 100644
index 0000000..1893ae4
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -0,0 +1,76 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+	qcom,ion {
+		compatible = "qcom,msm-ion";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,ion-heap@30 { /* SYSTEM HEAP */
+			reg = <30>;
+		};
+
+		qcom,ion-heap@8 { /* CP_MM HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <8>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
+			qcom,memory-reservation-size = <0x7800000>;
+		};
+
+		qcom,ion-heap@29 { /* FIRMWARE HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <29>;
+			qcom,heap-align = <0x20000>;
+			qcom,heap-adjacent = <8>;
+			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
+			qcom,memory-reservation-size = <0xA00000>;
+		};
+
+		qcom,ion-heap@12 { /* MFC HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <12>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
+			qcom,memory-reservation-size = <0x2000>;
+		};
+
+		qcom,ion-heap@24 { /* SF HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <24>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
+			qcom,memory-reservation-size = <0x2800000>;
+		};
+
+		qcom,ion-heap@25 { /* IOMMU HEAP */
+			reg = <25>;
+		};
+
+		qcom,ion-heap@27 { /* QSECOM HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <27>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
+			qcom,memory-reservation-size = <0x600000>;
+		};
+
+		qcom,ion-heap@28 { /* AUDIO HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <28>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
+			qcom,memory-reservation-size = <0x2B4000>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
new file mode 100644
index 0000000..d14e014
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -0,0 +1,32 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+	qcom,mdss_mdp@fd900000 {
+		compatible = "qcom,mdss_mdp";
+		reg = <0xfd900000 0x22100>;
+		interrupts = <0 72 0>;
+		vdd-supply = <&gdsc_mdss>;
+	};
+
+	mdss_dsi: qcom,mdss_dsi@fd922800 {
+		compatible = "qcom,msm-mdss-dsi";
+		reg = <0xfd922800 0x5ac>,
+			<0xfd8c2000 0x01000>;
+	};
+
+	qcom,mdss_wb_panel {
+		compatible = "qcom,mdss_wb";
+		qcom,mdss_pan_res = <640 480>;
+		qcom,mdss_pan_bpp = <24>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index b376544..eb269eb 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -10,13 +10,38 @@
  * GNU General Public License for more details.
  */
 
-
-/* QPNP controlled regulators: */
-
 &spmi_bus {
-
 	qcom,pm8941@1 {
 
+		pm8941_s1: regulator@1400 {
+			regulator-min-microvolt = <1300000>;
+			regulator-max-microvolt = <1300000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			status = "okay";
+		};
+
+		regulator@1700 {
+			regulator-min-microvolt = <2150000>;
+			regulator-max-microvolt = <2150000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+			regulator-name = "8941_s2_local";
+			regulator-always-on;
+			qcom,system-load = <100000>;
+		};
+
+		pm8941_s3: regulator@1a00 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			status = "okay";
+		};
+
 		pm8941_boost: regulator@a000 {
 			regulator-min-microvolt = <5000000>;
 			regulator-max-microvolt = <5000000>;
@@ -24,6 +49,216 @@
 			status = "okay";
 		};
 
+		pm8941_l1: regulator@4000 {
+			parent-supply = <&pm8941_s1>;
+			regulator-min-microvolt = <1225000>;
+			regulator-max-microvolt = <1225000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			status = "okay";
+		};
+
+		pm8941_l2: regulator@4100 {
+			parent-supply = <&pm8941_s3>;
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_l3: regulator@4200 {
+			parent-supply = <&pm8941_s1>;
+			regulator-min-microvolt = <1225000>;
+			regulator-max-microvolt = <1225000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_l4: regulator@4300 {
+			parent-supply = <&pm8941_s1>;
+			regulator-min-microvolt = <1225000>;
+			regulator-max-microvolt = <1225000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_l6: regulator@4500 {
+			parent-supply = <&pm8941_s2>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_l8: regulator@4700 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_l9: regulator@4800 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_l10: regulator@4900 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_l11: regulator@4a00 {
+			parent-supply = <&pm8941_s1>;
+			regulator-min-microvolt = <1300000>;
+			regulator-max-microvolt = <1300000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		regulator@4b00 {
+			parent-supply = <&pm8941_s2>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+			regulator-name = "8941_l12_local";
+			regulator-always-on;
+			qcom,system-load = <100000>;
+		};
+
+		pm8941_l13: regulator@4c00 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_l14: regulator@4d00 {
+			parent-supply = <&pm8941_s2>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_l15: regulator@4e00 {
+			parent-supply = <&pm8941_s2>;
+			regulator-min-microvolt = <2050000>;
+			regulator-max-microvolt = <2050000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_l16: regulator@4f00 {
+			regulator-min-microvolt = <2700000>;
+			regulator-max-microvolt = <2700000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_l17: regulator@5000 {
+			regulator-min-microvolt = <2850000>;
+			regulator-max-microvolt = <2850000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_l18: regulator@5100 {
+			regulator-min-microvolt = <2850000>;
+			regulator-max-microvolt = <2850000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_l19: regulator@5200 {
+			regulator-min-microvolt = <2900000>;
+			regulator-max-microvolt = <2900000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_l20: regulator@5300 {
+			regulator-min-microvolt = <2950000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_l21: regulator@5400 {
+			regulator-min-microvolt = <2950000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_l22: regulator@5500 {
+			regulator-min-microvolt = <3000000>;
+			regulator-max-microvolt = <3000000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_l23: regulator@5600 {
+			regulator-min-microvolt = <3000000>;
+			regulator-max-microvolt = <3000000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_l24: regulator@5700 {
+			regulator-min-microvolt = <3075000>;
+			regulator-max-microvolt = <3075000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_lvs1: regulator@8000 {
+			parent-supply = <&pm8941_s3>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_lvs2: regulator@8100 {
+			parent-supply = <&pm8941_s3>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pm8941_lvs3: regulator@8200 {
+			parent-supply = <&pm8941_s3>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
 		pm8941_mvs1: regulator@8300 {
 			parent-supply = <&pm8941_boost>;
 			qcom,enable-time = <200>;
@@ -41,34 +276,40 @@
 
 	qcom,pm8841@5 {
 
-		pm8841_s5: regulator@2000 {
-			regulator-min-microvolt = <850000>;
-			regulator-max-microvolt = <1100000>;
+		regulator@1400 {
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			status = "okay";
+			regulator-name = "8841_s1_local";
+			qcom,system-load = <100000>;
+		};
+
+		regulator@1700 {
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1050000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			regulator-name = "8841_s2_local";
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
+
+		pm8841_s3: regulator@1a00 {
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1050000>;
 			qcom,enable-time = <500>;
 			qcom,pull-down-enable = <1>;
 			regulator-always-on;
 			status = "okay";
 		};
 
-		pm8841_s6: regulator@2300 {
-			regulator-min-microvolt = <850000>;
-			regulator-max-microvolt = <1100000>;
-			qcom,enable-time = <500>;
-			qcom,pull-down-enable = <1>;
-			status = "okay";
-		};
-
-		pm8841_s7: regulator@2600 {
-			regulator-min-microvolt = <850000>;
-			regulator-max-microvolt = <1100000>;
-			qcom,enable-time = <500>;
-			qcom,pull-down-enable = <1>;
-			status = "okay";
-		};
-
-		pm8841_s8: regulator@2900 {
-			regulator-min-microvolt = <850000>;
-			regulator-max-microvolt = <1100000>;
+		pm8841_s4: regulator@1d00 {
+			regulator-min-microvolt = <900000>;
+			regulator-max-microvolt = <900000>;
 			qcom,enable-time = <500>;
 			qcom,pull-down-enable = <1>;
 			status = "okay";
@@ -76,7 +317,6 @@
 	};
 };
 
-
 /* RPM controlled regulators: */
 
 &rpm_bus {
@@ -124,39 +364,6 @@
 		};
 	};
 
-	rpm-regulator-smpb3 {
-		status = "okay";
-		pm8841_s3: regulator-s3 {
-			regulator-min-microvolt = <1150000>;
-			regulator-max-microvolt = <1150000>;
-			qcom,init-voltage = <1150000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-smpb4 {
-		status = "okay";
-		pm8841_s4: regulator-s4 {
-			regulator-min-microvolt = <900000>;
-			regulator-max-microvolt = <900000>;
-			qcom,init-voltage = <900000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-smpa1 {
-		status = "okay";
-		pm8941_s1: regulator-s1 {
-			regulator-min-microvolt = <1300000>;
-			regulator-max-microvolt = <1300000>;
-			qcom,init-voltage = <1300000>;
-			qcom,init-current = <100>;
-			qcom,system-load = <100000>;
-			regulator-always-on;
-			status = "okay";
-		};
-	};
-
 	rpm-regulator-smpa2 {
 		status = "okay";
 		qcom,allow-atomic = <1>;
@@ -176,140 +383,6 @@
 		};
 	};
 
-	rpm-regulator-smpa3 {
-		status = "okay";
-		pm8941_s3: regulator-s3 {
-			regulator-min-microvolt = <1800000>;
-			regulator-max-microvolt = <1800000>;
-			qcom,init-voltage = <1800000>;
-			qcom,init-current = <100>;
-			qcom,system-load = <100000>;
-			regulator-always-on;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa1 {
-		status = "okay";
-		pm8941_l1: regulator-l1 {
-			parent-supply = <&pm8941_s1>;
-			regulator-min-microvolt = <1225000>;
-			regulator-max-microvolt = <1225000>;
-			qcom,init-voltage = <1225000>;
-			qcom,init-current = <10>;
-			qcom,system-load = <10000>;
-			regulator-always-on;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa2 {
-		status = "okay";
-		pm8941_l2: regulator-l2 {
-			parent-supply = <&pm8941_s3>;
-			regulator-min-microvolt = <1200000>;
-			regulator-max-microvolt = <1200000>;
-			qcom,init-voltage = <1200000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa3 {
-		status = "okay";
-		pm8941_l3: regulator-l3 {
-			parent-supply = <&pm8941_s1>;
-			regulator-min-microvolt = <1225000>;
-			regulator-max-microvolt = <1225000>;
-			qcom,init-voltage = <1225000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa4 {
-		status = "okay";
-		pm8941_l4: regulator-l4 {
-			parent-supply = <&pm8941_s1>;
-			regulator-min-microvolt = <12250000>;
-			regulator-max-microvolt = <12250000>;
-			qcom,init-voltage = <12250000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa5 {
-		status = "okay";
-		pm8941_l5: regulator-l5 {
-			parent-supply = <&pm8941_s2>;
-			regulator-min-microvolt = <1800000>;
-			regulator-max-microvolt = <1800000>;
-			qcom,init-voltage = <1800000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa6 {
-		status = "okay";
-		pm8941_l6: regulator-l6 {
-			parent-supply = <&pm8941_s2>;
-			regulator-min-microvolt = <1800000>;
-			regulator-max-microvolt = <1800000>;
-			qcom,init-voltage = <1800000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa7 {
-		status = "okay";
-		pm8941_l7: regulator-l7 {
-			parent-supply = <&pm8941_s2>;
-			regulator-min-microvolt = <1800000>;
-			regulator-max-microvolt = <1800000>;
-			qcom,init-voltage = <1800000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa8 {
-		status = "okay";
-		pm8941_l8: regulator-l8 {
-			regulator-min-microvolt = <1800000>;
-			regulator-max-microvolt = <1800000>;
-			qcom,init-voltage = <1800000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa9 {
-		status = "okay";
-		pm8941_l9: regulator-l9 {
-			regulator-min-microvolt = <1800000>;
-			regulator-max-microvolt = <2950000>;
-			qcom,init-voltage = <2950000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa10 {
-		status = "okay";
-		pm8941_l10: regulator-l10 {
-			regulator-min-microvolt = <1800000>;
-			regulator-max-microvolt = <2950000>;
-			qcom,init-voltage = <2950000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa11 {
-		status = "okay";
-		pm8941_l11: regulator-l11 {
-			parent-supply = <&pm8941_s1>;
-			regulator-min-microvolt = <1300000>;
-			regulator-max-microvolt = <1300000>;
-			qcom,init-voltage = <1300000>;
-			status = "okay";
-		};
-	};
-
 	rpm-regulator-ldoa12 {
 		status = "okay";
 		qcom,allow-atomic = <1>;
@@ -329,152 +402,6 @@
 			compatible = "qcom,rpm-regulator-smd";
 		};
 	};
-
-	rpm-regulator-ldoa13 {
-		status = "okay";
-		pm8941_l13: regulator-l13 {
-			regulator-min-microvolt = <1800000>;
-			regulator-max-microvolt = <2950000>;
-			qcom,init-voltage = <2950000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa14 {
-		status = "okay";
-		pm8941_l14: regulator-l14 {
-			parent-supply = <&pm8941_s2>;
-			regulator-min-microvolt = <1800000>;
-			regulator-max-microvolt = <1800000>;
-			qcom,init-voltage = <1800000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa15 {
-		status = "okay";
-		pm8941_l15: regulator-l15 {
-			parent-supply = <&pm8941_s2>;
-			regulator-min-microvolt = <2050000>;
-			regulator-max-microvolt = <2050000>;
-			qcom,init-voltage = <2050000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa16 {
-		status = "okay";
-		pm8941_l16: regulator-l16 {
-			regulator-min-microvolt = <2700000>;
-			regulator-max-microvolt = <2700000>;
-			qcom,init-voltage = <2700000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa17 {
-		status = "okay";
-		pm8941_l17: regulator-l17 {
-			regulator-min-microvolt = <2850000>;
-			regulator-max-microvolt = <2850000>;
-			qcom,init-voltage = <2850000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa18 {
-		status = "okay";
-		pm8941_l18: regulator-l18 {
-			regulator-min-microvolt = <2850000>;
-			regulator-max-microvolt = <2850000>;
-			qcom,init-voltage = <2850000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa19 {
-		status = "okay";
-		pm8941_l19: regulator-l19 {
-			regulator-min-microvolt = <2900000>;
-			regulator-max-microvolt = <2900000>;
-			qcom,init-voltage = <2900000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa20 {
-		status = "okay";
-		pm8941_l20: regulator-l20 {
-			regulator-min-microvolt = <2950000>;
-			regulator-max-microvolt = <2950000>;
-			qcom,init-voltage = <2950000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa21 {
-		status = "okay";
-		pm8941_l21: regulator-l21 {
-			regulator-min-microvolt = <2950000>;
-			regulator-max-microvolt = <2950000>;
-			qcom,init-voltage = <2950000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa22 {
-		status = "okay";
-		pm8941_l22: regulator-l22 {
-			regulator-min-microvolt = <3000000>;
-			regulator-max-microvolt = <3000000>;
-			qcom,init-voltage = <3000000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa23 {
-		status = "okay";
-		pm8941_l23: regulator-l23 {
-			regulator-min-microvolt = <3000000>;
-			regulator-max-microvolt = <3000000>;
-			qcom,init-voltage = <3000000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-ldoa24 {
-		status = "okay";
-		pm8941_l24: regulator-l24 {
-			regulator-min-microvolt = <3075000>;
-			regulator-max-microvolt = <3075000>;
-			qcom,init-voltage = <3075000>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-vsa1 {
-		status = "okay";
-		pm8941_lvs1: regulator-lvs1 {
-			parent-supply = <&pm8941_s3>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-vsa2 {
-		status = "okay";
-		pm8941_lvs2: regulator-lvs2 {
-			parent-supply = <&pm8941_s3>;
-			status = "okay";
-		};
-	};
-
-	rpm-regulator-vsa3 {
-		status = "okay";
-		pm8941_lvs3: regulator-lvs3 {
-			parent-supply = <&pm8941_s3>;
-			status = "okay";
-		};
-	};
 };
 
 / {
diff --git a/arch/arm/boot/dts/msm8974-rumi.dts b/arch/arm/boot/dts/msm8974-rumi.dts
index 2cf68b8..35331517 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dts
+++ b/arch/arm/boot/dts/msm8974-rumi.dts
@@ -17,13 +17,14 @@
 / {
 	model = "Qualcomm MSM 8974 RUMI";
 	compatible = "qcom,msm8974-rumi", "qcom,msm8974";
+	qcom,msm-id = <126 15 0>;
 
 	timer {
 		clock-frequency = <5000000>;
 	};
 
-	serial@f991f000 {
-		status = "disable";
+	serial@f995e000 {
+		status = "ok";
 	};
 
 	usb@f9a55000 {
@@ -88,6 +89,10 @@
 		status = "disable";
 	};
 
+	qcom,mdss_dsi@fd922800 {
+		status = "disable";
+	};
+
 	qcom,spmi@fc4c0000 {
 		status = "disable";
 	};
diff --git a/arch/arm/boot/dts/msm8974-sim.dts b/arch/arm/boot/dts/msm8974-sim.dts
index b6044a6..d5368fa 100644
--- a/arch/arm/boot/dts/msm8974-sim.dts
+++ b/arch/arm/boot/dts/msm8974-sim.dts
@@ -13,8 +13,86 @@
 /dts-v1/;
 
 /include/ "msm8974.dtsi"
+/include/ "dsi-panel-sim-video.dtsi"
 
 / {
 	model = "Qualcomm MSM 8974 Simulator";
 	compatible = "qcom,msm8974-sim", "qcom,msm8974";
+	qcom,msm-id = <126 16 0>;
+
+	qcom,mdss_dsi@fd922800 {
+		qcom,mdss_dsi_sim_video {
+			status = "ok";
+		};
+	};
+
+	serial@f991f000 {
+		status = "ok";
+	};
+
+	serial@f995e000 {
+		status = "ok";
+	};
+};
+
+&jpeg_iommu {
+		qcom,iommu-ctx@fda6c000 {
+			interrupts = <0 69 0>;
+		};
+
+		qcom,iommu-ctx@fda6d000 {
+			interrupts = <0 70 0>;
+		};
+
+		qcom,iommu-ctx@fda6e000 {
+			interrupts = <0 71 0>;
+		};
+};
+
+&mdp_iommu {
+		qcom,iommu-ctx@fd930000 {
+			interrupts = <0 46 0>;
+		};
+
+		qcom,iommu-ctx@fd931000 {
+			interrupts = <0 47 0>;
+		};
+};
+
+&venus_iommu {
+		qcom,iommu-ctx@fdc8c000 {
+			interrupts = <0 43 0>;
+		};
+
+		qcom,iommu-ctx@fdc8d000 {
+			interrupts = <0 42 0>;
+		};
+
+		qcom,iommu-ctx@fdc8e000 {
+			interrupts = <0 41 0>;
+		};
+};
+
+&kgsl_iommu {
+		qcom,iommu-ctx@fdb18000 {
+			interrupts = <0 240 0>;
+		};
+
+		qcom,iommu-ctx@fdb19000 {
+			interrupts = <0 241 0>;
+		};
+};
+
+&vfe_iommu {
+		qcom,iommu-ctx@fda4c000 {
+			interrupts = <0 64 0>;
+		};
+
+		qcom,iommu-ctx@fda4d000 {
+			interrupts = <0 65 0>;
+		};
+
+		qcom,iommu-ctx@fda4e000 {
+			interrupts = <0 66 0>;
+		};
 };
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index edb57dd..166a17d 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -13,7 +13,12 @@
 /include/ "skeleton.dtsi"
 /include/ "msm8974_pm.dtsi"
 /include/ "msm8974-iommu.dtsi"
+/include/ "msm8974-camera.dtsi"
+/include/ "msm8974-coresight.dtsi"
 /include/ "msm-gdsc.dtsi"
+/include/ "msm8974-ion.dtsi"
+/include/ "msm8974-gpu.dtsi"
+/include/ "msm8974-mdss.dtsi"
 
 / {
 	model = "Qualcomm MSM 8974";
@@ -30,10 +35,11 @@
 
 	msmgpio: gpio@fd510000 {
 		compatible = "qcom,msm-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
 		reg = <0xfd510000 0x4000>;
-		#gpio-cells = <2>;
 	};
 
 	timer {
@@ -60,18 +66,28 @@
 		compatible = "qcom,msm-lsuart-v14";
 		reg = <0xf991f000 0x1000>;
 		interrupts = <0 109 0>;
+		status = "disabled";
 	};
 
 	serial@f995e000 {
 		compatible = "qcom,msm-lsuart-v14";
 		reg = <0xf995e000 0x1000>;
 		interrupts = <0 114 0>;
+		status = "disabled";
+	};
+
+	serial@f991e000 {
+		compatible = "qcom,msm-lsuart-v14";
+		reg = <0xf991e000 0x1000>;
+		interrupts = <0 108 0>;
+		status = "disabled";
 	};
 
 	usb@f9a55000 {
 		compatible = "qcom,hsusb-otg";
 		reg = <0xf9a55000 0x400>;
-		interrupts = <0 134 0>;
+		interrupts = <0 134 0 0 140 0>;
+		interrupt-names = "core_irq", "async_irq";
 		HSUSB_VDDCX-supply = <&pm8841_s2>;
 		HSUSB_1p8-supply = <&pm8941_l6>;
 		HSUSB_3p3-supply = <&pm8941_l24>;
@@ -79,13 +95,16 @@
 		qcom,hsusb-otg-phy-type = <2>;
 		qcom,hsusb-otg-mode = <1>;
 		qcom,hsusb-otg-otg-control = <1>;
+		qcom,hsusb-otg-disable-reset;
 	};
 
 	qcom,sdcc@f9824000 {
 		cell-index = <1>; /* SDC1 eMMC slot */
 		compatible = "qcom,msm-sdcc";
 		reg = <0xf9824000 0x1000>;
+		reg-names = "core_mem";
 		interrupts = <0 123 0>;
+		interrupt-names = "core_irq";
 		vdd-supply = <&pm8941_l20>;
 		vdd-io-supply = <&pm8941_s3>;
 
@@ -112,7 +131,9 @@
 		cell-index = <2>; /* SDC2 SD card slot */
 		compatible = "qcom,msm-sdcc";
 		reg = <0xf98a4000 0x1000>;
+		reg-names = "core_mem";
 		interrupts = <0 125 0>;
+		interrupt-names = "core_irq";
 		vdd-supply = <&pm8941_l21>;
 		vdd-io-supply = <&pm8941_l13>;
 
@@ -141,7 +162,9 @@
 		cell-index = <3>; /* SDC3 SDIO slot */
 		compatible = "qcom,msm-sdcc";
 		reg = <0xf9864000 0x1000>;
+		reg-names = "core_mem";
 		interrupts = <0 127 0>;
+		interrupt-names = "core_irq";
 
 		gpios = <&msmgpio 40 0>, /* CLK */
 			<&msmgpio 39 0>, /* CMD */
@@ -162,7 +185,9 @@
 		cell-index = <4>; /* SDC4 SDIO slot */
 		compatible = "qcom,msm-sdcc";
 		reg = <0xf98e4000 0x1000>;
+		reg-names = "core_mem";
 		interrupts = <0 129 0>;
+		interrupt-names = "core_irq";
 
 		gpios = <&msmgpio 93 0>, /* CLK */
 			<&msmgpio 91 0>, /* CMD */
@@ -205,6 +230,54 @@
 		interrupts = <0 163 0 0 164 0>;
 		interrupt-names = "slimbus_irq", "slimbus_bam_irq";
 		qcom,min-clk-gear = <10>;
+		qcom,rxreg-access;
+
+		taiko_codec {
+			compatible = "qcom,taiko-slim-pgd";
+			elemental-addr = [00 01 A0 00 17 02];
+
+			qcom,cdc-reset-gpio = <&msmgpio 63 0>;
+
+			cdc-vdd-buck-supply = <&pm8941_s2>;
+			qcom,cdc-vdd-buck-voltage = <2150000 2150000>;
+			qcom,cdc-vdd-buck-current = <650000>;
+
+			cdc-vdd-tx-h-supply = <&pm8941_s3>;
+			qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+			qcom,cdc-vdd-tx-h-current = <25000>;
+
+			cdc-vdd-rx-h-supply = <&pm8941_s3>;
+			qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+			qcom,cdc-vdd-rx-h-current = <25000>;
+
+			cdc-vddpx-1-supply = <&pm8941_s3>;
+			qcom,cdc-vddpx-1-voltage = <1800000 1800000>;
+			qcom,cdc-vddpx-1-current = <10000>;
+
+			cdc-vdd-a-1p2v-supply = <&pm8941_l1>;
+			qcom,cdc-vdd-a-1p2v-voltage = <1225000 1225000>;
+			qcom,cdc-vdd-a-1p2v-current = <10000>;
+
+			cdc-vddcx-1-supply = <&pm8941_l1>;
+			qcom,cdc-vddcx-1-voltage = <1225000 1225000>;
+			qcom,cdc-vddcx-1-current = <10000>;
+
+			cdc-vddcx-2-supply = <&pm8941_l1>;
+			qcom,cdc-vddcx-2-voltage = <1225000 1225000>;
+			qcom,cdc-vddcx-2-current = <10000>;
+
+			qcom,cdc-micbias-ldoh-v = <0x3>;
+			qcom,cdc-micbias-cfilt1-mv = <1800>;
+			qcom,cdc-micbias-cfilt2-mv = <2700>;
+			qcom,cdc-micbias-cfilt3-mv = <1800>;
+			qcom,cdc-micbias1-cfilt-sel = <0x0>;
+			qcom,cdc-micbias2-cfilt-sel = <0x1>;
+			qcom,cdc-micbias3-cfilt-sel = <0x2>;
+			qcom,cdc-micbias4-cfilt-sel = <0x2>;
+
+			qcom,cdc-slim-ifd = "taiko-slim-ifd";
+			qcom,cdc-slim-ifd-elemental-addr = [00 00 A0 00 17 02];
+		};
 	};
 
 	spmi_bus: qcom,spmi@fc4c0000 {
@@ -217,97 +290,142 @@
 		interrupts = <0 190 0 0 187 0>;
 		qcom,pmic-arb-ee = <0>;
 		qcom,pmic-arb-channel = <0>;
-		qcom,pmic-arb-ppid-map = <0x13000000>, /* PM8941_LDO1 */
-					 <0x13100001>, /* PM8941_LDO2 */
-					 <0x13200002>, /* PM8941_LDO3 */
-					 <0x13300003>, /* PM8941_LDO4 */
-					 <0x13400004>, /* PM8941_LDO5 */
-					 <0x13500005>, /* PM8941_LDO6 */
-					 <0x13600006>, /* PM8941_LDO7 */
-					 <0x13700007>, /* PM8941_LDO8 */
-					 <0x13800008>, /* PM8941_LDO9 */
-					 <0x13900009>, /* PM8941_LDO10 */
-					 <0x13a0000a>, /* PM8941_LDO11 */
-					 <0x13b0000b>, /* PM8941_LDO12 */
-					 <0x13c0000c>, /* PM8941_LDO13 */
-					 <0x13d0000d>, /* PM8941_LDO14 */
-					 <0x13e0000e>, /* PM8941_LDO15 */
-					 <0x13f0000f>, /* PM8941_LDO16 */
-					 <0x14000010>, /* PM8941_LDO17 */
-					 <0x14100011>, /* PM8941_LDO18 */
-					 <0x14200012>, /* PM8941_LDO19 */
-					 <0x14300013>, /* PM8941_LDO20 */
-					 <0x14400014>, /* PM8941_LDO21 */
-					 <0x14500015>, /* PM8941_LDO22 */
-					 <0x14600016>, /* PM8941_LDO23 */
-					 <0x14700017>, /* PM8941_LDO24 */
-					 <0x14800018>, /* PM8941_LDO25 */
-					 <0x14900019>, /* PM8941_LDO26 */
-					 <0x0c00001a>, /* PM8941_GPIO1 */
-					 <0x0c10001b>, /* PM8941_GPIO2 */
-					 <0x0c20001c>, /* PM8941_GPIO3 */
-					 <0x0c30001d>, /* PM8941_GPIO4 */
-					 <0x0c40001e>, /* PM8941_GPIO5 */
-					 <0x0c50001f>, /* PM8941_GPIO6 */
-					 <0x0c600020>, /* PM8941_GPIO7 */
-					 <0x0c700021>, /* PM8941_GPIO8 */
-					 <0x0c800022>, /* PM8941_GPIO9 */
-					 <0x0c900023>, /* PM8941_GPIO10 */
-					 <0x0ca00024>, /* PM8941_GPIO11 */
-					 <0x0cb00025>, /* PM8941_GPIO12 */
-					 <0x0cc00026>, /* PM8941_GPIO13 */
-					 <0x0cd00027>, /* PM8941_GPIO14 */
-					 <0x0ce00028>, /* PM8941_GPIO15 */
-					 <0x0cf00029>, /* PM8941_GPIO16 */
-					 <0x0d00002a>, /* PM8941_GPIO17 */
-					 <0x0d10002b>, /* PM8941_GPIO18 */
-					 <0x0d20002c>, /* PM8941_GPIO19 */
-					 <0x0d30002d>, /* PM8941_GPIO20 */
-					 <0x0d40002e>, /* PM8941_GPIO21 */
-					 <0x0d50002f>, /* PM8941_GPIO22 */
-					 <0x0d600030>, /* PM8941_GPIO23 */
-					 <0x0d700031>, /* PM8941_GPIO24 */
-					 <0x0d800032>, /* PM8941_GPIO25 */
-					 <0x0d900033>, /* PM8941_GPIO26 */
-					 <0x0da00034>, /* PM8941_GPIO27 */
-					 <0x0db00035>, /* PM8941_GPIO28 */
-					 <0x0dc00036>, /* PM8941_GPIO29 */
-					 <0x0dd00037>, /* PM8941_GPIO30 */
-					 <0x0de00038>, /* PM8941_GPIO31 */
-					 <0x0df00039>, /* PM8941_GPIO32 */
-					 <0x0e00003a>, /* PM8941_GPIO33 */
-					 <0x0e10003b>, /* PM8941_GPIO34 */
-					 <0x0e20003c>, /* PM8941_GPIO35 */
-					 <0x0e30003d>, /* PM8941_GPIO36 */
-					 <0x0280003e>, /* COINCELL */
-					 <0x0100003f>, /* SMBC_OVP */
-					 <0x01100040>, /* SMBC_CHG */
-					 <0x01200041>, /* SMBC_BIF */
-					 <0x00500042>, /* INTERRUPT */
-					 <0x00100043>, /* PM8941_0 */
-					 <0x20100044>, /* PM8841_0 */
-					 <0x10100045>, /* PM8941_1 */
-					 <0x30100046>, /* PM8841_1 */
-					 <0x00800047>, /* PON0 */
-					 <0x20800048>, /* PON1 */
-					 <0x11000049>, /* PM8941_SMPS1 */
-					 <0x1110004a>, /* PM8941_SMPS2 */
-					 <0x1120004b>, /* PM8941_SMPS3 */
-					 <0x3100004c>, /* PM8841_SMPS1 */
-					 <0x3110004d>, /* PM8841_SMPS2 */
-					 <0x3120004e>, /* PM8841_SMPS3 */
-					 <0x3130004f>, /* PM8841_SMPS4 */
-					 <0x31400050>, /* PM8841_SMPS5 */
-					 <0x31500051>, /* PM8841_SMPS6 */
-					 <0x31600052>, /* PM8841_SMPS7 */
-					 <0x31700053>, /* PM8841_SMPS8 */
-					 <0x05000054>, /* SHARED_XO */
-					 <0x05100055>, /* BB_CLK1 */
-					 <0x05200056>, /* BB_CLK2 */
-					 <0x05900057>, /* SLEEP_CLK */
-					 <0x07000058>, /* PBS_CORE */
-					 <0x07100059>, /* PBS_CLIENT1 */
-					 <0x0720005a>; /* PBS_CLIENT2 */
+		qcom,pmic-arb-ppid-map = <0x40400000>, /* BUS */
+					 <0x40500001>, /* INT */
+					 <0x40600002>, /* SPMI */
+					 <0x40800003>, /* PON */
+					 <0x42400004>, /* TEMP_ALARM */
+					 <0x47000005>, /* PBS_CORE */
+					 <0x47100006>, /* PBS_CLIENT0 */
+					 <0x47200007>, /* PBS_CLIENT1 */
+					 <0x47300008>, /* PBS_CLIENT2 */
+					 <0x47400009>, /* PBS_CLIENT3 */
+					 <0x4750000a>, /* PBS_CLIENT4 */
+					 <0x4760000b>, /* PBS_CLIENT5 */
+					 <0x4770000c>, /* PBS_CLIENT6 */
+					 <0x4780000d>, /* PBS_CLIENT7 */
+					 <0x4a00000e>, /* MPP1 */
+					 <0x4a100021>, /* MPP2 */
+					 <0x4a20000f>, /* MPP3 */
+					 <0x4a300010>, /* MPP4 */
+					 <0x51000011>, /* BCLK_GEN_MAIN */
+					 <0x51d00012>, /* S4_CTRL */
+					 <0x51e00013>, /* S4_PS */
+					 <0x51f00014>, /* S4_FREQ */
+					 <0x52000015>, /* S5_CTRL */
+					 <0x52100016>, /* S5_PS */
+					 <0x52200017>, /* S5_FREQ */
+					 <0x52300018>, /* S6_CTRL */
+					 <0x52400019>, /* S6_PS */
+					 <0x5250001a>, /* S6_FREQ */
+					 <0x5260001b>, /* S7_CTRL */
+					 <0x5270001c>, /* S7_PS */
+					 <0x5280001d>, /* S7_FREQ */
+					 <0x5290001e>, /* S8_CTRL */
+					 <0x52a0001f>, /* S8_PS */
+					 <0x52b00020>, /* S8_FREQ */
+					 <0x00400022>, /* BUS */
+					 <0x00500023>, /* INT */
+					 <0x00600024>, /* SPMI */
+					 <0x00800025>, /* PON */
+					 <0x00b00027>, /* VREG_TFT */
+					 <0x01000028>, /* SMBB_CHGR */
+					 <0x01100029>, /* SMBB_BUCK */
+					 <0x0120002a>, /* SMBB_BAT_IF */
+					 <0x0130002b>, /* SMBB_USB_CHGPTH */
+					 <0x0140002c>, /* SMBB_DC_CHGPTH */
+					 <0x0150002d>, /* SMBB_BOOST */
+					 <0x0160002e>, /* SMBB_MISC */
+					 <0x0170002f>, /* SMBB_FREQ */
+					 <0x02400030>, /* TEMP_ALARM */
+					 <0x02800031>, /* COIN */
+					 <0x03100032>, /* VADC1_USR */
+					 <0x03300033>, /* VADC1_BMS */
+					 <0x03400034>, /* VADC2_BTM */
+					 <0x03600035>, /* IADC1_USR */
+					 <0x03800036>, /* IADC1_BMS */
+					 <0x04000037>, /* BMS1 */
+					 <0x05700039>, /* DIFF_CLK1 */
+					 <0x05c0003b>, /* DIV_CLK2 */
+					 <0x0610003d>, /* RTC_ALARM */
+					 <0x0620003e>, /* RTC_TIMER */
+					 <0x07100040>, /* PBS_CLIENT0 */
+					 <0x07200041>, /* PBS_CLIENT1 */
+					 <0x07300042>, /* PBS_CLIENT2 */
+					 <0x07400043>, /* PBS_CLIENT3 */
+					 <0x07500044>, /* PBS_CLIENT4 */
+					 <0x07600045>, /* PBS_CLIENT5 */
+					 <0x07700046>, /* PBS_CLIENT6 */
+					 <0x07800047>, /* PBS_CLIENT7 */
+					 <0x07900048>, /* PBS_CLIENT8 */
+					 <0x07a00049>, /* PBS_CLIENT9 */
+					 <0x07b0004a>, /* PBS_CLIENT10 */
+					 <0x07c0004b>, /* PBS_CLIENT11 */
+					 <0x07d0004c>, /* PBS_CLIENT12 */
+					 <0x07e0004d>, /* PBS_CLIENT13 */
+					 <0x07f0004e>, /* PBS_CLIENT14 */
+					 <0x0800004f>, /* PBS_CLIENT15 */
+					 <0x0a100050>, /* MPP2 */
+					 <0x0a300051>, /* MPP4 */
+					 <0x0a400052>, /* MPP5 */
+					 <0x0a500053>, /* MPP6 */
+					 <0x0a600054>, /* MPP7 */
+					 <0x0a700055>, /* MPP8 */
+					 <0x0c000056>, /* GPIO1 */
+					 <0x0c100057>, /* GPIO2 */
+					 <0x0c200058>, /* GPIO3 */
+					 <0x0c300059>, /* GPIO4 */
+					 <0x0c40005a>, /* GPIO5 */
+					 <0x0c50005b>, /* GPIO6 */
+					 <0x0c60005c>, /* GPIO7 */
+					 <0x0c70005d>, /* GPIO8 */
+					 <0x0c80005e>, /* GPIO9 */
+					 <0x0c90005f>, /* GPIO10 */
+					 <0x0ca00060>, /* GPIO11 */
+					 <0x0cb00061>, /* GPIO12 */
+					 <0x0cc00062>, /* GPIO13 */
+					 <0x0cd00063>, /* GPIO14 */
+					 <0x0ce00064>, /* GPIO15 */
+					 <0x0cf00065>, /* GPIO16 */
+					 <0x0d200066>, /* GPIO19 */
+					 <0x0d300067>, /* GPIO20 */
+					 <0x0d500068>, /* GPIO22 */
+					 <0x0d600069>, /* GPIO23 */
+					 <0x0d70006a>, /* GPIO24 */
+					 <0x0d80006b>, /* GPIO25 */
+					 <0x0d90006c>, /* GPIO26 */
+					 <0x0da0006d>, /* GPIO27 */
+					 <0x0dc0006e>, /* GPIO29 */
+					 <0x0dd0006f>, /* GPIO30 */
+					 <0x0df00070>, /* GPIO32 */
+					 <0x0e000071>, /* GPIO33 */
+					 <0x0e100072>, /* GPIO34 */
+					 <0x0e200073>, /* GPIO35 */
+					 <0x0e300074>, /* GPIO36 */
+					 <0x11000075>, /* BUCK_CMN */
+					 <0x1a000076>, /* BOOST */
+					 <0x1a100077>, /* BOOST_FREQ */
+					 <0x1a800078>, /* KEYPAD1 */
+					 <0x1b000079>, /* LPG_LUT */
+					 <0x1b10007a>, /* LPG_CHAN1 */
+					 <0x1b20007b>, /* LPG_CHAN2 */
+					 <0x1b30007c>, /* LPG_CHAN3 */
+					 <0x1b40007d>, /* LPG_CHAN4 */
+					 <0x1b50007e>, /* LPG_CHAN5 */
+					 <0x1b60007f>, /* LPG_CHAN6 */
+					 <0x1b700080>, /* LPG_CHAN7 */
+					 <0x1b800081>, /* LPG_CHAN8 */
+					 <0x1bc00082>, /* PWM_3D */
+					 <0x1c000083>, /* VIB1 */
+					 <0x1d000084>, /* TRI_LED */
+					 <0x1d300085>, /* FLASH1 */
+					 <0x1d800086>, /* WLED1 */
+					 <0x1e200087>, /* KPDBL_MAIN */
+					 <0x1e300088>, /* KPDBL_LUT */
+					 <0x1e400089>, /* LPG_CHAN9 */
+					 <0x1e50008a>, /* LPG_CHAN10 */
+					 <0x1e60008b>, /* LPG_CHAN11 */
+					 <0x1e70008c>; /* LPG_CHAN12 */
 	};
 
 	i2c@f9966000 {
@@ -347,9 +465,9 @@
 		l2_hfpll_b-supply = <&pm8941_l12_ao>;
 	};
 
-	qcom,ssusb@F9200000 {
+	qcom,ssusb@f9200000 {
 		compatible = "qcom,dwc-usb3-msm";
-		reg = <0xF9200000 0xFA000>;
+		reg = <0xf9200000 0xfc000>;
 		interrupts = <0 131 0 0 179 0>;
 		interrupt-names = "irq", "otg_irq";
 		SSUSB_VDDCX-supply = <&pm8841_s2>;
@@ -452,7 +570,8 @@
 		reg = <0xfc880000 0x100>,
 		      <0xfd485000 0x400>,
 		      <0xfc820000 0x020>,
-		      <0xfc401680 0x004>;
+		      <0xfc401680 0x004>,
+		      <0xfc980008 0x004>;
 		vdd_mss-supply = <&pm8841_s3>;
 
 		qcom,firmware-name = "mba";
@@ -488,6 +607,7 @@
 		interrupts = <0 76 0 0 77 0>;
 		interrupt-names = "ocmem_irq", "dm_irq";
 		qcom,ocmem-num-regions = <0x3>;
+		qcom,resource-type = <0x706d636f>;
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges = <0x0 0xfec00000 0x180000>;
@@ -538,21 +658,6 @@
 		compatible = "qcom,qseecom";
 	};
 
-	qcom,mdss_mdp@fd900000 {
-		cell-index = <0>;
-		compatible = "qcom,mdss_mdp";
-		reg = <0xfd900000 0x22100>;
-		interrupts = <0 72 0>;
-		vdd-supply = <&gdsc_mdss>;
-	};
-
-	qcom,mdss_wb_panel {
-		cell-index = <1>;
-		compatible = "qcom,mdss_wb";
-		qcom,mdss_pan_res = <640 480>;
-		qcom,mdss_pan_bpp = <24>;
-	};
-
 	qcom,wdt@f9017000 {
 		compatible = "qcom,msm-watchdog";
 		reg = <0xf9017000 0x1000>;
@@ -591,8 +696,8 @@
 		reg-names = "tsens_physical", "tsens_eeprom_physical";
 		interrupts = <0 184 0>;
 		qcom,sensors = <11>;
-		qcom,slope = <1134 1122 1142 1123 1176 1176 1176 1186 1176
-				1176 1176>;
+		qcom,slope = <3200 3200 3200 3200 3200 3200 3200 3200 3200
+				3200 3200>;
 	};
 
 	qcom,msm-rtb {
@@ -605,16 +710,94 @@
 		compatible = "qcom,qcedev";
 		reg = <0xfd440000 0x20000>,
 		      <0xfd444000 0x8000>;
+		reg-names = "crypto-base","crypto-bam-base";
 		interrupts = <0 235 0>;
-		qcom,bam-pipes = <0>;
+		qcom,bam-pipe-pair = <0>;
 	};
 
         qcom,qcrypto@fd444000 {
 		compatible = "qcom,qcrypto";
 		reg = <0xfd440000 0x20000>,
 		      <0xfd444000 0x8000>;
+		reg-names = "crypto-base","crypto-bam-base";
 		interrupts = <0 235 0>;
-		qcom,bam-pipes = <1>;
+		qcom,bam-pipe-pair = <1>;
+	};
+
+	qcom,usbbam@f9304000 {
+		compatible = "qcom,usb-bam-msm";
+		reg = <0xf9304000 0x9000>;
+		interrupts = <0 132 0>;
+		qcom,usb-active-bam = <0>;
+		qcom,usb-total-bam-num = <1>;
+		qcom,usb-bam-num-pipes = <16>;
+		qcom,usb-base-address = <0xf9200000>;
+
+		qcom,pipe1 {
+			label = "usb-to-peri-qdss-dwc3";
+			qcom,usb-bam-type = <0>;
+			qcom,src-bam-physical-address = <0>;
+			qcom,src-bam-pipe-index = <0>;
+			qcom,dst-bam-physical-address = <0>;
+			qcom,dst-bam-pipe-index = <0>;
+			qcom,data-fifo-offset = <0>;
+			qcom,data-fifo-size = <0>;
+			qcom,descriptor-fifo-offset = <0>;
+			qcom,descriptor-fifo-size = <0>;
+		};
+
+		qcom,pipe2 {
+			label = "peri-to-usb-qdss-dwc3";
+			qcom,usb-bam-type = <0>;
+			qcom,src-bam-physical-address = <0xfc37C000>;
+			qcom,src-bam-pipe-index = <0>;
+			qcom,dst-bam-physical-address = <0xf9304000>;
+			qcom,dst-bam-pipe-index = <2>;
+			qcom,data-fifo-offset = <0xf0000>;
+			qcom,data-fifo-size = <0x4000>;
+			qcom,descriptor-fifo-offset = <0xf4000>;
+			qcom,descriptor-fifo-size = <0x1400>;
+		};
+	};
+
+	qcom,msm-thermal {
+		compatible = "qcom,msm-thermal";
+		qcom,sensor-id = <0>;
+		qcom,poll-ms = <250>;
+		qcom,limit-temp = <60>;
+		qcom,temp-hysteresis = <10>;
+		qcom,freq-step = <2>;
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&pm8941_gpios 3 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&pm8941_gpios 4 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&pm8941_gpios 5 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm9625.dts b/arch/arm/boot/dts/msm9625.dts
index 6b44be9..041b4dd1 100644
--- a/arch/arm/boot/dts/msm9625.dts
+++ b/arch/arm/boot/dts/msm9625.dts
@@ -26,8 +26,19 @@
 		      <0xF9002000 0x1000>;
 	};
 
+	l2: cache-controller@f9040000 {
+		compatible = "arm,pl310-cache";
+		reg = <0xf9040000 0x1000>;
+		arm,data-latency = <1 1 1>;
+		arm,tag-latency = <1 1 1>;
+		cache-unified;
+		cache-level = <2>;
+	};
+
 	msmgpio: gpio@fd510000 {
 		compatible = "qcom,msm-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
 		reg = <0xfd510000 0x4000>;
@@ -65,4 +76,26 @@
 		interrupts = <0 247 0>;
 		interrupt-names = "bam_irq";
 	};
+
+	spi@f9928000 {
+		compatible = "qcom,spi-qup-v2";
+		reg = <0xf9928000 0x1000>;
+		interrupts = <0 100 0>;
+		spi-max-frequency = <24000000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		gpios = <&msmgpio 23 0>, /* CLK  */
+			<&msmgpio 21 0>, /* MISO */
+			<&msmgpio 20 0>; /* MOSI */
+
+		cs-gpios = <&msmgpio 69 0>;
+
+		ethernet-switch@0 {
+			compatible = "simtec,ks8851";
+			reg = <0>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <75 0>;
+			spi-max-frequency = <5000000>;
+		};
+	};
 };
diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
index 595ecd29..32e9cc6 100644
--- a/arch/arm/common/dmabounce.c
+++ b/arch/arm/common/dmabounce.c
@@ -173,7 +173,8 @@
 	read_lock_irqsave(&device_info->lock, flags);
 
 	list_for_each_entry(b, &device_info->safe_buffers, node)
-		if (b->safe_dma_addr == safe_dma_addr) {
+		if (b->safe_dma_addr <= safe_dma_addr &&
+		    b->safe_dma_addr + b->size > safe_dma_addr) {
 			rb = b;
 			break;
 		}
@@ -254,7 +255,7 @@
 	if (buf == NULL) {
 		dev_err(dev, "%s: unable to map unsafe buffer %p!\n",
 		       __func__, ptr);
-		return ~0;
+		return DMA_ERROR_CODE;
 	}
 
 	dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
@@ -320,7 +321,7 @@
 
 	ret = needs_bounce(dev, dma_addr, size);
 	if (ret < 0)
-		return ~0;
+		return DMA_ERROR_CODE;
 
 	if (ret == 0) {
 		__dma_page_cpu_to_dev(page, offset, size, dir);
@@ -329,7 +330,7 @@
 
 	if (PageHighMem(page)) {
 		dev_err(dev, "DMA buffer bouncing of HIGHMEM pages is not supported\n");
-		return ~0;
+		return DMA_ERROR_CODE;
 	}
 
 	return map_single(dev, page_address(page) + offset, size, dir);
@@ -362,9 +363,10 @@
 EXPORT_SYMBOL(__dma_unmap_page);
 
 int dmabounce_sync_for_cpu(struct device *dev, dma_addr_t addr,
-		unsigned long off, size_t sz, enum dma_data_direction dir)
+		size_t sz, enum dma_data_direction dir)
 {
 	struct safe_buffer *buf;
+	unsigned long off;
 
 	dev_dbg(dev, "%s(dma=%#x,off=%#lx,sz=%zx,dir=%x)\n",
 		__func__, addr, off, sz, dir);
@@ -373,6 +375,8 @@
 	if (!buf)
 		return 1;
 
+	off = addr - buf->safe_dma_addr;
+
 	BUG_ON(buf->direction != dir);
 
 	dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
@@ -391,9 +395,10 @@
 EXPORT_SYMBOL(dmabounce_sync_for_cpu);
 
 int dmabounce_sync_for_device(struct device *dev, dma_addr_t addr,
-		unsigned long off, size_t sz, enum dma_data_direction dir)
+		size_t sz, enum dma_data_direction dir)
 {
 	struct safe_buffer *buf;
+	unsigned long off;
 
 	dev_dbg(dev, "%s(dma=%#x,off=%#lx,sz=%zx,dir=%x)\n",
 		__func__, addr, off, sz, dir);
@@ -402,6 +407,8 @@
 	if (!buf)
 		return 1;
 
+	off = addr - buf->safe_dma_addr;
+
 	BUG_ON(buf->direction != dir);
 
 	dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 314f91b..00325c9 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -218,7 +218,6 @@
 # CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set
 CONFIG_DIAG_CHAR=y
 # CONFIG_HW_RANDOM is not set
-CONFIG_DCC_TTY=y
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 # CONFIG_I2C_MSM is not set
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index aad13b8..5c5a152 100644
--- a/arch/arm/configs/msm7630_defconfig
+++ b/arch/arm/configs/msm7630_defconfig
@@ -238,7 +238,6 @@
 CONFIG_SERIAL_MSM_HS=y
 CONFIG_DIAG_CHAR=y
 # CONFIG_HW_RANDOM is not set
-CONFIG_DCC_TTY=y
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QUP=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index f3b2219..a51b76d 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -417,8 +417,6 @@
 CONFIG_ANDROID_TIMED_GPIO=y
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 CONFIG_MSM_SSBI=y
-CONFIG_MSM_IOMMU=y
-# CONFIG_IOMMU_PGTABLES_L2 is not set
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 4748496..0efe658 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -282,7 +282,6 @@
 CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM=y
-CONFIG_DCC_TTY=y
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 # CONFIG_I2C_MSM is not set
@@ -419,8 +418,6 @@
 CONFIG_ANDROID_TIMED_GPIO=y
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 CONFIG_MSM_SSBI=y
-CONFIG_MSM_IOMMU=y
-# CONFIG_IOMMU_PGTABLES_L2 is not set
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 66e71fc..3fad6b7 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -59,7 +59,7 @@
 CONFIG_MACH_MPQ8064_HRD=y
 CONFIG_MACH_MPQ8064_DTV=y
 # CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_KERNEL_PMEM_EBI_REGION=y
+CONFIG_KERNEL_MSM_CONTIG_MEM_REGION=y
 # CONFIG_MSM_FIQ_SUPPORT is not set
 # CONFIG_MSM_PROC_COMM is not set
 CONFIG_MSM_SMD=y
@@ -233,6 +233,9 @@
 CONFIG_BT_BNEP_PROTO_FILTER=y
 CONFIG_BT_HIDP=y
 CONFIG_BT_HCISMD=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_ATH3K=y
+CONFIG_MSM_BT_POWER=y
 CONFIG_CFG80211=m
 # CONFIG_CFG80211_WEXT is not set
 CONFIG_RFKILL=y
@@ -285,6 +288,8 @@
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_PMIC8XXX_PWRKEY=y
 CONFIG_INPUT_UINPUT=y
+CONFIG_STM_LIS3DH=y
+CONFIG_INPUT_MPU3050=y
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_N_SMUX=y
 CONFIG_N_SMUX_LOOPBACK=y
@@ -351,6 +356,7 @@
 CONFIG_IMX074_EEPROM=y
 CONFIG_IMX091_EEPROM=y
 CONFIG_MSM_GEMINI=y
+CONFIG_MSM_MERCURY=y
 CONFIG_MSM_CSI20_HEADER=y
 CONFIG_S5K3L1YX=y
 CONFIG_IMX091=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 3731845..cd79e98 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -58,7 +58,7 @@
 CONFIG_MACH_MPQ8064_HRD=y
 CONFIG_MACH_MPQ8064_DTV=y
 # CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_KERNEL_PMEM_EBI_REGION=y
+CONFIG_KERNEL_MSM_CONTIG_MEM_REGION=y
 # CONFIG_MSM_FIQ_SUPPORT is not set
 # CONFIG_MSM_PROC_COMM is not set
 CONFIG_MSM_SMD=y
@@ -237,6 +237,9 @@
 CONFIG_BT_BNEP_PROTO_FILTER=y
 CONFIG_BT_HIDP=y
 CONFIG_BT_HCISMD=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_ATH3K=y
+CONFIG_MSM_BT_POWER=y
 CONFIG_CFG80211=m
 # CONFIG_CFG80211_WEXT is not set
 CONFIG_RFKILL=y
@@ -289,6 +292,8 @@
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_PMIC8XXX_PWRKEY=y
 CONFIG_INPUT_UINPUT=y
+CONFIG_STM_LIS3DH=y
+CONFIG_INPUT_MPU3050=y
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_N_SMUX=y
 CONFIG_N_SMUX_LOOPBACK=y
@@ -354,6 +359,7 @@
 CONFIG_IMX074_EEPROM=y
 CONFIG_IMX091_EEPROM=y
 CONFIG_MSM_GEMINI=y
+CONFIG_MSM_MERCURY=y
 CONFIG_MSM_CSI20_HEADER=y
 CONFIG_S5K3L1YX=y
 CONFIG_IMX091=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 00b4164..53193a1 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -51,7 +51,15 @@
 CONFIG_MSM_TZ_LOG=y
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_MSM_OCMEM=y
+CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
+CONFIG_MSM_OCMEM_DEBUG=y
+CONFIG_MSM_OCMEM_POWER_DISABLE=y
 CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_CACHE_ERP=y
+CONFIG_MSM_L1_ERR_PANIC=y
+CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
+CONFIG_MSM_L2_ERP_2BIT_PANIC=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
@@ -62,7 +70,6 @@
 CONFIG_HIGHMEM=y
 CONFIG_VMALLOC_RESERVE=0x19000000
 CONFIG_USE_OF=y
-CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
@@ -98,6 +105,8 @@
 CONFIG_IPV6_MIP6=y
 CONFIG_IPV6_MULTIPLE_TABLES=y
 CONFIG_IPV6_SUBTREES=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_QSEECOM=y
@@ -119,6 +128,7 @@
 # CONFIG_MSM_RMNET is not set
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
 CONFIG_INPUT_JOYSTICK=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_INPUT_MISC=y
@@ -126,6 +136,7 @@
 CONFIG_SERIAL_MSM_HSL=y
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
 CONFIG_DIAG_CHAR=y
+CONFIG_HVC_DCC=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM=y
 CONFIG_DCC_TTY=y
@@ -147,6 +158,8 @@
 CONFIG_POWER_SUPPLY=y
 # CONFIG_BATTERY_MSM is not set
 # CONFIG_HWMON is not set
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS8974=y
 CONFIG_REGULATOR_STUB=y
 CONFIG_REGULATOR_QPNP=y
 CONFIG_MEDIA_SUPPORT=y
@@ -158,6 +171,7 @@
 # CONFIG_RADIO_ADAPTERS is not set
 CONFIG_ION=y
 CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
 CONFIG_FB=y
 CONFIG_FB_MSM=y
 # CONFIG_FB_MSM_BACKLIGHT is not set
@@ -237,8 +251,6 @@
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
-CONFIG_EARLY_PRINTK=y
 CONFIG_KEYS=y
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_SHA256=y
@@ -250,4 +262,19 @@
 CONFIG_CRYPTO_DEV_QCEDEV=m
 CONFIG_CRC_CCITT=y
 CONFIG_LIBCRC32C=y
-CONFIG_MSM_BUS_SCALING=y
+
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+
+CONFIG_BT_HCISMD=y
+CONFIG_MSM_BT_POWER=y
+
+CONFIG_RADIO_IRIS=y
+CONFIG_RADIO_IRIS_TRANSPORT=m
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 9094db7..446734f 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -56,9 +56,28 @@
 CONFIG_MTD_BLOCK=y
 # CONFIG_MTD_MSM_NAND is not set
 CONFIG_MTD_MSM_QPIC_NAND=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IPV6=y
+# CONFIG_WIRELESS is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 # CONFIG_ANDROID_PMEM is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+CONFIG_KS8851=y
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_MSM_RMNET is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
@@ -70,6 +89,9 @@
 CONFIG_SERIAL_MSM_HSL=y
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
 CONFIG_HW_RANDOM=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
 CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_SYSFS=y
 # CONFIG_HWMON is not set
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index dc988ff..d055a53 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -10,6 +10,8 @@
 #include <asm-generic/dma-coherent.h>
 #include <asm/memory.h>
 
+#define DMA_ERROR_CODE	(~0)
+
 #ifdef __arch_page_to_dma
 #error Please update to __arch_pfn_to_dma
 #endif
@@ -123,7 +125,7 @@
  */
 static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
-	return dma_addr == ~0;
+	return dma_addr == DMA_ERROR_CODE;
 }
 
 /*
@@ -304,19 +306,17 @@
 /*
  * Private functions
  */
-int dmabounce_sync_for_cpu(struct device *, dma_addr_t, unsigned long,
-		size_t, enum dma_data_direction);
-int dmabounce_sync_for_device(struct device *, dma_addr_t, unsigned long,
-		size_t, enum dma_data_direction);
+int dmabounce_sync_for_cpu(struct device *, dma_addr_t, size_t, enum dma_data_direction);
+int dmabounce_sync_for_device(struct device *, dma_addr_t, size_t, enum dma_data_direction);
 #else
 static inline int dmabounce_sync_for_cpu(struct device *d, dma_addr_t addr,
-	unsigned long offset, size_t size, enum dma_data_direction dir)
+	size_t size, enum dma_data_direction dir)
 {
 	return 1;
 }
 
 static inline int dmabounce_sync_for_device(struct device *d, dma_addr_t addr,
-	unsigned long offset, size_t size, enum dma_data_direction dir)
+	size_t size, enum dma_data_direction dir)
 {
 	return 1;
 }
@@ -491,6 +491,33 @@
 	__dma_unmap_page(dev, handle, size, dir);
 }
 
+
+static inline void dma_sync_single_for_cpu(struct device *dev,
+		dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+	BUG_ON(!valid_dma_direction(dir));
+
+	debug_dma_sync_single_for_cpu(dev, handle, size, dir);
+
+	if (!dmabounce_sync_for_cpu(dev, handle, size, dir))
+		return;
+
+	__dma_single_dev_to_cpu(dma_to_virt(dev, handle), size, dir);
+}
+
+static inline void dma_sync_single_for_device(struct device *dev,
+		dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+	BUG_ON(!valid_dma_direction(dir));
+
+	debug_dma_sync_single_for_device(dev, handle, size, dir);
+
+	if (!dmabounce_sync_for_device(dev, handle, size, dir))
+		return;
+
+	__dma_single_cpu_to_dev(dma_to_virt(dev, handle), size, dir);
+}
+
 /**
  * dma_sync_single_range_for_cpu
  * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
@@ -513,40 +540,14 @@
 		dma_addr_t handle, unsigned long offset, size_t size,
 		enum dma_data_direction dir)
 {
-	BUG_ON(!valid_dma_direction(dir));
-
-	debug_dma_sync_single_for_cpu(dev, handle + offset, size, dir);
-
-	if (!dmabounce_sync_for_cpu(dev, handle, offset, size, dir))
-		return;
-
-	__dma_single_dev_to_cpu(dma_to_virt(dev, handle) + offset, size, dir);
+	dma_sync_single_for_cpu(dev, handle + offset, size, dir);
 }
 
 static inline void dma_sync_single_range_for_device(struct device *dev,
 		dma_addr_t handle, unsigned long offset, size_t size,
 		enum dma_data_direction dir)
 {
-	BUG_ON(!valid_dma_direction(dir));
-
-	debug_dma_sync_single_for_device(dev, handle + offset, size, dir);
-
-	if (!dmabounce_sync_for_device(dev, handle, offset, size, dir))
-		return;
-
-	__dma_single_cpu_to_dev(dma_to_virt(dev, handle) + offset, size, dir);
-}
-
-static inline void dma_sync_single_for_cpu(struct device *dev,
-		dma_addr_t handle, size_t size, enum dma_data_direction dir)
-{
-	dma_sync_single_range_for_cpu(dev, handle, 0, size, dir);
-}
-
-static inline void dma_sync_single_for_device(struct device *dev,
-		dma_addr_t handle, size_t size, enum dma_data_direction dir)
-{
-	dma_sync_single_range_for_device(dev, handle, 0, size, dir);
+	dma_sync_single_for_device(dev, handle + offset, size, dir);
 }
 
 /*
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 7b6f42a..84560dc 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -313,7 +313,6 @@
  * We provide our own arch_get_unmapped_area to cope with VIPT caches.
  */
 #define HAVE_ARCH_UNMAPPED_AREA
-#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
 
 /*
  * remap a physical page `pfn' of size `size' with page protection `prot'
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 37cbfcb..0d0103a 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -108,6 +108,12 @@
 	enum arm_pmu_type type;
 	cpumask_t	active_irqs;
 	const char	*name;
+	int		num_events;
+	atomic_t	active_events;
+	struct mutex	reserve_mutex;
+	u64		max_period;
+	struct platform_device	*plat_device;
+	u32		from_idle;
 	irqreturn_t	(*handle_irq)(int irq_num, void *dev);
 	int     	(*request_pmu_irq)(int irq, irq_handler_t *irq_h);
 	void    	(*free_pmu_irq)(int irq);
@@ -123,11 +129,6 @@
 	void		(*stop)(void);
 	void		(*reset)(void *);
 	int		(*map_event)(struct perf_event *event);
-	int		num_events;
-	atomic_t	active_events;
-	struct mutex	reserve_mutex;
-	u64		max_period;
-	struct platform_device	*plat_device;
 	struct pmu_hw_events	*(*get_hw_events)(void);
 	int	(*test_set_event_constraints)(struct perf_event *event);
 	int	(*clear_event_constraints)(struct perf_event *event);
diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
index 07209d7..8e2bb29 100644
--- a/arch/arm/include/asm/processor.h
+++ b/arch/arm/include/asm/processor.h
@@ -126,8 +126,6 @@
 
 #endif
 
-#define HAVE_ARCH_PICK_MMAP_LAYOUT
-
 #endif
 
 #endif /* __ASM_ARM_PROCESSOR_H */
diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h
index 94aa75e..bc81696 100644
--- a/arch/arm/include/asm/spinlock.h
+++ b/arch/arm/include/asm/spinlock.h
@@ -37,9 +37,11 @@
 #endif
 
 /*
- * The fixup involves disabling interrupts during execution of the WFE
- * instruction. This could potentially lead to deadlock if a thread is trying
- * to acquire a spinlock which is being released from an interrupt context.
+ * The fixup involves disabling FIQs during execution of the WFE instruction.
+ * This could potentially lead to deadlock if a thread is trying to acquire a
+ * spinlock which is being released from an FIQ. This should not be a problem
+ * because FIQs are handled by the secure environment and do not directly
+ * manipulate spinlocks.
  */
 #ifdef CONFIG_MSM_KRAIT_WFE_FIXUP
 #define WFE_SAFE(fixup, tmp) 				\
@@ -47,7 +49,7 @@
 "	cmp	" fixup ", #0\n"			\
 "	wfeeq\n"					\
 "	beq	10f\n"					\
-"	cpsid	if\n"					\
+"	cpsid   f\n"					\
 "	mrc	p15, 7, " fixup ", c15, c0, 5\n"	\
 "	bic	" fixup ", " fixup ", #0x10000\n"	\
 "	mcr	p15, 7, " fixup ", c15, c0, 5\n"	\
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 43c627d..23d310d 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -208,11 +208,11 @@
 	unsigned long ctrl;
 
 	ctrl = arch_specific_timer->reg_read(ARCH_TIMER_REG_CTRL);
-	ctrl |= ARCH_TIMER_CTRL_ENABLE;
-	ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
-
+	ctrl &= ~(ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_MASK);
 	arch_specific_timer->reg_write(ARCH_TIMER_REG_CTRL, ctrl);
 	arch_specific_timer->reg_write(ARCH_TIMER_REG_TVAL, evt);
+	ctrl |= ARCH_TIMER_CTRL_ENABLE;
+	arch_specific_timer->reg_write(ARCH_TIMER_REG_CTRL, ctrl);
 
 	return 0;
 }
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 7c44acd..7a8c2d6 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -966,7 +966,7 @@
  * SP points to a minimal amount of processor-private memory, the address
  * of which is copied into r0 for the mode specific abort handler.
  */
-	.macro	vector_stub, name, mode, correction=0
+	.macro	vector_stub, name, mode, fixup, correction=0
 	.align	5
 
 vector_\name:
@@ -995,6 +995,18 @@
 	and	lr, lr, #0x0f
  THUMB(	adr	r0, 1f			)
  THUMB(	ldr	lr, [r0, lr, lsl #2]	)
+	.if	\fixup
+#ifdef CONFIG_MSM_KRAIT_WFE_FIXUP
+	ldr	r0, .krait_fixup
+	ldr	r0, [r0]
+	cmp	r0, #0
+	beq	10f
+	mrc	p15, 7, r0, c15, c0, 5
+	orr	r0, r0, #0x10000
+	mcr	p15, 7, r0, c15, c0, 5
+10:	isb
+#endif
+	.endif
 	mov	r0, sp
  ARM(	ldr	lr, [pc, lr, lsl #2]	)
 	movs	pc, lr			@ branch to handler in SVC mode
@@ -1010,7 +1022,7 @@
 /*
  * Interrupt dispatcher
  */
-	vector_stub	irq, IRQ_MODE, 4
+	vector_stub	irq, IRQ_MODE, 1, 4
 
 	.long	__irq_usr			@  0  (USR_26 / USR_32)
 	.long	__irq_invalid			@  1  (FIQ_26 / FIQ_32)
@@ -1033,7 +1045,7 @@
  * Data abort dispatcher
  * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
  */
-	vector_stub	dabt, ABT_MODE, 8
+	vector_stub	dabt, ABT_MODE, 0, 8
 
 	.long	__dabt_usr			@  0  (USR_26 / USR_32)
 	.long	__dabt_invalid			@  1  (FIQ_26 / FIQ_32)
@@ -1056,7 +1068,7 @@
  * Prefetch abort dispatcher
  * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
  */
-	vector_stub	pabt, ABT_MODE, 4
+	vector_stub	pabt, ABT_MODE, 0, 4
 
 	.long	__pabt_usr			@  0 (USR_26 / USR_32)
 	.long	__pabt_invalid			@  1 (FIQ_26 / FIQ_32)
@@ -1079,7 +1091,7 @@
  * Undef instr entry dispatcher
  * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
  */
-	vector_stub	und, UND_MODE
+	vector_stub	und, UND_MODE, 0
 
 	.long	__und_usr			@  0 (USR_26 / USR_32)
 	.long	__und_invalid			@  1 (FIQ_26 / FIQ_32)
@@ -1131,6 +1143,8 @@
 
 .LCvswi:
 	.word	vector_swi
+.krait_fixup:
+	.word	msm_krait_need_wfe_fixup
 
 	.globl	__stubs_end
 __stubs_end:
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c
index 1ef5022..bf17145 100644
--- a/arch/arm/kernel/ftrace.c
+++ b/arch/arm/kernel/ftrace.c
@@ -78,20 +78,6 @@
 	return 0;
 }
 
-int ftrace_arch_code_modify_prepare(void)
-{
-	set_kernel_text_rw();
-	set_all_modules_text_rw();
-	return 0;
-}
-
-int ftrace_arch_code_modify_post_process(void)
-{
-	set_all_modules_text_ro();
-	set_kernel_text_ro();
-	return 0;
-}
-
 static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr)
 {
 	return arm_gen_branch_link(pc, addr);
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 778128b..e97aef2 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -600,6 +600,21 @@
 	struct arm_pmu *armpmu = to_arm_pmu(pmu);
 	struct pmu_hw_events *hw_events = armpmu->get_hw_events();
 	int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events);
+	int idx;
+
+	if (armpmu->from_idle) {
+		for (idx = 0; idx <= cpu_pmu->num_events; ++idx) {
+			struct perf_event *event = hw_events->events[idx];
+
+			if (!event)
+				continue;
+
+			armpmu->enable(&event->hw, idx, event->cpu);
+		}
+
+		/* Reset bit so we don't needlessly re-enable counters.*/
+		armpmu->from_idle = 0;
+	}
 
 	if (enabled)
 		armpmu->start();
@@ -716,6 +731,7 @@
  * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
  * junk values out of them.
  */
+
 static int __cpuinit pmu_cpu_notify(struct notifier_block *b,
 					unsigned long action, void *hcpu)
 {
@@ -785,6 +801,11 @@
 	case CPU_PM_ENTER_FAILED:
 	case CPU_PM_EXIT:
 		if (cpu_has_active_perf() && cpu_pmu->reset) {
+			/*
+			 * Flip this bit so armpmu_enable knows it needs
+			 * to re-enable active counters.
+			 */
+			cpu_pmu->from_idle = 1;
 			cpu_pmu->reset(NULL);
 			perf_pmu_enable(&cpu_pmu->pmu);
 		}
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 28d6e60..7d26726 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -541,7 +541,8 @@
 	dump_stack();
 
 	pr_info("\nsending IPI to all other CPUs:\n");
-	smp_cross_call(&backtrace_mask, IPI_CPU_BACKTRACE);
+	if (!cpus_empty(backtrace_mask))
+		smp_cross_call(&backtrace_mask, IPI_CPU_BACKTRACE);
 
 	/* Wait for up to 10 seconds for all other CPUs to do the backtrace */
 	for (i = 0; i < 10 * 1000; i++) {
@@ -651,7 +652,8 @@
 
 	cpumask_copy(&mask, cpu_online_mask);
 	cpumask_clear_cpu(smp_processor_id(), &mask);
-	smp_cross_call(&mask, IPI_CPU_STOP);
+	if (!cpumask_empty(&mask))
+		smp_cross_call(&mask, IPI_CPU_STOP);
 
 	/* Wait up to one second for other CPUs to stop */
 	timeout = USEC_PER_SEC;
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 0873d5a..6836c5b 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -254,11 +254,12 @@
 	select SPARSE_IRQ
 	select MSM_RPM_SMD
 	select REGULATOR
-	select MSM_QDSP6_APR
+	select MSM_QDSP6_APRV2
 	select MSM_QDSP6V2_CODECS
 	select MSM_AUDIO_QDSP6V2 if SND_SOC
 	select MSM_RPM_REGULATOR_SMD
 	select ARM_HAS_SG_CHAIN
+	select MSM_RUN_QUEUE_STATS
 
 config ARCH_FSM9XXX
 	bool "FSM9XXX"
@@ -309,13 +310,14 @@
 	bool "MSM9625"
 	select ARM_GIC
 	select GIC_SECURE
+	select MIGHT_HAVE_CACHE_L2X0
 	select ARCH_MSM_CORTEX_A5
 	select SMP
 	select MSM_SMP
 	select CPU_V7
 	select MSM_GPIOMUX
 	select MULTI_IRQ_HANDLER
-	select GPIO_MSM_V2
+	select GPIO_MSM_V3
 
 endmenu
 
@@ -893,12 +895,15 @@
 	default "0x40200000" if ARCH_MSM8X60
 	default "0x10000000"
 
-config KERNEL_PMEM_EBI_REGION
-	bool "Enable in-kernel PMEM region for EBI"
+config KERNEL_MSM_CONTIG_MEM_REGION
+	bool "Enable in-kernel contiguous memory region"
 	default y if ARCH_MSM8X60
 	depends on ANDROID_PMEM && (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM8974)
 	help
-	   Enable the in-kernel PMEM allocator to use EBI memory.
+	   Enable the in-kernel contiguous memory allocator. Sets up a
+	   region of physically contiguous memory. This memory is
+	   reserved during initialization, and can be used
+	   generically.
 
 config KERNEL_PMEM_SMI_REGION
 	bool "Enable in-kernel PMEM region for SMI"
@@ -2145,11 +2150,6 @@
 	help
 	  Enables embedded trace collection on MSM8660
 
-config MSM_SLEEP_STATS
-	bool "Enable exporting of MSM sleep stats to userspace"
-	depends on CPU_IDLE
-	default n
-
 config MSM_SLEEP_STATS_DEVICE
 	bool "Enable exporting of MSM sleep device stats to userspace"
 
@@ -2216,6 +2216,16 @@
 	  used by audio driver to configure QDSP6's
 	  ASM, ADM and AFE.
 
+config MSM_QDSP6_APRV2
+	bool "Audio QDSP6 APRv2 support"
+	depends on MSM_SMD
+	default n
+	help
+	  Enable APRv2 IPC protocol support between
+	  application processor and QDSP6. APR is
+	  used by audio driver to configure QDSP6's
+	  ASM, ADM and AFE.
+
 config MSM_QDSP6_CODECS
 	bool "Audio Codecs on QDSP6 APR "
 	depends on MSM_SMD
@@ -2253,6 +2263,16 @@
           AAC, AMRNB, AMRWB, EVRC, MP3, QCELP among
           others.
 
+config MSM_ADSP_LOADER
+        tristate "ADSP loader support"
+        select SND_SOC_MSM_APRV2_INTF
+	depends on MSM_AUDIO_QDSP6V2 && m
+        help
+          Enable ADSP image loader.
+	  The ADSP loader brings ADSP out of reset
+	  for the platforms that use APRv2.
+	  Say M if you want to enable this module.
+
 config MSM_ULTRASOUND
 	bool "MSM ultrasound support"
 	depends on MSM_AUDIO_QDSP6
@@ -2312,6 +2332,42 @@
 	  Enable support for On-Chip Memory available on certain MSM chipsets.
 	  OCMEM is a low latency, high performance pool shared by subsystems.
 
+config MSM_OCMEM_LOCAL_POWER_CTRL
+	bool "OCMEM Local Power Control"
+	depends on MSM_OCMEM
+	help
+	  Enable direct power management of the OCMEM core by the
+	  OCMEM driver. By default power management is delegated to
+	  the RPM. Selecting this option causes the OCMEM driver to
+	  directly handle the various macro power transitions.
+
+config MSM_OCMEM_DEBUG
+	bool "OCMEM Debug Support"
+	depends on MSM_OCMEM
+	help
+	  Enable debug options for On-chip Memory (OCMEM) driver.
+	  Various debug options include memory, power and latency.
+	  Choosing one of these options allows debugging of each
+	  individual subsystem separately.
+
+config MSM_OCMEM_POWER_DEBUG
+	bool "OCMEM Power Debug Support"
+	depends on MSM_OCMEM_DEBUG
+	help
+	  Enable debug support for OCMEM power management.
+	  This adds support for verifying all power management
+	  related operations of OCMEM. Both local power management
+	  and RPM assisted power management operations are supported.
+
+config MSM_OCMEM_POWER_DISABLE
+	bool "OCMEM Disable Power Control"
+	depends on MSM_OCMEM_DEBUG
+	help
+	  Disable all OCMEM power management.
+	  This keeps all OCMEM macros turned ON at all times thus
+	  never allowing them to be turned OFF. Both local power
+	  management and RPM assisted power modes are supported.
+
 config MSM_RTB
 	bool "Register tracing"
 	help
@@ -2427,6 +2483,19 @@
 	  algorithm and the algorithm returns a frequency for the core which is
 	  passed to the frequency change driver.
 
+config MSM_CPR
+	tristate "Use MSM CPR in S/W mode"
+	help
+	  Enable CPR (core power reduction) in S/W mode, where the processor
+	  get's the notification from CPR block and programs the PMIC.
+
+config MSM_VP_REGULATOR
+	tristate "Use MSM PMIC8029 C2 regulator"
+	depends on ARCH_MSM8625
+	help
+	  Enable MSM PMIC8029 C2 regulator support using APC_PLEVEL access
+	  for MSMs like 8625.
+
 config HAVE_ARCH_HAS_CURRENT_TIMER
 	bool
 
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 4b41399..3da1040 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -253,7 +253,7 @@
 obj-$(CONFIG_MACH_MSM7627A_QRD1) += board-qrd7627a.o board-7627a-all.o
 obj-$(CONFIG_MACH_MSM7627A_QRD3) += board-qrd7627a.o board-7627a-all.o
 obj-$(CONFIG_MACH_MSM7627A_EVB) += board-qrd7627a.o board-7627a-all.o
-obj-$(CONFIG_ARCH_MSM8625) += devices-msm7x27a.o clock-pcom-lookup.o mpm-8625.o
+obj-$(CONFIG_ARCH_MSM8625) += msm_smem_iface.o devices-msm7x27a.o clock-pcom-lookup.o mpm-8625.o
 obj-$(CONFIG_MACH_MSM8625_RUMI3) += board-msm7x27a.o
 obj-$(CONFIG_MACH_MSM8625_SURF) +=  board-msm7x27a.o board-7627a-all.o
 obj-$(CONFIG_MACH_MSM8625_EVB) +=  board-qrd7627a.o board-7627a-all.o
@@ -266,7 +266,7 @@
 obj-$(CONFIG_MACH_MSM7X25_FFA) += board-msm7x27.o devices-msm7x25.o
 obj-$(CONFIG_ARCH_MSM8960) += clock-local.o clock-dss-8960.o clock-8960.o clock-rpm.o clock-pll.o
 obj-$(CONFIG_ARCH_MSM8960) += footswitch-8x60.o
-obj-$(CONFIG_ARCH_MSM8960) += acpuclock-8960.o
+obj-$(CONFIG_ARCH_MSM8960) += acpuclock-8960.o acpuclock-8960ab.o
 obj-$(CONFIG_ARCH_MSM8960) += memory_topology.o
 obj-$(CONFIG_ARCH_MSM8960) += saw-regulator.o
 obj-$(CONFIG_ARCH_MSM8960) += devices-8960.o
@@ -289,10 +289,11 @@
 obj-$(CONFIG_MACH_MPQ8064_DTV) += board-8064-all.o board-8064-regulator.o
 obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o board-9615-gpiomux.o board-9615-storage.o board-9615-display.o
 obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o clock-pll.o
-obj-$(CONFIG_ARCH_MSM8974) += board-8974.o board-dt.o board-8974-regulator.o board-8974-gpiomux.o
+obj-$(CONFIG_ARCH_MSM8974) += board-8974.o board-dt.o board-8974-gpiomux.o
 obj-$(CONFIG_ARCH_MSM8974) += acpuclock-8974.o
 obj-$(CONFIG_ARCH_MSM8974) += clock-local2.o clock-pll.o clock-8974.o clock-rpm.o clock-voter.o
 obj-$(CONFIG_ARCH_MSM8974) += gdsc.o
+obj-$(CONFIG_ARCH_MSM8974) += krait-regulator.o
 obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
 obj-$(CONFIG_ARCH_MSM8930) += acpuclock-8930.o acpuclock-8627.o acpuclock-8930aa.o
 
@@ -340,7 +341,7 @@
 obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-vcm.o
 endif
 obj-$(CONFIG_MSM_OCMEM) += ocmem.o ocmem_allocator.o ocmem_notifier.o
-obj-$(CONFIG_MSM_OCMEM) += ocmem_sched.o ocmem_api.o ocmem_rdm.o
+obj-$(CONFIG_MSM_OCMEM) += ocmem_sched.o ocmem_api.o ocmem_rdm.o ocmem_core.o
 
 obj-$(CONFIG_ARCH_MSM7X27) += gpiomux-7x27.o gpiomux-v1.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-7x30.o gpiomux-v1.o gpiomux.o
@@ -353,7 +354,6 @@
 obj-$(CONFIG_ARCH_MSM9625) += gpiomux-v2.o gpiomux.o
 
 
-obj-$(CONFIG_MSM_SLEEP_STATS) += idle_stats.o
 obj-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += idle_stats_device.o
 obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o msm_dcvs_idle.o
 obj-$(CONFIG_MSM_RUN_QUEUE_STATS) += msm_rq_stats.o
@@ -382,3 +382,9 @@
 obj-$(CONFIG_MSM_HSIC_SYSMON_TEST) += hsic_sysmon_test.o
 
 obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o
+obj-$(CONFIG_MSM_CPR) += msm_cpr.o
+obj-$(CONFIG_MSM_VP_REGULATOR) += msm_vp.o
+
+ifdef CONFIG_MSM_CPR
+obj-$(CONFIG_DEBUG_FS) += msm_cpr-debug.o
+endif
diff --git a/arch/arm/mach-msm/acpuclock-7627.c b/arch/arm/mach-msm/acpuclock-7627.c
index 639cc94..3bcba5f 100644
--- a/arch/arm/mach-msm/acpuclock-7627.c
+++ b/arch/arm/mach-msm/acpuclock-7627.c
@@ -249,14 +249,16 @@
 /* 8625 PLL4 @ 1209MHz with GSM capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_pll4_1209[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
-	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 1, 61440 },
-	{ 1, 122880, ACPU_PLL_1, 1, 1,  15360, 3, 2, 61440 },
-	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3, 61440 },
-	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
-	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
-	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
-	{ 0, 604800, ACPU_PLL_4, 6, 1, 75600, 3, 6, 160000 },
-	{ 1, 1209600, ACPU_PLL_4, 6, 0, 151200, 3, 7, 200000},
+	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 0, 61440 },
+	{ 0, 122880, ACPU_PLL_1, 1, 1,  15360, 3, 1, 61440 },
+	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 1, 61440 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 2, 122880 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 2, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 3, 122880 },
+	{ 0, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 4, 160000 },
+	{ 1, 700800, ACPU_PLL_4, 6, 0, 87500, 3, 4, 160000, &pll4_cfg_tbl[0]},
+	{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 5, 200000, &pll4_cfg_tbl[1]},
+	{ 1, 1209600, ACPU_PLL_4, 6, 0, 151200, 3, 6, 200000, &pll4_cfg_tbl[2]},
 	{ 0 }
 };
 
@@ -264,13 +266,14 @@
 static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_1200_pll4_1209[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
 	{ 0, 65536, ACPU_PLL_1, 1, 3,  8192, 3, 1, 49152 },
-	{ 1, 98304, ACPU_PLL_1, 1, 1,  12288, 3, 2, 49152 },
+	{ 0, 98304, ACPU_PLL_1, 1, 1,  12288, 3, 2, 49152 },
 	{ 1, 196608, ACPU_PLL_1, 1, 0, 24576, 3, 3, 98304 },
-	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
-	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
-	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
-	{ 0, 604800, ACPU_PLL_4, 6, 1, 75600, 3, 6, 160000 },
-	{ 1, 1209600, ACPU_PLL_4, 6, 0, 151200, 3, 7, 200000},
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 2, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 3, 122880 },
+	{ 0, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 4, 160000 },
+	{ 1, 700800, ACPU_PLL_4, 6, 0, 87500, 3, 4, 160000, &pll4_cfg_tbl[0]},
+	{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 5, 200000, &pll4_cfg_tbl[1]},
+	{ 1, 1209600, ACPU_PLL_4, 6, 0, 151200, 3, 6, 200000, &pll4_cfg_tbl[2]},
 	{ 0 }
 };
 
@@ -307,6 +310,35 @@
 	{ 0 }
 };
 
+/* 8625v2.0 PLL4 @ 1008MHz with GSM capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_pll4_1008_2p0[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
+	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 0, 61440 },
+	{ 0, 122880, ACPU_PLL_1, 1, 1,  15360, 3, 1, 61440 },
+	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 1, 61440 },
+	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 2, 122880 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 2, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 3, 122880 },
+	{ 0, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 4, 160000 },
+	{ 1, 700800, ACPU_PLL_4, 6, 0, 87500, 3, 4, 160000, &pll4_cfg_tbl[0]},
+	{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 5, 200000, &pll4_cfg_tbl[1]},
+	{ 0 }
+};
+
+/* 8625v2.0 PLL4 @ 1008MHz with CDMA capable modem */
+static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_1200_pll4_1008_2p0[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
+	{ 0, 65536, ACPU_PLL_1, 1, 3,  8192, 3, 1, 49152 },
+	{ 0, 98304, ACPU_PLL_1, 1, 1,  12288, 3, 2, 49152 },
+	{ 1, 196608, ACPU_PLL_1, 1, 0, 24576, 3, 3, 98304 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 2, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 3, 122880 },
+	{ 0, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 4, 160000 },
+	{ 1, 700800, ACPU_PLL_4, 6, 0, 87500, 3, 4, 160000, &pll4_cfg_tbl[0]},
+	{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 5, 200000, &pll4_cfg_tbl[1]},
+	{ 0 }
+};
+
 /* 8625 PLL4 @ 1152MHz with GSM capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_pll4_1152[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
@@ -725,7 +757,7 @@
 		if ((delta > drv_state.max_speed_delta_khz)
 				|| (strt_s->pll == ACPU_PLL_4 &&
 					tgt_s->pll == ACPU_PLL_4))
-			clk_disable_unprepare(pll_clk[backup_s->pll].clk);
+			clk_disable(pll_clk[backup_s->pll].clk);
 
 		goto done;
 	}
@@ -946,6 +978,26 @@
 			acpu_freq_tbl =
 				pll0_960_pll1_737_pll2_1200_25a;
 		}
+		t->tbl = acpu_freq_tbl;
+	}
+
+	/*
+	 * 1008Mhz table selection based on the Lvalue of the PLL
+	 * is conflicting with the 7627AA and 8625 v1.0 1GHz parts
+	 * since v2.0 8625 chips are using different clock plan based
+	 * reprogramming method.
+	 */
+	if (cpu_is_msm8625() &&
+		(SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2) &&
+		pll_mhz[ACPU_PLL_4] == 1008) {
+
+		if (pll_mhz[ACPU_PLL_2] == 245)
+			acpu_freq_tbl =
+				pll0_960_pll1_245_pll2_1200_pll4_1008_2p0;
+		else
+			acpu_freq_tbl =
+				pll0_960_pll1_196_pll2_1200_pll4_1008_2p0;
+		t->tbl = acpu_freq_tbl;
 	} else {
 		/* Select the right table to use. */
 		for (; t->tbl != 0; t++) {
@@ -959,17 +1011,31 @@
 		}
 	}
 
+	if (acpu_freq_tbl == NULL) {
+		pr_crit("Unknown PLL configuration!\n");
+		BUG();
+	}
+
 	/*
-	 * When PLL4 can run max @ 1401.6MHz, we have to support
-	 * dynamic reprograming of PLL4.
-	 *
+	 * Turn ON the dynamic reprogramming method
+	 * if one of the table entry has pll_rate defined.
+	 */
+	for ( ; t->tbl->a11clk_khz; t->tbl++) {
+		if (t->tbl->pll_rate) {
+			if (!dynamic_reprogram) {
+				dynamic_reprogram = 1;
+				pr_info("Dynamic reprogramming is ON\n");
+			}
+		}
+	}
+
+	/*
 	 * Also find the backup pll used during PLL4 reprogramming.
 	 * We are using PLL2@600MHz as backup PLL, since 800MHz jump
 	 * is fine.
 	 */
-	if (t->pll4_rate == 1401) {
-		dynamic_reprogram = 1;
-		for ( ; t->tbl->a11clk_khz; t->tbl++) {
+	if (dynamic_reprogram) {
+		for (t->tbl = acpu_freq_tbl; t->tbl->a11clk_khz; t->tbl++) {
 			if (t->tbl->pll == ACPU_PLL_2 &&
 					t->tbl->a11clk_src_div == 1) {
 				backup_s = t->tbl;
@@ -977,11 +1043,6 @@
 			}
 		}
 	}
-
-	if (acpu_freq_tbl == NULL) {
-		pr_crit("Unknown PLL configuration!\n");
-		BUG();
-	}
 }
 
 /*
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
index 6f9960d..a9521f0 100644
--- a/arch/arm/mach-msm/acpuclock-8064.c
+++ b/arch/arm/mach-msm/acpuclock-8064.c
@@ -121,6 +121,7 @@
 	[12] = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 5 },
 	[13] = { { 1080000, HFPLL, 1, 0, 0x28 }, 1150000, 1150000, 5 },
 	[14] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 5 },
+	[15] = { { 1188000, HFPLL, 1, 0, 0x2C }, 1150000, 1150000, 5 },
 };
 
 static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
@@ -137,15 +138,15 @@
 	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(6),  1100000 },
 	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(6),  1125000 },
 	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(6),  1125000 },
-	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(14), 1175000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(14), 1175000 },
-	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(14), 1200000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(14), 1200000 },
-	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(14), 1225000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(14), 1225000 },
-	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(14), 1237500 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(14), 1237500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(14), 1250000 },
+	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1175000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1175000 },
+	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1200000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1200000 },
+	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1225000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1225000 },
+	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1237500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1237500 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1250000 },
 	{ 0, { 0 } }
 };
 
@@ -163,15 +164,15 @@
 	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(6),  1050000 },
 	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(6),  1075000 },
 	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(6),  1075000 },
-	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(14), 1125000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(14), 1125000 },
-	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(14), 1150000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(14), 1150000 },
-	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(14), 1175000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(14), 1175000 },
-	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(14), 1187500 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(14), 1187500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(14), 1200000 },
+	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1125000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1125000 },
+	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1150000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1150000 },
+	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1175000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1175000 },
+	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1187500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1187500 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1200000 },
 	{ 0, { 0 } }
 };
 
@@ -189,15 +190,15 @@
 	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(6),  1000000 },
 	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(6),  1025000 },
 	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(6),  1025000 },
-	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(14), 1075000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(14), 1075000 },
-	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(14), 1100000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(14), 1100000 },
-	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(14), 1125000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(14), 1125000 },
-	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(14), 1137500 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(14), 1137500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(14), 1150000 },
+	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1075000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1075000 },
+	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1100000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1100000 },
+	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1125000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1125000 },
+	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1137500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1137500 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1150000 },
 	{ 0, { 0 } }
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-8960ab.c b/arch/arm/mach-msm/acpuclock-8960ab.c
new file mode 100644
index 0000000..6366376
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-8960ab.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <mach/rpm-regulator.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+
+#include "acpuclock.h"
+#include "acpuclock-krait.h"
+
+static struct hfpll_data hfpll_data __initdata = {
+	.mode_offset = 0x00,
+	.l_offset = 0x08,
+	.m_offset = 0x0C,
+	.n_offset = 0x10,
+	.config_offset = 0x04,
+	.config_val = 0x7845C665,
+	.has_droop_ctl = true,
+	.droop_offset = 0x14,
+	.droop_val = 0x0108C000,
+	.low_vdd_l_max = 37,
+	.nom_vdd_l_max = 74,
+	.vdd[HFPLL_VDD_NONE] = 0,
+	.vdd[HFPLL_VDD_LOW]  = 945000,
+	.vdd[HFPLL_VDD_NOM]  = 1050000,
+	.vdd[HFPLL_VDD_HIGH] = 1150000,
+};
+
+static struct scalable scalable[] __initdata = {
+	[CPU0] = {
+		.hfpll_phys_base = 0x00903200,
+		.aux_clk_sel_phys = 0x02088014,
+		.aux_clk_sel = 3,
+		.l2cpmr_iaddr = 0x4501,
+		.vreg[VREG_CORE] = { "krait0", 1300000 },
+		.vreg[VREG_MEM]  = { "krait0_mem", 1150000 },
+		.vreg[VREG_DIG]  = { "krait0_dig", 1150000 },
+		.vreg[VREG_HFPLL_A] = { "krait0_s8", 2050000 },
+		.vreg[VREG_HFPLL_B] = { "krait0_l23", 1800000 },
+	},
+	[CPU1] = {
+		.hfpll_phys_base = 0x00903300,
+		.aux_clk_sel_phys = 0x02098014,
+		.aux_clk_sel = 3,
+		.l2cpmr_iaddr = 0x5501,
+		.vreg[VREG_CORE] = { "krait1", 1300000 },
+		.vreg[VREG_MEM]  = { "krait1_mem", 1150000 },
+		.vreg[VREG_DIG]  = { "krait1_dig", 1150000 },
+		.vreg[VREG_HFPLL_A] = { "krait1_s8", 2050000 },
+		.vreg[VREG_HFPLL_B] = { "krait1_l23", 1800000 },
+	},
+	[L2] = {
+		.hfpll_phys_base = 0x00903400,
+		.aux_clk_sel_phys = 0x02011028,
+		.aux_clk_sel = 3,
+		.l2cpmr_iaddr = 0x0500,
+		.vreg[VREG_HFPLL_A] = { "l2_s8", 2050000 },
+		.vreg[VREG_HFPLL_B] = { "l2_l23", 1800000 },
+	},
+};
+
+static struct msm_bus_paths bw_level_tbl[] __initdata = {
+	[0] =  BW_MBPS(640), /* At least  80 MHz on bus. */
+	[1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
+	[2] = BW_MBPS(1600), /* At least 200 MHz on bus. */
+	[3] = BW_MBPS(2128), /* At least 266 MHz on bus. */
+	[4] = BW_MBPS(3200), /* At least 400 MHz on bus. */
+	[5] = BW_MBPS(4264), /* At least 533 MHz on bus. */
+};
+
+static struct msm_bus_scale_pdata bus_scale_data __initdata = {
+	.usecase = bw_level_tbl,
+	.num_usecases = ARRAY_SIZE(bw_level_tbl),
+	.active_only = 1,
+	.name = "acpuclk-8960ab",
+};
+
+static struct l2_level l2_freq_tbl[] __initdata = {
+	[0]  = { {  384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
+	[1]  = { {  486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 2 },
+	[2]  = { {  594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
+	[3]  = { {  702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 4 },
+	[4]  = { {  810000, HFPLL, 1, 0, 0x1E }, 1050000, 1050000, 4 },
+	[5]  = { {  918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 5 },
+	[6]  = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 5 },
+	[7]  = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 5 },
+	[8]  = { { 1242000, HFPLL, 1, 0, 0x2E }, 1150000, 1150000, 5 },
+	[9]  = { { 1350000, HFPLL, 1, 0, 0x32 }, 1150000, 1150000, 5 },
+};
+
+static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
+	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(0),   950000 },
+	{ 0, {   432000, HFPLL, 2, 0, 0x20 }, L2(3),   975000 },
+	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(3),   975000 },
+	{ 0, {   540000, HFPLL, 2, 0, 0x28 }, L2(3),  1000000 },
+	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(3),  1000000 },
+	{ 0, {   648000, HFPLL, 1, 0, 0x18 }, L2(3),  1025000 },
+	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(3),  1025000 },
+	{ 0, {   756000, HFPLL, 1, 0, 0x1C }, L2(3),  1075000 },
+	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(3),  1075000 },
+	{ 0, {   864000, HFPLL, 1, 0, 0x20 }, L2(3),  1100000 },
+	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(3),  1100000 },
+	{ 0, {   972000, HFPLL, 1, 0, 0x24 }, L2(3),  1125000 },
+	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(3),  1125000 },
+	{ 0, {  1080000, HFPLL, 1, 0, 0x28 }, L2(9),  1175000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(9),  1175000 },
+	{ 0, {  1188000, HFPLL, 1, 0, 0x2C }, L2(9),  1200000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(9),  1200000 },
+	{ 0, {  1296000, HFPLL, 1, 0, 0x30 }, L2(9),  1225000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(9),  1225000 },
+	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(9),  1237500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(9),  1237500 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(9),  1250000 },
+	{ 0, { 0 } }
+};
+
+static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
+[PVS_SLOW]    = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),  0 },
+[PVS_NOMINAL] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),  0 },
+[PVS_FAST]    = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),  0 },
+};
+
+static struct acpuclk_krait_params acpuclk_8960ab_params __initdata = {
+	.scalable = scalable,
+	.scalable_size = sizeof(scalable),
+	.hfpll_data = &hfpll_data,
+	.pvs_tables = pvs_tables,
+	.l2_freq_tbl = l2_freq_tbl,
+	.l2_freq_tbl_size = sizeof(l2_freq_tbl),
+	.bus_scale = &bus_scale_data,
+	.qfprom_phys_base = 0x00700000,
+};
+
+static int __init acpuclk_8960ab_probe(struct platform_device *pdev)
+{
+	return acpuclk_krait_init(&pdev->dev, &acpuclk_8960ab_params);
+}
+
+static struct platform_driver acpuclk_8960ab_driver = {
+	.driver = {
+		.name = "acpuclk-8960ab",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init acpuclk_8960ab_init(void)
+{
+	return platform_driver_probe(&acpuclk_8960ab_driver,
+					acpuclk_8960ab_probe);
+}
+device_initcall(acpuclk_8960ab_init);
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 8c89014..22275b4 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -23,7 +23,7 @@
 #include "acpuclock-krait.h"
 
 /* Corner type vreg VDD values */
-#define LVL_NONE	RPM_REGULATOR_CORNER_RETENTION
+#define LVL_NONE	RPM_REGULATOR_CORNER_NONE
 #define LVL_LOW		RPM_REGULATOR_CORNER_SVS_SOC
 #define LVL_NOM		RPM_REGULATOR_CORNER_NORMAL
 #define LVL_HIGH	RPM_REGULATOR_CORNER_SUPER_TURBO
@@ -94,11 +94,10 @@
 };
 
 static struct msm_bus_paths bw_level_tbl[] __initdata = {
-	[0] =  BW_MBPS(400), /* At least  50 MHz on bus. */
-	[1] =  BW_MBPS(800), /* At least 100 MHz on bus. */
-	[2] = BW_MBPS(1334), /* At least 167 MHz on bus. */
-	[3] = BW_MBPS(2666), /* At least 200 MHz on bus. */
-	[4] = BW_MBPS(3200), /* At least 333 MHz on bus. */
+	[0] =  BW_MBPS(552), /* At least  69 MHz on bus. */
+	[1] = BW_MBPS(1112), /* At least 139 MHz on bus. */
+	[2] = BW_MBPS(2224), /* At least 278 MHz on bus. */
+	[3] = BW_MBPS(4448), /* At least 556 MHz on bus. */
 };
 
 static struct msm_bus_scale_pdata bus_scale_data __initdata = {
@@ -109,31 +108,59 @@
 };
 
 static struct l2_level l2_freq_tbl[] __initdata = {
-	[0]  = { {  300000, PLL_0, 0, 2,   0 }, LVL_LOW, 1050000, 2 },
-	[1]  = { {  384000, HFPLL, 2, 0,  40 }, LVL_NOM, 1050000, 2 },
-	[2]  = { {  460800, HFPLL, 2, 0,  48 }, LVL_NOM, 1050000, 2 },
-	[3]  = { {  537600, HFPLL, 1, 0,  28 }, LVL_NOM, 1050000, 2 },
-	[4]  = { {  576000, HFPLL, 1, 0,  30 }, LVL_NOM, 1050000, 3 },
-	[5]  = { {  652800, HFPLL, 1, 0,  34 }, LVL_NOM, 1050000, 3 },
-	[6]  = { {  729600, HFPLL, 1, 0,  38 }, LVL_NOM, 1050000, 3 },
-	[7]  = { {  806400, HFPLL, 1, 0,  42 }, LVL_NOM, 1050000, 3 },
-	[8]  = { {  883200, HFPLL, 1, 0,  46 }, LVL_NOM, 1050000, 4 },
-	[9]  = { {  960000, HFPLL, 1, 0,  50 }, LVL_NOM, 1050000, 4 },
-	[10] = { { 1036800, HFPLL, 1, 0,  54 }, LVL_NOM, 1050000, 4 },
+	[0]  = { {  300000, PLL_0, 0, 2,   0 }, LVL_LOW,   950000, 0 },
+	[1]  = { {  384000, HFPLL, 2, 0,  40 }, LVL_NOM,   950000, 1 },
+	[2]  = { {  460800, HFPLL, 2, 0,  48 }, LVL_NOM,   950000, 1 },
+	[3]  = { {  537600, HFPLL, 1, 0,  28 }, LVL_NOM,   950000, 2 },
+	[4]  = { {  576000, HFPLL, 1, 0,  30 }, LVL_NOM,   950000, 2 },
+	[5]  = { {  652800, HFPLL, 1, 0,  34 }, LVL_NOM,   950000, 2 },
+	[6]  = { {  729600, HFPLL, 1, 0,  38 }, LVL_NOM,   950000, 2 },
+	[7]  = { {  806400, HFPLL, 1, 0,  42 }, LVL_NOM,   950000, 2 },
+	[8]  = { {  883200, HFPLL, 1, 0,  46 }, LVL_HIGH, 1050000, 2 },
+	[9]  = { {  960000, HFPLL, 1, 0,  50 }, LVL_HIGH, 1050000, 2 },
+	[10] = { { 1036800, HFPLL, 1, 0,  54 }, LVL_HIGH, 1050000, 3 },
+	[11] = { { 1113600, HFPLL, 1, 0,  58 }, LVL_HIGH, 1050000, 3 },
+	[12] = { { 1190400, HFPLL, 1, 0,  62 }, LVL_HIGH, 1050000, 3 },
+	[13] = { { 1267200, HFPLL, 1, 0,  66 }, LVL_HIGH, 1050000, 3 },
+	[14] = { { 1344000, HFPLL, 1, 0,  70 }, LVL_HIGH, 1050000, 3 },
+	[15] = { { 1420800, HFPLL, 1, 0,  74 }, LVL_HIGH, 1050000, 3 },
+	[16] = { { 1497600, HFPLL, 1, 0,  78 }, LVL_HIGH, 1050000, 3 },
+	[17] = { { 1574400, HFPLL, 1, 0,  82 }, LVL_HIGH, 1050000, 3 },
+	[18] = { { 1651200, HFPLL, 1, 0,  86 }, LVL_HIGH, 1050000, 3 },
+	[19] = { { 1728000, HFPLL, 1, 0,  90 }, LVL_HIGH, 1050000, 3 },
+	[20] = { { 1804800, HFPLL, 1, 0,  94 }, LVL_HIGH, 1050000, 3 },
+	[21] = { { 1881600, HFPLL, 1, 0,  98 }, LVL_HIGH, 1050000, 3 },
+	[22] = { { 1958400, HFPLL, 1, 0, 102 }, LVL_HIGH, 1050000, 3 },
+	[23] = { { 2035200, HFPLL, 1, 0, 106 }, LVL_HIGH, 1050000, 3 },
+	[24] = { { 2112000, HFPLL, 1, 0, 110 }, LVL_HIGH, 1050000, 3 },
+	[25] = { { 2188800, HFPLL, 1, 0, 114 }, LVL_HIGH, 1050000, 3 },
 };
 
 static struct acpu_level acpu_freq_tbl[] __initdata = {
-	{ 1, {  300000, PLL_0, 0, 2,   0 }, L2(0),  1050000, 3200000 },
-	{ 1, {  384000, HFPLL, 2, 0,  40 }, L2(1),  1050000, 3200000 },
-	{ 1, {  460800, HFPLL, 2, 0,  48 }, L2(2),  1050000, 3200000 },
-	{ 1, {  537600, HFPLL, 1, 0,  28 }, L2(3),  1050000, 3200000 },
-	{ 1, {  576000, HFPLL, 1, 0,  30 }, L2(4),  1050000, 3200000 },
-	{ 1, {  652800, HFPLL, 1, 0,  34 }, L2(5),  1050000, 3200000 },
-	{ 1, {  729600, HFPLL, 1, 0,  38 }, L2(6),  1050000, 3200000 },
-	{ 1, {  806400, HFPLL, 1, 0,  42 }, L2(7),  1050000, 3200000 },
-	{ 1, {  883200, HFPLL, 1, 0,  46 }, L2(8),  1050000, 3200000 },
-	{ 1, {  960000, HFPLL, 1, 0,  50 }, L2(9),  1050000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1, 0,  54 }, L2(10), 1050000, 3200000 },
+	{ 1, {  300000, PLL_0, 0, 2,   0 }, L2(0),   950000, 3200000 },
+	{ 1, {  384000, HFPLL, 2, 0,  40 }, L2(3),   950000, 3200000 },
+	{ 1, {  460800, HFPLL, 2, 0,  48 }, L2(3),   950000, 3200000 },
+	{ 1, {  537600, HFPLL, 1, 0,  28 }, L2(5),   950000, 3200000 },
+	{ 1, {  576000, HFPLL, 1, 0,  30 }, L2(5),   950000, 3200000 },
+	{ 1, {  652800, HFPLL, 1, 0,  34 }, L2(5),   950000, 3200000 },
+	{ 1, {  729600, HFPLL, 1, 0,  38 }, L2(5),   950000, 3200000 },
+	{ 1, {  806400, HFPLL, 1, 0,  42 }, L2(7),   950000, 3200000 },
+	{ 1, {  883200, HFPLL, 1, 0,  46 }, L2(7),   950000, 3200000 },
+	{ 1, {  960000, HFPLL, 1, 0,  50 }, L2(7),   950000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1, 0,  54 }, L2(7),   950000, 3200000 },
+	{ 0, { 1113600, HFPLL, 1, 0,  58 }, L2(12), 1050000, 3200000 },
+	{ 0, { 1190400, HFPLL, 1, 0,  62 }, L2(12), 1050000, 3200000 },
+	{ 0, { 1267200, HFPLL, 1, 0,  66 }, L2(12), 1050000, 3200000 },
+	{ 0, { 1344000, HFPLL, 1, 0,  70 }, L2(15), 1050000, 3200000 },
+	{ 0, { 1420800, HFPLL, 1, 0,  74 }, L2(15), 1050000, 3200000 },
+	{ 0, { 1497600, HFPLL, 1, 0,  78 }, L2(15), 1050000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1, 0,  82 }, L2(20), 1050000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1, 0,  86 }, L2(20), 1050000, 3200000 },
+	{ 0, { 1728000, HFPLL, 1, 0,  90 }, L2(20), 1050000, 3200000 },
+	{ 0, { 1804800, HFPLL, 1, 0,  94 }, L2(25), 1050000, 3200000 },
+	{ 0, { 1881600, HFPLL, 1, 0,  98 }, L2(25), 1050000, 3200000 },
+	{ 0, { 1958400, HFPLL, 1, 0, 102 }, L2(25), 1050000, 3200000 },
+	{ 0, { 1996800, HFPLL, 1, 0, 104 }, L2(25), 1050000, 3200000 },
 	{ 0, { 0 } }
 };
 
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index 33396e5..9afa7c0 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -214,6 +214,9 @@
 {
 	const struct core_speed *strt_s = sc->cur_speed;
 
+	if (strt_s == tgt_s)
+		return;
+
 	if (strt_s->src == HFPLL && tgt_s->src == HFPLL) {
 		/*
 		 * Move to an always-on source running at a frequency
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index b35e949..04e751a 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -47,16 +47,29 @@
 #define BAM_MUX_HDR_CMD_STATUS		3 /* unused */
 #define BAM_MUX_HDR_CMD_OPEN_NO_A2_PC	4
 
-#define POLLING_MIN_SLEEP	950	/* 0.95 ms */
-#define POLLING_MAX_SLEEP	1050	/* 1.05 ms */
-#define POLLING_INACTIVITY	40	/* cycles before switch to intr mode */
 
 #define LOW_WATERMARK		2
 #define HIGH_WATERMARK		4
+#define DEFAULT_POLLING_MIN_SLEEP (950)
+#define MAX_POLLING_SLEEP (6050)
+#define MIN_POLLING_SLEEP (950)
 
 static int msm_bam_dmux_debug_enable;
 module_param_named(debug_enable, msm_bam_dmux_debug_enable,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int POLLING_MIN_SLEEP = 950;
+module_param_named(min_sleep, POLLING_MIN_SLEEP,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int POLLING_MAX_SLEEP = 1050;
+module_param_named(max_sleep, POLLING_MAX_SLEEP,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int POLLING_INACTIVITY = 40;
+module_param_named(inactivity, POLLING_INACTIVITY,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int bam_adaptive_timer_enabled = 1;
+module_param_named(adaptive_timer_enabled,
+			bam_adaptive_timer_enabled,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
 
 #if defined(DEBUG)
 static uint32_t bam_dmux_read_cnt;
@@ -177,6 +190,7 @@
 static int bam_mux_initialized;
 
 static int polling_mode;
+static unsigned long rx_timer_interval;
 
 static LIST_HEAD(bam_rx_pool);
 static DEFINE_MUTEX(bam_rx_pool_mutexlock);
@@ -1116,6 +1130,7 @@
 	struct rx_pkt_info *info;
 	int inactive_cycles = 0;
 	int ret;
+	u32 buffs_unused, buffs_used;
 
 	while (bam_connection_is_active) { /* timer loop */
 		++inactive_cycles;
@@ -1162,12 +1177,47 @@
 			handle_bam_mux_cmd(&info->work);
 		}
 
-		if (inactive_cycles == POLLING_INACTIVITY) {
+		if (inactive_cycles >= POLLING_INACTIVITY) {
 			rx_switch_to_interrupt_mode();
 			break;
 		}
 
-		usleep_range(POLLING_MIN_SLEEP, POLLING_MAX_SLEEP);
+		if (bam_adaptive_timer_enabled) {
+			usleep_range(rx_timer_interval, rx_timer_interval + 50);
+
+			ret = sps_get_unused_desc_num(bam_rx_pipe,
+						&buffs_unused);
+
+			if (ret) {
+				pr_err("%s: error getting num buffers unused after sleep\n",
+					__func__);
+
+				break;
+			}
+
+			buffs_used = NUM_BUFFERS - buffs_unused;
+
+			if (buffs_unused == 0) {
+				rx_timer_interval = MIN_POLLING_SLEEP;
+			} else {
+				if (buffs_used > 0) {
+					rx_timer_interval =
+						(2 * NUM_BUFFERS *
+							rx_timer_interval)/
+						(3 * buffs_used);
+				} else {
+					rx_timer_interval =
+						MAX_POLLING_SLEEP;
+				}
+			}
+
+			if (rx_timer_interval > MAX_POLLING_SLEEP)
+				rx_timer_interval = MAX_POLLING_SLEEP;
+			else if (rx_timer_interval < MIN_POLLING_SLEEP)
+				rx_timer_interval = MIN_POLLING_SLEEP;
+		} else {
+			usleep_range(POLLING_MIN_SLEEP, POLLING_MAX_SLEEP);
+		}
 	}
 }
 
@@ -2379,6 +2429,8 @@
 		bam_dmux_state_logging_disabled = 1;
 	}
 
+	rx_timer_interval = DEFAULT_POLLING_MIN_SLEEP;
+
 	subsys_notif_register_notifier("modem", &restart_notifier);
 	return platform_driver_register(&bam_dmux_driver);
 }
diff --git a/arch/arm/mach-msm/board-8064-display.c b/arch/arm/mach-msm/board-8064-display.c
index 330d7a8..5780ca1 100644
--- a/arch/arm/mach-msm/board-8064-display.c
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -236,18 +236,9 @@
 	.name = "mdp",
 };
 
-static int mdp_core_clk_rate_table[] = {
-	59080000,
-	128000000,
-	160000000,
-	200000000,
-};
-
 static struct msm_panel_common_pdata mdp_pdata = {
 	.gpio = MDP_VSYNC_GPIO,
-	.mdp_core_clk_rate = 59080000,
-	.mdp_core_clk_table = mdp_core_clk_rate_table,
-	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+	.mdp_max_clk = 200000000,
 	.mdp_bus_scale_table = &mdp_bus_scale_pdata,
 	.mdp_rev = MDP_REV_44,
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
@@ -626,14 +617,17 @@
 
 static int lvds_pixel_remap(void)
 {
+	u32 ver = socinfo_get_version();
+
 	if (machine_is_apq8064_cdp() ||
 	    machine_is_apq8064_liquid()) {
-		u32 ver = socinfo_get_version();
 		if ((SOCINFO_VERSION_MAJOR(ver) == 1) &&
 		    (SOCINFO_VERSION_MINOR(ver) == 0))
 			return LVDS_PIXEL_MAP_PATTERN_1;
 	} else if (machine_is_mpq8064_dtv()) {
-		return LVDS_PIXEL_MAP_PATTERN_2;
+		if ((SOCINFO_VERSION_MAJOR(ver) == 1) &&
+		    (SOCINFO_VERSION_MINOR(ver) == 0))
+			return LVDS_PIXEL_MAP_PATTERN_2;
 	}
 	return 0;
 }
@@ -1023,8 +1017,6 @@
  */
 static void set_mdp_clocks_for_wuxga(void)
 {
-	int i;
-
 	mdp_ui_vectors[0].ab = 2000000000;
 	mdp_ui_vectors[0].ib = 2000000000;
 	mdp_vga_vectors[0].ab = 2000000000;
@@ -1034,11 +1026,6 @@
 	mdp_1080p_vectors[0].ab = 2000000000;
 	mdp_1080p_vectors[0].ib = 2000000000;
 
-	mdp_pdata.mdp_core_clk_rate = 200000000;
-
-	for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
-		mdp_core_clk_rate_table[i] = 200000000;
-
 	if (apq8064_hdmi_as_primary_selected()) {
 		dtv_bus_def_vectors[0].ab = 2000000000;
 		dtv_bus_def_vectors[0].ib = 2000000000;
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 1c19442..4c7ea58 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -493,6 +493,22 @@
 		},
 	},
 };
+static struct msm_gpiomux_config cyts_gpio_alt_config[] __initdata = {
+	{	/* TS INTERRUPT */
+		.gpio = 6,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cyts_int_act_cfg,
+			[GPIOMUX_SUSPENDED] = &cyts_int_sus_cfg,
+		},
+	},
+	{	/* TS SLEEP */
+		.gpio = 12,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cyts_sleep_act_cfg,
+			[GPIOMUX_SUSPENDED] = &cyts_sleep_sus_cfg,
+		},
+	},
+};
 
 static struct gpiomux_setting hsic_act_cfg = {
 	.func = GPIOMUX_FUNC_1,
@@ -788,7 +804,7 @@
 static struct gpiomux_setting mdm2ap_status_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_NONE,
+	.pull = GPIOMUX_PULL_DOWN,
 };
 
 static struct gpiomux_setting mdm2ap_errfatal_cfg = {
@@ -828,6 +844,7 @@
 	{
 		.gpio = 49,
 		.settings = {
+			[GPIOMUX_ACTIVE] = &mdm2ap_status_cfg,
 			[GPIOMUX_SUSPENDED] = &mdm2ap_status_cfg,
 		}
 	},
@@ -868,6 +885,58 @@
 	},
 };
 
+static struct msm_gpiomux_config mdm_i2s_configs[] __initdata = {
+	/* AP2MDM_STATUS */
+	{
+		.gpio = 48,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+		}
+	},
+	/* MDM2AP_STATUS */
+	{
+		.gpio = 49,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mdm2ap_status_cfg,
+		}
+	},
+	/* MDM2AP_ERRFATAL */
+	{
+		.gpio = 19,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mdm2ap_errfatal_cfg,
+		}
+	},
+	/* AP2MDM_ERRFATAL */
+	{
+		.gpio = 18,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+		}
+	},
+	/* AP2MDM_SOFT_RESET, aka AP2MDM_PON_RESET_N */
+	{
+		.gpio = 0,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_soft_reset_cfg,
+		}
+	},
+	/* AP2MDM_WAKEUP */
+	{
+		.gpio = 44,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ap2mdm_wakeup,
+		}
+	},
+	/* MDM2AP_PBL_READY*/
+	{
+		.gpio = 81,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mdm2ap_pblrdy,
+		}
+	},
+};
+
 static struct gpiomux_setting mi2s_act_cfg = {
 	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_8MA,
@@ -1201,6 +1270,7 @@
 void __init apq8064_init_gpiomux(void)
 {
 	int rc;
+	int platform_version = socinfo_get_platform_version();
 
 	rc = msm_gpiomux_init(NR_GPIO_IRQS);
 	if (rc) {
@@ -1255,16 +1325,27 @@
 	msm_gpiomux_install(apq8064_ext_regulator_configs,
 			ARRAY_SIZE(apq8064_ext_regulator_configs));
 
-	if (machine_is_apq8064_mtp())
-		msm_gpiomux_install(mdm_configs,
-			ARRAY_SIZE(mdm_configs));
+	if (machine_is_apq8064_mtp()) {
+		if (SOCINFO_VERSION_MINOR(platform_version) == 1)
+			msm_gpiomux_install(mdm_i2s_configs,
+					ARRAY_SIZE(mdm_i2s_configs));
+		else
+			msm_gpiomux_install(mdm_configs,
+					ARRAY_SIZE(mdm_configs));
+	}
+
+	if (machine_is_apq8064_mtp()) {
+		if (SOCINFO_VERSION_MINOR(platform_version) == 1) {
+			msm_gpiomux_install(cyts_gpio_alt_config,
+					ARRAY_SIZE(cyts_gpio_alt_config));
+		} else {
+			msm_gpiomux_install(cyts_gpio_configs,
+					ARRAY_SIZE(cyts_gpio_configs));
+		}
+	}
 
 #ifdef CONFIG_USB_EHCI_MSM_HSIC
 	if (machine_is_apq8064_mtp())
-		msm_gpiomux_install(cyts_gpio_configs,
-				ARRAY_SIZE(cyts_gpio_configs));
-
-	if (machine_is_apq8064_mtp())
 		msm_gpiomux_install(apq8064_hsic_configs,
 				ARRAY_SIZE(apq8064_hsic_configs));
 #endif
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 0e31c45..0c2e4c3 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -127,6 +127,7 @@
 	/* TABLA CODEC RESET */
 	PM8921_GPIO_OUTPUT(34, 1, MED),
 	PM8921_GPIO_OUTPUT(13, 0, HIGH),               /* PCIE_CLK_PWR_EN */
+	PM8921_GPIO_INPUT(12, PM_GPIO_PULL_UP_30),     /* PCIE_WAKE_N */
 };
 
 static struct pm8xxx_gpio_init pm8921_mtp_kp_gpios[] __initdata = {
@@ -140,6 +141,12 @@
 	PM8921_GPIO_INPUT(17, PM_GPIO_PULL_UP_1P5),	/* SD_WP */
 };
 
+static struct pm8xxx_gpio_init pm8921_mpq_gpios[] __initdata = {
+	PM8921_GPIO_INIT(27, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0,
+			PM_GPIO_PULL_NO, PM_GPIO_VIN_VPH, PM_GPIO_STRENGTH_NO,
+			PM_GPIO_FUNC_NORMAL, 0, 0),
+};
+
 /* Initial PM8XXX MPP configurations */
 static struct pm8xxx_mpp_init pm8xxx_mpps[] __initdata = {
 	PM8921_MPP_INIT(3, D_OUTPUT, PM8921_MPP_DIG_LEVEL_VPH, DOUT_CTRL_LOW),
@@ -185,6 +192,18 @@
 			}
 		}
 
+	if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd()
+					|| machine_is_mpq8064_dtv())
+		for (i = 0; i < ARRAY_SIZE(pm8921_mpq_gpios); i++) {
+			rc = pm8xxx_gpio_config(pm8921_mpq_gpios[i].gpio,
+						&pm8921_mpq_gpios[i].config);
+			if (rc) {
+				pr_err("%s: pm8xxx_gpio_config: rc=%d\n",
+					__func__, rc);
+				break;
+			}
+		}
+
 	for (i = 0; i < ARRAY_SIZE(pm8xxx_mpps); i++) {
 		rc = pm8xxx_mpp_config(pm8xxx_mpps[i].mpp,
 					&pm8xxx_mpps[i].config);
@@ -341,6 +360,7 @@
 };
 
 #define MAX_VOLTAGE_MV          4200
+#define CHG_TERM_MA		100
 static struct pm8921_charger_platform_data
 apq8064_pm8921_chg_pdata __devinitdata = {
 	.safety_time		= 180,
@@ -350,7 +370,7 @@
 	.uvd_thresh_voltage	= 4050,
 	.alarm_voltage		= 3400,
 	.resume_voltage_delta	= 100,
-	.term_current		= 100,
+	.term_current		= CHG_TERM_MA,
 	.cool_temp		= 10,
 	.warm_temp		= 40,
 	.temp_check_period	= 1,
@@ -371,11 +391,14 @@
 
 static struct pm8921_bms_platform_data
 apq8064_pm8921_bms_pdata __devinitdata = {
-	.battery_type	= BATT_UNKNOWN,
-	.r_sense		= 10,
-	.i_test			= 2500,
-	.v_failure		= 3000,
-	.max_voltage_uv		= MAX_VOLTAGE_MV * 1000,
+	.battery_type			= BATT_UNKNOWN,
+	.r_sense			= 10,
+	.v_cutoff			= 3400,
+	.max_voltage_uv			= MAX_VOLTAGE_MV * 1000,
+	.rconn_mohm			= 18,
+	.shutdown_soc_valid_limit	= 20,
+	.adjust_soc_low_threshold	= 25,
+	.chg_term_ua			= CHG_TERM_MA * 1000,
 };
 
 static struct pm8921_platform_data
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index a84cb39..10b7034 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -632,11 +632,12 @@
 };
 
 struct rpm_regulator_platform_data apq8064_rpm_regulator_pdata __devinitdata = {
-	.init_data		= apq8064_rpm_regulator_init_data,
-	.num_regulators		= ARRAY_SIZE(apq8064_rpm_regulator_init_data),
-	.version		= RPM_VREG_VERSION_8960,
-	.vreg_id_vdd_mem	= RPM_VREG_ID_PM8921_L24,
-	.vreg_id_vdd_dig	= RPM_VREG_ID_PM8921_S3,
-	.consumer_map		= msm_rpm_regulator_consumer_mapping,
+	.init_data		  = apq8064_rpm_regulator_init_data,
+	.num_regulators		  = ARRAY_SIZE(apq8064_rpm_regulator_init_data),
+	.version		  = RPM_VREG_VERSION_8960,
+	.vreg_id_vdd_mem	  = RPM_VREG_ID_PM8921_L24,
+	.vreg_id_vdd_dig	  = RPM_VREG_ID_PM8921_S3,
+	.requires_tcxo_workaround = true,
+	.consumer_map		  = msm_rpm_regulator_consumer_mapping,
 	.consumer_map_len = ARRAY_SIZE(msm_rpm_regulator_consumer_mapping),
 };
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 6317685..ab9004f 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -95,7 +95,7 @@
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 #define HOLE_SIZE		0x20000
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0x65000
+#define MSM_CONTIG_MEM_SIZE  0x65000
 #ifdef CONFIG_MSM_IOMMU
 #define MSM_ION_MM_SIZE		0x3800000
 #define MSM_ION_SF_SIZE		0
@@ -111,7 +111,7 @@
 #define MSM_ION_MFC_SIZE	SZ_8K
 #define MSM_ION_AUDIO_SIZE	MSM_PMEM_AUDIO_SIZE
 #else
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0x110C000
+#define MSM_CONTIG_MEM_SIZE  0x110C000
 #define MSM_ION_HEAP_NUM	1
 #endif
 
@@ -128,18 +128,19 @@
 #define PCIE_AXI_BAR_PHYS   0x08000000
 #define PCIE_AXI_BAR_SIZE   SZ_128M
 
-/* PCIe power enable pmic gpio */
+/* PCIe pmic gpios */
+#define PCIE_WAKE_N_PMIC_GPIO 12
 #define PCIE_PWR_EN_PMIC_GPIO 13
 #define PCIE_RST_N_PMIC_MPP 1
 
-#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
-static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
-static int __init pmem_kernel_ebi1_size_setup(char *p)
+#ifdef CONFIG_KERNEL_MSM_CONTIG_MEM_REGION
+static unsigned msm_contig_mem_size = MSM_CONTIG_MEM_SIZE;
+static int __init msm_contig_mem_size_setup(char *p)
 {
-	pmem_kernel_ebi1_size = memparse(p, NULL);
+	msm_contig_mem_size = memparse(p, NULL);
 	return 0;
 }
-early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+early_param("msm_contig_mem_size", msm_contig_mem_size_setup);
 #endif
 
 #ifdef CONFIG_ANDROID_PMEM
@@ -262,7 +263,7 @@
 	reserve_memory_for(&android_pmem_pdata);
 	reserve_memory_for(&android_pmem_audio_pdata);
 #endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
-	apq8064_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+	apq8064_reserve_table[MEMTYPE_EBI1].size += msm_contig_mem_size;
 #endif /*CONFIG_ANDROID_PMEM*/
 }
 
@@ -887,6 +888,10 @@
 	-1
 };
 
+#define PMIC_GPIO_DP		27    /* PMIC GPIO for D+ change */
+#define PMIC_GPIO_DP_IRQ	PM8921_GPIO_IRQ(PM8921_IRQ_BASE, PMIC_GPIO_DP)
+#define MSM_MPM_PIN_USB1_OTGSESSVLD	40
+
 static struct msm_otg_platform_data msm_otg_pdata = {
 	.mode			= USB_OTG,
 	.otg_control		= OTG_PMIC_CONTROL,
@@ -895,6 +900,7 @@
 	.power_budget		= 750,
 	.bus_scale_table	= &usb_bus_scale_pdata,
 	.phy_init_seq		= phy_init_seq,
+	.mpm_otgsessvld_int	= MSM_MPM_PIN_USB1_OTGSESSVLD,
 };
 
 static struct msm_usb_host_platform_data msm_ehci_host_pdata3 = {
@@ -912,6 +918,9 @@
 		if (machine_is_apq8064_liquid())
 			msm_ehci_host_pdata3.dock_connect_irq =
 					PM8921_MPP_IRQ(PM8921_IRQ_BASE, 9);
+		else
+			msm_ehci_host_pdata3.pmic_gpio_dp_irq =
+							PMIC_GPIO_DP_IRQ;
 
 		apq8064_device_ehci_host3.dev.platform_data =
 				&msm_ehci_host_pdata3;
@@ -1013,7 +1022,7 @@
 	.micbias = {
 		.ldoh_v = TABLA_LDOH_2P85_V,
 		.cfilt1_mv = 1800,
-		.cfilt2_mv = 1800,
+		.cfilt2_mv = 2700,
 		.cfilt3_mv = 1800,
 		.bias1_cfilt_sel = TABLA_CFILT1_SEL,
 		.bias2_cfilt_sel = TABLA_CFILT2_SEL,
@@ -1080,7 +1089,7 @@
 	.micbias = {
 		.ldoh_v = TABLA_LDOH_2P85_V,
 		.cfilt1_mv = 1800,
-		.cfilt2_mv = 1800,
+		.cfilt2_mv = 2700,
 		.cfilt3_mv = 1800,
 		.bias1_cfilt_sel = TABLA_CFILT1_SEL,
 		.bias2_cfilt_sel = TABLA_CFILT2_SEL,
@@ -1373,6 +1382,7 @@
 };
 #define CYTTSP_TS_GPIO_IRQ		6
 #define CYTTSP_TS_GPIO_SLEEP		33
+#define CYTTSP_TS_GPIO_SLEEP_ALT	12
 
 static ssize_t tma340_vkeys_show(struct kobject *kobj,
 			struct kobj_attribute *attr, char *buf)
@@ -1726,6 +1736,12 @@
 	.mdm2ap_vddmin_gpio = 80,
 };
 
+static struct gpiomux_setting mdm2ap_status_gpio_run_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
 static struct mdm_platform_data mdm_platform_data = {
 	.mdm_version = "3.0",
 	.ramdump_delay_ms = 2000,
@@ -1734,6 +1750,7 @@
 	.vddmin_resource = &mdm_vddmin_rscs,
 	.peripheral_platform_device = &apq8064_device_hsic_host,
 	.ramdump_timeout_ms = 120000,
+	.mdm2ap_status_gpio_run_cfg = &mdm2ap_status_gpio_run_cfg,
 };
 
 static struct tsens_platform_data apq_tsens_pdata  = {
@@ -2075,6 +2092,7 @@
 	.gpio = msm_pcie_gpio_info,
 	.axi_addr = PCIE_AXI_BAR_PHYS,
 	.axi_size = PCIE_AXI_BAR_SIZE,
+	.wake_n = PM8921_GPIO_IRQ(PM8921_IRQ_BASE, PCIE_WAKE_N_PMIC_GPIO),
 };
 
 static int __init mpq8064_pcie_enabled(void)
@@ -2224,6 +2242,7 @@
 	&apq_lpa_pcm,
 	&apq_compr_dsp,
 	&apq_multi_ch_pcm,
+	&apq_lowlatency_pcm,
 	&apq_pcm_hostless,
 	&apq_cpudai_afe_01_rx,
 	&apq_cpudai_afe_01_tx,
@@ -2250,7 +2269,6 @@
 	&msm_bus_8064_cpss_fpb,
 	&apq8064_msm_device_vidc,
 	&msm_pil_dsps,
-	&msm_8960_riva,
 	&msm_8960_q6_lpass,
 	&msm_pil_vidc,
 	&msm_gss,
@@ -2260,11 +2278,13 @@
 	&msm8960_device_ebi1_ch0_erp,
 	&msm8960_device_ebi1_ch1_erp,
 	&epm_adc_device,
-	&apq8064_qdss_device,
-	&msm_etb_device,
-	&msm_tpiu_device,
-	&msm_funnel_device,
-	&apq8064_etm_device,
+	&coresight_tpiu_device,
+	&coresight_etb_device,
+	&apq8064_coresight_funnel_device,
+	&coresight_etm0_device,
+	&coresight_etm1_device,
+	&coresight_etm2_device,
+	&coresight_etm3_device,
 	&apq_cpudai_slim_4_rx,
 	&apq_cpudai_slim_4_tx,
 #ifdef CONFIG_MSM_GEMINI
@@ -2273,6 +2293,7 @@
 	&apq8064_iommu_domain_device,
 	&msm_tsens_device,
 	&apq8064_cache_dump_device,
+	&msm_8064_device_tspp,
 };
 
 static struct platform_device *cdp_devices[] __initdata = {
@@ -2893,6 +2914,8 @@
 
 static void __init apq8064_common_init(void)
 {
+	u32 platform_version;
+	platform_device_register(&msm_gpio_device);
 	msm_tsens_early_init(&apq_tsens_pdata);
 	msm_thermal_init(&msm_thermal_pdata);
 	if (socinfo_init() < 0)
@@ -2935,12 +2958,23 @@
 
 	if (machine_is_apq8064_mtp()) {
 		mdm_8064_device.dev.platform_data = &mdm_platform_data;
-		platform_device_register(&mdm_8064_device);
+		platform_version = socinfo_get_platform_version();
+		if (SOCINFO_VERSION_MINOR(platform_version) == 1) {
+			i2s_mdm_8064_device.dev.platform_data =
+				&mdm_platform_data;
+			platform_device_register(&i2s_mdm_8064_device);
+		} else {
+			mdm_8064_device.dev.platform_data = &mdm_platform_data;
+			platform_device_register(&mdm_8064_device);
+		}
 	}
 	platform_device_register(&apq8064_slim_ctrl);
 	slim_register_board_info(apq8064_slim_devices,
 		ARRAY_SIZE(apq8064_slim_devices));
-	apq8064_init_dsps();
+	if (!PLATFORM_IS_MPQ8064()) {
+		apq8064_init_dsps();
+		platform_device_register(&msm_8960_riva);
+	}
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
 	msm_spm_l2_init(msm_spm_l2_data);
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
@@ -2956,6 +2990,9 @@
 {
 	if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
 		pr_err("meminfo_init() failed!\n");
+	if (machine_is_apq8064_mtp() &&
+		SOCINFO_VERSION_MINOR(socinfo_get_platform_version()) == 1)
+			cyttsp_pdata.sleep_gpio = CYTTSP_TS_GPIO_SLEEP_ALT;
 	apq8064_common_init();
 	if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
 		machine_is_mpq8064_dtv()) {
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index d975997..2a8e918 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -413,31 +413,9 @@
 
 #endif
 
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-static int mdp_core_clk_rate_table[] = {
-	200000000,
-	200000000,
-	200000000,
-	200000000,
-};
-#else
-static int mdp_core_clk_rate_table[] = {
-	85330000,
-	128000000,
-	160000000,
-	200000000,
-};
-#endif
-
 static struct msm_panel_common_pdata mdp_pdata = {
 	.gpio = MDP_VSYNC_GPIO,
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-	.mdp_core_clk_rate = 200000000,
-#else
-	.mdp_core_clk_rate = 85330000,
-#endif
-	.mdp_core_clk_table = mdp_core_clk_rate_table,
-	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+	.mdp_max_clk = 200000000,
 #ifdef CONFIG_MSM_BUS_SCALING
 	.mdp_bus_scale_table = &mdp_bus_scale_pdata,
 #endif
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index e0f012a..ff0a61f 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -688,6 +688,22 @@
 	},
 };
 
+static struct gpiomux_setting gyro_int_line = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config msm8930_gyro_int_config[] __initdata = {
+	{
+		.gpio = 69,	/* Gyro Interrupt Line */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gyro_int_line,
+			[GPIOMUX_ACTIVE] = &gyro_int_line,
+		},
+	},
+};
+
 int __init msm8930_init_gpiomux(void)
 {
 	int rc = msm_gpiomux_init(NR_GPIO_IRQS);
@@ -758,5 +774,9 @@
 	msm_gpiomux_install(msm8930_sd_det_config,
 			ARRAY_SIZE(msm8930_sd_det_config));
 
+	if (machine_is_msm8930_fluid() || machine_is_msm8930_mtp())
+		msm_gpiomux_install(msm8930_gyro_int_config,
+			ARRAY_SIZE(msm8930_gyro_int_config));
+
 	return 0;
 }
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index a1a4b7c..e3479eb 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -207,6 +207,7 @@
 };
 
 #define MAX_VOLTAGE_MV		4200
+#define CHG_TERM_MA		100
 static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = {
 	.safety_time		= 180,
 	.update_time		= 60000,
@@ -214,7 +215,7 @@
 	.min_voltage		= 3200,
 	.uvd_thresh_voltage	= 4050,
 	.resume_voltage_delta	= 100,
-	.term_current		= 100,
+	.term_current		= CHG_TERM_MA,
 	.cool_temp		= 10,
 	.warm_temp		= 40,
 	.temp_check_period	= 1,
@@ -340,11 +341,13 @@
 };
 
 static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
-	.battery_type	= BATT_UNKNOWN,
-	.r_sense		= 10,
-	.i_test			= 2500,
-	.v_failure		= 3000,
-	.max_voltage_uv		= MAX_VOLTAGE_MV * 1000,
+	.battery_type			= BATT_UNKNOWN,
+	.r_sense			= 10,
+	.v_cutoff			= 3400,
+	.max_voltage_uv			= MAX_VOLTAGE_MV * 1000,
+	.shutdown_soc_valid_limit	= 20,
+	.adjust_soc_low_threshold	= 25,
+	.chg_term_ua			= CHG_TERM_MA * 1000,
 };
 
 static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index d3a4960..d4bd18f 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -99,6 +99,9 @@
 	REGULATOR_SUPPLY("cam_vdig",		"4-0048"),
 	REGULATOR_SUPPLY("cam_vdig",            "4-0020"),
 };
+VREG_CONSUMERS(L13) = {
+	REGULATOR_SUPPLY("8038_l13",		NULL),
+};
 VREG_CONSUMERS(L14) = {
 	REGULATOR_SUPPLY("8038_l14",		NULL),
 	REGULATOR_SUPPLY("pa_therm",		"pm8xxx-adc"),
@@ -148,6 +151,9 @@
 	REGULATOR_SUPPLY("8038_l24",		NULL),
 	REGULATOR_SUPPLY("riva_vddmx",		"wcnss_wlan.0"),
 };
+VREG_CONSUMERS(L25) = {
+	REGULATOR_SUPPLY("8038_l25",		NULL),
+};
 VREG_CONSUMERS(L26) = {
 	REGULATOR_SUPPLY("8038_l26",		NULL),
 };
@@ -492,6 +498,7 @@
 	RPM_LDO(L10,	 0, 1, 0, 2900000, 2900000, NULL,      0, 0),
 	RPM_LDO(L11,	 1, 1, 0, 1800000, 1800000, "8038_s4", 10000, 10000),
 	RPM_LDO(L12,	 0, 1, 0, 1200000, 1200000, "8038_s2", 0, 0),
+	RPM_LDO(L13,	 0, 0, 0, 2220000, 2220000, NULL,      0, 0),
 	RPM_LDO(L14,	 0, 1, 0, 1800000, 1800000, NULL,      0, 0),
 	RPM_LDO(L15,	 0, 1, 0, 1800000, 2950000, NULL,      0, 0),
 	RPM_LDO(L17,	 0, 1, 0, 1800000, 2950000, NULL,      0, 0),
@@ -501,6 +508,7 @@
 	RPM_LDO(L22,	 1, 1, 0, 1850000, 2950000, NULL,      10000, 10000),
 	RPM_LDO(L23,	 1, 1, 1, 1800000, 1800000, "8038_s4", 0, 0),
 	RPM_LDO(L24,	 0, 1, 1,  500000, 1150000, "8038_s2", 10000, 10000),
+	RPM_LDO(L25,	 0, 0, 0, 1740000, 1740000, "8038_l13", 0, 0),
 	RPM_LDO(L26,     1, 1, 0, 1050000, 1050000, "8038_s2", 10000, 10000),
 
 	/*	ID     a_on pd ss		    supply */
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index fb20307..a7147b5 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -141,7 +141,7 @@
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 #define HOLE_SIZE	0x20000
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0x65000
+#define MSM_CONTIG_MEM_SIZE  0x65000
 #ifdef CONFIG_MSM_IOMMU
 #define MSM_ION_MM_SIZE            0x3800000 /* Need to be multiple of 64K */
 #define MSM_ION_SF_SIZE            0x0
@@ -168,18 +168,18 @@
 #define MSM8930_FW_START	MSM8930_FIXED_AREA_START
 
 #else
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0x110C000
+#define MSM_CONTIG_MEM_SIZE  0x110C000
 #define MSM_ION_HEAP_NUM	1
 #endif
 
-#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
-static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
-static int __init pmem_kernel_ebi1_size_setup(char *p)
+#ifdef CONFIG_KERNEL_MSM_CONTIG_MEM_REGION
+static unsigned msm_contig_mem_size = MSM_CONTIG_MEM_SIZE;
+static int __init msm_contig_mem_size_setup(char *p)
 {
-	pmem_kernel_ebi1_size = memparse(p, NULL);
+	msm_contig_mem_size = memparse(p, NULL);
 	return 0;
 }
-early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+early_param("msm_contig_mem_size", msm_contig_mem_size_setup);
 #endif
 
 #ifdef CONFIG_ANDROID_PMEM
@@ -322,7 +322,7 @@
 	reserve_memory_for(&android_pmem_pdata);
 	reserve_memory_for(&android_pmem_audio_pdata);
 #endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
-	msm8930_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+	msm8930_reserve_table[MEMTYPE_EBI1].size += msm_contig_mem_size;
 #endif /*CONFIG_ANDROID_PMEM*/
 }
 
@@ -1455,6 +1455,8 @@
 	0x13, 0x83, /* set source impedance adjusment */
 	-1};
 
+#define MSM_MPM_PIN_USB1_OTGSESSVLD	40
+
 static struct msm_otg_platform_data msm_otg_pdata = {
 	.mode			= USB_OTG,
 	.otg_control		= OTG_PMIC_CONTROL,
@@ -1467,6 +1469,7 @@
 #ifdef CONFIG_FB_MSM_HDMI_MHL_8334
 	.mhl_dev_name		= "sii8334",
 #endif
+	.mpm_otgsessvld_int	= MSM_MPM_PIN_USB1_OTGSESSVLD,
 };
 #endif
 
@@ -2236,14 +2239,11 @@
 	&msm8930_ion_dev,
 #endif
 	&msm_device_tz_log,
-
-#ifdef CONFIG_MSM_QDSS
-	&msm_qdss_device,
-	&msm_etb_device,
-	&msm_tpiu_device,
-	&msm_funnel_device,
-	&msm_etm_device,
-#endif
+	&coresight_tpiu_device,
+	&coresight_etb_device,
+	&coresight_funnel_device,
+	&coresight_etm0_device,
+	&coresight_etm1_device,
 	&msm_device_dspcrashd_8960,
 	&msm8960_device_watchdog,
 #ifdef MSM8930_PHASE_2
@@ -2297,6 +2297,8 @@
 	&msm_cpudai_incall_record_rx,
 	&msm_cpudai_incall_record_tx,
 	&msm_pcm_hostless,
+	&msm_multi_ch_pcm,
+	&msm_lowlatency_pcm,
 };
 
 static void __init msm8930_i2c_init(void)
@@ -2431,6 +2433,7 @@
 static struct i2c_board_info __initdata mpu3050_i2c_boardinfo[] = {
 	{
 		I2C_BOARD_INFO("mpu3050", 0x68),
+		.irq = MSM_GPIO_TO_INT(MPU3050_INT_GPIO),
 		.platform_data = &mpu3050_gyro,
 	},
 };
@@ -2572,6 +2575,7 @@
 	if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
 		pr_err("meminfo_init() failed!\n");
 
+	platform_device_register(&msm_gpio_device);
 	msm_tsens_early_init(&msm_tsens_pdata);
 	msm_thermal_init(&msm_thermal_pdata);
 	BUG_ON(msm_rpm_init(&msm8930_rpm_data));
@@ -2606,7 +2610,12 @@
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
 	msm_spm_l2_init(msm_spm_l2_data);
 	msm8930_init_buses();
-	platform_add_devices(msm8930_footswitch, msm8930_num_footswitch);
+	if (cpu_is_msm8627())
+		platform_add_devices(msm8627_footswitch,
+				msm8627_num_footswitch);
+	else
+		platform_add_devices(msm8930_footswitch,
+				msm8930_num_footswitch);
 	if (cpu_is_msm8627())
 		platform_device_register(&msm8627_device_acpuclk);
 	else if (cpu_is_msm8930())
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index ddeba32..f993ed8 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -573,18 +573,9 @@
 
 #endif
 
-static int mdp_core_clk_rate_table[] = {
-	85330000,
-	128000000,
-	160000000,
-	200000000,
-};
-
 static struct msm_panel_common_pdata mdp_pdata = {
 	.gpio = MDP_VSYNC_GPIO,
-	.mdp_core_clk_rate = 85330000,
-	.mdp_core_clk_table = mdp_core_clk_rate_table,
-	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+	.mdp_max_clk = 200000000,
 #ifdef CONFIG_MSM_BUS_SCALING
 	.mdp_bus_scale_table = &mdp_bus_scale_pdata,
 #endif
@@ -1043,8 +1034,6 @@
  */
 static void set_mdp_clocks_for_wuxga(void)
 {
-	int i;
-
 	mdp_ui_vectors[0].ab = 2000000000;
 	mdp_ui_vectors[0].ib = 2000000000;
 	mdp_vga_vectors[0].ab = 2000000000;
@@ -1054,11 +1043,6 @@
 	mdp_1080p_vectors[0].ab = 2000000000;
 	mdp_1080p_vectors[0].ib = 2000000000;
 
-	mdp_pdata.mdp_core_clk_rate = 200000000;
-
-	for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
-		mdp_core_clk_rate_table[i] = 200000000;
-
 	if (hdmi_is_primary) {
 		dtv_bus_def_vectors[0].ab = 2000000000;
 		dtv_bus_def_vectors[0].ib = 2000000000;
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
index 5851990..1771bb9 100644
--- a/arch/arm/mach-msm/board-8960-gpiomux.c
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -55,6 +55,19 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+static struct gpiomux_setting gsbi6_active_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi6_suspended_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+
 static struct gpiomux_setting external_vfr[] = {
 	/* Suspended state */
 	{
@@ -436,6 +449,27 @@
 		},
 	},
 	{
+		.gpio      = 27,        /* GSBI6 BT_INT2AP_N for AR3002 */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi6_suspended_cfg,
+			[GPIOMUX_ACTIVE]    = &gsbi6_active_cfg,
+		},
+	},
+	{
+		.gpio      = 28,        /* GSBI6 BT_EN for AR3002 */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi6_suspended_cfg,
+			[GPIOMUX_ACTIVE]    = &gsbi6_active_cfg,
+		},
+	},
+	{
+		.gpio      = 29,        /* GSBI6 BT_WAKE for AR3002 */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi6_suspended_cfg,
+			[GPIOMUX_ACTIVE]    = &gsbi6_active_cfg,
+		},
+	},
+	{
 		.gpio      = 44,	/* GSBI12 I2C QUP SDA */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gsbi12,
@@ -759,6 +793,16 @@
 	},
 };
 
+static struct msm_gpiomux_config hap_lvl_shft_config_sglte[] __initdata = {
+	{
+		.gpio = 89,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &hap_lvl_shft_suspended_config,
+			[GPIOMUX_ACTIVE] = &hap_lvl_shft_active_config,
+		},
+	},
+};
+
 static struct msm_gpiomux_config sglte_configs[] __initdata = {
 	/* AP2MDM_STATUS */
 	{
@@ -979,8 +1023,9 @@
 	}
 
 #if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
-	msm_gpiomux_install(msm8960_ethernet_configs,
-			ARRAY_SIZE(msm8960_ethernet_configs));
+	if (socinfo_get_platform_subtype() != PLATFORM_SUBTYPE_SGLTE)
+		msm_gpiomux_install(msm8960_ethernet_configs,
+				ARRAY_SIZE(msm8960_ethernet_configs));
 #endif
 
 	msm_gpiomux_install(msm8960_gsbi_configs,
@@ -1007,9 +1052,15 @@
 #endif
 
 	if (machine_is_msm8960_mtp() || machine_is_msm8960_fluid() ||
-		machine_is_msm8960_liquid() || machine_is_msm8960_cdp())
-		msm_gpiomux_install(hap_lvl_shft_config,
-			ARRAY_SIZE(hap_lvl_shft_config));
+		machine_is_msm8960_liquid() || machine_is_msm8960_cdp()) {
+		if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
+			msm_gpiomux_install(hap_lvl_shft_config_sglte,
+				ARRAY_SIZE(hap_lvl_shft_config_sglte));
+
+		else
+			msm_gpiomux_install(hap_lvl_shft_config,
+				ARRAY_SIZE(hap_lvl_shft_config));
+	}
 
 #ifdef CONFIG_USB_EHCI_MSM_HSIC
 	if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 1) &&
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 83ee965..1d3fa00 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -394,6 +394,7 @@
 };
 
 #define MAX_VOLTAGE_MV		4200
+#define CHG_TERM_MA		100
 static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = {
 	.safety_time		= 180,
 	.update_time		= 60000,
@@ -402,7 +403,7 @@
 	.uvd_thresh_voltage	= 4050,
 	.alarm_voltage		= 3400,
 	.resume_voltage_delta	= 100,
-	.term_current		= 100,
+	.term_current		= CHG_TERM_MA,
 	.cool_temp		= 10,
 	.warm_temp		= 40,
 	.temp_check_period	= 1,
@@ -421,12 +422,14 @@
 };
 
 static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
-	.battery_type	= BATT_UNKNOWN,
-	.r_sense		= 10,
-	.i_test			= 2500,
-	.v_failure		= 3000,
-	.max_voltage_uv		= MAX_VOLTAGE_MV * 1000,
-	.rconn_mohm		= 18,
+	.battery_type			= BATT_UNKNOWN,
+	.r_sense			= 10,
+	.v_cutoff			= 3400,
+	.max_voltage_uv			= MAX_VOLTAGE_MV * 1000,
+	.rconn_mohm			= 18,
+	.shutdown_soc_valid_limit	= 20,
+	.adjust_soc_low_threshold	= 25,
+	.chg_term_ua			= CHG_TERM_MA * 1000,
 };
 
 #define	PM8921_LC_LED_MAX_CURRENT	4	/* I = 4mA */
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index 6ad44d8..bcfd5585f 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -182,10 +182,12 @@
 VREG_CONSUMERS(S5) = {
 	REGULATOR_SUPPLY("8921_s5",		NULL),
 	REGULATOR_SUPPLY("krait0",		"acpuclk-8960"),
+	REGULATOR_SUPPLY("krait0",		"acpuclk-8960ab"),
 };
 VREG_CONSUMERS(S6) = {
 	REGULATOR_SUPPLY("8921_s6",		NULL),
 	REGULATOR_SUPPLY("krait1",		"acpuclk-8960"),
+	REGULATOR_SUPPLY("krait1",		"acpuclk-8960ab"),
 };
 VREG_CONSUMERS(S7) = {
 	REGULATOR_SUPPLY("8921_s7",		NULL),
@@ -581,6 +583,17 @@
 	RPM_REG_MAP(S8,  0, 1, "krait0_s8",  "acpuclk-8960"),
 	RPM_REG_MAP(S8,  0, 2, "krait1_s8",  "acpuclk-8960"),
 	RPM_REG_MAP(S8,  0, 6, "l2_s8",      "acpuclk-8960"),
+
+	RPM_REG_MAP(L23, 0, 1, "krait0_l23", "acpuclk-8960ab"),
+	RPM_REG_MAP(L23, 0, 2, "krait1_l23", "acpuclk-8960ab"),
+	RPM_REG_MAP(L23, 0, 6, "l2_l23",     "acpuclk-8960ab"),
+	RPM_REG_MAP(L24, 0, 1, "krait0_mem", "acpuclk-8960ab"),
+	RPM_REG_MAP(L24, 0, 2, "krait1_mem", "acpuclk-8960ab"),
+	RPM_REG_MAP(S3,  0, 1, "krait0_dig", "acpuclk-8960ab"),
+	RPM_REG_MAP(S3,  0, 2, "krait1_dig", "acpuclk-8960ab"),
+	RPM_REG_MAP(S8,  0, 1, "krait0_s8",  "acpuclk-8960ab"),
+	RPM_REG_MAP(S8,  0, 2, "krait1_s8",  "acpuclk-8960ab"),
+	RPM_REG_MAP(S8,  0, 6, "l2_s8",      "acpuclk-8960ab"),
 };
 
 struct rpm_regulator_platform_data msm_rpm_regulator_pdata __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 63eef4a..641c144 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -109,7 +109,6 @@
 
 #define KS8851_RST_GPIO		89
 #define KS8851_IRQ_GPIO		90
-#define HAP_SHIFT_LVL_OE_GPIO	47
 
 #define MHL_GPIO_INT            4
 #define MHL_GPIO_RESET          15
@@ -146,7 +145,7 @@
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 #define HOLE_SIZE	0x20000
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0x65000
+#define MSM_CONTIG_MEM_SIZE  0x65000
 #ifdef CONFIG_MSM_IOMMU
 #define MSM_ION_MM_SIZE            0x3800000 /* Need to be multiple of 64K */
 #define MSM_ION_SF_SIZE            0x0
@@ -174,18 +173,18 @@
 
 static unsigned msm_ion_sf_size = MSM_ION_SF_SIZE;
 #else
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0x110C000
+#define MSM_CONTIG_MEM_SIZE  0x110C000
 #define MSM_ION_HEAP_NUM	1
 #endif
 
-#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
-static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
-static int __init pmem_kernel_ebi1_size_setup(char *p)
+#ifdef CONFIG_KERNEL_MSM_CONTIG_MEM_REGION
+static unsigned msm_contig_mem_size = MSM_CONTIG_MEM_SIZE;
+static int __init msm_contig_mem_size_setup(char *p)
 {
-	pmem_kernel_ebi1_size = memparse(p, NULL);
+	msm_contig_mem_size = memparse(p, NULL);
 	return 0;
 }
-early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+early_param("msm_contig_mem_size", msm_contig_mem_size_setup);
 #endif
 
 #ifdef CONFIG_ANDROID_PMEM
@@ -337,7 +336,7 @@
 	reserve_memory_for(&android_pmem_pdata);
 	reserve_memory_for(&android_pmem_audio_pdata);
 #endif
-	msm8960_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+	msm8960_reserve_table[MEMTYPE_EBI1].size += msm_contig_mem_size;
 #endif
 }
 
@@ -1487,6 +1486,8 @@
 };
 #endif
 
+#define MSM_MPM_PIN_USB1_OTGSESSVLD	40
+
 static struct msm_otg_platform_data msm_otg_pdata = {
 	.mode			= USB_OTG,
 	.otg_control		= OTG_PMIC_CONTROL,
@@ -1495,6 +1496,7 @@
 	.power_budget		= 750,
 #ifdef CONFIG_MSM_BUS_SCALING
 	.bus_scale_table	= &usb_bus_scale_pdata,
+	.mpm_otgsessvld_int	= MSM_MPM_PIN_USB1_OTGSESSVLD,
 #endif
 #ifdef CONFIG_FB_MSM_HDMI_MHL_8334
 	.mhl_dev_name		= "sii8334",
@@ -1706,6 +1708,8 @@
 	},
 };
 
+#define HAP_SHIFT_LVL_OE_GPIO		47
+#define HAP_SHIFT_LVL_OE_GPIO_SGLTE	89
 #define PM_HAP_EN_GPIO		PM8921_GPIO_PM_TO_SYS(33)
 #define PM_HAP_LEN_GPIO		PM8921_GPIO_PM_TO_SYS(20)
 
@@ -1714,8 +1718,13 @@
 static int isa1200_power(int on)
 {
 	int rc = 0;
+	int hap_oe_gpio = HAP_SHIFT_LVL_OE_GPIO;
 
-	gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !!on);
+	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
+		hap_oe_gpio = HAP_SHIFT_LVL_OE_GPIO_SGLTE;
+
+
+	gpio_set_value(hap_oe_gpio, !!on);
 
 	rc = on ? msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_ON) :
 			msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_OFF);
@@ -1728,13 +1737,14 @@
 	return 0;
 
 err_xo_vote:
-	gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !on);
+	gpio_set_value(hap_oe_gpio, !on);
 	return rc;
 }
 
 static int isa1200_dev_setup(bool enable)
 {
 	int rc = 0;
+	int hap_oe_gpio = HAP_SHIFT_LVL_OE_GPIO;
 
 	struct pm_gpio hap_gpio_config = {
 		.direction      = PM_GPIO_DIR_OUT,
@@ -1747,6 +1757,9 @@
 		.output_value   = 0,
 	};
 
+	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
+		hap_oe_gpio = HAP_SHIFT_LVL_OE_GPIO_SGLTE;
+
 	if (enable == true) {
 		rc = pm8xxx_gpio_config(PM_HAP_EN_GPIO, &hap_gpio_config);
 		if (rc) {
@@ -1762,14 +1775,14 @@
 			return rc;
 		}
 
-		rc = gpio_request(HAP_SHIFT_LVL_OE_GPIO, "hap_shft_lvl_oe");
+		rc = gpio_request(hap_oe_gpio, "hap_shft_lvl_oe");
 		if (rc) {
 			pr_err("%s: unable to request gpio %d (%d)\n",
-					__func__, HAP_SHIFT_LVL_OE_GPIO, rc);
+					__func__, hap_oe_gpio, rc);
 			return rc;
 		}
 
-		rc = gpio_direction_output(HAP_SHIFT_LVL_OE_GPIO, 0);
+		rc = gpio_direction_output(hap_oe_gpio, 0);
 		if (rc) {
 			pr_err("%s: Unable to set direction\n", __func__);
 			goto free_gpio;
@@ -1783,7 +1796,7 @@
 			goto gpio_set_dir;
 		}
 	} else {
-		gpio_free(HAP_SHIFT_LVL_OE_GPIO);
+		gpio_free(hap_oe_gpio);
 
 		msm_xo_put(xo_handle_d1);
 	}
@@ -1791,9 +1804,9 @@
 	return 0;
 
 gpio_set_dir:
-	gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, 0);
+	gpio_set_value(hap_oe_gpio, 0);
 free_gpio:
-	gpio_free(HAP_SHIFT_LVL_OE_GPIO);
+	gpio_free(hap_oe_gpio);
 	return rc;
 }
 
@@ -2333,7 +2346,7 @@
 	.rst_gpio = KS8851_RST_GPIO,
 };
 
-static struct spi_board_info spi_board_info[] __initdata = {
+static struct spi_board_info spi_eth_info[] __initdata = {
 	{
 		.modalias               = "ks8851",
 		.irq                    = MSM_GPIO_TO_INT(KS8851_IRQ_GPIO),
@@ -2343,6 +2356,8 @@
 		.mode                   = SPI_MODE_0,
 		.platform_data		= &spi_eth_pdata
 	},
+};
+static struct spi_board_info spi_board_info[] __initdata = {
 	{
 		.modalias               = "dsi_novatek_3d_panel_spi",
 		.max_speed_hz           = 10800000,
@@ -2496,8 +2511,89 @@
 static struct msm_serial_hs_platform_data msm_uart_dm9_pdata;
 #endif
 
+#if defined(CONFIG_BT) && defined(CONFIG_BT_HCIUART_ATH3K)
+static struct resource bluesleep_resources[] = {
+	{
+		.name   = "gpio_host_wake",
+		.start  = 27,
+		.end    = 27,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "gpio_ext_wake",
+		.start  = 29,
+		.end    = 29,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "host_wake",
+		.start  = MSM_GPIO_TO_INT(27),
+		.end    = MSM_GPIO_TO_INT(27),
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_bluesleep_device = {
+	.name		= "bluesleep",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(bluesleep_resources),
+	.resource	= bluesleep_resources,
+};
+
+static struct platform_device msm_bt_power_device = {
+	.name = "bt_power",
+};
+
+int gpio_bt_sys_rest_en = 28;
+
+static int bluetooth_power(int on)
+{
+	int rc;
+
+	if (on) {
+		rc = gpio_direction_output(gpio_bt_sys_rest_en, 1);
+		msleep(100);
+	} else {
+		gpio_set_value(gpio_bt_sys_rest_en, 0);
+		rc = gpio_direction_input(gpio_bt_sys_rest_en);
+		msleep(100);
+	}
+	pr_err("%s on= %d rc = %d\n", __func__, on, rc);
+	return 0;
+}
+
+static void __init bt_power_init(void)
+{
+	int rc;
+
+	msm_bt_power_device.dev.platform_data = &bluetooth_power;
+	pr_err("%s enter\n", __func__);
+
+	rc = gpio_request(gpio_bt_sys_rest_en, "bt sys_rst_n");
+	if (rc) {
+		pr_err("%s: unable to request gpio %d (%d)\n",
+			__func__, gpio_bt_sys_rest_en, rc);
+		return;
+	}
+
+	/* When booting up, de-assert BT reset pin */
+	rc = gpio_direction_output(gpio_bt_sys_rest_en, 0);
+	if (rc) {
+		pr_err("%s: Unable to set direction\n", __func__);
+		goto free_gpio;
+	}
+	pr_err("%s done\n", __func__);
+	return;
+
+free_gpio:
+	gpio_free(gpio_bt_sys_rest_en);
+	return;
+}
+#else
+#define bt_power_init(x) do {} while (0)
+#endif
+
 static struct platform_device *common_devices[] __initdata = {
-	&msm8960_device_acpuclk,
 	&msm8960_device_dmov,
 	&msm_device_smd,
 	&msm_device_uart_dm6,
@@ -2515,6 +2611,10 @@
 #endif
 	&msm_slim_ctrl,
 	&msm_device_wcnss_wlan,
+#if defined(CONFIG_BT) && defined(CONFIG_BT_HCIUART_ATH3K)
+	&msm_bluesleep_device,
+	&msm_bt_power_device,
+#endif
 #if defined(CONFIG_QSEECOM)
 	&qseecom_device,
 #endif
@@ -2563,13 +2663,11 @@
 	&msm8960_rpm_log_device,
 	&msm8960_rpm_stat_device,
 	&msm_device_tz_log,
-#ifdef CONFIG_MSM_QDSS
-	&msm_qdss_device,
-	&msm_etb_device,
-	&msm_tpiu_device,
-	&msm_funnel_device,
-	&msm_etm_device,
-#endif
+	&coresight_tpiu_device,
+	&coresight_etb_device,
+	&coresight_funnel_device,
+	&coresight_etm0_device,
+	&coresight_etm1_device,
 	&msm_device_dspcrashd_8960,
 	&msm8960_device_watchdog,
 	&msm8960_rtb_device,
@@ -2597,6 +2695,7 @@
 	&android_usb_device,
 	&msm_pcm,
 	&msm_multi_ch_pcm,
+	&msm_lowlatency_pcm,
 	&msm_pcm_routing,
 	&msm_cpudai0,
 	&msm_cpudai1,
@@ -2909,7 +3008,7 @@
 		ARRAY_SIZE(sii_device_info),
 	},
 	{
-		I2C_LIQUID,
+		I2C_LIQUID | I2C_FFA,
 		MSM_8960_GSBI10_QUP_I2C_BUS_ID,
 		msm_isa1200_board_info,
 		ARRAY_SIZE(msm_isa1200_board_info),
@@ -2983,6 +3082,7 @@
 	if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
 		pr_err("meminfo_init() failed!\n");
 
+	platform_device_register(&msm_gpio_device);
 	msm_tsens_early_init(&msm_tsens_pdata);
 	msm_thermal_init(&msm_thermal_pdata);
 	BUG_ON(msm_rpm_init(&msm8960_rpm_data));
@@ -3013,10 +3113,12 @@
 	msm8960_device_qup_spi_gsbi1.dev.platform_data =
 				&msm8960_qup_spi_gsbi1_pdata;
 	spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+	if (socinfo_get_platform_subtype() != PLATFORM_SUBTYPE_SGLTE)
+		spi_register_board_info(spi_eth_info, ARRAY_SIZE(spi_eth_info));
 
 	msm8960_init_pmic();
-	if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2 &&
-		(machine_is_msm8960_mtp())) || machine_is_msm8960_liquid())
+	if (machine_is_msm8960_liquid() || (machine_is_msm8960_mtp() &&
+		(socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)))
 		msm_isa1200_board_info[0].platform_data = &isa1200_1_pdata;
 	msm8960_i2c_init();
 	msm8960_gfx_init();
@@ -3046,7 +3148,12 @@
 		msm_device_uart_dm8.dev.platform_data = &msm_uart_dm8_pdata;
 		platform_device_register(&msm_device_uart_dm8);
 	}
+	if (cpu_is_msm8960ab())
+		platform_device_register(&msm8960ab_device_acpuclk);
+	else
+		platform_device_register(&msm8960_device_acpuclk);
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+
 	msm8960_pm8921_gpio_mpp_init();
 	platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
 	msm8960_init_smsc_hub();
@@ -3064,6 +3171,7 @@
 	msm8960_init_dsps();
 	change_memory_power = &msm8960_change_memory_power;
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	bt_power_init();
 	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
 		mdm_sglte_device.dev.platform_data = &sglte_platform_data;
 		platform_device_register(&mdm_sglte_device);
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 6fcc779..bf80262 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -101,13 +101,13 @@
 		},
 	},
 	{
-		.gpio      = 45,	       /* BLSP8 UART TX */
+		.gpio      = 4,			/* BLSP2 UART TX */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
 		},
 	},
 	{
-		.gpio      = 46,	       /* BLSP8 UART RX */
+		.gpio      = 5,			/* BLSP2 UART RX */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
 		},
diff --git a/arch/arm/mach-msm/board-8974-regulator.c b/arch/arm/mach-msm/board-8974-regulator.c
deleted file mode 100644
index 1a41f09..0000000
--- a/arch/arm/mach-msm/board-8974-regulator.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/platform_device.h>
-#include <linux/regulator/stub-regulator.h>
-
-#define VREG_CONSUMERS(_name) \
-	static struct regulator_consumer_supply vreg_consumers_##_name[]
-
-/*
- * Consumer specific regulator names:
- *			 regulator name		consumer dev_name
- */
-VREG_CONSUMERS(K0) = {
-	REGULATOR_SUPPLY("krait0",		"f9000000.qcom,acpuclk"),
-};
-VREG_CONSUMERS(K1) = {
-	REGULATOR_SUPPLY("krait1",		"f9000000.qcom,acpuclk"),
-};
-VREG_CONSUMERS(K2) = {
-	REGULATOR_SUPPLY("krait2",		"f9000000.qcom,acpuclk"),
-};
-VREG_CONSUMERS(K3) = {
-	REGULATOR_SUPPLY("krait3",		"f9000000.qcom,acpuclk"),
-};
-
-#define PM8X41_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
-			 _always_on, _supply_regulator, _hpm_min, _system_uA)  \
-	struct stub_regulator_pdata vreg_dev_##_id##_pdata __devinitdata = { \
-		.init_data = { \
-			.constraints = { \
-				.valid_modes_mask	= _modes, \
-				.valid_ops_mask		= _ops, \
-				.min_uV			= _min_uV, \
-				.max_uV			= _max_uV, \
-				.input_uV		= _max_uV, \
-				.apply_uV		= 0,	\
-				.always_on		= _always_on, \
-				.name			= _name, \
-			}, \
-			.num_consumer_supplies	= \
-					ARRAY_SIZE(vreg_consumers_##_id), \
-			.consumer_supplies	= vreg_consumers_##_id, \
-			.supply_regulator	= _supply_regulator, \
-		}, \
-		.hpm_min_load		= _hpm_min, \
-		.system_uA		= _system_uA, \
-	}
-
-#define KRAIT_PWR(_id, _name, _always_on, _min_uV, _max_uV, \
-		_supply_regulator, _hpm_min, _system_uA) \
-	PM8X41_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
-		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
-		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
-		REGULATOR_CHANGE_DRMS, _always_on, \
-		_supply_regulator, _hpm_min, _system_uA)
-
-/*	 ID      name     a_on  min_uV   max_uV  supply  hpm_min sys_uA  */
-KRAIT_PWR(K0, "krait0", 0, 850000,  1100000, NULL,     100000, 0);
-KRAIT_PWR(K1, "krait1", 0, 850000,  1100000, NULL,     100000, 0);
-KRAIT_PWR(K2, "krait2", 0, 850000,  1100000, NULL,     100000, 0);
-KRAIT_PWR(K3, "krait3", 0, 850000,  1100000, NULL,     100000, 0);
-
-#define VREG_DEVICE(_name, _devid) \
-	static struct platform_device vreg_device_##_name __devinitdata = \
-	{ \
-		.name = STUB_REGULATOR_DRIVER_NAME, \
-		.id = _devid, \
-		.dev = { .platform_data = &vreg_dev_##_name##_pdata }, \
-	}
-
-VREG_DEVICE(K0, 0);
-VREG_DEVICE(K1, 1);
-VREG_DEVICE(K2, 2);
-VREG_DEVICE(K3, 3);
-
-struct platform_device *msm_8974_stub_regulator_devices[] __devinitdata = {
-	&vreg_device_K0,
-	&vreg_device_K1,
-	&vreg_device_K2,
-	&vreg_device_K3,
-};
-
-int msm_8974_stub_regulator_devices_len __devinitdata =
-			ARRAY_SIZE(msm_8974_stub_regulator_devices);
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index d65ebe1..388307b 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -20,15 +20,13 @@
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/of_irq.h>
-#ifdef CONFIG_ION_MSM
-#include <linux/ion.h>
-#endif
 #include <linux/memory.h>
 #ifdef CONFIG_ANDROID_PMEM
 #include <linux/android_pmem.h>
 #endif
-#include <linux/regulator/stub-regulator.h>
 #include <linux/regulator/machine.h>
+#include <linux/regulator/krait-regulator.h>
+#include <linux/msm_thermal.h>
 #include <asm/mach/map.h>
 #include <asm/hardware/gic.h>
 #include <mach/board.h>
@@ -52,17 +50,6 @@
 #include "lpm_resources.h"
 
 #define MSM_KERNEL_EBI1_MEM_SIZE	0x280000
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-#define MSM_ION_SF_SIZE 0x4000000 /* 64 Mbytes */
-#else
-#define MSM_ION_SF_SIZE 0x2800000 /* 40 Mbytes */
-#endif
-#define MSM_ION_MM_FW_SIZE	0xa00000 /* (10MB) */
-#define MSM_ION_MM_SIZE		0x7800000 /* (120MB) */
-#define MSM_ION_QSECOM_SIZE	0x600000 /* (6MB) */
-#define MSM_ION_MFC_SIZE	SZ_8K
-#define MSM_ION_AUDIO_SIZE	0x2B4000
-#define MSM_ION_HEAP_NUM	8
 
 #ifdef CONFIG_KERNEL_PMEM_EBI_REGION
 static unsigned kernel_ebi1_mem_size = MSM_KERNEL_EBI1_MEM_SIZE;
@@ -90,121 +77,12 @@
 	return MEMTYPE_EBI1;
 }
 
-#ifdef CONFIG_ION_MSM
-static struct ion_cp_heap_pdata cp_mm_ion_pdata = {
-	.permission_type = IPT_TYPE_MM_CARVEOUT,
-	.align = PAGE_SIZE,
-};
-
-static struct ion_cp_heap_pdata cp_mfc_ion_pdata = {
-	.permission_type = IPT_TYPE_MFC_SHAREDMEM,
-	.align = PAGE_SIZE,
-};
-
-static struct ion_co_heap_pdata co_ion_pdata = {
-	.adjacent_mem_id = INVALID_HEAP_ID,
-	.align = PAGE_SIZE,
-};
-
-static struct ion_co_heap_pdata fw_co_ion_pdata = {
-	.adjacent_mem_id = ION_CP_MM_HEAP_ID,
-	.align = SZ_128K,
-};
-
-/**
- * These heaps are listed in the order they will be allocated. Due to
- * video hardware restrictions and content protection the FW heap has to
- * be allocated adjacent (below) the MM heap and the MFC heap has to be
- * allocated after the MM heap to ensure MFC heap is not more than 256MB
- * away from the base address of the FW heap.
- * However, the order of FW heap and MM heap doesn't matter since these
- * two heaps are taken care of by separate code to ensure they are adjacent
- * to each other.
- * Don't swap the order unless you know what you are doing!
- */
-static struct ion_platform_data ion_pdata = {
-	.nr = MSM_ION_HEAP_NUM,
-	.heaps = {
-		{
-			.id	= ION_SYSTEM_HEAP_ID,
-			.type	= ION_HEAP_TYPE_SYSTEM,
-			.name	= ION_VMALLOC_HEAP_NAME,
-		},
-		{
-			.id	= ION_CP_MM_HEAP_ID,
-			.type	= ION_HEAP_TYPE_CP,
-			.name	= ION_MM_HEAP_NAME,
-			.size	= MSM_ION_MM_SIZE,
-			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &cp_mm_ion_pdata,
-		},
-		{
-			.id	= ION_MM_FIRMWARE_HEAP_ID,
-			.type	= ION_HEAP_TYPE_CARVEOUT,
-			.name	= ION_MM_FIRMWARE_HEAP_NAME,
-			.size	= MSM_ION_MM_FW_SIZE,
-			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &fw_co_ion_pdata,
-		},
-		{
-			.id	= ION_CP_MFC_HEAP_ID,
-			.type	= ION_HEAP_TYPE_CP,
-			.name	= ION_MFC_HEAP_NAME,
-			.size	= MSM_ION_MFC_SIZE,
-			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &cp_mfc_ion_pdata,
-		},
-		{
-			.id	= ION_SF_HEAP_ID,
-			.type	= ION_HEAP_TYPE_CARVEOUT,
-			.name	= ION_SF_HEAP_NAME,
-			.size	= MSM_ION_SF_SIZE,
-			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &co_ion_pdata,
-		},
-		{
-			.id	= ION_IOMMU_HEAP_ID,
-			.type	= ION_HEAP_TYPE_IOMMU,
-			.name	= ION_IOMMU_HEAP_NAME,
-		},
-		{
-			.id	= ION_QSECOM_HEAP_ID,
-			.type	= ION_HEAP_TYPE_CARVEOUT,
-			.name	= ION_QSECOM_HEAP_NAME,
-			.size	= MSM_ION_QSECOM_SIZE,
-			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &co_ion_pdata,
-		},
-		{
-			.id	= ION_AUDIO_HEAP_ID,
-			.type	= ION_HEAP_TYPE_CARVEOUT,
-			.name	= ION_AUDIO_HEAP_NAME,
-			.size	= MSM_ION_AUDIO_SIZE,
-			.memory_type = ION_EBI_TYPE,
-			.extra_data = (void *) &co_ion_pdata,
-		},
-	}
-};
-
-static struct platform_device ion_dev = {
-	.name = "ion-msm",
-	.id = 1,
-	.dev = { .platform_data = &ion_pdata },
-};
-
-static void __init reserve_ion_memory(void)
+static void __init reserve_ebi_memory(void)
 {
-	msm_8974_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MM_SIZE;
-	msm_8974_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MM_FW_SIZE;
-	msm_8974_reserve_table[MEMTYPE_EBI1].size += MSM_ION_SF_SIZE;
-	msm_8974_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MFC_SIZE;
-	msm_8974_reserve_table[MEMTYPE_EBI1].size += MSM_ION_QSECOM_SIZE;
-	msm_8974_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
 #ifdef CONFIG_KERNEL_PMEM_EBI_REGION
 	msm_8974_reserve_table[MEMTYPE_EBI1].size += kernel_ebi1_mem_size;
 #endif
 }
-#endif
 
 static struct resource smd_resource[] = {
 	{
@@ -370,9 +248,7 @@
 
 static void __init msm_8974_calculate_reserve_sizes(void)
 {
-#ifdef CONFIG_ION_MSM
-	reserve_ion_memory();
-#endif
+	reserve_ebi_memory();
 }
 
 static struct reserve_info msm_8974_reserve_info __initdata = {
@@ -535,49 +411,10 @@
 
 void __init msm_8974_add_devices(void)
 {
-#ifdef CONFIG_ION_MSM
-	platform_device_register(&ion_dev);
-#endif
 	platform_device_register(&msm_device_smd_8974);
 	platform_device_register(&android_usb_device);
-	platform_add_devices(msm_8974_stub_regulator_devices,
-					msm_8974_stub_regulator_devices_len);
 }
 
-static struct clk_lookup msm_clocks_dummy[] = {
-	CLK_DUMMY("xo",		XO_CLK,		NULL,	OFF),
-	CLK_DUMMY("xo",		XO_CLK,		"pil_pronto",		OFF),
-	CLK_DUMMY("core_clk",	BLSP2_UART_CLK,	"msm_serial_hsl.0",	OFF),
-	CLK_DUMMY("iface_clk",	BLSP2_UART_CLK,	"msm_serial_hsl.0",	OFF),
-	CLK_DUMMY("core_clk",	SDC1_CLK,	NULL,			OFF),
-	CLK_DUMMY("iface_clk",	SDC1_P_CLK,	NULL,			OFF),
-	CLK_DUMMY("core_clk",	SDC3_CLK,	NULL,			OFF),
-	CLK_DUMMY("iface_clk",	SDC3_P_CLK,	NULL,			OFF),
-	CLK_DUMMY("phy_clk", NULL, "msm_otg", OFF),
-	CLK_DUMMY("core_clk", NULL, "msm_otg", OFF),
-	CLK_DUMMY("iface_clk", NULL, "msm_otg", OFF),
-	CLK_DUMMY("xo", NULL, "msm_otg", OFF),
-	CLK_DUMMY("dfab_clk",	DFAB_CLK,	NULL, 0),
-	CLK_DUMMY("dma_bam_pclk",	DMA_BAM_P_CLK,	NULL, 0),
-	CLK_DUMMY("mem_clk",	NULL,	NULL, 0),
-	CLK_DUMMY("core_clk",	SPI_CLK,	"spi_qsd.1",	OFF),
-	CLK_DUMMY("iface_clk",	SPI_P_CLK,	"spi_qsd.1",	OFF),
-	CLK_DUMMY("core_clk",	NULL,	"f9966000.i2c", 0),
-	CLK_DUMMY("iface_clk",	NULL,	"f9966000.i2c", 0),
-	CLK_DUMMY("core_clk",	NULL,	"fe12f000.slim",	OFF),
-	CLK_DUMMY("core_clk", "mdp.0", NULL, 0),
-	CLK_DUMMY("core_clk_src", "mdp.0", NULL, 0),
-	CLK_DUMMY("lut_clk", "mdp.0", NULL, 0),
-	CLK_DUMMY("vsync_clk", "mdp.0", NULL, 0),
-	CLK_DUMMY("iface_clk", "mdp.0", NULL, 0),
-	CLK_DUMMY("bus_clk", "mdp.0", NULL, 0),
-};
-
-struct clock_init_data msm_dummy_clock_init_data __initdata = {
-	.table = msm_clocks_dummy,
-	.size = ARRAY_SIZE(msm_clocks_dummy),
-};
-
 /*
  * Used to satisfy dependencies for devices that need to be
  * run early or in a particular order. Most likely your device doesn't fall
@@ -592,12 +429,13 @@
 	msm_lpmrs_module_init();
 	rpm_regulator_smd_driver_init();
 	msm_spm_device_init();
-	regulator_stub_init();
+	krait_power_init();
 	if (machine_is_msm8974_rumi())
-		msm_clock_init(&msm_dummy_clock_init_data);
+		msm_clock_init(&msm8974_rumi_clock_init_data);
 	else
 		msm_clock_init(&msm8974_clock_init_data);
 	msm8974_init_buses();
+	msm_thermal_device_init();
 }
 
 static struct of_device_id irq_match[] __initdata  = {
@@ -625,12 +463,12 @@
 }
 
 static struct of_dev_auxdata msm_8974_auxdata_lookup[] __initdata = {
-	OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF991F000, \
-			"msm_serial_hsl.0", NULL),
 	OF_DEV_AUXDATA("qcom,hsusb-otg", 0xF9A55000, \
 			"msm_otg", NULL),
 	OF_DEV_AUXDATA("qcom,dwc-usb3-msm", 0xF9200000, \
 			"msm_dwc3", NULL),
+	OF_DEV_AUXDATA("qcom,usb-bam-msm", 0xF9304000, \
+			"usb_bam", NULL),
 	OF_DEV_AUXDATA("qcom,spi-qup-v2", 0xF9924000, \
 			"spi_qsd.1", NULL),
 	OF_DEV_AUXDATA("qcom,spmi-pmic-arb", 0xFC4C0000, \
@@ -649,6 +487,34 @@
 	OF_DEV_AUXDATA("qcom,pil-mba",     0xFC820000, "pil-mba", NULL),
 	OF_DEV_AUXDATA("qcom,pil-pronto", 0xFB21B000, \
 			"pil_pronto", NULL),
+	OF_DEV_AUXDATA("arm,coresight-tmc", 0xFC322000, \
+			"coresight-tmc-etr", NULL),
+	OF_DEV_AUXDATA("arm,coresight-tpiu", 0xFC318000, \
+			"coresight-tpiu", NULL),
+	OF_DEV_AUXDATA("qcom,coresight-replicator", 0xFC31C000, \
+			"coresight-replicator", NULL),
+	OF_DEV_AUXDATA("arm,coresight-tmc", 0xFC307000, \
+			"coresight-tmc-etf", NULL),
+	OF_DEV_AUXDATA("arm,coresight-funnel", 0xFC31B000, \
+			"coresight-funnel-merg", NULL),
+	OF_DEV_AUXDATA("arm,coresight-funnel", 0xFC319000, \
+			"coresight-funnel-in0", NULL),
+	OF_DEV_AUXDATA("arm,coresight-funnel", 0xFC31A000, \
+			"coresight-funnel-in1", NULL),
+	OF_DEV_AUXDATA("arm,coresight-funnel", 0xFC345000, \
+			"coresight-funnel-kpss", NULL),
+	OF_DEV_AUXDATA("arm,coresight-funnel", 0xFC364000, \
+			"coresight-funnel-mmss", NULL),
+	OF_DEV_AUXDATA("arm,coresight-stm", 0xFC321000, \
+			"coresight-stm", NULL),
+	OF_DEV_AUXDATA("arm,coresight-etm", 0xFC33C000, \
+			"coresight-etm0", NULL),
+	OF_DEV_AUXDATA("arm,coresight-etm", 0xFC33D000, \
+			"coresight-etm1", NULL),
+	OF_DEV_AUXDATA("arm,coresight-etm", 0xFC33E000, \
+			"coresight-etm2", NULL),
+	OF_DEV_AUXDATA("arm,coresight-etm", 0xFC33F000, \
+			"coresight-etm3", NULL),
 	OF_DEV_AUXDATA("qcom,msm-rng", 0xF9BFF000, \
 			"msm_rng", NULL),
 	OF_DEV_AUXDATA("qcom,qseecom", 0xFE806000, \
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index a312e2b..f885774 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -976,6 +976,7 @@
 				msm_android_usb_hsic_device.dev.platform_data;
 
 	msm9615_device_init();
+	platform_device_register(&msm_gpio_device);
 	msm9615_init_gpiomux();
 	msm9615_i2c_init();
 	regulator_suppress_info_printing();
diff --git a/arch/arm/mach-msm/board-9625-gpiomux.c b/arch/arm/mach-msm/board-9625-gpiomux.c
index e28c734..2919f06 100644
--- a/arch/arm/mach-msm/board-9625-gpiomux.c
+++ b/arch/arm/mach-msm/board-9625-gpiomux.c
@@ -24,6 +24,18 @@
 	.dir = GPIOMUX_OUT_HIGH,
 };
 
+static struct gpiomux_setting gpio_spi_cs_config = {
+	.func = GPIOMUX_FUNC_9,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gpio_spi_config = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
 static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
 	{
 		.gpio      = 45,	       /* BLSP1 UART TX */
@@ -37,6 +49,31 @@
 			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
 		},
 	},
+	{
+		.gpio      = 69,		/* BLSP6 QUP SPI_CS_N */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+		},
+	},
+	{
+		.gpio      = 20,		/* BLSP6 QUP SPI_DATA_MOSI */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 21,		/* BLSP6 QUP SPI_DATA_MISO */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 23,		/* BLSP6 QUP SPI_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+
 };
 
 void __init msm9625_init_gpiomux(void)
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 60dfe3c..e7ef1a9 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -21,6 +21,7 @@
 #include <linux/of_irq.h>
 #include <linux/memory.h>
 #include <asm/mach/map.h>
+#include <asm/hardware/cache-l2x0.h>
 #include <asm/hardware/gic.h>
 #include <asm/arch_timer.h>
 #include <asm/mach/arch.h>
@@ -30,6 +31,10 @@
 #include <mach/gpio.h>
 #include "clock.h"
 
+#define L2CC_AUX_CTRL	((0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) | \
+			(0x2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | \
+			(0x1 << L2X0_AUX_CTRL_EVNT_MON_BUS_EN_SHIFT))
+
 static struct clk_lookup msm_clocks_dummy[] = {
 	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
 	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
@@ -41,8 +46,8 @@
 	CLK_DUMMY("dfab_clk",	DFAB_CLK,	NULL, 0),
 	CLK_DUMMY("dma_bam_pclk",	DMA_BAM_P_CLK,	NULL, 0),
 	CLK_DUMMY("mem_clk",	NULL,	NULL, 0),
-	CLK_DUMMY("core_clk",	NULL,	"spi_qsd.1",	OFF),
-	CLK_DUMMY("iface_clk",	NULL,	"spi_qsd.1",	OFF),
+	CLK_DUMMY("core_clk",	SPI_CLK,	"spi_qsd.1",	OFF),
+	CLK_DUMMY("iface_clk",	SPI_P_CLK,	"spi_qsd.1",	OFF),
 	CLK_DUMMY("core_clk",	NULL,	"f9966000.i2c", 0),
 	CLK_DUMMY("iface_clk",	NULL,	"f9966000.i2c", 0),
 	CLK_DUMMY("core_clk",	NULL,	"fe12f000.slim",	OFF),
@@ -67,11 +72,14 @@
 static struct of_dev_auxdata msm9625_auxdata_lookup[] __initdata = {
 	OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF991F000, \
 			"msm_serial_hsl.0", NULL),
+	OF_DEV_AUXDATA("qcom,spi-qup-v2", 0xF9928000, \
+			"spi_qsd.1", NULL),
 	{}
 };
 
 void __init msm9625_init_irq(void)
 {
+	l2x0_of_init(L2CC_AUX_CTRL, L2X0_AUX_CTRL_MASK);
 	of_irq_init(irq_match);
 }
 
@@ -88,6 +96,8 @@
 {
 	if (socinfo_init() < 0)
 		pr_err("%s: socinfo_init() failed\n", __func__);
+
+	msm9625_init_gpiomux();
 	msm_clock_init(&msm_dummy_clock_init_data);
 	of_platform_populate(NULL, of_default_bus_match_table,
 			msm9625_auxdata_lookup, NULL);
diff --git a/arch/arm/mach-msm/board-msm7627a-display.c b/arch/arm/mach-msm/board-msm7627a-display.c
index 3726941..e305fe6 100644
--- a/arch/arm/mach-msm/board-msm7627a-display.c
+++ b/arch/arm/mach-msm/board-msm7627a-display.c
@@ -81,6 +81,7 @@
 	"gpio_disp_reset",
 };
 
+static char lcdc_splash_is_enabled(void);
 static int lcdc_truly_gpio_init(void)
 {
 	int i;
@@ -103,7 +104,12 @@
 					lcdc_truly_gpio_table[i]);
 				goto truly_gpio_fail;
 			}
-			rc = gpio_direction_output(lcdc_truly_gpio_table[i], 0);
+			if (lcdc_splash_is_enabled())
+				rc = gpio_direction_output(
+					lcdc_truly_gpio_table[i], 1);
+			else
+				rc = gpio_direction_output(
+					lcdc_truly_gpio_table[i], 0);
 			if (rc < 0) {
 				pr_err("Error direct lcdc gpio:%d\n",
 					lcdc_truly_gpio_table[i]);
@@ -247,6 +253,7 @@
 static int sku3_lcdc_power_save(int on)
 {
 	int rc = 0;
+	static int cont_splash_done;
 
 	if (on) {
 		sku3_lcdc_lcd_camera_power_onoff(1);
@@ -257,6 +264,11 @@
 			return rc;
 		}
 
+		if (lcdc_splash_is_enabled() && !cont_splash_done) {
+			cont_splash_done = 1;
+			return rc;
+		}
+
 		if (lcdc_truly_gpio_initialized) {
 			/*LCD reset*/
 			gpio_set_value(SKU3_LCDC_GPIO_DISPLAY_RESET, 1);
@@ -778,8 +790,14 @@
 static struct msm_panel_common_pdata mdp_pdata = {
 	.gpio = 97,
 	.mdp_rev = MDP_REV_303,
+	.cont_splash_enabled = 0x1,
 };
 
+static char lcdc_splash_is_enabled()
+{
+	return mdp_pdata.cont_splash_enabled;
+}
+
 #define GPIO_LCDC_BRDG_PD	128
 #define GPIO_LCDC_BRDG_RESET_N	129
 #define GPIO_LCD_DSI_SEL	125
@@ -1142,11 +1160,11 @@
 }
 
 static int qrd3_dsi_gpio_initialized;
+static struct regulator *gpio_reg_2p85v, *gpio_reg_1p8v;
 
 static int mipi_dsi_panel_qrd3_power(int on)
 {
 	int rc = 0;
-	static struct regulator *gpio_reg_2p85v, *gpio_reg_1p8v;
 
 	if (!qrd3_dsi_gpio_initialized) {
 		pmapp_disp_backlight_init();
@@ -1155,21 +1173,42 @@
 		if (rc < 0)
 			return rc;
 
-		gpio_reg_2p85v = regulator_get(&mipi_dsi_device.dev,
-								"lcd_vdd");
-		if (IS_ERR(gpio_reg_2p85v)) {
-			pr_err("%s:ext_2p85v regulator get failed", __func__);
-			return -EINVAL;
-		}
-
-		gpio_reg_1p8v = regulator_get(&mipi_dsi_device.dev,
-								"lcd_vddi");
-		if (IS_ERR(gpio_reg_1p8v)) {
-			pr_err("%s:ext_1p8v regulator get failed", __func__);
-			return -EINVAL;
-		}
-
 		qrd3_dsi_gpio_initialized = 1;
+
+		if (mdp_pdata.cont_splash_enabled) {
+			rc = gpio_tlmm_config(GPIO_CFG(
+			     GPIO_QRD3_LCD_BACKLIGHT_EN, 0, GPIO_CFG_OUTPUT,
+			     GPIO_CFG_PULL_UP, GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+			if (rc < 0) {
+				pr_err("failed QRD3 GPIO_BACKLIGHT_EN tlmm config\n");
+				return rc;
+			}
+			rc = gpio_direction_output(GPIO_QRD3_LCD_BACKLIGHT_EN,
+			     1);
+			if (rc < 0) {
+				pr_err("failed to enable backlight\n");
+				gpio_free(GPIO_QRD3_LCD_BACKLIGHT_EN);
+				return rc;
+			}
+
+			/*Configure LCD Bridge reset*/
+			rc = gpio_tlmm_config(qrd3_mipi_dsi_gpio[0],
+			     GPIO_CFG_ENABLE);
+			if (rc < 0) {
+				pr_err("Failed to enable LCD Bridge reset enable\n");
+				return rc;
+			}
+
+			rc = gpio_direction_output(GPIO_QRD3_LCD_BRDG_RESET_N,
+			     1);
+
+			if (rc < 0) {
+				pr_err("Failed GPIO bridge Reset\n");
+				gpio_free(GPIO_QRD3_LCD_BRDG_RESET_N);
+				return rc;
+			}
+			return 0;
+		}
 	}
 
 	if (on) {
@@ -1246,6 +1285,7 @@
 	return rc;
 }
 
+static char mipi_dsi_splash_is_enabled(void);
 static int mipi_dsi_panel_power(int on)
 {
 	int rc = 0;
@@ -1268,9 +1308,15 @@
 	.dsi_power_save		= mipi_dsi_panel_power,
 	.dsi_client_reset       = msm_fb_dsi_client_reset,
 	.get_lane_config	= msm_fb_get_lane_config,
+	.splash_is_enabled	= mipi_dsi_splash_is_enabled,
 };
 #endif
 
+static char mipi_dsi_splash_is_enabled(void)
+{
+	return mdp_pdata.cont_splash_enabled;
+}
+
 static char prim_panel_name[PANEL_NAME_MAX_LEN];
 static int __init prim_display_setup(char *param)
 {
@@ -1280,6 +1326,8 @@
 }
 early_param("prim_display", prim_display_setup);
 
+static int disable_splash;
+
 void msm7x27a_set_display_params(char *prim_panel)
 {
 	if (strnlen(prim_panel, PANEL_NAME_MAX_LEN)) {
@@ -1288,10 +1336,22 @@
 		pr_debug("msm_fb_pdata.prim_panel_name %s\n",
 			msm_fb_pdata.prim_panel_name);
 	}
+	if (strnlen(msm_fb_pdata.prim_panel_name, PANEL_NAME_MAX_LEN)) {
+		if (strncmp((char *)msm_fb_pdata.prim_panel_name,
+			"mipi_cmd_nt35510_wvga",
+			strnlen("mipi_cmd_nt35510_wvga",
+				PANEL_NAME_MAX_LEN)) &&
+		    strncmp((char *)msm_fb_pdata.prim_panel_name,
+			"mipi_video_nt35510_wvga",
+			strnlen("mipi_video_nt35510_wvga",
+				PANEL_NAME_MAX_LEN)))
+			disable_splash = 1;
+	}
 }
 
 void __init msm_fb_add_devices(void)
 {
+	int rc = 0;
 	msm7x27a_set_display_params(prim_panel_name);
 	if (machine_is_msm7627a_qrd1())
 		platform_add_devices(qrd_fb_devices,
@@ -1300,15 +1360,22 @@
 						|| machine_is_msm8625_evt()) {
 		mipi_NT35510_pdata.bl_lock = 1;
 		mipi_NT35516_pdata.bl_lock = 1;
+		if (disable_splash)
+			mdp_pdata.cont_splash_enabled = 0x0;
+
+
 		platform_add_devices(evb_fb_devices,
 				ARRAY_SIZE(evb_fb_devices));
 	} else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()) {
 		sku3_lcdc_lcd_camera_power_init();
+		mdp_pdata.cont_splash_enabled = 0x1;
 		platform_add_devices(qrd3_fb_devices,
 						ARRAY_SIZE(qrd3_fb_devices));
-	} else
+	} else {
+		mdp_pdata.cont_splash_enabled = 0x0;
 		platform_add_devices(msm_fb_devices,
 				ARRAY_SIZE(msm_fb_devices));
+	}
 
 	msm_fb_register_device("mdp", &mdp_pdata);
 	if (machine_is_msm7625a_surf() || machine_is_msm7x27a_surf() ||
@@ -1318,4 +1385,26 @@
 #ifdef CONFIG_FB_MSM_MIPI_DSI
 	msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);
 #endif
+	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+					|| machine_is_msm8625_evt()) {
+		gpio_reg_2p85v = regulator_get(&mipi_dsi_device.dev,
+								"lcd_vdd");
+		if (IS_ERR(gpio_reg_2p85v))
+			pr_err("%s:ext_2p85v regulator get failed", __func__);
+
+		gpio_reg_1p8v = regulator_get(&mipi_dsi_device.dev,
+								"lcd_vddi");
+		if (IS_ERR(gpio_reg_1p8v))
+			pr_err("%s:ext_1p8v regulator get failed", __func__);
+
+		if (mdp_pdata.cont_splash_enabled) {
+			/*Enable EXT_2.85 and 1.8 regulators*/
+			rc = regulator_enable(gpio_reg_2p85v);
+			if (rc < 0)
+				pr_err("%s: reg enable failed\n", __func__);
+			rc = regulator_enable(gpio_reg_1p8v);
+			if (rc < 0)
+				pr_err("%s: reg enable failed\n", __func__);
+		}
+	}
 }
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 3bd7eeb..b67d982 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -159,7 +159,7 @@
 };
 
 #ifdef CONFIG_ARCH_MSM7X27A
-#define MSM_PMEM_MDP_SIZE       0x2300000
+#define MSM_PMEM_MDP_SIZE                0x1B00000
 #define MSM7x25A_MSM_PMEM_MDP_SIZE       0x1500000
 
 #define MSM_PMEM_ADSP_SIZE      0x1200000
@@ -513,7 +513,8 @@
 	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
 	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
 	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
-	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))| \
+	(1<<MSM_ADSP_CODEC_AC3)
 #define DEC1_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
 	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
 	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index ea12570..4524f43 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -4339,7 +4339,7 @@
 	}
 
 	if (quickvx_mddi_client)
-		rc = regulator_set_voltage(mddi_ldo20, 1800000, 1800000);
+		rc = regulator_set_voltage(mddi_ldo20, 1500000, 1800000);
 	else
 		rc = regulator_set_voltage(mddi_ldo20, 1500000, 1500000);
 
@@ -4539,19 +4539,10 @@
 	.mddi_client_power = msm_fb_mddi_client_power,
 };
 
-int mdp_core_clk_rate_table[] = {
-	122880000,
-	122880000,
-	192000000,
-	192000000,
-};
-
 static struct msm_panel_common_pdata mdp_pdata = {
 	.hw_revision_addr = 0xac001270,
 	.gpio = 30,
-	.mdp_core_clk_rate = 122880000,
-	.mdp_core_clk_table = mdp_core_clk_rate_table,
-	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+	.mdp_max_clk = 192000000,
 	.mdp_rev = MDP_REV_40,
 	.mem_hid = MEMTYPE_EBI0,
 };
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 50b1ac5..47d847e 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -2629,7 +2629,12 @@
 #define USER_SMI_SIZE         (MSM_SMI_SIZE - KERNEL_SMI_SIZE)
 #define MSM_PMEM_SMIPOOL_SIZE USER_SMI_SIZE
 
+#ifdef CONFIG_MSM_CP
 #define MSM_ION_HOLE_SIZE	SZ_128K /* (128KB) */
+#else
+#define MSM_ION_HOLE_SIZE	0
+#endif
+
 #define MSM_MM_FW_SIZE		(0x200000 - MSM_ION_HOLE_SIZE) /*(2MB-128KB)*/
 #define MSM_ION_MM_SIZE		0x3800000  /* (56MB) */
 #define MSM_ION_MFC_SIZE	SZ_8K
@@ -2639,6 +2644,14 @@
 #define MSM_ION_MM_BASE		(MSM_ION_HOLE_BASE + MSM_ION_HOLE_SIZE)
 #define MSM_ION_MFC_BASE	(MSM_ION_MM_BASE + MSM_ION_MM_SIZE)
 
+#ifdef CONFIG_MSM_CP
+#define SECURE_BASE	(MSM_ION_HOLE_BASE)
+#define SECURE_SIZE	(MSM_ION_MM_SIZE + MSM_ION_HOLE_SIZE)
+#else
+#define SECURE_BASE	(MSM_MM_FW_BASE)
+#define SECURE_SIZE	(MSM_ION_MM_SIZE + MSM_MM_FW_SIZE)
+#endif
+
 #define MSM_ION_SF_SIZE		0x4000000 /* 64MB */
 #define MSM_ION_CAMERA_SIZE     MSM_PMEM_ADSP_SIZE
 
@@ -5293,8 +5306,8 @@
 	.request_region = request_smi_region,
 	.release_region = release_smi_region,
 	.setup_region = setup_smi_region,
-	.secure_base = MSM_ION_HOLE_BASE,
-	.secure_size = MSM_ION_HOLE_SIZE + MSM_ION_MM_SIZE,
+	.secure_base = SECURE_BASE,
+	.secure_size = SECURE_SIZE,
 	.iommu_map_all = 1,
 	.iommu_2x_map_domain = VIDEO_DOMAIN,
 };
@@ -9638,27 +9651,9 @@
 }
 #endif
 
-#ifdef CONFIG_FB_MSM_MIPI_DSI
-int mdp_core_clk_rate_table[] = {
-	85330000,
-	128000000,
-	160000000,
-	200000000,
-};
-#else
-int mdp_core_clk_rate_table[] = {
-	59080000,
-	128000000,
-	128000000,
-	200000000,
-};
-#endif
-
 static struct msm_panel_common_pdata mdp_pdata = {
 	.gpio = MDP_VSYNC_GPIO,
-	.mdp_core_clk_rate = 59080000,
-	.mdp_core_clk_table = mdp_core_clk_rate_table,
-	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+	.mdp_max_clk = 200000000,
 #ifdef CONFIG_MSM_BUS_SCALING
 	.mdp_bus_scale_table = &mdp_bus_scale_pdata,
 #endif
@@ -9751,9 +9746,7 @@
 static void __init msm_fb_add_devices(void)
 {
 #ifdef CONFIG_FB_MSM_LCDC_DSUB
-	mdp_pdata.mdp_core_clk_table = NULL;
-	mdp_pdata.num_mdp_clk = 0;
-	mdp_pdata.mdp_core_clk_rate = 200000000;
+	mdp_pdata.mdp_max_clk = 200000000;
 #endif
 	msm_fb_register_device("mdp", &mdp_pdata);
 
@@ -9777,8 +9770,6 @@
  */
 static void set_mdp_clocks_for_wuxga(void)
 {
-	int i;
-
 	mdp_sd_smi_vectors[0].ab = 2000000000;
 	mdp_sd_smi_vectors[0].ib = 2000000000;
 	mdp_sd_smi_vectors[1].ab = 2000000000;
@@ -9804,10 +9795,7 @@
 	mdp_1080p_vectors[1].ab = 2000000000;
 	mdp_1080p_vectors[1].ib = 2000000000;
 
-	mdp_pdata.mdp_core_clk_rate = 200000000;
-
-	for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
-		mdp_core_clk_rate_table[i] = 200000000;
+	mdp_pdata.mdp_max_clk = 200000000;
 }
 
 #if (defined(CONFIG_MARIMBA_CORE)) && \
@@ -10213,6 +10201,7 @@
 #endif
 	pmic_reset_irq = PM8058_IRQ_BASE + PM8058_RESOUT_IRQ;
 
+	platform_device_register(&msm_gpio_device);
 	/*
 	 * Initialize RPM first as other drivers and devices may need
 	 * it for their initialization.
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 1921cc3..6fa45c6 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -129,7 +129,7 @@
 };
 
 #ifdef CONFIG_ARCH_MSM7X27A
-#define MSM_PMEM_MDP_SIZE       0x2300000
+#define MSM_PMEM_MDP_SIZE       0x1B00000
 #define MSM_PMEM_ADSP_SIZE      0x1200000
 
 #define MSM_ION_AUDIO_SIZE	(MSM_PMEM_AUDIO_SIZE + PMEM_KERNEL_EBI1_SIZE)
@@ -459,7 +459,8 @@
 	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
 	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
 	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
-	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))| \
+	(1<<MSM_ADSP_CODEC_AC3)
 #define DEC1_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
 	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
 	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 8b57394..635bc52 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -3200,12 +3200,36 @@
 	F_END
 };
 
+static struct branch_clk dsi1_reset_clk = {
+	.b = {
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(7),
+		.halt_check = NOCHECK,
+	},
+	.c = {
+		.dbg_name = "dsi1_reset_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(dsi1_reset_clk.c),
+	},
+};
+
+static struct branch_clk dsi2_reset_clk = {
+	.b = {
+		.reset_reg = SW_RESET_CORE_REG,
+		.reset_mask = BIT(25),
+		.halt_check = NOCHECK,
+	},
+	.c = {
+		.dbg_name = "dsi2_reset_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(dsi2_reset_clk.c),
+	},
+};
+
 static struct rcg_clk dsi1_byte_clk = {
 	.b = {
 		.ctl_reg = DSI1_BYTE_CC_REG,
 		.en_mask = BIT(0),
-		.reset_reg = SW_RESET_CORE_REG,
-		.reset_mask = BIT(7),
 		.halt_reg = DBG_BUS_VEC_B_REG,
 		.halt_bit = 21,
 		.retain_reg = DSI1_BYTE_CC_REG,
@@ -3228,8 +3252,6 @@
 	.b = {
 		.ctl_reg = DSI2_BYTE_CC_REG,
 		.en_mask = BIT(0),
-		.reset_reg = SW_RESET_CORE_REG,
-		.reset_mask = BIT(25),
 		.halt_reg = DBG_BUS_VEC_B_REG,
 		.halt_bit = 20,
 		.retain_reg = DSI2_BYTE_CC_REG,
@@ -3252,7 +3274,6 @@
 	.b = {
 		.ctl_reg = DSI1_ESC_CC_REG,
 		.en_mask = BIT(0),
-		.reset_reg = SW_RESET_CORE_REG,
 		.halt_reg = DBG_BUS_VEC_I_REG,
 		.halt_bit = 1,
 	},
@@ -3506,6 +3527,12 @@
 static unsigned long fmax_gfx3d_8930[MAX_VDD_LEVELS] __initdata = {
 	[VDD_DIG_LOW]     = 192000000,
 	[VDD_DIG_NOMINAL] = 320000000,
+	[VDD_DIG_HIGH]    = 400000000
+};
+
+static unsigned long fmax_gfx3d_8930aa[MAX_VDD_LEVELS] __initdata = {
+	[VDD_DIG_LOW]     = 192000000,
+	[VDD_DIG_NOMINAL] = 320000000,
 	[VDD_DIG_HIGH]    = 450000000
 };
 
@@ -4549,6 +4576,7 @@
 	}
 static struct clk_freq_tbl clk_tbl_pcm_492[] = {
 	{ .ns_val = BIT(10) /* external input */ },
+	F_PCM(  256000, pll4, 4, 1, 480),
 	F_PCM(  512000, pll4, 4, 1, 240),
 	F_PCM(  768000, pll4, 4, 1, 160),
 	F_PCM( 1024000, pll4, 4, 1, 120),
@@ -4565,6 +4593,7 @@
 
 static struct clk_freq_tbl clk_tbl_pcm_393[] = {
 	{ .ns_val = BIT(10) /* external input */ },
+	F_PCM(  256000, pll4, 4, 1, 384),
 	F_PCM(  512000, pll4, 4, 1, 192),
 	F_PCM(  768000, pll4, 4, 1, 128),
 	F_PCM( 1024000, pll4, 4, 1,  96),
@@ -5121,6 +5150,7 @@
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_gss"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"BAM_RMNT"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"msm_xo"),
+	CLK_LOOKUP("vref_buff",		cxo_clk.c,	"rpm-regulator"),
 	CLK_LOOKUP("pll2",		pll2_clk.c,	NULL),
 	CLK_LOOKUP("pll8",		pll8_clk.c,	NULL),
 	CLK_LOOKUP("pll4",		pll4_clk.c,	NULL),
@@ -5158,11 +5188,13 @@
 	CLK_LOOKUP("dfab_clk",		dfab_msmbus_clk.c,	"msm_bus"),
 	CLK_LOOKUP("dfab_a_clk",	dfab_msmbus_a_clk.c,	"msm_bus"),
 	CLK_LOOKUP("core_a_clk",	qdss_a_clk.c,		""),
-	CLK_LOOKUP("core_clk",		qdss_clk.c,		"msm_etb.0"),
-	CLK_LOOKUP("core_clk",		qdss_clk.c,		"msm_tpiu.0"),
-	CLK_LOOKUP("core_clk",		qdss_clk.c,		"msm_funnel.0"),
-	CLK_LOOKUP("core_clk",		qdss_clk.c,		"msm_stm.0"),
-	CLK_LOOKUP("core_clk",		qdss_clk.c,		"msm_etm.0"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-tpiu.0"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-etb.0"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-funnel.0"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-etm.0"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-etm.1"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-etm.2"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-etm.3"),
 
 	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,		""),
 	CLK_LOOKUP("mmfpb_clk",		mmfpb_clk.c,		""),
@@ -5469,6 +5501,9 @@
 	CLK_LOOKUP("mem_clk",		ebi1_acpu_a_clk.c, ""),
 	CLK_LOOKUP("bus_clk",		afab_acpu_a_clk.c, ""),
 
+	CLK_LOOKUP("reset1_clk",	dsi1_reset_clk.c, "footswitch-8x60.4"),
+	CLK_LOOKUP("reset2_clk",	dsi2_reset_clk.c, "footswitch-8x60.4"),
+
 	CLK_LOOKUP("l2_mclk",		l2_m_clk,     ""),
 	CLK_LOOKUP("krait0_mclk",	krait0_m_clk, ""),
 	CLK_LOOKUP("krait1_mclk",	krait1_m_clk, ""),
@@ -5486,6 +5521,7 @@
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.2"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"BAM_RMNT"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"msm_xo"),
+	CLK_LOOKUP("vref_buff",		cxo_clk.c,	"rpm-regulator"),
 	CLK_LOOKUP("pll2",		pll2_clk.c,	NULL),
 	CLK_LOOKUP("pll8",		pll8_clk.c,	NULL),
 	CLK_LOOKUP("pll4",		pll4_clk.c,	NULL),
@@ -5523,11 +5559,13 @@
 	CLK_LOOKUP("dfab_clk",		dfab_msmbus_clk.c,	"msm_bus"),
 	CLK_LOOKUP("dfab_a_clk",	dfab_msmbus_a_clk.c,	"msm_bus"),
 	CLK_LOOKUP("core_a_clk",	qdss_a_clk.c,		""),
-	CLK_LOOKUP("core_clk",		qdss_clk.c,		"msm_etb.0"),
-	CLK_LOOKUP("core_clk",		qdss_clk.c,		"msm_tpiu.0"),
-	CLK_LOOKUP("core_clk",		qdss_clk.c,		"msm_funnel.0"),
-	CLK_LOOKUP("core_clk",		qdss_clk.c,		"msm_stm.0"),
-	CLK_LOOKUP("core_clk",		qdss_clk.c,		"msm_etm.0"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-tpiu.0"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-etb.0"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-funnel.0"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-etm.0"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-etm.1"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-etm.2"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-etm.3"),
 
 	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,		NULL),
 	CLK_LOOKUP("mmfpb_clk",		mmfpb_clk.c,		NULL),
@@ -5786,6 +5824,9 @@
 	CLK_LOOKUP("mem_clk",		ebi1_acpu_a_clk.c, ""),
 	CLK_LOOKUP("bus_clk",		afab_acpu_a_clk.c, ""),
 
+	CLK_LOOKUP("reset1_clk",	dsi1_reset_clk.c, "footswitch-8x60.4"),
+	CLK_LOOKUP("reset2_clk",	dsi2_reset_clk.c, "footswitch-8x60.4"),
+
 	CLK_LOOKUP("l2_mclk",		l2_m_clk,     ""),
 	CLK_LOOKUP("krait0_mclk",	krait0_m_clk, ""),
 	CLK_LOOKUP("krait1_mclk",	krait1_m_clk, ""),
@@ -5828,6 +5869,7 @@
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.1"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.2"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"BAM_RMNT"),
+	CLK_LOOKUP("vref_buff",		cxo_clk.c,	"rpm-regulator"),
 	CLK_LOOKUP("pll2",		pll2_clk.c,	NULL),
 	CLK_LOOKUP("pll8",		pll8_clk.c,	NULL),
 	CLK_LOOKUP("pll4",		pll4_clk.c,	NULL),
@@ -5865,11 +5907,13 @@
 	CLK_LOOKUP("dfab_clk",		dfab_msmbus_clk.c,	"msm_bus"),
 	CLK_LOOKUP("dfab_a_clk",	dfab_msmbus_a_clk.c,	"msm_bus"),
 	CLK_LOOKUP("core_a_clk",	qdss_a_clk.c,		""),
-	CLK_LOOKUP("core_clk",		qdss_clk.c,		"msm_etb.0"),
-	CLK_LOOKUP("core_clk",		qdss_clk.c,		"msm_tpiu.0"),
-	CLK_LOOKUP("core_clk",		qdss_clk.c,		"msm_funnel.0"),
-	CLK_LOOKUP("core_clk",		qdss_clk.c,		"msm_stm.0"),
-	CLK_LOOKUP("core_clk",		qdss_clk.c,		"msm_etm.0"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-tpiu.0"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-etb.0"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-funnel.0"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-etm.0"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-etm.1"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-etm.2"),
+	CLK_LOOKUP("core_clk",		qdss_clk.c,	"coresight-etm.3"),
 
 	CLK_LOOKUP("ebi1_clk",		ebi1_clk.c,		NULL),
 	CLK_LOOKUP("mmfpb_clk",		mmfpb_clk.c,		NULL),
@@ -6111,6 +6155,8 @@
 	CLK_LOOKUP("mem_clk",		ebi1_acpu_a_clk.c, ""),
 	CLK_LOOKUP("bus_clk",		afab_acpu_a_clk.c, ""),
 
+	CLK_LOOKUP("reset1_clk",	dsi1_reset_clk.c, "footswitch-8x60.4"),
+
 	CLK_LOOKUP("l2_mclk",		l2_m_clk,     ""),
 	CLK_LOOKUP("krait0_mclk",	krait0_m_clk, ""),
 	CLK_LOOKUP("krait1_mclk",	krait1_m_clk, ""),
@@ -6477,12 +6523,15 @@
 	 * Change the freq tables and voltage requirements for
 	 * clocks which differ between 8960 and 8930.
 	 */
-	if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
-		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8930;
-
+	if (cpu_is_msm8930() || cpu_is_msm8627()) {
 		memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8930,
 		       sizeof(gfx3d_clk.c.fmax));
-
+	} else if (cpu_is_msm8930aa()) {
+		memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8930aa,
+		       sizeof(gfx3d_clk.c.fmax));
+	}
+	if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
+		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8930;
 		pll15_clk.c.rate = 900000000;
 		gmem_axi_clk.c.depends = &gfx3d_axi_clk_8930.c;
 	}
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 82b7fd6..e4bcfa9 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -18,9 +18,12 @@
 #include <linux/spinlock.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
+#include <linux/iopoll.h>
 
 #include <mach/clk.h>
 #include <mach/rpm-regulator-smd.h>
+#include <mach/socinfo.h>
+#include <mach/rpm-smd.h>
 
 #include "clock-local2.h"
 #include "clock-pll.h"
@@ -32,6 +35,7 @@
 	MMSS_BASE,
 	LPASS_BASE,
 	MSS_BASE,
+	APCS_BASE,
 	N_BASES,
 };
 
@@ -41,6 +45,7 @@
 #define MMSS_REG_BASE(x) (void __iomem *)(virt_bases[MMSS_BASE] + (x))
 #define LPASS_REG_BASE(x) (void __iomem *)(virt_bases[LPASS_BASE] + (x))
 #define MSS_REG_BASE(x) (void __iomem *)(virt_bases[MSS_BASE] + (x))
+#define APCS_REG_BASE(x) (void __iomem *)(virt_bases[APCS_BASE] + (x))
 
 #define GPLL0_MODE_REG                 0x0000
 #define GPLL0_L_REG                    0x0004
@@ -100,6 +105,7 @@
 #define CLOCK_FRQ_MEASURE_CTL_REG      0x1884
 #define CLOCK_FRQ_MEASURE_STATUS_REG   0x1888
 #define GCC_XO_DIV4_CBCR_REG           0x10C8
+#define GCC_PLLTEST_PAD_CFG_REG        0x188C
 #define APCS_GPLL_ENA_VOTE_REG         0x1480
 #define MMSS_PLL_VOTE_APCS_REG         0x0100
 #define MMSS_DEBUG_CLK_CTL_REG         0x0900
@@ -107,6 +113,8 @@
 #define LPASS_LPA_PLL_VOTE_APPS_REG    0x2000
 #define MSS_DEBUG_CLK_CTL_REG          0x0078
 
+#define GLB_CLK_DIAG_REG               0x001C
+
 #define USB30_MASTER_CMD_RCGR          0x03D4
 #define USB30_MOCK_UTMI_CMD_RCGR       0x03E8
 #define USB_HSIC_SYSTEM_CMD_RCGR       0x041C
@@ -378,6 +386,8 @@
 #define GP1_CBCR                                 0x1900
 #define GP2_CBCR                                 0x1940
 #define GP3_CBCR                                 0x1980
+#define AUDIO_CORE_GDSCR			 0x7000
+#define AUDIO_CORE_IXFABRIC_CBCR		 0x1B000
 #define AUDIO_CORE_LPAIF_CODEC_SPKR_OSR_CBCR     0xA014
 #define AUDIO_CORE_LPAIF_CODEC_SPKR_IBIT_CBCR    0xA018
 #define AUDIO_CORE_LPAIF_CODEC_SPKR_EBIT_CBCR    0xA01C
@@ -480,9 +490,12 @@
 #define OCMEMNOC_CBCR                            0x50B4
 #define LPASS_Q6SS_AHB_LFABIF_CBCR               0x22000
 #define LPASS_Q6SS_XO_CBCR                       0x26000
+#define LPASS_Q6_AXI_CBCR			 0x11C0
+#define Q6SS_AHBM_CBCR				 0x22004
 #define MSS_XO_Q6_CBCR                           0x108C
 #define MSS_BUS_Q6_CBCR                          0x10A4
 #define MSS_CFG_AHB_CBCR                         0x0280
+#define MSS_Q6_BIMC_AXI_CBCR			 0x0284
 
 #define APCS_CLOCK_BRANCH_ENA_VOTE 0x1484
 #define APCS_CLOCK_SLEEP_ENA_VOTE  0x1488
@@ -513,7 +526,7 @@
 		.freq_hz = (f), \
 		.src_clk = &s##_clk_src.c, \
 		.m_val = (m), \
-		.n_val = ~((n)-(m)), \
+		.n_val = ~((n)-(m)) * !!(n), \
 		.d_val = ~(n),\
 		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
 			| BVAL(10, 8, s##_source_val), \
@@ -524,7 +537,7 @@
 		.freq_hz = (f), \
 		.src_clk = &s##_clk_src.c, \
 		.m_val = (m), \
-		.n_val = ~((n)-(m)), \
+		.n_val = ~((n)-(m)) * !!(n), \
 		.d_val = ~(n),\
 		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
 			| BVAL(10, 8, s##_mm_source_val), \
@@ -534,7 +547,7 @@
 	{ \
 		.freq_hz = (f), \
 		.m_val = (m), \
-		.n_val = ~((n)-(m)), \
+		.n_val = ~((n)-(m)) * !!(n), \
 		.d_val = ~(n),\
 		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
 			| BVAL(10, 8, s##_mm_source_val), \
@@ -545,7 +558,7 @@
 		.freq_hz = (f), \
 		.src_clk = &s##_clk_src.c, \
 		.m_val = (m), \
-		.n_val = ~((n)-(m)), \
+		.n_val = ~((n)-(m)) * !!(n), \
 		.d_val = ~(n),\
 		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
 			| BVAL(10, 8, s##_hsic_source_val), \
@@ -556,7 +569,7 @@
 		.freq_hz = (f), \
 		.src_clk = &s##_clk_src.c, \
 		.m_val = (m), \
-		.n_val = ~((n)-(m)), \
+		.n_val = ~((n)-(m)) * !!(n), \
 		.d_val = ~(n),\
 		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
 			| BVAL(10, 8, s##_lpass_source_val), \
@@ -603,13 +616,16 @@
 #define RPM_BUS_CLK_TYPE	0x316b6c63
 #define RPM_MEM_CLK_TYPE	0x326b6c63
 
-#define CXO_ID		0x0
-#define QDSS_ID		0x1
+#define RPM_SMD_KEY_ENABLE	0x62616E45
+
+#define CXO_ID			0x0
+#define QDSS_ID			0x1
+#define RPM_SCALING_ENABLE_ID	0x2
 
 #define PNOC_ID		0x0
 #define SNOC_ID		0x1
 #define CNOC_ID		0x2
-#define MMSSNOC_AHB_ID  0x4
+#define MMSSNOC_AHB_ID  0x3
 
 #define BIMC_ID		0x0
 #define OCMEM_ID	0x1
@@ -751,14 +767,19 @@
 static DEFINE_CLK_VOTER(bimc_msmbus_clk, &bimc_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(bimc_acpu_a_clk, &bimc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ocmemgx_gfx3d_clk, &ocmemgx_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(ocmemgx_msmbus_clk, &ocmemgx_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(ocmemgx_msmbus_a_clk, &ocmemgx_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ocmemgx_core_clk, &ocmemgx_clk.c, LONG_MAX);
 
 static DEFINE_CLK_VOTER(pnoc_sdcc1_clk, &pnoc_clk.c, 0);
 static DEFINE_CLK_VOTER(pnoc_sdcc2_clk, &pnoc_clk.c, 0);
 static DEFINE_CLK_VOTER(pnoc_sdcc3_clk, &pnoc_clk.c, 0);
 static DEFINE_CLK_VOTER(pnoc_sdcc4_clk, &pnoc_clk.c, 0);
 
+static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, 0);
+static DEFINE_CLK_VOTER(pnoc_qseecom_clk, &pnoc_clk.c, 0);
+
 static struct clk_freq_tbl ftbl_gcc_usb30_master_clk[] = {
 	F(125000000,  gpll0,   1,   5,  24),
 	F_END
@@ -1270,6 +1291,12 @@
 	F_END
 };
 
+static struct clk_freq_tbl ftbl_gcc_sdcc_apps_rumi_clk[] = {
+	F(   400000,    cxo,  12,   1,   4),
+	F( 19200000,    cxo,  1,    0,   0),
+	F_END
+};
+
 static struct rcg_clk sdcc1_apps_clk_src = {
 	.cmd_rcgr_reg = SDCC1_APPS_CMD_RCGR,
 	.set_rate = set_rate_mnd,
@@ -2270,11 +2297,22 @@
 	},
 };
 
+static struct branch_clk gcc_mss_q6_bimc_axi_clk = {
+	.cbcr_reg = MSS_Q6_BIMC_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mss_q6_bimc_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_q6_bimc_axi_clk.c),
+	},
+};
+
 static struct clk_freq_tbl ftbl_mmss_axi_clk[] = {
 	F_MM( 19200000,    cxo,     1,   0,   0),
 	F_MM(150000000,  gpll0,     4,   0,   0),
 	F_MM(282000000, mmpll1,     3,   0,   0),
-	F_MM(320000000, mmpll1,   2.5,   0,   0),
+	F_MM(320000000, mmpll0,   2.5,   0,   0),
 	F_MM(400000000, mmpll0,     2,   0,   0),
 	F_END
 };
@@ -3730,17 +3768,6 @@
 	},
 };
 
-static struct branch_clk mmss_mmssnoc_ahb_clk = {
-	.cbcr_reg = MMSS_MMSSNOC_AHB_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[MMSS_BASE],
-	.c = {
-		.dbg_name = "mmss_mmssnoc_ahb_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(mmss_mmssnoc_ahb_clk.c),
-	},
-};
-
 static struct branch_clk mmss_mmssnoc_bto_ahb_clk = {
 	.cbcr_reg = MMSS_MMSSNOC_BTO_AHB_CBCR,
 	.has_sibling = 1,
@@ -3755,8 +3782,7 @@
 static struct branch_clk mmss_mmssnoc_axi_clk = {
 	.cbcr_reg = MMSS_MMSSNOC_AXI_CBCR,
 	.parent = &axi_clk_src.c,
-	/* The bus driver needs set_rate to go through to the parent */
-	.has_sibling = 0,
+	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mmss_mmssnoc_axi_clk",
@@ -3768,12 +3794,14 @@
 static struct branch_clk mmss_s0_axi_clk = {
 	.cbcr_reg = MMSS_S0_AXI_CBCR,
 	.parent = &axi_clk_src.c,
-	.has_sibling = 1,
+	/* The bus driver needs set_rate to go through to the parent */
+	.has_sibling = 0,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mmss_s0_axi_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(mmss_s0_axi_clk.c),
+		.depends = &mmss_mmssnoc_axi_clk.c,
 	},
 };
 
@@ -3863,7 +3891,7 @@
 
 static struct branch_clk oxili_gfx3d_clk = {
 	.cbcr_reg = OXILI_GFX3D_CBCR,
-	.has_sibling = 1,
+	.parent = &ocmemgx_gfx3d_clk.c,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "oxili_gfx3d_clk",
@@ -3885,7 +3913,7 @@
 };
 
 static struct clk_freq_tbl ftbl_audio_core_slimbus_core_clock[] = {
-	F_LPASS(28800000, lpapll0, 1, 15, 256),
+	F_LPASS(24576000, lpapll0, 4, 1, 5),
 	F_END
 };
 
@@ -3929,7 +3957,7 @@
 	F_LPASS(  512000, lpapll0, 16, 1, 60),
 	F_LPASS(  768000, lpapll0, 16, 1, 40),
 	F_LPASS( 1024000, lpapll0, 16, 1, 30),
-	F_LPASS( 1536000, lpapll0, 16, 1, 10),
+	F_LPASS( 1536000, lpapll0, 16, 1, 20),
 	F_LPASS( 2048000, lpapll0, 16, 1, 15),
 	F_LPASS( 3072000, lpapll0, 16, 1, 10),
 	F_LPASS( 4096000, lpapll0, 15, 1,  8),
@@ -4300,6 +4328,28 @@
 	},
 };
 
+static struct branch_clk audio_core_ixfabric_clk = {
+	.cbcr_reg = AUDIO_CORE_IXFABRIC_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_ixfabric_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_ixfabric_clk.c),
+	},
+};
+
+static struct branch_clk gcc_lpass_q6_axi_clk = {
+	.cbcr_reg = LPASS_Q6_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_lpass_q6_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_lpass_q6_axi_clk.c),
+	},
+};
+
 static struct branch_clk q6ss_xo_clk = {
 	.cbcr_reg = LPASS_Q6SS_XO_CBCR,
 	.bcr_reg = LPASS_Q6SS_BCR,
@@ -4312,6 +4362,17 @@
 	},
 };
 
+static struct branch_clk q6ss_ahbm_clk = {
+	.cbcr_reg = Q6SS_AHBM_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "q6ss_ahbm_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(q6ss_ahbm_clk.c),
+	},
+};
+
 static struct branch_clk mss_xo_q6_clk = {
 	.cbcr_reg = MSS_XO_Q6_CBCR,
 	.bcr_reg = MSS_Q6SS_BCR,
@@ -4337,6 +4398,12 @@
 	},
 };
 
+static DEFINE_CLK_MEASURE(l2_m_clk);
+static DEFINE_CLK_MEASURE(krait0_m_clk);
+static DEFINE_CLK_MEASURE(krait1_m_clk);
+static DEFINE_CLK_MEASURE(krait2_m_clk);
+static DEFINE_CLK_MEASURE(krait3_m_clk);
+
 #ifdef CONFIG_DEBUG_FS
 
 struct measure_mux_entry {
@@ -4346,73 +4413,78 @@
 };
 
 struct measure_mux_entry measure_mux[] = {
-	{&gcc_bam_dma_ahb_clk.c,		GCC_BASE, 0x00e8},
-	{&gcc_blsp1_ahb_clk.c,			GCC_BASE, 0x0090},
-	{&gcc_blsp1_qup1_i2c_apps_clk.c,	GCC_BASE, 0x0093},
-	{&gcc_blsp1_qup1_spi_apps_clk.c,	GCC_BASE, 0x0092},
-	{&gcc_blsp1_qup2_i2c_apps_clk.c,	GCC_BASE, 0x0098},
-	{&gcc_blsp1_qup2_spi_apps_clk.c,	GCC_BASE, 0x0096},
-	{&gcc_blsp1_qup3_i2c_apps_clk.c,	GCC_BASE, 0x009c},
-	{&gcc_blsp1_qup3_spi_apps_clk.c,	GCC_BASE, 0x009b},
-	{&gcc_blsp1_qup4_i2c_apps_clk.c,	GCC_BASE, 0x00a1},
-	{&gcc_blsp1_qup4_spi_apps_clk.c,	GCC_BASE, 0x00a0},
-	{&gcc_blsp1_qup5_i2c_apps_clk.c,	GCC_BASE, 0x00a5},
-	{&gcc_blsp1_qup5_spi_apps_clk.c,	GCC_BASE, 0x00a4},
-	{&gcc_blsp1_qup6_i2c_apps_clk.c,	GCC_BASE, 0x00aa},
-	{&gcc_blsp1_qup6_spi_apps_clk.c,	GCC_BASE, 0x00a9},
-	{&gcc_blsp1_uart1_apps_clk.c,		GCC_BASE, 0x0094},
-	{&gcc_blsp1_uart2_apps_clk.c,		GCC_BASE, 0x0099},
-	{&gcc_blsp1_uart3_apps_clk.c,		GCC_BASE, 0x009d},
-	{&gcc_blsp1_uart4_apps_clk.c,		GCC_BASE, 0x00a2},
-	{&gcc_blsp1_uart5_apps_clk.c,		GCC_BASE, 0x00a6},
-	{&gcc_blsp1_uart6_apps_clk.c,		GCC_BASE, 0x00ab},
-	{&gcc_blsp2_ahb_clk.c,			GCC_BASE, 0x00b0},
-	{&gcc_blsp2_qup1_i2c_apps_clk.c,	GCC_BASE, 0x00b3},
-	{&gcc_blsp2_qup1_spi_apps_clk.c,	GCC_BASE, 0x00b2},
-	{&gcc_blsp2_qup2_i2c_apps_clk.c,	GCC_BASE, 0x00b8},
-	{&gcc_blsp2_qup2_spi_apps_clk.c,	GCC_BASE, 0x00b6},
-	{&gcc_blsp2_qup3_i2c_apps_clk.c,	GCC_BASE, 0x00bc},
-	{&gcc_blsp2_qup3_spi_apps_clk.c,	GCC_BASE, 0x00bb},
-	{&gcc_blsp2_qup4_i2c_apps_clk.c,	GCC_BASE, 0x00c1},
-	{&gcc_blsp2_qup4_spi_apps_clk.c,	GCC_BASE, 0x00c0},
-	{&gcc_blsp2_qup5_i2c_apps_clk.c,	GCC_BASE, 0x00c5},
-	{&gcc_blsp2_qup5_spi_apps_clk.c,	GCC_BASE, 0x00c4},
-	{&gcc_blsp2_qup6_i2c_apps_clk.c,	GCC_BASE, 0x00ca},
-	{&gcc_blsp2_qup6_spi_apps_clk.c,	GCC_BASE, 0x00c9},
-	{&gcc_blsp2_uart1_apps_clk.c,		GCC_BASE, 0x00b4},
-	{&gcc_blsp2_uart2_apps_clk.c,		GCC_BASE, 0x00b9},
-	{&gcc_blsp2_uart3_apps_clk.c,		GCC_BASE, 0x00bd},
-	{&gcc_blsp2_uart4_apps_clk.c,		GCC_BASE, 0x00c2},
-	{&gcc_blsp2_uart5_apps_clk.c,		GCC_BASE, 0x00c6},
-	{&gcc_blsp2_uart6_apps_clk.c,		GCC_BASE, 0x00cb},
-	{&gcc_boot_rom_ahb_clk.c,		GCC_BASE, 0x0100},
-	{&gcc_ocmem_noc_cfg_ahb_clk.c,		GCC_BASE, 0x0029},
-	{&gcc_mmss_noc_cfg_ahb_clk.c,		GCC_BASE, 0x002A},
-	{&gcc_mss_cfg_ahb_clk.c,		GCC_BASE, 0x0030},
-	{&gcc_ce1_clk.c,			GCC_BASE, 0x0140},
-	{&gcc_ce2_clk.c,			GCC_BASE, 0x0148},
-	{&gcc_pdm2_clk.c,			GCC_BASE, 0x00da},
-	{&gcc_pdm_ahb_clk.c,			GCC_BASE, 0x00d8},
-	{&gcc_prng_ahb_clk.c,			GCC_BASE, 0x00e0},
-	{&gcc_sdcc1_ahb_clk.c,			GCC_BASE, 0x0071},
-	{&gcc_sdcc1_apps_clk.c,			GCC_BASE, 0x0070},
-	{&gcc_sdcc2_ahb_clk.c,			GCC_BASE, 0x0079},
-	{&gcc_sdcc2_apps_clk.c,			GCC_BASE, 0x0078},
-	{&gcc_sdcc3_ahb_clk.c,			GCC_BASE, 0x0081},
-	{&gcc_sdcc3_apps_clk.c,			GCC_BASE, 0x0080},
-	{&gcc_sdcc4_ahb_clk.c,			GCC_BASE, 0x0089},
-	{&gcc_sdcc4_apps_clk.c,			GCC_BASE, 0x0088},
-	{&gcc_tsif_ahb_clk.c,			GCC_BASE, 0x00f0},
-	{&gcc_tsif_ref_clk.c,			GCC_BASE, 0x00f1},
+	{&gcc_pdm_ahb_clk.c,			GCC_BASE, 0x00d0},
+	{&gcc_blsp2_qup1_i2c_apps_clk.c,	GCC_BASE, 0x00ab},
+	{&gcc_blsp2_qup3_spi_apps_clk.c,	GCC_BASE, 0x00b3},
+	{&gcc_blsp2_uart5_apps_clk.c,		GCC_BASE, 0x00be},
 	{&gcc_usb30_master_clk.c,		GCC_BASE, 0x0050},
+	{&gcc_blsp2_qup3_i2c_apps_clk.c,	GCC_BASE, 0x00b4},
+	{&gcc_usb_hsic_system_clk.c,		GCC_BASE, 0x0059},
+	{&gcc_blsp2_uart3_apps_clk.c,		GCC_BASE, 0x00b5},
+	{&gcc_usb_hsic_io_cal_clk.c,		GCC_BASE, 0x005b},
+	{&gcc_ce2_axi_clk.c,			GCC_BASE, 0x0141},
+	{&gcc_sdcc3_ahb_clk.c,			GCC_BASE, 0x0079},
+	{&gcc_blsp1_qup5_i2c_apps_clk.c,	GCC_BASE, 0x009d},
+	{&gcc_blsp1_qup1_spi_apps_clk.c,	GCC_BASE, 0x008a},
+	{&gcc_blsp2_uart4_apps_clk.c,		GCC_BASE, 0x00ba},
+	{&gcc_ce2_clk.c,			GCC_BASE, 0x0140},
+	{&gcc_blsp1_uart2_apps_clk.c,		GCC_BASE, 0x0091},
+	{&gcc_sdcc1_ahb_clk.c,			GCC_BASE, 0x0069},
+	{&gcc_mss_cfg_ahb_clk.c,		GCC_BASE, 0x0030},
+	{&gcc_tsif_ahb_clk.c,			GCC_BASE, 0x00e8},
+	{&gcc_sdcc4_ahb_clk.c,			GCC_BASE, 0x0081},
+	{&gcc_blsp1_qup4_spi_apps_clk.c,	GCC_BASE, 0x0098},
+	{&gcc_blsp2_qup4_spi_apps_clk.c,	GCC_BASE, 0x00b8},
+	{&gcc_blsp1_qup3_spi_apps_clk.c,	GCC_BASE, 0x0093},
+	{&gcc_blsp1_qup6_i2c_apps_clk.c,	GCC_BASE, 0x00a2},
+	{&gcc_blsp2_qup6_i2c_apps_clk.c,	GCC_BASE, 0x00c2},
+	{&gcc_bam_dma_ahb_clk.c,		GCC_BASE, 0x00e0},
+	{&gcc_sdcc3_apps_clk.c,			GCC_BASE, 0x0078},
+	{&gcc_usb_hs_system_clk.c,		GCC_BASE, 0x0060},
+	{&gcc_blsp1_ahb_clk.c,			GCC_BASE, 0x0088},
+	{&gcc_sdcc1_apps_clk.c,			GCC_BASE, 0x0068},
+	{&gcc_blsp2_qup5_i2c_apps_clk.c,	GCC_BASE, 0x00bd},
+	{&gcc_blsp1_uart4_apps_clk.c,		GCC_BASE, 0x009a},
+	{&gcc_blsp2_qup2_spi_apps_clk.c,	GCC_BASE, 0x00ae},
+	{&gcc_blsp2_qup6_spi_apps_clk.c,	GCC_BASE, 0x00c1},
+	{&gcc_blsp2_uart2_apps_clk.c,		GCC_BASE, 0x00b1},
+	{&gcc_blsp1_qup2_spi_apps_clk.c,	GCC_BASE, 0x008e},
+	{&gcc_usb_hsic_ahb_clk.c,		GCC_BASE, 0x0058},
+	{&gcc_blsp1_uart3_apps_clk.c,		GCC_BASE, 0x0095},
 	{&gcc_usb30_mock_utmi_clk.c,		GCC_BASE, 0x0052},
-	{&gcc_usb_hs_ahb_clk.c,			GCC_BASE, 0x0069},
-	{&gcc_usb_hs_system_clk.c,		GCC_BASE, 0x0068},
-	{&gcc_usb_hsic_ahb_clk.c,		GCC_BASE, 0x0060},
-	{&gcc_usb_hsic_clk.c,			GCC_BASE, 0x0062},
-	{&gcc_usb_hsic_io_cal_clk.c,		GCC_BASE, 0x0063},
-	{&gcc_usb_hsic_system_clk.c,		GCC_BASE, 0x0061},
-	{&mmss_mmssnoc_ahb_clk.c,		MMSS_BASE, 0x0001},
+	{&gcc_ce1_axi_clk.c,			GCC_BASE, 0x0139},
+	{&gcc_sdcc4_apps_clk.c,			GCC_BASE, 0x0080},
+	{&gcc_blsp1_qup5_spi_apps_clk.c,	GCC_BASE, 0x009c},
+	{&gcc_usb_hs_ahb_clk.c,			GCC_BASE, 0x0061},
+	{&gcc_blsp1_qup6_spi_apps_clk.c,	GCC_BASE, 0x00a1},
+	{&gcc_blsp2_qup2_i2c_apps_clk.c,	GCC_BASE, 0x00b0},
+	{&gcc_prng_ahb_clk.c,			GCC_BASE, 0x00d8},
+	{&gcc_blsp1_qup3_i2c_apps_clk.c,	GCC_BASE, 0x0094},
+	{&gcc_usb_hsic_clk.c,			GCC_BASE, 0x005a},
+	{&gcc_blsp1_uart6_apps_clk.c,		GCC_BASE, 0x00a3},
+	{&gcc_sdcc2_apps_clk.c,			GCC_BASE, 0x0070},
+	{&gcc_tsif_ref_clk.c,			GCC_BASE, 0x00e9},
+	{&gcc_blsp1_uart1_apps_clk.c,		GCC_BASE, 0x008c},
+	{&gcc_blsp2_qup5_spi_apps_clk.c,	GCC_BASE, 0x00bc},
+	{&gcc_blsp1_qup4_i2c_apps_clk.c,	GCC_BASE, 0x0099},
+	{&gcc_mmss_noc_cfg_ahb_clk.c,		GCC_BASE, 0x002a},
+	{&gcc_blsp2_ahb_clk.c,			GCC_BASE, 0x00a8},
+	{&gcc_boot_rom_ahb_clk.c,		GCC_BASE, 0x00f8},
+	{&gcc_ce1_ahb_clk.c,			GCC_BASE, 0x013a},
+	{&gcc_pdm2_clk.c,			GCC_BASE, 0x00d2},
+	{&gcc_blsp2_qup4_i2c_apps_clk.c,	GCC_BASE, 0x00b9},
+	{&gcc_ce2_ahb_clk.c,			GCC_BASE, 0x0142},
+	{&gcc_blsp1_uart5_apps_clk.c,		GCC_BASE, 0x009e},
+	{&gcc_blsp2_qup1_spi_apps_clk.c,	GCC_BASE, 0x00aa},
+	{&gcc_blsp1_qup2_i2c_apps_clk.c,	GCC_BASE, 0x0090},
+	{&gcc_blsp2_uart1_apps_clk.c,		GCC_BASE, 0x00ac},
+	{&gcc_blsp1_qup1_i2c_apps_clk.c,	GCC_BASE, 0x008b},
+	{&gcc_blsp2_uart6_apps_clk.c,		GCC_BASE, 0x00c3},
+	{&gcc_sdcc2_ahb_clk.c,			GCC_BASE, 0x0071},
+	{&gcc_ocmem_noc_cfg_ahb_clk.c,		GCC_BASE, 0x0029},
+	{&gcc_ce1_clk.c,			GCC_BASE, 0x0138},
+	{&gcc_lpass_q6_axi_clk.c,		GCC_BASE, 0x0160},
+	{&gcc_mss_q6_bimc_axi_clk.c,		GCC_BASE, 0x0031},
 	{&mmss_mmssnoc_axi_clk.c,		MMSS_BASE, 0x0004},
 	{&ocmemnoc_clk.c,			MMSS_BASE, 0x0007},
 	{&ocmemcx_ocmemnoc_clk.c,		MMSS_BASE, 0x0009},
@@ -4465,6 +4537,16 @@
 	{&camss_vfe_vfe_ahb_clk.c,		MMSS_BASE, 0x003c},
 	{&camss_vfe_vfe_axi_clk.c,		MMSS_BASE, 0x003d},
 	{&camss_vfe_vfe_ocmemnoc_clk.c,		MMSS_BASE, 0x003e},
+	{&oxilicx_axi_clk.c,			MMSS_BASE, 0x000b},
+	{&oxilicx_ahb_clk.c,			MMSS_BASE, 0x000c},
+	{&ocmemcx_ocmemnoc_clk.c,		MMSS_BASE, 0x0009},
+	{&oxili_gfx3d_clk.c,			MMSS_BASE, 0x000d},
+	{&venus0_axi_clk.c,			MMSS_BASE, 0x000f},
+	{&venus0_ocmemnoc_clk.c,		MMSS_BASE, 0x0010},
+	{&venus0_ahb_clk.c,			MMSS_BASE, 0x0011},
+	{&venus0_vcodec0_clk.c,			MMSS_BASE, 0x000e},
+	{&mmss_s0_axi_clk.c,			MMSS_BASE, 0x0005},
+	{&mmssnoc_ahb_clk.c,			MMSS_BASE, 0x0001},
 	{&mdss_ahb_clk.c,			MMSS_BASE, 0x0022},
 	{&mdss_hdmi_clk.c,			MMSS_BASE, 0x001d},
 	{&mdss_mdp_clk.c,			MMSS_BASE, 0x0014},
@@ -4493,9 +4575,17 @@
 	{&audio_core_slimbus_lfabif_clk.c,	LPASS_BASE, 0x003e},
 	{&q6ss_xo_clk.c,			LPASS_BASE, 0x002b},
 	{&q6ss_ahb_lfabif_clk.c,		LPASS_BASE, 0x001e},
+	{&q6ss_ahbm_clk.c,			LPASS_BASE, 0x001d},
+	{&audio_core_ixfabric_clk.c,		LPASS_BASE, 0x0059},
 	{&mss_bus_q6_clk.c,			MSS_BASE, 0x003c},
 	{&mss_xo_q6_clk.c,			MSS_BASE, 0x0007},
 
+	{&l2_m_clk,				APCS_BASE, 0x0081},
+	{&krait0_m_clk,				APCS_BASE, 0x0080},
+	{&krait1_m_clk,				APCS_BASE, 0x0088},
+	{&krait2_m_clk,				APCS_BASE, 0x0090},
+	{&krait3_m_clk,				APCS_BASE, 0x0098},
+
 	{&dummy_clk,				N_BASES,   0x0000},
 };
 
@@ -4545,12 +4635,12 @@
 		break;
 
 	case LPASS_BASE:
-		clk_sel = 0x169;
+		clk_sel = 0x161;
 		regval = BVAL(11, 0, measure_mux[i].debug_mux);
 		writel_relaxed(regval, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL_REG));
 
 		/* Activate debug clock output */
-		regval |= BIT(16);
+		regval |= BIT(20);
 		writel_relaxed(regval, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL_REG));
 		break;
 
@@ -4560,6 +4650,13 @@
 		writel_relaxed(regval, MSS_REG_BASE(MSS_DEBUG_CLK_CTL_REG));
 		break;
 
+	case APCS_BASE:
+		clk->multiplier = 4;
+		clk_sel = 0x16A;
+		regval = measure_mux[i].debug_mux;
+		writel_relaxed(regval, APCS_REG_BASE(GLB_CLK_DIAG_REG));
+		break;
+
 	default:
 		return -EINVAL;
 	}
@@ -4649,6 +4746,7 @@
 		ret = (raw_count_full * clk->multiplier);
 	}
 
+	writel_relaxed(0x51A00, GCC_REG_BASE(GCC_PLLTEST_PAD_CFG_REG));
 	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
 
 	clk_disable_unprepare(&cxo_clk_src.c);
@@ -4681,6 +4779,48 @@
 	.multiplier = 1,
 };
 
+
+static struct clk_lookup msm_clocks_8974_rumi[] = {
+	CLK_LOOKUP("iface_clk", gcc_sdcc1_ahb_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("core_clk", gcc_sdcc1_apps_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("bus_clk", pnoc_sdcc1_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("iface_clk", gcc_sdcc2_ahb_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("core_clk", gcc_sdcc2_apps_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("bus_clk", pnoc_sdcc2_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("iface_clk", gcc_sdcc3_ahb_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("core_clk", gcc_sdcc3_apps_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("bus_clk", pnoc_sdcc3_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("iface_clk", gcc_sdcc4_ahb_clk.c, "msm_sdcc.4"),
+	CLK_LOOKUP("core_clk", gcc_sdcc4_apps_clk.c, "msm_sdcc.4"),
+	CLK_LOOKUP("bus_clk", pnoc_sdcc4_clk.c, "msm_sdcc.4"),
+	CLK_DUMMY("xo",		XO_CLK,		NULL,	OFF),
+	CLK_DUMMY("xo",		XO_CLK,		"pil_pronto",		OFF),
+	CLK_DUMMY("core_clk",	BLSP2_UART_CLK,	"f991f000.serial",	OFF),
+	CLK_DUMMY("iface_clk",	BLSP2_UART_CLK,	"f991f000.serial",	OFF),
+	CLK_DUMMY("core_clk",	SDC1_CLK,	NULL,			OFF),
+	CLK_DUMMY("iface_clk",	SDC1_P_CLK,	NULL,			OFF),
+	CLK_DUMMY("core_clk",	SDC3_CLK,	NULL,			OFF),
+	CLK_DUMMY("iface_clk",	SDC3_P_CLK,	NULL,			OFF),
+	CLK_DUMMY("phy_clk", NULL, "msm_otg", OFF),
+	CLK_DUMMY("core_clk", NULL, "msm_otg", OFF),
+	CLK_DUMMY("iface_clk", NULL, "msm_otg", OFF),
+	CLK_DUMMY("xo", NULL, "msm_otg", OFF),
+	CLK_DUMMY("dfab_clk",	DFAB_CLK,	NULL, 0),
+	CLK_DUMMY("dma_bam_pclk",	DMA_BAM_P_CLK,	NULL, 0),
+	CLK_DUMMY("mem_clk",	NULL,	NULL, 0),
+	CLK_DUMMY("core_clk",	SPI_CLK,	"spi_qsd.1",	OFF),
+	CLK_DUMMY("iface_clk",	SPI_P_CLK,	"spi_qsd.1",	OFF),
+	CLK_DUMMY("core_clk",	NULL,	"f9966000.i2c", 0),
+	CLK_DUMMY("iface_clk",	NULL,	"f9966000.i2c", 0),
+	CLK_DUMMY("core_clk",	NULL,	"fe12f000.slim",	OFF),
+	CLK_DUMMY("core_clk", "mdp.0", NULL, 0),
+	CLK_DUMMY("core_clk_src", "mdp.0", NULL, 0),
+	CLK_DUMMY("lut_clk", "mdp.0", NULL, 0),
+	CLK_DUMMY("vsync_clk", "mdp.0", NULL, 0),
+	CLK_DUMMY("iface_clk", "mdp.0", NULL, 0),
+	CLK_DUMMY("bus_clk", "mdp.0", NULL, 0),
+};
+
 static struct clk_lookup msm_clocks_8974[] = {
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	"msm_otg"),
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil-q6v5-lpass"),
@@ -4690,7 +4830,8 @@
 	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
 
 	CLK_LOOKUP("dma_bam_pclk", gcc_bam_dma_ahb_clk.c, "msm_sps"),
-	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "msm_serial_hsl.0"),
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991f000.serial"),
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991e000.serial"),
 	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "spi_qsd.1"),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, ""),
@@ -4705,8 +4846,8 @@
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup6_i2c_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup6_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp1_uart1_apps_clk.c, ""),
-	CLK_LOOKUP("core_clk", gcc_blsp1_uart2_apps_clk.c, ""),
-	CLK_LOOKUP("core_clk", gcc_blsp1_uart3_apps_clk.c, "msm_serial_hsl.0"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart2_apps_clk.c, "f991e000.serial"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart3_apps_clk.c, "f991f000.serial"),
 	CLK_LOOKUP("core_clk", gcc_blsp1_uart4_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp1_uart5_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp1_uart6_apps_clk.c, ""),
@@ -4784,11 +4925,12 @@
 
 	/* Multimedia clocks */
 	CLK_LOOKUP("bus_clk_src", axi_clk_src.c, ""),
-	CLK_LOOKUP("bus_clk", mmss_mmssnoc_ahb_clk.c, ""),
 	CLK_LOOKUP("bus_clk", mmss_mmssnoc_axi_clk.c, ""),
 	CLK_LOOKUP("core_clk", mdss_edpaux_clk.c, ""),
 	CLK_LOOKUP("core_clk", mdss_edppixel_clk.c, ""),
-	CLK_LOOKUP("core_clk", mdss_esc0_clk.c, ""),
+	CLK_LOOKUP("byte_clk", mdss_byte0_clk.c, "fd922800.qcom,mdss_dsi"),
+	CLK_LOOKUP("byte_clk", mdss_byte1_clk.c, ""),
+	CLK_LOOKUP("core_clk", mdss_esc0_clk.c, "fd922800.qcom,mdss_dsi"),
 	CLK_LOOKUP("core_clk", mdss_esc1_clk.c, ""),
 	CLK_LOOKUP("iface_clk", mdss_hdmi_ahb_clk.c, ""),
 	CLK_LOOKUP("core_clk", mdss_hdmi_clk.c, ""),
@@ -4865,6 +5007,8 @@
 	CLK_LOOKUP("core_clk", oxilicx_axi_clk.c, "fdb10000.qcom,iommu"),
 	CLK_LOOKUP("iface_clk", oxilicx_ahb_clk.c, "fdb10000.qcom,iommu"),
 	CLK_LOOKUP("alt_core_clk", oxili_gfx3d_clk.c, "fdb10000.qcom,iommu"),
+	CLK_LOOKUP("core_clk", ocmemgx_core_clk.c, "fdd00000.qcom,ocmem"),
+	CLK_LOOKUP("iface_clk", ocmemcx_ocmemnoc_clk.c, "fdd00000.qcom,ocmem"),
 	CLK_LOOKUP("iface_clk", venus0_ahb_clk.c, "fdc84000.qcom,iommu"),
 	CLK_LOOKUP("alt_core_clk", venus0_vcodec0_clk.c, "fdc84000.qcom,iommu"),
 	CLK_LOOKUP("core_clk", venus0_axi_clk.c, "fdc84000.qcom,iommu"),
@@ -4881,6 +5025,7 @@
 
 
 	/* LPASS clocks */
+	CLK_LOOKUP("bus_clk", audio_core_ixfabric_clk.c, ""),
 	CLK_LOOKUP("core_clk", audio_core_slimbus_core_clk.c, "fe12f000.slim"),
 	CLK_LOOKUP("iface_clk", audio_core_slimbus_lfabif_clk.c,
 			"fe12f000.slim"),
@@ -4904,28 +5049,34 @@
 	CLK_LOOKUP("osr_clk", audio_core_lpaif_quad_osr_clk.c, ""),
 	CLK_LOOKUP("ebit_clk", audio_core_lpaif_quad_ebit_clk.c, ""),
 	CLK_LOOKUP("ibit_clk", audio_core_lpaif_quad_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk", audio_core_lpaif_pcm0_clk_src.c, ""),
+	CLK_LOOKUP("pcm_clk", audio_core_lpaif_pcm0_clk_src.c,
+						"msm-dai-q6.4106"),
 	CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm0_ebit_clk.c, ""),
+	CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm0_ibit_clk.c,
+						"msm-dai-q6.4106"),
 	CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm0_ibit_clk.c, ""),
 	CLK_LOOKUP("core_clk", audio_core_lpaif_pcm1_clk_src.c, ""),
 	CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm1_ebit_clk.c, ""),
 	CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm1_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk_src", audio_core_lpaif_pcmoe_clk_src.c, ""),
-	CLK_LOOKUP("core_clk", audio_core_lpaif_pcmoe_clk.c, ""),
+	CLK_LOOKUP("core_oe_src_clk", audio_core_lpaif_pcmoe_clk_src.c,
+						"msm-dai-q6.4106"),
+	CLK_LOOKUP("core_oe_clk", audio_core_lpaif_pcmoe_clk.c,
+						"msm-dai-q6.4106"),
 
-	CLK_LOOKUP("core_clk",       mss_xo_q6_clk.c, "pil-q6v5-mss"),
-	CLK_LOOKUP("bus_clk",       mss_bus_q6_clk.c, "pil-q6v5-mss"),
-	CLK_LOOKUP("bus_clk",  gcc_mss_cfg_ahb_clk.c, ""),
-	CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, "pil-q6v5-mss"),
-	CLK_LOOKUP("core_clk",         q6ss_xo_clk.c, "pil-q6v5-lpass"),
-	CLK_LOOKUP("bus_clk",  q6ss_ahb_lfabif_clk.c, "pil-q6v5-lpass"),
+	CLK_LOOKUP("core_clk",       mss_xo_q6_clk.c,  "pil-q6v5-mss"),
+	CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "pil-q6v5-mss"),
+	CLK_LOOKUP("iface_clk", gcc_mss_cfg_ahb_clk.c, "pil-q6v5-mss"),
+	CLK_LOOKUP("reg_clk",       mss_bus_q6_clk.c,  "pil-q6v5-mss"),
+	CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c,  "pil-q6v5-mss"),
+
+	CLK_LOOKUP("core_clk",         q6ss_xo_clk.c,  "pil-q6v5-lpass"),
+	CLK_LOOKUP("bus_clk", gcc_lpass_q6_axi_clk.c,  "pil-q6v5-lpass"),
+	CLK_LOOKUP("iface_clk", q6ss_ahb_lfabif_clk.c, "pil-q6v5-lpass"),
+	CLK_LOOKUP("reg_clk",        q6ss_ahbm_clk.c,  "pil-q6v5-lpass"),
 	CLK_LOOKUP("core_clk", gcc_prng_ahb_clk.c, "msm_rng"),
 
-	/* TODO: Remove dummy clocks as soon as they become unnecessary */
-	CLK_DUMMY("dfab_clk",  DFAB_CLK,    "msm_sps", OFF),
-	CLK_DUMMY("mem_clk",       NULL,    "msm_sps", OFF),
-	CLK_DUMMY("bus_clk",       NULL,        "scm", OFF),
-	CLK_DUMMY("bus_clk",       NULL,    "qseecom", OFF),
+	CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "msm_sps"),
+	CLK_LOOKUP("bus_clk",  pnoc_qseecom_clk.c, "qseecom"),
 
 	CLK_LOOKUP("bus_clk", snoc_clk.c, ""),
 	CLK_LOOKUP("bus_clk", pnoc_clk.c, ""),
@@ -4951,8 +5102,8 @@
 	CLK_LOOKUP("ocmem_a_clk", ocmemgx_msmbus_a_clk.c, "msm_bus"),
 	CLK_LOOKUP("bus_clk",	ocmemnoc_clk.c,		"msm_ocmem_noc"),
 	CLK_LOOKUP("bus_a_clk",	ocmemnoc_clk.c,		"msm_ocmem_noc"),
-	CLK_LOOKUP("bus_clk",	mmss_mmssnoc_axi_clk.c,	"msm_mmss_noc"),
-	CLK_LOOKUP("bus_a_clk",	mmss_mmssnoc_axi_clk.c,	"msm_mmss_noc"),
+	CLK_LOOKUP("bus_clk",	mmss_s0_axi_clk.c,	"msm_mmss_noc"),
+	CLK_LOOKUP("bus_a_clk",	mmss_s0_axi_clk.c,	"msm_mmss_noc"),
 	CLK_LOOKUP("iface_clk", gcc_mmss_noc_cfg_ahb_clk.c, ""),
 	CLK_LOOKUP("iface_clk", gcc_ocmem_noc_cfg_ahb_clk.c, ""),
 
@@ -4985,6 +5136,12 @@
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm1"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm2"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm3"),
+
+	CLK_LOOKUP("l2_m_clk",		l2_m_clk,     ""),
+	CLK_LOOKUP("krait0_m_clk",	krait0_m_clk, ""),
+	CLK_LOOKUP("krait1_m_clk",	krait1_m_clk, ""),
+	CLK_LOOKUP("krait2_m_clk",	krait2_m_clk, ""),
+	CLK_LOOKUP("krait3_m_clk",	krait3_m_clk, ""),
 };
 
 static struct pll_config_regs gpll0_regs __initdata = {
@@ -5142,10 +5299,26 @@
 };
 
 #define PLL_AUX_OUTPUT_BIT 1
+#define PLL_AUX2_OUTPUT_BIT 2
+
+#define PWR_ON_MASK		BIT(31)
+#define EN_REST_WAIT_MASK	(0xF << 20)
+#define EN_FEW_WAIT_MASK	(0xF << 16)
+#define CLK_DIS_WAIT_MASK	(0xF << 12)
+#define SW_OVERRIDE_MASK	BIT(2)
+#define HW_CONTROL_MASK		BIT(1)
+#define SW_COLLAPSE_MASK	BIT(0)
+
+/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
+#define EN_REST_WAIT_VAL	(0x2 << 20)
+#define EN_FEW_WAIT_VAL		(0x2 << 16)
+#define CLK_DIS_WAIT_VAL	(0x2 << 12)
+#define GDSC_TIMEOUT_US		50000
 
 static void __init reg_init(void)
 {
-	u32 regval;
+	u32 regval, status;
+	int ret;
 
 	if (!(readl_relaxed(GCC_REG_BASE(GPLL0_STATUS_REG))
 			& gpll0_clk_src.status_mask))
@@ -5160,9 +5333,9 @@
 	configure_pll(&mmpll3_config, &mmpll3_regs, 0);
 	configure_pll(&lpapll0_config, &lpapll0_regs, 1);
 
-	/* Active GPLL0's aux output. This is needed by acpuclock. */
+	/* Enable GPLL0's aux outputs. */
 	regval = readl_relaxed(GCC_REG_BASE(GPLL0_USER_CTL_REG));
-	regval |= BIT(PLL_AUX_OUTPUT_BIT);
+	regval |= BIT(PLL_AUX_OUTPUT_BIT) | BIT(PLL_AUX2_OUTPUT_BIT);
 	writel_relaxed(regval, GCC_REG_BASE(GPLL0_USER_CTL_REG));
 
 	/* Vote for GPLL0 to turn on. Needed by acpuclock. */
@@ -5175,6 +5348,31 @@
 	 * register.
 	 */
 	writel_relaxed(0x0, GCC_REG_BASE(APCS_CLOCK_SLEEP_ENA_VOTE));
+
+	/*
+	 * TODO: The following sequence enables the LPASS audio core GDSC.
+	 * Remove when this becomes unnecessary.
+	 */
+
+	/*
+	 * Disable HW trigger: collapse/restore occur based on registers writes.
+	 * Disable SW override: Use hardware state-machine for sequencing.
+	 */
+	regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
+	regval &= ~(HW_CONTROL_MASK | SW_OVERRIDE_MASK);
+
+	/* Configure wait time between states. */
+	regval &= ~(EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK);
+	regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
+	writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
+
+	regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
+	regval &= ~BIT(0);
+	writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
+
+	ret = readl_poll_timeout(LPASS_REG_BASE(AUDIO_CORE_GDSCR), status,
+				status & PWR_ON_MASK, 50, GDSC_TIMEOUT_US);
+	WARN(ret, "LPASS Audio Core GDSC did not power on.\n");
 }
 
 static void __init msm8974_clock_post_init(void)
@@ -5195,6 +5393,11 @@
 	 */
 	clk_prepare_enable(&cxo_a_clk_src.c);
 
+	/* TODO: Temporarily enable a clock to allow access to LPASS core
+	 * registers.
+	 */
+	clk_prepare_enable(&audio_core_ixfabric_clk.c);
+
 	/*
 	 * TODO: Temporarily enable NOC configuration AHB clocks. Remove when
 	 * the bus driver is ready.
@@ -5231,17 +5434,38 @@
 			audio_core_slimbus_core_clk_src.freq_tbl[0].freq_hz);
 }
 
-#define GCC_CC_PHYS	0xFC400000
-#define GCC_CC_SIZE	SZ_16K
+#define GCC_CC_PHYS		0xFC400000
+#define GCC_CC_SIZE		SZ_16K
 
-#define MMSS_CC_PHYS	0xFD8C0000
-#define MMSS_CC_SIZE	SZ_256K
+#define MMSS_CC_PHYS		0xFD8C0000
+#define MMSS_CC_SIZE		SZ_256K
 
-#define LPASS_CC_PHYS	0xFE000000
-#define LPASS_CC_SIZE	SZ_256K
+#define LPASS_CC_PHYS		0xFE000000
+#define LPASS_CC_SIZE		SZ_256K
 
-#define MSS_CC_PHYS	0xFC980000
-#define MSS_CC_SIZE	SZ_16K
+#define MSS_CC_PHYS		0xFC980000
+#define MSS_CC_SIZE		SZ_16K
+
+#define APCS_GCC_CC_PHYS	0xF9011000
+#define APCS_GCC_CC_SIZE	SZ_4K
+
+static void __init enable_rpm_scaling(void)
+{
+	int rc, value = 0x1;
+	struct msm_rpm_kvp kvp = {
+		.key = RPM_SMD_KEY_ENABLE,
+		.data = (void *)&value,
+		.length = sizeof(value),
+	};
+
+	rc = msm_rpm_send_message_noirq(MSM_RPM_CTX_SLEEP_SET,
+			RPM_MISC_CLK_TYPE, RPM_SCALING_ENABLE_ID, &kvp, 1);
+	WARN(rc < 0, "RPM clock scaling (sleep set) did not enable!\n");
+
+	rc = msm_rpm_send_message_noirq(MSM_RPM_CTX_ACTIVE_SET,
+			RPM_MISC_CLK_TYPE, RPM_SCALING_ENABLE_ID, &kvp, 1);
+	WARN(rc < 0, "RPM clock scaling (active set) did not enable!\n");
+}
 
 static void __init msm8974_clock_pre_init(void)
 {
@@ -5261,11 +5485,15 @@
 	if (!virt_bases[MSS_BASE])
 		panic("clock-8974: Unable to ioremap MSS_CC memory!");
 
+	virt_bases[APCS_BASE] = ioremap(APCS_GCC_CC_PHYS, APCS_GCC_CC_SIZE);
+	if (!virt_bases[APCS_BASE])
+		panic("clock-8974: Unable to ioremap APCS_GCC_CC memory!");
+
 	clk_ops_local_pll.enable = msm8974_pll_clk_enable;
 
 	vdd_dig_reg = rpm_regulator_get(NULL, "vdd_dig");
 	if (IS_ERR(vdd_dig_reg))
-		panic("clock-copper: Unable to get the vdd_dig regulator!");
+		panic("clock-8974: Unable to get the vdd_dig regulator!");
 
 	/*
 	 * TODO: Set a voltage and enable vdd_dig, leaving the voltage high
@@ -5276,6 +5504,8 @@
 	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
 	rpm_regulator_enable(vdd_dig_reg);
 
+	enable_rpm_scaling();
+
 	reg_init();
 }
 
@@ -5284,6 +5514,32 @@
 	return unvote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
 }
 
+static void __init msm8974_rumi_clock_pre_init(void)
+{
+	virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
+	if (!virt_bases[GCC_BASE])
+		panic("clock-8974: Unable to ioremap GCC memory!");
+
+	/* SDCC clocks are partially emulated in the RUMI */
+	sdcc1_apps_clk_src.freq_tbl = ftbl_gcc_sdcc_apps_rumi_clk;
+	sdcc2_apps_clk_src.freq_tbl = ftbl_gcc_sdcc_apps_rumi_clk;
+	sdcc3_apps_clk_src.freq_tbl = ftbl_gcc_sdcc_apps_rumi_clk;
+	sdcc4_apps_clk_src.freq_tbl = ftbl_gcc_sdcc_apps_rumi_clk;
+
+	vdd_dig_reg = rpm_regulator_get(NULL, "vdd_dig");
+	if (IS_ERR(vdd_dig_reg))
+		panic("clock-8974: Unable to get the vdd_dig regulator!");
+
+	/*
+	 * TODO: Set a voltage and enable vdd_dig, leaving the voltage high
+	 * until late_init. This may not be necessary with clock handoff;
+	 * Investigate this code on a real non-simulator target to determine
+	 * its necessity.
+	 */
+	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
+	rpm_regulator_enable(vdd_dig_reg);
+}
+
 struct clock_init_data msm8974_clock_init_data __initdata = {
 	.table = msm_clocks_8974,
 	.size = ARRAY_SIZE(msm_clocks_8974),
@@ -5291,3 +5547,9 @@
 	.post_init = msm8974_clock_post_init,
 	.late_init = msm8974_clock_late_init,
 };
+
+struct clock_init_data msm8974_rumi_clock_init_data __initdata = {
+	.table = msm_clocks_8974_rumi,
+	.size = ARRAY_SIZE(msm_clocks_8974_rumi),
+	.pre_init = msm8974_rumi_clock_pre_init,
+};
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 1769f07..bc57c3b 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -3486,6 +3486,7 @@
 	CLK_LOOKUP("xo",		cxo_a_clk.c,	""),
 	CLK_LOOKUP("xo",		pxo_a_clk.c,	""),
 	CLK_LOOKUP("xo",		pxo_clk.c,	"pil_modem"),
+	CLK_LOOKUP("vref_buff",		cxo_clk.c,	"rpm-regulator"),
 	CLK_LOOKUP("pll4",		pll4_clk.c,	"pil_qdsp6v3"),
 	CLK_LOOKUP("measure",		measure_clk.c,	"debug"),
 
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 3c9bd36..494823b 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -1619,6 +1619,7 @@
 	CLK_LOOKUP("xo",	cxo_a_clk.c,	""),
 	CLK_LOOKUP("xo",	cxo_clk.c,	"BAM_RMNT"),
 	CLK_LOOKUP("xo",	cxo_clk.c,	"msm_xo"),
+	CLK_LOOKUP("vref_buff",	cxo_clk.c,	"rpm-regulator"),
 	CLK_LOOKUP("pll0",	pll0_clk.c,	NULL),
 	CLK_LOOKUP("pll8",	pll8_clk.c,	NULL),
 	CLK_LOOKUP("pll14",	pll14_clk.c,	NULL),
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index 7263512..807d587 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -35,7 +35,8 @@
 		clk_set_max_rate(clock, val);
 	ret = clk_set_rate(clock, val);
 	if (ret)
-		pr_err("clk_set_rate failed (%d)\n", ret);
+		pr_err("clk_set_rate(%s, %lu) failed (%d)\n", clock->dbg_name,
+				(unsigned long)val, ret);
 
 	return ret;
 }
@@ -58,7 +59,7 @@
 	int ret, is_hw_gated;
 
 	/* Check to see if the clock is in hardware gating mode */
-	if (clock->flags & CLKFLAG_HWCG)
+	if (clock->ops->in_hwcg_mode)
 		is_hw_gated = clock->ops->in_hwcg_mode(clock);
 	else
 		is_hw_gated = 0;
@@ -134,7 +135,10 @@
 static int clock_debug_hwcg_get(void *data, u64 *val)
 {
 	struct clk *clock = data;
-	*val = !!(clock->flags & CLKFLAG_HWCG);
+	if (clock->ops->in_hwcg_mode)
+		*val = !!clock->ops->in_hwcg_mode(clock);
+	else
+		*val = 0;
 	return 0;
 }
 
@@ -246,6 +250,40 @@
 	.release	= seq_release,
 };
 
+static int fmax_rates_show(struct seq_file *m, void *unused)
+{
+	struct clk *clock = m->private;
+	int level = 0;
+
+	int vdd_level = find_vdd_level(clock, clock->rate);
+	if (vdd_level < 0) {
+		seq_printf(m, "could not find_vdd_level for %s, %ld\n",
+			clock->dbg_name, clock->rate);
+		return 0;
+	}
+	for (level = 0; level < ARRAY_SIZE(clock->fmax); level++) {
+		if (vdd_level == level)
+			seq_printf(m, "[%lu] ", clock->fmax[level]);
+		else
+			seq_printf(m, "%lu ", clock->fmax[level]);
+	}
+	seq_printf(m, "\n");
+
+	return 0;
+}
+
+static int fmax_rates_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, fmax_rates_show, inode->i_private);
+}
+
+static const struct file_operations fmax_rates_fops = {
+	.open		= fmax_rates_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
 int __init clock_debug_add(struct clk *clock)
 {
 	char temp[50], *ptr;
@@ -289,6 +327,11 @@
 				S_IRUGO, clk_dir, clock, &list_rates_fops))
 			goto error;
 
+	if (clock->vdd_class && !debugfs_create_file("fmax_rates",
+				S_IRUGO, clk_dir, clock, &fmax_rates_fops))
+			goto error;
+
+
 	return 0;
 error:
 	debugfs_remove_recursive(clk_dir);
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index 51e5703d..2df1cd1 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -563,11 +563,8 @@
 {
 	if (!branch_in_hwcg_mode(b)) {
 		b->hwcg_mask = 0;
-		c->flags &= ~CLKFLAG_HWCG;
 		if (b->ctl_reg && readl_relaxed(b->ctl_reg) & b->en_mask)
 			return HANDOFF_ENABLED_CLK;
-	} else {
-		c->flags |= CLKFLAG_HWCG;
 	}
 	return HANDOFF_DISABLED_CLK;
 }
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 23b4723..d5ee35b 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -305,6 +305,11 @@
 	return _rcg_clk_handoff(to_rcg_clk(c), 0);
 }
 
+#define BRANCH_CHECK_MASK	BM(31, 28)
+#define BRANCH_ON_VAL		BVAL(31, 28, 0x0)
+#define BRANCH_OFF_VAL		BVAL(31, 28, 0x8)
+#define BRANCH_NOC_FSM_ON_VAL	BVAL(31, 28, 0x2)
+
 /*
  * Branch clock functions
  */
@@ -326,15 +331,22 @@
 		udelay(HALT_CHECK_DELAY_US);
 	} else if (halt_check == HALT) {
 		int count;
+		u32 val;
 		for (count = HALT_CHECK_MAX_LOOPS; count > 0; count--) {
-			if (br_status == BRANCH_ON
-				&& !(readl_relaxed(cbcr_reg)
-						& CBCR_BRANCH_OFF_BIT))
-				return;
-			if (br_status == BRANCH_OFF
-				&& (readl_relaxed(cbcr_reg)
-						& CBCR_BRANCH_OFF_BIT))
-				return;
+			val = readl_relaxed(cbcr_reg);
+			val &= BRANCH_CHECK_MASK;
+			switch (br_status) {
+			case BRANCH_ON:
+				if (val == BRANCH_ON_VAL
+					|| val == BRANCH_NOC_FSM_ON_VAL)
+					return;
+				break;
+
+			case BRANCH_OFF:
+				if (val == BRANCH_OFF_VAL)
+					return;
+				break;
+			};
 			udelay(1);
 		}
 		WARN(count == 0, "%s status stuck %s", clk_name, status_str);
@@ -568,6 +580,8 @@
 	return HANDOFF_ENABLED_CLK;
 }
 
+struct clk_ops clk_ops_empty;
+
 struct clk_ops clk_ops_rcg = {
 	.enable = rcg_clk_enable,
 	.set_rate = rcg_clk_set_rate,
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index 1de79d7..572cec6f 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -169,10 +169,21 @@
  */
 extern spinlock_t local_clock_reg_lock;
 
+extern struct clk_ops clk_ops_empty;
 extern struct clk_ops clk_ops_rcg;
 extern struct clk_ops clk_ops_rcg_mnd;
 extern struct clk_ops clk_ops_branch;
 extern struct clk_ops clk_ops_vote;
 
+/*
+ * Clock definition macros
+ */
+#define DEFINE_CLK_MEASURE(name) \
+	struct clk name = { \
+		.ops = &clk_ops_empty, \
+		.dbg_name = #name, \
+		CLK_INIT(name), \
+	}; \
+
 #endif /* __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_2_H */
 
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index 207dbef..be69827 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -54,6 +54,23 @@
 	return (rc < 0) ? rc : iv.value * r->factor;
 }
 
+static int clk_rpmrs_handoff(struct rpm_clk *r)
+{
+	struct msm_rpm_iv_pair iv = { .id = r->rpm_status_id, };
+	int rc = msm_rpm_get_status(&iv, 1);
+
+	if (rc < 0)
+		return rc;
+
+	if (!r->branch) {
+		r->last_set_khz = iv.value;
+		r->last_set_sleep_khz = iv.value;
+		r->c.rate = iv.value * r->factor;
+	}
+
+	return 0;
+}
+
 static int clk_rpmrs_set_rate_smd(struct rpm_clk *r, uint32_t value,
 				uint32_t context, int noirq)
 {
@@ -71,10 +88,16 @@
 						r->rpm_clk_id, &kvp, 1);
 }
 
+static int clk_rpmrs_handoff_smd(struct rpm_clk *r)
+{
+	return 0;
+}
+
 struct clk_rpmrs_data {
 	int (*set_rate_fn)(struct rpm_clk *r, uint32_t value,
 				uint32_t context, int noirq);
 	int (*get_rate_fn)(struct rpm_clk *r);
+	int (*handoff_fn)(struct rpm_clk *r);
 	int ctx_active_id;
 	int ctx_sleep_id;
 };
@@ -82,12 +105,14 @@
 struct clk_rpmrs_data clk_rpmrs_data = {
 	.set_rate_fn = clk_rpmrs_set_rate,
 	.get_rate_fn = clk_rpmrs_get_rate,
+	.handoff_fn = clk_rpmrs_handoff,
 	.ctx_active_id = MSM_RPM_CTX_SET_0,
 	.ctx_sleep_id = MSM_RPM_CTX_SET_SLEEP,
 };
 
 struct clk_rpmrs_data clk_rpmrs_data_smd = {
 	.set_rate_fn = clk_rpmrs_set_rate_smd,
+	.handoff_fn = clk_rpmrs_handoff_smd,
 	.ctx_active_id = MSM_RPM_CTX_ACTIVE_SET,
 	.ctx_sleep_id = MSM_RPM_CTX_SLEEP_SET,
 };
@@ -257,7 +282,6 @@
 static enum handoff rpm_clk_handoff(struct clk *clk)
 {
 	struct rpm_clk *r = to_rpm_clk(clk);
-	struct msm_rpm_iv_pair iv = { r->rpm_status_id };
 	int rc;
 
 	/*
@@ -266,16 +290,10 @@
 	 * assume these clocks are enabled (unless the RPM call fails) so
 	 * child clocks of these RPM clocks can still be handed off.
 	 */
-	rc  = msm_rpm_get_status(&iv, 1);
+	rc  = r->rpmrs_data->handoff_fn(r);
 	if (rc < 0)
 		return HANDOFF_DISABLED_CLK;
 
-	if (!r->branch) {
-		r->last_set_khz = iv.value;
-		r->last_set_sleep_khz = iv.value;
-		clk->rate = iv.value * r->factor;
-	}
-
 	return HANDOFF_ENABLED_CLK;
 }
 
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index da8c3a9..f605c1f 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -33,7 +33,7 @@
 static LIST_HEAD(handoff_list);
 
 /* Find the voltage level required for a given rate. */
-static int find_vdd_level(struct clk *clk, unsigned long rate)
+int find_vdd_level(struct clk *clk, unsigned long rate)
 {
 	int level;
 
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index df2aa4e..d88466d 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -29,7 +29,6 @@
 #define CLKFLAG_NOINVERT		0x00000002
 #define CLKFLAG_NONEST			0x00000004
 #define CLKFLAG_NORESET			0x00000008
-#define CLKFLAG_HWCG			0x00000020
 #define CLKFLAG_RETAIN			0x00000040
 #define CLKFLAG_NORETAIN		0x00000080
 #define CLKFLAG_SKIP_HANDOFF		0x00000100
@@ -171,10 +170,12 @@
 extern struct clock_init_data msm8625_dummy_clock_init_data;
 extern struct clock_init_data msm8930_clock_init_data;
 extern struct clock_init_data msm8974_clock_init_data;
+extern struct clock_init_data msm8974_rumi_clock_init_data;
 
 void msm_clock_init(struct clock_init_data *data);
 int vote_vdd_level(struct clk_vdd_class *vdd_class, int level);
 int unvote_vdd_level(struct clk_vdd_class *vdd_class, int level);
+int find_vdd_level(struct clk *clk, unsigned long rate);
 
 #ifdef CONFIG_DEBUG_FS
 int clock_debug_init(struct clock_init_data *data);
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index e4ec4d4..de97186 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -68,29 +68,6 @@
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
 };
 
-
-#ifdef CONFIG_MSM_SLEEP_STATS
-static DEFINE_PER_CPU(struct atomic_notifier_head, msm_cpuidle_notifiers);
-
-int msm_cpuidle_register_notifier(unsigned int cpu, struct notifier_block *nb)
-{
-	struct atomic_notifier_head *head =
-		&per_cpu(msm_cpuidle_notifiers, cpu);
-
-	return atomic_notifier_chain_register(head, nb);
-}
-EXPORT_SYMBOL(msm_cpuidle_register_notifier);
-
-int msm_cpuidle_unregister_notifier(unsigned int cpu, struct notifier_block *nb)
-{
-	struct atomic_notifier_head *head =
-		&per_cpu(msm_cpuidle_notifiers, cpu);
-
-	return atomic_notifier_chain_unregister(head, nb);
-}
-EXPORT_SYMBOL(msm_cpuidle_unregister_notifier);
-#endif
-
 static int msm_cpuidle_enter(
 	struct cpuidle_device *dev, struct cpuidle_driver *drv, int index)
 {
@@ -98,17 +75,9 @@
 	int i = 0;
 	enum msm_pm_sleep_mode pm_mode;
 	struct cpuidle_state_usage *st_usage = NULL;
-#ifdef CONFIG_MSM_SLEEP_STATS
-	struct atomic_notifier_head *head =
-			&__get_cpu_var(msm_cpuidle_notifiers);
-#endif
 
 	local_irq_disable();
 
-#ifdef CONFIG_MSM_SLEEP_STATS
-	atomic_notifier_call_chain(head, MSM_CPUIDLE_STATE_ENTER, NULL);
-#endif
-
 #ifdef CONFIG_CPU_PM
 	cpu_pm_enter();
 #endif
@@ -128,10 +97,6 @@
 	cpu_pm_exit();
 #endif
 
-#ifdef CONFIG_MSM_SLEEP_STATS
-	atomic_notifier_call_chain(head, MSM_CPUIDLE_STATE_EXIT, NULL);
-#endif
-
 	local_irq_enable();
 
 	return ret;
@@ -219,16 +184,3 @@
 
 	return 0;
 }
-
-static int __init msm_cpuidle_early_init(void)
-{
-#ifdef CONFIG_MSM_SLEEP_STATS
-	unsigned int cpu;
-
-	for_each_possible_cpu(cpu)
-		ATOMIC_INIT_NOTIFIER_HEAD(&per_cpu(msm_cpuidle_notifiers, cpu));
-#endif
-	return 0;
-}
-
-early_initcall(msm_cpuidle_early_init);
diff --git a/arch/arm/mach-msm/dal_axi.c b/arch/arm/mach-msm/dal_axi.c
index 739b7dc..1d873ca 100644
--- a/arch/arm/mach-msm/dal_axi.c
+++ b/arch/arm/mach-msm/dal_axi.c
@@ -17,6 +17,8 @@
 #define DALRPC_PORT_NAME  "DAL00"
 
 enum {
+	DALRPC_AXI_ALLOCATE = DALDEVICE_FIRST_DEVICE_API_IDX + 1,
+	DALRPC_AXI_FREE = DALDEVICE_FIRST_DEVICE_API_IDX + 2,
 	DALRPC_AXI_CONFIGURE_BRIDGE = DALDEVICE_FIRST_DEVICE_API_IDX + 11
 };
 
@@ -38,6 +40,67 @@
 
 };
 
+static void *cam_dev_handle;
+static int __axi_free(int mode)
+{
+	int rc = 0;
+
+	if (!cam_dev_handle)
+		return rc;
+
+	rc = dalrpc_fcn_0(DALRPC_AXI_FREE, cam_dev_handle, mode);
+	if (rc) {
+		printk(KERN_ERR "%s: AXI bus device (%d) failed to be configured\n",
+			__func__, rc);
+		goto fail_dal_fcn_0;
+	}
+
+	/* close device handle */
+	rc = daldevice_detach(cam_dev_handle);
+	if (rc) {
+		printk(KERN_ERR "%s: failed to detach AXI bus device (%d)\n",
+			__func__, rc);
+		goto fail_dal_attach_detach;
+	}
+	cam_dev_handle = NULL;
+	return 0;
+
+fail_dal_fcn_0:
+	(void)daldevice_detach(cam_dev_handle);
+	cam_dev_handle = NULL;
+fail_dal_attach_detach:
+	return rc;
+}
+
+static int __axi_allocate(int mode)
+{
+	int rc;
+
+	/* get device handle */
+	rc = daldevice_attach(DALDEVICEID_AXI, DALRPC_PORT_NAME,
+				DALRPC_DEST_MODEM, &cam_dev_handle);
+	if (rc) {
+		printk(KERN_ERR "%s: failed to attach AXI bus device (%d)\n",
+			__func__, rc);
+		goto fail_dal_attach_detach;
+	}
+
+	rc = dalrpc_fcn_0(DALRPC_AXI_ALLOCATE, cam_dev_handle, mode);
+	if (rc) {
+		printk(KERN_ERR "%s: AXI bus device (%d) failed to be configured\n",
+			__func__, rc);
+		goto fail_dal_fcn_0;
+	}
+
+	return 0;
+
+fail_dal_fcn_0:
+	(void)daldevice_detach(cam_dev_handle);
+	cam_dev_handle = NULL;
+fail_dal_attach_detach:
+	return rc;
+}
+
 static int axi_configure_bridge_grfx_sync_mode(int bridge_mode)
 {
 	int rc;
@@ -82,7 +145,15 @@
 	return rc;
 }
 
+int axi_free(mode)
+{
+	return __axi_free(mode);
+}
 
+int axi_allocate(mode)
+{
+	return __axi_allocate(mode);
+}
 
 int set_grp2d_async(void)
 {
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index b756307..fbd53d0 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -29,6 +29,7 @@
 #include <sound/msm-dai-q6.h>
 #include <sound/apr_audio.h>
 #include <mach/msm_tsif.h>
+#include <mach/msm_tspp.h>
 #include <mach/msm_bus_board.h>
 #include <mach/rpm.h>
 #include <mach/mdm2.h>
@@ -106,6 +107,15 @@
 	.bark_time = 11000,
 	.has_secure = true,
 	.needs_expired_enable = true,
+	.base = MSM_TMR0_BASE + WDT0_OFFSET,
+};
+
+static struct resource msm_watchdog_resources[] = {
+	{
+		.start	= WDT0_ACCSCSSNBARK_INT,
+		.end	= WDT0_ACCSCSSNBARK_INT,
+		.flags	= IORESOURCE_IRQ,
+	},
 };
 
 struct platform_device msm8064_device_watchdog = {
@@ -114,6 +124,8 @@
 	.dev = {
 		.platform_data = &msm_watchdog_pdata,
 	},
+	.num_resources	= ARRAY_SIZE(msm_watchdog_resources),
+	.resource	= msm_watchdog_resources,
 };
 
 static struct resource msm_dmov_resource[] = {
@@ -603,6 +615,67 @@
 	}
 };
 
+#define MSM_TSPP_PHYS			(0x18202000)
+#define MSM_TSPP_SIZE			(0x1000)
+#define MSM_TSPP_BAM_PHYS		(0x18204000)
+#define MSM_TSPP_BAM_SIZE		(0x2000)
+
+static const struct msm_gpio tspp_gpios[] = {
+	{ .gpio_cfg = TSIF_0_CLK,  .label =  "tsif_clk", },
+	{ .gpio_cfg = TSIF_0_EN,   .label =  "tsif_en", },
+	{ .gpio_cfg = TSIF_0_DATA, .label =  "tsif_data", },
+	{ .gpio_cfg = TSIF_0_SYNC, .label =  "tsif_sync", },
+	{ .gpio_cfg = TSIF_1_CLK,  .label =  "tsif_clk", },
+	{ .gpio_cfg = TSIF_1_EN,   .label =  "tsif_en", },
+	{ .gpio_cfg = TSIF_1_DATA, .label =  "tsif_data", },
+	{ .gpio_cfg = TSIF_1_SYNC, .label =  "tsif_sync", },
+};
+
+static struct resource tspp_resources[] = {
+	[0] = {
+		.flags = IORESOURCE_IRQ,
+		.start = TSIF_TSPP_IRQ,
+		.end   = TSIF1_IRQ,
+	},
+	[1] = {
+		.flags = IORESOURCE_MEM,
+		.start = MSM_TSIF0_PHYS,
+		.end   = MSM_TSIF0_PHYS + MSM_TSIF_SIZE - 1,
+	},
+	[2] = {
+		.flags = IORESOURCE_MEM,
+		.start = MSM_TSIF1_PHYS,
+		.end   = MSM_TSIF1_PHYS + MSM_TSIF_SIZE - 1,
+	},
+	[3] = {
+		.flags = IORESOURCE_MEM,
+		.start = MSM_TSPP_PHYS,
+		.end   = MSM_TSPP_PHYS + MSM_TSPP_SIZE - 1,
+	},
+	[4] = {
+		.flags = IORESOURCE_MEM,
+		.start = MSM_TSPP_BAM_PHYS,
+		.end   = MSM_TSPP_BAM_PHYS + MSM_TSPP_BAM_SIZE - 1,
+	},
+};
+
+static struct msm_tspp_platform_data tspp_platform_data = {
+	.num_gpios = ARRAY_SIZE(tspp_gpios),
+	.gpios = tspp_gpios,
+	.tsif_pclk = "iface_clk",
+	.tsif_ref_clk = "ref_clk",
+};
+
+struct platform_device msm_8064_device_tspp = {
+	.name          = "msm_tspp",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(tspp_resources),
+	.resource      = tspp_resources,
+	.dev = {
+		.platform_data = &tspp_platform_data
+	},
+};
+
 /*
  * Machine specific data for AUX PCM Interface
  * which the driver will  be unware of.
@@ -694,6 +767,11 @@
 	.id     = -1,
 };
 
+struct platform_device apq_lowlatency_pcm = {
+	.name   = "msm-lowlatency-pcm-dsp",
+	.id     = -1,
+};
+
 struct platform_device apq_pcm_hostless = {
 	.name	= "msm-pcm-hostless",
 	.id	= -1,
@@ -1368,19 +1446,19 @@
 	},
 #ifdef CONFIG_MMC_MSM_SPS_SUPPORT
 	{
-		.name   = "sdcc_dml_addr",
+		.name   = "dml_mem",
 		.start	= MSM_SDC1_DML_BASE,
 		.end	= MSM_SDC1_BAM_BASE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_addr",
+		.name   = "bam_mem",
 		.start	= MSM_SDC1_BAM_BASE,
 		.end	= MSM_SDC1_BAM_BASE + (2 * SZ_4K) - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_irq",
+		.name   = "bam_irq",
 		.start	= SDC1_BAM_IRQ,
 		.end	= SDC1_BAM_IRQ,
 		.flags	= IORESOURCE_IRQ,
@@ -1403,19 +1481,19 @@
 	},
 #ifdef CONFIG_MMC_MSM_SPS_SUPPORT
 	{
-		.name   = "sdcc_dml_addr",
+		.name   = "dml_mem",
 		.start	= MSM_SDC2_DML_BASE,
 		.end	= MSM_SDC2_BAM_BASE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_addr",
+		.name   = "bam_mem",
 		.start	= MSM_SDC2_BAM_BASE,
 		.end	= MSM_SDC2_BAM_BASE + (2 * SZ_4K) - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_irq",
+		.name   = "bam_irq",
 		.start	= SDC2_BAM_IRQ,
 		.end	= SDC2_BAM_IRQ,
 		.flags	= IORESOURCE_IRQ,
@@ -1438,19 +1516,19 @@
 	},
 #ifdef CONFIG_MMC_MSM_SPS_SUPPORT
 	{
-		.name   = "sdcc_dml_addr",
+		.name   = "dml_mem",
 		.start	= MSM_SDC3_DML_BASE,
 		.end	= MSM_SDC3_BAM_BASE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_addr",
+		.name   = "bam_mem",
 		.start	= MSM_SDC3_BAM_BASE,
 		.end	= MSM_SDC3_BAM_BASE + (2 * SZ_4K) - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_irq",
+		.name   = "bam_irq",
 		.start	= SDC3_BAM_IRQ,
 		.end	= SDC3_BAM_IRQ,
 		.flags	= IORESOURCE_IRQ,
@@ -1473,19 +1551,19 @@
 	},
 #ifdef CONFIG_MMC_MSM_SPS_SUPPORT
 	{
-		.name   = "sdcc_dml_addr",
+		.name   = "dml_mem",
 		.start	= MSM_SDC4_DML_BASE,
 		.end	= MSM_SDC4_BAM_BASE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_addr",
+		.name   = "bam_mem",
 		.start	= MSM_SDC4_BAM_BASE,
 		.end	= MSM_SDC4_BAM_BASE + (2 * SZ_4K) - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_irq",
+		.name   = "bam_irq",
 		.start	= SDC4_BAM_IRQ,
 		.end	= SDC4_BAM_IRQ,
 		.flags	= IORESOURCE_IRQ,
@@ -1868,6 +1946,8 @@
 		{ .name = "lut_clk" },
 		{ .name = "tv_src_clk" },
 		{ .name = "tv_clk" },
+		{ .name = "reset1_clk" },
+		{ .name = "reset2_clk" },
 		{ 0 }
 	},
 	.bus_port0 = MSM_BUS_MASTER_MDP_PORT0,
@@ -2399,8 +2479,11 @@
 #define MDM2AP_STATUS			49
 #define AP2MDM_STATUS			48
 #define AP2MDM_SOFT_RESET		27
+#define I2S_AP2MDM_SOFT_RESET		0
 #define AP2MDM_WAKEUP			35
+#define I2S_AP2MDM_WAKEUP		44
 #define MDM2AP_PBLRDY			46
+#define I2S_MDM2AP_PBLRDY		81
 
 static struct resource mdm_resources[] = {
 	{
@@ -2447,6 +2530,51 @@
 	},
 };
 
+static struct resource i2s_mdm_resources[] = {
+	{
+		.start	= MDM2AP_ERRFATAL,
+		.end	= MDM2AP_ERRFATAL,
+		.name	= "MDM2AP_ERRFATAL",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_ERRFATAL,
+		.end	= AP2MDM_ERRFATAL,
+		.name	= "AP2MDM_ERRFATAL",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= MDM2AP_STATUS,
+		.end	= MDM2AP_STATUS,
+		.name	= "MDM2AP_STATUS",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= AP2MDM_STATUS,
+		.end	= AP2MDM_STATUS,
+		.name	= "AP2MDM_STATUS",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= I2S_AP2MDM_SOFT_RESET,
+		.end	= I2S_AP2MDM_SOFT_RESET,
+		.name	= "AP2MDM_SOFT_RESET",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= I2S_AP2MDM_WAKEUP,
+		.end	= I2S_AP2MDM_WAKEUP,
+		.name	= "AP2MDM_WAKEUP",
+		.flags	= IORESOURCE_IO,
+	},
+	{
+		.start	= I2S_MDM2AP_PBLRDY,
+		.end	= I2S_MDM2AP_PBLRDY,
+		.name	= "MDM2AP_PBLRDY",
+		.flags	= IORESOURCE_IO,
+	},
+};
+
 struct platform_device mdm_8064_device = {
 	.name		= "mdm2_modem",
 	.id		= -1,
@@ -2454,6 +2582,12 @@
 	.resource	= mdm_resources,
 };
 
+struct platform_device i2s_mdm_8064_device = {
+	.name		= "mdm2_modem",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(i2s_mdm_resources),
+	.resource	= i2s_mdm_resources,
+};
 static int apq8064_LPM_latency = 1000; /* >100 usec for WFI */
 
 struct platform_device apq8064_cpu_idle_device = {
@@ -2642,43 +2776,105 @@
 	.resource	= msm_cache_erp_resources,
 };
 
-#define MSM_QDSS_PHYS_BASE		0x01A00000
-#define MSM_ETM_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x1C000)
+#define CORESIGHT_PHYS_BASE		0x01A00000
+#define CORESIGHT_FUNNEL_PHYS_BASE	(CORESIGHT_PHYS_BASE + 0x4000)
+#define CORESIGHT_ETM2_PHYS_BASE	(CORESIGHT_PHYS_BASE + 0x1E000)
+#define CORESIGHT_ETM3_PHYS_BASE	(CORESIGHT_PHYS_BASE + 0x1F000)
 
-#define QDSS_SOURCE(src_name, fpm) { .name = src_name, .fport_mask = fpm, }
-
-static struct qdss_source msm_qdss_sources[] = {
-	QDSS_SOURCE("msm_etm", 0x33),
-	QDSS_SOURCE("msm_oxili", 0x80),
-};
-
-static struct msm_qdss_platform_data qdss_pdata = {
-	.src_table = msm_qdss_sources,
-	.size = ARRAY_SIZE(msm_qdss_sources),
-	.afamily = 1,
-};
-
-struct platform_device apq8064_qdss_device = {
-	.name          = "msm_qdss",
-	.id            = -1,
-	.dev           = {
-		.platform_data = &qdss_pdata,
-	},
-};
-
-static struct resource msm_etm_resources[] = {
+static struct resource coresight_funnel_resources[] = {
 	{
-		.start = MSM_ETM_PHYS_BASE,
-		.end   = MSM_ETM_PHYS_BASE + (SZ_4K * 4) - 1,
+		.start = CORESIGHT_FUNNEL_PHYS_BASE,
+		.end   = CORESIGHT_FUNNEL_PHYS_BASE + SZ_4K - 1,
 		.flags = IORESOURCE_MEM,
 	},
 };
 
-struct platform_device apq8064_etm_device = {
-	.name          = "msm_etm",
+static const int coresight_funnel_outports[] = { 0, 1 };
+static const int coresight_funnel_child_ids[] = { 0, 1 };
+static const int coresight_funnel_child_ports[] = { 0, 0 };
+
+static struct coresight_platform_data coresight_funnel_pdata = {
+	.id		= 2,
+	.name		= "coresight-funnel",
+	.nr_inports	= 4,
+	.outports	= coresight_funnel_outports,
+	.child_ids	= coresight_funnel_child_ids,
+	.child_ports	= coresight_funnel_child_ports,
+	.nr_outports	= ARRAY_SIZE(coresight_funnel_outports),
+};
+
+struct platform_device apq8064_coresight_funnel_device = {
+	.name          = "coresight-funnel",
 	.id            = 0,
-	.num_resources = ARRAY_SIZE(msm_etm_resources),
-	.resource      = msm_etm_resources,
+	.num_resources = ARRAY_SIZE(coresight_funnel_resources),
+	.resource      = coresight_funnel_resources,
+	.dev = {
+		.platform_data = &coresight_funnel_pdata,
+	},
+};
+
+static struct resource coresight_etm2_resources[] = {
+	{
+		.start = CORESIGHT_ETM2_PHYS_BASE,
+		.end   = CORESIGHT_ETM2_PHYS_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static const int coresight_etm2_outports[] = { 0 };
+static const int coresight_etm2_child_ids[] = { 2 };
+static const int coresight_etm2_child_ports[] = { 4 };
+
+static struct coresight_platform_data coresight_etm2_pdata = {
+	.id		= 6,
+	.name		= "coresight-etm2",
+	.nr_inports	= 1,
+	.outports	= coresight_etm2_outports,
+	.child_ids	= coresight_etm2_child_ids,
+	.child_ports	= coresight_etm2_child_ports,
+	.nr_outports	= ARRAY_SIZE(coresight_etm2_outports),
+};
+
+struct platform_device coresight_etm2_device = {
+	.name          = "coresight-etm",
+	.id            = 2,
+	.num_resources = ARRAY_SIZE(coresight_etm2_resources),
+	.resource      = coresight_etm2_resources,
+	.dev = {
+		.platform_data = &coresight_etm2_pdata,
+	},
+};
+
+static struct resource coresight_etm3_resources[] = {
+	{
+		.start = CORESIGHT_ETM3_PHYS_BASE,
+		.end   = CORESIGHT_ETM3_PHYS_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static const int coresight_etm3_outports[] = { 0 };
+static const int coresight_etm3_child_ids[] = { 2 };
+static const int coresight_etm3_child_ports[] = { 5 };
+
+static struct coresight_platform_data coresight_etm3_pdata = {
+	.id		= 7,
+	.name		= "coresight-etm3",
+	.nr_inports	= 3,
+	.outports	= coresight_etm3_outports,
+	.child_ids	= coresight_etm3_child_ids,
+	.child_ports	= coresight_etm3_child_ports,
+	.nr_outports	= ARRAY_SIZE(coresight_etm3_outports),
+};
+
+struct platform_device coresight_etm3_device = {
+	.name          = "coresight-etm",
+	.id            = 3,
+	.num_resources = ARRAY_SIZE(coresight_etm3_resources),
+	.resource      = coresight_etm3_resources,
+	.dev = {
+		.platform_data = &coresight_etm3_pdata,
+	},
 };
 
 struct msm_iommu_domain_name apq8064_iommu_ctx_names[] = {
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 7cb6e95..eac2140 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -416,7 +416,7 @@
 	.bus_port0 = MSM_BUS_MASTER_JPEG_ENC,
 };
 
-static struct fs_driver_data mdp_fs_data = {
+static struct fs_driver_data mdp_fs_data_8930 = {
 	.clks = (struct fs_clk_data[]){
 		{ .name = "core_clk" },
 		{ .name = "iface_clk" },
@@ -425,6 +425,21 @@
 		{ .name = "lut_clk" },
 		{ .name = "tv_src_clk" },
 		{ .name = "tv_clk" },
+		{ .name = "reset1_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_MDP_PORT0,
+	.bus_port1 = MSM_BUS_MASTER_MDP_PORT1,
+};
+
+static struct fs_driver_data mdp_fs_data_8627 = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk" },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ .name = "vsync_clk" },
+		{ .name = "lut_clk" },
+		{ .name = "reset1_clk" },
 		{ 0 }
 	},
 	.bus_port0 = MSM_BUS_MASTER_MDP_PORT0,
@@ -473,7 +488,7 @@
 };
 
 struct platform_device *msm8930_footswitch[] __initdata = {
-	FS_8X60(FS_MDP,    "vdd",	"mdp.0",	&mdp_fs_data),
+	FS_8X60(FS_MDP,    "vdd",	"mdp.0",	&mdp_fs_data_8930),
 	FS_8X60(FS_ROT,    "vdd",	"msm_rotator.0", &rot_fs_data),
 	FS_8X60(FS_IJPEG,  "vdd",	"msm_gemini.0", &ijpeg_fs_data),
 	FS_8X60(FS_VFE,    "vdd",	"msm_vfe.0",	&vfe_fs_data),
@@ -483,6 +498,17 @@
 };
 unsigned msm8930_num_footswitch __initdata = ARRAY_SIZE(msm8930_footswitch);
 
+struct platform_device *msm8627_footswitch[] __initdata = {
+	FS_8X60(FS_MDP,    "vdd",	"mdp.0",	&mdp_fs_data_8627),
+	FS_8X60(FS_ROT,    "vdd",	"msm_rotator.0", &rot_fs_data),
+	FS_8X60(FS_IJPEG,  "vdd",	"msm_gemini.0", &ijpeg_fs_data),
+	FS_8X60(FS_VFE,    "vdd",	"msm_vfe.0",	&vfe_fs_data),
+	FS_8X60(FS_VPE,    "vdd",	"msm_vpe.0",	&vpe_fs_data),
+	FS_8X60(FS_GFX3D,  "vdd",	"kgsl-3d0.0",	&gfx3d_fs_data),
+	FS_8X60(FS_VED,    "vdd",	"msm_vidc.0",	&ved_fs_data),
+};
+unsigned msm8627_num_footswitch __initdata = ARRAY_SIZE(msm8627_footswitch);
+
 /* MSM Video core device */
 #ifdef CONFIG_MSM_BUS_SCALING
 static struct msm_bus_vectors vidc_init_vectors[] = {
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index b1ebe33..8a4b3f4 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -207,6 +207,11 @@
 	.id		= -1,
 };
 
+struct platform_device msm8960ab_device_acpuclk = {
+	.name		= "acpuclk-8960ab",
+	.id		= -1,
+};
+
 #define SHARED_IMEM_TZ_BASE 0x2a03f720
 static struct resource tzlog_resources[] = {
 	{
@@ -819,19 +824,19 @@
 	},
 #ifdef CONFIG_MMC_MSM_SPS_SUPPORT
 	{
-		.name   = "sdcc_dml_addr",
+		.name   = "dml_mem",
 		.start	= MSM_SDC1_DML_BASE,
 		.end	= MSM_SDC1_BAM_BASE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_addr",
+		.name   = "bam_mem",
 		.start	= MSM_SDC1_BAM_BASE,
 		.end	= MSM_SDC1_BAM_BASE + (2 * SZ_4K) - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_irq",
+		.name   = "bam_irq",
 		.start	= SDC1_BAM_IRQ,
 		.end	= SDC1_BAM_IRQ,
 		.flags	= IORESOURCE_IRQ,
@@ -854,19 +859,19 @@
 	},
 #ifdef CONFIG_MMC_MSM_SPS_SUPPORT
 	{
-		.name   = "sdcc_dml_addr",
+		.name   = "dml_mem",
 		.start	= MSM_SDC2_DML_BASE,
 		.end	= MSM_SDC2_BAM_BASE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_addr",
+		.name   = "bam_mem",
 		.start	= MSM_SDC2_BAM_BASE,
 		.end	= MSM_SDC2_BAM_BASE + (2 * SZ_4K) - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_irq",
+		.name   = "bam_irq",
 		.start	= SDC2_BAM_IRQ,
 		.end	= SDC2_BAM_IRQ,
 		.flags	= IORESOURCE_IRQ,
@@ -889,19 +894,19 @@
 	},
 #ifdef CONFIG_MMC_MSM_SPS_SUPPORT
 	{
-		.name   = "sdcc_dml_addr",
+		.name   = "dml_mem",
 		.start	= MSM_SDC3_DML_BASE,
 		.end	= MSM_SDC3_BAM_BASE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_addr",
+		.name   = "bam_mem",
 		.start	= MSM_SDC3_BAM_BASE,
 		.end	= MSM_SDC3_BAM_BASE + (2 * SZ_4K) - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_irq",
+		.name   = "bam_irq",
 		.start	= SDC3_BAM_IRQ,
 		.end	= SDC3_BAM_IRQ,
 		.flags	= IORESOURCE_IRQ,
@@ -924,19 +929,19 @@
 	},
 #ifdef CONFIG_MMC_MSM_SPS_SUPPORT
 	{
-		.name   = "sdcc_dml_addr",
+		.name   = "dml_mem",
 		.start	= MSM_SDC4_DML_BASE,
 		.end	= MSM_SDC4_BAM_BASE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_addr",
+		.name   = "bam_mem",
 		.start	= MSM_SDC4_BAM_BASE,
 		.end	= MSM_SDC4_BAM_BASE + (2 * SZ_4K) - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_irq",
+		.name   = "bam_irq",
 		.start	= SDC4_BAM_IRQ,
 		.end	= SDC4_BAM_IRQ,
 		.flags	= IORESOURCE_IRQ,
@@ -959,19 +964,19 @@
 	},
 #ifdef CONFIG_MMC_MSM_SPS_SUPPORT
 	{
-		.name   = "sdcc_dml_addr",
+		.name   = "dml_mem",
 		.start	= MSM_SDC5_DML_BASE,
 		.end	= MSM_SDC5_BAM_BASE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_addr",
+		.name   = "bam_mem",
 		.start	= MSM_SDC5_BAM_BASE,
 		.end	= MSM_SDC5_BAM_BASE + (2 * SZ_4K) - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_irq",
+		.name   = "bam_irq",
 		.start	= SDC5_BAM_IRQ,
 		.end	= SDC5_BAM_IRQ,
 		.flags	= IORESOURCE_IRQ,
@@ -1331,6 +1336,15 @@
 	.pet_time = 10000,
 	.bark_time = 11000,
 	.has_secure = true,
+	.base = MSM_TMR0_BASE + WDT0_OFFSET,
+};
+
+static struct resource msm_watchdog_resources[] = {
+	{
+		.start	= WDT0_ACCSCSSNBARK_INT,
+		.end	= WDT0_ACCSCSSNBARK_INT,
+		.flags	= IORESOURCE_IRQ,
+	},
 };
 
 struct platform_device msm8960_device_watchdog = {
@@ -1339,6 +1353,8 @@
 	.dev = {
 		.platform_data = &msm_watchdog_pdata,
 	},
+	.num_resources	= ARRAY_SIZE(msm_watchdog_resources),
+	.resource	= msm_watchdog_resources,
 };
 
 static struct resource msm_dmov_resource[] = {
@@ -1938,6 +1954,11 @@
 	.id	= -1,
 };
 
+struct platform_device msm_lowlatency_pcm = {
+	.name	= "msm-lowlatency-pcm-dsp",
+	.id	= -1,
+};
+
 struct platform_device msm_pcm_routing = {
 	.name	= "msm-pcm-routing",
 	.id	= -1,
@@ -2151,6 +2172,8 @@
 		{ .name = "lut_clk" },
 		{ .name = "tv_src_clk" },
 		{ .name = "tv_clk" },
+		{ .name = "reset1_clk" },
+		{ .name = "reset2_clk" },
 		{ 0 }
 	},
 	.bus_port0 = MSM_BUS_MASTER_MDP_PORT0,
@@ -3455,95 +3478,199 @@
 
 #endif /* CONFIG_MSM_DSPS */
 
-#ifdef CONFIG_MSM_QDSS
+#define CORESIGHT_PHYS_BASE		0x01A00000
+#define CORESIGHT_TPIU_PHYS_BASE	(CORESIGHT_PHYS_BASE + 0x3000)
+#define CORESIGHT_ETB_PHYS_BASE		(CORESIGHT_PHYS_BASE + 0x1000)
+#define CORESIGHT_FUNNEL_PHYS_BASE	(CORESIGHT_PHYS_BASE + 0x4000)
+#define CORESIGHT_STM_PHYS_BASE		(CORESIGHT_PHYS_BASE + 0x6000)
+#define CORESIGHT_ETM0_PHYS_BASE	(CORESIGHT_PHYS_BASE + 0x1C000)
+#define CORESIGHT_ETM1_PHYS_BASE	(CORESIGHT_PHYS_BASE + 0x1D000)
 
-#define MSM_QDSS_PHYS_BASE		0x01A00000
-#define MSM_ETB_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x1000)
-#define MSM_TPIU_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x3000)
-#define MSM_FUNNEL_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x4000)
-#define MSM_ETM_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x1C000)
+#define CORESIGHT_STM_CHANNEL_PHYS_BASE	(0x14000000 + 0x280000)
 
-#define QDSS_SOURCE(src_name, fpm) { .name = src_name, .fport_mask = fpm, }
-
-static struct qdss_source msm_qdss_sources[] = {
-	QDSS_SOURCE("msm_etm", 0x3),
-};
-
-static struct msm_qdss_platform_data qdss_pdata = {
-	.src_table = msm_qdss_sources,
-	.size = ARRAY_SIZE(msm_qdss_sources),
-	.afamily = 1,
-};
-
-struct platform_device msm_qdss_device = {
-	.name          = "msm_qdss",
-	.id            = -1,
-	.dev           = {
-		.platform_data = &qdss_pdata,
-	},
-};
-
-static struct resource msm_etb_resources[] = {
+static struct resource coresight_tpiu_resources[] = {
 	{
-		.start = MSM_ETB_PHYS_BASE,
-		.end   = MSM_ETB_PHYS_BASE + SZ_4K - 1,
+		.start = CORESIGHT_TPIU_PHYS_BASE,
+		.end   = CORESIGHT_TPIU_PHYS_BASE + SZ_4K - 1,
 		.flags = IORESOURCE_MEM,
 	},
 };
 
-struct platform_device msm_etb_device = {
-	.name          = "msm_etb",
-	.id            = 0,
-	.num_resources = ARRAY_SIZE(msm_etb_resources),
-	.resource      = msm_etb_resources,
+static struct coresight_platform_data coresight_tpiu_pdata = {
+	.id		= 0,
+	.name		= "coresight-tpiu",
+	.nr_inports	= 1,
+	.nr_outports	= 0,
 };
 
-static struct resource msm_tpiu_resources[] = {
+struct platform_device coresight_tpiu_device = {
+	.name          = "coresight-tpiu",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(coresight_tpiu_resources),
+	.resource      = coresight_tpiu_resources,
+	.dev = {
+		.platform_data = &coresight_tpiu_pdata,
+	},
+};
+
+static struct resource coresight_etb_resources[] = {
 	{
-		.start = MSM_TPIU_PHYS_BASE,
-		.end   = MSM_TPIU_PHYS_BASE + SZ_4K - 1,
+		.start = CORESIGHT_ETB_PHYS_BASE,
+		.end   = CORESIGHT_ETB_PHYS_BASE + SZ_4K - 1,
 		.flags = IORESOURCE_MEM,
 	},
 };
 
-struct platform_device msm_tpiu_device = {
-	.name          = "msm_tpiu",
-	.id            = 0,
-	.num_resources = ARRAY_SIZE(msm_tpiu_resources),
-	.resource      = msm_tpiu_resources,
+static struct coresight_platform_data coresight_etb_pdata = {
+	.id		= 1,
+	.name		= "coresight-etb",
+	.nr_inports	= 1,
+	.nr_outports	= 0,
+	.default_sink	= true,
 };
 
-static struct resource msm_funnel_resources[] = {
+struct platform_device coresight_etb_device = {
+	.name          = "coresight-etb",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(coresight_etb_resources),
+	.resource      = coresight_etb_resources,
+	.dev = {
+		.platform_data = &coresight_etb_pdata,
+	},
+};
+
+static struct resource coresight_funnel_resources[] = {
 	{
-		.start = MSM_FUNNEL_PHYS_BASE,
-		.end   = MSM_FUNNEL_PHYS_BASE + SZ_4K - 1,
+		.start = CORESIGHT_FUNNEL_PHYS_BASE,
+		.end   = CORESIGHT_FUNNEL_PHYS_BASE + SZ_4K - 1,
 		.flags = IORESOURCE_MEM,
 	},
 };
 
-struct platform_device msm_funnel_device = {
-	.name          = "msm_funnel",
-	.id            = 0,
-	.num_resources = ARRAY_SIZE(msm_funnel_resources),
-	.resource      = msm_funnel_resources,
+static const int coresight_funnel_outports[] = { 0, 1 };
+static const int coresight_funnel_child_ids[] = { 0, 1 };
+static const int coresight_funnel_child_ports[] = { 0, 0 };
+
+static struct coresight_platform_data coresight_funnel_pdata = {
+	.id		= 2,
+	.name		= "coresight-funnel",
+	.nr_inports	= 4,
+	.outports	= coresight_funnel_outports,
+	.child_ids	= coresight_funnel_child_ids,
+	.child_ports	= coresight_funnel_child_ports,
+	.nr_outports	= ARRAY_SIZE(coresight_funnel_outports),
 };
 
-static struct resource msm_etm_resources[] = {
+struct platform_device coresight_funnel_device = {
+	.name          = "coresight-funnel",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(coresight_funnel_resources),
+	.resource      = coresight_funnel_resources,
+	.dev = {
+		.platform_data = &coresight_funnel_pdata,
+	},
+};
+
+static struct resource coresight_stm_resources[] = {
 	{
-		.start = MSM_ETM_PHYS_BASE,
-		.end   = MSM_ETM_PHYS_BASE + (SZ_4K * 2) - 1,
+		.start = CORESIGHT_STM_PHYS_BASE,
+		.end   = CORESIGHT_STM_PHYS_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = CORESIGHT_STM_CHANNEL_PHYS_BASE,
+		.end   = CORESIGHT_STM_CHANNEL_PHYS_BASE + SZ_1M + SZ_512K - 1,
 		.flags = IORESOURCE_MEM,
 	},
 };
 
-struct platform_device msm_etm_device = {
-	.name          = "msm_etm",
-	.id            = 0,
-	.num_resources = ARRAY_SIZE(msm_etm_resources),
-	.resource      = msm_etm_resources,
+static const int coresight_stm_outports[] = { 0 };
+static const int coresight_stm_child_ids[] = { 2 };
+static const int coresight_stm_child_ports[] = { 2 };
+
+static struct coresight_platform_data coresight_stm_pdata = {
+	.id		= 3,
+	.name		= "coresight-stm",
+	.nr_inports	= 0,
+	.outports	= coresight_stm_outports,
+	.child_ids	= coresight_stm_child_ids,
+	.child_ports	= coresight_stm_child_ports,
+	.nr_outports	= ARRAY_SIZE(coresight_stm_outports),
 };
 
-#endif
+struct platform_device coresight_stm_device = {
+	.name          = "coresight-stm",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(coresight_stm_resources),
+	.resource      = coresight_stm_resources,
+	.dev = {
+		.platform_data = &coresight_stm_pdata,
+	},
+};
+
+static struct resource coresight_etm0_resources[] = {
+	{
+		.start = CORESIGHT_ETM0_PHYS_BASE,
+		.end   = CORESIGHT_ETM0_PHYS_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static const int coresight_etm0_outports[] = { 0 };
+static const int coresight_etm0_child_ids[] = { 2 };
+static const int coresight_etm0_child_ports[] = { 0 };
+
+static struct coresight_platform_data coresight_etm0_pdata = {
+	.id		= 4,
+	.name		= "coresight-etm0",
+	.nr_inports	= 0,
+	.outports	= coresight_etm0_outports,
+	.child_ids	= coresight_etm0_child_ids,
+	.child_ports	= coresight_etm0_child_ports,
+	.nr_outports	= ARRAY_SIZE(coresight_etm0_outports),
+};
+
+struct platform_device coresight_etm0_device = {
+	.name          = "coresight-etm",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(coresight_etm0_resources),
+	.resource      = coresight_etm0_resources,
+	.dev = {
+		.platform_data = &coresight_etm0_pdata,
+	},
+};
+
+static struct resource coresight_etm1_resources[] = {
+	{
+		.start = CORESIGHT_ETM1_PHYS_BASE,
+		.end   = CORESIGHT_ETM1_PHYS_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static const int coresight_etm1_outports[] = { 0 };
+static const int coresight_etm1_child_ids[] = { 2 };
+static const int coresight_etm1_child_ports[] = { 1 };
+
+static struct coresight_platform_data coresight_etm1_pdata = {
+	.id		= 5,
+	.name		= "coresight-etm1",
+	.nr_inports	= 0,
+	.outports	= coresight_etm1_outports,
+	.child_ids	= coresight_etm1_child_ids,
+	.child_ports	= coresight_etm1_child_ports,
+	.nr_outports	= ARRAY_SIZE(coresight_etm1_outports),
+};
+
+struct platform_device coresight_etm1_device = {
+	.name          = "coresight-etm",
+	.id            = 1,
+	.num_resources = ARRAY_SIZE(coresight_etm1_resources),
+	.resource      = coresight_etm1_resources,
+	.dev = {
+		.platform_data = &coresight_etm1_pdata,
+	},
+};
 
 static struct resource msm_ebi1_ch0_erp_resources[] = {
 	{
@@ -3911,6 +4038,11 @@
 	},
 };
 
+struct platform_device msm_gpio_device = {
+	.name = "msmgpio",
+	.id = -1,
+};
+
 struct platform_device mdm_sglte_device = {
 	.name		= "mdm2_modem",
 	.id		= -1,
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 9c2b26a..c307714 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -70,6 +70,15 @@
 	.bark_time = 11000,
 	.has_secure = false,
 	.use_kernel_fiq = true,
+	.base = MSM_TMR_BASE + WDT0_OFFSET,
+};
+
+static struct resource msm_watchdog_resources[] = {
+	{
+		.start	= WDT0_ACCSCSSNBARK_INT,
+		.end	= WDT0_ACCSCSSNBARK_INT,
+		.flags	= IORESOURCE_IRQ,
+	},
 };
 
 struct platform_device msm9615_device_watchdog = {
@@ -78,6 +87,8 @@
 	.dev = {
 		.platform_data = &msm_watchdog_pdata,
 	},
+	.num_resources	= ARRAY_SIZE(msm_watchdog_resources),
+	.resource	= msm_watchdog_resources,
 };
 
 static struct resource msm_dmov_resource[] = {
@@ -845,19 +856,19 @@
 	},
 #ifdef CONFIG_MMC_MSM_SPS_SUPPORT
 	{
-		.name   = "sdcc_dml_addr",
+		.name   = "dml_mem",
 		.start  = MSM_SDC1_DML_BASE,
 		.end    = MSM_SDC1_BAM_BASE - 1,
 		.flags  = IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_addr",
+		.name   = "bam_mem",
 		.start  = MSM_SDC1_BAM_BASE,
 		.end    = MSM_SDC1_BAM_BASE + (2 * SZ_4K) - 1,
 		.flags  = IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_irq",
+		.name   = "bam_irq",
 		.start  = SDC1_BAM_IRQ,
 		.end    = SDC1_BAM_IRQ,
 		.flags  = IORESOURCE_IRQ,
@@ -880,19 +891,19 @@
 	},
 #ifdef CONFIG_MMC_MSM_SPS_SUPPORT
 	{
-		.name   = "sdcc_dml_addr",
+		.name   = "dml_mem",
 		.start  = MSM_SDC2_DML_BASE,
 		.end    = MSM_SDC2_BAM_BASE - 1,
 		.flags  = IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_addr",
+		.name   = "bam_mem",
 		.start  = MSM_SDC2_BAM_BASE,
 		.end    = MSM_SDC2_BAM_BASE + (2 * SZ_4K) - 1,
 		.flags  = IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_irq",
+		.name   = "bam_irq",
 		.start  = SDC2_BAM_IRQ,
 		.end    = SDC2_BAM_IRQ,
 		.flags  = IORESOURCE_IRQ,
@@ -1372,6 +1383,10 @@
 	},
 };
 
+struct platform_device msm_gpio_device = {
+	.name = "msmgpio",
+	.id = -1,
+};
 
 void __init msm9615_device_init(void)
 {
@@ -1382,7 +1397,6 @@
 		msm_rpmrs_levels[0].latency_us;
 	msm_android_usb_hsic_pdata.swfi_latency =
 		msm_rpmrs_levels[0].latency_us;
-
 }
 
 #define MSM_SHARED_RAM_PHYS 0x40000000
diff --git a/arch/arm/mach-msm/devices-fsm9xxx.c b/arch/arm/mach-msm/devices-fsm9xxx.c
index 5f4d940..639eeae 100644
--- a/arch/arm/mach-msm/devices-fsm9xxx.c
+++ b/arch/arm/mach-msm/devices-fsm9xxx.c
@@ -419,6 +419,15 @@
 	.bark_time = 11000,
 	.has_secure = false,
 	.has_vic = true,
+	.base = MSM_TMR_BASE + WDT1_OFFSET,
+};
+
+static struct resource msm_watchdog_resources[] = {
+	{
+		.start	= INT_WDT1_ACCSCSSBARK,
+		.end	= INT_WDT1_ACCSCSSBARK,
+		.flags	= IORESOURCE_IRQ,
+	},
 };
 
 struct platform_device fsm9xxx_device_watchdog = {
@@ -427,5 +436,7 @@
 	.dev = {
 		.platform_data = &fsm_watchdog_pdata,
 	},
+	.num_resources	= ARRAY_SIZE(msm_watchdog_resources),
+	.resource	= msm_watchdog_resources,
 };
 
diff --git a/arch/arm/mach-msm/devices-msm7x25.c b/arch/arm/mach-msm/devices-msm7x25.c
index 2be7d5e..99b2960 100644
--- a/arch/arm/mach-msm/devices-msm7x25.c
+++ b/arch/arm/mach-msm/devices-msm7x25.c
@@ -439,23 +439,25 @@
 #define MSM_SDC4_BASE         0xA0700000
 static struct resource resources_sdc1[] = {
 	{
+		.name	= "core_mem",
 		.start	= MSM_SDC1_BASE,
 		.end	= MSM_SDC1_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name	= "core_irq",
 		.start	= INT_SDC1_0,
 		.end	= INT_SDC1_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC1_CHAN,
 		.end	= DMOV_SDC1_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC1_CRCI,
 		.end	= DMOV_SDC1_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -464,23 +466,25 @@
 
 static struct resource resources_sdc2[] = {
 	{
+		.name	= "core_mem",
 		.start	= MSM_SDC2_BASE,
 		.end	= MSM_SDC2_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name   = "core_irq",
 		.start	= INT_SDC2_0,
 		.end	= INT_SDC2_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC2_CHAN,
 		.end	= DMOV_SDC2_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC2_CRCI,
 		.end	= DMOV_SDC2_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -489,23 +493,25 @@
 
 static struct resource resources_sdc3[] = {
 	{
+		.name	= "core_mem",
 		.start	= MSM_SDC3_BASE,
 		.end	= MSM_SDC3_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name   = "core_irq",
 		.start	= INT_SDC3_0,
 		.end	= INT_SDC3_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC3_CHAN,
 		.end	= DMOV_SDC3_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC3_CRCI,
 		.end	= DMOV_SDC3_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -514,23 +520,25 @@
 
 static struct resource resources_sdc4[] = {
 	{
+		.name	= "core_mem",
 		.start	= MSM_SDC4_BASE,
 		.end	= MSM_SDC4_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name   = "core_irq",
 		.start	= INT_SDC4_0,
 		.end	= INT_SDC4_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC4_CHAN,
 		.end	= DMOV_SDC4_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC4_CRCI,
 		.end	= DMOV_SDC4_CRCI,
 		.flags	= IORESOURCE_DMA,
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
index 69d7430..82c5eed 100644
--- a/arch/arm/mach-msm/devices-msm7x27.c
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -448,23 +448,25 @@
 #define MSM_SDC4_BASE         0xA0700000
 static struct resource resources_sdc1[] = {
 	{
+		.name	= "core_mem",
 		.start	= MSM_SDC1_BASE,
 		.end	= MSM_SDC1_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name	= "core_irq",
 		.start	= INT_SDC1_0,
 		.end	= INT_SDC1_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC1_CHAN,
 		.end	= DMOV_SDC1_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC1_CRCI,
 		.end	= DMOV_SDC1_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -473,23 +475,25 @@
 
 static struct resource resources_sdc2[] = {
 	{
+		.name	= "core_mem",
 		.start	= MSM_SDC2_BASE,
 		.end	= MSM_SDC2_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name   = "core_irq",
 		.start	= INT_SDC2_0,
 		.end	= INT_SDC2_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC2_CHAN,
 		.end	= DMOV_SDC2_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC2_CRCI,
 		.end	= DMOV_SDC2_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -498,23 +502,25 @@
 
 static struct resource resources_sdc3[] = {
 	{
+		.name	= "core_mem",
 		.start	= MSM_SDC3_BASE,
 		.end	= MSM_SDC3_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name   = "core_irq",
 		.start	= INT_SDC3_0,
 		.end	= INT_SDC3_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC3_CHAN,
 		.end	= DMOV_SDC3_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC3_CRCI,
 		.end	= DMOV_SDC3_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -523,23 +529,25 @@
 
 static struct resource resources_sdc4[] = {
 	{
+		.name	= "core_mem",
 		.start	= MSM_SDC4_BASE,
 		.end	= MSM_SDC4_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name   = "core_irq",
 		.start	= INT_SDC4_0,
 		.end	= INT_SDC4_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC4_CHAN,
 		.end	= DMOV_SDC4_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC4_CRCI,
 		.end	= DMOV_SDC4_CRCI,
 		.flags	= IORESOURCE_DMA,
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 96984fb..1fcf7dc 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -507,23 +507,25 @@
 #define MSM_SDC4_BASE         0xA0700000
 static struct resource resources_sdc1[] = {
 	{
+		.name	= "core_mem",
 		.start	= MSM_SDC1_BASE,
 		.end	= MSM_SDC1_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name	= "core_irq",
 		.start	= INT_SDC1_0,
 		.end	= INT_SDC1_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC1_CHAN,
 		.end	= DMOV_SDC1_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC1_CRCI,
 		.end	= DMOV_SDC1_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -532,23 +534,25 @@
 
 static struct resource resources_sdc2[] = {
 	{
+		.name	= "core_mem",
 		.start	= MSM_SDC2_BASE,
 		.end	= MSM_SDC2_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name   = "core_irq",
 		.start	= INT_SDC2_0,
 		.end	= INT_SDC2_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC2_CHAN,
 		.end	= DMOV_SDC2_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC2_CRCI,
 		.end	= DMOV_SDC2_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -557,23 +561,25 @@
 
 static struct resource resources_sdc3[] = {
 	{
+		.name   = "core_mem",
 		.start	= MSM_SDC3_BASE,
 		.end	= MSM_SDC3_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name   = "core_irq",
 		.start	= INT_SDC3_0,
 		.end	= INT_SDC3_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_NAND_CHAN,
 		.end	= DMOV_NAND_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC3_CRCI,
 		.end	= DMOV_SDC3_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -582,23 +588,25 @@
 
 static struct resource resources_sdc4[] = {
 	{
+		.name	= "core_mem",
 		.start	= MSM_SDC4_BASE,
 		.end	= MSM_SDC4_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name   = "core_irq",
 		.start	= INT_SDC4_0,
 		.end	= INT_SDC4_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC4_CHAN,
 		.end	= DMOV_SDC4_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC4_CRCI,
 		.end	= DMOV_SDC4_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -890,7 +898,7 @@
 		kgsl_3d0_pdata.idle_timeout = HZ/5;
 		kgsl_3d0_pdata.strtstp_sleepwake = false;
 		/* 8x25 supports a higher GPU frequency */
-		kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 300000000;
+		kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 320000000;
 		kgsl_3d0_pdata.pwrlevel[0].bus_freq = 200000000;
 	}
 }
@@ -1175,23 +1183,25 @@
 
 static struct resource msm8625_resources_sdc1[] = {
 	{
+		.name	= "core_mem",
 		.start	= MSM_SDC1_BASE,
 		.end	= MSM_SDC1_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name	= "core_irq",
 		.start	= MSM8625_INT_SDC1_0,
 		.end	= MSM8625_INT_SDC1_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC1_CHAN,
 		.end	= DMOV_SDC1_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC1_CRCI,
 		.end	= DMOV_SDC1_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -1200,23 +1210,25 @@
 
 static struct resource msm8625_resources_sdc2[] = {
 	{
+		.name   = "core_mem",
 		.start	= MSM_SDC2_BASE,
 		.end	= MSM_SDC2_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name	= "core_irq",
 		.start	= MSM8625_INT_SDC2_0,
 		.end	= MSM8625_INT_SDC2_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC2_CHAN,
 		.end	= DMOV_SDC2_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC2_CRCI,
 		.end	= DMOV_SDC2_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -1225,23 +1237,25 @@
 
 static struct resource msm8625_resources_sdc3[] = {
 	{
+		.name   = "core_mem",
 		.start	= MSM_SDC3_BASE,
 		.end	= MSM_SDC3_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name	= "core_irq",
 		.start	= MSM8625_INT_SDC3_0,
 		.end	= MSM8625_INT_SDC3_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC3_CHAN,
 		.end	= DMOV_SDC3_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC3_CRCI,
 		.end	= DMOV_SDC3_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -1250,23 +1264,25 @@
 
 static struct resource msm8625_resources_sdc4[] = {
 	{
+		.name   = "core_mem",
 		.start	= MSM_SDC4_BASE,
 		.end	= MSM_SDC4_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name	= "core_irq",
 		.start	= MSM8625_INT_SDC4_0,
 		.end	= MSM8625_INT_SDC4_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC4_CHAN,
 		.end	= DMOV_SDC4_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC4_CRCI,
 		.end	= DMOV_SDC4_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -1645,18 +1661,23 @@
 	/* Part number for 1GHz part */
 	case 0x770:
 	case 0x771:
+	case 0x77C:
 	case 0x780:
+	case 0x8D0:
 		cpu = MSM8625;
 		break;
 	/* Part number for 1.2GHz part */
 	case 0x773:
 	case 0x774:
 	case 0x781:
+	case 0x8D1:
 		cpu = MSM8625A;
 		break;
 	case 0x775:
 	case 0x776:
+	case 0x77D:
 	case 0x782:
+	case 0x8D2:
 		cpu = MSM8625AB;
 		break;
 	default:
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index f04ef9d..a6473c6 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -26,7 +26,7 @@
 #include <mach/dma.h>
 #include <mach/board.h>
 #include <asm/clkdev.h>
-
+#include <linux/ion.h>
 #include "devices.h"
 #include "footswitch.h"
 
@@ -784,23 +784,25 @@
 #define MSM_SDC4_BASE         0xA3100000
 static struct resource resources_sdc1[] = {
 	{
+		.name	= "core_mem",
 		.start	= MSM_SDC1_BASE,
 		.end	= MSM_SDC1_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name	= "core_irq",
 		.start	= INT_SDC1_0,
 		.end	= INT_SDC1_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC1_CHAN,
 		.end	= DMOV_SDC1_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC1_CRCI,
 		.end	= DMOV_SDC1_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -809,23 +811,25 @@
 
 static struct resource resources_sdc2[] = {
 	{
+		.name   = "core_mem",
 		.start	= MSM_SDC2_BASE,
 		.end	= MSM_SDC2_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name	= "core_irq",
 		.start	= INT_SDC2_0,
 		.end	= INT_SDC2_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_NAND_CHAN,
 		.end	= DMOV_NAND_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC2_CRCI,
 		.end	= DMOV_SDC2_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -834,23 +838,25 @@
 
 static struct resource resources_sdc3[] = {
 	{
+		.name   = "core_mem",
 		.start	= MSM_SDC3_BASE,
 		.end	= MSM_SDC3_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name	= "core_irq",
 		.start	= INT_SDC3_0,
 		.end	= INT_SDC3_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC3_CHAN,
 		.end	= DMOV_SDC3_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC3_CRCI,
 		.end	= DMOV_SDC3_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -859,23 +865,25 @@
 
 static struct resource resources_sdc4[] = {
 	{
+		.name   = "core_mem",
 		.start	= MSM_SDC4_BASE,
 		.end	= MSM_SDC4_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name	= "core_irq",
 		.start	= INT_SDC4_0,
 		.end	= INT_SDC4_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC4_CHAN,
 		.end	= DMOV_SDC4_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC4_CRCI,
 		.end	= DMOV_SDC4_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -955,8 +963,8 @@
 };
 
 struct msm_vidc_platform_data vidc_platform_data = {
-	.memtype = MEMTYPE_EBI0,
-	.enable_ion = 0,
+	.memtype = ION_CAMERA_HEAP_ID,
+	.enable_ion = 1,
 	.disable_dmx = 0,
 	.cont_mode_dpb_count = 8
 };
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 3920abe..9f31a18 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -100,6 +100,11 @@
 #define MSM_UART9DM_PHYS    (MSM_GSBI9_PHYS + 0x40000)
 #define INT_UART9DM_IRQ     GSBI9_UARTDM_IRQ
 
+struct platform_device msm_gpio_device = {
+	.name = "msmgpio",
+	.id = -1,
+};
+
 static void charm_ap2mdm_kpdpwr_on(void)
 {
 	gpio_direction_output(AP2MDM_PMIC_RESET_N, 0);
@@ -1091,43 +1096,45 @@
 
 static struct resource resources_sdc1[] = {
 	{
+		.name	= "core_mem",
 		.start	= MSM_SDC1_BASE,
 		.end	= MSM_SDC1_DML_BASE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name	= "core_irq",
 		.start	= SDC1_IRQ_0,
 		.end	= SDC1_IRQ_0,
 		.flags	= IORESOURCE_IRQ,
 	},
 #ifdef CONFIG_MMC_MSM_SPS_SUPPORT
 	{
-		.name   = "sdcc_dml_addr",
+		.name   = "dml_mem",
 		.start	= MSM_SDC1_DML_BASE,
 		.end	= MSM_SDC1_BAM_BASE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_addr",
+		.name   = "bam_mem",
 		.start	= MSM_SDC1_BAM_BASE,
 		.end	= MSM_SDC1_BAM_BASE + (2 * SZ_4K) - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_irq",
+		.name   = "bam_irq",
 		.start	= SDC1_BAM_IRQ,
 		.end	= SDC1_BAM_IRQ,
 		.flags	= IORESOURCE_IRQ,
 	},
 #else
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC1_CHAN,
 		.end	= DMOV_SDC1_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC1_CRCI,
 		.end	= DMOV_SDC1_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -1137,43 +1144,45 @@
 
 static struct resource resources_sdc2[] = {
 	{
+		.name	= "core_mem",
 		.start	= MSM_SDC2_BASE,
 		.end	= MSM_SDC2_DML_BASE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name	= "core_irq",
 		.start	= SDC2_IRQ_0,
 		.end	= SDC2_IRQ_0,
 		.flags	= IORESOURCE_IRQ,
 	},
 #ifdef CONFIG_MMC_MSM_SPS_SUPPORT
 	{
-		.name   = "sdcc_dml_addr",
+		.name   = "dml_mem",
 		.start	= MSM_SDC2_DML_BASE,
 		.end	= MSM_SDC2_BAM_BASE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_addr",
+		.name   = "bam_mem",
 		.start	= MSM_SDC2_BAM_BASE,
 		.end	= MSM_SDC2_BAM_BASE + (2 * SZ_4K) - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_irq",
+		.name   = "bam_irq",
 		.start	= SDC2_BAM_IRQ,
 		.end	= SDC2_BAM_IRQ,
 		.flags	= IORESOURCE_IRQ,
 	},
 #else
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC2_CHAN,
 		.end	= DMOV_SDC2_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC2_CRCI,
 		.end	= DMOV_SDC2_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -1183,43 +1192,45 @@
 
 static struct resource resources_sdc3[] = {
 	{
+		.name	= "core_mem",
 		.start	= MSM_SDC3_BASE,
 		.end	= MSM_SDC3_DML_BASE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name	= "core_irq",
 		.start	= SDC3_IRQ_0,
 		.end	= SDC3_IRQ_0,
 		.flags	= IORESOURCE_IRQ,
 	},
 #ifdef CONFIG_MMC_MSM_SPS_SUPPORT
 	{
-		.name   = "sdcc_dml_addr",
+		.name   = "dml_mem",
 		.start	= MSM_SDC3_DML_BASE,
 		.end	= MSM_SDC3_BAM_BASE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_addr",
+		.name   = "bam_mem",
 		.start	= MSM_SDC3_BAM_BASE,
 		.end	= MSM_SDC3_BAM_BASE + (2 * SZ_4K) - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_irq",
+		.name   = "bam_irq",
 		.start	= SDC3_BAM_IRQ,
 		.end	= SDC3_BAM_IRQ,
 		.flags	= IORESOURCE_IRQ,
 	},
 #else
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC3_CHAN,
 		.end	= DMOV_SDC3_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC3_CRCI,
 		.end	= DMOV_SDC3_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -1229,43 +1240,45 @@
 
 static struct resource resources_sdc4[] = {
 	{
+		.name	= "core_mem",
 		.start	= MSM_SDC4_BASE,
 		.end	= MSM_SDC4_DML_BASE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name	= "core_irq",
 		.start	= SDC4_IRQ_0,
 		.end	= SDC4_IRQ_0,
 		.flags	= IORESOURCE_IRQ,
 	},
 #ifdef CONFIG_MMC_MSM_SPS_SUPPORT
 	{
-		.name   = "sdcc_dml_addr",
+		.name   = "dml_mem",
 		.start	= MSM_SDC4_DML_BASE,
 		.end	= MSM_SDC4_BAM_BASE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_addr",
+		.name   = "bam_mem",
 		.start	= MSM_SDC4_BAM_BASE,
 		.end	= MSM_SDC4_BAM_BASE + (2 * SZ_4K) - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_irq",
+		.name   = "bam_irq",
 		.start	= SDC4_BAM_IRQ,
 		.end	= SDC4_BAM_IRQ,
 		.flags	= IORESOURCE_IRQ,
 	},
 #else
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC4_CHAN,
 		.end	= DMOV_SDC4_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC4_CRCI,
 		.end	= DMOV_SDC4_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -1275,43 +1288,45 @@
 
 static struct resource resources_sdc5[] = {
 	{
+		.name	= "core_mem",
 		.start	= MSM_SDC5_BASE,
 		.end	= MSM_SDC5_DML_BASE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name	= "core_irq",
 		.start	= SDC5_IRQ_0,
 		.end	= SDC5_IRQ_0,
 		.flags	= IORESOURCE_IRQ,
 	},
 #ifdef CONFIG_MMC_MSM_SPS_SUPPORT
 	{
-		.name   = "sdcc_dml_addr",
+		.name   = "dml_mem",
 		.start	= MSM_SDC5_DML_BASE,
 		.end	= MSM_SDC5_BAM_BASE - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_addr",
+		.name   = "bam_mem",
 		.start	= MSM_SDC5_BAM_BASE,
 		.end	= MSM_SDC5_BAM_BASE + (2 * SZ_4K) - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.name   = "sdcc_bam_irq",
+		.name   = "bam_irq",
 		.start	= SDC5_BAM_IRQ,
 		.end	= SDC5_BAM_IRQ,
 		.flags	= IORESOURCE_IRQ,
 	},
 #else
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC5_CHAN,
 		.end	= DMOV_SDC5_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC5_CRCI,
 		.end	= DMOV_SDC5_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -1981,6 +1996,15 @@
 	.pet_time = 10000,
 	.bark_time = 11000,
 	.has_secure = true,
+	.base = MSM_TMR0_BASE + WDT0_OFFSET,
+};
+
+static struct resource msm_watchdog_resources[] = {
+	{
+		.start	= WDT0_ACCSCSSNBARK_INT,
+		.end	= WDT0_ACCSCSSNBARK_INT,
+		.flags	= IORESOURCE_IRQ,
+	},
 };
 
 struct platform_device msm8660_device_watchdog = {
@@ -1989,6 +2013,8 @@
 	.dev = {
 		.platform_data = &msm_watchdog_pdata,
 	},
+	.num_resources	= ARRAY_SIZE(msm_watchdog_resources),
+	.resource	= msm_watchdog_resources,
 };
 
 static struct resource msm_dmov_resource_adm0[] = {
@@ -2289,10 +2315,14 @@
 #ifdef CONFIG_MSM_BUS_SCALING
 	.vidc_bus_client_pdata = &vidc_bus_client_data,
 #endif
+#ifdef CONFIG_MSM_VIDC_CONTENT_PROTECTION
+	.cp_enabled = 1,
+#else
+	.cp_enabled = 0,
+#endif
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 	.memtype = ION_CP_MM_HEAP_ID,
 	.enable_ion = 1,
-	.cp_enabled = 1,
 	.secure_wb_heap = 1,
 #else
 	.memtype = MEMTYPE_SMI_KERNEL,
diff --git a/arch/arm/mach-msm/devices-qsd8x50.c b/arch/arm/mach-msm/devices-qsd8x50.c
index ec4a14f..03ffa2f 100644
--- a/arch/arm/mach-msm/devices-qsd8x50.c
+++ b/arch/arm/mach-msm/devices-qsd8x50.c
@@ -490,23 +490,25 @@
 #define MSM_SDC4_BASE         0xA0600000
 static struct resource resources_sdc1[] = {
 	{
+		.name	= "core_mem",
 		.start	= MSM_SDC1_BASE,
 		.end	= MSM_SDC1_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name   = "core_irq",
 		.start	= INT_SDC1_0,
 		.end	= INT_SDC1_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC1_CHAN,
 		.end	= DMOV_SDC1_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC1_CRCI,
 		.end	= DMOV_SDC1_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -515,23 +517,25 @@
 
 static struct resource resources_sdc2[] = {
 	{
+		.name   = "core_mem",
 		.start	= MSM_SDC2_BASE,
 		.end	= MSM_SDC2_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name   = "core_irq",
 		.start	= INT_SDC2_0,
 		.end	= INT_SDC2_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC2_CHAN,
 		.end	= DMOV_SDC2_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC2_CRCI,
 		.end	= DMOV_SDC2_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -540,23 +544,25 @@
 
 static struct resource resources_sdc3[] = {
 	{
+		.name   = "core_mem",
 		.start	= MSM_SDC3_BASE,
 		.end	= MSM_SDC3_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name   = "core_irq",
 		.start	= INT_SDC3_0,
 		.end	= INT_SDC3_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC3_CHAN,
 		.end	= DMOV_SDC3_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC3_CRCI,
 		.end	= DMOV_SDC3_CRCI,
 		.flags	= IORESOURCE_DMA,
@@ -565,23 +571,25 @@
 
 static struct resource resources_sdc4[] = {
 	{
+		.name   = "core_mem",
 		.start	= MSM_SDC4_BASE,
 		.end	= MSM_SDC4_BASE + SZ_4K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
+		.name   = "core_irq",
 		.start	= INT_SDC4_0,
 		.end	= INT_SDC4_1,
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "sdcc_dma_chnl",
+		.name	= "dma_chnl",
 		.start	= DMOV_SDC4_CHAN,
 		.end	= DMOV_SDC4_CHAN,
 		.flags	= IORESOURCE_DMA,
 	},
 	{
-		.name	= "sdcc_dma_crci",
+		.name	= "dma_crci",
 		.start	= DMOV_SDC4_CRCI,
 		.end	= DMOV_SDC4_CRCI,
 		.flags	= IORESOURCE_DMA,
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index c71af12..e3e7de4 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -191,6 +191,7 @@
 
 extern struct platform_device msm_device_tsif[2];
 extern struct platform_device msm_8064_device_tsif[2];
+extern struct platform_device msm_8064_device_tspp;
 
 extern struct platform_device msm_device_ssbi_pmic1;
 extern struct platform_device msm_device_ssbi_pmic2;
@@ -206,6 +207,7 @@
 
 extern struct platform_device msm_pcm;
 extern struct platform_device msm_multi_ch_pcm;
+extern struct platform_device msm_lowlatency_pcm;
 extern struct platform_device msm_pcm_routing;
 extern struct platform_device msm_cpudai0;
 extern struct platform_device msm_cpudai1;
@@ -269,6 +271,7 @@
 extern struct platform_device apq_lpa_pcm;
 extern struct platform_device apq_compr_dsp;
 extern struct platform_device apq_multi_ch_pcm;
+extern struct platform_device apq_lowlatency_pcm;
 extern struct platform_device apq_pcm_hostless;
 extern struct platform_device apq_cpudai_afe_01_rx;
 extern struct platform_device apq_cpudai_afe_01_tx;
@@ -295,6 +298,8 @@
 extern unsigned apq8064_num_footswitch;
 extern struct platform_device *msm8930_footswitch[];
 extern unsigned msm8930_num_footswitch;
+extern struct platform_device *msm8627_footswitch[];
+extern unsigned msm8627_num_footswitch;
 
 extern struct platform_device fsm_qfp_fuse_device;
 
@@ -362,13 +367,14 @@
 extern struct platform_device msm9615_device_watchdog;
 extern struct platform_device fsm9xxx_device_watchdog;
 
-extern struct platform_device apq8064_qdss_device;
-extern struct platform_device msm_qdss_device;
-extern struct platform_device msm_etb_device;
-extern struct platform_device msm_tpiu_device;
-extern struct platform_device msm_funnel_device;
-extern struct platform_device msm_etm_device;
-extern struct platform_device apq8064_etm_device;
+extern struct platform_device coresight_tpiu_device;
+extern struct platform_device coresight_etb_device;
+extern struct platform_device coresight_funnel_device;
+extern struct platform_device apq8064_coresight_funnel_device;
+extern struct platform_device coresight_etm0_device;
+extern struct platform_device coresight_etm1_device;
+extern struct platform_device coresight_etm2_device;
+extern struct platform_device coresight_etm3_device;
 #endif
 
 extern struct platform_device msm_bus_8064_apps_fabric;
@@ -378,6 +384,7 @@
 extern struct platform_device msm_bus_8064_cpss_fpb;
 
 extern struct platform_device mdm_8064_device;
+extern struct platform_device i2s_mdm_8064_device;
 extern struct platform_device msm_dsps_device_8064;
 extern struct platform_device *msm_8974_stub_regulator_devices[];
 extern int msm_8974_stub_regulator_devices_len;
@@ -432,4 +439,7 @@
 extern struct platform_device msm8930_device_acpuclk;
 extern struct platform_device msm8930aa_device_acpuclk;
 extern struct platform_device msm8960_device_acpuclk;
+extern struct platform_device msm8960ab_device_acpuclk;
 extern struct platform_device msm9615_device_acpuclk;
+
+extern struct platform_device msm_gpio_device;
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index f8324ce..d1d9f4b 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -54,8 +54,8 @@
 			 * OK, proper wakeup, we're done
 			 */
 			pen_release = -1;
-			dmac_flush_range((void *)&pen_release,
-				(void *)(&pen_release + sizeof(pen_release)));
+			dmac_flush_range((char *)&pen_release,
+				(char *)&pen_release + sizeof(pen_release));
 			break;
 		}
 
@@ -67,8 +67,8 @@
 		 * possible, since we are currently running incoherently, and
 		 * therefore cannot safely call printk() or anything else
 		 */
-		dmac_inv_range((void *)&pen_release,
-			       (void *)(&pen_release + sizeof(pen_release)));
+		dmac_inv_range((char *)&pen_release,
+			       (char *)&pen_release + sizeof(pen_release));
 		pr_debug("CPU%u: spurious wakeup call\n", cpu);
 	}
 }
diff --git a/arch/arm/mach-msm/idle_stats.c b/arch/arm/mach-msm/idle_stats.c
deleted file mode 100644
index f4d3a27..0000000
--- a/arch/arm/mach-msm/idle_stats.c
+++ /dev/null
@@ -1,545 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/cdev.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/hrtimer.h>
-#include <linux/interrupt.h>
-#include <linux/ktime.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/version.h>
-#include <linux/sched.h>
-#include <asm/uaccess.h>
-
-#include "idle_stats.h"
-#include <mach/cpuidle.h>
-
-/******************************************************************************
- * Debug Definitions
- *****************************************************************************/
-
-enum {
-	MSM_IDLE_STATS_DEBUG_API = BIT(0),
-	MSM_IDLE_STATS_DEBUG_SIGNAL = BIT(1),
-	MSM_IDLE_STATS_DEBUG_MIGRATION = BIT(2),
-};
-
-static int msm_idle_stats_debug_mask;
-module_param_named(
-	debug_mask, msm_idle_stats_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
-);
-
-/******************************************************************************
- * Driver Definitions
- *****************************************************************************/
-
-#define MSM_IDLE_STATS_DRIVER_NAME "msm_idle_stats"
-
-static dev_t msm_idle_stats_dev_nr;
-static struct cdev msm_idle_stats_cdev;
-static struct class *msm_idle_stats_class;
-
-/******************************************************************************
- * Device Definitions
- *****************************************************************************/
-
-struct msm_idle_stats_device {
-	unsigned int cpu;
-	struct mutex mutex;
-	struct notifier_block notifier;
-
-	int64_t collection_expiration;
-	struct msm_idle_stats stats;
-	struct hrtimer timer;
-
-	wait_queue_head_t wait_q;
-	atomic_t collecting;
-};
-
-static DEFINE_SPINLOCK(msm_idle_stats_devs_lock);
-static DEFINE_PER_CPU(struct msm_idle_stats_device *, msm_idle_stats_devs);
-
-/******************************************************************************
- *
- *****************************************************************************/
-
-static inline int64_t msm_idle_stats_bound_interval(int64_t interval)
-{
-	if (interval <= 0)
-		return 1;
-
-	if (interval > UINT_MAX)
-		return UINT_MAX;
-
-	return interval;
-}
-
-static enum hrtimer_restart msm_idle_stats_timer(struct hrtimer *timer)
-{
-	struct msm_idle_stats_device *stats_dev;
-	unsigned int cpu;
-	int64_t now;
-	int64_t interval;
-
-	stats_dev = container_of(timer, struct msm_idle_stats_device, timer);
-	cpu = get_cpu();
-
-	if (cpu != stats_dev->cpu) {
-		if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_MIGRATION)
-			pr_info("%s: timer migrated from cpu%u to cpu%u\n",
-				__func__, stats_dev->cpu, cpu);
-
-		stats_dev->stats.event = MSM_IDLE_STATS_EVENT_TIMER_MIGRATED;
-		goto timer_exit;
-	}
-
-	now = ktime_to_us(ktime_get());
-	interval = now - stats_dev->stats.last_busy_start;
-
-	if (stats_dev->stats.busy_timer > 0 &&
-			interval >= stats_dev->stats.busy_timer - 1)
-		stats_dev->stats.event =
-			MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED;
-	else
-		stats_dev->stats.event =
-			MSM_IDLE_STATS_EVENT_COLLECTION_TIMER_EXPIRED;
-
-timer_exit:
-	atomic_set(&stats_dev->collecting, 0);
-	wake_up_interruptible(&stats_dev->wait_q);
-
-	put_cpu();
-	return HRTIMER_NORESTART;
-}
-
-static void msm_idle_stats_pre_idle(struct msm_idle_stats_device *stats_dev)
-{
-	int64_t now;
-	int64_t interval;
-
-	if (smp_processor_id() != stats_dev->cpu) {
-		WARN_ON(1);
-		return;
-	}
-
-	if (!atomic_read(&stats_dev->collecting))
-		return;
-
-	hrtimer_cancel(&stats_dev->timer);
-
-	now = ktime_to_us(ktime_get());
-	interval = now - stats_dev->stats.last_busy_start;
-	interval = msm_idle_stats_bound_interval(interval);
-
-	stats_dev->stats.busy_intervals[stats_dev->stats.nr_collected]
-		= (__u32) interval;
-	stats_dev->stats.last_idle_start = now;
-}
-
-static void msm_idle_stats_post_idle(struct msm_idle_stats_device *stats_dev)
-{
-	int64_t now;
-	int64_t interval;
-	int64_t timer_interval;
-	int rc;
-
-	if (smp_processor_id() != stats_dev->cpu) {
-		WARN_ON(1);
-		return;
-	}
-
-	if (!atomic_read(&stats_dev->collecting))
-		return;
-
-	now = ktime_to_us(ktime_get());
-	interval = now - stats_dev->stats.last_idle_start;
-	interval = msm_idle_stats_bound_interval(interval);
-
-	stats_dev->stats.idle_intervals[stats_dev->stats.nr_collected]
-		= (__u32) interval;
-	stats_dev->stats.nr_collected++;
-	stats_dev->stats.last_busy_start = now;
-
-	if (stats_dev->stats.nr_collected >= MSM_IDLE_STATS_NR_MAX_INTERVALS) {
-		stats_dev->stats.event = MSM_IDLE_STATS_EVENT_COLLECTION_FULL;
-		goto post_idle_collection_done;
-	}
-
-	timer_interval = stats_dev->collection_expiration - now;
-	if (timer_interval <= 0) {
-		stats_dev->stats.event =
-			MSM_IDLE_STATS_EVENT_COLLECTION_TIMER_EXPIRED;
-		goto post_idle_collection_done;
-	}
-
-	if (stats_dev->stats.busy_timer > 0 &&
-			timer_interval > stats_dev->stats.busy_timer)
-		timer_interval = stats_dev->stats.busy_timer;
-
-	rc = hrtimer_start(&stats_dev->timer,
-		ktime_set(0, timer_interval * 1000), HRTIMER_MODE_REL_PINNED);
-	WARN_ON(rc);
-
-	return;
-
-post_idle_collection_done:
-	atomic_set(&stats_dev->collecting, 0);
-	wake_up_interruptible(&stats_dev->wait_q);
-}
-
-static int msm_idle_stats_notified(struct notifier_block *nb,
-	unsigned long val, void *v)
-{
-	struct msm_idle_stats_device *stats_dev = container_of(
-				nb, struct msm_idle_stats_device, notifier);
-
-	if (val == MSM_CPUIDLE_STATE_EXIT)
-		msm_idle_stats_post_idle(stats_dev);
-	else
-		msm_idle_stats_pre_idle(stats_dev);
-
-	return 0;
-}
-
-static int msm_idle_stats_collect(struct file *filp,
-				  unsigned int cmd, unsigned long arg)
-{
-	struct msm_idle_stats_device *stats_dev;
-	struct msm_idle_stats *stats;
-	int rc;
-
-	stats_dev = (struct msm_idle_stats_device *) filp->private_data;
-	stats = &stats_dev->stats;
-
-	rc = mutex_lock_interruptible(&stats_dev->mutex);
-	if (rc) {
-		if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_SIGNAL)
-			pr_info("%s: interrupted while waiting on device "
-				"mutex\n", __func__);
-
-		rc = -EINTR;
-		goto collect_exit;
-	}
-
-	if (atomic_read(&stats_dev->collecting)) {
-		pr_err("%s: inconsistent state\n", __func__);
-		rc = -EBUSY;
-		goto collect_unlock_exit;
-	}
-
-	rc = copy_from_user(stats, (void *)arg, sizeof(*stats));
-	if (rc) {
-		rc = -EFAULT;
-		goto collect_unlock_exit;
-	}
-
-	if (stats->nr_collected >= MSM_IDLE_STATS_NR_MAX_INTERVALS ||
-			stats->busy_timer > MSM_IDLE_STATS_MAX_TIMER ||
-			stats->collection_timer > MSM_IDLE_STATS_MAX_TIMER) {
-		rc = -EINVAL;
-		goto collect_unlock_exit;
-	}
-
-	if (get_cpu() != stats_dev->cpu) {
-		put_cpu();
-		rc = -EACCES;
-		goto collect_unlock_exit;
-	}
-
-	/*
-	 * When collection_timer == 0, stop collecting at the next
-	 * post idle.
-	 */
-	stats_dev->collection_expiration =
-		ktime_to_us(ktime_get()) + stats->collection_timer;
-
-	/*
-	 * Enable collection before starting any timer.
-	 */
-	atomic_set(&stats_dev->collecting, 1);
-
-	/*
-	 * When busy_timer == 0, do not set any busy timer.
-	 */
-	if (stats->busy_timer > 0) {
-		rc = hrtimer_start(&stats_dev->timer,
-			ktime_set(0, stats->busy_timer * 1000),
-			HRTIMER_MODE_REL_PINNED);
-		WARN_ON(rc);
-	}
-
-	put_cpu();
-	if (wait_event_interruptible(stats_dev->wait_q,
-			!atomic_read(&stats_dev->collecting))) {
-		if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_SIGNAL)
-			pr_info("%s: interrupted while waiting on "
-				"collection\n", __func__);
-
-		hrtimer_cancel(&stats_dev->timer);
-		atomic_set(&stats_dev->collecting, 0);
-
-		rc = -EINTR;
-		goto collect_unlock_exit;
-	}
-
-	stats->return_timestamp = ktime_to_us(ktime_get());
-
-	rc = copy_to_user((void *)arg, stats, sizeof(*stats));
-	if (rc) {
-		rc = -EFAULT;
-		goto collect_unlock_exit;
-	}
-
-collect_unlock_exit:
-	mutex_unlock(&stats_dev->mutex);
-
-collect_exit:
-	return rc;
-}
-
-static int msm_idle_stats_open(struct inode *inode, struct file *filp)
-{
-	struct msm_idle_stats_device *stats_dev;
-	int rc;
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: enter\n", __func__);
-
-	rc = nonseekable_open(inode, filp);
-	if (rc) {
-		pr_err("%s: failed to set nonseekable\n", __func__);
-		goto open_bail;
-	}
-
-	stats_dev = (struct msm_idle_stats_device *)
-			kzalloc(sizeof(*stats_dev), GFP_KERNEL);
-	if (!stats_dev) {
-		pr_err("%s: failed to allocate device struct\n", __func__);
-		rc = -ENOMEM;
-		goto open_bail;
-	}
-
-	stats_dev->cpu = MINOR(inode->i_rdev);
-	mutex_init(&stats_dev->mutex);
-	stats_dev->notifier.notifier_call = msm_idle_stats_notified;
-	hrtimer_init(&stats_dev->timer,
-			CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
-	stats_dev->timer.function = msm_idle_stats_timer;
-	init_waitqueue_head(&stats_dev->wait_q);
-	atomic_set(&stats_dev->collecting, 0);
-
-	filp->private_data = stats_dev;
-
-	/*
-	 * Make sure only one device exists per cpu.
-	 */
-	spin_lock(&msm_idle_stats_devs_lock);
-	if (per_cpu(msm_idle_stats_devs, stats_dev->cpu)) {
-		spin_unlock(&msm_idle_stats_devs_lock);
-		rc = -EBUSY;
-		goto open_free_bail;
-	}
-
-	per_cpu(msm_idle_stats_devs, stats_dev->cpu) = stats_dev;
-	spin_unlock(&msm_idle_stats_devs_lock);
-
-	rc = msm_cpuidle_register_notifier(stats_dev->cpu,
-						&stats_dev->notifier);
-	if (rc) {
-		pr_err("%s: failed to register idle notification\n", __func__);
-		goto open_null_bail;
-	}
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: done\n", __func__);
-	return 0;
-
-open_null_bail:
-	spin_lock(&msm_idle_stats_devs_lock);
-	per_cpu(msm_idle_stats_devs, stats_dev->cpu) = NULL;
-	spin_unlock(&msm_idle_stats_devs_lock);
-
-open_free_bail:
-	kfree(stats_dev);
-
-open_bail:
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: exit, %d\n", __func__, rc);
-	return rc;
-}
-
-static int msm_idle_stats_release(struct inode *inode, struct file *filp)
-{
-	struct msm_idle_stats_device *stats_dev;
-	int rc;
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: enter\n", __func__);
-
-	stats_dev = (struct msm_idle_stats_device *) filp->private_data;
-	rc = msm_cpuidle_unregister_notifier(stats_dev->cpu,
-						&stats_dev->notifier);
-	WARN_ON(rc);
-
-	spin_lock(&msm_idle_stats_devs_lock);
-	per_cpu(msm_idle_stats_devs, stats_dev->cpu) = NULL;
-	spin_unlock(&msm_idle_stats_devs_lock);
-	filp->private_data = NULL;
-
-	hrtimer_cancel(&stats_dev->timer);
-	kfree(stats_dev);
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: done\n", __func__);
-	return 0;
-}
-
-static long msm_idle_stats_ioctl(struct file *filp, unsigned int cmd,
-				unsigned long arg)
-{
-	int rc;
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: enter\n", __func__);
-
-	switch (cmd) {
-	case MSM_IDLE_STATS_IOC_COLLECT:
-		rc = msm_idle_stats_collect(filp, cmd, arg);
-		break;
-
-	default:
-		rc = -ENOTTY;
-		break;
-	}
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: exit, %d\n", __func__, rc);
-	return rc;
-}
-
-/******************************************************************************
- *
- *****************************************************************************/
-
-static const struct file_operations msm_idle_stats_fops = {
-	.owner   = THIS_MODULE,
-	.open    = msm_idle_stats_open,
-	.release = msm_idle_stats_release,
-	.unlocked_ioctl   = msm_idle_stats_ioctl,
-};
-
-static int __init msm_idle_stats_init(void)
-{
-	unsigned int nr_cpus = num_possible_cpus();
-	struct device *dev;
-	int rc;
-	int i;
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: enter\n", __func__);
-
-	rc = alloc_chrdev_region(&msm_idle_stats_dev_nr,
-			0, nr_cpus, MSM_IDLE_STATS_DRIVER_NAME);
-	if (rc) {
-		pr_err("%s: failed to allocate device number, rc %d\n",
-			__func__, rc);
-		goto init_bail;
-	}
-
-	msm_idle_stats_class = class_create(THIS_MODULE,
-					MSM_IDLE_STATS_DRIVER_NAME);
-	if (IS_ERR(msm_idle_stats_class)) {
-		pr_err("%s: failed to create device class\n", __func__);
-		rc = -ENOMEM;
-		goto init_unreg_bail;
-	}
-
-	for (i = 0; i < nr_cpus; i++) {
-		dev = device_create(msm_idle_stats_class, NULL,
-				msm_idle_stats_dev_nr + i, NULL,
-				MSM_IDLE_STATS_DRIVER_NAME "%d", i);
-
-		if (!dev) {
-			pr_err("%s: failed to create device %d\n",
-				__func__, i);
-			rc = -ENOMEM;
-			goto init_remove_bail;
-		}
-	}
-
-	cdev_init(&msm_idle_stats_cdev, &msm_idle_stats_fops);
-	msm_idle_stats_cdev.owner = THIS_MODULE;
-
-	/*
-	 * Call cdev_add() last, after everything else is initialized and
-	 * the driver is ready to accept system calls.
-	 */
-	rc = cdev_add(&msm_idle_stats_cdev, msm_idle_stats_dev_nr, nr_cpus);
-	if (rc) {
-		pr_err("%s: failed to register char device, rc %d\n",
-			__func__, rc);
-		goto init_remove_bail;
-	}
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: done\n", __func__);
-	return 0;
-
-init_remove_bail:
-	for (i = i - 1; i >= 0; i--)
-		device_destroy(
-			msm_idle_stats_class, msm_idle_stats_dev_nr + i);
-
-	class_destroy(msm_idle_stats_class);
-
-init_unreg_bail:
-	unregister_chrdev_region(msm_idle_stats_dev_nr, nr_cpus);
-
-init_bail:
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: exit, %d\n", __func__, rc);
-	return rc;
-}
-
-static void __exit msm_idle_stats_exit(void)
-{
-	unsigned int nr_cpus = num_possible_cpus();
-	int i;
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: enter\n", __func__);
-
-	cdev_del(&msm_idle_stats_cdev);
-
-	for (i = nr_cpus - 1; i >= 0; i--)
-		device_destroy(
-			msm_idle_stats_class, msm_idle_stats_dev_nr + i);
-
-	class_destroy(msm_idle_stats_class);
-	unregister_chrdev_region(msm_idle_stats_dev_nr, nr_cpus);
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: done\n", __func__);
-}
-
-module_init(msm_idle_stats_init);
-module_exit(msm_idle_stats_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("idle stats driver");
-MODULE_VERSION("1.0");
diff --git a/arch/arm/mach-msm/idle_stats.h b/arch/arm/mach-msm/idle_stats.h
deleted file mode 100644
index 6c8db1e..0000000
--- a/arch/arm/mach-msm/idle_stats.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __ARCH_ARM_MACH_MSM_IDLE_STATS_H
-#define __ARCH_ARM_MACH_MSM_IDLE_STATS_H
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-
-enum msm_idle_stats_event {
-	MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED = 1,
-	MSM_IDLE_STATS_EVENT_COLLECTION_TIMER_EXPIRED = 2,
-	MSM_IDLE_STATS_EVENT_COLLECTION_FULL = 3,
-	MSM_IDLE_STATS_EVENT_TIMER_MIGRATED = 4,
-};
-
-/*
- * All time, timer, and time interval values are in units of
- * microseconds unless stated otherwise.
- */
-#define MSM_IDLE_STATS_NR_MAX_INTERVALS 100
-#define MSM_IDLE_STATS_MAX_TIMER 1000000
-
-struct msm_idle_stats {
-	__u32 busy_timer;
-	__u32 collection_timer;
-
-	__u32 busy_intervals[MSM_IDLE_STATS_NR_MAX_INTERVALS];
-	__u32 idle_intervals[MSM_IDLE_STATS_NR_MAX_INTERVALS];
-	__u32 nr_collected;
-	__s64 last_busy_start;
-	__s64 last_idle_start;
-
-	enum msm_idle_stats_event event;
-	__s64 return_timestamp;
-};
-
-#define MSM_IDLE_STATS_IOC_MAGIC  0xD8
-#define MSM_IDLE_STATS_IOC_COLLECT  \
-		_IOWR(MSM_IDLE_STATS_IOC_MAGIC, 1, struct msm_idle_stats)
-
-#endif  /* __ARCH_ARM_MACH_MSM_IDLE_STATS_H */
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 2667f267..4de4d51 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -334,6 +334,7 @@
 	MSM_ADSP_CODEC_AMRWB = 11,
 	MSM_ADSP_CODEC_EVRC = 12,
 	MSM_ADSP_CODEC_WMAPRO = 13,
+	MSM_ADSP_CODEC_AC3 = 23,
 	MSM_ADSP_MODE_TUNNEL = 24,
 	MSM_ADSP_MODE_NONTUNNEL = 25,
 	MSM_ADSP_MODE_LP = 26,
@@ -391,9 +392,7 @@
 	void (*panel_config_gpio)(int);
 	int (*vga_switch)(int select_vga);
 	int *gpio_num;
-	int mdp_core_clk_rate;
-	unsigned num_mdp_clk;
-	int *mdp_core_clk_table;
+	u32 mdp_max_clk;
 #ifdef CONFIG_MSM_BUS_SCALING
 	struct msm_bus_scale_pdata *mdp_bus_scale_table;
 #endif
@@ -596,6 +595,7 @@
 void msm_8974_reserve(void);
 void msm_8974_very_early(void);
 void msm_8974_init_gpiomux(void);
+void msm9625_init_gpiomux(void);
 
 struct mmc_platform_data;
 int msm_add_sdcc(unsigned int controller,
diff --git a/arch/arm/mach-msm/include/mach/cpuidle.h b/arch/arm/mach-msm/include/mach/cpuidle.h
index 2a5aa97..af773a0 100644
--- a/arch/arm/mach-msm/include/mach/cpuidle.h
+++ b/arch/arm/mach-msm/include/mach/cpuidle.h
@@ -25,31 +25,16 @@
 	enum msm_pm_sleep_mode mode_nr;
 };
 
-#ifdef CONFIG_CPU_IDLE
+#ifdef CONFIG_PM
 s32 msm_cpuidle_get_deep_idle_latency(void);
-int msm_cpuidle_init(void);
 #else
-static inline int msm_cpuidle_init(void) { return -ENOSYS; }
 static inline s32 msm_cpuidle_get_deep_idle_latency(void) { return 0; }
 #endif
 
-#ifdef CONFIG_MSM_SLEEP_STATS
-enum {
-	MSM_CPUIDLE_STATE_ENTER,
-	MSM_CPUIDLE_STATE_EXIT
-};
-
-int msm_cpuidle_register_notifier(unsigned int cpu,
-		struct notifier_block *nb);
-int msm_cpuidle_unregister_notifier(unsigned int cpu,
-		struct notifier_block *nb);
+#ifdef CONFIG_CPU_IDLE
+int msm_cpuidle_init(void);
 #else
-static inline int msm_cpuidle_register_notifier(unsigned int cpu,
-		struct notifier_block *nb)
-{ return -ENODEV; }
-static inline int msm_cpuidle_unregister_notifier(unsigned int cpu,
-		struct notifier_block *nb)
-{ return -ENODEV; }
+static inline int msm_cpuidle_init(void) { return -ENOSYS; }
 #endif
 
 #endif /* __ARCH_ARM_MACH_MSM_CPUIDLE_H */
diff --git a/arch/arm/mach-msm/include/mach/dal_axi.h b/arch/arm/mach-msm/include/mach/dal_axi.h
index 4e32aa3..84cd37f 100644
--- a/arch/arm/mach-msm/include/mach/dal_axi.h
+++ b/arch/arm/mach-msm/include/mach/dal_axi.h
@@ -17,5 +17,7 @@
 int set_grp2d_async(void);
 int set_grp3d_async(void);
 int set_grp_xbar_async(void);
-
+int axi_allocate(int mode);
+int axi_free(int mode);
+#define AXI_FLOW_VIEWFINDER_HI	243
 #endif  /* _DAL_AXI_H */
diff --git a/arch/arm/mach-msm/include/mach/irqs-9625.h b/arch/arm/mach-msm/include/mach/irqs-9625.h
index 91b4d07..f50606d 100644
--- a/arch/arm/mach-msm/include/mach/irqs-9625.h
+++ b/arch/arm/mach-msm/include/mach/irqs-9625.h
@@ -21,11 +21,11 @@
  * 32+:   SPI (shared peripheral interrupts)
  */
 
+#define GIC_SPI_START 32
 
 #define APCC_QGICL2PERFMONIRPTREQ	(GIC_SPI_START + 1)
 #define SC_SICL2PERFMONIRPTREQ		APCC_QGICL2PERFMONIRPTREQ
-#define TLMM_MSM_SUMMARY_IRQ		(GIC_SPI_START + 16)
-#define SPS_BAM_DMA_IRQ			(GIC_SPI_START + 208)
+#define TLMM_MSM_SUMMARY_IRQ		(GIC_SPI_START + 208)
 
 #define NR_MSM_IRQS 288
 #define NR_GPIO_IRQS 88
diff --git a/arch/arm/mach-msm/include/mach/mdm2.h b/arch/arm/mach-msm/include/mach/mdm2.h
index c4877cc..6ec12c1 100644
--- a/arch/arm/mach-msm/include/mach/mdm2.h
+++ b/arch/arm/mach-msm/include/mach/mdm2.h
@@ -32,6 +32,7 @@
 	struct platform_device *peripheral_platform_device;
 	const unsigned int ramdump_timeout_ms;
 	int image_upgrade_supported;
+	struct gpiomux_setting *mdm2ap_status_gpio_run_cfg;
 };
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h
index 4f8e0c1..1c7b2fb 100644
--- a/arch/arm/mach-msm/include/mach/memory.h
+++ b/arch/arm/mach-msm/include/mach/memory.h
@@ -78,6 +78,7 @@
 int platform_physical_remove_pages(u64, u64);
 int platform_physical_active_pages(u64, u64);
 int platform_physical_low_power_pages(u64, u64);
+int msm_get_memory_type_from_name(const char *memtype_name);
 
 extern int (*change_memory_power)(u64, u64, int);
 
diff --git a/arch/arm/mach-msm/include/mach/msm_hsusb.h b/arch/arm/mach-msm/include/mach/msm_hsusb.h
index 4f140cc..4e22b0f 100644
--- a/arch/arm/mach-msm/include/mach/msm_hsusb.h
+++ b/arch/arm/mach-msm/include/mach/msm_hsusb.h
@@ -202,8 +202,4 @@
 	struct clk *ebi1_clk;
 };
 
-int msm_ep_config(struct usb_ep *ep);
-int msm_ep_unconfig(struct usb_ep *ep);
-int msm_data_fifo_config(struct usb_ep *ep, u32 addr, u32 size);
-
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8974.h b/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
index fb61d54..1458afe 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
@@ -37,6 +37,9 @@
 #define MSM8974_TLMM_PHYS	0xFD510000
 #define MSM8974_TLMM_SIZE	SZ_16K
 
+#define MSM8974_MPM2_PSHOLD_PHYS	0xFC4AB000
+#define MSM8974_MPM2_PSHOLD_SIZE	SZ_4K
+
 #ifdef CONFIG_DEBUG_MSM8974_UART
 #define MSM_DEBUG_UART_BASE	IOMEM(0xFA71E000)
 #define MSM_DEBUG_UART_PHYS	0xF991E000
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
index 4f90ea5..17156b1f 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -126,6 +126,9 @@
 #define MSM_HDMI_PHYS		0x04A00000
 #define MSM_HDMI_SIZE		SZ_4K
 
+/* Needed to keep the unified iomap happy */
+#define MSM_MPM2_PSHOLD_BASE	MSM_TLMM_BASE
+
 #ifdef CONFIG_DEBUG_MSM8660_UART
 #define MSM_DEBUG_UART_BASE	0xFBC40000
 #define MSM_DEBUG_UART_PHYS	0x19C40000
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 7085db7..4c849d4 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -93,6 +93,7 @@
 #define MSM_SCU_BASE		IOMEM(0xFA104000)	/*  4K */
 #define MSM_CFG_CTL_BASE	IOMEM(0xFA105000)	/*  4K */
 #define MSM_CLK_CTL_SH2_BASE	IOMEM(0xFA106000)	/*  4K */
+#define MSM_MPM2_PSHOLD_BASE	IOMEM(0xFA107000)	/*  4k */
 #define MSM_MDC_BASE		IOMEM(0xFA400000)	/*  1M */
 #define MSM_AD5_BASE		IOMEM(0xFA900000)	/*  13M (D00000)
 							  0xFB600000 */
diff --git a/arch/arm/mach-msm/include/mach/msm_pcie.h b/arch/arm/mach-msm/include/mach/msm_pcie.h
index 8bc4317..74f0f5b 100644
--- a/arch/arm/mach-msm/include/mach/msm_pcie.h
+++ b/arch/arm/mach-msm/include/mach/msm_pcie.h
@@ -22,7 +22,7 @@
 	MSM_PCIE_MAX_GPIO
 };
 
-/* gpio info structrue */
+/* gpio info structure */
 struct msm_pcie_gpio_info_t {
 	char      *name;
 	uint32_t   num;
@@ -32,8 +32,10 @@
 /* msm pcie platfrom data */
 struct msm_pcie_platform {
 	struct msm_pcie_gpio_info_t  *gpio;
+
 	uint32_t                      axi_addr;
 	uint32_t                      axi_size;
+	uint32_t                      wake_n;
 };
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/ocmem.h b/arch/arm/mach-msm/include/mach/ocmem.h
index 415f8ed..904de5e 100644
--- a/arch/arm/mach-msm/include/mach/ocmem.h
+++ b/arch/arm/mach-msm/include/mach/ocmem.h
@@ -47,6 +47,24 @@
 	struct ocmem_chunk chunks[OCMEM_MAX_CHUNKS];
 };
 
+enum ocmem_power_state {
+	OCMEM_OFF = 0x0,
+	OCMEM_RETENTION,
+	OCMEM_ON,
+	OCMEM_MAX = OCMEM_ON,
+};
+
+struct ocmem_resource {
+	unsigned resource_id;
+	unsigned num_keys;
+	unsigned int *keys;
+};
+
+struct ocmem_vectors {
+	unsigned num_resources;
+	struct ocmem_resource *r;
+};
+
 /* List of clients that allocate/interact with OCMEM */
 /* Must be in sync with client_names */
 enum ocmem_client {
@@ -120,4 +138,14 @@
 int ocmem_evict(int client_id);
 
 int ocmem_restore(int client_id);
+
+/* Power Control APIs */
+int ocmem_set_power_state(int client_id, struct ocmem_buf *buf,
+				enum ocmem_power_state new_state);
+
+enum ocmem_power_state ocmem_get_power_state(int client_id,
+				struct ocmem_buf *buf);
+
+struct ocmem_vectors *ocmem_get_vectors(int client_id,
+						struct ocmem_buf *buf);
 #endif
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 70b5a45..a5b0275 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -16,11 +16,12 @@
 /** All interfaces in this header should only be used by OCMEM driver
  *  Client drivers should use wrappers available in ocmem.h
  **/
-
-#include "ocmem.h"
-#include <mach/msm_iomap.h>
-#include <asm/io.h>
 #include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/io.h>
+#include <mach/msm_iomap.h>
+#include "ocmem.h"
+
 
 #define OCMEM_PHYS_BASE 0xFEC00000
 #define OCMEM_PHYS_SIZE 0x180000
@@ -36,6 +37,7 @@
 };
 
 struct ocmem_zone {
+	bool active;
 	int owner;
 	int active_regions;
 	int max_regions;
@@ -62,10 +64,19 @@
 	SCHED_DUMP,
 };
 
+/* Operational modes of each region */
+enum region_mode {
+	WIDE_MODE = 0x0,
+	THIN_MODE,
+	MODE_DEFAULT = WIDE_MODE,
+};
+
 struct ocmem_plat_data {
 	void __iomem *vbase;
 	unsigned long size;
 	unsigned long base;
+	struct clk *core_clk;
+	struct clk *iface_clk;
 	struct ocmem_partition *parts;
 	int nr_parts;
 	void __iomem *reg_base;
@@ -77,6 +88,8 @@
 	int ocmem_irq;
 	int dm_irq;
 	bool interleaved;
+	bool rpm_pwr_ctrl;
+	unsigned rpm_rsc_type;
 };
 
 struct ocmem_eviction_data {
@@ -113,6 +126,8 @@
 	unsigned long req_start;
 	unsigned long req_end;
 	unsigned long req_sz;
+	/* Request Power State */
+	unsigned power_state;
 	struct ocmem_eviction_data *edata;
 };
 
@@ -154,7 +169,20 @@
 		return NULL;
 }
 
+/* Simple wrappers which will have debug features added later */
+static inline int ocmem_read(void *at)
+{
+	return readl_relaxed(at);
+}
+
+static inline int ocmem_write(unsigned long val, void *at)
+{
+	writel_relaxed(val, at);
+	return 0;
+}
+
 struct ocmem_zone *get_zone(unsigned);
+int zone_active(int);
 unsigned long offset_to_phys(unsigned long);
 unsigned long phys_to_offset(unsigned long);
 unsigned long allocate_head(struct ocmem_zone *, unsigned long);
@@ -170,6 +198,7 @@
 
 int ocmem_sched_init(void);
 int ocmem_rdm_init(struct platform_device *);
+int ocmem_core_init(struct platform_device *);
 int process_allocate(int, struct ocmem_handle *, unsigned long, unsigned long,
 			unsigned long, bool, bool);
 int process_free(int, struct ocmem_handle *);
@@ -180,4 +209,10 @@
 int ocmem_rdm_transfer(int, struct ocmem_map_list *,
 				unsigned long, int);
 unsigned long process_quota(int);
+int ocmem_memory_off(int, unsigned long, unsigned long);
+int ocmem_memory_on(int, unsigned long, unsigned long);
+int ocmem_enable_core_clock(void);
+int ocmem_enable_iface_clock(void);
+void ocmem_disable_core_clock(void);
+void ocmem_disable_iface_clock(void);
 #endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h
index 98f20a2..3115299 100644
--- a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h
@@ -414,6 +414,7 @@
 /*
  * Command Structure to configure Per decoder Parameters (AMRWB)
  */
+#define ADEC_PARAMS_AC3_INDEX 14
 
 struct audpp_cmd_cfg_adec_params_amrwb {
 	   audpp_cmd_cfg_adec_params_common     common;
@@ -424,6 +425,18 @@
 	sizeof(struct audpp_cmd_cfg_adec_params_amrwb)
 
 /*
+ * Command Structure to configure Per decoder Parameters (AC3)
+ */
+
+struct audpp_cmd_cfg_adec_params_ac3 {
+	audpp_cmd_cfg_adec_params_common	common;
+	unsigned short				index[ADEC_PARAMS_AC3_INDEX];
+} __packed;
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_AC3_LEN \
+	sizeof(struct audpp_cmd_cfg_adec_params_ac3)
+
+/*
  * Command Structure to configure the  HOST PCM interface
  */
 
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
index 62d7a33..296f222 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
@@ -13,13 +13,18 @@
 #ifndef __APR_H_
 #define __APR_H_
 
-#define APR_Q6_NOIMG   0
-#define APR_Q6_LOADING 1
-#define APR_Q6_LOADED  2
+#include <linux/mutex.h>
+
+enum apr_subsys_state {
+	APR_SUBSYS_DOWN,
+	APR_SUBSYS_UP,
+	APR_SUBSYS_LOADED,
+};
 
 struct apr_q6 {
 	void *pil;
-	uint32_t state;
+	atomic_t q6_state;
+	atomic_t modem_state;
 	struct mutex lock;
 };
 
@@ -138,6 +143,12 @@
 	struct apr_svc svc[APR_SVC_MAX];
 };
 
+int apr_load_adsp_image(void);
+struct apr_client *apr_get_client(int dest_id, int client_id);
+int apr_wait_for_device_up(int dest_id);
+int apr_get_svc(const char *svc_name, int dest_id, int *client_id,
+		int *svc_idx, int *svc_id);
+void apr_cb_func(void *buf, int len, void *priv);
 struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
 					uint32_t src_port, void *priv);
 inline int apr_fill_hdr(void *handle, uint32_t *buf, uint16_t src_port,
@@ -149,4 +160,9 @@
 void change_q6_state(int state);
 void q6audio_dsp_not_responding(void);
 void apr_reset(void *handle);
+enum apr_subsys_state apr_get_modem_state(void);
+void apr_set_modem_state(enum apr_subsys_state state);
+enum apr_subsys_state apr_get_q6_state(void);
+int apr_set_q6_state(enum apr_subsys_state state);
+void apr_set_subsys_state(void);
 #endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h b/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h
index 684f9d3..47056a8 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h
@@ -100,6 +100,7 @@
 	RPM_VREG_ID_PM8038_L10,
 	RPM_VREG_ID_PM8038_L11,
 	RPM_VREG_ID_PM8038_L12,
+	RPM_VREG_ID_PM8038_L13,
 	RPM_VREG_ID_PM8038_L14,
 	RPM_VREG_ID_PM8038_L15,
 	RPM_VREG_ID_PM8038_L16,
@@ -111,6 +112,7 @@
 	RPM_VREG_ID_PM8038_L22,
 	RPM_VREG_ID_PM8038_L23,
 	RPM_VREG_ID_PM8038_L24,
+	RPM_VREG_ID_PM8038_L25,
 	RPM_VREG_ID_PM8038_L26,
 	RPM_VREG_ID_PM8038_L27,
 	RPM_VREG_ID_PM8038_S1,
@@ -154,6 +156,7 @@
 };
 
 /* Minimum high power mode loads in uA. */
+#define RPM_VREG_8930_LDO_5_HPM_MIN_LOAD		0
 #define RPM_VREG_8930_LDO_50_HPM_MIN_LOAD		5000
 #define RPM_VREG_8930_LDO_150_HPM_MIN_LOAD		10000
 #define RPM_VREG_8930_LDO_300_HPM_MIN_LOAD		10000
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator.h b/arch/arm/mach-msm/include/mach/rpm-regulator.h
index 1f4ef2d..d2ff2fe 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator.h
@@ -165,6 +165,7 @@
 	enum rpm_vreg_version			version;
 	int					vreg_id_vdd_mem;
 	int					vreg_id_vdd_dig;
+	bool					requires_tcxo_workaround;
 	struct rpm_regulator_consumer_mapping	*consumer_map;
 	int					consumer_map_len;
 };
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index 319a3ec..edc4b39 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -59,6 +59,9 @@
 #define SPS_IOVEC_FLAG_NO_SUBMIT 0x0002  /* Do not submit descriptor to HW */
 #define SPS_IOVEC_FLAG_DEFAULT   0x0001  /* Use driver default */
 
+/* Maximum descriptor/iovec size */
+#define SPS_IOVEC_MAX_SIZE   (32 * 1024 - 1)  /* 32K-1 bytes due to HW limit */
+
 /* BAM device options flags */
 
 /*
@@ -103,6 +106,9 @@
 #define SPS_BAM_SEC_DO_NOT_CONFIG   0
 #define SPS_BAM_SEC_DO_CONFIG       0x0A434553
 
+/* BAM pipe selection */
+#define SPS_BAM_PIPE(n)             (1UL << (n))
+
 /* This enum specifies the operational mode for an SPS connection */
 enum sps_mode {
 	SPS_MODE_SRC = 0,  /* end point is the source (producer) */
@@ -1232,6 +1238,20 @@
  */
 int sps_get_unused_desc_num(struct sps_pipe *h, u32 *desc_num);
 
+/**
+ * Get the debug info of BAM registers and descriptor FIFOs
+ *
+ * @dev - BAM device handle
+ *
+ * @option - debugging option
+ *
+ * @para - parameter used for an option (such as pipe combination)
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_get_bam_debug_info(u32 dev, u32 option, u32 para);
+
 #else
 static inline int sps_register_bam_device(const struct sps_bam_props
 			*bam_props, u32 *dev_handle)
@@ -1388,6 +1408,11 @@
 {
 	return -EPERM;
 }
+
+static inline int sps_get_bam_debug_info(u32 dev, u32 option, u32 para)
+{
+	return -EPERM;
+}
 #endif
 
 #endif /* _SPS_H_ */
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index ec135a3..47313a7 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -12,6 +12,7 @@
 
 #ifndef _USB_BAM_H_
 #define _USB_BAM_H_
+#include "sps.h"
 
 /**
  * SPS Pipes direction.
@@ -43,7 +44,7 @@
  * @return 0 on success, negative value on error
  *
  */
-int usb_bam_connect(u8 idx, u8 *src_pipe_idx, u8 *dst_pipe_idx);
+int usb_bam_connect(u8 idx, u32 *src_pipe_idx, u32 *dst_pipe_idx);
 
 /**
  * Register a wakeup callback from peer BAM.
@@ -57,8 +58,40 @@
  */
 int usb_bam_register_wake_cb(u8 idx,
 	 int (*callback)(void *), void* param);
+
+/**
+ * Disconnect USB-to-Periperal SPS connection.
+ *
+ * @idx - Connection index.
+ *
+ * @return 0 on success, negative value on error
+ */
+int usb_bam_disconnect_pipe(u8 idx);
+
+/**
+ * Returns usb bam connection parameters.
+ *
+ * @conn_idx - Connection index.
+ *
+ * @usb_bam_pipe_dir - Usb pipe direction to/from peripheral.
+ *
+ * @usb_bam_handle - Usb bam handle.
+ *
+ * @usb_bam_pipe_idx - Usb bam pipe index.
+ *
+ * @peer_pipe_idx - Peer pipe index.
+ *
+ * @desc_fifo - Descriptor fifo parameters.
+ *
+ * @data_fifo - Data fifo parameters.
+ *
+ */
+void get_bam2bam_connection_info(u8 conn_idx, enum usb_bam_pipe_dir pipe_dir,
+	u32 *usb_bam_handle, u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
+	struct sps_mem_buffer *desc_fifo, struct sps_mem_buffer *data_fifo);
+
 #else
-static inline int usb_bam_connect(u8 idx, u8 *src_pipe_idx, u8 *dst_pipe_idx)
+static inline int usb_bam_connect(u8 idx, u32 *src_pipe_idx, u32 *dst_pipe_idx)
 {
 	return -ENODEV;
 }
@@ -68,6 +101,18 @@
 {
 	return -ENODEV;
 }
+
+static inline int usb_bam_disconnect_pipe(u8 idx)
+{
+	return -ENODEV;
+}
+
+static inline void get_bam2bam_connection_info(u8 conn_idx,
+	enum usb_bam_pipe_dir pipe_dir, u32 *usb_bam_handle,
+	u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
+	struct sps_mem_buffer *desc_fifo, struct sps_mem_buffer *data_fifo)
+{
+	return;
+}
 #endif
 #endif				/* _USB_BAM_H_ */
-
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index a2f2c31..89964de 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -300,6 +300,7 @@
 	MSM_CHIP_DEVICE(QGIC_CPU, MSM8974),
 	MSM_CHIP_DEVICE(APCS_GCC, MSM8974),
 	MSM_CHIP_DEVICE(TLMM, MSM8974),
+	MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM8974),
 	{
 		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
 		.length =   MSM_SHARED_RAM_SIZE,
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index c0bff63..7dc8d0f 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -130,7 +130,6 @@
 	uint32_t remote_node_id;
 	uint32_t initialized;
 	struct list_head pkt_list;
-	wait_queue_head_t read_wait;
 	struct wake_lock wakelock;
 	struct mutex rx_lock;
 	struct mutex tx_lock;
@@ -262,16 +261,15 @@
 		return NULL;
 
 	mutex_lock(&xprt_info->rx_lock);
-	while (!(xprt_info->abort_data_read) &&
-		list_empty(&xprt_info->pkt_list)) {
-		mutex_unlock(&xprt_info->rx_lock);
-		wait_event(xprt_info->read_wait,
-			   ((xprt_info->abort_data_read) ||
-			   !list_empty(&xprt_info->pkt_list)));
-		mutex_lock(&xprt_info->rx_lock);
-	}
 	if (xprt_info->abort_data_read) {
 		mutex_unlock(&xprt_info->rx_lock);
+		pr_err("%s detected SSR & exiting now\n",
+			xprt_info->xprt->name);
+		return NULL;
+	}
+
+	if (list_empty(&xprt_info->pkt_list)) {
+		mutex_unlock(&xprt_info->rx_lock);
 		return NULL;
 	}
 
@@ -1364,144 +1362,135 @@
 			     struct msm_ipc_router_xprt_info,
 			     read_data);
 
-	pkt = rr_read(xprt_info);
-	if (!pkt) {
-		pr_err("%s: rr_read failed\n", __func__);
-		goto fail_io;
-	}
+	while ((pkt = rr_read(xprt_info)) != NULL) {
+		if (pkt->length < IPC_ROUTER_HDR_SIZE ||
+		    pkt->length > MAX_IPC_PKT_SIZE) {
+			pr_err("%s: Invalid pkt length %d\n",
+				__func__, pkt->length);
+			goto fail_data;
+		}
 
-	if (pkt->length < IPC_ROUTER_HDR_SIZE ||
-	    pkt->length > MAX_IPC_PKT_SIZE) {
-		pr_err("%s: Invalid pkt length %d\n", __func__, pkt->length);
-		goto fail_data;
-	}
+		head_skb = skb_peek(pkt->pkt_fragment_q);
+		if (!head_skb) {
+			pr_err("%s: head_skb is invalid\n", __func__);
+			goto fail_data;
+		}
 
-	head_skb = skb_peek(pkt->pkt_fragment_q);
-	if (!head_skb) {
-		pr_err("%s: head_skb is invalid\n", __func__);
-		goto fail_data;
-	}
+		hdr = (struct rr_header *)(head_skb->data);
+		RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
+		   hdr->version, hdr->type, hdr->src_node_id, hdr->src_port_id,
+		   hdr->confirm_rx, hdr->size, hdr->dst_node_id,
+		   hdr->dst_port_id);
 
-	hdr = (struct rr_header *)(head_skb->data);
-	RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
-	   hdr->version, hdr->type, hdr->src_node_id, hdr->src_port_id,
-	   hdr->confirm_rx, hdr->size, hdr->dst_node_id, hdr->dst_port_id);
-	RAW_HDR("[r rr_h] "
-		"ver=%i,type=%s,src_node_id=%08x,src_port_id=%08x,"
-		"confirm_rx=%i,size=%3i,dst_node_id=%08x,dst_port_id=%08x\n",
-		hdr->version, type_to_str(hdr->type), hdr->src_node_id,
-		hdr->src_port_id, hdr->confirm_rx, hdr->size, hdr->dst_node_id,
-		hdr->dst_port_id);
+		if (hdr->version != IPC_ROUTER_VERSION) {
+			pr_err("version %d != %d\n",
+				hdr->version, IPC_ROUTER_VERSION);
+			goto fail_data;
+		}
 
-	if (hdr->version != IPC_ROUTER_VERSION) {
-		pr_err("version %d != %d\n", hdr->version, IPC_ROUTER_VERSION);
-		goto fail_data;
-	}
+		if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
+		    ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
+		     (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
+			forward_msg(xprt_info, pkt);
+			release_pkt(pkt);
+			continue;
+		}
 
-	if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
-	    ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
-	     (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
-		forward_msg(xprt_info, pkt);
-		release_pkt(pkt);
-		goto done;
-	}
-
-	if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
-	    (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
-		process_control_msg(xprt_info, pkt);
-		release_pkt(pkt);
-		goto done;
-	}
+		if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
+		    (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
+			process_control_msg(xprt_info, pkt);
+			release_pkt(pkt);
+			continue;
+		}
 #if defined(CONFIG_MSM_SMD_LOGGING)
 #if defined(DEBUG)
-	if (msm_ipc_router_debug_mask & SMEM_LOG) {
-		smem_log_event((SMEM_LOG_PROC_ID_APPS |
-			SMEM_LOG_RPC_ROUTER_EVENT_BASE |
-			IPC_ROUTER_LOG_EVENT_RX),
-			(hdr->src_node_id << 24) |
-			(hdr->src_port_id & 0xffffff),
-			(hdr->dst_node_id << 24) |
-			(hdr->dst_port_id & 0xffffff),
-			(hdr->type << 24) | (hdr->confirm_rx << 16) |
-			(hdr->size & 0xffff));
-	}
+		if (msm_ipc_router_debug_mask & SMEM_LOG) {
+			smem_log_event((SMEM_LOG_PROC_ID_APPS |
+				SMEM_LOG_RPC_ROUTER_EVENT_BASE |
+				IPC_ROUTER_LOG_EVENT_RX),
+				(hdr->src_node_id << 24) |
+				(hdr->src_port_id & 0xffffff),
+				(hdr->dst_node_id << 24) |
+				(hdr->dst_port_id & 0xffffff),
+				(hdr->type << 24) | (hdr->confirm_rx << 16) |
+				(hdr->size & 0xffff));
+		}
 #endif
 #endif
 
-	resume_tx = hdr->confirm_rx;
-	resume_tx_node_id = hdr->dst_node_id;
-	resume_tx_port_id = hdr->dst_port_id;
+		resume_tx = hdr->confirm_rx;
+		resume_tx_node_id = hdr->dst_node_id;
+		resume_tx_port_id = hdr->dst_port_id;
 
-	rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
+		rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
 						      hdr->src_port_id);
 
-	mutex_lock(&local_ports_lock);
-	port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
-	if (!port_ptr) {
-		pr_err("%s: No local port id %08x\n", __func__,
-			hdr->dst_port_id);
-		mutex_unlock(&local_ports_lock);
-		release_pkt(pkt);
-		goto process_done;
-	}
-
-	if (!rport_ptr) {
-		rport_ptr = msm_ipc_router_create_remote_port(
-							hdr->src_node_id,
-							hdr->src_port_id);
-		if (!rport_ptr) {
-			pr_err("%s: Remote port %08x:%08x creation failed\n",
-				__func__, hdr->src_node_id, hdr->src_port_id);
+		mutex_lock(&local_ports_lock);
+		port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
+		if (!port_ptr) {
+			pr_err("%s: No local port id %08x\n", __func__,
+				hdr->dst_port_id);
 			mutex_unlock(&local_ports_lock);
+			release_pkt(pkt);
 			goto process_done;
 		}
-	}
 
-	if (!port_ptr->notify) {
-		mutex_lock(&port_ptr->port_rx_q_lock);
-		wake_lock(&port_ptr->port_rx_wake_lock);
-		list_add_tail(&pkt->list, &port_ptr->port_rx_q);
-		wake_up(&port_ptr->port_rx_wait_q);
-		mutex_unlock(&port_ptr->port_rx_q_lock);
-		mutex_unlock(&local_ports_lock);
-	} else {
-		mutex_lock(&port_ptr->port_rx_q_lock);
-		src_addr = kmalloc(sizeof(struct msm_ipc_port_addr),
-				   GFP_KERNEL);
-		if (src_addr) {
-			src_addr->node_id = hdr->src_node_id;
-			src_addr->port_id = hdr->src_port_id;
+		if (!rport_ptr) {
+			rport_ptr = msm_ipc_router_create_remote_port(
+							hdr->src_node_id,
+							hdr->src_port_id);
+			if (!rport_ptr) {
+				pr_err("%s: Rmt Prt %08x:%08x create failed\n",
+					__func__, hdr->src_node_id,
+					hdr->src_port_id);
+				mutex_unlock(&local_ports_lock);
+				goto process_done;
+			}
 		}
-		skb_pull(head_skb, IPC_ROUTER_HDR_SIZE);
-		mutex_unlock(&local_ports_lock);
-		port_ptr->notify(MSM_IPC_ROUTER_READ_CB, pkt->pkt_fragment_q,
-				 src_addr, port_ptr->priv);
-		mutex_unlock(&port_ptr->port_rx_q_lock);
-		pkt->pkt_fragment_q = NULL;
-		src_addr = NULL;
-		release_pkt(pkt);
-	}
+
+		if (!port_ptr->notify) {
+			mutex_lock(&port_ptr->port_rx_q_lock);
+			wake_lock(&port_ptr->port_rx_wake_lock);
+			list_add_tail(&pkt->list, &port_ptr->port_rx_q);
+			wake_up(&port_ptr->port_rx_wait_q);
+			mutex_unlock(&port_ptr->port_rx_q_lock);
+			mutex_unlock(&local_ports_lock);
+		} else {
+			mutex_lock(&port_ptr->port_rx_q_lock);
+			src_addr = kmalloc(sizeof(struct msm_ipc_port_addr),
+					   GFP_KERNEL);
+			if (src_addr) {
+				src_addr->node_id = hdr->src_node_id;
+				src_addr->port_id = hdr->src_port_id;
+			}
+			skb_pull(head_skb, IPC_ROUTER_HDR_SIZE);
+			mutex_unlock(&local_ports_lock);
+			port_ptr->notify(MSM_IPC_ROUTER_READ_CB,
+				pkt->pkt_fragment_q, src_addr, port_ptr->priv);
+			mutex_unlock(&port_ptr->port_rx_q_lock);
+			pkt->pkt_fragment_q = NULL;
+			src_addr = NULL;
+			release_pkt(pkt);
+		}
 
 process_done:
-	if (resume_tx) {
-		union rr_control_msg msg;
+		if (resume_tx) {
+			union rr_control_msg msg;
 
-		msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
-		msg.cli.node_id = resume_tx_node_id;
-		msg.cli.port_id = resume_tx_port_id;
+			msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
+			msg.cli.node_id = resume_tx_node_id;
+			msg.cli.port_id = resume_tx_port_id;
 
-		RR("x RESUME_TX id=%d:%08x\n",
-		   msg.cli.node_id, msg.cli.port_id);
-		msm_ipc_router_send_control_msg(xprt_info, &msg);
+			RR("x RESUME_TX id=%d:%08x\n",
+			   msg.cli.node_id, msg.cli.port_id);
+			msm_ipc_router_send_control_msg(xprt_info, &msg);
+		}
+
 	}
-
-done:
-	queue_work(xprt_info->workqueue, &xprt_info->read_data);
 	return;
 
 fail_data:
 	release_pkt(pkt);
-fail_io:
 	pr_err("ipc_router has died\n");
 }
 
@@ -2334,7 +2323,6 @@
 	xprt_info->initialized = 0;
 	xprt_info->remote_node_id = -1;
 	INIT_LIST_HEAD(&xprt_info->pkt_list);
-	init_waitqueue_head(&xprt_info->read_wait);
 	mutex_init(&xprt_info->rx_lock);
 	mutex_init(&xprt_info->tx_lock);
 	wake_lock_init(&xprt_info->wakelock,
@@ -2368,8 +2356,6 @@
 	}
 	mutex_unlock(&routing_table_lock);
 
-	queue_work(xprt_info->workqueue, &xprt_info->read_data);
-
 	xprt->priv = xprt_info;
 
 	return 0;
@@ -2382,8 +2368,9 @@
 	if (xprt && xprt->priv) {
 		xprt_info = xprt->priv;
 
+		mutex_lock(&xprt_info->rx_lock);
 		xprt_info->abort_data_read = 1;
-		wake_up(&xprt_info->read_wait);
+		mutex_unlock(&xprt_info->rx_lock);
 
 		mutex_lock(&xprt_info_list_lock);
 		list_del(&xprt_info->list);
@@ -2481,8 +2468,8 @@
 	mutex_lock(&xprt_info->rx_lock);
 	list_add_tail(&pkt->list, &xprt_info->pkt_list);
 	wake_lock(&xprt_info->wakelock);
-	wake_up(&xprt_info->read_wait);
 	mutex_unlock(&xprt_info->rx_lock);
+	queue_work(xprt_info->workqueue, &xprt_info->read_data);
 }
 
 static int modem_restart_notifier_cb(struct notifier_block *this,
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
new file mode 100644
index 0000000..96c4809
--- /dev/null
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -0,0 +1,756 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/krait-regulator.h>
+
+#include "spm.h"
+
+/*
+ *                   supply
+ *                   from
+ *                   pmic
+ *                   gang
+ *                    |        LDO BYP [6]
+ *                    |         /
+ *                    |        /
+ *                    |_______/   _____
+ *                    |                |
+ *                 ___|___             |
+ *		  |       |            |
+ *		  |       |               /
+ *		  |  LDO  |              /
+ *		  |       |             /    BHS[6]
+ *                |_______|            |
+ *                    |                |
+ *                    |________________|
+ *                    |
+ *            ________|________
+ *           |                 |
+ *           |      KRAIT      |
+ *           |_________________|
+ */
+
+#define V_RETENTION			600000
+#define V_LDO_HEADROOM			150000
+
+#define PMIC_VOLTAGE_MIN		350000
+#define PMIC_VOLTAGE_MAX		1355000
+#define LV_RANGE_STEP			5000
+
+/* use LDO for core voltage below LDO_THRESH */
+#define CORE_VOLTAGE_LDO_THRESH		750000
+
+#define LOAD_PER_PHASE			3200000
+
+#define CORE_VOLTAGE_MIN		900000
+
+#define KRAIT_LDO_VOLTAGE_MIN		465000
+#define KRAIT_LDO_VOLTAGE_OFFSET	465000
+#define KRAIT_LDO_STEP			5000
+
+#define BHS_SETTLING_DELAY_US		1
+#define LDO_SETTLING_DELAY_US		1
+
+#define _KRAIT_MASK(BITS, POS)  (((u32)(1 << (BITS)) - 1) << POS)
+#define KRAIT_MASK(LEFT_BIT_POS, RIGHT_BIT_POS) \
+		_KRAIT_MASK(LEFT_BIT_POS - RIGHT_BIT_POS + 1, RIGHT_BIT_POS)
+
+#define APC_SECURE		0x00000000
+#define CPU_PWR_CTL		0x00000004
+#define APC_PWR_STATUS		0x00000008
+#define APC_TEST_BUS_SEL	0x0000000C
+#define CPU_TRGTD_DBG_RST	0x00000010
+#define APC_PWR_GATE_CTL	0x00000014
+#define APC_LDO_VREF_SET	0x00000018
+
+/* bit definitions for APC_PWR_GATE_CTL */
+#define BHS_CNT_BIT_POS		24
+#define BHS_CNT_MASK		KRAIT_MASK(31, 24)
+#define BHS_CNT_DEFAULT		64
+
+#define CLK_SRC_SEL_BIT_POS	15
+#define CLK_SRC_SEL_MASK	KRAIT_MASK(15, 15)
+#define CLK_SRC_DEFAULT		0
+
+#define LDO_PWR_DWN_BIT_POS	16
+#define LDO_PWR_DWN_MASK	KRAIT_MASK(21, 16)
+
+#define LDO_BYP_BIT_POS		8
+#define LDO_BYP_MASK		KRAIT_MASK(13, 8)
+
+#define BHS_SEG_EN_BIT_POS	1
+#define BHS_SEG_EN_MASK		KRAIT_MASK(6, 1)
+#define BHS_SEG_EN_DEFAULT	0x3F
+
+#define BHS_EN_BIT_POS		0
+#define BHS_EN_MASK		KRAIT_MASK(0, 0)
+
+/* bit definitions for APC_LDO_VREF_SET register */
+#define VREF_RET_POS		8
+#define VREF_RET_MASK		KRAIT_MASK(14, 8)
+
+#define VREF_LDO_BIT_POS	0
+#define VREF_LDO_MASK		KRAIT_MASK(6, 0)
+
+/**
+ * struct pmic_gang_vreg -
+ * @name:			the string used to represent the gang
+ * @pmic_vmax_uV:		the current pmic gang voltage
+ * @pmic_phase_count:		the number of phases turned on in the gang
+ * @krait_power_vregs:		a list of krait consumers this gang supplies to
+ * @krait_power_vregs_lock:	lock to prevent simultaneous access to the list
+ *				and its nodes. This needs to be taken by each
+ *				regulator's callback functions to prevent
+ *				simultaneous updates to the pmic's phase
+ *				voltage.
+ */
+struct pmic_gang_vreg {
+	const char		*name;
+	int			pmic_vmax_uV;
+	int			pmic_phase_count;
+	struct list_head	krait_power_vregs;
+	struct mutex		krait_power_vregs_lock;
+};
+
+static struct pmic_gang_vreg *the_gang;
+
+enum krait_supply_mode {
+	HS_MODE = REGULATOR_MODE_NORMAL,
+	LDO_MODE = REGULATOR_MODE_IDLE,
+};
+
+struct krait_power_vreg {
+	struct list_head		link;
+	struct regulator_desc		desc;
+	struct regulator_dev		*rdev;
+	const char			*name;
+	struct pmic_gang_vreg		*pvreg;
+	int				uV;
+	int				load_uA;
+	enum krait_supply_mode		mode;
+	void __iomem			*reg_base;
+};
+
+static void krait_masked_write(struct krait_power_vreg *kvreg,
+					int reg, uint32_t mask, uint32_t val)
+{
+	uint32_t reg_val;
+
+	reg_val = readl_relaxed(kvreg->reg_base + reg);
+	reg_val &= ~mask;
+	reg_val |= (val & mask);
+	writel_relaxed(reg_val, kvreg->reg_base + reg);
+
+	/*
+	 * Barrier to ensure that the reads and writes from
+	 * other regulator regions (they are 1k apart) execute in
+	 * order to the above write.
+	 */
+	mb();
+}
+
+static int get_krait_ldo_uv(struct krait_power_vreg *kvreg)
+{
+	uint32_t reg_val;
+	int uV;
+
+	reg_val = readl_relaxed(kvreg->reg_base + APC_LDO_VREF_SET);
+	reg_val &= VREF_LDO_MASK;
+	reg_val >>= VREF_LDO_BIT_POS;
+
+	if (reg_val == 0)
+		uV = 0;
+	else
+		uV = KRAIT_LDO_VOLTAGE_OFFSET + reg_val * KRAIT_LDO_STEP;
+
+	return uV;
+}
+
+static int set_krait_ldo_uv(struct krait_power_vreg *kvreg)
+{
+	uint32_t reg_val;
+
+	reg_val = kvreg->uV - KRAIT_LDO_VOLTAGE_OFFSET / KRAIT_LDO_STEP;
+	krait_masked_write(kvreg, APC_LDO_VREF_SET, VREF_LDO_MASK,
+						reg_val << VREF_LDO_BIT_POS);
+
+	return 0;
+}
+
+static int switch_to_using_hs(struct krait_power_vreg *kvreg)
+{
+	if (kvreg->mode == HS_MODE)
+		return 0;
+
+	/*
+	 * enable ldo bypass - the krait is powered still by LDO since
+	 * LDO is enabled and BHS is disabled
+	 */
+	krait_masked_write(kvreg, APC_PWR_GATE_CTL, LDO_BYP_MASK, LDO_BYP_MASK);
+
+	/* enable bhs */
+	krait_masked_write(kvreg, APC_PWR_GATE_CTL, BHS_EN_MASK, BHS_EN_MASK);
+
+	/*
+	 * wait for the bhs to settle - note that
+	 * after the voltage has settled both BHS and LDO are supplying power
+	 * to the krait. This avoids glitches during switching
+	 */
+	udelay(BHS_SETTLING_DELAY_US);
+
+	/* disable ldo - only the BHS provides voltage to the cpu after this */
+	krait_masked_write(kvreg, APC_PWR_GATE_CTL,
+				LDO_PWR_DWN_MASK, LDO_PWR_DWN_MASK);
+
+	kvreg->mode = HS_MODE;
+	return 0;
+}
+
+static int switch_to_using_ldo(struct krait_power_vreg *kvreg)
+{
+	if (kvreg->mode == LDO_MODE && get_krait_ldo_uv(kvreg) == kvreg->uV)
+		return 0;
+
+	/*
+	 * if the krait is in ldo mode and a voltage change is requested on the
+	 * ldo switch to using hs before changing ldo voltage
+	 */
+	if (kvreg->mode == LDO_MODE)
+		switch_to_using_hs(kvreg);
+
+	set_krait_ldo_uv(kvreg);
+
+	/*
+	 * enable ldo - note that both LDO and BHS are are supplying voltage to
+	 * the cpu after this. This avoids glitches during switching from BHS
+	 * to LDO.
+	 */
+	krait_masked_write(kvreg, APC_PWR_GATE_CTL, LDO_PWR_DWN_MASK, 0);
+
+	/* wait for the ldo to settle */
+	udelay(LDO_SETTLING_DELAY_US);
+
+	/*
+	 * disable BHS and disable LDO bypass seperate from enabling
+	 * the LDO above.
+	 */
+	krait_masked_write(kvreg, APC_PWR_GATE_CTL,
+		BHS_EN_MASK | LDO_BYP_MASK, 0);
+
+	kvreg->mode = LDO_MODE;
+	return 0;
+}
+
+static int set_pmic_gang_phases(int phase_count)
+{
+	/*
+	 * TODO : spm writes for phase control,
+	 * pmic phase control is not working yet
+	 */
+	return 0;
+}
+
+static int set_pmic_gang_voltage(int uV)
+{
+	int setpoint;
+
+	if (uV < PMIC_VOLTAGE_MIN) {
+		pr_err("requested %d < %d, restricting it to %d\n",
+				uV, PMIC_VOLTAGE_MIN, PMIC_VOLTAGE_MIN);
+		uV = PMIC_VOLTAGE_MIN;
+	}
+	if (uV > PMIC_VOLTAGE_MAX) {
+		pr_err("requested %d > %d, restricting it to %d\n",
+				uV, PMIC_VOLTAGE_MAX, PMIC_VOLTAGE_MAX);
+		uV = PMIC_VOLTAGE_MAX;
+	}
+
+	setpoint = DIV_ROUND_UP(uV, LV_RANGE_STEP);
+	return msm_spm_apcs_set_vdd(setpoint);
+}
+
+static int configure_ldo_or_hs(struct krait_power_vreg *from, int vmax)
+{
+	struct pmic_gang_vreg *pvreg = from->pvreg;
+	struct krait_power_vreg *kvreg;
+	int rc = 0;
+
+	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
+		if (kvreg->uV > CORE_VOLTAGE_LDO_THRESH
+			 || kvreg->uV > vmax - V_LDO_HEADROOM) {
+			rc = switch_to_using_hs(kvreg);
+			if (rc < 0) {
+				pr_err("could not switch %s to hs rc = %d\n",
+							kvreg->name, rc);
+				return rc;
+			}
+		} else {
+			rc = switch_to_using_ldo(kvreg);
+			if (rc < 0) {
+				pr_err("could not switch %s to ldo rc = %d\n",
+							kvreg->name, rc);
+				return rc;
+			}
+		}
+	}
+
+	return rc;
+}
+
+#define SLEW_RATE 2994
+static int pmic_gang_set_voltage_increase(struct krait_power_vreg *from,
+							int vmax)
+{
+	struct pmic_gang_vreg *pvreg = from->pvreg;
+	int rc = 0;
+	int settling_us;
+
+	/*
+	 * since pmic gang voltage is increasing set the gang voltage
+	 * prior to changing ldo/hs states of the requesting krait
+	 */
+	rc = set_pmic_gang_voltage(vmax);
+	if (rc < 0) {
+		dev_err(&from->rdev->dev, "%s failed set voltage %d rc = %d\n",
+				pvreg->name, vmax, rc);
+	}
+
+	/* delay until the voltage is settled when it is raised */
+	settling_us = DIV_ROUND_UP(vmax - pvreg->pmic_vmax_uV, SLEW_RATE);
+	udelay(settling_us);
+
+	rc = configure_ldo_or_hs(from, vmax);
+	if (rc < 0) {
+		dev_err(&from->rdev->dev, "%s failed ldo/hs conf %d rc = %d\n",
+				pvreg->name, vmax, rc);
+	}
+
+	return rc;
+}
+
+static int pmic_gang_set_voltage_decrease(struct krait_power_vreg *from,
+							int vmax)
+{
+	struct pmic_gang_vreg *pvreg = from->pvreg;
+	int rc = 0;
+
+	/*
+	 * since pmic gang voltage is decreasing ldos might get out of their
+	 * operating range. Hence configure such kraits to be in hs mode prior
+	 * to setting the pmic gang voltage
+	 */
+	rc = configure_ldo_or_hs(from, vmax);
+	if (rc < 0) {
+		dev_err(&from->rdev->dev, "%s failed ldo/hs conf %d rc = %d\n",
+				pvreg->name, vmax, rc);
+		return rc;
+	}
+
+	rc = set_pmic_gang_voltage(vmax);
+	if (rc < 0) {
+		dev_err(&from->rdev->dev, "%s failed set voltage %d rc = %d\n",
+				pvreg->name, vmax, rc);
+	}
+
+	return rc;
+}
+
+static int pmic_gang_set_voltage(struct krait_power_vreg *from,
+				 int vmax)
+{
+	struct pmic_gang_vreg *pvreg = from->pvreg;
+
+	if (pvreg->pmic_vmax_uV == vmax)
+		return 0;
+	else if (vmax < pvreg->pmic_vmax_uV)
+		return pmic_gang_set_voltage_decrease(from, vmax);
+
+	return pmic_gang_set_voltage_increase(from, vmax);
+}
+
+#define PHASE_SETTLING_TIME_US		10
+static unsigned int pmic_gang_set_phases(struct krait_power_vreg *from,
+				int load_uA)
+{
+	struct pmic_gang_vreg *pvreg = from->pvreg;
+	int phase_count = DIV_ROUND_UP(load_uA, LOAD_PER_PHASE) - 1;
+	int rc = 0;
+
+	if (phase_count < 0)
+		phase_count = 0;
+
+	if (phase_count != pvreg->pmic_phase_count) {
+		rc = set_pmic_gang_phases(phase_count);
+		if (rc < 0) {
+			dev_err(&from->rdev->dev,
+				"%s failed set phase %d rc = %d\n",
+				pvreg->name, phase_count, rc);
+			return rc;
+		}
+
+		/*
+		 * delay until the phases are settled when
+		 * the count is raised
+		 */
+		if (phase_count > pvreg->pmic_phase_count)
+			udelay(PHASE_SETTLING_TIME_US);
+
+		pvreg->pmic_phase_count = phase_count;
+	}
+	return rc;
+}
+
+static int __init pvreg_init(struct platform_device *pdev)
+{
+	struct pmic_gang_vreg *pvreg;
+
+	pvreg = devm_kzalloc(&pdev->dev,
+			sizeof(struct pmic_gang_vreg), GFP_KERNEL);
+	if (!pvreg) {
+		pr_err("kzalloc failed.\n");
+		return -ENOMEM;
+	}
+
+	pvreg->name = "pmic_gang";
+	pvreg->pmic_vmax_uV = PMIC_VOLTAGE_MIN;
+	pvreg->pmic_phase_count = 1;
+
+	mutex_init(&pvreg->krait_power_vregs_lock);
+	INIT_LIST_HEAD(&pvreg->krait_power_vregs);
+	the_gang = pvreg;
+
+	pr_debug("name=%s inited\n", pvreg->name);
+
+	return 0;
+}
+
+static int krait_power_get_voltage(struct regulator_dev *rdev)
+{
+	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
+
+	return kvreg->uV;
+}
+
+static int get_vmax(struct krait_power_vreg *from, int min_uV)
+{
+	int vmax = 0;
+	int v;
+	struct krait_power_vreg *kvreg;
+	struct pmic_gang_vreg *pvreg = from->pvreg;
+
+	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
+		v = kvreg->uV;
+
+		if (kvreg == from)
+			v = min_uV;
+
+		if (vmax < v)
+			vmax = v;
+	}
+	return vmax;
+}
+
+static int get_total_load(struct krait_power_vreg *from)
+{
+	int load_total = 0;
+	struct krait_power_vreg *kvreg;
+	struct pmic_gang_vreg *pvreg = from->pvreg;
+
+	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link)
+		load_total += kvreg->load_uA;
+
+	return load_total;
+}
+
+#define ROUND_UP_VOLTAGE(v, res) (DIV_ROUND_UP(v, res) * res)
+static int krait_power_set_voltage(struct regulator_dev *rdev,
+			int min_uV, int max_uV, unsigned *selector)
+{
+	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
+	struct pmic_gang_vreg *pvreg = kvreg->pvreg;
+	int rc;
+	int vmax;
+
+	/*
+	 * if the voltage requested is below LDO_THRESHOLD this cpu could
+	 * switch to LDO mode. Hence round the voltage as per the LDO
+	 * resolution
+	 */
+	if (min_uV < CORE_VOLTAGE_LDO_THRESH) {
+		if (min_uV < KRAIT_LDO_VOLTAGE_MIN)
+			min_uV = KRAIT_LDO_VOLTAGE_MIN;
+		min_uV = ROUND_UP_VOLTAGE(min_uV, KRAIT_LDO_STEP);
+	}
+
+	mutex_lock(&pvreg->krait_power_vregs_lock);
+
+	vmax = get_vmax(kvreg, min_uV);
+
+	/* round up the pmic voltage as per its resolution */
+	vmax = ROUND_UP_VOLTAGE(vmax, LV_RANGE_STEP);
+
+	/*
+	 * Assign the voltage before updating the gang voltage as we iterate
+	 * over all the core voltages and choose HS or LDO for each of them
+	 */
+	kvreg->uV = min_uV;
+
+	rc = pmic_gang_set_voltage(kvreg, vmax);
+	if (rc < 0) {
+		dev_err(&rdev->dev, "%s failed set voltage (%d, %d) rc = %d\n",
+				kvreg->name, min_uV, max_uV, rc);
+		goto out;
+	}
+
+	pvreg->pmic_vmax_uV = vmax;
+
+out:
+	mutex_unlock(&pvreg->krait_power_vregs_lock);
+	return rc;
+}
+
+static unsigned int krait_power_get_optimum_mode(struct regulator_dev *rdev,
+			int input_uV, int output_uV, int load_uA)
+{
+	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
+	struct pmic_gang_vreg *pvreg = kvreg->pvreg;
+	int rc;
+	int load_total_uA;
+	int reg_mode = -EINVAL;
+
+	mutex_lock(&pvreg->krait_power_vregs_lock);
+
+	kvreg->load_uA = load_uA;
+
+	load_total_uA = get_total_load(kvreg);
+
+	rc = pmic_gang_set_phases(kvreg, load_total_uA);
+	if (rc < 0) {
+		dev_err(&rdev->dev, "%s failed set mode %d rc = %d\n",
+				kvreg->name, load_total_uA, rc);
+		goto out;
+	}
+
+	reg_mode = kvreg->mode;
+out:
+	mutex_unlock(&pvreg->krait_power_vregs_lock);
+	return reg_mode;
+}
+
+static int krait_power_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	return 0;
+}
+
+static unsigned int krait_power_get_mode(struct regulator_dev *rdev)
+{
+	struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
+
+	return kvreg->mode;
+}
+
+static struct regulator_ops krait_power_ops = {
+	.get_voltage		= krait_power_get_voltage,
+	.set_voltage		= krait_power_set_voltage,
+	.get_optimum_mode	= krait_power_get_optimum_mode,
+	.set_mode		= krait_power_set_mode,
+	.get_mode		= krait_power_get_mode,
+};
+
+static void kvreg_hw_init(struct krait_power_vreg *kvreg)
+{
+	/*
+	 * bhs_cnt value sets the ramp-up time from power collapse,
+	 * initialize the ramp up time
+	 */
+	krait_masked_write(kvreg, APC_PWR_GATE_CTL,
+		BHS_CNT_MASK, BHS_CNT_DEFAULT << BHS_CNT_BIT_POS);
+
+	krait_masked_write(kvreg, APC_PWR_GATE_CTL,
+		CLK_SRC_SEL_MASK, CLK_SRC_DEFAULT << CLK_SRC_SEL_BIT_POS);
+
+	/* BHS has six different segments, turn them all on */
+	krait_masked_write(kvreg, APC_PWR_GATE_CTL,
+		BHS_SEG_EN_MASK, BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS);
+}
+
+static int __devinit krait_power_probe(struct platform_device *pdev)
+{
+	struct krait_power_vreg *kvreg;
+	struct resource *res;
+	struct regulator_init_data *init_data = pdev->dev.platform_data;
+	int rc = 0;
+
+	/* Initialize the pmic gang if it hasn't been initialized already */
+	if (the_gang == NULL) {
+		rc = pvreg_init(pdev);
+		if (rc < 0) {
+			dev_err(&pdev->dev,
+				"failed to init pmic gang rc = %d\n", rc);
+			return rc;
+		}
+	}
+
+	if (pdev->dev.of_node) {
+		/* Get init_data from device tree. */
+		init_data = of_get_regulator_init_data(&pdev->dev,
+							pdev->dev.of_node);
+		init_data->constraints.valid_ops_mask
+			|= REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_DRMS
+			| REGULATOR_CHANGE_MODE;
+		init_data->constraints.valid_modes_mask
+			|= REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE
+			| REGULATOR_MODE_FAST;
+		init_data->constraints.input_uV = init_data->constraints.max_uV;
+	}
+
+	if (!init_data) {
+		dev_err(&pdev->dev, "init data required.\n");
+		return -EINVAL;
+	}
+
+	if (!init_data->constraints.name) {
+		dev_err(&pdev->dev,
+			"regulator name must be specified in constraints.\n");
+		return -EINVAL;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "missing physical register addresses\n");
+		return -EINVAL;
+	}
+
+	kvreg = devm_kzalloc(&pdev->dev,
+			sizeof(struct krait_power_vreg), GFP_KERNEL);
+	if (!kvreg) {
+		dev_err(&pdev->dev, "kzalloc failed.\n");
+		return -ENOMEM;
+	}
+
+	kvreg->reg_base = devm_ioremap(&pdev->dev,
+				res->start, resource_size(res));
+
+	kvreg->pvreg	  = the_gang;
+	kvreg->name	  = init_data->constraints.name;
+	kvreg->desc.name  = kvreg->name;
+	kvreg->desc.ops   = &krait_power_ops;
+	kvreg->desc.type  = REGULATOR_VOLTAGE;
+	kvreg->desc.owner = THIS_MODULE;
+	kvreg->uV	  = CORE_VOLTAGE_MIN;
+	kvreg->mode	  = HS_MODE;
+	kvreg->desc.ops   = &krait_power_ops;
+
+	platform_set_drvdata(pdev, kvreg);
+
+	mutex_lock(&the_gang->krait_power_vregs_lock);
+	list_add_tail(&kvreg->link, &the_gang->krait_power_vregs);
+	mutex_unlock(&the_gang->krait_power_vregs_lock);
+
+	kvreg->rdev = regulator_register(&kvreg->desc, &pdev->dev, init_data,
+					 kvreg, pdev->dev.of_node);
+	if (IS_ERR(kvreg->rdev)) {
+		rc = PTR_ERR(kvreg->rdev);
+		pr_err("regulator_register failed, rc=%d.\n", rc);
+		goto out;
+	}
+
+	kvreg_hw_init(kvreg);
+	dev_dbg(&pdev->dev, "id=%d, name=%s\n", pdev->id, kvreg->name);
+
+	return 0;
+out:
+	mutex_lock(&the_gang->krait_power_vregs_lock);
+	list_del(&kvreg->link);
+	mutex_unlock(&the_gang->krait_power_vregs_lock);
+
+	platform_set_drvdata(pdev, NULL);
+	return rc;
+}
+
+static int __devexit krait_power_remove(struct platform_device *pdev)
+{
+	struct krait_power_vreg *kvreg = platform_get_drvdata(pdev);
+	struct pmic_gang_vreg *pvreg = kvreg->pvreg;
+
+	mutex_lock(&pvreg->krait_power_vregs_lock);
+	list_del(&kvreg->link);
+	mutex_unlock(&pvreg->krait_power_vregs_lock);
+
+	regulator_unregister(kvreg->rdev);
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static struct of_device_id krait_power_match_table[] = {
+	{ .compatible = "qcom,krait-regulator", },
+	{}
+};
+
+static struct platform_driver krait_power_driver = {
+	.probe	= krait_power_probe,
+	.remove	= __devexit_p(krait_power_remove),
+	.driver	= {
+		.name		= KRAIT_REGULATOR_DRIVER_NAME,
+		.of_match_table	= krait_power_match_table,
+		.owner		= THIS_MODULE,
+	},
+};
+
+int __init krait_power_init(void)
+{
+	return platform_driver_register(&krait_power_driver);
+}
+
+static void __exit krait_power_exit(void)
+{
+	platform_driver_unregister(&krait_power_driver);
+}
+
+module_exit(krait_power_exit);
+
+void secondary_cpu_hs_init(void *base_ptr)
+{
+	/* 605mV retention and 705mV operational voltage */
+	writel_relaxed(0x1C30, base_ptr + APC_LDO_VREF_SET);
+	writel_relaxed(0x430000, base_ptr + 0x20);
+	writel_relaxed(0x21, base_ptr + 0x1C);
+
+	/* Turn on the BHS, turn off LDO Bypass and power down LDO */
+	writel_relaxed(0x403F007F, base_ptr + APC_PWR_GATE_CTL);
+	mb();
+	udelay(1);
+
+	/* Finally turn on the bypass so that BHS supplies power */
+	writel_relaxed(0x403F3F7F, base_ptr + APC_PWR_GATE_CTL);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("KRAIT POWER regulator driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:"KRAIT_REGULATOR_DRIVER_NAME);
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index e74af2e..2073856 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -41,10 +41,9 @@
 #include "devices.h"
 #include "clock.h"
 #include "mdm_private.h"
-
 #define MDM_PBLRDY_CNT		20
 
-static int mdm_debug_on;
+static int mdm_debug_mask;
 static int power_on_count;
 static int hsic_peripheral_status;
 static DEFINE_MUTEX(hsic_status_lock);
@@ -135,7 +134,6 @@
 {
 	int i;
 	int pblrdy;
-
 	if (power_on_count != 1) {
 		pr_err("%s: Calling fn when power_on_count != 1\n",
 			   __func__);
@@ -151,9 +149,8 @@
 	 * powered down.
 	 */
 	mdm_toggle_soft_reset(mdm_drv);
-
 	/* If the device has a kpd pwr gpio then toggle it. */
-	if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0) {
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_kpdpwr_n_gpio)) {
 		/* Pull AP2MDM_KPDPWR gpio high and wait for PS_HOLD to settle,
 		 * then	pull it back low.
 		 */
@@ -163,7 +160,7 @@
 		gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 0);
 	}
 
-	if (!mdm_drv->mdm2ap_pblrdy)
+	if (!GPIO_IS_VALID(mdm_drv->mdm2ap_pblrdy))
 		goto start_mdm_peripheral;
 
 	for (i = 0; i  < MDM_PBLRDY_CNT; i++) {
@@ -172,7 +169,6 @@
 			break;
 		usleep_range(5000, 5000);
 	}
-
 	pr_debug("%s: i:%d\n", __func__, i);
 
 start_mdm_peripheral:
@@ -189,7 +185,7 @@
 	mdm_peripheral_disconnect(mdm_drv);
 	mdm_toggle_soft_reset(mdm_drv);
 
-	if (!mdm_drv->mdm2ap_pblrdy)
+	if (!GPIO_IS_VALID(mdm_drv->mdm2ap_pblrdy))
 		goto start_mdm_peripheral;
 
 	for (i = 0; i  < MDM_PBLRDY_CNT; i++) {
@@ -214,7 +210,7 @@
 	 * de-assert it now so that it can be asserted later.
 	 * May not be used.
 	 */
-	if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_wakeup_gpio))
 		gpio_direction_output(mdm_drv->ap2mdm_wakeup_gpio, 0);
 
 	/*
@@ -234,7 +230,7 @@
 
 static void debug_state_changed(int value)
 {
-	mdm_debug_on = value;
+	mdm_debug_mask = value;
 }
 
 static void mdm_status_changed(struct mdm_modem_drv *mdm_drv, int value)
@@ -244,7 +240,7 @@
 	if (value) {
 		mdm_peripheral_disconnect(mdm_drv);
 		mdm_peripheral_connect(mdm_drv);
-		if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+		if (GPIO_IS_VALID(mdm_drv->ap2mdm_wakeup_gpio))
 			gpio_direction_output(mdm_drv->ap2mdm_wakeup_gpio, 1);
 	}
 }
@@ -266,7 +262,7 @@
 		 * high.
 		 */
 		mdm_drv->disable_status_check = 1;
-		if (mdm_drv->usb_switch_gpio > 0) {
+		if (GPIO_IS_VALID(mdm_drv->usb_switch_gpio)) {
 			pr_info("%s Switching usb control to MDM\n", __func__);
 			gpio_direction_output(mdm_drv->usb_switch_gpio, 1);
 		} else
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index c853b0b..2ee6938 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -30,6 +30,7 @@
 #include <linux/workqueue.h>
 #include <linux/clk.h>
 #include <linux/mfd/pmic8058.h>
+#include <linux/msm_charm.h>
 #include <asm/mach-types.h>
 #include <asm/uaccess.h>
 #include <mach/mdm2.h>
@@ -37,7 +38,7 @@
 #include <mach/subsystem_notif.h>
 #include <mach/subsystem_restart.h>
 #include <mach/rpm.h>
-#include <linux/msm_charm.h>
+#include <mach/gpiomux.h>
 #include "msm_watchdog.h"
 #include "mdm_private.h"
 #include "sysmon.h"
@@ -48,10 +49,11 @@
 #define MDM_RDUMP_TIMEOUT	120000L
 #define MDM2AP_STATUS_TIMEOUT_MS 60000L
 
-static int mdm_debug_on;
+static unsigned int mdm_debug_mask;
 static struct workqueue_struct *mdm_queue;
 static struct workqueue_struct *mdm_sfr_queue;
 static unsigned int dump_timeout_ms;
+static int vddmin_gpios_sent;
 
 #define EXTERNAL_MODEM "external_modem"
 
@@ -68,6 +70,13 @@
 #define SFR_MAX_RETRIES		10
 #define SFR_RETRY_INTERVAL	1000
 
+enum gpio_update_config {
+	GPIO_UPDATE_BOOTING_CONFIG = 1,
+	GPIO_UPDATE_RUNNING_CONFIG,
+};
+static int mdm2ap_status_valid_old_config;
+static struct gpiomux_setting mdm2ap_status_old_config;
+
 static irqreturn_t mdm_vddmin_change(int irq, void *dev_id)
 {
 	int value = gpio_get_value(
@@ -92,6 +101,7 @@
 	if (!vddmin_res)
 		return;
 
+	pr_info("Enabling vddmin logging\n");
 	req.id = vddmin_res->rpm_id;
 	req.value = ((uint32_t)vddmin_res->ap2mdm_vddmin_gpio & 0x0000FFFF)
 							<< 16;
@@ -100,7 +110,7 @@
 
 	msm_rpm_set(MSM_RPM_CTX_SET_0, &req, 1);
 
-	/* Monitor low power gpio from mdm */
+	/* Start monitoring low power gpio from mdm */
 	irq = MSM_GPIO_TO_INT(vddmin_res->mdm2ap_vddmin_gpio);
 	if (irq < 0) {
 		pr_err("%s: could not get LPM POWER IRQ resource.\n",
@@ -163,6 +173,37 @@
 
 static DECLARE_DELAYED_WORK(mdm2ap_status_check_work, mdm2ap_status_check);
 
+static void mdm_update_gpio_configs(enum gpio_update_config gpio_config)
+{
+	/* Some gpio configuration may need updating after modem bootup.*/
+	switch (gpio_config) {
+	case GPIO_UPDATE_RUNNING_CONFIG:
+		if (mdm_drv->pdata->mdm2ap_status_gpio_run_cfg) {
+			if (msm_gpiomux_write(mdm_drv->mdm2ap_status_gpio,
+				GPIOMUX_ACTIVE,
+				mdm_drv->pdata->mdm2ap_status_gpio_run_cfg,
+				&mdm2ap_status_old_config))
+				pr_err("%s: failed updating running gpio config\n",
+					   __func__);
+			else
+				mdm2ap_status_valid_old_config = 1;
+		}
+		break;
+	case GPIO_UPDATE_BOOTING_CONFIG:
+		if (mdm2ap_status_valid_old_config) {
+			msm_gpiomux_write(mdm_drv->mdm2ap_status_gpio,
+					GPIOMUX_ACTIVE,
+					&mdm2ap_status_old_config,
+					NULL);
+			mdm2ap_status_valid_old_config = 0;
+		}
+		break;
+	default:
+		pr_err("%s: called with no config\n", __func__);
+		break;
+	}
+}
+
 long mdm_modem_ioctl(struct file *filp, unsigned int cmd,
 				unsigned long arg)
 {
@@ -205,11 +246,10 @@
 		else
 			first_boot = 0;
 
-		/* Start a timer to check that the mdm2ap_status gpio
-		 * goes high.
+		/* If successful, start a timer to check that the mdm2ap_status
+		 * gpio goes high.
 		 */
-
-		if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
+		if (!status && gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
 			schedule_delayed_work(&mdm2ap_status_check_work,
 				msecs_to_jiffies(MDM2AP_STATUS_TIMEOUT_MS));
 		break;
@@ -266,6 +306,9 @@
 	pr_debug("%s: status:%d\n", __func__, value);
 	if (mdm_drv->mdm_ready && mdm_drv->ops->status_cb)
 		mdm_drv->ops->status_cb(mdm_drv, value);
+
+	/* Update gpio configuration to "running" config. */
+	mdm_update_gpio_configs(GPIO_UPDATE_RUNNING_CONFIG);
 }
 
 static DECLARE_WORK(mdm_status_work, mdm_status_fn);
@@ -364,6 +407,7 @@
 static int mdm_subsys_shutdown(const struct subsys_desc *crashed_subsys)
 {
 	mdm_drv->mdm_ready = 0;
+	cancel_delayed_work(&mdm2ap_status_check_work);
 	gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
 	if (mdm_drv->pdata->ramdump_delay_ms > 0) {
 		/* Wait for the external modem to complete
@@ -371,10 +415,13 @@
 		 */
 		msleep(mdm_drv->pdata->ramdump_delay_ms);
 	}
-	if (!mdm_drv->mdm_unexpected_reset_occurred)
+	if (!mdm_drv->mdm_unexpected_reset_occurred) {
 		mdm_drv->ops->reset_mdm_cb(mdm_drv);
-	else
+		/* Update gpio configuration to "booting" config. */
+		mdm_update_gpio_configs(GPIO_UPDATE_BOOTING_CONFIG);
+	} else {
 		mdm_drv->mdm_unexpected_reset_occurred = 0;
+	}
 	return 0;
 }
 
@@ -404,6 +451,7 @@
 				const struct subsys_desc *crashed_subsys)
 {
 	mdm_drv->mdm_ram_dump_status = 0;
+	cancel_delayed_work(&mdm2ap_status_check_work);
 	if (want_dumps) {
 		mdm_drv->boot_type = CHARM_RAM_DUMPS;
 		complete(&mdm_needs_reload);
@@ -416,8 +464,11 @@
 			pr_info("%s: mdm modem ramdumps completed.\n",
 					__func__);
 		INIT_COMPLETION(mdm_ram_dumps);
-		if (!mdm_drv->pdata->no_powerdown_after_ramdumps)
+		if (!mdm_drv->pdata->no_powerdown_after_ramdumps) {
 			mdm_drv->ops->power_down_mdm_cb(mdm_drv);
+			/* Update gpio configuration to "booting" config. */
+			mdm_update_gpio_configs(GPIO_UPDATE_BOOTING_CONFIG);
+		}
 	}
 	return mdm_drv->mdm_ram_dump_status;
 }
@@ -429,23 +480,33 @@
 	.name = EXTERNAL_MODEM,
 };
 
-static int mdm_debug_on_set(void *data, u64 val)
+/* Once the gpios are sent to RPM and debugging
+ * starts, there is no way to stop it without
+ * rebooting the device.
+ */
+static int mdm_debug_mask_set(void *data, u64 val)
 {
-	mdm_debug_on = val;
+	if (!vddmin_gpios_sent &&
+		(val & MDM_DEBUG_MASK_VDDMIN_SETUP)) {
+		mdm_setup_vddmin_gpios();
+		vddmin_gpios_sent = 1;
+	}
+
+	mdm_debug_mask = val;
 	if (mdm_drv->ops->debug_state_changed_cb)
-		mdm_drv->ops->debug_state_changed_cb(mdm_debug_on);
+		mdm_drv->ops->debug_state_changed_cb(mdm_debug_mask);
 	return 0;
 }
 
-static int mdm_debug_on_get(void *data, u64 *val)
+static int mdm_debug_mask_get(void *data, u64 *val)
 {
-	*val = mdm_debug_on;
+	*val = mdm_debug_mask;
 	return 0;
 }
 
-DEFINE_SIMPLE_ATTRIBUTE(mdm_debug_on_fops,
-			mdm_debug_on_get,
-			mdm_debug_on_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(mdm_debug_mask_fops,
+			mdm_debug_mask_get,
+			mdm_debug_mask_set, "%llu\n");
 
 static int mdm_debugfs_init(void)
 {
@@ -455,8 +516,8 @@
 	if (IS_ERR(dent))
 		return PTR_ERR(dent);
 
-	debugfs_create_file("debug_on", 0644, dent, NULL,
-			&mdm_debug_on_fops);
+	debugfs_create_file("debug_mask", 0644, dent, NULL,
+			&mdm_debug_mask_fops);
 	return 0;
 }
 
@@ -468,68 +529,57 @@
 	/* MDM2AP_ERRFATAL */
 	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
 							"MDM2AP_ERRFATAL");
-	if (pres)
-		mdm_drv->mdm2ap_errfatal_gpio = pres->start;
+	mdm_drv->mdm2ap_errfatal_gpio = pres ? pres->start : -1;
 
 	/* AP2MDM_ERRFATAL */
 	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
 							"AP2MDM_ERRFATAL");
-	if (pres)
-		mdm_drv->ap2mdm_errfatal_gpio = pres->start;
+	mdm_drv->ap2mdm_errfatal_gpio = pres ? pres->start : -1;
 
 	/* MDM2AP_STATUS */
 	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
 							"MDM2AP_STATUS");
-	if (pres)
-		mdm_drv->mdm2ap_status_gpio = pres->start;
+	mdm_drv->mdm2ap_status_gpio = pres ? pres->start : -1;
 
 	/* AP2MDM_STATUS */
 	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
 							"AP2MDM_STATUS");
-	if (pres)
-		mdm_drv->ap2mdm_status_gpio = pres->start;
+	mdm_drv->ap2mdm_status_gpio = pres ? pres->start : -1;
 
 	/* MDM2AP_WAKEUP */
 	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
 							"MDM2AP_WAKEUP");
-	if (pres)
-		mdm_drv->mdm2ap_wakeup_gpio = pres->start;
+	mdm_drv->mdm2ap_wakeup_gpio = pres ? pres->start : -1;
 
 	/* AP2MDM_WAKEUP */
 	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
 							"AP2MDM_WAKEUP");
-	if (pres)
-		mdm_drv->ap2mdm_wakeup_gpio = pres->start;
+	mdm_drv->ap2mdm_wakeup_gpio = pres ? pres->start : -1;
 
 	/* AP2MDM_SOFT_RESET */
 	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
 							"AP2MDM_SOFT_RESET");
-	if (pres)
-		mdm_drv->ap2mdm_soft_reset_gpio = pres->start;
+	mdm_drv->ap2mdm_soft_reset_gpio = pres ? pres->start : -1;
 
 	/* AP2MDM_KPDPWR_N */
 	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
 							"AP2MDM_KPDPWR_N");
-	if (pres)
-		mdm_drv->ap2mdm_kpdpwr_n_gpio = pres->start;
+	mdm_drv->ap2mdm_kpdpwr_n_gpio = pres ? pres->start : -1;
 
 	/* AP2MDM_PMIC_PWR_EN */
 	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
 							"AP2MDM_PMIC_PWR_EN");
-	if (pres)
-		mdm_drv->ap2mdm_pmic_pwr_en_gpio = pres->start;
+	mdm_drv->ap2mdm_pmic_pwr_en_gpio = pres ? pres->start : -1;
 
 	/* MDM2AP_PBLRDY */
 	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
 							"MDM2AP_PBLRDY");
-	if (pres)
-		mdm_drv->mdm2ap_pblrdy = pres->start;
+	mdm_drv->mdm2ap_pblrdy = pres ? pres->start : -1;
 
 	/*USB_SW*/
 	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
 							"USB_SW");
-	if (pres)
-		mdm_drv->usb_switch_gpio = pres->start;
+	mdm_drv->usb_switch_gpio = pres ? pres->start : -1;
 
 	mdm_drv->boot_type                  = CHARM_NORMAL_BOOT;
 
@@ -552,28 +602,28 @@
 
 	mdm_modem_initialize_data(pdev, p_mdm_cb);
 	if (mdm_drv->ops->debug_state_changed_cb)
-		mdm_drv->ops->debug_state_changed_cb(mdm_debug_on);
+		mdm_drv->ops->debug_state_changed_cb(mdm_debug_mask);
 
 	gpio_request(mdm_drv->ap2mdm_status_gpio, "AP2MDM_STATUS");
 	gpio_request(mdm_drv->ap2mdm_errfatal_gpio, "AP2MDM_ERRFATAL");
-	if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0)
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_kpdpwr_n_gpio))
 		gpio_request(mdm_drv->ap2mdm_kpdpwr_n_gpio, "AP2MDM_KPDPWR_N");
 	gpio_request(mdm_drv->mdm2ap_status_gpio, "MDM2AP_STATUS");
 	gpio_request(mdm_drv->mdm2ap_errfatal_gpio, "MDM2AP_ERRFATAL");
-	if (mdm_drv->mdm2ap_pblrdy > 0)
+	if (GPIO_IS_VALID(mdm_drv->mdm2ap_pblrdy))
 		gpio_request(mdm_drv->mdm2ap_pblrdy, "MDM2AP_PBLRDY");
 
-	if (mdm_drv->ap2mdm_pmic_pwr_en_gpio > 0)
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
 		gpio_request(mdm_drv->ap2mdm_pmic_pwr_en_gpio,
 					 "AP2MDM_PMIC_PWR_EN");
-	if (mdm_drv->ap2mdm_soft_reset_gpio > 0)
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_soft_reset_gpio))
 		gpio_request(mdm_drv->ap2mdm_soft_reset_gpio,
 					 "AP2MDM_SOFT_RESET");
 
-	if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_wakeup_gpio))
 		gpio_request(mdm_drv->ap2mdm_wakeup_gpio, "AP2MDM_WAKEUP");
 
-	if (mdm_drv->usb_switch_gpio > 0) {
+	if (GPIO_IS_VALID(mdm_drv->usb_switch_gpio)) {
 		if (gpio_request(mdm_drv->usb_switch_gpio, "USB_SW")) {
 			pr_err("%s Failed to get usb switch gpio\n", __func__);
 			mdm_drv->usb_switch_gpio = -1;
@@ -583,7 +633,7 @@
 	gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
 	gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
 
-	if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_wakeup_gpio))
 		gpio_direction_output(mdm_drv->ap2mdm_wakeup_gpio, 0);
 
 	gpio_direction_input(mdm_drv->mdm2ap_status_gpio);
@@ -661,7 +711,7 @@
 	mdm_drv->mdm_status_irq = irq;
 
 status_err:
-	if (mdm_drv->mdm2ap_pblrdy > 0) {
+	if (GPIO_IS_VALID(mdm_drv->mdm2ap_pblrdy)) {
 		irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_pblrdy);
 		if (irq < 0) {
 			pr_err("%s: could not get MDM2AP_PBLRDY IRQ resource",
@@ -686,10 +736,8 @@
 	 * If AP2MDM_PMIC_PWR_EN gpio is used, pull it high. It remains
 	 * high until the whole phone is shut down.
 	 */
-	if (mdm_drv->ap2mdm_pmic_pwr_en_gpio > 0)
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
 		gpio_direction_output(mdm_drv->ap2mdm_pmic_pwr_en_gpio, 1);
-	/* Register VDDmin gpios with RPM */
-	mdm_setup_vddmin_gpios();
 
 	/* Perform early powerup of the external modem in order to
 	 * allow tabla devices to be found.
@@ -703,16 +751,16 @@
 fatal_err:
 	gpio_free(mdm_drv->ap2mdm_status_gpio);
 	gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
-	if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0)
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_kpdpwr_n_gpio))
 		gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
-	if (mdm_drv->ap2mdm_pmic_pwr_en_gpio > 0)
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
 		gpio_free(mdm_drv->ap2mdm_pmic_pwr_en_gpio);
 	gpio_free(mdm_drv->mdm2ap_status_gpio);
 	gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
-	if (mdm_drv->ap2mdm_soft_reset_gpio > 0)
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_soft_reset_gpio))
 		gpio_free(mdm_drv->ap2mdm_soft_reset_gpio);
 
-	if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_wakeup_gpio))
 		gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
 
 	kfree(mdm_drv);
@@ -728,16 +776,16 @@
 
 	gpio_free(mdm_drv->ap2mdm_status_gpio);
 	gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
-	if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0)
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_kpdpwr_n_gpio))
 		gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
-	if (mdm_drv->ap2mdm_pmic_pwr_en_gpio > 0)
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
 		gpio_free(mdm_drv->ap2mdm_pmic_pwr_en_gpio);
 	gpio_free(mdm_drv->mdm2ap_status_gpio);
 	gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
-	if (mdm_drv->ap2mdm_soft_reset_gpio > 0)
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_soft_reset_gpio))
 		gpio_free(mdm_drv->ap2mdm_soft_reset_gpio);
 
-	if (mdm_drv->ap2mdm_wakeup_gpio > 0)
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_wakeup_gpio))
 		gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
 
 	kfree(mdm_drv);
@@ -751,7 +799,7 @@
 	mdm_disable_irqs();
 
 	mdm_drv->ops->power_down_mdm_cb(mdm_drv);
-	if (mdm_drv->ap2mdm_pmic_pwr_en_gpio > 0)
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
 		gpio_direction_output(mdm_drv->ap2mdm_pmic_pwr_en_gpio, 0);
 }
 
diff --git a/arch/arm/mach-msm/mdm_private.h b/arch/arm/mach-msm/mdm_private.h
index 7aba83d..c406b89 100644
--- a/arch/arm/mach-msm/mdm_private.h
+++ b/arch/arm/mach-msm/mdm_private.h
@@ -13,6 +13,9 @@
 #ifndef _ARCH_ARM_MACH_MSM_MDM_PRIVATE_H
 #define _ARCH_ARM_MACH_MSM_MDM_PRIVATE_H
 
+#define MDM_DEBUG_MASK_VDDMIN_SETUP (0x00000002)
+#define GPIO_IS_VALID(gpio) \
+	(gpio != -1)
 struct mdm_modem_drv;
 
 struct mdm_ops {
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index 63c2d3a..4a2fd7c 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -390,24 +390,33 @@
 	[MEMTYPE_EBI1] = "EBI1",
 };
 
-static int reserve_memory_type(char *mem_name,
-				struct memtype_reserve *reserve_table,
-				int size)
+int msm_get_memory_type_from_name(const char *memtype_name)
 {
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(memtype_names); i++) {
-		if (memtype_names[i] && strcmp(mem_name,
-				memtype_names[i]) == 0) {
-			reserve_table[i].size += size;
-			return 0;
-		}
+		if (memtype_names[i] &&
+		    strcmp(memtype_name, memtype_names[i]) == 0)
+			return i;
 	}
 
-	pr_err("Could not find memory type %s\n", mem_name);
+	pr_err("Could not find memory type %s\n", memtype_name);
 	return -EINVAL;
 }
 
+static int reserve_memory_type(const char *mem_name,
+				struct memtype_reserve *reserve_table,
+				int size)
+{
+	int ret = msm_get_memory_type_from_name(mem_name);
+
+	if (ret >= 0) {
+		reserve_table[ret].size += size;
+		ret = 0;
+	}
+	return ret;
+}
+
 static int check_for_compat(unsigned long node)
 {
 	char **start = __compat_exports_start;
diff --git a/arch/arm/mach-msm/modem-8960.c b/arch/arm/mach-msm/modem-8960.c
index 73b9b1f..844a78b 100644
--- a/arch/arm/mach-msm/modem-8960.c
+++ b/arch/arm/mach-msm/modem-8960.c
@@ -38,8 +38,6 @@
 static struct subsys_device *modem_8960_dev;
 
 #define MAX_SSR_REASON_LEN 81U
-#define Q6_FW_WDOG_ENABLE		0x08882024
-#define Q6_SW_WDOG_ENABLE		0x08982024
 
 static void log_modem_sfr(void)
 {
@@ -71,26 +69,6 @@
 	subsystem_restart_dev(modem_8960_dev);
 }
 
-static void modem_wdog_check(struct work_struct *work)
-{
-	void __iomem *q6_sw_wdog_addr;
-	u32 regval;
-
-	q6_sw_wdog_addr = ioremap_nocache(Q6_SW_WDOG_ENABLE, 4);
-	if (!q6_sw_wdog_addr)
-		panic("Unable to check modem watchdog status.\n");
-
-	regval = readl_relaxed(q6_sw_wdog_addr);
-	if (!regval) {
-		pr_err("modem-8960: Modem watchdog wasn't activated!. Restarting the modem now.\n");
-		restart_modem();
-	}
-
-	iounmap(q6_sw_wdog_addr);
-}
-
-static DECLARE_DELAYED_WORK(modem_wdog_check_work, modem_wdog_check);
-
 static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
 {
 	/* Ignore if we're the one that set SMSM_RESET */
@@ -103,18 +81,15 @@
 	}
 }
 
+#define Q6_FW_WDOG_ENABLE		0x08882024
+#define Q6_SW_WDOG_ENABLE		0x08982024
+
 static int modem_shutdown(const struct subsys_desc *subsys)
 {
 	void __iomem *q6_fw_wdog_addr;
 	void __iomem *q6_sw_wdog_addr;
 
 	/*
-	 * Cancel any pending wdog_check work items, since we're shutting
-	 * down anyway.
-	 */
-	cancel_delayed_work(&modem_wdog_check_work);
-
-	/*
 	 * Disable the modem watchdog since it keeps running even after the
 	 * modem is shutdown.
 	 */
@@ -150,8 +125,6 @@
 	pil_force_boot("modem");
 	enable_irq(Q6FW_WDOG_EXPIRED_IRQ);
 	enable_irq(Q6SW_WDOG_EXPIRED_IRQ);
-	schedule_delayed_work(&modem_wdog_check_work,
-				msecs_to_jiffies(MODEM_WDOG_CHECK_TIMEOUT_MS));
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index e035e35..9dcd51f 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -139,7 +139,7 @@
 
 	for (i = 0; i < fabric->pdata->len; i++) {
 		struct msm_bus_inode_info *info;
-		int ctx;
+		int ctx, j;
 
 		info = kzalloc(sizeof(struct msm_bus_inode_info), GFP_KERNEL);
 		if (info == NULL) {
@@ -189,11 +189,17 @@
 		if (fabric->fabdev.hw_algo.node_init == NULL)
 			continue;
 
+		for (j = 0; j < NUM_CTX; j++)
+			clk_prepare_enable(fabric->info.nodeclk[j].clk);
+
 		fabric->fabdev.hw_algo.node_init(fabric->hw_data, info);
 		if (ret) {
 			MSM_BUS_ERR("Unable to init node info, ret: %d\n", ret);
 			kfree(info);
 		}
+
+		for (j = 0; j < NUM_CTX; j++)
+			clk_disable_unprepare(fabric->info.nodeclk[j].clk);
 	}
 
 	MSM_BUS_DBG("Fabric: %d nmasters: %d nslaves: %d\n"
@@ -337,6 +343,7 @@
 {
 	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
 	void *sel_cdata;
+	int i;
 
 	/* Temporarily stub out arbitration settings for msm8974 */
 	if (machine_is_msm8974())
@@ -354,8 +361,14 @@
 		return;
 	}
 
+	for (i = 0; i < NUM_CTX; i++)
+		clk_prepare_enable(fabric->info.nodeclk[i].clk);
+
 	fabdev->hw_algo.update_bw(hop, info, fabric->pdata, sel_cdata,
 		master_tiers, add_bw);
+	for (i = 0; i < NUM_CTX; i++)
+		clk_disable_unprepare(fabric->info.nodeclk[i].clk);
+
 	fabric->arb_dirty = true;
 }
 
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
index 2597e27..e6ec722 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
@@ -388,7 +388,8 @@
 		(struct msm_bus_noc_info *)hw_data;
 
 	if (!IS_SLAVE(info->node_info->priv_id))
-		msm_bus_noc_mas_init(ninfo, info);
+		if (info->node_info->hw_sel != MSM_BUS_RPM)
+			msm_bus_noc_mas_init(ninfo, info);
 }
 
 static int msm_bus_noc_allocate_commit_data(struct msm_bus_fabric_registration
diff --git a/arch/arm/mach-msm/msm_cpr-debug.c b/arch/arm/mach-msm/msm_cpr-debug.c
new file mode 100644
index 0000000..723423c
--- /dev/null
+++ b/arch/arm/mach-msm/msm_cpr-debug.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+struct msm_cpr_debug_device {
+	struct mutex	debug_mutex;
+	struct dentry	*dir;
+	int		addr_offset;
+	void __iomem	*base;
+};
+
+static inline
+void write_reg(struct msm_cpr_debug_device *cpr, u32 value)
+{
+	writel_relaxed(value, cpr->base + cpr->addr_offset);
+}
+
+static inline u32 read_reg(struct msm_cpr_debug_device *cpr)
+{
+	return readl_relaxed(cpr->base + cpr->addr_offset);
+}
+
+static bool msm_cpr_debug_addr_is_valid(int addr)
+{
+	if (addr < 0 || addr > 0x15C) {
+		pr_err("CPR register address is invalid: %d\n", addr);
+		return false;
+	}
+	return true;
+}
+
+static int msm_cpr_debug_data_set(void *data, u64 val)
+{
+	struct msm_cpr_debug_device *debugdev = data;
+	uint32_t reg = val;
+
+	mutex_lock(&debugdev->debug_mutex);
+
+	if (msm_cpr_debug_addr_is_valid(debugdev->addr_offset))
+		write_reg(debugdev, reg);
+
+	mutex_unlock(&debugdev->debug_mutex);
+	return 0;
+}
+
+static int msm_cpr_debug_data_get(void *data, u64 *val)
+{
+	struct msm_cpr_debug_device *debugdev = data;
+	uint32_t reg;
+
+	mutex_lock(&debugdev->debug_mutex);
+
+	if (msm_cpr_debug_addr_is_valid(debugdev->addr_offset)) {
+		reg = read_reg(debugdev);
+		*val = reg;
+	}
+	mutex_unlock(&debugdev->debug_mutex);
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_data_fops, msm_cpr_debug_data_get,
+			msm_cpr_debug_data_set, "0x%02llX\n");
+
+static int msm_cpr_debug_addr_set(void *data, u64 val)
+{
+	struct msm_cpr_debug_device *debugdev = data;
+
+	if (msm_cpr_debug_addr_is_valid(val)) {
+		mutex_lock(&debugdev->debug_mutex);
+		debugdev->addr_offset = val;
+		mutex_unlock(&debugdev->debug_mutex);
+	}
+
+	return 0;
+}
+
+static int msm_cpr_debug_addr_get(void *data, u64 *val)
+{
+	struct msm_cpr_debug_device *debugdev = data;
+
+	mutex_lock(&debugdev->debug_mutex);
+
+	if (msm_cpr_debug_addr_is_valid(debugdev->addr_offset))
+		*val = debugdev->addr_offset;
+
+	mutex_unlock(&debugdev->debug_mutex);
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_addr_fops, msm_cpr_debug_addr_get,
+			msm_cpr_debug_addr_set, "0x%03llX\n");
+
+int msm_cpr_debug_init(void *data)
+{
+	char *name = "cpr-debug";
+	struct msm_cpr_debug_device *debugdev;
+	struct dentry *dir;
+	struct dentry *temp;
+	int rc;
+
+	debugdev = kzalloc(sizeof(struct msm_cpr_debug_device), GFP_KERNEL);
+	if (debugdev == NULL) {
+		pr_err("kzalloc failed\n");
+		return -ENOMEM;
+	}
+
+	dir = debugfs_create_dir(name, NULL);
+	if (dir == NULL || IS_ERR(dir)) {
+		pr_err("debugfs_create_dir failed: rc=%ld\n", PTR_ERR(dir));
+		rc = PTR_ERR(dir);
+		goto dir_error;
+	}
+
+	temp = debugfs_create_file("address", S_IRUGO | S_IWUSR, dir, debugdev,
+				   &debug_addr_fops);
+	if (temp == NULL || IS_ERR(temp)) {
+		pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
+		rc = PTR_ERR(temp);
+		goto file_error;
+	}
+
+	temp = debugfs_create_file("data", S_IRUGO | S_IWUSR, dir, debugdev,
+				   &debug_data_fops);
+	if (temp == NULL  || IS_ERR(temp)) {
+		pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
+		rc = PTR_ERR(temp);
+		goto file_error;
+	}
+	debugdev->base = data;
+	debugdev->addr_offset = -1;
+	debugdev->dir = dir;
+	mutex_init(&debugdev->debug_mutex);
+
+	return 0;
+
+file_error:
+	debugfs_remove_recursive(dir);
+dir_error:
+	kfree(debugdev);
+
+	return rc;
+}
diff --git a/arch/arm/mach-msm/msm_cpr.c b/arch/arm/mach-msm/msm_cpr.c
new file mode 100644
index 0000000..f4272f3
--- /dev/null
+++ b/arch/arm/mach-msm/msm_cpr.c
@@ -0,0 +1,861 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/debugfs.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/cpufreq.h>
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+
+#include <mach/irqs.h>
+
+#include "msm_cpr.h"
+
+#define MODULE_NAME "msm-cpr"
+
+/* Need platform device handle for suspend and resume APIs */
+static struct platform_device *cpr_pdev;
+
+struct msm_cpr {
+	int curr_osc;
+	int cpr_mode;
+	int prev_mode;
+	uint32_t floor;
+	uint32_t ceiling;
+	void __iomem *base;
+	unsigned int irq;
+	struct mutex cpr_mutex;
+	struct regulator *vreg_cx;
+	const struct msm_cpr_config *config;
+	struct notifier_block freq_transition;
+	struct msm_cpr_vp_data *vp;
+};
+
+/* Need to maintain state data for suspend and resume APIs */
+static struct msm_cpr_reg cpr_save_state;
+
+static inline
+void cpr_write_reg(struct msm_cpr *cpr, u32 offset, u32 value)
+{
+	writel_relaxed(value, cpr->base + offset);
+}
+
+static inline u32 cpr_read_reg(struct msm_cpr *cpr, u32 offset)
+{
+	return readl_relaxed(cpr->base + offset);
+}
+
+static
+void cpr_modify_reg(struct msm_cpr *cpr, u32 offset, u32 mask, u32 value)
+{
+	u32 reg_val;
+
+	reg_val = readl_relaxed(cpr->base + offset);
+	reg_val &= ~mask;
+	reg_val |= value;
+	writel_relaxed(reg_val, cpr->base + offset);
+}
+
+#ifdef DEBUG
+static void cpr_regs_dump_all(struct msm_cpr *cpr)
+{
+	pr_debug("RBCPR_GCNT_TARGET(%d): 0x%x\n",
+		cpr->curr_osc, readl_relaxed(cpr->base +
+		RBCPR_GCNT_TARGET(cpr->curr_osc)));
+	pr_debug("RBCPR_TIMER_INTERVAL: 0x%x\n",
+		readl_relaxed(cpr->base + RBCPR_TIMER_INTERVAL));
+	pr_debug("RBIF_TIMER_ADJUST: 0x%x\n",
+		readl_relaxed(cpr->base + RBIF_TIMER_ADJUST));
+	pr_debug("RBIF_LIMIT: 0x%x\n",
+		readl_relaxed(cpr->base + RBIF_LIMIT));
+	pr_debug("RBCPR_STEP_QUOT: 0x%x\n",
+		readl_relaxed(cpr->base + RBCPR_STEP_QUOT));
+	pr_debug("RBIF_SW_VLEVEL: 0x%x\n",
+		readl_relaxed(cpr->base + RBIF_SW_VLEVEL));
+	pr_debug("RBCPR_DEBUG1: 0x%x\n",
+		readl_relaxed(cpr->base + RBCPR_DEBUG1));
+	pr_debug("RBCPR_RESULT_0: 0x%x\n",
+		readl_relaxed(cpr->base + RBCPR_RESULT_0));
+	pr_debug("RBCPR_RESULT_1: 0x%x\n",
+		readl_relaxed(cpr->base + RBCPR_RESULT_1));
+	pr_debug("RBCPR_QUOT_AVG: 0x%x\n",
+		readl_relaxed(cpr->base + RBCPR_QUOT_AVG));
+	pr_debug("RBCPR_CTL: 0x%x\n",
+		readl_relaxed(cpr->base + RBCPR_CTL));
+	pr_debug("RBIF_IRQ_EN(0): 0x%x\n",
+		cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line)));
+	pr_debug("RBIF_IRQ_STATUS: 0x%x\n",
+		cpr_read_reg(cpr, RBIF_IRQ_STATUS));
+}
+#endif
+
+/* Enable the CPR H/W Block */
+static void cpr_enable(struct msm_cpr *cpr)
+{
+	mutex_lock(&cpr->cpr_mutex);
+	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, ENABLE_CPR);
+	mutex_unlock(&cpr->cpr_mutex);
+}
+
+/* Disable the CPR H/W Block */
+static void cpr_disable(struct msm_cpr *cpr)
+{
+	mutex_lock(&cpr->cpr_mutex);
+	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
+	mutex_unlock(&cpr->cpr_mutex);
+}
+
+static int32_t cpr_poll_result(struct msm_cpr *cpr)
+{
+	uint32_t val = 0;
+	int8_t rc = 0;
+
+	rc = readl_poll_timeout(cpr->base + RBCPR_RESULT_0, val, ~val & BUSY_M,
+				10, 1000);
+	if (rc)
+		pr_info("%s: RBCPR_RESULT_0 read error: %d\n",
+			 __func__, rc);
+	return rc;
+}
+
+static int32_t cpr_poll_result_done(struct msm_cpr *cpr)
+{
+	uint32_t val = 0;
+	int8_t rc = 0;
+
+	rc = readl_poll_timeout(cpr->base + RBIF_IRQ_STATUS, val, val & 0x1,
+				10, 1000);
+	if (rc)
+		pr_info("%s: RBCPR_IRQ_STATUS read error: %d\n",
+			 __func__, rc);
+	return rc;
+}
+
+static void
+cpr_2pt_kv_analysis(struct msm_cpr *cpr, struct msm_cpr_mode *chip_data)
+{
+	int32_t tgt_volt_mV = 0, level_uV, rc;
+	uint32_t quot1, quot2;
+
+	/**
+	 * 2 Point KV Analysis to calculate Step Quot
+	 * STEP_QUOT is number of QUOT units per PMIC step
+	 * STEP_QUOT = (quot1 - quot2) / 4
+	 *
+	 * The step quot is calculated once for every mode and stored for
+	 * later use.
+	 */
+	if (chip_data->step_quot != ~0)
+		goto out_2pt_kv;
+
+	/**
+	 * Using the value from chip_data->tgt_volt_offset
+	 * calculate the new PMIC adjusted voltages and set
+	 * the PMIC to provide this value.
+	 *
+	 * Assuming default voltage is the highest value of safe boot up
+	 * voltage, offset is always subtracted from it.
+	 *
+	 */
+	if (chip_data->tgt_volt_offset > 0) {
+		tgt_volt_mV = chip_data->calibrated_mV -
+			(chip_data->tgt_volt_offset * cpr->vp->step_size);
+	}
+	pr_debug("tgt_volt_mV = %d, calibrated_mV = %d", tgt_volt_mV,
+			chip_data->calibrated_mV);
+
+	/* level_uV = tgt_volt_mV * 1000; */
+	level_uV = 1350000;
+	/* Call the PMIC specific routine to set the voltage */
+	rc = regulator_set_voltage(cpr->vreg_cx, level_uV, level_uV);
+	if (rc) {
+		pr_err("%s: Initial voltage set at %duV failed. %d\n",
+			__func__, level_uV, rc);
+		return;
+	}
+	rc = regulator_enable(cpr->vreg_cx);
+	if (rc) {
+		pr_err("failed to enable %s, rc=%d\n", "vdd_cx", rc);
+		return;
+	}
+
+	/* Store the adjusted value of voltage */
+	chip_data->calibrated_mV = 1300;
+
+	/* Take first CPR measurement at a higher voltage to get QUOT1 */
+
+	/* Enable the Software mode of operation */
+	cpr_modify_reg(cpr, RBCPR_CTL, HW_TO_PMIC_EN_M, SW_MODE);
+
+	/* Enable the cpr measurement */
+	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, ENABLE_CPR);
+
+	/* IRQ is already disabled */
+	rc = cpr_poll_result_done(cpr);
+	if (rc) {
+		pr_err("%s: Quot1: Exiting due to INT_DONE poll timeout\n",
+			__func__);
+		return;
+	}
+
+	rc = cpr_poll_result(cpr);
+	if (rc) {
+		pr_err("%s: Quot1: Exiting due to BUSY poll timeout\n",
+			__func__);
+		return;
+	}
+
+	quot1 = (cpr_read_reg(cpr, RBCPR_DEBUG1) & QUOT_SLOW_M) >> 12;
+
+	/* Take second CPR measurement at a lower voltage to get QUOT2 */
+	level_uV = 1300000;
+
+	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
+	/* Call the PMIC specific routine to set the voltage */
+	rc = regulator_set_voltage(cpr->vreg_cx, level_uV, level_uV);
+	if (rc) {
+		pr_err("%s: Voltage set at %duV failed. %d\n",
+			__func__, level_uV, rc);
+		return;
+	}
+
+	cpr_modify_reg(cpr, RBCPR_CTL, HW_TO_PMIC_EN_M, SW_MODE);
+	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, ENABLE_CPR);
+
+	/* cpr_write_reg(cpr, RBIF_CONT_NACK_CMD, 0x1); */
+	rc = cpr_poll_result_done(cpr);
+	if (rc) {
+		pr_err("%s: Quot2: Exiting due to INT_DONE poll timeout\n",
+			__func__);
+		goto err_poll_result_done;
+	}
+	/* IRQ is already disabled */
+	rc = cpr_poll_result(cpr);
+	if (rc) {
+		pr_err("%s: Quot2: Exiting due to BUSY poll timeout\n",
+			__func__);
+		goto err_poll_result;
+	}
+	quot2 = (cpr_read_reg(cpr, RBCPR_DEBUG1) & QUOT_SLOW_M) >> 12;
+	chip_data->step_quot = (quot1 - quot2) / 4;
+	pr_debug("%s: Calculated Step Quot is %d\n",
+			__func__, chip_data->step_quot);
+	/* Disable the cpr */
+	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
+
+out_2pt_kv:
+	/* Program the step quot */
+	cpr_write_reg(cpr, RBCPR_STEP_QUOT, (chip_data->step_quot & 0xFF));
+	return;
+err_poll_result:
+err_poll_result_done:
+	regulator_disable(cpr->vreg_cx);
+}
+
+static inline
+void cpr_irq_clr_and_ack(struct msm_cpr *cpr, uint32_t mask)
+{
+	/* Clear the interrupt */
+	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+	/* Acknowledge the Recommendation */
+	cpr_write_reg(cpr, RBIF_CONT_ACK_CMD, 0x1);
+}
+
+static inline
+void cpr_irq_clr_and_nack(struct msm_cpr *cpr, uint32_t mask)
+{
+	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+	cpr_write_reg(cpr, RBIF_CONT_NACK_CMD, 0x1);
+}
+
+static void cpr_irq_set(struct msm_cpr *cpr, uint32_t irq, bool enable)
+{
+	uint32_t irq_enabled;
+
+	irq_enabled = cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line));
+	if (enable == 1)
+		irq_enabled |= irq;
+	else
+		irq_enabled &= ~irq;
+	cpr_modify_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line),
+			INT_MASK, irq_enabled);
+}
+
+static void
+cpr_up_event_handler(struct msm_cpr *cpr, uint32_t new_volt)
+{
+	int rc, set_volt_mV;
+	struct msm_cpr_mode *chip_data;
+
+	chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
+
+	/**
+	 * FIXME: Need to handle a potential race condition between
+	 * freq switch handler and CPR interrupt handler here
+	 */
+	/* Set New PMIC voltage */
+	set_volt_mV = (new_volt < chip_data->Vmax ? new_volt
+				: chip_data->Vmax);
+	rc = regulator_set_voltage(cpr->vreg_cx, set_volt_mV * 1000,
+					set_volt_mV * 1000);
+	if (rc) {
+		pr_err("%s: Voltage set at %dmV failed. %d\n",
+			__func__, set_volt_mV, rc);
+		cpr_irq_clr_and_nack(cpr, BIT(4) | BIT(0));
+		return;
+	}
+	pr_debug("%s: Voltage set at %dmV\n", __func__, set_volt_mV);
+
+	/**
+	 * Save the new calibrated voltage to be re-used
+	 * whenever we return to same mode after a mode switch.
+	 */
+	chip_data->calibrated_mV = set_volt_mV;
+
+	/* Clear all the interrupts */
+	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+
+	/* Disable Auto ACK for Down interrupts */
+	cpr_modify_reg(cpr, RBCPR_CTL, SW_AUTO_CONT_NACK_DN_EN_M, 0);
+
+	/* Enable down interrupts to App as it might have got disabled if CPR
+	 * hit Vmin earlier. Voltage set is above Vmin now.
+	 */
+	cpr_irq_set(cpr, DOWN_INT, 1);
+
+	/* Acknowledge the Recommendation */
+	cpr_write_reg(cpr, RBIF_CONT_ACK_CMD, 0x1);
+}
+
+static void
+cpr_dn_event_handler(struct msm_cpr *cpr, uint32_t new_volt)
+{
+	int rc, set_volt_mV;
+	struct msm_cpr_mode *chip_data;
+
+	chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
+
+	/**
+	 * FIXME: Need to handle a potential race condition between
+	 * freq switch handler and CPR interrupt handler here
+	 */
+	/* Set New PMIC volt */
+	set_volt_mV = (new_volt > chip_data->Vmin ? new_volt
+				: chip_data->Vmin);
+	rc = regulator_set_voltage(cpr->vreg_cx, set_volt_mV * 1000,
+					set_volt_mV * 1000);
+	if (rc) {
+		pr_err("%s: Voltage at %dmV failed %d\n",
+			__func__, set_volt_mV, rc);
+		cpr_irq_clr_and_nack(cpr, BIT(2) | BIT(0));
+		return;
+	}
+	pr_debug("%s: Voltage set at %dmV\n", __func__, set_volt_mV);
+
+	/**
+	 * Save the new calibrated voltage to be re-used
+	 * whenever we return to same mode after a mode switch.
+	 */
+	chip_data->calibrated_mV = set_volt_mV;
+
+	/* Clear all the interrupts */
+	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+
+	if (new_volt <= chip_data->Vmin) {
+		/*
+		 * Disable down interrupt to App after we hit Vmin
+		 * It shall be enabled after we service an up interrupt
+		 *
+		 * A race condition between freq switch handler and CPR
+		 * interrupt handler is possible. So, do not disable
+		 * interrupt if a freq switch already caused a mode
+		 * change since we need this interrupt in the new mode.
+		 */
+		if (cpr->cpr_mode == cpr->prev_mode) {
+			/* Enable Auto ACK for CPR Down Flags
+			 * while DOWN_INT to App is disabled */
+			cpr_modify_reg(cpr, RBCPR_CTL,
+					SW_AUTO_CONT_NACK_DN_EN_M,
+					SW_AUTO_CONT_NACK_DN_EN);
+			cpr_irq_set(cpr, DOWN_INT, 0);
+			pr_debug("%s: DOWN_INT disabled\n", __func__);
+		}
+	}
+	/* Acknowledge the Recommendation */
+	cpr_write_reg(cpr, RBIF_CONT_ACK_CMD, 0x1);
+}
+
+static void cpr_set_vdd(struct msm_cpr *cpr, enum cpr_action action)
+{
+	uint32_t curr_volt, new_volt, error_step;
+	struct msm_cpr_mode *chip_data;
+
+	chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
+	error_step = cpr_read_reg(cpr, RBCPR_RESULT_0) >> 2;
+	error_step &= 0xF;
+	curr_volt = chip_data->calibrated_mV;
+
+	if (action == UP) {
+		/**
+		 * Using up margin in the comparison helps avoid having to
+		 * change up threshold values in chip register.
+		 */
+		if (error_step < (cpr->config->up_threshold +
+					cpr->config->up_margin)) {
+			/* FIXME: Avoid repeated dn interrupts if we are here */
+			pr_debug("UP_INT error step too small to set\n");
+			cpr_irq_clr_and_nack(cpr, BIT(4) | BIT(0));
+			return;
+		}
+
+		/* Calculte new PMIC voltage */
+		new_volt = curr_volt + (error_step * cpr->vp->step_size);
+		pr_debug("UP_INT: new_volt: %d\n", new_volt);
+		cpr_up_event_handler(cpr, new_volt);
+
+	} else if (action == DOWN) {
+		/**
+		 * Using down margin in the comparison helps avoid having to
+		 * change down threshold values in chip register.
+		 */
+		if (error_step < (cpr->config->dn_threshold +
+					cpr->config->dn_margin)) {
+			/* FIXME: Avoid repeated dn interrupts if we are here */
+			pr_debug("DOWN_INT error_step too small to set\n");
+			cpr_irq_clr_and_nack(cpr, BIT(2) | BIT(0));
+			return;
+		}
+
+		/* Calculte new PMIC voltage */
+		new_volt = curr_volt - (error_step * cpr->vp->step_size);
+		pr_debug("DOWN_INT: new_volt: %d\n", new_volt);
+		cpr_dn_event_handler(cpr, new_volt);
+	}
+}
+
+static irqreturn_t cpr_irq0_handler(int irq, void *dev_id)
+{
+	struct msm_cpr *cpr = dev_id;
+	uint32_t reg_val, ctl_reg;
+
+	reg_val = cpr_read_reg(cpr, RBIF_IRQ_STATUS);
+	ctl_reg = cpr_read_reg(cpr, RBCPR_CTL);
+
+	/* Following sequence of handling is as per each IRQ's priority */
+	if (reg_val & BIT(4)) {
+		pr_debug(" CPR:IRQ %d occured for UP Flag\n", irq);
+		cpr_set_vdd(cpr, UP);
+
+	} else if ((reg_val & BIT(2)) && !(ctl_reg & SW_AUTO_CONT_NACK_DN_EN)) {
+		pr_debug(" CPR:IRQ %d occured for Down Flag\n", irq);
+		cpr_set_vdd(cpr, DOWN);
+
+	} else if (reg_val & BIT(1)) {
+		pr_debug(" CPR:IRQ %d occured for Min Flag\n", irq);
+		cpr_irq_clr_and_nack(cpr, BIT(1) | BIT(0));
+
+	} else if (reg_val & BIT(5)) {
+		pr_debug(" CPR:IRQ %d occured for MAX Flag\n", irq);
+		cpr_irq_clr_and_nack(cpr, BIT(5) | BIT(0));
+
+	} else if (reg_val & BIT(3)) {
+		/* SW_AUTO_CONT_ACK_EN is enabled */
+		pr_debug(" CPR:IRQ %d occured for Mid Flag\n", irq);
+	}
+	return IRQ_HANDLED;
+}
+
+static void cpr_config(struct msm_cpr *cpr)
+{
+	uint32_t delay_count, cnt = 0, rc, tmp_uV;
+	struct msm_cpr_mode *chip_data;
+
+	chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
+
+	/* Program the SW vlevel */
+	cpr_modify_reg(cpr, RBIF_SW_VLEVEL, SW_VLEVEL_M,
+			cpr->config->sw_vlevel);
+
+	/* Set the floor and ceiling values */
+	cpr->floor =  cpr->config->floor;
+	cpr->ceiling = cpr->config->ceiling;
+
+	/* Program the Ceiling & Floor values */
+	cpr_modify_reg(cpr, RBIF_LIMIT, (CEILING_M | FLOOR_M),
+					((cpr->ceiling << 6) | cpr->floor));
+
+	/* Program the Up and Down Threshold values */
+	cpr_modify_reg(cpr, RBCPR_CTL, UP_THRESHOLD_M | DN_THRESHOLD_M,
+			cpr->config->up_threshold << 24 |
+			cpr->config->dn_threshold << 28);
+
+	cpr->curr_osc = chip_data->ring_osc;
+
+	/**
+	 * Program the gate count and target values
+	 * for all the ring oscilators
+	 */
+	while (cnt < NUM_OSC) {
+		cpr_modify_reg(cpr, RBCPR_GCNT_TARGET(cnt),
+				(GCNT_M | TARGET_M),
+				(chip_data->ring_osc_data[cnt].gcnt << 12 |
+				chip_data->ring_osc_data[cnt].target_count));
+		pr_debug("RBCPR_GCNT_TARGET(%d): = 0x%x\n", cnt,
+			readl_relaxed(cpr->base + RBCPR_GCNT_TARGET(cnt)));
+		cnt++;
+	}
+
+	/* Configure the step quot */
+	cpr_2pt_kv_analysis(cpr, chip_data);
+
+	/**
+	 * Call the PMIC specific routine to set the voltage
+	 * Set with an extra step since it helps as per
+	 * characterization data.
+	 */
+	chip_data->calibrated_mV +=  cpr->vp->step_size;
+	tmp_uV = chip_data->calibrated_mV * 1000;
+	rc = regulator_set_voltage(cpr->vreg_cx, tmp_uV, tmp_uV);
+	if (rc)
+		pr_err("%s: Voltage set failed %d\n", __func__, rc);
+
+	/* Program the Timer for default delay between CPR measurements */
+	delay_count = 0xFFFF;
+	cpr_write_reg(cpr, RBCPR_TIMER_INTERVAL, delay_count);
+
+	/* Enable the Timer */
+	cpr_modify_reg(cpr, RBCPR_CTL, TIMER_M, ENABLE_TIMER);
+
+	/* Enable Auto ACK for Mid interrupts */
+	cpr_modify_reg(cpr, RBCPR_CTL, SW_AUTO_CONT_ACK_EN_M,
+			SW_AUTO_CONT_ACK_EN);
+}
+
+static void cpr_mode_config(struct msm_cpr *cpr, enum cpr_mode mode)
+{
+	if (cpr->cpr_mode == mode)
+		return;
+
+	cpr->cpr_mode = mode;
+	pr_debug("%s: Switching to %s mode\n", __func__,
+		(mode == TURBO_MODE ? "TURBO" : "NORMAL"));
+
+	/* Configure the new mode */
+	cpr_config(cpr);
+}
+
+static int
+cpr_freq_transition(struct notifier_block *nb, unsigned long val,
+				void *data)
+{
+	struct msm_cpr *cpr = container_of(nb, struct msm_cpr, freq_transition);
+	struct cpufreq_freqs *freqs = data;
+
+	switch (val) {
+	case CPUFREQ_PRECHANGE:
+		return 0;
+		pr_debug("pre freq change notification to cpr\n");
+
+		disable_irq(cpr->irq);
+		cpr_disable(cpr);
+		cpr->prev_mode = cpr->cpr_mode;
+		break;
+	case CPUFREQ_POSTCHANGE:
+		return 0;
+		pr_debug("post freq change notification to cpr\n");
+
+		if (freqs->new >= cpr->config->nom_freq_limit)
+			cpr_mode_config(cpr, TURBO_MODE);
+		else
+			cpr_mode_config(cpr, NORMAL_MODE);
+		/**
+		 * Enable all interrupts. One of them could be in a disabled
+		 * state if vdd had hit Vmax / Vmin earlier
+		 */
+		cpr_irq_set(cpr, (UP_INT | DOWN_INT), 1);
+
+		enable_irq(cpr->irq);
+
+		cpr_enable(cpr);
+
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int msm_cpr_resume(struct device *dev)
+{
+	struct msm_cpr *cpr = dev_get_drvdata(dev);
+	int osc_num = cpr->config->cpr_mode_data->ring_osc;
+
+	cpr_write_reg(cpr, RBCPR_TIMER_INTERVAL,
+		cpr_save_state.rbif_timer_interval);
+	cpr_write_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line),
+		cpr_save_state.rbif_int_en);
+	cpr_write_reg(cpr, RBIF_LIMIT,
+		cpr_save_state.rbif_limit);
+	cpr_write_reg(cpr, RBIF_TIMER_ADJUST,
+		cpr_save_state.rbif_timer_adjust);
+	cpr_write_reg(cpr, RBCPR_GCNT_TARGET(osc_num),
+		cpr_save_state.rbcpr_gcnt_target);
+	cpr_write_reg(cpr, RBCPR_STEP_QUOT,
+		cpr_save_state.rbcpr_step_quot);
+	cpr_write_reg(cpr, RBIF_SW_VLEVEL,
+		cpr_save_state.rbif_sw_level);
+
+	cpr_enable(cpr);
+	cpr_write_reg(cpr, RBCPR_CTL,
+		cpr_save_state.rbcpr_ctl);
+	enable_irq(cpr->irq);
+
+	return 0;
+}
+
+static int msm_cpr_suspend(struct device *dev)
+
+{
+	struct msm_cpr *cpr = dev_get_drvdata(dev);
+	int osc_num = cpr->config->cpr_mode_data->ring_osc;
+
+	cpr_save_state.rbif_timer_interval =
+		cpr_read_reg(cpr, RBCPR_TIMER_INTERVAL);
+	cpr_save_state.rbif_int_en =
+		cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line));
+	cpr_save_state.rbif_limit =
+		cpr_read_reg(cpr, RBIF_LIMIT);
+	cpr_save_state.rbif_timer_adjust =
+		cpr_read_reg(cpr, RBIF_TIMER_ADJUST);
+	cpr_save_state.rbcpr_gcnt_target =
+		cpr_read_reg(cpr, RBCPR_GCNT_TARGET(osc_num));
+	cpr_save_state.rbcpr_step_quot =
+		cpr_read_reg(cpr, RBCPR_STEP_QUOT);
+	cpr_save_state.rbif_sw_level =
+		cpr_read_reg(cpr, RBIF_SW_VLEVEL);
+	cpr_save_state.rbcpr_ctl =
+		cpr_read_reg(cpr, RBCPR_CTL);
+
+	disable_irq(cpr->irq);
+	cpr_disable(cpr);
+
+	return 0;
+}
+
+void msm_cpr_pm_resume(void)
+{
+	msm_cpr_resume(&cpr_pdev->dev);
+}
+EXPORT_SYMBOL(msm_cpr_pm_resume);
+
+void msm_cpr_pm_suspend(void)
+{
+	msm_cpr_suspend(&cpr_pdev->dev);
+}
+EXPORT_SYMBOL(msm_cpr_pm_suspend);
+#endif
+
+void msm_cpr_disable(void)
+{
+	struct msm_cpr *cpr = platform_get_drvdata(cpr_pdev);
+	cpr_disable(cpr);
+}
+EXPORT_SYMBOL(msm_cpr_disable);
+
+void msm_cpr_enable(void)
+{
+	struct msm_cpr *cpr = platform_get_drvdata(cpr_pdev);
+	cpr_enable(cpr);
+}
+EXPORT_SYMBOL(msm_cpr_enable);
+
+static int __devinit msm_cpr_probe(struct platform_device *pdev)
+{
+	int res, irqn, irq_enabled;
+	struct msm_cpr *cpr;
+	const struct msm_cpr_config *pdata = pdev->dev.platform_data;
+	void __iomem *base;
+	struct resource *mem;
+
+	if (!pdata) {
+		pr_err("CPR: Platform data is not available\n");
+		return -EIO;
+	}
+
+	cpr = devm_kzalloc(&pdev->dev, sizeof(struct msm_cpr), GFP_KERNEL);
+	if (!cpr)
+		return -ENOMEM;
+
+	/* Initialize platform_data */
+	cpr->config = pdata;
+
+	cpr_pdev = pdev;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem || !mem->start) {
+		pr_err("CPR: get resource failed\n");
+		res = -ENXIO;
+		goto out;
+	}
+
+	base = ioremap_nocache(mem->start, resource_size(mem));
+	if (!base) {
+		pr_err("CPR: ioremap failed\n");
+		res = -ENOMEM;
+		goto out;
+	}
+
+	if (cpr->config->irq_line < 0) {
+		pr_err("CPR: Invalid IRQ line specified\n");
+		res = -ENXIO;
+		goto err_ioremap;
+	}
+	irqn = platform_get_irq(pdev, cpr->config->irq_line);
+	if (irqn < 0) {
+		pr_err("CPR: Unable to get irq\n");
+		res = -ENXIO;
+		goto err_ioremap;
+	}
+
+	cpr->irq = irqn;
+
+	cpr->base = base;
+
+	cpr->vp = pdata->vp_data;
+
+	mutex_init(&cpr->cpr_mutex);
+
+	/* Initialize the Voltage domain for CPR */
+	cpr->vreg_cx = regulator_get(&pdev->dev, "vddx_cx");
+	if (IS_ERR(cpr->vreg_cx)) {
+		res = PTR_ERR(cpr->vreg_cx);
+		pr_err("could not get regulator: %d\n", res);
+		goto err_reg_get;
+	}
+
+	/* Assume current mode is TURBO Mode */
+	cpr->cpr_mode = TURBO_MODE;
+	cpr->prev_mode = TURBO_MODE;
+
+	/* Initial configuration of CPR */
+	cpr_config(cpr);
+
+	platform_set_drvdata(pdev, cpr);
+
+	/* Initialze the Debugfs Entry for cpr */
+	res = msm_cpr_debug_init(cpr->base);
+	if (res) {
+		pr_err("CPR: Debugfs Creation Failed\n");
+		goto err_ioremap;
+	}
+
+	/* Register the interrupt handler for IRQ 0 */
+	res = request_threaded_irq(irqn, NULL, cpr_irq0_handler,
+			IRQF_TRIGGER_RISING, "msm-cpr-irq0", cpr);
+	if (res) {
+		pr_err("CPR: request irq failed for IRQ %d\n", irqn);
+		goto err_ioremap;
+	}
+
+	/**
+	 * Enable the requested interrupt lines.
+	 * Do not enable MID_INT since we shall use
+	 * SW_AUTO_CONT_ACK_EN bit.
+	 */
+	irq_enabled = INT_MASK & ~MID_INT;
+	cpr_modify_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line),
+			INT_MASK, irq_enabled);
+
+	/* Enable the cpr */
+	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, ENABLE_CPR);
+
+
+	cpr->freq_transition.notifier_call = cpr_freq_transition;
+	cpufreq_register_notifier(&cpr->freq_transition,
+					CPUFREQ_TRANSITION_NOTIFIER);
+
+	return res;
+
+err_reg_get:
+	free_irq(irqn, cpr);
+err_ioremap:
+	iounmap(base);
+out:
+	return res;
+}
+
+static int __devexit msm_cpr_remove(struct platform_device *pdev)
+{
+	struct msm_cpr *cpr = platform_get_drvdata(pdev);
+
+	cpufreq_unregister_notifier(&cpr->freq_transition,
+					CPUFREQ_TRANSITION_NOTIFIER);
+
+	regulator_disable(cpr->vreg_cx);
+	regulator_put(cpr->vreg_cx);
+	free_irq(cpr->irq, cpr);
+	iounmap(cpr->base);
+	mutex_destroy(&cpr->cpr_mutex);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static const struct dev_pm_ops msm_cpr_dev_pm_ops = {
+	.suspend = msm_cpr_suspend,
+	.resume = msm_cpr_resume,
+};
+
+static struct platform_driver msm_cpr_driver = {
+	.probe = msm_cpr_probe,
+	.remove = __devexit_p(msm_cpr_remove),
+	.driver = {
+		.name = MODULE_NAME,
+		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm = &msm_cpr_dev_pm_ops,
+#endif
+	},
+};
+
+static int __init msm_init_cpr(void)
+{
+	return platform_driver_register(&msm_cpr_driver);
+}
+
+module_init(msm_init_cpr);
+
+static void __exit msm_exit_cpr(void)
+{
+	platform_driver_unregister(&msm_cpr_driver);
+}
+
+module_exit(msm_exit_cpr);
+
+MODULE_DESCRIPTION("MSM CPR Driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/msm_cpr.h b/arch/arm/mach-msm/msm_cpr.h
new file mode 100644
index 0000000..2642b9c
--- /dev/null
+++ b/arch/arm/mach-msm/msm_cpr.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_CPR_H
+#define __ARCH_ARM_MACH_MSM_CPR_H
+
+/* Register Offsets for RBCPR */
+
+/* RBCPR Gate Count and Target Registers */
+#define RBCPR_GCNT_TARGET(n)	(0x60 + 4 * n)
+
+/* RBCPR Timer Control */
+#define RBCPR_TIMER_INTERVAL	0x44
+#define RBIF_TIMER_ADJUST	0x4C
+
+/* RBCPR Config Register */
+#define RBIF_LIMIT		0x48
+#define RBCPR_STEP_QUOT		0X80
+#define RBCPR_CTL		0x90
+#define RBIF_SW_VLEVEL		0x94
+#define RBIF_CONT_ACK_CMD	0x98
+#define RBIF_CONT_NACK_CMD	0x9C
+
+/* RBCPR Result status Register */
+#define RBCPR_RESULT_0		0xA0
+#define RBCPR_RESULT_1		0xA4
+#define RBCPR_QUOT_AVG		0x118
+
+/* RBCPR DEBUG Register */
+#define RBCPR_DEBUG1		0x120
+
+/* RBCPR Interrupt Control Register */
+#define RBIF_IRQ_EN(n)		(0x100 + 4 * n)
+#define RBIF_IRQ_CLEAR		0x110
+#define RBIF_IRQ_STATUS		0x114
+
+/* Bit Mask Values */
+#define GCNT_M				0x003FF000
+#define TARGET_M			0x00000FFF
+#define SW_VLEVEL_M			0x0000003F
+#define UP_FLAG_M			0x00000010
+#define DOWN_FLAG_M			0x00000004
+#define CEILING_M			0x00000FC0
+#define FLOOR_M				0x0000003F
+#define LOOP_EN_M			0x00000001
+#define TIMER_M				0x00000008
+#define SW_AUTO_CONT_ACK_EN_M		0x00000020
+#define SW_AUTO_CONT_NACK_DN_EN_M	0x00000040
+#define HW_TO_PMIC_EN_M			BIT(4)
+#define BUSY_M				BIT(19)
+#define QUOT_SLOW_M			0x00FFF000
+#define UP_THRESHOLD_M			0x0F000000
+#define DN_THRESHOLD_M			0xF0000000
+
+/* Bit Values */
+#define ENABLE_CPR		BIT(0)
+#define DISABLE_CPR		0x0
+#define ENABLE_TIMER		BIT(3)
+#define DISABLE_TIMER		0x0
+#define SW_MODE			0x0
+#define SW_AUTO_CONT_ACK_EN	BIT(5)
+#define SW_AUTO_CONT_NACK_DN_EN	BIT(6)
+
+/* Test values for RBCPR RUMI Testing */
+#define GNT_CNT			0xC0
+#define TARGET			0xEFF
+
+#define CEILING_V		0x30
+#define FLOOR_V			0x15
+
+#define SW_LEVEL		0x20
+
+/* Interrupt Mask for All interrupt flags */
+#define INT_MASK (MIN_INT | DOWN_INT | MID_INT | UP_INT | MAX_INT)
+
+/* Number of oscilator in each sensor */
+#define NUM_OSC 8
+
+#define CPR_MODE 2
+
+/**
+ * enum cpr_mode - Modes in which cpr is used
+ */
+enum cpr_mode {
+	NORMAL_MODE = 0,
+	TURBO_MODE,
+	SVS_MODE,
+};
+
+/**
+ * enum cpr_action - Cpr actions to be taken
+ */
+enum cpr_action {
+	DOWN = 0,
+	UP,
+};
+
+/**
+ * enum cpr_interrupt
+ */
+enum cpr_interrupt {
+	DONE_INT	= BIT(0),
+	MIN_INT		= BIT(1),
+	DOWN_INT	= BIT(2),
+	MID_INT		= BIT(3),
+	UP_INT		= BIT(4),
+	MAX_INT		= BIT(5),
+};
+
+/**
+ * struct msm_vp_data - structure for VP configuration
+ * @min_volt_mV: minimum milivolt level for VP
+ * @max_volt_mV: maximum milivolt level for VP
+ * @default_volt_mV: default milivolt for VP
+ * @step_size_mV: step size of voltage
+ */
+struct msm_cpr_vp_data {
+	int min_volt;
+	int max_volt;
+	int default_volt;
+	int step_size;
+};
+
+/**
+ * struct msm_cpr_osc -  Data for CPR ring oscillator
+ * @gcnt: gate count value for the oscillator
+ * @target_count: target value for ring oscillator
+ */
+struct msm_cpr_osc {
+	int gcnt;
+	uint32_t target_count;
+};
+
+/**
+ * struct msm_cpr_mode -  Data for CPR modes of operation
+ * @msm_cpr_osc: structure for oscillator data
+ * @ring_osc: ring oscillator of the sensor
+ * @tgt_volt_offset: inital voltage offset from default value
+ * @step_quot: step Quot for CPR calcuation
+ */
+struct msm_cpr_mode {
+	struct msm_cpr_osc ring_osc_data[NUM_OSC];
+	int ring_osc;
+	int32_t tgt_volt_offset;
+	uint32_t step_quot;
+	uint32_t Vmax;
+	uint32_t Vmin;
+	uint32_t calibrated_mV;
+};
+
+/**
+ * struct msm_cpr_config -  Platform data for CPR configuration
+ * @ref_clk_khz: clock value of CPR in KHz
+ * @delay_us: timer delay in micro second
+ * @irq_line: irq line to be use (0 or 1 or 2)
+ * @msm_cpr_mode: structure for CPR mode data
+ */
+struct msm_cpr_config {
+	unsigned long ref_clk_khz;
+	unsigned long delay_us;
+	int irq_line;
+	struct msm_cpr_mode *cpr_mode_data;
+	int min_down_step;
+	uint32_t tgt_count_div_N; /* Target Cnt(Nom) = Target Cnt(Turbo) / N */
+	uint32_t floor;
+	uint32_t ceiling;
+	uint32_t sw_vlevel;
+	uint32_t up_threshold;
+	uint32_t dn_threshold;
+	uint32_t up_margin;
+	uint32_t dn_margin;
+	uint32_t nom_freq_limit;
+	struct msm_cpr_vp_data *vp_data;
+};
+
+/**
+* struct msm_cpr_config -  CPR Registers
+*/
+struct msm_cpr_reg {
+	uint32_t rbif_timer_interval;
+	uint32_t rbif_int_en;
+	uint32_t rbif_limit;
+	uint32_t rbif_timer_adjust;
+	uint32_t rbcpr_gcnt_target;
+	uint32_t rbcpr_step_quot;
+	uint32_t rbif_sw_level;
+	uint32_t rbcpr_ctl;
+};
+
+#if defined(CONFIG_MSM_CPR) || defined(CONFIG_MSM_CPR_MODULE)
+/* msm_cpr_pm_resume: Used by Power Manager for Idle Power Collapse */
+void msm_cpr_pm_resume(void);
+/* msm_cpr_pm_suspend: Used by Power Manager for Idle Power Collapse */
+void msm_cpr_pm_suspend(void);
+/* msm_cpr_enable: Used by Power Manager for GDFS */
+void msm_cpr_enable(void);
+/* msm_cpr_disable: Used by Power Manager for GDFS */
+void msm_cpr_disable(void);
+#else
+/* msm_cpr_pm_resume: Used by Power Manager for Idle Power Collapse */
+void msm_cpr_pm_resume(void) { }
+/* msm_cpr_pm_suspend: Used by Power Manager for Idle Power Collapse */
+void msm_cpr_pm_suspend(void) { }
+/* msm_cpr_enable: Used by Power Manager for GDFS */
+void msm_cpr_enable(void) { }
+/* msm_cpr_disable: Used by Power Manager for GDFS */
+void msm_cpr_disable(void) { }
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+int msm_cpr_debug_init(void *);
+#else
+static inline int msm_cpr_debug_init(void *) { return 0; }
+#endif
+#endif /* __ARCH_ARM_MACH_MSM_CPR_H */
diff --git a/arch/arm/mach-msm/msm_vp.c b/arch/arm/mach-msm/msm_vp.c
new file mode 100644
index 0000000..2569474
--- /dev/null
+++ b/arch/arm/mach-msm/msm_vp.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#include <mach/msm_iomap.h>
+
+/* Address for Perf Level Registor */
+#define VDD_APC_PLEVEL_BASE (MSM_CLK_CTL_BASE + 0x0298)
+#define VDD_APC_PLEVEL(n) (VDD_APC_PLEVEL_BASE + 4 * n)
+
+/* Address for SYS_P_Level register */
+#define VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124)
+
+#define MV_TO_UV(mv) ((mv)*1000)
+#define UV_TO_MV(uv) (((uv)+999)/1000)
+
+#define MSM_VP_REGULATOR_DEV_NAME  "vp-regulator"
+
+/**
+ * Convert Voltage to PLEVEL register value
+ * Here x is required voltage in minivolt
+ * e.g. if Required voltage is 1200mV then
+ * required value to be programmed into the
+ * Plevel register is 0x32. This equation is
+ * based on H/W logic being used in SVS controller.
+ *
+ * Here we are taking the minimum voltage step
+ * to be 12.5mV as per H/W logic and adding 0x20
+ * is for selecting the reference voltage.
+ * 750mV is minimum voltage of MSMC2 smps.
+ */
+#define VOLT_TO_BIT(x) (((x-750)/(12500/1000)) + 0x20)
+#define VREG_VREF_SEL  (1 << 5)
+#define VREG_PD_EN     (1 << 6)
+
+/**
+ * struct msm_vp -  Structure for VP
+ * @regulator_dev: structure for regulator device
+ * @current_voltage: current voltage value
+ */
+struct msm_vp {
+	struct device		*dev;
+	struct regulator_dev	*rdev;
+	int current_voltage;
+};
+
+/* Function to change the Vdd Level */
+static int vp_reg_set_voltage(struct regulator_dev *rdev, int min_uV,
+						int max_uV, unsigned *sel)
+{
+	struct msm_vp *vp = rdev_get_drvdata(rdev);
+	uint32_t reg_val, perf_level, plevel, cur_plevel, fine_step_volt;
+
+	reg_val = readl_relaxed(VDD_SVS_PLEVEL_ADDR);
+	perf_level = reg_val & 0x07;
+
+	plevel = (min_uV - 750000) / 25000;
+	fine_step_volt = (min_uV - 750000) % 25000;
+
+	/**
+	 * Program the new voltage level for the current perf_level
+	 * in corresponding PLEVEL register.
+	 */
+	cur_plevel = readl_relaxed(VDD_APC_PLEVEL(perf_level));
+	/* clear lower 6 bits */
+	cur_plevel &= ~0x3F;
+	cur_plevel |= (plevel | VREG_VREF_SEL);
+	if (fine_step_volt >= 12500)
+		cur_plevel |= VREG_PD_EN;
+	writel_relaxed(cur_plevel, VDD_APC_PLEVEL(perf_level));
+
+	/* Clear the current perf level */
+	reg_val &= 0xF8;
+	writel_relaxed(reg_val, VDD_SVS_PLEVEL_ADDR);
+
+	/* Initiate the PMIC SSBI request to change the voltage */
+	reg_val |= (BIT(7) | perf_level << 3);
+	writel_relaxed(reg_val, VDD_SVS_PLEVEL_ADDR);
+	mb();
+	udelay(62);
+
+	if ((readl_relaxed(VDD_SVS_PLEVEL_ADDR) & 0x07) != perf_level) {
+		pr_err("Vdd Set Failed\n");
+		return -EIO;
+	}
+
+	vp->current_voltage = (min_uV / 1000);
+	return 0;
+}
+
+static int vp_reg_get_voltage(struct regulator_dev *rdev)
+{
+	struct msm_vp *vp = rdev_get_drvdata(rdev);
+
+	return MV_TO_UV(vp->current_voltage);
+}
+
+static int vp_reg_enable(struct regulator_dev *rdev)
+{
+	return 0;
+}
+
+static int vp_reg_disable(struct regulator_dev *rdev)
+{
+	return 0;
+}
+
+/* Regulator registration specific data */
+/* FIXME: should move to board-xx-regulator.c file */
+static struct regulator_consumer_supply vp_consumer =
+	REGULATOR_SUPPLY("vddx_cx", "msm-cpr");
+
+static struct regulator_init_data vp_reg_data = {
+	.constraints	= {
+		.name		= "vddx_c2",
+		.min_uV		= 750000,
+		.max_uV		= 1500000,
+		.valid_ops_mask	= REGULATOR_CHANGE_VOLTAGE |
+					REGULATOR_CHANGE_STATUS,
+		.valid_modes_mask = REGULATOR_MODE_NORMAL,
+		.boot_on	= 1,
+		.input_uV	= 0,
+		.always_on	= 1,
+	},
+	.num_consumer_supplies = 1,
+	.consumer_supplies = &vp_consumer,
+};
+
+/* Regulator specific ops */
+static struct regulator_ops vp_reg_ops = {
+	.enable			= vp_reg_enable,
+	.disable		= vp_reg_disable,
+	.get_voltage		= vp_reg_get_voltage,
+	.set_voltage		= vp_reg_set_voltage,
+};
+
+/* Regulator Description */
+static struct regulator_desc vp_reg = {
+	.name = "vddcx",
+	.id = -1,
+	.ops = &vp_reg_ops,
+	.type = REGULATOR_VOLTAGE,
+};
+
+static int __devinit msm_vp_reg_probe(struct platform_device *pdev)
+{
+	struct msm_vp *vp;
+	int rc;
+
+	vp = kzalloc(sizeof(struct msm_vp), GFP_KERNEL);
+	if (!vp) {
+		pr_err("Could not allocate memory for VP\n");
+		return -ENOMEM;
+	}
+
+	vp->rdev = regulator_register(&vp_reg, NULL, &vp_reg_data, vp, NULL);
+	if (IS_ERR(vp->rdev)) {
+		rc = PTR_ERR(vp->rdev);
+		pr_err("Failed to register regulator: %d\n", rc);
+		goto error;
+	}
+
+	platform_set_drvdata(pdev, vp);
+
+	return 0;
+error:
+	kfree(vp);
+	return rc;
+}
+
+static int __devexit msm_vp_reg_remove(struct platform_device *pdev)
+{
+	struct msm_vp *vp = platform_get_drvdata(pdev);
+
+	regulator_unregister(vp->rdev);
+	platform_set_drvdata(pdev, NULL);
+	kfree(vp);
+
+	return 0;
+}
+
+static struct platform_driver msm_vp_reg_driver = {
+	.probe	= msm_vp_reg_probe,
+	.remove = __devexit_p(msm_vp_reg_remove),
+	.driver = {
+		.name	= MSM_VP_REGULATOR_DEV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init msm_vp_reg_init(void)
+{
+	return platform_driver_register(&msm_vp_reg_driver);
+}
+postcore_initcall(msm_vp_reg_init);
+
+static void __exit msm_vp_reg_exit(void)
+{
+	platform_driver_unregister(&msm_vp_reg_driver);
+}
+module_exit(msm_vp_reg_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM VP regulator driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:" MSM_VP_REGULATOR_DEV_NAME);
diff --git a/arch/arm/mach-msm/msm_watchdog.c b/arch/arm/mach-msm/msm_watchdog.c
index b471426..aca7667 100644
--- a/arch/arm/mach-msm/msm_watchdog.c
+++ b/arch/arm/mach-msm/msm_watchdog.c
@@ -37,22 +37,23 @@
 
 #define TCSR_WDT_CFG	0x30
 
-#define WDT0_RST	0x38
-#define WDT0_EN		0x40
-#define WDT0_STS	0x44
-#define WDT0_BARK_TIME	0x4C
-#define WDT0_BITE_TIME	0x5C
+#define WDT_RST		0x0
+#define WDT_EN		0x8
+#define WDT_STS		0xC
+#define WDT_BARK_TIME	0x14
+#define WDT_BITE_TIME	0x24
 
 #define WDT_HZ		32768
 
 struct msm_watchdog_dump msm_dump_cpu_ctx;
 
-static void __iomem *msm_tmr0_base;
+static void __iomem *msm_wdt_base;
 
 static unsigned long delay_time;
 static unsigned long bark_time;
 static unsigned long long last_pet;
 static bool has_vic;
+static unsigned int msm_wdog_irq;
 
 /*
  * On the kernel command line specify
@@ -116,8 +117,8 @@
 	if (!enable)
 		return 0;
 
-	__raw_writel(1, msm_tmr0_base + WDT0_RST);
-	__raw_writel(0, msm_tmr0_base + WDT0_EN);
+	__raw_writel(1, msm_wdt_base + WDT_RST);
+	__raw_writel(0, msm_wdt_base + WDT_EN);
 	mb();
 	return 0;
 }
@@ -127,8 +128,8 @@
 	if (!enable)
 		return 0;
 
-	__raw_writel(1, msm_tmr0_base + WDT0_EN);
-	__raw_writel(1, msm_tmr0_base + WDT0_RST);
+	__raw_writel(1, msm_wdt_base + WDT_EN);
+	__raw_writel(1, msm_wdt_base + WDT_RST);
 	mb();
 	return 0;
 }
@@ -137,14 +138,14 @@
 			      unsigned long event, void *ptr)
 {
 	if (panic_timeout == 0) {
-		__raw_writel(0, msm_tmr0_base + WDT0_EN);
+		__raw_writel(0, msm_wdt_base + WDT_EN);
 		mb();
 	} else {
 		__raw_writel(WDT_HZ * (panic_timeout + 4),
-				msm_tmr0_base + WDT0_BARK_TIME);
+				msm_wdt_base + WDT_BARK_TIME);
 		__raw_writel(WDT_HZ * (panic_timeout + 4),
-				msm_tmr0_base + WDT0_BITE_TIME);
-		__raw_writel(1, msm_tmr0_base + WDT0_RST);
+				msm_wdt_base + WDT_BITE_TIME);
+		__raw_writel(1, msm_wdt_base + WDT_RST);
 	}
 	return NOTIFY_DONE;
 }
@@ -162,14 +163,14 @@
 {
 	struct wdog_disable_work_data *work_data =
 		container_of(work, struct wdog_disable_work_data, work);
-	__raw_writel(0, msm_tmr0_base + WDT0_EN);
+	__raw_writel(0, msm_wdt_base + WDT_EN);
 	mb();
 	if (has_vic) {
-		free_irq(WDT0_ACCSCSSNBARK_INT, 0);
+		free_irq(msm_wdog_irq, 0);
 	} else {
-		disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
+		disable_percpu_irq(msm_wdog_irq);
 		if (!appsbark_fiq) {
-			free_percpu_irq(WDT0_ACCSCSSNBARK_INT,
+			free_percpu_irq(msm_wdog_irq,
 					percpu_pdata);
 			free_percpu(percpu_pdata);
 		}
@@ -178,7 +179,7 @@
 	atomic_notifier_chain_unregister(&panic_notifier_list, &panic_blk);
 	cancel_delayed_work(&dogwork_struct);
 	/* may be suspended after the first write above */
-	__raw_writel(0, msm_tmr0_base + WDT0_EN);
+	__raw_writel(0, msm_wdt_base + WDT_EN);
 	complete(&work_data->complete);
 	pr_info("MSM Watchdog deactivated.\n");
 }
@@ -229,11 +230,11 @@
 	if (!enable)
 		return;
 
-	slack = __raw_readl(msm_tmr0_base + WDT0_STS) >> 3;
+	slack = __raw_readl(msm_wdt_base + WDT_STS) >> 3;
 	slack = ((bark_time*WDT_HZ)/1000) - slack;
 	if (slack < min_slack_ticks)
 		min_slack_ticks = slack;
-	__raw_writel(1, msm_tmr0_base + WDT0_RST);
+	__raw_writel(1, msm_wdt_base + WDT_RST);
 	time_ns = sched_clock();
 	slack_ns = (last_pet + bark_time_ns) - time_ns;
 	if (slack_ns < min_slack_ns)
@@ -329,7 +330,7 @@
 	int ret;
 
 	if (has_vic) {
-		ret = request_irq(WDT0_ACCSCSSNBARK_INT, wdog_bark_handler, 0,
+		ret = request_irq(msm_wdog_irq, wdog_bark_handler, 0,
 				  "apps_wdog_bark", NULL);
 		if (ret)
 			return;
@@ -344,7 +345,7 @@
 		}
 
 		msm_wdog_fiq_setup(stack);
-		gic_set_irq_secure(WDT0_ACCSCSSNBARK_INT);
+		gic_set_irq_secure(msm_wdog_irq);
 	} else {
 		percpu_pdata = alloc_percpu(struct msm_watchdog_pdata *);
 		if (!percpu_pdata) {
@@ -354,7 +355,7 @@
 		}
 
 		/* Must request irq before sending scm command */
-		ret = request_percpu_irq(WDT0_ACCSCSSNBARK_INT,
+		ret = request_percpu_irq(msm_wdog_irq,
 			wdog_bark_handler, "apps_wdog_bark", percpu_pdata);
 		if (ret) {
 			free_percpu(percpu_pdata);
@@ -364,20 +365,20 @@
 
 	configure_bark_dump();
 
-	__raw_writel(timeout, msm_tmr0_base + WDT0_BARK_TIME);
-	__raw_writel(timeout + 3*WDT_HZ, msm_tmr0_base + WDT0_BITE_TIME);
+	__raw_writel(timeout, msm_wdt_base + WDT_BARK_TIME);
+	__raw_writel(timeout + 3*WDT_HZ, msm_wdt_base + WDT_BITE_TIME);
 
 	schedule_delayed_work_on(0, &dogwork_struct, delay_time);
 
 	atomic_notifier_chain_register(&panic_notifier_list,
 				       &panic_blk);
 
-	__raw_writel(1, msm_tmr0_base + WDT0_EN);
-	__raw_writel(1, msm_tmr0_base + WDT0_RST);
+	__raw_writel(1, msm_wdt_base + WDT_EN);
+	__raw_writel(1, msm_wdt_base + WDT_RST);
 	last_pet = sched_clock();
 
 	if (!has_vic)
-		enable_percpu_irq(WDT0_ACCSCSSNBARK_INT, IRQ_TYPE_EDGE_RISING);
+		enable_percpu_irq(msm_wdog_irq, IRQ_TYPE_EDGE_RISING);
 
 	printk(KERN_INFO "MSM Watchdog Initialized\n");
 
@@ -400,7 +401,8 @@
 		appsbark_fiq = pdata->use_kernel_fiq;
 	}
 
-	msm_tmr0_base = msm_timer_get_timer0_base();
+	msm_wdt_base = pdata->base;
+	msm_wdog_irq = platform_get_irq(pdev, 0);
 
 	/*
 	 * This is only temporary till SBLs turn on the XPUs
diff --git a/arch/arm/mach-msm/msm_watchdog.h b/arch/arm/mach-msm/msm_watchdog.h
index 00ff0b6..5fb82ee 100644
--- a/arch/arm/mach-msm/msm_watchdog.h
+++ b/arch/arm/mach-msm/msm_watchdog.h
@@ -13,6 +13,10 @@
 #ifndef __ARCH_ARM_MACH_MSM_MSM_WATCHDOG_H
 #define __ARCH_ARM_MACH_MSM_MSM_WATCHDOG_H
 
+/* The base is just address of the WDT_RST register */
+#define WDT0_OFFSET	0x38
+#define WDT1_OFFSET	0x60
+
 struct msm_watchdog_pdata {
 	/* pet interval period in ms */
 	unsigned int pet_time;
@@ -23,6 +27,7 @@
 	bool has_vic;
 	/* You have to be running in secure mode to use FIQ */
 	bool use_kernel_fiq;
+	void __iomem *base;
 };
 
 struct msm_watchdog_dump {
diff --git a/arch/arm/mach-msm/msm_watchdog_v2.c b/arch/arm/mach-msm/msm_watchdog_v2.c
index a5f8bcc..ea408f7 100644
--- a/arch/arm/mach-msm/msm_watchdog_v2.c
+++ b/arch/arm/mach-msm/msm_watchdog_v2.c
@@ -22,6 +22,8 @@
 #include <linux/of.h>
 #include <linux/cpu.h>
 #include <linux/platform_device.h>
+#include <mach/scm.h>
+#include <mach/msm_memory_dump.h>
 
 #define MODULE_NAME "msm_watchdog"
 #define WDT0_ACCSCSSNBARK_INT 0
@@ -32,7 +34,8 @@
 #define WDT0_BARK_TIME	0x10
 #define WDT0_BITE_TIME	0x14
 
-#define MASK_SIZE	32
+#define MASK_SIZE		32
+#define SCM_SET_REGSAVE_CMD	0x2
 
 struct msm_watchdog_data {
 	unsigned int __iomem phys_base;
@@ -47,6 +50,7 @@
 	unsigned long long last_pet;
 	unsigned min_slack_ticks;
 	unsigned long long min_slack_ns;
+	void *scm_regsave;
 	cpumask_t alive_mask;
 	struct work_struct init_dogwork_struct;
 	struct delayed_work dogwork_struct;
@@ -88,11 +92,9 @@
 static void dump_cpu_alive_mask(struct msm_watchdog_data *wdog_dd)
 {
 	static char alive_mask_buf[MASK_SIZE];
-	size_t count = cpulist_scnprintf(alive_mask_buf, MASK_SIZE,
+	cpulist_scnprintf(alive_mask_buf, MASK_SIZE,
 						&wdog_dd->alive_mask);
-	alive_mask_buf[count] = '\n';
-	alive_mask_buf[count++] = '\0';
-	printk(KERN_INFO "cpu alive mask from last pet\n%s", alive_mask_buf);
+	printk(KERN_INFO "cpu alive mask from last pet %s\n", alive_mask_buf);
 }
 
 static int msm_watchdog_suspend(struct device *dev)
@@ -196,8 +198,6 @@
 	if (wdog_dd->do_ipi_ping)
 		ping_other_cpus(wdog_dd);
 	pet_watchdog(wdog_dd);
-	if (wdog_dd->do_ipi_ping)
-		dump_cpu_alive_mask(wdog_dd);
 	if (enable)
 		schedule_delayed_work(&wdog_dd->dogwork_struct,
 							delay_time);
@@ -242,6 +242,44 @@
 	return IRQ_HANDLED;
 }
 
+static void configure_bark_dump(struct msm_watchdog_data *wdog_dd)
+{
+	int ret;
+	struct msm_client_dump dump_entry;
+	struct {
+		unsigned addr;
+		int len;
+	} cmd_buf;
+
+	wdog_dd->scm_regsave = (void *)__get_free_page(GFP_KERNEL);
+	if (wdog_dd->scm_regsave) {
+		cmd_buf.addr = virt_to_phys(wdog_dd->scm_regsave);
+		cmd_buf.len  = PAGE_SIZE;
+		ret = scm_call(SCM_SVC_UTIL, SCM_SET_REGSAVE_CMD,
+					&cmd_buf, sizeof(cmd_buf), NULL, 0);
+		if (ret)
+			pr_err("Setting register save address failed.\n"
+				       "Registers won't be dumped on a dog "
+				       "bite\n");
+		dump_entry.id = MSM_CPU_CTXT;
+		dump_entry.start_addr = virt_to_phys(wdog_dd->scm_regsave);
+		dump_entry.end_addr = dump_entry.start_addr + PAGE_SIZE;
+		ret = msm_dump_table_register(&dump_entry);
+		if (ret)
+			pr_err("Setting cpu dump region failed\n"
+				"Registers wont be dumped during cpu hang\n");
+	} else {
+		pr_err("Allocating register save space failed\n"
+			       "Registers won't be dumped on a dog bite\n");
+		/*
+		 * No need to bail if allocation fails. Simply don't
+		 * send the command, and the secure side will reset
+		 * without saving registers.
+		 */
+	}
+}
+
+
 static void init_watchdog_work(struct work_struct *work)
 {
 	struct msm_watchdog_data *wdog_dd = container_of(work,
@@ -252,6 +290,7 @@
 	delay_time = msecs_to_jiffies(wdog_dd->pet_time);
 	wdog_dd->min_slack_ticks = UINT_MAX;
 	wdog_dd->min_slack_ns = ULLONG_MAX;
+	configure_bark_dump(wdog_dd);
 	timeout = (wdog_dd->bark_time * WDT_HZ)/1000;
 	__raw_writel(timeout, wdog_dd->base + WDT0_BARK_TIME);
 	__raw_writel(timeout + 3*WDT_HZ, wdog_dd->base + WDT0_BITE_TIME);
diff --git a/arch/arm/mach-msm/msm_xo.c b/arch/arm/mach-msm/msm_xo.c
index 8254502..2d61504 100644
--- a/arch/arm/mach-msm/msm_xo.c
+++ b/arch/arm/mach-msm/msm_xo.c
@@ -259,9 +259,9 @@
 		}
 		/* Ignore transitions from pin to on or vice versa */
 		if (mode && xo_voter->mode == MSM_XO_MODE_OFF)
-			clk_enable(xo_clk);
+			clk_prepare_enable(xo_clk);
 		else if (!mode)
-			clk_disable(xo_clk);
+			clk_disable_unprepare(xo_clk);
 	}
 	xo_voter->mode = mode;
 out:
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index 753f6fb..82fe2f8 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -24,14 +24,8 @@
 #include <linux/seq_file.h>
 #include <mach/ocmem_priv.h>
 
-/* This code is to temporarily work around the default state of OCMEM
-   regions in Virtio. These registers will be read from DT in a subsequent
-   patch which initializes the regions to appropriate default state.
-*/
-
 #define OCMEM_REGION_CTL_BASE 0xFDD0003C
 #define OCMEM_REGION_CTL_SIZE 0xFD0
-#define REGION_ENABLE 0x00003333
 #define GRAPHICS_REGION_CTL (0x17F000)
 
 struct ocmem_partition {
@@ -109,7 +103,7 @@
 const char *get_name(int id)
 {
 	if (!check_id(id))
-		return NULL;
+		return "Unknown";
 	return client_names[id];
 }
 
@@ -132,6 +126,15 @@
 	return offset + ocmem_pdata->base;
 }
 
+inline int zone_active(int id)
+{
+	struct ocmem_zone *z = get_zone(id);
+	if (z)
+		return z->active == true ? 1 : 0;
+	else
+		return 0;
+}
+
 static struct ocmem_plat_data *parse_static_config(struct platform_device *pdev)
 {
 	struct ocmem_plat_data *pdata = NULL;
@@ -269,6 +272,68 @@
 	return i;
 }
 
+#if defined(CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL)
+static int parse_power_ctrl_config(struct ocmem_plat_data *pdata,
+					struct device_node *node)
+{
+	pdata->rpm_pwr_ctrl = false;
+	pdata->rpm_rsc_type = ~0x0;
+	return 0;
+}
+#else
+static int parse_power_ctrl_config(struct ocmem_plat_data *pdata,
+					struct device_node *node)
+{
+	unsigned rsc_type = ~0x0;
+	pdata->rpm_pwr_ctrl = false;
+	if (of_property_read_u32(node, "qcom,resource-type",
+					&rsc_type))
+		return -EINVAL;
+	pdata->rpm_pwr_ctrl = true;
+	pdata->rpm_rsc_type = rsc_type;
+	return 0;
+
+}
+#endif /* CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL */
+
+/* Core Clock Operations */
+int ocmem_enable_core_clock(void)
+{
+	int ret;
+	ret = clk_prepare_enable(ocmem_pdata->core_clk);
+	if (ret) {
+		pr_err("ocmem: Failed to enable core clock\n");
+		return ret;
+	}
+	pr_debug("ocmem: Enabled core clock\n");
+	return 0;
+}
+
+void ocmem_disable_core_clock(void)
+{
+	clk_disable_unprepare(ocmem_pdata->core_clk);
+	pr_debug("ocmem: Disabled core clock\n");
+}
+
+/* Branch Clock Operations */
+int ocmem_enable_iface_clock(void)
+{
+	int ret;
+	ret = clk_prepare_enable(ocmem_pdata->iface_clk);
+	if (ret) {
+		pr_err("ocmem: Failed to disable branch clock\n");
+		return ret;
+	}
+	pr_debug("ocmem: Enabled iface clock\n");
+	return 0;
+}
+
+void ocmem_disable_iface_clock(void)
+{
+	clk_disable_unprepare(ocmem_pdata->iface_clk);
+	pr_debug("ocmem: Disabled iface clock\n");
+}
+
 static struct ocmem_plat_data *parse_dt_config(struct platform_device *pdev)
 {
 	struct device   *dev = &pdev->dev;
@@ -393,6 +458,11 @@
 	} else
 		dev_dbg(dev, "Found %d ocmem partitions\n", nr_parts);
 
+	if (parse_power_ctrl_config(pdata, node)) {
+		dev_err(dev, "No OCMEM RPM Resource specified\n");
+		return NULL;
+	}
+
 	pdata->nr_parts = nr_parts;
 	pdata->parts = parts;
 	pdata->nr_regions = nr_regions;
@@ -421,6 +491,7 @@
 	for (i = 0; i < pdata->nr_parts; i++) {
 		struct ocmem_partition *part = &pdata->parts[i];
 		zone = get_zone(part->id);
+		zone->active = false;
 
 		dev_dbg(dev, "Partition %d, start %lx, size %lx for %s\n",
 				i, part->p_start, part->p_size,
@@ -478,6 +549,7 @@
 			z_ops->allocate = allocate_head;
 			z_ops->free = free_head;
 		}
+		zone->active = true;
 		active_zones++;
 
 		if (active_zones == 1)
@@ -492,10 +564,34 @@
 	return 0;
 }
 
+/* Enable the ocmem graphics mpU as a workaround */
+/* This will be programmed by TZ after TZ support is integrated */
+static int ocmem_init_gfx_mpu(struct platform_device *pdev)
+{
+	int rc;
+	struct device *dev = &pdev->dev;
+	void __iomem *ocmem_region_vbase = NULL;
+
+	ocmem_region_vbase = devm_ioremap_nocache(dev, OCMEM_REGION_CTL_BASE,
+							OCMEM_REGION_CTL_SIZE);
+	if (!ocmem_region_vbase)
+		return -EBUSY;
+
+	rc = ocmem_enable_core_clock();
+
+	if (rc < 0)
+		return rc;
+
+	writel_relaxed(GRAPHICS_REGION_CTL, ocmem_region_vbase + 0xFCC);
+	ocmem_disable_core_clock();
+	return 0;
+}
+
 static int __devinit msm_ocmem_probe(struct platform_device *pdev)
 {
 	struct device   *dev = &pdev->dev;
-	void *ocmem_region_vbase = NULL;
+	struct clk *ocmem_core_clk = NULL;
+	struct clk *ocmem_iface_clk = NULL;
 
 	if (!pdev->dev.of_node) {
 		dev_info(dev, "Missing Configuration in Device Tree\n");
@@ -514,8 +610,34 @@
 
 	dev_info(dev, "OCMEM Virtual addr %p\n", ocmem_pdata->vbase);
 
+	ocmem_core_clk = devm_clk_get(dev, "core_clk");
+
+	if (IS_ERR(ocmem_core_clk)) {
+		dev_err(dev, "Unable to get the core clock\n");
+		return PTR_ERR(ocmem_core_clk);
+	}
+
+	/* The core clock is synchronous with graphics */
+	if (clk_set_rate(ocmem_core_clk, 1000) < 0) {
+		dev_err(dev, "Set rate failed on the core clock\n");
+		return -EBUSY;
+	}
+
+	ocmem_iface_clk = devm_clk_get(dev, "iface_clk");
+
+	if (IS_ERR(ocmem_iface_clk)) {
+		dev_err(dev, "Unable to get the memory interface clock\n");
+		return PTR_ERR(ocmem_core_clk);
+	};
+
+	ocmem_pdata->core_clk = ocmem_core_clk;
+	ocmem_pdata->iface_clk = ocmem_iface_clk;
+
 	platform_set_drvdata(pdev, ocmem_pdata);
 
+	if (ocmem_core_init(pdev))
+		return -EBUSY;
+
 	if (ocmem_zone_init(pdev))
 		return -EBUSY;
 
@@ -525,21 +647,14 @@
 	if (ocmem_sched_init())
 		return -EBUSY;
 
-	ocmem_region_vbase = devm_ioremap_nocache(dev, OCMEM_REGION_CTL_BASE,
-							OCMEM_REGION_CTL_SIZE);
-	if (!ocmem_region_vbase)
-		return -EBUSY;
-	/* Enable all the 3 regions until we have support for power features */
-	writel_relaxed(REGION_ENABLE, ocmem_region_vbase);
-	writel_relaxed(REGION_ENABLE, ocmem_region_vbase + 4);
-	writel_relaxed(REGION_ENABLE, ocmem_region_vbase + 8);
-	/* Enable the ocmem graphics mpU as a workaround in Virtio */
-	/* This will be programmed by TZ after TZ support is integrated */
-	writel_relaxed(GRAPHICS_REGION_CTL, ocmem_region_vbase + 0xFCC);
-
 	if (ocmem_rdm_init(pdev))
 		return -EBUSY;
 
+	if (ocmem_init_gfx_mpu(pdev)) {
+		dev_err(dev, "Unable to initialize Graphics mPU\n");
+		return -EBUSY;
+	}
+
 	dev_dbg(dev, "initialized successfully\n");
 	return 0;
 }
diff --git a/arch/arm/mach-msm/ocmem_api.c b/arch/arm/mach-msm/ocmem_api.c
index bb32fca..2604d47 100644
--- a/arch/arm/mach-msm/ocmem_api.c
+++ b/arch/arm/mach-msm/ocmem_api.c
@@ -110,6 +110,12 @@
 		return NULL;
 	}
 
+	if (!zone_active(client_id)) {
+		pr_err("ocmem: Client %s (id: %d) not allowed to use OCMEM\n",
+					get_name(client_id), client_id);
+		return NULL;
+	}
+
 	if (size < OCMEM_MIN_ALLOC) {
 		pr_err("ocmem: requested size %lx must be at least %x\n",
 				size, OCMEM_MIN_ALLOC);
@@ -136,6 +142,12 @@
 		return NULL;
 	}
 
+	if (!zone_active(client_id)) {
+		pr_err("ocmem: Client %s (id: %d) not allowed to use OCMEM\n",
+					get_name(client_id), client_id);
+		return NULL;
+	}
+
 	if (size < OCMEM_MIN_ALLOC) {
 		pr_err("ocmem: requested size %lx must be at least %x\n",
 				size, OCMEM_MIN_ALLOC);
@@ -162,6 +174,12 @@
 		return NULL;
 	}
 
+	if (!zone_active(client_id)) {
+		pr_err("ocmem: Client %s (id: %d) not allowed to use OCMEM\n",
+					get_name(client_id), client_id);
+		return NULL;
+	}
+
 	/* Asynchronous API requires notifier registration */
 	if (!check_notifier(client_id)) {
 		pr_err("ocmem: No notifier registered for client %d\n",
@@ -202,6 +220,12 @@
 		return NULL;
 	}
 
+	if (!zone_active(client_id)) {
+		pr_err("ocmem: Client %s (id: %d) not allowed to use OCMEM\n",
+					get_name(client_id), client_id);
+		return NULL;
+	}
+
 	if (size < OCMEM_MIN_ALLOC) {
 		pr_err("ocmem: requested size %lx must be at least %x\n",
 				size, OCMEM_MIN_ALLOC);
@@ -226,6 +250,12 @@
 		return -EINVAL;
 	}
 
+	if (!zone_active(client_id)) {
+		pr_err("ocmem: Client %s (id: %d) not allowed to use OCMEM\n",
+					get_name(client_id), client_id);
+		return -EINVAL;
+	}
+
 	if (!buffer) {
 		pr_err("ocmem: Invalid buffer\n");
 		return -EINVAL;
@@ -240,6 +270,13 @@
 		return -EINVAL;
 	if (len >= buffer->len)
 		return -EINVAL;
+
+	if (!zone_active(client_id)) {
+		pr_err("ocmem: Client id: %s (id: %d) not allowed to use OCMEM\n",
+					get_name(client_id), client_id);
+		return -EINVAL;
+	}
+
 	return __ocmem_shrink(client_id, buffer, len);
 }
 
@@ -282,6 +319,12 @@
 		return -EINVAL;
 	}
 
+	if (!zone_active(client_id)) {
+		pr_err("ocmem: Client id: %s (id: %d) not allowed to use OCMEM\n",
+					get_name(client_id), client_id);
+		return -EINVAL;
+	}
+
 	/* Asynchronous API requires notifier registration */
 	if (!check_notifier(client_id)) {
 		pr_err("ocmem: No notifier registered for client %d\n",
@@ -320,6 +363,12 @@
 		return -EINVAL;
 	}
 
+	if (!zone_active(client_id)) {
+		pr_err("ocmem: Client id: %s (id: %d) not allowed to use OCMEM\n",
+					get_name(client_id), client_id);
+		return -EINVAL;
+	}
+
 	/* Asynchronous API requires notifier registration */
 	if (!check_notifier(client_id)) {
 		pr_err("ocmem: No notifier registered for client %d\n",
@@ -399,3 +448,22 @@
 	mutex_unlock(&ocmem_eviction_lock);
 	return ret;
 }
+
+/* Wrappers until power control is transitioned to clients */
+enum ocmem_power_state ocmem_get_power_state(int client_id,
+						struct ocmem_buf *buffer)
+{
+	return 0;
+}
+
+int ocmem_set_power_state(int client_id, struct ocmem_buf *buffer,
+					enum ocmem_power_state new_state)
+{
+	return 0;
+}
+
+struct ocmem_vectors *ocmem_get_vectors(int client_id,
+				struct ocmem_buf *buffer)
+{
+	return NULL;
+}
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
new file mode 100644
index 0000000..c7cc57e
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -0,0 +1,796 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/mutex.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <mach/ocmem_priv.h>
+#include <mach/rpm-smd.h>
+
+static unsigned num_regions;
+static unsigned num_macros;
+static unsigned num_ports;
+static unsigned num_banks;
+
+static unsigned long macro_size;
+static unsigned long region_size;
+
+static bool rpm_power_control;
+
+struct ocmem_hw_macro {
+	atomic_t m_on[OCMEM_CLIENT_MAX];
+	atomic_t m_retain[OCMEM_CLIENT_MAX];
+	unsigned m_state;
+};
+
+struct ocmem_hw_region {
+	unsigned psgsc_ctrl;
+	bool interleaved;
+	unsigned int mode;
+	unsigned int num_macros;
+	struct ocmem_hw_macro *macro;
+	struct msm_rpm_request *rpm_req;
+	unsigned r_state;
+};
+
+static struct ocmem_hw_region *region_ctrl;
+static struct mutex region_ctrl_lock;
+static void *ocmem_base;
+
+#define OCMEM_V1_REGIONS 3
+#define OCMEM_V1_MACROS 8
+
+#define OC_HW_VERS (0x0)
+#define OC_HW_PROFILE (0x4)
+#define OC_GEN_STATUS (0xC)
+#define OC_PSGSC_STATUS (0x38)
+#define OC_PSGSC_CTL (0x3C)
+#define OC_REGION_CTL (0x1000)
+
+#define NUM_PORTS_MASK (0xF << 0)
+#define NUM_PORTS_SHIFT (0)
+
+#define NUM_MACROS_MASK (0xF << 8)
+#define NUM_MACROS_SHIFT (8)
+
+#define INTERLEAVING_MASK (0x1 << 17)
+#define INTERLEAVING_SHIFT (17)
+
+/* Power states of each memory macro */
+#define PASSTHROUGH (0x0)
+#define CORE_ON (0x2)
+#define PERI_ON (0x1)
+#define CLK_OFF (0x4)
+#define MACRO_ON (CORE_ON|PERI_ON)
+#define MACRO_SLEEP_RETENTION (CLK_OFF|CORE_ON)
+#define MACRO_SLEEP_RETENTION_PERI_ON (CLK_OFF|MACRO_ON)
+#define MACRO_OFF (CLK_OFF)
+
+#define M_PSCGC_CTL_n(x) (0x7 << (x * 4))
+
+#define PSCGC_CTL_IDX(x) ((x) * 0x4)
+#define PSCGC_CTL_n(x) (OC_PSGSC_CTL + (PSCGC_CTL_IDX(x)))
+
+/* Power states of each ocmem region */
+#define REGION_NORMAL_PASSTHROUGH 0x00000000
+#define REGION_FORCE_PERI_ON 0x00001111
+#define REGION_FORCE_CORE_ON 0x00002222
+#define REGION_FORCE_ALL_ON 0x00003333
+#define REGION_SLEEP_NO_RETENTION 0x00004444
+#define REGION_SLEEP_PERI_OFF 0x00006666
+#define REGION_SLEEP_PERI_ON 0x00007777
+
+#define REGION_DEFAULT_OFF REGION_SLEEP_NO_RETENTION
+#define REGION_DEFAULT_ON REGION_FORCE_ALL_ON
+#define REGION_DEFAULT_RETENTION REGION_SLEEP_PERI_OFF
+
+enum rpm_macro_state {
+	rpm_macro_off = 0x0,
+	rpm_macro_retain,
+	rpm_macro_on,
+};
+
+static int rpm_write(unsigned long val, unsigned id);
+
+static inline unsigned hw_macro_state(unsigned region_state)
+{
+	unsigned macro_state;
+
+	switch (region_state) {
+	case REGION_DEFAULT_ON:
+		macro_state = MACRO_ON;
+		break;
+	case REGION_DEFAULT_OFF:
+		macro_state = MACRO_OFF;
+		break;
+	case REGION_DEFAULT_RETENTION:
+		macro_state = MACRO_SLEEP_RETENTION;
+		break;
+	default:
+		macro_state = MACRO_OFF;
+		break;
+	}
+	return macro_state;
+}
+
+static inline unsigned rpm_macro_state(unsigned hw_macro_state)
+{
+	unsigned macro_state;
+
+	switch (hw_macro_state) {
+	case MACRO_ON:
+		macro_state = rpm_macro_on;
+		break;
+	case MACRO_OFF:
+		macro_state = rpm_macro_off;
+		break;
+	case MACRO_SLEEP_RETENTION:
+		macro_state = rpm_macro_retain;
+		break;
+	default:
+		macro_state = rpm_macro_off;
+		break;
+	}
+	return macro_state;
+}
+
+/* Generic wrapper that sets the region state either
+   by a direct write or through appropriate RPM call
+*/
+/* Must be called with region mutex held */
+static int commit_region_state(unsigned region_num)
+{
+	int rc = -1;
+	unsigned new_state;
+
+	if (region_num >= num_regions)
+		return -EINVAL;
+
+	new_state = region_ctrl[region_num].r_state;
+	pr_debug("ocmem: commit region (%d) new state %x\n", region_num,
+								new_state);
+	if (rpm_power_control)
+		rc = rpm_write(new_state, region_num);
+	else
+		rc = ocmem_write(new_state,
+					ocmem_base + PSCGC_CTL_n(region_num));
+	return 0;
+}
+
+/* Returns the current state of a OCMEM region */
+/* Must be called with region mutex held */
+static int read_region_state(unsigned region_num)
+{
+	int state;
+
+	pr_debug("rpm_get_region_state: #: %d\n", region_num);
+
+	if (region_num >= num_regions)
+		return -EINVAL;
+
+	if (rpm_power_control)
+		state = region_ctrl[region_num].r_state;
+	else
+		state = ocmem_read(ocmem_base + PSCGC_CTL_n(region_num));
+
+	pr_debug("ocmem: region (%d) state %x\n", region_num, state);
+
+	return state;
+}
+
+/* Returns the current state of a OCMEM macro that belongs to a region */
+static int read_macro_state(unsigned region_num, unsigned macro_num)
+{
+	int state;
+
+	if (macro_num >= num_banks)
+		return -EINVAL;
+
+	state = read_region_state(region_num);
+
+	if (state < 0)
+		return -EINVAL;
+
+	state &= M_PSCGC_CTL_n(macro_num);
+	state = state >> (macro_num * 4);
+
+	pr_debug("rpm_get_macro_state: macro (%d) region (%d) state %x\n",
+			macro_num, region_num, state);
+
+	return state;
+}
+
+static int apply_macro_vote(int id, unsigned region_num,
+				unsigned macro_num, int new_state)
+{
+	struct ocmem_hw_macro *m = NULL;
+	struct ocmem_hw_region *region = NULL;
+
+	if (region_num >= num_regions)
+		return -EINVAL;
+
+	if (macro_num >= num_banks)
+		return -EINVAL;
+
+	region = &region_ctrl[region_num];
+
+	m = &region->macro[macro_num];
+
+	pr_debug("m (%d): curr state %x votes (on: %d retain %d) new state %x\n",
+			macro_num, m->m_state,
+			atomic_read(&m->m_on[id]),
+			atomic_read(&m->m_retain[id]),
+			new_state);
+
+	switch (m->m_state) {
+	case MACRO_OFF:
+		if (new_state == MACRO_ON)
+			atomic_inc(&m->m_on[id]);
+		break;
+	case MACRO_ON:
+		if (new_state == MACRO_OFF) {
+			atomic_dec(&m->m_on[id]);
+		} else if (new_state == MACRO_SLEEP_RETENTION) {
+			atomic_inc(&m->m_retain[id]);
+			atomic_dec(&m->m_on[id]);
+		}
+		break;
+	case MACRO_SLEEP_RETENTION:
+		if (new_state == MACRO_OFF) {
+			atomic_dec(&m->m_retain[id]);
+		} else if (new_state == MACRO_ON) {
+			atomic_inc(&m->m_on[id]);
+			atomic_dec(&m->m_retain[id]);
+		}
+		break;
+	}
+
+	pr_debug("macro (%d) region (%d) votes for %d (on: %d retain %d)\n",
+				region_num, macro_num, id,
+				atomic_read(&m->m_on[id]),
+				atomic_read(&m->m_retain[id]));
+	return 0;
+}
+
+static int aggregate_macro_state(unsigned region_num, unsigned macro_num)
+{
+	struct ocmem_hw_macro *m = NULL;
+	struct ocmem_hw_region *region = NULL;
+	int i = 0;
+	/* The default is for the macro to be OFF */
+	unsigned m_state = MACRO_OFF;
+
+	if (region_num >= num_regions)
+		return -EINVAL;
+
+	if (macro_num >= num_banks)
+		return -EINVAL;
+
+	region = &region_ctrl[region_num];
+	m = &region->macro[macro_num];
+
+	for (i = 0; i < OCMEM_CLIENT_MAX; i++) {
+		if (atomic_read(&m->m_on[i]) > 0) {
+			/* atleast one client voted for ON state */
+			m_state = MACRO_ON;
+			goto done_aggregation;
+		} else if (atomic_read(&m->m_retain[i]) > 0) {
+			m_state = MACRO_SLEEP_RETENTION;
+			/* continue and examine votes of other clients */
+		}
+	}
+done_aggregation:
+	m->m_state = m_state;
+	pr_debug("macro (%d) region (%d) aggregated state %x", macro_num,
+						region_num, m->m_state);
+	return 0;
+}
+
+static int aggregate_region_state(unsigned region_num)
+{
+	struct ocmem_hw_region *region = NULL;
+	unsigned r_state;
+	unsigned i = 0;
+
+	if (region_num >= num_regions)
+		return -EINVAL;
+
+	region = &region_ctrl[region_num];
+	r_state = REGION_DEFAULT_OFF;
+
+	/* In wide mode all macros must have the same state */
+	if (region->mode == WIDE_MODE) {
+		for (i = 0; i < region->num_macros; i++) {
+			if (region->macro[i].m_state == MACRO_ON) {
+				r_state = REGION_DEFAULT_ON;
+				break;
+			} else if (region->macro[i].m_state ==
+						MACRO_SLEEP_RETENTION) {
+				r_state = REGION_DEFAULT_RETENTION;
+			}
+		}
+	} else {
+	/* In narrow mode each macro is allowed to be in a different state */
+	/* The region mode is simply the collection of all macro states */
+		for (i = 0; i < region->num_macros; i++) {
+			r_state &= ~M_PSCGC_CTL_n(i);
+			r_state |= region->macro[i].m_state << (i * 4);
+		}
+	}
+
+	pr_debug("region (%d) curr state (%x) aggregated state (%x)\n",
+			region_num, region->r_state, r_state);
+	region->r_state = r_state;
+	return 0;
+}
+
+static int rpm_write(unsigned long val, unsigned id)
+{
+	int i = 0;
+	int ret = 0;
+	struct ocmem_hw_region *region;
+
+	region = &region_ctrl[id];
+
+	for (i = 0; i < region->num_macros; i++) {
+		unsigned macro_state;
+		unsigned rpm_state;
+
+		macro_state = read_macro_state(id, i);
+		rpm_state = rpm_macro_state(macro_state);
+
+		if (val == REGION_DEFAULT_ON) {
+			pr_debug("macro (%d) region (%d) -> active\n",
+				i, id);
+			rpm_state = rpm_macro_on;
+		}
+
+		if (val == REGION_DEFAULT_OFF) {
+			pr_debug("macro (%d) region (%d) -> off\n",
+				i, id);
+			rpm_state = rpm_macro_off;
+		}
+
+		ret = msm_rpm_add_kvp_data(region->rpm_req, i,
+						(u8 *) &rpm_state, 4);
+
+		if (ret < 0) {
+			pr_err("ocmem: Error adding key %d val %d on rsc %d\n",
+					i, rpm_state, id);
+			return -EINVAL;
+		}
+	}
+
+	ret = msm_rpm_send_request(region->rpm_req);
+
+	if (ret < 0) {
+		pr_err("ocmem: Error sending RPM request\n");
+		return -EINVAL;
+	}
+
+	pr_debug("Transmit request to rpm for region %d\n", id);
+	return 0;
+}
+
+#if defined(CONFIG_MSM_OCMEM_POWER_DISABLE)
+static int ocmem_core_set_default_state(void)
+{
+	int rc = 0;
+
+	/* The OCMEM core clock and branch clocks are always turned ON */
+	rc = ocmem_enable_core_clock();
+	if (rc < 0)
+		return rc;
+
+	rc = ocmem_enable_iface_clock();
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
+/* Initializes a region to be turned ON in wide mode */
+static int ocmem_region_set_default_state(unsigned int r_num)
+{
+	unsigned m_num = 0;
+
+	mutex_lock(&region_ctrl_lock);
+
+	for (m_num = 0; m_num < num_banks; m_num++) {
+		apply_macro_vote(0, r_num, m_num, MACRO_ON);
+		aggregate_macro_state(r_num, m_num);
+	}
+
+	aggregate_region_state(r_num);
+	commit_region_state(r_num);
+
+	mutex_unlock(&region_ctrl_lock);
+	return 0;
+}
+
+#else
+static int ocmem_region_set_default_state(unsigned int region_num)
+{
+	return 0;
+}
+
+static int ocmem_core_set_default_state(void)
+{
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_MSM_OCMEM_POWER_DEBUG)
+
+static int read_hw_region_state(unsigned region_num)
+{
+	int state;
+
+	pr_debug("rpm_get_region_state: #: %d\n", region_num);
+
+	if (region_num >= num_regions)
+		return -EINVAL;
+
+	state = ocmem_read(ocmem_base + PSCGC_CTL_n(region_num));
+
+	pr_debug("ocmem: region (%d) state %x\n", region_num, state);
+
+	return state;
+}
+
+int ocmem_region_toggle(unsigned int r_num)
+{
+	unsigned reboot_state = ~0x0;
+	unsigned m_num = 0;
+
+	mutex_lock(&region_ctrl_lock);
+	/* Turn on each macro at boot for quick hw sanity check */
+	reboot_state = read_hw_region_state(r_num);
+
+	if (reboot_state != REGION_DEFAULT_OFF) {
+		pr_err("Region %d not in power off state (%x)\n",
+				r_num, reboot_state);
+		goto toggle_fail;
+	}
+
+	for (m_num = 0; m_num < num_banks; m_num++) {
+		apply_macro_vote(0, r_num, m_num, MACRO_ON);
+		aggregate_macro_state(r_num, m_num);
+	}
+
+	aggregate_region_state(r_num);
+	commit_region_state(r_num);
+
+	reboot_state = read_hw_region_state(r_num);
+
+	if (reboot_state != REGION_DEFAULT_ON) {
+		pr_err("Failed to power on Region %d(state:%x)\n",
+				r_num, reboot_state);
+		goto toggle_fail;
+	}
+
+	/* Turn off all memory macros again */
+
+	for (m_num = 0; m_num < num_banks; m_num++) {
+		apply_macro_vote(0, r_num, m_num, MACRO_OFF);
+		aggregate_macro_state(r_num, m_num);
+	}
+
+	aggregate_region_state(r_num);
+	commit_region_state(r_num);
+
+	reboot_state = read_hw_region_state(r_num);
+
+	if (reboot_state != REGION_DEFAULT_OFF) {
+		pr_err("Failed to power off Region %d(state:%x)\n",
+				r_num, reboot_state);
+		goto toggle_fail;
+	}
+	mutex_unlock(&region_ctrl_lock);
+	return 0;
+
+toggle_fail:
+	mutex_unlock(&region_ctrl_lock);
+	return -EINVAL;
+}
+
+int memory_is_off(unsigned int num)
+{
+	if (read_hw_region_state(num) == REGION_DEFAULT_OFF)
+		return 1;
+	else
+		return 0;
+}
+
+#else
+int ocmem_region_toggle(unsigned int region_num)
+{
+	return 0;
+}
+
+int memory_is_off(unsigned int num)
+{
+	return 0;
+}
+#endif /* CONFIG_MSM_OCMEM_POWER_DEBUG */
+
+/* Memory Macro Power Transition Sequences
+ * Normal to Sleep With Retention:
+	REGION_DEFAULT_ON -> REGION_DEFAULT_RETENTION
+ * Sleep With Retention to Normal:
+	REGION_DEFAULT_RETENTION -> REGION_FORCE_CORE_ON -> REGION_DEFAULT_ON
+ * Normal to OFF:
+	REGION_DEFAULT_ON -> REGION_DEFAULT_OFF
+ * OFF to Normal:
+	REGION_DEFAULT_OFF -> REGION_DEFAULT_ON
+**/
+
+#if defined(CONFIG_MSM_OCMEM_POWER_DISABLE)
+/* If power management is disabled leave the macro states as is */
+static int switch_power_state(int id, unsigned long offset, unsigned long len,
+			unsigned new_state)
+{
+	return 0;
+}
+
+#else
+static int switch_power_state(int id, unsigned long offset, unsigned long len,
+			unsigned new_state)
+{
+	unsigned region_start = num_regions;
+	unsigned region_end = num_regions;
+	unsigned curr_state = 0x0;
+	int i = 0;
+	int j = 0;
+	unsigned start_m = num_banks;
+	unsigned end_m = num_banks;
+	unsigned long region_offset = 0;
+	int rc = 0;
+
+	if (offset < 0)
+		return -EINVAL;
+
+	if (len < macro_size)
+		return -EINVAL;
+
+
+	pr_debug("ocmem: power_transition to %x for client %d\n", new_state,
+							id);
+
+	region_start = offset / region_size;
+	region_end = (offset + len - 1) / region_size;
+
+	pr_debug("ocmem: region start %u end %u\n", region_start, region_end);
+
+	if (region_start >= num_regions ||
+		(region_end >= num_regions))
+			return -EINVAL;
+
+	rc = ocmem_enable_core_clock();
+
+	if (rc < 0) {
+		pr_err("ocmem: Power transistion request for client %s (id: %d) failed\n",
+				get_name(id), id);
+		return rc;
+	}
+
+	mutex_lock(&region_ctrl_lock);
+
+	for (i = region_start; i <= region_end; i++) {
+
+		curr_state = read_region_state(i);
+
+		switch (curr_state) {
+		case REGION_DEFAULT_OFF:
+			if (new_state != REGION_DEFAULT_ON)
+				goto invalid_transition;
+			break;
+		case REGION_DEFAULT_RETENTION:
+			if (new_state != REGION_DEFAULT_ON)
+				goto invalid_transition;
+			break;
+		default:
+			break;
+		}
+
+		if (len >= region_size) {
+			pr_debug("switch: entire region (%d)\n", i);
+			start_m = 0;
+			end_m = num_banks;
+		} else {
+			region_offset = offset - (i * region_size);
+			start_m = region_offset / macro_size;
+			end_m = (region_offset + len - 1) / macro_size;
+			pr_debug("switch: macro (%u to %u)\n", start_m, end_m);
+		}
+
+		for (j = start_m; j <= end_m; j++) {
+			pr_debug("vote: macro (%d) region (%d)\n", j, i);
+			apply_macro_vote(id, i, j,
+				hw_macro_state(new_state));
+			aggregate_macro_state(i, j);
+		}
+		aggregate_region_state(i);
+		commit_region_state(i);
+		len -= region_size;
+
+		/* If we voted ON/retain the banks must never be OFF */
+		if (new_state != REGION_DEFAULT_OFF) {
+			if (memory_is_off(i)) {
+				pr_err("ocmem: Accessing memory during sleep\n");
+				WARN_ON(1);
+			}
+		}
+
+	}
+	mutex_unlock(&region_ctrl_lock);
+	ocmem_disable_core_clock();
+	return 0;
+invalid_transition:
+	mutex_unlock(&region_ctrl_lock);
+	ocmem_disable_core_clock();
+	pr_err("ocmem_core: Invalid state transition detected for %d\n", id);
+	pr_err("ocmem_core: Offset %lx Len %lx curr_state %x new_state %x\n",
+			offset, len, curr_state, new_state);
+	WARN_ON(1);
+	return -EINVAL;
+}
+#endif
+
+/* Interfaces invoked from the scheduler */
+int ocmem_memory_off(int id, unsigned long offset, unsigned long len)
+{
+	return switch_power_state(id, offset, len, REGION_DEFAULT_OFF);
+}
+
+int ocmem_memory_on(int id, unsigned long offset, unsigned long len)
+{
+	return switch_power_state(id, offset, len, REGION_DEFAULT_ON);
+}
+
+int ocmem_memory_retain(int id, unsigned long offset, unsigned long len)
+{
+	return switch_power_state(id, offset, len, REGION_DEFAULT_RETENTION);
+}
+
+int ocmem_core_init(struct platform_device *pdev)
+{
+	struct device   *dev = &pdev->dev;
+	struct ocmem_plat_data *pdata = NULL;
+	unsigned hw_ver;
+	bool interleaved;
+	unsigned i, j, k;
+	unsigned rsc_type = 0;
+	int rc = 0;
+
+	pdata = platform_get_drvdata(pdev);
+	ocmem_base = pdata->reg_base;
+
+	rc = ocmem_enable_core_clock();
+
+	if (rc < 0)
+		return rc;
+
+	hw_ver = ocmem_read(ocmem_base + OC_HW_PROFILE);
+
+	if (pdata->nr_regions != OCMEM_V1_REGIONS) {
+		pr_err("Invalid number of regions (%d)\n", pdata->nr_regions);
+		goto hw_not_supported;
+	}
+
+	num_macros = (hw_ver & NUM_MACROS_MASK) >> NUM_MACROS_SHIFT;
+	num_ports = (hw_ver & NUM_PORTS_MASK) >> NUM_PORTS_SHIFT;
+
+	if (num_macros != OCMEM_V1_MACROS) {
+		pr_err("Invalid number of macros (%d)\n", pdata->nr_macros);
+		goto hw_not_supported;
+	}
+
+	interleaved = (hw_ver & INTERLEAVING_MASK) >> INTERLEAVING_SHIFT;
+
+	if (interleaved == false) {
+		pr_err("Interleaving is disabled\n");
+		goto hw_not_supported;
+	}
+
+	num_regions = pdata->nr_regions;
+
+	pdata->interleaved = true;
+	pdata->nr_macros = num_macros;
+	pdata->nr_ports = num_ports;
+	macro_size = SZ_64K;
+	region_size = macro_size * num_ports;
+	num_banks = num_ports / 2;
+	rsc_type = pdata->rpm_rsc_type;
+
+	pr_debug("ocmem_core: ports %d regions %d macros %d interleaved %d\n",
+				num_ports, num_regions, num_macros,
+				interleaved);
+
+	region_ctrl = devm_kzalloc(dev, sizeof(struct ocmem_hw_region)
+					 * num_regions, GFP_KERNEL);
+
+	if (!region_ctrl) {
+		goto err_no_mem;
+	}
+
+	mutex_init(&region_ctrl_lock);
+
+	for (i = 0 ; i < num_regions; i++) {
+		struct ocmem_hw_region *region = &region_ctrl[i];
+		struct msm_rpm_request *req = NULL;
+		region->interleaved = interleaved;
+		region->mode = MODE_DEFAULT;
+		region->r_state = REGION_DEFAULT_OFF;
+		region->num_macros = num_banks;
+
+		region->macro = devm_kzalloc(dev,
+					sizeof(struct ocmem_hw_macro) *
+						num_banks, GFP_KERNEL);
+		if (!region->macro) {
+			goto err_no_mem;
+		}
+
+		for (j = 0; j < num_banks; j++) {
+			struct ocmem_hw_macro *m = &region->macro[j];
+			m->m_state = MACRO_OFF;
+			for (k = 0; k < OCMEM_CLIENT_MAX; k++) {
+				atomic_set(&m->m_on[k], 0);
+				atomic_set(&m->m_retain[k], 0);
+			}
+		}
+
+		if (pdata->rpm_pwr_ctrl) {
+			rpm_power_control = true;
+			req = msm_rpm_create_request(MSM_RPM_CTX_ACTIVE_SET,
+					rsc_type, i, num_banks);
+
+			if (!req) {
+				pr_err("Unable to create RPM request\n");
+				goto region_init_error;
+			}
+
+			pr_debug("rpm request type %x (rsc: %d) with %d elements\n",
+						rsc_type, i, num_banks);
+
+			region->rpm_req = req;
+		}
+
+		if (ocmem_region_toggle(i)) {
+			pr_err("Failed to verify region %d\n", i);
+			goto region_init_error;
+		}
+
+		if (ocmem_region_set_default_state(i)) {
+			pr_err("Failed to initialize region %d\n", i);
+			goto region_init_error;
+		}
+	}
+
+	rc = ocmem_core_set_default_state();
+
+	if (rc < 0)
+		return rc;
+
+	ocmem_disable_core_clock();
+	return 0;
+
+err_no_mem:
+	pr_err("ocmem: Unable to allocate memory\n");
+region_init_error:
+hw_not_supported:
+	pr_err("Unsupported OCMEM h/w configuration %x\n", hw_ver);
+	ocmem_disable_core_clock();
+	return -EINVAL;
+}
diff --git a/arch/arm/mach-msm/ocmem_notifier.c b/arch/arm/mach-msm/ocmem_notifier.c
index 9fbcd73..644c809 100644
--- a/arch/arm/mach-msm/ocmem_notifier.c
+++ b/arch/arm/mach-msm/ocmem_notifier.c
@@ -82,6 +82,12 @@
 		return NULL;
 	}
 
+	if (!zone_active(client_id)) {
+		pr_err("ocmem: Client %s (id: %d) not allowed to use OCMEM\n",
+					get_name(client_id), client_id);
+		return NULL;
+	}
+
 	if (!nb) {
 		pr_err("ocmem: Invalid Notifier Block\n");
 		return NULL;
diff --git a/arch/arm/mach-msm/ocmem_rdm.c b/arch/arm/mach-msm/ocmem_rdm.c
index 6b93d04..ccbef9b 100644
--- a/arch/arm/mach-msm/ocmem_rdm.c
+++ b/arch/arm/mach-msm/ocmem_rdm.c
@@ -109,19 +109,6 @@
 	unsigned int ctrl;
 } dm_table[RDM_MAX_ENTRIES];
 
-/* Wrapper that will shadow these values later */
-static int ocmem_read(void *at)
-{
-	return readl_relaxed(at);
-}
-
-/* Wrapper that will shadow these values later */
-static int ocmem_write(unsigned long val, void *at)
-{
-	writel_relaxed(val, at);
-	return 0;
-}
-
 static inline int client_ctrl_id(int id)
 {
 	return (id == OCMEM_SENSORS) ? 1 : 0;
@@ -155,6 +142,15 @@
 	int i = 0;
 	int j = 0;
 	int status = 0;
+	int rc = 0;
+
+	rc = ocmem_enable_core_clock();
+
+	if (rc < 0) {
+		pr_err("RDM transfer failed for client %s (id: %d)\n",
+				get_name(id), id);
+		return rc;
+	}
 
 	for (i = 0, j = slot; i < num_chunks; i++, j++) {
 
@@ -209,6 +205,7 @@
 	wait_event_interruptible(dm_wq,
 		atomic_read(&dm_pending) == 0);
 
+	ocmem_disable_core_clock();
 	return 0;
 }
 
@@ -231,8 +228,16 @@
 		return -EINVAL;
 	}
 
+	rc = ocmem_enable_core_clock();
+
+	if (rc < 0) {
+		pr_err("RDM initialization failed\n");
+		return rc;
+	}
+
 	init_waitqueue_head(&dm_wq);
 	/* enable dm interrupts */
 	ocmem_write(DM_INTR_ENABLE, dm_base + DM_INTR_MASK);
+	ocmem_disable_core_clock();
 	return 0;
 }
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index f6d066d..3ac8e0a 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -116,7 +116,7 @@
 	int hw_interconnect;
 } ocmem_client_table[OCMEM_CLIENT_MAX] = {
 	{OCMEM_GRAPHICS, PRIO_GFX, OCMEM_PERFORMANCE, OCMEM_PORT},
-	{OCMEM_VIDEO, PRIO_VIDEO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
+	{OCMEM_VIDEO, PRIO_VIDEO, OCMEM_PERFORMANCE, OCMEM_PORT},
 	{OCMEM_CAMERA, NO_PRIO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
 	{OCMEM_HP_AUDIO, PRIO_HP_AUDIO, OCMEM_PASSIVE, OCMEM_BLOCKED},
 	{OCMEM_VOICE, PRIO_VOICE, OCMEM_PASSIVE, OCMEM_BLOCKED},
@@ -511,18 +511,48 @@
 	return 0;
 }
 
-/* process map is a wrapper where power control will be added later */
 static int process_map(struct ocmem_req *req, unsigned long start,
 				unsigned long end)
 {
+	int rc = 0;
+
+	rc = ocmem_enable_core_clock();
+
+	if (rc < 0)
+		goto core_clock_fail;
+
+	rc = ocmem_enable_iface_clock();
+
+	if (rc < 0)
+		goto process_map_fail;
+
 	return do_map(req);
+
+process_map_fail:
+	ocmem_disable_core_clock();
+core_clock_fail:
+	pr_err("ocmem: Failed to map ocmem request\n");
+	return rc;
 }
 
-/* process unmap is a wrapper where power control will be added later */
 static int process_unmap(struct ocmem_req *req, unsigned long start,
 				unsigned long end)
 {
-	return do_unmap(req);
+	int rc = 0;
+
+	rc = do_unmap(req);
+
+	if (rc < 0)
+		goto process_unmap_fail;
+
+	ocmem_disable_iface_clock();
+	ocmem_disable_core_clock();
+
+	return 0;
+
+process_unmap_fail:
+	pr_err("ocmem: Failed to unmap ocmem request\n");
+	return rc;
 }
 
 static int __sched_grow(struct ocmem_req *req, bool can_block)
@@ -1083,6 +1113,7 @@
 static int process_grow(struct ocmem_req *req)
 {
 	int rc = 0;
+	unsigned long offset = 0;
 
 	/* Attempt to grow the region */
 	rc = do_grow(req);
@@ -1097,6 +1128,15 @@
 			return -EINVAL;
 	}
 
+	offset = phys_to_offset(req->req_start);
+
+	rc = ocmem_memory_on(req->owner, offset, req->req_sz);
+
+	if (rc < 0) {
+		pr_err("Failed to switch ON memory macros\n");
+		goto power_ctl_error;
+	}
+
 	/* Notify the client about the buffer growth */
 	rc = dispatch_notification(req->owner, OCMEM_ALLOC_GROW, req->buffer);
 	if (rc < 0) {
@@ -1105,6 +1145,8 @@
 		BUG();
 	}
 	return 0;
+power_ctl_error:
+	return -EINVAL;
 }
 
 static int do_shrink(struct ocmem_req *req, unsigned long shrink_size)
@@ -1187,6 +1229,7 @@
 {
 	struct ocmem_req *req = NULL;
 	struct ocmem_buf *buffer = NULL;
+	unsigned long offset = 0;
 	int rc = 0;
 
 	if (is_blocked(id)) {
@@ -1211,6 +1254,20 @@
 			return -EINVAL;
 	}
 
+
+	if (req->req_sz != 0) {
+
+		offset = phys_to_offset(req->req_start);
+
+		rc = ocmem_memory_off(req->owner, offset, req->req_sz);
+
+		if (rc < 0) {
+			pr_err("Failed to switch OFF memory macros\n");
+			return -EINVAL;
+		}
+
+	}
+
 	rc = do_free(req);
 
 	if (rc < 0)
@@ -1244,7 +1301,6 @@
 		event = (rc == 0) ? OCMEM_MAP_DONE : OCMEM_MAP_FAIL;
 	else
 		event = (rc == 0) ? OCMEM_UNMAP_DONE : OCMEM_UNMAP_FAIL;
-
 	up_write(&req->rw_sem);
 	kfree(work_data);
 	dispatch_notification(id, event, buffer);
@@ -1300,6 +1356,7 @@
 		goto transfer_out_error;
 	}
 
+
 	return 0;
 
 transfer_out_error:
@@ -1538,6 +1595,7 @@
 	struct ocmem_req *req = NULL;
 	struct ocmem_buf *buffer = NULL;
 	int rc = 0;
+	unsigned long offset = 0;
 
 	/* sanity checks */
 	if (is_blocked(id)) {
@@ -1579,8 +1637,21 @@
 			goto map_error;
 	}
 
+	if (req->req_sz != 0) {
+
+		offset = phys_to_offset(req->req_start);
+
+		rc = ocmem_memory_on(req->owner, offset, req->req_sz);
+
+		if (rc < 0) {
+			pr_err("Failed to switch ON memory macros\n");
+			goto power_ctl_error;
+		}
+	}
+
 	return 0;
 
+power_ctl_error:
 map_error:
 	handle->req = NULL;
 	do_free(req);
@@ -1595,6 +1666,7 @@
 	struct ocmem_handle *handle = NULL;
 	int rc = 0;
 	int id = req->owner;
+	unsigned long offset = 0;
 
 	handle = req_to_handle(req);
 	BUG_ON(handle == NULL);
@@ -1611,6 +1683,18 @@
 			goto map_error;
 	}
 
+	if (req->req_sz != 0) {
+
+		offset = phys_to_offset(req->req_start);
+
+		rc = ocmem_memory_on(req->owner, offset, req->req_sz);
+
+		if (rc < 0) {
+			pr_err("Failed to switch ON memory macros\n");
+			goto power_ctl_error;
+		}
+	}
+
 	/* Notify the client about the buffer growth */
 	rc = dispatch_notification(id, OCMEM_ALLOC_GROW, req->buffer);
 	if (rc < 0) {
@@ -1620,6 +1704,7 @@
 	}
 	return 0;
 
+power_ctl_error:
 map_error:
 	handle->req = NULL;
 	do_free(req);
diff --git a/arch/arm/mach-msm/pcie.c b/arch/arm/mach-msm/pcie.c
index d954b53..709c8e8 100644
--- a/arch/arm/mach-msm/pcie.c
+++ b/arch/arm/mach-msm/pcie.c
@@ -619,6 +619,7 @@
 	msm_pcie_dev.pdev = pdev;
 	pdata = pdev->dev.platform_data;
 	msm_pcie_dev.gpio = pdata->gpio;
+	msm_pcie_dev.wake_n = pdata->wake_n;
 	msm_pcie_dev.vreg = msm_pcie_vreg_info;
 	msm_pcie_dev.clk = msm_pcie_clk_info;
 	msm_pcie_dev.res = msm_pcie_res_info;
@@ -706,6 +707,26 @@
 DECLARE_PCI_FIXUP_EARLY(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
 			msm_pcie_fixup_early);
 
+/* enable wake_n interrupt during suspend */
+static void msm_pcie_fixup_suspend(struct pci_dev *dev)
+{
+	PCIE_DBG("enabling wake_n\n");
+	if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
+		enable_irq(msm_pcie_dev.wake_n);
+}
+DECLARE_PCI_FIXUP_SUSPEND(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
+			  msm_pcie_fixup_suspend);
+
+/* disable wake_n interrupt when system is not in suspend */
+static void msm_pcie_fixup_resume(struct pci_dev *dev)
+{
+	PCIE_DBG("disabling wake_n\n");
+	if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
+		disable_irq(msm_pcie_dev.wake_n);
+}
+DECLARE_PCI_FIXUP_RESUME(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
+			 msm_pcie_fixup_resume);
+
 /*
  * actual physical (BAR) address of the device resources starts from
  * MSM_PCIE_DEV_BAR_ADDR; the system axi address for the device resources starts
diff --git a/arch/arm/mach-msm/pcie.h b/arch/arm/mach-msm/pcie.h
index fba6b11..d7cce3e 100644
--- a/arch/arm/mach-msm/pcie.h
+++ b/arch/arm/mach-msm/pcie.h
@@ -68,6 +68,8 @@
 	uint32_t                      axi_bar_end;
 
 	struct resource               dev_mem_res;
+
+	uint32_t                      wake_n;
 };
 
 extern uint32_t msm_pcie_irq_init(struct msm_pcie_dev_t *dev);
diff --git a/arch/arm/mach-msm/pcie_irq.c b/arch/arm/mach-msm/pcie_irq.c
index d915561..5a44a17 100644
--- a/arch/arm/mach-msm/pcie_irq.c
+++ b/arch/arm/mach-msm/pcie_irq.c
@@ -39,7 +39,13 @@
 
 static DECLARE_BITMAP(msi_irq_in_use, NR_PCIE_MSI_IRQS);
 
-irqreturn_t handle_msi_irq(int irq, void *data)
+static irqreturn_t handle_wake_irq(int irq, void *data)
+{
+	PCIE_DBG("\n");
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t handle_msi_irq(int irq, void *data)
 {
 	int i, j;
 	unsigned long val;
@@ -87,15 +93,32 @@
 	/* register handler for physical MSI interrupt line */
 	rc = request_irq(PCIE20_INT_MSI, handle_msi_irq, IRQF_TRIGGER_RISING,
 			 "msm_pcie_msi", dev);
-	if (rc)
+	if (rc) {
 		pr_err("Unable to allocate msi interrupt\n");
+		goto out;
+	}
 
+	/* register handler for PCIE_WAKE_N interrupt line */
+	rc = request_irq(dev->wake_n, handle_wake_irq, IRQF_TRIGGER_FALLING,
+			 "msm_pcie_wake", dev);
+	if (rc) {
+		pr_err("Unable to allocate wake interrupt\n");
+		free_irq(PCIE20_INT_MSI, dev);
+		goto out;
+	}
+
+	enable_irq_wake(dev->wake_n);
+
+	/* PCIE_WAKE_N should be enabled only during system suspend */
+	disable_irq(dev->wake_n);
+out:
 	return rc;
 }
 
 void __exit msm_pcie_irq_deinit(struct msm_pcie_dev_t *dev)
 {
 	free_irq(PCIE20_INT_MSI, dev);
+	free_irq(dev->wake_n, dev);
 }
 
 void msm_pcie_destroy_irq(unsigned int irq)
diff --git a/arch/arm/mach-msm/pil-mba.c b/arch/arm/mach-msm/pil-mba.c
index d0ba7d0..2176b26 100644
--- a/arch/arm/mach-msm/pil-mba.c
+++ b/arch/arm/mach-msm/pil-mba.c
@@ -37,7 +37,6 @@
 
 #define STATUS_META_DATA_AUTH_SUCCESS	0x3
 #define STATUS_AUTH_COMPLETE		0x4
-#define STATUS_ERROR_MASK		BIT(31)
 
 #define AUTH_TIMEOUT_US			10000000
 #define PROXY_TIMEOUT_MS		10000
@@ -75,7 +74,7 @@
 			      const u8 *metadata, size_t size)
 {
 	struct mba_data *drv = dev_get_drvdata(pil->dev);
-	u32 status;
+	s32 status;
 	int ret;
 
 	/* Copy metadata to assigned shared buffer location */
@@ -89,10 +88,14 @@
 	writel_relaxed(drv->metadata_phys, drv->reg_base + RMB_PMI_META_DATA);
 	writel_relaxed(CMD_META_DATA_READY, drv->reg_base + RMB_MBA_COMMAND);
 	ret = readl_poll_timeout(drv->reg_base + RMB_MBA_STATUS, status,
-		status == STATUS_META_DATA_AUTH_SUCCESS,
+		status == STATUS_META_DATA_AUTH_SUCCESS || status < 0,
 		POLL_INTERVAL_US, AUTH_TIMEOUT_US);
-	if (ret)
+	if (ret) {
 		dev_err(pil->dev, "MBA authentication timed out\n");
+	} else if (status < 0) {
+		dev_err(pil->dev, "MBA returned error %d\n", status);
+		ret = -EINVAL;
+	}
 
 	return ret;
 }
@@ -101,6 +104,7 @@
 			       size_t size)
 {
 	struct mba_data *drv = dev_get_drvdata(pil->dev);
+	s32 status;
 
 	/* Begin image authentication */
 	if (drv->img_length == 0) {
@@ -111,28 +115,33 @@
 	drv->img_length += size;
 	writel_relaxed(drv->img_length, drv->reg_base + RMB_PMI_CODE_LENGTH);
 
-	return readl_relaxed(drv->reg_base + RMB_MBA_STATUS)
-			& STATUS_ERROR_MASK;
+	status = readl_relaxed(drv->reg_base + RMB_MBA_STATUS);
+	if (status < 0) {
+		dev_err(pil->dev, "MBA returned error %d\n", status);
+		return -EINVAL;
+	}
+
+	return 0;
 }
 
 static int pil_mba_auth(struct pil_desc *pil)
 {
 	struct mba_data *drv = dev_get_drvdata(pil->dev);
 	int ret;
-	u32 status;
+	s32 status;
 
 	/* Wait for all segments to be authenticated or an error to occur */
 	ret = readl_poll_timeout(drv->reg_base + RMB_MBA_STATUS, status,
-			status == STATUS_AUTH_COMPLETE ||
-			status & STATUS_ERROR_MASK,
+			status == STATUS_AUTH_COMPLETE || status < 0,
 			50, AUTH_TIMEOUT_US);
-	if (ret)
-		return ret;
+	if (ret) {
+		dev_err(pil->dev, "MBA authentication timed out\n");
+	} else if (status < 0) {
+		dev_err(pil->dev, "MBA returned error %d\n", status);
+		ret = -EINVAL;
+	}
 
-	if (status & STATUS_ERROR_MASK)
-		return -EINVAL;
-
-	return 0;
+	return ret;
 }
 
 static int pil_mba_shutdown(struct pil_desc *pil)
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index 58d5176..01cdb0b 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -117,11 +117,12 @@
 	void __iomem *base = drv->base;
 	unsigned long start_addr = drv->start_addr;
 
-	/* Deassert reset to Pronto */
+	/* Deassert reset to subsystem and wait for propagation */
 	reg = readl_relaxed(drv->reset_base);
 	reg &= ~CLK_CTL_WCNSS_RESTART_BIT;
 	writel_relaxed(reg, drv->reset_base);
 	mb();
+	udelay(2);
 
 	/* Configure boot address */
 	writel_relaxed(start_addr >> 16, base +
@@ -206,11 +207,12 @@
 	mb();
 	usleep_range(1000, 2000);
 
-	/* Deassert reset to Pronto */
+	/* Deassert reset to subsystem and wait for propagation */
 	reg = readl_relaxed(drv->reset_base);
 	reg &= ~CLK_CTL_WCNSS_RESTART_BIT;
 	writel_relaxed(reg, drv->reset_base);
 	mb();
+	udelay(2);
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 311f8a7..44d8bc6 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -18,13 +18,56 @@
 #include <linux/err.h>
 #include <linux/of.h>
 #include <linux/clk.h>
-
+#include <mach/clk.h>
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
 
 #define QDSP6SS_RST_EVB			0x010
 #define PROXY_TIMEOUT_MS		10000
 
+static int pil_lpass_enable_clks(struct q6v5_data *drv)
+{
+	int ret;
+
+	ret = clk_reset(drv->core_clk, CLK_RESET_DEASSERT);
+	if (ret)
+		goto err_reset;
+	ret = clk_prepare_enable(drv->core_clk);
+	if (ret)
+		goto err_core_clk;
+	ret = clk_prepare_enable(drv->ahb_clk);
+	if (ret)
+		goto err_ahb_clk;
+	ret = clk_prepare_enable(drv->axi_clk);
+	if (ret)
+		goto err_axi_clk;
+	ret = clk_prepare_enable(drv->reg_clk);
+	if (ret)
+		goto err_reg_clk;
+
+	return 0;
+
+err_reg_clk:
+	clk_disable_unprepare(drv->axi_clk);
+err_axi_clk:
+	clk_disable_unprepare(drv->ahb_clk);
+err_ahb_clk:
+	clk_disable_unprepare(drv->core_clk);
+err_core_clk:
+	clk_reset(drv->core_clk, CLK_RESET_ASSERT);
+err_reset:
+	return ret;
+}
+
+static void pil_lpass_disable_clks(struct q6v5_data *drv)
+{
+	clk_disable_unprepare(drv->reg_clk);
+	clk_disable_unprepare(drv->axi_clk);
+	clk_disable_unprepare(drv->ahb_clk);
+	clk_disable_unprepare(drv->core_clk);
+	clk_reset(drv->core_clk, CLK_RESET_ASSERT);
+}
+
 static int pil_lpass_shutdown(struct pil_desc *pil)
 {
 	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
@@ -37,10 +80,10 @@
 	 * performed during the shutdown succeed.
 	 */
 	if (drv->is_booted == false)
-		pil_q6v5_enable_clks(pil);
+		pil_lpass_enable_clks(drv);
 
 	pil_q6v5_shutdown(pil);
-	pil_q6v5_disable_clks(pil);
+	pil_lpass_disable_clks(drv);
 
 	drv->is_booted = false;
 
@@ -52,7 +95,7 @@
 	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
 	int ret;
 
-	ret = pil_q6v5_enable_clks(pil);
+	ret = pil_lpass_enable_clks(drv);
 	if (ret)
 		return ret;
 
@@ -62,7 +105,7 @@
 
 	ret = pil_q6v5_reset(pil);
 	if (ret) {
-		pil_q6v5_disable_clks(pil);
+		pil_lpass_disable_clks(drv);
 		return ret;
 	}
 
@@ -96,6 +139,22 @@
 	desc->owner = THIS_MODULE;
 	desc->proxy_timeout = PROXY_TIMEOUT_MS;
 
+	drv->core_clk = devm_clk_get(&pdev->dev, "core_clk");
+	if (IS_ERR(drv->core_clk))
+		return PTR_ERR(drv->core_clk);
+
+	drv->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
+	if (IS_ERR(drv->ahb_clk))
+		return PTR_ERR(drv->ahb_clk);
+
+	drv->axi_clk = devm_clk_get(&pdev->dev, "bus_clk");
+	if (IS_ERR(drv->axi_clk))
+		return PTR_ERR(drv->axi_clk);
+
+	drv->reg_clk = devm_clk_get(&pdev->dev, "reg_clk");
+	if (IS_ERR(drv->reg_clk))
+		return PTR_ERR(drv->reg_clk);
+
 	drv->pil = msm_pil_register(desc);
 	if (IS_ERR(drv->pil))
 		return PTR_ERR(drv->pil);
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index 62685ca..6a30940 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -38,6 +38,9 @@
 #define MSS_MODEM_HALT_BASE		0x200
 #define MSS_NC_HALT_BASE		0x280
 
+/* MSS_CLAMP_IO Register Value */
+#define MSS_IO_UNCLAMP_ALL		0x40
+
 /* RMB Status Register Values */
 #define STATUS_PBL_SUCCESS		0x1
 #define STATUS_XPU_UNLOCKED		0x1
@@ -71,6 +74,55 @@
 	return regulator_disable(drv->vreg);
 }
 
+static int pil_mss_enable_clks(struct q6v5_data *drv)
+{
+	int ret;
+
+	ret = clk_prepare_enable(drv->ahb_clk);
+	if (ret)
+		goto err_ahb_clk;
+	ret = clk_reset(drv->core_clk, CLK_RESET_DEASSERT);
+	if (ret)
+		goto err_reset;
+	ret = clk_prepare_enable(drv->core_clk);
+	if (ret)
+		goto err_core_clk;
+	ret = clk_prepare_enable(drv->axi_clk);
+	if (ret)
+		goto err_axi_clk;
+	ret = clk_prepare_enable(drv->reg_clk);
+	if (ret)
+		goto err_reg_clk;
+	ret = clk_prepare_enable(drv->rom_clk);
+	if (ret)
+		goto err_rom_clk;
+
+	return 0;
+
+err_rom_clk:
+	clk_disable_unprepare(drv->reg_clk);
+err_reg_clk:
+	clk_disable_unprepare(drv->axi_clk);
+err_axi_clk:
+	clk_disable_unprepare(drv->core_clk);
+err_core_clk:
+	clk_reset(drv->core_clk, CLK_RESET_ASSERT);
+err_reset:
+	clk_disable_unprepare(drv->ahb_clk);
+err_ahb_clk:
+	return ret;
+}
+
+static void pil_mss_disable_clks(struct q6v5_data *drv)
+{
+	clk_disable_unprepare(drv->rom_clk);
+	clk_disable_unprepare(drv->reg_clk);
+	clk_disable_unprepare(drv->axi_clk);
+	clk_disable_unprepare(drv->core_clk);
+	clk_reset(drv->core_clk, CLK_RESET_ASSERT);
+	clk_disable_unprepare(drv->ahb_clk);
+}
+
 static int wait_for_mba_ready(struct device *dev)
 {
 	struct q6v5_data *drv = dev_get_drvdata(dev);
@@ -120,11 +172,11 @@
 	 */
 	if (drv->is_booted == false) {
 		pil_mss_power_up(pil->dev);
-		pil_q6v5_enable_clks(pil);
+		pil_mss_enable_clks(drv);
 	}
 	pil_q6v5_shutdown(pil);
 
-	pil_q6v5_disable_clks(pil);
+	pil_mss_disable_clks(drv);
 	pil_mss_power_down(pil->dev);
 
 	writel_relaxed(1, drv->restart_reg);
@@ -139,8 +191,10 @@
 	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
 	int ret;
 
+	/* Deassert reset to subsystem and wait for propagation */
 	writel_relaxed(0, drv->restart_reg);
 	mb();
+	udelay(2);
 
 	/*
 	 * Bring subsystem out of reset and enable required
@@ -150,7 +204,7 @@
 	if (ret)
 		goto err_power;
 
-	ret = pil_q6v5_enable_clks(pil);
+	ret = pil_mss_enable_clks(drv);
 	if (ret)
 		goto err_clks;
 
@@ -164,6 +218,9 @@
 				drv->reg_base + QDSP6SS_RST_EVB);
 	}
 
+	/* De-assert MSS IO clamps */
+	writel_relaxed(MSS_IO_UNCLAMP_ALL, drv->io_clamp_reg);
+
 	ret = pil_q6v5_reset(pil);
 	if (ret)
 		goto err_q6v5_reset;
@@ -182,7 +239,7 @@
 err_auth:
 	pil_q6v5_shutdown(pil);
 err_q6v5_reset:
-	pil_q6v5_disable_clks(pil);
+	pil_mss_disable_clks(drv);
 err_clks:
 	pil_mss_power_down(pil->dev);
 err_power:
@@ -231,11 +288,17 @@
 	if (!drv->restart_reg)
 		return -ENOMEM;
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
+	drv->io_clamp_reg = devm_ioremap(&pdev->dev, res->start,
+					resource_size(res));
+	if (!drv->io_clamp_reg)
+		return -ENOMEM;
+
 	drv->vreg = devm_regulator_get(&pdev->dev, "vdd_mss");
 	if (IS_ERR(drv->vreg))
 		return PTR_ERR(drv->vreg);
 
-	ret = regulator_set_voltage(drv->vreg, 1150000, 1150000);
+	ret = regulator_set_voltage(drv->vreg, 1050000, 1050000);
 	if (ret)
 		dev_err(&pdev->dev, "Failed to set regulator's voltage.\n");
 
@@ -245,9 +308,25 @@
 		return ret;
 	}
 
-	drv->mem_clk = devm_clk_get(&pdev->dev, "mem_clk");
-	if (IS_ERR(drv->mem_clk))
-		return PTR_ERR(drv->mem_clk);
+	drv->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
+	if (IS_ERR(drv->ahb_clk))
+		return PTR_ERR(drv->ahb_clk);
+
+	drv->core_clk = devm_clk_get(&pdev->dev, "core_clk");
+	if (IS_ERR(drv->core_clk))
+		return PTR_ERR(drv->core_clk);
+
+	drv->axi_clk = devm_clk_get(&pdev->dev, "bus_clk");
+	if (IS_ERR(drv->axi_clk))
+		return PTR_ERR(drv->axi_clk);
+
+	drv->reg_clk = devm_clk_get(&pdev->dev, "reg_clk");
+	if (IS_ERR(drv->reg_clk))
+		return PTR_ERR(drv->reg_clk);
+
+	drv->rom_clk = devm_clk_get(&pdev->dev, "mem_clk");
+	if (IS_ERR(drv->rom_clk))
+		return PTR_ERR(drv->rom_clk);
 
 	drv->pil = msm_pil_register(desc);
 	if (IS_ERR(drv->pil))
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index a362a7e3..772031b 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -20,9 +20,7 @@
 #include <linux/err.h>
 #include <linux/of.h>
 #include <linux/clk.h>
-
 #include <mach/clk.h>
-
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
 
@@ -30,6 +28,7 @@
 #define QDSP6SS_RESET			0x014
 #define QDSP6SS_GFMUX_CTL		0x020
 #define QDSP6SS_PWR_CTL			0x030
+#define QDSP6SS_CGC_OVERRIDE		0x034
 
 /* AXI Halt Register Offsets */
 #define AXI_HALTREQ			0x0
@@ -39,15 +38,15 @@
 #define HALT_ACK_TIMEOUT_US		100000
 
 /* QDSP6SS_RESET */
+#define Q6SS_STOP_CORE			BIT(0)
 #define Q6SS_CORE_ARES			BIT(1)
-#define Q6SS_ETM_ISDB_ARES		BIT(3)
-#define Q6SS_STOP_CORE			BIT(4)
+#define Q6SS_BUS_ARES_ENA		BIT(2)
 
 /* QDSP6SS_GFMUX_CTL */
 #define Q6SS_CLK_ENA			BIT(1)
 
 /* QDSP6SS_PWR_CTL */
-#define Q6SS_L2DATA_SLP_NRET_N		BIT(0)
+#define Q6SS_L2DATA_SLP_NRET_N		(BIT(0)|BIT(1)|BIT(2))
 #define Q6SS_L2TAG_SLP_NRET_N		BIT(16)
 #define Q6SS_ETB_SLP_NRET_N		BIT(17)
 #define Q6SS_L2DATA_STBY_N		BIT(18)
@@ -55,6 +54,10 @@
 #define Q6SS_CLAMP_IO			BIT(20)
 #define QDSS_BHS_ON			BIT(21)
 
+/* QDSP6SS_CGC_OVERRIDE */
+#define Q6SS_CORE_CLK_EN		BIT(0)
+#define Q6SS_CORE_RCLK_EN		BIT(1)
+
 int pil_q6v5_make_proxy_votes(struct pil_desc *pil)
 {
 	int ret;
@@ -107,50 +110,6 @@
 }
 EXPORT_SYMBOL(pil_q6v5_init_image);
 
-int pil_q6v5_enable_clks(struct pil_desc *pil)
-{
-	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
-	int ret;
-
-	ret = clk_reset(drv->core_clk, CLK_RESET_DEASSERT);
-	if (ret)
-		goto err_reset;
-	ret = clk_prepare_enable(drv->core_clk);
-	if (ret)
-		goto err_core_clk;
-	ret = clk_prepare_enable(drv->bus_clk);
-	if (ret)
-		goto err_bus_clk;
-	if (drv->mem_clk) {
-		ret = clk_prepare_enable(drv->mem_clk);
-		if (ret)
-			goto err_mem_clk;
-	}
-
-	return 0;
-
-err_mem_clk:
-	clk_disable_unprepare(drv->bus_clk);
-err_bus_clk:
-	clk_disable_unprepare(drv->core_clk);
-err_core_clk:
-	clk_reset(drv->core_clk, CLK_RESET_ASSERT);
-err_reset:
-	return ret;
-}
-EXPORT_SYMBOL(pil_q6v5_enable_clks);
-
-void pil_q6v5_disable_clks(struct pil_desc *pil)
-{
-	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
-
-	clk_disable_unprepare(drv->bus_clk);
-	clk_disable_unprepare(drv->core_clk);
-	clk_disable_unprepare(drv->mem_clk);
-	clk_reset(drv->core_clk, CLK_RESET_ASSERT);
-}
-EXPORT_SYMBOL(pil_q6v5_disable_clks);
-
 void pil_q6v5_shutdown(struct pil_desc *pil)
 {
 	u32 val;
@@ -174,7 +133,7 @@
 
 	/* Assert Q6 resets */
 	val = readl_relaxed(drv->reg_base + QDSP6SS_RESET);
-	val = (Q6SS_CORE_ARES | Q6SS_ETM_ISDB_ARES);
+	val = (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENA);
 	writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
 
 	/* Kill power at block headswitch (affects LPASS only) */
@@ -191,7 +150,7 @@
 
 	/* Assert resets, stop core */
 	val = readl_relaxed(drv->reg_base + QDSP6SS_RESET);
-	val |= (Q6SS_CORE_ARES | Q6SS_ETM_ISDB_ARES | Q6SS_STOP_CORE);
+	val |= (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENA | Q6SS_STOP_CORE);
 	writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
 
 	/* Enable power block headswitch (only affects LPASS) */
@@ -211,9 +170,15 @@
 	writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
 
 	/* Bring core out of reset */
-	val = Q6SS_STOP_CORE;
+	val = readl_relaxed(drv->reg_base + QDSP6SS_RESET);
+	val &= ~Q6SS_CORE_ARES;
 	writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
 
+	/* Disable clock gating for core and rclk */
+	val = readl_relaxed(drv->reg_base + QDSP6SS_CGC_OVERRIDE);
+	val |= Q6SS_CORE_RCLK_EN | Q6SS_CORE_CLK_EN;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_CGC_OVERRIDE);
+
 	/* Turn on core clock */
 	val = readl_relaxed(drv->reg_base + QDSP6SS_GFMUX_CTL);
 	val |= Q6SS_CLK_ENA;
@@ -266,14 +231,6 @@
 	if (IS_ERR(drv->xo))
 		return ERR_CAST(drv->xo);
 
-	drv->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
-	if (IS_ERR(drv->bus_clk))
-		return ERR_CAST(drv->bus_clk);
-
-	drv->core_clk = devm_clk_get(&pdev->dev, "core_clk");
-	if (IS_ERR(drv->core_clk))
-		return ERR_CAST(drv->core_clk);
-
 	desc->dev = &pdev->dev;
 
 	return desc;
diff --git a/arch/arm/mach-msm/pil-q6v5.h b/arch/arm/mach-msm/pil-q6v5.h
index e0d7a20..03f93fa 100644
--- a/arch/arm/mach-msm/pil-q6v5.h
+++ b/arch/arm/mach-msm/pil-q6v5.h
@@ -21,13 +21,16 @@
 
 struct q6v5_data {
 	void __iomem *reg_base;
-	struct clk *xo;
-	struct clk *bus_clk;
-	struct clk *core_clk;
-	struct clk *mem_clk;
+	struct clk *xo;		/* XO clock source */
+	struct clk *ahb_clk;	/* PIL access to registers */
+	struct clk *axi_clk;	/* CPU access to memory */
+	struct clk *core_clk;	/* CPU core */
+	struct clk *reg_clk;	/* CPU access registers */
+	struct clk *rom_clk;	/* Boot ROM */
 	void __iomem *axi_halt_base;
 	void __iomem *rmb_base;
 	void __iomem *restart_reg;
+	void __iomem *io_clamp_reg;
 	unsigned long start_addr;
 	struct regulator *vreg;
 	bool is_booted;
@@ -42,8 +45,6 @@
 			size_t size);
 void pil_q6v5_shutdown(struct pil_desc *pil);
 int pil_q6v5_reset(struct pil_desc *pil);
-int pil_q6v5_enable_clks(struct pil_desc *pil);
-void pil_q6v5_disable_clks(struct pil_desc *pil);
 struct pil_desc *pil_q6v5_init(struct platform_device *pdev);
 
 #endif
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index 2d1fa80..3040a31 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -228,18 +228,6 @@
 
 static int pil_riva_shutdown(struct pil_desc *pil)
 {
-	struct riva_data *drv = dev_get_drvdata(pil->dev);
-	u32 reg;
-
-	/* Put cCPU and cCPU clock into reset */
-	reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_VAL);
-	reg &= ~(RIVA_PMU_OVRD_VAL_CCPU_RESET | RIVA_PMU_OVRD_VAL_CCPU_CLK);
-	writel_relaxed(reg, drv->base + RIVA_PMU_OVRD_VAL);
-	reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_EN);
-	reg |= RIVA_PMU_OVRD_EN_CCPU_RESET | RIVA_PMU_OVRD_EN_CCPU_CLK;
-	writel_relaxed(reg, drv->base + RIVA_PMU_OVRD_EN);
-	mb();
-
 	/* Assert reset to Riva */
 	writel_relaxed(1, RIVA_RESET);
 	mb();
diff --git a/arch/arm/mach-msm/pil-venus.c b/arch/arm/mach-msm/pil-venus.c
index 6a0aeaa..49c39ec 100644
--- a/arch/arm/mach-msm/pil-venus.c
+++ b/arch/arm/mach-msm/pil-venus.c
@@ -228,12 +228,6 @@
 	writel_relaxed(drv->fw_sz, wrapper_base +
 			VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR);
 
-	rc = iommu_attach_device(drv->iommu_fw_domain, drv->iommu_fw_ctx);
-	if (rc) {
-		dev_err(pil->dev, "venus fw iommu attach failed\n");
-		goto err_iommu_attach;
-	}
-
 	/* Enable all Venus internal clocks */
 	writel_relaxed(0, wrapper_base + VENUS_WRAPPER_CLOCK_CONFIG);
 	writel_relaxed(0, wrapper_base + VENUS_WRAPPER_CPU_CLOCK_CONFIG);
@@ -247,6 +241,12 @@
 	 */
 	udelay(1);
 
+	rc = iommu_attach_device(drv->iommu_fw_domain, drv->iommu_fw_ctx);
+	if (rc) {
+		dev_err(pil->dev, "venus fw iommu attach failed\n");
+		goto err_iommu_attach;
+	}
+
 	/* Map virtual addr space 0 - fw_sz to firmware physical addr space */
 	rc = msm_iommu_map_contig_buffer(pa, drv->venus_domain_num, 0,
 					 drv->fw_sz, SZ_4K, 0, &iova);
@@ -285,19 +285,6 @@
 
 	venus_clock_prepare_enable(pil->dev);
 
-	/* Halt AXI and AXI OCMEM VBIF Access */
-	reg = readl_relaxed(vbif_base + VENUS_VBIF_AXI_HALT_CTRL0);
-	reg |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ;
-	writel_relaxed(reg, vbif_base + VENUS_VBIF_AXI_HALT_CTRL0);
-
-	/* Request for AXI bus port halt */
-	rc = readl_poll_timeout(vbif_base + VENUS_VBIF_AXI_HALT_CTRL1,
-			reg, reg & VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK,
-			POLL_INTERVAL_US,
-			VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US);
-	if (rc)
-		dev_err(pil->dev, "Port halt timeout\n");
-
 	/* Assert the reset to ARM9 */
 	reg = readl_relaxed(wrapper_base + VENUS_WRAPPER_SW_RESET);
 	reg |= BIT(4);
@@ -311,6 +298,19 @@
 
 	iommu_detach_device(drv->iommu_fw_domain, drv->iommu_fw_ctx);
 
+	/* Halt AXI and AXI OCMEM VBIF Access */
+	reg = readl_relaxed(vbif_base + VENUS_VBIF_AXI_HALT_CTRL0);
+	reg |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ;
+	writel_relaxed(reg, vbif_base + VENUS_VBIF_AXI_HALT_CTRL0);
+
+	/* Request for AXI bus port halt */
+	rc = readl_poll_timeout(vbif_base + VENUS_VBIF_AXI_HALT_CTRL1,
+			reg, reg & VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK,
+			POLL_INTERVAL_US,
+			VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US);
+	if (rc)
+		dev_err(pil->dev, "Port halt timeout\n");
+
 	venus_clock_disable_unprepare(pil->dev);
 
 	regulator_disable(drv->gdsc);
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index a11ca95..b2d3dfa 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -14,6 +14,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/regulator/krait-regulator.h>
 
 #include <asm/hardware/gic.h>
 #include <asm/cacheflush.h>
@@ -120,6 +121,31 @@
 	return 0;
 }
 
+static int __cpuinit krait_release_secondary_p3(unsigned long base, int cpu)
+{
+	void *base_ptr = ioremap_nocache(base + (cpu * 0x10000), SZ_4K);
+	if (!base_ptr)
+		return -ENODEV;
+
+	secondary_cpu_hs_init(base_ptr);
+
+	writel_relaxed(0x021, base_ptr+0x04);
+	mb();
+	udelay(2);
+
+	writel_relaxed(0x020, base_ptr+0x04);
+	mb();
+	udelay(2);
+
+	writel_relaxed(0x000, base_ptr+0x04);
+	mb();
+
+	writel_relaxed(0x080, base_ptr+0x04);
+	mb();
+	iounmap(base_ptr);
+	return 0;
+}
+
 static int __cpuinit release_secondary(unsigned int cpu)
 {
 	BUG_ON(cpu >= get_core_count());
@@ -134,6 +160,9 @@
 	    cpu_is_apq8064() || cpu_is_msm8627() || cpu_is_msm8960ab())
 		return krait_release_secondary(0x02088000, cpu);
 
+	if (cpu_is_msm8974())
+		return krait_release_secondary_p3(0xf9088000, cpu);
+
 	WARN(1, "unknown CPU case in release_secondary\n");
 	return -EINVAL;
 }
@@ -205,8 +234,8 @@
 		if (pen_release == -1)
 			break;
 
-		dmac_inv_range((void *)&pen_release,
-			       (void *)(&pen_release+sizeof(pen_release)));
+		dmac_inv_range((char *)&pen_release,
+			       (char *)&pen_release + sizeof(pen_release));
 		udelay(10);
 	}
 
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 769d740..c1a899d 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -825,7 +825,7 @@
 		msm_pm_power_collapse_standalone(false);
 	else if (allow[MSM_PM_SLEEP_MODE_RETENTION])
 		msm_pm_retention();
-	else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT])
+	else
 		msm_pm_swfi();
 }
 
diff --git a/arch/arm/mach-msm/qdsp5/Makefile b/arch/arm/mach-msm/qdsp5/Makefile
index 2ce0031..89648fe 100644
--- a/arch/arm/mach-msm/qdsp5/Makefile
+++ b/arch/arm/mach-msm/qdsp5/Makefile
@@ -17,4 +17,4 @@
 obj-y += snd.o snd_adie.o
 obj-$(CONFIG_ARCH_MSM7X27A) += audio_fm.o
 obj-$(CONFIG_ARCH_MSM7X27A) += audio_mvs.o
-obj-$(CONFIG_ARCH_MSM7X27A) += audio_lpa.o
+obj-$(CONFIG_ARCH_MSM7X27A) += audio_lpa.o audio_ac3.o
diff --git a/arch/arm/mach-msm/qdsp5/adsp_rm.c b/arch/arm/mach-msm/qdsp5/adsp_rm.c
index 81147f7..f67946c 100644
--- a/arch/arm/mach-msm/qdsp5/adsp_rm.c
+++ b/arch/arm/mach-msm/qdsp5/adsp_rm.c
@@ -33,7 +33,8 @@
 			"PCM Blocks not Sufficient",
 			"TASK is already occupied",
 			"Concurrency not supported",
-			"MIPS not sufficient"
+			"MIPS not sufficient",
+			"DDP invalid/no licence"
 			};
 static struct client {
 	wait_queue_head_t		wait;
diff --git a/arch/arm/mach-msm/qdsp5/audio_ac3.c b/arch/arm/mach-msm/qdsp5/audio_ac3.c
new file mode 100644
index 0000000..ee085c5
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_ac3.c
@@ -0,0 +1,1753 @@
+/* arch/arm/mach-msm/audio_ac3.c
+ *
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
+ *
+ * This code also borrows from audio_aac.c, which is
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/earlysuspend.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <linux/memory_alloc.h>
+#include <linux/msm_audio_ac3.h>
+#include <linux/ion.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audplaycmdi.h>
+#include <mach/qdsp5/qdsp5audplaymsg.h>
+#include <mach/qdsp5/qdsp5rmtcmdi.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+#include "audmgr.h"
+
+#define BUFSZ			4096
+#define DMASZ			(BUFSZ * 2)
+
+#define AUDDEC_DEC_AC3		23
+
+#define PCM_BUFSZ		6168 /* maximum frame size is 512 * 6 samples */
+#define PCM_BUF_MAX_COUNT	5  /* DSP only accepts 5 buffers at most
+				    * but support 2 buffers currently
+				   */
+#define ROUTING_MODE_FTRT	1
+#define ROUTING_MODE_RT		2
+
+/* Decoder status received from AUDPPTASK */
+#define AUDPP_DEC_STATUS_SLEEP	0
+#define	AUDPP_DEC_STATUS_INIT  1
+#define AUDPP_DEC_STATUS_CFG   2
+#define AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDAC3_METAFIELD_MASK 0xFFFF0000
+#define AUDAC3_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDAC3_EOS_FLG_MASK 0x01
+#define AUDAC3_EOS_NONE 0x0 /* No EOS detected */
+#define AUDAC3_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDAC3_EVENT_NUM 10 /* Default number of pre-allocated event packets */
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+	unsigned short mfield_sz; /* only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audac3_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct audac3_event {
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	int32_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+	struct audmgr audmgr;
+	struct msm_audio_ac3_config ac3_config;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys;  /* physical address of write buffer */
+	void *map_v_read;
+	void *map_v_write;
+
+	int mfield; /* meta field embedded in data */
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	uint8_t opened;
+	uint8_t enabled;
+	uint8_t running;
+	uint8_t stopped;	/* set when stopped, cleared on flush */
+	uint8_t pcm_feedback;
+	uint8_t buf_refresh;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+	int rmt_resource_released;
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audac3_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+
+	int eq_enable;
+	int eq_needs_commit;
+	audpp_cmd_cfg_object_params_eqalizer eq;
+	audpp_cmd_cfg_object_params_volume vol_pan;
+	struct ion_client *client;
+	struct ion_handle *input_buff_handle;
+	struct ion_handle *output_buff_handle;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audac3_send_data(struct audio *audio, unsigned needed);
+static void audac3_dsp_event(void *private, unsigned id, uint16_t *msg);
+static void audac3_config_hostpcm(struct audio *audio);
+static void audac3_buffer_refresh(struct audio *audio);
+static void audac3_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload);
+
+static int rmt_put_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_DISABLE;
+	cmd.dec_type = AUDDEC_DEC_AC3;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return put_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+static int rmt_get_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_ENABLE;
+	cmd.dec_type = AUDDEC_DEC_AC3;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+	return get_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int audac3_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (audio->enabled)
+		return 0;
+
+	if (audio->rmt_resource_released == 1) {
+		audio->rmt_resource_released = 0;
+		rc = rmt_get_resource(audio);
+		if (rc) {
+			MM_ERR("ADSP resources are not available for AC3"\
+				" session 0x%08x on decoder: %d\n Ignoring"\
+				" error and going ahead with the playback\n",
+				(int)audio, audio->dec_id);
+		}
+	}
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+		cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+		cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+		cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK;
+		cfg.codec = RPC_AUD_DEF_CODEC_AC3;
+		cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+		rc = audmgr_enable(&audio->audmgr, &cfg);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audac3_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audac3_disable(struct audio *audio)
+{
+	int rc = 0;
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		audio->stopped = 1;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+		rmt_put_resource(audio);
+		audio->rmt_resource_released = 1;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+
+static void audac3_update_pcm_buf_entry(struct audio *audio,
+					 uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr
+				== payload[2 + index * 2]) {
+			MM_DBG("in[%d] ready\n", audio->fill_next);
+			audio->in[audio->fill_next].used =
+				payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+
+		} else {
+			MM_ERR("expected=%x ret=%x\n",
+				audio->in[audio->fill_next].addr,
+				payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audac3_buffer_refresh(audio);
+	} else {
+		MM_DBG("read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audac3_send_data(audio, 1);
+		break;
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		MM_DBG("\n"); /* Macro prints the file name and function */
+		audac3_update_pcm_buf_entry(audio, msg);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+	default:
+		MM_ERR("unexpected message from decoder\n");
+	}
+}
+
+static void audac3_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status:sleep reason =0x%04x\n",
+					reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init\n");
+				if (audio->pcm_feedback)
+					audpp_cmd_cfg_routing_mode(audio);
+				else
+					audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg\n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play\n");
+				if (audio->pcm_feedback) {
+					audac3_config_hostpcm(audio);
+					audac3_buffer_refresh(audio);
+				}
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status\n");
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+			audpp_dsp_set_eq(audio->dec_id,	audio->eq_enable,
+								&audio->eq);
+			audpp_avsync(audio->dec_id, 22050);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audpp_avsync(audio->dec_id, 0);
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK\n");
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		audio->rflush = 0;
+		wake_up(&audio->write_wait);
+		if (audio->pcm_feedback)
+			audac3_buffer_refresh(audio);
+		break;
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+struct msm_adsp_ops audplay_adsp_ops_ac3 = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	u16 cfg_dec_cmd[AUDPP_CMD_CFG_DEC_TYPE_LEN / sizeof(unsigned short)];
+
+	memset(cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+	cfg_dec_cmd[0] = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_AC3;
+	else
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_DIS_DEC_V;
+
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+static int get_frequency_index(unsigned short frequency)
+{
+	switch (frequency) {
+	case 48000: return 0;
+	case 44100: return 1;
+	case 32000: return 2;
+	default: return -EINVAL;
+	}
+}
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_ac3 cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	/* dsp needs word size */
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_AC3_LEN >> 1;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = (audio->ac3_config).fsCod;
+
+	cmd.index[0] = (((audio->ac3_config).numChans << 8) & 0xFF00) |
+				((audio->ac3_config).wordSize & 0x00FF);
+
+	cmd.index[1] = (((audio->ac3_config).kCapableMode << 12) & 0xF000) |
+				(((audio->ac3_config).compMode << 8) & 0x0F00) |
+				(((audio->ac3_config).outLfeOn << 4) & 0x00F0) |
+				((audio->ac3_config).outputMode & 0x000F);
+
+	cmd.index[2] = ((((audio->ac3_config).stereoMode << 12) & 0xF000) |
+			(((audio->ac3_config).dualMonoMode << 8) & 0x0F00) |
+			((get_frequency_index((audio->ac3_config).fsCod) << 4)
+			& 0x00F0)) & 0xFFF0; /* last 4 bytes are reserved */
+
+	cmd.index[3] = (audio->ac3_config).pcmScaleFac;
+	cmd.index[4] = (audio->ac3_config).dynRngScaleHi;
+	cmd.index[5] = (audio->ac3_config).dynRngScaleLow;
+
+	cmd.index[6] = (((audio->ac3_config).user_downmix_flag << 8) & 0xFF00)|
+			((audio->ac3_config).user_karaoke_flag & 0x00FF);
+
+	cmd.index[7] = (audio->ac3_config).dm_address_high;
+	cmd.index[8] = (audio->ac3_config).dm_address_low;
+	cmd.index[9] = (audio->ac3_config).ko_address_high;
+	cmd.index[10] = (audio->ac3_config).ko_address_high;
+
+	cmd.index[11] = (((audio->ac3_config).max_rep_count << 1) & 0xFFFE) |
+			((audio->ac3_config).error_concealment & 0x0001);
+
+	cmd.index[12] = (((audio->ac3_config).channel_routing_mode[3] << 12)
+			& 0xF000) |
+			(((audio->ac3_config).channel_routing_mode[2] << 8)
+			& 0x0F00) |
+			(((audio->ac3_config).channel_routing_mode[1] << 4)
+			& 0x00F0) |
+			((audio->ac3_config).channel_routing_mode[0] & 0x000F);
+
+	cmd.index[13] = ((((audio->ac3_config).channel_routing_mode[5] << 12)
+			& 0xF000) |
+			(((audio->ac3_config).channel_routing_mode[4] << 8)
+			& 0x0F00)) & 0xFF00; /* last 8 bytes are reserved */
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+				       unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+	cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+	if (audio->mfield)
+		cmd.decoder_id = AUDAC3_METAFIELD_MASK |
+			(audio->out[idx].mfield_sz >> 1);
+	else
+		cmd.decoder_id = audio->dec_id;
+	cmd.buf_ptr = audio->out[idx].addr;
+	cmd.buf_size = len / 2;
+	cmd.partition_number = 0;
+	/* complete writes to the input buffer */
+	wmb();
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audac3_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size;
+
+	refresh_cmd.buf_read_count = 0;
+	MM_DBG("buf0_addr=%x buf0_len=%d\n", refresh_cmd.buf0_address,
+			refresh_cmd.buf0_length);
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audac3_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = 1;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+
+}
+
+static void audac3_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audac3_flush(struct audio *audio)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audac3_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+/*check if func to be added to validate user data*/
+
+static void audac3_ioport_reset(struct audio *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audac3_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audac3_flush_pcm_buf(audio);
+	mutex_unlock(&audio->read_lock);
+}
+
+static int audac3_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audac3_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audac3_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audac3_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+			struct audac3_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+
+static long audac3_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audac3_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audac3_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audac3_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audac3_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id, enable, &audio->eq);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static long audac3_ioctl(struct file *file, unsigned int cmd,
+			  unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	int len = 0;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audac3_process_event_req(audio,
+					(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audac3_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS) {
+				MM_ERR("In audio->dec_state !=\n");
+				rc = -ENODEV;
+			} else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audac3_disable(audio);
+		audac3_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audac3_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	case AUDIO_SET_CONFIG:{
+			struct msm_audio_config config;
+			if (copy_from_user
+				(&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			audio->mfield = config.meta_field;
+			rc = 0;
+			MM_DBG("AUDIO_SET_CONFIG applicable only"\
+				" for meta field configuration\n");
+			break;
+		}
+	case AUDIO_GET_CONFIG:{
+			struct msm_audio_config config;
+			config.buffer_size = BUFSZ;
+			config.buffer_count = 2;
+			config.sample_rate = (audio->ac3_config).fsCod;
+			config.channel_count = 2;
+			config.meta_field = 0;
+			config.unused[0] = 0;
+			config.unused[1] = 0;
+			config.unused[2] = 0;
+			if (copy_to_user((void *)arg, &config, sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_GET_AC3_CONFIG:{
+			if (copy_to_user((void *)arg, &audio->ac3_config,
+				sizeof(audio->ac3_config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_AC3_CONFIG:{
+			struct msm_audio_ac3_config usr_config;
+
+			if (copy_from_user
+				(&usr_config, (void *)arg,
+					sizeof(usr_config))) {
+				rc = -EFAULT;
+				break;
+			}
+
+			audio->ac3_config = usr_config;
+			rc = 0;
+			break;
+		}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			config.pcm_feedback = audio->pcm_feedback;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ;
+			if (copy_to_user((void *)arg, &config, sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (config.pcm_feedback != audio->pcm_feedback) {
+
+				MM_ERR("Not sufficient permission to"\
+					" change the playback mode\n");
+				rc = -EACCES;
+				break;
+
+			}
+			if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+			    (config.buffer_count == 1))
+				config.buffer_count = PCM_BUF_MAX_COUNT;
+
+			if (config.buffer_size < PCM_BUFSZ)
+				config.buffer_size = PCM_BUFSZ;
+
+			/* Check if pcm feedback is required */
+			if ((config.pcm_feedback) && (!audio->read_data)) {
+				MM_DBG("allocate PCM buf %d\n",
+					config.buffer_count *
+					config.buffer_size);
+				handle = ion_alloc(audio->client,
+					(config.buffer_size *
+					config.buffer_count),
+					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+				if (IS_ERR_OR_NULL(handle)) {
+					MM_ERR("Unable to alloc I/P buffs\n");
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+					break;
+				}
+
+				audio->input_buff_handle = handle;
+
+				rc = ion_phys(audio->client ,
+					handle, &addr, &len);
+				if (rc) {
+					MM_ERR("Invalid phy: %x sz: %x\n",
+						(unsigned int) addr,
+						(unsigned int) len);
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+					break;
+				} else {
+					MM_INFO("Got valid phy: %x sz: %x\n",
+						(unsigned int) audio->read_phys,
+						(unsigned int) len);
+				}
+				audio->read_phys = (int32_t)addr;
+
+				rc = ion_handle_get_flags(audio->client,
+					handle, &ionflag);
+				if (rc) {
+					MM_ERR("could not get flags\n");
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+					break;
+				}
+
+				audio->map_v_read = ion_map_kernel(
+					audio->client,
+					handle, ionflag);
+				if (IS_ERR(audio->map_v_read)) {
+					MM_ERR("map of read buf failed\n");
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+				} else {
+					uint8_t index;
+					uint32_t offset = 0;
+					audio->read_data =
+						audio->map_v_read;
+					audio->buf_refresh = 0;
+					audio->pcm_buf_count =
+					    config.buffer_count;
+					audio->read_next = 0;
+					audio->fill_next = 0;
+
+					for (index = 0;
+					     index < config.buffer_count;
+					     index++) {
+						audio->in[index].data =
+						    audio->read_data + offset;
+						audio->in[index].addr =
+						    audio->read_phys + offset;
+						audio->in[index].size =
+						    config.buffer_size;
+						audio->in[index].used = 0;
+						offset += config.buffer_size;
+					}
+					MM_DBG("read buf: phy addr"\
+						" 0x%08x kernel addr 0x%08x\n",
+						audio->read_phys,
+						(int)audio->read_data);
+					rc = 0;
+				}
+			} else {
+				rc = 0;
+			}
+			break;
+		}
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+static int audac3_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (!audio->running || audio->pcm_feedback) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+}
+
+static ssize_t audac3_read(struct file *file, char __user *buf, size_t count,
+			    loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+	if (!audio->pcm_feedback) {
+		MM_ERR("returning from read as tunnel mode\n");
+		return 0;
+		/* PCM feedback is not enabled. Nothing to read */
+	}
+	mutex_lock(&audio->read_lock);
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+				(audio->in[audio->read_next].used > 0) ||
+				(audio->stopped) || (audio->rflush));
+
+		MM_DBG("wait terminated count%d\n", count);
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver does
+			 * not know frame size, read count must be greater or
+			 * equal to size of PCM samples
+			 */
+			MM_DBG("read stop - partial frame\n");
+			break;
+		} else {
+			MM_DBG("read from in[%d]\n", audio->read_next);
+			/* order reads from the output buffer */
+			rmb();
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x\n",
+				       (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			break;
+				/* Force to exit while loop
+				 * to prevent output thread
+				 * sleep too long if data is
+				 * not ready at this moment
+				 */
+
+		}
+	}
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		MM_DBG("kick start pcm feedback again\n");
+		audac3_buffer_refresh(audio);
+	}
+	mutex_unlock(&audio->read_lock);
+	if (buf > start)
+		rc = buf - start;
+	MM_DBG("read %d bytes\n", rc);
+	return rc;
+}
+
+static int audac3_process_eos(struct audio *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	int rc = 0;
+	struct buffer *frame;
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	audac3_send_data(audio, 0);
+
+done:
+	return rc;
+}
+
+static ssize_t audac3_write(struct file *file, const char __user *buf,
+			     size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	unsigned short mfield_size = 0;
+	int rc = 0, eos_condition = AUDAC3_EOS_NONE;
+
+	MM_DBG("cnt=%d\n", count);
+
+	if (count & 1)
+		return -EINVAL;
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+						|| (audio->stopped)
+						|| (audio->wflush));
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (audio->mfield) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (__get_user(mfield_size,
+					(unsigned short __user *) buf)) {
+					rc = -EFAULT;
+					break;
+				} else if (mfield_size > count) {
+					rc = -EINVAL;
+					break;
+				}
+				MM_DBG("mf offset_val %x\n", mfield_size);
+				if (copy_from_user(cpy_ptr, buf,
+							mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer has
+				 * contains just meta field
+				 */
+				if (cpy_ptr[AUDAC3_EOS_FLG_OFFSET] &
+						AUDAC3_EOS_FLG_MASK) {
+					MM_DBG("eos set\n");
+					eos_condition = AUDAC3_EOS_SET;
+					if (mfield_size == count) {
+						buf += mfield_size;
+						break;
+					} else
+					cpy_ptr[AUDAC3_EOS_FLG_OFFSET] &=
+						~AUDAC3_EOS_FLG_MASK;
+				}
+				 /* Check EOS to see if */
+				cpy_ptr += mfield_size;
+				count -= mfield_size;
+				buf += mfield_size;
+			 } else {
+				 mfield_size = 0;
+				 MM_DBG("continuous buffer\n");
+			 }
+			 frame->mfield_sz = mfield_size;
+		}
+
+		xfer = (count > (frame->size - mfield_size)) ?
+			(frame->size - mfield_size) : count;
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+		frame->used = xfer + mfield_size;
+		audio->out_head ^= 1;
+		count -= xfer;
+		buf += xfer;
+		audac3_send_data(audio, 0);
+	}
+	if (eos_condition == AUDAC3_EOS_SET)
+		rc = audac3_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+static int audac3_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	audac3_disable(audio);
+	if (audio->rmt_resource_released == 0)
+		rmt_put_resource(audio);
+	audac3_flush(audio);
+	audac3_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audac3_reset_event_queue(audio);
+	ion_unmap_kernel(audio->client, audio->output_buff_handle);
+	ion_free(audio->client, audio->output_buff_handle);
+	if (audio->input_buff_handle != NULL) {
+		ion_unmap_kernel(audio->client, audio->input_buff_handle);
+		ion_free(audio->client, audio->input_buff_handle);
+	}
+	ion_client_destroy(audio->client);
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audac3_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload)
+{
+	struct audac3_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+				struct audac3_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audac3_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static void audac3_suspend(struct early_suspend *h)
+{
+	struct audac3_suspend_ctl *ctl =
+		container_of(h, struct audac3_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audac3_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audac3_resume(struct early_suspend *h)
+{
+	struct audac3_suspend_ctl *ctl =
+		container_of(h, struct audac3_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audac3_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audac3_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audac3_debug_read(struct file *file, char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 1024;
+	static char buffer[1024];
+	int n = 0, i;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_feedback %d\n", audio->pcm_feedback);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_count %d\n", audio->pcm_buf_count);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_sz %d\n", audio->in[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"volume %x\n", audio->vol_pan.volume);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"running %d\n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"dec state %d\n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_needed %d\n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_head %d\n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_tail %d\n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[0].used %d\n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[1].used %d\n", audio->out[1].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"buffer_refresh %d\n", audio->buf_refresh);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"read_next %d\n", audio->read_next);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"fill_next %d\n", audio->fill_next);
+	for (i = 0; i < audio->pcm_buf_count; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+				"in[%d].size %d\n", i, audio->in[i].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audac3_debug_fops = {
+	.read = audac3_debug_read,
+	.open = audac3_debug_open,
+};
+#endif
+
+static int audac3_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, dec_attrb, decid, i;
+	struct audac3_event *e_node = NULL;
+	int len = 0;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_ac3_" + 5];
+#endif
+
+	/* Allocate audio instance, set to zero */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_AC3;
+	if ((file->f_mode & FMODE_WRITE) &&
+			(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+		audio->pcm_feedback = NON_TUNNEL_MODE_PLAYBACK;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+		audio->pcm_feedback = TUNNEL_MODE_PLAYBACK;
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	client = msm_ion_client_create(UINT_MAX, "Audio_AC3_client");
+	if (IS_ERR_OR_NULL(client)) {
+		MM_ERR("Unable to create ION client\n");
+		rc = -ENOMEM;
+		goto client_create_error;
+	}
+	audio->client = client;
+
+	handle = ion_alloc(client, DMASZ, SZ_4K,
+			ION_HEAP(ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL(handle)) {
+		MM_ERR("Unable to create allocate O/P buffers\n");
+		rc = -ENOMEM;
+		goto output_buff_alloc_error;
+	}
+
+	audio->output_buff_handle = handle;
+
+	rc = ion_phys(client, handle, &addr, &len);
+	if (rc) {
+		MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+		goto output_buff_get_phys_error;
+	} else {
+		MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+	}
+	audio->phys = (int32_t)addr;
+
+	rc = ion_handle_get_flags(client, handle, &ionflag);
+	if (rc) {
+		MM_ERR("could not get flags for the handle\n");
+		goto output_buff_get_flags_error;
+	}
+
+	audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR(audio->map_v_write)) {
+		MM_ERR("could not map write buffers,freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENOMEM;
+		goto output_buff_map_error;
+	}
+	audio->data = audio->map_v_write;
+	MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+		audio->phys, (int)audio->data);
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+			&audplay_adsp_ops_ac3, audio);
+	if (rc) {
+		MM_ERR("failed to get %s module, freeing instance 0x%08x\n",
+				audio->module_name, (int)audio);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_close(&audio->audmgr);
+		goto err;
+	}
+
+	rc = rmt_get_resource(audio);
+	if (rc) {
+		MM_ERR("ADSP resources are not available for AC3 session"\
+			" 0x%08x on decoder: %d\n", (int)audio, audio->dec_id);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_close(&audio->audmgr);
+		msm_adsp_put(audio->audplay);
+		goto err;
+	}
+
+	/* Initialize all locks of audio instance */
+	audio->input_buff_handle = NULL;
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->read_wait);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = BUFSZ;
+
+	audio->out[1].data = audio->data + BUFSZ;
+	audio->out[1].addr = audio->phys + BUFSZ;
+	audio->out[1].size = BUFSZ;
+
+	audio->vol_pan.volume = 0x3FFF;
+
+	(audio->ac3_config).wordSize = AUDAC3_DEF_WORDSIZE;
+	(audio->ac3_config).user_downmix_flag = AUDAC3_DEF_USER_DOWNMIX_FLAG;
+	(audio->ac3_config).user_karaoke_flag = AUDAC3_DEF_USER_KARAOKE_FLAG;
+	(audio->ac3_config).error_concealment = AUDAC3_DEF_ERROR_CONCEALMENT;
+	(audio->ac3_config).max_rep_count = AUDAC3_DEF_MAX_REPEAT_COUNT;
+
+	audac3_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_ac3_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+			NULL, (void *) audio, &audac3_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audac3_resume;
+	audio->suspend_ctl.node.suspend = audac3_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDAC3_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audac3_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+err:
+	ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_flags_error:
+output_buff_get_phys_error:
+	ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+	ion_client_destroy(client);
+client_create_error:
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_ac3_fops = {
+	.owner = THIS_MODULE,
+	.open = audac3_open,
+	.release = audac3_release,
+	.read = audac3_read,
+	.write = audac3_write,
+	.unlocked_ioctl = audac3_ioctl,
+	.fsync = audac3_fsync,
+};
+
+struct miscdevice audio_ac3_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_ac3",
+	.fops = &audio_ac3_fops,
+};
+
+static int __init audac3_init(void)
+{
+	return misc_register(&audio_ac3_misc);
+
+}
+
+static void __exit audac3_exit(void)
+{
+	misc_deregister(&audio_ac3_misc);
+}
+
+module_init(audac3_init);
+module_exit(audac3_exit);
+
+MODULE_DESCRIPTION("MSM AC3 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5/audmgr.h b/arch/arm/mach-msm/qdsp5/audmgr.h
index 34c8488..3d8c560 100644
--- a/arch/arm/mach-msm/qdsp5/audmgr.h
+++ b/arch/arm/mach-msm/qdsp5/audmgr.h
@@ -77,6 +77,7 @@
 	RPC_AUD_DEF_CODEC_AMR_NB,
 	RPC_AUD_DEF_CODEC_13K,
 	RPC_AUD_DEF_CODEC_EVRC,
+	RPC_AUD_DEF_CODEC_AC3,
 	RPC_AUD_DEF_CODEC_MAX_002,
 };
 
diff --git a/arch/arm/mach-msm/qdsp5/audmgr_new.h b/arch/arm/mach-msm/qdsp5/audmgr_new.h
index 3604405..2453022 100644
--- a/arch/arm/mach-msm/qdsp5/audmgr_new.h
+++ b/arch/arm/mach-msm/qdsp5/audmgr_new.h
@@ -75,6 +75,7 @@
 	RPC_AUD_DEF_CODEC_AMR_NB,
 	RPC_AUD_DEF_CODEC_13K,
 	RPC_AUD_DEF_CODEC_EVRC,
+	RPC_AUD_DEF_CODEC_AC3,
 	RPC_AUD_DEF_CODEC_MAX_002,
 };
 
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index 2ea1bc9..0c75f66 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -10,7 +10,8 @@
 obj-y += audio_mvs.o
 obj-$(CONFIG_FB_MSM_HDMI_MSM_PANEL) += lpa_if_hdmi.o
 endif
-obj-$(CONFIG_MSM_QDSP6_APR) += apr.o apr_tal.o q6core.o dsp_debug.o
+obj-$(CONFIG_MSM_QDSP6_APR) += apr.o apr_v1.o apr_tal.o q6core.o dsp_debug.o
+obj-$(CONFIG_MSM_QDSP6_APRV2) += apr.o apr_v2.o apr_tal.o q6core.o dsp_debug.o
 obj-y += audio_acdb.o
 ifdef CONFIG_ARCH_MSM9615
 obj-y += rtac.o
@@ -23,4 +24,5 @@
 obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
 obj-$(CONFIG_MSM_QDSP6V2_CODECS) += rtac_v2.o q6audio_v2.o q6audio_v2_aio.o
 obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
+obj-$(CONFIG_MSM_ADSP_LOADER) += adsp-loader.o
 obj-$(CONFIG_MSM_ULTRASOUND) += ultrasound/
diff --git a/arch/arm/mach-msm/qdsp6v2/adsp-loader.c b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
new file mode 100644
index 0000000..9924b52
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <mach/peripheral-loader.h>
+#include <mach/qdsp6v2/apr.h>
+
+#define Q6_PIL_GET_DELAY_MS 100
+
+struct adsp_loader_private {
+	void *pil_h;
+};
+
+static int adsp_loader_probe(struct platform_device *pdev)
+{
+	struct adsp_loader_private *priv;
+	int rc = 0;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, priv);
+
+	priv->pil_h = pil_get("adsp");
+	if (IS_ERR(priv->pil_h)) {
+		pr_err("%s: pil get adsp failed, error:%d\n", __func__, rc);
+		devm_kfree(&pdev->dev, priv);
+		goto fail;
+	}
+
+	/* Query the DSP to check if resources are available */
+	msleep(Q6_PIL_GET_DELAY_MS);
+
+	/* Set the state of the ADSP in APR driver */
+	apr_set_q6_state(APR_SUBSYS_LOADED);
+
+	/* Query for MMPM API */
+
+	pr_info("%s: Q6/ADSP image is loaded\n", __func__);
+fail:
+	return rc;
+}
+
+static int adsp_loader_remove(struct platform_device *pdev)
+{
+	struct adsp_loader_private *priv;
+
+	priv = platform_get_drvdata(pdev);
+	pil_put(priv->pil_h);
+	pr_info("%s: Q6/ADSP image is unloaded\n", __func__);
+
+	return 0;
+}
+
+static const struct of_device_id adsp_loader_dt_match[] = {
+	{ .compatible = "qcom,adsp-loader" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, adsp_loader_dt_match);
+
+static struct platform_driver adsp_loader_driver = {
+	.driver = {
+		.name = "adsp-loader",
+		.owner = THIS_MODULE,
+		.of_match_table = adsp_loader_dt_match,
+	},
+	.probe = adsp_loader_probe,
+	.remove = __devexit_p(adsp_loader_remove),
+};
+
+static int __init adsp_loader_init(void)
+{
+	return platform_driver_register(&adsp_loader_driver);
+}
+module_init(adsp_loader_init);
+
+static void __exit adsp_loader_exit(void)
+{
+	platform_driver_unregister(&adsp_loader_driver);
+}
+module_exit(adsp_loader_exit);
+
+MODULE_DESCRIPTION("ADSP Loader module");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index a0bfb27..d70da19 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -15,7 +15,6 @@
 #include <linux/types.h>
 #include <linux/uaccess.h>
 #include <linux/spinlock.h>
-#include <linux/mutex.h>
 #include <linux/list.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
@@ -36,13 +35,11 @@
 #include <mach/subsystem_notif.h>
 #include <mach/subsystem_restart.h>
 
-struct apr_q6 q6;
-struct apr_client client[APR_DEST_MAX][APR_CLIENT_MAX];
-static atomic_t dsp_state;
-static atomic_t modem_state;
+static struct apr_q6 q6;
+static struct apr_client client[APR_DEST_MAX][APR_CLIENT_MAX];
 
-static wait_queue_head_t  dsp_wait;
-static wait_queue_head_t  modem_wait;
+static wait_queue_head_t dsp_wait;
+static wait_queue_head_t modem_wait;
 /* Subsystem restart: QDSP6 data, functions */
 static struct workqueue_struct *apr_reset_workqueue;
 static void apr_reset_deregister(struct work_struct *work);
@@ -51,6 +48,199 @@
 	struct work_struct work;
 };
 
+struct apr_svc_table {
+	char name[64];
+	int idx;
+	int id;
+	int client_id;
+};
+
+static const struct apr_svc_table svc_tbl_audio[] = {
+	{
+		.name = "AFE",
+		.idx = 0,
+		.id = APR_SVC_AFE,
+		.client_id = APR_CLIENT_AUDIO,
+	},
+	{
+		.name = "ASM",
+		.idx = 1,
+		.id = APR_SVC_ASM,
+		.client_id = APR_CLIENT_AUDIO,
+	},
+	{
+		.name = "ADM",
+		.idx = 2,
+		.id = APR_SVC_ADM,
+		.client_id = APR_CLIENT_AUDIO,
+	},
+	{
+		.name = "CORE",
+		.idx = 3,
+		.id = APR_SVC_ADSP_CORE,
+		.client_id = APR_CLIENT_AUDIO,
+	},
+	{
+		.name = "TEST",
+		.idx = 4,
+		.id = APR_SVC_TEST_CLIENT,
+		.client_id = APR_CLIENT_AUDIO,
+	},
+	{
+		.name = "MVM",
+		.idx = 5,
+		.id = APR_SVC_ADSP_MVM,
+		.client_id = APR_CLIENT_AUDIO,
+	},
+	{
+		.name = "CVS",
+		.idx = 6,
+		.id = APR_SVC_ADSP_CVS,
+		.client_id = APR_CLIENT_AUDIO,
+	},
+	{
+		.name = "CVP",
+		.idx = 7,
+		.id = APR_SVC_ADSP_CVP,
+		.client_id = APR_CLIENT_AUDIO,
+	},
+	{
+		.name = "USM",
+		.idx = 8,
+		.id = APR_SVC_USM,
+		.client_id = APR_CLIENT_AUDIO,
+	},
+};
+
+static struct apr_svc_table svc_tbl_voice[] = {
+	{
+		.name = "VSM",
+		.idx = 0,
+		.id = APR_SVC_VSM,
+		.client_id = APR_CLIENT_VOICE,
+	},
+	{
+		.name = "VPM",
+		.idx = 1,
+		.id = APR_SVC_VPM,
+		.client_id = APR_CLIENT_VOICE,
+	},
+	{
+		.name = "MVS",
+		.idx = 2,
+		.id = APR_SVC_MVS,
+		.client_id = APR_CLIENT_VOICE,
+	},
+	{
+		.name = "MVM",
+		.idx = 3,
+		.id = APR_SVC_MVM,
+		.client_id = APR_CLIENT_VOICE,
+	},
+	{
+		.name = "CVS",
+		.idx = 4,
+		.id = APR_SVC_CVS,
+		.client_id = APR_CLIENT_VOICE,
+	},
+	{
+		.name = "CVP",
+		.idx = 5,
+		.id = APR_SVC_CVP,
+		.client_id = APR_CLIENT_VOICE,
+	},
+	{
+		.name = "SRD",
+		.idx = 6,
+		.id = APR_SVC_SRD,
+		.client_id = APR_CLIENT_VOICE,
+	},
+	{
+		.name = "TEST",
+		.idx = 7,
+		.id = APR_SVC_TEST_CLIENT,
+		.client_id = APR_CLIENT_VOICE,
+	},
+};
+
+enum apr_subsys_state apr_get_modem_state(void)
+{
+	return atomic_read(&q6.modem_state);
+}
+
+void apr_set_modem_state(enum apr_subsys_state state)
+{
+	atomic_set(&q6.modem_state, state);
+}
+
+enum apr_subsys_state apr_cmpxchg_modem_state(enum apr_subsys_state prev,
+					      enum apr_subsys_state new)
+{
+	return atomic_cmpxchg(&q6.modem_state, prev, new);
+}
+
+enum apr_subsys_state apr_get_q6_state(void)
+{
+	return atomic_read(&q6.q6_state);
+}
+EXPORT_SYMBOL_GPL(apr_get_q6_state);
+
+int apr_set_q6_state(enum apr_subsys_state state)
+{
+	pr_debug("%s: setting adsp state %d\n", __func__, state);
+	if (state < APR_SUBSYS_DOWN || state > APR_SUBSYS_LOADED)
+		return -EINVAL;
+	atomic_set(&q6.q6_state, state);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(apr_set_q6_state);
+
+enum apr_subsys_state apr_cmpxchg_q6_state(enum apr_subsys_state prev,
+					   enum apr_subsys_state new)
+{
+	return atomic_cmpxchg(&q6.q6_state, prev, new);
+}
+
+int apr_wait_for_device_up(int dest_id)
+{
+	int rc = -1;
+	if (dest_id == APR_DEST_MODEM)
+		rc = wait_event_interruptible_timeout(modem_wait,
+				    (apr_get_modem_state() == APR_SUBSYS_UP),
+				    (1 * HZ));
+	else if (dest_id == APR_DEST_QDSP6)
+		rc = wait_event_interruptible_timeout(dsp_wait,
+				    (apr_get_q6_state() == APR_SUBSYS_UP),
+				    (1 * HZ));
+	else
+		pr_err("%s: unknown dest_id %d\n", __func__, dest_id);
+	/* returns left time */
+	return rc;
+}
+
+int apr_load_adsp_image(void)
+{
+	int rc = 0;
+	mutex_lock(&q6.lock);
+	if (apr_get_q6_state() == APR_SUBSYS_UP) {
+		q6.pil = pil_get("q6");
+		if (IS_ERR(q6.pil)) {
+			rc = PTR_ERR(q6.pil);
+			pr_err("APR: Unable to load q6 image, error:%d\n", rc);
+		} else {
+			apr_set_q6_state(APR_SUBSYS_LOADED);
+			pr_debug("APR: Image is loaded, stated\n");
+		}
+	} else
+		pr_debug("APR: cannot load state %d\n", apr_get_q6_state());
+	mutex_unlock(&q6.lock);
+	return rc;
+}
+
+struct apr_client *apr_get_client(int dest_id, int client_id)
+{
+	return &client[dest_id][client_id];
+}
 
 int apr_send_pkt(void *handle, uint32_t *buf)
 {
@@ -72,11 +262,11 @@
 	}
 
 	if ((svc->dest_id == APR_DEST_QDSP6) &&
-					(atomic_read(&dsp_state) == 0)) {
-		pr_err("apr: Still dsp is not Up\n");
+	    (apr_get_q6_state() != APR_SUBSYS_LOADED)) {
+		pr_err("%s: Still dsp is not Up\n", __func__);
 		return -ENETRESET;
 	} else if ((svc->dest_id == APR_DEST_MODEM) &&
-					(atomic_read(&modem_state) == 0)) {
+		   (apr_get_modem_state() == APR_SUBSYS_DOWN)) {
 		pr_err("apr: Still Modem is not Up\n");
 		return -ENETRESET;
 	}
@@ -111,7 +301,7 @@
 	return w_len;
 }
 
-static void apr_cb_func(void *buf, int len, void *priv)
+void apr_cb_func(void *buf, int len, void *priv)
 {
 	struct apr_client_data data;
 	struct apr_client *apr_client;
@@ -136,8 +326,7 @@
 	pr_debug("\n*****************\n");
 
 	if (!buf || len <= APR_HDR_SIZE) {
-		pr_err("APR: Improper apr pkt received:%p %d\n",
-								buf, len);
+		pr_err("APR: Improper apr pkt received:%p %d\n", buf, len);
 		return;
 	}
 	hdr = buf;
@@ -162,8 +351,7 @@
 	}
 	msg_type = hdr->hdr_field;
 	msg_type = (msg_type >> 0x08) & 0x0003;
-	if (msg_type >= APR_MSG_TYPE_MAX &&
-			msg_type != APR_BASIC_RSP_RESULT) {
+	if (msg_type >= APR_MSG_TYPE_MAX && msg_type != APR_BASIC_RSP_RESULT) {
 		pr_err("APR: Wrong message type: %d\n", msg_type);
 		return;
 	}
@@ -180,8 +368,8 @@
 	if (hdr->src_domain == APR_DOMAIN_MODEM) {
 		src = APR_DEST_MODEM;
 		if (svc == APR_SVC_MVS || svc == APR_SVC_MVM ||
-			svc == APR_SVC_CVS || svc == APR_SVC_CVP ||
-			svc == APR_SVC_TEST_CLIENT)
+		    svc == APR_SVC_CVS || svc == APR_SVC_CVP ||
+		    svc == APR_SVC_TEST_CLIENT)
 			clnt = APR_CLIENT_VOICE;
 		else {
 			pr_err("APR: Wrong svc :%d\n", svc);
@@ -190,11 +378,11 @@
 	} else if (hdr->src_domain == APR_DOMAIN_ADSP) {
 		src = APR_DEST_QDSP6;
 		if (svc == APR_SVC_AFE || svc == APR_SVC_ASM ||
-			svc == APR_SVC_VSM || svc == APR_SVC_VPM ||
-			svc == APR_SVC_ADM || svc == APR_SVC_ADSP_CORE ||
-			svc == APR_SVC_USM ||
-			svc == APR_SVC_TEST_CLIENT || svc == APR_SVC_ADSP_MVM ||
-			svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP)
+		    svc == APR_SVC_VSM || svc == APR_SVC_VPM ||
+		    svc == APR_SVC_ADM || svc == APR_SVC_ADSP_CORE ||
+		    svc == APR_SVC_USM ||
+		    svc == APR_SVC_TEST_CLIENT || svc == APR_SVC_ADSP_MVM ||
+		    svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP)
 			clnt = APR_CLIENT_AUDIO;
 		else {
 			pr_err("APR: Wrong svc :%d\n", svc);
@@ -220,7 +408,7 @@
 	}
 	pr_debug("svc_idx = %d\n", i);
 	pr_debug("%x %x %x %p %p\n", c_svc->id, c_svc->dest_id,
-			c_svc->client_id, c_svc->fn, c_svc->priv);
+		 c_svc->client_id, c_svc->fn, c_svc->priv);
 	data.payload_size = hdr->pkt_size - hdr_size;
 	data.opcode = hdr->opcode;
 	data.src = src;
@@ -241,199 +429,39 @@
 		pr_err("APR: Rxed a packet for NULL callback\n");
 }
 
-struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
-					uint32_t src_port, void *priv)
+int apr_get_svc(const char *svc_name, int dest_id, int *client_id,
+		int *svc_idx, int *svc_id)
 {
-	int client_id = 0;
-	int svc_idx = 0;
-	int svc_id = 0;
-	int dest_id = 0;
-	int temp_port = 0;
-	struct apr_svc *svc = NULL;
-	int rc = 0;
+	int i;
+	int size;
+	struct apr_svc_table *tbl;
+	int ret = 0;
 
-	if (!dest || !svc_name || !svc_fn)
-		return NULL;
-
-	if (!strncmp(dest, "ADSP", 4))
-		dest_id = APR_DEST_QDSP6;
-	else if (!strncmp(dest, "MODEM", 5)) {
-		dest_id = APR_DEST_MODEM;
+	if (dest_id == APR_DEST_QDSP6) {
+		tbl = (struct apr_svc_table *)&svc_tbl_audio;
+		size = ARRAY_SIZE(svc_tbl_audio);
 	} else {
-		pr_err("APR: wrong destination\n");
-		goto done;
+		tbl = (struct apr_svc_table *)&svc_tbl_voice;
+		size = ARRAY_SIZE(svc_tbl_voice);
 	}
 
-	if ((dest_id == APR_DEST_QDSP6) &&
-				(atomic_read(&dsp_state) == 0)) {
-		pr_info("%s: Wait for Lpass to bootup\n", __func__);
-		rc = wait_event_interruptible_timeout(dsp_wait,
-				(atomic_read(&dsp_state) == 1), (1 * HZ));
-		if (rc == 0) {
-			pr_err("%s: DSP is not Up\n", __func__);
-			return NULL;
-		}
-		pr_info("%s: Lpass Up\n", __func__);
-	} else if ((dest_id == APR_DEST_MODEM) &&
-					(atomic_read(&modem_state) == 0)) {
-		pr_info("%s: Wait for modem to bootup\n", __func__);
-		rc = wait_event_interruptible_timeout(modem_wait,
-			(atomic_read(&modem_state) == 1), (1 * HZ));
-		if (rc == 0) {
-			pr_err("%s: Modem is not Up\n", __func__);
-			return NULL;
-		}
-		pr_info("%s: modem Up\n", __func__);
-	}
-
-	if (!strncmp(svc_name, "AFE", 3)) {
-		client_id = APR_CLIENT_AUDIO;
-		svc_idx = 0;
-		svc_id = APR_SVC_AFE;
-	} else if (!strncmp(svc_name, "ASM", 3)) {
-		client_id = APR_CLIENT_AUDIO;
-		svc_idx = 1;
-		svc_id = APR_SVC_ASM;
-	} else if (!strncmp(svc_name, "ADM", 3)) {
-		client_id = APR_CLIENT_AUDIO;
-		svc_idx = 2;
-		svc_id = APR_SVC_ADM;
-	} else if (!strncmp(svc_name, "CORE", 4)) {
-		client_id = APR_CLIENT_AUDIO;
-		svc_idx = 3;
-		svc_id = APR_SVC_ADSP_CORE;
-	} else if (!strncmp(svc_name, "TEST", 4)) {
-		if (dest_id == APR_DEST_QDSP6) {
-			client_id = APR_CLIENT_AUDIO;
-			svc_idx = 4;
-		} else {
-			client_id = APR_CLIENT_VOICE;
-			svc_idx = 7;
-		}
-		svc_id = APR_SVC_TEST_CLIENT;
-	} else if (!strncmp(svc_name, "VSM", 3)) {
-		client_id = APR_CLIENT_VOICE;
-		svc_idx = 0;
-		svc_id = APR_SVC_VSM;
-	} else if (!strncmp(svc_name, "VPM", 3)) {
-		client_id = APR_CLIENT_VOICE;
-		svc_idx = 1;
-		svc_id = APR_SVC_VPM;
-	} else if (!strncmp(svc_name, "MVS", 3)) {
-		client_id = APR_CLIENT_VOICE;
-		svc_idx = 2;
-		svc_id = APR_SVC_MVS;
-	} else if (!strncmp(svc_name, "MVM", 3)) {
-		if (dest_id == APR_DEST_MODEM) {
-			client_id = APR_CLIENT_VOICE;
-			svc_idx = 3;
-			svc_id = APR_SVC_MVM;
-		} else {
-			client_id = APR_CLIENT_AUDIO;
-			svc_idx = 5;
-			svc_id = APR_SVC_ADSP_MVM;
-		}
-	} else if (!strncmp(svc_name, "CVS", 3)) {
-		if (dest_id == APR_DEST_MODEM) {
-			client_id = APR_CLIENT_VOICE;
-			svc_idx = 4;
-			svc_id = APR_SVC_CVS;
-		} else {
-			client_id = APR_CLIENT_AUDIO;
-			svc_idx = 6;
-			svc_id = APR_SVC_ADSP_CVS;
-		}
-	} else if (!strncmp(svc_name, "CVP", 3)) {
-		if (dest_id == APR_DEST_MODEM) {
-			client_id = APR_CLIENT_VOICE;
-			svc_idx = 5;
-			svc_id = APR_SVC_CVP;
-		} else {
-			client_id = APR_CLIENT_AUDIO;
-			svc_idx = 7;
-			svc_id = APR_SVC_ADSP_CVP;
-		}
-	} else if (!strncmp(svc_name, "SRD", 3)) {
-		client_id = APR_CLIENT_VOICE;
-		svc_idx = 6;
-		svc_id = APR_SVC_SRD;
-	} else if (!strncmp(svc_name, "USM", 3)) {
-		client_id = APR_CLIENT_AUDIO;
-		svc_idx = 8;
-		svc_id = APR_SVC_USM;
-	} else {
-		pr_err("APR: Wrong svc name\n");
-		goto done;
-	}
-
-	pr_debug("svc name = %s c_id = %d dest_id = %d\n",
-				svc_name, client_id, dest_id);
-	mutex_lock(&q6.lock);
-	if (q6.state == APR_Q6_NOIMG) {
-		q6.pil = pil_get("q6");
-		if (IS_ERR(q6.pil)) {
-			q6.pil = pil_get("adsp");
-			if (IS_ERR(q6.pil)) {
-				rc = PTR_ERR(q6.pil);
-				pr_err("APR: Unable to load q6 image, error:%d\n",
-									 rc);
-				mutex_unlock(&q6.lock);
-				return svc;
-			}
-		}
-		q6.state = APR_Q6_LOADED;
-	}
-	mutex_unlock(&q6.lock);
-	mutex_lock(&client[dest_id][client_id].m_lock);
-	if (!client[dest_id][client_id].handle) {
-		client[dest_id][client_id].handle = apr_tal_open(client_id,
-				dest_id, APR_DL_SMD, apr_cb_func, NULL);
-		if (!client[dest_id][client_id].handle) {
-			svc = NULL;
-			pr_err("APR: Unable to open handle\n");
-			mutex_unlock(&client[dest_id][client_id].m_lock);
-			goto done;
-		}
-	}
-	mutex_unlock(&client[dest_id][client_id].m_lock);
-	svc = &client[dest_id][client_id].svc[svc_idx];
-	mutex_lock(&svc->m_lock);
-	client[dest_id][client_id].id = client_id;
-	if (svc->need_reset) {
-		mutex_unlock(&svc->m_lock);
-		pr_err("APR: Service needs reset\n");
-		goto done;
-	}
-	svc->priv = priv;
-	svc->id = svc_id;
-	svc->dest_id = dest_id;
-	svc->client_id = client_id;
-	if (src_port != 0xFFFFFFFF) {
-		temp_port = ((src_port >> 8) * 8) + (src_port & 0xFF);
-		pr_debug("port = %d t_port = %d\n", src_port, temp_port);
-		if (temp_port >= APR_MAX_PORTS || temp_port < 0) {
-			pr_err("APR: temp_port out of bounds\n");
-			mutex_unlock(&svc->m_lock);
-			return NULL;
-		}
-		if (!svc->port_cnt && !svc->svc_cnt)
-			client[dest_id][client_id].svc_cnt++;
-		svc->port_cnt++;
-		svc->port_fn[temp_port] = svc_fn;
-		svc->port_priv[temp_port] = priv;
-	} else {
-		if (!svc->fn) {
-			if (!svc->port_cnt && !svc->svc_cnt)
-				client[dest_id][client_id].svc_cnt++;
-			svc->fn = svc_fn;
-			if (svc->port_cnt)
-				svc->svc_cnt++;
+	for (i = 0; i < size; i++) {
+		if (!strncmp(svc_name, tbl[i].name, strlen(tbl[i].name))) {
+			*client_id = tbl[i].client_id;
+			*svc_idx = tbl[i].idx;
+			*svc_id = tbl[i].id;
+			break;
 		}
 	}
 
-	mutex_unlock(&svc->m_lock);
-done:
-	return svc;
+	pr_debug("%s: svc_name = %s c_id = %d dest_id = %d\n",
+		 __func__, svc_name, *client_id, dest_id);
+	if (i == size) {
+		pr_err("%s: APR: Wrong svc name %s\n", __func__, svc_name);
+		ret = -EINVAL;
+	}
+
+	return ret;
 }
 
 static void apr_reset_deregister(struct work_struct *work)
@@ -489,7 +517,7 @@
 		svc->need_reset = 0x0;
 	}
 	if (client[dest_id][client_id].handle &&
-		!client[dest_id][client_id].svc_cnt) {
+	    !client[dest_id][client_id].svc_cnt) {
 		apr_tal_close(client[dest_id][client_id].handle);
 		client[dest_id][client_id].handle = NULL;
 	}
@@ -524,14 +552,7 @@
 	queue_work(apr_reset_workqueue, &apr_reset_worker->work);
 }
 
-void change_q6_state(int state)
-{
-	mutex_lock(&q6.lock);
-	q6.state = state;
-	mutex_unlock(&q6.lock);
-}
-
-int adsp_state(int state)
+static int adsp_state(int state)
 {
 	pr_info("dsp state = %d\n", state);
 	return 0;
@@ -590,12 +611,12 @@
 }
 
 static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
-								void *_cmd)
+			     void *_cmd)
 {
 	switch (code) {
 	case SUBSYS_BEFORE_SHUTDOWN:
 		pr_debug("M-Notify: Shutdown started\n");
-		atomic_set(&modem_state, 0);
+		apr_set_modem_state(APR_SUBSYS_DOWN);
 		dispatch_event(code, APR_DEST_MODEM);
 		break;
 	case SUBSYS_AFTER_SHUTDOWN:
@@ -605,10 +626,9 @@
 		pr_debug("M-notify: Bootup started\n");
 		break;
 	case SUBSYS_AFTER_POWERUP:
-		if (atomic_read(&modem_state) == 0) {
-			atomic_set(&modem_state, 1);
+		if (apr_cmpxchg_modem_state(APR_SUBSYS_DOWN, APR_SUBSYS_UP) ==
+						APR_SUBSYS_DOWN)
 			wake_up(&modem_wait);
-		}
 		pr_debug("M-Notify: Bootup Completed\n");
 		break;
 	default:
@@ -623,12 +643,12 @@
 };
 
 static int lpass_notifier_cb(struct notifier_block *this, unsigned long code,
-								void *_cmd)
+			     void *_cmd)
 {
 	switch (code) {
 	case SUBSYS_BEFORE_SHUTDOWN:
 		pr_debug("L-Notify: Shutdown started\n");
-		atomic_set(&dsp_state, 0);
+		apr_set_q6_state(APR_SUBSYS_DOWN);
 		dispatch_event(code, APR_DEST_QDSP6);
 		break;
 	case SUBSYS_AFTER_SHUTDOWN:
@@ -638,10 +658,9 @@
 		pr_debug("L-notify: Bootup started\n");
 		break;
 	case SUBSYS_AFTER_POWERUP:
-		if (atomic_read(&dsp_state) == 0) {
-			atomic_set(&dsp_state, 1);
+		if (apr_cmpxchg_q6_state(APR_SUBSYS_DOWN, APR_SUBSYS_UP) ==
+					     APR_SUBSYS_DOWN)
 			wake_up(&dsp_wait);
-		}
 		pr_debug("L-Notify: Bootup Completed\n");
 		break;
 	default:
@@ -670,8 +689,7 @@
 		}
 	mutex_init(&q6.lock);
 	dsp_debug_register(adsp_state);
-	apr_reset_workqueue =
-		create_singlethread_workqueue("apr_driver");
+	apr_reset_workqueue = create_singlethread_workqueue("apr_driver");
 	if (!apr_reset_workqueue)
 		return -ENOMEM;
 	return 0;
@@ -683,10 +701,9 @@
 	int ret = 0;
 	init_waitqueue_head(&dsp_wait);
 	init_waitqueue_head(&modem_wait);
-	atomic_set(&dsp_state, 1);
-	atomic_set(&modem_state, 1);
 	subsys_notif_register_notifier("modem", &mnb);
 	subsys_notif_register_notifier("lpass", &lnb);
+	apr_set_subsys_state();
 	return ret;
 }
 late_initcall(apr_late_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/apr_v1.c b/arch/arm/mach-msm/qdsp6v2/apr_v1.c
new file mode 100644
index 0000000..9535968
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/apr_v1.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/err.h>
+#include <mach/qdsp6v2/apr.h>
+#include <mach/qdsp6v2/apr_tal.h>
+#include <mach/qdsp6v2/dsp_debug.h>
+#include <mach/peripheral-loader.h>
+
+struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
+			     uint32_t src_port, void *priv)
+{
+	struct apr_client *client;
+	int client_id = 0;
+	int svc_idx = 0;
+	int svc_id = 0;
+	int dest_id = 0;
+	int temp_port = 0;
+	struct apr_svc *svc = NULL;
+	int rc = 0;
+
+	if (!dest || !svc_name || !svc_fn)
+		return NULL;
+
+	if (!strncmp(dest, "ADSP", 4))
+		dest_id = APR_DEST_QDSP6;
+	else if (!strncmp(dest, "MODEM", 5)) {
+		dest_id = APR_DEST_MODEM;
+	} else {
+		pr_err("APR: wrong destination\n");
+		goto done;
+	}
+
+	if (dest_id == APR_DEST_QDSP6 &&
+	    apr_get_q6_state() == APR_SUBSYS_DOWN) {
+		pr_info("%s: Wait for Lpass to bootup\n", __func__);
+		rc = apr_wait_for_device_up(dest_id);
+		if (rc == 0) {
+			pr_err("%s: DSP is not Up\n", __func__);
+			return NULL;
+		}
+		pr_info("%s: Lpass Up\n", __func__);
+	} else if (dest_id == APR_DEST_MODEM &&
+		   (apr_get_modem_state() == APR_SUBSYS_DOWN)) {
+		pr_info("%s: Wait for modem to bootup\n", __func__);
+		rc = apr_wait_for_device_up(dest_id);
+		if (rc == 0) {
+			pr_err("%s: Modem is not Up\n", __func__);
+			return NULL;
+		}
+		pr_info("%s: modem Up\n", __func__);
+	}
+
+	if (apr_get_svc(svc_name, dest_id, &client_id, &svc_idx, &svc_id)) {
+		pr_err("%s: apr_get_svc failed\n", __func__);
+		goto done;
+	}
+
+	/* APRv1 loads ADSP image automatically */
+	apr_load_adsp_image();
+
+	client = apr_get_client(dest_id, client_id);
+	mutex_lock(&client->m_lock);
+	if (!client->handle) {
+		client->handle = apr_tal_open(client_id, dest_id, APR_DL_SMD,
+					      apr_cb_func, NULL);
+		if (!client->handle) {
+			svc = NULL;
+			pr_err("APR: Unable to open handle\n");
+			mutex_unlock(&client->m_lock);
+			goto done;
+		}
+	}
+	mutex_unlock(&client->m_lock);
+	svc = &client->svc[svc_idx];
+	mutex_lock(&svc->m_lock);
+	client->id = client_id;
+	if (svc->need_reset) {
+		mutex_unlock(&svc->m_lock);
+		pr_err("APR: Service needs reset\n");
+		goto done;
+	}
+	svc->priv = priv;
+	svc->id = svc_id;
+	svc->dest_id = dest_id;
+	svc->client_id = client_id;
+	if (src_port != 0xFFFFFFFF) {
+		temp_port = ((src_port >> 8) * 8) + (src_port & 0xFF);
+		pr_debug("port = %d t_port = %d\n", src_port, temp_port);
+		if (temp_port >= APR_MAX_PORTS || temp_port < 0) {
+			pr_err("APR: temp_port out of bounds\n");
+			mutex_unlock(&svc->m_lock);
+			return NULL;
+		}
+		if (!svc->port_cnt && !svc->svc_cnt)
+			client->svc_cnt++;
+		svc->port_cnt++;
+		svc->port_fn[temp_port] = svc_fn;
+		svc->port_priv[temp_port] = priv;
+	} else {
+		if (!svc->fn) {
+			if (!svc->port_cnt && !svc->svc_cnt)
+				client->svc_cnt++;
+			svc->fn = svc_fn;
+			if (svc->port_cnt)
+				svc->svc_cnt++;
+		}
+	}
+
+	mutex_unlock(&svc->m_lock);
+done:
+	return svc;
+}
+
+void apr_set_subsys_state(void)
+{
+	apr_set_q6_state(APR_SUBSYS_UP);
+	apr_set_modem_state(APR_SUBSYS_UP);
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/apr_v2.c b/arch/arm/mach-msm/qdsp6v2/apr_v2.c
new file mode 100644
index 0000000..1ef189f
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/apr_v2.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <mach/qdsp6v2/apr.h>
+#include <mach/qdsp6v2/apr_tal.h>
+#include <mach/qdsp6v2/dsp_debug.h>
+
+struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
+			     uint32_t src_port, void *priv)
+{
+	struct apr_client *client;
+	int client_id = 0;
+	int svc_idx = 0;
+	int svc_id = 0;
+	int dest_id = 0;
+	int temp_port = 0;
+	struct apr_svc *svc = NULL;
+	int rc = 0;
+
+	if (!dest || !svc_name || !svc_fn)
+		return NULL;
+
+	if (!strncmp(dest, "ADSP", 4))
+		dest_id = APR_DEST_QDSP6;
+	else if (!strncmp(dest, "MODEM", 5)) {
+		dest_id = APR_DEST_MODEM;
+	} else {
+		pr_err("APR: wrong destination\n");
+		goto done;
+	}
+
+	if ((dest_id == APR_DEST_QDSP6)) {
+		if (apr_get_q6_state() != APR_SUBSYS_LOADED) {
+			pr_err("%s: adsp not up\n", __func__);
+			return NULL;
+		}
+		pr_info("%s: Lpass Up\n", __func__);
+	} else if ((dest_id == APR_DEST_MODEM) &&
+		   (apr_get_modem_state() == APR_SUBSYS_DOWN)) {
+		pr_info("%s: Wait for modem to bootup\n", __func__);
+		rc = apr_wait_for_device_up(dest_id);
+		if (rc == 0) {
+			pr_err("%s: Modem is not Up\n", __func__);
+			return NULL;
+		}
+		pr_info("%s: modem Up\n", __func__);
+	}
+
+	if (apr_get_svc(svc_name, dest_id, &client_id, &svc_idx, &svc_id)) {
+		pr_err("%s: apr_get_svc failed\n", __func__);
+		goto done;
+	}
+
+	/* APRv2 doen't load ADSP image automatically */
+
+	client = apr_get_client(dest_id, client_id);
+	mutex_lock(&client->m_lock);
+	if (!client->handle) {
+		client->handle = apr_tal_open(client_id, dest_id, APR_DL_SMD,
+					      apr_cb_func, NULL);
+		if (!client->handle) {
+			svc = NULL;
+			pr_err("APR: Unable to open handle\n");
+			mutex_unlock(&client->m_lock);
+			goto done;
+		}
+	}
+	mutex_unlock(&client->m_lock);
+	svc = &client->svc[svc_idx];
+	mutex_lock(&svc->m_lock);
+	client->id = client_id;
+	if (svc->need_reset) {
+		mutex_unlock(&svc->m_lock);
+		pr_err("APR: Service needs reset\n");
+		goto done;
+	}
+	svc->priv = priv;
+	svc->id = svc_id;
+	svc->dest_id = dest_id;
+	svc->client_id = client_id;
+	if (src_port != 0xFFFFFFFF) {
+		temp_port = ((src_port >> 8) * 8) + (src_port & 0xFF);
+		pr_debug("port = %d t_port = %d\n", src_port, temp_port);
+		if (temp_port >= APR_MAX_PORTS || temp_port < 0) {
+			pr_err("APR: temp_port out of bounds\n");
+			mutex_unlock(&svc->m_lock);
+			return NULL;
+		}
+		if (!svc->port_cnt && !svc->svc_cnt)
+			client->svc_cnt++;
+		svc->port_cnt++;
+		svc->port_fn[temp_port] = svc_fn;
+		svc->port_priv[temp_port] = priv;
+	} else {
+		if (!svc->fn) {
+			if (!svc->port_cnt && !svc->svc_cnt)
+				client->svc_cnt++;
+			svc->fn = svc_fn;
+			if (svc->port_cnt)
+				svc->svc_cnt++;
+		}
+	}
+
+	mutex_unlock(&svc->m_lock);
+done:
+	return svc;
+}
+
+void apr_set_subsys_state(void)
+{
+	apr_set_q6_state(APR_SUBSYS_DOWN);
+	apr_set_modem_state(APR_SUBSYS_UP);
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
index 1092c77..5c1e7ce 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -20,7 +20,7 @@
 #include <mach/qdsp6v2/audio_acdb.h>
 
 
-#define MAX_NETWORKS		12
+#define MAX_NETWORKS		15
 
 struct sidetone_atomic_cal {
 	atomic_t	enable;
diff --git a/arch/arm/mach-msm/qdsp6v2/q6core.c b/arch/arm/mach-msm/qdsp6v2/q6core.c
index edb1e7d..d7de50e6 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6core.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6core.c
@@ -337,7 +337,7 @@
 		if (apr_handle_q)
 			apr_deregister(apr_handle_q);
 	} else if (!strncmp(l_buf + 20, "loaded", 64)) {
-		change_q6_state(APR_Q6_LOADED);
+		apr_set_q6_state(APR_SUBSYS_LOADED);
 	} else if (!strncmp(l_buf + 20, "boom", 64)) {
 		q6audio_dsp_not_responding();
 	} else if (!strncmp(l_buf + 20, "dsp_ver", 64)) {
diff --git a/arch/arm/mach-msm/rpm-regulator-8660.c b/arch/arm/mach-msm/rpm-regulator-8660.c
index 6c4a9ad..be590e1 100644
--- a/arch/arm/mach-msm/rpm-regulator-8660.c
+++ b/arch/arm/mach-msm/rpm-regulator-8660.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -98,7 +98,8 @@
 	&ncp_set_points,
 };
 
-#define LDO(_vreg_id, _rpm_id, _name, _name_pc, _ranges, _hpm_min_load) \
+#define LDO(_vreg_id, _rpm_id, _name, _name_pc, _ranges, _hpm_min_load, \
+		_requires_cxo) \
 	[RPM_VREG_ID_##_vreg_id] = { \
 		.req = { \
 			[0] = { .id = MSM_RPM_ID_##_rpm_id##_0, }, \
@@ -111,6 +112,7 @@
 		.id		 = RPM_VREG_ID_##_vreg_id, \
 		.rdesc.name	 = _name, \
 		.rdesc_pc.name	 = _name_pc, \
+		.requires_cxo	 = _requires_cxo, \
 	}
 
 #define SMPS(_vreg_id, _rpm_id, _name, _name_pc, _ranges, _hpm_min_load) \
@@ -159,32 +161,32 @@
 	}
 
 static struct vreg vregs[] = {
-	LDO(PM8058_L0,   LDO0,   "8058_l0",   "8058_l0_pc",  nldo, LDO_150),
-	LDO(PM8058_L1,   LDO1,   "8058_l1",   "8058_l1_pc",  nldo, LDO_300),
-	LDO(PM8058_L2,   LDO2,   "8058_l2",   "8058_l2_pc",  pldo, LDO_300),
-	LDO(PM8058_L3,   LDO3,   "8058_l3",   "8058_l3_pc",  pldo, LDO_150),
-	LDO(PM8058_L4,   LDO4,   "8058_l4",   "8058_l4_pc",  pldo, LDO_50),
-	LDO(PM8058_L5,   LDO5,   "8058_l5",   "8058_l5_pc",  pldo, LDO_300),
-	LDO(PM8058_L6,   LDO6,   "8058_l6",   "8058_l6_pc",  pldo, LDO_50),
-	LDO(PM8058_L7,   LDO7,   "8058_l7",   "8058_l7_pc",  pldo, LDO_50),
-	LDO(PM8058_L8,   LDO8,   "8058_l8",   "8058_l8_pc",  pldo, LDO_300),
-	LDO(PM8058_L9,   LDO9,   "8058_l9",   "8058_l9_pc",  pldo, LDO_300),
-	LDO(PM8058_L10,  LDO10,  "8058_l10",  "8058_l10_pc", pldo, LDO_300),
-	LDO(PM8058_L11,  LDO11,  "8058_l11",  "8058_l11_pc", pldo, LDO_150),
-	LDO(PM8058_L12,  LDO12,  "8058_l12",  "8058_l12_pc", pldo, LDO_150),
-	LDO(PM8058_L13,  LDO13,  "8058_l13",  "8058_l13_pc", pldo, LDO_300),
-	LDO(PM8058_L14,  LDO14,  "8058_l14",  "8058_l14_pc", pldo, LDO_300),
-	LDO(PM8058_L15,  LDO15,  "8058_l15",  "8058_l15_pc", pldo, LDO_300),
-	LDO(PM8058_L16,  LDO16,  "8058_l16",  "8058_l16_pc", pldo, LDO_300),
-	LDO(PM8058_L17,  LDO17,  "8058_l17",  "8058_l17_pc", pldo, LDO_150),
-	LDO(PM8058_L18,  LDO18,  "8058_l18",  "8058_l18_pc", pldo, LDO_150),
-	LDO(PM8058_L19,  LDO19,  "8058_l19",  "8058_l19_pc", pldo, LDO_150),
-	LDO(PM8058_L20,  LDO20,  "8058_l20",  "8058_l20_pc", pldo, LDO_150),
-	LDO(PM8058_L21,  LDO21,  "8058_l21",  "8058_l21_pc", nldo, LDO_150),
-	LDO(PM8058_L22,  LDO22,  "8058_l22",  "8058_l22_pc", nldo, LDO_300),
-	LDO(PM8058_L23,  LDO23,  "8058_l23",  "8058_l23_pc", nldo, LDO_300),
-	LDO(PM8058_L24,  LDO24,  "8058_l24",  "8058_l24_pc", nldo, LDO_150),
-	LDO(PM8058_L25,  LDO25,  "8058_l25",  "8058_l25_pc", nldo, LDO_150),
+	LDO(PM8058_L0,   LDO0,   "8058_l0",   "8058_l0_pc",  nldo, LDO_150, 1),
+	LDO(PM8058_L1,   LDO1,   "8058_l1",   "8058_l1_pc",  nldo, LDO_300, 1),
+	LDO(PM8058_L2,   LDO2,   "8058_l2",   "8058_l2_pc",  pldo, LDO_300, 0),
+	LDO(PM8058_L3,   LDO3,   "8058_l3",   "8058_l3_pc",  pldo, LDO_150, 0),
+	LDO(PM8058_L4,   LDO4,   "8058_l4",   "8058_l4_pc",  pldo, LDO_50,  0),
+	LDO(PM8058_L5,   LDO5,   "8058_l5",   "8058_l5_pc",  pldo, LDO_300, 0),
+	LDO(PM8058_L6,   LDO6,   "8058_l6",   "8058_l6_pc",  pldo, LDO_50,  0),
+	LDO(PM8058_L7,   LDO7,   "8058_l7",   "8058_l7_pc",  pldo, LDO_50,  0),
+	LDO(PM8058_L8,   LDO8,   "8058_l8",   "8058_l8_pc",  pldo, LDO_300, 0),
+	LDO(PM8058_L9,   LDO9,   "8058_l9",   "8058_l9_pc",  pldo, LDO_300, 0),
+	LDO(PM8058_L10,  LDO10,  "8058_l10",  "8058_l10_pc", pldo, LDO_300, 0),
+	LDO(PM8058_L11,  LDO11,  "8058_l11",  "8058_l11_pc", pldo, LDO_150, 0),
+	LDO(PM8058_L12,  LDO12,  "8058_l12",  "8058_l12_pc", pldo, LDO_150, 0),
+	LDO(PM8058_L13,  LDO13,  "8058_l13",  "8058_l13_pc", pldo, LDO_300, 0),
+	LDO(PM8058_L14,  LDO14,  "8058_l14",  "8058_l14_pc", pldo, LDO_300, 0),
+	LDO(PM8058_L15,  LDO15,  "8058_l15",  "8058_l15_pc", pldo, LDO_300, 0),
+	LDO(PM8058_L16,  LDO16,  "8058_l16",  "8058_l16_pc", pldo, LDO_300, 0),
+	LDO(PM8058_L17,  LDO17,  "8058_l17",  "8058_l17_pc", pldo, LDO_150, 0),
+	LDO(PM8058_L18,  LDO18,  "8058_l18",  "8058_l18_pc", pldo, LDO_150, 0),
+	LDO(PM8058_L19,  LDO19,  "8058_l19",  "8058_l19_pc", pldo, LDO_150, 0),
+	LDO(PM8058_L20,  LDO20,  "8058_l20",  "8058_l20_pc", pldo, LDO_150, 0),
+	LDO(PM8058_L21,  LDO21,  "8058_l21",  "8058_l21_pc", nldo, LDO_150, 1),
+	LDO(PM8058_L22,  LDO22,  "8058_l22",  "8058_l22_pc", nldo, LDO_300, 1),
+	LDO(PM8058_L23,  LDO23,  "8058_l23",  "8058_l23_pc", nldo, LDO_300, 1),
+	LDO(PM8058_L24,  LDO24,  "8058_l24",  "8058_l24_pc", nldo, LDO_150, 1),
+	LDO(PM8058_L25,  LDO25,  "8058_l25",  "8058_l25_pc", nldo, LDO_150, 1),
 
 	SMPS(PM8058_S0,  SMPS0,  "8058_s0",   "8058_s0_pc",  smps, SMPS),
 	SMPS(PM8058_S1,  SMPS1,  "8058_s1",   "8058_s1_pc",  smps, SMPS),
@@ -197,13 +199,13 @@
 
 	NCP(PM8058_NCP,  NCP,    "8058_ncp",  NULL),
 
-	LDO(PM8901_L0,   LDO0B,  "8901_l0",   "8901_l0_pc",  nldo, LDO_300),
-	LDO(PM8901_L1,   LDO1B,  "8901_l1",   "8901_l1_pc",  pldo, LDO_300),
-	LDO(PM8901_L2,   LDO2B,  "8901_l2",   "8901_l2_pc",  pldo, LDO_300),
-	LDO(PM8901_L3,   LDO3B,  "8901_l3",   "8901_l3_pc",  pldo, LDO_300),
-	LDO(PM8901_L4,   LDO4B,  "8901_l4",   "8901_l4_pc",  pldo, LDO_300),
-	LDO(PM8901_L5,   LDO5B,  "8901_l5",   "8901_l5_pc",  pldo, LDO_300),
-	LDO(PM8901_L6,   LDO6B,  "8901_l6",   "8901_l6_pc",  pldo, LDO_300),
+	LDO(PM8901_L0,   LDO0B,  "8901_l0",   "8901_l0_pc",  nldo, LDO_300, 1),
+	LDO(PM8901_L1,   LDO1B,  "8901_l1",   "8901_l1_pc",  pldo, LDO_300, 0),
+	LDO(PM8901_L2,   LDO2B,  "8901_l2",   "8901_l2_pc",  pldo, LDO_300, 0),
+	LDO(PM8901_L3,   LDO3B,  "8901_l3",   "8901_l3_pc",  pldo, LDO_300, 0),
+	LDO(PM8901_L4,   LDO4B,  "8901_l4",   "8901_l4_pc",  pldo, LDO_300, 0),
+	LDO(PM8901_L5,   LDO5B,  "8901_l5",   "8901_l5_pc",  pldo, LDO_300, 0),
+	LDO(PM8901_L6,   LDO6B,  "8901_l6",   "8901_l6_pc",  pldo, LDO_300, 0),
 
 	SMPS(PM8901_S0,  SMPS0B, "8901_s0",   "8901_s0_pc", ftsmps, FTSMPS),
 	SMPS(PM8901_S1,  SMPS1B, "8901_s1",   "8901_s1_pc", ftsmps, FTSMPS),
diff --git a/arch/arm/mach-msm/rpm-regulator-8930.c b/arch/arm/mach-msm/rpm-regulator-8930.c
index f396fed..3878e22 100644
--- a/arch/arm/mach-msm/rpm-regulator-8930.c
+++ b/arch/arm/mach-msm/rpm-regulator-8930.c
@@ -71,6 +71,11 @@
 	VOLTAGE_RANGE( 750000, 1537500, 12500),
 };
 
+static struct vreg_range ln_ldo_ranges[] = {
+	VOLTAGE_RANGE( 690000, 1110000,  60000),
+	VOLTAGE_RANGE(1380000, 2220000, 120000),
+};
+
 static struct vreg_range smps_ranges[] = {
 	VOLTAGE_RANGE( 375000,  737500, 12500),
 	VOLTAGE_RANGE( 750000, 1487500, 12500),
@@ -90,6 +95,7 @@
 static struct vreg_set_points pldo_set_points = SET_POINTS(pldo_ranges);
 static struct vreg_set_points nldo_set_points = SET_POINTS(nldo_ranges);
 static struct vreg_set_points nldo1200_set_points = SET_POINTS(nldo1200_ranges);
+static struct vreg_set_points ln_ldo_set_points = SET_POINTS(ln_ldo_ranges);
 static struct vreg_set_points smps_set_points = SET_POINTS(smps_ranges);
 static struct vreg_set_points ftsmps_set_points = SET_POINTS(ftsmps_ranges);
 static struct vreg_set_points corner_set_points = SET_POINTS(corner_ranges);
@@ -98,12 +104,13 @@
 	&pldo_set_points,
 	&nldo_set_points,
 	&nldo1200_set_points,
+	&ln_ldo_set_points,
 	&smps_set_points,
 	&ftsmps_set_points,
 	&corner_set_points,
 };
 
-#define LDO(_id, _name, _name_pc, _ranges, _hpm_min_load) \
+#define LDO(_id, _name, _name_pc, _ranges, _hpm_min_load, _requires_cxo) \
 	[RPM_VREG_ID_PM8038_##_id] = { \
 		.req = { \
 			[0] = { .id = MSM_RPM_ID_PM8038_##_id##_0, }, \
@@ -116,6 +123,7 @@
 		.id		 = RPM_VREG_ID_PM8038_##_id, \
 		.rdesc.name	 = _name, \
 		.rdesc_pc.name	 = _name_pc, \
+		.requires_cxo	 = _requires_cxo, \
 	}
 
 #define SMPS(_id, _name, _name_pc, _ranges, _hpm_min_load) \
@@ -160,31 +168,33 @@
 	}
 
 static struct vreg vregs[] = {
-	LDO(L1,   "8038_l1",   NULL,          nldo1200, LDO_1200),
-	LDO(L2,   "8038_l2",   "8038_l2_pc",  nldo,     LDO_150),
-	LDO(L3,   "8038_l3",   "8038_l3_pc",  pldo,     LDO_50),
-	LDO(L4,   "8038_l4",   "8038_l4_pc",  pldo,     LDO_50),
-	LDO(L5,   "8038_l5",   "8038_l5_pc",  pldo,     LDO_600),
-	LDO(L6,   "8038_l6",   "8038_l6_pc",  pldo,     LDO_600),
-	LDO(L7,   "8038_l7",   "8038_l7_pc",  pldo,     LDO_600),
-	LDO(L8,   "8038_l8",   "8038_l8_pc",  pldo,     LDO_300),
-	LDO(L9,   "8038_l9",   "8038_l9_pc",  pldo,     LDO_300),
-	LDO(L10,  "8038_l10",  "8038_l10_pc", pldo,     LDO_600),
-	LDO(L11,  "8038_l11",  "8038_l11_pc", pldo,     LDO_600),
-	LDO(L12,  "8038_l12",  "8038_l12_pc", nldo,     LDO_300),
-	LDO(L14,  "8038_l14",  "8038_l14_pc", pldo,     LDO_50),
-	LDO(L15,  "8038_l15",  "8038_l15_pc", pldo,     LDO_150),
-	LDO(L16,  "8038_l16",  NULL,          nldo1200, LDO_1200),
-	LDO(L17,  "8038_l17",  "8038_l17_pc", pldo,     LDO_150),
-	LDO(L18,  "8038_l18",  "8038_l18_pc", pldo,     LDO_50),
-	LDO(L19,  "8038_l19",  NULL,          nldo1200, LDO_1200),
-	LDO(L20,  "8038_l20",  NULL,          nldo1200, LDO_1200),
-	LDO(L21,  "8038_l21",  "8038_l21_pc", pldo,     LDO_150),
-	LDO(L22,  "8038_l22",  "8038_l22_pc", pldo,     LDO_50),
-	LDO(L23,  "8038_l23",  "8038_l23_pc", pldo,     LDO_50),
-	LDO(L24,  "8038_l24",  NULL,          nldo1200, LDO_1200),
-	LDO(L26,  "8038_l26",  "8038_l26_pc", nldo,     LDO_150),
-	LDO(L27,  "8038_l27",  NULL,          nldo1200, LDO_1200),
+	LDO(L1,   "8038_l1",   NULL,          nldo1200, LDO_1200, 1),
+	LDO(L2,   "8038_l2",   "8038_l2_pc",  nldo,     LDO_150,  1),
+	LDO(L3,   "8038_l3",   "8038_l3_pc",  pldo,     LDO_50,   0),
+	LDO(L4,   "8038_l4",   "8038_l4_pc",  pldo,     LDO_50,   0),
+	LDO(L5,   "8038_l5",   "8038_l5_pc",  pldo,     LDO_600,  0),
+	LDO(L6,   "8038_l6",   "8038_l6_pc",  pldo,     LDO_600,  0),
+	LDO(L7,   "8038_l7",   "8038_l7_pc",  pldo,     LDO_600,  0),
+	LDO(L8,   "8038_l8",   "8038_l8_pc",  pldo,     LDO_300,  0),
+	LDO(L9,   "8038_l9",   "8038_l9_pc",  pldo,     LDO_300,  0),
+	LDO(L10,  "8038_l10",  "8038_l10_pc", pldo,     LDO_600,  0),
+	LDO(L11,  "8038_l11",  "8038_l11_pc", pldo,     LDO_600,  0),
+	LDO(L12,  "8038_l12",  "8038_l12_pc", nldo,     LDO_300,  1),
+	LDO(L13,  "8038_l13",  NULL,          ln_ldo,   LDO_5,    0),
+	LDO(L14,  "8038_l14",  "8038_l14_pc", pldo,     LDO_50,   0),
+	LDO(L15,  "8038_l15",  "8038_l15_pc", pldo,     LDO_150,  0),
+	LDO(L16,  "8038_l16",  NULL,          nldo1200, LDO_1200, 1),
+	LDO(L17,  "8038_l17",  "8038_l17_pc", pldo,     LDO_150,  0),
+	LDO(L18,  "8038_l18",  "8038_l18_pc", pldo,     LDO_50,   0),
+	LDO(L19,  "8038_l19",  NULL,          nldo1200, LDO_1200, 1),
+	LDO(L20,  "8038_l20",  NULL,          nldo1200, LDO_1200, 1),
+	LDO(L21,  "8038_l21",  "8038_l21_pc", pldo,     LDO_150,  0),
+	LDO(L22,  "8038_l22",  "8038_l22_pc", pldo,     LDO_50,   0),
+	LDO(L23,  "8038_l23",  "8038_l23_pc", pldo,     LDO_50,   0),
+	LDO(L24,  "8038_l24",  NULL,          nldo1200, LDO_1200, 1),
+	LDO(L25,  "8038_l25",  NULL,          ln_ldo,   LDO_5,    0),
+	LDO(L26,  "8038_l26",  "8038_l26_pc", nldo,     LDO_150,  1),
+	LDO(L27,  "8038_l27",  NULL,          nldo1200, LDO_1200, 1),
 
 	SMPS(S1,  "8038_s1",   "8038_s1_pc",  smps,     SMPS_1500),
 	SMPS(S2,  "8038_s2",   "8038_s2_pc",  smps,     SMPS_1500),
@@ -236,8 +246,12 @@
 {
 	int real_id = 0;
 
-	if (id >= RPM_VREG_ID_PM8038_L2_PC && id <= RPM_VREG_ID_PM8038_L15_PC)
+	if (id >= RPM_VREG_ID_PM8038_L2_PC && id <= RPM_VREG_ID_PM8038_L12_PC)
 		real_id = id - RPM_VREG_ID_PM8038_L2_PC;
+	else if (id >= RPM_VREG_ID_PM8038_L14_PC
+			&& id <= RPM_VREG_ID_PM8038_L15_PC)
+		real_id = id - RPM_VREG_ID_PM8038_L14_PC
+				+ RPM_VREG_ID_PM8038_L14;
 	else if (id >= RPM_VREG_ID_PM8038_L17_PC
 			&& id <= RPM_VREG_ID_PM8038_L18_PC)
 		real_id = id - RPM_VREG_ID_PM8038_L17_PC
diff --git a/arch/arm/mach-msm/rpm-regulator-8960.c b/arch/arm/mach-msm/rpm-regulator-8960.c
index 8726ed4..e75d730 100644
--- a/arch/arm/mach-msm/rpm-regulator-8960.c
+++ b/arch/arm/mach-msm/rpm-regulator-8960.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -106,7 +106,7 @@
 	&ncp_set_points,
 };
 
-#define LDO(_id, _name, _name_pc, _ranges, _hpm_min_load) \
+#define LDO(_id, _name, _name_pc, _ranges, _hpm_min_load, _requires_cxo) \
 	[RPM_VREG_ID_PM8921_##_id] = { \
 		.req = { \
 			[0] = { .id = MSM_RPM_ID_PM8921_##_id##_0, }, \
@@ -119,6 +119,7 @@
 		.id		 = RPM_VREG_ID_PM8921_##_id, \
 		.rdesc.name	 = _name, \
 		.rdesc_pc.name	 = _name_pc, \
+		.requires_cxo	 = _requires_cxo, \
 	}
 
 #define SMPS(_id, _name, _name_pc, _ranges, _hpm_min_load) \
@@ -177,32 +178,32 @@
 	}
 
 static struct vreg vregs[] = {
-	LDO(L1,   "8921_l1",   "8921_l1_pc",  nldo,     LDO_150),
-	LDO(L2,   "8921_l2",   "8921_l2_pc",  nldo,     LDO_150),
-	LDO(L3,   "8921_l3",   "8921_l3_pc",  pldo,     LDO_150),
-	LDO(L4,   "8921_l4",   "8921_l4_pc",  pldo,     LDO_50),
-	LDO(L5,   "8921_l5",   "8921_l5_pc",  pldo,     LDO_300),
-	LDO(L6,   "8921_l6",   "8921_l6_pc",  pldo,     LDO_600),
-	LDO(L7,   "8921_l7",   "8921_l7_pc",  pldo,     LDO_150),
-	LDO(L8,   "8921_l8",   "8921_l8_pc",  pldo,     LDO_300),
-	LDO(L9,   "8921_l9",   "8921_l9_pc",  pldo,     LDO_300),
-	LDO(L10,  "8921_l10",  "8921_l10_pc", pldo,     LDO_600),
-	LDO(L11,  "8921_l11",  "8921_l11_pc", pldo,     LDO_150),
-	LDO(L12,  "8921_l12",  "8921_l12_pc", nldo,     LDO_150),
-	LDO(L14,  "8921_l14",  "8921_l14_pc", pldo,     LDO_50),
-	LDO(L15,  "8921_l15",  "8921_l15_pc", pldo,     LDO_150),
-	LDO(L16,  "8921_l16",  "8921_l16_pc", pldo,     LDO_300),
-	LDO(L17,  "8921_l17",  "8921_l17_pc", pldo,     LDO_150),
-	LDO(L18,  "8921_l18",  "8921_l18_pc", nldo,     LDO_150),
-	LDO(L21,  "8921_l21",  "8921_l21_pc", pldo,     LDO_150),
-	LDO(L22,  "8921_l22",  "8921_l22_pc", pldo,     LDO_150),
-	LDO(L23,  "8921_l23",  "8921_l23_pc", pldo,     LDO_150),
-	LDO(L24,  "8921_l24",  NULL,          nldo1200, LDO_1200),
-	LDO(L25,  "8921_l25",  NULL,          nldo1200, LDO_1200),
-	LDO(L26,  "8921_l26",  NULL,          nldo1200, LDO_1200),
-	LDO(L27,  "8921_l27",  NULL,          nldo1200, LDO_1200),
-	LDO(L28,  "8921_l28",  NULL,          nldo1200, LDO_1200),
-	LDO(L29,  "8921_l29",  "8921_l29_pc", pldo,     LDO_150),
+	LDO(L1,   "8921_l1",   "8921_l1_pc",  nldo,     LDO_150,  1),
+	LDO(L2,   "8921_l2",   "8921_l2_pc",  nldo,     LDO_150,  1),
+	LDO(L3,   "8921_l3",   "8921_l3_pc",  pldo,     LDO_150,  0),
+	LDO(L4,   "8921_l4",   "8921_l4_pc",  pldo,     LDO_50,   0),
+	LDO(L5,   "8921_l5",   "8921_l5_pc",  pldo,     LDO_300,  0),
+	LDO(L6,   "8921_l6",   "8921_l6_pc",  pldo,     LDO_600,  0),
+	LDO(L7,   "8921_l7",   "8921_l7_pc",  pldo,     LDO_150,  0),
+	LDO(L8,   "8921_l8",   "8921_l8_pc",  pldo,     LDO_300,  0),
+	LDO(L9,   "8921_l9",   "8921_l9_pc",  pldo,     LDO_300,  0),
+	LDO(L10,  "8921_l10",  "8921_l10_pc", pldo,     LDO_600,  0),
+	LDO(L11,  "8921_l11",  "8921_l11_pc", pldo,     LDO_150,  0),
+	LDO(L12,  "8921_l12",  "8921_l12_pc", nldo,     LDO_150,  1),
+	LDO(L14,  "8921_l14",  "8921_l14_pc", pldo,     LDO_50,   0),
+	LDO(L15,  "8921_l15",  "8921_l15_pc", pldo,     LDO_150,  0),
+	LDO(L16,  "8921_l16",  "8921_l16_pc", pldo,     LDO_300,  0),
+	LDO(L17,  "8921_l17",  "8921_l17_pc", pldo,     LDO_150,  0),
+	LDO(L18,  "8921_l18",  "8921_l18_pc", nldo,     LDO_150,  1),
+	LDO(L21,  "8921_l21",  "8921_l21_pc", pldo,     LDO_150,  0),
+	LDO(L22,  "8921_l22",  "8921_l22_pc", pldo,     LDO_150,  0),
+	LDO(L23,  "8921_l23",  "8921_l23_pc", pldo,     LDO_150,  0),
+	LDO(L24,  "8921_l24",  NULL,          nldo1200, LDO_1200, 0),
+	LDO(L25,  "8921_l25",  NULL,          nldo1200, LDO_1200, 0),
+	LDO(L26,  "8921_l26",  NULL,          nldo1200, LDO_1200, 0),
+	LDO(L27,  "8921_l27",  NULL,          nldo1200, LDO_1200, 0),
+	LDO(L28,  "8921_l28",  NULL,          nldo1200, LDO_1200, 0),
+	LDO(L29,  "8921_l29",  "8921_l29_pc", pldo,     LDO_150,  0),
 
 	SMPS(S1,  "8921_s1",   "8921_s1_pc",  smps,     SMPS_1500),
 	SMPS(S2,  "8921_s2",   "8921_s2_pc",  smps,     SMPS_1500),
diff --git a/arch/arm/mach-msm/rpm-regulator-9615.c b/arch/arm/mach-msm/rpm-regulator-9615.c
index 82ac3d8..4abdc52 100644
--- a/arch/arm/mach-msm/rpm-regulator-9615.c
+++ b/arch/arm/mach-msm/rpm-regulator-9615.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -95,7 +95,7 @@
 	&corner_set_points,
 };
 
-#define LDO(_id, _name, _name_pc, _ranges, _hpm_min_load) \
+#define LDO(_id, _name, _name_pc, _ranges, _hpm_min_load, _requires_cxo) \
 	[RPM_VREG_ID_PM8018_##_id] = { \
 		.req = { \
 			[0] = { .id = MSM_RPM_ID_PM8018_##_id##_0, }, \
@@ -108,6 +108,7 @@
 		.id		 = RPM_VREG_ID_PM8018_##_id, \
 		.rdesc.name	 = _name, \
 		.rdesc_pc.name	 = _name_pc, \
+		.requires_cxo	 = _requires_cxo, \
 	}
 
 #define SMPS(_id, _name, _name_pc, _ranges, _hpm_min_load) \
@@ -152,19 +153,19 @@
 	}
 
 static struct vreg vregs[] = {
-	LDO(L2,   "8018_l2",   "8018_l2_pc",  pldo,     LDO_50),
-	LDO(L3,   "8018_l3",   "8018_l3_pc",  pldo,     LDO_50),
-	LDO(L4,   "8018_l4",   "8018_l4_pc",  pldo,     LDO_300),
-	LDO(L5,   "8018_l5",   "8018_l5_pc",  pldo,     LDO_150),
-	LDO(L6,   "8018_l6",   "8018_l6_pc",  pldo,     LDO_150),
-	LDO(L7,   "8018_l7",   "8018_l7_pc",  pldo,     LDO_300),
-	LDO(L8,   "8018_l8",   "8018_l8_pc",  nldo,     LDO_150),
-	LDO(L9,   "8018_l9",   NULL,          nldo1200, LDO_1200),
-	LDO(L10,  "8018_l10",  NULL,          nldo1200, LDO_1200),
-	LDO(L11,  "8018_l11",  NULL,          nldo1200, LDO_1200),
-	LDO(L12,  "8018_l12",  NULL,          nldo1200, LDO_1200),
-	LDO(L13,  "8018_l13",  "8018_l13_pc", pldo,     LDO_50),
-	LDO(L14,  "8018_l14",  "8018_l14_pc", pldo,     LDO_50),
+	LDO(L2,   "8018_l2",   "8018_l2_pc",  pldo,     LDO_50,   0),
+	LDO(L3,   "8018_l3",   "8018_l3_pc",  pldo,     LDO_50,   0),
+	LDO(L4,   "8018_l4",   "8018_l4_pc",  pldo,     LDO_300,  0),
+	LDO(L5,   "8018_l5",   "8018_l5_pc",  pldo,     LDO_150,  0),
+	LDO(L6,   "8018_l6",   "8018_l6_pc",  pldo,     LDO_150,  0),
+	LDO(L7,   "8018_l7",   "8018_l7_pc",  pldo,     LDO_300,  0),
+	LDO(L8,   "8018_l8",   "8018_l8_pc",  nldo,     LDO_150,  1),
+	LDO(L9,   "8018_l9",   NULL,          nldo1200, LDO_1200, 0),
+	LDO(L10,  "8018_l10",  NULL,          nldo1200, LDO_1200, 0),
+	LDO(L11,  "8018_l11",  NULL,          nldo1200, LDO_1200, 0),
+	LDO(L12,  "8018_l12",  NULL,          nldo1200, LDO_1200, 0),
+	LDO(L13,  "8018_l13",  "8018_l13_pc", pldo,     LDO_50,   0),
+	LDO(L14,  "8018_l14",  "8018_l14_pc", pldo,     LDO_50,   0),
 
 	SMPS(S1,  "8018_s1",   "8018_s1_pc",  smps,     SMPS_1500),
 	SMPS(S2,  "8018_s2",   "8018_s2_pc",  smps,     SMPS_1500),
diff --git a/arch/arm/mach-msm/rpm-regulator-private.h b/arch/arm/mach-msm/rpm-regulator-private.h
index d4f9a8a..c3ddc33 100644
--- a/arch/arm/mach-msm/rpm-regulator-private.h
+++ b/arch/arm/mach-msm/rpm-regulator-private.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -79,6 +79,7 @@
 	struct rpm_vreg_parts		*part;
 	int				type;
 	int				id;
+	bool				requires_cxo;
 	struct mutex			pc_lock;
 	int				save_uV;
 	int				mode;
diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c
index f663695..68ff55b 100644
--- a/arch/arm/mach-msm/rpm-regulator.c
+++ b/arch/arm/mach-msm/rpm-regulator.c
@@ -14,6 +14,7 @@
 #define pr_fmt(fmt) "%s: " fmt, __func__
 
 #include <linux/module.h>
+#include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -21,7 +22,10 @@
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/platform_device.h>
+#include <linux/wakelock.h>
+#include <linux/workqueue.h>
 #include <linux/regulator/driver.h>
+
 #include <mach/rpm.h>
 #include <mach/rpm-regulator.h>
 #include <mach/rpm-regulator-smd.h>
@@ -74,6 +78,11 @@
 	((_vreg->req[_vreg->part->_part.word].value & _vreg->part->_part.mask) \
 		>> _vreg->part->_part.shift)
 
+#define GET_PART_PREV_ACT(_vreg, _part) \
+	((_vreg->prev_active_req[_vreg->part->_part.word].value \
+	  & _vreg->part->_part.mask) \
+		>> _vreg->part->_part.shift)
+
 #define USES_PART(_vreg, _part) (_vreg->part->_part.mask)
 
 #define vreg_err(vreg, fmt, ...) \
@@ -287,6 +296,95 @@
 			vreg->req[0].id, vreg->req[0].value);
 }
 
+static bool requires_tcxo_workaround;
+static bool tcxo_workaround_noirq;
+static struct clk *tcxo_handle;
+static struct wake_lock tcxo_wake_lock;
+static DEFINE_MUTEX(tcxo_mutex);
+/* Spin lock needed for sleep-selectable regulators. */
+static DEFINE_SPINLOCK(tcxo_noirq_lock);
+static bool tcxo_is_enabled;
+/*
+ * TCXO must be kept on for at least the duration of its warmup (4 ms);
+ * otherwise, it will stay on when hardware disabling is attempted.
+ */
+#define TCXO_WARMUP_TIME_MS 4
+
+static void tcxo_get_handle(void)
+{
+	int rc;
+
+	if (!tcxo_handle) {
+		tcxo_handle = clk_get_sys("rpm-regulator", "vref_buff");
+		if (IS_ERR(tcxo_handle)) {
+			tcxo_handle = NULL;
+		} else {
+			rc = clk_prepare(tcxo_handle);
+			if (rc) {
+				clk_put(tcxo_handle);
+				tcxo_handle = NULL;
+			}
+		}
+	}
+}
+
+/*
+ * Perform best effort enable of CXO.  Since the MSM clock drivers depend upon
+ * the rpm-regulator driver, any rpm-regulator devices that are configured with
+ * always_on == 1 will not be able to enable CXO during probe.  This does not
+ * cause a problem though since CXO will be enabled by the boot loaders before
+ * Apps boots up.
+ */
+static bool tcxo_enable(void)
+{
+	int rc;
+
+	if (tcxo_handle && !tcxo_is_enabled) {
+		rc = clk_enable(tcxo_handle);
+		if (!rc) {
+			tcxo_is_enabled = true;
+			wake_lock(&tcxo_wake_lock);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+static void tcxo_delayed_disable_work(struct work_struct *work)
+{
+	unsigned long flags = 0;
+
+	if (tcxo_workaround_noirq)
+		spin_lock_irqsave(&tcxo_noirq_lock, flags);
+	else
+		mutex_lock(&tcxo_mutex);
+
+	clk_disable(tcxo_handle);
+	tcxo_is_enabled = false;
+	wake_unlock(&tcxo_wake_lock);
+
+	if (tcxo_workaround_noirq)
+		spin_unlock_irqrestore(&tcxo_noirq_lock, flags);
+	else
+		mutex_unlock(&tcxo_mutex);
+}
+
+static DECLARE_DELAYED_WORK(tcxo_disable_work, tcxo_delayed_disable_work);
+
+static void tcxo_delayed_disable(void)
+{
+	/*
+	 * The delay in jiffies has 1 added to it to ensure that at least
+	 * one jiffy takes place before the work is enqueued.  Without this,
+	 * the work would be scheduled to run in the very next jiffy which could
+	 * result in too little delay and TCXO being stuck on.
+	 */
+	if (tcxo_handle)
+		schedule_delayed_work(&tcxo_disable_work,
+				msecs_to_jiffies(TCXO_WARMUP_TIME_MS) + 1);
+}
+
 /* Spin lock needed for sleep-selectable regulators. */
 static DEFINE_SPINLOCK(rpm_noirq_lock);
 
@@ -321,6 +419,9 @@
 {
 	struct msm_rpm_iv_pair *prev_req;
 	int rc = 0, max_uV_vote = 0;
+	unsigned long flags = 0;
+	bool tcxo_enabled = false;
+	bool voltage_increased = false;
 	unsigned prev0, prev1;
 	int *min_uV_vote;
 	int i;
@@ -362,6 +463,16 @@
 	/* Ignore duplicate requests */
 	if (vreg->req[0].value != prev_req[0].value ||
 	    vreg->req[1].value != prev_req[1].value) {
+
+		/* Enable CXO clock if necessary for TCXO workaround. */
+		if (requires_tcxo_workaround && vreg->requires_cxo
+		    && (set == MSM_RPM_CTX_SET_0)
+		    && (GET_PART(vreg, uV) > GET_PART_PREV_ACT(vreg, uV))) {
+			voltage_increased = true;
+			spin_lock_irqsave(&tcxo_noirq_lock, flags);
+			tcxo_enabled = tcxo_enable();
+		}
+
 		rc = msm_rpmrs_set_noirq(set, vreg->req, cnt);
 		if (rc) {
 			vreg->req[0].value = prev0;
@@ -381,6 +492,16 @@
 			prev_req[0].value = vreg->req[0].value;
 			prev_req[1].value = vreg->req[1].value;
 		}
+
+		/*
+		 * Schedule CXO clock to be disabled after TCXO warmup time if
+		 * TCXO workaround is applicable for this regulator.
+		 */
+		if (voltage_increased) {
+			if (tcxo_enabled)
+				tcxo_delayed_disable();
+			spin_unlock_irqrestore(&tcxo_noirq_lock, flags);
+		}
 	} else if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_DUPLICATE) {
 		rpm_regulator_duplicate(vreg, set, cnt);
 	}
@@ -916,6 +1037,9 @@
 		unsigned mask1, unsigned val1, unsigned cnt)
 {
 	unsigned prev0 = 0, prev1 = 0;
+	unsigned long flags = 0;
+	bool tcxo_enabled = false;
+	bool voltage_increased = false;
 	int rc;
 
 	/*
@@ -942,7 +1066,25 @@
 		return 0;
 	}
 
-	rc = msm_rpm_set(MSM_RPM_CTX_SET_0, vreg->req, cnt);
+	/* Enable CXO clock if necessary for TCXO workaround. */
+	if (requires_tcxo_workaround && vreg->requires_cxo
+	    && (GET_PART(vreg, uV) > GET_PART_PREV_ACT(vreg, uV))) {
+		if (!tcxo_handle)
+			tcxo_get_handle();
+		if (tcxo_workaround_noirq)
+			spin_lock_irqsave(&tcxo_noirq_lock, flags);
+		else
+			mutex_lock(&tcxo_mutex);
+
+		voltage_increased = true;
+		tcxo_enabled = tcxo_enable();
+	}
+
+	if (voltage_increased && tcxo_workaround_noirq)
+		rc = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_0, vreg->req, cnt);
+	else
+		rc = msm_rpm_set(MSM_RPM_CTX_SET_0, vreg->req, cnt);
+
 	if (rc) {
 		vreg->req[0].value = prev0;
 		vreg->req[1].value = prev1;
@@ -956,6 +1098,20 @@
 		vreg->prev_active_req[1].value = vreg->req[1].value;
 	}
 
+	/*
+	 * Schedule CXO clock to be disabled after TCXO warmup time if TCXO
+	 * workaround is applicable for this regulator.
+	 */
+	if (voltage_increased) {
+		if (tcxo_enabled)
+			tcxo_delayed_disable();
+
+		if (tcxo_workaround_noirq)
+			spin_unlock_irqrestore(&tcxo_noirq_lock, flags);
+		else
+			mutex_unlock(&tcxo_mutex);
+	}
+
 	return rc;
 }
 
@@ -1470,6 +1626,20 @@
 	[RPM_REGULATOR_TYPE_CORNER]	= &corner_ops,
 };
 
+static struct vreg *rpm_vreg_get_vreg(int id)
+{
+	struct vreg *vreg;
+
+	if (id < config->vreg_id_min || id > config->vreg_id_max)
+		return NULL;
+
+	if (!config->is_real_id(id))
+		id = config->pc_id_to_real_id(id);
+	vreg = &config->vregs[id];
+
+	return vreg;
+}
+
 static int __devinit
 rpm_vreg_init_regulator(const struct rpm_regulator_init_data *pdata,
 			struct device *dev)
@@ -1478,7 +1648,7 @@
 	struct regulator_dev *rdev;
 	struct vreg *vreg;
 	unsigned pin_ctrl;
-	int id, pin_fn;
+	int pin_fn;
 	int rc = 0;
 
 	if (!pdata) {
@@ -1486,17 +1656,12 @@
 		return -EINVAL;
 	}
 
-	id = pdata->id;
-
-	if (id < config->vreg_id_min || id > config->vreg_id_max) {
-		pr_err("invalid regulator id: %d\n", id);
+	vreg = rpm_vreg_get_vreg(pdata->id);
+	if (!vreg) {
+		pr_err("invalid regulator id: %d\n", pdata->id);
 		return -ENODEV;
 	}
 
-	if (!config->is_real_id(pdata->id))
-		id = config->pc_id_to_real_id(pdata->id);
-	vreg = &config->vregs[id];
-
 	if (config->is_real_id(pdata->id))
 		rdesc = &vreg->rdesc;
 	else
@@ -1627,6 +1792,7 @@
 	struct rpm_regulator_platform_data *platform_data;
 	static struct rpm_regulator_consumer_mapping *prev_consumer_map;
 	static int prev_consumer_map_len;
+	struct vreg *vreg;
 	int rc = 0;
 	int i, id;
 
@@ -1705,6 +1871,25 @@
 
 	}
 
+	if (platform_data->requires_tcxo_workaround
+	    && !requires_tcxo_workaround) {
+		requires_tcxo_workaround = true;
+		wake_lock_init(&tcxo_wake_lock, WAKE_LOCK_SUSPEND,
+				"rpm_regulator_tcxo");
+	}
+
+	if (requires_tcxo_workaround && !tcxo_workaround_noirq) {
+		for (i = 0; i < platform_data->num_regulators; i++) {
+			vreg = rpm_vreg_get_vreg(
+					platform_data->init_data[i].id);
+			if (vreg && vreg->requires_cxo
+			    && platform_data->init_data[i].sleep_selectable) {
+				tcxo_workaround_noirq = true;
+				break;
+			}
+		}
+	}
+
 	/* Initialize all of the regulators listed in the platform data. */
 	for (i = 0; i < platform_data->num_regulators; i++) {
 		rc = rpm_vreg_init_regulator(&platform_data->init_data[i],
@@ -1785,6 +1970,9 @@
 
 	for (i = 0; i < config->vregs_len; i++)
 		mutex_destroy(&config->vregs[i].pc_lock);
+
+	if (tcxo_handle)
+		clk_put(tcxo_handle);
 }
 
 postcore_initcall(rpm_vreg_init);
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 0faafc8c..1225fec 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -64,7 +64,8 @@
 #define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_KERNEL)
 #define INV_HDR "resource does not exist"
 #define ERR "err\0"
-#define MAX_ERR_BUFFER_SIZE 60
+#define MAX_ERR_BUFFER_SIZE 128
+#define INIT_ERROR 1
 
 static ATOMIC_NOTIFIER_HEAD(msm_rpm_sleep_notifier);
 static bool standalone;
@@ -388,6 +389,7 @@
 	init_completion(&data->ack);
 	data->ack_recd = false;
 	data->msg_id = msg_id;
+	data->errno = INIT_ERROR;
 	spin_lock_irqsave(&msm_rpm_list_lock, flags);
 	list_add(&data->list, &msm_rpm_wait_list);
 	spin_unlock_irqrestore(&msm_rpm_list_lock, flags);
@@ -463,7 +465,7 @@
 	return rc;
 }
 
-static void msm_rpm_read_smd_data(char *buf)
+static int msm_rpm_read_smd_data(char *buf)
 {
 	int pkt_sz;
 	int bytes_read = 0;
@@ -473,7 +475,7 @@
 	BUG_ON(pkt_sz > MAX_ERR_BUFFER_SIZE);
 
 	if (pkt_sz != smd_read_avail(msm_rpm_data.ch_info))
-		return;
+		return -EAGAIN;
 
 	BUG_ON(pkt_sz == 0);
 
@@ -487,6 +489,8 @@
 	} while (pkt_sz > 0);
 
 	BUG_ON(pkt_sz < 0);
+
+	return 0;
 }
 
 static void msm_rpm_smd_work(struct work_struct *work)
@@ -498,11 +502,15 @@
 
 	while (smd_is_pkt_avail(msm_rpm_data.ch_info) && !irq_process) {
 		spin_lock_irqsave(&msm_rpm_data.smd_lock_read, flags);
-		msm_rpm_read_smd_data(buf);
-		spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read, flags);
+		if (msm_rpm_read_smd_data(buf)) {
+			spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read,
+					flags);
+			break;
+		}
 		msg_id = msm_rpm_get_msg_id_from_ack(buf);
 		errno = msm_rpm_get_error_from_ack(buf);
 		msm_rpm_process_ack(msg_id, errno);
+		spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read, flags);
 	}
 }
 
@@ -814,6 +822,12 @@
 		 */
 		goto wait_ack_cleanup;
 
+	if (elem->errno != INIT_ERROR) {
+		rc = elem->errno;
+		msm_rpm_free_list_entry(elem);
+		goto wait_ack_cleanup;
+	}
+
 	while ((id != msg_id) && (count++ < 10)) {
 		if (smd_is_pkt_avail(msm_rpm_data.ch_info)) {
 			int errno;
diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c
index 4096d9c..55ae2f8 100644
--- a/arch/arm/mach-msm/scm-pas.c
+++ b/arch/arm/mach-msm/scm-pas.c
@@ -94,7 +94,7 @@
 {
 	int ret = 0;
 
-	if (!scm_perf_client || !scm_bus_clk)
+	if (!scm_perf_client)
 		return -EINVAL;
 
 	mutex_lock(&scm_pas_bw_mutex);
@@ -102,7 +102,7 @@
 		ret = msm_bus_scale_client_update_request(scm_perf_client, 1);
 		if (ret) {
 			pr_err("bandwidth request failed (%d)\n", ret);
-		} else {
+		} else if (scm_bus_clk) {
 			ret = clk_prepare_enable(scm_bus_clk);
 			if (ret)
 				pr_err("clock enable failed\n");
@@ -121,7 +121,8 @@
 	mutex_lock(&scm_pas_bw_mutex);
 	if (scm_pas_bw_count-- == 1) {
 		msm_bus_scale_client_update_request(scm_perf_client, 0);
-		clk_disable_unprepare(scm_bus_clk);
+		if (scm_bus_clk)
+			clk_disable_unprepare(scm_bus_clk);
 	}
 	mutex_unlock(&scm_pas_bw_mutex);
 }
@@ -190,16 +191,23 @@
 
 static int __init scm_pas_init(void)
 {
+	if (cpu_is_msm8974()) {
+		scm_pas_bw_tbl[0].vectors[0].src = MSM_BUS_MASTER_CRYPTO_CORE0;
+		scm_pas_bw_tbl[1].vectors[0].src = MSM_BUS_MASTER_CRYPTO_CORE0;
+	} else {
+		scm_bus_clk = clk_get_sys("scm", "bus_clk");
+		if (!IS_ERR(scm_bus_clk)) {
+			clk_set_rate(scm_bus_clk, 64000000);
+		} else {
+			scm_bus_clk = NULL;
+			pr_warn("unable to get bus clock\n");
+		}
+	}
+
 	scm_perf_client = msm_bus_scale_register_client(&scm_pas_bus_pdata);
 	if (!scm_perf_client)
 		pr_warn("unable to register bus client\n");
-	scm_bus_clk = clk_get_sys("scm", "bus_clk");
-	if (!IS_ERR(scm_bus_clk)) {
-		clk_set_rate(scm_bus_clk, 64000000);
-	} else {
-		scm_bus_clk = NULL;
-		pr_warn("unable to get bus clock\n");
-	}
+
 	return 0;
 }
 module_init(scm_pas_init);
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index decee95..e82e44b 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -2264,13 +2264,17 @@
 
 int smd_is_pkt_avail(smd_channel_t *ch)
 {
+	unsigned long flags;
+
 	if (!ch || !ch->is_pkt_ch)
 		return -EINVAL;
 
 	if (ch->current_packet)
 		return 1;
 
+	spin_lock_irqsave(&smd_lock, flags);
 	update_packet_state(ch);
+	spin_unlock_irqrestore(&smd_lock, flags);
 
 	return ch->current_packet ? 1 : 0;
 }
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 6d73e1d..9c3b6bd 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -63,7 +63,7 @@
 	char wlname[64];
 	struct work_struct work;
 	spinlock_t restart_lock;
-	bool restarting;
+	int restart_count;
 
 	void *notify;
 
@@ -438,8 +438,9 @@
 
 out:
 	spin_lock_irqsave(&dev->restart_lock, flags);
-	wake_unlock(&dev->wake_lock);
-	dev->restarting = false;
+	dev->restart_count--;
+	if (!dev->restart_count)
+		wake_unlock(&dev->wake_lock);
 	spin_unlock_irqrestore(&dev->restart_lock, flags);
 }
 
@@ -448,16 +449,21 @@
 	struct subsys_desc *desc = dev->desc;
 	unsigned long flags;
 
-	spin_lock_irqsave(&dev->restart_lock, flags);
-	if (!dev->restarting) {
-		pr_debug("Restarting %s [level=%d]!\n", desc->name,
-				restart_level);
+	pr_debug("Restarting %s [level=%d]!\n", desc->name, restart_level);
 
-		dev->restarting = true;
+	spin_lock_irqsave(&dev->restart_lock, flags);
+	if (!dev->restart_count)
 		wake_lock(&dev->wake_lock);
-		queue_work(ssr_wq, &dev->work);
-	}
+	dev->restart_count++;
 	spin_unlock_irqrestore(&dev->restart_lock, flags);
+
+	if (!queue_work(ssr_wq, &dev->work)) {
+		spin_lock_irqsave(&dev->restart_lock, flags);
+		dev->restart_count--;
+		if (!dev->restart_count)
+			wake_unlock(&dev->wake_lock);
+		spin_unlock_irqrestore(&dev->restart_lock, flags);
+	}
 }
 
 int subsystem_restart_dev(struct subsys_device *dev)
diff --git a/arch/arm/mach-msm/timer.h b/arch/arm/mach-msm/timer.h
index 5d18bb4..ebe1819 100644
--- a/arch/arm/mach-msm/timer.h
+++ b/arch/arm/mach-msm/timer.h
@@ -16,10 +16,10 @@
 
 extern struct sys_timer msm_timer;
 
-void __iomem *msm_timer_get_timer0_base(void);
 uint32_t msm_timer_get_sclk_ticks(void);
 int msm_timer_init_time_sync(void (*timeout)(void));
 #ifndef CONFIG_ARM_ARCH_TIMER
+void __iomem *msm_timer_get_timer0_base(void);
 int64_t msm_timer_enter_idle(void);
 void msm_timer_exit_idle(int low_power);
 int64_t msm_timer_get_sclk_time(int64_t *period);
@@ -27,5 +27,6 @@
 static inline int64_t msm_timer_enter_idle(void) { return 0; }
 static inline void msm_timer_exit_idle(int low_power) { return; }
 static inline int64_t msm_timer_get_sclk_time(int64_t *period) { return 0; }
+static inline void __iomem *msm_timer_get_timer0_base(void) { return NULL; }
 #endif
 #endif
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index 318523b..cbf1d72 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -180,8 +180,13 @@
 static void riva_crash_shutdown(const struct subsys_desc *subsys)
 {
 	pr_err("%s: crash shutdown : %d\n", MODULE_NAME, riva_crash);
-	if (riva_crash != true)
+	if (riva_crash != true) {
 		smsm_riva_reset();
+		/* give sufficient time for wcnss to finish it's error
+		 * fatal routine */
+		msleep(3000);
+	}
+
 }
 
 static struct subsys_desc riva_8960 = {
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index b1911c4..553bece 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -181,14 +181,14 @@
 
 		pud = pud_alloc(&init_mm, pgd, base);
 		if (!pud) {
-			printk(KERN_ERR "%s: no pud tables\n", __func__);
+			pr_err("%s: no pud tables\n", __func__);
 			ret = -ENOMEM;
 			break;
 		}
 
 		pmd = pmd_alloc(&init_mm, pud, base);
 		if (!pmd) {
-			printk(KERN_ERR "%s: no pmd tables\n", __func__);
+			pr_err("%s: no pmd tables\n", __func__);
 			ret = -ENOMEM;
 			break;
 		}
@@ -196,7 +196,7 @@
 
 		pte = pte_alloc_kernel(pmd, base);
 		if (!pte) {
-			printk(KERN_ERR "%s: no pte tables\n", __func__);
+			pr_err("%s: no pte tables\n", __func__);
 			ret = -ENOMEM;
 			break;
 		}
@@ -311,7 +311,7 @@
 	int bit;
 
 	if (!consistent_pte) {
-		printk(KERN_ERR "%s: not initialised\n", __func__);
+		pr_err("%s: not initialised\n", __func__);
 		dump_stack();
 		return NULL;
 	}
@@ -370,14 +370,14 @@
 
 	c = arm_vmregion_find_remove(&consistent_head, (unsigned long)cpu_addr);
 	if (!c) {
-		printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n",
+		pr_err("%s: trying to free invalid coherent area: %p\n",
 		       __func__, cpu_addr);
 		dump_stack();
 		return;
 	}
 
 	if ((c->vm_end - c->vm_start) != size) {
-		printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n",
+		pr_err("%s: freeing wrong coherent size (%ld != %d)\n",
 		       __func__, c->vm_end - c->vm_start, size);
 		dump_stack();
 		size = c->vm_end - c->vm_start;
@@ -399,8 +399,8 @@
 		}
 
 		if (pte_none(pte) || !pte_present(pte))
-			printk(KERN_CRIT "%s: bad page in kernel page table\n",
-			       __func__);
+			pr_crit("%s: bad page in kernel page table\n",
+				__func__);
 	} while (size -= PAGE_SIZE);
 
 	flush_tlb_kernel_range(c->vm_start, c->vm_end);
@@ -584,7 +584,7 @@
 	 */
 	gfp &= ~(__GFP_COMP);
 
-	*handle = ~0;
+	*handle = DMA_ERROR_CODE;
 	size = PAGE_ALIGN(size);
 
 	if (arch_is_coherent() || nommu())
@@ -639,6 +639,10 @@
 	int ret = -ENXIO;
 #ifdef CONFIG_MMU
 	unsigned long pfn = dma_to_pfn(dev, dma_addr);
+
+	if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
+		return ret;
+
 	ret = remap_pfn_range(vma, vma->vm_start,
 			      pfn + vma->vm_pgoff,
 			      vma->vm_end - vma->vm_start,
@@ -898,7 +902,7 @@
 	int i;
 
 	for_each_sg(sg, s, nents, i) {
-		if (!dmabounce_sync_for_cpu(dev, sg_dma_address(s), 0,
+		if (!dmabounce_sync_for_cpu(dev, sg_dma_address(s),
 					    sg_dma_len(s), dir))
 			continue;
 
@@ -924,7 +928,7 @@
 	int i;
 
 	for_each_sg(sg, s, nents, i) {
-		if (!dmabounce_sync_for_device(dev, sg_dma_address(s), 0,
+		if (!dmabounce_sync_for_device(dev, sg_dma_address(s),
 					sg_dma_len(s), dir))
 			continue;
 
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index b6fb52a..57f41ca 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -250,8 +250,8 @@
 #endif
 }
 
-#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
-static void __init arm_bootmem_free_apnm(unsigned long max_low,
+#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
+static void __init arm_bootmem_free_hmnm(unsigned long max_low,
 	unsigned long max_high)
 {
 	unsigned long max_zone_pfns[MAX_NR_ZONES];
@@ -267,7 +267,7 @@
 		unsigned long start = memblock_region_memory_base_pfn(reg);
 		unsigned long end = memblock_region_memory_end_pfn(reg);
 
-		add_active_range(0, start, end);
+		memblock_set_node(PFN_PHYS(start), PFN_PHYS(end - start), 0);
 	}
 	free_area_init_nodes(max_zone_pfns);
 }
@@ -491,8 +491,8 @@
 	 */
 	sparse_init();
 
-#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
-	arm_bootmem_free_apnm(max_low, max_high);
+#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
+	arm_bootmem_free_hmnm(max_low, max_high);
 #else
 	/*
 	 * Now free the memory - free_area_init_node needs
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
index ce8cb19..06262c5 100644
--- a/arch/arm/mm/mmap.c
+++ b/arch/arm/mm/mmap.c
@@ -11,49 +11,10 @@
 #include <linux/random.h>
 #include <asm/cachetype.h>
 
-static inline unsigned long COLOUR_ALIGN_DOWN(unsigned long addr,
-					      unsigned long pgoff)
-{
-	unsigned long base = addr & ~(SHMLBA-1);
-	unsigned long off = (pgoff << PAGE_SHIFT) & (SHMLBA-1);
-
-	if (base + off <= addr)
-		return base + off;
-
-	return base - off;
-}
-
 #define COLOUR_ALIGN(addr,pgoff)		\
 	((((addr)+SHMLBA-1)&~(SHMLBA-1)) +	\
 	 (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1)))
 
-/* gap between mmap and stack */
-#define MIN_GAP (128*1024*1024UL)
-#define MAX_GAP ((TASK_SIZE)/6*5)
-
-static int mmap_is_legacy(void)
-{
-	if (current->personality & ADDR_COMPAT_LAYOUT)
-		return 1;
-
-	if (rlimit(RLIMIT_STACK) == RLIM_INFINITY)
-		return 1;
-
-	return sysctl_legacy_va_layout;
-}
-
-static unsigned long mmap_base(unsigned long rnd)
-{
-	unsigned long gap = rlimit(RLIMIT_STACK);
-
-	if (gap < MIN_GAP)
-		gap = MIN_GAP;
-	else if (gap > MAX_GAP)
-		gap = MAX_GAP;
-
-	return PAGE_ALIGN(TASK_SIZE - gap - rnd);
-}
-
 /*
  * We need to ensure that shared mappings are correctly aligned to
  * avoid aliasing issues with VIPT caches.  We need to ensure that
@@ -107,9 +68,13 @@
 	if (len > mm->cached_hole_size) {
 	        start_addr = addr = mm->free_area_cache;
 	} else {
-	        start_addr = addr = mm->mmap_base;
+		start_addr = addr = TASK_UNMAPPED_BASE;
 	        mm->cached_hole_size = 0;
 	}
+	/* 8 bits of randomness in 20 address space bits */
+	if ((current->flags & PF_RANDOMIZE) &&
+	    !(current->personality & ADDR_NO_RANDOMIZE))
+		addr += (get_random_int() % (1 << 8)) << PAGE_SHIFT;
 
 full_search:
 	if (do_align)
@@ -146,134 +111,6 @@
 	}
 }
 
-unsigned long
-arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
-			const unsigned long len, const unsigned long pgoff,
-			const unsigned long flags)
-{
-	struct vm_area_struct *vma;
-	struct mm_struct *mm = current->mm;
-	unsigned long addr = addr0;
-	int do_align = 0;
-	int aliasing = cache_is_vipt_aliasing();
-
-	/*
-	 * We only need to do colour alignment if either the I or D
-	 * caches alias.
-	 */
-	if (aliasing)
-		do_align = filp || (flags & MAP_SHARED);
-
-	/* requested length too big for entire address space */
-	if (len > TASK_SIZE)
-		return -ENOMEM;
-
-	if (flags & MAP_FIXED) {
-		if (aliasing && flags & MAP_SHARED &&
-		    (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
-			return -EINVAL;
-		return addr;
-	}
-
-	/* requesting a specific address */
-	if (addr) {
-		if (do_align)
-			addr = COLOUR_ALIGN(addr, pgoff);
-		else
-			addr = PAGE_ALIGN(addr);
-		vma = find_vma(mm, addr);
-		if (TASK_SIZE - len >= addr &&
-				(!vma || addr + len <= vma->vm_start))
-			return addr;
-	}
-
-	/* check if free_area_cache is useful for us */
-	if (len <= mm->cached_hole_size) {
-		mm->cached_hole_size = 0;
-		mm->free_area_cache = mm->mmap_base;
-	}
-
-	/* either no address requested or can't fit in requested address hole */
-	addr = mm->free_area_cache;
-	if (do_align) {
-		unsigned long base = COLOUR_ALIGN_DOWN(addr - len, pgoff);
-		addr = base + len;
-	}
-
-	/* make sure it can fit in the remaining address space */
-	if (addr > len) {
-		vma = find_vma(mm, addr-len);
-		if (!vma || addr <= vma->vm_start)
-			/* remember the address as a hint for next time */
-			return (mm->free_area_cache = addr-len);
-	}
-
-	if (mm->mmap_base < len)
-		goto bottomup;
-
-	addr = mm->mmap_base - len;
-	if (do_align)
-		addr = COLOUR_ALIGN_DOWN(addr, pgoff);
-
-	do {
-		/*
-		 * Lookup failure means no vma is above this address,
-		 * else if new region fits below vma->vm_start,
-		 * return with success:
-		 */
-		vma = find_vma(mm, addr);
-		if (!vma || addr+len <= vma->vm_start)
-			/* remember the address as a hint for next time */
-			return (mm->free_area_cache = addr);
-
-		/* remember the largest hole we saw so far */
-		if (addr + mm->cached_hole_size < vma->vm_start)
-			mm->cached_hole_size = vma->vm_start - addr;
-
-		/* try just below the current vma->vm_start */
-		addr = vma->vm_start - len;
-		if (do_align)
-			addr = COLOUR_ALIGN_DOWN(addr, pgoff);
-	} while (len < vma->vm_start);
-
-bottomup:
-	/*
-	 * A failed mmap() very likely causes application failure,
-	 * so fall back to the bottom-up function here. This scenario
-	 * can happen with large stack limits and large mmap()
-	 * allocations.
-	 */
-	mm->cached_hole_size = ~0UL;
-	mm->free_area_cache = TASK_UNMAPPED_BASE;
-	addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
-	/*
-	 * Restore the topdown base:
-	 */
-	mm->free_area_cache = mm->mmap_base;
-	mm->cached_hole_size = ~0UL;
-
-	return addr;
-}
-
-void arch_pick_mmap_layout(struct mm_struct *mm)
-{
-	unsigned long random_factor = 0UL;
-
-	/* 8 bits of randomness in 20 address space bits */
-	if ((current->flags & PF_RANDOMIZE) &&
-	    !(current->personality & ADDR_NO_RANDOMIZE))
-		random_factor = (get_random_int() % (1 << 8)) << PAGE_SHIFT;
-
-	if (mmap_is_legacy()) {
-		mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
-		mm->get_unmapped_area = arch_get_unmapped_area;
-		mm->unmap_area = arch_unmap_area;
-	} else {
-		mm->mmap_base = mmap_base(random_factor);
-		mm->get_unmapped_area = arch_get_unmapped_area_topdown;
-		mm->unmap_area = arch_unmap_area_topdown;
-	}
-}
 
 /*
  * You really shouldn't be using read() or write() on /dev/mem.  This
diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c
index bb0025c..1b85949 100644
--- a/drivers/base/dma-coherent.c
+++ b/drivers/base/dma-coherent.c
@@ -10,6 +10,7 @@
 struct dma_coherent_mem {
 	void		*virt_base;
 	dma_addr_t	device_base;
+	phys_addr_t	pfn_base;
 	int		size;
 	int		flags;
 	unsigned long	*bitmap;
@@ -44,6 +45,7 @@
 
 	dev->dma_mem->virt_base = mem_base;
 	dev->dma_mem->device_base = device_addr;
+	dev->dma_mem->pfn_base = PFN_DOWN(bus_addr);
 	dev->dma_mem->size = pages;
 	dev->dma_mem->flags = flags;
 
@@ -176,3 +178,43 @@
 	return 0;
 }
 EXPORT_SYMBOL(dma_release_from_coherent);
+
+/**
+ * dma_mmap_from_coherent() - try to mmap the memory allocated from
+ * per-device coherent memory pool to userspace
+ * @dev:	device from which the memory was allocated
+ * @vma:	vm_area for the userspace memory
+ * @vaddr:	cpu address returned by dma_alloc_from_coherent
+ * @size:	size of the memory buffer allocated by dma_alloc_from_coherent
+ *
+ * This checks whether the memory was allocated from the per-device
+ * coherent memory pool and if so, maps that memory to the provided vma.
+ *
+ * Returns 1 if we correctly mapped the memory, or 0 if
+ * dma_release_coherent() should proceed with mapping memory from
+ * generic pools.
+ */
+int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
+			   void *vaddr, size_t size, int *ret)
+{
+	struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
+
+	if (mem && vaddr >= mem->virt_base && vaddr + size <=
+		   (mem->virt_base + (mem->size << PAGE_SHIFT))) {
+		unsigned long off = vma->vm_pgoff;
+		int start = (vaddr - mem->virt_base) >> PAGE_SHIFT;
+		int user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+		int count = size >> PAGE_SHIFT;
+
+		*ret = -ENXIO;
+		if (off < count && user_count <= count - off) {
+			unsigned pfn = mem->pfn_base + start + off;
+			*ret = remap_pfn_range(vma, vma->vm_start, pfn,
+					       user_count << PAGE_SHIFT,
+					       vma->vm_page_prot);
+		}
+		return 1;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(dma_mmap_from_coherent);
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index 4093935..cfcacff 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -5,6 +5,7 @@
  *  power management protocol extension to H4 to support AR300x Bluetooth Chip.
  *
  *  Copyright (c) 2009-2010 Atheros Communications Inc.
+ *  Copyright (c) 2012, Code Aurora Forum. All rights reserved.
  *
  *  Acknowledgements:
  *  This file is based on hci_h4.c, which was written
@@ -35,12 +36,53 @@
 #include <linux/errno.h>
 #include <linux/ioctl.h>
 #include <linux/skbuff.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
 #include "hci_uart.h"
 
+unsigned int enableuartsleep = 1;
+module_param(enableuartsleep, uint, 0644);
+/*
+ * Global variables
+ */
+/** Global state flags */
+static unsigned long flags;
+
+/** Tasklet to respond to change in hostwake line */
+static struct tasklet_struct hostwake_task;
+
+/** Transmission timer */
+static void bluesleep_tx_timer_expire(unsigned long data);
+static DEFINE_TIMER(tx_timer, bluesleep_tx_timer_expire, 0, 0);
+
+/** Lock for state transitions */
+static spinlock_t rw_lock;
+
+#define POLARITY_LOW 0
+#define POLARITY_HIGH 1
+
+struct bluesleep_info {
+	unsigned host_wake;			/* wake up host */
+	unsigned ext_wake;			/* wake up device */
+	unsigned host_wake_irq;
+	int irq_polarity;
+};
+
+/* 1 second timeout */
+#define TX_TIMER_INTERVAL  1
+
+/* state variable names and bit positions */
+#define BT_TXEXPIRED    0x01
+#define BT_SLEEPENABLE  0x02
+#define BT_SLEEPCMD	0x03
+
+/* global pointer to a single hci device. */
+static struct bluesleep_info *bsi;
+
 struct ath_struct {
 	struct hci_uart *hu;
 	unsigned int cur_sleep;
@@ -49,35 +91,30 @@
 	struct work_struct ctxtsw;
 };
 
+static void hostwake_interrupt(unsigned long data)
+{
+	printk(KERN_INFO " wakeup host\n");
+}
+
+static void modify_timer_task(void)
+{
+	spin_lock(&rw_lock);
+	mod_timer(&tx_timer, jiffies + (TX_TIMER_INTERVAL * HZ));
+	clear_bit(BT_TXEXPIRED, &flags);
+	spin_unlock(&rw_lock);
+
+}
+
 static int ath_wakeup_ar3k(struct tty_struct *tty)
 {
-	struct ktermios ktermios;
-	int status = tty->driver->ops->tiocmget(tty);
-
-	if (status & TIOCM_CTS)
-		return status;
-
-	/* Disable Automatic RTSCTS */
-	memcpy(&ktermios, tty->termios, sizeof(ktermios));
-	ktermios.c_cflag &= ~CRTSCTS;
-	tty_set_termios(tty, &ktermios);
-
-	/* Clear RTS first */
-	status = tty->driver->ops->tiocmget(tty);
-	tty->driver->ops->tiocmset(tty, 0x00, TIOCM_RTS);
-	mdelay(20);
-
-	/* Set RTS, wake up board */
-	status = tty->driver->ops->tiocmget(tty);
-	tty->driver->ops->tiocmset(tty, TIOCM_RTS, 0x00);
-	mdelay(20);
-
-	status = tty->driver->ops->tiocmget(tty);
-
-	/* Disable Automatic RTSCTS */
-	ktermios.c_cflag |= CRTSCTS;
-	status = tty_set_termios(tty, &ktermios);
-
+	int status = 0;
+	if (test_bit(BT_TXEXPIRED, &flags)) {
+		printk(KERN_INFO "wakeup device\n");
+		gpio_set_value(bsi->ext_wake, 0);
+		msleep(20);
+		gpio_set_value(bsi->ext_wake, 1);
+	}
+	modify_timer_task();
 	return status;
 }
 
@@ -94,12 +131,8 @@
 	tty = hu->tty;
 
 	/* verify and wake up controller */
-	if (ath->cur_sleep) {
+	if (test_bit(BT_SLEEPENABLE, &flags))
 		status = ath_wakeup_ar3k(tty);
-		if (!(status & TIOCM_CTS))
-			return;
-	}
-
 	/* Ready to send Data */
 	clear_bit(HCI_UART_SENDING, &hu->tx_state);
 	hci_uart_tx_wakeup(hu);
@@ -121,6 +154,11 @@
 	hu->priv = ath;
 	ath->hu = hu;
 
+	ath->cur_sleep = enableuartsleep;
+	if (ath->cur_sleep == 1) {
+		set_bit(BT_SLEEPENABLE, &flags);
+		modify_timer_task();
+	}
 	INIT_WORK(&ath->ctxtsw, ath_hci_uart_work);
 
 	return 0;
@@ -173,9 +211,10 @@
 	 */
 	if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) {
 		struct hci_command_hdr *hdr = (void *)skb->data;
-
-		if (__le16_to_cpu(hdr->opcode) == HCI_OP_ATH_SLEEP)
+		if (__le16_to_cpu(hdr->opcode) == HCI_OP_ATH_SLEEP) {
+			set_bit(BT_SLEEPCMD, &flags);
 			ath->cur_sleep = skb->data[HCI_COMMAND_HDR_SIZE];
+		}
 	}
 
 	BT_DBG("hu %p skb %p", hu, skb);
@@ -201,17 +240,55 @@
 /* Recv data */
 static int ath_recv(struct hci_uart *hu, void *data, int count)
 {
-	int ret;
+	struct ath_struct *ath = hu->priv;
+	unsigned int type;
 
-	ret = hci_recv_stream_fragment(hu->hdev, data, count);
-	if (ret < 0) {
+	if (hci_recv_stream_fragment(hu->hdev, data, count) < 0)
 		BT_ERR("Frame Reassembly Failed");
-		return ret;
-	}
 
+	if (count & test_bit(BT_SLEEPCMD, &flags)) {
+		struct sk_buff *skb = hu->hdev->reassembly[0];
+
+		if (!skb) {
+			struct { char type; } *pkt;
+
+			/* Start of the frame */
+			pkt = data;
+			type = pkt->type;
+		} else
+			type = bt_cb(skb)->pkt_type;
+
+		if (type == HCI_EVENT_PKT) {
+			clear_bit(BT_SLEEPCMD, &flags);
+			printk(KERN_INFO "cur_sleep:%d\n", ath->cur_sleep);
+			if (ath->cur_sleep == 1)
+				set_bit(BT_SLEEPENABLE, &flags);
+			else
+				clear_bit(BT_SLEEPENABLE, &flags);
+		}
+		if (test_bit(BT_SLEEPENABLE, &flags))
+			modify_timer_task();
+	}
 	return count;
 }
 
+static void bluesleep_tx_timer_expire(unsigned long data)
+{
+	if (!test_bit(BT_SLEEPENABLE, &flags))
+		return;
+	BT_DBG("Tx timer expired");
+	printk(KERN_INFO "Tx timer expired\n");
+
+	set_bit(BT_TXEXPIRED, &flags);
+}
+
+static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id)
+{
+	/* schedule a tasklet to handle the change in the host wake line */
+	tasklet_schedule(&hostwake_task);
+	return IRQ_HANDLED;
+}
+
 static struct hci_uart_proto athp = {
 	.id = HCI_UART_ATH3K,
 	.open = ath_open,
@@ -222,19 +299,159 @@
 	.flush = ath_flush,
 };
 
+static int __init bluesleep_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct resource *res;
+
+	bsi = kzalloc(sizeof(struct bluesleep_info), GFP_KERNEL);
+	if (!bsi) {
+		ret = -ENOMEM;
+		goto failed;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+						"gpio_host_wake");
+	if (!res) {
+		BT_ERR("couldn't find host_wake gpio\n");
+		ret = -ENODEV;
+		goto free_bsi;
+	}
+	bsi->host_wake = res->start;
+
+	ret = gpio_request(bsi->host_wake, "bt_host_wake");
+	if (ret)
+		goto free_bsi;
+
+	/* configure host_wake as input */
+	ret = gpio_direction_input(bsi->host_wake);
+	if (ret < 0) {
+		pr_err("%s: gpio_direction_input failed for GPIO %d, error %d\n",
+			__func__, bsi->host_wake, ret);
+		gpio_free(bsi->host_wake);
+		goto free_bsi;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+						"gpio_ext_wake");
+	if (!res) {
+		BT_ERR("couldn't find ext_wake gpio\n");
+		ret = -ENODEV;
+		goto free_bt_host_wake;
+	}
+	bsi->ext_wake = res->start;
+
+	ret = gpio_request(bsi->ext_wake, "bt_ext_wake");
+	if (ret)
+		goto free_bt_host_wake;
+
+	/* configure ext_wake as output mode*/
+	ret = gpio_direction_output(bsi->ext_wake, 1);
+	if (ret < 0) {
+		pr_err("%s: gpio_direction_output failed for GPIO %d, error %d\n",
+			__func__, bsi->ext_wake, ret);
+		gpio_free(bsi->ext_wake);
+		goto free_bt_host_wake;
+	}
+	gpio_set_value(bsi->ext_wake, 1);
+
+	bsi->host_wake_irq = platform_get_irq_byname(pdev, "host_wake");
+	if (bsi->host_wake_irq < 0) {
+		BT_ERR("couldn't find host_wake irq\n");
+		ret = -ENODEV;
+		goto free_bt_ext_wake;
+	}
+
+	bsi->irq_polarity = POLARITY_LOW;	/* low edge (falling edge) */
+
+	/* Initialize spinlock. */
+	spin_lock_init(&rw_lock);
+
+	/* Initialize timer */
+	init_timer(&tx_timer);
+	tx_timer.function = bluesleep_tx_timer_expire;
+	tx_timer.data = 0;
+
+	/* initialize host wake tasklet */
+	tasklet_init(&hostwake_task, hostwake_interrupt, 0);
+
+	if (bsi->irq_polarity == POLARITY_LOW) {
+		ret = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
+				IRQF_DISABLED | IRQF_TRIGGER_FALLING,
+				"bluetooth hostwake", NULL);
+	} else  {
+		ret = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
+				IRQF_DISABLED | IRQF_TRIGGER_RISING,
+				"bluetooth hostwake", NULL);
+	}
+	if (ret  < 0) {
+		BT_ERR("Couldn't acquire BT_HOST_WAKE IRQ");
+		goto free_bt_timer;
+	}
+
+	ret = enable_irq_wake(bsi->host_wake_irq);
+	if (ret < 0) {
+		BT_ERR("Couldn't enable BT_HOST_WAKE as wakeup interrupt");
+		free_irq(bsi->host_wake_irq, NULL);
+		goto free_bt_timer;
+	}
+
+	return 0;
+
+free_bt_timer:
+	del_timer(&tx_timer);
+free_bt_ext_wake:
+	gpio_free(bsi->ext_wake);
+free_bt_host_wake:
+	gpio_free(bsi->host_wake);
+free_bsi:
+	kfree(bsi);
+failed:
+	return ret;
+}
+
+static int bluesleep_remove(struct platform_device *pdev)
+{
+	/* assert bt wake */
+	gpio_set_value(bsi->ext_wake, 0);
+	if (disable_irq_wake(bsi->host_wake_irq))
+		BT_ERR("Couldn't disable hostwake IRQ wakeup mode\n");
+	free_irq(bsi->host_wake_irq, NULL);
+	del_timer_sync(&tx_timer);
+	gpio_free(bsi->host_wake);
+	gpio_free(bsi->ext_wake);
+	kfree(bsi);
+	return 0;
+}
+
+static struct platform_driver bluesleep_driver = {
+	.remove = bluesleep_remove,
+	.driver = {
+		.name = "bluesleep",
+		.owner = THIS_MODULE,
+	},
+};
+
 int __init ath_init(void)
 {
-	int err = hci_uart_register_proto(&athp);
+	int ret;
 
-	if (!err)
+	ret = hci_uart_register_proto(&athp);
+
+	if (!ret)
 		BT_INFO("HCIATH3K protocol initialized");
-	else
+	else {
 		BT_ERR("HCIATH3K protocol registration failed");
-
-	return err;
+		return ret;
+	}
+	ret = platform_driver_probe(&bluesleep_driver, bluesleep_probe);
+	if (ret)
+		return ret;
+	return 0;
 }
 
 int __exit ath_deinit(void)
 {
+	platform_driver_unregister(&bluesleep_driver);
 	return hci_uart_unregister_proto(&athp);
 }
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 121bf7c9..5c04693 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
  *  Copyright (C) 2004-2005  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (c) 2000-2001, 2010-2011, Code Aurora Forum. All rights reserved.
+ *  Copyright (c) 2000-2001, 2010-2012, Code Aurora Forum. All rights reserved.
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -51,6 +51,7 @@
 static bool reset = 0;
 
 static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO];
+static void hci_uart_tty_wakeup_action(unsigned long data);
 
 int hci_uart_register_proto(struct hci_uart_proto *p)
 {
@@ -276,6 +277,8 @@
 	tty->receive_room = 65536;
 
 	spin_lock_init(&hu->rx_lock);
+	tasklet_init(&hu->tty_wakeup_task, hci_uart_tty_wakeup_action,
+			 (unsigned long)hu);
 
 	/* Flush any pending characters in the driver and line discipline. */
 
@@ -309,6 +312,8 @@
 		if (hdev)
 			hci_uart_close(hdev);
 
+		tasklet_kill(&hu->tty_wakeup_task);
+
 		if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
 			hu->proto->close(hu);
 			if (hdev) {
@@ -323,6 +328,8 @@
  *
  *    Callback for transmit wakeup. Called when low level
  *    device driver can accept more send data.
+ *    This callback gets called from the isr context so
+ *    schedule the send data operation to tasklet.
  *
  * Arguments:        tty    pointer to associated tty instance data
  * Return Value:    None
@@ -330,12 +337,26 @@
 static void hci_uart_tty_wakeup(struct tty_struct *tty)
 {
 	struct hci_uart *hu = (void *)tty->disc_data;
+	tasklet_schedule(&hu->tty_wakeup_task);
+}
+
+/* hci_uart_tty_wakeup_action()
+ *
+ * Scheduled action to transmit data when low level device
+ * driver can accept more data.
+ */
+static void hci_uart_tty_wakeup_action(unsigned long data)
+{
+	struct hci_uart *hu = (struct hci_uart *)data;
+	struct tty_struct *tty;
 
 	BT_DBG("");
 
 	if (!hu)
 		return;
 
+	tty = hu->tty;
+
 	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 
 	if (tty != hu->tty)
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index dc48239..123fc24 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
  *  Copyright (C) 2004-2005  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
+ *  Copyright (c) 2000-2001, 2010, 2012 Code Aurora Forum. All rights reserved.
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -66,6 +66,7 @@
 	unsigned long		hdev_flags;
 
 	struct hci_uart_proto	*proto;
+	struct tasklet_struct	tty_wakeup_task;
 	void			*priv;
 
 	struct sk_buff		*tx_skb;
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 95a85f2a..0febaf3 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -251,6 +251,7 @@
 	int logging_mode;
 	int mask_check;
 	int logging_process_id;
+	struct task_struct *socket_process;
 #ifdef CONFIG_DIAG_SDIO_PIPE
 	unsigned char *buf_in_sdio;
 	unsigned char *usb_buf_mdm_out;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 240a514..30504bc 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -230,6 +230,13 @@
 	* This call will remove any pending registrations of such client
 	*/
 	diagchar_ioctl(NULL, DIAG_IOCTL_DCI_DEINIT, 0);
+
+	/* If the exiting process is the socket process */
+	if (driver->socket_process &&
+		(driver->socket_process->tgid == current->tgid)) {
+		driver->socket_process = NULL;
+	}
+
 #ifdef CONFIG_DIAG_OVER_USB
 	/* If the SD logging process exits, change logging to USB mode */
 	if (driver->logging_process_id == current->tgid) {
@@ -344,6 +351,7 @@
 	void *temp_buf;
 	uint16_t support_list = 0;
 	struct dci_notification_tbl *notify_params;
+	int status;
 
 	if (iocmd == DIAG_IOCTL_COMMAND_REG) {
 		struct bindpkt_params_per_process *pkt_params =
@@ -480,12 +488,32 @@
 		mutex_lock(&driver->diagchar_mutex);
 		temp = driver->logging_mode;
 		driver->logging_mode = (int)ioarg;
-		if (driver->logging_mode == MEMORY_DEVICE_MODE)
+		if (driver->logging_mode == MEMORY_DEVICE_MODE) {
 			driver->mask_check = 1;
+			if (driver->socket_process) {
+				/*
+				 * Notify the socket logging process that we
+				 * are switching to MEMORY_DEVICE_MODE
+				 */
+				status = send_sig(SIGCONT,
+					 driver->socket_process, 0);
+				if (status) {
+					pr_err("diag: %s, Error notifying ",
+						__func__);
+					pr_err("socket process, status: %d\n",
+						status);
+				}
+			}
+		}
 		if (driver->logging_mode == UART_MODE) {
 			driver->mask_check = 0;
 			driver->logging_mode = MEMORY_DEVICE_MODE;
 		}
+		if (driver->logging_mode == SOCKET_MODE) {
+			driver->socket_process = current;
+			driver->mask_check = 0;
+			driver->logging_mode = MEMORY_DEVICE_MODE;
+		}
 		driver->logging_process_id = current->tgid;
 		mutex_unlock(&driver->diagchar_mutex);
 		if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
@@ -1251,6 +1279,7 @@
 		driver->poolsize_write_struct = poolsize_write_struct;
 		driver->num_clients = max_clients;
 		driver->logging_mode = USB_MODE;
+		driver->socket_process = NULL;
 		driver->mask_check = 0;
 		mutex_init(&driver->diagchar_mutex);
 		init_waitqueue_head(&driver->wait_q);
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index b228276..5a74e8c 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -205,6 +205,39 @@
 		return 0;
 }
 
+/*
+ * This function should be called if you feel that the logging process may
+ * need to be woken up. For instance, if the logging mode is MEMORY_DEVICE MODE
+ * and while trying to read data from a SMD data channel there are no buffers
+ * available to read the data into, then this function should be called to
+ * determine if the logging process needs to be woken up.
+ */
+void chk_logging_wakeup(void)
+{
+	int i;
+
+	/* Find the index of the logging process */
+	for (i = 0; i < driver->num_clients; i++)
+		if (driver->client_map[i].pid ==
+			driver->logging_process_id)
+			break;
+
+	if (i < driver->num_clients) {
+		/* At very high logging rates a race condition can
+		 * occur where the buffers containing the data from
+		 * an smd channel are all in use, but the data_ready
+		 * flag is cleared. In this case, the buffers never
+		 * have their data read/logged.  Detect and remedy this
+		 * situation.
+		 */
+		if ((driver->data_ready[i] & USER_SPACE_LOG_TYPE) == 0) {
+			driver->data_ready[i] |= USER_SPACE_LOG_TYPE;
+			pr_debug("diag: Force wakeup of logging process\n");
+			wake_up_interruptible(&driver->wait_q);
+		}
+	}
+}
+
 void __diag_smd_send_req(void)
 {
 	void *buf = NULL;
@@ -248,6 +281,9 @@
 							 write_ptr_modem);
 			}
 		}
+	} else if (driver->ch && !buf &&
+		(driver->logging_mode == MEMORY_DEVICE_MODE)) {
+		chk_logging_wakeup();
 	}
 }
 
@@ -417,6 +453,9 @@
 					 write_ptr_wcnss);
 			}
 		}
+	} else if (driver->ch_wcnss && !buf &&
+		(driver->logging_mode == MEMORY_DEVICE_MODE)) {
+		chk_logging_wakeup();
 	}
 }
 
@@ -463,6 +502,9 @@
 							 write_ptr_qdsp);
 			}
 		}
+	} else if (driver->chqdsp && !buf &&
+		(driver->logging_mode == MEMORY_DEVICE_MODE)) {
+		chk_logging_wakeup();
 	}
 }
 
diff --git a/drivers/char/hw_random/msm_rng.c b/drivers/char/hw_random/msm_rng.c
index 7e6670d..60ca44f 100644
--- a/drivers/char/hw_random/msm_rng.c
+++ b/drivers/char/hw_random/msm_rng.c
@@ -127,9 +127,9 @@
 					PRNG_HW_ENABLE;
 	/* PRNG H/W is not ON */
 	if (val != PRNG_HW_ENABLE) {
-		val = readl_relaxed(msm_rng_dev->base + PRNG_LFSR_CFG_OFFSET) &
-					PRNG_LFSR_CFG_MASK;
-		val |= PRNG_LFSR_CFG_MASK;
+		val = readl_relaxed(msm_rng_dev->base + PRNG_LFSR_CFG_OFFSET);
+		val &= PRNG_LFSR_CFG_MASK;
+		val |= PRNG_LFSR_CFG_CLOCKS;
 		writel_relaxed(val, msm_rng_dev->base + PRNG_LFSR_CFG_OFFSET);
 
 		/* The PRNG CONFIG register should be first written */
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index a0a6380..3ea5efa 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -420,6 +420,7 @@
 		break;
 	case MDP_Y_CRCB_H2V1:
 	case MDP_Y_CBCR_H2V1:
+	case MDP_Y_CRCB_H1V2:
 		p->num_planes = 2;
 		p->plane_size[0] = w * h;
 		p->plane_size[1] = w * h;
@@ -650,9 +651,12 @@
 	int bpp;
 	uint32_t dst_format;
 
-	if (info->src.format == MDP_YCRYCB_H2V1)
-		dst_format = MDP_Y_CRCB_H2V1;
-	else
+	if (info->src.format == MDP_YCRYCB_H2V1) {
+		if (info->rotations & MDP_ROT_90)
+			dst_format = MDP_Y_CRCB_H1V2;
+		else
+			dst_format = MDP_Y_CRCB_H2V1;
+	} else
 		return -EINVAL;
 
 	if (info->dst.format != dst_format)
@@ -1285,7 +1289,10 @@
 		info.dst.format = info.src.format;
 		break;
 	case MDP_YCRYCB_H2V1:
-		info.dst.format = MDP_Y_CRCB_H2V1;
+		if (info.rotations & MDP_ROT_90)
+			info.dst.format = MDP_Y_CRCB_H1V2;
+		else
+			info.dst.format = MDP_Y_CRCB_H2V1;
 		break;
 	case MDP_Y_CB_CR_H2V2:
 	case MDP_Y_CBCR_H2V2_TILE:
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 2ee2093..bded488 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -1,2 +1,3 @@
 
-obj-$(CONFIG_MSM_QDSS) += coresight.o coresight-etb.o coresight-tpiu.o coresight-funnel.o coresight-stm.o coresight-etm.o
+obj-$(CONFIG_OF) += of_coresight.o
+obj-$(CONFIG_MSM_QDSS) += coresight.o coresight-tmc.o coresight-tpiu.o coresight-etb.o coresight-funnel.o coresight-replicator.o coresight-stm.o coresight-etm.o
diff --git a/drivers/coresight/coresight-etb.c b/drivers/coresight/coresight-etb.c
index 2bffae5..56cee06 100644
--- a/drivers/coresight/coresight-etb.c
+++ b/drivers/coresight/coresight-etb.c
@@ -23,8 +23,9 @@
 #include <linux/uaccess.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
-#include <linux/mutex.h>
+#include <linux/spinlock.h>
 #include <linux/clk.h>
+#include <linux/of_coresight.h>
 #include <linux/coresight.h>
 
 #include "coresight-priv.h"
@@ -32,6 +33,17 @@
 #define etb_writel(drvdata, val, off)	__raw_writel((val), drvdata->base + off)
 #define etb_readl(drvdata, off)		__raw_readl(drvdata->base + off)
 
+#define ETB_LOCK(drvdata)						\
+do {									\
+	mb();								\
+	etb_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+} while (0)
+#define ETB_UNLOCK(drvdata)						\
+do {									\
+	etb_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
+	mb();								\
+} while (0)
+
 #define ETB_RAM_DEPTH_REG	(0x004)
 #define ETB_STATUS_REG		(0x00C)
 #define ETB_RAM_READ_DATA_REG	(0x010)
@@ -50,42 +62,29 @@
 #define ETB_ITATBCTR1		(0xEF4)
 #define ETB_ITATBCTR0		(0xEF8)
 
-
 #define BYTES_PER_WORD		4
 #define ETB_SIZE_WORDS		4096
 #define FRAME_SIZE_WORDS	4
 
-#define ETB_LOCK()							\
-do {									\
-	mb();								\
-	etb_writel(drvdata, 0x0, CORESIGHT_LAR);			\
-} while (0)
-#define ETB_UNLOCK()							\
-do {									\
-	etb_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
-	mb();								\
-} while (0)
-
 struct etb_drvdata {
-	uint8_t		*buf;
-	void __iomem	*base;
-	bool		enabled;
-	bool		reading;
-	spinlock_t	spinlock;
-	atomic_t	in_use;
-	struct device	*dev;
-	struct kobject	*kobj;
-	struct clk	*clk;
-	uint32_t	trigger_cntr;
+	void __iomem		*base;
+	struct device		*dev;
+	struct coresight_device	*csdev;
+	struct miscdevice	miscdev;
+	struct clk		*clk;
+	spinlock_t		spinlock;
+	bool			reading;
+	atomic_t		in_use;
+	uint8_t			*buf;
+	bool			enable;
+	uint32_t		trigger_cntr;
 };
 
-static struct etb_drvdata *drvdata;
-
-static void __etb_enable(void)
+static void __etb_enable(struct etb_drvdata *drvdata)
 {
 	int i;
 
-	ETB_UNLOCK();
+	ETB_UNLOCK(drvdata);
 
 	etb_writel(drvdata, 0x0, ETB_RAM_WRITE_POINTER);
 	for (i = 0; i < ETB_SIZE_WORDS; i++)
@@ -98,11 +97,12 @@
 	etb_writel(drvdata, BIT(13) | BIT(0), ETB_FFCR);
 	etb_writel(drvdata, BIT(0), ETB_CTL_REG);
 
-	ETB_LOCK();
+	ETB_LOCK(drvdata);
 }
 
-int etb_enable(void)
+static int etb_enable(struct coresight_device *csdev)
 {
+	struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 	int ret;
 	unsigned long flags;
 
@@ -111,25 +111,24 @@
 		return ret;
 
 	spin_lock_irqsave(&drvdata->spinlock, flags);
-	__etb_enable();
-	drvdata->enabled = true;
-	dev_info(drvdata->dev, "ETB enabled\n");
+	__etb_enable(drvdata);
+	drvdata->enable = true;
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
+	dev_info(drvdata->dev, "ETB enabled\n");
 	return 0;
 }
 
-static void __etb_disable(void)
+static void __etb_disable(struct etb_drvdata *drvdata)
 {
 	int count;
 	uint32_t ffcr;
 
-	ETB_UNLOCK();
+	ETB_UNLOCK(drvdata);
 
 	ffcr = etb_readl(drvdata, ETB_FFCR);
 	ffcr |= (BIT(12) | BIT(6));
 	etb_writel(drvdata, ffcr, ETB_FFCR);
-
 	for (count = TIMEOUT_US; BVAL(etb_readl(drvdata, ETB_FFCR), 6) != 0
 				&& count > 0; count--)
 		udelay(1);
@@ -137,30 +136,16 @@
 	     etb_readl(drvdata, ETB_FFCR));
 
 	etb_writel(drvdata, 0x0, ETB_CTL_REG);
-
 	for (count = TIMEOUT_US; BVAL(etb_readl(drvdata, ETB_FFSR), 1) != 1
 				&& count > 0; count--)
 		udelay(1);
 	WARN(count == 0, "timeout while disabling DRVDATA, ETB_FFSR: %#x\n",
 	     etb_readl(drvdata, ETB_FFSR));
 
-	ETB_LOCK();
+	ETB_LOCK(drvdata);
 }
 
-void etb_disable(void)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&drvdata->spinlock, flags);
-	__etb_disable();
-	drvdata->enabled = false;
-	dev_info(drvdata->dev, "ETB disabled\n");
-	spin_unlock_irqrestore(&drvdata->spinlock, flags);
-
-	clk_disable_unprepare(drvdata->clk);
-}
-
-static void __etb_dump(void)
+static void __etb_dump(struct etb_drvdata *drvdata)
 {
 	int i;
 	uint8_t *buf_ptr;
@@ -170,7 +155,7 @@
 	uint32_t frame_off;
 	uint32_t frame_endoff;
 
-	ETB_UNLOCK();
+	ETB_UNLOCK(drvdata);
 
 	read_ptr = etb_readl(drvdata, ETB_RAM_READ_POINTER);
 	write_ptr = etb_readl(drvdata, ETB_RAM_WRITE_POINTER);
@@ -211,26 +196,69 @@
 
 	etb_writel(drvdata, read_ptr, ETB_RAM_READ_POINTER);
 
-	ETB_LOCK();
+	ETB_LOCK(drvdata);
 }
 
-void etb_dump(void)
+static void etb_disable(struct coresight_device *csdev)
+{
+	struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	unsigned long flags;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	__etb_disable(drvdata);
+	__etb_dump(drvdata);
+	drvdata->enable = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	clk_disable_unprepare(drvdata->clk);
+
+	dev_info(drvdata->dev, "ETB disabled\n");
+}
+
+static void etb_abort(struct coresight_device *csdev)
+{
+	struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	unsigned long flags;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	__etb_disable(drvdata);
+	__etb_dump(drvdata);
+	drvdata->enable = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "ETB aborted\n");
+}
+
+static const struct coresight_ops_sink etb_sink_ops = {
+	.enable		= etb_enable,
+	.disable	= etb_disable,
+	.abort		= etb_abort,
+};
+
+static const struct coresight_ops etb_cs_ops = {
+	.sink_ops	= &etb_sink_ops,
+};
+
+static void etb_dump(struct etb_drvdata *drvdata)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&drvdata->spinlock, flags);
-	if (drvdata->enabled) {
-		__etb_disable();
-		__etb_dump();
-		__etb_enable();
-
-		dev_info(drvdata->dev, "ETB dumped\n");
+	if (drvdata->enable) {
+		__etb_disable(drvdata);
+		__etb_dump(drvdata);
+		__etb_enable(drvdata);
 	}
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "ETB dumped\n");
 }
 
 static int etb_open(struct inode *inode, struct file *file)
 {
+	struct etb_drvdata *drvdata = container_of(file->private_data,
+						   struct etb_drvdata, miscdev);
+
 	if (atomic_cmpxchg(&drvdata->in_use, 0, 1))
 		return -EBUSY;
 
@@ -241,8 +269,11 @@
 static ssize_t etb_read(struct file *file, char __user *data,
 				size_t len, loff_t *ppos)
 {
+	struct etb_drvdata *drvdata = container_of(file->private_data,
+						   struct etb_drvdata, miscdev);
+
 	if (drvdata->reading == false) {
-		etb_dump();
+		etb_dump(drvdata);
 		drvdata->reading = true;
 	}
 
@@ -258,38 +289,35 @@
 
 	dev_dbg(drvdata->dev, "%s: %d bytes copied, %d bytes left\n",
 		__func__, len, (int) (ETB_SIZE_WORDS * BYTES_PER_WORD - *ppos));
-
 	return len;
 }
 
 static int etb_release(struct inode *inode, struct file *file)
 {
-	drvdata->reading = false;
+	struct etb_drvdata *drvdata = container_of(file->private_data,
+						   struct etb_drvdata, miscdev);
 
+	drvdata->reading = false;
 	atomic_set(&drvdata->in_use, 0);
 
 	dev_dbg(drvdata->dev, "%s: released\n", __func__);
-
 	return 0;
 }
 
 static const struct file_operations etb_fops = {
-	.owner =	THIS_MODULE,
-	.open =		etb_open,
-	.read =		etb_read,
-	.release =	etb_release,
-};
-
-static struct miscdevice etb_misc = {
-	.name =		"msm_etb",
-	.minor =	MISC_DYNAMIC_MINOR,
-	.fops =		&etb_fops,
+	.owner		= THIS_MODULE,
+	.open		= etb_open,
+	.read		= etb_read,
+	.release	= etb_release,
+	.llseek		= no_llseek,
 };
 
 static ssize_t etb_show_trigger_cntr(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
+	struct etb_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->trigger_cntr;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -297,6 +325,7 @@
 				      struct device_attribute *attr,
 				      const char *buf, size_t size)
 {
+	struct etb_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -308,120 +337,105 @@
 static DEVICE_ATTR(trigger_cntr, S_IRUGO | S_IWUSR, etb_show_trigger_cntr,
 		   etb_store_trigger_cntr);
 
-static int __devinit etb_sysfs_init(void)
-{
-	int ret;
+static struct attribute *etb_attrs[] = {
+	&dev_attr_trigger_cntr.attr,
+	NULL,
+};
 
-	drvdata->kobj = kobject_create_and_add("etb", qdss_get_modulekobj());
-	if (!drvdata->kobj) {
-		dev_err(drvdata->dev, "failed to create ETB sysfs kobject\n");
-		ret = -ENOMEM;
-		goto err_create;
-	}
+static struct attribute_group etb_attr_grp = {
+	.attrs = etb_attrs,
+};
 
-	ret = sysfs_create_file(drvdata->kobj, &dev_attr_trigger_cntr.attr);
-	if (ret) {
-		dev_err(drvdata->dev, "failed to create ETB sysfs trigger_cntr"
-		" attribute\n");
-		goto err_file;
-	}
-
-	return 0;
-err_file:
-	kobject_put(drvdata->kobj);
-err_create:
-	return ret;
-}
-
-static void __devexit etb_sysfs_exit(void)
-{
-	sysfs_remove_file(drvdata->kobj, &dev_attr_trigger_cntr.attr);
-	kobject_put(drvdata->kobj);
-}
+static const struct attribute_group *etb_attr_grps[] = {
+	&etb_attr_grp,
+	NULL,
+};
 
 static int __devinit etb_probe(struct platform_device *pdev)
 {
 	int ret;
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct etb_drvdata *drvdata;
 	struct resource *res;
+	struct coresight_desc *desc;
 
-	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
-	if (!drvdata) {
-		ret = -ENOMEM;
-		goto err_kzalloc_drvdata;
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
 	}
 
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		ret = -EINVAL;
-		goto err_res;
-	}
+	if (!res)
+		return -ENODEV;
 
-	drvdata->base = ioremap_nocache(res->start, resource_size(res));
-	if (!drvdata->base) {
-		ret = -EINVAL;
-		goto err_ioremap;
-	}
-
-	drvdata->dev = &pdev->dev;
+	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!drvdata->base)
+		return -ENOMEM;
 
 	spin_lock_init(&drvdata->spinlock);
 
-	drvdata->clk = clk_get(drvdata->dev, "core_clk");
-	if (IS_ERR(drvdata->clk)) {
-		ret = PTR_ERR(drvdata->clk);
-		goto err_clk_get;
-	}
+	drvdata->clk = devm_clk_get(dev, "core_clk");
+	if (IS_ERR(drvdata->clk))
+		return PTR_ERR(drvdata->clk);
 
 	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
 	if (ret)
-		goto err_clk_rate;
+		return ret;
 
-	ret = misc_register(&etb_misc);
+	drvdata->buf = devm_kzalloc(dev, ETB_SIZE_WORDS * BYTES_PER_WORD,
+				    GFP_KERNEL);
+	if (!drvdata->buf)
+		return -ENOMEM;
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+	desc->type = CORESIGHT_DEV_TYPE_SINK;
+	desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
+	desc->ops = &etb_cs_ops;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->groups = etb_attr_grps;
+	desc->owner = THIS_MODULE;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev))
+		return PTR_ERR(drvdata->csdev);
+
+	drvdata->miscdev.name = ((struct coresight_platform_data *)
+				 (pdev->dev.platform_data))->name;
+	drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
+	drvdata->miscdev.fops = &etb_fops;
+	ret = misc_register(&drvdata->miscdev);
 	if (ret)
-		goto err_misc;
+		goto err;
 
-	drvdata->buf = kzalloc(ETB_SIZE_WORDS * BYTES_PER_WORD, GFP_KERNEL);
-	if (!drvdata->buf) {
-		ret = -ENOMEM;
-		goto err_alloc;
-	}
-
-	etb_sysfs_init();
-
-	dev_info(drvdata->dev, "ETB initialized\n");
+	dev_info(dev, "ETB initialized\n");
 	return 0;
-
-err_alloc:
-	misc_deregister(&etb_misc);
-err_misc:
-err_clk_rate:
-	clk_put(drvdata->clk);
-err_clk_get:
-	iounmap(drvdata->base);
-err_ioremap:
-err_res:
-	kfree(drvdata);
-err_kzalloc_drvdata:
-	dev_err(drvdata->dev, "ETB init failed\n");
+err:
+	coresight_unregister(drvdata->csdev);
 	return ret;
 }
 
 static int __devexit etb_remove(struct platform_device *pdev)
 {
-	if (drvdata->enabled)
-		etb_disable();
-	etb_sysfs_exit();
-	kfree(drvdata->buf);
-	misc_deregister(&etb_misc);
-	clk_put(drvdata->clk);
-	iounmap(drvdata->base);
-	kfree(drvdata);
+	struct etb_drvdata *drvdata = platform_get_drvdata(pdev);
 
+	misc_deregister(&drvdata->miscdev);
+	coresight_unregister(drvdata->csdev);
 	return 0;
 }
 
 static struct of_device_id etb_match[] = {
-	{.compatible = "qcom,msm-etb"},
+	{.compatible = "arm,coresight-etb"},
 	{}
 };
 
@@ -429,7 +443,7 @@
 	.probe          = etb_probe,
 	.remove         = __devexit_p(etb_remove),
 	.driver         = {
-		.name   = "msm_etb",
+		.name   = "coresight-etb",
 		.owner	= THIS_MODULE,
 		.of_match_table = etb_match,
 	},
diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
index b3d2a16..e805c7f 100644
--- a/drivers/coresight/coresight-etm.c
+++ b/drivers/coresight/coresight-etm.c
@@ -26,17 +26,30 @@
 #include <linux/pm_qos.h>
 #include <linux/sysfs.h>
 #include <linux/stat.h>
+#include <linux/mutex.h>
 #include <linux/clk.h>
+#include <linux/of_coresight.h>
 #include <linux/coresight.h>
 #include <asm/sections.h>
 #include <mach/socinfo.h>
 
 #include "coresight-priv.h"
 
-#define etm_writel(drvdata, cpu, val, off)	\
-			__raw_writel((val), drvdata->base + (SZ_4K * cpu) + off)
-#define etm_readl(drvdata, cpu, off)	\
-			__raw_readl(drvdata->base + (SZ_4K * cpu) + off)
+#define etm_writel(drvdata, val, off)	\
+			__raw_writel((val), drvdata->base + off)
+#define etm_readl(drvdata, off)		\
+			__raw_readl(drvdata->base + off)
+
+#define ETM_LOCK(drvdata)						\
+do {									\
+	mb();								\
+	etm_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+} while (0)
+#define ETM_UNLOCK(drvdata)						\
+do {									\
+	etm_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
+	mb();								\
+} while (0)
 
 /*
  * Device registers:
@@ -119,7 +132,7 @@
 
 #define ETM_SEQ_STATE_MAX_VAL	(0x2)
 
-enum {
+enum etm_addr_type {
 	ETM_ADDR_TYPE_NONE,
 	ETM_ADDR_TYPE_SINGLE,
 	ETM_ADDR_TYPE_RANGE,
@@ -127,42 +140,24 @@
 	ETM_ADDR_TYPE_STOP,
 };
 
-#define ETM_LOCK(cpu)							\
-do {									\
-	mb();								\
-	etm_writel(drvdata, cpu, 0x0, CORESIGHT_LAR);			\
-} while (0)
-#define ETM_UNLOCK(cpu)							\
-do {									\
-	etm_writel(drvdata, cpu, CORESIGHT_UNLOCK, CORESIGHT_LAR);	\
-	mb();								\
-} while (0)
-
-
-#ifdef MODULE_PARAM_PREFIX
-#undef MODULE_PARAM_PREFIX
-#endif
-#define MODULE_PARAM_PREFIX "coresight."
-
 #ifdef CONFIG_MSM_QDSS_ETM_DEFAULT_ENABLE
-static int etm_boot_enable = 1;
+static int boot_enable = 1;
 #else
-static int etm_boot_enable;
+static int boot_enable;
 #endif
 module_param_named(
-	etm_boot_enable, etm_boot_enable, int, S_IRUGO
+	boot_enable, boot_enable, int, S_IRUGO
 );
 
 struct etm_drvdata {
 	void __iomem			*base;
-	bool				enabled;
+	struct device			*dev;
+	struct coresight_device		*csdev;
+	struct clk			*clk;
+	struct mutex			mutex;
 	struct wake_lock		wake_lock;
 	struct pm_qos_request		qos_req;
-	struct qdss_source		*src;
-	struct mutex			mutex;
-	struct device			*dev;
-	struct kobject			*kobj;
-	struct clk			*clk;
+	int				cpu;
 	uint8_t				arch;
 	uint8_t				nr_addr_cmp;
 	uint8_t				nr_cntr;
@@ -200,9 +195,6 @@
 	uint32_t			timestamp_event;
 };
 
-static struct etm_drvdata *drvdata;
-
-
 /* ETM clock is derived from the processor clock and gets enabled on a
  * logical OR of below items on Krait (pass2 onwards):
  * 1.CPMR[ETMCLKEN] is 1
@@ -218,115 +210,107 @@
  * clock vote in the driver and the save-restore code uses 1. above
  * for its vote
  */
-static void etm_set_pwrdwn(int cpu)
+static void etm_set_pwrdwn(struct etm_drvdata *drvdata)
 {
 	uint32_t etmcr;
 
-	etmcr = etm_readl(drvdata, cpu, ETMCR);
+	etmcr = etm_readl(drvdata, ETMCR);
 	etmcr |= BIT(0);
-	etm_writel(drvdata, cpu, etmcr, ETMCR);
+	etm_writel(drvdata, etmcr, ETMCR);
 }
 
-static void etm_clr_pwrdwn(int cpu)
+static void etm_clr_pwrdwn(struct etm_drvdata *drvdata)
 {
 	uint32_t etmcr;
 
-	etmcr = etm_readl(drvdata, cpu, ETMCR);
+	etmcr = etm_readl(drvdata, ETMCR);
 	etmcr &= ~BIT(0);
-	etm_writel(drvdata, cpu, etmcr, ETMCR);
+	etm_writel(drvdata, etmcr, ETMCR);
 }
 
-static void etm_set_prog(int cpu)
+static void etm_set_prog(struct etm_drvdata *drvdata)
 {
 	uint32_t etmcr;
 	int count;
 
-	etmcr = etm_readl(drvdata, cpu, ETMCR);
+	etmcr = etm_readl(drvdata, ETMCR);
 	etmcr |= BIT(10);
-	etm_writel(drvdata, cpu, etmcr, ETMCR);
-
-	for (count = TIMEOUT_US; BVAL(etm_readl(drvdata, cpu, ETMSR), 1) != 1
+	etm_writel(drvdata, etmcr, ETMCR);
+	for (count = TIMEOUT_US; BVAL(etm_readl(drvdata, ETMSR), 1) != 1
 				&& count > 0; count--)
 		udelay(1);
 	WARN(count == 0, "timeout while setting prog bit, ETMSR: %#x\n",
-	     etm_readl(drvdata, cpu, ETMSR));
+	     etm_readl(drvdata, ETMSR));
 }
 
-static void etm_clr_prog(int cpu)
+static void etm_clr_prog(struct etm_drvdata *drvdata)
 {
 	uint32_t etmcr;
 	int count;
 
-	etmcr = etm_readl(drvdata, cpu, ETMCR);
+	etmcr = etm_readl(drvdata, ETMCR);
 	etmcr &= ~BIT(10);
-	etm_writel(drvdata, cpu, etmcr, ETMCR);
-
-	for (count = TIMEOUT_US; BVAL(etm_readl(drvdata, cpu, ETMSR), 1) != 0
+	etm_writel(drvdata, etmcr, ETMCR);
+	for (count = TIMEOUT_US; BVAL(etm_readl(drvdata, ETMSR), 1) != 0
 				&& count > 0; count--)
 		udelay(1);
 	WARN(count == 0, "timeout while clearing prog bit, ETMSR: %#x\n",
-	     etm_readl(drvdata, cpu, ETMSR));
+	     etm_readl(drvdata, ETMSR));
 }
 
-static void __etm_enable(int cpu)
+static void __etm_enable(struct etm_drvdata *drvdata)
 {
 	int i;
 
-	ETM_UNLOCK(cpu);
+	ETM_UNLOCK(drvdata);
 	/* Vote for ETM power/clock enable */
-	etm_clr_pwrdwn(cpu);
-	etm_set_prog(cpu);
+	etm_clr_pwrdwn(drvdata);
+	etm_set_prog(drvdata);
 
-	etm_writel(drvdata, cpu, drvdata->ctrl | BIT(10), ETMCR);
-	etm_writel(drvdata, cpu, drvdata->trigger_event, ETMTRIGGER);
-	etm_writel(drvdata, cpu, drvdata->startstop_ctrl, ETMTSSCR);
-	etm_writel(drvdata, cpu, drvdata->enable_event, ETMTEEVR);
-	etm_writel(drvdata, cpu, drvdata->enable_ctrl1, ETMTECR1);
-	etm_writel(drvdata, cpu, drvdata->fifofull_level, ETMFFLR);
+	etm_writel(drvdata, drvdata->ctrl | BIT(10), ETMCR);
+	etm_writel(drvdata, drvdata->trigger_event, ETMTRIGGER);
+	etm_writel(drvdata, drvdata->startstop_ctrl, ETMTSSCR);
+	etm_writel(drvdata, drvdata->enable_event, ETMTEEVR);
+	etm_writel(drvdata, drvdata->enable_ctrl1, ETMTECR1);
+	etm_writel(drvdata, drvdata->fifofull_level, ETMFFLR);
 	for (i = 0; i < drvdata->nr_addr_cmp; i++) {
-		etm_writel(drvdata, cpu, drvdata->addr_val[i], ETMACVRn(i));
-		etm_writel(drvdata, cpu, drvdata->addr_acctype[i], ETMACTRn(i));
+		etm_writel(drvdata, drvdata->addr_val[i], ETMACVRn(i));
+		etm_writel(drvdata, drvdata->addr_acctype[i], ETMACTRn(i));
 	}
 	for (i = 0; i < drvdata->nr_cntr; i++) {
-		etm_writel(drvdata, cpu, drvdata->cntr_rld_val[i],
-			   ETMCNTRLDVRn(i));
-		etm_writel(drvdata, cpu, drvdata->cntr_event[i], ETMCNTENRn(i));
-		etm_writel(drvdata, cpu, drvdata->cntr_rld_event[i],
+		etm_writel(drvdata, drvdata->cntr_rld_val[i], ETMCNTRLDVRn(i));
+		etm_writel(drvdata, drvdata->cntr_event[i], ETMCNTENRn(i));
+		etm_writel(drvdata, drvdata->cntr_rld_event[i],
 			   ETMCNTRLDEVRn(i));
-		etm_writel(drvdata, cpu, drvdata->cntr_val[i], ETMCNTVRn(i));
+		etm_writel(drvdata, drvdata->cntr_val[i], ETMCNTVRn(i));
 	}
-	etm_writel(drvdata, cpu, drvdata->seq_12_event, ETMSQ12EVR);
-	etm_writel(drvdata, cpu, drvdata->seq_21_event, ETMSQ21EVR);
-	etm_writel(drvdata, cpu, drvdata->seq_23_event, ETMSQ23EVR);
-	etm_writel(drvdata, cpu, drvdata->seq_31_event, ETMSQ31EVR);
-	etm_writel(drvdata, cpu, drvdata->seq_32_event, ETMSQ32EVR);
-	etm_writel(drvdata, cpu, drvdata->seq_13_event, ETMSQ13EVR);
-	etm_writel(drvdata, cpu, drvdata->seq_curr_state, ETMSQR);
+	etm_writel(drvdata, drvdata->seq_12_event, ETMSQ12EVR);
+	etm_writel(drvdata, drvdata->seq_21_event, ETMSQ21EVR);
+	etm_writel(drvdata, drvdata->seq_23_event, ETMSQ23EVR);
+	etm_writel(drvdata, drvdata->seq_31_event, ETMSQ31EVR);
+	etm_writel(drvdata, drvdata->seq_32_event, ETMSQ32EVR);
+	etm_writel(drvdata, drvdata->seq_13_event, ETMSQ13EVR);
+	etm_writel(drvdata, drvdata->seq_curr_state, ETMSQR);
 	for (i = 0; i < drvdata->nr_ext_out; i++)
-		etm_writel(drvdata, cpu, 0x0000406F, ETMEXTOUTEVRn(i));
+		etm_writel(drvdata, 0x0000406F, ETMEXTOUTEVRn(i));
 	for (i = 0; i < drvdata->nr_ctxid_cmp; i++)
-		etm_writel(drvdata, cpu, drvdata->ctxid_val[i], ETMCIDCVRn(i));
-	etm_writel(drvdata, cpu, drvdata->ctxid_mask, ETMCIDCMR);
-	etm_writel(drvdata, cpu, drvdata->sync_freq, ETMSYNCFR);
-	etm_writel(drvdata, cpu, 0x00000000, ETMEXTINSELR);
-	etm_writel(drvdata, cpu, drvdata->timestamp_event, ETMTSEVR);
-	etm_writel(drvdata, cpu, 0x00000000, ETMAUXCR);
-	etm_writel(drvdata, cpu, cpu+1, ETMTRACEIDR);
-	etm_writel(drvdata, cpu, 0x00000000, ETMVMIDCVR);
+		etm_writel(drvdata, drvdata->ctxid_val[i], ETMCIDCVRn(i));
+	etm_writel(drvdata, drvdata->ctxid_mask, ETMCIDCMR);
+	etm_writel(drvdata, drvdata->sync_freq, ETMSYNCFR);
+	etm_writel(drvdata, 0x00000000, ETMEXTINSELR);
+	etm_writel(drvdata, drvdata->timestamp_event, ETMTSEVR);
+	etm_writel(drvdata, 0x00000000, ETMAUXCR);
+	etm_writel(drvdata, drvdata->cpu + 1, ETMTRACEIDR);
+	etm_writel(drvdata, 0x00000000, ETMVMIDCVR);
 
-	etm_clr_prog(cpu);
-	ETM_LOCK(cpu);
+	etm_clr_prog(drvdata);
+	ETM_LOCK(drvdata);
 }
 
-static int etm_enable(void)
+static int etm_enable(struct coresight_device *csdev)
 {
-	int ret, cpu;
-
-	if (drvdata->enabled) {
-		dev_err(drvdata->dev, "ETM tracing already enabled\n");
-		ret = -EPERM;
-		goto err;
-	}
+	struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	int ret;
 
 	wake_lock(&drvdata->wake_lock);
 	/* 1. causes all online cpus to come out of idle PC
@@ -342,52 +326,37 @@
 	if (ret)
 		goto err_clk;
 
-	ret = qdss_enable(drvdata->src);
-	if (ret)
-		goto err_qdss;
-
-	for_each_online_cpu(cpu)
-		__etm_enable(cpu);
-
-	drvdata->enabled = true;
+	mutex_lock(&drvdata->mutex);
+	__etm_enable(drvdata);
+	mutex_unlock(&drvdata->mutex);
 
 	pm_qos_update_request(&drvdata->qos_req, PM_QOS_DEFAULT_VALUE);
 	wake_unlock(&drvdata->wake_lock);
 
 	dev_info(drvdata->dev, "ETM tracing enabled\n");
 	return 0;
-
-err_qdss:
-	clk_disable_unprepare(drvdata->clk);
 err_clk:
 	pm_qos_update_request(&drvdata->qos_req, PM_QOS_DEFAULT_VALUE);
 	wake_unlock(&drvdata->wake_lock);
-err:
 	return ret;
 }
 
-static void __etm_disable(int cpu)
+static void __etm_disable(struct etm_drvdata *drvdata)
 {
-	ETM_UNLOCK(cpu);
-	etm_set_prog(cpu);
+	ETM_UNLOCK(drvdata);
+	etm_set_prog(drvdata);
 
 	/* program trace enable to low by using always false event */
-	etm_writel(drvdata, cpu, 0x6F | BIT(14), ETMTEEVR);
+	etm_writel(drvdata, 0x6F | BIT(14), ETMTEEVR);
 
 	/* Vote for ETM power/clock disable */
-	etm_set_pwrdwn(cpu);
-	ETM_LOCK(cpu);
+	etm_set_pwrdwn(drvdata);
+	ETM_LOCK(drvdata);
 }
 
-static int etm_disable(void)
+static void etm_disable(struct coresight_device *csdev)
 {
-	int ret, cpu;
-
-	if (!drvdata->enabled) {
-		dev_err(drvdata->dev, "ETM tracing already disabled\n");
-		ret = -EPERM;
-		goto err;
-	}
+	struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
 	wake_lock(&drvdata->wake_lock);
 	/* 1. causes all online cpus to come out of idle PC
@@ -399,12 +368,9 @@
 	 */
 	pm_qos_update_request(&drvdata->qos_req, 0);
 
-	for_each_online_cpu(cpu)
-		__etm_disable(cpu);
-
-	drvdata->enabled = false;
-
-	qdss_disable(drvdata->src);
+	mutex_lock(&drvdata->mutex);
+	__etm_disable(drvdata);
+	mutex_unlock(&drvdata->mutex);
 
 	clk_disable_unprepare(drvdata->clk);
 
@@ -412,55 +378,23 @@
 	wake_unlock(&drvdata->wake_lock);
 
 	dev_info(drvdata->dev, "ETM tracing disabled\n");
-	return 0;
-err:
-	return ret;
 }
 
-/* Memory mapped writes to clear os lock not supported */
-static void etm_os_unlock(void *unused)
-{
-	unsigned long value = 0x0;
+static const struct coresight_ops_source etm_source_ops = {
+	.enable		= etm_enable,
+	.disable	= etm_disable,
+};
 
-	asm("mcr p14, 1, %0, c1, c0, 4\n\t" : : "r" (value));
-	asm("isb\n\t");
-}
-
-static ssize_t etm_show_enabled(struct device *dev,
-				struct device_attribute *attr, char *buf)
-{
-	unsigned long val = drvdata->enabled;
-	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
-}
-
-static ssize_t etm_store_enabled(struct device *dev,
-				 struct device_attribute *attr,
-				 const char *buf, size_t size)
-{
-	int ret = 0;
-	unsigned long val;
-
-	if (sscanf(buf, "%lx", &val) != 1)
-		return -EINVAL;
-
-	mutex_lock(&drvdata->mutex);
-	if (val)
-		ret = etm_enable();
-	else
-		ret = etm_disable();
-	mutex_unlock(&drvdata->mutex);
-
-	if (ret)
-		return ret;
-	return size;
-}
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, etm_show_enabled,
-		   etm_store_enabled);
+static const struct coresight_ops etm_cs_ops = {
+	.source_ops	= &etm_source_ops,
+};
 
 static ssize_t etm_show_nr_addr_cmp(struct device *dev,
 				    struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->nr_addr_cmp;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 static DEVICE_ATTR(nr_addr_cmp, S_IRUGO, etm_show_nr_addr_cmp, NULL);
@@ -468,7 +402,9 @@
 static ssize_t etm_show_nr_cntr(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->nr_cntr;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 static DEVICE_ATTR(nr_cntr, S_IRUGO, etm_show_nr_cntr, NULL);
@@ -476,7 +412,9 @@
 static ssize_t etm_show_nr_ctxid_cmp(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->nr_ctxid_cmp;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 static DEVICE_ATTR(nr_ctxid_cmp, S_IRUGO, etm_show_nr_ctxid_cmp, NULL);
@@ -484,7 +422,9 @@
 static ssize_t etm_show_reset(struct device *dev, struct device_attribute *attr,
 			      char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->reset;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -493,6 +433,7 @@
 			       struct device_attribute *attr, const char *buf,
 			       size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	int i;
 	unsigned long val;
 
@@ -536,7 +477,11 @@
 		for (i = 0; i < drvdata->nr_ctxid_cmp; i++)
 			drvdata->ctxid_val[i] = 0x0;
 		drvdata->ctxid_mask = 0x0;
-		drvdata->sync_freq = 0x80;
+		/* Bits[7:0] of ETMSYNCFR are reserved on Krait pass3 onwards */
+		if (cpu_is_krait() && !cpu_is_krait_v1() && !cpu_is_krait_v2())
+			drvdata->sync_freq = 0x100;
+		else
+			drvdata->sync_freq = 0x80;
 		drvdata->timestamp_event = 0x406F;
 	}
 	mutex_unlock(&drvdata->mutex);
@@ -547,13 +492,16 @@
 static ssize_t etm_show_mode(struct device *dev, struct device_attribute *attr,
 			      char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->mode;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
 static ssize_t etm_store_mode(struct device *dev, struct device_attribute *attr,
 			      const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -581,6 +529,7 @@
 		drvdata->ctrl |= BIT(28);
 	else
 		drvdata->ctrl &= ~BIT(28);
+
 	if (drvdata->mode & ETM_MODE_CTXID)
 		drvdata->ctrl |= (BIT(14) | BIT(15));
 	else
@@ -594,7 +543,9 @@
 static ssize_t etm_show_trigger_event(struct device *dev,
 				      struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->trigger_event;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -602,6 +553,7 @@
 				       struct device_attribute *attr,
 				       const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -616,7 +568,9 @@
 static ssize_t etm_show_enable_event(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->enable_event;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -624,6 +578,7 @@
 				      struct device_attribute *attr,
 				      const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -638,7 +593,9 @@
 static ssize_t etm_show_fifofull_level(struct device *dev,
 				       struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->fifofull_level;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -646,6 +603,7 @@
 					struct device_attribute *attr,
 					const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -660,7 +618,9 @@
 static ssize_t etm_show_addr_idx(struct device *dev,
 				 struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->addr_idx;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -668,6 +628,7 @@
 				  struct device_attribute *attr,
 				  const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -689,6 +650,7 @@
 static ssize_t etm_show_addr_single(struct device *dev,
 				    struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 	uint8_t idx;
 
@@ -709,6 +671,7 @@
 				     struct device_attribute *attr,
 				     const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 	uint8_t idx;
 
@@ -734,6 +697,7 @@
 static ssize_t etm_show_addr_range(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val1, val2;
 	uint8_t idx;
 
@@ -761,6 +725,7 @@
 				    struct device_attribute *attr,
 				    const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val1, val2;
 	uint8_t idx;
 
@@ -798,6 +763,7 @@
 static ssize_t etm_show_addr_start(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 	uint8_t idx;
 
@@ -818,6 +784,7 @@
 				    struct device_attribute *attr,
 				    const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 	uint8_t idx;
 
@@ -845,6 +812,7 @@
 static ssize_t etm_show_addr_stop(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 	uint8_t idx;
 
@@ -865,6 +833,7 @@
 				  struct device_attribute *attr,
 				  const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 	uint8_t idx;
 
@@ -892,6 +861,7 @@
 static ssize_t etm_show_addr_acctype(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	mutex_lock(&drvdata->mutex);
@@ -904,6 +874,7 @@
 				      struct device_attribute *attr,
 				      const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -920,7 +891,9 @@
 static ssize_t etm_show_cntr_idx(struct device *dev,
 				 struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->addr_idx;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -928,6 +901,7 @@
 				  struct device_attribute *attr,
 				  const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -949,7 +923,9 @@
 static ssize_t etm_show_cntr_rld_val(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
+
 	mutex_lock(&drvdata->mutex);
 	val = drvdata->cntr_rld_val[drvdata->cntr_idx];
 	mutex_unlock(&drvdata->mutex);
@@ -960,6 +936,7 @@
 				      struct device_attribute *attr,
 				      const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -976,6 +953,7 @@
 static ssize_t etm_show_cntr_event(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	mutex_lock(&drvdata->mutex);
@@ -988,6 +966,7 @@
 				    struct device_attribute *attr,
 				    const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -1004,6 +983,7 @@
 static ssize_t etm_show_cntr_rld_event(struct device *dev,
 				       struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	mutex_lock(&drvdata->mutex);
@@ -1016,6 +996,7 @@
 					struct device_attribute *attr,
 					const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -1032,6 +1013,7 @@
 static ssize_t etm_show_cntr_val(struct device *dev,
 				 struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	mutex_lock(&drvdata->mutex);
@@ -1044,6 +1026,7 @@
 				  struct device_attribute *attr,
 				  const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -1060,7 +1043,9 @@
 static ssize_t etm_show_seq_12_event(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->seq_12_event;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -1068,6 +1053,7 @@
 				      struct device_attribute *attr,
 				      const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -1082,7 +1068,9 @@
 static ssize_t etm_show_seq_21_event(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->seq_21_event;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -1090,6 +1078,7 @@
 				      struct device_attribute *attr,
 				      const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -1104,7 +1093,9 @@
 static ssize_t etm_show_seq_23_event(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->seq_23_event;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -1112,6 +1103,7 @@
 				      struct device_attribute *attr,
 				      const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -1126,7 +1118,9 @@
 static ssize_t etm_show_seq_31_event(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->seq_31_event;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -1134,6 +1128,7 @@
 				      struct device_attribute *attr,
 				      const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -1148,7 +1143,9 @@
 static ssize_t etm_show_seq_32_event(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->seq_32_event;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -1156,6 +1153,7 @@
 				      struct device_attribute *attr,
 				      const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -1170,7 +1168,9 @@
 static ssize_t etm_show_seq_13_event(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->seq_13_event;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -1178,6 +1178,7 @@
 				      struct device_attribute *attr,
 				      const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -1192,7 +1193,9 @@
 static ssize_t etm_show_seq_curr_state(struct device *dev,
 				       struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->seq_curr_state;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -1200,6 +1203,7 @@
 					struct device_attribute *attr,
 					const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -1216,7 +1220,9 @@
 static ssize_t etm_show_ctxid_idx(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->ctxid_idx;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -1224,6 +1230,7 @@
 				   struct device_attribute *attr,
 				   const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -1245,6 +1252,7 @@
 static ssize_t etm_show_ctxid_val(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	mutex_lock(&drvdata->mutex);
@@ -1257,6 +1265,7 @@
 				   struct device_attribute *attr,
 				   const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -1273,7 +1282,9 @@
 static ssize_t etm_show_ctxid_mask(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->ctxid_mask;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -1281,6 +1292,7 @@
 				    struct device_attribute *attr,
 				    const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -1295,6 +1307,7 @@
 static ssize_t etm_show_sync_freq(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->sync_freq;
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
@@ -1303,6 +1316,7 @@
 				   struct device_attribute *attr,
 				   const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -1318,7 +1332,9 @@
 					struct device_attribute *attr,
 					char *buf)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->timestamp_event;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -1326,6 +1342,7 @@
 					 struct device_attribute *attr,
 					 const char *buf, size_t size)
 {
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -1376,39 +1393,18 @@
 	.attrs = etm_attrs,
 };
 
-static int __devinit etm_sysfs_init(void)
+static const struct attribute_group *etm_attr_grps[] = {
+	&etm_attr_grp,
+	NULL,
+};
+
+/* Memory mapped writes to clear os lock not supported */
+static void etm_os_unlock(void *unused)
 {
-	int ret;
+	unsigned long value = 0x0;
 
-	drvdata->kobj = kobject_create_and_add("etm", qdss_get_modulekobj());
-	if (!drvdata->kobj) {
-		dev_err(drvdata->dev, "failed to create ETM sysfs kobject\n");
-		ret = -ENOMEM;
-		goto err_create;
-	}
-
-	ret = sysfs_create_file(drvdata->kobj, &dev_attr_enabled.attr);
-	if (ret) {
-		dev_err(drvdata->dev, "failed to create ETM sysfs enabled"
-		" attribute\n");
-		goto err_file;
-	}
-
-	if (sysfs_create_group(drvdata->kobj, &etm_attr_grp))
-		dev_err(drvdata->dev, "failed to create ETM sysfs group\n");
-
-	return 0;
-err_file:
-	kobject_put(drvdata->kobj);
-err_create:
-	return ret;
-}
-
-static void __devexit etm_sysfs_exit(void)
-{
-	sysfs_remove_group(drvdata->kobj, &etm_attr_grp);
-	sysfs_remove_file(drvdata->kobj, &dev_attr_enabled.attr);
-	kobject_put(drvdata->kobj);
+	asm("mcr p14, 1, %0, c1, c0, 4\n\t" : : "r" (value));
+	asm("isb\n\t");
 }
 
 static bool __devinit etm_arch_supported(uint8_t arch)
@@ -1422,34 +1418,32 @@
 	return true;
 }
 
-static int __devinit etm_init_arch_data(void)
+static int __devinit etm_init_arch_data(struct etm_drvdata *drvdata)
 {
 	int ret;
-	/* use cpu 0 for setup */
-	int cpu = 0;
 	uint32_t etmidr;
 	uint32_t etmccr;
 
 	/* Unlock OS lock first to allow memory mapped reads and writes */
 	etm_os_unlock(NULL);
 	smp_call_function(etm_os_unlock, NULL, 1);
-	ETM_UNLOCK(cpu);
+	ETM_UNLOCK(drvdata);
 	/* Vote for ETM power/clock enable */
-	etm_clr_pwrdwn(cpu);
+	etm_clr_pwrdwn(drvdata);
 	/* Set prog bit. It will be set from reset but this is included to
 	 * ensure it is set
 	 */
-	etm_set_prog(cpu);
+	etm_set_prog(drvdata);
 
 	/* find all capabilities */
-	etmidr = etm_readl(drvdata, cpu, ETMIDR);
+	etmidr = etm_readl(drvdata, ETMIDR);
 	drvdata->arch = BMVAL(etmidr, 4, 11);
 	if (etm_arch_supported(drvdata->arch) == false) {
 		ret = -EINVAL;
 		goto err;
 	}
 
-	etmccr = etm_readl(drvdata, cpu, ETMCCR);
+	etmccr = etm_readl(drvdata, ETMCCR);
 	drvdata->nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
 	drvdata->nr_cntr = BMVAL(etmccr, 13, 15);
 	drvdata->nr_ext_inp = BMVAL(etmccr, 17, 19);
@@ -1457,15 +1451,15 @@
 	drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
 
 	/* Vote for ETM power/clock disable */
-	etm_set_pwrdwn(cpu);
-	ETM_LOCK(cpu);
+	etm_set_pwrdwn(drvdata);
+	ETM_LOCK(drvdata);
 
 	return 0;
 err:
 	return ret;
 }
 
-static void __devinit etm_init_default_data(void)
+static void __devinit etm_init_default_data(struct etm_drvdata *drvdata)
 {
 	int i;
 
@@ -1489,7 +1483,11 @@
 	drvdata->seq_31_event = 0x406F;
 	drvdata->seq_32_event = 0x406F;
 	drvdata->seq_13_event = 0x406F;
-	drvdata->sync_freq = 0x80;
+	/* Bits[7:0] of ETMSYNCFR are reserved on Krait pass3 onwards */
+	if (cpu_is_krait() && !cpu_is_krait_v1() && !cpu_is_krait_v2())
+		drvdata->sync_freq = 0x100;
+	else
+		drvdata->sync_freq = 0x80;
 	drvdata->timestamp_event = 0x406F;
 
 	/* Overrides for Krait pass1 */
@@ -1511,112 +1509,108 @@
 static int __devinit etm_probe(struct platform_device *pdev)
 {
 	int ret;
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct etm_drvdata *drvdata;
 	struct resource *res;
+	static int etm_count;
+	struct coresight_desc *desc;
 
-	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
-	if (!drvdata) {
-		ret = -ENOMEM;
-		goto err_kzalloc_drvdata;
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
 	}
 
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		ret = -EINVAL;
-		goto err_res;
-	}
+	if (!res)
+		return -ENODEV;
 
-	drvdata->base = ioremap_nocache(res->start, resource_size(res));
-	if (!drvdata->base) {
-		ret = -EINVAL;
-		goto err_ioremap;
-	}
-
-	drvdata->dev = &pdev->dev;
+	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!drvdata->base)
+		return -ENOMEM;
 
 	mutex_init(&drvdata->mutex);
-	wake_lock_init(&drvdata->wake_lock, WAKE_LOCK_SUSPEND, "msm_etm");
+	wake_lock_init(&drvdata->wake_lock, WAKE_LOCK_SUSPEND, "coresight-etm");
 	pm_qos_add_request(&drvdata->qos_req, PM_QOS_CPU_DMA_LATENCY,
 			   PM_QOS_DEFAULT_VALUE);
-	drvdata->src = qdss_get("msm_etm");
-	if (IS_ERR(drvdata->src)) {
-		ret = PTR_ERR(drvdata->src);
-		goto err_qdssget;
-	}
 
-	drvdata->clk = clk_get(drvdata->dev, "core_clk");
+	drvdata->clk = devm_clk_get(dev, "core_clk");
 	if (IS_ERR(drvdata->clk)) {
 		ret = PTR_ERR(drvdata->clk);
-		goto err_clk_get;
+		goto err0;
 	}
 
 	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
 	if (ret)
-		goto err_clk_rate;
+		goto err0;
+
+	drvdata->cpu = etm_count++;
 
 	ret = clk_prepare_enable(drvdata->clk);
 	if (ret)
-		goto err_clk_enable;
+		goto err0;
 
-	ret = etm_init_arch_data();
+	ret = etm_init_arch_data(drvdata);
 	if (ret)
-		goto err_arch;
-
-	etm_init_default_data();
-
-	ret = etm_sysfs_init();
-	if (ret)
-		goto err_sysfs;
-
-	drvdata->enabled = false;
+		goto err1;
+	etm_init_default_data(drvdata);
 
 	clk_disable_unprepare(drvdata->clk);
 
-	dev_info(drvdata->dev, "ETM initialized\n");
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc) {
+		ret = -ENOMEM;
+		goto err0;
+	}
+	desc->type = CORESIGHT_DEV_TYPE_SOURCE;
+	desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
+	desc->ops = &etm_cs_ops;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->groups = etm_attr_grps;
+	desc->owner = THIS_MODULE;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev)) {
+		ret = PTR_ERR(drvdata->csdev);
+		goto err0;
+	}
 
-	if (etm_boot_enable)
-		etm_enable();
+	dev_info(dev, "ETM initialized\n");
+
+	if (boot_enable)
+		coresight_enable(drvdata->csdev);
 
 	return 0;
-
-err_sysfs:
-err_arch:
+err1:
 	clk_disable_unprepare(drvdata->clk);
-err_clk_enable:
-err_clk_rate:
-	clk_put(drvdata->clk);
-err_clk_get:
-	qdss_put(drvdata->src);
-err_qdssget:
+err0:
 	pm_qos_remove_request(&drvdata->qos_req);
 	wake_lock_destroy(&drvdata->wake_lock);
 	mutex_destroy(&drvdata->mutex);
-	iounmap(drvdata->base);
-err_ioremap:
-err_res:
-	kfree(drvdata);
-err_kzalloc_drvdata:
-	dev_err(drvdata->dev, "ETM init failed\n");
 	return ret;
 }
 
 static int __devexit etm_remove(struct platform_device *pdev)
 {
-	if (drvdata->enabled)
-		etm_disable();
-	etm_sysfs_exit();
-	clk_put(drvdata->clk);
-	qdss_put(drvdata->src);
+	struct etm_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	coresight_unregister(drvdata->csdev);
 	pm_qos_remove_request(&drvdata->qos_req);
 	wake_lock_destroy(&drvdata->wake_lock);
 	mutex_destroy(&drvdata->mutex);
-	iounmap(drvdata->base);
-	kfree(drvdata);
-
 	return 0;
 }
 
 static struct of_device_id etm_match[] = {
-	{.compatible = "qcom,msm-etm"},
+	{.compatible = "arm,coresight-etm"},
 	{}
 };
 
@@ -1624,7 +1618,7 @@
 	.probe          = etm_probe,
 	.remove         = __devexit_p(etm_remove),
 	.driver         = {
-		.name   = "msm_etm",
+		.name   = "coresight-etm",
 		.owner	= THIS_MODULE,
 		.of_match_table = etm_match,
 	},
diff --git a/drivers/coresight/coresight-funnel.c b/drivers/coresight/coresight-funnel.c
index 79a27f4..3d5c0c2 100644
--- a/drivers/coresight/coresight-funnel.c
+++ b/drivers/coresight/coresight-funnel.c
@@ -20,113 +20,118 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
+#include <linux/of_coresight.h>
 #include <linux/coresight.h>
 
 #include "coresight-priv.h"
 
-#define funnel_writel(drvdata, id, val, off)	\
-			__raw_writel((val), drvdata->base + (SZ_4K * id) + off)
-#define funnel_readl(drvdata, id, off)		\
-			__raw_readl(drvdata->base + (SZ_4K * id) + off)
+#define funnel_writel(drvdata, val, off)	\
+			__raw_writel((val), drvdata->base + off)
+#define funnel_readl(drvdata, off)		\
+			__raw_readl(drvdata->base + off)
 
-#define FUNNEL_FUNCTL			(0x000)
-#define FUNNEL_PRICTL			(0x004)
-#define FUNNEL_ITATBDATA0		(0xEEC)
-#define FUNNEL_ITATBCTR2		(0xEF0)
-#define FUNNEL_ITATBCTR1		(0xEF4)
-#define FUNNEL_ITATBCTR0		(0xEF8)
-
-
-#define FUNNEL_LOCK(id)							\
+#define FUNNEL_LOCK(drvdata)						\
 do {									\
 	mb();								\
-	funnel_writel(drvdata, id, 0x0, CORESIGHT_LAR);			\
+	funnel_writel(drvdata, 0x0, CORESIGHT_LAR);			\
 } while (0)
-#define FUNNEL_UNLOCK(id)						\
+#define FUNNEL_UNLOCK(drvdata)						\
 do {									\
-	funnel_writel(drvdata, id, CORESIGHT_UNLOCK, CORESIGHT_LAR);	\
+	funnel_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);	\
 	mb();								\
 } while (0)
 
-#define FUNNEL_HOLDTIME_MASK		(0xF00)
-#define FUNNEL_HOLDTIME_SHFT		(0x8)
-#define FUNNEL_HOLDTIME			(0x7 << FUNNEL_HOLDTIME_SHFT)
+#define FUNNEL_FUNCTL		(0x000)
+#define FUNNEL_PRICTL		(0x004)
+#define FUNNEL_ITATBDATA0	(0xEEC)
+#define FUNNEL_ITATBCTR2	(0xEF0)
+#define FUNNEL_ITATBCTR1	(0xEF4)
+#define FUNNEL_ITATBCTR0	(0xEF8)
+
+#define FUNNEL_HOLDTIME_MASK	(0xF00)
+#define FUNNEL_HOLDTIME_SHFT	(0x8)
+#define FUNNEL_HOLDTIME		(0x7 << FUNNEL_HOLDTIME_SHFT)
 
 struct funnel_drvdata {
-	void __iomem	*base;
-	bool		enabled;
-	struct mutex	mutex;
-	struct device	*dev;
-	struct kobject	*kobj;
-	struct clk	*clk;
-	uint32_t	priority;
+	void __iomem		*base;
+	struct device		*dev;
+	struct coresight_device	*csdev;
+	struct clk		*clk;
+	uint32_t		priority;
 };
 
-static struct funnel_drvdata *drvdata;
-
-static void __funnel_enable(uint8_t id, uint32_t port_mask)
+static void __funnel_enable(struct funnel_drvdata *drvdata, int port)
 {
 	uint32_t functl;
 
-	FUNNEL_UNLOCK(id);
+	FUNNEL_UNLOCK(drvdata);
 
-	functl = funnel_readl(drvdata, id, FUNNEL_FUNCTL);
+	functl = funnel_readl(drvdata, FUNNEL_FUNCTL);
 	functl &= ~FUNNEL_HOLDTIME_MASK;
 	functl |= FUNNEL_HOLDTIME;
-	functl |= port_mask;
-	funnel_writel(drvdata, id, functl, FUNNEL_FUNCTL);
-	funnel_writel(drvdata, id, drvdata->priority, FUNNEL_PRICTL);
+	functl |= (1 << port);
+	funnel_writel(drvdata, functl, FUNNEL_FUNCTL);
+	funnel_writel(drvdata, drvdata->priority, FUNNEL_PRICTL);
 
-	FUNNEL_LOCK(id);
+	FUNNEL_LOCK(drvdata);
 }
 
-int funnel_enable(uint8_t id, uint32_t port_mask)
+static int funnel_enable(struct coresight_device *csdev, int inport,
+			 int outport)
 {
+	struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 	int ret;
 
 	ret = clk_prepare_enable(drvdata->clk);
 	if (ret)
 		return ret;
 
-	mutex_lock(&drvdata->mutex);
-	__funnel_enable(id, port_mask);
-	drvdata->enabled = true;
-	dev_info(drvdata->dev, "FUNNEL port mask 0x%lx enabled\n",
-					(unsigned long) port_mask);
-	mutex_unlock(&drvdata->mutex);
+	__funnel_enable(drvdata, inport);
 
+	dev_info(drvdata->dev, "FUNNEL inport %d enabled\n", inport);
 	return 0;
 }
 
-static void __funnel_disable(uint8_t id, uint32_t port_mask)
+static void __funnel_disable(struct funnel_drvdata *drvdata, int inport)
 {
 	uint32_t functl;
 
-	FUNNEL_UNLOCK(id);
+	FUNNEL_UNLOCK(drvdata);
 
-	functl = funnel_readl(drvdata, id, FUNNEL_FUNCTL);
-	functl &= ~port_mask;
-	funnel_writel(drvdata, id, functl, FUNNEL_FUNCTL);
+	functl = funnel_readl(drvdata, FUNNEL_FUNCTL);
+	functl &= ~(1 << inport);
+	funnel_writel(drvdata, functl, FUNNEL_FUNCTL);
 
-	FUNNEL_LOCK(id);
+	FUNNEL_LOCK(drvdata);
 }
 
-void funnel_disable(uint8_t id, uint32_t port_mask)
+static void funnel_disable(struct coresight_device *csdev, int inport,
+			   int outport)
 {
-	mutex_lock(&drvdata->mutex);
-	__funnel_disable(id, port_mask);
-	drvdata->enabled = false;
-	dev_info(drvdata->dev, "FUNNEL port mask 0x%lx disabled\n",
-					(unsigned long) port_mask);
-	mutex_unlock(&drvdata->mutex);
+	struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	__funnel_disable(drvdata, inport);
 
 	clk_disable_unprepare(drvdata->clk);
+
+	dev_info(drvdata->dev, "FUNNEL inport %d disabled\n", inport);
 }
 
+static const struct coresight_ops_link funnel_link_ops = {
+	.enable		= funnel_enable,
+	.disable	= funnel_disable,
+};
+
+static const struct coresight_ops funnel_cs_ops = {
+	.link_ops	= &funnel_link_ops,
+};
+
 static ssize_t funnel_show_priority(struct device *dev,
 				    struct device_attribute *attr, char *buf)
 {
+	struct funnel_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->priority;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -134,6 +139,7 @@
 				     struct device_attribute *attr,
 				     const char *buf, size_t size)
 {
+	struct funnel_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -145,107 +151,86 @@
 static DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, funnel_show_priority,
 		   funnel_store_priority);
 
-static int __devinit funnel_sysfs_init(void)
-{
-	int ret;
+static struct attribute *funnel_attrs[] = {
+	&dev_attr_priority.attr,
+	NULL,
+};
 
-	drvdata->kobj = kobject_create_and_add("funnel", qdss_get_modulekobj());
-	if (!drvdata->kobj) {
-		dev_err(drvdata->dev, "failed to create FUNNEL sysfs kobject\n");
-		ret = -ENOMEM;
-		goto err_create;
-	}
+static struct attribute_group funnel_attr_grp = {
+	.attrs = funnel_attrs,
+};
 
-	ret = sysfs_create_file(drvdata->kobj, &dev_attr_priority.attr);
-	if (ret) {
-		dev_err(drvdata->dev, "failed to create FUNNEL sysfs priority"
-		" attribute\n");
-		goto err_file;
-	}
-
-	return 0;
-err_file:
-	kobject_put(drvdata->kobj);
-err_create:
-	return ret;
-}
-
-static void __devexit funnel_sysfs_exit(void)
-{
-	sysfs_remove_file(drvdata->kobj, &dev_attr_priority.attr);
-	kobject_put(drvdata->kobj);
-}
+static const struct attribute_group *funnel_attr_grps[] = {
+	&funnel_attr_grp,
+	NULL,
+};
 
 static int __devinit funnel_probe(struct platform_device *pdev)
 {
 	int ret;
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct funnel_drvdata *drvdata;
 	struct resource *res;
+	struct coresight_desc *desc;
 
-	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
-	if (!drvdata) {
-		ret = -ENOMEM;
-		goto err_kzalloc_drvdata;
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
 	}
 
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		ret = -EINVAL;
-		goto err_res;
-	}
+	if (!res)
+		return -ENODEV;
 
-	drvdata->base = ioremap_nocache(res->start, resource_size(res));
-	if (!drvdata->base) {
-		ret = -EINVAL;
-		goto err_ioremap;
-	}
+	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!drvdata->base)
+		return -ENOMEM;
 
-	drvdata->dev = &pdev->dev;
-
-	mutex_init(&drvdata->mutex);
-
-	drvdata->clk = clk_get(drvdata->dev, "core_clk");
-	if (IS_ERR(drvdata->clk)) {
-		ret = PTR_ERR(drvdata->clk);
-		goto err_clk_get;
-	}
+	drvdata->clk = devm_clk_get(dev, "core_clk");
+	if (IS_ERR(drvdata->clk))
+		return PTR_ERR(drvdata->clk);
 
 	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
 	if (ret)
-		goto err_clk_rate;
+		return ret;
 
-	funnel_sysfs_init();
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+	desc->type = CORESIGHT_DEV_TYPE_LINK;
+	desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG;
+	desc->ops = &funnel_cs_ops;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->groups = funnel_attr_grps;
+	desc->owner = THIS_MODULE;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev))
+		return PTR_ERR(drvdata->csdev);
 
-	dev_info(drvdata->dev, "FUNNEL initialized\n");
+	dev_info(dev, "FUNNEL initialized\n");
 	return 0;
-
-err_clk_rate:
-	clk_put(drvdata->clk);
-err_clk_get:
-	mutex_destroy(&drvdata->mutex);
-	iounmap(drvdata->base);
-err_ioremap:
-err_res:
-	kfree(drvdata);
-err_kzalloc_drvdata:
-	dev_err(drvdata->dev, "FUNNEL init failed\n");
-	return ret;
 }
 
 static int __devexit funnel_remove(struct platform_device *pdev)
 {
-	if (drvdata->enabled)
-		funnel_disable(0x0, 0xFF);
-	funnel_sysfs_exit();
-	clk_put(drvdata->clk);
-	mutex_destroy(&drvdata->mutex);
-	iounmap(drvdata->base);
-	kfree(drvdata);
+	struct funnel_drvdata *drvdata = platform_get_drvdata(pdev);
 
+	coresight_unregister(drvdata->csdev);
 	return 0;
 }
 
 static struct of_device_id funnel_match[] = {
-	{.compatible = "qcom,msm-funnel"},
+	{.compatible = "arm,coresight-funnel"},
 	{}
 };
 
@@ -253,7 +238,7 @@
 	.probe          = funnel_probe,
 	.remove         = __devexit_p(funnel_remove),
 	.driver         = {
-		.name   = "msm_funnel",
+		.name   = "coresight-funnel",
 		.owner	= THIS_MODULE,
 		.of_match_table = funnel_match,
 	},
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
index dab854c..a28a3a5 100644
--- a/drivers/coresight/coresight-priv.h
+++ b/drivers/coresight/coresight-priv.h
@@ -36,13 +36,4 @@
 #define BMVAL(val, lsb, msb)	((val & BM(lsb, msb)) >> lsb)
 #define BVAL(val, n)		((val & BIT(n)) >> n)
 
-int etb_enable(void);
-void etb_disable(void);
-void etb_dump(void);
-void tpiu_disable(void);
-int funnel_enable(uint8_t id, uint32_t port_mask);
-void funnel_disable(uint8_t id, uint32_t port_mask);
-
-struct kobject *qdss_get_modulekobj(void);
-
 #endif
diff --git a/drivers/coresight/coresight-replicator.c b/drivers/coresight/coresight-replicator.c
new file mode 100644
index 0000000..fec76c5
--- /dev/null
+++ b/drivers/coresight/coresight-replicator.c
@@ -0,0 +1,211 @@
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+
+#include "coresight-priv.h"
+
+#define replicator_writel(drvdata, val, off)	\
+				__raw_writel((val), drvdata->base + off)
+#define replicator_readl(drvdata, off)		\
+				__raw_readl(drvdata->base + off)
+
+#define REPLICATOR_LOCK(drvdata)					\
+do {									\
+	mb();								\
+	replicator_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+} while (0)
+#define REPLICATOR_UNLOCK(drvdata)					\
+do {									\
+	replicator_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);	\
+	mb();								\
+} while (0)
+
+#define REPLICATOR_IDFILTER0		(0x000)
+#define REPLICATOR_IDFILTER1		(0x004)
+#define REPLICATOR_ITATBCTR0		(0xEFC)
+#define REPLICATOR_ITATBCTR1		(0xEF8)
+
+struct replicator_drvdata {
+	void __iomem		*base;
+	struct device		*dev;
+	struct coresight_device	*csdev;
+	struct clk		*clk;
+};
+
+static void __replicator_enable(struct replicator_drvdata *drvdata, int outport)
+{
+	REPLICATOR_UNLOCK(drvdata);
+
+	if (outport == 0) {
+		replicator_writel(drvdata, 0x0, REPLICATOR_IDFILTER0);
+		replicator_writel(drvdata, 0xFF, REPLICATOR_IDFILTER1);
+	} else {
+		replicator_writel(drvdata, 0x0, REPLICATOR_IDFILTER1);
+		replicator_writel(drvdata, 0xFF, REPLICATOR_IDFILTER0);
+	}
+
+	REPLICATOR_LOCK(drvdata);
+}
+
+static int replicator_enable(struct coresight_device *csdev, int inport,
+			     int outport)
+{
+	struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	int ret;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		return ret;
+
+	__replicator_enable(drvdata, outport);
+
+	dev_info(drvdata->dev, "REPLICATOR enabled\n");
+	return 0;
+}
+
+static void __replicator_disable(struct replicator_drvdata *drvdata,
+				 int outport)
+{
+	REPLICATOR_UNLOCK(drvdata);
+
+	if (outport == 0)
+		replicator_writel(drvdata, 0xFF, REPLICATOR_IDFILTER0);
+	else
+		replicator_writel(drvdata, 0xFF, REPLICATOR_IDFILTER1);
+
+	REPLICATOR_LOCK(drvdata);
+}
+
+static void replicator_disable(struct coresight_device *csdev, int inport,
+			       int outport)
+{
+	struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	__replicator_disable(drvdata, outport);
+
+	clk_disable_unprepare(drvdata->clk);
+
+	dev_info(drvdata->dev, "REPLICATOR disabled\n");
+}
+
+static const struct coresight_ops_link replicator_link_ops = {
+	.enable		= replicator_enable,
+	.disable	= replicator_disable,
+};
+
+static const struct coresight_ops replicator_cs_ops = {
+	.link_ops	= &replicator_link_ops,
+};
+
+static int __devinit replicator_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct replicator_drvdata *drvdata;
+	struct resource *res;
+	struct coresight_desc *desc;
+
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
+	}
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!drvdata->base)
+		return -ENOMEM;
+
+	drvdata->clk = devm_clk_get(dev, "core_clk");
+	if (IS_ERR(drvdata->clk))
+		return PTR_ERR(drvdata->clk);
+
+	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
+	if (ret)
+		return ret;
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+	desc->type = CORESIGHT_DEV_TYPE_LINK;
+	desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
+	desc->ops = &replicator_cs_ops;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev))
+		return PTR_ERR(drvdata->csdev);
+
+	dev_info(dev, "REPLICATOR initialized\n");
+	return 0;
+}
+
+static int __devexit replicator_remove(struct platform_device *pdev)
+{
+	struct replicator_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	coresight_unregister(drvdata->csdev);
+	return 0;
+}
+
+static struct of_device_id replicator_match[] = {
+	{.compatible = "qcom,coresight-replicator"},
+	{}
+};
+
+static struct platform_driver replicator_driver = {
+	.probe          = replicator_probe,
+	.remove         = __devexit_p(replicator_remove),
+	.driver         = {
+		.name   = "coresight-replicator",
+		.owner	= THIS_MODULE,
+		.of_match_table = replicator_match,
+	},
+};
+
+static int __init replicator_init(void)
+{
+	return platform_driver_register(&replicator_driver);
+}
+module_init(replicator_init);
+
+static void __exit replicator_exit(void)
+{
+	platform_driver_unregister(&replicator_driver);
+}
+module_exit(replicator_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Replicator driver");
diff --git a/drivers/coresight/coresight-stm.c b/drivers/coresight/coresight-stm.c
index 6387947..e366918 100644
--- a/drivers/coresight/coresight-stm.c
+++ b/drivers/coresight/coresight-stm.c
@@ -22,22 +22,69 @@
 #include <linux/miscdevice.h>
 #include <linux/uaccess.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 #include <linux/clk.h>
+#include <linux/of_coresight.h>
 #include <linux/coresight.h>
 #include <linux/coresight-stm.h>
 #include <asm/unaligned.h>
 
 #include "coresight-priv.h"
 
-#define stm_writel(drvdata, val, off)	\
-			__raw_writel((val), drvdata->base + off)
-#define stm_readl(drvdata, val, off)	\
-			__raw_readl(drvdata->base + off)
+#define stm_writel(drvdata, val, off)	__raw_writel((val), drvdata->base + off)
+#define stm_readl(drvdata, off)		__raw_readl(drvdata->base + off)
+
+#define STM_LOCK(drvdata)						\
+do {									\
+	mb();								\
+	stm_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+} while (0)
+#define STM_UNLOCK(drvdata)						\
+do {									\
+	stm_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
+	mb();								\
+} while (0)
+
+#define STMDMASTARTR		(0xC04)
+#define STMDMASTOPR		(0xC08)
+#define STMDMASTATR		(0xC0C)
+#define STMDMACTLR		(0xC10)
+#define STMDMAIDR		(0xCFC)
+#define STMHEER			(0xD00)
+#define STMHETER		(0xD20)
+#define STMHEMCR		(0xD64)
+#define STMHEMASTR		(0xDF4)
+#define STMHEFEAT1R		(0xDF8)
+#define STMHEIDR		(0xDFC)
+#define STMSPER			(0xE00)
+#define STMSPTER		(0xE20)
+#define STMSPSCR		(0xE60)
+#define STMSPMSCR		(0xE64)
+#define STMSPOVERRIDER		(0xE68)
+#define STMSPMOVERRIDER		(0xE6C)
+#define STMSPTRIGCSR		(0xE70)
+#define STMTCSR			(0xE80)
+#define STMTSSTIMR		(0xE84)
+#define STMTSFREQR		(0xE8C)
+#define STMSYNCR		(0xE90)
+#define STMAUXCR		(0xE94)
+#define STMSPFEAT1R		(0xEA0)
+#define STMSPFEAT2R		(0xEA4)
+#define STMSPFEAT3R		(0xEA8)
+#define STMITTRIGGER		(0xEE8)
+#define STMITATBDATA0		(0xEEC)
+#define STMITATBCTR2		(0xEF0)
+#define STMITATBID		(0xEF4)
+#define STMITATBCTR0		(0xEF8)
 
 #define NR_STM_CHANNEL		(32)
 #define BYTES_PER_CHANNEL	(256)
+#define STM_TRACE_BUF_SIZE	(1024)
 
-enum {
+#define OST_START_TOKEN		(0x30)
+#define OST_VERSION		(0x1)
+
+enum stm_pkt_type {
 	STM_PKT_TYPE_DATA	= 0x98,
 	STM_PKT_TYPE_FLAG	= 0xE8,
 	STM_PKT_TYPE_TRIG	= 0xF8,
@@ -47,45 +94,24 @@
 	STM_OPTION_MARKED	= 0x10,
 };
 
-#define STM_TRACE_BUF_SIZE	(1024)
-
-#define OST_START_TOKEN		(0x30)
-#define OST_VERSION		(0x1)
-
-#define stm_channel_addr(ch)						\
-				(drvdata->chs.base + (ch * BYTES_PER_CHANNEL))
+#define stm_channel_addr(drvdata, ch)	(drvdata->chs.base +	\
+					(ch * BYTES_PER_CHANNEL))
 #define stm_channel_off(type, opts)	(type & ~opts)
 
-#define STM_LOCK()							\
-do {									\
-	mb();								\
-	stm_writel(drvdata, 0x0, CORESIGHT_LAR);			\
-} while (0)
-#define STM_UNLOCK()							\
-do {									\
-	stm_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
-	mb();								\
-} while (0)
-
-#define STMSPER		(0xE00)
-#define STMSPTER	(0xE20)
-#define STMTCSR		(0xE80)
-#define STMSYNCR	(0xE90)
-
 #ifdef CONFIG_MSM_QDSS_STM_DEFAULT_ENABLE
-static int stm_boot_enable = 1;
+static int boot_enable = 1;
 #else
-static int stm_boot_enable;
+static int boot_enable;
 #endif
 
 module_param_named(
-	stm_boot_enable, stm_boot_enable, int, S_IRUGO
+	boot_enable, boot_enable, int, S_IRUGO
 );
 
-static int stm_boot_nr_channel;
+static int boot_nr_channel;
 
 module_param_named(
-	stm_boot_nr_channel, stm_boot_nr_channel, int, S_IRUGO
+	boot_nr_channel, boot_nr_channel, int, S_IRUGO
 );
 
 struct channel_space {
@@ -95,99 +121,202 @@
 
 struct stm_drvdata {
 	void __iomem		*base;
-	bool			enabled;
-	struct qdss_source	*src;
 	struct device		*dev;
-	struct kobject		*kobj;
+	struct coresight_device	*csdev;
+	struct miscdevice	miscdev;
 	struct clk		*clk;
-	uint32_t		entity;
+	spinlock_t		spinlock;
 	struct channel_space	chs;
+	bool			enable;
+	uint32_t		entity;
 };
 
-static struct stm_drvdata *drvdata;
+static struct stm_drvdata *stmdrvdata;
 
-static void __stm_enable(void)
+static int stm_hwevent_isenable(struct stm_drvdata *drvdata)
 {
-	STM_UNLOCK();
+	int ret = 0;
 
-	stm_writel(drvdata, 0x80, STMSYNCR);
-	stm_writel(drvdata, 0xFFFFFFFF, STMSPTER);
-	stm_writel(drvdata, 0xFFFFFFFF, STMSPER);
-	stm_writel(drvdata, 0x30003, STMTCSR);
+	spin_lock(&drvdata->spinlock);
+	if (drvdata->enable)
+		if (BVAL(stm_readl(drvdata, STMHEMCR), 0))
+			ret = stm_readl(drvdata, STMHEER) == 0 ? 0 : 1;
+	spin_unlock(&drvdata->spinlock);
 
-	STM_LOCK();
-}
-
-static int stm_enable(void)
-{
-	int ret;
-
-	if (drvdata->enabled) {
-		dev_err(drvdata->dev, "STM tracing already enabled\n");
-		ret = -EINVAL;
-		goto err;
-	}
-
-	ret = clk_prepare_enable(drvdata->clk);
-	if (ret)
-		goto err_clk;
-
-	ret = qdss_enable(drvdata->src);
-	if (ret)
-		goto err_qdss;
-
-	__stm_enable();
-
-	drvdata->enabled = true;
-
-	dev_info(drvdata->dev, "STM tracing enabled\n");
-	return 0;
-
-err_qdss:
-	clk_disable_unprepare(drvdata->clk);
-err_clk:
-err:
 	return ret;
 }
 
-static void __stm_disable(void)
+static void __stm_hwevent_enable(struct stm_drvdata *drvdata)
 {
-	STM_UNLOCK();
+	STM_UNLOCK(drvdata);
 
-	stm_writel(drvdata, 0x30000, STMTCSR);
+	stm_writel(drvdata, 0x0, STMHETER);
+	stm_writel(drvdata, 0xFFFFFFFF, STMHEER);
+	stm_writel(drvdata, 0x5, STMHEMCR);
+
+	STM_LOCK(drvdata);
+}
+
+static int stm_hwevent_enable(struct stm_drvdata *drvdata)
+{
+	int ret = 0;
+
+	spin_lock(&drvdata->spinlock);
+	if (drvdata->enable)
+		__stm_hwevent_enable(drvdata);
+	else
+		ret = -EINVAL;
+	spin_unlock(&drvdata->spinlock);
+
+	return ret;
+}
+
+static int stm_port_isenable(struct stm_drvdata *drvdata)
+{
+	int ret = 0;
+
+	spin_lock(&drvdata->spinlock);
+	if (drvdata->enable)
+		ret = stm_readl(drvdata, STMSPER) == 0 ? 0 : 1;
+	spin_unlock(&drvdata->spinlock);
+
+	return ret;
+}
+
+static void __stm_port_enable(struct stm_drvdata *drvdata)
+{
+	STM_UNLOCK(drvdata);
+
+	stm_writel(drvdata, 0xFFFFFFFF, STMSPTER);
+	stm_writel(drvdata, 0xFFFFFFFF, STMSPER);
+
+	STM_LOCK(drvdata);
+}
+
+static int stm_port_enable(struct stm_drvdata *drvdata)
+{
+	int ret = 0;
+
+	spin_lock(&drvdata->spinlock);
+	if (drvdata->enable)
+		__stm_port_enable(drvdata);
+	else
+		ret = -EINVAL;
+	spin_unlock(&drvdata->spinlock);
+
+	return ret;
+}
+
+static void __stm_enable(struct stm_drvdata *drvdata)
+{
+	__stm_hwevent_enable(drvdata);
+	__stm_port_enable(drvdata);
+
+	STM_UNLOCK(drvdata);
+
+	stm_writel(drvdata, 0x80, STMSYNCR);
+	/* SYNCEN is read-only and HWTEN is not implemented */
+	stm_writel(drvdata, 0x30003, STMTCSR);
+
+	STM_LOCK(drvdata);
+}
+
+static int stm_enable(struct coresight_device *csdev)
+{
+	struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	int ret;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		return ret;
+
+	spin_lock(&drvdata->spinlock);
+	__stm_enable(drvdata);
+	drvdata->enable = true;
+	spin_unlock(&drvdata->spinlock);
+
+	dev_info(drvdata->dev, "STM tracing enabled\n");
+	return 0;
+}
+
+static void __stm_hwevent_disable(struct stm_drvdata *drvdata)
+{
+	STM_UNLOCK(drvdata);
+
+	stm_writel(drvdata, 0x0, STMHETER);
+	stm_writel(drvdata, 0x0, STMHEER);
+	stm_writel(drvdata, 0x0, STMHEMCR);
+
+	STM_LOCK(drvdata);
+}
+
+static void stm_hwevent_disable(struct stm_drvdata *drvdata)
+{
+	spin_lock(&drvdata->spinlock);
+	if (drvdata->enable)
+		__stm_hwevent_disable(drvdata);
+	spin_unlock(&drvdata->spinlock);
+}
+
+static void __stm_port_disable(struct stm_drvdata *drvdata)
+{
+	STM_UNLOCK(drvdata);
+
 	stm_writel(drvdata, 0x0, STMSPER);
 	stm_writel(drvdata, 0x0, STMSPTER);
 
-	STM_LOCK();
+	STM_LOCK(drvdata);
 }
 
-static int stm_disable(void)
+static void stm_port_disable(struct stm_drvdata *drvdata)
 {
-	int ret;
+	spin_lock(&drvdata->spinlock);
+	if (drvdata->enable)
+		__stm_port_disable(drvdata);
+	spin_unlock(&drvdata->spinlock);
+}
 
-	if (!drvdata->enabled) {
-		dev_err(drvdata->dev, "STM tracing already disabled\n");
-		ret = -EINVAL;
-		goto err;
-	}
+static void __stm_disable(struct stm_drvdata *drvdata)
+{
+	STM_UNLOCK(drvdata);
 
-	__stm_disable();
+	stm_writel(drvdata, 0x30000, STMTCSR);
 
-	drvdata->enabled = false;
+	STM_LOCK(drvdata);
 
-	qdss_disable(drvdata->src);
+	__stm_hwevent_disable(drvdata);
+	__stm_port_disable(drvdata);
+}
+
+static void stm_disable(struct coresight_device *csdev)
+{
+	struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	spin_lock(&drvdata->spinlock);
+	__stm_disable(drvdata);
+	drvdata->enable = false;
+	spin_unlock(&drvdata->spinlock);
+
+	/* Wait for 100ms so that pending data has been written to HW */
+	msleep(100);
 
 	clk_disable_unprepare(drvdata->clk);
 
 	dev_info(drvdata->dev, "STM tracing disabled\n");
-	return 0;
-
-err:
-	return ret;
 }
 
+static const struct coresight_ops_source stm_source_ops = {
+	.enable		= stm_enable,
+	.disable	= stm_disable,
+};
+
+static const struct coresight_ops stm_cs_ops = {
+	.source_ops	= &stm_source_ops,
+};
+
 static uint32_t stm_channel_alloc(uint32_t off)
 {
+	struct stm_drvdata *drvdata = stmdrvdata;
 	uint32_t ch;
 
 	do {
@@ -201,6 +330,8 @@
 
 static void stm_channel_free(uint32_t ch)
 {
+	struct stm_drvdata *drvdata = stmdrvdata;
+
 	clear_bit(ch, drvdata->chs.bitmap);
 }
 
@@ -301,13 +432,14 @@
 static inline int __stm_trace(uint32_t options, uint8_t entity_id,
 			      uint8_t proto_id, const void *data, uint32_t size)
 {
+	struct stm_drvdata *drvdata = stmdrvdata;
 	int len = 0;
 	uint32_t ch;
 	unsigned long ch_addr;
 
 	/* allocate channel and get the channel address */
 	ch = stm_channel_alloc(0);
-	ch_addr = (unsigned long)stm_channel_addr(ch);
+	ch_addr = (unsigned long)stm_channel_addr(drvdata, ch);
 
 	/* send the ost header */
 	len += stm_trace_ost_header(ch_addr, options, entity_id, proto_id, data,
@@ -344,21 +476,25 @@
 int stm_trace(uint32_t options, uint8_t entity_id, uint8_t proto_id,
 			const void *data, uint32_t size)
 {
+	struct stm_drvdata *drvdata = stmdrvdata;
+
 	/* we don't support sizes more than 24bits (0 to 23) */
-	if (!(drvdata->enabled && (drvdata->entity & entity_id) &&
+	if (!(drvdata && drvdata->enable && (drvdata->entity & entity_id) &&
 	      (size < 0x1000000)))
 		return 0;
 
 	return __stm_trace(options, entity_id, proto_id, data, size);
 }
-EXPORT_SYMBOL(stm_trace);
+EXPORT_SYMBOL_GPL(stm_trace);
 
 static ssize_t stm_write(struct file *file, const char __user *data,
 			 size_t size, loff_t *ppos)
 {
+	struct stm_drvdata *drvdata = container_of(file->private_data,
+						   struct stm_drvdata, miscdev);
 	char *buf;
 
-	if (!drvdata->enabled)
+	if (!drvdata->enable)
 		return -EINVAL;
 
 	if (!(drvdata->entity & OST_ENTITY_DEV_NODE))
@@ -386,49 +522,81 @@
 
 static const struct file_operations stm_fops = {
 	.owner		= THIS_MODULE,
+	.open		= nonseekable_open,
 	.write		= stm_write,
 	.llseek		= no_llseek,
 };
 
-static struct miscdevice stm_misc = {
-	.name		= "msm_stm",
-	.minor		= MISC_DYNAMIC_MINOR,
-	.fops		= &stm_fops,
-};
-
-static ssize_t stm_show_enabled(struct device *dev,
-				struct device_attribute *attr, char *buf)
+static ssize_t stm_show_hwevent_enable(struct device *dev,
+				       struct device_attribute *attr, char *buf)
 {
-	unsigned long val = drvdata->enabled;
+	struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = stm_hwevent_isenable(drvdata);
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
-static ssize_t stm_store_enabled(struct device *dev,
-				 struct device_attribute *attr,
-				const char *buf, size_t size)
+static ssize_t stm_store_hwevent_enable(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t size)
 {
-	int ret = 0;
+	struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
+	int ret = 0;
 
 	if (sscanf(buf, "%lx", &val) != 1)
 		return -EINVAL;
 
 	if (val)
-		ret = stm_enable();
+		ret = stm_hwevent_enable(drvdata);
 	else
-		ret = stm_disable();
+		stm_hwevent_disable(drvdata);
 
 	if (ret)
 		return ret;
 	return size;
 }
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, stm_show_enabled,
-		   stm_store_enabled);
+static DEVICE_ATTR(hwevent_enable, S_IRUGO | S_IWUSR, stm_show_hwevent_enable,
+		   stm_store_hwevent_enable);
+
+static ssize_t stm_show_port_enable(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = stm_port_isenable(drvdata);
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t stm_store_port_enable(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t size)
+{
+	struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+	int ret = 0;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	if (val)
+		ret = stm_port_enable(drvdata);
+	else
+		stm_port_disable(drvdata);
+
+	if (ret)
+		return ret;
+	return size;
+}
+static DEVICE_ATTR(port_enable, S_IRUGO | S_IWUSR, stm_show_port_enable,
+		   stm_store_port_enable);
 
 static ssize_t stm_show_entity(struct device *dev,
 			       struct device_attribute *attr, char *buf)
 {
+	struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val = drvdata->entity;
+
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 
@@ -436,6 +604,7 @@
 				struct device_attribute *attr,
 				const char *buf, size_t size)
 {
+	struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 	unsigned long val;
 
 	if (sscanf(buf, "%lx", &val) != 1)
@@ -447,167 +616,131 @@
 static DEVICE_ATTR(entity, S_IRUGO | S_IWUSR, stm_show_entity,
 		   stm_store_entity);
 
-static int __devinit stm_sysfs_init(void)
-{
-	int ret;
+static struct attribute *stm_attrs[] = {
+	&dev_attr_hwevent_enable.attr,
+	&dev_attr_port_enable.attr,
+	&dev_attr_entity.attr,
+	NULL,
+};
 
-	drvdata->kobj = kobject_create_and_add("stm", qdss_get_modulekobj());
-	if (!drvdata->kobj) {
-		dev_err(drvdata->dev, "failed to create STM sysfs kobject\n");
-		ret = -ENOMEM;
-		goto err_create;
-	}
+static struct attribute_group stm_attr_grp = {
+	.attrs = stm_attrs,
+};
 
-	ret = sysfs_create_file(drvdata->kobj, &dev_attr_enabled.attr);
-	if (ret) {
-		dev_err(drvdata->dev, "failed to create STM sysfs enabled attr\n");
-		goto err_file;
-	}
-
-	if (sysfs_create_file(drvdata->kobj, &dev_attr_entity.attr))
-		dev_err(drvdata->dev, "failed to create STM sysfs entity attr\n");
-
-	return 0;
-err_file:
-	kobject_put(drvdata->kobj);
-err_create:
-	return ret;
-}
-
-static void __devexit stm_sysfs_exit(void)
-{
-	sysfs_remove_file(drvdata->kobj, &dev_attr_entity.attr);
-	sysfs_remove_file(drvdata->kobj, &dev_attr_enabled.attr);
-	kobject_put(drvdata->kobj);
-}
+static const struct attribute_group *stm_attr_grps[] = {
+	&stm_attr_grp,
+	NULL,
+};
 
 static int __devinit stm_probe(struct platform_device *pdev)
 {
 	int ret;
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct stm_drvdata *drvdata;
 	struct resource *res;
 	size_t res_size, bitmap_size;
+	struct coresight_desc *desc;
 
-	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
-	if (!drvdata) {
-		ret = -ENOMEM;
-		goto err_kzalloc_drvdata;
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
 	}
 
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	/* Store the driver data pointer for use in exported functions */
+	stmdrvdata = drvdata;
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		ret = -EINVAL;
-		goto err_res0;
-	}
+	if (!res)
+		return -ENODEV;
 
-	drvdata->base = ioremap_nocache(res->start, resource_size(res));
-	if (!drvdata->base) {
-		ret = -EINVAL;
-		goto err_ioremap0;
-	}
+	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!drvdata->base)
+		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	if (!res) {
-		ret = -EINVAL;
-		goto err_res1;
-	}
+	if (!res)
+		return -ENODEV;
 
-	if (stm_boot_nr_channel) {
-		res_size = min((resource_size_t)(stm_boot_nr_channel *
+	if (boot_nr_channel) {
+		res_size = min((resource_size_t)(boot_nr_channel *
 				  BYTES_PER_CHANNEL), resource_size(res));
-		bitmap_size = stm_boot_nr_channel * sizeof(long);
+		bitmap_size = boot_nr_channel * sizeof(long);
 	} else {
 		res_size = min((resource_size_t)(NR_STM_CHANNEL *
 				 BYTES_PER_CHANNEL), resource_size(res));
 		bitmap_size = NR_STM_CHANNEL * sizeof(long);
 	}
+	drvdata->chs.base = devm_ioremap(dev, res->start, res_size);
+	if (!drvdata->chs.base)
+		return -ENOMEM;
+	drvdata->chs.bitmap = devm_kzalloc(dev, bitmap_size, GFP_KERNEL);
+	if (!drvdata->chs.bitmap)
+		return -ENOMEM;
 
-	drvdata->chs.bitmap = kzalloc(bitmap_size, GFP_KERNEL);
-	if (!drvdata->chs.bitmap) {
-		ret = -ENOMEM;
-		goto err_bitmap;
-	}
+	spin_lock_init(&drvdata->spinlock);
 
-	drvdata->chs.base = ioremap_nocache(res->start, res_size);
-	if (!drvdata->chs.base) {
-		ret = -EINVAL;
-		goto err_ioremap1;
-	}
-
-	drvdata->dev = &pdev->dev;
-
-	ret = misc_register(&stm_misc);
-	if (ret)
-		goto err_misc;
-
-	drvdata->src = qdss_get("msm_stm");
-	if (IS_ERR(drvdata->src)) {
-		ret = PTR_ERR(drvdata->src);
-		goto err_qdssget;
-	}
-
-	drvdata->clk = clk_get(drvdata->dev, "core_clk");
-	if (IS_ERR(drvdata->clk)) {
-		ret = PTR_ERR(drvdata->clk);
-		goto err_clk_get;
-	}
+	drvdata->clk = devm_clk_get(dev, "core_clk");
+	if (IS_ERR(drvdata->clk))
+		return PTR_ERR(drvdata->clk);
 
 	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
 	if (ret)
-		goto err_clk_rate;
+		return ret;
 
 	drvdata->entity = OST_ENTITY_ALL;
 
-	ret = stm_sysfs_init();
-	if (ret)
-		goto err_sysfs;
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+	desc->type = CORESIGHT_DEV_TYPE_SOURCE;
+	desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE;
+	desc->ops = &stm_cs_ops;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->groups = stm_attr_grps;
+	desc->owner = THIS_MODULE;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev))
+		return PTR_ERR(drvdata->csdev);
 
-	if (stm_boot_enable)
-		stm_enable();
+	drvdata->miscdev.name = ((struct coresight_platform_data *)
+				 (pdev->dev.platform_data))->name;
+	drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
+	drvdata->miscdev.fops = &stm_fops;
+	ret = misc_register(&drvdata->miscdev);
+	if (ret)
+		goto err;
 
 	dev_info(drvdata->dev, "STM initialized\n");
+
+	if (boot_enable)
+		coresight_enable(drvdata->csdev);
+
 	return 0;
-
-err_sysfs:
-err_clk_rate:
-	clk_put(drvdata->clk);
-err_clk_get:
-	qdss_put(drvdata->src);
-err_qdssget:
-	misc_deregister(&stm_misc);
-err_misc:
-	iounmap(drvdata->chs.base);
-err_ioremap1:
-	kfree(drvdata->chs.bitmap);
-err_bitmap:
-err_res1:
-	iounmap(drvdata->base);
-err_ioremap0:
-err_res0:
-	kfree(drvdata);
-err_kzalloc_drvdata:
-
-	dev_err(drvdata->dev, "STM init failed\n");
+err:
+	coresight_unregister(drvdata->csdev);
 	return ret;
 }
 
 static int __devexit stm_remove(struct platform_device *pdev)
 {
-	if (drvdata->enabled)
-		stm_disable();
-	stm_sysfs_exit();
-	clk_put(drvdata->clk);
-	qdss_put(drvdata->src);
-	misc_deregister(&stm_misc);
-	iounmap(drvdata->chs.base);
-	kfree(drvdata->chs.bitmap);
-	iounmap(drvdata->base);
-	kfree(drvdata);
+	struct stm_drvdata *drvdata = platform_get_drvdata(pdev);
 
+	misc_deregister(&drvdata->miscdev);
+	coresight_unregister(drvdata->csdev);
 	return 0;
 }
 
 static struct of_device_id stm_match[] = {
-	{.compatible = "qcom,msm-stm"},
+	{.compatible = "arm,coresight-stm"},
 	{}
 };
 
@@ -615,7 +748,7 @@
 	.probe          = stm_probe,
 	.remove         = __devexit_p(stm_remove),
 	.driver         = {
-		.name   = "msm_stm",
+		.name   = "coresight-stm",
 		.owner	= THIS_MODULE,
 		.of_match_table = stm_match,
 	},
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
new file mode 100644
index 0000000..1c85aff
--- /dev/null
+++ b/drivers/coresight/coresight-tmc.c
@@ -0,0 +1,790 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/memory_alloc.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+#include <mach/memory.h>
+
+#include "coresight-priv.h"
+
+#define tmc_writel(drvdata, val, off)	__raw_writel((val), drvdata->base + off)
+#define tmc_readl(drvdata, off)		__raw_readl(drvdata->base + off)
+
+#define TMC_LOCK(drvdata)						\
+do {									\
+	mb();								\
+	tmc_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+} while (0)
+#define TMC_UNLOCK(drvdata)						\
+do {									\
+	tmc_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
+	mb();								\
+} while (0)
+
+#define TMC_RSZ			(0x004)
+#define TMC_STS			(0x00C)
+#define TMC_RRD			(0x010)
+#define TMC_RRP			(0x014)
+#define TMC_RWP			(0x018)
+#define TMC_TRG			(0x01C)
+#define TMC_CTL			(0x020)
+#define TMC_RWD			(0x024)
+#define TMC_MODE		(0x028)
+#define TMC_LBUFLEVEL		(0x02C)
+#define TMC_CBUFLEVEL		(0x030)
+#define TMC_BUFWM		(0x034)
+#define TMC_RRPHI		(0x038)
+#define TMC_RWPHI		(0x03C)
+#define TMC_AXICTL		(0x110)
+#define TMC_DBALO		(0x118)
+#define TMC_DBAHI		(0x11C)
+#define TMC_FFSR		(0x300)
+#define TMC_FFCR		(0x304)
+#define TMC_PSCR		(0x308)
+#define TMC_ITMISCOP0		(0xEE0)
+#define TMC_ITTRFLIN		(0xEE8)
+#define TMC_ITATBDATA0		(0xEEC)
+#define TMC_ITATBCTR2		(0xEF0)
+#define TMC_ITATBCTR1		(0xEF4)
+#define TMC_ITATBCTR0		(0xEF8)
+
+#define BYTES_PER_WORD		4
+
+enum tmc_config_type {
+	TMC_CONFIG_TYPE_ETB,
+	TMC_CONFIG_TYPE_ETR,
+	TMC_CONFIG_TYPE_ETF,
+};
+
+enum tmc_mode {
+	TMC_MODE_CIRCULAR_BUFFER,
+	TMC_MODE_SOFTWARE_FIFO,
+	TMC_MODE_HARDWARE_FIFO,
+};
+
+enum tmc_mem_intf_width {
+	TMC_MEM_INTF_WIDTH_32BITS	= 0x2,
+	TMC_MEM_INTF_WIDTH_64BITS	= 0x3,
+	TMC_MEM_INTF_WIDTH_128BITS	= 0x4,
+	TMC_MEM_INTF_WIDTH_256BITS	= 0x5,
+};
+
+struct tmc_drvdata {
+	void __iomem		*base;
+	struct device		*dev;
+	struct coresight_device	*csdev;
+	struct miscdevice	miscdev;
+	struct clk		*clk;
+	spinlock_t		spinlock;
+	int			read_count;
+	bool			reading;
+	char			*buf;
+	unsigned long		paddr;
+	void __iomem		*vaddr;
+	uint32_t		size;
+	bool			enable;
+	enum tmc_config_type	config_type;
+	uint32_t		trigger_cntr;
+};
+
+static void tmc_wait_for_ready(struct tmc_drvdata *drvdata)
+{
+	int count;
+
+	/* Ensure formatter, unformatter and hardware fifo are empty */
+	for (count = TIMEOUT_US; BVAL(tmc_readl(drvdata, TMC_STS), 2) != 1
+				&& count > 0; count--)
+		udelay(1);
+	WARN(count == 0, "timeout while waiting for TMC ready, TMC_STS: %#x\n",
+	     tmc_readl(drvdata, TMC_STS));
+}
+
+static void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
+{
+	int count;
+	uint32_t ffcr;
+
+	ffcr = tmc_readl(drvdata, TMC_FFCR);
+	ffcr |= BIT(12);
+	tmc_writel(drvdata, ffcr, TMC_FFCR);
+	ffcr |= BIT(6);
+	tmc_writel(drvdata, ffcr, TMC_FFCR);
+	/* Ensure flush completes */
+	for (count = TIMEOUT_US; BVAL(tmc_readl(drvdata, TMC_FFCR), 6) != 0
+				&& count > 0; count--)
+		udelay(1);
+	WARN(count == 0, "timeout while flushing TMC, TMC_FFCR: %#x\n",
+	     tmc_readl(drvdata, TMC_FFCR));
+
+	tmc_wait_for_ready(drvdata);
+}
+
+static void __tmc_enable(struct tmc_drvdata *drvdata)
+{
+	tmc_writel(drvdata, 0x1, TMC_CTL);
+}
+
+static void __tmc_disable(struct tmc_drvdata *drvdata)
+{
+	tmc_writel(drvdata, 0x0, TMC_CTL);
+}
+
+static void __tmc_etb_enable(struct tmc_drvdata *drvdata)
+{
+	/* Zero out the memory to help with debug */
+	memset(drvdata->buf, 0, drvdata->size);
+
+	TMC_UNLOCK(drvdata);
+
+	tmc_writel(drvdata, TMC_MODE_CIRCULAR_BUFFER, TMC_MODE);
+	tmc_writel(drvdata, 0x133, TMC_FFCR);
+	tmc_writel(drvdata, drvdata->trigger_cntr, TMC_TRG);
+	__tmc_enable(drvdata);
+
+	TMC_LOCK(drvdata);
+}
+
+static void __tmc_etr_enable(struct tmc_drvdata *drvdata)
+{
+	uint32_t axictl;
+
+	/* Zero out the memory to help with debug */
+	memset(drvdata->vaddr, 0, drvdata->size);
+
+	TMC_UNLOCK(drvdata);
+
+	tmc_writel(drvdata, drvdata->size / BYTES_PER_WORD, TMC_RSZ);
+	tmc_writel(drvdata, TMC_MODE_CIRCULAR_BUFFER, TMC_MODE);
+
+	axictl = tmc_readl(drvdata, TMC_AXICTL);
+	axictl |= (0xF << 8);
+	tmc_writel(drvdata, axictl, TMC_AXICTL);
+	axictl &= ~(0x1 << 7);
+	tmc_writel(drvdata, axictl, TMC_AXICTL);
+	axictl = (axictl & ~0x3) | 0x2;
+	tmc_writel(drvdata, axictl, TMC_AXICTL);
+
+	tmc_writel(drvdata, drvdata->paddr, TMC_DBALO);
+	tmc_writel(drvdata, 0x0, TMC_DBAHI);
+	tmc_writel(drvdata, 0x133, TMC_FFCR);
+	__tmc_enable(drvdata);
+
+	TMC_LOCK(drvdata);
+}
+
+static void __tmc_etf_enable(struct tmc_drvdata *drvdata)
+{
+	TMC_UNLOCK(drvdata);
+
+	tmc_writel(drvdata, TMC_MODE_HARDWARE_FIFO, TMC_MODE);
+	tmc_writel(drvdata, 0x3, TMC_FFCR);
+	tmc_writel(drvdata, 0x0, TMC_BUFWM);
+	__tmc_enable(drvdata);
+
+	TMC_LOCK(drvdata);
+}
+
+static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
+{
+	int ret;
+	unsigned long flags;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading) {
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		clk_disable_unprepare(drvdata->clk);
+		return -EBUSY;
+	}
+
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+		__tmc_etb_enable(drvdata);
+	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		__tmc_etr_enable(drvdata);
+	} else {
+		if (mode == TMC_MODE_CIRCULAR_BUFFER)
+			__tmc_etb_enable(drvdata);
+		else
+			__tmc_etf_enable(drvdata);
+	}
+	drvdata->enable = true;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC enabled\n");
+	return 0;
+}
+
+static int tmc_enable_sink(struct coresight_device *csdev)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	return tmc_enable(drvdata, TMC_MODE_CIRCULAR_BUFFER);
+}
+
+static int tmc_enable_link(struct coresight_device *csdev, int inport,
+			   int outport)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	return tmc_enable(drvdata, TMC_MODE_HARDWARE_FIFO);
+}
+
+static void __tmc_etb_dump(struct tmc_drvdata *drvdata)
+{
+	enum tmc_mem_intf_width memwidth;
+	uint8_t memwords;
+	char *bufp;
+	uint32_t read_data;
+	int i;
+
+	memwidth = BMVAL(tmc_readl(drvdata, CORESIGHT_DEVID), 8, 10);
+	if (memwidth == TMC_MEM_INTF_WIDTH_32BITS)
+		memwords = 1;
+	else if (memwidth == TMC_MEM_INTF_WIDTH_64BITS)
+		memwords = 2;
+	else if (memwidth == TMC_MEM_INTF_WIDTH_128BITS)
+		memwords = 4;
+	else
+		memwords = 8;
+
+	bufp = drvdata->buf;
+	while (1) {
+		for (i = 0; i < memwords; i++) {
+			read_data = tmc_readl(drvdata, TMC_RRD);
+			if (read_data == 0xFFFFFFFF)
+				return;
+			memcpy(bufp, &read_data, BYTES_PER_WORD);
+			bufp += BYTES_PER_WORD;
+		}
+	}
+}
+
+static void __tmc_etb_disable(struct tmc_drvdata *drvdata)
+{
+	TMC_UNLOCK(drvdata);
+
+	tmc_flush_and_stop(drvdata);
+	__tmc_etb_dump(drvdata);
+	__tmc_disable(drvdata);
+
+	TMC_LOCK(drvdata);
+}
+
+static void __tmc_etr_dump(struct tmc_drvdata *drvdata)
+{
+	uint32_t rwp, rwphi;
+
+	rwp = tmc_readl(drvdata, TMC_RWP);
+	rwphi = tmc_readl(drvdata, TMC_RWPHI);
+
+	if (BVAL(tmc_readl(drvdata, TMC_STS), 0))
+		drvdata->buf = drvdata->vaddr + rwp;
+	else
+		drvdata->buf = drvdata->vaddr;
+}
+
+static void __tmc_etr_disable(struct tmc_drvdata *drvdata)
+{
+	TMC_UNLOCK(drvdata);
+
+	tmc_flush_and_stop(drvdata);
+	__tmc_etr_dump(drvdata);
+	__tmc_disable(drvdata);
+
+	TMC_LOCK(drvdata);
+}
+
+static void __tmc_etf_disable(struct tmc_drvdata *drvdata)
+{
+	TMC_UNLOCK(drvdata);
+
+	tmc_flush_and_stop(drvdata);
+	__tmc_disable(drvdata);
+
+	TMC_LOCK(drvdata);
+}
+
+static void tmc_disable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading)
+		goto out;
+
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+		__tmc_etb_disable(drvdata);
+	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		__tmc_etr_disable(drvdata);
+	} else {
+		if (mode == TMC_MODE_CIRCULAR_BUFFER)
+			__tmc_etb_disable(drvdata);
+		else
+			__tmc_etf_disable(drvdata);
+	}
+out:
+	drvdata->enable = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	clk_disable_unprepare(drvdata->clk);
+
+	dev_info(drvdata->dev, "TMC disabled\n");
+}
+
+static void tmc_disable_sink(struct coresight_device *csdev)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	tmc_disable(drvdata, TMC_MODE_CIRCULAR_BUFFER);
+}
+
+static void tmc_disable_link(struct coresight_device *csdev, int inport,
+			     int outport)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	tmc_disable(drvdata, TMC_MODE_HARDWARE_FIFO);
+}
+
+static void tmc_abort(struct coresight_device *csdev)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	unsigned long flags;
+	enum tmc_mode mode;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading)
+		goto out0;
+
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+		__tmc_etb_disable(drvdata);
+	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		__tmc_etr_disable(drvdata);
+	} else {
+		mode = tmc_readl(drvdata, TMC_MODE);
+		if (mode == TMC_MODE_CIRCULAR_BUFFER)
+			__tmc_etb_disable(drvdata);
+		else
+			goto out1;
+	}
+out0:
+	drvdata->enable = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC aborted\n");
+	return;
+out1:
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+}
+
+static const struct coresight_ops_sink tmc_sink_ops = {
+	.enable		= tmc_enable_sink,
+	.disable	= tmc_disable_sink,
+	.abort		= tmc_abort,
+};
+
+static const struct coresight_ops_link tmc_link_ops = {
+	.enable		= tmc_enable_link,
+	.disable	= tmc_disable_link,
+};
+
+static const struct coresight_ops tmc_etb_cs_ops = {
+	.sink_ops	= &tmc_sink_ops,
+};
+
+static const struct coresight_ops tmc_etr_cs_ops = {
+	.sink_ops	= &tmc_sink_ops,
+};
+
+static const struct coresight_ops tmc_etf_cs_ops = {
+	.sink_ops	= &tmc_sink_ops,
+	.link_ops	= &tmc_link_ops,
+};
+
+static int tmc_read_prepare(struct tmc_drvdata *drvdata)
+{
+	int ret;
+	unsigned long flags;
+	enum tmc_mode mode;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (!drvdata->enable)
+		goto out;
+
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+		__tmc_etb_disable(drvdata);
+	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		__tmc_etr_disable(drvdata);
+	} else {
+		mode = tmc_readl(drvdata, TMC_MODE);
+		if (mode == TMC_MODE_CIRCULAR_BUFFER) {
+			__tmc_etb_disable(drvdata);
+		} else {
+			ret = -ENODEV;
+			goto err;
+		}
+	}
+out:
+	drvdata->reading = true;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC read start\n");
+	return 0;
+err:
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	return ret;
+}
+
+static void tmc_read_unprepare(struct tmc_drvdata *drvdata)
+{
+	unsigned long flags;
+	enum tmc_mode mode;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (!drvdata->enable)
+		goto out;
+
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+		__tmc_etb_enable(drvdata);
+	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		__tmc_etr_enable(drvdata);
+	} else {
+		mode = tmc_readl(drvdata, TMC_MODE);
+		if (mode == TMC_MODE_CIRCULAR_BUFFER)
+			__tmc_etb_enable(drvdata);
+	}
+out:
+	drvdata->reading = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC read end\n");
+}
+
+static int tmc_open(struct inode *inode, struct file *file)
+{
+	struct tmc_drvdata *drvdata = container_of(file->private_data,
+						   struct tmc_drvdata, miscdev);
+	int ret = 0;
+
+	if (drvdata->read_count++)
+		goto out;
+
+	ret = tmc_read_prepare(drvdata);
+	if (ret)
+		return ret;
+out:
+	nonseekable_open(inode, file);
+
+	dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
+	return 0;
+}
+
+static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
+			loff_t *ppos)
+{
+	struct tmc_drvdata *drvdata = container_of(file->private_data,
+						   struct tmc_drvdata, miscdev);
+	char *bufp = drvdata->buf + *ppos;
+
+	if (*ppos + len > drvdata->size)
+		len = drvdata->size - *ppos;
+
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		if (bufp == (char *)(drvdata->vaddr + drvdata->size))
+			bufp = drvdata->vaddr;
+		if ((bufp + len) > (char *)(drvdata->vaddr + drvdata->size))
+			len = (char *)(drvdata->vaddr + drvdata->size) - bufp;
+	}
+
+	if (copy_to_user(data, bufp, len)) {
+		dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__);
+		return -EFAULT;
+	}
+
+	*ppos += len;
+
+	dev_dbg(drvdata->dev, "%s: %d bytes copied, %d bytes left\n",
+		__func__, len, (int) (drvdata->size - *ppos));
+	return len;
+}
+
+static int tmc_release(struct inode *inode, struct file *file)
+{
+	struct tmc_drvdata *drvdata = container_of(file->private_data,
+						   struct tmc_drvdata, miscdev);
+
+	if (--drvdata->read_count) {
+		if (drvdata->read_count < 0) {
+			WARN_ONCE(1, "mismatched close\n");
+			drvdata->read_count = 0;
+		}
+		goto out;
+	}
+
+	tmc_read_unprepare(drvdata);
+out:
+	dev_dbg(drvdata->dev, "%s: released\n", __func__);
+	return 0;
+}
+
+static const struct file_operations tmc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= tmc_open,
+	.read		= tmc_read,
+	.release	= tmc_release,
+	.llseek		= no_llseek,
+};
+
+static ssize_t tmc_show_trigger_cntr(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->trigger_cntr;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t tmc_store_trigger_cntr(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t size)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->trigger_cntr = val;
+	return size;
+}
+static DEVICE_ATTR(trigger_cntr, S_IRUGO | S_IWUSR, tmc_show_trigger_cntr,
+		   tmc_store_trigger_cntr);
+
+static struct attribute *tmc_attrs[] = {
+	&dev_attr_trigger_cntr.attr,
+	NULL,
+};
+
+static struct attribute_group tmc_attr_grp = {
+	.attrs = tmc_attrs,
+};
+
+static const struct attribute_group *tmc_etb_attr_grps[] = {
+	&tmc_attr_grp,
+	NULL,
+};
+
+static const struct attribute_group *tmc_etr_attr_grps[] = {
+	&tmc_attr_grp,
+	NULL,
+};
+
+static const struct attribute_group *tmc_etf_attr_grps[] = {
+	&tmc_attr_grp,
+	NULL,
+};
+
+static int __devinit tmc_probe(struct platform_device *pdev)
+{
+	int ret;
+	uint32_t devid;
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct tmc_drvdata *drvdata;
+	struct resource *res;
+	struct coresight_desc *desc;
+
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
+	}
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!drvdata->base)
+		return -ENOMEM;
+
+	spin_lock_init(&drvdata->spinlock);
+
+	drvdata->clk = devm_clk_get(dev, "core_clk");
+	if (IS_ERR(drvdata->clk))
+		return PTR_ERR(drvdata->clk);
+
+	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		return ret;
+
+	devid = tmc_readl(drvdata, CORESIGHT_DEVID);
+	drvdata->config_type = BMVAL(devid, 6, 7);
+
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
+		drvdata->size = SZ_1M;
+	else
+		drvdata->size = tmc_readl(drvdata, TMC_RSZ) * BYTES_PER_WORD;
+
+	clk_disable_unprepare(drvdata->clk);
+
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		drvdata->paddr = allocate_contiguous_ebi_nomap(drvdata->size,
+							       SZ_4K);
+		if (!drvdata->paddr)
+			return -ENOMEM;
+		drvdata->vaddr = devm_ioremap(dev, drvdata->paddr,
+					      drvdata->size);
+		if (!drvdata->vaddr) {
+			ret = -ENOMEM;
+			goto err0;
+		}
+		memset(drvdata->vaddr, 0, drvdata->size);
+	} else {
+		drvdata->buf = devm_kzalloc(dev, drvdata->size, GFP_KERNEL);
+		if (!drvdata->buf)
+			return -ENOMEM;
+	}
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc) {
+		ret = -ENOMEM;
+		goto err0;
+	}
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+		desc->type = CORESIGHT_DEV_TYPE_SINK;
+		desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
+		desc->ops = &tmc_etb_cs_ops;
+		desc->pdata = pdev->dev.platform_data;
+		desc->dev = &pdev->dev;
+		desc->groups = tmc_etb_attr_grps;
+		desc->owner = THIS_MODULE;
+		drvdata->csdev = coresight_register(desc);
+		if (IS_ERR(drvdata->csdev)) {
+			ret = PTR_ERR(drvdata->csdev);
+			goto err0;
+		}
+	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		desc->type = CORESIGHT_DEV_TYPE_SINK;
+		desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
+		desc->ops = &tmc_etr_cs_ops;
+		desc->pdata = pdev->dev.platform_data;
+		desc->dev = &pdev->dev;
+		desc->groups = tmc_etr_attr_grps;
+		desc->owner = THIS_MODULE;
+		drvdata->csdev = coresight_register(desc);
+		if (IS_ERR(drvdata->csdev)) {
+			ret = PTR_ERR(drvdata->csdev);
+			goto err0;
+		}
+	} else {
+		desc->type = CORESIGHT_DEV_TYPE_LINKSINK;
+		desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
+		desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;
+		desc->ops = &tmc_etf_cs_ops;
+		desc->pdata = pdev->dev.platform_data;
+		desc->dev = &pdev->dev;
+		desc->groups = tmc_etf_attr_grps;
+		desc->owner = THIS_MODULE;
+		drvdata->csdev = coresight_register(desc);
+		if (IS_ERR(drvdata->csdev)) {
+			ret = PTR_ERR(drvdata->csdev);
+			goto err0;
+		}
+	}
+
+	drvdata->miscdev.name = ((struct coresight_platform_data *)
+				 (pdev->dev.platform_data))->name;
+	drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
+	drvdata->miscdev.fops = &tmc_fops;
+	ret = misc_register(&drvdata->miscdev);
+	if (ret)
+		goto err1;
+
+	dev_info(dev, "TMC initialized\n");
+	return 0;
+err1:
+	coresight_unregister(drvdata->csdev);
+err0:
+	free_contiguous_memory_by_paddr(drvdata->paddr);
+	return ret;
+}
+
+static int __devexit tmc_remove(struct platform_device *pdev)
+{
+	struct tmc_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	misc_deregister(&drvdata->miscdev);
+	coresight_unregister(drvdata->csdev);
+	free_contiguous_memory_by_paddr(drvdata->paddr);
+	return 0;
+}
+
+static struct of_device_id tmc_match[] = {
+	{.compatible = "arm,coresight-tmc"},
+	{}
+};
+
+static struct platform_driver tmc_driver = {
+	.probe          = tmc_probe,
+	.remove         = __devexit_p(tmc_remove),
+	.driver         = {
+		.name   = "coresight-tmc",
+		.owner	= THIS_MODULE,
+		.of_match_table = tmc_match,
+	},
+};
+
+static int __init tmc_init(void)
+{
+	return platform_driver_register(&tmc_driver);
+}
+module_init(tmc_init);
+
+static void __exit tmc_exit(void)
+{
+	platform_driver_unregister(&tmc_driver);
+}
+module_exit(tmc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Trace Memory Controller driver");
diff --git a/drivers/coresight/coresight-tpiu.c b/drivers/coresight/coresight-tpiu.c
index c0bcfdd..290ae7f 100644
--- a/drivers/coresight/coresight-tpiu.c
+++ b/drivers/coresight/coresight-tpiu.c
@@ -19,6 +19,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
+#include <linux/of_coresight.h>
 #include <linux/coresight.h>
 
 #include "coresight-priv.h"
@@ -26,135 +27,182 @@
 #define tpiu_writel(drvdata, val, off)	__raw_writel((val), drvdata->base + off)
 #define tpiu_readl(drvdata, off)	__raw_readl(drvdata->base + off)
 
-#define TPIU_SUPP_PORTSZ				(0x000)
-#define TPIU_CURR_PORTSZ				(0x004)
-#define TPIU_SUPP_TRIGMODES				(0x100)
-#define TPIU_TRIG_CNTRVAL				(0x104)
-#define TPIU_TRIG_MULT					(0x108)
-#define TPIU_SUPP_TESTPATM				(0x200)
-#define TPIU_CURR_TESTPATM				(0x204)
-#define TPIU_TEST_PATREPCNTR				(0x208)
-#define TPIU_FFSR					(0x300)
-#define TPIU_FFCR					(0x304)
-#define TPIU_FSYNC_CNTR					(0x308)
-#define TPIU_EXTCTL_INPORT				(0x400)
-#define TPIU_EXTCTL_OUTPORT				(0x404)
-#define TPIU_ITTRFLINACK				(0xEE4)
-#define TPIU_ITTRFLIN					(0xEE8)
-#define TPIU_ITATBDATA0					(0xEEC)
-#define TPIU_ITATBCTR2					(0xEF0)
-#define TPIU_ITATBCTR1					(0xEF4)
-#define TPIU_ITATBCTR0					(0xEF8)
-
-
-#define TPIU_LOCK()							\
+#define TPIU_LOCK(drvdata)						\
 do {									\
 	mb();								\
 	tpiu_writel(drvdata, 0x0, CORESIGHT_LAR);			\
 } while (0)
-#define TPIU_UNLOCK()							\
+#define TPIU_UNLOCK(drvdata)						\
 do {									\
 	tpiu_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
 	mb();								\
 } while (0)
 
+#define TPIU_SUPP_PORTSZ	(0x000)
+#define TPIU_CURR_PORTSZ	(0x004)
+#define TPIU_SUPP_TRIGMODES	(0x100)
+#define TPIU_TRIG_CNTRVAL	(0x104)
+#define TPIU_TRIG_MULT		(0x108)
+#define TPIU_SUPP_TESTPATM	(0x200)
+#define TPIU_CURR_TESTPATM	(0x204)
+#define TPIU_TEST_PATREPCNTR	(0x208)
+#define TPIU_FFSR		(0x300)
+#define TPIU_FFCR		(0x304)
+#define TPIU_FSYNC_CNTR		(0x308)
+#define TPIU_EXTCTL_INPORT	(0x400)
+#define TPIU_EXTCTL_OUTPORT	(0x404)
+#define TPIU_ITTRFLINACK	(0xEE4)
+#define TPIU_ITTRFLIN		(0xEE8)
+#define TPIU_ITATBDATA0		(0xEEC)
+#define TPIU_ITATBCTR2		(0xEF0)
+#define TPIU_ITATBCTR1		(0xEF4)
+#define TPIU_ITATBCTR0		(0xEF8)
+
 struct tpiu_drvdata {
-	void __iomem	*base;
-	bool		enabled;
-	struct device	*dev;
-	struct clk	*clk;
+	void __iomem		*base;
+	struct device		*dev;
+	struct coresight_device	*csdev;
+	struct clk		*clk;
 };
 
-static struct tpiu_drvdata *drvdata;
-
-static void __tpiu_disable(void)
+static void __tpiu_enable(struct tpiu_drvdata *drvdata)
 {
-	TPIU_UNLOCK();
+	TPIU_UNLOCK(drvdata);
+
+	/* TODO: fill this up */
+
+	TPIU_LOCK(drvdata);
+}
+
+static int tpiu_enable(struct coresight_device *csdev)
+{
+	struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	int ret;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		return ret;
+
+	__tpiu_enable(drvdata);
+
+	dev_info(drvdata->dev, "TPIU enabled\n");
+	return 0;
+}
+
+static void __tpiu_disable(struct tpiu_drvdata *drvdata)
+{
+	TPIU_UNLOCK(drvdata);
 
 	tpiu_writel(drvdata, 0x3000, TPIU_FFCR);
 	tpiu_writel(drvdata, 0x3040, TPIU_FFCR);
 
-	TPIU_LOCK();
+	TPIU_LOCK(drvdata);
 }
 
-void tpiu_disable(void)
+static void tpiu_disable(struct coresight_device *csdev)
 {
-	__tpiu_disable();
-	drvdata->enabled = false;
+	struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	__tpiu_disable(drvdata);
+
+	clk_disable_unprepare(drvdata->clk);
+
 	dev_info(drvdata->dev, "TPIU disabled\n");
 }
 
+static void tpiu_abort(struct coresight_device *csdev)
+{
+	struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	__tpiu_disable(drvdata);
+
+	dev_info(drvdata->dev, "TPIU aborted\n");
+}
+
+static const struct coresight_ops_sink tpiu_sink_ops = {
+	.enable		= tpiu_enable,
+	.disable	= tpiu_disable,
+	.abort		= tpiu_abort,
+};
+
+static const struct coresight_ops tpiu_cs_ops = {
+	.sink_ops	= &tpiu_sink_ops,
+};
+
 static int __devinit tpiu_probe(struct platform_device *pdev)
 {
 	int ret;
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct tpiu_drvdata *drvdata;
 	struct resource *res;
+	struct coresight_desc *desc;
 
-	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
-	if (!drvdata) {
-		ret = -ENOMEM;
-		goto err_kzalloc_drvdata;
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
 	}
 
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		ret = -EINVAL;
-		goto err_res;
-	}
+	if (!res)
+		return -ENODEV;
 
-	drvdata->base = ioremap_nocache(res->start, resource_size(res));
-	if (!drvdata->base) {
-		ret = -EINVAL;
-		goto err_ioremap;
-	}
+	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!drvdata->base)
+		return -ENOMEM;
 
-	drvdata->dev = &pdev->dev;
-
-	drvdata->clk = clk_get(drvdata->dev, "core_clk");
-	if (IS_ERR(drvdata->clk)) {
-		ret = PTR_ERR(drvdata->clk);
-		goto err_clk_get;
-	}
+	drvdata->clk = devm_clk_get(dev, "core_clk");
+	if (IS_ERR(drvdata->clk))
+		return PTR_ERR(drvdata->clk);
 
 	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
 	if (ret)
-		goto err_clk_rate;
+		return ret;
 
-	/* Disable tpiu to support older targets that need this */
 	ret = clk_prepare_enable(drvdata->clk);
 	if (ret)
-		goto err_clk_enable;
-	__tpiu_disable();
+		return ret;
+
+	/* Disable tpiu to support older targets that need this */
+	__tpiu_disable(drvdata);
+
 	clk_disable_unprepare(drvdata->clk);
 
-	dev_info(drvdata->dev, "TPIU initialized\n");
-	return 0;
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+	desc->type = CORESIGHT_DEV_TYPE_SINK;
+	desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_PORT;
+	desc->ops = &tpiu_cs_ops;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev))
+		return PTR_ERR(drvdata->csdev);
 
-err_clk_enable:
-err_clk_rate:
-	clk_put(drvdata->clk);
-err_clk_get:
-	iounmap(drvdata->base);
-err_ioremap:
-err_res:
-	kfree(drvdata);
-err_kzalloc_drvdata:
-	dev_err(drvdata->dev, "TPIU init failed\n");
-	return ret;
+	dev_info(dev, "TPIU initialized\n");
+	return 0;
 }
 
 static int __devexit tpiu_remove(struct platform_device *pdev)
 {
-	if (drvdata->enabled)
-		tpiu_disable();
-	clk_put(drvdata->clk);
-	iounmap(drvdata->base);
-	kfree(drvdata);
+	struct tpiu_drvdata *drvdata = platform_get_drvdata(pdev);
 
+	coresight_unregister(drvdata->csdev);
 	return 0;
 }
 
 static struct of_device_id tpiu_match[] = {
-	{.compatible = "qcom,msm-tpiu"},
+	{.compatible = "arm,coresight-tpiu"},
 	{}
 };
 
@@ -162,7 +210,7 @@
 	.probe          = tpiu_probe,
 	.remove         = __devexit_p(tpiu_remove),
 	.driver         = {
-		.name   = "msm_tpiu",
+		.name   = "coresight-tpiu",
 		.owner	= THIS_MODULE,
 		.of_match_table = tpiu_match,
 	},
diff --git a/drivers/coresight/coresight.c b/drivers/coresight/coresight.c
index a17ac9a..f76d303 100644
--- a/drivers/coresight/coresight.c
+++ b/drivers/coresight/coresight.c
@@ -26,17 +26,13 @@
 
 #include "coresight-priv.h"
 
-
 #define NO_SINK		(-1)
-#define MAX_STR_LEN	(65535)
-
 
 static int curr_sink = NO_SINK;
 static LIST_HEAD(coresight_orph_conns);
 static LIST_HEAD(coresight_devs);
 static DEFINE_SEMAPHORE(coresight_mutex);
 
-
 static int coresight_find_link_inport(struct coresight_device *csdev)
 {
 	int i;
@@ -343,7 +339,7 @@
 	up(&coresight_mutex);
 	return ret;
 }
-EXPORT_SYMBOL(coresight_enable);
+EXPORT_SYMBOL_GPL(coresight_enable);
 
 void coresight_disable(struct coresight_device *csdev)
 {
@@ -366,7 +362,29 @@
 out:
 	up(&coresight_mutex);
 }
-EXPORT_SYMBOL(coresight_disable);
+EXPORT_SYMBOL_GPL(coresight_disable);
+
+void coresight_abort(void)
+{
+	struct coresight_device *cd;
+
+	if (down_trylock(&coresight_mutex)) {
+		pr_err("coresight: abort could not be processed\n");
+		return;
+	}
+	if (curr_sink == NO_SINK)
+		goto out;
+
+	list_for_each_entry(cd, &coresight_devs, dev_link) {
+		if (cd->id == curr_sink) {
+			if (cd->enable && cd->ops->sink_ops->abort)
+				cd->ops->sink_ops->abort(cd);
+		}
+	}
+out:
+	up(&coresight_mutex);
+}
+EXPORT_SYMBOL_GPL(coresight_abort);
 
 static ssize_t coresight_show_type(struct device *dev,
 				   struct device_attribute *attr, char *buf)
@@ -626,7 +644,7 @@
 err_kzalloc_csdev:
 	return ERR_PTR(ret);
 }
-EXPORT_SYMBOL(coresight_register);
+EXPORT_SYMBOL_GPL(coresight_register);
 
 void coresight_unregister(struct coresight_device *csdev)
 {
@@ -638,7 +656,7 @@
 		put_device(&csdev->dev);
 	}
 }
-EXPORT_SYMBOL(coresight_unregister);
+EXPORT_SYMBOL_GPL(coresight_unregister);
 
 static int __init coresight_init(void)
 {
@@ -653,300 +671,3 @@
 module_exit(coresight_exit);
 
 MODULE_LICENSE("GPL v2");
-/*
- * Exclusion rules for structure fields.
- *
- * S: qdss.sources_mutex protected.
- * I: qdss.sink_mutex protected.
- * C: qdss.clk_mutex protected.
- */
-struct qdss_ctx {
-	struct kobject			*modulekobj;
-	uint8_t				afamily;
-	struct list_head		sources;	/* S: sources list */
-	struct mutex			sources_mutex;
-	uint8_t				sink_count;	/* I: sink count */
-	struct mutex			sink_mutex;
-	uint8_t				max_clk;
-	struct clk			*clk;
-};
-
-static struct qdss_ctx qdss;
-
-/**
- * qdss_get - get the qdss source handle
- * @name: name of the qdss source
- *
- * Searches the sources list to get the qdss source handle for this source.
- *
- * CONTEXT:
- * Typically called from init or probe functions
- *
- * RETURNS:
- * pointer to struct qdss_source on success, %NULL on failure
- */
-struct qdss_source *qdss_get(const char *name)
-{
-	struct qdss_source *src, *source = NULL;
-
-	mutex_lock(&qdss.sources_mutex);
-	list_for_each_entry(src, &qdss.sources, link) {
-		if (src->name) {
-			if (strncmp(src->name, name, MAX_STR_LEN))
-				continue;
-			source = src;
-			break;
-		}
-	}
-	mutex_unlock(&qdss.sources_mutex);
-
-	return source ? source : ERR_PTR(-ENOENT);
-}
-EXPORT_SYMBOL(qdss_get);
-
-/**
- * qdss_put - release the qdss source handle
- * @name: name of the qdss source
- *
- * CONTEXT:
- * Typically called from driver remove or exit functions
- */
-void qdss_put(struct qdss_source *src)
-{
-}
-EXPORT_SYMBOL(qdss_put);
-
-/**
- * qdss_enable - enable qdss for the source
- * @src: handle for the source making the call
- *
- * Enables qdss block (relevant funnel ports and sink) if not already
- * enabled, otherwise increments the reference count
- *
- * CONTEXT:
- * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
- *
- * RETURNS:
- * 0 on success, non-zero on failure
- */
-int qdss_enable(struct qdss_source *src)
-{
-	if (!src)
-		return -EINVAL;
-
-	if (qdss.afamily) {
-		mutex_lock(&qdss.sink_mutex);
-		if (qdss.sink_count == 0) {
-			tpiu_disable();
-			/* enable ETB first to avoid losing any trace data */
-			etb_enable();
-		}
-		qdss.sink_count++;
-		mutex_unlock(&qdss.sink_mutex);
-	}
-
-	funnel_enable(0x0, src->fport_mask);
-	return 0;
-}
-EXPORT_SYMBOL(qdss_enable);
-
-/**
- * qdss_disable - disable qdss for the source
- * @src: handle for the source making the call
- *
- * Disables qdss block (relevant funnel ports and sink) if the reference count
- * is one, otherwise decrements the reference count
- *
- * CONTEXT:
- * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
- */
-void qdss_disable(struct qdss_source *src)
-{
-	if (!src)
-		return;
-
-	if (qdss.afamily) {
-		mutex_lock(&qdss.sink_mutex);
-		if (WARN(qdss.sink_count == 0, "qdss is unbalanced\n"))
-			goto out;
-		if (qdss.sink_count == 1) {
-			etb_dump();
-			etb_disable();
-		}
-		qdss.sink_count--;
-		mutex_unlock(&qdss.sink_mutex);
-	}
-
-	funnel_disable(0x0, src->fport_mask);
-	return;
-out:
-	mutex_unlock(&qdss.sink_mutex);
-}
-EXPORT_SYMBOL(qdss_disable);
-
-/**
- * qdss_disable_sink - force disable the current qdss sink(s)
- *
- * Force disable the current qdss sink(s) to stop the sink from accepting any
- * trace generated subsequent to this call. This function should only be used
- * as a way to stop the sink from getting polluted with trace data that is
- * uninteresting after an event of interest has occured.
- *
- * CONTEXT:
- * Can be called from atomic or non-atomic context.
- */
-void qdss_disable_sink(void)
-{
-	if (qdss.afamily) {
-		etb_dump();
-		etb_disable();
-	}
-}
-EXPORT_SYMBOL(qdss_disable_sink);
-
-struct kobject *qdss_get_modulekobj(void)
-{
-	return qdss.modulekobj;
-}
-
-#define QDSS_ATTR(name)						\
-static struct kobj_attribute name##_attr =				\
-		__ATTR(name, S_IRUGO | S_IWUSR, name##_show, name##_store)
-
-static ssize_t max_clk_store(struct kobject *kobj,
-			struct kobj_attribute *attr,
-			const char *buf, size_t n)
-{
-	unsigned long val;
-
-	if (sscanf(buf, "%lx", &val) != 1)
-		return -EINVAL;
-
-	qdss.max_clk = val;
-	return n;
-}
-static ssize_t max_clk_show(struct kobject *kobj,
-			struct kobj_attribute *attr,
-			char *buf)
-{
-	unsigned long val = qdss.max_clk;
-	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
-}
-QDSS_ATTR(max_clk);
-
-static void __devinit qdss_add_sources(struct qdss_source *srcs, size_t num)
-{
-	mutex_lock(&qdss.sources_mutex);
-	while (num--) {
-		list_add_tail(&srcs->link, &qdss.sources);
-		srcs++;
-	}
-	mutex_unlock(&qdss.sources_mutex);
-}
-
-static int __init qdss_sysfs_init(void)
-{
-	int ret;
-
-	qdss.modulekobj = kset_find_obj(module_kset, KBUILD_MODNAME);
-	if (!qdss.modulekobj) {
-		pr_err("failed to find QDSS sysfs module kobject\n");
-		ret = -ENOENT;
-		goto err;
-	}
-
-	ret = sysfs_create_file(qdss.modulekobj, &max_clk_attr.attr);
-	if (ret) {
-		pr_err("failed to create QDSS sysfs max_clk attribute\n");
-		goto err;
-	}
-
-	return 0;
-err:
-	return ret;
-}
-
-static void __devexit qdss_sysfs_exit(void)
-{
-	sysfs_remove_file(qdss.modulekobj, &max_clk_attr.attr);
-}
-
-static int __devinit qdss_probe(struct platform_device *pdev)
-{
-	int ret = 0;
-	struct msm_qdss_platform_data *pdata;
-
-	mutex_init(&qdss.sources_mutex);
-	mutex_init(&qdss.sink_mutex);
-
-	INIT_LIST_HEAD(&qdss.sources);
-
-	pdata = pdev->dev.platform_data;
-	if (!pdata)
-		goto err_pdata;
-
-	qdss.afamily = pdata->afamily;
-	qdss_add_sources(pdata->src_table, pdata->size);
-
-	pr_info("QDSS arch initialized\n");
-	return 0;
-err_pdata:
-	mutex_destroy(&qdss.sink_mutex);
-	mutex_destroy(&qdss.sources_mutex);
-	pr_err("QDSS init failed\n");
-	return ret;
-}
-
-static int __devexit qdss_remove(struct platform_device *pdev)
-{
-	qdss_sysfs_exit();
-	mutex_destroy(&qdss.sink_mutex);
-	mutex_destroy(&qdss.sources_mutex);
-
-	return 0;
-}
-
-static struct of_device_id qdss_match[] = {
-	{.compatible = "qcom,msm-qdss"},
-	{}
-};
-
-static struct platform_driver qdss_driver = {
-	.probe          = qdss_probe,
-	.remove         = __devexit_p(qdss_remove),
-	.driver         = {
-		.name   = "msm_qdss",
-		.owner	= THIS_MODULE,
-		.of_match_table = qdss_match,
-	},
-};
-
-static int __init qdss_init(void)
-{
-	return platform_driver_register(&qdss_driver);
-}
-arch_initcall(qdss_init);
-
-static int __init qdss_module_init(void)
-{
-	int ret;
-
-	ret = qdss_sysfs_init();
-	if (ret)
-		goto err_sysfs;
-
-	pr_info("QDSS module initialized\n");
-	return 0;
-err_sysfs:
-	return ret;
-}
-module_init(qdss_module_init);
-
-static void __exit qdss_exit(void)
-{
-	platform_driver_unregister(&qdss_driver);
-}
-module_exit(qdss_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Qualcomm Debug SubSystem Driver");
diff --git a/drivers/coresight/of_coresight.c b/drivers/coresight/of_coresight.c
new file mode 100644
index 0000000..5c2c525
--- /dev/null
+++ b/drivers/coresight/of_coresight.c
@@ -0,0 +1,99 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/coresight.h>
+
+struct coresight_platform_data *of_get_coresight_platform_data(
+				struct device *dev, struct device_node *node)
+{
+	int i, ret = 0;
+	uint32_t outports_len = 0;
+	struct device_node *child_node;
+	struct coresight_platform_data *pdata;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return ERR_PTR(-ENOMEM);
+
+	ret = of_property_read_u32(node, "coresight-id", &pdata->id);
+	if (ret)
+		return ERR_PTR(ret);
+
+	ret = of_property_read_string(node, "coresight-name", &pdata->name);
+	if (ret)
+		return ERR_PTR(ret);
+
+	ret = of_property_read_u32(node, "coresight-nr-inports",
+				   &pdata->nr_inports);
+	if (ret)
+		return ERR_PTR(ret);
+
+	pdata->nr_outports = 0;
+	if (of_get_property(node, "coresight-outports", &outports_len))
+		pdata->nr_outports = outports_len/sizeof(uint32_t);
+
+	if (pdata->nr_outports) {
+		pdata->outports = devm_kzalloc(dev, pdata->nr_outports *
+					       sizeof(*pdata->outports),
+					       GFP_KERNEL);
+		if (!pdata->outports)
+			return ERR_PTR(-ENOMEM);
+
+		ret = of_property_read_u32_array(node, "coresight-outports",
+						 (u32 *)pdata->outports,
+						 pdata->nr_outports);
+		if (ret)
+			return ERR_PTR(ret);
+
+		pdata->child_ids = devm_kzalloc(dev, pdata->nr_outports *
+						sizeof(*pdata->child_ids),
+						GFP_KERNEL);
+		if (!pdata->child_ids)
+			return ERR_PTR(-ENOMEM);
+
+		for (i = 0; i < pdata->nr_outports; i++) {
+			child_node = of_parse_phandle(node,
+						      "coresight-child-list",
+						      i);
+			if (!child_node)
+				return ERR_PTR(-EINVAL);
+
+			ret = of_property_read_u32(child_node, "coresight-id",
+						   (u32 *)&pdata->child_ids[i]);
+			of_node_put(child_node);
+			if (ret)
+				return ERR_PTR(ret);
+		}
+
+		pdata->child_ports = devm_kzalloc(dev, pdata->nr_outports *
+						  sizeof(*pdata->child_ports),
+						  GFP_KERNEL);
+		if (!pdata->child_ports)
+			return ERR_PTR(-ENOMEM);
+
+		ret = of_property_read_u32_array(node, "coresight-child-ports",
+						 (u32 *)pdata->child_ports,
+						 pdata->nr_outports);
+		if (ret)
+			return ERR_PTR(ret);
+	}
+
+	pdata->default_sink = of_property_read_bool(node,
+						    "coresight-default-sink");
+	return pdata;
+}
+EXPORT_SYMBOL_GPL(of_get_coresight_platform_data);
diff --git a/drivers/gpio/gpio-msm-common.c b/drivers/gpio/gpio-msm-common.c
index fa8239a..46f6460 100644
--- a/drivers/gpio/gpio-msm-common.c
+++ b/drivers/gpio/gpio-msm-common.c
@@ -23,6 +23,7 @@
 #include <linux/irqdomain.h>
 #include <linux/of.h>
 #include <linux/err.h>
+#include <linux/platform_device.h>
 
 #include <asm/mach/irq.h>
 
@@ -299,6 +300,7 @@
 
 	spin_lock_irqsave(&tlmm_lock, irq_flags);
 	__set_bit(gpio, msm_gpio.enabled_irqs);
+	__msm_gpio_set_intr_status(gpio);
 	__msm_gpio_set_intr_cfg_enable(gpio, 1);
 	mb();
 	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
@@ -401,59 +403,6 @@
 	.irq_disable	= msm_gpio_irq_disable,
 };
 
-/*
- * This lock class tells lockdep that GPIO irqs are in a different
- * category than their parent, so it won't report false recursion.
- */
-static struct lock_class_key msm_gpio_lock_class;
-
-/* TODO: This should be a real platform_driver */
-static int __devinit msm_gpio_probe(void)
-{
-	int ret;
-#ifndef CONFIG_OF
-	int irq, i;
-#endif
-
-	spin_lock_init(&tlmm_lock);
-	bitmap_zero(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
-	bitmap_zero(msm_gpio.wake_irqs, NR_MSM_GPIOS);
-	bitmap_zero(msm_gpio.dual_edge_irqs, NR_MSM_GPIOS);
-	ret = gpiochip_add(&msm_gpio.gpio_chip);
-	if (ret < 0)
-		return ret;
-
-#ifndef CONFIG_OF
-	for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
-		irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
-		irq_set_lockdep_class(irq, &msm_gpio_lock_class);
-		irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
-					 handle_level_irq);
-		set_irq_flags(irq, IRQF_VALID);
-	}
-#endif
-	ret = request_irq(TLMM_MSM_SUMMARY_IRQ, msm_summary_irq_handler,
-			IRQF_TRIGGER_HIGH, "msmgpio", NULL);
-	if (ret) {
-		pr_err("Request_irq failed for TLMM_MSM_SUMMARY_IRQ - %d\n",
-				ret);
-		return ret;
-	}
-	return 0;
-}
-
-static int __devexit msm_gpio_remove(void)
-{
-	int ret = gpiochip_remove(&msm_gpio.gpio_chip);
-
-	if (ret < 0)
-		return ret;
-
-	irq_set_handler(TLMM_MSM_SUMMARY_IRQ, NULL);
-
-	return 0;
-}
-
 #ifdef CONFIG_PM
 static int msm_gpio_suspend(void)
 {
@@ -517,22 +466,6 @@
 	.resume = msm_gpio_resume,
 };
 
-static int __init msm_gpio_init(void)
-{
-	msm_gpio_probe();
-	register_syscore_ops(&msm_gpio_syscore_ops);
-	return 0;
-}
-
-static void __exit msm_gpio_exit(void)
-{
-	unregister_syscore_ops(&msm_gpio_syscore_ops);
-	msm_gpio_remove();
-}
-
-postcore_initcall(msm_gpio_init);
-module_exit(msm_gpio_exit);
-
 static void msm_tlmm_set_field(const struct tlmm_field_cfg *configs,
 			       unsigned id, unsigned width, unsigned val)
 {
@@ -593,6 +526,89 @@
 }
 EXPORT_SYMBOL(msm_gpio_install_direct_irq);
 
+/*
+ * This lock class tells lockdep that GPIO irqs are in a different
+ * category than their parent, so it won't report false recursion.
+ */
+static struct lock_class_key msm_gpio_lock_class;
+
+static int __devinit msm_gpio_probe(struct platform_device *pdev)
+{
+	int ret;
+#ifndef CONFIG_OF
+	int irq, i;
+#endif
+	msm_gpio.gpio_chip.dev = &pdev->dev;
+	spin_lock_init(&tlmm_lock);
+	bitmap_zero(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
+	bitmap_zero(msm_gpio.wake_irqs, NR_MSM_GPIOS);
+	bitmap_zero(msm_gpio.dual_edge_irqs, NR_MSM_GPIOS);
+	ret = gpiochip_add(&msm_gpio.gpio_chip);
+	if (ret < 0)
+		return ret;
+
+#ifndef CONFIG_OF
+	for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
+		irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
+		irq_set_lockdep_class(irq, &msm_gpio_lock_class);
+		irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
+					 handle_level_irq);
+		set_irq_flags(irq, IRQF_VALID);
+	}
+#endif
+	ret = request_irq(TLMM_MSM_SUMMARY_IRQ, msm_summary_irq_handler,
+			IRQF_TRIGGER_HIGH, "msmgpio", NULL);
+	if (ret) {
+		pr_err("Request_irq failed for TLMM_MSM_SUMMARY_IRQ - %d\n",
+				ret);
+		return ret;
+	}
+	register_syscore_ops(&msm_gpio_syscore_ops);
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id msm_gpio_of_match[] __devinitdata = {
+	{.compatible = "qcom,msm-gpio", },
+	{ },
+};
+#endif
+
+static int __devexit msm_gpio_remove(struct platform_device *pdev)
+{
+	int ret;
+
+	unregister_syscore_ops(&msm_gpio_syscore_ops);
+	ret = gpiochip_remove(&msm_gpio.gpio_chip);
+	if (ret < 0)
+		return ret;
+	irq_set_handler(TLMM_MSM_SUMMARY_IRQ, NULL);
+
+	return 0;
+}
+
+static struct platform_driver msm_gpio_driver = {
+	.probe = msm_gpio_probe,
+	.remove = __devexit_p(msm_gpio_remove),
+	.driver = {
+		.name = "msmgpio",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(msm_gpio_of_match),
+	},
+};
+
+static void __exit msm_gpio_exit(void)
+{
+	platform_driver_unregister(&msm_gpio_driver);
+}
+module_exit(msm_gpio_exit);
+
+static int __init msm_gpio_init(void)
+{
+	return platform_driver_register(&msm_gpio_driver);
+}
+postcore_initcall(msm_gpio_init);
+
 #ifdef CONFIG_OF
 static int msm_gpio_irq_domain_xlate(struct irq_domain *d,
 				     struct device_node *controller,
diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c
index bac9f8a..943a4a2 100644
--- a/drivers/gpio/gpio-msm-v2.c
+++ b/drivers/gpio/gpio-msm-v2.c
@@ -149,10 +149,8 @@
 {
 	if (val) {
 		set_gpio_bits(INTR_ENABLE, GPIO_INTR_CFG(gpio));
-		__raw_writel(TARGET_PROC_SCORPION, GPIO_INTR_CFG_SU(gpio));
 
 	} else {
-		__raw_writel(TARGET_PROC_NONE, GPIO_INTR_CFG_SU(gpio));
 		clr_gpio_bits(INTR_ENABLE, GPIO_INTR_CFG(gpio));
 	}
 }
@@ -161,6 +159,15 @@
 {
 	unsigned cfg;
 
+	/* RAW_STATUS_EN is left on for all gpio irqs. Due to the
+	 * internal circuitry of TLMM, toggling the RAW_STATUS
+	 * could cause the INTR_STATUS to be set for EDGE interrupts.
+	 */
+	cfg  = __msm_gpio_get_intr_config(gpio);
+	cfg |= INTR_RAW_STATUS_EN;
+	__raw_writel(cfg, GPIO_INTR_CFG(gpio));
+	__raw_writel(TARGET_PROC_SCORPION, GPIO_INTR_CFG_SU(gpio));
+
 	cfg  = __msm_gpio_get_intr_config(gpio);
 	if (type & IRQ_TYPE_EDGE_BOTH)
 		cfg |= INTR_DECT_CTL_EDGE;
@@ -172,23 +179,13 @@
 	else
 		cfg &= ~INTR_POL_CTL_HI;
 
-	/* RAW_STATUS_EN is left on for all gpio irqs. Due to the
-	 * internal circuitry of TLMM, toggling the RAW_STATUS
-	 * could cause the INTR_STATUS to be set for EDGE interrupts.
-	 */
-	cfg |= INTR_RAW_STATUS_EN;
 	__raw_writel(cfg, GPIO_INTR_CFG(gpio));
-
 	/* Sometimes it might take a little while to update
 	 * the interrupt status after the RAW_STATUS is enabled
+	 * We clear the interrupt status before enabling the
+	 * interrupt in the unmask call-back.
 	 */
 	udelay(5);
-
-	/* Clear the interrupt status to clear out any spurious
-	 * irq as a result of the above operation
-	 */
-	__msm_gpio_set_intr_status(gpio);
-
 }
 
 void __gpio_tlmm_config(unsigned config)
diff --git a/drivers/gpio/gpio-msm-v3.c b/drivers/gpio/gpio-msm-v3.c
index 6086de3..26716a0 100644
--- a/drivers/gpio/gpio-msm-v3.c
+++ b/drivers/gpio/gpio-msm-v3.c
@@ -141,7 +141,7 @@
 
 void __msm_gpio_set_intr_status(unsigned gpio)
 {
-	__raw_writel(BIT(INTR_STATUS_BIT), GPIO_INTR_STATUS(gpio));
+	__raw_writel(0, GPIO_INTR_STATUS(gpio));
 }
 
 unsigned __msm_gpio_get_intr_config(unsigned gpio)
@@ -155,11 +155,10 @@
 
 	cfg = __raw_readl(GPIO_INTR_CFG(gpio));
 	if (val) {
-		cfg &= ~(INTR_TARGET_PROC_NONE | INTR_DIR_CONN_EN);
-		cfg |= INTR_ENABLE | INTR_TARGET_PROC_APPS;
+		cfg &= ~INTR_DIR_CONN_EN;
+		cfg |= INTR_ENABLE;
 	} else {
-		cfg &= ~(INTR_TARGET_PROC_APPS | INTR_ENABLE);
-		cfg |= INTR_TARGET_PROC_NONE;
+		cfg &= ~INTR_ENABLE;
 	}
 	__raw_writel(cfg, GPIO_INTR_CFG(gpio));
 }
@@ -168,7 +167,12 @@
 {
 	unsigned cfg;
 
-	cfg = __raw_readl(GPIO_INTR_CFG(gpio));
+	/* RAW_STATUS_EN is left on for all gpio irqs. Due to the
+	 * internal circuitry of TLMM, toggling the RAW_STATUS
+	 * could cause the INTR_STATUS to be set for EDGE interrupts.
+	 */
+	cfg = INTR_RAW_STATUS_EN | INTR_TARGET_PROC_APPS;
+	__raw_writel(cfg, GPIO_INTR_CFG(gpio));
 	cfg &= ~INTR_DECT_CTL_MASK;
 	if (type == IRQ_TYPE_EDGE_RISING)
 		cfg |= INTR_DECT_CTL_POS_EDGE;
@@ -179,27 +183,18 @@
 	else
 		cfg |= INTR_DECT_CTL_LEVEL;
 
-	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
-		cfg |= INTR_POL_CTL_HI;
-	else
+	if (type & IRQ_TYPE_LEVEL_LOW)
 		cfg &= ~INTR_POL_CTL_HI;
+	else
+		cfg |= INTR_POL_CTL_HI;
 
-	/* RAW_STATUS_EN is left on for all gpio irqs. Due to the
-	 * internal circuitry of TLMM, toggling the RAW_STATUS
-	 * could cause the INTR_STATUS to be set for EDGE interrupts.
-	 */
-	cfg |= INTR_RAW_STATUS_EN;
 	__raw_writel(cfg, GPIO_INTR_CFG(gpio));
-
 	/* Sometimes it might take a little while to update
 	 * the interrupt status after the RAW_STATUS is enabled
+	 * We clear the interrupt status before enabling the
+	 * interrupt in the unmask call-back.
 	 */
 	udelay(5);
-
-	/* Clear the interrupt status to clear out any spurious
-	 * irq as a result of the above operation
-	 */
-	__msm_gpio_set_intr_status(gpio);
 }
 
 void __gpio_tlmm_config(unsigned config)
diff --git a/drivers/gpio/qpnp-pin.c b/drivers/gpio/qpnp-pin.c
index bbcba81..7bfb208 100644
--- a/drivers/gpio/qpnp-pin.c
+++ b/drivers/gpio/qpnp-pin.c
@@ -31,6 +31,10 @@
 		((q_spec)->offset + reg_index)
 
 #define Q_REG_STATUS1			0x8
+#define Q_REG_STATUS1_VAL_MASK		0x1
+#define Q_REG_STATUS1_GPIO_EN_MASK	0x2
+#define Q_REG_STATUS1_MPP_EN_MASK	0x80
+
 #define Q_NUM_CTL_REGS			0xD
 
 /* type registers base address offsets */
@@ -39,17 +43,17 @@
 
 /* gpio peripheral type and subtype values */
 #define Q_GPIO_TYPE			0x10
-#define Q_GPIO_SUBTYPE_GPIO_4CH		0x0
-#define Q_GPIO_SUBTYPE_GPIOC_4CH	0x2
-#define Q_GPIO_SUBTYPE_GPIO_8CH		0x4
-#define Q_GPIO_SUBTYPE_GPIOC_8CH	0x6
+#define Q_GPIO_SUBTYPE_GPIO_4CH		0x1
+#define Q_GPIO_SUBTYPE_GPIOC_4CH	0x5
+#define Q_GPIO_SUBTYPE_GPIO_8CH		0x9
+#define Q_GPIO_SUBTYPE_GPIOC_8CH	0xD
 
 /* mpp peripheral type and subtype values */
 #define Q_MPP_TYPE			0x11
-#define Q_MPP_SUBTYPE_4CH_NO_ANA_OUT	0x1
-#define Q_MPP_SUBTYPE_4CH_NO_SINK	0x2
-#define Q_MPP_SUBTYPE_4CH_FULL_FUNC	0x3
-#define Q_MPP_SUBTYPE_8CH_FULL_FUNC	0x7
+#define Q_MPP_SUBTYPE_4CH_NO_ANA_OUT	0x3
+#define Q_MPP_SUBTYPE_4CH_NO_SINK	0x5
+#define Q_MPP_SUBTYPE_4CH_FULL_FUNC	0x7
+#define Q_MPP_SUBTYPE_8CH_FULL_FUNC	0xF
 
 /* control register base address offsets */
 #define Q_REG_MODE_CTL			0x40
@@ -129,7 +133,8 @@
 #define Q_NUM_PARAMS			Q_PIN_CFG_INVALID
 
 /* param error checking */
-#define QPNP_PIN_MODE_INVALID		3
+#define QPNP_PIN_GPIO_MODE_INVALID	3
+#define QPNP_PIN_MPP_MODE_INVALID	7
 #define QPNP_PIN_INVERT_INVALID		2
 #define QPNP_PIN_OUT_BUF_INVALID	3
 #define QPNP_PIN_VIN_4CH_INVALID	5
@@ -225,8 +230,12 @@
 {
 	switch (idx) {
 	case Q_PIN_CFG_MODE:
-		if (val >= QPNP_PIN_MODE_INVALID)
-			return -EINVAL;
+		if (q_spec->type == Q_GPIO_TYPE &&
+		    val >= QPNP_PIN_GPIO_MODE_INVALID)
+				return -EINVAL;
+		else if (q_spec->type == Q_MPP_TYPE &&
+			 val >= QPNP_PIN_MPP_MODE_INVALID)
+				return -EINVAL;
 		break;
 	case Q_PIN_CFG_OUTPUT_TYPE:
 		if (q_spec->type != Q_GPIO_TYPE)
@@ -327,29 +336,40 @@
 	name = (q_spec->type == Q_GPIO_TYPE) ? "gpio" : "mpp";
 
 	if (Q_CHK_INVALID(Q_PIN_CFG_MODE, q_spec, param->mode))
-		pr_err("invalid direction for %s %d\n", name, pin);
+		pr_err("invalid direction value %d for %s %d\n",
+						param->mode, name, pin);
 	else if (Q_CHK_INVALID(Q_PIN_CFG_INVERT, q_spec, param->invert))
-		pr_err("invalid invert polarity for %s %d\n", name, pin);
+		pr_err("invalid invert polarity value %d for %s %d\n",
+						param->invert,  name, pin);
 	else if (Q_CHK_INVALID(Q_PIN_CFG_SELECT, q_spec, param->select))
-		pr_err("invalid source select for %s %d\n", name, pin);
+		pr_err("invalid source select value %d for %s %d\n",
+						param->select, name, pin);
 	else if (Q_CHK_INVALID(Q_PIN_CFG_OUT_STRENGTH,
 						q_spec, param->out_strength))
-		pr_err("invalid out strength for %s %d\n", name, pin);
+		pr_err("invalid out strength value %d for %s %d\n",
+					param->out_strength,  name, pin);
 	else if (Q_CHK_INVALID(Q_PIN_CFG_OUTPUT_TYPE,
 						 q_spec, param->output_type))
-		pr_err("invalid out type for %s %d\n", name, pin);
+		pr_err("invalid out type value %d for %s %d\n",
+					param->output_type,  name, pin);
 	else if (Q_CHK_INVALID(Q_PIN_CFG_VIN_SEL, q_spec, param->vin_sel))
-		pr_err("invalid vin select value for %s %d\n", name, pin);
+		pr_err("invalid vin select %d value for %s %d\n",
+						param->vin_sel, name, pin);
 	else if (Q_CHK_INVALID(Q_PIN_CFG_PULL, q_spec, param->pull))
-		pr_err("invalid pull value for pin %s %d\n", name, pin);
+		pr_err("invalid pull value %d for pin %s %d\n",
+						param->pull,  name, pin);
 	else if (Q_CHK_INVALID(Q_PIN_CFG_MASTER_EN, q_spec, param->master_en))
-		pr_err("invalid master_en value for %s %d\n", name, pin);
+		pr_err("invalid master_en value %d for %s %d\n",
+						param->master_en, name, pin);
 	else if (Q_CHK_INVALID(Q_PIN_CFG_AOUT_REF, q_spec, param->aout_ref))
-		pr_err("invalid aout_reg value for %s %d\n", name, pin);
+		pr_err("invalid aout_reg value %d for %s %d\n",
+						param->aout_ref, name, pin);
 	else if (Q_CHK_INVALID(Q_PIN_CFG_AIN_ROUTE, q_spec, param->ain_route))
-		pr_err("invalid ain_route value for %s %d\n", name, pin);
+		pr_err("invalid ain_route value %d for %s %d\n",
+						param->ain_route, name, pin);
 	else if (Q_CHK_INVALID(Q_PIN_CFG_CS_OUT, q_spec, param->cs_out))
-		pr_err("invalid cs_out value for %s %d\n", name, pin);
+		pr_err("invalid cs_out value %d for %s %d\n",
+						param->cs_out, name, pin);
 	else
 		return 0;
 
@@ -402,39 +422,41 @@
 }
 
 static int qpnp_pin_read_regs(struct qpnp_pin_chip *q_chip,
-			       struct qpnp_pin_spec *q_spec, u16 addr, u8 *buf)
+			      struct qpnp_pin_spec *q_spec)
 {
 	int bytes_left = q_spec->num_ctl_regs;
 	int rc;
-	char *reg_p = &q_spec->regs[0];
+	char *buf_p = &q_spec->regs[0];
+	u16 reg_addr = Q_REG_ADDR(q_spec, Q_REG_MODE_CTL);
 
 	while (bytes_left > 0) {
 		rc = spmi_ext_register_readl(q_chip->spmi->ctrl, q_spec->slave,
-					Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
-					reg_p, bytes_left < 8 ? bytes_left : 8);
+			  reg_addr, buf_p, bytes_left < 8 ? bytes_left : 8);
 		if (rc)
 			return rc;
 		bytes_left -= 8;
-		reg_p += 8;
+		buf_p += 8;
+		reg_addr += 8;
 	}
 	return 0;
 }
 
 static int qpnp_pin_write_regs(struct qpnp_pin_chip *q_chip,
-				struct qpnp_pin_spec *q_spec, u16 addr, u8 *buf)
+			       struct qpnp_pin_spec *q_spec)
 {
 	int bytes_left = q_spec->num_ctl_regs;
 	int rc;
-	char *reg_p = &q_spec->regs[0];
+	char *buf_p = &q_spec->regs[0];
+	u16 reg_addr = Q_REG_ADDR(q_spec, Q_REG_MODE_CTL);
 
 	while (bytes_left > 0) {
 		rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
-					Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
-					reg_p, bytes_left < 8 ? bytes_left : 8);
+			  reg_addr, buf_p, bytes_left < 8 ? bytes_left : 8);
 		if (rc)
 			return rc;
 		bytes_left -= 8;
-		reg_p += 8;
+		buf_p += 8;
+		reg_addr += 8;
 	}
 	return 0;
 }
@@ -445,9 +467,7 @@
 	int rc;
 	struct device *dev = &q_chip->spmi->dev;
 
-	rc = qpnp_pin_read_regs(q_chip, q_spec,
-				 Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
-				 &q_spec->regs[Q_REG_I_MODE_CTL]);
+	rc = qpnp_pin_read_regs(q_chip, q_spec);
 	if (rc)
 		dev_err(dev, "%s: unable to read control regs\n", __func__);
 
@@ -520,9 +540,7 @@
 			  Q_REG_CS_OUT_SHIFT, Q_REG_CS_OUT_MASK,
 			  param->cs_out);
 
-	rc = qpnp_pin_write_regs(q_chip, q_spec,
-				 Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
-				 &q_spec->regs[Q_REG_I_MODE_CTL]);
+	rc = qpnp_pin_write_regs(q_chip, q_spec);
 	if (rc) {
 		dev_err(&q_chip->spmi->dev, "%s: unable to write master enable\n",
 								__func__);
@@ -532,7 +550,7 @@
 	return 0;
 
 gpio_cfg:
-	dev_err(dev, "%s: unable to set default config for pmic gpio %d\n",
+	dev_err(dev, "%s: unable to set default config for pmic pin %d\n",
 						__func__, q_spec->pmic_pin);
 
 	return rc;
@@ -612,7 +630,7 @@
 	int rc, ret_val;
 	struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
 	struct qpnp_pin_spec *q_spec = NULL;
-	u8 buf[1];
+	u8 buf[1], en_mask;
 
 	if (WARN_ON(!q_chip))
 		return -ENODEV;
@@ -624,11 +642,17 @@
 	/* gpio val is from RT status iff input is enabled */
 	if ((q_spec->regs[Q_REG_I_MODE_CTL] & Q_REG_MODE_SEL_MASK)
 						== QPNP_PIN_MODE_DIG_IN) {
-		/* INT_RT_STS */
 		rc = spmi_ext_register_readl(q_chip->spmi->ctrl, q_spec->slave,
 				Q_REG_ADDR(q_spec, Q_REG_STATUS1),
 				&buf[0], 1);
-		return buf[0];
+
+		en_mask = q_spec->type == Q_GPIO_TYPE ?
+				Q_REG_STATUS1_GPIO_EN_MASK :
+				Q_REG_STATUS1_MPP_EN_MASK;
+		if (!(buf[0] & en_mask))
+			return -EPERM;
+
+		return buf[0] & Q_REG_STATUS1_VAL_MASK;
 
 	} else {
 		ret_val = (q_spec->regs[Q_REG_I_MODE_CTL] &
@@ -655,7 +679,7 @@
 			  Q_REG_OUT_INVERT_SHIFT, Q_REG_OUT_INVERT_MASK, 0);
 
 	rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
-			      Q_REG_ADDR(q_spec, Q_REG_I_MODE_CTL),
+			      Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
 			      &q_spec->regs[Q_REG_I_MODE_CTL], 1);
 	if (rc)
 		dev_err(&q_chip->spmi->dev, "%s: spmi write failed\n",
@@ -688,7 +712,7 @@
 	if (!q_chip || !q_spec)
 		return -EINVAL;
 
-	if (mode >= QPNP_PIN_MODE_INVALID) {
+	if (qpnp_pin_check_config(Q_PIN_CFG_MODE, q_spec, mode)) {
 		pr_err("invalid mode specification %d\n", mode);
 		return -EINVAL;
 	}
@@ -699,7 +723,7 @@
 			mode);
 
 	rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
-			      Q_REG_ADDR(q_spec, Q_REG_I_MODE_CTL),
+			      Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
 			      &q_spec->regs[Q_REG_I_MODE_CTL], 1);
 	return rc;
 }
@@ -783,7 +807,7 @@
 				       Q_REG_OUT_TYPE_SHIFT,
 				       Q_REG_OUT_TYPE_MASK);
 	param.invert	   = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
-				       Q_REG_OUT_INVERT_MASK,
+				       Q_REG_OUT_INVERT_SHIFT,
 				       Q_REG_OUT_INVERT_MASK);
 	param.pull	   = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
 				       Q_REG_PULL_SHIFT, Q_REG_PULL_MASK);
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index eec3fe0..c65a000 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -18,15 +18,82 @@
 #include <linux/slab.h>
 #include <linux/memory_alloc.h>
 #include <linux/fmem.h>
+#include <linux/of.h>
 #include <mach/ion.h>
 #include <mach/msm_memtypes.h>
 #include "../ion_priv.h"
 #include "ion_cp_common.h"
 
+#define ION_COMPAT_STR	"qcom,msm-ion"
+#define ION_COMPAT_MEM_RESERVE_STR "qcom,msm-ion-reserve"
+
 static struct ion_device *idev;
 static int num_heaps;
 static struct ion_heap **heaps;
 
+struct ion_heap_desc {
+	unsigned int id;
+	enum ion_heap_type type;
+	const char *name;
+	unsigned int permission_type;
+};
+
+
+static struct ion_heap_desc ion_heap_meta[] = {
+	{
+		.id	= ION_SYSTEM_HEAP_ID,
+		.type	= ION_HEAP_TYPE_SYSTEM,
+		.name	= ION_VMALLOC_HEAP_NAME,
+	},
+	{
+		.id	= ION_CP_MM_HEAP_ID,
+		.type	= ION_HEAP_TYPE_CP,
+		.name	= ION_MM_HEAP_NAME,
+		.permission_type = IPT_TYPE_MM_CARVEOUT,
+	},
+	{
+		.id	= ION_MM_FIRMWARE_HEAP_ID,
+		.type	= ION_HEAP_TYPE_CARVEOUT,
+		.name	= ION_MM_FIRMWARE_HEAP_NAME,
+	},
+	{
+		.id	= ION_CP_MFC_HEAP_ID,
+		.type	= ION_HEAP_TYPE_CP,
+		.name	= ION_MFC_HEAP_NAME,
+		.permission_type = IPT_TYPE_MFC_SHAREDMEM,
+	},
+	{
+		.id	= ION_SF_HEAP_ID,
+		.type	= ION_HEAP_TYPE_CARVEOUT,
+		.name	= ION_SF_HEAP_NAME,
+	},
+	{
+		.id	= ION_IOMMU_HEAP_ID,
+		.type	= ION_HEAP_TYPE_IOMMU,
+		.name	= ION_IOMMU_HEAP_NAME,
+	},
+	{
+		.id	= ION_QSECOM_HEAP_ID,
+		.type	= ION_HEAP_TYPE_CARVEOUT,
+		.name	= ION_QSECOM_HEAP_NAME,
+	},
+	{
+		.id	= ION_AUDIO_HEAP_ID,
+		.type	= ION_HEAP_TYPE_CARVEOUT,
+		.name	= ION_AUDIO_HEAP_NAME,
+	},
+	{
+		.id	= ION_CP_WB_HEAP_ID,
+		.type	= ION_HEAP_TYPE_CP,
+		.name	= ION_WB_HEAP_NAME,
+	},
+	{
+		.id	= ION_CAMERA_HEAP_ID,
+		.type	= ION_HEAP_TYPE_CARVEOUT,
+		.name	= ION_CAMERA_HEAP_NAME,
+	},
+};
+
 struct ion_client *msm_ion_client_create(unsigned int heap_mask,
 					const char *name)
 {
@@ -269,11 +336,243 @@
 	}
 }
 
+static int msm_init_extra_data(struct ion_platform_heap *heap,
+			       const struct ion_heap_desc *heap_desc)
+{
+	int ret = 0;
+
+	switch (heap->type) {
+	case ION_HEAP_TYPE_CP:
+	{
+		heap->extra_data = kzalloc(sizeof(struct ion_cp_heap_pdata),
+					   GFP_KERNEL);
+		if (!heap->extra_data) {
+			ret = -ENOMEM;
+		} else {
+			struct ion_cp_heap_pdata *extra = heap->extra_data;
+			extra->permission_type = heap_desc->permission_type;
+		}
+		break;
+	}
+	case ION_HEAP_TYPE_CARVEOUT:
+	{
+		heap->extra_data = kzalloc(sizeof(struct ion_co_heap_pdata),
+					   GFP_KERNEL);
+		if (!heap->extra_data)
+			ret = -ENOMEM;
+		break;
+	}
+	default:
+		heap->extra_data = 0;
+		break;
+	}
+	return ret;
+}
+
+static int msm_ion_populate_heap(struct ion_platform_heap *heap)
+{
+	unsigned int i;
+	int ret = -EINVAL;
+	unsigned int len = ARRAY_SIZE(ion_heap_meta);
+	for (i = 0; i < len; ++i) {
+		if (ion_heap_meta[i].id == heap->id) {
+			heap->name = ion_heap_meta[i].name;
+			heap->type = ion_heap_meta[i].type;
+			ret = msm_init_extra_data(heap, &ion_heap_meta[i]);
+			break;
+		}
+	}
+	if (ret)
+		pr_err("%s: Unable to populate heap, error: %d", __func__, ret);
+	return ret;
+}
+
+static void free_pdata(const struct ion_platform_data *pdata)
+{
+	unsigned int i;
+	for (i = 0; i < pdata->nr; ++i)
+		kfree(pdata->heaps[i].extra_data);
+	kfree(pdata);
+}
+
+static int memtype_to_ion_memtype[] = {
+	[MEMTYPE_SMI_KERNEL] = ION_SMI_TYPE,
+	[MEMTYPE_SMI]	= ION_SMI_TYPE,
+	[MEMTYPE_EBI0] = ION_EBI_TYPE,
+	[MEMTYPE_EBI1] = ION_EBI_TYPE,
+};
+
+static void msm_ion_get_heap_align(struct device_node *node,
+				   struct ion_platform_heap *heap)
+{
+	unsigned int val;
+
+	int ret = of_property_read_u32(node, "qcom,heap-align", &val);
+	if (!ret) {
+		switch (heap->type) {
+		case ION_HEAP_TYPE_CP:
+		{
+			struct ion_cp_heap_pdata *extra =
+						heap->extra_data;
+			extra->align = val;
+			break;
+		}
+		case ION_HEAP_TYPE_CARVEOUT:
+		{
+			struct ion_co_heap_pdata *extra =
+						heap->extra_data;
+			extra->align = val;
+			break;
+		}
+		default:
+			pr_err("ION-heap %s: Cannot specify alignment for this type of heap\n",
+					heap->name);
+			break;
+		}
+	}
+}
+
+static int msm_ion_get_heap_size(struct device_node *node,
+				 struct ion_platform_heap *heap)
+{
+	unsigned int val;
+	int ret = 0;
+	const char *memory_name_prop;
+
+	ret = of_property_read_u32(node, "qcom,memory-reservation-size", &val);
+	if (!ret) {
+		heap->size = val;
+		ret = of_property_read_string(node,
+					      "qcom,memory-reservation-type",
+					      &memory_name_prop);
+
+		if (!ret && memory_name_prop) {
+			val = msm_get_memory_type_from_name(memory_name_prop);
+			if (val < 0) {
+				ret = -EINVAL;
+				goto out;
+			}
+			heap->memory_type = memtype_to_ion_memtype[val];
+		}
+		if (heap->size && (ret || !memory_name_prop)) {
+			pr_err("%s: Need to specify reservation type\n",
+				__func__);
+			ret = -EINVAL;
+		}
+	} else {
+		ret = 0;
+	}
+out:
+	return ret;
+}
+
+
+static void msm_ion_get_heap_adjacent(struct device_node *node,
+				      struct ion_platform_heap *heap)
+{
+	unsigned int val;
+	int ret = of_property_read_u32(node, "qcom,heap-adjacent", &val);
+	if (!ret) {
+		switch (heap->type) {
+		case ION_HEAP_TYPE_CARVEOUT:
+		{
+			struct ion_co_heap_pdata *extra = heap->extra_data;
+			extra->adjacent_mem_id = val;
+			break;
+		}
+		default:
+			pr_err("ION-heap %s: Cannot specify adjcent mem id for this type of heap\n",
+				heap->name);
+			break;
+		}
+	} else {
+		switch (heap->type) {
+		case ION_HEAP_TYPE_CARVEOUT:
+		{
+			struct ion_co_heap_pdata *extra = heap->extra_data;
+			extra->adjacent_mem_id = INVALID_HEAP_ID;
+			break;
+		}
+		default:
+			break;
+		}
+	}
+}
+
+static struct ion_platform_data *msm_ion_parse_dt(
+					const struct device_node *dt_node)
+{
+	struct ion_platform_data *pdata = 0;
+	struct device_node *node;
+	uint32_t val = 0;
+	int ret = 0;
+	uint32_t num_heaps = 0;
+	int idx = 0;
+
+	for_each_child_of_node(dt_node, node)
+		num_heaps++;
+
+	if (!num_heaps)
+		return ERR_PTR(-EINVAL);
+
+	pdata = kzalloc(sizeof(struct ion_platform_data) +
+			num_heaps*sizeof(struct ion_platform_heap), GFP_KERNEL);
+	if (!pdata)
+		return ERR_PTR(-ENOMEM);
+
+	pdata->nr = num_heaps;
+
+	for_each_child_of_node(dt_node, node) {
+		/**
+		 * TODO: Replace this with of_get_address() when this patch
+		 * gets merged: http://
+		 * permalink.gmane.org/gmane.linux.drivers.devicetree/18614
+		*/
+		ret = of_property_read_u32(node, "reg", &val);
+		if (ret) {
+			pr_err("%s: Unable to find reg key", __func__);
+			goto free_heaps;
+		}
+		pdata->heaps[idx].id = val;
+
+		ret = msm_ion_populate_heap(&pdata->heaps[idx]);
+		if (ret)
+			goto free_heaps;
+
+		msm_ion_get_heap_align(node, &pdata->heaps[idx]);
+
+		ret = msm_ion_get_heap_size(node, &pdata->heaps[idx]);
+		if (ret)
+			goto free_heaps;
+
+		msm_ion_get_heap_adjacent(node, &pdata->heaps[idx]);
+
+		++idx;
+	}
+	return pdata;
+
+free_heaps:
+	free_pdata(pdata);
+	return ERR_PTR(ret);
+}
+
 static int msm_ion_probe(struct platform_device *pdev)
 {
-	struct ion_platform_data *pdata = pdev->dev.platform_data;
-	int err;
+	struct ion_platform_data *pdata;
+	unsigned int pdata_needs_to_be_freed;
+	int err = -1;
 	int i;
+	if (pdev->dev.of_node) {
+		pdata = msm_ion_parse_dt(pdev->dev.of_node);
+		if (IS_ERR(pdata)) {
+			err = PTR_ERR(pdata);
+			goto out;
+		}
+		pdata_needs_to_be_freed = 1;
+	} else {
+		pdata = pdev->dev.platform_data;
+		pdata_needs_to_be_freed = 0;
+	}
 
 	num_heaps = pdata->nr;
 
@@ -315,6 +614,8 @@
 
 		ion_device_add_heap(idev, heaps[i]);
 	}
+	if (pdata_needs_to_be_freed)
+		free_pdata(pdata);
 
 	check_for_heap_overlap(pdata->heaps, num_heaps);
 	platform_set_drvdata(pdev, idev);
@@ -322,6 +623,8 @@
 
 freeheaps:
 	kfree(heaps);
+	if (pdata_needs_to_be_freed)
+		free_pdata(pdata);
 out:
 	return err;
 }
@@ -339,10 +642,19 @@
 	return 0;
 }
 
+static struct of_device_id msm_ion_match_table[] = {
+	{.compatible = ION_COMPAT_STR},
+	{},
+};
+EXPORT_COMPAT(ION_COMPAT_MEM_RESERVE_STR);
+
 static struct platform_driver msm_ion_driver = {
 	.probe = msm_ion_probe,
 	.remove = msm_ion_remove,
-	.driver = { .name = "ion-msm" }
+	.driver = {
+		.name = "ion-msm",
+		.of_match_table = msm_ion_match_table,
+	},
 };
 
 static int __init msm_ion_init(void)
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index 6cdb5f1..c7ed329 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -35,6 +35,7 @@
 
 msm_z180-y += \
 	z180.o \
+	z180_postmortem.o \
 	z180_trace.o
 
 msm_kgsl_core-objs = $(msm_kgsl_core-y)
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 8ec9431..33fcbfd 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -248,6 +248,8 @@
 #define A3XX_VBIF_OUT_WR_LIM_CONF0 0x3035
 #define A3XX_VBIF_DDR_OUT_MAX_BURST 0x3036
 #define A3XX_VBIF_ARB_CTL 0x303C
+#define A3XX_VBIF_ROUND_ROBIN_QOS_ARB 0x3049
+#define A3XX_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x3058
 #define A3XX_VBIF_OUT_AXI_AOOO_EN 0x305E
 #define A3XX_VBIF_OUT_AXI_AOOO 0x305F
 
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 3047693..3d1fbc8 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -15,8 +15,14 @@
 #include <linux/vmalloc.h>
 #include <linux/ioctl.h>
 #include <linux/sched.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <mach/socinfo.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_dcvs.h>
+#include <mach/msm_dcvs_scm.h>
 
 #include "kgsl.h"
 #include "kgsl_pwrscale.h"
@@ -26,8 +32,6 @@
 
 #include "adreno.h"
 #include "adreno_pm4types.h"
-#include "adreno_debugfs.h"
-#include "adreno_postmortem.h"
 
 #include "a2xx_reg.h"
 #include "a3xx_reg.h"
@@ -107,7 +111,7 @@
 	.gmem_size = SZ_256K,
 	.pfp_fw = NULL,
 	.pm4_fw = NULL,
-	.wait_timeout = 10000, /* in milliseconds */
+	.wait_timeout = 0, /* in milliseconds, 0 means disabled */
 	.ib_check_level = 0,
 };
 
@@ -178,7 +182,9 @@
 	{ ADRENO_REV_A320, 3, 2, 0, ANY_ID,
 		"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
 		512, 0, 2, SZ_512K },
-
+	{ ADRENO_REV_A330, 3, 3, 0, 0,
+		"a330_pm4.fw", "a330_pfp.fw", &adreno_a3xx_gpudev,
+		512, 0, 2, SZ_1M },
 };
 
 static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
@@ -647,12 +653,520 @@
 	adreno_dev->gmem_size = adreno_gpulist[i].gmem_size;
 }
 
+static struct platform_device_id adreno_id_table[] = {
+	{ DEVICE_3D0_NAME, (kernel_ulong_t)&device_3d0.dev, },
+	{},
+};
+
+MODULE_DEVICE_TABLE(platform, adreno_id_table);
+
+static struct of_device_id adreno_match_table[] = {
+	{ .compatible = "qcom,kgsl-3d0", },
+	{}
+};
+
+static inline int adreno_of_read_property(struct device_node *node,
+	const char *prop, unsigned int *ptr)
+{
+	int ret = of_property_read_u32(node, prop, ptr);
+	if (ret)
+		KGSL_CORE_ERR("Unable to read '%s'\n", prop);
+	return ret;
+}
+
+static struct device_node *adreno_of_find_subnode(struct device_node *parent,
+	const char *name)
+{
+	struct device_node *child;
+
+	for_each_child_of_node(parent, child) {
+		if (of_device_is_compatible(child, name))
+			return child;
+	}
+
+	return NULL;
+}
+
+static int adreno_of_get_pwrlevels(struct device_node *parent,
+	struct kgsl_device_platform_data *pdata)
+{
+	struct device_node *node, *child;
+	int ret = -EINVAL;
+
+	node = adreno_of_find_subnode(parent, "qcom,gpu-pwrlevels");
+
+	if (node == NULL) {
+		KGSL_CORE_ERR("Unable to find 'qcom,gpu-pwrlevels'\n");
+		return -EINVAL;
+	}
+
+	pdata->num_levels = 0;
+
+	for_each_child_of_node(node, child) {
+		unsigned int index;
+		struct kgsl_pwrlevel *level;
+
+		if (adreno_of_read_property(child, "reg", &index))
+			goto done;
+
+		if (index >= KGSL_MAX_PWRLEVELS) {
+			KGSL_CORE_ERR("Pwrlevel index %d is out of range\n",
+				index);
+			continue;
+		}
+
+		if (index >= pdata->num_levels)
+			pdata->num_levels = index + 1;
+
+		level = &pdata->pwrlevel[index];
+
+		if (adreno_of_read_property(child, "qcom,gpu-freq",
+			&level->gpu_freq))
+			goto done;
+
+		if (adreno_of_read_property(child, "qcom,bus-freq",
+			&level->bus_freq))
+			goto done;
+
+		if (adreno_of_read_property(child, "qcom,io-fraction",
+			&level->io_fraction))
+			level->io_fraction = 0;
+	}
+
+	if (adreno_of_read_property(parent, "qcom,initial-pwrlevel",
+		&pdata->init_level))
+		pdata->init_level = 1;
+
+	if (pdata->init_level < 0 || pdata->init_level > pdata->num_levels) {
+		KGSL_CORE_ERR("Initial power level out of range\n");
+		pdata->init_level = 1;
+	}
+
+	ret = 0;
+done:
+	return ret;
+
+}
+static void adreno_of_free_bus_scale_info(struct msm_bus_scale_pdata *pdata)
+{
+	int i;
+
+	if (pdata == NULL)
+		return;
+
+	for (i = 0;  pdata->usecase && i < pdata->num_usecases; i++)
+		kfree(pdata->usecase[i].vectors);
+
+	kfree(pdata->usecase);
+	kfree(pdata);
+}
+
+struct msm_bus_scale_pdata *adreno_of_get_bus_scale(struct device_node *node)
+{
+	static int bus_vectors_src[3] = {MSM_BUS_MASTER_GRAPHICS_3D,
+		MSM_BUS_MASTER_GRAPHICS_3D_PORT1, MSM_BUS_MASTER_V_OCMEM_GFX3D};
+	static int bus_vectors_dst[2] = {MSM_BUS_SLAVE_EBI_CH0,
+		MSM_BUS_SLAVE_OCMEM};
+	const unsigned int *vectors;
+	struct msm_bus_scale_pdata *pdata;
+	int i, j, len, num_paths;
+	int ret = -EINVAL;
+
+	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+
+	if (!pdata) {
+		KGSL_CORE_ERR("kzalloc(%d) failed\n", sizeof(*pdata));
+		return ERR_PTR(-ENOMEM);
+	}
+
+	if (adreno_of_read_property(node, "qcom,grp3d-num-bus-scale-usecases",
+		&pdata->num_usecases)) {
+		pdata->num_usecases = 0;
+		goto err;
+	}
+
+	pdata->usecase =  kzalloc(pdata->num_usecases *
+		sizeof(struct msm_bus_paths), GFP_KERNEL);
+
+	if (pdata->usecase == NULL) {
+		KGSL_CORE_ERR("kzalloc (%d) failed\n",
+			pdata->num_usecases * sizeof(struct msm_bus_paths));
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	if (adreno_of_read_property(node, "qcom,grp3d-num-vectors-per-usecase",
+		&num_paths))
+		goto err;
+
+	vectors = of_get_property(node, "qcom,grp3d-vectors", &len);
+
+	if (len != pdata->num_usecases * num_paths *
+		sizeof(struct msm_bus_vectors)) {
+		KGSL_CORE_ERR("Invalid size for the bus scale vectors\n");
+		goto err;
+	}
+
+	for (i = 0; i < pdata->num_usecases; i++) {
+		pdata->usecase[i].num_paths = num_paths;
+		pdata->usecase[i].vectors = kzalloc(num_paths *
+						sizeof(struct msm_bus_vectors),
+						GFP_KERNEL);
+		if (!pdata->usecase[i].vectors) {
+			KGSL_CORE_ERR("kzalloc(%d) failed\n",
+				num_paths * sizeof(struct msm_bus_vectors));
+			ret = -ENOMEM;
+			goto err;
+		}
+		for (j = 0; j < num_paths; j++) {
+			int index = (i * num_paths + j) * 4;
+			pdata->usecase[i].vectors[j].src =
+				bus_vectors_src[be32_to_cpu(vectors[index])];
+			pdata->usecase[i].vectors[j].dst =
+				bus_vectors_dst[
+					be32_to_cpu(vectors[index + 1])];
+			pdata->usecase[i].vectors[j].ab =
+				be32_to_cpu(vectors[index + 2]);
+			pdata->usecase[i].vectors[j].ib =
+				KGSL_CONVERT_TO_MBPS(
+					be32_to_cpu(vectors[index + 3]));
+		}
+	}
+
+	pdata->name = "grp3d";
+
+	return pdata;
+
+err:
+	adreno_of_free_bus_scale_info(pdata);
+
+	return ERR_PTR(ret);
+}
+
+static struct msm_dcvs_core_info *adreno_of_get_dcvs(struct device_node *parent)
+{
+	struct device_node *node, *child;
+	struct msm_dcvs_core_info *info = NULL;
+	int count = 0;
+	int ret = -EINVAL;
+
+	node = adreno_of_find_subnode(parent, "qcom,dcvs-core-info");
+	if (node == NULL)
+		return ERR_PTR(-EINVAL);
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+
+	if (info == NULL) {
+		KGSL_CORE_ERR("kzalloc(%d) failed\n", sizeof(*info));
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	for_each_child_of_node(node, child)
+		count++;
+
+	info->core_param.num_freq = count;
+
+	info->freq_tbl = kzalloc(info->core_param.num_freq *
+			sizeof(struct msm_dcvs_freq_entry),
+			GFP_KERNEL);
+
+	if (info->freq_tbl == NULL) {
+		KGSL_CORE_ERR("kzalloc(%d) failed\n",
+			info->core_param.num_freq *
+			sizeof(struct msm_dcvs_freq_entry));
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	for_each_child_of_node(node, child) {
+		unsigned int index;
+
+		if (adreno_of_read_property(child, "reg", &index))
+			goto err;
+
+		if (index >= info->core_param.num_freq) {
+			KGSL_CORE_ERR("DCVS freq entry %d is out of range\n",
+				index);
+			continue;
+		}
+
+		if (adreno_of_read_property(child, "qcom,freq",
+			&info->freq_tbl[index].freq))
+			goto err;
+
+		if (adreno_of_read_property(child, "qcom,idle-energy",
+			&info->freq_tbl[index].idle_energy))
+			info->freq_tbl[index].idle_energy = 0;
+
+		if (adreno_of_read_property(child, "qcom,active-energy",
+			&info->freq_tbl[index].active_energy))
+			info->freq_tbl[index].active_energy = 0;
+	}
+
+	if (adreno_of_read_property(node, "qcom,core-max-time-us",
+		&info->core_param.max_time_us))
+		goto err;
+
+	if (adreno_of_read_property(node, "qcom,algo-slack-time-us",
+		&info->algo_param.slack_time_us))
+		goto err;
+
+	if (adreno_of_read_property(node, "qcom,algo-disable-pc-threshold",
+		&info->algo_param.disable_pc_threshold))
+		goto err;
+
+	if (adreno_of_read_property(node, "qcom,algo-ss-window-size",
+		&info->algo_param.ss_window_size))
+		goto err;
+
+	if (adreno_of_read_property(node, "qcom,algo-ss-util-pct",
+		&info->algo_param.ss_util_pct))
+		goto err;
+
+	if (adreno_of_read_property(node, "qcom,algo-em-max-util-pct",
+		&info->algo_param.em_max_util_pct))
+		goto err;
+
+	if (adreno_of_read_property(node, "qcom,algo-ss-iobusy-conv",
+		&info->algo_param.ss_iobusy_conv))
+		goto err;
+
+	return info;
+
+err:
+	if (info)
+		kfree(info->freq_tbl);
+
+	kfree(info);
+
+	return ERR_PTR(ret);
+}
+
+static int adreno_of_get_iommu(struct device_node *parent,
+	struct kgsl_device_platform_data *pdata)
+{
+	struct device_node *node, *child;
+	struct kgsl_device_iommu_data *data = NULL;
+	struct kgsl_iommu_ctx *ctxs = NULL;
+	u32 reg_val[2];
+	int ctx_index = 0;
+
+	node = of_parse_phandle(parent, "iommu", 0);
+	if (node == NULL)
+		return -EINVAL;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (data == NULL) {
+		KGSL_CORE_ERR("kzalloc(%d) failed\n", sizeof(*data));
+		goto err;
+	}
+
+	if (of_property_read_u32_array(node, "reg", reg_val, 2))
+		goto err;
+
+	data->physstart = reg_val[0];
+	data->physend = data->physstart + reg_val[1] - 1;
+
+	data->iommu_ctx_count = 0;
+
+	for_each_child_of_node(node, child)
+		data->iommu_ctx_count++;
+
+	ctxs = kzalloc(data->iommu_ctx_count * sizeof(struct kgsl_iommu_ctx),
+		GFP_KERNEL);
+
+	if (ctxs == NULL) {
+		KGSL_CORE_ERR("kzalloc(%d) failed\n",
+			data->iommu_ctx_count * sizeof(struct kgsl_iommu_ctx));
+		goto err;
+	}
+
+	for_each_child_of_node(node, child) {
+		int ret = of_property_read_string(child, "label",
+				&ctxs[ctx_index].iommu_ctx_name);
+
+		if (ret) {
+			KGSL_CORE_ERR("Unable to read KGSL IOMMU 'label'\n");
+			goto err;
+		}
+
+		if (adreno_of_read_property(child, "qcom,iommu-ctx-sids",
+			&ctxs[ctx_index].ctx_id))
+			goto err;
+
+		ctx_index++;
+	}
+
+	data->iommu_ctxs = ctxs;
+
+	pdata->iommu_data = data;
+	pdata->iommu_count = 1;
+
+	return 0;
+
+err:
+	kfree(ctxs);
+	kfree(data);
+
+	return -EINVAL;
+}
+
+static int adreno_of_get_pdata(struct platform_device *pdev)
+{
+	struct kgsl_device_platform_data *pdata = NULL;
+	struct kgsl_device *device;
+	int ret = -EINVAL;
+
+	pdev->id_entry = adreno_id_table;
+
+	pdata = pdev->dev.platform_data;
+	if (pdata)
+		return 0;
+
+	if (of_property_read_string(pdev->dev.of_node, "label", &pdev->name)) {
+		KGSL_CORE_ERR("Unable to read 'label'\n");
+		goto err;
+	}
+
+	if (adreno_of_read_property(pdev->dev.of_node, "qcom,id", &pdev->id))
+		goto err;
+
+	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+	if (pdata == NULL) {
+		KGSL_CORE_ERR("kzalloc(%d) failed\n", sizeof(*pdata));
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	if (adreno_of_read_property(pdev->dev.of_node, "qcom,chipid",
+		&pdata->chipid))
+		goto err;
+
+	/* pwrlevel Data */
+	ret = adreno_of_get_pwrlevels(pdev->dev.of_node, pdata);
+	if (ret)
+		goto err;
+
+	/* Default value is 83, if not found in DT */
+	if (adreno_of_read_property(pdev->dev.of_node, "qcom,idle-timeout",
+		&pdata->idle_timeout))
+		pdata->idle_timeout = 83;
+
+	if (adreno_of_read_property(pdev->dev.of_node, "qcom,nap-allowed",
+		&pdata->nap_allowed))
+		pdata->nap_allowed = 1;
+
+	if (adreno_of_read_property(pdev->dev.of_node, "qcom,clk-map",
+		&pdata->clk_map))
+		goto err;
+
+	device = (struct kgsl_device *)pdev->id_entry->driver_data;
+
+	if (device->id != KGSL_DEVICE_3D0)
+		goto err;
+
+	/* Bus Scale Data */
+
+	pdata->bus_scale_table = adreno_of_get_bus_scale(pdev->dev.of_node);
+	if (IS_ERR_OR_NULL(pdata->bus_scale_table)) {
+		ret = PTR_ERR(pdata->bus_scale_table);
+		goto err;
+	}
+
+	pdata->core_info = adreno_of_get_dcvs(pdev->dev.of_node);
+	if (IS_ERR_OR_NULL(pdata->core_info)) {
+		ret = PTR_ERR(pdata->core_info);
+		goto err;
+	}
+
+	ret = adreno_of_get_iommu(pdev->dev.of_node, pdata);
+	if (ret)
+		goto err;
+
+	pdev->dev.platform_data = pdata;
+	return 0;
+
+err:
+	if (pdata) {
+		adreno_of_free_bus_scale_info(pdata->bus_scale_table);
+		if (pdata->core_info)
+			kfree(pdata->core_info->freq_tbl);
+		kfree(pdata->core_info);
+
+		if (pdata->iommu_data)
+			kfree(pdata->iommu_data->iommu_ctxs);
+
+		kfree(pdata->iommu_data);
+	}
+
+	kfree(pdata);
+
+	return ret;
+}
+
+#ifdef CONFIG_MSM_OCMEM
+static int
+adreno_ocmem_gmem_malloc(struct adreno_device *adreno_dev)
+{
+	if (adreno_dev->gpurev != ADRENO_REV_A330)
+		return 0;
+
+	/* OCMEM is only needed once, do not support consective allocation */
+	if (adreno_dev->ocmem_hdl != NULL)
+		return 0;
+
+	adreno_dev->ocmem_hdl =
+		ocmem_allocate(OCMEM_GRAPHICS, adreno_dev->gmem_size);
+	if (adreno_dev->ocmem_hdl == NULL)
+		return -ENOMEM;
+
+	adreno_dev->gmem_size = adreno_dev->ocmem_hdl->len;
+	adreno_dev->gmem_base = adreno_dev->ocmem_hdl->addr;
+
+	return 0;
+}
+
+static void
+adreno_ocmem_gmem_free(struct adreno_device *adreno_dev)
+{
+	if (adreno_dev->gpurev != ADRENO_REV_A330)
+		return;
+
+	if (adreno_dev->ocmem_hdl == NULL)
+		return;
+
+	ocmem_free(OCMEM_GRAPHICS, adreno_dev->ocmem_hdl);
+	adreno_dev->ocmem_hdl = NULL;
+}
+#else
+static int
+adreno_ocmem_gmem_malloc(struct adreno_device *adreno_dev)
+{
+	return 0;
+}
+
+static void
+adreno_ocmem_gmem_free(struct adreno_device *adreno_dev)
+{
+}
+#endif
+
 static int __devinit
 adreno_probe(struct platform_device *pdev)
 {
 	struct kgsl_device *device;
 	struct adreno_device *adreno_dev;
 	int status = -EINVAL;
+	bool is_dt;
+
+	is_dt = of_match_device(adreno_match_table, &pdev->dev);
+
+	if (is_dt && pdev->dev.of_node) {
+		status = adreno_of_get_pdata(pdev);
+		if (status)
+			goto error_return;
+	}
 
 	device = (struct kgsl_device *)pdev->id_entry->driver_data;
 	adreno_dev = ADRENO_DEVICE(device);
@@ -678,6 +1192,7 @@
 	adreno_ringbuffer_close(&adreno_dev->ringbuffer);
 error:
 	device->parentdev = NULL;
+error_return:
 	return status;
 }
 
@@ -740,6 +1255,12 @@
 	if (status)
 		goto error_clk_off;
 
+	status = adreno_ocmem_gmem_malloc(adreno_dev);
+	if (status) {
+		KGSL_DRV_ERR(device, "OCMEM malloc failed\n");
+		goto error_mmu_off;
+	}
+
 	/* Start the GPU */
 	adreno_dev->gpudev->start(adreno_dev);
 
@@ -756,7 +1277,10 @@
 	}
 
 	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
+
+error_mmu_off:
 	kgsl_mmu_stop(&device->mmu);
+
 error_clk_off:
 	kgsl_pwrctrl_disable(device);
 
@@ -777,6 +1301,8 @@
 	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
 	del_timer_sync(&device->idle_timer);
 
+	adreno_ocmem_gmem_free(adreno_dev);
+
 	/* Power down the device */
 	kgsl_pwrctrl_disable(device);
 
@@ -955,7 +1481,7 @@
 		 * them to pass */
 		adreno_ringbuffer_restore(rb, rec_data->bad_rb_buffer,
 					rec_data->bad_rb_size);
-		idle_ret = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+		idle_ret = adreno_idle(device);
 		if (idle_ret) {
 			ret = adreno_stop(device);
 			if (ret) {
@@ -998,7 +1524,7 @@
 	if (ret || !rec_data->bad_rb_size) {
 		adreno_ringbuffer_restore(rb, rec_data->rb_buffer,
 				rec_data->rb_size);
-		ret = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+		ret = adreno_idle(device);
 		if (ret) {
 			/* If we fail here we can try to invalidate another
 			 * context and try recovering again */
@@ -1111,7 +1637,7 @@
 		 * Trigger an automatic dump of the state to
 		 * the console
 		 */
-		adreno_postmortem_dump(device, 0);
+		kgsl_postmortem_dump(device, 0);
 
 		/*
 		 * Make a GPU snapshot.  For now, do it after the PM dump so we
@@ -1280,61 +1806,74 @@
 	adreno_regwrite(device, REG_CP_RB_WPTR, adreno_dev->ringbuffer.wptr);
 }
 
-/* Caller must hold the device mutex. */
-int adreno_idle(struct kgsl_device *device, unsigned int timeout)
+static int adreno_ringbuffer_drain(struct kgsl_device *device,
+	unsigned int *regs)
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+	unsigned long wait;
+	unsigned long timeout = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
+
+	if (!(rb->flags & KGSL_FLAGS_STARTED))
+		return 0;
+
+	/*
+	 * The first time into the loop, wait for 100 msecs and kick wptr again
+	 * to ensure that the hardware has updated correctly.  After that, kick
+	 * it periodically every KGSL_TIMEOUT_PART msecs until the timeout
+	 * expires
+	 */
+
+	wait = jiffies + msecs_to_jiffies(100);
+
+	adreno_poke(device);
+
+	do {
+		if (time_after(jiffies, wait)) {
+			adreno_poke(device);
+
+			/* Check to see if the core is hung */
+			if (adreno_hang_detect(device, regs))
+				return -ETIMEDOUT;
+
+			wait = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
+		}
+		GSL_RB_GET_READPTR(rb, &rb->rptr);
+
+		if (time_after(jiffies, timeout)) {
+			KGSL_DRV_ERR(device, "rptr: %x, wptr: %x\n",
+				rb->rptr, rb->wptr);
+			return -ETIMEDOUT;
+		}
+	} while (rb->rptr != rb->wptr);
+
+	return 0;
+}
+
+/* Caller must hold the device mutex. */
+int adreno_idle(struct kgsl_device *device)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	unsigned int rbbm_status;
-	unsigned long wait_timeout =
-		msecs_to_jiffies(adreno_dev->wait_timeout);
 	unsigned long wait_time;
 	unsigned long wait_time_part;
-	unsigned int msecs;
-	unsigned int msecs_first;
-	unsigned int msecs_part = KGSL_TIMEOUT_PART;
 	unsigned int prev_reg_val[hang_detect_regs_count];
 
 	memset(prev_reg_val, 0, sizeof(prev_reg_val));
 
-	/* Restrict timeout value between adreno_dev->wait_timeout and 0 */
-	if ((timeout == 0) || (timeout > adreno_dev->wait_timeout))
-		msecs = adreno_dev->wait_timeout;
-	else
-		msecs = timeout;
-
 	kgsl_cffdump_regpoll(device->id,
 		adreno_dev->gpudev->reg_rbbm_status << 2,
 		0x00000000, 0x80000000);
-	/* first, wait until the CP has consumed all the commands in
-	 * the ring buffer
-	 */
+
 retry:
-	if (rb->flags & KGSL_FLAGS_STARTED) {
-		msecs_first = (msecs <= 100) ? ((msecs + 4) / 5) : 100;
-		wait_time = jiffies + wait_timeout;
-		wait_time_part = jiffies + msecs_to_jiffies(msecs_first);
-		adreno_poke(device);
-		do {
-			if (time_after(jiffies, wait_time_part)) {
-				adreno_poke(device);
-				wait_time_part = jiffies +
-					msecs_to_jiffies(msecs_part);
-				if ((adreno_hang_detect(device, prev_reg_val)))
-					goto err;
-			}
-			GSL_RB_GET_READPTR(rb, &rb->rptr);
-			if (time_after(jiffies, wait_time)) {
-				KGSL_DRV_ERR(device, "rptr: %x, wptr: %x\n",
-					rb->rptr, rb->wptr);
-				goto err;
-			}
-		} while (rb->rptr != rb->wptr);
-	}
+	/* First, wait for the ringbuffer to drain */
+	if (adreno_ringbuffer_drain(device, prev_reg_val))
+		goto err;
 
 	/* now, wait for the GPU to finish its operations */
-	wait_time = jiffies + wait_timeout;
-	wait_time_part = jiffies + msecs_to_jiffies(msecs_part);
+	wait_time = jiffies + ADRENO_IDLE_TIMEOUT;
+	wait_time_part = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
+
 	while (time_before(jiffies, wait_time)) {
 		adreno_regread(device, adreno_dev->gpudev->reg_rbbm_status,
 			&rbbm_status);
@@ -1350,7 +1889,7 @@
 		 */
 		if (time_after(jiffies, wait_time_part)) {
 				wait_time_part = jiffies +
-					msecs_to_jiffies(msecs_part);
+					msecs_to_jiffies(KGSL_TIMEOUT_PART);
 				if ((adreno_hang_detect(device, prev_reg_val)))
 					goto err;
 		}
@@ -1361,7 +1900,7 @@
 	KGSL_DRV_ERR(device, "spun too long waiting for RB to idle\n");
 	if (KGSL_STATE_DUMP_AND_RECOVER != device->state &&
 		!adreno_dump_and_recover(device)) {
-		wait_time = jiffies + wait_timeout;
+		wait_time = jiffies + ADRENO_IDLE_TIMEOUT;
 		goto retry;
 	}
 	return -ETIMEDOUT;
@@ -1408,7 +1947,7 @@
 	/* switch to NULL ctxt */
 	if (adreno_dev->drawctxt_active != NULL) {
 		adreno_drawctxt_switch(adreno_dev, NULL, 0);
-		status = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+		status = adreno_idle(device);
 	}
 
 	return status;
@@ -1590,9 +2129,8 @@
 			cmds[1] = 0;
 
 			if (adreno_dev->drawctxt_active)
-				adreno_ringbuffer_issuecmds(device,
-					adreno_dev->drawctxt_active,
-					KGSL_CMD_FLAGS_NONE, &cmds[0], 2);
+				adreno_ringbuffer_issuecmds_intr(device,
+						context, &cmds[0], 2);
 			else
 				/* We would never call this function if there
 				 * was no active contexts running */
@@ -1659,12 +2197,11 @@
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 	int retries = 0;
-	unsigned int msecs_first;
-	unsigned int msecs_part = KGSL_TIMEOUT_PART;
 	unsigned int ts_issued;
 	unsigned int context_id = _get_context_id(context);
 	unsigned int time_elapsed = 0;
 	unsigned int prev_reg_val[hang_detect_regs_count];
+	unsigned int wait;
 
 	memset(prev_reg_val, 0, sizeof(prev_reg_val));
 
@@ -1682,11 +2219,18 @@
 		goto done;
 	}
 
-	/* Keep the first timeout as 100msecs before rewriting
-	 * the WPTR. Less visible impact if the WPTR has not
-	 * been updated properly.
+	/*
+	 * Make the first timeout interval 100 msecs and then try to kick the
+	 * wptr again.  This helps to ensure the wptr is updated properly.  If
+	 * the requested timeout is less than 100 msecs, then wait 20msecs which
+	 * is the minimum amount of time we can safely wait at 100HZ
 	 */
-	msecs_first = (msecs <= 100) ? ((msecs + 4) / 5) : 100;
+
+	if (msecs == 0 || msecs >= 100)
+		wait = 100;
+	else
+		wait = 20;
+
 	do {
 		/*
 		 * If the context ID is invalid, we are in a race with
@@ -1725,8 +2269,8 @@
 				device->wait_queue,
 				kgsl_check_interrupt_timestamp(device,
 					context, timestamp),
-				msecs_to_jiffies(retries ?
-					msecs_part : msecs_first), io);
+				msecs_to_jiffies(wait), io);
+
 		mutex_lock(&device->mutex);
 
 		if (status > 0) {
@@ -1739,11 +2283,12 @@
 		}
 		/*this wait timed out*/
 
-		time_elapsed = time_elapsed +
-				(retries ? msecs_part : msecs_first);
+		time_elapsed += wait;
+		wait = KGSL_TIMEOUT_PART;
+
 		retries++;
 
-	} while (time_elapsed < msecs);
+	} while (!msecs || time_elapsed < msecs);
 
 hang_dump:
 	/*
@@ -1925,14 +2470,9 @@
 	.drawctxt_create = adreno_drawctxt_create,
 	.drawctxt_destroy = adreno_drawctxt_destroy,
 	.setproperty = adreno_setproperty,
+	.postmortem_dump = adreno_dump,
 };
 
-static struct platform_device_id adreno_id_table[] = {
-	{ DEVICE_3D0_NAME, (kernel_ulong_t)&device_3d0.dev, },
-	{ },
-};
-MODULE_DEVICE_TABLE(platform, adreno_id_table);
-
 static struct platform_driver adreno_platform_driver = {
 	.probe = adreno_probe,
 	.remove = __devexit_p(adreno_remove),
@@ -1943,6 +2483,7 @@
 		.owner = THIS_MODULE,
 		.name = DEVICE_3D_NAME,
 		.pm = &kgsl_pm_ops,
+		.of_match_table = adreno_match_table,
 	}
 };
 
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 57f4859..26d5eaa 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -17,6 +17,7 @@
 #include "adreno_drawctxt.h"
 #include "adreno_ringbuffer.h"
 #include "kgsl_iommu.h"
+#include <mach/ocmem.h>
 
 #define DEVICE_3D_NAME "kgsl-3d"
 #define DEVICE_3D0_NAME "kgsl-3d0"
@@ -32,7 +33,7 @@
 /* Flags to control command packet settings */
 #define KGSL_CMD_FLAGS_NONE             0x00000000
 #define KGSL_CMD_FLAGS_PMODE		0x00000001
-#define KGSL_CMD_FLAGS_NO_TS_CMP	0x00000002
+#define KGSL_CMD_FLAGS_DUMMY_INTR_CMD	0x00000002
 
 /* Command identifiers */
 #define KGSL_CONTEXT_TO_MEM_IDENTIFIER	0x2EADBEEF
@@ -48,10 +49,18 @@
 #define ADRENO_DEFAULT_PWRSCALE_POLICY  NULL
 #endif
 
+void adreno_debugfs_init(struct kgsl_device *device);
+
 #define ADRENO_ISTORE_START 0x5000 /* Istore offset */
 
 #define ADRENO_NUM_CTX_SWITCH_ALLOWED_BEFORE_DRAW	50
 
+/* One cannot wait forever for the core to idle, so set an upper limit to the
+ * amount of time to wait for the core to go idle
+ */
+
+#define ADRENO_IDLE_TIMEOUT (20 * 1000)
+
 enum adreno_gpurev {
 	ADRENO_REV_UNKNOWN = 0,
 	ADRENO_REV_A200 = 200,
@@ -61,6 +70,7 @@
 	ADRENO_REV_A225 = 225,
 	ADRENO_REV_A305 = 305,
 	ADRENO_REV_A320 = 320,
+	ADRENO_REV_A330 = 330,
 };
 
 struct adreno_gpudev;
@@ -87,6 +97,7 @@
 	unsigned int instruction_size;
 	unsigned int ib_check_level;
 	unsigned int fast_hang_detect;
+	struct ocmem_buf *ocmem_hdl;
 };
 
 struct adreno_gpudev {
@@ -157,12 +168,14 @@
 extern const unsigned int hang_detect_regs_count;
 
 
-int adreno_idle(struct kgsl_device *device, unsigned int timeout);
+int adreno_idle(struct kgsl_device *device);
 void adreno_regread(struct kgsl_device *device, unsigned int offsetwords,
 				unsigned int *value);
 void adreno_regwrite(struct kgsl_device *device, unsigned int offsetwords,
 				unsigned int value);
 
+int adreno_dump(struct kgsl_device *device, int manual);
+
 struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
 						unsigned int pt_base,
 						unsigned int gpuaddr,
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 5a76c86..5ba3778 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1822,7 +1822,8 @@
 	if (state) {
 		adreno_regwrite(device, REG_RBBM_INT_CNTL, RBBM_INT_MASK);
 		adreno_regwrite(device, REG_CP_INT_CNTL, CP_INT_MASK);
-		adreno_regwrite(device, MH_INTERRUPT_MASK, KGSL_MMU_INT_MASK);
+		adreno_regwrite(device, MH_INTERRUPT_MASK,
+			kgsl_mmu_get_int_mask());
 	} else {
 		adreno_regwrite(device, REG_RBBM_INT_CNTL, 0);
 		adreno_regwrite(device, REG_CP_INT_CNTL, 0);
@@ -1982,7 +1983,13 @@
 			0x18000000);
 	}
 
-	adreno_regwrite(device, REG_RBBM_CNTL, 0x00004442);
+	if (adreno_is_a203(adreno_dev))
+		/* For A203 increase number of clocks that RBBM
+		 * will wait before de-asserting Register Clock
+		 * Active signal */
+		adreno_regwrite(device, REG_RBBM_CNTL, 0x0000FFFF);
+	else
+		adreno_regwrite(device, REG_RBBM_CNTL, 0x00004442);
 
 	adreno_regwrite(device, REG_SQ_VS_PROGRAM, 0x00000000);
 	adreno_regwrite(device, REG_SQ_PS_PROGRAM, 0x00000000);
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index bb89067..205c9ff 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2290,9 +2290,6 @@
 	build_quad_vtxbuff(drawctxt, &drawctxt->context_gmem_shadow,
 		&tmp_ctx.cmd);
 
-	/* Dow we need to idle? */
-	/* adreno_idle(&adreno_dev->dev, KGSL_TIMEOUT_DEFAULT); */
-
 	tmp_ctx.cmd = build_gmem2sys_cmds(adreno_dev, drawctxt,
 		&drawctxt->context_gmem_shadow);
 	tmp_ctx.cmd = build_sys2gmem_cmds(adreno_dev, drawctxt,
@@ -2701,24 +2698,46 @@
 	struct kgsl_device *device = &adreno_dev->dev;
 
 	/* Set up 16 deep read/write request queues */
+	if (adreno_dev->gpurev == ADRENO_REV_A330) {
+		adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818);
+		adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x00001818);
+		adreno_regwrite(device, A3XX_VBIF_OUT_RD_LIM_CONF0, 0x00001818);
+		adreno_regwrite(device, A3XX_VBIF_OUT_WR_LIM_CONF0, 0x00001818);
+		adreno_regwrite(device, A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
+		adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818);
+		adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF1, 0x00001818);
+		/* Enable WR-REQ */
+		adreno_regwrite(device, A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000FF);
 
-	adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
-	adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);
-	adreno_regwrite(device, A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010);
-	adreno_regwrite(device, A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010);
-	adreno_regwrite(device, A3XX_VBIF_DDR_OUT_MAX_BURST, 0x00000303);
-	adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010);
-	adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010);
+		/* Set up round robin arbitration between both AXI ports */
+		adreno_regwrite(device, A3XX_VBIF_ARB_CTL, 0x00000030);
+		/* Set up VBIF_ROUND_ROBIN_QOS_ARB */
+		adreno_regwrite(device, A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001);
 
-	/* Enable WR-REQ */
-	adreno_regwrite(device, A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x000000FF);
+		/* Set up AOOO */
+		adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO_EN, 0x00000FFF);
+		adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO, 0x0FFF0FFF);
 
-	/* Set up round robin arbitration between both AXI ports */
-	adreno_regwrite(device, A3XX_VBIF_ARB_CTL, 0x00000030);
+		/* VBIF AXI AMEMTYPE CONFIG */
+		adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AMEMTYPE_CONF0,
+			0x22222222);
+	} else {
+		adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
+		adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);
+		adreno_regwrite(device, A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010);
+		adreno_regwrite(device, A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010);
+		adreno_regwrite(device, A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
+		adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010);
+		adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010);
+		/* Enable WR-REQ */
+		adreno_regwrite(device, A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000FF);
 
-	/* Set up AOOO */
-	adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003C);
-	adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO, 0x003C003C);
+		/* Set up round robin arbitration between both AXI ports */
+		adreno_regwrite(device, A3XX_VBIF_ARB_CTL, 0x00000030);
+		/* Set up AOOO */
+		adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003C);
+		adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO, 0x003C003C);
+	}
 
 	if (cpu_is_apq8064()) {
 		/* Enable 1K sort */
diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c
index e3c9a18..bb3da40 100644
--- a/drivers/gpu/msm/adreno_debugfs.c
+++ b/drivers/gpu/msm/adreno_debugfs.c
@@ -18,67 +18,11 @@
 #include <linux/io.h>
 
 #include "kgsl.h"
-#include "adreno_postmortem.h"
 #include "adreno.h"
 
 #include "a2xx_reg.h"
 
 unsigned int kgsl_cff_dump_enable;
-int adreno_pm_regs_enabled;
-int adreno_pm_ib_enabled;
-
-static struct dentry *pm_d_debugfs;
-
-static int pm_dump_set(void *data, u64 val)
-{
-	struct kgsl_device *device = data;
-
-	if (val) {
-		mutex_lock(&device->mutex);
-		adreno_postmortem_dump(device, 1);
-		mutex_unlock(&device->mutex);
-	}
-
-	return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(pm_dump_fops,
-			NULL,
-			pm_dump_set, "%llu\n");
-
-static int pm_regs_enabled_set(void *data, u64 val)
-{
-	adreno_pm_regs_enabled = val ? 1 : 0;
-	return 0;
-}
-
-static int pm_regs_enabled_get(void *data, u64 *val)
-{
-	*val = adreno_pm_regs_enabled;
-	return 0;
-}
-
-static int pm_ib_enabled_set(void *data, u64 val)
-{
-	adreno_pm_ib_enabled = val ? 1 : 0;
-	return 0;
-}
-
-static int pm_ib_enabled_get(void *data, u64 *val)
-{
-	*val = adreno_pm_ib_enabled;
-	return 0;
-}
-
-
-DEFINE_SIMPLE_ATTRIBUTE(pm_regs_enabled_fops,
-			pm_regs_enabled_get,
-			pm_regs_enabled_set, "%llu\n");
-
-DEFINE_SIMPLE_ATTRIBUTE(pm_ib_enabled_fops,
-			pm_ib_enabled_get,
-			pm_ib_enabled_set, "%llu\n");
-
 
 static int kgsl_cff_dump_enable_set(void *data, u64 val)
 {
@@ -116,23 +60,9 @@
 		&adreno_dev->wait_timeout);
 	debugfs_create_u32("ib_check", 0644, device->d_debugfs,
 			   &adreno_dev->ib_check_level);
-
 	/* By Default enable fast hang detection */
 	adreno_dev->fast_hang_detect = 1;
 	debugfs_create_u32("fast_hang_detect", 0644, device->d_debugfs,
 			   &adreno_dev->fast_hang_detect);
 
-	/* Create post mortem control files */
-
-	pm_d_debugfs = debugfs_create_dir("postmortem", device->d_debugfs);
-
-	if (IS_ERR(pm_d_debugfs))
-		return;
-
-	debugfs_create_file("dump",  0600, pm_d_debugfs, device,
-			    &pm_dump_fops);
-	debugfs_create_file("regs_enabled", 0644, pm_d_debugfs, device,
-			    &pm_regs_enabled_fops);
-	debugfs_create_file("ib_enabled", 0644, pm_d_debugfs, device,
-				    &pm_ib_enabled_fops);
 }
diff --git a/drivers/gpu/msm/adreno_debugfs.h b/drivers/gpu/msm/adreno_debugfs.h
deleted file mode 100644
index 5f8d89a..0000000
--- a/drivers/gpu/msm/adreno_debugfs.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Copyright (c) 2002,2008-2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-#ifndef __ADRENO_DEBUGFS_H
-#define __ADRENO_DEBUGFS_H
-
-#ifdef CONFIG_DEBUG_FS
-
-int adreno_debugfs_init(struct kgsl_device *device);
-
-extern int adreno_pm_regs_enabled;
-extern int adreno_pm_ib_enabled;
-
-static inline int is_adreno_pm_regs_enabled(void)
-{
-	return adreno_pm_regs_enabled;
-}
-
-static inline int is_adreno_pm_ib_enabled(void)
-{
-	return adreno_pm_ib_enabled;
-}
-
-#else
-static inline int adreno_debugfs_init(struct kgsl_device *device)
-{
-	return 0;
-}
-
-static inline int kgsl_pmregs_enabled(void)
-{
-	/* If debugfs is turned off, then always print registers */
-	return 1;
-}
-#endif
-
-#endif /* __ADRENO_DEBUGFS_H */
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 098c4f5..bd22233 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -147,6 +147,7 @@
 {
 	struct adreno_context *drawctxt;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
 	int ret;
 
 	drawctxt = kzalloc(sizeof(struct adreno_context), GFP_KERNEL);
@@ -157,6 +158,7 @@
 	drawctxt->pagetable = pagetable;
 	drawctxt->bin_base_offset = 0;
 	drawctxt->id = context->id;
+	rb->timestamp[context->id] = 0;
 
 	if (flags & KGSL_CONTEXT_PREAMBLE)
 		drawctxt->flags |= CTXT_FLAGS_PREAMBLE;
@@ -174,6 +176,12 @@
 	kgsl_sharedmem_writel(&device->memstore,
 			KGSL_MEMSTORE_OFFSET(drawctxt->id, ref_wait_ts),
 			KGSL_INIT_REFTIMESTAMP);
+	kgsl_sharedmem_writel(&device->memstore,
+			KGSL_MEMSTORE_OFFSET(drawctxt->id, ts_cmp_enable), 0);
+	kgsl_sharedmem_writel(&device->memstore,
+			KGSL_MEMSTORE_OFFSET(drawctxt->id, soptimestamp), 0);
+	kgsl_sharedmem_writel(&device->memstore,
+			KGSL_MEMSTORE_OFFSET(drawctxt->id, eoptimestamp), 0);
 
 	context->devctxt = drawctxt;
 	return 0;
@@ -216,7 +224,7 @@
 		adreno_drawctxt_switch(adreno_dev, NULL, 0);
 	}
 
-	adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+	adreno_idle(device);
 
 	kgsl_sharedmem_free(&drawctxt->gpustate);
 	kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 3cc4bcf..2038c10 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -19,8 +19,6 @@
 #include "adreno.h"
 #include "adreno_pm4types.h"
 #include "adreno_ringbuffer.h"
-#include "adreno_postmortem.h"
-#include "adreno_debugfs.h"
 #include "kgsl_cffdump.h"
 #include "kgsl_pwrctrl.h"
 
@@ -678,7 +676,7 @@
 		"MH_INTERRUPT: MASK = %08X | STATUS   = %08X\n", r1, r2);
 }
 
-static int adreno_dump(struct kgsl_device *device)
+int adreno_dump(struct kgsl_device *device, int manual)
 {
 	unsigned int cp_ib1_base, cp_ib1_bufsz;
 	unsigned int cp_ib2_base, cp_ib2_bufsz;
@@ -834,7 +832,7 @@
 		cp_rb_base, cp_rb_rptr, cp_rb_wptr, read_idx);
 	adreno_dump_rb(device, rb_copy, num_item<<2, read_idx, rb_count);
 
-	if (is_adreno_pm_ib_enabled()) {
+	if (device->pm_ib_enabled) {
 		for (read_idx = NUM_DWORDS_OF_RINGBUFFER_HISTORY;
 			read_idx >= 0; --read_idx) {
 			uint32_t this_cmd = rb_copy[read_idx];
@@ -865,7 +863,7 @@
 	}
 
 	/* Dump the registers if the user asked for it */
-	if (is_adreno_pm_regs_enabled()) {
+	if (device->pm_regs_enabled) {
 		if (adreno_is_a20x(adreno_dev))
 			adreno_dump_regs(device, a200_registers,
 					a200_registers_count);
@@ -885,85 +883,3 @@
 end:
 	return result;
 }
-
-/**
- * adreno_postmortem_dump - Dump the current GPU state
- * @device - A pointer to the KGSL device to dump
- * @manual - A flag that indicates if this was a manually triggered
- *           dump (from debugfs).  If zero, then this is assumed to be a
- *           dump automaticlaly triggered from a hang
-*/
-
-int adreno_postmortem_dump(struct kgsl_device *device, int manual)
-{
-	bool saved_nap;
-	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
-
-	BUG_ON(device == NULL);
-
-	kgsl_cffdump_hang(device->id);
-
-	/* For a manual dump, make sure that the system is idle */
-
-	if (manual) {
-		if (device->active_cnt != 0) {
-			mutex_unlock(&device->mutex);
-			wait_for_completion(&device->suspend_gate);
-			mutex_lock(&device->mutex);
-		}
-
-		if (device->state == KGSL_STATE_ACTIVE)
-			kgsl_idle(device,  KGSL_TIMEOUT_DEFAULT);
-
-	}
-	KGSL_LOG_DUMP(device, "POWER: FLAGS = %08lX | ACTIVE POWERLEVEL = %08X",
-			pwr->power_flags, pwr->active_pwrlevel);
-
-	KGSL_LOG_DUMP(device, "POWER: INTERVAL TIMEOUT = %08X ",
-		pwr->interval_timeout);
-
-	KGSL_LOG_DUMP(device, "GRP_CLK = %lu ",
-				  kgsl_get_clkrate(pwr->grp_clks[0]));
-
-	KGSL_LOG_DUMP(device, "BUS CLK = %lu ",
-		kgsl_get_clkrate(pwr->ebi1_clk));
-
-	/* Disable the idle timer so we don't get interrupted */
-	del_timer_sync(&device->idle_timer);
-	mutex_unlock(&device->mutex);
-	flush_workqueue(device->work_queue);
-	mutex_lock(&device->mutex);
-
-	/* Turn off napping to make sure we have the clocks full
-	   attention through the following process */
-	saved_nap = device->pwrctrl.nap_allowed;
-	device->pwrctrl.nap_allowed = false;
-
-	/* Force on the clocks */
-	kgsl_pwrctrl_wake(device);
-
-	/* Disable the irq */
-	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
-
-	adreno_dump(device);
-
-	/* Restore nap mode */
-	device->pwrctrl.nap_allowed = saved_nap;
-
-	/* On a manual trigger, turn on the interrupts and put
-	   the clocks to sleep.  They will recover themselves
-	   on the next event.  For a hang, leave things as they
-	   are until recovery kicks in. */
-
-	if (manual) {
-		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
-
-		/* try to go into a sleep mode until the next event */
-		kgsl_pwrctrl_request_state(device, KGSL_STATE_SLEEP);
-		kgsl_pwrctrl_sleep(device);
-	}
-
-	KGSL_DRV_ERR(device, "Dump Finished\n");
-
-	return 0;
-}
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 86a349ad..ad9007f 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -22,7 +22,6 @@
 #include "adreno.h"
 #include "adreno_pm4types.h"
 #include "adreno_ringbuffer.h"
-#include "adreno_debugfs.h"
 
 #include "a2xx_reg.h"
 #include "a3xx_reg.h"
@@ -53,11 +52,9 @@
 	unsigned int freecmds;
 	unsigned int *cmds;
 	uint cmds_gpu;
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
-	unsigned long wait_timeout = msecs_to_jiffies(adreno_dev->wait_timeout);
 	unsigned long wait_time;
+	unsigned long wait_timeout = msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
 	unsigned long wait_time_part;
-	unsigned int msecs_part = KGSL_TIMEOUT_PART;
 	unsigned int prev_reg_val[hang_detect_regs_count];
 
 	memset(prev_reg_val, 0, sizeof(prev_reg_val));
@@ -88,7 +85,7 @@
 	}
 
 	wait_time = jiffies + wait_timeout;
-	wait_time_part = jiffies + msecs_to_jiffies(msecs_part);
+	wait_time_part = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
 	/* wait for space in ringbuffer */
 	while (1) {
 		GSL_RB_GET_READPTR(rb, &rb->rptr);
@@ -102,7 +99,7 @@
 		 */
 		if (time_after(jiffies, wait_time_part)) {
 			wait_time_part = jiffies +
-				msecs_to_jiffies(msecs_part);
+				msecs_to_jiffies(KGSL_TIMEOUT_PART);
 			if ((adreno_hang_detect(rb->device,
 						prev_reg_val))){
 				KGSL_DRV_ERR(rb->device,
@@ -394,7 +391,7 @@
 	adreno_dev->gpudev->rb_init(adreno_dev, rb);
 
 	/* idle device to validate ME INIT */
-	status = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+	status = adreno_idle(device);
 
 	if (status == 0)
 		rb->flags |= KGSL_FLAGS_STARTED;
@@ -404,11 +401,8 @@
 
 void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb)
 {
-	if (rb->flags & KGSL_FLAGS_STARTED) {
-		/* ME_HALT */
-		adreno_regwrite(rb->device, REG_CP_ME_CNTL, 0x10000000);
+	if (rb->flags & KGSL_FLAGS_STARTED)
 		rb->flags &= ~KGSL_FLAGS_STARTED;
-	}
 }
 
 int adreno_ringbuffer_init(struct kgsl_device *device)
@@ -494,9 +488,9 @@
 	*  error checking if needed
 	*/
 	total_sizedwords += flags & KGSL_CMD_FLAGS_PMODE ? 4 : 0;
-	total_sizedwords += !(flags & KGSL_CMD_FLAGS_NO_TS_CMP) ? 7 : 0;
 	/* 2 dwords to store the start of command sequence */
 	total_sizedwords += 2;
+	total_sizedwords += context ? 7 : 0;
 
 	if (adreno_is_a3xx(adreno_dev))
 		total_sizedwords += 7;
@@ -548,9 +542,10 @@
 
 	/* always increment the global timestamp. once. */
 	rb->timestamp[KGSL_MEMSTORE_GLOBAL]++;
-	if (context) {
+
+	if (context && !(flags & KGSL_CMD_FLAGS_DUMMY_INTR_CMD)) {
 		if (context_id == KGSL_MEMSTORE_GLOBAL)
-			rb->timestamp[context_id] =
+			rb->timestamp[context->id] =
 				rb->timestamp[KGSL_MEMSTORE_GLOBAL];
 		else
 			rb->timestamp[context_id]++;
@@ -580,7 +575,7 @@
 		GSL_RB_WRITE(ringcmds, rcmd_gpu,
 			cp_type3_packet(CP_MEM_WRITE, 2));
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
-			KGSL_MEMSTORE_OFFSET(context->id, soptimestamp)));
+			KGSL_MEMSTORE_OFFSET(context_id, soptimestamp)));
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
 
 		/* end-of-pipeline timestamp */
@@ -588,14 +583,14 @@
 			cp_type3_packet(CP_EVENT_WRITE, 3));
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
-			KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp)));
+			KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
 
 		GSL_RB_WRITE(ringcmds, rcmd_gpu,
 			cp_type3_packet(CP_MEM_WRITE, 2));
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
-			      KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
-				      eoptimestamp)));
+			KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+				eoptimestamp)));
 		GSL_RB_WRITE(ringcmds, rcmd_gpu,
 			rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
 	} else {
@@ -603,13 +598,11 @@
 			cp_type3_packet(CP_EVENT_WRITE, 3));
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
 		GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
-			      KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
-				      eoptimestamp)));
-		GSL_RB_WRITE(ringcmds, rcmd_gpu,
-			rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
+			KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
+		GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[context_id]);
 	}
 
-	if (!(flags & KGSL_CMD_FLAGS_NO_TS_CMP)) {
+	if (context) {
 		/* Conditional execution based on memory values */
 		GSL_RB_WRITE(ringcmds, rcmd_gpu,
 			cp_type3_packet(CP_COND_EXEC, 4));
@@ -641,6 +634,30 @@
 	return timestamp;
 }
 
+void
+adreno_ringbuffer_issuecmds_intr(struct kgsl_device *device,
+						struct kgsl_context *k_ctxt,
+						unsigned int *cmds,
+						int sizedwords)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+	struct adreno_context *a_ctxt = NULL;
+
+	if (!k_ctxt)
+		return;
+
+	a_ctxt = k_ctxt->devctxt;
+
+	if (k_ctxt->id == KGSL_CONTEXT_INVALID ||
+		a_ctxt == NULL ||
+		device->state & KGSL_STATE_HUNG)
+		return;
+
+	adreno_ringbuffer_addcmds(rb, a_ctxt, KGSL_CMD_FLAGS_DUMMY_INTR_CMD,
+			cmds, sizedwords);
+}
+
 unsigned int
 adreno_ringbuffer_issuecmds(struct kgsl_device *device,
 						struct adreno_context *drawctxt,
@@ -942,7 +959,7 @@
 	 * this is conservative but works reliably and is ok
 	 * even for performance simulations
 	 */
-	adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+	adreno_idle(device);
 #endif
 	/* If context hung and recovered then return error so that the
 	 * application may handle it */
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index 4cc57c2..6c3d9b1 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -110,6 +110,11 @@
 					unsigned int *cmdaddr,
 					int sizedwords);
 
+void adreno_ringbuffer_issuecmds_intr(struct kgsl_device *device,
+					struct kgsl_context *k_ctxt,
+					unsigned int *cmdaddr,
+					int sizedwords);
+
 void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb);
 
 void kgsl_cp_intrcallback(struct kgsl_device *device);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 5991dfd..e7a1c135 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -450,6 +450,7 @@
 	    device->state == KGSL_STATE_ACTIVE &&
 		device->requested_state == KGSL_STATE_NONE) {
 		kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
+		kgsl_pwrscale_idle(device, 1);
 		if (kgsl_pwrctrl_sleep(device) != 0)
 			mod_timer(&device->idle_timer,
 				  jiffies +
@@ -558,7 +559,7 @@
 			break;
 		case KGSL_STATE_ACTIVE:
 			/* Wait for the device to become idle */
-			device->ftbl->idle(device, KGSL_TIMEOUT_DEFAULT);
+			device->ftbl->idle(device);
 		case KGSL_STATE_NAP:
 		case KGSL_STATE_SLEEP:
 			/* Get the completion ready to be waited upon. */
@@ -2176,7 +2177,7 @@
 static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 {
 	struct kgsl_device_private *dev_priv = filep->private_data;
-	unsigned int nr = _IOC_NR(cmd);
+	unsigned int nr;
 	kgsl_ioctl_func_t func;
 	int lock, ret;
 	char ustack[64];
@@ -2192,6 +2193,8 @@
 	else if (cmd == IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_OLD)
 		cmd = IOCTL_KGSL_CMDSTREAM_READTIMESTAMP;
 
+	nr = _IOC_NR(cmd);
+
 	if (cmd & (IOC_IN | IOC_OUT)) {
 		if (_IOC_SIZE(cmd) < sizeof(ustack))
 			uptr = ustack;
@@ -2216,7 +2219,20 @@
 	}
 
 	if (nr < ARRAY_SIZE(kgsl_ioctl_funcs) &&
-	    kgsl_ioctl_funcs[nr].func != NULL) {
+		kgsl_ioctl_funcs[nr].func != NULL) {
+
+		/*
+		 * Make sure that nobody tried to send us a malformed ioctl code
+		 * with a valid NR but bogus flags
+		 */
+
+		if (kgsl_ioctl_funcs[nr].cmd != cmd) {
+			KGSL_DRV_ERR(dev_priv->device,
+				"Malformed ioctl code %08x\n", cmd);
+			ret = -ENOIOCTLCMD;
+			goto done;
+		}
+
 		func = kgsl_ioctl_funcs[nr].func;
 		lock = kgsl_ioctl_funcs[nr].lock;
 	} else {
@@ -2570,6 +2586,83 @@
 }
 EXPORT_SYMBOL(kgsl_device_platform_probe);
 
+int kgsl_postmortem_dump(struct kgsl_device *device, int manual)
+{
+	bool saved_nap;
+	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+
+	BUG_ON(device == NULL);
+
+	kgsl_cffdump_hang(device->id);
+
+	/* For a manual dump, make sure that the system is idle */
+
+	if (manual) {
+		if (device->active_cnt != 0) {
+			mutex_unlock(&device->mutex);
+			wait_for_completion(&device->suspend_gate);
+			mutex_lock(&device->mutex);
+		}
+
+		if (device->state == KGSL_STATE_ACTIVE)
+			kgsl_idle(device);
+
+	}
+	KGSL_LOG_DUMP(device, "|%s| Dump Started\n", device->name);
+	KGSL_LOG_DUMP(device, "POWER: FLAGS = %08lX | ACTIVE POWERLEVEL = %08X",
+			pwr->power_flags, pwr->active_pwrlevel);
+
+	KGSL_LOG_DUMP(device, "POWER: INTERVAL TIMEOUT = %08X ",
+		pwr->interval_timeout);
+
+	KGSL_LOG_DUMP(device, "GRP_CLK = %lu ",
+				  kgsl_get_clkrate(pwr->grp_clks[0]));
+
+	KGSL_LOG_DUMP(device, "BUS CLK = %lu ",
+		kgsl_get_clkrate(pwr->ebi1_clk));
+
+	/* Disable the idle timer so we don't get interrupted */
+	del_timer_sync(&device->idle_timer);
+	mutex_unlock(&device->mutex);
+	flush_workqueue(device->work_queue);
+	mutex_lock(&device->mutex);
+
+	/* Turn off napping to make sure we have the clocks full
+	   attention through the following process */
+	saved_nap = device->pwrctrl.nap_allowed;
+	device->pwrctrl.nap_allowed = false;
+
+	/* Force on the clocks */
+	kgsl_pwrctrl_wake(device);
+
+	/* Disable the irq */
+	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
+
+	/*Call the device specific postmortem dump function*/
+	device->ftbl->postmortem_dump(device, manual);
+
+	/* Restore nap mode */
+	device->pwrctrl.nap_allowed = saved_nap;
+
+	/* On a manual trigger, turn on the interrupts and put
+	   the clocks to sleep.  They will recover themselves
+	   on the next event.  For a hang, leave things as they
+	   are until recovery kicks in. */
+
+	if (manual) {
+		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
+
+		/* try to go into a sleep mode until the next event */
+		kgsl_pwrctrl_request_state(device, KGSL_STATE_SLEEP);
+		kgsl_pwrctrl_sleep(device);
+	}
+
+	KGSL_LOG_DUMP(device, "|%s| Dump Finished\n", device->name);
+
+	return 0;
+}
+EXPORT_SYMBOL(kgsl_postmortem_dump);
+
 void kgsl_device_platform_remove(struct kgsl_device *device)
 {
 	kgsl_device_snapshot_close(device);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 8a3345b..ac04c56 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -173,6 +173,7 @@
 #endif
 
 void kgsl_mem_entry_destroy(struct kref *kref);
+int kgsl_postmortem_dump(struct kgsl_device *device, int manual);
 
 struct kgsl_mem_entry *kgsl_get_mem_entry(unsigned int ptbase,
 		unsigned int gpuaddr, unsigned int size);
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index 328dd95e..545d2b3 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -22,6 +22,60 @@
 #define KGSL_LOG_LEVEL_MAX     7
 
 struct dentry *kgsl_debugfs_dir;
+static struct dentry *pm_d_debugfs;
+
+static int pm_dump_set(void *data, u64 val)
+{
+	struct kgsl_device *device = data;
+
+	if (val) {
+		mutex_lock(&device->mutex);
+		kgsl_postmortem_dump(device, 1);
+		mutex_unlock(&device->mutex);
+	}
+
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(pm_dump_fops,
+			NULL,
+			pm_dump_set, "%llu\n");
+
+static int pm_regs_enabled_set(void *data, u64 val)
+{
+	struct kgsl_device *device = data;
+	device->pm_regs_enabled = val ? 1 : 0;
+	return 0;
+}
+
+static int pm_regs_enabled_get(void *data, u64 *val)
+{
+	struct kgsl_device *device = data;
+	*val = device->pm_regs_enabled;
+	return 0;
+}
+
+static int pm_ib_enabled_set(void *data, u64 val)
+{
+	struct kgsl_device *device = data;
+	device->pm_ib_enabled = val ? 1 : 0;
+	return 0;
+}
+
+static int pm_ib_enabled_get(void *data, u64 *val)
+{
+	struct kgsl_device *device = data;
+	*val = device->pm_ib_enabled;
+	return 0;
+}
+
+
+DEFINE_SIMPLE_ATTRIBUTE(pm_regs_enabled_fops,
+			pm_regs_enabled_get,
+			pm_regs_enabled_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(pm_ib_enabled_fops,
+			pm_ib_enabled_get,
+			pm_ib_enabled_set, "%llu\n");
 
 static inline int kgsl_log_set(unsigned int *log_val, void *data, u64 val)
 {
@@ -75,6 +129,21 @@
 				&mem_log_fops);
 	debugfs_create_file("log_level_pwr", 0644, device->d_debugfs, device,
 				&pwr_log_fops);
+
+	/* Create postmortem dump control files */
+
+	pm_d_debugfs = debugfs_create_dir("postmortem", device->d_debugfs);
+
+	if (IS_ERR(pm_d_debugfs))
+		return;
+
+	debugfs_create_file("dump",  0600, pm_d_debugfs, device,
+			    &pm_dump_fops);
+	debugfs_create_file("regs_enabled", 0644, pm_d_debugfs, device,
+			    &pm_regs_enabled_fops);
+	debugfs_create_file("ib_enabled", 0644, pm_d_debugfs, device,
+				    &pm_ib_enabled_fops);
+
 }
 
 void kgsl_core_debugfs_init(void)
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 0336a20..2a2e916 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -67,7 +67,7 @@
 		unsigned int offsetwords, unsigned int *value);
 	void (*regwrite) (struct kgsl_device *device,
 		unsigned int offsetwords, unsigned int value);
-	int (*idle) (struct kgsl_device *device, unsigned int timeout);
+	int (*idle) (struct kgsl_device *device);
 	unsigned int (*isidle) (struct kgsl_device *device);
 	int (*suspend_context) (struct kgsl_device *device);
 	int (*start) (struct kgsl_device *device, unsigned int init_ram);
@@ -110,6 +110,7 @@
 	int (*setproperty) (struct kgsl_device *device,
 		enum kgsl_property_type type, void *value,
 		unsigned int sizebytes);
+	int (*postmortem_dump) (struct kgsl_device *device, int manual);
 };
 
 /* MH register values */
@@ -196,6 +197,10 @@
 	struct work_struct ts_expired_ws;
 	struct list_head events;
 	s64 on_time;
+
+	/* Postmortem Control switches */
+	int pm_regs_enabled;
+	int pm_ib_enabled;
 };
 
 void kgsl_timestamp_expired(struct work_struct *work);
@@ -282,9 +287,9 @@
 	device->ftbl->regwrite(device, offsetwords, value);
 }
 
-static inline int kgsl_idle(struct kgsl_device *device, unsigned int timeout)
+static inline int kgsl_idle(struct kgsl_device *device)
 {
-	return device->ftbl->idle(device, timeout);
+	return device->ftbl->idle(device);
 }
 
 static inline unsigned int kgsl_gpuid(struct kgsl_device *device,
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index edccff1..8cf00ea 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -472,7 +472,7 @@
 		return;
 
 	if (flags & KGSL_MMUFLAGS_PTUPDATE) {
-		kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
+		kgsl_idle(mmu->device);
 		gpummu_pt = mmu->hwpagetable->priv;
 		kgsl_regwrite(mmu->device, MH_MMU_PT_BASE,
 			gpummu_pt->base.gpuaddr);
@@ -552,7 +552,7 @@
 	kgsl_regwrite(device, MH_MMU_CONFIG, mmu->config);
 
 	/* idle device */
-	kgsl_idle(device,  KGSL_TIMEOUT_DEFAULT);
+	kgsl_idle(device);
 
 	/* enable axi interrupts */
 	kgsl_regwrite(device, MH_INTERRUPT_MASK,
@@ -686,7 +686,6 @@
 
 static void kgsl_gpummu_stop(struct kgsl_mmu *mmu)
 {
-	kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
 	mmu->flags &= ~KGSL_FLAGS_STARTED;
 }
 
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 016771b..1eb671f 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -880,7 +880,6 @@
 	 */
 
 	if (mmu->flags & KGSL_FLAGS_STARTED) {
-		kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
 		/* detach iommu attachment */
 		kgsl_detach_pagetable_iommu_domain(mmu);
 		mmu->hwpagetable = NULL;
@@ -967,7 +966,7 @@
 	/* Mask off the lsb of the pt base address since lsb will not change */
 	pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK << KGSL_IOMMU_TTBR0_PA_SHIFT);
 	if (flags & KGSL_MMUFLAGS_PTUPDATE) {
-		kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
+		kgsl_idle(mmu->device);
 		for (i = 0; i < iommu->unit_count; i++) {
 			/* get the lsb value which should not change when
 			 * changing ttbr0 */
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index c02274d..0426339 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -24,7 +24,6 @@
 #include "kgsl_mmu.h"
 #include "kgsl_device.h"
 #include "kgsl_sharedmem.h"
-#include "adreno_postmortem.h"
 
 #define KGSL_MMU_ALIGN_SHIFT    13
 #define KGSL_MMU_ALIGN_MASK     (~((1 << KGSL_MMU_ALIGN_SHIFT) - 1))
@@ -561,7 +560,7 @@
 	struct kgsl_mh *mh = &device->mh;
 	/* force mmu off to for now*/
 	kgsl_regwrite(device, MH_MMU_CONFIG, 0);
-	kgsl_idle(device,  KGSL_TIMEOUT_DEFAULT);
+	kgsl_idle(device);
 
 	/* define physical memory range accessible by the core */
 	kgsl_regwrite(device, MH_MMU_MPU_BASE, mh->mpu_base);
@@ -825,3 +824,13 @@
 		kgsl_mmu_type = KGSL_MMU_TYPE_NONE;
 }
 EXPORT_SYMBOL(kgsl_mmu_set_mmutype);
+
+int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr)
+{
+	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
+		return 1;
+	return ((gpuaddr >= KGSL_PAGETABLE_BASE) &&
+		(gpuaddr < (KGSL_PAGETABLE_BASE + kgsl_mmu_get_ptsize())));
+}
+EXPORT_SYMBOL(kgsl_mmu_gpuaddr_in_range);
+
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index bc6ec8e..8221b80 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -205,6 +205,7 @@
 void kgsl_mmu_set_mmutype(char *mmutype);
 enum kgsl_mmutype kgsl_mmu_get_mmutype(void);
 unsigned int kgsl_mmu_get_ptsize(void);
+int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr);
 
 /*
  * Static inline functions of MMU that simply call the SMMU specific
@@ -293,10 +294,14 @@
 		mmu->mmu_ops->mmu_disable_clk_on_ts(mmu, ts, ts_valid);
 }
 
-static inline int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr)
+static inline unsigned int kgsl_mmu_get_int_mask(void)
 {
-	return ((gpuaddr >= KGSL_PAGETABLE_BASE) &&
-		(gpuaddr < (KGSL_PAGETABLE_BASE + kgsl_mmu_get_ptsize())));
+	/* Dont enable gpummu interrupts, if iommu is enabled */
+	if (KGSL_MMU_TYPE_GPU == kgsl_mmu_get_mmutype())
+		return KGSL_MMU_INT_MASK;
+	else
+		return (MH_INTERRUPT_MASK__AXI_READ_ERROR |
+			MH_INTERRUPT_MASK__AXI_WRITE_ERROR);
 }
 
 #endif /* __KGSL_MMU_H */
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 8759dc6..736fb4e 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -17,6 +17,7 @@
 #include <linux/pm_runtime.h>
 #include <mach/msm_iomap.h>
 #include <mach/msm_bus.h>
+#include <linux/ktime.h>
 
 #include "kgsl.h"
 #include "kgsl_pwrscale.h"
@@ -60,6 +61,30 @@
 	},
 };
 
+/* Update the elapsed time at a particular clock level
+ * if the device is active(on_time = true).Otherwise
+ * store it as sleep time.
+ */
+static void update_clk_statistics(struct kgsl_device *device,
+				bool on_time)
+{
+	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+	struct kgsl_clk_stats *clkstats = &pwr->clk_stats;
+	ktime_t elapsed;
+	int elapsed_us;
+	if (clkstats->start.tv64 == 0)
+		clkstats->start = ktime_get();
+	clkstats->stop = ktime_get();
+	elapsed = ktime_sub(clkstats->stop, clkstats->start);
+	elapsed_us = ktime_to_us(elapsed);
+	clkstats->elapsed += elapsed_us;
+	if (on_time)
+		clkstats->clock_time[pwr->active_pwrlevel] += elapsed_us;
+	else
+		clkstats->clock_time[pwr->num_pwrlevels - 1] += elapsed_us;
+	clkstats->start = ktime_get();
+}
+
 void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
 				unsigned int new_level)
 {
@@ -71,6 +96,9 @@
 		int diff = new_level - pwr->active_pwrlevel;
 		int d = (diff > 0) ? 1 : -1;
 		int level = pwr->active_pwrlevel;
+		/* Update the clock stats */
+		update_clk_statistics(device, true);
+		/* Finally set active level */
 		pwr->active_pwrlevel = new_level;
 		if ((test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags)) ||
 			(device->state == KGSL_STATE_NAP)) {
@@ -80,8 +108,8 @@
 			 * Idle the gpu core before changing the clock freq.
 			 */
 			if (pwr->idle_needed == true)
-				device->ftbl->idle(device,
-						KGSL_TIMEOUT_DEFAULT);
+				device->ftbl->idle(device);
+
 			/* Don't shift by more than one level at a time to
 			 * avoid glitches.
 			 */
@@ -285,23 +313,51 @@
 {
 	int ret;
 	struct kgsl_device *device = kgsl_device_from_dev(dev);
-	struct kgsl_busy *b = &device->pwrctrl.busy;
-	ret = snprintf(buf, 17, "%7d %7d\n",
-				   b->on_time_old, b->time_old);
+	struct kgsl_clk_stats *clkstats = &device->pwrctrl.clk_stats;
+	ret = snprintf(buf, PAGE_SIZE, "%7d %7d\n",
+			clkstats->on_time_old, clkstats->elapsed_old);
 	if (!test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) {
-		b->on_time_old = 0;
-		b->time_old = 0;
+		clkstats->on_time_old = 0;
+		clkstats->elapsed_old = 0;
 	}
 	return ret;
 }
 
+static int kgsl_pwrctrl_gputop_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	int ret;
+	struct kgsl_device *device = kgsl_device_from_dev(dev);
+	struct kgsl_clk_stats *clkstats = &device->pwrctrl.clk_stats;
+	int i = 0;
+	char *ptr = buf;
+
+	ret = snprintf(buf, PAGE_SIZE, "%7d %7d ", clkstats->on_time_old,
+					clkstats->elapsed_old);
+	for (i = 0, ptr += ret; i < device->pwrctrl.num_pwrlevels;
+							i++, ptr += ret)
+		ret = snprintf(ptr, PAGE_SIZE, "%7d ",
+						clkstats->old_clock_time[i]);
+
+	if (!test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) {
+		clkstats->on_time_old = 0;
+		clkstats->elapsed_old = 0;
+		for (i = 0; i < KGSL_MAX_PWRLEVELS ; i++)
+			clkstats->old_clock_time[i] = 0;
+	}
+	return (unsigned int) (ptr - buf);
+}
+
 DEVICE_ATTR(gpuclk, 0644, kgsl_pwrctrl_gpuclk_show, kgsl_pwrctrl_gpuclk_store);
 DEVICE_ATTR(max_gpuclk, 0644, kgsl_pwrctrl_max_gpuclk_show,
 	kgsl_pwrctrl_max_gpuclk_store);
 DEVICE_ATTR(pwrnap, 0664, kgsl_pwrctrl_pwrnap_show, kgsl_pwrctrl_pwrnap_store);
 DEVICE_ATTR(idle_timer, 0644, kgsl_pwrctrl_idle_timer_show,
 	kgsl_pwrctrl_idle_timer_store);
-DEVICE_ATTR(gpubusy, 0644, kgsl_pwrctrl_gpubusy_show,
+DEVICE_ATTR(gpubusy, 0444, kgsl_pwrctrl_gpubusy_show,
+	NULL);
+DEVICE_ATTR(gputop, 0444, kgsl_pwrctrl_gputop_show,
 	NULL);
 
 static const struct device_attribute *pwrctrl_attr_list[] = {
@@ -310,6 +366,7 @@
 	&dev_attr_pwrnap,
 	&dev_attr_idle_timer,
 	&dev_attr_gpubusy,
+	&dev_attr_gputop,
 	NULL
 };
 
@@ -323,29 +380,37 @@
 	kgsl_remove_device_sysfs_files(device->dev, pwrctrl_attr_list);
 }
 
+static void update_statistics(struct kgsl_device *device)
+{
+	struct kgsl_clk_stats *clkstats = &device->pwrctrl.clk_stats;
+	unsigned int on_time = 0;
+	int i;
+	int num_pwrlevels = device->pwrctrl.num_pwrlevels - 1;
+	/*PER CLK TIME*/
+	for (i = 0; i < num_pwrlevels; i++) {
+		clkstats->old_clock_time[i] = clkstats->clock_time[i];
+		on_time += clkstats->clock_time[i];
+		clkstats->clock_time[i] = 0;
+	}
+	clkstats->old_clock_time[num_pwrlevels] =
+				clkstats->clock_time[num_pwrlevels];
+	clkstats->clock_time[num_pwrlevels] = 0;
+	clkstats->on_time_old = on_time;
+	clkstats->elapsed_old = clkstats->elapsed;
+	clkstats->elapsed = 0;
+}
+
 /* Track the amount of time the gpu is on vs the total system time. *
  * Regularly update the percentage of busy time displayed by sysfs. */
 static void kgsl_pwrctrl_busy_time(struct kgsl_device *device, bool on_time)
 {
-	struct kgsl_busy *b = &device->pwrctrl.busy;
-	int elapsed;
-	if (b->start.tv_sec == 0)
-		do_gettimeofday(&(b->start));
-	do_gettimeofday(&(b->stop));
-	elapsed = (b->stop.tv_sec - b->start.tv_sec) * 1000000;
-	elapsed += b->stop.tv_usec - b->start.tv_usec;
-	b->time += elapsed;
-	if (on_time)
-		b->on_time += elapsed;
+	struct kgsl_clk_stats *clkstats = &device->pwrctrl.clk_stats;
+	update_clk_statistics(device, on_time);
 	/* Update the output regularly and reset the counters. */
-	if ((b->time > UPDATE_BUSY_VAL) ||
+	if ((clkstats->elapsed > UPDATE_BUSY_VAL) ||
 		!test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) {
-		b->on_time_old = b->on_time;
-		b->time_old = b->time;
-		b->on_time = 0;
-		b->time = 0;
+		update_statistics(device);
 	}
-	do_gettimeofday(&(b->start));
 }
 
 void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
@@ -439,8 +504,8 @@
 		if (test_and_clear_bit(KGSL_PWRFLAGS_POWER_ON,
 			&pwr->power_flags)) {
 			trace_kgsl_rail(device, state);
-			if (pwr->gpu_dig)
-				regulator_disable(pwr->gpu_dig);
+			if (pwr->gpu_cx)
+				regulator_disable(pwr->gpu_cx);
 			if (pwr->gpu_reg)
 				regulator_disable(pwr->gpu_reg);
 		}
@@ -456,8 +521,8 @@
 							"failed: %d\n",
 							status);
 			}
-			if (pwr->gpu_dig) {
-				int status = regulator_enable(pwr->gpu_dig);
+			if (pwr->gpu_cx) {
+				int status = regulator_enable(pwr->gpu_cx);
 				if (status)
 					KGSL_DRV_ERR(device,
 							"cx regulator_enable "
@@ -547,11 +612,11 @@
 		pwr->gpu_reg = NULL;
 
 	if (pwr->gpu_reg) {
-		pwr->gpu_dig = regulator_get(&pdev->dev, "vdd_dig");
-		if (IS_ERR(pwr->gpu_dig))
-			pwr->gpu_dig = NULL;
+		pwr->gpu_cx = regulator_get(&pdev->dev, "vddcx");
+		if (IS_ERR(pwr->gpu_cx))
+			pwr->gpu_cx = NULL;
 	} else
-		pwr->gpu_dig = NULL;
+		pwr->gpu_cx = NULL;
 
 	pwr->power_flags = 0;
 
@@ -615,9 +680,9 @@
 		pwr->gpu_reg = NULL;
 	}
 
-	if (pwr->gpu_dig) {
-		regulator_put(pwr->gpu_dig);
-		pwr->gpu_dig = NULL;
+	if (pwr->gpu_cx) {
+		regulator_put(pwr->gpu_cx);
+		pwr->gpu_cx = NULL;
 	}
 
 	for (i = 1; i < KGSL_MAX_CLKS; i++)
@@ -640,7 +705,7 @@
 
 	mutex_lock(&device->mutex);
 	if (device->state & (KGSL_STATE_ACTIVE | KGSL_STATE_NAP)) {
-		kgsl_pwrscale_idle(device);
+		kgsl_pwrscale_idle(device, 0);
 
 		if (kgsl_pwrctrl_sleep(device) != 0) {
 			mod_timer(&device->idle_timer,
@@ -648,10 +713,11 @@
 					device->pwrctrl.interval_timeout);
 			/* If the GPU has been too busy to sleep, make sure *
 			 * that is acurately reflected in the % busy numbers. */
-			device->pwrctrl.busy.no_nap_cnt++;
-			if (device->pwrctrl.busy.no_nap_cnt > UPDATE_BUSY) {
+			device->pwrctrl.clk_stats.no_nap_cnt++;
+			if (device->pwrctrl.clk_stats.no_nap_cnt >
+							 UPDATE_BUSY) {
 				kgsl_pwrctrl_busy_time(device, true);
-				device->pwrctrl.busy.no_nap_cnt = 0;
+				device->pwrctrl.clk_stats.no_nap_cnt = 0;
 			}
 		}
 	} else if (device->state & (KGSL_STATE_HUNG |
@@ -753,7 +819,7 @@
 _sleep_accounting(struct kgsl_device *device)
 {
 	kgsl_pwrctrl_busy_time(device, false);
-	device->pwrctrl.busy.start.tv_sec = 0;
+	device->pwrctrl.clk_stats.start = ktime_set(0, 0);
 	device->pwrctrl.time = 0;
 	kgsl_pwrscale_sleep(device);
 }
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 954c818..c02a9fc 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -27,14 +27,15 @@
 
 struct platform_device;
 
-struct kgsl_busy {
-	struct timeval start;
-	struct timeval stop;
-	int on_time;
-	int time;
-	int on_time_old;
-	int time_old;
+struct kgsl_clk_stats {
+	unsigned int old_clock_time[KGSL_MAX_PWRLEVELS];
+	unsigned int clock_time[KGSL_MAX_PWRLEVELS];
+	unsigned int on_time_old;
+	ktime_t start;
+	ktime_t stop;
 	unsigned int no_nap_cnt;
+	unsigned int elapsed;
+	unsigned int elapsed_old;
 };
 
 struct kgsl_pwrctrl {
@@ -50,14 +51,14 @@
 	unsigned int interval_timeout;
 	bool strtstp_sleepwake;
 	struct regulator *gpu_reg;
-	struct regulator *gpu_dig;
+	struct regulator *gpu_cx;
 	uint32_t pcl;
 	unsigned int nap_allowed;
 	unsigned int idle_needed;
 	const char *irq_name;
 	s64 time;
-	struct kgsl_busy busy;
 	unsigned int restore_slumber;
+	struct kgsl_clk_stats clk_stats;
 };
 
 void kgsl_pwrctrl_irq(struct kgsl_device *device, int state);
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index 6fb9326..f6277b3 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -237,21 +237,18 @@
 void kgsl_pwrscale_busy(struct kgsl_device *device)
 {
 	if (PWRSCALE_ACTIVE(device) && device->pwrscale.policy->busy)
-		if ((!device->pwrscale.gpu_busy) &&
-			(device->requested_state != KGSL_STATE_SLUMBER))
+		if (device->requested_state != KGSL_STATE_SLUMBER)
 			device->pwrscale.policy->busy(device,
 					&device->pwrscale);
-	device->pwrscale.gpu_busy = 1;
 }
 
-void kgsl_pwrscale_idle(struct kgsl_device *device)
+void kgsl_pwrscale_idle(struct kgsl_device *device, unsigned int ignore_idle)
 {
 	if (PWRSCALE_ACTIVE(device) && device->pwrscale.policy->idle)
 		if (device->requested_state != KGSL_STATE_SLUMBER &&
 			device->requested_state != KGSL_STATE_SLEEP)
 			device->pwrscale.policy->idle(device,
-					&device->pwrscale);
-	device->pwrscale.gpu_busy = 0;
+					&device->pwrscale, ignore_idle);
 }
 EXPORT_SYMBOL(kgsl_pwrscale_idle);
 
diff --git a/drivers/gpu/msm/kgsl_pwrscale.h b/drivers/gpu/msm/kgsl_pwrscale.h
index 34698cd..ba9b1af 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.h
+++ b/drivers/gpu/msm/kgsl_pwrscale.h
@@ -23,7 +23,8 @@
 	void (*close)(struct kgsl_device *device,
 		struct kgsl_pwrscale *pwrscale);
 	void (*idle)(struct kgsl_device *device,
-		struct kgsl_pwrscale *pwrscale);
+		struct kgsl_pwrscale *pwrscale,
+		unsigned int ignore_idle);
 	void (*busy)(struct kgsl_device *device,
 		struct kgsl_pwrscale *pwrscale);
 	void (*sleep)(struct kgsl_device *device,
@@ -36,7 +37,6 @@
 	struct kgsl_pwrscale_policy *policy;
 	struct kobject kobj;
 	void *priv;
-	int gpu_busy;
 	int enabled;
 };
 
@@ -64,7 +64,8 @@
 	struct kgsl_pwrscale_policy *policy);
 void kgsl_pwrscale_detach_policy(struct kgsl_device *device);
 
-void kgsl_pwrscale_idle(struct kgsl_device *device);
+void kgsl_pwrscale_idle(struct kgsl_device *device,
+				unsigned int ignore_idle);
 void kgsl_pwrscale_busy(struct kgsl_device *device);
 void kgsl_pwrscale_sleep(struct kgsl_device *device);
 void kgsl_pwrscale_wake(struct kgsl_device *device);
diff --git a/drivers/gpu/msm/kgsl_pwrscale_idlestats.c b/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
index 4102302..fc58dd1 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
@@ -131,7 +131,7 @@
 }
 
 static void idlestats_idle(struct kgsl_device *device,
-			struct kgsl_pwrscale *pwrscale)
+		struct kgsl_pwrscale *pwrscale, unsigned int ignore_idle)
 {
 	int i, nr_cpu;
 	struct idlestats_priv *priv = pwrscale->priv;
diff --git a/drivers/gpu/msm/kgsl_pwrscale_msm.c b/drivers/gpu/msm/kgsl_pwrscale_msm.c
index 61d4b2d..c6f8b1b 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_msm.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_msm.c
@@ -17,6 +17,7 @@
 #include "kgsl_pwrscale.h"
 #include "kgsl_device.h"
 #include "a2xx_reg.h"
+#include "kgsl_trace.h"
 
 struct msm_priv {
 	struct kgsl_device *device;
@@ -26,6 +27,7 @@
 	struct msm_dcvs_idle idle_source;
 	struct msm_dcvs_freq freq_sink;
 	struct msm_dcvs_core_info *core_info;
+	int gpu_busy;
 };
 
 static int msm_idle_enable(struct msm_dcvs_idle *self,
@@ -89,29 +91,40 @@
 			struct kgsl_pwrscale *pwrscale)
 {
 	struct msm_priv *priv = pwrscale->priv;
-	if (priv->enabled)
+	if (priv->enabled && !priv->gpu_busy) {
 		msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_EXIT, 0);
+		trace_kgsl_mpdcvs(device, 1);
+		priv->gpu_busy = 1;
+	}
 	return;
 }
 
 static void msm_idle(struct kgsl_device *device,
-			struct kgsl_pwrscale *pwrscale)
+		struct kgsl_pwrscale *pwrscale, unsigned int ignore_idle)
 {
 	struct msm_priv *priv = pwrscale->priv;
-	unsigned int rb_rptr, rb_wptr;
-	kgsl_regread(device, REG_CP_RB_RPTR, &rb_rptr);
-	kgsl_regread(device, REG_CP_RB_WPTR, &rb_wptr);
 
-	if (priv->enabled && (rb_rptr == rb_wptr))
-		msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
-
+	if (priv->enabled && priv->gpu_busy)
+		if (device->ftbl->isidle(device)) {
+			msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
+			trace_kgsl_mpdcvs(device, 0);
+			priv->gpu_busy = 0;
+		}
 	return;
 }
 
 static void msm_sleep(struct kgsl_device *device,
 			struct kgsl_pwrscale *pwrscale)
 {
-	/* do we need to reset any parameters here? */
+	struct msm_priv *priv = pwrscale->priv;
+
+	if (priv->enabled && priv->gpu_busy) {
+		msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
+		trace_kgsl_mpdcvs(device, 0);
+		priv->gpu_busy = 0;
+	}
+
+	return;
 }
 
 static int msm_init(struct kgsl_device *device,
@@ -159,10 +172,10 @@
 	ret = msm_dcvs_freq_sink_register(&priv->freq_sink);
 	if (ret >= 0) {
 		if (device->ftbl->isidle(device)) {
-			device->pwrscale.gpu_busy = 0;
+			priv->gpu_busy = 0;
 			msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
 		} else {
-			device->pwrscale.gpu_busy = 1;
+			priv->gpu_busy = 1;
 		}
 		return 0;
 	}
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index d6c5e66..1b029b1 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -119,16 +119,19 @@
 					device->pwrctrl.default_pwrlevel);
 }
 
-static void tz_idle(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale)
+static void tz_idle(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale,
+						unsigned int ignore_idle)
 {
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 	struct tz_priv *priv = pwrscale->priv;
 	struct kgsl_power_stats stats;
 	int val, idle;
 
+	if (ignore_idle)
+		return;
+
 	/* In "performance" mode the clock speed always stays
 	   the same */
-
 	if (priv->governor == TZ_GOVERNOR_PERFORMANCE)
 		return;
 
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 9c470f4..2bd03fb 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -438,6 +438,20 @@
 	free_contiguous_memory_by_paddr(memdesc->physaddr);
 }
 
+static int kgsl_ebimem_map_kernel(struct kgsl_memdesc *memdesc)
+{
+	if (!memdesc->hostptr) {
+		memdesc->hostptr = ioremap(memdesc->physaddr, memdesc->size);
+		if (!memdesc->hostptr) {
+			KGSL_CORE_ERR("ioremap failed, addr:0x%p, size:0x%x\n",
+				memdesc->hostptr, memdesc->size);
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
 static void kgsl_coherent_free(struct kgsl_memdesc *memdesc)
 {
 	kgsl_driver.stats.coherent -= memdesc->size;
@@ -458,6 +472,7 @@
 	.free = kgsl_ebimem_free,
 	.vmflags = kgsl_contiguous_vmflags,
 	.vmfault = kgsl_contiguous_vmfault,
+	.map_kernel_mem = kgsl_ebimem_map_kernel,
 };
 
 static struct kgsl_memdesc_ops kgsl_coherent_ops = {
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 3eff40f..81ab3fb 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -251,6 +251,29 @@
 	)
 );
 
+TRACE_EVENT(kgsl_mpdcvs,
+
+	TP_PROTO(struct kgsl_device *device, unsigned int state),
+
+	TP_ARGS(device, state),
+
+	TP_STRUCT__entry(
+		__string(device_name, device->name)
+		__field(unsigned int, state)
+	),
+
+	TP_fast_assign(
+		__assign_str(device_name, device->name);
+		__entry->state = state;
+	),
+
+	TP_printk(
+		"d_name=%s %s",
+		__get_str(device_name),
+		__entry->state ? "BUSY" : "IDLE"
+	)
+);
+
 DECLARE_EVENT_CLASS(kgsl_pwrstate_template,
 	TP_PROTO(struct kgsl_device *device, unsigned int state),
 
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 6efba45..8ddc991 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -25,9 +25,6 @@
 #define DRIVER_VERSION_MAJOR   3
 #define DRIVER_VERSION_MINOR   1
 
-#define Z180_DEVICE(device) \
-		KGSL_CONTAINER_OF(device, struct z180_device, dev)
-
 #define GSL_VGC_INT_MASK \
 	 (REG_VGC_IRQSTATUS__MH_MASK | \
 	  REG_VGC_IRQSTATUS__G2D_MASK | \
@@ -41,16 +38,12 @@
 #define VGV3_CONTROL_MARKADD_FSHIFT 0
 #define VGV3_CONTROL_MARKADD_FMASK 0xfff
 
-#define Z180_PACKET_SIZE 15
 #define Z180_MARKER_SIZE 10
 #define Z180_CALL_CMD     0x1000
 #define Z180_MARKER_CMD   0x8000
 #define Z180_STREAM_END_CMD 0x9000
 #define Z180_STREAM_PACKET 0x7C000176
 #define Z180_STREAM_PACKET_CALL 0x7C000275
-#define Z180_PACKET_COUNT 8
-#define Z180_RB_SIZE (Z180_PACKET_SIZE*Z180_PACKET_COUNT \
-			  *sizeof(uint32_t))
 
 #define NUMTEXUNITS             4
 #define TEXUNITREGCOUNT         25
@@ -365,7 +358,7 @@
 	return ts_diff < Z180_PACKET_COUNT;
 }
 
-static int z180_idle(struct kgsl_device *device, unsigned int timeout)
+static int z180_idle(struct kgsl_device *device)
 {
 	int status = 0;
 	struct z180_device *z180_dev = Z180_DEVICE(device);
@@ -373,7 +366,8 @@
 	if (timestamp_cmp(z180_dev->current_timestamp,
 		z180_dev->timestamp) > 0)
 		status = z180_wait(device, NULL,
-				z180_dev->current_timestamp, timeout);
+				z180_dev->current_timestamp,
+				Z180_IDLE_TIMEOUT);
 
 	if (status)
 		KGSL_DRV_ERR(device, "z180_waittimestamp() timed out\n");
@@ -590,7 +584,7 @@
 static int z180_stop(struct kgsl_device *device)
 {
 	device->ftbl->irqctrl(device, 0);
-	z180_idle(device, KGSL_TIMEOUT_DEFAULT);
+	z180_idle(device);
 
 	del_timer_sync(&device->idle_timer);
 
@@ -846,6 +840,7 @@
 	else if (timeout == 0) {
 		status = -ETIMEDOUT;
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_HUNG);
+		kgsl_postmortem_dump(device, 0);
 	} else
 		status = timeout;
 
@@ -858,7 +853,7 @@
 {
 	struct z180_device *z180_dev = Z180_DEVICE(device);
 
-	z180_idle(device, KGSL_TIMEOUT_DEFAULT);
+	z180_idle(device);
 
 	if (z180_dev->ringbuffer.prevctx == context->id) {
 		z180_dev->ringbuffer.prevctx = Z180_INVALID_CONTEXT;
@@ -892,7 +887,8 @@
 
 	if (state) {
 		z180_regwrite(device, (ADDR_VGC_IRQENABLE >> 2), 3);
-		z180_regwrite(device, MH_INTERRUPT_MASK, KGSL_MMU_INT_MASK);
+		z180_regwrite(device, MH_INTERRUPT_MASK,
+			kgsl_mmu_get_int_mask());
 	} else {
 		z180_regwrite(device, (ADDR_VGC_IRQENABLE >> 2), 0);
 		z180_regwrite(device, MH_INTERRUPT_MASK, 0);
@@ -935,6 +931,7 @@
 	.drawctxt_create = NULL,
 	.drawctxt_destroy = z180_drawctxt_destroy,
 	.ioctl = NULL,
+	.postmortem_dump = z180_dump,
 };
 
 static struct platform_device_id z180_id_table[] = {
diff --git a/drivers/gpu/msm/z180.h b/drivers/gpu/msm/z180.h
index e5c5ef3..a8973d2a 100644
--- a/drivers/gpu/msm/z180.h
+++ b/drivers/gpu/msm/z180.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -19,8 +19,18 @@
 #define DEVICE_2D0_NAME "kgsl-2d0"
 #define DEVICE_2D1_NAME "kgsl-2d1"
 
+#define Z180_PACKET_SIZE 15
+#define Z180_PACKET_COUNT 8
+#define Z180_RB_SIZE (Z180_PACKET_SIZE*Z180_PACKET_COUNT \
+			  *sizeof(uint32_t))
+#define Z180_DEVICE(device) \
+		KGSL_CONTAINER_OF(device, struct z180_device, dev)
+
 #define Z180_DEFAULT_PWRSCALE_POLICY  NULL
 
+/* Wait a maximum of 10 seconds when trying to idle the core */
+#define Z180_IDLE_TIMEOUT (10 * 1000)
+
 struct z180_ringbuffer {
 	unsigned int prevctx;
 	struct kgsl_memdesc      cmdbufdesc;
@@ -34,4 +44,6 @@
 	spinlock_t cmdwin_lock;
 };
 
+int z180_dump(struct kgsl_device *, int);
+
 #endif /* __Z180_H */
diff --git a/drivers/gpu/msm/z180_postmortem.c b/drivers/gpu/msm/z180_postmortem.c
new file mode 100644
index 0000000..a9b0c50
--- /dev/null
+++ b/drivers/gpu/msm/z180_postmortem.c
@@ -0,0 +1,229 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "kgsl.h"
+#include "kgsl_device.h"
+#include "z180.h"
+#include "z180_reg.h"
+
+#define Z180_STREAM_PACKET_CALL 0x7C000275
+
+/* Postmortem Dump formatted Output parameters */
+
+/* Number of Words per dump data line */
+#define WORDS_PER_LINE 8
+
+/* Number of spaces per dump data line */
+#define NUM_SPACES (WORDS_PER_LINE - 1)
+
+/*
+ * Output dump data is formatted as string, hence number of chars
+ * per line for line string allocation
+ */
+#define CHARS_PER_LINE  \
+	((WORDS_PER_LINE * (2*sizeof(unsigned int))) + NUM_SPACES + 1)
+
+/* Z180 registers (byte offsets) to be dumped */
+static const unsigned int regs_to_dump[] = {
+		ADDR_VGC_VERSION,
+		ADDR_VGC_SYSSTATUS,
+		ADDR_VGC_IRQSTATUS,
+		ADDR_VGC_IRQENABLE,
+		ADDR_VGC_IRQ_ACTIVE_CNT,
+		ADDR_VGC_CLOCKEN,
+		ADDR_VGC_MH_DATA_ADDR,
+		ADDR_VGC_GPR0,
+		ADDR_VGC_GPR1,
+		ADDR_VGC_BUSYCNT,
+		ADDR_VGC_FIFOFREE,
+};
+
+/**
+ * z180_dump_regs - Dumps all of Z180 external registers. Prints the word offset
+ * of the register in each output line.
+ * @device: kgsl_device pointer to the Z180 core
+ */
+static void z180_dump_regs(struct kgsl_device *device)
+{
+	unsigned int i;
+	unsigned int reg_val;
+
+	KGSL_LOG_DUMP(device, "Z180 Register Dump\n");
+	for (i = 0; i < ARRAY_SIZE(regs_to_dump); i++) {
+		kgsl_regread(device,
+				regs_to_dump[i]/sizeof(unsigned int), &reg_val);
+		KGSL_LOG_DUMP(device, "REG: %04X: %08X\n",
+				regs_to_dump[i]/sizeof(unsigned int), reg_val);
+	}
+}
+
+/**
+ * z180_dump_ringbuffer - Dumps the Z180 core's ringbuffer contents
+ * @device: kgsl_device pointer to the z180 core
+ */
+static void z180_dump_ringbuffer(struct kgsl_device *device)
+{
+	unsigned int rb_size;
+	unsigned int *rb_hostptr;
+	unsigned int rb_words;
+	unsigned int rb_gpuaddr;
+	struct z180_device *z180_dev = Z180_DEVICE(device);
+	unsigned int i;
+	char linebuf[CHARS_PER_LINE];
+
+	KGSL_LOG_DUMP(device, "Z180 ringbuffer dump\n");
+
+	rb_hostptr = (unsigned int *) z180_dev->ringbuffer.cmdbufdesc.hostptr;
+
+	rb_size = Z180_RB_SIZE;
+	rb_gpuaddr = z180_dev->ringbuffer.cmdbufdesc.gpuaddr;
+
+	rb_words = rb_size/sizeof(unsigned int);
+
+	KGSL_LOG_DUMP(device, "ringbuffer size: %u\n", rb_size);
+
+	KGSL_LOG_DUMP(device, "rb_words: %d\n", rb_words);
+
+	for (i = 0; i < rb_words; i += WORDS_PER_LINE) {
+		hex_dump_to_buffer(rb_hostptr+i,
+				rb_size - i*sizeof(unsigned int),
+				WORDS_PER_LINE*sizeof(unsigned int),
+				sizeof(unsigned int), linebuf,
+				sizeof(linebuf), false);
+		KGSL_LOG_DUMP(device, "RB: %04X: %s\n",
+				rb_gpuaddr + i*sizeof(unsigned int), linebuf);
+	}
+}
+
+
+static void z180_dump_ib(struct kgsl_device *device)
+{
+	unsigned int rb_size;
+	unsigned int *rb_hostptr;
+	unsigned int rb_words;
+	unsigned int rb_gpuaddr;
+	unsigned int ib_gpuptr = 0;
+	unsigned int ib_size = 0;
+	void *ib_hostptr = NULL;
+	int rb_slot_num = -1;
+	struct z180_device *z180_dev = Z180_DEVICE(device);
+	struct kgsl_mem_entry *entry = NULL;
+	unsigned int pt_base;
+	unsigned int i;
+	unsigned int j;
+	char linebuf[CHARS_PER_LINE];
+	unsigned int current_ib_slot;
+	unsigned int len;
+	unsigned int rowsize;
+	KGSL_LOG_DUMP(device, "Z180 IB dump\n");
+
+	rb_hostptr = (unsigned int *) z180_dev->ringbuffer.cmdbufdesc.hostptr;
+
+	rb_size = Z180_RB_SIZE;
+	rb_gpuaddr = z180_dev->ringbuffer.cmdbufdesc.gpuaddr;
+
+	rb_words = rb_size/sizeof(unsigned int);
+
+	KGSL_LOG_DUMP(device, "Ringbuffer size (bytes): %u\n", rb_size);
+
+	KGSL_LOG_DUMP(device, "rb_words: %d\n", rb_words);
+
+	pt_base = kgsl_mmu_get_current_ptbase(&device->mmu);
+
+	/* Dump the current IB */
+	for (i = 0; i < rb_words; i++) {
+		if (rb_hostptr[i] == Z180_STREAM_PACKET_CALL) {
+
+			rb_slot_num++;
+			current_ib_slot =
+				z180_dev->current_timestamp % Z180_PACKET_COUNT;
+			if (rb_slot_num != current_ib_slot)
+				continue;
+
+			ib_gpuptr = rb_hostptr[i+1];
+
+			entry = kgsl_get_mem_entry(pt_base, ib_gpuptr, 1);
+
+			if (entry == NULL) {
+				KGSL_LOG_DUMP(device,
+				"IB mem entry not found for ringbuffer slot#: %d\n",
+				rb_slot_num);
+				continue;
+			}
+
+			ib_hostptr = kgsl_memdesc_map(&entry->memdesc);
+
+			if (ib_hostptr == NULL) {
+				KGSL_LOG_DUMP(device,
+				"Could not map IB to kernel memory, Ringbuffer Slot: %d\n",
+				rb_slot_num);
+				continue;
+			}
+
+			ib_size = entry->memdesc.size;
+			KGSL_LOG_DUMP(device,
+				"IB size: %dbytes, IB size in words: %d\n",
+				ib_size,
+				ib_size/sizeof(unsigned int));
+
+			for (j = 0; j < ib_size; j += WORDS_PER_LINE) {
+				len = ib_size - j*sizeof(unsigned int);
+				rowsize = WORDS_PER_LINE*sizeof(unsigned int);
+				hex_dump_to_buffer(ib_hostptr+j, len, rowsize,
+						sizeof(unsigned int), linebuf,
+						sizeof(linebuf), false);
+				KGSL_LOG_DUMP(device, "IB%d: %04X: %s\n",
+						rb_slot_num,
+						(rb_gpuaddr +
+						j*sizeof(unsigned int)),
+						linebuf);
+			}
+			KGSL_LOG_DUMP(device, "IB Dump Finished\n");
+		}
+	}
+}
+
+
+/**
+ * z180_dump - Dumps the Z180 ringbuffer and registers (and IBs if asked for)
+ * for postmortem
+ * analysis.
+ * @device: kgsl_device pointer to the Z180 core
+ */
+int z180_dump(struct kgsl_device *device, int manual)
+{
+	struct z180_device *z180_dev = Z180_DEVICE(device);
+
+	mb();
+
+	KGSL_LOG_DUMP(device, "Retired Timestamp: %d\n", z180_dev->timestamp);
+	KGSL_LOG_DUMP(device,
+			"Current Timestamp: %d\n", z180_dev->current_timestamp);
+
+	/* Dump ringbuffer */
+	z180_dump_ringbuffer(device);
+
+	/* Dump registers */
+	z180_dump_regs(device);
+
+	/* Dump IBs, if asked for */
+	if (device->pm_ib_enabled)
+		z180_dump_ib(device);
+
+	/* Get the stack trace if the dump was automatic */
+	if (!manual)
+		BUG_ON(1);
+
+	return 0;
+}
+
diff --git a/drivers/gpu/msm/z180_reg.h b/drivers/gpu/msm/z180_reg.h
index 5b6c001..07d60b9 100644
--- a/drivers/gpu/msm/z180_reg.h
+++ b/drivers/gpu/msm/z180_reg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2007-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -45,5 +45,12 @@
 #define ADDR_VGV3_NEXTADDR               0x0075
 #define ADDR_VGV3_NEXTCMD                0x0076
 #define ADDR_VGV3_WRITEADDR              0x0072
+#define ADDR_VGC_VERSION				 0x400
+#define ADDR_VGC_SYSSTATUS				 0x410
+#define ADDR_VGC_CLOCKEN				 0x508
+#define ADDR_VGC_GPR0					 0x520
+#define ADDR_VGC_GPR1					 0x528
+#define ADDR_VGC_BUSYCNT				 0x530
+#define ADDR_VGC_FIFOFREE				 0x7c0
 
 #endif /* __Z180_REG_H */
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 53fec5b..1ed287a 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -878,6 +878,16 @@
 	  The VADC includes support for the conversion sequencer. The driver supports
 	  reading the ADC through the AMUX channels for external pull-ups simultaneously.
 
+config SENSORS_QPNP_ADC_CURRENT
+	tristate "Support for Qualcomm QPNP current ADC"
+	depends on SPMI
+	help
+	  This is the IADC driver for Qualcomm QPNP ADC Chip.
+
+	  The driver supports single mode operation to read from upto seven channel
+	  configuration that include reading the external/internal Rsense, CSP_EX,
+	  CSN_EX pair along with the gain and offset calibration.
+
 config SENSORS_PC87360
 	tristate "National Semiconductor PC87360 family"
 	depends on !PPC
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 2ff9454..ad5c6bb 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -131,6 +131,7 @@
 obj-$(CONFIG_SENSORS_PM8XXX_ADC)	+= pm8xxx-adc.o pm8xxx-adc-scale.o
 obj-$(CONFIG_SENSORS_EPM_ADC)	+= epm_adc.o
 obj-$(CONFIG_SENSORS_QPNP_ADC_VOLTAGE)	+= qpnp-adc-voltage.o qpnp-adc-common.o
+obj-$(CONFIG_SENSORS_QPNP_ADC_CURRENT)	+= qpnp-adc-current.o qpnp-adc-common.o
 
 obj-$(CONFIG_PMBUS)		+= pmbus/
 
diff --git a/drivers/hwmon/pm8xxx-adc.c b/drivers/hwmon/pm8xxx-adc.c
index aa9acf7..8e35252 100644
--- a/drivers/hwmon/pm8xxx-adc.c
+++ b/drivers/hwmon/pm8xxx-adc.c
@@ -23,7 +23,6 @@
 #include <linux/hwmon.h>
 #include <linux/module.h>
 #include <linux/debugfs.h>
-#include <linux/wakelock.h>
 #include <linux/interrupt.h>
 #include <linux/completion.h>
 #include <linux/hwmon-sysfs.h>
@@ -123,6 +122,7 @@
 #define PM8XXX_ADC_PA_THERM_VREG_UA_LOAD		100000
 #define PM8XXX_ADC_HWMON_NAME_LENGTH			32
 #define PM8XXX_ADC_BTM_INTERVAL_MAX			0x14
+#define PM8XXX_ADC_COMPLETION_TIMEOUT			(2 * HZ)
 
 struct pm8xxx_adc {
 	struct device				*dev;
@@ -141,7 +141,6 @@
 	struct work_struct			cool_work;
 	uint32_t				mpp_base;
 	struct device				*hwmon;
-	struct wake_lock			adc_wakelock;
 	int					msm_suspend_check;
 	struct pm8xxx_adc_amux_properties	*conv;
 	struct pm8xxx_adc_arb_btm_param		batt;
@@ -223,7 +222,6 @@
 			pr_err("PM8xxx ADC request made after suspend_noirq "
 					"with channel: %d\n", channel);
 		data_arb_cntrl |= PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB;
-		wake_lock(&adc_pmic->adc_wakelock);
 	}
 
 	/* Write twice to the CNTRL register for the arbiter settings
@@ -242,8 +240,7 @@
 		INIT_COMPLETION(adc_pmic->adc_rslt_completion);
 		rc = pm8xxx_writeb(adc_pmic->dev->parent,
 			PM8XXX_ADC_ARB_USRP_CNTRL1, data_arb_cntrl);
-	} else
-		wake_unlock(&adc_pmic->adc_wakelock);
+	}
 
 	return 0;
 }
@@ -734,7 +731,23 @@
 		goto fail;
 	}
 
-	wait_for_completion(&adc_pmic->adc_rslt_completion);
+	rc = wait_for_completion_timeout(&adc_pmic->adc_rslt_completion,
+						PM8XXX_ADC_COMPLETION_TIMEOUT);
+	if (!rc) {
+		u8 data_arb_usrp_cntrl1 = 0;
+		rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_CNTRL1,
+					&data_arb_usrp_cntrl1);
+		if (rc < 0)
+			goto fail;
+		if (data_arb_usrp_cntrl1 == (PM8XXX_ADC_ARB_USRP_CNTRL1_EOC |
+					PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB))
+			pr_debug("End of conversion status set\n");
+		else {
+			pr_err("EOC interrupt not received\n");
+			rc = -EINVAL;
+			goto fail;
+		}
+	}
 
 	rc = pm8xxx_adc_read_adc_code(&result->adc_code);
 	if (rc) {
@@ -1134,7 +1147,6 @@
 	struct pm8xxx_adc *adc_pmic = pmic_adc;
 	int i;
 
-	wake_lock_destroy(&adc_pmic->adc_wakelock);
 	platform_set_drvdata(pdev, NULL);
 	pmic_adc = NULL;
 	if (!pa_therm) {
@@ -1236,8 +1248,6 @@
 
 	disable_irq_nosync(adc_pmic->btm_cool_irq);
 	platform_set_drvdata(pdev, adc_pmic);
-	wake_lock_init(&adc_pmic->adc_wakelock, WAKE_LOCK_SUSPEND,
-					"pm8xxx_adc_wakelock");
 	adc_pmic->msm_suspend_check = 0;
 	pmic_adc = adc_pmic;
 
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index c8fe798..c122270 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -110,8 +110,8 @@
 	struct device_node *child;
 	struct qpnp_vadc_amux *adc_channel_list;
 	struct qpnp_adc_properties *adc_prop;
-	struct qpnp_vadc_amux_properties *amux_prop;
-	int count_adc_channel_list = 0, decimation, rc = 0;
+	struct qpnp_adc_amux_properties *amux_prop;
+	int count_adc_channel_list = 0, decimation, rc = 0, i = 0;
 
 	if (!node)
 		return -EINVAL;
@@ -133,7 +133,7 @@
 		return -ENOMEM;
 	}
 	adc_channel_list = devm_kzalloc(&spmi->dev,
-		(sizeof(struct qpnp_vadc_amux) * count_adc_channel_list),
+		sizeof(struct qpnp_vadc_amux) * count_adc_channel_list,
 				GFP_KERNEL);
 	if (!adc_channel_list) {
 		dev_err(&spmi->dev, "Unable to allocate memory\n");
@@ -141,16 +141,19 @@
 	}
 
 	amux_prop = devm_kzalloc(&spmi->dev,
-		sizeof(struct qpnp_vadc_amux_properties) +
+		sizeof(struct qpnp_adc_amux_properties) +
 		sizeof(struct qpnp_vadc_chan_properties), GFP_KERNEL);
 	if (!amux_prop) {
 		dev_err(&spmi->dev, "Unable to allocate memory\n");
 		return -ENOMEM;
 	}
 
+	adc_qpnp->adc_channels = adc_channel_list;
+	adc_qpnp->amux_prop = amux_prop;
+
 	for_each_child_of_node(node, child) {
 		int channel_num, scaling, post_scaling, hw_settle_time;
-		int fast_avg_setup, calib_type, i = 0, rc;
+		int fast_avg_setup, calib_type, rc;
 		const char *calibration_param, *channel_name;
 
 		channel_name = of_get_property(child,
@@ -216,8 +219,6 @@
 		adc_channel_list[i].fast_avg_setup = fast_avg_setup;
 		i++;
 	}
-	adc_qpnp->adc_channels = adc_channel_list;
-	adc_qpnp->amux_prop = amux_prop;
 
 	/* Get the ADC VDD reference voltage and ADC bit resolution */
 	rc = of_property_read_u32(node, "qcom,adc-vdd-reference",
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
new file mode 100644
index 0000000..b689255
--- /dev/null
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -0,0 +1,584 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/hwmon.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/spmi.h>
+#include <linux/of_irq.h>
+#include <linux/wakelock.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/qpnp/qpnp-adc.h>
+#include <linux/platform_device.h>
+
+/* QPNP IADC register definition */
+#define QPNP_STATUS1					0x8
+#define QPNP_STATUS1_OP_MODE				4
+#define QPNP_STATUS1_MULTI_MEAS_EN			BIT(3)
+#define QPNP_STATUS1_MEAS_INTERVAL_EN_STS		BIT(2)
+#define QPNP_STATUS1_REQ_STS				BIT(1)
+#define QPNP_STATUS1_EOC				BIT(0)
+#define QPNP_STATUS2					0x9
+#define QPNP_STATUS2_CONV_SEQ_STATE_SHIFT		4
+#define QPNP_STATUS2_FIFO_NOT_EMPTY_FLAG		BIT(1)
+#define QPNP_STATUS2_CONV_SEQ_TIMEOUT_STS		BIT(0)
+#define QPNP_CONV_TIMEOUT_ERR				2
+
+#define QPNP_INT_RT_ST					0x10
+#define QPNP_INT_SET_TYPE				0x11
+#define QPNP_INT_SET_TYPE_LOW_THR_INT_SET		BIT(4)
+#define QPNP_INT_SET_TYPE_HIGH_THR_INT_SET		BIT(3)
+#define QPNP_INT_SET_TYPE_CONV_SEQ_TIMEOUT_INT_SET	BIT(2)
+#define QPNP_INT_SET_TYPE_FIFO_NOT_EMPTY_INT_SET	BIT(1)
+#define QPNP_INT_SET_TYPE_EOC_SET_INT_TYPE		BIT(0)
+#define QPNP_INT_POLARITY_HIGH				0x12
+#define QPNP_INT_POLARITY_LOW				0x13
+#define QPNP_INT_EN_SET					0x15
+#define QPNP_INT_EN_SET_LOW_THR_INT_EN_SET		BIT(4)
+#define QPNP_INT_EN_SET_HIGH_THR_INT_EN_SET		BIT(3)
+#define QPNP_INT_EN_SET_CONV_SEQ_TIMEOUT_INT_EN		BIT(2)
+#define QPNP_INT_EN_SET_FIFO_NOT_EMPTY_INT_EN		BIT(1)
+#define QPNP_INT_EN_SET_EOC_INT_EN_SET			BIT(0)
+#define QPNP_INT_CLR					0x16
+#define QPNP_INT_CLR_LOW_THR_INT_EN_CLR			BIT(4)
+#define QPNP_INT_CLR_HIGH_THR_INT_EN_CLKR		BIT(3)
+#define QPNP_INT_CLR_CONV_SEQ_TIMEOUT_INT_EN		BIT(2)
+#define QPNP_INT_CLR_FIFO_NOT_EMPTY_INT_EN		BIT(1)
+#define QPNP_INT_CLR_EOC_INT_EN_CLR			BIT(0)
+#define QPNP_INT_CLR_MASK				0x1f
+#define QPNP_MODE_CTL					0x40
+#define QPNP_OP_MODE_SHIFT				4
+#define QPNP_USE_BMS_DATA				BIT(4)
+#define QPNP_VADC_SYNCH_EN				BIT(2)
+#define QPNP_OFFSET_RMV_EN				BIT(1)
+#define QPNP_ADC_TRIM_EN				BIT(0)
+#define QPNP_EN_CTL1					0x46
+#define QPNP_ADC_CH_SEL_CTL				0x48
+#define QPNP_ADC_DIG_PARAM				0x50
+#define QPNP_ADC_CLK_SEL_MASK				0x3
+#define QPNP_ADC_DEC_RATIO_SEL_MASK			0xc
+#define QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT		2
+
+#define QPNP_HW_SETTLE_DELAY				0x51
+#define QPNP_CONV_REQ					0x52
+#define QPNP_CONV_REQ_SET				BIT(7)
+#define QPNP_CONV_SEQ_CTL				0x54
+#define QPNP_CONV_SEQ_HOLDOFF_SHIFT			4
+#define QPNP_CONV_SEQ_TRIG_CTL				0x55
+#define QPNP_FAST_AVG_CTL				0x5a
+
+#define QPNP_M0_LOW_THR_LSB				0x5c
+#define QPNP_M0_LOW_THR_MSB				0x5d
+#define QPNP_M0_HIGH_THR_LSB				0x5e
+#define QPNP_M0_HIGH_THR_MSB				0x5f
+#define QPNP_M1_LOW_THR_LSB				0x69
+#define QPNP_M1_LOW_THR_MSB				0x6a
+#define QPNP_M1_HIGH_THR_LSB				0x6b
+#define QPNP_M1_HIGH_THR_MSB				0x6c
+
+#define QPNP_DATA0					0x60
+#define QPNP_DATA1					0x61
+#define QPNP_CONV_TIMEOUT_ERR				2
+
+#define QPNP_IADC_MODE_CTL				0x40
+#define QPNP_IADC_USE_BMS_DATA				BIT(4)
+#define QPNP_IADC_RESERVED_BIT3				BIT(3)
+#define QPNP_IADC_VADC_SYNC_EN				BIT(2)
+#define QPNP_IADC_OFFSET_RMV_EN				BIT(1)
+#define QPNP_IADC_ADC_TRIM_EN				BIT(0)
+
+#define QPNP_IADC_ADC_CH_SEL_CTL			0x48
+#define QPNP_IADC_ADC_CHX_SEL_SHIFT			3
+
+#define QPNP_IADC_ADC_DIG_PARAM				0x50
+#define QPNP_IADC_CLK_SEL_SHIFT				1
+#define QPNP_IADC_DEC_RATIO_SEL				3
+
+#define QPNP_IADC_CONV_REQUEST				0x52
+#define QPNP_IADC_CONV_REQ				BIT(7)
+
+#define QPNP_IADC_DATA0					0x60
+#define QPNP_IADC_DATA1					0x61
+
+#define QPNP_ADC_CONV_TIME_MIN				2000
+#define QPNP_ADC_CONV_TIME_MAX				2200
+
+#define QPNP_ADC_GAIN_CALCULATION			2500
+
+struct qpnp_iadc_drv {
+	struct qpnp_adc_drv		*adc;
+	int32_t				rsense;
+	struct device			*iadc_hwmon;
+	bool				iadc_init_calib;
+	struct sensor_device_attribute		sens_attr[0];
+};
+
+struct qpnp_iadc_drv	*qpnp_iadc;
+
+static int32_t qpnp_iadc_read_reg(uint32_t reg, u8 *data)
+{
+	struct qpnp_iadc_drv *iadc = qpnp_iadc;
+	int rc;
+
+	rc = spmi_ext_register_readl(iadc->adc->spmi->ctrl, iadc->adc->slave,
+		(iadc->adc->offset + reg), data, 1);
+	if (rc < 0) {
+		pr_err("qpnp iadc read reg %d failed with %d\n", reg, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int32_t qpnp_iadc_write_reg(uint32_t reg, u8 data)
+{
+	struct qpnp_iadc_drv *iadc = qpnp_iadc;
+	int rc;
+	u8 *buf;
+
+	buf = &data;
+	rc = spmi_ext_register_writel(iadc->adc->spmi->ctrl, iadc->adc->slave,
+		(iadc->adc->offset + reg), buf, 1);
+	if (rc < 0) {
+		pr_err("qpnp iadc write reg %d failed with %d\n", reg, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int32_t qpnp_iadc_configure_interrupt(void)
+{
+	int rc = 0;
+	u8 data = 0;
+
+	/* Configure interrupt as an Edge trigger */
+	rc = qpnp_iadc_write_reg(QPNP_INT_SET_TYPE,
+					QPNP_INT_CLR_MASK);
+	if (rc < 0) {
+		pr_err("%s Interrupt configure failed\n", __func__);
+		return rc;
+	}
+
+	/* Configure interrupt for rising edge trigger */
+	rc = qpnp_iadc_write_reg(QPNP_INT_POLARITY_HIGH,
+					QPNP_INT_CLR_MASK);
+	if (rc < 0) {
+		pr_err("%s Rising edge trigger configure failed\n", __func__);
+		return rc;
+	}
+
+	/* Disable low level interrupt triggering */
+	data = QPNP_INT_CLR_MASK;
+	rc = qpnp_iadc_write_reg(QPNP_INT_POLARITY_LOW,
+					(~data & QPNP_INT_CLR_MASK));
+	if (rc < 0) {
+		pr_err("%s Setting level low to disable failed\n", __func__);
+		return rc;
+	}
+
+	return 0;
+}
+
+static void trigger_iadc_completion(struct work_struct *work)
+{
+	struct qpnp_iadc_drv *iadc = qpnp_iadc;
+	int rc;
+
+	rc = qpnp_iadc_write_reg(QPNP_INT_CLR, QPNP_INT_CLR_MASK);
+	if (rc < 0)
+		pr_err("qpnp iadc interrupt mask failed with %d\n", rc);
+
+	complete(&iadc->adc->adc_rslt_completion);
+
+	return;
+}
+DECLARE_WORK(trigger_iadc_completion_work, trigger_iadc_completion);
+
+static irqreturn_t qpnp_iadc_isr(int irq, void *dev_id)
+{
+	schedule_work(&trigger_iadc_completion_work);
+
+	return IRQ_HANDLED;
+}
+
+static int32_t qpnp_iadc_read_conversion_result(int32_t *data)
+{
+	uint8_t rslt_lsb, rslt_msb;
+	int32_t rc;
+
+	rc = qpnp_iadc_read_reg(QPNP_IADC_DATA0, &rslt_lsb);
+	if (rc < 0) {
+		pr_err("qpnp adc result read failed with %d\n", rc);
+		return rc;
+	}
+
+	rc = qpnp_iadc_read_reg(QPNP_IADC_DATA1, &rslt_msb);
+	if (rc < 0) {
+		pr_err("qpnp adc result read failed with %d\n", rc);
+		return rc;
+	}
+
+	*data = (rslt_msb << 8) | rslt_lsb;
+
+	rc = qpnp_vadc_check_result(data);
+	if (rc < 0) {
+		pr_err("VADC data check failed\n");
+		return rc;
+	}
+
+	return 0;
+}
+
+static int32_t qpnp_iadc_configure(enum qpnp_iadc_channels channel,
+						int32_t *result)
+{
+	struct qpnp_iadc_drv *iadc = qpnp_iadc;
+	u8 qpnp_iadc_mode_reg = 0, qpnp_iadc_ch_sel_reg = 0;
+	u8 qpnp_iadc_conv_req = 0, qpnp_iadc_dig_param_reg = 0;
+	int32_t rc = 0;
+
+	qpnp_iadc_mode_reg |= (QPNP_IADC_USE_BMS_DATA | QPNP_IADC_USE_BMS_DATA
+			| QPNP_IADC_OFFSET_RMV_EN | QPNP_IADC_ADC_TRIM_EN);
+
+	qpnp_iadc_ch_sel_reg = channel << QPNP_IADC_ADC_CHX_SEL_SHIFT;
+
+	qpnp_iadc_dig_param_reg |= iadc->adc->amux_prop->decimation <<
+					QPNP_IADC_DEC_RATIO_SEL;
+
+	qpnp_iadc_conv_req = QPNP_IADC_CONV_REQ;
+
+	rc = qpnp_iadc_write_reg(QPNP_INT_EN_SET,
+					QPNP_INT_EN_SET_EOC_INT_EN_SET);
+	if (rc < 0) {
+		pr_err("qpnp adc configure error for interrupt setup\n");
+		return rc;
+	}
+
+	rc = qpnp_iadc_write_reg(QPNP_IADC_MODE_CTL, qpnp_iadc_mode_reg);
+	if (rc) {
+		pr_err("qpnp adc read adc failed with %d\n", rc);
+		return rc;
+	}
+
+	rc = qpnp_iadc_write_reg(QPNP_IADC_ADC_CH_SEL_CTL,
+						qpnp_iadc_ch_sel_reg);
+	if (rc) {
+		pr_err("qpnp adc read adc failed with %d\n", rc);
+		return rc;
+	}
+
+	rc = qpnp_iadc_write_reg(QPNP_ADC_DIG_PARAM,
+						qpnp_iadc_dig_param_reg);
+	if (rc) {
+		pr_err("qpnp adc read adc failed with %d\n", rc);
+		return rc;
+	}
+
+	rc = qpnp_iadc_write_reg(QPNP_HW_SETTLE_DELAY,
+				iadc->adc->amux_prop->hw_settle_time);
+	if (rc < 0) {
+		pr_err("qpnp adc configure error for hw settling time setup\n");
+		return rc;
+	}
+
+	rc = qpnp_iadc_write_reg(QPNP_FAST_AVG_CTL,
+					iadc->adc->amux_prop->fast_avg_setup);
+	if (rc < 0) {
+		pr_err("qpnp adc fast averaging configure error\n");
+		return rc;
+	}
+
+	rc = qpnp_iadc_write_reg(QPNP_CONV_REQ, qpnp_iadc_conv_req);
+	if (rc) {
+		pr_err("qpnp adc read adc failed with %d\n", rc);
+		return rc;
+	}
+
+	wait_for_completion(&iadc->adc->adc_rslt_completion);
+
+	rc = qpnp_iadc_read_conversion_result(result);
+	if (rc) {
+		pr_err("qpnp adc read adc failed with %d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int32_t qpnp_iadc_init_calib(void)
+{
+	struct qpnp_iadc_drv *iadc = qpnp_iadc;
+	int32_t rc = 0, result;
+
+	rc = qpnp_iadc_configure(GAIN_CALIBRATION_25MV, &result);
+	if (rc < 0) {
+		pr_err("qpnp adc result read failed with %d\n", rc);
+		goto fail;
+	}
+
+	iadc->adc->calib.gain = result;
+
+	rc = qpnp_iadc_configure(OFFSET_CALIBRATION_SHORT_CADC_LEADS,
+								&result);
+	if (rc < 0) {
+		pr_err("qpnp adc result read failed with %d\n", rc);
+		goto fail;
+	}
+
+	iadc->adc->calib.offset = result;
+
+fail:
+	return rc;
+}
+
+int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
+						int32_t *result)
+{
+	struct qpnp_iadc_drv *iadc = qpnp_iadc;
+	int32_t vsense_mv = 0, rc;
+
+	mutex_lock(&iadc->adc->adc_lock);
+
+	if (!iadc->iadc_init_calib) {
+		rc = qpnp_iadc_init_calib();
+		if (!rc) {
+			pr_err("Calibration failed\n");
+			goto fail;
+		} else
+			iadc->iadc_init_calib = true;
+	}
+
+	rc = qpnp_iadc_configure(channel, result);
+	if (rc < 0) {
+		pr_err("qpnp adc result read failed with %d\n", rc);
+		goto fail;
+	}
+
+	vsense_mv = ((*result - iadc->adc->calib.offset)/
+			(iadc->adc->calib.gain - iadc->adc->calib.offset))
+			* QPNP_ADC_GAIN_CALCULATION;
+
+	*result = (vsense_mv/qpnp_iadc->rsense);
+
+fail:
+	mutex_unlock(&iadc->adc->adc_lock);
+
+	return rc;
+}
+EXPORT_SYMBOL(qpnp_iadc_read);
+
+int32_t qpnp_iadc_get_gain(int32_t *result)
+{
+	return qpnp_iadc_read(GAIN_CALIBRATION_25MV, result);
+}
+EXPORT_SYMBOL(qpnp_iadc_get_gain);
+
+int32_t qpnp_iadc_get_offset(enum qpnp_iadc_channels channel,
+						int32_t *result)
+{
+	return qpnp_iadc_read(channel, result);
+}
+EXPORT_SYMBOL(qpnp_iadc_get_offset);
+
+static ssize_t qpnp_iadc_show(struct device *dev,
+			struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	int32_t result;
+	int rc = -1;
+
+	rc = qpnp_iadc_read(attr->index, &result);
+
+	if (rc)
+		return 0;
+
+	return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
+					"Result:%d\n", result);
+}
+
+static struct sensor_device_attribute qpnp_adc_attr =
+	SENSOR_ATTR(NULL, S_IRUGO, qpnp_iadc_show, NULL, 0);
+
+static int32_t qpnp_iadc_init_hwmon(struct spmi_device *spmi)
+{
+	struct qpnp_iadc_drv *iadc = qpnp_iadc;
+	struct device_node *child;
+	struct device_node *node = spmi->dev.of_node;
+	int rc = 0, i = 0, channel;
+
+	for_each_child_of_node(node, child) {
+		channel = iadc->adc->adc_channels[i].channel_num;
+		qpnp_adc_attr.index = iadc->adc->adc_channels[i].channel_num;
+		qpnp_adc_attr.dev_attr.attr.name =
+						iadc->adc->adc_channels[i].name;
+		sysfs_attr_init(&iadc->sens_attr[i].dev_attr.attr);
+		memcpy(&iadc->sens_attr[i], &qpnp_adc_attr,
+						sizeof(qpnp_adc_attr));
+		rc = device_create_file(&spmi->dev,
+				&iadc->sens_attr[i].dev_attr);
+		if (rc) {
+			dev_err(&spmi->dev,
+				"device_create_file failed for dev %s\n",
+				iadc->adc->adc_channels[i].name);
+			goto hwmon_err_sens;
+		}
+		i++;
+	}
+
+	return 0;
+hwmon_err_sens:
+	pr_err("Init HWMON failed for qpnp_iadc with %d\n", rc);
+	return rc;
+}
+
+static int __devinit qpnp_iadc_probe(struct spmi_device *spmi)
+{
+	struct qpnp_iadc_drv *iadc;
+	struct qpnp_adc_drv *adc_qpnp;
+	struct device_node *node = spmi->dev.of_node;
+	struct device_node *child;
+	int rc, count_adc_channel_list = 0;
+
+	if (!node)
+		return -EINVAL;
+
+	if (qpnp_iadc) {
+		pr_err("IADC already in use\n");
+		return -EBUSY;
+	}
+
+	for_each_child_of_node(node, child)
+		count_adc_channel_list++;
+
+	if (!count_adc_channel_list) {
+		pr_err("No channel listing\n");
+		return -EINVAL;
+	}
+
+	iadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_iadc_drv) +
+		(sizeof(struct sensor_device_attribute) *
+				count_adc_channel_list), GFP_KERNEL);
+	if (!iadc) {
+		dev_err(&spmi->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
+			GFP_KERNEL);
+	if (!adc_qpnp) {
+		dev_err(&spmi->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	iadc->adc = adc_qpnp;
+
+	rc = qpnp_adc_get_devicetree_data(spmi, iadc->adc);
+	if (rc) {
+		dev_err(&spmi->dev, "failed to read device tree\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(node, "qcom,rsense",
+			&iadc->rsense);
+	if (rc) {
+		pr_err("Invalid rsens reference property\n");
+		return -EINVAL;
+	}
+
+	rc = devm_request_irq(&spmi->dev, iadc->adc->adc_irq,
+				qpnp_iadc_isr,
+	IRQF_TRIGGER_RISING, "qpnp_iadc_interrupt", iadc);
+	if (rc) {
+		dev_err(&spmi->dev, "failed to request adc irq\n");
+		return rc;
+	} else
+		enable_irq_wake(iadc->adc->adc_irq);
+
+	iadc->iadc_init_calib = false;
+	dev_set_drvdata(&spmi->dev, iadc);
+	qpnp_iadc = iadc;
+
+	rc = qpnp_iadc_init_hwmon(spmi);
+	if (rc) {
+		dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
+		return rc;
+	}
+	iadc->iadc_hwmon = hwmon_device_register(&iadc->adc->spmi->dev);
+
+	rc = qpnp_iadc_configure_interrupt();
+	if (rc) {
+		dev_err(&spmi->dev, "failed to configure interrupt");
+		return rc;
+	}
+
+	return 0;
+}
+
+static int __devexit qpnp_iadc_remove(struct spmi_device *spmi)
+{
+	struct qpnp_iadc_drv *iadc = dev_get_drvdata(&spmi->dev);
+	struct device_node *node = spmi->dev.of_node;
+	struct device_node *child;
+	int i = 0;
+
+	for_each_child_of_node(node, child) {
+		device_remove_file(&spmi->dev,
+			&iadc->sens_attr[i].dev_attr);
+		i++;
+	}
+	dev_set_drvdata(&spmi->dev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id qpnp_iadc_match_table[] = {
+	{	.compatible = "qcom,qpnp-iadc",
+	},
+	{}
+};
+
+static struct spmi_driver qpnp_iadc_driver = {
+	.driver		= {
+		.name	= "qcom,qpnp-iadc",
+		.of_match_table = qpnp_iadc_match_table,
+	},
+	.probe		= qpnp_iadc_probe,
+	.remove		= qpnp_iadc_remove,
+};
+
+static int __init qpnp_iadc_init(void)
+{
+	return spmi_driver_register(&qpnp_iadc_driver);
+}
+module_init(qpnp_iadc_init);
+
+static void __exit qpnp_iadc_exit(void)
+{
+	spmi_driver_unregister(&qpnp_iadc_driver);
+}
+module_exit(qpnp_iadc_exit);
+
+MODULE_DESCRIPTION("QPNP PMIC current ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index 8b2cb97..9e8a2e2 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -37,6 +37,7 @@
 #define QPNP_VADC_STATUS1_MEAS_INTERVAL_EN_STS			BIT(2)
 #define QPNP_VADC_STATUS1_REQ_STS				BIT(1)
 #define QPNP_VADC_STATUS1_EOC					BIT(0)
+#define QPNP_VADC_STATUS1_REQ_STS_EOC_MASK			0x3
 #define QPNP_VADC_STATUS2					0x9
 #define QPNP_VADC_STATUS2_CONV_SEQ_STATE				6
 #define QPNP_VADC_STATUS2_FIFO_NOT_EMPTY_FLAG			BIT(1)
@@ -92,8 +93,6 @@
 #define QPNP_VADC_CONV_TIME_MIN					2000
 #define QPNP_VADC_CONV_TIME_MAX					2100
 
-#define QPNP_ADC_HWMON_NAME_LENGTH				16
-
 struct qpnp_vadc_drv {
 	struct qpnp_adc_drv		*adc;
 	struct dentry			*dent;
@@ -114,7 +113,7 @@
 	int rc;
 
 	rc = spmi_ext_register_readl(vadc->adc->spmi->ctrl, vadc->adc->slave,
-		reg, data, 1);
+		(vadc->adc->offset + reg), data, 1);
 	if (rc < 0) {
 		pr_err("qpnp adc read reg %d failed with %d\n", reg, rc);
 		return rc;
@@ -132,7 +131,7 @@
 	buf = &data;
 
 	rc = spmi_ext_register_writel(vadc->adc->spmi->ctrl, vadc->adc->slave,
-		reg, buf, 1);
+		(vadc->adc->offset + reg), buf, 1);
 	if (rc < 0) {
 		pr_err("qpnp adc write reg %d failed with %d\n", reg, rc);
 		return rc;
@@ -200,63 +199,89 @@
 }
 
 int32_t qpnp_vadc_configure(
-			struct qpnp_vadc_amux_properties *chan_prop)
+			struct qpnp_adc_amux_properties *chan_prop)
 {
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
 	u8 decimation = 0, conv_sequence = 0, conv_sequence_trig = 0;
+	u8 mode_ctrl = 0;
 	int rc = 0;
 
-	rc = qpnp_vadc_write_reg(QPNP_VADC_INT_EN_SET,
+	if (vadc->vadc_init_calib) {
+		/* Configure interrupt if calibration is complete */
+		rc = qpnp_vadc_write_reg(QPNP_VADC_INT_EN_SET,
 				QPNP_VADC_INT_EOC_BIT);
+		if (rc < 0) {
+			pr_err("Configure error for interrupt setup\n");
+			return rc;
+		}
+	}
+
+	/* Mode selection */
+	rc = qpnp_vadc_read_reg(QPNP_VADC_MODE_CTL, &mode_ctrl);
 	if (rc < 0) {
-		pr_err("qpnp adc configure error for interrupt setup\n");
+		pr_err("Mode configure read error\n");
+		return rc;
+	}
+	mode_ctrl |= chan_prop->mode_sel << QPNP_VADC_OP_MODE_SHIFT;
+	rc = qpnp_vadc_write_reg(QPNP_VADC_MODE_CTL, mode_ctrl);
+	if (rc < 0) {
+		pr_err("Mode configure write error\n");
 		return rc;
 	}
 
-	rc = qpnp_vadc_write_reg(QPNP_VADC_MODE_CTL, chan_prop->mode_sel);
-	if (rc < 0) {
-		pr_err("qpnp adc configure error for mode selection\n");
+	rc = qpnp_vadc_enable(true);
+	if (rc)
 		return rc;
-	}
 
+	/* Channel selection */
 	rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_CH_SEL_CTL,
 						chan_prop->amux_channel);
 	if (rc < 0) {
-		pr_err("qpnp adc configure error for channel selection\n");
+		pr_err("Channel configure error\n");
 		return rc;
 	}
 
+	/* Digital parameter setup */
+	rc = qpnp_vadc_read_reg(QPNP_VADC_ADC_DIG_PARAM, &decimation);
+	if (rc < 0) {
+		pr_err("Digital parameter configure read error\n");
+		return rc;
+	}
 	decimation |= chan_prop->decimation <<
 				QPNP_VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT;
 	rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_DIG_PARAM, decimation);
 	if (rc < 0) {
-		pr_err("qpnp adc configure error for digital parameter setup\n");
+		pr_err("Digital parameter configure write error\n");
 		return rc;
 	}
 
+	/* HW settling time delay */
 	rc = qpnp_vadc_write_reg(QPNP_VADC_HW_SETTLE_DELAY,
 						chan_prop->hw_settle_time);
 	if (rc < 0) {
-		pr_err("qpnp adc configure error for hw settling time setup\n");
+		pr_err("HW settling time setup error\n");
 		return rc;
 	}
 
 	if (chan_prop->mode_sel == (ADC_OP_NORMAL_MODE <<
 					QPNP_VADC_OP_MODE_SHIFT)) {
+		/* Normal measurement mode */
 		rc = qpnp_vadc_write_reg(QPNP_VADC_FAST_AVG_CTL,
 						chan_prop->fast_avg_setup);
 		if (rc < 0) {
-			pr_err("qpnp adc fast averaging configure error\n");
+			pr_err("Fast averaging configure error\n");
 			return rc;
 		}
 	} else if (chan_prop->mode_sel == (ADC_OP_CONVERSION_SEQUENCER <<
 					QPNP_VADC_OP_MODE_SHIFT)) {
+		/* Conversion sequence mode */
 		conv_sequence = ((ADC_SEQ_HOLD_100US <<
 				QPNP_VADC_CONV_SEQ_HOLDOFF_SHIFT) |
 				ADC_CONV_SEQ_TIMEOUT_5MS);
 		rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_CTL,
 							conv_sequence);
 		if (rc < 0) {
-			pr_err("qpnp adc conversion sequence error\n");
+			pr_err("Conversion sequence error\n");
 			return rc;
 		}
 
@@ -266,14 +291,15 @@
 		rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_TRIG_CTL,
 							conv_sequence_trig);
 		if (rc < 0) {
-			pr_err("qpnp adc conversion trigger error\n");
+			pr_err("Conversion trigger error\n");
 			return rc;
 		}
 	}
 
+	/* Request conversion */
 	rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_REQ, QPNP_VADC_CONV_REQ_SET);
 	if (rc < 0) {
-		pr_err("qpnp adc request conversion failed\n");
+		pr_err("Request conversion failed\n");
 		return rc;
 	}
 
@@ -284,29 +310,34 @@
 static int32_t qpnp_vadc_read_conversion_result(int32_t *data)
 {
 	uint8_t rslt_lsb, rslt_msb;
-	int rc = 0;
+	int rc = 0, status = 0;
 
-	rc = qpnp_vadc_read_reg(QPNP_VADC_DATA0, &rslt_lsb);
-	if (rc < 0) {
-		pr_err("qpnp adc result read failed for data0 with %d\n", rc);
-		return rc;
+	status = qpnp_vadc_read_reg(QPNP_VADC_DATA0, &rslt_lsb);
+	if (status < 0) {
+		pr_err("qpnp adc result read failed for data0\n");
+		goto fail;
 	}
 
-	rc = qpnp_vadc_read_reg(QPNP_VADC_DATA1, &rslt_msb);
-	if (rc < 0) {
-		pr_err("qpnp adc result read failed for data1 with %d\n", rc);
-		return rc;
+	status = qpnp_vadc_read_reg(QPNP_VADC_DATA1, &rslt_msb);
+	if (status < 0) {
+		pr_err("qpnp adc result read failed for data1\n");
+		goto fail;
 	}
 
 	*data = (rslt_msb << 8) | rslt_lsb;
 
-	rc = qpnp_vadc_check_result(data);
-	if (rc < 0) {
+	status = qpnp_vadc_check_result(data);
+	if (status < 0) {
 		pr_err("VADC data check failed\n");
-		return rc;
+		goto fail;
 	}
 
-	return 0;
+fail:
+	rc = qpnp_vadc_enable(false);
+	if (rc)
+		return rc;
+
+	return status;
 }
 
 static int32_t qpnp_vadc_read_status(int mode_sel)
@@ -374,7 +405,7 @@
 static uint32_t qpnp_vadc_calib_device(void)
 {
 	struct qpnp_vadc_drv *vadc = qpnp_vadc;
-	struct qpnp_vadc_amux_properties conv;
+	struct qpnp_adc_amux_properties conv;
 	int rc, calib_read_1, calib_read_2;
 	u8 status1 = 0;
 
@@ -395,6 +426,7 @@
 		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
 		if (rc < 0)
 			return rc;
+		status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
 		usleep_range(QPNP_VADC_CONV_TIME_MIN,
 					QPNP_VADC_CONV_TIME_MAX);
 	}
@@ -416,11 +448,13 @@
 		goto calib_fail;
 	}
 
+	status1 = 0;
 	while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
 					QPNP_VADC_STATUS1_EOC)) {
 		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
 		if (rc < 0)
 			return rc;
+		status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
 		usleep_range(QPNP_VADC_CONV_TIME_MIN,
 					QPNP_VADC_CONV_TIME_MAX);
 	}
@@ -451,11 +485,13 @@
 		goto calib_fail;
 	}
 
+	status1 = 0;
 	while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
 					QPNP_VADC_STATUS1_EOC)) {
 		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
 		if (rc < 0)
 			return rc;
+		status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
 		usleep_range(QPNP_VADC_CONV_TIME_MIN,
 					QPNP_VADC_CONV_TIME_MAX);
 	}
@@ -477,11 +513,13 @@
 		goto calib_fail;
 	}
 
+	status1 = 0;
 	while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
 					QPNP_VADC_STATUS1_EOC)) {
 		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
 		if (rc < 0)
 			return rc;
+		status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
 		usleep_range(QPNP_VADC_CONV_TIME_MIN,
 					QPNP_VADC_CONV_TIME_MAX);
 	}
@@ -510,7 +548,7 @@
 					struct qpnp_vadc_result *result)
 {
 	struct qpnp_vadc_drv *vadc = qpnp_vadc;
-	int rc, scale_type, amux_prescaling;
+	int rc = 0, scale_type, amux_prescaling;
 
 	if (!vadc->vadc_init_calib) {
 		rc = qpnp_vadc_calib_device();
@@ -523,10 +561,6 @@
 
 	mutex_lock(&vadc->adc->adc_lock);
 
-	rc = qpnp_vadc_enable(true);
-	if (rc)
-		goto fail_unlock;
-
 	vadc->adc->amux_prop->amux_channel = channel;
 	vadc->adc->amux_prop->decimation =
 			vadc->adc->adc_channels[channel].adc_decimation;
@@ -543,15 +577,15 @@
 						<< QPNP_VADC_OP_MODE_SHIFT);
 	else {
 		pr_err("Invalid trigger channel:%d\n", trigger_channel);
-		goto fail;
+		goto fail_unlock;
 	}
 
 	vadc->adc->amux_prop->trigger_channel = trigger_channel;
 
 	rc = qpnp_vadc_configure(vadc->adc->amux_prop);
 	if (rc) {
-		pr_info("qpnp vadc configure failed with %d\n", rc);
-		goto fail;
+		pr_err("qpnp vadc configure failed with %d\n", rc);
+		goto fail_unlock;
 	}
 
 	wait_for_completion(&vadc->adc->adc_rslt_completion);
@@ -559,13 +593,13 @@
 	if (trigger_channel < ADC_SEQ_NONE) {
 		rc = qpnp_vadc_read_status(vadc->adc->amux_prop->mode_sel);
 		if (rc)
-			pr_info("Conversion sequence timed out - %d\n", rc);
+			pr_debug("Conversion sequence timed out - %d\n", rc);
 	}
 
 	rc = qpnp_vadc_read_conversion_result(&result->adc_code);
 	if (rc) {
-		pr_info("qpnp vadc read adc code failed with %d\n", rc);
-		goto fail;
+		pr_err("qpnp vadc read adc code failed with %d\n", rc);
+		goto fail_unlock;
 	}
 
 	amux_prescaling = vadc->adc->adc_channels[channel].chan_path_prescaling;
@@ -578,17 +612,12 @@
 	scale_type = vadc->adc->adc_channels[channel].adc_scale_fn;
 	if (scale_type >= SCALE_NONE) {
 		rc = -EBADF;
-		goto fail;
+		goto fail_unlock;
 	}
 
 	vadc_scale_fn[scale_type].chan(result->adc_code,
 		vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
 
-fail:
-	rc = qpnp_vadc_enable(false);
-	if (rc)
-		pr_err("Disable ADC failed during configuration\n");
-
 fail_unlock:
 	mutex_unlock(&vadc->adc->adc_lock);
 
@@ -651,7 +680,7 @@
 
 	return 0;
 hwmon_err_sens:
-	pr_info("Init HWMON failed for qpnp_adc with %d\n", rc);
+	pr_err("Init HWMON failed for qpnp_adc with %d\n", rc);
 	return rc;
 }
 
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 297afa7..c1617bff 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -1339,8 +1339,10 @@
 		}
 		free_irq(dev->err_irq, dev);
 	} else {
-		if (dev->dev->of_node)
+		if (dev->dev->of_node) {
+			dev->adapter.dev.of_node = pdev->dev.of_node;
 			of_i2c_register_devices(&dev->adapter);
+		}
 		return 0;
 	}
 
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index 8b6e172..d3da652 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -40,6 +40,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
+#include <linux/gpio.h>
 #include <linux/input/mpu3050.h>
 #include <linux/regulator/consumer.h>
 
@@ -50,6 +51,8 @@
 #define MPU3050_MIN_VALUE	-32768
 #define MPU3050_MAX_VALUE	32767
 
+#define MPU3050_MIN_POLL_INTERVAL	1
+#define MPU3050_MAX_POLL_INTERVAL	250
 #define MPU3050_DEFAULT_POLL_INTERVAL	200
 #define MPU3050_DEFAULT_FS_RANGE	3
 
@@ -90,8 +93,10 @@
 #define MPU3050_DLPF_CFG_MASK		0x07
 /* INT_CFG */
 #define MPU3050_RAW_RDY_EN		0x01
-#define MPU3050_MPU_RDY_EN		0x02
-#define MPU3050_LATCH_INT_EN		0x04
+#define MPU3050_MPU_RDY_EN		0x04
+#define MPU3050_LATCH_INT_EN		0x20
+#define MPU3050_OPEN_DRAIN		0x40
+#define MPU3050_ACTIVE_LOW		0x80
 /* PWR_MGM */
 #define MPU3050_PWR_MGM_PLL_X		0x01
 #define MPU3050_PWR_MGM_PLL_Y		0x02
@@ -117,6 +122,7 @@
 	struct mpu3050_gyro_platform_data *platform_data;
 	struct delayed_work input_work;
 	u32    use_poll;
+	u32    poll_interval;
 };
 
 struct sensor_regulator {
@@ -190,6 +196,78 @@
 }
 
 /**
+ *	mpu3050_attr_get_polling_rate	-	get the sampling rate
+ */
+static ssize_t mpu3050_attr_get_polling_rate(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	int val;
+	struct mpu3050_sensor *sensor = dev_get_drvdata(dev);
+	val = sensor ? sensor->poll_interval : 0;
+	return snprintf(buf, 8, "%d\n", val);
+}
+
+/**
+ *	mpu3050_attr_set_polling_rate	-	set the sampling rate
+ */
+static ssize_t mpu3050_attr_set_polling_rate(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	struct mpu3050_sensor *sensor = dev_get_drvdata(dev);
+	unsigned long interval_ms;
+
+	if (kstrtoul(buf, 10, &interval_ms))
+		return -EINVAL;
+	if ((interval_ms < MPU3050_MIN_POLL_INTERVAL) ||
+		(interval_ms > MPU3050_MAX_POLL_INTERVAL))
+		return -EINVAL;
+
+	if (sensor)
+		sensor->poll_interval = interval_ms;
+
+	/* Output frequency divider. The poll interval */
+	i2c_smbus_write_byte_data(sensor->client, MPU3050_SMPLRT_DIV,
+					interval_ms - 1);
+
+	return size;
+}
+
+static struct device_attribute attributes[] = {
+
+	__ATTR(pollrate_ms, 0666,
+		mpu3050_attr_get_polling_rate,
+		mpu3050_attr_set_polling_rate),
+};
+
+static int create_sysfs_interfaces(struct device *dev)
+{
+	int i;
+	int err;
+	for (i = 0; i < ARRAY_SIZE(attributes); i++) {
+		err = device_create_file(dev, attributes + i);
+		if (err)
+			goto error;
+	}
+	return 0;
+
+error:
+	for ( ; i >= 0; i--)
+		device_remove_file(dev, attributes + i);
+	dev_err(dev, "%s:Unable to create interface\n", __func__);
+	return err;
+}
+
+static int remove_sysfs_interfaces(struct device *dev)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(attributes); i++)
+		device_remove_file(dev, attributes + i);
+	return 0;
+}
+
+/**
  *	mpu3050_xyz_read_reg	-	read the axes values
  *	@buffer: provide register addr and get register
  *	@length: length of register
@@ -284,20 +362,20 @@
 	struct mpu3050_sensor *sensor = input_get_drvdata(input);
 	int error;
 
-	pm_runtime_get(sensor->dev);
+	pm_runtime_get_sync(sensor->dev);
 
 	/* Enable interrupts */
 	error = i2c_smbus_write_byte_data(sensor->client, MPU3050_INT_CFG,
-					  MPU3050_LATCH_INT_EN |
-					  MPU3050_RAW_RDY_EN |
-					  MPU3050_MPU_RDY_EN);
+					MPU3050_ACTIVE_LOW |
+					MPU3050_OPEN_DRAIN |
+					MPU3050_RAW_RDY_EN);
 	if (error < 0) {
 		pm_runtime_put(sensor->dev);
 		return error;
 	}
 	if (sensor->use_poll)
 		schedule_delayed_work(&sensor->input_work,
-			msecs_to_jiffies(MPU3050_DEFAULT_POLL_INTERVAL));
+			msecs_to_jiffies(sensor->poll_interval));
 
 	return 0;
 }
@@ -366,7 +444,7 @@
 
 	if (sensor->use_poll)
 		schedule_delayed_work(&sensor->input_work,
-			msecs_to_jiffies(MPU3050_DEFAULT_POLL_INTERVAL));
+			msecs_to_jiffies(sensor->poll_interval));
 }
 
 /**
@@ -399,7 +477,7 @@
 
 	/* Output frequency divider. The poll interval */
 	ret = i2c_smbus_write_byte_data(client, MPU3050_SMPLRT_DIV,
-					MPU3050_DEFAULT_POLL_INTERVAL - 1);
+					sensor->poll_interval - 1);
 	if (ret < 0)
 		return ret;
 
@@ -444,6 +522,18 @@
 	sensor->dev = &client->dev;
 	sensor->idev = idev;
 	sensor->platform_data = client->dev.platform_data;
+	i2c_set_clientdata(client, sensor);
+	if (sensor->platform_data) {
+		u32 interval = sensor->platform_data->poll_interval;
+
+		if ((interval < MPU3050_MIN_POLL_INTERVAL) ||
+			(interval > MPU3050_MAX_POLL_INTERVAL))
+			sensor->poll_interval = MPU3050_DEFAULT_POLL_INTERVAL;
+		else
+			sensor->poll_interval = interval;
+	} else {
+		sensor->poll_interval = MPU3050_DEFAULT_POLL_INTERVAL;
+	}
 
 	mpu3050_set_power_mode(client, 1);
 	msleep(10);
@@ -485,14 +575,34 @@
 		goto err_pm_set_suspended;
 
 	if (client->irq == 0) {
-		INIT_DELAYED_WORK(&sensor->input_work, mpu3050_input_work_fn);
 		sensor->use_poll = 1;
+		INIT_DELAYED_WORK(&sensor->input_work, mpu3050_input_work_fn);
 	} else {
 		sensor->use_poll = 0;
 
+		if (gpio_is_valid(sensor->platform_data->gpio_int)) {
+			/* configure interrupt gpio */
+			ret = gpio_request(sensor->platform_data->gpio_int,
+								"gyro_gpio_int");
+			if (ret) {
+				pr_err("%s: unable to request interrupt gpio %d\n",
+					__func__,
+					sensor->platform_data->gpio_int);
+				goto err_pm_set_suspended;
+			}
+
+			ret = gpio_direction_input(
+				sensor->platform_data->gpio_int);
+			if (ret) {
+				pr_err("%s: unable to set direction for gpio %d\n",
+				__func__, sensor->platform_data->gpio_int);
+				goto err_free_gpio;
+			}
+		}
+
 		error = request_threaded_irq(client->irq,
 				     NULL, mpu3050_interrupt_thread,
-				     IRQF_TRIGGER_RISING,
+				     IRQF_TRIGGER_FALLING,
 				     "mpu3050", sensor);
 		if (error) {
 			dev_err(&client->dev,
@@ -508,14 +618,26 @@
 		goto err_free_irq;
 	}
 
+	error = create_sysfs_interfaces(&client->dev);
+	if (error < 0) {
+		dev_err(&client->dev, "failed to create sysfs\n");
+		goto err_input_cleanup;
+	}
+
 	pm_runtime_enable(&client->dev);
 	pm_runtime_set_autosuspend_delay(&client->dev, MPU3050_AUTO_DELAY);
 
 	return 0;
 
+err_input_cleanup:
+	input_unregister_device(idev);
 err_free_irq:
 	if (client->irq > 0)
 		free_irq(client->irq, sensor);
+err_free_gpio:
+	if ((client->irq > 0) &&
+		(gpio_is_valid(sensor->platform_data->gpio_int)))
+		gpio_free(sensor->platform_data->gpio_int);
 err_pm_set_suspended:
 	pm_runtime_set_suspended(&client->dev);
 err_free_mem:
@@ -537,8 +659,12 @@
 	pm_runtime_disable(&client->dev);
 	pm_runtime_set_suspended(&client->dev);
 
-	free_irq(client->irq, sensor);
+	if (client->irq)
+		free_irq(client->irq, sensor);
+
+	remove_sysfs_interfaces(&client->dev);
 	input_unregister_device(sensor->idev);
+
 	kfree(sensor);
 
 	return 0;
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 1c70527..49a081e 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -36,7 +36,9 @@
 /* Family ID */
 #define MXT224_ID	0x80
 #define MXT224E_ID	0x81
+#define MXT336S_ID	0x82
 #define MXT1386_ID	0xA0
+#define MXT1664S_ID	0xA2
 
 /* Version */
 #define MXT_VER_20		20
@@ -94,6 +96,7 @@
 #define MXT_TOUCH_PROXKEY_T52		52
 #define MXT_PROCI_GRIPFACE_T20		20
 #define MXT_PROCG_NOISE_T22		22
+#define MXT_PROCG_NOISE_T62		62
 #define MXT_PROCI_ONETOUCH_T24		24
 #define MXT_PROCI_TWOTOUCH_T27		27
 #define MXT_PROCI_GRIP_T40		40
@@ -102,6 +105,7 @@
 #define MXT_PROCI_STYLUS_T47		47
 #define MXT_PROCI_ADAPTIVETHRESHOLD_T55 55
 #define MXT_PROCI_SHIELDLESS_T56	56
+#define MXT_PROCI_EXTRATSDATA_T57	57
 #define MXT_PROCG_NOISESUPPRESSION_T48	48
 #define MXT_SPT_COMMSCONFIG_T18		18
 #define MXT_SPT_GPIOPWM_T19		19
@@ -111,6 +115,7 @@
 #define MXT_SPT_DIGITIZER_T43		43
 #define MXT_SPT_MESSAGECOUNT_T44	44
 #define MXT_SPT_CTECONFIG_T46		46
+#define MXT_SPT_TIMER_T61		61
 
 /* MXT_GEN_COMMAND_T6 field */
 #define MXT_COMMAND_RESET	0
@@ -231,6 +236,8 @@
 #define MXT224_RESET_TIME	65	/* msec */
 #define MXT224E_RESET_TIME	150	/* msec */
 #define MXT1386_RESET_TIME	250	/* msec */
+#define MXT336S_RESET_TIME	25	/* msec */
+#define MXT1664S_RESET_TIME	65	/* msec */
 #define MXT_RESET_TIME		250	/* msec */
 #define MXT_RESET_NOCHGREAD	400	/* msec */
 
@@ -372,6 +379,7 @@
 	case MXT_TOUCH_PROXKEY_T52:
 	case MXT_PROCI_GRIPFACE_T20:
 	case MXT_PROCG_NOISE_T22:
+	case MXT_PROCG_NOISE_T62:
 	case MXT_PROCI_ONETOUCH_T24:
 	case MXT_PROCI_TWOTOUCH_T27:
 	case MXT_PROCI_GRIP_T40:
@@ -379,6 +387,7 @@
 	case MXT_PROCI_TOUCHSUPPRESSION_T42:
 	case MXT_PROCI_STYLUS_T47:
 	case MXT_PROCI_SHIELDLESS_T56:
+	case MXT_PROCI_EXTRATSDATA_T57:
 	case MXT_PROCG_NOISESUPPRESSION_T48:
 	case MXT_SPT_COMMSCONFIG_T18:
 	case MXT_SPT_GPIOPWM_T19:
@@ -387,6 +396,7 @@
 	case MXT_SPT_USERDATA_T38:
 	case MXT_SPT_DIGITIZER_T43:
 	case MXT_SPT_CTECONFIG_T46:
+	case MXT_SPT_TIMER_T61:
 	case MXT_PROCI_ADAPTIVETHRESHOLD_T55:
 		return true;
 	default:
@@ -406,6 +416,7 @@
 	case MXT_TOUCH_PROXKEY_T52:
 	case MXT_PROCI_GRIPFACE_T20:
 	case MXT_PROCG_NOISE_T22:
+	case MXT_PROCG_NOISE_T62:
 	case MXT_PROCI_ONETOUCH_T24:
 	case MXT_PROCI_TWOTOUCH_T27:
 	case MXT_PROCI_GRIP_T40:
@@ -413,6 +424,7 @@
 	case MXT_PROCI_TOUCHSUPPRESSION_T42:
 	case MXT_PROCI_STYLUS_T47:
 	case MXT_PROCI_SHIELDLESS_T56:
+	case MXT_PROCI_EXTRATSDATA_T57:
 	case MXT_PROCG_NOISESUPPRESSION_T48:
 	case MXT_SPT_COMMSCONFIG_T18:
 	case MXT_SPT_GPIOPWM_T19:
@@ -421,6 +433,7 @@
 	case MXT_SPT_USERDATA_T38:
 	case MXT_SPT_DIGITIZER_T43:
 	case MXT_SPT_CTECONFIG_T46:
+	case MXT_SPT_TIMER_T61:
 	case MXT_PROCI_ADAPTIVETHRESHOLD_T55:
 		return true;
 	default:
@@ -1293,8 +1306,12 @@
 	case MXT224E_ID:
 		msleep(MXT224E_RESET_TIME);
 		break;
+	case MXT336S_ID:
+		msleep(MXT336S_RESET_TIME);
 	case MXT1386_ID:
 		msleep(MXT1386_RESET_TIME);
+	case MXT1664S_ID:
+		msleep(MXT1664S_RESET_TIME);
 		break;
 	default:
 		msleep(MXT_RESET_TIME);
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index e59ca17..55639e0 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -415,6 +415,7 @@
 
 	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
 
 	input_set_abs_params(input_dev, ABS_X, ts->min_x,
 				ts->max_x, pdata->fuzzx, 0);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 790cc10..df71f76 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -685,6 +685,52 @@
 	}
 }
 
+void dvb_dmx_swfilter_section_packets(struct dvb_demux *demux, const u8 *buf,
+			      size_t count)
+{
+	struct dvb_demux_feed *feed;
+	u16 pid = ts_pid(buf);
+	struct timespec pre_time;
+
+	if (dvb_demux_performancecheck)
+		pre_time = current_kernel_time();
+
+	spin_lock(&demux->lock);
+
+	demux->sw_filter_abort = 0;
+
+	while (count--) {
+		if (buf[0] != 0x47) {
+			buf += 188;
+			continue;
+		}
+
+		if (demux->playback_mode == DMX_PB_MODE_PULL)
+			if (dvb_dmx_swfilter_buffer_check(demux, pid) < 0)
+				break;
+
+		list_for_each_entry(feed, &demux->feed_list, list_head) {
+			if (feed->pid != pid)
+				continue;
+
+			if (!feed->feed.sec.is_filtering)
+				continue;
+
+			if (dvb_dmx_swfilter_section_packet(feed, buf) < 0) {
+				feed->feed.sec.seclen = 0;
+				feed->feed.sec.secbufp = 0;
+			}
+		}
+		buf += 188;
+	}
+
+	spin_unlock(&demux->lock);
+
+	if (dvb_demux_performancecheck)
+		demux->total_process_time += dvb_dmx_calc_time_delta(pre_time);
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter_section_packets);
+
 void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
 			      size_t count)
 {
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index a663191..5a32363 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -179,6 +179,8 @@
 
 int dvb_dmx_init(struct dvb_demux *dvbdemux);
 void dvb_dmx_release(struct dvb_demux *dvbdemux);
+void dvb_dmx_swfilter_section_packets(struct dvb_demux *demux, const u8 *buf,
+			      size_t count);
 void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf,
 			      size_t count);
 void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
index bd1ecfe..74a0dbe 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
@@ -26,8 +26,8 @@
 #define DMX_TSIF_MAX_SECTION_FILTER_NUM	64
 
 /* When TSIF driver notifies demux that new packets are received */
-#define DMX_TSIF_PACKETS_IN_CHUNK_DEF		16
-#define DMX_TSIF_CHUNKS_IN_BUF			8
+#define DMX_TSIF_PACKETS_IN_CHUNK_DEF		512
+#define DMX_TSIF_CHUNKS_IN_BUF			16
 #define DMX_TSIF_TIME_LIMIT			10000
 
 /* TSIF_DRIVER_MODE: 3 means manual control from debugfs. use 1 normally. */
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
index fd94e80..c1d1462 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
@@ -47,22 +47,29 @@
 
 #define TSPP_RAW_TTS_SIZE				192
 
-/* Size of single descriptor.
- * Assuming 20MBit/sec stream, with 200 packets
- * per descriptor there would be about 68 descriptors.
- * Meanning about 68 interrupts per second.
+/* Size of single descriptor. Using max descriptor size (170 packets).
+ * Assuming 20MBit/sec stream, with 170 packets
+ * per descriptor there would be about 82 descriptors,
+ * Meanning about 82 notifications per second.
  */
-#define TSPP_BUFFER_SIZE			(TSPP_RAW_TTS_SIZE * 200)
+#define MAX_BAM_DESCRIPTOR_SIZE		(32*1024 - 1)
+#define TSPP_BUFFER_SIZE			\
+	((MAX_BAM_DESCRIPTOR_SIZE / TSPP_RAW_TTS_SIZE) * TSPP_RAW_TTS_SIZE)
 
 /* Number of descriptors, total size: TSPP_BUFFER_SIZE*TSPP_BUFFER_COUNT */
-#define TSPP_BUFFER_COUNT				(16)
+#define TSPP_BUFFER_COUNT				(32)
 
 /* When TSPP notifies demux that new packets are received */
-#define TSPP_NOTIFICATION_SIZE			(TSPP_RAW_TTS_SIZE * 100)
+#define TSPP_NOTIFICATION_SIZE			1
 
 /* Channel timeout in msec */
 #define TSPP_CHANNEL_TIMEOUT			16
 
+/* module parameters for load time configuration */
+static int tsif0_mode = TSPP_TSIF_MODE_2;
+static int tsif1_mode = TSPP_TSIF_MODE_2;
+module_param(tsif0_mode, int, S_IRUGO);
+module_param(tsif1_mode, int, S_IRUGO);
 
 /*
  * Work scheduled each time TSPP notifies dmx
@@ -232,7 +239,7 @@
  * @channel_id: Channel with new TS packets
  * @user: user-data holding TSIF number
  */
-static void mpq_tspp_callback(u32 channel_id, void *user)
+static void mpq_tspp_callback(int channel_id, void *user)
 {
 	int tsif = (int)user;
 	struct work_struct *work;
@@ -271,14 +278,17 @@
 	int ret;
 	int channel_id;
 	int *channel_ref_count;
+	enum tspp_tsif_mode mode;
 
 	/* determine the TSIF we are reading from */
 	if (mpq_demux->source == DMX_SOURCE_FRONT0) {
 		tsif = 0;
 		tspp_source = TSPP_SOURCE_TSIF0;
+		mode = (enum tspp_tsif_mode)tsif0_mode;
 	} else if (mpq_demux->source == DMX_SOURCE_FRONT1) {
 		tsif = 1;
 		tspp_source = TSPP_SOURCE_TSIF1;
+		mode = (enum tspp_tsif_mode)tsif1_mode;
 	} else {
 		/* invalid source */
 		MPQ_DVB_ERR_PRINT(
@@ -331,7 +341,7 @@
 		}
 
 		/* set TSPP source */
-		ret = tspp_open_stream(0, channel_id, tspp_source);
+		ret = tspp_open_stream(0, channel_id, tspp_source, mode);
 		if (ret < 0) {
 			MPQ_DVB_ERR_PRINT(
 				"%s: tspp_select_source(%d,%d) failed (%d)\n",
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index c0a35f9..1894465 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -2347,37 +2347,6 @@
 	int retval;
 	radio->region = req_region;
 
-	switch (radio->region) {
-	case IRIS_REGION_US:
-		radio->recv_conf.band_low_limit =
-			REGION_US_EU_BAND_LOW;
-		radio->recv_conf.band_high_limit =
-			REGION_US_EU_BAND_HIGH;
-		break;
-	case IRIS_REGION_EU:
-		radio->recv_conf.band_low_limit =
-			REGION_US_EU_BAND_LOW;
-		radio->recv_conf.band_high_limit =
-			REGION_US_EU_BAND_HIGH;
-		break;
-	case IRIS_REGION_JAPAN:
-		radio->recv_conf.band_low_limit =
-			REGION_JAPAN_STANDARD_BAND_LOW;
-		radio->recv_conf.band_high_limit =
-			REGION_JAPAN_STANDARD_BAND_HIGH;
-		break;
-	case IRIS_REGION_JAPAN_WIDE:
-		radio->recv_conf.band_low_limit =
-			REGION_JAPAN_WIDE_BAND_LOW;
-		radio->recv_conf.band_high_limit =
-			REGION_JAPAN_WIDE_BAND_HIGH;
-		break;
-	default:
-		/* The user specifies the value.
-		   So nothing needs to be done */
-		break;
-	}
-
 	retval = hci_set_fm_recv_conf(
 			&radio->recv_conf,
 			radio->fm_hdev);
@@ -2391,34 +2360,6 @@
 	int retval;
 	radio->region = req_region;
 
-	switch (radio->region) {
-	case IRIS_REGION_US:
-		radio->trans_conf.band_low_limit =
-			REGION_US_EU_BAND_LOW;
-		radio->trans_conf.band_high_limit =
-			REGION_US_EU_BAND_HIGH;
-		break;
-	case IRIS_REGION_EU:
-		radio->trans_conf.band_low_limit =
-			REGION_US_EU_BAND_LOW;
-		radio->trans_conf.band_high_limit =
-			REGION_US_EU_BAND_HIGH;
-		break;
-	case IRIS_REGION_JAPAN:
-		radio->trans_conf.band_low_limit =
-			REGION_JAPAN_STANDARD_BAND_LOW;
-		radio->trans_conf.band_high_limit =
-			REGION_JAPAN_STANDARD_BAND_HIGH;
-		break;
-	case IRIS_REGION_JAPAN_WIDE:
-		radio->recv_conf.band_low_limit =
-			REGION_JAPAN_WIDE_BAND_LOW;
-		radio->recv_conf.band_high_limit =
-			REGION_JAPAN_WIDE_BAND_HIGH;
-	default:
-		break;
-	}
-
 	retval = hci_set_fm_trans_conf(
 			&radio->trans_conf,
 				radio->fm_hdev);
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 116b7f9..af4c2c9 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -122,6 +122,8 @@
 	int enable_optimized_srch_alg;
 	unsigned char spur_table_size;
 	struct fm_spur_data spur_data;
+	atomic_t validate_channel;
+	unsigned char is_station_valid;
 };
 
 /**************************************************************************
@@ -152,6 +154,7 @@
 static int update_spur_table(struct tavarua_device *radio);
 static int xfr_rdwr_data(struct tavarua_device *radio, int op, int size,
 	unsigned long offset, unsigned char *buf);
+static int compute_MPX_DCC(struct tavarua_device *radio, int *val);
 
 /* work function */
 static void read_int_stat(struct work_struct *work);
@@ -734,7 +737,7 @@
 static void tavarua_handle_interrupts(struct tavarua_device *radio)
 {
 	int i;
-	int retval;
+	int retval, adj_channel_tune_req = 0;
 	unsigned char xfr_status;
 	if (!radio->handle_irq) {
 		FMDBG("IRQ happend, but I wont handle it\n");
@@ -758,7 +761,25 @@
 			complete(&radio->sync_req_done);
 			radio->tune_req = 0;
 		}
-		tavarua_q_event(radio, TAVARUA_EVT_TUNE_SUCC);
+
+		/*
+		 * Do not queue the TUNE event while validating if the station
+		 * is good or not. As part of channel validation we tune to the
+		 * adjacent station, measure its MPX_DCC value, then tune back
+		 * to the original station and measure its MPX_DCC value.
+		 * Compare the MPX_DCC values of curent and adjacent stations
+		 * and decide if the channel is valid or not. During this period
+		 * we should not queue the TUNE event to the upper layers.
+		 */
+		adj_channel_tune_req = atomic_read(&radio->validate_channel);
+		if (adj_channel_tune_req) {
+			complete(&radio->sync_req_done);
+			FMDBG("Tune event for adjacent channel\n");
+		} else {
+			tavarua_q_event(radio, TAVARUA_EVT_TUNE_SUCC);
+			FMDBG("Queueing Tune event\n");
+		}
+
 		if (radio->srch_params.get_list) {
 			tavarua_start_xfr(radio, TAVARUA_XFR_SRCH_LIST,
 							RX_STATIONS_0);
@@ -2603,40 +2624,57 @@
 static int xfr_rdwr_data(struct tavarua_device *radio, int op, int size,
 	unsigned long offset, unsigned char *buf) {
 
-	unsigned char xfr_buf[XFR_REG_NUM];
+	unsigned char xfr_buf[XFR_REG_NUM + 1];
 	int retval = 0, temp = 0;
 
+	/* zero initialize the buffer */
 	memset(xfr_buf, 0x0, XFR_REG_NUM);
+
+	/* save the 'size' parameter */
 	temp = size;
 
-	xfr_buf[XFR_MODE_OFFSET]     = (size << 1);
+	/* Populate the XFR bytes */
+	xfr_buf[XFR_MODE_OFFSET]     = LSH_DATA(size, 1);
 	xfr_buf[XFR_ADDR_MSB_OFFSET] = GET_FREQ(offset, 1);
 	xfr_buf[XFR_ADDR_LSB_OFFSET] = GET_FREQ(offset, 0);
-
 	if (op == XFR_READ) {
+		if (size > XFR_REG_NUM) {
+			FMDERR("%s: Cant read more than 16 bytes\n", __func__);
+			return -EINVAL;
+		}
 		xfr_buf[XFR_MODE_OFFSET] |= (XFR_PEEK_MODE);
 		size = 3;
 	} else if (op == XFR_WRITE) {
+		if (size > (XFR_REG_NUM - 2)) {
+			FMDERR("%s: Cant write more than 14 bytes\n", __func__);
+			return -EINVAL;
+		}
 		xfr_buf[XFR_MODE_OFFSET] |= (XFR_POKE_MODE);
 		memcpy(&xfr_buf[XFR_DATA_OFFSET], buf, size);
 		size += 3;
 	}
 
+	/* Perform the XFR READ/WRITE operation */
+	init_completion(&radio->sync_req_done);
 	retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, size);
 	if (retval < 0) {
-		FMDERR("%s: Failed to performXFR operation\n", __func__);
+		FMDERR("%s: Failed to perform XFR operation\n", __func__);
 		return retval;
 	}
 
-	size = temp;
-
 	/*Wait for the XFR interrupt */
-	init_completion(&radio->sync_req_done);
 	if (!wait_for_completion_timeout(&radio->sync_req_done,
 		msecs_to_jiffies(WAIT_TIMEOUT))) {
 		FMDERR("Timeout: No XFR interrupt");
+		return -ETIMEDOUT;
 	}
 
+	/*
+	 * For XFR READ operation save the XFR data provided by the SOC.
+	 * Firmware reads the data from the address specified and places
+	 * them in to the registers XFRDAT0-XFRDAT15 which the host can read.
+	 */
+	size = temp;
 	if (op == XFR_READ) {
 		retval = tavarua_read_registers(radio, XFRDAT0, size);
 		if (retval < 0) {
@@ -2645,6 +2683,10 @@
 		}
 		if (buf != NULL)
 			memcpy(buf, &radio->registers[XFRDAT0], size);
+		else {
+			FMDERR("%s: No buffer to copy XFR data\n", __func__);
+			return -EINVAL;
+		}
 	}
 
 	return retval;
@@ -2966,6 +3008,9 @@
 	case V4L2_CID_PRIVATE_IRIS_GET_SINR:
 		retval = 0;
 		break;
+	case V4L2_CID_PRIVATE_VALID_CHANNEL:
+		ctrl->value = radio->is_station_valid;
+		break;
 	default:
 		retval = -EINVAL;
 	}
@@ -3114,12 +3159,15 @@
 		struct v4l2_control *ctrl)
 {
 	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
-	int retval = 0;
-	int size = 0, cnt = 0;
+	int retval = 0, size = 0, cnt = 0;
 	unsigned char value;
 	unsigned char xfr_buf[XFR_REG_NUM];
 	unsigned char tx_data[XFR_REG_NUM];
 	unsigned char dis_buf[XFR_REG_NUM];
+	unsigned int freq = 0, mpx_dcc = 0;
+	unsigned long curr = 0, prev = 0;
+
+	memset(xfr_buf, 0x0, XFR_REG_NUM);
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_VOLUME:
@@ -3538,6 +3586,104 @@
 		if (retval < 0)
 			FMDERR("Tone generator failed\n");
 		break;
+	case V4L2_CID_PRIVATE_VALID_CHANNEL:
+		/* Do not notify the host of tune event */
+		atomic_set(&radio->validate_channel, 1);
+
+		FMDBG("Going into low power mode\n");
+		retval = tavarua_disable_interrupts(radio);
+
+		/*
+		 * Tune to 50KHz adjacent channel. If the requested station
+		 * falls in JAPAN band and on the lower band-limit, then the
+		 * adjacnet channel to be considered is 50KHz to the right side
+		 * of the requested station as firmware does not allows to tune
+		 * to frequency outside the range: 76000KHz to 108000KHz.
+		 */
+		if (ctrl->value == REGION_JAPAN_STANDARD_BAND_LOW)
+			freq = (ctrl->value + ADJ_CHANNEL_KHZ);
+		else
+			freq = (ctrl->value - ADJ_CHANNEL_KHZ);
+		INIT_COMPLETION(radio->sync_req_done);
+		retval = tavarua_set_freq(radio, (freq * TUNE_MULT));
+		if (retval < 0) {
+			FMDERR("Failed to tune to adjacent station\n");
+			goto error;
+		}
+		if (!wait_for_completion_timeout(&radio->sync_req_done,
+			msecs_to_jiffies(wait_timeout))) {
+			FMDERR("Timeout: No Tune response\n");
+			retval = -ETIMEDOUT;
+			goto error;
+		}
+
+		/*
+		 * Wait for a minimum of 100ms for the firmware
+		 * to start collecting the MPX_DCC values
+		 */
+		msleep(TAVARUA_DELAY * 10);
+
+		/* Compute MPX_DCC of adjacent station */
+		retval = compute_MPX_DCC(radio, &mpx_dcc);
+		if (retval < 0) {
+			FMDERR("Failed to get MPX_DCC of adjacent station\n");
+			goto error;
+		}
+		/* Calculate the absolute value of MPX_DCC */
+		prev = abs(mpx_dcc);
+
+		/* Tune back to original station */
+		INIT_COMPLETION(radio->sync_req_done);
+		retval = tavarua_set_freq(radio, (ctrl->value * TUNE_MULT));
+		if (retval < 0) {
+			FMDERR("Failed to tune to requested station\n");
+			goto error;
+		}
+		if (!wait_for_completion_timeout(&radio->sync_req_done,
+			msecs_to_jiffies(wait_timeout))) {
+			FMDERR("Timeout: No Tune response\n");
+			retval = -ETIMEDOUT;
+			goto error;
+		}
+
+		/*
+		 * Wait for a minimum of 100ms for the firmware
+		 * to start collecting the MPX_DCC values
+		 */
+		msleep(TAVARUA_DELAY * 10);
+
+		/* Compute MPX_DCC of current station */
+		retval = compute_MPX_DCC(radio, &mpx_dcc);
+		if (retval < 0) {
+			FMDERR("Failed to get MPX_DCC of current station\n");
+			goto error;
+		}
+		/* Calculate the absolute value of MPX_DCC */
+		curr = abs(mpx_dcc);
+
+		FMDBG("Going into normal power mode\n");
+		tavarua_setup_interrupts(radio,
+			(radio->registers[RDCTRL] & 0x03));
+
+		FMDBG("Absolute MPX_DCC of current station  : %lu\n", curr);
+		FMDBG("Absolute MPX_DCC of adjacent station : %lu\n", prev);
+
+		/*
+		 * For valid stations, the absolute MPX_DCC value will be within
+		 * the range 0 <= MPX_DCC <= 12566 and the MPX_DCC value of the
+		 * adjacent station will be greater than 20,000.
+		 */
+		if ((curr <= MPX_DCC_LIMIT) &&
+			(prev > MPX_DCC_UPPER_LIMIT)) {
+			FMDBG("%d KHz is A VALID STATION!\n", ctrl->value);
+			radio->is_station_valid = VALID_CHANNEL;
+		} else {
+			FMDBG("%d KHz is NOT A VALID STATION!\n", ctrl->value);
+			radio->is_station_valid = INVALID_CHANNEL;
+		}
+error:
+		atomic_set(&radio->validate_channel, 0);
+		break;
 	default:
 		retval = -EINVAL;
 	}
@@ -3548,6 +3694,56 @@
 	return retval;
 }
 
+static int compute_MPX_DCC(struct tavarua_device *radio, int *val)
+{
+
+	int DCC = 0, retval = 0;
+	int MPX_DCC[3];
+	unsigned char value;
+	unsigned char xfr_buf[XFR_REG_NUM];
+
+	/* Freeze the MPX_DCC value from changing */
+	value = CTRL_ON;
+	retval = xfr_rdwr_data(radio, XFR_WRITE, 1, MPX_DCC_BYPASS_REG, &value);
+	if (retval < 0) {
+		FMDERR("%s: Failed to freeze MPX_DCC\n", __func__);
+		return retval;
+	}
+
+	/* Measure the MPX_DCC of current station. */
+	retval = xfr_rdwr_data(radio, XFR_READ, 3, MPX_DCC_DATA_REG, xfr_buf);
+	if (retval < 0) {
+		FMDERR("%s: Failed to read MPX_DCC\n", __func__);
+		return retval;
+	}
+	MPX_DCC[0] = xfr_buf[0];
+	MPX_DCC[1] = xfr_buf[1];
+	MPX_DCC[2] = xfr_buf[2];
+	/*
+	 * Form the final MPX_DCC parameter
+	 * MPX_DCC[0] will form the LSB part
+	 * MPX_DCC[1] will be the middle part and 4 bits of
+	 * MPX_DCC[2] will be the MSB part of the 20-bit signed MPX_DCC
+	 */
+	DCC = (LSH_DATA(MPX_DCC[2], 16) | LSH_DATA(MPX_DCC[1], 8) | MPX_DCC[0]);
+
+	/* if bit-19 is '1',set remaining bits to '1' & make it -tive */
+	if (DCC & 0x00080000)
+		DCC |= 0xFFF00000;
+
+	*val = DCC;
+
+	/* Un-freeze the MPX_DCC value */
+	value = CTRL_OFF;
+	retval = xfr_rdwr_data(radio, XFR_WRITE, 1, 0x88C0, &value);
+	if (retval < 0) {
+		FMDERR("%s: Failed to un-freeze MPX_DCC\n", __func__);
+		return retval;
+	}
+
+	return retval;
+}
+
 /*=============================================================================
 FUNCTION:  tavarua_vidioc_g_tuner
 =============================================================================*/
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index e0de38d..082ee3d 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -215,6 +215,7 @@
 obj-$(CONFIG_MSM_CAMERA) += msm/
 obj-$(CONFIG_ARCH_OMAP)	+= omap/
 obj-$(CONFIG_MSM_VIDC_V4L2) += msm_vidc/
+obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += msm_wfd/
 
 ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 5088d21..c673852 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -56,5 +56,4 @@
 obj-$(CONFIG_MT9D112) += mt9d112.o mt9d112_reg.o
 
 obj-$(CONFIG_MT9D113) += mt9d113.o mt9d113_reg.o
-obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += wfd/
 obj-$(CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE) += msm_v4l2_video.o
diff --git a/drivers/media/video/msm/csi/include/csi2.0/msm_ispif_hwreg.h b/drivers/media/video/msm/csi/include/csi2.0/msm_ispif_hwreg.h
index ecc4fea2..c678ea2 100644
--- a/drivers/media/video/msm/csi/include/csi2.0/msm_ispif_hwreg.h
+++ b/drivers/media/video/msm/csi/include/csi2.0/msm_ispif_hwreg.h
@@ -69,9 +69,11 @@
 #define RAW_INTF_1_OVERFLOW_IRQ      25
 #define RESET_DONE_IRQ               27
 
-#define ISPIF_IRQ_STATUS_MASK        0xA493000
-#define ISPIF_IRQ_1_STATUS_MASK      0xA493000
-#define ISPIF_IRQ_STATUS_RDI_SOF_MASK	0x492000
+#define ISPIF_IRQ_STATUS_MASK          0xA493249
+#define ISPIF_IRQ_1_STATUS_MASK        0xA493249
+#define ISPIF_IRQ_STATUS_RDI_SOF_MASK  0x492000
+#define ISPIF_IRQ_STATUS_PIX_SOF_MASK  0x249
+#define ISPIF_IRQ_STATUS_SOF_MASK      0x492249
 #define ISPIF_IRQ_GLOBAL_CLEAR_CMD     0x1
 
 #endif
diff --git a/drivers/media/video/msm/csi/include/csi3.0/msm_ispif_hwreg.h b/drivers/media/video/msm/csi/include/csi3.0/msm_ispif_hwreg.h
index 820adf4..4b17538 100644
--- a/drivers/media/video/msm/csi/include/csi3.0/msm_ispif_hwreg.h
+++ b/drivers/media/video/msm/csi/include/csi3.0/msm_ispif_hwreg.h
@@ -83,9 +83,12 @@
 #define RAW_INTF_1_OVERFLOW_IRQ      25
 #define RESET_DONE_IRQ               27
 
-#define ISPIF_IRQ_STATUS_MASK        0xA493000
-#define ISPIF_IRQ_1_STATUS_MASK      0xA493000
-#define ISPIF_IRQ_STATUS_RDI_SOF_MASK	0x492000
+#define ISPIF_IRQ_STATUS_MASK          0xA493249
+#define ISPIF_IRQ_1_STATUS_MASK        0xA493249
+#define ISPIF_IRQ_STATUS_RDI_SOF_MASK  0x492000
+#define ISPIF_IRQ_STATUS_PIX_SOF_MASK  0x249
+#define ISPIF_IRQ_STATUS_SOF_MASK      0x492249
 #define ISPIF_IRQ_GLOBAL_CLEAR_CMD     0x1
 
+
 #endif
diff --git a/drivers/media/video/msm/csi/msm_ispif.c b/drivers/media/video/msm/csi/msm_ispif.c
index 02daa98..a5db556 100644
--- a/drivers/media/video/msm/csi/msm_ispif.c
+++ b/drivers/media/video/msm/csi/msm_ispif.c
@@ -24,6 +24,7 @@
 #define V4L2_IDENT_ISPIF                     50001
 #define CSID_VERSION_V2                      0x02000011
 #define CSID_VERSION_V3                      0x30000000
+
 #define MAX_CID 15
 
 static atomic_t ispif_irq_cnt;
@@ -52,6 +53,7 @@
 			else
 				data1 |= (0x1 << PIX_0_VFE_RST_STB) |
 					(0x1 << PIX_0_CSID_RST_STB);
+			ispif->pix_sof_count = 0;
 			break;
 
 		case RDI0:
@@ -127,7 +129,7 @@
 			(0x1 << PIX_1_CSID_RST_STB) |
 			(0x1 << RDI_2_VFE_RST_STB) |
 			(0x1 << RDI_2_CSID_RST_STB);
-	return 0;
+	ispif->pix_sof_count = 0;
 	msm_camera_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR);
 	rc = wait_for_completion_interruptible(&ispif->reset_complete);
 	if (ispif->csid_version >= CSID_VERSION_V3) {
@@ -573,7 +575,8 @@
 
 DECLARE_TASKLET(ispif_tasklet, ispif_do_tasklet, 0);
 
-static void ispif_process_irq(struct ispif_irq_status *out)
+static void ispif_process_irq(struct ispif_device *ispif,
+	struct ispif_irq_status *out)
 {
 	unsigned long flags;
 	struct ispif_isr_queue_cmd *qcmd;
@@ -588,6 +591,13 @@
 	qcmd->ispifInterruptStatus0 = out->ispifIrqStatus0;
 	qcmd->ispifInterruptStatus1 = out->ispifIrqStatus1;
 
+	if (qcmd->ispifInterruptStatus0 & ISPIF_IRQ_STATUS_PIX_SOF_MASK) {
+		CDBG("%s: ispif PIX sof irq\n", __func__);
+		ispif->pix_sof_count++;
+		v4l2_subdev_notify(&ispif->subdev, NOTIFY_VFE_SOF_COUNT,
+			(void *)&ispif->pix_sof_count);
+	}
+
 	spin_lock_irqsave(&ispif_tasklet_lock, flags);
 	list_add_tail(&qcmd->list, &ispif_tasklet_q);
 
@@ -610,7 +620,7 @@
 	msm_camera_io_w(out->ispifIrqStatus1,
 		ispif->base + ISPIF_IRQ_CLEAR_1_ADDR);
 
-	CDBG("ispif->irq: Irq_status0 = 0x%x\n",
+	CDBG("%s: irq ispif->irq: Irq_status0 = 0x%x\n", __func__,
 		out->ispifIrqStatus0);
 	if (out->ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) {
 		if (out->ispifIrqStatus0 & (0x1 << RESET_DONE_IRQ))
@@ -619,10 +629,10 @@
 			pr_err("%s: pix intf 0 overflow.\n", __func__);
 		if (out->ispifIrqStatus0 & (0x1 << RAW_INTF_0_OVERFLOW_IRQ))
 			pr_err("%s: rdi intf 0 overflow.\n", __func__);
-		if ((out->ispifIrqStatus0 & ISPIF_IRQ_STATUS_RDI_SOF_MASK) ||
+		if ((out->ispifIrqStatus0 & ISPIF_IRQ_STATUS_SOF_MASK) ||
 			(out->ispifIrqStatus1 &
-				ISPIF_IRQ_STATUS_RDI_SOF_MASK)) {
-			ispif_process_irq(out);
+				ISPIF_IRQ_STATUS_SOF_MASK)) {
+			ispif_process_irq(ispif, out);
 		}
 	}
 	msm_camera_io_w(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
@@ -653,7 +663,6 @@
 	INIT_LIST_HEAD(&ispif_tasklet_q);
 	rc = request_irq(ispif->irq->start, msm_io_ispif_irq,
 		IRQF_TRIGGER_RISING, "ispif", ispif);
-
 	init_completion(&ispif->reset_complete);
 
 	ispif->csid_version = *csid_version;
diff --git a/drivers/media/video/msm/csi/msm_ispif.h b/drivers/media/video/msm/csi/msm_ispif.h
index df93a44..f4ad661 100644
--- a/drivers/media/video/msm/csi/msm_ispif.h
+++ b/drivers/media/video/msm/csi/msm_ispif.h
@@ -34,6 +34,7 @@
 	struct completion reset_complete;
 	uint32_t csid_version;
 	struct clk *ispif_clk[5];
+	uint32_t pix_sof_count;
 };
 
 struct ispif_isr_queue_cmd {
diff --git a/drivers/media/video/msm/eeprom/msm_camera_eeprom.c b/drivers/media/video/msm/eeprom/msm_camera_eeprom.c
index 96a6e04..effae8b 100644
--- a/drivers/media/video/msm/eeprom/msm_camera_eeprom.c
+++ b/drivers/media/video/msm/eeprom/msm_camera_eeprom.c
@@ -100,7 +100,7 @@
 		}
 		rc = e_ctrl->func_tbl.eeprom_get_info(e_ctrl,
 			&cdata.cfg.get_info);
-
+		cdata.is_eeprom_supported = 1;
 		if (copy_to_user((void *)argp,
 			&cdata,
 			sizeof(struct msm_eeprom_cfg_data)))
diff --git a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
index 7e80145..9549dcc 100644
--- a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
+++ b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
@@ -21,7 +21,7 @@
 #include <mach/clk.h>
 #include <mach/msm_bus.h>
 #include <mach/msm_bus_board.h>
-
+#include <mach/dal_axi.h>
 
 #define MSM_AXI_QOS_PREVIEW 200000
 #define MSM_AXI_QOS_SNAPSHOT 200000
@@ -142,6 +142,7 @@
 		break;
 	case S_PREVIEW:
 		update_axi_qos(MSM_AXI_QOS_PREVIEW);
+		axi_allocate(AXI_FLOW_VIEWFINDER_HI);
 		break;
 	case S_VIDEO:
 		update_axi_qos(MSM_AXI_QOS_RECORDING);
@@ -153,6 +154,7 @@
 		update_axi_qos(PM_QOS_DEFAULT_VALUE);
 		break;
 	case S_EXIT:
+		axi_free(AXI_FLOW_VIEWFINDER_HI);
 		release_axi_qos();
 		break;
 	default:
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 29aba08..e5c1091 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -189,12 +189,25 @@
 {
 	int rc = 0, i, j;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
+	struct msm_cam_media_controller *pmctl;
+	struct msm_cam_v4l2_device *pcam = video_drvdata(f);
 	pcam_inst = container_of(f->private_data,
 		struct msm_cam_v4l2_dev_inst, eventHandle);
 	D("%s\n", __func__);
 	WARN_ON(pctx != f->private_data);
 
 	mutex_lock(&pcam_inst->inst_lock);
+	if (!pcam_inst->vbqueue_initialized && pb->count) {
+		pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
+		if (pmctl == NULL) {
+			pr_err("%s Invalid mctl ptr", __func__);
+			return -EINVAL;
+		}
+		pmctl->mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq,
+			pb->type);
+		pcam_inst->vbqueue_initialized = 1;
+	}
+
 	rc = vb2_reqbufs(&pcam_inst->vid_bufq, pb);
 	if (rc < 0) {
 		pr_err("%s reqbufs failed %d ", __func__, rc);
@@ -564,7 +577,6 @@
 	int rc;
 	/* get the video device */
 	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
-	struct msm_cam_media_controller *pmctl;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
 	pcam_inst = container_of(f->private_data,
 		struct msm_cam_v4l2_dev_inst, eventHandle);
@@ -575,16 +587,6 @@
 		(void *)pfmt->fmt.pix.priv);
 	WARN_ON(pctx != f->private_data);
 
-	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
-	if (pmctl == NULL)
-		return -EINVAL;
-
-	if (!pcam_inst->vbqueue_initialized) {
-		pmctl->mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq,
-					V4L2_BUF_TYPE_VIDEO_CAPTURE);
-		pcam_inst->vbqueue_initialized = 1;
-	}
-
 	mutex_lock(&pcam->vid_lock);
 
 	rc = msm_server_set_fmt(pcam, pcam_inst->my_index, pfmt);
@@ -602,7 +604,6 @@
 {
 	int rc;
 	struct msm_cam_v4l2_device *pcam = video_drvdata(f);
-	struct msm_cam_media_controller *pmctl;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
 	pcam_inst = container_of(f->private_data,
 			struct msm_cam_v4l2_dev_inst, eventHandle);
@@ -610,16 +611,6 @@
 	D("%s Inst %p\n", __func__, pcam_inst);
 	WARN_ON(pctx != f->private_data);
 
-	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
-	if (pmctl == NULL)
-		return -EINVAL;
-
-	if (!pcam_inst->vbqueue_initialized) {
-		pmctl->mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq,
-					V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
-		pcam_inst->vbqueue_initialized = 1;
-	}
-
 	mutex_lock(&pcam->vid_lock);
 	rc = msm_server_set_fmt_mplane(pcam, pcam_inst->my_index, pfmt);
 	mutex_unlock(&pcam->vid_lock);
@@ -718,6 +709,8 @@
 	SET_VIDEO_INST_IDX(pcam_inst->inst_handle, pcam_inst->my_index);
 	pcam_inst->pcam->dev_inst_map[pcam_inst->image_mode] = pcam_inst;
 	pcam_inst->path = msm_vidbuf_get_path(pcam_inst->image_mode);
+	rc = msm_cam_server_config_interface_map(pcam_inst->image_mode,
+			pcam_inst->pcam->mctl_handle);
 	D("%spath=%d,rc=%d\n", __func__,
 		pcam_inst->path, rc);
 	return rc;
@@ -834,7 +827,6 @@
 	int ion_client_created = 0;
 #endif
 	int server_q_idx = 0;
-	/*struct msm_isp_ops *p_isp = 0;*/
 	/* get the video device */
 	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
@@ -941,8 +933,7 @@
 	msm_destroy_v4l2_event_queue(&pcam_inst->eventHandle);
 
 	if (pmctl->mctl_release)
-		if (pmctl->mctl_release(pmctl) < 0)
-			pr_err("%s: mctl_release failed\n", __func__);
+		pmctl->mctl_release(pmctl);
 mctl_open_failed:
 	if (pcam->use_count == 1) {
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
@@ -1066,11 +1057,8 @@
 	if (pcam_inst->streamon) {
 		/*something went wrong since instance
 		is closing without streamoff*/
-		if (pmctl->mctl_release) {
-			rc = pmctl->mctl_release(pmctl);
-			if (rc < 0)
-				pr_err("mctl_release fails %d\n", rc);
-		}
+		if (pmctl->mctl_release)
+			pmctl->mctl_release(pmctl);
 		pmctl->mctl_release = NULL;/*so that it isn't closed again*/
 	}
 
@@ -1100,11 +1088,8 @@
 				pr_err("msm_send_close_server failed %d\n", rc);
 		}
 
-		if (pmctl->mctl_release) {
-			rc = pmctl->mctl_release(pmctl);
-			if (rc < 0)
-				pr_err("mctl_release fails %d\n", rc);
-		}
+		if (pmctl->mctl_release)
+			pmctl->mctl_release(pmctl);
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 		kref_put(&pmctl->refcount, msm_release_ion_client);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index c23ac34..8c644b8 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -151,11 +151,11 @@
 	NOTIFY_ISPIF_STREAM, /* arg = enable parameter for s_stream */
 	NOTIFY_VPE_MSG_EVT,
 	NOTIFY_VFE_CAMIF_ERROR,
+	NOTIFY_VFE_SOF_COUNT, /*arg = int*/
 	NOTIFY_PCLK_CHANGE, /* arg = pclk */
 	NOTIFY_CSIPHY_CFG, /* arg = msm_camera_csiphy_params */
 	NOTIFY_CSID_CFG, /* arg = msm_camera_csid_params */
 	NOTIFY_CSIC_CFG, /* arg = msm_camera_csic_params */
-	NOTIFY_VFE_BUF_FREE_EVT, /* arg = msm_camera_csic_params */
 	NOTIFY_VFE_IRQ,
 	NOTIFY_AXI_IRQ,
 	NOTIFY_GESTURE_EVT, /* arg = v4l2_event */
@@ -240,7 +240,7 @@
 	int (*mctl_cb)(void);
 	int (*mctl_cmd)(struct msm_cam_media_controller *p_mctl,
 					unsigned int cmd, unsigned long arg);
-	int (*mctl_release)(struct msm_cam_media_controller *p_mctl);
+	void (*mctl_release)(struct msm_cam_media_controller *p_mctl);
 	int (*mctl_buf_init)(struct msm_cam_v4l2_dev_inst *pcam);
 	int (*mctl_vbqueue_init)(struct msm_cam_v4l2_dev_inst *pcam,
 				struct vb2_queue *q, enum v4l2_buf_type type);
@@ -291,15 +291,10 @@
 struct msm_isp_ops {
 	char *config_dev_name;
 
-	/*int (*isp_init)(struct msm_cam_v4l2_device *pcam);*/
-	int (*isp_open)(struct v4l2_subdev *sd,
-		struct msm_cam_media_controller *mctl);
 	int (*isp_config)(struct msm_cam_media_controller *pmctl,
 		 unsigned int cmd, unsigned long arg);
 	int (*isp_notify)(struct v4l2_subdev *sd,
 		unsigned int notification, void *arg);
-	void (*isp_release)(struct msm_cam_media_controller *mctl,
-		struct v4l2_subdev *sd);
 	int (*isp_pp_cmd)(struct msm_cam_media_controller *pmctl,
 		 struct msm_mctl_pp_cmd, void *data);
 
@@ -401,9 +396,9 @@
 	struct cdev config_cdev;
 	struct v4l2_queue_util config_stat_event_queue;
 	int use_count;
-	/*struct msm_isp_ops* isp_subdev;*/
 	struct msm_cam_media_controller *p_mctl;
 	struct msm_mem_map_info mem_map;
+	int dev_num;
 };
 
 struct msm_cam_subdev_info {
@@ -493,6 +488,15 @@
 	struct intr_table_entry comp_intr_tbl[CAMERA_SS_IRQ_MAX];
 };
 
+struct interface_map {
+	/* The interafce a particular stream belongs to.
+	 * PIX0, RDI0, RDI1, or RDI2
+	 */
+	int interface;
+	/* The handle of the mctl intstance interface runs on */
+	uint32_t mctl_handle;
+};
+
 /* abstract camera server device for all sensor successfully probed*/
 struct msm_cam_server_dev {
 
@@ -508,7 +512,7 @@
 	/* info of configs successfully created*/
 	struct msm_cam_config_dev_info config_info;
 	/* active working camera device - only one allowed at this time*/
-	struct msm_cam_v4l2_device *pcam_active;
+	struct msm_cam_v4l2_device *pcam_active[MAX_NUM_ACTIVE_CAMERA];
 	/* number of camera devices opened*/
 	atomic_t number_pcam_active;
 	struct v4l2_queue_util server_command_queue;
@@ -522,6 +526,8 @@
 	struct msm_cam_server_mctl_inst mctl[MAX_NUM_ACTIVE_CAMERA];
 	uint32_t mctl_handle_cnt;
 
+	struct interface_map interface_map_table[INTF_MAX];
+
 	int use_count;
 	/* all the registered ISP subdevice*/
 	struct msm_isp_ops *isp_subdev[MSM_MAX_CAMERA_CONFIGS];
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 935ce75..3d94afd 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -67,16 +67,16 @@
 	}
 }
 
-static int msm_isp_notify_VFE_BUF_FREE_EVT(struct v4l2_subdev *sd, void *arg)
+static int msm_isp_notify_VFE_SOF_COUNT_EVT(struct v4l2_subdev *sd, void *arg)
 {
 	struct msm_vfe_cfg_cmd cfgcmd;
 	struct msm_camvfe_params vfe_params;
 	int rc;
 
-	cfgcmd.cmd_type = CMD_VFE_BUFFER_RELEASE;
+	cfgcmd.cmd_type = CMD_VFE_SOF_COUNT_UPDATE;
 	cfgcmd.value = NULL;
 	vfe_params.vfe_cfg = &cfgcmd;
-	vfe_params.data = NULL;
+	vfe_params.data = arg;
 	rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
 	return 0;
 }
@@ -294,8 +294,8 @@
 	if (notification == NOTIFY_VFE_BUF_EVT)
 		return msm_isp_notify_VFE_BUF_EVT(sd, arg);
 
-	if (notification == NOTIFY_VFE_BUF_FREE_EVT)
-		return msm_isp_notify_VFE_BUF_FREE_EVT(sd, arg);
+	if (notification == NOTIFY_VFE_SOF_COUNT)
+		return msm_isp_notify_VFE_SOF_COUNT_EVT(sd, arg);
 
 	isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_ATOMIC);
 	if (!isp_event) {
@@ -499,35 +499,6 @@
 	return msm_isp_notify_vfe(sd, notification, arg);
 }
 
-/* This function is called by open() function, so we need to init HW*/
-static int msm_isp_open(struct v4l2_subdev *sd,
-	struct msm_cam_media_controller *mctl)
-{
-	/* init vfe and senor, register sync callbacks for init*/
-	int rc = 0;
-	D("%s\n", __func__);
-	if (!mctl) {
-		pr_err("%s: param is NULL", __func__);
-		return -EINVAL;
-	}
-
-	rc = v4l2_subdev_call(sd, core, ioctl,
-				VIDIOC_MSM_VFE_INIT, NULL);
-	if (rc < 0) {
-		pr_err("%s: vfe_init failed at %d\n",
-			__func__, rc);
-	}
-	return rc;
-}
-
-static void msm_isp_release(struct msm_cam_media_controller *mctl,
-	struct v4l2_subdev *sd)
-{
-	D("%s\n", __func__);
-	v4l2_subdev_call(sd, core, ioctl,
-				VIDIOC_MSM_VFE_RELEASE, NULL);
-}
-
 static int msm_config_vfe(struct v4l2_subdev *sd,
 	struct msm_cam_media_controller *mctl, void __user *arg)
 {
@@ -780,9 +751,7 @@
 	int i = 0;
 
 	for (i = 0; i < g_num_config_nodes; i++) {
-		isp_subdev[i].isp_open = msm_isp_open;
 		isp_subdev[i].isp_config = msm_isp_config;
-		isp_subdev[i].isp_release  = msm_isp_release;
 		isp_subdev[i].isp_notify = msm_isp_notify;
 	}
 	return 0;
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 6a446bf..6126901 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -130,6 +130,14 @@
 	.pxlcode	= V4L2_MBUS_FMT_SGRBG10_1X10, /* Bayer sensor */
 	.colorspace = V4L2_COLORSPACE_JPEG,
 	},
+	{
+	.name	   = "YUYV",
+	.depth	  = 16,
+	.bitsperpxl = 16,
+	.fourcc	 = V4L2_PIX_FMT_YUYV,
+	.pxlcode	= V4L2_MBUS_FMT_YUYV8_2X8, /* YUV sensor */
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	},
 
 };
 
@@ -189,6 +197,20 @@
 	return rc;
 }
 
+static uint8_t msm_sensor_state_check(
+	struct msm_cam_media_controller *p_mctl)
+{
+	struct msm_sensor_ctrl_t *s_ctrl = NULL;
+	if (!p_mctl)
+		return 0;
+	if (!p_mctl->sensor_sdev)
+		return 0;
+	s_ctrl = get_sctrl(p_mctl->sensor_sdev);
+	if (s_ctrl->sensor_state == MSM_SENSOR_POWER_UP)
+		return 1;
+	return 0;
+}
+
 /* called by the server or the config nodes to handle user space
 	commands*/
 static int msm_mctl_cmd(struct msm_cam_media_controller *p_mctl,
@@ -319,7 +341,6 @@
 	case MSM_CAM_IOCTL_EEPROM_IO_CFG: {
 		struct msm_eeprom_cfg_data eeprom_data;
 		if (p_mctl->eeprom_sdev) {
-			eeprom_data.is_eeprom_supported = 1;
 			rc = v4l2_subdev_call(p_mctl->eeprom_sdev,
 				core, ioctl, VIDIOC_MSM_EEPROM_CFG, argp);
 		} else {
@@ -362,7 +383,8 @@
 			ERR_COPY_FROM_USER();
 			rc = -EFAULT;
 		} else {
-			rc = msm_flash_ctrl(p_mctl->sdata, &flash_info);
+			if (msm_sensor_state_check(p_mctl))
+				rc = msm_flash_ctrl(p_mctl->sdata, &flash_info);
 		}
 		break;
 	}
@@ -549,9 +571,8 @@
 	return rc;
 }
 
-static int msm_mctl_release(struct msm_cam_media_controller *p_mctl)
+static void msm_mctl_release(struct msm_cam_media_controller *p_mctl)
 {
-	int rc = 0;
 	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(p_mctl->sensor_sdev);
 	struct msm_camera_sensor_info *sinfo =
 		(struct msm_camera_sensor_info *) s_ctrl->sensordata;
@@ -574,11 +595,6 @@
 			VIDIOC_MSM_AXI_RELEASE, NULL);
 	}
 
-	if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release
-		&& p_mctl->isp_sdev->sd)
-		p_mctl->isp_sdev->isp_release(p_mctl,
-			p_mctl->isp_sdev->sd);
-
 	if (p_mctl->csid_sdev) {
 		v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
 			VIDIOC_MSM_CSID_RELEASE, NULL);
@@ -602,7 +618,6 @@
 	pm_qos_remove_request(&p_mctl->pm_qos_req_list);
 
 	wake_unlock(&p_mctl->wake_lock);
-	return rc;
 }
 
 int msm_mctl_init_user_formats(struct msm_cam_v4l2_device *pcam)
@@ -861,6 +876,7 @@
 
 	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
 	mutex_lock(&pcam->mctl_node.dev_lock);
+	mutex_lock(&pcam_inst->inst_lock);
 	D("%s : active %d ", __func__, pcam->mctl_node.active);
 	if (pcam->mctl_node.active == 1) {
 		rc = msm_cam_server_close_mctl_session(pcam);
@@ -873,6 +889,7 @@
 		pmctl = NULL;
 	}
 	pcam_inst->streamon = 0;
+	pcam->mctl_node.use_count--;
 	pcam->mctl_node.dev_inst_map[pcam_inst->image_mode] = NULL;
 	if (pcam_inst->vbqueue_initialized)
 		vb2_queue_release(&pcam_inst->vid_bufq);
@@ -881,17 +898,16 @@
 	msm_destroy_v4l2_event_queue(&pcam_inst->eventHandle);
 	CLR_MCTLPP_INST_IDX(pcam_inst->inst_handle);
 	CLR_IMG_MODE(pcam_inst->inst_handle);
-
+	mutex_unlock(&pcam_inst->inst_lock);
 	mutex_destroy(&pcam_inst->inst_lock);
 
 	kfree(pcam_inst);
+	f->private_data = NULL;
 	if (NULL != pmctl) {
 		D("%s : release ion client", __func__);
 		kref_put(&pmctl->refcount, msm_release_ion_client);
 	}
-	f->private_data = NULL;
 	mutex_unlock(&pcam->mctl_node.dev_lock);
-	pcam->mctl_node.use_count--;
 	D("%s : use_count %d X ", __func__, pcam->mctl_node.use_count);
 	return rc;
 }
@@ -996,12 +1012,24 @@
 {
 	int rc = 0, i, j;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
+	struct msm_cam_media_controller *pmctl;
+	struct msm_cam_v4l2_device *pcam = video_drvdata(f);
 	pcam_inst = container_of(f->private_data,
 		struct msm_cam_v4l2_dev_inst, eventHandle);
 	D("%s\n", __func__);
 	WARN_ON(pctx != f->private_data);
 
 	mutex_lock(&pcam_inst->inst_lock);
+	if (!pcam_inst->vbqueue_initialized && pb->count) {
+		pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
+		if (pmctl == NULL) {
+			pr_err("%s Invalid mctl ptr", __func__);
+			return -EINVAL;
+		}
+		pmctl->mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq,
+			pb->type);
+		pcam_inst->vbqueue_initialized = 1;
+	}
 	rc = vb2_reqbufs(&pcam_inst->vid_bufq, pb);
 	if (rc < 0) {
 		pr_err("%s reqbufs failed %d ", __func__, rc);
@@ -1314,30 +1342,10 @@
 					struct v4l2_format *pfmt)
 {
 	int rc = 0;
-	/* get the video device */
-	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
-	struct msm_cam_media_controller *pmctl;
-	struct msm_cam_v4l2_dev_inst *pcam_inst;
-	pcam_inst = container_of(f->private_data,
-		struct msm_cam_v4l2_dev_inst, eventHandle);
 
 	D("%s\n", __func__);
-	D("%s, inst=0x%x,idx=%d,priv = 0x%p\n",
-		__func__, (u32)pcam_inst, pcam_inst->my_index,
-		(void *)pfmt->fmt.pix.priv);
 	WARN_ON(pctx != f->private_data);
 
-	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
-	if (!pmctl) {
-		pr_err("%s mctl ptr is null ", __func__);
-		return -EINVAL;
-	}
-	if (!pcam_inst->vbqueue_initialized) {
-		pmctl->mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq,
-					V4L2_BUF_TYPE_VIDEO_CAPTURE);
-		pcam_inst->vbqueue_initialized = 1;
-	}
-
 	return rc;
 }
 
@@ -1346,25 +1354,13 @@
 {
 	int rc = 0, i;
 	struct msm_cam_v4l2_device *pcam = video_drvdata(f);
-	struct msm_cam_media_controller *pmctl;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
 	pcam_inst = container_of(f->private_data,
 			struct msm_cam_v4l2_dev_inst, eventHandle);
 
-	D("%s Inst %p vbqueue %d\n", __func__,
-		pcam_inst, pcam_inst->vbqueue_initialized);
+	D("%s Inst %p\n", __func__, pcam_inst);
 	WARN_ON(pctx != f->private_data);
 
-	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
-	if (!pmctl) {
-		pr_err("%s mctl ptr is null ", __func__);
-		return -EINVAL;
-	}
-	if (!pcam_inst->vbqueue_initialized) {
-		pmctl->mctl_vbqueue_init(pcam_inst, &pcam_inst->vid_bufq,
-					V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
-		pcam_inst->vbqueue_initialized = 1;
-	}
 	for (i = 0; i < pcam->num_fmts; i++)
 		if (pcam->usr_fmts[i].fourcc == pfmt->fmt.pix_mp.pixelformat)
 			break;
@@ -1468,6 +1464,9 @@
 	pcam_inst->pcam->mctl_node.dev_inst_map[pcam_inst->image_mode] =
 		pcam_inst;
 	pcam_inst->path = msm_mctl_vidbuf_get_path(pcam_inst->image_mode);
+
+	rc = msm_cam_server_config_interface_map(pcam_inst->image_mode,
+			pcam_inst->pcam->mctl_handle);
 	D("%s path=%d, image mode = %d rc=%d\n", __func__,
 		pcam_inst->path, pcam_inst->image_mode, rc);
 	return rc;
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index a69858a..9f7f689 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -212,11 +212,6 @@
 	pcam = pcam_inst->pcam;
 	buf = container_of(vb, struct msm_frame_buffer, vidbuf);
 
-	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
-	if (pmctl == NULL) {
-		pr_err("%s No mctl found\n", __func__);
-		return;
-	}
 
 	if (pcam_inst->vid_fmt.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 		for (i = 0; i < vb->num_planes; i++) {
@@ -262,6 +257,12 @@
 		}
 		spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
 	}
+	pmctl = msm_cam_server_get_mctl(pcam->mctl_handle);
+	if (pmctl == NULL) {
+		pr_err("%s No mctl found\n", __func__);
+		buf->state = MSM_BUFFER_STATE_UNUSED;
+		return;
+	}
 	for (i = 0; i < vb->num_planes; i++) {
 		mem = vb2_plane_cookie(vb, i);
 		videobuf2_pmem_contig_user_put(mem, pmctl->client);
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index 76d57f0..0c781c5 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -408,6 +408,8 @@
 {
 	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
 	void __user *argp = (void __user *)arg;
+	if (s_ctrl->sensor_state == MSM_SENSOR_POWER_DOWN)
+		return -EINVAL;
 	switch (cmd) {
 	case VIDIOC_MSM_SENSOR_CFG:
 		return s_ctrl->func_tbl->sensor_config(s_ctrl, argp);
@@ -1612,6 +1614,7 @@
 	if (rc > 0)
 		rc = 0;
 	s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+	s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
 	return rc;
 }
 
@@ -1709,6 +1712,7 @@
 		if (rc < 0) {
 			pr_err("%s: %s power_up failed rc = %d\n", __func__,
 				s_ctrl->sensordata->sensor_name, rc);
+			s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
 		} else {
 			if (s_ctrl->func_tbl->sensor_match_id)
 				rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl);
@@ -1723,10 +1727,13 @@
 					pr_err("%s: %s power_down failed\n",
 					__func__,
 					s_ctrl->sensordata->sensor_name);
+				s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
 			}
+			s_ctrl->sensor_state = MSM_SENSOR_POWER_UP;
 		}
 	} else {
 		rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+		s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
 	}
 	mutex_unlock(s_ctrl->msm_sensor_mutex);
 	return rc;
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index 124c559..6c6b33e5 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -158,6 +158,11 @@
 	uint8_t is_csic;
 };
 
+enum msm_sensor_state {
+	MSM_SENSOR_POWER_UP,
+	MSM_SENSOR_POWER_DOWN,
+};
+
 struct msm_sensor_ctrl_t {
 	struct  msm_camera_sensor_info *sensordata;
 	struct i2c_client *msm_sensor_client;
@@ -198,6 +203,7 @@
 	struct regulator **reg_ptr;
 	struct clk *cam_clk;
 	long clk_rate;
+	enum msm_sensor_state sensor_state;
 };
 
 void msm_sensor_start_stream(struct msm_sensor_ctrl_t *s_ctrl);
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index 36b9576..0919799 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -108,6 +108,58 @@
 	v4l2_fh_exit(eventHandle);
 }
 
+int msm_cam_server_config_interface_map(u32 extendedmode, uint32_t mctl_handle)
+{
+	int i = 0;
+	int rc = 0;
+	int old_handle;
+	int interface;
+
+	switch (extendedmode) {
+	case MSM_V4L2_EXT_CAPTURE_MODE_RDI:
+		interface = RDI_0;
+		break;
+	case MSM_V4L2_EXT_CAPTURE_MODE_RDI1:
+		interface = RDI_1;
+		break;
+	case MSM_V4L2_EXT_CAPTURE_MODE_RDI2:
+		interface = RDI_2;
+		break;
+	default:
+		interface = PIX_0;
+		break;
+	}
+	for (i = 0; i < INTF_MAX; i++) {
+		if (g_server_dev.interface_map_table[i].interface ==
+							interface) {
+			old_handle =
+				g_server_dev.interface_map_table[i].mctl_handle;
+			if (old_handle == 0) {
+				g_server_dev.interface_map_table[i].mctl_handle
+					= mctl_handle;
+			} else if (old_handle != mctl_handle) {
+				pr_err("%s: interface_map[%d] was set: %d\n",
+					__func__, i, old_handle);
+				rc = -EINVAL;
+			}
+			break;
+		}
+	}
+
+	if (i == INTF_MAX)
+		rc = -EINVAL;
+	return rc;
+}
+
+void msm_cam_server_clear_interface_map(uint32_t mctl_handle)
+{
+	int i;
+	for (i = 0; i < INTF_MAX; i++)
+		if (g_server_dev.interface_map_table[i].mctl_handle ==
+								mctl_handle)
+			g_server_dev.interface_map_table[i].mctl_handle = 0;
+}
+
 uint32_t msm_cam_server_get_mctl_handle(void)
 {
 	uint32_t i;
@@ -146,13 +198,15 @@
 	return NULL;
 }
 
-static void msm_cam_server_send_error_evt(int evt_type)
+
+static void msm_cam_server_send_error_evt(
+		struct msm_cam_media_controller *pmctl, int evt_type)
 {
 	struct v4l2_event v4l2_ev;
 	v4l2_ev.id = 0;
 	v4l2_ev.type = evt_type;
 	ktime_get_ts(&v4l2_ev.timestamp);
-	v4l2_event_queue(g_server_dev.pcam_active->pvdev, &v4l2_ev);
+	v4l2_event_queue(pmctl->pcam_ptr->pvdev, &v4l2_ev);
 }
 
 static int msm_ctrl_cmd_done(void *arg)
@@ -370,7 +424,8 @@
 	ctrlcmd.vnode_id = pcam->vnode_id;
 	ctrlcmd.queue_idx = pcam->server_queue_idx;
 	ctrlcmd.stream_type = pcam->dev_inst[idx]->image_mode;
-	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
+	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[
+						pcam->server_queue_idx];
 
 	/* send command to config thread in userspace, and get return value */
 	rc = msm_server_control(&g_server_dev, &ctrlcmd);
@@ -384,15 +439,17 @@
 {
 	int rc = 0;
 	struct msm_ctrl_cmd ctrlcmd;
+	int idx = pcam->server_queue_idx;
 	D("%s qid %d\n", __func__, pcam->server_queue_idx);
 	ctrlcmd.type	   = MSM_V4L2_OPEN;
 	ctrlcmd.timeout_ms = 10000;
-	ctrlcmd.length	 = strnlen(g_server_dev.config_info.config_dev_name[0],
-				MAX_DEV_NAME_LEN)+1;
-	ctrlcmd.value    = (char *)g_server_dev.config_info.config_dev_name[0];
+	ctrlcmd.length = strnlen(
+		g_server_dev.config_info.config_dev_name[idx],
+		MAX_DEV_NAME_LEN)+1;
+	ctrlcmd.value = (char *)g_server_dev.config_info.config_dev_name[idx];
 	ctrlcmd.vnode_id = pcam->vnode_id;
 	ctrlcmd.queue_idx = pcam->server_queue_idx;
-	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
+	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[idx];
 
 	/* send command to config thread in usersspace, and get return value */
 	rc = msm_server_control(&g_server_dev, &ctrlcmd);
@@ -407,12 +464,14 @@
 	D("%s qid %d\n", __func__, pcam->server_queue_idx);
 	ctrlcmd.type	   = MSM_V4L2_CLOSE;
 	ctrlcmd.timeout_ms = 10000;
-	ctrlcmd.length	 = strnlen(g_server_dev.config_info.config_dev_name[0],
-				MAX_DEV_NAME_LEN)+1;
-	ctrlcmd.value    = (char *)g_server_dev.config_info.config_dev_name[0];
+	ctrlcmd.length	 = strnlen(g_server_dev.config_info.config_dev_name[
+				pcam->server_queue_idx], MAX_DEV_NAME_LEN)+1;
+	ctrlcmd.value    = (char *)g_server_dev.config_info.config_dev_name[
+				pcam->server_queue_idx];
 	ctrlcmd.vnode_id = pcam->vnode_id;
 	ctrlcmd.queue_idx = pcam->server_queue_idx;
-	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
+	ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[
+						pcam->server_queue_idx];
 
 	/* send command to config thread in usersspace, and get return value */
 	rc = msm_server_control(&g_server_dev, &ctrlcmd);
@@ -904,19 +963,20 @@
 		return rc;
 	}
 
-	/* The number of camera instance should be controlled by the
-		resource manager. Currently supporting one active instance
-		until multiple instances are supported */
-	if (atomic_read(&ps->number_pcam_active) > 0) {
-		pr_err("%s Cannot have more than one active camera %d\n",
+	/*
+	 * The number of camera instance should be controlled by the
+	 * resource manager. Currently supporting two active instances
+	 */
+	if (atomic_read(&ps->number_pcam_active) > 1) {
+		pr_err("%s Cannot have more than two active camera %d\n",
 			__func__, atomic_read(&ps->number_pcam_active));
 		return -EINVAL;
 	}
 	/* book keeping this camera session*/
-	ps->pcam_active = pcam;
+	ps->pcam_active[pcam->server_queue_idx] = pcam;
 	atomic_inc(&ps->number_pcam_active);
 
-	D("config pcam = 0x%p\n", ps->pcam_active);
+	D("config pcam = 0x%p\n", pcam);
 
 	/* initialization the media controller module*/
 	msm_mctl_init(pcam);
@@ -928,6 +988,7 @@
 static int msm_cam_server_close_session(struct msm_cam_server_dev *ps,
 	struct msm_cam_v4l2_device *pcam)
 {
+	int i;
 	int rc = 0;
 	D("%s\n", __func__);
 
@@ -936,10 +997,14 @@
 		return rc;
 	}
 
-
 	atomic_dec(&ps->number_pcam_active);
-	ps->pcam_active = NULL;
+	ps->pcam_active[pcam->server_queue_idx] = NULL;
 
+	for (i = 0; i < INTF_MAX; i++) {
+		if (ps->interface_map_table[i].mctl_handle ==
+			pcam->mctl_handle)
+			ps->interface_map_table[i].mctl_handle = 0;
+	}
 	msm_mctl_free(pcam);
 	return rc;
 }
@@ -1228,22 +1293,23 @@
 	mutex_unlock(&g_server_dev.server_lock);
 
 	if (g_server_dev.use_count == 0) {
+		int i;
 		mutex_lock(&g_server_dev.server_lock);
-		if (g_server_dev.pcam_active) {
-			struct msm_cam_media_controller *pmctl = NULL;
-			int rc;
+		for (i = 0; i < MAX_NUM_ACTIVE_CAMERA; i++) {
+			if (g_server_dev.pcam_active[i]) {
+				struct msm_cam_media_controller *pmctl = NULL;
 
-			pmctl = msm_cam_server_get_mctl(
-				g_server_dev.pcam_active->mctl_handle);
-			if (pmctl && pmctl->mctl_release) {
-				rc = pmctl->mctl_release(pmctl);
-				if (rc < 0)
-					pr_err("mctl_release fails %d\n", rc);
-				/*so that it isn't closed again*/
-				pmctl->mctl_release = NULL;
+				pmctl = msm_cam_server_get_mctl(
+				g_server_dev.pcam_active[i]->mctl_handle);
+				if (pmctl && pmctl->mctl_release) {
+					pmctl->mctl_release(pmctl);
+					/*so that it isn't closed again*/
+					pmctl->mctl_release = NULL;
+				}
+				msm_cam_server_send_error_evt(pmctl,
+					V4L2_EVENT_PRIVATE_START +
+					MSM_CAM_APP_NOTIFY_ERROR_EVENT);
 			}
-			msm_cam_server_send_error_evt(V4L2_EVENT_PRIVATE_START
-				+ MSM_CAM_APP_NOTIFY_ERROR_EVENT);
 		}
 		sub.type = V4L2_EVENT_ALL;
 		msm_server_v4l2_unsubscribe_event(
@@ -1433,44 +1499,94 @@
 	.vidioc_default = msm_ioctl_server,
 };
 
+static uint32_t msm_camera_server_find_mctl(
+		unsigned int notification, void *arg)
+{
+	int i;
+	uint32_t interface;
+
+	switch (notification) {
+	case NOTIFY_ISP_MSG_EVT:
+		if (((struct isp_msg_event *)arg)->msg_id ==
+			MSG_ID_RDI0_UPDATE_ACK)
+			interface = RDI_0;
+		else if (((struct isp_msg_event *)arg)->msg_id ==
+			MSG_ID_RDI1_UPDATE_ACK)
+			interface = RDI_1;
+		else
+			interface = PIX_0;
+		break;
+	case NOTIFY_VFE_MSG_OUT:
+		if (((struct isp_msg_output *)arg)->output_id ==
+					MSG_ID_OUTPUT_TERTIARY1)
+			interface = RDI_0;
+		else if (((struct isp_msg_output *)arg)->output_id ==
+						MSG_ID_OUTPUT_TERTIARY2)
+			interface = RDI_1;
+		else
+			interface = PIX_0;
+		break;
+	case NOTIFY_VFE_BUF_EVT: {
+		struct msm_vfe_resp *rp;
+		struct msm_frame_info *frame_info;
+		rp = (struct msm_vfe_resp *)arg;
+		frame_info = rp->evt_msg.data;
+		if (frame_info->path == VFE_MSG_OUTPUT_TERTIARY1)
+			interface = RDI_0;
+		else if (frame_info->path == VFE_MSG_OUTPUT_TERTIARY2)
+			interface = RDI_1;
+		else
+			interface = PIX_0;
+		}
+		break;
+	case NOTIFY_VFE_MSG_STATS:
+	case NOTIFY_VFE_MSG_COMP_STATS:
+	case NOTIFY_VFE_CAMIF_ERROR:
+	default:
+		interface = PIX_0;
+		break;
+	}
+
+	for (i = 0; i < INTF_MAX; i++) {
+		if (interface == g_server_dev.interface_map_table[i].interface)
+			break;
+	}
+	if (i == INTF_MAX) {
+		pr_err("%s: Cannot find valid interface map\n", __func__);
+		return -EINVAL;
+	} else
+		return g_server_dev.interface_map_table[i].mctl_handle;
+}
+
 static void msm_cam_server_subdev_notify(struct v4l2_subdev *sd,
 				unsigned int notification, void *arg)
 {
 	int rc = -EINVAL;
-	struct msm_sensor_ctrl_t *s_ctrl;
-	struct msm_camera_sensor_info *sinfo;
-	struct msm_camera_device_platform_data *camdev;
-	uint8_t csid_core = 0;
-	struct msm_cam_media_controller *p_mctl;
+	uint32_t mctl_handle = 0;
+	struct msm_cam_media_controller *p_mctl = NULL;
+	int is_gesture_evt =
+		(notification == NOTIFY_GESTURE_EVT)
+		|| (notification == NOTIFY_GESTURE_CAM_EVT);
 
-	if (notification == NOTIFY_PCLK_CHANGE ||
-		notification == NOTIFY_CSIPHY_CFG ||
-		notification == NOTIFY_CSID_CFG ||
-		notification == NOTIFY_CSIC_CFG) {
-		s_ctrl = get_sctrl(sd);
-		sinfo = (struct msm_camera_sensor_info *) s_ctrl->sensordata;
-		camdev = sinfo->pdata;
-		csid_core = camdev->csid_core;
-	}
-	if (notification != NOTIFY_GESTURE_CAM_EVT) {
-		p_mctl = v4l2_get_subdev_hostdata(sd);
-		if (p_mctl == NULL) {
-			pr_err("%s: cannot find mctl, %d\n",
-				__func__, notification);
+	if (!is_gesture_evt) {
+		mctl_handle = msm_camera_server_find_mctl(notification, arg);
+		if (mctl_handle < 0) {
+			pr_err("%s: Couldn't find mctl instance!\n", __func__);
 			return;
 		}
 	}
 	switch (notification) {
 	case NOTIFY_ISP_MSG_EVT:
 	case NOTIFY_VFE_MSG_OUT:
+	case NOTIFY_VFE_SOF_COUNT:
 	case NOTIFY_VFE_MSG_STATS:
 	case NOTIFY_VFE_MSG_COMP_STATS:
 	case NOTIFY_VFE_BUF_EVT:
-	case NOTIFY_VFE_BUF_FREE_EVT:
-		if (g_server_dev.isp_subdev[0] &&
-			g_server_dev.isp_subdev[0]->isp_notify
+		p_mctl = msm_cam_server_get_mctl(mctl_handle);
+		if (p_mctl->isp_sdev &&
+			p_mctl->isp_sdev->isp_notify
 			&& p_mctl->isp_sdev->sd)
-			rc = g_server_dev.isp_subdev[0]->isp_notify(
+			rc = p_mctl->isp_sdev->isp_notify(
 				p_mctl->isp_sdev->sd, notification, arg);
 		break;
 	case NOTIFY_VFE_IRQ:{
@@ -1479,15 +1595,15 @@
 		cfg_cmd.cmd_type = CMD_VFE_PROCESS_IRQ;
 		vfe_params.vfe_cfg = &cfg_cmd;
 		vfe_params.data = arg;
-		rc = v4l2_subdev_call(p_mctl->isp_sdev->sd,
+		rc = v4l2_subdev_call(sd,
 			core, ioctl, 0, &vfe_params);
 	}
 		break;
 	case NOTIFY_AXI_IRQ:
-		rc = v4l2_subdev_call(p_mctl->axi_sdev,
-			core, ioctl, VIDIOC_MSM_AXI_IRQ, arg);
+		rc = v4l2_subdev_call(sd, core, ioctl, VIDIOC_MSM_AXI_IRQ, arg);
 		break;
 	case NOTIFY_PCLK_CHANGE:
+		p_mctl = v4l2_get_subdev_hostdata(sd);
 		if (p_mctl->axi_sdev)
 			rc = v4l2_subdev_call(p_mctl->axi_sdev, video,
 			s_crystal_freq, *(uint32_t *)arg, 0);
@@ -1496,14 +1612,17 @@
 			s_crystal_freq, *(uint32_t *)arg, 0);
 		break;
 	case NOTIFY_CSIPHY_CFG:
+		p_mctl = v4l2_get_subdev_hostdata(sd);
 		rc = v4l2_subdev_call(p_mctl->csiphy_sdev,
 			core, ioctl, VIDIOC_MSM_CSIPHY_CFG, arg);
 		break;
 	case NOTIFY_CSID_CFG:
+		p_mctl = v4l2_get_subdev_hostdata(sd);
 		rc = v4l2_subdev_call(p_mctl->csid_sdev,
 			core, ioctl, VIDIOC_MSM_CSID_CFG, arg);
 		break;
 	case NOTIFY_CSIC_CFG:
+		p_mctl = v4l2_get_subdev_hostdata(sd);
 		rc = v4l2_subdev_call(p_mctl->csic_sdev,
 			core, ioctl, VIDIOC_MSM_CSIC_CFG, arg);
 		break;
@@ -1516,7 +1635,8 @@
 			core, ioctl, VIDIOC_MSM_GESTURE_CAM_EVT, arg);
 		break;
 	case NOTIFY_VFE_CAMIF_ERROR: {
-		msm_cam_server_send_error_evt(V4L2_EVENT_PRIVATE_START
+		p_mctl = msm_cam_server_get_mctl(mctl_handle);
+		msm_cam_server_send_error_evt(p_mctl, V4L2_EVENT_PRIVATE_START
 			+ MSM_CAM_APP_NOTIFY_ERROR_EVENT);
 		break;
 	}
@@ -2111,7 +2231,6 @@
 	spin_lock_init(&g_server_dev.intr_table_lock);
 	memset(&g_server_dev.irq_lkup_table, 0,
 			sizeof(struct irqmgr_intr_lkup_table));
-	g_server_dev.pcam_active = NULL;
 	g_server_dev.camera_info.num_cameras = 0;
 	atomic_set(&g_server_dev.number_pcam_active, 0);
 	g_server_dev.server_evt_id = 0;
@@ -2129,6 +2248,12 @@
 		queue->queue_active = 0;
 		msm_queue_init(&queue->ctrl_q, "control");
 		msm_queue_init(&queue->eventData_q, "eventdata");
+		g_server_dev.pcam_active[i] = NULL;
+	}
+
+	for (i = 0; i < INTF_MAX; i++) {
+		g_server_dev.interface_map_table[i].interface = 0x01 << i;
+		g_server_dev.interface_map_table[i].mctl_handle = 0;
 	}
 	return rc;
 }
@@ -2161,13 +2286,17 @@
 	int *p_active)
 {
 	int rc = 0;
+	int i = 0;
 	struct msm_cam_media_controller *pmctl = NULL;
-	D("%s: %p", __func__, g_server_dev.pcam_active);
 	*p_active = 0;
-	if (g_server_dev.pcam_active) {
-		D("%s: Active camera present return", __func__);
-		return 0;
+
+	for (i = 0; i < MAX_NUM_ACTIVE_CAMERA; i++) {
+		if (NULL != g_server_dev.pcam_active[i]) {
+			pr_info("%s: Active camera present return", __func__);
+			return 0;
+		}
 	}
+
 	rc = msm_cam_server_open_session(&g_server_dev, pcam);
 	if (rc < 0) {
 		pr_err("%s: cam_server_open_session failed %d\n",
@@ -2206,11 +2335,8 @@
 		return -ENODEV;
 	}
 
-	if (pmctl->mctl_release) {
-		rc = pmctl->mctl_release(pmctl);
-		if (rc < 0)
-			pr_err("mctl_release fails %d\n", rc);
-	}
+	if (pmctl->mctl_release)
+		pmctl->mctl_release(pmctl);
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 	kref_put(&pmctl->refcount, msm_release_ion_client);
@@ -2452,8 +2578,8 @@
 	config_cam->use_count++;
 
 	/* assume there is only one active camera possible*/
-	config_cam->p_mctl =
-		msm_cam_server_get_mctl(g_server_dev.pcam_active->mctl_handle);
+	config_cam->p_mctl = msm_cam_server_get_mctl(
+		g_server_dev.pcam_active[config_cam->dev_num]->mctl_handle);
 	if (!config_cam->p_mctl) {
 		pr_err("%s: cannot find mctl\n", __func__);
 		return -ENODEV;
@@ -2858,6 +2984,7 @@
 	msm_setup_v4l2_event_queue(
 		&config_cam->config_stat_event_queue.eventHandle,
 		config_cam->config_stat_event_queue.pvdev);
+	config_cam->dev_num = dev_num;
 
 	return rc;
 
@@ -2870,9 +2997,9 @@
 {
 	int rc = 0, i;
 	memset(&g_server_dev, 0, sizeof(struct msm_cam_server_dev));
-	/*for now just create a config 0 node
+	/*for now just create two config nodes
 	  put logic here later to know how many configs to create*/
-	g_server_dev.config_info.num_config_nodes = 1;
+	g_server_dev.config_info.num_config_nodes = 2;
 
 	rc = msm_isp_init_module(g_server_dev.config_info.num_config_nodes);
 	if (rc < 0) {
diff --git a/drivers/media/video/msm/server/msm_cam_server.h b/drivers/media/video/msm/server/msm_cam_server.h
index 270a906..ef5bb8e 100644
--- a/drivers/media/video/msm/server/msm_cam_server.h
+++ b/drivers/media/video/msm/server/msm_cam_server.h
@@ -64,4 +64,6 @@
 int msm_cam_server_request_irq(void *arg);
 int msm_cam_server_update_irqmap(
 	struct msm_cam_server_irqmap_entry *entry);
+int msm_cam_server_config_interface_map(u32 extendedmode,
+					uint32_t mctl_handle);
 #endif /* _MSM_CAM_SERVER_H */
diff --git a/drivers/media/video/msm/vfe/Makefile b/drivers/media/video/msm/vfe/Makefile
index 8068e4f..91f0e7f 100644
--- a/drivers/media/video/msm/vfe/Makefile
+++ b/drivers/media/video/msm/vfe/Makefile
@@ -16,4 +16,5 @@
 obj-$(CONFIG_ARCH_MSM_ARM11) += msm_vfe7x.o
 obj-$(CONFIG_ARCH_QSD8X50) += msm_vfe8x.o msm_vfe8x_proc.o
 obj-$(CONFIG_ARCH_MSM8960) += msm_vfe32.o
+obj-$(CONFIG_ARCH_MSM8974) += msm_vfe40.o msm_vfe40_axi.o
 obj-$(CONFIG_MSM_CAMERA_V4L2) += msm_vfe_stats_buf.o
diff --git a/drivers/media/video/msm/vfe/msm_vfe31_v4l2.c b/drivers/media/video/msm/vfe/msm_vfe31_v4l2.c
index a3037d5..0bd7b94 100644
--- a/drivers/media/video/msm/vfe/msm_vfe31_v4l2.c
+++ b/drivers/media/video/msm/vfe/msm_vfe31_v4l2.c
@@ -3830,6 +3830,10 @@
 			/* No need to decouple AXI/VFE for VFE3.1*/
 			break;
 
+		case CMD_AXI_RESET:
+			/* No need to decouple AXI/VFE for VFE3.1*/
+			break;
+
 		default:
 			pr_err("%s Unsupported AXI configuration %x ", __func__,
 				cmd->cmd_type);
diff --git a/drivers/media/video/msm/vfe/msm_vfe32.c b/drivers/media/video/msm/vfe/msm_vfe32.c
index 2f50d7f..c8d22d4 100644
--- a/drivers/media/video/msm/vfe/msm_vfe32.c
+++ b/drivers/media/video/msm/vfe/msm_vfe32.c
@@ -412,36 +412,33 @@
 	}
 }
 
-static void vfe32_stop(struct vfe32_ctrl_type *vfe32_ctrl)
+static void axi_disable_irq(struct axi_ctrl_t *axi_ctrl)
 {
-	unsigned long flags;
-
-	atomic_set(&vfe32_ctrl->share_ctrl->vstate, 0);
-
-	/* for reset hw modules, and send msg when reset_irq comes.*/
-	spin_lock_irqsave(&vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
-	vfe32_ctrl->share_ctrl->stop_ack_pending = TRUE;
-	spin_unlock_irqrestore(&vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
 
 	/* disable all interrupts.  */
 	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
 	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
 
 	/* clear all pending interrupts*/
 	msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
 	msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
 	/* Ensure the write order while writing
 	to the command register using the barrier */
 	msm_camera_io_w_mb(1,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
+}
 
+static void vfe32_stop(struct vfe32_ctrl_type *vfe32_ctrl)
+{
+
+	atomic_set(&vfe32_ctrl->share_ctrl->vstate, 0);
 	/* in either continuous or snapshot mode, stop command can be issued
 	 * at any time. stop camif immediately. */
-	msm_camera_io_w(CAMIF_COMMAND_STOP_IMMEDIATELY,
+	msm_camera_io_w(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
 		vfe32_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND);
 	vfe32_ctrl->share_ctrl->operation_mode &=
 		~(vfe32_ctrl->share_ctrl->current_mode);
@@ -561,44 +558,50 @@
 								axi_cfg, 12);
 		axi_cfg += 3;
 	}
-	/* TODO: Only reload for 1st axi config for concurrent case */
 	msm_camera_io_w(bus_cmd, axi_ctrl->share_ctrl->vfebase +
 					V32_AXI_BUS_CMD_OFF);
 	return 0;
 }
 
+static void axi_reset_internal_variables(
+	struct axi_ctrl_t *axi_ctrl)
+{
+	unsigned long flags;
+	/* state control variables */
+	axi_ctrl->share_ctrl->start_ack_pending = FALSE;
+	atomic_set(&irq_cnt, 0);
+
+	spin_lock_irqsave(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
+	axi_ctrl->share_ctrl->stop_ack_pending  = FALSE;
+	spin_unlock_irqrestore(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
+
+	init_completion(&axi_ctrl->share_ctrl->reset_complete);
+
+	spin_lock_irqsave(&axi_ctrl->share_ctrl->update_ack_lock, flags);
+	axi_ctrl->share_ctrl->update_ack_pending = FALSE;
+	spin_unlock_irqrestore(&axi_ctrl->share_ctrl->update_ack_lock, flags);
+
+	axi_ctrl->share_ctrl->recording_state = VFE_STATE_IDLE;
+	axi_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
+
+	atomic_set(&axi_ctrl->share_ctrl->vstate, 0);
+	atomic_set(&axi_ctrl->share_ctrl->rdi0_update_ack_pending, 0);
+	atomic_set(&axi_ctrl->share_ctrl->rdi1_update_ack_pending, 0);
+	atomic_set(&axi_ctrl->share_ctrl->rdi2_update_ack_pending, 0);
+
+	/* 0 for continuous mode, 1 for snapshot mode */
+	axi_ctrl->share_ctrl->operation_mode = 0;
+	axi_ctrl->share_ctrl->current_mode = 0;
+	axi_ctrl->share_ctrl->outpath.output_mode = 0;
+	axi_ctrl->share_ctrl->vfe_capture_count = 0;
+
+	/* this is unsigned 32 bit integer. */
+	axi_ctrl->share_ctrl->vfeFrameId = 0;
+}
+
 static void vfe32_reset_internal_variables(
 	struct vfe32_ctrl_type *vfe32_ctrl)
 {
-	unsigned long flags;
-	vfe32_ctrl->vfeImaskCompositePacked = 0;
-	/* state control variables */
-	vfe32_ctrl->start_ack_pending = FALSE;
-	atomic_set(&irq_cnt, 0);
-
-	spin_lock_irqsave(&vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
-	vfe32_ctrl->share_ctrl->stop_ack_pending  = FALSE;
-	spin_unlock_irqrestore(&vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
-
-	init_completion(&vfe32_ctrl->reset_complete);
-
-	spin_lock_irqsave(&vfe32_ctrl->update_ack_lock, flags);
-	vfe32_ctrl->update_ack_pending = FALSE;
-	spin_unlock_irqrestore(&vfe32_ctrl->update_ack_lock, flags);
-
-	vfe32_ctrl->recording_state = VFE_STATE_IDLE;
-	vfe32_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
-
-	atomic_set(&vfe32_ctrl->share_ctrl->vstate, 0);
-
-	/* 0 for continuous mode, 1 for snapshot mode */
-	vfe32_ctrl->share_ctrl->operation_mode = 0;
-	vfe32_ctrl->share_ctrl->current_mode = 0;
-	vfe32_ctrl->share_ctrl->outpath.output_mode = 0;
-	vfe32_ctrl->share_ctrl->vfe_capture_count = 0;
-
-	/* this is unsigned 32 bit integer. */
-	vfe32_ctrl->share_ctrl->vfeFrameId = 0;
 	/* Stats control variables. */
 	memset(&(vfe32_ctrl->afbfStatsControl), 0,
 		sizeof(struct vfe_stats_control));
@@ -682,31 +685,30 @@
 	vfe32_program_dmi_cfg(NO_MEM_SELECTED, vfe32_ctrl);
 }
 
-static int vfe32_reset(struct vfe32_ctrl_type *vfe32_ctrl)
+static int axi_reset(struct axi_ctrl_t *axi_ctrl)
 {
-	vfe32_reset_internal_variables(vfe32_ctrl);
+	axi_reset_internal_variables(axi_ctrl);
 	/* disable all interrupts.  vfeImaskLocal is also reset to 0
 	* to begin with. */
 	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
 
 	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
 
 	/* clear all pending interrupts*/
 	msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
 	msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
 
 	/* Ensure the write order while writing
 	to the command register using the barrier */
-	msm_camera_io_w_mb(1, vfe32_ctrl->share_ctrl->vfebase +
-		VFE_IRQ_CMD);
+	msm_camera_io_w_mb(1, axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
 
 	/* enable reset_ack interrupt.  */
 	msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
-	vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
 
 	/* Write to VFE_GLOBAL_RESET_CMD to reset the vfe hardware. Once reset
 	 * is done, hardware interrupt will be generated.  VFE ist processes
@@ -716,13 +718,10 @@
 	/* Ensure the write order while writing
 	to the command register using the barrier */
 	msm_camera_io_w_mb(VFE_RESET_UPON_RESET_CMD,
-		vfe32_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
+		axi_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
 
-	if (vfe32_ctrl->is_reset_blocking)
-		return wait_for_completion_interruptible(
-				&vfe32_ctrl->reset_complete);
-	else
-		return 0;
+	return wait_for_completion_interruptible(
+			&axi_ctrl->share_ctrl->reset_complete);
 }
 
 static int vfe32_operation_config(uint32_t *cmd,
@@ -1068,7 +1067,7 @@
 	uint16_t vfe_operation_mode =
 		vfe32_ctrl->share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
 			VFE_OUTPUTS_RDI1);
-	vfe32_ctrl->start_ack_pending = TRUE;
+	vfe32_ctrl->share_ctrl->start_ack_pending = TRUE;
 	CDBG("VFE opertaion mode = 0x%x, output mode = 0x%x\n",
 		vfe32_ctrl->share_ctrl->current_mode,
 		vfe32_ctrl->share_ctrl->outpath.output_mode);
@@ -1095,13 +1094,25 @@
 		irq_mask1 |= VFE_IRQ_STATUS1_RDI0_REG_UPDATE_MASK;
 		msm_camera_io_w(irq_mask1, vfe32_ctrl->share_ctrl->vfebase +
 			VFE_IRQ_MASK_1);
-		msm_camera_io_w_mb(reg_update|0x2, vfe32_ctrl->share_ctrl->
-			vfebase + VFE_REG_UPDATE_CMD);
+		if (!atomic_cmpxchg(
+			&vfe32_ctrl->share_ctrl->rdi0_update_ack_pending,
+				0, 1)) {
+			msm_camera_io_w_mb(reg_update|0x2,
+				vfe32_ctrl->share_ctrl->vfebase +
+				VFE_REG_UPDATE_CMD);
+		}
 	}
 	if (vfe32_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
 		irq_mask1 |= VFE_IRQ_STATUS1_RDI1_REG_UPDATE_MASK;
 		msm_camera_io_w(irq_mask1, vfe32_ctrl->share_ctrl->vfebase +
 			VFE_IRQ_MASK_1);
+		if (!atomic_cmpxchg(
+			&vfe32_ctrl->share_ctrl->rdi1_update_ack_pending,
+				0, 1)) {
+			msm_camera_io_w_mb(reg_update|0x4,
+			vfe32_ctrl->share_ctrl->vfebase +
+			VFE_REG_UPDATE_CMD);
+		}
 		msm_camera_io_w_mb(reg_update|0x4, vfe32_ctrl->share_ctrl->
 			vfebase + VFE_REG_UPDATE_CMD);
 	}
@@ -1122,9 +1133,7 @@
 	struct msm_cam_media_controller *pmctl,
 	struct vfe32_ctrl_type *vfe32_ctrl)
 {
-	msm_camio_bus_scale_cfg(
-		pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO);
-	vfe32_ctrl->recording_state = VFE_STATE_START_REQUESTED;
+	vfe32_ctrl->share_ctrl->recording_state = VFE_STATE_START_REQUESTED;
 	msm_camera_io_w_mb(1,
 		vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
 	return 0;
@@ -1134,11 +1143,9 @@
 	struct msm_cam_media_controller *pmctl,
 	struct vfe32_ctrl_type *vfe32_ctrl)
 {
-	vfe32_ctrl->recording_state = VFE_STATE_STOP_REQUESTED;
+	vfe32_ctrl->share_ctrl->recording_state = VFE_STATE_STOP_REQUESTED;
 	msm_camera_io_w_mb(1,
 		vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
-	msm_camio_bus_scale_cfg(
-		pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
 	return 0;
 }
 
@@ -1151,8 +1158,6 @@
 	vfe32_ctrl->share_ctrl->vfe_capture_count =
 		vfe32_ctrl->share_ctrl->outpath.out0.capture_cnt;
 
-	msm_camio_bus_scale_cfg(
-		pmctl->sdata->pdata->cam_bus_scale_table, S_LIVESHOT);
 	vfe32_ctrl->share_ctrl->liveshot_state = VFE_STATE_START_REQUESTED;
 	msm_camera_io_w_mb(1, vfe32_ctrl->
 		share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
@@ -1165,8 +1170,6 @@
 	vfe32_ctrl->share_ctrl->liveshot_state = VFE_STATE_STOP_REQUESTED;
 	msm_camera_io_w_mb(1,
 		vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
-	msm_camio_bus_scale_cfg(
-		pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO);
 }
 
 static int vfe32_zsl(
@@ -1174,8 +1177,6 @@
 	struct vfe32_ctrl_type *vfe32_ctrl)
 {
 	vfe32_start_common(vfe32_ctrl);
-	msm_camio_bus_scale_cfg(
-		pmctl->sdata->pdata->cam_bus_scale_table, S_ZSL);
 
 	msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase + 0x18C);
 	msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase + 0x188);
@@ -1188,8 +1189,6 @@
 {
 	vfe32_ctrl->share_ctrl->outpath.out0.capture_cnt = num_frames_capture;
 	vfe32_ctrl->share_ctrl->vfe_capture_count = num_frames_capture;
-	msm_camio_bus_scale_cfg(
-		pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
 	vfe32_start_common(vfe32_ctrl);
 	return 0;
 }
@@ -1217,9 +1216,6 @@
 
 	vfe32_ctrl->share_ctrl->vfe_capture_count = num_frames_capture;
 
-	msm_camio_bus_scale_cfg(
-		pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
-
 	vfe32_start_common(vfe32_ctrl);
 	/* for debug */
 	msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase + 0x18C);
@@ -1231,8 +1227,6 @@
 	struct msm_cam_media_controller *pmctl,
 	struct vfe32_ctrl_type *vfe32_ctrl)
 {
-	msm_camio_bus_scale_cfg(
-		pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
 	vfe32_start_common(vfe32_ctrl);
 	return 0;
 }
@@ -1284,9 +1278,9 @@
 		vfe32_ctrl->update_gamma = false;
 	}
 
-	spin_lock_irqsave(&vfe32_ctrl->update_ack_lock, flags);
-	vfe32_ctrl->update_ack_pending = TRUE;
-	spin_unlock_irqrestore(&vfe32_ctrl->update_ack_lock, flags);
+	spin_lock_irqsave(&vfe32_ctrl->share_ctrl->update_ack_lock, flags);
+	vfe32_ctrl->share_ctrl->update_ack_pending = TRUE;
+	spin_unlock_irqrestore(&vfe32_ctrl->share_ctrl->update_ack_lock, flags);
 	/* Ensure the write order while writing
 	to the command register using the barrier */
 	msm_camera_io_w_mb(1,
@@ -1467,53 +1461,53 @@
 		b = &outch->free_buf;
 	return b;
 }
-static int vfe32_configure_pingpong_buffers(
-	int id, int path, struct vfe32_ctrl_type *vfe32_ctrl)
+static int configure_pingpong_buffers(
+	int id, int path, struct axi_ctrl_t *axi_ctrl)
 {
 	struct vfe32_output_ch *outch = NULL;
 	int rc = 0;
 	uint32_t inst_handle = 0;
 	if (path == VFE_MSG_OUTPUT_PRIMARY)
-		inst_handle = vfe32_ctrl->share_ctrl->outpath.out0.inst_handle;
+		inst_handle = axi_ctrl->share_ctrl->outpath.out0.inst_handle;
 	else if (path == VFE_MSG_OUTPUT_SECONDARY)
-		inst_handle = vfe32_ctrl->share_ctrl->outpath.out1.inst_handle;
+		inst_handle = axi_ctrl->share_ctrl->outpath.out1.inst_handle;
 	else if (path == VFE_MSG_OUTPUT_TERTIARY1)
-		inst_handle = vfe32_ctrl->share_ctrl->outpath.out2.inst_handle;
+		inst_handle = axi_ctrl->share_ctrl->outpath.out2.inst_handle;
 	else if (path == VFE_MSG_OUTPUT_TERTIARY2)
-		inst_handle = vfe32_ctrl->share_ctrl->outpath.out3.inst_handle;
+		inst_handle = axi_ctrl->share_ctrl->outpath.out3.inst_handle;
 
 	vfe32_subdev_notify(id, path, inst_handle,
-		&vfe32_ctrl->subdev, vfe32_ctrl->share_ctrl);
-	outch = vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
+		&axi_ctrl->subdev, axi_ctrl->share_ctrl);
+	outch = vfe32_get_ch(path, axi_ctrl->share_ctrl);
 	if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) {
 		/* Configure Preview Ping Pong */
 		pr_info("%s Configure ping/pong address for %d",
 						__func__, path);
 		vfe32_put_ch_ping_addr(
-			vfe32_ctrl->share_ctrl->vfebase, outch->ch0,
+			axi_ctrl->share_ctrl->vfebase, outch->ch0,
 			outch->ping.ch_paddr[0]);
 		vfe32_put_ch_pong_addr(
-			vfe32_ctrl->share_ctrl->vfebase, outch->ch0,
+			axi_ctrl->share_ctrl->vfebase, outch->ch0,
 			outch->pong.ch_paddr[0]);
 
-		if ((vfe32_ctrl->share_ctrl->current_mode !=
+		if ((axi_ctrl->share_ctrl->current_mode !=
 			VFE_OUTPUTS_RAW) && (path != VFE_MSG_OUTPUT_TERTIARY1)
 			&& (path != VFE_MSG_OUTPUT_TERTIARY2)) {
 			vfe32_put_ch_ping_addr(
-				vfe32_ctrl->share_ctrl->vfebase, outch->ch1,
+				axi_ctrl->share_ctrl->vfebase, outch->ch1,
 				outch->ping.ch_paddr[1]);
 			vfe32_put_ch_pong_addr(
-				vfe32_ctrl->share_ctrl->vfebase, outch->ch1,
+				axi_ctrl->share_ctrl->vfebase, outch->ch1,
 				outch->pong.ch_paddr[1]);
 		}
 
 		if (outch->ping.num_planes > 2)
 			vfe32_put_ch_ping_addr(
-				vfe32_ctrl->share_ctrl->vfebase, outch->ch2,
+				axi_ctrl->share_ctrl->vfebase, outch->ch2,
 				outch->ping.ch_paddr[2]);
 		if (outch->pong.num_planes > 2)
 			vfe32_put_ch_pong_addr(
-				vfe32_ctrl->share_ctrl->vfebase, outch->ch2,
+				axi_ctrl->share_ctrl->vfebase, outch->ch2,
 				outch->pong.ch_paddr[2]);
 
 		/* avoid stale info */
@@ -1568,7 +1562,6 @@
 	uint32_t *cmdp_local = NULL;
 	uint32_t snapshot_cnt = 0;
 	uint32_t temp1 = 0, temp2 = 0;
-	uint16_t vfe_mode = 0;
 	struct msm_camera_vfe_params_t vfe_params;
 
 	CDBG("vfe32_proc_general: cmdID = %s, length = %d\n",
@@ -1577,8 +1570,7 @@
 	case VFE_CMD_RESET:
 		pr_info("vfe32_proc_general: cmdID = %s\n",
 			vfe32_general_cmd[cmd->id]);
-		vfe32_ctrl->is_reset_blocking = false;
-		vfe32_reset(vfe32_ctrl);
+		vfe32_reset_internal_variables(vfe32_ctrl);
 		break;
 	case VFE_CMD_START:
 		pr_info("vfe32_proc_general: cmdID = %s\n",
@@ -1592,42 +1584,7 @@
 
 		vfe32_ctrl->share_ctrl->current_mode =
 			vfe_params.operation_mode;
-		vfe_mode = vfe32_ctrl->share_ctrl->current_mode
-			& ~(VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI1);
-		if (vfe_mode) {
-			if ((vfe32_ctrl->share_ctrl->current_mode &
-				VFE_OUTPUTS_PREVIEW_AND_VIDEO) ||
-				(vfe32_ctrl->share_ctrl->current_mode &
-				VFE_OUTPUTS_PREVIEW))
-				/* Configure primary channel */
-				rc = vfe32_configure_pingpong_buffers(
-					VFE_MSG_START,
-					VFE_MSG_OUTPUT_PRIMARY,
-					vfe32_ctrl);
-			else
-			/* Configure secondary channel */
-				rc = vfe32_configure_pingpong_buffers(
-					VFE_MSG_START,
-					VFE_MSG_OUTPUT_SECONDARY,
-					vfe32_ctrl);
-		}
-		if (vfe32_ctrl->share_ctrl->current_mode &
-				VFE_OUTPUTS_RDI0)
-			rc = vfe32_configure_pingpong_buffers(
-				VFE_MSG_START, VFE_MSG_OUTPUT_TERTIARY1,
-				vfe32_ctrl);
-		if (vfe32_ctrl->share_ctrl->current_mode &
-				VFE_OUTPUTS_RDI1)
-			rc = vfe32_configure_pingpong_buffers(
-				VFE_MSG_START, VFE_MSG_OUTPUT_TERTIARY2,
-				vfe32_ctrl);
 
-		if (rc < 0) {
-			pr_err("%s error configuring pingpong buffers"
-				   " for preview", __func__);
-			rc = -EINVAL;
-			goto proc_general_done;
-		}
 		rc = vfe32_start(pmctl, vfe32_ctrl);
 		break;
 	case VFE_CMD_UPDATE:
@@ -1645,15 +1602,6 @@
 		snapshot_cnt = vfe_params.capture_count;
 		vfe32_ctrl->share_ctrl->current_mode =
 			vfe_params.operation_mode;
-		rc = vfe32_configure_pingpong_buffers(
-			VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_PRIMARY,
-			vfe32_ctrl);
-		if (rc < 0) {
-			pr_err("%s error configuring pingpong buffers"
-				   " for snapshot", __func__);
-			rc = -EINVAL;
-			goto proc_general_done;
-		}
 		rc = vfe32_capture_raw(pmctl, vfe32_ctrl, snapshot_cnt);
 		break;
 	case VFE_CMD_CAPTURE:
@@ -1667,78 +1615,12 @@
 		snapshot_cnt = vfe_params.capture_count;
 		vfe32_ctrl->share_ctrl->current_mode =
 			vfe_params.operation_mode;
-		if (vfe32_ctrl->share_ctrl->current_mode ==
-			VFE_OUTPUTS_JPEG_AND_THUMB ||
-		vfe32_ctrl->share_ctrl->current_mode ==
-			VFE_OUTPUTS_THUMB_AND_JPEG) {
-			if (snapshot_cnt != 1) {
-				pr_err("only support 1 inline snapshot\n");
-				rc = -EINVAL;
-				goto proc_general_done;
-			}
-			/* Configure primary channel for JPEG */
-			rc = vfe32_configure_pingpong_buffers(
-				VFE_MSG_JPEG_CAPTURE,
-				VFE_MSG_OUTPUT_PRIMARY,
-				vfe32_ctrl);
-		} else {
-			/* Configure primary channel */
-			rc = vfe32_configure_pingpong_buffers(
-				VFE_MSG_CAPTURE,
-				VFE_MSG_OUTPUT_PRIMARY,
-				vfe32_ctrl);
-		}
-		if (rc < 0) {
-			pr_err("%s error configuring pingpong buffers"
-				   " for primary output", __func__);
-			rc = -EINVAL;
-			goto proc_general_done;
-		}
-		/* Configure secondary channel */
-		rc = vfe32_configure_pingpong_buffers(
-				VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_SECONDARY,
-				vfe32_ctrl);
-		if (rc < 0) {
-			pr_err("%s error configuring pingpong buffers"
-				   " for secondary output", __func__);
-			rc = -EINVAL;
-			goto proc_general_done;
-		}
+
 		rc = vfe32_capture(pmctl, snapshot_cnt, vfe32_ctrl);
 		break;
 	case VFE_CMD_START_RECORDING:
 		pr_info("vfe32_proc_general: cmdID = %s\n",
 			vfe32_general_cmd[cmd->id]);
-		if (copy_from_user(&temp1, (void __user *)(cmd->value),
-				sizeof(uint32_t))) {
-			pr_err("%s Error copying inst_handle for recording\n",
-				__func__);
-			rc = -EFAULT;
-			goto proc_general_done;
-		}
-		if (vfe32_ctrl->share_ctrl->current_mode &
-			VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
-			vfe32_ctrl->share_ctrl->outpath.out1.inst_handle =
-				temp1;
-			rc = vfe32_configure_pingpong_buffers(
-				VFE_MSG_START_RECORDING,
-				VFE_MSG_OUTPUT_SECONDARY,
-				vfe32_ctrl);
-		} else if (vfe32_ctrl->share_ctrl->current_mode &
-			VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
-			vfe32_ctrl->share_ctrl->outpath.out0.inst_handle =
-				temp1;
-			rc = vfe32_configure_pingpong_buffers(
-				VFE_MSG_START_RECORDING,
-				VFE_MSG_OUTPUT_PRIMARY,
-				vfe32_ctrl);
-		}
-		if (rc < 0) {
-			pr_err("%s error configuring pingpong buffers"
-				" for video", __func__);
-			rc = -EINVAL;
-			goto proc_general_done;
-		}
 		rc = vfe32_start_recording(pmctl, vfe32_ctrl);
 		break;
 	case VFE_CMD_STOP_RECORDING:
@@ -2280,23 +2162,7 @@
 		break;
 
 	case VFE_CMD_LIVESHOT:
-		if (copy_from_user(&temp1, (void __user *)(cmd->value),
-				sizeof(uint32_t))) {
-			pr_err("%s Error copying inst_handle for liveshot ",
-				__func__);
-			rc = -EFAULT;
-			goto proc_general_done;
-		}
-		vfe32_ctrl->share_ctrl->outpath.out0.inst_handle = temp1;
 		/* Configure primary channel */
-		rc = vfe32_configure_pingpong_buffers(VFE_MSG_CAPTURE,
-					VFE_MSG_OUTPUT_PRIMARY, vfe32_ctrl);
-		if (rc < 0) {
-			pr_err("%s error configuring pingpong buffers"
-				   " for primary output", __func__);
-			rc = -EINVAL;
-			goto proc_general_done;
-		}
 		vfe32_start_liveshot(pmctl, vfe32_ctrl);
 		break;
 
@@ -2838,14 +2704,6 @@
 
 		vfe32_ctrl->share_ctrl->current_mode =
 			vfe_params.operation_mode;
-		rc = vfe32_configure_pingpong_buffers(VFE_MSG_START,
-			VFE_MSG_OUTPUT_PRIMARY, vfe32_ctrl);
-		if (rc < 0)
-			goto proc_general_done;
-		rc = vfe32_configure_pingpong_buffers(VFE_MSG_START,
-			VFE_MSG_OUTPUT_SECONDARY, vfe32_ctrl);
-		if (rc < 0)
-			goto proc_general_done;
 
 		rc = vfe32_zsl(pmctl, vfe32_ctrl);
 		break;
@@ -3110,12 +2968,6 @@
 		CDBG("%s Stopping liveshot ", __func__);
 		vfe32_stop_liveshot(pmctl, vfe32_ctrl);
 		break;
-	case VFE_CMD_RESET_2:
-		CDBG("vfe32_proc_general: cmdID = %s\n",
-			vfe32_general_cmd[cmd->id]);
-		vfe32_ctrl->is_reset_blocking = true;
-		vfe32_reset(vfe32_ctrl);
-		break;
 	default:
 		if (cmd->length != vfe32_cmd[cmd->id].length)
 			return -EINVAL;
@@ -3179,7 +3031,8 @@
 {
 	unsigned long flags;
 
-	if (vfe32_ctrl->recording_state == VFE_STATE_START_REQUESTED) {
+	if (vfe32_ctrl->share_ctrl->recording_state ==
+				VFE_STATE_START_REQUESTED) {
 		if (vfe32_ctrl->share_ctrl->operation_mode &
 				VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
 			msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
@@ -3197,11 +3050,11 @@
 				vfe32_AXI_WM_CFG[vfe32_ctrl->
 				share_ctrl->outpath.out1.ch1]);
 		}
-		vfe32_ctrl->recording_state = VFE_STATE_STARTED;
+		vfe32_ctrl->share_ctrl->recording_state = VFE_STATE_STARTED;
 		msm_camera_io_w_mb(1,
 			vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
 		CDBG("start video triggered .\n");
-	} else if (vfe32_ctrl->recording_state ==
+	} else if (vfe32_ctrl->share_ctrl->recording_state ==
 			VFE_STATE_STOP_REQUESTED) {
 		if (vfe32_ctrl->share_ctrl->operation_mode &
 				VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
@@ -3223,40 +3076,47 @@
 		CDBG("stop video triggered .\n");
 	}
 
-	spin_lock_irqsave(&vfe32_ctrl->start_ack_lock, flags);
-	if (vfe32_ctrl->start_ack_pending == TRUE) {
-		vfe32_ctrl->start_ack_pending = FALSE;
-		spin_unlock_irqrestore(&vfe32_ctrl->start_ack_lock, flags);
+	spin_lock_irqsave(&vfe32_ctrl->share_ctrl->start_ack_lock, flags);
+	if (vfe32_ctrl->share_ctrl->start_ack_pending == TRUE) {
+		vfe32_ctrl->share_ctrl->start_ack_pending = FALSE;
+		spin_unlock_irqrestore(
+			&vfe32_ctrl->share_ctrl->start_ack_lock, flags);
 		vfe32_send_isp_msg(&vfe32_ctrl->subdev,
 			vfe32_ctrl->share_ctrl->vfeFrameId, MSG_ID_START_ACK);
 	} else {
-		spin_unlock_irqrestore(&vfe32_ctrl->start_ack_lock, flags);
-		if (vfe32_ctrl->recording_state ==
+		spin_unlock_irqrestore(
+			&vfe32_ctrl->share_ctrl->start_ack_lock, flags);
+		if (vfe32_ctrl->share_ctrl->recording_state ==
 				VFE_STATE_STOP_REQUESTED) {
-			vfe32_ctrl->recording_state = VFE_STATE_STOPPED;
+			vfe32_ctrl->share_ctrl->recording_state =
+						VFE_STATE_STOPPED;
 			/* request a reg update and send STOP_REC_ACK
 			 * when we process the next reg update irq.
 			 */
 			msm_camera_io_w_mb(1,
 			vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
-		} else if (vfe32_ctrl->recording_state ==
+		} else if (vfe32_ctrl->share_ctrl->recording_state ==
 					VFE_STATE_STOPPED) {
 			vfe32_send_isp_msg(&vfe32_ctrl->subdev,
 				vfe32_ctrl->share_ctrl->vfeFrameId,
 				MSG_ID_STOP_REC_ACK);
-			vfe32_ctrl->recording_state = VFE_STATE_IDLE;
+			vfe32_ctrl->share_ctrl->recording_state =
+						VFE_STATE_IDLE;
 		}
-		spin_lock_irqsave(&vfe32_ctrl->update_ack_lock, flags);
-		if (vfe32_ctrl->update_ack_pending == TRUE) {
-			vfe32_ctrl->update_ack_pending = FALSE;
+		spin_lock_irqsave(
+			&vfe32_ctrl->share_ctrl->update_ack_lock, flags);
+		if (vfe32_ctrl->share_ctrl->update_ack_pending == TRUE) {
+			vfe32_ctrl->share_ctrl->update_ack_pending = FALSE;
 			spin_unlock_irqrestore(
-				&vfe32_ctrl->update_ack_lock, flags);
+				&vfe32_ctrl->share_ctrl->update_ack_lock,
+								flags);
 			vfe32_send_isp_msg(&vfe32_ctrl->subdev,
 				vfe32_ctrl->share_ctrl->vfeFrameId,
 				MSG_ID_UPDATE_ACK);
 		} else {
 			spin_unlock_irqrestore(
-				&vfe32_ctrl->update_ack_lock, flags);
+				&vfe32_ctrl->share_ctrl->update_ack_lock,
+								flags);
 		}
 	}
 
@@ -3376,34 +3236,22 @@
 static void vfe32_process_rdi0_reg_update_irq(
 	struct vfe32_ctrl_type *vfe32_ctrl)
 {
-	unsigned long flags;
-	spin_lock_irqsave(&vfe32_ctrl->start_ack_lock, flags);
-	if (vfe32_ctrl->start_ack_pending == TRUE) {
-		vfe32_ctrl->start_ack_pending = FALSE;
-		spin_unlock_irqrestore(
-				&vfe32_ctrl->start_ack_lock, flags);
+	if (atomic_cmpxchg(
+		&vfe32_ctrl->share_ctrl->rdi0_update_ack_pending, 1, 0)) {
 		vfe32_send_isp_msg(&vfe32_ctrl->subdev,
-			vfe32_ctrl->share_ctrl->vfeFrameId, MSG_ID_START_ACK);
-	} else {
-		spin_unlock_irqrestore(
-				&vfe32_ctrl->start_ack_lock, flags);
+			vfe32_ctrl->share_ctrl->vfeFrameId,
+			MSG_ID_RDI0_UPDATE_ACK);
 	}
 }
 
 static void vfe32_process_rdi1_reg_update_irq(
 	struct vfe32_ctrl_type *vfe32_ctrl)
 {
-	unsigned long flags;
-	spin_lock_irqsave(&vfe32_ctrl->start_ack_lock, flags);
-	if (vfe32_ctrl->start_ack_pending == TRUE) {
-		vfe32_ctrl->start_ack_pending = FALSE;
-		spin_unlock_irqrestore(
-				&vfe32_ctrl->start_ack_lock, flags);
+	if (atomic_cmpxchg(
+		&vfe32_ctrl->share_ctrl->rdi1_update_ack_pending, 1, 0)) {
 		vfe32_send_isp_msg(&vfe32_ctrl->subdev,
-			vfe32_ctrl->share_ctrl->vfeFrameId, MSG_ID_START_ACK);
-	} else {
-		spin_unlock_irqrestore(
-				&vfe32_ctrl->start_ack_lock, flags);
+			vfe32_ctrl->share_ctrl->vfeFrameId,
+			MSG_ID_RDI1_UPDATE_ACK);
 	}
 }
 
@@ -3509,12 +3357,7 @@
 		/* reload all write masters. (frame & line)*/
 		msm_camera_io_w(0x7FFF,
 			vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
-		if (vfe32_ctrl->is_reset_blocking)
-			complete(&vfe32_ctrl->reset_complete);
-		else
-			vfe32_send_isp_msg(&vfe32_ctrl->subdev,
-				vfe32_ctrl->share_ctrl->vfeFrameId,
-				MSG_ID_RESET_ACK);
+		complete(&vfe32_ctrl->share_ctrl->reset_complete);
 	}
 }
 
@@ -3523,11 +3366,11 @@
 {
 	if (vfe32_ctrl->share_ctrl->operation_mode &
 		VFE_OUTPUTS_RAW) {
-		if (vfe32_ctrl->start_ack_pending) {
+		if (vfe32_ctrl->share_ctrl->start_ack_pending) {
 			vfe32_send_isp_msg(&vfe32_ctrl->subdev,
 				vfe32_ctrl->share_ctrl->vfeFrameId,
 				MSG_ID_START_ACK);
-			vfe32_ctrl->start_ack_pending = FALSE;
+			vfe32_ctrl->share_ctrl->start_ack_pending = FALSE;
 		}
 		vfe32_ctrl->share_ctrl->vfe_capture_count--;
 		/* if last frame to be captured: */
@@ -3543,11 +3386,14 @@
 			VFE_MODE_OF_OPERATION_VIDEO) &&
 		(vfe32_ctrl->share_ctrl->vfeFrameId %
 			vfe32_ctrl->hfr_mode != 0)) {
-		vfe32_ctrl->share_ctrl->vfeFrameId++;
+		if (vfe32_ctrl->vfe_sof_count_enable)
+			vfe32_ctrl->share_ctrl->vfeFrameId++;
 		CDBG("Skip the SOF notification when HFR enabled\n");
 		return;
 	}
-	vfe32_ctrl->share_ctrl->vfeFrameId++;
+	if (vfe32_ctrl->vfe_sof_count_enable)
+		vfe32_ctrl->share_ctrl->vfeFrameId++;
+
 	vfe32_send_isp_msg(&vfe32_ctrl->subdev,
 		vfe32_ctrl->share_ctrl->vfeFrameId, MSG_ID_SOF_ACK);
 	CDBG("camif_sof_irq, frameId = %d\n",
@@ -4373,7 +4219,6 @@
 	struct vfe32_ctrl_type *vfe32_ctrl, uint32_t irqstatus)
 {
 	uint32_t status_bits = VFE_COM_STATUS & irqstatus;
-
 	if ((vfe32_ctrl->hfr_mode != HFR_MODE_OFF) &&
 		(vfe32_ctrl->share_ctrl->vfeFrameId %
 		 vfe32_ctrl->hfr_mode != 0)) {
@@ -4514,7 +4359,7 @@
 				VFE_IRQ_STATUS0_CAMIF_SOF_MASK) {
 			if (stat_interrupt)
 				vfe32_ctrl->simultaneous_sof_stat = 1;
-			v4l2_subdev_notify(&axi_ctrl->subdev,
+			v4l2_subdev_notify(&vfe32_ctrl->subdev,
 				NOTIFY_VFE_IRQ,
 				(void *)VFE_IRQ_STATUS0_CAMIF_SOF_MASK);
 		}
@@ -4522,28 +4367,33 @@
 		/* interrupt to be processed,  *qcmd has the payload.  */
 		if (qcmd->vfeInterruptStatus0 &
 				VFE_IRQ_STATUS0_REG_UPDATE_MASK)
-			v4l2_subdev_notify(&axi_ctrl->subdev,
+			v4l2_subdev_notify(&vfe32_ctrl->subdev,
 				NOTIFY_VFE_IRQ,
 				(void *)VFE_IRQ_STATUS0_REG_UPDATE_MASK);
 
 		if (qcmd->vfeInterruptStatus1 &
 				VFE_IRQ_STATUS1_RDI0_REG_UPDATE_MASK)
-			v4l2_subdev_notify(&axi_ctrl->subdev,
+			v4l2_subdev_notify(&vfe32_ctrl->subdev,
 				NOTIFY_VFE_IRQ,
 				(void *)VFE_IRQ_STATUS1_RDI0_REG_UPDATE);
 
 		if (qcmd->vfeInterruptStatus1 &
 				VFE_IRQ_STATUS1_RDI1_REG_UPDATE_MASK)
-			v4l2_subdev_notify(&axi_ctrl->subdev,
+			v4l2_subdev_notify(&vfe32_ctrl->subdev,
 				NOTIFY_VFE_IRQ,
 				(void *)VFE_IRQ_STATUS1_RDI1_REG_UPDATE);
 
 		if (qcmd->vfeInterruptStatus1 &
 				VFE_IMASK_WHILE_STOPPING_1)
-			v4l2_subdev_notify(&axi_ctrl->subdev,
+			v4l2_subdev_notify(&vfe32_ctrl->subdev,
 				NOTIFY_VFE_IRQ,
 				(void *)VFE_IMASK_WHILE_STOPPING_1);
 
+		if (atomic_read(&axi_ctrl->share_ctrl->handle_axi_irq))
+			v4l2_subdev_notify(&axi_ctrl->subdev,
+				NOTIFY_AXI_IRQ,
+				(void *)qcmd->vfeInterruptStatus0);
+
 		if (atomic_read(&axi_ctrl->share_ctrl->vstate)) {
 			if (qcmd->vfeInterruptStatus1 &
 					VFE32_IMASK_ERROR_ONLY_1) {
@@ -4553,9 +4403,6 @@
 					qcmd->vfeInterruptStatus1 &
 					VFE32_IMASK_ERROR_ONLY_1);
 			}
-			v4l2_subdev_notify(&axi_ctrl->subdev,
-				NOTIFY_AXI_IRQ,
-				(void *)qcmd->vfeInterruptStatus0);
 
 			/* then process stats irq. */
 			if (axi_ctrl->share_ctrl->stats_comp) {
@@ -4563,7 +4410,7 @@
 				if (qcmd->vfeInterruptStatus0 &
 					VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK) {
 					CDBG("Stats composite irq occured.\n");
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)qcmd->vfeInterruptStatus0);
 				}
@@ -4571,60 +4418,60 @@
 				/* process individual stats interrupt. */
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_AEC_BG)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_STATS_AEC_BG);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_AWB)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_STATS_AWB);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_AF_BF)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_STATS_AF_BF);
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_SK_BHIST)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_STATS_SK_BHIST);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_IHIST)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_STATS_IHIST);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_RS)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_STATS_RS);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_CS)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_STATS_CS);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_SYNC_TIMER0)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_SYNC_TIMER0);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_SYNC_TIMER1)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_SYNC_TIMER1);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_SYNC_TIMER2)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_SYNC_TIMER2);
 			}
@@ -4845,7 +4692,9 @@
 		cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE &&
 		cmd->cmd_type != CMD_STATS_BG_BUF_RELEASE &&
 		cmd->cmd_type != CMD_STATS_BF_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_BHIST_BUF_RELEASE) {
+		cmd->cmd_type != CMD_STATS_BHIST_BUF_RELEASE &&
+		cmd->cmd_type != CMD_VFE_SOF_COUNT_UPDATE &&
+		cmd->cmd_type != CMD_VFE_COUNT_SOF_ENABLE) {
 			if (copy_from_user(&vfecmd,
 					(void __user *)(cmd->value),
 					sizeof(vfecmd))) {
@@ -4925,6 +4774,19 @@
 	case CMD_GENERAL:
 		rc = vfe32_proc_general(pmctl, &vfecmd, vfe32_ctrl);
 	break;
+	case CMD_VFE_COUNT_SOF_ENABLE: {
+		int enable = *((int *)cmd->value);
+		if (enable)
+			vfe32_ctrl->vfe_sof_count_enable = TRUE;
+		else
+			vfe32_ctrl->vfe_sof_count_enable = false;
+	}
+	break;
+	case CMD_VFE_SOF_COUNT_UPDATE:
+		if (!vfe32_ctrl->vfe_sof_count_enable)
+			vfe32_ctrl->share_ctrl->vfeFrameId =
+			*((uint32_t *)vfe_params->data);
+	break;
 	case CMD_CONFIG_PING_ADDR: {
 		int path = *((int *)cmd->value);
 		struct vfe32_output_ch *outch =
@@ -5071,16 +4933,17 @@
 		(struct vfe32_ctrl_type *)v4l2_get_subdevdata(sd);
 
 	spin_lock_init(&vfe32_ctrl->share_ctrl->stop_flag_lock);
+	spin_lock_init(&vfe32_ctrl->share_ctrl->abort_lock);
 	spin_lock_init(&vfe32_ctrl->state_lock);
-	spin_lock_init(&vfe32_ctrl->io_lock);
-	spin_lock_init(&vfe32_ctrl->update_ack_lock);
-	spin_lock_init(&vfe32_ctrl->start_ack_lock);
+	spin_lock_init(&vfe32_ctrl->share_ctrl->update_ack_lock);
+	spin_lock_init(&vfe32_ctrl->share_ctrl->start_ack_lock);
 	spin_lock_init(&vfe32_ctrl->stats_bufq_lock);
 
 	vfe32_ctrl->update_linear = false;
 	vfe32_ctrl->update_rolloff = false;
 	vfe32_ctrl->update_la = false;
 	vfe32_ctrl->update_gamma = false;
+	vfe32_ctrl->vfe_sof_count_enable = false;
 	vfe32_ctrl->hfr_mode = HFR_MODE_OFF;
 
 	memset(&vfe32_ctrl->stats_ctrl, 0, sizeof(struct msm_stats_bufq_ctrl));
@@ -5125,9 +4988,216 @@
 		vfe32_ctrl->share_ctrl->vfebase = NULL;
 }
 
-void axi_start(struct axi_ctrl_t *axi_ctrl, uint16_t cmd_type)
+void axi_abort(struct axi_ctrl_t *axi_ctrl)
+{
+	uint8_t  axi_busy_flag = true;
+	/* axi halt command. */
+	msm_camera_io_w(AXI_HALT,
+		axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD);
+	wmb();
+	while (axi_busy_flag) {
+		if (msm_camera_io_r(
+			axi_ctrl->share_ctrl->vfebase + VFE_AXI_STATUS) & 0x1)
+			axi_busy_flag = false;
+	}
+	/* Ensure the write order while writing
+	* to the command register using the barrier */
+	msm_camera_io_w_mb(AXI_HALT_CLEAR,
+		axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD);
+
+	/* after axi halt, then ok to apply global reset.
+	* enable reset_ack and async timer interrupt only while
+	* stopping the pipeline.*/
+	msm_camera_io_w(0xf0000000,
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+	msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	/* Ensure the write order while writing
+	* to the command register using the barrier */
+	msm_camera_io_w_mb(VFE_RESET_UPON_STOP_CMD,
+		axi_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
+}
+
+int axi_config_buffers(struct axi_ctrl_t *axi_ctrl,
+	struct msm_camera_vfe_params_t vfe_params)
+{
+	uint16_t vfe_mode = axi_ctrl->share_ctrl->current_mode
+			& ~(VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI1);
+	int rc = 0;
+	switch (vfe_params.cmd_type) {
+	case AXI_CMD_PREVIEW:
+		if (vfe_mode) {
+			if ((axi_ctrl->share_ctrl->current_mode &
+				VFE_OUTPUTS_PREVIEW_AND_VIDEO) ||
+				(axi_ctrl->share_ctrl->current_mode &
+				VFE_OUTPUTS_PREVIEW))
+				/* Configure primary channel */
+				rc = configure_pingpong_buffers(
+					VFE_MSG_START,
+					VFE_MSG_OUTPUT_PRIMARY,
+					axi_ctrl);
+			else
+			/* Configure secondary channel */
+				rc = configure_pingpong_buffers(
+					VFE_MSG_START,
+					VFE_MSG_OUTPUT_SECONDARY,
+					axi_ctrl);
+		}
+		if (axi_ctrl->share_ctrl->current_mode &
+				VFE_OUTPUTS_RDI0)
+			rc = configure_pingpong_buffers(
+				VFE_MSG_START, VFE_MSG_OUTPUT_TERTIARY1,
+				axi_ctrl);
+		if (axi_ctrl->share_ctrl->current_mode &
+				VFE_OUTPUTS_RDI1)
+			rc = configure_pingpong_buffers(
+				VFE_MSG_START, VFE_MSG_OUTPUT_TERTIARY2,
+				axi_ctrl);
+
+		if (rc < 0) {
+			pr_err("%s error configuring pingpong buffers for preview",
+				__func__);
+			rc = -EINVAL;
+			goto config_done;
+		}
+		break;
+	case AXI_CMD_RAW_CAPTURE:
+		rc = configure_pingpong_buffers(
+			VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_PRIMARY,
+			axi_ctrl);
+		if (rc < 0) {
+			pr_err("%s error configuring pingpong buffers for snapshot",
+				__func__);
+			rc = -EINVAL;
+			goto config_done;
+		}
+		break;
+	case AXI_CMD_ZSL:
+		rc = configure_pingpong_buffers(VFE_MSG_START,
+			VFE_MSG_OUTPUT_PRIMARY, axi_ctrl);
+		if (rc < 0)
+			goto config_done;
+		rc = configure_pingpong_buffers(VFE_MSG_START,
+			VFE_MSG_OUTPUT_SECONDARY, axi_ctrl);
+		if (rc < 0)
+			goto config_done;
+		break;
+	case AXI_CMD_RECORD:
+		if (axi_ctrl->share_ctrl->current_mode &
+			VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
+			axi_ctrl->share_ctrl->outpath.out1.inst_handle =
+				vfe_params.inst_handle;
+			rc = configure_pingpong_buffers(
+				VFE_MSG_START_RECORDING,
+				VFE_MSG_OUTPUT_SECONDARY,
+				axi_ctrl);
+		} else if (axi_ctrl->share_ctrl->current_mode &
+			VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
+			axi_ctrl->share_ctrl->outpath.out0.inst_handle =
+				vfe_params.inst_handle;
+			rc = configure_pingpong_buffers(
+				VFE_MSG_START_RECORDING,
+				VFE_MSG_OUTPUT_PRIMARY,
+				axi_ctrl);
+		}
+		if (rc < 0) {
+			pr_err("%s error configuring pingpong buffers for video",
+				__func__);
+			rc = -EINVAL;
+			goto config_done;
+		}
+		break;
+	case AXI_CMD_LIVESHOT:
+		axi_ctrl->share_ctrl->outpath.out0.inst_handle =
+			vfe_params.inst_handle;
+		rc = configure_pingpong_buffers(VFE_MSG_CAPTURE,
+					VFE_MSG_OUTPUT_PRIMARY, axi_ctrl);
+		if (rc < 0) {
+			pr_err("%s error configuring pingpong buffers for primary output",
+				__func__);
+			rc = -EINVAL;
+			goto config_done;
+		}
+		break;
+	case AXI_CMD_CAPTURE:
+		if (axi_ctrl->share_ctrl->current_mode ==
+			VFE_OUTPUTS_JPEG_AND_THUMB ||
+		axi_ctrl->share_ctrl->current_mode ==
+			VFE_OUTPUTS_THUMB_AND_JPEG) {
+
+			/* Configure primary channel for JPEG */
+			rc = configure_pingpong_buffers(
+				VFE_MSG_JPEG_CAPTURE,
+				VFE_MSG_OUTPUT_PRIMARY,
+				axi_ctrl);
+		} else {
+			/* Configure primary channel */
+			rc = configure_pingpong_buffers(
+				VFE_MSG_CAPTURE,
+				VFE_MSG_OUTPUT_PRIMARY,
+				axi_ctrl);
+		}
+		if (rc < 0) {
+			pr_err("%s error configuring pingpong buffers for primary output",
+				__func__);
+			rc = -EINVAL;
+			goto config_done;
+		}
+		/* Configure secondary channel */
+		rc = configure_pingpong_buffers(
+				VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_SECONDARY,
+				axi_ctrl);
+		if (rc < 0) {
+			pr_err("%s error configuring pingpong buffers for secondary output",
+				__func__);
+			rc = -EINVAL;
+			goto config_done;
+		}
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+
+	}
+config_done:
+	return rc;
+}
+
+void axi_start(struct msm_cam_media_controller *pmctl,
+	struct axi_ctrl_t *axi_ctrl, struct msm_camera_vfe_params_t vfe_params)
 {
 	uint32_t irq_comp_mask = 0, irq_mask = 0;
+	int rc = 0;
+	rc = axi_config_buffers(axi_ctrl, vfe_params);
+	if (rc < 0)
+		return;
+
+	switch (vfe_params.cmd_type) {
+	case AXI_CMD_PREVIEW:
+		msm_camio_bus_scale_cfg(
+		pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+		break;
+	case AXI_CMD_CAPTURE:
+	case AXI_CMD_RAW_CAPTURE:
+		msm_camio_bus_scale_cfg(
+		pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
+		break;
+	case AXI_CMD_RECORD:
+		msm_camio_bus_scale_cfg(
+		pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO);
+		return;
+	case AXI_CMD_ZSL:
+		msm_camio_bus_scale_cfg(
+		pmctl->sdata->pdata->cam_bus_scale_table, S_ZSL);
+		break;
+	case AXI_CMD_LIVESHOT:
+		msm_camio_bus_scale_cfg(
+		pmctl->sdata->pdata->cam_bus_scale_table, S_LIVESHOT);
+		return;
+	default:
+		return;
+	}
 
 	irq_comp_mask =
 		msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
@@ -5179,7 +5249,7 @@
 	msm_camera_io_w(irq_comp_mask,
 		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
 
-	switch (cmd_type) {
+	switch (vfe_params.cmd_type) {
 	case AXI_CMD_PREVIEW: {
 		uint16_t operation_mode =
 		(axi_ctrl->share_ctrl->operation_mode &
@@ -5286,37 +5356,160 @@
 		msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
 			vfe32_AXI_WM_CFG[axi_ctrl->share_ctrl->
 			outpath.out3.ch0]);
+	atomic_set(&axi_ctrl->share_ctrl->handle_axi_irq, 1);
 }
 
-void axi_stop(struct axi_ctrl_t *axi_ctrl, uint16_t cmd_type)
+void axi_stop(struct msm_cam_media_controller *pmctl,
+	struct axi_ctrl_t *axi_ctrl, struct msm_camera_vfe_params_t vfe_params)
 {
-	uint8_t  axiBusyFlag = true;
-	/* axi halt command. */
-	msm_camera_io_w(AXI_HALT,
-		axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD);
-	wmb();
-	while (axiBusyFlag) {
-		if (msm_camera_io_r(
-			axi_ctrl->share_ctrl->vfebase + VFE_AXI_STATUS) & 0x1)
-			axiBusyFlag = false;
+	uint32_t reg_update = 0;
+	unsigned long flags;
+	uint32_t operation_mode =
+	axi_ctrl->share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+		VFE_OUTPUTS_RDI1);
+
+	switch (vfe_params.cmd_type) {
+	case AXI_CMD_PREVIEW:
+	case AXI_CMD_CAPTURE:
+	case AXI_CMD_RAW_CAPTURE:
+	case AXI_CMD_ZSL:
+		break;
+	case AXI_CMD_RECORD:
+		msm_camio_bus_scale_cfg(
+		pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+		return;
+	case AXI_CMD_LIVESHOT:
+		msm_camio_bus_scale_cfg(
+		pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO);
+		return;
+	default:
+		return;
 	}
-	/* Ensure the write order while writing
-	to the command register using the barrier */
-	msm_camera_io_w_mb(AXI_HALT_CLEAR,
-		axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD);
 
-	/* after axi halt, then ok to apply global reset. */
-	/* enable reset_ack and async timer interrupt only while
-	stopping the pipeline.*/
-	msm_camera_io_w(0xf0000000,
-		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
-	msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
-		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+	if (!axi_ctrl->share_ctrl->skip_abort) {
+		atomic_set(&axi_ctrl->share_ctrl->handle_axi_irq, 0);
+		axi_disable_irq(axi_ctrl);
+	}
 
-	/* Ensure the write order while writing
-	to the command register using the barrier */
-	msm_camera_io_w_mb(VFE_RESET_UPON_STOP_CMD,
-		axi_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
+	spin_lock_irqsave(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
+	axi_ctrl->share_ctrl->stop_ack_pending  = TRUE;
+	spin_unlock_irqrestore(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
+	switch (vfe_params.cmd_type) {
+	case AXI_CMD_PREVIEW: {
+		switch (operation_mode) {
+		case VFE_OUTPUTS_PREVIEW:
+		case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
+			if (axi_ctrl->share_ctrl->outpath.output_mode &
+				VFE32_OUTPUT_MODE_PRIMARY) {
+				msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out0.ch0]);
+				msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out0.ch1]);
+			} else if (axi_ctrl->share_ctrl->outpath.output_mode &
+					VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+				msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out0.ch0]);
+				msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out0.ch1]);
+				msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out0.ch2]);
+			}
+			break;
+		default:
+			if (axi_ctrl->share_ctrl->outpath.output_mode &
+				VFE32_OUTPUT_MODE_SECONDARY) {
+				msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out1.ch0]);
+				msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out1.ch1]);
+			} else if (axi_ctrl->share_ctrl->outpath.output_mode &
+				VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+				msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out1.ch0]);
+				msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out1.ch1]);
+				msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
+					+ vfe32_AXI_WM_CFG[axi_ctrl->
+					share_ctrl->outpath.out1.ch2]);
+			}
+			break;
+			}
+		}
+		break;
+	default:
+		if (axi_ctrl->share_ctrl->outpath.output_mode &
+			VFE32_OUTPUT_MODE_PRIMARY) {
+			msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out0.ch0]);
+			msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out0.ch1]);
+		} else if (axi_ctrl->share_ctrl->outpath.output_mode &
+				VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+			msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out0.ch0]);
+			msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out0.ch1]);
+			msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out0.ch2]);
+		}
+
+		if (axi_ctrl->share_ctrl->outpath.output_mode &
+			VFE32_OUTPUT_MODE_SECONDARY) {
+			msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out1.ch0]);
+			msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out1.ch1]);
+		} else if (axi_ctrl->share_ctrl->outpath.output_mode &
+			VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+			msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out1.ch0]);
+			msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out1.ch1]);
+			msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+				vfe32_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out1.ch2]);
+		}
+		break;
+	}
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0)
+		msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+			vfe32_AXI_WM_CFG[axi_ctrl->share_ctrl->
+			outpath.out2.ch0]);
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1)
+		msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
+			vfe32_AXI_WM_CFG[axi_ctrl->share_ctrl->
+			outpath.out3.ch0]);
+
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0)
+		reg_update |= 0x2;
+	if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1)
+		reg_update |= 0x4;
+
+	if (operation_mode)
+		reg_update |= 0x1;
+	msm_camera_io_w_mb(reg_update,
+		axi_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+	if (!axi_ctrl->share_ctrl->skip_abort)
+		axi_abort(axi_ctrl);
+
 }
 
 static int msm_axi_config(struct v4l2_subdev *sd, void __user *arg)
@@ -5324,7 +5517,10 @@
 	struct msm_vfe_cfg_cmd cfgcmd;
 	struct msm_isp_cmd vfecmd;
 	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+	struct msm_cam_media_controller *pmctl =
+		(struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
 	int rc = 0, vfe_cmd_type = 0, rdi_mode = 0;
+	unsigned long flags;
 
 	if (!axi_ctrl->share_ctrl->vfebase) {
 		pr_err("%s: base address unmapped\n", __func__);
@@ -5520,7 +5716,12 @@
 		}
 		axi_ctrl->share_ctrl->current_mode =
 			vfe_params.operation_mode;
-		axi_start(axi_ctrl, vfe_params.cmd_type);
+		spin_lock_irqsave(&axi_ctrl->share_ctrl->abort_lock, flags);
+		axi_ctrl->share_ctrl->skip_abort =
+			vfe_params.skip_abort;
+		spin_unlock_irqrestore(&axi_ctrl->share_ctrl->abort_lock,
+			flags);
+		axi_start(pmctl, axi_ctrl, vfe_params);
 		}
 		break;
 	case CMD_AXI_STOP: {
@@ -5532,9 +5733,17 @@
 		}
 		axi_ctrl->share_ctrl->current_mode =
 			vfe_params.operation_mode;
-		axi_stop(axi_ctrl, vfe_params.cmd_type);
+		spin_lock_irqsave(&axi_ctrl->share_ctrl->abort_lock, flags);
+		axi_ctrl->share_ctrl->skip_abort =
+			vfe_params.skip_abort;
+		spin_unlock_irqrestore(&axi_ctrl->share_ctrl->abort_lock,
+			flags);
+		axi_stop(pmctl, axi_ctrl, vfe_params);
 		}
 		break;
+	case CMD_AXI_RESET:
+		axi_reset(axi_ctrl);
+		break;
 	default:
 		pr_err("%s Unsupported AXI configuration %x ", __func__,
 			cfgcmd.cmd_type);
@@ -5547,6 +5756,7 @@
 {
 	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
 	uint32_t irqstatus = (uint32_t) arg;
+	unsigned long flags;
 
 	if (!axi_ctrl->share_ctrl->vfebase) {
 		pr_err("%s: base address unmapped\n", __func__);
@@ -5595,6 +5805,17 @@
 				CAMIF_COMMAND_STOP_IMMEDIATELY,
 				axi_ctrl->share_ctrl->vfebase +
 				VFE_CAMIF_COMMAND);
+			spin_lock_irqsave(&axi_ctrl->share_ctrl->abort_lock,
+				flags);
+			if (axi_ctrl->share_ctrl->skip_abort) {
+				spin_unlock_irqrestore(&axi_ctrl->share_ctrl->
+					abort_lock, flags);
+				atomic_set(&axi_ctrl->share_ctrl->
+					handle_axi_irq, 0);
+				axi_disable_irq(axi_ctrl);
+			} else
+				spin_unlock_irqrestore(&axi_ctrl->share_ctrl->
+					abort_lock, flags);
 			vfe32_send_isp_msg(&axi_ctrl->subdev,
 				axi_ctrl->share_ctrl->vfeFrameId,
 				MSG_ID_SNAPSHOT_DONE);
@@ -5673,7 +5894,9 @@
 		rc = 0;
 		break;
 	default:
-		pr_err("%s: command not found\n", __func__);
+		pr_err("%s: command %d not found\n", __func__,
+						_IOC_NR(cmd));
+		break;
 	}
 	return rc;
 }
diff --git a/drivers/media/video/msm/vfe/msm_vfe32.h b/drivers/media/video/msm/vfe/msm_vfe32.h
index 170bfb7..f4b7edb 100644
--- a/drivers/media/video/msm/vfe/msm_vfe32.h
+++ b/drivers/media/video/msm/vfe/msm_vfe32.h
@@ -941,9 +941,11 @@
 	uint32_t register_total;
 
 	atomic_t vstate;
+	atomic_t handle_axi_irq;
 	uint32_t vfeFrameId;
 	uint32_t stats_comp;
 	spinlock_t  stop_flag_lock;
+	spinlock_t  abort_lock;
 	int8_t stop_ack_pending;
 	enum vfe_output_state liveshot_state;
 	uint32_t vfe_capture_count;
@@ -956,8 +958,20 @@
 	uint32_t skip_abort;
 	spinlock_t  sd_notify_lock;
 
+	struct completion reset_complete;
+
+	spinlock_t  update_ack_lock;
+	spinlock_t  start_ack_lock;
+
 	struct axi_ctrl_t *axi_ctrl;
 	struct vfe32_ctrl_type *vfe32_ctrl;
+	int8_t start_ack_pending;
+	int8_t update_ack_pending;
+	enum vfe_output_state recording_state;
+
+	atomic_t rdi0_update_ack_pending;
+	atomic_t rdi1_update_ack_pending;
+	atomic_t rdi2_update_ack_pending;
 };
 
 struct axi_ctrl_t {
@@ -978,21 +992,12 @@
 };
 
 struct vfe32_ctrl_type {
-	uint32_t vfeImaskCompositePacked;
-
-	spinlock_t  update_ack_lock;
-	spinlock_t  start_ack_lock;
 	spinlock_t  state_lock;
-	spinlock_t  io_lock;
 	spinlock_t  stats_bufq_lock;
 	uint32_t extlen;
 	void *extdata;
 
-	int8_t start_ack_pending;
-	int8_t update_ack_pending;
-	bool is_reset_blocking;
-	struct completion reset_complete;
-	enum vfe_output_state recording_state;
+	int8_t vfe_sof_count_enable;
 	int8_t update_linear;
 	int8_t update_rolloff;
 	int8_t update_la;
@@ -1004,12 +1009,6 @@
 	uint32_t sync_timer_state;
 	uint32_t sync_timer_number;
 
-	uint32_t output1Pattern;
-	uint32_t output1Period;
-	uint32_t output2Pattern;
-	uint32_t output2Period;
-	uint32_t vfeFrameSkipCount;
-	uint32_t vfeFrameSkipPeriod;
 	struct msm_ver_num_info ver_num;
 	struct vfe_stats_control afbfStatsControl;
 	struct vfe_stats_control awbStatsControl;
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.c b/drivers/media/video/msm/vfe/msm_vfe40.c
new file mode 100644
index 0000000..5a1d488
--- /dev/null
+++ b/drivers/media/video/msm/vfe/msm_vfe40.c
@@ -0,0 +1,3699 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/atomic.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <mach/irqs.h>
+#include <mach/camera.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/msm_isp.h>
+
+#include "msm.h"
+#include "msm_vfe40.h"
+
+struct vfe40_isr_queue_cmd {
+	struct list_head list;
+	uint32_t                           vfeInterruptStatus0;
+	uint32_t                           vfeInterruptStatus1;
+};
+
+static const char * const vfe40_general_cmd[] = {
+	"DUMMY_0",  /* 0 */
+	"SET_CLK",
+	"RESET",
+	"START",
+	"TEST_GEN_START",
+	"OPERATION_CFG",  /* 5 */
+	"AXI_OUT_CFG",
+	"CAMIF_CFG",
+	"AXI_INPUT_CFG",
+	"BLACK_LEVEL_CFG",
+	"ROLL_OFF_CFG",  /* 10 */
+	"DEMUX_CFG",
+	"FOV_CFG",
+	"MAIN_SCALER_CFG",
+	"WB_CFG",
+	"COLOR_COR_CFG", /* 15 */
+	"RGB_G_CFG",
+	"LA_CFG",
+	"CHROMA_EN_CFG",
+	"CHROMA_SUP_CFG",
+	"MCE_CFG", /* 20 */
+	"SK_ENHAN_CFG",
+	"ASF_CFG",
+	"S2Y_CFG",
+	"S2CbCr_CFG",
+	"CHROMA_SUBS_CFG",  /* 25 */
+	"OUT_CLAMP_CFG",
+	"FRAME_SKIP_CFG",
+	"DUMMY_1",
+	"DUMMY_2",
+	"DUMMY_3",  /* 30 */
+	"UPDATE",
+	"BL_LVL_UPDATE",
+	"DEMUX_UPDATE",
+	"FOV_UPDATE",
+	"MAIN_SCALER_UPDATE",  /* 35 */
+	"WB_UPDATE",
+	"COLOR_COR_UPDATE",
+	"RGB_G_UPDATE",
+	"LA_UPDATE",
+	"CHROMA_EN_UPDATE",  /* 40 */
+	"CHROMA_SUP_UPDATE",
+	"MCE_UPDATE",
+	"SK_ENHAN_UPDATE",
+	"S2CbCr_UPDATE",
+	"S2Y_UPDATE",  /* 45 */
+	"ASF_UPDATE",
+	"FRAME_SKIP_UPDATE",
+	"CAMIF_FRAME_UPDATE",
+	"STATS_AF_UPDATE",
+	"STATS_AE_UPDATE",  /* 50 */
+	"STATS_AWB_UPDATE",
+	"STATS_RS_UPDATE",
+	"STATS_CS_UPDATE",
+	"STATS_SKIN_UPDATE",
+	"STATS_IHIST_UPDATE",  /* 55 */
+	"DUMMY_4",
+	"EPOCH1_ACK",
+	"EPOCH2_ACK",
+	"START_RECORDING",
+	"STOP_RECORDING",  /* 60 */
+	"DUMMY_5",
+	"DUMMY_6",
+	"CAPTURE",
+	"DUMMY_7",
+	"STOP",  /* 65 */
+	"GET_HW_VERSION",
+	"GET_FRAME_SKIP_COUNTS",
+	"OUTPUT1_BUFFER_ENQ",
+	"OUTPUT2_BUFFER_ENQ",
+	"OUTPUT3_BUFFER_ENQ",  /* 70 */
+	"JPEG_OUT_BUF_ENQ",
+	"RAW_OUT_BUF_ENQ",
+	"RAW_IN_BUF_ENQ",
+	"STATS_AF_ENQ",
+	"STATS_AE_ENQ",  /* 75 */
+	"STATS_AWB_ENQ",
+	"STATS_RS_ENQ",
+	"STATS_CS_ENQ",
+	"STATS_SKIN_ENQ",
+	"STATS_IHIST_ENQ",  /* 80 */
+	"DUMMY_8",
+	"JPEG_ENC_CFG",
+	"DUMMY_9",
+	"STATS_AF_START",
+	"STATS_AF_STOP",  /* 85 */
+	"STATS_AE_START",
+	"STATS_AE_STOP",
+	"STATS_AWB_START",
+	"STATS_AWB_STOP",
+	"STATS_RS_START",  /* 90 */
+	"STATS_RS_STOP",
+	"STATS_CS_START",
+	"STATS_CS_STOP",
+	"STATS_SKIN_START",
+	"STATS_SKIN_STOP",  /* 95 */
+	"STATS_IHIST_START",
+	"STATS_IHIST_STOP",
+	"DUMMY_10",
+	"SYNC_TIMER_SETTING",
+	"ASYNC_TIMER_SETTING",  /* 100 */
+	"LIVESHOT",
+	"LA_SETUP",
+	"LINEARIZATION_CFG",
+	"DEMOSAICV3",
+	"DEMOSAICV3_ABCC_CFG", /* 105 */
+	"DEMOSAICV3_DBCC_CFG",
+	"DEMOSAICV3_DBPC_CFG",
+	"DEMOSAICV3_ABF_CFG",
+	"DEMOSAICV3_ABCC_UPDATE",
+	"DEMOSAICV3_DBCC_UPDATE", /* 110 */
+	"DEMOSAICV3_DBPC_UPDATE",
+	"XBAR_CFG",
+	"EZTUNE_CFG",
+	"V40_ZSL",
+	"LINEARIZATION_UPDATE", /*115*/
+	"DEMOSAICV3_ABF_UPDATE",
+	"CLF_CFG",
+	"CLF_LUMA_UPDATE",
+	"CLF_CHROMA_UPDATE",
+	"PCA_ROLL_OFF_CFG", /*120*/
+	"PCA_ROLL_OFF_UPDATE",
+	"GET_REG_DUMP",
+	"GET_LINEARIZATON_TABLE",
+	"GET_MESH_ROLLOFF_TABLE",
+	"GET_PCA_ROLLOFF_TABLE", /*125*/
+	"GET_RGB_G_TABLE",
+	"GET_LA_TABLE",
+	"DEMOSAICV3_UPDATE",
+	"ACTIVE_REGION_CONFIG",
+	"COLOR_PROCESSING_CONFIG", /*130*/
+	"STATS_WB_AEC_CONFIG",
+	"STATS_WB_AEC_UPDATE",
+	"Y_GAMMA_CONFIG",
+	"SCALE_OUTPUT1_CONFIG",
+	"SCALE_OUTPUT2_CONFIG", /*135*/
+	"CAPTURE_RAW",
+	"STOP_LIVESHOT",
+	"RECONFIG_VFE",
+	"STATS_REQBUF_CFG",
+	"STATS_ENQUEUEBUF_CFG",/*140*/
+	"STATS_FLUSH_BUFQ_CFG",
+	"FOV_ENC_CFG",
+	"FOV_VIEW_CFG",
+	"FOV_ENC_UPDATE",
+	"FOV_VIEW_UPDATE",/*145*/
+	"SCALER_ENC_CFG",
+	"SCALER_VIEW_CFG",
+	"SCALER_ENC_UPDATE",
+	"SCALER_VIEW_UPDATE",
+	"COLORXFORM_ENC_CFG",/*150*/
+	"COLORXFORM_VIEW_CFG",
+	"COLORXFORM_ENC_UPDATE",
+	"COLORXFORM_VIEW_UPDATE",
+};
+
+static void vfe40_stop(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	unsigned long flags;
+
+	atomic_set(&vfe40_ctrl->share_ctrl->vstate, 0);
+
+	/* for reset hw modules, and send msg when reset_irq comes.*/
+	spin_lock_irqsave(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
+	vfe40_ctrl->share_ctrl->stop_ack_pending = TRUE;
+	spin_unlock_irqrestore(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
+
+	/* disable all interrupts.  */
+	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	/* clear all pending interrupts*/
+	msm_camera_io_w(VFE_CLEAR_ALL_IRQ0,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+	msm_camera_io_w(VFE_CLEAR_ALL_IRQ1,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_camera_io_w_mb(1,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
+
+	/* in either continuous or snapshot mode, stop command can be issued
+	 * at any time. stop camif immediately. */
+	msm_camera_io_w(CAMIF_COMMAND_STOP_IMMEDIATELY,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND);
+}
+
+void vfe40_subdev_notify(int id, int path, int image_mode,
+	struct v4l2_subdev *sd, struct vfe_share_ctrl_t *share_ctrl)
+{
+	struct msm_vfe_resp rp;
+	struct msm_frame_info frame_info;
+	unsigned long flags = 0;
+	spin_lock_irqsave(&share_ctrl->sd_notify_lock, flags);
+	CDBG("%s: msgId = %d\n", __func__, id);
+	memset(&rp, 0, sizeof(struct msm_vfe_resp));
+	rp.evt_msg.type   = MSM_CAMERA_MSG;
+	frame_info.image_mode = image_mode;
+	frame_info.path = path;
+	rp.evt_msg.data = &frame_info;
+	rp.type	   = id;
+	v4l2_subdev_notify(sd, NOTIFY_VFE_BUF_EVT, &rp);
+	spin_unlock_irqrestore(&share_ctrl->sd_notify_lock, flags);
+}
+
+static void vfe40_reset_internal_variables(
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	unsigned long flags;
+	vfe40_ctrl->vfeImaskCompositePacked = 0;
+	/* state control variables */
+	vfe40_ctrl->start_ack_pending = FALSE;
+	atomic_set(&vfe40_ctrl->share_ctrl->irq_cnt, 0);
+
+	spin_lock_irqsave(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
+	vfe40_ctrl->share_ctrl->stop_ack_pending  = FALSE;
+	spin_unlock_irqrestore(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
+
+	vfe40_ctrl->reset_ack_pending  = FALSE;
+
+	spin_lock_irqsave(&vfe40_ctrl->update_ack_lock, flags);
+	vfe40_ctrl->update_ack_pending = FALSE;
+	spin_unlock_irqrestore(&vfe40_ctrl->update_ack_lock, flags);
+
+	vfe40_ctrl->recording_state = VFE_STATE_IDLE;
+	vfe40_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
+
+	atomic_set(&vfe40_ctrl->share_ctrl->vstate, 0);
+
+	/* 0 for continuous mode, 1 for snapshot mode */
+	vfe40_ctrl->share_ctrl->operation_mode = 0;
+	vfe40_ctrl->share_ctrl->outpath.output_mode = 0;
+	vfe40_ctrl->share_ctrl->vfe_capture_count = 0;
+
+	/* this is unsigned 32 bit integer. */
+	vfe40_ctrl->share_ctrl->vfeFrameId = 0;
+	/* Stats control variables. */
+	memset(&(vfe40_ctrl->afStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe40_ctrl->awbStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe40_ctrl->aecStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe40_ctrl->ihistStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe40_ctrl->rsStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	memset(&(vfe40_ctrl->csStatsControl), 0,
+		sizeof(struct vfe_stats_control));
+
+	vfe40_ctrl->frame_skip_cnt = 31;
+	vfe40_ctrl->frame_skip_pattern = 0xffffffff;
+	vfe40_ctrl->snapshot_frame_cnt = 0;
+}
+
+static void vfe40_reset(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	vfe40_reset_internal_variables(vfe40_ctrl);
+	/* disable all interrupts.  vfeImaskLocal is also reset to 0
+	* to begin with. */
+	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+
+	msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	/* clear all pending interrupts*/
+	msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+	msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_camera_io_w_mb(1, vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
+
+	/* enable reset_ack interrupt.  */
+	msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
+	vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	/* Write to VFE_GLOBAL_RESET_CMD to reset the vfe hardware. Once reset
+	 * is done, hardware interrupt will be generated.  VFE ist processes
+	 * the interrupt to complete the function call.  Note that the reset
+	 * function is synchronous. */
+
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_camera_io_w_mb(VFE_RESET_UPON_RESET_CMD,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
+
+	msm_camera_io_w(0xAAAAAAAA,
+	vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_0);
+	msm_camera_io_w(0xAAAAAAAA,
+	vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_1);
+	msm_camera_io_w(0xAAAAAAAA,
+	vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_2);
+	msm_camera_io_w(0xAAAAAAAA,
+	vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_3);
+	msm_camera_io_w(0xAAAAAAAA,
+	vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_4);
+	msm_camera_io_w(0xAAAAAAAA,
+	vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_5);
+	msm_camera_io_w(0xAAAAAAAA,
+	vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_6);
+	msm_camera_io_w(0x0002AAAA,
+	vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_7);
+}
+
+static int vfe40_operation_config(uint32_t *cmd,
+			struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	uint32_t *p = cmd;
+
+	vfe40_ctrl->share_ctrl->operation_mode = *p;
+	vfe40_ctrl->share_ctrl->stats_comp = *(++p);
+	vfe40_ctrl->hfr_mode = *(++p);
+
+	msm_camera_io_w(*(++p),
+		vfe40_ctrl->share_ctrl->vfebase + VFE_CFG);
+	msm_camera_io_w(*(++p),
+		vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+	msm_camera_io_w(*(++p),
+		vfe40_ctrl->share_ctrl->vfebase + VFE_RDI0_CFG);
+	if (msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
+		V40_GET_HW_VERSION_OFF) ==
+		VFE40_HW_NUMBER) {
+		msm_camera_io_w(*(++p),
+			vfe40_ctrl->share_ctrl->vfebase + VFE_RDI1_CFG);
+		msm_camera_io_w(*(++p),
+			vfe40_ctrl->share_ctrl->vfebase + VFE_RDI2_CFG);
+	}  else {
+		++p;
+		++p;
+	}
+	msm_camera_io_w(*(++p),
+		vfe40_ctrl->share_ctrl->vfebase + VFE_REALIGN_BUF);
+	msm_camera_io_w(*(++p),
+		vfe40_ctrl->share_ctrl->vfebase + VFE_CHROMA_UP);
+	msm_camera_io_w(*(++p),
+		vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
+	return 0;
+}
+
+static unsigned long vfe40_stats_dqbuf(struct vfe40_ctrl_type *vfe40_ctrl,
+	enum msm_stats_enum_type stats_type)
+{
+	struct msm_stats_meta_buf *buf = NULL;
+	int rc = 0;
+	rc = vfe40_ctrl->stats_ops.dqbuf(
+			vfe40_ctrl->stats_ops.stats_ctrl, stats_type, &buf);
+	if (rc < 0) {
+		pr_err("%s: dq stats buf (type = %d) err = %d",
+			__func__, stats_type, rc);
+		return 0L;
+	}
+	return buf->paddr;
+}
+
+static unsigned long vfe40_stats_flush_enqueue(
+	struct vfe40_ctrl_type *vfe40_ctrl,
+	enum msm_stats_enum_type stats_type)
+{
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+	int rc = 0;
+	int i;
+
+	/*
+	 * Passing NULL for ion client as the buffers are already
+	 * mapped at this stage, client is not required, flush all
+	 * the buffers, and buffers move to PREPARE state
+	 */
+
+	rc = vfe40_ctrl->stats_ops.bufq_flush(
+			vfe40_ctrl->stats_ops.stats_ctrl, stats_type, NULL);
+	if (rc < 0) {
+		pr_err("%s: dq stats buf (type = %d) err = %d",
+			__func__, stats_type, rc);
+		return 0L;
+	}
+	/* Queue all the buffers back to QUEUED state */
+	bufq = vfe40_ctrl->stats_ctrl.bufq[stats_type];
+	for (i = 0; i < bufq->num_bufs; i++) {
+		stats_buf = &bufq->bufs[i];
+		rc = vfe40_ctrl->stats_ops.enqueue_buf(
+				vfe40_ctrl->stats_ops.stats_ctrl,
+				&(stats_buf->info), NULL);
+		if (rc < 0) {
+			pr_err("%s: dq stats buf (type = %d) err = %d",
+				 __func__, stats_type, rc);
+			return rc;
+		}
+	}
+	return 0L;
+}
+
+static int vfe_stats_awb_buf_init(
+	struct vfe40_ctrl_type *vfe40_ctrl,
+	struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AWB);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq awb ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe40_ctrl->share_ctrl->vfebase +
+		VFE_BUS_STATS_AWB_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AWB);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq awb ping buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe40_ctrl->share_ctrl->vfebase +
+		VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+	return 0;
+}
+
+static int vfe_stats_aec_buf_init(
+	struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AEC);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq aec ping buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe40_ctrl->share_ctrl->vfebase +
+		VFE_BUS_STATS_AEC_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AEC);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq aec pong buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe40_ctrl->share_ctrl->vfebase +
+		VFE_BUS_STATS_AEC_WR_PONG_ADDR);
+	return 0;
+}
+
+static int vfe_stats_af_buf_init(
+	struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	rc = vfe40_stats_flush_enqueue(vfe40_ctrl, MSM_STATS_TYPE_AF);
+	if (rc < 0) {
+		pr_err("%s: dq stats buf err = %d",
+			   __func__, rc);
+		spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+		return -EINVAL;
+	}
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AF);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq af ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe40_ctrl->share_ctrl->vfebase +
+		VFE_BUS_STATS_AF_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AF);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq af pong buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe40_ctrl->share_ctrl->vfebase +
+		VFE_BUS_STATS_AF_WR_PONG_ADDR);
+
+	return 0;
+}
+
+static int vfe_stats_ihist_buf_init(
+	struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_IHIST);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq ihist ping buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe40_ctrl->share_ctrl->vfebase +
+		VFE_BUS_STATS_HIST_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_IHIST);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq ihist pong buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe40_ctrl->share_ctrl->vfebase +
+		VFE_BUS_STATS_HIST_WR_PONG_ADDR);
+
+	return 0;
+}
+
+static int vfe_stats_rs_buf_init(
+	struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_RS);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq rs ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe40_ctrl->share_ctrl->vfebase +
+		VFE_BUS_STATS_RS_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_RS);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq rs pong buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe40_ctrl->share_ctrl->vfebase +
+		VFE_BUS_STATS_RS_WR_PONG_ADDR);
+	return 0;
+}
+
+static int vfe_stats_cs_buf_init(
+	struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_CS);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq cs ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe40_ctrl->share_ctrl->vfebase +
+		VFE_BUS_STATS_CS_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_CS);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq cs pong buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe40_ctrl->share_ctrl->vfebase +
+		VFE_BUS_STATS_CS_WR_PONG_ADDR);
+	return 0;
+}
+
+static void vfe40_start_common(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	uint32_t irq_mask = 0x1E000011;
+	vfe40_ctrl->start_ack_pending = TRUE;
+	CDBG("VFE opertaion mode = 0x%x, output mode = 0x%x\n",
+		vfe40_ctrl->share_ctrl->operation_mode,
+		vfe40_ctrl->share_ctrl->outpath.output_mode);
+
+	msm_camera_io_w(irq_mask,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+	msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_camera_io_w_mb(1,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+	msm_camera_io_w_mb(1,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND);
+
+	msm_camera_io_dump(vfe40_ctrl->share_ctrl->vfebase,
+		vfe40_ctrl->share_ctrl->register_total*4);
+
+	atomic_set(&vfe40_ctrl->share_ctrl->vstate, 1);
+}
+
+static int vfe40_start_recording(
+	struct msm_cam_media_controller *pmctl,
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	msm_camio_bus_scale_cfg(
+		pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO);
+	vfe40_ctrl->recording_state = VFE_STATE_START_REQUESTED;
+	msm_camera_io_w_mb(1,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+	return 0;
+}
+
+static int vfe40_stop_recording(
+	struct msm_cam_media_controller *pmctl,
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	vfe40_ctrl->recording_state = VFE_STATE_STOP_REQUESTED;
+	msm_camera_io_w_mb(1,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+	msm_camio_bus_scale_cfg(
+		pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+	return 0;
+}
+
+static void vfe40_start_liveshot(
+	struct msm_cam_media_controller *pmctl,
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	/* Hardcode 1 live snapshot for now. */
+	vfe40_ctrl->share_ctrl->outpath.out0.capture_cnt = 1;
+	vfe40_ctrl->share_ctrl->vfe_capture_count =
+		vfe40_ctrl->share_ctrl->outpath.out0.capture_cnt;
+
+	vfe40_ctrl->share_ctrl->liveshot_state = VFE_STATE_START_REQUESTED;
+	msm_camera_io_w_mb(1, vfe40_ctrl->
+		share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+}
+
+static int vfe40_zsl(
+	struct msm_cam_media_controller *pmctl,
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	uint32_t irq_comp_mask = 0;
+	/* capture command is valid for both idle and active state. */
+	irq_comp_mask	=
+		msm_camera_io_r(vfe40_ctrl->
+		share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+	CDBG("%s:op mode %d O/P Mode %d\n", __func__,
+		vfe40_ctrl->share_ctrl->operation_mode,
+		vfe40_ctrl->share_ctrl->outpath.output_mode);
+
+	if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+		VFE40_OUTPUT_MODE_PRIMARY) {
+		irq_comp_mask |= (
+			(0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch0)) |
+			(0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch1)));
+	} else if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+		irq_comp_mask |= (
+			(0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch0)) |
+			(0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch1)) |
+			(0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch2)));
+	}
+
+	if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+		VFE40_OUTPUT_MODE_SECONDARY) {
+		irq_comp_mask |= ((0x1 << (vfe40_ctrl->
+				share_ctrl->outpath.out1.ch0 + 8)) |
+			(0x1 << (vfe40_ctrl->
+				share_ctrl->outpath.out1.ch1 + 8)));
+	} else if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+			   VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+		irq_comp_mask |= (
+			(0x1 << (vfe40_ctrl->
+				share_ctrl->outpath.out1.ch0 + 8)) |
+			(0x1 << (vfe40_ctrl->
+				share_ctrl->outpath.out1.ch1 + 8)) |
+			(0x1 << (vfe40_ctrl->
+				share_ctrl->outpath.out1.ch2 + 8)));
+	}
+
+	if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_PRIMARY) {
+		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[vfe40_ctrl->
+			share_ctrl->outpath.out0.ch0]);
+		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[vfe40_ctrl->
+			share_ctrl->outpath.out0.ch1]);
+	} else if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+				VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[vfe40_ctrl->
+			share_ctrl->outpath.out0.ch0]);
+		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[vfe40_ctrl->
+			share_ctrl->outpath.out0.ch1]);
+		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[vfe40_ctrl->
+			share_ctrl->outpath.out0.ch2]);
+	}
+
+	if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_SECONDARY) {
+		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[vfe40_ctrl->
+			share_ctrl->outpath.out1.ch0]);
+		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[vfe40_ctrl->
+			share_ctrl->outpath.out1.ch1]);
+	} else if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+				VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[vfe40_ctrl->
+			share_ctrl->outpath.out1.ch0]);
+		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[vfe40_ctrl->
+			share_ctrl->outpath.out1.ch1]);
+		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[vfe40_ctrl->
+			share_ctrl->outpath.out1.ch2]);
+	}
+
+	msm_camera_io_w(irq_comp_mask,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+	vfe40_start_common(vfe40_ctrl);
+	msm_camio_bus_scale_cfg(
+		pmctl->sdata->pdata->cam_bus_scale_table, S_ZSL);
+
+	msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + 0x18C);
+	msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + 0x188);
+	return 0;
+}
+static int vfe40_capture_raw(
+	struct msm_cam_media_controller *pmctl,
+	struct vfe40_ctrl_type *vfe40_ctrl,
+	uint32_t num_frames_capture)
+{
+	uint32_t irq_comp_mask = 0;
+
+	vfe40_ctrl->share_ctrl->outpath.out0.capture_cnt = num_frames_capture;
+	vfe40_ctrl->share_ctrl->vfe_capture_count = num_frames_capture;
+
+	irq_comp_mask	=
+		msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+	if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+		VFE40_OUTPUT_MODE_PRIMARY) {
+		irq_comp_mask |=
+			(0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch0));
+		msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[vfe40_ctrl->
+			share_ctrl->outpath.out0.ch0]);
+	}
+
+	msm_camera_io_w(irq_comp_mask,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+	msm_camio_bus_scale_cfg(
+		pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
+	vfe40_start_common(vfe40_ctrl);
+	return 0;
+}
+
+static int vfe40_capture(
+	struct msm_cam_media_controller *pmctl,
+	uint32_t num_frames_capture,
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	uint32_t irq_comp_mask = 0;
+
+	/* capture command is valid for both idle and active state. */
+	vfe40_ctrl->share_ctrl->outpath.out1.capture_cnt = num_frames_capture;
+	if (vfe40_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_MAIN_AND_THUMB ||
+		vfe40_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_THUMB_AND_MAIN ||
+		vfe40_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_JPEG_AND_THUMB ||
+		vfe40_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_THUMB_AND_JPEG) {
+		vfe40_ctrl->share_ctrl->outpath.out0.capture_cnt =
+			num_frames_capture;
+	}
+
+	vfe40_ctrl->share_ctrl->vfe_capture_count = num_frames_capture;
+	irq_comp_mask = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+	if (vfe40_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_MAIN_AND_THUMB ||
+		vfe40_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_JPEG_AND_THUMB ||
+		vfe40_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_THUMB_AND_MAIN) {
+		if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_PRIMARY) {
+			irq_comp_mask |= (0x1 << vfe40_ctrl->
+				share_ctrl->outpath.out0.ch0 |
+				0x1 << vfe40_ctrl->
+				share_ctrl->outpath.out0.ch1);
+		}
+		if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_SECONDARY) {
+			irq_comp_mask |=
+				(0x1 << (vfe40_ctrl->
+					share_ctrl->outpath.out1.ch0 + 8) |
+				0x1 << (vfe40_ctrl->
+					share_ctrl->outpath.out1.ch1 + 8));
+		}
+		if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_PRIMARY) {
+			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				share_ctrl->outpath.out0.ch0]);
+			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				share_ctrl->outpath.out0.ch1]);
+		}
+		if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_SECONDARY) {
+			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				share_ctrl->outpath.out1.ch0]);
+			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				share_ctrl->outpath.out1.ch1]);
+		}
+	}
+
+	vfe40_ctrl->share_ctrl->vfe_capture_count = num_frames_capture;
+
+	msm_camera_io_w(irq_comp_mask,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+	msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+	msm_camio_bus_scale_cfg(
+		pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
+
+	vfe40_start_common(vfe40_ctrl);
+	/* for debug */
+	msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + 0x18C);
+	msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + 0x188);
+	return 0;
+}
+
+static int vfe40_start(
+	struct msm_cam_media_controller *pmctl,
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	uint32_t irq_comp_mask = 0;
+	irq_comp_mask	=
+		msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
+			VFE_IRQ_COMP_MASK);
+
+	if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_PRIMARY) {
+		irq_comp_mask |= (
+			0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch0 |
+			0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch1);
+	} else if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+			   VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+		irq_comp_mask |= (
+			0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch0 |
+			0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch1 |
+			0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch2);
+	}
+	if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_SECONDARY) {
+		irq_comp_mask |= (
+			0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch0 + 8) |
+			0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch1 + 8));
+	} else if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+		irq_comp_mask |= (
+			0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch0 + 8) |
+			0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch1 + 8) |
+			0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch2 + 8));
+	}
+	msm_camera_io_w(irq_comp_mask,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+	/*
+	msm_camio_bus_scale_cfg(
+		pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);*/
+	vfe40_start_common(vfe40_ctrl);
+	return 0;
+}
+
+static void vfe40_update(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	unsigned long flags;
+	uint32_t value = 0;
+	if (vfe40_ctrl->update_linear) {
+		if (!msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase +
+			V40_LINEARIZATION_OFF1))
+			msm_camera_io_w(1,
+				vfe40_ctrl->share_ctrl->vfebase +
+				V40_LINEARIZATION_OFF1);
+		else
+			msm_camera_io_w(0,
+				vfe40_ctrl->share_ctrl->vfebase +
+				V40_LINEARIZATION_OFF1);
+		vfe40_ctrl->update_linear = false;
+	}
+
+	if (vfe40_ctrl->update_la) {
+		if (!msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + V40_LA_OFF))
+			msm_camera_io_w(1,
+				vfe40_ctrl->share_ctrl->vfebase + V40_LA_OFF);
+		else
+			msm_camera_io_w(0,
+				vfe40_ctrl->share_ctrl->vfebase + V40_LA_OFF);
+		vfe40_ctrl->update_la = false;
+	}
+
+	if (vfe40_ctrl->update_gamma) {
+		value = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + V40_RGB_G_OFF);
+		value ^= V40_GAMMA_LUT_BANK_SEL_MASK;
+		msm_camera_io_w(value,
+			vfe40_ctrl->share_ctrl->vfebase + V40_RGB_G_OFF);
+		vfe40_ctrl->update_gamma = false;
+	}
+
+	spin_lock_irqsave(&vfe40_ctrl->update_ack_lock, flags);
+	vfe40_ctrl->update_ack_pending = TRUE;
+	spin_unlock_irqrestore(&vfe40_ctrl->update_ack_lock, flags);
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_camera_io_w_mb(1,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+	return;
+}
+
+static void vfe40_sync_timer_stop(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	uint32_t value = 0;
+	vfe40_ctrl->sync_timer_state = 0;
+	if (vfe40_ctrl->sync_timer_number == 0)
+		value = 0x10000;
+	else if (vfe40_ctrl->sync_timer_number == 1)
+		value = 0x20000;
+	else if (vfe40_ctrl->sync_timer_number == 2)
+		value = 0x40000;
+
+	/* Timer Stop */
+	msm_camera_io_w(value,
+		vfe40_ctrl->share_ctrl->vfebase + V40_SYNC_TIMER_OFF);
+}
+
+static void vfe40_sync_timer_start(
+	const uint32_t *tbl,
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	/* set bit 8 for auto increment. */
+	uint32_t value = 1;
+	uint32_t val;
+
+	vfe40_ctrl->sync_timer_state = *tbl++;
+	vfe40_ctrl->sync_timer_repeat_count = *tbl++;
+	vfe40_ctrl->sync_timer_number = *tbl++;
+	CDBG("%s timer_state %d, repeat_cnt %d timer number %d\n",
+		 __func__, vfe40_ctrl->sync_timer_state,
+		 vfe40_ctrl->sync_timer_repeat_count,
+		 vfe40_ctrl->sync_timer_number);
+
+	if (vfe40_ctrl->sync_timer_state) { /* Start Timer */
+		value = value << vfe40_ctrl->sync_timer_number;
+	} else { /* Stop Timer */
+		CDBG("Failed to Start timer\n");
+		return;
+	}
+
+	/* Timer Start */
+	msm_camera_io_w(value,
+		vfe40_ctrl->share_ctrl->vfebase + V40_SYNC_TIMER_OFF);
+	/* Sync Timer Line Start */
+	value = *tbl++;
+	msm_camera_io_w(value,
+		vfe40_ctrl->share_ctrl->vfebase + V40_SYNC_TIMER_OFF +
+		4 + ((vfe40_ctrl->sync_timer_number) * 12));
+	/* Sync Timer Pixel Start */
+	value = *tbl++;
+	msm_camera_io_w(value,
+			vfe40_ctrl->share_ctrl->vfebase + V40_SYNC_TIMER_OFF +
+			 8 + ((vfe40_ctrl->sync_timer_number) * 12));
+	/* Sync Timer Pixel Duration */
+	value = *tbl++;
+	val = vfe40_ctrl->share_ctrl->vfe_clk_rate / 10000;
+	val = 10000000 / val;
+	val = value * 10000 / val;
+	CDBG("%s: Pixel Clk Cycles!!! %d\n", __func__, val);
+	msm_camera_io_w(val,
+		vfe40_ctrl->share_ctrl->vfebase + V40_SYNC_TIMER_OFF +
+		12 + ((vfe40_ctrl->sync_timer_number) * 12));
+	/* Timer0 Active High/LOW */
+	value = *tbl++;
+	msm_camera_io_w(value,
+		vfe40_ctrl->share_ctrl->vfebase + V40_SYNC_TIMER_POLARITY_OFF);
+	/* Selects sync timer 0 output to drive onto timer1 port */
+	value = 0;
+	msm_camera_io_w(value,
+		vfe40_ctrl->share_ctrl->vfebase + V40_TIMER_SELECT_OFF);
+}
+
+static void vfe40_program_dmi_cfg(
+	enum VFE40_DMI_RAM_SEL bankSel,
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	/* set bit 8 for auto increment. */
+	uint32_t value = VFE_DMI_CFG_DEFAULT;
+	value += (uint32_t)bankSel;
+	CDBG("%s: banksel = %d\n", __func__, bankSel);
+
+	msm_camera_io_w(value, vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_CFG);
+	/* by default, always starts with offset 0.*/
+	msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_ADDR);
+}
+static void vfe40_write_gamma_cfg(
+	enum VFE40_DMI_RAM_SEL channel_sel,
+	const uint32_t *tbl,
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	int i;
+	uint32_t value, value1, value2;
+	vfe40_program_dmi_cfg(channel_sel, vfe40_ctrl);
+	for (i = 0 ; i < (VFE40_GAMMA_NUM_ENTRIES/2) ; i++) {
+		value = *tbl++;
+		value1 = value & 0x0000FFFF;
+		value2 = (value & 0xFFFF0000)>>16;
+		msm_camera_io_w((value1),
+			vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
+		msm_camera_io_w((value2),
+			vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
+	}
+	vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+}
+
+static void vfe40_read_gamma_cfg(
+	enum VFE40_DMI_RAM_SEL channel_sel,
+	uint32_t *tbl,
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	int i;
+	vfe40_program_dmi_cfg(channel_sel, vfe40_ctrl);
+	CDBG("%s: Gamma table channel: %d\n", __func__, channel_sel);
+	for (i = 0 ; i < VFE40_GAMMA_NUM_ENTRIES ; i++) {
+		*tbl = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
+		CDBG("%s: %08x\n", __func__, *tbl);
+		tbl++;
+	}
+	vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+}
+
+static void vfe40_write_la_cfg(
+	enum VFE40_DMI_RAM_SEL channel_sel,
+	const uint32_t *tbl,
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	uint32_t i;
+	uint32_t value, value1, value2;
+
+	vfe40_program_dmi_cfg(channel_sel, vfe40_ctrl);
+	for (i = 0 ; i < (VFE40_LA_TABLE_LENGTH/2) ; i++) {
+		value = *tbl++;
+		value1 = value & 0x0000FFFF;
+		value2 = (value & 0xFFFF0000)>>16;
+		msm_camera_io_w((value1),
+			vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
+		msm_camera_io_w((value2),
+			vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
+	}
+	vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+}
+
+struct vfe40_output_ch *vfe40_get_ch(
+	int path, struct vfe_share_ctrl_t *share_ctrl)
+{
+	struct vfe40_output_ch *ch = NULL;
+
+	if (path == VFE_MSG_OUTPUT_PRIMARY)
+		ch = &share_ctrl->outpath.out0;
+	else if (path == VFE_MSG_OUTPUT_SECONDARY)
+		ch = &share_ctrl->outpath.out1;
+	else
+		pr_err("%s: Invalid path %d\n", __func__,
+			path);
+
+	BUG_ON(ch == NULL);
+	return ch;
+}
+
+static int vfe40_configure_pingpong_buffers(
+	int id, int path, struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	struct vfe40_output_ch *outch = NULL;
+	int rc = 0;
+	uint32_t image_mode = 0;
+	if (path == VFE_MSG_OUTPUT_PRIMARY)
+		image_mode = vfe40_ctrl->share_ctrl->outpath.out0.image_mode;
+	else
+		image_mode = vfe40_ctrl->share_ctrl->outpath.out1.image_mode;
+
+	vfe40_subdev_notify(id, path, image_mode,
+		&vfe40_ctrl->subdev, vfe40_ctrl->share_ctrl);
+	outch = vfe40_get_ch(path, vfe40_ctrl->share_ctrl);
+	if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) {
+		/* Configure Preview Ping Pong */
+		CDBG("%s Configure ping/pong address for %d",
+						__func__, path);
+		vfe40_put_ch_ping_addr(
+			vfe40_ctrl->share_ctrl->vfebase, outch->ch0,
+			outch->ping.ch_paddr[0]);
+		vfe40_put_ch_pong_addr(
+			vfe40_ctrl->share_ctrl->vfebase, outch->ch0,
+			outch->pong.ch_paddr[0]);
+
+		if (vfe40_ctrl->share_ctrl->operation_mode !=
+			VFE_OUTPUTS_RAW) {
+			vfe40_put_ch_ping_addr(
+				vfe40_ctrl->share_ctrl->vfebase, outch->ch1,
+				outch->ping.ch_paddr[1]);
+			vfe40_put_ch_pong_addr(
+				vfe40_ctrl->share_ctrl->vfebase, outch->ch1,
+				outch->pong.ch_paddr[1]);
+		}
+
+		if (outch->ping.num_planes > 2)
+			vfe40_put_ch_ping_addr(
+				vfe40_ctrl->share_ctrl->vfebase, outch->ch2,
+				outch->ping.ch_paddr[2]);
+		if (outch->pong.num_planes > 2)
+			vfe40_put_ch_pong_addr(
+				vfe40_ctrl->share_ctrl->vfebase, outch->ch2,
+				outch->pong.ch_paddr[2]);
+
+		/* avoid stale info */
+		memset(&outch->ping, 0, sizeof(struct msm_free_buf));
+		memset(&outch->pong, 0, sizeof(struct msm_free_buf));
+	} else {
+		pr_err("%s ping/pong addr is null!!", __func__);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static void vfe40_write_linear_cfg(
+	enum VFE40_DMI_RAM_SEL channel_sel,
+	const uint32_t *tbl, struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	uint32_t i;
+
+	vfe40_program_dmi_cfg(channel_sel, vfe40_ctrl);
+	/* for loop for configuring LUT. */
+	for (i = 0 ; i < VFE40_LINEARIZATON_TABLE_LENGTH ; i++) {
+		msm_camera_io_w(*tbl,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
+		tbl++;
+	}
+	CDBG("done writing to linearization table\n");
+	vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+}
+
+void vfe40_send_isp_msg(
+	struct v4l2_subdev *sd,
+	uint32_t vfeFrameId,
+	uint32_t isp_msg_id)
+{
+	struct isp_msg_event isp_msg_evt;
+
+	isp_msg_evt.msg_id = isp_msg_id;
+	isp_msg_evt.sof_count = vfeFrameId;
+	v4l2_subdev_notify(sd,
+			NOTIFY_ISP_MSG_EVT,
+			(void *)&isp_msg_evt);
+}
+
+static int vfe40_proc_general(
+	struct msm_cam_media_controller *pmctl,
+	struct msm_isp_cmd *cmd,
+	struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	int i , rc = 0;
+	uint32_t old_val = 0 , new_val = 0;
+	uint32_t *cmdp = NULL;
+	uint32_t *cmdp_local = NULL;
+	uint32_t snapshot_cnt = 0;
+	uint32_t temp1 = 0, temp2 = 0;
+
+	CDBG("vfe40_proc_general: cmdID = %s, length = %d\n",
+		vfe40_general_cmd[cmd->id], cmd->length);
+	switch (cmd->id) {
+	case VFE_CMD_RESET:
+		CDBG("vfe40_proc_general: cmdID = %s\n",
+			vfe40_general_cmd[cmd->id]);
+		vfe40_reset(vfe40_ctrl);
+		break;
+	case VFE_CMD_START:
+		CDBG("vfe40_proc_general: cmdID = %s\n",
+			vfe40_general_cmd[cmd->id]);
+		if ((vfe40_ctrl->share_ctrl->operation_mode ==
+				VFE_OUTPUTS_PREVIEW_AND_VIDEO) ||
+				(vfe40_ctrl->share_ctrl->operation_mode ==
+				VFE_OUTPUTS_PREVIEW))
+			/* Configure primary channel */
+			rc = vfe40_configure_pingpong_buffers(
+				VFE_MSG_START, VFE_MSG_OUTPUT_PRIMARY,
+				vfe40_ctrl);
+		else
+			/* Configure secondary channel */
+			rc = vfe40_configure_pingpong_buffers(
+				VFE_MSG_START, VFE_MSG_OUTPUT_SECONDARY,
+				vfe40_ctrl);
+		if (rc < 0) {
+			pr_err(
+				"%s error configuring pingpong buffers for preview",
+				__func__);
+			rc = -EINVAL;
+			goto proc_general_done;
+		}
+
+		rc = vfe40_start(pmctl, vfe40_ctrl);
+		break;
+	case VFE_CMD_UPDATE:
+		vfe40_update(vfe40_ctrl);
+		break;
+	case VFE_CMD_CAPTURE_RAW:
+		CDBG("%s: cmdID = VFE_CMD_CAPTURE_RAW\n", __func__);
+		if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value),
+				sizeof(uint32_t))) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		rc = vfe40_configure_pingpong_buffers(
+			VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_PRIMARY,
+			vfe40_ctrl);
+		if (rc < 0) {
+			pr_err(
+				"%s error configuring pingpong buffers for snapshot",
+				__func__);
+			rc = -EINVAL;
+			goto proc_general_done;
+		}
+		rc = vfe40_capture_raw(pmctl, vfe40_ctrl, snapshot_cnt);
+		break;
+	case VFE_CMD_CAPTURE:
+		if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value),
+				sizeof(uint32_t))) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+
+		if (vfe40_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_JPEG_AND_THUMB ||
+		vfe40_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_THUMB_AND_JPEG) {
+			if (snapshot_cnt != 1) {
+				pr_err("only support 1 inline snapshot\n");
+				rc = -EINVAL;
+				goto proc_general_done;
+			}
+			/* Configure primary channel for JPEG */
+			rc = vfe40_configure_pingpong_buffers(
+				VFE_MSG_JPEG_CAPTURE,
+				VFE_MSG_OUTPUT_PRIMARY,
+				vfe40_ctrl);
+		} else {
+			/* Configure primary channel */
+			rc = vfe40_configure_pingpong_buffers(
+				VFE_MSG_CAPTURE,
+				VFE_MSG_OUTPUT_PRIMARY,
+				vfe40_ctrl);
+		}
+		if (rc < 0) {
+			pr_err(
+			"%s error configuring pingpong buffers for primary output",
+			__func__);
+			rc = -EINVAL;
+			goto proc_general_done;
+		}
+		/* Configure secondary channel */
+		rc = vfe40_configure_pingpong_buffers(
+				VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_SECONDARY,
+				vfe40_ctrl);
+		if (rc < 0) {
+			pr_err(
+			"%s error configuring pingpong buffers for secondary output",
+			__func__);
+			rc = -EINVAL;
+			goto proc_general_done;
+		}
+		rc = vfe40_capture(pmctl, snapshot_cnt, vfe40_ctrl);
+		break;
+	case VFE_CMD_START_RECORDING:
+		CDBG("vfe40_proc_general: cmdID = %s\n",
+			vfe40_general_cmd[cmd->id]);
+		if (vfe40_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_PREVIEW_AND_VIDEO)
+			rc = vfe40_configure_pingpong_buffers(
+				VFE_MSG_START_RECORDING,
+				VFE_MSG_OUTPUT_SECONDARY,
+				vfe40_ctrl);
+		else if (vfe40_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_VIDEO_AND_PREVIEW)
+			rc = vfe40_configure_pingpong_buffers(
+				VFE_MSG_START_RECORDING,
+				VFE_MSG_OUTPUT_PRIMARY,
+				vfe40_ctrl);
+		if (rc < 0) {
+			pr_err(
+				"%s error configuring pingpong buffers for video\n",
+				__func__);
+			rc = -EINVAL;
+			goto proc_general_done;
+		}
+		rc = vfe40_start_recording(pmctl, vfe40_ctrl);
+		break;
+	case VFE_CMD_STOP_RECORDING:
+		CDBG("vfe40_proc_general: cmdID = %s\n",
+			vfe40_general_cmd[cmd->id]);
+		rc = vfe40_stop_recording(pmctl, vfe40_ctrl);
+		break;
+	case VFE_CMD_OPERATION_CFG: {
+		if (cmd->length != V40_OPERATION_CFG_LEN) {
+			rc = -EINVAL;
+			goto proc_general_done;
+		}
+		cmdp = kmalloc(V40_OPERATION_CFG_LEN, GFP_ATOMIC);
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			V40_OPERATION_CFG_LEN)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		rc = vfe40_operation_config(cmdp, vfe40_ctrl);
+		}
+		break;
+
+	case VFE_CMD_STATS_AE_START: {
+		rc = vfe_stats_aec_buf_init(vfe40_ctrl, NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of AEC",
+				 __func__);
+			goto proc_general_done;
+		}
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val |= BG_ENABLE_MASK;
+		msm_camera_io_w(old_val,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_cmd[cmd->id].offset,
+			cmdp, (vfe40_cmd[cmd->id].length));
+		}
+		break;
+	case VFE_CMD_STATS_AF_START: {
+		rc = vfe_stats_af_buf_init(vfe40_ctrl, NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of AF",
+				__func__);
+			goto proc_general_done;
+		}
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
+			VFE_MODULE_CFG);
+		old_val |= BF_ENABLE_MASK;
+		msm_camera_io_w(old_val,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_cmd[cmd->id].offset,
+			cmdp, (vfe40_cmd[cmd->id].length));
+		}
+		break;
+
+	case VFE_CMD_STATS_AWB_START: {
+		rc = vfe_stats_awb_buf_init(vfe40_ctrl, NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of AWB",
+				 __func__);
+			goto proc_general_done;
+		}
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val |= AWB_ENABLE_MASK;
+		msm_camera_io_w(old_val,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_cmd[cmd->id].offset,
+			cmdp, (vfe40_cmd[cmd->id].length));
+		}
+		break;
+
+	case VFE_CMD_STATS_IHIST_START: {
+		rc = vfe_stats_ihist_buf_init(vfe40_ctrl, NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of IHIST",
+				 __func__);
+			goto proc_general_done;
+		}
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val |= IHIST_ENABLE_MASK;
+		msm_camera_io_w(old_val,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_cmd[cmd->id].offset,
+			cmdp, (vfe40_cmd[cmd->id].length));
+		}
+		break;
+
+
+	case VFE_CMD_STATS_RS_START: {
+		rc = vfe_stats_rs_buf_init(vfe40_ctrl, NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of RS",
+				__func__);
+			goto proc_general_done;
+		}
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_cmd[cmd->id].offset,
+			cmdp, (vfe40_cmd[cmd->id].length));
+		}
+		break;
+
+	case VFE_CMD_STATS_CS_START: {
+		rc = vfe_stats_cs_buf_init(vfe40_ctrl, NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of CS",
+				__func__);
+			goto proc_general_done;
+		}
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_cmd[cmd->id].offset,
+			cmdp, (vfe40_cmd[cmd->id].length));
+		}
+		break;
+
+	case VFE_CMD_MCE_UPDATE:
+	case VFE_CMD_MCE_CFG:{
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		/* Incrementing with 4 so as to point to the 2nd Register as
+		the 2nd register has the mce_enable bit */
+		old_val = msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
+			V40_CHROMA_SUP_OFF + 4);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		new_val = *cmdp_local;
+		old_val &= MCE_EN_MASK;
+		new_val = new_val | old_val;
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			V40_CHROMA_SUP_OFF + 4, &new_val, 4);
+		cmdp_local += 1;
+
+		old_val = msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
+			V40_CHROMA_SUP_OFF + 8);
+		new_val = *cmdp_local;
+		old_val &= MCE_Q_K_MASK;
+		new_val = new_val | old_val;
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			V40_CHROMA_SUP_OFF + 8, &new_val, 4);
+		cmdp_local += 1;
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_cmd[cmd->id].offset,
+			cmdp_local, (vfe40_cmd[cmd->id].length));
+		}
+		break;
+	case VFE_CMD_CHROMA_SUP_UPDATE:
+	case VFE_CMD_CHROMA_SUP_CFG:{
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		msm_camera_io_memcpy(vfe40_ctrl->share_ctrl->vfebase +
+			V40_CHROMA_SUP_OFF, cmdp_local, 4);
+
+		cmdp_local += 1;
+		new_val = *cmdp_local;
+		/* Incrementing with 4 so as to point to the 2nd Register as
+		 * the 2nd register has the mce_enable bit
+		 */
+		old_val = msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
+			V40_CHROMA_SUP_OFF + 4);
+		old_val &= ~MCE_EN_MASK;
+		new_val = new_val | old_val;
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			V40_CHROMA_SUP_OFF + 4, &new_val, 4);
+		cmdp_local += 1;
+
+		old_val = msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
+			V40_CHROMA_SUP_OFF + 8);
+		new_val = *cmdp_local;
+		old_val &= ~MCE_Q_K_MASK;
+		new_val = new_val | old_val;
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			V40_CHROMA_SUP_OFF + 8, &new_val, 4);
+		}
+		break;
+	case VFE_CMD_BLACK_LEVEL_CFG:
+		rc = -EFAULT;
+		goto proc_general_done;
+
+	case VFE_CMD_LA_CFG:
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_cmd[cmd->id].offset,
+			cmdp_local, (vfe40_cmd[cmd->id].length));
+
+		cmdp_local += 1;
+		vfe40_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0,
+						   cmdp_local, vfe40_ctrl);
+		break;
+
+	case VFE_CMD_LA_UPDATE: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+
+		cmdp_local = cmdp + 1;
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + V40_LA_OFF);
+		if (old_val != 0x0)
+			vfe40_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0,
+				cmdp_local, vfe40_ctrl);
+		else
+			vfe40_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK1,
+				cmdp_local, vfe40_ctrl);
+		}
+		vfe40_ctrl->update_la = true;
+		break;
+
+	case VFE_CMD_GET_LA_TABLE:
+		temp1 = sizeof(uint32_t) * VFE40_LA_TABLE_LENGTH / 2;
+		if (cmd->length != temp1) {
+			rc = -EINVAL;
+			goto proc_general_done;
+		}
+		cmdp = kzalloc(temp1, GFP_KERNEL);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		if (msm_camera_io_r(vfe40_ctrl->
+				share_ctrl->vfebase + V40_LA_OFF))
+			vfe40_program_dmi_cfg(LUMA_ADAPT_LUT_RAM_BANK1,
+						vfe40_ctrl);
+		else
+			vfe40_program_dmi_cfg(LUMA_ADAPT_LUT_RAM_BANK0,
+						vfe40_ctrl);
+		for (i = 0 ; i < (VFE40_LA_TABLE_LENGTH / 2) ; i++) {
+			*cmdp_local =
+				msm_camera_io_r(
+					vfe40_ctrl->share_ctrl->vfebase +
+					VFE_DMI_DATA_LO);
+			*cmdp_local |= (msm_camera_io_r(
+				vfe40_ctrl->share_ctrl->vfebase +
+				VFE_DMI_DATA_LO)) << 16;
+			cmdp_local++;
+		}
+		vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+		if (copy_to_user((void __user *)(cmd->value), cmdp,
+			temp1)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		break;
+	case VFE_CMD_SK_ENHAN_CFG:
+	case VFE_CMD_SK_ENHAN_UPDATE:{
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase + V40_SCE_OFF,
+			cmdp, V40_SCE_LEN);
+		}
+		break;
+
+	case VFE_CMD_LIVESHOT:
+		/* Configure primary channel */
+		rc = vfe40_configure_pingpong_buffers(VFE_MSG_CAPTURE,
+					VFE_MSG_OUTPUT_PRIMARY, vfe40_ctrl);
+		if (rc < 0) {
+			pr_err(
+			"%s error configuring pingpong buffers for primary output\n",
+			__func__);
+			rc = -EINVAL;
+			goto proc_general_done;
+		}
+		vfe40_start_liveshot(pmctl, vfe40_ctrl);
+		break;
+
+	case VFE_CMD_LINEARIZATION_CFG:
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			V40_LINEARIZATION_OFF1,
+			cmdp_local, V40_LINEARIZATION_LEN1);
+
+		cmdp_local = cmdp + 17;
+		vfe40_write_linear_cfg(BLACK_LUT_RAM_BANK0,
+					cmdp_local, vfe40_ctrl);
+		break;
+
+	case VFE_CMD_LINEARIZATION_UPDATE:
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		cmdp_local++;
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			V40_LINEARIZATION_OFF1 + 4,
+			cmdp_local, (V40_LINEARIZATION_LEN1 - 4));
+		cmdp_local = cmdp + 17;
+		/*extracting the bank select*/
+		old_val = msm_camera_io_r(
+				vfe40_ctrl->share_ctrl->vfebase +
+				V40_LINEARIZATION_OFF1);
+
+		if (old_val != 0x0)
+			vfe40_write_linear_cfg(BLACK_LUT_RAM_BANK0,
+						cmdp_local, vfe40_ctrl);
+		else
+			vfe40_write_linear_cfg(BLACK_LUT_RAM_BANK1,
+						cmdp_local, vfe40_ctrl);
+		vfe40_ctrl->update_linear = true;
+		break;
+
+	case VFE_CMD_GET_LINEARIZATON_TABLE:
+		temp1 = sizeof(uint32_t) * VFE40_LINEARIZATON_TABLE_LENGTH;
+		if (cmd->length != temp1) {
+			rc = -EINVAL;
+			goto proc_general_done;
+		}
+		cmdp = kzalloc(temp1, GFP_KERNEL);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		if (msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase +
+			V40_LINEARIZATION_OFF1))
+			vfe40_program_dmi_cfg(BLACK_LUT_RAM_BANK1, vfe40_ctrl);
+		else
+			vfe40_program_dmi_cfg(BLACK_LUT_RAM_BANK0, vfe40_ctrl);
+		CDBG("%s: Linearization Table\n", __func__);
+		for (i = 0 ; i < VFE40_LINEARIZATON_TABLE_LENGTH ; i++) {
+			*cmdp_local = msm_camera_io_r(
+				vfe40_ctrl->share_ctrl->vfebase +
+				VFE_DMI_DATA_LO);
+			CDBG("%s: %08x\n", __func__, *cmdp_local);
+			cmdp_local++;
+		}
+		vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+		if (copy_to_user((void __user *)(cmd->value), cmdp,
+			temp1)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		break;
+	case VFE_CMD_DEMOSAICV3:
+		if (cmd->length !=
+			V40_DEMOSAICV3_0_LEN+V40_DEMOSAICV3_1_LEN) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		new_val = *cmdp_local;
+
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF);
+		old_val &= DEMOSAIC_MASK;
+		new_val = new_val | old_val;
+		*cmdp_local = new_val;
+
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF,
+			cmdp_local, V40_DEMOSAICV3_0_LEN);
+		cmdp_local += 1;
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_1_OFF,
+			cmdp_local, V40_DEMOSAICV3_1_LEN);
+		break;
+
+	case VFE_CMD_DEMOSAICV3_UPDATE:
+		if (cmd->length !=
+			V40_DEMOSAICV3_0_LEN * V40_DEMOSAICV3_UP_REG_CNT) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		new_val = *cmdp_local;
+
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF);
+		old_val &= DEMOSAIC_MASK;
+		new_val = new_val | old_val;
+		*cmdp_local = new_val;
+
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF,
+			cmdp_local, V40_DEMOSAICV3_0_LEN);
+		/* As the address space is not contiguous increment by 2
+		 * before copying to next address space */
+		cmdp_local += 1;
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_1_OFF,
+			cmdp_local, 2 * V40_DEMOSAICV3_0_LEN);
+		/* As the address space is not contiguous increment by 2
+		 * before copying to next address space */
+		cmdp_local += 2;
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_2_OFF,
+			cmdp_local, 2 * V40_DEMOSAICV3_0_LEN);
+		break;
+
+	case VFE_CMD_DEMOSAICV3_ABCC_CFG:
+		rc = -EFAULT;
+		break;
+
+	case VFE_CMD_DEMOSAICV3_ABF_UPDATE:/* 116 ABF update  */
+	case VFE_CMD_DEMOSAICV3_ABF_CFG: { /* 108 ABF config  */
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		new_val = *cmdp_local;
+
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF);
+		old_val &= ABF_MASK;
+		new_val = new_val | old_val;
+		*cmdp_local = new_val;
+
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF,
+			cmdp_local, 4);
+
+		cmdp_local += 1;
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_cmd[cmd->id].offset,
+			cmdp_local, (vfe40_cmd[cmd->id].length));
+		}
+		break;
+
+	case VFE_CMD_DEMOSAICV3_DBCC_CFG:
+	case VFE_CMD_DEMOSAICV3_DBCC_UPDATE:
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		new_val = *cmdp_local;
+
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF);
+		old_val &= DBCC_MASK;
+
+		new_val = new_val | old_val;
+		*cmdp_local = new_val;
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF,
+			cmdp_local, 4);
+		cmdp_local += 1;
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_cmd[cmd->id].offset,
+			cmdp_local, (vfe40_cmd[cmd->id].length));
+		break;
+
+	case VFE_CMD_DEMOSAICV3_DBPC_CFG:
+	case VFE_CMD_DEMOSAICV3_DBPC_UPDATE:
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+		new_val = *cmdp_local;
+
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF);
+		old_val &= DBPC_MASK;
+
+		new_val = new_val | old_val;
+		*cmdp_local = new_val;
+		msm_camera_io_memcpy(vfe40_ctrl->share_ctrl->vfebase +
+			V40_DEMOSAICV3_0_OFF,
+			cmdp_local, V40_DEMOSAICV3_0_LEN);
+		cmdp_local += 1;
+		msm_camera_io_memcpy(vfe40_ctrl->share_ctrl->vfebase +
+			V40_DEMOSAICV3_DBPC_CFG_OFF,
+			cmdp_local, V40_DEMOSAICV3_DBPC_LEN);
+		cmdp_local += 1;
+		msm_camera_io_memcpy(vfe40_ctrl->share_ctrl->vfebase +
+			V40_DEMOSAICV3_DBPC_CFG_OFF0,
+			cmdp_local, V40_DEMOSAICV3_DBPC_LEN);
+		cmdp_local += 1;
+		msm_camera_io_memcpy(vfe40_ctrl->share_ctrl->vfebase +
+			V40_DEMOSAICV3_DBPC_CFG_OFF1,
+			cmdp_local, V40_DEMOSAICV3_DBPC_LEN);
+		cmdp_local += 1;
+		msm_camera_io_memcpy(vfe40_ctrl->share_ctrl->vfebase +
+			V40_DEMOSAICV3_DBPC_CFG_OFF2,
+			cmdp_local, V40_DEMOSAICV3_DBPC_LEN);
+		break;
+
+	case VFE_CMD_RGB_G_CFG: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase + V40_RGB_G_OFF,
+			cmdp, 4);
+		cmdp += 1;
+
+		vfe40_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0, cmdp, vfe40_ctrl);
+		vfe40_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0, cmdp, vfe40_ctrl);
+		vfe40_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0, cmdp, vfe40_ctrl);
+		}
+	    cmdp -= 1;
+		break;
+
+	case VFE_CMD_RGB_G_UPDATE: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + V40_RGB_G_OFF);
+		cmdp += 1;
+		if (old_val != 0x0) {
+			vfe40_write_gamma_cfg(
+				RGBLUT_RAM_CH0_BANK0, cmdp, vfe40_ctrl);
+			vfe40_write_gamma_cfg(
+				RGBLUT_RAM_CH1_BANK0, cmdp, vfe40_ctrl);
+			vfe40_write_gamma_cfg(
+				RGBLUT_RAM_CH2_BANK0, cmdp, vfe40_ctrl);
+		} else {
+			vfe40_write_gamma_cfg(
+				RGBLUT_RAM_CH0_BANK1, cmdp, vfe40_ctrl);
+			vfe40_write_gamma_cfg(
+				RGBLUT_RAM_CH1_BANK1, cmdp, vfe40_ctrl);
+			vfe40_write_gamma_cfg(
+				RGBLUT_RAM_CH2_BANK1, cmdp, vfe40_ctrl);
+		}
+		}
+		vfe40_ctrl->update_gamma = TRUE;
+		cmdp -= 1;
+		break;
+
+	case VFE_CMD_GET_RGB_G_TABLE:
+		temp1 = sizeof(uint32_t) * VFE40_GAMMA_NUM_ENTRIES * 3;
+		if (cmd->length != temp1) {
+			rc = -EINVAL;
+			goto proc_general_done;
+		}
+		cmdp = kzalloc(temp1, GFP_KERNEL);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		cmdp_local = cmdp;
+
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + V40_RGB_G_OFF);
+		temp2 = old_val ? RGBLUT_RAM_CH0_BANK1 :
+			RGBLUT_RAM_CH0_BANK0;
+		for (i = 0; i < 3; i++) {
+			vfe40_read_gamma_cfg(temp2,
+				cmdp_local + (VFE40_GAMMA_NUM_ENTRIES * i),
+				vfe40_ctrl);
+			temp2 += 2;
+		}
+		if (copy_to_user((void __user *)(cmd->value), cmdp,
+			temp1)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		break;
+
+	case VFE_CMD_STATS_AWB_STOP: {
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= ~AWB_ENABLE_MASK;
+		msm_camera_io_w(old_val,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		}
+		break;
+
+	case VFE_CMD_STATS_AE_STOP: {
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= ~BG_ENABLE_MASK;
+		msm_camera_io_w(old_val,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		}
+		break;
+	case VFE_CMD_STATS_AF_STOP: {
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= ~BF_ENABLE_MASK;
+		msm_camera_io_w(old_val,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		rc = vfe40_stats_flush_enqueue(vfe40_ctrl, MSM_STATS_TYPE_AF);
+		if (rc < 0) {
+			pr_err("%s: dq stats buf err = %d",
+				   __func__, rc);
+			return -EINVAL;
+		}
+		}
+		break;
+
+	case VFE_CMD_STATS_IHIST_STOP: {
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= ~IHIST_ENABLE_MASK;
+		msm_camera_io_w(old_val,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		}
+		break;
+
+	case VFE_CMD_STATS_RS_STOP: {
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= ~RS_ENABLE_MASK;
+		msm_camera_io_w(old_val,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		}
+		break;
+
+	case VFE_CMD_STATS_CS_STOP: {
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= ~CS_ENABLE_MASK;
+		msm_camera_io_w(old_val,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		}
+		break;
+	case VFE_CMD_STOP:
+		CDBG("vfe40_proc_general: cmdID = %s\n",
+			vfe40_general_cmd[cmd->id]);
+		vfe40_stop(vfe40_ctrl);
+		break;
+
+	case VFE_CMD_SYNC_TIMER_SETTING:
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		vfe40_sync_timer_start(cmdp, vfe40_ctrl);
+		break;
+
+	case VFE_CMD_MODULE_CFG: {
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp,
+			(void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		*cmdp &= ~STATS_ENABLE_MASK;
+		old_val = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		old_val &= STATS_ENABLE_MASK;
+		*cmdp |= old_val;
+
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_cmd[cmd->id].offset,
+			cmdp, (vfe40_cmd[cmd->id].length));
+		}
+		break;
+
+	case VFE_CMD_ZSL:
+		rc = vfe40_configure_pingpong_buffers(VFE_MSG_START,
+			VFE_MSG_OUTPUT_PRIMARY, vfe40_ctrl);
+		if (rc < 0)
+			goto proc_general_done;
+		rc = vfe40_configure_pingpong_buffers(VFE_MSG_START,
+			VFE_MSG_OUTPUT_SECONDARY, vfe40_ctrl);
+		if (rc < 0)
+			goto proc_general_done;
+
+		rc = vfe40_zsl(pmctl, vfe40_ctrl);
+		break;
+
+	case VFE_CMD_ASF_CFG:
+	case VFE_CMD_ASF_UPDATE:
+		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		if (copy_from_user(cmdp, (void __user *)(cmd->value),
+			cmd->length)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_cmd[cmd->id].offset,
+			cmdp, (vfe40_cmd[cmd->id].length));
+		cmdp_local = cmdp + V40_ASF_LEN/4;
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			V40_ASF_SPECIAL_EFX_CFG_OFF,
+			cmdp_local, V40_ASF_SPECIAL_EFX_CFG_LEN);
+		break;
+
+	case VFE_CMD_GET_HW_VERSION:
+		if (cmd->length != V40_GET_HW_VERSION_LEN) {
+			rc = -EINVAL;
+			goto proc_general_done;
+		}
+		cmdp = kmalloc(V40_GET_HW_VERSION_LEN, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		*cmdp = msm_camera_io_r(
+			vfe40_ctrl->share_ctrl->vfebase+V40_GET_HW_VERSION_OFF);
+		if (copy_to_user((void __user *)(cmd->value), cmdp,
+			V40_GET_HW_VERSION_LEN)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		break;
+	case VFE_CMD_GET_REG_DUMP:
+		temp1 = sizeof(uint32_t) *
+			vfe40_ctrl->share_ctrl->register_total;
+		if (cmd->length != temp1) {
+			rc = -EINVAL;
+			goto proc_general_done;
+		}
+		cmdp = kmalloc(temp1, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+		msm_camera_io_dump(vfe40_ctrl->share_ctrl->vfebase,
+			vfe40_ctrl->share_ctrl->register_total*4);
+		CDBG("%s: %p %p %d\n", __func__, (void *)cmdp,
+			vfe40_ctrl->share_ctrl->vfebase, temp1);
+		memcpy_fromio((void *)cmdp,
+			vfe40_ctrl->share_ctrl->vfebase, temp1);
+		if (copy_to_user((void __user *)(cmd->value), cmdp, temp1)) {
+			rc = -EFAULT;
+			goto proc_general_done;
+		}
+		break;
+	case VFE_CMD_FRAME_SKIP_CFG:
+		if (cmd->length != vfe40_cmd[cmd->id].length)
+			return -EINVAL;
+
+		cmdp = kmalloc(vfe40_cmd[cmd->id].length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+
+		if (copy_from_user((cmdp), (void __user *)cmd->value,
+				cmd->length)) {
+			rc = -EFAULT;
+			pr_err("%s copy from user failed for cmd %d",
+				__func__, cmd->id);
+			break;
+		}
+
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_cmd[cmd->id].offset,
+			cmdp, (vfe40_cmd[cmd->id].length));
+		vfe40_ctrl->frame_skip_cnt = ((uint32_t)
+			*cmdp & VFE_FRAME_SKIP_PERIOD_MASK) + 1;
+		vfe40_ctrl->frame_skip_pattern = (uint32_t)(*(cmdp + 2));
+		break;
+	default:
+		if (cmd->length != vfe40_cmd[cmd->id].length)
+			return -EINVAL;
+
+		cmdp = kmalloc(vfe40_cmd[cmd->id].length, GFP_ATOMIC);
+		if (!cmdp) {
+			rc = -ENOMEM;
+			goto proc_general_done;
+		}
+
+		if (copy_from_user((cmdp), (void __user *)cmd->value,
+				cmd->length)) {
+			rc = -EFAULT;
+			pr_err("%s copy from user failed for cmd %d",
+				__func__, cmd->id);
+			goto proc_general_done;
+		}
+		msm_camera_io_memcpy(
+			vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_cmd[cmd->id].offset,
+			cmdp, (vfe40_cmd[cmd->id].length));
+		break;
+
+	}
+
+proc_general_done:
+	kfree(cmdp);
+
+	return rc;
+}
+
+static inline void vfe40_read_irq_status(
+	struct axi_ctrl_t *axi_ctrl, struct vfe40_irq_status *out)
+{
+	uint32_t *temp;
+	memset(out, 0, sizeof(struct vfe40_irq_status));
+	temp = (uint32_t *)(axi_ctrl->share_ctrl->vfebase + VFE_IRQ_STATUS_0);
+	out->vfeIrqStatus0 = msm_camera_io_r(temp);
+
+	temp = (uint32_t *)(axi_ctrl->share_ctrl->vfebase + VFE_IRQ_STATUS_1);
+	out->vfeIrqStatus1 = msm_camera_io_r(temp);
+
+	temp = (uint32_t *)(axi_ctrl->share_ctrl->vfebase + VFE_CAMIF_STATUS);
+	out->camifStatus = msm_camera_io_r(temp);
+	CDBG("camifStatus  = 0x%x\n", out->camifStatus);
+
+	/* clear the pending interrupt of the same kind.*/
+	msm_camera_io_w(out->vfeIrqStatus0,
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+	msm_camera_io_w(out->vfeIrqStatus1,
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_camera_io_w_mb(1, axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
+
+}
+
+static void vfe40_process_reg_update_irq(
+		struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	unsigned long flags;
+
+	if (vfe40_ctrl->recording_state == VFE_STATE_START_REQUESTED) {
+		if (vfe40_ctrl->share_ctrl->operation_mode ==
+				VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
+			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				share_ctrl->outpath.out0.ch0]);
+			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				share_ctrl->outpath.out0.ch1]);
+		} else if (vfe40_ctrl->share_ctrl->operation_mode ==
+				VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
+			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				share_ctrl->outpath.out1.ch0]);
+			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				share_ctrl->outpath.out1.ch1]);
+		}
+		vfe40_ctrl->recording_state = VFE_STATE_STARTED;
+		msm_camera_io_w_mb(1,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+		CDBG("start video triggered .\n");
+	} else if (vfe40_ctrl->recording_state ==
+			VFE_STATE_STOP_REQUESTED) {
+		if (vfe40_ctrl->share_ctrl->operation_mode ==
+				VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
+			msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				share_ctrl->outpath.out0.ch0]);
+			msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				share_ctrl->outpath.out0.ch1]);
+		} else if (vfe40_ctrl->share_ctrl->operation_mode ==
+				VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
+			msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				share_ctrl->outpath.out1.ch0]);
+			msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				share_ctrl->outpath.out1.ch1]);
+		}
+		CDBG("stop video triggered .\n");
+	}
+
+	if (vfe40_ctrl->start_ack_pending == TRUE) {
+		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+			vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_START_ACK);
+		vfe40_ctrl->start_ack_pending = FALSE;
+	} else {
+		if (vfe40_ctrl->recording_state ==
+				VFE_STATE_STOP_REQUESTED) {
+			vfe40_ctrl->recording_state = VFE_STATE_STOPPED;
+			/* request a reg update and send STOP_REC_ACK
+			 * when we process the next reg update irq.
+			 */
+			msm_camera_io_w_mb(1,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+		} else if (vfe40_ctrl->recording_state ==
+					VFE_STATE_STOPPED) {
+			vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+				vfe40_ctrl->share_ctrl->vfeFrameId,
+				MSG_ID_STOP_REC_ACK);
+			vfe40_ctrl->recording_state = VFE_STATE_IDLE;
+		}
+		spin_lock_irqsave(&vfe40_ctrl->update_ack_lock, flags);
+		if (vfe40_ctrl->update_ack_pending == TRUE) {
+			vfe40_ctrl->update_ack_pending = FALSE;
+			spin_unlock_irqrestore(
+				&vfe40_ctrl->update_ack_lock, flags);
+			vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+				vfe40_ctrl->share_ctrl->vfeFrameId,
+				MSG_ID_UPDATE_ACK);
+		} else {
+			spin_unlock_irqrestore(
+				&vfe40_ctrl->update_ack_lock, flags);
+		}
+	}
+
+	if (vfe40_ctrl->share_ctrl->liveshot_state ==
+		VFE_STATE_START_REQUESTED) {
+		CDBG("%s enabling liveshot output\n", __func__);
+		if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+				VFE40_OUTPUT_MODE_PRIMARY) {
+			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				share_ctrl->outpath.out0.ch0]);
+			msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
+			vfe40_AXI_WM_CFG[vfe40_ctrl->
+				share_ctrl->outpath.out0.ch1]);
+			vfe40_ctrl->share_ctrl->liveshot_state =
+				VFE_STATE_STARTED;
+		}
+	}
+
+	if (vfe40_ctrl->share_ctrl->liveshot_state == VFE_STATE_STARTED) {
+		vfe40_ctrl->share_ctrl->vfe_capture_count--;
+		if (!vfe40_ctrl->share_ctrl->vfe_capture_count)
+			vfe40_ctrl->share_ctrl->liveshot_state =
+				VFE_STATE_STOP_REQUESTED;
+		msm_camera_io_w_mb(1, vfe40_ctrl->
+			share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+	} else if (vfe40_ctrl->share_ctrl->liveshot_state ==
+			VFE_STATE_STOP_REQUESTED) {
+		CDBG("%s: disabling liveshot output\n", __func__);
+		if (vfe40_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_PRIMARY) {
+			msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				share_ctrl->outpath.out0.ch0]);
+			msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[vfe40_ctrl->
+				share_ctrl->outpath.out0.ch1]);
+			vfe40_ctrl->share_ctrl->liveshot_state =
+				VFE_STATE_STOPPED;
+			msm_camera_io_w_mb(1, vfe40_ctrl->share_ctrl->vfebase +
+				VFE_REG_UPDATE_CMD);
+		}
+	} else if (vfe40_ctrl->share_ctrl->liveshot_state ==
+			VFE_STATE_STOPPED) {
+		vfe40_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
+	}
+
+	if ((vfe40_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_THUMB_AND_MAIN) ||
+		(vfe40_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_MAIN_AND_THUMB) ||
+		(vfe40_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_THUMB_AND_JPEG) ||
+		(vfe40_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_JPEG_AND_THUMB)) {
+		/* in snapshot mode */
+		/* later we need to add check for live snapshot mode. */
+		if (vfe40_ctrl->frame_skip_pattern & (0x1 <<
+			(vfe40_ctrl->snapshot_frame_cnt %
+				vfe40_ctrl->frame_skip_cnt))) {
+			vfe40_ctrl->share_ctrl->vfe_capture_count--;
+			/* if last frame to be captured: */
+			if (vfe40_ctrl->share_ctrl->vfe_capture_count == 0) {
+				/* stop the bus output:write master enable = 0*/
+				if (vfe40_ctrl->share_ctrl->outpath.output_mode
+					& VFE40_OUTPUT_MODE_PRIMARY) {
+					msm_camera_io_w(0,
+						vfe40_ctrl->share_ctrl->vfebase+
+						vfe40_AXI_WM_CFG[vfe40_ctrl->
+						share_ctrl->outpath.out0.ch0]);
+					msm_camera_io_w(0,
+						vfe40_ctrl->share_ctrl->vfebase+
+						vfe40_AXI_WM_CFG[vfe40_ctrl->
+						share_ctrl->outpath.out0.ch1]);
+				}
+				if (vfe40_ctrl->share_ctrl->outpath.output_mode&
+						VFE40_OUTPUT_MODE_SECONDARY) {
+					msm_camera_io_w(0,
+						vfe40_ctrl->share_ctrl->vfebase+
+						vfe40_AXI_WM_CFG[vfe40_ctrl->
+						share_ctrl->outpath.out1.ch0]);
+					msm_camera_io_w(0,
+						vfe40_ctrl->share_ctrl->vfebase+
+						vfe40_AXI_WM_CFG[vfe40_ctrl->
+						share_ctrl->outpath.out1.ch1]);
+				}
+				msm_camera_io_w_mb
+				(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+				vfe40_ctrl->share_ctrl->vfebase +
+				VFE_CAMIF_COMMAND);
+				vfe40_ctrl->snapshot_frame_cnt = -1;
+				vfe40_ctrl->frame_skip_cnt = 31;
+				vfe40_ctrl->frame_skip_pattern = 0xffffffff;
+			} /*if snapshot count is 0*/
+		} /*if frame is not being dropped*/
+		vfe40_ctrl->snapshot_frame_cnt++;
+		/* then do reg_update. */
+		msm_camera_io_w(1,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+	} /* if snapshot mode. */
+}
+
+static void vfe40_set_default_reg_values(
+			struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	msm_camera_io_w(0x800080,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_0);
+	msm_camera_io_w(0x800080,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_1);
+	/* What value should we program CGC_OVERRIDE to? */
+	msm_camera_io_w(0xFFFFF,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_CGC_OVERRIDE);
+
+	/* default frame drop period and pattern */
+	msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_ENC_MIN);
+	msm_camera_io_w(0xFFFFFF,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_ENC_MAX);
+	msm_camera_io_w(0,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_VIEW_MIN);
+	msm_camera_io_w(0xFFFFFF,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_VIEW_MAX);
+
+	/* stats UB config */
+	msm_camera_io_w(0x3980007,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_AEC_UB_CFG);
+	msm_camera_io_w(0x3A00007,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_AF_UB_CFG);
+	msm_camera_io_w(0x3A8000F,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_AWB_UB_CFG);
+	msm_camera_io_w(0x3B80007,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_RS_UB_CFG);
+	msm_camera_io_w(0x3C0001F,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_CS_UB_CFG);
+	msm_camera_io_w(0x3E0001F,
+		vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_HIST_UB_CFG);
+}
+
+static void vfe40_process_reset_irq(
+		struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	unsigned long flags;
+
+	atomic_set(&vfe40_ctrl->share_ctrl->vstate, 0);
+
+	spin_lock_irqsave(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
+	if (vfe40_ctrl->share_ctrl->stop_ack_pending) {
+		vfe40_ctrl->share_ctrl->stop_ack_pending = FALSE;
+		spin_unlock_irqrestore(
+			&vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
+		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+			vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_STOP_ACK);
+	} else {
+		spin_unlock_irqrestore(
+			&vfe40_ctrl->share_ctrl->stop_flag_lock, flags);
+		/* this is from reset command. */
+		vfe40_set_default_reg_values(vfe40_ctrl);
+
+		/* reload all write masters. (frame & line)*/
+		msm_camera_io_w(0x7FFF,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
+		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+			vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_RESET_ACK);
+	}
+}
+
+static void vfe40_process_camif_sof_irq(
+		struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	if (vfe40_ctrl->share_ctrl->operation_mode ==
+		VFE_OUTPUTS_RAW) {
+		if (vfe40_ctrl->start_ack_pending) {
+			vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+				vfe40_ctrl->share_ctrl->vfeFrameId,
+				MSG_ID_START_ACK);
+			vfe40_ctrl->start_ack_pending = FALSE;
+		}
+		vfe40_ctrl->share_ctrl->vfe_capture_count--;
+		/* if last frame to be captured: */
+		if (vfe40_ctrl->share_ctrl->vfe_capture_count == 0) {
+			/* Ensure the write order while writing
+			 to the command register using the barrier */
+			msm_camera_io_w_mb(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+			vfe40_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND);
+		}
+	} /* if raw snapshot mode. */
+	if ((vfe40_ctrl->hfr_mode != HFR_MODE_OFF) &&
+		(vfe40_ctrl->share_ctrl->operation_mode ==
+			VFE_MODE_OF_OPERATION_VIDEO) &&
+		(vfe40_ctrl->share_ctrl->vfeFrameId %
+			vfe40_ctrl->hfr_mode != 0)) {
+		vfe40_ctrl->share_ctrl->vfeFrameId++;
+		CDBG("Skip the SOF notification when HFR enabled\n");
+		return;
+	}
+	vfe40_ctrl->share_ctrl->vfeFrameId++;
+	vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+		vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_SOF_ACK);
+	CDBG("camif_sof_irq, frameId = %d\n",
+		vfe40_ctrl->share_ctrl->vfeFrameId);
+
+	if (vfe40_ctrl->sync_timer_state) {
+		if (vfe40_ctrl->sync_timer_repeat_count == 0)
+			vfe40_sync_timer_stop(vfe40_ctrl);
+		else
+			vfe40_ctrl->sync_timer_repeat_count--;
+	}
+}
+
+static void vfe40_process_error_irq(
+	struct axi_ctrl_t *axi_ctrl, uint32_t errStatus)
+{
+	uint32_t reg_value;
+
+	if (errStatus & VFE40_IMASK_CAMIF_ERROR) {
+		pr_err("vfe40_irq: camif errors\n");
+		reg_value = msm_camera_io_r(
+			axi_ctrl->share_ctrl->vfebase + VFE_CAMIF_STATUS);
+		pr_err("camifStatus  = 0x%x\n", reg_value);
+		vfe40_send_isp_msg(&axi_ctrl->subdev,
+			axi_ctrl->share_ctrl->vfeFrameId, MSG_ID_CAMIF_ERROR);
+	}
+
+	if (errStatus & VFE40_IMASK_BHIST_OVWR)
+		pr_err("vfe40_irq: stats bhist overwrite\n");
+
+	if (errStatus & VFE40_IMASK_STATS_CS_OVWR)
+		pr_err("vfe40_irq: stats cs overwrite\n");
+
+	if (errStatus & VFE40_IMASK_STATS_IHIST_OVWR)
+		pr_err("vfe40_irq: stats ihist overwrite\n");
+
+	if (errStatus & VFE40_IMASK_REALIGN_BUF_Y_OVFL)
+		pr_err("vfe40_irq: realign bug Y overflow\n");
+
+	if (errStatus & VFE40_IMASK_REALIGN_BUF_CB_OVFL)
+		pr_err("vfe40_irq: realign bug CB overflow\n");
+
+	if (errStatus & VFE40_IMASK_REALIGN_BUF_CR_OVFL)
+		pr_err("vfe40_irq: realign bug CR overflow\n");
+
+	if (errStatus & VFE40_IMASK_VIOLATION) {
+		pr_err("vfe40_irq: violation interrupt\n");
+		reg_value = msm_camera_io_r(
+			axi_ctrl->share_ctrl->vfebase + VFE_VIOLATION_STATUS);
+		pr_err("%s: violationStatus  = 0x%x\n", __func__, reg_value);
+	}
+
+	if (errStatus & VFE40_IMASK_IMG_MAST_0_BUS_OVFL)
+		pr_err("vfe40_irq: image master 0 bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_IMG_MAST_1_BUS_OVFL)
+		pr_err("vfe40_irq: image master 1 bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_IMG_MAST_2_BUS_OVFL)
+		pr_err("vfe40_irq: image master 2 bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_IMG_MAST_3_BUS_OVFL)
+		pr_err("vfe40_irq: image master 3 bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_IMG_MAST_4_BUS_OVFL)
+		pr_err("vfe40_irq: image master 4 bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_IMG_MAST_5_BUS_OVFL)
+		pr_err("vfe40_irq: image master 5 bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_IMG_MAST_6_BUS_OVFL)
+		pr_err("vfe40_irq: image master 6 bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_STATS_AE_BG_BUS_OVFL)
+		pr_err("vfe40_irq: ae/bg stats bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_STATS_AF_BF_BUS_OVFL)
+		pr_err("vfe40_irq: af/bf stats bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_STATS_AWB_BUS_OVFL)
+		pr_err("vfe40_irq: awb stats bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_STATS_RS_BUS_OVFL)
+		pr_err("vfe40_irq: rs stats bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_STATS_CS_BUS_OVFL)
+		pr_err("vfe40_irq: cs stats bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_STATS_IHIST_BUS_OVFL)
+		pr_err("vfe40_irq: ihist stats bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_STATS_SKIN_BHIST_BUS_OVFL)
+		pr_err("vfe40_irq: skin/bhist stats bus overflow\n");
+
+	if (errStatus & VFE40_IMASK_AXI_ERROR)
+		pr_err("vfe40_irq: axi error\n");
+}
+
+static uint32_t  vfe40_process_stats_irq_common(
+	struct vfe40_ctrl_type *vfe40_ctrl,
+	uint32_t statsNum, uint32_t newAddr)
+{
+	uint32_t pingpongStatus;
+	uint32_t returnAddr;
+	uint32_t pingpongAddr;
+
+	/* must be 0=ping, 1=pong */
+	pingpongStatus =
+		((msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
+		VFE_BUS_PING_PONG_STATUS))
+	& ((uint32_t)(1<<(statsNum + 7)))) >> (statsNum + 7);
+	/* stats bits starts at 7 */
+	CDBG("statsNum %d, pingpongStatus %d\n", statsNum, pingpongStatus);
+	pingpongAddr =
+		((uint32_t)(vfe40_ctrl->share_ctrl->vfebase +
+				VFE_BUS_STATS_PING_PONG_BASE)) +
+				(3*statsNum)*4 + (1-pingpongStatus)*4;
+	returnAddr = msm_camera_io_r((uint32_t *)pingpongAddr);
+	msm_camera_io_w(newAddr, (uint32_t *)pingpongAddr);
+	return returnAddr;
+}
+
+static void
+vfe_send_stats_msg(struct vfe40_ctrl_type *vfe40_ctrl,
+	uint32_t bufAddress, uint32_t statsNum)
+{
+	int rc = 0;
+	void *vaddr = NULL;
+	/* fill message with right content. */
+	/* @todo This is causing issues, need further investigate */
+	/* spin_lock_irqsave(&ctrl->state_lock, flags); */
+	struct isp_msg_stats msgStats;
+	msgStats.frameCounter = vfe40_ctrl->share_ctrl->vfeFrameId;
+	msgStats.buffer = bufAddress;
+
+	switch (statsNum) {
+	case statsAeNum:{
+		msgStats.id = MSG_ID_STATS_AEC;
+		rc = vfe40_ctrl->stats_ops.dispatch(
+				vfe40_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_AEC, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe40_ctrl->stats_ops.client);
+		}
+		break;
+	case statsAfNum:{
+		msgStats.id = MSG_ID_STATS_AF;
+		rc = vfe40_ctrl->stats_ops.dispatch(
+				vfe40_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_AF, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe40_ctrl->stats_ops.client);
+		}
+		break;
+	case statsAwbNum: {
+		msgStats.id = MSG_ID_STATS_AWB;
+		rc = vfe40_ctrl->stats_ops.dispatch(
+				vfe40_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_AWB, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe40_ctrl->stats_ops.client);
+		}
+		break;
+
+	case statsIhistNum: {
+		msgStats.id = MSG_ID_STATS_IHIST;
+		rc = vfe40_ctrl->stats_ops.dispatch(
+				vfe40_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_IHIST, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe40_ctrl->stats_ops.client);
+		}
+		break;
+	case statsRsNum: {
+		msgStats.id = MSG_ID_STATS_RS;
+		rc = vfe40_ctrl->stats_ops.dispatch(
+				vfe40_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_RS, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe40_ctrl->stats_ops.client);
+		}
+		break;
+	case statsCsNum: {
+		msgStats.id = MSG_ID_STATS_CS;
+		rc = vfe40_ctrl->stats_ops.dispatch(
+				vfe40_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_CS, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe40_ctrl->stats_ops.client);
+		}
+		break;
+
+	default:
+		goto stats_done;
+	}
+	if (rc == 0) {
+		msgStats.buffer = (uint32_t)vaddr;
+		v4l2_subdev_notify(&vfe40_ctrl->subdev,
+			NOTIFY_VFE_MSG_STATS,
+			&msgStats);
+	} else {
+		pr_err("%s: paddr to idx mapping error, stats_id = %d, paddr = 0x%d",
+			 __func__, msgStats.id, msgStats.buffer);
+	}
+stats_done:
+	spin_unlock_irqrestore(&ctrl->state_lock, flags);
+	return;
+}
+
+static void vfe_send_comp_stats_msg(
+	struct vfe40_ctrl_type *vfe40_ctrl, uint32_t status_bits)
+{
+	struct msm_stats_buf msgStats;
+	uint32_t temp;
+
+	msgStats.frame_id = vfe40_ctrl->share_ctrl->vfeFrameId;
+	msgStats.status_bits = status_bits;
+
+	msgStats.aec.buff = vfe40_ctrl->aecStatsControl.bufToRender;
+	msgStats.awb.buff = vfe40_ctrl->awbStatsControl.bufToRender;
+	msgStats.af.buff = vfe40_ctrl->afStatsControl.bufToRender;
+
+	msgStats.ihist.buff = vfe40_ctrl->ihistStatsControl.bufToRender;
+	msgStats.rs.buff = vfe40_ctrl->rsStatsControl.bufToRender;
+	msgStats.cs.buff = vfe40_ctrl->csStatsControl.bufToRender;
+
+	temp = msm_camera_io_r(
+		vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_AWB_SGW_CFG);
+	msgStats.awb_ymin = (0xFF00 & temp) >> 8;
+
+	v4l2_subdev_notify(&vfe40_ctrl->subdev,
+				NOTIFY_VFE_MSG_COMP_STATS,
+				&msgStats);
+}
+
+static void vfe40_process_stats_awb_irq(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	unsigned long flags;
+	uint32_t addr;
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AWB);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (addr) {
+		vfe40_ctrl->awbStatsControl.bufToRender =
+			vfe40_process_stats_irq_common(vfe40_ctrl, statsAwbNum,
+			addr);
+
+		vfe_send_stats_msg(vfe40_ctrl,
+			vfe40_ctrl->awbStatsControl.bufToRender, statsAwbNum);
+	} else{
+		vfe40_ctrl->awbStatsControl.droppedStatsFrameCount++;
+		CDBG("%s: droppedStatsFrameCount = %d", __func__,
+			vfe40_ctrl->awbStatsControl.droppedStatsFrameCount);
+	}
+}
+
+static void vfe40_process_stats_ihist_irq(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	unsigned long flags;
+	uint32_t addr;
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_IHIST);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (addr) {
+		vfe40_ctrl->ihistStatsControl.bufToRender =
+			vfe40_process_stats_irq_common(
+			vfe40_ctrl, statsIhistNum, addr);
+
+		vfe_send_stats_msg(vfe40_ctrl,
+			vfe40_ctrl->ihistStatsControl.bufToRender,
+			statsIhistNum);
+	} else {
+		vfe40_ctrl->ihistStatsControl.droppedStatsFrameCount++;
+		CDBG("%s: droppedStatsFrameCount = %d", __func__,
+			vfe40_ctrl->ihistStatsControl.droppedStatsFrameCount);
+	}
+}
+
+static void vfe40_process_stats_rs_irq(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	unsigned long flags;
+	uint32_t addr;
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_RS);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (addr) {
+		vfe40_ctrl->rsStatsControl.bufToRender =
+			vfe40_process_stats_irq_common(vfe40_ctrl, statsRsNum,
+			addr);
+
+		vfe_send_stats_msg(vfe40_ctrl,
+			vfe40_ctrl->rsStatsControl.bufToRender, statsRsNum);
+	} else {
+		vfe40_ctrl->rsStatsControl.droppedStatsFrameCount++;
+		CDBG("%s: droppedStatsFrameCount = %d", __func__,
+			vfe40_ctrl->rsStatsControl.droppedStatsFrameCount);
+	}
+}
+
+static void vfe40_process_stats_cs_irq(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+	unsigned long flags;
+	uint32_t addr;
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_CS);
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (addr) {
+		vfe40_ctrl->csStatsControl.bufToRender =
+			vfe40_process_stats_irq_common(vfe40_ctrl, statsCsNum,
+			addr);
+
+		vfe_send_stats_msg(vfe40_ctrl,
+			vfe40_ctrl->csStatsControl.bufToRender, statsCsNum);
+	} else {
+		vfe40_ctrl->csStatsControl.droppedStatsFrameCount++;
+		CDBG("%s: droppedStatsFrameCount = %d", __func__,
+			vfe40_ctrl->csStatsControl.droppedStatsFrameCount);
+	}
+}
+
+static void vfe40_process_stats(struct vfe40_ctrl_type *vfe40_ctrl,
+	uint32_t status_bits)
+{
+	unsigned long flags;
+	int32_t process_stats = false;
+	uint32_t addr;
+
+	CDBG("%s, stats = 0x%x\n", __func__, status_bits);
+	spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
+		addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
+			MSM_STATS_TYPE_AWB);
+		if (addr) {
+			vfe40_ctrl->awbStatsControl.bufToRender =
+				vfe40_process_stats_irq_common(
+				vfe40_ctrl, statsAwbNum,
+				addr);
+			process_stats = true;
+		} else{
+			vfe40_ctrl->awbStatsControl.droppedStatsFrameCount++;
+			vfe40_ctrl->awbStatsControl.bufToRender = 0;
+		}
+	} else {
+		vfe40_ctrl->awbStatsControl.bufToRender = 0;
+	}
+
+	if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
+		addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
+					MSM_STATS_TYPE_IHIST);
+		if (addr) {
+			vfe40_ctrl->ihistStatsControl.bufToRender =
+				vfe40_process_stats_irq_common(
+				vfe40_ctrl, statsIhistNum,
+				addr);
+			process_stats = true;
+		} else {
+			vfe40_ctrl->ihistStatsControl.droppedStatsFrameCount++;
+			vfe40_ctrl->ihistStatsControl.bufToRender = 0;
+		}
+	} else {
+		vfe40_ctrl->ihistStatsControl.bufToRender = 0;
+	}
+
+	if (status_bits & VFE_IRQ_STATUS0_STATS_RS) {
+		addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
+					MSM_STATS_TYPE_RS);
+		if (addr) {
+			vfe40_ctrl->rsStatsControl.bufToRender =
+				vfe40_process_stats_irq_common(
+				vfe40_ctrl, statsRsNum,
+				addr);
+			process_stats = true;
+		} else {
+			vfe40_ctrl->rsStatsControl.droppedStatsFrameCount++;
+			vfe40_ctrl->rsStatsControl.bufToRender = 0;
+		}
+	} else {
+		vfe40_ctrl->rsStatsControl.bufToRender = 0;
+	}
+
+	if (status_bits & VFE_IRQ_STATUS0_STATS_CS) {
+		addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
+					MSM_STATS_TYPE_CS);
+		if (addr) {
+			vfe40_ctrl->csStatsControl.bufToRender =
+				vfe40_process_stats_irq_common(
+				vfe40_ctrl, statsCsNum,
+				addr);
+			process_stats = true;
+		} else {
+			vfe40_ctrl->csStatsControl.droppedStatsFrameCount++;
+			vfe40_ctrl->csStatsControl.bufToRender = 0;
+		}
+	} else {
+		vfe40_ctrl->csStatsControl.bufToRender = 0;
+	}
+	spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+	if (process_stats)
+		vfe_send_comp_stats_msg(vfe40_ctrl, status_bits);
+
+	return;
+}
+
+static void vfe40_process_stats_irq(
+	struct vfe40_ctrl_type *vfe40_ctrl, uint32_t irqstatus)
+{
+	uint32_t status_bits = VFE_COM_STATUS & irqstatus;
+
+	if ((vfe40_ctrl->hfr_mode != HFR_MODE_OFF) &&
+		(vfe40_ctrl->share_ctrl->vfeFrameId %
+		 vfe40_ctrl->hfr_mode != 0)) {
+		CDBG("Skip the stats when HFR enabled\n");
+		return;
+	}
+
+	vfe40_process_stats(vfe40_ctrl, status_bits);
+	return;
+}
+
+static void vfe40_process_irq(
+	struct vfe40_ctrl_type *vfe40_ctrl, uint32_t irqstatus)
+{
+	if (irqstatus &
+		VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0) {
+		vfe40_process_stats_irq(vfe40_ctrl, irqstatus);
+		return;
+	}
+
+	switch (irqstatus) {
+	case VFE_IRQ_STATUS0_CAMIF_SOF_MASK:
+		CDBG("irq	camifSofIrq\n");
+		vfe40_process_camif_sof_irq(vfe40_ctrl);
+		break;
+	case VFE_IRQ_STATUS0_REG_UPDATE_MASK:
+		CDBG("irq	regUpdateIrq\n");
+		vfe40_process_reg_update_irq(vfe40_ctrl);
+		break;
+	case VFE_IMASK_WHILE_STOPPING_0:
+		CDBG("irq	resetAckIrq\n");
+		vfe40_process_reset_irq(vfe40_ctrl);
+		break;
+	case VFE_IRQ_STATUS0_STATS_AWB:
+		CDBG("Stats AWB irq occured.\n");
+		vfe40_process_stats_awb_irq(vfe40_ctrl);
+		break;
+	case VFE_IRQ_STATUS0_STATS_IHIST:
+		CDBG("Stats IHIST irq occured.\n");
+		vfe40_process_stats_ihist_irq(vfe40_ctrl);
+		break;
+	case VFE_IRQ_STATUS0_STATS_RS:
+		CDBG("Stats RS irq occured.\n");
+		vfe40_process_stats_rs_irq(vfe40_ctrl);
+		break;
+	case VFE_IRQ_STATUS0_STATS_CS:
+		CDBG("Stats CS irq occured.\n");
+		vfe40_process_stats_cs_irq(vfe40_ctrl);
+		break;
+	case VFE_IRQ_STATUS1_SYNC_TIMER0:
+		CDBG("SYNC_TIMER 0 irq occured.\n");
+		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+			vfe40_ctrl->share_ctrl->vfeFrameId,
+			MSG_ID_SYNC_TIMER0_DONE);
+		break;
+	case VFE_IRQ_STATUS1_SYNC_TIMER1:
+		CDBG("SYNC_TIMER 1 irq occured.\n");
+		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+			vfe40_ctrl->share_ctrl->vfeFrameId,
+			MSG_ID_SYNC_TIMER1_DONE);
+		break;
+	case VFE_IRQ_STATUS1_SYNC_TIMER2:
+		CDBG("SYNC_TIMER 2 irq occured.\n");
+		vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+			vfe40_ctrl->share_ctrl->vfeFrameId,
+			MSG_ID_SYNC_TIMER2_DONE);
+		break;
+	default:
+		pr_err("Invalid IRQ status\n");
+	}
+}
+
+static void axi40_do_tasklet(unsigned long data)
+{
+	unsigned long flags;
+	struct axi_ctrl_t *axi_ctrl = (struct axi_ctrl_t *)data;
+	struct vfe40_isr_queue_cmd *qcmd = NULL;
+
+	CDBG("=== axi40_do_tasklet start ===\n");
+
+	while (atomic_read(&axi_ctrl->share_ctrl->irq_cnt)) {
+		spin_lock_irqsave(&axi_ctrl->tasklet_lock, flags);
+		qcmd = list_first_entry(&axi_ctrl->tasklet_q,
+			struct vfe40_isr_queue_cmd, list);
+		atomic_sub(1, &axi_ctrl->share_ctrl->irq_cnt);
+
+		if (!qcmd) {
+			spin_unlock_irqrestore(&axi_ctrl->tasklet_lock,
+				flags);
+			return;
+		}
+
+		list_del(&qcmd->list);
+		spin_unlock_irqrestore(&axi_ctrl->tasklet_lock,
+			flags);
+
+		if (qcmd->vfeInterruptStatus0 &
+				VFE_IRQ_STATUS0_CAMIF_SOF_MASK)
+			v4l2_subdev_notify(&axi_ctrl->subdev,
+				NOTIFY_VFE_IRQ,
+				(void *)VFE_IRQ_STATUS0_CAMIF_SOF_MASK);
+
+		/* interrupt to be processed,  *qcmd has the payload.  */
+		if (qcmd->vfeInterruptStatus0 &
+				VFE_IRQ_STATUS0_REG_UPDATE_MASK) {
+			v4l2_subdev_notify(&axi_ctrl->subdev,
+				NOTIFY_VFE_IRQ,
+				(void *)VFE_IRQ_STATUS0_REG_UPDATE_MASK);
+		}
+
+		if (qcmd->vfeInterruptStatus0 &
+				VFE_IMASK_WHILE_STOPPING_0)
+			v4l2_subdev_notify(&axi_ctrl->subdev,
+				NOTIFY_VFE_IRQ,
+				(void *)VFE_IMASK_WHILE_STOPPING_0);
+
+		if (atomic_read(&axi_ctrl->share_ctrl->vstate)) {
+			if (qcmd->vfeInterruptStatus1 &
+					VFE40_IMASK_ERROR_ONLY_1) {
+				pr_err("irq	errorIrq\n");
+				vfe40_process_error_irq(
+					axi_ctrl,
+					qcmd->vfeInterruptStatus1 &
+					VFE40_IMASK_ERROR_ONLY_1);
+			}
+			v4l2_subdev_notify(&axi_ctrl->subdev,
+				NOTIFY_AXI_IRQ,
+				(void *)qcmd->vfeInterruptStatus0);
+
+			/* then process stats irq. */
+			if (axi_ctrl->share_ctrl->stats_comp) {
+				/* process stats comb interrupt. */
+				if (qcmd->vfeInterruptStatus0 &
+					VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0) {
+					CDBG("Stats composite irq occured.\n");
+					v4l2_subdev_notify(&axi_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)qcmd->vfeInterruptStatus0);
+				}
+			} else {
+				/* process individual stats interrupt. */
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_STATS_AWB)
+					v4l2_subdev_notify(&axi_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS0_STATS_AWB);
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_STATS_IHIST)
+					v4l2_subdev_notify(&axi_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS0_STATS_IHIST);
+
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_STATS_RS)
+					v4l2_subdev_notify(&axi_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS0_STATS_RS);
+
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS0_STATS_CS)
+					v4l2_subdev_notify(&axi_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS0_STATS_CS);
+
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS1_SYNC_TIMER0)
+					v4l2_subdev_notify(&axi_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS1_SYNC_TIMER0);
+
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS1_SYNC_TIMER1)
+					v4l2_subdev_notify(&axi_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS1_SYNC_TIMER1);
+
+				if (qcmd->vfeInterruptStatus0 &
+						VFE_IRQ_STATUS1_SYNC_TIMER2)
+					v4l2_subdev_notify(&axi_ctrl->subdev,
+					NOTIFY_VFE_IRQ,
+					(void *)VFE_IRQ_STATUS1_SYNC_TIMER2);
+			}
+		}
+		kfree(qcmd);
+	}
+	CDBG("=== axi40_do_tasklet end ===\n");
+}
+
+static irqreturn_t vfe40_parse_irq(int irq_num, void *data)
+{
+	unsigned long flags;
+	struct vfe40_irq_status irq;
+	struct vfe40_isr_queue_cmd *qcmd;
+	struct axi_ctrl_t *axi_ctrl = data;
+
+	CDBG("vfe_parse_irq\n");
+
+	vfe40_read_irq_status(axi_ctrl, &irq);
+
+	if ((irq.vfeIrqStatus0 == 0) && (irq.vfeIrqStatus1 == 0)) {
+		CDBG("vfe_parse_irq: vfeIrqStatus0 & 1 are both 0!\n");
+		return IRQ_HANDLED;
+	}
+
+	qcmd = kzalloc(sizeof(struct vfe40_isr_queue_cmd),
+		GFP_ATOMIC);
+	if (!qcmd) {
+		pr_err("vfe_parse_irq: qcmd malloc failed!\n");
+		return IRQ_HANDLED;
+	}
+
+	spin_lock_irqsave(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
+	if (axi_ctrl->share_ctrl->stop_ack_pending) {
+		irq.vfeIrqStatus0 &= VFE_IMASK_WHILE_STOPPING_0;
+		irq.vfeIrqStatus1 &= VFE_IMASK_WHILE_STOPPING_1;
+	}
+	spin_unlock_irqrestore(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
+
+	CDBG("vfe_parse_irq: Irq_status0 = 0x%x, Irq_status1 = 0x%x.\n",
+		irq.vfeIrqStatus0, irq.vfeIrqStatus1);
+
+	qcmd->vfeInterruptStatus0 = irq.vfeIrqStatus0;
+	qcmd->vfeInterruptStatus1 = irq.vfeIrqStatus1;
+
+	spin_lock_irqsave(&axi_ctrl->tasklet_lock, flags);
+	list_add_tail(&qcmd->list, &axi_ctrl->tasklet_q);
+
+	atomic_add(1, &axi_ctrl->share_ctrl->irq_cnt);
+	spin_unlock_irqrestore(&axi_ctrl->tasklet_lock, flags);
+	tasklet_schedule(&axi_ctrl->vfe40_tasklet);
+	return IRQ_HANDLED;
+}
+
+
+static long vfe_stats_bufq_sub_ioctl(
+	struct vfe40_ctrl_type *vfe_ctrl,
+	struct msm_vfe_cfg_cmd *cmd, void *ion_client)
+{
+	long rc = 0;
+	switch (cmd->cmd_type) {
+	case VFE_CMD_STATS_REQBUF:
+	if (!vfe_ctrl->stats_ops.stats_ctrl) {
+		/* stats_ctrl has not been init yet */
+		rc = msm_stats_buf_ops_init(&vfe_ctrl->stats_ctrl,
+				(struct ion_client *)ion_client,
+				&vfe_ctrl->stats_ops);
+		if (rc < 0) {
+			pr_err("%s: cannot init stats ops", __func__);
+			goto end;
+		}
+		rc = vfe_ctrl->stats_ops.stats_ctrl_init(&vfe_ctrl->stats_ctrl);
+		if (rc < 0) {
+			pr_err("%s: cannot init stats_ctrl ops", __func__);
+			memset(&vfe_ctrl->stats_ops, 0,
+				sizeof(vfe_ctrl->stats_ops));
+			goto end;
+		}
+		if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats reqbuf input size = %d,\n"
+				"struct size = %d, mitch match\n",
+				 __func__, cmd->length,
+				sizeof(struct msm_stats_reqbuf));
+			rc = -EINVAL ;
+			goto end;
+		}
+	}
+	rc = vfe_ctrl->stats_ops.reqbuf(
+			&vfe_ctrl->stats_ctrl,
+			(struct msm_stats_reqbuf *)cmd->value,
+			vfe_ctrl->stats_ops.client);
+	break;
+	case VFE_CMD_STATS_ENQUEUEBUF:
+	if (sizeof(struct msm_stats_buf_info) != cmd->length) {
+		/* error. the length not match */
+		pr_err("%s: stats enqueuebuf input size = %d,\n"
+			"struct size = %d, mitch match\n",
+			 __func__, cmd->length,
+			sizeof(struct msm_stats_buf_info));
+			rc = -EINVAL;
+			goto end;
+	}
+	rc = vfe_ctrl->stats_ops.enqueue_buf(
+			&vfe_ctrl->stats_ctrl,
+			(struct msm_stats_buf_info *)cmd->value,
+			vfe_ctrl->stats_ops.client);
+	break;
+	case VFE_CMD_STATS_FLUSH_BUFQ:
+	{
+		struct msm_stats_flush_bufq *flush_req = NULL;
+		flush_req = (struct msm_stats_flush_bufq *)cmd->value;
+		if (sizeof(struct msm_stats_flush_bufq) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats flush queue input size = %d,\n"
+				"struct size = %d, mitch match\n",
+				__func__, cmd->length,
+				sizeof(struct msm_stats_flush_bufq));
+			rc = -EINVAL;
+			goto end;
+	}
+	rc = vfe_ctrl->stats_ops.bufq_flush(
+			&vfe_ctrl->stats_ctrl,
+			(enum msm_stats_enum_type)flush_req->stats_type,
+			vfe_ctrl->stats_ops.client);
+	}
+	break;
+	default:
+		rc = -1;
+		pr_err("%s: cmd_type %d not supported", __func__,
+			cmd->cmd_type);
+	break;
+	}
+end:
+	return rc;
+}
+
+static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int subdev_cmd, void *arg)
+{
+	struct msm_cam_media_controller *pmctl =
+		(struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
+	struct vfe40_ctrl_type *vfe40_ctrl =
+		(struct vfe40_ctrl_type *)v4l2_get_subdevdata(sd);
+	struct msm_isp_cmd vfecmd;
+	struct msm_camvfe_params *vfe_params =
+		(struct msm_camvfe_params *)arg;
+	struct msm_vfe_cfg_cmd *cmd = vfe_params->vfe_cfg;
+	void *data = vfe_params->data;
+
+	long rc = 0;
+	struct vfe_cmd_stats_buf *scfg = NULL;
+	struct vfe_cmd_stats_ack *sack = NULL;
+
+	if (!vfe40_ctrl->share_ctrl->vfebase) {
+		pr_err("%s: base address unmapped\n", __func__);
+		return -EFAULT;
+	}
+
+	switch (cmd->cmd_type) {
+	case CMD_VFE_PROCESS_IRQ:
+		vfe40_process_irq(vfe40_ctrl, (uint32_t) data);
+		return rc;
+	case VFE_CMD_STATS_REQBUF:
+	case VFE_CMD_STATS_ENQUEUEBUF:
+	case VFE_CMD_STATS_FLUSH_BUFQ:
+		/* for easy porting put in one envelope */
+		rc = vfe_stats_bufq_sub_ioctl(vfe40_ctrl,
+				cmd, vfe_params->data);
+		return rc;
+	default:
+		if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
+			cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+			cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
+			cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+				if (copy_from_user(&vfecmd,
+					(void __user *)(cmd->value),
+					sizeof(vfecmd))) {
+						pr_err("%s %d: copy_from_user failed\n",
+							__func__, __LINE__);
+					return -EFAULT;
+				}
+		} else {
+			/* here eith stats release or frame release. */
+			if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
+				cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+				cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) {
+				/* then must be stats release. */
+				if (!data) {
+					pr_err("%s: data = NULL, cmd->cmd_type = %d",
+						__func__, cmd->cmd_type);
+					return -EFAULT;
+				}
+				sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
+							GFP_ATOMIC);
+				if (!sack) {
+					pr_err("%s: no mem for cmd->cmd_type = %d",
+					 __func__, cmd->cmd_type);
+					return -ENOMEM;
+				}
+				sack->nextStatsBuf = *(uint32_t *)data;
+			}
+		}
+		CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
+
+		if ((cmd->cmd_type == CMD_STATS_AF_ENABLE)    ||
+			(cmd->cmd_type == CMD_STATS_AWB_ENABLE)   ||
+			(cmd->cmd_type == CMD_STATS_IHIST_ENABLE) ||
+			(cmd->cmd_type == CMD_STATS_RS_ENABLE)    ||
+			(cmd->cmd_type == CMD_STATS_CS_ENABLE)    ||
+			(cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
+				scfg = NULL;
+				/* individual */
+				goto vfe40_config_done;
+		}
+		switch (cmd->cmd_type) {
+		case CMD_GENERAL:
+			rc = vfe40_proc_general(pmctl, &vfecmd, vfe40_ctrl);
+		break;
+		case CMD_CONFIG_PING_ADDR: {
+			int path = *((int *)cmd->value);
+			struct vfe40_output_ch *outch =
+				vfe40_get_ch(path, vfe40_ctrl->share_ctrl);
+			outch->ping = *((struct msm_free_buf *)data);
+		}
+		break;
+
+		case CMD_CONFIG_PONG_ADDR: {
+			int path = *((int *)cmd->value);
+			struct vfe40_output_ch *outch =
+				vfe40_get_ch(path, vfe40_ctrl->share_ctrl);
+			outch->pong = *((struct msm_free_buf *)data);
+		}
+		break;
+
+		case CMD_CONFIG_FREE_BUF_ADDR: {
+			int path = *((int *)cmd->value);
+			struct vfe40_output_ch *outch =
+				vfe40_get_ch(path, vfe40_ctrl->share_ctrl);
+			outch->free_buf = *((struct msm_free_buf *)data);
+		}
+		break;
+		case CMD_SNAP_BUF_RELEASE:
+			break;
+		default:
+			pr_err("%s Unsupported AXI configuration %x ", __func__,
+				cmd->cmd_type);
+		break;
+		}
+	}
+vfe40_config_done:
+	kfree(scfg);
+	kfree(sack);
+	CDBG("%s done: rc = %d\n", __func__, (int) rc);
+	return rc;
+}
+
+static const struct v4l2_subdev_core_ops msm_vfe_subdev_core_ops = {
+	.ioctl = msm_vfe_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_vfe_subdev_ops = {
+	.core = &msm_vfe_subdev_core_ops,
+};
+
+int msm_vfe_subdev_init(struct v4l2_subdev *sd,
+			struct msm_cam_media_controller *mctl)
+{
+	int rc = 0;
+	struct vfe40_ctrl_type *vfe40_ctrl =
+		(struct vfe40_ctrl_type *)v4l2_get_subdevdata(sd);
+	v4l2_set_subdev_hostdata(sd, mctl);
+
+	spin_lock_init(&vfe40_ctrl->share_ctrl->stop_flag_lock);
+	spin_lock_init(&vfe40_ctrl->state_lock);
+	spin_lock_init(&vfe40_ctrl->io_lock);
+	spin_lock_init(&vfe40_ctrl->update_ack_lock);
+	spin_lock_init(&vfe40_ctrl->stats_bufq_lock);
+
+
+	vfe40_ctrl->update_linear = false;
+	vfe40_ctrl->update_rolloff = false;
+	vfe40_ctrl->update_la = false;
+	vfe40_ctrl->update_gamma = false;
+	vfe40_ctrl->hfr_mode = HFR_MODE_OFF;
+
+	return rc;
+}
+
+void msm_vfe_subdev_release(struct v4l2_subdev *sd)
+{
+	struct vfe40_ctrl_type *vfe40_ctrl =
+		(struct vfe40_ctrl_type *)v4l2_get_subdevdata(sd);
+	if (!vfe40_ctrl->share_ctrl->vfebase)
+		vfe40_ctrl->share_ctrl->vfebase = NULL;
+}
+
+static const struct v4l2_subdev_internal_ops msm_vfe_internal_ops;
+
+static int __devinit vfe40_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct axi_ctrl_t *axi_ctrl;
+	struct vfe40_ctrl_type *vfe40_ctrl;
+	struct vfe_share_ctrl_t *share_ctrl;
+	struct msm_cam_subdev_info sd_info;
+	CDBG("%s: device id = %d\n", __func__, pdev->id);
+
+	share_ctrl = kzalloc(sizeof(struct vfe_share_ctrl_t), GFP_KERNEL);
+	if (!share_ctrl) {
+		pr_err("%s: no enough memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	axi_ctrl = kzalloc(sizeof(struct axi_ctrl_t), GFP_KERNEL);
+	if (!axi_ctrl) {
+		pr_err("%s: no enough memory\n", __func__);
+		kfree(share_ctrl);
+		return -ENOMEM;
+	}
+
+	vfe40_ctrl = kzalloc(sizeof(struct vfe40_ctrl_type), GFP_KERNEL);
+	if (!vfe40_ctrl) {
+		pr_err("%s: no enough memory\n", __func__);
+		kfree(share_ctrl);
+		kfree(axi_ctrl);
+		return -ENOMEM;
+	}
+
+	if (pdev->dev.of_node)
+		of_property_read_u32((&pdev->dev)->of_node,
+			"cell-index", &pdev->id);
+
+	share_ctrl->axi_ctrl = axi_ctrl;
+	share_ctrl->vfe40_ctrl = vfe40_ctrl;
+	axi_ctrl->share_ctrl = share_ctrl;
+	vfe40_ctrl->share_ctrl = share_ctrl;
+	axi_ctrl->pdev = pdev;
+	vfe40_axi_probe(axi_ctrl);
+
+	v4l2_subdev_init(&vfe40_ctrl->subdev, &msm_vfe_subdev_ops);
+	vfe40_ctrl->subdev.internal_ops = &msm_vfe_internal_ops;
+	vfe40_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(vfe40_ctrl->subdev.name,
+			 sizeof(vfe40_ctrl->subdev.name), "vfe4.0");
+	v4l2_set_subdevdata(&vfe40_ctrl->subdev, vfe40_ctrl);
+	platform_set_drvdata(pdev, &vfe40_ctrl->subdev);
+
+	axi_ctrl->vfemem = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "vfe");
+	if (!axi_ctrl->vfemem) {
+		pr_err("%s: no mem resource?\n", __func__);
+		rc = -ENODEV;
+		goto vfe40_no_resource;
+	}
+	axi_ctrl->vfeirq = platform_get_resource_byname(pdev,
+					IORESOURCE_IRQ, "vfe");
+	if (!axi_ctrl->vfeirq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		rc = -ENODEV;
+		goto vfe40_no_resource;
+	}
+
+	axi_ctrl->vfeio = request_mem_region(axi_ctrl->vfemem->start,
+		resource_size(axi_ctrl->vfemem), pdev->name);
+	if (!axi_ctrl->vfeio) {
+		pr_err("%s: no valid mem region\n", __func__);
+		rc = -EBUSY;
+		goto vfe40_no_resource;
+	}
+
+	rc = request_irq(axi_ctrl->vfeirq->start, vfe40_parse_irq,
+		IRQF_TRIGGER_RISING, "vfe", axi_ctrl);
+	if (rc < 0) {
+		release_mem_region(axi_ctrl->vfemem->start,
+			resource_size(axi_ctrl->vfemem));
+		pr_err("%s: irq request fail\n", __func__);
+		rc = -EBUSY;
+		goto vfe40_no_resource;
+	}
+
+	disable_irq(axi_ctrl->vfeirq->start);
+
+	tasklet_init(&axi_ctrl->vfe40_tasklet,
+		axi40_do_tasklet, (unsigned long)axi_ctrl);
+
+	vfe40_ctrl->pdev = pdev;
+	sd_info.sdev_type = VFE_DEV;
+	sd_info.sd_index = pdev->id;
+	sd_info.irq_num = axi_ctrl->vfeirq->start;
+	msm_cam_register_subdev_node(&vfe40_ctrl->subdev, &sd_info);
+	return 0;
+
+vfe40_no_resource:
+	kfree(vfe40_ctrl);
+	kfree(axi_ctrl);
+	return 0;
+}
+
+static const struct of_device_id msm_vfe_dt_match[] = {
+	{.compatible = "qcom,vfe40"},
+};
+
+MODULE_DEVICE_TABLE(of, msm_vfe_dt_match);
+
+static struct platform_driver vfe40_driver = {
+	.probe = vfe40_probe,
+	.driver = {
+		.name = MSM_VFE_DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = msm_vfe_dt_match,
+	},
+};
+
+static int __init msm_vfe40_init_module(void)
+{
+	return platform_driver_register(&vfe40_driver);
+}
+
+static void __exit msm_vfe40_exit_module(void)
+{
+	platform_driver_unregister(&vfe40_driver);
+}
+
+module_init(msm_vfe40_init_module);
+module_exit(msm_vfe40_exit_module);
+MODULE_DESCRIPTION("VFE 4.0 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.h b/drivers/media/video/msm/vfe/msm_vfe40.h
new file mode 100644
index 0000000..c8b0cb8
--- /dev/null
+++ b/drivers/media/video/msm/vfe/msm_vfe40.h
@@ -0,0 +1,1202 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_VFE40_H__
+#define __MSM_VFE40_H__
+
+#include <linux/bitops.h>
+#include "msm_vfe_stats_buf.h"
+
+#define TRUE  1
+#define FALSE 0
+
+#define VFE40_HW_NUMBER 0x10000015
+
+/* This defines total number registers in VFE.
+ * Each register is 4 bytes so to get the range,
+ * multiply this number with 4. */
+#define VFE40_REGISTER_TOTAL 0x00000320
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x10:
+ * disable image data capture immediately. */
+#define CAMIF_COMMAND_STOP_IMMEDIATELY  0x00000002
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x00:
+ * disable image data capture at frame boundary */
+#define CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY  0x00000000
+
+/* to halt axi bridge */
+#define AXI_HALT  0x00000001
+
+/* clear the halt bit. */
+#define AXI_HALT_CLEAR  0x00000000
+
+/* reset the pipeline when stop command is issued.
+ * (without reset the register.) bit 26-32 = 0,
+ * domain reset, bit 0-9 = 1 for module reset, except
+ * register module. */
+#define VFE_RESET_UPON_STOP_CMD  0x000003ef
+
+/* reset the pipeline when reset command.
+ * bit 26-32 = 0, domain reset, bit 0-9 = 1 for module reset. */
+#define VFE_RESET_UPON_RESET_CMD  0x000001ff
+
+/* constants for irq registers */
+#define VFE_DISABLE_ALL_IRQS 0
+/* bit =1 is to clear the corresponding bit in VFE_IRQ_STATUS.  */
+#define VFE_CLEAR_ALL_IRQ0   0xffff7fff
+#define VFE_CLEAR_ALL_IRQ1   0xffffffff
+
+#define VFE_IRQ_STATUS0_CAMIF_SOF_MASK            (0x00000001<<0)
+#define VFE_IRQ_STATUS0_REG_UPDATE_MASK           (0x00000001<<4)
+#define VFE_IRQ_STATUS0_STATS_BE                  (0x00000001<<16)
+#define VFE_IRQ_STATUS0_STATS_BG                  (0x00000001<<17)
+#define VFE_IRQ_STATUS0_STATS_BF                  (0x00000001<<18)
+#define VFE_IRQ_STATUS0_STATS_AWB                 (0x00000001<<19)
+#define VFE_IRQ_STATUS0_STATS_RS                  (0x00000001<<20)
+#define VFE_IRQ_STATUS0_STATS_CS                  (0x00000001<<21)
+#define VFE_IRQ_STATUS0_STATS_IHIST               (0x00000001<<22)
+#define VFE_IRQ_STATUS0_STATS_SKIN_BHIST          (0x00000001<<23)
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK (0x00000001<<25)
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK (0x00000001<<26)
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE2_MASK (0x00000001<<27)
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE3_MASK (0x00000001<<28)
+#define VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0     (0x00000001<<29)
+#define VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_1     (0x00000001<<30)
+#define VFE_IRQ_STATUS0_RESET_AXI_HALT_ACK_MASK   (0x00000001<<31)
+
+#define VFE_IRQ_STATUS1_SYNC_TIMER0               (0x00000001<<25)
+#define VFE_IRQ_STATUS1_SYNC_TIMER1               (0x00000001<<26)
+#define VFE_IRQ_STATUS1_SYNC_TIMER2               (0x00000001<<27)
+#define VFE_IRQ_STATUS1_ASYNC_TIMER0              (0x00000001<<28)
+#define VFE_IRQ_STATUS1_ASYNC_TIMER1              (0x00000001<<29)
+#define VFE_IRQ_STATUS1_ASYNC_TIMER2              (0x00000001<<30)
+#define VFE_IRQ_STATUS1_ASYNC_TIMER3              (0x00000001<<31)
+
+/* imask for while waiting for stop ack,  driver has already
+ * requested stop, waiting for reset irq, and async timer irq.
+ * For irq_status_0, bit 28-32 are for async timer. For
+ * irq_status_1, bit 22 for reset irq, bit 23 for axi_halt_ack
+   irq */
+#define VFE_IMASK_WHILE_STOPPING_0  0x80000000
+#define VFE_IMASK_WHILE_STOPPING_1  0x00000100
+
+/* For ABF bit 4 is set to zero and other's 1 */
+#define ABF_MASK 0xFFFFFFF7
+
+/* For DBPC bit 0 is set to zero and other's 1 */
+#define DBPC_MASK 0xFFFFFFFE
+
+/* For DBPC bit 1 is set to zero and other's 1 */
+#define DBCC_MASK 0xFFFFFFFD
+
+/* For DBPC/ABF/DBCC/ABCC bits are set to 1 all others 0 */
+#define DEMOSAIC_MASK 0xF
+
+/* For MCE enable bit 28 set to zero and other's 1 */
+#define MCE_EN_MASK 0xEFFFFFFF
+
+/* For MCE Q_K bit 28 to 32 set to zero and other's 1 */
+#define MCE_Q_K_MASK 0x0FFFFFFF
+
+#define BE_ENABLE_MASK    (0x00000001<<5)
+#define BG_ENABLE_MASK    (0x00000001<<6)
+#define BF_ENABLE_MASK    (0x00000001<<7)
+#define AWB_ENABLE_MASK   (0x00000001<<8)
+#define RS_ENABLE_MASK    (0x00000001<<9)
+#define CS_ENABLE_MASK    (0x00000001<<10)
+#define CLF_ENABLE_MASK   (0x00000001<<12)
+#define IHIST_ENABLE_MASK (0x00000001<<15)
+#define RS_CS_ENABLE_MASK (RS_ENABLE_MASK|CS_ENABLE_MASK)
+#define STATS_ENABLE_MASK 0x000487E0   /* bit 18,15,10,9,8,7,6,5*/
+
+#define VFE_DMI_CFG_DEFAULT              0x00000100
+
+#define HFR_MODE_OFF 1
+#define VFE_FRAME_SKIP_PERIOD_MASK 0x0000001F /*bits 0 -4*/
+
+enum VFE40_DMI_RAM_SEL {
+	NO_MEM_SELECTED          = 0,
+	BLACK_LUT_RAM_BANK0      = 0x1,
+	BLACK_LUT_RAM_BANK1      = 0x2,
+	ROLLOFF_RAM0_BANK0       = 0x3,
+	ROLLOFF_RAM0_BANK1       = 0x4,
+	DEMOSAIC_LUT_RAM_BANK0   = 0x5,
+	DEMOSAIC_LUT_RAM_BANK1   = 0x6,
+	STATS_BHIST_RAM0         = 0x7,
+	STATS_BHIST_RAM1         = 0x8,
+	RGBLUT_RAM_CH0_BANK0     = 0x9,
+	RGBLUT_RAM_CH0_BANK1     = 0xa,
+	RGBLUT_RAM_CH1_BANK0     = 0xb,
+	RGBLUT_RAM_CH1_BANK1     = 0xc,
+	RGBLUT_RAM_CH2_BANK0     = 0xd,
+	RGBLUT_RAM_CH2_BANK1     = 0xe,
+	RGBLUT_CHX_BANK0         = 0xf,
+	RGBLUT_CHX_BANK1         = 0x10,
+	STATS_IHIST_RAM          = 0x11,
+	LUMA_ADAPT_LUT_RAM_BANK0 = 0x12,
+	LUMA_ADAPT_LUT_RAM_BANK1 = 0x13,
+};
+
+enum vfe_output_state {
+	VFE_STATE_IDLE,
+	VFE_STATE_START_REQUESTED,
+	VFE_STATE_STARTED,
+	VFE_STATE_STOP_REQUESTED,
+	VFE_STATE_STOPPED,
+};
+
+#define V40_CAMIF_OFF             0x000002F8
+#define V40_CAMIF_LEN             36
+
+#define V40_DEMUX_OFF             0x00000424
+#define V40_DEMUX_LEN             28
+
+#define V40_DEMOSAICV3_0_OFF      0x00000440
+#define V40_DEMOSAICV3_0_LEN      4
+#define V40_DEMOSAICV3_1_OFF      0x00000518
+#define V40_DEMOSAICV3_1_LEN      88
+#define V40_DEMOSAICV3_2_OFF      0x00000568
+#define V40_DEMOSAICV3_UP_REG_CNT 5
+
+#define V40_OUT_CLAMP_OFF         0x00000874
+#define V40_OUT_CLAMP_LEN         16
+
+#define V40_OPERATION_CFG_LEN     44
+
+#define V40_AXI_OUT_OFF           0x0000004C
+#define V40_AXI_OUT_LEN           412
+#define V40_AXI_CH_INF_LEN        32
+#define V40_AXI_CFG_LEN           71
+
+#define V40_FOV_ENC_OFF           0x00000854
+#define V40_FOV_ENC_LEN           16
+#define V40_FOV_VIEW_OFF          0x00000864
+#define V40_FOV_VIEW_LEN          16
+
+#define V40_SCALER_ENC_OFF 0x0000075C
+#define V40_SCALER_ENC_LEN 72
+
+#define V40_SCALER_VIEW_OFF 0x000007A4
+#define V40_SCALER_VIEW_LEN 72
+
+#define V40_COLORXFORM_ENC_CFG_OFF 0x0000071C
+#define V40_COLORXFORM_ENC_CFG_LEN 32
+
+#define V40_COLORXFORM_VIEW_CFG_OFF 0x0000073C
+#define V40_COLORXFORM_VIEW_CFG_LEN 32
+
+#define V40_CHROMA_EN_OFF 0x00000640
+#define V40_CHROMA_EN_LEN 36
+
+#define V40_SYNC_TIMER_OFF      0x00000324
+#define V40_SYNC_TIMER_POLARITY_OFF 0x0000034C
+#define V40_TIMER_SELECT_OFF        0x00000374
+#define V40_SYNC_TIMER_LEN 28
+
+#define V40_ASYNC_TIMER_OFF 0x00000350
+#define V40_ASYNC_TIMER_LEN 28
+
+/* use 10x13 mesh table in vfe40*/
+#define V40_MESH_ROLL_OFF_CFG_OFF             0x00000400
+#define V40_MESH_ROLL_OFF_CFG_LEN             36
+#define V40_MESH_ROLL_OFF_TABLE_SIZE          130
+
+
+#define V40_COLOR_COR_OFF 0x000005D0
+#define V40_COLOR_COR_LEN 52
+
+#define V40_WB_OFF 0x00000580
+#define V40_WB_LEN 4
+
+#define V40_RGB_G_OFF 0x00000638
+#define V40_RGB_G_LEN 4
+#define V40_GAMMA_LUT_BANK_SEL_MASK           0x00000007
+
+#define V40_LA_OFF 0x0000063C
+#define V40_LA_LEN 4
+
+#define V40_SCE_OFF 0x00000694
+#define V40_SCE_LEN 136
+
+#define V40_CHROMA_SUP_OFF 0x00000664
+#define V40_CHROMA_SUP_LEN 12
+
+#define V40_MCE_OFF 0x00000670
+#define V40_MCE_LEN 36
+
+#define V40_STATS_BE_OFF 0x0000088C
+#define V40_STATS_BE_LEN 12
+
+#define V40_STATS_BG_OFF 0x00000898
+#define V40_STATS_BG_LEN 12
+
+#define V40_STATS_BF_OFF 0x000008A4
+#define V40_STATS_BF_LEN 24
+
+#define V40_STATS_BHIST_OFF 0x000008BC
+#define V40_STATS_BHIST_LEN 8
+
+#define V40_STATS_AWB_OFF 0x000008C4
+#define V40_STATS_AWB_LEN 32
+
+#define V40_STATS_RS_OFF 0x000008E4
+#define V40_STATS_RS_LEN 8
+
+#define V40_STATS_CS_OFF 0x000008EC
+#define V40_STATS_CS_LEN 8
+
+#define V40_STATS_IHIST_OFF 0x000008F4
+#define V40_STATS_IHIST_LEN 8
+
+#define V40_STATS_SKIN_OFF 0x000008FC
+#define V40_STATS_SKIN_LEN 20
+
+#define V40_ASF_OFF 0x000007EC
+#define V40_ASF_LEN 48
+#define V40_ASF_UPDATE_LEN 36
+
+#define V40_CAPTURE_LEN 4
+
+#define V40_GET_HW_VERSION_OFF 0
+#define V40_GET_HW_VERSION_LEN 4
+
+#define V40_LINEARIZATION_OFF1 0x0000037C
+#define V40_LINEARIZATION_LEN1 68
+
+#define V40_DEMOSAICV3_DBPC_CFG_OFF  0x00000444
+#define V40_DEMOSAICV3_DBPC_LEN 4
+
+#define V40_DEMOSAICV3_DBPC_CFG_OFF0 0x00000448
+#define V40_DEMOSAICV3_DBPC_CFG_OFF1 0x0000044C
+#define V40_DEMOSAICV3_DBPC_CFG_OFF2 0x00000450
+
+#define V40_DEMOSAICV3_DBCC_OFF 0x00000454
+#define V40_DEMOSAICV3_DBCC_LEN 16
+
+#define V40_DEMOSAICV3_ABF_OFF 0x00000464
+#define V40_DEMOSAICV3_ABF_LEN 180
+
+#define V40_MODULE_CFG_OFF 0x00000018
+#define V40_MODULE_CFG_LEN 4
+
+#define V40_ASF_SPECIAL_EFX_CFG_OFF 0x0000081C
+#define V40_ASF_SPECIAL_EFX_CFG_LEN 4
+
+#define V40_CLF_CFG_OFF 0x00000588
+#define V40_CLF_CFG_LEN 72
+
+#define V40_CLF_LUMA_UPDATE_OFF 0x0000058C
+#define V40_CLF_LUMA_UPDATE_LEN 60
+
+#define V40_CLF_CHROMA_UPDATE_OFF 0x000005C8
+#define V40_CLF_CHROMA_UPDATE_LEN 8
+
+#define VFE40_GAMMA_NUM_ENTRIES  64
+
+#define VFE40_LA_TABLE_LENGTH    64
+
+#define VFE40_LINEARIZATON_TABLE_LENGTH    36
+
+#define VFE_WM_CFG_BASE 0x0070
+#define VFE_WM_CFG_LEN 0x0024
+
+#define vfe40_get_ch_ping_addr(base, chn) \
+	(msm_camera_io_r((base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn)))
+#define vfe40_get_ch_pong_addr(base, chn) \
+	(msm_camera_io_r((base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn) + 4))
+#define vfe40_get_ch_addr(ping_pong, base, chn) \
+	((((ping_pong) & (1 << (chn))) == 0) ? \
+	(vfe40_get_ch_pong_addr((base), chn)) : \
+	(vfe40_get_ch_ping_addr((base), chn)))
+
+#define vfe40_put_ch_ping_addr(base, chn, addr) \
+	(msm_camera_io_w((addr), \
+	(base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn)))
+#define vfe40_put_ch_pong_addr(base, chn, addr) \
+	(msm_camera_io_w((addr), \
+	(base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn) + 4))
+#define vfe40_put_ch_addr(ping_pong, base, chn, addr) \
+	(((ping_pong) & (1 << (chn))) == 0 ?   \
+	vfe40_put_ch_pong_addr((base), (chn), (addr)) : \
+	vfe40_put_ch_ping_addr((base), (chn), (addr)))
+
+struct vfe_cmd_hw_version {
+	uint32_t minorVersion;
+	uint32_t majorVersion;
+	uint32_t coreVersion;
+};
+
+enum VFE_AXI_OUTPUT_MODE {
+	VFE_AXI_OUTPUT_MODE_Output1,
+	VFE_AXI_OUTPUT_MODE_Output2,
+	VFE_AXI_OUTPUT_MODE_Output1AndOutput2,
+	VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2,
+	VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1,
+	VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2,
+	VFE_AXI_LAST_OUTPUT_MODE_ENUM
+};
+
+enum VFE_RAW_WR_PATH_SEL {
+	VFE_RAW_OUTPUT_DISABLED,
+	VFE_RAW_OUTPUT_ENC_CBCR_PATH,
+	VFE_RAW_OUTPUT_VIEW_CBCR_PATH,
+	VFE_RAW_OUTPUT_PATH_INVALID
+};
+
+
+#define VFE_AXI_OUTPUT_BURST_LENGTH     4
+#define VFE_MAX_NUM_FRAGMENTS_PER_FRAME 4
+#define VFE_AXI_OUTPUT_CFG_FRAME_COUNT  3
+
+struct vfe_cmds_per_write_master {
+	uint16_t imageWidth;
+	uint16_t imageHeight;
+	uint16_t outRowCount;
+	uint16_t outRowIncrement;
+	uint32_t outFragments[VFE_AXI_OUTPUT_CFG_FRAME_COUNT]
+		[VFE_MAX_NUM_FRAGMENTS_PER_FRAME];
+};
+
+struct vfe_cmds_axi_per_output_path {
+	uint8_t fragmentCount;
+	struct vfe_cmds_per_write_master firstWM;
+	struct vfe_cmds_per_write_master secondWM;
+};
+
+enum VFE_AXI_BURST_LENGTH {
+	VFE_AXI_BURST_LENGTH_IS_2  = 2,
+	VFE_AXI_BURST_LENGTH_IS_4  = 4,
+	VFE_AXI_BURST_LENGTH_IS_8  = 8,
+	VFE_AXI_BURST_LENGTH_IS_16 = 16
+};
+
+
+struct vfe_cmd_fov_crop_config {
+	uint8_t enable;
+	uint16_t firstPixel;
+	uint16_t lastPixel;
+	uint16_t firstLine;
+	uint16_t lastLine;
+};
+
+struct vfe_cmds_main_scaler_stripe_init {
+	uint16_t MNCounterInit;
+	uint16_t phaseInit;
+};
+
+struct vfe_cmds_scaler_one_dimension {
+	uint8_t  enable;
+	uint16_t inputSize;
+	uint16_t outputSize;
+	uint32_t phaseMultiplicationFactor;
+	uint8_t  interpolationResolution;
+};
+
+struct vfe_cmd_main_scaler_config {
+	uint8_t enable;
+	struct vfe_cmds_scaler_one_dimension    hconfig;
+	struct vfe_cmds_scaler_one_dimension    vconfig;
+	struct vfe_cmds_main_scaler_stripe_init MNInitH;
+	struct vfe_cmds_main_scaler_stripe_init MNInitV;
+};
+
+struct vfe_cmd_scaler2_config {
+	uint8_t enable;
+	struct vfe_cmds_scaler_one_dimension hconfig;
+	struct vfe_cmds_scaler_one_dimension vconfig;
+};
+
+
+struct vfe_cmd_frame_skip_update {
+	uint32_t output1Pattern;
+	uint32_t output2Pattern;
+};
+
+struct vfe_cmd_output_clamp_config {
+	uint8_t minCh0;
+	uint8_t minCh1;
+	uint8_t minCh2;
+	uint8_t maxCh0;
+	uint8_t maxCh1;
+	uint8_t maxCh2;
+};
+
+struct vfe_cmd_chroma_subsample_config {
+	uint8_t enable;
+	uint8_t cropEnable;
+	uint8_t vsubSampleEnable;
+	uint8_t hsubSampleEnable;
+	uint8_t vCosited;
+	uint8_t hCosited;
+	uint8_t vCositedPhase;
+	uint8_t hCositedPhase;
+	uint16_t cropWidthFirstPixel;
+	uint16_t cropWidthLastPixel;
+	uint16_t cropHeightFirstLine;
+	uint16_t cropHeightLastLine;
+};
+
+enum VFE_START_PIXEL_PATTERN {
+	VFE_BAYER_RGRGRG,
+	VFE_BAYER_GRGRGR,
+	VFE_BAYER_BGBGBG,
+	VFE_BAYER_GBGBGB,
+	VFE_YUV_YCbYCr,
+	VFE_YUV_YCrYCb,
+	VFE_YUV_CbYCrY,
+	VFE_YUV_CrYCbY
+};
+
+enum VFE_BUS_RD_INPUT_PIXEL_PATTERN {
+	VFE_BAYER_RAW,
+	VFE_YUV_INTERLEAVED,
+	VFE_YUV_PSEUDO_PLANAR_Y,
+	VFE_YUV_PSEUDO_PLANAR_CBCR
+};
+
+enum VFE_YUV_INPUT_COSITING_MODE {
+	VFE_YUV_COSITED,
+	VFE_YUV_INTERPOLATED
+};
+
+struct vfe_cmds_demosaic_abf {
+	uint8_t   enable;
+	uint8_t   forceOn;
+	uint8_t   shift;
+	uint16_t  lpThreshold;
+	uint16_t  max;
+	uint16_t  min;
+	uint8_t   ratio;
+};
+
+struct vfe_cmds_demosaic_bpc {
+	uint8_t   enable;
+	uint16_t  fmaxThreshold;
+	uint16_t  fminThreshold;
+	uint16_t  redDiffThreshold;
+	uint16_t  blueDiffThreshold;
+	uint16_t  greenDiffThreshold;
+};
+
+struct vfe_cmd_demosaic_config {
+	uint8_t   enable;
+	uint8_t   slopeShift;
+	struct vfe_cmds_demosaic_abf abfConfig;
+	struct vfe_cmds_demosaic_bpc bpcConfig;
+};
+
+struct vfe_cmd_demosaic_bpc_update {
+	struct vfe_cmds_demosaic_bpc bpcUpdate;
+};
+
+struct vfe_cmd_demosaic_abf_update {
+	struct vfe_cmds_demosaic_abf abfUpdate;
+};
+
+struct vfe_cmd_white_balance_config {
+	uint8_t  enable;
+	uint16_t ch2Gain;
+	uint16_t ch1Gain;
+	uint16_t ch0Gain;
+};
+
+enum VFE_COLOR_CORRECTION_COEF_QFACTOR {
+	COEF_IS_Q7_SIGNED,
+	COEF_IS_Q8_SIGNED,
+	COEF_IS_Q9_SIGNED,
+	COEF_IS_Q10_SIGNED
+};
+
+struct vfe_cmd_color_correction_config {
+	uint8_t     enable;
+	enum VFE_COLOR_CORRECTION_COEF_QFACTOR coefQFactor;
+	int16_t  C0;
+	int16_t  C1;
+	int16_t  C2;
+	int16_t  C3;
+	int16_t  C4;
+	int16_t  C5;
+	int16_t  C6;
+	int16_t  C7;
+	int16_t  C8;
+	int16_t  K0;
+	int16_t  K1;
+	int16_t  K2;
+};
+
+#define VFE_LA_TABLE_LENGTH 64
+
+struct vfe_cmd_la_config {
+	uint8_t enable;
+	int16_t table[VFE_LA_TABLE_LENGTH];
+};
+
+#define VFE_GAMMA_TABLE_LENGTH 256
+enum VFE_RGB_GAMMA_TABLE_SELECT {
+	RGB_GAMMA_CH0_SELECTED,
+	RGB_GAMMA_CH1_SELECTED,
+	RGB_GAMMA_CH2_SELECTED,
+	RGB_GAMMA_CH0_CH1_SELECTED,
+	RGB_GAMMA_CH0_CH2_SELECTED,
+	RGB_GAMMA_CH1_CH2_SELECTED,
+	RGB_GAMMA_CH0_CH1_CH2_SELECTED
+};
+
+struct vfe_cmd_rgb_gamma_config {
+	uint8_t enable;
+	enum VFE_RGB_GAMMA_TABLE_SELECT channelSelect;
+	int16_t table[VFE_GAMMA_TABLE_LENGTH];
+};
+
+struct vfe_cmd_chroma_enhan_config {
+	uint8_t  enable;
+	int16_t am;
+	int16_t ap;
+	int16_t bm;
+	int16_t bp;
+	int16_t cm;
+	int16_t cp;
+	int16_t dm;
+	int16_t dp;
+	int16_t kcr;
+	int16_t kcb;
+	int16_t RGBtoYConversionV0;
+	int16_t RGBtoYConversionV1;
+	int16_t RGBtoYConversionV2;
+	uint8_t RGBtoYConversionOffset;
+};
+
+struct vfe_cmd_chroma_suppression_config {
+	uint8_t enable;
+	uint8_t m1;
+	uint8_t m3;
+	uint8_t n1;
+	uint8_t n3;
+	uint8_t nn1;
+	uint8_t mm1;
+};
+
+struct vfe_cmd_asf_config {
+	uint8_t enable;
+	uint8_t smoothFilterEnabled;
+	uint8_t sharpMode;
+	uint8_t smoothCoefCenter;
+	uint8_t smoothCoefSurr;
+	uint8_t normalizeFactor;
+	uint8_t sharpK1;
+	uint8_t sharpK2;
+	uint8_t sharpThreshE1;
+	int8_t sharpThreshE2;
+	int8_t sharpThreshE3;
+	int8_t sharpThreshE4;
+	int8_t sharpThreshE5;
+	int8_t filter1Coefficients[9];
+	int8_t filter2Coefficients[9];
+	uint8_t  cropEnable;
+	uint16_t cropFirstPixel;
+	uint16_t cropLastPixel;
+	uint16_t cropFirstLine;
+	uint16_t cropLastLine;
+};
+
+struct vfe_cmd_asf_update {
+	uint8_t enable;
+	uint8_t smoothFilterEnabled;
+	uint8_t sharpMode;
+	uint8_t smoothCoefCenter;
+	uint8_t smoothCoefSurr;
+	uint8_t normalizeFactor;
+	uint8_t sharpK1;
+	uint8_t sharpK2;
+	uint8_t sharpThreshE1;
+	int8_t  sharpThreshE2;
+	int8_t  sharpThreshE3;
+	int8_t  sharpThreshE4;
+	int8_t  sharpThreshE5;
+	int8_t  filter1Coefficients[9];
+	int8_t  filter2Coefficients[9];
+	uint8_t cropEnable;
+};
+
+enum VFE_TEST_GEN_SYNC_EDGE {
+	VFE_TEST_GEN_SYNC_EDGE_ActiveHigh,
+	VFE_TEST_GEN_SYNC_EDGE_ActiveLow
+};
+
+
+struct vfe_cmd_bus_pm_start {
+	uint8_t output2YWrPmEnable;
+	uint8_t output2CbcrWrPmEnable;
+	uint8_t output1YWrPmEnable;
+	uint8_t output1CbcrWrPmEnable;
+};
+
+struct  vfe_frame_skip_counts {
+	uint32_t  totalFrameCount;
+	uint32_t  output1Count;
+	uint32_t  output2Count;
+};
+
+enum VFE_AXI_RD_UNPACK_HBI_SEL {
+	VFE_AXI_RD_HBI_32_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_64_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_128_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_256_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_512_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_1024_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_2048_CLOCK_CYCLES,
+	VFE_AXI_RD_HBI_4096_CLOCK_CYCLES
+};
+
+struct vfe_frame_bpc_info {
+	uint32_t greenDefectPixelCount;
+	uint32_t redBlueDefectPixelCount;
+};
+
+struct vfe_frame_asf_info {
+	uint32_t  asfMaxEdge;
+	uint32_t  asfHbiCount;
+};
+
+struct vfe_msg_camif_status {
+	uint8_t  camifState;
+	uint32_t pixelCount;
+	uint32_t lineCount;
+};
+
+struct vfe40_irq_status {
+	uint32_t vfeIrqStatus0;
+	uint32_t vfeIrqStatus1;
+	uint32_t camifStatus;
+	uint32_t demosaicStatus;
+	uint32_t asfMaxEdge;
+};
+
+#define V40_PREVIEW_AXI_FLAG  0x00000001
+#define V40_SNAPSHOT_AXI_FLAG (0x00000001<<1)
+
+struct vfe40_cmd_type {
+	uint16_t id;
+	uint32_t length;
+	uint32_t offset;
+	uint32_t flag;
+};
+
+struct vfe40_free_buf {
+	struct list_head node;
+	uint32_t paddr;
+	uint32_t y_off;
+	uint32_t cbcr_off;
+};
+
+struct vfe40_output_ch {
+	struct list_head free_buf_queue;
+	spinlock_t free_buf_lock;
+	uint16_t image_mode;
+	int8_t ch0;
+	int8_t ch1;
+	int8_t ch2;
+	uint32_t  capture_cnt;
+	uint32_t  frame_drop_cnt;
+	struct msm_free_buf ping;
+	struct msm_free_buf pong;
+	struct msm_free_buf free_buf;
+};
+
+/* no error irq in mask 0 */
+#define VFE40_IMASK_ERROR_ONLY_0  0x0
+/* when normal case, don't want to block error status. */
+/* bit 0-21 are error irq bits */
+#define VFE40_IMASK_ERROR_ONLY_1               0x005FFFFF
+#define VFE40_IMASK_CAMIF_ERROR               (0x00000001<<0)
+#define VFE40_IMASK_BHIST_OVWR                (0x00000001<<1)
+#define VFE40_IMASK_STATS_CS_OVWR             (0x00000001<<2)
+#define VFE40_IMASK_STATS_IHIST_OVWR          (0x00000001<<3)
+#define VFE40_IMASK_REALIGN_BUF_Y_OVFL        (0x00000001<<4)
+#define VFE40_IMASK_REALIGN_BUF_CB_OVFL       (0x00000001<<5)
+#define VFE40_IMASK_REALIGN_BUF_CR_OVFL       (0x00000001<<6)
+#define VFE40_IMASK_VIOLATION                 (0x00000001<<7)
+#define VFE40_IMASK_IMG_MAST_0_BUS_OVFL       (0x00000001<<8)
+#define VFE40_IMASK_IMG_MAST_1_BUS_OVFL       (0x00000001<<9)
+#define VFE40_IMASK_IMG_MAST_2_BUS_OVFL       (0x00000001<<10)
+#define VFE40_IMASK_IMG_MAST_3_BUS_OVFL       (0x00000001<<11)
+#define VFE40_IMASK_IMG_MAST_4_BUS_OVFL       (0x00000001<<12)
+#define VFE40_IMASK_IMG_MAST_5_BUS_OVFL       (0x00000001<<13)
+#define VFE40_IMASK_IMG_MAST_6_BUS_OVFL       (0x00000001<<14)
+#define VFE40_IMASK_STATS_AE_BG_BUS_OVFL      (0x00000001<<15)
+#define VFE40_IMASK_STATS_AF_BF_BUS_OVFL      (0x00000001<<16)
+#define VFE40_IMASK_STATS_AWB_BUS_OVFL        (0x00000001<<17)
+#define VFE40_IMASK_STATS_RS_BUS_OVFL         (0x00000001<<18)
+#define VFE40_IMASK_STATS_CS_BUS_OVFL         (0x00000001<<19)
+#define VFE40_IMASK_STATS_IHIST_BUS_OVFL      (0x00000001<<20)
+#define VFE40_IMASK_STATS_SKIN_BHIST_BUS_OVFL (0x00000001<<21)
+#define VFE40_IMASK_AXI_ERROR                 (0x00000001<<22)
+
+#define VFE_COM_STATUS 0x000FE000
+
+struct vfe40_output_path {
+	uint16_t output_mode;     /* bitmask  */
+
+	struct vfe40_output_ch out0; /* preview and thumbnail */
+	struct vfe40_output_ch out1; /* snapshot */
+	struct vfe40_output_ch out2; /* video    */
+};
+
+struct vfe40_frame_extra {
+	uint32_t greenDefectPixelCount;
+	uint32_t redBlueDefectPixelCount;
+
+	uint32_t  asfMaxEdge;
+	uint32_t  asfHbiCount;
+
+	uint32_t yWrPmStats0;
+	uint32_t yWrPmStats1;
+	uint32_t cbcrWrPmStats0;
+	uint32_t cbcrWrPmStats1;
+
+	uint32_t  frameCounter;
+};
+
+#define VFE_CLEAR_ALL_IRQS              0xffffffff
+
+#define VFE_HW_VERSION			        0x00000000
+#define VFE_GLOBAL_RESET                0x0000000C
+#define VFE_MODULE_RESET                0x00000010
+#define VFE_CGC_OVERRIDE                0x00000014
+#define VFE_MODULE_CFG                  0x00000018
+#define VFE_CFG				            0x0000001C
+#define VFE_IRQ_CMD                     0x00000024
+#define VFE_IRQ_MASK_0                  0x00000028
+#define VFE_IRQ_MASK_1                  0x0000002C
+#define VFE_IRQ_CLEAR_0                 0x00000030
+#define VFE_IRQ_CLEAR_1                 0x00000034
+#define VFE_IRQ_STATUS_0                0x00000038
+#define VFE_IRQ_STATUS_1                0x0000003C
+#define VFE_IRQ_COMP_MASK               0x00000040
+#define VFE_BUS_CMD                     0x0000004C
+#define VFE_BUS_PING_PONG_STATUS        0x00000180
+#define VFE_AXI_CMD                     0x000001D8
+#define VFE_AXI_STATUS        0x000002C0
+#define VFE_BUS_STATS_PING_PONG_BASE    0x000000F4
+
+#define VFE_BUS_STATS_AEC_WR_PING_ADDR    0x000000F4
+#define VFE_BUS_STATS_AEC_WR_PONG_ADDR    0x000000F8
+#define VFE_BUS_STATS_AEC_UB_CFG          0x000000FC
+#define VFE_BUS_STATS_AF_WR_PING_ADDR     0x00000100
+#define VFE_BUS_STATS_AF_WR_PONG_ADDR     0x00000104
+#define VFE_BUS_STATS_AF_UB_CFG           0x00000108
+#define VFE_BUS_STATS_AWB_WR_PING_ADDR    0x0000010C
+#define VFE_BUS_STATS_AWB_WR_PONG_ADDR    0x00000110
+#define VFE_BUS_STATS_AWB_UB_CFG          0x00000114
+#define VFE_BUS_STATS_RS_WR_PING_ADDR    0x00000118
+#define VFE_BUS_STATS_RS_WR_PONG_ADDR    0x0000011C
+#define VFE_BUS_STATS_RS_UB_CFG          0x00000120
+#define VFE_BUS_STATS_CS_WR_PING_ADDR    0x00000124
+#define VFE_BUS_STATS_CS_WR_PONG_ADDR    0x00000128
+#define VFE_BUS_STATS_CS_UB_CFG          0x0000012C
+#define VFE_BUS_STATS_HIST_WR_PING_ADDR   0x00000130
+#define VFE_BUS_STATS_HIST_WR_PONG_ADDR   0x00000134
+#define VFE_BUS_STATS_HIST_UB_CFG          0x00000138
+#define VFE_BUS_STATS_SKIN_WR_PING_ADDR    0x0000013C
+#define VFE_BUS_STATS_SKIN_WR_PONG_ADDR    0x00000140
+#define VFE_BUS_STATS_SKIN_UB_CFG          0x00000144
+
+#define VFE_0_BUS_BDG_QOS_CFG_0     0x000002C4
+#define VFE_0_BUS_BDG_QOS_CFG_1     0x000002C8
+#define VFE_0_BUS_BDG_QOS_CFG_2     0x000002CC
+#define VFE_0_BUS_BDG_QOS_CFG_3     0x000002D0
+#define VFE_0_BUS_BDG_QOS_CFG_4     0x000002D4
+#define VFE_0_BUS_BDG_QOS_CFG_5     0x000002D8
+#define VFE_0_BUS_BDG_QOS_CFG_6     0x000002DC
+#define VFE_0_BUS_BDG_QOS_CFG_7     0x000002E0
+
+#define VFE_CAMIF_COMMAND               0x000002F4
+#define VFE_CAMIF_STATUS                0x0000031C
+#define VFE_REG_UPDATE_CMD              0x00000378
+#define VFE_DEMUX_GAIN_0                0x00000428
+#define VFE_DEMUX_GAIN_1                0x0000042C
+#define VFE_CHROMA_UP                   0x0000057C
+
+#define VFE_CLAMP_ENC_MAX               0x00000874
+#define VFE_CLAMP_ENC_MIN               0x00000878
+#define VFE_CLAMP_VIEW_MAX              0x0000087C
+#define VFE_CLAMP_VIEW_MIN              0x00000880
+
+#define VFE_REALIGN_BUF                 0x00000884
+#define VFE_STATS_CFG                   0x00000888
+#define VFE_STATS_AWB_SGW_CFG           0x000008CC
+#define VFE_DMI_CFG                     0x00000910
+#define VFE_DMI_ADDR                    0x00000914
+#define VFE_DMI_DATA_LO                 0x0000091C
+#define VFE_BUS_IO_FORMAT_CFG           0x00000054
+#define VFE_RDI0_CFG                    0x000002E8
+#define VFE_RDI1_CFG                    0x000002EC
+#define VFE_RDI2_CFG                    0x000002F0
+
+#define VFE_VIOLATION_STATUS            0x000007B4
+
+#define VFE40_DMI_DATA_HI               0x00000918
+#define VFE40_DMI_DATA_LO               0x0000091C
+
+#define VFE40_OUTPUT_MODE_PT			BIT(0)
+#define VFE40_OUTPUT_MODE_S			BIT(1)
+#define VFE40_OUTPUT_MODE_V			BIT(2)
+#define VFE40_OUTPUT_MODE_P			BIT(3)
+#define VFE40_OUTPUT_MODE_T			BIT(4)
+#define VFE40_OUTPUT_MODE_P_ALL_CHNLS		BIT(5)
+#define VFE40_OUTPUT_MODE_PRIMARY		BIT(6)
+#define VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS	BIT(7)
+#define VFE40_OUTPUT_MODE_SECONDARY		BIT(8)
+#define VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS	BIT(9)
+
+struct vfe_stats_control {
+	uint32_t droppedStatsFrameCount;
+	uint32_t bufToRender;
+};
+struct axi_ctrl_t;
+struct vfe40_ctrl_type;
+
+struct vfe_share_ctrl_t {
+	void __iomem *vfebase;
+	uint32_t register_total;
+
+	atomic_t vstate;
+	uint32_t vfeFrameId;
+	uint32_t stats_comp;
+	spinlock_t  stop_flag_lock;
+	int8_t stop_ack_pending;
+	enum vfe_output_state liveshot_state;
+	uint32_t vfe_capture_count;
+
+	uint16_t operation_mode;     /* streaming or snapshot */
+	struct vfe40_output_path outpath;
+
+	uint32_t ref_count;
+	spinlock_t  sd_notify_lock;
+	uint32_t vfe_clk_rate;
+
+	atomic_t irq_cnt;
+	struct axi_ctrl_t *axi_ctrl;
+	struct vfe40_ctrl_type *vfe40_ctrl;
+};
+
+struct axi_ctrl_t {
+	struct v4l2_subdev subdev;
+	struct platform_device *pdev;
+	struct resource *vfeirq;
+	spinlock_t  tasklet_lock;
+	struct list_head tasklet_q;
+
+	void *syncdata;
+
+	struct resource	*vfemem;
+	struct resource *vfeio;
+	struct regulator *fs_vfe;
+	struct clk *vfe_clk[3];
+	struct tasklet_struct vfe40_tasklet;
+	struct vfe_share_ctrl_t *share_ctrl;
+};
+
+struct vfe40_ctrl_type {
+	uint32_t vfeImaskCompositePacked;
+
+	spinlock_t  update_ack_lock;
+	spinlock_t  state_lock;
+	spinlock_t  io_lock;
+	spinlock_t  stats_bufq_lock;
+	uint32_t extlen;
+	void *extdata;
+
+	int8_t start_ack_pending;
+	int8_t reset_ack_pending;
+	int8_t update_ack_pending;
+	enum vfe_output_state recording_state;
+	int8_t update_linear;
+	int8_t update_rolloff;
+	int8_t update_la;
+	int8_t update_gamma;
+
+	struct vfe_share_ctrl_t *share_ctrl;
+
+	uint32_t sync_timer_repeat_count;
+	uint32_t sync_timer_state;
+	uint32_t sync_timer_number;
+
+	uint32_t output1Pattern;
+	uint32_t output1Period;
+	uint32_t output2Pattern;
+	uint32_t output2Period;
+	uint32_t vfeFrameSkipCount;
+	uint32_t vfeFrameSkipPeriod;
+	struct vfe_stats_control afStatsControl;
+	struct vfe_stats_control awbStatsControl;
+	struct vfe_stats_control aecStatsControl;
+	struct vfe_stats_control ihistStatsControl;
+	struct vfe_stats_control rsStatsControl;
+	struct vfe_stats_control csStatsControl;
+
+	/* v4l2 subdev */
+	struct v4l2_subdev subdev;
+	struct platform_device *pdev;
+	uint32_t hfr_mode;
+	uint32_t frame_skip_cnt;
+	uint32_t frame_skip_pattern;
+	uint32_t snapshot_frame_cnt;
+	struct msm_stats_bufq_ctrl stats_ctrl;
+	struct msm_stats_ops stats_ops;
+};
+
+#define statsAeNum      0
+#define statsAfNum      1
+#define statsAwbNum     2
+#define statsRsNum      3
+#define statsCsNum      4
+#define statsIhistNum   5
+#define statsSkinNum    6
+
+struct vfe_cmd_stats_ack {
+	uint32_t  nextStatsBuf;
+};
+
+#define VFE_STATS_BUFFER_COUNT            3
+
+struct vfe_cmd_stats_buf {
+	uint32_t statsBuf[VFE_STATS_BUFFER_COUNT];
+};
+
+void vfe40_subdev_notify(int id, int path, int image_mode,
+	struct v4l2_subdev *sd, struct vfe_share_ctrl_t *share_ctrl);
+struct vfe40_output_ch *vfe40_get_ch(
+	int path, struct vfe_share_ctrl_t *share_ctrl);
+void vfe40_send_isp_msg(struct v4l2_subdev *sd,
+	uint32_t vfeFrameId, uint32_t isp_msg_id);
+void vfe40_axi_probe(struct axi_ctrl_t *axi_ctrl);
+
+static const uint32_t vfe40_AXI_WM_CFG[] = {
+	0x0000006C,
+	0x00000090,
+	0x000000B4,
+	0x000000D8,
+	0x000000FC,
+	0x00000120,
+	0x00000144,
+};
+
+static struct vfe40_cmd_type vfe40_cmd[] = {
+/*0*/
+	{VFE_CMD_DUMMY_0},
+	{VFE_CMD_SET_CLK},
+	{VFE_CMD_RESET},
+	{VFE_CMD_START},
+	{VFE_CMD_TEST_GEN_START},
+/*5*/
+	{VFE_CMD_OPERATION_CFG, V40_OPERATION_CFG_LEN},
+	{VFE_CMD_AXI_OUT_CFG, V40_AXI_OUT_LEN, V40_AXI_OUT_OFF, 0xFF},
+	{VFE_CMD_CAMIF_CFG, V40_CAMIF_LEN, V40_CAMIF_OFF, 0xFF},
+	{VFE_CMD_AXI_INPUT_CFG},
+	{VFE_CMD_BLACK_LEVEL_CFG},
+/*10*/
+	{VFE_CMD_MESH_ROLL_OFF_CFG},
+	{VFE_CMD_DEMUX_CFG, V40_DEMUX_LEN, V40_DEMUX_OFF, 0xFF},
+	{VFE_CMD_FOV_CFG},
+	{VFE_CMD_MAIN_SCALER_CFG},
+	{VFE_CMD_WB_CFG, V40_WB_LEN, V40_WB_OFF, 0xFF},
+/*15*/
+	{VFE_CMD_COLOR_COR_CFG, V40_COLOR_COR_LEN, V40_COLOR_COR_OFF, 0xFF},
+	{VFE_CMD_RGB_G_CFG, V40_RGB_G_LEN, V40_RGB_G_OFF, 0xFF},
+	{VFE_CMD_LA_CFG, V40_LA_LEN, V40_LA_OFF, 0xFF },
+	{VFE_CMD_CHROMA_EN_CFG, V40_CHROMA_EN_LEN, V40_CHROMA_EN_OFF, 0xFF},
+	{VFE_CMD_CHROMA_SUP_CFG, V40_CHROMA_SUP_LEN, V40_CHROMA_SUP_OFF, 0xFF},
+/*20*/
+	{VFE_CMD_MCE_CFG, V40_MCE_LEN, V40_MCE_OFF, 0xFF},
+	{VFE_CMD_SK_ENHAN_CFG, V40_SCE_LEN, V40_SCE_OFF, 0xFF},
+	{VFE_CMD_ASF_CFG, V40_ASF_LEN, V40_ASF_OFF, 0xFF},
+	{VFE_CMD_S2Y_CFG},
+	{VFE_CMD_S2CbCr_CFG},
+/*25*/
+	{VFE_CMD_CHROMA_SUBS_CFG},
+	{VFE_CMD_OUT_CLAMP_CFG, V40_OUT_CLAMP_LEN, V40_OUT_CLAMP_OFF, 0xFF},
+	{VFE_CMD_FRAME_SKIP_CFG},
+	{VFE_CMD_DUMMY_1},
+	{VFE_CMD_DUMMY_2},
+/*30*/
+	{VFE_CMD_DUMMY_3},
+	{VFE_CMD_UPDATE},
+	{VFE_CMD_BL_LVL_UPDATE},
+	{VFE_CMD_DEMUX_UPDATE, V40_DEMUX_LEN, V40_DEMUX_OFF, 0xFF},
+	{VFE_CMD_FOV_UPDATE},
+/*35*/
+	{VFE_CMD_MAIN_SCALER_UPDATE},
+	{VFE_CMD_WB_UPDATE, V40_WB_LEN, V40_WB_OFF, 0xFF},
+	{VFE_CMD_COLOR_COR_UPDATE, V40_COLOR_COR_LEN, V40_COLOR_COR_OFF, 0xFF},
+	{VFE_CMD_RGB_G_UPDATE, V40_RGB_G_LEN, V40_CHROMA_EN_OFF, 0xFF},
+	{VFE_CMD_LA_UPDATE, V40_LA_LEN, V40_LA_OFF, 0xFF },
+/*40*/
+	{VFE_CMD_CHROMA_EN_UPDATE, V40_CHROMA_EN_LEN, V40_CHROMA_EN_OFF, 0xFF},
+	{VFE_CMD_CHROMA_SUP_UPDATE, V40_CHROMA_SUP_LEN,
+		V40_CHROMA_SUP_OFF, 0xFF},
+	{VFE_CMD_MCE_UPDATE, V40_MCE_LEN, V40_MCE_OFF, 0xFF},
+	{VFE_CMD_SK_ENHAN_UPDATE, V40_SCE_LEN, V40_SCE_OFF, 0xFF},
+	{VFE_CMD_S2CbCr_UPDATE},
+/*45*/
+	{VFE_CMD_S2Y_UPDATE},
+	{VFE_CMD_ASF_UPDATE, V40_ASF_UPDATE_LEN, V40_ASF_OFF, 0xFF},
+	{VFE_CMD_FRAME_SKIP_UPDATE},
+	{VFE_CMD_CAMIF_FRAME_UPDATE},
+	{VFE_CMD_STATS_AF_UPDATE},
+/*50*/
+	{VFE_CMD_STATS_AE_UPDATE},
+	{VFE_CMD_STATS_AWB_UPDATE, V40_STATS_AWB_LEN, V40_STATS_AWB_OFF},
+	{VFE_CMD_STATS_RS_UPDATE, V40_STATS_RS_LEN, V40_STATS_RS_OFF},
+	{VFE_CMD_STATS_CS_UPDATE, V40_STATS_CS_LEN, V40_STATS_CS_OFF},
+	{VFE_CMD_STATS_SKIN_UPDATE},
+/*55*/
+	{VFE_CMD_STATS_IHIST_UPDATE, V40_STATS_IHIST_LEN, V40_STATS_IHIST_OFF},
+	{VFE_CMD_DUMMY_4},
+	{VFE_CMD_EPOCH1_ACK},
+	{VFE_CMD_EPOCH2_ACK},
+	{VFE_CMD_START_RECORDING},
+/*60*/
+	{VFE_CMD_STOP_RECORDING},
+	{VFE_CMD_DUMMY_5},
+	{VFE_CMD_DUMMY_6},
+	{VFE_CMD_CAPTURE, V40_CAPTURE_LEN, 0xFF},
+	{VFE_CMD_DUMMY_7},
+/*65*/
+	{VFE_CMD_STOP},
+	{VFE_CMD_GET_HW_VERSION, V40_GET_HW_VERSION_LEN,
+		V40_GET_HW_VERSION_OFF},
+	{VFE_CMD_GET_FRAME_SKIP_COUNTS},
+	{VFE_CMD_OUTPUT1_BUFFER_ENQ},
+	{VFE_CMD_OUTPUT2_BUFFER_ENQ},
+/*70*/
+	{VFE_CMD_OUTPUT3_BUFFER_ENQ},
+	{VFE_CMD_JPEG_OUT_BUF_ENQ},
+	{VFE_CMD_RAW_OUT_BUF_ENQ},
+	{VFE_CMD_RAW_IN_BUF_ENQ},
+	{VFE_CMD_STATS_AF_ENQ},
+/*75*/
+	{VFE_CMD_STATS_AE_ENQ},
+	{VFE_CMD_STATS_AWB_ENQ},
+	{VFE_CMD_STATS_RS_ENQ},
+	{VFE_CMD_STATS_CS_ENQ},
+	{VFE_CMD_STATS_SKIN_ENQ},
+/*80*/
+	{VFE_CMD_STATS_IHIST_ENQ},
+	{VFE_CMD_DUMMY_8},
+	{VFE_CMD_JPEG_ENC_CFG},
+	{VFE_CMD_DUMMY_9},
+	{VFE_CMD_STATS_AF_START},
+/*85*/
+	{VFE_CMD_STATS_AF_STOP},
+	{VFE_CMD_STATS_AE_START},
+	{VFE_CMD_STATS_AE_STOP},
+	{VFE_CMD_STATS_AWB_START, V40_STATS_AWB_LEN, V40_STATS_AWB_OFF},
+	{VFE_CMD_STATS_AWB_STOP},
+/*90*/
+	{VFE_CMD_STATS_RS_START, V40_STATS_RS_LEN, V40_STATS_RS_OFF},
+	{VFE_CMD_STATS_RS_STOP},
+	{VFE_CMD_STATS_CS_START, V40_STATS_CS_LEN, V40_STATS_CS_OFF},
+	{VFE_CMD_STATS_CS_STOP},
+	{VFE_CMD_STATS_SKIN_START},
+/*95*/
+	{VFE_CMD_STATS_SKIN_STOP},
+	{VFE_CMD_STATS_IHIST_START, V40_STATS_IHIST_LEN, V40_STATS_IHIST_OFF},
+	{VFE_CMD_STATS_IHIST_STOP},
+	{VFE_CMD_DUMMY_10},
+	{VFE_CMD_SYNC_TIMER_SETTING, V40_SYNC_TIMER_LEN, V40_SYNC_TIMER_OFF},
+/*100*/
+	{VFE_CMD_ASYNC_TIMER_SETTING, V40_ASYNC_TIMER_LEN, V40_ASYNC_TIMER_OFF},
+	{VFE_CMD_LIVESHOT},
+	{VFE_CMD_LA_SETUP},
+	{VFE_CMD_LINEARIZATION_CFG, V40_LINEARIZATION_LEN1,
+		V40_LINEARIZATION_OFF1},
+	{VFE_CMD_DEMOSAICV3},
+/*105*/
+	{VFE_CMD_DEMOSAICV3_ABCC_CFG},
+	{VFE_CMD_DEMOSAICV3_DBCC_CFG, V40_DEMOSAICV3_DBCC_LEN,
+		V40_DEMOSAICV3_DBCC_OFF},
+	{VFE_CMD_DEMOSAICV3_DBPC_CFG},
+	{VFE_CMD_DEMOSAICV3_ABF_CFG, V40_DEMOSAICV3_ABF_LEN,
+		V40_DEMOSAICV3_ABF_OFF},
+	{VFE_CMD_DEMOSAICV3_ABCC_UPDATE},
+/*110*/
+	{VFE_CMD_DEMOSAICV3_DBCC_UPDATE, V40_DEMOSAICV3_DBCC_LEN,
+		V40_DEMOSAICV3_DBCC_OFF},
+	{VFE_CMD_DEMOSAICV3_DBPC_UPDATE},
+	{VFE_CMD_XBAR_CFG},
+	{VFE_CMD_MODULE_CFG, V40_MODULE_CFG_LEN, V40_MODULE_CFG_OFF},
+	{VFE_CMD_ZSL},
+/*115*/
+	{VFE_CMD_LINEARIZATION_UPDATE, V40_LINEARIZATION_LEN1,
+		V40_LINEARIZATION_OFF1},
+	{VFE_CMD_DEMOSAICV3_ABF_UPDATE, V40_DEMOSAICV3_ABF_LEN,
+		V40_DEMOSAICV3_ABF_OFF},
+	{VFE_CMD_CLF_CFG, V40_CLF_CFG_LEN, V40_CLF_CFG_OFF},
+	{VFE_CMD_CLF_LUMA_UPDATE, V40_CLF_LUMA_UPDATE_LEN,
+		V40_CLF_LUMA_UPDATE_OFF},
+	{VFE_CMD_CLF_CHROMA_UPDATE, V40_CLF_CHROMA_UPDATE_LEN,
+		V40_CLF_CHROMA_UPDATE_OFF},
+/*120*/
+	{VFE_CMD_PCA_ROLL_OFF_CFG},
+	{VFE_CMD_PCA_ROLL_OFF_UPDATE},
+	{VFE_CMD_GET_REG_DUMP},
+	{VFE_CMD_GET_LINEARIZATON_TABLE},
+	{VFE_CMD_GET_MESH_ROLLOFF_TABLE},
+/*125*/
+	{VFE_CMD_GET_PCA_ROLLOFF_TABLE},
+	{VFE_CMD_GET_RGB_G_TABLE},
+	{VFE_CMD_GET_LA_TABLE},
+	{VFE_CMD_DEMOSAICV3_UPDATE},
+	{VFE_CMD_ACTIVE_REGION_CFG},
+/*130*/
+	{VFE_CMD_COLOR_PROCESSING_CONFIG},
+	{VFE_CMD_STATS_WB_AEC_CONFIG},
+	{VFE_CMD_STATS_WB_AEC_UPDATE},
+	{VFE_CMD_Y_GAMMA_CONFIG},
+	{VFE_CMD_SCALE_OUTPUT1_CONFIG},
+/*135*/
+	{VFE_CMD_SCALE_OUTPUT2_CONFIG},
+	{VFE_CMD_CAPTURE_RAW},
+	{VFE_CMD_STOP_LIVESHOT},
+	{VFE_CMD_RECONFIG_VFE},
+	{VFE_CMD_STATS_REQBUF},
+/*140*/
+	{VFE_CMD_STATS_ENQUEUEBUF},
+	{VFE_CMD_STATS_FLUSH_BUFQ},
+	{VFE_CMD_FOV_ENC_CFG, V40_FOV_ENC_LEN, V40_FOV_ENC_OFF, 0xFF},
+	{VFE_CMD_FOV_VIEW_CFG, V40_FOV_VIEW_LEN, V40_FOV_VIEW_OFF, 0xFF},
+	{VFE_CMD_FOV_ENC_UPDATE, V40_FOV_ENC_LEN, V40_FOV_ENC_OFF, 0xFF},
+/*145*/
+	{VFE_CMD_FOV_VIEW_UPDATE, V40_FOV_VIEW_LEN, V40_FOV_VIEW_OFF, 0xFF},
+	{VFE_CMD_SCALER_ENC_CFG, V40_SCALER_ENC_LEN, V40_SCALER_ENC_OFF, 0xFF},
+	{VFE_CMD_SCALER_VIEW_CFG, V40_SCALER_VIEW_LEN,
+		V40_SCALER_VIEW_OFF, 0xFF},
+	{VFE_CMD_SCALER_ENC_UPDATE, V40_SCALER_ENC_LEN,
+		V40_SCALER_ENC_OFF, 0xFF},
+	{VFE_CMD_SCALER_VIEW_UPDATE, V40_SCALER_VIEW_LEN,
+		V40_SCALER_VIEW_OFF, 0xFF},
+/*150*/
+	{VFE_CMD_COLORXFORM_ENC_CFG, V40_COLORXFORM_ENC_CFG_LEN,
+		V40_COLORXFORM_ENC_CFG_OFF, 0xFF},
+	{VFE_CMD_COLORXFORM_VIEW_CFG, V40_COLORXFORM_VIEW_CFG_LEN,
+		V40_COLORXFORM_VIEW_CFG_OFF},
+	{VFE_CMD_COLORXFORM_ENC_UPDATE, V40_COLORXFORM_ENC_CFG_LEN,
+		V40_COLORXFORM_ENC_CFG_OFF, 0xFF},
+	{VFE_CMD_COLORXFORM_VIEW_UPDATE, V40_COLORXFORM_VIEW_CFG_LEN,
+		V40_COLORXFORM_VIEW_CFG_OFF, 0xFF},
+};
+
+#endif /* __MSM_VFE40_H__ */
diff --git a/drivers/media/video/msm/vfe/msm_vfe40_axi.c b/drivers/media/video/msm/vfe/msm_vfe40_axi.c
new file mode 100644
index 0000000..35d5207
--- /dev/null
+++ b/drivers/media/video/msm/vfe/msm_vfe40_axi.c
@@ -0,0 +1,812 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/atomic.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
+#include <mach/irqs.h>
+#include <mach/camera.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/msm_isp.h>
+
+#include "msm.h"
+#include "msm_vfe40.h"
+
+static int msm_axi_subdev_s_crystal_freq(struct v4l2_subdev *sd,
+						u32 freq, u32 flags)
+{
+	int rc = 0;
+	int round_rate;
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+
+	round_rate = clk_round_rate(axi_ctrl->vfe_clk[0], freq);
+	if (rc < 0) {
+		pr_err("%s: clk_round_rate failed %d\n",
+					__func__, rc);
+		return rc;
+	}
+
+	axi_ctrl->share_ctrl->vfe_clk_rate = round_rate;
+	rc = clk_set_rate(axi_ctrl->vfe_clk[0], round_rate);
+	if (rc < 0)
+		pr_err("%s: clk_set_rate failed %d\n",
+					__func__, rc);
+
+	return rc;
+}
+
+void axi_start(struct axi_ctrl_t *axi_ctrl)
+{
+	switch (axi_ctrl->share_ctrl->operation_mode) {
+	case VFE_OUTPUTS_PREVIEW:
+	case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
+		if (axi_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_PRIMARY) {
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out0.ch0]);
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out0.ch1]);
+		} else if (axi_ctrl->share_ctrl->outpath.output_mode &
+				VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out0.ch0]);
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out0.ch1]);
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out0.ch2]);
+		}
+		break;
+	default:
+		if (axi_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_SECONDARY) {
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out1.ch0]);
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out1.ch1]);
+		} else if (axi_ctrl->share_ctrl->outpath.output_mode &
+			VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out1.ch0]);
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out1.ch1]);
+			msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+				vfe40_AXI_WM_CFG[axi_ctrl->
+				share_ctrl->outpath.out1.ch2]);
+		}
+		break;
+	}
+}
+
+void axi_stop(struct axi_ctrl_t *axi_ctrl)
+{
+	uint8_t  axiBusyFlag = true;
+	/* axi halt command. */
+	msm_camera_io_w(AXI_HALT,
+		axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD);
+	wmb();
+	while (axiBusyFlag) {
+		if (msm_camera_io_r(
+			axi_ctrl->share_ctrl->vfebase + VFE_AXI_STATUS) & 0x1)
+			axiBusyFlag = false;
+	}
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_camera_io_w_mb(AXI_HALT_CLEAR,
+		axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD);
+
+	/* after axi halt, then ok to apply global reset. */
+	/* enable reset_ack and async timer interrupt only while
+	stopping the pipeline.*/
+	msm_camera_io_w(0xf0000000,
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+	msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
+		axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+	/* Ensure the write order while writing
+	to the command register using the barrier */
+	msm_camera_io_w_mb(VFE_RESET_UPON_STOP_CMD,
+		axi_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
+}
+
+static int vfe40_config_axi(
+	struct axi_ctrl_t *axi_ctrl, int mode, uint32_t *ao)
+{
+	uint32_t *ch_info;
+	uint32_t *axi_cfg = ao;
+
+	/* Update the corresponding write masters for each output*/
+	ch_info = axi_cfg + V40_AXI_CFG_LEN;
+	axi_ctrl->share_ctrl->outpath.out0.ch0 = 0x0000FFFF & *ch_info;
+	axi_ctrl->share_ctrl->outpath.out0.ch1 =
+		0x0000FFFF & (*ch_info++ >> 16);
+	axi_ctrl->share_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info;
+	axi_ctrl->share_ctrl->outpath.out0.image_mode =
+		0x0000FFFF & (*ch_info++ >> 16);
+	axi_ctrl->share_ctrl->outpath.out1.ch0 = 0x0000FFFF & *ch_info;
+	axi_ctrl->share_ctrl->outpath.out1.ch1 =
+		0x0000FFFF & (*ch_info++ >> 16);
+	axi_ctrl->share_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info;
+	axi_ctrl->share_ctrl->outpath.out1.image_mode =
+		0x0000FFFF & (*ch_info++ >> 16);
+	axi_ctrl->share_ctrl->outpath.out2.ch0 = 0x0000FFFF & *ch_info;
+	axi_ctrl->share_ctrl->outpath.out2.ch1 =
+		0x0000FFFF & (*ch_info++ >> 16);
+	axi_ctrl->share_ctrl->outpath.out2.ch2 = 0x0000FFFF & *ch_info++;
+
+	switch (mode) {
+	case OUTPUT_PRIM:
+		axi_ctrl->share_ctrl->outpath.output_mode =
+			VFE40_OUTPUT_MODE_PRIMARY;
+		break;
+	case OUTPUT_PRIM_ALL_CHNLS:
+		axi_ctrl->share_ctrl->outpath.output_mode =
+			VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
+		break;
+	case OUTPUT_PRIM|OUTPUT_SEC:
+		axi_ctrl->share_ctrl->outpath.output_mode =
+			VFE40_OUTPUT_MODE_PRIMARY;
+		axi_ctrl->share_ctrl->outpath.output_mode |=
+			VFE40_OUTPUT_MODE_SECONDARY;
+		break;
+	case OUTPUT_PRIM|OUTPUT_SEC_ALL_CHNLS:
+		axi_ctrl->share_ctrl->outpath.output_mode =
+			VFE40_OUTPUT_MODE_PRIMARY;
+		axi_ctrl->share_ctrl->outpath.output_mode |=
+			VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS;
+		break;
+	case OUTPUT_PRIM_ALL_CHNLS|OUTPUT_SEC:
+		axi_ctrl->share_ctrl->outpath.output_mode =
+			VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
+		axi_ctrl->share_ctrl->outpath.output_mode |=
+			VFE40_OUTPUT_MODE_SECONDARY;
+		break;
+	default:
+		pr_err("%s Invalid AXI mode %d ", __func__, mode);
+		return -EINVAL;
+	}
+	msm_camera_io_w(*ao, axi_ctrl->share_ctrl->vfebase +
+		VFE_BUS_IO_FORMAT_CFG);
+	msm_camera_io_memcpy(axi_ctrl->share_ctrl->vfebase +
+		vfe40_cmd[VFE_CMD_AXI_OUT_CFG].offset, axi_cfg,
+		vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length - V40_AXI_CH_INF_LEN);
+	return 0;
+}
+
+static int msm_axi_config(struct v4l2_subdev *sd, void __user *arg)
+{
+	struct msm_vfe_cfg_cmd cfgcmd;
+	struct msm_isp_cmd vfecmd;
+	int rc = 0;
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+
+	if (!axi_ctrl->share_ctrl->vfebase) {
+		pr_err("%s: base address unmapped\n", __func__);
+		return -EFAULT;
+	}
+	if (NULL != arg) {
+		if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
+			ERR_COPY_FROM_USER();
+			return -EFAULT;
+		}
+	}
+	if (NULL != cfgcmd.value) {
+		if (copy_from_user(&vfecmd,
+				(void __user *)(cfgcmd.value),
+				sizeof(vfecmd))) {
+			pr_err("%s %d: copy_from_user failed\n", __func__,
+				__LINE__);
+			return -EFAULT;
+		}
+	}
+
+	switch (cfgcmd.cmd_type) {
+	case CMD_AXI_CFG_PRIM: {
+		uint32_t *axio = NULL;
+		axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			rc = -EFAULT;
+			break;
+		}
+		vfe40_config_axi(axi_ctrl, OUTPUT_PRIM, axio);
+		kfree(axio);
+	}
+		break;
+	case CMD_AXI_CFG_PRIM_ALL_CHNLS: {
+		uint32_t *axio = NULL;
+		axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			rc = -EFAULT;
+			break;
+		}
+		vfe40_config_axi(axi_ctrl, OUTPUT_PRIM_ALL_CHNLS, axio);
+		kfree(axio);
+	}
+		break;
+	case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC: {
+		uint32_t *axio = NULL;
+		axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			rc = -EFAULT;
+			break;
+		}
+		vfe40_config_axi(axi_ctrl, OUTPUT_PRIM|OUTPUT_SEC, axio);
+		kfree(axio);
+	}
+		break;
+	case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC_ALL_CHNLS: {
+		uint32_t *axio = NULL;
+		axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			rc = -EFAULT;
+			break;
+		}
+		vfe40_config_axi(axi_ctrl,
+			OUTPUT_PRIM|OUTPUT_SEC_ALL_CHNLS, axio);
+		kfree(axio);
+	}
+		break;
+	case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC: {
+		uint32_t *axio = NULL;
+		axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+				GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user(axio, (void __user *)(vfecmd.value),
+				vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+			kfree(axio);
+			rc = -EFAULT;
+			break;
+		}
+		vfe40_config_axi(axi_ctrl,
+			OUTPUT_PRIM_ALL_CHNLS|OUTPUT_SEC, axio);
+		kfree(axio);
+	}
+		break;
+	case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC_ALL_CHNLS:
+		pr_err("%s Invalid/Unsupported AXI configuration %x",
+			__func__, cfgcmd.cmd_type);
+		break;
+	case CMD_AXI_START:
+		axi_start(axi_ctrl);
+		break;
+	case CMD_AXI_STOP:
+		axi_stop(axi_ctrl);
+		break;
+	default:
+		pr_err("%s Unsupported AXI configuration %x ", __func__,
+			cfgcmd.cmd_type);
+		break;
+	}
+	return rc;
+}
+
+static struct msm_free_buf *vfe40_check_free_buffer(
+	int id, int path, struct axi_ctrl_t *axi_ctrl)
+{
+	struct vfe40_output_ch *outch = NULL;
+	struct msm_free_buf *b = NULL;
+	uint32_t image_mode = 0;
+
+	if (path == VFE_MSG_OUTPUT_PRIMARY)
+		image_mode = axi_ctrl->share_ctrl->outpath.out0.image_mode;
+	else
+		image_mode = axi_ctrl->share_ctrl->outpath.out1.image_mode;
+
+	vfe40_subdev_notify(id, path, image_mode,
+		&axi_ctrl->subdev, axi_ctrl->share_ctrl);
+	outch = vfe40_get_ch(path, axi_ctrl->share_ctrl);
+	if (outch->free_buf.ch_paddr[0])
+		b = &outch->free_buf;
+	return b;
+}
+
+static void vfe_send_outmsg(
+	struct axi_ctrl_t *axi_ctrl, uint8_t msgid,
+	uint32_t ch0_paddr, uint32_t ch1_paddr,
+	uint32_t ch2_paddr, uint32_t image_mode)
+{
+	struct isp_msg_output msg;
+
+	msg.output_id = msgid;
+	msg.buf.image_mode = image_mode;
+	msg.buf.ch_paddr[0]	= ch0_paddr;
+	msg.buf.ch_paddr[1]	= ch1_paddr;
+	msg.buf.ch_paddr[2]	= ch2_paddr;
+	msg.frameCounter = axi_ctrl->share_ctrl->vfeFrameId;
+
+	v4l2_subdev_notify(&axi_ctrl->subdev,
+			NOTIFY_VFE_MSG_OUT,
+			&msg);
+	return;
+}
+
+static void vfe40_process_output_path_irq_0(
+	struct axi_ctrl_t *axi_ctrl)
+{
+	uint32_t ping_pong;
+	uint32_t ch0_paddr, ch1_paddr, ch2_paddr;
+	uint8_t out_bool = 0;
+	struct msm_free_buf *free_buf = NULL;
+
+	free_buf = vfe40_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
+		VFE_MSG_OUTPUT_PRIMARY, axi_ctrl);
+
+	/* we render frames in the following conditions:
+	1. Continuous mode and the free buffer is avaialable.
+	2. In snapshot shot mode, free buffer is not always available.
+	when pending snapshot count is <=1,  then no need to use
+	free buffer.
+	*/
+	out_bool = (
+		(axi_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_THUMB_AND_MAIN ||
+		axi_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_MAIN_AND_THUMB ||
+		axi_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_THUMB_AND_JPEG ||
+		axi_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_JPEG_AND_THUMB ||
+		axi_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_RAW ||
+		axi_ctrl->share_ctrl->liveshot_state ==
+			VFE_STATE_STARTED ||
+		axi_ctrl->share_ctrl->liveshot_state ==
+			VFE_STATE_STOP_REQUESTED ||
+		axi_ctrl->share_ctrl->liveshot_state ==
+			VFE_STATE_STOPPED) &&
+		(axi_ctrl->share_ctrl->vfe_capture_count <= 1)) ||
+			free_buf;
+
+	if (out_bool) {
+		ping_pong = msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
+			VFE_BUS_PING_PONG_STATUS);
+
+		/* Channel 0*/
+		ch0_paddr = vfe40_get_ch_addr(
+			ping_pong, axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out0.ch0);
+		/* Channel 1*/
+		ch1_paddr = vfe40_get_ch_addr(
+			ping_pong, axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out0.ch1);
+		/* Channel 2*/
+		ch2_paddr = vfe40_get_ch_addr(
+			ping_pong, axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out0.ch2);
+
+		CDBG("output path 0, ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
+			ch0_paddr, ch1_paddr, ch2_paddr);
+		if (free_buf) {
+			/* Y channel */
+			vfe40_put_ch_addr(ping_pong,
+			axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out0.ch0,
+			free_buf->ch_paddr[0]);
+			/* Chroma channel */
+			vfe40_put_ch_addr(ping_pong,
+			axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out0.ch1,
+			free_buf->ch_paddr[1]);
+			if (free_buf->num_planes > 2)
+				vfe40_put_ch_addr(ping_pong,
+					axi_ctrl->share_ctrl->vfebase,
+					axi_ctrl->share_ctrl->outpath.out0.ch2,
+					free_buf->ch_paddr[2]);
+		}
+		if (axi_ctrl->share_ctrl->operation_mode ==
+				VFE_OUTPUTS_THUMB_AND_MAIN ||
+			axi_ctrl->share_ctrl->operation_mode ==
+				VFE_OUTPUTS_MAIN_AND_THUMB ||
+			axi_ctrl->share_ctrl->operation_mode ==
+				VFE_OUTPUTS_THUMB_AND_JPEG ||
+			axi_ctrl->share_ctrl->operation_mode ==
+				VFE_OUTPUTS_JPEG_AND_THUMB ||
+			axi_ctrl->share_ctrl->operation_mode ==
+				VFE_OUTPUTS_RAW ||
+			axi_ctrl->share_ctrl->liveshot_state ==
+				VFE_STATE_STOPPED)
+			axi_ctrl->share_ctrl->outpath.out0.capture_cnt--;
+
+		vfe_send_outmsg(axi_ctrl,
+			MSG_ID_OUTPUT_PRIMARY, ch0_paddr,
+			ch1_paddr, ch2_paddr,
+			axi_ctrl->share_ctrl->outpath.out0.image_mode);
+
+		if (axi_ctrl->share_ctrl->liveshot_state == VFE_STATE_STOPPED)
+			axi_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
+
+	} else {
+		axi_ctrl->share_ctrl->outpath.out0.frame_drop_cnt++;
+		CDBG("path_irq_0 - no free buffer!\n");
+	}
+}
+
+static void vfe40_process_output_path_irq_1(
+	struct axi_ctrl_t *axi_ctrl)
+{
+	uint32_t ping_pong;
+	uint32_t ch0_paddr, ch1_paddr, ch2_paddr;
+	/* this must be snapshot main image output. */
+	uint8_t out_bool = 0;
+	struct msm_free_buf *free_buf = NULL;
+
+	free_buf = vfe40_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
+		VFE_MSG_OUTPUT_SECONDARY, axi_ctrl);
+	out_bool = ((axi_ctrl->share_ctrl->operation_mode ==
+				VFE_OUTPUTS_THUMB_AND_MAIN ||
+			axi_ctrl->share_ctrl->operation_mode ==
+				VFE_OUTPUTS_MAIN_AND_THUMB ||
+			axi_ctrl->share_ctrl->operation_mode ==
+				VFE_OUTPUTS_RAW ||
+			axi_ctrl->share_ctrl->operation_mode ==
+				VFE_OUTPUTS_JPEG_AND_THUMB) &&
+			(axi_ctrl->share_ctrl->vfe_capture_count <= 1)) ||
+				free_buf;
+
+	if (out_bool) {
+		ping_pong = msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
+			VFE_BUS_PING_PONG_STATUS);
+
+		/* Y channel */
+		ch0_paddr = vfe40_get_ch_addr(ping_pong,
+			axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out1.ch0);
+		/* Chroma channel */
+		ch1_paddr = vfe40_get_ch_addr(ping_pong,
+			axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out1.ch1);
+		ch2_paddr = vfe40_get_ch_addr(ping_pong,
+			axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out1.ch2);
+
+		CDBG("%s ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
+			__func__, ch0_paddr, ch1_paddr, ch2_paddr);
+		if (free_buf) {
+			/* Y channel */
+			vfe40_put_ch_addr(ping_pong,
+			axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out1.ch0,
+			free_buf->ch_paddr[0]);
+			/* Chroma channel */
+			vfe40_put_ch_addr(ping_pong,
+			axi_ctrl->share_ctrl->vfebase,
+			axi_ctrl->share_ctrl->outpath.out1.ch1,
+			free_buf->ch_paddr[1]);
+			if (free_buf->num_planes > 2)
+				vfe40_put_ch_addr(ping_pong,
+					axi_ctrl->share_ctrl->vfebase,
+					axi_ctrl->share_ctrl->outpath.out1.ch2,
+					free_buf->ch_paddr[2]);
+		}
+		if (axi_ctrl->share_ctrl->operation_mode ==
+				VFE_OUTPUTS_THUMB_AND_MAIN ||
+			axi_ctrl->share_ctrl->operation_mode ==
+				VFE_OUTPUTS_MAIN_AND_THUMB ||
+			axi_ctrl->share_ctrl->operation_mode ==
+				VFE_OUTPUTS_RAW ||
+			axi_ctrl->share_ctrl->operation_mode ==
+				VFE_OUTPUTS_JPEG_AND_THUMB)
+			axi_ctrl->share_ctrl->outpath.out1.capture_cnt--;
+
+		vfe_send_outmsg(axi_ctrl,
+			MSG_ID_OUTPUT_SECONDARY, ch0_paddr,
+			ch1_paddr, ch2_paddr,
+			axi_ctrl->share_ctrl->outpath.out1.image_mode);
+
+	} else {
+		axi_ctrl->share_ctrl->outpath.out1.frame_drop_cnt++;
+		CDBG("path_irq_1 - no free buffer!\n");
+	}
+}
+
+static void msm_axi_process_irq(struct v4l2_subdev *sd, void *arg)
+{
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+	uint32_t irqstatus = (uint32_t) arg;
+
+	if (!axi_ctrl->share_ctrl->vfebase) {
+		pr_err("%s: base address unmapped\n", __func__);
+		return;
+	}
+	/* next, check output path related interrupts. */
+	if (irqstatus &
+		VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK) {
+		CDBG("Image composite done 0 irq occured.\n");
+		vfe40_process_output_path_irq_0(axi_ctrl);
+	}
+	if (irqstatus &
+		VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK) {
+		CDBG("Image composite done 1 irq occured.\n");
+		vfe40_process_output_path_irq_1(axi_ctrl);
+	}
+	/* in snapshot mode if done then send
+	snapshot done message */
+	if (axi_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_THUMB_AND_MAIN ||
+		axi_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_MAIN_AND_THUMB ||
+		axi_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_THUMB_AND_JPEG ||
+		axi_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_JPEG_AND_THUMB ||
+		axi_ctrl->share_ctrl->operation_mode ==
+			VFE_OUTPUTS_RAW) {
+		if ((axi_ctrl->share_ctrl->outpath.out0.capture_cnt == 0)
+				&& (axi_ctrl->share_ctrl->outpath.out1.
+				capture_cnt == 0)) {
+			msm_camera_io_w_mb(
+				CAMIF_COMMAND_STOP_IMMEDIATELY,
+				axi_ctrl->share_ctrl->vfebase +
+				VFE_CAMIF_COMMAND);
+			vfe40_send_isp_msg(&axi_ctrl->subdev,
+				axi_ctrl->share_ctrl->vfeFrameId,
+				MSG_ID_SNAPSHOT_DONE);
+		}
+	}
+}
+
+static int msm_axi_buf_cfg(struct v4l2_subdev *sd, void __user *arg)
+{
+	struct msm_camvfe_params *vfe_params =
+		(struct msm_camvfe_params *)arg;
+	struct msm_vfe_cfg_cmd *cmd = vfe_params->vfe_cfg;
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+	void *data = vfe_params->data;
+	int rc = 0;
+
+	if (!axi_ctrl->share_ctrl->vfebase) {
+		pr_err("%s: base address unmapped\n", __func__);
+		return -EFAULT;
+	}
+
+	switch (cmd->cmd_type) {
+	case CMD_CONFIG_PING_ADDR: {
+		int path = *((int *)cmd->value);
+		struct vfe40_output_ch *outch =
+			vfe40_get_ch(path, axi_ctrl->share_ctrl);
+		outch->ping = *((struct msm_free_buf *)data);
+	}
+		break;
+
+	case CMD_CONFIG_PONG_ADDR: {
+		int path = *((int *)cmd->value);
+		struct vfe40_output_ch *outch =
+			vfe40_get_ch(path, axi_ctrl->share_ctrl);
+		outch->pong = *((struct msm_free_buf *)data);
+	}
+		break;
+
+	case CMD_CONFIG_FREE_BUF_ADDR: {
+		int path = *((int *)cmd->value);
+		struct vfe40_output_ch *outch =
+			vfe40_get_ch(path, axi_ctrl->share_ctrl);
+		outch->free_buf = *((struct msm_free_buf *)data);
+	}
+		break;
+	default:
+		pr_err("%s Unsupported AXI Buf config %x ", __func__,
+			cmd->cmd_type);
+	}
+	return rc;
+};
+
+static struct msm_cam_clk_info vfe40_clk_info[] = {
+	{"vfe_clk_src", 266670000},
+	{"camss_vfe_vfe_clk", -1},
+	{"camss_csi_vfe_clk", -1},
+	{"top_clk", -1},
+	{"iface_clk", -1},
+	{"bus_clk", -1},
+};
+
+int msm_axi_subdev_init(struct v4l2_subdev *sd,
+			struct msm_cam_media_controller *mctl)
+{
+	int rc = 0;
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+	v4l2_set_subdev_hostdata(sd, mctl);
+	spin_lock_init(&axi_ctrl->tasklet_lock);
+	INIT_LIST_HEAD(&axi_ctrl->tasklet_q);
+	spin_lock_init(&axi_ctrl->share_ctrl->sd_notify_lock);
+
+	axi_ctrl->share_ctrl->vfebase = ioremap(axi_ctrl->vfemem->start,
+		resource_size(axi_ctrl->vfemem));
+	if (!axi_ctrl->share_ctrl->vfebase) {
+		rc = -ENOMEM;
+		pr_err("%s: vfe ioremap failed\n", __func__);
+		goto remap_failed;
+	}
+
+	if (axi_ctrl->fs_vfe == NULL) {
+		axi_ctrl->fs_vfe =
+			regulator_get(&axi_ctrl->pdev->dev, "vdd");
+		if (IS_ERR(axi_ctrl->fs_vfe)) {
+			pr_err("%s: Regulator FS_VFE get failed %ld\n",
+				__func__, PTR_ERR(axi_ctrl->fs_vfe));
+			axi_ctrl->fs_vfe = NULL;
+			goto fs_failed;
+		} else if (regulator_enable(axi_ctrl->fs_vfe)) {
+			pr_err("%s: Regulator FS_VFE enable failed\n",
+							__func__);
+			regulator_put(axi_ctrl->fs_vfe);
+			axi_ctrl->fs_vfe = NULL;
+			goto fs_failed;
+		}
+	}
+	rc = msm_cam_clk_enable(&axi_ctrl->pdev->dev, vfe40_clk_info,
+			axi_ctrl->vfe_clk, ARRAY_SIZE(vfe40_clk_info), 1);
+	if (rc < 0)
+			goto clk_enable_failed;
+
+	msm_camio_bus_scale_cfg(
+		mctl->sdata->pdata->cam_bus_scale_table, S_INIT);
+	msm_camio_bus_scale_cfg(
+		mctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+
+	axi_ctrl->share_ctrl->register_total = VFE40_REGISTER_TOTAL;
+
+	enable_irq(axi_ctrl->vfeirq->start);
+
+	return rc;
+clk_enable_failed:
+	regulator_disable(axi_ctrl->fs_vfe);
+	regulator_put(axi_ctrl->fs_vfe);
+	axi_ctrl->fs_vfe = NULL;
+fs_failed:
+	iounmap(axi_ctrl->share_ctrl->vfebase);
+	axi_ctrl->share_ctrl->vfebase = NULL;
+remap_failed:
+	disable_irq(axi_ctrl->vfeirq->start);
+	return rc;
+}
+
+void msm_axi_subdev_release(struct v4l2_subdev *sd)
+{
+	struct msm_cam_media_controller *pmctl =
+		(struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+	if (!axi_ctrl->share_ctrl->vfebase) {
+		pr_err("%s: base address unmapped\n", __func__);
+		return;
+	}
+
+	CDBG("%s, free_irq\n", __func__);
+	disable_irq(axi_ctrl->vfeirq->start);
+	tasklet_kill(&axi_ctrl->vfe40_tasklet);
+	msm_cam_clk_enable(&axi_ctrl->pdev->dev, vfe40_clk_info,
+		axi_ctrl->vfe_clk, ARRAY_SIZE(vfe40_clk_info), 0);
+
+	if (axi_ctrl->fs_vfe) {
+		regulator_disable(axi_ctrl->fs_vfe);
+		regulator_put(axi_ctrl->fs_vfe);
+		axi_ctrl->fs_vfe = NULL;
+	}
+	iounmap(axi_ctrl->share_ctrl->vfebase);
+	axi_ctrl->share_ctrl->vfebase = NULL;
+
+	if (atomic_read(&axi_ctrl->share_ctrl->irq_cnt))
+		pr_warning("%s, Warning IRQ Count not ZERO\n", __func__);
+
+	msm_camio_bus_scale_cfg(
+		pmctl->sdata->pdata->cam_bus_scale_table, S_EXIT);
+}
+
+static long msm_axi_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	int rc = -ENOIOCTLCMD;
+	switch (cmd) {
+	case VIDIOC_MSM_AXI_INIT:
+		rc = msm_axi_subdev_init(sd,
+			(struct msm_cam_media_controller *)arg);
+		break;
+	case VIDIOC_MSM_AXI_CFG:
+		rc = msm_axi_config(sd, arg);
+		break;
+	case VIDIOC_MSM_AXI_IRQ:
+		msm_axi_process_irq(sd, arg);
+		rc = 0;
+		break;
+	case VIDIOC_MSM_AXI_BUF_CFG:
+		msm_axi_buf_cfg(sd, arg);
+		rc = 0;
+		break;
+	case VIDIOC_MSM_AXI_RELEASE:
+		msm_axi_subdev_release(sd);
+		rc = 0;
+		break;
+	default:
+		pr_err("%s: command not found\n", __func__);
+	}
+	return rc;
+}
+
+static const struct v4l2_subdev_core_ops msm_axi_subdev_core_ops = {
+	.ioctl = msm_axi_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_video_ops msm_axi_subdev_video_ops = {
+	.s_crystal_freq = msm_axi_subdev_s_crystal_freq,
+};
+
+static const struct v4l2_subdev_ops msm_axi_subdev_ops = {
+	.core = &msm_axi_subdev_core_ops,
+	.video = &msm_axi_subdev_video_ops,
+};
+
+static const struct v4l2_subdev_internal_ops msm_axi_internal_ops;
+
+void vfe40_axi_probe(struct axi_ctrl_t *axi_ctrl)
+{
+	struct msm_cam_subdev_info sd_info;
+	v4l2_subdev_init(&axi_ctrl->subdev, &msm_axi_subdev_ops);
+	axi_ctrl->subdev.internal_ops = &msm_axi_internal_ops;
+	axi_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(axi_ctrl->subdev.name,
+			 sizeof(axi_ctrl->subdev.name), "axi");
+	v4l2_set_subdevdata(&axi_ctrl->subdev, axi_ctrl);
+
+	sd_info.sdev_type = AXI_DEV;
+	sd_info.sd_index = axi_ctrl->pdev->id;
+	sd_info.irq_num = 0;
+	msm_cam_register_subdev_node(&axi_ctrl->subdev, &sd_info);
+}
diff --git a/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
index e1d8b48..460eb07 100644
--- a/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
@@ -696,7 +696,6 @@
 
 		switch (id) {
 		case MSG_SNAPSHOT:
-			msm_camio_set_perf_lvl(S_PREVIEW);
 			while (vfe2x_ctrl->snap.frame_cnt <
 				vfe2x_ctrl->num_snap) {
 				vfe_7x_ops(driver_data, MSG_OUTPUT_S, len,
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
index 76e3592..76d8068 100644
--- a/drivers/media/video/msm_vidc/msm_smem.c
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -35,6 +35,8 @@
 	if (align < 4096)
 		align = 4096;
 	flags |= UNCACHED;
+	pr_debug("\n In %s  domain: %d, Partition: %d\n",
+		__func__, domain_num, partition_num);
 	rc = ion_map_iommu(clnt, hndl, domain_num, partition_num, align,
 			0, iova, buffer_size, flags, 0);
 	if (rc)
@@ -45,9 +47,9 @@
 }
 
 static void put_device_address(struct ion_client *clnt,
-		struct ion_handle *hndl, int domain_num)
+		struct ion_handle *hndl, int domain_num, int partition_num)
 {
-	ion_unmap_iommu(clnt, hndl, domain_num, 0);
+	ion_unmap_iommu(clnt, hndl, domain_num, partition_num);
 }
 
 static int ion_user_to_kernel(struct smem_client *client,
@@ -91,6 +93,8 @@
 	mem->smem_priv = hndl;
 	mem->device_addr = iova + offset;
 	mem->size = buffer_size;
+	pr_debug("Buffer device address: 0x%lx, size: %d\n",
+		mem->device_addr, mem->size);
 	return rc;
 fail_device_address:
 	ion_unmap_kernel(client->clnt, hndl);
@@ -108,12 +112,12 @@
 	unsigned long iova = 0;
 	unsigned long buffer_size = 0;
 	int rc = 0;
-	if (size == 0)
-		goto skip_mem_alloc;
 	flags = flags | ION_HEAP(ION_CP_MM_HEAP_ID);
 	if (align < 4096)
 		align = 4096;
 	size = (size + 4095) & (~4095);
+	pr_debug("\n in %s domain: %d, Partition: %d\n",
+		__func__, domain, partition);
 	hndl = ion_alloc(client->clnt, size, align, flags);
 	if (IS_ERR_OR_NULL(hndl)) {
 		pr_err("Failed to allocate shared memory = %p, %d, %d, 0x%x\n",
@@ -138,7 +142,7 @@
 		goto fail_device_address;
 	}
 	mem->device_addr = iova;
-	pr_err("device_address = 0x%lx, kvaddr = 0x%p\n",
+	pr_debug("device_address = 0x%lx, kvaddr = 0x%p\n",
 		mem->device_addr, mem->kvaddr);
 	mem->size = size;
 	return rc;
@@ -147,14 +151,13 @@
 fail_map:
 	ion_free(client->clnt, hndl);
 fail_shared_mem_alloc:
-skip_mem_alloc:
 	return rc;
 }
 
 static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
 {
 	put_device_address(client->clnt,
-		mem->smem_priv, mem->domain);
+		mem->smem_priv, mem->domain, mem->partition_num);
 	ion_unmap_kernel(client->clnt, mem->smem_priv);
 	ion_free(client->clnt, mem->smem_priv);
 }
@@ -236,12 +239,15 @@
 	struct smem_client *client;
 	int rc = 0;
 	struct msm_smem *mem;
-
 	client = clt;
 	if (!client) {
 		pr_err("Invalid  client passed\n");
 		return NULL;
 	}
+	if (!size) {
+		pr_err("No need to allocate memory of size: %d\n", size);
+		return NULL;
+	}
 	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
 	if (!mem) {
 		pr_err("Failed to allocate shared mem\n");
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index cf1ebbb..12b4c76 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -31,6 +31,7 @@
 
 #define BASE_DEVICE_NUMBER 32
 #define MAX_EVENTS 30
+#define SHARED_QSIZE 0x1000000
 
 
 static struct msm_bus_vectors ocmem_init_vectors[]  = {
@@ -505,6 +506,13 @@
 	return msm_vidc_decoder_cmd((void *)vidc_inst, dec);
 }
 
+static int msm_v4l2_encoder_cmd(struct file *file, void *fh,
+				struct v4l2_encoder_cmd *enc)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_encoder_cmd((void *)vidc_inst, enc);
+}
+
 static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
 	.vidioc_querycap = msm_v4l2_querycap,
 	.vidioc_enum_fmt_vid_cap_mplane = msm_v4l2_enum_fmt,
@@ -524,6 +532,7 @@
 	.vidioc_subscribe_event = msm_v4l2_subscribe_event,
 	.vidioc_unsubscribe_event = msm_v4l2_unsubscribe_event,
 	.vidioc_decoder_cmd = msm_v4l2_decoder_cmd,
+	.vidioc_encoder_cmd = msm_v4l2_encoder_cmd,
 };
 
 static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = {
@@ -583,7 +592,7 @@
 	struct msm_vidc_core *core)
 {
 	size_t len;
-	struct msm_iova_partition partition;
+	struct msm_iova_partition partition[2];
 	struct msm_iova_layout layout;
 	int rc = 0;
 	int i;
@@ -606,14 +615,28 @@
 			rc = -EINVAL;
 			break;
 		}
-		partition.start = io_map[i].addr_range[0];
-		partition.size = io_map[i].addr_range[1];
-		layout.partitions = &partition;
-		layout.npartitions = 1;
+		partition[0].start = io_map[i].addr_range[0];
+		if (i == NS_MAP) {
+			partition[0].size =
+				io_map[i].addr_range[1] - SHARED_QSIZE;
+			partition[1].start =
+				partition[0].start + io_map[i].addr_range[1]
+					- SHARED_QSIZE;
+			partition[1].size = SHARED_QSIZE;
+			layout.npartitions = 2;
+		} else {
+			partition[0].size = io_map[i].addr_range[1];
+			layout.npartitions = 1;
+		}
+		layout.partitions = &partition[0];
 		layout.client_name = io_map[i].name;
 		layout.domain_flags = 0;
-		pr_debug("Registering domain with: %lx, %lx, %s\n",
-			partition.start, partition.size, layout.client_name);
+		pr_debug("Registering domain 1 with: %lx, %lx, %s\n",
+			partition[0].start, partition[0].size,
+			layout.client_name);
+		pr_debug("Registering domain 2 with: %lx, %lx, %s\n",
+			partition[1].start, partition[1].size,
+			layout.client_name);
 		io_map[i].domain = msm_register_domain(&layout);
 		if (io_map[i].domain < 0) {
 			pr_err("Failed to register cp domain\n");
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index d2b1acd..a838a12 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -440,14 +440,16 @@
 	if (fmt) {
 		f->fmt.pix_mp.pixelformat = fmt->fourcc;
 		if (inst->in_reconfig == true) {
-			inst->height = inst->reconfig_height;
-			inst->width = inst->reconfig_width;
+			inst->prop.height = inst->reconfig_height;
+			inst->prop.width = inst->reconfig_width;
 		}
-		f->fmt.pix_mp.height = inst->height;
-		f->fmt.pix_mp.width = inst->width;
+		f->fmt.pix_mp.height = inst->prop.height;
+		f->fmt.pix_mp.width = inst->prop.width;
+		f->fmt.pix_mp.num_planes = fmt->num_planes;
 		for (i = 0; i < fmt->num_planes; ++i) {
 			f->fmt.pix_mp.plane_fmt[i].sizeimage =
-			fmt->get_frame_size(i, inst->height, inst->width);
+			fmt->get_frame_size(i, inst->prop.height,
+				inst->prop.width);
 		}
 	} else {
 		pr_err("Buf type not recognized, type = %d\n",
@@ -491,6 +493,7 @@
 	}
 
 	if (fmt) {
+		f->fmt.pix_mp.num_planes = fmt->num_planes;
 		for (i = 0; i < fmt->num_planes; ++i) {
 			f->fmt.pix_mp.plane_fmt[i].sizeimage =
 				fmt->get_frame_size(i, f->fmt.pix_mp.height,
@@ -582,7 +585,7 @@
 			*num_buffers = MIN_NUM_OUTPUT_BUFFERS;
 		for (i = 0; i < *num_planes; i++) {
 			sizes[i] = inst->fmts[OUTPUT_PORT]->get_frame_size(
-					i, inst->height, inst->width);
+					i, inst->prop.height, inst->prop.width);
 		}
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
@@ -645,6 +648,11 @@
 		pr_err("Failed to set scratch buffers: %d\n", rc);
 		goto fail_start;
 	}
+	rc = msm_comm_set_persist_buffers(inst);
+	if (rc) {
+		pr_err("Failed to set persist buffers: %d\n", rc);
+		goto fail_start;
+	}
 	rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
 	if (rc) {
 		pr_err("Failed to move inst: %p to start done state\n",
@@ -714,11 +722,13 @@
 	switch (q->type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		if (!inst->vb2_bufq[CAPTURE_PORT].streaming)
-			rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+			rc = msm_comm_try_state(inst,
+				MSM_VIDC_RELEASE_RESOURCES_DONE);
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		if (!inst->vb2_bufq[OUTPUT_PORT].streaming)
-			rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+			rc = msm_comm_try_state(inst,
+				MSM_VIDC_RELEASE_RESOURCES_DONE);
 		break;
 	default:
 		pr_err("Q-type is not supported: %d\n", q->type);
@@ -727,7 +737,7 @@
 	}
 	if (rc)
 		pr_err("Failed to move inst: %p, cap = %d to state: %d\n",
-				inst, q->type, MSM_VIDC_CLOSE_DONE);
+				inst, q->type, MSM_VIDC_RELEASE_RESOURCES_DONE);
 	return rc;
 }
 
@@ -739,6 +749,74 @@
 		pr_err("Failed to queue buffer: %d\n", rc);
 }
 
+int msm_vdec_cmd(struct msm_vidc_inst *inst, struct v4l2_decoder_cmd *dec)
+{
+	int rc = 0;
+	bool ip_flush = false,
+	     op_flush = false;
+
+	switch (dec->cmd) {
+	case V4L2_DEC_QCOM_CMD_FLUSH:
+		mutex_lock(&inst->sync_lock);
+		ip_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT;
+		op_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE;
+		/* Only support flush on decoder (for now)*/
+		if (inst->session_type == MSM_VIDC_ENCODER) {
+			pr_err("Buffer flushing not supported for encoder\n");
+			rc = -ENOTSUPP;
+			mutex_unlock(&inst->sync_lock);
+			break;
+		}
+
+		/* Certain types of flushes aren't supported such as: */
+		/* 1) Input only flush */
+		if (ip_flush && !op_flush) {
+			pr_err("Input only flush not supported\n");
+			rc = -ENOTSUPP;
+			mutex_unlock(&inst->sync_lock);
+			break;
+		}
+
+		/* 2) Output only flush when in reconfig */
+		if (!ip_flush && op_flush && !inst->in_reconfig) {
+			pr_err("Output only flush only supported when reconfiguring\n");
+			rc = -ENOTSUPP;
+			mutex_unlock(&inst->sync_lock);
+			break;
+		}
+
+		/* Finally flush */
+		if (op_flush && ip_flush)
+			rc = vidc_hal_session_flush(inst->session,
+					HAL_FLUSH_ALL);
+		else if (ip_flush)
+			rc = vidc_hal_session_flush(inst->session,
+					HAL_FLUSH_INPUT);
+		else if (op_flush)
+			rc = vidc_hal_session_flush(inst->session,
+					HAL_FLUSH_OUTPUT);
+		mutex_unlock(&inst->sync_lock);
+		break;
+	case V4L2_DEC_CMD_STOP:
+		rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+		if (rc)
+			pr_err("Failed to close instance\n");
+		break;
+	default:
+		pr_err("Unknown Decoder Command\n");
+		rc = -ENOTSUPP;
+		goto exit;
+	}
+
+	if (rc) {
+		pr_err("Failed to exec decoder cmd %d\n", dec->cmd);
+		goto exit;
+	}
+exit:
+	return rc;
+}
+
+
 static const struct vb2_ops msm_vdec_vb2q_ops = {
 	.queue_setup = msm_vdec_queue_setup,
 	.start_streaming = msm_vdec_start_streaming,
diff --git a/drivers/media/video/msm_vidc/msm_vdec.h b/drivers/media/video/msm_vidc/msm_vdec.h
index 1242fb4..b8326d8 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.h
+++ b/drivers/media/video/msm_vidc/msm_vdec.h
@@ -31,6 +31,7 @@
 int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
 int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
 int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_vdec_cmd(struct msm_vidc_inst *inst, struct v4l2_decoder_cmd *dec);
 struct vb2_ops *msm_vdec_get_vb2q_ops(void);
 
 #endif
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index fbd3378..2e51daa 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -22,13 +22,13 @@
 #define DEFAULT_WIDTH 1280
 #define MIN_NUM_OUTPUT_BUFFERS 2
 #define MAX_NUM_OUTPUT_BUFFERS 8
-#define MIN_BIT_RATE 64
-#define MAX_BIT_RATE 160000
-#define DEFAULT_BIT_RATE 64
-#define BIT_RATE_STEP 1
-#define MIN_FRAME_RATE 1
-#define MAX_FRAME_RATE 240
-#define DEFAULT_FRAME_RATE 30
+#define MIN_BIT_RATE 64000
+#define MAX_BIT_RATE 160000000
+#define DEFAULT_BIT_RATE 64000
+#define BIT_RATE_STEP 100
+#define MIN_FRAME_RATE 65536
+#define MAX_FRAME_RATE 15728640
+#define DEFAULT_FRAME_RATE 1966080
 #define DEFAULT_IR_MBS 30
 #define MAX_SLICE_BYTE_SIZE 1024
 #define MIN_SLICE_BYTE_SIZE 1024
@@ -621,11 +621,21 @@
 	unsigned long flags;
 	struct vb2_buf_entry *temp;
 	struct list_head *ptr, *next;
+	rc = msm_comm_try_get_bufreqs(inst);
+	if (rc) {
+		pr_err("Failed to get Buffer Requirements : %d\n", rc);
+		goto fail_start;
+	}
 	rc = msm_comm_set_scratch_buffers(inst);
 	if (rc) {
 		pr_err("Failed to set scratch buffers: %d\n", rc);
 		goto fail_start;
 	}
+	rc = msm_comm_set_persist_buffers(inst);
+	if (rc) {
+		pr_err("Failed to set persist buffers: %d\n", rc);
+		goto fail_start;
+	}
 	rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
 	if (rc) {
 		pr_err("Failed to move inst: %p to start done state\n",
@@ -696,7 +706,7 @@
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-		rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+		rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
 		break;
 	default:
 		pr_err("Q-type is not supported: %d\n", q->type);
@@ -752,7 +762,12 @@
 	void *pdata;
 	struct msm_vidc_inst *inst = container_of(ctrl->handler,
 					struct msm_vidc_inst, ctrl_handler);
-
+	rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+	if (rc) {
+		pr_err("Failed to move inst: %p to start done state\n",
+				inst);
+		goto failed_open_done;
+	}
 	control.id = ctrl->id;
 	control.value = ctrl->val;
 
@@ -1172,6 +1187,7 @@
 	}
 	if (rc)
 		pr_err("Failed to set hal property for framesize\n");
+failed_open_done:
 	return rc;
 }
 static int msm_venc_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
@@ -1201,7 +1217,7 @@
 	inst->fmts[OUTPUT_PORT] = &venc_formats[0];
 	inst->prop.height = DEFAULT_HEIGHT;
 	inst->prop.width = DEFAULT_WIDTH;
-	inst->prop.height = 30;
+	inst->prop.fps = 30;
 	return rc;
 }
 
@@ -1214,6 +1230,15 @@
 	return v4l2_g_ctrl(&inst->ctrl_handler, ctrl);
 }
 
+int msm_venc_cmd(struct msm_vidc_inst *inst, struct v4l2_encoder_cmd *enc)
+{
+	int rc = 0;
+	rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+	if (rc)
+		pr_err("Failed to close instance\n");
+	return rc;
+}
+
 int msm_venc_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
 {
 	if (!inst || !cap) {
@@ -1294,6 +1319,7 @@
 	}
 
 	if (fmt) {
+		f->fmt.pix_mp.num_planes = fmt->num_planes;
 		for (i = 0; i < fmt->num_planes; ++i) {
 			f->fmt.pix_mp.plane_fmt[i].sizeimage =
 				fmt->get_frame_size(i, f->fmt.pix_mp.height,
@@ -1334,6 +1360,7 @@
 		f->fmt.pix_mp.pixelformat = fmt->fourcc;
 		f->fmt.pix_mp.height = inst->prop.height;
 		f->fmt.pix_mp.width = inst->prop.width;
+		f->fmt.pix_mp.num_planes = fmt->num_planes;
 		for (i = 0; i < fmt->num_planes; ++i) {
 			f->fmt.pix_mp.plane_fmt[i].sizeimage =
 			fmt->get_frame_size(i, inst->prop.height,
diff --git a/drivers/media/video/msm_vidc/msm_venc.h b/drivers/media/video/msm_vidc/msm_venc.h
index 4a156dd..83610b3 100644
--- a/drivers/media/video/msm_vidc/msm_venc.h
+++ b/drivers/media/video/msm_vidc/msm_venc.h
@@ -30,6 +30,7 @@
 int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
 int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
 int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_venc_cmd(struct msm_vidc_inst *inst, struct v4l2_encoder_cmd *enc);
 struct vb2_ops *msm_venc_get_vb2q_ops(void);
 
 #endif
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index 4d4cec5..7c9b6db 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -29,11 +29,6 @@
 	struct vb2_buffer *out_vb = NULL;
 	struct vb2_buffer *cap_vb = NULL;
 	unsigned long flags;
-	if (!outq->streaming && !capq->streaming) {
-		pr_err("Returning POLLERR from here: %d, %d\n",
-			outq->streaming, capq->streaming);
-		return POLLERR;
-	}
 	poll_wait(filp, &inst->event_handler.wait, wait);
 	poll_wait(filp, &capq->done_wq, wait);
 	poll_wait(filp, &outq->done_wq, wait);
@@ -140,6 +135,22 @@
 	return -EINVAL;
 }
 
+int msm_vidc_encoder_cmd(void *instance, struct v4l2_encoder_cmd *enc)
+{
+	struct msm_vidc_inst *inst = instance;
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_cmd(instance, enc);
+	return -EINVAL;
+}
+
+int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec)
+{
+	struct msm_vidc_inst *inst = instance;
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_cmd(instance, dec);
+	return -EINVAL;
+}
+
 int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
 {
 	struct msm_vidc_inst *inst = instance;
@@ -243,6 +254,7 @@
 	inst->session_type = session_type;
 	INIT_LIST_HEAD(&inst->pendingq);
 	INIT_LIST_HEAD(&inst->internalbufs);
+	INIT_LIST_HEAD(&inst->persistbufs);
 	inst->state = MSM_VIDC_CORE_UNINIT_DONE;
 	inst->core = core;
 	for (i = SESSION_MSG_INDEX(SESSION_MSG_START);
@@ -316,6 +328,15 @@
 				kfree(buf);
 			}
 		}
+		if (!list_empty(&inst->persistbufs)) {
+			list_for_each_safe(ptr, next, &inst->persistbufs) {
+				buf = list_entry(ptr, struct internal_buf,
+						list);
+				list_del(&buf->list);
+				msm_smem_free(inst->mem_client, buf->handle);
+				kfree(buf);
+			}
+		}
 		if (inst->extradata_handle)
 			msm_smem_free(inst->mem_client, inst->extradata_handle);
 		spin_unlock_irqrestore(&inst->lock, flags);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 6835467..50f98da 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -22,7 +22,7 @@
 #include "vidc_hal_api.h"
 #include "msm_smem.h"
 
-#define HW_RESPONSE_TIMEOUT 5000
+#define HW_RESPONSE_TIMEOUT (5 * 60 * 1000)
 
 #define IS_ALREADY_IN_STATE(__p, __d) ({\
 	int __rc = (__p >= __d);\
@@ -1126,7 +1126,7 @@
 		pr_err("inst: %p is already in state: %d\n", inst, inst->state);
 		goto exit;
 	}
-	ocmem_sz = get_ocmem_requirement(inst->height, inst->width);
+	ocmem_sz = get_ocmem_requirement(inst->prop.height, inst->prop.width);
 	rc = msm_comm_alloc_ocmem(inst->core, ocmem_sz);
 	if (rc)
 		pr_warn("Failed to allocate OCMEM. Performance will be impacted\n");
@@ -1421,67 +1421,6 @@
 	return rc;
 }
 
-int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec)
-{
-	int rc = 0;
-	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
-	bool ip_flush = false,
-	     op_flush = false;
-
-	mutex_lock(&inst->sync_lock);
-
-	switch (dec->cmd) {
-	case V4L2_DEC_QCOM_CMD_FLUSH:
-		ip_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT;
-		op_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE;
-		/* Only support flush on decoder (for now)*/
-		if (inst->session_type == MSM_VIDC_ENCODER) {
-			pr_err("Buffer flushing not supported for encoder\n");
-			rc = -ENOTSUPP;
-			break;
-		}
-
-		/* Certain types of flushes aren't supported such as: */
-		/* 1) Input only flush */
-		if (ip_flush && !op_flush) {
-			pr_err("Input only flush not supported\n");
-			rc = -ENOTSUPP;
-			break;
-		}
-
-		/* 2) Output only flush when in reconfig */
-		if (!ip_flush && op_flush && !inst->in_reconfig) {
-			pr_err("Output only flush only supported when reconfiguring\n");
-			rc = -ENOTSUPP;
-			break;
-		}
-
-		/* Finally flush */
-		if (op_flush && ip_flush)
-			rc = vidc_hal_session_flush(inst->session,
-					HAL_FLUSH_ALL);
-		else if (ip_flush)
-			rc = vidc_hal_session_flush(inst->session,
-					HAL_FLUSH_INPUT);
-		else if (op_flush)
-			rc = vidc_hal_session_flush(inst->session,
-					HAL_FLUSH_OUTPUT);
-
-		break;
-	default:
-		rc = -ENOTSUPP;
-		goto exit;
-	}
-
-	if (rc) {
-		pr_err("Failed to exec decoder cmd %d\n", dec->cmd);
-		goto exit;
-	}
-exit:
-	mutex_unlock(&inst->sync_lock);
-	return rc;
-}
-
 int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
 {
 	int rc = 0;
@@ -1490,10 +1429,13 @@
 	struct list_head *ptr, *next;
 	struct vidc_buffer_addr_info buffer_info;
 	unsigned long flags;
+	struct hal_buffer_requirements *scratch_buf =
+		&inst->buff_req.buffer[HAL_BUFFER_INTERNAL_SCRATCH];
 	int i;
+
 	pr_debug("scratch: num = %d, size = %d\n",
-			inst->buff_req.buffer[6].buffer_count_actual,
-			inst->buff_req.buffer[6].buffer_size);
+			scratch_buf->buffer_count_actual,
+			scratch_buf->buffer_size);
 	spin_lock_irqsave(&inst->lock, flags);
 	if (!list_empty(&inst->internalbufs)) {
 		list_for_each_safe(ptr, next, &inst->internalbufs) {
@@ -1505,40 +1447,103 @@
 		}
 	}
 	spin_unlock_irqrestore(&inst->lock, flags);
-
-
-	for (i = 0; i < inst->buff_req.buffer[6].buffer_count_actual;
+	if (scratch_buf->buffer_size) {
+		for (i = 0; i < scratch_buf->buffer_count_actual;
 				i++) {
-		handle = msm_smem_alloc(inst->mem_client,
-				inst->buff_req.buffer[6].buffer_size, 1, 0,
+			handle = msm_smem_alloc(inst->mem_client,
+				scratch_buf->buffer_size, 1, 0,
 				inst->core->resources.io_map[NS_MAP].domain, 0);
-		if (!handle) {
-			pr_err("Failed to allocate scratch memory\n");
-			rc = -ENOMEM;
-			goto err_no_mem;
-		}
-		binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
-		if (!binfo) {
-			pr_err("Out of memory\n");
-			rc = -ENOMEM;
-			goto err_no_mem;
-		}
-		binfo->handle = handle;
-		spin_lock_irqsave(&inst->lock, flags);
-		list_add_tail(&binfo->list, &inst->internalbufs);
-		spin_unlock_irqrestore(&inst->lock, flags);
-		buffer_info.buffer_size =
-				inst->buff_req.buffer[6].buffer_size;
-		buffer_info.buffer_type = HAL_BUFFER_INTERNAL_SCRATCH;
-		buffer_info.num_buffers = 1;
-		buffer_info.align_device_addr = handle->device_addr;
-		rc = vidc_hal_session_set_buffers((void *) inst->session,
-				&buffer_info);
-		if (rc) {
-			pr_err("vidc_hal_session_set_buffers failed");
-			break;
+			if (!handle) {
+				pr_err("Failed to allocate scratch memory\n");
+				rc = -ENOMEM;
+				goto err_no_mem;
+			}
+			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+			if (!binfo) {
+				pr_err("Out of memory\n");
+				rc = -ENOMEM;
+				goto fail_kzalloc;
+			}
+			binfo->handle = handle;
+			buffer_info.buffer_size = scratch_buf->buffer_size;
+			buffer_info.buffer_type = HAL_BUFFER_INTERNAL_SCRATCH;
+			buffer_info.num_buffers = 1;
+			buffer_info.align_device_addr = handle->device_addr;
+			rc = vidc_hal_session_set_buffers(
+					(void *) inst->session,	&buffer_info);
+			if (rc) {
+				pr_err("vidc_hal_session_set_buffers failed");
+				goto fail_set_buffers;
+			}
+			spin_lock_irqsave(&inst->lock, flags);
+			list_add_tail(&binfo->list, &inst->internalbufs);
+			spin_unlock_irqrestore(&inst->lock, flags);
 		}
 	}
+	return rc;
+fail_set_buffers:
+	kfree(binfo);
+fail_kzalloc:
+	msm_smem_free(inst->mem_client, handle);
+err_no_mem:
+	return rc;
+}
+
+int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct msm_smem *handle;
+	struct internal_buf *binfo;
+	struct vidc_buffer_addr_info buffer_info;
+	unsigned long flags;
+	struct hal_buffer_requirements *persist_buf =
+		&inst->buff_req.buffer[HAL_BUFFER_INTERNAL_PERSIST];
+	int i;
+	pr_debug("persist: num = %d, size = %d\n",
+		persist_buf->buffer_count_actual,
+		persist_buf->buffer_size);
+	if (!list_empty(&inst->persistbufs)) {
+		pr_err("Persist buffers already allocated\n");
+		return rc;
+	}
+
+	if (persist_buf->buffer_size) {
+		for (i = 0;	i <	persist_buf->buffer_count_actual; i++) {
+			handle = msm_smem_alloc(inst->mem_client,
+				persist_buf->buffer_size, 1, 0,
+				inst->core->resources.io_map[NS_MAP].domain, 0);
+			if (!handle) {
+				pr_err("Failed to allocate persist memory\n");
+				rc = -ENOMEM;
+				goto err_no_mem;
+			}
+			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+			if (!binfo) {
+				pr_err("Out of memory\n");
+				rc = -ENOMEM;
+				goto fail_kzalloc;
+			}
+			binfo->handle = handle;
+			buffer_info.buffer_size = persist_buf->buffer_size;
+			buffer_info.buffer_type = HAL_BUFFER_INTERNAL_PERSIST;
+			buffer_info.num_buffers = 1;
+			buffer_info.align_device_addr = handle->device_addr;
+			rc = vidc_hal_session_set_buffers(
+				(void *) inst->session, &buffer_info);
+			if (rc) {
+				pr_err("vidc_hal_session_set_buffers failed");
+				goto fail_set_buffers;
+			}
+			spin_lock_irqsave(&inst->lock, flags);
+			list_add_tail(&binfo->list, &inst->persistbufs);
+			spin_unlock_irqrestore(&inst->lock, flags);
+		}
+	}
+	return rc;
+fail_set_buffers:
+	kfree(binfo);
+fail_kzalloc:
+	msm_smem_free(inst->mem_client, handle);
 err_no_mem:
 	return rc;
 }
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
index 2009ca6..9430d5f 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -28,6 +28,7 @@
 int msm_comm_try_state(struct msm_vidc_inst *inst, int state);
 int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst);
 int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
+int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
 int msm_comm_qbuf(struct vb2_buffer *vb);
 int msm_comm_scale_clocks(struct msm_vidc_core *core);
 #define IS_PRIV_CTRL(idx) (\
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index 992f39c..630f383 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -201,14 +201,13 @@
 	int session_type;
 	void *session;
 	struct session_prop prop;
-	u32 width;
-	u32 height;
 	int state;
 	const struct msm_vidc_format *fmts[MAX_PORT_NUM];
 	struct vb2_queue vb2_bufq[MAX_PORT_NUM];
 	spinlock_t lock;
 	struct list_head pendingq;
 	struct list_head internalbufs;
+	struct list_head persistbufs;
 	struct buffer_requirements buff_req;
 	void *mem_client;
 	struct v4l2_ctrl_handler ctrl_handler;
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index 16a3ecd..cf540d8 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -316,7 +316,7 @@
 	vmem = (struct vidc_mem_addr *)mem;
 	HAL_MSG_HIGH("start to alloc: size:%d, Flags: %d", size, flags);
 
-	alloc  = msm_smem_alloc(clnt, size, align, flags, domain, 0);
+	alloc  = msm_smem_alloc(clnt, size, align, flags, domain, 1);
 	HAL_MSG_LOW("Alloc done");
 	if (!alloc) {
 		HAL_MSG_HIGH("Alloc fail in %s", __func__);
@@ -1201,9 +1201,11 @@
 	}
 	case HAL_PARAM_VENC_RATE_CONTROL:
 	{
+		u32 *rc_mode;
 		pkt->rg_property_data[0] =
 			HFI_PROPERTY_PARAM_VENC_RATE_CONTROL;
-		switch ((enum hal_rate_control)pdata) {
+		rc_mode = (u32 *)pdata;
+		switch ((enum hal_rate_control) *rc_mode) {
 		case HAL_RATE_CONTROL_OFF:
 		pkt->rg_property_data[1] = HFI_RATE_CONTROL_OFF;
 			break;
diff --git a/drivers/media/video/msm/wfd/Makefile b/drivers/media/video/msm_wfd/Makefile
similarity index 100%
rename from drivers/media/video/msm/wfd/Makefile
rename to drivers/media/video/msm_wfd/Makefile
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm_wfd/enc-subdev.c
similarity index 100%
rename from drivers/media/video/msm/wfd/enc-subdev.c
rename to drivers/media/video/msm_wfd/enc-subdev.c
diff --git a/drivers/media/video/msm/wfd/enc-subdev.h b/drivers/media/video/msm_wfd/enc-subdev.h
similarity index 100%
rename from drivers/media/video/msm/wfd/enc-subdev.h
rename to drivers/media/video/msm_wfd/enc-subdev.h
diff --git a/drivers/media/video/msm/wfd/mdp-subdev.c b/drivers/media/video/msm_wfd/mdp-subdev.c
similarity index 100%
rename from drivers/media/video/msm/wfd/mdp-subdev.c
rename to drivers/media/video/msm_wfd/mdp-subdev.c
diff --git a/drivers/media/video/msm/wfd/mdp-subdev.h b/drivers/media/video/msm_wfd/mdp-subdev.h
similarity index 100%
rename from drivers/media/video/msm/wfd/mdp-subdev.h
rename to drivers/media/video/msm_wfd/mdp-subdev.h
diff --git a/drivers/media/video/msm/wfd/vsg-subdev.c b/drivers/media/video/msm_wfd/vsg-subdev.c
similarity index 100%
rename from drivers/media/video/msm/wfd/vsg-subdev.c
rename to drivers/media/video/msm_wfd/vsg-subdev.c
diff --git a/drivers/media/video/msm/wfd/vsg-subdev.h b/drivers/media/video/msm_wfd/vsg-subdev.h
similarity index 100%
rename from drivers/media/video/msm/wfd/vsg-subdev.h
rename to drivers/media/video/msm_wfd/vsg-subdev.h
diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm_wfd/wfd-ioctl.c
similarity index 100%
rename from drivers/media/video/msm/wfd/wfd-ioctl.c
rename to drivers/media/video/msm_wfd/wfd-ioctl.c
diff --git a/drivers/media/video/msm/wfd/wfd-util.c b/drivers/media/video/msm_wfd/wfd-util.c
similarity index 100%
rename from drivers/media/video/msm/wfd/wfd-util.c
rename to drivers/media/video/msm_wfd/wfd-util.c
diff --git a/drivers/media/video/msm/wfd/wfd-util.h b/drivers/media/video/msm_wfd/wfd-util.h
similarity index 100%
rename from drivers/media/video/msm/wfd/wfd-util.h
rename to drivers/media/video/msm_wfd/wfd-util.h
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index f1f1c69..9f2ead4 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -273,10 +273,10 @@
 
 #ifdef TOP_FIELD_FIX
 	writel_iowmb(0x00000000 | vp_act->top_field << 0, VCAP_VP_CTRL);
-	writel_iowmb(0x00030000 | vp_act->top_field << 0, VCAP_VP_CTRL);
+	writel_iowmb(0x00010000 | vp_act->top_field << 0, VCAP_VP_CTRL);
 #else
 	writel_iowmb(0x00000000 | top_field, VCAP_VP_CTRL);
-	writel_iowmb(0x00030000 | top_field, VCAP_VP_CTRL);
+	writel_iowmb(0x00010000 | top_field, VCAP_VP_CTRL);
 #endif
 	enable_irq(dev->vpirq->start);
 	writel_iowmb(irq, VCAP_VP_INT_CLEAR);
@@ -420,58 +420,84 @@
 
 int init_motion_buf(struct vcap_client_data *c_data)
 {
+	int rc;
 	struct vcap_dev *dev = c_data->dev;
-	void *buf;
-	unsigned long motion_base_addr;
-	uint32_t size = ((c_data->vp_out_fmt.width + 63) >> 6) *
+	struct ion_handle *handle = NULL;
+	unsigned long paddr, ionflag = 0;
+	void *vaddr;
+	size_t len;
+	size_t size = ((c_data->vp_out_fmt.width + 63) >> 6) *
 		((c_data->vp_out_fmt.height + 7) >> 3) * 16;
 
-	if (c_data->vid_vp_action.bufMotion) {
+	if (c_data->vid_vp_action.motionHandle) {
 		pr_err("Motion buffer has already been created");
 		return -ENOEXEC;
 	}
 
-	buf = kzalloc(size, GFP_KERNEL);
-	if (!buf)
+	handle = ion_alloc(dev->ion_client, size, SZ_4K,
+			ION_HEAP(ION_CP_MM_HEAP_ID));
+	if (IS_ERR_OR_NULL(handle)) {
+		pr_err("%s: ion_alloc failed\n", __func__);
 		return -ENOMEM;
+	}
+	rc = ion_phys(dev->ion_client, handle, &paddr, &len);
+	if (rc < 0) {
+		pr_err("%s: ion_phys failed\n", __func__);
+		ion_free(dev->ion_client, handle);
+		return rc;
+	}
 
-	c_data->vid_vp_action.bufMotion = buf;
-	motion_base_addr = virt_to_phys(buf);
-	writel_iowmb(motion_base_addr, VCAP_VP_MOTION_EST_ADDR);
+	rc = ion_handle_get_flags(dev->ion_client, handle, &ionflag);
+	if (rc) {
+		pr_err("%s: get flags ion handle failed\n", __func__);
+		ion_free(dev->ion_client, handle);
+		return rc;
+	}
+
+	vaddr = ion_map_kernel(dev->ion_client, handle, ionflag);
+	if (IS_ERR(vaddr)) {
+		pr_err("%s: Map motion buffer failed\n", __func__);
+		ion_free(dev->ion_client, handle);
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	memset(vaddr, 0, size);
+	c_data->vid_vp_action.motionHandle = handle;
+
+	vaddr = NULL;
+	ion_unmap_kernel(dev->ion_client, handle);
+
+	writel_iowmb(paddr, VCAP_VP_MOTION_EST_ADDR);
 	return 0;
 }
 
 void deinit_motion_buf(struct vcap_client_data *c_data)
 {
 	struct vcap_dev *dev = c_data->dev;
-	void *buf;
-
-	if (!c_data->vid_vp_action.bufMotion) {
+	if (!c_data->vid_vp_action.motionHandle) {
 		pr_err("Motion buffer has not been created");
 		return;
 	}
 
-	buf = c_data->vid_vp_action.bufMotion;
-
 	writel_iowmb(0x00000000, VCAP_VP_MOTION_EST_ADDR);
-	c_data->vid_vp_action.bufMotion = NULL;
-	kfree(buf);
+	ion_free(dev->ion_client, c_data->vid_vp_action.motionHandle);
+	c_data->vid_vp_action.motionHandle = NULL;
 	return;
 }
 
 int init_nr_buf(struct vcap_client_data *c_data)
 {
 	struct vcap_dev *dev = c_data->dev;
-	struct nr_buffer *buf;
-	uint32_t frame_size, tot_size, rc;
+	struct ion_handle *handle = NULL;
+	size_t frame_size, tot_size, len;
+	unsigned long paddr;
+	int rc;
 
-	if (c_data->vid_vp_action.bufNR.vaddr) {
+	if (c_data->vid_vp_action.bufNR.nr_handle) {
 		pr_err("NR buffer has already been created");
 		return -ENOEXEC;
 	}
-	buf = &c_data->vid_vp_action.bufNR;
-	if (!buf)
-		return -ENOMEM;
 
 	frame_size = c_data->vp_in_fmt.width * c_data->vp_in_fmt.height;
 	if (c_data->vp_in_fmt.pixfmt == V4L2_PIX_FMT_NV16)
@@ -479,19 +505,30 @@
 	else
 		tot_size = frame_size / 2 * 3;
 
-	buf->vaddr = kzalloc(tot_size, GFP_KERNEL);
-	if (!buf->vaddr)
+	handle = ion_alloc(dev->ion_client, tot_size, SZ_4K,
+			ION_HEAP(ION_CP_MM_HEAP_ID));
+	if (IS_ERR_OR_NULL(handle)) {
+		pr_err("%s: ion_alloc failed\n", __func__);
 		return -ENOMEM;
+	}
 
+	rc = ion_phys(dev->ion_client, handle, &paddr, &len);
+	if (rc < 0) {
+		pr_err("%s: ion_phys failed\n", __func__);
+		ion_free(dev->ion_client, handle);
+		return rc;
+	}
+
+	c_data->vid_vp_action.bufNR.nr_handle = handle;
 	update_nr_value(c_data);
 
-	buf->paddr = virt_to_phys(buf->vaddr);
+	c_data->vid_vp_action.bufNR.paddr = paddr;
 	rc = readl_relaxed(VCAP_VP_NR_CONFIG2);
-	rc |= 0x02D00001;
+	rc |= (((c_data->vp_out_fmt.width / 16) << 20) | 0x1);
 	writel_relaxed(rc, VCAP_VP_NR_CONFIG2);
-	writel_relaxed(buf->paddr, VCAP_VP_NR_T2_Y_BASE_ADDR);
-	writel_relaxed(buf->paddr + frame_size, VCAP_VP_NR_T2_C_BASE_ADDR);
-	buf->nr_pos = NRT2_BUF;
+	writel_relaxed(paddr, VCAP_VP_NR_T2_Y_BASE_ADDR);
+	writel_relaxed(paddr + frame_size, VCAP_VP_NR_T2_C_BASE_ADDR);
+	c_data->vid_vp_action.bufNR.nr_pos = NRT2_BUF;
 	return 0;
 }
 
@@ -501,20 +538,19 @@
 	struct nr_buffer *buf;
 	uint32_t rc;
 
-	if (!c_data->vid_vp_action.bufNR.vaddr) {
+	if (!c_data->vid_vp_action.bufNR.nr_handle) {
 		pr_err("NR buffer has not been created");
 		return;
 	}
-
 	buf = &c_data->vid_vp_action.bufNR;
 
 	rc = readl_relaxed(VCAP_VP_NR_CONFIG2);
-	rc &= !(0x02D00001);
+	rc &= !(0x0FF00001);
 	writel_relaxed(rc, VCAP_VP_NR_CONFIG2);
 
-	kfree(buf->vaddr);
+	ion_free(dev->ion_client, buf->nr_handle);
+	buf->nr_handle = NULL;
 	buf->paddr = 0;
-	buf->vaddr = NULL;
 	return;
 }
 
@@ -592,18 +628,26 @@
 {
 	struct vcap_dev *dev = c_data->dev;
 	unsigned int width, height;
+	struct ion_handle *handle = NULL;
 	unsigned long paddr;
-	void *temp;
+	size_t len;
 	uint32_t reg;
 	int rc = 0;
 
 	dprintk(2, "%s: Start VP dummy event\n", __func__);
-	temp = kzalloc(0x1200, GFP_KERNEL);
-	if (!temp) {
-		pr_err("%s: Failed to alloc mem", __func__);
+	handle = ion_alloc(dev->ion_client, 0x1200, SZ_4K,
+			ION_HEAP(ION_CP_MM_HEAP_ID));
+	if (IS_ERR_OR_NULL(handle)) {
+		pr_err("%s: ion_alloc failed\n", __func__);
 		return -ENOMEM;
 	}
-	paddr = virt_to_phys(temp);
+
+	rc = ion_phys(dev->ion_client, handle, &paddr, &len);
+	if (rc < 0) {
+		pr_err("%s: ion_phys failed\n", __func__);
+		ion_free(dev->ion_client, handle);
+		return rc;
+	}
 
 	width = c_data->vp_out_fmt.width;
 	height = c_data->vp_out_fmt.height;
@@ -626,7 +670,7 @@
 
 	writel_relaxed(0x01100101, VCAP_VP_INTERRUPT_ENABLE);
 	writel_iowmb(0x00000000, VCAP_VP_CTRL);
-	writel_iowmb(0x00030000, VCAP_VP_CTRL);
+	writel_iowmb(0x00010000, VCAP_VP_CTRL);
 
 	enable_irq(dev->vpirq->start);
 	rc = wait_event_interruptible_timeout(dev->vp_dummy_waitq,
@@ -650,7 +694,7 @@
 
 	c_data->vp_out_fmt.width = width;
 	c_data->vp_out_fmt.height = height;
-	kfree(temp);
+	ion_free(dev->ion_client, handle);
 
 	dprintk(2, "%s: Exit VP dummy event\n", __func__);
 	return rc;
@@ -748,10 +792,10 @@
 	writel_relaxed(0x01100101, VCAP_VP_INTERRUPT_ENABLE);
 #ifdef TOP_FIELD_FIX
 	writel_iowmb(0x00000000 | vp_act->top_field << 0, VCAP_VP_CTRL);
-	writel_iowmb(0x00030000 | vp_act->top_field << 0, VCAP_VP_CTRL);
+	writel_iowmb(0x00010000 | vp_act->top_field << 0, VCAP_VP_CTRL);
 #else
 	writel_iowmb(0x00000000 | top_field, VCAP_VP_CTRL);
-	writel_iowmb(0x00030000 | top_field, VCAP_VP_CTRL);
+	writel_iowmb(0x00010000 | top_field, VCAP_VP_CTRL);
 #endif
 	atomic_set(&c_data->dev->vp_enabled, 1);
 	enable_irq(dev->vpirq->start);
@@ -795,10 +839,10 @@
 	writel_relaxed(0x01100101, VCAP_VP_INTERRUPT_ENABLE);
 #ifdef TOP_FIELD_FIX
 	writel_iowmb(0x00000000 | vp_act->top_field << 0, VCAP_VP_CTRL);
-	writel_iowmb(0x00030000 | vp_act->top_field << 0, VCAP_VP_CTRL);
+	writel_iowmb(0x00010000 | vp_act->top_field << 0, VCAP_VP_CTRL);
 #else
 	writel_iowmb(0x00000000 | top_field, VCAP_VP_CTRL);
-	writel_iowmb(0x00030000 | top_field, VCAP_VP_CTRL);
+	writel_iowmb(0x00010000 | top_field, VCAP_VP_CTRL);
 #endif
 
 	atomic_set(&c_data->dev->vp_enabled, 1);
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
index 2ec872b..a7d13a8 100644
--- a/drivers/media/video/videobuf2-core.c
+++ b/drivers/media/video/videobuf2-core.c
@@ -1104,7 +1104,7 @@
 	 * consistent after getting driver's lock back.
 	 */
 	if (q->memory == V4L2_MEMORY_USERPTR) {
-		mmap_sem = &current->mm->mmap_sem;
+		mmap_sem = &current->active_mm->mmap_sem;
 		call_qop(q, wait_prepare, q);
 		down_read(mmap_sem);
 		call_qop(q, wait_finish, q);
@@ -1330,12 +1330,14 @@
 		return -EINVAL;
 	}
 
+	mutex_lock(&q->q_lock);
 	ret = __vb2_get_done_vb(q, &vb, nonblocking);
 	if (ret < 0) {
 		dprintk(1, "dqbuf: error getting next done buffer\n");
+		mutex_unlock(&q->q_lock);
 		return ret;
 	}
-
+	mutex_unlock(&q->q_lock);
 	ret = call_qop(q, buf_finish, vb);
 	if (ret) {
 		dprintk(1, "dqbuf: buffer finish failed\n");
@@ -1447,15 +1449,17 @@
 	/*
 	 * Let driver notice that streaming state has been enabled.
 	 */
+	mutex_lock(&q->q_lock);
 	ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count));
 	if (ret) {
 		dprintk(1, "streamon: driver refused to start streaming\n");
 		__vb2_queue_cancel(q);
+		mutex_unlock(&q->q_lock);
 		return ret;
 	}
 
 	q->streaming = 1;
-
+	mutex_unlock(&q->q_lock);
 	dprintk(3, "Streamon successful\n");
 	return 0;
 }
@@ -1729,6 +1733,7 @@
 	INIT_LIST_HEAD(&q->queued_list);
 	INIT_LIST_HEAD(&q->done_list);
 	spin_lock_init(&q->done_lock);
+	mutex_init(&q->q_lock);
 	init_waitqueue_head(&q->done_wq);
 
 	if (q->buf_struct_size == 0)
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 90673fc5..05707fd 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -12,6 +12,7 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
@@ -246,6 +247,12 @@
 	},
 };
 
+static struct mfd_cell taiko_devs[] = {
+	{
+		.name = "taiko_codec",
+	},
+};
+
 static void wcd9xxx_bring_up(struct wcd9xxx *wcd9xxx)
 {
 	wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x4);
@@ -314,10 +321,12 @@
 
 	wcd9xxx_bring_up(wcd9xxx);
 
-	ret = wcd9xxx_irq_init(wcd9xxx);
-	if (ret) {
-		pr_err("IRQ initialization failed\n");
-		goto err;
+	if (wcd9xxx->irq != -1) {
+		ret = wcd9xxx_irq_init(wcd9xxx);
+		if (ret) {
+			pr_err("IRQ initialization failed\n");
+			goto err;
+		}
 	}
 
 	wcd9xxx->idbyte_0 = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_0);
@@ -336,13 +345,16 @@
 	} else if (wcd9xxx->idbyte_0 == 0x1) {
 		wcd9xxx_dev = tabla1x_devs;
 		wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
+	} else if (wcd9xxx->idbyte_0 == 0x0 && wcd9xxx->idbyte_1 == 0x0 &&
+		   wcd9xxx->idbyte_2 == 0x2 && wcd9xxx->idbyte_3 == 0x1) {
+		wcd9xxx_dev = taiko_devs;
+		wcd9xxx_dev_size = ARRAY_SIZE(taiko_devs);
 	} else if (wcd9xxx->idbyte_0 == 0x0) {
 		wcd9xxx_dev = sitar_devs;
 		wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
 	}
-	ret = mfd_add_devices(wcd9xxx->dev, -1,
-		      wcd9xxx_dev, wcd9xxx_dev_size,
-		      NULL, 0);
+	ret = mfd_add_devices(wcd9xxx->dev, -1, wcd9xxx_dev, wcd9xxx_dev_size,
+			      NULL, 0);
 	if (ret != 0) {
 		dev_err(wcd9xxx->dev, "Failed to add children: %d\n", ret);
 		goto err_irq;
@@ -488,10 +500,15 @@
 		goto err;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++)
-		wcd9xxx->supplies[i].supply = pdata->regulator[i].name;
+	wcd9xxx->num_of_supplies = 0;
+	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+		if (pdata->regulator[i].name) {
+			wcd9xxx->supplies[i].supply = pdata->regulator[i].name;
+			wcd9xxx->num_of_supplies++;
+		}
+	}
 
-	ret = regulator_bulk_get(wcd9xxx->dev, ARRAY_SIZE(pdata->regulator),
+	ret = regulator_bulk_get(wcd9xxx->dev, wcd9xxx->num_of_supplies,
 				 wcd9xxx->supplies);
 	if (ret != 0) {
 		dev_err(wcd9xxx->dev, "Failed to get supplies: err = %d\n",
@@ -499,7 +516,7 @@
 		goto err_supplies;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+	for (i = 0; i < wcd9xxx->num_of_supplies; i++) {
 		ret = regulator_set_voltage(wcd9xxx->supplies[i].consumer,
 			pdata->regulator[i].min_uV, pdata->regulator[i].max_uV);
 		if (ret) {
@@ -519,7 +536,7 @@
 		}
 	}
 
-	ret = regulator_bulk_enable(ARRAY_SIZE(pdata->regulator),
+	ret = regulator_bulk_enable(wcd9xxx->num_of_supplies,
 				    wcd9xxx->supplies);
 	if (ret != 0) {
 		dev_err(wcd9xxx->dev, "Failed to enable supplies: err = %d\n",
@@ -529,13 +546,13 @@
 	return ret;
 
 err_configure:
-	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+	for (i = 0; i < wcd9xxx->num_of_supplies; i++) {
 		regulator_set_voltage(wcd9xxx->supplies[i].consumer, 0,
 			pdata->regulator[i].max_uV);
 		regulator_set_optimum_mode(wcd9xxx->supplies[i].consumer, 0);
 	}
 err_get:
-	regulator_bulk_free(ARRAY_SIZE(pdata->regulator), wcd9xxx->supplies);
+	regulator_bulk_free(wcd9xxx->num_of_supplies, wcd9xxx->supplies);
 err_supplies:
 	kfree(wcd9xxx->supplies);
 err:
@@ -547,14 +564,14 @@
 {
 	int i;
 
-	regulator_bulk_disable(ARRAY_SIZE(pdata->regulator),
+	regulator_bulk_disable(wcd9xxx->num_of_supplies,
 				    wcd9xxx->supplies);
-	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+	for (i = 0; i < wcd9xxx->num_of_supplies; i++) {
 		regulator_set_voltage(wcd9xxx->supplies[i].consumer, 0,
 			pdata->regulator[i].max_uV);
 		regulator_set_optimum_mode(wcd9xxx->supplies[i].consumer, 0);
 	}
-	regulator_bulk_free(ARRAY_SIZE(pdata->regulator), wcd9xxx->supplies);
+	regulator_bulk_free(wcd9xxx->num_of_supplies, wcd9xxx->supplies);
 	kfree(wcd9xxx->supplies);
 }
 
@@ -783,6 +800,252 @@
 	return 0;
 }
 
+#define CODEC_DT_MAX_PROP_SIZE   40
+static int wcd9xxx_dt_parse_vreg_info(struct device *dev,
+	struct wcd9xxx_regulator *vreg, const char *vreg_name)
+{
+	int len, ret = 0;
+	const __be32 *prop;
+	char prop_name[CODEC_DT_MAX_PROP_SIZE];
+	struct device_node *regnode = NULL;
+	u32 prop_val;
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "%s-supply",
+		vreg_name);
+	regnode = of_parse_phandle(dev->of_node, prop_name, 0);
+
+	if (!regnode) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+				prop_name, dev->of_node->full_name);
+		return -ENODEV;
+	}
+	vreg->name = vreg_name;
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+		"qcom,%s-voltage", vreg_name);
+	prop = of_get_property(dev->of_node, prop_name, &len);
+
+	if (!prop || (len != (2 * sizeof(__be32)))) {
+		dev_err(dev, "%s %s property\n",
+				prop ? "invalid format" : "no", prop_name);
+		return -ENODEV;
+	} else {
+		vreg->min_uV = be32_to_cpup(&prop[0]);
+		vreg->max_uV = be32_to_cpup(&prop[1]);
+	}
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+			"qcom,%s-current", vreg_name);
+
+	ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
+	if (ret) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+				prop_name, dev->of_node->full_name);
+		return -ENODEV;
+	}
+	vreg->optimum_uA = prop_val;
+
+	dev_info(dev, "%s: vol=[%d %d]uV, curr=[%d]uA\n", vreg->name,
+		vreg->min_uV, vreg->max_uV, vreg->optimum_uA);
+	return 0;
+}
+
+static int wcd9xxx_dt_parse_micbias_info(struct device *dev,
+	struct wcd9xxx_micbias_setting *micbias)
+{
+	int ret = 0;
+	char prop_name[CODEC_DT_MAX_PROP_SIZE];
+	u32 prop_val;
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+			"qcom,cdc-micbias-ldoh-v");
+	ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
+	if (ret) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+			prop_name, dev->of_node->full_name);
+		return -ENODEV;
+	}
+	micbias->ldoh_v  =  (u8)prop_val;
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+			"qcom,cdc-micbias-cfilt1-mv");
+	ret = of_property_read_u32(dev->of_node, prop_name,
+				   &micbias->cfilt1_mv);
+	if (ret) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+			prop_name, dev->of_node->full_name);
+		return -ENODEV;
+	}
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+			"qcom,cdc-micbias-cfilt2-mv");
+	ret = of_property_read_u32(dev->of_node, prop_name,
+				   &micbias->cfilt2_mv);
+	if (ret) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+			prop_name, dev->of_node->full_name);
+		return -ENODEV;
+	}
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+			"qcom,cdc-micbias-cfilt3-mv");
+	ret = of_property_read_u32(dev->of_node, prop_name,
+				   &micbias->cfilt3_mv);
+	if (ret) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+			prop_name, dev->of_node->full_name);
+		return -ENODEV;
+	}
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+			"qcom,cdc-micbias1-cfilt-sel");
+	ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
+	if (ret) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+			prop_name, dev->of_node->full_name);
+		return -ENODEV;
+	}
+	micbias->bias1_cfilt_sel = (u8)prop_val;
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+			"qcom,cdc-micbias2-cfilt-sel");
+	ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
+	if (ret) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+			prop_name, dev->of_node->full_name);
+		return -ENODEV;
+	}
+	micbias->bias2_cfilt_sel = (u8)prop_val;
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+			"qcom,cdc-micbias3-cfilt-sel");
+	ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
+	if (ret) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+			prop_name, dev->of_node->full_name);
+		return -ENODEV;
+	}
+	micbias->bias3_cfilt_sel = (u8)prop_val;
+
+	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
+			"qcom,cdc-micbias4-cfilt-sel");
+	ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
+	if (ret) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+			prop_name, dev->of_node->full_name);
+		return -ENODEV;
+	}
+	micbias->bias4_cfilt_sel = (u8)prop_val;
+
+	dev_dbg(dev, "ldoh_v  %u cfilt1_mv %u cfilt2_mv %u cfilt3_mv %u",
+		(u32)micbias->ldoh_v, (u32)micbias->cfilt1_mv,
+		(u32)micbias->cfilt2_mv, (u32)micbias->cfilt3_mv);
+
+	dev_dbg(dev, "bias1_cfilt_sel %u bias2_cfilt_sel %u\n",
+		(u32)micbias->bias1_cfilt_sel, (u32)micbias->bias2_cfilt_sel);
+
+	dev_dbg(dev, "bias3_cfilt_sel %u bias4_cfilt_sel %u\n",
+		(u32)micbias->bias3_cfilt_sel, (u32)micbias->bias4_cfilt_sel);
+
+	return 0;
+}
+
+static int wcd9xxx_dt_parse_slim_interface_dev_info(struct device *dev,
+						struct slim_device *slim_ifd)
+{
+	int ret = 0;
+	struct property *prop;
+
+	ret = of_property_read_string(dev->of_node, "qcom,cdc-slim-ifd",
+				      &slim_ifd->name);
+	if (ret) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+			"qcom,cdc-slim-ifd-dev", dev->of_node->full_name);
+		return -ENODEV;
+	}
+	prop = of_find_property(dev->of_node,
+			"qcom,cdc-slim-ifd-elemental-addr", NULL);
+	if (!prop) {
+		dev_err(dev, "Looking up %s property in node %s failed",
+			"qcom,cdc-slim-ifd-elemental-addr",
+			dev->of_node->full_name);
+		return -ENODEV;
+	} else if (prop->length != 6) {
+		dev_err(dev, "invalid codec slim ifd addr. addr length = %d\n",
+			      prop->length);
+		return -ENODEV;
+	}
+	memcpy(slim_ifd->e_addr, prop->value, 6);
+
+	return 0;
+}
+
+static char *taiko_supplies[] = {
+	"cdc-vdd-buck", "cdc-vdd-tx-h", "cdc-vdd-rx-h", "cdc-vddpx-1",
+	"cdc-vdd-a-1p2v", "cdc-vddcx-1", "cdc-vddcx-2",
+};
+
+static struct wcd9xxx_pdata *wcd9xxx_populate_dt_pdata(struct device *dev)
+{
+	struct wcd9xxx_pdata *pdata;
+	int ret, i;
+	char **codec_supplies;
+	u32 num_of_supplies = 0;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(dev,
+			"could not allocate memory for platform data\n");
+		return NULL;
+	}
+
+	if (!strcmp(dev_name(dev), "taiko-slim-pgd")) {
+		codec_supplies = taiko_supplies;
+		num_of_supplies = ARRAY_SIZE(taiko_supplies);
+	} else {
+		dev_err(dev, "%s unsupported device %s\n",
+				__func__, dev_name(dev));
+		goto err;
+	}
+
+	if (num_of_supplies > ARRAY_SIZE(pdata->regulator)) {
+		dev_err(dev, "%s: Num of supplies %u > max supported %u\n",
+		      __func__, num_of_supplies, ARRAY_SIZE(pdata->regulator));
+
+		goto err;
+	}
+
+	for (i = 0; i < num_of_supplies; i++) {
+		ret = wcd9xxx_dt_parse_vreg_info(dev, &pdata->regulator[i],
+			codec_supplies[i]);
+		if (ret)
+			goto err;
+	}
+
+	ret = wcd9xxx_dt_parse_micbias_info(dev, &pdata->micbias);
+	if (ret)
+		goto err;
+
+	pdata->reset_gpio = of_get_named_gpio(dev->of_node,
+				"qcom,cdc-reset-gpio", 0);
+	if (pdata->reset_gpio < 0) {
+		dev_err(dev, "Looking up %s property in node %s failed %d\n",
+			"qcom, cdc-reset-gpio", dev->of_node->full_name,
+			pdata->reset_gpio);
+		goto err;
+	}
+	pdata->irq = -1;
+
+	ret = wcd9xxx_dt_parse_slim_interface_dev_info(dev,
+			&pdata->slimbus_slave_device);
+	if (ret)
+		goto err;
+	return pdata;
+err:
+	devm_kfree(dev, pdata);
+	return NULL;
+}
+
 static int wcd9xxx_slim_probe(struct slim_device *slim)
 {
 	struct wcd9xxx *wcd9xxx;
@@ -790,8 +1053,15 @@
 	int ret = 0;
 	int sgla_retry_cnt;
 
-	dev_info(&slim->dev, "Initialized slim device %s\n", slim->name);
-	pdata = slim->dev.platform_data;
+	if (slim->dev.of_node) {
+		dev_info(&slim->dev, "Platform data from device tree\n");
+		pdata = wcd9xxx_populate_dt_pdata(&slim->dev);
+		slim->dev.platform_data = pdata;
+
+	} else {
+		dev_info(&slim->dev, "Platform data from board file\n");
+		pdata = slim->dev.platform_data;
+	}
 
 	if (!pdata) {
 		dev_err(&slim->dev, "Error, no platform data\n");
@@ -883,7 +1153,9 @@
 		pr_err("%s: error, initializing device failed\n", __func__);
 		goto err_slim_add;
 	}
+
 	wcd9xxx_init_slimslave(wcd9xxx, wcd9xxx_pgd_la);
+
 #ifdef CONFIG_DEBUG_FS
 	debugCodec = wcd9xxx;
 
@@ -1091,6 +1363,23 @@
 	.suspend = wcd9xxx_slim_suspend,
 };
 
+static const struct slim_device_id taiko_slimtest_id[] = {
+	{"taiko-slim-pgd", 0},
+	{}
+};
+
+static struct slim_driver taiko_slim_driver = {
+	.driver = {
+		.name = "taiko-slim",
+		.owner = THIS_MODULE,
+	},
+	.probe = wcd9xxx_slim_probe,
+	.remove = wcd9xxx_slim_remove,
+	.id_table = taiko_slimtest_id,
+	.resume = wcd9xxx_slim_resume,
+	.suspend = wcd9xxx_slim_suspend,
+};
+
 #define WCD9XXX_I2C_TOP_LEVEL	0
 #define WCD9XXX_I2C_ANALOG	1
 #define WCD9XXX_I2C_DIGITAL_1	2
@@ -1119,7 +1408,7 @@
 
 static int __init wcd9xxx_init(void)
 {
-	int ret1, ret2, ret3, ret4, ret5;
+	int ret1, ret2, ret3, ret4, ret5, ret6;
 
 	ret1 = slim_driver_register(&tabla_slim_driver);
 	if (ret1 != 0)
@@ -1141,7 +1430,11 @@
 	if (ret5 != 0)
 		pr_err("Failed to register sitar SB driver: %d\n", ret5);
 
-	return (ret1 && ret2 && ret3 && ret4 && ret5) ? -1 : 0;
+	ret6 = slim_driver_register(&taiko_slim_driver);
+	if (ret6 != 0)
+		pr_err("Failed to register taiko SB driver: %d\n", ret6);
+
+	return (ret1 && ret2 && ret3 && ret4 && ret5 && ret6) ? -1 : 0;
 }
 module_init(wcd9xxx_init);
 
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index ea9fcaf..71c68acb 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -12,6 +12,9 @@
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+
+#define WCD9XXX_CHIP_ID_TAIKO 0x00000201
 
 struct wcd9xxx_slim_sch_rx {
 	u32 sph;
@@ -30,37 +33,111 @@
 struct wcd9xxx_slim_sch {
 	struct wcd9xxx_slim_sch_rx rx[SLIM_MAX_RX_PORTS];
 	struct wcd9xxx_slim_sch_tx tx[SLIM_MAX_TX_PORTS];
+
+	u16 rx_port_start_offset;
+	u16 num_rx_slave_port;
+	u16 port_ch_0_start_port_id;
+	u16 port_ch_0_end_port_id;
+	u16 pgd_tx_port_ch_1_end_port_id;
+	u16 rx_port_ch_reg_base;
+	u16 port_tx_cfg_reg_base;
+	u16 port_rx_cfg_reg_base;
+	int number_of_tx_slave_dev_ports;
+	int number_of_rx_slave_dev_ports;
 };
 
 static struct wcd9xxx_slim_sch sh_ch;
 
 static int wcd9xxx_alloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx,
-					u8 wcd9xxx_pgd_la);
+				       u8 wcd9xxx_pgd_la);
 static int wcd9xxx_alloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx,
 					u8 wcd9xxx_pgd_la);
 static int wcd9xxx_dealloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx);
 static int wcd9xxx_dealloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx);
 
+static int wcd9xxx_configure_ports(struct wcd9xxx *wcd9xxx)
+{
+	int i;
+	u32 id;
+	for (i = 0; i < 4; i++)
+		((u8 *)&id)[i] = wcd9xxx_reg_read(wcd9xxx,
+						  WCD9XXX_A_CHIP_ID_BYTE_0 + i);
+	id = cpu_to_be32(id);
+	pr_debug("%s: chip id 0x%08x\n", __func__, id);
+	if (id != WCD9XXX_CHIP_ID_TAIKO) {
+		sh_ch.rx_port_start_offset =
+		    TABLA_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS;
+		sh_ch.num_rx_slave_port =
+		    TABLA_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS;
+		sh_ch.port_ch_0_start_port_id =
+		    TABLA_SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID;
+		sh_ch.port_ch_0_end_port_id =
+		    TABLA_SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID;
+		sh_ch.pgd_tx_port_ch_1_end_port_id =
+		    TABLA_SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID;
+
+		sh_ch.rx_port_ch_reg_base =
+		    0x180 + (TABLA_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS * 4);
+		sh_ch.port_rx_cfg_reg_base =
+		    0x040 + (TABLA_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS);
+		sh_ch.port_tx_cfg_reg_base = 0x040;
+
+		sh_ch.number_of_tx_slave_dev_ports =
+		    TABLA_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS;
+		sh_ch.number_of_rx_slave_dev_ports =
+		    TABLA_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS;
+	} else {
+		sh_ch.rx_port_start_offset =
+		    TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS;
+		sh_ch.num_rx_slave_port =
+		    TAIKO_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS;
+		sh_ch.port_ch_0_start_port_id =
+		    TAIKO_SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID;
+		sh_ch.port_ch_0_end_port_id =
+		    TAIKO_SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID;
+		sh_ch.pgd_tx_port_ch_1_end_port_id =
+		    TAIKO_SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID;
+
+		sh_ch.rx_port_ch_reg_base = 0x180;
+		sh_ch.port_rx_cfg_reg_base = 0x040;
+		sh_ch.port_tx_cfg_reg_base = 0x050;
+
+		sh_ch.number_of_tx_slave_dev_ports =
+		    TAIKO_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS;
+		sh_ch.number_of_rx_slave_dev_ports =
+		    TAIKO_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS;
+	}
+
+	return 0;
+}
+
 int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la)
 {
 	int ret = 0;
 
+	ret = wcd9xxx_configure_ports(wcd9xxx);
+	if (ret) {
+		pr_err("%s: Failed to configure register address offset\n",
+		       __func__);
+		goto err;
+	}
+
 	ret = wcd9xxx_alloc_slim_sh_ch_rx(wcd9xxx, wcd9xxx_pgd_la);
 	if (ret) {
 		pr_err("%s: Failed to alloc rx slimbus shared channels\n",
-								__func__);
-		goto rx_err;
+		       __func__);
+		goto err;
 	}
 	ret = wcd9xxx_alloc_slim_sh_ch_tx(wcd9xxx, wcd9xxx_pgd_la);
 	if (ret) {
 		pr_err("%s: Failed to alloc tx slimbus shared channels\n",
-								__func__);
+		       __func__);
 		goto tx_err;
 	}
 	return 0;
 tx_err:
 	wcd9xxx_dealloc_slim_sh_ch_rx(wcd9xxx);
-rx_err:
+err:
 	return ret;
 }
 
@@ -82,23 +159,22 @@
 	return ret;
 }
 
-int wcd9xxx_get_channel(struct wcd9xxx *wcd9xxx,
-		unsigned int *rx_ch,
-		unsigned int *tx_ch)
+int wcd9xxx_get_channel(struct wcd9xxx *wcd9xxx, unsigned int *rx_ch,
+			unsigned int *tx_ch)
 {
 	int ch_idx = 0;
 	struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
 	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
 
-	for (ch_idx = 0; ch_idx < SLIM_MAX_RX_PORTS; ch_idx++)
+	for (ch_idx = 0; ch_idx < sh_ch.number_of_rx_slave_dev_ports; ch_idx++)
 		rx_ch[ch_idx] = rx[ch_idx].ch_num;
-	for (ch_idx = 0; ch_idx < SLIM_MAX_TX_PORTS; ch_idx++)
+	for (ch_idx = 0; ch_idx < sh_ch.number_of_tx_slave_dev_ports; ch_idx++)
 		tx_ch[ch_idx] = tx[ch_idx].ch_num;
 	return 0;
 }
 
 static int wcd9xxx_alloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx,
-			u8 wcd9xxx_pgd_la)
+				       u8 wcd9xxx_pgd_la)
 {
 	int ret = 0;
 	u8 ch_idx ;
@@ -109,35 +185,38 @@
 	 * DSP requires channel number to be between 128 and 255.
 	 */
 	pr_debug("%s: pgd_la[%d]\n", __func__, wcd9xxx_pgd_la);
-	for (ch_idx = 0; ch_idx < SLIM_MAX_RX_PORTS; ch_idx++) {
-		slave_port_id = (ch_idx + 1 +
-				SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS);
+	for (ch_idx = 0; ch_idx < sh_ch.number_of_rx_slave_dev_ports;
+	     ch_idx++) {
+		slave_port_id = (ch_idx + sh_ch.rx_port_start_offset);
 		rx[ch_idx].ch_num = slave_port_id + BASE_CH_NUM;
 		ret = slim_get_slaveport(wcd9xxx_pgd_la, slave_port_id,
 					&rx[ch_idx].sph, SLIM_SINK);
 		if (ret < 0) {
 			pr_err("%s: slave port failure id[%d] ret[%d]\n",
-					__func__, slave_port_id, ret);
+			       __func__, slave_port_id, ret);
 			goto err;
 		}
 
 		ret = slim_query_ch(wcd9xxx->slim, rx[ch_idx].ch_num,
-							&rx[ch_idx].ch_h);
+				    &rx[ch_idx].ch_h);
 		if (ret < 0) {
 			pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n",
-					__func__, rx[ch_idx].ch_num, ret);
+			       __func__, rx[ch_idx].ch_num, ret);
 			goto err;
 		}
+		pr_debug("%s:ch_num=%d ch_h=%d sph=%d la=%d slave_port_id %d\n",
+			 __func__, rx[ch_idx].ch_num, rx[ch_idx].ch_h,
+			 rx[ch_idx].sph, wcd9xxx_pgd_la, slave_port_id);
 	}
 err:
 	return ret;
 }
 
 static int wcd9xxx_alloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx,
-			u8 wcd9xxx_pgd_la)
+				       u8 wcd9xxx_pgd_la)
 {
 	int ret = 0;
-	u8 ch_idx ;
+	u8 ch_idx;
 	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
 	u16 slave_port_id = 0;
 
@@ -146,21 +225,22 @@
 	 * use channel numbers from 138 to 144, for TX port
 	 * use channel numbers from 128 to 137
 	 */
-	for (ch_idx = 0; ch_idx < SLIM_MAX_TX_PORTS; ch_idx++) {
+	for (ch_idx = 0; ch_idx < sh_ch.number_of_tx_slave_dev_ports;
+	     ch_idx++) {
 		slave_port_id = ch_idx;
 		tx[ch_idx].ch_num = slave_port_id + BASE_CH_NUM;
 		ret = slim_get_slaveport(wcd9xxx_pgd_la, slave_port_id,
-					&tx[ch_idx].sph, SLIM_SRC);
+					 &tx[ch_idx].sph, SLIM_SRC);
 		if (ret < 0) {
 			pr_err("%s: slave port failure id[%d] ret[%d]\n",
-					__func__, slave_port_id, ret);
+			       __func__, slave_port_id, ret);
 			goto err;
 		}
 		ret = slim_query_ch(wcd9xxx->slim, tx[ch_idx].ch_num,
-							&tx[ch_idx].ch_h);
+				    &tx[ch_idx].ch_h);
 		if (ret < 0) {
 			pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n",
-					__func__, tx[ch_idx].ch_num, ret);
+			       __func__, tx[ch_idx].ch_num, ret);
 			goto err;
 		}
 	}
@@ -174,7 +254,7 @@
 	int ret = 0;
 	struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
 	/* slim_dealloc_ch */
-	for (idx = 0; idx < SLIM_MAX_RX_PORTS; idx++) {
+	for (idx = 0; idx < sh_ch.number_of_rx_slave_dev_ports; idx++) {
 		ret = slim_dealloc_ch(wcd9xxx->slim, rx[idx].ch_h);
 		if (ret < 0) {
 			pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n",
@@ -191,7 +271,7 @@
 	int ret = 0;
 	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
 	/* slim_dealloc_ch */
-	for (idx = 0; idx < SLIM_MAX_TX_PORTS; idx++) {
+	for (idx = 0; idx < sh_ch.number_of_tx_slave_dev_ports; idx++) {
 		ret = slim_dealloc_ch(wcd9xxx->slim, tx[idx].ch_h);
 		if (ret < 0) {
 			pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n",
@@ -204,9 +284,9 @@
 
 /* Enable slimbus slave device for RX path */
 int wcd9xxx_cfg_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
-				unsigned int ch_cnt, unsigned int rate)
+			    unsigned int ch_cnt, unsigned int rate)
 {
-	u8 i = 0;
+	u8 i;
 	u16 grph;
 	u32 sph[SLIM_MAX_RX_PORTS] = {0};
 	u16 ch_h[SLIM_MAX_RX_PORTS] = {0};
@@ -221,53 +301,56 @@
 	pr_debug("%s: ch_cnt[%d] rate=%d\n", __func__, ch_cnt, rate);
 
 	for (i = 0; i < ch_cnt; i++) {
-		idx = (ch_num[i] - BASE_CH_NUM -
-			SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+		idx = (ch_num[i] - BASE_CH_NUM - sh_ch.rx_port_start_offset);
 		ch_h[i] = rx[idx].ch_h;
 		sph[i] = rx[idx].sph;
-		slave_port_id = idx + 1;
-		if ((slave_port_id > SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS) ||
-			(slave_port_id == 0)) {
+		slave_port_id = idx;
+		pr_debug("%s: idx %d, ch_h %d, sph %d\n",
+			 __func__, idx, ch_h[i], sph[i]);
+		if ((slave_port_id > sh_ch.num_rx_slave_port)) {
 			pr_err("Slimbus: invalid slave port id: %d",
-							slave_port_id);
+			       slave_port_id);
 			ret = -EINVAL;
 			goto err;
 		}
-		slave_port_id += SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS;
+		slave_port_id += sh_ch.rx_port_start_offset;
+		pr_debug("%s: slave_port_id %d\n", __func__, slave_port_id);
 		/* look for the valid port range and chose the
 		 * payload accordingly
 		 */
-		if ((slave_port_id >
-				SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID) &&
-			(slave_port_id <=
-			 SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID)) {
-				payload_rx = payload_rx  |
-				(1 <<
-				(slave_port_id -
-				SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID));
+		if ((slave_port_id > sh_ch.pgd_tx_port_ch_1_end_port_id) &&
+		    (slave_port_id <= sh_ch.port_ch_0_end_port_id)) {
+			payload_rx = payload_rx |
+				(1 << (slave_port_id -
+				      sh_ch.port_ch_0_start_port_id));
 		} else {
 			ret = -EINVAL;
 			goto err;
 		}
+
 		multi_chan_cfg_reg_addr =
-				SB_PGD_RX_PORT_MULTI_CHANNEL_0(slave_port_id);
+		    SB_PGD_RX_PORT_MULTI_CHANNEL_0(sh_ch.rx_port_ch_reg_base,
+						   idx);
+		pr_debug("%s: multi_chan_cfg_reg_addr 0x%x\n", __func__,
+			 multi_chan_cfg_reg_addr);
+
 		/* write to interface device */
 		ret = wcd9xxx_interface_reg_write(wcd9xxx,
-				multi_chan_cfg_reg_addr,
-				payload_rx);
+						  multi_chan_cfg_reg_addr,
+						  payload_rx);
 		if (ret < 0) {
 			pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
-							__func__,
-							multi_chan_cfg_reg_addr,
-							payload_rx, ret);
+			       __func__, multi_chan_cfg_reg_addr,
+			       payload_rx, ret);
 			goto err;
 		}
 		/* configure the slave port for water mark and enable*/
 		wm_payload = (SLAVE_PORT_WATER_MARK_VALUE <<
-				SLAVE_PORT_WATER_MARK_SHIFT) +
-				SLAVE_PORT_ENABLE;
-		ret = wcd9xxx_interface_reg_write(wcd9xxx,
-				SB_PGD_PORT_CFG_BYTE_ADDR(slave_port_id),
+			      SLAVE_PORT_WATER_MARK_SHIFT) + SLAVE_PORT_ENABLE;
+		ret = wcd9xxx_interface_reg_write(
+				wcd9xxx,
+				SB_PGD_PORT_CFG_BYTE_ADDR(
+				    sh_ch.port_rx_cfg_reg_base, idx),
 				wm_payload);
 		if (ret < 0) {
 			pr_err("%s:watermark set failure for port[%d] ret[%d]",
@@ -283,16 +366,14 @@
 	prop.ratem = (rate/4000);
 	prop.sampleszbits = 16;
 
-	ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt,
-					true, &grph);
+	ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt, true, &grph);
 	if (ret < 0) {
 		pr_err("%s: slim_define_ch failed ret[%d]\n",
 					__func__, ret);
 		goto err;
 	}
 	for (i = 0; i < ch_cnt; i++) {
-		ret = slim_connect_sink(wcd9xxx->slim, &sph[i],
-							1, ch_h[i]);
+		ret = slim_connect_sink(wcd9xxx->slim, &sph[i], 1, ch_h[i]);
 		if (ret < 0) {
 			pr_err("%s: slim_connect_sink failed ret[%d]\n",
 						__func__, ret);
@@ -300,16 +381,14 @@
 		}
 	}
 	/* slim_control_ch */
-	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_ACTIVATE,
-					true);
+	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_ACTIVATE, true);
 	if (ret < 0) {
 		pr_err("%s: slim_control_ch failed ret[%d]\n",
 				__func__, ret);
 		goto err_close_slim_sch;
 	}
 	for (i = 0; i < ch_cnt; i++) {
-		idx = (ch_num[i] - BASE_CH_NUM -
-				SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+		idx = (ch_num[i] - BASE_CH_NUM - sh_ch.rx_port_start_offset);
 		rx[idx].grph = grph;
 	}
 	return 0;
@@ -324,7 +403,7 @@
 
 /* Enable slimbus slave device for RX path */
 int wcd9xxx_cfg_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
-				unsigned int ch_cnt, unsigned int rate)
+			    unsigned int ch_cnt, unsigned int rate)
 {
 	u8 i = 0;
 	u8  payload_tx_0 = 0, payload_tx_1 = 0, wm_payload = 0;
@@ -333,7 +412,7 @@
 	u16 ch_h[SLIM_MAX_TX_PORTS] = {0};
 	u16 idx = 0, slave_port_id;
 	int ret = 0;
-	unsigned short  multi_chan_cfg_reg_addr;
+	unsigned short multi_chan_cfg_reg_addr;
 
 	struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
 	struct slim_ch prop;
@@ -343,10 +422,12 @@
 		idx = (ch_num[i] - BASE_CH_NUM);
 		ch_h[i] = tx[idx].ch_h;
 		sph[i] = tx[idx].sph;
-		slave_port_id = idx ;
-		if (slave_port_id > SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS) {
+		slave_port_id = idx;
+		pr_debug("%s: idx %d, ch_h %d, sph %d, slave_port_id %d\n",
+			 __func__, idx, ch_h[i], sph[i], slave_port_id);
+		if (slave_port_id > sh_ch.number_of_tx_slave_dev_ports) {
 			pr_err("SLIMbus: invalid slave port id: %d",
-							slave_port_id);
+			       slave_port_id);
 			ret = -EINVAL;
 			goto err;
 		}
@@ -354,55 +435,60 @@
 		 *  payload accordingly
 		 */
 		if (slave_port_id <=
-			SB_PGD_TX_PORT_MULTI_CHANNEL_0_END_PORT_ID) {
+		    SB_PGD_TX_PORT_MULTI_CHANNEL_0_END_PORT_ID) {
 			payload_tx_0 = payload_tx_0 | (1 << slave_port_id);
 		} else if (slave_port_id <=
-				SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID) {
-				payload_tx_1 = payload_tx_1 |
-				(1 <<
-				(slave_port_id -
-				SB_PGD_TX_PORT_MULTI_CHANNEL_1_START_PORT_ID));
+			   sh_ch.pgd_tx_port_ch_1_end_port_id) {
+			payload_tx_1 = payload_tx_1 |
+			    (1 << (slave_port_id -
+				 SB_PGD_TX_PORT_MULTI_CHANNEL_1_START_PORT_ID));
 		} else {
+			pr_err("%s: slave port id %d error\n", __func__,
+			       slave_port_id);
 			ret = -EINVAL;
 			goto err;
 		}
 		multi_chan_cfg_reg_addr =
-				SB_PGD_TX_PORT_MULTI_CHANNEL_0(slave_port_id);
+		    SB_PGD_TX_PORT_MULTI_CHANNEL_0(slave_port_id);
+		pr_debug("%s: multi_chan_cfg_reg_addr 0x%x\n", __func__,
+			 multi_chan_cfg_reg_addr);
 		/* write to interface device */
 		ret = wcd9xxx_interface_reg_write(wcd9xxx,
 				multi_chan_cfg_reg_addr,
 				payload_tx_0);
 		if (ret < 0) {
 			pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
-								__func__,
-						multi_chan_cfg_reg_addr,
-						payload_tx_0, ret);
+			       __func__, multi_chan_cfg_reg_addr, payload_tx_0,
+			       ret);
 			goto err;
 		}
 		multi_chan_cfg_reg_addr =
-				SB_PGD_TX_PORT_MULTI_CHANNEL_1(slave_port_id);
+		    SB_PGD_TX_PORT_MULTI_CHANNEL_1(slave_port_id);
 		/* ports 8,9 */
 		ret = wcd9xxx_interface_reg_write(wcd9xxx,
-				multi_chan_cfg_reg_addr,
-				payload_tx_1);
+						  multi_chan_cfg_reg_addr,
+						  payload_tx_1);
 		if (ret < 0) {
 			pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
-								__func__,
-						multi_chan_cfg_reg_addr,
-						payload_tx_1, ret);
+			       __func__, multi_chan_cfg_reg_addr,
+			       payload_tx_1, ret);
 			goto err;
 		}
 		/* configure the slave port for water mark and enable*/
 		wm_payload = (SLAVE_PORT_WATER_MARK_VALUE <<
-				SLAVE_PORT_WATER_MARK_SHIFT) +
-				SLAVE_PORT_ENABLE;
-		ret = wcd9xxx_interface_reg_write(wcd9xxx,
-				SB_PGD_PORT_CFG_BYTE_ADDR(slave_port_id),
-				wm_payload);
+			      SLAVE_PORT_WATER_MARK_SHIFT) + SLAVE_PORT_ENABLE;
+		pr_debug("%s: tx_cfg_reg 0x%x wm 0x%x\n", __func__,
+			 SB_PGD_PORT_CFG_BYTE_ADDR(sh_ch.port_tx_cfg_reg_base,
+						   slave_port_id), wm_payload);
+		ret = wcd9xxx_interface_reg_write(
+					wcd9xxx,
+					SB_PGD_PORT_CFG_BYTE_ADDR(
+					    sh_ch.port_tx_cfg_reg_base,
+					    slave_port_id),
+					wm_payload);
 		if (ret < 0) {
-			pr_err("%s:watermark set failure for port[%d] ret[%d]",
-						__func__,
-						slave_port_id, ret);
+			pr_err("%s: watermark set failure for port[%d] ret[%d]",
+			       __func__, slave_port_id, ret);
 		}
 	}
 
@@ -413,25 +499,21 @@
 	prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
 	prop.ratem = (rate/4000);
 	prop.sampleszbits = 16;
-	ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt,
-					true, &grph);
+	ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt, true, &grph);
 	if (ret < 0) {
-		pr_err("%s: slim_define_ch failed ret[%d]\n",
-					__func__, ret);
+		pr_err("%s: slim_define_ch failed ret[%d]\n", __func__, ret);
 		goto err;
 	}
 	for (i = 0; i < ch_cnt; i++) {
-		ret = slim_connect_src(wcd9xxx->slim, sph[i],
-							ch_h[i]);
+		ret = slim_connect_src(wcd9xxx->slim, sph[i], ch_h[i]);
 		if (ret < 0) {
 			pr_err("%s: slim_connect_src failed ret[%d]\n",
-						__func__, ret);
+			       __func__, ret);
 			goto err;
 		}
 	}
 	/* slim_control_ch */
-	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_ACTIVATE,
-					true);
+	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_ACTIVATE, true);
 	if (ret < 0) {
 		pr_err("%s: slim_control_ch failed ret[%d]\n",
 				__func__, ret);
@@ -460,23 +542,23 @@
 
 	pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
 	for (i = 0; i < ch_cnt; i++) {
-		idx = (ch_num[i] - BASE_CH_NUM -
-			SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+		idx = (ch_num[i] - BASE_CH_NUM - sh_ch.rx_port_start_offset);
 		if (idx < 0) {
 			pr_err("%s: Error:-Invalid index found = %d\n",
-				__func__, idx);
+			       __func__, idx);
 			ret = -EINVAL;
 			goto err;
 		}
 		sph[i] = rx[idx].sph;
 		grph = rx[idx].grph;
+		pr_debug("%s: ch_num[%d] %d, idx %d, sph[%d] %x, grph %x\n",
+			 __func__, i, ch_num[i], idx, i, sph[i], grph);
 	}
 
 	/* slim_control_ch (REMOVE) */
 	ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
 	if (ret < 0) {
-		pr_err("%s: slim_control_ch failed ret[%d]\n",
-				__func__, ret);
+		pr_err("%s: slim_control_ch failed ret[%d]\n", __func__, ret);
 		goto err;
 	}
 	/* slim_disconnect_port */
@@ -486,8 +568,7 @@
 			 __func__, ret);
 	}
 	for (i = 0; i < ch_cnt; i++) {
-		idx = (ch_num[i] - BASE_CH_NUM -
-				SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+		idx = (ch_num[i] - BASE_CH_NUM - sh_ch.rx_port_start_offset);
 		rx[idx].grph = 0;
 	}
 err:
@@ -496,7 +577,7 @@
 EXPORT_SYMBOL_GPL(wcd9xxx_close_slim_sch_rx);
 
 int wcd9xxx_close_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
-				unsigned int ch_cnt)
+			      unsigned int ch_cnt)
 {
 	u16 grph = 0;
 	u32 sph[SLIM_MAX_TX_PORTS] = {0};
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 8354aa8..696f16d 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -522,7 +522,6 @@
 	return 0;
 }
 
-
 static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
 {
 	int ret;
@@ -771,21 +770,20 @@
 	int ret = 0;
 	struct qseecom_command_scm_resp resp;
 	struct qseecom_registered_app_list *ptr_app;
-	uint32_t unload = 0;
+	bool unload = false;
+	bool found_app = false;
 
 	if (qseecom.qseos_version == QSEOS_VERSION_14) {
 		spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
 		list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
 								list) {
 			if (ptr_app->app_id == data->client.app_id) {
+				found_app = true;
 				if (ptr_app->ref_cnt == 1) {
-					unload = __qseecom_cleanup_app(data);
-					list_del(&ptr_app->list);
-					kzfree(ptr_app);
+					unload = true;
 					break;
 				} else {
 					ptr_app->ref_cnt--;
-					data->released = true;
 					pr_warn("Can't unload app with id %d (it is inuse)\n",
 							ptr_app->app_id);
 					break;
@@ -795,14 +793,20 @@
 		spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
 								flags);
 	}
-	if (!IS_ERR_OR_NULL(data->client.ihandle)) {
-		ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
-		ion_free(qseecom.ion_clnt, data->client.ihandle);
+	if (found_app == false)  {
+		pr_err("Cannot find app with id = %d\n", data->client.app_id);
+		return -EINVAL;
 	}
 
 	if ((unload) && (qseecom.qseos_version == QSEOS_VERSION_14)) {
 		struct qseecom_unload_app_ireq req;
 
+		__qseecom_cleanup_app(data);
+		spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
+		list_del(&ptr_app->list);
+		kzfree(ptr_app);
+		spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
+								flags);
 		/* Populate the structure for sending scm call to load image */
 		req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
 		req.app_id = data->client.app_id;
@@ -840,6 +844,11 @@
 			}
 		}
 	}
+	if (!IS_ERR_OR_NULL(data->client.ihandle)) {
+		ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
+		ion_free(qseecom.ion_clnt, data->client.ihandle);
+		data->client.ihandle = NULL;
+	}
 	data->released = true;
 	return ret;
 }
diff --git a/drivers/misc/tsif.c b/drivers/misc/tsif.c
index aeda38c..7e59c98 100644
--- a/drivers/misc/tsif.c
+++ b/drivers/misc/tsif.c
@@ -169,6 +169,7 @@
 	dma_addr_t dmov_cmd_dma[2];
 	struct tsif_xfer xfer[2];
 	struct tasklet_struct dma_refill;
+	struct tasklet_struct clocks_off;
 	/* statistics */
 	u32 stat_rx;
 	u32 stat_overflow;
@@ -251,18 +252,24 @@
 {
 	if (on) {
 		if (tsif_device->tsif_clk)
-			clk_enable(tsif_device->tsif_clk);
+			clk_prepare_enable(tsif_device->tsif_clk);
 		if (tsif_device->tsif_pclk)
-			clk_enable(tsif_device->tsif_pclk);
-		clk_enable(tsif_device->tsif_ref_clk);
+			clk_prepare_enable(tsif_device->tsif_pclk);
+		clk_prepare_enable(tsif_device->tsif_ref_clk);
 	} else {
 		if (tsif_device->tsif_clk)
-			clk_disable(tsif_device->tsif_clk);
+			clk_disable_unprepare(tsif_device->tsif_clk);
 		if (tsif_device->tsif_pclk)
-			clk_disable(tsif_device->tsif_pclk);
-		clk_disable(tsif_device->tsif_ref_clk);
+			clk_disable_unprepare(tsif_device->tsif_pclk);
+		clk_disable_unprepare(tsif_device->tsif_ref_clk);
 	}
 }
+
+static void tsif_clocks_off(unsigned long data)
+{
+	struct msm_tsif_device *tsif_device = (struct msm_tsif_device *) data;
+	tsif_clock(tsif_device, 0);
+}
 /* ===clocks end=== */
 /* ===gpio begin=== */
 
@@ -605,17 +612,15 @@
 			if (tsif_device->state == tsif_state_running) {
 				tsif_stop_hw(tsif_device);
 				/*
-				 * Clocks _may_ be stopped right from IRQ
-				 * context. This is far from optimal w.r.t
-				 * latency.
-				 *
-				 * But, this branch taken only in case of
+				 * This branch is taken only in case of
 				 * severe hardware problem (I don't even know
-				 * what should happens for DMOV_RSLT_ERROR);
+				 * what should happen for DMOV_RSLT_ERROR);
 				 * thus I prefer code simplicity over
 				 * performance.
+				 * Clocks are turned off from outside the
+				 * interrupt context.
 				 */
-				tsif_clock(tsif_device, 0);
+				tasklet_schedule(&tsif_device->clocks_off);
 				tsif_device->state = tsif_state_flushing;
 			}
 		}
@@ -1313,6 +1318,8 @@
 	tsif_device->chunks_per_buf = TSIF_CHUNKS_IN_BUF_DEFAULT;
 	tasklet_init(&tsif_device->dma_refill, tsif_dma_refill,
 		     (unsigned long)tsif_device);
+	tasklet_init(&tsif_device->clocks_off, tsif_clocks_off,
+		     (unsigned long)tsif_device);
 	if (tsif_get_clocks(tsif_device))
 		goto err_clocks;
 /* map I/O memory */
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index d13b914..e4d0fc1 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1988,11 +1988,15 @@
 {
 	u8 rst_n_function;
 
-	if (!mmc_card_mmc(card))
+	if (mmc_card_sdio(card))
 		return 0;
-	rst_n_function = card->ext_csd.rst_n_function;
-	if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED)
-		return 0;
+
+	if (mmc_card_mmc(card)) {
+		rst_n_function = card->ext_csd.rst_n_function;
+		if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) !=
+		    EXT_CSD_RST_N_ENABLED)
+			return 0;
+	}
 	return 1;
 }
 EXPORT_SYMBOL(mmc_can_reset);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index b5ffe94..b1b8892 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1414,31 +1414,6 @@
 }
 
 /*
- * Save ios settings
- */
-static void mmc_save_ios(struct mmc_host *host)
-{
-	BUG_ON(!host);
-
-	mmc_host_clk_hold(host);
-
-	memcpy(&host->saved_ios, &host->ios, sizeof(struct mmc_ios));
-
-	mmc_host_clk_release(host);
-}
-
-/*
- * Restore ios setting
- */
-static void mmc_restore_ios(struct mmc_host *host)
-{
-	BUG_ON(!host);
-
-	memcpy(&host->ios, &host->saved_ios, sizeof(struct mmc_ios));
-	mmc_set_ios(host);
-}
-
-/*
  * Suspend callback from host.
  */
 static int mmc_suspend(struct mmc_host *host)
@@ -1449,7 +1424,6 @@
 	BUG_ON(!host->card);
 
 	mmc_claim_host(host);
-	mmc_save_ios(host);
 	if (mmc_can_poweroff_notify(host->card) &&
 		(host->caps2 & MMC_CAP2_POWER_OFF_VCCQ_DURING_SUSPEND)) {
 		err = mmc_poweroff_notify(host, MMC_PW_OFF_NOTIFY_SHORT);
@@ -1489,11 +1463,7 @@
 	BUG_ON(!host->card);
 
 	mmc_claim_host(host);
-	if (mmc_card_is_sleep(host->card)) {
-		mmc_restore_ios(host);
-		err = mmc_card_awake(host);
-	} else
-		err = mmc_init_card(host, host->ocr, host->card);
+	err = mmc_init_card(host, host->ocr, host->card);
 	mmc_release_host(host);
 
 	return err;
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 788e5f8..3dbf46f 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -2385,8 +2385,10 @@
 	struct msm_mmc_reg_data *vreg_table[2];
 
 	curr_slot = host->plat->vreg_data;
-	if (!curr_slot)
+	if (!curr_slot) {
+		rc = -EINVAL;
 		goto out;
+	}
 
 	vreg_table[0] = curr_slot->vdd_data;
 	vreg_table[1] = curr_slot->vdd_io_data;
@@ -3986,6 +3988,51 @@
 	return rc;
 }
 
+/*
+ * Work around of the unavailability of a power_reset functionality in SD cards
+ * by turning the OFF & back ON the regulators supplying the SD card.
+ */
+void msmsdcc_hw_reset(struct mmc_host *mmc)
+{
+	struct mmc_card *card = mmc->card;
+	struct msmsdcc_host *host = mmc_priv(mmc);
+	int rc;
+
+	/* Write-protection bits would be lost on a hardware reset in emmc */
+	if (!card || !mmc_card_sd(card))
+		return;
+
+	/*
+	 * Continuing on failing to disable regulator would lead to a panic
+	 * anyway, since the commands would fail and console would be flooded
+	 * with prints, eventually leading to a watchdog bark
+	 */
+	rc = msmsdcc_setup_vreg(host, false, false);
+	if (rc) {
+		pr_err("%s: %s disable regulator: failed: %d\n",
+		       mmc_hostname(mmc), __func__, rc);
+		BUG_ON(rc);
+	}
+
+	/* 10ms delay for the supply to reach the desired voltage level */
+	usleep_range(10000, 12000);
+
+	/*
+	 * Continuing on failing to enable regulator would lead to a panic
+	 * anyway, since the commands would fail and console would be flooded
+	 * with prints, eventually leading to a watchdog bark
+	 */
+	rc = msmsdcc_setup_vreg(host, true, false);
+	if (rc) {
+		pr_err("%s: %s enable regulator: failed: %d\n",
+		       mmc_hostname(mmc), __func__, rc);
+		BUG_ON(rc);
+	}
+
+	/* 10ms delay for the supply to reach the desired voltage level */
+	usleep_range(10000, 12000);
+}
+
 static const struct mmc_host_ops msmsdcc_ops = {
 	.enable		= msmsdcc_enable,
 	.disable	= msmsdcc_disable,
@@ -3996,7 +4043,8 @@
 	.get_ro		= msmsdcc_get_ro,
 	.enable_sdio_irq = msmsdcc_enable_sdio_irq,
 	.start_signal_voltage_switch = msmsdcc_switch_io_voltage,
-	.execute_tuning = msmsdcc_execute_tuning
+	.execute_tuning = msmsdcc_execute_tuning,
+	.hw_reset = msmsdcc_hw_reset,
 };
 
 static unsigned int
@@ -5359,7 +5407,6 @@
 	struct resource *dmares = NULL;
 	struct resource *dma_crci_res = NULL;
 	int ret = 0;
-	int i;
 
 	if (pdev->dev.of_node) {
 		plat = msmsdcc_populate_pdata(&pdev->dev);
@@ -5388,56 +5435,21 @@
 		pr_err("%s: Invalid resource\n", __func__);
 		return -ENXIO;
 	}
-	if (pdev->dev.of_node) {
-		/*
-		 * Device tree iomem resources are only accessible by index.
-		 * index = 0 -> SDCC register interface
-		 * index = 1 -> DML register interface
-		 * index = 2 -> BAM register interface
-		 * IRQ resources:
-		 * index = 0 -> SDCC IRQ
-		 * index = 1 -> BAM IRQ
-		 */
-		core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-		dml_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-		bam_memres = platform_get_resource(pdev, IORESOURCE_MEM, 2);
-		core_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-		bam_irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
-	} else {
-		for (i = 0; i < pdev->num_resources; i++) {
-			if (pdev->resource[i].flags & IORESOURCE_MEM) {
-				if (!strncmp(pdev->resource[i].name,
-						"sdcc_dml_addr",
-						sizeof("sdcc_dml_addr")))
-					dml_memres = &pdev->resource[i];
-				else if (!strncmp(pdev->resource[i].name,
-						"sdcc_bam_addr",
-						sizeof("sdcc_bam_addr")))
-					bam_memres = &pdev->resource[i];
-				else
-					core_memres = &pdev->resource[i];
 
-			}
-			if (pdev->resource[i].flags & IORESOURCE_IRQ) {
-				if (!strncmp(pdev->resource[i].name,
-						"sdcc_bam_irq",
-						sizeof("sdcc_bam_irq")))
-					bam_irqres = &pdev->resource[i];
-				else
-					core_irqres = &pdev->resource[i];
-			}
-			if (pdev->resource[i].flags & IORESOURCE_DMA) {
-				if (!strncmp(pdev->resource[i].name,
-						"sdcc_dma_chnl",
-						sizeof("sdcc_dma_chnl")))
-					dmares = &pdev->resource[i];
-				else if (!strncmp(pdev->resource[i].name,
-						"sdcc_dma_crci",
-						sizeof("sdcc_dma_crci")))
-					dma_crci_res = &pdev->resource[i];
-			}
-		}
-	}
+	core_memres = platform_get_resource_byname(pdev,
+			IORESOURCE_MEM, "core_mem");
+	bam_memres = platform_get_resource_byname(pdev,
+			IORESOURCE_MEM, "bam_mem");
+	dml_memres = platform_get_resource_byname(pdev,
+			IORESOURCE_MEM, "dml_mem");
+	core_irqres = platform_get_resource_byname(pdev,
+			IORESOURCE_IRQ, "core_irq");
+	bam_irqres = platform_get_resource_byname(pdev,
+			IORESOURCE_IRQ, "bam_irq");
+	dmares = platform_get_resource_byname(pdev,
+			IORESOURCE_DMA, "dma_chnl");
+	dma_crci_res = platform_get_resource_byname(pdev,
+			IORESOURCE_DMA, "dma_crci");
 
 	if (!core_irqres || !core_memres) {
 		pr_err("%s: Invalid sdcc core resource\n", __func__);
@@ -5629,7 +5641,7 @@
 	mmc->caps |= plat->mmc_bus_width;
 	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
 	mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
-
+	mmc->caps |= MMC_CAP_HW_RESET;
 	/*
 	 * If we send the CMD23 before multi block write/read command
 	 * then we need not to send CMD12 at the end of the transfer.
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
index eb57693..4f8039e 100644
--- a/drivers/net/usb/rmnet_usb_data.c
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -560,11 +560,12 @@
 
 	usb_enable_autosuspend(udev);
 
-	/* allow modem to wake up suspended system */
-	device_set_wakeup_enable(&udev->dev, 1);
-
-	/* set default autosuspend timeout for modem and roothub */
 	if (udev->parent && !udev->parent->parent) {
+		/* allow modem and roothub to wake up suspended system */
+		device_set_wakeup_enable(&udev->dev, 1);
+		device_set_wakeup_enable(&udev->parent->dev, 1);
+
+		/* set default autosuspend timeout for modem and roothub */
 		pm_runtime_set_autosuspend_delay(&udev->dev, 1000);
 		pm_runtime_set_autosuspend_delay(&udev->parent->dev, 200);
 	}
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 7695778..c0a4e0e 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -21,6 +21,7 @@
 #include <linux/workqueue.h>
 #include <linux/jiffies.h>
 #include <linux/gpio.h>
+#include <linux/wakelock.h>
 #include <mach/peripheral-loader.h>
 
 #define DEVICE "wcnss_wlan"
@@ -48,6 +49,7 @@
 	void		(*tm_notify)(struct device *, int);
 	struct wcnss_wlan_config wlan_config;
 	struct delayed_work wcnss_work;
+	struct wake_lock wcnss_wake_lock;
 } *penv = NULL;
 
 static ssize_t wcnss_serial_number_show(struct device *dev,
@@ -60,7 +62,7 @@
 }
 
 static ssize_t wcnss_serial_number_store(struct device *dev,
-		struct device_attribute *attr, const char * buf, size_t count)
+		struct device_attribute *attr, const char *buf, size_t count)
 {
 	unsigned int value;
 
@@ -88,7 +90,7 @@
 }
 
 static ssize_t wcnss_thermal_mitigation_store(struct device *dev,
-		struct device_attribute *attr, const char * buf, size_t count)
+		struct device_attribute *attr, const char *buf, size_t count)
 {
 	int value;
 
@@ -326,6 +328,20 @@
 	return 0;
 }
 
+void wcnss_prevent_suspend()
+{
+	if (penv)
+		wake_lock(&penv->wcnss_wake_lock);
+}
+EXPORT_SYMBOL(wcnss_prevent_suspend);
+
+void wcnss_allow_suspend()
+{
+	if (penv)
+		wake_unlock(&penv->wcnss_wake_lock);
+}
+EXPORT_SYMBOL(wcnss_allow_suspend);
+
 static int
 wcnss_trigger_config(struct platform_device *pdev)
 {
@@ -398,6 +414,8 @@
 	if (ret)
 		goto fail_sysfs;
 
+	wake_lock_init(&penv->wcnss_wake_lock, WAKE_LOCK_SUSPEND, "wcnss");
+
 	return 0;
 
 fail_sysfs:
diff --git a/drivers/of/of_slimbus.c b/drivers/of/of_slimbus.c
index 512ca73..8aaef25 100644
--- a/drivers/of/of_slimbus.c
+++ b/drivers/of/of_slimbus.c
@@ -66,6 +66,8 @@
 			kfree(slim);
 			return -ENOMEM;
 		}
+
+		slim->dev.of_node = of_node_get(node);
 		slim->name = (const char *)name;
 		binfo[n].bus_num = ctrl->nr;
 		binfo[n].slim_slave = slim;
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index d75cac4..34e1d40 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -67,4 +67,13 @@
 	  This driver supports the power-on functionality on Qualcomm
 	  PNP PMIC. It currently supports reporting the change in status of
 	  the KPDPWR_N line (connected to the power-key).
+
+config QPNP_CLKDIV
+	tristate "QPNP PMIC clkdiv driver"
+	depends on OF_SPMI && SPMI
+	help
+	  This driver supports the clkdiv functionality on the Qualcomm
+	  PNP PMIC. It configures the frequency of clkdiv outputs on the
+	  PMIC. These clocks are typically wired through alternate functions
+	  on gpio pins.
 endmenu
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index 2b6b806..35efd91 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -6,3 +6,4 @@
 obj-$(CONFIG_SPS) += sps/
 obj-$(CONFIG_QPNP_PWM) += qpnp-pwm.o
 obj-$(CONFIG_QPNP_POWER_ON) += qpnp-power-on.o
+obj-$(CONFIG_QPNP_CLKDIV) += qpnp-clkdiv.o
diff --git a/drivers/platform/msm/qpnp-clkdiv.c b/drivers/platform/msm/qpnp-clkdiv.c
new file mode 100644
index 0000000..2a9ba90
--- /dev/null
+++ b/drivers/platform/msm/qpnp-clkdiv.c
@@ -0,0 +1,287 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/types.h>
+#include <linux/spmi.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/time.h>
+#include <linux/qpnp/clkdiv.h>
+
+#define Q_MAX_DT_PROP_SIZE 32
+
+#define Q_REG_ADDR(q_clkdiv, reg_offset)	\
+		((q_clkdiv)->offset + reg_offset)
+
+#define Q_REG_DIV_CTL1			   0x43
+#define Q_REG_EN_CTL			   0x46
+
+#define Q_SET_EN			   BIT(7)
+
+#define Q_CXO_PERIOD_NS(_cxo_clk)	   (NSEC_PER_SEC / _cxo_clk)
+#define Q_DIV_PERIOD_NS(_cxo_clk, _div)	   (NSEC_PER_SEC / (_cxo_clk / _div))
+#define Q_ENABLE_DELAY_NS(_cxo_clk, _div)  (2 * Q_CXO_PERIOD_NS(_cxo_clk) + \
+					    3 * Q_DIV_PERIOD_NS(_cxo_clk, _div))
+#define Q_DISABLE_DELAY_NS(_cxo_clk, _div) (3 * Q_DIV_PERIOD_NS(_cxo_clk, _div))
+
+struct q_clkdiv {
+	uint32_t cxo_hz;
+	enum q_clkdiv_cfg cxo_div;
+	struct device_node *node;
+	uint16_t offset;
+	struct spmi_controller *ctrl;
+	bool enabled;
+	struct mutex lock;
+	struct list_head list;
+	uint8_t slave;
+};
+
+static LIST_HEAD(qpnp_clkdiv_devs);
+
+/**
+ * qpnp_clkdiv_get - get a clkdiv handle
+ * @dev: client device pointer.
+ * @name: client specific name for the clock in question.
+ *
+ * Return a clkdiv handle given a client specific name. This name be a prefix
+ * for a property naming that takes a phandle to the actual clkdiv device.
+ */
+struct q_clkdiv *qpnp_clkdiv_get(struct device *dev, const char *name)
+{
+	struct q_clkdiv *q_clkdiv;
+	struct device_node *divclk_node;
+	char prop_name[Q_MAX_DT_PROP_SIZE];
+	int n;
+
+	n = snprintf(prop_name, Q_MAX_DT_PROP_SIZE, "%s-clk", name);
+	if (n == Q_MAX_DT_PROP_SIZE)
+		return ERR_PTR(-EINVAL);
+
+	divclk_node = of_parse_phandle(dev->of_node, prop_name, 0);
+	if (divclk_node == NULL)
+		return ERR_PTR(-ENODEV);
+
+	list_for_each_entry(q_clkdiv, &qpnp_clkdiv_devs, list)
+		if (q_clkdiv->node == divclk_node)
+			return q_clkdiv;
+	return ERR_PTR(-EPROBE_DEFER);
+}
+EXPORT_SYMBOL(qpnp_clkdiv_get);
+
+static int __clkdiv_enable(struct q_clkdiv *q_clkdiv, bool enable)
+{
+	int rc;
+	char buf[1];
+
+	buf[0] = enable ? Q_SET_EN : 0;
+
+	mutex_lock(&q_clkdiv->lock);
+	rc = spmi_ext_register_writel(q_clkdiv->ctrl, q_clkdiv->slave,
+			      Q_REG_ADDR(q_clkdiv, Q_REG_EN_CTL),
+			      &buf[0], 1);
+	if (!rc)
+		q_clkdiv->enabled = enable;
+
+	mutex_unlock(&q_clkdiv->lock);
+
+	if (enable)
+		ndelay(Q_ENABLE_DELAY_NS(q_clkdiv->cxo_hz, q_clkdiv->cxo_div));
+	else
+		ndelay(Q_DISABLE_DELAY_NS(q_clkdiv->cxo_hz, q_clkdiv->cxo_div));
+
+	return rc;
+}
+
+/**
+ * qpnp_clkdiv_enable - enable a clkdiv
+ * @q_clkdiv: pointer to clkdiv handle
+ */
+int qpnp_clkdiv_enable(struct q_clkdiv *q_clkdiv)
+{
+	return __clkdiv_enable(q_clkdiv, true);
+}
+EXPORT_SYMBOL(qpnp_clkdiv_enable);
+
+/**
+ * qpnp_clkdiv_disable - disable a clkdiv
+ * @q_clkdiv: pointer to clkdiv handle
+ */
+int qpnp_clkdiv_disable(struct q_clkdiv *q_clkdiv)
+{
+	return __clkdiv_enable(q_clkdiv, false);
+}
+EXPORT_SYMBOL(qpnp_clkdiv_disable);
+
+/**
+ * @q_clkdiv: pointer to clkdiv handle
+ * @cfg: setting used to configure the output frequency
+ *
+ * Given a q_clkdiv_cfg setting, configure the corresponding clkdiv device
+ * for the desired output frequency.
+ */
+int qpnp_clkdiv_config(struct q_clkdiv *q_clkdiv, enum q_clkdiv_cfg cfg)
+{
+	int rc;
+	char buf[1];
+
+	if (cfg < 0 || cfg >= Q_CLKDIV_INVALID)
+		return -EINVAL;
+
+	buf[0] = cfg;
+
+	mutex_lock(&q_clkdiv->lock);
+
+	if (q_clkdiv->enabled) {
+		rc = __clkdiv_enable(q_clkdiv, false);
+		if (rc) {
+			pr_err("unable to disable clock\n");
+			goto cfg_err;
+		}
+	}
+
+	rc = spmi_ext_register_writel(q_clkdiv->ctrl, q_clkdiv->slave,
+			      Q_REG_ADDR(q_clkdiv, Q_REG_DIV_CTL1), &buf[0], 1);
+	if (rc) {
+		pr_err("enable to write config\n");
+		q_clkdiv->enabled = 0;
+		goto cfg_err;
+	}
+
+	q_clkdiv->cxo_div = cfg;
+
+	if (q_clkdiv->enabled) {
+		rc = __clkdiv_enable(q_clkdiv, true);
+		if (rc) {
+			pr_err("unable to re-enable clock\n");
+			goto cfg_err;
+		}
+	}
+
+cfg_err:
+	mutex_unlock(&q_clkdiv->lock);
+	return rc;
+}
+EXPORT_SYMBOL(qpnp_clkdiv_config);
+
+static int __devinit qpnp_clkdiv_probe(struct spmi_device *spmi)
+{
+	struct q_clkdiv *q_clkdiv;
+	struct device_node *node = spmi->dev.of_node;
+	int rc;
+	uint32_t en;
+	struct resource *res;
+
+	q_clkdiv = devm_kzalloc(&spmi->dev, sizeof(*q_clkdiv), GFP_ATOMIC);
+	if (!q_clkdiv)
+		return -ENOMEM;
+
+	rc = of_property_read_u32(node, "qcom,cxo-freq",
+					&q_clkdiv->cxo_hz);
+	if (rc) {
+		dev_err(&spmi->dev,
+			"%s: unable to get qcom,cxo-freq property\n", __func__);
+		return rc;
+	}
+
+	res = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&spmi->dev, "%s: unable to get device reg resource\n",
+					__func__);
+	}
+
+	q_clkdiv->slave = spmi->sid;
+	q_clkdiv->offset = res->start;
+	q_clkdiv->ctrl = spmi->ctrl;
+	q_clkdiv->node = node;
+	mutex_init(&q_clkdiv->lock);
+
+	rc = of_property_read_u32(node, "qcom,cxo-div",
+					&q_clkdiv->cxo_div);
+	if (rc && rc != -EINVAL) {
+		dev_err(&spmi->dev,
+			"%s: error getting qcom,cxo-div property\n",
+								__func__);
+		return rc;
+	}
+
+	if (!rc) {
+		rc = qpnp_clkdiv_config(q_clkdiv, q_clkdiv->cxo_div);
+		if (rc) {
+			dev_err(&spmi->dev,
+				"%s: unable to set default divide config\n",
+								    __func__);
+			return rc;
+		}
+	}
+
+	rc = of_property_read_u32(node, "qcom,enable", &en);
+	if (rc && rc != -EINVAL) {
+		dev_err(&spmi->dev,
+			"%s: error getting qcom,enable property\n", __func__);
+		return rc;
+	}
+	if (!rc) {
+		rc = __clkdiv_enable(q_clkdiv, en);
+		dev_err(&spmi->dev,
+				"%s: unable to set default config\n", __func__);
+		return rc;
+	}
+
+	dev_set_drvdata(&spmi->dev, q_clkdiv);
+	list_add(&q_clkdiv->list, &qpnp_clkdiv_devs);
+
+	return 0;
+}
+
+static int __devexit qpnp_clkdiv_remove(struct spmi_device *spmi)
+{
+	struct q_clkdiv *q_clkdiv = dev_get_drvdata(&spmi->dev);
+	list_del(&q_clkdiv->list);
+	return 0;
+}
+
+static struct of_device_id spmi_match_table[] = {
+	{	.compatible = "qcom,qpnp-clkdiv",
+	},
+	{}
+};
+
+static struct spmi_driver qpnp_clkdiv_driver = {
+	.driver		= {
+		.name	= "qcom,qpnp-clkdiv",
+		.of_match_table = spmi_match_table,
+	},
+	.probe		= qpnp_clkdiv_probe,
+	.remove		= __devexit_p(qpnp_clkdiv_remove),
+};
+
+static int __init qpnp_clkdiv_init(void)
+{
+	return spmi_driver_register(&qpnp_clkdiv_driver);
+}
+
+static void __exit qpnp_clkdiv_exit(void)
+{
+	return spmi_driver_unregister(&qpnp_clkdiv_driver);
+}
+
+MODULE_DESCRIPTION("QPNP PMIC clkdiv driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(qpnp_clkdiv_init);
+module_exit(qpnp_clkdiv_exit);
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index d8bb884..0119ebe 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -16,141 +16,635 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/spmi.h>
+#include <linux/delay.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/interrupt.h>
 #include <linux/input.h>
+#include <linux/log2.h>
 
+/* PON common register addresses */
 #define QPNP_PON_RT_STS(base)		(base + 0x10)
 #define QPNP_PON_PULL_CTL(base)		(base + 0x70)
 #define QPNP_PON_DBC_CTL(base)		(base + 0x71)
 
-#define QPNP_PON_CNTL_PULL_UP		BIT(1)
-#define QPNP_PON_CNTL_TRIG_DELAY_MASK	(0x7)
+/* PON/RESET sources register addresses */
+#define QPNP_PON_KPDPWR_S1_TIMER(base)	(base + 0x40)
+#define QPNP_PON_KPDPWR_S2_TIMER(base)	(base + 0x41)
+#define QPNP_PON_KPDPWR_S2_CNTL(base)	(base + 0x42)
+#define QPNP_PON_RESIN_S1_TIMER(base)	(base + 0x44)
+#define QPNP_PON_RESIN_S2_TIMER(base)	(base + 0x45)
+#define QPNP_PON_RESIN_S2_CNTL(base)	(base + 0x46)
+
+#define QPNP_PON_RESIN_PULL_UP		BIT(0)
+#define QPNP_PON_KPDPWR_PULL_UP		BIT(1)
+#define QPNP_PON_S2_CNTL_EN		BIT(7)
+#define QPNP_PON_S2_RESET_ENABLE	BIT(7)
+
+#define QPNP_PON_S1_TIMER_MASK		(0xF)
+#define QPNP_PON_S2_TIMER_MASK		(0x7)
+#define QPNP_PON_S2_CNTL_TYPE_MASK	(0xF)
+
+#define QPNP_PON_DBC_DELAY_MASK		(0x7)
 #define QPNP_PON_KPDPWR_N_SET		BIT(0)
+#define QPNP_PON_RESIN_N_SET		BIT(1)
+#define QPNP_PON_RESIN_BARK_N_SET	BIT(4)
+
+/* Ranges */
+#define QPNP_PON_S1_TIMER_MAX		10256
+#define QPNP_PON_S2_TIMER_MAX		2000
+#define QPNP_PON_RESET_TYPE_MAX		0xF
+#define PON_S1_COUNT_MAX		0xF
+
+#define QPNP_KEY_STATUS_DELAY		msecs_to_jiffies(500)
+
+enum pon_type {
+	PON_KPDPWR,
+	PON_RESIN,
+};
+
+struct qpnp_pon_config {
+	u32 pon_type;
+	u32 support_reset;
+	u32 key_code;
+	u32 s1_timer;
+	u32 s2_timer;
+	u32 s2_type;
+	u32 pull_up;
+	u32 state_irq;
+	u32 bark_irq;
+};
 
 struct qpnp_pon {
 	struct spmi_device *spmi;
 	struct input_dev *pon_input;
-	u32 key_status_irq;
+	struct qpnp_pon_config *pon_cfg;
+	int num_pon_config;
 	u16 base;
+	struct delayed_work bark_work;
 };
 
-static irqreturn_t qpnp_pon_key_irq(int irq, void *_pon)
-{
-	u8 pon_rt_sts;
-	int rc;
-	struct qpnp_pon *pon = _pon;
+static u32 s1_delay[PON_S1_COUNT_MAX + 1] = {
+	0 , 32, 56, 80, 138, 184, 272, 408, 608, 904, 1352, 2048,
+	3072, 4480, 6720, 10256
+};
 
+static int
+qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val)
+{
+	int rc;
+	u8 reg;
+
+	rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+							addr, &reg, 1);
+	if (rc) {
+		dev_err(&pon->spmi->dev,
+			"Unable to read from addr=%x, rc(%d)\n", addr, rc);
+		return rc;
+	}
+
+	reg &= ~mask;
+	reg |= val & mask;
+	rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
+							addr, &reg, 1);
+	if (rc)
+		dev_err(&pon->spmi->dev,
+			"Unable to write to addr=%x, rc(%d)\n", addr, rc);
+	return rc;
+}
+
+static struct qpnp_pon_config *
+qpnp_get_cfg(struct qpnp_pon *pon, u32 pon_type)
+{
+	int i;
+
+	for (i = 0; i < pon->num_pon_config; i++) {
+		if (pon_type == pon->pon_cfg[i].pon_type)
+			return  &pon->pon_cfg[i];
+	}
+
+	return NULL;
+}
+
+static int
+qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type)
+{
+	int rc;
+	struct qpnp_pon_config *cfg = NULL;
+	u8 pon_rt_sts = 0, pon_rt_bit = 0;
+
+	cfg = qpnp_get_cfg(pon, pon_type);
+	if (!cfg)
+		return -EINVAL;
+
+	/* Check if key reporting is supported */
+	if (!cfg->key_code)
+		return 0;
+
+	/* check the RT status to get the current status of the line */
 	rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
 				QPNP_PON_RT_STS(pon->base), &pon_rt_sts, 1);
 	if (rc) {
 		dev_err(&pon->spmi->dev, "Unable to read PON RT status\n");
-		return IRQ_HANDLED;
+		return rc;
 	}
 
-	input_report_key(pon->pon_input, KEY_POWER,
-				!(pon_rt_sts & QPNP_PON_KPDPWR_N_SET));
+	switch (cfg->pon_type) {
+	case PON_KPDPWR:
+		pon_rt_bit = QPNP_PON_KPDPWR_N_SET;
+		break;
+	case PON_RESIN:
+		pon_rt_bit = QPNP_PON_RESIN_N_SET;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	input_report_key(pon->pon_input, cfg->key_code,
+					(pon_rt_sts & pon_rt_bit));
 	input_sync(pon->pon_input);
 
+	return 0;
+}
+
+static irqreturn_t qpnp_kpdpwr_irq(int irq, void *_pon)
+{
+	int rc;
+	struct qpnp_pon *pon = _pon;
+
+	rc = qpnp_pon_input_dispatch(pon, PON_KPDPWR);
+	if (rc)
+		dev_err(&pon->spmi->dev, "Unable to send input event\n");
+
 	return IRQ_HANDLED;
 }
 
-static int __devinit qpnp_pon_key_init(struct qpnp_pon *pon)
+static irqreturn_t qpnp_kpdpwr_bark_irq(int irq, void *_pon)
+{
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t qpnp_resin_irq(int irq, void *_pon)
+{
+	int rc;
+	struct qpnp_pon *pon = _pon;
+
+	rc = qpnp_pon_input_dispatch(pon, PON_RESIN);
+	if (rc)
+		dev_err(&pon->spmi->dev, "Unable to send input event\n");
+	return IRQ_HANDLED;
+}
+
+static void bark_work_func(struct work_struct *work)
+{
+	int rc;
+	u8 pon_rt_sts = 0;
+	struct qpnp_pon_config *cfg;
+	struct qpnp_pon *pon =
+		container_of(work, struct qpnp_pon, bark_work.work);
+
+	/* enable reset */
+	rc = qpnp_pon_masked_write(pon, QPNP_PON_RESIN_S2_CNTL(pon->base),
+				QPNP_PON_S2_CNTL_EN, QPNP_PON_S2_CNTL_EN);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+		goto err_return;
+	}
+	/* bark RT status update delay */
+	msleep(100);
+	/* read the bark RT status */
+	rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+				QPNP_PON_RT_STS(pon->base), &pon_rt_sts, 1);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Unable to read PON RT status\n");
+		goto err_return;
+	}
+
+	if (!(pon_rt_sts & QPNP_PON_RESIN_BARK_N_SET)) {
+		cfg = qpnp_get_cfg(pon, PON_RESIN);
+		if (!cfg) {
+			dev_err(&pon->spmi->dev, "Invalid config pointer\n");
+			goto err_return;
+		}
+		/* report the key event and enable the bark IRQ */
+		input_report_key(pon->pon_input, cfg->key_code, 0);
+		input_sync(pon->pon_input);
+		enable_irq(cfg->bark_irq);
+	} else {
+		/* disable reset */
+		rc = qpnp_pon_masked_write(pon,
+				QPNP_PON_RESIN_S2_CNTL(pon->base),
+				QPNP_PON_S2_CNTL_EN, 0);
+		if (rc) {
+			dev_err(&pon->spmi->dev,
+				"Unable to configure S2 enable\n");
+			goto err_return;
+		}
+		/* re-arm the work */
+		schedule_delayed_work(&pon->bark_work, QPNP_KEY_STATUS_DELAY);
+	}
+
+err_return:
+	return;
+}
+
+static irqreturn_t qpnp_resin_bark_irq(int irq, void *_pon)
+{
+	int rc;
+	struct qpnp_pon *pon = _pon;
+	struct qpnp_pon_config *cfg;
+
+	/* disable the bark interrupt */
+	disable_irq_nosync(irq);
+
+	/* disable reset */
+	rc = qpnp_pon_masked_write(pon, QPNP_PON_RESIN_S2_CNTL(pon->base),
+						QPNP_PON_S2_CNTL_EN, 0);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+		goto err_exit;
+	}
+
+	cfg = qpnp_get_cfg(pon, PON_RESIN);
+	if (!cfg) {
+		dev_err(&pon->spmi->dev, "Invalid config pointer\n");
+		goto err_exit;
+	}
+
+	/* report the key event */
+	input_report_key(pon->pon_input, cfg->key_code, 1);
+	input_sync(pon->pon_input);
+	/* schedule work to check the bark status for key-release */
+	schedule_delayed_work(&pon->bark_work, QPNP_KEY_STATUS_DELAY);
+err_exit:
+	return IRQ_HANDLED;
+}
+
+static int __devinit
+qpnp_config_pull(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
+{
+	int rc;
+	u8 pull_bit;
+
+	switch (cfg->pon_type) {
+	case PON_KPDPWR:
+		pull_bit = QPNP_PON_KPDPWR_PULL_UP;
+		break;
+	case PON_RESIN:
+		pull_bit = QPNP_PON_RESIN_PULL_UP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	rc = qpnp_pon_masked_write(pon, QPNP_PON_PULL_CTL(pon->base),
+				pull_bit, cfg->pull_up ? pull_bit : 0);
+	if (rc)
+		dev_err(&pon->spmi->dev, "Unable to config pull-up\n");
+
+	return rc;
+}
+
+static int __devinit
+qpnp_config_reset(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
+{
+	int rc;
+	u8 i;
+	u16 s1_timer_addr, s2_cntl_addr, s2_timer_addr;
+
+	switch (cfg->pon_type) {
+	case PON_KPDPWR:
+		s1_timer_addr = QPNP_PON_KPDPWR_S1_TIMER(pon->base);
+		s2_timer_addr = QPNP_PON_KPDPWR_S2_TIMER(pon->base);
+		s2_cntl_addr = QPNP_PON_KPDPWR_S2_CNTL(pon->base);
+		break;
+	case PON_RESIN:
+		s1_timer_addr = QPNP_PON_RESIN_S1_TIMER(pon->base);
+		s2_timer_addr = QPNP_PON_RESIN_S2_TIMER(pon->base);
+		s2_cntl_addr = QPNP_PON_RESIN_S2_CNTL(pon->base);
+		break;
+	default:
+		return -EINVAL;
+	}
+	/* disable S2 reset */
+	rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+				QPNP_PON_S2_CNTL_EN, 0);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+		return rc;
+	}
+
+	usleep(100);
+
+	/* configure s1 timer, s2 timer and reset type */
+	for (i = 0; i < PON_S1_COUNT_MAX + 1; i++) {
+		if (cfg->s1_timer <= s1_delay[i])
+			break;
+	}
+	rc = qpnp_pon_masked_write(pon, s1_timer_addr,
+				QPNP_PON_S1_TIMER_MASK, i);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Unable to configure S1 timer\n");
+		return rc;
+	}
+
+	i = 0;
+	if (cfg->s2_timer) {
+		i = cfg->s2_timer / 10;
+		i = ilog2(i + 1);
+	}
+
+	rc = qpnp_pon_masked_write(pon, s2_timer_addr,
+				QPNP_PON_S2_TIMER_MASK, i);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Unable to configure S2 timer\n");
+		return rc;
+	}
+
+	rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+				QPNP_PON_S2_CNTL_TYPE_MASK, (u8)cfg->s2_type);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Unable to configure S2 reset type\n");
+		return rc;
+	}
+
+	/* enable S2 reset */
+	rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+				QPNP_PON_S2_CNTL_EN, QPNP_PON_S2_CNTL_EN);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+		return rc;
+	}
+
+	return 0;
+}
+
+static int __devinit
+qpnp_pon_request_irqs(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
 {
 	int rc = 0;
-	u32 pullup, delay;
-	u8 pon_cntl;
 
-	pon->key_status_irq = spmi_get_irq_byname(pon->spmi,
-						NULL, "power-key");
-	if (pon->key_status_irq < 0) {
-		dev_err(&pon->spmi->dev, "Unable to get pon key irq\n");
-		return -ENXIO;
-	}
-
-	rc = of_property_read_u32(pon->spmi->dev.of_node,
-					"qcom,pon-key-dbc-delay", &delay);
-	if (rc) {
-		delay = (delay << 6) / USEC_PER_SEC;
-		delay = ilog2(delay);
-
-		rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
-				QPNP_PON_DBC_CTL(pon->base), &pon_cntl, 1);
-		if (rc) {
-			dev_err(&pon->spmi->dev, "spmi read addr=%x failed\n",
-						QPNP_PON_DBC_CTL(pon->base));
-			return rc;
-		}
-		pon_cntl &= ~QPNP_PON_CNTL_TRIG_DELAY_MASK;
-		pon_cntl |= (delay & QPNP_PON_CNTL_TRIG_DELAY_MASK);
-		rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
-				QPNP_PON_DBC_CTL(pon->base), &pon_cntl, 1);
-		if (rc) {
-			dev_err(&pon->spmi->dev, "spmi write addre=%x failed\n",
-						QPNP_PON_DBC_CTL(pon->base));
-			return rc;
-		}
-	}
-
-	rc = of_property_read_u32(pon->spmi->dev.of_node,
-				"qcom,pon-key-pull-up", &pullup);
-	if (!rc) {
-		rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
-				QPNP_PON_PULL_CTL(pon->base), &pon_cntl, 1);
-		if (rc) {
-			dev_err(&pon->spmi->dev, "spmi read addr=%x failed\n",
-						QPNP_PON_PULL_CTL(pon->base));
-			return rc;
-		}
-		if (pullup)
-			pon_cntl |= QPNP_PON_CNTL_PULL_UP;
-		else
-			pon_cntl &= ~QPNP_PON_CNTL_PULL_UP;
-
-		rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
-				QPNP_PON_PULL_CTL(pon->base), &pon_cntl, 1);
-		if (rc) {
-			dev_err(&pon->spmi->dev, "spmi write addr=%x failed\n",
-						QPNP_PON_PULL_CTL(pon->base));
-			return rc;
-		}
-	}
-
-	pon->pon_input = input_allocate_device();
-	if (!pon->pon_input) {
-		dev_err(&pon->spmi->dev, "Can't allocate pon button\n");
-		return -ENOMEM;
-	}
-
-	input_set_capability(pon->pon_input, EV_KEY, KEY_POWER);
-	pon->pon_input->name = "qpnp_pon_key";
-	pon->pon_input->phys = "qpnp_pon_key/input0";
-
-	rc = input_register_device(pon->pon_input);
-	if (rc) {
-		dev_err(&pon->spmi->dev, "Can't register pon key: %d\n", rc);
-		goto free_input_dev;
-	}
-
-	rc = request_any_context_irq(pon->key_status_irq, qpnp_pon_key_irq,
+	switch (cfg->pon_type) {
+	case PON_KPDPWR:
+		rc = devm_request_irq(&pon->spmi->dev, cfg->state_irq,
+							qpnp_kpdpwr_irq,
 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-						"qpnp_pon_key_status", pon);
-	if (rc < 0) {
-		dev_err(&pon->spmi->dev, "Can't request %d IRQ for pon: %d\n",
-						pon->key_status_irq, rc);
-		goto unreg_input_dev;
+						"qpnp_kpdpwr_status", pon);
+		if (rc < 0) {
+			dev_err(&pon->spmi->dev, "Can't request %d IRQ\n",
+							cfg->state_irq);
+			return rc;
+		}
+		if (cfg->support_reset) {
+			rc = devm_request_irq(&pon->spmi->dev, cfg->bark_irq,
+						qpnp_kpdpwr_bark_irq,
+						IRQF_TRIGGER_RISING,
+						"qpnp_kpdpwr_bark", pon);
+			if (rc < 0) {
+				dev_err(&pon->spmi->dev,
+					"Can't request %d IRQ\n",
+						cfg->bark_irq);
+				return rc;
+			}
+		}
+		break;
+	case PON_RESIN:
+		rc = devm_request_irq(&pon->spmi->dev, cfg->state_irq,
+							qpnp_resin_irq,
+				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+						"qpnp_resin_status", pon);
+		if (rc < 0) {
+			dev_err(&pon->spmi->dev, "Can't request %d IRQ\n",
+							cfg->state_irq);
+			return rc;
+		}
+		if (cfg->support_reset) {
+			rc = devm_request_irq(&pon->spmi->dev, cfg->bark_irq,
+						qpnp_resin_bark_irq,
+						IRQF_TRIGGER_RISING,
+						"qpnp_resin_bark", pon);
+			if (rc < 0) {
+				dev_err(&pon->spmi->dev,
+					"Can't request %d IRQ\n",
+						cfg->bark_irq);
+				return rc;
+			}
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int __devinit
+qpnp_pon_config_input(struct qpnp_pon *pon,  struct qpnp_pon_config *cfg)
+{
+	if (!pon->pon_input) {
+		pon->pon_input = input_allocate_device();
+		if (!pon->pon_input) {
+			dev_err(&pon->spmi->dev,
+				"Can't allocate pon input device\n");
+			return -ENOMEM;
+		}
+		pon->pon_input->name = "qpnp_pon";
+		pon->pon_input->phys = "qpnp_pon/input0";
+	}
+
+	input_set_capability(pon->pon_input, EV_KEY, cfg->key_code);
+
+	return 0;
+}
+
+static int __devinit qpnp_pon_config_init(struct qpnp_pon *pon)
+{
+	int rc = 0, i = 0;
+	struct device_node *pp = NULL;
+	struct qpnp_pon_config *cfg;
+
+	/* iterate through the list of pon configs */
+	while ((pp = of_get_next_child(pon->spmi->dev.of_node, pp))) {
+
+		cfg = &pon->pon_cfg[i++];
+
+		rc = of_property_read_u32(pp, "qcom,pon-type", &cfg->pon_type);
+		if (rc) {
+			dev_err(&pon->spmi->dev, "PON type not specified\n");
+			return rc;
+		}
+
+		switch (cfg->pon_type) {
+		case PON_KPDPWR:
+			cfg->state_irq = spmi_get_irq_byname(pon->spmi,
+							NULL, "kpdpwr");
+			if (cfg->state_irq < 0) {
+				dev_err(&pon->spmi->dev,
+					"Unable to get kpdpwr irq\n");
+				return cfg->state_irq;
+			}
+
+			rc = of_property_read_u32(pp, "qcom,support-reset",
+							&cfg->support_reset);
+			if (rc && rc != -EINVAL) {
+				dev_err(&pon->spmi->dev,
+					"Unable to read 'support-reset'\n");
+				return rc;
+			}
+
+			if (cfg->support_reset) {
+				cfg->bark_irq = spmi_get_irq_byname(pon->spmi,
+							NULL, "kpdpwr-bark");
+				if (cfg->bark_irq < 0) {
+					dev_err(&pon->spmi->dev,
+					"Unable to get kpdpwr-bark irq\n");
+					return cfg->bark_irq;
+				}
+			}
+			break;
+		case PON_RESIN:
+			cfg->state_irq = spmi_get_irq_byname(pon->spmi,
+							NULL, "resin");
+			if (cfg->state_irq < 0) {
+				dev_err(&pon->spmi->dev,
+					"Unable to get resin irq\n");
+				return cfg->bark_irq;
+			}
+
+			rc = of_property_read_u32(pp, "qcom,support-reset",
+							&cfg->support_reset);
+			if (rc && rc != -EINVAL) {
+				dev_err(&pon->spmi->dev,
+					"Unable to read 'support-reset'\n");
+				return rc;
+			}
+
+			if (cfg->support_reset) {
+				cfg->bark_irq = spmi_get_irq_byname(pon->spmi,
+							NULL, "resin-bark");
+				if (cfg->bark_irq < 0) {
+					dev_err(&pon->spmi->dev,
+					"Unable to get resin-bark irq\n");
+					return cfg->bark_irq;
+				}
+			}
+			break;
+		default:
+			dev_err(&pon->spmi->dev, "PON RESET %d not supported",
+								cfg->pon_type);
+			return -EINVAL;
+		}
+
+		if (cfg->support_reset) {
+			/*
+			 * Get the reset parameters (bark debounce time and
+			 * reset debounce time) for the reset line.
+			 */
+			rc = of_property_read_u32(pp, "qcom,s1-timer",
+							&cfg->s1_timer);
+			if (rc) {
+				dev_err(&pon->spmi->dev,
+					"Unable to read s1-timer\n");
+				return rc;
+			}
+			if (cfg->s1_timer > QPNP_PON_S1_TIMER_MAX) {
+				dev_err(&pon->spmi->dev,
+					"Incorrect S1 debounce time\n");
+				return -EINVAL;
+			}
+			rc = of_property_read_u32(pp, "qcom,s2-timer",
+							&cfg->s2_timer);
+			if (rc) {
+				dev_err(&pon->spmi->dev,
+					"Unable to read s2-timer\n");
+				return rc;
+			}
+			if (cfg->s2_timer > QPNP_PON_S2_TIMER_MAX) {
+				dev_err(&pon->spmi->dev,
+					"Incorrect S2 debounce time\n");
+				return -EINVAL;
+			}
+			rc = of_property_read_u32(pp, "qcom,s2-type",
+							&cfg->s2_type);
+			if (rc) {
+				dev_err(&pon->spmi->dev,
+					"Unable to read s2-type\n");
+				return rc;
+			}
+			if (cfg->s2_type > QPNP_PON_RESET_TYPE_MAX) {
+				dev_err(&pon->spmi->dev,
+					"Incorrect reset type specified\n");
+				return -EINVAL;
+			}
+		}
+		/*
+		 * Get the standard-key parameters. This might not be
+		 * specified if there is no key mapping on the reset line.
+		 */
+		rc = of_property_read_u32(pp, "linux,code", &cfg->key_code);
+		if (rc && rc == -EINVAL) {
+			dev_err(&pon->spmi->dev,
+				"Unable to read key-code\n");
+			return rc;
+		}
+		/* Register key configuration */
+		if (cfg->key_code) {
+			rc = qpnp_pon_config_input(pon, cfg);
+			if (rc < 0)
+				return rc;
+		}
+		/* get the pull-up configuration */
+		rc = of_property_read_u32(pp, "qcom,pull-up", &cfg->pull_up);
+		if (rc && rc != -EINVAL) {
+			dev_err(&pon->spmi->dev, "Unable to read pull-up\n");
+			return rc;
+		}
+	}
+
+	/* register the input device */
+	if (pon->pon_input) {
+		rc = input_register_device(pon->pon_input);
+		if (rc) {
+			dev_err(&pon->spmi->dev,
+				"Can't register pon key: %d\n", rc);
+			goto free_input_dev;
+		}
+	}
+
+	for (i = 0; i < pon->num_pon_config; i++) {
+		cfg = &pon->pon_cfg[i];
+		/* Configure the pull-up */
+		rc = qpnp_config_pull(pon, cfg);
+		if (rc) {
+			dev_err(&pon->spmi->dev, "Unable to config pull-up\n");
+			goto unreg_input_dev;
+		}
+		/* Configure the reset-configuration */
+		if (cfg->support_reset) {
+			rc = qpnp_config_reset(pon, cfg);
+			if (rc) {
+				dev_err(&pon->spmi->dev,
+					"Unable to config pon reset\n");
+				goto unreg_input_dev;
+			}
+		}
+		rc = qpnp_pon_request_irqs(pon, cfg);
+		if (rc) {
+			dev_err(&pon->spmi->dev, "Unable to request-irq's\n");
+			goto unreg_input_dev;
+		}
 	}
 
 	device_init_wakeup(&pon->spmi->dev, 1);
-	enable_irq_wake(pon->key_status_irq);
 
 	return rc;
 
 unreg_input_dev:
-	input_unregister_device(pon->pon_input);
+	if (pon->pon_input)
+		input_unregister_device(pon->pon_input);
 free_input_dev:
-	input_free_device(pon->pon_input);
+	if (pon->pon_input)
+		input_free_device(pon->pon_input);
 	return rc;
 }
 
@@ -158,7 +652,8 @@
 {
 	struct qpnp_pon *pon;
 	struct resource *pon_resource;
-	u32 pon_key_enable = 0;
+	struct device_node *itr = NULL;
+	u32 delay = 0;
 	int rc = 0;
 
 	pon = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_pon),
@@ -170,6 +665,20 @@
 
 	pon->spmi = spmi;
 
+	/* get the total number of pon configurations */
+	while ((itr = of_get_next_child(spmi->dev.of_node, itr)))
+		pon->num_pon_config++;
+
+	if (!pon->num_pon_config) {
+		/* No PON config., do not register the driver */
+		dev_err(&spmi->dev, "No PON config. specified\n");
+		return -EINVAL;
+	}
+
+	pon->pon_cfg = devm_kzalloc(&spmi->dev,
+			sizeof(struct qpnp_pon_config) * pon->num_pon_config,
+								GFP_KERNEL);
+
 	pon_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
 	if (!pon_resource) {
 		dev_err(&spmi->dev, "Unable to get PON base address\n");
@@ -177,36 +686,45 @@
 	}
 	pon->base = pon_resource->start;
 
-	dev_set_drvdata(&spmi->dev, pon);
-
-	/* pon-key-enable property must be set to register pon key */
-	rc = of_property_read_u32(spmi->dev.of_node, "qcom,pon-key-enable",
-							&pon_key_enable);
+	rc = of_property_read_u32(pon->spmi->dev.of_node,
+				"qcom,pon-dbc-delay", &delay);
 	if (rc && rc != -EINVAL) {
-		dev_err(&spmi->dev,
-			"Error reading 'pon-key-enable' property (%d)", rc);
+		dev_err(&spmi->dev, "Unable to read debounce delay\n");
 		return rc;
-	}
-
-	if (pon_key_enable) {
-		rc = qpnp_pon_key_init(pon);
-		if (rc < 0) {
-			dev_err(&spmi->dev, "Failed to register pon-key\n");
+	} else {
+		delay = (delay << 6) / USEC_PER_SEC;
+		delay = ilog2(delay);
+		rc = qpnp_pon_masked_write(pon, QPNP_PON_DBC_CTL(pon->base),
+						QPNP_PON_DBC_DELAY_MASK, delay);
+		if (rc) {
+			dev_err(&spmi->dev, "Unable to set PON debounce\n");
 			return rc;
 		}
 	}
 
-	return 0;
+	dev_set_drvdata(&spmi->dev, pon);
+
+	INIT_DELAYED_WORK(&pon->bark_work, bark_work_func);
+
+	/* register the PON configurations */
+	rc = qpnp_pon_config_init(pon);
+	if (rc) {
+		dev_err(&spmi->dev,
+			"Unable to intialize PON configurations\n");
+		return rc;
+	}
+
+	return rc;
 }
 
 static int qpnp_pon_remove(struct spmi_device *spmi)
 {
 	struct qpnp_pon *pon = dev_get_drvdata(&spmi->dev);
 
-	if (pon->pon_input) {
-		free_irq(pon->key_status_irq, pon);
+	cancel_delayed_work_sync(&pon->bark_work);
+
+	if (pon->pon_input)
 		input_unregister_device(pon->pon_input);
-	}
 
 	return 0;
 }
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index 708d658..6f9af363 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -1,4 +1,5 @@
 /* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -27,6 +28,8 @@
 #include <linux/qpnp/pwm.h>
 
 #define QPNP_LPG_DRIVER_NAME	"qcom,qpnp-pwm"
+#define QPNP_LPG_CHANNEL_BASE	"qpnp-lpg-channel-base"
+#define QPNP_LPG_LUT_BASE	"qpnp-lpg-lut-base"
 
 /* LPG Control for LPG_PATTERN_CONFIG */
 #define QPNP_RAMP_DIRECTION_SHIFT	4
@@ -207,26 +210,19 @@
 
 static RADIX_TREE(lpg_dev_tree, GFP_KERNEL);
 
-struct qpnp_lut_default_config {
-	u32		*duty_pct_list;
-	int		size;
-	int		start_idx;
-};
-
 struct qpnp_lut_config {
-	struct qpnp_lut_default_config def_config;
-	u8		*duty_pct_list;
-	int		list_size;
-	int		lo_index;
-	int		hi_index;
-	int		lut_pause_hi_cnt;
-	int		lut_pause_lo_cnt;
-	int		ramp_step_ms;
-	bool		ramp_direction;
-	bool		pattern_repeat;
-	bool		ramp_toggle;
-	bool		enable_pause_hi;
-	bool		enable_pause_lo;
+	u8	*duty_pct_list;
+	int	list_len;
+	int	lo_index;
+	int	hi_index;
+	int	lut_pause_hi_cnt;
+	int	lut_pause_lo_cnt;
+	int	ramp_step_ms;
+	bool	ramp_direction;
+	bool	pattern_repeat;
+	bool	ramp_toggle;
+	bool	enable_pause_hi;
+	bool	enable_pause_lo;
 };
 
 struct qpnp_lpg_config {
@@ -234,8 +230,6 @@
 	u16			base_addr;
 	u16			lut_base_addr;
 	u16			lut_size;
-	bool			bypass_lut;
-	bool			lpg_configured;
 };
 
 struct qpnp_pwm_config {
@@ -304,6 +298,8 @@
 
 #define QPNP_ENABLE_LUT_CONTROL(p_val)	qpnp_set_control(p_val, 1, 1, 1, 0, 1)
 #define QPNP_ENABLE_PWM_CONTROL(p_val)	qpnp_set_control(p_val, 1, 1, 0, 1, 0)
+#define QPNP_IS_PWM_CONFIG_SELECTED(val) (val & QPNP_PWM_SRC_SELECT_MASK)
+
 
 static inline void qpnp_convert_to_lut_flags(int *flags,
 				struct qpnp_lut_config *l_config)
@@ -316,10 +312,10 @@
 }
 
 static inline void qpnp_set_lut_params(struct lut_params *l_params,
-				struct qpnp_lut_config *l_config)
+		struct qpnp_lut_config *l_config, int s_idx, int size)
 {
-	l_params->start_idx = l_config->def_config.start_idx;
-	l_params->idx_len = l_config->def_config.size;
+	l_params->start_idx = s_idx;
+	l_params->idx_len = size;
 	l_params->lut_pause_hi = l_config->lut_pause_hi_cnt;
 	l_params->lut_pause_lo = l_config->lut_pause_lo_cnt;
 	l_params->ramp_step_ms = l_config->ramp_step_ms;
@@ -442,7 +438,7 @@
 	struct qpnp_lut_config	*lut = &chip->lpg_config.lut_config;
 	int			i, pwm_size, rc = 0;
 	int			burst_size = SPMI_MAX_BUF_LEN;
-	int			list_len = lut->list_size << 1;
+	int			list_len = lut->list_len << 1;
 	int			offset = lut->lo_index << 2;
 
 	pwm_size = QPNP_GET_PWM_SIZE(
@@ -451,15 +447,15 @@
 
 	max_pwm_value = (1 << pwm_size) - 1;
 
-	if (unlikely(lut->list_size != (lut->hi_index - lut->lo_index + 1))) {
+	if (unlikely(lut->list_len != (lut->hi_index - lut->lo_index + 1))) {
 		pr_err("LUT internal Data structure corruption detected\n");
-		pr_err("LUT list size: %d\n", lut->list_size);
+		pr_err("LUT list size: %d\n", lut->list_len);
 		pr_err("However, index size is: %d\n",
 				(lut->hi_index - lut->lo_index + 1));
 		return -EINVAL;
 	}
 
-	for (i = 0; i <= lut->list_size; i++) {
+	for (i = 0; i <= lut->list_len; i++) {
 		if (raw_value)
 			pwm_value = duty_pct[i];
 		else
@@ -597,7 +593,7 @@
 		lpg_config->base_addr, QPNP_LPG_PWM_TYPE_CONFIG, 1, chip);
 }
 
-static int qpnp_pwm_configure_control(struct pwm_device *pwm)
+static int qpnp_configure_pwm_control(struct pwm_device *pwm)
 {
 	struct qpnp_lpg_config	*lpg_config = &pwm->chip->lpg_config;
 	struct qpnp_lpg_chip	*chip = pwm->chip;
@@ -615,7 +611,7 @@
 
 }
 
-static int qpnp_lpg_configure_control(struct pwm_device *pwm)
+static int qpnp_configure_lpg_control(struct pwm_device *pwm)
 {
 	struct qpnp_lpg_config	*lpg_config = &pwm->chip->lpg_config;
 	struct qpnp_lpg_chip	*chip = pwm->chip;
@@ -789,7 +785,7 @@
 		pr_err("Failed to configure LUT pattern");
 		return rc;
 	}
-	rc = qpnp_lpg_configure_control(pwm);
+	rc = qpnp_configure_lpg_control(pwm);
 	if (rc) {
 		pr_err("Failed to configure pause registers");
 		return rc;
@@ -829,7 +825,7 @@
 		lpg_config->base_addr, QPNP_RAMP_CONTROL, 1, chip);
 }
 
-static int qpnp_lpg_disable_lut(struct pwm_device *pwm)
+static int qpnp_disable_lut(struct pwm_device *pwm)
 {
 	struct qpnp_lpg_config	*lpg_config = &pwm->chip->lpg_config;
 	struct qpnp_lpg_chip	*chip = pwm->chip;
@@ -863,7 +859,7 @@
 		lpg_config->base_addr, QPNP_RAMP_CONTROL, 1, chip);
 }
 
-static int qpnp_lpg_disable_pwm(struct pwm_device *pwm)
+static int qpnp_disable_pwm(struct pwm_device *pwm)
 {
 	struct qpnp_lpg_config	*lpg_config = &pwm->chip->lpg_config;
 	struct qpnp_lpg_chip	*chip = pwm->chip;
@@ -914,15 +910,13 @@
 		return rc;
 	}
 
-	rc = qpnp_pwm_configure_control(pwm);
+	rc = qpnp_configure_pwm_control(pwm);
 	if (rc) {
 		pr_err("Could not update PWM control for");
 		pr_err("channel %d rc=%d\n", pwm_config->channel_id, rc);
 		return rc;
 	}
 
-	pwm->chip->lpg_config.lpg_configured = 1;
-
 	pr_debug("duty/period=%u/%u usec: pwm_value=%d (of %d)\n",
 		 (unsigned)duty_us, (unsigned)period_us,
 		 pwm_config->pwm_value, 1 << period->pwm_size);
@@ -935,8 +929,6 @@
 {
 	struct qpnp_lpg_config		*lpg_config;
 	struct qpnp_lut_config		*lut_config;
-	struct qpnp_lut_default_config  *def_lut_config =
-					&lut_config->def_config;
 	struct pwm_period_config	*period;
 	struct qpnp_pwm_config		*pwm_config;
 	int				start_idx = lut_params.start_idx;
@@ -948,23 +940,6 @@
 	pwm_config = &pwm->pwm_config;
 	lpg_config = &pwm->chip->lpg_config;
 	lut_config = &lpg_config->lut_config;
-	def_lut_config = &lut_config->def_config;
-
-	if ((start_idx + len) > lpg_config->lut_size) {
-		pr_err("Exceed LUT limit\n");
-		return -EINVAL;
-	}
-	if ((unsigned)period_us > PM_PWM_PERIOD_MAX ||
-		(unsigned)period_us < PM_PWM_PERIOD_MIN) {
-		pr_err("Period out of range\n");
-		return -EINVAL;
-	}
-
-	if (!pwm_config->in_use) {
-		pr_err("channel_id: %d: stale handle?\n",
-				pwm_config->channel_id);
-		return -EINVAL;
-	}
 
 	period = &pwm_config->period;
 
@@ -981,37 +956,10 @@
 	if (flags & PM_PWM_LUT_USE_RAW_VALUE)
 		raw_lut = 1;
 
-	lut_config->list_size = len;
+	lut_config->list_len = len;
 	lut_config->lo_index = start_idx;
 	lut_config->hi_index = start_idx + len - 1;
 
-	/*
-	 * LUT may not be specified in device tree by default.
-	 * This is the first time user is configuring it.
-	 */
-	if (lpg_config->bypass_lut) {
-		def_lut_config->duty_pct_list = kzalloc(sizeof(u32) *
-							len, GFP_KERNEL);
-		if (!def_lut_config->duty_pct_list) {
-			pr_err("kzalloc failed on def_duty_pct_list\n");
-			return -ENOMEM;
-		}
-
-		lut_config->duty_pct_list = kzalloc(lpg_config->lut_size *
-						sizeof(u16), GFP_KERNEL);
-		if (!lut_config->duty_pct_list) {
-			pr_err("kzalloc failed on duty_pct_list\n");
-			kfree(def_lut_config->duty_pct_list);
-			return -ENOMEM;
-		}
-
-		def_lut_config->size = len;
-		def_lut_config->start_idx = start_idx;
-		memcpy(def_lut_config->duty_pct_list, duty_pct, len);
-
-		lpg_config->bypass_lut = 0;
-	}
-
 	rc = qpnp_lpg_change_table(pwm, duty_pct, raw_lut);
 	if (rc) {
 		pr_err("qpnp_lpg_change_table: rc=%d\n", rc);
@@ -1041,12 +989,28 @@
 	lut_config->ramp_toggle	    = !!(flags & PM_PWM_LUT_REVERSE);
 	lut_config->enable_pause_hi = !!(flags & PM_PWM_LUT_PAUSE_HI_EN);
 	lut_config->enable_pause_lo = !!(flags & PM_PWM_LUT_PAUSE_LO_EN);
-	lpg_config->bypass_lut = 0;
 
 	rc = qpnp_lpg_change_lut(pwm);
 
-	if (!rc)
-		lpg_config->lpg_configured = 1;
+	return rc;
+}
+
+static int _pwm_enable(struct pwm_device *pwm)
+{
+	int rc;
+	struct qpnp_lpg_chip *chip;
+
+	chip = pwm->chip;
+
+	mutex_lock(&pwm->chip->lpg_mutex);
+
+	if (QPNP_IS_PWM_CONFIG_SELECTED(
+		chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL]))
+		rc = qpnp_lpg_enable_pwm(pwm);
+	else
+		rc = qpnp_lpg_enable_lut(pwm);
+
+	mutex_unlock(&pwm->chip->lpg_mutex);
 
 	return rc;
 }
@@ -1108,11 +1072,10 @@
 	pwm_config = &pwm->pwm_config;
 
 	if (pwm_config->in_use) {
-		qpnp_lpg_disable_pwm(pwm);
-		qpnp_lpg_disable_lut(pwm);
+		qpnp_disable_pwm(pwm);
+		qpnp_disable_lut(pwm);
 		pwm_config->in_use = 0;
 		pwm_config->lable = NULL;
-		pwm->chip->lpg_config.lpg_configured = 0;
 	}
 
 	mutex_unlock(&pwm->chip->lpg_mutex);
@@ -1155,43 +1118,20 @@
 int pwm_enable(struct pwm_device *pwm)
 {
 	struct qpnp_pwm_config	*p_config;
-	struct qpnp_lpg_chip	*chip;
-	int			rc = 0;
 
 	if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
 		pr_err("Invalid pwm handle or no pwm_chip\n");
 		return -EINVAL;
 	}
 
-	mutex_lock(&pwm->chip->lpg_mutex);
-
-	chip = pwm->chip;
 	p_config = &pwm->pwm_config;
 
 	if (!p_config->in_use) {
 		pr_err("channel_id: %d: stale handle?\n", p_config->channel_id);
-		rc = -EINVAL;
-		goto out_unlock;
+		return -EINVAL;
 	}
 
-	if (!pwm->chip->lpg_config.lpg_configured) {
-		pr_err("Request received to enable PWM for channel Id: %d\n",
-							p_config->channel_id);
-		pr_err("However, PWM isn't configured\n");
-		pr_err("falling back to defaultconfiguration\n");
-		rc = _pwm_config(pwm, p_config->pwm_duty,
-					p_config->pwm_period);
-		if (rc) {
-			pr_err("Could not apply default PWM config\n");
-			goto out_unlock;
-		}
-	}
-
-	rc = qpnp_lpg_enable_pwm(pwm);
-
-out_unlock:
-	mutex_unlock(&pwm->chip->lpg_mutex);
-	return rc;
+	return _pwm_enable(pwm);
 }
 EXPORT_SYMBOL_GPL(pwm_enable);
 
@@ -1215,21 +1155,50 @@
 	pwm_config = &pwm->pwm_config;
 
 	if (pwm_config->in_use) {
-		if (!pwm->chip->lpg_config.lpg_configured) {
-			pr_err("Request received to disable PWM for\n");
-			pr_err("channel Id: %d\n", pwm_config->channel_id);
-			pr_err("However PWM is not configured by any means\n");
-			goto out_unlock;
-		}
-		qpnp_lpg_disable_pwm(pwm);
+		if (QPNP_IS_PWM_CONFIG_SELECTED(
+			chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL]))
+			qpnp_disable_pwm(pwm);
+		else
+			qpnp_disable_lut(pwm);
 	}
 
-out_unlock:
 	mutex_unlock(&pwm->chip->lpg_mutex);
 }
 EXPORT_SYMBOL_GPL(pwm_disable);
 
 /**
+ * pwm_change_mode - Change the PWM mode configuration
+ * @pwm: the PWM device
+ * @mode: Mode selection value
+ */
+int pwm_change_mode(struct pwm_device *pwm, enum pm_pwm_mode mode)
+{
+	int rc;
+
+	if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
+		pr_err("Invalid pwm handle or no pwm_chip\n");
+		return -EINVAL;
+	}
+
+	if (mode < PM_PWM_MODE_PWM || mode > PM_PWM_MODE_LPG) {
+		pr_err("Invalid mode value\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&pwm->chip->lpg_mutex);
+
+	if (mode)
+		rc = qpnp_configure_lpg_control(pwm);
+	else
+		rc = qpnp_configure_pwm_control(pwm);
+
+	mutex_unlock(&pwm->chip->lpg_mutex);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(pwm_change_mode);
+
+/**
  * pwm_config_period - change PWM period
  *
  * @pwm: the PWM device
@@ -1356,11 +1325,29 @@
 	if (pwm->chip == NULL)
 		return -ENODEV;
 
+	if (!pwm->pwm_config.in_use) {
+		pr_err("channel_id: %d: stale handle?\n",
+				pwm->pwm_config.channel_id);
+		return -EINVAL;
+	}
+
 	if (duty_pct == NULL && !(lut_params.flags & PM_PWM_LUT_NO_TABLE)) {
 		pr_err("Invalid duty_pct with flag\n");
 		return -EINVAL;
 	}
 
+	if ((lut_params.start_idx + lut_params.idx_len) >
+				pwm->chip->lpg_config.lut_size) {
+		pr_err("Exceed LUT limit\n");
+		return -EINVAL;
+	}
+
+	if ((unsigned)period_us > PM_PWM_PERIOD_MAX ||
+		(unsigned)period_us < PM_PWM_PERIOD_MIN) {
+		pr_err("Period out of range\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&pwm->chip->lpg_mutex);
 
 	rc = _pwm_lut_config(pwm, period_us, duty_pct, lut_params);
@@ -1371,87 +1358,136 @@
 }
 EXPORT_SYMBOL_GPL(pwm_lut_config);
 
-/**
- * pwm_lut_enable - control a PWM device to start/stop LUT ramp
- * @pwm: the PWM device
- * @start: to start (1), or stop (0)
- */
-int pwm_lut_enable(struct pwm_device *pwm, int start)
+static int qpnp_parse_pwm_dt_config(struct device_node *of_pwm_node,
+		struct device_node *of_parent, struct qpnp_lpg_chip *chip)
 {
-	struct qpnp_lpg_config	*lpg_config;
-	struct qpnp_pwm_config	*p_config;
-	struct lut_params	lut_params;
-	int			rc = 0;
+	int rc, period;
+	struct pwm_device *pwm_dev = &chip->pwm_dev;
 
-	if (pwm == NULL || IS_ERR(pwm)) {
-		pr_err("Invalid pwm handle\n");
+	rc = of_property_read_u32(of_parent, "qcom,period", (u32 *)&period);
+	if (rc) {
+		pr_err("node is missing PWM Period prop");
+		return rc;
+	}
+
+	rc = of_property_read_u32(of_pwm_node, "qcom,duty",
+				&pwm_dev->pwm_config.pwm_duty);
+	if (rc) {
+		pr_err("node is missing PWM Duty prop");
+		return rc;
+	}
+
+	rc = _pwm_config(pwm_dev, pwm_dev->pwm_config.pwm_duty, period);
+
+	return rc;
+}
+
+#define qpnp_check_optional_dt_bindings(func)	\
+do {					\
+	rc = func;			\
+	if (rc && rc != -EINVAL)	\
+		goto out;		\
+	rc = 0;				\
+} while (0);
+
+static int qpnp_parse_lpg_dt_config(struct device_node *of_lpg_node,
+		struct device_node *of_parent, struct qpnp_lpg_chip *chip)
+{
+	int rc, period, list_size, start_idx, *duty_pct_list;
+	struct pwm_device *pwm_dev = &chip->pwm_dev;
+	struct qpnp_lpg_config	*lpg_config = &chip->lpg_config;
+	struct qpnp_lut_config	*lut_config = &lpg_config->lut_config;
+	struct lut_params	lut_params;
+
+	rc = of_property_read_u32(of_parent, "qcom,period", &period);
+	if (rc) {
+		pr_err("node is missing PWM Period prop");
+		return rc;
+	}
+
+	if (!of_get_property(of_lpg_node, "qcom,duty-percents", &list_size)) {
+		pr_err("node is missing duty-pct list");
+		return rc;
+	}
+
+	rc = of_property_read_u32(of_lpg_node, "cell-index", &start_idx);
+	if (rc) {
+		pr_err("Missing start index");
+		return rc;
+	}
+
+	list_size /= sizeof(u32);
+
+	if (list_size + start_idx > lpg_config->lut_size) {
+		pr_err("duty pct list size overflows\n");
 		return -EINVAL;
 	}
 
-	if (pwm->chip == NULL)
-		return -ENODEV;
+	duty_pct_list = kzalloc(sizeof(u32) * list_size, GFP_KERNEL);
 
-	lpg_config = &pwm->chip->lpg_config;
-	p_config = &pwm->pwm_config;
-
-	mutex_lock(&pwm->chip->lpg_mutex);
-
-	if (start) {
-		if (!lpg_config->lpg_configured) {
-			pr_err("Request received to enable LUT for\n");
-			pr_err("LPG channel %d\n", pwm->pwm_config.channel_id);
-			pr_err("But LPG is not configured, falling back to\n");
-			pr_err(" default LUT configuration if available\n");
-
-			if (lpg_config->bypass_lut) {
-				pr_err("No default LUT configuration found\n");
-				pr_err("Use pwm_lut_config() to configure\n");
-				rc = -EINVAL;
-				goto out;
-			}
-
-			qpnp_set_lut_params(&lut_params,
-					&lpg_config->lut_config);
-
-			rc = _pwm_lut_config(pwm, p_config->pwm_period,
-			(int *)lpg_config->lut_config.def_config.duty_pct_list,
-			lut_params);
-			if (rc) {
-				pr_err("Could not set the default LUT conf\n");
-				goto out;
-			}
-		}
-
-		rc = qpnp_lpg_enable_lut(pwm);
-	} else {
-		if (unlikely(!lpg_config->lpg_configured)) {
-			pr_err("LPG isn't configured\n");
-			rc = -EINVAL;
-			goto out;
-		}
-		rc = qpnp_lpg_disable_lut(pwm);
+	if (!duty_pct_list) {
+		pr_err("kzalloc failed on duty_pct_list\n");
+		return -ENOMEM;
 	}
 
+	rc = of_property_read_u32_array(of_lpg_node, "qcom,duty-percents",
+						duty_pct_list, list_size);
+	if (rc) {
+		pr_err("invalid or missing property:\n");
+		pr_err("qcom,duty-pcts-list\n");
+		kfree(duty_pct_list);
+		return rc;
+	}
+
+	/* Read optional properties */
+	qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
+		"qcom,ramp-step-duration", &lut_config->ramp_step_ms));
+	qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
+		"qcom,lpg-lut-pause-hi", &lut_config->lut_pause_hi_cnt));
+	qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
+		"qcom,lpg-lut-pause-lo", &lut_config->lut_pause_lo_cnt));
+	qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
+				"qcom,lpg-lut-ramp-direction",
+				(u32 *)&lut_config->ramp_direction));
+	qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
+				"qcom,lpg-lut-pattern-repeat",
+				(u32 *)&lut_config->pattern_repeat));
+	qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
+				"qcom,lpg-lut-ramp-toggle",
+				(u32 *)&lut_config->ramp_toggle));
+	qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
+				"qcom,lpg-lut-enable-pause-hi",
+				(u32 *)&lut_config->enable_pause_hi));
+	qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
+				"qcom,lpg-lut-enable-pause-lo",
+				(u32 *)&lut_config->enable_pause_lo));
+
+	qpnp_set_lut_params(&lut_params, lut_config, start_idx, list_size);
+
+	_pwm_lut_config(pwm_dev, period, duty_pct_list, lut_params);
+
 out:
-	mutex_unlock(&pwm->chip->lpg_mutex);
+	kfree(duty_pct_list);
 	return rc;
 }
-EXPORT_SYMBOL_GPL(pwm_lut_enable);
 
 /* Fill in lpg device elements based on values found in device tree. */
-static int qpnp_lpg_get_dt_config(struct spmi_device *spmi,
+static int qpnp_parse_dt_config(struct spmi_device *spmi,
 					struct qpnp_lpg_chip *chip)
 {
-	int			rc;
+	int			rc, enable;
+	const char		*lable;
 	struct resource		*res;
+	struct device_node	*node;
+	int found_pwm_subnode = 0;
+	int found_lpg_subnode = 0;
 	struct device_node	*of_node = spmi->dev.of_node;
-	struct qpnp_lpg_config	*lpg_config = &chip->lpg_config;
 	struct pwm_device	*pwm_dev = &chip->pwm_dev;
-	struct qpnp_lut_config	*lut_config = &chip->lpg_config.lut_config;
-	struct qpnp_lut_default_config	*def_lut_config =
-						&lut_config->def_config;
+	struct qpnp_lpg_config	*lpg_config = &chip->lpg_config;
+	struct qpnp_lut_config	*lut_config = &lpg_config->lut_config;
 
-	res = spmi_get_resource(spmi, 0, IORESOURCE_MEM, 0);
+	res = spmi_get_resource_byname(spmi, NULL, IORESOURCE_MEM,
+					QPNP_LPG_CHANNEL_BASE);
 	if (!res) {
 		dev_err(&spmi->dev, "%s: node is missing base address\n",
 			__func__);
@@ -1460,7 +1496,8 @@
 
 	lpg_config->base_addr = res->start;
 
-	res = spmi_get_resource(spmi, 0, IORESOURCE_MEM, 1);
+	res = spmi_get_resource_byname(spmi, NULL, IORESOURCE_MEM,
+						QPNP_LPG_LUT_BASE);
 	if (!res) {
 		dev_err(&spmi->dev, "%s: node is missing LUT base address\n",
 								__func__);
@@ -1471,88 +1508,68 @@
 	/* Each entry of LUT is of 2 bytes */
 	lpg_config->lut_size = resource_size(res) >> 1;
 
+	lut_config->duty_pct_list = kzalloc(lpg_config->lut_size *
+						sizeof(u16), GFP_KERNEL);
+	if (!lut_config->duty_pct_list) {
+		pr_err("can not allocate duty pct list\n");
+		return -ENOMEM;
+	}
 
 	rc = of_property_read_u32(of_node, "qcom,channel-id",
 				&pwm_dev->pwm_config.channel_id);
 	if (rc) {
-		dev_err(&spmi->dev, "%s: node is missing LPG channel id",
+		dev_err(&spmi->dev, "%s: node is missing LPG channel id\n",
 								__func__);
-		return rc;
+		goto out;
 	}
 
-	rc = of_property_read_u32(of_node, "qcom,period",
-				&pwm_dev->pwm_config.pwm_period);
-	if (rc) {
-		dev_err(&spmi->dev, "%s: node is missing PWM Period value",
+	for_each_child_of_node(of_node, node) {
+		rc = of_property_read_string(node, "label", &lable);
+		if (rc) {
+			dev_err(&spmi->dev, "%s: Missing lable property\n",
 								__func__);
-		return rc;
+			goto out;
+		}
+		if (!strncmp(lable, "pwm", 3)) {
+			rc = qpnp_parse_pwm_dt_config(node, of_node, chip);
+			if (rc)
+				goto out;
+			found_pwm_subnode = 1;
+		} else if (!strncmp(lable, "lpg", 3)) {
+			qpnp_parse_lpg_dt_config(node, of_node, chip);
+			if (rc)
+				goto out;
+			found_lpg_subnode = 1;
+		} else {
+			dev_err(&spmi->dev, "%s: Invalid value for lable prop",
+								__func__);
+		}
 	}
 
-	if (!of_get_property(of_node, "qcom,duty-percents",
-						&def_lut_config->size)) {
-		lpg_config->bypass_lut = 1;
-	}
-
-	if (lpg_config->bypass_lut)
+	rc = of_property_read_u32(of_node, "qcom,mode-select", &enable);
+	if (rc)
 		goto read_opt_props;
 
-	rc = of_property_read_u32(of_node, "qcom,start-index",
-					&def_lut_config->start_idx);
-
-	if (rc) {
-		dev_err(&spmi->dev, "Missing start index");
-		return rc;
+	if ((enable == PM_PWM_MODE_PWM && found_pwm_subnode == 0) ||
+		(enable == PM_PWM_MODE_LPG && found_lpg_subnode == 0)) {
+		dev_err(&spmi->dev, "%s: Invalid mode select\n", __func__);
+		rc = -EINVAL;
+		goto out;
 	}
 
-	def_lut_config->size /= sizeof(u32);
-
-	def_lut_config->duty_pct_list = kzalloc(sizeof(u32) *
-					def_lut_config->size, GFP_KERNEL);
-	if (!def_lut_config->duty_pct_list) {
-		dev_err(&spmi->dev, "%s: kzalloc failed on duty_pct_list\n",
-								__func__);
-		return -ENOMEM;
-	}
-
-	rc = of_property_read_u32_array(of_node, "qcom,duty-percents",
-		def_lut_config->duty_pct_list, def_lut_config->size);
-	if (rc) {
-		dev_err(&spmi->dev, "invalid or missing property:\n");
-		dev_err(&spmi->dev, "qcom,duty-pcts-list\n");
-		kfree(def_lut_config->duty_pct_list);
-		return rc;
-	}
-
-	lut_config->duty_pct_list = kzalloc(lpg_config->lut_size * sizeof(u16),
-								GFP_KERNEL);
-	if (!lut_config->duty_pct_list) {
-		dev_err(&spmi->dev, "can not allocate duty pct list\n");
-		kfree(def_lut_config->duty_pct_list);
-		return -ENOMEM;
-	}
+	pwm_change_mode(pwm_dev, enable);
+	_pwm_enable(pwm_dev);
 
 read_opt_props:
 	/* Initialize optional config parameters from DT if provided */
-	of_property_read_u32(of_node, "qcom,duty",
-					&pwm_dev->pwm_config.pwm_duty);
-	of_property_read_u32(of_node, "qcom,ramp-step-duration",
-					&lut_config->ramp_step_ms);
-	of_property_read_u32(of_node, "qcom,lpg-lut-pause-hi",
-					&lut_config->lut_pause_hi_cnt);
-	of_property_read_u32(of_node, "qcom,lpg-lut-pause-lo",
-					&lut_config->lut_pause_lo_cnt);
-	of_property_read_u32(of_node, "qcom,lpg-lut-ramp-direction",
-					(u32 *)&lut_config->ramp_direction);
-	of_property_read_u32(of_node, "qcom,lpg-lut-pattern-repeat",
-					(u32 *)&lut_config->pattern_repeat);
-	of_property_read_u32(of_node, "qcom,lpg-lut-ramp-toggle",
-					(u32 *)&lut_config->ramp_toggle);
-	of_property_read_u32(of_node, "qcom,lpg-lut-enable-pause-hi",
-					(u32 *)&lut_config->enable_pause_hi);
-	of_property_read_u32(of_node, "qcom,lpg-lut-enable-pause-lo",
-					(u32 *)&lut_config->enable_pause_lo);
+	of_property_read_string(node, "qcom,channel-owner",
+				&pwm_dev->pwm_config.lable);
 
 	return 0;
+
+out:
+	kfree(lut_config->duty_pct_list);
+	return rc;
 }
 
 static int __devinit qpnp_pwm_probe(struct spmi_device *spmi)
@@ -1572,7 +1589,7 @@
 	chip->pwm_dev.chip = chip;
 	dev_set_drvdata(&spmi->dev, chip);
 
-	rc = qpnp_lpg_get_dt_config(spmi, chip);
+	rc = qpnp_parse_dt_config(spmi, chip);
 
 	if (rc)
 		goto failed_config;
@@ -1610,7 +1627,6 @@
 	if (chip) {
 		lpg_config = &chip->lpg_config;
 		kfree(lpg_config->lut_config.duty_pct_list);
-		kfree(lpg_config->lut_config.def_config.duty_pct_list);
 		mutex_destroy(&chip->lpg_mutex);
 		kfree(chip);
 	}
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index cf98f68..31b405a 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.c
@@ -1152,7 +1152,6 @@
 	return bam_read_reg(base, P_TIMER(pipe));
 }
 
-#ifdef CONFIG_DEBUG_FS
 /* output the content of BAM-level registers */
 void print_bam_reg(void *virt_addr)
 {
@@ -1399,4 +1398,3 @@
 
 	SPS_INFO("--------------------  end of FIFO  --------------------\n");
 }
-#endif
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 0371f5a..656d1fb 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -461,6 +461,98 @@
 }
 #endif
 
+/* Get the debug info of BAM registers and descriptor FIFOs */
+int sps_get_bam_debug_info(u32 dev, u32 option, u32 para)
+{
+	int res = 0;
+	struct sps_bam *bam;
+	u32 i;
+	u32 num_pipes = 0;
+	void *vir_addr;
+
+	if (dev == 0) {
+		SPS_ERR("sps:%s:device handle should not be 0.\n", __func__);
+		return SPS_ERROR;
+	}
+
+	mutex_lock(&sps->lock);
+	/* Search for the target BAM device */
+	bam = sps_h2bam(dev);
+	if (bam == NULL) {
+		pr_err("sps:Can't find any BAM with handle 0x%x.", dev);
+		mutex_unlock(&sps->lock);
+		return SPS_ERROR;
+	}
+	mutex_unlock(&sps->lock);
+
+	vir_addr = bam->base;
+	num_pipes = bam->props.num_pipes;
+
+	switch (option) {
+	case 1: /* output all registers of this BAM */
+		print_bam_reg(vir_addr);
+		for (i = 0; i < num_pipes; i++)
+			print_bam_pipe_reg(vir_addr, i);
+		break;
+	case 2: /* output BAM-level registers */
+		print_bam_reg(vir_addr);
+		break;
+	case 3: /* output selected BAM-level registers */
+		print_bam_selected_reg(vir_addr);
+		break;
+	case 4: /* output selected registers of all pipes */
+		for (i = 0; i < num_pipes; i++)
+			print_bam_pipe_selected_reg(vir_addr, i);
+		break;
+	case 5: /* output selected registers of selected pipes */
+		for (i = 0; i < num_pipes; i++)
+			if (para & (1UL << i))
+				print_bam_pipe_selected_reg(vir_addr, i);
+		break;
+	case 6: /* output selected registers of typical pipes */
+		print_bam_pipe_selected_reg(vir_addr, 4);
+		print_bam_pipe_selected_reg(vir_addr, 5);
+		break;
+	case 7: /* output desc FIFO of all pipes */
+		for (i = 0; i < num_pipes; i++)
+			print_bam_pipe_desc_fifo(vir_addr, i);
+		break;
+	case 8: /* output desc FIFO of selected pipes */
+		for (i = 0; i < num_pipes; i++)
+			if (para & (1UL << i))
+				print_bam_pipe_desc_fifo(vir_addr, i);
+		break;
+	case 9: /* output desc FIFO of typical pipes */
+		print_bam_pipe_desc_fifo(vir_addr, 4);
+		print_bam_pipe_desc_fifo(vir_addr, 5);
+		break;
+	case 10: /* output selected registers and desc FIFO of all pipes */
+		for (i = 0; i < num_pipes; i++) {
+			print_bam_pipe_selected_reg(vir_addr, i);
+			print_bam_pipe_desc_fifo(vir_addr, i);
+		}
+		break;
+	case 11: /* output selected registers and desc FIFO of selected pipes */
+		for (i = 0; i < num_pipes; i++)
+			if (para & (1UL << i)) {
+				print_bam_pipe_selected_reg(vir_addr, i);
+				print_bam_pipe_desc_fifo(vir_addr, i);
+			}
+		break;
+	case 12: /* output selected registers and desc FIFO of typical pipes */
+		print_bam_pipe_selected_reg(vir_addr, 4);
+		print_bam_pipe_desc_fifo(vir_addr, 4);
+		print_bam_pipe_selected_reg(vir_addr, 5);
+		print_bam_pipe_desc_fifo(vir_addr, 5);
+		break;
+	default:
+		pr_info("sps:no option is chosen yet.");
+	}
+
+	return res;
+}
+EXPORT_SYMBOL(sps_get_bam_debug_info);
+
 /**
  * Initialize SPS device
  *
@@ -1099,6 +1191,49 @@
 EXPORT_SYMBOL(sps_flow_off);
 
 /**
+ * Check if the flags on a descriptor/iovec are valid
+ *
+ * @flags - flags on a descriptor/iovec
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+static int sps_check_iovec_flags(u32 flags)
+{
+	if ((flags & SPS_IOVEC_FLAG_NWD) &&
+		!(flags & (SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_CMD))) {
+		SPS_ERR("sps:NWD is only valid with EOT or CMD.\n");
+		return SPS_ERROR;
+	} else if ((flags & SPS_IOVEC_FLAG_EOT) &&
+		(flags & SPS_IOVEC_FLAG_CMD)) {
+		SPS_ERR("sps:EOT and CMD are not allowed to coexist.\n");
+		return SPS_ERROR;
+	} else if (!(flags & SPS_IOVEC_FLAG_CMD) &&
+		(flags & (SPS_IOVEC_FLAG_LOCK | SPS_IOVEC_FLAG_UNLOCK))) {
+		static char err_msg[] =
+		"pipe lock/unlock flags are only valid with Command Descriptor";
+		SPS_ERR("sps:%s.\n", err_msg);
+		return SPS_ERROR;
+	} else if ((flags & SPS_IOVEC_FLAG_LOCK) &&
+		(flags & SPS_IOVEC_FLAG_UNLOCK)) {
+		static char err_msg[] =
+		"Can't lock and unlock a pipe by the same Command Descriptor";
+		SPS_ERR("sps:%s.\n", err_msg);
+		return SPS_ERROR;
+	} else if ((flags & SPS_IOVEC_FLAG_IMME) &&
+		(flags & SPS_IOVEC_FLAG_CMD)) {
+		SPS_ERR("sps:Immediate and CMD are not allowed to coexist.\n");
+		return SPS_ERROR;
+	} else if ((flags & SPS_IOVEC_FLAG_IMME) &&
+		(flags & SPS_IOVEC_FLAG_NWD)) {
+		SPS_ERR("sps:Immediate and NWD are not allowed to coexist.\n");
+		return SPS_ERROR;
+	}
+
+	return 0;
+}
+
+/**
  * Perform a DMA transfer on an SPS connection end point
  *
  */
@@ -1107,6 +1242,8 @@
 	struct sps_pipe *pipe = h;
 	struct sps_bam *bam;
 	int result;
+	struct sps_iovec *iovec;
+	int i;
 
 	SPS_DBG("sps:%s.", __func__);
 
@@ -1116,6 +1253,34 @@
 	} else if (transfer == NULL) {
 		SPS_ERR("sps:%s:transfer is NULL.\n", __func__);
 		return SPS_ERROR;
+	} else if (transfer->iovec == NULL) {
+		SPS_ERR("sps:%s:iovec list is NULL.\n", __func__);
+		return SPS_ERROR;
+	} else if (transfer->iovec_count == 0) {
+		SPS_ERR("sps:%s:iovec list is empty.\n", __func__);
+		return SPS_ERROR;
+	} else if (transfer->iovec_phys == 0) {
+		SPS_ERR("sps:%s:iovec list address is invalid.\n", __func__);
+		return SPS_ERROR;
+	}
+
+	/* Verify content of IOVECs */
+	iovec = transfer->iovec;
+	for (i = 0; i < transfer->iovec_count; i++) {
+		u32 flags = iovec->flags;
+
+		if (iovec->addr == 0) {
+			SPS_ERR("sps:%s:iovec address is invalid.\n", __func__);
+			return SPS_ERROR;
+		} else if (iovec->size > SPS_IOVEC_MAX_SIZE) {
+			SPS_ERR("sps:%s:iovec size is invalid.\n", __func__);
+			return SPS_ERROR;
+		}
+
+		if (sps_check_iovec_flags(flags))
+			return SPS_ERROR;
+
+		iovec++;
 	}
 
 	bam = sps_bam_lock(pipe);
@@ -1148,33 +1313,8 @@
 		return SPS_ERROR;
 	}
 
-	if ((flags & SPS_IOVEC_FLAG_NWD) &&
-		!(flags & (SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_CMD))) {
-		SPS_ERR("sps:NWD is only valid with EOT or CMD.\n");
+	if (sps_check_iovec_flags(flags))
 		return SPS_ERROR;
-	} else if ((flags & SPS_IOVEC_FLAG_EOT) &&
-		(flags & SPS_IOVEC_FLAG_CMD)) {
-		SPS_ERR("sps:EOT and CMD are not allowed to coexist.\n");
-		return SPS_ERROR;
-	} else if (!(flags & SPS_IOVEC_FLAG_CMD) &&
-		(flags & (SPS_IOVEC_FLAG_LOCK | SPS_IOVEC_FLAG_UNLOCK))) {
-		SPS_ERR("sps:pipe lock and unlock flags are only valid with "
-			"Command Descriptor.\n");
-		return SPS_ERROR;
-	} else if ((flags & SPS_IOVEC_FLAG_LOCK) &&
-		(flags & SPS_IOVEC_FLAG_UNLOCK)) {
-		SPS_ERR("sps:Can't lock and unlock a pipe by the same"
-			"Command Descriptor.\n");
-		return SPS_ERROR;
-	} else if ((flags & SPS_IOVEC_FLAG_IMME) &&
-		(flags & SPS_IOVEC_FLAG_CMD)) {
-		SPS_ERR("sps:Immediate and CMD are not allowed to coexist.\n");
-		return SPS_ERROR;
-	} else if ((flags & SPS_IOVEC_FLAG_IMME) &&
-		(flags & SPS_IOVEC_FLAG_NWD)) {
-		SPS_ERR("sps:Immediate and NWD are not allowed to coexist.\n");
-		return SPS_ERROR;
-	}
 
 	bam = sps_bam_lock(pipe);
 	if (bam == NULL)
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index 5a141ca..43a50bd 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -183,6 +183,7 @@
 #ifdef CONFIG_DEBUG_FS
 /* record debug info for debugfs */
 void sps_debugfs_record(const char *);
+#endif
 
 /* output the content of BAM-level registers */
 void print_bam_reg(void *);
@@ -198,7 +199,6 @@
 
 /* output descriptor FIFO of a pipe */
 void print_bam_pipe_desc_fifo(void *, u32);
-#endif
 
 /**
  * Translate physical to virtual address
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index d3edfa8..b7c73de 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -18,13 +18,14 @@
 #include <linux/io.h>
 #include <linux/stat.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/usb/msm_hsusb.h>
 #include <mach/usb_bam.h>
 #include <mach/sps.h>
 #include <linux/workqueue.h>
 
 #define USB_SUMMING_THRESHOLD 512
-#define CONNECTIONS_NUM		4
+#define CONNECTIONS_NUM	4
 
 static struct sps_bam_props usb_props;
 static struct sps_pipe *sps_pipes[CONNECTIONS_NUM][2];
@@ -43,32 +44,35 @@
 
 struct usb_bam_connect_info {
 	u8 idx;
-	u8 *src_pipe;
-	u8 *dst_pipe;
+	u32 *src_pipe;
+	u32 *dst_pipe;
 	struct usb_bam_wake_event_info peer_event;
 	bool enabled;
 };
 
 static struct usb_bam_connect_info usb_bam_connections[CONNECTIONS_NUM];
+static struct usb_bam_pipe_connect ***msm_usb_bam_connections_info;
+static struct usb_bam_pipe_connect *bam_connection_arr;
+
+static bool device_tree_enabled;
 
 static inline int bam_offset(struct msm_usb_bam_platform_data *pdata)
 {
 	return pdata->usb_active_bam * CONNECTIONS_NUM * 2;
 }
 
-static int connect_pipe(u8 connection_idx, enum usb_bam_pipe_dir pipe_dir,
-						u8 *usb_pipe_idx)
+static int connect_pipe(u8 conn_idx, enum usb_bam_pipe_dir pipe_dir,
+						u32 *usb_pipe_idx)
 {
 	int ret;
-	struct sps_pipe **pipe = &sps_pipes[connection_idx][pipe_dir];
+	struct sps_pipe **pipe = &sps_pipes[conn_idx][pipe_dir];
 	struct sps_connect *connection =
-		&sps_connections[connection_idx][pipe_dir];
+		&sps_connections[conn_idx][pipe_dir];
 	struct msm_usb_bam_platform_data *pdata =
-		(struct msm_usb_bam_platform_data *)
-			(usb_bam_pdev->dev.platform_data);
+		usb_bam_pdev->dev.platform_data;
 	struct usb_bam_pipe_connect *pipe_connection =
-			(struct usb_bam_pipe_connect *)(pdata->connections +
-			 bam_offset(pdata) + (2*connection_idx+pipe_dir));
+		(struct usb_bam_pipe_connect *)(pdata->connections +
+			 bam_offset(pdata) + (2*conn_idx+pipe_dir));
 
 	*pipe = sps_alloc_endpoint();
 	if (*pipe == NULL) {
@@ -105,26 +109,54 @@
 		*usb_pipe_idx = connection->dest_pipe_index;
 	}
 
-	ret = sps_setup_bam2bam_fifo(
-				&data_mem_buf[connection_idx][pipe_dir],
+	if (!device_tree_enabled) {
+		ret = sps_setup_bam2bam_fifo(
+				&data_mem_buf[conn_idx][pipe_dir],
 				pipe_connection->data_fifo_base_offset,
 				pipe_connection->data_fifo_size, 1);
-	if (ret) {
-		pr_err("%s: data fifo setup failure %d\n", __func__, ret);
-		goto fifo_setup_error;
-	}
-	connection->data = data_mem_buf[connection_idx][pipe_dir];
+		if (ret) {
+			pr_err("%s: data fifo setup failure %d\n", __func__,
+				ret);
+			goto fifo_setup_error;
+		}
 
-	ret = sps_setup_bam2bam_fifo(
-				&desc_mem_buf[connection_idx][pipe_dir],
+		ret = sps_setup_bam2bam_fifo(
+				&desc_mem_buf[conn_idx][pipe_dir],
 				pipe_connection->desc_fifo_base_offset,
 				pipe_connection->desc_fifo_size, 1);
-	if (ret) {
-		pr_err("%s: desc. fifo setup failure %d\n", __func__, ret);
-		goto fifo_setup_error;
+		if (ret) {
+			pr_err("%s: desc. fifo setup failure %d\n", __func__,
+				ret);
+			goto fifo_setup_error;
+		}
+	} else {
+		data_mem_buf[conn_idx][pipe_dir].phys_base =
+			pipe_connection->data_fifo_base_offset +
+				pdata->usb_base_address;
+		data_mem_buf[conn_idx][pipe_dir].size =
+			pipe_connection->data_fifo_size;
+		data_mem_buf[conn_idx][pipe_dir].base =
+			ioremap(data_mem_buf[conn_idx][pipe_dir].phys_base,
+				data_mem_buf[conn_idx][pipe_dir].size);
+		memset(data_mem_buf[conn_idx][pipe_dir].base, 0,
+			data_mem_buf[conn_idx][pipe_dir].size);
+
+		desc_mem_buf[conn_idx][pipe_dir].phys_base =
+			pipe_connection->desc_fifo_base_offset +
+				pdata->usb_base_address;
+		desc_mem_buf[conn_idx][pipe_dir].size =
+			pipe_connection->desc_fifo_size;
+		desc_mem_buf[conn_idx][pipe_dir].base =
+			ioremap(desc_mem_buf[conn_idx][pipe_dir].phys_base,
+				desc_mem_buf[conn_idx][pipe_dir].size);
+		memset(desc_mem_buf[conn_idx][pipe_dir].base, 0,
+			desc_mem_buf[conn_idx][pipe_dir].size);
 	}
-	connection->desc = desc_mem_buf[connection_idx][pipe_dir];
+
+	connection->data = data_mem_buf[conn_idx][pipe_dir];
+	connection->desc = desc_mem_buf[conn_idx][pipe_dir];
 	connection->event_thresh = 16;
+	connection->options = SPS_O_AUTO_ENABLE;
 
 	ret = sps_connect(*pipe, connection);
 	if (ret < 0) {
@@ -141,7 +173,22 @@
 	return ret;
 }
 
-int usb_bam_connect(u8 idx, u8 *src_pipe_idx, u8 *dst_pipe_idx)
+
+static int disconnect_pipe(u8 connection_idx, enum usb_bam_pipe_dir pipe_dir,
+						u32 *usb_pipe_idx)
+{
+	struct sps_pipe *pipe = sps_pipes[connection_idx][pipe_dir];
+	struct sps_connect *connection =
+		&sps_connections[connection_idx][pipe_dir];
+
+	sps_disconnect(pipe);
+	sps_free_endpoint(pipe);
+
+	connection->options &= ~SPS_O_AUTO_ENABLE;
+	return 0;
+}
+
+int usb_bam_connect(u8 idx, u32 *src_pipe_idx, u32 *dst_pipe_idx)
 {
 	struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
 	int ret;
@@ -153,7 +200,7 @@
 	}
 
 	if (connection->enabled) {
-		pr_info("%s: connection %d was already established\n",
+		pr_debug("%s: connection %d was already established\n",
 			__func__, idx);
 		return 0;
 	}
@@ -161,19 +208,23 @@
 	connection->dst_pipe = dst_pipe_idx;
 	connection->idx = idx;
 
-	/* open USB -> Peripheral pipe */
-	ret = connect_pipe(connection->idx, USB_TO_PEER_PERIPHERAL,
-					   connection->src_pipe);
-	if (ret) {
-		pr_err("%s: src pipe connection failure\n", __func__);
-		return ret;
+	if (src_pipe_idx) {
+		/* open USB -> Peripheral pipe */
+		ret = connect_pipe(connection->idx, USB_TO_PEER_PERIPHERAL,
+			connection->src_pipe);
+		if (ret) {
+			pr_err("%s: src pipe connection failure\n", __func__);
+			return ret;
+		}
 	}
-	/* open Peripheral -> USB pipe */
-	ret = connect_pipe(connection->idx, PEER_PERIPHERAL_TO_USB,
-				 connection->dst_pipe);
-	if (ret) {
-		pr_err("%s: dst pipe connection failure\n", __func__);
-		return ret;
+	if (dst_pipe_idx) {
+		/* open Peripheral -> USB pipe */
+		ret = connect_pipe(connection->idx, PEER_PERIPHERAL_TO_USB,
+			connection->dst_pipe);
+		if (ret) {
+			pr_err("%s: dst pipe connection failure\n", __func__);
+			return ret;
+		}
 	}
 	connection->enabled = 1;
 
@@ -232,19 +283,259 @@
 	return 0;
 }
 
+int usb_bam_disconnect_pipe(u8 idx)
+{
+	struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
+	int ret;
+
+	if (idx >= CONNECTIONS_NUM) {
+		pr_err("%s: Invalid connection index\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (!connection->enabled) {
+		pr_debug("%s: connection %d isn't enabled\n",
+			__func__, idx);
+		return 0;
+	}
+
+	if (connection->src_pipe) {
+		/* close USB -> Peripheral pipe */
+		ret = disconnect_pipe(connection->idx, USB_TO_PEER_PERIPHERAL,
+						   connection->src_pipe);
+		if (ret) {
+			pr_err("%s: src pipe connection failure\n", __func__);
+			return ret;
+		}
+
+	}
+	if (connection->dst_pipe) {
+		/* close Peripheral -> USB pipe */
+		ret = disconnect_pipe(connection->idx, PEER_PERIPHERAL_TO_USB,
+			connection->dst_pipe);
+		if (ret) {
+			pr_err("%s: dst pipe connection failure\n", __func__);
+			return ret;
+		}
+	}
+
+	connection->src_pipe = 0;
+	connection->dst_pipe = 0;
+	connection->enabled = 0;
+
+	return 0;
+}
+
+static int update_connections_info(struct device_node *node, int bam,
+	int conn_num, int dir)
+{
+	u32 rc;
+	char *key = NULL;
+	uint32_t val = 0;
+
+	struct usb_bam_pipe_connect *pipe_connection;
+
+	pipe_connection = &msm_usb_bam_connections_info[bam][conn_num][dir];
+
+	key = "qcom,src-bam-physical-address";
+	rc = of_property_read_u32(node, key, &val);
+	if (rc)
+		goto err;
+	pipe_connection->src_phy_addr = val;
+
+	key = "qcom,src-bam-pipe-index";
+	rc = of_property_read_u32(node, key, &val);
+	if (rc)
+		goto err;
+	pipe_connection->src_pipe_index = val;
+
+	key = "qcom,dst-bam-physical-address";
+	rc = of_property_read_u32(node, key, &val);
+	if (rc)
+		goto err;
+	pipe_connection->dst_phy_addr = val;
+
+	key = "qcom,dst-bam-pipe-index";
+	rc = of_property_read_u32(node, key, &val);
+	if (rc)
+		goto err;
+	pipe_connection->dst_pipe_index = val;
+
+	key = "qcom,data-fifo-offset";
+	rc = of_property_read_u32(node, key, &val);
+	if (rc)
+		goto err;
+	pipe_connection->data_fifo_base_offset = val;
+
+	key = "qcom,data-fifo-size";
+	rc = of_property_read_u32(node, key, &val);
+	if (rc)
+		goto err;
+	pipe_connection->data_fifo_size = val;
+
+	key = "qcom,descriptor-fifo-offset";
+	rc = of_property_read_u32(node, key, &val);
+	if (rc)
+		goto err;
+	pipe_connection->desc_fifo_base_offset = val;
+
+	key = "qcom,descriptor-fifo-size";
+	rc = of_property_read_u32(node, key, &val);
+	if (rc)
+		goto err;
+	pipe_connection->desc_fifo_size = val;
+
+	return 0;
+
+err:
+	pr_err("%s: Error in name %s key %s\n", __func__,
+		node->full_name, key);
+	return -EFAULT;
+}
+
+static struct msm_usb_bam_platform_data *usb_bam_dt_to_pdata(
+	struct platform_device *pdev)
+{
+	struct msm_usb_bam_platform_data *pdata;
+	struct device_node *node = pdev->dev.of_node;
+	u32 i, j;
+	int conn_num, bam;
+	u8 dir;
+	u8 ncolumns = 2;
+	int bam_amount, rc = 0;
+	u32 pipe_entry = 0;
+	char *key = NULL;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		pr_err("unable to allocate platform data\n");
+		return NULL;
+	}
+
+	rc = of_property_read_u32(node, "qcom,usb-active-bam",
+		&pdata->usb_active_bam);
+	if (rc) {
+		pr_err("Invalid usb active bam property\n");
+		return NULL;
+	}
+
+	rc = of_property_read_u32(node, "qcom,usb-total-bam-num",
+		&pdata->total_bam_num);
+	if (rc) {
+		pr_err("Invalid usb total bam num property\n");
+		return NULL;
+	}
+
+	rc = of_property_read_u32(node, "qcom,usb-bam-num-pipes",
+		&pdata->usb_bam_num_pipes);
+	if (rc) {
+		pr_err("Invalid usb bam num pipes property\n");
+		return NULL;
+	}
+
+	rc = of_property_read_u32(node, "qcom,usb-base-address",
+		&pdata->usb_base_address);
+	if (rc) {
+		pr_err("Invalid usb base address property\n");
+		return NULL;
+	}
+
+	for_each_child_of_node(pdev->dev.of_node, node)
+		pipe_entry++;
+
+	/*
+	 * we need to know the number of connection, so we will know
+	 * how much memory to allocate
+	 */
+	conn_num = pipe_entry / 2;
+	bam_amount = pdata->total_bam_num;
+
+	if (conn_num > 0 && conn_num < pdata->usb_bam_num_pipes) {
+		/* alloc msm_usb_bam_connections_info */
+		bam_connection_arr = devm_kzalloc(&pdev->dev, bam_amount *
+			conn_num * ncolumns *
+			sizeof(struct usb_bam_pipe_connect), GFP_KERNEL);
+
+		if (!bam_connection_arr)
+			goto err;
+
+		msm_usb_bam_connections_info = devm_kzalloc(&pdev->dev,
+			bam_amount * sizeof(struct usb_bam_pipe_connect **),
+			GFP_KERNEL);
+
+		if (!msm_usb_bam_connections_info)
+			goto err;
+
+		for (j = 0; j < bam_amount; j++) {
+			msm_usb_bam_connections_info[j] =
+				devm_kzalloc(&pdev->dev, conn_num *
+				sizeof(struct usb_bam_pipe_connect *),
+				GFP_KERNEL);
+			for (i = 0; i < conn_num; i++)
+				msm_usb_bam_connections_info[j][i] =
+					bam_connection_arr +
+					(j * conn_num * ncolumns) +
+					(i * ncolumns);
+		}
+
+		/* retrieve device tree parameters */
+		for_each_child_of_node(pdev->dev.of_node, node) {
+			const char *str;
+
+			key = "qcom,usb-bam-type";
+			rc = of_property_read_u32(node, key, &bam);
+			if (rc)
+				goto err;
+
+			rc = of_property_read_string(node, "label", &str);
+			if (rc) {
+				pr_err("Cannot read string\n");
+				goto err;
+			}
+
+			if (strstr(str, "usb-to-peri"))
+				dir = USB_TO_PEER_PERIPHERAL;
+			else if (strstr(str, "peri-to-usb"))
+				dir = PEER_PERIPHERAL_TO_USB;
+			else
+				goto err;
+
+			if (!strcmp(str, "usb-to-peri-qdss-dwc3") ||
+				!strcmp(str, "peri-to-usb-qdss-dwc3"))
+					conn_num = 0;
+			else
+				goto err;
+
+			rc = update_connections_info(node, bam, conn_num, dir);
+			if (rc)
+				goto err;
+		}
+
+		pdata->connections = &msm_usb_bam_connections_info[0][0][0];
+
+	} else {
+		goto err;
+	}
+
+	return pdata;
+err:
+	pr_err("%s: failed\n", __func__);
+	return NULL;
+}
+
 static int usb_bam_init(void)
 {
 	u32 h_usb;
 	int ret;
 	void *usb_virt_addr;
 	struct msm_usb_bam_platform_data *pdata =
-		(struct msm_usb_bam_platform_data *)
-			(usb_bam_pdev->dev.platform_data);
+		usb_bam_pdev->dev.platform_data;
 	struct resource *res;
 	int irq;
 
 	res = platform_get_resource(usb_bam_pdev, IORESOURCE_MEM,
-						pdata->usb_active_bam);
+		pdata->usb_active_bam);
 	if (!res) {
 		dev_err(&usb_bam_pdev->dev, "Unable to get memory resource\n");
 		return -ENODEV;
@@ -266,6 +557,7 @@
 	usb_props.virt_size = resource_size(res);
 	usb_props.irq = irq;
 	usb_props.summing_threshold = USB_SUMMING_THRESHOLD;
+	usb_props.event_threshold = 512;
 	usb_props.num_pipes = pdata->usb_bam_num_pipes;
 
 	ret = sps_register_bam_device(&usb_props, &h_usb);
@@ -286,11 +578,10 @@
 usb_bam_show_enable(struct device *dev, struct device_attribute *attr,
 		    char *buf)
 {
-	struct platform_device *pdev = container_of(dev, struct platform_device,
-						    dev);
+	struct platform_device *pdev =
+		container_of(dev, struct platform_device, dev);
 	struct msm_usb_bam_platform_data *pdata =
-		(struct msm_usb_bam_platform_data *)
-			(usb_bam_pdev->dev.platform_data);
+		usb_bam_pdev->dev.platform_data;
 
 	if (!pdev || !pdata)
 		return 0;
@@ -302,11 +593,10 @@
 				     struct device_attribute *attr,
 				     const char *buf, size_t count)
 {
-	struct platform_device *pdev = container_of(dev, struct platform_device,
-						    dev);
+	struct platform_device *pdev = container_of(dev,
+		struct platform_device, dev);
 	struct msm_usb_bam_platform_data *pdata =
-		(struct msm_usb_bam_platform_data *)
-			(usb_bam_pdev->dev.platform_data);
+		usb_bam_pdev->dev.platform_data;
 	char str[10], *pstr;
 	int ret, i;
 
@@ -336,6 +626,7 @@
 static int usb_bam_probe(struct platform_device *pdev)
 {
 	int ret, i;
+	struct msm_usb_bam_platform_data *pdata;
 
 	dev_dbg(&pdev->dev, "usb_bam_probe\n");
 
@@ -345,9 +636,19 @@
 			usb_bam_wake_work);
 	}
 
-	if (!pdev->dev.platform_data) {
+	if (pdev->dev.of_node) {
+		dev_dbg(&pdev->dev, "device tree enabled\n");
+		device_tree_enabled = 1;
+		pdata = usb_bam_dt_to_pdata(pdev);
+		if (!pdata)
+			return -ENOMEM;
+		pdev->dev.platform_data = pdata;
+	} else if (!pdev->dev.platform_data) {
 		dev_err(&pdev->dev, "missing platform_data\n");
 		return -ENODEV;
+	} else {
+		pdata = pdev->dev.platform_data;
+		device_tree_enabled = 0;
 	}
 	usb_bam_pdev = pdev;
 
@@ -365,6 +666,32 @@
 	return ret;
 }
 
+void get_bam2bam_connection_info(u8 conn_idx, enum usb_bam_pipe_dir pipe_dir,
+	u32 *usb_bam_handle, u32 *usb_bam_pipe_idx, u32 *peer_pipe_idx,
+	struct sps_mem_buffer *desc_fifo, struct sps_mem_buffer *data_fifo)
+{
+	struct sps_connect *connection =
+		&sps_connections[conn_idx][pipe_dir];
+
+
+	if (pipe_dir == USB_TO_PEER_PERIPHERAL) {
+		*usb_bam_handle = connection->source;
+		*usb_bam_pipe_idx = connection->src_pipe_index;
+		*peer_pipe_idx = connection->dest_pipe_index;
+	} else {
+		*usb_bam_handle = connection->destination;
+		*usb_bam_pipe_idx = connection->dest_pipe_index;
+		*peer_pipe_idx = connection->src_pipe_index;
+	}
+	if (data_fifo)
+		memcpy(data_fifo, &data_mem_buf[conn_idx][pipe_dir],
+			sizeof(struct sps_mem_buffer));
+	if (desc_fifo)
+		memcpy(desc_fifo, &desc_mem_buf[conn_idx][pipe_dir],
+			sizeof(struct sps_mem_buffer));
+}
+EXPORT_SYMBOL(get_bam2bam_connection_info);
+
 static int usb_bam_remove(struct platform_device *pdev)
 {
 	destroy_workqueue(usb_bam_wq);
@@ -372,10 +699,20 @@
 	return 0;
 }
 
+static const struct of_device_id usb_bam_dt_match[] = {
+	{ .compatible = "qcom,usb-bam-msm",
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, usb_bam_dt_match);
+
 static struct platform_driver usb_bam_driver = {
 	.probe = usb_bam_probe,
 	.remove = usb_bam_remove,
-	.driver = { .name = "usb_bam", },
+	.driver		= {
+		.name	= "usb_bam",
+		.of_match_table = usb_bam_dt_match,
+	},
 };
 
 static int __init init(void)
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 9a55b3b..ceca0e7 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -20,6 +20,7 @@
 #include <linux/mfd/pm8xxx/pm8921-bms.h>
 #include <linux/mfd/pm8xxx/core.h>
 #include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <linux/mfd/pm8xxx/pm8921-charger.h>
 #include <linux/mfd/pm8xxx/ccadc.h>
 #include <linux/power/bq51051b_charger.h>
 #include <linux/interrupt.h>
@@ -28,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
+#include <linux/rtc.h>
 
 #define BMS_CONTROL		0x224
 #define BMS_S1_DELAY		0x225
@@ -50,6 +52,9 @@
 
 #define TEMP_SOC_STORAGE	0x107
 
+#define TEMP_IAVG_STORAGE	0x105
+#define TEMP_IAVG_STORAGE_USE_MASK	0x0F
+
 enum pmic_bms_interrupts {
 	PM8921_BMS_SBI_WRITE_OK,
 	PM8921_BMS_CC_THR,
@@ -68,16 +73,6 @@
 	int		last_good_ocv_uv;
 };
 
-struct pm8921_rbatt_params {
-	uint16_t	ocv_for_rbatt_raw;
-	uint16_t	vsense_for_rbatt_raw;
-	uint16_t	vbatt_for_rbatt_raw;
-
-	int		ocv_for_rbatt_uv;
-	int		vsense_for_rbatt_uv;
-	int		vbatt_for_rbatt_uv;
-};
-
 /**
  * struct pm8921_bms_chip -
  * @bms_output_lock:	lock to prevent concurrent bms reads
@@ -93,8 +88,7 @@
 	struct device		*dev;
 	struct dentry		*dent;
 	unsigned int		r_sense;
-	unsigned int		i_test;
-	unsigned int		v_failure;
+	unsigned int		v_cutoff;
 	unsigned int		fcc;
 	struct single_row_lut	*fcc_temp_lut;
 	struct single_row_lut	*fcc_sf_lut;
@@ -103,6 +97,8 @@
 	struct sf_lut		*rbatt_sf_lut;
 	int			delta_rbatt_mohm;
 	struct work_struct	calib_hkadc_work;
+	struct delayed_work	calib_hkadc_delayed_work;
+	struct mutex		calib_mutex;
 	unsigned int		revision;
 	unsigned int		xoadc_v0625_usb_present;
 	unsigned int		xoadc_v0625_usb_absent;
@@ -120,29 +116,45 @@
 	unsigned int		charging_began;
 	unsigned int		start_percent;
 	unsigned int		end_percent;
+	int			charge_time_us;
+	int			catch_up_time_us;
 	enum battery_type	batt_type;
 	uint16_t		ocv_reading_at_100;
 	int			cc_reading_at_100;
 	int			max_voltage_uv;
 
-	int			batt_temp_suspend;
-	int			soc_rbatt_suspend;
+	int			chg_term_ua;
 	int			default_rbatt_mohm;
 	int			amux_2_trim_delta;
 	uint16_t		prev_last_good_ocv_raw;
 	unsigned int		rconn_mohm;
 	struct mutex		last_ocv_uv_mutex;
 	int			last_ocv_uv;
+	int			pon_ocv_uv;
 	int			last_cc_uah;
-	struct timeval		t;
-	int			last_uuc_uah;
+	unsigned long		tm_sec;
 	int			enable_fcc_learning;
 	int			shutdown_soc;
-	int			timer_uuc_expired;
-	struct delayed_work	uuc_timer_work;
-	int			uuc_uah_iavg_prev;
+	int			shutdown_iavg_ua;
+	struct delayed_work	calculate_soc_delayed_work;
+	struct timespec		t_soc_queried;
+	int			shutdown_soc_valid_limit;
+	int			ignore_shutdown_soc;
+	int			prev_iavg_ua;
+	int			prev_uuc_iavg_ma;
+	int			prev_pc_unusable;
+	int			adjust_soc_low_threshold;
+
+	int			ibat_at_cv_ua;
+	int			soc_at_cv;
+	int			prev_chg_soc;
 };
 
+/*
+ * protects against simultaneous adjustment of ocv based on shutdown soc and
+ * invalidating the shutdown soc
+ */
+static DEFINE_MUTEX(soc_invalidation_mutex);
 static int shutdown_soc_invalid;
 static struct pm8921_bms_chip *the_chip;
 
@@ -158,7 +170,7 @@
 module_param(last_chargecycles, int, 0644);
 module_param(last_charge_increase, int, 0644);
 
-static int last_rbatt = -EINVAL;
+static int calculated_soc = -EINVAL;
 static int last_soc = -EINVAL;
 static int last_real_fcc_mah = -EINVAL;
 static int last_real_fcc_batt_temp = -EINVAL;
@@ -176,7 +188,6 @@
 	.get = param_get_int,
 };
 
-module_param_cb(last_rbatt, &bms_param_ops, &last_rbatt, 0644);
 module_param_cb(last_soc, &bms_param_ops, &last_soc, 0644);
 
 /*
@@ -338,19 +349,13 @@
 
 static int usb_chg_plugged_in(void)
 {
-	union power_supply_propval ret = {0,};
-	static struct power_supply *psy;
+	int val = pm8921_is_usb_chg_plugged_in();
 
-	if (psy == NULL) {
-		psy = power_supply_get_by_name("usb");
-		if (psy == NULL)
-			return 0;
-	}
+	/* treat as if usb is not present in case of error */
+	if (val == -EINVAL)
+		val = 0;
 
-	if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret))
-		return 0;
-
-	return ret.intval;
+	return val;
 }
 
 static int wireless_chg_plugged_in(void)
@@ -495,8 +500,8 @@
 	return div_s64(cc * CC_RESOLUTION_N, CC_RESOLUTION_D);
 }
 
-#define CC_READING_TICKS	55
-#define SLEEP_CLK_HZ		32768
+#define CC_READING_TICKS	56
+#define SLEEP_CLK_HZ		32764
 #define SECONDS_PER_HOUR	3600
 /**
  * ccmicrovolt_to_nvh -
@@ -744,6 +749,82 @@
 	return 0;
 }
 
+/* get ocv given a soc  -- reverse lookup */
+static int interpolate_ocv(struct pm8921_bms_chip *chip,
+				int batt_temp_degc, int pc)
+{
+	int i, ocvrow1, ocvrow2, ocv;
+	int rows, cols;
+	int row1 = 0;
+	int row2 = 0;
+
+	rows = chip->pc_temp_ocv_lut->rows;
+	cols = chip->pc_temp_ocv_lut->cols;
+	if (pc > chip->pc_temp_ocv_lut->percent[0]) {
+		pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
+		row1 = 0;
+		row2 = 0;
+	}
+	if (pc < chip->pc_temp_ocv_lut->percent[rows - 1]) {
+		pr_debug("pc %d less than known pc ranges for sf\n", pc);
+		row1 = rows - 1;
+		row2 = rows - 1;
+	}
+	for (i = 0; i < rows; i++) {
+		if (pc == chip->pc_temp_ocv_lut->percent[i]) {
+			row1 = i;
+			row2 = i;
+			break;
+		}
+		if (pc > chip->pc_temp_ocv_lut->percent[i]) {
+			row1 = i - 1;
+			row2 = i;
+			break;
+		}
+	}
+
+	if (batt_temp_degc < chip->pc_temp_ocv_lut->temp[0])
+		batt_temp_degc = chip->pc_temp_ocv_lut->temp[0];
+	if (batt_temp_degc > chip->pc_temp_ocv_lut->temp[cols - 1])
+		batt_temp_degc = chip->pc_temp_ocv_lut->temp[cols - 1];
+
+	for (i = 0; i < cols; i++)
+		if (batt_temp_degc <= chip->pc_temp_ocv_lut->temp[i])
+			break;
+	if (batt_temp_degc == chip->pc_temp_ocv_lut->temp[i]) {
+		ocv = linear_interpolate(
+				chip->pc_temp_ocv_lut->ocv[row1][i],
+				chip->pc_temp_ocv_lut->percent[row1],
+				chip->pc_temp_ocv_lut->ocv[row2][i],
+				chip->pc_temp_ocv_lut->percent[row2],
+				pc);
+		return ocv;
+	}
+
+	ocvrow1 = linear_interpolate(
+				chip->pc_temp_ocv_lut->ocv[row1][i - 1],
+				chip->pc_temp_ocv_lut->temp[i - 1],
+				chip->pc_temp_ocv_lut->ocv[row1][i],
+				chip->pc_temp_ocv_lut->temp[i],
+				batt_temp_degc);
+
+	ocvrow2 = linear_interpolate(
+				chip->pc_temp_ocv_lut->ocv[row2][i - 1],
+				chip->pc_temp_ocv_lut->temp[i - 1],
+				chip->pc_temp_ocv_lut->ocv[row2][i],
+				chip->pc_temp_ocv_lut->temp[i],
+				batt_temp_degc);
+
+	ocv = linear_interpolate(
+				ocvrow1,
+				chip->pc_temp_ocv_lut->percent[row1],
+				ocvrow2,
+				chip->pc_temp_ocv_lut->percent[row2],
+				pc);
+
+	return ocv;
+}
+
 static int interpolate_pc(struct pm8921_bms_chip *chip,
 				int batt_temp, int ocv)
 {
@@ -848,7 +929,7 @@
 #define BMS_MODE_BIT	BIT(6)
 #define EN_VBAT_BIT	BIT(5)
 #define OVERRIDE_MODE_DELAY_MS	20
-int pm8921_bms_get_simultaneous_battery_voltage_and_current(int *ibat_ua,
+int override_mode_simultaneous_battery_voltage_and_current(int *ibat_ua,
 								int *vbat_uv)
 {
 	int16_t vsense_raw;
@@ -856,11 +937,6 @@
 	int vsense_uv;
 	int usb_chg;
 
-	if (the_chip == NULL) {
-		pr_err("Called to early\n");
-		return -EINVAL;
-	}
-
 	mutex_lock(&the_chip->bms_output_lock);
 
 	pm8xxx_writeb(the_chip->dev->parent, BMS_S1_DELAY, 0x00);
@@ -893,46 +969,6 @@
 			*ibat_ua, *vbat_uv);
 	return 0;
 }
-EXPORT_SYMBOL(pm8921_bms_get_simultaneous_battery_voltage_and_current);
-
-static int read_rbatt_params_raw(struct pm8921_bms_chip *chip,
-				struct pm8921_rbatt_params *raw)
-{
-	int usb_chg;
-
-	mutex_lock(&chip->bms_output_lock);
-	pm_bms_lock_output_data(chip);
-
-	pm_bms_read_output_data(chip,
-			OCV_FOR_RBATT, &raw->ocv_for_rbatt_raw);
-	pm_bms_read_output_data(chip,
-			VBATT_FOR_RBATT, &raw->vbatt_for_rbatt_raw);
-	pm_bms_read_output_data(chip,
-			VSENSE_FOR_RBATT, &raw->vsense_for_rbatt_raw);
-
-	pm_bms_unlock_output_data(chip);
-	mutex_unlock(&chip->bms_output_lock);
-
-	usb_chg = usb_chg_plugged_in();
-
-#ifdef CONFIG_WIRELESS_CHARGER
-	usb_chg |= wireless_chg_plugged_in();
-#endif
-	convert_vbatt_raw_to_uv(chip, usb_chg,
-			raw->vbatt_for_rbatt_raw, &raw->vbatt_for_rbatt_uv);
-	convert_vbatt_raw_to_uv(chip, usb_chg,
-			raw->ocv_for_rbatt_raw, &raw->ocv_for_rbatt_uv);
-	convert_vsense_to_uv(chip, raw->vsense_for_rbatt_raw,
-					&raw->vsense_for_rbatt_uv);
-
-	pr_debug("vbatt_for_rbatt_raw = 0x%x, vbatt_for_rbatt= %duV\n",
-			raw->vbatt_for_rbatt_raw, raw->vbatt_for_rbatt_uv);
-	pr_debug("ocv_for_rbatt_raw = 0x%x, ocv_for_rbatt= %duV\n",
-			raw->ocv_for_rbatt_raw, raw->ocv_for_rbatt_uv);
-	pr_debug("vsense_for_rbatt_raw = 0x%x, vsense_for_rbatt= %duV\n",
-			raw->vsense_for_rbatt_raw, raw->vsense_for_rbatt_uv);
-	return 0;
-}
 
 #define MBG_TRANSIENT_ERROR_RAW 51
 static void adjust_pon_ocv_raw(struct pm8921_bms_chip *chip,
@@ -971,6 +1007,7 @@
 		convert_vbatt_raw_to_uv(chip, usb_chg,
 			raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
 		chip->last_ocv_uv = raw->last_good_ocv_uv;
+		pr_debug("PON_OCV_UV = %d\n", chip->last_ocv_uv);
 	} else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
 		chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
 		convert_vbatt_raw_to_uv(chip, usb_chg,
@@ -1006,7 +1043,7 @@
 {
 	int rbatt, scalefactor;
 
-	rbatt = (last_rbatt < 0) ? chip->default_rbatt_mohm : last_rbatt;
+	rbatt = chip->default_rbatt_mohm;
 	pr_debug("rbatt before scaling = %d\n", rbatt);
 	if (chip->rbatt_sf_lut == NULL)  {
 		pr_debug("RBATT = %d\n", rbatt);
@@ -1035,27 +1072,6 @@
 	return rbatt;
 }
 
-static int calculate_rbatt_resume(struct pm8921_bms_chip *chip,
-				struct pm8921_rbatt_params *raw)
-{
-	unsigned int  r_batt;
-
-	if (raw->ocv_for_rbatt_uv <= 0
-		|| raw->ocv_for_rbatt_uv <= raw->vbatt_for_rbatt_uv
-		|| raw->vsense_for_rbatt_raw <= 0) {
-		pr_debug("rbatt readings unavailable ocv = %d, vbatt = %d,"
-					"vsen = %d\n",
-					raw->ocv_for_rbatt_uv,
-					raw->vbatt_for_rbatt_uv,
-					raw->vsense_for_rbatt_raw);
-		return -EINVAL;
-	}
-	r_batt = ((raw->ocv_for_rbatt_uv - raw->vbatt_for_rbatt_uv)
-			* chip->r_sense) / raw->vsense_for_rbatt_uv;
-	pr_debug("r_batt = %umilliOhms", r_batt);
-	return r_batt;
-}
-
 static int calculate_fcc_uah(struct pm8921_bms_chip *chip, int batt_temp,
 							int chargecycles)
 {
@@ -1108,7 +1124,7 @@
 		return rc;
 	}
 
-	rbatt = (last_rbatt < 0) ? chip->default_rbatt_mohm : last_rbatt;
+	rbatt = chip->default_rbatt_mohm;
 	*ocv = vbatt + (ibatt_ua * rbatt)/1000;
 	return 0;
 }
@@ -1159,185 +1175,230 @@
 	*val = cc_uah;
 }
 
-static int calculate_uuc_uah_at_given_current(struct pm8921_bms_chip *chip,
+static int calculate_termination_uuc(struct pm8921_bms_chip *chip,
 				 int batt_temp, int chargecycles,
-				int rbatt, int fcc_uah, int i_ma)
+				int fcc_uah, int i_ma,
+				int *ret_pc_unusable)
 {
 	int unusable_uv, pc_unusable, uuc;
+	int i = 0;
+	int ocv_mv;
+	int batt_temp_degc = batt_temp / 10;
+	int rbatt_mohm;
+	int delta_uv;
+	int prev_delta_uv = 0;
+	int prev_rbatt_mohm = 0;
+	int prev_ocv_mv = 0;
+	int uuc_rbatt_uv;
 
-	/* calculate unusable charge with itest */
-	unusable_uv = (rbatt * i_ma) + (chip->v_failure * 1000);
+	for (i = 0; i <= 100; i++) {
+		ocv_mv = interpolate_ocv(chip, batt_temp_degc, i);
+		rbatt_mohm = get_rbatt(chip, i, batt_temp);
+		unusable_uv = (rbatt_mohm * i_ma) + (chip->v_cutoff * 1000);
+		delta_uv = ocv_mv * 1000 - unusable_uv;
+
+		pr_debug("soc = %d ocv = %d rbat = %d u_uv = %d delta_v = %d\n",
+				i, ocv_mv, rbatt_mohm, unusable_uv, delta_uv);
+
+		if (delta_uv > 0)
+			break;
+
+		prev_delta_uv = delta_uv;
+		prev_rbatt_mohm = rbatt_mohm;
+		prev_ocv_mv = ocv_mv;
+	}
+
+	uuc_rbatt_uv = linear_interpolate(rbatt_mohm, delta_uv,
+					prev_rbatt_mohm, prev_delta_uv,
+					0);
+
+	unusable_uv = (uuc_rbatt_uv * i_ma) + (chip->v_cutoff * 1000);
+
 	pc_unusable = calculate_pc(chip, unusable_uv, batt_temp, chargecycles);
 	uuc = (fcc_uah * pc_unusable) / 100;
-	pr_debug("For i_ma = %d, unusable_uv = %d unusable_pc = %d uuc = %d\n",
-					i_ma, unusable_uv, pc_unusable, uuc);
+	pr_debug("For i_ma = %d, unusable_rbatt = %d unusable_uv = %d unusable_pc = %d uuc = %d\n",
+					i_ma, uuc_rbatt_uv, unusable_uv,
+					pc_unusable, uuc);
+	*ret_pc_unusable = pc_unusable;
 	return uuc;
 }
 
-#define SOC_RBATT_CHG		70
-#define SOC_RBATT_DISCHG	20
-
-static int uuc_iavg_div = 150;
-module_param(uuc_iavg_div, int, 0644);
-
-static int uuc_min_step_size = 120;
-module_param(uuc_min_step_size, int, 0644);
-
-static int uuc_multiplier = 1000;
-module_param(uuc_multiplier, int, 0644);
-
-#define UUC_TIMER_MS		120000
-
-static void uuc_timer_work(struct work_struct *work)
+static int adjust_uuc(struct pm8921_bms_chip *chip, int fcc_uah,
+			int new_pc_unusable,
+			int new_uuc,
+			int batt_temp,
+			int rbatt,
+			int *iavg_ma)
 {
-	struct pm8921_bms_chip *chip = container_of(work,
-				struct pm8921_bms_chip, uuc_timer_work.work);
+	int new_unusable_mv;
+	int batt_temp_degc = batt_temp / 10;
 
-	pr_debug("UUC Timer expired\n");
-	/* indicates the system is done with the high load during bootup */
-	chip->timer_uuc_expired = 1;
+	if (chip->prev_pc_unusable == -EINVAL
+		|| abs(chip->prev_pc_unusable - new_pc_unusable) <= 1) {
+		chip->prev_pc_unusable = new_pc_unusable;
+		return new_uuc;
+	}
+
+	/* the uuc is trying to change more than 1% restrict it */
+	if (new_pc_unusable > chip->prev_pc_unusable)
+		chip->prev_pc_unusable++;
+	else
+		chip->prev_pc_unusable--;
+
+	new_uuc = (fcc_uah * chip->prev_pc_unusable) / 100;
+
+	/* also find update the iavg_ma accordingly */
+	new_unusable_mv = interpolate_ocv(chip, batt_temp_degc,
+						chip->prev_pc_unusable);
+	if (new_unusable_mv < chip->v_cutoff)
+		new_unusable_mv = chip->v_cutoff;
+
+	*iavg_ma = (new_unusable_mv - chip->v_cutoff) * 1000 / rbatt;
+	if (*iavg_ma == 0)
+		*iavg_ma = 1;
+	pr_debug("Restricting UUC to %d (%d%%) unusable_mv = %d iavg_ma = %d\n",
+					new_uuc, chip->prev_pc_unusable,
+					new_unusable_mv, *iavg_ma);
+
+	return new_uuc;
 }
 
 static void calculate_iavg_ua(struct pm8921_bms_chip *chip, int cc_uah,
-				int *iavg_ua, int *delta_time_us)
+				int *iavg_ua, int *delta_time_s)
 {
 	int delta_cc_uah;
-	struct timeval now;
+	struct rtc_time tm;
+	struct rtc_device *rtc;
+	unsigned long now_tm_sec = 0;
+	int rc = 0;
 
-	delta_cc_uah = cc_uah - chip->last_cc_uah;
-	do_gettimeofday(&now);
-	if (chip->t.tv_sec != 0) {
-		*delta_time_us = (now.tv_sec - chip->t.tv_sec) * USEC_PER_SEC
-				+ now.tv_usec - chip->t.tv_usec;
-	} else {
-		/* calculation for the first time */
-		*delta_time_us = 0;
+	/* if anything fails report the previous iavg_ua */
+	*iavg_ua = chip->prev_iavg_ua;
+
+	rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+	if (rtc == NULL) {
+		pr_err("%s: unable to open rtc device (%s)\n",
+			__FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
+		goto out;
 	}
 
-	if (*delta_time_us != 0)
-		*iavg_ua = div_s64((s64)delta_cc_uah * 3600 * 1000000,
-					*delta_time_us);
-	else
-		*iavg_ua = 0;
+	rc = rtc_read_time(rtc, &tm);
+	if (rc) {
+		pr_err("Error reading rtc device (%s) : %d\n",
+			CONFIG_RTC_HCTOSYS_DEVICE, rc);
+		goto out;
+	}
 
-	pr_debug("t.tv_sec = %d, now.tv_sec = %d delta_us = %d iavg_ua = %d\n",
-				(int)chip->t.tv_sec, (int)now.tv_sec,
-				*delta_time_us, (int)*iavg_ua);
+	rc = rtc_valid_tm(&tm);
+	if (rc) {
+		pr_err("Invalid RTC time (%s): %d\n",
+			CONFIG_RTC_HCTOSYS_DEVICE, rc);
+		goto out;
+	}
+	rtc_tm_to_time(&tm, &now_tm_sec);
+
+	if (chip->tm_sec == 0) {
+		*delta_time_s = 0;
+		pm8921_bms_get_battery_current(iavg_ua);
+		goto out;
+	}
+
+	*delta_time_s = (now_tm_sec - chip->tm_sec);
+
+	/* use the previous iavg if called within 15 seconds */
+	if (*delta_time_s < 15) {
+		*iavg_ua = chip->prev_iavg_ua;
+		goto out;
+	}
+
+	delta_cc_uah = cc_uah - chip->last_cc_uah;
+
+	*iavg_ua = div_s64((s64)delta_cc_uah * 3600, *delta_time_s);
+
+	pr_debug("tm_sec = %ld, now_tm_sec = %ld delta_s = %d delta_cc = %d iavg_ua = %d\n",
+				chip->tm_sec, now_tm_sec,
+				*delta_time_s, delta_cc_uah, (int)*iavg_ua);
+
+out:
+	/* remember the iavg */
+	chip->prev_iavg_ua = *iavg_ua;
+
 	/* remember cc_uah */
 	chip->last_cc_uah = cc_uah;
 
 	/* remember this time */
-	chip->t = now;
+	chip->tm_sec = now_tm_sec;
 }
 
-#define UUC_IAVG_THRESHOLD_UAH	50000
-static int scale_unusable_charge_uah(struct pm8921_bms_chip *chip,
-			bool charging, int uuc_uah_iavg, int uuc_uah_itest,
-			int uuc_uah_iavg_prev)
-{
-	int stepsize = 0;
-	int delta_uuc = 0;
-	int uuc_reported = 0;
-
-	if (charging) {
-		stepsize = max(uuc_min_step_size,
-				uuc_multiplier * (SOC_RBATT_CHG - last_soc));
-		/*
-		 * set the delta only if uuc is decreasing. If it has increased
-		 * simply report the last uuc since we don't want to report a
-		 * higher uuc as charging progresses
-		 */
-		if (chip->last_uuc_uah > uuc_uah_iavg)
-			delta_uuc = (chip->last_uuc_uah - uuc_uah_iavg)
-								/ stepsize;
-		uuc_reported = chip->last_uuc_uah - delta_uuc;
-	} else {
-		stepsize = max(uuc_min_step_size,
-			uuc_multiplier * (last_soc - SOC_RBATT_DISCHG));
-		if (uuc_uah_itest > uuc_uah_iavg) {
-			if ((uuc_uah_iavg > uuc_uah_iavg_prev
-						+ UUC_IAVG_THRESHOLD_UAH)
-				&& chip->timer_uuc_expired)
-				/*
-				 * there is a big jump in iavg current way past
-				 * the bootup increase  uuc to this high iavg
-				 * based uuc in steps
-				 */
-				delta_uuc = (uuc_uah_iavg - uuc_uah_iavg_prev)
-							/ uuc_iavg_div;
-			else
-				/* increase uuc towards itest based uuc */
-				delta_uuc = (uuc_uah_itest - uuc_uah_iavg)
-						/ stepsize;
-		} else {
-			/*
-			 * the iavg based uuc was higher than itest based
-			 * uuc. This means that iavg > itest. Itest represents
-			 * the max current drawn from the device at anytime.
-			 * If we find iavg > itest, ignore iavg and simply step
-			 * up the uuc based on itest
-			 */
-			delta_uuc = uuc_uah_itest / stepsize;
-		}
-		uuc_reported = min(uuc_uah_itest,
-					chip->last_uuc_uah + delta_uuc);
-	}
-	pr_debug("uuc_prev = %d stepsize = %d d_uuc =  %d uuc_reported = %d\n",
-			chip->last_uuc_uah, (int)stepsize, delta_uuc,
-			uuc_reported);
-	return uuc_reported;
-}
-
+#define IAVG_SAMPLES 16
+#define CHARGING_IAVG_MA 250
+#define MIN_SECONDS_FOR_VALID_SAMPLE	20
 static int calculate_unusable_charge_uah(struct pm8921_bms_chip *chip,
 				int rbatt, int fcc_uah, int cc_uah,
 				int soc_rbatt, int batt_temp, int chargecycles,
-				int iavg_ua)
+				int iavg_ua, int delta_time_s)
 {
-	int uuc_uah_itest, uuc_uah_iavg, uuc_reported;
-	static int firsttime = 1;
+	int uuc_uah_iavg;
+	int i;
 	int iavg_ma = iavg_ua / 1000;
+	static int iavg_samples[IAVG_SAMPLES];
+	static int iavg_index;
+	static int iavg_num_samples;
+	static int firsttime = 1;
+	int pc_unusable;
 
-	/* calculate unusable charge with itest */
-	uuc_uah_itest = calculate_uuc_uah_at_given_current(chip,
+	/*
+	 * if we are called first time fill all the
+	 * samples with the the shutdown_iavg_ua
+	 */
+	if (firsttime && chip->shutdown_iavg_ua != 0) {
+		pr_emerg("Using shutdown_iavg_ua = %d in all samples\n",
+				chip->shutdown_iavg_ua);
+		for (i = 0; i < IAVG_SAMPLES; i++)
+			iavg_samples[i] = chip->shutdown_iavg_ua;
+
+		iavg_index = 0;
+		iavg_num_samples = IAVG_SAMPLES;
+	}
+
+	/*
+	 * if we are charging use a nominal avg current so that we keep
+	 * a reasonable UUC while charging
+	 */
+	if (iavg_ma < 0)
+		iavg_ma = CHARGING_IAVG_MA;
+	iavg_samples[iavg_index] = iavg_ma;
+	iavg_index = (iavg_index + 1) % IAVG_SAMPLES;
+	iavg_num_samples++;
+	if (iavg_num_samples >= IAVG_SAMPLES)
+		iavg_num_samples = IAVG_SAMPLES;
+
+	/* now that this sample is added calcualte the average */
+	iavg_ma = 0;
+	if (iavg_num_samples != 0) {
+		for (i = 0; i < iavg_num_samples; i++) {
+			pr_debug("iavg_samples[%d] = %d\n", i, iavg_samples[i]);
+			iavg_ma += iavg_samples[i];
+		}
+
+		iavg_ma = DIV_ROUND_CLOSEST(iavg_ma, iavg_num_samples);
+	}
+
+	uuc_uah_iavg = calculate_termination_uuc(chip,
 					batt_temp, chargecycles,
-					rbatt, fcc_uah, chip->i_test);
-
-	pr_debug("itest = %d uuc_itest = %d\n", chip->i_test, uuc_uah_itest);
-
-	/* calculate unusable charge with iavg */
-	iavg_ma = max(0, iavg_ma);
-	uuc_uah_iavg = calculate_uuc_uah_at_given_current(chip,
-					batt_temp, chargecycles,
-					rbatt, fcc_uah, iavg_ma);
+					fcc_uah, iavg_ma,
+					&pc_unusable);
 	pr_debug("iavg = %d uuc_iavg = %d\n", iavg_ma, uuc_uah_iavg);
 
-	if (firsttime) {
-		chip->uuc_uah_iavg_prev = uuc_uah_iavg;
+	/* restrict the uuc such that it can increase only by one percent */
+	uuc_uah_iavg = adjust_uuc(chip, fcc_uah, pc_unusable, uuc_uah_iavg,
+					batt_temp, rbatt, &iavg_ma);
 
-		if (cc_uah < chip->last_cc_uah)
-			chip->last_uuc_uah = uuc_uah_itest;
-		else
-			chip->last_uuc_uah = uuc_uah_iavg;
-		pr_debug("firsttime uuc_prev = %d\n", chip->last_uuc_uah);
-	}
+	/* find out what the avg current should be for this uuc */
+	chip->prev_uuc_iavg_ma = iavg_ma;
 
-	uuc_reported = scale_unusable_charge_uah(chip,
-				cc_uah < chip->last_cc_uah,
-				uuc_uah_iavg, uuc_uah_itest,
-				chip->uuc_uah_iavg_prev);
-
-	/* remember the last uuc_uah_iavg */
-	chip->uuc_uah_iavg_prev = uuc_uah_iavg;
-
-	/* remember the reported uuc */
-	chip->last_uuc_uah = uuc_reported;
-
-	if (firsttime == 1) {
-		/* uuc calculation for the first time is done */
-		firsttime = 0;
-	}
-
-	return uuc_reported;
+	firsttime = 0;
+	return uuc_uah_iavg;
 }
 
 /* calculate remainging charge at the time of ocv */
@@ -1363,7 +1424,7 @@
 						int *cc_uah,
 						int *rbatt,
 						int *iavg_ua,
-						int *delta_time_us)
+						int *delta_time_s)
 {
 	int soc_rbatt;
 
@@ -1389,11 +1450,12 @@
 		soc_rbatt = 0;
 	*rbatt = get_rbatt(chip, soc_rbatt, batt_temp);
 
-	calculate_iavg_ua(chip, *cc_uah, iavg_ua, delta_time_us);
+	calculate_iavg_ua(chip, *cc_uah, iavg_ua, delta_time_s);
 
 	*unusable_charge_uah = calculate_unusable_charge_uah(chip, *rbatt,
 					*fcc_uah, *cc_uah, soc_rbatt,
-					batt_temp, chargecycles, *iavg_ua);
+					batt_temp, chargecycles, *iavg_ua,
+					*delta_time_s);
 	pr_debug("UUC = %uuAh\n", *unusable_charge_uah);
 }
 
@@ -1408,7 +1470,7 @@
 	int real_fcc_uah;
 	int rbatt;
 	int iavg_ua;
-	int delta_time_us;
+	int delta_time_s;
 
 	calculate_soc_params(chip, raw, batt_temp, chargecycles,
 						&fcc_uah,
@@ -1417,7 +1479,7 @@
 						&cc_uah,
 						&rbatt,
 						&iavg_ua,
-						&delta_time_us);
+						&delta_time_s);
 
 	real_fcc_uah = remaining_charge_uah - cc_uah;
 	*ret_fcc_uah = fcc_uah;
@@ -1426,6 +1488,107 @@
 	return real_fcc_uah;
 }
 
+int pm8921_bms_get_simultaneous_battery_voltage_and_current(int *ibat_ua,
+								int *vbat_uv)
+{
+	int rc;
+
+	if (the_chip == NULL) {
+		pr_err("Called too early\n");
+		return -EINVAL;
+	}
+
+	if (pm8921_is_batfet_closed()) {
+		return override_mode_simultaneous_battery_voltage_and_current(
+								ibat_ua,
+								vbat_uv);
+	} else {
+		pr_debug("batfet is open using separate vbat and ibat meas\n");
+		rc = get_battery_uvolts(the_chip, vbat_uv);
+		if (rc < 0) {
+			pr_err("adc vbat failed err = %d\n", rc);
+			return rc;
+		}
+		rc = pm8921_bms_get_battery_current(ibat_ua);
+		if (rc < 0) {
+			pr_err("bms ibat failed err = %d\n", rc);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(pm8921_bms_get_simultaneous_battery_voltage_and_current);
+
+static void find_ocv_for_soc(struct pm8921_bms_chip *chip,
+			int batt_temp,
+			int chargecycles,
+			int fcc_uah,
+			int uuc_uah,
+			int cc_uah,
+			int shutdown_soc,
+			int *rc_uah,
+			int *ocv_uv)
+{
+	s64 rc;
+	int pc, new_pc;
+	int batt_temp_degc = batt_temp / 10;
+	int ocv;
+
+	rc = (s64)shutdown_soc * (fcc_uah - uuc_uah);
+	rc = div_s64(rc, 100) + cc_uah + uuc_uah;
+	pc = DIV_ROUND_CLOSEST((int)rc * 100, fcc_uah);
+	pc = clamp(pc, 0, 100);
+
+	ocv = interpolate_ocv(chip, batt_temp_degc, pc);
+
+	pr_debug("s_soc = %d, fcc = %d uuc = %d rc = %d, pc = %d, ocv mv = %d\n",
+			shutdown_soc, fcc_uah, uuc_uah, (int)rc, pc, ocv);
+	new_pc = interpolate_pc(chip, batt_temp_degc, ocv);
+	pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
+
+	while (abs(new_pc - pc) > 1) {
+		int delta_mv = 5;
+
+		if (new_pc > pc)
+			delta_mv = -1 * delta_mv;
+
+		ocv = ocv + delta_mv;
+		new_pc = interpolate_pc(chip, batt_temp_degc, ocv);
+		pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
+	}
+
+	*ocv_uv = ocv * 1000;
+	*rc_uah = (int)rc;
+}
+
+static void adjust_rc_and_uuc_for_specific_soc(
+						struct pm8921_bms_chip *chip,
+						int batt_temp,
+						int chargecycles,
+						int soc,
+						int fcc_uah,
+						int uuc_uah,
+						int cc_uah,
+						int rc_uah,
+						int rbatt,
+						int *ret_ocv,
+						int *ret_rc,
+						int *ret_uuc,
+						int *ret_rbatt)
+{
+	int ocv_uv;
+
+	find_ocv_for_soc(chip, batt_temp, chargecycles,
+					fcc_uah, uuc_uah, cc_uah,
+					soc,
+					&rc_uah, &ocv_uv);
+
+	*ret_ocv = ocv_uv;
+	*ret_rbatt = rbatt;
+	*ret_rc = rc_uah;
+	*ret_uuc = uuc_uah;
+}
 static int bound_soc(int soc)
 {
 	soc = max(0, soc);
@@ -1433,9 +1596,73 @@
 	return soc;
 }
 
+static int charging_adjustments(struct pm8921_bms_chip *chip,
+				int soc, int vbat_uv, int ibat_ua,
+				int batt_temp, int chargecycles,
+				int fcc_uah, int cc_uah, int uuc_uah)
+{
+	int chg_soc;
+
+	if (chip->soc_at_cv == -EINVAL) {
+		/* In constant current charging return the calc soc */
+		if (vbat_uv <= chip->max_voltage_uv)
+			pr_debug("CC CHG SOC %d\n", soc);
+
+		/* Note the CC to CV point */
+		if (vbat_uv >= chip->max_voltage_uv) {
+			chip->soc_at_cv = soc;
+			chip->prev_chg_soc = soc;
+			chip->ibat_at_cv_ua = ibat_ua;
+			pr_debug("CC_TO_CV ibat_ua = %d CHG SOC %d\n",
+					ibat_ua, soc);
+		}
+		return soc;
+	}
+
+	/*
+	 * battery is in CV phase - begin liner inerpolation of soc based on
+	 * battery charge current
+	 */
+
+	/*
+	 * if voltage lessened (possibly because of a system load)
+	 * keep reporting the prev chg soc
+	 */
+	if (vbat_uv <= chip->max_voltage_uv) {
+		pr_debug("vbat %d < max = %d CC CHG SOC %d\n",
+			vbat_uv, chip->max_voltage_uv, chip->prev_chg_soc);
+		return chip->prev_chg_soc;
+	}
+
+	chg_soc = linear_interpolate(chip->soc_at_cv, chip->ibat_at_cv_ua,
+					100, -100000,
+					ibat_ua);
+
+	/* always report a higher soc */
+	if (chg_soc > chip->prev_chg_soc) {
+		int new_ocv_uv;
+		int new_rc;
+
+		chip->prev_chg_soc = chg_soc;
+
+		find_ocv_for_soc(chip, batt_temp, chargecycles,
+				fcc_uah, uuc_uah, cc_uah,
+				chg_soc,
+				&new_rc, &new_ocv_uv);
+		the_chip->last_ocv_uv = new_ocv_uv;
+		pr_debug("CC CHG ADJ OCV = %d CHG SOC %d\n",
+				new_ocv_uv,
+				chip->prev_chg_soc);
+	}
+
+	pr_debug("Reporting CHG SOC %d\n", chip->prev_chg_soc);
+	return chip->prev_chg_soc;
+}
+
 static int last_soc_est = -EINVAL;
-static int adjust_soc(struct pm8921_bms_chip *chip, int soc, int batt_temp,
-		int rbatt , int fcc_uah, int uuc_uah, int cc_uah)
+static int adjust_soc(struct pm8921_bms_chip *chip, int soc,
+		int batt_temp, int chargecycles,
+		int rbatt, int fcc_uah, int uuc_uah, int cc_uah)
 {
 	int ibat_ua = 0, vbat_uv = 0;
 	int ocv_est_uv = 0, soc_est = 0, pc_est = 0, pc = 0;
@@ -1445,23 +1672,47 @@
 	int pc_new = 0;
 	int soc_new = 0;
 	int m = 0;
+	int rc = 0;
+	int delta_ocv_uv_limit = 0;
 
-	pm8921_bms_get_simultaneous_battery_voltage_and_current(&ibat_ua,
-		&vbat_uv);
-
-	if (ibat_ua < 0)
+	rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
+							&ibat_ua,
+							&vbat_uv);
+	if (rc < 0) {
+		pr_err("simultaneous vbat ibat failed err = %d\n", rc);
 		goto out;
+	}
+
+
+	delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000);
+
 	ocv_est_uv = vbat_uv + (ibat_ua * rbatt)/1000;
 	pc_est = calculate_pc(chip, ocv_est_uv, batt_temp, last_chargecycles);
 	soc_est = div_s64((s64)fcc_uah * pc_est - uuc_uah*100,
 						(s64)fcc_uah - uuc_uah);
 	soc_est = bound_soc(soc_est);
 
+	if (ibat_ua < 0) {
+		soc = charging_adjustments(chip, soc, vbat_uv, ibat_ua,
+				batt_temp, chargecycles,
+				fcc_uah, cc_uah, uuc_uah);
+		goto out;
+	}
+
 	/*
-	 * do not adjust if soc_est is between 45 and 25 OR soc_est is
-	 * same as what bms calculated
+	 * do not adjust
+	 * if soc is same as what bms calculated
+	 * if soc_est is between 45 and 25, this is the flat portion of the
+	 * curve where soc_est is not so accurate. We generally don't want to
+	 * adjust when soc_est is inaccurate except for the cases when soc is
+	 * way far off (higher than 50 or lesser than 20).
+	 * Also don't adjust soc if it is above 90 becuase we might pull it low
+	 * and  cause a bad user experience
 	 */
-	if (is_between(45, 25, soc_est) || soc_est == soc)
+	if (soc_est == soc
+		|| (is_between(45, chip->adjust_soc_low_threshold, soc_est)
+		&& is_between(50, chip->adjust_soc_low_threshold - 5, soc))
+		|| soc >= 90)
 		goto out;
 
 	if (last_soc_est == -EINVAL)
@@ -1495,6 +1746,18 @@
 
 	delta_ocv_uv = div_s64((soc - soc_est) * (s64)m * 1000,
 							n * (pc - pc_new));
+
+	if (abs(delta_ocv_uv) > delta_ocv_uv_limit) {
+		pr_debug("limiting delta ocv %d limit = %d\n", delta_ocv_uv,
+				delta_ocv_uv_limit);
+
+		if (delta_ocv_uv > 0)
+			delta_ocv_uv = delta_ocv_uv_limit;
+		else
+			delta_ocv_uv = -1 * delta_ocv_uv_limit;
+		pr_debug("new delta ocv = %d\n", delta_ocv_uv);
+	}
+
 	chip->last_ocv_uv -= delta_ocv_uv;
 
 	if (chip->last_ocv_uv >= chip->max_voltage_uv)
@@ -1519,79 +1782,156 @@
 out:
 	pr_debug("ibat_ua = %d, vbat_uv = %d, ocv_est_uv = %d, pc_est = %d, "
 		"soc_est = %d, n = %d, delta_ocv_uv = %d, last_ocv_uv = %d, "
-		"pc_new = %d, soc_new = %d\n",
+		"pc_new = %d, soc_new = %d, rbatt = %d, m = %d\n",
 		ibat_ua, vbat_uv, ocv_est_uv, pc_est,
 		soc_est, n, delta_ocv_uv, chip->last_ocv_uv,
-		pc_new, soc_new);
+		pc_new, soc_new, rbatt, m);
 
 	return soc;
 }
 
-#define MAX_SHUTDOWN_ADJUST_SECONDS	1800
-static int adjust_for_shutdown_soc(struct pm8921_bms_chip *chip, int soc)
+#define IGNORE_SOC_TEMP_DECIDEG		50
+#define IAVG_STEP_SIZE_MA	50
+#define IAVG_START		600
+#define SOC_ZERO		0xFF
+static void backup_soc_and_iavg(struct pm8921_bms_chip *chip, int batt_temp,
+				int soc)
 {
-	struct timespec uptime;
-	int val;
+	u8 temp;
+	int iavg_ma = chip->prev_uuc_iavg_ma;
 
-	/* value of zero means the shutdown soc should not be used */
-	if (chip->shutdown_soc == 0)
-		return soc;
+	if (iavg_ma > IAVG_START)
+		temp = (iavg_ma - IAVG_START) / IAVG_STEP_SIZE_MA;
+	else
+		temp = 0;
 
-	if (shutdown_soc_invalid) {
-		chip->shutdown_soc = 0;
-		return soc;
-	}
+	pm_bms_masked_write(chip, TEMP_IAVG_STORAGE,
+			TEMP_IAVG_STORAGE_USE_MASK, temp);
 
-	do_posix_clock_monotonic_gettime(&uptime);
+	/* since only 6 bits are available for SOC, we store half the soc */
+	if (soc == 0)
+		temp = SOC_ZERO;
+	else
+		temp = soc;
 
-	if (uptime.tv_sec >= MAX_SHUTDOWN_ADJUST_SECONDS) {
-		/*
-		 * adjusted for a long time now, switch to reporting the
-		 * calculated soc
-		 */
-		chip->shutdown_soc = 0;
-		return soc;
-	}
-
-	val = ((MAX_SHUTDOWN_ADJUST_SECONDS - uptime.tv_sec)
-		* chip->shutdown_soc
-		+ uptime.tv_sec * soc);
-	val /= MAX_SHUTDOWN_ADJUST_SECONDS;
-	pr_debug("shutdown_soc = %d, adj soc = %d, calc soc = %d\n",
-				chip->shutdown_soc, val, soc);
-
-	return val;
+	/* don't store soc if temperature is below 5degC */
+	if (batt_temp > IGNORE_SOC_TEMP_DECIDEG)
+		pm8xxx_writeb(the_chip->dev->parent, TEMP_SOC_STORAGE, temp);
 }
 
-static void backup_soc(struct pm8921_bms_chip *chip, int last_soc)
-{
-	/* TODO: if 0x107 is free for all variants 8917, 8038 etc */
-	pm8xxx_writeb(the_chip->dev->parent, TEMP_SOC_STORAGE, last_soc);
-}
-
-static void read_shutdown_soc(struct pm8921_bms_chip *chip)
+static void read_shutdown_soc_and_iavg(struct pm8921_bms_chip *chip)
 {
 	int rc;
 	u8 temp;
 
+	rc = pm8xxx_readb(chip->dev->parent, TEMP_IAVG_STORAGE, &temp);
+	if (rc) {
+		pr_err("failed to read addr = %d %d assuming %d\n",
+				TEMP_IAVG_STORAGE, rc, IAVG_START);
+		chip->shutdown_iavg_ua = IAVG_START;
+	} else {
+		temp &= TEMP_IAVG_STORAGE_USE_MASK;
+
+		if (temp == 0) {
+			chip->shutdown_iavg_ua = IAVG_START;
+		} else {
+			chip->shutdown_iavg_ua = IAVG_START
+					+ IAVG_STEP_SIZE_MA * (temp + 1);
+		}
+	}
+
 	rc = pm8xxx_readb(chip->dev->parent, TEMP_SOC_STORAGE, &temp);
-	if (rc)
+	if (rc) {
 		pr_err("failed to read addr = %d %d\n", TEMP_SOC_STORAGE, rc);
-	else
+	} else {
 		chip->shutdown_soc = temp;
 
-	pr_debug("shutdown_soc = %d\n", chip->shutdown_soc);
+		if (chip->shutdown_soc == 0) {
+			pr_debug("No shutdown soc available\n");
+			shutdown_soc_invalid = 1;
+			chip->shutdown_iavg_ua = 0;
+		} else if (chip->shutdown_soc == SOC_ZERO) {
+			chip->shutdown_soc = 0;
+		}
+	}
+
+	if (chip->ignore_shutdown_soc) {
+		shutdown_soc_invalid = 1;
+		chip->shutdown_soc = 0;
+		chip->shutdown_iavg_ua = 0;
+	}
+
+	pr_debug("shutdown_soc = %d shutdown_iavg = %d shutdown_soc_invalid = %d\n",
+			chip->shutdown_soc,
+			chip->shutdown_iavg_ua,
+			shutdown_soc_invalid);
 }
 
-void pm8921_bms_invalidate_shutdown_soc(void)
+#define SOC_CATCHUP_SEC_MAX		600
+#define SOC_CATCHUP_SEC_PER_PERCENT	60
+#define MAX_CATCHUP_SOC	(SOC_CATCHUP_SEC_MAX/SOC_CATCHUP_SEC_PER_PERCENT)
+static int scale_soc_while_chg(struct pm8921_bms_chip *chip,
+				int delta_time_us, int new_soc, int prev_soc)
 {
-	pr_debug("Invalidating shutdown soc - the battery was removed\n");
-	shutdown_soc_invalid = 1;
-	if (the_chip)
-		the_chip->shutdown_soc = 0;
-}
-EXPORT_SYMBOL(pm8921_bms_invalidate_shutdown_soc);
+	int chg_time_sec;
+	int catch_up_sec;
+	int scaled_soc;
+	int numerator;
 
+	/*
+	 * The device must be charging for reporting a higher soc, if
+	 * not ignore this soc and continue reporting the prev_soc.
+	 * Also don't report a high value immediately slowly scale the
+	 * value from prev_soc to the new soc based on a charge time
+	 * weighted average
+	 */
+
+	/* if we are not charging return last soc */
+	if (the_chip->start_percent == -EINVAL)
+		return prev_soc;
+
+	/* if soc is called in quick succession return the last soc */
+	if (delta_time_us < USEC_PER_SEC)
+		return prev_soc;
+
+	chg_time_sec = DIV_ROUND_UP(the_chip->charge_time_us, USEC_PER_SEC);
+	catch_up_sec = DIV_ROUND_UP(the_chip->catch_up_time_us, USEC_PER_SEC);
+	pr_debug("cts= %d catch_up_sec = %d\n", chg_time_sec, catch_up_sec);
+
+	/*
+	 * if we have been charging for more than catch_up time simply return
+	 * new soc
+	 */
+	if (chg_time_sec > catch_up_sec)
+		return new_soc;
+
+	numerator = (catch_up_sec - chg_time_sec) * prev_soc
+			+ chg_time_sec * new_soc;
+	scaled_soc = numerator / catch_up_sec;
+
+	pr_debug("cts = %d new_soc = %d prev_soc = %d scaled_soc = %d\n",
+			chg_time_sec, new_soc, prev_soc, scaled_soc);
+
+	return scaled_soc;
+}
+
+static bool is_shutdown_soc_within_limits(struct pm8921_bms_chip *chip, int soc)
+{
+	if (shutdown_soc_invalid) {
+		pr_debug("NOT forcing shutdown soc = %d\n", chip->shutdown_soc);
+		return 0;
+	}
+
+	if (abs(chip->shutdown_soc - soc) > chip->shutdown_soc_valid_limit) {
+		pr_debug("rejecting shutdown soc = %d, soc = %d limit = %d\n",
+			chip->shutdown_soc, soc,
+			chip->shutdown_soc_valid_limit);
+		shutdown_soc_invalid = 1;
+		return 0;
+	}
+
+	return 1;
+}
 /*
  * Remaining Usable Charge = remaining_charge (charge at ocv instance)
  *				- coloumb counter charge
@@ -1606,9 +1946,14 @@
 	int remaining_charge_uah, soc;
 	int cc_uah;
 	int rbatt;
-	int shutdown_adjusted_soc;
 	int iavg_ua;
-	int delta_time_us;
+	int delta_time_s;
+	int new_ocv;
+	int new_rc_uah;
+	int new_ucc_uah;
+	int new_rbatt;
+	int shutdown_soc;
+	static int firsttime = 1;
 
 	calculate_soc_params(chip, raw, batt_temp, chargecycles,
 						&fcc_uah,
@@ -1617,7 +1962,7 @@
 						&cc_uah,
 						&rbatt,
 						&iavg_ua,
-						&delta_time_us);
+						&delta_time_s);
 
 	/* calculate remaining usable charge */
 	remaining_usable_charge_uah = remaining_charge_uah
@@ -1630,13 +1975,43 @@
 						fcc_uah, unusable_charge_uah);
 		soc = 0;
 	} else {
-		soc = (remaining_usable_charge_uah * 100)
-			/ (fcc_uah - unusable_charge_uah);
+		soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
+					(fcc_uah - unusable_charge_uah));
+	}
+
+	if (firsttime && soc < 0) {
+		/*
+		 * first time calcualtion and the pon ocv  is too low resulting
+		 * in a bad soc. Adjust ocv such that we get 0 soc
+		 */
+		pr_debug("soc is %d, adjusting pon ocv to make it 0\n", soc);
+		adjust_rc_and_uuc_for_specific_soc(
+						chip,
+						batt_temp, chargecycles,
+						0,
+						fcc_uah, unusable_charge_uah,
+						cc_uah, remaining_charge_uah,
+						rbatt,
+						&new_ocv,
+						&new_rc_uah, &new_ucc_uah,
+						&new_rbatt);
+		chip->last_ocv_uv = new_ocv;
+		remaining_charge_uah = new_rc_uah;
+		unusable_charge_uah = new_ucc_uah;
+		rbatt = new_rbatt;
+
+		remaining_usable_charge_uah = remaining_charge_uah
+					- cc_uah
+					- unusable_charge_uah;
+
+		soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
+					(fcc_uah - unusable_charge_uah));
+		pr_debug("DONE for O soc is %d, pon ocv adjusted to %duV\n",
+				soc, chip->last_ocv_uv);
 	}
 
 	if (soc > 100)
 		soc = 100;
-	pr_debug("SOC = %u%%\n", soc);
 
 	if (bms_fake_battery != -EINVAL) {
 		pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
@@ -1658,30 +2033,210 @@
 		soc = 0;
 	}
 
-	soc = adjust_soc(chip, soc, batt_temp, rbatt,
-					fcc_uah, unusable_charge_uah, cc_uah);
+	mutex_lock(&soc_invalidation_mutex);
+	shutdown_soc = chip->shutdown_soc;
 
-	if (last_soc == -EINVAL || soc <= last_soc) {
-		last_soc = soc;
-	} else {
+	if (firsttime && soc != shutdown_soc
+			&& is_shutdown_soc_within_limits(chip, soc)) {
 		/*
-		 * soc > last_soc
-		 * the device must be charging for reporting a higher soc, if
-		 * not ignore this soc and continue reporting the last_soc
+		 * soc for the first time - use shutdown soc
+		 * to adjust pon ocv since it is a small percent away from
+		 * the real soc
 		 */
-		if (the_chip->start_percent != -EINVAL)
-			last_soc = soc;
-		else
-			pr_debug("soc = %d reporting last_soc = %d\n", soc,
-								last_soc);
+		pr_debug("soc = %d before forcing shutdown_soc = %d\n",
+							soc, shutdown_soc);
+		adjust_rc_and_uuc_for_specific_soc(
+						chip,
+						batt_temp, chargecycles,
+						shutdown_soc,
+						fcc_uah, unusable_charge_uah,
+						cc_uah, remaining_charge_uah,
+						rbatt,
+						&new_ocv,
+						&new_rc_uah, &new_ucc_uah,
+						&new_rbatt);
+
+		chip->pon_ocv_uv = chip->last_ocv_uv;
+		chip->last_ocv_uv = new_ocv;
+		remaining_charge_uah = new_rc_uah;
+		unusable_charge_uah = new_ucc_uah;
+		rbatt = new_rbatt;
+
+		remaining_usable_charge_uah = remaining_charge_uah
+					- cc_uah
+					- unusable_charge_uah;
+
+		soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
+					(fcc_uah - unusable_charge_uah));
+
+		pr_debug("DONE for shutdown_soc = %d soc is %d, adjusted ocv to %duV\n",
+				shutdown_soc, soc, chip->last_ocv_uv);
+	}
+	mutex_unlock(&soc_invalidation_mutex);
+
+	pr_debug("SOC before adjustment = %d\n", soc);
+	calculated_soc = adjust_soc(chip, soc, batt_temp, chargecycles,
+			rbatt, fcc_uah, unusable_charge_uah, cc_uah);
+
+	pr_debug("calculated SOC = %d\n", calculated_soc);
+	firsttime = 0;
+	return calculated_soc;
+}
+
+#define CALCULATE_SOC_MS	20000
+static void calculate_soc_work(struct work_struct *work)
+{
+	struct pm8921_bms_chip *chip = container_of(work,
+				struct pm8921_bms_chip,
+				calculate_soc_delayed_work.work);
+	int batt_temp, rc;
+	struct pm8xxx_adc_chan_result result;
+	struct pm8921_soc_params raw;
+	int soc;
+
+	rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
+	if (rc) {
+		pr_err("error reading adc channel = %d, rc = %d\n",
+					chip->batt_temp_channel, rc);
+		return;
+	}
+	pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+						result.measurement);
+	batt_temp = (int)result.physical;
+
+	mutex_lock(&chip->last_ocv_uv_mutex);
+	read_soc_params_raw(chip, &raw);
+
+	soc = calculate_state_of_charge(chip, &raw,
+					batt_temp, last_chargecycles);
+	mutex_unlock(&chip->last_ocv_uv_mutex);
+
+	schedule_delayed_work(&chip->calculate_soc_delayed_work,
+			round_jiffies_relative(msecs_to_jiffies
+			(CALCULATE_SOC_MS)));
+}
+
+static int report_state_of_charge(struct pm8921_bms_chip *chip)
+{
+	int soc = calculated_soc;
+	int delta_time_us;
+	struct timespec now;
+	struct pm8xxx_adc_chan_result result;
+	int batt_temp;
+	int rc;
+
+	rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
+	if (rc) {
+		pr_err("error reading adc channel = %d, rc = %d\n",
+					the_chip->batt_temp_channel, rc);
+		return rc;
+	}
+	pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+						result.measurement);
+	batt_temp = (int)result.physical;
+
+	do_posix_clock_monotonic_gettime(&now);
+	if (chip->t_soc_queried.tv_sec != 0) {
+		delta_time_us
+		= (now.tv_sec - chip->t_soc_queried.tv_sec) * USEC_PER_SEC
+			+ (now.tv_nsec - chip->t_soc_queried.tv_nsec) / 1000;
+	} else {
+		/* calculation for the first time */
+		delta_time_us = 0;
 	}
 
-	shutdown_adjusted_soc = adjust_for_shutdown_soc(chip, last_soc);
-	backup_soc(chip, shutdown_adjusted_soc);
+	/*
+	 * account for charge time - limit it to SOC_CATCHUP_SEC to
+	 * avoid overflows when charging continues for extended periods
+	 */
+	if (the_chip->start_percent != -EINVAL) {
+		if (the_chip->charge_time_us == 0) {
+			/*
+			 * calculating soc for the first time
+			 * after start of chg. Initialize catchup time
+			 */
+			if (abs(soc - last_soc) < MAX_CATCHUP_SOC)
+				the_chip->catch_up_time_us =
+				(soc - last_soc) * SOC_CATCHUP_SEC_PER_PERCENT
+					 * USEC_PER_SEC;
+			else
+				the_chip->catch_up_time_us =
+				SOC_CATCHUP_SEC_MAX * USEC_PER_SEC;
 
-	return shutdown_adjusted_soc;
+			if (the_chip->catch_up_time_us < 0)
+				the_chip->catch_up_time_us = 0;
+		}
+
+		/* add charge time */
+		if (the_chip->charge_time_us
+				< SOC_CATCHUP_SEC_MAX * USEC_PER_SEC)
+			chip->charge_time_us += delta_time_us;
+
+		/* end catchup if calculated soc and last soc are same */
+		if (last_soc == soc)
+			the_chip->catch_up_time_us = 0;
+	}
+
+	/* last_soc < soc  ... scale and catch up */
+	if (last_soc != -EINVAL && last_soc < soc && soc != 100)
+		soc = scale_soc_while_chg(chip, delta_time_us, soc, last_soc);
+
+	last_soc = soc;
+	backup_soc_and_iavg(chip, batt_temp, last_soc);
+	pr_debug("Reported SOC = %d\n", last_soc);
+	chip->t_soc_queried = now;
+
+	return last_soc;
 }
 
+void pm8921_bms_invalidate_shutdown_soc(void)
+{
+	int calculate_soc = 0;
+	struct pm8921_bms_chip *chip = the_chip;
+	int batt_temp, rc;
+	struct pm8xxx_adc_chan_result result;
+	struct pm8921_soc_params raw;
+	int soc;
+
+	pr_debug("Invalidating shutdown soc - the battery was removed\n");
+	if (shutdown_soc_invalid)
+		return;
+
+	mutex_lock(&soc_invalidation_mutex);
+	shutdown_soc_invalid = 1;
+	last_soc = -EINVAL;
+	if (the_chip) {
+		/* reset to pon ocv undoing what the adjusting did */
+		if (the_chip->pon_ocv_uv) {
+			the_chip->last_ocv_uv = the_chip->pon_ocv_uv;
+			calculate_soc = 1;
+			pr_debug("resetting ocv to pon_ocv = %d\n",
+						the_chip->pon_ocv_uv);
+		}
+	}
+	mutex_unlock(&soc_invalidation_mutex);
+	if (!calculate_soc)
+		return;
+
+	rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
+	if (rc) {
+		pr_err("error reading adc channel = %d, rc = %d\n",
+					chip->batt_temp_channel, rc);
+		return;
+	}
+	pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+						result.measurement);
+	batt_temp = (int)result.physical;
+
+	mutex_lock(&chip->last_ocv_uv_mutex);
+	read_soc_params_raw(chip, &raw);
+
+	soc = calculate_state_of_charge(chip, &raw,
+					batt_temp, last_chargecycles);
+	mutex_unlock(&chip->last_ocv_uv_mutex);
+}
+EXPORT_SYMBOL(pm8921_bms_invalidate_shutdown_soc);
+
 #define MIN_DELTA_625_UV	1000
 static void calib_hkadc(struct pm8921_bms_chip *chip)
 {
@@ -1690,10 +2245,11 @@
 	int usb_chg;
 	int this_delta;
 
+	mutex_lock(&chip->calib_mutex);
 	rc = pm8xxx_adc_read(the_chip->ref1p25v_channel, &result);
 	if (rc) {
 		pr_err("ADC failed for 1.25volts rc = %d\n", rc);
-		return;
+		goto out;
 	}
 	voltage = xoadc_reading_to_microvolt(result.adc_code);
 
@@ -1705,7 +2261,7 @@
 	rc = pm8xxx_adc_read(the_chip->ref625mv_channel, &result);
 	if (rc) {
 		pr_err("ADC failed for 1.25volts rc = %d\n", rc);
-		return;
+		goto out;
 	}
 	voltage = xoadc_reading_to_microvolt(result.adc_code);
 
@@ -1734,6 +2290,8 @@
 			chip->xoadc_v0625_usb_absent,
 			last_usb_cal_delta_uv);
 	}
+out:
+	mutex_unlock(&chip->calib_mutex);
 }
 
 static void calibrate_hkadc_work(struct work_struct *work)
@@ -1749,6 +2307,19 @@
 	schedule_work(&the_chip->calib_hkadc_work);
 }
 
+#define HKADC_CALIB_DELAY_MS	600000
+static void calibrate_hkadc_delayed_work(struct work_struct *work)
+{
+	struct pm8921_bms_chip *chip = container_of(work,
+				struct pm8921_bms_chip,
+				calib_hkadc_delayed_work.work);
+
+	calib_hkadc(chip);
+	schedule_delayed_work(&chip->calib_hkadc_delayed_work,
+			round_jiffies_relative(msecs_to_jiffies
+			(HKADC_CALIB_DELAY_MS)));
+}
+
 int pm8921_bms_get_vsense_avg(int *result)
 {
 	int rc = -EINVAL;
@@ -1794,33 +2365,12 @@
 
 int pm8921_bms_get_percent_charge(void)
 {
-	int batt_temp, rc;
-	struct pm8xxx_adc_chan_result result;
-	struct pm8921_soc_params raw;
-	int soc;
-
 	if (!the_chip) {
 		pr_err("called before initialization\n");
 		return -EINVAL;
 	}
 
-	rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
-	if (rc) {
-		pr_err("error reading adc channel = %d, rc = %d\n",
-					the_chip->batt_temp_channel, rc);
-		return rc;
-	}
-	pr_debug("batt_temp phy = %lld meas = 0x%llx", result.physical,
-						result.measurement);
-	batt_temp = (int)result.physical;
-
-	mutex_lock(&the_chip->last_ocv_uv_mutex);
-	read_soc_params_raw(the_chip, &raw);
-
-	soc = calculate_state_of_charge(the_chip, &raw,
-					batt_temp, last_chargecycles);
-	mutex_unlock(&the_chip->last_ocv_uv_mutex);
-	return soc;
+	return report_state_of_charge(the_chip);
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_get_percent_charge);
 
@@ -1835,7 +2385,7 @@
 	int cc_uah;
 	int rbatt;
 	int iavg_ua;
-	int delta_time_us;
+	int delta_time_s;
 
 	if (!the_chip) {
 		pr_err("called before initialization\n");
@@ -1863,7 +2413,7 @@
 						&cc_uah,
 						&rbatt,
 						&iavg_ua,
-						&delta_time_us);
+						&delta_time_s);
 	mutex_unlock(&the_chip->last_ocv_uv_mutex);
 
 	return rbatt;
@@ -1901,32 +2451,24 @@
 #define OCV_TOL_NO_OCV		0x00
 void pm8921_bms_charging_began(void)
 {
-	int batt_temp, rc;
-	struct pm8xxx_adc_chan_result result;
 	struct pm8921_soc_params raw;
 
-	rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
-	if (rc) {
-		pr_err("error reading adc channel = %d, rc = %d\n",
-				the_chip->batt_temp_channel, rc);
-		return;
-	}
-	pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
-						result.measurement);
-	batt_temp = (int)result.physical;
-
 	mutex_lock(&the_chip->last_ocv_uv_mutex);
 	read_soc_params_raw(the_chip, &raw);
-
-	the_chip->start_percent = calculate_state_of_charge(the_chip, &raw,
-					batt_temp, last_chargecycles);
 	mutex_unlock(&the_chip->last_ocv_uv_mutex);
 
+	the_chip->start_percent = report_state_of_charge(the_chip);
+
 	bms_start_percent = the_chip->start_percent;
 	bms_start_ocv_uv = raw.last_good_ocv_uv;
 	calculate_cc_uah(the_chip, raw.cc, &bms_start_cc_uah);
 	pm_bms_masked_write(the_chip, BMS_TOLERANCES,
 			IBAT_TOL_MASK, IBAT_TOL_DEFAULT);
+	the_chip->charge_time_us = 0;
+	the_chip->catch_up_time_us = 0;
+
+	the_chip->soc_at_cv = -EINVAL;
+	the_chip->prev_chg_soc = -EINVAL;
 	pr_debug("start_percent = %u%%\n", the_chip->start_percent);
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_charging_began);
@@ -1991,7 +2533,6 @@
 		last_real_fcc_mah = new_fcc_uah/1000;
 		last_real_fcc_batt_temp = batt_temp;
 		readjust_fcc_table();
-
 	}
 
 	if (is_battery_full) {
@@ -2005,7 +2546,7 @@
 		 * forget the old cc value
 		 */
 		the_chip->last_cc_uah = 0;
-		pr_debug("EOC ocv_reading = 0x%x cc = 0x%x\n",
+		pr_debug("EOC BATT_FULL ocv_reading = 0x%x cc = 0x%x\n",
 				the_chip->ocv_reading_at_100,
 				the_chip->cc_reading_at_100);
 	}
@@ -2031,6 +2572,10 @@
 			last_chargecycles);
 	the_chip->start_percent = -EINVAL;
 	the_chip->end_percent = -EINVAL;
+	the_chip->charge_time_us = 0;
+	the_chip->catch_up_time_us = 0;
+	the_chip->soc_at_cv = -EINVAL;
+	the_chip->prev_chg_soc = -EINVAL;
 	pm_bms_masked_write(the_chip, BMS_TOLERANCES,
 				IBAT_TOL_MASK, IBAT_TOL_NOCHG);
 }
@@ -2177,94 +2722,6 @@
 	return -EINVAL;
 }
 
-static int pm8921_bms_suspend(struct device *dev)
-{
-	int rc;
-	struct pm8xxx_adc_chan_result result;
-	struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
-	struct pm8921_soc_params raw;
-	int fcc_uah;
-	int remaining_charge_uah;
-	int cc_uah;
-
-	chip->batt_temp_suspend = 0;
-	rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
-	if (rc) {
-		pr_err("error reading adc channel = %d, rc = %d\n",
-					chip->batt_temp_channel, rc);
-	}
-	chip->batt_temp_suspend = (int)result.physical;
-
-	mutex_lock(&chip->last_ocv_uv_mutex);
-	read_soc_params_raw(chip, &raw);
-
-	fcc_uah = calculate_fcc_uah(chip,
-			chip->batt_temp_suspend, last_chargecycles);
-	pr_debug("FCC = %uuAh batt_temp = %d, cycles = %d\n",
-			fcc_uah, chip->batt_temp_suspend, last_chargecycles);
-	/* calculate remainging charge */
-	remaining_charge_uah = calculate_remaining_charge_uah(chip, &raw,
-					fcc_uah, chip->batt_temp_suspend,
-					last_chargecycles);
-	pr_debug("RC = %uuAh\n", remaining_charge_uah);
-
-	/* calculate cc micro_volt_hour */
-	calculate_cc_uah(chip, raw.cc, &cc_uah);
-	pr_debug("cc_uah = %duAh raw->cc = %x cc = %lld after subtracting %x\n",
-				cc_uah, raw.cc,
-				(int64_t)raw.cc - chip->cc_reading_at_100,
-				chip->cc_reading_at_100);
-	chip->soc_rbatt_suspend = ((remaining_charge_uah - cc_uah) * 100)
-						/ fcc_uah;
-	mutex_unlock(&chip->last_ocv_uv_mutex);
-
-	return 0;
-}
-
-#define DELTA_RBATT_PERCENT	10
-static int pm8921_bms_resume(struct device *dev)
-{
-	struct pm8921_rbatt_params raw;
-	struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
-	int rbatt;
-	int expected_rbatt;
-	int scalefactor;
-	int delta_rbatt;
-
-	read_rbatt_params_raw(chip, &raw);
-	rbatt = calculate_rbatt_resume(chip, &raw);
-
-	if (rbatt < 0)
-		return 0;
-
-	expected_rbatt
-		= (last_rbatt < 0) ? chip->default_rbatt_mohm : last_rbatt;
-
-	if (chip->rbatt_sf_lut) {
-		scalefactor = interpolate_scalingfactor(chip,
-						chip->rbatt_sf_lut,
-						chip->batt_temp_suspend / 10,
-						chip->soc_rbatt_suspend);
-		rbatt = rbatt * 100 / scalefactor;
-	}
-
-	delta_rbatt = expected_rbatt - rbatt;
-	if (delta_rbatt)
-		delta_rbatt = -delta_rbatt;
-	/*
-	 * only update last_rbatt if rbatt is within some
-	 * percent of expected_rbatt
-	 */
-	if (delta_rbatt * 100 <= DELTA_RBATT_PERCENT * expected_rbatt)
-		last_rbatt = rbatt;
-
-	return 0;
-}
-
-static const struct dev_pm_ops pm8921_pm_ops = {
-	.suspend	= pm8921_bms_suspend,
-	.resume		= pm8921_bms_resume,
-};
 #define EN_BMS_BIT	BIT(7)
 #define EN_PON_HS_BIT	BIT(0)
 static int __devinit pm8921_bms_hw_init(struct pm8921_bms_chip *chip)
@@ -2394,7 +2851,6 @@
 }
 
 enum bms_request_operation {
-	CALC_RBATT,
 	CALC_FCC,
 	CALC_PC,
 	CALC_SOC,
@@ -2455,18 +2911,13 @@
 	int ret = 0;
 	int ibat_ua, vbat_uv;
 	struct pm8921_soc_params raw;
-	struct pm8921_rbatt_params rraw;
 
 	read_soc_params_raw(the_chip, &raw);
-	read_rbatt_params_raw(the_chip, &rraw);
 
 	*val = 0;
 
 	/* global irq number passed in via data */
 	switch (param) {
-	case CALC_RBATT:
-		*val = calculate_rbatt_resume(the_chip, &rraw);
-		break;
 	case CALC_FCC:
 		*val = calculate_fcc_uah(the_chip, test_batt_temp,
 							test_chargecycle);
@@ -2525,10 +2976,8 @@
 	int param = (int)data;
 	int ret = 0;
 	struct pm8921_soc_params raw;
-	struct pm8921_rbatt_params rraw;
 
 	read_soc_params_raw(the_chip, &raw);
-	read_rbatt_params_raw(the_chip, &rraw);
 
 	*val = 0;
 
@@ -2540,15 +2989,6 @@
 	case LAST_GOOD_OCV_VALUE:
 		*val = raw.last_good_ocv_uv;
 		break;
-	case VBATT_FOR_RBATT:
-		*val = rraw.vbatt_for_rbatt_uv;
-		break;
-	case VSENSE_FOR_RBATT:
-		*val = rraw.vsense_for_rbatt_uv;
-		break;
-	case OCV_FOR_RBATT:
-		*val = rraw.ocv_for_rbatt_uv;
-		break;
 	case VSENSE_AVG:
 		read_vsense_avg(the_chip, (uint *)val);
 		break;
@@ -2644,8 +3084,6 @@
 	debugfs_create_file("read_vsense_avg", 0644, chip->dent,
 				(void *)VSENSE_AVG, &reading_fops);
 
-	debugfs_create_file("show_rbatt", 0644, chip->dent,
-				(void *)CALC_RBATT, &calc_fops);
 	debugfs_create_file("show_fcc", 0644, chip->dent,
 				(void *)CALC_FCC, &calc_fops);
 	debugfs_create_file("show_pc", 0644, chip->dent,
@@ -2751,13 +3189,22 @@
 	mutex_init(&chip->last_ocv_uv_mutex);
 	chip->dev = &pdev->dev;
 	chip->r_sense = pdata->r_sense;
-	chip->i_test = pdata->i_test;
-	chip->v_failure = pdata->v_failure;
+	chip->v_cutoff = pdata->v_cutoff;
 	chip->max_voltage_uv = pdata->max_voltage_uv;
+	chip->chg_term_ua = pdata->chg_term_ua;
 	chip->batt_type = pdata->battery_type;
 	chip->rconn_mohm = pdata->rconn_mohm;
 	chip->start_percent = -EINVAL;
 	chip->end_percent = -EINVAL;
+	chip->shutdown_soc_valid_limit = pdata->shutdown_soc_valid_limit;
+	chip->adjust_soc_low_threshold = pdata->adjust_soc_low_threshold;
+	if (chip->adjust_soc_low_threshold >= 45)
+		chip->adjust_soc_low_threshold = 45;
+
+	chip->prev_pc_unusable = -EINVAL;
+	chip->soc_at_cv = -EINVAL;
+
+	chip->ignore_shutdown_soc = pdata->ignore_shutdown_soc;
 	rc = set_battery_data(chip);
 	if (rc) {
 		pr_err("%s bad battery data %d\n", __func__, rc);
@@ -2781,7 +3228,14 @@
 	chip->batt_id_channel = pdata->bms_cdata.batt_id_channel;
 	chip->revision = pm8xxx_get_revision(chip->dev->parent);
 	chip->enable_fcc_learning = pdata->enable_fcc_learning;
+
+	mutex_init(&chip->calib_mutex);
 	INIT_WORK(&chip->calib_hkadc_work, calibrate_hkadc_work);
+	INIT_DELAYED_WORK(&chip->calib_hkadc_delayed_work,
+				calibrate_hkadc_delayed_work);
+
+	INIT_DELAYED_WORK(&chip->calculate_soc_delayed_work,
+			calculate_soc_work);
 
 	rc = request_irqs(chip, pdev);
 	if (rc) {
@@ -2795,7 +3249,7 @@
 		goto free_irqs;
 	}
 
-	read_shutdown_soc(chip);
+	read_shutdown_soc_and_iavg(chip);
 
 	platform_set_drvdata(pdev, chip);
 	the_chip = chip;
@@ -2808,20 +3262,20 @@
 	}
 	check_initial_ocv(chip);
 
-	/* initial hkadc calibration */
-	schedule_work(&chip->calib_hkadc_work);
+	/* start periodic hkadc calibration */
+	schedule_delayed_work(&chip->calib_hkadc_delayed_work, 0);
+
 	/* enable the vbatt reading interrupts for scheduling hkadc calib */
 	pm8921_bms_enable_irq(chip, PM8921_BMS_GOOD_OCV);
 	pm8921_bms_enable_irq(chip, PM8921_BMS_OCV_FOR_R);
 
-	INIT_DELAYED_WORK(&chip->uuc_timer_work, uuc_timer_work);
-	schedule_delayed_work(&chip->uuc_timer_work,
-					msecs_to_jiffies(UUC_TIMER_MS));
+	calculate_soc_work(&(chip->calculate_soc_delayed_work.work));
 
 	get_battery_uvolts(chip, &vbatt);
 	pr_info("OK battery_capacity_at_boot=%d volt = %d ocv = %d\n",
 				pm8921_bms_get_percent_charge(),
 				vbatt, chip->last_ocv_uv);
+
 	return 0;
 
 free_irqs:
@@ -2849,7 +3303,6 @@
 	.driver	= {
 		.name	= PM8921_BMS_DEV_NAME,
 		.owner	= THIS_MODULE,
-		.pm	= &pm8921_pm_ops
 	},
 };
 
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index bede625..d2724dd 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -284,6 +284,7 @@
 	u8				active_path;
 	int				ext_batt_health;
 	int				ext_batt_temp_monitor;
+	int				recent_reported_soc;
 };
 
 /* user space parameter to limit usb current */
@@ -344,6 +345,10 @@
 	return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
 }
 
+static int is_batfet_closed(struct pm8921_chg_chip *chip)
+{
+	return pm_chg_get_rt_status(chip, BATFET_IRQ);
+}
 #define CAPTURE_FSM_STATE_CMD	0xC2
 #define READ_BANK_7		0x70
 #define READ_BANK_4		0x40
@@ -1417,6 +1422,7 @@
 	if (percent_soc <= 10)
 		pr_warn("low battery charge = %d%%\n", percent_soc);
 
+	chip->recent_reported_soc = percent_soc;
 	return percent_soc;
 }
 
@@ -1770,6 +1776,15 @@
 }
 EXPORT_SYMBOL(pm8921_is_battery_present);
 
+int pm8921_is_batfet_closed(void)
+{
+	if (!the_chip) {
+		pr_err("called before init\n");
+		return -EINVAL;
+	}
+	return is_batfet_closed(the_chip);
+}
+EXPORT_SYMBOL(pm8921_is_batfet_closed);
 /*
  * Disabling the charge current limit causes current
  * current limits to have no monitoring. An adequate charger
@@ -2623,6 +2638,10 @@
 		}
 	} else if (active_path & DC_ACTIVE_BIT) {
 		pr_debug("DC charger active\n");
+		/* Some board designs are not prone to reverse boost on DC
+		 * charging path */
+		if (!chip->dc_unplug_check)
+			return;
 	} else {
 		/* No charger active */
 		if (!(is_usb_chg_plugged_in(chip)
@@ -2945,6 +2964,7 @@
  *		per update_time minutes
  *
  */
+#define LOW_SOC_HEARTBEAT_MS	20000
 static void update_heartbeat(struct work_struct *work)
 {
 	struct delayed_work *dwork = to_delayed_work(work);
@@ -2953,7 +2973,12 @@
 
 	pm_chg_failed_clear(chip, 1);
 	power_supply_changed(&chip->batt_psy);
-	schedule_delayed_work(&chip->update_heartbeat_work,
+	if (chip->recent_reported_soc <= 20)
+		schedule_delayed_work(&chip->update_heartbeat_work,
+			      round_jiffies_relative(msecs_to_jiffies
+						     (LOW_SOC_HEARTBEAT_MS)));
+	else
+		schedule_delayed_work(&chip->update_heartbeat_work,
 			      round_jiffies_relative(msecs_to_jiffies
 						     (chip->update_time)));
 }
@@ -2964,6 +2989,8 @@
 
 static int ichg_threshold_ua = -400000;
 module_param(ichg_threshold_ua, int, 0644);
+
+#define PM8921_CHG_VDDMAX_RES_MV	10
 static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip)
 {
 	int ichg_meas_ua, vbat_uv;
@@ -3023,9 +3050,11 @@
 		return;
 	}
 
+	adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
+					* PM8921_CHG_VDDMAX_RES_MV;
+
 	if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
 		adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
-
 	pr_debug("adjusting vdd_max_mv to %d to make "
 		"vbat_batt_termial_uv = %d to %d\n",
 		adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
@@ -4297,6 +4326,7 @@
 		chip->warm_temp_dc = INT_MIN;
 
 	chip->temp_check_period = pdata->temp_check_period;
+	chip->dc_unplug_check = pdata->dc_unplug_check;
 	chip->max_bat_chg_current = pdata->max_bat_chg_current;
 	chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
 	chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c
index 861bac8..e48257a 100644
--- a/drivers/power/pm8xxx-ccadc.c
+++ b/drivers/power/pm8xxx-ccadc.c
@@ -685,13 +685,13 @@
 		goto free_chip;
 	}
 
-	INIT_DELAYED_WORK(&chip->calib_ccadc_work, calibrate_ccadc_work);
-	schedule_delayed_work(&chip->calib_ccadc_work, 0);
 
 	disable_irq_nosync(chip->eoc_irq);
 
 	platform_set_drvdata(pdev, chip);
 	the_chip = chip;
+	INIT_DELAYED_WORK(&chip->calib_ccadc_work, calibrate_ccadc_work);
+	schedule_delayed_work(&chip->calib_ccadc_work, 0);
 
 	create_debugfs_entries(chip);
 
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index e87b4bd..352e60e 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -76,12 +76,29 @@
 	if (psy->set_property)
 		return psy->set_property(psy, POWER_SUPPLY_PROP_SCOPE,
 								&ret);
-
 	return -ENXIO;
 }
 EXPORT_SYMBOL_GPL(power_supply_set_scope);
 
 /**
+ * power_supply_set_supply_type - set type of the power supply
+ * @psy:	the power supply to control
+ * @supply_type:	sets type property of power supply
+ */
+int power_supply_set_supply_type(struct power_supply *psy,
+				enum power_supply_type supply_type)
+{
+	const union power_supply_propval ret = {supply_type,};
+
+	if (psy->set_property)
+		return psy->set_property(psy, POWER_SUPPLY_PROP_TYPE,
+								&ret);
+
+	return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(power_supply_set_supply_type);
+
+/**
  * power_supply_set_charge_type - set charge type of the power supply
  * @psy:	the power supply to control
  * @enable:	sets charge type property of power supply
diff --git a/drivers/regulator/qpnp-regulator.c b/drivers/regulator/qpnp-regulator.c
index 8d592fb..0e836c7 100644
--- a/drivers/regulator/qpnp-regulator.c
+++ b/drivers/regulator/qpnp-regulator.c
@@ -268,8 +268,8 @@
 };
 
 static struct qpnp_voltage_range ftsmps_ranges[] = {
-	VOLTAGE_RANGE(0,   80000,  350000, 1355000,  5000),
-	VOLTAGE_RANGE(1,  160000, 1360000, 2710000, 10000),
+	VOLTAGE_RANGE(0,       0,  350000, 1275000,  5000),
+	VOLTAGE_RANGE(1,       0, 1280000, 2040000, 10000),
 };
 
 static struct qpnp_voltage_range boost_ranges[] = {
@@ -982,16 +982,26 @@
 static int qpnp_regulator_match(struct qpnp_regulator *vreg)
 {
 	const struct qpnp_regulator_mapping *mapping;
+	struct device_node *node = vreg->spmi_dev->dev.of_node;
 	int rc, i;
 	u8 raw_type[2], type, subtype;
+	u32 type_reg[2];
 
-	rc = qpnp_vreg_read(vreg, QPNP_COMMON_REG_TYPE, raw_type, 2);
-	if (rc) {
-		vreg_err(vreg, "could not read type register, rc=%d\n", rc);
-		return rc;
+	rc = of_property_read_u32_array(node, "qcom,force-type",
+								type_reg, 2);
+	if (!rc) {
+		type = type_reg[0];
+		subtype = type_reg[1];
+	} else {
+		rc = qpnp_vreg_read(vreg, QPNP_COMMON_REG_TYPE, raw_type, 2);
+		if (rc) {
+			vreg_err(vreg,
+				"could not read type register, rc=%d\n", rc);
+			return rc;
+		}
+		type = raw_type[0];
+		subtype = raw_type[1];
 	}
-	type = raw_type[0];
-	subtype = raw_type[1];
 
 	rc = -ENODEV;
 	for (i = 0; i < ARRAY_SIZE(supported_regulators); i++) {
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 624b7ef..81f74dd 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -1754,9 +1754,6 @@
 		},
 	};
 
-	if (!dev->use_rx_msgqs)
-		goto init_rx_msgq;
-
 	bam_props.ee = dev->ee;
 	bam_props.virt_addr = dev->bam.base;
 	bam_props.phys_addr = bam_mem->start;
@@ -1792,7 +1789,7 @@
 	ret = msm_slim_init_rx_msgq(dev);
 	if (ret)
 		dev_err(dev->dev, "msm_slim_init_rx_msgq failed 0x%x\n", ret);
-	if (!dev->use_rx_msgqs && bam_handle) {
+	if (ret && bam_handle) {
 		sps_deregister_bam_device(bam_handle);
 		dev->bam.hdl = 0L;
 	}
@@ -1858,6 +1855,7 @@
 	struct resource		*bam_mem, *bam_io;
 	struct resource		*slim_mem, *slim_io;
 	struct resource		*irq, *bam_irq;
+	bool			rxreg_access = false;
 	slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						"slimbus_physical");
 	if (!slim_mem) {
@@ -1930,13 +1928,15 @@
 			dev_err(&pdev->dev, "Cell index not specified:%d", ret);
 			goto err_of_init_failed;
 		}
+		rxreg_access = of_property_read_bool(pdev->dev.of_node,
+					"qcom,rxreg-access");
 		/* Optional properties */
 		ret = of_property_read_u32(pdev->dev.of_node,
 					"qcom,min-clk-gear", &dev->ctrl.min_cg);
 		ret = of_property_read_u32(pdev->dev.of_node,
 					"qcom,max-clk-gear", &dev->ctrl.max_cg);
-		pr_err("min_cg:%d, max_cg:%d, ret:%d", dev->ctrl.min_cg,
-					dev->ctrl.max_cg, ret);
+		pr_debug("min_cg:%d, max_cg:%d, rxreg: %d", dev->ctrl.min_cg,
+					dev->ctrl.max_cg, rxreg_access);
 	} else {
 		dev->ctrl.nr = pdev->id;
 	}
@@ -1955,7 +1955,11 @@
 	mutex_init(&dev->tx_lock);
 	spin_lock_init(&dev->rx_lock);
 	dev->ee = 1;
-	dev->use_rx_msgqs = 1;
+	if (rxreg_access)
+		dev->use_rx_msgqs = 0;
+	else
+		dev->use_rx_msgqs = 1;
+
 	dev->irq = irq->start;
 	dev->bam.irq = bam_irq->start;
 
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index 3fd890c..e8295f4 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -2516,6 +2516,18 @@
 	u32 segdist;
 	struct slim_pending_ch *pch;
 
+	/*
+	 * If there are no pending changes from this client, avoid sending
+	 * the reconfiguration sequence
+	 */
+	if (sb->pending_msgsl == sb->cur_msgsl &&
+		list_empty(&sb->mark_define) &&
+		list_empty(&sb->mark_removal) &&
+		list_empty(&sb->mark_suspend)) {
+		pr_debug("SLIM_CL: skip reconfig sequence");
+		return 0;
+	}
+
 	mutex_lock(&ctrl->sched.m_reconf);
 	mutex_lock(&ctrl->m_ctrl);
 	/*
@@ -2568,7 +2580,6 @@
 		struct slim_ich *slc = &ctrl->chans[pch->chan];
 		slc->state = SLIM_CH_SUSPENDED;
 	}
-	mutex_unlock(&ctrl->m_ctrl);
 
 	ret = slim_allocbw(sb, &subframe, &clkgear);
 
@@ -2718,7 +2729,6 @@
 			NULL, 0, 3, NULL, 0, NULL);
 	dev_dbg(&ctrl->dev, "reconfig now:ret:%d\n", ret);
 	if (!ret) {
-		mutex_lock(&ctrl->m_ctrl);
 		ctrl->sched.subfrmcode = subframe;
 		ctrl->clkgear = clkgear;
 		ctrl->sched.msgsl = ctrl->sched.pending_msgsl;
@@ -2730,7 +2740,6 @@
 	}
 
 revert_reconfig:
-	mutex_lock(&ctrl->m_ctrl);
 	/* Revert channel changes */
 	slim_chan_changes(sb, true);
 	mutex_unlock(&ctrl->m_ctrl);
@@ -2973,6 +2982,7 @@
 	mutex_unlock(&ctrl->sched.m_reconf);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(slim_ctrl_clk_pause);
 
 MODULE_LICENSE("GPL v2");
 MODULE_VERSION("0.1");
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index f2c881d..9f3327a 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1818,6 +1818,14 @@
 			goto err_probe_exit;
 		}
 
+		rc = of_property_read_u32(pdev->dev.of_node,
+				"cell-index", &pdev->id);
+		if (rc)
+			dev_warn(&pdev->dev,
+				"using default bus_num %d\n", pdev->id);
+		else
+			master->bus_num = pdev->id;
+
 		for (i = 0; i < ARRAY_SIZE(spi_rsrcs); ++i) {
 			dd->spi_gpios[i] = of_get_gpio_flags(pdev->dev.of_node,
 								i, &flags);
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index 422e99e..ae1eff8 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -79,6 +79,7 @@
 #define PMIC_ARB_MAX_PERIPHS		256
 #define PMIC_ARB_PERIPH_ID_VALID	(1 << 15)
 #define PMIC_ARB_TIMEOUT_US		100
+#define PMIC_ARB_MAX_TRANS_BYTES	(8)
 
 #define PMIC_ARB_APID_MASK				0xFF
 #define PMIC_ARB_PPID_MASK				0xFFF
@@ -160,49 +161,29 @@
 	return -ETIMEDOUT;
 }
 
+/**
+ * pa_read_data: reads pmic-arb's register and copy 1..4 bytes to buf
+ * @bc byte count -1. range: 0..3
+ * @reg register's address
+ * @buf output parameter, length must be bc+1
+ */
 static void pa_read_data(struct spmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc)
 {
 	u32 data = pmic_arb_read(dev, reg);
-
-	switch (bc & 0x3) {
-	case 3:
-		*buf++ = data & 0xff;
-		data >>= 8;
-	case 2:
-		*buf++ = data & 0xff;
-		data >>= 8;
-	case 1:
-		*buf++ = data & 0xff;
-		data >>= 8;
-	case 0:
-		*buf++ = data & 0xff;
-	default:
-		break;
-	}
+	memcpy(buf, &data, (bc & 3) + 1);
 }
 
+/**
+ * pa_write_data: write 1..4 bytes from buf to pmic-arb's register
+ * @bc byte-count -1. range: 0..3
+ * @reg register's address
+ * @buf buffer to write. length must be bc+1
+ */
 static void
 pa_write_data(struct spmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc)
 {
 	u32 data = 0;
-
-	switch (bc & 0x3) {
-	case 3:
-		data = (buf[0]|buf[1]<<8|buf[2]<<16|buf[3]<<24);
-		break;
-	case 2:
-		data = (buf[0]|buf[1]<<8|buf[2]<<16);
-		break;
-	case 1:
-		data = (buf[0]|buf[1]<<8);
-		break;
-	case 0:
-		data = (buf[0]);
-		break;
-	default:
-		break;
-	}
-
+	memcpy(&data, buf, (bc & 3) + 1);
 	pmic_arb_write(dev, reg, data);
 }
 
@@ -238,6 +219,12 @@
 	u32 cmd;
 	int rc;
 
+	if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
+		dev_err(pmic_arb->dev
+		, "pmic-arb supports 1..%d bytes per trans, but:%d requested"
+					, PMIC_ARB_MAX_TRANS_BYTES, bc+1);
+		return  -EINVAL;
+	}
 	pr_debug("op:0x%x sid:%d bc:%d addr:0x%x\n", opc, sid, bc, addr);
 
 	/* Check the opcode */
@@ -259,11 +246,12 @@
 		goto done;
 
 	/* Read from FIFO, note 'bc' is actually number of bytes minus 1 */
-	pa_read_data(pmic_arb, buf, PMIC_ARB_RDATA0(pmic_arb->channel), bc);
+	pa_read_data(pmic_arb, buf, PMIC_ARB_RDATA0(pmic_arb->channel)
+							, min_t(u8, bc, 3));
 
 	if (bc > 3)
 		pa_read_data(pmic_arb, buf + 4,
-				PMIC_ARB_RDATA1(pmic_arb->channel), bc);
+				PMIC_ARB_RDATA1(pmic_arb->channel), bc - 4);
 
 done:
 	spin_unlock_irqrestore(&pmic_arb->lock, flags);
@@ -278,6 +266,12 @@
 	u32 cmd;
 	int rc;
 
+	if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
+		dev_err(pmic_arb->dev
+		, "pmic-arb supports 1..%d bytes per trans, but:%d requested"
+					, PMIC_ARB_MAX_TRANS_BYTES, bc+1);
+		return  -EINVAL;
+	}
 	pr_debug("op:0x%x sid:%d bc:%d addr:0x%x\n", opc, sid, bc, addr);
 
 	/* Check the opcode */
@@ -296,11 +290,11 @@
 
 	/* Write data to FIFOs */
 	spin_lock_irqsave(&pmic_arb->lock, flags);
-	pa_write_data(pmic_arb, buf, PMIC_ARB_WDATA0(pmic_arb->channel), bc);
-
+	pa_write_data(pmic_arb, buf, PMIC_ARB_WDATA0(pmic_arb->channel)
+							, min_t(u8, bc, 3));
 	if (bc > 3)
 		pa_write_data(pmic_arb, buf + 4,
-				PMIC_ARB_WDATA1(pmic_arb->channel), bc);
+				PMIC_ARB_WDATA1(pmic_arb->channel), bc - 4);
 
 	/* Start the transaction */
 	pmic_arb_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd);
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index 5d79bd2..42a5a71 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -695,7 +695,7 @@
 		ret = -EINVAL;
 		goto done;
 	}
-	if ((asma->vm_start + asma->size) > (vma->vm_start + vma->vm_end)) {
+	if ((asma->vm_start + asma->size) > vma->vm_end) {
 		ret = -EINVAL;
 		goto done;
 	}
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index b2d2f74..d082273 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -75,7 +75,7 @@
 
 config THERMAL_MONITOR
 	bool "Monitor thermal state and limit CPU Frequency"
-	depends on THERMAL_TSENS8960
+	depends on THERMAL_TSENS8960 || THERMAL_TSENS8974
 	depends on CPU_FREQ_MSM
 	default n
 	help
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 6628b79..3366bba 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -60,19 +60,40 @@
 #define TSENS2_POINT1_MASK		0x3f00000
 #define TSENS3_POINT1_MASK		0xfc000000
 #define TSENS4_POINT1_MASK		0x3f
-#define TSENS5_POINT1_MASK		0xfc00
+#define TSENS5_POINT1_MASK		0xfc0
 #define TSENS6_POINT1_MASK		0x3f000
 #define TSENS7_POINT1_MASK		0xfc0000
 #define TSENS8_POINT1_MASK		0x3f000000
 #define TSENS9_POINT1_MASK		0x3f
 #define TSENS10_POINT1_MASK		0xfc00
 #define TSENS_CAL_SEL_0_1		0xc0000000
-#define TSENS_CAL_SEL_2			BIT(30)
+#define TSENS_CAL_SEL_2			0x40000000
 #define TSENS_CAL_SEL_SHIFT		30
 #define TSENS_CAL_SEL_SHIFT_2		28
-#define TSENS_ONE_POINT_CALIB		0x3
+#define TSENS_ONE_POINT_CALIB		0x1
 #define TSENS_TWO_POINT_CALIB		0x2
 
+#define TSENS0_POINT1_SHIFT		8
+#define TSENS1_POINT1_SHIFT		14
+#define TSENS2_POINT1_SHIFT		20
+#define TSENS3_POINT1_SHIFT		26
+#define TSENS5_POINT1_SHIFT		6
+#define TSENS6_POINT1_SHIFT		12
+#define TSENS7_POINT1_SHIFT		18
+#define TSENS8_POINT1_SHIFT		24
+#define TSENS10_POINT1_SHIFT		6
+
+#define TSENS_POINT2_BASE_SHIFT		12
+#define TSENS0_POINT2_SHIFT		20
+#define TSENS1_POINT2_SHIFT		26
+#define TSENS3_POINT2_SHIFT		6
+#define TSENS4_POINT2_SHIFT		12
+#define TSENS5_POINT2_SHIFT		18
+#define TSENS6_POINT2_SHIFT		24
+#define TSENS8_POINT2_SHIFT		6
+#define TSENS9_POINT2_SHIFT		12
+#define TSENS10_POINT2_SHIFT		18
+
 #define TSENS_BASE2_MASK		0xff000
 #define TSENS0_POINT2_MASK		0x3f00000
 #define TSENS1_POINT2_MASK		0xfc000000
@@ -97,11 +118,11 @@
 #define TSENS_THRESHOLD_MAX_CODE	0x3ff
 #define TSENS_THRESHOLD_MIN_CODE	0x0
 
-#define TSENS_CTRL_INIT_DATA1		0x3fffff9
-#define TSENS_GLOBAL_INIT_DATA		0x20013
-#define TSENS_S0_MAIN_CFG_INIT_DATA	0x1ba
+#define TSENS_CTRL_INIT_DATA1		0x1cfff9
+#define TSENS_GLOBAL_INIT_DATA		0x302f16c
+#define TSENS_S0_MAIN_CFG_INIT_DATA	0x1c3
 #define TSENS_SN_MIN_MAX_STATUS_CTRL_DATA	0x3ffc00
-#define TSENS_SN_REMOTE_CFG_DATA	0xdba
+#define TSENS_SN_REMOTE_CFG_DATA	0x11c3
 
 /* Trips: warm and cool */
 enum tsens_trip_type {
@@ -141,27 +162,26 @@
 static int tsens_tz_code_to_degc(int adc_code, int sensor_num)
 {
 	int degcbeforefactor, degc;
-	degcbeforefactor = (adc_code *
-			tmdev->sensor[sensor_num].slope_mul_tsens_factor
-			+ tmdev->sensor[sensor_num].offset);
+	degcbeforefactor = ((adc_code * tmdev->tsens_factor) -
+				tmdev->sensor[sensor_num].offset)/
+			tmdev->sensor[sensor_num].slope_mul_tsens_factor;
 
 	if (degcbeforefactor == 0)
 		degc = degcbeforefactor;
 	else if (degcbeforefactor > 0)
-		degc = (degcbeforefactor + tmdev->tsens_factor/2)
-				/ tmdev->tsens_factor;
+		degc = ((degcbeforefactor * tmdev->tsens_factor) +
+				tmdev->tsens_factor/2)/tmdev->tsens_factor;
 	else
-		degc = (degcbeforefactor - tmdev->tsens_factor/2)
-				/ tmdev->tsens_factor;
+		degc = ((degcbeforefactor * tmdev->tsens_factor) -
+				tmdev->tsens_factor/2)/tmdev->tsens_factor;
+
 	return degc;
 }
 
 static int tsens_tz_degc_to_code(int degc, int sensor_num)
 {
-	int code = (degc * tmdev->tsens_factor -
-		tmdev->sensor[sensor_num].offset
-		+ tmdev->sensor[sensor_num].slope_mul_tsens_factor/2)
-		/ tmdev->sensor[sensor_num].slope_mul_tsens_factor;
+	int code = ((degc * tmdev->sensor[sensor_num].slope_mul_tsens_factor)
+		+ tmdev->sensor[sensor_num].offset)/tmdev->tsens_factor;
 
 	if (code > TSENS_THRESHOLD_MAX_CODE)
 		code = TSENS_THRESHOLD_MAX_CODE;
@@ -212,7 +232,7 @@
 
 	return 0;
 }
-EXPORT_SYMBOL(msm_tsens_get_temp);
+EXPORT_SYMBOL(tsens_get_temp);
 
 static int tsens_tz_get_mode(struct thermal_zone_device *thermal,
 			      enum thermal_device_mode *mode)
@@ -474,118 +494,150 @@
 
 static int tsens_calib_sensors(void)
 {
-	int i, tsens_base1_data, tsens0_point1, tsens1_point1;
-	int tsens2_point1, tsens3_point1, tsens4_point1, tsens5_point1;
-	int tsens6_point1, tsens7_point1, tsens8_point1, tsens9_point1;
-	int tsens10_point1, tsens0_point2, tsens1_point2, tsens2_point2;
-	int tsens3_point2, tsens4_point2, tsens5_point2, tsens6_point2;
-	int tsens7_point2, tsens8_point2, tsens9_point2, tsens10_point2;
-	int tsens_base2_data, tsens_calibration_mode, temp;
+	int i, tsens_base1_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
+	int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0;
+	int tsens5_point1 = 0, tsens6_point1 = 0, tsens7_point1 = 0;
+	int tsens8_point1 = 0, tsens9_point1 = 0, tsens10_point1 = 0;
+	int tsens0_point2 = 0, tsens1_point2 = 0, tsens2_point2 = 0;
+	int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
+	int tsens6_point2 = 0, tsens7_point2 = 0, tsens8_point2 = 0;
+	int tsens9_point2 = 0, tsens10_point2 = 0;
+	int tsens_base2_data = 0, tsens_calibration_mode = 0, temp = 0;
 	uint32_t calib_data[5];
 
 	for (i = 0; i < 5; i++)
 		calib_data[i] = readl_relaxed(tmdev->tsens_calib_addr
 					+ (i * TSENS_SN_ADDR_OFFSET));
 
-	tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1
-			>> TSENS_CAL_SEL_SHIFT);
-	temp = (calib_data[3] & TSENS_CAL_SEL_2
-			>> TSENS_CAL_SEL_SHIFT_2);
+	tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1)
+			>> TSENS_CAL_SEL_SHIFT;
+	temp = (calib_data[3] & TSENS_CAL_SEL_2)
+			>> TSENS_CAL_SEL_SHIFT_2;
 	tsens_calibration_mode |= temp;
-	/* Remove this after bringup */
-	tsens_calibration_mode = TSENS_ONE_POINT_CALIB;
 
-	if (!tsens_calibration_mode) {
-		pr_err("TSENS not calibrated\n");
-		return -ENODEV;
+	if (tsens_calibration_mode == 0) {
+		pr_debug("TSENS is calibrationless mode\n");
+		for (i = 0; i < tmdev->tsens_num_sensor; i++) {
+			tmdev->sensor[i].calib_data_point2 = 780;
+			tmdev->sensor[i].calib_data_point1 = 492;
+		}
+		goto compute_intercept_slope;
 	} else if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB ||
 				TSENS_TWO_POINT_CALIB) {
-		tsens_base1_data = calib_data[0] & TSENS_BASE1_MASK;
-		tsens0_point1 = calib_data[0] & TSENS0_POINT1_MASK;
-		tsens1_point1 = calib_data[0] & TSENS1_POINT1_MASK;
-		tsens2_point1 = calib_data[0] & TSENS2_POINT1_MASK;
-		tsens3_point1 = calib_data[0] & TSENS3_POINT1_MASK;
-		tsens4_point1 = calib_data[1] & TSENS4_POINT1_MASK;
-		tsens5_point1 = calib_data[1] & TSENS5_POINT1_MASK;
-		tsens6_point1 = calib_data[1] & TSENS6_POINT1_MASK;
-		tsens7_point1 = calib_data[1] & TSENS7_POINT1_MASK;
-		tsens8_point1 = calib_data[1] & TSENS8_POINT1_MASK;
-		tsens9_point1 = calib_data[2] & TSENS9_POINT1_MASK;
-		tsens10_point1 = calib_data[2] & TSENS10_POINT1_MASK;
+		tsens_base1_data = (calib_data[0] & TSENS_BASE1_MASK);
+		tsens0_point1 = (calib_data[0] & TSENS0_POINT1_MASK) >>
+							TSENS0_POINT1_SHIFT;
+		tsens1_point1 = (calib_data[0] & TSENS1_POINT1_MASK) >>
+							TSENS1_POINT1_SHIFT;
+		tsens2_point1 = (calib_data[0] & TSENS2_POINT1_MASK) >>
+							TSENS2_POINT1_SHIFT;
+		tsens3_point1 = (calib_data[0] & TSENS3_POINT1_MASK) >>
+							TSENS3_POINT1_SHIFT;
+		tsens4_point1 = (calib_data[1] & TSENS4_POINT1_MASK);
+		tsens5_point1 = (calib_data[1] & TSENS5_POINT1_MASK) >>
+							TSENS5_POINT1_SHIFT;
+		tsens6_point1 = (calib_data[1] & TSENS6_POINT1_MASK) >>
+							TSENS6_POINT1_SHIFT;
+		tsens7_point1 = (calib_data[1] & TSENS7_POINT1_MASK) >>
+							TSENS7_POINT1_SHIFT;
+		tsens8_point1 = (calib_data[1] & TSENS8_POINT1_MASK) >>
+							TSENS8_POINT1_SHIFT;
+		tsens9_point1 = (calib_data[2] & TSENS9_POINT1_MASK);
+		tsens10_point1 = (calib_data[2] & TSENS10_POINT1_MASK) >>
+							TSENS10_POINT1_SHIFT;
 	} else if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
-		tsens_base2_data = calib_data[2] & TSENS_BASE2_MASK;
-		tsens0_point2 = calib_data[2] & TSENS0_POINT2_MASK;
-		tsens1_point2 = calib_data[2] & TSENS1_POINT2_MASK;
-		tsens2_point2 = calib_data[3] & TSENS2_POINT2_MASK;
-		tsens3_point2 = calib_data[3] & TSENS3_POINT2_MASK;
-		tsens4_point2 = calib_data[3] & TSENS4_POINT2_MASK;
-		tsens5_point2 = calib_data[3] & TSENS5_POINT2_MASK;
-		tsens6_point2 = calib_data[3] & TSENS6_POINT2_MASK;
-		tsens7_point2 = calib_data[4] & TSENS7_POINT2_MASK;
-		tsens8_point2 = calib_data[4] & TSENS8_POINT2_MASK;
-		tsens9_point2 = calib_data[4] & TSENS9_POINT2_MASK;
-		tsens10_point2 = calib_data[4] & TSENS10_POINT2_MASK;
-	} else
+		tsens_base2_data = (calib_data[2] & TSENS_BASE2_MASK) >>
+						TSENS_POINT2_BASE_SHIFT;
+		tsens0_point2 = (calib_data[2] & TSENS0_POINT2_MASK) >>
+						TSENS0_POINT2_SHIFT;
+		tsens1_point2 = (calib_data[2] & TSENS1_POINT2_MASK) >>
+						TSENS1_POINT2_SHIFT;
+		tsens2_point2 = (calib_data[3] & TSENS2_POINT2_MASK);
+		tsens3_point2 = (calib_data[3] & TSENS3_POINT2_MASK) >>
+						TSENS3_POINT2_SHIFT;
+		tsens4_point2 = (calib_data[3] & TSENS4_POINT2_MASK) >>
+						TSENS4_POINT2_SHIFT;
+		tsens5_point2 = (calib_data[3] & TSENS5_POINT2_MASK) >>
+						TSENS5_POINT2_SHIFT;
+		tsens6_point2 = (calib_data[3] & TSENS6_POINT2_MASK) >>
+						TSENS6_POINT2_SHIFT;
+		tsens7_point2 = (calib_data[4] & TSENS7_POINT2_MASK);
+		tsens8_point2 = (calib_data[4] & TSENS8_POINT2_MASK) >>
+						TSENS8_POINT2_SHIFT;
+		tsens9_point2 = (calib_data[4] & TSENS9_POINT2_MASK) >>
+						TSENS9_POINT2_SHIFT;
+		tsens10_point2 = (calib_data[4] & TSENS10_POINT2_MASK) >>
+						TSENS10_POINT2_SHIFT;
+	} else {
 		pr_debug("Calibration mode is unknown: %d\n",
 						tsens_calibration_mode);
+		return -ENODEV;
+	}
 
-	tmdev->sensor[0].calib_data_point1 =
+	if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB ||
+					TSENS_TWO_POINT_CALIB) {
+		tmdev->sensor[0].calib_data_point1 =
 		(((tsens_base1_data + tsens0_point1) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[0].calib_data_point2 =
-		(((tsens_base2_data + tsens0_point2) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[1].calib_data_point1 =
+		tmdev->sensor[1].calib_data_point1 =
 		(((tsens_base1_data + tsens1_point1) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[1].calib_data_point2 =
-		(((tsens_base2_data + tsens1_point2) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[2].calib_data_point1 =
+		tmdev->sensor[2].calib_data_point1 =
 		(((tsens_base1_data + tsens2_point1) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[2].calib_data_point2 =
-		(((tsens_base2_data + tsens2_point2) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[3].calib_data_point1 =
+		tmdev->sensor[3].calib_data_point1 =
 		(((tsens_base1_data + tsens3_point1) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[3].calib_data_point2 =
-		(((tsens_base2_data + tsens3_point2) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[4].calib_data_point1 =
+		tmdev->sensor[4].calib_data_point1 =
 		(((tsens_base1_data + tsens4_point1) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[4].calib_data_point2 =
-		(((tsens_base2_data + tsens4_point2) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[5].calib_data_point1 =
+		tmdev->sensor[5].calib_data_point1 =
 		(((tsens_base1_data + tsens5_point1) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[5].calib_data_point2 =
-		(((tsens_base2_data + tsens5_point2) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[6].calib_data_point1 =
+		tmdev->sensor[6].calib_data_point1 =
 		(((tsens_base1_data + tsens6_point1) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[6].calib_data_point2 =
-		(((tsens_base2_data + tsens6_point2) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[7].calib_data_point1 =
+		tmdev->sensor[7].calib_data_point1 =
 		(((tsens_base1_data + tsens7_point1) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[7].calib_data_point2 =
-		(((tsens_base2_data + tsens7_point2) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[8].calib_data_point1 =
+		tmdev->sensor[8].calib_data_point1 =
 		(((tsens_base1_data + tsens8_point1) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[8].calib_data_point2 =
-		(((tsens_base2_data + tsens8_point2) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[9].calib_data_point1 =
+		tmdev->sensor[9].calib_data_point1 =
 		(((tsens_base1_data + tsens9_point1) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[9].calib_data_point2 =
-		(((tsens_base2_data + tsens9_point2) < 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[10].calib_data_point1 =
+		tmdev->sensor[10].calib_data_point1 =
 		(((tsens_base1_data + tsens10_point1) << 2) | TSENS_BIT_APPEND);
-	tmdev->sensor[10].calib_data_point2 =
-		(((tsens_base2_data + tsens10_point2) << 2) | TSENS_BIT_APPEND);
+	}
 
+	if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+		tmdev->sensor[0].calib_data_point2 =
+		(((tsens_base2_data + tsens0_point2) << 2) | TSENS_BIT_APPEND);
+		tmdev->sensor[1].calib_data_point2 =
+		(((tsens_base2_data + tsens1_point2) << 2) | TSENS_BIT_APPEND);
+		tmdev->sensor[2].calib_data_point2 =
+		(((tsens_base2_data + tsens2_point2) << 2) | TSENS_BIT_APPEND);
+		tmdev->sensor[3].calib_data_point2 =
+		(((tsens_base2_data + tsens3_point2) << 2) | TSENS_BIT_APPEND);
+		tmdev->sensor[4].calib_data_point2 =
+		(((tsens_base2_data + tsens4_point2) << 2) | TSENS_BIT_APPEND);
+		tmdev->sensor[5].calib_data_point2 =
+		(((tsens_base2_data + tsens5_point2) << 2) | TSENS_BIT_APPEND);
+		tmdev->sensor[6].calib_data_point2 =
+		(((tsens_base2_data + tsens6_point2) << 2) | TSENS_BIT_APPEND);
+		tmdev->sensor[7].calib_data_point2 =
+		(((tsens_base2_data + tsens7_point2) << 2) | TSENS_BIT_APPEND);
+		tmdev->sensor[8].calib_data_point2 =
+		(((tsens_base2_data + tsens8_point2) << 2) | TSENS_BIT_APPEND);
+		tmdev->sensor[9].calib_data_point2 =
+		(((tsens_base2_data + tsens9_point2) << 2) | TSENS_BIT_APPEND);
+		tmdev->sensor[10].calib_data_point2 =
+		(((tsens_base2_data + tsens10_point2) << 2) | TSENS_BIT_APPEND);
+	}
+
+compute_intercept_slope:
 	for (i = 0; i < tmdev->tsens_num_sensor; i++) {
 		int32_t num = 0, den = 0;
-		num = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT2;
-		den = tmdev->sensor[i].calib_data_point2 -
+		if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
+			num = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT2;
+			den = tmdev->sensor[i].calib_data_point2 -
 					tmdev->sensor[i].calib_data_point1;
-		num *= tmdev->tsens_factor;
-		if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)
+			num *= tmdev->tsens_factor;
 			tmdev->sensor[i].slope_mul_tsens_factor = num/den;
-		tmdev->sensor[i].offset = (TSENS_CAL_DEGC_POINT1 *
-			tmdev->tsens_factor)
-			- (tmdev->sensor[i].calib_data_point1 *
-			tmdev->sensor[i].slope_mul_tsens_factor);
+		}
+		tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
+			tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
+				tmdev->sensor[i].slope_mul_tsens_factor);
 		INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
 		tmdev->prev_reading_avail = false;
 	}
@@ -615,7 +667,7 @@
 	}
 
 	rc = of_property_read_u32_array(of_node,
-		"qcom,slope", tsens_slope_data, tsens_num_sensors/sizeof(u32));
+		"qcom,slope", tsens_slope_data, tsens_num_sensors);
 	if (rc) {
 		dev_err(&pdev->dev, "invalid or missing property: tsens-slope\n");
 		return rc;
@@ -734,6 +786,7 @@
 		goto fail;
 
 	tsens_hw_init();
+
 	tmdev->prev_reading_avail = true;
 
 	platform_set_drvdata(pdev, tmdev);
@@ -758,7 +811,7 @@
 
 static int __devinit _tsens_register_thermal(void)
 {
-	struct platform_device *pdev = tmdev->pdev;
+	struct platform_device *pdev;
 	int rc, i;
 
 	if (!tmdev) {
@@ -766,6 +819,8 @@
 		return -ENODEV;
 	}
 
+	pdev = tmdev->pdev;
+
 	for (i = 0; i < tmdev->tsens_num_sensor; i++) {
 		char name[18];
 		snprintf(name, sizeof(name), "tsens_tz_sensor%d", i);
@@ -781,6 +836,7 @@
 			goto fail;
 		}
 	}
+
 	rc = request_irq(tmdev->tsens_irq, tsens_isr,
 		IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
 	if (rc < 0) {
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 0575d80..2dd2592 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -21,6 +21,8 @@
 #include <linux/cpufreq.h>
 #include <linux/msm_tsens.h>
 #include <linux/msm_thermal.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
 #include <mach/cpufreq.h>
 
 static int enabled;
@@ -176,7 +178,7 @@
 module_param_cb(enabled, &module_ops, &enabled, 0644);
 MODULE_PARM_DESC(enabled, "enforce thermal limit on cpu");
 
-int __init msm_thermal_init(struct msm_thermal_data *pdata)
+int __devinit msm_thermal_init(struct msm_thermal_data *pdata)
 {
 	int ret = 0;
 
@@ -190,3 +192,64 @@
 
 	return ret;
 }
+
+static int __devinit msm_thermal_dev_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	char *key = NULL;
+	struct device_node *node = pdev->dev.of_node;
+	struct msm_thermal_data data;
+
+	memset(&data, 0, sizeof(struct msm_thermal_data));
+	key = "qcom,sensor-id";
+	ret = of_property_read_u32(node, key, &data.sensor_id);
+	if (ret)
+		goto fail;
+	WARN_ON(data.sensor_id >= TSENS_MAX_SENSORS);
+
+	key = "qcom,poll-ms";
+	ret = of_property_read_u32(node, key, &data.poll_ms);
+	if (ret)
+		goto fail;
+
+	key = "qcom,limit-temp";
+	ret = of_property_read_u32(node, key, &data.limit_temp_degC);
+	if (ret)
+		goto fail;
+
+	key = "qcom,temp-hysteresis";
+	ret = of_property_read_u32(node, key, &data.temp_hysteresis_degC);
+	if (ret)
+		goto fail;
+
+	key = "qcom,freq-step";
+	ret = of_property_read_u32(node, key, &data.freq_step);
+
+fail:
+	if (ret)
+		pr_err("%s: Failed reading node=%s, key=%s\n",
+		       __func__, node->full_name, key);
+	else
+		ret = msm_thermal_init(&data);
+
+	return ret;
+}
+
+static struct of_device_id msm_thermal_match_table[] = {
+	{.compatible = "qcom,msm-thermal"},
+	{},
+};
+
+static struct platform_driver msm_thermal_device_driver = {
+	.probe = msm_thermal_dev_probe,
+	.driver = {
+		.name = "msm-thermal",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_thermal_match_table,
+	},
+};
+
+int __init msm_thermal_device_init(void)
+{
+	return platform_driver_register(&msm_thermal_device_driver);
+}
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index cb09de3..1385e08 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -274,6 +274,7 @@
 	struct mutex mutex_lha0;
 
 	int is_initialized;
+	int platform_devs_registered;
 	int in_reset;
 	int ld_open_count;
 	struct tty_struct *tty;
@@ -359,6 +360,7 @@
 static void smux_uart_power_on_atomic(void);
 static int smux_rx_flow_control_updated(struct smux_lch_t *ch);
 static void smux_flush_workqueues(void);
+static void smux_pdev_release(struct device *dev);
 
 /**
  * Convert TTY Error Flags to string for logging purposes.
@@ -3362,6 +3364,8 @@
 				void *data)
 {
 	unsigned long flags;
+	int i;
+	int tmp;
 	int power_off_uart = 0;
 
 	if (code == SUBSYS_BEFORE_SHUTDOWN) {
@@ -3370,6 +3374,25 @@
 		smux.in_reset = 1;
 		mutex_unlock(&smux.mutex_lha0);
 		return NOTIFY_DONE;
+	} else if (code == SUBSYS_AFTER_POWERUP) {
+		/* re-register platform devices */
+		SMUX_DBG("%s: ssr - after power-up\n", __func__);
+		mutex_lock(&smux.mutex_lha0);
+		if (smux.ld_open_count > 0
+				&& !smux.platform_devs_registered) {
+			for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
+				SMUX_DBG("%s: register pdev '%s'\n",
+					__func__, smux_devs[i].name);
+				smux_devs[i].dev.release = smux_pdev_release;
+				tmp = platform_device_register(&smux_devs[i]);
+				if (tmp)
+					pr_err("%s: error %d registering device %s\n",
+					   __func__, tmp, smux_devs[i].name);
+			}
+			smux.platform_devs_registered = 1;
+		}
+		mutex_unlock(&smux.mutex_lha0);
+		return NOTIFY_DONE;
 	} else if (code != SUBSYS_AFTER_SHUTDOWN) {
 		return NOTIFY_DONE;
 	}
@@ -3378,23 +3401,34 @@
 	/* Cleanup channels */
 	smux_flush_workqueues();
 	mutex_lock(&smux.mutex_lha0);
-	smux_lch_purge();
-	if (smux.tty)
-		tty_driver_flush_buffer(smux.tty);
+	if (smux.ld_open_count > 0) {
+		smux_lch_purge();
+		if (smux.tty)
+			tty_driver_flush_buffer(smux.tty);
 
-	/* Power-down UART */
-	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
-	if (smux.power_state != SMUX_PWR_OFF) {
-		SMUX_PWR("%s: SSR - turning off UART\n", __func__);
-		smux.power_state = SMUX_PWR_OFF;
-		power_off_uart = 1;
+		/* Unregister platform devices */
+		if (smux.platform_devs_registered) {
+			for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
+				SMUX_DBG("%s: unregister pdev '%s'\n",
+						__func__, smux_devs[i].name);
+				platform_device_unregister(&smux_devs[i]);
+			}
+			smux.platform_devs_registered = 0;
+		}
+
+		/* Power-down UART */
+		spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+		if (smux.power_state != SMUX_PWR_OFF) {
+			SMUX_PWR("%s: SSR - turning off UART\n", __func__);
+			smux.power_state = SMUX_PWR_OFF;
+			power_off_uart = 1;
+		}
+		smux.powerdown_enabled = 0;
+		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+		if (power_off_uart)
+			smux_uart_power_off_atomic();
 	}
-	smux.powerdown_enabled = 0;
-	spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
-
-	if (power_off_uart)
-		smux_uart_power_off_atomic();
-
 	smux.tx_activity_flag = 0;
 	smux.rx_activity_flag = 0;
 	smux.rx_state = SMUX_RX_IDLE;
@@ -3468,6 +3502,7 @@
 			pr_err("%s: error %d registering device %s\n",
 				   __func__, tmp, smux_devs[i].name);
 	}
+	smux.platform_devs_registered = 1;
 	mutex_unlock(&smux.mutex_lha0);
 	return 0;
 }
@@ -3494,10 +3529,13 @@
 	smux_lch_purge();
 
 	/* Unregister platform devices */
-	for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
-		SMUX_DBG("%s: unregister pdev '%s'\n",
-				__func__, smux_devs[i].name);
-		platform_device_unregister(&smux_devs[i]);
+	if (smux.platform_devs_registered) {
+		for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
+			SMUX_DBG("%s: unregister pdev '%s'\n",
+					__func__, smux_devs[i].name);
+			platform_device_unregister(&smux_devs[i]);
+		}
+		smux.platform_devs_registered = 0;
 	}
 
 	/* Schedule UART power-up if it's down */
@@ -3643,6 +3681,7 @@
 	smux.ld_open_count = 0;
 	smux.in_reset = 0;
 	smux.is_initialized = 1;
+	smux.platform_devs_registered = 0;
 	smux_byte_loopback = 0;
 
 	spin_lock_init(&smux.tx_lock_lha2);
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index 987008df..f065eaa 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -1384,13 +1384,12 @@
 	if (!gsbi_resource)
 		gsbi_resource = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 	msm_hsl_port->clk = clk_get(&pdev->dev, "core_clk");
-	if (gsbi_resource) {
+	msm_hsl_port->pclk = clk_get(&pdev->dev, "iface_clk");
+
+	if (gsbi_resource)
 		msm_hsl_port->is_uartdm = 1;
-		msm_hsl_port->pclk = clk_get(&pdev->dev, "iface_clk");
-	} else {
+	else
 		msm_hsl_port->is_uartdm = 0;
-		msm_hsl_port->pclk = NULL;
-	}
 
 	if (unlikely(IS_ERR(msm_hsl_port->clk))) {
 		printk(KERN_ERR "%s: Error getting clk\n", __func__);
diff --git a/drivers/tty/smux_ctl.c b/drivers/tty/smux_ctl.c
index 0078b04..7e0e6f8 100644
--- a/drivers/tty/smux_ctl.c
+++ b/drivers/tty/smux_ctl.c
@@ -33,6 +33,7 @@
 #include <linux/smux.h>
 #include <linux/slab.h>
 #include <linux/debugfs.h>
+#include <linux/poll.h>
 
 #include <asm/ioctls.h>
 
@@ -753,6 +754,33 @@
 	return ret;
 }
 
+static unsigned int smux_ctl_poll(struct file *file, poll_table *wait)
+{
+	struct smux_ctl_dev *devp;
+	unsigned int mask = 0;
+	int readable;
+
+	devp = file->private_data;
+	if (!devp)
+		return -ENODEV;
+
+	SMUXCTL_DBG(SMUX_CTL_MODULE_NAME ": %s called on smuxctl%d\n",
+			__func__, devp->id);
+
+	poll_wait(file, &devp->read_wait_queue, wait);
+
+	readable = smux_ctl_readable(devp->id);
+	if (readable < 0) {
+		pr_err(SMUX_CTL_MODULE_NAME ": %s err%d during poll for smuxctl%d\n",
+			__func__, readable, devp->id);
+		mask = POLLERR;
+	} else if (readable) {
+		mask = POLLIN | POLLRDNORM;
+	}
+
+	return mask;
+}
+
 static const struct file_operations smux_ctl_fops = {
 	.owner = THIS_MODULE,
 	.open = smux_ctl_open,
@@ -760,6 +788,7 @@
 	.read = smux_ctl_read,
 	.write = smux_ctl_write,
 	.unlocked_ioctl = smux_ctl_ioctl,
+	.poll = smux_ctl_poll,
 };
 
 static void smux_ctl_reset_channel(struct smux_ctl_dev *devp)
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 91e326f..3d29607 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -463,6 +463,8 @@
 			int count;
 			char *char_buf;
 			unsigned char *flag_buf;
+			unsigned int left = 0;
+			unsigned int max_space;
 
 			count = head->commit - head->read;
 			if (!count) {
@@ -477,10 +479,33 @@
 			   line discipline as we want to empty the queue */
 			if (test_bit(TTY_FLUSHPENDING, &tty->flags))
 				break;
+
+			/* update receive room */
+			spin_lock(&tty->read_lock);
+			if (tty->update_room_in_ldisc) {
+				if ((tty->read_cnt == N_TTY_BUF_SIZE - 1) &&
+					(tty->receive_room ==
+						N_TTY_BUF_SIZE - 1))
+					tty->rr_bug++;
+				left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+			}
+			spin_unlock(&tty->read_lock);
+
 			if (!tty->receive_room)
 				break;
-			if (count > tty->receive_room)
-				count = tty->receive_room;
+
+			if (tty->update_room_in_ldisc && !left) {
+				schedule_work(&tty->buf.work);
+				break;
+			}
+
+			if (tty->update_room_in_ldisc)
+				max_space = min(left, tty->receive_room);
+			else
+				max_space = tty->receive_room;
+
+			if (count > max_space)
+				count = max_space;
 			char_buf = head->char_buf_ptr + head->read;
 			flag_buf = head->flag_buf_ptr + head->read;
 			head->read += count;
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 136c6d9..522e3a4 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -43,27 +43,29 @@
  *  USB DBM Hardware registers.
  *
  */
-#define DBM_EP_CFG(n)		(0x00 + 4 * (n))
-#define DBM_DATA_FIFO(n)	(0x10 + 4 * (n))
-#define DBM_DATA_FIFO_SIZE(n)	(0x20 + 4 * (n))
-#define DBM_DATA_FIFO_EN	(0x30)
-#define DBM_GEVNTADR		(0x34)
-#define DBM_GEVNTSIZ		(0x38)
-#define DBM_DBG_CNFG		(0x3C)
-#define DBM_HW_TRB0_EP(n)	(0x40 + 4 * (n))
-#define DBM_HW_TRB1_EP(n)	(0x50 + 4 * (n))
-#define DBM_HW_TRB2_EP(n)	(0x60 + 4 * (n))
-#define DBM_HW_TRB3_EP(n)	(0x70 + 4 * (n))
-#define DBM_PIPE_CFG		(0x80)
-#define DBM_SOFT_RESET		(0x84)
+#define DBM_BASE		0x000F8000
+#define DBM_EP_CFG(n)		(DBM_BASE + (0x00 + 4 * (n)))
+#define DBM_DATA_FIFO(n)	(DBM_BASE + (0x10 + 4 * (n)))
+#define DBM_DATA_FIFO_SIZE(n)	(DBM_BASE + (0x20 + 4 * (n)))
+#define DBM_DATA_FIFO_EN	(DBM_BASE + (0x30))
+#define DBM_GEVNTADR		(DBM_BASE + (0x34))
+#define DBM_GEVNTSIZ		(DBM_BASE + (0x38))
+#define DBM_DBG_CNFG		(DBM_BASE + (0x3C))
+#define DBM_HW_TRB0_EP(n)	(DBM_BASE + (0x40 + 4 * (n)))
+#define DBM_HW_TRB1_EP(n)	(DBM_BASE + (0x50 + 4 * (n)))
+#define DBM_HW_TRB2_EP(n)	(DBM_BASE + (0x60 + 4 * (n)))
+#define DBM_HW_TRB3_EP(n)	(DBM_BASE + (0x70 + 4 * (n)))
+#define DBM_PIPE_CFG		(DBM_BASE + (0x80))
+#define DBM_SOFT_RESET		(DBM_BASE + (0x84))
+#define DBM_GEN_CFG		(DBM_BASE + (0x88))
 
 /**
  *  USB DBM  Hardware registers bitmask.
  *
  */
 /* DBM_EP_CFG */
-#define DBM_EN_EP		0x00000000
-#define DBM_USB3_EP_NUM		0x0000003E
+#define DBM_EN_EP		0x00000001
+#define USB3_EPNUM		0x0000003E
 #define DBM_BAM_PIPE_NUM	0x000000C0
 #define DBM_PRODUCER		0x00000100
 #define DBM_DISABLE_WB		0x00000200
@@ -83,8 +85,9 @@
 #define DBM_SFT_RST_EP1		0x00000002
 #define DBM_SFT_RST_EP2		0x00000004
 #define DBM_SFT_RST_EP3		0x00000008
-#define DBM_SFT_RST_EPS		0x0000000F
-#define DBM_SFT_RST		0x80000000
+#define DBM_SFT_RST_EPS_MASK	0x0000000F
+#define DBM_SFT_RST_MASK	0x80000000
+#define DBM_EN_MASK		0x00000002
 
 #define DBM_MAX_EPS		4
 
@@ -93,17 +96,18 @@
 #define DBM_TRB_DATA_SRC	0x40000000
 #define DBM_TRB_DMA		0x20000000
 #define DBM_TRB_EP_NUM(ep)	(ep<<24)
+
 /**
  *  USB QSCRATCH Hardware registers
  *
  */
 #define QSCRATCH_REG_OFFSET	(0x000F8800)
+#define QSCRATCH_GENERAL_CFG	(QSCRATCH_REG_OFFSET + 0x08)
 #define CHARGING_DET_CTRL_REG	(QSCRATCH_REG_OFFSET + 0x18)
 #define CHARGING_DET_OUTPUT_REG	(QSCRATCH_REG_OFFSET + 0x1C)
 #define ALT_INTERRUPT_EN_REG	(QSCRATCH_REG_OFFSET + 0x20)
 #define HS_PHY_IRQ_STAT_REG	(QSCRATCH_REG_OFFSET + 0x24)
 
-
 struct dwc3_msm_req_complete {
 	struct list_head list_item;
 	struct usb_request *req;
@@ -271,21 +275,6 @@
 }
 
 /**
- * Return DBM EP number which is not already configured.
- *
- */
-static int dwc3_msm_find_avail_dbm_ep(void)
-{
-	int i;
-
-	for (i = 0; i < context->dbm_num_eps; i++)
-		if (!context->ep_num_mapping[i])
-			return i;
-
-	return -ENODEV; /* Not found */
-}
-
-/**
  * Return DBM EP number according to usb endpoint number.
  *
  */
@@ -339,12 +328,21 @@
  * Reset the DBM registers upon initialization.
  *
  */
-static int dwc3_msm_dbm_soft_reset(void)
+static int dwc3_msm_dbm_soft_reset(int enter_reset)
 {
 	dev_dbg(context->dev, "%s\n", __func__);
-
-	dwc3_msm_write_reg_field(context->base, DBM_SOFT_RESET,
-		DBM_SFT_RST, 1);
+	if (enter_reset) {
+		dev_dbg(context->dev, "enter DBM reset\n");
+		dwc3_msm_write_reg_field(context->base, DBM_SOFT_RESET,
+			DBM_SFT_RST_MASK, 1);
+	} else {
+		dev_dbg(context->dev, "exit DBM reset\n");
+		dwc3_msm_write_reg_field(context->base, DBM_SOFT_RESET,
+			DBM_SFT_RST_MASK, 0);
+		/*enable DBM*/
+		dwc3_msm_write_reg_field(context->base, QSCRATCH_GENERAL_CFG,
+			DBM_EN_MASK, 0x1);
+	}
 
 	return 0;
 }
@@ -371,10 +369,10 @@
 
 	if (enter_reset) {
 		dwc3_msm_write_reg_field(context->base, DBM_SOFT_RESET,
-			DBM_SFT_RST_EPS, 1 << dbm_ep);
+			DBM_SFT_RST_EPS_MASK & 1 << dbm_ep, 1);
 	} else {
 		dwc3_msm_write_reg_field(context->base, DBM_SOFT_RESET,
-			DBM_SFT_RST_EPS, 0);
+			DBM_SFT_RST_EPS_MASK & 1 << dbm_ep, 0);
 	}
 
 	return 0;
@@ -397,36 +395,39 @@
 				  bool internal_mem, bool ioc)
 {
 	u8 dbm_ep;
-	u8 ioc_mask;
+	u32 ep_cfg;
 
 	dev_dbg(context->dev, "%s\n", __func__);
 
-	dbm_ep = dwc3_msm_find_avail_dbm_ep();
+	dbm_ep = dwc3_msm_find_matching_dbm_ep(usb_ep);
+
 	if (dbm_ep < 0) {
-		dev_err(context->dev, "%s: No more DBM eps\n", __func__);
+		dev_err(context->dev,
+				"%s: Invalid usb ep index\n", __func__);
 		return -ENODEV;
 	}
-
-	context->ep_num_mapping[dbm_ep] = usb_ep;
-
 	/* First, reset the dbm endpoint */
-	dwc3_msm_dbm_ep_soft_reset(dbm_ep, false);
+	dwc3_msm_dbm_ep_soft_reset(dbm_ep, 0);
 
-	ioc_mask = dwc3_msm_read_reg_field(context->base, DBM_DBG_CNFG,
-		DBM_ENABLE_IOC_MASK);
-	ioc_mask &= ~(ioc << dbm_ep); /* Clear ioc bit for dbm_ep */
 	/* Set ioc bit for dbm_ep if needed */
 	dwc3_msm_write_reg_field(context->base, DBM_DBG_CNFG,
-		DBM_ENABLE_IOC_MASK, ioc_mask | (ioc << dbm_ep));
+		DBM_ENABLE_IOC_MASK & 1 << dbm_ep, ioc ? 1 : 0);
 
-	dwc3_msm_write_reg(context->base, DBM_EP_CFG(dbm_ep),
-		producer | disable_wb | internal_mem);
+	ep_cfg = (producer ? DBM_PRODUCER : 0) |
+		(disable_wb ? DBM_DISABLE_WB : 0) |
+		(internal_mem ? DBM_INT_RAM_ACC : 0);
+
 	dwc3_msm_write_reg_field(context->base, DBM_EP_CFG(dbm_ep),
-		DBM_USB3_EP_NUM, usb_ep);
+		DBM_PRODUCER | DBM_DISABLE_WB | DBM_INT_RAM_ACC, ep_cfg >> 8);
+
+	dwc3_msm_write_reg_field(context->base, DBM_EP_CFG(dbm_ep), USB3_EPNUM,
+		usb_ep);
 	dwc3_msm_write_reg_field(context->base, DBM_EP_CFG(dbm_ep),
 		DBM_BAM_PIPE_NUM, bam_pipe);
-	dwc3_msm_write_reg_field(context->base, DBM_EP_CFG(dbm_ep),
-		DBM_EN_EP, 1);
+	dwc3_msm_write_reg_field(context->base, DBM_PIPE_CFG, 0x000000ff,
+		0xe4);
+	dwc3_msm_write_reg_field(context->base, DBM_EP_CFG(dbm_ep), DBM_EN_EP,
+		1);
 
 	return dbm_ep;
 }
@@ -471,20 +472,16 @@
  * @size - size of data fifo.
  *
  */
-int msm_data_fifo_config(struct usb_ep *ep, u32 addr, u32 size)
+int msm_data_fifo_config(struct usb_ep *ep, u32 addr, u32 size, u8 dst_pipe_idx)
 {
 	u8 dbm_ep;
 	struct dwc3_ep *dep = to_dwc3_ep(ep);
+	u8 bam_pipe = dst_pipe_idx;
 
 	dev_dbg(context->dev, "%s\n", __func__);
 
-	dbm_ep = dwc3_msm_find_matching_dbm_ep(dep->number);
-
-	if (dbm_ep >= context->dbm_num_eps) {
-		dev_err(context->dev,
-				"%s: Invalid DBM ep index\n", __func__);
-		return -ENODEV;
-	}
+	dbm_ep = bam_pipe;
+	context->ep_num_mapping[dbm_ep] = dep->number;
 
 	dwc3_msm_write_reg(context->base, DBM_DATA_FIFO(dbm_ep), addr);
 	dwc3_msm_write_reg_field(context->base, DBM_DATA_FIFO_SIZE(dbm_ep),
@@ -547,7 +544,8 @@
 	 * taken by the caller of this function (dwc3_gadget_giveback()).
 	 */
 	request->complete = req_complete->orig_complete;
-	request->complete(ep, request);
+	if (request->complete)
+		request->complete(ep, request);
 
 	kfree(req_complete);
 }
@@ -585,18 +583,18 @@
 	memset(trb, 0, sizeof(*trb));
 
 	req->trb = trb;
-	req->trb_dma = dwc3_trb_dma_offset(dep, trb);
-	trb->bph = DBM_TRB_BIT | DBM_TRB_DATA_SRC |
-		   DBM_TRB_DMA | DBM_TRB_EP_NUM(dep->number);
+	trb->bph = DBM_TRB_BIT | DBM_TRB_DMA | DBM_TRB_EP_NUM(dep->number);
 	trb->size = DWC3_TRB_SIZE_LENGTH(req->request.length);
 	trb->ctrl = DWC3_TRBCTL_NORMAL | DWC3_TRB_CTRL_HWO | DWC3_TRB_CTRL_CHN;
+	req->trb_dma = dwc3_trb_dma_offset(dep, trb);
 
 	/* Second, prepare a Link TRB that points to the first TRB*/
 	trb_link = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
 	dep->free_slot++;
+	memset(trb_link, 0, sizeof *trb_link);
 
 	trb_link->bpl = lower_32_bits(req->trb_dma);
-	trb_link->bph = DBM_TRB_BIT | DBM_TRB_DATA_SRC |
+	trb_link->bph = DBM_TRB_BIT |
 			DBM_TRB_DMA | DBM_TRB_EP_NUM(dep->number);
 	trb_link->size = 0;
 	trb_link->ctrl = DWC3_TRBCTL_LINK_TRB | DWC3_TRB_CTRL_HWO;
@@ -605,8 +603,9 @@
 	 * Now start the transfer
 	 */
 	memset(&params, 0, sizeof(params));
-	params.param0 = upper_32_bits(req->trb_dma);
-	params.param1 = lower_32_bits(req->trb_dma);
+	params.param0 = 0; /* TDAddr High */
+	params.param1 = lower_32_bits(req->trb_dma); /* DAddr Low */
+
 	cmd = DWC3_DEPCMD_STARTTRANSFER;
 	ret = dwc3_send_gadget_ep_cmd(dep->dwc, dep->number, cmd, &params);
 	if (ret < 0) {
@@ -657,6 +656,7 @@
 	bool disable_wb;
 	bool internal_mem;
 	bool ioc;
+	u8 speed;
 
 	if (!(request->udc_priv & MSM_SPS_MODE)) {
 		/* Not SPS mode, call original queue */
@@ -707,17 +707,9 @@
 	request->complete = dwc3_msm_req_complete_func;
 
 	/*
-	 * Configure dbm event buffers if this is the first
-	 * dbm endpoint we about to configure.
-	 */
-	if (0 == dwc3_msm_configured_dbm_ep_num())
-		dwc3_msm_event_buffer_config(dwc->ev_buffs[0]->dma,
-					     dwc->ev_buffs[0]->length);
-
-	/*
 	 * Configure the DBM endpoint
 	 */
-	bam_pipe = (request->udc_priv & MSM_PIPE_ID_MASK);
+	bam_pipe = request->udc_priv & MSM_PIPE_ID_MASK;
 	producer = ((request->udc_priv & MSM_PRODUCER) ? true : false);
 	disable_wb = ((request->udc_priv & MSM_DISABLE_WB) ? true : false);
 	internal_mem = ((request->udc_priv & MSM_INTERNAL_MEM) ? true : false);
@@ -752,6 +744,9 @@
 		return ret;
 	}
 
+	speed = dwc3_readl(dwc->regs, DWC3_DSTS) & DWC3_DSTS_CONNECTSPD;
+	dwc3_msm_write_reg(context->base, DBM_GEN_CFG, speed >> 2);
+
 	return 0;
 }
 
@@ -1551,7 +1546,12 @@
 	}
 
 	/* Reset the DBM */
-	dwc3_msm_dbm_soft_reset();
+	dwc3_msm_dbm_soft_reset(1);
+	usleep_range(1000, 1200);
+	dwc3_msm_dbm_soft_reset(0);
+
+	dwc3_msm_event_buffer_config(dwc3_readl(msm->base, DWC3_GEVNTADRLO(0)),
+		dwc3_readl(msm->base, DWC3_GEVNTSIZ(0)));
 
 	msm->otg_xceiv = usb_get_transceiver();
 	if (msm->otg_xceiv) {
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index e64c5ff..ca6dc64 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -45,6 +45,7 @@
 #include "composite.c"
 
 #include "f_diag.c"
+#include "f_qdss.c"
 #include "f_rmnet_smd.c"
 #include "f_rmnet_sdio.c"
 #include "f_rmnet_smd_sdio.c"
@@ -76,6 +77,7 @@
 #include "u_bam_data.c"
 #include "f_mbim.c"
 #include "f_qc_ecm.c"
+#include "f_qc_rndis.c"
 #include "u_qc_ether.c"
 #ifdef CONFIG_TARGET_CORE
 #include "f_tcm.c"
@@ -102,7 +104,7 @@
 	char *dev_name;
 	struct device_attribute **attributes;
 
-	/* for android_dev.enabled_functions */
+	/* for android_conf.enabled_functions */
 	struct list_head enabled_list;
 
 	struct android_dev *android_dev;
@@ -130,8 +132,8 @@
 };
 
 struct android_dev {
+	const char *name;
 	struct android_usb_function **functions;
-	struct list_head enabled_functions;
 	struct usb_composite_dev *cdev;
 	struct device *dev;
 
@@ -146,9 +148,23 @@
 	struct pm_qos_request pm_qos_req_dma;
 	struct work_struct work;
 
+	/* A list of struct android_configuration */
+	struct list_head configs;
+	int configs_num;
+
+	/* A list node inside the android_dev_list */
 	struct list_head list_item;
 
-	struct usb_configuration config;
+};
+
+struct android_configuration {
+	struct usb_configuration usb_config;
+
+	/* A list of the functions supported by this config */
+	struct list_head enabled_functions;
+
+	/* A list node inside the struct android_dev.configs list */
+	struct list_head list_item;
 };
 
 static struct class *android_class;
@@ -157,6 +173,10 @@
 static int android_bind_config(struct usb_configuration *c);
 static void android_unbind_config(struct usb_configuration *c);
 static struct android_dev *cdev_to_android_dev(struct usb_composite_dev *cdev);
+static struct android_configuration *alloc_android_config
+						(struct android_dev *dev);
+static void free_android_config(struct android_dev *dev,
+				struct android_configuration *conf);
 
 /* string IDs are assigned dynamically */
 #define STRING_MANUFACTURER_IDX		0
@@ -299,13 +319,17 @@
 static void android_enable(struct android_dev *dev)
 {
 	struct usb_composite_dev *cdev = dev->cdev;
+	struct android_configuration *conf;
 
 	if (WARN_ON(!dev->disable_depth))
 		return;
 
 	if (--dev->disable_depth == 0) {
-		usb_add_config(cdev, &dev->config,
-					android_bind_config);
+
+		list_for_each_entry(conf, &dev->configs, list_item)
+			usb_add_config(cdev, &conf->usb_config,
+						android_bind_config);
+
 		usb_gadget_connect(cdev->gadget);
 	}
 }
@@ -313,12 +337,15 @@
 static void android_disable(struct android_dev *dev)
 {
 	struct usb_composite_dev *cdev = dev->cdev;
+	struct android_configuration *conf;
 
 	if (dev->disable_depth++ == 0) {
 		usb_gadget_disconnect(cdev->gadget);
 		/* Cancel pending control requests */
 		usb_ep_dequeue(cdev->gadget->ep0, cdev->req);
-		usb_remove_config(cdev, &dev->config);
+
+		list_for_each_entry(conf, &dev->configs, list_item)
+			usb_remove_config(cdev, &conf->usb_config);
 	}
 }
 
@@ -739,6 +766,37 @@
 	.attributes	= diag_function_attributes,
 };
 
+/* DEBUG */
+static int qdss_function_init(struct android_usb_function *f,
+	struct usb_composite_dev *cdev)
+{
+	return qdss_setup();
+}
+
+static void qdss_function_cleanup(struct android_usb_function *f)
+{
+	qdss_cleanup();
+}
+
+static int qdss_function_bind_config(struct android_usb_function *f,
+					struct usb_configuration *c)
+{
+	int  err = -1;
+
+	err = qdss_bind_config(c, "qdss");
+	if (err)
+		pr_err("qdss: Cannot open channel qdss");
+
+	return err;
+}
+
+static struct android_usb_function qdss_function = {
+	.name		= "qdss",
+	.init		= qdss_function_init,
+	.cleanup	= qdss_function_cleanup,
+	.bind_config	= qdss_function_bind_config,
+};
+
 /* SERIAL */
 static char serial_transports[32];	/*enabled FSERIAL ports - "tty[,sdio]"*/
 static ssize_t serial_transports_store(
@@ -1117,6 +1175,7 @@
 struct rndis_function_config {
 	u8      ethaddr[ETH_ALEN];
 	u32     vendorID;
+	u8      max_pkt_per_xfer;
 	char	manufacturer[256];
 	/* "Wireless" RNDIS; auto-detected by Windows */
 	bool	wceis;
@@ -1138,6 +1197,22 @@
 	f->config = NULL;
 }
 
+static int rndis_qc_function_init(struct android_usb_function *f,
+					struct usb_composite_dev *cdev)
+{
+	f->config = kzalloc(sizeof(struct rndis_function_config), GFP_KERNEL);
+	if (!f->config)
+		return -ENOMEM;
+
+	return rndis_qc_init();
+}
+
+static void rndis_qc_function_cleanup(struct android_usb_function *f)
+{
+	rndis_qc_cleanup();
+	kfree(f->config);
+}
+
 static int
 rndis_function_bind_config(struct android_usb_function *f,
 		struct usb_configuration *c)
@@ -1176,12 +1251,56 @@
 					   rndis->manufacturer);
 }
 
+static int rndis_qc_function_bind_config(struct android_usb_function *f,
+					struct usb_configuration *c)
+{
+	int ret;
+	struct rndis_function_config *rndis = f->config;
+
+	if (!rndis) {
+		pr_err("%s: rndis_pdata\n", __func__);
+		return -EINVAL;
+	}
+
+	pr_info("%s MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", __func__,
+		rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2],
+		rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]);
+
+	ret = gether_qc_setup_name(c->cdev->gadget, rndis->ethaddr, "rndis");
+	if (ret) {
+		pr_err("%s: gether_setup failed\n", __func__);
+		return ret;
+	}
+
+	if (rndis->wceis) {
+		/* "Wireless" RNDIS; auto-detected by Windows */
+		rndis_qc_iad_descriptor.bFunctionClass =
+						USB_CLASS_WIRELESS_CONTROLLER;
+		rndis_qc_iad_descriptor.bFunctionSubClass = 0x01;
+		rndis_qc_iad_descriptor.bFunctionProtocol = 0x03;
+		rndis_qc_control_intf.bInterfaceClass =
+						USB_CLASS_WIRELESS_CONTROLLER;
+		rndis_qc_control_intf.bInterfaceSubClass =	 0x01;
+		rndis_qc_control_intf.bInterfaceProtocol =	 0x03;
+	}
+
+	return rndis_qc_bind_config_vendor(c, rndis->ethaddr, rndis->vendorID,
+				    rndis->manufacturer,
+					rndis->max_pkt_per_xfer);
+}
+
 static void rndis_function_unbind_config(struct android_usb_function *f,
 						struct usb_configuration *c)
 {
 	gether_cleanup();
 }
 
+static void rndis_qc_function_unbind_config(struct android_usb_function *f,
+						struct usb_configuration *c)
+{
+	gether_qc_cleanup();
+}
+
 static ssize_t rndis_manufacturer_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
@@ -1288,11 +1407,38 @@
 static DEVICE_ATTR(vendorID, S_IRUGO | S_IWUSR, rndis_vendorID_show,
 						rndis_vendorID_store);
 
+static ssize_t rndis_max_pkt_per_xfer_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct android_usb_function *f = dev_get_drvdata(dev);
+	struct rndis_function_config *config = f->config;
+	return snprintf(buf, PAGE_SIZE, "%d\n", config->max_pkt_per_xfer);
+}
+
+static ssize_t rndis_max_pkt_per_xfer_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct android_usb_function *f = dev_get_drvdata(dev);
+	struct rndis_function_config *config = f->config;
+	int value;
+
+	if (sscanf(buf, "%d", &value) == 1) {
+		config->max_pkt_per_xfer = value;
+		return size;
+	}
+	return -EINVAL;
+}
+
+static DEVICE_ATTR(max_pkt_per_xfer, S_IRUGO | S_IWUSR,
+				   rndis_max_pkt_per_xfer_show,
+				   rndis_max_pkt_per_xfer_store);
+
 static struct device_attribute *rndis_function_attributes[] = {
 	&dev_attr_manufacturer,
 	&dev_attr_wceis,
 	&dev_attr_ethaddr,
 	&dev_attr_vendorID,
+	&dev_attr_max_pkt_per_xfer,
 	NULL
 };
 
@@ -1306,6 +1452,15 @@
 };
 #endif /* CONFIG_USB_ANDROID_CDC_ECM */
 
+static struct android_usb_function rndis_qc_function = {
+	.name		= "rndis_qc",
+	.init		= rndis_qc_function_init,
+	.cleanup	= rndis_qc_function_cleanup,
+	.bind_config	= rndis_qc_function_bind_config,
+	.unbind_config	= rndis_qc_function_unbind_config,
+	.attributes	= rndis_function_attributes,
+};
+
 struct mass_storage_function_config {
 	struct fsg_config fsg;
 	struct fsg_common *common;
@@ -1501,6 +1656,7 @@
 	&rmnet_smd_sdio_function,
 	&rmnet_function,
 	&diag_function,
+	&qdss_function,
 	&serial_function,
 	&adb_function,
 	&ccid_function,
@@ -1512,6 +1668,7 @@
 #else
 	&rndis_function,
 #endif
+	&rndis_qc_function,
 	&mass_storage_function,
 	&accessory_function,
 	&uasp_function,
@@ -1613,9 +1770,11 @@
 			       struct usb_configuration *c)
 {
 	struct android_usb_function *f;
+	struct android_configuration *conf =
+		container_of(c, struct android_configuration, usb_config);
 	int ret;
 
-	list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
+	list_for_each_entry(f, &conf->enabled_functions, enabled_list) {
 		ret = f->bind_config(f, c);
 		if (ret) {
 			pr_err("%s: %s failed", __func__, f->name);
@@ -1630,25 +1789,30 @@
 			       struct usb_configuration *c)
 {
 	struct android_usb_function *f;
+	struct android_configuration *conf =
+		container_of(c, struct android_configuration, usb_config);
 
-	list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
+	list_for_each_entry(f, &conf->enabled_functions, enabled_list) {
 		if (f->unbind_config)
 			f->unbind_config(f, c);
 	}
 }
 
-static int android_enable_function(struct android_dev *dev, char *name)
+static int android_enable_function(struct android_dev *dev,
+				   struct android_configuration *conf,
+				   char *name)
 {
 	struct android_usb_function **functions = dev->functions;
 	struct android_usb_function *f;
 	while ((f = *functions++)) {
 		if (!strcmp(name, f->name)) {
 			if (f->android_dev)
-				pr_err("%s cannot be enabled on two devices\n",
+				pr_err("%s already enabled in other " \
+					"configuration or device\n",
 					f->name);
 			else {
 				list_add_tail(&f->enabled_list,
-					      &dev->enabled_functions);
+					      &conf->enabled_functions);
 				f->android_dev = dev;
 				return 0;
 			}
@@ -1664,9 +1828,20 @@
 		struct device_attribute *attr, char *buf)
 {
 	struct android_dev *dev = dev_get_drvdata(pdev);
+	struct android_configuration *conf;
+
+	/*
+	 * Show the wakeup attribute of the first configuration,
+	 * since all configurations have the same wakeup attribute
+	 */
+	if (dev->configs_num == 0)
+		return 0;
+	conf = list_entry(dev->configs.next,
+			  struct android_configuration,
+			  list_item);
 
 	return snprintf(buf, PAGE_SIZE, "%d\n",
-			!!(dev->config.bmAttributes &
+			!!(conf->usb_config.bmAttributes &
 				USB_CONFIG_ATT_WAKEUP));
 }
 
@@ -1674,6 +1849,7 @@
 		struct device_attribute *attr, const char *buff, size_t size)
 {
 	struct android_dev *dev = dev_get_drvdata(pdev);
+	struct android_configuration *conf;
 	int enable = 0;
 
 	sscanf(buff, "%d", &enable);
@@ -1681,10 +1857,13 @@
 	pr_debug("android_usb: %s remote wakeup\n",
 			enable ? "enabling" : "disabling");
 
-	if (enable)
-		dev->config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-	else
-		dev->config.bmAttributes &= ~USB_CONFIG_ATT_WAKEUP;
+	list_for_each_entry(conf, &dev->configs, list_item)
+		if (enable)
+			conf->usb_config.bmAttributes |=
+					USB_CONFIG_ATT_WAKEUP;
+		else
+			conf->usb_config.bmAttributes &=
+					~USB_CONFIG_ATT_WAKEUP;
 
 	return size;
 }
@@ -1693,13 +1872,18 @@
 functions_show(struct device *pdev, struct device_attribute *attr, char *buf)
 {
 	struct android_dev *dev = dev_get_drvdata(pdev);
+	struct android_configuration *conf;
 	struct android_usb_function *f;
 	char *buff = buf;
 
 	mutex_lock(&dev->mutex);
 
-	list_for_each_entry(f, &dev->enabled_functions, enabled_list)
-		buff += snprintf(buff, PAGE_SIZE, "%s,", f->name);
+	list_for_each_entry(conf, &dev->configs, list_item) {
+		if (buff != buf)
+			*(buff-1) = ':';
+		list_for_each_entry(f, &conf->enabled_functions, enabled_list)
+			buff += snprintf(buff, PAGE_SIZE, "%s,", f->name);
+	}
 
 	mutex_unlock(&dev->mutex);
 
@@ -1714,6 +1898,9 @@
 {
 	struct android_dev *dev = dev_get_drvdata(pdev);
 	struct android_usb_function *f;
+	struct list_head *curr_conf = &dev->configs;
+	struct android_configuration *conf;
+	char *conf_str;
 	char *name;
 	char buf[256], *b;
 	int err;
@@ -1726,21 +1913,45 @@
 	}
 
 	/* Clear previous enabled list */
-	list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
-		f->android_dev = NULL;
+	list_for_each_entry(conf, &dev->configs, list_item) {
+		list_for_each_entry(f, &conf->enabled_functions, enabled_list)
+			f->android_dev = NULL;
+		INIT_LIST_HEAD(&conf->enabled_functions);
 	}
-	INIT_LIST_HEAD(&dev->enabled_functions);
 
 	strlcpy(buf, buff, sizeof(buf));
 	b = strim(buf);
 
 	while (b) {
-		name = strsep(&b, ",");
-		if (name) {
-			err = android_enable_function(dev, name);
-			if (err)
-				pr_err("android_usb: Cannot enable '%s'", name);
+		conf_str = strsep(&b, ":");
+		if (conf_str) {
+			/* If the next not equal to the head, take it */
+			if (curr_conf->next != &dev->configs)
+				conf = list_entry(curr_conf->next,
+						  struct android_configuration,
+						  list_item);
+			else
+				conf = alloc_android_config(dev);
+
+			curr_conf = curr_conf->next;
 		}
+
+		while (conf_str) {
+			name = strsep(&conf_str, ",");
+			if (name) {
+				err = android_enable_function(dev, conf, name);
+				if (err)
+					pr_err("android_usb: Cannot enable %s",
+						name);
+			}
+		}
+	}
+
+	/* Free uneeded configurations if exists */
+	while (curr_conf->next != &dev->configs) {
+		conf = list_entry(curr_conf->next,
+				  struct android_configuration, list_item);
+		free_android_config(dev, conf);
 	}
 
 	mutex_unlock(&dev->mutex);
@@ -1762,6 +1973,7 @@
 	struct android_dev *dev = dev_get_drvdata(pdev);
 	struct usb_composite_dev *cdev = dev->cdev;
 	struct android_usb_function *f;
+	struct android_configuration *conf;
 	int enabled = 0;
 
 	if (!cdev)
@@ -1781,18 +1993,22 @@
 		cdev->desc.bDeviceClass = device_desc.bDeviceClass;
 		cdev->desc.bDeviceSubClass = device_desc.bDeviceSubClass;
 		cdev->desc.bDeviceProtocol = device_desc.bDeviceProtocol;
-		list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
-			if (f->enable)
-				f->enable(f);
-		}
+		list_for_each_entry(conf, &dev->configs, list_item)
+			list_for_each_entry(f, &conf->enabled_functions,
+						enabled_list) {
+				if (f->enable)
+					f->enable(f);
+			}
 		android_enable(dev);
 		dev->enabled = true;
 	} else if (!enabled && dev->enabled) {
 		android_disable(dev);
-		list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
-			if (f->disable)
-				f->disable(f);
-		}
+		list_for_each_entry(conf, &dev->configs, list_item)
+			list_for_each_entry(f, &conf->enabled_functions,
+						enabled_list) {
+				if (f->disable)
+					f->disable(f);
+			}
 		dev->enabled = false;
 	} else {
 		pr_err("android_usb: already %s\n",
@@ -1948,6 +2164,7 @@
 {
 	struct android_dev *dev;
 	struct usb_gadget	*gadget = cdev->gadget;
+	struct android_configuration *conf;
 	int			gcnum, id, ret;
 
 	/* Bind to the last android_dev that was probed */
@@ -1996,7 +2213,8 @@
 	device_desc.iSerialNumber = id;
 
 	if (gadget_is_otg(cdev->gadget))
-		dev->config.descriptors = otg_desc;
+		list_for_each_entry(conf, &dev->configs, list_item)
+			conf->usb_config.descriptors = otg_desc;
 
 	gcnum = usb_gadget_controller_number(gadget);
 	if (gcnum >= 0)
@@ -2037,6 +2255,7 @@
 	struct android_dev		*dev = cdev_to_android_dev(cdev);
 	struct usb_request		*req = cdev->req;
 	struct android_usb_function	*f;
+	struct android_configuration	*conf;
 	int value = -EOPNOTSUPP;
 	unsigned long flags;
 
@@ -2045,13 +2264,16 @@
 	req->length = 0;
 	gadget->ep0->driver_data = cdev;
 
-	list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
-		if (f->ctrlrequest) {
-			value = f->ctrlrequest(f, cdev, c);
-			if (value >= 0)
-				break;
-		}
-	}
+	list_for_each_entry(conf, &dev->configs, list_item)
+		if (&conf->usb_config == cdev->config)
+			list_for_each_entry(f,
+					    &conf->enabled_functions,
+					    enabled_list)
+				if (f->ctrlrequest) {
+					value = f->ctrlrequest(f, cdev, c);
+					if (value >= 0)
+						break;
+				}
 
 	/* Special case the accessory function.
 	 * It needs to handle control requests before it is enabled.
@@ -2142,6 +2364,38 @@
 	return dev;
 }
 
+static struct android_configuration *alloc_android_config
+						(struct android_dev *dev)
+{
+	struct android_configuration *conf;
+
+	conf = kzalloc(sizeof(*conf), GFP_KERNEL);
+	if (!conf) {
+		pr_err("%s(): Failed to alloc memory for android conf\n",
+			__func__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	dev->configs_num++;
+	conf->usb_config.label = dev->name;
+	conf->usb_config.unbind = android_unbind_config;
+	conf->usb_config.bConfigurationValue = dev->configs_num;
+
+	INIT_LIST_HEAD(&conf->enabled_functions);
+
+	list_add_tail(&conf->list_item, &dev->configs);
+
+	return conf;
+}
+
+static void free_android_config(struct android_dev *dev,
+			     struct android_configuration *conf)
+{
+	list_del(&conf->list_item);
+	dev->configs_num--;
+	kfree(conf);
+}
+
 static int __devinit android_probe(struct platform_device *pdev)
 {
 	struct android_usb_platform_data *pdata = pdev->dev.platform_data;
@@ -2162,12 +2416,11 @@
 		goto err_alloc;
 	}
 
-	android_dev->config.label = pdev->name;
-	android_dev->config.unbind = android_unbind_config;
-	android_dev->config.bConfigurationValue = 1;
+	android_dev->name = pdev->name;
 	android_dev->disable_depth = 1;
 	android_dev->functions = supported_functions;
-	INIT_LIST_HEAD(&android_dev->enabled_functions);
+	android_dev->configs_num = 0;
+	INIT_LIST_HEAD(&android_dev->configs);
 	INIT_WORK(&android_dev->work, android_work);
 	mutex_init(&android_dev->mutex);
 
diff --git a/drivers/usb/gadget/ci13xxx_msm_hsic.c b/drivers/usb/gadget/ci13xxx_msm_hsic.c
index 5d5ee00..6faaf78 100644
--- a/drivers/usb/gadget/ci13xxx_msm_hsic.c
+++ b/drivers/usb/gadget/ci13xxx_msm_hsic.c
@@ -244,20 +244,20 @@
 		goto put_cal_clk;
 	}
 
-	clk_enable(mhsic->iface_clk);
-	clk_enable(mhsic->core_clk);
-	clk_enable(mhsic->phy_clk);
-	clk_enable(mhsic->alt_core_clk);
-	clk_enable(mhsic->cal_clk);
+	clk_prepare_enable(mhsic->iface_clk);
+	clk_prepare_enable(mhsic->core_clk);
+	clk_prepare_enable(mhsic->phy_clk);
+	clk_prepare_enable(mhsic->alt_core_clk);
+	clk_prepare_enable(mhsic->cal_clk);
 
 	return 0;
 
 put_clocks:
-	clk_disable(mhsic->iface_clk);
-	clk_disable(mhsic->core_clk);
-	clk_disable(mhsic->phy_clk);
-	clk_disable(mhsic->alt_core_clk);
-	clk_disable(mhsic->cal_clk);
+	clk_disable_unprepare(mhsic->iface_clk);
+	clk_disable_unprepare(mhsic->core_clk);
+	clk_disable_unprepare(mhsic->phy_clk);
+	clk_disable_unprepare(mhsic->alt_core_clk);
+	clk_disable_unprepare(mhsic->cal_clk);
 put_cal_clk:
 	clk_put(mhsic->cal_clk);
 put_alt_core_clk:
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 4d15d4d..4d15c55 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -54,6 +54,7 @@
 #include <linux/dmapool.h>
 #include <linux/dma-mapping.h>
 #include <linux/init.h>
+#include <linux/ratelimit.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irq.h>
@@ -74,6 +75,7 @@
  *****************************************************************************/
 
 #define DMA_ADDR_INVALID	(~(dma_addr_t)0)
+#define ATDTW_SET_DELAY		100 /* 100msec delay */
 
 /* ctrl register bank access */
 static DEFINE_SPINLOCK(udc_lock);
@@ -1764,6 +1766,7 @@
 		struct ci13xxx_req *mReqPrev;
 		int n = hw_ep_bit(mEp->num, mEp->dir);
 		int tmp_stat;
+		ktime_t start, diff;
 
 		mReqPrev = list_entry(mEp->qh.queue.prev,
 				struct ci13xxx_req, queue);
@@ -1774,9 +1777,20 @@
 		wmb();
 		if (hw_cread(CAP_ENDPTPRIME, BIT(n)))
 			goto done;
+		start = ktime_get();
 		do {
 			hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW);
 			tmp_stat = hw_cread(CAP_ENDPTSTAT, BIT(n));
+			diff = ktime_sub(ktime_get(), start);
+			/* poll for max. 100ms */
+			if (ktime_to_ms(diff) > ATDTW_SET_DELAY) {
+				if (hw_cread(CAP_USBCMD, USBCMD_ATDTW))
+					break;
+				printk_ratelimited(KERN_ERR
+				"%s:queue failed ep#%d %s\n",
+				 __func__, mEp->num, mEp->dir ? "IN" : "OUT");
+				return -EAGAIN;
+			}
 		} while (!hw_cread(CAP_USBCMD, USBCMD_ATDTW));
 		hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, 0);
 		if (tmp_stat)
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
new file mode 100644
index 0000000..dcf307d
--- /dev/null
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -0,0 +1,1151 @@
+/*
+ * f_qc_rndis.c -- RNDIS link function driver
+ *
+ * Copyright (C) 2003-2005,2008 David Brownell
+ * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
+ * Copyright (C) 2008 Nokia Corporation
+ * Copyright (C) 2009 Samsung Electronics
+ *			Author: Michal Nazarewicz (mina86@mina86.com)
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* #define VERBOSE_DEBUG */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/etherdevice.h>
+
+#include <linux/atomic.h>
+
+#include "u_ether.h"
+#include "u_qc_ether.h"
+#include "rndis.h"
+
+
+/*
+ * This function is an RNDIS Ethernet port -- a Microsoft protocol that's
+ * been promoted instead of the standard CDC Ethernet.  The published RNDIS
+ * spec is ambiguous, incomplete, and needlessly complex.  Variants such as
+ * ActiveSync have even worse status in terms of specification.
+ *
+ * In short:  it's a protocol controlled by (and for) Microsoft, not for an
+ * Open ecosystem or markets.  Linux supports it *only* because Microsoft
+ * doesn't support the CDC Ethernet standard.
+ *
+ * The RNDIS data transfer model is complex, with multiple Ethernet packets
+ * per USB message, and out of band data.  The control model is built around
+ * what's essentially an "RNDIS RPC" protocol.  It's all wrapped in a CDC ACM
+ * (modem, not Ethernet) veneer, with those ACM descriptors being entirely
+ * useless (they're ignored).  RNDIS expects to be the only function in its
+ * configuration, so it's no real help if you need composite devices; and
+ * it expects to be the first configuration too.
+ *
+ * There is a single technical advantage of RNDIS over CDC Ethernet, if you
+ * discount the fluff that its RPC can be made to deliver: it doesn't need
+ * a NOP altsetting for the data interface.  That lets it work on some of the
+ * "so smart it's stupid" hardware which takes over configuration changes
+ * from the software, and adds restrictions like "no altsettings".
+ *
+ * Unfortunately MSFT's RNDIS drivers are buggy.  They hang or oops, and
+ * have all sorts of contrary-to-specification oddities that can prevent
+ * them from working sanely.  Since bugfixes (or accurate specs, letting
+ * Linux work around those bugs) are unlikely to ever come from MSFT, you
+ * may want to avoid using RNDIS on purely operational grounds.
+ *
+ * Omissions from the RNDIS 1.0 specification include:
+ *
+ *   - Power management ... references data that's scattered around lots
+ *     of other documentation, which is incorrect/incomplete there too.
+ *
+ *   - There are various undocumented protocol requirements, like the need
+ *     to send garbage in some control-OUT messages.
+ *
+ *   - MS-Windows drivers sometimes emit undocumented requests.
+ *
+ * This function is based on RNDIS link function driver and
+ * contains MSM specific implementation.
+ */
+
+struct f_rndis_qc {
+	struct qc_gether			port;
+	u8				ctrl_id, data_id;
+	u8				ethaddr[ETH_ALEN];
+	u32				vendorID;
+	u8				max_pkt_per_xfer;
+	const char			*manufacturer;
+	int				config;
+	atomic_t		ioctl_excl;
+	atomic_t		open_excl;
+
+	struct usb_ep			*notify;
+	struct usb_request		*notify_req;
+	atomic_t			notify_count;
+};
+
+static inline struct f_rndis_qc *func_to_rndis_qc(struct usb_function *f)
+{
+	return container_of(f, struct f_rndis_qc, port.func);
+}
+
+/* peak (theoretical) bulk transfer rate in bits-per-second */
+static unsigned int rndis_qc_bitrate(struct usb_gadget *g)
+{
+	if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
+		return 13 * 1024 * 8 * 1000 * 8;
+	else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return 13 * 512 * 8 * 1000 * 8;
+	else
+		return 19 * 64 * 1 * 1000 * 8;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define RNDIS_QC_LOG2_STATUS_INTERVAL_MSEC	5	/* 1 << 5 == 32 msec */
+#define RNDIS_QC_STATUS_BYTECOUNT		8	/* 8 bytes data */
+
+/* currently only one rndis instance is supported */
+#define RNDIS_QC_NO_PORTS					1
+
+/* default max packets per tarnsfer value */
+#define DEFAULT_MAX_PKT_PER_XFER			15
+
+
+#define RNDIS_QC_IOCTL_MAGIC		'i'
+#define RNDIS_QC_GET_MAX_PKT_PER_XFER   _IOR(RNDIS_QC_IOCTL_MAGIC, 1, u8)
+
+
+/* interface descriptor: */
+
+static struct usb_interface_descriptor rndis_qc_control_intf = {
+	.bLength =		sizeof rndis_qc_control_intf,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	/* .bInterfaceNumber = DYNAMIC */
+	/* status endpoint is optional; this could be patched later */
+	.bNumEndpoints =	1,
+	.bInterfaceClass =	USB_CLASS_COMM,
+	.bInterfaceSubClass =   USB_CDC_SUBCLASS_ACM,
+	.bInterfaceProtocol =   USB_CDC_ACM_PROTO_VENDOR,
+	/* .iInterface = DYNAMIC */
+};
+
+static struct usb_cdc_header_desc rndis_qc_header_desc = {
+	.bLength =		sizeof rndis_qc_header_desc,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
+
+	.bcdCDC =		cpu_to_le16(0x0110),
+};
+
+static struct usb_cdc_call_mgmt_descriptor rndis_qc_call_mgmt_descriptor = {
+	.bLength =		sizeof rndis_qc_call_mgmt_descriptor,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_CALL_MANAGEMENT_TYPE,
+
+	.bmCapabilities =	0x00,
+	.bDataInterface =	0x01,
+};
+
+static struct usb_cdc_acm_descriptor rndis_qc_acm_descriptor = {
+	.bLength =		sizeof rndis_qc_acm_descriptor,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_ACM_TYPE,
+
+	.bmCapabilities =	0x00,
+};
+
+static struct usb_cdc_union_desc rndis_qc_union_desc = {
+	.bLength =		sizeof(rndis_qc_union_desc),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_UNION_TYPE,
+	/* .bMasterInterface0 =	DYNAMIC */
+	/* .bSlaveInterface0 =	DYNAMIC */
+};
+
+/* the data interface has two bulk endpoints */
+
+static struct usb_interface_descriptor rndis_qc_data_intf = {
+	.bLength =		sizeof rndis_qc_data_intf,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	/* .bInterfaceNumber = DYNAMIC */
+	.bNumEndpoints =	2,
+	.bInterfaceClass =	USB_CLASS_CDC_DATA,
+	.bInterfaceSubClass =	0,
+	.bInterfaceProtocol =	0,
+	/* .iInterface = DYNAMIC */
+};
+
+
+static struct usb_interface_assoc_descriptor
+rndis_qc_iad_descriptor = {
+	.bLength =		sizeof rndis_qc_iad_descriptor,
+	.bDescriptorType =	USB_DT_INTERFACE_ASSOCIATION,
+	.bFirstInterface =	0, /* XXX, hardcoded */
+	.bInterfaceCount =	2, /* control + data */
+	.bFunctionClass =	USB_CLASS_COMM,
+	.bFunctionSubClass =	USB_CDC_SUBCLASS_ETHERNET,
+	.bFunctionProtocol =	USB_CDC_PROTO_NONE,
+	/* .iFunction = DYNAMIC */
+};
+
+/* full speed support: */
+
+static struct usb_endpoint_descriptor rndis_qc_fs_notify_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(RNDIS_QC_STATUS_BYTECOUNT),
+	.bInterval =		1 << RNDIS_QC_LOG2_STATUS_INTERVAL_MSEC,
+};
+
+static struct usb_endpoint_descriptor rndis_qc_fs_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_endpoint_descriptor rndis_qc_fs_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_descriptor_header *eth_qc_fs_function[] = {
+	(struct usb_descriptor_header *) &rndis_qc_iad_descriptor,
+	/* control interface matches ACM, not Ethernet */
+	(struct usb_descriptor_header *) &rndis_qc_control_intf,
+	(struct usb_descriptor_header *) &rndis_qc_header_desc,
+	(struct usb_descriptor_header *) &rndis_qc_call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &rndis_qc_acm_descriptor,
+	(struct usb_descriptor_header *) &rndis_qc_union_desc,
+	(struct usb_descriptor_header *) &rndis_qc_fs_notify_desc,
+	/* data interface has no altsetting */
+	(struct usb_descriptor_header *) &rndis_qc_data_intf,
+	(struct usb_descriptor_header *) &rndis_qc_fs_in_desc,
+	(struct usb_descriptor_header *) &rndis_qc_fs_out_desc,
+	NULL,
+};
+
+/* high speed support: */
+
+static struct usb_endpoint_descriptor rndis_qc_hs_notify_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(RNDIS_QC_STATUS_BYTECOUNT),
+	.bInterval =		RNDIS_QC_LOG2_STATUS_INTERVAL_MSEC + 4,
+};
+static struct usb_endpoint_descriptor rndis_qc_hs_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor rndis_qc_hs_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+};
+
+static struct usb_descriptor_header *eth_qc_hs_function[] = {
+	(struct usb_descriptor_header *) &rndis_qc_iad_descriptor,
+	/* control interface matches ACM, not Ethernet */
+	(struct usb_descriptor_header *) &rndis_qc_control_intf,
+	(struct usb_descriptor_header *) &rndis_qc_header_desc,
+	(struct usb_descriptor_header *) &rndis_qc_call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &rndis_qc_acm_descriptor,
+	(struct usb_descriptor_header *) &rndis_qc_union_desc,
+	(struct usb_descriptor_header *) &rndis_qc_hs_notify_desc,
+	/* data interface has no altsetting */
+	(struct usb_descriptor_header *) &rndis_qc_data_intf,
+	(struct usb_descriptor_header *) &rndis_qc_hs_in_desc,
+	(struct usb_descriptor_header *) &rndis_qc_hs_out_desc,
+	NULL,
+};
+
+/* super speed support: */
+
+static struct usb_endpoint_descriptor rndis_qc_ss_notify_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(STATUS_BYTECOUNT),
+	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4,
+};
+
+static struct usb_ss_ep_comp_descriptor rndis_qc_ss_intr_comp_desc = {
+	.bLength =		sizeof ss_intr_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 3 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+	.wBytesPerInterval =	cpu_to_le16(STATUS_BYTECOUNT),
+};
+
+static struct usb_endpoint_descriptor rndis_qc_ss_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor rndis_qc_ss_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor rndis_qc_ss_bulk_comp_desc = {
+	.bLength =		sizeof ss_bulk_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 2 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+};
+
+static struct usb_descriptor_header *eth_qc_ss_function[] = {
+	(struct usb_descriptor_header *) &rndis_iad_descriptor,
+
+	/* control interface matches ACM, not Ethernet */
+	(struct usb_descriptor_header *) &rndis_qc_control_intf,
+	(struct usb_descriptor_header *) &rndis_qc_header_desc,
+	(struct usb_descriptor_header *) &rndis_qc_call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &rndis_qc_acm_descriptor,
+	(struct usb_descriptor_header *) &rndis_qc_union_desc,
+	(struct usb_descriptor_header *) &rndis_qc_ss_notify_desc,
+	(struct usb_descriptor_header *) &rndis_qc_ss_intr_comp_desc,
+
+	/* data interface has no altsetting */
+	(struct usb_descriptor_header *) &rndis_qc_data_intf,
+	(struct usb_descriptor_header *) &rndis_qc_ss_in_desc,
+	(struct usb_descriptor_header *) &rndis_qc_ss_bulk_comp_desc,
+	(struct usb_descriptor_header *) &rndis_qc_ss_out_desc,
+	(struct usb_descriptor_header *) &rndis_qc_ss_bulk_comp_desc,
+	NULL,
+};
+
+/* string descriptors: */
+
+static struct usb_string rndis_qc_string_defs[] = {
+	[0].s = "RNDIS Communications Control",
+	[1].s = "RNDIS Ethernet Data",
+	[2].s = "RNDIS",
+	{  } /* end of list */
+};
+
+static struct usb_gadget_strings rndis_qc_string_table = {
+	.language =		0x0409,	/* en-us */
+	.strings =		rndis_qc_string_defs,
+};
+
+static struct usb_gadget_strings *rndis_qc_strings[] = {
+	&rndis_qc_string_table,
+	NULL,
+};
+
+struct f_rndis_qc *_rndis_qc;
+
+static inline int rndis_qc_lock(atomic_t *excl)
+{
+	if (atomic_inc_return(excl) == 1) {
+		return 0;
+	} else {
+		atomic_dec(excl);
+		return -EBUSY;
+	}
+}
+
+static inline void rndis_qc_unlock(atomic_t *excl)
+{
+	atomic_dec(excl);
+}
+
+/* MSM bam support */
+static struct data_port rndis_qc_bam_port;
+
+static int rndis_qc_bam_setup(void)
+{
+	int ret;
+
+	ret = bam_data_setup(RNDIS_QC_NO_PORTS);
+	if (ret) {
+		pr_err("bam_data_setup failed err: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int rndis_qc_bam_connect(struct f_rndis_qc *dev)
+{
+	int ret;
+
+	rndis_qc_bam_port.func = dev->port.func;
+	rndis_qc_bam_port.in = dev->port.in_ep;
+	rndis_qc_bam_port.out = dev->port.out_ep;
+
+	/* currently we use the first connection */
+	ret = bam_data_connect(&rndis_qc_bam_port, 0, 0);
+	if (ret) {
+		pr_err("bam_data_connect failed: err:%d\n",
+				ret);
+		return ret;
+	} else {
+		pr_info("rndis bam connected\n");
+	}
+
+	return 0;
+}
+
+static int rndis_qc_bam_disconnect(struct f_rndis_qc *dev)
+{
+	pr_info("dev:%p. %s Do nothing.\n",
+			dev, __func__);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct sk_buff *rndis_qc_add_header(struct qc_gether *port,
+					struct sk_buff *skb)
+{
+	struct sk_buff *skb2;
+
+	skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type));
+	if (skb2)
+		rndis_add_hdr(skb2);
+
+	dev_kfree_skb_any(skb);
+	return skb2;
+}
+
+int rndis_qc_rm_hdr(struct qc_gether *port,
+			struct sk_buff *skb,
+			struct sk_buff_head *list)
+{
+	/* tmp points to a struct rndis_packet_msg_type */
+	__le32 *tmp = (void *)skb->data;
+
+	/* MessageType, MessageLength */
+	if (cpu_to_le32(REMOTE_NDIS_PACKET_MSG)
+			!= get_unaligned(tmp++)) {
+		dev_kfree_skb_any(skb);
+		return -EINVAL;
+	}
+	tmp++;
+
+	/* DataOffset, DataLength */
+	if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) {
+		dev_kfree_skb_any(skb);
+		return -EOVERFLOW;
+	}
+	skb_trim(skb, get_unaligned_le32(tmp++));
+
+	skb_queue_tail(list, skb);
+	return 0;
+}
+
+
+static void rndis_qc_response_available(void *_rndis)
+{
+	struct f_rndis_qc			*rndis = _rndis;
+	struct usb_request		*req = rndis->notify_req;
+	__le32				*data = req->buf;
+	int				status;
+
+	if (atomic_inc_return(&rndis->notify_count) != 1)
+		return;
+
+	/* Send RNDIS RESPONSE_AVAILABLE notification; a
+	 * USB_CDC_NOTIFY_RESPONSE_AVAILABLE "should" work too
+	 *
+	 * This is the only notification defined by RNDIS.
+	 */
+	data[0] = cpu_to_le32(1);
+	data[1] = cpu_to_le32(0);
+
+	status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC);
+	if (status) {
+		atomic_dec(&rndis->notify_count);
+		pr_info("notify/0 --> %d\n", status);
+	}
+}
+
+static void rndis_qc_response_complete(struct usb_ep *ep,
+						struct usb_request *req)
+{
+	struct f_rndis_qc			*rndis = req->context;
+	int				status = req->status;
+
+	/* after TX:
+	 *  - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control)
+	 *  - RNDIS_RESPONSE_AVAILABLE (status/irq)
+	 */
+	switch (status) {
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+		/* connection gone */
+		atomic_set(&rndis->notify_count, 0);
+		break;
+	default:
+		pr_info("RNDIS %s response error %d, %d/%d\n",
+			ep->name, status,
+			req->actual, req->length);
+		/* FALLTHROUGH */
+	case 0:
+		if (ep != rndis->notify)
+			break;
+
+		/* handle multiple pending RNDIS_RESPONSE_AVAILABLE
+		 * notifications by resending until we're done
+		 */
+		if (atomic_dec_and_test(&rndis->notify_count))
+			break;
+		status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC);
+		if (status) {
+			atomic_dec(&rndis->notify_count);
+			DBG(cdev, "notify/1 --> %d\n", status);
+		}
+		break;
+	}
+}
+
+static void rndis_qc_command_complete(struct usb_ep *ep,
+							struct usb_request *req)
+{
+	struct f_rndis_qc			*rndis = req->context;
+	int				status;
+
+	/* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
+	status = rndis_msg_parser(rndis->config, (u8 *) req->buf);
+	if (status < 0)
+		pr_err("RNDIS command error %d, %d/%d\n",
+			status, req->actual, req->length);
+}
+
+static int
+rndis_qc_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+	struct f_rndis_qc		*rndis = func_to_rndis_qc(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
+	struct usb_request	*req = cdev->req;
+	int			value = -EOPNOTSUPP;
+	u16			w_index = le16_to_cpu(ctrl->wIndex);
+	u16			w_value = le16_to_cpu(ctrl->wValue);
+	u16			w_length = le16_to_cpu(ctrl->wLength);
+
+	/* composite driver infrastructure handles everything except
+	 * CDC class messages; interface activation uses set_alt().
+	 */
+	switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
+
+	/* RNDIS uses the CDC command encapsulation mechanism to implement
+	 * an RPC scheme, with much getting/setting of attributes by OID.
+	 */
+	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+			| USB_CDC_SEND_ENCAPSULATED_COMMAND:
+		if (w_value || w_index != rndis->ctrl_id)
+			goto invalid;
+		/* read the request; process it later */
+		value = w_length;
+		req->complete = rndis_qc_command_complete;
+		req->context = rndis;
+		/* later, rndis_response_available() sends a notification */
+		break;
+
+	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+			| USB_CDC_GET_ENCAPSULATED_RESPONSE:
+		if (w_value || w_index != rndis->ctrl_id)
+			goto invalid;
+		else {
+			u8 *buf;
+			u32 n;
+
+			/* return the result */
+			buf = rndis_get_next_response(rndis->config, &n);
+			if (buf) {
+				memcpy(req->buf, buf, n);
+				req->complete = rndis_qc_response_complete;
+				rndis_free_response(rndis->config, buf);
+				value = n;
+			}
+			/* else stalls ... spec says to avoid that */
+		}
+		break;
+
+	default:
+invalid:
+		VDBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
+			ctrl->bRequestType, ctrl->bRequest,
+			w_value, w_index, w_length);
+	}
+
+	/* respond with data transfer or status phase? */
+	if (value >= 0) {
+		DBG(cdev, "rndis req%02x.%02x v%04x i%04x l%d\n",
+			ctrl->bRequestType, ctrl->bRequest,
+			w_value, w_index, w_length);
+		req->zero = (value < w_length);
+		req->length = value;
+		value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+		if (value < 0)
+			pr_err("rndis response on err %d\n", value);
+	}
+
+	/* device either stalls (value < 0) or reports success */
+	return value;
+}
+
+
+static int rndis_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+	struct f_rndis_qc		*rndis = func_to_rndis_qc(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
+
+	/* we know alt == 0 */
+
+	if (intf == rndis->ctrl_id) {
+		if (rndis->notify->driver_data) {
+			VDBG(cdev, "reset rndis control %d\n", intf);
+			usb_ep_disable(rndis->notify);
+		}
+		if (!rndis->notify->desc) {
+			VDBG(cdev, "init rndis ctrl %d\n", intf);
+			if (config_ep_by_speed(cdev->gadget, f, rndis->notify))
+				goto fail;
+		}
+		usb_ep_enable(rndis->notify);
+		rndis->notify->driver_data = rndis;
+
+	} else if (intf == rndis->data_id) {
+		struct net_device	*net;
+
+		if (rndis->port.in_ep->driver_data) {
+			DBG(cdev, "reset rndis\n");
+			gether_qc_disconnect(&rndis->port);
+			rndis_qc_bam_disconnect(rndis);
+		}
+
+		if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) {
+			DBG(cdev, "init rndis\n");
+			if (config_ep_by_speed(cdev->gadget, f,
+					       rndis->port.in_ep) ||
+			    config_ep_by_speed(cdev->gadget, f,
+					       rndis->port.out_ep)) {
+				rndis->port.in_ep->desc = NULL;
+				rndis->port.out_ep->desc = NULL;
+				goto fail;
+			}
+		}
+
+		/* Avoid ZLPs; they can be troublesome. */
+		rndis->port.is_zlp_ok = false;
+
+		/* RNDIS should be in the "RNDIS uninitialized" state,
+		 * either never activated or after rndis_uninit().
+		 *
+		 * We don't want data to flow here until a nonzero packet
+		 * filter is set, at which point it enters "RNDIS data
+		 * initialized" state ... but we do want the endpoints
+		 * to be activated.  It's a strange little state.
+		 *
+		 * REVISIT the RNDIS gadget code has done this wrong for a
+		 * very long time.  We need another call to the link layer
+		 * code -- gether_updown(...bool) maybe -- to do it right.
+		 */
+		rndis->port.cdc_filter = 0;
+
+		DBG(cdev, "RNDIS RX/TX early activation ...\n");
+		net = gether_qc_connect(&rndis->port);
+		if (IS_ERR(net))
+			return PTR_ERR(net);
+
+		if (rndis_qc_bam_connect(rndis))
+			goto fail;
+
+		rndis_set_param_dev(rndis->config, net,
+				&rndis->port.cdc_filter);
+	} else
+		goto fail;
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static void rndis_qc_disable(struct usb_function *f)
+{
+	struct f_rndis_qc		*rndis = func_to_rndis_qc(f);
+
+	if (!rndis->notify->driver_data)
+		return;
+
+	pr_info("rndis deactivated\n");
+
+	rndis_uninit(rndis->config);
+	gether_qc_disconnect(&rndis->port);
+	rndis_qc_bam_disconnect(rndis);
+
+	usb_ep_disable(rndis->notify);
+	rndis->notify->driver_data = NULL;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * This isn't quite the same mechanism as CDC Ethernet, since the
+ * notification scheme passes less data, but the same set of link
+ * states must be tested.  A key difference is that altsettings are
+ * not used to tell whether the link should send packets or not.
+ */
+
+static void rndis_qc_open(struct qc_gether *geth)
+{
+	struct f_rndis_qc		*rndis = func_to_rndis_qc(&geth->func);
+	struct usb_composite_dev *cdev = geth->func.config->cdev;
+
+	DBG(cdev, "%s\n", __func__);
+
+	rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3,
+				rndis_qc_bitrate(cdev->gadget) / 100);
+	rndis_signal_connect(rndis->config);
+}
+
+static void rndis_qc_close(struct qc_gether *geth)
+{
+	struct f_rndis_qc		*rndis = func_to_rndis_qc(&geth->func);
+
+	DBG(geth->func.config->cdev, "%s\n", __func__);
+
+	rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, 0);
+	rndis_signal_disconnect(rndis->config);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* ethernet function driver setup/binding */
+
+static int
+rndis_qc_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct usb_composite_dev *cdev = c->cdev;
+	struct f_rndis_qc		*rndis = func_to_rndis_qc(f);
+	int			status;
+	struct usb_ep		*ep;
+
+	/* allocate instance-specific interface IDs */
+	status = usb_interface_id(c, f);
+	if (status < 0)
+		goto fail;
+	rndis->ctrl_id = status;
+	rndis_qc_iad_descriptor.bFirstInterface = status;
+
+	rndis_qc_control_intf.bInterfaceNumber = status;
+	rndis_qc_union_desc.bMasterInterface0 = status;
+
+	status = usb_interface_id(c, f);
+	if (status < 0)
+		goto fail;
+	rndis->data_id = status;
+
+	rndis_qc_data_intf.bInterfaceNumber = status;
+	rndis_qc_union_desc.bSlaveInterface0 = status;
+
+	status = -ENODEV;
+
+	/* allocate instance-specific endpoints */
+	ep = usb_ep_autoconfig(cdev->gadget, &rndis_qc_fs_in_desc);
+	if (!ep)
+		goto fail;
+	rndis->port.in_ep = ep;
+	ep->driver_data = cdev;	/* claim */
+
+	ep = usb_ep_autoconfig(cdev->gadget, &rndis_qc_fs_out_desc);
+	if (!ep)
+		goto fail;
+	rndis->port.out_ep = ep;
+	ep->driver_data = cdev;	/* claim */
+
+	/* NOTE:  a status/notification endpoint is, strictly speaking,
+	 * optional.  We don't treat it that way though!  It's simpler,
+	 * and some newer profiles don't treat it as optional.
+	 */
+	ep = usb_ep_autoconfig(cdev->gadget, &rndis_qc_fs_notify_desc);
+	if (!ep)
+		goto fail;
+	rndis->notify = ep;
+	ep->driver_data = cdev;	/* claim */
+
+	status = -ENOMEM;
+
+	/* allocate notification request and buffer */
+	rndis->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
+	if (!rndis->notify_req)
+		goto fail;
+	rndis->notify_req->buf = kmalloc(RNDIS_QC_STATUS_BYTECOUNT, GFP_KERNEL);
+	if (!rndis->notify_req->buf)
+		goto fail;
+	rndis->notify_req->length = RNDIS_QC_STATUS_BYTECOUNT;
+	rndis->notify_req->context = rndis;
+	rndis->notify_req->complete = rndis_qc_response_complete;
+
+	/* copy descriptors, and track endpoint copies */
+	f->descriptors = usb_copy_descriptors(eth_qc_fs_function);
+	if (!f->descriptors)
+		goto fail;
+
+	/* support all relevant hardware speeds... we expect that when
+	 * hardware is dual speed, all bulk-capable endpoints work at
+	 * both speeds
+	 */
+	if (gadget_is_dualspeed(c->cdev->gadget)) {
+		rndis_qc_hs_in_desc.bEndpointAddress =
+				rndis_qc_fs_in_desc.bEndpointAddress;
+		rndis_qc_hs_out_desc.bEndpointAddress =
+				rndis_qc_fs_out_desc.bEndpointAddress;
+		rndis_qc_hs_notify_desc.bEndpointAddress =
+				rndis_qc_fs_notify_desc.bEndpointAddress;
+
+		/* copy descriptors, and track endpoint copies */
+		f->hs_descriptors = usb_copy_descriptors(eth_qc_hs_function);
+
+		if (!f->hs_descriptors)
+			goto fail;
+	}
+
+	if (gadget_is_superspeed(c->cdev->gadget)) {
+		rndis_qc_ss_in_desc.bEndpointAddress =
+				rndis_qc_fs_in_desc.bEndpointAddress;
+		rndis_qc_ss_out_desc.bEndpointAddress =
+				rndis_qc_fs_out_desc.bEndpointAddress;
+		rndis_qc_ss_notify_desc.bEndpointAddress =
+				rndis_qc_fs_notify_desc.bEndpointAddress;
+
+		/* copy descriptors, and track endpoint copies */
+		f->ss_descriptors = usb_copy_descriptors(eth_qc_ss_function);
+		if (!f->ss_descriptors)
+			goto fail;
+	}
+
+	rndis->port.open = rndis_qc_open;
+	rndis->port.close = rndis_qc_close;
+
+	status = rndis_register(rndis_qc_response_available, rndis);
+	if (status < 0)
+		goto fail;
+	rndis->config = status;
+
+	rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, 0);
+	rndis_set_host_mac(rndis->config, rndis->ethaddr);
+
+	if (rndis_set_param_vendor(rndis->config, rndis->vendorID,
+				   rndis->manufacturer))
+			goto fail;
+
+	rndis_set_max_pkt_xfer(rndis->config, rndis->max_pkt_per_xfer);
+
+	/* NOTE:  all that is done without knowing or caring about
+	 * the network link ... which is unavailable to this code
+	 * until we're activated via set_alt().
+	 */
+
+	DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n",
+			gadget_is_superspeed(c->cdev->gadget) ? "super" :
+			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
+			rndis->port.in_ep->name, rndis->port.out_ep->name,
+			rndis->notify->name);
+	return 0;
+
+fail:
+	if (gadget_is_superspeed(c->cdev->gadget) && f->ss_descriptors)
+		usb_free_descriptors(f->ss_descriptors);
+	if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors)
+		usb_free_descriptors(f->hs_descriptors);
+	if (f->descriptors)
+		usb_free_descriptors(f->descriptors);
+
+	if (rndis->notify_req) {
+		kfree(rndis->notify_req->buf);
+		usb_ep_free_request(rndis->notify, rndis->notify_req);
+	}
+
+	/* we might as well release our claims on endpoints */
+	if (rndis->notify)
+		rndis->notify->driver_data = NULL;
+	if (rndis->port.out_ep->desc)
+		rndis->port.out_ep->driver_data = NULL;
+	if (rndis->port.in_ep->desc)
+		rndis->port.in_ep->driver_data = NULL;
+
+	pr_err("%s: can't bind, err %d\n", f->name, status);
+
+	return status;
+}
+
+static void
+rndis_qc_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct f_rndis_qc		*rndis = func_to_rndis_qc(f);
+
+	rndis_deregister(rndis->config);
+	rndis_exit();
+
+	if (gadget_is_dualspeed(c->cdev->gadget))
+		usb_free_descriptors(f->hs_descriptors);
+	usb_free_descriptors(f->descriptors);
+
+	kfree(rndis->notify_req->buf);
+	usb_ep_free_request(rndis->notify, rndis->notify_req);
+
+	kfree(rndis);
+}
+
+/* Some controllers can't support RNDIS ... */
+static inline bool can_support_rndis_qc(struct usb_configuration *c)
+{
+	/* everything else is *presumably* fine */
+	return true;
+}
+
+/**
+ * rndis_qc_bind_config - add RNDIS network link to a configuration
+ * @c: the configuration to support the network link
+ * @ethaddr: a buffer in which the ethernet address of the host side
+ *	side of the link was recorded
+ * Context: single threaded during gadget setup
+ *
+ * Returns zero on success, else negative errno.
+ *
+ * Caller must have called @gether_setup().  Caller is also responsible
+ * for calling @gether_cleanup() before module unload.
+ */
+int
+rndis_qc_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+{
+	return rndis_qc_bind_config_vendor(c, ethaddr, 0, NULL, 1);
+}
+
+int
+rndis_qc_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+					 u32 vendorID, const char *manufacturer,
+					 u8 max_pkt_per_xfer)
+{
+	struct f_rndis_qc	*rndis;
+	int		status;
+
+	if (!can_support_rndis_qc(c) || !ethaddr)
+		return -EINVAL;
+
+	/* setup RNDIS itself */
+	status = rndis_init();
+	if (status < 0)
+		return status;
+
+	status = rndis_qc_bam_setup();
+	if (status) {
+		pr_err("bam setup failed");
+		return status;
+	}
+
+	/* maybe allocate device-global string IDs */
+	if (rndis_qc_string_defs[0].id == 0) {
+
+		/* control interface label */
+		status = usb_string_id(c->cdev);
+		if (status < 0)
+			return status;
+		rndis_qc_string_defs[0].id = status;
+		rndis_qc_control_intf.iInterface = status;
+
+		/* data interface label */
+		status = usb_string_id(c->cdev);
+		if (status < 0)
+			return status;
+		rndis_qc_string_defs[1].id = status;
+		rndis_qc_data_intf.iInterface = status;
+
+		/* IAD iFunction label */
+		status = usb_string_id(c->cdev);
+		if (status < 0)
+			return status;
+		rndis_qc_string_defs[2].id = status;
+		rndis_qc_iad_descriptor.iFunction = status;
+	}
+
+	/* allocate and initialize one new instance */
+	status = -ENOMEM;
+	rndis = kzalloc(sizeof *rndis, GFP_KERNEL);
+	if (!rndis)
+		goto fail;
+
+	memcpy(rndis->ethaddr, ethaddr, ETH_ALEN);
+	rndis->vendorID = vendorID;
+	rndis->manufacturer = manufacturer;
+
+	/* if max_pkt_per_xfer was not configured set to default value */
+	rndis->max_pkt_per_xfer =
+		max_pkt_per_xfer ? max_pkt_per_xfer : DEFAULT_MAX_PKT_PER_XFER;
+
+	/* RNDIS activates when the host changes this filter */
+	rndis->port.cdc_filter = 0;
+
+	/* RNDIS has special (and complex) framing */
+	rndis->port.header_len = sizeof(struct rndis_packet_msg_type);
+	rndis->port.wrap = rndis_qc_add_header;
+	rndis->port.unwrap = rndis_qc_rm_hdr;
+
+	rndis->port.func.name = "rndis";
+	rndis->port.func.strings = rndis_qc_strings;
+	/* descriptors are per-instance copies */
+	rndis->port.func.bind = rndis_qc_bind;
+	rndis->port.func.unbind = rndis_qc_unbind;
+	rndis->port.func.set_alt = rndis_qc_set_alt;
+	rndis->port.func.setup = rndis_qc_setup;
+	rndis->port.func.disable = rndis_qc_disable;
+
+	_rndis_qc = rndis;
+
+	status = usb_add_function(c, &rndis->port.func);
+	if (status) {
+		kfree(rndis);
+fail:
+		rndis_exit();
+	}
+	return status;
+}
+
+static int rndis_qc_open_dev(struct inode *ip, struct file *fp)
+{
+	pr_info("Open rndis QC driver\n");
+
+	if (!_rndis_qc) {
+		pr_err("rndis_qc_dev not created yet\n");
+		return -ENODEV;
+	}
+
+	if (rndis_qc_lock(&_rndis_qc->open_excl)) {
+		pr_err("Already opened\n");
+		return -EBUSY;
+	}
+
+	fp->private_data = _rndis_qc;
+	pr_info("rndis QC file opened\n");
+
+	return 0;
+}
+
+static int rndis_qc_release_dev(struct inode *ip, struct file *fp)
+{
+	struct f_rndis_qc	*rndis = fp->private_data;
+
+	pr_info("Close rndis QC file");
+	rndis_qc_unlock(&rndis->open_excl);
+
+	return 0;
+}
+
+static long rndis_qc_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
+{
+	struct f_rndis_qc	*rndis = fp->private_data;
+	int ret = 0;
+
+	pr_info("Received command %d", cmd);
+
+	if (rndis_qc_lock(&rndis->ioctl_excl))
+		return -EBUSY;
+
+	switch (cmd) {
+	case RNDIS_QC_GET_MAX_PKT_PER_XFER:
+		ret = copy_to_user((void __user *)arg,
+					&rndis->max_pkt_per_xfer,
+					sizeof(rndis->max_pkt_per_xfer));
+		if (ret) {
+			pr_err("copying to user space failed");
+			ret = -EFAULT;
+		}
+		pr_info("Sent max packets per xfer %d",
+				rndis->max_pkt_per_xfer);
+		break;
+	default:
+		pr_err("Unsupported IOCTL");
+		ret = -EINVAL;
+	}
+
+	rndis_qc_unlock(&rndis->ioctl_excl);
+
+	return ret;
+}
+
+static const struct file_operations rndis_qc_fops = {
+	.owner = THIS_MODULE,
+	.open = rndis_qc_open_dev,
+	.release = rndis_qc_release_dev,
+	.unlocked_ioctl	= rndis_qc_ioctl,
+};
+
+static struct miscdevice rndis_qc_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "android_rndis_qc",
+	.fops = &rndis_qc_fops,
+};
+
+static int rndis_qc_init(void)
+{
+	int ret;
+
+	pr_info("initialize rndis QC instance\n");
+
+	ret = misc_register(&rndis_qc_device);
+	if (ret)
+		pr_err("rndis QC driver failed to register");
+
+	return ret;
+}
+
+static void rndis_qc_cleanup(void)
+{
+	pr_info("rndis QC cleanup");
+
+	misc_deregister(&rndis_qc_device);
+	_rndis_qc = NULL;
+}
+
+
diff --git a/drivers/usb/gadget/f_qdss.c b/drivers/usb/gadget/f_qdss.c
new file mode 100644
index 0000000..0c81904
--- /dev/null
+++ b/drivers/usb/gadget/f_qdss.c
@@ -0,0 +1,817 @@
+/*
+ * f_qdss.c -- QDSS function Driver
+ *
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/usb/usb_qdss.h>
+#include <linux/usb/msm_hsusb.h>
+
+#include "f_qdss.h"
+#include "u_qdss.c"
+
+static DEFINE_SPINLOCK(d_lock);
+static LIST_HEAD(usb_qdss_ch_list);
+
+static struct usb_interface_descriptor qdss_data_intf_desc = {
+	.bLength            =	sizeof qdss_data_intf_desc,
+	.bDescriptorType    =	USB_DT_INTERFACE,
+	.bAlternateSetting  =   0,
+	.bNumEndpoints      =	1,
+	.bInterfaceClass    =	0xff,
+	.bInterfaceSubClass =	0xff,
+	.bInterfaceProtocol =	0xff,
+};
+
+static struct usb_endpoint_descriptor qdss_hs_data_desc = {
+	.bLength              =	 USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType      =	 USB_DT_ENDPOINT,
+	.bEndpointAddress     =	 USB_DIR_IN,
+	.bmAttributes         =	 USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize       =	 __constant_cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor qdss_ss_data_desc = {
+	.bLength              =	 USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType      =	 USB_DT_ENDPOINT,
+	.bEndpointAddress     =	 USB_DIR_IN,
+	.bmAttributes         =  USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize       =	 __constant_cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor qdss_data_ep_comp_desc = {
+	.bLength              =	 sizeof qdss_data_ep_comp_desc,
+	.bDescriptorType      =	 USB_DT_SS_ENDPOINT_COMP,
+	.bMaxBurst            =	 1,
+	.bmAttributes         =	 0,
+	.wBytesPerInterval    =	 0,
+};
+
+static struct usb_interface_descriptor qdss_ctrl_intf_desc = {
+	.bLength            =	sizeof qdss_ctrl_intf_desc,
+	.bDescriptorType    =	USB_DT_INTERFACE,
+	.bAlternateSetting  =   0,
+	.bNumEndpoints      =	2,
+	.bInterfaceClass    =	0xff,
+	.bInterfaceSubClass =	0xff,
+	.bInterfaceProtocol =	0xff,
+};
+
+static struct usb_endpoint_descriptor qdss_hs_ctrl_in_desc = {
+	.bLength            =	USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType    =	USB_DT_ENDPOINT,
+	.bEndpointAddress   =	USB_DIR_IN,
+	.bmAttributes       =	USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize     =	__constant_cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor qdss_ss_ctrl_in_desc = {
+	.bLength            =	USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType    =	USB_DT_ENDPOINT,
+	.bEndpointAddress   =	USB_DIR_IN,
+	.bmAttributes       =	USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize     =	__constant_cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor qdss_hs_ctrl_out_desc = {
+	.bLength            =	USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType    =	USB_DT_ENDPOINT,
+	.bEndpointAddress   =	USB_DIR_OUT,
+	.bmAttributes       =	USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize     =	__constant_cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor qdss_ss_ctrl_out_desc = {
+	.bLength            =	USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType    =	USB_DT_ENDPOINT,
+	.bEndpointAddress   =	USB_DIR_OUT,
+	.bmAttributes       =	USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize     =	__constant_cpu_to_le16(0x400),
+};
+
+static struct usb_ss_ep_comp_descriptor qdss_ctrl_in_ep_comp_desc = {
+	.bLength            =	sizeof qdss_ctrl_in_ep_comp_desc,
+	.bDescriptorType    =	USB_DT_SS_ENDPOINT_COMP,
+	.bMaxBurst          =	0,
+	.bmAttributes       =	0,
+	.wBytesPerInterval  =	0,
+};
+
+static struct usb_ss_ep_comp_descriptor qdss_ctrl_out_ep_comp_desc = {
+	.bLength            =	sizeof qdss_ctrl_out_ep_comp_desc,
+	.bDescriptorType    =	USB_DT_SS_ENDPOINT_COMP,
+	.bMaxBurst          =	0,
+	.bmAttributes       =	0,
+	.wBytesPerInterval  =	0,
+};
+
+static struct usb_descriptor_header *qdss_hs_desc[] = {
+	(struct usb_descriptor_header *) &qdss_data_intf_desc,
+	(struct usb_descriptor_header *) &qdss_hs_data_desc,
+	(struct usb_descriptor_header *) &qdss_ctrl_intf_desc,
+	(struct usb_descriptor_header *) &qdss_hs_ctrl_in_desc,
+	(struct usb_descriptor_header *) &qdss_hs_ctrl_out_desc,
+	NULL,
+};
+
+static struct usb_descriptor_header *qdss_ss_desc[] = {
+	(struct usb_descriptor_header *) &qdss_data_intf_desc,
+	(struct usb_descriptor_header *) &qdss_ss_data_desc,
+	(struct usb_descriptor_header *) &qdss_data_ep_comp_desc,
+	(struct usb_descriptor_header *) &qdss_ctrl_intf_desc,
+	(struct usb_descriptor_header *) &qdss_ss_ctrl_in_desc,
+	(struct usb_descriptor_header *) &qdss_ctrl_in_ep_comp_desc,
+	(struct usb_descriptor_header *) &qdss_ss_ctrl_out_desc,
+	(struct usb_descriptor_header *) &qdss_ctrl_out_ep_comp_desc,
+	NULL,
+};
+
+/* string descriptors: */
+#define QDSS_DATA_IDX	0
+#define QDSS_CTRL_IDX	1
+
+static struct usb_string qdss_string_defs[] = {
+	[QDSS_DATA_IDX].s = "QDSS DATA",
+	[QDSS_CTRL_IDX].s = "QDSS CTRL",
+	{}, /* end of list */
+};
+
+static struct usb_gadget_strings qdss_string_table = {
+	.language =		0x0409,
+	.strings =		qdss_string_defs,
+};
+
+static struct usb_gadget_strings *qdss_strings[] = {
+	&qdss_string_table,
+	NULL,
+};
+
+static inline struct f_qdss *func_to_qdss(struct usb_function *f)
+{
+	return container_of(f, struct f_qdss, function);
+}
+
+/*----------------------------------------------------------------------*/
+
+static void qdss_ctrl_write_complete(struct usb_ep *ep,
+	struct usb_request *req)
+{
+	struct f_qdss *qdss = ep->driver_data;
+	struct qdss_request *d_req = req->context;
+	unsigned long flags;
+
+	pr_debug("qdss_ctrl_write_complete\n");
+
+	if (!req->status) {
+		/* send zlp */
+		if ((req->length >= ep->maxpacket) &&
+				((req->length % ep->maxpacket) == 0)) {
+			req->length = 0;
+			d_req->actual = req->actual;
+			d_req->status = req->status;
+			usb_ep_queue(qdss->ctrl_in, req, GFP_ATOMIC);
+			return;
+		}
+	}
+
+	spin_lock_irqsave(&qdss->lock, flags);
+	list_add_tail(&req->list, &qdss->ctrl_write_pool);
+	if (req->length != 0) {
+		d_req->actual = req->actual;
+		d_req->status = req->status;
+	}
+	spin_unlock_irqrestore(&qdss->lock, flags);
+
+	if (qdss->ch.notify)
+		qdss->ch.notify(qdss->ch.priv, USB_QDSS_CTRL_WRITE_DONE, d_req,
+			NULL);
+}
+
+static void qdss_ctrl_read_complete(struct usb_ep *ep,
+	struct usb_request *req)
+{
+	struct f_qdss *qdss = ep->driver_data;
+	struct qdss_request *d_req = req->context;
+	unsigned long flags;
+
+	pr_debug("qdss_ctrl_read_complete\n");
+
+	d_req->actual = req->actual;
+	d_req->status = req->status;
+
+	spin_lock_irqsave(&qdss->lock, flags);
+	list_add_tail(&req->list, &qdss->ctrl_read_pool);
+	spin_unlock_irqrestore(&qdss->lock, flags);
+
+	if (qdss->ch.notify)
+		qdss->ch.notify(qdss->ch.priv, USB_QDSS_CTRL_READ_DONE, d_req,
+			NULL);
+}
+
+void usb_qdss_free_req(struct usb_qdss_ch *ch)
+{
+	struct f_qdss *qdss;
+	struct usb_request *req;
+	struct list_head *act, *tmp;
+
+	pr_debug("usb_qdss_free_req\n");
+
+	qdss = ch->priv_usb;
+	if (!qdss) {
+		pr_err("usb_qdss_free_req: qdss ctx is NULL\n");
+		return;
+	}
+
+	list_for_each_safe(act, tmp, &qdss->ctrl_write_pool) {
+		req = list_entry(act, struct usb_request, list);
+		list_del(&req->list);
+		usb_ep_free_request(qdss->ctrl_in, req);
+	}
+
+	list_for_each_safe(act, tmp, &qdss->ctrl_read_pool) {
+		req = list_entry(act, struct usb_request, list);
+		list_del(&req->list);
+		usb_ep_free_request(qdss->ctrl_out, req);
+	}
+}
+EXPORT_SYMBOL(usb_qdss_free_req);
+
+int usb_qdss_alloc_req(struct usb_qdss_ch *ch, int no_write_buf,
+	int no_read_buf)
+{
+	struct f_qdss *qdss = ch->priv_usb;
+	struct usb_request *req;
+	int i;
+
+	pr_debug("usb_qdss_alloc_req\n");
+
+	if (no_write_buf <= 0 || no_read_buf <= 0 || !qdss) {
+		pr_err("usb_qdss_alloc_req: missing params\n");
+		return -ENODEV;
+	}
+
+	for (i = 0; i < no_write_buf; i++) {
+		req = usb_ep_alloc_request(qdss->ctrl_in, GFP_ATOMIC);
+		if (!req) {
+			pr_err("usb_qdss_alloc_req: ctrl_in allocation err\n");
+			goto fail;
+		}
+		req->complete = qdss_ctrl_write_complete;
+		list_add_tail(&req->list, &qdss->ctrl_write_pool);
+	}
+
+	for (i = 0; i < no_read_buf; i++) {
+		req = usb_ep_alloc_request(qdss->ctrl_out, GFP_ATOMIC);
+		if (!req) {
+			pr_err("usb_qdss_alloc_req:ctrl_out allocation err\n");
+			goto fail;
+		}
+		req->complete = qdss_ctrl_read_complete;
+		list_add_tail(&req->list, &qdss->ctrl_read_pool);
+	}
+
+	return 0;
+
+fail:
+	usb_qdss_free_req(ch);
+	return -ENOMEM;
+}
+EXPORT_SYMBOL(usb_qdss_alloc_req);
+
+static void clear_eps(struct usb_function *f)
+{
+	struct f_qdss *qdss = func_to_qdss(f);
+
+	pr_debug("clear_eps\n");
+
+	if (qdss->ctrl_in)
+		qdss->ctrl_in->driver_data = NULL;
+	if (qdss->ctrl_out)
+		qdss->ctrl_out->driver_data = NULL;
+	if (qdss->data)
+		qdss->data->driver_data = NULL;
+}
+
+static void clear_desc(struct usb_gadget *gadget, struct usb_function *f)
+{
+	pr_debug("clear_desc\n");
+
+	if (gadget_is_superspeed(gadget) && f->ss_descriptors)
+		usb_free_descriptors(f->ss_descriptors);
+
+	if (gadget_is_dualspeed(gadget) && f->hs_descriptors)
+		usb_free_descriptors(f->hs_descriptors);
+}
+
+static int qdss_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct usb_gadget *gadget = c->cdev->gadget;
+	struct f_qdss *qdss = func_to_qdss(f);
+	struct usb_ep *ep;
+	int iface;
+
+	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) {
+		pr_err("interface allocation error\n");
+		return iface;
+	}
+	qdss_data_intf_desc.bInterfaceNumber = iface;
+	qdss->data_iface_id = iface;
+
+	/* Allocate ctrl I/F */
+	iface = usb_interface_id(c, f);
+	if (iface < 0) {
+		pr_err("interface allocation error\n");
+		return iface;
+	}
+	qdss_ctrl_intf_desc.bInterfaceNumber = iface;
+	qdss->ctrl_iface_id = iface;
+
+	ep = usb_ep_autoconfig_ss(gadget, &qdss_ss_data_desc,
+		&qdss_data_ep_comp_desc);
+	if (!ep) {
+		pr_err("ep_autoconfig error\n");
+		goto fail;
+	}
+	qdss->data = ep;
+	ep->driver_data = qdss;
+
+	ep = usb_ep_autoconfig_ss(gadget, &qdss_ss_ctrl_in_desc,
+		&qdss_ctrl_in_ep_comp_desc);
+	if (!ep) {
+		pr_err("ep_autoconfig error\n");
+		goto fail;
+	}
+	qdss->ctrl_in = ep;
+	ep->driver_data = qdss;
+
+	ep = usb_ep_autoconfig_ss(gadget, &qdss_ss_ctrl_out_desc,
+		&qdss_ctrl_out_ep_comp_desc);
+	if (!ep) {
+		pr_err("ep_autoconfig error\n");
+		goto fail;
+	}
+	qdss->ctrl_out = ep;
+	ep->driver_data = qdss;
+
+	/*update descriptors*/
+	qdss_hs_data_desc.bEndpointAddress =
+		qdss_ss_data_desc.bEndpointAddress;
+	qdss_hs_ctrl_in_desc.bEndpointAddress =
+		qdss_ss_ctrl_in_desc.bEndpointAddress;
+	qdss_hs_ctrl_out_desc.bEndpointAddress =
+		qdss_ss_ctrl_out_desc.bEndpointAddress;
+
+	f->hs_descriptors = usb_copy_descriptors(qdss_hs_desc);
+	if (!f->hs_descriptors) {
+		pr_err("usb_copy_descriptors error\n");
+		goto fail;
+	}
+
+	/* update ss descriptors */
+	if (gadget_is_superspeed(gadget)) {
+		f->ss_descriptors = usb_copy_descriptors(qdss_ss_desc);
+		if (!f->ss_descriptors) {
+			pr_err("usb_copy_descriptors error\n");
+			goto fail;
+		}
+	}
+
+	return 0;
+fail:
+	clear_eps(f);
+	clear_desc(gadget, f);
+	return -ENOTSUPP;
+}
+
+
+static void qdss_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	pr_debug("qdss_unbind\n");
+
+	clear_desc(c->cdev->gadget, f);
+}
+
+static void qdss_eps_disable(struct usb_function *f)
+{
+	struct f_qdss  *qdss = func_to_qdss(f);
+
+	pr_debug("qdss_eps_disable\n");
+
+	if (qdss->ctrl_in_enabled) {
+		usb_ep_disable(qdss->ctrl_in);
+		qdss->ctrl_in_enabled = 0;
+		qdss->ctrl_in->driver_data = NULL;
+	}
+
+	if (qdss->ctrl_out_enabled) {
+		usb_ep_disable(qdss->ctrl_out);
+		qdss->ctrl_out_enabled = 0;
+		qdss->ctrl_out->driver_data = NULL;
+	}
+
+	if (qdss->data_enabled) {
+		usb_ep_disable(qdss->data);
+		qdss->data_enabled = 0;
+		qdss->data->driver_data = NULL;
+	}
+}
+
+static void qdss_disable(struct usb_function *f)
+{
+	struct f_qdss	*qdss = func_to_qdss(f);
+	unsigned long flags;
+	int status;
+
+	pr_debug("qdss_disable\n");
+
+	spin_lock_irqsave(&qdss->lock, flags);
+	qdss->usb_connected = 0;
+	spin_unlock_irqrestore(&qdss->lock, flags);
+
+	/*cancell all active xfers*/
+	qdss_eps_disable(f);
+
+	/* notify qdss to cancell all active transfers*/
+	if (qdss->ch.notify) {
+		qdss->ch.notify(qdss->ch.priv, USB_QDSS_DISCONNECT, NULL,
+			NULL);
+		/* If the app was never started, we can skip USB BAM reset */
+		status = set_qdss_data_connection(qdss->data,
+			qdss->data->address, 0);
+		if (status)
+			pr_err("qdss_disable error");
+	}
+}
+
+static void usb_qdss_work_func(struct work_struct *work)
+{
+	struct f_qdss *qdss = container_of(work, struct f_qdss, qdss_work);
+	int status;
+
+	pr_debug("usb_qdss_work_func\n");
+
+	status = init_data(qdss->data);
+	if (status) {
+		pr_err("init_data error");
+		return;
+	}
+
+	status = set_qdss_data_connection(qdss->data,
+		qdss->data->address, 1);
+	if (status) {
+		pr_err("set_qdss_data_connection error");
+		return;
+	}
+	if (qdss->ch.notify)
+		qdss->ch.notify(qdss->ch.priv, USB_QDSS_CONNECT, NULL,
+			&qdss->ch);
+
+	status = send_sps_req(qdss->data);
+	if (status) {
+		pr_err("send_sps_req error\n");
+		return;
+	}
+}
+
+static int qdss_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+	struct f_qdss  *qdss = func_to_qdss(f);
+	struct usb_gadget *gadget = f->config->cdev->gadget;
+	struct usb_qdss_ch *ch = &qdss->ch;
+	int ret = 0;
+
+	pr_debug("qdss_set_alt\n");
+
+	if (alt != 0)
+		goto fail;
+
+	if (gadget->speed != USB_SPEED_SUPER &&
+		gadget->speed != USB_SPEED_HIGH) {
+			pr_err("qdss_st_alt: qdss supportes HS or SS only\n");
+			goto fail;
+	}
+
+	if (intf == qdss->data_iface_id) {
+		if (config_ep_by_speed(gadget, f, qdss->data))
+			return -EINVAL;
+
+		ret = usb_ep_enable(qdss->data);
+		if (ret)
+			goto fail;
+
+		qdss->data->driver_data = qdss;
+		qdss->data_enabled = 1;
+
+	} else if (intf == qdss->ctrl_iface_id) {
+		if (config_ep_by_speed(gadget, f, qdss->ctrl_in))
+			return -EINVAL;
+
+		ret = usb_ep_enable(qdss->ctrl_in);
+		if (ret)
+			goto fail;
+
+		qdss->ctrl_in->driver_data = qdss;
+		qdss->ctrl_in_enabled = 1;
+
+		if (config_ep_by_speed(gadget, f, qdss->ctrl_out))
+			return -EINVAL;
+
+		ret = usb_ep_enable(qdss->ctrl_out);
+		if (ret)
+			goto fail;
+
+		qdss->ctrl_out->driver_data = qdss;
+		qdss->ctrl_out_enabled = 1;
+	}
+
+	if (qdss->ctrl_out_enabled && qdss->ctrl_in_enabled &&
+		qdss->data_enabled)
+		qdss->usb_connected = 1;
+
+	if (qdss->usb_connected && ch->app_conn)
+		schedule_work(&qdss->qdss_work);
+
+	return 0;
+fail:
+	pr_err("qdss_set_alt failed\n");
+	qdss_eps_disable(f);
+	return ret;
+}
+
+static int qdss_bind_config(struct usb_configuration *c, const char *name)
+{
+	struct f_qdss *qdss;
+	int status, found = 0;
+	struct usb_qdss_ch *ch;
+	unsigned long flags;
+
+	pr_debug("qdss_bind_config\n");
+
+	if (qdss_string_defs[QDSS_DATA_IDX].id == 0) {
+		status = usb_string_id(c->cdev);
+		if (status < 0)
+			return status;
+		qdss_string_defs[QDSS_DATA_IDX].id = status;
+		qdss_data_intf_desc.iInterface = status;
+
+		status = usb_string_id(c->cdev);
+		if (status < 0)
+			return status;
+		qdss_string_defs[QDSS_CTRL_IDX].id = status;
+		qdss_ctrl_intf_desc.iInterface = status;
+	}
+
+	spin_lock_irqsave(&d_lock, flags);
+	list_for_each_entry(ch, &usb_qdss_ch_list, list) {
+		if (!strncmp(name, ch->name, sizeof(ch->name))) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		pr_debug("qdss_bind_config allocating channel\n");
+		qdss = kzalloc(sizeof *qdss, GFP_ATOMIC);
+		if (!qdss) {
+			pr_err("qdss_bind_config: allocating channel failed\n");
+			spin_unlock_irqrestore(&d_lock, flags);
+			return -ENOMEM;
+		}
+
+		ch = &qdss->ch;
+		ch->name = name;
+		list_add_tail(&ch->list, &usb_qdss_ch_list);
+	} else {
+		qdss = container_of(ch, struct f_qdss, ch);
+		ch->priv_usb = qdss;
+	}
+	spin_unlock_irqrestore(&d_lock, flags);
+	qdss->cdev = c->cdev;
+	qdss->function.name = name;
+	qdss->function.descriptors = qdss_hs_desc;
+	qdss->function.hs_descriptors = qdss_hs_desc;
+	qdss->function.strings = qdss_strings;
+	qdss->function.bind = qdss_bind;
+	qdss->function.unbind = qdss_unbind;
+	qdss->function.set_alt = qdss_set_alt;
+	qdss->function.disable = qdss_disable;
+	INIT_LIST_HEAD(&qdss->ctrl_read_pool);
+	INIT_LIST_HEAD(&qdss->ctrl_write_pool);
+	INIT_WORK(&qdss->qdss_work, usb_qdss_work_func);
+
+	status = usb_add_function(c, &qdss->function);
+	if (status) {
+		pr_err("qdss usb_add_function failed\n");
+		ch->priv_usb = NULL;
+		kfree(qdss);
+	}
+
+	return status;
+}
+
+int usb_qdss_ctrl_read(struct usb_qdss_ch *ch, struct qdss_request *d_req)
+{
+	struct f_qdss *qdss = ch->priv_usb;
+	unsigned long flags;
+	struct usb_request *req = NULL;
+
+	pr_debug("usb_qdss_ctrl_read\n");
+
+	if (!qdss)
+		return -ENODEV;
+
+	spin_lock_irqsave(&qdss->lock, flags);
+
+	if (qdss->usb_connected == 0) {
+		spin_unlock_irqrestore(&qdss->lock, flags);
+		return -EIO;
+	}
+
+	if (list_empty(&qdss->ctrl_read_pool)) {
+		spin_unlock_irqrestore(&qdss->lock, flags);
+		pr_err("error: usb_qdss_ctrl_read list is empty\n");
+		return -EAGAIN;
+	}
+
+	req = list_first_entry(&qdss->ctrl_read_pool, struct usb_request, list);
+	list_del(&req->list);
+	spin_unlock_irqrestore(&qdss->lock, flags);
+
+	req->buf = d_req->buf;
+	req->length = d_req->length;
+	req->context = d_req;
+
+	if (usb_ep_queue(qdss->ctrl_out, req, GFP_ATOMIC)) {
+		/* If error add the link to linked list again*/
+		spin_lock_irqsave(&qdss->lock, flags);
+		list_add_tail(&req->list, &qdss->ctrl_read_pool);
+		spin_unlock_irqrestore(&qdss->lock, flags);
+		pr_err("qdss usb_ep_queue failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(usb_qdss_ctrl_read);
+
+int usb_qdss_ctrl_write(struct usb_qdss_ch *ch, struct qdss_request *d_req)
+{
+	struct f_qdss *qdss = ch->priv_usb;
+	unsigned long flags;
+	struct usb_request *req = NULL;
+
+	pr_debug("usb_qdss_ctrl_write\n");
+
+	if (!qdss)
+		return -ENODEV;
+
+	spin_lock_irqsave(&qdss->lock, flags);
+
+	if (qdss->usb_connected == 0) {
+		spin_unlock_irqrestore(&qdss->lock, flags);
+		return -EIO;
+	}
+
+	if (list_empty(&qdss->ctrl_write_pool)) {
+		pr_err("error: usb_qdss_ctrl_write list is empty\n");
+		spin_unlock_irqrestore(&qdss->lock, flags);
+		return -EAGAIN;
+	}
+
+	req = list_first_entry(&qdss->ctrl_write_pool, struct usb_request,
+		list);
+	list_del(&req->list);
+	spin_unlock_irqrestore(&qdss->lock, flags);
+
+	req->buf = d_req->buf;
+	req->length = d_req->length;
+	req->context = d_req;
+	if (usb_ep_queue(qdss->ctrl_in, req, GFP_ATOMIC)) {
+		spin_lock_irqsave(&qdss->lock, flags);
+		list_add_tail(&req->list, &qdss->ctrl_write_pool);
+		spin_unlock_irqrestore(&qdss->lock, flags);
+		pr_err("qdss usb_ep_queue failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(usb_qdss_ctrl_write);
+
+struct usb_qdss_ch *usb_qdss_open(const char *name, void *priv,
+	void (*notify)(void *, unsigned, struct qdss_request *,
+		struct usb_qdss_ch *))
+{
+	struct usb_qdss_ch *ch;
+	struct f_qdss *qdss;
+	unsigned long flags;
+	int found = 0;
+
+	pr_debug("usb_qdss_open\n");
+
+	if (!notify) {
+		pr_err("usb_qdss_open: notification func is missing\n");
+		return NULL;
+	}
+
+	spin_lock_irqsave(&d_lock, flags);
+	/* Check if we already have a channel with this name */
+	list_for_each_entry(ch, &usb_qdss_ch_list, list) {
+		if (!strncmp(name, ch->name, sizeof(ch->name))) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		pr_debug("usb_qdss_open: allocation qdss ctx\n");
+		qdss = kzalloc(sizeof(*qdss), GFP_ATOMIC);
+		if (!qdss) {
+			spin_unlock_irqrestore(&d_lock, flags);
+			return ERR_PTR(-ENOMEM);
+		}
+		ch = &qdss->ch;
+		list_add_tail(&ch->list, &usb_qdss_ch_list);
+	} else {
+		pr_debug("usb_qdss_open: qdss ctx found\n");
+		qdss = container_of(ch, struct f_qdss, ch);
+		ch->priv_usb = qdss;
+	}
+
+	ch->name = name;
+	ch->priv = priv;
+	ch->notify = notify;
+	ch->app_conn = 1;
+	spin_unlock_irqrestore(&d_lock, flags);
+
+	/* the case USB cabel was connected befor qdss called  qdss_open*/
+	if (qdss->usb_connected == 1)
+		schedule_work(&qdss->qdss_work);
+
+	return ch;
+}
+EXPORT_SYMBOL(usb_qdss_open);
+
+void usb_qdss_close(struct usb_qdss_ch *ch)
+{
+	struct f_qdss *qdss = ch->priv_usb;
+	unsigned long flags;
+
+	pr_debug("usb_qdss_close\n");
+
+	spin_lock_irqsave(&d_lock, flags);
+	/*free not used reqests*/
+	usb_qdss_free_req(ch);
+	usb_ep_dequeue(qdss->data, qdss->endless_req);
+	qdss->endless_req = NULL;
+	spin_unlock_irqrestore(&d_lock, flags);
+}
+EXPORT_SYMBOL(usb_qdss_close);
+
+static void qdss_cleanup(void)
+{
+	struct f_qdss *qdss;
+	struct list_head *act, *tmp;
+	struct usb_qdss_ch *_ch;
+	unsigned long flags;
+
+	pr_debug("qdss_cleanup\n");
+
+	list_for_each_safe(act, tmp, &usb_qdss_ch_list) {
+		_ch = list_entry(act, struct usb_qdss_ch, list);
+		qdss = container_of(_ch, struct f_qdss, ch);
+		spin_lock_irqsave(&d_lock, flags);
+
+		if (!_ch->priv) {
+			list_del(&_ch->list);
+			kfree(qdss);
+		}
+		spin_unlock_irqrestore(&d_lock, flags);
+	}
+}
+
+static int qdss_setup(void)
+{
+	return 0;
+}
+
diff --git a/drivers/usb/gadget/f_qdss.h b/drivers/usb/gadget/f_qdss.h
new file mode 100644
index 0000000..b61244b
--- /dev/null
+++ b/drivers/usb/gadget/f_qdss.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details
+ */
+
+#ifndef _F_QDSS_H
+#define _F_QDSS_H
+
+#include <linux/kernel.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/* struct f_qdss - USB qdss function driver private structure */
+struct f_qdss {
+	struct usb_function function;
+	struct usb_composite_dev *cdev;
+	u8 ctrl_iface_id;
+	u8 data_iface_id;
+	int usb_connected;
+	struct usb_request *endless_req;
+	struct usb_ep *ctrl_out;
+	struct usb_ep *ctrl_in;
+	struct usb_ep *data;
+	struct usb_qdss_ch ch;
+	struct list_head ctrl_read_pool;
+	struct list_head ctrl_write_pool;
+	struct work_struct qdss_work;
+	spinlock_t lock;
+	unsigned int data_enabled:1;
+	unsigned int ctrl_in_enabled:1;
+	unsigned int ctrl_out_enabled:1;
+};
+
+#endif
+
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 414a7b9..1d0b6d4 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -607,6 +607,7 @@
 	struct usb_cdc_notification	*event;
 	unsigned long			flags;
 	int				ret;
+	struct rmnet_ctrl_pkt	*cpkt;
 
 	pr_debug("%s:dev:%p portno#%d\n", __func__, dev, dev->port_num);
 
@@ -633,6 +634,14 @@
 	ret = usb_ep_queue(dev->notify, dev->notify_req, GFP_ATOMIC);
 	if (ret) {
 		atomic_dec(&dev->notify_count);
+		spin_lock_irqsave(&dev->lock, flags);
+		cpkt = list_first_entry(&dev->cpkt_resp_q,
+					struct rmnet_ctrl_pkt, list);
+		if (cpkt) {
+			list_del(&cpkt->list);
+			rmnet_free_ctrl_pkt(cpkt);
+		}
+		spin_unlock_irqrestore(&dev->lock, flags);
 		pr_debug("ep enqueue error %d\n", ret);
 	}
 }
@@ -768,6 +777,8 @@
 {
 	struct f_rmnet *dev = req->context;
 	int status = req->status;
+	unsigned long		flags;
+	struct rmnet_ctrl_pkt	*cpkt;
 
 	pr_debug("%s: dev:%p port#%d\n", __func__, dev, dev->port_num);
 
@@ -790,6 +801,14 @@
 		status = usb_ep_queue(dev->notify, req, GFP_ATOMIC);
 		if (status) {
 			atomic_dec(&dev->notify_count);
+			spin_lock_irqsave(&dev->lock, flags);
+			cpkt = list_first_entry(&dev->cpkt_resp_q,
+						struct rmnet_ctrl_pkt, list);
+			if (cpkt) {
+				list_del(&cpkt->list);
+				rmnet_free_ctrl_pkt(cpkt);
+			}
+			spin_unlock_irqrestore(&dev->lock, flags);
 			pr_debug("ep enqueue error %d\n", status);
 		}
 		break;
diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c
index 6fb2ce5..2461960 100644
--- a/drivers/usb/gadget/f_serial.c
+++ b/drivers/usb/gadget/f_serial.c
@@ -572,6 +572,7 @@
 #ifdef CONFIG_MODEM_SUPPORT
 	usb_ep_fifo_flush(gser->notify);
 	usb_ep_disable(gser->notify);
+	gser->notify->driver_data = NULL;
 #endif
 	gser->online = 0;
 }
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 16c4afb..e0520c7 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -585,8 +585,8 @@
 	resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION);
 	resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS);
 	resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3);
-	resp->MaxPacketsPerTransfer = cpu_to_le32(TX_SKB_HOLD_THRESHOLD);
-	resp->MaxTransferSize = cpu_to_le32(TX_SKB_HOLD_THRESHOLD *
+	resp->MaxPacketsPerTransfer = cpu_to_le32(params->max_pkt_per_xfer);
+	resp->MaxTransferSize = cpu_to_le32(params->max_pkt_per_xfer *
 		(params->dev->mtu
 		+ sizeof(struct ethhdr)
 		+ sizeof(struct rndis_packet_msg_type)
@@ -902,6 +902,8 @@
 			rndis_per_dev_params[i].used = 1;
 			rndis_per_dev_params[i].resp_avail = resp_avail;
 			rndis_per_dev_params[i].v = v;
+			rndis_per_dev_params[i].max_pkt_per_xfer =
+							TX_SKB_HOLD_THRESHOLD;
 			pr_debug("%s: configNr = %d\n", __func__, i);
 			return i;
 		}
@@ -955,6 +957,13 @@
 	return 0;
 }
 
+void rndis_set_max_pkt_xfer(u8 configNr, u8 max_pkt_per_xfer)
+{
+	pr_debug("%s:\n", __func__);
+
+	rndis_per_dev_params[configNr].max_pkt_per_xfer = max_pkt_per_xfer;
+}
+
 void rndis_add_hdr(struct sk_buff *skb)
 {
 	struct rndis_packet_msg_type *header;
diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h
index 907c330..1f06c42 100644
--- a/drivers/usb/gadget/rndis.h
+++ b/drivers/usb/gadget/rndis.h
@@ -235,6 +235,7 @@
 	struct net_device	*dev;
 
 	u32			vendorID;
+	u8			max_pkt_per_xfer;
 	const char		*vendorDescr;
 	void			(*resp_avail)(void *v);
 	void			*v;
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 1fade88..a9e5d91 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -98,8 +98,8 @@
 	struct usb_request	*rx_req;
 	struct usb_request	*tx_req;
 
-	u8					src_pipe_idx;
-	u8					dst_pipe_idx;
+	u32					src_pipe_idx;
+	u32					dst_pipe_idx;
 	u8					connection_idx;
 
 	/* stats */
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index 73b4e75..a105f5d 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -50,8 +50,8 @@
 	struct usb_request	*rx_req;
 	struct usb_request	*tx_req;
 
-	u8			src_pipe_idx;
-	u8			dst_pipe_idx;
+	u32			src_pipe_idx;
+	u32			dst_pipe_idx;
 	u8			connection_idx;
 };
 
diff --git a/drivers/usb/gadget/u_ctrl_hsuart.c b/drivers/usb/gadget/u_ctrl_hsuart.c
index 7102d81..a55960e 100644
--- a/drivers/usb/gadget/u_ctrl_hsuart.c
+++ b/drivers/usb/gadget/u_ctrl_hsuart.c
@@ -289,7 +289,7 @@
 
 void ghsuart_ctrl_disconnect(void *gptr, int port_num)
 {
-	struct gctrl_port	*port;
+	struct ghsuart_ctrl_port	*port;
 	struct grmnet		*gr = NULL;
 	unsigned long		flags;
 
@@ -300,7 +300,7 @@
 		return;
 	}
 
-	port = gctrl_ports[port_num].port;
+	port = ghsuart_ctrl_ports[port_num].port;
 
 	if (!gptr || !port) {
 		pr_err("%s: grmnet port is null\n", __func__);
@@ -372,7 +372,7 @@
 static void ghsuart_ctrl_port_free(int portno)
 {
 	struct ghsuart_ctrl_port	*port = ghsuart_ctrl_ports[portno].port;
-	struct platform_driver	*pdrv = &gctrl_ports[portno].pdrv;
+	struct platform_driver	*pdrv = &ghsuart_ctrl_ports[portno].pdrv;
 
 	destroy_workqueue(port->wq);
 	if (pdrv)
diff --git a/drivers/usb/gadget/u_data_hsuart.c b/drivers/usb/gadget/u_data_hsuart.c
index 91b1190..74bb93f 100644
--- a/drivers/usb/gadget/u_data_hsuart.c
+++ b/drivers/usb/gadget/u_data_hsuart.c
@@ -843,12 +843,15 @@
 	ghsuart_data_free_buffers(port);
 
 	/* disable endpoints */
-	if (port->in)
+	if (port->in) {
 		usb_ep_disable(port->in);
+		port->in->driver_data = NULL;
+	}
 
-	if (port->out)
+	if (port->out) {
 		usb_ep_disable(port->out);
-
+		port->out->driver_data = NULL;
+	}
 	atomic_set(&port->connected, 0);
 
 	if (port->gtype == USB_GADGET_SERIAL) {
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 78ab8b7..fd10394 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -46,6 +46,8 @@
 
 #define UETH__VERSION	"29-May-2008"
 
+static struct workqueue_struct	*uether_wq;
+
 struct eth_dev {
 	/* lock is held while accessing port_usb
 	 * or updating its backlink port_usb->ioport
@@ -74,6 +76,7 @@
 						struct sk_buff_head *list);
 
 	struct work_struct	work;
+	struct work_struct	rx_work;
 
 	unsigned long		todo;
 #define	WORK_RX_MEMORY		0
@@ -88,7 +91,6 @@
 
 #define DEFAULT_QLEN	2	/* double buffering by default */
 
-
 #ifdef CONFIG_USB_GADGET_DUALSPEED
 
 static unsigned qmult = 10;
@@ -265,18 +267,16 @@
 		DBG(dev, "rx submit --> %d\n", retval);
 		if (skb)
 			dev_kfree_skb_any(skb);
-		spin_lock_irqsave(&dev->req_lock, flags);
-		list_add(&req->list, &dev->rx_reqs);
-		spin_unlock_irqrestore(&dev->req_lock, flags);
 	}
 	return retval;
 }
 
 static void rx_complete(struct usb_ep *ep, struct usb_request *req)
 {
-	struct sk_buff	*skb = req->context, *skb2;
+	struct sk_buff	*skb = req->context;
 	struct eth_dev	*dev = ep->driver_data;
 	int		status = req->status;
+	bool		queue = 0;
 
 	switch (status) {
 
@@ -300,30 +300,9 @@
 		} else {
 			skb_queue_tail(&dev->rx_frames, skb);
 		}
-		skb = NULL;
 
-		skb2 = skb_dequeue(&dev->rx_frames);
-		while (skb2) {
-			if (status < 0
-					|| ETH_HLEN > skb2->len
-					|| skb2->len > ETH_FRAME_LEN) {
-				dev->net->stats.rx_errors++;
-				dev->net->stats.rx_length_errors++;
-				DBG(dev, "rx length %d\n", skb2->len);
-				dev_kfree_skb_any(skb2);
-				goto next_frame;
-			}
-			skb2->protocol = eth_type_trans(skb2, dev->net);
-			dev->net->stats.rx_packets++;
-			dev->net->stats.rx_bytes += skb2->len;
-
-			/* no buffer copies needed, unless hardware can't
-			 * use skb buffers.
-			 */
-			status = netif_rx(skb2);
-next_frame:
-			skb2 = skb_dequeue(&dev->rx_frames);
-		}
+		if (!status)
+			queue = 1;
 		break;
 
 	/* software-driven interface shutdown */
@@ -346,22 +325,20 @@
 		/* FALLTHROUGH */
 
 	default:
+		queue = 1;
+		dev_kfree_skb_any(skb);
 		dev->net->stats.rx_errors++;
 		DBG(dev, "rx status %d\n", status);
 		break;
 	}
 
-	if (skb)
-		dev_kfree_skb_any(skb);
-	if (!netif_running(dev->net)) {
 clean:
-		spin_lock(&dev->req_lock);
-		list_add(&req->list, &dev->rx_reqs);
-		spin_unlock(&dev->req_lock);
-		req = NULL;
-	}
-	if (req)
-		rx_submit(dev, req, GFP_ATOMIC);
+	spin_lock(&dev->req_lock);
+	list_add(&req->list, &dev->rx_reqs);
+	spin_unlock(&dev->req_lock);
+
+	if (queue)
+		queue_work(uether_wq, &dev->rx_work);
 }
 
 static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n)
@@ -426,16 +403,24 @@
 {
 	struct usb_request	*req;
 	unsigned long		flags;
+	int			req_cnt = 0;
 
 	/* fill unused rxq slots with some skb */
 	spin_lock_irqsave(&dev->req_lock, flags);
 	while (!list_empty(&dev->rx_reqs)) {
+		/* break the nexus of continuous completion and re-submission*/
+		if (++req_cnt > qlen(dev->gadget))
+			break;
+
 		req = container_of(dev->rx_reqs.next,
 				struct usb_request, list);
 		list_del_init(&req->list);
 		spin_unlock_irqrestore(&dev->req_lock, flags);
 
 		if (rx_submit(dev, req, gfp_flags) < 0) {
+			spin_lock_irqsave(&dev->req_lock, flags);
+			list_add(&req->list, &dev->rx_reqs);
+			spin_unlock_irqrestore(&dev->req_lock, flags);
 			defer_kevent(dev, WORK_RX_MEMORY);
 			return;
 		}
@@ -445,6 +430,36 @@
 	spin_unlock_irqrestore(&dev->req_lock, flags);
 }
 
+static void process_rx_w(struct work_struct *work)
+{
+	struct eth_dev	*dev = container_of(work, struct eth_dev, rx_work);
+	struct sk_buff	*skb;
+	int		status = 0;
+
+	if (!dev->port_usb)
+		return;
+
+	while ((skb = skb_dequeue(&dev->rx_frames))) {
+		if (status < 0
+				|| ETH_HLEN > skb->len
+				|| skb->len > ETH_FRAME_LEN) {
+			dev->net->stats.rx_errors++;
+			dev->net->stats.rx_length_errors++;
+			DBG(dev, "rx length %d\n", skb->len);
+			dev_kfree_skb_any(skb);
+			continue;
+		}
+		skb->protocol = eth_type_trans(skb, dev->net);
+		dev->net->stats.rx_packets++;
+		dev->net->stats.rx_bytes += skb->len;
+
+		status = netif_rx_ni(skb);
+	}
+
+	if (netif_running(dev->net))
+		rx_fill(dev, GFP_KERNEL);
+}
+
 static void eth_work(struct work_struct *work)
 {
 	struct eth_dev	*dev = container_of(work, struct eth_dev, work);
@@ -931,6 +946,7 @@
 	spin_lock_init(&dev->lock);
 	spin_lock_init(&dev->req_lock);
 	INIT_WORK(&dev->work, eth_work);
+	INIT_WORK(&dev->rx_work, process_rx_w);
 	INIT_LIST_HEAD(&dev->tx_reqs);
 	INIT_LIST_HEAD(&dev->rx_reqs);
 
@@ -1096,6 +1112,7 @@
 {
 	struct eth_dev		*dev = link->ioport;
 	struct usb_request	*req;
+	struct sk_buff		*skb;
 
 	if (!dev)
 		return;
@@ -1138,6 +1155,12 @@
 		spin_lock(&dev->req_lock);
 	}
 	spin_unlock(&dev->req_lock);
+
+	spin_lock(&dev->rx_frames.lock);
+	while ((skb = __skb_dequeue(&dev->rx_frames)))
+		dev_kfree_skb_any(skb);
+	spin_unlock(&dev->rx_frames.lock);
+
 	link->out_ep->driver_data = NULL;
 	link->out_ep->desc = NULL;
 
@@ -1151,3 +1174,23 @@
 	link->ioport = NULL;
 	spin_unlock(&dev->lock);
 }
+
+static int __init gether_init(void)
+{
+	uether_wq  = create_singlethread_workqueue("uether");
+	if (!uether_wq) {
+		pr_err("%s: Unable to create workqueue: uether\n", __func__);
+		return -ENOMEM;
+	}
+	return 0;
+}
+module_init(gether_init);
+
+static void __exit gether_exit(void)
+{
+	destroy_workqueue(uether_wq);
+
+}
+module_exit(gether_exit);
+MODULE_DESCRIPTION("ethernet over USB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/gadget/u_qdss.c b/drivers/usb/gadget/u_qdss.c
new file mode 100644
index 0000000..d227c62
--- /dev/null
+++ b/drivers/usb/gadget/u_qdss.c
@@ -0,0 +1,136 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/usb/msm_hsusb.h>
+#include <mach/usb_bam.h>
+
+#define BAM_CONNC_IDX 0 /* USB bam connection index */
+
+struct  usb_qdss_bam_connect_info {
+	u32 usb_bam_pipe_idx;
+	u32 peer_pipe_idx;
+	u32 usb_bam_handle;
+	struct sps_mem_buffer *data_fifo;
+};
+
+static struct usb_qdss_bam_connect_info bam_info;
+
+int send_sps_req(struct usb_ep *data_ep)
+{
+	struct usb_request *req = NULL;
+	struct f_qdss *qdss = data_ep->driver_data;
+	struct usb_gadget *gadget = qdss->cdev->gadget;
+	u32 sps_params = 0;
+
+	pr_debug("send_sps_req\n");
+
+	req = usb_ep_alloc_request(data_ep, GFP_ATOMIC);
+	if (!req) {
+		pr_err("usb_ep_alloc_request failed\n");
+		return -ENOMEM;
+	}
+
+	if (gadget_is_dwc3(gadget)) {
+		req->length = 32*1024;
+		sps_params = MSM_SPS_MODE | MSM_DISABLE_WB | MSM_INTERNAL_MEM |
+			bam_info.usb_bam_pipe_idx;
+	} else {
+		/* non DWC3 BAM requires req->length to be 0 */
+		req->length = 0;
+		sps_params = (MSM_SPS_MODE | bam_info.usb_bam_pipe_idx |
+				MSM_VENDOR_ID) & ~MSM_IS_FINITE_TRANSFER;
+	}
+	req->udc_priv = sps_params;
+	qdss->endless_req = req;
+	if (usb_ep_queue(data_ep, req, GFP_ATOMIC)) {
+		pr_err("send_sps_req: usb_ep_queue error\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+int set_qdss_data_connection(struct usb_ep *data_ep, u8 data_addr, int enable)
+{
+	int res = 0;
+
+	pr_debug("set_qdss_data_connection\n");
+
+	if (enable) {
+		res = usb_bam_connect(BAM_CONNC_IDX, NULL,
+			&(bam_info.usb_bam_pipe_idx));
+		if (res) {
+			pr_err("usb_bam_connection error\n");
+			return res;
+		}
+
+		bam_info.data_fifo =
+			kzalloc(sizeof(struct sps_mem_buffer *), GFP_KERNEL);
+		if (!bam_info.data_fifo) {
+			pr_err("qdss_data_connection: memory alloc failed\n");
+			return -ENOMEM;
+		}
+		get_bam2bam_connection_info(BAM_CONNC_IDX,
+			PEER_PERIPHERAL_TO_USB, &bam_info.usb_bam_handle,
+			&bam_info.usb_bam_pipe_idx, &bam_info.peer_pipe_idx,
+			NULL, bam_info.data_fifo);
+
+		msm_data_fifo_config(data_ep, bam_info.data_fifo->phys_base,
+			bam_info.data_fifo->size, bam_info.usb_bam_pipe_idx);
+	} else {
+		kfree(bam_info.data_fifo);
+		res = usb_bam_disconnect_pipe(BAM_CONNC_IDX);
+		if (res) {
+			pr_err("usb_bam_disconnection error\n");
+			return res;
+		}
+
+	}
+	return res;
+}
+
+int init_data(struct usb_ep *ep)
+{
+	struct f_qdss *qdss = ep->driver_data;
+	struct usb_gadget *gadget = qdss->cdev->gadget;
+	int res = 0;
+
+	pr_debug("init_data\n");
+
+	if (gadget_is_dwc3(gadget)) {
+		res = msm_ep_config(ep);
+		if (res)
+			pr_err("msm_ep_config failed\n");
+	} else {
+		pr_debug("QDSS is used with non DWC3 core\n");
+	}
+
+	return res;
+}
+
+int uninit_data(struct usb_ep *ep)
+{
+	struct f_qdss *qdss = ep->driver_data;
+	struct usb_gadget *gadget = qdss->cdev->gadget;
+	int res = 0;
+
+	pr_err("uninit_data\n");
+
+	if (gadget_is_dwc3(gadget)) {
+		res = msm_ep_unconfig(ep);
+		if (res)
+			pr_err("msm_ep_config failed\n");
+	}
+
+	return res;
+}
diff --git a/drivers/usb/gadget/u_sdio.c b/drivers/usb/gadget/u_sdio.c
index 5e9b0ec..a604e1e 100644
--- a/drivers/usb/gadget/u_sdio.c
+++ b/drivers/usb/gadget/u_sdio.c
@@ -990,8 +990,10 @@
 
 	/* disable endpoints, aborting down any active I/O */
 	usb_ep_disable(gser->out);
+	gser->out->driver_data = NULL;
 
 	usb_ep_disable(gser->in);
+	gser->in->driver_data = NULL;
 
 	spin_lock_irqsave(&port->port_lock, flags);
 	gsdio_free_requests(gser->out, &port->read_pool);
diff --git a/drivers/usb/gadget/u_smd.c b/drivers/usb/gadget/u_smd.c
index a5ceaff..ce285a3 100644
--- a/drivers/usb/gadget/u_smd.c
+++ b/drivers/usb/gadget/u_smd.c
@@ -712,7 +712,9 @@
 
 	/* disable endpoints, aborting down any active I/O */
 	usb_ep_disable(gser->out);
+	gser->out->driver_data = NULL;
 	usb_ep_disable(gser->in);
+	gser->in->driver_data = NULL;
 
 	spin_lock_irqsave(&port->port_lock, flags);
 	gsmd_free_requests(gser->out, &port->read_pool);
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 3a84515..8003464 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -27,7 +27,6 @@
 #include <linux/err.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
-#include <linux/wakelock.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 
@@ -48,6 +47,8 @@
 #define USB_REG_START_OFFSET 0x90
 #define USB_REG_END_OFFSET 0x250
 
+static struct workqueue_struct  *ehci_wq;
+
 struct msm_hsic_hcd {
 	struct ehci_hcd		ehci;
 	struct device		*dev;
@@ -57,17 +58,19 @@
 	struct clk		*phy_clk;
 	struct clk		*cal_clk;
 	struct regulator	*hsic_vddcx;
-	bool			async_int;
 	atomic_t                in_lpm;
-	struct wake_lock	wlock;
 	int			peripheral_status_irq;
 	int			wakeup_irq;
 	int			wakeup_gpio;
 	bool			wakeup_irq_enabled;
-	atomic_t		pm_usage_cnt;
+	bool			irq_enabled;
+	bool			async_int;
 	uint32_t		bus_perf_client;
 	uint32_t		wakeup_int_cnt;
 	enum usb_vdd_type	vdd_type;
+
+	struct work_struct	bus_vote_w;
+	bool			bus_vote;
 };
 
 struct msm_hsic_hcd *__mehci;
@@ -599,13 +602,15 @@
 
 	disable_irq(hcd->irq);
 
-	/* make sure we don't race against a remote wakeup */
-	if (test_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags) ||
+	/* make sure we don't race against the root hub being resumed */
+	if (HCD_RH_RUNNING(hcd) || HCD_WAKEUP_PENDING(hcd) ||
 	    readl_relaxed(USB_PORTSC) & PORT_RESUME) {
-		dev_dbg(mehci->dev, "wakeup pending, aborting suspend\n");
+		dev_warn(mehci->dev, "%s: Root hub is not suspended\n",
+				__func__);
 		enable_irq(hcd->irq);
 		return -EBUSY;
 	}
+	mehci->irq_enabled = false;
 
 	/*
 	 * PHY may take some time or even fail to enter into low power
@@ -658,22 +663,18 @@
 		dev_err(mehci->dev, "unable to set vddcx voltage for VDD MIN\n");
 
 	if (mehci->bus_perf_client && debug_bus_voting_enabled) {
-		ret = msm_bus_scale_client_update_request(
-				mehci->bus_perf_client, 0);
-		if (ret)
-			dev_err(mehci->dev, "%s: Failed to dvote for "
-				   "bus bandwidth %d\n", __func__, ret);
+		mehci->bus_vote = false;
+		queue_work(ehci_wq, &mehci->bus_vote_w);
 	}
 
 	atomic_set(&mehci->in_lpm, 1);
+	mehci->irq_enabled = true;
 	enable_irq(hcd->irq);
 
 	mehci->wakeup_irq_enabled = 1;
 	enable_irq_wake(mehci->wakeup_irq);
 	enable_irq(mehci->wakeup_irq);
 
-	wake_unlock(&mehci->wlock);
-
 	dev_dbg(mehci->dev, "HSIC-USB in low power mode\n");
 
 	return 0;
@@ -697,14 +698,9 @@
 		mehci->wakeup_irq_enabled = 0;
 	}
 
-	wake_lock(&mehci->wlock);
-
 	if (mehci->bus_perf_client && debug_bus_voting_enabled) {
-		ret = msm_bus_scale_client_update_request(
-				mehci->bus_perf_client, 1);
-		if (ret)
-			dev_err(mehci->dev, "%s: Failed to vote for "
-				   "bus bandwidth %d\n", __func__, ret);
+		mehci->bus_vote = true;
+		queue_work(ehci_wq, &mehci->bus_vote_w);
 	}
 
 	min_vol = vdd_val[mehci->vdd_type][VDD_MIN];
@@ -757,29 +753,45 @@
 	if (mehci->async_int) {
 		mehci->async_int = false;
 		pm_runtime_put_noidle(mehci->dev);
-		enable_irq(hcd->irq);
 	}
 
-	if (atomic_read(&mehci->pm_usage_cnt)) {
-		atomic_set(&mehci->pm_usage_cnt, 0);
-		pm_runtime_put_noidle(mehci->dev);
+	if (!mehci->irq_enabled) {
+		enable_irq(hcd->irq);
+		mehci->irq_enabled = true;
 	}
 
+	pm_relax(mehci->dev);
+
 	dev_dbg(mehci->dev, "HSIC-USB exited from low power mode\n");
 
 	return 0;
 }
 #endif
 
+static void ehci_hsic_bus_vote_w(struct work_struct *w)
+{
+	struct msm_hsic_hcd *mehci =
+			container_of(w, struct msm_hsic_hcd, bus_vote_w);
+	int ret;
+
+	ret = msm_bus_scale_client_update_request(mehci->bus_perf_client,
+			mehci->bus_vote);
+	if (ret)
+		dev_err(mehci->dev, "%s: Failed to vote for bus bandwidth %d\n",
+				__func__, ret);
+}
+
 static irqreturn_t msm_hsic_irq(struct usb_hcd *hcd)
 {
 	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
 
 	if (atomic_read(&mehci->in_lpm)) {
 		disable_irq_nosync(hcd->irq);
+		mehci->irq_enabled = false;
 		dev_dbg(mehci->dev, "phy async intr\n");
 		mehci->async_int = true;
 		pm_runtime_get(mehci->dev);
+		pm_stay_awake(mehci->dev);
 		return IRQ_HANDLED;
 	}
 
@@ -996,7 +1008,9 @@
 	dev_dbg(mehci->dev, "%s: hsic remote wakeup interrupt cnt: %u\n",
 			__func__, mehci->wakeup_int_cnt);
 
-	wake_lock(&mehci->wlock);
+	mehci->async_int = true;
+	pm_runtime_get(mehci->dev);
+	pm_stay_awake(mehci->dev);
 
 	if (mehci->wakeup_irq_enabled) {
 		mehci->wakeup_irq_enabled = 0;
@@ -1004,11 +1018,6 @@
 		disable_irq_nosync(irq);
 	}
 
-	if (!atomic_read(&mehci->pm_usage_cnt)) {
-		atomic_set(&mehci->pm_usage_cnt, 1);
-		pm_runtime_get(mehci->dev);
-	}
-
 	return IRQ_HANDLED;
 }
 
@@ -1297,15 +1306,23 @@
 		goto deinit_vddcx;
 	}
 
+	ehci_wq = create_singlethread_workqueue("ehci_wq");
+	if (!ehci_wq) {
+		dev_err(&pdev->dev, "unable to create workqueue\n");
+		ret = -ENOMEM;
+		goto deinit_vddcx;
+	}
+
+	INIT_WORK(&mehci->bus_vote_w, ehci_hsic_bus_vote_w);
+
 	ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to register HCD\n");
 		goto unconfig_gpio;
 	}
 
+	mehci->irq_enabled = true;
 	device_init_wakeup(&pdev->dev, 1);
-	wake_lock_init(&mehci->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
-	wake_lock(&mehci->wlock);
 
 	if (mehci->peripheral_status_irq) {
 		ret = request_threaded_irq(mehci->peripheral_status_irq,
@@ -1343,11 +1360,8 @@
 		    msm_bus_scale_register_client(pdata->bus_scale_table);
 		/* Configure BUS performance parameters for MAX bandwidth */
 		if (mehci->bus_perf_client) {
-			ret = msm_bus_scale_client_update_request(
-					mehci->bus_perf_client, 1);
-			if (ret)
-				dev_err(&pdev->dev, "%s: Failed to vote for "
-					   "bus bandwidth %d\n", __func__, ret);
+			mehci->bus_vote = true;
+			queue_work(ehci_wq, &mehci->bus_vote_w);
 		} else {
 			dev_err(&pdev->dev, "%s: Failed to register BUS "
 						"scaling client!!\n", __func__);
@@ -1373,6 +1387,7 @@
 	return 0;
 
 unconfig_gpio:
+	destroy_workqueue(ehci_wq);
 	msm_hsic_config_gpios(mehci, 0);
 deinit_vddcx:
 	msm_hsic_init_vddcx(mehci, 0);
@@ -1400,6 +1415,14 @@
 		free_irq(mehci->wakeup_irq, mehci);
 	}
 
+	/*
+	 * If the update request is called after unregister, the request will
+	 * fail. Results are undefined if unregister is called in the middle of
+	 * update request.
+	 */
+	mehci->bus_vote = false;
+	cancel_work_sync(&mehci->bus_vote_w);
+
 	if (mehci->bus_perf_client)
 		msm_bus_scale_unregister_client(mehci->bus_perf_client);
 
@@ -1407,12 +1430,13 @@
 	device_init_wakeup(&pdev->dev, 0);
 	pm_runtime_set_suspended(&pdev->dev);
 
+	destroy_workqueue(ehci_wq);
+
 	usb_remove_hcd(hcd);
 	msm_hsic_config_gpios(mehci, 0);
 	msm_hsic_init_vddcx(mehci, 0);
 
 	msm_hsic_init_clocks(mehci, 0);
-	wake_lock_destroy(&mehci->wlock);
 	iounmap(hcd->regs);
 	usb_put_hcd(hcd);
 
@@ -1441,12 +1465,26 @@
 	return ret;
 }
 
+static int msm_hsic_pm_suspend_noirq(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+
+	if (mehci->async_int) {
+		dev_dbg(dev, "suspend_noirq: Aborting due to pending interrupt\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
 static int msm_hsic_pm_resume(struct device *dev)
 {
 	int ret;
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
 
+	dev_dbg(dev, "ehci-msm-hsic PM resume\n");
 	dbg_log_event(NULL, "PM Resume", 0);
 
 	if (device_may_wakeup(dev))
@@ -1500,6 +1538,7 @@
 #ifdef CONFIG_PM
 static const struct dev_pm_ops msm_hsic_dev_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(msm_hsic_pm_suspend, msm_hsic_pm_resume)
+	.suspend_noirq = msm_hsic_pm_suspend_noirq,
 	SET_RUNTIME_PM_OPS(msm_hsic_runtime_suspend, msm_hsic_runtime_resume,
 				msm_hsic_runtime_idle)
 };
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index 8a87a6a..c612cb9 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -54,6 +54,10 @@
 	bool					async_int;
 	bool					vbus_on;
 	atomic_t				in_lpm;
+	int					pmic_gpio_dp_irq;
+	bool					pmic_gpio_dp_irq_enabled;
+	uint32_t				pmic_gpio_int_cnt;
+	atomic_t				pm_usage_cnt;
 	struct wake_lock			wlock;
 };
 
@@ -603,6 +607,11 @@
 
 	atomic_set(&mhcd->in_lpm, 1);
 	enable_irq(hcd->irq);
+	if (mhcd->pmic_gpio_dp_irq) {
+		mhcd->pmic_gpio_dp_irq_enabled = 1;
+		enable_irq_wake(mhcd->pmic_gpio_dp_irq);
+		enable_irq(mhcd->pmic_gpio_dp_irq);
+	}
 	wake_unlock(&mhcd->wlock);
 
 	dev_info(mhcd->dev, "EHCI USB in low power mode\n");
@@ -622,6 +631,11 @@
 		return 0;
 	}
 
+	if (mhcd->pmic_gpio_dp_irq_enabled) {
+		disable_irq_wake(mhcd->pmic_gpio_dp_irq);
+		disable_irq_nosync(mhcd->pmic_gpio_dp_irq);
+		mhcd->pmic_gpio_dp_irq_enabled = 0;
+	}
 	wake_lock(&mhcd->wlock);
 
 	/* Vote for TCXO when waking up the phy */
@@ -669,6 +683,11 @@
 		enable_irq(hcd->irq);
 	}
 
+	if (atomic_read(&mhcd->pm_usage_cnt)) {
+		atomic_set(&mhcd->pm_usage_cnt, 0);
+		pm_runtime_put_noidle(mhcd->dev);
+	}
+
 	dev_info(mhcd->dev, "EHCI USB exited from low power mode\n");
 
 	return 0;
@@ -689,6 +708,32 @@
 	return ehci_irq(hcd);
 }
 
+static irqreturn_t msm_ehci_host_wakeup_irq(int irq, void *data)
+{
+
+	struct msm_hcd *mhcd = data;
+
+	mhcd->pmic_gpio_int_cnt++;
+	dev_dbg(mhcd->dev, "%s: hsusb host remote wakeup interrupt cnt: %u\n",
+			__func__, mhcd->pmic_gpio_int_cnt);
+
+
+	wake_lock(&mhcd->wlock);
+
+	if (mhcd->pmic_gpio_dp_irq_enabled) {
+		mhcd->pmic_gpio_dp_irq_enabled = 0;
+		disable_irq_wake(irq);
+		disable_irq_nosync(irq);
+	}
+
+	if (!atomic_read(&mhcd->pm_usage_cnt)) {
+		atomic_set(&mhcd->pm_usage_cnt, 1);
+		pm_runtime_get(mhcd->dev);
+	}
+
+	return IRQ_HANDLED;
+}
+
 static int msm_ehci_reset(struct usb_hcd *hcd)
 {
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
@@ -952,6 +997,22 @@
 	 * hence, runtime framework automatically calls this driver's
 	 * runtime APIs based on root-hub's state.
 	 */
+	/* configure pmic_gpio_irq for D+ change */
+	if (pdata && pdata->pmic_gpio_dp_irq)
+		mhcd->pmic_gpio_dp_irq = pdata->pmic_gpio_dp_irq;
+	if (mhcd->pmic_gpio_dp_irq) {
+		ret = request_threaded_irq(mhcd->pmic_gpio_dp_irq, NULL,
+				msm_ehci_host_wakeup_irq,
+				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+				"msm_ehci_host_wakeup", mhcd);
+		if (!ret) {
+			disable_irq_nosync(mhcd->pmic_gpio_dp_irq);
+		} else {
+			dev_err(&pdev->dev, "request_irq(%d) failed: %d\n",
+					mhcd->pmic_gpio_dp_irq, ret);
+			mhcd->pmic_gpio_dp_irq = 0;
+		}
+	}
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 
@@ -984,6 +1045,11 @@
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 	struct msm_hcd *mhcd = hcd_to_mhcd(hcd);
 
+	if (mhcd->pmic_gpio_dp_irq) {
+		if (mhcd->pmic_gpio_dp_irq_enabled)
+			disable_irq_wake(mhcd->pmic_gpio_dp_irq);
+		free_irq(mhcd->pmic_gpio_dp_irq, mhcd);
+	}
 	device_init_wakeup(&pdev->dev, 0);
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_set_suspended(&pdev->dev);
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index 13828e0..3aa2e5c 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -293,3 +293,13 @@
 	  driver for dial up network and RMNET.
 	  To compile this driver as a module, choose M here: the module
 	  will be called mdm_bridge. If unsure, choose N.
+
+config USB_QCOM_KS_BRIDGE
+	tristate "USB Qualcomm kick start bridge"
+	depends on USB
+	help
+	  Say Y here if you have a Qualcomm modem device connected via USB that
+	  will be bridged in kernel space. This driver works as a bridge to pass
+	  boot images, ram-dumps and efs sync
+	  To compile this driver as a module, choose M here: the module
+	  will be called ks_bridge. If unsure, choose N.
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index b4aee65..447e4d2 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -33,3 +33,4 @@
 obj-$(CONFIG_USB_QCOM_DIAG_BRIDGE_TEST)	+= diag_bridge_test.o
 mdm_bridge-y				:= mdm_ctrl_bridge.o mdm_data_bridge.o
 obj-$(CONFIG_USB_QCOM_MDM_BRIDGE) 	+= mdm_bridge.o
+obj-$(CONFIG_USB_QCOM_KS_BRIDGE)	+= ks_bridge.o
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
new file mode 100644
index 0000000..10cbe59
--- /dev/null
+++ b/drivers/usb/misc/ks_bridge.c
@@ -0,0 +1,805 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/* add additional information to our printk's */
+#define pr_fmt(fmt) "%s: " fmt "\n", __func__
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/platform_device.h>
+#include <linux/ratelimit.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/miscdevice.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+
+#define DRIVER_DESC	"USB host ks bridge driver"
+#define DRIVER_VERSION	"1.0"
+
+struct data_pkt {
+	int			n_read;
+	char			*buf;
+	size_t			len;
+	struct list_head	list;
+	void			*ctxt;
+};
+
+#define FILE_OPENED		BIT(0)
+#define USB_DEV_CONNECTED	BIT(1)
+#define NO_RX_REQS		10
+#define NO_BRIDGE_INSTANCES	2
+#define BOOT_BRIDGE_INDEX	0
+#define EFS_BRIDGE_INDEX	1
+#define MAX_DATA_PKT_SIZE	16384
+
+struct ks_bridge {
+	char			*name;
+	spinlock_t		lock;
+	struct workqueue_struct	*wq;
+	struct work_struct	to_mdm_work;
+	struct work_struct	start_rx_work;
+	struct list_head	to_mdm_list;
+	struct list_head	to_ks_list;
+	wait_queue_head_t	ks_wait_q;
+
+	/* usb specific */
+	struct usb_device	*udev;
+	struct usb_interface	*ifc;
+	__u8			in_epAddr;
+	__u8			out_epAddr;
+	unsigned int		in_pipe;
+	unsigned int		out_pipe;
+	struct usb_anchor	submitted;
+
+	unsigned long		flags;
+	unsigned int		alloced_read_pkts;
+
+#define DBG_MSG_LEN   40
+#define DBG_MAX_MSG   500
+	unsigned int	dbg_idx;
+	rwlock_t	dbg_lock;
+	char     (dbgbuf[DBG_MAX_MSG])[DBG_MSG_LEN];   /* buffer */
+};
+struct ks_bridge *__ksb[NO_BRIDGE_INSTANCES];
+
+/* by default debugging is enabled */
+static unsigned int enable_dbg = 1;
+module_param(enable_dbg, uint, S_IRUGO | S_IWUSR);
+
+static void
+dbg_log_event(struct ks_bridge *ksb, char *event, int d1, int d2)
+{
+	unsigned long flags;
+	unsigned long long t;
+	unsigned long nanosec;
+
+	if (!enable_dbg)
+		return;
+
+	write_lock_irqsave(&ksb->dbg_lock, flags);
+	t = cpu_clock(smp_processor_id());
+	nanosec = do_div(t, 1000000000)/1000;
+	scnprintf(ksb->dbgbuf[ksb->dbg_idx], DBG_MSG_LEN, "%5lu.%06lu:%s:%x:%x",
+			(unsigned long)t, nanosec, event, d1, d2);
+
+	ksb->dbg_idx++;
+	ksb->dbg_idx = ksb->dbg_idx % DBG_MAX_MSG;
+	write_unlock_irqrestore(&ksb->dbg_lock, flags);
+}
+
+static
+struct data_pkt *ksb_alloc_data_pkt(size_t count, gfp_t flags, void *ctxt)
+{
+	struct data_pkt *pkt;
+
+	pkt = kzalloc(sizeof(struct data_pkt), flags);
+	if (!pkt) {
+		pr_err("failed to allocate data packet\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	pkt->buf = kmalloc(count, flags);
+	if (!pkt->buf) {
+		pr_err("failed to allocate data buffer\n");
+		kfree(pkt);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	pkt->len = count;
+	INIT_LIST_HEAD(&pkt->list);
+	pkt->ctxt = ctxt;
+
+	return pkt;
+}
+
+static void ksb_free_data_pkt(struct data_pkt *pkt)
+{
+	kfree(pkt->buf);
+	kfree(pkt);
+}
+
+
+static ssize_t ksb_fs_read(struct file *fp, char __user *buf,
+				size_t count, loff_t *pos)
+{
+	int ret;
+	unsigned long flags;
+	struct ks_bridge *ksb = fp->private_data;
+	struct data_pkt *pkt;
+	size_t space, copied;
+
+read_start:
+	if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
+		return -ENODEV;
+
+	spin_lock_irqsave(&ksb->lock, flags);
+	if (list_empty(&ksb->to_ks_list)) {
+		spin_unlock_irqrestore(&ksb->lock, flags);
+		ret = wait_event_interruptible(ksb->ks_wait_q,
+				!list_empty(&ksb->to_ks_list) ||
+				!test_bit(USB_DEV_CONNECTED, &ksb->flags));
+		if (ret < 0)
+			return ret;
+
+		goto read_start;
+	}
+
+	space = count;
+	copied = 0;
+	while (!list_empty(&ksb->to_ks_list) && space) {
+		size_t len;
+
+		pkt = list_first_entry(&ksb->to_ks_list, struct data_pkt, list);
+		len = min_t(size_t, space, pkt->len);
+		pkt->n_read += len;
+		spin_unlock_irqrestore(&ksb->lock, flags);
+
+		ret = copy_to_user(buf + copied, pkt->buf, len);
+		if (ret) {
+			pr_err("copy_to_user failed err:%d\n", ret);
+			ksb_free_data_pkt(pkt);
+			ksb->alloced_read_pkts--;
+			return ret;
+		}
+
+		space -= len;
+		copied += len;
+
+		spin_lock_irqsave(&ksb->lock, flags);
+		if (pkt->n_read == pkt->len) {
+			list_del_init(&pkt->list);
+			ksb_free_data_pkt(pkt);
+			ksb->alloced_read_pkts--;
+		}
+	}
+	spin_unlock_irqrestore(&ksb->lock, flags);
+
+	dbg_log_event(ksb, "KS_READ", copied, 0);
+
+	pr_debug("count:%d space:%d copied:%d", count, space, copied);
+
+	return copied;
+}
+
+static void ksb_tx_cb(struct urb *urb)
+{
+	struct data_pkt *pkt = urb->context;
+	struct ks_bridge *ksb = pkt->ctxt;
+
+	dbg_log_event(ksb, "C TX_URB", urb->status, 0);
+	pr_debug("status:%d", urb->status);
+
+	if (ksb->ifc)
+		usb_autopm_put_interface_async(ksb->ifc);
+
+	if (urb->status < 0)
+		pr_err_ratelimited("urb failed with err:%d", urb->status);
+
+	ksb_free_data_pkt(pkt);
+}
+
+static void ksb_tomdm_work(struct work_struct *w)
+{
+	struct ks_bridge *ksb = container_of(w, struct ks_bridge, to_mdm_work);
+	struct data_pkt	*pkt;
+	unsigned long flags;
+	struct urb *urb;
+	int ret;
+
+	spin_lock_irqsave(&ksb->lock, flags);
+	while (!list_empty(&ksb->to_mdm_list)
+			&& test_bit(USB_DEV_CONNECTED, &ksb->flags)) {
+		pkt = list_first_entry(&ksb->to_mdm_list,
+				struct data_pkt, list);
+		list_del_init(&pkt->list);
+		spin_unlock_irqrestore(&ksb->lock, flags);
+
+		urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!urb) {
+			pr_err_ratelimited("unable to allocate urb");
+			ksb_free_data_pkt(pkt);
+			return;
+		}
+
+		ret = usb_autopm_get_interface(ksb->ifc);
+		if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
+			pr_err_ratelimited("autopm_get failed:%d", ret);
+			usb_free_urb(urb);
+			ksb_free_data_pkt(pkt);
+			return;
+		}
+		usb_fill_bulk_urb(urb, ksb->udev, ksb->out_pipe,
+				pkt->buf, pkt->len, ksb_tx_cb, pkt);
+		usb_anchor_urb(urb, &ksb->submitted);
+
+		dbg_log_event(ksb, "S TX_URB", pkt->len, 0);
+
+		ret = usb_submit_urb(urb, GFP_KERNEL);
+		if (ret) {
+			pr_err("out urb submission failed");
+			usb_unanchor_urb(urb);
+			usb_free_urb(urb);
+			ksb_free_data_pkt(pkt);
+			usb_autopm_put_interface(ksb->ifc);
+			return;
+		}
+
+		spin_lock_irqsave(&ksb->lock, flags);
+	}
+	spin_unlock_irqrestore(&ksb->lock, flags);
+}
+
+static ssize_t ksb_fs_write(struct file *fp, const char __user *buf,
+				 size_t count, loff_t *pos)
+{
+	int			ret;
+	struct data_pkt		*pkt;
+	unsigned long		flags;
+	struct ks_bridge	*ksb = fp->private_data;
+
+	pkt = ksb_alloc_data_pkt(count, GFP_KERNEL, ksb);
+	if (IS_ERR(pkt)) {
+		pr_err("unable to allocate data packet");
+		return PTR_ERR(pkt);
+	}
+
+	ret = copy_from_user(pkt->buf, buf, count);
+	if (ret) {
+		pr_err("copy_from_user failed: err:%d", ret);
+		ksb_free_data_pkt(pkt);
+		return ret;
+	}
+
+	spin_lock_irqsave(&ksb->lock, flags);
+	list_add_tail(&pkt->list, &ksb->to_mdm_list);
+	spin_unlock_irqrestore(&ksb->lock, flags);
+
+	queue_work(ksb->wq, &ksb->to_mdm_work);
+
+	return count;
+}
+
+static int efs_fs_open(struct inode *ip, struct file *fp)
+{
+	struct ks_bridge *ksb = __ksb[EFS_BRIDGE_INDEX];
+
+	pr_debug(":%s", ksb->name);
+	dbg_log_event(ksb, "EFS-FS-OPEN", 0, 0);
+
+	if (!ksb) {
+		pr_err("ksb is being removed");
+		return -ENODEV;
+	}
+
+	fp->private_data = ksb;
+	set_bit(FILE_OPENED, &ksb->flags);
+
+	if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
+		queue_work(ksb->wq, &ksb->start_rx_work);
+
+	return 0;
+}
+
+static int ksb_fs_open(struct inode *ip, struct file *fp)
+{
+	struct ks_bridge *ksb = __ksb[BOOT_BRIDGE_INDEX];
+
+	pr_debug(":%s", ksb->name);
+	dbg_log_event(ksb, "KS-FS-OPEN", 0, 0);
+
+	if (!ksb) {
+		pr_err("ksb is being removed");
+		return -ENODEV;
+	}
+
+	fp->private_data = ksb;
+	set_bit(FILE_OPENED, &ksb->flags);
+
+	if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
+		queue_work(ksb->wq, &ksb->start_rx_work);
+
+	return 0;
+}
+
+static int ksb_fs_release(struct inode *ip, struct file *fp)
+{
+	struct ks_bridge	*ksb = fp->private_data;
+
+	pr_debug(":%s", ksb->name);
+	dbg_log_event(ksb, "FS-RELEASE", 0, 0);
+
+	clear_bit(FILE_OPENED, &ksb->flags);
+	fp->private_data = NULL;
+
+	return 0;
+}
+
+static const struct file_operations ksb_fops = {
+	.owner = THIS_MODULE,
+	.read = ksb_fs_read,
+	.write = ksb_fs_write,
+	.open = ksb_fs_open,
+	.release = ksb_fs_release,
+};
+
+static struct miscdevice ksb_fboot_dev = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "ks_bridge",
+	.fops = &ksb_fops,
+};
+
+static const struct file_operations efs_fops = {
+	.owner = THIS_MODULE,
+	.read = ksb_fs_read,
+	.write = ksb_fs_write,
+	.open = efs_fs_open,
+	.release = ksb_fs_release,
+};
+
+static struct miscdevice ksb_efs_dev = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "efs_bridge",
+	.fops = &efs_fops,
+};
+
+static const struct usb_device_id ksb_usb_ids[] = {
+	{ USB_DEVICE(0x5c6, 0x9008),
+	.driver_info = (unsigned long)&ksb_fboot_dev, },
+	{ USB_DEVICE(0x5c6, 0x9048),
+	.driver_info = (unsigned long)&ksb_efs_dev, },
+	{ USB_DEVICE(0x5c6, 0x904C),
+	.driver_info = (unsigned long)&ksb_efs_dev, },
+
+	{} /* terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, ksb_usb_ids);
+
+static void ksb_rx_cb(struct urb *urb);
+static void submit_one_urb(struct ks_bridge *ksb)
+{
+	struct data_pkt	*pkt;
+	struct urb *urb;
+	int ret;
+
+	pkt = ksb_alloc_data_pkt(MAX_DATA_PKT_SIZE, GFP_ATOMIC, ksb);
+	if (IS_ERR(pkt)) {
+		pr_err("unable to allocate data pkt");
+		return;
+	}
+
+	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!urb) {
+		pr_err("unable to allocate urb");
+		ksb_free_data_pkt(pkt);
+		return;
+	}
+	ksb->alloced_read_pkts++;
+
+	usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe,
+			pkt->buf, pkt->len,
+			ksb_rx_cb, pkt);
+	usb_anchor_urb(urb, &ksb->submitted);
+
+	dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
+
+	ret = usb_submit_urb(urb, GFP_ATOMIC);
+	if (ret) {
+		pr_err("in urb submission failed");
+		usb_unanchor_urb(urb);
+		usb_free_urb(urb);
+		ksb_free_data_pkt(pkt);
+		ksb->alloced_read_pkts--;
+		return;
+	}
+
+	usb_free_urb(urb);
+}
+static void ksb_rx_cb(struct urb *urb)
+{
+	struct data_pkt *pkt = urb->context;
+	struct ks_bridge *ksb = pkt->ctxt;
+
+	dbg_log_event(ksb, "C RX_URB", urb->status, urb->actual_length);
+
+	pr_debug("status:%d actual:%d", urb->status, urb->actual_length);
+
+	if (urb->status < 0) {
+		if (urb->status != -ESHUTDOWN && urb->status != -ENOENT)
+			pr_err_ratelimited("urb failed with err:%d",
+					urb->status);
+		ksb_free_data_pkt(pkt);
+		ksb->alloced_read_pkts--;
+		return;
+	}
+
+	if (urb->actual_length == 0) {
+		ksb_free_data_pkt(pkt);
+		ksb->alloced_read_pkts--;
+		goto resubmit_urb;
+	}
+
+	spin_lock(&ksb->lock);
+	pkt->len = urb->actual_length;
+	list_add_tail(&pkt->list, &ksb->to_ks_list);
+	spin_unlock(&ksb->lock);
+
+	/* wake up read thread */
+	wake_up(&ksb->ks_wait_q);
+
+resubmit_urb:
+	submit_one_urb(ksb);
+
+}
+
+static void ksb_start_rx_work(struct work_struct *w)
+{
+	struct ks_bridge *ksb =
+			container_of(w, struct ks_bridge, start_rx_work);
+	struct data_pkt	*pkt;
+	struct urb *urb;
+	int i = 0;
+	int ret;
+
+	for (i = 0; i < NO_RX_REQS; i++) {
+		pkt = ksb_alloc_data_pkt(MAX_DATA_PKT_SIZE, GFP_KERNEL, ksb);
+		if (IS_ERR(pkt)) {
+			pr_err("unable to allocate data pkt");
+			return;
+		}
+
+		urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!urb) {
+			pr_err("unable to allocate urb");
+			ksb_free_data_pkt(pkt);
+			return;
+		}
+
+		ret = usb_autopm_get_interface(ksb->ifc);
+		if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
+			pr_err_ratelimited("autopm_get failed:%d", ret);
+			usb_free_urb(urb);
+			ksb_free_data_pkt(pkt);
+			return;
+		}
+		ksb->alloced_read_pkts++;
+
+		usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe,
+				pkt->buf, pkt->len,
+				ksb_rx_cb, pkt);
+		usb_anchor_urb(urb, &ksb->submitted);
+
+		dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
+
+		ret = usb_submit_urb(urb, GFP_KERNEL);
+		if (ret) {
+			pr_err("in urb submission failed");
+			usb_unanchor_urb(urb);
+			usb_free_urb(urb);
+			ksb_free_data_pkt(pkt);
+			ksb->alloced_read_pkts--;
+			usb_autopm_put_interface(ksb->ifc);
+			return;
+		}
+
+		usb_autopm_put_interface_async(ksb->ifc);
+		usb_free_urb(urb);
+	}
+}
+
+static int
+ksb_usb_probe(struct usb_interface *ifc, const struct usb_device_id *id)
+{
+	__u8				ifc_num;
+	struct usb_host_interface	*ifc_desc;
+	struct usb_endpoint_descriptor	*ep_desc;
+	int				i;
+	struct ks_bridge		*ksb;
+	struct miscdevice		*fs_dev;
+
+	ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
+
+	switch (id->idProduct) {
+	case 0x9008:
+		if (ifc_num != 0)
+			return -ENODEV;
+		ksb = __ksb[BOOT_BRIDGE_INDEX];
+		break;
+	case 0x9048:
+	case 0x904C:
+		if (ifc_num != 2)
+			return -ENODEV;
+		ksb = __ksb[EFS_BRIDGE_INDEX];
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	if (!ksb) {
+		pr_err("ksb is not initialized");
+		return -ENODEV;
+	}
+
+	ksb->udev = usb_get_dev(interface_to_usbdev(ifc));
+	ksb->ifc = ifc;
+	ifc_desc = ifc->cur_altsetting;
+
+	for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
+		ep_desc = &ifc_desc->endpoint[i].desc;
+
+		if (!ksb->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
+			ksb->in_epAddr = ep_desc->bEndpointAddress;
+
+		if (!ksb->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
+			ksb->out_epAddr = ep_desc->bEndpointAddress;
+	}
+
+	if (!(ksb->in_epAddr && ksb->out_epAddr)) {
+		pr_err("could not find bulk in and bulk out endpoints");
+		usb_put_dev(ksb->udev);
+		ksb->ifc = NULL;
+		return -ENODEV;
+	}
+
+	ksb->in_pipe = usb_rcvbulkpipe(ksb->udev, ksb->in_epAddr);
+	ksb->out_pipe = usb_sndbulkpipe(ksb->udev, ksb->out_epAddr);
+
+	usb_set_intfdata(ifc, ksb);
+	set_bit(USB_DEV_CONNECTED, &ksb->flags);
+
+	dbg_log_event(ksb, "PID-ATT", id->idProduct, 0);
+
+	fs_dev = (struct miscdevice *)id->driver_info;
+	misc_register(fs_dev);
+
+	usb_enable_autosuspend(ksb->udev);
+
+	pr_debug("usb dev connected");
+
+	return 0;
+}
+
+static int ksb_usb_suspend(struct usb_interface *ifc, pm_message_t message)
+{
+	struct ks_bridge *ksb = usb_get_intfdata(ifc);
+
+	dbg_log_event(ksb, "SUSPEND", 0, 0);
+
+	pr_info("read cnt: %d", ksb->alloced_read_pkts);
+
+	usb_kill_anchored_urbs(&ksb->submitted);
+
+	return 0;
+}
+
+static int ksb_usb_resume(struct usb_interface *ifc)
+{
+	struct ks_bridge *ksb = usb_get_intfdata(ifc);
+
+	dbg_log_event(ksb, "RESUME", 0, 0);
+
+	if (test_bit(FILE_OPENED, &ksb->flags))
+		queue_work(ksb->wq, &ksb->start_rx_work);
+
+	return 0;
+}
+
+static void ksb_usb_disconnect(struct usb_interface *ifc)
+{
+	struct ks_bridge *ksb = usb_get_intfdata(ifc);
+	unsigned long flags;
+	struct data_pkt *pkt;
+
+	dbg_log_event(ksb, "PID-DETACH", 0, 0);
+
+	clear_bit(USB_DEV_CONNECTED, &ksb->flags);
+	wake_up(&ksb->ks_wait_q);
+	cancel_work_sync(&ksb->to_mdm_work);
+
+	usb_kill_anchored_urbs(&ksb->submitted);
+
+	spin_lock_irqsave(&ksb->lock, flags);
+	while (!list_empty(&ksb->to_ks_list)) {
+		pkt = list_first_entry(&ksb->to_ks_list,
+				struct data_pkt, list);
+		list_del_init(&pkt->list);
+		ksb_free_data_pkt(pkt);
+	}
+	while (!list_empty(&ksb->to_mdm_list)) {
+		pkt = list_first_entry(&ksb->to_mdm_list,
+				struct data_pkt, list);
+		list_del_init(&pkt->list);
+		ksb_free_data_pkt(pkt);
+	}
+	spin_unlock_irqrestore(&ksb->lock, flags);
+
+	usb_put_dev(ksb->udev);
+	ksb->ifc = NULL;
+	usb_set_intfdata(ifc, NULL);
+
+	return;
+}
+
+static struct usb_driver ksb_usb_driver = {
+	.name =		"ks_bridge",
+	.probe =	ksb_usb_probe,
+	.disconnect =	ksb_usb_disconnect,
+	.suspend =	ksb_usb_suspend,
+	.resume =	ksb_usb_resume,
+	.id_table =	ksb_usb_ids,
+	.supports_autosuspend = 1,
+};
+
+static ssize_t ksb_debug_show(struct seq_file *s, void *unused)
+{
+	unsigned long		flags;
+	struct ks_bridge	*ksb = s->private;
+	int			i;
+
+	read_lock_irqsave(&ksb->dbg_lock, flags);
+	for (i = 0; i < DBG_MAX_MSG; i++) {
+		if (i == (ksb->dbg_idx - 1))
+			seq_printf(s, "-->%s\n", ksb->dbgbuf[i]);
+		else
+			seq_printf(s, "%s\n", ksb->dbgbuf[i]);
+	}
+	read_unlock_irqrestore(&ksb->dbg_lock, flags);
+
+	return 0;
+}
+
+static int ksb_debug_open(struct inode *ip, struct file *fp)
+{
+	return single_open(fp, ksb_debug_show, ip->i_private);
+
+	return 0;
+}
+
+static const struct file_operations dbg_fops = {
+	.open = ksb_debug_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+static struct dentry *dbg_dir;
+static int __init ksb_init(void)
+{
+	struct ks_bridge *ksb;
+	int num_instances = 0;
+	int ret = 0;
+	int i;
+
+	dbg_dir = debugfs_create_dir("ks_bridge", NULL);
+	if (IS_ERR(dbg_dir))
+		pr_err("unable to create debug dir");
+
+	for (i = 0; i < NO_BRIDGE_INSTANCES; i++) {
+		ksb = kzalloc(sizeof(struct ks_bridge), GFP_KERNEL);
+		if (!ksb) {
+			pr_err("unable to allocat mem for ks_bridge");
+			return -ENOMEM;
+		}
+		__ksb[i] = ksb;
+
+		ksb->name = kasprintf(GFP_KERNEL, "ks_bridge:%i", i + 1);
+		if (!ksb->name) {
+			pr_info("unable to allocate name");
+			kfree(ksb);
+			ret = -ENOMEM;
+			goto dev_free;
+		}
+
+		spin_lock_init(&ksb->lock);
+		INIT_LIST_HEAD(&ksb->to_mdm_list);
+		INIT_LIST_HEAD(&ksb->to_ks_list);
+		init_waitqueue_head(&ksb->ks_wait_q);
+		ksb->wq = create_singlethread_workqueue(ksb->name);
+		if (!ksb->wq) {
+			pr_err("unable to allocate workqueue");
+			kfree(ksb->name);
+			kfree(ksb);
+			ret = -ENOMEM;
+			goto dev_free;
+		}
+
+		INIT_WORK(&ksb->to_mdm_work, ksb_tomdm_work);
+		INIT_WORK(&ksb->start_rx_work, ksb_start_rx_work);
+		init_usb_anchor(&ksb->submitted);
+
+		ksb->dbg_idx = 0;
+		ksb->dbg_lock = __RW_LOCK_UNLOCKED(lck);
+
+		if (!IS_ERR(dbg_dir))
+			debugfs_create_file(ksb->name, S_IRUGO, dbg_dir,
+					ksb, &dbg_fops);
+
+		num_instances++;
+	}
+
+	ret = usb_register(&ksb_usb_driver);
+	if (ret) {
+		pr_err("unable to register ks bridge driver");
+		goto dev_free;
+	}
+
+	pr_info("init done");
+
+	return 0;
+
+dev_free:
+	if (!IS_ERR(dbg_dir))
+		debugfs_remove_recursive(dbg_dir);
+
+	for (i = 0; i < num_instances; i++) {
+		ksb = __ksb[i];
+
+		destroy_workqueue(ksb->wq);
+		kfree(ksb->name);
+		kfree(ksb);
+	}
+
+	return ret;
+
+}
+
+static void __exit ksb_exit(void)
+{
+	struct ks_bridge *ksb;
+	int i;
+
+	if (!IS_ERR(dbg_dir))
+		debugfs_remove_recursive(dbg_dir);
+
+	usb_deregister(&ksb_usb_driver);
+
+	for (i = 0; i < NO_BRIDGE_INSTANCES; i++) {
+		ksb = __ksb[i];
+
+		destroy_workqueue(ksb->wq);
+		kfree(ksb->name);
+		kfree(ksb);
+	}
+}
+
+module_init(ksb_init);
+module_exit(ksb_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 0f045e1..a3bd36a 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -45,6 +45,7 @@
 #include <asm/mach-types.h>
 
 #include <mach/clk.h>
+#include <mach/mpm.h>
 #include <mach/msm_xo.h>
 #include <mach/msm_bus.h>
 #include <mach/rpm-regulator.h>
@@ -848,9 +849,13 @@
 
 	/* Ensure that above operation is completed before turning off clocks */
 	mb();
-	if (!motg->pdata->core_clk_always_on_workaround) {
+	/* Consider clocks on workaround flag only in case of bus suspend */
+	if (!(phy->state == OTG_STATE_B_PERIPHERAL &&
+		test_bit(A_BUS_SUSPEND, &motg->inputs)) ||
+	    !motg->pdata->core_clk_always_on_workaround) {
 		clk_disable_unprepare(motg->pclk);
 		clk_disable_unprepare(motg->core_clk);
+		motg->lpm_flags |= CLOCKS_DOWN;
 	}
 
 	/* usb phy no more require TCXO clock, hence vote for TCXO disable */
@@ -876,13 +881,21 @@
 
 	if (device_may_wakeup(phy->dev)) {
 		enable_irq_wake(motg->irq);
+		if (motg->async_irq)
+			enable_irq_wake(motg->async_irq);
 		if (motg->pdata->pmic_id_irq)
 			enable_irq_wake(motg->pdata->pmic_id_irq);
+		if (pdata->otg_control == OTG_PHY_CONTROL &&
+			pdata->mpm_otgsessvld_int)
+			msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 1);
 	}
 	if (bus)
 		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
 
 	atomic_set(&motg->in_lpm, 1);
+	/* Enable ASYNC IRQ (if present) during LPM */
+	if (motg->async_irq)
+		enable_irq(motg->async_irq);
 	enable_irq(motg->irq);
 	wake_unlock(&motg->wlock);
 
@@ -895,6 +908,7 @@
 {
 	struct usb_phy *phy = &motg->phy;
 	struct usb_bus *bus = phy->otg->host;
+	struct msm_otg_platform_data *pdata = motg->pdata;
 	int cnt = 0;
 	unsigned temp;
 	u32 phy_ctrl_val = 0;
@@ -914,9 +928,10 @@
 		motg->lpm_flags &= ~XO_SHUTDOWN;
 	}
 
-	if (!motg->pdata->core_clk_always_on_workaround) {
+	if (motg->lpm_flags & CLOCKS_DOWN) {
 		clk_prepare_enable(motg->core_clk);
 		clk_prepare_enable(motg->pclk);
+		motg->lpm_flags &= ~CLOCKS_DOWN;
 	}
 
 	if (motg->lpm_flags & PHY_PWR_COLLAPSED) {
@@ -971,8 +986,13 @@
 skip_phy_resume:
 	if (device_may_wakeup(phy->dev)) {
 		disable_irq_wake(motg->irq);
+		if (motg->async_irq)
+			disable_irq_wake(motg->async_irq);
 		if (motg->pdata->pmic_id_irq)
 			disable_irq_wake(motg->pdata->pmic_id_irq);
+		if (pdata->otg_control == OTG_PHY_CONTROL &&
+			pdata->mpm_otgsessvld_int)
+			msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 0);
 	}
 	if (bus)
 		set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
@@ -980,10 +1000,15 @@
 	atomic_set(&motg->in_lpm, 0);
 
 	if (motg->async_int) {
+		/* Match the disable_irq call from ISR */
+		enable_irq(motg->async_int);
 		motg->async_int = 0;
-		enable_irq(motg->irq);
 	}
 
+	/* If ASYNC IRQ is present then keep it enabled only during LPM */
+	if (motg->async_irq)
+		disable_irq(motg->async_irq);
+
 	dev_info(phy->dev, "USB exited from low power mode\n");
 
 	return 0;
@@ -2721,13 +2746,17 @@
 	irqreturn_t ret = IRQ_HANDLED;
 
 	if (atomic_read(&motg->in_lpm)) {
-		pr_debug("OTG IRQ: in LPM\n");
+		pr_debug("OTG IRQ: %d in LPM\n", irq);
 		disable_irq_nosync(irq);
-		motg->async_int = 1;
-		if (atomic_read(&motg->pm_suspended))
+		motg->async_int = irq;
+		if (atomic_read(&motg->pm_suspended)) {
 			motg->sm_work_pending = true;
-		else
+			if ((otg->phy->state == OTG_STATE_A_SUSPEND) ||
+				(otg->phy->state == OTG_STATE_A_WAIT_BCON))
+				set_bit(A_BUS_REQ, &motg->inputs);
+		} else {
 			pm_request_resume(otg->phy->dev);
+		}
 		return IRQ_HANDLED;
 	}
 
@@ -3378,6 +3407,9 @@
 				&pdata->phy_type);
 	of_property_read_u32(node, "qcom,hsusb-otg-pmic-id-irq",
 				&pdata->pmic_id_irq);
+	pdata->disable_reset_on_disconnect = of_property_read_bool(node,
+				"qcom,hsusb-otg-disable-reset");
+
 	return pdata;
 }
 
@@ -3500,6 +3532,12 @@
 		goto free_regs;
 	}
 
+	motg->async_irq = platform_get_irq_byname(pdev, "async_irq");
+	if (motg->async_irq < 0) {
+		dev_dbg(&pdev->dev, "platform_get_irq for async_int failed\n");
+		motg->async_irq = 0;
+	}
+
 	motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
 	if (IS_ERR(motg->xo_handle)) {
 		dev_err(&pdev->dev, "%s not able to get the handle "
@@ -3586,6 +3624,19 @@
 		goto destroy_wlock;
 	}
 
+	if (motg->async_irq) {
+		ret = request_irq(motg->async_irq, msm_otg_irq, IRQF_SHARED,
+							"msm_otg", motg);
+		if (ret) {
+			dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
+			goto free_irq;
+		}
+		disable_irq(motg->async_irq);
+	}
+
+	if (pdata->otg_control == OTG_PHY_CONTROL && pdata->mpm_otgsessvld_int)
+		msm_mpm_enable_pin(pdata->mpm_otgsessvld_int, 1);
+
 	phy->init = msm_otg_reset;
 	phy->set_power = msm_otg_set_power;
 	phy->set_suspend = msm_otg_set_suspend;
@@ -3601,7 +3652,7 @@
 	ret = usb_set_transceiver(&motg->phy);
 	if (ret) {
 		dev_err(&pdev->dev, "usb_set_transceiver failed\n");
-		goto free_irq;
+		goto free_async_irq;
 	}
 
 	if (motg->pdata->mode == USB_OTG &&
@@ -3669,6 +3720,9 @@
 
 remove_phy:
 	usb_set_transceiver(NULL);
+free_async_irq:
+	if (motg->async_irq)
+		free_irq(motg->async_irq, motg);
 free_irq:
 	free_irq(motg->irq, motg);
 destroy_wlock:
@@ -3737,6 +3791,10 @@
 	usb_set_transceiver(NULL);
 	free_irq(motg->irq, motg);
 
+	if (motg->pdata->otg_control == OTG_PHY_CONTROL &&
+		motg->pdata->mpm_otgsessvld_int)
+		msm_mpm_enable_pin(motg->pdata->mpm_otgsessvld_int, 0);
+
 	/*
 	 * Put PHY in low power mode.
 	 */
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 366df67..c3f741b 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -495,6 +495,7 @@
 	/* explicitly set the driver mode to raw */
 	tty->raw = 1;
 	tty->real_raw = 1;
+	tty->update_room_in_ldisc = 1;
 
 	set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
 	dbg("%s", __func__);
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index bc417c1..208c478 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -1452,21 +1452,21 @@
 	len += ret;
 
 	if (len && (format & TOP_AND_BOTTOM))
-		ret = snprintf(buf + len, PAGE_SIZE, ":%s",
+		ret = snprintf(buf + len, PAGE_SIZE - len, ":%s",
 			single_video_3d_format_2string(
 				format & TOP_AND_BOTTOM));
 	else
-		ret = snprintf(buf + len, PAGE_SIZE, "%s",
+		ret = snprintf(buf + len, PAGE_SIZE - len, "%s",
 			single_video_3d_format_2string(
 				format & TOP_AND_BOTTOM));
 	len += ret;
 
 	if (len && (format & SIDE_BY_SIDE_HALF))
-		ret = snprintf(buf + len, PAGE_SIZE, ":%s",
+		ret = snprintf(buf + len, PAGE_SIZE - len, ":%s",
 			single_video_3d_format_2string(
 				format & SIDE_BY_SIDE_HALF));
 	else
-		ret = snprintf(buf + len, PAGE_SIZE, "%s",
+		ret = snprintf(buf + len, PAGE_SIZE - len, "%s",
 			single_video_3d_format_2string(
 				format & SIDE_BY_SIDE_HALF));
 	len += ret;
diff --git a/drivers/video/msm/lcdc.c b/drivers/video/msm/lcdc.c
index 863d59d..2170abe 100644
--- a/drivers/video/msm/lcdc.c
+++ b/drivers/video/msm/lcdc.c
@@ -37,6 +37,7 @@
 
 static int lcdc_off(struct platform_device *pdev);
 static int lcdc_on(struct platform_device *pdev);
+static void cont_splash_clk_ctrl(int enable);
 
 static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
 static int pdev_list_cnt;
@@ -100,6 +101,8 @@
 #endif
 	mfd = platform_get_drvdata(pdev);
 
+	cont_splash_clk_ctrl(0);
+
 	if (lcdc_pdata && lcdc_pdata->lcdc_get_clk)
 		panel_pixclock_freq = lcdc_pdata->lcdc_get_clk();
 
@@ -151,6 +154,20 @@
 	return ret;
 }
 
+static void cont_splash_clk_ctrl(int enable)
+{
+	static int cont_splash_clks_enabled;
+	if (enable && !cont_splash_clks_enabled) {
+		clk_prepare_enable(pixel_mdp_clk);
+		clk_prepare_enable(pixel_lcdc_clk);
+		cont_splash_clks_enabled = 1;
+	} else if (!enable && cont_splash_clks_enabled) {
+		clk_disable_unprepare(pixel_mdp_clk);
+		clk_disable_unprepare(pixel_lcdc_clk);
+		cont_splash_clks_enabled = 0;
+	}
+}
+
 static int lcdc_probe(struct platform_device *pdev)
 {
 	struct msm_fb_data_type *mfd;
@@ -199,6 +216,8 @@
 	if (!mdp_dev)
 		return -ENOMEM;
 
+	cont_splash_clk_ctrl(1);
+
 	/*
 	 * link to the latest pdev
 	 */
diff --git a/drivers/video/msm/lcdc_truly_ips3p2335.c b/drivers/video/msm/lcdc_truly_ips3p2335.c
index a4a370e..b2f4ab8 100644
--- a/drivers/video/msm/lcdc_truly_ips3p2335.c
+++ b/drivers/video/msm/lcdc_truly_ips3p2335.c
@@ -148,6 +148,13 @@
 
 static int lcdc_truly_panel_on(struct platform_device *pdev)
 {
+	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+
+	if (!mfd->cont_splash_done) {
+		mfd->cont_splash_done = 1;
+		return 0;
+	}
+
 	/* Configure reset GPIO that drives DAC */
 	if (lcdc_truly_pdata->panel_config_gpio)
 		lcdc_truly_pdata->panel_config_gpio(1);
diff --git a/drivers/video/msm/lvds.c b/drivers/video/msm/lvds.c
index 2987e2f..13bb9e3 100644
--- a/drivers/video/msm/lvds.c
+++ b/drivers/video/msm/lvds.c
@@ -173,7 +173,7 @@
 			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
 			MDP_OUTP(MDP_BASE +  0xc2020, 0x00090a0b);
 			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
-			MDP_OUTP(MDP_BASE +  0xc2024, 0x151a191a);
+			MDP_OUTP(MDP_BASE +  0xc2024, 0x1518191a);
 			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
 			MDP_OUTP(MDP_BASE +  0xc2028, 0x00121314);
 			/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 2a97a55..09eb05d 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -50,6 +50,7 @@
 static struct clk *mdp_lut_clk;
 int mdp_rev;
 int mdp_iommu_split_domain;
+u32 mdp_max_clk = 200000000;
 
 static struct platform_device *mdp_init_pdev;
 static struct regulator *footswitch;
@@ -68,6 +69,8 @@
 boolean mdp_current_clk_on = FALSE;
 boolean mdp_is_in_isr = FALSE;
 
+struct vsync vsync_cntrl;
+
 /*
  * legacy mdp_in_processing is only for DMA2-MDDI
  * this applies to DMA2 block only
@@ -95,13 +98,13 @@
 static struct delayed_work mdp_pipe_ctrl_worker;
 
 static boolean mdp_suspended = FALSE;
+ulong mdp4_display_intf;
 DEFINE_MUTEX(mdp_suspend_mutex);
 
 #ifdef CONFIG_FB_MSM_MDP40
 struct mdp_dma_data dma2_data;
 struct mdp_dma_data dma_s_data;
 struct mdp_dma_data dma_e_data;
-ulong mdp4_display_intf;
 #else
 static struct mdp_dma_data dma2_data;
 static struct mdp_dma_data dma_s_data;
@@ -1306,8 +1309,56 @@
 }
 #endif
 
-/* Returns < 0 on error, 0 on timeout, or > 0 on successful wait */
+static void send_vsync_work(struct work_struct *work)
+{
+	char buf[64];
+	char *envp[2];
 
+	snprintf(buf, sizeof(buf), "VSYNC=%llu",
+			ktime_to_ns(vsync_cntrl.vsync_time));
+	envp[0] = buf;
+	envp[1] = NULL;
+	kobject_uevent_env(&(vsync_cntrl.dev->kobj), KOBJ_CHANGE, envp);
+}
+
+void mdp3_vsync_irq_enable(int intr, int term)
+{
+	unsigned long flag;
+
+	spin_lock_irqsave(&mdp_spin_lock, flag);
+	outp32(MDP_INTR_CLEAR, intr);
+	mdp_intr_mask |= intr;
+	outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+	mdp_enable_irq(term);
+	spin_unlock_irqrestore(&mdp_spin_lock, flag);
+}
+
+void mdp3_vsync_irq_disable(int intr, int term)
+{
+	unsigned long flag;
+
+	spin_lock_irqsave(&mdp_spin_lock, flag);
+	/* required to synchronize between frame update and vsync
+	 * since both use the same LCDC_FRAME_START interrupt
+	 */
+	if (intr == LCDC_FRAME_START && dma2_data.waiting == FALSE) {
+		mdp_intr_mask &= ~intr;
+		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+	}
+	mdp_disable_irq(term);
+	spin_unlock_irqrestore(&mdp_spin_lock, flag);
+}
+
+#ifdef CONFIG_FB_MSM_MDP303
+/* vsync_isr_handler: Called from isr context*/
+static void vsync_isr_handler(void)
+{
+	vsync_cntrl.vsync_time = ktime_get();
+	schedule_work(&(vsync_cntrl.vsync_work));
+}
+#endif
+
+/* Returns < 0 on error, 0 on timeout, or > 0 on successful wait */
 int mdp_ppp_pipe_wait(void)
 {
 	int ret = 1;
@@ -1468,11 +1519,9 @@
 		outpdw(MDP_BASE + 0x0004, 0);
 	} else if (term == MDP_OVERLAY1_TERM) {
 		mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-		mdp_lut_enable();
 		outpdw(MDP_BASE + 0x0008, 0);
 	} else if (term == MDP_OVERLAY2_TERM) {
 		mdp_pipe_ctrl(MDP_OVERLAY2_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-		mdp_lut_enable();
 		outpdw(MDP_BASE + 0x00D0, 0);
 	}
 #else
@@ -1498,10 +1547,13 @@
 
 #ifdef CONFIG_FB_MSM_NO_MDP_PIPE_CTRL
 
-static void mdp_clk_off(void)
+/*
+ * mdp_clk_disable_unprepare(void) called from thread context
+ */
+static void mdp_clk_disable_unprepare(void)
 {
 	mb();
-	vsync_clk_disable();
+	vsync_clk_disable_unprepare();
 
 	if (mdp_clk != NULL)
 		clk_disable_unprepare(mdp_clk);
@@ -1513,8 +1565,10 @@
 		clk_disable_unprepare(mdp_lut_clk);
 }
 
-
-static void mdp_clk_on(void)
+/*
+ * mdp_clk_prepare_enable(void) called from thread context
+ */
+static void mdp_clk_prepare_enable(void)
 {
 	if (mdp_clk != NULL)
 		clk_prepare_enable(mdp_clk);
@@ -1525,9 +1579,12 @@
 	if (mdp_lut_clk != NULL)
 		clk_prepare_enable(mdp_lut_clk);
 
-	vsync_clk_enable();
+	vsync_clk_prepare_enable();
 }
 
+/*
+ * mdp_clk_ctrl: called from thread context
+ */
 void mdp_clk_ctrl(int on)
 {
 	static int mdp_clk_cnt;
@@ -1535,13 +1592,13 @@
 	mutex_lock(&mdp_suspend_mutex);
 	if (on) {
 		if (mdp_clk_cnt == 0)
-			mdp_clk_on();
+			mdp_clk_prepare_enable();
 		mdp_clk_cnt++;
 	} else {
 		if (mdp_clk_cnt) {
 			mdp_clk_cnt--;
 			if (mdp_clk_cnt == 0)
-				mdp_clk_off();
+				mdp_clk_disable_unprepare();
 		}
 	}
 	mutex_unlock(&mdp_suspend_mutex);
@@ -1767,6 +1824,10 @@
 	if (!mdp_interrupt)
 		goto out;
 
+	/*Primary Vsync interrupt*/
+	if (mdp_interrupt & MDP_PRIM_RDPTR)
+		vsync_isr_handler();
+
 	/* DMA3 TV-Out Start */
 	if (mdp_interrupt & TV_OUT_DMA3_START) {
 		/* let's disable TV out interrupt */
@@ -1814,12 +1875,19 @@
 			dma = &dma2_data;
 			spin_lock_irqsave(&mdp_spin_lock, flag);
 			/* let's disable LCDC interrupt */
-			mdp_intr_mask &= ~LCDC_FRAME_START;
-			outp32(MDP_INTR_ENABLE, mdp_intr_mask);
 			if (dma->waiting) {
 				dma->waiting = FALSE;
 				complete(&dma->comp);
 			}
+
+			if (vsync_cntrl.vsync_irq_enabled)
+				vsync_isr_handler();
+
+			if (!vsync_cntrl.vsync_irq_enabled && !(dma->waiting)) {
+				mdp_intr_mask &= ~LCDC_FRAME_START;
+				outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+			}
+
 			spin_unlock_irqrestore(&mdp_spin_lock, flag);
 		}
 
@@ -1950,7 +2018,7 @@
 	for (i = 0; i < MDP_MAX_BLOCK; i++) {
 		atomic_set(&mdp_block_power_cnt[i], 0);
 	}
-
+	INIT_WORK(&(vsync_cntrl.vsync_work), send_vsync_work);
 #ifdef MSM_FB_ENABLE_DBGFS
 	{
 		struct dentry *root;
@@ -2054,35 +2122,53 @@
 	return ret;
 }
 
+#ifdef CONFIG_FB_MSM_MDP303
+unsigned is_mdp4_hw_reset(void)
+{
+	return 0;
+}
+void mdp4_hw_init(void)
+{
+	/* empty */
+}
+#endif
+
 static int mdp_on(struct platform_device *pdev)
 {
 	int ret = 0;
-#ifdef CONFIG_FB_MSM_MDP40
 	struct msm_fb_data_type *mfd;
-
 	mfd = platform_get_drvdata(pdev);
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	mdp_clk_ctrl(1);
-	mdp4_hw_init();
-	outpdw(MDP_BASE + 0x0038, mdp4_display_intf);
-	if (mfd->panel.type == MIPI_CMD_PANEL) {
-		mdp_vsync_cfg_regs(mfd, FALSE);
-		mdp4_dsi_cmd_on(pdev);
-	} else if (mfd->panel.type == MIPI_VIDEO_PANEL)
-		mdp4_dsi_video_on(pdev);
-	else if (mfd->panel.type == HDMI_PANEL ||
-			mfd->panel.type == LCDC_PANEL ||
-			mfd->panel.type == LVDS_PANEL)
-		mdp4_lcdc_on(pdev);
 
-	mdp_clk_ctrl(0);
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-#endif
+	if (mdp_rev >= MDP_REV_40) {
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		mdp_clk_ctrl(1);
+		mdp4_hw_init();
+		outpdw(MDP_BASE + 0x0038, mdp4_display_intf);
+		if (mfd->panel.type == MIPI_CMD_PANEL) {
+			mdp_vsync_cfg_regs(mfd, FALSE);
+			mdp4_dsi_cmd_on(pdev);
+		} else if (mfd->panel.type == MIPI_VIDEO_PANEL) {
+			mdp4_dsi_video_on(pdev);
+		} else if (mfd->panel.type == HDMI_PANEL ||
+				mfd->panel.type == LCDC_PANEL ||
+				mfd->panel.type == LVDS_PANEL) {
+			mdp4_lcdc_on(pdev);
+		}
+
+		mdp_clk_ctrl(0);
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	}
+
+	if ((mdp_rev == MDP_REV_303) &&
+			(mfd->panel.type == MIPI_CMD_PANEL))
+		vsync_cntrl.dev = mfd->fbi->dev;
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
 	ret = panel_next_on(pdev);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
+
 	mdp_histogram_ctrl_all(TRUE);
 
 	return ret;
@@ -2129,33 +2215,6 @@
 				__func__, mdp_hw_revision);
 }
 
-#ifdef CONFIG_FB_MSM_MDP40
-static void configure_mdp_core_clk_table(uint32 min_clk_rate)
-{
-	uint8 count;
-	uint32 current_rate;
-	if (mdp_clk && mdp_pdata && mdp_pdata->mdp_core_clk_table) {
-		min_clk_rate = clk_round_rate(mdp_clk, min_clk_rate);
-		if (clk_set_rate(mdp_clk, min_clk_rate) < 0)
-			printk(KERN_ERR "%s: clk_set_rate failed\n",
-							 __func__);
-		else {
-			count = 0;
-			current_rate = clk_get_rate(mdp_clk);
-			while (count < mdp_pdata->num_mdp_clk) {
-				if (mdp_pdata->mdp_core_clk_table[count]
-						< current_rate) {
-					mdp_pdata->
-					mdp_core_clk_table[count] =
-							current_rate;
-				}
-				count++;
-			}
-		}
-	}
-}
-#endif
-
 #ifdef CONFIG_MSM_BUS_SCALING
 static uint32_t mdp_bus_scale_handle;
 int mdp_bus_scale_update_request(uint32_t index)
@@ -2174,29 +2233,24 @@
 }
 #endif
 DEFINE_MUTEX(mdp_clk_lock);
-int mdp_set_core_clk(uint16 perf_level)
+int mdp_set_core_clk(u32 rate)
 {
 	int ret = -EINVAL;
-	if (mdp_clk && mdp_pdata
-		 && mdp_pdata->mdp_core_clk_table) {
-		if (perf_level > mdp_pdata->num_mdp_clk)
-			printk(KERN_ERR "%s invalid perf level\n", __func__);
-		else {
-			mutex_lock(&mdp_clk_lock);
-			ret = clk_set_rate(mdp_clk,
-				mdp_pdata->
-				mdp_core_clk_table[mdp_pdata->num_mdp_clk
-						 - perf_level]);
-			mutex_unlock(&mdp_clk_lock);
-			if (ret) {
-				printk(KERN_ERR "%s unable to set mdp_core_clk rate\n",
-					__func__);
-			}
-		}
-	}
+	if (mdp_clk)
+		ret = clk_set_rate(mdp_clk, rate);
+	if (ret)
+		pr_err("%s unable to set mdp clk rate", __func__);
+	else
+		pr_debug("%s mdp clk rate to be set %d: actual rate %ld\n",
+			__func__, rate, clk_get_rate(mdp_clk));
 	return ret;
 }
 
+int mdp_clk_round_rate(u32 rate)
+{
+	return clk_round_rate(mdp_clk, rate);
+}
+
 unsigned long mdp_get_core_clk(void)
 {
 	unsigned long clk_rate = 0;
@@ -2209,25 +2263,6 @@
 	return clk_rate;
 }
 
-unsigned long mdp_perf_level2clk_rate(uint32 perf_level)
-{
-	unsigned long clk_rate = 0;
-
-	if (mdp_pdata && mdp_pdata->mdp_core_clk_table) {
-		if (perf_level > mdp_pdata->num_mdp_clk) {
-			printk(KERN_ERR "%s invalid perf level\n", __func__);
-			clk_rate = mdp_get_core_clk();
-		} else {
-			clk_rate = mdp_pdata->
-				mdp_core_clk_table[mdp_pdata->num_mdp_clk
-					- perf_level];
-		}
-	} else
-		clk_rate = mdp_get_core_clk();
-
-	return clk_rate;
-}
-
 static int mdp_irq_clk_setup(struct platform_device *pdev,
 	char cont_splashScreen)
 {
@@ -2284,21 +2319,25 @@
 	}
 
 #ifdef CONFIG_FB_MSM_MDP40
-	/*
-	 * mdp_clk should greater than mdp_pclk always
-	 */
-	if (mdp_pdata && mdp_pdata->mdp_core_clk_rate) {
-		if (cont_splashScreen)
-			mdp_clk_rate = clk_get_rate(mdp_clk);
-		else
-			mdp_clk_rate = mdp_pdata->mdp_core_clk_rate;
 
-		mutex_lock(&mdp_clk_lock);
-		clk_set_rate(mdp_clk, mdp_clk_rate);
-		if (mdp_lut_clk != NULL)
-			clk_set_rate(mdp_lut_clk, mdp_clk_rate);
-		mutex_unlock(&mdp_clk_lock);
-	}
+	if (mdp_pdata)
+		mdp_max_clk = mdp_pdata->mdp_max_clk;
+	else
+		pr_err("%s cannot get mdp max clk!\n", __func__);
+
+	if (!mdp_max_clk)
+		pr_err("%s mdp max clk is zero!\n", __func__);
+
+	if (cont_splashScreen)
+		mdp_clk_rate = clk_get_rate(mdp_clk);
+	else
+		mdp_clk_rate = mdp_max_clk;
+
+	mutex_lock(&mdp_clk_lock);
+	clk_set_rate(mdp_clk, mdp_clk_rate);
+	if (mdp_lut_clk != NULL)
+		clk_set_rate(mdp_lut_clk, mdp_clk_rate);
+	mutex_unlock(&mdp_clk_lock);
 
 	MSM_FB_DEBUG("mdp_clk: mdp_clk=%d\n", (int)clk_get_rate(mdp_clk));
 #endif
@@ -2395,8 +2434,10 @@
 		if (mdp_pdata->cont_splash_enabled) {
 			mfd->cont_splash_done = 0;
 			if (!contSplash_update_done) {
-				mdp_pipe_ctrl(MDP_CMD_BLOCK,
-					MDP_BLOCK_POWER_ON, FALSE);
+				if (mfd->panel.type == MIPI_VIDEO_PANEL ||
+				    mfd->panel.type == LCDC_PANEL)
+					mdp_pipe_ctrl(MDP_CMD_BLOCK,
+						MDP_BLOCK_POWER_ON, FALSE);
 				contSplash_update_done = 1;
 			}
 		} else
@@ -2417,8 +2458,6 @@
 		mfd->ov1_wb_buf->size = 0;
 		mfd->mem_hid = 0;
 	}
-	mfd->ov0_blt_state  = 0;
-	mfd->use_ov0_blt = 0 ;
 
 	/* initialize Post Processing data*/
 	mdp_hist_lut_init();
@@ -2517,7 +2556,6 @@
 	case MIPI_VIDEO_PANEL:
 #ifndef CONFIG_FB_MSM_MDP303
 		mipi = &mfd->panel_info.mipi;
-		configure_mdp_core_clk_table((mipi->dsi_pclk_rate) * 23 / 20);
 		mdp4_dsi_vsync_init(0);
 		mfd->hw_refresh = TRUE;
 		mfd->dma_fnc = mdp4_dsi_video_overlay;
@@ -2541,11 +2579,13 @@
 		mfd->do_histogram = mdp_do_histogram;
 		mfd->start_histogram = mdp_histogram_start;
 		mfd->stop_histogram = mdp_histogram_stop;
+		mfd->vsync_ctrl = mdp_dma_video_vsync_ctrl;
 		if (mfd->panel_info.pdest == DISPLAY_1)
 			mfd->dma = &dma2_data;
 		else {
 			printk(KERN_ERR "Invalid Selection of destination panel\n");
 			rc = -ENODEV;
+			mdp_clk_ctrl(0);
 			goto mdp_probe_err;
 		}
 
@@ -2560,7 +2600,6 @@
 #ifndef CONFIG_FB_MSM_MDP303
 		mfd->dma_fnc = mdp4_dsi_cmd_overlay;
 		mipi = &mfd->panel_info.mipi;
-		configure_mdp_core_clk_table((mipi->dsi_pclk_rate) * 3 / 2);
 		mdp4_dsi_rdptr_init(0);
 		if (mfd->panel_info.pdest == DISPLAY_1) {
 			if_no = PRIMARY_INTF_SEL;
@@ -2587,11 +2626,13 @@
 		mfd->do_histogram = mdp_do_histogram;
 		mfd->start_histogram = mdp_histogram_start;
 		mfd->stop_histogram = mdp_histogram_stop;
+		mfd->vsync_ctrl = mdp_dma_vsync_ctrl;
 		if (mfd->panel_info.pdest == DISPLAY_1)
 			mfd->dma = &dma2_data;
 		else {
 			printk(KERN_ERR "Invalid Selection of destination panel\n");
 			rc = -ENODEV;
+			mdp_clk_ctrl(0);
 			goto mdp_probe_err;
 		}
 		INIT_WORK(&mfd->dma_update_worker,
@@ -2643,8 +2684,6 @@
 
 #ifdef CONFIG_FB_MSM_MDP40
 		mdp4_lcdc_vsync_init(0);
-		configure_mdp_core_clk_table((mfd->panel_info.clk_rate)
-								* 23 / 20);
 		if (mfd->panel.type == HDMI_PANEL) {
 			mfd->dma = &dma_e_data;
 			mdp4_display_intf_sel(EXTERNAL_INTF_SEL, LCDC_RGB_INTF);
@@ -2654,6 +2693,7 @@
 		}
 #else
 		mfd->dma = &dma2_data;
+		mfd->vsync_ctrl = mdp_dma_lcdc_vsync_ctrl;
 		spin_lock_irqsave(&mdp_spin_lock, flag);
 		mdp_intr_mask &= ~MDP_DMA_P_DONE;
 		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
@@ -2690,6 +2730,7 @@
 				pr_err("%s: writeback panel not supprted\n",
 					 __func__);
 				platform_device_put(msm_fb_dev);
+				mdp_clk_ctrl(0);
 				return -ENODEV;
 			}
 			pdata->on = mdp4_overlay_writeback_on;
@@ -2706,11 +2747,12 @@
 		mdp_clk_ctrl(0);
 		goto mdp_probe_err;
 	}
-#ifdef CONFIG_FB_MSM_MDP40
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	mdp4_display_intf = inpdw(MDP_BASE + 0x0038);
-	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-#endif
+
+	if (mdp_rev >= MDP_REV_40) {
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		mdp4_display_intf = inpdw(MDP_BASE + 0x0038);
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	}
 
 	mdp_clk_ctrl(0);
 
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index b92b956..8920b4d 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -44,9 +44,10 @@
 extern int mdp_rev;
 extern int mdp_iommu_split_domain;
 extern struct mdp_csc_cfg mdp_csc_convert[4];
-
 extern struct workqueue_struct *mdp_hist_wq;
 
+extern uint32 mdp_intr_mask;
+
 #define MDP4_REVISION_V1		0
 #define MDP4_REVISION_V2		1
 #define MDP4_REVISION_V2_1	2
@@ -90,6 +91,15 @@
 extern unsigned char hdmi_prim_display;
 extern unsigned char hdmi_prim_resolution;
 
+struct vsync {
+	ktime_t vsync_time;
+	struct device *dev;
+	struct work_struct vsync_work;
+	int vsync_irq_enabled;
+};
+
+extern struct vsync vsync_cntrl;
+
 /*
  * MDP Image Structure
  */
@@ -287,6 +297,7 @@
 #define MDP_HISTOGRAM_TERM_DMA_S 0x20000
 #define MDP_HISTOGRAM_TERM_VG_1 0x40000
 #define MDP_HISTOGRAM_TERM_VG_2 0x80000
+#define MDP_VSYNC_TERM 0x1000
 
 #define ACTIVE_START_X_EN BIT(31)
 #define ACTIVE_START_Y_EN BIT(31)
@@ -306,6 +317,7 @@
 #define MDP_PPP_DONE 				BIT(0)
 #define TV_OUT_DMA3_DONE    BIT(6)
 #define TV_ENC_UNDERRUN     BIT(7)
+#define MDP_PRIM_RDPTR      BIT(8)
 #define TV_OUT_DMA3_START   BIT(13)
 #define MDP_HIST_DONE       BIT(20)
 
@@ -800,7 +812,9 @@
 void mdp_disable_irq_nosync(uint32 term);
 int mdp_get_bytes_per_pixel(uint32_t format,
 				 struct msm_fb_data_type *mfd);
-int mdp_set_core_clk(uint16 perf_level);
+int mdp_set_core_clk(u32 rate);
+int mdp_clk_round_rate(u32 rate);
+
 unsigned long mdp_get_core_clk(void);
 unsigned long mdp_perf_level2clk_rate(uint32 perf_level);
 
@@ -812,10 +826,15 @@
 	return 0;
 }
 #endif
+void mdp_dma_vsync_ctrl(int enable);
+void mdp_dma_video_vsync_ctrl(int enable);
+void mdp_dma_lcdc_vsync_ctrl(int enable);
+void mdp3_vsync_irq_enable(int intr, int term);
+void mdp3_vsync_irq_disable(int intr, int term);
 
 #ifdef MDP_HW_VSYNC
-void vsync_clk_enable(void);
-void vsync_clk_disable(void);
+void vsync_clk_prepare_enable(void);
+void vsync_clk_disable_unprepare(void);
 void mdp_hw_vsync_clk_enable(struct msm_fb_data_type *mfd);
 void mdp_hw_vsync_clk_disable(struct msm_fb_data_type *mfd);
 void mdp_vsync_clk_disable(void);
@@ -862,6 +881,11 @@
 {
 	/* empty */
 }
+static inline int msmfb_overlay_vsync_ctrl(struct fb_info *info,
+						void __user *argp)
+{
+	return 0;
+}
 #endif
 
 int mdp_ppp_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req);
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 72e7c8f..cc4eae51 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -27,6 +27,7 @@
 extern uint32 mdp4_extn_disp;
 extern char *mmss_cc_base;	/* mutimedia sub system clock control */
 extern spinlock_t dsi_clk_lock;
+extern u32 mdp_max_clk;
 
 #define MDP4_OVERLAYPROC0_BASE	0x10000
 #define MDP4_OVERLAYPROC1_BASE	0x18000
@@ -361,6 +362,8 @@
 	uint32 blt_ov_done;
 	uint32 blt_dmap_koff;
 	uint32 blt_dmap_done;
+	uint32 req_clk;
+	uint32 req_bw;
 	uint32 luma_align_size;
 	struct mdp_overlay_pp_params pp_cfg;
 	struct mdp_overlay req_data;
@@ -610,9 +613,6 @@
 void mdp4_lcdc_wait4vsync(int cndx, long long *vtime);
 void mdp4_overlay_lcdc_vsync_push(struct msm_fb_data_type *mfd,
 				struct mdp4_overlay_pipe *pipe);
-void mdp4_overlay_dtv_set_perf(struct msm_fb_data_type *mfd);
-void mdp4_update_perf_level(u32 perf_level);
-void mdp4_set_perf_level(void);
 void mdp4_mddi_overlay_dmas_restore(void);
 
 #ifndef CONFIG_FB_MSM_MIPI_DSI
@@ -665,24 +665,17 @@
 uint32 mdp4_rgb_igc_lut_cvt(uint32 ndx);
 void mdp4_vg_qseed_init(int);
 int mdp4_overlay_blt(struct fb_info *info, struct msmfb_overlay_blt *req);
-int mdp4_overlay_blt_offset(struct fb_info *info,
-					struct msmfb_overlay_blt *req);
-
 
 #ifdef CONFIG_FB_MSM_MIPI_DSI
-int mdp4_dsi_overlay_blt_start(struct msm_fb_data_type *mfd);
-int mdp4_dsi_overlay_blt_stop(struct msm_fb_data_type *mfd);
+void mdp4_dsi_cmd_blt_start(struct msm_fb_data_type *mfd);
+void mdp4_dsi_cmd_blt_stop(struct msm_fb_data_type *mfd);
 void mdp4_dsi_video_blt_start(struct msm_fb_data_type *mfd);
 void mdp4_dsi_video_blt_stop(struct msm_fb_data_type *mfd);
-void mdp4_dsi_overlay_blt(struct msm_fb_data_type *mfd,
-					struct msmfb_overlay_blt *req);
-int mdp4_dsi_overlay_blt_offset(struct msm_fb_data_type *mfd,
+void mdp4_dsi_cmd_overlay_blt(struct msm_fb_data_type *mfd,
 					struct msmfb_overlay_blt *req);
 
 void mdp4_dsi_video_overlay_blt(struct msm_fb_data_type *mfd,
 					struct msmfb_overlay_blt *req);
-int mdp4_dsi_video_overlay_blt_offset(struct msm_fb_data_type *mfd,
-					struct msmfb_overlay_blt *req);
 void mdp4_dsi_video_base_swap(int cndx, struct mdp4_overlay_pipe *pipe);
 
 #ifdef CONFIG_FB_MSM_MDP40
@@ -726,16 +719,21 @@
 	struct msm_fb_data_type *mfd, struct msmfb_overlay_blt *req)
 {
 }
-static inline int mdp4_dsi_video_overlay_blt_offset(
+static inline void mdp4_dsi_cmd_overlay_blt(
 	struct msm_fb_data_type *mfd, struct msmfb_overlay_blt *req)
 {
-	return -ENODEV;
 }
 static inline void mdp4_dsi_video_base_swap(int cndx,
 			struct mdp4_overlay_pipe *pipe)
 {
 	/* empty */
 }
+static inline void mdp4_dsi_cmd_blt_start(struct msm_fb_data_type *mfd)
+{
+}
+static inline void mdp4_dsi_cmd_blt_stop(struct msm_fb_data_type *mfd)
+{
+}
 #endif  /* CONFIG_FB_MSM_MIPI_DSI */
 
 void mdp4_lcdc_overlay_blt(struct msm_fb_data_type *mfd,
@@ -882,9 +880,6 @@
 int mdp4_overlay_writeback_on(struct platform_device *pdev);
 int mdp4_overlay_writeback_off(struct platform_device *pdev);
 void mdp4_writeback_overlay(struct msm_fb_data_type *mfd);
-void mdp4_writeback_kickoff_video(struct msm_fb_data_type *mfd,
-		struct mdp4_overlay_pipe *pipe);
-void mdp4_writeback_dma_busy_wait(struct msm_fb_data_type *mfd);
 void mdp4_overlay1_done_writeback(struct mdp_dma_data *dma);
 
 int mdp4_writeback_start(struct fb_info *info);
@@ -925,5 +920,26 @@
 int mdp4_v4l2_overlay_play(struct fb_info *info, struct mdp4_overlay_pipe *pipe,
 	unsigned long srcp0_addr, unsigned long srcp1_addr,
 	unsigned long srcp2_addr);
+int mdp4_overlay_mdp_pipe_req(struct mdp4_overlay_pipe *pipe,
+				struct msm_fb_data_type *mfd);
+int mdp4_overlay_mdp_perf_req(struct msm_fb_data_type *mfd,
+				struct mdp4_overlay_pipe *plist);
+void mdp4_overlay_mdp_perf_upd(struct msm_fb_data_type *mfd, int flag);
+
+#ifndef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+static inline void mdp4_writeback_dma_busy_wait(struct msm_fb_data_type *mfd)
+{
+	/* empty */
+}
+static inline void mdp4_writeback_kickoff_video(struct msm_fb_data_type *mfd,
+		struct mdp4_overlay_pipe *pipe)
+{
+	/* empty */
+}
+#else
+void mdp4_writeback_dma_busy_wait(struct msm_fb_data_type *mfd);
+void mdp4_writeback_kickoff_video(struct msm_fb_data_type *mfd,
+		struct mdp4_overlay_pipe *pipe);
+#endif
 
 #endif /* MDP_H */
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 6e51b23..90d8219 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -104,7 +104,21 @@
 
 static DEFINE_MUTEX(iommu_mutex);
 static struct mdp4_overlay_ctrl *ctrl = &mdp4_overlay_db;
-static int new_perf_level;
+
+struct mdp4_overlay_perf {
+	u32 mdp_clk_rate;
+	u32 use_ov0_blt;
+	u32 use_ov1_blt;
+	u32 mdp_bw;
+};
+
+struct mdp4_overlay_perf perf_request = {
+	.mdp_bw = OVERLAY_PERF_LEVEL4,
+};
+struct mdp4_overlay_perf perf_current = {
+	.mdp_bw = OVERLAY_PERF_LEVEL4,
+};
+
 static struct ion_client *display_iclient;
 
 
@@ -154,7 +168,6 @@
 		pr_err("%s: Error, mixer=%d iommu fndx=%d\n",
 				__func__, mixer, flist->fndx);
 		mdp4_stat.iommu_drop++;
-		mutex_unlock(&iommu_mutex);
 		return;
 	}
 
@@ -221,10 +234,17 @@
 	}
 
 	mutex_lock(&iommu_mutex);
-	mdp4_stat.iommu_map++;
 	iom = &pipe->iommu;
+	if (iom->prev_ihdl[plane]) {
+		mdp4_overlay_iommu_2freelist(pipe->mixer_num,
+						iom->prev_ihdl[plane]);
+		mdp4_stat.iommu_drop++;
+		pr_err("%s: dropped, ndx=%d plane=%d\n", __func__,
+						pipe->pipe_ndx, plane);
+	}
 	iom->prev_ihdl[plane] = iom->ihdl[plane];
 	iom->ihdl[plane] = *srcp_ihdl;
+	mdp4_stat.iommu_map++;
 
 	pr_debug("%s: ndx=%d plane=%d prev=0x%p cur=0x%p start=0x%lx len=%lx\n",
 		 __func__, pipe->pipe_ndx, plane, iom->prev_ihdl[plane],
@@ -468,14 +488,18 @@
 		dma2_cfg_reg |= DMA_PACK_PATTERN_RGB;
 
 
-	if (mfd->panel_info.bpp == 18) {
+	if ((mfd->panel_info.type == MIPI_CMD_PANEL) ||
+		(mfd->panel_info.type == MIPI_VIDEO_PANEL)) {
+		dma2_cfg_reg |= DMA_DSTC0G_8BITS |	/* 888 24BPP */
+		    DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS;
+	} else if (mfd->panel_info.bpp == 18) {
 		dma2_cfg_reg |= DMA_DSTC0G_6BITS |	/* 666 18BPP */
 		    DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS;
 	} else if (mfd->panel_info.bpp == 16) {
 		dma2_cfg_reg |= DMA_DSTC0G_6BITS |	/* 565 16BPP */
 		    DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS;
 	} else {
-		dma2_cfg_reg |= DMA_DSTC0G_8BITS |	/* 888 16BPP */
+		dma2_cfg_reg |= DMA_DSTC0G_8BITS |	/* 888 24BPP */
 		    DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS;
 	}
 
@@ -1655,6 +1679,12 @@
 
 	bspipe = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE];
 
+	/*
+	 * bspipe is clone here
+	 * get real pipe
+	 */
+	bspipe = mdp4_overlay_ndx2pipe(bspipe->pipe_ndx);
+
 	/* save original base layer */
 	ctrl->baselayer[mixer] = bspipe;
 
@@ -1818,7 +1848,13 @@
 		op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN);
 		outpdw(base + 0x0058, op_mode);
 		outpdw(base + 0x1008, 0);	/* black */
+		/*
+		 * Set src size and dst size same to avoid underruns
+		 */
+		outpdw(base + 0x0000, inpdw(base + 0x0008));
 	} else {
+		u32 src_size = ((pipe->src_h << 16) | pipe->src_w);
+		outpdw(base + 0x0000, src_size);
 		format &= ~MDP4_FORMAT_SOLID_FILL;
 		blend->solidfill_pipe = NULL;
 	}
@@ -2071,7 +2107,7 @@
 void mdp4_overlay_pipe_free(struct mdp4_overlay_pipe *pipe)
 {
 	uint32 ptype, num, ndx, mixer;
-	struct mdp4_iommu_pipe_info *iom_pipe_info;
+	struct mdp4_iommu_pipe_info iom;
 
 	pr_debug("%s: pipe=%x ndx=%d\n", __func__, (int)pipe, pipe->pipe_ndx);
 
@@ -2079,90 +2115,18 @@
 	num = pipe->pipe_num;
 	ndx = pipe->pipe_ndx;
 	mixer = pipe->mixer_num;
-	iom_pipe_info = &mdp_iommu[pipe->mixer_num][pipe->pipe_ndx - 1];
-	iom_pipe_info->mark_unmap = 1;
 
 	mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0);
 
-	memset(pipe, 0, sizeof(*pipe));
+	iom = pipe->iommu;
 
+	memset(pipe, 0, sizeof(*pipe));
 	pipe->pipe_type = ptype;
 	pipe->pipe_num = num;
 	pipe->pipe_ndx = ndx;
 	pipe->mixer_num = mixer;
-}
+	pipe->iommu = iom;
 
-static int mdp4_overlay_validate_downscale(struct mdp_overlay *req,
-	struct msm_fb_data_type *mfd, uint32 perf_level, uint32 pclk_rate)
-{
-	__u32 panel_clk_khz, mdp_clk_khz;
-	__u32 num_hsync_pix_clks, mdp_clks_per_hsync, src_wh;
-	__u32 hsync_period_ps, mdp_period_ps, total_hsync_period_ps;
-	unsigned long fill_rate_y_dir, fill_rate_x_dir;
-	unsigned long fillratex100, mdp_pixels_produced;
-	unsigned long mdp_clk_hz;
-
-	pr_debug("%s: LCDC Mode Downscale validation with MDP Core"
-		" Clk rate\n", __func__);
-	pr_debug("src_w %u, src_h %u, dst_w %u, dst_h %u\n",
-		req->src_rect.w, req->src_rect.h, req->dst_rect.w,
-		req->dst_rect.h);
-
-
-	panel_clk_khz = pclk_rate/1000;
-	mdp_clk_hz = mdp_perf_level2clk_rate(perf_level);
-
-	if (!mdp_clk_hz || !req->dst_rect.w || !req->dst_rect.h) {
-		pr_debug("mdp_perf_level2clk_rate returned 0,"
-			 "or dst_rect height/width is 0,"
-			 "Downscale Validation incomplete\n");
-		return 0;
-	}
-
-	mdp_clk_khz = mdp_clk_hz/1000;
-
-	num_hsync_pix_clks = mfd->panel_info.lcdc.h_back_porch +
-		mfd->panel_info.lcdc.h_front_porch +
-		mfd->panel_info.lcdc.h_pulse_width +
-		mfd->panel_info.xres;
-
-	hsync_period_ps = 1000000000/panel_clk_khz;
-	mdp_period_ps = 1000000000/mdp_clk_khz;
-
-	total_hsync_period_ps = num_hsync_pix_clks * hsync_period_ps;
-	mdp_clks_per_hsync = total_hsync_period_ps/mdp_period_ps;
-
-	pr_debug("hsync_period_ps %u, mdp_period_ps %u,"
-		"total_hsync_period_ps %u\n", hsync_period_ps,
-		mdp_period_ps, total_hsync_period_ps);
-
-	src_wh = req->src_rect.w * req->src_rect.h;
-	if (src_wh % req->dst_rect.h)
-		fill_rate_y_dir = (src_wh / req->dst_rect.h) + 1;
-	else
-		fill_rate_y_dir = (src_wh / req->dst_rect.h);
-
-	fill_rate_x_dir = (mfd->panel_info.xres - req->dst_rect.w)
-		+ req->src_rect.w;
-
-	if (fill_rate_y_dir >= fill_rate_x_dir)
-		fillratex100 = 100 * fill_rate_y_dir / mfd->panel_info.xres;
-	else
-		fillratex100 = 100 * fill_rate_x_dir / mfd->panel_info.xres;
-
-	pr_debug("mdp_clks_per_hsync %u, fill_rate_y_dir %lu,"
-		"fill_rate_x_dir %lu\n", mdp_clks_per_hsync,
-		fill_rate_y_dir, fill_rate_x_dir);
-
-	mdp_pixels_produced = 100 * mdp_clks_per_hsync/fillratex100;
-	pr_debug("fillratex100 %lu, mdp_pixels_produced %lu\n",
-		fillratex100, mdp_pixels_produced);
-	if (mdp_pixels_produced <= mfd->panel_info.xres) {
-		mdp4_stat.err_underflow++;
-		return -ERANGE;
-	}
-
-	return 0;
 }
 
 static int mdp4_overlay_req2pipe(struct mdp_overlay *req, int mixer,
@@ -2170,7 +2134,6 @@
 			struct msm_fb_data_type *mfd)
 {
 	struct mdp4_overlay_pipe *pipe;
-	struct mdp4_iommu_pipe_info *iom_pipe_info;
 	int ret, ptype;
 
 	u32 upscale_max;
@@ -2350,8 +2313,6 @@
 			display_iclient);
 	}
 
-	iom_pipe_info = &mdp_iommu[pipe->mixer_num][pipe->pipe_ndx - 1];
-
 	pipe->src_format = req->src.format;
 	ret = mdp4_overlay_format2pipe(pipe);
 
@@ -2409,11 +2370,451 @@
 
 	pipe->transp = req->transp_mask;
 
+	pipe->flags = req->flags;
+
 	*ppipe = pipe;
 
 	return 0;
 }
 
+static int mdp4_calc_pipe_mdp_clk(struct msm_fb_data_type *mfd,
+				  struct mdp4_overlay_pipe *pipe)
+{
+	u32 pclk;
+	u32 xscale, yscale;
+	u32 hsync = 0;
+	u32 shift = 16;
+	u64 rst;
+	int ret = -EINVAL;
+
+	if (!pipe) {
+		pr_err("%s: pipe is null!\n", __func__);
+		pipe->req_bw = OVERLAY_PERF_LEVEL4;
+		return ret;
+	}
+	if (!mfd) {
+		pr_err("%s: mfd is null!\n", __func__);
+		pipe->req_bw = OVERLAY_PERF_LEVEL4;
+		return ret;
+	}
+
+	/*
+	 * Serveral special cases require the max mdp clk but cannot
+	 * be explained by mdp clk equation.
+	 */
+	if (pipe->flags & MDP_DEINTERLACE) {
+		pr_info("%s deinterlace requires max mdp clk.\n",
+			__func__);
+		pipe->req_clk = mdp_max_clk;
+		return 0;
+	}
+
+	pr_debug("%s: pipe sets: panel res(x,y)=(%d,%d)\n",
+		 __func__,  mfd->panel_info.xres, mfd->panel_info.yres);
+	pr_debug("%s: src(w,h)(%d,%d),src(x,y)(%d,%d)\n",
+		 __func__,  pipe->src_w, pipe->src_h, pipe->src_x, pipe->src_y);
+	pr_debug("%s: dst(w,h)(%d,%d),dst(x,y)(%d,%d)\n",
+		 __func__, pipe->dst_w, pipe->dst_h, pipe->dst_x, pipe->dst_y);
+
+	pclk = (mfd->panel_info.type == MIPI_VIDEO_PANEL ||
+		mfd->panel_info.type == MIPI_CMD_PANEL) ?
+		mfd->panel_info.mipi.dsi_pclk_rate :
+		mfd->panel_info.clk_rate;
+	if (!pclk) {
+		pipe->req_clk = mdp_max_clk;
+		pr_err("%s panel pixel clk is zero!\n", __func__);
+		return ret;
+	}
+	pr_debug("%s: mdp panel pixel clk is %d.\n",
+		 __func__, pclk);
+
+	if (!pipe->dst_h) {
+		pr_err("%s: pipe dst_h is zero!\n", __func__);
+		pipe->req_clk = mdp_max_clk;
+		return ret;
+	}
+
+	if (!pipe->src_h) {
+		pr_err("%s: pipe src_h is zero!\n", __func__);
+		pipe->req_clk = mdp_max_clk;
+		return ret;
+	}
+
+	if (!pipe->dst_w) {
+		pr_err("%s: pipe dst_w is zero!\n", __func__);
+		pipe->req_clk = mdp_max_clk;
+		return ret;
+	}
+
+	if (!pipe->dst_h) {
+		pr_err("%s: pipe dst_h is zero!\n", __func__);
+		pipe->req_clk = mdp_max_clk;
+		return ret;
+	}
+
+	/*
+	 * For the scaling cases, make more margin by removing porch
+	 * values and adding extra 20%.
+	 */
+	if ((pipe->src_h != pipe->dst_h) ||
+	    (pipe->src_w != pipe->dst_w)) {
+		hsync = mfd->panel_info.xres;
+		hsync *= 100;
+		hsync /= 120;
+		pr_debug("%s: panel hsync is %d. with scaling\n",
+			__func__, hsync);
+
+	} else {
+		hsync = mfd->panel_info.lcdc.h_back_porch +
+			mfd->panel_info.lcdc.h_front_porch +
+			mfd->panel_info.lcdc.h_pulse_width +
+			mfd->panel_info.xres;
+		pr_debug("%s: panel hsync is %d.\n",
+			__func__, hsync);
+	}
+
+	if (!hsync) {
+		pipe->req_clk = mdp_max_clk;
+		pr_err("%s: panel hsync is zero!\n", __func__);
+		return 0;
+	}
+
+	xscale = mfd->panel_info.xres;
+	xscale += pipe->src_w;
+
+	if (xscale < pipe->dst_w) {
+		pipe->req_clk = mdp_max_clk;
+		pr_err("%s: xres+src_w cannot be less than dst_w!\n",
+		       __func__);
+		return ret;
+	}
+
+	xscale -= pipe->dst_w;
+	xscale <<= shift;
+	xscale /= hsync;
+	pr_debug("%s: the right %d shifted xscale is %d.\n",
+		 __func__, shift, xscale);
+
+	if (pipe->src_h > pipe->dst_h) {
+		yscale = pipe->src_h;
+		yscale <<= shift;
+		yscale /= pipe->dst_h;
+	} else {		/* upscale */
+		yscale = pipe->dst_h;
+		yscale <<= shift;
+		yscale /= pipe->src_h;
+	}
+
+	yscale *= pipe->src_w;
+	yscale /= hsync;
+
+	pr_debug("%s: the right %d shifted yscale is %d.\n",
+		 __func__, shift, yscale);
+
+	rst = pclk;
+	if (yscale > xscale)
+		rst *= yscale;
+	else
+		rst *= xscale;
+
+	rst >>= shift;
+
+	/*
+	 * If the calculated mdp clk is less than panel pixel clk,
+	 * most likely due to upscaling, mdp clk rate will be set to
+	 * greater than pclk. Now the driver uses 1.15 as the
+	 * factor. Ideally this factor is passed from board file.
+	 */
+	if (rst < pclk) {
+		rst = ((pclk >> shift) * 23 / 20) << shift;
+		pr_debug("%s calculated mdp clk is less than pclk.\n",
+			__func__);
+	}
+
+	pipe->req_clk = (u32) rst;
+
+	pr_debug("%s: required mdp clk %d mixer %d pipe ndx %d\n",
+		 __func__, pipe->req_clk, pipe->mixer_num, pipe->pipe_ndx);
+
+	return 0;
+}
+
+#define OVERLAY_VGA_SIZE	0x04B000
+#define OVERLAY_720P_TILE_SIZE  0x0E6000
+#define OVERLAY_WSVGA_SIZE 0x98000 /* 1024x608, align 600 to 32bit */
+
+#define OVERLAY_BUS_SCALE_TABLE_BASE	6
+
+
+static int mdp4_calc_pipe_mdp_bw(struct msm_fb_data_type *mfd,
+			  struct mdp4_overlay_pipe *pipe)
+{
+	u32 res;
+	int ret = -EINVAL;
+
+	if (!pipe) {
+		pr_err("%s: pipe is null!\n", __func__);
+		return ret;
+	}
+	if (!mfd) {
+		pr_err("%s: mfd is null!\n", __func__);
+		return ret;
+	}
+
+	if (pipe->flags & MDP_DEINTERLACE) {
+		pr_info("%s deinterlace requires max mdp bw.\n",
+			__func__);
+		pipe->req_bw = OVERLAY_PERF_LEVEL1;
+		return 0;
+	}
+
+	if (pipe->pipe_type == OVERLAY_TYPE_BF) {
+		pipe->req_bw = OVERLAY_PERF_LEVEL4;
+		return 0;
+	}
+
+	res = pipe->src_w * pipe->src_h;
+
+	if (res <= OVERLAY_WSVGA_SIZE)
+		pipe->req_bw = OVERLAY_PERF_LEVEL4;
+	else if (res <= OVERLAY_VGA_SIZE)
+		pipe->req_bw = OVERLAY_PERF_LEVEL3;
+	else if (res <= OVERLAY_720P_TILE_SIZE)
+		pipe->req_bw = OVERLAY_PERF_LEVEL2;
+	else
+		pipe->req_bw = OVERLAY_PERF_LEVEL1;
+
+	return 0;
+}
+
+int mdp4_overlay_mdp_perf_req(struct msm_fb_data_type *mfd,
+			      struct mdp4_overlay_pipe *plist)
+{
+	u32 worst_mdp_clk = 0;
+	u32 worst_mdp_bw = OVERLAY_PERF_LEVEL4;
+	int i;
+	struct mdp4_overlay_perf *perf_req = &perf_request;
+	struct mdp4_overlay_pipe *pipe = plist;
+	u32 cnt = 0;
+	int ret = -EINVAL;
+
+	if (!mfd) {
+		pr_err("%s: mfd is null!\n", __func__);
+		return ret;
+	}
+
+	if (!plist) {
+		pr_err("%s: plist is null!\n", __func__);
+		return ret;
+	}
+
+	perf_req->use_ov0_blt = 0;
+	perf_req->use_ov1_blt = 0;
+
+	for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
+
+		if (!pipe)
+			return ret;
+
+		if (!pipe->pipe_used)
+			continue;
+		cnt++;
+		if (worst_mdp_clk < pipe->req_clk)
+			worst_mdp_clk = pipe->req_clk;
+		if (pipe->req_clk > mdp_max_clk) {
+			if (pipe->mixer_num == MDP4_MIXER0)
+				perf_req->use_ov0_blt = 1;
+			if (pipe->mixer_num == MDP4_MIXER1)
+				perf_req->use_ov1_blt = 1;
+		}
+
+		if (!pipe->req_bw) {
+			pr_err("%s mdp pipe bw request should not be zero!\n",
+			       __func__);
+			pr_debug("%s %d pid %d num %d idx %d mix %d bw %d\n",
+				 __func__, __LINE__, current->pid,
+				 pipe->pipe_num, pipe->pipe_ndx,
+				 pipe->mixer_num, pipe->req_bw);
+			pipe->req_bw = OVERLAY_PERF_LEVEL4;
+		}
+
+		if (pipe->req_bw < worst_mdp_bw)
+			worst_mdp_bw = pipe->req_bw;
+
+		if (mfd->mdp_rev == MDP_REV_41) {
+			/*
+			 * writeback (blt) mode to provide work around
+			 * for dsi cmd mode interface hardware bug.
+			 */
+			if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
+				if (pipe->dst_x != 0)
+					perf_req->use_ov0_blt = 1;
+			}
+			if ((mfd->panel_info.xres > 1280) &&
+			    (mfd->panel_info.type != DTV_PANEL)) {
+				perf_req->use_ov0_blt = 1;
+			}
+		}
+	}
+
+	perf_req->mdp_clk_rate = worst_mdp_clk;
+	if (perf_req->mdp_clk_rate > mdp_max_clk)
+		perf_req->mdp_clk_rate = mdp_max_clk;
+
+	perf_req->mdp_clk_rate = mdp_clk_round_rate(perf_req->mdp_clk_rate);
+
+	perf_req->mdp_bw = worst_mdp_bw;
+
+	if (cnt >= 3)
+		perf_req->mdp_bw = OVERLAY_PERF_LEVEL1;
+
+	pr_debug("%s %d pid %d cnt %d clk %d ov0_blt %d, ov1_blt %d bw %d\n",
+		 __func__, __LINE__, current->pid, cnt,
+		 perf_req->mdp_clk_rate,
+		 perf_req->use_ov0_blt,
+		 perf_req->use_ov1_blt,
+		 perf_req->mdp_bw);
+
+	return 0;
+}
+
+int mdp4_overlay_mdp_pipe_req(struct mdp4_overlay_pipe *pipe,
+				  struct msm_fb_data_type *mfd)
+{
+	int ret = 0;
+
+	if (mdp4_calc_pipe_mdp_clk(mfd, pipe)) {
+		pr_err("%s unable to calc mdp pipe clk rate ret=%d\n",
+		       __func__, ret);
+		ret = -EINVAL;
+	}
+	if (mdp4_calc_pipe_mdp_bw(mfd, pipe)) {
+		pr_err("%s unable to calc mdp pipe bandwidth ret=%d\n",
+		       __func__, ret);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+void mdp4_overlay_mdp_perf_upd(struct msm_fb_data_type *mfd,
+				  int flag)
+{
+	struct mdp4_overlay_perf *perf_req = &perf_request;
+	struct mdp4_overlay_perf *perf_cur = &perf_current;
+
+	pr_debug("%s %d: req mdp clk %d, cur mdp clk %d flag %d\n",
+		 __func__, __LINE__,
+		 perf_req->mdp_clk_rate,
+		 perf_cur->mdp_clk_rate,
+		 flag);
+
+	if (!mdp4_extn_disp)
+		perf_cur->use_ov1_blt = 0;
+
+	if (flag) {
+		if (perf_req->mdp_clk_rate > perf_cur->mdp_clk_rate) {
+			mdp_set_core_clk(perf_req->mdp_clk_rate);
+			pr_info("%s mdp clk is changed [%d] from %d to %d\n",
+				__func__,
+				flag,
+				perf_cur->mdp_clk_rate,
+				perf_req->mdp_clk_rate);
+			perf_cur->mdp_clk_rate =
+				perf_req->mdp_clk_rate;
+		}
+		if (perf_req->mdp_bw < perf_cur->mdp_bw) {
+			mdp_bus_scale_update_request
+				(OVERLAY_BUS_SCALE_TABLE_BASE -
+				 perf_req->mdp_bw);
+			pr_info("%s mdp bw is changed [%d] from %d to %d\n",
+				__func__,
+				flag,
+				perf_cur->mdp_bw,
+				perf_req->mdp_bw);
+			perf_cur->mdp_bw = perf_req->mdp_bw;
+		}
+		if (mfd->panel_info.pdest == DISPLAY_1 &&
+		    perf_req->use_ov0_blt && !perf_cur->use_ov0_blt) {
+			mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
+			if (mfd->panel_info.type == LCDC_PANEL ||
+			    mfd->panel_info.type == LVDS_PANEL)
+				mdp4_lcdc_overlay_blt_start(mfd);
+			else if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
+				mdp4_dsi_video_blt_start(mfd);
+			else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
+				mdp4_dsi_cmd_blt_start(mfd);
+			pr_info("%s mixer0 start blt [%d] from %d to %d.\n",
+				__func__,
+				flag,
+				perf_cur->use_ov0_blt,
+				perf_req->use_ov0_blt);
+			perf_cur->use_ov0_blt = perf_req->use_ov0_blt;
+		}
+		if (mfd->panel_info.pdest == DISPLAY_2 &&
+		    perf_req->use_ov1_blt && !perf_cur->use_ov1_blt) {
+			mdp4_allocate_writeback_buf(mfd, MDP4_MIXER1);
+			mdp4_dtv_overlay_blt_start(mfd);
+			pr_info("%s mixer1 start blt [%d] from %d to %d.\n",
+				__func__,
+				flag,
+				perf_cur->use_ov1_blt,
+				perf_req->use_ov1_blt);
+			perf_cur->use_ov1_blt = perf_req->use_ov1_blt;
+		}
+	} else {
+		if (perf_req->mdp_clk_rate < perf_cur->mdp_clk_rate) {
+			pr_info("%s mdp clk is changed [%d] from %d to %d\n",
+				__func__,
+				flag,
+				perf_cur->mdp_clk_rate,
+				perf_req->mdp_clk_rate);
+			mdp_set_core_clk(perf_req->mdp_clk_rate);
+			perf_cur->mdp_clk_rate =
+				perf_req->mdp_clk_rate;
+		}
+		if (perf_req->mdp_bw > perf_cur->mdp_bw) {
+			pr_info("%s mdp bw is changed [%d] from %d to %d\n",
+				__func__,
+				flag,
+				perf_cur->mdp_bw,
+				perf_req->mdp_bw);
+			mdp_bus_scale_update_request
+				(OVERLAY_BUS_SCALE_TABLE_BASE -
+				 perf_req->mdp_bw);
+			perf_cur->mdp_bw = perf_req->mdp_bw;
+		}
+		if (mfd->panel_info.pdest == DISPLAY_1 &&
+		    !perf_req->use_ov0_blt && perf_cur->use_ov0_blt) {
+			if (mfd->panel_info.type == LCDC_PANEL ||
+			    mfd->panel_info.type == LVDS_PANEL)
+				mdp4_lcdc_overlay_blt_stop(mfd);
+			else if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
+				mdp4_dsi_video_blt_stop(mfd);
+			else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
+				mdp4_dsi_cmd_blt_stop(mfd);
+			mdp4_free_writeback_buf(mfd, MDP4_MIXER0);
+			pr_info("%s mixer0 stop blt [%d] from %d to %d.\n",
+				__func__,
+				flag,
+				perf_cur->use_ov0_blt,
+				perf_req->use_ov0_blt);
+			perf_cur->use_ov0_blt = perf_req->use_ov0_blt;
+		}
+		if (mfd->panel_info.pdest == DISPLAY_2 &&
+		    !perf_req->use_ov1_blt && perf_cur->use_ov1_blt) {
+			mdp4_dtv_overlay_blt_stop(mfd);
+			mdp4_free_writeback_buf(mfd, MDP4_MIXER1);
+			pr_info("%s mixer1 stop blt [%d] from %d to %d.\n",
+				__func__,
+				flag,
+				perf_cur->use_ov1_blt,
+				perf_req->use_ov1_blt);
+			perf_cur->use_ov1_blt = perf_req->use_ov1_blt;
+		}
+	}
+	return;
+}
+
 static int get_img(struct msmfb_data *img, struct fb_info *info,
 	struct mdp4_overlay_pipe *pipe, unsigned int plane,
 	unsigned long *start, unsigned long *len, struct file **srcp_file,
@@ -2443,6 +2844,8 @@
 				DISPLAY_SUBSYSTEM_ID)) {
 				ret = -1;
 			} else {
+				pr_warn("%s: mdp4_overlay play with FB memory\n",
+							 __func__);
 				*srcp_file = file;
 				*p_need = put_needed;
 			}
@@ -2505,7 +2908,7 @@
 		return -EINTR;
 
 	if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
-		mdp4_dsi_overlay_blt(mfd, req);
+		mdp4_dsi_cmd_overlay_blt(mfd, req);
 	else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO)
 		mdp4_dsi_video_overlay_blt(mfd, req);
 	else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
@@ -2534,197 +2937,10 @@
 	return 0;
 }
 
-#define OVERLAY_VGA_SIZE	0x04B000
-#define OVERLAY_720P_TILE_SIZE  0x0E6000
-#define OVERLAY_WSVGA_SIZE 0x98000 /* 1024x608, align 600 to 32bit */
-
-#define OVERLAY_BUS_SCALE_TABLE_BASE	6
-
-static int mdp4_overlay_is_rgb_type(int format)
-{
-	switch (format) {
-	case MDP_RGB_565:
-	case MDP_RGB_888:
-	case MDP_BGR_565:
-	case MDP_XRGB_8888:
-	case MDP_ARGB_8888:
-	case MDP_RGBA_8888:
-	case MDP_BGRA_8888:
-	case MDP_RGBX_8888:
-		return 1;
-	default:
-		return 0;
-	}
-}
-
-static uint32 mdp4_overlay_get_perf_level(struct mdp_overlay *req,
-					  struct msm_fb_data_type *mfd)
-{
-	int is_fg = 0, i, cnt;
-
-	if (req->is_fg && ((req->alpha & 0x0ff) == 0xff))
-		is_fg = 1;
-
-	if (mdp4_extn_disp)
-		return OVERLAY_PERF_LEVEL1;
-
-	if (req->flags & (MDP_DEINTERLACE | MDP_BACKEND_COMPOSITION))
-		return OVERLAY_PERF_LEVEL1;
-
-	for (i = 0, cnt = 0; i < OVERLAY_PIPE_MAX; i++) {
-		if (ctrl->plist[i].pipe_used && ++cnt > 2)
-			return OVERLAY_PERF_LEVEL1;
-	}
-
-	if (mdp4_overlay_is_rgb_type(req->src.format) && is_fg &&
-		((req->src.width * req->src.height) <= OVERLAY_WSVGA_SIZE))
-		return OVERLAY_PERF_LEVEL4;
-	else if (mdp4_overlay_is_rgb_type(req->src.format))
-		return OVERLAY_PERF_LEVEL1;
-
-	if (req->src.width*req->src.height <= OVERLAY_VGA_SIZE) {
-		if (mfd->mdp_rev >= MDP_REV_42)
-			return OVERLAY_PERF_LEVEL4;
-		else
-			return OVERLAY_PERF_LEVEL3;
-
-	} else if (req->src.width*req->src.height <= OVERLAY_720P_TILE_SIZE) {
-		u32 max, min;
-		max = (req->dst_rect.h > req->dst_rect.w) ?
-			req->dst_rect.h : req->dst_rect.w;
-		min = (mfd->panel_info.yres > mfd->panel_info.xres) ?
-			mfd->panel_info.xres : mfd->panel_info.yres;
-		if (max > min)	/* landscape mode */
-			return OVERLAY_PERF_LEVEL3;
-		else		/* potrait mode */
-			return OVERLAY_PERF_LEVEL2;
-	}
-	else
-		return OVERLAY_PERF_LEVEL1;
-}
-
-void mdp4_update_perf_level(u32 perf_level)
-{
-	static int first = 1;
-
-	new_perf_level = perf_level;
-
-	if (first) {
-		first = 0;
-		mdp4_set_perf_level();
-	}
-}
-
-void mdp4_set_perf_level(void)
-{
-	static int old_perf_level;
-	int cur_perf_level;
-
-	if (mdp4_extn_disp)
-		cur_perf_level = OVERLAY_PERF_LEVEL1;
-	else
-		cur_perf_level = new_perf_level;
-
-	if (old_perf_level != cur_perf_level) {
-		mdp_set_core_clk(cur_perf_level);
-		old_perf_level = cur_perf_level;
-		mdp_bus_scale_update_request(OVERLAY_BUS_SCALE_TABLE_BASE
-					     - cur_perf_level);
-	}
-}
-
-static void mdp4_overlay_update_blt_mode(struct msm_fb_data_type *mfd)
-{
-	if (mfd->use_ov0_blt == mfd->ov0_blt_state)
-		return;
-
-	if (mfd->use_ov0_blt) {
-		if (mfd->panel_info.type == LCDC_PANEL ||
-		    mfd->panel_info.type == LVDS_PANEL)
-			mdp4_lcdc_overlay_blt_start(mfd);
-		else if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
-			mdp4_dsi_video_blt_start(mfd);
-		else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
-			mdp4_dsi_overlay_blt_start(mfd);
-		else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
-			mdp4_mddi_overlay_blt_start(mfd);
-	} else {
-		if (mfd->panel_info.type == LCDC_PANEL ||
-		    mfd->panel_info.type == LVDS_PANEL)
-			mdp4_lcdc_overlay_blt_stop(mfd);
-		else if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
-			mdp4_dsi_video_blt_stop(mfd);
-		else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
-			mdp4_dsi_overlay_blt_stop(mfd);
-		else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
-			mdp4_mddi_overlay_blt_stop(mfd);
-	}
-	mfd->ov0_blt_state = mfd->use_ov0_blt;
-}
-
-static void mdp4_overlay1_update_blt_mode(struct msm_fb_data_type *mfd)
-{
-	if (mfd->ov1_blt_state == mfd->use_ov1_blt)
-		return;
-	if (mfd->use_ov1_blt) {
-		mdp4_dtv_overlay_blt_start(mfd);
-		pr_debug("%s overlay1 writeback is enabled\n", __func__);
-	} else {
-		mdp4_dtv_overlay_blt_stop(mfd);
-		pr_debug("%s overlay1 writeback is disabled\n", __func__);
-	}
-	mfd->ov1_blt_state = mfd->use_ov1_blt;
-}
-
-static u32 mdp4_overlay_blt_enable(struct mdp_overlay *req,
-	struct msm_fb_data_type *mfd, uint32 perf_level)
-{
-	u32 clk_rate = mfd->panel_info.clk_rate;
-	u32 blt_chq_req  = 0, use_blt = 0;
-
-	if ((mfd->panel_info.type == MIPI_VIDEO_PANEL) ||
-		 (mfd->panel_info.type == MIPI_CMD_PANEL))
-		clk_rate = (&mfd->panel_info.mipi)->dsi_pclk_rate;
-
-	if ((mfd->panel_info.type == LCDC_PANEL) ||
-	    (mfd->panel_info.type == MIPI_VIDEO_PANEL) ||
-	    (mfd->panel_info.type == DTV_PANEL) ||
-	    (mfd->panel_info.type == MIPI_CMD_PANEL))
-		blt_chq_req = 1;
-
-	if (blt_chq_req && (req->src_rect.h > req->dst_rect.h ||
-		req->src_rect.w > req->dst_rect.w)) {
-		if (mdp4_overlay_validate_downscale(req, mfd, perf_level,
-			clk_rate))
-			use_blt = 1;
-	}
-
-	if (mfd->panel_info.type == MDDI_PANEL) {
-		if ((req->src_rect.h/2) >= req->dst_rect.h ||
-			(req->src_rect.w/2) >= req->dst_rect.w)
-				use_blt = 1;
-	}
-
-	if (mfd->mdp_rev == MDP_REV_41) {
-		/*
-		* writeback (blt) mode to provide work around for
-		* dsi cmd mode interface hardware bug.
-		*/
-		if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
-			if (req->dst_rect.x != 0)
-				use_blt = 1;
-		}
-		if ((mfd->panel_info.xres > 1280) &&
-		    (mfd->panel_info.type != DTV_PANEL))
-			use_blt = 1;
-	}
-	return use_blt;
-}
-
 int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
-	int ret, mixer, perf_level;
+	int ret, mixer;
 	struct mdp4_overlay_pipe *pipe;
 
 	if (mfd == NULL) {
@@ -2754,20 +2970,10 @@
 		return ret;
 	}
 
-	perf_level = mdp4_overlay_get_perf_level(req, mfd);
-
-	if (mixer == MDP4_MIXER0) {
-		u32 use_blt = mdp4_overlay_blt_enable(req, mfd,	perf_level);
-		mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1));
-		mfd->use_ov0_blt |= (use_blt << (pipe->pipe_ndx-1));
-	}
-
 	/* return id back to user */
 	req->id = pipe->pipe_ndx;	/* pipe_ndx start from 1 */
 	pipe->req_data = *req;		/* keep original req */
 
-	pipe->flags = req->flags;
-
 	if (!IS_ERR_OR_NULL(mfd->iclient)) {
 		pr_debug("pipe->flags 0x%x\n", pipe->flags);
 		if (pipe->flags & MDP_SECURE_OVERLAY_SESSION) {
@@ -2790,47 +2996,8 @@
 								__func__);
 	}
 
-	if (ctrl->panel_mode & MDP4_PANEL_DTV &&
-	    pipe->mixer_num == MDP4_MIXER1) {
-		u32 use_blt = mdp4_overlay_blt_enable(req, mfd, perf_level);
+	mdp4_overlay_mdp_pipe_req(pipe, mfd);
 
-		if (hdmi_prim_display) {
-			if (!mdp4_overlay_is_rgb_type(req->src.format) &&
-				pipe->pipe_type == OVERLAY_TYPE_VIDEO &&
-				(req->src_rect.h > req->dst_rect.h ||
-				req->src_rect.w > req->dst_rect.w))
-				use_blt = 1;
-		}
-
-		mdp4_overlay_dtv_set(mfd, pipe);
-		mfd->use_ov1_blt &= ~(1 << (pipe->pipe_ndx-1));
-		mfd->use_ov1_blt |= (use_blt << (pipe->pipe_ndx-1));
-	}
-
-	if (new_perf_level != perf_level) {
-		u32 old_level = new_perf_level;
-		mdp4_update_perf_level(perf_level);
-
-		/* change clck base on perf level */
-		if (pipe->mixer_num == MDP4_MIXER0) {
-			if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
-				if (old_level > perf_level)
-					mdp4_set_perf_level();
-			} else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
-				mdp4_set_perf_level();
-			} else if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
-				if (old_level > perf_level)
-					mdp4_set_perf_level();
-			} else if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
-				mdp4_mddi_dma_busy_wait(mfd);
-				mdp4_mddi_blt_dmap_busy_wait(mfd);
-				mdp4_set_perf_level();
-			}
-		} else {
-			if (ctrl->panel_mode & MDP4_PANEL_DTV)
-				mdp4_overlay_dtv_set_perf(mfd);
-		}
-	}
 	mutex_unlock(&mfd->dma->ov_mutex);
 
 	return 0;
@@ -2886,7 +3053,6 @@
 	else {
 		/* mixer 0 */
 		ctrl->mixer0_played = 0;
-
 		if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
 			if (mfd->panel_power_on)
 				mdp4_mddi_blt_dmap_busy_wait(mfd);
@@ -2901,15 +3067,9 @@
 			if (mfd->panel_power_on)
 				mdp4_mddi_overlay_restore();
 		}
-
-		mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1));
-		mdp4_overlay_update_blt_mode(mfd);
 	} else {	/* mixer1, DTV, ATV */
-		if (ctrl->panel_mode & MDP4_PANEL_DTV) {
+		if (ctrl->panel_mode & MDP4_PANEL_DTV)
 			mdp4_overlay_dtv_unset(mfd, pipe);
-			mfd->use_ov1_blt &= ~(1 << (pipe->pipe_ndx-1));
-			mdp4_overlay1_update_blt_mode(mfd);
-		}
 	}
 
 	mdp4_stat.overlay_unset[pipe->mixer_num]++;
@@ -2923,30 +3083,38 @@
 
 int mdp4_overlay_wait4vsync(struct fb_info *info, long long *vtime)
 {
-	if (info->node == 0) {
+	if (!hdmi_prim_display && info->node == 0) {
 		if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO)
 			mdp4_dsi_video_wait4vsync(0, vtime);
 		else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
 			mdp4_dsi_cmd_wait4vsync(0, vtime);
 		else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
 			mdp4_lcdc_wait4vsync(0, vtime);
-	} else if (info->node == 1)
+	} else if (hdmi_prim_display || info->node == 1) {
 		mdp4_dtv_wait4vsync(0, vtime);
+	}
 
 	return 0;
 }
 
 int mdp4_overlay_vsync_ctrl(struct fb_info *info, int enable)
 {
-	if (info->node == 0) {
+	int cmd;
+
+	if (enable)
+		cmd = 1;
+	else
+		cmd = 0;
+
+	if (!hdmi_prim_display && info->node == 0) {
 		if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO)
-			mdp4_dsi_video_vsync_ctrl(0, enable);
+			mdp4_dsi_video_vsync_ctrl(0, cmd);
 		else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
-			mdp4_dsi_cmd_vsync_ctrl(0, enable);
+			mdp4_dsi_cmd_vsync_ctrl(0, cmd);
 		else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
-			mdp4_lcdc_vsync_ctrl(0, enable);
-	} else if (info->node == 1)
-		mdp4_dtv_vsync_ctrl(0, enable);
+			mdp4_lcdc_vsync_ctrl(0, cmd);
+	} else if (hdmi_prim_display || info->node == 1)
+		mdp4_dtv_vsync_ctrl(0, cmd);
 
 	return 0;
 }
@@ -3018,7 +3186,6 @@
 
 	pr_debug("%s: pipe=%x ndx=%d num=%d used=%d\n", __func__,
 		(int) pipe, pipe->pipe_ndx, pipe->pipe_num, pipe->pipe_used);
-
 	mdp4_overlay_reg_flush(pipe, 1);
 	mdp4_mixer_stage_up(pipe);
 }
@@ -3052,10 +3219,12 @@
 
 	if (pipe->pipe_type == OVERLAY_TYPE_BF) {
 		mdp4_overlay_borderfill_stage_up(pipe);
+		mdp4_mixer_stage_commit(pipe->mixer_num);
 		return 0;
 	}
 
-	if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+	if (pipe->mixer_num == MDP4_MIXER2 ||
+					ctrl->panel_mode & MDP4_PANEL_MDDI)
 		mutex_lock(&mfd->dma->ov_mutex);
 
 	img = &req->data;
@@ -3163,13 +3332,10 @@
 		}
 	}
 
-	if (mfd->use_ov0_blt)
-		mdp4_overlay_update_blt_mode(mfd);
+	mdp4_overlay_mdp_perf_req(mfd, ctrl->plist);
 
-	if (mfd->use_ov1_blt)
-		mdp4_overlay1_update_blt_mode(mfd);
-
-	if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+	if (pipe->mixer_num == MDP4_MIXER2 ||
+				ctrl->panel_mode & MDP4_PANEL_MDDI)
 		goto mddi;
 
 	if (pipe->mixer_num == MDP4_MIXER0) {
@@ -3192,32 +3358,27 @@
 	return ret;
 
 mddi:
-
 	if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) {
 		mdp4_overlay_vg_setup(pipe);    /* video/graphic pipe */
 	} else {
 		mdp4_overlay_rgb_setup(pipe);	/* rgb pipe */
 	}
 
-	if (pipe->mixer_num != MDP4_MIXER2) {
-		if ((ctrl->panel_mode & MDP4_PANEL_DTV) ||
-			(ctrl->panel_mode & MDP4_PANEL_LCDC) ||
-			(ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO))
-			mdp4_overlay_reg_flush(pipe, 1);
-	}
-
 	mdp4_mixer_stage_up(pipe);
-	if (!(pipe->flags & MDP_OV_PLAY_NOWAIT))
+
+	if (pipe->mixer_num == MDP4_MIXER2) {
+		ctrl->mixer2_played++;
+		if (ctrl->panel_mode & MDP4_PANEL_WRITEBACK) {
+			mdp4_writeback_dma_busy_wait(mfd);
+			mdp4_writeback_kickoff_video(mfd, pipe);
+		}
+	} else if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
+		if (pipe->flags & MDP_OV_PLAY_NOWAIT) {
+			mdp4_stat.overlay_play[pipe->mixer_num]++;
+			mutex_unlock(&mfd->dma->ov_mutex);
+			goto end;
+		}
 		mdp4_mixer_stage_commit(pipe->mixer_num);
-
-
-	if (pipe->flags & MDP_OV_PLAY_NOWAIT) {
-		mdp4_stat.overlay_play[pipe->mixer_num]++;
-		mutex_unlock(&mfd->dma->ov_mutex);
-		goto end;
-	}
-
-	if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
 		mdp4_mddi_dma_busy_wait(mfd);
 		mdp4_mddi_kickoff_video(mfd, pipe);
 	}
@@ -3424,7 +3585,7 @@
 		mdp4_overlay_reg_flush(pipe, 1);
 
 	mdp4_mixer_stage_up(pipe);
-
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 #ifdef V4L2_VSYNC
 	/*
 	 * TODO: incorporate v4l2 into vsycn driven mechanism
diff --git a/drivers/video/msm/mdp4_overlay_atv.c b/drivers/video/msm/mdp4_overlay_atv.c
index 753ff23..c133831 100644
--- a/drivers/video/msm/mdp4_overlay_atv.c
+++ b/drivers/video/msm/mdp4_overlay_atv.c
@@ -110,14 +110,13 @@
 
 	mdp4_overlay_dmae_xy(pipe);	/* dma_e */
 	mdp4_overlay_dmae_cfg(mfd, 1);
-
 	mdp4_overlay_rgb_setup(pipe);
 
 	mdp4_overlayproc_cfg(pipe);
 
 	mdp4_overlay_reg_flush(pipe, 1);
 	mdp4_mixer_stage_up(pipe);
-
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 	if (ret == 0)
 		mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 
@@ -183,10 +182,12 @@
 	} else {
 		pipe->srcp0_addr = (uint32)(buf + buf_offset);
 	}
+	mdp4_overlay_mdp_perf_req(pipe, mfd);
+	mdp4_overlay_mdp_perf_upd(mfd, 1);
 	mdp4_overlay_rgb_setup(pipe);
 	mdp4_overlay_reg_flush(pipe, 0);
 	mdp4_mixer_stage_up(pipe);
-
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 	printk(KERN_INFO "mdp4_atv_overlay: pipe=%x ndx=%d\n",
 					(int)pipe, pipe->pipe_ndx);
 
@@ -201,10 +202,7 @@
 	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 	wait_for_completion_killable(&atv_pipe->comp);
 	mdp_disable_irq(MDP_OVERLAY1_TERM);
-
-	/* change mdp clk while mdp is idle` */
-	mdp4_set_perf_level();
-
+	mdp4_overlay_mdp_perf_upd(mfd, 0);
 	mdp4_stat.kickoff_atv++;
 	mutex_unlock(&mfd->dma->ov_mutex);
 }
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index 7998d8b..36a6b2a 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -39,7 +39,7 @@
 static int vsync_start_y_adjust = 4;
 
 #define MAX_CONTROLLER	1
-#define VSYNC_EXPIRE_TICK 2
+#define VSYNC_EXPIRE_TICK 4
 #define BACKLIGHT_MAX 4
 
 struct backlight {
@@ -54,24 +54,34 @@
 	int inited;
 	int update_ndx;
 	int expire_tick;
-	uint32 dmap_intr_tot;
+	int blt_wait;
+	u32 ov_koff;
+	u32 ov_done;
+	u32 dmap_koff;
+	u32 dmap_done;
 	uint32 rdptr_intr_tot;
 	uint32 rdptr_sirq_tot;
 	atomic_t suspend;
-	int dmap_wait_cnt;
 	int wait_vsync_cnt;
-	int commit_cnt;
+	int blt_change;
+	int blt_free;
+	int blt_end;
+	int fake_vsync;
 	struct mutex update_lock;
+	struct completion ov_comp;
 	struct completion dmap_comp;
 	struct completion vsync_comp;
-	spinlock_t dmap_spin_lock;
 	spinlock_t spin_lock;
+	struct msm_fb_data_type *mfd;
 	struct mdp4_overlay_pipe *base_pipe;
 	struct vsync_update vlist[2];
 	struct backlight blight;
-	int vsync_irq_enabled;
+	int vsync_enabled;
+	int clk_enabled;
+	int clk_control;
 	ktime_t vsync_time;
 	struct work_struct vsync_work;
+	struct work_struct clk_work;
 } vsync_ctrl_db[MAX_CONTROLLER];
 
 static void vsync_irq_enable(int intr, int term)
@@ -80,7 +90,6 @@
 
 	spin_lock_irqsave(&mdp_spin_lock, flag);
 	/* no need to clrear other interrupts for comamnd mode */
-	outp32(MDP_INTR_CLEAR, INTR_PRIMARY_RDPTR);
 	mdp_intr_mask |= intr;
 	outp32(MDP_INTR_ENABLE, mdp_intr_mask);
 	mdp_enable_irq(term);
@@ -161,30 +170,7 @@
 	return cnt;
 }
 
-void mdp4_blt_dmap_cfg(struct mdp4_overlay_pipe *pipe)
-{
-	uint32 off, addr;
-	int bpp;
-
-	if (pipe->ov_blt_addr == 0)
-		return;
-
-#ifdef BLT_RGB565
-	bpp = 2; /* overlay ouput is RGB565 */
-#else
-	bpp = 3; /* overlay ouput is RGB888 */
-#endif
-	off = 0;
-	if (pipe->blt_dmap_done & 0x01)
-		off = pipe->src_height * pipe->src_width * bpp;
-	addr = pipe->dma_blt_addr + off;
-
-	/* dmap */
-	MDP_OUTP(MDP_BASE + 0x90008, addr);
-}
-
-
-void mdp4_blt_overlay0_cfg(struct mdp4_overlay_pipe *pipe)
+static void mdp4_dsi_cmd_blt_ov_update(struct mdp4_overlay_pipe *pipe)
 {
 	uint32 off, addr;
 	int bpp;
@@ -199,7 +185,7 @@
 	bpp = 3; /* overlay ouput is RGB888 */
 #endif
 	off = 0;
-	if (pipe->blt_ov_done & 0x01)
+	if (pipe->ov_cnt & 0x01)
 		off = pipe->src_height * pipe->src_width * bpp;
 	addr = pipe->ov_blt_addr + off;
 	/* overlay 0 */
@@ -208,32 +194,91 @@
 	outpdw(overlay_base + 0x001c, addr);
 }
 
-static void vsync_commit_kickoff_dmap(struct mdp4_overlay_pipe *pipe)
+static void mdp4_dsi_cmd_blt_dmap_update(struct mdp4_overlay_pipe *pipe)
 {
-	if (mipi_dsi_ctrl_lock(1)) {
-		mdp4_stat.kickoff_dmap++;
-		pipe->blt_dmap_koff++;
-		vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
-		outpdw(MDP_BASE + 0x000c, 0); /* kickoff dmap engine */
-		mb();
-	}
+	uint32 off, addr;
+	int bpp;
+
+	if (pipe->ov_blt_addr == 0)
+		return;
+
+#ifdef BLT_RGB565
+	bpp = 2; /* overlay ouput is RGB565 */
+#else
+	bpp = 3; /* overlay ouput is RGB888 */
+#endif
+	off = 0;
+	if (pipe->dmap_cnt & 0x01)
+		off = pipe->src_height * pipe->src_width * bpp;
+	addr = pipe->dma_blt_addr + off;
+
+	/* dmap */
+	MDP_OUTP(MDP_BASE + 0x90008, addr);
 }
 
-static void vsync_commit_kickoff_ov0(struct mdp4_overlay_pipe *pipe, int blt)
+static void mdp4_dsi_cmd_wait4dmap(int cndx);
+static void mdp4_dsi_cmd_wait4ov(int cndx);
+
+static void mdp4_dsi_cmd_do_blt(struct msm_fb_data_type *mfd, int enable)
 {
-	int locked = 1;
+	unsigned long flags;
+	int cndx = 0;
+	struct vsycn_ctrl *vctrl;
+	struct mdp4_overlay_pipe *pipe;
+	int need_wait;
 
-	if (blt)
-		vsync_irq_enable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);
-	else
-		locked = mipi_dsi_ctrl_lock(1);
+	vctrl = &vsync_ctrl_db[cndx];
+	pipe = vctrl->base_pipe;
 
-	if (locked) {
-		mdp4_stat.kickoff_ov0++;
-		pipe->blt_ov_koff++;
-		outpdw(MDP_BASE + 0x0004, 0); /* kickoff overlay engine */
-		mb();
+	mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
+
+	if (mfd->ov0_wb_buf->write_addr == 0) {
+		pr_err("%s: no blt_base assigned\n", __func__);
+		return;
 	}
+
+	spin_lock_irqsave(&vctrl->spin_lock, flags);
+	if (enable && pipe->ov_blt_addr == 0) {
+		vctrl->blt_change++;
+		if (vctrl->dmap_koff != vctrl->dmap_done) {
+			INIT_COMPLETION(vctrl->dmap_comp);
+			need_wait = 1;
+		}
+	} else if (enable == 0 && pipe->ov_blt_addr) {
+		vctrl->blt_change++;
+		if (vctrl->ov_koff != vctrl->dmap_done) {
+			INIT_COMPLETION(vctrl->dmap_comp);
+			need_wait = 1;
+		}
+	}
+	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
+	if (need_wait)
+		mdp4_dsi_cmd_wait4dmap(0);
+
+	spin_lock_irqsave(&vctrl->spin_lock, flags);
+	if (enable && pipe->ov_blt_addr == 0) {
+		pipe->ov_blt_addr = mfd->ov0_wb_buf->write_addr;
+		pipe->dma_blt_addr = mfd->ov0_wb_buf->read_addr;
+		pipe->ov_cnt = 0;
+		pipe->dmap_cnt = 0;
+		vctrl->ov_koff = vctrl->dmap_koff;
+		vctrl->ov_done = vctrl->dmap_done;
+		vctrl->blt_free = 0;
+		vctrl->blt_wait = 0;
+		vctrl->blt_end = 0;
+		mdp4_stat.blt_dsi_video++;
+	} else if (enable == 0 && pipe->ov_blt_addr) {
+		pipe->ov_blt_addr = 0;
+		pipe->dma_blt_addr =  0;
+		vctrl->blt_end = 1;
+		vctrl->blt_free = 4;	/* 4 commits to free wb buf */
+	}
+
+	pr_debug("%s: changed=%d enable=%d ov_blt_addr=%x\n", __func__,
+		vctrl->blt_change, enable, (int)pipe->ov_blt_addr);
+
+	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
 }
 
 /*
@@ -266,95 +311,137 @@
 	pr_debug("%s: vndx=%d pipe_ndx=%d expire=%x pid=%d\n", __func__,
 		undx, pipe->pipe_ndx, vctrl->expire_tick, current->pid);
 
-	*pp = *pipe;	/* keep it */
+	*pp = *pipe;	/* clone it */
 	vp->update_cnt++;
 
-	if (vctrl->expire_tick == 0) {
-		mipi_dsi_clk_cfg(1);
-		mdp_clk_ctrl(1);
-		vsync_irq_enable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
-	}
-	vctrl->expire_tick = VSYNC_EXPIRE_TICK;
 	mutex_unlock(&vctrl->update_lock);
+	mdp4_stat.overlay_play[pipe->mixer_num]++;
 }
 
+static void mdp4_dsi_cmd_blt_ov_update(struct mdp4_overlay_pipe *pipe);
+
 int mdp4_dsi_cmd_pipe_commit(void)
 {
-
-	int  i, undx, cnt;
+	int  i, undx;
 	int mixer = 0;
 	struct vsycn_ctrl *vctrl;
 	struct vsync_update *vp;
 	struct mdp4_overlay_pipe *pipe;
 	unsigned long flags;
-	int diff;
+	int need_dmap_wait = 0;
+	int need_ov_wait = 0;
+	int cnt = 0;
 
 	vctrl = &vsync_ctrl_db[0];
+
 	mutex_lock(&vctrl->update_lock);
 	undx =  vctrl->update_ndx;
 	vp = &vctrl->vlist[undx];
 	pipe = vctrl->base_pipe;
 	mixer = pipe->mixer_num;
 
-	pr_debug("%s: vndx=%d cnt=%d expire=%x pid=%d\n", __func__,
-		undx, vp->update_cnt, vctrl->expire_tick, current->pid);
-
-	cnt = 0;
 	if (vp->update_cnt == 0) {
 		mutex_unlock(&vctrl->update_lock);
 		return cnt;
 	}
+
 	vctrl->update_ndx++;
 	vctrl->update_ndx &= 0x01;
-	vctrl->commit_cnt++;
-	vp->update_cnt = 0;	/* reset */
+	vp->update_cnt = 0;     /* reset */
+	if (vctrl->blt_free) {
+		vctrl->blt_free--;
+		if (vctrl->blt_free == 0)
+			mdp4_free_writeback_buf(vctrl->mfd, mixer);
+	}
 	mutex_unlock(&vctrl->update_lock);
 
+
 	mdp4_backlight_commit_level(vctrl);
 
 	/* free previous committed iommu back to pool */
 	mdp4_overlay_iommu_unmap_freelist(mixer);
 
+	spin_lock_irqsave(&vctrl->spin_lock, flags);
+	if (pipe->ov_blt_addr) {
+		/* Blt */
+		if (vctrl->blt_wait)
+			need_dmap_wait = 1;
+		else if (vctrl->ov_koff != vctrl->ov_done) {
+			INIT_COMPLETION(vctrl->ov_comp);
+			need_ov_wait = 1;
+		}
+	} else {
+		/* direct out */
+		if (vctrl->dmap_koff != vctrl->dmap_done) {
+			INIT_COMPLETION(vctrl->dmap_comp);
+			pr_debug("%s: wait, ok=%d od=%d dk=%d dd=%d cpu=%d\n",
+			 __func__, vctrl->ov_koff, vctrl->ov_done,
+			vctrl->dmap_koff, vctrl->dmap_done, smp_processor_id());
+			need_dmap_wait = 1;
+		}
+	}
+	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
+	if (need_dmap_wait) {
+		pr_debug("%s: wait4dmap\n", __func__);
+		mdp4_dsi_cmd_wait4dmap(0);
+	}
+
+	if (need_ov_wait) {
+		pr_debug("%s: wait4ov\n", __func__);
+		mdp4_dsi_cmd_wait4ov(0);
+	}
+
+	if (pipe->ov_blt_addr) {
+		if (vctrl->blt_end) {
+			vctrl->blt_end = 0;
+			pipe->ov_blt_addr = 0;
+			pipe->dma_blt_addr =  0;
+		}
+	}
+
+	if (vctrl->blt_change) {
+		mdp4_overlayproc_cfg(pipe);
+		mdp4_overlay_dmap_xy(pipe);
+		vctrl->blt_change = 0;
+	}
+
 	pipe = vp->plist;
 	for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
 		if (pipe->pipe_used) {
 			cnt++;
 			mdp4_overlay_vsync_commit(pipe);
 			/* free previous iommu to freelist
-			 * which will be freed at next
-			 * pipe_commit
-			 */
+			* which will be freed at next
+			* pipe_commit
+			*/
 			mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0);
 			pipe->pipe_used = 0; /* clear */
 		}
 	}
+
 	mdp4_mixer_stage_commit(mixer);
 
-
-	pr_debug("%s: intr=%d expire=%d cpu=%d\n", __func__,
-		vctrl->rdptr_intr_tot, vctrl->expire_tick, smp_processor_id());
-
-	spin_lock_irqsave(&vctrl->spin_lock, flags);
 	pipe = vctrl->base_pipe;
-	if (pipe->blt_changed) {
-		/* blt configurtion changed */
-		pipe->blt_changed = 0;
-		mdp4_overlayproc_cfg(pipe);
-		mdp4_overlay_dmap_xy(pipe);
-	}
-
+	spin_lock_irqsave(&vctrl->spin_lock, flags);
 	if (pipe->ov_blt_addr) {
-		diff = pipe->blt_ov_koff - pipe->blt_ov_done;
-		if (diff < 1) {
-			mdp4_blt_overlay0_cfg(pipe);
-			vsync_commit_kickoff_ov0(pipe, 1);
-		}
+		mdp4_dsi_cmd_blt_ov_update(pipe);
+		pipe->ov_cnt++;
+		vctrl->ov_koff++;
+		vsync_irq_enable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);
 	} else {
-		vsync_commit_kickoff_ov0(pipe, 0);
+		vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
+		vctrl->dmap_koff++;
 	}
-
+	pr_debug("%s: kickoff\n", __func__);
+	/* kickoff overlay engine */
+	mdp4_stat.kickoff_ov0++;
+	outpdw(MDP_BASE + 0x0004, 0);
+	mb(); /* make sure kickoff ececuted */
 	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
 
+	mdp4_stat.overlay_commit[pipe->mixer_num]++;
+
 	return cnt;
 }
 
@@ -369,23 +456,15 @@
 
 	vctrl = &vsync_ctrl_db[cndx];
 
-	if (vctrl->vsync_irq_enabled == enable)
+	if (enable && vctrl->fake_vsync) {
+		vctrl->fake_vsync = 0;
+		schedule_work(&vctrl->vsync_work);
+	}
+
+	if (vctrl->vsync_enabled == enable)
 		return;
 
-	vctrl->vsync_irq_enabled = enable;
-
-	mutex_lock(&vctrl->update_lock);
-	if (enable) {
-		mipi_dsi_clk_cfg(1);
-		mdp_clk_ctrl(1);
-		vsync_irq_enable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
-	} else {
-		mipi_dsi_clk_cfg(0);
-		mdp_clk_ctrl(0);
-		vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
-		vctrl->expire_tick = 0;
-	}
-	mutex_unlock(&vctrl->update_lock);
+	vctrl->vsync_enabled = enable;
 }
 
 void mdp4_dsi_cmd_wait4vsync(int cndx, long long *vtime)
@@ -402,8 +481,10 @@
 	vctrl = &vsync_ctrl_db[cndx];
 	pipe = vctrl->base_pipe;
 
-	if (atomic_read(&vctrl->suspend) > 0)
+	if (atomic_read(&vctrl->suspend) > 0) {
+		*vtime = -1;
 		return;
+	}
 
 	spin_lock_irqsave(&vctrl->spin_lock, flags);
 	if (vctrl->wait_vsync_cnt == 0)
@@ -412,10 +493,44 @@
 	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
 
 	wait_for_completion(&vctrl->vsync_comp);
+	mdp4_stat.wait4vsync0++;
 
 	*vtime = ktime_to_ns(vctrl->vsync_time);
 }
 
+static void mdp4_dsi_cmd_wait4dmap(int cndx)
+{
+	struct vsycn_ctrl *vctrl;
+
+	if (cndx >= MAX_CONTROLLER) {
+		pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+		return;
+	}
+
+	vctrl = &vsync_ctrl_db[cndx];
+
+	if (atomic_read(&vctrl->suspend) > 0)
+		return;
+
+	wait_for_completion(&vctrl->dmap_comp);
+}
+
+static void mdp4_dsi_cmd_wait4ov(int cndx)
+{
+	struct vsycn_ctrl *vctrl;
+
+	if (cndx >= MAX_CONTROLLER) {
+		pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+		return;
+	}
+
+	vctrl = &vsync_ctrl_db[cndx];
+
+	if (atomic_read(&vctrl->suspend) > 0)
+		return;
+
+	wait_for_completion(&vctrl->ov_comp);
+}
 
 /*
  * primary_rdptr_isr:
@@ -427,10 +542,17 @@
 	struct vsycn_ctrl *vctrl;
 
 	vctrl = &vsync_ctrl_db[cndx];
-	pr_debug("%s: cpu=%d\n", __func__, smp_processor_id());
+	pr_debug("%s: ISR, cpu=%d\n", __func__, smp_processor_id());
 	vctrl->rdptr_intr_tot++;
 	vctrl->vsync_time = ktime_get();
 	schedule_work(&vctrl->vsync_work);
+
+	spin_lock(&vctrl->spin_lock);
+	if (vctrl->wait_vsync_cnt) {
+		complete(&vctrl->vsync_comp);
+		vctrl->wait_vsync_cnt = 0;
+	}
+	spin_unlock(&vctrl->spin_lock);
 }
 
 void mdp4_dmap_done_dsi_cmd(int cndx)
@@ -439,35 +561,34 @@
 	struct mdp4_overlay_pipe *pipe;
 	int diff;
 
-	vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
-
 	vctrl = &vsync_ctrl_db[cndx];
-	vctrl->dmap_intr_tot++;
 	pipe = vctrl->base_pipe;
 
-	if (pipe->ov_blt_addr == 0) {
-		mdp4_overlay_dma_commit(cndx);
-		return;
-	}
-
 	 /* blt enabled */
 	spin_lock(&vctrl->spin_lock);
-	pipe->blt_dmap_done++;
-	diff = pipe->blt_ov_done - pipe->blt_dmap_done;
-	spin_unlock(&vctrl->spin_lock);
-	pr_debug("%s: ov_done=%d dmap_done=%d ov_koff=%d dmap_koff=%d\n",
-			__func__, pipe->blt_ov_done, pipe->blt_dmap_done,
-				pipe->blt_ov_koff, pipe->blt_dmap_koff);
+	vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
+	vctrl->dmap_done++;
+	diff = vctrl->ov_done - vctrl->dmap_done;
+	pr_debug("%s: ov_koff=%d ov_done=%d dmap_koff=%d dmap_done=%d cpu=%d\n",
+		__func__, vctrl->ov_koff, vctrl->ov_done, vctrl->dmap_koff,
+		vctrl->dmap_done, smp_processor_id());
+	complete_all(&vctrl->dmap_comp);
 	if (diff <= 0) {
-		if (pipe->blt_end) {
-			pipe->blt_end = 0;
-			pipe->ov_blt_addr = 0;
-			pipe->dma_blt_addr = 0;
-			pipe->blt_changed = 1;
-			pr_info("%s: BLT-END\n", __func__);
-		}
+		if (vctrl->blt_wait)
+			vctrl->blt_wait = 0;
+		spin_unlock(&vctrl->spin_lock);
+		return;
 	}
-	spin_unlock(&dsi_clk_lock);
+
+	/* kick dmap */
+	mdp4_dsi_cmd_blt_dmap_update(pipe);
+	pipe->dmap_cnt++;
+	mdp4_stat.kickoff_dmap++;
+	vctrl->dmap_koff++;
+	vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
+	outpdw(MDP_BASE + 0x000c, 0); /* kickoff dmap engine */
+	mb(); /* make sure kickoff executed */
+	spin_unlock(&vctrl->spin_lock);
 }
 
 /*
@@ -479,30 +600,61 @@
 	struct mdp4_overlay_pipe *pipe;
 	int diff;
 
-	vsync_irq_disable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);
-
 	vctrl = &vsync_ctrl_db[cndx];
 	pipe = vctrl->base_pipe;
 
 	spin_lock(&vctrl->spin_lock);
-	pipe->blt_ov_done++;
-	diff = pipe->blt_ov_done - pipe->blt_dmap_done;
-	spin_unlock(&vctrl->spin_lock);
+	vsync_irq_disable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);
+	vctrl->ov_done++;
+	complete_all(&vctrl->ov_comp);
+	diff = vctrl->ov_done - vctrl->dmap_done;
 
-	pr_debug("%s: ov_done=%d dmap_done=%d ov_koff=%d dmap_koff=%d diff=%d\n",
-			__func__, pipe->blt_ov_done, pipe->blt_dmap_done,
-			pipe->blt_ov_koff, pipe->blt_dmap_koff, diff);
+	pr_debug("%s: ov_koff=%d ov_done=%d dmap_koff=%d dmap_done=%d cpu=%d\n",
+		__func__, vctrl->ov_koff, vctrl->ov_done, vctrl->dmap_koff,
+		vctrl->dmap_done, smp_processor_id());
 
 	if (pipe->ov_blt_addr == 0) {
 		/* blt disabled */
-		pr_debug("%s: NON-BLT\n", __func__);
+		spin_unlock(&vctrl->spin_lock);
 		return;
 	}
 
-	if (diff == 1) {
-		mdp4_blt_dmap_cfg(pipe);
-		vsync_commit_kickoff_dmap(pipe);
+	if (diff > 1) {
+		/*
+		 * two overlay_done and none dmap_done yet
+		 * let dmap_done kickoff dmap
+		 * and put pipe_commit to wait
+		 */
+		vctrl->blt_wait = 1;
+		pr_debug("%s: blt_wait set\n", __func__);
+		spin_unlock(&vctrl->spin_lock);
+		return;
 	}
+	mdp4_dsi_cmd_blt_dmap_update(pipe);
+	pipe->dmap_cnt++;
+	mdp4_stat.kickoff_dmap++;
+	vctrl->dmap_koff++;
+	vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
+	outpdw(MDP_BASE + 0x000c, 0); /* kickoff dmap engine */
+	mb(); /* make sure kickoff executed */
+	spin_unlock(&vctrl->spin_lock);
+}
+
+static void clk_ctrl_work(struct work_struct *work)
+{
+	struct vsycn_ctrl *vctrl =
+		container_of(work, typeof(*vctrl), clk_work);
+
+	mutex_lock(&vctrl->update_lock);
+	if (vctrl->clk_control) {
+		if (vctrl->clk_enabled) {
+			mdp_clk_ctrl(0);
+			vctrl->clk_enabled = 0;
+			vctrl->fake_vsync = 1;
+		}
+	}
+
+	mutex_unlock(&vctrl->update_lock);
 }
 
 static void send_vsync_work(struct work_struct *work)
@@ -539,11 +691,12 @@
 	vctrl->blight.get = 0;
 	vctrl->blight.tot = 0;
 	mutex_init(&vctrl->update_lock);
-	init_completion(&vctrl->vsync_comp);
+	init_completion(&vctrl->ov_comp);
 	init_completion(&vctrl->dmap_comp);
+	init_completion(&vctrl->vsync_comp);
 	spin_lock_init(&vctrl->spin_lock);
-	spin_lock_init(&vctrl->dmap_spin_lock);
 	INIT_WORK(&vctrl->vsync_work, send_vsync_work);
+	INIT_WORK(&vctrl->clk_work, clk_ctrl_work);
 }
 
 void mdp4_primary_rdptr(void)
@@ -701,7 +854,7 @@
 	pipe->ov_blt_addr = 0;
 	pipe->dma_blt_addr = 0;
 
-	MDP_OUTP(MDP_BASE + 0x021c, 0x10); /* read pointer */
+	MDP_OUTP(MDP_BASE + 0x021c, 10); /* read pointer */
 
 	/*
 	 * configure dsi stream id
@@ -711,6 +864,7 @@
 	/* disable dsi trigger */
 	MDP_OUTP(MDP_BASE + 0x000a4, 0x00);
 
+
 	mdp4_overlay_setup_pipe_addr(mfd, pipe);
 
 	mdp4_overlay_rgb_setup(pipe);
@@ -725,10 +879,9 @@
 
 	mdp4_overlay_dmap_cfg(mfd, 0);
 
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 	/* MDP cmd block disable */
 	mdp_clk_ctrl(0);
-
-	wmb();
 }
 
 /* 3D side by side */
@@ -751,7 +904,6 @@
 	if (pipe->pipe_used == 0 ||
 			pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) {
 		pr_err("%s: NOT baselayer\n", __func__);
-		mutex_unlock(&mfd->dma->ov_mutex);
 		return;
 	}
 
@@ -805,82 +957,25 @@
 
 	mdp4_overlay_dmap_cfg(mfd, 0);
 
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 	/* MDP cmd block disable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 }
 
-int mdp4_dsi_overlay_blt_start(struct msm_fb_data_type *mfd)
+void mdp4_dsi_cmd_blt_start(struct msm_fb_data_type *mfd)
 {
-	unsigned long flag;
-	int cndx = 0;
-	struct vsycn_ctrl *vctrl;
-	struct mdp4_overlay_pipe *pipe;
-
-	vctrl = &vsync_ctrl_db[cndx];
-	pipe = vctrl->base_pipe;
-
-	pr_debug("%s: blt_end=%d blt_addr=%x pid=%d\n",
-		 __func__, pipe->blt_end, (int)pipe->ov_blt_addr, current->pid);
-
-	mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
-
-	if (mfd->ov0_wb_buf->write_addr == 0) {
-		pr_err("%s: no blt_base assigned\n", __func__);
-		return -EBUSY;
-	}
-
-	if (pipe->ov_blt_addr == 0) {
-		spin_lock_irqsave(&vctrl->spin_lock, flag);
-		pipe->blt_end = 0;
-		pipe->blt_cnt = 0;
-		pipe->blt_changed = 1;
-		pipe->ov_cnt = 0;
-		pipe->dmap_cnt = 0;
-		pipe->blt_ov_koff = 0;
-		pipe->blt_dmap_koff = 0;
-		pipe->blt_ov_done = 0;
-		pipe->blt_dmap_done = 0;
-		pipe->ov_blt_addr = mfd->ov0_wb_buf->write_addr;
-		pipe->dma_blt_addr = mfd->ov0_wb_buf->read_addr;
-		mdp4_stat.blt_dsi_cmd++;
-		spin_unlock_irqrestore(&vctrl->spin_lock, flag);
-		return 0;
-	}
-
-	return -EBUSY;
+	mdp4_dsi_cmd_do_blt(mfd, 1);
 }
 
-int mdp4_dsi_overlay_blt_stop(struct msm_fb_data_type *mfd)
+void mdp4_dsi_cmd_blt_stop(struct msm_fb_data_type *mfd)
 {
-	unsigned long flag;
-	int cndx = 0;
-	struct vsycn_ctrl *vctrl;
-	struct mdp4_overlay_pipe *pipe;
-
-	vctrl = &vsync_ctrl_db[cndx];
-	pipe = vctrl->base_pipe;
-
-	pr_info("%s: blt_end=%d blt_addr=%x pid=%d\n",
-		 __func__, pipe->blt_end, (int)pipe->ov_blt_addr, current->pid);
-
-	if ((pipe->blt_end == 0) && pipe->ov_blt_addr) {
-		spin_lock_irqsave(&vctrl->spin_lock, flag);
-		pipe->blt_end = 1;	/* mark as end */
-		spin_unlock_irqrestore(&vctrl->spin_lock, flag);
-		return 0;
-	}
-
-	return -EBUSY;
+	mdp4_dsi_cmd_do_blt(mfd, 0);
 }
 
-void mdp4_dsi_overlay_blt(struct msm_fb_data_type *mfd,
+void mdp4_dsi_cmd_overlay_blt(struct msm_fb_data_type *mfd,
 					struct msmfb_overlay_blt *req)
 {
-	if (req->enable)
-		mdp4_dsi_overlay_blt_start(mfd);
-	else if (req->enable == 0)
-		mdp4_dsi_overlay_blt_stop(mfd);
-
+	mdp4_dsi_cmd_do_blt(mfd, req->enable);
 }
 
 int mdp4_dsi_cmd_on(struct platform_device *pdev)
@@ -895,9 +990,11 @@
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
 
 	vctrl = &vsync_ctrl_db[cndx];
+	vctrl->mfd = mfd;
 	vctrl->dev = mfd->fbi->dev;
 
 	mdp_clk_ctrl(1);
+	vsync_irq_enable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
 
 	if (vctrl->base_pipe == NULL)
 		mdp4_overlay_update_dsi_cmd(mfd);
@@ -932,16 +1029,16 @@
 
 	atomic_set(&vctrl->suspend, 1);
 
-	/* make sure dsi clk is on so that
-	 * at panel_next_off() dsi panel can be shut off
-	 */
-	mipi_dsi_ahb_ctrl(1);
-	mipi_dsi_clk_enable();
+	mipi_dsi_cmd_backlight_tx(150);
 
 	mdp4_mixer_stage_down(pipe);
 	mdp4_overlay_pipe_free(pipe);
 	vctrl->base_pipe = NULL;
 
+	vctrl->fake_vsync = 1;
+
+	vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
+
 	pr_info("%s-:\n", __func__);
 
 	/*
@@ -984,12 +1081,14 @@
 	int cndx = 0;
 	struct vsycn_ctrl *vctrl;
 	struct mdp4_overlay_pipe *pipe;
+	long long xx;
 
 	vctrl = &vsync_ctrl_db[cndx];
 
 	if (!mfd->panel_power_on)
 		return;
 
+	vctrl->clk_control = 0;
 	pipe = vctrl->base_pipe;
 	if (pipe == NULL) {
 		pr_err("%s: NO base pipe\n", __func__);
@@ -1001,5 +1100,13 @@
 		mdp4_overlay_setup_pipe_addr(mfd, pipe);
 		mdp4_dsi_cmd_pipe_queue(0, pipe);
 	}
+
+	mdp4_overlay_mdp_perf_upd(mfd, 1);
+
 	mdp4_dsi_cmd_pipe_commit();
+	mdp4_dsi_cmd_wait4vsync(0, &xx);
+	vctrl->expire_tick = VSYNC_EXPIRE_TICK;
+	vctrl->clk_control = 1;
+
+	mdp4_overlay_mdp_perf_upd(mfd, 0);
 }
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 62cc6d2..3c4748d 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -74,8 +74,7 @@
 	unsigned long flag;
 
 	spin_lock_irqsave(&mdp_spin_lock, flag);
-	outp32(MDP_INTR_CLEAR,
-		INTR_DMA_P_DONE | INTR_OVERLAY0_DONE | INTR_PRIMARY_VSYNC);
+	outp32(MDP_INTR_CLEAR, intr);
 	mdp_intr_mask |= intr;
 	outp32(MDP_INTR_ENABLE, mdp_intr_mask);
 	mdp_enable_irq(term);
@@ -88,8 +87,7 @@
 	unsigned long flag;
 
 	spin_lock_irqsave(&mdp_spin_lock, flag);
-	outp32(MDP_INTR_CLEAR,
-		INTR_DMA_P_DONE | INTR_OVERLAY0_DONE | INTR_PRIMARY_VSYNC);
+	outp32(MDP_INTR_CLEAR, intr);
 	mdp_intr_mask &= ~intr;
 	outp32(MDP_INTR_ENABLE, mdp_intr_mask);
 	mdp_disable_irq_nosync(term);
@@ -124,9 +122,6 @@
 		return;
 	}
 
-	/* start timing generator & mmu if they are not started yet */
-	mdp4_overlay_dsi_video_start();
-
 	vctrl = &vsync_ctrl_db[cndx];
 
 	if (atomic_read(&vctrl->suspend) > 0)
@@ -198,6 +193,8 @@
 	}
 	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
 
+	mdp4_overlay_mdp_perf_upd(vctrl->mfd, 1);
+
 	if (vctrl->blt_change) {
 		pipe = vctrl->base_pipe;
 		spin_lock_irqsave(&vctrl->spin_lock, flags);
@@ -211,6 +208,7 @@
 	}
 
 	pipe = vp->plist;
+
 	for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
 		if (pipe->pipe_used) {
 			cnt++;
@@ -226,6 +224,9 @@
 
 	mdp4_mixer_stage_commit(mixer);
 
+	/* start timing generator & mmu if they are not started yet */
+	mdp4_overlay_dsi_video_start();
+
 	pipe = vctrl->base_pipe;
 	spin_lock_irqsave(&vctrl->spin_lock, flags);
 	if (pipe->ov_blt_addr) {
@@ -331,25 +332,27 @@
 	wait_for_completion(&vctrl->dmap_comp);
 }
 
+
 static void mdp4_dsi_video_wait4dmap_done(int cndx)
 {
-        unsigned long flags;
-        struct vsycn_ctrl *vctrl;
+	unsigned long flags;
+	struct vsycn_ctrl *vctrl;
 
-        if (cndx >= MAX_CONTROLLER) {
-            pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
-            return;
-        }
-        vctrl = &vsync_ctrl_db[cndx];
+	if (cndx >= MAX_CONTROLLER) {
+		pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+		return;
+	}
+	vctrl = &vsync_ctrl_db[cndx];
 
-        spin_lock_irqsave(&vctrl->spin_lock, flags);
-        INIT_COMPLETION(vctrl->dmap_comp);
-        vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
-        spin_unlock_irqrestore(&vctrl->spin_lock, flags);
-        mdp4_dsi_video_wait4dmap(cndx);
-        vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
+	spin_lock_irqsave(&vctrl->spin_lock, flags);
+	INIT_COMPLETION(vctrl->dmap_comp);
+	vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
+	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+	mdp4_dsi_video_wait4dmap(cndx);
+	vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
 }
 
+
 static void mdp4_dsi_video_wait4ov(int cndx)
 {
 	struct vsycn_ctrl *vctrl;
@@ -474,6 +477,7 @@
 
 	vctrl->mfd = mfd;
 	vctrl->dev = mfd->fbi->dev;
+	vctrl->fake_vsync = 1;
 
 	/* mdp clock on */
 	mdp_clk_ctrl(1);
@@ -515,7 +519,6 @@
 	if (!(mfd->cont_splash_done)) {
 		mfd->cont_splash_done = 1;
 		mdp4_dsi_video_wait4dmap_done(0);
-		/* disable timing generator */
 		MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
 		mipi_dsi_controller_cfg(0);
 	}
@@ -526,6 +529,8 @@
 	pipe->src_w = fbi->var.xres;
 	pipe->src_y = 0;
 	pipe->src_x = 0;
+	pipe->dst_h = fbi->var.yres;
+	pipe->dst_w = fbi->var.xres;
 	pipe->srcp0_ystride = fbi->fix.line_length;
 	pipe->bpp = bpp;
 
@@ -537,6 +542,8 @@
 	pipe->dst_h = fbi->var.yres;
 	pipe->dst_w = fbi->var.xres;
 
+	mdp4_overlay_mdp_pipe_req(pipe, mfd);
+
 	atomic_set(&vctrl->suspend, 0);
 
 	mdp4_overlay_dmap_xy(pipe);	/* dma_p */
@@ -546,8 +553,7 @@
 
 	mdp4_overlay_reg_flush(pipe, 1);
 	mdp4_mixer_stage_up(pipe);
-
-
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 	/*
 	 * DSI timing setting
 	 */
@@ -768,6 +774,8 @@
 
 	mdp4_mixer_stage_up(pipe);
 
+	mdp4_mixer_stage_commit(pipe->mixer_num);
+
 	mb();
 }
 
@@ -819,13 +827,6 @@
 	MDP_OUTP(MDP_BASE + 0x90008, addr);
 }
 
-void mdp4_overlay_dsi_video_set_perf(struct msm_fb_data_type *mfd)
-{
-	/* change mdp clk while mdp is idle */
-	mdp4_set_perf_level();
-}
-
-
 /*
  * mdp4_primary_vsync_dsi_video: called from isr
  */
@@ -927,8 +928,6 @@
 	vctrl = &vsync_ctrl_db[cndx];
 	pipe = vctrl->base_pipe;
 
-	mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
-
 	if (mfd->ov0_wb_buf->write_addr == 0) {
 		pr_info("%s: no blt_base assigned\n", __func__);
 		return;
@@ -1010,11 +1009,15 @@
 		mdp4_dsi_video_pipe_queue(0, pipe);
 	}
 
+	mdp4_overlay_mdp_perf_upd(mfd, 1);
+
 	mdp4_dsi_video_pipe_commit();
 
 	if (pipe->ov_blt_addr)
 		mdp4_dsi_video_wait4ov(0);
 	else
 		mdp4_dsi_video_wait4dmap(0);
+
+	mdp4_overlay_mdp_perf_upd(mfd, 0);
 }
 
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 9b5d728..12f88a81 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -73,7 +73,9 @@
 	int dmae_wait_cnt;
 	int wait_vsync_cnt;
 	int blt_change;
+	int fake_vsync;
 	struct mutex update_lock;
+	struct completion ov_comp;
 	struct completion dmae_comp;
 	struct completion vsync_comp;
 	spinlock_t spin_lock;
@@ -89,8 +91,7 @@
 	unsigned long flag;
 
 	spin_lock_irqsave(&mdp_spin_lock, flag);
-	outp32(MDP_INTR_CLEAR,
-		INTR_DMA_E_DONE | INTR_OVERLAY1_DONE | INTR_EXTERNAL_VSYNC);
+	outp32(MDP_INTR_CLEAR, intr);
 	mdp_intr_mask |= intr;
 	outp32(MDP_INTR_ENABLE, mdp_intr_mask);
 	mdp_enable_irq(term);
@@ -103,8 +104,7 @@
 	unsigned long flag;
 
 	spin_lock_irqsave(&mdp_spin_lock, flag);
-	outp32(MDP_INTR_CLEAR,
-		INTR_DMA_P_DONE | INTR_OVERLAY0_DONE | INTR_PRIMARY_VSYNC);
+	outp32(MDP_INTR_CLEAR, intr);
 	mdp_intr_mask &= ~intr;
 	outp32(MDP_INTR_ENABLE, mdp_intr_mask);
 	mdp_disable_irq_nosync(term);
@@ -141,9 +141,6 @@
 		return;
 	}
 
-	/* start timing generator & mmu if they are not started yet */
-	mdp4_overlay_dtv_start();
-
 	vctrl = &vsync_ctrl_db[cndx];
 
 	if (atomic_read(&vctrl->suspend) > 0)
@@ -161,6 +158,7 @@
 	*pp = *pipe;	/* keep it */
 	vp->update_cnt++;
 	mutex_unlock(&vctrl->update_lock);
+	mdp4_stat.overlay_play[pipe->mixer_num]++;
 }
 
 static void mdp4_dtv_blt_ov_update(struct mdp4_overlay_pipe *pipe);
@@ -199,11 +197,19 @@
 		if (pipe->pipe_used) {
 			cnt++;
 			mdp4_overlay_vsync_commit(pipe);
+			/* free previous iommu to freelist
+			* which will be freed at next
+			* pipe_commit
+			*/
+			mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0);
 			pipe->pipe_used = 0; /* clear */
 		}
 	}
 	mdp4_mixer_stage_commit(mixer);
 
+	 /* start timing generator & mmu if they are not started yet */
+	mdp4_overlay_dtv_start();
+
 	pipe = vctrl->base_pipe;
 	spin_lock_irqsave(&vctrl->spin_lock, flags);
 	if (pipe->ov_blt_addr) {
@@ -217,10 +223,11 @@
 		outpdw(MDP_BASE + 0x0008, 0);
 	} else if (vctrl->dmae_intr_cnt == 0) {
 		/* schedule second phase update  at dmap */
-		vctrl->dmae_intr_cnt++;
+		INIT_COMPLETION(vctrl->dmae_comp);
 		vsync_irq_enable(INTR_DMA_E_DONE, MDP_DMA_E_TERM);
 	}
 	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+	mdp4_stat.overlay_commit[pipe->mixer_num]++;
 
 	return cnt;
 }
@@ -236,6 +243,11 @@
 
 	vctrl = &vsync_ctrl_db[cndx];
 
+	if (vctrl->fake_vsync) {
+		vctrl->fake_vsync = 0;
+		schedule_work(&vctrl->vsync_work);
+	}
+
 	if (vctrl->vsync_irq_enabled == enable)
 		return;
 
@@ -281,7 +293,6 @@
 
 static void mdp4_dtv_wait4dmae(int cndx)
 {
-	unsigned long flags;
 	struct vsycn_ctrl *vctrl;
 
 	if (cndx >= MAX_CONTROLLER) {
@@ -294,19 +305,7 @@
 	if (atomic_read(&vctrl->suspend) > 0)
 		return;
 
-	spin_lock_irqsave(&vctrl->spin_lock, flags);
-	if (vctrl->dmae_wait_cnt == 0) {
-		INIT_COMPLETION(vctrl->dmae_comp);
-		if (vctrl->dmae_intr_cnt == 0) {
-			vctrl->dmae_intr_cnt++;
-			vsync_irq_enable(INTR_DMA_E_DONE, MDP_DMA_E_TERM);
-		}
-	}
-	vctrl->dmae_wait_cnt++;
-	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
-
 	wait_for_completion(&vctrl->dmae_comp);
-	pr_info("%s: pid=%d after wait\n", __func__, current->pid);
 }
 
 static void send_vsync_work(struct work_struct *work)
@@ -342,6 +341,8 @@
 	vctrl->update_ndx = 0;
 	mutex_init(&vctrl->update_lock);
 	init_completion(&vctrl->vsync_comp);
+	init_completion(&vctrl->ov_comp);
+	init_completion(&vctrl->dmae_comp);
 	atomic_set(&vctrl->suspend, 0);
 	spin_lock_init(&vctrl->spin_lock);
 	INIT_WORK(&vctrl->vsync_work, send_vsync_work);
@@ -523,6 +524,7 @@
 		return -EINVAL;
 
 	vctrl->dev = mfd->fbi->dev;
+	vctrl->fake_vsync = 1;
 
 	mdp_footswitch_ctrl(TRUE);
 	/* Mdp clock enable */
@@ -589,6 +591,7 @@
 
 	ret = panel_next_off(pdev);
 	mdp_footswitch_ctrl(FALSE);
+	vctrl->fake_vsync = 1;
 
 	/* Mdp clock disable */
 	mdp_clk_ctrl(0);
@@ -646,8 +649,7 @@
 
 void mdp4_overlay_dtv_set_perf(struct msm_fb_data_type *mfd)
 {
-	/* change mdp clk while mdp is idle` */
-	mdp4_set_perf_level();
+
 }
 
 static void mdp4_overlay_dtv_alloc_pipe(struct msm_fb_data_type *mfd,
@@ -700,10 +702,16 @@
 	pipe->src_width = fbi->var.xres;
 	pipe->src_h = fbi->var.yres;
 	pipe->src_w = fbi->var.xres;
+	pipe->dst_h = fbi->var.yres;
+	pipe->dst_w = fbi->var.xres;
 	pipe->src_y = 0;
 	pipe->src_x = 0;
+	pipe->dst_h = fbi->var.yres;
+	pipe->dst_w = fbi->var.xres;
 	pipe->srcp0_ystride = fbi->fix.line_length;
 
+	mdp4_overlay_mdp_pipe_req(pipe, mfd);
+
 	ret = mdp4_overlay_format2pipe(pipe);
 	if (ret < 0)
 		pr_warn("%s: format2type failed\n", __func__);
@@ -718,7 +726,7 @@
 
 	mdp4_overlay_reg_flush(pipe, 1);
 	mdp4_mixer_stage_up(pipe);
-
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 	vctrl->base_pipe = pipe; /* keep it */
 }
 
@@ -835,6 +843,7 @@
 	} else  {
 		mdp4_overlay_dma_commit(MDP4_MIXER1);
 	}
+
 	vsync_irq_disable(INTR_DMA_E_DONE, MDP_DMA_E_TERM);
 	spin_unlock(&vctrl->spin_lock);
 }
@@ -891,6 +900,7 @@
 	MDP_OUTP(rgb_base + 0x0050, temp_src_format | BIT(22));
 	mdp4_overlay_reg_flush(vctrl->base_pipe, 1);
 	mdp4_mixer_stage_up(vctrl->base_pipe);
+	mdp4_mixer_stage_commit(vctrl->base_pipe->mixer_num);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 }
 
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index 2da2052..4a478cd 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -80,8 +80,7 @@
 	unsigned long flag;
 
 	spin_lock_irqsave(&mdp_spin_lock, flag);
-	outp32(MDP_INTR_CLEAR,
-		INTR_DMA_P_DONE | INTR_OVERLAY0_DONE | INTR_PRIMARY_VSYNC);
+	outp32(MDP_INTR_CLEAR, intr);
 	mdp_intr_mask |= intr;
 	outp32(MDP_INTR_ENABLE, mdp_intr_mask);
 	mdp_enable_irq(term);
@@ -94,8 +93,7 @@
 	unsigned long flag;
 
 	spin_lock_irqsave(&mdp_spin_lock, flag);
-	outp32(MDP_INTR_CLEAR,
-		INTR_DMA_P_DONE | INTR_OVERLAY0_DONE | INTR_PRIMARY_VSYNC);
+	outp32(MDP_INTR_CLEAR, intr);
 	mdp_intr_mask &= ~intr;
 	outp32(MDP_INTR_ENABLE, mdp_intr_mask);
 	mdp_disable_irq_nosync(term);
@@ -130,9 +128,6 @@
 		return;
 	}
 
-       /* start timing generator & mmu if they are not started yet */
-	mdp4_overlay_lcdc_start();
-
 	vctrl = &vsync_ctrl_db[cndx];
 
 	if (atomic_read(&vctrl->suspend) > 0)
@@ -203,6 +198,8 @@
 	}
 	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
 
+	mdp4_overlay_mdp_perf_upd(vctrl->mfd, 1);
+
 	if (vctrl->blt_change) {
 		pipe = vctrl->base_pipe;
 		spin_lock_irqsave(&vctrl->spin_lock, flags);
@@ -231,6 +228,9 @@
 
 	mdp4_mixer_stage_commit(mixer);
 
+	/* start timing generator & mmu if they are not started yet */
+	mdp4_overlay_lcdc_start();
+
 	pipe = vctrl->base_pipe;
 	spin_lock_irqsave(&vctrl->spin_lock, flags);
 	if (pipe->ov_blt_addr) {
@@ -460,6 +460,7 @@
 
 	vctrl->mfd = mfd;
 	vctrl->dev = mfd->fbi->dev;
+	vctrl->fake_vsync = 1;
 
 	/* mdp clock on */
 	mdp_clk_ctrl(1);
@@ -503,6 +504,8 @@
 	pipe->src_w = fbi->var.xres;
 	pipe->src_y = 0;
 	pipe->src_x = 0;
+	pipe->dst_h = fbi->var.yres;
+	pipe->dst_w = fbi->var.xres;
 
 	if (mfd->display_iova)
 		pipe->srcp0_addr = mfd->display_iova + buf_offset;
@@ -512,6 +515,8 @@
 	pipe->srcp0_ystride = fbi->fix.line_length;
 	pipe->bpp = bpp;
 
+	mdp4_overlay_mdp_pipe_req(pipe, mfd);
+
 	atomic_set(&vctrl->suspend, 0);
 
 	mdp4_overlay_dmap_xy(pipe);
@@ -713,12 +718,6 @@
 	MDP_OUTP(MDP_BASE + 0x90008, addr);
 }
 
-void mdp4_overlay_lcdc_set_perf(struct msm_fb_data_type *mfd)
-{
-	/* change mdp clk while mdp is idle */
-	mdp4_set_perf_level();
-}
-
 /*
  * mdp4_primary_vsync_lcdc: called from isr
  */
@@ -899,10 +898,14 @@
 		mdp4_lcdc_pipe_queue(0, pipe);
 	}
 
+	mdp4_overlay_mdp_perf_upd(mfd, 1);
+
 	mdp4_lcdc_pipe_commit();
 
 	if (pipe->ov_blt_addr)
 		mdp4_lcdc_wait4ov(0);
 	else
 		mdp4_lcdc_wait4dmap(0);
+
+	mdp4_overlay_mdp_perf_upd(mfd, 0);
 }
diff --git a/drivers/video/msm/mdp4_overlay_mddi.c b/drivers/video/msm/mdp4_overlay_mddi.c
index 103419e..e6ff9ef 100644
--- a/drivers/video/msm/mdp4_overlay_mddi.c
+++ b/drivers/video/msm/mdp4_overlay_mddi.c
@@ -243,7 +243,7 @@
 	mdp4_overlay_dmap_xy(pipe);
 
 	mdp4_overlay_dmap_cfg(mfd, 0);
-
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 	mdp4_mddi_vsync_enable(mfd, pipe, 0);
 
 	/* MDP cmd block disable */
@@ -574,8 +574,6 @@
 				struct mdp4_overlay_pipe *pipe)
 {
 	unsigned long flag;
-	/* change mdp clk while mdp is idle` */
-	mdp4_set_perf_level();
 
 	mdp_enable_irq(MDP_OVERLAY0_TERM);
 	spin_lock_irqsave(&mdp_spin_lock, flag);
@@ -660,9 +658,6 @@
 void mdp4_mddi_dma_s_kickoff(struct msm_fb_data_type *mfd,
 				struct mdp4_overlay_pipe *pipe)
 {
-	/* change mdp clk while mdp is idle` */
-	mdp4_set_perf_level();
-
 	mdp_enable_irq(MDP_DMA_S_TERM);
 
 	if (mddi_pipe->ov_blt_addr == 0)
@@ -698,9 +693,10 @@
 
 		if (mddi_pipe && mddi_pipe->ov_blt_addr)
 			mdp4_mddi_blt_dmap_busy_wait(mfd);
-
+		mdp4_overlay_mdp_perf_upd(mfd, 0);
 		mdp4_overlay_update_lcd(mfd);
 
+		mdp4_overlay_mdp_perf_upd(mfd, 1);
 		if (mdp_hw_revision < MDP4_REVISION_V2_1) {
 			/* dmas dmap switch */
 			if (mdp4_overlay_mixer_play(mddi_pipe->mixer_num)
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index 32fe141..940aea8 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -174,6 +174,8 @@
 	pipe->dst_y = 0;
 	pipe->dst_x = 0;
 
+	mdp4_overlay_mdp_pipe_req(pipe, mfd);
+
 	if (mfd->display_iova)
 		pipe->srcp0_addr = mfd->display_iova + buf_offset;
 	else
@@ -182,7 +184,7 @@
 	mdp4_mixer_stage_up(pipe);
 
 	mdp4_overlayproc_cfg(pipe);
-
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 	/* MDP cmd block disable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
@@ -286,6 +288,8 @@
 
 	pr_debug("%s: pid=%d\n", __func__, current->pid);
 
+	mdp4_mixer_stage_commit(pipe->mixer_num);
+
 	mdp4_writeback_overlay_kickoff(mfd, pipe);
 
 	mutex_lock(&mfd->writeback_mutex);
@@ -299,6 +303,7 @@
 void mdp4_writeback_kickoff_ui(struct msm_fb_data_type *mfd,
 		struct mdp4_overlay_pipe *pipe)
 {
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 
 	pr_debug("%s: pid=%d\n", __func__, current->pid);
 	mdp4_writeback_overlay_kickoff(mfd, pipe);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index e76b8ba..ca73a70 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -249,7 +249,7 @@
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 
-	mdp4_update_perf_level(OVERLAY_PERF_LEVEL4);
+	mdp_bus_scale_update_request(5);
 
 #ifdef MDP4_ERROR
 	/*
diff --git a/drivers/video/msm/mdp_dma.c b/drivers/video/msm/mdp_dma.c
index 3a7513a..a506648a 100644
--- a/drivers/video/msm/mdp_dma.c
+++ b/drivers/video/msm/mdp_dma.c
@@ -512,6 +512,23 @@
 	up(&mfd->dma->mutex);
 }
 
+void mdp_dma_vsync_ctrl(int enable)
+{
+	if (vsync_cntrl.vsync_irq_enabled == enable)
+		return;
+
+	vsync_cntrl.vsync_irq_enabled = enable;
+
+	if (enable) {
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		MDP_OUTP(MDP_BASE + 0x021c, 0x10); /* read pointer */
+		mdp3_vsync_irq_enable(MDP_PRIM_RDPTR, MDP_VSYNC_TERM);
+	} else {
+		mdp3_vsync_irq_disable(MDP_PRIM_RDPTR, MDP_VSYNC_TERM);
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	}
+}
+
 void mdp_lcd_update_workqueue_handler(struct work_struct *work)
 {
 	struct msm_fb_data_type *mfd = NULL;
diff --git a/drivers/video/msm/mdp_dma_dsi_video.c b/drivers/video/msm/mdp_dma_dsi_video.c
index 1ba5b8d..d94896f 100644
--- a/drivers/video/msm/mdp_dma_dsi_video.c
+++ b/drivers/video/msm/mdp_dma_dsi_video.c
@@ -26,6 +26,7 @@
 #include "mdp.h"
 #include "msm_fb.h"
 #include "mdp4.h"
+#include "mipi_dsi.h"
 
 #define DSI_VIDEO_BASE	0xF0000
 #define DMA_P_BASE      0x90000
@@ -86,6 +87,7 @@
 	fbi = mfd->fbi;
 	var = &fbi->var;
 
+	vsync_cntrl.dev = mfd->fbi->dev;
 	bpp = fbi->var.bits_per_pixel / 8;
 	buf = (uint8 *) fbi->fix.smem_start;
 
@@ -128,6 +130,7 @@
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 
+
 	/* starting address */
 	MDP_OUTP(MDP_BASE + DMA_P_BASE + 0x8, (uint32) buf);
 
@@ -191,6 +194,13 @@
 	ctrl_polarity =	(data_en_polarity << 2) |
 		(vsync_polarity << 1) | (hsync_polarity);
 
+	if (!(mfd->cont_splash_done)) {
+		mdp_pipe_ctrl(MDP_CMD_BLOCK,
+			MDP_BLOCK_POWER_OFF, FALSE);
+		MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
+		mipi_dsi_controller_cfg(0);
+	}
+
 	MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x4, hsync_ctrl);
 	MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x8, vsync_period);
 	MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0xc, vsync_pulse_width);
@@ -237,6 +247,22 @@
 	return ret;
 }
 
+void mdp_dma_video_vsync_ctrl(int enable)
+{
+	if (vsync_cntrl.vsync_irq_enabled == enable)
+		return;
+
+	vsync_cntrl.vsync_irq_enabled = enable;
+
+	if (enable) {
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		mdp3_vsync_irq_enable(LCDC_FRAME_START, MDP_VSYNC_TERM);
+	} else {
+		mdp3_vsync_irq_disable(LCDC_FRAME_START, MDP_VSYNC_TERM);
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	}
+}
+
 void mdp_dsi_video_update(struct msm_fb_data_type *mfd)
 {
 	struct fb_info *fbi = mfd->fbi;
diff --git a/drivers/video/msm/mdp_dma_lcdc.c b/drivers/video/msm/mdp_dma_lcdc.c
index c418e9c..e030c99 100644
--- a/drivers/video/msm/mdp_dma_lcdc.c
+++ b/drivers/video/msm/mdp_dma_lcdc.c
@@ -105,6 +105,7 @@
 
 	fbi = mfd->fbi;
 	var = &fbi->var;
+	vsync_cntrl.dev = mfd->fbi->dev;
 
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
@@ -249,6 +250,12 @@
 	ctrl_polarity =
 	    (data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity);
 
+	if (!(mfd->cont_splash_done)) {
+		mdp_pipe_ctrl(MDP_CMD_BLOCK,
+			MDP_BLOCK_POWER_OFF, FALSE);
+		MDP_OUTP(MDP_BASE + timer_base, 0);
+	}
+
 	MDP_OUTP(MDP_BASE + timer_base + 0x4, hsync_ctrl);
 	MDP_OUTP(MDP_BASE + timer_base + 0x8, vsync_period);
 	MDP_OUTP(MDP_BASE + timer_base + 0xc, vsync_pulse_width * hsync_period);
@@ -321,6 +328,22 @@
 	return ret;
 }
 
+void mdp_dma_lcdc_vsync_ctrl(int enable)
+{
+	if (vsync_cntrl.vsync_irq_enabled == enable)
+		return;
+
+	vsync_cntrl.vsync_irq_enabled = enable;
+
+	if (enable) {
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		mdp3_vsync_irq_enable(LCDC_FRAME_START, MDP_VSYNC_TERM);
+	} else {
+		mdp3_vsync_irq_disable(LCDC_FRAME_START, MDP_VSYNC_TERM);
+		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	}
+}
+
 void mdp_lcdc_update(struct msm_fb_data_type *mfd)
 {
 	struct fb_info *fbi = mfd->fbi;
diff --git a/drivers/video/msm/mdp_vsync.c b/drivers/video/msm/mdp_vsync.c
index 966b40d..cc350d3 100644
--- a/drivers/video/msm/mdp_vsync.c
+++ b/drivers/video/msm/mdp_vsync.c
@@ -74,14 +74,13 @@
 static uint32 vsync_cnt_cfg;
 
 
-
-void vsync_clk_enable()
+void vsync_clk_prepare_enable(void)
 {
 	if (mdp_vsync_clk)
 		clk_prepare_enable(mdp_vsync_clk);
 }
 
-void vsync_clk_disable()
+void vsync_clk_disable_unprepare(void)
 {
 	if (mdp_vsync_clk)
 		clk_disable_unprepare(mdp_vsync_clk);
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index 492437e..b6294f4 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -7,4 +7,10 @@
 mdss-mdp-objs += mdss_mdp_wb.o
 obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o
 obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o
+
+mdss-dsi-objs := mdss_dsi.o mdss_dsi_host.o
+mdss-dsi-objs += mdss_dsi_panel.o
+mdss-dsi-objs += msm_mdss_io_8974.o
+obj-$(CONFIG_FB_MSM_MDSS) += mdss-dsi.o
+
 obj-$(CONFIG_FB_MSM_MDSS_WRITEBACK) += mdss_wb.o
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index a58c3e6..6145d67 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -22,6 +22,7 @@
 #define MDSS_REG_READ(addr) readl_relaxed(mdss_reg_base + addr)
 
 extern unsigned char *mdss_reg_base;
+extern spinlock_t dsi_clk_lock;
 
 enum mdss_mdp_clk_type {
 	MDSS_CLK_AHB,
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
new file mode 100644
index 0000000..d051828
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -0,0 +1,383 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+
+#include "mdss.h"
+#include "mdss_panel.h"
+#include "mdss_dsi.h"
+
+static struct mdss_panel_common_pdata *panel_pdata;
+
+static unsigned char *mdss_dsi_base;
+
+static int mdss_dsi_off(struct mdss_panel_data *pdata)
+{
+	int ret = 0;
+	struct mdss_panel_info *pinfo;
+
+	pinfo = &pdata->panel_info;
+
+	if (pdata->panel_info.type == MIPI_VIDEO_PANEL)
+		mdss_dsi_controller_cfg(0, pdata);
+
+	mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
+
+	ret = panel_pdata->off(pdata);
+	if (ret) {
+		pr_err("%s: Panel OFF failed\n", __func__);
+		return ret;
+	}
+
+	spin_lock_bh(&dsi_clk_lock);
+	mdss_dsi_clk_disable();
+
+	/* disable dsi engine */
+	MIPI_OUTP(mdss_dsi_base + 0x0004, 0);
+
+	spin_unlock_bh(&dsi_clk_lock);
+
+	mdss_dsi_unprepare_clocks();
+
+	pr_debug("%s-:\n", __func__);
+
+	return ret;
+}
+
+static int mdss_dsi_on(struct mdss_panel_data *pdata)
+{
+	int ret = 0;
+	u32 clk_rate;
+	struct mdss_panel_info *pinfo;
+	struct mipi_panel_info *mipi;
+	u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height;
+	u32 ystride, bpp, data;
+	u32 dummy_xres, dummy_yres;
+
+	pinfo = &pdata->panel_info;
+
+	cont_splash_clk_ctrl(0);
+	mdss_dsi_prepare_clocks();
+
+	spin_lock_bh(&dsi_clk_lock);
+
+	MIPI_OUTP(mdss_dsi_base + 0x118, 1);
+	MIPI_OUTP(mdss_dsi_base + 0x118, 0);
+
+	mdss_dsi_clk_enable();
+	spin_unlock_bh(&dsi_clk_lock);
+
+	clk_rate = pdata->panel_info.clk_rate;
+	clk_rate = min(clk_rate, pdata->panel_info.clk_max);
+
+	hbp = pdata->panel_info.lcdc.h_back_porch;
+	hfp = pdata->panel_info.lcdc.h_front_porch;
+	vbp = pdata->panel_info.lcdc.v_back_porch;
+	vfp = pdata->panel_info.lcdc.v_front_porch;
+	hspw = pdata->panel_info.lcdc.h_pulse_width;
+	vspw = pdata->panel_info.lcdc.v_pulse_width;
+	width = pdata->panel_info.xres;
+	height = pdata->panel_info.yres;
+
+	mipi  = &pdata->panel_info.mipi;
+	if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
+		dummy_xres = pdata->panel_info.lcdc.xres_pad;
+		dummy_yres = pdata->panel_info.lcdc.yres_pad;
+
+		MIPI_OUTP(mdss_dsi_base + 0x24,
+			((hspw + hbp + width + dummy_xres) << 16 |
+			(hspw + hbp)));
+		MIPI_OUTP(mdss_dsi_base + 0x28,
+			((vspw + vbp + height + dummy_yres) << 16 |
+			(vspw + vbp)));
+		MIPI_OUTP(mdss_dsi_base + 0x2C,
+			(vspw + vbp + height + dummy_yres +
+				vfp - 1) << 16 | (hspw + hbp +
+				width + dummy_xres + hfp - 1));
+
+		MIPI_OUTP(mdss_dsi_base + 0x30, (hspw << 16));
+		MIPI_OUTP(mdss_dsi_base + 0x34, 0);
+		MIPI_OUTP(mdss_dsi_base + 0x38, (vspw << 16));
+
+	} else {		/* command mode */
+		if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
+			bpp = 3;
+		else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB666)
+			bpp = 3;
+		else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565)
+			bpp = 2;
+		else
+			bpp = 3;	/* Default format set to RGB888 */
+
+		ystride = width * bpp + 1;
+
+		/* DSI_COMMAND_MODE_MDP_STREAM_CTRL */
+		data = (ystride << 16) | (mipi->vc << 8) | DTYPE_DCS_LWRITE;
+		MIPI_OUTP(mdss_dsi_base + 0x60, data);
+		MIPI_OUTP(mdss_dsi_base + 0x58, data);
+
+		/* DSI_COMMAND_MODE_MDP_STREAM_TOTAL */
+		data = height << 16 | width;
+		MIPI_OUTP(mdss_dsi_base + 0x64, data);
+		MIPI_OUTP(mdss_dsi_base + 0x5C, data);
+	}
+
+	mdss_dsi_host_init(mipi, pdata);
+
+	if (mipi->force_clk_lane_hs) {
+		u32 tmp;
+
+		tmp = MIPI_INP(mdss_dsi_base + 0xac);
+		tmp |= (1<<28);
+		MIPI_OUTP(mdss_dsi_base + 0xac, tmp);
+		wmb();
+	}
+
+	ret = panel_pdata->on(pdata);
+	if (ret) {
+		pr_err("%s: unable to initialize the panel\n", __func__);
+		return ret;
+	}
+
+	mdss_dsi_op_mode_config(mipi->mode, pdata);
+
+	pr_debug("%s-:\n", __func__);
+	return ret;
+}
+
+unsigned char *mdss_dsi_get_base_adr(void)
+{
+	return mdss_dsi_base;
+}
+
+unsigned char *mdss_dsi_get_clk_base(void)
+{
+	return mdss_dsi_base;
+}
+
+static int mdss_dsi_resource_initialized;
+
+static int __devinit mdss_dsi_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	pr_debug("%s\n", __func__);
+
+	if (pdev->dev.of_node && !mdss_dsi_resource_initialized) {
+		struct resource *mdss_dsi_mres;
+		pdev->id = 1;
+		mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		if (!mdss_dsi_mres) {
+			pr_err("%s:%d unable to get the MDSS resources",
+				       __func__, __LINE__);
+			return -ENOMEM;
+		}
+		if (mdss_dsi_mres) {
+			mdss_dsi_base = ioremap(mdss_dsi_mres->start,
+				resource_size(mdss_dsi_mres));
+			if (!mdss_dsi_base) {
+				pr_err("%s:%d unable to remap dsi resources",
+					       __func__, __LINE__);
+				return -ENOMEM;
+			}
+		}
+
+		if (mdss_dsi_clk_init(pdev)) {
+			iounmap(mdss_dsi_base);
+			return -EPERM;
+		}
+
+		rc = of_platform_populate(pdev->dev.of_node,
+					NULL, NULL, &pdev->dev);
+		if (rc) {
+			dev_err(&pdev->dev,
+				"%s: failed to add child nodes, rc=%d\n",
+							__func__, rc);
+			iounmap(mdss_dsi_base);
+			return rc;
+		}
+
+		mdss_dsi_resource_initialized = 1;
+	}
+
+	if (!mdss_dsi_resource_initialized)
+		return -EPERM;
+
+	return 0;
+}
+
+static int __devexit mdss_dsi_remove(struct platform_device *pdev)
+{
+	struct msm_fb_data_type *mfd;
+
+	mfd = platform_get_drvdata(pdev);
+	iounmap(mdss_dsi_base);
+	return 0;
+}
+
+struct device dsi_dev;
+
+int dsi_panel_device_register(struct platform_device *pdev,
+			      struct mdss_panel_common_pdata *panel_data)
+{
+	struct mipi_panel_info *mipi;
+	int rc;
+	u8 lanes = 0, bpp;
+	u32 h_period, v_period, dsi_pclk_rate;
+	struct mdss_panel_data *pdata = NULL;
+
+	panel_pdata = panel_data;
+
+	h_period = ((panel_pdata->panel_info.lcdc.h_pulse_width)
+			+ (panel_pdata->panel_info.lcdc.h_back_porch)
+			+ (panel_pdata->panel_info.xres)
+			+ (panel_pdata->panel_info.lcdc.h_front_porch));
+
+	v_period = ((panel_pdata->panel_info.lcdc.v_pulse_width)
+			+ (panel_pdata->panel_info.lcdc.v_back_porch)
+			+ (panel_pdata->panel_info.yres)
+			+ (panel_pdata->panel_info.lcdc.v_front_porch));
+
+	mipi  = &panel_pdata->panel_info.mipi;
+
+	panel_pdata->panel_info.type =
+		((mipi->mode == DSI_VIDEO_MODE)
+			? MIPI_VIDEO_PANEL : MIPI_CMD_PANEL);
+
+	if (mipi->data_lane3)
+		lanes += 1;
+	if (mipi->data_lane2)
+		lanes += 1;
+	if (mipi->data_lane1)
+		lanes += 1;
+	if (mipi->data_lane0)
+		lanes += 1;
+
+
+	if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
+	    || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB888)
+	    || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB666_LOOSE))
+		bpp = 3;
+	else if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565)
+		 || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB565))
+		bpp = 2;
+	else
+		bpp = 3;		/* Default format set to RGB888 */
+
+	if (panel_pdata->panel_info.type == MIPI_VIDEO_PANEL &&
+		!panel_pdata->panel_info.clk_rate) {
+		h_period += panel_pdata->panel_info.lcdc.xres_pad;
+		v_period += panel_pdata->panel_info.lcdc.yres_pad;
+
+		if (lanes > 0) {
+			panel_pdata->panel_info.clk_rate =
+			((h_period * v_period * (mipi->frame_rate) * bpp * 8)
+			   / lanes);
+		} else {
+			pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__);
+			panel_pdata->panel_info.clk_rate =
+				(h_period * v_period
+					 * (mipi->frame_rate) * bpp * 8);
+		}
+	}
+	pll_divider_config.clk_rate = panel_pdata->panel_info.clk_rate;
+
+	rc = mdss_dsi_clk_div_config(bpp, lanes, &dsi_pclk_rate);
+	if (rc) {
+		pr_err("%s: unable to initialize the clk dividers\n", __func__);
+		return rc;
+	}
+
+	if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 103300000))
+		dsi_pclk_rate = 35000000;
+	mipi->dsi_pclk_rate = dsi_pclk_rate;
+
+	/*
+	 * data chain
+	 */
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	pdata->on = mdss_dsi_on;
+	pdata->off = mdss_dsi_off;
+	memcpy(&(pdata->panel_info), &(panel_pdata->panel_info),
+	       sizeof(struct mdss_panel_info));
+
+	pdata->dsi_base = mdss_dsi_base;
+
+	/*
+	 * register in mdp driver
+	 */
+	rc = mdss_register_panel(pdata);
+	if (rc) {
+		dev_err(&pdev->dev, "unable to register MIPI DSI panel\n");
+		devm_kfree(&pdev->dev, pdata);
+		return rc;
+	}
+
+	pr_debug("%s: Panal data initialized\n", __func__);
+	return 0;
+}
+
+static const struct of_device_id msm_mdss_dsi_dt_match[] = {
+	{.compatible = "qcom,msm-mdss-dsi"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, msm_mdss_dsi_dt_match);
+
+static struct platform_driver mdss_dsi_driver = {
+	.probe = mdss_dsi_probe,
+	.remove = __devexit_p(mdss_dsi_remove),
+	.shutdown = NULL,
+	.driver = {
+		.name = "mdss_dsi",
+		.of_match_table = msm_mdss_dsi_dt_match,
+	},
+};
+
+static int mdss_dsi_register_driver(void)
+{
+	return platform_driver_register(&mdss_dsi_driver);
+}
+
+static int __init mdss_dsi_driver_init(void)
+{
+	int ret;
+
+	mdss_dsi_init();
+
+	ret = mdss_dsi_register_driver();
+	if (ret) {
+		pr_err("mdss_dsi_register_driver() failed!\n");
+		return ret;
+	}
+
+	return ret;
+}
+module_init(mdss_dsi_driver_init);
+
+static void __exit mdss_dsi_driver_cleanup(void)
+{
+	iounmap(mdss_dsi_base);
+	platform_driver_unregister(&mdss_dsi_driver);
+}
+module_exit(mdss_dsi_driver_cleanup);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("DSI controller driver");
+MODULE_AUTHOR("Chandan Uddaraju <chandanu@codeaurora.org>");
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
new file mode 100644
index 0000000..57fce1a
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -0,0 +1,294 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef MDSS_DSI_H
+#define MDSS_DSI_H
+
+#include <linux/list.h>
+#include <mach/scm-io.h>
+
+#include "mdss_panel.h"
+
+#define MMSS_MDSS_CC_BASE_PHY 0xFD8C2300	/* mmss clcok control */
+#define MMSS_SERDES_BASE_PHY 0x04f01000 /* mmss (De)Serializer CFG */
+
+#define MIPI_OUTP(addr, data) writel_relaxed((data), (addr))
+#define MIPI_INP(addr) readl_relaxed(addr)
+
+#ifdef CONFIG_MSM_SECURE_IO
+#define MIPI_OUTP_SECURE(addr, data) secure_writel((data), (addr))
+#define MIPI_INP_SECURE(addr) secure_readl(addr)
+#else
+#define MIPI_OUTP_SECURE(addr, data) writel_relaxed((data), (addr))
+#define MIPI_INP_SECURE(addr) readl_relaxed(addr)
+#endif
+
+#define MIPI_DSI_PRIM 1
+#define MIPI_DSI_SECD 2
+
+#define MIPI_DSI_PANEL_VGA	0
+#define MIPI_DSI_PANEL_WVGA	1
+#define MIPI_DSI_PANEL_WVGA_PT	2
+#define MIPI_DSI_PANEL_FWVGA_PT	3
+#define MIPI_DSI_PANEL_WSVGA_PT	4
+#define MIPI_DSI_PANEL_QHD_PT 5
+#define MIPI_DSI_PANEL_WXGA	6
+#define MIPI_DSI_PANEL_WUXGA	7
+#define MIPI_DSI_PANEL_720P_PT	8
+#define DSI_PANEL_MAX	8
+
+enum {		/* mipi dsi panel */
+	DSI_VIDEO_MODE,
+	DSI_CMD_MODE,
+};
+
+enum {
+	ST_DSI_CLK_OFF,
+	ST_DSI_SUSPEND,
+	ST_DSI_RESUME,
+	ST_DSI_PLAYING,
+	ST_DSI_NUM
+};
+
+enum {
+	EV_DSI_UPDATE,
+	EV_DSI_DONE,
+	EV_DSI_TOUT,
+	EV_DSI_NUM
+};
+
+enum {
+	LANDSCAPE = 1,
+	PORTRAIT = 2,
+};
+
+enum dsi_trigger_type {
+	DSI_CMD_MODE_DMA,
+	DSI_CMD_MODE_MDP,
+};
+
+#define DSI_NON_BURST_SYNCH_PULSE	0
+#define DSI_NON_BURST_SYNCH_EVENT	1
+#define DSI_BURST_MODE			2
+
+#define DSI_RGB_SWAP_RGB	0
+#define DSI_RGB_SWAP_RBG	1
+#define DSI_RGB_SWAP_BGR	2
+#define DSI_RGB_SWAP_BRG	3
+#define DSI_RGB_SWAP_GRB	4
+#define DSI_RGB_SWAP_GBR	5
+
+#define DSI_VIDEO_DST_FORMAT_RGB565		0
+#define DSI_VIDEO_DST_FORMAT_RGB666		1
+#define DSI_VIDEO_DST_FORMAT_RGB666_LOOSE	2
+#define DSI_VIDEO_DST_FORMAT_RGB888		3
+
+#define DSI_CMD_DST_FORMAT_RGB111	0
+#define DSI_CMD_DST_FORMAT_RGB332	3
+#define DSI_CMD_DST_FORMAT_RGB444	4
+#define DSI_CMD_DST_FORMAT_RGB565	6
+#define DSI_CMD_DST_FORMAT_RGB666	7
+#define DSI_CMD_DST_FORMAT_RGB888	8
+
+#define DSI_INTR_ERROR_MASK		BIT(25)
+#define DSI_INTR_ERROR			BIT(24)
+#define DSI_INTR_VIDEO_DONE_MASK	BIT(17)
+#define DSI_INTR_VIDEO_DONE		BIT(16)
+#define DSI_INTR_CMD_MDP_DONE_MASK	BIT(9)
+#define DSI_INTR_CMD_MDP_DONE		BIT(8)
+#define DSI_INTR_CMD_DMA_DONE_MASK	BIT(1)
+#define DSI_INTR_CMD_DMA_DONE		BIT(0)
+
+#define DSI_CMD_TRIGGER_NONE		0x0	/* mdp trigger */
+#define DSI_CMD_TRIGGER_TE		0x02
+#define DSI_CMD_TRIGGER_SW		0x04
+#define DSI_CMD_TRIGGER_SW_SEOF		0x05	/* cmd dma only */
+#define DSI_CMD_TRIGGER_SW_TE		0x06
+
+extern struct device dsi_dev;
+extern int mdss_dsi_clk_on;
+extern u32 dsi_irq;
+
+struct dsiphy_pll_divider_config {
+	u32 clk_rate;
+	u32 fb_divider;
+	u32 ref_divider_ratio;
+	u32 bit_clk_divider;	/* oCLK1 */
+	u32 byte_clk_divider;	/* oCLK2 */
+	u32 analog_posDiv;
+	u32 digital_posDiv;
+};
+
+extern struct dsiphy_pll_divider_config pll_divider_config;
+
+struct dsi_clk_mnd_table {
+	u8 lanes;
+	u8 bpp;
+	u8 pll_digital_posDiv;
+	u8 pclk_m;
+	u8 pclk_n;
+	u8 pclk_d;
+};
+
+static const struct dsi_clk_mnd_table mnd_table[] = {
+	{ 1, 2,  8, 1, 1, 0},
+	{ 1, 3, 12, 1, 1, 0},
+	{ 2, 2,  4, 1, 1, 0},
+	{ 2, 3,  6, 1, 1, 0},
+	{ 3, 2,  1, 3, 8, 4},
+	{ 3, 3,  4, 1, 1, 0},
+	{ 4, 2,  2, 1, 1, 0},
+	{ 4, 3,  3, 1, 1, 0},
+};
+
+struct dsi_clk_desc {
+	u32 src;
+	u32 m;
+	u32 n;
+	u32 d;
+	u32 mnd_mode;
+	u32 pre_div_func;
+};
+
+#define DSI_HOST_HDR_SIZE	4
+#define DSI_HDR_LAST		BIT(31)
+#define DSI_HDR_LONG_PKT	BIT(30)
+#define DSI_HDR_BTA		BIT(29)
+#define DSI_HDR_VC(vc)		(((vc) & 0x03) << 22)
+#define DSI_HDR_DTYPE(dtype)	(((dtype) & 0x03f) << 16)
+#define DSI_HDR_DATA2(data)	(((data) & 0x0ff) << 8)
+#define DSI_HDR_DATA1(data)	((data) & 0x0ff)
+#define DSI_HDR_WC(wc)		((wc) & 0x0ffff)
+
+#define DSI_BUF_SIZE	1024
+#define MDSS_DSI_MRPS	0x04  /* Maximum Return Packet Size */
+
+#define MDSS_DSI_LEN 8 /* 4 x 4 - 6 - 2, bytes dcs header+crc-align  */
+
+struct dsi_buf {
+	u32 *hdr;	/* dsi host header */
+	char *start;	/* buffer start addr */
+	char *end;	/* buffer end addr */
+	int size;	/* size of buffer */
+	char *data;	/* buffer */
+	int len;	/* data length */
+	dma_addr_t dmap; /* mapped dma addr */
+};
+
+/* dcs read/write */
+#define DTYPE_DCS_WRITE		0x05	/* short write, 0 parameter */
+#define DTYPE_DCS_WRITE1	0x15	/* short write, 1 parameter */
+#define DTYPE_DCS_READ		0x06	/* read */
+#define DTYPE_DCS_LWRITE	0x39	/* long write */
+
+/* generic read/write */
+#define DTYPE_GEN_WRITE		0x03	/* short write, 0 parameter */
+#define DTYPE_GEN_WRITE1	0x13	/* short write, 1 parameter */
+#define DTYPE_GEN_WRITE2	0x23	/* short write, 2 parameter */
+#define DTYPE_GEN_LWRITE	0x29	/* long write */
+#define DTYPE_GEN_READ		0x04	/* long read, 0 parameter */
+#define DTYPE_GEN_READ1		0x14	/* long read, 1 parameter */
+#define DTYPE_GEN_READ2		0x24	/* long read, 2 parameter */
+
+#define DTYPE_TEAR_ON		0x35	/* set tear on */
+#define DTYPE_MAX_PKTSIZE	0x37	/* set max packet size */
+#define DTYPE_NULL_PKT		0x09	/* null packet, no data */
+#define DTYPE_BLANK_PKT		0x19	/* blankiing packet, no data */
+
+#define DTYPE_CM_ON		0x02	/* color mode off */
+#define DTYPE_CM_OFF		0x12	/* color mode on */
+#define DTYPE_PERIPHERAL_OFF	0x22
+#define DTYPE_PERIPHERAL_ON	0x32
+
+/*
+ * dcs response
+ */
+#define DTYPE_ACK_ERR_RESP      0x02
+#define DTYPE_EOT_RESP          0x08    /* end of tx */
+#define DTYPE_GEN_READ1_RESP    0x11    /* 1 parameter, short */
+#define DTYPE_GEN_READ2_RESP    0x12    /* 2 parameter, short */
+#define DTYPE_GEN_LREAD_RESP    0x1a
+#define DTYPE_DCS_LREAD_RESP    0x1c
+#define DTYPE_DCS_READ1_RESP    0x21    /* 1 parameter, short */
+#define DTYPE_DCS_READ2_RESP    0x22    /* 2 parameter, short */
+
+struct dsi_cmd_desc {
+	int dtype;
+	int last;
+	int vc;
+	int ack;	/* ask ACK from peripheral */
+	int wait;
+	int dlen;
+	char *payload;
+};
+
+struct dsi_kickoff_action {
+	struct list_head act_entry;
+	void (*action) (void *);
+	void *data;
+};
+
+struct mdss_panel_common_pdata {
+	struct mdss_panel_info panel_info;
+	int (*on) (struct mdss_panel_data *pdata);
+	int (*off) (struct mdss_panel_data *pdata);
+};
+
+int dsi_panel_device_register(struct platform_device *pdev,
+			      struct mdss_panel_common_pdata *panel_data);
+
+char *mdss_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen);
+char *mdss_dsi_buf_init(struct dsi_buf *dp);
+void mdss_dsi_init(void);
+int mdss_dsi_buf_alloc(struct dsi_buf *, int size);
+int mdss_dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm);
+int mdss_dsi_cmds_tx(struct mdss_panel_data *pdata,
+		struct dsi_buf *dp, struct dsi_cmd_desc *cmds, int cnt);
+
+int mdss_dsi_cmd_dma_tx(struct dsi_buf *dp,
+				struct mdss_panel_data *pdata);
+int mdss_dsi_cmd_reg_tx(u32 data,
+				struct mdss_panel_data *pdata);
+int mdss_dsi_cmds_rx(struct mdss_panel_data *pdata,
+			struct dsi_buf *tp, struct dsi_buf *rp,
+			struct dsi_cmd_desc *cmds, int len);
+int mdss_dsi_cmd_dma_rx(struct dsi_buf *tp, int rlen,
+				struct mdss_panel_data *pdata);
+void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
+				struct mdss_panel_data *pdata);
+void mdss_dsi_op_mode_config(int mode,
+				struct mdss_panel_data *pdata);
+void mdss_dsi_cmd_mode_ctrl(int enable);
+void mdp4_dsi_cmd_trigger(void);
+void mdss_dsi_cmd_mdp_start(void);
+void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata);
+void mdss_dsi_ack_err_status(unsigned char *dsi_base);
+void mdss_dsi_clk_enable(void);
+void mdss_dsi_clk_disable(void);
+void mdss_dsi_controller_cfg(int enable,
+				struct mdss_panel_data *pdata);
+void mdss_dsi_sw_reset(struct mdss_panel_data *pdata);
+
+irqreturn_t mdss_dsi_isr(int irq, void *ptr);
+
+void mipi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata);
+int mdss_dsi_clk_div_config(u8 bpp, u8 lanes,
+			    u32 *expected_dsi_pclk);
+int mdss_dsi_clk_init(struct platform_device *pdev);
+void mdss_dsi_clk_deinit(struct device *dev);
+void mdss_dsi_prepare_clocks(void);
+void mdss_dsi_unprepare_clocks(void);
+void cont_splash_clk_ctrl(int enable);
+unsigned char *mdss_dsi_get_base_adr(void);
+
+#endif /* MDSS_DSI_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
new file mode 100644
index 0000000..7bc0105
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -0,0 +1,1259 @@
+
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/iopoll.h>
+
+#include "mdss.h"
+#include "mdss_dsi.h"
+
+static struct completion dsi_dma_comp;
+static int dsi_irq_enabled;
+static spinlock_t dsi_irq_lock;
+static spinlock_t dsi_mdp_lock;
+static int dsi_mdp_busy;
+
+spinlock_t dsi_clk_lock;
+
+struct mdss_hw mdss_dsi_hw = {
+	.hw_ndx = MDSS_HW_DSI0,
+	.irq_handler = mdss_dsi_isr,
+};
+
+void mdss_dsi_init(void)
+{
+	init_completion(&dsi_dma_comp);
+	spin_lock_init(&dsi_irq_lock);
+	spin_lock_init(&dsi_mdp_lock);
+	spin_lock_init(&dsi_clk_lock);
+}
+
+void mdss_dsi_enable_irq(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dsi_irq_lock, flags);
+	if (dsi_irq_enabled) {
+		pr_debug("%s: IRQ aleady enabled\n", __func__);
+		spin_unlock_irqrestore(&dsi_irq_lock, flags);
+		return;
+	}
+	mdss_enable_irq(&mdss_dsi_hw);
+	dsi_irq_enabled = 1;
+	/* TO DO: Check whether MDSS IRQ is enabled */
+	spin_unlock_irqrestore(&dsi_irq_lock, flags);
+}
+
+void mdss_dsi_disable_irq(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dsi_irq_lock, flags);
+	if (dsi_irq_enabled == 0) {
+		pr_debug("%s: IRQ already disabled\n", __func__);
+		spin_unlock_irqrestore(&dsi_irq_lock, flags);
+		return;
+	}
+	mdss_disable_irq(&mdss_dsi_hw);
+	dsi_irq_enabled = 0;
+	/* TO DO: Check whether MDSS IRQ is Disabled */
+	spin_unlock_irqrestore(&dsi_irq_lock, flags);
+}
+
+/*
+ * mdss_dsi_disale_irq_nosync() should be called
+ * from interrupt context
+ */
+void mdss_dsi_disable_irq_nosync(void)
+{
+	spin_lock(&dsi_irq_lock);
+	if (dsi_irq_enabled == 0) {
+		pr_debug("%s: IRQ cannot be disabled\n", __func__);
+		spin_unlock(&dsi_irq_lock);
+		return;
+	}
+
+	dsi_irq_enabled = 0;
+	spin_unlock(&dsi_irq_lock);
+}
+
+/*
+ * mipi dsi buf mechanism
+ */
+char *mdss_dsi_buf_reserve(struct dsi_buf *dp, int len)
+{
+	dp->data += len;
+	return dp->data;
+}
+
+char *mdss_dsi_buf_unreserve(struct dsi_buf *dp, int len)
+{
+	dp->data -= len;
+	return dp->data;
+}
+
+char *mdss_dsi_buf_push(struct dsi_buf *dp, int len)
+{
+	dp->data -= len;
+	dp->len += len;
+	return dp->data;
+}
+
+char *mdss_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen)
+{
+	dp->hdr = (u32 *)dp->data;
+	return mdss_dsi_buf_reserve(dp, hlen);
+}
+
+char *mdss_dsi_buf_init(struct dsi_buf *dp)
+{
+	int off;
+
+	dp->data = dp->start;
+	off = (int)dp->data;
+	/* 8 byte align */
+	off &= 0x07;
+	if (off)
+		off = 8 - off;
+	dp->data += off;
+	dp->len = 0;
+	return dp->data;
+}
+
+int mdss_dsi_buf_alloc(struct dsi_buf *dp, int size)
+{
+
+	dp->start = kmalloc(size, GFP_KERNEL);
+	if (dp->start == NULL) {
+		pr_err("%s:%u\n", __func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	dp->end = dp->start + size;
+	dp->size = size;
+
+	if ((int)dp->start & 0x07)
+		pr_err("%s: buf NOT 8 bytes aligned\n", __func__);
+
+	dp->data = dp->start;
+	dp->len = 0;
+	return size;
+}
+
+/*
+ * mipi dsi generic long write
+ */
+static int mdss_dsi_generic_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+	char *bp;
+	u32 *hp;
+	int i, len;
+
+	bp = mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+
+	/* fill up payload */
+	if (cm->payload) {
+		len = cm->dlen;
+		len += 3;
+		len &= ~0x03;	/* multipled by 4 */
+		for (i = 0; i < cm->dlen; i++)
+			*bp++ = cm->payload[i];
+
+		/* append 0xff to the end */
+		for (; i < len; i++)
+			*bp++ = 0xff;
+
+		dp->len += len;
+	}
+
+	/* fill up header */
+	hp = dp->hdr;
+	*hp = 0;
+	*hp = DSI_HDR_WC(cm->dlen);
+	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_LONG_PKT;
+	*hp |= DSI_HDR_DTYPE(DTYPE_GEN_LWRITE);
+	if (cm->last)
+		*hp |= DSI_HDR_LAST;
+
+	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+	return dp->len;
+}
+
+/*
+ * mipi dsi generic short write with 0, 1 2 parameters
+ */
+static int mdss_dsi_generic_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+	u32 *hp;
+	int len;
+
+	if (cm->dlen && cm->payload == 0) {
+		pr_err("%s: NO payload error\n", __func__);
+		return 0;
+	}
+
+	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+	hp = dp->hdr;
+	*hp = 0;
+	*hp |= DSI_HDR_VC(cm->vc);
+	if (cm->last)
+		*hp |= DSI_HDR_LAST;
+
+
+	len = (cm->dlen > 2) ? 2 : cm->dlen;
+
+	if (len == 1) {
+		*hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE1);
+		*hp |= DSI_HDR_DATA1(cm->payload[0]);
+		*hp |= DSI_HDR_DATA2(0);
+	} else if (len == 2) {
+		*hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE2);
+		*hp |= DSI_HDR_DATA1(cm->payload[0]);
+		*hp |= DSI_HDR_DATA2(cm->payload[1]);
+	} else {
+		*hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE);
+		*hp |= DSI_HDR_DATA1(0);
+		*hp |= DSI_HDR_DATA2(0);
+	}
+
+	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+	return dp->len;	/* 4 bytes */
+}
+
+/*
+ * mipi dsi gerneric read with 0, 1 2 parameters
+ */
+static int mdss_dsi_generic_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+	u32 *hp;
+	int len;
+
+	if (cm->dlen && cm->payload == 0) {
+		pr_err("%s: NO payload error\n", __func__);
+		return 0;
+	}
+
+	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+	hp = dp->hdr;
+	*hp = 0;
+	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_BTA;
+	if (cm->last)
+		*hp |= DSI_HDR_LAST;
+
+	len = (cm->dlen > 2) ? 2 : cm->dlen;
+
+	if (len == 1) {
+		*hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ1);
+		*hp |= DSI_HDR_DATA1(cm->payload[0]);
+		*hp |= DSI_HDR_DATA2(0);
+	} else if (len == 2) {
+		*hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ2);
+		*hp |= DSI_HDR_DATA1(cm->payload[0]);
+		*hp |= DSI_HDR_DATA2(cm->payload[1]);
+	} else {
+		*hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ);
+		*hp |= DSI_HDR_DATA1(0);
+		*hp |= DSI_HDR_DATA2(0);
+	}
+
+	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+	return dp->len;	/* 4 bytes */
+}
+
+/*
+ * mipi dsi dcs long write
+ */
+static int mdss_dsi_dcs_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+	char *bp;
+	u32 *hp;
+	int i, len;
+
+	bp = mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+
+	/*
+	 * fill up payload
+	 * dcs command byte (first byte) followed by payload
+	 */
+	if (cm->payload) {
+		len = cm->dlen;
+		len += 3;
+		len &= ~0x03;	/* multipled by 4 */
+		for (i = 0; i < cm->dlen; i++)
+			*bp++ = cm->payload[i];
+
+		/* append 0xff to the end */
+		for (; i < len; i++)
+			*bp++ = 0xff;
+
+		dp->len += len;
+	}
+
+	/* fill up header */
+	hp = dp->hdr;
+	*hp = 0;
+	*hp = DSI_HDR_WC(cm->dlen);
+	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_LONG_PKT;
+	*hp |= DSI_HDR_DTYPE(DTYPE_DCS_LWRITE);
+	if (cm->last)
+		*hp |= DSI_HDR_LAST;
+
+	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+	return dp->len;
+}
+
+/*
+ * mipi dsi dcs short write with 0 parameters
+ */
+static int mdss_dsi_dcs_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+	u32 *hp;
+	int len;
+
+	if (cm->payload == 0) {
+		pr_err("%s: NO payload error\n", __func__);
+		return -EINVAL;
+	}
+
+	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+	hp = dp->hdr;
+	*hp = 0;
+	*hp |= DSI_HDR_VC(cm->vc);
+	if (cm->ack)		/* ask ACK trigger msg from peripeheral */
+		*hp |= DSI_HDR_BTA;
+	if (cm->last)
+		*hp |= DSI_HDR_LAST;
+
+	len = (cm->dlen > 1) ? 1 : cm->dlen;
+
+	*hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE);
+	*hp |= DSI_HDR_DATA1(cm->payload[0]);	/* dcs command byte */
+	*hp |= DSI_HDR_DATA2(0);
+
+	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+	return dp->len;
+}
+
+/*
+ * mipi dsi dcs short write with 1 parameters
+ */
+static int mdss_dsi_dcs_swrite1(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+	u32 *hp;
+
+	if (cm->dlen < 2 || cm->payload == 0) {
+		pr_err("%s: NO payload error\n", __func__);
+		return -EINVAL;
+	}
+
+	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+	hp = dp->hdr;
+	*hp = 0;
+	*hp |= DSI_HDR_VC(cm->vc);
+	if (cm->ack)		/* ask ACK trigger msg from peripeheral */
+		*hp |= DSI_HDR_BTA;
+	if (cm->last)
+		*hp |= DSI_HDR_LAST;
+
+	*hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE1);
+	*hp |= DSI_HDR_DATA1(cm->payload[0]);	/* dcs comamnd byte */
+	*hp |= DSI_HDR_DATA2(cm->payload[1]);	/* parameter */
+
+	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+	return dp->len;
+}
+/*
+ * mipi dsi dcs read with 0 parameters
+ */
+
+static int mdss_dsi_dcs_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+	u32 *hp;
+
+	if (cm->payload == 0) {
+		pr_err("%s: NO payload error\n", __func__);
+		return -EINVAL;
+	}
+
+	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+	hp = dp->hdr;
+	*hp = 0;
+	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_BTA;
+	*hp |= DSI_HDR_DTYPE(DTYPE_DCS_READ);
+	if (cm->last)
+		*hp |= DSI_HDR_LAST;
+
+	*hp |= DSI_HDR_DATA1(cm->payload[0]);	/* dcs command byte */
+	*hp |= DSI_HDR_DATA2(0);
+
+	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+	return dp->len;	/* 4 bytes */
+}
+
+static int mdss_dsi_cm_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+	u32 *hp;
+
+	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+	hp = dp->hdr;
+	*hp = 0;
+	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_DTYPE(DTYPE_CM_ON);
+	if (cm->last)
+		*hp |= DSI_HDR_LAST;
+
+	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+	return dp->len;	/* 4 bytes */
+}
+
+static int mdss_dsi_cm_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+	u32 *hp;
+
+	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+	hp = dp->hdr;
+	*hp = 0;
+	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_DTYPE(DTYPE_CM_OFF);
+	if (cm->last)
+		*hp |= DSI_HDR_LAST;
+
+	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+	return dp->len;	/* 4 bytes */
+}
+
+static int mdss_dsi_peripheral_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+	u32 *hp;
+
+	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+	hp = dp->hdr;
+	*hp = 0;
+	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_ON);
+	if (cm->last)
+		*hp |= DSI_HDR_LAST;
+
+	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+	return dp->len;	/* 4 bytes */
+}
+
+static int mdss_dsi_peripheral_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+	u32 *hp;
+
+	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+	hp = dp->hdr;
+	*hp = 0;
+	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_OFF);
+	if (cm->last)
+		*hp |= DSI_HDR_LAST;
+
+	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+	return dp->len;	/* 4 bytes */
+}
+
+static int mdss_dsi_set_max_pktsize(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+	u32 *hp;
+
+	if (cm->payload == 0) {
+		pr_err("%s: NO payload error\n", __func__);
+		return 0;
+	}
+
+	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+	hp = dp->hdr;
+	*hp = 0;
+	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_DTYPE(DTYPE_MAX_PKTSIZE);
+	if (cm->last)
+		*hp |= DSI_HDR_LAST;
+
+	*hp |= DSI_HDR_DATA1(cm->payload[0]);
+	*hp |= DSI_HDR_DATA2(cm->payload[1]);
+
+	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+	return dp->len;	/* 4 bytes */
+}
+
+static int mdss_dsi_null_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+	u32 *hp;
+
+	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+	hp = dp->hdr;
+	*hp = 0;
+	*hp = DSI_HDR_WC(cm->dlen);
+	*hp |= DSI_HDR_LONG_PKT;
+	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_DTYPE(DTYPE_NULL_PKT);
+	if (cm->last)
+		*hp |= DSI_HDR_LAST;
+
+	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+	return dp->len;	/* 4 bytes */
+}
+
+static int mdss_dsi_blank_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+	u32 *hp;
+
+	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
+	hp = dp->hdr;
+	*hp = 0;
+	*hp = DSI_HDR_WC(cm->dlen);
+	*hp |= DSI_HDR_LONG_PKT;
+	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_DTYPE(DTYPE_BLANK_PKT);
+	if (cm->last)
+		*hp |= DSI_HDR_LAST;
+
+	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
+
+	return dp->len;	/* 4 bytes */
+}
+
+/*
+ * prepare cmd buffer to be txed
+ */
+int mdss_dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
+{
+	int len = 0;
+
+	switch (cm->dtype) {
+	case DTYPE_GEN_WRITE:
+	case DTYPE_GEN_WRITE1:
+	case DTYPE_GEN_WRITE2:
+		len = mdss_dsi_generic_swrite(dp, cm);
+		break;
+	case DTYPE_GEN_LWRITE:
+		len = mdss_dsi_generic_lwrite(dp, cm);
+		break;
+	case DTYPE_GEN_READ:
+	case DTYPE_GEN_READ1:
+	case DTYPE_GEN_READ2:
+		len = mdss_dsi_generic_read(dp, cm);
+		break;
+	case DTYPE_DCS_LWRITE:
+		len = mdss_dsi_dcs_lwrite(dp, cm);
+		break;
+	case DTYPE_DCS_WRITE:
+		len = mdss_dsi_dcs_swrite(dp, cm);
+		break;
+	case DTYPE_DCS_WRITE1:
+		len = mdss_dsi_dcs_swrite1(dp, cm);
+		break;
+	case DTYPE_DCS_READ:
+		len = mdss_dsi_dcs_read(dp, cm);
+		break;
+	case DTYPE_MAX_PKTSIZE:
+		len = mdss_dsi_set_max_pktsize(dp, cm);
+		break;
+	case DTYPE_NULL_PKT:
+		len = mdss_dsi_null_pkt(dp, cm);
+		break;
+	case DTYPE_BLANK_PKT:
+		len = mdss_dsi_blank_pkt(dp, cm);
+		break;
+	case DTYPE_CM_ON:
+		len = mdss_dsi_cm_on(dp, cm);
+		break;
+	case DTYPE_CM_OFF:
+		len = mdss_dsi_cm_off(dp, cm);
+		break;
+	case DTYPE_PERIPHERAL_ON:
+		len = mdss_dsi_peripheral_on(dp, cm);
+		break;
+	case DTYPE_PERIPHERAL_OFF:
+		len = mdss_dsi_peripheral_off(dp, cm);
+		break;
+	default:
+		pr_debug("%s: dtype=%x NOT supported\n",
+					__func__, cm->dtype);
+		break;
+
+	}
+
+	return len;
+}
+
+/*
+ * mdss_dsi_short_read1_resp: 1 parameter
+ */
+static int mdss_dsi_short_read1_resp(struct dsi_buf *rp)
+{
+	/* strip out dcs type */
+	rp->data++;
+	rp->len = 1;
+	return rp->len;
+}
+
+/*
+ * mdss_dsi_short_read2_resp: 2 parameter
+ */
+static int mdss_dsi_short_read2_resp(struct dsi_buf *rp)
+{
+	/* strip out dcs type */
+	rp->data++;
+	rp->len = 2;
+	return rp->len;
+}
+
+static int mdss_dsi_long_read_resp(struct dsi_buf *rp)
+{
+	short len;
+
+	len = rp->data[2];
+	len <<= 8;
+	len |= rp->data[1];
+	/* strip out dcs header */
+	rp->data += 4;
+	rp->len -= 4;
+	/* strip out 2 bytes of checksum */
+	rp->len -= 2;
+	return len;
+}
+
+void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
+				struct mdss_panel_data *pdata)
+{
+	u32 dsi_ctrl, intr_ctrl;
+	u32 data;
+
+	pinfo->rgb_swap = DSI_RGB_SWAP_RGB;
+
+	if (pinfo->mode == DSI_VIDEO_MODE) {
+		data = 0;
+		if (pinfo->pulse_mode_hsa_he)
+			data |= BIT(28);
+		if (pinfo->hfp_power_stop)
+			data |= BIT(24);
+		if (pinfo->hbp_power_stop)
+			data |= BIT(20);
+		if (pinfo->hsa_power_stop)
+			data |= BIT(16);
+		if (pinfo->eof_bllp_power_stop)
+			data |= BIT(15);
+		if (pinfo->bllp_power_stop)
+			data |= BIT(12);
+		data |= ((pinfo->traffic_mode & 0x03) << 8);
+		data |= ((pinfo->dst_format & 0x03) << 4); /* 2 bits */
+		data |= (pinfo->vc & 0x03);
+		MIPI_OUTP((pdata->dsi_base) + 0x0010, data);
+
+		data = 0;
+		data |= ((pinfo->rgb_swap & 0x07) << 12);
+		if (pinfo->b_sel)
+			data |= BIT(8);
+		if (pinfo->g_sel)
+			data |= BIT(4);
+		if (pinfo->r_sel)
+			data |= BIT(0);
+		MIPI_OUTP((pdata->dsi_base) + 0x0020, data);
+	} else if (pinfo->mode == DSI_CMD_MODE) {
+		data = 0;
+		data |= ((pinfo->interleave_max & 0x0f) << 20);
+		data |= ((pinfo->rgb_swap & 0x07) << 16);
+		if (pinfo->b_sel)
+			data |= BIT(12);
+		if (pinfo->g_sel)
+			data |= BIT(8);
+		if (pinfo->r_sel)
+			data |= BIT(4);
+		data |= (pinfo->dst_format & 0x0f);	/* 4 bits */
+		MIPI_OUTP((pdata->dsi_base) + 0x003c, data);
+
+		/* DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL */
+		data = pinfo->wr_mem_continue & 0x0ff;
+		data <<= 8;
+		data |= (pinfo->wr_mem_start & 0x0ff);
+		if (pinfo->insert_dcs_cmd)
+			data |= BIT(16);
+		MIPI_OUTP((pdata->dsi_base) + 0x0044, data);
+	} else
+		pr_err("%s: Unknown DSI mode=%d\n", __func__, pinfo->mode);
+
+	dsi_ctrl = BIT(8) | BIT(2);	/* clock enable & cmd mode */
+	intr_ctrl = 0;
+	intr_ctrl = (DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_CMD_MDP_DONE_MASK);
+
+	if (pinfo->crc_check)
+		dsi_ctrl |= BIT(24);
+	if (pinfo->ecc_check)
+		dsi_ctrl |= BIT(20);
+	if (pinfo->data_lane3)
+		dsi_ctrl |= BIT(7);
+	if (pinfo->data_lane2)
+		dsi_ctrl |= BIT(6);
+	if (pinfo->data_lane1)
+		dsi_ctrl |= BIT(5);
+	if (pinfo->data_lane0)
+		dsi_ctrl |= BIT(4);
+
+	/* from frame buffer, low power mode */
+	/* DSI_COMMAND_MODE_DMA_CTRL */
+	MIPI_OUTP((pdata->dsi_base) + 0x3C, 0x14000000);
+
+	data = 0;
+	if (pinfo->te_sel)
+		data |= BIT(31);
+	data |= pinfo->mdp_trigger << 4;/* cmd mdp trigger */
+	data |= pinfo->dma_trigger;	/* cmd dma trigger */
+	data |= (pinfo->stream & 0x01) << 8;
+	MIPI_OUTP((pdata->dsi_base) + 0x0084, data); /* DSI_TRIG_CTRL */
+
+	/* DSI_LAN_SWAP_CTRL */
+	MIPI_OUTP((pdata->dsi_base) + 0x00b0, pinfo->dlane_swap);
+
+	/* clock out ctrl */
+	data = pinfo->t_clk_post & 0x3f;	/* 6 bits */
+	data <<= 8;
+	data |= pinfo->t_clk_pre & 0x3f;	/*  6 bits */
+	/* DSI_CLKOUT_TIMING_CTRL */
+	MIPI_OUTP((pdata->dsi_base) + 0xc4, data);
+
+	data = 0;
+	if (pinfo->rx_eot_ignore)
+		data |= BIT(4);
+	if (pinfo->tx_eot_append)
+		data |= BIT(0);
+	MIPI_OUTP((pdata->dsi_base) + 0x00cc, data); /* DSI_EOT_PACKET_CTRL */
+
+
+	/* allow only ack-err-status  to generate interrupt */
+	/* DSI_ERR_INT_MASK0 */
+	MIPI_OUTP((pdata->dsi_base) + 0x010c, 0x13ff3fe0);
+
+	intr_ctrl |= DSI_INTR_ERROR_MASK;
+	MIPI_OUTP((pdata->dsi_base) + 0x0110, intr_ctrl); /* DSI_INTL_CTRL */
+
+	/* turn esc, byte, dsi, pclk, sclk, hclk on */
+	MIPI_OUTP((pdata->dsi_base) + 0x11c, 0x23f); /* DSI_CLK_CTRL */
+
+	dsi_ctrl |= BIT(0);	/* enable dsi */
+	MIPI_OUTP((pdata->dsi_base) + 0x0004, dsi_ctrl);
+
+	wmb();
+}
+
+void mipi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata)
+{
+	u32 data = MIPI_INP((pdata->dsi_base) + 0x3c);
+
+	if (mode == 0)
+		data &= ~BIT(26);
+	else
+		data |= BIT(26);
+
+	MIPI_OUTP((pdata->dsi_base) + 0x3c, data);
+}
+
+void mdss_dsi_sw_reset(struct mdss_panel_data *pdata)
+{
+	MIPI_OUTP((pdata->dsi_base) + 0x118, 0x01);
+	wmb();
+	MIPI_OUTP((pdata->dsi_base) + 0x118, 0x00);
+	wmb();
+}
+
+void mdss_dsi_controller_cfg(int enable,
+			     struct mdss_panel_data *pdata)
+{
+
+	u32 dsi_ctrl;
+	u32 status;
+	u32 sleep_us = 1000;
+	u32 timeout_us = 16000;
+
+	/* Check for CMD_MODE_DMA_BUSY */
+	if (readl_poll_timeout(((pdata->dsi_base) + 0x0008),
+			   status,
+			   ((status & 0x02) == 0),
+			       sleep_us, timeout_us))
+		pr_info("%s: DSI status=%x failed\n", __func__, status);
+
+	/* Check for x_HS_FIFO_EMPTY */
+	if (readl_poll_timeout(((pdata->dsi_base) + 0x000c),
+			   status,
+			   ((status & 0x11111000) == 0x11111000),
+			       sleep_us, timeout_us))
+		pr_info("%s: FIFO status=%x failed\n", __func__, status);
+
+	dsi_ctrl = MIPI_INP((pdata->dsi_base) + 0x0004);
+	if (enable)
+		dsi_ctrl |= 0x01;
+	else
+		dsi_ctrl &= ~0x01;
+
+	MIPI_OUTP((pdata->dsi_base) + 0x0004, dsi_ctrl);
+	wmb();
+}
+
+void mdss_dsi_op_mode_config(int mode,
+			     struct mdss_panel_data *pdata)
+{
+
+	u32 dsi_ctrl, intr_ctrl;
+
+	dsi_ctrl = MIPI_INP((pdata->dsi_base) + 0x0004);
+	dsi_ctrl &= ~0x07;
+	if (mode == DSI_VIDEO_MODE) {
+		dsi_ctrl |= 0x03;
+		intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK;
+	} else {		/* command mode */
+		dsi_ctrl |= 0x05;
+		intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_ERROR_MASK |
+				DSI_INTR_CMD_MDP_DONE_MASK;
+	}
+
+	pr_debug("%s: dsi_ctrl=%x intr=%x\n", __func__, dsi_ctrl, intr_ctrl);
+
+	MIPI_OUTP((pdata->dsi_base) + 0x0110, intr_ctrl); /* DSI_INTL_CTRL */
+	MIPI_OUTP((pdata->dsi_base) + 0x0004, dsi_ctrl);
+	wmb();
+}
+
+void mdss_dsi_cmd_mdp_start(void)
+{
+	unsigned long flag;
+
+	spin_lock_irqsave(&dsi_mdp_lock, flag);
+	mdss_dsi_enable_irq();
+	dsi_mdp_busy = true;
+	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
+}
+
+
+void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata)
+{
+	u32 status;
+	int timeout_us = 10000;
+
+	MIPI_OUTP((pdata->dsi_base) + 0x098, 0x01);	/* trigger */
+	wmb();
+
+	/* Check for CMD_MODE_DMA_BUSY */
+	if (readl_poll_timeout(((pdata->dsi_base) + 0x0008),
+				status, ((status & 0x0010) == 0),
+				0, timeout_us))
+		pr_info("%s: DSI status=%x failed\n", __func__, status);
+
+	mdss_dsi_ack_err_status((pdata->dsi_base));
+
+	pr_debug("%s: BTA done, status = %d\n", __func__, status);
+}
+
+int mdss_dsi_cmd_reg_tx(u32 data,
+			struct mdss_panel_data *pdata)
+{
+	int i;
+	char *bp;
+
+	bp = (char *)&data;
+	pr_debug("%s: ", __func__);
+	for (i = 0; i < 4; i++)
+		pr_debug("%x ", *bp++);
+
+	pr_debug("\n");
+
+	MIPI_OUTP((pdata->dsi_base) + 0x0084, 0x04);/* sw trigger */
+	MIPI_OUTP((pdata->dsi_base) + 0x0004, 0x135);
+
+	wmb();
+
+	MIPI_OUTP((pdata->dsi_base) + 0x03c, data);
+	wmb();
+	MIPI_OUTP((pdata->dsi_base) + 0x090, 0x01);	/* trigger */
+	wmb();
+
+	udelay(300);
+
+	return 4;
+}
+
+/*
+ * mdss_dsi_cmds_tx:
+ * ov_mutex need to be acquired before call this function.
+ */
+int mdss_dsi_cmds_tx(struct mdss_panel_data *pdata,
+		struct dsi_buf *tp, struct dsi_cmd_desc *cmds, int cnt)
+{
+	struct dsi_cmd_desc *cm;
+	u32 dsi_ctrl, ctrl;
+	int i, video_mode;
+	unsigned long flag;
+
+	/* turn on cmd mode
+	* for video mode, do not send cmds more than
+	* one pixel line, since it only transmit it
+	* during BLLP.
+	*/
+	dsi_ctrl = MIPI_INP((pdata->dsi_base) + 0x0004);
+	video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
+	if (video_mode) {
+		ctrl = dsi_ctrl | 0x04; /* CMD_MODE_EN */
+		MIPI_OUTP((pdata->dsi_base) + 0x0004, ctrl);
+	}
+
+	spin_lock_irqsave(&dsi_mdp_lock, flag);
+	mdss_dsi_enable_irq();
+	dsi_mdp_busy = true;
+	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
+
+	cm = cmds;
+	mdss_dsi_buf_init(tp);
+	for (i = 0; i < cnt; i++) {
+		mdss_dsi_buf_init(tp);
+		mdss_dsi_cmd_dma_add(tp, cm);
+		mdss_dsi_cmd_dma_tx(tp, pdata);
+		if (cm->wait)
+			msleep(cm->wait);
+		cm++;
+	}
+
+	spin_lock_irqsave(&dsi_mdp_lock, flag);
+	dsi_mdp_busy = false;
+	mdss_dsi_disable_irq();
+	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
+
+	if (video_mode)
+		MIPI_OUTP((pdata->dsi_base) + 0x0004, dsi_ctrl); /* restore */
+
+	return cnt;
+}
+
+/* MDSS_DSI_MRPS, Maximum Return Packet Size */
+static char max_pktsize[2] = {0x00, 0x00}; /* LSB tx first, 10 bytes */
+
+static struct dsi_cmd_desc pkt_size_cmd[] = {
+	{DTYPE_MAX_PKTSIZE, 1, 0, 0, 0,
+		sizeof(max_pktsize), max_pktsize}
+};
+
+/*
+ * DSI panel reply with  MAX_RETURN_PACKET_SIZE bytes of data
+ * plus DCS header, ECC and CRC for DCS long read response
+ * mdss_dsi_controller only have 4x32 bits register ( 16 bytes) to
+ * hold data per transaction.
+ * MDSS_DSI_LEN equal to 8
+ * len should be either 4 or 8
+ * any return data more than MDSS_DSI_LEN need to be break down
+ * to multiple transactions.
+ *
+ * ov_mutex need to be acquired before call this function.
+ */
+int mdss_dsi_cmds_rx(struct mdss_panel_data *pdata,
+			struct dsi_buf *tp, struct dsi_buf *rp,
+			struct dsi_cmd_desc *cmds, int rlen)
+{
+	int cnt, len, diff, pkt_size;
+	unsigned long flag;
+	char cmd;
+
+	if (pdata->panel_info.mipi.no_max_pkt_size)
+		rlen = ALIGN(rlen, 4); /* Only support rlen = 4*n */
+
+	len = rlen;
+	diff = 0;
+
+	if (len <= 2)
+		cnt = 4;	/* short read */
+	else {
+		if (len > MDSS_DSI_LEN)
+			len = MDSS_DSI_LEN;	/* 8 bytes at most */
+
+		len = ALIGN(len, 4); /* len 4 bytes align */
+		diff = len - rlen;
+		/*
+		 * add extra 2 bytes to len to have overall
+		 * packet size is multipe by 4. This also make
+		 * sure 4 bytes dcs headerlocates within a
+		 * 32 bits register after shift in.
+		 * after all, len should be either 6 or 10.
+		 */
+		len += 2;
+		cnt = len + 6; /* 4 bytes header + 2 bytes crc */
+	}
+
+	spin_lock_irqsave(&dsi_mdp_lock, flag);
+	mdss_dsi_enable_irq();
+	dsi_mdp_busy = true;
+	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
+
+	if (!pdata->panel_info.mipi.no_max_pkt_size) {
+		/* packet size need to be set at every read */
+		pkt_size = len;
+		max_pktsize[0] = pkt_size;
+		mdss_dsi_buf_init(tp);
+		mdss_dsi_cmd_dma_add(tp, pkt_size_cmd);
+		mdss_dsi_cmd_dma_tx(tp, pdata);
+	}
+
+	mdss_dsi_buf_init(tp);
+	mdss_dsi_cmd_dma_add(tp, cmds);
+
+	/* transmit read comamnd to client */
+	mdss_dsi_cmd_dma_tx(tp, pdata);
+	/*
+	 * once cmd_dma_done interrupt received,
+	 * return data from client is ready and stored
+	 * at RDBK_DATA register already
+	 */
+	mdss_dsi_buf_init(rp);
+	if (pdata->panel_info.mipi.no_max_pkt_size) {
+		/*
+		 * expect rlen = n * 4
+		 * short alignement for start addr
+		 */
+		rp->data += 2;
+	}
+
+	mdss_dsi_cmd_dma_rx(rp, cnt, pdata);
+
+	spin_lock_irqsave(&dsi_mdp_lock, flag);
+	dsi_mdp_busy = false;
+	mdss_dsi_disable_irq();
+	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
+
+	if (pdata->panel_info.mipi.no_max_pkt_size) {
+		/*
+		 * remove extra 2 bytes from previous
+		 * rx transaction at shift register
+		 * which was inserted during copy
+		 * shift registers to rx buffer
+		 * rx payload start from long alignment addr
+		 */
+		rp->data += 2;
+	}
+
+	cmd = rp->data[0];
+	switch (cmd) {
+	case DTYPE_ACK_ERR_RESP:
+		pr_debug("%s: rx ACK_ERR_PACLAGE\n", __func__);
+		break;
+	case DTYPE_GEN_READ1_RESP:
+	case DTYPE_DCS_READ1_RESP:
+		mdss_dsi_short_read1_resp(rp);
+		break;
+	case DTYPE_GEN_READ2_RESP:
+	case DTYPE_DCS_READ2_RESP:
+		mdss_dsi_short_read2_resp(rp);
+		break;
+	case DTYPE_GEN_LREAD_RESP:
+	case DTYPE_DCS_LREAD_RESP:
+		mdss_dsi_long_read_resp(rp);
+		rp->len -= 2; /* extra 2 bytes added */
+		rp->len -= diff; /* align bytes */
+		break;
+	default:
+		break;
+	}
+
+	return rp->len;
+}
+
+int mdss_dsi_cmd_dma_tx(struct dsi_buf *tp,
+			struct mdss_panel_data *pdata)
+{
+	int len;
+	int i;
+	char *bp;
+
+	bp = tp->data;
+
+	pr_debug("%s: ", __func__);
+	for (i = 0; i < tp->len; i++)
+		pr_debug("%x ", *bp++);
+
+	pr_debug("\n");
+
+	len = tp->len;
+	len += 3;
+	len &= ~0x03;	/* multipled by 4 */
+
+	tp->dmap = dma_map_single(&dsi_dev, tp->data, len, DMA_TO_DEVICE);
+	if (dma_mapping_error(&dsi_dev, tp->dmap))
+		pr_err("%s: dmap mapp failed\n", __func__);
+
+	INIT_COMPLETION(dsi_dma_comp);
+
+	MIPI_OUTP((pdata->dsi_base) + 0x048, tp->dmap);
+	MIPI_OUTP((pdata->dsi_base) + 0x04c, len);
+	wmb();
+
+	MIPI_OUTP((pdata->dsi_base) + 0x090, 0x01);	/* trigger */
+	wmb();
+
+	wait_for_completion(&dsi_dma_comp);
+
+	dma_unmap_single(&dsi_dev, tp->dmap, len, DMA_TO_DEVICE);
+	tp->dmap = 0;
+	return tp->len;
+}
+
+int mdss_dsi_cmd_dma_rx(struct dsi_buf *rp, int rlen,
+			struct mdss_panel_data *pdata)
+{
+	u32 *lp, data;
+	int i, off, cnt;
+
+	lp = (u32 *)rp->data;
+	cnt = rlen;
+	cnt += 3;
+	cnt >>= 2;
+
+	if (cnt > 4)
+		cnt = 4; /* 4 x 32 bits registers only */
+
+	off = 0x06c;	/* DSI_RDBK_DATA0 */
+	off += ((cnt - 1) * 4);
+
+
+	for (i = 0; i < cnt; i++) {
+		data = (u32)MIPI_INP((pdata->dsi_base) + off);
+		*lp++ = ntohl(data);	/* to network byte order */
+		off -= 4;
+		rp->len += sizeof(*lp);
+	}
+
+	return rlen;
+}
+
+void mdss_dsi_ack_err_status(unsigned char *dsi_base)
+{
+	u32 status;
+
+	status = MIPI_INP(dsi_base + 0x0068);/* DSI_ACK_ERR_STATUS */
+
+	if (status) {
+		MIPI_OUTP(dsi_base + 0x0068, status);
+		pr_debug("%s: status=%x\n", __func__, status);
+	}
+}
+
+void mdss_dsi_timeout_status(unsigned char *dsi_base)
+{
+	u32 status;
+
+	status = MIPI_INP(dsi_base + 0x00c0);/* DSI_TIMEOUT_STATUS */
+	if (status & 0x0111) {
+		MIPI_OUTP(dsi_base + 0x00c0, status);
+		pr_debug("%s: status=%x\n", __func__, status);
+	}
+}
+
+void mdss_dsi_dln0_phy_err(unsigned char *dsi_base)
+{
+	u32 status;
+
+	status = MIPI_INP(dsi_base + 0x00b4);/* DSI_DLN0_PHY_ERR */
+
+	if (status & 0x011111) {
+		MIPI_OUTP(dsi_base + 0x00b4, status);
+		pr_debug("%s: status=%x\n", __func__, status);
+	}
+}
+
+void mdss_dsi_fifo_status(unsigned char *dsi_base)
+{
+	u32 status;
+
+	status = MIPI_INP(dsi_base + 0x000c);/* DSI_FIFO_STATUS */
+
+	if (status & 0x44444489) {
+		MIPI_OUTP(dsi_base + 0x000c, status);
+		pr_debug("%s: status=%x\n", __func__, status);
+	}
+}
+
+void mdss_dsi_status(unsigned char *dsi_base)
+{
+	u32 status;
+
+	status = MIPI_INP(dsi_base + 0x0008);/* DSI_STATUS */
+
+	if (status & 0x80000000) {
+		MIPI_OUTP(dsi_base + 0x0008, status);
+		pr_debug("%s: status=%x\n", __func__, status);
+	}
+}
+
+void mdss_dsi_error(unsigned char *dsi_base)
+{
+	/* DSI_ERR_INT_MASK0 */
+	mdss_dsi_ack_err_status(dsi_base);	/* mask0, 0x01f */
+	mdss_dsi_timeout_status(dsi_base);	/* mask0, 0x0e0 */
+	mdss_dsi_fifo_status(dsi_base);		/* mask0, 0x133d00 */
+	mdss_dsi_status(dsi_base);		/* mask0, 0xc0100 */
+	mdss_dsi_dln0_phy_err(dsi_base);	/* mask0, 0x3e00000 */
+}
+
+
+irqreturn_t mdss_dsi_isr(int irq, void *ptr)
+{
+	u32 isr;
+	unsigned char *dsi_base;
+
+	dsi_base = mdss_dsi_get_base_adr();
+	if (!dsi_base)
+		pr_err("%s:%d DSI base adr no Initialized",
+				       __func__, __LINE__);
+
+	isr = MIPI_INP(dsi_base + 0x0110);/* DSI_INTR_CTRL */
+	MIPI_OUTP(dsi_base + 0x0110, isr);
+
+	if (isr & DSI_INTR_ERROR)
+		mdss_dsi_error(dsi_base);
+
+	if (isr & DSI_INTR_VIDEO_DONE) {
+		/*
+		* do something  here
+		*/
+	}
+
+	if (isr & DSI_INTR_CMD_DMA_DONE)
+		complete(&dsi_dma_comp);
+
+	if (isr & DSI_INTR_CMD_MDP_DONE) {
+		spin_lock(&dsi_mdp_lock);
+		dsi_mdp_busy = false;
+		mdss_dsi_disable_irq_nosync();
+		spin_unlock(&dsi_mdp_lock);
+	}
+
+	return IRQ_HANDLED;
+}
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
new file mode 100644
index 0000000..bfb7fae
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -0,0 +1,358 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#include "mdss_dsi.h"
+
+#define DT_CMD_HDR 6
+
+static struct dsi_buf dsi_panel_tx_buf;
+static struct dsi_buf dsi_panel_rx_buf;
+
+static struct dsi_cmd_desc *dsi_panel_on_cmds;
+static struct dsi_cmd_desc *dsi_panel_off_cmds;
+static int num_of_on_cmds;
+static int num_of_off_cmds;
+static char *on_cmds, *off_cmds;
+
+static int mdss_dsi_panel_on(struct mdss_panel_data *pdata)
+{
+	struct mipi_panel_info *mipi;
+
+	mipi  = &pdata->panel_info.mipi;
+
+	pr_debug("%s:%d, debug info (mode) : %d\n", __func__, __LINE__,
+		 mipi->mode);
+
+	if (mipi->mode == DSI_VIDEO_MODE) {
+		mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf, dsi_panel_on_cmds,
+			num_of_on_cmds);
+	} else {
+		pr_err("%s:%d, CMD MODE NOT SUPPORTED", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mdss_dsi_panel_off(struct mdss_panel_data *pdata)
+{
+	struct mipi_panel_info *mipi;
+
+	mipi  = &pdata->panel_info.mipi;
+
+	pr_debug("%s:%d, debug info\n", __func__, __LINE__);
+
+	if (mipi->mode == DSI_VIDEO_MODE) {
+		mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf, dsi_panel_off_cmds,
+			num_of_off_cmds);
+	} else {
+		pr_debug("%s:%d, CMD mode not supported", __func__, __LINE__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mdss_panel_parse_dt(struct platform_device *pdev,
+			    struct mdss_panel_common_pdata *panel_data)
+{
+	struct device_node *np = pdev->dev.of_node;
+	u32 res[6], tmp;
+	int rc, i, len;
+	int cmd_plen, data_offset;
+	const char *data;
+
+	rc = of_property_read_u32_array(np, "qcom,mdss-pan-res", res, 2);
+	if (rc) {
+		pr_err("%s:%d, panel resolution not specified\n",
+						__func__, __LINE__);
+		return -EINVAL;
+	}
+	panel_data->panel_info.xres = (!rc ? res[0] : 640);
+	panel_data->panel_info.yres = (!rc ? res[1] : 480);
+
+	rc = of_property_read_u32(np, "qcom,mdss-pan-bpp", &tmp);
+	if (rc) {
+		pr_err("%s:%d, panel bpp not specified\n",
+						__func__, __LINE__);
+		return -EINVAL;
+	}
+	panel_data->panel_info.bpp = (!rc ? tmp : 24);
+
+	rc = of_property_read_u32_array(np,
+		"qcom,mdss-pan-porch-values", res, 6);
+	panel_data->panel_info.lcdc.h_back_porch = (!rc ? res[0] : 6);
+	panel_data->panel_info.lcdc.h_pulse_width = (!rc ? res[1] : 2);
+	panel_data->panel_info.lcdc.h_front_porch = (!rc ? res[2] : 6);
+	panel_data->panel_info.lcdc.v_back_porch = (!rc ? res[3] : 6);
+	panel_data->panel_info.lcdc.v_pulse_width = (!rc ? res[4] : 2);
+	panel_data->panel_info.lcdc.v_front_porch = (!rc ? res[5] : 6);
+
+	rc = of_property_read_u32(np,
+		"qcom,mdss-pan-underflow-clr", &tmp);
+	panel_data->panel_info.lcdc.underflow_clr = (!rc ? tmp : 0xff);
+
+	rc = of_property_read_u32_array(np,
+		"qcom,mdss-pan-bl-levels", res, 2);
+	panel_data->panel_info.bl_min = (!rc ? res[0] : 0);
+	panel_data->panel_info.bl_max = (!rc ? res[1] : 255);
+
+	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-mode", &tmp);
+	panel_data->panel_info.mipi.mode = (!rc ? tmp : DSI_VIDEO_MODE);
+
+	rc = of_property_read_u32(np,
+		"qcom,mdss-pan-dsi-h-pulse-mode", &tmp);
+	panel_data->panel_info.mipi.pulse_mode_hsa_he = (!rc ? tmp : false);
+
+	rc = of_property_read_u32_array(np,
+		"qcom,mdss-pan-dsi-h-power-stop", res, 3);
+	panel_data->panel_info.mipi.hbp_power_stop = (!rc ? res[0] : false);
+	panel_data->panel_info.mipi.hsa_power_stop = (!rc ? res[1] : false);
+	panel_data->panel_info.mipi.hfp_power_stop = (!rc ? res[2] : false);
+
+	rc = of_property_read_u32_array(np,
+		"qcom,mdss-pan-dsi-bllp-power-stop", res, 2);
+	panel_data->panel_info.mipi.bllp_power_stop =
+					(!rc ? res[0] : false);
+	panel_data->panel_info.mipi.eof_bllp_power_stop =
+					(!rc ? res[1] : false);
+
+	rc = of_property_read_u32(np,
+		"qcom,mdss-pan-dsi-traffic-mode", &tmp);
+	panel_data->panel_info.mipi.traffic_mode =
+			(!rc ? tmp : DSI_NON_BURST_SYNCH_PULSE);
+
+	rc = of_property_read_u32(np,
+		"qcom,mdss-pan-dsi-dst-format", &tmp);
+	panel_data->panel_info.mipi.dst_format =
+			(!rc ? tmp : DSI_VIDEO_DST_FORMAT_RGB888);
+
+	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-vc", &tmp);
+	panel_data->panel_info.mipi.vc = (!rc ? tmp : 0);
+
+	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-rgb-swap", &tmp);
+	panel_data->panel_info.mipi.rgb_swap = (!rc ? tmp : DSI_RGB_SWAP_RGB);
+
+	rc = of_property_read_u32_array(np,
+		"qcom,mdss-pan-dsi-data-lanes", res, 4);
+	panel_data->panel_info.mipi.data_lane0 = (!rc ? res[0] : true);
+	panel_data->panel_info.mipi.data_lane1 = (!rc ? res[1] : false);
+	panel_data->panel_info.mipi.data_lane2 = (!rc ? res[2] : false);
+	panel_data->panel_info.mipi.data_lane3 = (!rc ? res[3] : false);
+
+	rc = of_property_read_u32_array(np, "qcom,mdss-pan-dsi-t-clk", res, 2);
+	panel_data->panel_info.mipi.t_clk_pre = (!rc ? res[0] : 0x24);
+	panel_data->panel_info.mipi.t_clk_post = (!rc ? res[1] : 0x03);
+
+	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-stream", &tmp);
+	panel_data->panel_info.mipi.stream = (!rc ? tmp : 0);
+
+	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-mdp-tr", &tmp);
+	panel_data->panel_info.mipi.mdp_trigger =
+			(!rc ? tmp : DSI_CMD_TRIGGER_SW);
+	if (panel_data->panel_info.mipi.mdp_trigger > 6) {
+		pr_err("%s:%d, Invalid mdp trigger. Forcing to sw trigger",
+						 __func__, __LINE__);
+		panel_data->panel_info.mipi.mdp_trigger =
+					DSI_CMD_TRIGGER_SW;
+	}
+
+	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-dma-tr", &tmp);
+	panel_data->panel_info.mipi.dma_trigger =
+			(!rc ? tmp : DSI_CMD_TRIGGER_SW);
+	if (panel_data->panel_info.mipi.dma_trigger > 6) {
+		pr_err("%s:%d, Invalid dma trigger. Forcing to sw trigger",
+						 __func__, __LINE__);
+		panel_data->panel_info.mipi.dma_trigger =
+					DSI_CMD_TRIGGER_SW;
+	}
+
+	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-frame-rate", &tmp);
+	panel_data->panel_info.mipi.frame_rate = (!rc ? tmp : 60);
+
+	data = of_get_property(np, "qcom,panel-on-cmds", &len);
+	if (!data) {
+		pr_err("%s:%d, Unable to read ON cmds", __func__, __LINE__);
+		goto error;
+	}
+
+	on_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL);
+	if (!on_cmds)
+		return -ENOMEM;
+
+	memcpy(on_cmds, data, len);
+
+	data_offset = 0;
+	cmd_plen = 0;
+	while ((len - data_offset) >= DT_CMD_HDR) {
+		data_offset += (DT_CMD_HDR - 1);
+		cmd_plen = on_cmds[data_offset++];
+		data_offset += cmd_plen;
+		num_of_on_cmds++;
+	}
+	if (!num_of_on_cmds) {
+		pr_err("%s:%d, No ON cmds specified", __func__, __LINE__);
+		goto error;
+	}
+
+	dsi_panel_on_cmds =
+		kzalloc((num_of_on_cmds * sizeof(struct dsi_cmd_desc)),
+						GFP_KERNEL);
+	if (!dsi_panel_on_cmds)
+		return -ENOMEM;
+
+	data_offset = 0;
+	for (i = 0; i < num_of_on_cmds; i++) {
+		dsi_panel_on_cmds[i].dtype = on_cmds[data_offset++];
+		dsi_panel_on_cmds[i].last = on_cmds[data_offset++];
+		dsi_panel_on_cmds[i].vc = on_cmds[data_offset++];
+		dsi_panel_on_cmds[i].ack = on_cmds[data_offset++];
+		dsi_panel_on_cmds[i].wait = on_cmds[data_offset++];
+		dsi_panel_on_cmds[i].dlen = on_cmds[data_offset++];
+		dsi_panel_on_cmds[i].payload = &on_cmds[data_offset];
+		data_offset += (dsi_panel_on_cmds[i].dlen);
+	}
+
+	if (data_offset != len) {
+		pr_err("%s:%d, Incorrect ON command entries",
+						__func__, __LINE__);
+		goto error;
+	}
+
+	data = of_get_property(np, "qcom,panel-off-cmds", &len);
+	if (!data) {
+		pr_err("%s:%d, Unable to read OFF cmds", __func__, __LINE__);
+		goto error;
+	}
+
+	off_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL);
+	if (!off_cmds)
+		return -ENOMEM;
+
+	memcpy(off_cmds, data, len);
+
+	data_offset = 0;
+	cmd_plen = 0;
+	while ((len - data_offset) >= DT_CMD_HDR) {
+		data_offset += (DT_CMD_HDR - 1);
+		cmd_plen = off_cmds[data_offset++];
+		data_offset += cmd_plen;
+		num_of_off_cmds++;
+	}
+	if (!num_of_off_cmds) {
+		pr_err("%s:%d, No OFF cmds specified", __func__, __LINE__);
+		goto error;
+	}
+
+	dsi_panel_off_cmds = kzalloc(num_of_off_cmds
+				* sizeof(struct dsi_cmd_desc),
+					GFP_KERNEL);
+	if (!dsi_panel_off_cmds)
+		return -ENOMEM;
+
+	data_offset = 0;
+	for (i = 0; i < num_of_off_cmds; i++) {
+		dsi_panel_off_cmds[i].dtype = off_cmds[data_offset++];
+		dsi_panel_off_cmds[i].last = off_cmds[data_offset++];
+		dsi_panel_off_cmds[i].vc = off_cmds[data_offset++];
+		dsi_panel_off_cmds[i].ack = off_cmds[data_offset++];
+		dsi_panel_off_cmds[i].wait = off_cmds[data_offset++];
+		dsi_panel_off_cmds[i].dlen = off_cmds[data_offset++];
+		dsi_panel_off_cmds[i].payload = &off_cmds[data_offset];
+		data_offset += (dsi_panel_off_cmds[i].dlen);
+	}
+
+	if (data_offset != len) {
+		pr_err("%s:%d, Incorrect OFF command entries",
+						__func__, __LINE__);
+		goto error;
+	}
+
+	return 0;
+error:
+	kfree(dsi_panel_on_cmds);
+	kfree(dsi_panel_off_cmds);
+	kfree(on_cmds);
+	kfree(off_cmds);
+
+	return -EINVAL;
+}
+
+static int __devinit mdss_dsi_panel_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct mdss_panel_common_pdata *vendor_pdata = NULL;
+	static const char *panel_name;
+
+	if (pdev->dev.parent == NULL) {
+		pr_err("%s: parent device missing\n", __func__);
+		return -ENODEV;
+	}
+
+	pr_debug("%s:%d, debug info id=%d", __func__, __LINE__, pdev->id);
+	if (!pdev->dev.of_node)
+		return -ENODEV;
+
+	panel_name = of_get_property(pdev->dev.of_node, "label", NULL);
+	if (!panel_name)
+		pr_info("%s:%d, panel name not specified\n",
+						__func__, __LINE__);
+	else
+		pr_info("%s: Panel Name = %s\n", __func__, panel_name);
+
+	vendor_pdata = devm_kzalloc(&pdev->dev,
+			sizeof(*vendor_pdata), GFP_KERNEL);
+	if (!vendor_pdata)
+		return -ENOMEM;
+
+	rc = mdss_panel_parse_dt(pdev, vendor_pdata);
+	if (rc) {
+		devm_kfree(&pdev->dev, vendor_pdata);
+		vendor_pdata = NULL;
+		return rc;
+	}
+	vendor_pdata->on = mdss_dsi_panel_on;
+	vendor_pdata->off = mdss_dsi_panel_off;
+
+	rc = dsi_panel_device_register(pdev, vendor_pdata);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+static const struct of_device_id mdss_dsi_panel_match[] = {
+	{.compatible = "qcom,mdss-dsi-panel"},
+	{}
+};
+
+static struct platform_driver this_driver = {
+	.probe  = mdss_dsi_panel_probe,
+	.driver = {
+		.name   = "dsi_panel",
+		.of_match_table = mdss_dsi_panel_match,
+	},
+};
+
+static int __init mdss_dsi_panel_init(void)
+{
+	mdss_dsi_buf_alloc(&dsi_panel_tx_buf, DSI_BUF_SIZE);
+	mdss_dsi_buf_alloc(&dsi_panel_rx_buf, DSI_BUF_SIZE);
+
+	return platform_driver_register(&this_driver);
+}
+module_init(mdss_dsi_panel_init);
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index ee086ad..7efca07 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -276,9 +276,8 @@
 	if ((!mfd) || (mfd->key != MFD_KEY))
 		return 0;
 
-	/*
-	 * suspend this channel
-	 */
+	pr_debug("mdss_fb suspend index=%d\n", mfd->index);
+
 	mfd->suspend.op_enable = mfd->op_enable;
 	mfd->suspend.panel_power_on = mfd->panel_power_on;
 
@@ -295,7 +294,6 @@
 	return 0;
 }
 
-#if defined(CONFIG_PM)
 static int mdss_fb_resume_sub(struct msm_fb_data_type *mfd)
 {
 	int ret = 0;
@@ -303,6 +301,8 @@
 	if ((!mfd) || (mfd->key != MFD_KEY))
 		return 0;
 
+	pr_debug("mdss_fb resume index=%d\n", mfd->index);
+
 	/* resume state var recover */
 	mfd->op_enable = mfd->suspend.op_enable;
 
@@ -316,59 +316,43 @@
 	return ret;
 }
 
-static int mdss_fb_suspend(struct platform_device *pdev, pm_message_t state)
+int mdss_fb_suspend_all(void)
 {
-	struct msm_fb_data_type *mfd;
-	int ret = 0;
-
-	pr_debug("mdss_fb_suspend\n");
-
-	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
-
-	if ((!mfd) || (mfd->key != MFD_KEY))
-		return 0;
-
+	struct fb_info *fbi;
+	int ret, i;
+	int result = 0;
 	console_lock();
-	fb_set_suspend(mfd->fbi, FBINFO_STATE_SUSPENDED);
+	for (i = 0; i < fbi_list_index; i++) {
+		fbi = fbi_list[i];
+		fb_set_suspend(fbi, FBINFO_STATE_SUSPENDED);
 
-	ret = mdss_fb_suspend_sub(mfd);
-	if (ret != 0) {
-		pr_err("failed to suspend! %d\n", ret);
-		fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING);
-	} else {
-		pdev->dev.power.power_state = state;
+		ret = mdss_fb_suspend_sub(fbi->par);
+		if (ret != 0) {
+			fb_set_suspend(fbi, FBINFO_STATE_RUNNING);
+			result = ret;
+		}
 	}
-
 	console_unlock();
-	return ret;
+	return result;
 }
 
-static int mdss_fb_resume(struct platform_device *pdev)
+int mdss_fb_resume_all(void)
 {
-	/* This resume function is called when interrupt is enabled.
-	 */
-	int ret = 0;
-	struct msm_fb_data_type *mfd;
-
-	pr_debug("mdss_fb_resume\n");
-
-	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
-
-	if ((!mfd) || (mfd->key != MFD_KEY))
-		return 0;
+	struct fb_info *fbi;
+	int ret, i;
+	int result = 0;
 
 	console_lock();
-	ret = mdss_fb_resume_sub(mfd);
-	pdev->dev.power.power_state = PMSG_ON;
-	fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING);
-	console_unlock();
+	for (i = 0; i < fbi_list_index; i++) {
+		fbi = fbi_list[i];
 
-	return ret;
+		ret = mdss_fb_resume_sub(fbi->par);
+		if (ret == 0)
+			fb_set_suspend(fbi, FBINFO_STATE_RUNNING);
+	}
+	console_unlock();
+	return result;
 }
-#else
-#define mdss_fb_suspend NULL
-#define mdss_fb_resume NULL
-#endif
 
 #if defined(CONFIG_PM) && defined(CONFIG_SUSPEND)
 static int mdss_fb_ext_suspend(struct device *dev)
@@ -413,9 +397,6 @@
 static struct platform_driver mdss_fb_driver = {
 	.probe = mdss_fb_probe,
 	.remove = mdss_fb_remove,
-	.suspend = mdss_fb_suspend,
-	.resume = mdss_fb_resume,
-	.shutdown = NULL,
 	.driver = {
 		.name = "mdss_fb",
 		.pm = &mdss_fb_dev_pm_ops,
@@ -611,11 +592,27 @@
 	size *= mfd->fb_page;
 
 	if (mfd->index == 0) {
-		virt = dma_alloc_coherent(NULL, size, (dma_addr_t *) &phys,
-				GFP_KERNEL);
-		if (!virt) {
-			pr_err("unable to alloc fb memory size=%u\n", size);
-			return -ENOMEM;
+		struct ion_client *iclient = mfd->iclient;
+
+		if (iclient) {
+			mfd->ihdl = ion_alloc(iclient, size, SZ_4K,
+					 ION_HEAP(ION_CP_MM_HEAP_ID) |
+					 ION_HEAP(ION_SF_HEAP_ID));
+			if (IS_ERR_OR_NULL(mfd->ihdl)) {
+				pr_err("unable to alloc fbmem from ion (%p)\n",
+					mfd->ihdl);
+				return -ENOMEM;
+			}
+
+			virt = ion_map_kernel(iclient, mfd->ihdl, 0);
+			ion_phys(iclient, mfd->ihdl, &phys, &size);
+		} else {
+			virt = dma_alloc_coherent(NULL, size,
+					(dma_addr_t *) &phys, GFP_KERNEL);
+			if (!virt) {
+				pr_err("unable to alloc fbmem size=%u\n", size);
+				return -ENOMEM;
+			}
 		}
 
 		pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index ac6c213..3ea0ab3 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -75,6 +75,8 @@
 			   struct fb_cmap *cmap);
 	int (*do_histogram) (struct fb_info *info,
 			     struct mdp_histogram *hist);
+
+	struct ion_handle *ihdl;
 	void *cursor_buf;
 	void *cursor_buf_phys;
 
@@ -97,4 +99,6 @@
 int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num);
 void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl);
 void mdss_fb_update_backlight(struct msm_fb_data_type *mfd);
+int mdss_fb_suspend_all(void);
+int mdss_fb_resume_all(void);
 #endif /* MDSS_FB_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 46e49da..c267a78 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -74,30 +74,18 @@
 	MDSS_MDP_MIXER_TYPE_WRITEBACK,
 };
 
-#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \
-	{ \
+#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val)		\
+	{						\
 		.src = MSM_BUS_MASTER_MDP_PORT0,	\
 		.dst = MSM_BUS_SLAVE_EBI_CH0,		\
 		.ab = (ab_val),				\
 		.ib = (ib_val),				\
 	}
 
-#define MDP_BUS_VECTOR_ENTRY_NDX(n) \
-		MDP_BUS_VECTOR_ENTRY((n) * 100000000, (n) * 200000000)
-
 static struct msm_bus_vectors mdp_bus_vectors[] = {
-	MDP_BUS_VECTOR_ENTRY_NDX(0),
-	MDP_BUS_VECTOR_ENTRY_NDX(1),
-	MDP_BUS_VECTOR_ENTRY_NDX(2),
-	MDP_BUS_VECTOR_ENTRY_NDX(3),
-	MDP_BUS_VECTOR_ENTRY_NDX(4),
-	MDP_BUS_VECTOR_ENTRY_NDX(5),
-	MDP_BUS_VECTOR_ENTRY_NDX(6),
-	MDP_BUS_VECTOR_ENTRY_NDX(7),
-	MDP_BUS_VECTOR_ENTRY_NDX(8),
-	MDP_BUS_VECTOR_ENTRY_NDX(9),
-	MDP_BUS_VECTOR_ENTRY_NDX(10),
-	MDP_BUS_VECTOR_ENTRY(200000000, 200000000)
+	MDP_BUS_VECTOR_ENTRY(0, 0),
+	MDP_BUS_VECTOR_ENTRY(SZ_128M, SZ_256M),
+	MDP_BUS_VECTOR_ENTRY(SZ_256M, SZ_512M),
 };
 static struct msm_bus_paths mdp_bus_usecases[ARRAY_SIZE(mdp_bus_vectors)];
 static struct msm_bus_scale_pdata mdp_bus_scale_table = {
@@ -270,34 +258,39 @@
 		msm_bus_scale_unregister_client(mdss_res->bus_hdl);
 }
 
-int mdss_mdp_bus_scale_set_min_quota(u32 quota)
+int mdss_mdp_bus_scale_set_quota(u32 ab_quota, u32 ib_quota)
 {
-	struct msm_bus_scale_pdata *bus_pdata = &mdp_bus_scale_table;
-	struct msm_bus_vectors *vect = NULL;
-	int lvl;
+	static int current_bus_idx;
+	int bus_idx;
 
 	if (mdss_res->bus_hdl < 1) {
 		pr_err("invalid bus handle %d\n", mdss_res->bus_hdl);
 		return -EINVAL;
 	}
 
-	for (lvl = 0; lvl < bus_pdata->num_usecases; lvl++) {
-		if (bus_pdata->usecase[lvl].num_paths) {
-			vect = &bus_pdata->usecase[lvl].vectors[0];
-			if (vect->ab >= quota) {
-				pr_debug("lvl=%d quota=%u ab=%u\n", lvl, quota,
-						vect->ab);
-				break;
-			}
+	if ((ab_quota | ib_quota) == 0) {
+		bus_idx = 0;
+	} else {
+		int num_cases = mdp_bus_scale_table.num_usecases;
+		struct msm_bus_vectors *vect = NULL;
+
+		bus_idx = (current_bus_idx % (num_cases - 1)) + 1;
+
+		vect = mdp_bus_scale_table.usecase[current_bus_idx].vectors;
+		if ((ab_quota == vect->ab) && (ib_quota == vect->ib)) {
+			pr_debug("skip bus scaling, no change in vectors\n");
+			return 0;
 		}
-	}
 
-	if (lvl == bus_pdata->num_usecases) {
-		pr_warn("cannot match quota=%u try with max level\n", quota);
-		lvl--;
-	}
+		vect = mdp_bus_scale_table.usecase[bus_idx].vectors;
+		vect->ab = ab_quota;
+		vect->ib = ib_quota;
 
-	return msm_bus_scale_client_update_request(mdss_res->bus_hdl, lvl);
+		pr_debug("bus scale idx=%d ab=%u ib=%u\n", bus_idx,
+				vect->ab, vect->ib);
+	}
+	current_bus_idx = bus_idx;
+	return msm_bus_scale_client_update_request(mdss_res->bus_hdl, bus_idx);
 }
 
 static inline u32 mdss_mdp_irq_mask(u32 intr_type, u32 intf_num)
@@ -427,6 +420,8 @@
 				pr_debug("mdp clk rate=%lu\n", clk_rate);
 		}
 		mutex_unlock(&mdp_clk_lock);
+	} else {
+		pr_err("mdp src clk not setup properly\n");
 	}
 }
 
@@ -466,7 +461,7 @@
 
 static void mdss_mdp_clk_ctrl_workqueue_handler(struct work_struct *work)
 {
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_MASTER_OFF, false);
 }
 
 void mdss_mdp_clk_ctrl(int enable, int isr)
@@ -485,13 +480,19 @@
 	 */
 	WARN_ON(isr == true && enable);
 
-	if (enable) {
+	if (enable == MDP_BLOCK_POWER_ON) {
 		atomic_inc(&clk_ref);
 	} else if (!atomic_add_unless(&clk_ref, -1, 0)) {
-		pr_debug("master power-off req\n");
-		force_off = 1;
+		if (enable == MDP_BLOCK_MASTER_OFF) {
+			pr_debug("master power-off req\n");
+			force_off = 1;
+		} else {
+			WARN(1, "too many mdp clock off call\n");
+		}
 	}
 
+	WARN_ON(enable == MDP_BLOCK_MASTER_OFF && !force_off);
+
 	if (isr) {
 		/* if it's power off send workqueue to turn off clocks */
 		if (mdss_res->clk_ena && !atomic_read(&clk_ref))
@@ -561,6 +562,7 @@
 		goto error;
 	}
 	regulator_enable(mdss_res->fs);
+	mdss_res->fs_ena = true;
 
 	if (mdss_mdp_irq_clk_register(pdev, "bus_clk", MDSS_CLK_AXI) ||
 	    mdss_mdp_irq_clk_register(pdev, "iface_clk", MDSS_CLK_AHB) ||
@@ -736,7 +738,7 @@
 
 	flush_workqueue(mdss_res->clk_ctrl_wq);
 
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_MASTER_OFF, false);
 
 	mutex_lock(&mdp_suspend_mutex);
 	mdss_res->suspend = true;
@@ -745,24 +747,38 @@
 
 static int mdss_mdp_suspend(struct platform_device *pdev, pm_message_t state)
 {
-	if (pdev->id == 0) {
-		mdss_mdp_suspend_sub();
-		if (mdss_res->clk_ena) {
-			pr_err("MDP suspend failed\n");
-			return -EBUSY;
-		}
-		mdss_mdp_footswitch_ctrl(false);
+	int ret;
+	pr_debug("display suspend");
+
+	ret = mdss_fb_suspend_all();
+	if (IS_ERR_VALUE(ret)) {
+		pr_err("Unable to suspend all fb panels (%d)\n", ret);
+		return ret;
 	}
+	mdss_mdp_suspend_sub();
+	if (mdss_res->clk_ena) {
+		pr_err("MDP suspend failed\n");
+		return -EBUSY;
+	}
+	mdss_mdp_footswitch_ctrl(false);
+
 	return 0;
 }
 
 static int mdss_mdp_resume(struct platform_device *pdev)
 {
+	int ret = 0;
+
+	pr_debug("resume display");
+
 	mdss_mdp_footswitch_ctrl(true);
 	mutex_lock(&mdp_suspend_mutex);
 	mdss_res->suspend = false;
 	mutex_unlock(&mdp_suspend_mutex);
-	return 0;
+	ret = mdss_fb_resume_all();
+	if (IS_ERR_VALUE(ret))
+		pr_err("Unable to resume all fb panels (%d)\n", ret);
+	return ret;
 }
 #else
 #define mdss_mdp_suspend NULL
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 4489fbb..776bf8b 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -61,8 +61,9 @@
 #endif
 
 enum mdss_mdp_block_power_state {
-	MDP_BLOCK_POWER_OFF,
-	MDP_BLOCK_POWER_ON
+	MDP_BLOCK_MASTER_OFF = -1,
+	MDP_BLOCK_POWER_OFF = 0,
+	MDP_BLOCK_POWER_ON = 1,
 };
 
 enum mdss_mdp_mixer_type {
@@ -118,7 +119,10 @@
 	u16 height;
 	u32 dst_format;
 
+	u32 bus_ab_quota;
+	u32 bus_ib_quota;
 	u32 bus_quota;
+	u32 clk_rate;
 
 	struct msm_fb_data_type *mfd;
 	struct mdss_mdp_mixer *mixer_left;
@@ -144,8 +148,6 @@
 	u8 cursor_enabled;
 	u8 rotator_mode;
 
-	u32 bus_quota;
-
 	struct mdss_mdp_ctl *ctl;
 	struct mdss_mdp_pipe *stage_pipe[MDSS_MDP_MAX_STAGE];
 };
@@ -231,7 +233,6 @@
 	struct mdss_mdp_format_params *src_fmt;
 	struct mdss_mdp_plane_sizes src_planes;
 
-	u32 bus_quota;
 	u8 mixer_stage;
 	u8 is_fg;
 	u8 alpha;
@@ -273,7 +274,7 @@
 int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
 			       void (*fnc_ptr)(void *), void *arg);
 
-int mdss_mdp_bus_scale_set_min_quota(u32 quota);
+int mdss_mdp_bus_scale_set_quota(u32 ab_quota, u32 ib_quota);
 void mdss_mdp_set_clk_rate(unsigned long min_clk_rate);
 unsigned long mdss_mdp_get_clk_rate(u32 clk_idx);
 int mdss_mdp_vsync_clk_enable(int enable);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index c80527d9..d29ecd6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -20,122 +20,177 @@
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 
+/* 1.10 bus fudge factor */
+#define MDSS_MDP_BUS_FUDGE_FACTOR(val) ALIGN((((val) * 11) / 10), SZ_16M)
+/* 1.25 clock fudge factor */
+#define MDSS_MDP_CLK_FUDGE_FACTOR(val) (((val) * 5) / 4)
+
 enum {
-	MDSS_MDP_BUS_UPDATE_SKIP,
-	MDSS_MDP_BUS_UPDATE_EARLY,
-	MDSS_MDP_BUS_UPDATE_LATE,
+	MDSS_MDP_PERF_UPDATE_SKIP,
+	MDSS_MDP_PERF_UPDATE_EARLY,
+	MDSS_MDP_PERF_UPDATE_LATE,
 };
 
+#define MDSS_MDP_PERF_UPDATE_CLK BIT(0)
+#define MDSS_MDP_PERF_UPDATE_BUS BIT(1)
+#define MDSS_MDP_PERF_UPDATE_ALL -1
+
 static DEFINE_MUTEX(mdss_mdp_ctl_lock);
 static struct mdss_mdp_ctl mdss_mdp_ctl_list[MDSS_MDP_MAX_CTL];
 static struct mdss_mdp_mixer mdss_mdp_mixer_list[MDSS_MDP_MAX_LAYERMIXER];
 
-static int mdss_mdp_ctl_update_clk_rate(void)
+static int mdss_mdp_ctl_perf_commit(u32 flags)
 {
 	struct mdss_mdp_ctl *ctl;
 	int cnum;
-	unsigned long clk_rate = MDP_CLK_DEFAULT_RATE;
+	unsigned long clk_rate = 0;
+	u32 bus_ab_quota = 0, bus_ib_quota = 0;
+
+	if (!flags) {
+		pr_err("nothing to update\n");
+		return -EINVAL;
+	}
 
 	mutex_lock(&mdss_mdp_ctl_lock);
 	for (cnum = 0; cnum < MDSS_MDP_MAX_CTL; cnum++) {
 		ctl = &mdss_mdp_ctl_list[cnum];
-		if (ctl->power_on && ctl->mfd) {
-			unsigned long tmp;
-			pr_debug("ctl=%d pclk_rate=%u\n", ctl->num,
-					ctl->mfd->panel_info.clk_rate);
-			tmp = (ctl->mfd->panel_info.clk_rate * 23) / 20;
-			if (tmp > clk_rate)
-				clk_rate = tmp;
+		if (ctl->power_on) {
+			bus_ab_quota += ctl->bus_ab_quota;
+			bus_ib_quota += ctl->bus_ib_quota;
+
+			if (ctl->clk_rate > clk_rate)
+				clk_rate = ctl->clk_rate;
 		}
 	}
-	mdss_mdp_set_clk_rate(clk_rate);
-	mutex_unlock(&mdss_mdp_ctl_lock);
-
-	return 0;
-}
-
-static int mdss_mdp_ctl_update_bus_scale(void)
-{
-	struct mdss_mdp_ctl *ctl;
-	int cnum;
-	u32 bus_quota = 0;
-
-	mutex_lock(&mdss_mdp_ctl_lock);
-	for (cnum = 0; cnum < MDSS_MDP_MAX_CTL; cnum++) {
-		ctl = &mdss_mdp_ctl_list[cnum];
-		if (ctl->power_on)
-			bus_quota += ctl->bus_quota;
+	if (flags & MDSS_MDP_PERF_UPDATE_BUS) {
+		bus_ab_quota = MDSS_MDP_BUS_FUDGE_FACTOR(bus_ab_quota);
+		bus_ib_quota = MDSS_MDP_BUS_FUDGE_FACTOR(bus_ib_quota);
+		mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota);
 	}
-	mdss_mdp_bus_scale_set_min_quota(bus_quota);
+	if (flags & MDSS_MDP_PERF_UPDATE_CLK) {
+		clk_rate = MDSS_MDP_CLK_FUDGE_FACTOR(clk_rate);
+		pr_debug("update clk rate = %lu\n", clk_rate);
+		mdss_mdp_set_clk_rate(clk_rate);
+	}
 	mutex_unlock(&mdss_mdp_ctl_lock);
 
 	return 0;
 }
 
-static void mdss_mdp_bus_update_pipe_quota(struct mdss_mdp_pipe *pipe)
-{
-	u32 quota;
-
-	quota = pipe->img_width * pipe->img_height * 60 * pipe->src_fmt->bpp;
-	quota *= 5 / 4; /* 1.25 factor */
-
-	pr_debug("pipe=%d quota old=%u new=%u\n", pipe->num,
-		   pipe->bus_quota, quota);
-	pipe->bus_quota = quota;
-}
-
-static int mdss_mdp_bus_update_mixer_quota(struct mdss_mdp_mixer *mixer)
+static void mdss_mdp_perf_mixer_update(struct mdss_mdp_mixer *mixer,
+				       u32 *bus_ab_quota, u32 *bus_ib_quota,
+				       u32 *clk_rate)
 {
 	struct mdss_mdp_pipe *pipe;
-	u32 quota, stage;
+	const int fps = 60;
+	u32 quota, rate;
+	u32 v_total, v_active;
+	int i;
 
-	if (!mixer)
-		return 0;
+	*bus_ab_quota = 0;
+	*bus_ib_quota = 0;
+	*clk_rate = 0;
 
-	quota = 0;
-	for (stage = 0; stage < MDSS_MDP_MAX_STAGE; stage++) {
-		pipe = mixer->stage_pipe[stage];
+	if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
+		struct mdss_panel_info *pinfo = &mixer->ctl->mfd->panel_info;
+		v_total = (pinfo->yres + pinfo->lcdc.v_back_porch +
+			pinfo->lcdc.v_front_porch + pinfo->lcdc.v_pulse_width);
+		v_active = pinfo->yres;
+	} else if (mixer->rotator_mode) {
+		pipe = mixer->stage_pipe[0]; /* rotator pipe */
+		v_total = pipe->flags & MDP_ROT_90 ? pipe->dst.w : pipe->dst.h;
+		v_active = v_total;
+	} else {
+		v_total = mixer->height;
+		v_active = v_total;
+	}
+
+	for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) {
+		u32 ib_quota;
+		pipe = mixer->stage_pipe[i];
 		if (pipe == NULL)
 			continue;
 
-		quota += pipe->bus_quota;
+		quota = fps * pipe->src.w * pipe->src.h;
+		if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420)
+			quota = (quota * 3) / 2;
+		else
+			quota *= pipe->src_fmt->bpp;
+
+		if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF)
+			quota = (quota / v_active) * v_total;
+		else
+			quota *= 2; /* bus read + write */
+
+		rate = pipe->dst.w;
+		if (pipe->src.h > pipe->dst.h) {
+			rate = (rate * pipe->src.h) / pipe->dst.h;
+			ib_quota = (quota / pipe->dst.h) * pipe->src.h;
+		} else {
+			ib_quota = quota;
+		}
+		rate *= v_total * fps;
+		if (mixer->rotator_mode)
+			rate /= 4; /* block mode fetch at 4 pix/clk */
+
+		*bus_ab_quota += quota;
+		*bus_ib_quota += ib_quota;
+		if (rate > *clk_rate)
+			*clk_rate = rate;
+
+		pr_debug("mixer=%d pnum=%d clk_rate=%u bus ab=%u ib=%u\n",
+			 mixer->num, pipe->num, rate, quota, ib_quota);
 	}
 
-	pr_debug("mixer=%d quota old=%u new=%u\n", mixer->num,
-		   mixer->bus_quota, quota);
-
-	if (quota != mixer->bus_quota) {
-		mixer->bus_quota = quota;
-		return 1;
-	}
-
-	return 0;
+	pr_debug("final mixer=%d clk_rate=%u bus ab=%u ib=%u\n", mixer->num,
+		 *clk_rate, *bus_ab_quota, *bus_ib_quota);
 }
 
-static int mdss_mdp_bus_update_ctl_quota(struct mdss_mdp_ctl *ctl)
+static int mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl, u32 *flags)
 {
-	int ret = MDSS_MDP_BUS_UPDATE_SKIP;
+	int ret = MDSS_MDP_PERF_UPDATE_SKIP;
+	u32 clk_rate, ab_quota, ib_quota;
+	u32 max_clk_rate = 0, total_ab_quota = 0, total_ib_quota = 0;
 
-	if (mdss_mdp_bus_update_mixer_quota(ctl->mixer_left) ||
-			mdss_mdp_bus_update_mixer_quota(ctl->mixer_right)) {
-		u32 quota = 0;
+	if (ctl->mixer_left) {
+		mdss_mdp_perf_mixer_update(ctl->mixer_left, &ab_quota,
+					   &ib_quota, &clk_rate);
+		total_ab_quota += ab_quota;
+		total_ib_quota += ib_quota;
+		max_clk_rate = clk_rate;
+	}
 
-		if (ctl->mixer_left)
-			quota += ctl->mixer_left->bus_quota;
-		if (ctl->mixer_right)
-			quota += ctl->mixer_right->bus_quota;
+	if (ctl->mixer_right) {
+		mdss_mdp_perf_mixer_update(ctl->mixer_right, &ab_quota,
+					   &ib_quota, &clk_rate);
+		total_ab_quota += ab_quota;
+		total_ib_quota += ib_quota;
+		if (clk_rate > max_clk_rate)
+			max_clk_rate = clk_rate;
+	}
 
-		pr_debug("ctl=%d quota old=%u new=%u\n",
-			   ctl->num, ctl->bus_quota, quota);
+	*flags = 0;
 
-		if (quota != ctl->bus_quota) {
-			if (quota > ctl->bus_quota)
-				ret = MDSS_MDP_BUS_UPDATE_EARLY;
+	if (max_clk_rate != ctl->clk_rate) {
+		if (max_clk_rate > ctl->clk_rate)
+			ret = MDSS_MDP_PERF_UPDATE_EARLY;
+		else
+			ret = MDSS_MDP_PERF_UPDATE_LATE;
+		ctl->clk_rate = max_clk_rate;
+		*flags |= MDSS_MDP_PERF_UPDATE_CLK;
+	}
+
+	if ((total_ab_quota != ctl->bus_ab_quota) ||
+			(total_ib_quota != ctl->bus_ib_quota)) {
+		if (ret == MDSS_MDP_PERF_UPDATE_SKIP) {
+			if (total_ib_quota > ctl->bus_ib_quota)
+				ret = MDSS_MDP_PERF_UPDATE_EARLY;
 			else
-				ret = MDSS_MDP_BUS_UPDATE_LATE;
-
-			ctl->bus_quota = quota;
+				ret = MDSS_MDP_PERF_UPDATE_LATE;
 		}
+		ctl->bus_ab_quota = total_ab_quota;
+		ctl->bus_ib_quota = total_ib_quota;
+		*flags |= MDSS_MDP_PERF_UPDATE_BUS;
 	}
 
 	return ret;
@@ -261,6 +316,7 @@
 	mixer->ctl = ctl;
 
 	ctl->start_fnc = mdss_mdp_writeback_start;
+	ctl->power_on = true;
 
 	if (ctl->start_fnc)
 		ctl->start_fnc(ctl);
@@ -442,7 +498,6 @@
 	mutex_lock(&ctl->lock);
 
 	ctl->power_on = true;
-	mdss_mdp_ctl_update_clk_rate();
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	if (ctl->start_fnc)
@@ -531,8 +586,7 @@
 
 	ctl->play_cnt = 0;
 
-	mdss_mdp_ctl_update_bus_scale();
-	mdss_mdp_ctl_update_clk_rate();
+	mdss_mdp_ctl_perf_commit(MDSS_MDP_PERF_UPDATE_ALL);
 
 	mutex_unlock(&ctl->lock);
 
@@ -705,7 +759,6 @@
 	if (params_changed) {
 		mixer->params_changed++;
 		mixer->stage_pipe[pipe->mixer_stage] = pipe;
-		mdss_mdp_bus_update_pipe_quota(pipe);
 	}
 
 	if (pipe->type == MDSS_MDP_PIPE_TYPE_DMA)
@@ -764,14 +817,18 @@
 {
 	int mixer1_changed, mixer2_changed;
 	int ret = 0;
-	int bus_update = MDSS_MDP_BUS_UPDATE_SKIP;
+	int perf_update = MDSS_MDP_PERF_UPDATE_SKIP;
+	u32 update_flags = 0;
 
 	if (!ctl) {
 		pr_err("display function not set\n");
 		return -ENODEV;
 	}
 
-	pr_debug("commit ctl=%d\n", ctl->num);
+	if (!ctl->power_on)
+		return 0;
+
+	pr_debug("commit ctl=%d play_cnt=%d\n", ctl->num, ctl->play_cnt);
 
 	if (mutex_lock_interruptible(&ctl->lock))
 		return -EINTR;
@@ -781,7 +838,7 @@
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	if (mixer1_changed || mixer2_changed) {
-		bus_update = mdss_mdp_bus_update_ctl_quota(ctl);
+		perf_update = mdss_mdp_ctl_perf_update(ctl, &update_flags);
 
 		if (ctl->prepare_fnc)
 			ret = ctl->prepare_fnc(ctl, arg);
@@ -790,8 +847,8 @@
 			goto done;
 		}
 
-		if (bus_update == MDSS_MDP_BUS_UPDATE_EARLY)
-			mdss_mdp_ctl_update_bus_scale();
+		if (perf_update == MDSS_MDP_PERF_UPDATE_EARLY)
+			mdss_mdp_ctl_perf_commit(update_flags);
 
 		if (mixer1_changed)
 			mdss_mdp_mixer_update(ctl->mixer_left);
@@ -813,8 +870,8 @@
 
 	ctl->play_cnt++;
 
-	if (bus_update == MDSS_MDP_BUS_UPDATE_LATE)
-		mdss_mdp_ctl_update_bus_scale();
+	if (perf_update == MDSS_MDP_PERF_UPDATE_LATE)
+		mdss_mdp_ctl_perf_commit(update_flags);
 
 done:
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 4ca1dce..8825cc6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -375,6 +375,7 @@
 #define MDSS_MDP_REG_INTF_FRAME_LINE_COUNT_EN		0x0A8
 #define MDSS_MDP_REG_INTF_FRAME_COUNT			0x0AC
 #define MDSS_MDP_REG_INTF_LINE_COUNT			0x0B0
+#define MDSS_MDP_PANEL_FORMAT_RGB888			0x213F
 
 enum mdss_mdp_pingpong_index {
 	MDSS_MDP_PINGPONG0,
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 21ef290..bc64d2e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -135,6 +135,8 @@
 			   p->hsync_skew);
 	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_POLARITY_CTL,
 			   polarity_ctl);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_PANEL_FORMAT,
+			   MDSS_MDP_PANEL_FORMAT_RGB888);
 
 	return 0;
 }
@@ -297,14 +299,14 @@
 	itp.underflow_clr = pinfo->lcdc.underflow_clr;
 	itp.hsync_skew = pinfo->lcdc.hsync_skew;
 
-	itp.xres = fbi->var.xres;
-	itp.yres = fbi->var.yres;
-	itp.h_back_porch = fbi->var.left_margin;
-	itp.h_front_porch = fbi->var.right_margin;
-	itp.v_back_porch = fbi->var.upper_margin;
-	itp.v_front_porch = fbi->var.lower_margin;
-	itp.hsync_pulse_width = fbi->var.hsync_len;
-	itp.vsync_pulse_width = fbi->var.vsync_len;
+	itp.xres =  pinfo->xres;
+	itp.yres = pinfo->yres;
+	itp.h_back_porch =  pinfo->lcdc.h_back_porch;
+	itp.h_front_porch =  pinfo->lcdc.h_front_porch;
+	itp.v_back_porch =  pinfo->lcdc.v_back_porch;
+	itp.v_front_porch = pinfo->lcdc.v_front_porch;
+	itp.hsync_pulse_width = pinfo->lcdc.h_pulse_width;
+	itp.vsync_pulse_width = pinfo->lcdc.v_pulse_width;
 
 	if (mdss_mdp_video_timegen_setup(ctl, &itp)) {
 		pr_err("unable to get timing parameters\n");
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index d9a148e..9a8260f 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -630,7 +630,8 @@
 		return -ENODEV;
 	}
 
-	pr_debug("pnum=%x mixer=%d\n", pipe->num, pipe->mixer->num);
+	pr_debug("pnum=%x mixer=%d play_cnt=%u\n", pipe->num,
+		 pipe->mixer->num, pipe->play_cnt);
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 0411d8e..3ec3a5d 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -167,6 +167,7 @@
 struct mdss_panel_data {
 	struct mdss_panel_info panel_info;
 	void (*set_backlight) (u32 bl_level);
+	unsigned char *dsi_base;
 
 	/* function entry chain */
 	int (*on) (struct mdss_panel_data *pdata);
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
new file mode 100644
index 0000000..c766ec7
--- /dev/null
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -0,0 +1,199 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/clk.h>
+#include <mach/msm_iomap.h>
+
+#include "mdss_dsi.h"
+
+#define SW_RESET BIT(2)
+#define SW_RESET_PLL BIT(0)
+#define PWRDN_B BIT(7)
+
+static struct dsi_clk_desc dsi_pclk;
+
+static struct clk *dsi_byte_div_clk;
+static struct clk *dsi_esc_clk;
+
+int mdss_dsi_clk_on;
+
+int mdss_dsi_clk_init(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+
+	dsi_byte_div_clk = clk_get(dev, "byte_clk");
+	if (IS_ERR(dsi_byte_div_clk)) {
+		pr_err("can't find dsi_byte_div_clk\n");
+		dsi_byte_div_clk = NULL;
+		goto mdss_dsi_clk_err;
+	}
+
+	dsi_esc_clk = clk_get(dev, "core_clk");
+	if (IS_ERR(dsi_esc_clk)) {
+		printk(KERN_ERR "can't find dsi_esc_clk\n");
+		dsi_esc_clk = NULL;
+		goto mdss_dsi_clk_err;
+	}
+
+	return 0;
+
+mdss_dsi_clk_err:
+	mdss_dsi_clk_deinit(dev);
+	return -EPERM;
+}
+
+void mdss_dsi_clk_deinit(struct device *dev)
+{
+	if (dsi_byte_div_clk)
+		clk_put(dsi_byte_div_clk);
+	if (dsi_esc_clk)
+		clk_put(dsi_esc_clk);
+}
+
+#define PREF_DIV_RATIO 27
+struct dsiphy_pll_divider_config pll_divider_config;
+
+int mdss_dsi_clk_div_config(u8 bpp, u8 lanes,
+			    u32 *expected_dsi_pclk)
+{
+	u32 fb_divider, rate, vco;
+	u32 div_ratio = 0;
+	u32 pll_analog_posDiv = 1;
+	struct dsi_clk_mnd_table const *mnd_entry = mnd_table;
+	if (pll_divider_config.clk_rate == 0)
+		pll_divider_config.clk_rate = 454000000;
+
+	rate = (pll_divider_config.clk_rate / 2)
+			 / 1000000; /* Half Bit Clock In Mhz */
+
+	if (rate < 43) {
+		vco = rate * 16;
+		div_ratio = 16;
+		pll_analog_posDiv = 8;
+	} else if (rate < 85) {
+		vco = rate * 8;
+		div_ratio = 8;
+		pll_analog_posDiv = 4;
+	} else if (rate < 170) {
+		vco = rate * 4;
+		div_ratio = 4;
+		pll_analog_posDiv = 2;
+	} else if (rate < 340) {
+		vco = rate * 2;
+		div_ratio = 2;
+		pll_analog_posDiv = 1;
+	} else {
+		/* DSI PLL Direct path configuration */
+		vco = rate * 1;
+		div_ratio = 1;
+		pll_analog_posDiv = 1;
+	}
+
+	/* find the mnd settings from mnd_table entry */
+	for (; mnd_entry != mnd_table + ARRAY_SIZE(mnd_table); ++mnd_entry) {
+		if (((mnd_entry->lanes) == lanes) &&
+			((mnd_entry->bpp) == bpp))
+			break;
+	}
+
+	if (mnd_entry == mnd_table + ARRAY_SIZE(mnd_table)) {
+		pr_err("%s: requested Lanes, %u & BPP, %u, not supported\n",
+			__func__, lanes, bpp);
+		return -EINVAL;
+	}
+	fb_divider = ((vco * PREF_DIV_RATIO) / 27);
+	pll_divider_config.fb_divider = fb_divider;
+	pll_divider_config.ref_divider_ratio = PREF_DIV_RATIO;
+	pll_divider_config.bit_clk_divider = div_ratio;
+	pll_divider_config.byte_clk_divider =
+			pll_divider_config.bit_clk_divider * 8;
+	pll_divider_config.analog_posDiv = pll_analog_posDiv;
+	pll_divider_config.digital_posDiv =
+			(mnd_entry->pll_digital_posDiv) * div_ratio;
+
+	if ((mnd_entry->pclk_d == 0)
+		|| (mnd_entry->pclk_m == 1)) {
+		dsi_pclk.mnd_mode = 0;
+		dsi_pclk.src = 0x3;
+		dsi_pclk.pre_div_func = (mnd_entry->pclk_n - 1);
+	} else {
+		dsi_pclk.mnd_mode = 2;
+		dsi_pclk.src = 0x3;
+		dsi_pclk.m = mnd_entry->pclk_m;
+		dsi_pclk.n = mnd_entry->pclk_n;
+		dsi_pclk.d = mnd_entry->pclk_d;
+	}
+	*expected_dsi_pclk = (((pll_divider_config.clk_rate) * lanes)
+				      / (8 * bpp));
+
+	return 0;
+}
+
+void cont_splash_clk_ctrl(int enable)
+{
+	static int cont_splash_clks_enabled;
+	if (enable && !cont_splash_clks_enabled) {
+			clk_prepare_enable(dsi_byte_div_clk);
+			clk_prepare_enable(dsi_esc_clk);
+			cont_splash_clks_enabled = 1;
+	} else if (!enable && cont_splash_clks_enabled) {
+			clk_disable_unprepare(dsi_byte_div_clk);
+			clk_disable_unprepare(dsi_esc_clk);
+			cont_splash_clks_enabled = 0;
+	}
+}
+
+void mdss_dsi_prepare_clocks(void)
+{
+	clk_prepare(dsi_byte_div_clk);
+	clk_prepare(dsi_esc_clk);
+}
+
+void mdss_dsi_unprepare_clocks(void)
+{
+	clk_unprepare(dsi_esc_clk);
+	clk_unprepare(dsi_byte_div_clk);
+}
+
+void mdss_dsi_clk_enable(void)
+{
+	if (mdss_dsi_clk_on) {
+		pr_info("%s: mdss_dsi_clks already ON\n", __func__);
+		return;
+	}
+
+	if (clk_set_rate(dsi_byte_div_clk, 1) < 0)	/* divided by 1 */
+		pr_err("%s: dsi_byte_div_clk - clk_set_rate failed\n",
+					__func__);
+	if (clk_set_rate(dsi_esc_clk, 2) < 0) /* divided by 2 */
+		pr_err("%s: dsi_esc_clk - clk_set_rate failed\n",
+					__func__);
+	clk_enable(dsi_byte_div_clk);
+	clk_enable(dsi_esc_clk);
+	mdss_dsi_clk_on = 1;
+}
+
+void mdss_dsi_clk_disable(void)
+{
+	if (mdss_dsi_clk_on == 0) {
+		pr_info("%s: mdss_dsi_clks already OFF\n", __func__);
+		return;
+	}
+	clk_disable(dsi_esc_clk);
+	clk_disable(dsi_byte_div_clk);
+	mdss_dsi_clk_on = 0;
+}
diff --git a/drivers/video/msm/mipi_NT35510.c b/drivers/video/msm/mipi_NT35510.c
index 04178fa..94c24ee 100644
--- a/drivers/video/msm/mipi_NT35510.c
+++ b/drivers/video/msm/mipi_NT35510.c
@@ -482,6 +482,11 @@
 
 	mipi  = &mfd->panel_info.mipi;
 
+	if (!mfd->cont_splash_done) {
+		mfd->cont_splash_done = 1;
+		return 0;
+	}
+
 	if (mipi_nt35510_pdata && mipi_nt35510_pdata->rotate_panel)
 		rotate = mipi_nt35510_pdata->rotate_panel();
 
diff --git a/drivers/video/msm/mipi_dsi.c b/drivers/video/msm/mipi_dsi.c
index da094b3..9cff41f 100644
--- a/drivers/video/msm/mipi_dsi.c
+++ b/drivers/video/msm/mipi_dsi.c
@@ -574,8 +574,10 @@
 	if (rc)
 		goto mipi_dsi_probe_err;
 
-	if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 103300000))
+	if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 223000000)) {
+		pr_err("%s: Pixel clock not supported\n", __func__);
 		dsi_pclk_rate = 35000000;
+	}
 	mipi->dsi_pclk_rate = dsi_pclk_rate;
 
 	/*
diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c
index 4afffb0..39e2d6d 100644
--- a/drivers/video/msm/mipi_dsi_host.c
+++ b/drivers/video/msm/mipi_dsi_host.c
@@ -1151,15 +1151,11 @@
 
 	spin_lock_irqsave(&dsi_mdp_lock, flag);
 	dsi_mdp_busy = TRUE;
-	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
 	led_pwm1[1] = (unsigned char)(level);
 	tp = &dsi_tx_buf;
 	cmd = &backlight_cmd;
 	mipi_dsi_buf_init(&dsi_tx_buf);
 
-
-
 	if (tp->dmap) {
 		dma_unmap_single(&dsi_dev, tp->dmap, tp->len, DMA_TO_DEVICE);
 		tp->dmap = 0;
@@ -1180,10 +1176,6 @@
 	wmb();
 	MIPI_OUTP(MIPI_DSI_BASE + 0x08c, 0x01);	/* trigger */
 	wmb();
-
-	spin_lock_irqsave(&dsi_mdp_lock, flag);
-	dsi_mdp_busy = FALSE;
-	complete(&dsi_mdp_comp);
 	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
 }
 
@@ -1383,6 +1375,8 @@
 int mipi_dsi_cmd_dma_tx(struct dsi_buf *tp)
 {
 
+	unsigned long flags;
+
 #ifdef DSI_HOST_DEBUG
 	int i;
 	char *bp;
@@ -1396,6 +1390,7 @@
 	pr_debug("\n");
 #endif
 
+	spin_lock_irqsave(&dsi_mdp_lock, flags);
 	tp->len += 3;
 	tp->len &= ~0x03;	/* multipled by 4 */
 
@@ -1410,6 +1405,7 @@
 	wmb();
 	MIPI_OUTP(MIPI_DSI_BASE + 0x08c, 0x01);	/* trigger */
 	wmb();
+	spin_unlock_irqrestore(&dsi_mdp_lock, flags);
 
 	wait_for_completion(&dsi_dma_comp);
 
@@ -1549,8 +1545,8 @@
 
 	if (isr & DSI_INTR_CMD_DMA_DONE) {
 		mipi_dsi_mdp_stat_inc(STAT_DSI_CMD);
-		complete(&dsi_dma_comp);
 		spin_lock(&dsi_mdp_lock);
+		complete(&dsi_dma_comp);
 		dsi_ctrl_lock = FALSE;
 		mipi_dsi_disable_irq_nosync();
 		spin_unlock(&dsi_mdp_lock);
diff --git a/drivers/video/msm/msm_dss_io_7x27a.c b/drivers/video/msm/msm_dss_io_7x27a.c
index 17ee976..18e8ac5 100644
--- a/drivers/video/msm/msm_dss_io_7x27a.c
+++ b/drivers/video/msm/msm_dss_io_7x27a.c
@@ -317,6 +317,24 @@
 
 void cont_splash_clk_ctrl(int enable)
 {
+	static int cont_splash_clks_enabled;
+	if (enable && !cont_splash_clks_enabled) {
+		clk_prepare_enable(dsi_ref_clk);
+		clk_prepare_enable(mdp_dsi_pclk);
+		clk_prepare_enable(dsi_byte_div_clk);
+		clk_prepare_enable(dsi_esc_clk);
+		clk_prepare_enable(dsi_pixel_clk);
+		clk_prepare_enable(dsi_clk);
+		cont_splash_clks_enabled = 1;
+	} else if (!enable && cont_splash_clks_enabled) {
+		clk_disable_unprepare(dsi_clk);
+		clk_disable_unprepare(dsi_pixel_clk);
+		clk_disable_unprepare(dsi_esc_clk);
+		clk_disable_unprepare(dsi_byte_div_clk);
+		clk_disable_unprepare(mdp_dsi_pclk);
+		clk_disable_unprepare(dsi_ref_clk);
+		cont_splash_clks_enabled = 0;
+	}
 }
 
 void mipi_dsi_prepare_clocks(void)
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 09cbe1b..8997292 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -382,6 +382,7 @@
 	if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
 		return -ENOMEM;
 
+	vsync_cntrl.dev = mfd->fbi->dev;
 	mfd->panel_info.frame_count = 0;
 	mfd->bl_level = 0;
 	bl_scale = 1024;
@@ -1462,10 +1463,22 @@
 
 	/* cursor memory allocation */
 	if (mfd->cursor_update) {
+		unsigned long cursor_buf_iommu = 0;
 		mfd->cursor_buf = dma_alloc_coherent(NULL,
 					MDP_CURSOR_SIZE,
 					(dma_addr_t *) &mfd->cursor_buf_phys,
 					GFP_KERNEL);
+
+		msm_iommu_map_contig_buffer((unsigned long)mfd->cursor_buf_phys,
+					    DISPLAY_READ_DOMAIN,
+					    GEN_POOL,
+					    MDP_CURSOR_SIZE,
+					    SZ_4K,
+					    0,
+					    &cursor_buf_iommu);
+		if (cursor_buf_iommu)
+			mfd->cursor_buf_phys = (void *)cursor_buf_iommu;
+
 		if (!mfd->cursor_buf)
 			mfd->cursor_update = 0;
 	}
@@ -1511,7 +1524,10 @@
 	ret = 0;
 
 #ifdef CONFIG_HAS_EARLYSUSPEND
-	if (hdmi_prim_display || mfd->panel_info.type != DTV_PANEL) {
+
+	if (hdmi_prim_display ||
+	    (mfd->panel_info.type != DTV_PANEL &&
+	     mfd->panel_info.type != WRITEBACK_PANEL)) {
 		mfd->early_suspend.suspend = msmfb_early_suspend;
 		mfd->early_suspend.resume = msmfb_early_resume;
 		mfd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 2;
@@ -1784,8 +1800,7 @@
 	if (mfd->msmfb_no_update_notify_timer.function)
 		del_timer(&mfd->msmfb_no_update_notify_timer);
 
-	mfd->msmfb_no_update_notify_timer.expires =
-				jiffies + ((1000 * HZ) / 1000);
+	mfd->msmfb_no_update_notify_timer.expires = jiffies + (2 * HZ);
 	add_timer(&mfd->msmfb_no_update_notify_timer);
 	mutex_unlock(&msm_fb_notify_update_sem);
 
@@ -2833,6 +2848,27 @@
 	return 0;
 }
 
+static int msmfb_vsync_ctrl(struct fb_info *info, void __user *argp)
+{
+	int enable, ret;
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+	ret = copy_from_user(&enable, argp, sizeof(enable));
+	if (ret) {
+		pr_err("%s:msmfb_overlay_vsync ioctl failed", __func__);
+		return ret;
+	}
+
+	if (mfd->vsync_ctrl)
+		mfd->vsync_ctrl(enable);
+	else {
+		pr_err("%s: Vsync IOCTL not supported", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 #ifdef CONFIG_FB_MSM_OVERLAY
 static int msmfb_overlay_get(struct fb_info *info, void __user *p)
 {
@@ -2895,25 +2931,6 @@
 	return mdp4_overlay_unset(info, ndx);
 }
 
-static int msmfb_overlay_wait4vsync(struct fb_info *info, void __user *argp)
-{
-	int ret;
-	long long vtime;
-
-	ret = mdp4_overlay_wait4vsync(info, &vtime);
-	if (ret) {
-		pr_err("%s: ioctl failed\n", __func__);
-		return ret;
-	}
-
-	if (copy_to_user(argp, &vtime, sizeof(vtime))) {
-		pr_err("%s: copy2user failed\n", __func__);
-		return -EFAULT;
-	}
-
-	return 0;
-}
-
 static int msmfb_overlay_vsync_ctrl(struct fb_info *info, void __user *argp)
 {
 	int ret;
@@ -2972,8 +2989,7 @@
 	if (mfd->msmfb_no_update_notify_timer.function)
 		del_timer(&mfd->msmfb_no_update_notify_timer);
 
-	mfd->msmfb_no_update_notify_timer.expires =
-				jiffies + ((1000 * HZ) / 1000);
+	mfd->msmfb_no_update_notify_timer.expires = jiffies + (2 * HZ);
 	add_timer(&mfd->msmfb_no_update_notify_timer);
 	mutex_unlock(&msm_fb_notify_update_sem);
 
@@ -3345,16 +3361,6 @@
 
 	switch (cmd) {
 #ifdef CONFIG_FB_MSM_OVERLAY
-	case FBIO_WAITFORVSYNC:
-		down(&msm_fb_ioctl_ppp_sem);
-		ret = msmfb_overlay_wait4vsync(info, argp);
-		up(&msm_fb_ioctl_ppp_sem);
-		break;
-	case MSMFB_OVERLAY_VSYNC_CTRL:
-		down(&msm_fb_ioctl_ppp_sem);
-		ret = msmfb_overlay_vsync_ctrl(info, argp);
-		up(&msm_fb_ioctl_ppp_sem);
-		break;
 	case MSMFB_OVERLAY_GET:
 		down(&msm_fb_ioctl_ppp_sem);
 		ret = msmfb_overlay_get(info, argp);
@@ -3423,6 +3429,15 @@
 		ret = msmfb_overlay_ioctl_writeback_terminate(info);
 		break;
 #endif
+	case MSMFB_VSYNC_CTRL:
+	case MSMFB_OVERLAY_VSYNC_CTRL:
+		down(&msm_fb_ioctl_ppp_sem);
+		if (mdp_rev >= MDP_REV_40)
+			ret = msmfb_overlay_vsync_ctrl(info, argp);
+		else
+			ret = msmfb_vsync_ctrl(info, argp);
+		up(&msm_fb_ioctl_ppp_sem);
+		break;
 	case MSMFB_BLIT:
 		down(&msm_fb_ioctl_ppp_sem);
 		ret = msmfb_blit(info, argp);
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index 0658365..ae5acf4 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -80,6 +80,7 @@
 	DISP_TARGET dest;
 	struct fb_info *fbi;
 
+	struct device *dev;
 	boolean op_enable;
 	uint32 fb_imgType;
 	boolean sw_currently_refreshing;
@@ -134,6 +135,7 @@
 			      struct mdp_histogram_data *hist);
 	int (*start_histogram) (struct mdp_histogram_start_req *req);
 	int (*stop_histogram) (struct fb_info *info, uint32_t block);
+	void (*vsync_ctrl) (int enable);
 	void *cursor_buf;
 	void *cursor_buf_phys;
 
@@ -182,8 +184,6 @@
 	u32 ov_start;
 	u32 mem_hid;
 	u32 mdp_rev;
-	u32 use_ov0_blt, ov0_blt_state;
-	u32 use_ov1_blt, ov1_blt_state;
 	u32 writeback_state;
 	bool writeback_active_cnt;
 	int cont_splash_done;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index 22eaf4f..8ec444f 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -366,10 +366,6 @@
 			need_reconfig = ddl_check_reconfig(ddl);
 			DDL_MSG_HIGH("%s : need_reconfig = %u\n", __func__,
 				 need_reconfig);
-			if (input_vcd_frm->flags &
-				  VCD_FRAME_FLAG_EOS) {
-				need_reconfig = false;
-			}
 			if (((input_vcd_frm->flags &
 				VCD_FRAME_FLAG_CODECCONFIG) &&
 				(!(input_vcd_frm->flags &
@@ -1302,6 +1298,7 @@
 		ddl_process_decoder_metadata(ddl);
 		vidc_sm_get_aspect_ratio_info(
 			&ddl->shared_mem[ddl->command_channel],
+			decoder->codec.codec,
 			&output_vcd_frm->aspect_ratio_info);
 		ddl_context->ddl_callback(VCD_EVT_RESP_OUTPUT_DONE,
 			vcd_status, output_frame,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
index 267e924..fade821 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
@@ -217,6 +217,7 @@
 	DDL_METADATA_ALIGNSIZE(suffix);
 	decoder->suffix = suffix;
 	output_buf_req->sz += suffix;
+	decoder->meta_data_offset = 0;
 	DDL_MSG_LOW("metadata output buf size : %d", suffix);
 }
 
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index ab4d51c..033457d 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -201,6 +201,7 @@
 			decoder->dynamic_prop_change |=
 				DDL_DEC_REQ_OUTPUT_FLUSH;
 			decoder->dpb_mask.client_mask = 0;
+			decoder->field_needed_for_prev_ip = 0;
 			vcd_status = VCD_S_SUCCESS;
 		}
 	break;
@@ -1952,11 +1953,7 @@
 					DDL_TILE_MULTIPLY_FACTOR);
 		total_memory_size += component_mem_size;
 	} else {
-		if (decoding)
-			total_memory_size = frame_sz.scan_lines *
-						frame_sz.stride;
-		else
-			total_memory_size = frame_sz.height * frame_sz.stride;
+		total_memory_size = frame_sz.scan_lines * frame_sz.stride;
 		c_offset = DDL_ALIGN(total_memory_size,
 			DDL_LINEAR_MULTIPLY_FACTOR);
 		total_memory_size = c_offset + DDL_ALIGN(
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index 839a9c1..d83cde8 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -205,6 +205,10 @@
 #define VIDC_SM_ASPECT_RATIO_INFO_ADDR               0x00c8
 #define VIDC_SM_MPEG4_ASPECT_RATIO_INFO_BMSK         0xf
 #define VIDC_SM_MPEG4_ASPECT_RATIO_INFO_SHFT         0x0
+#define VIDC_SM_MPEG2_ASPECT_RATIO_INFO_BMSK         0x000f0000
+#define VIDC_SM_MPEG2_ASPECT_RATIO_INFO_SHFT         16
+#define VIDC_SM_H264_ASPECT_RATIO_INFO_BMSK          0x00000ff0
+#define VIDC_SM_H264_ASPECT_RATIO_INFO_SHFT          4
 #define VIDC_SM_EXTENDED_PAR_ADDR                    0x00cc
 #define VIDC_SM_EXTENDED_PAR_WIDTH_BMSK              0xffff0000
 #define VIDC_SM_EXTENDED_PAR_WIDTH_SHFT              16
@@ -802,23 +806,160 @@
 }
 
 void vidc_sm_get_aspect_ratio_info(struct ddl_buf_addr *shared_mem,
-	struct vcd_aspect_ratio *aspect_ratio_info)
+	enum vcd_codec codec, struct vcd_aspect_ratio *aspect_ratio_info)
 {
-	u32 extended_par_info = 0;
-	aspect_ratio_info->aspect_ratio = DDL_MEM_READ_32(shared_mem,
+	u32 extended_par_info = 0, aspect_ratio = 0;
+
+	aspect_ratio = DDL_MEM_READ_32(shared_mem,
 				VIDC_SM_ASPECT_RATIO_INFO_ADDR);
 
-	if (aspect_ratio_info->aspect_ratio == 0x0f) {
-		extended_par_info = DDL_MEM_READ_32(shared_mem,
-			VIDC_SM_EXTENDED_PAR_ADDR);
-		aspect_ratio_info->extended_par_width =
-			VIDC_GETFIELD(extended_par_info,
-			VIDC_SM_EXTENDED_PAR_WIDTH_BMSK,
-			VIDC_SM_EXTENDED_PAR_WIDTH_SHFT);
-		aspect_ratio_info->extended_par_height =
-			VIDC_GETFIELD(extended_par_info,
-			VIDC_SM_EXTENDED_PAR_HEIGHT_BMSK,
-			VIDC_SM_EXTENDED_PAR_HEIGHT_SHFT);
+	if (codec == VCD_CODEC_H264) {
+		aspect_ratio_info->aspect_ratio =
+			VIDC_GETFIELD(aspect_ratio,
+			VIDC_SM_H264_ASPECT_RATIO_INFO_BMSK,
+			VIDC_SM_H264_ASPECT_RATIO_INFO_SHFT);
+
+		switch (aspect_ratio_info->aspect_ratio) {
+		case 1:
+			aspect_ratio_info->par_width    = 1;
+			aspect_ratio_info->par_height   = 1;
+			break;
+		case 2:
+			aspect_ratio_info->par_width    = 12;
+			aspect_ratio_info->par_height   = 11;
+			break;
+		case 3:
+			aspect_ratio_info->par_width    = 10;
+			aspect_ratio_info->par_height   = 11;
+			break;
+		case 4:
+			aspect_ratio_info->par_width    = 16;
+			aspect_ratio_info->par_height   = 11;
+			break;
+		case 5:
+			aspect_ratio_info->par_width    = 40;
+			aspect_ratio_info->par_height   = 33;
+			break;
+		case 6:
+			aspect_ratio_info->par_width    = 24;
+			aspect_ratio_info->par_height   = 11;
+			break;
+		case 7:
+			aspect_ratio_info->par_width    = 20;
+			aspect_ratio_info->par_height   = 11;
+			break;
+		case 8:
+			aspect_ratio_info->par_width    = 32;
+			aspect_ratio_info->par_height   = 11;
+			break;
+		case 9:
+			aspect_ratio_info->par_width    = 80;
+			aspect_ratio_info->par_height   = 33;
+			break;
+		case 10:
+			aspect_ratio_info->par_width    = 18;
+			aspect_ratio_info->par_height   = 11;
+			break;
+		case 11:
+			aspect_ratio_info->par_width    = 15;
+			aspect_ratio_info->par_height   = 11;
+			break;
+		case 12:
+			aspect_ratio_info->par_width    = 64;
+			aspect_ratio_info->par_height   = 33;
+			break;
+		case 13:
+			aspect_ratio_info->par_width    = 160;
+			aspect_ratio_info->par_height   = 99;
+			break;
+		case 14:
+			aspect_ratio_info->par_width    = 4;
+			aspect_ratio_info->par_height   = 3;
+			break;
+		case 15:
+			aspect_ratio_info->par_width    = 3;
+			aspect_ratio_info->par_height   = 2;
+			break;
+		case 16:
+			aspect_ratio_info->par_width    = 2;
+			aspect_ratio_info->par_height   = 1;
+			break;
+		case 255:
+			extended_par_info = DDL_MEM_READ_32(shared_mem,
+				VIDC_SM_EXTENDED_PAR_ADDR);
+			aspect_ratio_info->par_width =
+				VIDC_GETFIELD(extended_par_info,
+				VIDC_SM_EXTENDED_PAR_WIDTH_BMSK,
+				VIDC_SM_EXTENDED_PAR_WIDTH_SHFT);
+			aspect_ratio_info->par_height =
+				VIDC_GETFIELD(extended_par_info,
+				VIDC_SM_EXTENDED_PAR_HEIGHT_BMSK,
+				VIDC_SM_EXTENDED_PAR_HEIGHT_SHFT);
+			break;
+		default:
+			DDL_MSG_HIGH("Incorrect Aspect Ratio.");
+			aspect_ratio_info->par_width    = 1;
+			aspect_ratio_info->par_height   = 1;
+			break;
+		}
+	} else if ((codec == VCD_CODEC_MPEG4) ||
+		(codec == VCD_CODEC_DIVX_4) ||
+		(codec == VCD_CODEC_DIVX_5) ||
+		(codec == VCD_CODEC_DIVX_6) ||
+		(codec == VCD_CODEC_XVID) ||
+		(codec == VCD_CODEC_MPEG2)) {
+
+		if (codec == VCD_CODEC_MPEG2) {
+			aspect_ratio_info->aspect_ratio =
+				VIDC_GETFIELD(aspect_ratio,
+				VIDC_SM_MPEG2_ASPECT_RATIO_INFO_BMSK,
+				VIDC_SM_MPEG2_ASPECT_RATIO_INFO_SHFT);
+		} else {
+			aspect_ratio_info->aspect_ratio =
+				VIDC_GETFIELD(aspect_ratio,
+				VIDC_SM_MPEG4_ASPECT_RATIO_INFO_BMSK,
+				VIDC_SM_MPEG4_ASPECT_RATIO_INFO_SHFT);
+		}
+
+		switch (aspect_ratio_info->aspect_ratio) {
+		case 1:
+			aspect_ratio_info->par_width    = 1;
+			aspect_ratio_info->par_height   = 1;
+			break;
+		case 2:
+			aspect_ratio_info->par_width    = 12;
+			aspect_ratio_info->par_height   = 11;
+			break;
+		case 3:
+			aspect_ratio_info->par_width    = 10;
+			aspect_ratio_info->par_height   = 11;
+			break;
+		case 4:
+			aspect_ratio_info->par_width    = 16;
+			aspect_ratio_info->par_height   = 11;
+			break;
+		case 5:
+			aspect_ratio_info->par_width    = 40;
+			aspect_ratio_info->par_height   = 33;
+			break;
+		case 15:
+			extended_par_info = DDL_MEM_READ_32(shared_mem,
+				VIDC_SM_EXTENDED_PAR_ADDR);
+			aspect_ratio_info->par_width =
+				VIDC_GETFIELD(extended_par_info,
+				VIDC_SM_EXTENDED_PAR_WIDTH_BMSK,
+				VIDC_SM_EXTENDED_PAR_WIDTH_SHFT);
+			aspect_ratio_info->par_height =
+				VIDC_GETFIELD(extended_par_info,
+				VIDC_SM_EXTENDED_PAR_HEIGHT_BMSK,
+				VIDC_SM_EXTENDED_PAR_HEIGHT_SHFT);
+			break;
+		default:
+			DDL_MSG_HIGH("Incorrect Aspect Ratio.");
+			aspect_ratio_info->par_width    = 1;
+			aspect_ratio_info->par_height   = 1;
+			break;
+		}
 	}
 }
 
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index 6cd75595..1a46c36 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -180,7 +180,7 @@
 	struct ddl_buf_addr *shared_mem,
 	enum vidc_sm_num_stuff_bytes_consume_info consume_info);
 void vidc_sm_get_aspect_ratio_info(struct ddl_buf_addr *shared_mem,
-	struct vcd_aspect_ratio *aspect_ratio_info);
+	enum vcd_codec codec, struct vcd_aspect_ratio *aspect_ratio_info);
 void vidc_sm_set_encoder_slice_batch_int_ctrl(struct ddl_buf_addr *shared_mem,
 	u32 slice_batch_int_enable);
 void vidc_sm_get_num_slices_comp(struct ddl_buf_addr *shared_mem,
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
index 02b2369..a144e06 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
@@ -42,8 +42,17 @@
 	}
 
 	DDL_MEMSET(ddl_context, 0, sizeof(struct ddl_context));
-
 	DDL_BUSY(ddl_context);
+
+	if (res_trk_get_enable_ion()) {
+		VIDC_LOGERR_STRING("ddl_dev_init: ION framework enabled");
+		ddl_context->video_ion_client  =
+			res_trk_get_ion_client();
+		if (!ddl_context->video_ion_client) {
+			VIDC_LOGERR_STRING("ION client create failed");
+			return VCD_ERR_ILLEGAL_OP;
+		}
+	}
 	ddl_context->memtype = res_trk_get_mem_type();
 	if (ddl_context->memtype == -1) {
 		VIDC_LOGERR_STRING("ddl_dev_init:Invalid Memtype");
@@ -161,7 +170,7 @@
 
 	VIDC_LOG_STRING("FW_ENDDONE");
 	ddl_release_context_buffers(ddl_context);
-
+	ddl_context->video_ion_client = NULL;
 	DDL_IDLE(ddl_context);
 
 	return VCD_S_SUCCESS;
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/720p/ddl/vcd_ddl.h
index e1407c8..e6d3527 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012 Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -77,6 +77,7 @@
 	u32 *align_physical_addr;
 	u32 *align_virtual_addr;
 	struct msm_mapped_buffer *mapped_buffer;
+	struct ion_handle *alloc_handle;
 	u32 buffer_size;
 	enum ddl_mem_area mem_type;
 };
@@ -225,6 +226,7 @@
 	struct ddl_buf_addr dbg_core_dump;
 	u32 enable_dbg_core_dump;
 	struct ddl_client_context *ddl_clients[VCD_MAX_NO_CLIENT];
+	struct ion_client *video_ion_client;
 	u32 device_state;
 	u32 ddl_busy;
 	u32  intr_status;
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
index aa0d4b8..21f01d1 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
@@ -13,6 +13,7 @@
 #include <linux/memory_alloc.h>
 #include <media/msm/vidc_type.h>
 #include "vcd_ddl_utils.h"
+#include "vcd_res_tracker_api.h"
 
 #if DEBUG
 #define DBG(x...) printk(KERN_DEBUG x)
@@ -91,103 +92,178 @@
 	u32 alloc_size, flags = 0;
 	struct ddl_context *ddl_context;
 	struct msm_mapped_buffer *mapped_buffer = NULL;
+	unsigned long *kernel_vaddr = NULL;
+	ion_phys_addr_t phyaddr = 0;
+	size_t len = 0;
+	int ret = -EINVAL;
 
 	if (!buff_addr) {
-		ERR("\n%s() Invalid Parameters", __func__);
+		ERR("\n%s() Invalid Parameters\n", __func__);
 		return;
 	}
-
-	DBG_PMEM("\n%s() IN: Requested alloc size(%u)", __func__, (u32)sz);
-
 	if (align == DDL_LINEAR_BUFFER_ALIGN_BYTES) {
-
 		guard_bytes = 31;
 		align_mask = 0xFFFFFFE0U;
-
 	} else {
-
 		guard_bytes = DDL_TILE_BUF_ALIGN_GUARD_BYTES;
 		align_mask = DDL_TILE_BUF_ALIGN_MASK;
 	}
 	ddl_context = ddl_get_context();
 	alloc_size = sz + guard_bytes;
+	if (res_trk_get_enable_ion()) {
+		if (!ddl_context->video_ion_client)
+			ddl_context->video_ion_client =
+				res_trk_get_ion_client();
+		if (!ddl_context->video_ion_client) {
+			ERR("\n%s(): DDL ION Client Invalid handle\n",
+				__func__);
+			goto bailout;
+		}
+		buff_addr->mem_type = res_trk_get_mem_type();
+		buff_addr->alloc_handle = ion_alloc(
+					ddl_context->video_ion_client,
+					alloc_size,
+					SZ_4K,
+					buff_addr->mem_type);
+		if (!buff_addr->alloc_handle) {
+			ERR("\n%s(): DDL ION alloc failed\n",
+					__func__);
+			goto bailout;
+		}
+		ret = ion_phys(ddl_context->video_ion_client,
+					buff_addr->alloc_handle,
+					&phyaddr,
+					&len);
+		if (ret || !phyaddr) {
+			ERR("\n%s(): DDL ION client physical failed\n",
+					__func__);
+			goto free_ion_buffer;
+		}
+		buff_addr->physical_base_addr = (u32 *)phyaddr;
+		kernel_vaddr = (unsigned long *) ion_map_kernel(
+					ddl_context->video_ion_client,
+					buff_addr->alloc_handle,
+					UNCACHED);
+		if (IS_ERR_OR_NULL(kernel_vaddr)) {
+			ERR("\n%s(): DDL ION map failed\n", __func__);
+			goto unmap_ion_buffer;
+		}
+		buff_addr->virtual_base_addr = (u32 *)kernel_vaddr;
+		DBG("ddl_ion_alloc: handle(0x%x), mem_type(0x%x), "\
+			"phys(0x%x), virt(0x%x), size(%u), align(%u), "\
+			"alloced_len(%u)", (u32)buff_addr->alloc_handle,
+			(u32)buff_addr->mem_type,
+			(u32)buff_addr->physical_base_addr,
+			(u32)buff_addr->virtual_base_addr,
+			alloc_size, align, len);
+	} else {
+		physical_addr = (u32)
+			allocate_contiguous_memory_nomap(alloc_size,
+						ddl_context->memtype, SZ_4K);
+		if (!physical_addr) {
+			ERR("\n%s(): DDL pmem allocate failed\n",
+			       __func__);
+			goto bailout;
+		}
+		buff_addr->physical_base_addr = (u32 *) physical_addr;
+		flags = MSM_SUBSYSTEM_MAP_KADDR;
+		buff_addr->mapped_buffer =
+		msm_subsystem_map_buffer((unsigned long)physical_addr,
+		alloc_size, flags, NULL, 0);
+		if (IS_ERR(buff_addr->mapped_buffer)) {
+			ERR("\n%s() buffer map failed\n", __func__);
+			goto free_pmem_buffer;
+		}
+		mapped_buffer = buff_addr->mapped_buffer;
+		if (!mapped_buffer->vaddr) {
+			ERR("\n%s() mapped virtual address is NULL\n",
+				__func__);
+			goto unmap_pmem_buffer;
+		}
+		buff_addr->virtual_base_addr = mapped_buffer->vaddr;
+		DBG("ddl_pmem_alloc: mem_type(0x%x), phys(0x%x),"\
+			" virt(0x%x), sz(%u), align(%u)",
+			(u32)buff_addr->mem_type,
+			(u32)buff_addr->physical_base_addr,
+			(u32)buff_addr->virtual_base_addr,
+			alloc_size, SZ_4K);
+	}
 
-	physical_addr = (u32)
-		allocate_contiguous_memory_nomap(alloc_size,
-					ddl_context->memtype, SZ_4K);
-
-	if (!physical_addr) {
-		pr_err("%s(): could not allocate kernel pmem buffers\n",
-		       __func__);
-		goto bailout;
-	}
-	buff_addr->physical_base_addr = (u32 *) physical_addr;
-	flags = MSM_SUBSYSTEM_MAP_KADDR;
-	buff_addr->mapped_buffer =
-	msm_subsystem_map_buffer((unsigned long)physical_addr,
-	alloc_size, flags, NULL, 0);
-	if (IS_ERR(buff_addr->mapped_buffer)) {
-		pr_err(" %s() buffer map failed", __func__);
-		goto free_acm_alloc;
-	}
-	mapped_buffer = buff_addr->mapped_buffer;
-	if (!mapped_buffer->vaddr) {
-		pr_err("%s() mapped virtual address is NULL", __func__);
-		goto free_map_buffers;
-	}
-	buff_addr->virtual_base_addr = mapped_buffer->vaddr;
 	memset(buff_addr->virtual_base_addr, 0 , sz + guard_bytes);
 	buff_addr->buffer_size = sz;
-
-	buff_addr->align_physical_addr =
-	    (u32 *) ((physical_addr + guard_bytes) & align_mask);
-
-	align_offset =
-	    (u32) (buff_addr->align_physical_addr) - physical_addr;
-
+	buff_addr->align_physical_addr = (u32 *)
+		(((u32)buff_addr->physical_base_addr + guard_bytes) &
+		align_mask);
+	align_offset = (u32) (buff_addr->align_physical_addr) -
+		(u32)buff_addr->physical_base_addr;
 	buff_addr->align_virtual_addr =
 	    (u32 *) ((u32) (buff_addr->virtual_base_addr)
 		     + align_offset);
-
-	DBG_PMEM("\n%s() OUT: phy_addr(%p) ker_addr(%p) size(%u)", __func__,
-		buff_addr->physical_base_addr, buff_addr->virtual_base_addr,
-		buff_addr->buffer_size);
-
+	DBG("%s(): phys(0x%x) align_phys(0x%x), virt(0x%x),"\
+		" align_virt(0x%x)", __func__,
+		(u32)buff_addr->physical_base_addr,
+		(u32)buff_addr->align_physical_addr,
+		(u32)buff_addr->virtual_base_addr,
+		(u32)buff_addr->align_virtual_addr);
 	return;
-free_map_buffers:
-	msm_subsystem_unmap_buffer(buff_addr->mapped_buffer);
-free_acm_alloc:
-	free_contiguous_memory_by_paddr(
-		(unsigned long) physical_addr);
+
+unmap_pmem_buffer:
+	if (buff_addr->mapped_buffer)
+		msm_subsystem_unmap_buffer(buff_addr->mapped_buffer);
+free_pmem_buffer:
+	if (buff_addr->physical_base_addr)
+		free_contiguous_memory_by_paddr((unsigned long)
+			buff_addr->physical_base_addr);
+	memset(buff_addr, 0, sizeof(struct ddl_buf_addr));
+	return;
+
+unmap_ion_buffer:
+	if (ddl_context->video_ion_client) {
+		if (buff_addr->alloc_handle)
+			ion_unmap_kernel(ddl_context->video_ion_client,
+				buff_addr->alloc_handle);
+	}
+free_ion_buffer:
+	if (ddl_context->video_ion_client) {
+		if (buff_addr->alloc_handle)
+			ion_free(ddl_context->video_ion_client,
+				buff_addr->alloc_handle);
+	}
 bailout:
-	buff_addr->physical_base_addr = NULL;
-	buff_addr->virtual_base_addr = NULL;
-	buff_addr->buffer_size = 0;
-	buff_addr->mapped_buffer = NULL;
+	memset(buff_addr, 0, sizeof(struct ddl_buf_addr));
 }
 
 void ddl_pmem_free(struct ddl_buf_addr *buff_addr)
 {
+	struct ddl_context *ddl_context;
+	ddl_context = ddl_get_context();
 	if (!buff_addr) {
 		ERR("\n %s() invalid arguments %p", __func__, buff_addr);
 		return;
 	}
-	DBG_PMEM("\n%s() IN: phy_addr(%p) ker_addr(%p) size(%u)", __func__,
-		buff_addr->physical_base_addr, buff_addr->virtual_base_addr,
+	DBG("ddl_pmem_free: phys(0x%x) align_phys(0x%x), "\
+		"virt(0x%x), align_virt(0x%x), size(%u)",
+		(u32)buff_addr->physical_base_addr,
+		(u32)buff_addr->align_physical_addr,
+		(u32)buff_addr->virtual_base_addr,
+		(u32)buff_addr->align_virtual_addr,
 		buff_addr->buffer_size);
-
-	if (buff_addr->mapped_buffer)
-		msm_subsystem_unmap_buffer(buff_addr->mapped_buffer);
-	if (buff_addr->physical_base_addr)
-		free_contiguous_memory_by_paddr(
-			(unsigned long) buff_addr->physical_base_addr);
-	DBG_PMEM("\n%s() OUT: phy_addr(%p) ker_addr(%p) size(%u)", __func__,
-		buff_addr->physical_base_addr, buff_addr->virtual_base_addr,
-		buff_addr->buffer_size);
-	buff_addr->buffer_size = 0;
-	buff_addr->physical_base_addr = NULL;
-	buff_addr->virtual_base_addr = NULL;
-	buff_addr->mapped_buffer = NULL;
+	if (ddl_context->video_ion_client) {
+		if (buff_addr->alloc_handle) {
+			ion_unmap_kernel(ddl_context->video_ion_client,
+				buff_addr->alloc_handle);
+			ion_free(ddl_context->video_ion_client,
+				buff_addr->alloc_handle);
+		}
+	} else {
+		if (buff_addr->mapped_buffer)
+			msm_subsystem_unmap_buffer(
+				buff_addr->mapped_buffer);
+		if (buff_addr->physical_base_addr)
+			free_contiguous_memory_by_paddr((unsigned long)
+				buff_addr->physical_base_addr);
+	}
+	memset(buff_addr, 0, sizeof(struct ddl_buf_addr));
 }
 #endif
 
diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
index e51bf45..aee9dfe 100644
--- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
@@ -677,8 +677,16 @@
 	return false;
 }
 
+static struct ion_client *res_trk_create_ion_client(void){
+	struct ion_client *video_client;
+	VCDRES_MSG_LOW("%s", __func__);
+	video_client = msm_ion_client_create(-1, "video_client");
+	return video_client;
+}
+
 void res_trk_init(struct device *device, u32 irq)
 {
+	VCDRES_MSG_LOW("%s", __func__);
 	if (resource_context.device || resource_context.irq_num ||
 		!device) {
 		VCDRES_MSG_ERROR("%s() Resource Tracker Init error\n",
@@ -695,9 +703,27 @@
 		(struct msm_vidc_platform_data *) device->platform_data;
 	if (resource_context.vidc_platform_data) {
 		resource_context.memtype =
-		resource_context.vidc_platform_data->memtype;
+			resource_context.vidc_platform_data->memtype;
+		VCDRES_MSG_LOW("%s(): resource_context.memtype = 0x%x",
+			__func__, (u32)resource_context.memtype);
+		if (resource_context.vidc_platform_data->enable_ion) {
+			resource_context.res_ion_client =
+				res_trk_create_ion_client();
+			if (!(resource_context.res_ion_client)) {
+				VCDRES_MSG_ERROR("%s()ION createfail\n",
+						__func__);
+				return;
+			}
+			VCDRES_MSG_LOW("%s(): ion_client = 0x%x", __func__,
+				(u32)resource_context.res_ion_client);
+		} else {
+			VCDRES_MSG_ERROR("%s(): ION not disabled\n",
+					__func__);
+		}
 	} else {
 		resource_context.memtype = -1;
+		VCDRES_MSG_ERROR("%s(): vidc_platform_data is NULL",
+			__func__);
 	}
 }
 
@@ -705,18 +731,23 @@
 	return resource_context.core_type;
 }
 
-u32 res_trk_get_mem_type(void){
-	return resource_context.memtype;
-}
-
 u32 res_trk_get_enable_ion(void)
 {
-	return 0;
+	if (resource_context.vidc_platform_data->enable_ion)
+		return 1;
+	else
+		return 0;
 }
 
 struct ion_client *res_trk_get_ion_client(void)
 {
-	return NULL;
+	return resource_context.res_ion_client;
+}
+
+u32 res_trk_get_mem_type(void)
+{
+	u32 mem_type = ION_HEAP(resource_context.memtype);
+	return mem_type;
 }
 
 void res_trk_set_mem_type(enum ddl_mem_area mem_type)
diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.h b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.h
index 2b92a42..f8d9053 100644
--- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.h
+++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.h
@@ -13,6 +13,7 @@
 #ifndef _VIDEO_720P_RESOURCE_TRACKER_H_
 #define _VIDEO_720P_RESOURCE_TRACKER_H_
 #include <mach/board.h>
+#include <linux/ion.h>
 #include "vcd_res_tracker_api.h"
 
 #define VCD_RESTRK_MIN_PERF_LEVEL 37900
@@ -36,6 +37,8 @@
 	u32 core_type;
 	int memtype;
 	u32 secure_session;
+	struct ion_client *res_ion_client;
+	enum ddl_mem_area res_mem_type;
 };
 
 #if DEBUG
diff --git a/drivers/video/msm/vidc/Kconfig b/drivers/video/msm/vidc/Kconfig
index 9ffcb15..7820e53 100644
--- a/drivers/video/msm/vidc/Kconfig
+++ b/drivers/video/msm/vidc/Kconfig
@@ -37,3 +37,7 @@
 	help
 	This option enables support for Video decoder.
 
+config MSM_VIDC_CONTENT_PROTECTION
+	bool "Enable Content Protection"
+	help
+	  Enable content protection feature for Video.
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index 634011b..927f19b 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -334,9 +334,9 @@
 		output_frame->aspect_ratio_info.aspect_ratio =
 			vcd_frame_data->aspect_ratio_info.aspect_ratio;
 		output_frame->aspect_ratio_info.par_width =
-			vcd_frame_data->aspect_ratio_info.extended_par_width;
+			vcd_frame_data->aspect_ratio_info.par_width;
 		output_frame->aspect_ratio_info.par_height =
-			vcd_frame_data->aspect_ratio_info.extended_par_height;
+			vcd_frame_data->aspect_ratio_info.par_height;
 		vdec_msg->vdec_msg_info.msgdatasize =
 		    sizeof(struct vdec_output_frameinfo);
 	} else {
@@ -915,7 +915,8 @@
 				 __func__);
 			goto import_ion_error;
 		}
-		if (res_trk_check_for_sec_session()) {
+		if (res_trk_check_for_sec_session() ||
+		   (res_trk_get_core_type() == (u32)VCD_CORE_720P)) {
 			rc = ion_phys(client_ctx->user_ion_client,
 				client_ctx->h264_mv_ion_handle,
 				(unsigned long *) (&(vcd_h264_mv_buffer->
@@ -1038,7 +1039,8 @@
 	if (!IS_ERR_OR_NULL(client_ctx->h264_mv_ion_handle)) {
 		ion_unmap_kernel(client_ctx->user_ion_client,
 					client_ctx->h264_mv_ion_handle);
-		if (!res_trk_check_for_sec_session()) {
+		if (!res_trk_check_for_sec_session() &&
+		   (res_trk_get_core_type() != (u32)VCD_CORE_720P)) {
 			ion_unmap_iommu(client_ctx->user_ion_client,
 				client_ctx->h264_mv_ion_handle,
 				VIDEO_DOMAIN,
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index 9450ee7..50cccbb 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -1844,7 +1844,8 @@
 				 __func__);
 			goto import_ion_error;
 		}
-		if (res_trk_check_for_sec_session()) {
+		if (res_trk_check_for_sec_session() ||
+		   (res_trk_get_core_type() == (u32)VCD_CORE_720P)) {
 			rc = ion_phys(client_ctx->user_ion_client,
 				client_ctx->recon_buffer_ion_handle[i],
 				&phy_addr, &ion_len);
@@ -1945,7 +1946,8 @@
 		if (client_ctx->recon_buffer_ion_handle[i]) {
 			ion_unmap_kernel(client_ctx->user_ion_client,
 				client_ctx->recon_buffer_ion_handle[i]);
-			if (!res_trk_check_for_sec_session()) {
+			if (!res_trk_check_for_sec_session() &&
+			   (res_trk_get_core_type() != (u32)VCD_CORE_720P)) {
 				ion_unmap_iommu(client_ctx->user_ion_client,
 				client_ctx->recon_buffer_ion_handle[i],
 				VIDEO_DOMAIN,
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index dcacb3c..c884cf5 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -432,7 +432,9 @@
 				ion_unmap_kernel(client_ctx->user_ion_client,
 						buf_addr_table[i].
 						buff_ion_handle);
-				if (!res_trk_check_for_sec_session()) {
+				if (!res_trk_check_for_sec_session() &&
+				   (res_trk_get_core_type() !=
+				   (u32)VCD_CORE_720P)) {
 					ion_unmap_iommu(
 						client_ctx->user_ion_client,
 						buf_addr_table[i].
@@ -456,7 +458,8 @@
 		if (!IS_ERR_OR_NULL(client_ctx->user_ion_client)) {
 			ion_unmap_kernel(client_ctx->user_ion_client,
 					client_ctx->h264_mv_ion_handle);
-			if (!res_trk_check_for_sec_session()) {
+			if (!res_trk_check_for_sec_session() &&
+			    (res_trk_get_core_type() != (u32)VCD_CORE_720P)) {
 				ion_unmap_iommu(client_ctx->user_ion_client,
 					client_ctx->h264_mv_ion_handle,
 					VIDEO_DOMAIN,
@@ -652,7 +655,8 @@
 				*kernel_vaddr = (unsigned long)NULL;
 				goto ion_free_error;
 			}
-			if (res_trk_check_for_sec_session()) {
+			if (res_trk_check_for_sec_session() ||
+			   (res_trk_get_core_type() == (u32)VCD_CORE_720P)) {
 				if (ion_phys(client_ctx->user_ion_client,
 					buff_ion_handle,
 					&phys_addr, &ion_len)) {
@@ -780,7 +784,7 @@
 		*num_of_buffers = *num_of_buffers + 1;
 		DBG("%s() : client_ctx = %p, user_virt_addr = 0x%08lx, "
 			"kernel_vaddr = 0x%08lx inserted!", __func__,
-			client_ctx, user_vaddr, *kernel_vaddr);
+			client_ctx, user_vaddr, kernel_vaddr);
 	}
 	mutex_unlock(&client_ctx->enrty_queue_lock);
 	return true;
@@ -833,7 +837,8 @@
 	if (buf_addr_table[i].buff_ion_handle) {
 		ion_unmap_kernel(client_ctx->user_ion_client,
 				buf_addr_table[i].buff_ion_handle);
-		if (!res_trk_check_for_sec_session()) {
+		if (!res_trk_check_for_sec_session() &&
+		   (res_trk_get_core_type() != (u32)VCD_CORE_720P)) {
 			ion_unmap_iommu(client_ctx->user_ion_client,
 				buf_addr_table[i].buff_ion_handle,
 				VIDEO_DOMAIN,
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index c11ac301..28ea453 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -41,6 +41,8 @@
 	unsigned long buffer_size = 0;
 	int ret = 0;
 	unsigned long ionflag = 0;
+	ion_phys_addr_t phyaddr = 0;
+	size_t len = 0;
 
 	if (!kernel_vaddr || !phy_addr || !cctxt) {
 		pr_err("\n%s: Invalid parameters", __func__);
@@ -84,6 +86,9 @@
 		}
 		*phy_addr = (u8 *) mapped_buffer->iova[0];
 		*kernel_vaddr = (u8 *) mapped_buffer->vaddr;
+		VCD_MSG_LOW("vcd_pmem_alloc: phys(0x%x), virt(0x%x), "\
+			"sz(%u), flags(0x%x)", (u32)*phy_addr,
+			(u32)*kernel_vaddr, sz, (u32)flags);
 	} else {
 		map_buffer->alloc_handle = ion_alloc(
 			    cctxt->vcd_ion_client, sz, SZ_4K,
@@ -106,7 +111,8 @@
 			pr_err("%s() ION map failed", __func__);
 			goto ion_free_bailout;
 		}
-		ret = ion_map_iommu(cctxt->vcd_ion_client,
+		if (res_trk_get_core_type() != (u32)VCD_CORE_720P) {
+			ret = ion_map_iommu(cctxt->vcd_ion_client,
 				map_buffer->alloc_handle,
 				VIDEO_DOMAIN,
 				VIDEO_MAIN_POOL,
@@ -115,18 +121,32 @@
 				(unsigned long *)&iova,
 				(unsigned long *)&buffer_size,
 				UNCACHED, 0);
-		if (ret) {
-			pr_err("%s() ION iommu map failed", __func__);
-			goto ion_map_bailout;
+			if (ret) {
+				pr_err("%s() ION iommu map failed", __func__);
+				goto ion_map_bailout;
+			}
+			map_buffer->phy_addr = iova;
+		} else {
+			ret = ion_phys(cctxt->vcd_ion_client,
+				map_buffer->alloc_handle,
+				&phyaddr,
+				&len);
+			if (ret) {
+				pr_err("%s() ion_phys failed", __func__);
+				goto ion_map_bailout;
+			}
+			map_buffer->phy_addr = phyaddr;
 		}
-		map_buffer->phy_addr = iova;
 		if (!map_buffer->phy_addr) {
 			pr_err("%s() acm alloc failed", __func__);
 			goto free_map_table;
 		}
-		*phy_addr = (u8 *)iova;
+		*phy_addr = (u8 *)map_buffer->phy_addr;
 		mapped_buffer = NULL;
 		map_buffer->mapped_buffer = NULL;
+		VCD_MSG_LOW("vcd_ion_alloc: phys(0x%x), virt(0x%x), "\
+			"sz(%u), ionflags(0x%x)", (u32)*phy_addr,
+			(u32)*kernel_vaddr, sz, (u32)ionflag);
 	}
 
 	return 0;
@@ -176,10 +196,13 @@
 	if (map_buffer->mapped_buffer)
 		msm_subsystem_unmap_buffer(map_buffer->mapped_buffer);
 	if (cctxt->vcd_enable_ion) {
+		VCD_MSG_LOW("vcd_ion_free: phys(0x%x), virt(0x%x)",
+			(u32)phy_addr, (u32)kernel_vaddr);
 		if (map_buffer->alloc_handle) {
 			ion_unmap_kernel(cctxt->vcd_ion_client,
 					map_buffer->alloc_handle);
-			ion_unmap_iommu(cctxt->vcd_ion_client,
+			if (res_trk_get_core_type() != (u32)VCD_CORE_720P)
+				ion_unmap_iommu(cctxt->vcd_ion_client,
 					map_buffer->alloc_handle,
 					VIDEO_DOMAIN,
 					VIDEO_MAIN_POOL);
@@ -187,6 +210,8 @@
 			map_buffer->alloc_handle);
 		}
 	} else {
+		VCD_MSG_LOW("vcd_pmem_free: phys(0x%x), virt(0x%x)",
+			(u32)phy_addr, (u32)kernel_vaddr);
 		free_contiguous_memory_by_paddr(
 			(unsigned long)map_buffer->phy_addr);
 	}
diff --git a/fs/yaffs2/yaffs_vfs.c b/fs/yaffs2/yaffs_vfs.c
index 8e8c55b..4dd618f 100644
--- a/fs/yaffs2/yaffs_vfs.c
+++ b/fs/yaffs2/yaffs_vfs.c
@@ -497,8 +497,16 @@
 
 	if (ret_val == YAFFS_OK) {
 		if (target) {
-			drop_nlink(new_dentry->d_inode);
-			mark_inode_dirty(new_dentry->d_inode);
+			/*
+			 * We have identified target to be a
+			 * valid directory earlier. If it is
+			 * not the case throw a warning.
+			 */
+			WARN_ON(!new_dentry->d_inode);
+			if (new_dentry->d_inode) {
+				drop_nlink(new_dentry->d_inode);
+				mark_inode_dirty(new_dentry->d_inode);
+			}
 		}
 
 		update_dir_time(old_dir);
diff --git a/include/asm-generic/dma-coherent.h b/include/asm-generic/dma-coherent.h
index 85a3ffa..abfb268 100644
--- a/include/asm-generic/dma-coherent.h
+++ b/include/asm-generic/dma-coherent.h
@@ -3,13 +3,15 @@
 
 #ifdef CONFIG_HAVE_GENERIC_DMA_COHERENT
 /*
- * These two functions are only for dma allocator.
+ * These three functions are only for dma allocator.
  * Don't use them in device drivers.
  */
 int dma_alloc_from_coherent(struct device *dev, ssize_t size,
 				       dma_addr_t *dma_handle, void **ret);
 int dma_release_from_coherent(struct device *dev, int order, void *vaddr);
 
+int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
+			    void *cpu_addr, size_t size, int *ret);
 /*
  * Standard interface
  */
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 277fdf1..31a152d 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -427,6 +427,7 @@
 header-y += msm_vidc_enc.h
 header-y += msm_audio.h
 header-y += msm_audio_aac.h
+header-y += msm_audio_ac3.h
 header-y += msm_audio_acdb.h
 header-y += android_pmem.h
 header-y += msm_audio_wma.h
diff --git a/include/linux/coresight-stm.h b/include/linux/coresight-stm.h
index 20c4963..56a6cdf 100644
--- a/include/linux/coresight-stm.h
+++ b/include/linux/coresight-stm.h
@@ -14,12 +14,13 @@
 #define __MACH_STM_H
 
 enum {
-	OST_ENTITY_NONE			= 0x0,
-	OST_ENTITY_FTRACE_EVENTS	= 0x1,
-	OST_ENTITY_TRACE_PRINTK		= 0x2,
-	OST_ENTITY_TRACE_MARKER		= 0x4,
-	OST_ENTITY_DEV_NODE		= 0x8,
-	OST_ENTITY_ALL			= 0xF,
+	OST_ENTITY_NONE			= 0x00,
+	OST_ENTITY_FTRACE_EVENTS	= 0x01,
+	OST_ENTITY_TRACE_PRINTK		= 0x02,
+	OST_ENTITY_TRACE_MARKER		= 0x04,
+	OST_ENTITY_DEV_NODE		= 0x08,
+	OST_ENTITY_PRINTK		= 0x10,
+	OST_ENTITY_ALL			= 0x1F,
 };
 
 enum {
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index b6064a4..04fcd88 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -132,6 +132,7 @@
 struct coresight_ops_sink {
 	int (*enable)(struct coresight_device *csdev);
 	void (*disable)(struct coresight_device *csdev);
+	void (*abort)(struct coresight_device *csdev);
 };
 
 struct coresight_ops_link {
@@ -150,42 +151,21 @@
 	const struct coresight_ops_source *source_ops;
 };
 
-struct qdss_source {
-	struct list_head link;
-	const char *name;
-	uint32_t fport_mask;
-};
-
-struct msm_qdss_platform_data {
-	struct qdss_source *src_table;
-	size_t size;
-	uint8_t afamily;
-};
-
-
 #ifdef CONFIG_MSM_QDSS
-extern struct qdss_source *qdss_get(const char *name);
-extern void qdss_put(struct qdss_source *src);
-extern int qdss_enable(struct qdss_source *src);
-extern void qdss_disable(struct qdss_source *src);
-extern void qdss_disable_sink(void);
 extern struct coresight_device *
 coresight_register(struct coresight_desc *desc);
 extern void coresight_unregister(struct coresight_device *csdev);
 extern int coresight_enable(struct coresight_device *csdev);
 extern void coresight_disable(struct coresight_device *csdev);
+extern void coresight_abort(void);
 #else
-static inline struct qdss_source *qdss_get(const char *name) { return NULL; }
-static inline void qdss_put(struct qdss_source *src) {}
-static inline int qdss_enable(struct qdss_source *src) { return -ENOSYS; }
-static inline void qdss_disable(struct qdss_source *src) {}
-static inline void qdss_disable_sink(void) {}
 static inline struct coresight_device *
 coresight_register(struct coresight_desc *desc) { return NULL; }
 static inline void coresight_unregister(struct coresight_device *csdev) {}
 static inline int
 coresight_enable(struct coresight_device *csdev) { return -ENOSYS; }
 static inline void coresight_disable(struct coresight_device *csdev) {}
+static inline void coresight_abort(void) {}
 #endif
 
 #endif
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index fbffdd2..c953613 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -24,6 +24,7 @@
 #define MEMORY_DEVICE_MODE		2
 #define NO_LOGGING_MODE			3
 #define UART_MODE			4
+#define SOCKET_MODE			5
 
 /* different values that go in for diag_data_type */
 #define DATA_TYPE_EVENT         	0
@@ -111,7 +112,7 @@
 #define EVENT_LAST_ID			0x08AD
 
 #define MSG_SSID_0			0
-#define MSG_SSID_0_LAST			91
+#define MSG_SSID_0_LAST			93
 #define MSG_SSID_1			500
 #define MSG_SSID_1_LAST			506
 #define MSG_SSID_2			1000
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index f1e2527..771cb35 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -154,6 +154,14 @@
 	return desc->status_use_accessors & IRQ_NO_BALANCING_MASK;
 }
 
+static inline int irq_is_per_cpu(unsigned int irq)
+{
+	struct irq_desc *desc;
+
+	desc = irq_to_desc(irq);
+	return desc->status_use_accessors & IRQ_PER_CPU;
+}
+
 static inline void
 irq_set_lockdep_class(unsigned int irq, struct lock_class_key *class)
 {
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index d8a8ae4..9a02775 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -117,7 +117,8 @@
  * @r_sense:		sense resistor value in (mOhms)
  * @i_test:		current at which the unusable charger cutoff is to be
  *			calculated or the peak system current (mA)
- * @v_failure:		the voltage at which the battery is considered empty(mV)
+ * @v_cutoff:		the loaded voltage at which the battery
+ *			is considered empty(mV)
  * @enable_fcc_learning:	if set the driver will learn full charge
  *				capacity of the battery upon end of charge
  */
@@ -126,10 +127,14 @@
 	enum battery_type		battery_type;
 	unsigned int			r_sense;
 	unsigned int			i_test;
-	unsigned int			v_failure;
+	unsigned int			v_cutoff;
 	unsigned int			max_voltage_uv;
 	unsigned int			rconn_mohm;
 	int				enable_fcc_learning;
+	int				shutdown_soc_valid_limit;
+	int				ignore_shutdown_soc;
+	int				adjust_soc_low_threshold;
+	int				chg_term_ua;
 };
 
 #if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 2844d52..fa54978 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -90,6 +90,10 @@
  * @get_batt_capacity_percent:
  *			a board specific function to return battery
  *			capacity. If null - a default one will be used
+ * @dc_unplug_check:	enables the reverse boosting fix for the DC_IN line
+ *			however, this should only be enabled for devices which
+ *			control the DC OVP FETs otherwise this option should
+ *			remain disabled
  * @trkl_voltage:	the trkl voltage in (mV) below which hw controlled
  *			 trkl charging happens with linear charger
  * @weak_voltage:	the weak voltage (mV) below which hw controlled
@@ -140,6 +144,7 @@
 	int64_t				batt_id_min;
 	int64_t				batt_id_max;
 	bool				keep_btm_on_suspend;
+	bool				dc_unplug_check;
 	int				trkl_voltage;
 	int				weak_voltage;
 	int				trkl_current;
@@ -285,6 +290,13 @@
 
 int pm8921_set_ext_battery_health(int health);
 
+/**
+ * pm8921_is_batfet_closed - battery fet status
+ *
+ * Returns 1 if batfet is closed 0 if open. On configurations without
+ * batfet this will return 0.
+ */
+int pm8921_is_batfet_closed(void);
 #else
 static inline void pm8921_charger_vbus_draw(unsigned int mA)
 {
@@ -357,6 +369,10 @@
 {
 	return -ENXIO;
 }
+static inline int pm8921_is_batfet_closed(void)
+{
+	return 1;
+}
 #endif
 
 #endif
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index 17be2cb..105c2cb 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -144,6 +144,7 @@
 	int (*write_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
 			 int bytes, void *src, bool interface_reg);
 
+	u32 num_of_supplies;
 	struct regulator_bulk_data *supplies;
 
 	enum wcd9xxx_pm_state pm_state;
diff --git a/include/linux/mfd/wcd9xxx/pdata.h b/include/linux/mfd/wcd9xxx/pdata.h
index 1b7706bc..e831f0b 100644
--- a/include/linux/mfd/wcd9xxx/pdata.h
+++ b/include/linux/mfd/wcd9xxx/pdata.h
@@ -125,7 +125,7 @@
 	unsigned int	hph_ocp_limit:3; /* Headphone OCP current limit */
 };
 
-#define MAX_REGULATOR	6
+#define MAX_REGULATOR	7
 /*
  *      format : TABLA_<POWER_SUPPLY_PIN_NAME>_CUR_MAX
  *
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h b/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
index 93c21ce..9619527 100644
--- a/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
@@ -16,10 +16,6 @@
 #include <linux/slimbus/slimbus.h>
 #include <linux/mfd/wcd9xxx/core.h>
 
-/* Local to the core only */
-#define SLIM_MAX_RX_PORTS 7
-#define SLIM_MAX_TX_PORTS 10
-
 /* Channel numbers to be used for each port */
 enum {
 	SLIM_TX_1   = 128,
@@ -43,20 +39,43 @@
 };
 
 /*
- *  client is expected to give port ids in the range of 1-10 for Tx ports and
- *  1-7 for Rx ports, we need to add offset for getting the absolute slave
+ *  client is expected to give port ids in the range of
+ *  1-10 for pre Taiko Tx ports and 1-16 for Taiko
+ *  1-7 for pre Taiko Rx ports and 1-16 for Tako,
+ *  we need to add offset for getting the absolute slave
  *  port id before configuring the HW
  */
-#define SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS 10
-#define SB_PGD_OFFSET_OF_TX_SLAVE_DEV_PORTS     -1
-#define SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS 7
-#define SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS     9
+#define TABLA_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS 10
+#define TAIKO_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS 16
+
+#define SLIM_MAX_TX_PORTS TAIKO_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS
+
+#define TABLA_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS \
+	TABLA_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS
+#define TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS \
+	TAIKO_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS
+
+#define TABLA_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS 7
+#define TAIKO_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS 13
+
+#define SLIM_MAX_RX_PORTS TAIKO_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS
+
+#define TABLA_SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID \
+	TABLA_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS
+#define TAIKO_SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID \
+	TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS
+
+#define TABLA_SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID 16
+#define TAIKO_SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID 31
+
+#define TABLA_SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID 9
+#define TAIKO_SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID 15
 
 /* below details are taken from SLIMBUS slave SWI */
 #define SB_PGD_PORT_BASE 0x000
 
-#define SB_PGD_PORT_CFG_BYTE_ADDR(port_num) \
-		(SB_PGD_PORT_BASE + 0x040 + 1*port_num)
+#define SB_PGD_PORT_CFG_BYTE_ADDR(offset, port_num) \
+		(SB_PGD_PORT_BASE + offset + (1 * port_num))
 
 #define SB_PGD_TX_PORT_MULTI_CHANNEL_0(port_num) \
 		(SB_PGD_PORT_BASE + 0x100 + 4*port_num)
@@ -66,12 +85,9 @@
 #define SB_PGD_TX_PORT_MULTI_CHANNEL_1(port_num) \
 		(SB_PGD_PORT_BASE + 0x101 + 4*port_num)
 #define SB_PGD_TX_PORT_MULTI_CHANNEL_1_START_PORT_ID   8
-#define SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID     9
 
-#define SB_PGD_RX_PORT_MULTI_CHANNEL_0(port_num) \
-		(SB_PGD_PORT_BASE + 0x180 + 4*port_num)
-#define SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID   10
-#define SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID     16
+#define SB_PGD_RX_PORT_MULTI_CHANNEL_0(offset, port_num) \
+		(SB_PGD_PORT_BASE + offset + (4 * port_num))
 
 /* slave port water mark level
  *   (0: 6bytes, 1: 9bytes, 2: 12 bytes, 3: 15 bytes)
diff --git a/include/linux/msm_audio_ac3.h b/include/linux/msm_audio_ac3.h
new file mode 100644
index 0000000..fc50c30
--- /dev/null
+++ b/include/linux/msm_audio_ac3.h
@@ -0,0 +1,41 @@
+#ifndef __MSM_AUDIO_AC3_H
+#define __MSM_AUDIO_AC3_H
+
+#include <linux/msm_audio.h>
+
+#define AUDIO_SET_AC3_CONFIG  _IOW(AUDIO_IOCTL_MAGIC, \
+	(AUDIO_MAX_COMMON_IOCTL_NUM+0), unsigned)
+#define AUDIO_GET_AC3_CONFIG  _IOR(AUDIO_IOCTL_MAGIC, \
+	(AUDIO_MAX_COMMON_IOCTL_NUM+1), unsigned)
+
+#define AUDAC3_DEF_WORDSIZE 0
+#define AUDAC3_DEF_USER_DOWNMIX_FLAG 0x0
+#define AUDAC3_DEF_USER_KARAOKE_FLAG 0x0
+#define AUDAC3_DEF_ERROR_CONCEALMENT 0
+#define AUDAC3_DEF_MAX_REPEAT_COUNT  0
+
+struct msm_audio_ac3_config {
+	unsigned short		numChans;
+	unsigned short		wordSize;
+	unsigned short		kCapableMode;
+	unsigned short		compMode;
+	unsigned short		outLfeOn;
+	unsigned short		outputMode;
+	unsigned short		stereoMode;
+	unsigned short		dualMonoMode;
+	unsigned short		fsCod;
+	unsigned short		pcmScaleFac;
+	unsigned short		dynRngScaleHi;
+	unsigned short		dynRngScaleLow;
+	unsigned short		user_downmix_flag;
+	unsigned short		user_karaoke_flag;
+	unsigned short		dm_address_high;
+	unsigned short		dm_address_low;
+	unsigned short		ko_address_high;
+	unsigned short		ko_address_low;
+	unsigned short		error_concealment;
+	unsigned short		max_rep_count;
+	unsigned short		channel_routing_mode[6];
+};
+
+#endif /* __MSM_AUDIO_AC3_H */
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 4c42623..2519a6e 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -68,10 +68,8 @@
 						struct msmfb_data)
 #define MSMFB_WRITEBACK_TERMINATE _IO(MSMFB_IOCTL_MAGIC, 155)
 #define MSMFB_MDP_PP _IOWR(MSMFB_IOCTL_MAGIC, 156, struct msmfb_mdp_pp)
-
-#define MSMFB_OVERLAY_VSYNC_CTRL  _IOW(MSMFB_IOCTL_MAGIC, 160, unsigned int)
-
-
+#define MSMFB_OVERLAY_VSYNC_CTRL _IOW(MSMFB_IOCTL_MAGIC, 160, unsigned int)
+#define MSMFB_VSYNC_CTRL  _IOW(MSMFB_IOCTL_MAGIC, 161, unsigned int)
 #define FB_TYPE_3D_PANEL 0x10101010
 #define MDP_IMGTYPE2_START 0x10000
 #define MSMFB_DRIVER_VERSION	0xF9E8D701
diff --git a/include/linux/msm_thermal.h b/include/linux/msm_thermal.h
index 47a8753..8b7bb7c 100644
--- a/include/linux/msm_thermal.h
+++ b/include/linux/msm_thermal.h
@@ -24,11 +24,16 @@
 
 #ifdef CONFIG_THERMAL_MONITOR
 extern int msm_thermal_init(struct msm_thermal_data *pdata);
+extern int msm_thermal_device_init(void);
 #else
 static inline int msm_thermal_init(struct msm_thermal_data *pdata)
 {
 	return -ENOSYS;
 }
+static inline int msm_thermal_device_init(void)
+{
+	return -ENOSYS;
+}
 #endif
 
 #endif /*__MSM_THERMAL_H*/
diff --git a/include/linux/of_coresight.h b/include/linux/of_coresight.h
new file mode 100644
index 0000000..47a05c9
--- /dev/null
+++ b/include/linux/of_coresight.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_OF_CORESIGHT_H
+#define __LINUX_OF_CORESIGHT_H
+
+#ifdef CONFIG_OF
+extern struct coresight_platform_data *of_get_coresight_platform_data(
+				struct device *dev, struct device_node *node);
+#else
+static inline struct coresight_platform_data *of_get_coresight_platform_data(
+				struct device *dev, struct device_node *node)
+{
+	return NULL;
+}
+#endif
+
+#endif
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index e52bd41..035544c 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -213,6 +213,7 @@
 	int use_for_apm;
 };
 
+#if defined(CONFIG_POWER_SUPPLY) || defined(CONFIG_POWER_SUPPLY_MODULE)
 extern struct power_supply *power_supply_get_by_name(char *name);
 extern void power_supply_changed(struct power_supply *psy);
 extern int power_supply_am_i_supplied(struct power_supply *psy);
@@ -221,10 +222,31 @@
 extern int power_supply_set_online(struct power_supply *psy, bool enable);
 extern int power_supply_set_scope(struct power_supply *psy, int scope);
 extern int power_supply_set_charge_type(struct power_supply *psy, int type);
-
-#if defined(CONFIG_POWER_SUPPLY) || defined(CONFIG_POWER_SUPPLY_MODULE)
+extern int power_supply_set_supply_type(struct power_supply *psy,
+					enum power_supply_type supply_type);
 extern int power_supply_is_system_supplied(void);
 #else
+static inline struct power_supply *power_supply_get_by_name(char *name)
+							{ return -ENOSYS; }
+static inline int power_supply_am_i_supplied(struct power_supply *psy)
+							{ return -ENOSYS; }
+static inline int power_supply_set_battery_charged(struct power_supply *psy)
+							{ return -ENOSYS; }
+static inline int power_supply_set_current_limit(struct power_supply *psy,
+							int limit)
+							{ return -ENOSYS; }
+static inline int power_supply_set_online(struct power_supply *psy,
+							bool enable)
+							{ return -ENOSYS; }
+static inline int power_supply_set_scope(struct power_supply *psy,
+							int scope)
+							{ return -ENOSYS; }
+static inline int power_supply_set_charge_type(struct power_supply *psy,
+							int type)
+							{ return -ENOSYS; }
+static inline int power_supply_set_supply_type(struct power_supply *psy,
+					enum power_supply_type supply_type);
+							{ return -ENOSYS; }
 static inline int power_supply_is_system_supplied(void) { return -ENOSYS; }
 #endif
 
diff --git a/include/linux/qpnp/clkdiv.h b/include/linux/qpnp/clkdiv.h
new file mode 100644
index 0000000..c75a922
--- /dev/null
+++ b/include/linux/qpnp/clkdiv.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef QPNP_CLKDIV_H
+#define QPNP_CLKDIV_H
+
+enum q_clkdiv_cfg {
+	Q_CLKDIV_NO_CLK = 0,
+	Q_CLKDIV_XO_DIV_1,
+	Q_CLKDIV_XO_DIV_2,
+	Q_CLKDIV_XO_DIV_4,
+	Q_CLKDIV_XO_DIV_8,
+	Q_CLKDIV_XO_DIV_16,
+	Q_CLKDIV_XO_DIV_32,
+	Q_CLKDIV_XO_DIV_64,
+	Q_CLKDIV_INVALID,
+};
+
+struct q_clkdiv;
+
+struct q_clkdiv *qpnp_clkdiv_get(struct device *dev, const char *name);
+int qpnp_clkdiv_enable(struct q_clkdiv *q_clkdiv);
+int qpnp_clkdiv_disable(struct q_clkdiv *q_clkdiv);
+int qpnp_clkdiv_config(struct q_clkdiv *q_clkdiv,
+				enum q_clkdiv_cfg cfg);
+#endif
diff --git a/include/linux/qpnp/pwm.h b/include/linux/qpnp/pwm.h
index de89a37..50c15e9 100644
--- a/include/linux/qpnp/pwm.h
+++ b/include/linux/qpnp/pwm.h
@@ -114,6 +114,18 @@
 int pwm_config_pwm_value(struct pwm_device *pwm, int pwm_value);
 
 /*
+ * enum pm_pwm_mode - PWM mode selection
+ * %PM_PWM_MODE_PWM - Select PWM mode
+ * %PM_PWM_MODE_LPG - Select LPG mode
+ */
+enum pm_pwm_mode {
+	PM_PWM_MODE_PWM,
+	PM_PWM_MODE_LPG,
+};
+
+int pwm_change_mode(struct pwm_device *pwm, enum pm_pwm_mode mode);
+
+/*
  * lut_params: Lookup table (LUT) parameters
  * @start_idx: start index in lookup table from 0 to MAX-1
  * @idx_len: number of index
@@ -134,8 +146,6 @@
 int pwm_lut_config(struct pwm_device *pwm, int period_us,
 		int duty_pct[], struct lut_params lut_params);
 
-int pwm_lut_enable(struct pwm_device *pwm, int start);
-
 /* Standard APIs supported */
 /*
  * pwm_request - request a PWM device
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 33559dd..8468aa5 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -122,7 +122,22 @@
 	ADC_MAX_NUM,
 };
 
+/**
+ * enum qpnp_iadc_channels - QPNP IADC channel list
+ */
+enum qpnp_iadc_channels {
+	INTERNAL_RSENSE = 0,
+	EXTERNAL_RSENSE,
+	ALT_LEAD_PAIR,
+	GAIN_CALIBRATION_25MV,
+	OFFSET_CALIBRATION_SHORT_CADC_LEADS,
+	OFFSET_CALIBRATION_CSP_CSN,
+	OFFSET_CALIBRATION_CSP2_CSN2,
+	IADC_MUX_NUM,
+};
+
 #define QPNP_ADC_625_UV	625000
+#define QPNP_ADC_HWMON_NAME_LENGTH				16
 
 /**
  * enum qpnp_adc_decimation_type - Sampling rate supported.
@@ -565,6 +580,20 @@
 };
 
 /**
+ * struct qpnp_iadc_calib - IADC channel calibration structure.
+ * @channel - Channel for which the historical offset and gain is
+ *	      calculated. Available channels are internal rsense,
+ *	      external rsense and alternate lead pairs.
+ * @offset - Offset value for the channel.
+ * @gain - Gain of the channel.
+ */
+struct qpnp_iadc_calib {
+	enum qpnp_iadc_channels		channel;
+	int32_t				offset;
+	int32_t				gain;
+};
+
+/**
  * struct qpnp_adc_drv - QPNP ADC device structure.
  * @spmi - spmi device for ADC peripheral.
  * @offset - base offset for the ADC peripheral.
@@ -575,21 +604,23 @@
  * @adc_lock - ADC lock for access to the peripheral.
  * @adc_rslt_completion - ADC result notification after interrupt
  *			  is received.
+ * @calib - Internal rsens calibration values for gain and offset.
  */
 struct qpnp_adc_drv {
 	struct spmi_device		*spmi;
 	uint8_t				slave;
 	uint16_t			offset;
 	struct qpnp_adc_properties	*adc_prop;
-	struct qpnp_vadc_amux_properties	*amux_prop;
+	struct qpnp_adc_amux_properties	*amux_prop;
 	struct qpnp_vadc_amux		*adc_channels;
 	int				adc_irq;
 	struct mutex			adc_lock;
 	struct completion		adc_rslt_completion;
+	struct qpnp_iadc_calib		calib;
 };
 
 /**
- * struct qpnp_vadc_amux_properties - QPNP VADC amux channel property.
+ * struct qpnp_adc_amux_properties - QPNP VADC amux channel property.
  * @amux_channel - Refer to the qpnp_vadc_channel list.
  * @decimation - Sampling rate supported for the channel.
  * @mode_sel - The basic mode of operation.
@@ -600,7 +631,7 @@
  * @trigger_channel - HW trigger channel for conversion sequencer.
  * @chan_prop - Represent the channel properties of the ADC.
  */
-struct qpnp_vadc_amux_properties {
+struct qpnp_adc_amux_properties {
 	uint32_t			amux_channel;
 	uint32_t			decimation;
 	uint32_t			mode_sel;
@@ -653,7 +684,7 @@
  * @chan_prop:	Individual channel properties for the AMUX channel.
  */
 int32_t qpnp_vadc_configure(
-			struct qpnp_vadc_amux_properties *chan_prop);
+			struct qpnp_adc_amux_properties *chan_prop);
 
 /**
  * qpnp_adc_scale_default() - Scales the pre-calibrated digital output
@@ -686,4 +717,40 @@
 { return -ENXIO; }
 #endif
 
+/* Public API */
+#if defined(CONFIG_SENSORS_QPNP_ADC_CURRENT)				\
+			|| defined(CONFIG_SENSORS_QPNP_ADC_CURRENT_MODULE)
+/**
+ * qpnp_iadc_read() - Performs ADC read on the current channel.
+ * @channel:	Input channel to perform the ADC read.
+ * @result:	Current across rsens in mV.
+ */
+int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
+							int32_t *result);
+/**
+ * qpnp_iadc_get_gain() - Performs gain calibration over 25mV reference
+ *			  across CCADC.
+ * @result:	Gain result across 25mV reference.
+ */
+int32_t qpnp_iadc_get_gain(int32_t *result);
+
+/**
+ * qpnp_iadc_get_offset() - Performs offset calibration over selected
+ *			    channel. Channel can be internal rsense,
+ *			    external rsense and alternate lead pair.
+ * @result:	Gain result across 25mV reference.
+ */
+int32_t qpnp_iadc_get_offset(enum qpnp_iadc_channels channel,
+						int32_t *result);
+#else
+static inline int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
+							int *result)
+{ return -ENXIO; }
+static inline int32_t qpnp_iadc_get_gain(int32_t *result)
+{ return -ENXIO; }
+static inline int32_t qpnp_iadc_get_offset(enum qpnp_iadc_channels channel,
+						int32_t *result)
+{ return -ENXIO; }
+#endif
+
 #endif
diff --git a/include/linux/regulator/krait-regulator.h b/include/linux/regulator/krait-regulator.h
new file mode 100644
index 0000000..eb1c3fd
--- /dev/null
+++ b/include/linux/regulator/krait-regulator.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __KRAIT_REGULATOR_H__
+#define __KRAIT_REGULATOR_H__
+
+#define KRAIT_REGULATOR_DRIVER_NAME "krait-power-regulator"
+
+/**
+ * krait_power_init - driver initialization function
+ *
+ * This function registers the krait-power-regulator platform driver. This
+ * should be called from appropriate initialization code. Returns 0 on
+ * success and error on failure.
+ */
+int __init krait_power_init(void);
+void secondary_cpu_hs_init(void *base_ptr);
+
+#endif
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 6a0259d..6fcafa8 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -282,8 +282,10 @@
 	struct winsize winsize;		/* termios mutex */
 	unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;
 	unsigned char low_latency:1, warned:1;
+	unsigned char update_room_in_ldisc:1;
 	unsigned char ctrl_status;	/* ctrl_lock */
 	unsigned int receive_room;	/* Bytes free for queue */
+	unsigned int rr_bug;
 
 	struct tty_struct *link;
 	struct fasync_struct *fasync;
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 3b1d06d..ffa542f 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -187,6 +187,8 @@
  * @default_mode: Default operational mode. Applicable only if
  *              OTG switch is controller by user.
  * @pmic_id_irq: IRQ number assigned for PMIC USB ID line.
+ * @mpm_otgsessvld_int: MPM wakeup pin assigned for OTG SESSVLD
+ *              interrupt. Used when .otg_control == OTG_PHY_CONTROL.
  * @mhl_enable: indicates MHL connector or not.
  * @disable_reset_on_disconnect: perform USB PHY and LINK reset
  *              on USB cable disconnection.
@@ -211,6 +213,7 @@
 	enum msm_usb_phy_type phy_type;
 	void (*setup_gpio)(enum usb_otg_state state);
 	int pmic_id_irq;
+	unsigned int mpm_otgsessvld_int;
 	bool mhl_enable;
 	bool disable_reset_on_disconnect;
 	bool enable_dcd;
@@ -265,6 +268,7 @@
  * @otg: USB OTG Transceiver structure.
  * @pdata: otg device platform data.
  * @irq: IRQ number assigned for HSUSB controller.
+ * @async_irq: IRQ number used by some controllers during low power state
  * @clk: clock struct of alt_core_clk.
  * @pclk: clock struct of iface_clk.
  * @phy_reset_clk: clock struct of phy_clk.
@@ -273,7 +277,7 @@
  * @inputs: OTG state machine inputs(Id, SessValid etc).
  * @sm_work: OTG state machine work.
  * @in_lpm: indicates low power mode (LPM) state.
- * @async_int: Async interrupt arrived.
+ * @async_int: IRQ line on which ASYNC interrupt arrived in LPM.
  * @cur_power: The amount of mA available from downstream port.
  * @chg_work: Charger detection work.
  * @chg_state: The state of charger detection process.
@@ -295,6 +299,7 @@
 	struct usb_phy phy;
 	struct msm_otg_platform_data *pdata;
 	int irq;
+	int async_irq;
 	struct clk *clk;
 	struct clk *pclk;
 	struct clk *phy_reset_clk;
@@ -360,6 +365,7 @@
 #define PHY_PWR_COLLAPSED		BIT(0)
 #define PHY_RETENTIONED			BIT(1)
 #define XO_SHUTDOWN			BIT(2)
+#define CLOCKS_DOWN			BIT(3)
 	int reset_counter;
 	unsigned long b_last_se0_sess;
 	unsigned long tmouts;
@@ -376,6 +382,7 @@
 
 struct msm_usb_host_platform_data {
 	unsigned int power_budget;
+	int pmic_gpio_dp_irq;
 	unsigned int dock_connect_irq;
 };
 
@@ -389,21 +396,46 @@
 	bool core_clk_always_on_workaround;
 };
 
+/**
+ * struct usb_bam_pipe_connect: pipe connection information
+ * between USB/HSIC BAM and another BAM. USB/HSIC BAM can be
+ * either src BAM or dst BAM
+ * @src_phy_addr: src bam physical address.
+ * @src_pipe_index: src bam pipe index.
+ * @dst_phy_addr: dst bam physical address.
+ * @dst_pipe_index: dst bam pipe index.
+ * @data_fifo_base_offset: data fifo offset.
+ * @data_fifo_size: data fifo size.
+ * @desc_fifo_base_offset: descriptor fifo offset.
+ * @desc_fifo_size: descriptor fifo size.
+ */
 struct usb_bam_pipe_connect {
 	u32 src_phy_addr;
-	int src_pipe_index;
+	u32 src_pipe_index;
 	u32 dst_phy_addr;
-	int dst_pipe_index;
+	u32 dst_pipe_index;
 	u32 data_fifo_base_offset;
 	u32 data_fifo_size;
 	u32 desc_fifo_base_offset;
 	u32 desc_fifo_size;
 };
 
+/**
+ * struct msm_usb_bam_platform_data: pipe connection information
+ * between USB/HSIC BAM and another BAM. USB/HSIC BAM can be
+ * either src BAM or dst BAM
+ * @connections: holds all pipe connections data.
+ * @usb_active_bam: set USB or HSIC as the active BAM.
+ * @usb_bam_num_pipes: max number of pipes to use.
+ * @active_conn_num: number of active pipe connections.
+ * @usb_base_address: BAM physical address.
+ */
 struct msm_usb_bam_platform_data {
 	struct usb_bam_pipe_connect *connections;
 	int usb_active_bam;
 	int usb_bam_num_pipes;
+	u32 total_bam_num;
+	u32 usb_base_address;
 };
 
 enum usb_bam {
@@ -411,8 +443,27 @@
 	HSIC_BAM,
 };
 
+#ifdef CONFIG_USB_DWC3_MSM
 int msm_ep_config(struct usb_ep *ep);
 int msm_ep_unconfig(struct usb_ep *ep);
-int msm_data_fifo_config(struct usb_ep *ep, u32 addr, u32 size);
+int msm_data_fifo_config(struct usb_ep *ep, u32 addr, u32 size,
+	u8 dst_pipe_idx);
 
+#else
+static inline int msm_data_fifo_config(struct usb_ep *ep, u32 addr, u32 size,
+	u8 dst_pipe_idx)
+{
+	return -ENODEV;
+}
+
+static inline int msm_ep_config(struct usb_ep *ep)
+{
+	return -ENODEV;
+}
+
+static inline int msm_ep_unconfig(struct usb_ep *ep)
+{
+	return -ENODEV;
+}
+#endif
 #endif
diff --git a/include/linux/usb/usb_qdss.h b/include/linux/usb/usb_qdss.h
new file mode 100644
index 0000000..94a2c37
--- /dev/null
+++ b/include/linux/usb/usb_qdss.h
@@ -0,0 +1,55 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_USB_QDSS_H
+#define __LINUX_USB_QDSS_H
+
+#include <linux/kernel.h>
+
+struct qdss_request {
+	char *buf;
+	int length;
+	int actual;
+	int status;
+	void *context;
+};
+
+struct usb_qdss_ch {
+	const char *name;
+	struct list_head list;
+	void (*notify)(void *priv, unsigned event, struct qdss_request *d_req,
+		struct usb_qdss_ch *);
+	void *priv;
+	void *priv_usb;
+	int app_conn;
+};
+
+enum qdss_state {
+	USB_QDSS_CONNECT,
+	USB_QDSS_DISCONNECT,
+	USB_QDSS_CTRL_READ_DONE,
+	USB_QDSS_DATA_WRITE_DONE,
+	USB_QDSS_CTRL_WRITE_DONE,
+};
+
+struct usb_qdss_ch *usb_qdss_open(const char *name, void *priv,
+	void (*notify)(void *, unsigned, struct qdss_request *,
+		struct usb_qdss_ch *));
+void usb_qdss_close(struct usb_qdss_ch *ch);
+int usb_qdss_alloc_req(struct usb_qdss_ch *ch, int n_write, int n_read);
+void usb_qdss_free_req(struct usb_qdss_ch *ch);
+int usb_qdss_read(struct usb_qdss_ch *ch, struct qdss_request *d_req);
+int usb_qdss_write(struct usb_qdss_ch *ch, struct qdss_request *d_req);
+int usb_qdss_ctrl_write(struct usb_qdss_ch *ch, struct qdss_request *d_req);
+int usb_qdss_ctrl_read(struct usb_qdss_ch *ch, struct qdss_request *d_req);
+
+#endif
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 3e2f39b1..66b68d0 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -428,7 +428,28 @@
 #define V4L2_PIX_FMT_CIT_YYVYUY v4l2_fourcc('C', 'I', 'T', 'V') /* one line of Y then 1 line of VYUY */
 #define V4L2_PIX_FMT_KONICA420  v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */
 #define V4L2_PIX_FMT_JPGL	v4l2_fourcc('J', 'P', 'G', 'L') /* JPEG-Lite */
-#define V4L2_PIX_FMT_SE401      v4l2_fourcc('S', '4', '0', '1') /* se401 janggu compressed rgb */
+/* se401 janggu compressed rgb */
+#define V4L2_PIX_FMT_SE401      v4l2_fourcc('S', '4', '0', '1')
+/* Composite stats */
+#define V4L2_PIX_FMT_STATS_COMB v4l2_fourcc('S', 'T', 'C', 'M')
+/* AEC stats */
+#define V4L2_PIX_FMT_STATS_AE   v4l2_fourcc('S', 'T', 'A', 'E')
+/* AF stats */
+#define V4L2_PIX_FMT_STATS_AF   v4l2_fourcc('S', 'T', 'A', 'F')
+/* AWB stats */
+#define V4L2_PIX_FMT_STATS_AWB  v4l2_fourcc('S', 'T', 'W', 'B')
+/* IHIST stats */
+#define V4L2_PIX_FMT_STATS_IHST v4l2_fourcc('I', 'H', 'S', 'T')
+/* Column count stats */
+#define V4L2_PIX_FMT_STATS_CS   v4l2_fourcc('S', 'T', 'C', 'S')
+/* Row count stats */
+#define V4L2_PIX_FMT_STATS_RS   v4l2_fourcc('S', 'T', 'R', 'S')
+/* Bayer Grid stats */
+#define V4L2_PIX_FMT_STATS_BG   v4l2_fourcc('S', 'T', 'B', 'G')
+/* Bayer focus stats */
+#define V4L2_PIX_FMT_STATS_BF   v4l2_fourcc('S', 'T', 'B', 'F')
+/* Bayer hist stats */
+#define V4L2_PIX_FMT_STATS_BHST v4l2_fourcc('B', 'H', 'S', 'T')
 
 /*
  *	F O R M A T   E N U M E R A T I O N
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 46a5b1b..295be8f 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -48,6 +48,8 @@
 int free_riva_power_on_lock(char *driver_name);
 unsigned int wcnss_get_serial_number(void);
 void wcnss_flush_delayed_boot_votes(void);
+void wcnss_allow_suspend(void);
+void wcnss_prevent_suspend(void);
 #define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
 #define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))
 
diff --git a/include/media/msm/vcd_api.h b/include/media/msm/vcd_api.h
index c93b696..7104028 100644
--- a/include/media/msm/vcd_api.h
+++ b/include/media/msm/vcd_api.h
@@ -55,8 +55,8 @@
 
 struct vcd_aspect_ratio {
 	u32 aspect_ratio;
-	u32 extended_par_width;
-	u32 extended_par_height;
+	u32 par_width;
+	u32 par_height;
 };
 
 struct vcd_frame_data {
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 78ee3c8..d1d4eaa 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -486,7 +486,8 @@
 #define CMD_STATS_BG_BUF_RELEASE 56
 #define CMD_STATS_BF_BUF_RELEASE 57
 #define CMD_STATS_BHIST_BUF_RELEASE 58
-
+#define CMD_VFE_SOF_COUNT_UPDATE 59
+#define CMD_VFE_COUNT_SOF_ENABLE 60
 
 #define CMD_AXI_CFG_PRIM               BIT(8)
 #define CMD_AXI_CFG_PRIM_ALL_CHNLS     BIT(9)
@@ -497,6 +498,7 @@
 
 #define CMD_AXI_START  0xE1
 #define CMD_AXI_STOP   0xE2
+#define CMD_AXI_RESET  0xE3
 
 
 #define AXI_CMD_PREVIEW      BIT(0)
@@ -504,8 +506,7 @@
 #define AXI_CMD_RECORD       BIT(2)
 #define AXI_CMD_ZSL          BIT(3)
 #define AXI_CMD_RAW_CAPTURE  BIT(4)
-
-
+#define AXI_CMD_LIVESHOT     BIT(5)
 
 /* vfe config command: config command(from config thread)*/
 struct msm_vfe_cfg_cmd {
@@ -785,8 +786,19 @@
 	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+7)
 #define MSM_V4L2_EXT_CAPTURE_MODE_RDI2 \
 	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+8)
-#define MSM_V4L2_EXT_CAPTURE_MODE_MAX (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+9)
-
+#define MSM_V4L2_EXT_CAPTURE_MODE_AEC \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+9)
+#define MSM_V4L2_EXT_CAPTURE_MODE_AWB \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+10)
+#define MSM_V4L2_EXT_CAPTURE_MODE_AF \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+11)
+#define MSM_V4L2_EXT_CAPTURE_MODE_IHIST \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+12)
+#define MSM_V4L2_EXT_CAPTURE_MODE_CS \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+13)
+#define MSM_V4L2_EXT_CAPTURE_MODE_RS \
+	(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+14)
+#define MSM_V4L2_EXT_CAPTURE_MODE_MAX (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+15)
 
 #define MSM_V4L2_PID_MOTION_ISO              V4L2_CID_PRIVATE_BASE
 #define MSM_V4L2_PID_EFFECT                 (V4L2_CID_PRIVATE_BASE+1)
@@ -1776,6 +1788,7 @@
 	uint32_t capture_count;
 	uint32_t skip_abort;
 	uint16_t port_info;
+	uint32_t inst_handle;
 	uint16_t cmd_type;
 };
 
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index ab9e70c..9fa5932 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -65,7 +65,9 @@
 #define MSG_ID_STATS_BG                 46
 #define MSG_ID_STATS_BF                 47
 #define MSG_ID_STATS_BHIST              48
-
+#define MSG_ID_RDI0_UPDATE_ACK          49
+#define MSG_ID_RDI1_UPDATE_ACK          50
+#define MSG_ID_RDI2_UPDATE_ACK          51
 
 /* ISP command IDs */
 #define VFE_CMD_DUMMY_0                                 0
@@ -218,6 +220,19 @@
 #define VFE_CMD_STATS_BHIST_START                       147
 #define VFE_CMD_STATS_BHIST_STOP                        148
 #define VFE_CMD_RESET_2                                 149
+#define VFE_CMD_FOV_ENC_CFG                             150
+#define VFE_CMD_FOV_VIEW_CFG                            151
+#define VFE_CMD_FOV_ENC_UPDATE                          152
+#define VFE_CMD_FOV_VIEW_UPDATE                         153
+#define VFE_CMD_SCALER_ENC_CFG                          154
+#define VFE_CMD_SCALER_VIEW_CFG                         155
+#define VFE_CMD_SCALER_ENC_UPDATE                       156
+#define VFE_CMD_SCALER_VIEW_UPDATE                      157
+#define VFE_CMD_COLORXFORM_ENC_CFG                      158
+#define VFE_CMD_COLORXFORM_VIEW_CFG                     159
+#define VFE_CMD_COLORXFORM_ENC_UPDATE                   160
+#define VFE_CMD_COLORXFORM_VIEW_UPDATE                  161
+#define VFE_CMD_TEST_GEN_CFG                            162
 
 struct msm_isp_cmd {
 	int32_t  id;
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index baa6a286..2efe31c 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -44,6 +44,7 @@
 int msm_vidc_streamon(void *instance, enum v4l2_buf_type i);
 int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i);
 int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec);
+int msm_vidc_encoder_cmd(void *instance, struct v4l2_encoder_cmd *enc);
 int msm_vidc_poll(void *instance, struct file *filp,
 		struct poll_table_struct *pt);
 #endif
diff --git a/include/media/tavarua.h b/include/media/tavarua.h
index adbdada..d7b1340 100644
--- a/include/media/tavarua.h
+++ b/include/media/tavarua.h
@@ -176,6 +176,7 @@
 	V4L2_CID_PRIVATE_SPUR_FREQ_RMSSI,
 	V4L2_CID_PRIVATE_SPUR_SELECTION,
 	V4L2_CID_PRIVATE_UPDATE_SPUR_TABLE,
+	V4L2_CID_PRIVATE_VALID_CHANNEL,
 
 };
 
@@ -336,6 +337,16 @@
 	RDS_AF_JUMP,
 };
 
+/* Band limits */
+#define REGION_US_EU_BAND_LOW		87500
+#define REGION_US_EU_BAND_HIGH		108000
+#define REGION_JAPAN_STANDARD_BAND_LOW	76000
+#define REGION_JAPAN_STANDARD_BAND_HIGH	90000
+#define REGION_JAPAN_WIDE_BAND_LOW	90000
+#define REGION_JAPAN_WIDE_BAND_HIGH	108000
+#define MPX_DCC_BYPASS_REG		0x88C0
+#define MPX_DCC_DATA_REG		0x88C2
+
 enum audio_path {
 	FM_DIGITAL_PATH,
 	FM_ANALOG_PATH
@@ -534,6 +545,12 @@
 #define SPUR_TABLE_START_ADDR	(SPUR_TABLE_ADDR + 1)
 #define XFR_PEEK_COMPLETE	(XFR_PEEK_MODE | READ_COMPLETE)
 #define XFR_POKE_COMPLETE	(XFR_POKE_MODE)
+#define TUNE_MULT		(16)
+#define ADJ_CHANNEL_KHZ		(50)
+#define MPX_DCC_UPPER_LIMIT	(20000)
+#define MPX_DCC_LIMIT		(12566)
+#define INVALID_CHANNEL		(0)
+#define VALID_CHANNEL		(1)
 
 #define COMPUTE_SPUR(val)	((((val) - (76000)) / (50)))
 #define GET_FREQ(val, bit)	((bit == 1) ? ((val) >> 8) : ((val) & 0xFF))
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index 390a843..cf99435 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -28,6 +28,7 @@
 #include <media/v4l2-common.h>
 #include <media/vcap_fmt.h>
 #include <mach/board.h>
+#include <mach/iommu_domains.h>
 
 #define to_client_data(val)     container_of(val, struct vcap_client_data, vfh)
 
@@ -94,7 +95,7 @@
 };
 
 struct nr_buffer {
-	void						*vaddr;
+	struct ion_handle			*nr_handle;
 	unsigned long				paddr;
 	enum nr_buf_pos				nr_pos;
 };
@@ -118,6 +119,7 @@
 
 	struct vcap_buffer      *bufOut;
 
+	struct ion_handle		*motionHandle;
 	void					*bufMotion;
 	struct nr_buffer		bufNR;
 	struct nr_param			nr_param;
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index a15d1f1..2918b94 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -289,6 +289,7 @@
 	atomic_t			queued_count;
 	struct list_head		done_list;
 	spinlock_t			done_lock;
+	struct mutex		q_lock;
 	wait_queue_head_t		done_wq;
 
 	void				*alloc_ctx[VIDEO_MAX_PLANES];
diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h
index 160e3f0..6d94c34 100644
--- a/include/net/bluetooth/sco.h
+++ b/include/net/bluetooth/sco.h
@@ -31,7 +31,7 @@
 #define SCO_DEFAULT_FLUSH_TO	0xFFFF
 
 #define SCO_CONN_TIMEOUT	(HZ * 40)
-#define SCO_DISCONN_TIMEOUT	(HZ * 2)
+#define SCO_DISCONN_TIMEOUT	(HZ * 20)
 #define SCO_CONN_IDLE_TIMEOUT	(HZ * 60)
 
 /* SCO socket address */
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 979db58..b7ddb08 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -561,6 +561,7 @@
 #define ADM_CMD_COPP_CLOSE                               0x00010305
 
 #define ADM_CMD_MULTI_CHANNEL_COPP_OPEN                  0x00010310
+#define ADM_CMD_MULTI_CHANNEL_COPP_OPEN_V3               0x00010333
 struct adm_multi_ch_copp_open_command {
 	struct apr_hdr hdr;
 	u16 flags;
@@ -573,7 +574,6 @@
 	u32 rate;
 	u8 dev_channel_mapping[8];
 } __packed;
-
 #define ADM_CMD_MEMORY_MAP				0x00010C30
 struct adm_cmd_memory_map{
 	struct apr_hdr	hdr;
@@ -618,6 +618,14 @@
 #define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY			0x00010F72
 #define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY		0x00010F75
 
+#define LOWLATENCY_POPP_TOPOLOGY			0x00010C68
+#define LOWLATENCY_COPP_TOPOLOGY			0x00010312
+#define PCM_BITS_PER_SAMPLE				16
+
+#define ASM_OPEN_WRITE_PERF_MODE_BIT			(1<<28)
+#define ASM_OPEN_READ_PERF_MODE_BIT			(1<<29)
+#define ADM_MULTI_CH_COPP_OPEN_PERF_MODE_BIT		(1<<13)
+
 /* SRS TRUMEDIA GUIDS */
 /* topology */
 #define SRS_TRUMEDIA_TOPOLOGY_ID			0x00010D90
@@ -741,6 +749,7 @@
 } __attribute__ ((packed));
 
 #define ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN               0x00010311
+#define ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN_V3            0x00010334
 
 
 #define ASM_STREAM_PRIORITY_NORMAL	0
@@ -1102,6 +1111,7 @@
 
 /* Stream level commands */
 #define ASM_STREAM_CMD_OPEN_READ                         0x00010BCB
+#define ASM_STREAM_CMD_OPEN_READ_V2_1                    0x00010DB2
 struct asm_stream_cmd_open_read {
 	struct apr_hdr hdr;
 	u32            uMode;
@@ -1110,6 +1120,16 @@
 	u32            format;
 } __attribute__((packed));
 
+struct asm_stream_cmd_open_read_v2_1 {
+	struct apr_hdr hdr;
+	u32            uMode;
+	u32            src_endpoint;
+	u32            pre_proc_top;
+	u32            format;
+	u16            bits_per_sample;
+	u16            reserved;
+} __packed;
+
 /* Supported formats */
 #define LINEAR_PCM   0x00010BE5
 #define DTMF         0x00010BE6
@@ -1158,6 +1178,7 @@
 } __packed;
 
 #define ASM_STREAM_CMD_OPEN_WRITE                        0x00010BCA
+#define ASM_STREAM_CMD_OPEN_WRITE_V2_1                   0x00010DB1
 struct asm_stream_cmd_open_write {
 	struct apr_hdr hdr;
 	u32            uMode;
diff --git a/include/sound/q6adm.h b/include/sound/q6adm.h
index 8e15955..676c4cb1 100644
--- a/include/sound/q6adm.h
+++ b/include/sound/q6adm.h
@@ -27,7 +27,7 @@
 int adm_open(int port, int path, int rate, int mode, int topology);
 
 int adm_multi_ch_copp_open(int port, int path, int rate, int mode,
-				int topology);
+				int topology, int perfmode);
 
 int adm_memory_map_regions(uint32_t *buf_add, uint32_t mempool_id,
 				uint32_t *bufsz, uint32_t bufcnt);
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index ea77974..01f2fac 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -160,6 +160,7 @@
 	uint32_t         io_mode;
 	uint64_t         time_stamp;
 	atomic_t         cmd_response;
+	bool             perf_mode;
 };
 
 void q6asm_audio_client_free(struct audio_client *ac);
@@ -182,6 +183,7 @@
 			struct audio_client *ac);
 
 int q6asm_open_read(struct audio_client *ac, uint32_t format);
+int q6asm_open_read_v2_1(struct audio_client *ac, uint32_t format);
 
 int q6asm_open_read_compressed(struct audio_client *ac,
 			 uint32_t frames_per_buffer, uint32_t meta_data_mode);
diff --git a/include/trace/events/irq.h b/include/trace/events/irq.h
index 1c09820..0296174 100644
--- a/include/trace/events/irq.h
+++ b/include/trace/events/irq.h
@@ -43,14 +43,17 @@
 	TP_STRUCT__entry(
 		__field(	int,	irq		)
 		__string(	name,	action->name	)
+		__field(void*,	handler)
 	),
 
 	TP_fast_assign(
 		__entry->irq = irq;
 		__assign_str(name, action->name);
+		__entry->handler = action->handler;
 	),
 
-	TP_printk("irq=%d name=%s", __entry->irq, __get_str(name))
+	TP_printk("irq=%d name=%s handler=%pf",
+		 __entry->irq, __get_str(name), __entry->handler)
 );
 
 /**
diff --git a/include/trace/events/timer.h b/include/trace/events/timer.h
index 425bcfe..dd53c79 100644
--- a/include/trace/events/timer.h
+++ b/include/trace/events/timer.h
@@ -43,15 +43,17 @@
  */
 TRACE_EVENT(timer_start,
 
-	TP_PROTO(struct timer_list *timer, unsigned long expires),
+	TP_PROTO(struct timer_list *timer,
+		 unsigned long expires, char deferrable),
 
-	TP_ARGS(timer, expires),
+	TP_ARGS(timer, expires, deferrable),
 
 	TP_STRUCT__entry(
 		__field( void *,	timer		)
 		__field( void *,	function	)
 		__field( unsigned long,	expires		)
 		__field( unsigned long,	now		)
+		__field(char,	deferrable)
 	),
 
 	TP_fast_assign(
@@ -59,11 +61,12 @@
 		__entry->function	= timer->function;
 		__entry->expires	= expires;
 		__entry->now		= jiffies;
+		__entry->deferrable     = deferrable;
 	),
 
-	TP_printk("timer=%p function=%pf expires=%lu [timeout=%ld]",
+	TP_printk("timer=%p function=%pf expires=%lu [timeout=%ld] defer=%c",
 		  __entry->timer, __entry->function, __entry->expires,
-		  (long)__entry->expires - __entry->now)
+		  (long)__entry->expires - __entry->now, __entry->deferrable)
 );
 
 /**
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 7697249..5d675a7 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -17,6 +17,7 @@
  */
 
 #include <linux/ftrace_event.h>
+#include <linux/coresight-stm.h>
 
 /*
  * DECLARE_EVENT_CLASS can be used to add a generic function
@@ -544,9 +545,12 @@
 									\
 	{ assign; }							\
 									\
-	if (!filter_current_check_discard(buffer, event_call, entry, event)) \
+	if (!filter_current_check_discard(buffer, event_call, entry, event)) { \
+		stm_log(OST_ENTITY_FTRACE_EVENTS, entry,		\
+			sizeof(*entry) + __data_size);			\
 		trace_nowake_buffer_unlock_commit(buffer,		\
 						  event, irq_flags, pc); \
+	}								\
 }
 /*
  * The ftrace_test_probe is compiled out, it is only here as a build time check
diff --git a/kernel/printk.c b/kernel/printk.c
index 1320c94..e21712a 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -41,6 +41,7 @@
 #include <linux/cpu.h>
 #include <linux/notifier.h>
 #include <linux/rculist.h>
+#include <linux/coresight-stm.h>
 
 #include <asm/uaccess.h>
 
@@ -962,6 +963,8 @@
 		}
 	}
 
+	stm_log(OST_ENTITY_PRINTK, printk_buf, printed_len);
+
 	/*
 	 * Copy the output into log_buf. If the caller didn't provide
 	 * the appropriate log prefix, we insert them here
diff --git a/kernel/timer.c b/kernel/timer.c
index a297ffc..24c5d20 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -584,7 +584,8 @@
 debug_activate(struct timer_list *timer, unsigned long expires)
 {
 	debug_timer_activate(timer);
-	trace_timer_start(timer, expires);
+	trace_timer_start(timer, expires,
+			 tbase_get_deferrable(timer->base) > 0 ? 'y' : 'n');
 }
 
 static inline void debug_deactivate(struct timer_list *timer)
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 05970ea..b9d1a73 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -38,6 +38,7 @@
 #include <linux/poll.h>
 #include <linux/nmi.h>
 #include <linux/fs.h>
+#include <linux/coresight-stm.h>
 
 #include "trace.h"
 #include "trace_output.h"
@@ -1629,6 +1630,7 @@
 	memcpy(&entry->buf, trace_buf, len);
 	entry->buf[len] = '\0';
 	if (!filter_check_discard(call, entry, buffer, event)) {
+		stm_log(OST_ENTITY_TRACE_PRINTK, event, size);
 		ring_buffer_unlock_commit(buffer, event);
 		ftrace_trace_stack(buffer, irq_flags, 6, pc);
 	}
@@ -3826,6 +3828,7 @@
 	} else
 		entry->buf[cnt] = '\0';
 
+	stm_log(OST_ENTITY_TRACE_MARKER, event, size);
 	ring_buffer_unlock_commit(buffer, event);
 
 	written = cnt;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 0563af9..08bf42da 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -393,7 +393,9 @@
 
 	BT_DBG("conn %p mode %d", conn, conn->mode);
 
+	hci_dev_lock(conn->hdev);
 	hci_conn_enter_sniff_mode(conn);
+	hci_dev_unlock(conn->hdev);
 }
 
 static void hci_conn_rssi_update(struct work_struct *work)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 56bdd46..bf854c3 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2285,6 +2285,7 @@
 			if (count > hdev->acl_cnt)
 				return;
 
+			hci_dev_lock(hdev);
 			hci_conn_enter_active_mode(conn, bt_cb(skb)->force_active);
 
 			hci_send_frame(skb);
@@ -2294,6 +2295,7 @@
 			quote -= count;
 
 			conn->sent += count;
+			hci_dev_unlock(hdev);
 		}
 	}
 }
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index f83c108..6e8500b 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2929,8 +2929,16 @@
 static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_sniff_subrate *ev = (void *) skb->data;
+	struct hci_conn *conn =
+		hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
 
 	BT_DBG("%s status %d", hdev->name, ev->status);
+	if (conn && (ev->max_rx_latency > hdev->sniff_max_interval)) {
+		BT_ERR("value of rx_latency:%d", ev->max_rx_latency);
+		hci_dev_lock(hdev);
+		hci_conn_enter_active_mode(conn, 1);
+		hci_dev_unlock(hdev);
+	}
 }
 
 static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 0a89c11..d80c0e3 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -95,12 +95,12 @@
 
 static struct device *hidp_get_device(struct hidp_session *session)
 {
-	bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
-	bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
+	bdaddr_t *dst = &session->bdaddr;
+
 	struct device *device = NULL;
 	struct hci_dev *hdev;
 
-	hdev = hci_get_route(dst, src);
+	hdev = hci_get_route(dst, BDADDR_ANY);
 	if (!hdev)
 		return NULL;
 
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index f090a77..9669d4a 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -394,6 +394,15 @@
 
 	case BT_CONNECTED:
 	case BT_CONFIG:
+		if (sco_pi(sk)->conn) {
+			sk->sk_state = BT_DISCONN;
+			sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT);
+			hci_conn_put(sco_pi(sk)->conn->hcon);
+			sco_pi(sk)->conn->hcon = NULL;
+		} else
+			sco_chan_del(sk, ECONNRESET);
+		break;
+
 	case BT_CONNECT:
 	case BT_DISCONN:
 		sco_chan_del(sk, ECONNRESET);
@@ -803,6 +812,9 @@
 		if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
 			err = bt_sock_wait_state(sk, BT_CLOSED,
 							sk->sk_lingertime);
+		else
+			err = bt_sock_wait_state(sk, BT_CLOSED,
+							SCO_DISCONN_TIMEOUT);
 	}
 	release_sock(sk);
 	return err;
@@ -824,6 +836,11 @@
 		lock_sock(sk);
 		err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
 		release_sock(sk);
+	} else {
+		lock_sock(sk);
+		err = bt_sock_wait_state(sk, BT_CLOSED,
+							SCO_DISCONN_TIMEOUT);
+		release_sock(sk);
 	}
 
 	sock_orphan(sk);
@@ -857,7 +874,9 @@
 		conn->sk = NULL;
 		sco_pi(sk)->conn = NULL;
 		sco_conn_unlock(conn);
-		hci_conn_put(conn->hcon);
+
+		if (conn->hcon)
+			hci_conn_put(conn->hcon);
 	}
 
 	sk->sk_state = BT_CLOSED;
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 8129d97..5e5ad91 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -18,6 +18,7 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/skbuff.h>
+#include <linux/netdevice.h>
 #include <net/netlink.h>
 #include <net/pkt_sched.h>
 
@@ -176,6 +177,7 @@
 	struct prio_sched_data *q = qdisc_priv(sch);
 	struct tc_prio_qopt *qopt;
 	int i;
+	int flow_change = 0;
 
 	if (nla_len(opt) < sizeof(*qopt))
 		return -EINVAL;
@@ -190,7 +192,10 @@
 	}
 
 	sch_tree_lock(sch);
-	q->enable_flow = qopt->enable_flow;
+	if (q->enable_flow != qopt->enable_flow) {
+		q->enable_flow = qopt->enable_flow;
+		flow_change = 1;
+	}
 	q->bands = qopt->bands;
 	memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1);
 
@@ -225,6 +230,13 @@
 			}
 		}
 	}
+
+	/* Schedule qdisc when flow re-enabled */
+	if (flow_change && q->enable_flow) {
+		if (!test_bit(__QDISC_STATE_DEACTIVATED,
+			      &sch->state))
+			__netif_schedule(qdisc_root(sch));
+	}
 	return 0;
 }
 
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index deb67f5..776e193 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -3359,11 +3359,8 @@
 			"strcat"  => "strlcat",
 			"strncat"  => "strlcat",
 			"vsprintf"  => "vsnprintf",
-			"strcmp"  => "strncmp",
-			"strcasecmp" => "strncasecmp",
 			"strchr" => "strnchr",
 			"strstr" => "strnstr",
-			"strlen" => "strnlen",
 		);
 		foreach my $k (keys %str_fns) {
 			if ($line =~ /\b$k\b/) {
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index f4f55fa..32565bc 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -38,6 +38,8 @@
 
 #define WCD9304_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
 			SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_48000)
+#define ADC_DMIC_SEL_ADC	0
+#define	ADC_DMIC_SEL_DMIC	1
 
 #define NUM_DECIMATORS 4
 #define NUM_INTERPOLATORS 3
@@ -812,17 +814,106 @@
 static const struct snd_kcontrol_new sb_tx1_mux =
 	SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
 
+static int wcd9304_put_dec_enum(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+	{
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *w = wlist->widgets[0];
+	struct snd_soc_codec *codec = w->codec;
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int dec_mux, decimator;
+	char *dec_name = NULL;
+	char *widget_name = NULL;
+	char *temp;
+	u16 tx_mux_ctl_reg;
+	u8 adc_dmic_sel = 0x0;
+	int ret = 0;
+
+	if (ucontrol->value.enumerated.item[0] > e->max - 1)
+		return -EINVAL;
+
+	dec_mux = ucontrol->value.enumerated.item[0];
+
+	widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+	if (!widget_name)
+		return -ENOMEM;
+	temp = widget_name;
+
+	dec_name = strsep(&widget_name, " ");
+	widget_name = temp;
+	if (!dec_name) {
+		pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = kstrtouint(strpbrk(dec_name, "1234"), 10, &decimator);
+	if (ret < 0) {
+		pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	dev_dbg(w->dapm->dev, "%s(): widget = %s dec_name = %s decimator = %u"\
+		"dec_mux = %u\n", __func__, w->name, dec_name, decimator,
+		dec_mux);
+
+
+	switch (decimator) {
+	case 1:
+	case 2:
+		if ((dec_mux == 1) || (dec_mux == 6))
+			adc_dmic_sel = ADC_DMIC_SEL_DMIC;
+		else
+			adc_dmic_sel = ADC_DMIC_SEL_ADC;
+		break;
+	case 3:
+		if ((dec_mux == 1) || (dec_mux == 6) || (dec_mux == 7))
+			adc_dmic_sel = ADC_DMIC_SEL_DMIC;
+		else
+			adc_dmic_sel = ADC_DMIC_SEL_ADC;
+		break;
+	case 4:
+		if ((dec_mux == 1) || (dec_mux == 5)
+			|| (dec_mux == 6) || (dec_mux == 7))
+			adc_dmic_sel = ADC_DMIC_SEL_DMIC;
+		else
+			adc_dmic_sel = ADC_DMIC_SEL_ADC;
+		break;
+	default:
+		pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
+
+	snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
+
+	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+out:
+	kfree(widget_name);
+	return ret;
+}
+
+#define WCD9304_DEC_ENUM(xname, xenum) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_enum_double, \
+	.get = snd_soc_dapm_get_enum_double, \
+	.put = wcd9304_put_dec_enum, \
+	.private_value = (unsigned long)&xenum }
+
 static const struct snd_kcontrol_new dec1_mux =
-	SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
+	WCD9304_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
 
 static const struct snd_kcontrol_new dec2_mux =
-	SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
+	WCD9304_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
 
 static const struct snd_kcontrol_new dec3_mux =
-	SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
+	WCD9304_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
 
 static const struct snd_kcontrol_new dec4_mux =
-	SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
+	WCD9304_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
 
 static const struct snd_kcontrol_new iir1_inp1_mux =
 	SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
@@ -970,7 +1061,7 @@
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
-	u16 tx_dmic_ctl_reg, tx_mux_ctl_reg;
+	u16 tx_dmic_ctl_reg;
 	u8 dmic_clk_sel, dmic_clk_en;
 	unsigned int dmic;
 	int ret;
@@ -1000,15 +1091,12 @@
 		return -EINVAL;
 	}
 
-	tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
 	tx_dmic_ctl_reg = SITAR_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
 
 	pr_debug("%s %d\n", __func__, event);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x01, 0x01);
-
 		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
 				dmic_clk_sel, dmic_clk_sel);
 
@@ -1020,8 +1108,6 @@
 	case SND_SOC_DAPM_POST_PMD:
 		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
 				dmic_clk_en, 0);
-
-		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x01, 0x00);
 		break;
 	}
 	return 0;
@@ -1573,10 +1659,22 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		if (w->reg == SITAR_A_RX_HPH_L_DAC_CTL) {
+			snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
+				0x30, 0x20);
+			snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
+				0x0C, 0x08);
+		}
 		snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
+		if (w->reg == SITAR_A_RX_HPH_L_DAC_CTL) {
+			snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
+				0x30, 0x10);
+			snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
+				0x0C, 0x04);
+		}
 		break;
 	}
 	return 0;
@@ -2018,13 +2116,16 @@
 	{"HEADPHONE", NULL, "HPHL"},
 	{"HEADPHONE", NULL, "HPHR"},
 
+
 	{"HPHL DAC", NULL, "CP"},
 	{"HPHR DAC", NULL, "CP"},
 
 	{"HPHL", NULL, "HPHL DAC"},
-	{"HPHL DAC", "NULL", "DAC4 MUX"},
+	{"HPHL DAC", "NULL", "RX2 CHAIN"},
+	{"RX2 CHAIN", NULL, "DAC4 MUX"},
 	{"HPHR", NULL, "HPHR DAC"},
-	{"HPHR DAC", NULL, "RX3 MIX1"},
+	{"HPHR DAC", NULL, "RX3 CHAIN"},
+	{"RX3 CHAIN", NULL, "RX3 MIX1"},
 
 	{"DAC1 MUX", "RX1", "RX1 CHAIN"},
 	{"DAC2 MUX", "RX1", "RX1 CHAIN"},
@@ -2459,19 +2560,6 @@
 	return 0;
 }
 
-static void sitar_shutdown(struct snd_pcm_substream *substream,
-		struct snd_soc_dai *dai)
-{
-	struct wcd9xxx *wcd9xxx = dev_get_drvdata(dai->codec->dev->parent);
-	if ((wcd9xxx != NULL) && (wcd9xxx->dev != NULL) &&
-			(wcd9xxx->dev->parent != NULL)) {
-		pm_runtime_mark_last_busy(wcd9xxx->dev->parent);
-		pm_runtime_put(wcd9xxx->dev->parent);
-	}
-	pr_debug("%s(): substream = %s  stream = %d\n" , __func__,
-		substream->name, substream->stream);
-}
-
 int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
 {
 	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
@@ -2767,7 +2855,6 @@
 
 static struct snd_soc_dai_ops sitar_dai_ops = {
 	.startup = sitar_startup,
-	.shutdown = sitar_shutdown,
 	.hw_params = sitar_hw_params,
 	.set_sysclk = sitar_set_dai_sysclk,
 	.set_fmt = sitar_set_dai_fmt,
@@ -2872,6 +2959,15 @@
 	return ret;
 }
 
+static void sitar_codec_pm_runtime_put(struct wcd9xxx *sitar)
+{
+	if (sitar->dev != NULL &&
+			sitar->dev->parent != NULL) {
+		pm_runtime_mark_last_busy(sitar->dev->parent);
+		pm_runtime_put(sitar->dev->parent);
+	}
+}
+
 static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -2881,9 +2977,14 @@
 	u32  j = 0, ret = 0;
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
 	sitar = codec->control_data;
+
 	/* Execute the callback only if interface type is slimbus */
-	if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+	if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		if (event == SND_SOC_DAPM_POST_PMD && (sitar != NULL))
+			sitar_codec_pm_runtime_put(sitar);
 		return 0;
+	}
+
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
@@ -2922,6 +3023,8 @@
 					sitar_p->dai[j].ch_tot));
 			sitar_p->dai[j].ch_tot = 0;
 			ret = sitar_codec_enable_chmask(sitar_p, event, j);
+			if (sitar != NULL)
+				sitar_codec_pm_runtime_put(sitar);
 		}
 	}
 	return ret;
@@ -2940,8 +3043,12 @@
 	sitar = codec->control_data;
 
 	/* Execute the callback only if interface type is slimbus */
-	if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+	if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		if (event == SND_SOC_DAPM_POST_PMD && (sitar != NULL))
+			sitar_codec_pm_runtime_put(sitar);
 		return 0;
+	}
+
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
@@ -2980,6 +3087,8 @@
 					sitar_p->dai[j].ch_tot));
 			sitar_p->dai[j].ch_tot = 0;
 			ret = sitar_codec_enable_chmask(sitar_p, event, j);
+			if (sitar != NULL)
+				sitar_codec_pm_runtime_put(sitar);
 		}
 	}
 	return ret;
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 15a5567..4758829 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -35,6 +35,10 @@
 #include <linux/gpio.h>
 #include "wcd9310.h"
 
+static int cfilt_adjust_ms = 10;
+module_param(cfilt_adjust_ms, int, 0644);
+MODULE_PARM_DESC(cfilt_adjust_ms, "delay after adjusting cfilt voltage in ms");
+
 #define WCD9310_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
 			SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
 			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
@@ -2240,26 +2244,26 @@
 	}
 	snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
 
-	if (!tabla->no_mic_headset_override) {
-		if (mbhc_state == MBHC_STATE_POTENTIAL) {
-			pr_debug("%s recovering MBHC state macine\n", __func__);
-			tabla->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
-			/* set to max button press threshold */
-			snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
-				      0x7F);
-			snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
-				      0xFF);
-			snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
-				      (TABLA_IS_1_X(tabla_core->version) ?
-				       0x07 : 0x7F));
-			snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
-				      0xFF);
-			/* set to max */
-			snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
-				      0x7F);
-			snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
-				      0xFF);
-		}
+	if (tabla->no_mic_headset_override) {
+		pr_debug("%s setting button threshold to min", __func__);
+		/* set to min */
+		snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x80);
+		snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0x00);
+		snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL, 0x80);
+		snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL, 0x00);
+	} else if (unlikely(mbhc_state == MBHC_STATE_POTENTIAL)) {
+		pr_debug("%s recovering MBHC state machine\n", __func__);
+		tabla->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
+		/* set to max button press threshold */
+		snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL, 0x7F);
+		snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL, 0xFF);
+		snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
+			      (TABLA_IS_1_X(tabla_core->version) ?
+			       0x07 : 0x7F));
+		snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0xFF);
+		/* set to max */
+		snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL, 0x7F);
+		snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL, 0xFF);
 	}
 
 	snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
@@ -2479,11 +2483,11 @@
 			cfilt_k_val = tabla_find_k_value(
 						   tabla->pdata->micbias.ldoh_v,
 						   VDDIO_MICBIAS_MV);
-			usleep_range(10000, 10000);
 			snd_soc_update_bits(codec,
 					    tabla->mbhc_bias_regs.cfilt_val,
 					    0xFC, (cfilt_k_val << 2));
-			usleep_range(10000, 10000);
+			usleep_range(cfilt_adjust_ms * 1000,
+				     cfilt_adjust_ms * 1000);
 			snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
 				      tabla->mbhc_data.adj_v_ins_hu & 0xFF);
 			snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
@@ -2517,7 +2521,8 @@
 			snd_soc_update_bits(codec,
 					    tabla->mbhc_bias_regs.cfilt_val,
 					    0xFC, (cfilt_k_val << 2));
-			usleep_range(10000, 10000);
+			usleep_range(cfilt_adjust_ms * 1000,
+				     cfilt_adjust_ms * 1000);
 			snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
 				      tabla->mbhc_data.v_ins_hu & 0xFF);
 			snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
@@ -3687,19 +3692,9 @@
 	return v_hs_max;
 }
 
-static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
+static void tabla_codec_calibrate_rel(struct snd_soc_codec *codec)
 {
-	u8 *n_ready, *n_cic;
-	struct tabla_mbhc_btn_detect_cfg *btn_det;
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-	const s16 v_ins_hu = tabla_get_current_v_ins(tabla, true);
-
-	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
-
-	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
-		      v_ins_hu & 0xFF);
-	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
-		      (v_ins_hu >> 8) & 0xFF);
 
 	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
 		      tabla->mbhc_data.v_b1_hu & 0xFF);
@@ -3720,6 +3715,23 @@
 		      tabla->mbhc_data.v_brl & 0xFF);
 	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
 		      (tabla->mbhc_data.v_brl >> 8) & 0xFF);
+}
+
+static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
+{
+	u8 *n_ready, *n_cic;
+	struct tabla_mbhc_btn_detect_cfg *btn_det;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	const s16 v_ins_hu = tabla_get_current_v_ins(tabla, true);
+
+	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
+
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
+		      v_ins_hu & 0xFF);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
+		      (v_ins_hu >> 8) & 0xFF);
+
+	tabla_codec_calibrate_rel(codec);
 
 	n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
 	snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
@@ -3871,11 +3883,22 @@
 		}
 	} else if (dai->id == AIF1_CAP || dai->id == AIF2_CAP ||
 		   dai->id == AIF3_CAP) {
-		for (i = 0; i < tx_num; i++) {
-			tabla->dai[dai->id - 1].ch_num[i]  = tx_slot[i];
-			tabla->dai[dai->id - 1].ch_act = 0;
-			tabla->dai[dai->id - 1].ch_tot = tx_num;
+		tabla->dai[dai->id - 1].ch_tot = tx_num;
+		/* All channels are already active.
+		 * do not reset ch_act flag
+		 */
+		if ((tabla->dai[dai->id - 1].ch_tot != 0)
+			&& (tabla->dai[dai->id - 1].ch_act ==
+			tabla->dai[dai->id - 1].ch_tot)) {
+			pr_info("%s: ch_act = %d, ch_tot = %d\n", __func__,
+				tabla->dai[dai->id - 1].ch_act,
+				tabla->dai[dai->id - 1].ch_tot);
+			return 0;
 		}
+
+		tabla->dai[dai->id - 1].ch_act = 0;
+		for (i = 0; i < tx_num; i++)
+			tabla->dai[dai->id - 1].ch_num[i]  = tx_slot[i];
 	}
 	return 0;
 }
@@ -5671,15 +5694,55 @@
 	return r;
 }
 
+static void tabla_mbhc_calc_rel_thres(struct snd_soc_codec *codec, s16 mv)
+{
+	s16 deltamv;
+	struct tabla_priv *tabla;
+	struct tabla_mbhc_btn_detect_cfg *btn_det;
+
+	tabla = snd_soc_codec_get_drvdata(codec);
+	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
+
+	tabla->mbhc_data.v_b1_h =
+	    tabla_codec_v_sta_dce(codec, DCE,
+				  mv + btn_det->v_btn_press_delta_cic);
+
+	tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
+
+	tabla->mbhc_data.v_brl = TABLA_MBHC_BUTTON_MIN;
+
+	deltamv = mv + btn_det->v_btn_press_delta_sta;
+	tabla->mbhc_data.v_b1_hu = tabla_codec_v_sta_dce(codec, STA, deltamv);
+
+	deltamv = mv + btn_det->v_btn_press_delta_cic;
+	tabla->mbhc_data.v_b1_huc = tabla_codec_v_sta_dce(codec, DCE, deltamv);
+}
+
+static void tabla_mbhc_set_rel_thres(struct snd_soc_codec *codec, s16 mv)
+{
+	tabla_mbhc_calc_rel_thres(codec, mv);
+	tabla_codec_calibrate_rel(codec);
+}
+
+static s16 tabla_mbhc_highest_btn_mv(struct snd_soc_codec *codec)
+{
+	struct tabla_priv *tabla;
+	struct tabla_mbhc_btn_detect_cfg *btn_det;
+	u16 *btn_high;
+
+	tabla = snd_soc_codec_get_drvdata(codec);
+	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
+	btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
+
+	return btn_high[btn_det->num_btn - 1];
+}
+
 static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
 {
 	struct tabla_priv *tabla;
-	s16 btn_mv = 0, btn_delta_mv;
 	struct tabla_mbhc_btn_detect_cfg *btn_det;
 	struct tabla_mbhc_plug_type_cfg *plug_type;
-	u16 *btn_high;
 	u8 *n_ready;
-	int i;
 
 	tabla = snd_soc_codec_get_drvdata(codec);
 	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
@@ -5730,22 +5793,7 @@
 					     false);
 	}
 
-	btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
-	for (i = 0; i < btn_det->num_btn; i++)
-		btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
-
-	tabla->mbhc_data.v_b1_h = tabla_codec_v_sta_dce(codec, DCE, btn_mv);
-	btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
-	tabla->mbhc_data.v_b1_hu =
-	    tabla_codec_v_sta_dce(codec, STA, btn_delta_mv);
-
-	btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
-
-	tabla->mbhc_data.v_b1_huc =
-	    tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
-
-	tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
-	tabla->mbhc_data.v_brl = TABLA_MBHC_BUTTON_MIN;
+	tabla_mbhc_calc_rel_thres(codec, tabla_mbhc_highest_btn_mv(codec));
 
 	tabla->mbhc_data.v_no_mic =
 	    tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
@@ -5904,8 +5952,9 @@
 {
 	int i, mask;
 	short dce, sta;
-	s32 mv, mv_s, stamv_s;
+	s32 mv, mv_s, stamv, stamv_s;
 	bool vddio;
+	u16 *btn_high;
 	int btn = -1, meas = 0;
 	struct tabla_priv *priv = data;
 	const struct tabla_mbhc_btn_detect_cfg *d =
@@ -5918,6 +5967,7 @@
 
 	pr_debug("%s: enter\n", __func__);
 
+	btn_high = tabla_mbhc_cal_btn_det_mp(d, TABLA_BTN_DET_V_BTN_HIGH);
 	TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
 	if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
 		pr_debug("%s: mbhc is being recovered, skip button press\n",
@@ -5954,35 +6004,34 @@
 			pr_debug("%s: Button is already released shortly after "
 				 "resume\n", __func__);
 			n_btn_meas = 0;
-		} else {
-			pr_debug("%s: Button is already released without "
-				 "resume", __func__);
-			sta = tabla_codec_read_sta_result(codec);
-			stamv_s = tabla_codec_sta_dce_v(codec, 0, sta);
-			if (vddio)
-				stamv_s = tabla_scale_v_micb_vddio(priv,
-								   stamv_s,
-								   false);
-			btn = tabla_determine_button(priv, mv_s);
-			if (btn != tabla_determine_button(priv, stamv_s))
-				btn = -1;
-			goto done;
 		}
 	}
 
-	/* determine pressed button */
+	/* save hw dce */
 	btnmeas[meas++] = tabla_determine_button(priv, mv_s);
-	pr_debug("%s: meas %d - DCE %d,%d,%d button %d\n", __func__,
-		 meas - 1, dce, mv, mv_s, btnmeas[meas - 1]);
-	if (n_btn_meas == 0)
-		btn = btnmeas[0];
+	pr_debug("%s: meas HW - DCE %x,%d,%d button %d\n", __func__,
+		 dce, mv, mv_s, btnmeas[0]);
+	if (n_btn_meas == 0) {
+		sta = tabla_codec_read_sta_result(codec);
+		stamv_s = stamv = tabla_codec_sta_dce_v(codec, 0, sta);
+		if (vddio)
+			stamv_s = tabla_scale_v_micb_vddio(priv, stamv, false);
+		btn = tabla_determine_button(priv, stamv_s);
+		pr_debug("%s: meas HW - STA %x,%d,%d button %d\n", __func__,
+			 sta, stamv, stamv_s, btn);
+		BUG_ON(meas != 1);
+		if (btnmeas[0] != btn)
+			btn = -1;
+	}
+
+	/* determine pressed button */
 	for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
 		dce = tabla_codec_sta_dce(codec, 1, false);
 		mv = tabla_codec_sta_dce_v(codec, 1, dce);
 		mv_s = vddio ? tabla_scale_v_micb_vddio(priv, mv, false) : mv;
 
 		btnmeas[meas] = tabla_determine_button(priv, mv_s);
-		pr_debug("%s: meas %d - DCE %d,%d,%d button %d\n",
+		pr_debug("%s: meas %d - DCE %x,%d,%d button %d\n",
 			 __func__, meas, dce, mv, mv_s, btnmeas[meas]);
 		/* if large enough measurements are collected,
 		 * start to check if last all n_btn_con measurements were
@@ -6010,6 +6059,8 @@
 				 "press\n", __func__);
 			goto done;
 		}
+		/* narrow down release threshold */
+		tabla_mbhc_set_rel_thres(codec, btn_high[btn]);
 		mask = tabla_get_button_mask(btn);
 		priv->buttons_pressed |= mask;
 		wcd9xxx_lock_sleep(core);
@@ -6115,6 +6166,8 @@
 		priv->buttons_pressed &= ~TABLA_JACK_BUTTON_MASK;
 	}
 
+	/* revert narrowed release threshold */
+	tabla_mbhc_calc_rel_thres(codec, tabla_mbhc_highest_btn_mv(codec));
 	tabla_codec_calibrate_hs_polling(codec);
 
 	if (priv->mbhc_cfg.gpio)
@@ -7729,9 +7782,15 @@
 
 	lbuf[cnt] = '\0';
 	buf = (char *)lbuf;
-	tabla->no_mic_headset_override = (*strsep(&buf, " ") == '0') ?
-					     false : true;
-	return rc;
+	TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+	tabla->no_mic_headset_override =
+	    (*strsep(&buf, " ") == '0') ? false : true;
+	if (tabla->no_mic_headset_override && tabla->mbhc_polling_active) {
+		tabla_codec_pause_hs_polling(tabla->codec);
+		tabla_codec_start_hs_polling(tabla->codec);
+	}
+	TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+	return cnt;
 }
 
 static ssize_t codec_mbhc_debug_read(struct file *file, char __user *buf,
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 6da9166..01820eb 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -6817,18 +6817,21 @@
 	struct snd_soc_codec *codec = taiko->codec;
 	struct wcd9xxx_pdata *pdata = taiko->pdata;
 	int k1, k2, k3, rc = 0;
-	u8 leg_mode = pdata->amic_settings.legacy_mode;
-	u8 txfe_bypass = pdata->amic_settings.txfe_enable;
-	u8 txfe_buff = pdata->amic_settings.txfe_buff;
-	u8 flag = pdata->amic_settings.use_pdata;
+	u8 leg_mode, txfe_bypass, txfe_buff, flag;
 	u8 i = 0, j = 0;
 	u8 val_txfe = 0, value = 0;
 
 	if (!pdata) {
+		pr_err("%s: NULL pdata\n", __func__);
 		rc = -ENODEV;
 		goto done;
 	}
 
+	leg_mode = pdata->amic_settings.legacy_mode;
+	txfe_bypass = pdata->amic_settings.txfe_enable;
+	txfe_buff = pdata->amic_settings.txfe_buff;
+	flag = pdata->amic_settings.use_pdata;
+
 	/* Make sure settings are correct */
 	if ((pdata->micbias.ldoh_v > TAIKO_LDOH_2P85_V) ||
 	    (pdata->micbias.bias1_cfilt_sel > TAIKO_CFILT3_SEL) ||
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 43c678d..390c314 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -56,7 +56,7 @@
 
 obj-$(CONFIG_SND_SOC_MSM_QDSP6_INTF) += qdsp6/
 
-snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
+snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
 obj-$(CONFIG_SND_SOC_MSM_QDSP6_HDMI_AUDIO) += msm-dai-q6-hdmi.o
 obj-$(CONFIG_SND_SOC_VOICE) += msm-pcm-voice.o msm-pcm-voip.o
 snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index 6d3a331..17b8e30 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -830,7 +830,7 @@
 #undef S
 #define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
 	S(v_no_mic, 30);
-	S(v_hs_max, 1550);
+	S(v_hs_max, 2400);
 #undef S
 #define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
 	S(c[0], 62);
@@ -848,24 +848,24 @@
 	btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
 	btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
 	btn_low[0] = -50;
-	btn_high[0] = 10;
-	btn_low[1] = 11;
-	btn_high[1] = 38;
-	btn_low[2] = 39;
-	btn_high[2] = 64;
-	btn_low[3] = 65;
-	btn_high[3] = 91;
-	btn_low[4] = 92;
-	btn_high[4] = 115;
-	btn_low[5] = 116;
-	btn_high[5] = 141;
-	btn_low[6] = 142;
-	btn_high[6] = 163;
-	btn_low[7] = 164;
-	btn_high[7] = 250;
+	btn_high[0] = 20;
+	btn_low[1] = 21;
+	btn_high[1] = 62;
+	btn_low[2] = 62;
+	btn_high[2] = 104;
+	btn_low[3] = 105;
+	btn_high[3] = 143;
+	btn_low[4] = 144;
+	btn_high[4] = 181;
+	btn_low[5] = 182;
+	btn_high[5] = 218;
+	btn_low[6] = 219;
+	btn_high[6] = 254;
+	btn_low[7] = 255;
+	btn_high[7] = 330;
 	n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
-	n_ready[0] = 48;
-	n_ready[1] = 38;
+	n_ready[0] = 80;
+	n_ready[1] = 68;
 	n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
 	n_cic[0] = 60;
 	n_cic[1] = 47;
@@ -1724,6 +1724,37 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
+	{
+		.name = "VoLTE",
+		.stream_name = "VoLTE",
+		.cpu_dai_name   = "VoLTE",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_VOLTE,
+	},
+	{
+		.name = "MSM8960 LowLatency",
+		.stream_name = "MultiMedia5",
+		.cpu_dai_name   = "MultiMedia5",
+		.platform_name  = "msm-lowlatency-pcm-dsp",
+		.dynamic = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+	},
 	/* Backend DAI Links */
 	{
 		.name = LPASS_BE_SLIMBUS_0_RX,
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 35cbb5b..1dbd698 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -548,6 +548,7 @@
 	}
 	prtd = &compr->prtd;
 	prtd->substream = substream;
+	prtd->audio_client->perf_mode = false;
 	prtd->audio_client = q6asm_audio_client_alloc(
 				(app_cb)compr_event_handler, compr);
 	if (!prtd->audio_client) {
@@ -768,7 +769,9 @@
 			}
 			msm_pcm_routing_reg_phy_stream(
 				soc_prtd->dai_link->be_id,
-				prtd->session_id, substream->stream);
+				prtd->audio_client->perf_mode,
+				prtd->session_id,
+				substream->stream);
 
 			break;
 		}
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 4cd4a2c..011ff29 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -203,6 +203,17 @@
 			.rate_min =	8000,
 			.rate_max = 48000,
 		},
+		.capture = {
+			.stream_name = "MultiMedia5 Capture",
+			.aif_name = "MM_UL5",
+			.rates = (SNDRV_PCM_RATE_8000_48000|
+					SNDRV_PCM_RATE_KNOT),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min =     8000,
+			.rate_max =	48000,
+		},
 		.ops = &msm_fe_Multimedia_dai_ops,
 		.name = "MultiMedia5",
 	},
diff --git a/sound/soc/msm/msm-lowlatency-pcm-q6.c b/sound/soc/msm/msm-lowlatency-pcm-q6.c
new file mode 100644
index 0000000..129f69f
--- /dev/null
+++ b/sound/soc/msm/msm-lowlatency-pcm-q6.c
@@ -0,0 +1,756 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/android_pmem.h>
+#include <asm/dma.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+
+#include "msm-pcm-q6.h"
+#include "msm-pcm-routing.h"
+
+static struct audio_locks the_locks;
+
+struct snd_msm {
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+};
+
+struct snd_msm_volume {
+	struct msm_audio *prtd;
+	unsigned volume;
+};
+
+#define PLAYBACK_NUM_PERIODS		4
+#define PLAYBACK_MAX_PERIOD_SIZE	1024
+#define PLAYBACK_MIN_PERIOD_SIZE	512
+#define CAPTURE_NUM_PERIODS		4
+#define CAPTURE_MIN_PERIOD_SIZE		128
+#define CAPTURE_MAX_PERIOD_SIZE		1024
+
+static struct snd_pcm_hardware msm_pcm_hardware_capture = {
+	.info =                 (SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED |
+				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =                SNDRV_PCM_RATE_8000_48000,
+	.rate_min =             8000,
+	.rate_max =             48000,
+	.channels_min =         1,
+	.channels_max =         8,
+	.buffer_bytes_max =     CAPTURE_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE,
+	.period_bytes_min =	CAPTURE_MIN_PERIOD_SIZE,
+	.period_bytes_max =     CAPTURE_MAX_PERIOD_SIZE,
+	.periods_min =          CAPTURE_NUM_PERIODS,
+	.periods_max =          CAPTURE_NUM_PERIODS,
+	.fifo_size =            0,
+};
+
+static struct snd_pcm_hardware msm_pcm_hardware_playback = {
+	.info =                 (SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED |
+				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =                SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
+	.rate_min =             8000,
+	.rate_max =             48000,
+	.channels_min =         1,
+	.channels_max =         6,
+	.buffer_bytes_max =     PLAYBACK_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
+	.period_bytes_min =     PLAYBACK_MIN_PERIOD_SIZE,
+	.period_bytes_max =     PLAYBACK_MAX_PERIOD_SIZE,
+	.periods_min =          PLAYBACK_NUM_PERIODS,
+	.periods_max =          PLAYBACK_NUM_PERIODS,
+	.fifo_size =            0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+static uint32_t in_frame_info[CAPTURE_NUM_PERIODS][2];
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+	.count = ARRAY_SIZE(supported_sample_rates),
+	.list = supported_sample_rates,
+	.mask = 0,
+};
+
+static void event_handler(uint32_t opcode,
+		uint32_t token, uint32_t *payload, void *priv)
+{
+	struct msm_audio *prtd = priv;
+	struct snd_pcm_substream *substream = prtd->substream;
+	uint32_t *ptrmem = (uint32_t *)payload;
+	int i = 0;
+	uint32_t idx = 0;
+	uint32_t size = 0;
+
+	pr_debug("%s\n", __func__);
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE: {
+		pr_debug("ASM_DATA_EVENT_WRITE_DONE\n");
+		pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
+		prtd->pcm_irq_pos += prtd->pcm_count;
+		if (atomic_read(&prtd->start))
+			snd_pcm_period_elapsed(substream);
+		atomic_inc(&prtd->out_count);
+		wake_up(&the_locks.write_wait);
+		if (!atomic_read(&prtd->start))
+			break;
+		if (!prtd->mmap_flag)
+			break;
+		if (q6asm_is_cpu_buf_avail_nolock(IN,
+				prtd->audio_client,
+				&size, &idx)) {
+			pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
+					__func__, prtd->pcm_count);
+			q6asm_write_nolock(prtd->audio_client,
+				prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+		}
+		break;
+	}
+	case ASM_DATA_CMDRSP_EOS:
+		pr_debug("ASM_DATA_CMDRSP_EOS\n");
+		prtd->cmd_ack = 1;
+		wake_up(&the_locks.eos_wait);
+		break;
+	case ASM_DATA_EVENT_READ_DONE: {
+		pr_debug("ASM_DATA_EVENT_READ_DONE\n");
+		pr_debug("token = 0x%08x\n", token);
+		for (i = 0; i < 8; i++, ++ptrmem)
+			pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
+		in_frame_info[token][0] = payload[2];
+		in_frame_info[token][1] = payload[3];
+		prtd->pcm_irq_pos += in_frame_info[token][0];
+		pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
+		if (atomic_read(&prtd->start))
+			snd_pcm_period_elapsed(substream);
+		if (atomic_read(&prtd->in_count) <= prtd->periods)
+			atomic_inc(&prtd->in_count);
+		wake_up(&the_locks.read_wait);
+		if (prtd->mmap_flag
+			&& q6asm_is_cpu_buf_avail_nolock(OUT,
+				prtd->audio_client,
+				&size, &idx))
+			q6asm_read_nolock(prtd->audio_client);
+		break;
+	}
+	case APR_BASIC_RSP_RESULT: {
+		switch (payload[0]) {
+		case ASM_SESSION_CMD_RUN:
+			if (substream->stream
+				!= SNDRV_PCM_STREAM_PLAYBACK) {
+				atomic_set(&prtd->start, 1);
+				break;
+			}
+			if (prtd->mmap_flag) {
+				pr_debug("%s:writing %d bytes buffer to dsp\n",
+					__func__, prtd->pcm_count);
+				q6asm_write_nolock(prtd->audio_client,
+					prtd->pcm_count,
+					0, 0, NO_TIMESTAMP);
+			} else {
+				while (atomic_read(&prtd->out_needed)) {
+					pr_debug("%s:writing %d bytesto dsp\n",
+						__func__, prtd->pcm_count);
+					q6asm_write_nolock(prtd->audio_client,
+						prtd->pcm_count,
+						0, 0, NO_TIMESTAMP);
+					atomic_dec(&prtd->out_needed);
+					wake_up(&the_locks.write_wait);
+				};
+			}
+			atomic_set(&prtd->start, 1);
+			break;
+		default:
+			break;
+		}
+	}
+	break;
+	default:
+		pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
+		break;
+	}
+}
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int ret;
+
+	pr_debug("%s\n", __func__);
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = runtime->rate;
+	prtd->channel_mode = runtime->channels;
+	if (prtd->enabled)
+		return 0;
+
+	ret = q6asm_media_format_block_multi_ch_pcm(prtd->audio_client,
+			runtime->rate, runtime->channels);
+	if (ret < 0)
+		pr_info("%s: CMD Format block failed\n", __func__);
+
+	atomic_set(&prtd->out_count, runtime->periods);
+
+	prtd->enabled = 1;
+	prtd->cmd_ack = 0;
+
+	return 0;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int ret = 0;
+	int i = 0;
+	pr_debug("%s\n", __func__);
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = runtime->rate;
+	prtd->channel_mode = runtime->channels;
+
+	if (prtd->enabled)
+		return 0;
+
+	pr_debug("Samp_rate = %d\n", prtd->samp_rate);
+	pr_debug("Channel = %d\n", prtd->channel_mode);
+	ret = q6asm_enc_cfg_blk_pcm(prtd->audio_client, prtd->samp_rate,
+					prtd->channel_mode);
+	if (ret < 0)
+		pr_debug("%s: cmd cfg pcm was block failed", __func__);
+
+	for (i = 0; i < runtime->periods; i++)
+		q6asm_read(prtd->audio_client);
+	prtd->periods = runtime->periods;
+
+	prtd->enabled = 1;
+
+	return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		pr_debug("%s: Trigger start\n", __func__);
+		q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+		atomic_set(&prtd->start, 0);
+		if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+			break;
+		prtd->cmd_ack = 0;
+		q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
+		q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+		atomic_set(&prtd->start, 0);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct msm_audio *prtd;
+	int ret = 0;
+	pr_debug("%s lowlatency\n", __func__);
+	prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
+	if (prtd == NULL) {
+		pr_err("Failed to allocate memory for msm_audio\n");
+		return -ENOMEM;
+	}
+	prtd->substream = substream;
+	prtd->audio_client = q6asm_audio_client_alloc(
+				(app_cb)event_handler, prtd);
+	if (!prtd->audio_client) {
+		pr_err("%s: Could not allocate memory\n", __func__);
+		kfree(prtd);
+		return -ENOMEM;
+	}
+	prtd->audio_client->perf_mode = true;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		runtime->hw = msm_pcm_hardware_playback;
+		ret = q6asm_open_write(prtd->audio_client,
+				FORMAT_MULTI_CHANNEL_LINEAR_PCM);
+		if (ret < 0) {
+			pr_err("%s: pcm out open failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			kfree(prtd);
+			return -ENOMEM;
+		}
+	}
+	/* Capture path */
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		runtime->hw = msm_pcm_hardware_capture;
+		ret = q6asm_open_read_v2_1(prtd->audio_client,
+					FORMAT_LINEAR_PCM);
+		if (ret < 0) {
+			pr_err("%s: pcm in open failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			kfree(prtd);
+			return -ENOMEM;
+		}
+	}
+
+	pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
+
+	prtd->session_id = prtd->audio_client->session;
+	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+			prtd->audio_client->perf_mode,
+			prtd->session_id, substream->stream);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		prtd->cmd_ack = 1;
+
+	ret = snd_pcm_hw_constraint_list(runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE,
+				&constraints_sample_rates);
+	if (ret < 0)
+		pr_err("snd_pcm_hw_constraint_list failed\n");
+	/* Ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		pr_err("snd_pcm_hw_constraint_integer failed\n");
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret = snd_pcm_hw_constraint_minmax(runtime,
+			SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+			PLAYBACK_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
+			PLAYBACK_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
+		if (ret < 0) {
+			pr_err("constraint for buffer bytes min max ret = %d\n",
+									ret);
+		}
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		ret = snd_pcm_hw_constraint_minmax(runtime,
+			SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+			CAPTURE_NUM_PERIODS * CAPTURE_MIN_PERIOD_SIZE,
+			CAPTURE_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE);
+		if (ret < 0) {
+			pr_err("constraint for buffer bytes min max ret = %d\n",
+									ret);
+		}
+	}
+
+	prtd->dsp_cnt = 0;
+	runtime->private_data = prtd;
+	pr_debug("substream->pcm->device = %d\n", substream->pcm->device);
+	pr_debug("soc_prtd->dai_link->be_id = %d\n", soc_prtd->dai_link->be_id);
+	return 0;
+}
+
+static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
+	snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+	int fbytes = 0;
+	int xfer = 0;
+	char *bufptr = NULL;
+	void *data = NULL;
+	uint32_t idx = 0;
+	uint32_t size = 0;
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	fbytes = frames_to_bytes(runtime, frames);
+	pr_debug("%s: prtd->out_count = %d\n",
+				__func__, atomic_read(&prtd->out_count));
+	ret = wait_event_timeout(the_locks.write_wait,
+			(atomic_read(&prtd->out_count)), 5 * HZ);
+	if (ret < 0) {
+		pr_err("%s: wait_event_timeout failed\n", __func__);
+		goto fail;
+	}
+
+	if (!atomic_read(&prtd->out_count)) {
+		pr_err("%s: pcm stopped out_count 0\n", __func__);
+		return 0;
+	}
+
+	data = q6asm_is_cpu_buf_avail(IN, prtd->audio_client, &size, &idx);
+	bufptr = data;
+	if (bufptr) {
+		pr_debug("%s:fbytes =%d: xfer=%d size=%d\n",
+					__func__, fbytes, xfer, size);
+		xfer = fbytes;
+		if (copy_from_user(bufptr, buf, xfer)) {
+			ret = -EFAULT;
+			goto fail;
+		}
+		buf += xfer;
+		fbytes -= xfer;
+		pr_debug("%s:fbytes = %d: xfer=%d\n", __func__, fbytes, xfer);
+		if (atomic_read(&prtd->start)) {
+			pr_debug("%s:writing %d bytes of buffer to dsp\n",
+					__func__, xfer);
+			ret = q6asm_write(prtd->audio_client, xfer,
+						0, 0, NO_TIMESTAMP);
+			if (ret < 0) {
+				ret = -EFAULT;
+				goto fail;
+			}
+		} else
+			atomic_inc(&prtd->out_needed);
+		atomic_dec(&prtd->out_count);
+	}
+fail:
+	return  ret;
+}
+
+static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct msm_audio *prtd = runtime->private_data;
+	int dir = 0;
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+
+	dir = IN;
+	ret = wait_event_timeout(the_locks.eos_wait,
+				prtd->cmd_ack, 5 * HZ);
+	if (ret < 0)
+		pr_err("%s: CMD_EOS failed\n", __func__);
+	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	q6asm_audio_client_buf_free_contiguous(dir,
+				prtd->audio_client);
+
+	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+			SNDRV_PCM_STREAM_PLAYBACK);
+	q6asm_audio_client_free(prtd->audio_client);
+	kfree(prtd);
+	return 0;
+}
+
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+		 int channel, snd_pcm_uframes_t hwoff, void __user *buf,
+						 snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+	int fbytes = 0;
+	int xfer;
+	char *bufptr;
+	void *data = NULL;
+	static uint32_t idx;
+	static uint32_t size;
+	uint32_t offset = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = substream->runtime->private_data;
+
+
+	pr_debug("%s\n", __func__);
+	fbytes = frames_to_bytes(runtime, frames);
+
+	pr_debug("appl_ptr %d\n", (int)runtime->control->appl_ptr);
+	pr_debug("hw_ptr %d\n", (int)runtime->status->hw_ptr);
+	pr_debug("avail_min %d\n", (int)runtime->control->avail_min);
+
+	ret = wait_event_timeout(the_locks.read_wait,
+			(atomic_read(&prtd->in_count)), 5 * HZ);
+	if (ret < 0) {
+		pr_debug("%s: wait_event_timeout failed\n", __func__);
+		goto fail;
+	}
+	if (!atomic_read(&prtd->in_count)) {
+		pr_debug("%s: pcm stopped in_count 0\n", __func__);
+		return 0;
+	}
+	pr_debug("Checking if valid buffer is available...%08x\n",
+						(unsigned int) data);
+	data = q6asm_is_cpu_buf_avail(OUT, prtd->audio_client, &size, &idx);
+	bufptr = data;
+	pr_debug("Size = %d\n", size);
+	pr_debug("fbytes = %d\n", fbytes);
+	pr_debug("idx = %d\n", idx);
+	if (bufptr) {
+		xfer = fbytes;
+		if (xfer > size)
+			xfer = size;
+		offset = in_frame_info[idx][1];
+		pr_debug("Offset value = %d\n", offset);
+		if (copy_to_user(buf, bufptr+offset, xfer)) {
+			pr_err("Failed to copy buf to user\n");
+			ret = -EFAULT;
+			goto fail;
+		}
+		fbytes -= xfer;
+		size -= xfer;
+		in_frame_info[idx][1] += xfer;
+		pr_debug("%s:fbytes = %d: size=%d: xfer=%d\n",
+					__func__, fbytes, size, xfer);
+		pr_debug(" Sending next buffer to dsp\n");
+		memset(&in_frame_info[idx], 0,
+			sizeof(uint32_t) * 2);
+		atomic_dec(&prtd->in_count);
+		ret = q6asm_read(prtd->audio_client);
+		if (ret < 0) {
+			pr_err("q6asm read failed\n");
+			ret = -EFAULT;
+			goto fail;
+		}
+	} else
+		pr_err("No valid buffer\n");
+
+	pr_debug("Returning from capture_copy... %d\n", ret);
+fail:
+	return ret;
+}
+
+static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct msm_audio *prtd = runtime->private_data;
+	int dir = OUT;
+
+	pr_debug("%s\n", __func__);
+	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	q6asm_audio_client_buf_free_contiguous(dir,
+				prtd->audio_client);
+	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+			SNDRV_PCM_STREAM_CAPTURE);
+	q6asm_audio_client_free(prtd->audio_client);
+	kfree(prtd);
+
+	return 0;
+}
+
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+	 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+	return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_close(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_close(substream);
+	return ret;
+}
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_prepare(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_prepare(substream);
+	return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	if (prtd->pcm_irq_pos >= prtd->pcm_size)
+		prtd->pcm_irq_pos = 0;
+
+	pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
+	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int msm_pcm_mmap(struct snd_pcm_substream *substream,
+				struct vm_area_struct *vma)
+{
+	int result = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	pr_debug("%s\n", __func__);
+	prtd->mmap_flag = 1;
+
+	if (runtime->dma_addr && runtime->dma_bytes) {
+		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+		result = remap_pfn_range(vma, vma->vm_start,
+				runtime->dma_addr >> PAGE_SHIFT,
+				runtime->dma_bytes,
+				vma->vm_page_prot);
+	} else {
+		pr_err("Physical address or size of buf is NULL");
+		return -EINVAL;
+	}
+
+	return result;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+	struct audio_buffer *buf;
+	int dir, ret;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir = IN;
+	else
+		dir = OUT;
+
+	/*
+	 *TODO : Need to Add Async IO changes. All period
+	 * size might not be supported.
+	 */
+	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+		prtd->audio_client,
+		(params_buffer_bytes(params) / params_periods(params)),
+		params_periods(params));
+
+	if (ret < 0) {
+		pr_err("Audio Start: Buffer Allocation failed rc = %d\n", ret);
+		return -ENOMEM;
+	}
+	buf = prtd->audio_client->port[dir].buf;
+
+	pr_debug("%s:buf = %p\n", __func__, buf);
+	dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	dma_buf->dev.dev = substream->pcm->card->dev;
+	dma_buf->private_data = NULL;
+	dma_buf->area = buf[0].data;
+	dma_buf->addr =  buf[0].phys;
+	dma_buf->bytes = params_buffer_bytes(params);
+	if (!dma_buf->area)
+		return -ENOMEM;
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	return 0;
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open           = msm_pcm_open,
+	.copy		= msm_pcm_copy,
+	.hw_params	= msm_pcm_hw_params,
+	.close          = msm_pcm_close,
+	.ioctl          = snd_pcm_lib_ioctl,
+	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
+	.pointer        = msm_pcm_pointer,
+	.mmap		= msm_pcm_mmap,
+};
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	int ret = 0;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.ops		= &msm_pcm_ops,
+	.pcm_new	= msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_platform(&pdev->dev,
+				   &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+	.driver = {
+		.name = "msm-lowlatency-pcm-dsp",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	init_waitqueue_head(&the_locks.enable_wait);
+	init_waitqueue_head(&the_locks.eos_wait);
+	init_waitqueue_head(&the_locks.write_wait);
+	init_waitqueue_head(&the_locks.read_wait);
+
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("Multi channel PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-multi-ch-pcm-q6.c b/sound/soc/msm/msm-multi-ch-pcm-q6.c
index ef58dd1..2d23b48 100644
--- a/sound/soc/msm/msm-multi-ch-pcm-q6.c
+++ b/sound/soc/msm/msm-multi-ch-pcm-q6.c
@@ -330,6 +330,7 @@
 		return -ENOMEM;
 	}
 	prtd->substream = substream;
+	prtd->audio_client->perf_mode = false;
 	prtd->audio_client = q6asm_audio_client_alloc(
 				(app_cb)event_handler, prtd);
 	if (!prtd->audio_client) {
@@ -364,8 +365,8 @@
 
 	prtd->session_id = prtd->audio_client->session;
 	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+			prtd->audio_client->perf_mode,
 			prtd->session_id, substream->stream);
-
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		prtd->cmd_ack = 1;
 
diff --git a/sound/soc/msm/msm-pcm-afe.c b/sound/soc/msm/msm-pcm-afe.c
index 5f3cada..b7b4d51 100644
--- a/sound/soc/msm/msm-pcm-afe.c
+++ b/sound/soc/msm/msm-pcm-afe.c
@@ -140,9 +140,6 @@
 						runtime->channels * 2)));
 				pr_debug("prtd->poll_time: %d",
 						prtd->poll_time);
-				hrtimer_start(&prtd->hrt,
-					ns_to_ktime(0),
-					HRTIMER_MODE_REL);
 				break;
 			}
 			case AFE_EVENT_RTPORT_STOP:
@@ -206,9 +203,6 @@
 				snd_pcm_lib_period_bytes(prtd->substream)
 					* 1000 * 1000)/(runtime->rate
 					* runtime->channels * 2)));
-			hrtimer_start(&prtd->hrt,
-				ns_to_ktime(0),
-				HRTIMER_MODE_REL);
 			pr_debug("prtd->poll_time : %d", prtd->poll_time);
 			break;
 		}
@@ -465,6 +459,8 @@
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		pr_debug("%s: SNDRV_PCM_TRIGGER_START\n", __func__);
 		prtd->start = 1;
+		hrtimer_start(&prtd->hrt, ns_to_ktime(0),
+					HRTIMER_MODE_REL);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
diff --git a/sound/soc/msm/msm-pcm-lpa.c b/sound/soc/msm/msm-pcm-lpa.c
index 269b49b..116ce3e 100644
--- a/sound/soc/msm/msm-pcm-lpa.c
+++ b/sound/soc/msm/msm-pcm-lpa.c
@@ -282,6 +282,7 @@
 	}
 	runtime->hw = msm_pcm_hardware;
 	prtd->substream = substream;
+	prtd->audio_client->perf_mode = false;
 	prtd->audio_client = q6asm_audio_client_alloc(
 				(app_cb)event_handler, prtd);
 	if (!prtd->audio_client) {
@@ -311,6 +312,7 @@
 	pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
 	prtd->session_id = prtd->audio_client->session;
 	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+		prtd->audio_client->perf_mode,
 		prtd->session_id, substream->stream);
 
 	ret = snd_pcm_hw_constraint_list(runtime, 0,
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index 942c3ea..74136dc 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -324,6 +324,7 @@
 		kfree(prtd);
 		return -ENOMEM;
 	}
+	prtd->audio_client->perf_mode = false;
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		runtime->hw = msm_pcm_hardware_playback;
 		ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
@@ -338,6 +339,7 @@
 			prtd->audio_client->session);
 		prtd->session_id = prtd->audio_client->session;
 		msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+			prtd->audio_client->perf_mode,
 			prtd->session_id, substream->stream);
 		prtd->cmd_ack = 1;
 
@@ -443,7 +445,7 @@
 				prtd->audio_client);
 
 	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
-	SNDRV_PCM_STREAM_PLAYBACK);
+			SNDRV_PCM_STREAM_PLAYBACK);
 	q6asm_audio_client_free(prtd->audio_client);
 	kfree(prtd);
 	return 0;
@@ -649,8 +651,9 @@
 			prtd->audio_client->session);
 		prtd->session_id = prtd->audio_client->session;
 		msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+			prtd->audio_client->perf_mode,
 			prtd->session_id, substream->stream);
-	}
+		}
 
 	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
 			prtd->audio_client,
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index da3d335..374357d 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -38,6 +38,7 @@
 	unsigned long port_sessions; /* track Tx BE ports -> Rx BE */
 	unsigned int  sample_rate;
 	unsigned int  channel;
+	bool perf_mode;
 };
 
 #define INVALID_SESSION -1
@@ -291,7 +292,8 @@
 	mutex_unlock(&routing_lock);
 }
 
-void msm_pcm_routing_reg_phy_stream(int fedai_id, int dspst_id, int stream_type)
+void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode, int dspst_id,
+							int stream_type)
 {
 	int i, session_type, path_type, port_type;
 	struct route_payload payload;
@@ -321,6 +323,8 @@
 	if (eq_data[fedai_id].enable)
 		msm_send_eq_values(fedai_id);
 	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+		if (test_bit(fedai_id, &msm_bedais[i].fe_sessions))
+			msm_bedais[i].perf_mode = perf_mode;
 		if (!is_be_dai_extproc(i) &&
 		   (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
 		   (msm_bedais[i].active) &&
@@ -329,12 +333,22 @@
 			channels = msm_bedais[i].channel;
 
 			if ((stream_type == SNDRV_PCM_STREAM_PLAYBACK) &&
+				((channels == 1) || (channels == 2)) &&
+				msm_bedais[i].perf_mode) {
+				pr_debug("%s configure COPP to lowlatency mode",
+								__func__);
+				adm_multi_ch_copp_open(msm_bedais[i].port_id,
+				path_type,
+				msm_bedais[i].sample_rate,
+				msm_bedais[i].channel,
+				DEFAULT_COPP_TOPOLOGY, msm_bedais[i].perf_mode);
+			} else if ((stream_type == SNDRV_PCM_STREAM_PLAYBACK) &&
 				(channels > 2))
 				adm_multi_ch_copp_open(msm_bedais[i].port_id,
 				path_type,
 				msm_bedais[i].sample_rate,
 				msm_bedais[i].channel,
-				DEFAULT_COPP_TOPOLOGY);
+				DEFAULT_COPP_TOPOLOGY, msm_bedais[i].perf_mode);
 			else
 				adm_open(msm_bedais[i].port_id,
 				path_type,
@@ -440,18 +454,32 @@
 
 			channels = msm_bedais[reg].channel;
 
-			if ((session_type == SESSION_TYPE_RX) && (channels > 2))
+			if ((session_type == SESSION_TYPE_RX) &&
+				((channels == 1) || (channels == 2))
+				&& msm_bedais[reg].perf_mode) {
 				adm_multi_ch_copp_open(msm_bedais[reg].port_id,
 				path_type,
 				msm_bedais[reg].sample_rate,
 				channels,
-				DEFAULT_COPP_TOPOLOGY);
+				DEFAULT_COPP_TOPOLOGY,
+				msm_bedais[reg].perf_mode);
+				pr_debug("%s:configure COPP to lowlatency mode",
+								 __func__);
+			} else if ((session_type == SESSION_TYPE_RX)
+					&& (channels > 2))
+				adm_multi_ch_copp_open(msm_bedais[reg].port_id,
+				path_type,
+				msm_bedais[reg].sample_rate,
+				channels,
+				DEFAULT_COPP_TOPOLOGY,
+				msm_bedais[reg].perf_mode);
 			else
 				adm_open(msm_bedais[reg].port_id,
 				path_type,
 				msm_bedais[reg].sample_rate, channels,
 				DEFAULT_COPP_TOPOLOGY);
 
+
 			msm_pcm_routing_build_matrix(val,
 				fe_dai_map[val][session_type], path_type);
 			srs_port_id = msm_bedais[reg].port_id;
@@ -1375,6 +1403,12 @@
 	msm_routing_put_audio_mixer),
 };
 
+static const struct snd_kcontrol_new mmul5_mixer_controls[] = {
+	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
 
 static const struct snd_kcontrol_new mmul4_mixer_controls[] = {
 	SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
@@ -1782,6 +1816,7 @@
 	.put = msm_routing_set_srs_trumedia_control,
 	.private_value = ((unsigned long)&(struct soc_mixer_control)
 	{.reg = SND_SOC_NOPM,
+	.rreg = SND_SOC_NOPM,
 	.shift = 0,
 	.rshift = 0,
 	.max = 0xFFFFFFFF,
@@ -1801,6 +1836,7 @@
 	.put = msm_routing_set_srs_trumedia_control_HDMI,
 	.private_value = ((unsigned long)&(struct soc_mixer_control)
 	{.reg = SND_SOC_NOPM,
+	.rreg = SND_SOC_NOPM,
 	.shift = 0,
 	.rshift = 0,
 	.max = 0xFFFFFFFF,
@@ -1820,6 +1856,7 @@
 	.put = msm_routing_set_srs_trumedia_control_I2S,
 	.private_value = ((unsigned long)&(struct soc_mixer_control)
 	{.reg = SND_SOC_NOPM,
+	.rreg = SND_SOC_NOPM,
 	.shift = 0,
 	.rshift = 0,
 	.max = 0xFFFFFFFF,
@@ -2020,6 +2057,7 @@
 	SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
@@ -2119,6 +2157,8 @@
 	mmul2_mixer_controls, ARRAY_SIZE(mmul2_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia4 Mixer", SND_SOC_NOPM, 0, 0,
 	mmul4_mixer_controls, ARRAY_SIZE(mmul4_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia5 Mixer", SND_SOC_NOPM, 0, 0,
+	mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
 	SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -2277,6 +2317,7 @@
 	{"MultiMedia1 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
 	{"MultiMedia1 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
 	{"MultiMedia1 Mixer", "SLIM_4_TX", "SLIMBUS_4_TX"},
+	{"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -2317,6 +2358,7 @@
 	{"MultiMedia2 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"MM_UL2", NULL, "MultiMedia2 Mixer"},
 	{"MM_UL4", NULL, "MultiMedia4 Mixer"},
+	{"MM_UL5", NULL, "MultiMedia5 Mixer"},
 
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -2550,6 +2592,7 @@
 	bedai->active = 0;
 	bedai->sample_rate = 0;
 	bedai->channel = 0;
+	bedai->perf_mode = false;
 	mutex_unlock(&routing_lock);
 
 	return 0;
@@ -2562,6 +2605,7 @@
 	int i, path_type, session_type;
 	struct msm_pcm_routing_bdai_data *bedai;
 	u32 channels;
+	bool playback, capture;
 
 	if (be_id >= MSM_BACKEND_DAI_MAX) {
 		pr_err("%s: unexpected be_id %d\n", __func__, be_id);
@@ -2589,18 +2633,29 @@
 	* is started.
 	*/
 	bedai->active = 1;
+	playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	capture  = substream->stream == SNDRV_PCM_STREAM_CAPTURE;
+
 	for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
 		if (fe_dai_map[i][session_type] != INVALID_SESSION) {
-
 			channels = bedai->channel;
-			if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
-				substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			if ((playback || capture)
+				&& ((channels == 2) || (channels == 1)) &&
+				bedai->perf_mode) {
+				adm_multi_ch_copp_open(bedai->port_id,
+				path_type,
+				bedai->sample_rate,
+				channels,
+				DEFAULT_COPP_TOPOLOGY, bedai->perf_mode);
+				pr_debug("%s:configure COPP to lowlatency mode",
+								__func__);
+			} else if ((playback || capture)
 				&& (channels > 2))
 				adm_multi_ch_copp_open(bedai->port_id,
 				path_type,
 				bedai->sample_rate,
 				channels,
-				DEFAULT_COPP_TOPOLOGY);
+				DEFAULT_COPP_TOPOLOGY, bedai->perf_mode);
 			else
 				adm_open(bedai->port_id,
 				path_type,
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index 486c6d7..23e3943 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -111,8 +111,8 @@
  * dspst_id:  DSP audio stream ID
  * stream_type: playback or capture
  */
-void msm_pcm_routing_reg_phy_stream(int fedai_id, int dspst_id,
-	int stream_type);
+void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode,
+				int dspst_id, int stream_type);
 void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
 		int stream_type, int enable);
 
diff --git a/sound/soc/msm/msm-pcm-voip.c b/sound/soc/msm/msm-pcm-voip.c
index b18117c..359414b 100644
--- a/sound/soc/msm/msm-pcm-voip.c
+++ b/sound/soc/msm/msm-pcm-voip.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -531,6 +531,7 @@
 				list_first_entry(&prtd->free_in_queue,
 						struct voip_buf_node, list);
 			list_del(&buf_node->list);
+			spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
 			if (prtd->mode == MODE_PCM) {
 				ret = copy_from_user(&buf_node->frame.voc_pkt,
 							buf, count);
@@ -538,6 +539,7 @@
 			} else
 				ret = copy_from_user(&buf_node->frame,
 							buf, count);
+			spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
 			list_add_tail(&buf_node->list, &prtd->in_queue);
 			spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
 		} else {
@@ -582,6 +584,7 @@
 			buf_node = list_first_entry(&prtd->out_queue,
 					struct voip_buf_node, list);
 			list_del(&buf_node->list);
+			spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
 			if (prtd->mode == MODE_PCM)
 				ret = copy_to_user(buf,
 						   &buf_node->frame.voc_pkt,
@@ -595,6 +598,7 @@
 					__func__, ret);
 				ret = -EFAULT;
 			}
+			spin_lock_irqsave(&prtd->dsp_ul_lock, dsp_flags);
 			list_add_tail(&buf_node->list,
 						&prtd->free_out_queue);
 			spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index e86db10..a577b6a 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -1015,6 +1015,53 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
+	{
+		.name = "VoLTE",
+		.stream_name = "VoLTE",
+		.cpu_dai_name   = "VoLTE",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_VOLTE,
+	},
+	{
+		.name = "SGLTE",
+		.stream_name = "SGLTE",
+		.cpu_dai_name   = "SGLTE",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_SGLTE,
+	},
+	{
+		.name = "MSM8960 LowLatency",
+		.stream_name = "MultiMedia5",
+		.cpu_dai_name	= "MultiMedia5",
+		.platform_name  = "msm-lowlatency-pcm-dsp",
+		.dynamic = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+	},
 	/* Backend DAI Links */
 	{
 		.name = LPASS_BE_SLIMBUS_0_RX,
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index b10a7ea..040bbe0 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -1348,6 +1348,21 @@
 		.codec_name = "snd-soc-dummy",
 		.be_id = MSM_FRONTEND_DAI_SGLTE,
 	},
+	{
+		.name = "MSM8960 LowLatency",
+		.stream_name = "MultiMedia5",
+		.cpu_dai_name	= "MultiMedia5",
+		.platform_name  = "msm-lowlatency-pcm-dsp",
+		.dynamic = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+					SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+	},
 	/* Backend BT/FM DAI Links */
 	{
 		.name = LPASS_BE_INT_BT_SCO_RX,
@@ -1746,6 +1761,7 @@
 		msm8960_headset_gpios_configured = 1;
 
 	mutex_init(&cdc_mclk_mutex);
+
 	return ret;
 
 }
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 3516022..f50b915 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -837,6 +837,21 @@
 		.ignore_pmdown_time = 1,
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
 	},
+	/* Hostless PCM purpose */
+	{
+		.name = "SLIMBUS_0 Hostless",
+		.stream_name = "SLIMBUS_0 Hostless",
+		.cpu_dai_name = "SLIMBUS0_HOSTLESS",
+		.platform_name = "msm-pcm-hostless",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* dai link has playback support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
 	{
 		.name = "MSM8974 Compr",
 		.stream_name = "COMPR",
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index 0327e4a..6724c545 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -294,7 +294,8 @@
 
 		switch (data->opcode) {
 		case ADM_CMDRSP_COPP_OPEN:
-		case ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN: {
+		case ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN:
+		case ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN_V3: {
 			struct adm_copp_open_respond *open = data->payload;
 			if (open->copp_id == INVALID_COPP_ID) {
 				pr_err("%s: invalid coppid rxed %d\n",
@@ -707,7 +708,7 @@
 
 
 int adm_multi_ch_copp_open(int port_id, int path, int rate, int channel_mode,
-				int topology)
+				int topology, int perfmode)
 {
 	struct adm_multi_ch_copp_open_command open;
 	int ret = 0;
@@ -745,7 +746,17 @@
 
 		open.hdr.pkt_size =
 			sizeof(struct adm_multi_ch_copp_open_command);
-		open.hdr.opcode = ADM_CMD_MULTI_CHANNEL_COPP_OPEN;
+
+		if (perfmode) {
+			pr_debug("%s Performance mode", __func__);
+			open.hdr.opcode = ADM_CMD_MULTI_CHANNEL_COPP_OPEN_V3;
+			open.flags = ADM_MULTI_CH_COPP_OPEN_PERF_MODE_BIT;
+			open.reserved = PCM_BITS_PER_SAMPLE;
+		} else {
+			open.hdr.opcode = ADM_CMD_MULTI_CHANNEL_COPP_OPEN;
+			open.reserved = 0;
+		}
+
 		memset(open.dev_channel_mapping, 0, 8);
 
 		if (channel_mode == 1)	{
@@ -779,8 +790,6 @@
 					channel_mode);
 			return -EINVAL;
 		}
-
-
 		open.hdr.src_svc = APR_SVC_ADM;
 		open.hdr.src_domain = APR_DOMAIN_APPS;
 		open.hdr.src_port = port_id;
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index 4c0ac9e..a4f4b60 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -448,7 +448,7 @@
 
 	if ((port_id == RT_PROXY_DAI_001_RX) ||
 		(port_id == RT_PROXY_DAI_002_TX))
-		return -EINVAL;
+		return 0;
 	if ((port_id == RT_PROXY_DAI_002_RX) ||
 		(port_id == RT_PROXY_DAI_001_TX))
 		port_id = VIRTUAL_ID_TO_PORTID(port_id);
@@ -608,7 +608,7 @@
 
 	if ((port_id == RT_PROXY_DAI_001_RX) ||
 		(port_id == RT_PROXY_DAI_002_TX))
-		return -EINVAL;
+		return 0;
 	if ((port_id == RT_PROXY_DAI_002_RX) ||
 		(port_id == RT_PROXY_DAI_001_TX))
 		port_id = VIRTUAL_ID_TO_PORTID(port_id);
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 06be186..76940ee 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -209,6 +209,7 @@
 	session[ac->session] = 0;
 	mutex_unlock(&session_lock);
 	ac->session = 0;
+	ac->perf_mode = false;
 	return;
 }
 
@@ -412,6 +413,7 @@
 	ac->cb = cb;
 	ac->priv = priv;
 	ac->io_mode = SYNC_IO_MODE;
+	ac->perf_mode = false;
 	ac->apr = apr_register("ADSP", "ASM", \
 				(apr_fn)q6asm_callback,\
 				((ac->session) << 8 | 0x0001),\
@@ -844,6 +846,7 @@
 
 	if (data->opcode == APR_BASIC_RSP_RESULT) {
 		token = data->token;
+		pr_debug("%s payload[0]:%x", __func__, payload[0]);
 		switch (payload[0]) {
 		case ASM_STREAM_CMD_SET_PP_PARAMS:
 			if (rtac_make_asm_callback(ac->session, payload,
@@ -863,7 +866,9 @@
 			return -EINVAL;
 		}
 		case ASM_STREAM_CMD_OPEN_READ:
+		case ASM_STREAM_CMD_OPEN_READ_V2_1:
 		case ASM_STREAM_CMD_OPEN_WRITE:
+		case ASM_STREAM_CMD_OPEN_WRITE_V2_1:
 		case ASM_STREAM_CMD_OPEN_READWRITE:
 		case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
 		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
@@ -871,8 +876,11 @@
 		case ASM_STREAM_CMD_OPEN_READ_COMPRESSED:
 			if (atomic_read(&ac->cmd_state) && wakeup_flag) {
 				atomic_set(&ac->cmd_state, 0);
-				if (payload[1] == ADSP_EUNSUPPORTED)
+				if (payload[1] == ADSP_EUNSUPPORTED) {
+					pr_debug("paload[1]:%d unsupported",
+								payload[1]);
 					atomic_set(&ac->cmd_response, 1);
+				}
 				else
 					atomic_set(&ac->cmd_response, 0);
 				wake_up(&ac->cmd_wait);
@@ -1276,6 +1284,82 @@
 	return -EINVAL;
 }
 
+int q6asm_open_read_v2_1(struct audio_client *ac,
+		uint32_t format)
+{
+	int rc = 0x00;
+	struct asm_stream_cmd_open_read_v2_1 open;
+#ifdef CONFIG_DEBUG_FS
+	in_cont_index = 0;
+#endif
+	if ((ac == NULL) || (ac->apr == NULL)) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	pr_debug("%s:session[%d]", __func__, ac->session);
+
+	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+	open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V2_1;
+	open.src_endpoint = ASM_END_POINT_DEVICE_MATRIX;
+	open.pre_proc_top = get_asm_topology();
+	if (open.pre_proc_top == 0)
+		open.pre_proc_top = DEFAULT_POPP_TOPOLOGY;
+
+	switch (format) {
+	case FORMAT_LINEAR_PCM:
+		open.uMode = STREAM_PRIORITY_HIGH;
+		open.format = LINEAR_PCM;
+		break;
+	case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
+		open.uMode = STREAM_PRIORITY_HIGH;
+		open.format = MULTI_CHANNEL_PCM;
+		break;
+	case FORMAT_MPEG4_AAC:
+		open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+		open.format = MPEG4_AAC;
+		break;
+	case FORMAT_V13K:
+		open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+		open.format = V13K_FS;
+		break;
+	case FORMAT_EVRC:
+		open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+		open.format = EVRC_FS;
+		break;
+	case FORMAT_AMRNB:
+		open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+		open.format = AMRNB_FS;
+		break;
+	case FORMAT_AMRWB:
+		open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+		open.format = AMRWB_FS;
+		break;
+	default:
+		pr_err("Invalid format[%d]\n", format);
+		goto fail_cmd;
+	}
+	open.uMode = ASM_OPEN_READ_PERF_MODE_BIT;
+	open.bits_per_sample = PCM_BITS_PER_SAMPLE;
+	open.reserved = 0;
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+	if (rc < 0) {
+		pr_err("open failed op[0x%x]rc[%d]\n", \
+						open.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout. waited for OPEN_WRITE rc[%d]\n", __func__,
+			rc);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+
 int q6asm_open_read_compressed(struct audio_client *ac,
 			 uint32_t frames_per_buffer, uint32_t meta_data_mode)
 {
@@ -1396,12 +1480,20 @@
 
 	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
 
-	open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE;
-	open.uMode = STREAM_PRIORITY_HIGH;
-	/* source endpoint : matrix */
-	open.sink_endpoint = ASM_END_POINT_DEVICE_MATRIX;
-	open.stream_handle = 0x00;
-
+	if (ac->perf_mode) {
+		pr_debug("%s In Performance/lowlatency mode", __func__);
+		open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V2_1;
+		open.uMode = ASM_OPEN_WRITE_PERF_MODE_BIT;
+		/* source endpoint : matrix */
+		open.sink_endpoint = ASM_END_POINT_DEVICE_MATRIX;
+		open.stream_handle = PCM_BITS_PER_SAMPLE;
+	} else {
+		open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE;
+		open.uMode = STREAM_PRIORITY_HIGH;
+		/* source endpoint : matrix */
+		open.sink_endpoint = ASM_END_POINT_DEVICE_MATRIX;
+		open.stream_handle = 0x00;
+	}
 	open.post_proc_top = get_asm_topology();
 	if (open.post_proc_top == 0)
 		open.post_proc_top = DEFAULT_POPP_TOPOLOGY;
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index 3791f24..2a21dfa 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -36,10 +36,16 @@
 #define VOC_PATH_VOLTE_PASSIVE 2
 #define VOC_PATH_SGLTE_PASSIVE 3
 
-/* CVP CAL Size: 245760 = 240 * 1024 */
-#define CVP_CAL_SIZE 245760
-/* CVS CAL Size: 49152 = 48 * 1024 */
-#define CVS_CAL_SIZE 49152
+#define CAL_BUFFER_SIZE		4096
+#define NUM_CVP_CAL_BLOCKS	75
+#define NUM_CVS_CAL_BLOCKS	15
+#define CVP_CAL_SIZE		(NUM_CVP_CAL_BLOCKS * CAL_BUFFER_SIZE)
+#define CVS_CAL_SIZE		(NUM_CVS_CAL_BLOCKS * CAL_BUFFER_SIZE)
+#define VOICE_CAL_BUFFER_SIZE	(CVP_CAL_SIZE + CVS_CAL_SIZE)
+/* Total cal needed to support concurrent VOIP & VOLTE sessions */
+/* Due to memory map issue on Q6 separate memory has to be used */
+/* for VOIP & VOLTE  */
+#define TOTAL_VOICE_CAL_SIZE	(NUM_VOICE_CAL_BUFFERS * VOICE_CAL_BUFFER_SIZE)
 
 static struct common_data common;
 
@@ -198,6 +204,72 @@
 	return (session_id == common.voice[VOC_PATH_SGLTE_PASSIVE].session_id);
 }
 
+/* Only for memory allocated in the voice driver */
+/* which includes voip & volte */
+static int voice_get_cal_kernel_addr(int16_t session_id, int cal_type,
+					uint32_t *kvaddr)
+{
+	int	i, result = 0;
+	pr_debug("%s\n", __func__);
+
+	if (kvaddr == NULL) {
+		pr_err("%s: NULL pointer sent to function\n", __func__);
+		result = -EINVAL;
+		goto done;
+	} else if (is_voip_session(session_id)) {
+		i = VOIP_CAL;
+	} else if (is_volte_session(session_id)) {
+		i = VOLTE_CAL;
+	} else {
+		result = -EINVAL;
+		goto done;
+	}
+
+	if (common.voice_cal[i].cal_data[cal_type].kvaddr == 0) {
+		pr_err("%s: NULL pointer for session_id %d, type %d, cal_type %d\n",
+			__func__, session_id, i, cal_type);
+		result = -EFAULT;
+		goto done;
+	}
+
+	*kvaddr = common.voice_cal[i].cal_data[cal_type].kvaddr;
+done:
+	return result;
+}
+
+/* Only for memory allocated in the voice driver */
+/* which includes voip & volte */
+static int voice_get_cal_phys_addr(int16_t session_id, int cal_type,
+					uint32_t *paddr)
+{
+	int	i, result = 0;
+	pr_debug("%s\n", __func__);
+
+	if (paddr == NULL) {
+		pr_err("%s: NULL pointer sent to function\n", __func__);
+		result = -EINVAL;
+		goto done;
+	} else if (is_voip_session(session_id)) {
+		i = VOIP_CAL;
+	} else if (is_volte_session(session_id)) {
+		i = VOLTE_CAL;
+	} else {
+		result = -EINVAL;
+		goto done;
+	}
+
+	if (common.voice_cal[i].cal_data[cal_type].paddr == 0) {
+		pr_err("%s: No addr for session_id %d, type %d, cal_type %d\n",
+			__func__, session_id, i, cal_type);
+		result = -EFAULT;
+		goto done;
+	}
+
+	*paddr = common.voice_cal[i].cal_data[cal_type].paddr;
+done:
+	return result;
+}
+
 static int voice_apr_register(void)
 {
 	pr_debug("%s\n", __func__);
@@ -1237,7 +1309,8 @@
 	int ret = 0;
 	void *apr_cvs;
 	u16 cvs_handle;
-	uint32_t cal_paddr;
+	uint32_t cal_paddr = 0;
+	uint32_t cal_buf = 0;
 
 	/* get the cvs cal data */
 	get_all_vocstrm_cal(&cal_block);
@@ -1255,16 +1328,20 @@
 		return -EINVAL;
 	}
 
-	if (is_voip_session(v->session_id)) {
-		if (common.cvs_cal.buf) {
-			cal_paddr = common.cvs_cal.phy;
+	if (is_volte_session(v->session_id) ||
+			is_voip_session(v->session_id)) {
+		ret = voice_get_cal_phys_addr(v->session_id, CVS_CAL,
+						&cal_paddr);
+		if (ret < 0)
+			return ret;
 
-			memcpy(common.cvs_cal.buf,
-				(void *) cal_block.cal_kvaddr,
-				cal_block.cal_size);
-		} else {
-			return -EINVAL;
-		}
+		ret = voice_get_cal_kernel_addr(v->session_id, CVS_CAL,
+						&cal_buf);
+		if (ret < 0)
+			return ret;
+
+		memcpy((void *)cal_buf, (void *)cal_block.cal_kvaddr,
+			cal_block.cal_size);
 	} else {
 		cal_paddr = cal_block.cal_paddr;
 	}
@@ -1364,7 +1441,7 @@
 	int ret = 0;
 	void *apr_cvp;
 	u16 cvp_handle;
-	uint32_t cal_paddr;
+	uint32_t cal_paddr = 0;
 
 	/* get all cvp cal data */
 	get_all_cvp_cal(&cal_block);
@@ -1382,14 +1459,16 @@
 		return -EINVAL;
 	}
 
-	if (is_voip_session(v->session_id)) {
-		if (common.cvp_cal.buf)
-			cal_paddr = common.cvp_cal.phy;
-		else
-			return -EINVAL;
+	if (is_volte_session(v->session_id) ||
+			is_voip_session(v->session_id)) {
+		ret = voice_get_cal_phys_addr(v->session_id, CVP_CAL,
+						&cal_paddr);
+		if (ret < 0)
+			return ret;
 	} else {
 		cal_paddr = cal_block.cal_paddr;
 	}
+
 	cvp_handle = voice_get_cvp_handle(v);
 
 	/* fill in the header */
@@ -1402,7 +1481,7 @@
 	cvp_map_mem_cmd.hdr.token = 0;
 	cvp_map_mem_cmd.hdr.opcode = VSS_ICOMMON_CMD_MAP_MEMORY;
 
-	pr_debug("%s, phy_addr:0x%x, mem_size:%d\n", __func__,
+	pr_debug("%s, phys_addr: 0x%x, mem_size: %d\n", __func__,
 		cal_paddr, cal_block.cal_size);
 	cvp_map_mem_cmd.vss_map_mem.phys_addr = cal_paddr;
 	cvp_map_mem_cmd.vss_map_mem.mem_size = cal_block.cal_size;
@@ -1435,7 +1514,7 @@
 	int ret = 0;
 	void *apr_cvp;
 	u16 cvp_handle;
-	uint32_t cal_paddr;
+	uint32_t cal_paddr = 0;
 
 	get_all_cvp_cal(&cal_block);
 	if (cal_block.cal_size == 0)
@@ -1452,10 +1531,15 @@
 		return -EINVAL;
 	}
 
-	if (is_voip_session(v->session_id))
-		cal_paddr = common.cvp_cal.phy;
-	else
+	if (is_volte_session(v->session_id) ||
+			is_voip_session(v->session_id)) {
+		ret = voice_get_cal_phys_addr(v->session_id, CVP_CAL,
+						&cal_paddr);
+		if (ret < 0)
+			return ret;
+	} else {
 		cal_paddr = cal_block.cal_paddr;
+	}
 
 	cvp_handle = voice_get_cvp_handle(v);
 
@@ -1497,7 +1581,7 @@
 	int ret = 0;
 	void *apr_cvs;
 	u16 cvs_handle;
-	uint32_t cal_paddr;
+	uint32_t cal_paddr = 0;
 
 	/* get all cvs cal data */
 	get_all_vocstrm_cal(&cal_block);
@@ -1515,11 +1599,12 @@
 		return -EINVAL;
 	}
 
-	if (is_voip_session(v->session_id)) {
-		if (common.cvs_cal.buf)
-			cal_paddr = common.cvs_cal.phy;
-		else
-			return -EINVAL;
+	if (is_volte_session(v->session_id) ||
+			is_voip_session(v->session_id)) {
+		ret = voice_get_cal_phys_addr(v->session_id, CVS_CAL,
+						&cal_paddr);
+		if (ret < 0)
+			return ret;
 	} else {
 		cal_paddr = cal_block.cal_paddr;
 	}
@@ -1569,7 +1654,7 @@
 	int ret = 0;
 	void *apr_cvs;
 	u16 cvs_handle;
-	uint32_t cal_paddr;
+	uint32_t cal_paddr = 0;
 
 	get_all_vocstrm_cal(&cal_block);
 	if (cal_block.cal_size == 0)
@@ -1586,10 +1671,15 @@
 		return -EINVAL;
 	}
 
-	if (is_voip_session(v->session_id))
-		cal_paddr = common.cvs_cal.phy;
-	else
+	if (is_volte_session(v->session_id) ||
+			is_voip_session(v->session_id)) {
+		ret = voice_get_cal_phys_addr(v->session_id, CVS_CAL,
+						&cal_paddr);
+		if (ret < 0)
+			return ret;
+	} else {
 		cal_paddr = cal_block.cal_paddr;
+	}
 
 	cvs_handle = voice_get_cvs_handle(v);
 
@@ -1631,7 +1721,8 @@
 	int ret = 0;
 	void *apr_cvp;
 	u16 cvp_handle;
-	uint32_t cal_paddr;
+	uint32_t cal_paddr = 0;
+	uint32_t cal_buf = 0;
 
       /* get the cvp cal data */
 	get_all_vocproc_cal(&cal_block);
@@ -1649,16 +1740,20 @@
 		return -EINVAL;
 	}
 
-	if (is_voip_session(v->session_id)) {
-		if (common.cvp_cal.buf) {
-			cal_paddr = common.cvp_cal.phy;
+	if (is_volte_session(v->session_id) ||
+			is_voip_session(v->session_id)) {
+		ret = voice_get_cal_phys_addr(v->session_id, CVP_CAL,
+						&cal_paddr);
+		if (ret < 0)
+			return ret;
 
-			memcpy(common.cvp_cal.buf,
-				(void *)cal_block.cal_kvaddr,
-				cal_block.cal_size);
-		} else {
-			return -EINVAL;
-		}
+		ret = voice_get_cal_kernel_addr(v->session_id, CVP_CAL,
+						&cal_buf);
+		if (ret < 0)
+			return ret;
+
+		memcpy((void *)cal_buf, (void *)cal_block.cal_kvaddr,
+			cal_block.cal_size);
 	} else {
 		cal_paddr = cal_block.cal_paddr;
 	}
@@ -1759,7 +1854,8 @@
 	int ret = 0;
 	void *apr_cvp;
 	u16 cvp_handle;
-	uint32_t cal_paddr;
+	uint32_t cal_paddr = 0;
+	uint32_t cal_buf = 0;
 
 	/* get the cvp vol cal data */
 	get_all_vocvol_cal(&vol_block);
@@ -1779,16 +1875,21 @@
 		return -EINVAL;
 	}
 
-	if (is_voip_session(v->session_id)) {
-		if (common.cvp_cal.buf) {
-			cal_paddr = common.cvp_cal.phy + voc_block.cal_size;
+	if (is_volte_session(v->session_id) ||
+			is_voip_session(v->session_id)) {
+		ret = voice_get_cal_phys_addr(v->session_id, CVP_CAL,
+						&cal_paddr);
+		if (ret < 0)
+			return ret;
 
-			memcpy(common.cvp_cal.buf + voc_block.cal_size,
-				(void *) vol_block.cal_kvaddr,
-				vol_block.cal_size);
-		} else {
-			return -EINVAL;
-		}
+		cal_paddr += voc_block.cal_size;
+		ret = voice_get_cal_kernel_addr(v->session_id, CVP_CAL,
+						&cal_buf);
+		if (ret < 0)
+			return ret;
+
+		memcpy((void *)(cal_buf + voc_block.cal_size),
+			(void *)vol_block.cal_kvaddr, vol_block.cal_size);
 	} else {
 		cal_paddr = vol_block.cal_paddr;
 	}
@@ -3943,76 +4044,83 @@
 }
 
 
+static void voice_allocate_shared_memory(void)
+{
+	int			i, j, result;
+	int			offset = 0;
+	int			mem_len;
+	unsigned long		paddr;
+	void                    *kvptr;
+	pr_debug("%s\n", __func__);
+
+	common.ion_client = msm_ion_client_create(UINT_MAX, "q6voice_client");
+	if (IS_ERR_OR_NULL((void *)common.ion_client)) {
+		pr_err("%s: ION create client failed\n", __func__);
+		goto err;
+	}
+
+	common.ion_handle = ion_alloc(common.ion_client,
+				TOTAL_VOICE_CAL_SIZE,
+				SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL((void *) common.ion_handle)) {
+		pr_err("%s: ION memory allocation failed\n",
+			__func__);
+		goto err_ion_client;
+	}
+
+	result = ion_phys(common.ion_client, common.ion_handle,
+			&paddr, (size_t *)&mem_len);
+	if (result) {
+		pr_err("%s: ION Get Physical failed, rc = %d\n",
+			__func__, result);
+		goto err_ion_handle;
+	}
+
+	kvptr = ion_map_kernel(common.ion_client,
+				common.ion_handle, 0);
+	if (IS_ERR_OR_NULL(kvptr)) {
+		pr_err("%s: ION memory mapping failed\n", __func__);
+		goto err_ion_handle;
+	}
+
+	/* Make all phys & buf point to the correct address */
+	for (i = 0; i < NUM_VOICE_CAL_BUFFERS; i++) {
+		for (j = 0; j < NUM_VOICE_CAL_TYPES; j++) {
+			common.voice_cal[i].cal_data[j].paddr =
+				(uint32_t)(paddr + offset);
+			common.voice_cal[i].cal_data[j].kvaddr =
+				(uint32_t)((uint8_t *)kvptr + offset);
+			if (j == CVP_CAL)
+				offset += CVP_CAL_SIZE;
+			else
+				offset += CVS_CAL_SIZE;
+
+			pr_debug("%s: kernel addr = 0x%x, phys addr = 0x%x\n",
+				__func__,
+				common.voice_cal[i].cal_data[j].kvaddr,
+				common.voice_cal[i].cal_data[j].paddr);
+		}
+	}
+
+	return;
+
+err_ion_handle:
+	ion_free(common.ion_client, common.ion_handle);
+err_ion_client:
+	ion_client_destroy(common.ion_client);
+err:
+	return;
+}
+
 static int __init voice_init(void)
 {
 	int rc = 0, i = 0;
-	int len;
 
 	memset(&common, 0, sizeof(struct common_data));
 
-	/* Allocate memory for VoIP calibration */
-	common.client = msm_ion_client_create(UINT_MAX, "voip_client");
-	if (IS_ERR_OR_NULL((void *)common.client)) {
-		pr_err("%s: ION create client for Voip failed\n", __func__);
-		goto cont;
-	}
-	common.cvp_cal.handle = ion_alloc(common.client, CVP_CAL_SIZE, SZ_4K,
-					  ION_HEAP(ION_AUDIO_HEAP_ID));
-	if (IS_ERR_OR_NULL((void *) common.cvp_cal.handle)) {
-		pr_err("%s: ION memory allocation for CVP failed\n",
-			__func__);
-		ion_client_destroy(common.client);
-		goto cont;
-	}
+	/* Allocate shared memory */
+	voice_allocate_shared_memory();
 
-	rc = ion_phys(common.client, common.cvp_cal.handle,
-		  (ion_phys_addr_t *)&common.cvp_cal.phy, (size_t *)&len);
-	if (rc) {
-		pr_err("%s: ION Get Physical for cvp failed, rc = %d\n",
-			__func__, rc);
-		ion_free(common.client, common.cvp_cal.handle);
-		ion_client_destroy(common.client);
-		goto cont;
-	}
-
-	common.cvp_cal.buf = ion_map_kernel(common.client,
-					common.cvp_cal.handle, 0);
-	if (IS_ERR_OR_NULL((void *) common.cvp_cal.buf)) {
-		pr_err("%s: ION memory mapping for cvp failed\n", __func__);
-		common.cvp_cal.buf = NULL;
-		ion_free(common.client, common.cvp_cal.handle);
-		ion_client_destroy(common.client);
-		goto cont;
-	}
-	memset((void *)common.cvp_cal.buf, 0, CVP_CAL_SIZE);
-
-	common.cvs_cal.handle = ion_alloc(common.client, CVS_CAL_SIZE, SZ_4K,
-					 ION_HEAP(ION_AUDIO_HEAP_ID));
-	if (IS_ERR_OR_NULL((void *) common.cvs_cal.handle)) {
-		pr_err("%s: ION memory allocation for CVS failed\n",
-			__func__);
-		goto cont;
-	}
-
-	rc = ion_phys(common.client, common.cvs_cal.handle,
-		  (ion_phys_addr_t *)&common.cvs_cal.phy, (size_t *)&len);
-	if (rc) {
-		pr_err("%s: ION Get Physical for cvs failed, rc = %d\n",
-			__func__, rc);
-		ion_free(common.client, common.cvs_cal.handle);
-		goto cont;
-	}
-
-	common.cvs_cal.buf = ion_map_kernel(common.client,
-					common.cvs_cal.handle, 0);
-	if (IS_ERR_OR_NULL((void *) common.cvs_cal.buf)) {
-		pr_err("%s: ION memory mapping for cvs failed\n", __func__);
-		common.cvs_cal.buf = NULL;
-		ion_free(common.client, common.cvs_cal.handle);
-		goto cont;
-	}
-	memset((void *)common.cvs_cal.buf, 0, CVS_CAL_SIZE);
-cont:
 	/* set default value */
 	common.default_mute_val = 0;  /* default is un-mute */
 	common.default_vol_val = 0;
diff --git a/sound/soc/msm/qdsp6/q6voice.h b/sound/soc/msm/qdsp6/q6voice.h
index 468aba8..1cb2878 100644
--- a/sound/soc/msm/qdsp6/q6voice.h
+++ b/sound/soc/msm/qdsp6/q6voice.h
@@ -22,6 +22,20 @@
 #define VOC_REC_DOWNLINK	0x01
 #define VOC_REC_BOTH		0x02
 
+/* Needed for VOIP & VOLTE support */
+/* Due to Q6 memory map issue */
+enum {
+	VOIP_CAL,
+	VOLTE_CAL,
+	NUM_VOICE_CAL_BUFFERS
+};
+
+enum {
+	CVP_CAL,
+	CVS_CAL,
+	NUM_VOICE_CAL_TYPES
+};
+
 struct voice_header {
 	uint32_t id;
 	uint32_t data_len;
@@ -913,9 +927,14 @@
 };
 
 struct cal_mem {
-	struct ion_handle *handle;
-	uint32_t phy;
-	void *buf;
+	/* Physical Address */
+	uint32_t paddr;
+	/* Kernel Virtual Address */
+	uint32_t kvaddr;
+};
+
+struct cal_data {
+	struct cal_mem	cal_data[NUM_VOICE_CAL_TYPES];
 };
 
 #define MAX_VOC_SESSIONS 4
@@ -934,9 +953,9 @@
 	/* APR to CVP in the Q6 */
 	void *apr_q6_cvp;
 
-	struct ion_client *client;
-	struct cal_mem cvp_cal;
-	struct cal_mem cvs_cal;
+	struct ion_client *ion_client;
+	struct ion_handle *ion_handle;
+	struct cal_data voice_cal[NUM_VOICE_CAL_BUFFERS];
 
 	struct mutex common_lock;
 
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 99fd1d3..485569b 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -40,7 +40,11 @@
 	union afe_port_config port_config;
 };
 
-static struct clk *pcm_clk;
+static struct clk *pcm_src_clk;
+static struct clk *pcm_branch_clk;
+static struct clk *pcm_oe_src_clk;
+static struct clk *pcm_oe_branch_clk;
+
 static DEFINE_MUTEX(aux_pcm_mutex);
 static int aux_pcm_count;
 
@@ -120,6 +124,9 @@
 	if (IS_ERR_VALUE(rc))
 		dev_err(dai->dev, "fail to close AUX PCM TX port\n");
 
+	clk_disable_unprepare(pcm_branch_clk);
+	clk_disable_unprepare(pcm_oe_branch_clk);
+
 	mutex_unlock(&aux_pcm_mutex);
 }
 
@@ -127,8 +134,11 @@
 		struct snd_soc_dai *dai)
 {
 	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+	struct msm_dai_auxpcm_pdata *auxpcm_pdata = NULL;
 	int rc = 0;
 
+	auxpcm_pdata = dai->dev->platform_data;
+
 	mutex_lock(&aux_pcm_mutex);
 
 	if (aux_pcm_count == 2) {
@@ -170,12 +180,37 @@
 	 * assert/deasset and afe_open sequence is not followed.
 	 */
 
+	rc = clk_set_rate(pcm_src_clk, auxpcm_pdata->pcm_clk_rate);
+	if (rc < 0) {
+		pr_err("%s: clk_set_rate failed\n", __func__);
+		goto fail;
+	}
+
+	rc = clk_prepare_enable(pcm_branch_clk);
+	if (rc) {
+		pr_err("%s: clk enable failed\n", __func__);
+		goto fail;
+	}
+
+	rc = clk_set_rate(pcm_oe_src_clk, 24576000>>1);
+	if (rc < 0) {
+		pr_err("%s: clk_set_rate on pcm oe failed\n", __func__);
+		goto fail;
+	}
+
+	rc = clk_prepare_enable(pcm_oe_branch_clk);
+	if (rc) {
+		pr_err("%s: clk enable pcm_oe_branch_clk failed\n", __func__);
+		goto fail;
+	}
+
 	afe_open(PCM_RX, &dai_data->port_config, dai_data->rate);
 
 	afe_open(PCM_TX, &dai_data->port_config, dai_data->rate);
 
 	mutex_unlock(&aux_pcm_mutex);
 
+fail:
 	return rc;
 }
 
@@ -217,6 +252,7 @@
 	auxpcm_pdata = (struct msm_dai_auxpcm_pdata *)
 					dev_get_drvdata(dai->dev);
 	dai->dev->platform_data = auxpcm_pdata;
+	dai->id = dai->dev->id;
 
 	mutex_lock(&aux_pcm_mutex);
 
@@ -225,9 +261,41 @@
 	 * data to the cpu driver, since cpu drive is unaware of any
 	 * boarc specific configuration.
 	 */
-	if (!pcm_clk)
-		pcm_clk = clk_get(dai->dev, auxpcm_pdata->clk);
+	if ((!pcm_src_clk) || (!pcm_branch_clk)) {
+		pcm_src_clk = clk_get(dai->dev, auxpcm_pdata->clk);
 
+		if (IS_ERR(pcm_src_clk)) {
+			pr_err("%s: could not get pcm_src_clk\n", __func__);
+			pcm_src_clk = NULL;
+			return -ENODEV;
+		}
+
+		pcm_branch_clk = clk_get(dai->dev, "ibit_clk");
+
+		if (IS_ERR(pcm_branch_clk)) {
+			pr_err("%s: could not get pcm_branch_clk\n", __func__);
+			pcm_branch_clk = NULL;
+			return -ENODEV;
+		}
+	}
+
+	if ((!pcm_oe_src_clk) || (!pcm_oe_branch_clk)) {
+
+		pcm_oe_src_clk = clk_get(dai->dev, "core_oe_src_clk");
+
+		if (IS_ERR(pcm_oe_src_clk)) {
+			pr_err("%s: could not get pcm_oe_src_clk\n", __func__);
+			pcm_oe_src_clk = NULL;
+			return -ENODEV;
+		}
+
+		pcm_oe_branch_clk = clk_get(dai->dev, "core_oe_clk");
+		if (IS_ERR(pcm_oe_branch_clk)) {
+			pr_err("%s: could not get pcm_oe_clk\n", __func__);
+			pcm_oe_branch_clk = NULL;
+			return -ENODEV;
+		}
+	}
 	mutex_unlock(&aux_pcm_mutex);
 
 	dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data), GFP_KERNEL);
@@ -813,7 +881,7 @@
 	.remove = msm_dai_q6_dai_remove,
 };
 
-static int msm_auxpcm_dev_probe(struct platform_device *pdev)
+static int __devinit msm_auxpcm_dev_probe(struct platform_device *pdev)
 {
 	int id;
 	void *plat_data;
@@ -837,6 +905,7 @@
 	dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
 
 	dev_set_drvdata(&pdev->dev, plat_data);
+	pdev->dev.id = id;
 
 	switch (id) {
 	case AFE_PORT_ID_PRIMARY_PCM_RX:
@@ -855,7 +924,7 @@
 	return rc;
 }
 
-static int msm_auxpcm_resource_probe(
+static int __devinit msm_auxpcm_resource_probe(
 			struct platform_device *pdev)
 {
 	int rc = 0;
@@ -950,13 +1019,13 @@
 	return rc;
 }
 
-static int msm_auxpcm_dev_remove(struct platform_device *pdev)
+static int __devexit msm_auxpcm_dev_remove(struct platform_device *pdev)
 {
 	snd_soc_unregister_dai(&pdev->dev);
 	return 0;
 }
 
-static int msm_auxpcm_resource_remove(
+static int __devexit msm_auxpcm_resource_remove(
 				struct platform_device *pdev)
 {
 	void *auxpcm_pdata;
@@ -967,22 +1036,20 @@
 	return 0;
 }
 
-static const struct of_device_id msm_auxpcm_resource_dt_match[] = {
+static struct of_device_id msm_auxpcm_resource_dt_match[] = {
 	{ .compatible = "qcom,msm-auxpcm-resource", },
 	{}
 };
-MODULE_DEVICE_TABLE(of, msm_auxpcm_resource_dt_match);
 
-static const struct of_device_id msm_auxpcm_dev_dt_match[] = {
+static struct of_device_id msm_auxpcm_dev_dt_match[] = {
 	{ .compatible = "qcom,msm-auxpcm-dev", },
 	{}
 };
-MODULE_DEVICE_TABLE(of, msm_auxpcm_dev_dt_match);
 
 
-static struct platform_driver msm_auxpcm_dev = {
+static struct platform_driver msm_auxpcm_dev_driver = {
 	.probe  = msm_auxpcm_dev_probe,
-	.remove = msm_auxpcm_dev_remove,
+	.remove = __devexit_p(msm_auxpcm_dev_remove),
 	.driver = {
 		.name = "msm-auxpcm-dev",
 		.owner = THIS_MODULE,
@@ -990,9 +1057,9 @@
 	},
 };
 
-static struct platform_driver msm_auxpcm_resource = {
+static struct platform_driver msm_auxpcm_resource_driver = {
 	.probe  = msm_auxpcm_resource_probe,
-	.remove  = msm_auxpcm_resource_remove,
+	.remove  = __devexit_p(msm_auxpcm_resource_remove),
 	.driver = {
 		.name = "msm-auxpcm-resource",
 		.owner = THIS_MODULE,
@@ -1134,22 +1201,23 @@
 {
 	int rc;
 
-	rc = platform_driver_register(&msm_auxpcm_dev);
+	rc = platform_driver_register(&msm_auxpcm_dev_driver);
 	if (rc)
 		goto fail;
 
-	rc = platform_driver_register(&msm_auxpcm_resource);
+	rc = platform_driver_register(&msm_auxpcm_resource_driver);
+
 	if (rc) {
 		pr_err("%s: fail to register cpu dai driver\n", __func__);
-		platform_driver_unregister(&msm_auxpcm_dev);
+		platform_driver_unregister(&msm_auxpcm_dev_driver);
 		goto fail;
 	}
 
 	rc = platform_driver_register(&msm_dai_q6);
 	if (rc) {
 		pr_err("%s: fail to register dai q6 driver", __func__);
-		platform_driver_unregister(&msm_auxpcm_dev);
-		platform_driver_unregister(&msm_auxpcm_resource);
+		platform_driver_unregister(&msm_auxpcm_dev_driver);
+		platform_driver_unregister(&msm_auxpcm_resource_driver);
 		goto fail;
 	}
 
@@ -1157,8 +1225,8 @@
 	if (rc) {
 		pr_err("%s: fail to register dai q6 dev driver", __func__);
 		platform_driver_unregister(&msm_dai_q6);
-		platform_driver_unregister(&msm_auxpcm_dev);
-		platform_driver_unregister(&msm_auxpcm_resource);
+		platform_driver_unregister(&msm_auxpcm_dev_driver);
+		platform_driver_unregister(&msm_auxpcm_resource_driver);
 		goto fail;
 	}
 fail:
@@ -1170,8 +1238,8 @@
 {
 	platform_driver_unregister(&msm_dai_q6_dev);
 	platform_driver_unregister(&msm_dai_q6);
-	platform_driver_unregister(&msm_auxpcm_dev);
-	platform_driver_unregister(&msm_auxpcm_resource);
+	platform_driver_unregister(&msm_auxpcm_dev_driver);
+	platform_driver_unregister(&msm_auxpcm_resource_driver);
 }
 module_exit(msm_dai_q6_exit);
 
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 756cb18..2e58e1b 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -586,25 +586,23 @@
 						sizeof(lb_cmd) - APR_HDR_SIZE);
 	lb_cmd.hdr.src_port = 0;
 	lb_cmd.hdr.dest_port = 0;
-	lb_cmd.hdr.token = 0;
+	lb_cmd.hdr.token = index;
 	lb_cmd.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
 	lb_cmd.param.port_id = tx_port;
-	lb_cmd.param.payload_size = (sizeof(lb_cmd) -
-			sizeof(struct apr_hdr) -
-			sizeof(struct afe_port_cmd_set_param_v2));
+	lb_cmd.param.payload_size = (sizeof(lb_cmd) - sizeof(struct apr_hdr) -
+				     sizeof(struct afe_port_cmd_set_param_v2));
 	lb_cmd.param.payload_address_lsw = 0x00;
 	lb_cmd.param.payload_address_msw = 0x00;
 	lb_cmd.param.mem_map_handle = 0x00;
 	lb_cmd.pdata.module_id = AFE_MODULE_LOOPBACK;
 	lb_cmd.pdata.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
-	lb_cmd.pdata.param_size =  lb_cmd.param.payload_size -
-				sizeof(struct afe_port_param_data_v2);
+	lb_cmd.pdata.param_size = lb_cmd.param.payload_size -
+				  sizeof(struct afe_port_param_data_v2);
 
 	lb_cmd.dst_port_id = rx_port;
 	lb_cmd.routing_mode = LB_MODE_DEFAULT;
 	lb_cmd.enable = (enable ? 1 : 0);
-	lb_cmd.loopback_cfg_minor_version =
-					AFE_API_VERSION_LOOPBACK_CONFIG;
+	lb_cmd.loopback_cfg_minor_version = AFE_API_VERSION_LOOPBACK_CONFIG;
 	atomic_set(&this_afe.state, 1);
 
 	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lb_cmd);
@@ -613,9 +611,10 @@
 		ret = -EINVAL;
 		goto done;
 	}
+	pr_debug("%s: waiting for this_afe.wait[%d]\n", __func__, index);
 	ret = wait_event_timeout(this_afe.wait[index],
-		(atomic_read(&this_afe.state) == 0),
-				msecs_to_jiffies(TIMEOUT_MS));
+				 (atomic_read(&this_afe.state) == 0),
+				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: wait_event timeout\n", __func__);
 		ret = -EINVAL;
@@ -667,26 +666,24 @@
 	set_param.hdr.pkt_size = sizeof(set_param);
 	set_param.hdr.src_port = 0;
 	set_param.hdr.dest_port = 0;
-	set_param.hdr.token = 0;
+	set_param.hdr.token = index;
 	set_param.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
 
-	set_param.param.port_id		= port_id;
-	set_param.param.payload_size		=
-		(sizeof(struct afe_loopback_gain_per_path_param) -
-		 sizeof(struct apr_hdr) -
-		sizeof(struct afe_port_cmd_set_param_v2));
+	set_param.param.port_id	= port_id;
+	set_param.param.payload_size =
+	    (sizeof(struct afe_loopback_gain_per_path_param) -
+	     sizeof(struct apr_hdr) - sizeof(struct afe_port_cmd_set_param_v2));
 	set_param.param.payload_address_lsw	= 0;
 	set_param.param.payload_address_msw	= 0;
 	set_param.param.mem_map_handle        = 0;
 
-	set_param.pdata.module_id	= AFE_MODULE_LOOPBACK;
-	set_param.pdata.param_id	= AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH;
-	set_param.pdata.param_size = (set_param.param.payload_size -
-				sizeof(struct afe_port_param_data_v2));
+	set_param.pdata.module_id = AFE_MODULE_LOOPBACK;
+	set_param.pdata.param_id = AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH;
+	set_param.pdata.param_size =
+	    (set_param.param.payload_size -
+	     sizeof(struct afe_port_param_data_v2));
 	set_param.rx_port_id = port_id;
-	set_param.gain	= volume;
-
-	set_param.hdr.token = index;
+	set_param.gain = volume;
 
 	atomic_set(&this_afe.state, 1);
 	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_param);
@@ -698,8 +695,8 @@
 	}
 
 	ret = wait_event_timeout(this_afe.wait[index],
-		(atomic_read(&this_afe.state) == 0),
-			msecs_to_jiffies(TIMEOUT_MS));
+				 (atomic_read(&this_afe.state) == 0),
+				 msecs_to_jiffies(TIMEOUT_MS));
 	if (ret < 0) {
 		pr_err("%s: wait_event timeout\n", __func__);
 		ret = -EINVAL;
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index be2e0c5..2d2b333 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -700,7 +700,7 @@
 	if (perf_pmu__config(pmu, &attr, head_config))
 		return -EINVAL;
 
-	return add_event(list, idx, &attr, (char *) "pmu");
+	return add_event(list, idx, &attr, pmu->name);
 }
 
 void parse_events_update_lists(struct list_head *list_event,
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 28e5548..4b3a3c9 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -64,7 +64,7 @@
 num_dec		[0-9]+
 num_hex		0x[a-fA-F0-9]+
 num_raw_hex	[a-fA-F0-9]+
-name		[a-zA-Z_*?][a-zA-Z0-9_*?]*
+name		[a-zA-Z_*?][a-zA-Z\-0-9_*?]*
 modifier_event	[ukhpGH]{1,8}
 modifier_bp	[rwx]